diff --git a/src/libslic3r/ModelArrange.cpp b/src/libslic3r/ModelArrange.cpp index 8ed595802..1f517375c 100644 --- a/src/libslic3r/ModelArrange.cpp +++ b/src/libslic3r/ModelArrange.cpp @@ -15,6 +15,7 @@ namespace arr { using namespace libnest2d; +// Only for debugging. Prints the model object vertices on stdout. std::string toString(const Model& model, bool holes = true) { std::stringstream ss; @@ -78,6 +79,7 @@ std::string toString(const Model& model, bool holes = true) { return ss.str(); } +// Debugging: Save model to svg file. void toSVG(SVG& svg, const Model& model) { for(auto objptr : model.objects) { if(!objptr) continue; @@ -121,6 +123,10 @@ Box boundingBox(const Box& pilebb, const Box& ibb ) { return Box(minc, maxc); } +// This is "the" object function which is evaluated many times for each vertex +// (decimated with the accuracy parameter) of each object. Therefore it is +// upmost crucial for this function to be as efficient as it possibly can be but +// at the same time, it has to provide reasonable results. std::tuple objfunc(const PointImpl& bincenter, const shapelike::Shapes& merged_pile, @@ -253,6 +259,8 @@ objfunc(const PointImpl& bincenter, return std::make_tuple(score, fullbb); } +// Fill in the placer algorithm configuration with values carefully chosen for +// Slic3r. template void fillConfig(PConf& pcfg) { @@ -274,13 +282,19 @@ void fillConfig(PConf& pcfg) { pcfg.parallel = true; } +// Type trait for an arranger class for different bin types (box, circle, +// polygon, etc...) template class AutoArranger {}; + +// A class encapsulating the libnest2d Nester class and extending it with other +// management and spatial index structures for acceleration. template class _ArrBase { protected: + // Useful type shortcuts... using Placer = TPacker; using Selector = FirstFitSelection; using Packer = Nester; @@ -289,15 +303,15 @@ protected: using Pile = sl::Shapes; Packer m_pck; - PConfig m_pconf; // Placement configuration + PConfig m_pconf; // Placement configuration double m_bin_area; - SpatIndex m_rtree; - SpatIndex m_smallsrtree; - double m_norm; - Pile m_merged_pile; - Box m_pilebb; - ItemGroup m_remaining; - ItemGroup m_items; + SpatIndex m_rtree; // spatial index for the normal (bigger) objects + SpatIndex m_smallsrtree; // spatial index for only the smaller items + double m_norm; // A coefficient to scale distances + Pile m_merged_pile; // The already merged pile (vector of items) + Box m_pilebb; // The bounding box of the merged pile. + ItemGroup m_remaining; // Remaining items (m_items at the beginning) + ItemGroup m_items; // The items to be packed public: _ArrBase(const TBin& bin, Distance dist, @@ -308,6 +322,8 @@ public: { fillConfig(m_pconf); + // Set up a callback that is called just before arranging starts + // This functionality is provided by the Nester class (m_pack). m_pconf.before_packing = [this](const Pile& merged_pile, // merged pile const ItemGroup& items, // packed items @@ -344,8 +360,8 @@ public: } }; -template<> -class AutoArranger: public _ArrBase { +// Arranger specialization for a Box shaped bin. +template<> class AutoArranger: public _ArrBase { public: AutoArranger(const Box& bin, Distance dist, @@ -354,6 +370,9 @@ public: _ArrBase(bin, dist, progressind, stopcond) { + // Here we set up the actual object function that calls the common + // object function for all bin shapes than does an additional inside + // check for the arranged pile. m_pconf.object_function = [this, bin] (const Item &item) { auto result = objfunc(bin.center(), @@ -387,8 +406,8 @@ inline lnCircle to_lnCircle(const Circle& circ) { return lnCircle({circ.center()(0), circ.center()(1)}, circ.radius()); } -template<> -class AutoArranger: public _ArrBase { +// Arranger specialization for circle shaped bin. +template<> class AutoArranger: public _ArrBase { public: AutoArranger(const lnCircle& bin, Distance dist, @@ -396,6 +415,7 @@ public: std::function stopcond): _ArrBase(bin, dist, progressind, stopcond) { + // As with the box, only the inside check is different. m_pconf.object_function = [this, &bin] (const Item &item) { auto result = objfunc(bin.center(), @@ -431,8 +451,9 @@ public: } }; -template<> -class AutoArranger: public _ArrBase { +// Arranger specialization for a generalized polygon. +// Warning: this is unfinished business. It may or may not work. +template<> class AutoArranger: public _ArrBase { public: AutoArranger(const PolygonImpl& bin, Distance dist, std::function progressind, @@ -461,8 +482,10 @@ public: } }; -template<> // Specialization with no bin -class AutoArranger: public _ArrBase { +// Specialization with no bin. In this case the arranger should just arrange +// all objects into a minimum sized pile but it is not limited by a bin. A +// consequence is that only one pile should be created. +template<> class AutoArranger: public _ArrBase { public: AutoArranger(Distance dist, std::function progressind, @@ -490,14 +513,15 @@ public: // A container which stores a pointer to the 3D object and its projected // 2D shape from top view. -using ShapeData2D = - std::vector>; +using ShapeData2D = std::vector>; ShapeData2D projectModelFromTop(const Slic3r::Model &model) { ShapeData2D ret; - auto s = std::accumulate(model.objects.begin(), model.objects.end(), size_t(0), - [](size_t s, ModelObject* o){ + // Count all the items on the bin (all the object's instances) + auto s = std::accumulate(model.objects.begin(), model.objects.end(), + size_t(0), [](size_t s, ModelObject* o) + { return s + o->instances.size(); }); @@ -517,7 +541,8 @@ ShapeData2D projectModelFromTop(const Slic3r::Model &model) { rmesh.rotate_x(float(finst->get_rotation()(X))); rmesh.rotate_y(float(finst->get_rotation()(Y))); - // TODO export the exact 2D projection + // TODO export the exact 2D projection. Cannot do it as libnest2d + // does not support concave shapes (yet). auto p = rmesh.convex_hull(); p.make_clockwise(); @@ -549,6 +574,8 @@ ShapeData2D projectModelFromTop(const Slic3r::Model &model) { return ret; } +// Apply the calculated translations and rotations (currently disabled) to the +// Model object instances. void applyResult( IndexedPackGroup::value_type& group, Coord batch_offset, @@ -576,6 +603,7 @@ void applyResult( } } +// Get the type of bed geometry from a simple vector of points. BedShapeHint bedShape(const Polyline &bed) { BedShapeHint ret; @@ -654,11 +682,15 @@ BedShapeHint bedShape(const Polyline &bed) { return ret; } -bool arrange(Model &model, - coord_t min_obj_distance, - const Polyline &bed, - BedShapeHint bedhint, - bool first_bin_only, +// The final client function to arrange the Model. A progress indicator and +// a stop predicate can be also be passed to control the process. +bool arrange(Model &model, // The model with the geometries + coord_t min_obj_distance, // Has to be in scaled (clipper) measure + const Polyline &bed, // The bed geometry. + BedShapeHint bedhint, // Hint about the bed geometry type. + bool first_bin_only, // What to do is not all items fit. + + // Controlling callbacks. std::function progressind, std::function stopcondition) {