mirror of
				https://github.com/SoftFever/OrcaSlicer.git
				synced 2025-10-31 12:41:20 -06:00 
			
		
		
		
	ENH: auto-arranging allows more filaments together
Auto-arranging allows more filaments to be printed on the same plate Only HighTemp and LowTemp filaments are not allowed on the same plate. Jira: https://jira.bambooolab.com/browse/STUDIO-4682 Change-Id: I1bd4966e6aaa55a6dd9dff05f0bd94f2795a62b0 (cherry picked from commit 965040912af0555ca190702e7c7ac92e177a2922)
This commit is contained in:
		
							parent
							
								
									7b93986dfa
								
							
						
					
					
						commit
						d64031a054
					
				
					 7 changed files with 159 additions and 91 deletions
				
			
		|  | @ -69,13 +69,14 @@ class _Item { | |||
|         Box bb; bool valid; | ||||
|         BBCache(): valid(false) {} | ||||
|     } bb_cache_; | ||||
|      | ||||
| 
 | ||||
|     int binid_{BIN_ID_UNSET}, priority_{0}; | ||||
|     bool fixed_{false}; | ||||
| 
 | ||||
| public: | ||||
|     int itemid_{ 0 }; | ||||
|     std::vector<int> extrude_ids; | ||||
|     int filament_temp_type = -1; // -1 means unset. otherwise should be {0,1,2}
 | ||||
|     double height{ 0 }; | ||||
|     double print_temp{ 0 }; | ||||
|     double bed_temp{ 0 }; | ||||
|  | @ -140,7 +141,7 @@ public: | |||
|     inline _Item(TContour<RawShape>&& contour, | ||||
|                  THolesContainer<RawShape>&& holes): | ||||
|         sh_(sl::create<RawShape>(std::move(contour), std::move(holes))) {} | ||||
|      | ||||
| 
 | ||||
|     inline bool isFixed() const noexcept { return fixed_; } | ||||
|     inline void markAsFixedInBin(int binid) | ||||
|     { | ||||
|  | @ -150,7 +151,7 @@ public: | |||
| 
 | ||||
|     inline void binId(int idx) { binid_ = idx; } | ||||
|     inline int binId() const noexcept { return binid_; } | ||||
|      | ||||
| 
 | ||||
|     inline void priority(int p) { priority_ = p; } | ||||
|     inline int priority() const noexcept { return priority_; } | ||||
| 
 | ||||
|  | @ -303,18 +304,18 @@ public: | |||
|     { | ||||
|         rotation(rotation() + rads); | ||||
|     } | ||||
|      | ||||
| 
 | ||||
|     inline void inflation(Coord distance) BP2D_NOEXCEPT | ||||
|     { | ||||
|         inflation_ = distance; | ||||
|         has_inflation_ = true; | ||||
|         invalidateCache(); | ||||
|     } | ||||
|      | ||||
| 
 | ||||
|     inline Coord inflation() const BP2D_NOEXCEPT { | ||||
|         return inflation_; | ||||
|     } | ||||
|      | ||||
| 
 | ||||
|     inline void inflate(Coord distance) BP2D_NOEXCEPT | ||||
|     { | ||||
|         inflation(inflation() + distance); | ||||
|  | @ -780,7 +781,7 @@ template<class PlacementStrategy, class SelectionStrategy > | |||
| class _Nester { | ||||
|     using TSel = SelectionStrategyLike<SelectionStrategy>; | ||||
|     TSel selector_; | ||||
|      | ||||
| 
 | ||||
| public: | ||||
|     using Item = typename PlacementStrategy::Item; | ||||
|     using ShapeType = typename Item::ShapeType; | ||||
|  | @ -805,7 +806,7 @@ private: | |||
|     StopCondition stopfn_; | ||||
| 
 | ||||
|     template<class It> using TVal = remove_ref_t<typename It::value_type>; | ||||
|      | ||||
| 
 | ||||
|     template<class It, class Out> | ||||
|     using ItemIteratorOnly = | ||||
|         enable_if_t<std::is_convertible<TVal<It>&, TPItem&>::value, Out>; | ||||
|  | @ -863,14 +864,14 @@ public: | |||
|         if(infl > 0) std::for_each(from, to, [infl](Item& item) { | ||||
|             item.inflate(infl); | ||||
|         }); | ||||
|          | ||||
| 
 | ||||
|         selector_.template packItems<PlacementStrategy>( | ||||
|             from, to, bin_, pconfig_); | ||||
|          | ||||
| 
 | ||||
|         if(min_obj_distance_ > 0) std::for_each(from, to, [infl](Item& item) { | ||||
|             item.inflate(-infl); | ||||
|         }); | ||||
|          | ||||
| 
 | ||||
|         return selector_.getResult().size(); | ||||
|     } | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,5 +1,5 @@ | |||
| #include "Arrange.hpp" | ||||
| 
 | ||||
| #include "Print.hpp" | ||||
| #include "BoundingBox.hpp" | ||||
| 
 | ||||
| #include <libnest2d/backends/libslic3r/geometries.hpp> | ||||
|  | @ -260,7 +260,7 @@ Points get_shrink_bedpts(const DynamicPrintConfig* print_cfg, const ArrangeParam | |||
| // Slic3r.
 | ||||
| template<class PConf> | ||||
| void fill_config(PConf& pcfg, const ArrangeParams ¶ms) { | ||||
|      | ||||
| 
 | ||||
|         if (params.is_seq_print) { | ||||
|             // Start placing the items from the center of the print bed
 | ||||
|             pcfg.starting_point = PConf::Alignment::BOTTOM_LEFT; | ||||
|  | @ -269,7 +269,7 @@ void fill_config(PConf& pcfg, const ArrangeParams ¶ms) { | |||
|             // Start placing the items from the center of the print bed
 | ||||
|             pcfg.starting_point = PConf::Alignment::TOP_RIGHT; | ||||
|         } | ||||
|      | ||||
| 
 | ||||
|     if (params.do_final_align) { | ||||
|         // Align the arranged pile into the center of the bin
 | ||||
|         pcfg.alignment = PConf::Alignment::CENTER; | ||||
|  | @ -286,7 +286,7 @@ void fill_config(PConf& pcfg, const ArrangeParams ¶ms) { | |||
|     // The accuracy of optimization.
 | ||||
|     // Goes from 0.0 to 1.0 and scales performance as well
 | ||||
|     pcfg.accuracy = params.accuracy; | ||||
|      | ||||
| 
 | ||||
|     // Allow parallel execution.
 | ||||
|     pcfg.parallel = params.parallel; | ||||
| 
 | ||||
|  | @ -312,7 +312,7 @@ static double fixed_overfit(const std::tuple<double, Box>& result, const Box &bi | |||
|     Box fullbb  = sl::boundingBox(pilebb, binbb); | ||||
|     auto diff = double(fullbb.area()) - binbb.area(); | ||||
|     if(diff > 0) score += diff; | ||||
|      | ||||
| 
 | ||||
|     return score; | ||||
| } | ||||
| 
 | ||||
|  | @ -379,7 +379,7 @@ protected: | |||
|     std::vector<Box> m_excluded_and_extruCali_regions;  // excluded and extrusion calib regions
 | ||||
|     size_t    m_item_count = 0; // Number of all items to be packed
 | ||||
|     ArrangeParams params; | ||||
|      | ||||
| 
 | ||||
|     template<class T> ArithmeticOnly<T, double> norm(T val) | ||||
|     { | ||||
|         return double(val) / m_norm; | ||||
|  | @ -417,18 +417,18 @@ protected: | |||
|         const double bin_area = m_bin_area; | ||||
|         const SpatIndex& spatindex = m_rtree; | ||||
|         const SpatIndex& smalls_spatindex = m_smallsrtree; | ||||
|          | ||||
| 
 | ||||
|         // We will treat big items (compared to the print bed) differently
 | ||||
|         auto isBig = [bin_area](double a) { | ||||
|             return a/bin_area > BIG_ITEM_TRESHOLD ; | ||||
|         }; | ||||
|          | ||||
| 
 | ||||
|         // Candidate item bounding box
 | ||||
|         auto ibb = item.boundingBox(); | ||||
|          | ||||
| 
 | ||||
|         // Calculate the full bounding box of the pile with the candidate item
 | ||||
|         auto fullbb = sl::boundingBox(m_pilebb, ibb); | ||||
|          | ||||
| 
 | ||||
|         // The bounding box of the big items (they will accumulate in the center
 | ||||
|         // of the pile
 | ||||
|         Box bigbb; | ||||
|  | @ -437,31 +437,31 @@ protected: | |||
|             auto boostbb = spatindex.bounds(); | ||||
|             boost::geometry::convert(boostbb, bigbb); | ||||
|         } | ||||
|          | ||||
| 
 | ||||
|         // Will hold the resulting score
 | ||||
|         double score = 0; | ||||
|          | ||||
| 
 | ||||
|         // Density is the pack density: how big is the arranged pile
 | ||||
|         double density = 0; | ||||
|          | ||||
| 
 | ||||
|         // Distinction of cases for the arrangement scene
 | ||||
|         enum e_cases { | ||||
|             // This branch is for big items in a mixed (big and small) scene
 | ||||
|             // OR for all items in a small-only scene.
 | ||||
|             BIG_ITEM, | ||||
|              | ||||
| 
 | ||||
|             // This branch is for the last big item in a mixed scene
 | ||||
|             LAST_BIG_ITEM, | ||||
|              | ||||
| 
 | ||||
|             // For small items in a mixed scene.
 | ||||
|             SMALL_ITEM | ||||
|         } compute_case; | ||||
|          | ||||
| 
 | ||||
|         bool bigitems = isBig(item.area()) || spatindex.empty(); | ||||
|         if(!params.is_seq_print && bigitems && !m_remaining.empty()) compute_case = BIG_ITEM;  // do not use so complicated logic for sequential printing
 | ||||
|         else if (bigitems && m_remaining.empty()) compute_case = LAST_BIG_ITEM; | ||||
|         else compute_case = SMALL_ITEM; | ||||
|          | ||||
| 
 | ||||
|         switch (compute_case) { | ||||
|         case BIG_ITEM: { | ||||
|             const Point& minc = ibb.minCorner(); // bottom left corner
 | ||||
|  | @ -566,7 +566,7 @@ protected: | |||
|             } | ||||
| 
 | ||||
|             break; | ||||
|         }             | ||||
|         } | ||||
|         } | ||||
| 
 | ||||
| 
 | ||||
|  | @ -603,9 +603,11 @@ protected: | |||
|             for (int i = 0; i < m_items.size(); i++) { | ||||
|                 Item& p = m_items[i]; | ||||
|                 if (p.is_virt_object) continue; | ||||
|                 score += lambda3 * (item.bed_temp - p.vitrify_temp > VITRIFY_TEMP_DIFF_THRSH); | ||||
|                 //score += lambda3 * (item.bed_temp - p.vitrify_temp > VITRIFY_TEMP_DIFF_THRSH);
 | ||||
|                 if (!Print::is_filaments_compatible({item.filament_temp_type,p.filament_temp_type})) | ||||
|                     score += lambda3; | ||||
|             } | ||||
|             score += lambda3 * (item.bed_temp - item.vitrify_temp > VITRIFY_TEMP_DIFF_THRSH); | ||||
|             //score += lambda3 * (item.bed_temp - item.vitrify_temp > VITRIFY_TEMP_DIFF_THRSH);
 | ||||
|             score += lambda4 * hasRowHeightConflict + lambda4 * hasLidHeightConflict; | ||||
|         } | ||||
|         else { | ||||
|  | @ -625,7 +627,9 @@ protected: | |||
|                     // 高度接近的件尽量摆到一起
 | ||||
|                     score += (1- std::abs(item.height - p.height) / params.printable_height) | ||||
|                         * norm(pl::distance(ibb.center(), p.boundingBox().center())); | ||||
|                     score += LARGE_COST_TO_REJECT * (item.bed_temp - p.bed_temp != 0); | ||||
|                     //score += LARGE_COST_TO_REJECT * (item.bed_temp - p.bed_temp != 0);
 | ||||
|                     if (!Print::is_filaments_compatible({ item.filament_temp_type,p.filament_temp_type })) | ||||
|                         score += LARGE_COST_TO_REJECT; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|  | @ -656,9 +660,9 @@ protected: | |||
| 
 | ||||
|         return std::make_tuple(score, fullbb); | ||||
|     } | ||||
|      | ||||
| 
 | ||||
|     std::function<double(const Item&, const ItemGroup&)> get_objfn(); | ||||
|      | ||||
| 
 | ||||
| public: | ||||
|     AutoArranger(const TBin &                  bin, | ||||
|                  const ArrangeParams           ¶ms, | ||||
|  | @ -708,7 +712,7 @@ public: | |||
| 
 | ||||
|             m_rtree.clear(); | ||||
|             m_smallsrtree.clear(); | ||||
|              | ||||
| 
 | ||||
|             // We will treat big items (compared to the print bed) differently
 | ||||
|             auto isBig = [this](double a) { | ||||
|                 return a / m_bin_area > BIG_ITEM_TRESHOLD ; | ||||
|  | @ -721,7 +725,7 @@ public: | |||
|                 m_smallsrtree.insert({itm.boundingBox(), idx}); | ||||
|             } | ||||
|         }; | ||||
|          | ||||
| 
 | ||||
|         m_pconf.object_function = get_objfn(); | ||||
| 
 | ||||
|         // preload fixed items (and excluded regions) on plate
 | ||||
|  | @ -746,7 +750,7 @@ public: | |||
|         }; | ||||
| 
 | ||||
|         auto on_packed = params.on_packed; | ||||
|          | ||||
| 
 | ||||
|         if (progressind || on_packed) | ||||
|             m_pck.progressIndicator( | ||||
|                 [this, progressind, on_packed](unsigned num_finished) { | ||||
|  | @ -760,7 +764,8 @@ public: | |||
|                         if (on_packed) | ||||
|                             on_packed(ap); | ||||
|                         BOOST_LOG_TRIVIAL(debug) << "arrange " + last_packed.name + " succeed!" | ||||
|                             << ", plate id=" << ap.bed_idx << ", pos=" << last_packed.translation(); | ||||
|                             << ", plate id=" << ap.bed_idx << ", pos=" << last_packed.translation() | ||||
|                             << ", temp_type=" << last_packed.filament_temp_type; | ||||
|                     } | ||||
|                 }); | ||||
| 
 | ||||
|  | @ -783,21 +788,21 @@ public: | |||
|                     (i1.extrude_ids != i2.extrude_ids ? (i1.extrude_ids.front() < i2.extrude_ids.front()) : (i1.area() > i2.area())); | ||||
|             } | ||||
|         }; | ||||
|          | ||||
| 
 | ||||
|         m_pck.configure(m_pconf); | ||||
|     } | ||||
|       | ||||
| 
 | ||||
|     template<class It> inline void operator()(It from, It to) { | ||||
|         m_rtree.clear(); | ||||
|         m_item_count += size_t(to - from); | ||||
|         m_pck.execute(from, to); | ||||
|         m_item_count = 0; | ||||
|     } | ||||
|      | ||||
| 
 | ||||
|     PConfig& config() { return m_pconf; } | ||||
|     const PConfig& config() const { return m_pconf; } | ||||
|      | ||||
|     inline void preload(std::vector<Item>& fixeditems) {         | ||||
| 
 | ||||
|     inline void preload(std::vector<Item>& fixeditems) { | ||||
|         for(unsigned idx = 0; idx < fixeditems.size(); ++idx) { | ||||
|             Item& itm = fixeditems[idx]; | ||||
|             itm.markAsFixedInBin(itm.binId()); | ||||
|  | @ -813,7 +818,7 @@ template<> std::function<double(const Item&, const ItemGroup&)> AutoArranger<Box | |||
| 
 | ||||
|     return [this, origin_pack](const Item &itm, const ItemGroup&) { | ||||
|         auto result = objfunc(itm, origin_pack); | ||||
|          | ||||
| 
 | ||||
|         double score = std::get<0>(result); | ||||
|         auto& fullbb = std::get<1>(result); | ||||
| 
 | ||||
|  | @ -840,15 +845,15 @@ template<> std::function<double(const Item&, const ItemGroup&)> AutoArranger<Cir | |||
|     auto bb = sl::boundingBox(m_bin); | ||||
|     auto origin_pack = m_pconf.starting_point == PConfig::Alignment::CENTER ? bb.center() : bb.minCorner(); | ||||
|     return [this, origin_pack](const Item &item, const ItemGroup&) { | ||||
|          | ||||
| 
 | ||||
|         auto result = objfunc(item, origin_pack); | ||||
|          | ||||
| 
 | ||||
|         double score = std::get<0>(result); | ||||
|          | ||||
| 
 | ||||
|         auto isBig = [this](const Item& itm) { | ||||
|             return itm.area() / m_bin_area > BIG_ITEM_TRESHOLD ; | ||||
|         }; | ||||
|          | ||||
| 
 | ||||
|         if(isBig(item)) { | ||||
|             auto mp = m_merged_pile; | ||||
|             mp.push_back(item.transformedShape()); | ||||
|  | @ -857,7 +862,7 @@ template<> std::function<double(const Item&, const ItemGroup&)> AutoArranger<Cir | |||
|             if(miss < 0) miss = 0; | ||||
|             score += miss*miss; | ||||
|         } | ||||
|          | ||||
| 
 | ||||
|         return score; | ||||
|     }; | ||||
| } | ||||
|  | @ -873,7 +878,7 @@ std::function<double(const Item &, const ItemGroup&)> AutoArranger<ExPolygon>::g | |||
|         auto result = objfunc(itm, origin_pack); | ||||
| 
 | ||||
|         double score = std::get<0>(result); | ||||
|          | ||||
| 
 | ||||
|         auto mp = m_merged_pile; | ||||
|         mp.emplace_back(itm.transformedShape()); | ||||
|         auto chull = sl::convexHull(mp); | ||||
|  | @ -930,14 +935,14 @@ void _arrange( | |||
|     // Integer ceiling the min distance from the bed perimeters
 | ||||
|     coord_t md = params.min_obj_distance; | ||||
|     md = md / 2; | ||||
|      | ||||
| 
 | ||||
|     auto corrected_bin = bin; | ||||
|     //sl::offset(corrected_bin, md);
 | ||||
|     ArrangeParams mod_params = params; | ||||
|     mod_params.min_obj_distance = 0;  // items are already inflated
 | ||||
| 
 | ||||
|     AutoArranger<BinT> arranger{corrected_bin, mod_params, progressfn, stopfn}; | ||||
|      | ||||
| 
 | ||||
|     remove_large_items(excludes, corrected_bin); | ||||
| 
 | ||||
|     // If there is something on the plate
 | ||||
|  | @ -947,7 +952,7 @@ void _arrange( | |||
|     inp.reserve(shapes.size() + excludes.size()); | ||||
|     for (auto &itm : shapes  ) inp.emplace_back(itm); | ||||
|     for (auto &itm : excludes) inp.emplace_back(itm); | ||||
|      | ||||
| 
 | ||||
|     // Use the minimum bounding box rotation as a starting point.
 | ||||
|     // TODO: This only works for convex hull. If we ever switch to concave
 | ||||
|     // polygon nesting, a convex hull needs to be calculated.
 | ||||
|  | @ -987,16 +992,16 @@ inline double distance_to(const Point& p1, const Point& p2) | |||
| static CircleBed to_circle(const Point ¢er, const Points& points) { | ||||
|     std::vector<double> vertex_distances; | ||||
|     double avg_dist = 0; | ||||
|      | ||||
| 
 | ||||
|     for (auto pt : points) | ||||
|     { | ||||
|         double distance = distance_to(center, pt); | ||||
|         vertex_distances.push_back(distance); | ||||
|         avg_dist += distance; | ||||
|     } | ||||
|      | ||||
| 
 | ||||
|     avg_dist /= vertex_distances.size(); | ||||
|      | ||||
| 
 | ||||
|     CircleBed ret(center, avg_dist); | ||||
|     for(auto el : vertex_distances) | ||||
|     { | ||||
|  | @ -1005,7 +1010,7 @@ static CircleBed to_circle(const Point ¢er, const Points& points) { | |||
|             break; | ||||
|         } | ||||
|     } | ||||
|      | ||||
| 
 | ||||
|     return ret; | ||||
| } | ||||
| 
 | ||||
|  | @ -1039,6 +1044,7 @@ static void process_arrangeable(const ArrangePolygon &arrpoly, | |||
|     item.print_temp = arrpoly.print_temp; | ||||
|     item.vitrify_temp = arrpoly.vitrify_temp; | ||||
|     item.inflation(arrpoly.inflation); | ||||
|     item.filament_temp_type = arrpoly.filament_temp_type; | ||||
| } | ||||
| 
 | ||||
| template<class Fn> auto call_with_bed(const Points &bed, Fn &&fn) | ||||
|  | @ -1079,20 +1085,20 @@ void arrange(ArrangePolygons &      arrangables, | |||
|              const ArrangeParams &  params) | ||||
| { | ||||
|     namespace clppr = Slic3r::ClipperLib; | ||||
|      | ||||
| 
 | ||||
|     std::vector<Item> items, fixeditems; | ||||
|     items.reserve(arrangables.size()); | ||||
|      | ||||
| 
 | ||||
|     for (ArrangePolygon &arrangeable : arrangables) | ||||
|         process_arrangeable(arrangeable, items); | ||||
|      | ||||
| 
 | ||||
|     for (const ArrangePolygon &fixed: excludes) | ||||
|         process_arrangeable(fixed, fixeditems); | ||||
|      | ||||
| 
 | ||||
|     for (Item &itm : fixeditems) itm.inflate(scaled(-2. * EPSILON)); | ||||
|      | ||||
| 
 | ||||
|     _arrange(items, fixeditems, to_nestbin(bed), params, params.progressind, params.stopcondition); | ||||
|      | ||||
| 
 | ||||
|     for(size_t i = 0; i < items.size(); ++i) { | ||||
|         Point tr = items[i].translation(); | ||||
|         arrangables[i].translation = {coord_t(tr.x()), coord_t(tr.y())}; | ||||
|  |  | |||
|  | @ -40,12 +40,12 @@ static const constexpr int UNARRANGED = -1; | |||
| /// be modified during arrangement. Instead, the translation and rotation fields
 | ||||
| /// will mark the needed transformation for the polygon to be in the arranged
 | ||||
| /// position. These can also be set to an initial offset and rotation.
 | ||||
| /// 
 | ||||
| ///
 | ||||
| /// The bed_idx field will indicate the logical bed into which the
 | ||||
| /// polygon belongs: UNARRANGED means no place for the polygon
 | ||||
| /// (also the initial state before arrange), 0..N means the index of the bed.
 | ||||
| /// Zero is the physical bed, larger than zero means a virtual bed.
 | ||||
| struct ArrangePolygon {  | ||||
| struct ArrangePolygon { | ||||
|     ExPolygon poly;                 /// The 2D silhouette to be arranged
 | ||||
|     Vec2crd   translation{0, 0};    /// The translation of the poly
 | ||||
|     double    rotation{0.0};        /// The rotation of the poly in radians
 | ||||
|  | @ -62,6 +62,7 @@ struct ArrangePolygon { | |||
|     int       row{0}; | ||||
|     int       col{0}; | ||||
|     std::vector<int> extrude_ids{};      /// extruder_id for least extruder switch
 | ||||
|     int filament_temp_type{ -1 }; | ||||
|     int       bed_temp{0};         ///bed temperature for different material judge
 | ||||
|     int       print_temp{0};      ///print temperature for different material judge
 | ||||
|     int       first_bed_temp{ 0 };      ///first layer bed temperature for different material judge
 | ||||
|  | @ -69,20 +70,20 @@ struct ArrangePolygon { | |||
|     int       vitrify_temp{ 0 };   // max bed temperature for material compatibility, which is usually the filament vitrification temp
 | ||||
|     int       itemid{ 0 };         // item id in the vector, used for accessing all possible params like extrude_id
 | ||||
|     int       is_applied{ 0 };     // transform has been applied
 | ||||
|     double    height{ 0 };         // item height 
 | ||||
|     double    height{ 0 };         // item height
 | ||||
|     double    brim_width{ 0 };     // brim width
 | ||||
|     std::string name; | ||||
|      | ||||
| 
 | ||||
|     // If empty, any rotation is allowed (currently unsupported)
 | ||||
|     // If only a zero is there, no rotation is allowed
 | ||||
|     std::vector<double> allowed_rotations = {0.}; | ||||
|      | ||||
| 
 | ||||
|     /// Optional setter function which can store arbitrary data in its closure
 | ||||
|     std::function<void(const ArrangePolygon&)> setter = nullptr; | ||||
|      | ||||
| 
 | ||||
|     /// Helper function to call the setter with the arrange data arguments
 | ||||
|     void apply() { | ||||
|         if (setter && !is_applied) {  | ||||
|         if (setter && !is_applied) { | ||||
|             setter(*this); | ||||
|             is_applied = 1; | ||||
|         } | ||||
|  | @ -104,15 +105,15 @@ struct ArrangePolygon { | |||
| using ArrangePolygons = std::vector<ArrangePolygon>; | ||||
| 
 | ||||
| struct ArrangeParams { | ||||
|      | ||||
|     /// The minimum distance which is allowed for any 
 | ||||
| 
 | ||||
|     /// The minimum distance which is allowed for any
 | ||||
|     /// pair of items on the print bed in any direction.
 | ||||
|     coord_t min_obj_distance = 0; | ||||
|      | ||||
| 
 | ||||
|     /// The accuracy of optimization.
 | ||||
|     /// Goes from 0.0 to 1.0 and scales performance as well
 | ||||
|     float accuracy = 1.f; | ||||
|      | ||||
| 
 | ||||
|     /// Allow parallel execution.
 | ||||
|     bool parallel = true; | ||||
| 
 | ||||
|  | @ -136,18 +137,18 @@ struct ArrangeParams { | |||
| 
 | ||||
|     ArrangePolygons excluded_regions;   // regions cant't be used
 | ||||
|     ArrangePolygons nonprefered_regions; // regions can be used but not prefered
 | ||||
|      | ||||
|     /// Progress indicator callback called when an object gets packed. 
 | ||||
| 
 | ||||
|     /// Progress indicator callback called when an object gets packed.
 | ||||
|     /// The unsigned argument is the number of items remaining to pack.
 | ||||
|     std::function<void(unsigned, std::string)> progressind = [](unsigned st, std::string str = "") { | ||||
|         std::cout << "st=" << st << ", " << str << std::endl; | ||||
|     }; | ||||
| 
 | ||||
|     std::function<void(const ArrangePolygon &)> on_packed; | ||||
|      | ||||
| 
 | ||||
|     /// A predicate returning true if abort is needed.
 | ||||
|     std::function<bool(void)>     stopcondition; | ||||
|      | ||||
| 
 | ||||
|     ArrangeParams() = default; | ||||
|     explicit ArrangeParams(coord_t md) : min_obj_distance(md) {} | ||||
|     // to json format
 | ||||
|  | @ -186,11 +187,11 @@ Points get_shrink_bedpts(const DynamicPrintConfig* print_cfg, const ArrangeParam | |||
| /**
 | ||||
|  * \brief Arranges the input polygons. | ||||
|  * | ||||
|  * WARNING: Currently, only convex polygons are supported by the libnest2d  | ||||
|  * WARNING: Currently, only convex polygons are supported by the libnest2d | ||||
|  * library which is used to do the arrangement. This might change in the future | ||||
|  * this is why the interface contains a general polygon capable to have holes. | ||||
|  * | ||||
|  * \param items Input vector of ArrangePolygons. The transformation, rotation  | ||||
|  * \param items Input vector of ArrangePolygons. The transformation, rotation | ||||
|  * and bin_idx fields will be changed after the call finished and can be used | ||||
|  * to apply the result on the input polygon. | ||||
|  */ | ||||
|  |  | |||
|  | @ -2,6 +2,7 @@ | |||
| 
 | ||||
| #include <libslic3r/Model.hpp> | ||||
| #include <libslic3r/Geometry/ConvexHull.hpp> | ||||
| #include <libslic3r/Print.hpp> | ||||
| #include "MTUtils.hpp" | ||||
| 
 | ||||
| namespace Slic3r { | ||||
|  | @ -10,7 +11,7 @@ arrangement::ArrangePolygons get_arrange_polys(const Model &model, ModelInstance | |||
| { | ||||
|     size_t count = 0; | ||||
|     for (auto obj : model.objects) count += obj->instances.size(); | ||||
|      | ||||
| 
 | ||||
|     ArrangePolygons input; | ||||
|     input.reserve(count); | ||||
|     instances.clear(); instances.reserve(count); | ||||
|  | @ -21,21 +22,21 @@ arrangement::ArrangePolygons get_arrange_polys(const Model &model, ModelInstance | |||
|             input.emplace_back(ap); | ||||
|             instances.emplace_back(minst); | ||||
|         } | ||||
|      | ||||
| 
 | ||||
|     return input; | ||||
| } | ||||
| 
 | ||||
| bool apply_arrange_polys(ArrangePolygons &input, ModelInstancePtrs &instances, VirtualBedFn vfn) | ||||
| { | ||||
|     bool ret = true; | ||||
|      | ||||
| 
 | ||||
|     for(size_t i = 0; i < input.size(); ++i) { | ||||
|         if (input[i].bed_idx != 0) { ret = false; if (vfn) vfn(input[i]); } | ||||
|         if (input[i].bed_idx >= 0) | ||||
|             instances[i]->apply_arrange_result(input[i].translation.cast<double>(), | ||||
|                                                input[i].rotation); | ||||
|     } | ||||
|      | ||||
| 
 | ||||
|     return ret; | ||||
| } | ||||
| 
 | ||||
|  | @ -52,7 +53,7 @@ Slic3r::arrangement::ArrangePolygon get_arrange_poly(const Model &model) | |||
|             const Points &pts = obj_ap.poly.contour.points; | ||||
|             std::copy(pts.begin(), pts.end(), std::back_inserter(apts)); | ||||
|         } | ||||
|      | ||||
| 
 | ||||
|     apts = std::move(Geometry::convex_hull(apts).points); | ||||
|     return ap; | ||||
| } | ||||
|  | @ -118,7 +119,7 @@ arrangement::ArrangePolygon get_arrange_poly(ModelInstance* inst, const Slic3r:: | |||
| ArrangePolygon get_instance_arrange_poly(ModelInstance* instance, const Slic3r::DynamicPrintConfig& config) | ||||
| { | ||||
|     ArrangePolygon ap = get_arrange_poly(PtrWrapper{ instance }, config); | ||||
|      | ||||
| 
 | ||||
|     //BBS: add temperature information
 | ||||
|     if (config.has("curr_bed_type")) { | ||||
|         ap.bed_temp = 0; | ||||
|  | @ -138,11 +139,23 @@ ArrangePolygon get_instance_arrange_poly(ModelInstance* instance, const Slic3r:: | |||
|         ap.print_temp = config.opt_int("nozzle_temperature", ap.extrude_ids.front() - 1); | ||||
|     if (config.has("nozzle_temperature_initial_layer")) //get the nozzle_temperature_initial_layer
 | ||||
|         ap.first_print_temp = config.opt_int("nozzle_temperature_initial_layer", ap.extrude_ids.front() - 1); | ||||
|      | ||||
| 
 | ||||
|     if (config.has("temperature_vitrification")) { | ||||
|         ap.vitrify_temp = config.opt_int("temperature_vitrification", ap.extrude_ids.front() - 1); | ||||
|     } | ||||
| 
 | ||||
|     // get filament temp types
 | ||||
|     auto* filament_types_opt = dynamic_cast<const ConfigOptionStrings*>(config.option("filament_type")); | ||||
|     if (filament_types_opt) { | ||||
|         std::set<int> filament_temp_types; | ||||
|         for (auto i : ap.extrude_ids) { | ||||
|             std::string type_str = filament_types_opt->get_at(i-1); | ||||
|             int temp_type = Print::get_filament_temp_type(type_str); | ||||
|             filament_temp_types.insert(temp_type); | ||||
|         } | ||||
|         ap.filament_temp_type = Print::get_compatible_filament_type(filament_temp_types); | ||||
|     } | ||||
| 
 | ||||
|     // get brim width
 | ||||
|     auto obj = instance->get_object(); | ||||
| 
 | ||||
|  | @ -162,7 +175,7 @@ ArrangePolygon get_instance_arrange_poly(ModelInstance* instance, const Slic3r:: | |||
|         ap.brim_width = 24.0; // 2*MAX_BRANCH_RADIUS_FIRST_LAYER
 | ||||
|         ap.has_tree_support = true; | ||||
|     } | ||||
|      | ||||
| 
 | ||||
|     ap.height = obj->bounding_box().size().z(); | ||||
|     ap.name = obj->name; | ||||
|     return ap; | ||||
|  |  | |||
|  | @ -930,6 +930,44 @@ bool Print::check_multi_filaments_compatibility(const std::vector<std::string>& | |||
|     return true; | ||||
| } | ||||
| 
 | ||||
| bool Print::is_filaments_compatible(const std::vector<int>& filament_types) | ||||
| { | ||||
|     bool has_high_temperature_filament = false; | ||||
|     bool has_low_temperature_filament = false; | ||||
| 
 | ||||
|     for (const auto& type : filament_types) { | ||||
|         if (type == FilamentTempType::HighTemp) | ||||
|             has_high_temperature_filament = true; | ||||
|         else if (type == FilamentTempType::LowTemp) | ||||
|             has_low_temperature_filament = true; | ||||
|     } | ||||
| 
 | ||||
|     if (has_high_temperature_filament && has_low_temperature_filament) | ||||
|         return false; | ||||
| 
 | ||||
|     return true; | ||||
| } | ||||
| int Print::get_compatible_filament_type(const std::set<int>& filament_types) | ||||
| { | ||||
|     bool has_high_temperature_filament = false; | ||||
|     bool has_low_temperature_filament = false; | ||||
| 
 | ||||
|     for (const auto& type : filament_types) { | ||||
|         if (type == FilamentTempType::HighTemp) | ||||
|             has_high_temperature_filament = true; | ||||
|         else if (type == FilamentTempType::LowTemp) | ||||
|             has_low_temperature_filament = true; | ||||
|     } | ||||
| 
 | ||||
|     if (has_high_temperature_filament && has_low_temperature_filament) | ||||
|         return HighLowCompatible; | ||||
|     else if (has_high_temperature_filament) | ||||
|         return HighTemp; | ||||
|     else if (has_low_temperature_filament) | ||||
|         return LowTemp; | ||||
|     return HighLowCompatible; | ||||
| } | ||||
| 
 | ||||
| //BBS: this function is used to check whether multi filament can be printed
 | ||||
| StringObjectException Print::check_multi_filament_valid(const Print& print) | ||||
| { | ||||
|  |  | |||
|  | @ -821,6 +821,15 @@ public: | |||
|     Vec2d translate_to_print_space(const Point& point) const; | ||||
| 
 | ||||
|     static bool check_multi_filaments_compatibility(const std::vector<std::string>& filament_types); | ||||
|     // similar to check_multi_filaments_compatibility, but the input is int, and may be negative (means unset)
 | ||||
|     static bool is_filaments_compatible(const std::vector<int>& types); | ||||
|     // get the compatible filament type of a multi-material object
 | ||||
|     // Rule:
 | ||||
|     // 1. LowTemp+HighLowCompatible=LowTemp
 | ||||
|     // 2. HighTemp++HighLowCompatible=HighTemp
 | ||||
|     // 3. LowTemp+HighTemp+...=HighLowCompatible
 | ||||
|     // Unset types are just ignored.
 | ||||
|     static int get_compatible_filament_type(const std::set<int>& types); | ||||
| 
 | ||||
| protected: | ||||
|     // Invalidates the step, and its depending steps in Print.
 | ||||
|  |  | |||
|  | @ -517,9 +517,9 @@ void ArrangeJob::process() | |||
|     { | ||||
|         BOOST_LOG_TRIVIAL(warning)<< "Arrange full params: "<< params.to_json(); | ||||
|         BOOST_LOG_TRIVIAL(info) << boost::format("arrange: items selected before arranging: %1%") % m_selected.size(); | ||||
|         for (auto selected : m_selected) | ||||
|             BOOST_LOG_TRIVIAL(debug) << selected.name << ", extruder: " << selected.extrude_ids.back() << ", bed: " << selected.bed_idx | ||||
|             << ", bed_temp: " << selected.first_bed_temp << ", print_temp: " << selected.print_temp; | ||||
|         for (auto selected : m_selected) { | ||||
|             BOOST_LOG_TRIVIAL(debug) << selected.name << ", extruder: " << selected.extrude_ids.back() << ", bed: " << selected.bed_idx<<", filemant_type:" << selected.filament_temp_type; | ||||
|         } | ||||
|         BOOST_LOG_TRIVIAL(debug) << "items unselected before arrange: "; | ||||
|         for (auto item : m_unselected) | ||||
|             BOOST_LOG_TRIVIAL(debug) << item.name << ", bed: " << item.bed_idx << ", trans: " << item.translation.transpose(); | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Arthur
						Arthur