WIP: PrintRegion refactoring, it finally compiles!

Config/PrintConfig refactoring to support operator< for StaticPrintConfig
derived containers.
This commit is contained in:
Vojtech Bubnik 2021-05-24 14:10:04 +02:00
parent 740773db85
commit e658fe0698
8 changed files with 145 additions and 230 deletions

View File

@ -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;
@ -660,6 +676,7 @@ public:
ConfigOption* clone() const override { return new ConfigOptionIntsTempl(*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
{
@ -1113,6 +1145,8 @@ public:
ConfigOption* clone() const override { return new ConfigOptionPoints(*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); }
@ -1421,6 +1460,7 @@ public:
ConfigOption* clone() const override { return new ConfigOptionEnumGeneric(*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
{

View File

@ -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 &center);
@ -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;

View File

@ -221,8 +221,8 @@ 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 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();

View File

@ -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 = [&region_set](PrintRegionConfig &&config) -> PrintRegion* {
return nullptr;
std::vector<PrintRegion*> region_set;
auto get_create_region = [&region_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)

View File

@ -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

View File

@ -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 &region : 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] = &region - layer_range.volume_regions.data();
}
}
@ -398,105 +400,9 @@ static std::vector<std::vector<ExPolygons>> slices_to_regions(
}
});
}
}
#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);
return slices_by_region;
}
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)
{
@ -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;

View File

@ -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 */

View File

@ -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.