mirror of
				https://github.com/SoftFever/OrcaSlicer.git
				synced 2025-10-30 20:21:12 -06:00 
			
		
		
		
	WIP: PrintRegion refactoring, it finally compiles!
Config/PrintConfig refactoring to support operator< for StaticPrintConfig derived containers.
This commit is contained in:
		
							parent
							
								
									740773db85
								
							
						
					
					
						commit
						e658fe0698
					
				
					 8 changed files with 145 additions and 230 deletions
				
			
		|  | @ -37,6 +37,7 @@ namespace Slic3r { | |||
| 
 | ||||
|     inline bool operator==(const FloatOrPercent& l, const FloatOrPercent& r) throw() { return l.value == r.value && l.percent == r.percent; } | ||||
|     inline bool operator!=(const FloatOrPercent& l, const FloatOrPercent& r) throw() { return !(l == r); } | ||||
|     inline bool operator< (const FloatOrPercent& l, const FloatOrPercent& r) throw() { return l.value < r.value || (l.value == r.value && int(l.percent) < int(r.percent)); } | ||||
| } | ||||
| 
 | ||||
| namespace std { | ||||
|  | @ -230,6 +231,7 @@ public: | |||
| 
 | ||||
|     bool operator==(const T &rhs) const throw() { return this->value == rhs; } | ||||
|     bool operator!=(const T &rhs) const throw() { return this->value != rhs; } | ||||
|     bool operator< (const T &rhs) const throw() { return this->value < rhs; } | ||||
| 
 | ||||
|     size_t hash() const throw() override { return std::hash<T>{}(this->value); } | ||||
| 
 | ||||
|  | @ -467,6 +469,7 @@ public: | |||
|     double                  getFloat()  const override { return this->value; } | ||||
|     ConfigOption*           clone()     const override { return new ConfigOptionFloat(*this); } | ||||
|     bool                    operator==(const ConfigOptionFloat &rhs) const throw() { return this->value == rhs.value; } | ||||
|     bool                    operator< (const ConfigOptionFloat &rhs) const throw() { return this->value <  rhs.value; } | ||||
|      | ||||
|     std::string serialize() const override | ||||
|     { | ||||
|  | @ -508,6 +511,7 @@ public: | |||
|     ConfigOptionType        type()  const override { return static_type(); } | ||||
|     ConfigOption*           clone() const override { return new ConfigOptionFloatsTempl(*this); } | ||||
|     bool                    operator==(const ConfigOptionFloatsTempl &rhs) const throw() { return vectors_equal(this->values, rhs.values); } | ||||
|     bool                    operator< (const ConfigOptionFloatsTempl &rhs) const throw() { return vectors_lower(this->values, rhs.values); } | ||||
|     bool 					operator==(const ConfigOption &rhs) const override { | ||||
|         if (rhs.type() != this->type()) | ||||
|             throw Slic3r::RuntimeError("ConfigOptionFloatsTempl: Comparing incompatible types"); | ||||
|  | @ -598,6 +602,18 @@ protected: | |||
|     		// Not supporting nullable values, the default vector compare is cheaper.
 | ||||
|     		return v1 == v2; | ||||
|     } | ||||
|     static bool vectors_lower(const std::vector<double> &v1, const std::vector<double> &v2) { | ||||
|         if (NULLABLE) { | ||||
|             for (auto it1 = v1.begin(), it2 = v2.begin(); it1 != v1.end() && it2 != v2.end(); ++ it1, ++ it2) { | ||||
|                 auto null1 = int(std::isnan(*it1)); | ||||
|                 auto null2 = int(std::isnan(*it2)); | ||||
|                 return (null1 < null2) || (null1 == null2 && *it1 < *it2); | ||||
|             } | ||||
|             return v1.size() < v2.size(); | ||||
|         } else | ||||
|             // Not supporting nullable values, the default vector compare is cheaper.
 | ||||
|             return v1 < v2; | ||||
|     } | ||||
| 
 | ||||
| private: | ||||
| 	friend class cereal::access; | ||||
|  | @ -658,8 +674,9 @@ public: | |||
|     static ConfigOptionType static_type() { return coInts; } | ||||
|     ConfigOptionType        type()  const override { return static_type(); } | ||||
|     ConfigOption*           clone() const override { return new ConfigOptionIntsTempl(*this); } | ||||
|     ConfigOptionIntsTempl&  operator=(const ConfigOption *opt) { this->set(opt); return *this; } | ||||
|     ConfigOptionIntsTempl&  operator= (const ConfigOption *opt) { this->set(opt); return *this; } | ||||
|     bool                    operator==(const ConfigOptionIntsTempl &rhs) const throw() { return this->values == rhs.values; } | ||||
|     bool                    operator< (const ConfigOptionIntsTempl &rhs) const throw() { return this->values <  rhs.values; } | ||||
|     // Could a special "nil" value be stored inside the vector, indicating undefined value?
 | ||||
|     bool 					nullable() const override { return NULLABLE; } | ||||
|     // Special "nil" value to be stored into the vector if this->supports_nil().
 | ||||
|  | @ -776,6 +793,7 @@ public: | |||
|     ConfigOption*           clone() const override { return new ConfigOptionStrings(*this); } | ||||
|     ConfigOptionStrings&    operator=(const ConfigOption *opt) { this->set(opt); return *this; } | ||||
|     bool                    operator==(const ConfigOptionStrings &rhs) const throw() { return this->values == rhs.values; } | ||||
|     bool                    operator< (const ConfigOptionStrings &rhs) const throw() { return this->values <  rhs.values; } | ||||
|     bool					is_nil(size_t) const override { return false; } | ||||
| 
 | ||||
|     std::string serialize() const override | ||||
|  | @ -969,6 +987,7 @@ public: | |||
|         assert(dynamic_cast<const ConfigOptionVector<FloatOrPercent>*>(&rhs)); | ||||
|         return vectors_equal(this->values, static_cast<const ConfigOptionVector<FloatOrPercent>*>(&rhs)->values); | ||||
|     } | ||||
|     bool                    operator< (const ConfigOptionFloatsOrPercentsTempl &rhs) const throw() { return vectors_lower(this->values, rhs.values); } | ||||
| 
 | ||||
|     // Could a special "nil" value be stored inside the vector, indicating undefined value?
 | ||||
|     bool                    nullable() const override { return NULLABLE; } | ||||
|  | @ -1057,6 +1076,18 @@ protected: | |||
|             // Not supporting nullable values, the default vector compare is cheaper.
 | ||||
|             return v1 == v2; | ||||
|     } | ||||
|     static bool vectors_lower(const std::vector<FloatOrPercent> &v1, const std::vector<FloatOrPercent> &v2) { | ||||
|         if (NULLABLE) { | ||||
|             for (auto it1 = v1.begin(), it2 = v2.begin(); it1 != v1.end() && it2 != v2.end(); ++ it1, ++ it2) { | ||||
|                 auto null1 = int(std::isnan(*it1)); | ||||
|                 auto null2 = int(std::isnan(*it2)); | ||||
|                 return (null1 < null2) || (null1 == null2 && *it1 < *it2); | ||||
|             } | ||||
|             return v1.size() < v2.size(); | ||||
|         } else | ||||
|             // Not supporting nullable values, the default vector compare is cheaper.
 | ||||
|             return v1 < v2; | ||||
|     } | ||||
| 
 | ||||
| private: | ||||
|     friend class cereal::access; | ||||
|  | @ -1077,6 +1108,7 @@ public: | |||
|     ConfigOption*           clone() const override { return new ConfigOptionPoint(*this); } | ||||
|     ConfigOptionPoint&      operator=(const ConfigOption *opt) { this->set(opt); return *this; } | ||||
|     bool                    operator==(const ConfigOptionPoint &rhs) const throw() { return this->value == rhs.value; } | ||||
|     bool                    operator< (const ConfigOptionPoint &rhs) const throw() { return this->value <  rhs.value; } | ||||
| 
 | ||||
|     std::string serialize() const override | ||||
|     { | ||||
|  | @ -1111,8 +1143,10 @@ public: | |||
|     static ConfigOptionType static_type() { return coPoints; } | ||||
|     ConfigOptionType        type()  const override { return static_type(); } | ||||
|     ConfigOption*           clone() const override { return new ConfigOptionPoints(*this); } | ||||
|     ConfigOptionPoints&     operator=(const ConfigOption *opt) { this->set(opt); return *this; } | ||||
|     ConfigOptionPoints&     operator= (const ConfigOption *opt) { this->set(opt); return *this; } | ||||
|     bool                    operator==(const ConfigOptionPoints &rhs) const throw() { return this->values == rhs.values; } | ||||
|     bool                    operator< (const ConfigOptionPoints &rhs) const throw()  | ||||
|         { return std::lexicographical_compare(this->values.begin(), this->values.end(), rhs.values.begin(), rhs.values.end(), [](const auto &l, const auto &r){ return l < r; }); } | ||||
|     bool					is_nil(size_t) const override { return false; } | ||||
| 
 | ||||
|     std::string serialize() const override | ||||
|  | @ -1185,6 +1219,8 @@ public: | |||
|     ConfigOption*           clone() const override { return new ConfigOptionPoint3(*this); } | ||||
|     ConfigOptionPoint3&     operator=(const ConfigOption *opt) { this->set(opt); return *this; } | ||||
|     bool                    operator==(const ConfigOptionPoint3 &rhs) const throw() { return this->value == rhs.value; } | ||||
|     bool                    operator< (const ConfigOptionPoint3 &rhs) const throw()  | ||||
|         { return this->value.x() < rhs.value.x() || (this->value.x() == rhs.value.x() && (this->value.y() < rhs.value.y() || (this->value.y() == rhs.value.y() && this->value.z() < rhs.value.z()))); } | ||||
| 
 | ||||
|     std::string serialize() const override | ||||
|     { | ||||
|  | @ -1222,6 +1258,7 @@ public: | |||
|     ConfigOption*           clone()     const override { return new ConfigOptionBool(*this); } | ||||
|     ConfigOptionBool&       operator=(const ConfigOption *opt) { this->set(opt); return *this; } | ||||
|     bool                    operator==(const ConfigOptionBool &rhs) const throw() { return this->value == rhs.value; } | ||||
|     bool                    operator< (const ConfigOptionBool &rhs) const throw() { return int(this->value) < int(rhs.value); } | ||||
| 
 | ||||
|     std::string serialize() const override | ||||
|     { | ||||
|  | @ -1256,6 +1293,7 @@ public: | |||
|     ConfigOption*           clone() const override { return new ConfigOptionBoolsTempl(*this); } | ||||
|     ConfigOptionBoolsTempl& operator=(const ConfigOption *opt) { this->set(opt); return *this; } | ||||
|     bool                    operator==(const ConfigOptionBoolsTempl &rhs) const throw() { return this->values == rhs.values; } | ||||
|     bool                    operator< (const ConfigOptionBoolsTempl &rhs) const throw() { return this->values <  rhs.values; } | ||||
|     // Could a special "nil" value be stored inside the vector, indicating undefined value?
 | ||||
|     bool 					nullable() const override { return NULLABLE; } | ||||
|     // Special "nil" value to be stored into the vector if this->supports_nil().
 | ||||
|  | @ -1350,6 +1388,7 @@ public: | |||
|     ConfigOption*           clone() const override { return new ConfigOptionEnum<T>(*this); } | ||||
|     ConfigOptionEnum<T>&    operator=(const ConfigOption *opt) { this->set(opt); return *this; } | ||||
|     bool                    operator==(const ConfigOptionEnum<T> &rhs) const throw() { return this->value == rhs.value; } | ||||
|     bool                    operator< (const ConfigOptionEnum<T> &rhs) const throw() { return int(this->value) < int(rhs.value); } | ||||
|     int                     getInt() const override { return (int)this->value; } | ||||
|     void                    setInt(int val) override { this->value = T(val); } | ||||
| 
 | ||||
|  | @ -1419,8 +1458,9 @@ public: | |||
|     static ConfigOptionType     static_type() { return coEnum; } | ||||
|     ConfigOptionType            type()  const override { return static_type(); } | ||||
|     ConfigOption*               clone() const override { return new ConfigOptionEnumGeneric(*this); } | ||||
|     ConfigOptionEnumGeneric&    operator=(const ConfigOption *opt) { this->set(opt); return *this; } | ||||
|     ConfigOptionEnumGeneric&    operator= (const ConfigOption *opt) { this->set(opt); return *this; } | ||||
|     bool                        operator==(const ConfigOptionEnumGeneric &rhs) const throw() { return this->value == rhs.value; } | ||||
|     bool                        operator< (const ConfigOptionEnumGeneric &rhs) const throw() { return this->value <  rhs.value; } | ||||
| 
 | ||||
|     bool operator==(const ConfigOption &rhs) const override | ||||
|     { | ||||
|  |  | |||
|  | @ -54,7 +54,7 @@ using Transform2d    = Eigen::Transform<double, 2, Eigen::Affine, Eigen::DontAli | |||
| using Transform3f    = Eigen::Transform<float,  3, Eigen::Affine, Eigen::DontAlign>; | ||||
| using Transform3d    = Eigen::Transform<double, 3, Eigen::Affine, Eigen::DontAlign>; | ||||
| 
 | ||||
| inline bool operator<(const Vec2d &lhs, const Vec2d &rhs) { return lhs(0) < rhs(0) || (lhs(0) == rhs(0) && lhs(1) < rhs(1)); } | ||||
| inline bool operator<(const Vec2d &lhs, const Vec2d &rhs) { return lhs.x() < rhs.x() || (lhs.x() == rhs.x() && lhs.y() < rhs.y()); } | ||||
| 
 | ||||
| template<int Options> | ||||
| int32_t cross2(const Eigen::MatrixBase<Eigen::Matrix<int32_t, 2, 1, Options>> &v1, const Eigen::MatrixBase<Eigen::Matrix<int32_t, 2, 1, Options>> &v2) = delete; | ||||
|  | @ -62,36 +62,36 @@ int32_t cross2(const Eigen::MatrixBase<Eigen::Matrix<int32_t, 2, 1, Options>> &v | |||
| template<typename T, int Options> | ||||
| inline T cross2(const Eigen::MatrixBase<Eigen::Matrix<T, 2, 1, Options>> &v1, const Eigen::MatrixBase<Eigen::Matrix<T, 2, 1, Options>> &v2) | ||||
| { | ||||
|     return v1(0) * v2(1) - v1(1) * v2(0); | ||||
|     return v1.x() * v2.y() - v1.y() * v2.x(); | ||||
| } | ||||
| 
 | ||||
| template<typename Derived, typename Derived2> | ||||
| inline typename Derived::Scalar cross2(const Eigen::MatrixBase<Derived> &v1, const Eigen::MatrixBase<Derived2> &v2) | ||||
| { | ||||
|     static_assert(std::is_same<typename Derived::Scalar, typename Derived2::Scalar>::value, "cross2(): Scalar types of 1st and 2nd operand must be equal."); | ||||
|     return v1(0) * v2(1) - v1(1) * v2(0); | ||||
|     return v1.x() * v2.y() - v1.y() * v2.x(); | ||||
| } | ||||
| 
 | ||||
| template<typename T, int Options> | ||||
| inline Eigen::Matrix<T, 2, 1, Eigen::DontAlign> perp(const Eigen::MatrixBase<Eigen::Matrix<T, 2, 1, Options>> &v) { return Eigen::Matrix<T, 2, 1, Eigen::DontAlign>(- v.y(), v.x()); } | ||||
| 
 | ||||
| template<class T, int N, int Options> | ||||
| Eigen::Matrix<T, 2, 1, Eigen::DontAlign> to_2d(const Eigen::MatrixBase<Eigen::Matrix<T, N, 1, Options>> &ptN) { return { ptN(0), ptN(1) }; } | ||||
| Eigen::Matrix<T, 2, 1, Eigen::DontAlign> to_2d(const Eigen::MatrixBase<Eigen::Matrix<T, N, 1, Options>> &ptN) { return { ptN.x(), ptN.y() }; } | ||||
| 
 | ||||
| template<class T, int Options> | ||||
| Eigen::Matrix<T, 3, 1, Eigen::DontAlign> to_3d(const Eigen::MatrixBase<Eigen::Matrix<T, 2, 1, Options>> & pt, const T z) { return { pt(0), pt(1), z }; } | ||||
| Eigen::Matrix<T, 3, 1, Eigen::DontAlign> to_3d(const Eigen::MatrixBase<Eigen::Matrix<T, 2, 1, Options>> & pt, const T z) { return { pt.x(), pt.y(), z }; } | ||||
| 
 | ||||
| inline Vec2d   unscale(coord_t x, coord_t y) { return Vec2d(unscale<double>(x), unscale<double>(y)); } | ||||
| inline Vec2d   unscale(const Vec2crd &pt) { return Vec2d(unscale<double>(pt(0)), unscale<double>(pt(1))); } | ||||
| inline Vec2d   unscale(const Vec2d   &pt) { return Vec2d(unscale<double>(pt(0)), unscale<double>(pt(1))); } | ||||
| inline Vec2d   unscale(const Vec2crd &pt) { return Vec2d(unscale<double>(pt.x()), unscale<double>(pt.y())); } | ||||
| inline Vec2d   unscale(const Vec2d   &pt) { return Vec2d(unscale<double>(pt.x()), unscale<double>(pt.y())); } | ||||
| inline Vec3d   unscale(coord_t x, coord_t y, coord_t z) { return Vec3d(unscale<double>(x), unscale<double>(y), unscale<double>(z)); } | ||||
| inline Vec3d   unscale(const Vec3crd &pt) { return Vec3d(unscale<double>(pt(0)), unscale<double>(pt(1)), unscale<double>(pt(2))); } | ||||
| inline Vec3d   unscale(const Vec3d   &pt) { return Vec3d(unscale<double>(pt(0)), unscale<double>(pt(1)), unscale<double>(pt(2))); } | ||||
| inline Vec3d   unscale(const Vec3crd &pt) { return Vec3d(unscale<double>(pt.x()), unscale<double>(pt.y()), unscale<double>(pt.z())); } | ||||
| inline Vec3d   unscale(const Vec3d   &pt) { return Vec3d(unscale<double>(pt.x()), unscale<double>(pt.y()), unscale<double>(pt.z())); } | ||||
| 
 | ||||
| inline std::string to_string(const Vec2crd &pt) { return std::string("[") + std::to_string(pt(0)) + ", " + std::to_string(pt(1)) + "]"; } | ||||
| inline std::string to_string(const Vec2d   &pt) { return std::string("[") + std::to_string(pt(0)) + ", " + std::to_string(pt(1)) + "]"; } | ||||
| inline std::string to_string(const Vec3crd &pt) { return std::string("[") + std::to_string(pt(0)) + ", " + std::to_string(pt(1)) + ", " + std::to_string(pt(2)) + "]"; } | ||||
| inline std::string to_string(const Vec3d   &pt) { return std::string("[") + std::to_string(pt(0)) + ", " + std::to_string(pt(1)) + ", " + std::to_string(pt(2)) + "]"; } | ||||
| inline std::string to_string(const Vec2crd &pt) { return std::string("[") + std::to_string(pt.x()) + ", " + std::to_string(pt.y()) + "]"; } | ||||
| inline std::string to_string(const Vec2d   &pt) { return std::string("[") + std::to_string(pt.x()) + ", " + std::to_string(pt.y()) + "]"; } | ||||
| inline std::string to_string(const Vec3crd &pt) { return std::string("[") + std::to_string(pt.x()) + ", " + std::to_string(pt.y()) + ", " + std::to_string(pt.z()) + "]"; } | ||||
| inline std::string to_string(const Vec3d   &pt) { return std::string("[") + std::to_string(pt.x()) + ", " + std::to_string(pt.y()) + ", " + std::to_string(pt.z()) + "]"; } | ||||
| 
 | ||||
| std::vector<Vec3f> transform(const std::vector<Vec3f>& points, const Transform3f& t); | ||||
| Pointf3s transform(const Pointf3s& points, const Transform3d& t); | ||||
|  | @ -123,19 +123,17 @@ public: | |||
|         return *this; | ||||
|     } | ||||
| 
 | ||||
|     bool operator< (const Point& rhs) const { return (*this)(0) < rhs(0) || ((*this)(0) == rhs(0) && (*this)(1) < rhs(1)); } | ||||
| 
 | ||||
|     Point& operator+=(const Point& rhs) { (*this)(0) += rhs(0); (*this)(1) += rhs(1); return *this; } | ||||
|     Point& operator-=(const Point& rhs) { (*this)(0) -= rhs(0); (*this)(1) -= rhs(1); return *this; } | ||||
| 	Point& operator*=(const double &rhs) { (*this)(0) = coord_t((*this)(0) * rhs); (*this)(1) = coord_t((*this)(1) * rhs); return *this; } | ||||
|     Point operator*(const double &rhs) { return Point((*this)(0) * rhs, (*this)(1) * rhs); } | ||||
|     Point& operator+=(const Point& rhs) { this->x() += rhs.x(); this->y() += rhs.y(); return *this; } | ||||
|     Point& operator-=(const Point& rhs) { this->x() -= rhs.x(); this->y() -= rhs.y(); return *this; } | ||||
| 	Point& operator*=(const double &rhs) { this->x() = coord_t(this->x() * rhs); this->y() = coord_t(this->y() * rhs); return *this; } | ||||
|     Point operator*(const double &rhs) { return Point(this->x() * rhs, this->y() * rhs); } | ||||
| 
 | ||||
|     void   rotate(double angle) { this->rotate(std::cos(angle), std::sin(angle)); } | ||||
|     void   rotate(double cos_a, double sin_a) { | ||||
|         double cur_x = (double)(*this)(0); | ||||
|         double cur_y = (double)(*this)(1); | ||||
|         (*this)(0) = (coord_t)round(cos_a * cur_x - sin_a * cur_y); | ||||
|         (*this)(1) = (coord_t)round(cos_a * cur_y + sin_a * cur_x); | ||||
|         double cur_x = (double)this->x(); | ||||
|         double cur_y = (double)this->y(); | ||||
|         this->x() = (coord_t)round(cos_a * cur_x - sin_a * cur_y); | ||||
|         this->y() = (coord_t)round(cos_a * cur_y + sin_a * cur_x); | ||||
|     } | ||||
| 
 | ||||
|     void   rotate(double angle, const Point ¢er); | ||||
|  | @ -153,6 +151,11 @@ public: | |||
|     Point  projection_onto(const Line &line) const; | ||||
| }; | ||||
| 
 | ||||
| inline bool operator<(const Point &l, const Point &r)  | ||||
| {  | ||||
|     return l.x() < r.x() || (l.x() == r.x() && l.y() < r.y()); | ||||
| } | ||||
| 
 | ||||
| inline bool is_approx(const Point &p1, const Point &p2, coord_t epsilon = coord_t(SCALED_EPSILON)) | ||||
| { | ||||
| 	Point d = (p2 - p1).cwiseAbs(); | ||||
|  | @ -204,7 +207,7 @@ namespace int128 { | |||
| // To be used by std::unordered_map, std::unordered_multimap and friends.
 | ||||
| struct PointHash { | ||||
|     size_t operator()(const Vec2crd &pt) const { | ||||
|         return std::hash<coord_t>()(pt(0)) ^ std::hash<coord_t>()(pt(1)); | ||||
|         return std::hash<coord_t>()(pt.x()) ^ std::hash<coord_t>()(pt.y()); | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
|  | @ -265,7 +268,7 @@ public: | |||
|         const Point *pt = m_point_accessor(value); | ||||
|         if (pt != nullptr) { | ||||
|             // Range of fragment starts around grid_corner, close to pt.
 | ||||
|             auto range = m_map.equal_range(Point((*pt)(0)>>m_grid_log2, (*pt)(1)>>m_grid_log2)); | ||||
|             auto range = m_map.equal_range(Point((*pt).x()>>m_grid_log2, (*pt).y()>>m_grid_log2)); | ||||
|             // Remove the first item.
 | ||||
|             for (auto it = range.first; it != range.second; ++ it) { | ||||
|                 if (it->second == value) { | ||||
|  | @ -284,12 +287,12 @@ public: | |||
|         const ValueType *value_min = nullptr; | ||||
|         double           dist_min = std::numeric_limits<double>::max(); | ||||
|         // Round pt to a closest grid_cell corner.
 | ||||
|         Vec2crd            grid_corner((pt(0)+(m_grid_resolution>>1))>>m_grid_log2, (pt(1)+(m_grid_resolution>>1))>>m_grid_log2); | ||||
|         Vec2crd            grid_corner((pt.x()+(m_grid_resolution>>1))>>m_grid_log2, (pt.y()+(m_grid_resolution>>1))>>m_grid_log2); | ||||
|         // For four neighbors of grid_corner:
 | ||||
|         for (coord_t neighbor_y = -1; neighbor_y < 1; ++ neighbor_y) { | ||||
|             for (coord_t neighbor_x = -1; neighbor_x < 1; ++ neighbor_x) { | ||||
|                 // Range of fragment starts around grid_corner, close to pt.
 | ||||
|                 auto range = m_map.equal_range(Vec2crd(grid_corner(0) + neighbor_x, grid_corner(1) + neighbor_y)); | ||||
|                 auto range = m_map.equal_range(Vec2crd(grid_corner.x() + neighbor_x, grid_corner.y() + neighbor_y)); | ||||
|                 // Find the map entry closest to pt.
 | ||||
|                 for (auto it = range.first; it != range.second; ++it) { | ||||
|                     const ValueType &value = it->second; | ||||
|  | @ -313,14 +316,14 @@ public: | |||
|     std::vector<std::pair<const ValueType*, double>> find_all(const Vec2crd &pt) { | ||||
|         // Iterate over 4 closest grid cells around pt,
 | ||||
|         // Round pt to a closest grid_cell corner.
 | ||||
|         Vec2crd      grid_corner((pt(0)+(m_grid_resolution>>1))>>m_grid_log2, (pt(1)+(m_grid_resolution>>1))>>m_grid_log2); | ||||
|         Vec2crd      grid_corner((pt.x()+(m_grid_resolution>>1))>>m_grid_log2, (pt.y()+(m_grid_resolution>>1))>>m_grid_log2); | ||||
|         // For four neighbors of grid_corner:
 | ||||
|         std::vector<std::pair<const ValueType*, double>> out; | ||||
|         const double r2 = double(m_search_radius) * m_search_radius; | ||||
|         for (coord_t neighbor_y = -1; neighbor_y < 1; ++ neighbor_y) { | ||||
|             for (coord_t neighbor_x = -1; neighbor_x < 1; ++ neighbor_x) { | ||||
|                 // Range of fragment starts around grid_corner, close to pt.
 | ||||
|                 auto range = m_map.equal_range(Vec2crd(grid_corner(0) + neighbor_x, grid_corner(1) + neighbor_y)); | ||||
|                 auto range = m_map.equal_range(Vec2crd(grid_corner.x() + neighbor_x, grid_corner.y() + neighbor_y)); | ||||
|                 // Find the map entry closest to pt.
 | ||||
|                 for (auto it = range.first; it != range.second; ++it) { | ||||
|                     const ValueType &value = it->second; | ||||
|  |  | |||
|  | @ -221,9 +221,9 @@ public: | |||
|     Transform3d                                 trafo_bboxes; | ||||
|     std::vector<ObjectID>                       cached_volume_ids; | ||||
| 
 | ||||
|     size_t ref_cnt_inc() { ++ m_ref_cnt; } | ||||
|     size_t ref_cnt_dec() { if (-- m_ref_cnt == 0) delete this; } | ||||
|     void   clear() { | ||||
|     void ref_cnt_inc() { ++ m_ref_cnt; } | ||||
|     void ref_cnt_dec() { if (-- m_ref_cnt == 0) delete this; } | ||||
|     void clear() { | ||||
|         all_regions.clear(); | ||||
|         layer_ranges.clear(); | ||||
|     } | ||||
|  |  | |||
|  | @ -242,45 +242,6 @@ static t_config_option_keys full_print_config_diffs(const DynamicPrintConfig &cu | |||
|     return full_config_diff; | ||||
| } | ||||
| 
 | ||||
| bool model_volume_list_changed(const ModelObject &model_object_old, const ModelObject &model_object_new, const ModelVolumeType type) | ||||
| { | ||||
|     size_t i_old, i_new; | ||||
|     for (i_old = 0, i_new = 0; i_old < model_object_old.volumes.size() && i_new < model_object_new.volumes.size();) { | ||||
|         const ModelVolume &mv_old = *model_object_old.volumes[i_old]; | ||||
|         const ModelVolume &mv_new = *model_object_new.volumes[i_new]; | ||||
|         if (mv_old.type() != type) { | ||||
|             ++ i_old; | ||||
|             continue; | ||||
|         } | ||||
|         if (mv_new.type() != type) { | ||||
|             ++ i_new; | ||||
|             continue; | ||||
|         } | ||||
|         if (mv_old.id() != mv_new.id()) | ||||
|             return true; | ||||
|         //FIXME test for the content of the mesh!
 | ||||
| 
 | ||||
|         if (!mv_old.get_matrix().isApprox(mv_new.get_matrix())) | ||||
|             return true; | ||||
| 
 | ||||
|         ++ i_old; | ||||
|         ++ i_new; | ||||
|     } | ||||
|     for (; i_old < model_object_old.volumes.size(); ++ i_old) { | ||||
|         const ModelVolume &mv_old = *model_object_old.volumes[i_old]; | ||||
|         if (mv_old.type() == type) | ||||
|             // ModelVolume was deleted.
 | ||||
|             return true; | ||||
|     } | ||||
|     for (; i_new < model_object_new.volumes.size(); ++ i_new) { | ||||
|         const ModelVolume &mv_new = *model_object_new.volumes[i_new]; | ||||
|         if (mv_new.type() == type) | ||||
|             // ModelVolume was added.
 | ||||
|             return true; | ||||
|     } | ||||
|     return false; | ||||
| } | ||||
| 
 | ||||
| // Repository for solving partial overlaps of ModelObject::layer_config_ranges.
 | ||||
| // Here the const DynamicPrintConfig* point to the config in ModelObject::layer_config_ranges.
 | ||||
| class LayerRanges | ||||
|  | @ -290,6 +251,8 @@ public: | |||
|         t_layer_height_range        layer_height_range; | ||||
|         // Config is owned by the associated ModelObject.
 | ||||
|         const DynamicPrintConfig*   config { nullptr }; | ||||
| 
 | ||||
|         bool operator<(const LayerRange &rhs) const throw() { return this->layer_height_range < rhs.layer_height_range; } | ||||
|     }; | ||||
| 
 | ||||
|     LayerRanges() = default; | ||||
|  | @ -323,7 +286,7 @@ public: | |||
|     } | ||||
| 
 | ||||
|     const DynamicPrintConfig* config(const t_layer_height_range &range) const { | ||||
|         auto it = std::lower_bound(m_ranges.begin(), m_ranges.end(), LayerRange { t_layer_height_range(range.first - EPSILON, range.second - EPSILON), nullptr }); | ||||
|         auto it = std::lower_bound(m_ranges.begin(), m_ranges.end(), LayerRange{ { range.first - EPSILON, range.second - EPSILON } }); | ||||
|         // #ys_FIXME_COLOR
 | ||||
|         // assert(it != m_ranges.end());
 | ||||
|         // assert(it == m_ranges.end() || std::abs(it->first.first  - range.first ) < EPSILON);
 | ||||
|  | @ -518,7 +481,7 @@ static BoundingBoxf3 transformed_its_bbox2d(const indexed_triangle_set &its, con | |||
|     BoundingBoxf3 bbox; | ||||
|     for (const stl_triangle_vertex_indices &tri : its.indices) | ||||
|         for (int i = 0; i < 3; ++ i) | ||||
|             bbox.merge(m * its.vertices[tri(i)]); | ||||
|             bbox.merge((m * its.vertices[tri(i)]).cast<double>()); | ||||
|     bbox.min.x() -= offset; | ||||
|     bbox.min.y() -= offset; | ||||
|     bbox.min.x() += offset; | ||||
|  | @ -556,25 +519,25 @@ static void transformed_its_bboxes_in_z_ranges( | |||
|                         float t2 = (z_range.second - p1->z()) / zspan; | ||||
|                         Vec2f p = to_2d(*p1); | ||||
|                         Vec2f v(p2->x() - p1->x(), p2->y() - p1->y()); | ||||
|                         bbox.merge(to_3d((p + v * t1).eval(), float(z_range.first))); | ||||
|                         bbox.merge(to_3d((p + v * t2).eval(), float(z_range.second))); | ||||
|                         bbox.merge((to_3d((p + v * t1).eval(), float(z_range.first))).cast<double>()); | ||||
|                         bbox.merge((to_3d((p + v * t2).eval(), float(z_range.second))).cast<double>()); | ||||
|                     } else { | ||||
|                         // Single intersection with the lower limit.
 | ||||
|                         float t = (z_range.first - p1->z()) / (p2->z() - p1->z()); | ||||
|                         Vec2f v(p2->x() - p1->x(), p2->y() - p1->y()); | ||||
|                         bbox.merge(to_3d((to_2d(*p1) + v * t).eval(), float(z_range.first))); | ||||
|                         bbox.merge(*p2); | ||||
|                         bbox.merge((to_3d((to_2d(*p1) + v * t).eval(), float(z_range.first))).cast<double>()); | ||||
|                         bbox.merge(p2->cast<double>()); | ||||
|                     } | ||||
|                 } else if (p2->z() > z_range.second) { | ||||
|                     // Single intersection with the upper limit.
 | ||||
|                     float t = (z_range.second - p1->z()) / (p2->z() - p1->z()); | ||||
|                     Vec2f v(p2->x() - p1->x(), p2->y() - p1->y()); | ||||
|                     bbox.merge(to_3d((to_2d(*p1) + v * t).eval(), float(z_range.second))); | ||||
|                     bbox.merge(*p1); | ||||
|                     bbox.merge((to_3d((to_2d(*p1) + v * t).eval(), float(z_range.second)).cast<double>())); | ||||
|                     bbox.merge(p1->cast<double>()); | ||||
|                 } else { | ||||
|                     // Both points are inside.
 | ||||
|                     bbox.merge(*p1); | ||||
|                     bbox.merge(*p2); | ||||
|                     bbox.merge(p1->cast<double>()); | ||||
|                     bbox.merge(p2->cast<double>()); | ||||
|                 } | ||||
|                 iprev = iedge; | ||||
|             } | ||||
|  | @ -744,8 +707,8 @@ void update_volume_bboxes( | |||
|                     if (it != volumes_old.end() && it->volume_id == model_volume->id()) | ||||
|                         layer_range.volumes.emplace_back(*it); | ||||
|                 } else | ||||
|                     layer_range.volumes.emplace_back(model_volume->id(), | ||||
|                         transformed_its_bbox2d(model_volume->mesh().its, trafo_for_bbox(object_trafo, model_volume->get_matrix(false)), offset)); | ||||
|                     layer_range.volumes.push_back({ model_volume->id(), | ||||
|                         transformed_its_bbox2d(model_volume->mesh().its, trafo_for_bbox(object_trafo, model_volume->get_matrix(false)), offset) }); | ||||
|             } | ||||
|     } else { | ||||
|         std::vector<std::vector<PrintObjectRegions::VolumeExtents>> volumes_old; | ||||
|  | @ -779,7 +742,7 @@ void update_volume_bboxes( | |||
|                 } else { | ||||
|                     transformed_its_bboxes_in_z_ranges(model_volume->mesh().its, trafo_for_bbox(object_trafo, model_volume->get_matrix(false)), ranges, bboxes, offset); | ||||
|                     for (PrintObjectRegions::LayerRangeRegions &layer_range : layer_ranges) | ||||
|                         layer_range.volumes.emplace_back(model_volume->id(), bboxes[&layer_range - layer_ranges.data()]); | ||||
|                         layer_range.volumes.push_back({ model_volume->id(), bboxes[&layer_range - layer_ranges.data()] }); | ||||
|                 } | ||||
|             } | ||||
|     } | ||||
|  | @ -799,6 +762,7 @@ static PrintObjectRegions* generate_print_object_regions( | |||
|     const PrintRegionConfig                     &default_region_config, | ||||
|     const Transform3d                           &trafo, | ||||
|     size_t                                       num_extruders, | ||||
|     const float                                  xy_size_compensation, | ||||
|     const std::vector<unsigned int>             &painting_extruders) | ||||
| { | ||||
|     // Reuse the old object or generate a new one.
 | ||||
|  | @ -827,11 +791,20 @@ static PrintObjectRegions* generate_print_object_regions( | |||
|             layer_ranges_regions.push_back({ range.layer_height_range, range.config }); | ||||
|     } | ||||
| 
 | ||||
|     update_volume_bboxes(layer_ranges_regions, out->cached_volume_ids, model_volumes, out->trafo_bboxes, std::max(0.f, float(print_object.config().xy_size_compensation())); | ||||
|     update_volume_bboxes(layer_ranges_regions, out->cached_volume_ids, model_volumes, out->trafo_bboxes, std::max(0.f, xy_size_compensation)); | ||||
| 
 | ||||
|     std::set<const PrintRegion*> region_set; | ||||
|     auto get_create_region = [®ion_set](PrintRegionConfig &&config) -> PrintRegion* { | ||||
|         return nullptr; | ||||
|     std::vector<PrintRegion*> region_set; | ||||
|     auto get_create_region = [®ion_set, &all_regions](PrintRegionConfig &&config) -> PrintRegion* { | ||||
|         size_t hash = config.hash(); | ||||
|         auto it = Slic3r::lower_bound_by_predicate(region_set.begin(), region_set.end(), [&config, hash](const PrintRegion* l) { | ||||
|             return l->config_hash() < hash || (l->config_hash() == hash && l->config() < config); }); | ||||
|         if ((*it)->config_hash() == hash && (*it)->config() == config) | ||||
|             return *it; | ||||
|         // Insert into a sorted array, it has O(n) complexity, but the calling algorithm has an O(n^2*log(n)) complexity anyways.
 | ||||
|         all_regions.emplace_back(std::make_unique<PrintRegion>(std::move(config), hash)); | ||||
|         PrintRegion *region = all_regions.back().get(); | ||||
|         region_set.emplace(it, region); | ||||
|         return region; | ||||
|     }; | ||||
| 
 | ||||
|     // Chain the regions in the order they are stored in the volumes list.
 | ||||
|  | @ -1259,11 +1232,8 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_ | |||
|                     num_extruders, | ||||
|                     painting_extruders, | ||||
|                     *print_object_regions, | ||||
|                     [](){ | ||||
|                         // Stop the background process before assigning new configuration to the regions.
 | ||||
|                         t_config_option_keys diff = region.config().diff(region_config); | ||||
|                         update_apply_status(print_object->invalidate_state_by_config_options(region.config(), region_config, diff)); | ||||
|                         region.config_apply_only(region_config, diff, false); | ||||
|                     [&print_object, &update_apply_status](const PrintRegionConfig &old_config, const PrintRegionConfig &new_config, const t_config_option_keys &diff_keys) { | ||||
|                         update_apply_status(print_object.invalidate_state_by_config_options(old_config, new_config, diff_keys)); | ||||
|                     })) { | ||||
|                 // Regions are valid, just keep them.
 | ||||
|             } else { | ||||
|  | @ -1285,9 +1255,10 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_ | |||
|                 print_object_regions, | ||||
|                 print_object.model_object()->volumes, | ||||
|                 LayerRanges(print_object.model_object()->layer_config_ranges), | ||||
|                 model_object_status.print_instances.front().trafo, | ||||
|                 m_default_region_config, | ||||
|                 model_object_status.print_instances.front().trafo, | ||||
|                 num_extruders, | ||||
|                 float(print_object.config().xy_size_compensation.value), | ||||
|                 painting_extruders); | ||||
|         } | ||||
|         for (auto it = it_print_object; it != it_print_object_end; ++it) | ||||
|  |  | |||
|  | @ -346,6 +346,9 @@ public: \ | |||
| #define PRINT_CONFIG_CLASS_ELEMENT_INITIALIZATION(r, data, elem) PRINT_CONFIG_CLASS_ELEMENT_INITIALIZATION2(BOOST_PP_TUPLE_ELEM(1, elem)) | ||||
| #define PRINT_CONFIG_CLASS_ELEMENT_HASH(r, data, elem) boost::hash_combine(seed, BOOST_PP_TUPLE_ELEM(1, elem).hash()); | ||||
| #define PRINT_CONFIG_CLASS_ELEMENT_EQUAL(r, data, elem) if (! (BOOST_PP_TUPLE_ELEM(1, elem) == rhs.BOOST_PP_TUPLE_ELEM(1, elem))) return false; | ||||
| #define PRINT_CONFIG_CLASS_ELEMENT_LOWER(r, data, elem) \ | ||||
|         if (BOOST_PP_TUPLE_ELEM(1, elem) < rhs.BOOST_PP_TUPLE_ELEM(1, elem)) return true; \ | ||||
|         if (! (BOOST_PP_TUPLE_ELEM(1, elem) == rhs.BOOST_PP_TUPLE_ELEM(1, elem))) return false; | ||||
| 
 | ||||
| #define PRINT_CONFIG_CLASS_DEFINE(CLASS_NAME, PARAMETER_DEFINITION_SEQ) \ | ||||
| class CLASS_NAME : public StaticPrintConfig { \ | ||||
|  | @ -364,6 +367,11 @@ public: \ | |||
|         return true; \ | ||||
|     } \ | ||||
|     bool operator!=(const CLASS_NAME &rhs) const throw() { return ! (*this == rhs); } \ | ||||
|     bool operator<(const CLASS_NAME &rhs) const throw() \ | ||||
|     { \ | ||||
|         BOOST_PP_SEQ_FOR_EACH(PRINT_CONFIG_CLASS_ELEMENT_LOWER, _, PARAMETER_DEFINITION_SEQ) \ | ||||
|         return false; \ | ||||
|     } \ | ||||
| protected: \ | ||||
|     void initialize(StaticCacheBase &cache, const char *base_ptr) \ | ||||
|     { \ | ||||
|  | @ -932,6 +940,7 @@ PRINT_CONFIG_CLASS_DERIVED_DEFINE0( | |||
| #undef STATIC_PRINT_CONFIG_CACHE_DERIVED | ||||
| #undef PRINT_CONFIG_CLASS_ELEMENT_DEFINITION | ||||
| #undef PRINT_CONFIG_CLASS_ELEMENT_EQUAL | ||||
| #undef PRINT_CONFIG_CLASS_ELEMENT_LOWER | ||||
| #undef PRINT_CONFIG_CLASS_ELEMENT_HASH | ||||
| #undef PRINT_CONFIG_CLASS_ELEMENT_INITIALIZATION | ||||
| #undef PRINT_CONFIG_CLASS_ELEMENT_INITIALIZATION2 | ||||
|  |  | |||
|  | @ -162,12 +162,12 @@ static std::vector<VolumeSlices> slice_volumes_inner( | |||
|         slicing_ranges.reserve(layer_ranges.size()); | ||||
| 
 | ||||
|     MeshSlicingParamsEx params_base; | ||||
|     params_base.closing_radius = float(print_object_config.slice_closing_radius.value); | ||||
|     params_base.closing_radius = scaled<float>(print_object_config.slice_closing_radius.value); | ||||
|     params_base.extra_offset   = 0; | ||||
|     params_base.trafo          = object_trafo; | ||||
|     params_base.resolution     = scaled<double>(print_config.resolution.value); | ||||
| 
 | ||||
|     const float extra_offset = print_object_config.xy_size_compensation > 0 ? float(print_object_config.xy_size_compensation.value) : 0.f; | ||||
|     const auto extra_offset = print_object_config.xy_size_compensation > 0 ? scaled<float>(print_object_config.xy_size_compensation.value) : 0.f; | ||||
| 
 | ||||
|     for (const ModelVolume *model_volume : model_volumes) | ||||
|         if (model_volume_needs_slicing(*model_volume)) { | ||||
|  | @ -208,6 +208,8 @@ static std::vector<VolumeSlices> slice_volumes_inner( | |||
|             if (! out.empty() && out.back().slices.empty()) | ||||
|                 out.pop_back(); | ||||
|         } | ||||
| 
 | ||||
|     return out; | ||||
| } | ||||
| 
 | ||||
| static inline VolumeSlices& volume_slices_find_by_id(std::vector<VolumeSlices> &volume_slices, const ObjectID id) | ||||
|  | @ -302,7 +304,7 @@ static std::vector<std::vector<ExPolygons>> slices_to_regions( | |||
|             last_volume_idx_of_region.assign(print_object_regions.all_regions.size(), -1); | ||||
|             for (const PrintObjectRegions::VolumeRegion ®ion : layer_range.volume_regions) { | ||||
|                 int region_id = region.region->print_object_region_id(); | ||||
|                 layer_range_regions_to_slices.emplace_back(&volume_slices_find_by_id(volume_slices, region.model_volume->id()), last_volume_idx_of_region[region_id]); | ||||
|                 layer_range_regions_to_slices.push_back({ &volume_slices_find_by_id(volume_slices, region.model_volume->id()), last_volume_idx_of_region[region_id] }); | ||||
|                 last_volume_idx_of_region[region_id] = ®ion - layer_range.volume_regions.data(); | ||||
|             } | ||||
|         } | ||||
|  | @ -398,106 +400,10 @@ static std::vector<std::vector<ExPolygons>> slices_to_regions( | |||
|                 } | ||||
|             }); | ||||
|     } | ||||
| 
 | ||||
|     return slices_by_region; | ||||
| } | ||||
| 
 | ||||
| #if 0 | ||||
| // Z ranges are not applicable to modifier meshes, therefore a single volume will be found in volume_w_zrange at most once.
 | ||||
| std::vector<ExPolygons> PrintObject::slice_modifiers(size_t region_id, const std::vector<float> &slice_zs) const | ||||
| { | ||||
|     std::vector<ExPolygons> out; | ||||
|     if (region_id < m_region_volumes.size()) | ||||
|     { | ||||
|         std::vector<std::vector<t_layer_height_range>> volume_ranges; | ||||
|         const PrintRegionVolumes &volumes_and_ranges = m_region_volumes[region_id]; | ||||
|         volume_ranges.reserve(volumes_and_ranges.volumes.size()); | ||||
|         for (size_t i = 0; i < volumes_and_ranges.volumes.size(); ) { | ||||
|             int                volume_id    = volumes_and_ranges.volumes[i].volume_idx; | ||||
|             const ModelVolume *model_volume = this->model_object()->volumes[volume_id]; | ||||
|             if (model_volume->is_modifier()) { | ||||
|                 std::vector<t_layer_height_range> ranges; | ||||
|                 ranges.emplace_back(volumes_and_ranges.volumes[i].layer_height_range); | ||||
|                 size_t j = i + 1; | ||||
|                 for (; j < volumes_and_ranges.volumes.size() && volume_id == volumes_and_ranges.volumes[j].volume_idx; ++ j) { | ||||
|                     if (! ranges.empty() && std::abs(ranges.back().second - volumes_and_ranges.volumes[j].layer_height_range.first) < EPSILON) | ||||
|                         ranges.back().second = volumes_and_ranges.volumes[j].layer_height_range.second; | ||||
|                     else | ||||
|                         ranges.emplace_back(volumes_and_ranges.volumes[j].layer_height_range); | ||||
|                 } | ||||
|                 volume_ranges.emplace_back(std::move(ranges)); | ||||
|                 i = j; | ||||
|             } else | ||||
|                 ++ i; | ||||
|         } | ||||
| 
 | ||||
|         if (! volume_ranges.empty())  | ||||
|         { | ||||
|             bool equal_ranges = true; | ||||
|             for (size_t i = 1; i < volume_ranges.size(); ++ i) { | ||||
|                 assert(! volume_ranges[i].empty()); | ||||
|                 if (volume_ranges.front() != volume_ranges[i]) { | ||||
|                     equal_ranges = false; | ||||
|                     break; | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             if (equal_ranges && volume_ranges.front().size() == 1 && volume_ranges.front().front() == t_layer_height_range(0, DBL_MAX)) { | ||||
|                 // No modifier in this region was split to layer spans.
 | ||||
|                 std::vector<const ModelVolume*> volumes; | ||||
|                 for (const PrintRegionVolumes::VolumeWithZRange &volume_w_zrange : m_region_volumes[region_id].volumes) { | ||||
|                     const ModelVolume *volume = this->model_object()->volumes[volume_w_zrange.volume_idx]; | ||||
|                     if (volume->is_modifier()) | ||||
|                         volumes.emplace_back(volume); | ||||
|                 } | ||||
|                 out = this->slice_volumes(slice_zs, MeshSlicingParams::SlicingMode::Regular, volumes); | ||||
|             } else { | ||||
|                 // Some modifier in this region was split to layer spans.
 | ||||
|                 std::vector<char> merge; | ||||
|                 for (size_t region_id = 0; region_id < m_region_volumes.size(); ++ region_id) { | ||||
|                     const PrintRegionVolumes &volumes_and_ranges = m_region_volumes[region_id]; | ||||
|                     for (size_t i = 0; i < volumes_and_ranges.volumes.size(); ) { | ||||
|                         int                volume_id    = volumes_and_ranges.volumes[i].volume_idx; | ||||
|                         const ModelVolume *model_volume = this->model_object()->volumes[volume_id]; | ||||
|                         if (model_volume->is_modifier()) { | ||||
|                             BOOST_LOG_TRIVIAL(debug) << "Slicing modifiers - volume " << volume_id; | ||||
|                             // Find the ranges of this volume. Ranges in volumes_and_ranges must not overlap for a single volume.
 | ||||
|                             std::vector<t_layer_height_range> ranges; | ||||
|                             ranges.emplace_back(volumes_and_ranges.volumes[i].layer_height_range); | ||||
|                             size_t j = i + 1; | ||||
|                             for (; j < volumes_and_ranges.volumes.size() && volume_id == volumes_and_ranges.volumes[j].volume_idx; ++ j) | ||||
|                                 ranges.emplace_back(volumes_and_ranges.volumes[j].layer_height_range); | ||||
|                             // slicing in parallel
 | ||||
|                             std::vector<ExPolygons> this_slices = this->slice_volume(slice_zs, ranges, MeshSlicingParams::SlicingMode::Regular, *model_volume); | ||||
|                             // Variable this_slices could be empty if no value of slice_zs is within any of the ranges of this volume.
 | ||||
|                             if (out.empty()) { | ||||
|                                 out = std::move(this_slices); | ||||
|                                 merge.assign(out.size(), false); | ||||
|                             } else if (!this_slices.empty()) { | ||||
|                                 assert(out.size() == this_slices.size()); | ||||
|                                 for (size_t i = 0; i < out.size(); ++ i) | ||||
|                                     if (! this_slices[i].empty()) { | ||||
|                                         if (! out[i].empty()) { | ||||
|                                             append(out[i], this_slices[i]); | ||||
|                                             merge[i] = true; | ||||
|                                         } else | ||||
|                                             out[i] = std::move(this_slices[i]); | ||||
|                                     } | ||||
|                             } | ||||
|                             i = j; | ||||
|                         } else | ||||
|                             ++ i; | ||||
|                     } | ||||
|                 } | ||||
|                 for (size_t i = 0; i < merge.size(); ++ i) | ||||
|                     if (merge[i]) | ||||
|                         out[i] = union_ex(out[i]); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     return out; | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| std::string fix_slicing_errors(LayerPtrs &layers, const std::function<void()> &throw_if_canceled) | ||||
| { | ||||
|     // Collect layers with slicing errors.
 | ||||
|  | @ -725,8 +631,8 @@ void PrintObject::slice_volumes() | |||
| 
 | ||||
|     BOOST_LOG_TRIVIAL(debug) << "Slicing volumes - make_slices in parallel - begin"; | ||||
|     { | ||||
|         // Compensation value, scaled.
 | ||||
|         const float xy_compensation_scaled              = float(scale_(m_config.xy_size_compensation.value)); | ||||
|         // Compensation value, scaled. Only applying the negative scaling here, as the positive scaling has already been applied during slicing.
 | ||||
|         const auto  xy_compensation_scaled              = scaled<float>(std::min(m_config.xy_size_compensation.value, 0.)); | ||||
|         const float elephant_foot_compensation_scaled 	= (m_config.raft_layers == 0) ?  | ||||
|         	// Only enable Elephant foot compensation if printing directly on the print bed.
 | ||||
|             float(scale_(m_config.elefant_foot_compensation.value)) : | ||||
|  | @ -735,7 +641,7 @@ void PrintObject::slice_volumes() | |||
| 	    ExPolygons  lslices_1st_layer; | ||||
| 	    tbb::parallel_for( | ||||
| 	        tbb::blocked_range<size_t>(0, m_layers.size()), | ||||
| 			[this, upscaled, clipped, xy_compensation_scaled, elephant_foot_compensation_scaled, &lslices_1st_layer] | ||||
| 			[this, xy_compensation_scaled, elephant_foot_compensation_scaled, &lslices_1st_layer] | ||||
| 				(const tbb::blocked_range<size_t>& range) { | ||||
| 	            for (size_t layer_id = range.begin(); layer_id < range.end(); ++ layer_id) { | ||||
| 	                m_print->throw_if_canceled(); | ||||
|  | @ -743,8 +649,6 @@ void PrintObject::slice_volumes() | |||
| 	                // Apply size compensation and perform clipping of multi-part objects.
 | ||||
| 	                float elfoot = (layer_id == 0) ? elephant_foot_compensation_scaled : 0.f; | ||||
| 	                if (layer->m_regions.size() == 1) { | ||||
| 	                	assert(! upscaled); | ||||
| 	                	assert(! clipped); | ||||
| 	                    // Optimized version for a single region layer.
 | ||||
| 	                    // Single region, growing or shrinking.
 | ||||
| 	                    LayerRegion *layerm = layer->m_regions.front(); | ||||
|  | @ -763,35 +667,15 @@ void PrintObject::slice_volumes() | |||
| 										(delta == 0.f) ? lslices_1st_layer : offset_ex(lslices_1st_layer, delta),  | ||||
| 	                            		layerm->flow(frExternalPerimeter), unscale<double>(elfoot))), | ||||
| 								stInternal); | ||||
| 							if (xy_compensation_scaled != 0.f) | ||||
| 							if (xy_compensation_scaled < 0.f) | ||||
| 								lslices_1st_layer = offset_ex(std::move(lslices_1st_layer), xy_compensation_scaled); | ||||
| 	                    } else if (xy_compensation_scaled != 0.f) { | ||||
| 	                    } else if (xy_compensation_scaled < 0.f) { | ||||
| 	                        // Apply the XY compensation.
 | ||||
| 	                        layerm->slices.set( | ||||
|                                 offset_ex(to_expolygons(std::move(layerm->slices.surfaces)), xy_compensation_scaled), | ||||
| 	                            stInternal); | ||||
| 	                    } | ||||
| 	                } else { | ||||
| 	                    bool upscale   = ! upscaled && xy_compensation_scaled > 0.f; | ||||
| 	                    bool clip      = ! clipped && m_config.clip_multipart_objects.value; | ||||
| 	                    if (upscale || clip) { | ||||
| 	                        // Multiple regions, growing or just clipping one region by the other.
 | ||||
| 	                        // When clipping the regions, priority is given to the first regions.
 | ||||
| 	                        Polygons processed; | ||||
| 	            			for (size_t region_id = 0; region_id < layer->m_regions.size(); ++ region_id) { | ||||
| 	                            LayerRegion *layerm = layer->m_regions[region_id]; | ||||
| 	            				ExPolygons slices = to_expolygons(std::move(layerm->slices.surfaces)); | ||||
| 	            				if (upscale) | ||||
| 	            					slices = offset_ex(std::move(slices), xy_compensation_scaled); | ||||
| 	                            if (region_id > 0 && clip) | ||||
| 	                                // Trim by the slices of already processed regions.
 | ||||
| 	                                slices = diff_ex(slices, processed); | ||||
| 	                            if (clip && (region_id + 1 < layer->m_regions.size())) | ||||
| 	                                // Collect the already processed regions to trim the to be processed regions.
 | ||||
| 	                                polygons_append(processed, slices); | ||||
| 	                            layerm->slices.set(std::move(slices), stInternal); | ||||
| 	                        } | ||||
| 	                    } | ||||
| 	                    if (xy_compensation_scaled < 0.f || elfoot > 0.f) { | ||||
| 	                        // Apply the negative XY compensation.
 | ||||
| 	                        Polygons trimming; | ||||
|  |  | |||
|  | @ -1021,9 +1021,17 @@ static void make_expolygons(const Polygons &loops, const float closing_radius, c | |||
| //    double safety_offset = scale_(0.0499);
 | ||||
|     // 0.0001 is set to satisfy GH #520, #1029, #1364
 | ||||
|     assert(closing_radius >= 0); | ||||
|     assert(extra_offset >= 0); | ||||
|     double offset_out = + scale_(closing_radius + extra_offset); | ||||
|     double offset_in  = - scale_(closing_radius); | ||||
|     // Allowing negative extra_offset for shrinking a contour. This likely only makes sense if slicing a single region only.
 | ||||
|     //assert(extra_offset >= 0);
 | ||||
|     double offset_out; | ||||
|     double offset_in; | ||||
|     if (closing_radius >= extra_offset) { | ||||
|         offset_out = + scale_(closing_radius); | ||||
|         offset_in  = - scale_(closing_radius - extra_offset); | ||||
|     } else { | ||||
|         offset_out = + scale_(extra_offset); | ||||
|         offset_in  = 0.; | ||||
|     } | ||||
| 
 | ||||
|     /* The following line is commented out because it can generate wrong polygons,
 | ||||
|        see for example issue #661 */ | ||||
|  |  | |||
|  | @ -32,9 +32,9 @@ struct MeshSlicingParams | |||
| 
 | ||||
| struct MeshSlicingParamsEx : public MeshSlicingParams | ||||
| { | ||||
|     // Morphological closing operation when creating output expolygons.
 | ||||
|     // Morphological closing operation when creating output expolygons, scaled!
 | ||||
|     float         closing_radius { 0 }; | ||||
|     // Positive offset applied when creating output expolygons.
 | ||||
|     // Positive offset applied when creating output expolygons, scaled!
 | ||||
|     float         extra_offset { 0 }; | ||||
|     // Resolution for contour simplification, scaled!
 | ||||
|     // 0 = don't simplify.
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Vojtech Bubnik
						Vojtech Bubnik