diff --git a/xs/src/libslic3r/ModelArrange.hpp b/xs/src/libslic3r/ModelArrange.hpp index f2d399ac6..5b7a2a325 100644 --- a/xs/src/libslic3r/ModelArrange.hpp +++ b/xs/src/libslic3r/ModelArrange.hpp @@ -292,6 +292,7 @@ public: template inline IndexedPackGroup operator()(Args&&...args) { areacache_.clear(); + rtree_.clear(); return pck_.arrangeIndexed(std::forward(args)...); } }; @@ -440,16 +441,157 @@ ShapeData2D projectModelFromTop(const Slic3r::Model &model) { return ret; } -enum BedShapeHint { +class Circle { + Point center_; + double radius_; +public: + + inline Circle(): center_(0, 0), radius_(std::nan("")) {} + inline Circle(const Point& c, double r): center_(c), radius_(r) {} + + inline double radius() const { return radius_; } + inline const Point& center() const { return center_; } + inline operator bool() { return std::isnan(radius_); } +}; + + +Circle circle(std::array P) { + + using Coord = Point::coord_type; + using std::pow; + using std::abs; + using std::round; + using std::nan; + + auto getX = [](const Point& p) { return p.x; }; + auto getY = [](const Point& p) { return p.y; }; + + auto distance = [](const Point& p1, const Point& p2) { + return abs(p1.distance_to(p2)); + }; + + static const auto E = 10.0/SCALING_FACTOR; + + auto x1 = getX(P[0]), y1 = getY(P[0]); + auto x2 = getX(P[1]), y2 = getY(P[1]); + auto x3 = getX(P[2]), y3 = getY(P[2]); + + + auto A_div = (x2 - x1); + auto B_div = (x3 - x2); + if(A_div == 0 || B_div == 0) return Circle(); + + auto A = (y2 - y1)/A_div; + auto B = (y2 - y3)/B_div; + auto C = (-pow(x1, 2) - pow(y1, 2) + pow(x2, 2) + pow(y2, 2))/(2*(x2 - x1)); + auto D = (pow(x2, 2) + pow(y1, 2) - pow(x3, 2) - pow(y3, 2))/(2*(x3 - x2)); + + auto cy = (C + D)/(A + B); + auto cx = B*cy - D; + + Point cc = {Coord(round(cx)), Coord(round(cy))}; + auto d = distance(cc, P[0]); + auto d2 = distance(cc, P[1]); + auto d3 = distance(cc, P[2]); + + auto e1 = abs(d - d2); + auto e2 = abs(d - d3); + + if(e1 > E || e2 > E) return Circle(); + + return { cc, d }; +} + +Circle isCircle(const Polyline& p) { + + using std::abs; + + auto& pp = p.points; + static const double E = 10/SCALING_FACTOR; + double radius = 0; + bool ret = true; + Circle c; + for(auto i = 0; i < pp.size() - 3 && ret; i += 3) { + c = circle({pp[i], pp[i+1], pp[i+2]}); + if(c || abs(radius - c.radius()) >= E) ret = false; + else radius = c.radius(); + } + +// auto rem = pp.size() % 3; + +// if(ret && rem > 0) { +// std::array remarr; + +// auto i = 0; +// for(i = 0; i < rem; i++) remarr[i] = *(pp.rbegin() - i); +// while(i < 3) remarr[i] = pp[i++]; +// c = circle(remarr); +// if(c || abs(radius - c.radius()) >= E) ret = false; +// } + + if(!ret) c = Circle(); + + return c; +} + +enum class BedShapeType { BOX, CIRCLE, IRREGULAR, WHO_KNOWS }; -BedShapeHint bedShape(const Slic3r::Polyline& /*bed*/) { +struct BedShapeHint { + BedShapeType type; + /*union*/ struct { // I know but who cares... + Circle circ; + BoundingBox box; + Polyline polygon; + } shape; +}; + +BedShapeHint bedShape(const Polyline& bed) { + static const double E = 10/SCALING_FACTOR; + + BedShapeHint ret; + + auto width = [](const BoundingBox& box) { + return box.max.x - box.min.x; + }; + + auto height = [](const BoundingBox& box) { + return box.max.y - box.min.y; + }; + + auto area = [&width, &height](const BoundingBox& box) { + return width(box) * height(box); + }; + + auto poly_area = [](Polyline p) { + Polygon pp; pp.points.reserve(p.points.size() + 1); + pp.points = std::move(p.points); + pp.points.emplace_back(pp.points.front()); + return std::abs(pp.area()); + }; + + auto bb = bed.bounding_box(); + if(std::abs(area(bb) - poly_area(bed)) < E) { + ret.type = BedShapeType::BOX; + ret.shape.box = bb; + std::cout << "BOX" << std::endl; + } + else if(auto c = isCircle(bed)) { + ret.type = BedShapeType::CIRCLE; + ret.shape.circ = c; + std::cout << "Circle" << std::endl; + } else { + std::cout << "Polygon" << std::endl; + ret.type = BedShapeType::IRREGULAR; + ret.shape.polygon = bed; + } + // Determine the bed shape by hand - return BOX; + return ret; } void applyResult( @@ -525,7 +667,10 @@ bool arrange(Model &model, coordf_t min_obj_distance, }); IndexedPackGroup result; - BoundingBox bbb(bed.points); + + if(bedhint.type == BedShapeType::WHO_KNOWS) bedhint = bedShape(bed); + + BoundingBox bbb(bed); auto binbb = Box({ static_cast(bbb.min.x), @@ -536,8 +681,8 @@ bool arrange(Model &model, coordf_t min_obj_distance, static_cast(bbb.max.y) }); - switch(bedhint) { - case BOX: { + switch(bedhint.type) { + case BedShapeType::BOX: { // Create the arranger for the box shaped bed AutoArranger arrange(binbb, min_obj_distance, progressind); @@ -547,10 +692,11 @@ bool arrange(Model &model, coordf_t min_obj_distance, result = arrange(shapes.begin(), shapes.end()); break; } - case CIRCLE: + case BedShapeType::CIRCLE: break; - case IRREGULAR: - case WHO_KNOWS: { + case BedShapeType::IRREGULAR: + case BedShapeType::WHO_KNOWS: { + using P = libnest2d::PolygonImpl; auto ctour = Slic3rMultiPoint_to_ClipperPath(bed); diff --git a/xs/src/slic3r/AppController.cpp b/xs/src/slic3r/AppController.cpp index 58858f5fc..9394df363 100644 --- a/xs/src/slic3r/AppController.cpp +++ b/xs/src/slic3r/AppController.cpp @@ -288,6 +288,7 @@ const PrintConfig &PrintController::config() const return print_->config; } + void AppController::arrange_model() { auto ftr = std::async( @@ -324,10 +325,14 @@ void AppController::arrange_model() if(pind) pind->update(0, _(L("Arranging objects..."))); try { + arr::BedShapeHint hint; + // TODO: from Sasha from GUI + hint.type = arr::BedShapeType::WHO_KNOWS; + arr::arrange(*model_, min_obj_distance, bed, - arr::BOX, + hint, false, // create many piles not just one pile [pind, count](unsigned rem) { if(pind)