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
@ -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
|
||||
{
|
||||
|
@ -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,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();
|
||||
|
@ -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,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;
|
||||
|
@ -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…
Reference in New Issue
Block a user