diff --git a/src/libslic3r/Config.hpp b/src/libslic3r/Config.hpp index adda2654e..30d76d610 100644 --- a/src/libslic3r/Config.hpp +++ b/src/libslic3r/Config.hpp @@ -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{}(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 &v1, const std::vector &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*>(&rhs)); return vectors_equal(this->values, static_cast*>(&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 &v1, const std::vector &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(*this); } ConfigOptionEnum& operator=(const ConfigOption *opt) { this->set(opt); return *this; } bool operator==(const ConfigOptionEnum &rhs) const throw() { return this->value == rhs.value; } + bool operator< (const ConfigOptionEnum &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 { diff --git a/src/libslic3r/Point.hpp b/src/libslic3r/Point.hpp index 12870b713..36d85ef90 100644 --- a/src/libslic3r/Point.hpp +++ b/src/libslic3r/Point.hpp @@ -54,7 +54,7 @@ using Transform2d = Eigen::Transform; using Transform3d = Eigen::Transform; -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 int32_t cross2(const Eigen::MatrixBase> &v1, const Eigen::MatrixBase> &v2) = delete; @@ -62,36 +62,36 @@ int32_t cross2(const Eigen::MatrixBase> &v template inline T cross2(const Eigen::MatrixBase> &v1, const Eigen::MatrixBase> &v2) { - return v1(0) * v2(1) - v1(1) * v2(0); + return v1.x() * v2.y() - v1.y() * v2.x(); } template inline typename Derived::Scalar cross2(const Eigen::MatrixBase &v1, const Eigen::MatrixBase &v2) { static_assert(std::is_same::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 inline Eigen::Matrix perp(const Eigen::MatrixBase> &v) { return Eigen::Matrix(- v.y(), v.x()); } template -Eigen::Matrix to_2d(const Eigen::MatrixBase> &ptN) { return { ptN(0), ptN(1) }; } +Eigen::Matrix to_2d(const Eigen::MatrixBase> &ptN) { return { ptN.x(), ptN.y() }; } template -Eigen::Matrix to_3d(const Eigen::MatrixBase> & pt, const T z) { return { pt(0), pt(1), z }; } +Eigen::Matrix to_3d(const Eigen::MatrixBase> & pt, const T z) { return { pt.x(), pt.y(), z }; } inline Vec2d unscale(coord_t x, coord_t y) { return Vec2d(unscale(x), unscale(y)); } -inline Vec2d unscale(const Vec2crd &pt) { return Vec2d(unscale(pt(0)), unscale(pt(1))); } -inline Vec2d unscale(const Vec2d &pt) { return Vec2d(unscale(pt(0)), unscale(pt(1))); } +inline Vec2d unscale(const Vec2crd &pt) { return Vec2d(unscale(pt.x()), unscale(pt.y())); } +inline Vec2d unscale(const Vec2d &pt) { return Vec2d(unscale(pt.x()), unscale(pt.y())); } inline Vec3d unscale(coord_t x, coord_t y, coord_t z) { return Vec3d(unscale(x), unscale(y), unscale(z)); } -inline Vec3d unscale(const Vec3crd &pt) { return Vec3d(unscale(pt(0)), unscale(pt(1)), unscale(pt(2))); } -inline Vec3d unscale(const Vec3d &pt) { return Vec3d(unscale(pt(0)), unscale(pt(1)), unscale(pt(2))); } +inline Vec3d unscale(const Vec3crd &pt) { return Vec3d(unscale(pt.x()), unscale(pt.y()), unscale(pt.z())); } +inline Vec3d unscale(const Vec3d &pt) { return Vec3d(unscale(pt.x()), unscale(pt.y()), unscale(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 transform(const std::vector& 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()(pt(0)) ^ std::hash()(pt(1)); + return std::hash()(pt.x()) ^ std::hash()(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::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> 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> 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; diff --git a/src/libslic3r/Print.hpp b/src/libslic3r/Print.hpp index a90c76a91..1cc87d9d9 100644 --- a/src/libslic3r/Print.hpp +++ b/src/libslic3r/Print.hpp @@ -221,9 +221,9 @@ public: Transform3d trafo_bboxes; std::vector 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(); } diff --git a/src/libslic3r/PrintApply.cpp b/src/libslic3r/PrintApply.cpp index 3dc27a5b5..f428971fe 100644 --- a/src/libslic3r/PrintApply.cpp +++ b/src/libslic3r/PrintApply.cpp @@ -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()); 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()); + bbox.merge((to_3d((p + v * t2).eval(), float(z_range.second))).cast()); } 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()); + bbox.merge(p2->cast()); } } 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())); + bbox.merge(p1->cast()); } else { // Both points are inside. - bbox.merge(*p1); - bbox.merge(*p2); + bbox.merge(p1->cast()); + bbox.merge(p2->cast()); } 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> 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 &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 region_set; - auto get_create_region = [®ion_set](PrintRegionConfig &&config) -> PrintRegion* { - return nullptr; + std::vector 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(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) diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index 2ba6d4cbd..0d94513d6 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -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 diff --git a/src/libslic3r/PrintObjectSlice.cpp b/src/libslic3r/PrintObjectSlice.cpp index 961eaefb0..1b54cfb77 100644 --- a/src/libslic3r/PrintObjectSlice.cpp +++ b/src/libslic3r/PrintObjectSlice.cpp @@ -162,12 +162,12 @@ static std::vector 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(print_object_config.slice_closing_radius.value); params_base.extra_offset = 0; params_base.trafo = object_trafo; params_base.resolution = scaled(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(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 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 &volume_slices, const ObjectID id) @@ -302,7 +304,7 @@ static std::vector> 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> 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 PrintObject::slice_modifiers(size_t region_id, const std::vector &slice_zs) const -{ - std::vector out; - if (region_id < m_region_volumes.size()) - { - std::vector> 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 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 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 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 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 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 &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(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(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& 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(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; diff --git a/src/libslic3r/TriangleMeshSlicer.cpp b/src/libslic3r/TriangleMeshSlicer.cpp index e27766fb8..dac931724 100644 --- a/src/libslic3r/TriangleMeshSlicer.cpp +++ b/src/libslic3r/TriangleMeshSlicer.cpp @@ -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 */ diff --git a/src/libslic3r/TriangleMeshSlicer.hpp b/src/libslic3r/TriangleMeshSlicer.hpp index 3a144d834..4b8740d48 100644 --- a/src/libslic3r/TriangleMeshSlicer.hpp +++ b/src/libslic3r/TriangleMeshSlicer.hpp @@ -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.