diff options
Diffstat (limited to 'xs/src/libslic3r')
79 files changed, 3978 insertions, 2924 deletions
diff --git a/xs/src/libslic3r/BoundingBox.cpp b/xs/src/libslic3r/BoundingBox.cpp index 4355cd61b..d3cca7ff2 100644 --- a/xs/src/libslic3r/BoundingBox.cpp +++ b/xs/src/libslic3r/BoundingBox.cpp @@ -7,9 +7,9 @@ namespace Slic3r { template BoundingBoxBase<Point>::BoundingBoxBase(const std::vector<Point> &points); -template BoundingBoxBase<Pointf>::BoundingBoxBase(const std::vector<Pointf> &points); +template BoundingBoxBase<Vec2d>::BoundingBoxBase(const std::vector<Vec2d> &points); -template BoundingBox3Base<Pointf3>::BoundingBox3Base(const std::vector<Pointf3> &points); +template BoundingBox3Base<Vec3d>::BoundingBox3Base(const std::vector<Vec3d> &points); BoundingBox::BoundingBox(const Lines &lines) { @@ -22,23 +22,21 @@ BoundingBox::BoundingBox(const Lines &lines) *this = BoundingBox(points); } -void -BoundingBox::polygon(Polygon* polygon) const +void BoundingBox::polygon(Polygon* polygon) const { polygon->points.clear(); polygon->points.resize(4); - polygon->points[0].x = this->min.x; - polygon->points[0].y = this->min.y; - polygon->points[1].x = this->max.x; - polygon->points[1].y = this->min.y; - polygon->points[2].x = this->max.x; - polygon->points[2].y = this->max.y; - polygon->points[3].x = this->min.x; - polygon->points[3].y = this->max.y; + polygon->points[0](0) = this->min(0); + polygon->points[0](1) = this->min(1); + polygon->points[1](0) = this->max(0); + polygon->points[1](1) = this->min(1); + polygon->points[2](0) = this->max(0); + polygon->points[2](1) = this->max(1); + polygon->points[3](0) = this->min(0); + polygon->points[3](1) = this->max(1); } -Polygon -BoundingBox::polygon() const +Polygon BoundingBox::polygon() const { Polygon p; this->polygon(&p); @@ -50,8 +48,8 @@ BoundingBox BoundingBox::rotated(double angle) const BoundingBox out; out.merge(this->min.rotated(angle)); out.merge(this->max.rotated(angle)); - out.merge(Point(this->min.x, this->max.y).rotated(angle)); - out.merge(Point(this->max.x, this->min.y).rotated(angle)); + out.merge(Point(this->min(0), this->max(1)).rotated(angle)); + out.merge(Point(this->max(0), this->min(1)).rotated(angle)); return out; } @@ -60,36 +58,35 @@ BoundingBox BoundingBox::rotated(double angle, const Point ¢er) const BoundingBox out; out.merge(this->min.rotated(angle, center)); out.merge(this->max.rotated(angle, center)); - out.merge(Point(this->min.x, this->max.y).rotated(angle, center)); - out.merge(Point(this->max.x, this->min.y).rotated(angle, center)); + out.merge(Point(this->min(0), this->max(1)).rotated(angle, center)); + out.merge(Point(this->max(0), this->min(1)).rotated(angle, center)); return out; } template <class PointClass> void BoundingBoxBase<PointClass>::scale(double factor) { - this->min.scale(factor); - this->max.scale(factor); + this->min *= factor; + this->max *= factor; } template void BoundingBoxBase<Point>::scale(double factor); -template void BoundingBoxBase<Pointf>::scale(double factor); -template void BoundingBoxBase<Pointf3>::scale(double factor); +template void BoundingBoxBase<Vec2d>::scale(double factor); +template void BoundingBoxBase<Vec3d>::scale(double factor); template <class PointClass> void BoundingBoxBase<PointClass>::merge(const PointClass &point) { if (this->defined) { - this->min.x = std::min(point.x, this->min.x); - this->min.y = std::min(point.y, this->min.y); - this->max.x = std::max(point.x, this->max.x); - this->max.y = std::max(point.y, this->max.y); + this->min = this->min.cwiseMin(point); + this->max = this->max.cwiseMax(point); } else { - this->min = this->max = point; + this->min = point; + this->max = point; this->defined = true; } } template void BoundingBoxBase<Point>::merge(const Point &point); -template void BoundingBoxBase<Pointf>::merge(const Pointf &point); +template void BoundingBoxBase<Vec2d>::merge(const Vec2d &point); template <class PointClass> void BoundingBoxBase<PointClass>::merge(const std::vector<PointClass> &points) @@ -97,18 +94,16 @@ BoundingBoxBase<PointClass>::merge(const std::vector<PointClass> &points) this->merge(BoundingBoxBase(points)); } template void BoundingBoxBase<Point>::merge(const Points &points); -template void BoundingBoxBase<Pointf>::merge(const Pointfs &points); +template void BoundingBoxBase<Vec2d>::merge(const Pointfs &points); template <class PointClass> void BoundingBoxBase<PointClass>::merge(const BoundingBoxBase<PointClass> &bb) { - assert(bb.defined || bb.min.x >= bb.max.x || bb.min.y >= bb.max.y); + assert(bb.defined || bb.min(0) >= bb.max(0) || bb.min(1) >= bb.max(1)); if (bb.defined) { if (this->defined) { - this->min.x = std::min(bb.min.x, this->min.x); - this->min.y = std::min(bb.min.y, this->min.y); - this->max.x = std::max(bb.max.x, this->max.x); - this->max.y = std::max(bb.max.y, this->max.y); + this->min = this->min.cwiseMin(bb.min); + this->max = this->max.cwiseMax(bb.max); } else { this->min = bb.min; this->max = bb.max; @@ -117,120 +112,121 @@ BoundingBoxBase<PointClass>::merge(const BoundingBoxBase<PointClass> &bb) } } template void BoundingBoxBase<Point>::merge(const BoundingBoxBase<Point> &bb); -template void BoundingBoxBase<Pointf>::merge(const BoundingBoxBase<Pointf> &bb); +template void BoundingBoxBase<Vec2d>::merge(const BoundingBoxBase<Vec2d> &bb); template <class PointClass> void BoundingBox3Base<PointClass>::merge(const PointClass &point) { if (this->defined) { - this->min.z = std::min(point.z, this->min.z); - this->max.z = std::max(point.z, this->max.z); + this->min = this->min.cwiseMin(point); + this->max = this->max.cwiseMax(point); + } else { + this->min = point; + this->max = point; + this->defined = true; } - BoundingBoxBase<PointClass>::merge(point); } -template void BoundingBox3Base<Pointf3>::merge(const Pointf3 &point); +template void BoundingBox3Base<Vec3d>::merge(const Vec3d &point); template <class PointClass> void BoundingBox3Base<PointClass>::merge(const std::vector<PointClass> &points) { this->merge(BoundingBox3Base(points)); } -template void BoundingBox3Base<Pointf3>::merge(const Pointf3s &points); +template void BoundingBox3Base<Vec3d>::merge(const Pointf3s &points); template <class PointClass> void BoundingBox3Base<PointClass>::merge(const BoundingBox3Base<PointClass> &bb) { - assert(bb.defined || bb.min.x >= bb.max.x || bb.min.y >= bb.max.y || bb.min.z >= bb.max.z); + assert(bb.defined || bb.min(0) >= bb.max(0) || bb.min(1) >= bb.max(1) || bb.min(2) >= bb.max(2)); if (bb.defined) { if (this->defined) { - this->min.z = std::min(bb.min.z, this->min.z); - this->max.z = std::max(bb.max.z, this->max.z); + this->min = this->min.cwiseMin(bb.min); + this->max = this->max.cwiseMax(bb.max); + } else { + this->min = bb.min; + this->max = bb.max; + this->defined = true; } - BoundingBoxBase<PointClass>::merge(bb); } } -template void BoundingBox3Base<Pointf3>::merge(const BoundingBox3Base<Pointf3> &bb); +template void BoundingBox3Base<Vec3d>::merge(const BoundingBox3Base<Vec3d> &bb); template <class PointClass> PointClass BoundingBoxBase<PointClass>::size() const { - return PointClass(this->max.x - this->min.x, this->max.y - this->min.y); + return PointClass(this->max(0) - this->min(0), this->max(1) - this->min(1)); } template Point BoundingBoxBase<Point>::size() const; -template Pointf BoundingBoxBase<Pointf>::size() const; +template Vec2d BoundingBoxBase<Vec2d>::size() const; template <class PointClass> PointClass BoundingBox3Base<PointClass>::size() const { - return PointClass(this->max.x - this->min.x, this->max.y - this->min.y, this->max.z - this->min.z); + return PointClass(this->max(0) - this->min(0), this->max(1) - this->min(1), this->max(2) - this->min(2)); } -template Pointf3 BoundingBox3Base<Pointf3>::size() const; +template Vec3d BoundingBox3Base<Vec3d>::size() const; template <class PointClass> double BoundingBoxBase<PointClass>::radius() const { assert(this->defined); - double x = this->max.x - this->min.x; - double y = this->max.y - this->min.y; + double x = this->max(0) - this->min(0); + double y = this->max(1) - this->min(1); return 0.5 * sqrt(x*x+y*y); } template double BoundingBoxBase<Point>::radius() const; -template double BoundingBoxBase<Pointf>::radius() const; +template double BoundingBoxBase<Vec2d>::radius() const; template <class PointClass> double BoundingBox3Base<PointClass>::radius() const { - double x = this->max.x - this->min.x; - double y = this->max.y - this->min.y; - double z = this->max.z - this->min.z; + double x = this->max(0) - this->min(0); + double y = this->max(1) - this->min(1); + double z = this->max(2) - this->min(2); return 0.5 * sqrt(x*x+y*y+z*z); } -template double BoundingBox3Base<Pointf3>::radius() const; +template double BoundingBox3Base<Vec3d>::radius() const; template <class PointClass> void BoundingBoxBase<PointClass>::offset(coordf_t delta) { - this->min.translate(-delta, -delta); - this->max.translate(delta, delta); + PointClass v(delta, delta); + this->min -= v; + this->max += v; } template void BoundingBoxBase<Point>::offset(coordf_t delta); -template void BoundingBoxBase<Pointf>::offset(coordf_t delta); +template void BoundingBoxBase<Vec2d>::offset(coordf_t delta); template <class PointClass> void BoundingBox3Base<PointClass>::offset(coordf_t delta) { - this->min.translate(-delta, -delta, -delta); - this->max.translate(delta, delta, delta); + PointClass v(delta, delta, delta); + this->min -= v; + this->max += v; } -template void BoundingBox3Base<Pointf3>::offset(coordf_t delta); +template void BoundingBox3Base<Vec3d>::offset(coordf_t delta); template <class PointClass> PointClass BoundingBoxBase<PointClass>::center() const { - return PointClass( - (this->max.x + this->min.x)/2, - (this->max.y + this->min.y)/2 - ); + return (this->min + this->max) / 2; } template Point BoundingBoxBase<Point>::center() const; -template Pointf BoundingBoxBase<Pointf>::center() const; +template Vec2d BoundingBoxBase<Vec2d>::center() const; template <class PointClass> PointClass BoundingBox3Base<PointClass>::center() const { - return PointClass( - (this->max.x + this->min.x)/2, - (this->max.y + this->min.y)/2, - (this->max.z + this->min.z)/2 - ); + return (this->min + this->max) / 2; } -template Pointf3 BoundingBox3Base<Pointf3>::center() const; +template Vec3d BoundingBox3Base<Vec3d>::center() const; template <class PointClass> coordf_t BoundingBox3Base<PointClass>::max_size() const { PointClass s = size(); - return std::max(s.x, std::max(s.y, s.z)); + return std::max(s(0), std::max(s(1), s(2))); } -template coordf_t BoundingBox3Base<Pointf3>::max_size() const; +template coordf_t BoundingBox3Base<Vec3d>::max_size() const; // Align a coordinate to a grid. The coordinate may be negative, // the aligned value will never be bigger than the original one. @@ -248,46 +244,40 @@ static inline coord_t _align_to_grid(const coord_t coord, const coord_t spacing) void BoundingBox::align_to_grid(const coord_t cell_size) { if (this->defined) { - min.x = _align_to_grid(min.x, cell_size); - min.y = _align_to_grid(min.y, cell_size); + min(0) = _align_to_grid(min(0), cell_size); + min(1) = _align_to_grid(min(1), cell_size); } } -BoundingBoxf3 BoundingBoxf3::transformed(const std::vector<float>& matrix) const +BoundingBoxf3 BoundingBoxf3::transformed(const Transform3d& matrix) const { - Eigen::Matrix<float, 3, 8> vertices; - - vertices(0, 0) = (float)min.x; vertices(1, 0) = (float)min.y; vertices(2, 0) = (float)min.z; - vertices(0, 1) = (float)max.x; vertices(1, 1) = (float)min.y; vertices(2, 1) = (float)min.z; - vertices(0, 2) = (float)max.x; vertices(1, 2) = (float)max.y; vertices(2, 2) = (float)min.z; - vertices(0, 3) = (float)min.x; vertices(1, 3) = (float)max.y; vertices(2, 3) = (float)min.z; - vertices(0, 4) = (float)min.x; vertices(1, 4) = (float)min.y; vertices(2, 4) = (float)max.z; - vertices(0, 5) = (float)max.x; vertices(1, 5) = (float)min.y; vertices(2, 5) = (float)max.z; - vertices(0, 6) = (float)max.x; vertices(1, 6) = (float)max.y; vertices(2, 6) = (float)max.z; - vertices(0, 7) = (float)min.x; vertices(1, 7) = (float)max.y; vertices(2, 7) = (float)max.z; - - Eigen::Transform<float, 3, Eigen::Affine> m; - ::memcpy((void*)m.data(), (const void*)matrix.data(), 16 * sizeof(float)); - Eigen::Matrix<float, 3, 8> transf_vertices = m * vertices.colwise().homogeneous(); - - float min_x = transf_vertices(0, 0); - float max_x = transf_vertices(0, 0); - float min_y = transf_vertices(1, 0); - float max_y = transf_vertices(1, 0); - float min_z = transf_vertices(2, 0); - float max_z = transf_vertices(2, 0); + typedef Eigen::Matrix<double, 3, 8, Eigen::DontAlign> Vertices; + + Vertices src_vertices; + src_vertices(0, 0) = min(0); src_vertices(1, 0) = min(1); src_vertices(2, 0) = min(2); + src_vertices(0, 1) = max(0); src_vertices(1, 1) = min(1); src_vertices(2, 1) = min(2); + src_vertices(0, 2) = max(0); src_vertices(1, 2) = max(1); src_vertices(2, 2) = min(2); + src_vertices(0, 3) = min(0); src_vertices(1, 3) = max(1); src_vertices(2, 3) = min(2); + src_vertices(0, 4) = min(0); src_vertices(1, 4) = min(1); src_vertices(2, 4) = max(2); + src_vertices(0, 5) = max(0); src_vertices(1, 5) = min(1); src_vertices(2, 5) = max(2); + src_vertices(0, 6) = max(0); src_vertices(1, 6) = max(1); src_vertices(2, 6) = max(2); + src_vertices(0, 7) = min(0); src_vertices(1, 7) = max(1); src_vertices(2, 7) = max(2); + + Vertices dst_vertices = matrix * src_vertices.colwise().homogeneous(); + + Vec3d v_min(dst_vertices(0, 0), dst_vertices(1, 0), dst_vertices(2, 0)); + Vec3d v_max = v_min; for (int i = 1; i < 8; ++i) { - min_x = std::min(min_x, transf_vertices(0, i)); - max_x = std::max(max_x, transf_vertices(0, i)); - min_y = std::min(min_y, transf_vertices(1, i)); - max_y = std::max(max_y, transf_vertices(1, i)); - min_z = std::min(min_z, transf_vertices(2, i)); - max_z = std::max(max_z, transf_vertices(2, i)); + for (int j = 0; j < 3; ++j) + { + v_min(j) = std::min(v_min(j), dst_vertices(j, i)); + v_max(j) = std::max(v_max(j), dst_vertices(j, i)); + } } - return BoundingBoxf3(Pointf3((coordf_t)min_x, (coordf_t)min_y, (coordf_t)min_z), Pointf3((coordf_t)max_x, (coordf_t)max_y, (coordf_t)max_z)); + return BoundingBoxf3(v_min, v_max); } } diff --git a/xs/src/libslic3r/BoundingBox.hpp b/xs/src/libslic3r/BoundingBox.hpp index 5324dbe3b..db56c765c 100644 --- a/xs/src/libslic3r/BoundingBox.hpp +++ b/xs/src/libslic3r/BoundingBox.hpp @@ -7,11 +7,6 @@ namespace Slic3r { -typedef Point Size; -typedef Point3 Size3; -typedef Pointf Sizef; -typedef Pointf3 Sizef3; - template <class PointClass> class BoundingBoxBase { @@ -20,25 +15,22 @@ public: PointClass max; bool defined; - BoundingBoxBase() : defined(false) {}; + BoundingBoxBase() : defined(false), min(PointClass::Zero()), max(PointClass::Zero()) {} BoundingBoxBase(const PointClass &pmin, const PointClass &pmax) : - min(pmin), max(pmax), defined(pmin.x < pmax.x && pmin.y < pmax.y) {} - BoundingBoxBase(const std::vector<PointClass>& points) + min(pmin), max(pmax), defined(pmin(0) < pmax(0) && pmin(1) < pmax(1)) {} + BoundingBoxBase(const std::vector<PointClass>& points) : min(PointClass::Zero()), max(PointClass::Zero()) { if (points.empty()) CONFESS("Empty point set supplied to BoundingBoxBase constructor"); typename std::vector<PointClass>::const_iterator it = points.begin(); - this->min.x = this->max.x = it->x; - this->min.y = this->max.y = it->y; - for (++it; it != points.end(); ++it) - { - this->min.x = std::min(it->x, this->min.x); - this->min.y = std::min(it->y, this->min.y); - this->max.x = std::max(it->x, this->max.x); - this->max.y = std::max(it->y, this->max.y); + this->min = *it; + this->max = *it; + for (++ it; it != points.end(); ++ it) { + this->min = this->min.cwiseMin(*it); + this->max = this->max.cwiseMax(*it); } - this->defined = (this->min.x < this->max.x) && (this->min.y < this->max.y); + this->defined = (this->min(0) < this->max(0)) && (this->min(1) < this->max(1)); } void merge(const PointClass &point); void merge(const std::vector<PointClass> &points); @@ -46,17 +38,17 @@ public: void scale(double factor); PointClass size() const; double radius() const; - void translate(coordf_t x, coordf_t y) { assert(this->defined); this->min.translate(x, y); this->max.translate(x, y); } - void translate(const Pointf &pos) { this->translate(pos.x, pos.y); } + void translate(coordf_t x, coordf_t y) { assert(this->defined); PointClass v(x, y); this->min += v; this->max += v; } + void translate(const Vec2d &v) { this->min += v; this->max += v; } void offset(coordf_t delta); PointClass center() const; bool contains(const PointClass &point) const { - return point.x >= this->min.x && point.x <= this->max.x - && point.y >= this->min.y && point.y <= this->max.y; + return point(0) >= this->min(0) && point(0) <= this->max(0) + && point(1) >= this->min(1) && point(1) <= this->max(1); } bool overlap(const BoundingBoxBase<PointClass> &other) const { - return ! (this->max.x < other.min.x || this->min.x > other.max.x || - this->max.y < other.min.y || this->min.y > other.max.y); + return ! (this->max(0) < other.min(0) || this->min(0) > other.max(0) || + this->max(1) < other.min(1) || this->min(1) > other.max(1)); } bool operator==(const BoundingBoxBase<PointClass> &rhs) { return this->min == rhs.min && this->max == rhs.max; } bool operator!=(const BoundingBoxBase<PointClass> &rhs) { return ! (*this == rhs); } @@ -69,35 +61,33 @@ public: BoundingBox3Base() : BoundingBoxBase<PointClass>() {}; BoundingBox3Base(const PointClass &pmin, const PointClass &pmax) : BoundingBoxBase<PointClass>(pmin, pmax) - { if (pmin.z >= pmax.z) BoundingBoxBase<PointClass>::defined = false; } + { if (pmin(2) >= pmax(2)) BoundingBoxBase<PointClass>::defined = false; } BoundingBox3Base(const std::vector<PointClass>& points) - : BoundingBoxBase<PointClass>(points) { if (points.empty()) CONFESS("Empty point set supplied to BoundingBox3Base constructor"); - typename std::vector<PointClass>::const_iterator it = points.begin(); - this->min.z = this->max.z = it->z; - for (++it; it != points.end(); ++it) - { - this->min.z = std::min(it->z, this->min.z); - this->max.z = std::max(it->z, this->max.z); + this->min = *it; + this->max = *it; + for (++ it; it != points.end(); ++ it) { + this->min = this->min.cwiseMin(*it); + this->max = this->max.cwiseMax(*it); } - this->defined &= (this->min.z < this->max.z); + this->defined = (this->min(0) < this->max(0)) && (this->min(1) < this->max(1)) && (this->min(2) < this->max(2)); } void merge(const PointClass &point); void merge(const std::vector<PointClass> &points); void merge(const BoundingBox3Base<PointClass> &bb); PointClass size() const; double radius() const; - void translate(coordf_t x, coordf_t y, coordf_t z) { this->min.translate(x, y, z); this->max.translate(x, y, z); } - void translate(const Pointf3 &pos) { this->translate(pos.x, pos.y, pos.z); } + void translate(coordf_t x, coordf_t y, coordf_t z) { assert(this->defined); PointClass v(x, y, z); this->min += v; this->max += v; } + void translate(const Vec3d &v) { this->min += v; this->max += v; } void offset(coordf_t delta); PointClass center() const; coordf_t max_size() const; bool contains(const PointClass &point) const { - return BoundingBoxBase<PointClass>::contains(point) && point.z >= this->min.z && point.z <= this->max.z; + return BoundingBoxBase<PointClass>::contains(point) && point(2) >= this->min(2) && point(2) <= this->max(2); } bool contains(const BoundingBox3Base<PointClass>& other) const { @@ -105,7 +95,7 @@ public: } bool intersects(const BoundingBox3Base<PointClass>& other) const { - return (this->min.x < other.max.x) && (this->max.x > other.min.x) && (this->min.y < other.max.y) && (this->max.y > other.min.y) && (this->min.z < other.max.z) && (this->max.z > other.min.z); + return (this->min(0) < other.max(0)) && (this->max(0) > other.min(0)) && (this->min(1) < other.max(1)) && (this->max(1) > other.min(1)) && (this->min(2) < other.max(2)) && (this->max(2) > other.min(2)); } }; @@ -130,42 +120,42 @@ public: friend BoundingBox get_extents_rotated(const Points &points, double angle); }; -class BoundingBox3 : public BoundingBox3Base<Point3> +class BoundingBox3 : public BoundingBox3Base<Vec3crd> { public: - BoundingBox3() : BoundingBox3Base<Point3>() {}; - BoundingBox3(const Point3 &pmin, const Point3 &pmax) : BoundingBox3Base<Point3>(pmin, pmax) {}; - BoundingBox3(const Points3& points) : BoundingBox3Base<Point3>(points) {}; + BoundingBox3() : BoundingBox3Base<Vec3crd>() {}; + BoundingBox3(const Vec3crd &pmin, const Vec3crd &pmax) : BoundingBox3Base<Vec3crd>(pmin, pmax) {}; + BoundingBox3(const Points3& points) : BoundingBox3Base<Vec3crd>(points) {}; }; -class BoundingBoxf : public BoundingBoxBase<Pointf> +class BoundingBoxf : public BoundingBoxBase<Vec2d> { public: - BoundingBoxf() : BoundingBoxBase<Pointf>() {}; - BoundingBoxf(const Pointf &pmin, const Pointf &pmax) : BoundingBoxBase<Pointf>(pmin, pmax) {}; - BoundingBoxf(const std::vector<Pointf> &points) : BoundingBoxBase<Pointf>(points) {}; + BoundingBoxf() : BoundingBoxBase<Vec2d>() {}; + BoundingBoxf(const Vec2d &pmin, const Vec2d &pmax) : BoundingBoxBase<Vec2d>(pmin, pmax) {}; + BoundingBoxf(const std::vector<Vec2d> &points) : BoundingBoxBase<Vec2d>(points) {}; }; -class BoundingBoxf3 : public BoundingBox3Base<Pointf3> +class BoundingBoxf3 : public BoundingBox3Base<Vec3d> { public: - BoundingBoxf3() : BoundingBox3Base<Pointf3>() {}; - BoundingBoxf3(const Pointf3 &pmin, const Pointf3 &pmax) : BoundingBox3Base<Pointf3>(pmin, pmax) {}; - BoundingBoxf3(const std::vector<Pointf3> &points) : BoundingBox3Base<Pointf3>(points) {}; + BoundingBoxf3() : BoundingBox3Base<Vec3d>() {}; + BoundingBoxf3(const Vec3d &pmin, const Vec3d &pmax) : BoundingBox3Base<Vec3d>(pmin, pmax) {}; + BoundingBoxf3(const std::vector<Vec3d> &points) : BoundingBox3Base<Vec3d>(points) {}; - BoundingBoxf3 transformed(const std::vector<float>& matrix) const; + BoundingBoxf3 transformed(const Transform3d& matrix) const; }; template<typename VT> inline bool empty(const BoundingBoxBase<VT> &bb) { - return ! bb.defined || bb.min.x >= bb.max.x || bb.min.y >= bb.max.y; + return ! bb.defined || bb.min(0) >= bb.max(0) || bb.min(1) >= bb.max(1); } template<typename VT> inline bool empty(const BoundingBox3Base<VT> &bb) { - return ! bb.defined || bb.min.x >= bb.max.x || bb.min.y >= bb.max.y || bb.min.z >= bb.max.z; + return ! bb.defined || bb.min(0) >= bb.max(0) || bb.min(1) >= bb.max(1) || bb.min(2) >= bb.max(2); } } // namespace Slic3r diff --git a/xs/src/libslic3r/BridgeDetector.cpp b/xs/src/libslic3r/BridgeDetector.cpp index a5272683f..ccc3505ce 100644 --- a/xs/src/libslic3r/BridgeDetector.cpp +++ b/xs/src/libslic3r/BridgeDetector.cpp @@ -102,16 +102,16 @@ bool BridgeDetector::detect_angle(double bridge_direction_override) // Get an oriented bounding box around _anchor_regions. BoundingBox bbox = get_extents_rotated(this->_anchor_regions, - angle); // Cover the region with line segments. - lines.reserve((bbox.max.y - bbox.min.y + this->spacing) / this->spacing); + lines.reserve((bbox.max(1) - bbox.min(1) + this->spacing) / this->spacing); double s = sin(angle); double c = cos(angle); //FIXME Vojtech: The lines shall be spaced half the line width from the edge, but then // some of the test cases fail. Need to adjust the test cases then? -// for (coord_t y = bbox.min.y + this->spacing / 2; y <= bbox.max.y; y += this->spacing) - for (coord_t y = bbox.min.y; y <= bbox.max.y; y += this->spacing) +// for (coord_t y = bbox.min(1) + this->spacing / 2; y <= bbox.max(1); y += this->spacing) + for (coord_t y = bbox.min(1); y <= bbox.max(1); y += this->spacing) lines.push_back(Line( - Point((coord_t)round(c * bbox.min.x - s * y), (coord_t)round(c * y + s * bbox.min.x)), - Point((coord_t)round(c * bbox.max.x - s * y), (coord_t)round(c * y + s * bbox.max.x)))); + Point((coord_t)round(c * bbox.min(0) - s * y), (coord_t)round(c * y + s * bbox.min(0))), + Point((coord_t)round(c * bbox.max(0) - s * y), (coord_t)round(c * y + s * bbox.max(0))))); } double total_length = 0; @@ -182,9 +182,9 @@ std::vector<double> BridgeDetector::bridge_direction_candidates() const /* we also test angles of each open supporting edge (this finds the optimal angle for C-shaped supports) */ - for (Polylines::const_iterator edge = this->_edges.begin(); edge != this->_edges.end(); ++edge) - if (! edge->first_point().coincides_with(edge->last_point())) - angles.push_back(Line(edge->first_point(), edge->last_point()).direction()); + for (const Polyline &edge : this->_edges) + if (edge.first_point() != edge.last_point()) + angles.push_back(Line(edge.first_point(), edge.last_point()).direction()); // remove duplicates double min_resolution = PI/180.0; // 1 degree @@ -282,10 +282,12 @@ BridgeDetector::unsupported_edges(double angle, Polylines* unsupported) const extrusions would be anchored within such length (i.e. a slightly non-parallel bridging direction might still benefit from anchors if long enough) double angle_tolerance = PI / 180.0 * 5.0; */ - for (Lines::const_iterator line = unsupported_lines.begin(); line != unsupported_lines.end(); ++line) { - if (!Slic3r::Geometry::directions_parallel(line->direction(), angle)) - unsupported->push_back(*line); - } + for (const Line &line : unsupported_lines) + if (! Slic3r::Geometry::directions_parallel(line.direction(), angle)) { + unsupported->emplace_back(Polyline()); + unsupported->back().points.emplace_back(line.a); + unsupported->back().points.emplace_back(line.b); + } } /* diff --git a/xs/src/libslic3r/ClipperUtils.cpp b/xs/src/libslic3r/ClipperUtils.cpp index 31a12aa77..f00e908ce 100644 --- a/xs/src/libslic3r/ClipperUtils.cpp +++ b/xs/src/libslic3r/ClipperUtils.cpp @@ -171,7 +171,7 @@ Slic3rMultiPoint_to_ClipperPath(const MultiPoint &input) { ClipperLib::Path retval; for (Points::const_iterator pit = input.points.begin(); pit != input.points.end(); ++pit) - retval.push_back(ClipperLib::IntPoint( (*pit).x, (*pit).y )); + retval.push_back(ClipperLib::IntPoint( (*pit)(0), (*pit)(1) )); return retval; } @@ -181,7 +181,7 @@ Slic3rMultiPoint_to_ClipperPath_reversed(const Slic3r::MultiPoint &input) ClipperLib::Path output; output.reserve(input.points.size()); for (Slic3r::Points::const_reverse_iterator pit = input.points.rbegin(); pit != input.points.rend(); ++pit) - output.push_back(ClipperLib::IntPoint( (*pit).x, (*pit).y )); + output.push_back(ClipperLib::IntPoint( (*pit)(0), (*pit)(1) )); return output; } @@ -595,26 +595,26 @@ Polylines _clipper_pl(ClipperLib::ClipType clipType, const Polygons &subject, co to recombine continuous polylines. */ for (size_t i = 0; i < retval.size(); ++i) { for (size_t j = i+1; j < retval.size(); ++j) { - if (retval[i].points.back().coincides_with(retval[j].points.front())) { + if (retval[i].points.back() == retval[j].points.front()) { /* If last point of i coincides with first point of j, append points of j to i and delete j */ retval[i].points.insert(retval[i].points.end(), retval[j].points.begin()+1, retval[j].points.end()); retval.erase(retval.begin() + j); --j; - } else if (retval[i].points.front().coincides_with(retval[j].points.back())) { + } else if (retval[i].points.front() == retval[j].points.back()) { /* If first point of i coincides with last point of j, prepend points of j to i and delete j */ retval[i].points.insert(retval[i].points.begin(), retval[j].points.begin(), retval[j].points.end()-1); retval.erase(retval.begin() + j); --j; - } else if (retval[i].points.front().coincides_with(retval[j].points.front())) { + } else if (retval[i].points.front() == retval[j].points.front()) { /* Since Clipper does not preserve orientation of polylines, also check the case when first point of i coincides with first point of j. */ retval[j].reverse(); retval[i].points.insert(retval[i].points.begin(), retval[j].points.begin(), retval[j].points.end()-1); retval.erase(retval.begin() + j); --j; - } else if (retval[i].points.back().coincides_with(retval[j].points.back())) { + } else if (retval[i].points.back() == retval[j].points.back()) { /* Since Clipper does not preserve orientation of polylines, also check the case when last point of i coincides with last point of j. */ retval[j].reverse(); @@ -634,8 +634,8 @@ _clipper_ln(ClipperLib::ClipType clipType, const Lines &subject, const Polygons // convert Lines to Polylines Polylines polylines; polylines.reserve(subject.size()); - for (Lines::const_iterator line = subject.begin(); line != subject.end(); ++line) - polylines.push_back(*line); + for (const Line &line : subject) + polylines.emplace_back(Polyline(line.a, line.b)); // perform operation polylines = _clipper_pl(clipType, polylines, clip, safety_offset_); diff --git a/xs/src/libslic3r/Config.cpp b/xs/src/libslic3r/Config.cpp index 5db093c5c..e7442d773 100644 --- a/xs/src/libslic3r/Config.cpp +++ b/xs/src/libslic3r/Config.cpp @@ -592,7 +592,7 @@ void StaticConfig::set_defaults() t_config_option_keys StaticConfig::keys() const { t_config_option_keys keys; - assert(this->def != nullptr); + assert(this->def() != nullptr); for (const auto &opt_def : this->def()->options) if (this->option(opt_def.first) != nullptr) keys.push_back(opt_def.first); diff --git a/xs/src/libslic3r/Config.hpp b/xs/src/libslic3r/Config.hpp index 377bdbea4..e3cd14335 100644 --- a/xs/src/libslic3r/Config.hpp +++ b/xs/src/libslic3r/Config.hpp @@ -49,9 +49,9 @@ enum ConfigOptionType { coPercents = coPercent + coVectorType, // a fraction or an absolute value coFloatOrPercent = 5, - // single 2d point. Currently not used. + // single 2d point (Point2f). Currently not used. coPoint = 6, - // vector of 2d points. Currently used for the definition of the print bed and for the extruder offsets. + // vector of 2d points (Point2f). Currently used for the definition of the print bed and for the extruder offsets. coPoints = coPoint + coVectorType, // single boolean value coBool = 7, @@ -622,11 +622,11 @@ public: } }; -class ConfigOptionPoint : public ConfigOptionSingle<Pointf> +class ConfigOptionPoint : public ConfigOptionSingle<Vec2d> { public: - ConfigOptionPoint() : ConfigOptionSingle<Pointf>(Pointf(0,0)) {} - explicit ConfigOptionPoint(const Pointf &value) : ConfigOptionSingle<Pointf>(value) {} + ConfigOptionPoint() : ConfigOptionSingle<Vec2d>(Vec2d(0,0)) {} + explicit ConfigOptionPoint(const Vec2d &value) : ConfigOptionSingle<Vec2d>(value) {} static ConfigOptionType static_type() { return coPoint; } ConfigOptionType type() const override { return static_type(); } @@ -637,9 +637,9 @@ public: std::string serialize() const override { std::ostringstream ss; - ss << this->value.x; + ss << this->value(0); ss << ","; - ss << this->value.y; + ss << this->value(1); return ss.str(); } @@ -647,18 +647,18 @@ public: { UNUSED(append); char dummy; - return sscanf(str.data(), " %lf , %lf %c", &this->value.x, &this->value.y, &dummy) == 2 || - sscanf(str.data(), " %lf x %lf %c", &this->value.x, &this->value.y, &dummy) == 2; + return sscanf(str.data(), " %lf , %lf %c", &this->value(0), &this->value(1), &dummy) == 2 || + sscanf(str.data(), " %lf x %lf %c", &this->value(0), &this->value(1), &dummy) == 2; } }; -class ConfigOptionPoints : public ConfigOptionVector<Pointf> +class ConfigOptionPoints : public ConfigOptionVector<Vec2d> { public: - ConfigOptionPoints() : ConfigOptionVector<Pointf>() {} - explicit ConfigOptionPoints(size_t n, const Pointf &value) : ConfigOptionVector<Pointf>(n, value) {} - explicit ConfigOptionPoints(std::initializer_list<Pointf> il) : ConfigOptionVector<Pointf>(std::move(il)) {} - explicit ConfigOptionPoints(const std::vector<Pointf> &values) : ConfigOptionVector<Pointf>(values) {} + ConfigOptionPoints() : ConfigOptionVector<Vec2d>() {} + explicit ConfigOptionPoints(size_t n, const Vec2d &value) : ConfigOptionVector<Vec2d>(n, value) {} + explicit ConfigOptionPoints(std::initializer_list<Vec2d> il) : ConfigOptionVector<Vec2d>(std::move(il)) {} + explicit ConfigOptionPoints(const std::vector<Vec2d> &values) : ConfigOptionVector<Vec2d>(values) {} static ConfigOptionType static_type() { return coPoints; } ConfigOptionType type() const override { return static_type(); } @@ -671,9 +671,9 @@ public: std::ostringstream ss; for (Pointfs::const_iterator it = this->values.begin(); it != this->values.end(); ++it) { if (it - this->values.begin() != 0) ss << ","; - ss << it->x; + ss << (*it)(0); ss << "x"; - ss << it->y; + ss << (*it)(1); } return ss.str(); } @@ -696,13 +696,13 @@ public: std::istringstream is(str); std::string point_str; while (std::getline(is, point_str, ',')) { - Pointf point; + Vec2d point(Vec2d::Zero()); std::istringstream iss(point_str); std::string coord_str; if (std::getline(iss, coord_str, 'x')) { - std::istringstream(coord_str) >> point.x; + std::istringstream(coord_str) >> point(0); if (std::getline(iss, coord_str, 'x')) { - std::istringstream(coord_str) >> point.y; + std::istringstream(coord_str) >> point(1); } } this->values.push_back(point); @@ -821,12 +821,7 @@ public: bool deserialize(const std::string &str, bool append = false) override { UNUSED(append); - const t_config_enum_values &enum_keys_map = ConfigOptionEnum<T>::get_enum_values(); - auto it = enum_keys_map.find(str); - if (it == enum_keys_map.end()) - return false; - this->value = static_cast<T>(it->second); - return true; + return from_string(str, this->value); } static bool has(T value) @@ -838,7 +833,7 @@ public: } // Map from an enum name to an enum integer value. - static t_config_enum_names& get_enum_names() + static const t_config_enum_names& get_enum_names() { static t_config_enum_names names; if (names.empty()) { @@ -855,7 +850,17 @@ public: return names; } // Map from an enum name to an enum integer value. - static t_config_enum_values& get_enum_values(); + static const t_config_enum_values& get_enum_values(); + + static bool from_string(const std::string &str, T &value) + { + const t_config_enum_values &enum_keys_map = ConfigOptionEnum<T>::get_enum_values(); + auto it = enum_keys_map.find(str); + if (it == enum_keys_map.end()) + return false; + value = static_cast<T>(it->second); + return true; + } }; // Generic enum configuration value. @@ -900,7 +905,7 @@ public: // What type? bool, int, string etc. ConfigOptionType type = coNone; // Default value of this option. The default value object is owned by ConfigDef, it is released in its destructor. - ConfigOption *default_value = nullptr; + const ConfigOption *default_value = nullptr; // Usually empty. // Special values - "i_enum_open", "f_enum_open" to provide combo box for int or float selection, @@ -958,7 +963,7 @@ public: std::vector<std::string> enum_labels; // For enums (when type == coEnum). Maps enum_values to enums. // Initialized by ConfigOptionEnum<xxx>::get_enum_values() - t_config_enum_values *enum_keys_map = nullptr; + const t_config_enum_values *enum_keys_map = nullptr; bool has_enum_value(const std::string &value) const { for (const std::string &v : enum_values) @@ -1030,7 +1035,7 @@ public: TYPE* option(const t_config_option_key &opt_key, bool create = false) { ConfigOption *opt = this->optptr(opt_key, create); - assert(opt == nullptr || opt->type() == TYPE::static_type()); +// assert(opt == nullptr || opt->type() == TYPE::static_type()); return (opt == nullptr || opt->type() != TYPE::static_type()) ? nullptr : static_cast<TYPE*>(opt); } template<typename TYPE> diff --git a/xs/src/libslic3r/EdgeGrid.cpp b/xs/src/libslic3r/EdgeGrid.cpp index 733ff2ad7..50f424e6d 100644 --- a/xs/src/libslic3r/EdgeGrid.cpp +++ b/xs/src/libslic3r/EdgeGrid.cpp @@ -117,15 +117,15 @@ void EdgeGrid::Grid::create_from_m_contours(coord_t resolution) m_bbox.merge(pts[j]); } coord_t eps = 16; - m_bbox.min.x -= eps; - m_bbox.min.y -= eps; - m_bbox.max.x += eps; - m_bbox.max.y += eps; + m_bbox.min(0) -= eps; + m_bbox.min(1) -= eps; + m_bbox.max(0) += eps; + m_bbox.max(1) += eps; // 2) Initialize the edge grid. m_resolution = resolution; - m_cols = (m_bbox.max.x - m_bbox.min.x + m_resolution - 1) / m_resolution; - m_rows = (m_bbox.max.y - m_bbox.min.y + m_resolution - 1) / m_resolution; + m_cols = (m_bbox.max(0) - m_bbox.min(0) + m_resolution - 1) / m_resolution; + m_rows = (m_bbox.max(1) - m_bbox.min(1) + m_resolution - 1) / m_resolution; m_cells.assign(m_rows * m_cols, Cell()); // 3) First round of contour rasterization, count the edges per grid cell. @@ -135,15 +135,15 @@ void EdgeGrid::Grid::create_from_m_contours(coord_t resolution) // End points of the line segment. Slic3r::Point p1(pts[j]); Slic3r::Point p2 = pts[(j + 1 == pts.size()) ? 0 : j + 1]; - p1.x -= m_bbox.min.x; - p1.y -= m_bbox.min.y; - p2.x -= m_bbox.min.x; - p2.y -= m_bbox.min.y; + p1(0) -= m_bbox.min(0); + p1(1) -= m_bbox.min(1); + p2(0) -= m_bbox.min(0); + p2(1) -= m_bbox.min(1); // Get the cells of the end points. - coord_t ix = p1.x / m_resolution; - coord_t iy = p1.y / m_resolution; - coord_t ixb = p2.x / m_resolution; - coord_t iyb = p2.y / m_resolution; + coord_t ix = p1(0) / m_resolution; + coord_t iy = p1(1) / m_resolution; + coord_t ixb = p2(0) / m_resolution; + coord_t iyb = p2(1) / m_resolution; assert(ix >= 0 && ix < m_cols); assert(iy >= 0 && iy < m_rows); assert(ixb >= 0 && ixb < m_cols); @@ -154,13 +154,13 @@ void EdgeGrid::Grid::create_from_m_contours(coord_t resolution) // Both ends fall into the same cell. continue; // Raster the centeral part of the line. - coord_t dx = std::abs(p2.x - p1.x); - coord_t dy = std::abs(p2.y - p1.y); - if (p1.x < p2.x) { - int64_t ex = int64_t((ix + 1)*m_resolution - p1.x) * int64_t(dy); - if (p1.y < p2.y) { + coord_t dx = std::abs(p2(0) - p1(0)); + coord_t dy = std::abs(p2(1) - p1(1)); + if (p1(0) < p2(0)) { + int64_t ex = int64_t((ix + 1)*m_resolution - p1(0)) * int64_t(dy); + if (p1(1) < p2(1)) { // x positive, y positive - int64_t ey = int64_t((iy + 1)*m_resolution - p1.y) * int64_t(dx); + int64_t ey = int64_t((iy + 1)*m_resolution - p1(1)) * int64_t(dx); do { assert(ix <= ixb && iy <= iyb); if (ex < ey) { @@ -185,7 +185,7 @@ void EdgeGrid::Grid::create_from_m_contours(coord_t resolution) } else { // x positive, y non positive - int64_t ey = int64_t(p1.y - iy*m_resolution) * int64_t(dx); + int64_t ey = int64_t(p1(1) - iy*m_resolution) * int64_t(dx); do { assert(ix <= ixb && iy >= iyb); if (ex <= ey) { @@ -203,10 +203,10 @@ void EdgeGrid::Grid::create_from_m_contours(coord_t resolution) } } else { - int64_t ex = int64_t(p1.x - ix*m_resolution) * int64_t(dy); - if (p1.y < p2.y) { + int64_t ex = int64_t(p1(0) - ix*m_resolution) * int64_t(dy); + if (p1(1) < p2(1)) { // x non positive, y positive - int64_t ey = int64_t((iy + 1)*m_resolution - p1.y) * int64_t(dx); + int64_t ey = int64_t((iy + 1)*m_resolution - p1(1)) * int64_t(dx); do { assert(ix >= ixb && iy <= iyb); if (ex < ey) { @@ -225,7 +225,7 @@ void EdgeGrid::Grid::create_from_m_contours(coord_t resolution) } else { // x non positive, y non positive - int64_t ey = int64_t(p1.y - iy*m_resolution) * int64_t(dx); + int64_t ey = int64_t(p1(1) - iy*m_resolution) * int64_t(dx); do { assert(ix >= ixb && iy >= iyb); if (ex < ey) { @@ -279,15 +279,15 @@ void EdgeGrid::Grid::create_from_m_contours(coord_t resolution) // End points of the line segment. Slic3r::Point p1(pts[j]); Slic3r::Point p2 = pts[(j + 1 == pts.size()) ? 0 : j + 1]; - p1.x -= m_bbox.min.x; - p1.y -= m_bbox.min.y; - p2.x -= m_bbox.min.x; - p2.y -= m_bbox.min.y; + p1(0) -= m_bbox.min(0); + p1(1) -= m_bbox.min(1); + p2(0) -= m_bbox.min(0); + p2(1) -= m_bbox.min(1); // Get the cells of the end points. - coord_t ix = p1.x / m_resolution; - coord_t iy = p1.y / m_resolution; - coord_t ixb = p2.x / m_resolution; - coord_t iyb = p2.y / m_resolution; + coord_t ix = p1(0) / m_resolution; + coord_t iy = p1(1) / m_resolution; + coord_t ixb = p2(0) / m_resolution; + coord_t iyb = p2(1) / m_resolution; assert(ix >= 0 && ix < m_cols); assert(iy >= 0 && iy < m_rows); assert(ixb >= 0 && ixb < m_cols); @@ -298,13 +298,13 @@ void EdgeGrid::Grid::create_from_m_contours(coord_t resolution) // Both ends fall into the same cell. continue; // Raster the centeral part of the line. - coord_t dx = std::abs(p2.x - p1.x); - coord_t dy = std::abs(p2.y - p1.y); - if (p1.x < p2.x) { - int64_t ex = int64_t((ix + 1)*m_resolution - p1.x) * int64_t(dy); - if (p1.y < p2.y) { + coord_t dx = std::abs(p2(0) - p1(0)); + coord_t dy = std::abs(p2(1) - p1(1)); + if (p1(0) < p2(0)) { + int64_t ex = int64_t((ix + 1)*m_resolution - p1(0)) * int64_t(dy); + if (p1(1) < p2(1)) { // x positive, y positive - int64_t ey = int64_t((iy + 1)*m_resolution - p1.y) * int64_t(dx); + int64_t ey = int64_t((iy + 1)*m_resolution - p1(1)) * int64_t(dx); do { assert(ix <= ixb && iy <= iyb); if (ex < ey) { @@ -329,7 +329,7 @@ void EdgeGrid::Grid::create_from_m_contours(coord_t resolution) } else { // x positive, y non positive - int64_t ey = int64_t(p1.y - iy*m_resolution) * int64_t(dx); + int64_t ey = int64_t(p1(1) - iy*m_resolution) * int64_t(dx); do { assert(ix <= ixb && iy >= iyb); if (ex <= ey) { @@ -347,10 +347,10 @@ void EdgeGrid::Grid::create_from_m_contours(coord_t resolution) } } else { - int64_t ex = int64_t(p1.x - ix*m_resolution) * int64_t(dy); - if (p1.y < p2.y) { + int64_t ex = int64_t(p1(0) - ix*m_resolution) * int64_t(dy); + if (p1(1) < p2(1)) { // x non positive, y positive - int64_t ey = int64_t((iy + 1)*m_resolution - p1.y) * int64_t(dx); + int64_t ey = int64_t((iy + 1)*m_resolution - p1(1)) * int64_t(dx); do { assert(ix >= ixb && iy <= iyb); if (ex < ey) { @@ -369,7 +369,7 @@ void EdgeGrid::Grid::create_from_m_contours(coord_t resolution) } else { // x non positive, y non positive - int64_t ey = int64_t(p1.y - iy*m_resolution) * int64_t(dx); + int64_t ey = int64_t(p1(1) - iy*m_resolution) * int64_t(dx); do { assert(ix >= ixb && iy >= iyb); if (ex < ey) { @@ -429,15 +429,15 @@ bool EdgeGrid::Grid::intersect(const MultiPoint &polyline, bool closed) Point p1 = p1src; Point p2 = p2src; // Discretize the line segment p1, p2. - p1.x -= m_bbox.min.x; - p1.y -= m_bbox.min.y; - p2.x -= m_bbox.min.x; - p2.y -= m_bbox.min.y; + p1(0) -= m_bbox.min(0); + p1(1) -= m_bbox.min(1); + p2(0) -= m_bbox.min(0); + p2(1) -= m_bbox.min(1); // Get the cells of the end points. - coord_t ix = div_floor(p1.x, m_resolution); - coord_t iy = div_floor(p1.y, m_resolution); - coord_t ixb = div_floor(p2.x, m_resolution); - coord_t iyb = div_floor(p2.y, m_resolution); + coord_t ix = div_floor(p1(0), m_resolution); + coord_t iy = div_floor(p1(1), m_resolution); + coord_t ixb = div_floor(p2(0), m_resolution); + coord_t iyb = div_floor(p2(1), m_resolution); // assert(ix >= 0 && ix < m_cols); // assert(iy >= 0 && iy < m_rows); // assert(ixb >= 0 && ixb < m_cols); @@ -449,12 +449,12 @@ bool EdgeGrid::Grid::intersect(const MultiPoint &polyline, bool closed) // Both ends fall into the same cell. continue; // Raster the centeral part of the line. - coord_t dx = std::abs(p2.x - p1.x); - coord_t dy = std::abs(p2.y - p1.y); - if (p1.x < p2.x) { - int64_t ex = int64_t((ix + 1)*m_resolution - p1.x) * int64_t(dy); - if (p1.y < p2.y) { - int64_t ey = int64_t((iy + 1)*m_resolution - p1.y) * int64_t(dx); + coord_t dx = std::abs(p2(0) - p1(0)); + coord_t dy = std::abs(p2(1) - p1(1)); + if (p1(0) < p2(0)) { + int64_t ex = int64_t((ix + 1)*m_resolution - p1(0)) * int64_t(dy); + if (p1(1) < p2(1)) { + int64_t ey = int64_t((iy + 1)*m_resolution - p1(1)) * int64_t(dx); do { assert(ix <= ixb && iy <= iyb); if (ex < ey) { @@ -479,7 +479,7 @@ bool EdgeGrid::Grid::intersect(const MultiPoint &polyline, bool closed) } while (ix != ixb || iy != iyb); } else { - int64_t ey = int64_t(p1.y - iy*m_resolution) * int64_t(dx); + int64_t ey = int64_t(p1(1) - iy*m_resolution) * int64_t(dx); do { assert(ix <= ixb && iy >= iyb); if (ex <= ey) { @@ -498,9 +498,9 @@ bool EdgeGrid::Grid::intersect(const MultiPoint &polyline, bool closed) } } else { - int64_t ex = int64_t(p1.x - ix*m_resolution) * int64_t(dy); - if (p1.y < p2.y) { - int64_t ey = int64_t((iy + 1)*m_resolution - p1.y) * int64_t(dx); + int64_t ex = int64_t(p1(0) - ix*m_resolution) * int64_t(dy); + if (p1(1) < p2(1)) { + int64_t ey = int64_t((iy + 1)*m_resolution - p1(1)) * int64_t(dx); do { assert(ix >= ixb && iy <= iyb); if (ex < ey) { @@ -519,7 +519,7 @@ bool EdgeGrid::Grid::intersect(const MultiPoint &polyline, bool closed) } while (ix != ixb || iy != iyb); } else { - int64_t ey = int64_t(p1.y - iy*m_resolution) * int64_t(dx); + int64_t ey = int64_t(p1(1) - iy*m_resolution) * int64_t(dx); do { assert(ix >= ixb && iy >= iyb); if (ex < ey) { @@ -556,8 +556,8 @@ bool EdgeGrid::Grid::line_cell_intersect(const Point &p1a, const Point &p2a, con { BoundingBox bbox(p1a, p1a); bbox.merge(p2a); - int64_t va_x = p2a.x - p1a.x; - int64_t va_y = p2a.y - p1a.y; + int64_t va_x = p2a(0) - p1a(0); + int64_t va_y = p2a(1) - p1a(1); for (size_t i = cell.begin; i != cell.end; ++ i) { const std::pair<size_t, size_t> &cell_data = m_cell_data[i]; // Contour indexed by the ith line of this cell. @@ -576,21 +576,21 @@ bool EdgeGrid::Grid::line_cell_intersect(const Point &p1a, const Point &p2a, con if (! bbox.overlap(bbox2)) continue; // Now intersect the two line segments using exact arithmetics. - int64_t w1_x = p1b.x - p1a.x; - int64_t w1_y = p1b.y - p1a.y; - int64_t w2_x = p2b.x - p1a.x; - int64_t w2_y = p2b.y - p1a.y; + int64_t w1_x = p1b(0) - p1a(0); + int64_t w1_y = p1b(1) - p1a(1); + int64_t w2_x = p2b(0) - p1a(0); + int64_t w2_y = p2b(1) - p1a(1); int64_t side1 = va_x * w1_y - va_y * w1_x; int64_t side2 = va_x * w2_y - va_y * w2_x; if (side1 == side2 && side1 != 0) // The line segments don't intersect. continue; - w1_x = p1a.x - p1b.x; - w1_y = p1a.y - p1b.y; - w2_x = p2a.x - p1b.x; - w2_y = p2a.y - p1b.y; - int64_t vb_x = p2b.x - p1b.x; - int64_t vb_y = p2b.y - p1b.y; + w1_x = p1a(0) - p1b(0); + w1_y = p1a(1) - p1b(1); + w2_x = p2a(0) - p1b(0); + w2_y = p2a(1) - p1b(1); + int64_t vb_x = p2b(0) - p1b(0); + int64_t vb_y = p2b(1) - p1b(1); side1 = vb_x * w1_y - vb_y * w1_x; side2 = vb_x * w2_y - vb_y * w2_x; if (side1 == side2 && side1 != 0) @@ -607,13 +607,13 @@ bool EdgeGrid::Grid::line_cell_intersect(const Point &p1a, const Point &p2a, con bool EdgeGrid::Grid::inside(const Point &pt_src) { Point p = pt_src; - p.x -= m_bbox.min.x; - p.y -= m_bbox.min.y; + p(0) -= m_bbox.min(0); + p(1) -= m_bbox.min(1); // Get the cell of the point. - if (p.x < 0 || p.y < 0) + if (p(0) < 0 || p(1) < 0) return false; - coord_t ix = p.x / m_resolution; - coord_t iy = p.y / m_resolution; + coord_t ix = p(0) / m_resolution; + coord_t iy = p(1) / m_resolution; if (ix >= this->m_cols || iy >= this->m_rows) return false; @@ -634,21 +634,21 @@ bool EdgeGrid::Grid::inside(const Point &pt_src) idx2 = 0; const Point &p1 = contour[idx1]; const Point &p2 = contour[idx2]; - if (p1.y < p2.y) { - if (p.y < p1.y || p.y > p2.y) + if (p1(1) < p2(1)) { + if (p(1) < p1(1) || p(1) > p2(1)) continue; //FIXME finish this! int64_t vx = 0;// pt_src //FIXME finish this! int64_t det = 0; - } else if (p1.y != p2.y) { - assert(p1.y > p2.y); - if (p.y < p2.y || p.y > p1.y) + } else if (p1(1) != p2(1)) { + assert(p1(1) > p2(1)); + if (p(1) < p2(1) || p(1) > p1(1)) continue; } else { - assert(p1.y == p2.y); - if (p1.y == p.y) { - if (p.x >= p1.x && p.x <= p2.x) + assert(p1(1) == p2(1)); + if (p1(1) == p(1)) { + if (p(0) >= p1(0) && p(0) <= p2(0)) // On the segment. return true; // Before or after the segment. @@ -767,9 +767,9 @@ void EdgeGrid::Grid::calculate_sdf() const Slic3r::Point &p1 = pts[ipt]; const Slic3r::Point &p2 = pts[(ipt + 1 == pts.size()) ? 0 : ipt + 1]; // Segment vector - const Slic3r::Point v_seg = p1.vector_to(p2); + const Slic3r::Point v_seg = p2 - p1; // l2 of v_seg - const int64_t l2_seg = int64_t(v_seg.x) * int64_t(v_seg.x) + int64_t(v_seg.y) * int64_t(v_seg.y); + const int64_t l2_seg = int64_t(v_seg(0)) * int64_t(v_seg(0)) + int64_t(v_seg(1)) * int64_t(v_seg(1)); // For each corner of this cell and its 1 ring neighbours: for (int corner_y = -1; corner_y < 3; ++ corner_y) { coord_t corner_r = r + corner_y; @@ -780,28 +780,28 @@ void EdgeGrid::Grid::calculate_sdf() if (corner_c < 0 || corner_c >= ncols) continue; float &d_min = m_signed_distance_field[corner_r * ncols + corner_c]; - Slic3r::Point pt(m_bbox.min.x + corner_c * m_resolution, m_bbox.min.y + corner_r * m_resolution); - Slic3r::Point v_pt = p1.vector_to(pt); + Slic3r::Point pt(m_bbox.min(0) + corner_c * m_resolution, m_bbox.min(1) + corner_r * m_resolution); + Slic3r::Point v_pt = pt - p1; // dot(p2-p1, pt-p1) - int64_t t_pt = int64_t(v_seg.x) * int64_t(v_pt.x) + int64_t(v_seg.y) * int64_t(v_pt.y); + int64_t t_pt = int64_t(v_seg(0)) * int64_t(v_pt(0)) + int64_t(v_seg(1)) * int64_t(v_pt(1)); if (t_pt < 0) { // Closest to p1. - double dabs = sqrt(int64_t(v_pt.x) * int64_t(v_pt.x) + int64_t(v_pt.y) * int64_t(v_pt.y)); + double dabs = sqrt(int64_t(v_pt(0)) * int64_t(v_pt(0)) + int64_t(v_pt(1)) * int64_t(v_pt(1))); if (dabs < d_min) { // Previous point. const Slic3r::Point &p0 = pts[(ipt == 0) ? (pts.size() - 1) : ipt - 1]; - Slic3r::Point v_seg_prev = p0.vector_to(p1); - int64_t t2_pt = int64_t(v_seg_prev.x) * int64_t(v_pt.x) + int64_t(v_seg_prev.y) * int64_t(v_pt.y); + Slic3r::Point v_seg_prev = p1 - p0; + int64_t t2_pt = int64_t(v_seg_prev(0)) * int64_t(v_pt(0)) + int64_t(v_seg_prev(1)) * int64_t(v_pt(1)); if (t2_pt > 0) { // Inside the wedge between the previous and the next segment. // Set the signum depending on whether the vertex is convex or reflex. - int64_t det = int64_t(v_seg_prev.x) * int64_t(v_seg.y) - int64_t(v_seg_prev.y) * int64_t(v_seg.x); + int64_t det = int64_t(v_seg_prev(0)) * int64_t(v_seg(1)) - int64_t(v_seg_prev(1)) * int64_t(v_seg(0)); assert(det != 0); d_min = dabs; // Fill in an unsigned vector towards the zero iso surface. float *l = &L[(corner_r * ncols + corner_c) << 1]; - l[0] = std::abs(v_pt.x); - l[1] = std::abs(v_pt.y); + l[0] = std::abs(v_pt(0)); + l[1] = std::abs(v_pt(1)); #ifdef _DEBUG double dabs2 = sqrt(l[0]*l[0]+l[1]*l[1]); assert(std::abs(dabs-dabs2) < 1e-4 * std::max(dabs, dabs2)); @@ -816,7 +816,7 @@ void EdgeGrid::Grid::calculate_sdf() } else { // Closest to the segment. assert(t_pt >= 0 && t_pt <= l2_seg); - int64_t d_seg = int64_t(v_seg.y) * int64_t(v_pt.x) - int64_t(v_seg.x) * int64_t(v_pt.y); + int64_t d_seg = int64_t(v_seg(1)) * int64_t(v_pt(0)) - int64_t(v_seg(0)) * int64_t(v_pt(1)); double d = double(d_seg) / sqrt(double(l2_seg)); double dabs = std::abs(d); if (dabs < d_min) { @@ -824,8 +824,8 @@ void EdgeGrid::Grid::calculate_sdf() // Fill in an unsigned vector towards the zero iso surface. float *l = &L[(corner_r * ncols + corner_c) << 1]; float linv = float(d_seg) / float(l2_seg); - l[0] = std::abs(float(v_seg.y) * linv); - l[1] = std::abs(float(v_seg.x) * linv); + l[0] = std::abs(float(v_seg(1)) * linv); + l[1] = std::abs(float(v_seg(0)) * linv); #ifdef _DEBUG double dabs2 = sqrt(l[0]*l[0]+l[1]*l[1]); assert(std::abs(dabs-dabs2) <= 1e-4 * std::max(dabs, dabs2)); @@ -1059,8 +1059,8 @@ void EdgeGrid::Grid::calculate_sdf() float EdgeGrid::Grid::signed_distance_bilinear(const Point &pt) const { - coord_t x = pt.x - m_bbox.min.x; - coord_t y = pt.y - m_bbox.min.y; + coord_t x = pt(0) - m_bbox.min(0); + coord_t y = pt(1) - m_bbox.min(1); coord_t w = m_resolution * m_cols; coord_t h = m_resolution * m_rows; bool clamped = false; @@ -1124,39 +1124,39 @@ float EdgeGrid::Grid::signed_distance_bilinear(const Point &pt) const bool EdgeGrid::Grid::signed_distance_edges(const Point &pt, coord_t search_radius, coordf_t &result_min_dist, bool *pon_segment) const { BoundingBox bbox; - bbox.min = bbox.max = Point(pt.x - m_bbox.min.x, pt.y - m_bbox.min.y); + bbox.min = bbox.max = Point(pt(0) - m_bbox.min(0), pt(1) - m_bbox.min(1)); bbox.defined = true; // Upper boundary, round to grid and test validity. - bbox.max.x += search_radius; - bbox.max.y += search_radius; - if (bbox.max.x < 0 || bbox.max.y < 0) + bbox.max(0) += search_radius; + bbox.max(1) += search_radius; + if (bbox.max(0) < 0 || bbox.max(1) < 0) return false; - bbox.max.x /= m_resolution; - bbox.max.y /= m_resolution; - if (bbox.max.x >= m_cols) - bbox.max.x = m_cols - 1; - if (bbox.max.y >= m_rows) - bbox.max.y = m_rows - 1; + bbox.max(0) /= m_resolution; + bbox.max(1) /= m_resolution; + if (bbox.max(0) >= m_cols) + bbox.max(0) = m_cols - 1; + if (bbox.max(1) >= m_rows) + bbox.max(1) = m_rows - 1; // Lower boundary, round to grid and test validity. - bbox.min.x -= search_radius; - bbox.min.y -= search_radius; - if (bbox.min.x < 0) - bbox.min.x = 0; - if (bbox.min.y < 0) - bbox.min.y = 0; - bbox.min.x /= m_resolution; - bbox.min.y /= m_resolution; + bbox.min(0) -= search_radius; + bbox.min(1) -= search_radius; + if (bbox.min(0) < 0) + bbox.min(0) = 0; + if (bbox.min(1) < 0) + bbox.min(1) = 0; + bbox.min(0) /= m_resolution; + bbox.min(1) /= m_resolution; // Is the interval empty? - if (bbox.min.x > bbox.max.x || - bbox.min.y > bbox.max.y) + if (bbox.min(0) > bbox.max(0) || + bbox.min(1) > bbox.max(1)) return false; // Traverse all cells in the bounding box. float d_min = search_radius; // Signum of the distance field at pt. int sign_min = 0; bool on_segment = false; - for (int r = bbox.min.y; r <= bbox.max.y; ++ r) { - for (int c = bbox.min.x; c <= bbox.max.x; ++ c) { + for (int r = bbox.min(1); r <= bbox.max(1); ++ r) { + for (int c = bbox.min(0); c <= bbox.max(0); ++ c) { const Cell &cell = m_cells[r * m_cols + c]; for (size_t i = cell.begin; i < cell.end; ++ i) { const Slic3r::Points &pts = *m_contours[m_cell_data[i].first]; @@ -1164,25 +1164,25 @@ bool EdgeGrid::Grid::signed_distance_edges(const Point &pt, coord_t search_radiu // End points of the line segment. const Slic3r::Point &p1 = pts[ipt]; const Slic3r::Point &p2 = pts[(ipt + 1 == pts.size()) ? 0 : ipt + 1]; - Slic3r::Point v_seg = p1.vector_to(p2); - Slic3r::Point v_pt = p1.vector_to(pt); + Slic3r::Point v_seg = p2 - p1; + Slic3r::Point v_pt = pt - p1; // dot(p2-p1, pt-p1) - int64_t t_pt = int64_t(v_seg.x) * int64_t(v_pt.x) + int64_t(v_seg.y) * int64_t(v_pt.y); + int64_t t_pt = int64_t(v_seg(0)) * int64_t(v_pt(0)) + int64_t(v_seg(1)) * int64_t(v_pt(1)); // l2 of seg - int64_t l2_seg = int64_t(v_seg.x) * int64_t(v_seg.x) + int64_t(v_seg.y) * int64_t(v_seg.y); + int64_t l2_seg = int64_t(v_seg(0)) * int64_t(v_seg(0)) + int64_t(v_seg(1)) * int64_t(v_seg(1)); if (t_pt < 0) { // Closest to p1. - double dabs = sqrt(int64_t(v_pt.x) * int64_t(v_pt.x) + int64_t(v_pt.y) * int64_t(v_pt.y)); + double dabs = sqrt(int64_t(v_pt(0)) * int64_t(v_pt(0)) + int64_t(v_pt(1)) * int64_t(v_pt(1))); if (dabs < d_min) { // Previous point. const Slic3r::Point &p0 = pts[(ipt == 0) ? (pts.size() - 1) : ipt - 1]; - Slic3r::Point v_seg_prev = p0.vector_to(p1); - int64_t t2_pt = int64_t(v_seg_prev.x) * int64_t(v_pt.x) + int64_t(v_seg_prev.y) * int64_t(v_pt.y); + Slic3r::Point v_seg_prev = p1 - p0; + int64_t t2_pt = int64_t(v_seg_prev(0)) * int64_t(v_pt(0)) + int64_t(v_seg_prev(1)) * int64_t(v_pt(1)); if (t2_pt > 0) { // Inside the wedge between the previous and the next segment. d_min = dabs; // Set the signum depending on whether the vertex is convex or reflex. - int64_t det = int64_t(v_seg_prev.x) * int64_t(v_seg.y) - int64_t(v_seg_prev.y) * int64_t(v_seg.x); + int64_t det = int64_t(v_seg_prev(0)) * int64_t(v_seg(1)) - int64_t(v_seg_prev(1)) * int64_t(v_seg(0)); assert(det != 0); sign_min = (det > 0) ? 1 : -1; on_segment = false; @@ -1195,7 +1195,7 @@ bool EdgeGrid::Grid::signed_distance_edges(const Point &pt, coord_t search_radiu } else { // Closest to the segment. assert(t_pt >= 0 && t_pt <= l2_seg); - int64_t d_seg = int64_t(v_seg.y) * int64_t(v_pt.x) - int64_t(v_seg.x) * int64_t(v_pt.y); + int64_t d_seg = int64_t(v_seg(1)) * int64_t(v_pt(0)) - int64_t(v_seg(0)) * int64_t(v_pt(1)); double d = double(d_seg) / sqrt(double(l2_seg)); double dabs = std::abs(d); if (dabs < d_min) { @@ -1307,7 +1307,7 @@ Polygons EdgeGrid::Grid::contours_simplified(coord_t offset) const const Line &line_next = lines[it->second]; const Vector v1 = line_current.vector(); const Vector v2 = line_next.vector(); - int64_t cross = int64_t(v1.x) * int64_t(v2.y) - int64_t(v2.x) * int64_t(v1.y); + int64_t cross = int64_t(v1(0)) * int64_t(v2(1)) - int64_t(v2(0)) * int64_t(v1(1)); if (cross > 0) { // This has to be a convex right angle. There is no better next line. i_next = it->second; @@ -1328,10 +1328,10 @@ Polygons EdgeGrid::Grid::contours_simplified(coord_t offset) const Polygon &poly = out[i]; for (size_t j = 0; j < poly.points.size(); ++ j) { Point &p = poly.points[j]; - p.x *= m_resolution; - p.y *= m_resolution; - p.x += m_bbox.min.x; - p.y += m_bbox.min.y; + p(0) *= m_resolution; + p(1) *= m_resolution; + p(0) += m_bbox.min(0); + p(1) += m_bbox.min(1); } // Shrink the contour slightly, so if the same contour gets discretized and simplified again, one will get the same result. // Remove collineaer points. @@ -1341,11 +1341,11 @@ Polygons EdgeGrid::Grid::contours_simplified(coord_t offset) const size_t j0 = (j == 0) ? poly.points.size() - 1 : j - 1; size_t j2 = (j + 1 == poly.points.size()) ? 0 : j + 1; Point v = poly.points[j2] - poly.points[j0]; - if (v.x != 0 && v.y != 0) { + if (v(0) != 0 && v(1) != 0) { // This is a corner point. Copy it to the output contour. Point p = poly.points[j]; - p.y += (v.x < 0) ? - offset : offset; - p.x += (v.y > 0) ? - offset : offset; + p(1) += (v(0) < 0) ? - offset : offset; + p(0) += (v(1) > 0) ? - offset : offset; pts.push_back(p); } } @@ -1357,8 +1357,8 @@ Polygons EdgeGrid::Grid::contours_simplified(coord_t offset) const #if 0 void EdgeGrid::save_png(const EdgeGrid::Grid &grid, const BoundingBox &bbox, coord_t resolution, const char *path) { - unsigned int w = (bbox.max.x - bbox.min.x + resolution - 1) / resolution; - unsigned int h = (bbox.max.y - bbox.min.y + resolution - 1) / resolution; + unsigned int w = (bbox.max(0) - bbox.min(0) + resolution - 1) / resolution; + unsigned int h = (bbox.max(1) - bbox.min(1) + resolution - 1) / resolution; wxImage img(w, h); unsigned char *data = img.GetData(); memset(data, 0, w * h * 3); @@ -1371,7 +1371,7 @@ void EdgeGrid::save_png(const EdgeGrid::Grid &grid, const BoundingBox &bbox, coo for (coord_t r = 0; r < h; ++r) { for (coord_t c = 0; c < w; ++ c) { unsigned char *pxl = data + (((h - r - 1) * w) + c) * 3; - Point pt(c * resolution + bbox.min.x, r * resolution + bbox.min.y); + Point pt(c * resolution + bbox.min(0), r * resolution + bbox.min(1)); coordf_t min_dist; bool on_segment = true; #if 0 @@ -1409,8 +1409,8 @@ void EdgeGrid::save_png(const EdgeGrid::Grid &grid, const BoundingBox &bbox, coo pxl[2] = 0; } - float gridx = float(pt.x - grid.bbox().min.x) / float(grid.resolution()); - float gridy = float(pt.y - grid.bbox().min.y) / float(grid.resolution()); + float gridx = float(pt(0) - grid.bbox().min(0)) / float(grid.resolution()); + float gridy = float(pt(1) - grid.bbox().min(1)) / float(grid.resolution()); if (gridx >= -0.4f && gridy >= -0.4f && gridx <= grid.cols() + 0.4f && gridy <= grid.rows() + 0.4f) { int ix = int(floor(gridx + 0.5f)); int iy = int(floor(gridy + 0.5f)); diff --git a/xs/src/libslic3r/ExPolygon.cpp b/xs/src/libslic3r/ExPolygon.cpp index cd57fd7b0..4294fe543 100644 --- a/xs/src/libslic3r/ExPolygon.cpp +++ b/xs/src/libslic3r/ExPolygon.cpp @@ -34,54 +34,43 @@ ExPolygon::operator Polylines() const return to_polylines(*this); } -void -ExPolygon::scale(double factor) +void ExPolygon::scale(double factor) { contour.scale(factor); - for (Polygons::iterator it = holes.begin(); it != holes.end(); ++it) { - (*it).scale(factor); - } + for (Polygon &hole : holes) + hole.scale(factor); } -void -ExPolygon::translate(double x, double y) +void ExPolygon::translate(double x, double y) { contour.translate(x, y); - for (Polygons::iterator it = holes.begin(); it != holes.end(); ++it) { - (*it).translate(x, y); - } + for (Polygon &hole : holes) + hole.translate(x, y); } -void -ExPolygon::rotate(double angle) +void ExPolygon::rotate(double angle) { contour.rotate(angle); - for (Polygons::iterator it = holes.begin(); it != holes.end(); ++it) { - (*it).rotate(angle); - } + for (Polygon &hole : holes) + hole.rotate(angle); } -void -ExPolygon::rotate(double angle, const Point ¢er) +void ExPolygon::rotate(double angle, const Point ¢er) { contour.rotate(angle, center); - for (Polygons::iterator it = holes.begin(); it != holes.end(); ++it) { - (*it).rotate(angle, center); - } + for (Polygon &hole : holes) + hole.rotate(angle, center); } -double -ExPolygon::area() const +double ExPolygon::area() const { double a = this->contour.area(); - for (Polygons::const_iterator it = this->holes.begin(); it != this->holes.end(); ++it) { - a -= -(*it).area(); // holes have negative area - } + for (const Polygon &hole : holes) + a -= - hole.area(); // holes have negative area return a; } -bool -ExPolygon::is_valid() const +bool ExPolygon::is_valid() const { if (!this->contour.is_valid() || !this->contour.is_counter_clockwise()) return false; for (Polygons::const_iterator it = this->holes.begin(); it != this->holes.end(); ++it) { @@ -90,20 +79,17 @@ ExPolygon::is_valid() const return true; } -bool -ExPolygon::contains(const Line &line) const +bool ExPolygon::contains(const Line &line) const { - return this->contains((Polyline)line); + return this->contains(Polyline(line.a, line.b)); } -bool -ExPolygon::contains(const Polyline &polyline) const +bool ExPolygon::contains(const Polyline &polyline) const { return diff_pl((Polylines)polyline, *this).empty(); } -bool -ExPolygon::contains(const Polylines &polylines) const +bool ExPolygon::contains(const Polylines &polylines) const { #if 0 BoundingBox bbox = get_extents(polylines); @@ -120,8 +106,7 @@ ExPolygon::contains(const Polylines &polylines) const return pl_out.empty(); } -bool -ExPolygon::contains(const Point &point) const +bool ExPolygon::contains(const Point &point) const { if (!this->contour.contains(point)) return false; for (Polygons::const_iterator it = this->holes.begin(); it != this->holes.end(); ++it) { @@ -131,8 +116,7 @@ ExPolygon::contains(const Point &point) const } // inclusive version of contains() that also checks whether point is on boundaries -bool -ExPolygon::contains_b(const Point &point) const +bool ExPolygon::contains_b(const Point &point) const { return this->contains(point) || this->has_boundary_point(point); } @@ -243,25 +227,24 @@ ExPolygon::medial_axis(double max_width, double min_width, ThickPolylines* polyl Point new_front = polyline.points.front(); Point new_back = polyline.points.back(); if (polyline.endpoints.first && !this->has_boundary_point(new_front)) { - Line line(polyline.points.front(), polyline.points[1]); - + Vec2d p1 = polyline.points.front().cast<double>(); + Vec2d p2 = polyline.points[1].cast<double>(); // prevent the line from touching on the other side, otherwise intersection() might return that solution - if (polyline.points.size() == 2) line.b = line.midpoint(); - - line.extend_start(max_width); - (void)this->contour.intersection(line, &new_front); + if (polyline.points.size() == 2) + p2 = (p1 + p2) * 0.5; + // Extend the start of the segment. + p1 -= (p2 - p1).normalized() * max_width; + this->contour.intersection(Line(p1.cast<coord_t>(), p2.cast<coord_t>()), &new_front); } if (polyline.endpoints.second && !this->has_boundary_point(new_back)) { - Line line( - *(polyline.points.end() - 2), - polyline.points.back() - ); - + Vec2d p1 = (polyline.points.end() - 2)->cast<double>(); + Vec2d p2 = polyline.points.back().cast<double>(); // prevent the line from touching on the other side, otherwise intersection() might return that solution - if (polyline.points.size() == 2) line.a = line.midpoint(); - line.extend_end(max_width); - - (void)this->contour.intersection(line, &new_back); + if (polyline.points.size() == 2) + p1 = (p1 + p2) * 0.5; + // Extend the start of the segment. + p2 += (p2 - p1).normalized() * max_width; + this->contour.intersection(Line(p1.cast<coord_t>(), p2.cast<coord_t>()), &new_back); } polyline.points.front() = new_front; polyline.points.back() = new_back; @@ -294,14 +277,14 @@ ExPolygon::medial_axis(double max_width, double min_width, ThickPolylines* polyl // find another polyline starting here for (size_t j = i+1; j < pp.size(); ++j) { ThickPolyline& other = pp[j]; - if (polyline.last_point().coincides_with(other.last_point())) { + if (polyline.last_point() == other.last_point()) { other.reverse(); - } else if (polyline.first_point().coincides_with(other.last_point())) { + } else if (polyline.first_point() == other.last_point()) { polyline.reverse(); other.reverse(); - } else if (polyline.first_point().coincides_with(other.first_point())) { + } else if (polyline.first_point() == other.first_point()) { polyline.reverse(); - } else if (!polyline.last_point().coincides_with(other.first_point())) { + } else if (polyline.last_point() != other.first_point()) { continue; } @@ -361,7 +344,7 @@ ExPolygon::get_trapezoids2(Polygons* polygons) const std::vector<coord_t> xx; xx.reserve(pp.size()); for (Points::const_iterator p = pp.begin(); p != pp.end(); ++p) - xx.push_back(p->x); + xx.push_back(p->x()); std::sort(xx.begin(), xx.end()); // find trapezoids by looping from first to next-to-last coordinate @@ -372,14 +355,14 @@ ExPolygon::get_trapezoids2(Polygons* polygons) const // build rectangle Polygon poly; poly.points.resize(4); - poly[0].x = *x; - poly[0].y = bb.min.y; - poly[1].x = next_x; - poly[1].y = bb.min.y; - poly[2].x = next_x; - poly[2].y = bb.max.y; - poly[3].x = *x; - poly[3].y = bb.max.y; + poly[0](0) = *x; + poly[0](1) = bb.min(1); + poly[1](0) = next_x; + poly[1](1) = bb.min(1); + poly[2](0) = next_x; + poly[2](1) = bb.max(1); + poly[3](0) = *x; + poly[3](1) = bb.max(1); // intersect with this expolygon // append results to return value @@ -425,10 +408,11 @@ ExPolygon::triangulate_pp(Polygons* polygons) const TPPLPoly p; p.Init(int(ex->contour.points.size())); //printf(PRINTF_ZU "\n0\n", ex->contour.points.size()); - for (Points::const_iterator point = ex->contour.points.begin(); point != ex->contour.points.end(); ++point) { - p[ point-ex->contour.points.begin() ].x = point->x; - p[ point-ex->contour.points.begin() ].y = point->y; - //printf("%ld %ld\n", point->x, point->y); + for (const Point &point : ex->contour.points) { + size_t i = &point - &ex->contour.points.front(); + p[i].x = point(0); + p[i].y = point(1); + //printf("%ld %ld\n", point->x(), point->y()); } p.SetHole(false); input.push_back(p); @@ -439,10 +423,11 @@ ExPolygon::triangulate_pp(Polygons* polygons) const TPPLPoly p; p.Init(hole->points.size()); //printf(PRINTF_ZU "\n1\n", hole->points.size()); - for (Points::const_iterator point = hole->points.begin(); point != hole->points.end(); ++point) { - p[ point-hole->points.begin() ].x = point->x; - p[ point-hole->points.begin() ].y = point->y; - //printf("%ld %ld\n", point->x, point->y); + for (const Point &point : hole->points) { + size_t i = &point - &hole->points.front(); + p[i].x = point(0); + p[i].y = point(1); + //printf("%ld %ld\n", point->x(), point->y()); } p.SetHole(true); input.push_back(p); @@ -460,8 +445,8 @@ ExPolygon::triangulate_pp(Polygons* polygons) const Polygon p; p.points.resize(num_points); for (long i = 0; i < num_points; ++i) { - p.points[i].x = coord_t((*poly)[i].x); - p.points[i].y = coord_t((*poly)[i].y); + p.points[i](0) = coord_t((*poly)[i].x); + p.points[i](1) = coord_t((*poly)[i].y); } polygons->push_back(p); } @@ -477,19 +462,17 @@ ExPolygon::triangulate_p2t(Polygons* polygons) const // contour std::vector<p2t::Point*> ContourPoints; - for (Points::const_iterator point = ex->contour.points.begin(); point != ex->contour.points.end(); ++point) { + for (const Point &pt : ex->contour.points) // We should delete each p2t::Point object - ContourPoints.push_back(new p2t::Point(point->x, point->y)); - } + ContourPoints.push_back(new p2t::Point(pt(0), pt(1))); p2t::CDT cdt(ContourPoints); // holes for (Polygons::const_iterator hole = ex->holes.begin(); hole != ex->holes.end(); ++hole) { std::vector<p2t::Point*> points; - for (Points::const_iterator point = hole->points.begin(); point != hole->points.end(); ++point) { + for (const Point &pt : hole->points) // will be destructed in SweepContext::~SweepContext - points.push_back(new p2t::Point(point->x, point->y)); - } + points.push_back(new p2t::Point(pt(0), pt(1))); cdt.AddHole(points); } @@ -506,9 +489,8 @@ ExPolygon::triangulate_p2t(Polygons* polygons) const polygons->push_back(p); } - for(std::vector<p2t::Point*>::iterator it = ContourPoints.begin(); it != ContourPoints.end(); ++it) { - delete *it; - } + for (p2t::Point *ptr : ContourPoints) + delete ptr; } } @@ -523,17 +505,6 @@ ExPolygon::lines() const return lines; } -std::string -ExPolygon::dump_perl() const -{ - std::ostringstream ret; - ret << "[" << this->contour.dump_perl(); - for (Polygons::const_iterator h = this->holes.begin(); h != this->holes.end(); ++h) - ret << "," << h->dump_perl(); - ret << "]"; - return ret.str(); -} - BoundingBox get_extents(const ExPolygon &expolygon) { return get_extents(expolygon.contour); diff --git a/xs/src/libslic3r/ExPolygon.hpp b/xs/src/libslic3r/ExPolygon.hpp index f4782ba55..4833ee49e 100644 --- a/xs/src/libslic3r/ExPolygon.hpp +++ b/xs/src/libslic3r/ExPolygon.hpp @@ -63,7 +63,6 @@ public: void triangulate_pp(Polygons* polygons) const; void triangulate_p2t(Polygons* polygons) const; Lines lines() const; - std::string dump_perl() const; }; // Count a nuber of polygons stored inside the vector of expolygons. diff --git a/xs/src/libslic3r/ExtrusionEntity.cpp b/xs/src/libslic3r/ExtrusionEntity.cpp index c6f67b169..92f0d3669 100644 --- a/xs/src/libslic3r/ExtrusionEntity.cpp +++ b/xs/src/libslic3r/ExtrusionEntity.cpp @@ -220,7 +220,7 @@ void ExtrusionLoop::split_at(const Point &point, bool prefer_non_overhang) double min_non_overhang = std::numeric_limits<double>::max(); for (ExtrusionPaths::const_iterator path = this->paths.begin(); path != this->paths.end(); ++path) { Point p_tmp = point.projection_onto(path->polyline); - double dist = point.distance_to(p_tmp); + double dist = (p_tmp - point).cast<double>().norm(); if (dist < min) { p = p_tmp; min = dist; diff --git a/xs/src/libslic3r/ExtrusionEntity.hpp b/xs/src/libslic3r/ExtrusionEntity.hpp index 15363e8ed..90675c04a 100644 --- a/xs/src/libslic3r/ExtrusionEntity.hpp +++ b/xs/src/libslic3r/ExtrusionEntity.hpp @@ -149,7 +149,7 @@ public: // Minimum volumetric velocity of this extrusion entity. Used by the constant nozzle pressure algorithm. double min_mm3_per_mm() const { return this->mm3_per_mm; } Polyline as_polyline() const { return this->polyline; } - virtual double total_volume() const { return mm3_per_mm * unscale(length()); } + virtual double total_volume() const { return mm3_per_mm * unscale<double>(length()); } private: void _inflate_collection(const Polylines &polylines, ExtrusionEntityCollection* collection) const; diff --git a/xs/src/libslic3r/ExtrusionEntityCollection.hpp b/xs/src/libslic3r/ExtrusionEntityCollection.hpp index 382455fe3..3b34145f8 100644 --- a/xs/src/libslic3r/ExtrusionEntityCollection.hpp +++ b/xs/src/libslic3r/ExtrusionEntityCollection.hpp @@ -50,10 +50,15 @@ public: src.clear(); } } - void append(const ExtrusionPaths &paths) { + void append(const ExtrusionPaths &paths) { this->entities.reserve(this->entities.size() + paths.size()); - for (ExtrusionPaths::const_iterator path = paths.begin(); path != paths.end(); ++path) - this->entities.push_back(path->clone()); + for (const ExtrusionPath &path : paths) + this->entities.emplace_back(path.clone()); + } + void append(ExtrusionPaths &&paths) { + this->entities.reserve(this->entities.size() + paths.size()); + for (ExtrusionPath &path : paths) + this->entities.emplace_back(new ExtrusionPath(std::move(path))); } void replace(size_t i, const ExtrusionEntity &entity); void remove(size_t i); diff --git a/xs/src/libslic3r/ExtrusionSimulator.cpp b/xs/src/libslic3r/ExtrusionSimulator.cpp index daecbc0d1..fcb2fe825 100644 --- a/xs/src/libslic3r/ExtrusionSimulator.cpp +++ b/xs/src/libslic3r/ExtrusionSimulator.cpp @@ -893,24 +893,24 @@ ExtrusionSimulator::~ExtrusionSimulator() void ExtrusionSimulator::set_image_size(const Point &image_size) { // printf("ExtrusionSimulator::set_image_size()\n"); - if (this->image_size.x == image_size.x && - this->image_size.y == image_size.y) + if (this->image_size.x() == image_size.x() && + this->image_size.y() == image_size.y()) return; // printf("Setting image size: %d, %d\n", image_size.x, image_size.y); this->image_size = image_size; // Allocate the image data in an RGBA format. // printf("Allocating image data, size %d\n", image_size.x * image_size.y * 4); - pimpl->image_data.assign(image_size.x * image_size.y * 4, 0); + pimpl->image_data.assign(image_size.x() * image_size.y() * 4, 0); // printf("Allocating image data, allocated\n"); //FIXME fill the image with red vertical lines. - for (size_t r = 0; r < image_size.y; ++ r) { - for (size_t c = 0; c < image_size.x; c += 2) { + for (size_t r = 0; r < image_size.y(); ++ r) { + for (size_t c = 0; c < image_size.x(); c += 2) { // Color red - pimpl->image_data[r * image_size.x * 4 + c * 4] = 255; + pimpl->image_data[r * image_size.x() * 4 + c * 4] = 255; // Opacity full - pimpl->image_data[r * image_size.x * 4 + c * 4 + 3] = 255; + pimpl->image_data[r * image_size.x() * 4 + c * 4 + 3] = 255; } } // printf("Allocating image data, set\n"); @@ -922,8 +922,8 @@ void ExtrusionSimulator::set_viewport(const BoundingBox &viewport) if (this->viewport != viewport) { this->viewport = viewport; Point sz = viewport.size(); - pimpl->accumulator.resize(boost::extents[sz.y][sz.x]); - pimpl->bitmap.resize(boost::extents[sz.y*pimpl->bitmap_oversampled][sz.x*pimpl->bitmap_oversampled]); + pimpl->accumulator.resize(boost::extents[sz.y()][sz.x()]); + pimpl->bitmap.resize(boost::extents[sz.y()*pimpl->bitmap_oversampled][sz.x()*pimpl->bitmap_oversampled]); // printf("Accumulator size: %d, %d\n", sz.y, sz.x); } } @@ -943,8 +943,8 @@ void ExtrusionSimulator::reset_accumulator() // printf("ExtrusionSimulator::reset_accumulator()\n"); Point sz = viewport.size(); // printf("Reset accumulator, Accumulator size: %d, %d\n", sz.y, sz.x); - memset(&pimpl->accumulator[0][0], 0, sizeof(float) * sz.x * sz.y); - memset(&pimpl->bitmap[0][0], 0, sz.x * sz.y * pimpl->bitmap_oversampled * pimpl->bitmap_oversampled); + memset(&pimpl->accumulator[0][0], 0, sizeof(float) * sz.x() * sz.y()); + memset(&pimpl->bitmap[0][0], 0, sz.x() * sz.y() * pimpl->bitmap_oversampled * pimpl->bitmap_oversampled); pimpl->extrusion_points.clear(); // printf("Reset accumulator, done.\n"); } @@ -955,17 +955,17 @@ void ExtrusionSimulator::extrude_to_accumulator(const ExtrusionPath &path, const // Convert the path to V2f points, shift and scale them to the viewport. std::vector<V2f> polyline; polyline.reserve(path.polyline.points.size()); - float scalex = float(viewport.size().x) / float(bbox.size().x); - float scaley = float(viewport.size().y) / float(bbox.size().y); + float scalex = float(viewport.size().x()) / float(bbox.size().x()); + float scaley = float(viewport.size().y()) / float(bbox.size().y()); float w = scale_(path.width) * scalex; float h = scale_(path.height) * scalex; w = scale_(path.mm3_per_mm / path.height) * scalex; // printf("scalex: %f, scaley: %f\n", scalex, scaley); - // printf("bbox: %d,%d %d,%d\n", bbox.min.x, bbox.min.y, bbox.max.x, bbox.max.y); + // printf("bbox: %d,%d %d,%d\n", bbox.min.x(), bbox.min.y, bbox.max.x(), bbox.max.y); for (Points::const_iterator it = path.polyline.points.begin(); it != path.polyline.points.end(); ++ it) { - // printf("point %d,%d\n", it->x+shift.x, it->y+shift.y); + // printf("point %d,%d\n", it->x+shift.x(), it->y+shift.y); ExtrusionPoint ept; - ept.center = V2f(float(it->x+shift.x-bbox.min.x) * scalex, float(it->y+shift.y-bbox.min.y) * scaley); + ept.center = V2f(float((*it)(0)+shift.x()-bbox.min.x()) * scalex, float((*it)(1)+shift.y()-bbox.min.y()) * scaley); ept.radius = w/2.f; ept.height = 0.5f; polyline.push_back(ept.center); @@ -989,9 +989,9 @@ void ExtrusionSimulator::evaluate_accumulator(ExtrusionSimulationType simulation if (simulationType > ExtrusionSimulationDontSpread) { // Average the cells of a bitmap into a lower resolution floating point mask. - A2f mask(boost::extents[sz.y][sz.x]); - for (int r = 0; r < sz.y; ++r) { - for (int c = 0; c < sz.x; ++c) { + A2f mask(boost::extents[sz.y()][sz.x()]); + for (int r = 0; r < sz.y(); ++r) { + for (int c = 0; c < sz.x(); ++c) { float p = 0; for (int j = 0; j < pimpl->bitmap_oversampled; ++ j) { for (int i = 0; i < pimpl->bitmap_oversampled; ++ i) { @@ -1009,9 +1009,9 @@ void ExtrusionSimulator::evaluate_accumulator(ExtrusionSimulationType simulation } // Color map the accumulator. - for (int r = 0; r < sz.y; ++r) { - unsigned char *ptr = &pimpl->image_data[(image_size.x * (viewport.min.y + r) + viewport.min.x) * 4]; - for (int c = 0; c < sz.x; ++c) { + for (int r = 0; r < sz.y(); ++r) { + unsigned char *ptr = &pimpl->image_data[(image_size.x() * (viewport.min.y() + r) + viewport.min.x()) * 4]; + for (int c = 0; c < sz.x(); ++c) { #if 1 float p = pimpl->accumulator[r][c]; #else diff --git a/xs/src/libslic3r/Fill/Fill3DHoneycomb.cpp b/xs/src/libslic3r/Fill/Fill3DHoneycomb.cpp index aa9774784..6a37e4369 100644 --- a/xs/src/libslic3r/Fill/Fill3DHoneycomb.cpp +++ b/xs/src/libslic3r/Fill/Fill3DHoneycomb.cpp @@ -54,9 +54,9 @@ static std::vector<coordf_t> perpendPoints(const coordf_t offset, const size_t b // components that are outside these limits are set to the limits. static inline void trim(Pointfs &pts, coordf_t minX, coordf_t minY, coordf_t maxX, coordf_t maxY) { - for (Pointfs::iterator it = pts.begin(); it != pts.end(); ++ it) { - it->x = clamp(minX, maxX, it->x); - it->y = clamp(minY, maxY, it->y); + for (Vec2d &pt : pts) { + pt(0) = clamp(minX, maxX, pt(0)); + pt(1) = clamp(minY, maxY, pt(1)); } } @@ -66,7 +66,7 @@ static inline Pointfs zip(const std::vector<coordf_t> &x, const std::vector<coor Pointfs out; out.reserve(x.size()); for (size_t i = 0; i < x.size(); ++ i) - out.push_back(Pointf(x[i], y[i])); + out.push_back(Vec2d(x[i], y[i])); return out; } @@ -128,7 +128,7 @@ static Polylines makeGrid(coord_t z, coord_t gridSize, size_t gridWidth, size_t result.push_back(Polyline()); Polyline &polyline = result.back(); for (Pointfs::const_iterator it = it_polylines->begin(); it != it_polylines->end(); ++ it) - polyline.points.push_back(Point(coord_t(it->x * scaleFactor), coord_t(it->y * scaleFactor))); + polyline.points.push_back(Point(coord_t((*it)(0) * scaleFactor), coord_t((*it)(1) * scaleFactor))); } return result; } @@ -153,13 +153,13 @@ void Fill3DHoneycomb::_fill_surface_single( Polylines polylines = makeGrid( scale_(this->z), distance, - ceil(bb.size().x / distance) + 1, - ceil(bb.size().y / distance) + 1, + ceil(bb.size()(0) / distance) + 1, + ceil(bb.size()(1) / distance) + 1, ((this->layer_id/thickness_layers) % 2) + 1); // move pattern in place for (Polylines::iterator it = polylines.begin(); it != polylines.end(); ++ it) - it->translate(bb.min.x, bb.min.y); + it->translate(bb.min(0), bb.min(1)); // clip pattern to boundaries polylines = intersection_pl(polylines, (Polygons)expolygon); @@ -187,7 +187,7 @@ void Fill3DHoneycomb::_fill_surface_single( const Point &last_point = pts_end.back(); // TODO: we should also check that both points are on a fill_boundary to avoid // connecting paths on the boundaries of internal regions - if (first_point.distance_to(last_point) <= 1.5 * distance && + if ((last_point - first_point).cast<double>().norm() <= 1.5 * distance && expolygon_off.contains(Line(last_point, first_point))) { // Append the polyline. pts_end.insert(pts_end.end(), it_polyline->points.begin(), it_polyline->points.end()); diff --git a/xs/src/libslic3r/Fill/FillBase.hpp b/xs/src/libslic3r/Fill/FillBase.hpp index 62d18e518..b67d14339 100644 --- a/xs/src/libslic3r/Fill/FillBase.hpp +++ b/xs/src/libslic3r/Fill/FillBase.hpp @@ -121,11 +121,11 @@ public: return aligned; } static Point _align_to_grid(Point coord, Point spacing) - { return Point(_align_to_grid(coord.x, spacing.x), _align_to_grid(coord.y, spacing.y)); } + { return Point(_align_to_grid(coord(0), spacing(0)), _align_to_grid(coord(1), spacing(1))); } static coord_t _align_to_grid(coord_t coord, coord_t spacing, coord_t base) { return base + _align_to_grid(coord - base, spacing); } static Point _align_to_grid(Point coord, Point spacing, Point base) - { return Point(_align_to_grid(coord.x, spacing.x, base.x), _align_to_grid(coord.y, spacing.y, base.y)); } + { return Point(_align_to_grid(coord(0), spacing(0), base(0)), _align_to_grid(coord(1), spacing(1), base(1))); } }; } // namespace Slic3r diff --git a/xs/src/libslic3r/Fill/FillConcentric.cpp b/xs/src/libslic3r/Fill/FillConcentric.cpp index b21ad2799..8a3a7ea89 100644 --- a/xs/src/libslic3r/Fill/FillConcentric.cpp +++ b/xs/src/libslic3r/Fill/FillConcentric.cpp @@ -20,8 +20,8 @@ void FillConcentric::_fill_surface_single( coord_t distance = coord_t(min_spacing / params.density); if (params.density > 0.9999f && !params.dont_adjust) { - distance = this->_adjust_solid_spacing(bounding_box.size().x, distance); - this->spacing = unscale(distance); + distance = this->_adjust_solid_spacing(bounding_box.size()(0), distance); + this->spacing = unscale<double>(distance); } Polygons loops = (Polygons)expolygon; diff --git a/xs/src/libslic3r/Fill/FillGyroid.cpp b/xs/src/libslic3r/Fill/FillGyroid.cpp index 89d5d231e..d6bf03ce6 100644 --- a/xs/src/libslic3r/Fill/FillGyroid.cpp +++ b/xs/src/libslic3r/Fill/FillGyroid.cpp @@ -30,39 +30,39 @@ static inline double f(double x, double z_sin, double z_cos, bool vertical, bool } static inline Polyline make_wave( - const std::vector<Pointf>& one_period, double width, double height, double offset, double scaleFactor, + const std::vector<Vec2d>& one_period, double width, double height, double offset, double scaleFactor, double z_cos, double z_sin, bool vertical) { - std::vector<Pointf> points = one_period; - double period = points.back().x; + std::vector<Vec2d> points = one_period; + double period = points.back()(0); points.pop_back(); int n = points.size(); do { - points.emplace_back(Pointf(points[points.size()-n].x + period, points[points.size()-n].y)); - } while (points.back().x < width); - points.back().x = width; + points.emplace_back(Vec2d(points[points.size()-n](0) + period, points[points.size()-n](1))); + } while (points.back()(0) < width); + points.back()(0) = width; // and construct the final polyline to return: Polyline polyline; for (auto& point : points) { - point.y += offset; - point.y = clamp(0., height, double(point.y)); + point(1) += offset; + point(1) = clamp(0., height, double(point(1))); if (vertical) - std::swap(point.x, point.y); - polyline.points.emplace_back(convert_to<Point>(point * scaleFactor)); + std::swap(point(0), point(1)); + polyline.points.emplace_back((point * scaleFactor).cast<coord_t>()); } return polyline; } -static std::vector<Pointf> make_one_period(double width, double scaleFactor, double z_cos, double z_sin, bool vertical, bool flip) +static std::vector<Vec2d> make_one_period(double width, double scaleFactor, double z_cos, double z_sin, bool vertical, bool flip) { - std::vector<Pointf> points; + std::vector<Vec2d> points; double dx = M_PI_4; // very coarse spacing to begin with double limit = std::min(2*M_PI, width); for (double x = 0.; x < limit + EPSILON; x += dx) { // so the last point is there too x = std::min(x, limit); - points.emplace_back(Pointf(x,f(x, z_sin,z_cos, vertical, flip))); + points.emplace_back(Vec2d(x,f(x, z_sin,z_cos, vertical, flip))); } // now we will check all internal points and in case some are too far from the line connecting its neighbours, @@ -71,17 +71,19 @@ static std::vector<Pointf> make_one_period(double width, double scaleFactor, dou for (unsigned int i=1;i<points.size()-1;++i) { auto& lp = points[i-1]; // left point auto& tp = points[i]; // this point + Vec2d lrv = tp - lp; auto& rp = points[i+1]; // right point // calculate distance of the point to the line: - double dist_mm = unscale(scaleFactor * std::abs( (rp.y - lp.y)*tp.x + (lp.x - rp.x)*tp.y + (rp.x*lp.y - rp.y*lp.x) ) / std::hypot((rp.y - lp.y),(lp.x - rp.x))); - + double dist_mm = unscale<double>(scaleFactor) * std::abs(cross2(rp, lp) - cross2(rp - lp, tp)) / lrv.norm(); if (dist_mm > tolerance) { // if the difference from straight line is more than this - double x = 0.5f * (points[i-1].x + points[i].x); - points.emplace_back(Pointf(x, f(x, z_sin, z_cos, vertical, flip))); - x = 0.5f * (points[i+1].x + points[i].x); - points.emplace_back(Pointf(x, f(x, z_sin, z_cos, vertical, flip))); - std::sort(points.begin(), points.end()); // we added the points to the end, but need them all in order - --i; // decrement i so we also check the first newly added point + double x = 0.5f * (points[i-1](0) + points[i](0)); + points.emplace_back(Vec2d(x, f(x, z_sin, z_cos, vertical, flip))); + x = 0.5f * (points[i+1](0) + points[i](0)); + points.emplace_back(Vec2d(x, f(x, z_sin, z_cos, vertical, flip))); + // we added the points to the end, but need them all in order + std::sort(points.begin(), points.end(), [](const Vec2d &lhs, const Vec2d &rhs){ return lhs < rhs; }); + // decrement i so we also check the first newly added point + --i; } } return points; @@ -107,7 +109,7 @@ static Polylines make_gyroid_waves(double gridZ, double density_adjusted, double std::swap(width,height); } - std::vector<Pointf> one_period = make_one_period(width, scaleFactor, z_cos, z_sin, vertical, flip); // creates one period of the waves, so it doesn't have to be recalculated all the time + std::vector<Vec2d> one_period = make_one_period(width, scaleFactor, z_cos, z_sin, vertical, flip); // creates one period of the waves, so it doesn't have to be recalculated all the time Polylines result; for (double y0 = lower_bound; y0 < upper_bound+EPSILON; y0 += 2*M_PI) // creates odd polylines @@ -143,12 +145,12 @@ void FillGyroid::_fill_surface_single( scale_(this->z), density_adjusted, this->spacing, - ceil(bb.size().x / distance) + 1., - ceil(bb.size().y / distance) + 1.); + ceil(bb.size()(0) / distance) + 1., + ceil(bb.size()(1) / distance) + 1.); // move pattern in place for (Polyline &polyline : polylines) - polyline.translate(bb.min.x, bb.min.y); + polyline.translate(bb.min(0), bb.min(1)); // clip pattern to boundaries polylines = intersection_pl(polylines, (Polygons)expolygon); @@ -177,7 +179,7 @@ void FillGyroid::_fill_surface_single( // TODO: we should also check that both points are on a fill_boundary to avoid // connecting paths on the boundaries of internal regions // TODO: avoid crossing current infill path - if (first_point.distance_to(last_point) <= 5 * distance && + if ((last_point - first_point).cast<double>().norm() <= 5 * distance && expolygon_off.contains(Line(last_point, first_point))) { // Append the polyline. pts_end.insert(pts_end.end(), polyline.points.begin(), polyline.points.end()); diff --git a/xs/src/libslic3r/Fill/FillHoneycomb.cpp b/xs/src/libslic3r/Fill/FillHoneycomb.cpp index aa0e0f6b0..6f26167a2 100644 --- a/xs/src/libslic3r/Fill/FillHoneycomb.cpp +++ b/xs/src/libslic3r/Fill/FillHoneycomb.cpp @@ -50,13 +50,13 @@ void FillHoneycomb::_fill_surface_single( bounding_box.merge(_align_to_grid(bounding_box.min, Point(m.hex_width, m.pattern_height))); } - coord_t x = bounding_box.min.x; - while (x <= bounding_box.max.x) { + coord_t x = bounding_box.min(0); + while (x <= bounding_box.max(0)) { Polygon p; coord_t ax[2] = { x + m.x_offset, x + m.distance - m.x_offset }; for (size_t i = 0; i < 2; ++ i) { std::reverse(p.points.begin(), p.points.end()); // turn first half upside down - for (coord_t y = bounding_box.min.y; y <= bounding_box.max.y; y += m.y_short + m.hex_side + m.y_short + m.hex_side) { + for (coord_t y = bounding_box.min(1); y <= bounding_box.max(1); y += m.y_short + m.hex_side + m.y_short + m.hex_side) { p.points.push_back(Point(ax[1], y + m.y_offset)); p.points.push_back(Point(ax[0], y + m.y_short - m.y_offset)); p.points.push_back(Point(ax[0], y + m.y_short + m.hex_side + m.y_offset)); @@ -101,7 +101,7 @@ void FillHoneycomb::_fill_surface_single( for (Polylines::iterator it_path = chained.begin(); it_path != chained.end(); ++ it_path) { if (! paths.empty()) { // distance between first point of this path and last point of last path - double distance = paths.back().last_point().distance_to(it_path->first_point()); + double distance = (it_path->first_point() - paths.back().last_point()).cast<double>().norm(); if (distance <= m.hex_width) { paths.back().points.insert(paths.back().points.end(), it_path->points.begin(), it_path->points.end()); continue; diff --git a/xs/src/libslic3r/Fill/FillPlanePath.cpp b/xs/src/libslic3r/Fill/FillPlanePath.cpp index f71ef95a1..615cc6efe 100644 --- a/xs/src/libslic3r/Fill/FillPlanePath.cpp +++ b/xs/src/libslic3r/Fill/FillPlanePath.cpp @@ -24,14 +24,14 @@ void FillPlanePath::_fill_surface_single( Point shift = this->_centered() ? bounding_box.center() : bounding_box.min; - expolygon.translate(-shift.x, -shift.y); - bounding_box.translate(-shift.x, -shift.y); + expolygon.translate(-shift(0), -shift(1)); + bounding_box.translate(-shift(0), -shift(1)); Pointfs pts = _generate( - coord_t(ceil(coordf_t(bounding_box.min.x) / distance_between_lines)), - coord_t(ceil(coordf_t(bounding_box.min.y) / distance_between_lines)), - coord_t(ceil(coordf_t(bounding_box.max.x) / distance_between_lines)), - coord_t(ceil(coordf_t(bounding_box.max.y) / distance_between_lines))); + coord_t(ceil(coordf_t(bounding_box.min(0)) / distance_between_lines)), + coord_t(ceil(coordf_t(bounding_box.min(1)) / distance_between_lines)), + coord_t(ceil(coordf_t(bounding_box.max(0)) / distance_between_lines)), + coord_t(ceil(coordf_t(bounding_box.max(1)) / distance_between_lines))); Polylines polylines; if (pts.size() >= 2) { @@ -41,8 +41,8 @@ void FillPlanePath::_fill_surface_single( polyline.points.reserve(pts.size()); for (Pointfs::iterator it = pts.begin(); it != pts.end(); ++ it) polyline.points.push_back(Point( - coord_t(floor(it->x * distance_between_lines + 0.5)), - coord_t(floor(it->y * distance_between_lines + 0.5)))); + coord_t(floor((*it)(0) * distance_between_lines + 0.5)), + coord_t(floor((*it)(1) * distance_between_lines + 0.5)))); // intersection(polylines_src, offset((Polygons)expolygon, scale_(0.02)), &polylines); polylines = intersection_pl(polylines, to_polygons(expolygon)); @@ -62,7 +62,7 @@ void FillPlanePath::_fill_surface_single( // paths must be repositioned and rotated back for (Polylines::iterator it = polylines.begin(); it != polylines.end(); ++ it) { - it->translate(shift.x, shift.y); + it->translate(shift(0), shift(1)); it->rotate(direction.first); } } @@ -86,12 +86,12 @@ Pointfs FillArchimedeanChords::_generate(coord_t min_x, coord_t min_y, coord_t m coordf_t r = 1; Pointfs out; //FIXME Vojtech: If used as a solid infill, there is a gap left at the center. - out.push_back(Pointf(0, 0)); - out.push_back(Pointf(1, 0)); + out.push_back(Vec2d(0, 0)); + out.push_back(Vec2d(1, 0)); while (r < rmax) { theta += 1. / r; r = a + b * theta; - out.push_back(Pointf(r * cos(theta), r * sin(theta))); + out.push_back(Vec2d(r * cos(theta), r * sin(theta))); } return out; } @@ -162,7 +162,7 @@ Pointfs FillHilbertCurve::_generate(coord_t min_x, coord_t min_y, coord_t max_x, line.reserve(sz2); for (size_t i = 0; i < sz2; ++ i) { Point p = hilbert_n_to_xy(i); - line.push_back(Pointf(p.x + min_x, p.y + min_y)); + line.push_back(Vec2d(p(0) + min_x, p(1) + min_y)); } return line; } @@ -175,27 +175,27 @@ Pointfs FillOctagramSpiral::_generate(coord_t min_x, coord_t min_y, coord_t max_ coordf_t r = 0; coordf_t r_inc = sqrt(2.); Pointfs out; - out.push_back(Pointf(0, 0)); + out.push_back(Vec2d(0, 0)); while (r < rmax) { r += r_inc; coordf_t rx = r / sqrt(2.); coordf_t r2 = r + rx; - out.push_back(Pointf( r, 0.)); - out.push_back(Pointf( r2, rx)); - out.push_back(Pointf( rx, rx)); - out.push_back(Pointf( rx, r2)); - out.push_back(Pointf(0., r)); - out.push_back(Pointf(-rx, r2)); - out.push_back(Pointf(-rx, rx)); - out.push_back(Pointf(-r2, rx)); - out.push_back(Pointf(-r, 0.)); - out.push_back(Pointf(-r2, -rx)); - out.push_back(Pointf(-rx, -rx)); - out.push_back(Pointf(-rx, -r2)); - out.push_back(Pointf(0., -r)); - out.push_back(Pointf( rx, -r2)); - out.push_back(Pointf( rx, -rx)); - out.push_back(Pointf( r2+r_inc, -rx)); + out.push_back(Vec2d( r, 0.)); + out.push_back(Vec2d( r2, rx)); + out.push_back(Vec2d( rx, rx)); + out.push_back(Vec2d( rx, r2)); + out.push_back(Vec2d(0., r)); + out.push_back(Vec2d(-rx, r2)); + out.push_back(Vec2d(-rx, rx)); + out.push_back(Vec2d(-r2, rx)); + out.push_back(Vec2d(-r, 0.)); + out.push_back(Vec2d(-r2, -rx)); + out.push_back(Vec2d(-rx, -rx)); + out.push_back(Vec2d(-rx, -r2)); + out.push_back(Vec2d(0., -r)); + out.push_back(Vec2d( rx, -r2)); + out.push_back(Vec2d( rx, -rx)); + out.push_back(Vec2d( r2+r_inc, -rx)); } return out; } diff --git a/xs/src/libslic3r/Fill/FillRectilinear.cpp b/xs/src/libslic3r/Fill/FillRectilinear.cpp index 5ba30ba51..205eb1b66 100644 --- a/xs/src/libslic3r/Fill/FillRectilinear.cpp +++ b/xs/src/libslic3r/Fill/FillRectilinear.cpp @@ -26,8 +26,8 @@ void FillRectilinear::_fill_surface_single( // define flow spacing according to requested density if (params.density > 0.9999f && !params.dont_adjust) { - this->_line_spacing = this->_adjust_solid_spacing(bounding_box.size().x, this->_line_spacing); - this->spacing = unscale(this->_line_spacing); + this->_line_spacing = this->_adjust_solid_spacing(bounding_box.size()(0), this->_line_spacing); + this->spacing = unscale<double>(this->_line_spacing); } else { // extend bounding box so that our pattern will be aligned with other layers // Transform the reference point to the rotated coordinate system. @@ -38,14 +38,14 @@ void FillRectilinear::_fill_surface_single( } // generate the basic pattern - coord_t x_max = bounding_box.max.x + SCALED_EPSILON; + coord_t x_max = bounding_box.max(0) + SCALED_EPSILON; Lines lines; - for (coord_t x = bounding_box.min.x; x <= x_max; x += this->_line_spacing) - lines.push_back(this->_line(lines.size(), x, bounding_box.min.y, bounding_box.max.y)); + for (coord_t x = bounding_box.min(0); x <= x_max; x += this->_line_spacing) + lines.push_back(this->_line(lines.size(), x, bounding_box.min(1), bounding_box.max(1))); if (this->_horizontal_lines()) { - coord_t y_max = bounding_box.max.y + SCALED_EPSILON; - for (coord_t y = bounding_box.min.y; y <= y_max; y += this->_line_spacing) - lines.push_back(Line(Point(bounding_box.min.x, y), Point(bounding_box.max.x, y))); + coord_t y_max = bounding_box.max(1) + SCALED_EPSILON; + for (coord_t y = bounding_box.min(1); y <= y_max; y += this->_line_spacing) + lines.push_back(Line(Point(bounding_box.min(0), y), Point(bounding_box.max(0), y))); } // clip paths against a slightly larger expolygon, so that the first and last paths @@ -72,10 +72,10 @@ void FillRectilinear::_fill_surface_single( for (Polylines::iterator it_polyline = polylines.begin(); it_polyline != polylines.end(); ++ it_polyline) { Point *first_point = &it_polyline->points.front(); Point *last_point = &it_polyline->points.back(); - if (first_point->y > last_point->y) + if (first_point->y() > last_point->y()) std::swap(first_point, last_point); - first_point->y -= extra; - last_point->y += extra; + first_point->y() -= extra; + last_point->y() += extra; } size_t n_polylines_out_old = polylines_out.size(); @@ -103,10 +103,10 @@ void FillRectilinear::_fill_surface_single( const Point &first_point = it_polyline->points.front(); const Point &last_point = pts_end.back(); // Distance in X, Y. - const Vector distance = first_point.vector_to(last_point); + const Vector distance = last_point - first_point; // TODO: we should also check that both points are on a fill_boundary to avoid // connecting paths on the boundaries of internal regions - if (this->_can_connect(std::abs(distance.x), std::abs(distance.y)) && + if (this->_can_connect(std::abs(distance(0)), std::abs(distance(1))) && expolygon_off.contains(Line(last_point, first_point))) { // Append the polyline. pts_end.insert(pts_end.end(), it_polyline->points.begin(), it_polyline->points.end()); @@ -122,7 +122,7 @@ void FillRectilinear::_fill_surface_single( // paths must be rotated back for (Polylines::iterator it = polylines_out.begin() + n_polylines_out_old; it != polylines_out.end(); ++ it) { // No need to translate, the absolute position is irrelevant. - // it->translate(- direction.second.x, - direction.second.y); + // it->translate(- direction.second(0), - direction.second(1)); it->rotate(direction.first); } } diff --git a/xs/src/libslic3r/Fill/FillRectilinear2.cpp b/xs/src/libslic3r/Fill/FillRectilinear2.cpp index ddd785101..65440d0ef 100644 --- a/xs/src/libslic3r/Fill/FillRectilinear2.cpp +++ b/xs/src/libslic3r/Fill/FillRectilinear2.cpp @@ -42,12 +42,12 @@ static inline coordf_t segment_length(const Polygon &poly, size_t seg1, const Po Point px = (i == 0) ? p1 : p2; Point pa = poly.points[((seg == 0) ? poly.points.size() : seg) - 1]; Point pb = poly.points[seg]; - if (pa.x > pb.x) - std::swap(pa.x, pb.x); - if (pa.y > pb.y) - std::swap(pa.y, pb.y); - assert(px.x >= pa.x && px.x <= pb.x); - assert(px.y >= pa.y && px.y <= pb.y); + if (pa(0) > pb(0)) + std::swap(pa(0), pb(0)); + if (pa(1) > pb(1)) + std::swap(pa(1), pb(1)); + assert(px(0) >= pa(0) && px(0) <= pb(0)); + assert(px(1) >= pa(1) && px(1) <= pb(1)); } #endif /* SLIC3R_DEBUG */ const Point *pPrev = &p1; @@ -55,14 +55,14 @@ static inline coordf_t segment_length(const Polygon &poly, size_t seg1, const Po coordf_t len = 0; if (seg1 <= seg2) { for (size_t i = seg1; i < seg2; ++ i, pPrev = pThis) - len += pPrev->distance_to(*(pThis = &poly.points[i])); + len += (*pPrev - *(pThis = &poly.points[i])).cast<double>().norm(); } else { for (size_t i = seg1; i < poly.points.size(); ++ i, pPrev = pThis) - len += pPrev->distance_to(*(pThis = &poly.points[i])); + len += (*pPrev - *(pThis = &poly.points[i])).cast<double>().norm(); for (size_t i = 0; i < seg2; ++ i, pPrev = pThis) - len += pPrev->distance_to(*(pThis = &poly.points[i])); + len += (*pPrev - *(pThis = &poly.points[i])).cast<double>().norm(); } - len += pPrev->distance_to(p2); + len += (*pPrev - p2).cast<double>().norm(); return len; } @@ -791,15 +791,15 @@ bool FillRectilinear2::fill_surface_by_lines(const Surface *surface, const FillP // define flow spacing according to requested density if (params.full_infill() && !params.dont_adjust) { - line_spacing = this->_adjust_solid_spacing(bounding_box.size().x, line_spacing); - this->spacing = unscale(line_spacing); + line_spacing = this->_adjust_solid_spacing(bounding_box.size()(0), line_spacing); + this->spacing = unscale<double>(line_spacing); } else { // extend bounding box so that our pattern will be aligned with other layers // Transform the reference point to the rotated coordinate system. Point refpt = rotate_vector.second.rotated(- rotate_vector.first); // _align_to_grid will not work correctly with positive pattern_shift. coord_t pattern_shift_scaled = coord_t(scale_(pattern_shift)) % line_spacing; - refpt.x -= (pattern_shift_scaled >= 0) ? pattern_shift_scaled : (line_spacing + pattern_shift_scaled); + refpt(0) -= (pattern_shift_scaled >= 0) ? pattern_shift_scaled : (line_spacing + pattern_shift_scaled); bounding_box.merge(_align_to_grid( bounding_box.min, Point(line_spacing, line_spacing), @@ -808,8 +808,8 @@ bool FillRectilinear2::fill_surface_by_lines(const Surface *surface, const FillP // Intersect a set of euqally spaced vertical lines wiht expolygon. // n_vlines = ceil(bbox_width / line_spacing) - size_t n_vlines = (bounding_box.max.x - bounding_box.min.x + line_spacing - 1) / line_spacing; - coord_t x0 = bounding_box.min.x; + size_t n_vlines = (bounding_box.max(0) - bounding_box.min(0) + line_spacing - 1) / line_spacing; + coord_t x0 = bounding_box.min(0); if (params.full_infill()) x0 += (line_spacing + SCALED_EPSILON) / 2; @@ -842,8 +842,8 @@ bool FillRectilinear2::fill_surface_by_lines(const Surface *surface, const FillP const Point &p1 = contour[iPrev]; const Point &p2 = contour[iSegment]; // Which of the equally spaced vertical lines is intersected by this segment? - coord_t l = p1.x; - coord_t r = p2.x; + coord_t l = p1(0); + coord_t r = p2(0); if (l > r) std::swap(l, r); // il, ir are the left / right indices of vertical lines intersecting a segment @@ -869,33 +869,33 @@ bool FillRectilinear2::fill_surface_by_lines(const Surface *surface, const FillP assert(l <= this_x); assert(r >= this_x); // Calculate the intersection position in y axis. x is known. - if (p1.x == this_x) { - if (p2.x == this_x) { + if (p1(0) == this_x) { + if (p2(0) == this_x) { // Ignore strictly vertical segments. continue; } - is.pos_p = p1.y; + is.pos_p = p1(1); is.pos_q = 1; - } else if (p2.x == this_x) { - is.pos_p = p2.y; + } else if (p2(0) == this_x) { + is.pos_p = p2(1); is.pos_q = 1; } else { // First calculate the intersection parameter 't' as a rational number with non negative denominator. - if (p2.x > p1.x) { - is.pos_p = this_x - p1.x; - is.pos_q = p2.x - p1.x; + if (p2(0) > p1(0)) { + is.pos_p = this_x - p1(0); + is.pos_q = p2(0) - p1(0); } else { - is.pos_p = p1.x - this_x; - is.pos_q = p1.x - p2.x; + is.pos_p = p1(0) - this_x; + is.pos_q = p1(0) - p2(0); } assert(is.pos_p >= 0 && is.pos_p <= is.pos_q); // Make an intersection point from the 't'. - is.pos_p *= int64_t(p2.y - p1.y); - is.pos_p += p1.y * int64_t(is.pos_q); + is.pos_p *= int64_t(p2(1) - p1(1)); + is.pos_p += p1(1) * int64_t(is.pos_q); } // +-1 to take rounding into account. - assert(is.pos() + 1 >= std::min(p1.y, p2.y)); - assert(is.pos() <= std::max(p1.y, p2.y) + 1); + assert(is.pos() + 1 >= std::min(p1(1), p2(1))); + assert(is.pos() <= std::max(p1(1), p2(1)) + 1); segs[i].intersections.push_back(is); } } @@ -919,7 +919,7 @@ bool FillRectilinear2::fill_surface_by_lines(const Surface *surface, const FillP const Points &contour = poly_with_offset.contour(iContour).points; size_t iSegment = sil.intersections[i].iSegment; size_t iPrev = ((iSegment == 0) ? contour.size() : iSegment) - 1; - coord_t dir = contour[iSegment].x - contour[iPrev].x; + coord_t dir = contour[iSegment](0) - contour[iPrev](0); bool low = dir > 0; sil.intersections[i].type = poly_with_offset.is_contour_outer(iContour) ? (low ? SegmentIntersection::OUTER_LOW : SegmentIntersection::OUTER_HIGH) : @@ -1066,7 +1066,7 @@ bool FillRectilinear2::fill_surface_by_lines(const Surface *surface, const FillP intrsctn.consumed_vertical_up : seg.intersections[i-1].consumed_vertical_up; if (! consumed) { - coordf_t dist2 = sqr(coordf_t(pointLast.x - seg.pos)) + sqr(coordf_t(pointLast.y - intrsctn.pos())); + coordf_t dist2 = sqr(coordf_t(pointLast(0) - seg.pos)) + sqr(coordf_t(pointLast(1) - intrsctn.pos())); if (dist2 < dist2min) { dist2min = dist2; i_vline = i_vline2; @@ -1356,8 +1356,8 @@ bool FillRectilinear2::fill_surface_by_lines(const Surface *surface, const FillP // Handle nearly zero length edges. if (polyline_current->points.size() <= 1 || (polyline_current->points.size() == 2 && - std::abs(polyline_current->points.front().x - polyline_current->points.back().x) < SCALED_EPSILON && - std::abs(polyline_current->points.front().y - polyline_current->points.back().y) < SCALED_EPSILON)) + std::abs(polyline_current->points.front()(0) - polyline_current->points.back()(0)) < SCALED_EPSILON && + std::abs(polyline_current->points.front()(1) - polyline_current->points.back()(1)) < SCALED_EPSILON)) polylines_out.pop_back(); intrsctn = NULL; i_intersection = -1; @@ -1383,7 +1383,7 @@ bool FillRectilinear2::fill_surface_by_lines(const Surface *surface, const FillP // paths must be rotated back for (Polylines::iterator it = polylines_out.begin() + n_polylines_out_initial; it != polylines_out.end(); ++ it) { // No need to translate, the absolute position is irrelevant. - // it->translate(- rotate_vector.second.x, - rotate_vector.second.y); + // it->translate(- rotate_vector.second(0), - rotate_vector.second(1)); assert(! it->has_duplicate_points()); it->rotate(rotate_vector.first); //FIXME rather simplify the paths to avoid very short edges? diff --git a/xs/src/libslic3r/Fill/FillRectilinear3.cpp b/xs/src/libslic3r/Fill/FillRectilinear3.cpp index cccea3030..8fc129eac 100644 --- a/xs/src/libslic3r/Fill/FillRectilinear3.cpp +++ b/xs/src/libslic3r/Fill/FillRectilinear3.cpp @@ -217,30 +217,30 @@ Point SegmentIntersection::pos() const const Point &seg_start = poly.points[(this->iSegment == 0) ? poly.points.size() - 1 : this->iSegment - 1]; const Point &seg_end = poly.points[this->iSegment]; // Point, vector of the segment. - const Pointf p1 = convert_to<Pointf>(seg_start); - const Pointf v1 = convert_to<Pointf>(seg_end - seg_start); + const Vec2d p1(seg_start.cast<coordf_t>()); + const Vec2d v1((seg_end - seg_start).cast<coordf_t>()); // Point, vector of this hatching line. - const Pointf p2 = convert_to<Pointf>(line->pos); - const Pointf v2 = convert_to<Pointf>(line->dir); + const Vec2d p2(line->pos.cast<coordf_t>()); + const Vec2d v2(line->dir.cast<coordf_t>()); // Intersect the two rays. - double denom = v1.x * v2.y - v2.x * v1.y; + double denom = v1(0) * v2(1) - v2(0) * v1(1); Point out; if (denom == 0.) { // Lines are collinear. As the pos() method is not supposed to be called on collinear vectors, // the source vectors are not quite collinear. Return the center of the contour segment. out = seg_start + seg_end; - out.x >>= 1; - out.y >>= 1; + out(0) >>= 1; + out(1) >>= 1; } else { // Find the intersection point. - double t = (v2.x * (p1.y - p2.y) - v2.y * (p1.x - p2.x)) / denom; + double t = (v2(0) * (p1(1) - p2(1)) - v2(1) * (p1(0) - p2(0))) / denom; if (t < 0.) out = seg_start; else if (t > 1.) out = seg_end; else { - out.x = coord_t(floor(p1.x + t * v1.x + 0.5)); - out.y = coord_t(floor(p1.y + t * v1.y + 0.5)); + out(0) = coord_t(floor(p1(0) + t * v1(0) + 0.5)); + out(1) = coord_t(floor(p1(1) + t * v1(1) + 0.5)); } } return out; @@ -276,13 +276,13 @@ int SegmentIntersection::ordering_along_line(const SegmentIntersection &other) c // other.iSegment succeeds this->iSegment assert(seg_end_a == seg_start_b); // Avoid calling the 128bit x 128bit multiplication below if this->line intersects the common point. - if (cross(this->line->dir, seg_end_b - this->line->pos) == 0) + if (cross2(Vec2i64(this->line->dir.cast<int64_t>()), (seg_end_b - this->line->pos).cast<int64_t>()) == 0) return 0; } else if ((other.iSegment + 1) % poly_a.points.size() == this->iSegment) { // this->iSegment succeeds other.iSegment assert(seg_start_a == seg_end_b); // Avoid calling the 128bit x 128bit multiplication below if this->line intersects the common point. - if (cross(this->line->dir, seg_start_a - this->line->pos) == 0) + if (cross2(Vec2i64(this->line->dir.cast<int64_t>()), (seg_start_a - this->line->pos).cast<int64_t>()) == 0) return 0; } else { // General case. @@ -290,35 +290,35 @@ int SegmentIntersection::ordering_along_line(const SegmentIntersection &other) c } // First test, whether both points of one segment are completely in one half-plane of the other line. - const Point vec_b = seg_end_b - seg_start_b; - int side_start = signum(cross(vec_b, seg_start_a - seg_start_b)); - int side_end = signum(cross(vec_b, seg_end_a - seg_start_b)); + const Vec2i64 vec_b = (seg_end_b - seg_start_b).cast<int64_t>(); + int side_start = signum(cross2(vec_b, (seg_start_a - seg_start_b).cast<int64_t>())); + int side_end = signum(cross2(vec_b, (seg_end_a - seg_start_b).cast<int64_t>())); int side = side_start * side_end; if (side > 0) // This segment is completely inside one half-plane of the other line, therefore the ordering is trivial. - return signum(cross(vec_b, this->line->dir)) * side_start; + return signum(cross2(vec_b, this->line->dir.cast<int64_t>())) * side_start; - const Point vec_a = seg_end_a - seg_start_a; - int side_start2 = signum(cross(vec_a, seg_start_b - seg_start_a)); - int side_end2 = signum(cross(vec_a, seg_end_b - seg_start_a)); + const Vec2i64 vec_a = (seg_end_a - seg_start_a).cast<int64_t>(); + int side_start2 = signum(cross2(vec_a, (seg_start_b - seg_start_a).cast<int64_t>())); + int side_end2 = signum(cross2(vec_a, (seg_end_b - seg_start_a).cast<int64_t>())); int side2 = side_start2 * side_end2; //if (side == 0 && side2 == 0) // The segments share one of their end points. if (side2 > 0) // This segment is completely inside one half-plane of the other line, therefore the ordering is trivial. - return signum(cross(this->line->dir, vec_a)) * side_start2; + return signum(cross2(this->line->dir.cast<int64_t>(), vec_a)) * side_start2; // The two segments intersect and they are not sucessive segments of the same contour. // Ordering of the points depends on the position of the segment intersection (left / right from this->line), // therefore a simple test over the input segment end points is not sufficient. // Find the parameters of intersection of the two segmetns with this->line. - int64_t denom1 = cross(this->line->dir, vec_a); - int64_t denom2 = cross(this->line->dir, vec_b); - Point vx_a = seg_start_a - this->line->pos; - Point vx_b = seg_start_b - this->line->pos; - int64_t t1_times_denom1 = int64_t(vx_a.x) * int64_t(vec_a.y) - int64_t(vx_a.y) * int64_t(vec_a.x); - int64_t t2_times_denom2 = int64_t(vx_b.x) * int64_t(vec_b.y) - int64_t(vx_b.y) * int64_t(vec_b.x); + int64_t denom1 = cross2(this->line->dir.cast<int64_t>(), vec_a); + int64_t denom2 = cross2(this->line->dir.cast<int64_t>(), vec_b); + Vec2i64 vx_a = (seg_start_a - this->line->pos).cast<int64_t>(); + Vec2i64 vx_b = (seg_start_b - this->line->pos).cast<int64_t>(); + int64_t t1_times_denom1 = vx_a(0) * vec_a(1) - vx_a(1) * vec_a(0); + int64_t t2_times_denom2 = vx_b(0) * vec_b(1) - vx_b(1) * vec_b(0); assert(denom1 != 0); assert(denom2 != 0); return Int128::compare_rationals_filtered(t1_times_denom1, denom1, t2_times_denom2, denom2); @@ -330,7 +330,7 @@ bool SegmentIntersection::operator<(const SegmentIntersection &other) const #ifdef _DEBUG Point p1 = this->pos(); Point p2 = other.pos(); - int64_t d = dot(this->line->dir, p2 - p1); + int64_t d = this->line->dir.cast<int64_t>().dot((p2 - p1).cast<int64_t>()); #endif /* _DEBUG */ int ordering = this->ordering_along_line(other); #ifdef _DEBUG @@ -389,16 +389,16 @@ static bool prepare_infill_hatching_segments( // Define the flow spacing according to requested density. if (params.full_infill() && ! params.dont_adjust) { // Full infill, adjust the line spacing to fit an integer number of lines. - out.line_spacing = Fill::_adjust_solid_spacing(bounding_box.size().x, line_spacing); + out.line_spacing = Fill::_adjust_solid_spacing(bounding_box.size()(0), line_spacing); // Report back the adjusted line spacing. - fill_dir_params.spacing = float(unscale(line_spacing)); + fill_dir_params.spacing = unscale<double>(line_spacing); } else { // Extend bounding box so that our pattern will be aligned with the other layers. // Transform the reference point to the rotated coordinate system. Point refpt = rotate_vector.second.rotated(- out.angle); // _align_to_grid will not work correctly with positive pattern_shift. coord_t pattern_shift_scaled = coord_t(scale_(fill_dir_params.pattern_shift)) % line_spacing; - refpt.x -= (pattern_shift_scaled >= 0) ? pattern_shift_scaled : (line_spacing + pattern_shift_scaled); + refpt(0) -= (pattern_shift_scaled >= 0) ? pattern_shift_scaled : (line_spacing + pattern_shift_scaled); bounding_box.merge(Fill::_align_to_grid( bounding_box.min, Point(line_spacing, line_spacing), @@ -407,13 +407,13 @@ static bool prepare_infill_hatching_segments( // Intersect a set of euqally spaced vertical lines wiht expolygon. // n_vlines = ceil(bbox_width / line_spacing) - size_t n_vlines = (bounding_box.max.x - bounding_box.min.x + line_spacing - 1) / line_spacing; - coord_t x0 = bounding_box.min.x; + size_t n_vlines = (bounding_box.max(0) - bounding_box.min(0) + line_spacing - 1) / line_spacing; + coord_t x0 = bounding_box.min(0); if (params.full_infill()) x0 += coord_t((line_spacing + SCALED_EPSILON) / 2); out.line_spacing = line_spacing; - out.start_point = Point(x0, bounding_box.min.y); + out.start_point = Point(x0, bounding_box.min(1)); out.start_point.rotate(out.angle); #ifdef SLIC3R_DEBUG @@ -436,10 +436,10 @@ static bool prepare_infill_hatching_segments( for (size_t i = 0; i < n_vlines; ++ i) { auto &seg = out.segs[i]; seg.idx = i; - // seg.x = x0 + coord_t(i) * line_spacing; + // seg(0) = x0 + coord_t(i) * line_spacing; coord_t x = x0 + coord_t(i) * line_spacing; - seg.pos.x = coord_t(floor(cos_a * x - sin_a * bounding_box.min.y + 0.5)); - seg.pos.y = coord_t(floor(cos_a * bounding_box.min.y + sin_a * x + 0.5)); + seg.pos(0) = coord_t(floor(cos_a * x - sin_a * bounding_box.min(1) + 0.5)); + seg.pos(1) = coord_t(floor(cos_a * bounding_box.min(1) + sin_a * x + 0.5)); seg.dir = out.direction; } @@ -454,7 +454,7 @@ static bool prepare_infill_hatching_segments( const Point *pr = &contour[iSegment]; // Orient the segment to the direction vector. const Point v = *pr - *pl; - int orientation = Int128::sign_determinant_2x2_filtered(v.x, v.y, out.direction.x, out.direction.y); + int orientation = Int128::sign_determinant_2x2_filtered(v(0), v(1), out.direction(0), out.direction(1)); if (orientation == 0) // Ignore strictly vertical segments. continue; @@ -462,8 +462,8 @@ static bool prepare_infill_hatching_segments( // Always orient the input segment consistently towards the hatching direction. std::swap(pl, pr); // Which of the equally spaced vertical lines is intersected by this segment? - coord_t l = (coord_t)floor(cos_a * pl->x + sin_a * pl->y - SCALED_EPSILON); - coord_t r = (coord_t)ceil (cos_a * pr->x + sin_a * pr->y + SCALED_EPSILON); + coord_t l = (coord_t)floor(cos_a * (*pl)(0) + sin_a * (*pl)(1) - SCALED_EPSILON); + coord_t r = (coord_t)ceil (cos_a * (*pr)(0) + sin_a * (*pr)(1) + SCALED_EPSILON); assert(l < r - SCALED_EPSILON); // il, ir are the left / right indices of vertical lines intersecting a segment int il = std::max<int>(0, (l - x0 + line_spacing) / line_spacing); @@ -479,9 +479,9 @@ static bool prepare_infill_hatching_segments( // 2) all lines from il to ir intersect <pl, pr>. assert(il >= 0 && ir < int(out.segs.size())); for (int i = il; i <= ir; ++ i) { - // assert(out.segs[i].x == i * line_spacing + x0); - // assert(l <= out.segs[i].x); - // assert(r >= out.segs[i].x); + // assert(out.segs[i](0) == i * line_spacing + x0); + // assert(l <= out.segs[i](0)); + // assert(r >= out.segs[i](0)); SegmentIntersection is; is.line = &out.segs[i]; is.expoly_with_offset = &poly_with_offset; @@ -491,10 +491,10 @@ static bool prepare_infill_hatching_segments( // +-1 to take rounding into account. assert(int128::orient(out.segs[i].pos, out.segs[i].pos + out.direction, *pl) >= 0); assert(int128::orient(out.segs[i].pos, out.segs[i].pos + out.direction, *pr) <= 0); - assert(is.pos().x + 1 >= std::min(pl->x, pr->x)); - assert(is.pos().y + 1 >= std::min(pl->y, pr->y)); - assert(is.pos().x <= std::max(pl->x, pr->x) + 1); - assert(is.pos().y <= std::max(pl->y, pr->y) + 1); + assert(is.pos()(0) + 1 >= std::min((*pl)(0), (*pr)(0))); + assert(is.pos()(1) + 1 >= std::min((*pl)(1), (*pr)(1))); + assert(is.pos()(0) <= std::max((*pl)(0), (*pr)(0)) + 1); + assert(is.pos()(1) <= std::max((*pl)(1), (*pr)(1)) + 1); out.segs[i].intersections.push_back(is); } } @@ -510,7 +510,7 @@ static bool prepare_infill_hatching_segments( for (size_t i = 1; i < sil.intersections.size(); ++ i) { Point p1 = sil.intersections[i - 1].pos(); Point p2 = sil.intersections[i].pos(); - int64_t d = dot(sil.dir, p2 - p1); + int64_t d = sil.dir.cast<int64_t>().dot((p2 - p1).cast<int64_t>()); assert(d >= - int64_t(SCALED_EPSILON)); } #endif /* _DEBUG */ @@ -659,12 +659,12 @@ static inline coordf_t segment_length(const Polygon &poly, size_t seg1, const Po Point px = (i == 0) ? p1 : p2; Point pa = poly.points[((seg == 0) ? poly.points.size() : seg) - 1]; Point pb = poly.points[seg]; - if (pa.x > pb.x) - std::swap(pa.x, pb.x); - if (pa.y > pb.y) - std::swap(pa.y, pb.y); - assert(px.x >= pa.x && px.x <= pb.x); - assert(px.y >= pa.y && px.y <= pb.y); + if (pa(0) > pb(0)) + std::swap(pa(0), pb(0)); + if (pa(1) > pb(1)) + std::swap(pa(1), pb(1)); + assert(px(0) >= pa(0) && px(0) <= pb(0)); + assert(px(1) >= pa(1) && px(1) <= pb(1)); } #endif /* SLIC3R_DEBUG */ const Point *pPrev = &p1; @@ -672,14 +672,14 @@ static inline coordf_t segment_length(const Polygon &poly, size_t seg1, const Po coordf_t len = 0; if (seg1 <= seg2) { for (size_t i = seg1; i < seg2; ++ i, pPrev = pThis) - len += pPrev->distance_to(*(pThis = &poly.points[i])); + len += (*pPrev - *(pThis = &poly.points[i])).cast<double>().norm(); } else { for (size_t i = seg1; i < poly.points.size(); ++ i, pPrev = pThis) - len += pPrev->distance_to(*(pThis = &poly.points[i])); + len += (*pPrev - *(pThis = &poly.points[i])).cast<double>().norm(); for (size_t i = 0; i < seg2; ++ i, pPrev = pThis) - len += pPrev->distance_to(*(pThis = &poly.points[i])); + len += (*pPrev - *(pThis = &poly.points[i])).cast<double>().norm(); } - len += pPrev->distance_to(p2); + len += (*pPrev - p2).cast<double>().norm(); return len; } @@ -1191,7 +1191,7 @@ static bool fill_hatching_segments_legacy( intrsctn.consumed_vertical_up : seg.intersections[i-1].consumed_vertical_up; if (! consumed) { - coordf_t dist2 = pointLast.distance_to(intrsctn.pos()); + coordf_t dist2 = (intrsctn.pos() - pointLast).cast<double>().norm(); if (dist2 < dist2min) { dist2min = dist2; i_vline = i_vline2; @@ -1481,8 +1481,8 @@ static bool fill_hatching_segments_legacy( // Handle nearly zero length edges. if (polyline_current->points.size() <= 1 || (polyline_current->points.size() == 2 && - std::abs(polyline_current->points.front().x - polyline_current->points.back().x) < SCALED_EPSILON && - std::abs(polyline_current->points.front().y - polyline_current->points.back().y) < SCALED_EPSILON)) + std::abs(polyline_current->points.front()(0) - polyline_current->points.back()(0)) < SCALED_EPSILON && + std::abs(polyline_current->points.front()(1) - polyline_current->points.back()(1)) < SCALED_EPSILON)) polylines_out.pop_back(); intrsctn = NULL; i_intersection = -1; @@ -1510,7 +1510,7 @@ static bool fill_hatching_segments_legacy( // paths must be rotated back for (Polylines::iterator it = polylines_out.begin() + n_polylines_out_initial; it != polylines_out.end(); ++ it) { // No need to translate, the absolute position is irrelevant. - // it->translate(- rotate_vector.second.x, - rotate_vector.second.y); + // it->translate(- rotate_vector.second(0), - rotate_vector.second(1)); assert(! it->has_duplicate_points()); //it->rotate(rotate_vector.first); //FIXME rather simplify the paths to avoid very short edges? diff --git a/xs/src/libslic3r/Format/3mf.cpp b/xs/src/libslic3r/Format/3mf.cpp index 945bb1f86..4dc40bd3c 100644 --- a/xs/src/libslic3r/Format/3mf.cpp +++ b/xs/src/libslic3r/Format/3mf.cpp @@ -87,8 +87,6 @@ const char* INVALID_OBJECT_TYPES[] = "other" }; -typedef Eigen::Matrix<float, 4, 4, Eigen::RowMajor> Matrix4x4; - const char* get_attribute_value_charptr(const char** attributes, unsigned int attributes_size, const char* attribute_key) { if ((attributes == nullptr) || (attributes_size == 0) || (attributes_size % 2 != 0) || (attribute_key == nullptr)) @@ -121,11 +119,11 @@ int get_attribute_value_int(const char** attributes, unsigned int attributes_siz return (text != nullptr) ? ::atoi(text) : 0; } -Matrix4x4 get_matrix_from_string(const std::string& mat_str) +Slic3r::Transform3d get_transform_from_string(const std::string& mat_str) { if (mat_str.empty()) // empty string means default identity matrix - return Matrix4x4::Identity(); + return Slic3r::Transform3d::Identity(); std::vector<std::string> mat_elements_str; boost::split(mat_elements_str, mat_str, boost::is_any_of(" "), boost::token_compress_on); @@ -133,9 +131,9 @@ Matrix4x4 get_matrix_from_string(const std::string& mat_str) unsigned int size = (unsigned int)mat_elements_str.size(); if (size != 12) // invalid data, return identity matrix - return Matrix4x4::Identity(); + return Slic3r::Transform3d::Identity(); - Matrix4x4 ret = Matrix4x4::Identity(); + Slic3r::Transform3d ret = Slic3r::Transform3d::Identity(); unsigned int i = 0; // matrices are stored into 3mf files as 4x3 // we need to transpose them @@ -143,7 +141,7 @@ Matrix4x4 get_matrix_from_string(const std::string& mat_str) { for (unsigned int r = 0; r < 3; ++r) { - ret(r, c) = (float)::atof(mat_elements_str[i++].c_str()); + ret(r, c) = ::atof(mat_elements_str[i++].c_str()); } } return ret; @@ -209,17 +207,17 @@ namespace Slic3r { struct Component { int object_id; - Matrix4x4 matrix; + Transform3d transform; explicit Component(int object_id) : object_id(object_id) - , matrix(Matrix4x4::Identity()) + , transform(Transform3d::Identity()) { } - Component(int object_id, const Matrix4x4& matrix) + Component(int object_id, const Transform3d& transform) : object_id(object_id) - , matrix(matrix) + , transform(transform) { } }; @@ -273,11 +271,11 @@ namespace Slic3r { struct Instance { ModelInstance* instance; - Matrix4x4 matrix; + Transform3d transform; - Instance(ModelInstance* instance, const Matrix4x4& matrix) + Instance(ModelInstance* instance, const Transform3d& transform) : instance(instance) - , matrix(matrix) + , transform(transform) { } }; @@ -405,9 +403,9 @@ namespace Slic3r { bool _handle_start_metadata(const char** attributes, unsigned int num_attributes); bool _handle_end_metadata(); - bool _create_object_instance(int object_id, const Matrix4x4& matrix, unsigned int recur_counter); + bool _create_object_instance(int object_id, const Transform3d& transform, unsigned int recur_counter); - void _apply_transform(ModelInstance& instance, const Matrix4x4& matrix); + void _apply_transform(ModelInstance& instance, const Transform3d& transform); bool _handle_start_config(const char** attributes, unsigned int num_attributes); bool _handle_end_config(); @@ -936,8 +934,8 @@ namespace Slic3r { ModelObject* object = instance.instance->get_object(); if (object != nullptr) { - // apply the matrix to the instance - _apply_transform(*instance.instance, instance.matrix); + // apply the transform to the instance + _apply_transform(*instance.instance, instance.transform); } } } @@ -1121,7 +1119,7 @@ namespace Slic3r { bool _3MF_Importer::_handle_start_component(const char** attributes, unsigned int num_attributes) { int object_id = get_attribute_value_int(attributes, num_attributes, OBJECTID_ATTR); - Matrix4x4 matrix = get_matrix_from_string(get_attribute_value_string(attributes, num_attributes, TRANSFORM_ATTR)); + Transform3d transform = get_transform_from_string(get_attribute_value_string(attributes, num_attributes, TRANSFORM_ATTR)); IdToModelObjectMap::iterator object_item = m_objects.find(object_id); if (object_item == m_objects.end()) @@ -1134,7 +1132,7 @@ namespace Slic3r { } } - m_curr_object.components.emplace_back(object_id, matrix); + m_curr_object.components.emplace_back(object_id, transform); return true; } @@ -1167,9 +1165,9 @@ namespace Slic3r { // see specifications int object_id = get_attribute_value_int(attributes, num_attributes, OBJECTID_ATTR); - Matrix4x4 matrix = get_matrix_from_string(get_attribute_value_string(attributes, num_attributes, TRANSFORM_ATTR)); + Transform3d transform = get_transform_from_string(get_attribute_value_string(attributes, num_attributes, TRANSFORM_ATTR)); - return _create_object_instance(object_id, matrix, 1); + return _create_object_instance(object_id, transform, 1); } bool _3MF_Importer::_handle_end_item() @@ -1197,7 +1195,7 @@ namespace Slic3r { return true; } - bool _3MF_Importer::_create_object_instance(int object_id, const Matrix4x4& matrix, unsigned int recur_counter) + bool _3MF_Importer::_create_object_instance(int object_id, const Transform3d& transform, unsigned int recur_counter) { static const unsigned int MAX_RECURSIONS = 10; @@ -1234,7 +1232,7 @@ namespace Slic3r { return false; } - m_instances.emplace_back(instance, matrix); + m_instances.emplace_back(instance, transform); } } else @@ -1242,7 +1240,7 @@ namespace Slic3r { // recursively process nested components for (const Component& component : it->second) { - if (!_create_object_instance(component.object_id, matrix * component.matrix, recur_counter + 1)) + if (!_create_object_instance(component.object_id, transform * component.transform, recur_counter + 1)) return false; } } @@ -1250,20 +1248,20 @@ namespace Slic3r { return true; } - void _3MF_Importer::_apply_transform(ModelInstance& instance, const Matrix4x4& matrix) + void _3MF_Importer::_apply_transform(ModelInstance& instance, const Transform3d& transform) { // slic3r ModelInstance cannot be transformed using a matrix // we extract from the given matrix only the values currently used // translation - double offset_x = (double)matrix(0, 3); - double offset_y = (double)matrix(1, 3); - double offset_z = (double)matrix(2, 3); + double offset_x = transform(0, 3); + double offset_y = transform(1, 3); + double offset_z = transform(2, 3); // scale - double sx = ::sqrt(sqr((double)matrix(0, 0)) + sqr((double)matrix(1, 0)) + sqr((double)matrix(2, 0))); - double sy = ::sqrt(sqr((double)matrix(0, 1)) + sqr((double)matrix(1, 1)) + sqr((double)matrix(2, 1))); - double sz = ::sqrt(sqr((double)matrix(0, 2)) + sqr((double)matrix(1, 2)) + sqr((double)matrix(2, 2))); + double sx = ::sqrt(sqr(transform(0, 0)) + sqr(transform(1, 0)) + sqr(transform(2, 0))); + double sy = ::sqrt(sqr(transform(0, 1)) + sqr(transform(1, 1)) + sqr(transform(2, 1))); + double sz = ::sqrt(sqr(transform(0, 2)) + sqr(transform(1, 2)) + sqr(transform(2, 2))); // invalid scale value, return if ((sx == 0.0) || (sy == 0.0) || (sz == 0.0)) @@ -1273,89 +1271,26 @@ namespace Slic3r { if ((std::abs(sx - sy) > 0.00001) || (std::abs(sx - sz) > 0.00001)) return; -#if 0 // use quaternions - // rotations (extracted using quaternion) - double inv_sx = 1.0 / sx; - double inv_sy = 1.0 / sy; - double inv_sz = 1.0 / sz; - - Eigen::Matrix<double, 3, 3, Eigen::RowMajor> m3x3; - m3x3 << (double)matrix(0, 0) * inv_sx, (double)matrix(0, 1) * inv_sy, (double)matrix(0, 2) * inv_sz, - (double)matrix(1, 0) * inv_sx, (double)matrix(1, 1) * inv_sy, (double)matrix(1, 2) * inv_sz, - (double)matrix(2, 0) * inv_sx, (double)matrix(2, 1) * inv_sy, (double)matrix(2, 2) * inv_sz; - - double qw = 0.5 * ::sqrt(std::max(0.0, 1.0 + m3x3(0, 0) + m3x3(1, 1) + m3x3(2, 2))); - double qx = 0.5 * ::sqrt(std::max(0.0, 1.0 + m3x3(0, 0) - m3x3(1, 1) - m3x3(2, 2))); - double qy = 0.5 * ::sqrt(std::max(0.0, 1.0 - m3x3(0, 0) + m3x3(1, 1) - m3x3(2, 2))); - double qz = 0.5 * ::sqrt(std::max(0.0, 1.0 - m3x3(0, 0) - m3x3(1, 1) + m3x3(2, 2))); - - double q_magnitude = ::sqrt(sqr(qw) + sqr(qx) + sqr(qy) + sqr(qz)); - - // invalid length, return - if (q_magnitude == 0.0) - return; - - double inv_q_magnitude = 1.0 / q_magnitude; - - qw *= inv_q_magnitude; - qx *= inv_q_magnitude; - qy *= inv_q_magnitude; - qz *= inv_q_magnitude; - - double test = qx * qy + qz * qw; - double angle_x, angle_y, angle_z; - - if (test > 0.499) - { - // singularity at north pole - angle_x = 0.0; - angle_y = 2.0 * ::atan2(qx, qw); - angle_z = 0.5 * PI; - } - else if (test < -0.499) - { - // singularity at south pole - angle_x = 0.0; - angle_y = -2.0 * ::atan2(qx, qw); - angle_z = -0.5 * PI; - } - else - { - angle_x = ::atan2(2.0 * qx * qw - 2.0 * qy * qz, 1.0 - 2.0 * sqr(qx) - 2.0 * sqr(qz)); - angle_y = ::atan2(2.0 * qy * qw - 2.0 * qx * qz, 1.0 - 2.0 * sqr(qy) - 2.0 * sqr(qz)); - angle_z = ::asin(2.0 * qx * qy + 2.0 * qz * qw); - - if (angle_x < 0.0) - angle_x += 2.0 * PI; - - if (angle_y < 0.0) - angle_y += 2.0 * PI; - - if (angle_z < 0.0) - angle_z += 2.0 * PI; - } -#else // use eigen library double inv_sx = 1.0 / sx; double inv_sy = 1.0 / sy; double inv_sz = 1.0 / sz; Eigen::Matrix3d m3x3; - m3x3 << (double)matrix(0, 0) * inv_sx, (double)matrix(0, 1) * inv_sy, (double)matrix(0, 2) * inv_sz, - (double)matrix(1, 0) * inv_sx, (double)matrix(1, 1) * inv_sy, (double)matrix(1, 2) * inv_sz, - (double)matrix(2, 0) * inv_sx, (double)matrix(2, 1) * inv_sy, (double)matrix(2, 2) * inv_sz; + m3x3 << transform(0, 0) * inv_sx, transform(0, 1) * inv_sy, transform(0, 2) * inv_sz, + transform(1, 0) * inv_sx, transform(1, 1) * inv_sy, transform(1, 2) * inv_sz, + transform(2, 0) * inv_sx, transform(2, 1) * inv_sy, transform(2, 2) * inv_sz; Eigen::AngleAxisd rotation; rotation.fromRotationMatrix(m3x3); // invalid rotation axis, we currently handle only rotations around Z axis - if ((rotation.angle() != 0.0) && (rotation.axis() != Eigen::Vector3d::UnitZ()) && (rotation.axis() != -Eigen::Vector3d::UnitZ())) + if ((rotation.angle() != 0.0) && (rotation.axis() != Vec3d::UnitZ()) && (rotation.axis() != -Vec3d::UnitZ())) return; - double angle_z = (rotation.axis() == Eigen::Vector3d::UnitZ()) ? rotation.angle() : -rotation.angle(); -#endif + double angle_z = (rotation.axis() == Vec3d::UnitZ()) ? rotation.angle() : -rotation.angle(); - instance.offset.x = offset_x; - instance.offset.y = offset_y; + instance.offset(0) = offset_x; + instance.offset(1) = offset_y; instance.scaling_factor = sx; instance.rotation = angle_z; } @@ -1487,7 +1422,7 @@ namespace Slic3r { stl_facet& facet = stl.facet_start[i]; for (unsigned int v = 0; v < 3; ++v) { - ::memcpy((void*)&facet.vertex[v].x, (const void*)&geometry.vertices[geometry.triangles[src_start_id + ii + v] * 3], 3 * sizeof(float)); + ::memcpy(facet.vertex[v].data(), (const void*)&geometry.vertices[geometry.triangles[src_start_id + ii + v] * 3], 3 * sizeof(float)); } } @@ -1550,11 +1485,11 @@ namespace Slic3r { struct BuildItem { unsigned int id; - Matrix4x4 matrix; + Transform3d transform; - BuildItem(unsigned int id, const Matrix4x4& matrix) + BuildItem(unsigned int id, const Transform3d& transform) : id(id) - , matrix(matrix) + , transform(transform) { } }; @@ -1803,9 +1738,8 @@ namespace Slic3r { stream << " </" << COMPONENTS_TAG << ">\n"; } - Eigen::Affine3f transform; - transform = Eigen::Translation3f((float)instance->offset.x, (float)instance->offset.y, 0.0f) * Eigen::AngleAxisf((float)instance->rotation, Eigen::Vector3f::UnitZ()) * Eigen::Scaling((float)instance->scaling_factor); - build_items.emplace_back(instance_id, transform.matrix()); + Transform3d t = instance->world_matrix(); + build_items.emplace_back(instance_id, t); stream << " </" << OBJECT_TAG << ">\n"; @@ -1847,9 +1781,9 @@ namespace Slic3r { for (int i = 0; i < stl.stats.shared_vertices; ++i) { stream << " <" << VERTEX_TAG << " "; - stream << "x=\"" << stl.v_shared[i].x << "\" "; - stream << "y=\"" << stl.v_shared[i].y << "\" "; - stream << "z=\"" << stl.v_shared[i].z << "\" />\n"; + stream << "x=\"" << stl.v_shared[i](0) << "\" "; + stream << "y=\"" << stl.v_shared[i](1) << "\" "; + stream << "z=\"" << stl.v_shared[i](2) << "\" />\n"; } } @@ -1906,7 +1840,7 @@ namespace Slic3r { { for (unsigned r = 0; r < 3; ++r) { - stream << item.matrix(r, c); + stream << item.transform(r, c); if ((r != 2) || (c != 3)) stream << " "; } diff --git a/xs/src/libslic3r/Format/AMF.cpp b/xs/src/libslic3r/Format/AMF.cpp index 886bbae97..81617ad72 100644 --- a/xs/src/libslic3r/Format/AMF.cpp +++ b/xs/src/libslic3r/Format/AMF.cpp @@ -402,7 +402,7 @@ void AMFParserContext::endElement(const char * /* name */) for (size_t i = 0; i < m_volume_facets.size();) { stl_facet &facet = stl.facet_start[i/3]; for (unsigned int v = 0; v < 3; ++ v) - memcpy(&facet.vertex[v].x, &m_object_vertices[m_volume_facets[i ++] * 3], 3 * sizeof(float)); + memcpy(facet.vertex[v].data(), &m_object_vertices[m_volume_facets[i ++] * 3], 3 * sizeof(float)); } stl_get_size(&stl); m_volume->mesh.repair(); @@ -498,8 +498,8 @@ void AMFParserContext::endDocument() for (const Instance &instance : object.second.instances) if (instance.deltax_set && instance.deltay_set) { ModelInstance *mi = m_model.objects[object.second.idx]->add_instance(); - mi->offset.x = instance.deltax; - mi->offset.y = instance.deltay; + mi->offset(0) = instance.deltax; + mi->offset(1) = instance.deltay; mi->rotation = instance.rz_set ? instance.rz : 0.f; mi->scaling_factor = instance.scale_set ? instance.scale : 1.f; } @@ -761,9 +761,9 @@ bool store_amf(const char *path, Model *model, Print* print, bool export_print_c for (size_t i = 0; i < stl.stats.shared_vertices; ++ i) { stream << " <vertex>\n"; stream << " <coordinates>\n"; - stream << " <x>" << stl.v_shared[i].x << "</x>\n"; - stream << " <y>" << stl.v_shared[i].y << "</y>\n"; - stream << " <z>" << stl.v_shared[i].z << "</z>\n"; + stream << " <x>" << stl.v_shared[i](0) << "</x>\n"; + stream << " <y>" << stl.v_shared[i](1) << "</y>\n"; + stream << " <z>" << stl.v_shared[i](2) << "</z>\n"; stream << " </coordinates>\n"; stream << " </vertex>\n"; } @@ -804,8 +804,8 @@ bool store_amf(const char *path, Model *model, Print* print, bool export_print_c " <scale>%lf</scale>\n" " </instance>\n", object_id, - instance->offset.x, - instance->offset.y, + instance->offset(0), + instance->offset(1), instance->rotation, instance->scaling_factor); //FIXME missing instance->scaling_factor diff --git a/xs/src/libslic3r/Format/OBJ.cpp b/xs/src/libslic3r/Format/OBJ.cpp index ea6b5604c..ee5756083 100644 --- a/xs/src/libslic3r/Format/OBJ.cpp +++ b/xs/src/libslic3r/Format/OBJ.cpp @@ -57,14 +57,14 @@ bool load_obj(const char *path, Model *model, const char *object_name_in) continue; stl_facet &facet = stl.facet_start[i_face ++]; size_t num_normals = 0; - stl_normal normal = { 0.f }; + stl_normal normal(stl_normal::Zero()); for (unsigned int v = 0; v < 3; ++ v) { const ObjParser::ObjVertex &vertex = data.vertices[i++]; - memcpy(&facet.vertex[v].x, &data.coordinates[vertex.coordIdx*4], 3 * sizeof(float)); + memcpy(facet.vertex[v].data(), &data.coordinates[vertex.coordIdx*4], 3 * sizeof(float)); if (vertex.normalIdx != -1) { - normal.x += data.normals[vertex.normalIdx*3]; - normal.y += data.normals[vertex.normalIdx*3+1]; - normal.z += data.normals[vertex.normalIdx*3+2]; + normal(0) += data.normals[vertex.normalIdx*3]; + normal(1) += data.normals[vertex.normalIdx*3+1]; + normal(2) += data.normals[vertex.normalIdx*3+2]; ++ num_normals; } } @@ -74,33 +74,27 @@ bool load_obj(const char *path, Model *model, const char *object_name_in) facet2.vertex[0] = facet.vertex[0]; facet2.vertex[1] = facet.vertex[2]; const ObjParser::ObjVertex &vertex = data.vertices[i++]; - memcpy(&facet2.vertex[2].x, &data.coordinates[vertex.coordIdx * 4], 3 * sizeof(float)); + memcpy(facet2.vertex[2].data(), &data.coordinates[vertex.coordIdx * 4], 3 * sizeof(float)); if (vertex.normalIdx != -1) { - normal.x += data.normals[vertex.normalIdx*3]; - normal.y += data.normals[vertex.normalIdx*3+1]; - normal.z += data.normals[vertex.normalIdx*3+2]; + normal(0) += data.normals[vertex.normalIdx*3]; + normal(1) += data.normals[vertex.normalIdx*3+1]; + normal(2) += data.normals[vertex.normalIdx*3+2]; ++ num_normals; } if (num_normals == 4) { // Normalize an average normal of a quad. - float len = sqrt(facet.normal.x*facet.normal.x + facet.normal.y*facet.normal.y + facet.normal.z*facet.normal.z); + float len = facet.normal.norm(); if (len > EPSILON) { - normal.x /= len; - normal.y /= len; - normal.z /= len; + normal /= len; facet.normal = normal; facet2.normal = normal; } } } else if (num_normals == 3) { // Normalize an average normal of a triangle. - float len = sqrt(facet.normal.x*facet.normal.x + facet.normal.y*facet.normal.y + facet.normal.z*facet.normal.z); - if (len > EPSILON) { - normal.x /= len; - normal.y /= len; - normal.z /= len; - facet.normal = normal; - } + float len = facet.normal.norm(); + if (len > EPSILON) + facet.normal = normal / len; } } stl_get_size(&stl); diff --git a/xs/src/libslic3r/Format/PRUS.cpp b/xs/src/libslic3r/Format/PRUS.cpp index 1809eaead..3cf3fc075 100644 --- a/xs/src/libslic3r/Format/PRUS.cpp +++ b/xs/src/libslic3r/Format/PRUS.cpp @@ -166,7 +166,7 @@ bool load_prus(const char *path, Model *model) float trafo[3][4] = { 0 }; double instance_rotation = 0.; double instance_scaling_factor = 1.f; - Pointf instance_offset(0., 0.); + Vec2d instance_offset(0., 0.); bool trafo_set = false; unsigned int group_id = (unsigned int)-1; unsigned int extruder_id = (unsigned int)-1; @@ -207,8 +207,8 @@ bool load_prus(const char *path, Model *model) for (size_t c = 0; c < 3; ++ c) trafo[r][c] += mat_trafo(r, c); } - instance_offset.x = position[0] - zero[0]; - instance_offset.y = position[1] - zero[1]; + instance_offset(0) = position[0] - zero[0]; + instance_offset(1) = position[1] - zero[1]; trafo[2][3] = position[2] / instance_scaling_factor; trafo_set = true; } @@ -260,8 +260,8 @@ bool load_prus(const char *path, Model *model) mesh.repair(); // Transform the model. stl_transform(&stl, &trafo[0][0]); - if (std::abs(stl.stats.min.z) < EPSILON) - stl.stats.min.z = 0.; + if (std::abs(stl.stats.min(2)) < EPSILON) + stl.stats.min(2) = 0.; // Add a mesh to a model. if (mesh.facets_count() > 0) mesh_valid = true; @@ -309,11 +309,11 @@ bool load_prus(const char *path, Model *model) assert(res_normal == 3); int res_outer_loop = line_reader.next_line_scanf(" outer loop"); assert(res_outer_loop == 0); - int res_vertex1 = line_reader.next_line_scanf(" vertex %f %f %f", &facet.vertex[0].x, &facet.vertex[0].y, &facet.vertex[0].z); + int res_vertex1 = line_reader.next_line_scanf(" vertex %f %f %f", &facet.vertex[0](0), &facet.vertex[0](1), &facet.vertex[0](2)); assert(res_vertex1 == 3); - int res_vertex2 = line_reader.next_line_scanf(" vertex %f %f %f", &facet.vertex[1].x, &facet.vertex[1].y, &facet.vertex[1].z); + int res_vertex2 = line_reader.next_line_scanf(" vertex %f %f %f", &facet.vertex[1](0), &facet.vertex[1](1), &facet.vertex[1](2)); assert(res_vertex2 == 3); - int res_vertex3 = line_reader.next_line_scanf(" vertex %f %f %f", &facet.vertex[2].x, &facet.vertex[2].y, &facet.vertex[2].z); + int res_vertex3 = line_reader.next_line_scanf(" vertex %f %f %f", &facet.vertex[2](0), &facet.vertex[2](1), &facet.vertex[2](2)); assert(res_vertex3 == 3); int res_endloop = line_reader.next_line_scanf(" endloop"); assert(res_endloop == 0); @@ -324,9 +324,9 @@ bool load_prus(const char *path, Model *model) break; } // The facet normal has been parsed as a single string as to workaround for not a numbers in the normal definition. - if (sscanf(normal_buf[0], "%f", &facet.normal.x) != 1 || - sscanf(normal_buf[1], "%f", &facet.normal.y) != 1 || - sscanf(normal_buf[2], "%f", &facet.normal.z) != 1) { + if (sscanf(normal_buf[0], "%f", &facet.normal(0)) != 1 || + sscanf(normal_buf[1], "%f", &facet.normal(1)) != 1 || + sscanf(normal_buf[2], "%f", &facet.normal(2)) != 1) { // Normal was mangled. Maybe denormals or "not a number" were stored? // Just reset the normal and silently ignore it. memset(&facet.normal, 0, sizeof(facet.normal)); diff --git a/xs/src/libslic3r/GCode.cpp b/xs/src/libslic3r/GCode.cpp index 67a682d18..74a376ade 100644 --- a/xs/src/libslic3r/GCode.cpp +++ b/xs/src/libslic3r/GCode.cpp @@ -49,11 +49,11 @@ Polyline AvoidCrossingPerimeters::travel_to(const GCode &gcodegen, const Point & // If use_external, then perform the path planning in the world coordinate system (correcting for the gcodegen offset). // Otherwise perform the path planning in the coordinate system of the active object. bool use_external = this->use_external_mp || this->use_external_mp_once; - Point scaled_origin = use_external ? Point::new_scale(gcodegen.origin().x, gcodegen.origin().y) : Point(0, 0); + Point scaled_origin = use_external ? Point::new_scale(gcodegen.origin()(0), gcodegen.origin()(1)) : Point(0, 0); Polyline result = (use_external ? m_external_mp.get() : m_layer_mp.get())-> shortest_path(gcodegen.last_pos() + scaled_origin, point + scaled_origin); if (use_external) - result.translate(scaled_origin.negative()); + result.translate(- scaled_origin); return result; } @@ -64,8 +64,8 @@ std::string OozePrevention::pre_toolchange(GCode &gcodegen) // move to the nearest standby point if (!this->standby_points.empty()) { // get current position in print coordinates - Pointf3 writer_pos = gcodegen.writer().get_position(); - Point pos = Point::new_scale(writer_pos.x, writer_pos.y); + Vec3d writer_pos = gcodegen.writer().get_position(); + Point pos = Point::new_scale(writer_pos(0), writer_pos(1)); // find standby point Point standby_point; @@ -74,7 +74,7 @@ std::string OozePrevention::pre_toolchange(GCode &gcodegen) /* We don't call gcodegen.travel_to() because we don't need retraction (it was already triggered by the caller) nor avoid_crossing_perimeters and also because the coordinates of the destination point must not be transformed by origin nor current extruder offset. */ - gcode += gcodegen.writer().travel_to_xy(Pointf::new_unscale(standby_point), + gcode += gcodegen.writer().travel_to_xy(unscale(standby_point), "move to standby position"); } @@ -160,7 +160,7 @@ Wipe::wipe(GCode &gcodegen, bool toolchange) static inline Point wipe_tower_point_to_object_point(GCode &gcodegen, const WipeTower::xy &wipe_tower_pt) { - return Point(scale_(wipe_tower_pt.x - gcodegen.origin().x), scale_(wipe_tower_pt.y - gcodegen.origin().y)); + return Point(scale_(wipe_tower_pt.x - gcodegen.origin()(0)), scale_(wipe_tower_pt.y - gcodegen.origin()(1))); } std::string WipeTowerIntegration::append_tcr(GCode &gcodegen, const WipeTower::ToolChangeResult &tcr, int new_extruder_id) const @@ -207,7 +207,7 @@ std::string WipeTowerIntegration::append_tcr(GCode &gcodegen, const WipeTower::T check_add_eol(gcode); } // A phony move to the end position at the wipe tower. - gcodegen.writer().travel_to_xy(Pointf(end_pos.x, end_pos.y)); + gcodegen.writer().travel_to_xy(Vec2d(end_pos.x, end_pos.y)); gcodegen.set_last_pos(wipe_tower_point_to_object_point(gcodegen, end_pos)); // Prepare a future wipe. @@ -293,7 +293,7 @@ std::string WipeTowerIntegration::prime(GCode &gcodegen) gcodegen.writer().toolchange(current_extruder_id); gcodegen.placeholder_parser().set("current_extruder", current_extruder_id); // A phony move to the end position at the wipe tower. - gcodegen.writer().travel_to_xy(Pointf(m_priming.end_pos.x, m_priming.end_pos.y)); + gcodegen.writer().travel_to_xy(Vec2d(m_priming.end_pos.x, m_priming.end_pos.y)); gcodegen.set_last_pos(wipe_tower_point_to_object_point(gcodegen, m_priming.end_pos)); // Prepare a future wipe. gcodegen.m_wipe.path.points.clear(); @@ -325,7 +325,7 @@ std::string WipeTowerIntegration::tool_change(GCode &gcodegen, int extruder_id, std::string WipeTowerIntegration::finalize(GCode &gcodegen) { std::string gcode; - if (std::abs(gcodegen.writer().get_position().z - m_final_purge.print_z) > EPSILON) + if (std::abs(gcodegen.writer().get_position()(2) - m_final_purge.print_z) > EPSILON) gcode += gcodegen.change_layer(m_final_purge.print_z); gcode += append_tcr(gcodegen, m_final_purge, -1); return gcode; @@ -774,7 +774,7 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data) for (const ExPolygon &expoly : layer->slices.expolygons) for (const Point © : object->_shifted_copies) { islands.emplace_back(expoly.contour); - islands.back().translate(copy); + islands.back().translate(- copy); } //FIXME Mege the islands in parallel. m_avoid_crossing_perimeters.init_external_mp(union_ex(islands)); @@ -790,9 +790,9 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data) Polygon outer_skirt = Slic3r::Geometry::convex_hull(skirt_points); Polygons skirts; for (unsigned int extruder_id : print.extruders()) { - const Pointf &extruder_offset = print.config.extruder_offset.get_at(extruder_id); + const Vec2d &extruder_offset = print.config.extruder_offset.get_at(extruder_id); Polygon s(outer_skirt); - s.translate(-scale_(extruder_offset.x), -scale_(extruder_offset.y)); + s.translate(Point::new_scale(- extruder_offset(0), - extruder_offset(1))); skirts.emplace_back(std::move(s)); } m_ooze_prevention.enable = true; @@ -821,7 +821,7 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data) // Print objects from the smallest to the tallest to avoid collisions // when moving onto next object starting point. std::vector<PrintObject*> objects(printable_objects); - std::sort(objects.begin(), objects.end(), [](const PrintObject* po1, const PrintObject* po2) { return po1->size.z < po2->size.z; }); + std::sort(objects.begin(), objects.end(), [](const PrintObject* po1, const PrintObject* po2) { return po1->size(2) < po2->size(2); }); size_t finished_objects = 0; for (size_t object_id = initial_print_object_id; object_id < objects.size(); ++ object_id) { const PrintObject &object = *objects[object_id]; @@ -838,7 +838,7 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data) final_extruder_id = tool_ordering.last_extruder(); assert(final_extruder_id != (unsigned int)-1); } - this->set_origin(unscale(copy.x), unscale(copy.y)); + this->set_origin(unscale(copy)); if (finished_objects > 0) { // Move to the origin position for the copy we're going to print. // This happens before Z goes down to layer 0 again, so that no collision happens hopefully. @@ -947,7 +947,7 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data) { DynamicConfig config; config.set_key_value("layer_num", new ConfigOptionInt(m_layer_index)); - config.set_key_value("layer_z", new ConfigOptionFloat(m_writer.get_position().z - m_config.z_offset.value)); + config.set_key_value("layer_z", new ConfigOptionFloat(m_writer.get_position()(2) - m_config.z_offset.value)); if (print.config.single_extruder_multi_material) { // Process the end_filament_gcode for the active filament only. _writeln(file, this->placeholder_parser_process("end_filament_gcode", print.config.end_filament_gcode.get_at(m_writer.extruder()->id()), m_writer.extruder()->id(), &config)); @@ -1403,8 +1403,8 @@ void GCode::process_layer( layer_surface_bboxes.push_back(get_extents(expoly.contour)); auto point_inside_surface = [&layer, &layer_surface_bboxes](const size_t i, const Point &point) { const BoundingBox &bbox = layer_surface_bboxes[i]; - return point.x >= bbox.min.x && point.x < bbox.max.x && - point.y >= bbox.min.y && point.y < bbox.max.y && + return point(0) >= bbox.min(0) && point(0) < bbox.max(0) && + point(1) >= bbox.min(1) && point(1) < bbox.max(1) && layer.slices.expolygons[i].contour.contains(point); }; @@ -1554,7 +1554,7 @@ void GCode::process_layer( if (m_last_obj_copy != this_object_copy) m_avoid_crossing_perimeters.use_external_mp_once = true; m_last_obj_copy = this_object_copy; - this->set_origin(unscale(copy.x), unscale(copy.y)); + this->set_origin(unscale(copy)); if (object_by_extruder.support != nullptr && !print_wipe_extrusions) { m_layer = layers[layer_id].support_layer; gcode += this->extrude_support( @@ -1639,14 +1639,14 @@ void GCode::set_extruders(const std::vector<unsigned int> &extruder_ids) } } -void GCode::set_origin(const Pointf &pointf) +void GCode::set_origin(const Vec2d &pointf) { // if origin increases (goes towards right), last_pos decreases because it goes towards left const Point translate( - scale_(m_origin.x - pointf.x), - scale_(m_origin.y - pointf.y) + scale_(m_origin(0) - pointf(0)), + scale_(m_origin(1) - pointf(1)) ); - m_last_pos.translate(translate); + m_last_pos += translate; m_wipe.path.translate(translate); m_origin = pointf; } @@ -1777,13 +1777,13 @@ static Points::iterator project_point_to_polygon_and_insert(Polygon &polygon, co j = 0; const Point &p1 = polygon.points[i]; const Point &p2 = polygon.points[j]; - const Slic3r::Point v_seg = p1.vector_to(p2); - const Slic3r::Point v_pt = p1.vector_to(pt); - const int64_t l2_seg = int64_t(v_seg.x) * int64_t(v_seg.x) + int64_t(v_seg.y) * int64_t(v_seg.y); - int64_t t_pt = int64_t(v_seg.x) * int64_t(v_pt.x) + int64_t(v_seg.y) * int64_t(v_pt.y); + const Slic3r::Point v_seg = p2 - p1; + const Slic3r::Point v_pt = pt - p1; + const int64_t l2_seg = int64_t(v_seg(0)) * int64_t(v_seg(0)) + int64_t(v_seg(1)) * int64_t(v_seg(1)); + int64_t t_pt = int64_t(v_seg(0)) * int64_t(v_pt(0)) + int64_t(v_seg(1)) * int64_t(v_pt(1)); if (t_pt < 0) { // Closest to p1. - double dabs = sqrt(int64_t(v_pt.x) * int64_t(v_pt.x) + int64_t(v_pt.y) * int64_t(v_pt.y)); + double dabs = sqrt(int64_t(v_pt(0)) * int64_t(v_pt(0)) + int64_t(v_pt(1)) * int64_t(v_pt(1))); if (dabs < d_min) { d_min = dabs; i_min = i; @@ -1796,7 +1796,7 @@ static Points::iterator project_point_to_polygon_and_insert(Polygon &polygon, co } else { // Closest to the segment. assert(t_pt >= 0 && t_pt <= l2_seg); - int64_t d_seg = int64_t(v_seg.y) * int64_t(v_pt.x) - int64_t(v_seg.x) * int64_t(v_pt.y); + int64_t d_seg = int64_t(v_seg(1)) * int64_t(v_pt(0)) - int64_t(v_seg(0)) * int64_t(v_pt(1)); double d = double(d_seg) / sqrt(double(l2_seg)); double dabs = std::abs(d); if (dabs < d_min) { @@ -1805,15 +1805,15 @@ static Points::iterator project_point_to_polygon_and_insert(Polygon &polygon, co // Evaluate the foot point. pt_min = p1; double linv = double(d_seg) / double(l2_seg); - pt_min.x = pt.x - coord_t(floor(double(v_seg.y) * linv + 0.5)); - pt_min.y = pt.y + coord_t(floor(double(v_seg.x) * linv + 0.5)); + pt_min(0) = pt(0) - coord_t(floor(double(v_seg(1)) * linv + 0.5)); + pt_min(1) = pt(1) + coord_t(floor(double(v_seg(0)) * linv + 0.5)); assert(Line(p1, p2).distance_to(pt_min) < scale_(1e-5)); } } } assert(i_min != size_t(-1)); - if (pt_min.distance_to(polygon.points[i_min]) > eps) { + if ((pt_min - polygon.points[i_min]).cast<double>().norm() > eps) { // Insert a new point on the segment i_min, i_min+1. return polygon.points.insert(polygon.points.begin() + (i_min + 1), pt_min); } @@ -1825,8 +1825,8 @@ std::vector<float> polygon_parameter_by_length(const Polygon &polygon) // Parametrize the polygon by its length. std::vector<float> lengths(polygon.points.size()+1, 0.); for (size_t i = 1; i < polygon.points.size(); ++ i) - lengths[i] = lengths[i-1] + float(polygon.points[i].distance_to(polygon.points[i-1])); - lengths.back() = lengths[lengths.size()-2] + float(polygon.points.front().distance_to(polygon.points.back())); + lengths[i] = lengths[i-1] + (polygon.points[i] - polygon.points[i-1]).cast<float>().norm(); + lengths.back() = lengths[lengths.size()-2] + (polygon.points.front() - polygon.points.back()).cast<float>().norm(); return lengths; } @@ -1874,10 +1874,10 @@ std::vector<float> polygon_angles_at_vertices(const Polygon &polygon, const std: const Point &p0 = polygon.points[idx_prev]; const Point &p1 = polygon.points[idx_curr]; const Point &p2 = polygon.points[idx_next]; - const Point v1 = p0.vector_to(p1); - const Point v2 = p1.vector_to(p2); - int64_t dot = int64_t(v1.x)*int64_t(v2.x) + int64_t(v1.y)*int64_t(v2.y); - int64_t cross = int64_t(v1.x)*int64_t(v2.y) - int64_t(v1.y)*int64_t(v2.x); + const Point v1 = p1 - p0; + const Point v2 = p2 - p1; + int64_t dot = int64_t(v1(0))*int64_t(v2(0)) + int64_t(v1(1))*int64_t(v2(1)); + int64_t cross = int64_t(v1(0))*int64_t(v2(1)) - int64_t(v1(1))*int64_t(v2(0)); float angle = float(atan2(double(cross), double(dot))); angles[idx_curr] = angle; } @@ -1901,10 +1901,10 @@ std::string GCode::extrude_loop(ExtrusionLoop loop, std::string description, dou { static int iRun = 0; BoundingBox bbox = (*lower_layer_edge_grid)->bbox(); - bbox.min.x -= scale_(5.f); - bbox.min.y -= scale_(5.f); - bbox.max.x += scale_(5.f); - bbox.max.y += scale_(5.f); + bbox.min(0) -= scale_(5.f); + bbox.min(1) -= scale_(5.f); + bbox.max(0) += scale_(5.f); + bbox.max(1) += scale_(5.f); EdgeGrid::save_png(*(*lower_layer_edge_grid), bbox, scale_(0.1f), debug_out_path("GCode_extrude_loop_edge_grid-%d.png", iRun++)); } #endif @@ -1940,7 +1940,7 @@ std::string GCode::extrude_loop(ExtrusionLoop loop, std::string description, dou break; case spRear: last_pos = m_layer->object()->bounding_box().center(); - last_pos.y += coord_t(3. * m_layer->object()->bounding_box().radius()); + last_pos(1) += coord_t(3. * m_layer->object()->bounding_box().radius()); last_pos_weight = 5.f; break; } @@ -2073,7 +2073,7 @@ std::string GCode::extrude_loop(ExtrusionLoop loop, std::string description, dou //FIXME Better parametrize the loop by its length. Polygon polygon = loop.polygon(); Point centroid = polygon.centroid(); - last_pos = Point(polygon.bounding_box().max.x, centroid.y); + last_pos = Point(polygon.bounding_box().max(0), centroid(1)); last_pos.rotate(fmod((float)rand()/16.0, 2.0*PI), centroid); } // Find the closest point, avoid overhangs. @@ -2130,19 +2130,17 @@ std::string GCode::extrude_loop(ExtrusionLoop loop, std::string description, dou // create the destination point along the first segment and rotate it // we make sure we don't exceed the segment length because we don't know // the rotation of the second segment so we might cross the object boundary - Line first_segment( - paths.front().polyline.points[0], - paths.front().polyline.points[1] - ); - double distance = std::min<double>( - scale_(EXTRUDER_CONFIG(nozzle_diameter)), - first_segment.length() - ); - Point point = first_segment.point_at(distance); - point.rotate(angle, first_segment.a); - + Vec2d p1 = paths.front().polyline.points.front().cast<double>(); + Vec2d p2 = paths.front().polyline.points[1].cast<double>(); + Vec2d v = p2 - p1; + double nd = scale_(EXTRUDER_CONFIG(nozzle_diameter)); + double l2 = v.squaredNorm(); + // Shift by no more than a nozzle diameter. + //FIXME Hiding the seams will not work nicely for very densely discretized contours! + Point pt = ((nd * nd >= l2) ? p2 : (p1 + v * (nd / sqrt(l2)))).cast<coord_t>(); + pt.rotate(angle, paths.front().polyline.points.front()); // generate the travel move - gcode += m_writer.travel_to_xy(this->point_to_gcode(point), "move inwards before travel"); + gcode += m_writer.travel_to_xy(this->point_to_gcode(pt), "move inwards before travel"); } return gcode; @@ -2312,7 +2310,7 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description, std::string gcode; // go to first point of extrusion path - if (!m_last_pos_defined || !m_last_pos.coincides_with(path.first_point())) { + if (!m_last_pos_defined || m_last_pos != path.first_point()) { gcode += this->travel_to( path.first_point(), path.role(), @@ -2627,24 +2625,21 @@ std::string GCode::set_extruder(unsigned int extruder_id) } // convert a model-space scaled point into G-code coordinates -Pointf GCode::point_to_gcode(const Point &point) const +Vec2d GCode::point_to_gcode(const Point &point) const { - Pointf extruder_offset = EXTRUDER_CONFIG(extruder_offset); - return Pointf( - unscale(point.x) + m_origin.x - extruder_offset.x, - unscale(point.y) + m_origin.y - extruder_offset.y); + Vec2d extruder_offset = EXTRUDER_CONFIG(extruder_offset); + return unscale(point) + m_origin - extruder_offset; } // convert a model-space scaled point into G-code coordinates -Point GCode::gcode_to_point(const Pointf &point) const +Point GCode::gcode_to_point(const Vec2d &point) const { - Pointf extruder_offset = EXTRUDER_CONFIG(extruder_offset); + Vec2d extruder_offset = EXTRUDER_CONFIG(extruder_offset); return Point( - scale_(point.x - m_origin.x + extruder_offset.x), - scale_(point.y - m_origin.y + extruder_offset.y)); + scale_(point(0) - m_origin(0) + extruder_offset(0)), + scale_(point(1) - m_origin(1) + extruder_offset(1))); } - // Goes through by_region std::vector and returns reference to a subvector of entities, that are to be printed // during infill/perimeter wiping, or normally (depends on wiping_entities parameter) // Returns a reference to member to avoid copying. diff --git a/xs/src/libslic3r/GCode.hpp b/xs/src/libslic3r/GCode.hpp index 4953c39fe..dc8a32135 100644 --- a/xs/src/libslic3r/GCode.hpp +++ b/xs/src/libslic3r/GCode.hpp @@ -125,6 +125,7 @@ private: class GCode { public: GCode() : + m_origin(Vec2d::Zero()), m_enable_loop_clipping(true), m_enable_cooling_markers(false), m_enable_extrusion_role_markers(false), @@ -152,12 +153,12 @@ public: void do_export(Print *print, const char *path, GCodePreviewData *preview_data = nullptr); // Exported for the helper classes (OozePrevention, Wipe) and for the Perl binding for unit tests. - const Pointf& origin() const { return m_origin; } - void set_origin(const Pointf &pointf); - void set_origin(const coordf_t x, const coordf_t y) { this->set_origin(Pointf(x, y)); } + const Vec2d& origin() const { return m_origin; } + void set_origin(const Vec2d &pointf); + void set_origin(const coordf_t x, const coordf_t y) { this->set_origin(Vec2d(x, y)); } const Point& last_pos() const { return m_last_pos; } - Pointf point_to_gcode(const Point &point) const; - Point gcode_to_point(const Pointf &point) const; + Vec2d point_to_gcode(const Point &point) const; + Point gcode_to_point(const Vec2d &point) const; const FullPrintConfig &config() const { return m_config; } const Layer* layer() const { return m_layer; } GCodeWriter& writer() { return m_writer; } @@ -258,7 +259,7 @@ protected: /* Origin of print coordinates expressed in unscaled G-code coordinates. This affects the input arguments supplied to the extrude*() and travel_to() methods. */ - Pointf m_origin; + Vec2d m_origin; FullPrintConfig m_config; GCodeWriter m_writer; PlaceholderParser m_placeholder_parser; diff --git a/xs/src/libslic3r/GCode/Analyzer.cpp b/xs/src/libslic3r/GCode/Analyzer.cpp index b7ecee5a4..51d5b1a06 100644 --- a/xs/src/libslic3r/GCode/Analyzer.cpp +++ b/xs/src/libslic3r/GCode/Analyzer.cpp @@ -14,7 +14,7 @@ static const float MMMIN_TO_MMSEC = 1.0f / 60.0f; static const float INCHES_TO_MM = 25.4f; static const float DEFAULT_FEEDRATE = 0.0f; static const unsigned int DEFAULT_EXTRUDER_ID = 0; -static const Slic3r::Pointf3 DEFAULT_START_POSITION = Slic3r::Pointf3(0.0f, 0.0f, 0.0f); +static const Slic3r::Vec3d DEFAULT_START_POSITION = Slic3r::Vec3d(0.0f, 0.0f, 0.0f); static const float DEFAULT_START_EXTRUSION = 0.0f; namespace Slic3r { @@ -71,7 +71,7 @@ bool GCodeAnalyzer::Metadata::operator != (const GCodeAnalyzer::Metadata& other) return false; } -GCodeAnalyzer::GCodeMove::GCodeMove(GCodeMove::EType type, ExtrusionRole extrusion_role, unsigned int extruder_id, double mm3_per_mm, float width, float height, float feedrate, const Pointf3& start_position, const Pointf3& end_position, float delta_extruder) +GCodeAnalyzer::GCodeMove::GCodeMove(GCodeMove::EType type, ExtrusionRole extrusion_role, unsigned int extruder_id, double mm3_per_mm, float width, float height, float feedrate, const Vec3d& start_position, const Vec3d& end_position, float delta_extruder) : type(type) , data(extrusion_role, extruder_id, mm3_per_mm, width, height, feedrate) , start_position(start_position) @@ -80,7 +80,7 @@ GCodeAnalyzer::GCodeMove::GCodeMove(GCodeMove::EType type, ExtrusionRole extrusi { } -GCodeAnalyzer::GCodeMove::GCodeMove(GCodeMove::EType type, const GCodeAnalyzer::Metadata& data, const Pointf3& start_position, const Pointf3& end_position, float delta_extruder) +GCodeAnalyzer::GCodeMove::GCodeMove(GCodeMove::EType type, const GCodeAnalyzer::Metadata& data, const Vec3d& start_position, const Vec3d& end_position, float delta_extruder) : type(type) , data(data) , start_position(start_position) @@ -587,12 +587,12 @@ void GCodeAnalyzer::_reset_axes_position() ::memset((void*)m_state.position, 0, Num_Axis * sizeof(float)); } -void GCodeAnalyzer::_set_start_position(const Pointf3& position) +void GCodeAnalyzer::_set_start_position(const Vec3d& position) { m_state.start_position = position; } -const Pointf3& GCodeAnalyzer::_get_start_position() const +const Vec3d& GCodeAnalyzer::_get_start_position() const { return m_state.start_position; } @@ -612,9 +612,9 @@ float GCodeAnalyzer::_get_delta_extrusion() const return _get_axis_position(E) - m_state.start_extrusion; } -Pointf3 GCodeAnalyzer::_get_end_position() const +Vec3d GCodeAnalyzer::_get_end_position() const { - return Pointf3(m_state.position[X], m_state.position[Y], m_state.position[Z]); + return Vec3d(m_state.position[X], m_state.position[Y], m_state.position[Z]); } void GCodeAnalyzer::_store_move(GCodeAnalyzer::GCodeMove::EType type) @@ -673,7 +673,7 @@ void GCodeAnalyzer::_calc_gcode_preview_extrusion_layers(GCodePreviewData& previ Metadata data; float z = FLT_MAX; Polyline polyline; - Pointf3 position(FLT_MAX, FLT_MAX, FLT_MAX); + Vec3d position(FLT_MAX, FLT_MAX, FLT_MAX); float volumetric_rate = FLT_MAX; GCodePreviewData::Range height_range; GCodePreviewData::Range width_range; @@ -683,7 +683,7 @@ void GCodeAnalyzer::_calc_gcode_preview_extrusion_layers(GCodePreviewData& previ // constructs the polylines while traversing the moves for (const GCodeMove& move : extrude_moves->second) { - if ((data != move.data) || (z != move.start_position.z) || (position != move.start_position) || (volumetric_rate != move.data.feedrate * (float)move.data.mm3_per_mm)) + if ((data != move.data) || (z != move.start_position.z()) || (position != move.start_position) || (volumetric_rate != move.data.feedrate * (float)move.data.mm3_per_mm)) { // store current polyline polyline.remove_duplicate_points(); @@ -693,12 +693,12 @@ void GCodeAnalyzer::_calc_gcode_preview_extrusion_layers(GCodePreviewData& previ polyline = Polyline(); // add both vertices of the move - polyline.append(Point(scale_(move.start_position.x), scale_(move.start_position.y))); - polyline.append(Point(scale_(move.end_position.x), scale_(move.end_position.y))); + polyline.append(Point(scale_(move.start_position.x()), scale_(move.start_position.y()))); + polyline.append(Point(scale_(move.end_position.x()), scale_(move.end_position.y()))); // update current values data = move.data; - z = move.start_position.z; + z = move.start_position.z(); volumetric_rate = move.data.feedrate * (float)move.data.mm3_per_mm; height_range.update_from(move.data.height); width_range.update_from(move.data.width); @@ -707,7 +707,7 @@ void GCodeAnalyzer::_calc_gcode_preview_extrusion_layers(GCodePreviewData& previ } else // append end vertex of the move to current polyline - polyline.append(Point(scale_(move.end_position.x), scale_(move.end_position.y))); + polyline.append(Point(scale_(move.end_position.x()), scale_(move.end_position.y()))); // update current values position = move.end_position; @@ -742,7 +742,7 @@ void GCodeAnalyzer::_calc_gcode_preview_travel(GCodePreviewData& preview_data) return; Polyline3 polyline; - Pointf3 position(FLT_MAX, FLT_MAX, FLT_MAX); + Vec3d position(FLT_MAX, FLT_MAX, FLT_MAX); GCodePreviewData::Travel::EType type = GCodePreviewData::Travel::Num_Types; GCodePreviewData::Travel::Polyline::EDirection direction = GCodePreviewData::Travel::Polyline::Num_Directions; float feedrate = FLT_MAX; @@ -756,7 +756,7 @@ void GCodeAnalyzer::_calc_gcode_preview_travel(GCodePreviewData& preview_data) for (const GCodeMove& move : travel_moves->second) { GCodePreviewData::Travel::EType move_type = (move.delta_extruder < 0.0f) ? GCodePreviewData::Travel::Retract : ((move.delta_extruder > 0.0f) ? GCodePreviewData::Travel::Extrude : GCodePreviewData::Travel::Move); - GCodePreviewData::Travel::Polyline::EDirection move_direction = ((move.start_position.x != move.end_position.x) || (move.start_position.y != move.end_position.y)) ? GCodePreviewData::Travel::Polyline::Generic : GCodePreviewData::Travel::Polyline::Vertical; + GCodePreviewData::Travel::Polyline::EDirection move_direction = ((move.start_position.x() != move.end_position.x()) || (move.start_position.y() != move.end_position.y())) ? GCodePreviewData::Travel::Polyline::Generic : GCodePreviewData::Travel::Polyline::Vertical; if ((type != move_type) || (direction != move_direction) || (feedrate != move.data.feedrate) || (position != move.start_position) || (extruder_id != move.data.extruder_id)) { @@ -768,12 +768,12 @@ void GCodeAnalyzer::_calc_gcode_preview_travel(GCodePreviewData& preview_data) polyline = Polyline3(); // add both vertices of the move - polyline.append(Point3(scale_(move.start_position.x), scale_(move.start_position.y), scale_(move.start_position.z))); - polyline.append(Point3(scale_(move.end_position.x), scale_(move.end_position.y), scale_(move.end_position.z))); + polyline.append(Vec3crd(scale_(move.start_position.x()), scale_(move.start_position.y()), scale_(move.start_position.z()))); + polyline.append(Vec3crd(scale_(move.end_position.x()), scale_(move.end_position.y()), scale_(move.end_position.z()))); } else // append end vertex of the move to current polyline - polyline.append(Point3(scale_(move.end_position.x), scale_(move.end_position.y), scale_(move.end_position.z))); + polyline.append(Vec3crd(scale_(move.end_position.x()), scale_(move.end_position.y()), scale_(move.end_position.z()))); // update current values position = move.end_position; @@ -804,7 +804,7 @@ void GCodeAnalyzer::_calc_gcode_preview_retractions(GCodePreviewData& preview_da for (const GCodeMove& move : retraction_moves->second) { // store position - Point3 position(scale_(move.start_position.x), scale_(move.start_position.y), scale_(move.start_position.z)); + Vec3crd position(scale_(move.start_position.x()), scale_(move.start_position.y()), scale_(move.start_position.z())); preview_data.retraction.positions.emplace_back(position, move.data.width, move.data.height); } } @@ -818,7 +818,7 @@ void GCodeAnalyzer::_calc_gcode_preview_unretractions(GCodePreviewData& preview_ for (const GCodeMove& move : unretraction_moves->second) { // store position - Point3 position(scale_(move.start_position.x), scale_(move.start_position.y), scale_(move.start_position.z)); + Vec3crd position(scale_(move.start_position.x()), scale_(move.start_position.y()), scale_(move.start_position.z())); preview_data.unretraction.positions.emplace_back(position, move.data.width, move.data.height); } } diff --git a/xs/src/libslic3r/GCode/Analyzer.hpp b/xs/src/libslic3r/GCode/Analyzer.hpp index 03dbab338..27a49b869 100644 --- a/xs/src/libslic3r/GCode/Analyzer.hpp +++ b/xs/src/libslic3r/GCode/Analyzer.hpp @@ -75,12 +75,12 @@ public: EType type; Metadata data; - Pointf3 start_position; - Pointf3 end_position; + Vec3d start_position; + Vec3d end_position; float delta_extruder; - GCodeMove(EType type, ExtrusionRole extrusion_role, unsigned int extruder_id, double mm3_per_mm, float width, float height, float feedrate, const Pointf3& start_position, const Pointf3& end_position, float delta_extruder); - GCodeMove(EType type, const Metadata& data, const Pointf3& start_position, const Pointf3& end_position, float delta_extruder); + GCodeMove(EType type, ExtrusionRole extrusion_role, unsigned int extruder_id, double mm3_per_mm, float width, float height, float feedrate, const Vec3d& start_position, const Vec3d& end_position, float delta_extruder); + GCodeMove(EType type, const Metadata& data, const Vec3d& start_position, const Vec3d& end_position, float delta_extruder); }; typedef std::vector<GCodeMove> GCodeMovesList; @@ -93,7 +93,7 @@ private: EPositioningType global_positioning_type; EPositioningType e_local_positioning_type; Metadata data; - Pointf3 start_position; + Vec3d start_position = Vec3d::Zero(); float start_extrusion; float position[Num_Axis]; }; @@ -206,15 +206,15 @@ private: // Sets axes position to zero void _reset_axes_position(); - void _set_start_position(const Pointf3& position); - const Pointf3& _get_start_position() const; + void _set_start_position(const Vec3d& position); + const Vec3d& _get_start_position() const; void _set_start_extrusion(float extrusion); float _get_start_extrusion() const; float _get_delta_extrusion() const; // Returns current xyz position (from m_state.position[]) - Pointf3 _get_end_position() const; + Vec3d _get_end_position() const; // Adds a new move with the given data void _store_move(GCodeMove::EType type); diff --git a/xs/src/libslic3r/GCode/CoolingBuffer.cpp b/xs/src/libslic3r/GCode/CoolingBuffer.cpp index a15247693..40ccc7b09 100644 --- a/xs/src/libslic3r/GCode/CoolingBuffer.cpp +++ b/xs/src/libslic3r/GCode/CoolingBuffer.cpp @@ -23,10 +23,10 @@ CoolingBuffer::CoolingBuffer(GCode &gcodegen) : m_gcodegen(gcodegen), m_current_ void CoolingBuffer::reset() { m_current_pos.assign(5, 0.f); - Pointf3 pos = m_gcodegen.writer().get_position(); - m_current_pos[0] = float(pos.x); - m_current_pos[1] = float(pos.y); - m_current_pos[2] = float(pos.z); + Vec3d pos = m_gcodegen.writer().get_position(); + m_current_pos[0] = float(pos(0)); + m_current_pos[1] = float(pos(1)); + m_current_pos[2] = float(pos(2)); m_current_pos[4] = float(m_gcodegen.config().travel_speed.value); } diff --git a/xs/src/libslic3r/GCode/PreviewData.cpp b/xs/src/libslic3r/GCode/PreviewData.cpp index 3833bca06..9cf9716e0 100644 --- a/xs/src/libslic3r/GCode/PreviewData.cpp +++ b/xs/src/libslic3r/GCode/PreviewData.cpp @@ -226,7 +226,7 @@ void GCodePreviewData::Travel::set_default() const GCodePreviewData::Color GCodePreviewData::Retraction::Default_Color = GCodePreviewData::Color(1.0f, 1.0f, 1.0f, 1.0f); -GCodePreviewData::Retraction::Position::Position(const Point3& position, float width, float height) +GCodePreviewData::Retraction::Position::Position(const Vec3crd& position, float width, float height) : position(position) , width(width) , height(height) diff --git a/xs/src/libslic3r/GCode/PreviewData.hpp b/xs/src/libslic3r/GCode/PreviewData.hpp index ea8ca6d58..ab74993f5 100644 --- a/xs/src/libslic3r/GCode/PreviewData.hpp +++ b/xs/src/libslic3r/GCode/PreviewData.hpp @@ -151,11 +151,11 @@ public: struct Position { - Point3 position; + Vec3crd position; float width; float height; - Position(const Point3& position, float width, float height); + Position(const Vec3crd& position, float width, float height); }; typedef std::vector<Position> PositionsList; diff --git a/xs/src/libslic3r/GCode/PrintExtents.cpp b/xs/src/libslic3r/GCode/PrintExtents.cpp index 37b79f343..2ed607769 100644 --- a/xs/src/libslic3r/GCode/PrintExtents.cpp +++ b/xs/src/libslic3r/GCode/PrintExtents.cpp @@ -19,10 +19,10 @@ static inline BoundingBox extrusion_polyline_extents(const Polyline &polyline, c if (! polyline.points.empty()) bbox.merge(polyline.points.front()); for (const Point &pt : polyline.points) { - bbox.min.x = std::min(bbox.min.x, pt.x - radius); - bbox.min.y = std::min(bbox.min.y, pt.y - radius); - bbox.max.x = std::max(bbox.max.x, pt.x + radius); - bbox.max.y = std::max(bbox.max.y, pt.y + radius); + bbox.min(0) = std::min(bbox.min(0), pt(0) - radius); + bbox.min(1) = std::min(bbox.min(1), pt(1) - radius); + bbox.max(0) = std::max(bbox.max(0), pt(0) + radius); + bbox.max(1) = std::max(bbox.max(1), pt(1) + radius); } return bbox; } @@ -32,8 +32,8 @@ static inline BoundingBoxf extrusionentity_extents(const ExtrusionPath &extrusio BoundingBox bbox = extrusion_polyline_extents(extrusion_path.polyline, scale_(0.5 * extrusion_path.width)); BoundingBoxf bboxf; if (! empty(bbox)) { - bboxf.min = Pointf::new_unscale(bbox.min); - bboxf.max = Pointf::new_unscale(bbox.max); + bboxf.min = unscale(bbox.min); + bboxf.max = unscale(bbox.max); bboxf.defined = true; } return bboxf; @@ -46,8 +46,8 @@ static inline BoundingBoxf extrusionentity_extents(const ExtrusionLoop &extrusio bbox.merge(extrusion_polyline_extents(extrusion_path.polyline, scale_(0.5 * extrusion_path.width))); BoundingBoxf bboxf; if (! empty(bbox)) { - bboxf.min = Pointf::new_unscale(bbox.min); - bboxf.max = Pointf::new_unscale(bbox.max); + bboxf.min = unscale(bbox.min); + bboxf.max = unscale(bbox.max); bboxf.defined = true; } return bboxf; @@ -60,8 +60,8 @@ static inline BoundingBoxf extrusionentity_extents(const ExtrusionMultiPath &ext bbox.merge(extrusion_polyline_extents(extrusion_path.polyline, scale_(0.5 * extrusion_path.width))); BoundingBoxf bboxf; if (! empty(bbox)) { - bboxf.min = Pointf::new_unscale(bbox.min); - bboxf.max = Pointf::new_unscale(bbox.max); + bboxf.min = unscale(bbox.min); + bboxf.max = unscale(bbox.max); bboxf.defined = true; } return bboxf; @@ -123,7 +123,7 @@ BoundingBoxf get_print_object_extrusions_extents(const PrintObject &print_object bbox_this.merge(extrusionentity_extents(extrusion_entity)); for (const Point &offset : print_object._shifted_copies) { BoundingBoxf bbox_translated(bbox_this); - bbox_translated.translate(Pointf::new_unscale(offset)); + bbox_translated.translate(unscale(offset)); bbox.merge(bbox_translated); } } @@ -136,8 +136,9 @@ BoundingBoxf get_wipe_tower_extrusions_extents(const Print &print, const coordf_ { // Wipe tower extrusions are saved as if the tower was at the origin with no rotation // We need to get position and angle of the wipe tower to transform them to actual position. - Pointf wipe_tower_pos(print.config.wipe_tower_x.value, print.config.wipe_tower_y.value); - float wipe_tower_angle = print.config.wipe_tower_rotation_angle.value; + Transform2d trafo = + Eigen::Translation2d(print.config.wipe_tower_x.value, print.config.wipe_tower_y.value) * + Eigen::Rotation2Dd(print.config.wipe_tower_rotation_angle.value); BoundingBoxf bbox; for (const std::vector<WipeTower::ToolChangeResult> &tool_changes : print.m_wipe_tower_tool_changes) { @@ -147,19 +148,11 @@ BoundingBoxf get_wipe_tower_extrusions_extents(const Print &print, const coordf_ for (size_t i = 1; i < tcr.extrusions.size(); ++ i) { const WipeTower::Extrusion &e = tcr.extrusions[i]; if (e.width > 0) { - Pointf p1((&e - 1)->pos.x, (&e - 1)->pos.y); - Pointf p2(e.pos.x, e.pos.y); - p1.rotate(wipe_tower_angle); - p1.translate(wipe_tower_pos); - p2.rotate(wipe_tower_angle); - p2.translate(wipe_tower_pos); - - bbox.merge(p1); - coordf_t radius = 0.5 * e.width; - bbox.min.x = std::min(bbox.min.x, std::min(p1.x, p2.x) - radius); - bbox.min.y = std::min(bbox.min.y, std::min(p1.y, p2.y) - radius); - bbox.max.x = std::max(bbox.max.x, std::max(p1.x, p2.x) + radius); - bbox.max.y = std::max(bbox.max.y, std::max(p1.y, p2.y) + radius); + Vec2d delta = 0.5 * Vec2d(e.width, e.width); + Vec2d p1 = trafo * Vec2d((&e - 1)->pos.x, (&e - 1)->pos.y); + Vec2d p2 = trafo * Vec2d(e.pos.x, e.pos.y); + bbox.merge(p1.cwiseMin(p2) - delta); + bbox.merge(p1.cwiseMax(p2) + delta); } } } @@ -176,14 +169,14 @@ BoundingBoxf get_wipe_tower_priming_extrusions_extents(const Print &print) for (size_t i = 1; i < tcr.extrusions.size(); ++ i) { const WipeTower::Extrusion &e = tcr.extrusions[i]; if (e.width > 0) { - Pointf p1((&e - 1)->pos.x, (&e - 1)->pos.y); - Pointf p2(e.pos.x, e.pos.y); + Vec2d p1((&e - 1)->pos.x, (&e - 1)->pos.y); + Vec2d p2(e.pos.x, e.pos.y); bbox.merge(p1); coordf_t radius = 0.5 * e.width; - bbox.min.x = std::min(bbox.min.x, std::min(p1.x, p2.x) - radius); - bbox.min.y = std::min(bbox.min.y, std::min(p1.y, p2.y) - radius); - bbox.max.x = std::max(bbox.max.x, std::max(p1.x, p2.x) + radius); - bbox.max.y = std::max(bbox.max.y, std::max(p1.y, p2.y) + radius); + bbox.min(0) = std::min(bbox.min(0), std::min(p1(0), p2(0)) - radius); + bbox.min(1) = std::min(bbox.min(1), std::min(p1(1), p2(1)) - radius); + bbox.max(0) = std::max(bbox.max(0), std::max(p1(0), p2(0)) + radius); + bbox.max(1) = std::max(bbox.max(1), std::max(p1(1), p2(1)) + radius); } } } diff --git a/xs/src/libslic3r/GCode/WipeTower.hpp b/xs/src/libslic3r/GCode/WipeTower.hpp index 9bf350328..c35a0feb3 100644 --- a/xs/src/libslic3r/GCode/WipeTower.hpp +++ b/xs/src/libslic3r/GCode/WipeTower.hpp @@ -30,10 +30,9 @@ public: xy out(0,0); float temp_x = x - width / 2.f; float temp_y = y - depth / 2.f; - angle *= M_PI/180.; + angle *= float(M_PI/180.); out.x += temp_x * cos(angle) - temp_y * sin(angle) + width / 2.f; out.y += temp_x * sin(angle) + temp_y * cos(angle) + depth / 2.f; - return out; } diff --git a/xs/src/libslic3r/GCodeWriter.cpp b/xs/src/libslic3r/GCodeWriter.cpp index 34e6b7ec3..6ef17f4f4 100644 --- a/xs/src/libslic3r/GCodeWriter.cpp +++ b/xs/src/libslic3r/GCodeWriter.cpp @@ -276,30 +276,30 @@ std::string GCodeWriter::set_speed(double F, const std::string &comment, const s return gcode.str(); } -std::string GCodeWriter::travel_to_xy(const Pointf &point, const std::string &comment) +std::string GCodeWriter::travel_to_xy(const Vec2d &point, const std::string &comment) { - m_pos.x = point.x; - m_pos.y = point.y; + m_pos(0) = point(0); + m_pos(1) = point(1); std::ostringstream gcode; - gcode << "G1 X" << XYZF_NUM(point.x) - << " Y" << XYZF_NUM(point.y) + gcode << "G1 X" << XYZF_NUM(point(0)) + << " Y" << XYZF_NUM(point(1)) << " F" << XYZF_NUM(this->config.travel_speed.value * 60.0); COMMENT(comment); gcode << "\n"; return gcode.str(); } -std::string GCodeWriter::travel_to_xyz(const Pointf3 &point, const std::string &comment) +std::string GCodeWriter::travel_to_xyz(const Vec3d &point, const std::string &comment) { /* If target Z is lower than current Z but higher than nominal Z we don't perform the Z move but we only move in the XY plane and adjust the nominal Z by reducing the lift amount that will be used for unlift. */ - if (!this->will_move_z(point.z)) { - double nominal_z = m_pos.z - m_lifted; - m_lifted = m_lifted - (point.z - nominal_z); - return this->travel_to_xy(point); + if (!this->will_move_z(point(2))) { + double nominal_z = m_pos(2) - m_lifted; + m_lifted = m_lifted - (point(2) - nominal_z); + return this->travel_to_xy(to_2d(point)); } /* In all the other cases, we perform an actual XYZ move and cancel @@ -308,9 +308,9 @@ std::string GCodeWriter::travel_to_xyz(const Pointf3 &point, const std::string & m_pos = point; std::ostringstream gcode; - gcode << "G1 X" << XYZF_NUM(point.x) - << " Y" << XYZF_NUM(point.y) - << " Z" << XYZF_NUM(point.z) + gcode << "G1 X" << XYZF_NUM(point(0)) + << " Y" << XYZF_NUM(point(1)) + << " Z" << XYZF_NUM(point(2)) << " F" << XYZF_NUM(this->config.travel_speed.value * 60.0); COMMENT(comment); gcode << "\n"; @@ -323,7 +323,7 @@ std::string GCodeWriter::travel_to_z(double z, const std::string &comment) we don't perform the move but we only adjust the nominal Z by reducing the lift amount that will be used for unlift. */ if (!this->will_move_z(z)) { - double nominal_z = m_pos.z - m_lifted; + double nominal_z = m_pos(2) - m_lifted; m_lifted = m_lifted - (z - nominal_z); return ""; } @@ -336,7 +336,7 @@ std::string GCodeWriter::travel_to_z(double z, const std::string &comment) std::string GCodeWriter::_travel_to_z(double z, const std::string &comment) { - m_pos.z = z; + m_pos(2) = z; std::ostringstream gcode; gcode << "G1 Z" << XYZF_NUM(z) @@ -351,38 +351,38 @@ bool GCodeWriter::will_move_z(double z) const /* If target Z is lower than current Z but higher than nominal Z we don't perform an actual Z move. */ if (m_lifted > 0) { - double nominal_z = m_pos.z - m_lifted; - if (z >= nominal_z && z <= m_pos.z) + double nominal_z = m_pos(2) - m_lifted; + if (z >= nominal_z && z <= m_pos(2)) return false; } return true; } -std::string GCodeWriter::extrude_to_xy(const Pointf &point, double dE, const std::string &comment) +std::string GCodeWriter::extrude_to_xy(const Vec2d &point, double dE, const std::string &comment) { - m_pos.x = point.x; - m_pos.y = point.y; + m_pos(0) = point(0); + m_pos(1) = point(1); m_extruder->extrude(dE); std::ostringstream gcode; - gcode << "G1 X" << XYZF_NUM(point.x) - << " Y" << XYZF_NUM(point.y) + gcode << "G1 X" << XYZF_NUM(point(0)) + << " Y" << XYZF_NUM(point(1)) << " " << m_extrusion_axis << E_NUM(m_extruder->E()); COMMENT(comment); gcode << "\n"; return gcode.str(); } -std::string GCodeWriter::extrude_to_xyz(const Pointf3 &point, double dE, const std::string &comment) +std::string GCodeWriter::extrude_to_xyz(const Vec3d &point, double dE, const std::string &comment) { m_pos = point; m_lifted = 0; m_extruder->extrude(dE); std::ostringstream gcode; - gcode << "G1 X" << XYZF_NUM(point.x) - << " Y" << XYZF_NUM(point.y) - << " Z" << XYZF_NUM(point.z) + gcode << "G1 X" << XYZF_NUM(point(0)) + << " Y" << XYZF_NUM(point(1)) + << " Z" << XYZF_NUM(point(2)) << " " << m_extrusion_axis << E_NUM(m_extruder->E()); COMMENT(comment); gcode << "\n"; @@ -486,12 +486,12 @@ std::string GCodeWriter::lift() { double above = this->config.retract_lift_above.get_at(m_extruder->id()); double below = this->config.retract_lift_below.get_at(m_extruder->id()); - if (m_pos.z >= above && (below == 0 || m_pos.z <= below)) + if (m_pos(2) >= above && (below == 0 || m_pos(2) <= below)) target_lift = this->config.retract_lift.get_at(m_extruder->id()); } if (m_lifted == 0 && target_lift > 0) { m_lifted = target_lift; - return this->_travel_to_z(m_pos.z + target_lift, "lift Z"); + return this->_travel_to_z(m_pos(2) + target_lift, "lift Z"); } return ""; } @@ -500,7 +500,7 @@ std::string GCodeWriter::unlift() { std::string gcode; if (m_lifted > 0) { - gcode += this->_travel_to_z(m_pos.z - m_lifted, "restore layer Z"); + gcode += this->_travel_to_z(m_pos(2) - m_lifted, "restore layer Z"); m_lifted = 0; } return gcode; diff --git a/xs/src/libslic3r/GCodeWriter.hpp b/xs/src/libslic3r/GCodeWriter.hpp index f706b8768..664b0e3a1 100644 --- a/xs/src/libslic3r/GCodeWriter.hpp +++ b/xs/src/libslic3r/GCodeWriter.hpp @@ -55,18 +55,18 @@ public: std::string toolchange_prefix() const; std::string toolchange(unsigned int extruder_id); std::string set_speed(double F, const std::string &comment = std::string(), const std::string &cooling_marker = std::string()) const; - std::string travel_to_xy(const Pointf &point, const std::string &comment = std::string()); - std::string travel_to_xyz(const Pointf3 &point, const std::string &comment = std::string()); + std::string travel_to_xy(const Vec2d &point, const std::string &comment = std::string()); + std::string travel_to_xyz(const Vec3d &point, const std::string &comment = std::string()); std::string travel_to_z(double z, const std::string &comment = std::string()); bool will_move_z(double z) const; - std::string extrude_to_xy(const Pointf &point, double dE, const std::string &comment = std::string()); - std::string extrude_to_xyz(const Pointf3 &point, double dE, const std::string &comment = std::string()); + std::string extrude_to_xy(const Vec2d &point, double dE, const std::string &comment = std::string()); + std::string extrude_to_xyz(const Vec3d &point, double dE, const std::string &comment = std::string()); std::string retract(bool before_wipe = false); std::string retract_for_toolchange(bool before_wipe = false); std::string unretract(); std::string lift(); std::string unlift(); - Pointf3 get_position() const { return m_pos; } + Vec3d get_position() const { return m_pos; } private: std::vector<Extruder> m_extruders; @@ -81,7 +81,7 @@ private: unsigned int m_last_bed_temperature; bool m_last_bed_temperature_reached; double m_lifted; - Pointf3 m_pos; + Vec3d m_pos = Vec3d::Zero(); std::string _travel_to_z(double z, const std::string &comment); std::string _retract(double length, double restart_extra, const std::string &comment); diff --git a/xs/src/libslic3r/Geometry.cpp b/xs/src/libslic3r/Geometry.cpp index aaf0352c9..b0ded2d04 100644 --- a/xs/src/libslic3r/Geometry.cpp +++ b/xs/src/libslic3r/Geometry.cpp @@ -195,26 +195,29 @@ using namespace boost::polygon; // provides also high() and low() namespace Slic3r { namespace Geometry { -struct SortPoints { - template <class T> - bool operator()(const T& a, const T& b) const { - return (b.x > a.x) || (a.x == b.x && b.y > a.y); - } -}; +static bool sort_points(const Point& a, const Point& b) +{ + return (a(0) < b(0)) || (a(0) == b(0) && a(1) < b(1)); +} + +static bool sort_pointfs(const Vec3d& a, const Vec3d& b) +{ + return (a(0) < b(0)) || (a(0) == b(0) && a(1) < b(1)); +} // This implementation is based on Andrew's monotone chain 2D convex hull algorithm -template<class T> -static T raw_convex_hull(T& points) +Polygon +convex_hull(Points points) { assert(points.size() >= 3); // sort input points - std::sort(points.begin(), points.end(), SortPoints()); - + std::sort(points.begin(), points.end(), sort_points); + int n = points.size(), k = 0; - T hull; + Polygon hull; if (n >= 3) { - hull.resize(2*n); + hull.points.resize(2 * n); // Build lower hull for (int i = 0; i < n; i++) { @@ -228,10 +231,10 @@ static T raw_convex_hull(T& points) hull[k++] = points[i]; } - hull.resize(k); - - assert( hull.front().coincides_with(hull.back()) ); - hull.pop_back(); + hull.points.resize(k); + + assert(hull.points.front() == hull.points.back()); + hull.points.pop_back(); } return hull; @@ -240,14 +243,59 @@ static T raw_convex_hull(T& points) Pointf3s convex_hull(Pointf3s points) { - return raw_convex_hull(points); -} + assert(points.size() >= 3); + // sort input points + std::sort(points.begin(), points.end(), sort_pointfs); + + int n = points.size(), k = 0; + Pointf3s hull; + + if (n >= 3) + { + hull.resize(2 * n); + + // Build lower hull + for (int i = 0; i < n; ++i) + { + Point p = Point::new_scale(points[i](0), points[i](1)); + while (k >= 2) + { + Point k1 = Point::new_scale(hull[k - 1](0), hull[k - 1](1)); + Point k2 = Point::new_scale(hull[k - 2](0), hull[k - 2](1)); + + if (p.ccw(k2, k1) <= 0) + --k; + else + break; + } + + hull[k++] = points[i]; + } + + // Build upper hull + for (int i = n - 2, t = k + 1; i >= 0; --i) + { + Point p = Point::new_scale(points[i](0), points[i](1)); + while (k >= t) + { + Point k1 = Point::new_scale(hull[k - 1](0), hull[k - 1](1)); + Point k2 = Point::new_scale(hull[k - 2](0), hull[k - 2](1)); + + if (p.ccw(k2, k1) <= 0) + --k; + else + break; + } + + hull[k++] = points[i]; + } + + hull.resize(k); + + assert(hull.front() == hull.back()); + hull.pop_back(); + } -Polygon -convex_hull(Points points) -{ - Polygon hull; - hull.points = raw_convex_hull(points); return hull; } @@ -360,54 +408,54 @@ linint(double value, double oldmin, double oldmax, double newmin, double newmax) // If the points have the same weight, sort them lexicographically by their positions. struct ArrangeItem { ArrangeItem() {} - Pointf pos; + Vec2d pos; coordf_t weight; bool operator<(const ArrangeItem &other) const { return weight < other.weight || - ((weight == other.weight) && (pos.y < other.pos.y || (pos.y == other.pos.y && pos.x < other.pos.x))); + ((weight == other.weight) && (pos(1) < other.pos(1) || (pos(1) == other.pos(1) && pos(0) < other.pos(0)))); } }; -Pointfs arrange(size_t num_parts, const Pointf &part_size, coordf_t gap, const BoundingBoxf* bed_bounding_box) +Pointfs arrange(size_t num_parts, const Vec2d &part_size, coordf_t gap, const BoundingBoxf* bed_bounding_box) { // Use actual part size (the largest) plus separation distance (half on each side) in spacing algorithm. - const Pointf cell_size(part_size.x + gap, part_size.y + gap); + const Vec2d cell_size(part_size(0) + gap, part_size(1) + gap); const BoundingBoxf bed_bbox = (bed_bounding_box != NULL && bed_bounding_box->defined) ? *bed_bounding_box : // Bogus bed size, large enough not to trigger the unsufficient bed size error. BoundingBoxf( - Pointf(0, 0), - Pointf(cell_size.x * num_parts, cell_size.y * num_parts)); + Vec2d(0, 0), + Vec2d(cell_size(0) * num_parts, cell_size(1) * num_parts)); // This is how many cells we have available into which to put parts. - size_t cellw = size_t(floor((bed_bbox.size().x + gap) / cell_size.x)); - size_t cellh = size_t(floor((bed_bbox.size().y + gap) / cell_size.y)); + size_t cellw = size_t(floor((bed_bbox.size()(0) + gap) / cell_size(0))); + size_t cellh = size_t(floor((bed_bbox.size()(1) + gap) / cell_size(1))); if (num_parts > cellw * cellh) CONFESS(PRINTF_ZU " parts won't fit in your print area!\n", num_parts); // Get a bounding box of cellw x cellh cells, centered at the center of the bed. - Pointf cells_size(cellw * cell_size.x - gap, cellh * cell_size.y - gap); - Pointf cells_offset(bed_bbox.center() - 0.5 * cells_size); + Vec2d cells_size(cellw * cell_size(0) - gap, cellh * cell_size(1) - gap); + Vec2d cells_offset(bed_bbox.center() - 0.5 * cells_size); BoundingBoxf cells_bb(cells_offset, cells_size + cells_offset); // List of cells, sorted by distance from center. std::vector<ArrangeItem> cellsorder(cellw * cellh, ArrangeItem()); for (size_t j = 0; j < cellh; ++ j) { // Center of the jth row on the bed. - coordf_t cy = linint(j + 0.5, 0., double(cellh), cells_bb.min.y, cells_bb.max.y); + coordf_t cy = linint(j + 0.5, 0., double(cellh), cells_bb.min(1), cells_bb.max(1)); // Offset from the bed center. - coordf_t yd = cells_bb.center().y - cy; + coordf_t yd = cells_bb.center()(1) - cy; for (size_t i = 0; i < cellw; ++ i) { // Center of the ith column on the bed. - coordf_t cx = linint(i + 0.5, 0., double(cellw), cells_bb.min.x, cells_bb.max.x); + coordf_t cx = linint(i + 0.5, 0., double(cellw), cells_bb.min(0), cells_bb.max(0)); // Offset from the bed center. - coordf_t xd = cells_bb.center().x - cx; + coordf_t xd = cells_bb.center()(0) - cx; // Cell with a distance from the bed center. ArrangeItem &ci = cellsorder[j * cellw + i]; // Cell center - ci.pos.x = cx; - ci.pos.y = cy; + ci.pos(0) = cx; + ci.pos(1) = cy; // Square distance of the cell center to the bed center. ci.weight = xd * xd + yd * yd; } @@ -420,61 +468,61 @@ Pointfs arrange(size_t num_parts, const Pointf &part_size, coordf_t gap, const B Pointfs positions; positions.reserve(num_parts); for (std::vector<ArrangeItem>::const_iterator it = cellsorder.begin(); it != cellsorder.end(); ++ it) - positions.push_back(Pointf(it->pos.x - 0.5 * part_size.x, it->pos.y - 0.5 * part_size.y)); + positions.push_back(Vec2d(it->pos(0) - 0.5 * part_size(0), it->pos(1) - 0.5 * part_size(1))); return positions; } #else class ArrangeItem { - public: - Pointf pos; +public: + Vec2d pos = Vec2d::Zero(); size_t index_x, index_y; coordf_t dist; }; class ArrangeItemIndex { - public: +public: coordf_t index; ArrangeItem item; ArrangeItemIndex(coordf_t _index, ArrangeItem _item) : index(_index), item(_item) {}; }; bool -arrange(size_t total_parts, const Pointf &part_size, coordf_t dist, const BoundingBoxf* bb, Pointfs &positions) +arrange(size_t total_parts, const Vec2d &part_size, coordf_t dist, const BoundingBoxf* bb, Pointfs &positions) { positions.clear(); - Pointf part = part_size; + Vec2d part = part_size; // use actual part size (the largest) plus separation distance (half on each side) in spacing algorithm - part.x += dist; - part.y += dist; + part(0) += dist; + part(1) += dist; - Pointf area; + Vec2d area(Vec2d::Zero()); if (bb != NULL && bb->defined) { area = bb->size(); } else { // bogus area size, large enough not to trigger the error below - area.x = part.x * total_parts; - area.y = part.y * total_parts; + area(0) = part(0) * total_parts; + area(1) = part(1) * total_parts; } // this is how many cells we have available into which to put parts - size_t cellw = floor((area.x + dist) / part.x); - size_t cellh = floor((area.y + dist) / part.y); + size_t cellw = floor((area(0) + dist) / part(0)); + size_t cellh = floor((area(1) + dist) / part(1)); if (total_parts > (cellw * cellh)) return false; // total space used by cells - Pointf cells(cellw * part.x, cellh * part.y); + Vec2d cells(cellw * part(0), cellh * part(1)); // bounding box of total space used by cells BoundingBoxf cells_bb; - cells_bb.merge(Pointf(0,0)); // min + cells_bb.merge(Vec2d(0,0)); // min cells_bb.merge(cells); // max // center bounding box to area cells_bb.translate( - (area.x - cells.x) / 2, - (area.y - cells.y) / 2 + (area(0) - cells(0)) / 2, + (area(1) - cells(1)) / 2 ); // list of cells, sorted by distance from center @@ -483,15 +531,15 @@ arrange(size_t total_parts, const Pointf &part_size, coordf_t dist, const Boundi // work out distance for all cells, sort into list for (size_t i = 0; i <= cellw-1; ++i) { for (size_t j = 0; j <= cellh-1; ++j) { - coordf_t cx = linint(i + 0.5, 0, cellw, cells_bb.min.x, cells_bb.max.x); - coordf_t cy = linint(j + 0.5, 0, cellh, cells_bb.min.y, cells_bb.max.y); + coordf_t cx = linint(i + 0.5, 0, cellw, cells_bb.min(0), cells_bb.max(0)); + coordf_t cy = linint(j + 0.5, 0, cellh, cells_bb.min(1), cells_bb.max(1)); - coordf_t xd = fabs((area.x / 2) - cx); - coordf_t yd = fabs((area.y / 2) - cy); + coordf_t xd = fabs((area(0) / 2) - cx); + coordf_t yd = fabs((area(1) / 2) - cy); ArrangeItem c; - c.pos.x = cx; - c.pos.y = cy; + c.pos(0) = cx; + c.pos(1) = cy; c.index_x = i; c.index_y = j; c.dist = xd * xd + yd * yd - fabs((cellw / 2) - (i + 0.5)); @@ -548,13 +596,13 @@ arrange(size_t total_parts, const Pointf &part_size, coordf_t dist, const Boundi coordf_t cx = c.item.index_x - lx; coordf_t cy = c.item.index_y - ty; - positions.push_back(Pointf(cx * part.x, cy * part.y)); + positions.push_back(Vec2d(cx * part(0), cy * part(1))); } if (bb != NULL && bb->defined) { for (Pointfs::iterator p = positions.begin(); p != positions.end(); ++p) { - p->x += bb->min.x; - p->y += bb->min.y; + p->x() += bb->min(0); + p->y() += bb->min(1); } } @@ -623,15 +671,15 @@ namespace Voronoi { namespace Internal { if (cell1.contains_point() && cell2.contains_point()) { point_type p1 = retrieve_point(segments, cell1); point_type p2 = retrieve_point(segments, cell2); - origin.x((p1.x() + p2.x()) * 0.5); - origin.y((p1.y() + p2.y()) * 0.5); - direction.x(p1.y() - p2.y()); - direction.y(p2.x() - p1.x()); + origin.x((p1(0) + p2(0)) * 0.5); + origin.y((p1(1) + p2(1)) * 0.5); + direction.x(p1(1) - p2(1)); + direction.y(p2(0) - p1(0)); } else { origin = cell1.contains_segment() ? retrieve_point(segments, cell2) : retrieve_point(segments, cell1); segment_type segment = cell1.contains_segment() ? segments[cell1.source_index()] : segments[cell2.source_index()]; - coordinate_type dx = high(segment).x() - low(segment).x(); - coordinate_type dy = high(segment).y() - low(segment).y(); + coordinate_type dx = high(segment)(0) - low(segment)(0); + coordinate_type dy = high(segment)(1) - low(segment)(1); if ((low(segment) == origin) ^ cell1.contains_point()) { direction.x(dy); direction.y(-dx); @@ -640,19 +688,19 @@ namespace Voronoi { namespace Internal { direction.y(dx); } } - coordinate_type koef = bbox_max_size / (std::max)(fabs(direction.x()), fabs(direction.y())); + coordinate_type koef = bbox_max_size / (std::max)(fabs(direction(0)), fabs(direction(1))); if (edge.vertex0() == NULL) { clipped_edge->push_back(point_type( - origin.x() - direction.x() * koef, - origin.y() - direction.y() * koef)); + origin(0) - direction(0) * koef, + origin(1) - direction(1) * koef)); } else { clipped_edge->push_back( point_type(edge.vertex0()->x(), edge.vertex0()->y())); } if (edge.vertex1() == NULL) { clipped_edge->push_back(point_type( - origin.x() + direction.x() * koef, - origin.y() + direction.y() * koef)); + origin(0) + direction(0) * koef, + origin(1) + direction(1) * koef)); } else { clipped_edge->push_back( point_type(edge.vertex1()->x(), edge.vertex1()->y())); @@ -691,10 +739,10 @@ static inline void dump_voronoi_to_svg(const Lines &lines, /* const */ voronoi_d const bool primaryEdgesOnly = false; BoundingBox bbox = BoundingBox(lines); - bbox.min.x -= coord_t(1. / SCALING_FACTOR); - bbox.min.y -= coord_t(1. / SCALING_FACTOR); - bbox.max.x += coord_t(1. / SCALING_FACTOR); - bbox.max.y += coord_t(1. / SCALING_FACTOR); + bbox.min(0) -= coord_t(1. / SCALING_FACTOR); + bbox.min(1) -= coord_t(1. / SCALING_FACTOR); + bbox.max(0) += coord_t(1. / SCALING_FACTOR); + bbox.max(1) += coord_t(1. / SCALING_FACTOR); ::Slic3r::SVG svg(path, bbox); @@ -704,7 +752,7 @@ static inline void dump_voronoi_to_svg(const Lines &lines, /* const */ voronoi_d // bbox.scale(1.2); // For clipping of half-lines to some reasonable value. // The line will then be clipped by the SVG viewer anyway. - const double bbox_dim_max = double(bbox.max.x - bbox.min.x) + double(bbox.max.y - bbox.min.y); + const double bbox_dim_max = double(bbox.max(0) - bbox.min(0)) + double(bbox.max(1) - bbox.min(1)); // For the discretization of the Voronoi parabolic segments. const double discretization_step = 0.0005 * bbox_dim_max; @@ -712,8 +760,8 @@ static inline void dump_voronoi_to_svg(const Lines &lines, /* const */ voronoi_d std::vector<Voronoi::Internal::segment_type> segments; for (Lines::const_iterator it = lines.begin(); it != lines.end(); ++ it) segments.push_back(Voronoi::Internal::segment_type( - Voronoi::Internal::point_type(double(it->a.x), double(it->a.y)), - Voronoi::Internal::point_type(double(it->b.x), double(it->b.y)))); + Voronoi::Internal::point_type(double(it->a(0)), double(it->a(1))), + Voronoi::Internal::point_type(double(it->b(0)), double(it->b(1))))); // Color exterior edges. for (voronoi_diagram<double>::const_edge_iterator it = vd.edges().begin(); it != vd.edges().end(); ++it) @@ -727,13 +775,13 @@ static inline void dump_voronoi_to_svg(const Lines &lines, /* const */ voronoi_d } // Draw the input polygon. for (Lines::const_iterator it = lines.begin(); it != lines.end(); ++it) - svg.draw(Line(Point(coord_t(it->a.x), coord_t(it->a.y)), Point(coord_t(it->b.x), coord_t(it->b.y))), inputSegmentColor, inputSegmentLineWidth); + svg.draw(Line(Point(coord_t(it->a(0)), coord_t(it->a(1))), Point(coord_t(it->b(0)), coord_t(it->b(1)))), inputSegmentColor, inputSegmentLineWidth); #if 1 // Draw voronoi vertices. for (voronoi_diagram<double>::const_vertex_iterator it = vd.vertices().begin(); it != vd.vertices().end(); ++it) if (! internalEdgesOnly || it->color() != Voronoi::Internal::EXTERNAL_COLOR) - svg.draw(Point(coord_t(it->x()), coord_t(it->y())), voronoiPointColor, voronoiPointRadius); + svg.draw(Point(coord_t((*it)(0)), coord_t((*it)(1))), voronoiPointColor, voronoiPointRadius); for (voronoi_diagram<double>::const_edge_iterator it = vd.edges().begin(); it != vd.edges().end(); ++it) { if (primaryEdgesOnly && !it->is_primary()) @@ -758,7 +806,7 @@ static inline void dump_voronoi_to_svg(const Lines &lines, /* const */ voronoi_d color = voronoiLineColorSecondary; } for (std::size_t i = 0; i + 1 < samples.size(); ++i) - svg.draw(Line(Point(coord_t(samples[i].x()), coord_t(samples[i].y())), Point(coord_t(samples[i+1].x()), coord_t(samples[i+1].y()))), color, voronoiLineWidth); + svg.draw(Line(Point(coord_t(samples[i](0)), coord_t(samples[i](1))), Point(coord_t(samples[i+1](0)), coord_t(samples[i+1](1)))), color, voronoiLineWidth); } #endif @@ -773,8 +821,8 @@ static inline void dump_voronoi_to_svg(const Lines &lines, /* const */ voronoi_d template<typename T> T dist(const boost::polygon::point_data<T> &p1,const boost::polygon::point_data<T> &p2) { - T dx = p2.x() - p1.x(); - T dy = p2.y() - p1.y(); + T dx = p2(0) - p1(0); + T dy = p2(1) - p1(1); return sqrt(dx*dx+dy*dy); } @@ -785,11 +833,11 @@ inline point_type project_point_to_segment(segment_type &seg, point_type &px) typedef typename point_type::coordinate_type T; const point_type &p0 = low(seg); const point_type &p1 = high(seg); - const point_type dir(p1.x()-p0.x(), p1.y()-p0.y()); - const point_type dproj(px.x()-p0.x(), px.y()-p0.y()); - const T t = (dir.x()*dproj.x() + dir.y()*dproj.y()) / (dir.x()*dir.x() + dir.y()*dir.y()); + const point_type dir(p1(0)-p0(0), p1(1)-p0(1)); + const point_type dproj(px(0)-p0(0), px(1)-p0(1)); + const T t = (dir(0)*dproj(0) + dir(1)*dproj(1)) / (dir(0)*dir(0) + dir(1)*dir(1)); assert(t >= T(-1e-6) && t <= T(1. + 1e-6)); - return point_type(p0.x() + t*dir.x(), p0.y() + t*dir.y()); + return point_type(p0(0) + t*dir(0), p0(1) + t*dir(1)); } template<typename VD, typename SEGMENTS> @@ -843,8 +891,8 @@ public: Lines2VDSegments(const Lines &alines) : lines(alines) {} typename VD::segment_type operator[](size_t idx) const { return typename VD::segment_type( - typename VD::point_type(typename VD::coord_type(lines[idx].a.x), typename VD::coord_type(lines[idx].a.y)), - typename VD::point_type(typename VD::coord_type(lines[idx].b.x), typename VD::coord_type(lines[idx].b.y))); + typename VD::point_type(typename VD::coord_type(lines[idx].a(0)), typename VD::coord_type(lines[idx].a(1))), + typename VD::point_type(typename VD::coord_type(lines[idx].b(0)), typename VD::coord_type(lines[idx].b(1)))); } private: const Lines &lines; @@ -925,7 +973,7 @@ MedialAxis::build(ThickPolylines* polylines) assert(polyline.width.size() == polyline.points.size()*2 - 2); // prevent loop endpoints from being extended - if (polyline.first_point().coincides_with(polyline.last_point())) { + if (polyline.first_point() == polyline.last_point()) { polyline.endpoints.first = false; polyline.endpoints.second = false; } @@ -1018,7 +1066,7 @@ MedialAxis::validate_edge(const VD::edge_type* edge) // this could maybe be optimized (checking inclusion of the endpoints // might give false positives as they might belong to the contour itself) if (this->expolygon != NULL) { - if (line.a.coincides_with(line.b)) { + if (line.a == line.b) { // in this case, contains(line) returns a false positive if (!this->expolygon->contains(line.a)) return false; } else { @@ -1057,12 +1105,12 @@ MedialAxis::validate_edge(const VD::edge_type* edge) calculate the distance to that endpoint instead. */ coordf_t w0 = cell_r->contains_segment() - ? line.a.distance_to(segment_r)*2 - : line.a.distance_to(this->retrieve_endpoint(cell_r))*2; + ? segment_r.distance_to(line.a)*2 + : (this->retrieve_endpoint(cell_r) - line.a).cast<double>().norm()*2; coordf_t w1 = cell_l->contains_segment() - ? line.b.distance_to(segment_l)*2 - : line.b.distance_to(this->retrieve_endpoint(cell_l))*2; + ? segment_l.distance_to(line.b)*2 + : (this->retrieve_endpoint(cell_l) - line.b).cast<double>().norm()*2; if (cell_l->contains_segment() && cell_r->contains_segment()) { // calculate the relative angle between the two boundary segments diff --git a/xs/src/libslic3r/Geometry.hpp b/xs/src/libslic3r/Geometry.hpp index 956ef82aa..3698b996f 100644 --- a/xs/src/libslic3r/Geometry.hpp +++ b/xs/src/libslic3r/Geometry.hpp @@ -30,9 +30,9 @@ enum Orientation static inline Orientation orient(const Point &a, const Point &b, const Point &c) { // BOOST_STATIC_ASSERT(sizeof(coord_t) * 2 == sizeof(int64_t)); - int64_t u = int64_t(b.x) * int64_t(c.y) - int64_t(b.y) * int64_t(c.x); - int64_t v = int64_t(a.x) * int64_t(c.y) - int64_t(a.y) * int64_t(c.x); - int64_t w = int64_t(a.x) * int64_t(b.y) - int64_t(a.y) * int64_t(b.x); + int64_t u = int64_t(b(0)) * int64_t(c(1)) - int64_t(b(1)) * int64_t(c(0)); + int64_t v = int64_t(a(0)) * int64_t(c(1)) - int64_t(a(1)) * int64_t(c(0)); + int64_t w = int64_t(a(0)) * int64_t(b(1)) - int64_t(a(1)) * int64_t(b(0)); int64_t d = u - v + w; return (d > 0) ? ORIENTATION_CCW : ((d == 0) ? ORIENTATION_COLINEAR : ORIENTATION_CW); } @@ -52,7 +52,7 @@ static inline bool is_ccw(const Polygon &poly) for (unsigned int i = 1; i < poly.points.size(); ++ i) { const Point &pmin = poly.points[imin]; const Point &p = poly.points[i]; - if (p.x < pmin.x || (p.x == pmin.x && p.y < pmin.y)) + if (p(0) < pmin(0) || (p(0) == pmin(0) && p(1) < pmin(1))) imin = i; } @@ -66,26 +66,26 @@ static inline bool is_ccw(const Polygon &poly) return o == ORIENTATION_CCW; } -inline bool ray_ray_intersection(const Pointf &p1, const Vectorf &v1, const Pointf &p2, const Vectorf &v2, Pointf &res) +inline bool ray_ray_intersection(const Vec2d &p1, const Vec2d &v1, const Vec2d &p2, const Vec2d &v2, Vec2d &res) { - double denom = v1.x * v2.y - v2.x * v1.y; + double denom = v1(0) * v2(1) - v2(0) * v1(1); if (std::abs(denom) < EPSILON) return false; - double t = (v2.x * (p1.y - p2.y) - v2.y * (p1.x - p2.x)) / denom; - res.x = p1.x + t * v1.x; - res.y = p1.y + t * v1.y; + double t = (v2(0) * (p1(1) - p2(1)) - v2(1) * (p1(0) - p2(0))) / denom; + res(0) = p1(0) + t * v1(0); + res(1) = p1(1) + t * v1(1); return true; } -inline bool segment_segment_intersection(const Pointf &p1, const Vectorf &v1, const Pointf &p2, const Vectorf &v2, Pointf &res) +inline bool segment_segment_intersection(const Vec2d &p1, const Vec2d &v1, const Vec2d &p2, const Vec2d &v2, Vec2d &res) { - double denom = v1.x * v2.y - v2.x * v1.y; + double denom = v1(0) * v2(1) - v2(0) * v1(1); if (std::abs(denom) < EPSILON) // Lines are collinear. return false; - double s12_x = p1.x - p2.x; - double s12_y = p1.y - p2.y; - double s_numer = v1.x * s12_y - v1.y * s12_x; + double s12_x = p1(0) - p2(0); + double s12_y = p1(1) - p2(1); + double s_numer = v1(0) * s12_y - v1(1) * s12_x; bool denom_is_positive = false; if (denom < 0.) { denom_is_positive = true; @@ -95,7 +95,7 @@ inline bool segment_segment_intersection(const Pointf &p1, const Vectorf &v1, co if (s_numer < 0.) // Intersection outside of the 1st segment. return false; - double t_numer = v2.x * s12_y - v2.y * s12_x; + double t_numer = v2(0) * s12_y - v2(1) * s12_x; if (! denom_is_positive) t_numer = - t_numer; if (t_numer < 0. || s_numer > denom || t_numer > denom) @@ -103,8 +103,8 @@ inline bool segment_segment_intersection(const Pointf &p1, const Vectorf &v1, co return false; // Intersection inside both of the segments. double t = t_numer / denom; - res.x = p1.x + t * v1.x; - res.y = p1.y + t * v1.y; + res(0) = p1(0) + t * v1(0); + res(1) = p1(1) + t * v1(1); return true; } @@ -125,7 +125,7 @@ void simplify_polygons(const Polygons &polygons, double tolerance, Polygons* ret double linint(double value, double oldmin, double oldmax, double newmin, double newmax); bool arrange( // input - size_t num_parts, const Pointf &part_size, coordf_t gap, const BoundingBoxf* bed_bounding_box, + size_t num_parts, const Vec2d &part_size, coordf_t gap, const BoundingBoxf* bed_bounding_box, // output Pointfs &positions); diff --git a/xs/src/libslic3r/Layer.cpp b/xs/src/libslic3r/Layer.cpp index 652bcdaa0..20e8f8ae1 100644 --- a/xs/src/libslic3r/Layer.cpp +++ b/xs/src/libslic3r/Layer.cpp @@ -168,8 +168,8 @@ void Layer::export_region_slices_to_svg(const char *path) const for (Surfaces::const_iterator surface = (*region)->slices.surfaces.begin(); surface != (*region)->slices.surfaces.end(); ++surface) bbox.merge(get_extents(surface->expolygon)); Point legend_size = export_surface_type_legend_to_svg_box_size(); - Point legend_pos(bbox.min.x, bbox.max.y); - bbox.merge(Point(std::max(bbox.min.x + legend_size.x, bbox.max.x), bbox.max.y + legend_size.y)); + Point legend_pos(bbox.min(0), bbox.max(1)); + bbox.merge(Point(std::max(bbox.min(0) + legend_size(0), bbox.max(0)), bbox.max(1) + legend_size(1))); SVG svg(path, bbox); const float transparency = 0.5f; @@ -194,8 +194,8 @@ void Layer::export_region_fill_surfaces_to_svg(const char *path) const for (Surfaces::const_iterator surface = (*region)->fill_surfaces.surfaces.begin(); surface != (*region)->fill_surfaces.surfaces.end(); ++surface) bbox.merge(get_extents(surface->expolygon)); Point legend_size = export_surface_type_legend_to_svg_box_size(); - Point legend_pos(bbox.min.x, bbox.max.y); - bbox.merge(Point(std::max(bbox.min.x + legend_size.x, bbox.max.x), bbox.max.y + legend_size.y)); + Point legend_pos(bbox.min(0), bbox.max(1)); + bbox.merge(Point(std::max(bbox.min(0) + legend_size(0), bbox.max(0)), bbox.max(1) + legend_size(1))); SVG svg(path, bbox); const float transparency = 0.5f; diff --git a/xs/src/libslic3r/LayerRegion.cpp b/xs/src/libslic3r/LayerRegion.cpp index 68e17407e..afdc9c5a2 100644 --- a/xs/src/libslic3r/LayerRegion.cpp +++ b/xs/src/libslic3r/LayerRegion.cpp @@ -395,8 +395,8 @@ void LayerRegion::export_region_slices_to_svg(const char *path) const for (Surfaces::const_iterator surface = this->slices.surfaces.begin(); surface != this->slices.surfaces.end(); ++surface) bbox.merge(get_extents(surface->expolygon)); Point legend_size = export_surface_type_legend_to_svg_box_size(); - Point legend_pos(bbox.min.x, bbox.max.y); - bbox.merge(Point(std::max(bbox.min.x + legend_size.x, bbox.max.x), bbox.max.y + legend_size.y)); + Point legend_pos(bbox.min(0), bbox.max(1)); + bbox.merge(Point(std::max(bbox.min(0) + legend_size(0), bbox.max(0)), bbox.max(1) + legend_size(1))); SVG svg(path, bbox); const float transparency = 0.5f; @@ -422,8 +422,8 @@ void LayerRegion::export_region_fill_surfaces_to_svg(const char *path) const for (Surfaces::const_iterator surface = this->fill_surfaces.surfaces.begin(); surface != this->fill_surfaces.surfaces.end(); ++surface) bbox.merge(get_extents(surface->expolygon)); Point legend_size = export_surface_type_legend_to_svg_box_size(); - Point legend_pos(bbox.min.x, bbox.max.y); - bbox.merge(Point(std::max(bbox.min.x + legend_size.x, bbox.max.x), bbox.max.y + legend_size.y)); + Point legend_pos(bbox.min(0), bbox.max(1)); + bbox.merge(Point(std::max(bbox.min(0) + legend_size(0), bbox.max(0)), bbox.max(1) + legend_size(1))); SVG svg(path, bbox); const float transparency = 0.5f; diff --git a/xs/src/libslic3r/Line.cpp b/xs/src/libslic3r/Line.cpp index e9d5d7742..35cfa2b76 100644 --- a/xs/src/libslic3r/Line.cpp +++ b/xs/src/libslic3r/Line.cpp @@ -7,133 +7,70 @@ namespace Slic3r { -std::string -Line::wkt() const +Linef3 transform(const Linef3& line, const Transform3d& t) { - std::ostringstream ss; - ss << "LINESTRING(" << this->a.x << " " << this->a.y << "," - << this->b.x << " " << this->b.y << ")"; - return ss.str(); -} - -Line::operator Lines() const -{ - Lines lines; - lines.push_back(*this); - return lines; -} - -Line::operator Polyline() const -{ - Polyline pl; - pl.points.push_back(this->a); - pl.points.push_back(this->b); - return pl; -} - -void -Line::scale(double factor) -{ - this->a.scale(factor); - this->b.scale(factor); -} - -void -Line::translate(double x, double y) -{ - this->a.translate(x, y); - this->b.translate(x, y); -} - -void -Line::rotate(double angle, const Point ¢er) -{ - this->a.rotate(angle, center); - this->b.rotate(angle, center); -} - -void -Line::reverse() -{ - std::swap(this->a, this->b); -} + typedef Eigen::Matrix<double, 3, 2> LineInMatrixForm; -double -Line::length() const -{ - return this->a.distance_to(this->b); -} + LineInMatrixForm world_line; + ::memcpy((void*)world_line.col(0).data(), (const void*)line.a.data(), 3 * sizeof(double)); + ::memcpy((void*)world_line.col(1).data(), (const void*)line.b.data(), 3 * sizeof(double)); -Point -Line::midpoint() const -{ - return Point((this->a.x + this->b.x) / 2.0, (this->a.y + this->b.y) / 2.0); + LineInMatrixForm local_line = t * world_line.colwise().homogeneous(); + return Linef3(Vec3d(local_line(0, 0), local_line(1, 0), local_line(2, 0)), Vec3d(local_line(0, 1), local_line(1, 1), local_line(2, 1))); } -void -Line::point_at(double distance, Point* point) const +bool Line::intersection_infinite(const Line &other, Point* point) const { - double len = this->length(); - *point = this->a; - if (this->a.x != this->b.x) - point->x = this->a.x + (this->b.x - this->a.x) * distance / len; - if (this->a.y != this->b.y) - point->y = this->a.y + (this->b.y - this->a.y) * distance / len; -} - -Point -Line::point_at(double distance) const -{ - Point p; - this->point_at(distance, &p); - return p; -} - -bool -Line::intersection_infinite(const Line &other, Point* point) const -{ - Vector x = this->a.vector_to(other.a); - Vector d1 = this->vector(); - Vector d2 = other.vector(); - - double cross = d1.x * d2.y - d1.y * d2.x; - if (std::fabs(cross) < EPSILON) + Vec2d a1 = this->a.cast<double>(); + Vec2d a2 = other.a.cast<double>(); + Vec2d v12 = (other.a - this->a).cast<double>(); + Vec2d v1 = (this->b - this->a).cast<double>(); + Vec2d v2 = (other.b - other.a).cast<double>(); + double denom = cross2(v1, v2); + if (std::fabs(denom) < EPSILON) return false; - - double t1 = (x.x * d2.y - x.y * d2.x)/cross; - point->x = this->a.x + d1.x * t1; - point->y = this->a.y + d1.y * t1; + double t1 = cross2(v12, v2) / denom; + *point = (a1 + t1 * v1).cast<coord_t>(); return true; } -bool -Line::coincides_with(const Line &line) const +/* distance to the closest point of line */ +double Line::distance_to(const Point &point) const { - return this->a.coincides_with(line.a) && this->b.coincides_with(line.b); + const Line &line = *this; + const Vec2d v = (line.b - line.a).cast<double>(); + const Vec2d va = (point - line.a).cast<double>(); + const double l2 = v.squaredNorm(); // avoid a sqrt + if (l2 == 0.0) + // line.a == line.b case + return va.norm(); + // Consider the line extending the segment, parameterized as line.a + t (line.b - line.a). + // We find projection of this point onto the line. + // It falls where t = [(this-line.a) . (line.b-line.a)] / |line.b-line.a|^2 + const double t = va.dot(v) / l2; + if (t < 0.0) return va.norm(); // beyond the 'a' end of the segment + else if (t > 1.0) return (point - line.b).cast<double>().norm(); // beyond the 'b' end of the segment + return (t * v - va).norm(); } -double -Line::distance_to(const Point &point) const +double Line::perp_distance_to(const Point &point) const { - return point.distance_to(*this); + const Line &line = *this; + const Vec2d v = (line.b - line.a).cast<double>(); + const Vec2d va = (point - line.a).cast<double>(); + if (line.a == line.b) + return va.norm(); + return std::abs(cross2(v, va)) / v.norm(); } -double -Line::atan2_() const -{ - return atan2(this->b.y - this->a.y, this->b.x - this->a.x); -} - -double -Line::orientation() const +double Line::orientation() const { double angle = this->atan2_(); if (angle < 0) angle = 2*PI + angle; return angle; } -double -Line::direction() const +double Line::direction() const { double atan2 = this->atan2_(); return (fabs(atan2 - PI) < EPSILON) ? 0 @@ -141,108 +78,42 @@ Line::direction() const : atan2; } -bool -Line::parallel_to(double angle) const { - return Slic3r::Geometry::directions_parallel(this->direction(), angle); -} - -bool -Line::parallel_to(const Line &line) const { - return this->parallel_to(line.direction()); -} - -Vector -Line::vector() const +bool Line::parallel_to(double angle) const { - return Vector(this->b.x - this->a.x, this->b.y - this->a.y); -} - -Vector -Line::normal() const -{ - return Vector((this->b.y - this->a.y), -(this->b.x - this->a.x)); -} - -void -Line::extend_end(double distance) -{ - // relocate last point by extending the segment by the specified length - Line line = *this; - line.reverse(); - this->b = line.point_at(-distance); -} - -void -Line::extend_start(double distance) -{ - // relocate first point by extending the first segment by the specified length - this->a = this->point_at(-distance); + return Slic3r::Geometry::directions_parallel(this->direction(), angle); } -bool -Line::intersection(const Line& line, Point* intersection) const -{ - double denom = ((double)(line.b.y - line.a.y)*(this->b.x - this->a.x)) - - ((double)(line.b.x - line.a.x)*(this->b.y - this->a.y)); - - double nume_a = ((double)(line.b.x - line.a.x)*(this->a.y - line.a.y)) - - ((double)(line.b.y - line.a.y)*(this->a.x - line.a.x)); - - double nume_b = ((double)(this->b.x - this->a.x)*(this->a.y - line.a.y)) - - ((double)(this->b.y - this->a.y)*(this->a.x - line.a.x)); - - if (fabs(denom) < EPSILON) { - if (fabs(nume_a) < EPSILON && fabs(nume_b) < EPSILON) { - return false; // coincident - } - return false; // parallel - } - - double ua = nume_a / denom; - double ub = nume_b / denom; - - if (ua >= 0 && ua <= 1.0f && ub >= 0 && ub <= 1.0f) - { +bool Line::intersection(const Line &l2, Point *intersection) const +{ + const Line &l1 = *this; + const Vec2d v1 = (l1.b - l1.a).cast<double>(); + const Vec2d v2 = (l2.b - l2.a).cast<double>(); + const Vec2d v12 = (l1.a - l2.a).cast<double>(); + double denom = cross2(v1, v2); + double nume_a = cross2(v2, v12); + double nume_b = cross2(v1, v12); + if (fabs(denom) < EPSILON) +#if 0 + // Lines are collinear. Return true if they are coincident (overlappign). + return ! (fabs(nume_a) < EPSILON && fabs(nume_b) < EPSILON); +#else + return false; +#endif + double t1 = nume_a / denom; + double t2 = nume_b / denom; + if (t1 >= 0 && t1 <= 1.0f && t2 >= 0 && t2 <= 1.0f) { // Get the intersection point. - intersection->x = this->a.x + ua*(this->b.x - this->a.x); - intersection->y = this->a.y + ua*(this->b.y - this->a.y); + (*intersection) = (l1.a.cast<double>() + t1 * v1).cast<coord_t>(); return true; } - return false; // not intersecting } -double -Line::ccw(const Point& point) const -{ - return point.ccw(*this); -} - -double Line3::length() const -{ - return a.distance_to(b); -} - -Vector3 Line3::vector() const -{ - return Vector3(b.x - a.x, b.y - a.y, b.z - a.z); -} - -Pointf3 -Linef3::intersect_plane(double z) const -{ - return Pointf3( - this->a.x + (this->b.x - this->a.x) * (z - this->a.z) / (this->b.z - this->a.z), - this->a.y + (this->b.y - this->a.y) * (z - this->a.z) / (this->b.z - this->a.z), - z - ); -} - -void -Linef3::scale(double factor) +Vec3d Linef3::intersect_plane(double z) const { - this->a.scale(factor); - this->b.scale(factor); + auto v = (this->b - this->a).cast<double>(); + double t = (z - this->a(2)) / v(2); + return Vec3d(this->a(0) + v(0) * t, this->a(1) + v(1) * t, z); } } diff --git a/xs/src/libslic3r/Line.hpp b/xs/src/libslic3r/Line.hpp index 4826017ab..36e02247c 100644 --- a/xs/src/libslic3r/Line.hpp +++ b/xs/src/libslic3r/Line.hpp @@ -15,80 +15,85 @@ typedef std::vector<Line> Lines; typedef std::vector<Line3> Lines3; typedef std::vector<ThickLine> ThickLines; +Linef3 transform(const Linef3& line, const Transform3d& t); + class Line { public: - Point a; - Point b; - Line() {}; - explicit Line(Point _a, Point _b): a(_a), b(_b) {}; - std::string wkt() const; - operator Lines() const; - operator Polyline() const; - void scale(double factor); - void translate(double x, double y); - void rotate(double angle, const Point ¢er); - void reverse(); - double length() const; - Point midpoint() const; - void point_at(double distance, Point* point) const; - Point point_at(double distance) const; - bool intersection_infinite(const Line &other, Point* point) const; - bool coincides_with(const Line &line) const; + Line() {} + Line(const Point& _a, const Point& _b) : a(_a), b(_b) {} + explicit operator Lines() const { Lines lines; lines.emplace_back(*this); return lines; } + void scale(double factor) { this->a *= factor; this->b *= factor; } + void translate(double x, double y) { Vector v(x, y); this->a += v; this->b += v; } + void rotate(double angle, const Point ¢er) { this->a.rotate(angle, center); this->b.rotate(angle, center); } + void reverse() { std::swap(this->a, this->b); } + double length() const { return (b - a).cast<double>().norm(); } + Point midpoint() const { return (this->a + this->b) / 2; } + bool intersection_infinite(const Line &other, Point* point) const; + bool operator==(const Line &rhs) const { return this->a == rhs.a && this->b == rhs.b; } double distance_to(const Point &point) const; - bool parallel_to(double angle) const; - bool parallel_to(const Line &line) const; - double atan2_() const; + double perp_distance_to(const Point &point) const; + bool parallel_to(double angle) const; + bool parallel_to(const Line &line) const { return this->parallel_to(line.direction()); } + double atan2_() const { return atan2(this->b(1) - this->a(1), this->b(0) - this->a(0)); } double orientation() const; double direction() const; - Vector vector() const; - Vector normal() const; - void extend_end(double distance); - void extend_start(double distance); - bool intersection(const Line& line, Point* intersection) const; - double ccw(const Point& point) const; + Vector vector() const { return this->b - this->a; } + Vector normal() const { return Vector((this->b(1) - this->a(1)), -(this->b(0) - this->a(0))); } + bool intersection(const Line& line, Point* intersection) const; + double ccw(const Point& point) const { return point.ccw(*this); } + + Point a; + Point b; }; class ThickLine : public Line { - public: - coordf_t a_width, b_width; - - ThickLine() : a_width(0), b_width(0) {}; - ThickLine(Point _a, Point _b) : Line(_a, _b), a_width(0), b_width(0) {}; +public: + ThickLine() : a_width(0), b_width(0) {} + ThickLine(const Point& a, const Point& b) : Line(a, b), a_width(0), b_width(0) {} + ThickLine(const Point& a, const Point& b, double wa, double wb) : Line(a, b), a_width(wa), b_width(wb) {} + + double a_width, b_width; }; class Line3 { public: - Point3 a; - Point3 b; + Line3() : a(Vec3crd::Zero()), b(Vec3crd::Zero()) {} + Line3(const Vec3crd& _a, const Vec3crd& _b) : a(_a), b(_b) {} - Line3() {} - Line3(const Point3& _a, const Point3& _b) : a(_a), b(_b) {} + double length() const { return (this->a - this->b).cast<double>().norm(); } + Vec3crd vector() const { return this->b - this->a; } - double length() const; - Vector3 vector() const; + Vec3crd a; + Vec3crd b; }; class Linef { - public: - Pointf a; - Pointf b; - Linef() {}; - explicit Linef(Pointf _a, Pointf _b): a(_a), b(_b) {}; +public: + Linef() : a(Vec2d::Zero()), b(Vec2d::Zero()) {} + Linef(const Vec2d& _a, const Vec2d& _b) : a(_a), b(_b) {} + + Vec2d a; + Vec2d b; }; class Linef3 { - public: - Pointf3 a; - Pointf3 b; - Linef3() {}; - explicit Linef3(Pointf3 _a, Pointf3 _b): a(_a), b(_b) {}; - Pointf3 intersect_plane(double z) const; - void scale(double factor); +public: + Linef3() : a(Vec3d::Zero()), b(Vec3d::Zero()) {} + Linef3(const Vec3d& _a, const Vec3d& _b) : a(_a), b(_b) {} + + Vec3d intersect_plane(double z) const; + void scale(double factor) { this->a *= factor; this->b *= factor; } + Vec3d vector() const { return this->b - this->a; } + Vec3d unit_vector() const { return (length() == 0.0) ? Vec3d::Zero() : vector().normalized(); } + double length() const { return vector().norm(); } + + Vec3d a; + Vec3d b; }; } // namespace Slic3r diff --git a/xs/src/libslic3r/Model.cpp b/xs/src/libslic3r/Model.cpp index 09b515c2f..19c474cad 100644 --- a/xs/src/libslic3r/Model.cpp +++ b/xs/src/libslic3r/Model.cpp @@ -17,11 +17,6 @@ #include "SVG.hpp" #include <Eigen/Dense> -static const float UNIT_MATRIX[] = { 1.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 1.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 1.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 1.0f }; - namespace Slic3r { unsigned int Model::s_auto_extruder_id = 1; @@ -240,20 +235,17 @@ BoundingBoxf3 Model::bounding_box() const return bb; } -void Model::center_instances_around_point(const Pointf &point) +void Model::center_instances_around_point(const Vec2d &point) { -// BoundingBoxf3 bb = this->bounding_box(); BoundingBoxf3 bb; for (ModelObject *o : this->objects) for (size_t i = 0; i < o->instances.size(); ++ i) bb.merge(o->instance_bounding_box(i, false)); - Sizef3 size = bb.size(); - coordf_t shift_x = -bb.min.x + point.x - size.x/2; - coordf_t shift_y = -bb.min.y + point.y - size.y/2; + Vec2d shift = point - 0.5 * to_2d(bb.size()) - to_2d(bb.min); for (ModelObject *o : this->objects) { for (ModelInstance *i : o->instances) - i->offset.translate(shift_x, shift_y); + i->offset += shift; o->invalidate_bounding_box(); } } @@ -308,8 +300,8 @@ bool Model::arrange_objects(coordf_t dist, const BoundingBoxf* bb) for (size_t i = 0; i < o->instances.size(); ++ i) { // an accurate snug bounding box around the transformed mesh. BoundingBoxf3 bbox(o->instance_bounding_box(i, true)); - instance_sizes.push_back(bbox.size()); - instance_centers.push_back(bbox.center()); + instance_sizes.emplace_back(to_2d(bbox.size())); + instance_centers.emplace_back(to_2d(bbox.center())); } Pointfs positions; @@ -331,7 +323,7 @@ bool Model::arrange_objects(coordf_t dist, const BoundingBoxf* bb) // Duplicate the entire model preserving instance relative positions. void Model::duplicate(size_t copies_num, coordf_t dist, const BoundingBoxf* bb) { - Pointfs model_sizes(copies_num-1, this->bounding_box().size()); + Pointfs model_sizes(copies_num-1, to_2d(this->bounding_box().size())); Pointfs positions; if (! _arrange(model_sizes, dist, bb, positions)) CONFESS("Cannot duplicate part as the resulting objects would not fit on the print bed.\n"); @@ -342,9 +334,9 @@ void Model::duplicate(size_t copies_num, coordf_t dist, const BoundingBoxf* bb) // make a copy of the pointers in order to avoid recursion when appending their copies ModelInstancePtrs instances = o->instances; for (const ModelInstance *i : instances) { - for (const Pointf &pos : positions) { + for (const Vec2d &pos : positions) { ModelInstance *instance = o->add_instance(*i); - instance->offset.translate(pos); + instance->offset += pos; } } o->invalidate_bounding_box(); @@ -374,13 +366,13 @@ void Model::duplicate_objects_grid(size_t x, size_t y, coordf_t dist) ModelObject* object = this->objects.front(); object->clear_instances(); - Sizef3 size = object->bounding_box().size(); + Vec3d size = object->bounding_box().size(); for (size_t x_copy = 1; x_copy <= x; ++x_copy) { for (size_t y_copy = 1; y_copy <= y; ++y_copy) { ModelInstance* instance = object->add_instance(); - instance->offset.x = (size.x + dist) * (x_copy-1); - instance->offset.y = (size.y + dist) * (y_copy-1); + instance->offset(0) = (size(0) + dist) * (x_copy-1); + instance->offset(1) = (size(1) + dist) * (y_copy-1); } } } @@ -394,7 +386,7 @@ bool Model::looks_like_multipart_object() const if (obj->volumes.size() > 1 || obj->config.keys().size() > 1) return false; for (const ModelVolume *vol : obj->volumes) { - double zmin_this = vol->mesh.bounding_box().min.z; + double zmin_this = vol->mesh.bounding_box().min(2); if (zmin == std::numeric_limits<double>::max()) zmin = zmin_this; else if (std::abs(zmin - zmin_this) > EPSILON) @@ -438,13 +430,13 @@ void Model::adjust_min_z() if (objects.empty()) return; - if (bounding_box().min.z < 0.0) + if (bounding_box().min(2) < 0.0) { for (ModelObject* obj : objects) { if (obj != nullptr) { - coordf_t obj_min_z = obj->bounding_box().min.z; + coordf_t obj_min_z = obj->bounding_box().min(2); if (obj_min_z < 0.0) obj->translate(0.0, 0.0, -obj_min_z); } @@ -677,25 +669,19 @@ void ModelObject::center_around_origin() if (! v->modifier) bb.merge(v->mesh.bounding_box()); - // first align to origin on XYZ - Vectorf3 vector(-bb.min.x, -bb.min.y, -bb.min.z); - - // then center it on XY - Sizef3 size = bb.size(); - vector.x -= size.x/2; - vector.y -= size.y/2; - - this->translate(vector); - this->origin_translation.translate(vector); - + // Shift is the vector from the center of the bottom face of the bounding box to the origin + Vec3d shift = -bb.center(); + shift(2) = -bb.min(2); + + this->translate(shift); + this->origin_translation += shift; + if (!this->instances.empty()) { for (ModelInstance *i : this->instances) { // apply rotation and scaling to vector as well before translating instance, // in order to leave final position unaltered - Vectorf3 v = vector.negative(); - v.rotate(i->rotation); - v.scale(i->scaling_factor); - i->offset.translate(v.x, v.y); + Vec3d i_shift = i->world_matrix(true) * shift; + i->offset -= to_2d(i_shift); } this->invalidate_bounding_box(); } @@ -713,7 +699,7 @@ void ModelObject::translate(coordf_t x, coordf_t y, coordf_t z) m_bounding_box.translate(x, y, z); } -void ModelObject::scale(const Pointf3 &versor) +void ModelObject::scale(const Vec3d &versor) { for (ModelVolume *v : this->volumes) { @@ -721,11 +707,11 @@ void ModelObject::scale(const Pointf3 &versor) v->m_convex_hull.scale(versor); } // reset origin translation since it doesn't make sense anymore - this->origin_translation = Pointf3(0,0,0); + this->origin_translation = Vec3d::Zero(); this->invalidate_bounding_box(); } -void ModelObject::rotate(float angle, const Pointf3& axis) +void ModelObject::rotate(float angle, const Axis& axis) { for (ModelVolume *v : this->volumes) { @@ -735,23 +721,22 @@ void ModelObject::rotate(float angle, const Pointf3& axis) center_around_origin(); - this->origin_translation = Pointf3(0, 0, 0); + this->origin_translation = Vec3d::Zero(); this->invalidate_bounding_box(); } -void ModelObject::transform(const float* matrix3x4) +void ModelObject::rotate(float angle, const Vec3d& axis) { - if (matrix3x4 == nullptr) - return; - - for (ModelVolume* v : volumes) + for (ModelVolume *v : this->volumes) { - v->mesh.transform(matrix3x4); - v->m_convex_hull.transform(matrix3x4); + v->mesh.rotate(angle, axis); + v->m_convex_hull.rotate(angle, axis); } - origin_translation = Pointf3(0.0, 0.0, 0.0); - invalidate_bounding_box(); + center_around_origin(); + + this->origin_translation = Vec3d::Zero(); + this->invalidate_bounding_box(); } void ModelObject::mirror(const Axis &axis) @@ -762,7 +747,7 @@ void ModelObject::mirror(const Axis &axis) v->m_convex_hull.mirror(axis); } - this->origin_translation = Pointf3(0, 0, 0); + this->origin_translation = Vec3d::Zero(); this->invalidate_bounding_box(); } @@ -872,14 +857,7 @@ void ModelObject::check_instances_print_volume_state(const BoundingBoxf3& print_ { for (ModelInstance* inst : this->instances) { - std::vector<float> world_mat(UNIT_MATRIX, std::end(UNIT_MATRIX)); - Eigen::Transform<float, 3, Eigen::Affine> m = Eigen::Transform<float, 3, Eigen::Affine>::Identity(); - m.translate(Eigen::Vector3f((float)inst->offset.x, (float)inst->offset.y, 0.0f)); - m.rotate(Eigen::AngleAxisf(inst->rotation, Eigen::Vector3f::UnitZ())); - m.scale(inst->scaling_factor); - ::memcpy((void*)world_mat.data(), (const void*)m.data(), 16 * sizeof(float)); - - BoundingBoxf3 bb = vol->get_convex_hull().transformed_bounding_box(world_mat); + BoundingBoxf3 bb = vol->get_convex_hull().transformed_bounding_box(inst->world_matrix()); if (print_volume.contains(bb)) inst->print_volume_state = ModelInstance::PVS_Inside; @@ -901,16 +879,16 @@ void ModelObject::print_info() const TriangleMesh mesh = this->raw_mesh(); mesh.check_topology(); BoundingBoxf3 bb = mesh.bounding_box(); - Sizef3 size = bb.size(); - cout << "size_x = " << size.x << endl; - cout << "size_y = " << size.y << endl; - cout << "size_z = " << size.z << endl; - cout << "min_x = " << bb.min.x << endl; - cout << "min_y = " << bb.min.y << endl; - cout << "min_z = " << bb.min.z << endl; - cout << "max_x = " << bb.max.x << endl; - cout << "max_y = " << bb.max.y << endl; - cout << "max_z = " << bb.max.z << endl; + Vec3d size = bb.size(); + cout << "size_x = " << size(0) << endl; + cout << "size_y = " << size(1) << endl; + cout << "size_z = " << size(2) << endl; + cout << "min_x = " << bb.min(0) << endl; + cout << "min_y = " << bb.min(1) << endl; + cout << "min_z = " << bb.min(2) << endl; + cout << "max_x = " << bb.max(0) << endl; + cout << "max_y = " << bb.max(1) << endl; + cout << "max_z = " << bb.max(2) << endl; cout << "number_of_facets = " << mesh.stl.stats.number_of_facets << endl; cout << "manifold = " << (mesh.is_manifold() ? "yes" : "no") << endl; @@ -1008,45 +986,26 @@ size_t ModelVolume::split(unsigned int max_extruders) void ModelInstance::transform_mesh(TriangleMesh* mesh, bool dont_translate) const { - mesh->rotate_z(this->rotation); // rotate around mesh origin - mesh->scale(this->scaling_factor); // scale around mesh origin - if (!dont_translate) - mesh->translate(this->offset.x, this->offset.y, 0); + mesh->transform(world_matrix(dont_translate).cast<float>()); } BoundingBoxf3 ModelInstance::transform_mesh_bounding_box(const TriangleMesh* mesh, bool dont_translate) const { // Rotate around mesh origin. - double c = cos(this->rotation); - double s = sin(this->rotation); - BoundingBoxf3 bbox; - for (int i = 0; i < mesh->stl.stats.number_of_facets; ++ i) { - const stl_facet &facet = mesh->stl.facet_start[i]; - for (int j = 0; j < 3; ++ j) { - stl_vertex v = facet.vertex[j]; - double xold = v.x; - double yold = v.y; - v.x = float(c * xold - s * yold); - v.y = float(s * xold + c * yold); - bbox.merge(Pointf3(v.x, v.y, v.z)); - } - } - if (! empty(bbox)) { + TriangleMesh copy(*mesh); + copy.transform(world_matrix(true, false, true).cast<float>()); + BoundingBoxf3 bbox = copy.bounding_box(); + + if (!empty(bbox)) { // Scale the bounding box uniformly. if (std::abs(this->scaling_factor - 1.) > EPSILON) { - bbox.min.x *= float(this->scaling_factor); - bbox.min.y *= float(this->scaling_factor); - bbox.min.z *= float(this->scaling_factor); - bbox.max.x *= float(this->scaling_factor); - bbox.max.y *= float(this->scaling_factor); - bbox.max.z *= float(this->scaling_factor); + bbox.min *= this->scaling_factor; + bbox.max *= this->scaling_factor; } // Translate the bounding box. if (! dont_translate) { - bbox.min.x += float(this->offset.x); - bbox.min.y += float(this->offset.y); - bbox.max.x += float(this->offset.x); - bbox.max.y += float(this->offset.y); + Eigen::Map<Vec2d>(bbox.min.data()) += this->offset; + Eigen::Map<Vec2d>(bbox.max.data()) += this->offset; } } return bbox; @@ -1054,16 +1013,12 @@ BoundingBoxf3 ModelInstance::transform_mesh_bounding_box(const TriangleMesh* mes BoundingBoxf3 ModelInstance::transform_bounding_box(const BoundingBoxf3 &bbox, bool dont_translate) const { - Eigen::Transform<float, 3, Eigen::Affine> matrix = Eigen::Transform<float, 3, Eigen::Affine>::Identity(); - if (!dont_translate) - matrix.translate(Eigen::Vector3f((float)offset.x, (float)offset.y, 0.0f)); - - matrix.rotate(Eigen::AngleAxisf(rotation, Eigen::Vector3f::UnitZ())); - matrix.scale(scaling_factor); + return bbox.transformed(world_matrix(dont_translate)); +} - std::vector<float> m(16, 0.0f); - ::memcpy((void*)m.data(), (const void*)matrix.data(), 16 * sizeof(float)); - return bbox.transformed(m); +Vec3d ModelInstance::transform_vector(const Vec3d& v, bool dont_translate) const +{ + return world_matrix(dont_translate) * v; } void ModelInstance::transform_polygon(Polygon* polygon) const @@ -1072,4 +1027,20 @@ void ModelInstance::transform_polygon(Polygon* polygon) const polygon->scale(this->scaling_factor); // scale around polygon origin } +Transform3d ModelInstance::world_matrix(bool dont_translate, bool dont_rotate, bool dont_scale) const +{ + Transform3d m = Transform3d::Identity(); + + if (!dont_translate) + m.translate(Vec3d(offset(0), offset(1), 0.0)); + + if (!dont_rotate) + m.rotate(Eigen::AngleAxisd(rotation, Vec3d::UnitZ())); + + if (!dont_scale) + m.scale(scaling_factor); + + return m; +} + } diff --git a/xs/src/libslic3r/Model.hpp b/xs/src/libslic3r/Model.hpp index dadd515de..8a8af481c 100644 --- a/xs/src/libslic3r/Model.hpp +++ b/xs/src/libslic3r/Model.hpp @@ -84,7 +84,7 @@ public: center_around_origin() method. Callers might want to apply the same translation to new volumes before adding them to this object in order to preserve alignment when user expects that. */ - Pointf3 origin_translation; + Vec3d origin_translation; Model* get_model() const { return m_model; }; @@ -117,11 +117,11 @@ public: // A snug bounding box around the transformed non-modifier object volumes. BoundingBoxf3 instance_bounding_box(size_t instance_idx, bool dont_translate = false) const; void center_around_origin(); - void translate(const Vectorf3 &vector) { this->translate(vector.x, vector.y, vector.z); } + void translate(const Vec3d &vector) { this->translate(vector(0), vector(1), vector(2)); } void translate(coordf_t x, coordf_t y, coordf_t z); - void scale(const Pointf3 &versor); - void rotate(float angle, const Pointf3& axis); - void transform(const float* matrix3x4); + void scale(const Vec3d &versor); + void rotate(float angle, const Axis &axis); + void rotate(float angle, const Vec3d& axis); void mirror(const Axis &axis); size_t materials_count() const; size_t facets_count() const; @@ -135,7 +135,7 @@ public: void print_info() const; private: - ModelObject(Model *model) : layer_height_profile_valid(false), m_model(model), m_bounding_box_valid(false) {} + ModelObject(Model *model) : layer_height_profile_valid(false), m_model(model), origin_translation(Vec3d::Zero()), m_bounding_box_valid(false) {} ModelObject(Model *model, const ModelObject &other, bool copy_volumes = true); ModelObject& operator= (ModelObject other); void swap(ModelObject &other); @@ -226,7 +226,7 @@ public: double rotation; // Rotation around the Z axis, in radians around mesh center point double scaling_factor; - Pointf offset; // in unscaled coordinates + Vec2d offset; // in unscaled coordinates // flag showing the position of this instance with respect to the print volume (set by Print::validate() using ModelObject::check_instances_print_volume_state()) EPrintVolumeState print_volume_state; @@ -239,16 +239,20 @@ public: BoundingBoxf3 transform_mesh_bounding_box(const TriangleMesh* mesh, bool dont_translate = false) const; // Transform an external bounding box. BoundingBoxf3 transform_bounding_box(const BoundingBoxf3 &bbox, bool dont_translate = false) const; + // Transform an external vector. + Vec3d transform_vector(const Vec3d& v, bool dont_translate = false) const; // To be called on an external polygon. It does not translate the polygon, only rotates and scales. void transform_polygon(Polygon* polygon) const; + Transform3d world_matrix(bool dont_translate = false, bool dont_rotate = false, bool dont_scale = false) const; + bool is_printable() const { return print_volume_state == PVS_Inside; } private: // Parent object, owning this instance. ModelObject* object; - ModelInstance(ModelObject *object) : rotation(0), scaling_factor(1), object(object), print_volume_state(PVS_Inside) {} + ModelInstance(ModelObject *object) : rotation(0), scaling_factor(1), offset(Vec2d::Zero()), object(object), print_volume_state(PVS_Inside) {} ModelInstance(ModelObject *object, const ModelInstance &other) : rotation(other.rotation), scaling_factor(other.scaling_factor), offset(other.offset), object(object), print_volume_state(PVS_Inside) {} }; @@ -299,7 +303,7 @@ public: bool add_default_instances(); // Returns approximate axis aligned bounding box of this model BoundingBoxf3 bounding_box() const; - void center_instances_around_point(const Pointf &point); + void center_instances_around_point(const Vec2d &point); void translate(coordf_t x, coordf_t y, coordf_t z) { for (ModelObject *o : this->objects) o->translate(x, y, z); } TriangleMesh mesh() const; bool arrange_objects(coordf_t dist, const BoundingBoxf* bb = NULL); diff --git a/xs/src/libslic3r/ModelArrange.hpp b/xs/src/libslic3r/ModelArrange.hpp index f2d399ac6..36bd8ed97 100644 --- a/xs/src/libslic3r/ModelArrange.hpp +++ b/xs/src/libslic3r/ModelArrange.hpp @@ -44,11 +44,11 @@ std::string toString(const Model& model, bool holes = true) { ss << "\t\t{\n"; for(auto v : expoly.contour.points) ss << "\t\t\t{" - << v.x << ", " - << v.y << "},\n"; + << v(0) << ", " + << v(1) << "},\n"; { auto v = expoly.contour.points.front(); - ss << "\t\t\t{" << v.x << ", " << v.y << "},\n"; + ss << "\t\t\t{" << v(0) << ", " << v(1) << "},\n"; } ss << "\t\t},\n"; @@ -57,11 +57,11 @@ std::string toString(const Model& model, bool holes = true) { if(holes) for(auto h : expoly.holes) { ss << "\t\t\t{\n"; for(auto v : h.points) ss << "\t\t\t\t{" - << v.x << ", " - << v.y << "},\n"; + << v(0) << ", " + << v(1) << "},\n"; { auto v = h.points.front(); - ss << "\t\t\t\t{" << v.x << ", " << v.y << "},\n"; + ss << "\t\t\t\t{" << v(0) << ", " << v(1) << "},\n"; } ss << "\t\t\t},\n"; } @@ -99,54 +99,55 @@ namespace bgi = boost::geometry::index; using SpatElement = std::pair<Box, unsigned>; using SpatIndex = bgi::rtree< SpatElement, bgi::rstar<16, 4> >; +using ItemGroup = std::vector<std::reference_wrapper<Item>>; +template<class TBin> +using TPacker = typename placers::_NofitPolyPlacer<PolygonImpl, TBin>; + +const double BIG_ITEM_TRESHOLD = 0.02; + +Box boundingBox(const Box& pilebb, const Box& ibb ) { + auto& pminc = pilebb.minCorner(); + auto& pmaxc = pilebb.maxCorner(); + auto& iminc = ibb.minCorner(); + auto& imaxc = ibb.maxCorner(); + PointImpl minc, maxc; + + setX(minc, std::min(getX(pminc), getX(iminc))); + setY(minc, std::min(getY(pminc), getY(iminc))); + + setX(maxc, std::max(getX(pmaxc), getX(imaxc))); + setY(maxc, std::max(getY(pmaxc), getY(imaxc))); + return Box(minc, maxc); +} std::tuple<double /*score*/, Box /*farthest point from bin center*/> objfunc(const PointImpl& bincenter, - double /*bin_area*/, - ShapeLike::Shapes<PolygonImpl>& pile, // The currently arranged pile - double /*pile_area*/, + const shapelike::Shapes<PolygonImpl>& merged_pile, + const Box& pilebb, + const ItemGroup& items, const Item &item, + double bin_area, double norm, // A norming factor for physical dimensions - std::vector<double>& areacache, // pile item areas will be cached // a spatial index to quickly get neighbors of the candidate item - SpatIndex& spatindex + const SpatIndex& spatindex, + const ItemGroup& remaining ) { - using pl = PointLike; - using sl = ShapeLike; + using Coord = TCoord<PointImpl>; - static const double BIG_ITEM_TRESHOLD = 0.2; static const double ROUNDNESS_RATIO = 0.5; static const double DENSITY_RATIO = 1.0 - ROUNDNESS_RATIO; // We will treat big items (compared to the print bed) differently - auto normarea = [norm](double area) { return std::sqrt(area)/norm; }; - - // If a new bin has been created: - if(pile.size() < areacache.size()) { - areacache.clear(); - spatindex.clear(); - } - - // We must fill the caches: - int idx = 0; - for(auto& p : pile) { - if(idx == areacache.size()) { - areacache.emplace_back(sl::area(p)); - if(normarea(areacache[idx]) > BIG_ITEM_TRESHOLD) - spatindex.insert({sl::boundingBox(p), idx}); - } - - idx++; - } + auto isBig = [bin_area](double a) { + return a/bin_area > BIG_ITEM_TRESHOLD ; + }; // Candidate item bounding box - auto ibb = item.boundingBox(); + auto ibb = sl::boundingBox(item.transformedShape()); // Calculate the full bounding box of the pile with the candidate item - pile.emplace_back(item.transformedShape()); - auto fullbb = ShapeLike::boundingBox(pile); - pile.pop_back(); + auto fullbb = boundingBox(pilebb, ibb); // The bounding box of the big items (they will accumulate in the center // of the pile @@ -157,19 +158,11 @@ objfunc(const PointImpl& bincenter, boost::geometry::convert(boostbb, bigbb); } - // The size indicator of the candidate item. This is not the area, - // but almost... - double item_normarea = normarea(item.area()); - // Will hold the resulting score double score = 0; - if(item_normarea > BIG_ITEM_TRESHOLD) { + if(isBig(item.area())) { // This branch is for the bigger items.. - // Here we will use the closest point of the item bounding box to - // the already arranged pile. So not the bb center nor the a choosen - // corner but whichever is the closest to the center. This will - // prevent some unwanted strange arrangements. auto minc = ibb.minCorner(); // bottom left corner auto maxc = ibb.maxCorner(); // top right corner @@ -192,46 +185,62 @@ objfunc(const PointImpl& bincenter, auto dist = *(std::min_element(dists.begin(), dists.end())) / norm; // Density is the pack density: how big is the arranged pile - auto density = std::sqrt(fullbb.width()*fullbb.height()) / norm; - - // Prepare a variable for the alignment score. - // This will indicate: how well is the candidate item aligned with - // its neighbors. We will check the aligment with all neighbors and - // return the score for the best alignment. So it is enough for the - // candidate to be aligned with only one item. - auto alignment_score = std::numeric_limits<double>::max(); - - auto& trsh = item.transformedShape(); - - auto querybb = item.boundingBox(); - - // Query the spatial index for the neigbours - std::vector<SpatElement> result; - spatindex.query(bgi::intersects(querybb), std::back_inserter(result)); - - for(auto& e : result) { // now get the score for the best alignment - auto idx = e.second; - auto& p = pile[idx]; - auto parea = areacache[idx]; - auto bb = sl::boundingBox(sl::Shapes<PolygonImpl>{p, trsh}); - auto bbarea = bb.area(); - auto ascore = 1.0 - (item.area() + parea)/bbarea; + double density = 0; + + if(remaining.empty()) { + + auto mp = merged_pile; + mp.emplace_back(item.transformedShape()); + auto chull = sl::convexHull(mp); + + placers::EdgeCache<PolygonImpl> ec(chull); + + double circ = ec.circumference() / norm; + double bcirc = 2.0*(fullbb.width() + fullbb.height()) / norm; + score = 0.5*circ + 0.5*bcirc; + + } else { + // Prepare a variable for the alignment score. + // This will indicate: how well is the candidate item aligned with + // its neighbors. We will check the alignment with all neighbors and + // return the score for the best alignment. So it is enough for the + // candidate to be aligned with only one item. + auto alignment_score = 1.0; + + density = (fullbb.width()*fullbb.height()) / (norm*norm); + auto querybb = item.boundingBox(); + + // Query the spatial index for the neighbors + std::vector<SpatElement> result; + result.reserve(spatindex.size()); + spatindex.query(bgi::intersects(querybb), + std::back_inserter(result)); + + for(auto& e : result) { // now get the score for the best alignment + auto idx = e.second; + Item& p = items[idx]; + auto parea = p.area(); + if(std::abs(1.0 - parea/item.area()) < 1e-6) { + auto bb = boundingBox(p.boundingBox(), ibb); + auto bbarea = bb.area(); + auto ascore = 1.0 - (item.area() + parea)/bbarea; + + if(ascore < alignment_score) alignment_score = ascore; + } + } - if(ascore < alignment_score) alignment_score = ascore; + // The final mix of the score is the balance between the distance + // from the full pile center, the pack density and the + // alignment with the neighbors + if(result.empty()) + score = 0.5 * dist + 0.5 * density; + else + score = 0.45 * dist + 0.45 * density + 0.1 * alignment_score; } - - // The final mix of the score is the balance between the distance - // from the full pile center, the pack density and the - // alignment with the neigbours - auto C = 0.33; - score = C * dist + C * density + C * alignment_score; - - } else if( item_normarea < BIG_ITEM_TRESHOLD && spatindex.empty()) { - // If there are no big items, only small, we should consider the - // density here as well to not get silly results + } else if( !isBig(item.area()) && spatindex.empty()) { auto bindist = pl::distance(ibb.center(), bincenter) / norm; - auto density = std::sqrt(fullbb.width()*fullbb.height()) / norm; - score = ROUNDNESS_RATIO * bindist + DENSITY_RATIO * density; + // Bindist is surprisingly enough... + score = bindist; } else { // Here there are the small items that should be placed around the // already processed bigger items. @@ -259,7 +268,9 @@ void fillConfig(PConf& pcfg) { // The accuracy of optimization. // Goes from 0.0 to 1.0 and scales performance as well - pcfg.accuracy = 0.6f; + pcfg.accuracy = 0.65f; + + pcfg.parallel = true; } template<class TBin> @@ -268,31 +279,62 @@ class AutoArranger {}; template<class TBin> class _ArrBase { protected: - using Placer = strategies::_NofitPolyPlacer<PolygonImpl, TBin>; + + using Placer = TPacker<TBin>; using Selector = FirstFitSelection; - using Packer = Arranger<Placer, Selector>; + using Packer = Nester<Placer, Selector>; using PConfig = typename Packer::PlacementConfig; using Distance = TCoord<PointImpl>; - using Pile = ShapeLike::Shapes<PolygonImpl>; + using Pile = sl::Shapes<PolygonImpl>; Packer pck_; PConfig pconf_; // Placement configuration double bin_area_; - std::vector<double> areacache_; SpatIndex rtree_; + double norm_; + Pile merged_pile_; + Box pilebb_; + ItemGroup remaining_; + ItemGroup items_; public: _ArrBase(const TBin& bin, Distance dist, std::function<void(unsigned)> progressind): - pck_(bin, dist), bin_area_(ShapeLike::area<PolygonImpl>(bin)) + pck_(bin, dist), bin_area_(sl::area(bin)), + norm_(std::sqrt(sl::area(bin))) { fillConfig(pconf_); + + pconf_.before_packing = + [this](const Pile& merged_pile, // merged pile + const ItemGroup& items, // packed items + const ItemGroup& remaining) // future items to be packed + { + items_ = items; + merged_pile_ = merged_pile; + remaining_ = remaining; + + pilebb_ = sl::boundingBox(merged_pile); + + rtree_.clear(); + + // We will treat big items (compared to the print bed) differently + auto isBig = [this](double a) { + return a/bin_area_ > BIG_ITEM_TRESHOLD ; + }; + + for(unsigned idx = 0; idx < items.size(); ++idx) { + Item& itm = items[idx]; + if(isBig(itm.area())) rtree_.insert({itm.boundingBox(), idx}); + } + }; + pck_.progressIndicator(progressind); } template<class...Args> inline IndexedPackGroup operator()(Args&&...args) { - areacache_.clear(); - return pck_.arrangeIndexed(std::forward<Args>(args)...); + rtree_.clear(); + return pck_.executeIndexed(std::forward<Args>(args)...); } }; @@ -304,22 +346,69 @@ public: std::function<void(unsigned)> progressind): _ArrBase<Box>(bin, dist, progressind) { - pconf_.object_function = [this, bin] ( - Pile& pile, - const Item &item, - double pile_area, - double norm, - double /*penality*/) { - - auto result = objfunc(bin.center(), bin_area_, pile, - pile_area, item, norm, areacache_, rtree_); + + pconf_.object_function = [this, bin] (const Item &item) { + + auto result = objfunc(bin.center(), + merged_pile_, + pilebb_, + items_, + item, + bin_area_, + norm_, + rtree_, + remaining_); + double score = std::get<0>(result); auto& fullbb = std::get<1>(result); - auto wdiff = fullbb.width() - bin.width(); - auto hdiff = fullbb.height() - bin.height(); - if(wdiff > 0) score += std::pow(wdiff, 2) / norm; - if(hdiff > 0) score += std::pow(hdiff, 2) / norm; + double miss = Placer::overfit(fullbb, bin); + miss = miss > 0? miss : 0; + score += miss*miss; + + return score; + }; + + pck_.configure(pconf_); + } +}; + +using lnCircle = libnest2d::_Circle<libnest2d::PointImpl>; + +template<> +class AutoArranger<lnCircle>: public _ArrBase<lnCircle> { +public: + + AutoArranger(const lnCircle& bin, Distance dist, + std::function<void(unsigned)> progressind): + _ArrBase<lnCircle>(bin, dist, progressind) { + + pconf_.object_function = [this, &bin] (const Item &item) { + + auto result = objfunc(bin.center(), + merged_pile_, + pilebb_, + items_, + item, + bin_area_, + norm_, + rtree_, + remaining_); + + double score = std::get<0>(result); + + auto isBig = [this](const Item& itm) { + return itm.area()/bin_area_ > BIG_ITEM_TRESHOLD ; + }; + + if(isBig(item)) { + auto mp = merged_pile_; + mp.push_back(item.transformedShape()); + auto chull = sl::convexHull(mp); + double miss = Placer::overfit(chull, bin); + if(miss < 0) miss = 0; + score += miss*miss; + } return score; }; @@ -335,27 +424,20 @@ public: std::function<void(unsigned)> progressind): _ArrBase<PolygonImpl>(bin, dist, progressind) { - pconf_.object_function = [this, &bin] ( - Pile& pile, - const Item &item, - double pile_area, - double norm, - double /*penality*/) { - - auto binbb = ShapeLike::boundingBox(bin); - auto result = objfunc(binbb.center(), bin_area_, pile, - pile_area, item, norm, areacache_, rtree_); + pconf_.object_function = [this, &bin] (const Item &item) { + + auto binbb = sl::boundingBox(bin); + auto result = objfunc(binbb.center(), + merged_pile_, + pilebb_, + items_, + item, + bin_area_, + norm_, + rtree_, + remaining_); double score = std::get<0>(result); - pile.emplace_back(item.transformedShape()); - auto chull = ShapeLike::convexHull(pile); - pile.pop_back(); - - // If it does not fit into the print bed we will beat it with a - // large penality. If we would not do this, there would be only one - // big pile that doesn't care whether it fits onto the print bed. - if(!Placer::wouldFit(chull, bin)) score += norm; - return score; }; @@ -370,15 +452,17 @@ public: AutoArranger(Distance dist, std::function<void(unsigned)> progressind): _ArrBase<Box>(Box(0, 0), dist, progressind) { - this->pconf_.object_function = [this] ( - Pile& pile, - const Item &item, - double pile_area, - double norm, - double /*penality*/) { - - auto result = objfunc({0, 0}, 0, pile, pile_area, - item, norm, areacache_, rtree_); + this->pconf_.object_function = [this] (const Item &item) { + + auto result = objfunc({0, 0}, + merged_pile_, + pilebb_, + items_, + item, + 0, + norm_, + rtree_, + remaining_); return std::get<0>(result); }; @@ -427,8 +511,8 @@ ShapeData2D projectModelFromTop(const Slic3r::Model &model) { if(item.vertexCount() > 3) { item.rotation(objinst->rotation); item.translation( { - ClipperLib::cInt(objinst->offset.x/SCALING_FACTOR), - ClipperLib::cInt(objinst->offset.y/SCALING_FACTOR) + ClipperLib::cInt(objinst->offset(0)/SCALING_FACTOR), + ClipperLib::cInt(objinst->offset(1)/SCALING_FACTOR) }); ret.emplace_back(objinst, item); } @@ -440,16 +524,113 @@ ShapeData2D projectModelFromTop(const Slic3r::Model &model) { return ret; } -enum BedShapeHint { +class Circle { + Point center_; + double radius_; +public: + + inline Circle(): center_(0, 0), radius_(std::nan("")) {} + inline Circle(const Point& c, double r): center_(c), radius_(r) {} + + inline double radius() const { return radius_; } + inline const Point& center() const { return center_; } + inline operator bool() { return !std::isnan(radius_); } + inline operator lnCircle() { + return lnCircle({center_(0), center_(1)}, radius_); + } +}; + +enum class BedShapeType { BOX, CIRCLE, IRREGULAR, WHO_KNOWS }; -BedShapeHint bedShape(const Slic3r::Polyline& /*bed*/) { +struct BedShapeHint { + BedShapeType type; + /*union*/ struct { // I know but who cares... + Circle circ; + BoundingBox box; + Polyline polygon; + } shape; +}; + +BedShapeHint bedShape(const Polyline& bed) { + BedShapeHint ret; + + auto x = [](const Point& p) { return p(0); }; + auto y = [](const Point& p) { return p(1); }; + + auto width = [x](const BoundingBox& box) { + return x(box.max) - x(box.min); + }; + + auto height = [y](const BoundingBox& box) { + return y(box.max) - y(box.min); + }; + + auto area = [&width, &height](const BoundingBox& box) { + double w = width(box); + double h = height(box); + return w*h; + }; + + auto poly_area = [](Polyline p) { + Polygon pp; pp.points.reserve(p.points.size() + 1); + pp.points = std::move(p.points); + pp.points.emplace_back(pp.points.front()); + return std::abs(pp.area()); + }; + + auto distance_to = [x, y](const Point& p1, const Point& p2) { + double dx = x(p2) - x(p1); + double dy = y(p2) - y(p1); + return std::sqrt(dx*dx + dy*dy); + }; + + auto bb = bed.bounding_box(); + + auto isCircle = [bb, distance_to](const Polyline& polygon) { + auto center = bb.center(); + std::vector<double> vertex_distances; + double avg_dist = 0; + for (auto pt: polygon.points) + { + double distance = distance_to(center, pt); + vertex_distances.push_back(distance); + avg_dist += distance; + } + + avg_dist /= vertex_distances.size(); + + Circle ret(center, avg_dist); + for (auto el: vertex_distances) + { + if (abs(el - avg_dist) > 10 * SCALED_EPSILON) + ret = Circle(); + break; + } + + return ret; + }; + + auto parea = poly_area(bed); + + if( (1.0 - parea/area(bb)) < 1e-3 ) { + ret.type = BedShapeType::BOX; + ret.shape.box = bb; + } + else if(auto c = isCircle(bed)) { + ret.type = BedShapeType::CIRCLE; + ret.shape.circ = c; + } else { + ret.type = BedShapeType::IRREGULAR; + ret.shape.polygon = bed; + } + // Determine the bed shape by hand - return BOX; + return ret; } void applyResult( @@ -468,8 +649,7 @@ void applyResult( // appropriately auto off = item.translation(); Radians rot = item.rotation(); - Pointf foff(off.X*SCALING_FACTOR + batch_offset, - off.Y*SCALING_FACTOR); + Vec2d foff(off.X*SCALING_FACTOR + batch_offset, off.Y*SCALING_FACTOR); // write the tranformation data into the model instance inst_ptr->rotation = rot; @@ -525,19 +705,22 @@ bool arrange(Model &model, coordf_t min_obj_distance, }); IndexedPackGroup result; - BoundingBox bbb(bed.points); + + if(bedhint.type == BedShapeType::WHO_KNOWS) bedhint = bedShape(bed); + + BoundingBox bbb(bed); auto binbb = Box({ - static_cast<libnest2d::Coord>(bbb.min.x), - static_cast<libnest2d::Coord>(bbb.min.y) + static_cast<libnest2d::Coord>(bbb.min(0)), + static_cast<libnest2d::Coord>(bbb.min(1)) }, { - static_cast<libnest2d::Coord>(bbb.max.x), - static_cast<libnest2d::Coord>(bbb.max.y) + static_cast<libnest2d::Coord>(bbb.max(0)), + static_cast<libnest2d::Coord>(bbb.max(1)) }); - switch(bedhint) { - case BOX: { + switch(bedhint.type) { + case BedShapeType::BOX: { // Create the arranger for the box shaped bed AutoArranger<Box> arrange(binbb, min_obj_distance, progressind); @@ -547,16 +730,22 @@ bool arrange(Model &model, coordf_t min_obj_distance, result = arrange(shapes.begin(), shapes.end()); break; } - case CIRCLE: + case BedShapeType::CIRCLE: { + + auto c = bedhint.shape.circ; + auto cc = lnCircle(c); + + AutoArranger<lnCircle> arrange(cc, min_obj_distance, progressind); + result = arrange(shapes.begin(), shapes.end()); break; - case IRREGULAR: - case WHO_KNOWS: { + } + case BedShapeType::IRREGULAR: + case BedShapeType::WHO_KNOWS: { + using P = libnest2d::PolygonImpl; auto ctour = Slic3rMultiPoint_to_ClipperPath(bed); - P irrbed = ShapeLike::create<PolygonImpl>(std::move(ctour)); - -// std::cout << ShapeLike::toString(irrbed) << std::endl; + P irrbed = sl::create<PolygonImpl>(std::move(ctour)); AutoArranger<P> arrange(irrbed, min_obj_distance, progressind); @@ -567,6 +756,8 @@ bool arrange(Model &model, coordf_t min_obj_distance, } }; + if(result.empty()) return false; + if(first_bin_only) { applyResult(result.front(), 0, shapemap); } else { diff --git a/xs/src/libslic3r/MotionPlanner.cpp b/xs/src/libslic3r/MotionPlanner.cpp index e8605d68c..ff3475ed8 100644 --- a/xs/src/libslic3r/MotionPlanner.cpp +++ b/xs/src/libslic3r/MotionPlanner.cpp @@ -58,7 +58,7 @@ Polyline MotionPlanner::shortest_path(const Point &from, const Point &to) { // If we have an empty configuration space, return a straight move. if (m_islands.empty()) - return Line(from, to); + return Polyline(from, to); // Are both points in the same island? int island_idx_from = -1; @@ -74,7 +74,7 @@ Polyline MotionPlanner::shortest_path(const Point &from, const Point &to) // Since both points are in the same island, is a direct move possible? // If so, we avoid generating the visibility environment. if (island.m_island.contains(Line(from, to))) - return Line(from, to); + return Polyline(from, to); // Both points are inside a single island, but the straight line crosses the island boundary. island_idx = idx; break; @@ -90,7 +90,7 @@ Polyline MotionPlanner::shortest_path(const Point &from, const Point &to) if (env.m_env.expolygons.empty()) { // if this environment is empty (probably because it's too small), perform straight move // and avoid running the algorithms on empty dataset - return Line(from, to); + return Polyline(from, to); } // Now check whether points are inside the environment. @@ -224,7 +224,7 @@ const MotionPlannerGraph& MotionPlanner::init_graph(int island_idx) else v1_idx = i_v1->second; // Euclidean distance is used as weight for the graph edge - graph->add_edge(v0_idx, v1_idx, p0.distance_to(p1)); + graph->add_edge(v0_idx, v1_idx, (p1 - p0).cast<double>().norm()); } } } @@ -238,7 +238,7 @@ static inline size_t nearest_waypoint_index(const Point &start_point, const Poin size_t idx = size_t(-1); double dmin = std::numeric_limits<double>::infinity(); for (const Point &p : middle_points) { - double d = start_point.distance_to(p) + p.distance_to(end_point); + double d = (p - start_point).cast<double>().norm() + (end_point - p).cast<double>().norm(); if (d < dmin) { idx = &p - middle_points.data(); dmin = d; diff --git a/xs/src/libslic3r/MultiPoint.cpp b/xs/src/libslic3r/MultiPoint.cpp index 2e65492cd..f44897a04 100644 --- a/xs/src/libslic3r/MultiPoint.cpp +++ b/xs/src/libslic3r/MultiPoint.cpp @@ -8,59 +8,52 @@ MultiPoint::operator Points() const return this->points; } -void -MultiPoint::scale(double factor) +void MultiPoint::scale(double factor) { - for (Points::iterator it = points.begin(); it != points.end(); ++it) { - (*it).scale(factor); - } + for (Point &pt : points) + pt *= factor; } -void -MultiPoint::translate(double x, double y) +void MultiPoint::translate(double x, double y) { - for (Points::iterator it = points.begin(); it != points.end(); ++it) { - (*it).translate(x, y); - } + Vector v(x, y); + for (Point &pt : points) + pt += v; } -void -MultiPoint::translate(const Point &vector) +void MultiPoint::translate(const Point &v) { - this->translate(vector.x, vector.y); + for (Point &pt : points) + pt += v; } void MultiPoint::rotate(double cos_angle, double sin_angle) { for (Point &pt : this->points) { - double cur_x = double(pt.x); - double cur_y = double(pt.y); - pt.x = coord_t(round(cos_angle * cur_x - sin_angle * cur_y)); - pt.y = coord_t(round(cos_angle * cur_y + sin_angle * cur_x)); + double cur_x = double(pt(0)); + double cur_y = double(pt(1)); + pt(0) = coord_t(round(cos_angle * cur_x - sin_angle * cur_y)); + pt(1) = coord_t(round(cos_angle * cur_y + sin_angle * cur_x)); } } -void -MultiPoint::rotate(double angle, const Point ¢er) +void MultiPoint::rotate(double angle, const Point ¢er) { double s = sin(angle); double c = cos(angle); - for (Points::iterator it = points.begin(); it != points.end(); ++it) { - double dx = double(it->x - center.x); - double dy = double(it->y - center.y); - it->x = (coord_t)round(double(center.x) + c * dx - s * dy); - it->y = (coord_t)round(double(center.y) + c * dy + s * dx); + for (Point &pt : points) { + Vec2crd v(pt - center); + pt(0) = (coord_t)round(double(center(0)) + c * v[0] - s * v[1]); + pt(1) = (coord_t)round(double(center(1)) + c * v[1] + s * v[0]); } } -void -MultiPoint::reverse() +void MultiPoint::reverse() { std::reverse(this->points.begin(), this->points.end()); } -Point -MultiPoint::first_point() const +Point MultiPoint::first_point() const { return this->points.front(); } @@ -79,16 +72,16 @@ MultiPoint::length() const int MultiPoint::find_point(const Point &point) const { - for (Points::const_iterator it = this->points.begin(); it != this->points.end(); ++it) { - if (it->coincides_with(point)) return it - this->points.begin(); - } + for (const Point &pt : this->points) + if (pt == point) + return &pt - &this->points.front(); return -1; // not found } bool MultiPoint::has_boundary_point(const Point &point) const { - double dist = point.distance_to(point.projection_onto(*this)); + double dist = (point.projection_onto(*this) - point).cast<double>().norm(); return dist < SCALED_EPSILON; } @@ -102,7 +95,7 @@ bool MultiPoint::has_duplicate_points() const { for (size_t i = 1; i < points.size(); ++i) - if (points[i-1].coincides_with(points[i])) + if (points[i-1] == points[i]) return true; return false; } @@ -112,7 +105,7 @@ MultiPoint::remove_duplicate_points() { size_t j = 0; for (size_t i = 1; i < points.size(); ++i) { - if (points[j].coincides_with(points[i])) { + if (points[j] == points[i]) { // Just increase index i. } else { ++ j; @@ -146,10 +139,10 @@ bool MultiPoint::first_intersection(const Line& line, Point* intersection) const if (l.intersection(line, &ip)) { if (! found) { found = true; - dmin = ip.distance_to(line.a); + dmin = (line.a - ip).cast<double>().norm(); *intersection = ip; } else { - double d = ip.distance_to(line.a); + double d = (line.a - ip).cast<double>().norm(); if (d < dmin) { dmin = d; *intersection = ip; @@ -160,19 +153,6 @@ bool MultiPoint::first_intersection(const Line& line, Point* intersection) const return found; } -std::string -MultiPoint::dump_perl() const -{ - std::ostringstream ret; - ret << "["; - for (Points::const_iterator p = this->points.begin(); p != this->points.end(); ++p) { - ret << p->dump_perl(); - if (p != this->points.end()-1) ret << ","; - } - ret << "]"; - return ret.str(); -} - //FIXME This is very inefficient in term of memory use. // The recursive algorithm shall run in place, not allocating temporary data in each recursion. Points @@ -185,7 +165,7 @@ MultiPoint::_douglas_peucker(const Points &points, const double tolerance) Line full(points.front(), points.back()); for (Points::const_iterator it = points.begin() + 1; it != points.end(); ++it) { // we use shortest distance, not perpendicular distance - double d = it->distance_to(full); + double d = full.distance_to(*it); if (d > dmax) { index = it - points.begin(); dmax = d; @@ -216,25 +196,22 @@ MultiPoint::_douglas_peucker(const Points &points, const double tolerance) void MultiPoint3::translate(double x, double y) { - for (Point3& p : points) - { - p.translate(x, y); + for (Vec3crd &p : points) { + p(0) += x; + p(1) += y; } } void MultiPoint3::translate(const Point& vector) { - translate(vector.x, vector.y); + this->translate(vector(0), vector(1)); } double MultiPoint3::length() const { - Lines3 lines = this->lines(); double len = 0.0; - for (const Line3& line : lines) - { + for (const Line3& line : this->lines()) len += line.length(); - } return len; } @@ -246,15 +223,11 @@ BoundingBox3 MultiPoint3::bounding_box() const bool MultiPoint3::remove_duplicate_points() { size_t j = 0; - for (size_t i = 1; i < points.size(); ++i) - { - if (points[j].coincides_with(points[i])) - { + for (size_t i = 1; i < points.size(); ++i) { + if (points[j] == points[i]) { // Just increase index i. - } - else - { - ++j; + } else { + ++ j; if (j < i) points[j] = points[i]; } @@ -281,19 +254,19 @@ BoundingBox get_extents_rotated(const Points &points, double angle) double s = sin(angle); double c = cos(angle); Points::const_iterator it = points.begin(); - double cur_x = (double)it->x; - double cur_y = (double)it->y; - bbox.min.x = bbox.max.x = (coord_t)round(c * cur_x - s * cur_y); - bbox.min.y = bbox.max.y = (coord_t)round(c * cur_y + s * cur_x); + double cur_x = (double)(*it)(0); + double cur_y = (double)(*it)(1); + bbox.min(0) = bbox.max(0) = (coord_t)round(c * cur_x - s * cur_y); + bbox.min(1) = bbox.max(1) = (coord_t)round(c * cur_y + s * cur_x); for (++it; it != points.end(); ++it) { - double cur_x = (double)it->x; - double cur_y = (double)it->y; + double cur_x = (double)(*it)(0); + double cur_y = (double)(*it)(1); coord_t x = (coord_t)round(c * cur_x - s * cur_y); coord_t y = (coord_t)round(c * cur_y + s * cur_x); - bbox.min.x = std::min(x, bbox.min.x); - bbox.min.y = std::min(y, bbox.min.y); - bbox.max.x = std::max(x, bbox.max.x); - bbox.max.y = std::max(y, bbox.max.y); + bbox.min(0) = std::min(x, bbox.min(0)); + bbox.min(1) = std::min(y, bbox.min(1)); + bbox.max(0) = std::max(x, bbox.max(0)); + bbox.max(1) = std::max(y, bbox.max(1)); } bbox.defined = true; } diff --git a/xs/src/libslic3r/MultiPoint.hpp b/xs/src/libslic3r/MultiPoint.hpp index 0970e9a67..1fef4083b 100644 --- a/xs/src/libslic3r/MultiPoint.hpp +++ b/xs/src/libslic3r/MultiPoint.hpp @@ -18,10 +18,11 @@ public: Points points; operator Points() const; - MultiPoint() {}; + MultiPoint() {} MultiPoint(const MultiPoint &other) : points(other.points) {} MultiPoint(MultiPoint &&other) : points(std::move(other.points)) {} - explicit MultiPoint(const Points &_points): points(_points) {} + MultiPoint(std::initializer_list<Point> list) : points(list) {} + explicit MultiPoint(const Points &_points) : points(_points) {} MultiPoint& operator=(const MultiPoint &other) { points = other.points; return *this; } MultiPoint& operator=(MultiPoint &&other) { points = std::move(other.points); return *this; } void scale(double factor); @@ -43,9 +44,9 @@ public: int idx = -1; if (! this->points.empty()) { idx = 0; - double dist_min = this->points.front().distance_to(point); + double dist_min = (point - this->points.front()).cast<double>().norm(); for (int i = 1; i < int(this->points.size()); ++ i) { - double d = this->points[i].distance_to(point); + double d = (this->points[i] - point).cast<double>().norm(); if (d < dist_min) { dist_min = d; idx = i; @@ -75,7 +76,6 @@ public: bool intersection(const Line& line, Point* intersection) const; bool first_intersection(const Line& line, Point* intersection) const; - std::string dump_perl() const; static Points _douglas_peucker(const Points &points, const double tolerance); }; @@ -85,7 +85,7 @@ class MultiPoint3 public: Points3 points; - void append(const Point3& point) { this->points.push_back(point); } + void append(const Vec3crd& point) { this->points.push_back(point); } void translate(double x, double y); void translate(const Point& vector); diff --git a/xs/src/libslic3r/PerimeterGenerator.cpp b/xs/src/libslic3r/PerimeterGenerator.cpp index 1d2e6248f..de8aeeb2a 100644 --- a/xs/src/libslic3r/PerimeterGenerator.cpp +++ b/xs/src/libslic3r/PerimeterGenerator.cpp @@ -243,7 +243,7 @@ void PerimeterGenerator::process() perimeter_spacing / 2; // only apply infill overlap if we actually have one perimeter if (inset > 0) - inset -= scale_(this->config->get_abs_value("infill_overlap", unscale(inset + solid_infill_spacing / 2))); + inset -= scale_(this->config->get_abs_value("infill_overlap", unscale<double>(inset + solid_infill_spacing / 2))); // simplify infill contours according to resolution Polygons pp; for (ExPolygon &ex : last) @@ -366,99 +366,103 @@ ExtrusionEntityCollection PerimeterGenerator::_traverse_loops( return entities; } -ExtrusionEntityCollection PerimeterGenerator::_variable_width(const ThickPolylines &polylines, ExtrusionRole role, Flow flow) const +static inline ExtrusionPaths thick_polyline_to_extrusion_paths(const ThickPolyline &thick_polyline, ExtrusionRole role, Flow &flow, const float tolerance) { - // this value determines granularity of adaptive width, as G-code does not allow - // variable extrusion within a single move; this value shall only affect the amount - // of segments, and any pruning shall be performed before we apply this tolerance - const double tolerance = scale_(0.05); + ExtrusionPaths paths; + ExtrusionPath path(role); + ThickLines lines = thick_polyline.thicklines(); - ExtrusionEntityCollection coll; - for (const ThickPolyline &p : polylines) { - ExtrusionPaths paths; - ExtrusionPath path(role); - ThickLines lines = p.thicklines(); + for (int i = 0; i < (int)lines.size(); ++i) { + const ThickLine& line = lines[i]; - for (int i = 0; i < (int)lines.size(); ++i) { - const ThickLine& line = lines[i]; - - const coordf_t line_len = line.length(); - if (line_len < SCALED_EPSILON) continue; - - double thickness_delta = fabs(line.a_width - line.b_width); - if (thickness_delta > tolerance) { - const unsigned short segments = ceil(thickness_delta / tolerance); - const coordf_t seg_len = line_len / segments; - Points pp; - std::vector<coordf_t> width; - { - pp.push_back(line.a); - width.push_back(line.a_width); - for (size_t j = 1; j < segments; ++j) { - pp.push_back(line.point_at(j*seg_len)); - - coordf_t w = line.a_width + (j*seg_len) * (line.b_width-line.a_width) / line_len; - width.push_back(w); - width.push_back(w); - } - pp.push_back(line.b); - width.push_back(line.b_width); + const coordf_t line_len = line.length(); + if (line_len < SCALED_EPSILON) continue; + + double thickness_delta = fabs(line.a_width - line.b_width); + if (thickness_delta > tolerance) { + const unsigned short segments = ceil(thickness_delta / tolerance); + const coordf_t seg_len = line_len / segments; + Points pp; + std::vector<coordf_t> width; + { + pp.push_back(line.a); + width.push_back(line.a_width); + for (size_t j = 1; j < segments; ++j) { + pp.push_back((line.a.cast<double>() + (line.b - line.a).cast<double>().normalized() * (j * seg_len)).cast<coord_t>()); - assert(pp.size() == segments + 1); - assert(width.size() == segments*2); - } - - // delete this line and insert new ones - lines.erase(lines.begin() + i); - for (size_t j = 0; j < segments; ++j) { - ThickLine new_line(pp[j], pp[j+1]); - new_line.a_width = width[2*j]; - new_line.b_width = width[2*j+1]; - lines.insert(lines.begin() + i + j, new_line); + coordf_t w = line.a_width + (j*seg_len) * (line.b_width-line.a_width) / line_len; + width.push_back(w); + width.push_back(w); } + pp.push_back(line.b); + width.push_back(line.b_width); - -- i; - continue; + assert(pp.size() == segments + 1); + assert(width.size() == segments*2); + } + + // delete this line and insert new ones + lines.erase(lines.begin() + i); + for (size_t j = 0; j < segments; ++j) { + ThickLine new_line(pp[j], pp[j+1]); + new_line.a_width = width[2*j]; + new_line.b_width = width[2*j+1]; + lines.insert(lines.begin() + i + j, new_line); } - const double w = fmax(line.a_width, line.b_width); - if (path.polyline.points.empty()) { - path.polyline.append(line.a); + -- i; + continue; + } + + const double w = fmax(line.a_width, line.b_width); + if (path.polyline.points.empty()) { + path.polyline.append(line.a); + path.polyline.append(line.b); + // Convert from spacing to extrusion width based on the extrusion model + // of a square extrusion ended with semi circles. + flow.width = unscale<float>(w) + flow.height * (1. - 0.25 * PI); + #ifdef SLIC3R_DEBUG + printf(" filling %f gap\n", flow.width); + #endif + path.mm3_per_mm = flow.mm3_per_mm(); + path.width = flow.width; + path.height = flow.height; + } else { + thickness_delta = fabs(scale_(flow.width) - w); + if (thickness_delta <= tolerance) { + // the width difference between this line and the current flow width is + // within the accepted tolerance path.polyline.append(line.b); - // Convert from spacing to extrusion width based on the extrusion model - // of a square extrusion ended with semi circles. - flow.width = unscale(w) + flow.height * (1. - 0.25 * PI); - #ifdef SLIC3R_DEBUG - printf(" filling %f gap\n", flow.width); - #endif - path.mm3_per_mm = flow.mm3_per_mm(); - path.width = flow.width; - path.height = flow.height; } else { - thickness_delta = fabs(scale_(flow.width) - w); - if (thickness_delta <= tolerance) { - // the width difference between this line and the current flow width is - // within the accepted tolerance - path.polyline.append(line.b); - } else { - // we need to initialize a new line - paths.emplace_back(std::move(path)); - path = ExtrusionPath(role); - -- i; - } + // we need to initialize a new line + paths.emplace_back(std::move(path)); + path = ExtrusionPath(role); + -- i; } } - if (path.polyline.is_valid()) - paths.emplace_back(std::move(path)); + } + if (path.polyline.is_valid()) + paths.emplace_back(std::move(path)); + return paths; +} + +ExtrusionEntityCollection PerimeterGenerator::_variable_width(const ThickPolylines &polylines, ExtrusionRole role, Flow flow) const +{ + // This value determines granularity of adaptive width, as G-code does not allow + // variable extrusion within a single move; this value shall only affect the amount + // of segments, and any pruning shall be performed before we apply this tolerance. + ExtrusionEntityCollection coll; + const double tolerance = scale_(0.05); + for (const ThickPolyline &p : polylines) { + ExtrusionPaths paths = thick_polyline_to_extrusion_paths(p, role, flow, tolerance); // Append paths to collection. if (! paths.empty()) { - if (paths.front().first_point().coincides_with(paths.back().last_point())) - coll.append(ExtrusionLoop(paths)); + if (paths.front().first_point() == paths.back().last_point()) + coll.append(ExtrusionLoop(std::move(paths))); else - coll.append(paths); + coll.append(std::move(paths)); } } - return coll; } diff --git a/xs/src/libslic3r/PlaceholderParser.cpp b/xs/src/libslic3r/PlaceholderParser.cpp index 80740b20d..1cfd51141 100644 --- a/xs/src/libslic3r/PlaceholderParser.cpp +++ b/xs/src/libslic3r/PlaceholderParser.cpp @@ -693,7 +693,7 @@ namespace client case coInts: output.set_i(static_cast<const ConfigOptionInts *>(opt.opt)->values[idx]); break; case coStrings: output.set_s(static_cast<const ConfigOptionStrings *>(opt.opt)->values[idx]); break; case coPercents: output.set_d(static_cast<const ConfigOptionPercents*>(opt.opt)->values[idx]); break; - case coPoints: output.set_s(static_cast<const ConfigOptionPoints *>(opt.opt)->values[idx].dump_perl()); break; + case coPoints: output.set_s(to_string(static_cast<const ConfigOptionPoints *>(opt.opt)->values[idx])); break; case coBools: output.set_b(static_cast<const ConfigOptionBools *>(opt.opt)->values[idx] != 0); break; default: ctx->throw_exception("Unknown vector variable type", opt.it_range); diff --git a/xs/src/libslic3r/Point.cpp b/xs/src/libslic3r/Point.cpp index 349b00bb6..c2417d0dc 100644 --- a/xs/src/libslic3r/Point.cpp +++ b/xs/src/libslic3r/Point.cpp @@ -3,84 +3,70 @@ #include "MultiPoint.hpp" #include "Int128.hpp" #include <algorithm> -#include <cmath> namespace Slic3r { -Point::Point(double x, double y) +std::vector<Vec3f> transform(const std::vector<Vec3f>& points, const Transform3f& t) { - this->x = lrint(x); - this->y = lrint(y); -} + unsigned int vertices_count = (unsigned int)points.size(); + if (vertices_count == 0) + return std::vector<Vec3f>(); -std::string -Point::wkt() const -{ - std::ostringstream ss; - ss << "POINT(" << this->x << " " << this->y << ")"; - return ss.str(); -} + unsigned int data_size = 3 * vertices_count * sizeof(float); -std::string -Point::dump_perl() const -{ - std::ostringstream ss; - ss << "[" << this->x << "," << this->y << "]"; - return ss.str(); -} + Eigen::MatrixXf src(3, vertices_count); + ::memcpy((void*)src.data(), (const void*)points.data(), data_size); -void -Point::scale(double factor) -{ - this->x *= factor; - this->y *= factor; -} + Eigen::MatrixXf dst(3, vertices_count); + dst = t * src.colwise().homogeneous(); -void -Point::translate(double x, double y) -{ - this->x += x; - this->y += y; + std::vector<Vec3f> ret_points(vertices_count, Vec3f::Zero()); + ::memcpy((void*)ret_points.data(), (const void*)dst.data(), data_size); + return ret_points; } -void -Point::translate(const Vector &vector) +Pointf3s transform(const Pointf3s& points, const Transform3d& t) { - this->translate(vector.x, vector.y); -} + unsigned int vertices_count = (unsigned int)points.size(); + if (vertices_count == 0) + return Pointf3s(); -void -Point::rotate(double angle) -{ - double cur_x = (double)this->x; - double cur_y = (double)this->y; - double s = sin(angle); - double c = cos(angle); - this->x = (coord_t)round(c * cur_x - s * cur_y); - this->y = (coord_t)round(c * cur_y + s * cur_x); + unsigned int data_size = 3 * vertices_count * sizeof(double); + + Eigen::MatrixXd src(3, vertices_count); + ::memcpy((void*)src.data(), (const void*)points.data(), data_size); + + Eigen::MatrixXd dst(3, vertices_count); + dst = t * src.colwise().homogeneous(); + + Pointf3s ret_points(vertices_count, Vec3d::Zero()); + ::memcpy((void*)ret_points.data(), (const void*)dst.data(), data_size); + return ret_points; } -void -Point::rotate(double angle, const Point ¢er) +void Point::rotate(double angle) { - double cur_x = (double)this->x; - double cur_y = (double)this->y; - double s = sin(angle); - double c = cos(angle); - double dx = cur_x - (double)center.x; - double dy = cur_y - (double)center.y; - this->x = (coord_t)round( (double)center.x + c * dx - s * dy ); - this->y = (coord_t)round( (double)center.y + c * dy + s * dx ); + double cur_x = (double)(*this)(0); + double cur_y = (double)(*this)(1); + double s = ::sin(angle); + double c = ::cos(angle); + (*this)(0) = (coord_t)round(c * cur_x - s * cur_y); + (*this)(1) = (coord_t)round(c * cur_y + s * cur_x); } -bool -Point::coincides_with_epsilon(const Point &point) const +void Point::rotate(double angle, const Point ¢er) { - return std::abs(this->x - point.x) < SCALED_EPSILON && std::abs(this->y - point.y) < SCALED_EPSILON; + double cur_x = (double)(*this)(0); + double cur_y = (double)(*this)(1); + double s = ::sin(angle); + double c = ::cos(angle); + double dx = cur_x - (double)center(0); + double dy = cur_y - (double)center(1); + (*this)(0) = (coord_t)round( (double)center(0) + c * dx - s * dy ); + (*this)(1) = (coord_t)round( (double)center(1) + c * dy + s * dx ); } -int -Point::nearest_point_index(const Points &points) const +int Point::nearest_point_index(const Points &points) const { PointConstPtrs p; p.reserve(points.size()); @@ -97,12 +83,12 @@ int Point::nearest_point_index(const PointConstPtrs &points) const for (PointConstPtrs::const_iterator it = points.begin(); it != points.end(); ++it) { /* If the X distance of the candidate is > than the total distance of the best previous candidate, we know we don't want it */ - double d = sqr<double>(this->x - (*it)->x); + double d = sqr<double>((*this)(0) - (*it)->x()); if (distance != -1 && d > distance) continue; /* If the Y distance of the candidate is > than the total distance of the best previous candidate, we know we don't want it */ - d += sqr<double>(this->y - (*it)->y); + d += sqr<double>((*this)(1) - (*it)->y()); if (distance != -1 && d > distance) continue; idx = it - points.begin(); @@ -114,8 +100,7 @@ int Point::nearest_point_index(const PointConstPtrs &points) const return idx; } -int -Point::nearest_point_index(const PointPtrs &points) const +int Point::nearest_point_index(const PointPtrs &points) const { PointConstPtrs p; p.reserve(points.size()); @@ -124,8 +109,7 @@ Point::nearest_point_index(const PointPtrs &points) const return this->nearest_point_index(p); } -bool -Point::nearest_point(const Points &points, Point* point) const +bool Point::nearest_point(const Points &points, Point* point) const { int idx = this->nearest_point_index(points); if (idx == -1) return false; @@ -133,40 +117,6 @@ Point::nearest_point(const Points &points, Point* point) const return true; } -/* distance to the closest point of line */ -double -Point::distance_to(const Line &line) const -{ - const double dx = line.b.x - line.a.x; - const double dy = line.b.y - line.a.y; - - const double l2 = dx*dx + dy*dy; // avoid a sqrt - if (l2 == 0.0) return this->distance_to(line.a); // line.a == line.b case - - // Consider the line extending the segment, parameterized as line.a + t (line.b - line.a). - // We find projection of this point onto the line. - // It falls where t = [(this-line.a) . (line.b-line.a)] / |line.b-line.a|^2 - const double t = ((this->x - line.a.x) * dx + (this->y - line.a.y) * dy) / l2; - if (t < 0.0) return this->distance_to(line.a); // beyond the 'a' end of the segment - else if (t > 1.0) return this->distance_to(line.b); // beyond the 'b' end of the segment - Point projection( - line.a.x + t * dx, - line.a.y + t * dy - ); - return this->distance_to(projection); -} - -double -Point::perp_distance_to(const Line &line) const -{ - if (line.a.coincides_with(line.b)) return this->distance_to(line.a); - - double n = (double)(line.b.x - line.a.x) * (double)(line.a.y - this->y) - - (double)(line.a.x - this->x) * (double)(line.b.y - line.a.y); - - return std::abs(n) / line.length(); -} - /* Three points are a counter-clockwise turn if ccw > 0, clockwise if * ccw < 0, and collinear if ccw = 0 because ccw is a determinant that * gives the signed area of the triangle formed by p1, p2 and this point. @@ -174,51 +124,46 @@ Point::perp_distance_to(const Line &line) const * z-component of their 3D cross product. * We return double because it must be big enough to hold 2*max(|coordinate|)^2 */ -double -Point::ccw(const Point &p1, const Point &p2) const +double Point::ccw(const Point &p1, const Point &p2) const { - return (double)(p2.x - p1.x)*(double)(this->y - p1.y) - (double)(p2.y - p1.y)*(double)(this->x - p1.x); + return (double)(p2(0) - p1(0))*(double)((*this)(1) - p1(1)) - (double)(p2(1) - p1(1))*(double)((*this)(0) - p1(0)); } -double -Point::ccw(const Line &line) const +double Point::ccw(const Line &line) const { return this->ccw(line.a, line.b); } // returns the CCW angle between this-p1 and this-p2 // i.e. this assumes a CCW rotation from p1 to p2 around this -double -Point::ccw_angle(const Point &p1, const Point &p2) const +double Point::ccw_angle(const Point &p1, const Point &p2) const { - double angle = atan2(p1.x - this->x, p1.y - this->y) - - atan2(p2.x - this->x, p2.y - this->y); + double angle = atan2(p1(0) - (*this)(0), p1(1) - (*this)(1)) + - atan2(p2(0) - (*this)(0), p2(1) - (*this)(1)); // we only want to return only positive angles return angle <= 0 ? angle + 2*PI : angle; } -Point -Point::projection_onto(const MultiPoint &poly) const +Point Point::projection_onto(const MultiPoint &poly) const { Point running_projection = poly.first_point(); - double running_min = this->distance_to(running_projection); + double running_min = (running_projection - *this).cast<double>().norm(); Lines lines = poly.lines(); for (Lines::const_iterator line = lines.begin(); line != lines.end(); ++line) { Point point_temp = this->projection_onto(*line); - if (this->distance_to(point_temp) < running_min) { + if ((point_temp - *this).cast<double>().norm() < running_min) { running_projection = point_temp; - running_min = this->distance_to(running_projection); + running_min = (running_projection - *this).cast<double>().norm(); } } return running_projection; } -Point -Point::projection_onto(const Line &line) const +Point Point::projection_onto(const Line &line) const { - if (line.a.coincides_with(line.b)) return line.a; + if (line.a == line.b) return line.a; /* (Ported from VisiLibity by Karl J. Obermeyer) @@ -229,171 +174,35 @@ Point::projection_onto(const Line &line) const If theta is outside the interval [0,1], then one of the Line_Segment's endpoints must be closest to calling Point. */ - double lx = (double)(line.b.x - line.a.x); - double ly = (double)(line.b.y - line.a.y); - double theta = ( (double)(line.b.x - this->x)*lx + (double)(line.b.y- this->y)*ly ) + double lx = (double)(line.b(0) - line.a(0)); + double ly = (double)(line.b(1) - line.a(1)); + double theta = ( (double)(line.b(0) - (*this)(0))*lx + (double)(line.b(1)- (*this)(1))*ly ) / ( sqr<double>(lx) + sqr<double>(ly) ); if (0.0 <= theta && theta <= 1.0) - return theta * line.a + (1.0-theta) * line.b; + return (theta * line.a.cast<coordf_t>() + (1.0-theta) * line.b.cast<coordf_t>()).cast<coord_t>(); // Else pick closest endpoint. - if (this->distance_to(line.a) < this->distance_to(line.b)) { - return line.a; - } else { - return line.b; - } -} - -Point -Point::negative() const -{ - return Point(-this->x, -this->y); -} - -Vector -Point::vector_to(const Point &point) const -{ - return Vector(point.x - this->x, point.y - this->y); -} - -std::ostream& -operator<<(std::ostream &stm, const Pointf &pointf) -{ - return stm << pointf.x << "," << pointf.y; -} - -double -Pointf::ccw(const Pointf &p1, const Pointf &p2) const -{ - return (double)(p2.x - p1.x)*(double)(this->y - p1.y) - (double)(p2.y - p1.y)*(double)(this->x - p1.x); -} - -std::string -Pointf::wkt() const -{ - std::ostringstream ss; - ss << "POINT(" << this->x << " " << this->y << ")"; - return ss.str(); -} - -std::string -Pointf::dump_perl() const -{ - std::ostringstream ss; - ss << "[" << this->x << "," << this->y << "]"; - return ss.str(); -} - -void -Pointf::scale(double factor) -{ - this->x *= factor; - this->y *= factor; -} - -void -Pointf::translate(double x, double y) -{ - this->x += x; - this->y += y; -} - -void -Pointf::translate(const Vectorf &vector) -{ - this->translate(vector.x, vector.y); -} - -void -Pointf::rotate(double angle) -{ - double cur_x = this->x; - double cur_y = this->y; - double s = sin(angle); - double c = cos(angle); - this->x = c * cur_x - s * cur_y; - this->y = c * cur_y + s * cur_x; -} - -void -Pointf::rotate(double angle, const Pointf ¢er) -{ - double cur_x = this->x; - double cur_y = this->y; - double s = sin(angle); - double c = cos(angle); - double dx = cur_x - center.x; - double dy = cur_y - center.y; - this->x = center.x + c * dx - s * dy; - this->y = center.y + c * dy + s * dx; -} - -Pointf -Pointf::negative() const -{ - return Pointf(-this->x, -this->y); -} - -Vectorf -Pointf::vector_to(const Pointf &point) const -{ - return Vectorf(point.x - this->x, point.y - this->y); -} - -void -Pointf3::scale(double factor) -{ - Pointf::scale(factor); - this->z *= factor; -} - -void -Pointf3::translate(const Vectorf3 &vector) -{ - this->translate(vector.x, vector.y, vector.z); -} - -void -Pointf3::translate(double x, double y, double z) -{ - Pointf::translate(x, y); - this->z += z; -} - -double -Pointf3::distance_to(const Pointf3 &point) const -{ - double dx = ((double)point.x - this->x); - double dy = ((double)point.y - this->y); - double dz = ((double)point.z - this->z); - return sqrt(dx*dx + dy*dy + dz*dz); -} - -Pointf3 -Pointf3::negative() const -{ - return Pointf3(-this->x, -this->y, -this->z); + return ((line.a - *this).cast<double>().squaredNorm() < (line.b - *this).cast<double>().squaredNorm()) ? line.a : line.b; } -Vectorf3 -Pointf3::vector_to(const Pointf3 &point) const +std::ostream& operator<<(std::ostream &stm, const Vec2d &pointf) { - return Vectorf3(point.x - this->x, point.y - this->y, point.z - this->z); + return stm << pointf(0) << "," << pointf(1); } namespace int128 { -int orient(const Point &p1, const Point &p2, const Point &p3) +int orient(const Vec2crd &p1, const Vec2crd &p2, const Vec2crd &p3) { Slic3r::Vector v1(p2 - p1); Slic3r::Vector v2(p3 - p1); - return Int128::sign_determinant_2x2_filtered(v1.x, v1.y, v2.x, v2.y); + return Int128::sign_determinant_2x2_filtered(v1(0), v1(1), v2(0), v2(1)); } -int cross(const Point &v1, const Point &v2) +int cross(const Vec2crd &v1, const Vec2crd &v2) { - return Int128::sign_determinant_2x2_filtered(v1.x, v1.y, v2.x, v2.y); + return Int128::sign_determinant_2x2_filtered(v1(0), v1(1), v2(0), v2(1)); } } diff --git a/xs/src/libslic3r/Point.hpp b/xs/src/libslic3r/Point.hpp index 347966c03..c1aff561f 100644 --- a/xs/src/libslic3r/Point.hpp +++ b/xs/src/libslic3r/Point.hpp @@ -2,100 +2,131 @@ #define slic3r_Point_hpp_ #include "libslic3r.h" +#include <cstddef> #include <vector> -#include <math.h> +#include <cmath> #include <string> #include <sstream> #include <unordered_map> +#include <Eigen/Geometry> + namespace Slic3r { class Line; -class Linef; class MultiPoint; class Point; -class Point3; -class Pointf; -class Pointf3; typedef Point Vector; -typedef Point3 Vector3; -typedef Pointf Vectorf; -typedef Pointf3 Vectorf3; -typedef std::vector<Point> Points; -typedef std::vector<Point*> PointPtrs; -typedef std::vector<const Point*> PointConstPtrs; -typedef std::vector<Point3> Points3; -typedef std::vector<Pointf> Pointfs; -typedef std::vector<Pointf3> Pointf3s; -class Point +// Eigen types, to replace the Slic3r's own types in the future. +// Vector types with a fixed point coordinate base type. +typedef Eigen::Matrix<coord_t, 2, 1, Eigen::DontAlign> Vec2crd; +typedef Eigen::Matrix<coord_t, 3, 1, Eigen::DontAlign> Vec3crd; +typedef Eigen::Matrix<int64_t, 2, 1, Eigen::DontAlign> Vec2i64; +typedef Eigen::Matrix<int64_t, 3, 1, Eigen::DontAlign> Vec3i64; + +// Vector types with a double coordinate base type. +typedef Eigen::Matrix<float, 2, 1, Eigen::DontAlign> Vec2f; +typedef Eigen::Matrix<float, 3, 1, Eigen::DontAlign> Vec3f; +typedef Eigen::Matrix<double, 2, 1, Eigen::DontAlign> Vec2d; +typedef Eigen::Matrix<double, 3, 1, Eigen::DontAlign> Vec3d; + +typedef std::vector<Point> Points; +typedef std::vector<Point*> PointPtrs; +typedef std::vector<const Point*> PointConstPtrs; +typedef std::vector<Vec3crd> Points3; +typedef std::vector<Vec2d> Pointfs; +typedef std::vector<Vec3d> Pointf3s; + +typedef Eigen::Transform<float, 2, Eigen::Affine, Eigen::DontAlign> Transform2f; +typedef Eigen::Transform<double, 2, Eigen::Affine, Eigen::DontAlign> Transform2d; +typedef Eigen::Transform<float, 3, Eigen::Affine, Eigen::DontAlign> Transform3f; +typedef Eigen::Transform<double, 3, Eigen::Affine, Eigen::DontAlign> Transform3d; + +inline bool operator<(const Vec2d &lhs, const Vec2d &rhs) { return lhs(0) < rhs(0) || (lhs(0) == rhs(0) && lhs(1) < rhs(1)); } + +inline int64_t cross2(const Vec2i64 &v1, const Vec2i64 &v2) { return v1(0) * v2(1) - v1(1) * v2(0); } +inline coord_t cross2(const Vec2crd &v1, const Vec2crd &v2) { return v1(0) * v2(1) - v1(1) * v2(0); } +inline float cross2(const Vec2f &v1, const Vec2f &v2) { return v1(0) * v2(1) - v1(1) * v2(0); } +inline double cross2(const Vec2d &v1, const Vec2d &v2) { return v1(0) * v2(1) - v1(1) * v2(0); } + +inline Vec2crd to_2d(const Vec3crd &pt3) { return Vec2crd(pt3(0), pt3(1)); } +inline Vec2i64 to_2d(const Vec3i64 &pt3) { return Vec2i64(pt3(0), pt3(1)); } +inline Vec2f to_2d(const Vec3f &pt3) { return Vec2f (pt3(0), pt3(1)); } +inline Vec2d to_2d(const Vec3d &pt3) { return Vec2d (pt3(0), pt3(1)); } + +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 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 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)) + "]"; } + +std::vector<Vec3f> transform(const std::vector<Vec3f>& points, const Transform3f& t); +Pointf3s transform(const Pointf3s& points, const Transform3d& t); + +class Point : public Vec2crd { public: typedef coord_t coord_type; - coord_t x; - coord_t y; - Point(coord_t _x = 0, coord_t _y = 0): x(_x), y(_y) {}; - Point(int64_t _x, int64_t _y): x(coord_t(_x)), y(coord_t(_y)) {}; // for Clipper - Point(double x, double y); + + Point() : Vec2crd() { (*this)(0) = 0; (*this)(1) = 0; } + Point(coord_t x, coord_t y) { (*this)(0) = x; (*this)(1) = y; } + Point(int64_t x, int64_t y) { (*this)(0) = coord_t(x); (*this)(1) = coord_t(y); } // for Clipper + Point(double x, double y) { (*this)(0) = coord_t(lrint(x)); (*this)(1) = coord_t(lrint(y)); } + Point(const Point &rhs) { *this = rhs; } + // This constructor allows you to construct Point from Eigen expressions + template<typename OtherDerived> + Point(const Eigen::MatrixBase<OtherDerived> &other) : Vec2crd(other) {} static Point new_scale(coordf_t x, coordf_t y) { return Point(coord_t(scale_(x)), coord_t(scale_(y))); } - bool operator==(const Point& rhs) const { return this->x == rhs.x && this->y == rhs.y; } - bool operator!=(const Point& rhs) const { return ! (*this == rhs); } - bool operator<(const Point& rhs) const { return this->x < rhs.x || (this->x == rhs.x && this->y < rhs.y); } + // This method allows you to assign Eigen expressions to MyVectorType + template<typename OtherDerived> + Point& operator=(const Eigen::MatrixBase<OtherDerived> &other) + { + this->Vec2crd::operator=(other); + 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->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 coord_t& rhs) { this->x *= rhs; this->y *= rhs; return *this; } + 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) *= rhs; (*this)(1) *= rhs; return *this; } - std::string wkt() const; - std::string dump_perl() const; - void scale(double factor); - void translate(double x, double y); - void translate(const Vector &vector); - void rotate(double angle); - void rotate(double angle, const Point ¢er); - Point rotated(double angle) const { Point res(*this); res.rotate(angle); return res; } - Point rotated(double angle, const Point ¢er) const { Point res(*this); res.rotate(angle, center); return res; } - bool coincides_with(const Point &point) const { return this->x == point.x && this->y == point.y; } - bool coincides_with_epsilon(const Point &point) const; - int nearest_point_index(const Points &points) const; - int nearest_point_index(const PointConstPtrs &points) const; - int nearest_point_index(const PointPtrs &points) const; - bool nearest_point(const Points &points, Point* point) const; - double distance_to(const Point &point) const { return sqrt(distance_to_sq(point)); } - double distance_to_sq(const Point &point) const { double dx = double(point.x - this->x); double dy = double(point.y - this->y); return dx*dx + dy*dy; } - double distance_to(const Line &line) const; - double perp_distance_to(const Line &line) const; + void rotate(double angle); + void rotate(double angle, const Point ¢er); + Point rotated(double angle) const { Point res(*this); res.rotate(angle); return res; } + Point rotated(double angle, const Point ¢er) const { Point res(*this); res.rotate(angle, center); return res; } + int nearest_point_index(const Points &points) const; + int nearest_point_index(const PointConstPtrs &points) const; + int nearest_point_index(const PointPtrs &points) const; + bool nearest_point(const Points &points, Point* point) const; double ccw(const Point &p1, const Point &p2) const; double ccw(const Line &line) const; double ccw_angle(const Point &p1, const Point &p2) const; - Point projection_onto(const MultiPoint &poly) const; - Point projection_onto(const Line &line) const; - Point negative() const; - Vector vector_to(const Point &point) const; + Point projection_onto(const MultiPoint &poly) const; + Point projection_onto(const Line &line) const; }; -inline Point operator+(const Point& point1, const Point& point2) { return Point(point1.x + point2.x, point1.y + point2.y); } -inline Point operator-(const Point& point1, const Point& point2) { return Point(point1.x - point2.x, point1.y - point2.y); } -inline Point operator*(double scalar, const Point& point2) { return Point(scalar * point2.x, scalar * point2.y); } -inline int64_t cross(const Point &v1, const Point &v2) { return int64_t(v1.x) * int64_t(v2.y) - int64_t(v1.y) * int64_t(v2.x); } -inline int64_t dot(const Point &v1, const Point &v2) { return int64_t(v1.x) * int64_t(v2.x) + int64_t(v1.y) * int64_t(v2.y); } - namespace int128 { - -// Exact orientation predicate, -// returns +1: CCW, 0: collinear, -1: CW. -int orient(const Point &p1, const Point &p2, const Point &p3); - -// Exact orientation predicate, -// returns +1: CCW, 0: collinear, -1: CW. -int cross(const Point &v1, const Slic3r::Point &v2); + // Exact orientation predicate, + // returns +1: CCW, 0: collinear, -1: CW. + int orient(const Vec2crd &p1, const Vec2crd &p2, const Vec2crd &p3); + // Exact orientation predicate, + // returns +1: CCW, 0: collinear, -1: CW. + int cross(const Vec2crd &v1, const Vec2crd &v2); } // To be used by std::unordered_map, std::unordered_multimap and friends. struct PointHash { - size_t operator()(const Point &pt) const { - return std::hash<coord_t>()(pt.x) ^ std::hash<coord_t>()(pt.y); + size_t operator()(const Vec2crd &pt) const { + return std::hash<coord_t>()(pt(0)) ^ std::hash<coord_t>()(pt(1)); } }; @@ -139,36 +170,36 @@ public: } void insert(const ValueType &value) { - const Point *pt = m_point_accessor(value); + const Vec2crd *pt = m_point_accessor(value); if (pt != nullptr) - m_map.emplace(std::make_pair(Point(pt->x>>m_grid_log2, pt->y>>m_grid_log2), value)); + m_map.emplace(std::make_pair(Vec2crd(pt->x()>>m_grid_log2, pt->y()>>m_grid_log2), value)); } void insert(ValueType &&value) { - const Point *pt = m_point_accessor(value); + const Vec2crd *pt = m_point_accessor(value); if (pt != nullptr) - m_map.emplace(std::make_pair(Point(pt->x>>m_grid_log2, pt->y>>m_grid_log2), std::move(value))); + m_map.emplace(std::make_pair(Vec2crd(pt->x()>>m_grid_log2, pt->y()>>m_grid_log2), std::move(value))); } // Return a pair of <ValueType*, distance_squared> - std::pair<const ValueType*, double> find(const Point &pt) { + std::pair<const ValueType*, double> find(const Vec2crd &pt) { // Iterate over 4 closest grid cells around pt, // find the closest start point inside these cells to pt. const ValueType *value_min = nullptr; double dist_min = std::numeric_limits<double>::max(); // Round pt to a closest grid_cell corner. - Point grid_corner((pt.x+(m_grid_resolution>>1))>>m_grid_log2, (pt.y+(m_grid_resolution>>1))>>m_grid_log2); + Vec2crd grid_corner((pt(0)+(m_grid_resolution>>1))>>m_grid_log2, (pt(1)+(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(Point(grid_corner.x + neighbor_x, grid_corner.y + neighbor_y)); + auto range = m_map.equal_range(Vec2crd(grid_corner(0) + neighbor_x, grid_corner(1) + neighbor_y)); // Find the map entry closest to pt. for (auto it = range.first; it != range.second; ++it) { const ValueType &value = it->second; - const Point *pt2 = m_point_accessor(value); + const Vec2crd *pt2 = m_point_accessor(value); if (pt2 != nullptr) { - const double d2 = pt.distance_to_sq(*pt2); + const double d2 = (pt - *pt2).squaredNorm(); if (d2 < dist_min) { dist_min = d2; value_min = &value; @@ -183,7 +214,7 @@ public: } private: - typedef typename std::unordered_multimap<Point, ValueType, PointHash> map_type; + typedef typename std::unordered_multimap<Vec2crd, ValueType, PointHash> map_type; PointAccessor m_point_accessor; map_type m_map; coord_t m_search_radius; @@ -191,113 +222,7 @@ private: coord_t m_grid_log2; }; -class Point3 : public Point -{ -public: - coord_t z; - explicit Point3(coord_t _x = 0, coord_t _y = 0, coord_t _z = 0): Point(_x, _y), z(_z) {}; - static Point3 new_scale(coordf_t x, coordf_t y, coordf_t z) { return Point3(coord_t(scale_(x)), coord_t(scale_(y)), coord_t(scale_(z))); } - bool operator==(const Point3 &rhs) const { return this->x == rhs.x && this->y == rhs.y && this->z == rhs.z; } - bool operator!=(const Point3 &rhs) const { return ! (*this == rhs); } - bool coincides_with(const Point3& rhs) const { return this->x == rhs.x && this->y == rhs.y && this->z == rhs.z; } -private: - // Hide the following inherited methods: - bool operator==(const Point &rhs) const; - bool operator!=(const Point &rhs) const; -}; - -std::ostream& operator<<(std::ostream &stm, const Pointf &pointf); - -class Pointf -{ -public: - typedef coordf_t coord_type; - coordf_t x; - coordf_t y; - explicit Pointf(coordf_t _x = 0, coordf_t _y = 0): x(_x), y(_y) {}; - static Pointf new_unscale(coord_t x, coord_t y) { - return Pointf(unscale(x), unscale(y)); - }; - static Pointf new_unscale(const Point &p) { - return Pointf(unscale(p.x), unscale(p.y)); - }; - double ccw(const Pointf &p1, const Pointf &p2) const; - std::string wkt() const; - std::string dump_perl() const; - void scale(double factor); - void translate(double x, double y); - void translate(const Vectorf &vector); - void rotate(double angle); - void rotate(double angle, const Pointf ¢er); - Pointf negative() const; - Vectorf vector_to(const Pointf &point) const; - - Pointf& operator+=(const Pointf& rhs) { this->x += rhs.x; this->y += rhs.y; return *this; } - Pointf& operator-=(const Pointf& rhs) { this->x -= rhs.x; this->y -= rhs.y; return *this; } - Pointf& operator*=(const coordf_t& rhs) { this->x *= rhs; this->y *= rhs; return *this; } - - bool operator==(const Pointf &rhs) const { return this->x == rhs.x && this->y == rhs.y; } - bool operator!=(const Pointf &rhs) const { return ! (*this == rhs); } - bool operator< (const Pointf& rhs) const { return this->x < rhs.x || (this->x == rhs.x && this->y < rhs.y); } -}; - -inline Pointf operator+(const Pointf& point1, const Pointf& point2) { return Pointf(point1.x + point2.x, point1.y + point2.y); } -inline Pointf operator-(const Pointf& point1, const Pointf& point2) { return Pointf(point1.x - point2.x, point1.y - point2.y); } -inline Pointf operator*(double scalar, const Pointf& point2) { return Pointf(scalar * point2.x, scalar * point2.y); } -inline Pointf operator*(const Pointf& point2, double scalar) { return Pointf(scalar * point2.x, scalar * point2.y); } -inline coordf_t cross(const Pointf &v1, const Pointf &v2) { return v1.x * v2.y - v1.y * v2.x; } -inline coordf_t dot(const Pointf &v1, const Pointf &v2) { return v1.x * v2.x + v1.y * v2.y; } -inline coordf_t dot(const Pointf &v) { return v.x * v.x + v.y * v.y; } -inline double length(const Vectorf &v) { return sqrt(dot(v)); } -inline double l2(const Vectorf &v) { return dot(v); } -inline Vectorf normalize(const Vectorf& v) -{ - coordf_t len = ::sqrt(sqr(v.x) + sqr(v.y)); - return (len != 0.0) ? 1.0 / len * v : Vectorf(0.0, 0.0); -} - -class Pointf3 : public Pointf -{ -public: - coordf_t z; - explicit Pointf3(coordf_t _x = 0, coordf_t _y = 0, coordf_t _z = 0): Pointf(_x, _y), z(_z) {}; - static Pointf3 new_unscale(coord_t x, coord_t y, coord_t z) { - return Pointf3(unscale(x), unscale(y), unscale(z)); - }; - static Pointf3 new_unscale(const Point3& p) { return Pointf3(unscale(p.x), unscale(p.y), unscale(p.z)); } - void scale(double factor); - void translate(const Vectorf3 &vector); - void translate(double x, double y, double z); - double distance_to(const Pointf3 &point) const; - Pointf3 negative() const; - Vectorf3 vector_to(const Pointf3 &point) const; - - bool operator==(const Pointf3 &rhs) const { return this->x == rhs.x && this->y == rhs.y && this->z == rhs.z; } - bool operator!=(const Pointf3 &rhs) const { return ! (*this == rhs); } - -private: - // Hide the following inherited methods: - bool operator==(const Pointf &rhs) const; - bool operator!=(const Pointf &rhs) const; -}; - -inline Pointf3 operator+(const Pointf3& p1, const Pointf3& p2) { return Pointf3(p1.x + p2.x, p1.y + p2.y, p1.z + p2.z); } -inline Pointf3 operator-(const Pointf3& p1, const Pointf3& p2) { return Pointf3(p1.x - p2.x, p1.y - p2.y, p1.z - p2.z); } -inline Pointf3 operator-(const Pointf3& p) { return Pointf3(-p.x, -p.y, -p.z); } -inline Pointf3 operator*(double scalar, const Pointf3& p) { return Pointf3(scalar * p.x, scalar * p.y, scalar * p.z); } -inline Pointf3 operator*(const Pointf3& p, double scalar) { return Pointf3(scalar * p.x, scalar * p.y, scalar * p.z); } -inline Pointf3 cross(const Pointf3& v1, const Pointf3& v2) { return Pointf3(v1.y * v2.z - v1.z * v2.y, v1.z * v2.x - v1.x * v2.z, v1.x * v2.y - v1.y * v2.x); } -inline coordf_t dot(const Pointf3& v1, const Pointf3& v2) { return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z; } -inline Pointf3 normalize(const Pointf3& v) -{ - coordf_t len = ::sqrt(sqr(v.x) + sqr(v.y) + sqr(v.z)); - return (len != 0.0) ? 1.0 / len * v : Pointf3(0.0, 0.0, 0.0); -} - -template<typename TO> inline TO convert_to(const Point &src) { return TO(typename TO::coord_type(src.x), typename TO::coord_type(src.y)); } -template<typename TO> inline TO convert_to(const Pointf &src) { return TO(typename TO::coord_type(src.x), typename TO::coord_type(src.y)); } -template<typename TO> inline TO convert_to(const Point3 &src) { return TO(typename TO::coord_type(src.x), typename TO::coord_type(src.y), typename TO::coord_type(src.z)); } -template<typename TO> inline TO convert_to(const Pointf3 &src) { return TO(typename TO::coord_type(src.x), typename TO::coord_type(src.y), typename TO::coord_type(src.z)); } +std::ostream& operator<<(std::ostream &stm, const Vec2d &pointf); } // namespace Slic3r @@ -313,7 +238,7 @@ namespace boost { namespace polygon { typedef coord_t coordinate_type; static inline coordinate_type get(const Slic3r::Point& point, orientation_2d orient) { - return (orient == HORIZONTAL) ? point.x : point.y; + return (orient == HORIZONTAL) ? (coordinate_type)point(0) : (coordinate_type)point(1); } }; @@ -322,14 +247,14 @@ namespace boost { namespace polygon { typedef coord_t coordinate_type; static inline void set(Slic3r::Point& point, orientation_2d orient, coord_t value) { if (orient == HORIZONTAL) - point.x = value; + point(0) = value; else - point.y = value; + point(1) = value; } static inline Slic3r::Point construct(coord_t x_value, coord_t y_value) { Slic3r::Point retval; - retval.x = x_value; - retval.y = y_value; + retval(0) = x_value; + retval(1) = y_value; return retval; } }; diff --git a/xs/src/libslic3r/Polygon.cpp b/xs/src/libslic3r/Polygon.cpp index b5fd7e64f..14248d84f 100644 --- a/xs/src/libslic3r/Polygon.cpp +++ b/xs/src/libslic3r/Polygon.cpp @@ -44,11 +44,9 @@ Polyline Polygon::split_at_vertex(const Point &point) const { // find index of point - for (Points::const_iterator it = this->points.begin(); it != this->points.end(); ++it) { - if (it->coincides_with(point)) { - return this->split_at_index(it - this->points.begin()); - } - } + for (const Point &pt : this->points) + if (pt == point) + return this->split_at_index(&pt - &this->points.front()); CONFESS("Point not found"); return Polyline(); } @@ -88,7 +86,7 @@ int64_t Polygon::area2x() const int64_t a = 0; for (size_t i = 0, j = n - 1; i < n; ++i) - a += int64_t(poly[j].x + poly[i].x) * int64_t(poly[j].y - poly[i].y); + a += int64_t(poly[j](0) + poly[i](0)) * int64_t(poly[j](1) - poly[i](1)); j = i; } return -a * 0.5; @@ -103,7 +101,7 @@ double Polygon::area() const double a = 0.; for (size_t i = 0, j = n - 1; i < n; ++i) { - a += ((double)points[j].x + (double)points[i].x) * ((double)points[i].y - (double)points[j].y); + a += ((double)points[j](0) + (double)points[i](0)) * ((double)points[i](1) - (double)points[j](1)); j = i; } return 0.5 * a; @@ -157,17 +155,17 @@ Polygon::contains(const Point &point) const Points::const_iterator i = this->points.begin(); Points::const_iterator j = this->points.end() - 1; for (; i != this->points.end(); j = i++) { - //FIXME this test is not numerically robust. Particularly, it does not handle horizontal segments at y == point.y well. - // Does the ray with y == point.y intersect this line segment? + //FIXME this test is not numerically robust. Particularly, it does not handle horizontal segments at y == point(1) well. + // Does the ray with y == point(1) intersect this line segment? #if 1 - if ( ((i->y > point.y) != (j->y > point.y)) - && ((double)point.x < (double)(j->x - i->x) * (double)(point.y - i->y) / (double)(j->y - i->y) + (double)i->x) ) + if ( (((*i)(1) > point(1)) != ((*j)(1) > point(1))) + && ((double)point(0) < (double)((*j)(0) - (*i)(0)) * (double)(point(1) - (*i)(1)) / (double)((*j)(1) - (*i)(1)) + (double)(*i)(0)) ) result = !result; #else - if ((i->y > point.y) != (j->y > point.y)) { + if (((*i)(1) > point(1)) != ((*j)(1) > point(1))) { // Orientation predicated relative to i-th point. - double orient = (double)(point.x - i->x) * (double)(j->y - i->y) - (double)(point.y - i->y) * (double)(j->x - i->x); - if ((i->y > j->y) ? (orient > 0.) : (orient < 0.)) + double orient = (double)(point(0) - (*i)(0)) * (double)((*j)(1) - (*i)(1)) - (double)(point(1) - (*i)(1)) * (double)((*j)(0) - (*i)(0)); + if (((*i)(1) > (*j)(1)) ? (orient > 0.) : (orient < 0.)) result = !result; } #endif @@ -225,26 +223,13 @@ Polygon::centroid() const Polyline polyline = this->split_at_first_point(); for (Points::const_iterator point = polyline.points.begin(); point != polyline.points.end() - 1; ++point) { - x_temp += (double)( point->x + (point+1)->x ) * ( (double)point->x*(point+1)->y - (double)(point+1)->x*point->y ); - y_temp += (double)( point->y + (point+1)->y ) * ( (double)point->x*(point+1)->y - (double)(point+1)->x*point->y ); + x_temp += (double)( point->x() + (point+1)->x() ) * ( (double)point->x()*(point+1)->y() - (double)(point+1)->x()*point->y() ); + y_temp += (double)( point->y() + (point+1)->y() ) * ( (double)point->x()*(point+1)->y() - (double)(point+1)->x()*point->y() ); } return Point(x_temp/(6*area_temp), y_temp/(6*area_temp)); } -std::string -Polygon::wkt() const -{ - std::ostringstream wkt; - wkt << "POLYGON(("; - for (Points::const_iterator p = this->points.begin(); p != this->points.end(); ++p) { - wkt << p->x << " " << p->y; - if (p != this->points.end()-1) wkt << ","; - } - wkt << "))"; - return wkt.str(); -} - // find all concave vertices (i.e. having an internal angle greater than the supplied angle) // (external = right side, thus we consider ccw orientation) Points @@ -302,24 +287,24 @@ Point Polygon::point_projection(const Point &point) const for (size_t i = 0; i < this->points.size(); ++ i) { const Point &pt0 = this->points[i]; const Point &pt1 = this->points[(i + 1 == this->points.size()) ? 0 : i + 1]; - double d = pt0.distance_to(point); + double d = (point - pt0).cast<double>().norm(); if (d < dmin) { dmin = d; proj = pt0; } - d = pt1.distance_to(point); + d = (point - pt1).cast<double>().norm(); if (d < dmin) { dmin = d; proj = pt1; } - Pointf v1(coordf_t(pt1.x - pt0.x), coordf_t(pt1.y - pt0.y)); - coordf_t div = dot(v1); + Vec2d v1(coordf_t(pt1(0) - pt0(0)), coordf_t(pt1(1) - pt0(1))); + coordf_t div = v1.squaredNorm(); if (div > 0.) { - Pointf v2(coordf_t(point.x - pt0.x), coordf_t(point.y - pt0.y)); - coordf_t t = dot(v1, v2) / div; + Vec2d v2(coordf_t(point(0) - pt0(0)), coordf_t(point(1) - pt0(1))); + coordf_t t = v1.dot(v2) / div; if (t > 0. && t < 1.) { - Point foot(coord_t(floor(coordf_t(pt0.x) + t * v1.x + 0.5)), coord_t(floor(coordf_t(pt0.y) + t * v1.y + 0.5))); - d = foot.distance_to(point); + Point foot(coord_t(floor(coordf_t(pt0(0)) + t * v1(0) + 0.5)), coord_t(floor(coordf_t(pt0(1)) + t * v1(1) + 0.5))); + d = (point - foot).cast<double>().norm(); if (d < dmin) { dmin = d; proj = foot; @@ -376,12 +361,12 @@ static inline bool is_stick(const Point &p1, const Point &p2, const Point &p3) { Point v1 = p2 - p1; Point v2 = p3 - p2; - int64_t dir = int64_t(v1.x) * int64_t(v2.x) + int64_t(v1.y) * int64_t(v2.y); + int64_t dir = int64_t(v1(0)) * int64_t(v2(0)) + int64_t(v1(1)) * int64_t(v2(1)); if (dir > 0) // p3 does not turn back to p1. Do not remove p2. return false; - double l2_1 = double(v1.x) * double(v1.x) + double(v1.y) * double(v1.y); - double l2_2 = double(v2.x) * double(v2.x) + double(v2.y) * double(v2.y); + double l2_1 = double(v1(0)) * double(v1(0)) + double(v1(1)) * double(v1(1)); + double l2_2 = double(v2(0)) * double(v2(0)) + double(v2(1)) * double(v2(1)); if (dir == 0) // p1, p2, p3 may make a perpendicular corner, or there is a zero edge length. // Remove p2 if it is coincident with p1 or p2. @@ -389,7 +374,7 @@ static inline bool is_stick(const Point &p1, const Point &p2, const Point &p3) // p3 turns back to p1 after p2. Are p1, p2, p3 collinear? // Calculate distance from p3 to a segment (p1, p2) or from p1 to a segment(p2, p3), // whichever segment is longer - double cross = double(v1.x) * double(v2.y) - double(v2.x) * double(v1.y); + double cross = double(v1(0)) * double(v2(1)) - double(v2(0)) * double(v1(1)); double dist2 = cross * cross / std::max(l2_1, l2_2); return dist2 < EPSILON * EPSILON; } diff --git a/xs/src/libslic3r/Polygon.hpp b/xs/src/libslic3r/Polygon.hpp index 1a02d78b7..54909352c 100644 --- a/xs/src/libslic3r/Polygon.hpp +++ b/xs/src/libslic3r/Polygon.hpp @@ -24,11 +24,12 @@ public: explicit Polygon(const Points &points): MultiPoint(points) {} Polygon(const Polygon &other) : MultiPoint(other.points) {} Polygon(Polygon &&other) : MultiPoint(std::move(other.points)) {} - static Polygon new_scale(std::vector<Pointf> points) { - Points int_points; - for (auto pt : points) - int_points.push_back(Point::new_scale(pt.x, pt.y)); - return Polygon(int_points); + static Polygon new_scale(const std::vector<Vec2d> &points) { + Polygon pgn; + pgn.points.reserve(points.size()); + for (const Vec2d &pt : points) + pgn.points.emplace_back(Point::new_scale(pt(0), pt(1))); + return pgn; } Polygon& operator=(const Polygon &other) { points = other.points; return *this; } Polygon& operator=(Polygon &&other) { points = std::move(other.points); return *this; } @@ -54,7 +55,6 @@ public: void simplify(double tolerance, Polygons &polygons) const; void triangulate_convex(Polygons* polygons) const; Point centroid() const; - std::string wkt() const; Points concave_points(double angle = PI) const; Points convex_points(double angle = PI) const; // Projection of a point onto the polygon. diff --git a/xs/src/libslic3r/Polyline.cpp b/xs/src/libslic3r/Polyline.cpp index 3432506c6..b2e50bca3 100644 --- a/xs/src/libslic3r/Polyline.cpp +++ b/xs/src/libslic3r/Polyline.cpp @@ -33,7 +33,7 @@ Polyline::leftmost_point() const { Point p = this->points.front(); for (Points::const_iterator it = this->points.begin() + 1; it != this->points.end(); ++it) { - if (it->x < p.x) p = *it; + if ((*it)(0) < p(0)) p = *it; } return p; } @@ -52,92 +52,82 @@ Polyline::lines() const } // removes the given distance from the end of the polyline -void -Polyline::clip_end(double distance) +void Polyline::clip_end(double distance) { while (distance > 0) { - Point last_point = this->last_point(); + Vec2d last_point = this->last_point().cast<double>(); this->points.pop_back(); - if (this->points.empty()) break; - - double last_segment_length = last_point.distance_to(this->last_point()); - if (last_segment_length <= distance) { - distance -= last_segment_length; - continue; + if (this->points.empty()) + break; + Vec2d v = this->last_point().cast<double>() - last_point; + double lsqr = v.squaredNorm(); + if (lsqr > distance * distance) { + this->points.emplace_back((last_point + v * (distance / sqrt(lsqr))).cast<coord_t>()); + return; } - - Line segment(last_point, this->last_point()); - this->points.push_back(segment.point_at(distance)); - distance = 0; + distance -= sqrt(lsqr); } } // removes the given distance from the start of the polyline -void -Polyline::clip_start(double distance) +void Polyline::clip_start(double distance) { this->reverse(); this->clip_end(distance); - if (this->points.size() >= 2) this->reverse(); + if (this->points.size() >= 2) + this->reverse(); } -void -Polyline::extend_end(double distance) +void Polyline::extend_end(double distance) { // relocate last point by extending the last segment by the specified length - Line line( - this->points.back(), - *(this->points.end() - 2) - ); - this->points.back() = line.point_at(-distance); + Vec2d v = (this->points.back() - *(this->points.end() - 2)).cast<double>().normalized(); + this->points.back() += (v * distance).cast<coord_t>(); } -void -Polyline::extend_start(double distance) +void Polyline::extend_start(double distance) { // relocate first point by extending the first segment by the specified length - this->points.front() = Line(this->points.front(), this->points[1]).point_at(-distance); + Vec2d v = (this->points.front() - this->points[1]).cast<double>().normalized(); + this->points.front() += (v * distance).cast<coord_t>(); } /* this method returns a collection of points picked on the polygon contour so that they are evenly spaced according to the input distance */ -Points -Polyline::equally_spaced_points(double distance) const +Points Polyline::equally_spaced_points(double distance) const { Points points; - points.push_back(this->first_point()); + points.emplace_back(this->first_point()); double len = 0; for (Points::const_iterator it = this->points.begin() + 1; it != this->points.end(); ++it) { - double segment_length = it->distance_to(*(it-1)); + Vec2d p1 = (it-1)->cast<double>(); + Vec2d v = it->cast<double>() - p1; + double segment_length = v.norm(); len += segment_length; - if (len < distance) continue; - + if (len < distance) + continue; if (len == distance) { - points.push_back(*it); + points.emplace_back(*it); len = 0; continue; } - double take = segment_length - (len - distance); // how much we take of this segment - Line segment(*(it-1), *it); - points.push_back(segment.point_at(take)); - --it; - len = -take; + points.emplace_back((p1 + v * (take / v.norm())).cast<coord_t>()); + -- it; + len = - take; } return points; } -void -Polyline::simplify(double tolerance) +void Polyline::simplify(double tolerance) { this->points = MultiPoint::_douglas_peucker(this->points, tolerance); } /* This method simplifies all *lines* contained in the supplied area */ template <class T> -void -Polyline::simplify_by_visibility(const T &area) +void Polyline::simplify_by_visibility(const T &area) { Points &pp = this->points; @@ -157,30 +147,29 @@ Polyline::simplify_by_visibility(const T &area) template void Polyline::simplify_by_visibility<ExPolygon>(const ExPolygon &area); template void Polyline::simplify_by_visibility<ExPolygonCollection>(const ExPolygonCollection &area); -void -Polyline::split_at(const Point &point, Polyline* p1, Polyline* p2) const +void Polyline::split_at(const Point &point, Polyline* p1, Polyline* p2) const { if (this->points.empty()) return; // find the line to split at size_t line_idx = 0; Point p = this->first_point(); - double min = point.distance_to(p); + double min = (p - point).cast<double>().norm(); Lines lines = this->lines(); for (Lines::const_iterator line = lines.begin(); line != lines.end(); ++line) { Point p_tmp = point.projection_onto(*line); - if (point.distance_to(p_tmp) < min) { + if ((p_tmp - point).cast<double>().norm() < min) { p = p_tmp; - min = point.distance_to(p); + min = (p - point).cast<double>().norm(); line_idx = line - lines.begin(); } } // create first half p1->points.clear(); - for (Lines::const_iterator line = lines.begin(); line != lines.begin() + line_idx + 1; ++line) { - if (!line->a.coincides_with(p)) p1->points.push_back(line->a); - } + for (Lines::const_iterator line = lines.begin(); line != lines.begin() + line_idx + 1; ++line) + if (line->a != p) + p1->points.push_back(line->a); // we add point instead of p because they might differ because of numerical issues // and caller might want to rely on point belonging to result polylines p1->points.push_back(point); @@ -193,8 +182,7 @@ Polyline::split_at(const Point &point, Polyline* p1, Polyline* p2) const } } -bool -Polyline::is_straight() const +bool Polyline::is_straight() const { /* Check that each segment's direction is equal to the line connecting first point and last point. (Checking each line against the previous @@ -208,19 +196,6 @@ Polyline::is_straight() const return true; } -std::string -Polyline::wkt() const -{ - std::ostringstream wkt; - wkt << "LINESTRING(("; - for (Points::const_iterator p = this->points.begin(); p != this->points.end(); ++p) { - wkt << p->x << " " << p->y; - if (p != this->points.end()-1) wkt << ","; - } - wkt << "))"; - return wkt.str(); -} - BoundingBox get_extents(const Polyline &polyline) { return polyline.bounding_box(); @@ -254,30 +229,17 @@ bool remove_degenerate(Polylines &polylines) return modified; } -ThickLines -ThickPolyline::thicklines() const +ThickLines ThickPolyline::thicklines() const { ThickLines lines; if (this->points.size() >= 2) { lines.reserve(this->points.size() - 1); - for (size_t i = 0; i < this->points.size()-1; ++i) { - ThickLine line(this->points[i], this->points[i+1]); - line.a_width = this->width[2*i]; - line.b_width = this->width[2*i+1]; - lines.push_back(line); - } + for (size_t i = 0; i + 1 < this->points.size(); ++ i) + lines.emplace_back(this->points[i], this->points[i + 1], this->width[2 * i], this->width[2 * i + 1]); } return lines; } -void -ThickPolyline::reverse() -{ - Polyline::reverse(); - std::reverse(this->width.begin(), this->width.end()); - std::swap(this->endpoints.first, this->endpoints.second); -} - Lines3 Polyline3::lines() const { Lines3 lines; diff --git a/xs/src/libslic3r/Polyline.hpp b/xs/src/libslic3r/Polyline.hpp index b64743d84..0c934e074 100644 --- a/xs/src/libslic3r/Polyline.hpp +++ b/xs/src/libslic3r/Polyline.hpp @@ -19,14 +19,15 @@ public: Polyline() {}; Polyline(const Polyline &other) : MultiPoint(other.points) {} Polyline(Polyline &&other) : MultiPoint(std::move(other.points)) {} + Polyline(std::initializer_list<Point> list) : MultiPoint(list) {} + explicit Polyline(const Point &p1, const Point &p2) { points.reserve(2); points.emplace_back(p1); points.emplace_back(p2); } Polyline& operator=(const Polyline &other) { points = other.points; return *this; } Polyline& operator=(Polyline &&other) { points = std::move(other.points); return *this; } - static Polyline new_scale(std::vector<Pointf> points) { + static Polyline new_scale(const std::vector<Vec2d> &points) { Polyline pl; - Points int_points; - for (auto pt : points) - int_points.push_back(Point::new_scale(pt.x, pt.y)); - pl.append(int_points); + pl.points.reserve(points.size()); + for (const Vec2d &pt : points) + pl.points.emplace_back(Point::new_scale(pt(0), pt(1))); return pl; } @@ -71,7 +72,6 @@ public: template <class T> void simplify_by_visibility(const T &area); void split_at(const Point &point, Polyline* p1, Polyline* p2) const; bool is_straight() const; - std::string wkt() const; }; extern BoundingBox get_extents(const Polyline &polyline); @@ -129,12 +129,17 @@ inline void polylines_append(Polylines &dst, Polylines &&src) bool remove_degenerate(Polylines &polylines); class ThickPolyline : public Polyline { - public: - std::vector<coordf_t> width; - std::pair<bool,bool> endpoints; - ThickPolyline() : endpoints(std::make_pair(false, false)) {}; +public: + ThickPolyline() : endpoints(std::make_pair(false, false)) {} ThickLines thicklines() const; - void reverse(); + void reverse() { + Polyline::reverse(); + std::reverse(this->width.begin(), this->width.end()); + std::swap(this->endpoints.first, this->endpoints.second); + } + + std::vector<coordf_t> width; + std::pair<bool,bool> endpoints; }; class Polyline3 : public MultiPoint3 diff --git a/xs/src/libslic3r/PolylineCollection.cpp b/xs/src/libslic3r/PolylineCollection.cpp index ca9c64d23..3f65ea699 100644 --- a/xs/src/libslic3r/PolylineCollection.cpp +++ b/xs/src/libslic3r/PolylineCollection.cpp @@ -15,9 +15,9 @@ inline int nearest_point_index(const std::vector<Chaining> &pairs, const Point & T dmin = std::numeric_limits<T>::max(); int idx = 0; for (std::vector<Chaining>::const_iterator it = pairs.begin(); it != pairs.end(); ++it) { - T d = sqr(T(start_near.x - it->first.x)); + T d = sqr(T(start_near(0) - it->first(0))); if (d <= dmin) { - d += sqr(T(start_near.y - it->first.y)); + d += sqr(T(start_near(1) - it->first(1))); if (d < dmin) { idx = (it - pairs.begin()) * 2; dmin = d; @@ -26,9 +26,9 @@ inline int nearest_point_index(const std::vector<Chaining> &pairs, const Point & } } if (! no_reverse) { - d = sqr(T(start_near.x - it->last.x)); + d = sqr(T(start_near(0) - it->last(0))); if (d <= dmin) { - d += sqr(T(start_near.y - it->last.y)); + d += sqr(T(start_near(1) - it->last(1))); if (d < dmin) { idx = (it - pairs.begin()) * 2 + 1; dmin = d; @@ -82,7 +82,7 @@ Point PolylineCollection::leftmost_point(const Polylines &polylines) Point p = it->leftmost_point(); for (++ it; it != polylines.end(); ++it) { Point p2 = it->leftmost_point(); - if (p2.x < p.x) + if (p2(0) < p(0)) p = p2; } return p; diff --git a/xs/src/libslic3r/Print.cpp b/xs/src/libslic3r/Print.cpp index bd14837d9..aeb034378 100644 --- a/xs/src/libslic3r/Print.cpp +++ b/xs/src/libslic3r/Print.cpp @@ -11,6 +11,10 @@ #include <unordered_set> #include <boost/filesystem.hpp> #include <boost/lexical_cast.hpp> +#include <boost/log/trivial.hpp> + +#include "slic3r/ProgressIndicator.hpp" +#include "PrintExport.hpp" //! macro used to mark string used at localization, //! return same string @@ -538,9 +542,9 @@ bool Print::has_skirt() const std::string Print::validate() const { BoundingBox bed_box_2D = get_extents(Polygon::new_scale(config.bed_shape.values)); - BoundingBoxf3 print_volume(Pointf3(unscale(bed_box_2D.min.x), unscale(bed_box_2D.min.y), 0.0), Pointf3(unscale(bed_box_2D.max.x), unscale(bed_box_2D.max.y), config.max_print_height)); + BoundingBoxf3 print_volume(unscale(bed_box_2D.min(0), bed_box_2D.min(1), 0.0), unscale(bed_box_2D.max(0), bed_box_2D.max(1), scale_(config.max_print_height))); // Allow the objects to protrude below the print bed, only the part of the object above the print bed will be sliced. - print_volume.min.z = -1e10; + print_volume.min(2) = -1e10; unsigned int printable_count = 0; for (PrintObject *po : this->objects) { po->model_object()->check_instances_print_volume_state(print_volume); @@ -585,7 +589,7 @@ std::string Print::validate() const { std::vector<coord_t> object_height; for (const PrintObject *object : this->objects) - object_height.insert(object_height.end(), object->copies().size(), object->size.z); + object_height.insert(object_height.end(), object->copies().size(), object->size(2)); std::sort(object_height.begin(), object_height.end()); // Ignore the tallest *copy* (this is why we repeat height for all of them): // it will be printed as last one so its height doesn't matter. @@ -726,7 +730,7 @@ BoundingBox Print::bounding_box() const for (const PrintObject *object : this->objects) for (Point copy : object->_shifted_copies) { bb.merge(copy); - copy.translate(object->size); + copy += to_2d(object->size); bb.merge(copy); } return bb; @@ -902,7 +906,7 @@ void Print::_make_skirt() for (const Point &shift : object->_shifted_copies) { Points copy_points = object_points; for (Point &pt : copy_points) - pt.translate(shift); + pt += shift; append(points, copy_points); } } @@ -969,7 +973,7 @@ void Print::_make_skirt() this->skirt.append(eloop); if (this->config.min_skirt_length.value > 0) { // The skirt length is limited. Sum the total amount of filament length extruded, in mm. - extruded_length[extruder_idx] += unscale(loop.length()) * extruders_e_per_mm[extruder_idx]; + extruded_length[extruder_idx] += unscale<double>(loop.length()) * extruders_e_per_mm[extruder_idx]; if (extruded_length[extruder_idx] < this->config.min_skirt_length.value) { // Not extruded enough yet with the current extruder. Add another loop. if (i == 1) @@ -1054,7 +1058,7 @@ void Print::_make_wipe_tower() m_wipe_tower_depth = 0.f; // Get wiping matrix to get number of extruders and convert vector<double> to vector<float>: - std::vector<float> wiping_matrix((this->config.wiping_volumes_matrix.values).begin(),(this->config.wiping_volumes_matrix.values).end()); + std::vector<float> wiping_matrix(cast<float>(this->config.wiping_volumes_matrix.values)); // Extract purging volumes for each extruder pair: std::vector<std::vector<float>> wipe_volumes; const unsigned int number_of_extruders = (unsigned int)(sqrt(wiping_matrix.size())+EPSILON); @@ -1230,7 +1234,22 @@ std::string Print::output_filepath(const std::string &path) void Print::set_status(int percent, const std::string &message) { - printf("Print::status %d => %s\n", percent, message.c_str()); + if(progressindicator) progressindicator->update(unsigned(percent), message); + else { + printf("Print::status %d => %s\n", percent, message.c_str()); + std::cout.flush(); + } +} + +void Print::print_to_png(std::string dirpath) { + print_to<FilePrinterFormat::PNG>(*this, + dirpath, + float(this->config.bed_size_x.value), + float(this->config.bed_size_y.value), + int(this->config.pixel_width.value), + int(this->config.pixel_height.value), + float(this->config.exp_time.value), + float(this->config.exp_time_first.value)); } // Returns extruder this eec should be printed with, according to PrintRegion config diff --git a/xs/src/libslic3r/Print.hpp b/xs/src/libslic3r/Print.hpp index e3430ad0e..86dca2e26 100644 --- a/xs/src/libslic3r/Print.hpp +++ b/xs/src/libslic3r/Print.hpp @@ -118,7 +118,7 @@ public: // so that next call to make_perimeters() performs a union() before computing loops bool typed_slices; - Point3 size; // XYZ in scaled coordinates + Vec3crd size; // XYZ in scaled coordinates // scaled coordinates to add to copies (to compensate for the alignment // operated when creating the object but still preserving a coherent API @@ -138,13 +138,13 @@ public: const ModelObject* model_object() const { return this->_model_object; } const Points& copies() const { return this->_copies; } - bool add_copy(const Pointf &point); + bool add_copy(const Vec2d &point); bool delete_last_copy(); bool delete_all_copies() { return this->set_copies(Points()); } bool set_copies(const Points &points); bool reload_model_instances(); // since the object is aligned to origin, bounding box coincides with size - BoundingBox bounding_box() const { return BoundingBox(Point(0,0), this->size); } + BoundingBox bounding_box() const { return BoundingBox(Point(0,0), to_2d(this->size)); } // adds region_id, too, if necessary void add_region_volume(unsigned int region_id, int volume_id) { @@ -227,6 +227,9 @@ private: typedef std::vector<PrintObject*> PrintObjectPtrs; typedef std::vector<PrintRegion*> PrintRegionPtrs; +class ProgressIndicator; +using ProgressIndicatorPtr = std::shared_ptr<ProgressIndicator>; + // The complete print tray with possibly multiple objects. class Print { @@ -237,7 +240,10 @@ public: PrintObjectPtrs objects; PrintRegionPtrs regions; PlaceholderParser placeholder_parser; + // TODO: status_cb + ProgressIndicatorPtr progressindicator; + std::string estimated_normal_print_time; std::string estimated_silent_print_time; double total_used_filament, total_extruded_volume, total_cost, total_weight; @@ -322,8 +328,10 @@ public: // Has the calculation been canceled? bool canceled() { return m_canceled; } + void print_to_png(std::string dirpath); private: + bool invalidate_state_by_config_options(const std::vector<t_config_option_key> &opt_keys); PrintRegionConfig _region_config_from_model_volume(const ModelVolume &volume); diff --git a/xs/src/libslic3r/PrintConfig.cpp b/xs/src/libslic3r/PrintConfig.cpp index f9f0b2056..a3e84a356 100644 --- a/xs/src/libslic3r/PrintConfig.cpp +++ b/xs/src/libslic3r/PrintConfig.cpp @@ -18,8 +18,50 @@ namespace Slic3r { PrintConfigDef::PrintConfigDef() { + this->init_common_params(); + this->init_fff_params(); + this->init_sla_params(); +} + +void PrintConfigDef::init_common_params() +{ t_optiondef_map &Options = this->options; + ConfigOptionDef* def; + + def = this->add("printer_technology", coEnum); + def->label = L("Printer technology"); + def->tooltip = L("Printer technology"); + def->cli = "printer-technology=s"; + def->enum_keys_map = &ConfigOptionEnum<PrinterTechnology>::get_enum_values(); + def->enum_values.push_back("FFF"); + def->enum_values.push_back("SLA"); + def->default_value = new ConfigOptionEnum<PrinterTechnology>(ptFFF); + + def = this->add("bed_shape", coPoints); + def->label = L("Bed shape"); + def->default_value = new ConfigOptionPoints{ Vec2d(0, 0), Vec2d(200, 0), Vec2d(200, 200), Vec2d(0, 200) }; + def = this->add("layer_height", coFloat); + def->label = L("Layer height"); + def->category = L("Layers and Perimeters"); + def->tooltip = L("This setting controls the height (and thus the total number) of the slices/layers. " + "Thinner layers give better accuracy but take more time to print."); + def->sidetext = L("mm"); + def->cli = "layer-height=f"; + def->min = 0; + def->default_value = new ConfigOptionFloat(0.3); + + def = this->add("max_print_height", coFloat); + def->label = L("Max print height"); + def->tooltip = L("Set this to the maximum height that can be reached by your extruder while printing."); + def->sidetext = L("mm"); + def->cli = "max-print-height=f"; + def->default_value = new ConfigOptionFloat(200.0); +} + +void PrintConfigDef::init_fff_params() +{ + t_optiondef_map &Options = this->options; ConfigOptionDef* def; // Maximum extruder temperature, bumped to 1500 to support printing of glass. @@ -33,10 +75,6 @@ PrintConfigDef::PrintConfigDef() def->cli = "avoid-crossing-perimeters!"; def->default_value = new ConfigOptionBool(false); - def = this->add("bed_shape", coPoints); - def->label = L("Bed shape"); - def->default_value = new ConfigOptionPoints { Pointf(0,0), Pointf(200,0), Pointf(200,200), Pointf(0,200) }; - def = this->add("bed_temperature", coInts); def->label = L("Other layers"); def->tooltip = L("Bed temperature for layers after the first one. " @@ -392,7 +430,7 @@ PrintConfigDef::PrintConfigDef() "from the XY coordinate)."); def->sidetext = L("mm"); def->cli = "extruder-offset=s@"; - def->default_value = new ConfigOptionPoints { Pointf(0,0) }; + def->default_value = new ConfigOptionPoints { Vec2d(0,0) }; def = this->add("extrusion_axis", coString); def->label = L("Extrusion axis"); @@ -922,16 +960,6 @@ PrintConfigDef::PrintConfigDef() def->height = 50; def->default_value = new ConfigOptionString(""); - def = this->add("layer_height", coFloat); - def->label = L("Layer height"); - def->category = L("Layers and Perimeters"); - def->tooltip = L("This setting controls the height (and thus the total number) of the slices/layers. " - "Thinner layers give better accuracy but take more time to print."); - def->sidetext = L("mm"); - def->cli = "layer-height=f"; - def->min = 0; - def->default_value = new ConfigOptionFloat(0.3); - def = this->add("remaining_times", coBool); def->label = L("Supports remaining times"); def->tooltip = L("Emit M73 P[percent printed] R[remaining time in minutes] at 1 minute" @@ -1052,13 +1080,6 @@ PrintConfigDef::PrintConfigDef() def->min = 0; def->default_value = new ConfigOptionFloats { 0. }; - def = this->add("max_print_height", coFloat); - def->label = L("Max print height"); - def->tooltip = L("Set this to the maximum height that can be reached by your extruder while printing."); - def->sidetext = L("mm"); - def->cli = "max-print-height=f"; - def->default_value = new ConfigOptionFloat(200.0); - def = this->add("max_print_speed", coFloat); def->label = L("Max print speed"); def->tooltip = L("When setting other speed settings to 0 Slic3r will autocalculate the optimal speed " @@ -2101,6 +2122,149 @@ PrintConfigDef::PrintConfigDef() def->sidetext = L("mm"); def->cli = "z-offset=f"; def->default_value = new ConfigOptionFloat(0); + + def = this->add("bed_size_x", coFloat); + def->label = L("Bed size X"); + def->category = L("Dwarf"); + def->sidetext = L("mm"); + def->cli = "bed-size-x=f"; + def->default_value = new ConfigOptionFloat(68.); + + def = this->add("bed_size_y", coFloat); + def->label = L("Bed size Y"); + def->category = L("Dwarf"); + def->sidetext = L("mm"); + def->cli = "bed-size-y=f"; + def->default_value = new ConfigOptionFloat(120.); + + def = this->add("pixel_width", coInt); + def->label = L("Picture resolution X"); + def->category = L("Dwarf"); + def->sidetext = L("px"); + def->cli = "pixel-width=i"; + def->min = 1; + def->default_value = new ConfigOptionInt(1440); + + def = this->add("pixel_height", coInt); + def->label = L("Picture resolution Y"); + def->category = L("Dwarf"); + def->sidetext = L("px"); + def->cli = "pixel-height=i"; + def->min = 1; + def->default_value = new ConfigOptionInt(2560); + + def = this->add("exp_time", coFloat); + def->label = L("Exposure time"); + def->category = L("Dwarf"); + def->sidetext = L("s"); + def->cli = "exp-time=f"; + def->min = 1; + def->default_value = new ConfigOptionFloat(8.); + + def = this->add("exp_time_first", coFloat); + def->label = L("Exposure time first layers"); + def->category = L("Dwarf"); + def->sidetext = L("s"); + def->cli = "exp-time-first=f"; + def->min = 1; + def->default_value = new ConfigOptionFloat(35.); +} + +void PrintConfigDef::init_sla_params() +{ + t_optiondef_map &Options = this->options; + ConfigOptionDef* def; + + // SLA Printer settings + def = this->add("display_width", coFloat); + def->label = L("Display width"); + def->tooltip = L("Width of the display"); + def->cli = "display-width=f"; + def->min = 1; + def->default_value = new ConfigOptionFloat(150.); + + def = this->add("display_height", coFloat); + def->label = L("Display height"); + def->tooltip = L("Height of the display"); + def->cli = "display-height=f"; + def->min = 1; + def->default_value = new ConfigOptionFloat(100.); + + def = this->add("display_pixels_x", coInt); + def->full_label = L("Number of pixels in"); + def->label = ("X"); + def->tooltip = L("Number of pixels in X"); + def->cli = "display-pixels-x=i"; + def->min = 100; + def->default_value = new ConfigOptionInt(2000); + + def = this->add("display_pixels_y", coInt); + def->label = ("Y"); + def->tooltip = L("Number of pixels in Y"); + def->cli = "display-pixels-y=i"; + def->min = 100; + def->default_value = new ConfigOptionInt(1000); + + def = this->add("printer_correction", coFloats); + def->full_label = L("Printer scaling correction"); + def->tooltip = L("Printer scaling correction"); + def->min = 0; + def->default_value = new ConfigOptionFloats( { 1., 1., 1. } ); + + // SLA Material settings. + def = this->add("initial_layer_height", coFloat); + def->label = L("Initial layer height"); + def->tooltip = L("Initial layer height"); + def->sidetext = L("mm"); + def->cli = "initial-layer-height=f"; + def->min = 0; + def->default_value = new ConfigOptionFloat(0.3); + + def = this->add("exposure_time", coFloat); + def->label = L("Exposure time"); + def->tooltip = L("Exposure time"); + def->sidetext = L("s"); + def->cli = "exposure-time=f"; + def->min = 0; + def->default_value = new ConfigOptionFloat(10); + + def = this->add("initial_exposure_time", coFloat); + def->label = L("Initial exposure time"); + def->tooltip = L("Initial exposure time"); + def->sidetext = L("s"); + def->cli = "initial-exposure-time=f"; + def->min = 0; + def->default_value = new ConfigOptionFloat(15); + + def = this->add("material_correction_printing", coFloats); + def->full_label = L("Correction for expansion when printing"); + def->tooltip = L("Correction for expansion when printing"); + def->min = 0; + def->default_value = new ConfigOptionFloats( { 1. , 1., 1. } ); + + def = this->add("material_correction_curing", coFloats); + def->full_label = L("Correction for expansion after curing"); + def->tooltip = L("Correction for expansion after curing"); + def->min = 0; + def->default_value = new ConfigOptionFloats( { 1. , 1., 1. } ); + + def = this->add("material_notes", coString); + def->label = L("SLA print material notes"); + def->tooltip = L("You can put your notes regarding the SLA print material here."); + def->cli = "material-notes=s"; + def->multiline = true; + def->full_width = true; + def->height = 130; + def->default_value = new ConfigOptionString(""); + + def = this->add("default_sla_material_profile", coString); + def->label = L("Default SLA material profile"); + def->tooltip = L("Default print profile associated with the current printer profile. " + "On selection of the current printer profile, this print profile will be activated."); + def->default_value = new ConfigOptionString(); + + def = this->add("sla_material_settings_id", coString); + def->default_value = new ConfigOptionString(""); } void PrintConfigDef::handle_legacy(t_config_option_key &opt_key, std::string &value) @@ -2133,7 +2297,7 @@ void PrintConfigDef::handle_legacy(t_config_option_key &opt_key, std::string &va ConfigOptionPoint p; p.deserialize(value); std::ostringstream oss; - oss << "0x0," << p.value.x << "x0," << p.value.x << "x" << p.value.y << ",0x" << p.value.y; + oss << "0x0," << p.value(0) << "x0," << p.value(0) << "x" << p.value(1) << ",0x" << p.value(1); value = oss.str(); } else if ((opt_key == "perimeter_acceleration" && value == "25") || (opt_key == "infill_acceleration" && value == "50")) { @@ -2426,4 +2590,8 @@ StaticPrintConfig::StaticCache<class Slic3r::PrintConfig> PrintConfig::s_c StaticPrintConfig::StaticCache<class Slic3r::HostConfig> HostConfig::s_cache_HostConfig; StaticPrintConfig::StaticCache<class Slic3r::FullPrintConfig> FullPrintConfig::s_cache_FullPrintConfig; +StaticPrintConfig::StaticCache<class Slic3r::SLAMaterialConfig> SLAMaterialConfig::s_cache_SLAMaterialConfig; +StaticPrintConfig::StaticCache<class Slic3r::SLAPrinterConfig> SLAPrinterConfig::s_cache_SLAPrinterConfig; +StaticPrintConfig::StaticCache<class Slic3r::SLAFullPrintConfig> SLAFullPrintConfig::s_cache_SLAFullPrintConfig; + } diff --git a/xs/src/libslic3r/PrintConfig.hpp b/xs/src/libslic3r/PrintConfig.hpp index 932ed6054..5bc99a51a 100644 --- a/xs/src/libslic3r/PrintConfig.hpp +++ b/xs/src/libslic3r/PrintConfig.hpp @@ -22,6 +22,14 @@ namespace Slic3r { +enum PrinterTechnology +{ + // Fused Filament Fabrication + ptFFF, + // Stereolitography + ptSLA, +}; + enum GCodeFlavor { gcfRepRap, gcfRepetier, gcfTeacup, gcfMakerWare, gcfMarlin, gcfSailfish, gcfMach3, gcfMachinekit, gcfSmoothie, gcfNoExtrusion, @@ -48,7 +56,16 @@ enum FilamentType { ftPLA, ftABS, ftPET, ftHIPS, ftFLEX, ftSCAFF, ftEDGE, ftNGEN, ftPVA }; -template<> inline t_config_enum_values& ConfigOptionEnum<GCodeFlavor>::get_enum_values() { +template<> inline const t_config_enum_values& ConfigOptionEnum<PrinterTechnology>::get_enum_values() { + static t_config_enum_values keys_map; + if (keys_map.empty()) { + keys_map["FFF"] = ptFFF; + keys_map["SLA"] = ptSLA; + } + return keys_map; +} + +template<> inline const t_config_enum_values& ConfigOptionEnum<GCodeFlavor>::get_enum_values() { static t_config_enum_values keys_map; if (keys_map.empty()) { keys_map["reprap"] = gcfRepRap; @@ -65,7 +82,7 @@ template<> inline t_config_enum_values& ConfigOptionEnum<GCodeFlavor>::get_enum_ return keys_map; } -template<> inline t_config_enum_values& ConfigOptionEnum<PrintHostType>::get_enum_values() { +template<> inline const t_config_enum_values& ConfigOptionEnum<PrintHostType>::get_enum_values() { static t_config_enum_values keys_map; if (keys_map.empty()) { keys_map["octoprint"] = htOctoPrint; @@ -74,7 +91,7 @@ template<> inline t_config_enum_values& ConfigOptionEnum<PrintHostType>::get_enu return keys_map; } -template<> inline t_config_enum_values& ConfigOptionEnum<InfillPattern>::get_enum_values() { +template<> inline const t_config_enum_values& ConfigOptionEnum<InfillPattern>::get_enum_values() { static t_config_enum_values keys_map; if (keys_map.empty()) { keys_map["rectilinear"] = ipRectilinear; @@ -94,7 +111,7 @@ template<> inline t_config_enum_values& ConfigOptionEnum<InfillPattern>::get_enu return keys_map; } -template<> inline t_config_enum_values& ConfigOptionEnum<SupportMaterialPattern>::get_enum_values() { +template<> inline const t_config_enum_values& ConfigOptionEnum<SupportMaterialPattern>::get_enum_values() { static t_config_enum_values keys_map; if (keys_map.empty()) { keys_map["rectilinear"] = smpRectilinear; @@ -104,7 +121,7 @@ template<> inline t_config_enum_values& ConfigOptionEnum<SupportMaterialPattern> return keys_map; } -template<> inline t_config_enum_values& ConfigOptionEnum<SeamPosition>::get_enum_values() { +template<> inline const t_config_enum_values& ConfigOptionEnum<SeamPosition>::get_enum_values() { static t_config_enum_values keys_map; if (keys_map.empty()) { keys_map["random"] = spRandom; @@ -115,7 +132,7 @@ template<> inline t_config_enum_values& ConfigOptionEnum<SeamPosition>::get_enum return keys_map; } -template<> inline t_config_enum_values& ConfigOptionEnum<FilamentType>::get_enum_values() { +template<> inline const t_config_enum_values& ConfigOptionEnum<FilamentType>::get_enum_values() { static t_config_enum_values keys_map; if (keys_map.empty()) { keys_map["PLA"] = ftPLA; @@ -139,6 +156,11 @@ public: PrintConfigDef(); static void handle_legacy(t_config_option_key &opt_key, std::string &value); + +private: + void init_common_params(); + void init_fff_params(); + void init_sla_params(); }; // The one and only global definition of SLic3r configuration options. @@ -728,6 +750,12 @@ public: ConfigOptionFloats wiping_volumes_matrix; ConfigOptionFloats wiping_volumes_extruders; ConfigOptionFloat z_offset; + ConfigOptionFloat bed_size_x; + ConfigOptionFloat bed_size_y; + ConfigOptionInt pixel_width; + ConfigOptionInt pixel_height; + ConfigOptionFloat exp_time; + ConfigOptionFloat exp_time_first; protected: PrintConfig(int) : GCodeConfig(1) {} @@ -799,6 +827,12 @@ protected: OPT_PTR(wiping_volumes_matrix); OPT_PTR(wiping_volumes_extruders); OPT_PTR(z_offset); + OPT_PTR(bed_size_x); + OPT_PTR(bed_size_y); + OPT_PTR(pixel_width); + OPT_PTR(pixel_height); + OPT_PTR(exp_time); + OPT_PTR(exp_time_first); } }; @@ -851,6 +885,73 @@ protected: } }; +class SLAMaterialConfig : public StaticPrintConfig +{ + STATIC_PRINT_CONFIG_CACHE(SLAMaterialConfig) +public: + ConfigOptionFloat layer_height; + ConfigOptionFloat initial_layer_height; + ConfigOptionFloat exposure_time; + ConfigOptionFloat initial_exposure_time; + ConfigOptionFloats material_correction_printing; + ConfigOptionFloats material_correction_curing; +protected: + void initialize(StaticCacheBase &cache, const char *base_ptr) + { + OPT_PTR(layer_height); + OPT_PTR(initial_layer_height); + OPT_PTR(exposure_time); + OPT_PTR(initial_exposure_time); + OPT_PTR(material_correction_printing); + OPT_PTR(material_correction_curing); + } +}; + +class SLAPrinterConfig : public StaticPrintConfig +{ + STATIC_PRINT_CONFIG_CACHE(SLAPrinterConfig) +public: + ConfigOptionEnum<PrinterTechnology> printer_technology; + ConfigOptionPoints bed_shape; + ConfigOptionFloat max_print_height; + ConfigOptionFloat display_width; + ConfigOptionFloat display_height; + ConfigOptionInt display_pixels_x; + ConfigOptionInt display_pixels_y; + ConfigOptionFloats printer_correction; +protected: + void initialize(StaticCacheBase &cache, const char *base_ptr) + { + OPT_PTR(printer_technology); + OPT_PTR(bed_shape); + OPT_PTR(max_print_height); + OPT_PTR(display_width); + OPT_PTR(display_height); + OPT_PTR(display_pixels_x); + OPT_PTR(display_pixels_y); + OPT_PTR(printer_correction); + } +}; + +class SLAFullPrintConfig : public SLAPrinterConfig, public SLAMaterialConfig +{ + STATIC_PRINT_CONFIG_CACHE_DERIVED(SLAFullPrintConfig) + SLAFullPrintConfig() : SLAPrinterConfig(0), SLAMaterialConfig(0) { initialize_cache(); *this = s_cache_SLAFullPrintConfig.defaults(); } + +public: + // Validate the SLAFullPrintConfig. Returns an empty string on success, otherwise an error message is returned. +// std::string validate(); + +protected: + // Protected constructor to be called to initialize ConfigCache::m_default. + SLAFullPrintConfig(int) : SLAPrinterConfig(0), SLAMaterialConfig(0) {} + void initialize(StaticCacheBase &cache, const char *base_ptr) + { + this->SLAPrinterConfig ::initialize(cache, base_ptr); + this->SLAMaterialConfig::initialize(cache, base_ptr); + } +}; + #undef STATIC_PRINT_CONFIG_CACHE #undef STATIC_PRINT_CONFIG_CACHE_BASE #undef STATIC_PRINT_CONFIG_CACHE_DERIVED diff --git a/xs/src/libslic3r/PrintExport.hpp b/xs/src/libslic3r/PrintExport.hpp new file mode 100644 index 000000000..caaec26b2 --- /dev/null +++ b/xs/src/libslic3r/PrintExport.hpp @@ -0,0 +1,389 @@ +#ifndef PRINTEXPORT_HPP +#define PRINTEXPORT_HPP + +#include "Print.hpp" + +// For png export of the sliced model +#include <fstream> +#include <sstream> + +#include <wx/stdstream.h> +#include <wx/wfstream.h> +#include <wx/zipstrm.h> + +#include <boost/log/trivial.hpp> + +#include "Rasterizer/Rasterizer.hpp" +#include <tbb/parallel_for.h> +#include <tbb/spin_mutex.h>//#include "tbb/mutex.h" + +namespace Slic3r { + +enum class FilePrinterFormat { + PNG, + SVG +}; + +/* + * Interface for a file printer of the slices. Implementation can be an SVG + * or PNG printer or any other format. + * + * The format argument specifies the output format of the printer and it enables + * different implementations of this class template for each supported format. + * + */ +template<FilePrinterFormat format> +class FilePrinter { +public: + + void printConfig(const Print&); + + // Draw an ExPolygon which is a polygon inside a slice on the specified layer. + void drawPolygon(const ExPolygon& p, unsigned lyr); + + // Tell the printer how many layers should it consider. + void layers(unsigned layernum); + + // Get the number of layers in the print. + unsigned layers() const; + + /* Switch to a particular layer. If there where less layers then the + * specified layer number than an appropriate number of layers will be + * allocated in the printer. + */ + void beginLayer(unsigned layer); + + // Allocate a new layer on top of the last and switch to it. + void beginLayer(); + + /* + * Finish the selected layer. It means that no drawing is allowed on that + * layer anymore. This fact can be used to prepare the file system output + * data like png comprimation and so on. + */ + void finishLayer(unsigned layer); + + // Finish the top layer. + void finishLayer(); + + // Save all the layers into the file (or dir) specified in the path argument + void save(const std::string& path); + + // Save only the selected layer to the file specified in path argument. + void saveLayer(unsigned lyr, const std::string& path); +}; + +// Implementation for PNG raster output +// Be aware that if a large number of layers are allocated, it can very well +// exhaust the available memory especially on 32 bit platform. +template<> class FilePrinter<FilePrinterFormat::PNG> { + + struct Layer { + Raster first; + std::stringstream second; + + Layer() {} + + Layer(const Layer&) = delete; + Layer(Layer&& m): + first(std::move(m.first))/*, second(std::move(m.second))*/ {} + }; + + // We will save the compressed PNG data into stringstreams which can be done + // in parallel. Later we can write every layer to the disk sequentially. + std::vector<Layer> layers_rst_; + Raster::Resolution res_; + Raster::PixelDim pxdim_; + const Print *print_ = nullptr; + double exp_time_s_ = .0, exp_time_first_s_ = .0; + + std::string createIniContent(const std::string& projectname) { + double layer_height = print_? + print_->default_object_config.layer_height.getFloat() : + 0.05; + + using std::string; + using std::to_string; + + auto expt_str = to_string(exp_time_s_); + auto expt_first_str = to_string(exp_time_first_s_); + auto stepnum_str = to_string(static_cast<unsigned>(800*layer_height)); + auto layerh_str = to_string(layer_height); + + return string( + "action = print\n" + "jobDir = ") + projectname + "\n" + + "expTime = " + expt_str + "\n" + "expTimeFirst = " + expt_first_str + "\n" + "stepNum = " + stepnum_str + "\n" + "wifiOn = 1\n" + "tiltSlow = 60\n" + "tiltFast = 15\n" + "numFade = 10\n" + "startdelay = 0\n" + "layerHeight = " + layerh_str + "\n" + "noteInfo = " + "expTime="+expt_str+"+resinType=generic+layerHeight=" + +layerh_str+"+printer=DWARF3\n"; + } + + // Change this to TOP_LEFT if you want correct PNG orientation + static const Raster::Origin ORIGIN = Raster::Origin::BOTTOM_LEFT; + +public: + inline FilePrinter(double width_mm, double height_mm, + unsigned width_px, unsigned height_px, + double exp_time, double exp_time_first): + res_(width_px, height_px), + pxdim_(width_mm/width_px, height_mm/height_px), + exp_time_s_(exp_time), + exp_time_first_s_(exp_time_first) + { + } + + FilePrinter(const FilePrinter& ) = delete; + FilePrinter(FilePrinter&& m): + layers_rst_(std::move(m.layers_rst_)), + res_(m.res_), + pxdim_(m.pxdim_) {} + + inline void layers(unsigned cnt) { if(cnt > 0) layers_rst_.resize(cnt); } + inline unsigned layers() const { return layers_rst_.size(); } + + void printConfig(const Print& printconf) { print_ = &printconf; } + + inline void drawPolygon(const ExPolygon& p, unsigned lyr) { + assert(lyr < layers_rst_.size()); + layers_rst_[lyr].first.draw(p); + } + + inline void beginLayer(unsigned lyr) { + if(layers_rst_.size() <= lyr) layers_rst_.resize(lyr+1); + layers_rst_[lyr].first.reset(res_, pxdim_, ORIGIN); + } + + inline void beginLayer() { + layers_rst_.emplace_back(); + layers_rst_.front().first.reset(res_, pxdim_, ORIGIN); + } + + inline void finishLayer(unsigned lyr_id) { + assert(lyr_id < layers_rst_.size()); + layers_rst_[lyr_id].first.save(layers_rst_[lyr_id].second, + Raster::Compression::PNG); + layers_rst_[lyr_id].first.reset(); + } + + inline void finishLayer() { + if(!layers_rst_.empty()) { + layers_rst_.back().first.save(layers_rst_.back().second, + Raster::Compression::PNG); + layers_rst_.back().first.reset(); + } + } + + inline void save(const std::string& path) { + + wxFileName filepath(path); + + wxFFileOutputStream zipfile(path); + + std::string project = filepath.GetName().ToStdString(); + + if(!zipfile.IsOk()) { + BOOST_LOG_TRIVIAL(error) << "Can't create zip file for layers! " + << path; + return; + } + + wxZipOutputStream zipstream(zipfile); + wxStdOutputStream pngstream(zipstream); + + zipstream.PutNextEntry("config.ini"); + pngstream << createIniContent(project); + + for(unsigned i = 0; i < layers_rst_.size(); i++) { + if(layers_rst_[i].second.rdbuf()->in_avail() > 0) { + char lyrnum[6]; + std::sprintf(lyrnum, "%.5d", i); + auto zfilename = project + lyrnum + ".png"; + zipstream.PutNextEntry(zfilename); + pngstream << layers_rst_[i].second.rdbuf(); + layers_rst_[i].second.str(""); + } + } + + zipstream.Close(); + zipfile.Close(); + } + + void saveLayer(unsigned lyr, const std::string& path) { + unsigned i = lyr; + assert(i < layers_rst_.size()); + + char lyrnum[6]; + std::sprintf(lyrnum, "%.5d", lyr); + std::string loc = path + "layer" + lyrnum + ".png"; + + std::fstream out(loc, std::fstream::out | std::fstream::binary); + if(out.good()) { + layers_rst_[i].first.save(out, Raster::Compression::PNG); + } else { + BOOST_LOG_TRIVIAL(error) << "Can't create file for layer"; + } + + out.close(); + layers_rst_[i].first.reset(); + } +}; + +// Let's shadow this eigen interface +inline coord_t px(const Point& p) { return p(0); } +inline coord_t py(const Point& p) { return p(1); } +inline coordf_t px(const Vec2d& p) { return p(0); } +inline coordf_t py(const Vec2d& p) { return p(1); } + +template<FilePrinterFormat format, class...Args> +void print_to(Print& print, + std::string dirpath, + double width_mm, + double height_mm, + Args&&...args) +{ + + std::string& dir = dirpath; + + // This map will hold the layers sorted by z coordinate. Layers on the + // same height (from different objects) will be mapped to the same key and + // rasterized to the same image. + std::map<long long, LayerPtrs> layers; + + auto& objects = print.objects; + + // Merge the sliced layers with the support layers + std::for_each(objects.begin(), objects.end(), [&layers](PrintObject *o) { + for(auto l : o->layers) { + auto& lyrs = layers[static_cast<long long>(scale_(l->print_z))]; + lyrs.push_back(l); + } + + for(auto l : o->support_layers) { + auto& lyrs = layers[static_cast<long long>(scale_(l->print_z))]; + lyrs.push_back(l); + } + }); + + auto print_bb = print.bounding_box(); + Vec2d punsc = unscale(print_bb.size()); + + // If the print does not fit into the print area we should cry about it. + if(px(punsc) > width_mm || py(punsc) > height_mm) { + BOOST_LOG_TRIVIAL(warning) << "Warning: Print will not fit!" << "\n" + << "Width needed: " << px(punsc) << "\n" + << "Height needed: " << py(punsc) << "\n"; + } + + // Offset for centering the print onto the print area + auto cx = scale_(width_mm)/2 - (px(print_bb.center()) - px(print_bb.min)); + auto cy = scale_(height_mm)/2 - (py(print_bb.center()) - py(print_bb.min)); + + // Create the actual printer, forward any additional arguments to it. + FilePrinter<format> printer(width_mm, height_mm, + std::forward<Args>(args)...); + + printer.printConfig(print); + + printer.layers(layers.size()); // Allocate space for all the layers + + int st_prev = 0; + const std::string jobdesc = "Rasterizing and compressing sliced layers"; + tbb::spin_mutex m; + + std::vector<long long> keys; + keys.reserve(layers.size()); + for(auto& e : layers) keys.push_back(e.first); + + int initstatus = print.progressindicator? print.progressindicator->state() + : 0; + print.set_status(initstatus, jobdesc); + + // Method that prints one layer + auto process_layer = [&layers, &keys, &printer, &st_prev, &m, + &jobdesc, print_bb, dir, cx, cy, &print, initstatus] + (unsigned layer_id) + { + LayerPtrs lrange = layers[keys[layer_id]]; + + printer.beginLayer(layer_id); // Switch to the appropriate layer + + for(Layer *lp : lrange) { + Layer& l = *lp; + + ExPolygonCollection slices = l.slices; // Copy the layer slices + + // Sort the polygons in the layer + std::stable_sort(slices.expolygons.begin(), slices.expolygons.end(), + [](const ExPolygon& a, const ExPolygon& b) { + return a.contour.contains(b.contour.first_point()) ? false : + true; + }); + + // Draw all the polygons in the slice to the actual layer. + std::for_each(l.object()->_shifted_copies.begin(), + l.object()->_shifted_copies.end(), + [&] (Point d) + { + std::for_each(slices.expolygons.begin(), + slices.expolygons.end(), + [&] (ExPolygon slice) + { + slice.translate(px(d), py(d)); + slice.translate(-px(print_bb.min) + cx, + -py(print_bb.min) + cy); + + printer.drawPolygon(slice, layer_id); + }); + }); + + /*if(print.has_support_material() && layer_id > 0) { + BOOST_LOG_TRIVIAL(warning) << "support material for layer " + << layer_id + << " defined but export is " + "not yet implemented."; + + }*/ + + } + + printer.finishLayer(layer_id); // Finish the layer for later saving it. + + auto st = static_cast<int>(layer_id*80.0/layers.size()); + m.lock(); + if( st - st_prev > 10) { + print.set_status(initstatus + st, jobdesc); + st_prev = st; + } + m.unlock(); + + // printer.saveLayer(layer_id, dir); We could save the layer immediately + }; + + // Print all the layers in parallel + tbb::parallel_for<size_t, decltype(process_layer)>(0, + layers.size(), + process_layer); + + // Sequential version (for testing) + // for(unsigned l = 0; l < layers.size(); ++l) process_layer(l); + +// print.set_status(100, jobdesc); + + // Save the print into the file system. + print.set_status(initstatus + 90, "Writing layers to disk"); + printer.save(dir); + print.set_status(initstatus + 100, "Writing layers completed"); +} + +} + +#endif // PRINTEXPORT_HPP diff --git a/xs/src/libslic3r/PrintObject.cpp b/xs/src/libslic3r/PrintObject.cpp index 7150ead59..d03b99416 100644 --- a/xs/src/libslic3r/PrintObject.cpp +++ b/xs/src/libslic3r/PrintObject.cpp @@ -38,6 +38,7 @@ PrintObject::PrintObject(Print* print, ModelObject* model_object, const Bounding typed_slices(false), _print(print), _model_object(model_object), + size(Vec3crd::Zero()), layer_height_profile_valid(false) { // Compute the translation to be applied to our meshes so that we work with smaller coordinates @@ -48,10 +49,9 @@ PrintObject::PrintObject(Print* print, ModelObject* model_object, const Bounding // don't assume it's already aligned and we don't alter the original position in model. // We store the XY translation so that we can place copies correctly in the output G-code // (copies are expressed in G-code coordinates and this translation is not publicly exposed). - this->_copies_shift = Point::new_scale(modobj_bbox.min.x, modobj_bbox.min.y); + this->_copies_shift = Point::new_scale(modobj_bbox.min(0), modobj_bbox.min(1)); // Scale the object size and store it - Pointf3 size = modobj_bbox.size(); - this->size = Point3::new_scale(size.x, size.y, size.z); + this->size = (modobj_bbox.size() * (1. / SCALING_FACTOR)).cast<coord_t>(); } this->reload_model_instances(); @@ -59,10 +59,10 @@ PrintObject::PrintObject(Print* print, ModelObject* model_object, const Bounding this->layer_height_profile = model_object->layer_height_profile; } -bool PrintObject::add_copy(const Pointf &point) +bool PrintObject::add_copy(const Vec2d &point) { Points points = this->_copies; - points.push_back(Point::new_scale(point.x, point.y)); + points.push_back(Point::new_scale(point(0), point(1))); return this->set_copies(points); } @@ -86,11 +86,8 @@ bool PrintObject::set_copies(const Points &points) std::vector<Points::size_type> ordered_copies; Slic3r::Geometry::chained_path(points, ordered_copies); - for (size_t point_idx : ordered_copies) { - Point copy = points[point_idx]; - copy.translate(this->_copies_shift); - this->_shifted_copies.push_back(copy); - } + for (size_t point_idx : ordered_copies) + this->_shifted_copies.push_back(points[point_idx] + this->_copies_shift); bool invalidated = this->_print->invalidate_step(psSkirt); invalidated |= this->_print->invalidate_step(psBrim); @@ -106,7 +103,7 @@ bool PrintObject::reload_model_instances() for (const ModelInstance *mi : this->_model_object->instances) { if (mi->is_printable()) - copies.emplace_back(Point::new_scale(mi->offset.x, mi->offset.y)); + copies.emplace_back(Point::new_scale(mi->offset(0), mi->offset(1))); } return this->set_copies(copies); } @@ -1124,7 +1121,7 @@ SlicingParameters PrintObject::slicing_parameters() const { return SlicingParameters::create_from_config( this->print()->config, this->config, - unscale(this->size.z), this->print()->object_extruders()); + unscale<double>(this->size(2)), this->print()->object_extruders()); } bool PrintObject::update_layer_height_profile(std::vector<coordf_t> &layer_height_profile) const @@ -1338,7 +1335,7 @@ std::vector<ExPolygons> PrintObject::_slice_region(size_t region_id, const std:: // consider the first one this->model_object()->instances.front()->transform_mesh(&mesh, true); // align mesh to Z = 0 (it should be already aligned actually) and apply XY shift - mesh.translate(- float(unscale(this->_copies_shift.x)), - float(unscale(this->_copies_shift.y)), -float(this->model_object()->bounding_box().min.z)); + mesh.translate(- unscale<float>(this->_copies_shift(0)), - unscale<float>(this->_copies_shift(1)), - float(this->model_object()->bounding_box().min(2))); // perform actual slicing TriangleMeshSlicer mslicer(&mesh); mslicer.slice(z, &layers); diff --git a/xs/src/libslic3r/Rasterizer/Rasterizer.cpp b/xs/src/libslic3r/Rasterizer/Rasterizer.cpp new file mode 100644 index 000000000..b0bf04343 --- /dev/null +++ b/xs/src/libslic3r/Rasterizer/Rasterizer.cpp @@ -0,0 +1,214 @@ +#include "Rasterizer.hpp" +#include <ExPolygon.hpp> + +#include <cstdint> + +// For rasterizing +#include <agg/agg_basics.h> +#include <agg/agg_rendering_buffer.h> +#include <agg/agg_pixfmt_gray.h> +#include <agg/agg_pixfmt_rgb.h> +#include <agg/agg_renderer_base.h> +#include <agg/agg_renderer_scanline.h> + +#include <agg/agg_scanline_p.h> +#include <agg/agg_rasterizer_scanline_aa.h> +#include <agg/agg_path_storage.h> + +// For png compression +#include <png/writer.hpp> + +namespace Slic3r { + +class Raster::Impl { +public: + using TPixelRenderer = agg::pixfmt_gray8; // agg::pixfmt_rgb24; + using TRawRenderer = agg::renderer_base<TPixelRenderer>; + using TPixel = TPixelRenderer::color_type; + using TRawBuffer = agg::rendering_buffer; + + using TBuffer = std::vector<TPixelRenderer::pixel_type>; + + using TRendererAA = agg::renderer_scanline_aa_solid<TRawRenderer>; + + static const TPixel ColorWhite; + static const TPixel ColorBlack; + + using Origin = Raster::Origin; + +private: + Raster::Resolution resolution_; + Raster::PixelDim pxdim_; + TBuffer buf_; + TRawBuffer rbuf_; + TPixelRenderer pixfmt_; + TRawRenderer raw_renderer_; + TRendererAA renderer_; + Origin o_; + std::function<void(agg::path_storage&)> flipy_ = [](agg::path_storage&) {}; +public: + inline Impl(const Raster::Resolution& res, const Raster::PixelDim &pd, + Origin o): + resolution_(res), pxdim_(pd), + buf_(res.pixels()), + rbuf_(reinterpret_cast<TPixelRenderer::value_type*>(buf_.data()), + res.width_px, res.height_px, + res.width_px*TPixelRenderer::num_components), + pixfmt_(rbuf_), + raw_renderer_(pixfmt_), + renderer_(raw_renderer_), + o_(o) + { + renderer_.color(ColorWhite); + + // If we would like to play around with gamma + // ras.gamma(agg::gamma_power(1.0)); + + clear(); + + if(o_ == Origin::TOP_LEFT) flipy_ = [this](agg::path_storage& path) { + path.flip_y(0, resolution_.height_px); + }; + } + + void draw(const ExPolygon &poly) { + agg::rasterizer_scanline_aa<> ras; + agg::scanline_p8 scanlines; + + auto&& path = to_path(poly.contour); + flipy_(path); + ras.add_path(path); + + for(auto h : poly.holes) { + auto&& holepath = to_path(h); + flipy_(holepath); + ras.add_path(holepath); + } + + agg::render_scanlines(ras, scanlines, renderer_); + } + + inline void clear() { + raw_renderer_.clear(ColorBlack); + } + + inline TBuffer& buffer() { return buf_; } + + inline const Raster::Resolution resolution() { return resolution_; } + + inline Origin origin() const /*noexcept*/ { return o_; } + +private: + double getPx(const Point& p) { + return p(0) * SCALING_FACTOR/pxdim_.w_mm; + } + + double getPy(const Point& p) { + return p(1) * SCALING_FACTOR/pxdim_.h_mm; + } + + agg::path_storage to_path(const Polygon& poly) { + agg::path_storage path; + auto it = poly.points.begin(); + path.move_to(getPx(*it), getPy(*it)); + while(++it != poly.points.end()) + path.line_to(getPx(*it), getPy(*it)); + + path.line_to(getPx(poly.points.front()), getPy(poly.points.front())); + return path; + } + +}; + +const Raster::Impl::TPixel Raster::Impl::ColorWhite = Raster::Impl::TPixel(255); +const Raster::Impl::TPixel Raster::Impl::ColorBlack = Raster::Impl::TPixel(0); + +Raster::Raster(const Resolution &r, const PixelDim &pd, Origin o): + impl_(new Impl(r, pd, o)) {} + +Raster::Raster() {} + +Raster::~Raster() {} + +Raster::Raster(Raster &&m): + impl_(std::move(m.impl_)) {} + +void Raster::reset(const Raster::Resolution &r, const Raster::PixelDim &pd) +{ + // Free up the unnecessary memory and make sure it stays clear after + // an exception + auto o = impl_? impl_->origin() : Origin::TOP_LEFT; + reset(r, pd, o); +} + +void Raster::reset(const Raster::Resolution &r, const Raster::PixelDim &pd, + Raster::Origin o) +{ + impl_.reset(); + impl_.reset(new Impl(r, pd, o)); +} + +void Raster::reset() +{ + impl_.reset(); +} + +Raster::Resolution Raster::resolution() const +{ + if(impl_) return impl_->resolution(); + + return Resolution(0, 0); +} + +void Raster::clear() +{ + assert(impl_); + impl_->clear(); +} + +void Raster::draw(const ExPolygon &poly) +{ + assert(impl_); + impl_->draw(poly); +} + +void Raster::save(std::ostream& stream, Compression comp) +{ + assert(impl_); + switch(comp) { + case Compression::PNG: { + + png::writer<std::ostream> wr(stream); + + wr.set_bit_depth(8); + wr.set_color_type(png::color_type_gray); + wr.set_width(resolution().width_px); + wr.set_height(resolution().height_px); + wr.set_compression_type(png::compression_type_default); + + wr.write_info(); + + auto& b = impl_->buffer(); + auto ptr = reinterpret_cast<png::byte*>( b.data() ); + unsigned stride = + sizeof(Impl::TBuffer::value_type) * resolution().width_px; + + for(unsigned r = 0; r < resolution().height_px; r++, ptr+=stride) { + wr.write_row(ptr); + } + + break; + } + case Compression::RAW: { + stream << "P5 " + << impl_->resolution().width_px << " " + << impl_->resolution().height_px << " " + << "255 "; + + stream.write(reinterpret_cast<const char*>(impl_->buffer().data()), + impl_->buffer().size()*sizeof(Impl::TBuffer::value_type)); + } + } +} + +} diff --git a/xs/src/libslic3r/Rasterizer/Rasterizer.hpp b/xs/src/libslic3r/Rasterizer/Rasterizer.hpp new file mode 100644 index 000000000..cbb39bc6b --- /dev/null +++ b/xs/src/libslic3r/Rasterizer/Rasterizer.hpp @@ -0,0 +1,86 @@ +#ifndef RASTERIZER_HPP +#define RASTERIZER_HPP + +#include <ostream> +#include <memory> + +namespace Slic3r { + +class ExPolygon; + +/** + * @brief Raster captures an anti-aliased monochrome canvas where vectorial + * polygons can be rasterized. Fill color is always white and the background is + * black. Contours are anti-aliased. + * + * It also supports saving the raster data into a standard output stream in raw + * or PNG format. + */ +class Raster { + class Impl; + std::unique_ptr<Impl> impl_; +public: + + /// Supported compression types + enum class Compression { + RAW, //!> Uncompressed pixel data + PNG //!> PNG compression + }; + + enum class Origin { + TOP_LEFT, + BOTTOM_LEFT + }; + + /// Type that represents a resolution in pixels. + struct Resolution { + unsigned width_px; + unsigned height_px; + inline Resolution(unsigned w, unsigned h): width_px(w), height_px(h) {} + inline unsigned pixels() const /*noexcept*/ { + return width_px * height_px; + } + }; + + /// Types that represents the dimension of a pixel in millimeters. + struct PixelDim { + double w_mm; + double h_mm; + inline PixelDim(double px_width_mm, double px_height_mm ): + w_mm(px_width_mm), h_mm(px_height_mm) {} + }; + + /// Constructor taking the resolution and the pixel dimension. + explicit Raster(const Resolution& r, const PixelDim& pd, + Origin o = Origin::BOTTOM_LEFT ); + Raster(); + Raster(const Raster& cpy) = delete; + Raster& operator=(const Raster& cpy) = delete; + Raster(Raster&& m); + ~Raster(); + + /// Reallocated everything for the given resolution and pixel dimension. + void reset(const Resolution& r, const PixelDim& pd); + void reset(const Resolution& r, const PixelDim& pd, Origin o); + + /** + * Release the allocated resources. Drawing in this state ends in + * unspecified behaviour. + */ + void reset(); + + /// Get the resolution of the raster. + Resolution resolution() const; + + /// Clear the raster with black color. + void clear(); + + /// Draw a polygon with holes. + void draw(const ExPolygon& poly); + + /// Save the raster on the specified stream. + void save(std::ostream& stream, Compression comp = Compression::RAW); +}; + +} +#endif // RASTERIZER_HPP diff --git a/xs/src/libslic3r/SLABasePool.cpp b/xs/src/libslic3r/SLABasePool.cpp new file mode 100644 index 000000000..adf43eaf2 --- /dev/null +++ b/xs/src/libslic3r/SLABasePool.cpp @@ -0,0 +1,531 @@ +#include <functional> +#include <numeric> + +#include "SLABasePool.hpp" +#include "ExPolygon.hpp" +#include "TriangleMesh.hpp" +#include "ClipperUtils.hpp" +#include "boost/log/trivial.hpp" + +//#include "SVG.hpp" + +namespace Slic3r { namespace sla { + +namespace { + +using coord_t = Point::coord_type; + +/// get the scaled clipper units for a millimeter value +inline coord_t mm(double v) { return coord_t(v/SCALING_FACTOR); } + +/// Get x and y coordinates (because we are eigenizing...) +inline coord_t x(const Point& p) { return p(0); } +inline coord_t y(const Point& p) { return p(1); } +inline coord_t& x(Point& p) { return p(0); } +inline coord_t& y(Point& p) { return p(1); } + +inline coordf_t x(const Vec3d& p) { return p(0); } +inline coordf_t y(const Vec3d& p) { return p(1); } +inline coordf_t z(const Vec3d& p) { return p(2); } +inline coordf_t& x(Vec3d& p) { return p(0); } +inline coordf_t& y(Vec3d& p) { return p(1); } +inline coordf_t& z(Vec3d& p) { return p(2); } + +inline coord_t& x(Vec3crd& p) { return p(0); } +inline coord_t& y(Vec3crd& p) { return p(1); } +inline coord_t& z(Vec3crd& p) { return p(2); } +inline coord_t x(const Vec3crd& p) { return p(0); } +inline coord_t y(const Vec3crd& p) { return p(1); } +inline coord_t z(const Vec3crd& p) { return p(2); } + +inline void triangulate(const ExPolygon& expoly, Polygons& triangles) { + expoly.triangulate_p2t(&triangles); +} + +inline Polygons triangulate(const ExPolygon& expoly) { + Polygons tri; triangulate(expoly, tri); return tri; +} + +using Indices = std::vector<Vec3crd>; + +/// Intermediate struct for a 3D mesh +struct Contour3D { + Pointf3s points; + Indices indices; + + void merge(const Contour3D& ctr) { + auto s3 = coord_t(points.size()); + auto s = coord_t(indices.size()); + + points.insert(points.end(), ctr.points.begin(), ctr.points.end()); + indices.insert(indices.end(), ctr.indices.begin(), ctr.indices.end()); + + for(auto n = s; n < indices.size(); n++) { + auto& idx = indices[n]; x(idx) += s3; y(idx) += s3; z(idx) += s3; + } + } +}; + +/// Convert the triangulation output to an intermediate mesh. +inline Contour3D convert(const Polygons& triangles, coord_t z, bool dir) { + + Pointf3s points; + points.reserve(3*triangles.size()); + Indices indices; + indices.reserve(points.size()); + + for(auto& tr : triangles) { + auto c = coord_t(points.size()), b = c++, a = c++; + if(dir) indices.emplace_back(a, b, c); + else indices.emplace_back(c, b, a); + for(auto& p : tr.points) { + points.emplace_back(unscale(x(p), y(p), z)); + } + } + + return {points, indices}; +} + +/// Only a debug function to generate top and bottom plates from a 2D shape. +/// It is not used in the algorithm directly. +inline Contour3D roofs(const ExPolygon& poly, coord_t z_distance) { + Polygons triangles = triangulate(poly); + + auto lower = convert(triangles, 0, false); + auto upper = convert(triangles, z_distance, true); + lower.merge(upper); + return lower; +} + +inline Contour3D walls(const ExPolygon& floor_plate, const ExPolygon& ceiling, + double floor_z_mm, double ceiling_z_mm) { + using std::transform; using std::back_inserter; + + ExPolygon poly; + poly.contour.points = floor_plate.contour.points; + poly.holes.emplace_back(ceiling.contour); + auto& h = poly.holes.front(); + std::reverse(h.points.begin(), h.points.end()); + Polygons tri = triangulate(poly); + + Contour3D ret; + ret.points.reserve(tri.size() * 3); + + double fz = floor_z_mm; + double cz = ceiling_z_mm; + auto& rp = ret.points; + auto& rpi = ret.indices; + ret.indices.reserve(tri.size() * 3); + + coord_t idx = 0; + + auto hlines = h.lines(); + auto is_upper = [&hlines](const Point& p) { + return std::any_of(hlines.begin(), hlines.end(), + [&p](const Line& l) { + return l.distance_to(p) < mm(0.01); + }); + }; + + std::for_each(tri.begin(), tri.end(), + [&rp, &rpi, &poly, &idx, is_upper, fz, cz](const Polygon& pp) + { + for(auto& p : pp.points) + if(is_upper(p)) + rp.emplace_back(unscale(x(p), y(p), mm(cz))); + else rp.emplace_back(unscale(x(p), y(p), mm(fz))); + + coord_t a = idx++, b = idx++, c = idx++; + if(fz > cz) rpi.emplace_back(c, b, a); + else rpi.emplace_back(a, b, c); + }); + + return ret; +} + +/// Mesh from an existing contour. +inline TriangleMesh mesh(const Contour3D& ctour) { + return {ctour.points, ctour.indices}; +} + +/// Mesh from an evaporating 3D contour +inline TriangleMesh mesh(Contour3D&& ctour) { + return {std::move(ctour.points), std::move(ctour.indices)}; +} + +/// Offsetting with clipper and smoothing the edges into a curvature. +inline void offset(ExPolygon& sh, coord_t distance) { + using ClipperLib::ClipperOffset; + using ClipperLib::jtRound; + using ClipperLib::etClosedPolygon; + using ClipperLib::Paths; + using ClipperLib::Path; + + auto&& ctour = Slic3rMultiPoint_to_ClipperPath(sh.contour); + auto&& holes = Slic3rMultiPoints_to_ClipperPaths(sh.holes); + + // If the input is not at least a triangle, we can not do this algorithm + if(ctour.size() < 3 || + std::any_of(holes.begin(), holes.end(), + [](const Path& p) { return p.size() < 3; }) + ) { + BOOST_LOG_TRIVIAL(error) << "Invalid geometry for offsetting!"; + return; + } + + ClipperOffset offs; + offs.ArcTolerance = 0.01*mm(1); + Paths result; + offs.AddPath(ctour, jtRound, etClosedPolygon); + offs.AddPaths(holes, jtRound, etClosedPolygon); + offs.Execute(result, static_cast<double>(distance)); + + // Offsetting reverts the orientation and also removes the last vertex + // so boost will not have a closed polygon. + + bool found_the_contour = false; + sh.holes.clear(); + for(auto& r : result) { + if(ClipperLib::Orientation(r)) { + // We don't like if the offsetting generates more than one contour + // but throwing would be an overkill. Instead, we should warn the + // caller about the inability to create correct geometries + if(!found_the_contour) { + auto rr = ClipperPath_to_Slic3rPolygon(r); + sh.contour.points.swap(rr.points); + found_the_contour = true; + } else { + BOOST_LOG_TRIVIAL(warning) + << "Warning: offsetting result is invalid!"; + } + } else { + // TODO If there are multiple contours we can't be sure which hole + // belongs to the first contour. (But in this case the situation is + // bad enough to let it go...) + sh.holes.emplace_back(ClipperPath_to_Slic3rPolygon(r)); + } + } +} + +template<class ExP, class D> +inline Contour3D round_edges(const ExPolygon& base_plate, + double radius_mm, + double degrees, + double ceilheight_mm, + bool dir, + ExP&& last_offset = ExP(), D&& last_height = D()) +{ + auto ob = base_plate; + auto ob_prev = ob; + double wh = ceilheight_mm, wh_prev = wh; + Contour3D curvedwalls; + + const size_t steps = 6; // steps for 180 degrees + degrees = std::fmod(degrees, 180); + const int portion = int(steps*degrees / 90); + const double ystep_mm = radius_mm/steps; + coord_t s = dir? 1 : -1; + double xxprev = 0; + for(int i = 0; i < portion; i++) { + ob = base_plate; + + // The offset is given by the equation: x = sqrt(r^2 - y^2) + // which can be derived from the circle equation. y is the current + // height for which the offset is calculated and x is the offset itself + // r is the radius of the circle that is used to smooth the edges + + double r2 = radius_mm * radius_mm; + double y2 = steps*ystep_mm - i*ystep_mm; + y2 *= y2; + + double xx = sqrt(r2 - y2); + + offset(ob, s*mm(xx)); + wh = ceilheight_mm - i*ystep_mm; + + Contour3D pwalls; + if(xxprev < xx) pwalls = walls(ob, ob_prev, wh, wh_prev); + else pwalls = walls(ob_prev, ob, wh_prev, wh); + + curvedwalls.merge(pwalls); + ob_prev = ob; + wh_prev = wh; + xxprev = xx; + } + + last_offset = std::move(ob); + last_height = wh; + + return curvedwalls; +} + +/// Generating the concave part of the 3D pool with the bottom plate and the +/// side walls. +inline Contour3D inner_bed(const ExPolygon& poly, double depth_mm, + double begin_h_mm = 0) { + + Polygons triangles = triangulate(poly); + + coord_t depth = mm(depth_mm); + coord_t begin_h = mm(begin_h_mm); + + auto bottom = convert(triangles, -depth + begin_h, false); + auto lines = poly.lines(); + + // Generate outer walls + auto fp = [](const Point& p, Point::coord_type z) { + return unscale(x(p), y(p), z); + }; + + for(auto& l : lines) { + auto s = coord_t(bottom.points.size()); + + bottom.points.emplace_back(fp(l.a, -depth + begin_h)); + bottom.points.emplace_back(fp(l.b, -depth + begin_h)); + bottom.points.emplace_back(fp(l.a, begin_h)); + bottom.points.emplace_back(fp(l.b, begin_h)); + + bottom.indices.emplace_back(s + 3, s + 1, s); + bottom.indices.emplace_back(s + 2, s + 3, s); + } + + return bottom; +} + +/// Unification of polygons (with clipper) preserving holes as well. +inline ExPolygons unify(const ExPolygons& shapes) { + using ClipperLib::ptSubject; + + ExPolygons retv; + + bool closed = true; + bool valid = true; + + ClipperLib::Clipper clipper; + + for(auto& path : shapes) { + auto clipperpath = Slic3rMultiPoint_to_ClipperPath(path.contour); + + if(!clipperpath.empty()) + valid &= clipper.AddPath(clipperpath, ptSubject, closed); + + auto clipperholes = Slic3rMultiPoints_to_ClipperPaths(path.holes); + + for(auto& hole : clipperholes) { + if(!hole.empty()) + valid &= clipper.AddPath(hole, ptSubject, closed); + } + } + + if(!valid) BOOST_LOG_TRIVIAL(warning) << "Unification of invalid shapes!"; + + ClipperLib::PolyTree result; + clipper.Execute(ClipperLib::ctUnion, result, ClipperLib::pftNonZero); + + retv.reserve(static_cast<size_t>(result.Total())); + + // Now we will recursively traverse the polygon tree and serialize it + // into an ExPolygon with holes. The polygon tree has the clipper-ish + // PolyTree structure which alternates its nodes as contours and holes + + // A "declaration" of function for traversing leafs which are holes + std::function<void(ClipperLib::PolyNode*, ExPolygon&)> processHole; + + // Process polygon which calls processHoles which than calls processPoly + // again until no leafs are left. + auto processPoly = [&retv, &processHole](ClipperLib::PolyNode *pptr) { + ExPolygon poly; + poly.contour.points = ClipperPath_to_Slic3rPolygon(pptr->Contour); + for(auto h : pptr->Childs) { processHole(h, poly); } + retv.push_back(poly); + }; + + // Body of the processHole function + processHole = [&processPoly](ClipperLib::PolyNode *pptr, ExPolygon& poly) + { + poly.holes.emplace_back(); + poly.holes.back().points = ClipperPath_to_Slic3rPolygon(pptr->Contour); + for(auto c : pptr->Childs) processPoly(c); + }; + + // Wrapper for traversing. + auto traverse = [&processPoly] (ClipperLib::PolyNode *node) + { + for(auto ch : node->Childs) { + processPoly(ch); + } + }; + + // Here is the actual traverse + traverse(&result); + + return retv; +} + +inline Point centroid(Points& pp) { + Point c; + switch(pp.size()) { + case 0: break; + case 1: c = pp.front(); break; + case 2: c = (pp[0] + pp[1]) / 2; break; + default: { + Polygon p; + p.points.swap(pp); + c = p.centroid(); + pp.swap(p.points); + break; + } + } + + return c; +} + +inline Point centroid(const ExPolygon& poly) { + return poly.contour.centroid(); +} + +/// A fake concave hull that is constructed by connecting separate shapes +/// with explicit bridges. Bridges are generated from each shape's centroid +/// to the center of the "scene" which is the centroid calculated from the shape +/// centroids (a star is created...) +inline ExPolygons concave_hull(const ExPolygons& polys, double max_dist_mm = 50) +{ + if(polys.empty()) return ExPolygons(); + + ExPolygons punion = unify(polys); // could be redundant + + if(punion.size() == 1) return punion; + + // We get the centroids of all the islands in the 2D slice + Points centroids; centroids.reserve(punion.size()); + std::transform(punion.begin(), punion.end(), std::back_inserter(centroids), + [](const ExPolygon& poly) { return centroid(poly); }); + + // Centroid of the centroids of islands. This is where the additional + // connector sticks are routed. + Point cc = centroid(centroids); + + punion.reserve(punion.size() + centroids.size()); + + std::transform(centroids.begin(), centroids.end(), + std::back_inserter(punion), + [cc, max_dist_mm](const Point& c) { + + double dx = x(c) - x(cc), dy = y(c) - y(cc); + double l = std::sqrt(dx * dx + dy * dy); + double nx = dx / l, ny = dy / l; + double max_dist = mm(max_dist_mm); + + if(l > max_dist) return ExPolygon(); + + ExPolygon r; + auto& ctour = r.contour.points; + + ctour.reserve(3); + ctour.emplace_back(cc); + + Point d(coord_t(mm(1)*nx), coord_t(mm(1)*ny)); + ctour.emplace_back(c + Point( -y(d), x(d) )); + ctour.emplace_back(c + Point( y(d), -x(d) )); + offset(r, mm(1)); + + return r; + }); + + punion = unify(punion); + + return punion; +} + +} + +void ground_layer(const TriangleMesh &mesh, ExPolygons &output, float h) +{ + TriangleMesh m = mesh; + TriangleMeshSlicer slicer(&m); + + std::vector<ExPolygons> tmp; + + slicer.slice({h}, &tmp); + + output = tmp.front(); +} + +void create_base_pool(const ExPolygons &ground_layer, TriangleMesh& out, + double min_wall_thickness_mm, + double min_wall_height_mm, + double max_merge_distance_mm) +{ + auto concavehs = concave_hull(ground_layer, max_merge_distance_mm); + for(ExPolygon& concaveh : concavehs) { + if(concaveh.contour.points.empty()) return; + concaveh.holes.clear(); + + BoundingBox bb(concaveh); + coord_t w = x(bb.max) - x(bb.min); + coord_t h = y(bb.max) - y(bb.min); + + auto wall_thickness = coord_t((w+h)*0.01); + + const coord_t WALL_THICKNESS = mm(min_wall_thickness_mm) + + wall_thickness; + + const coord_t WALL_DISTANCE = coord_t(0.3*WALL_THICKNESS); + const coord_t HEIGHT = mm(min_wall_height_mm); + + auto outer_base = concaveh; + offset(outer_base, WALL_THICKNESS+WALL_DISTANCE); + auto inner_base = outer_base; + offset(inner_base, -WALL_THICKNESS); + inner_base.holes.clear(); outer_base.holes.clear(); + + ExPolygon top_poly; + top_poly.contour = outer_base.contour; + top_poly.holes.emplace_back(inner_base.contour); + auto& tph = top_poly.holes.back().points; + std::reverse(tph.begin(), tph.end()); + + Contour3D pool; + + ExPolygon ob = outer_base; double wh = 0; + auto curvedwalls = round_edges(ob, + 1, // radius 1 mm + 170, // 170 degrees + 0, // z position of the input plane + true, + ob, wh); + pool.merge(curvedwalls); + + ExPolygon ob_contr = ob; + ob_contr.holes.clear(); + + auto pwalls = walls(ob_contr, inner_base, wh, -min_wall_height_mm); + pool.merge(pwalls); + + Polygons top_triangles, bottom_triangles; + triangulate(top_poly, top_triangles); + triangulate(inner_base, bottom_triangles); + auto top_plate = convert(top_triangles, 0, false); + auto bottom_plate = convert(bottom_triangles, -HEIGHT, true); + + ob = inner_base; wh = 0; + curvedwalls = round_edges(ob, + 1, // radius 1 mm + 90, // 170 degrees + 0, // z position of the input plane + false, + ob, wh); + pool.merge(curvedwalls); + + auto innerbed = inner_bed(ob, min_wall_height_mm/2 + wh, wh); + + pool.merge(top_plate); + pool.merge(bottom_plate); + pool.merge(innerbed); + + out.merge(mesh(pool)); + } +} + +} +} diff --git a/xs/src/libslic3r/SLABasePool.hpp b/xs/src/libslic3r/SLABasePool.hpp new file mode 100644 index 000000000..55c94df07 --- /dev/null +++ b/xs/src/libslic3r/SLABasePool.hpp @@ -0,0 +1,32 @@ +#ifndef SLASUPPORTPOOL_HPP +#define SLASUPPORTPOOL_HPP + +#include <vector> + +namespace Slic3r { + +class ExPolygon; +class TriangleMesh; + +namespace sla { + +using ExPolygons = std::vector<ExPolygon>; + +/// Calculate the polygon representing the slice of the lowest layer of mesh +void ground_layer(const TriangleMesh& mesh, + ExPolygons& output, + float height = 0.1f); + +/// Calculate the pool for the mesh for SLA printing +void create_base_pool(const ExPolygons& ground_layer, + TriangleMesh& output_mesh, + double min_wall_thickness_mm = 2, + double min_wall_height_mm = 5, + double max_merge_distance_mm = 50 + ); + +} + +} + +#endif // SLASUPPORTPOOL_HPP diff --git a/xs/src/libslic3r/SVG.cpp b/xs/src/libslic3r/SVG.cpp index c94db8e74..03f55802e 100644 --- a/xs/src/libslic3r/SVG.cpp +++ b/xs/src/libslic3r/SVG.cpp @@ -3,7 +3,7 @@ #include <boost/nowide/cstdio.hpp> -#define COORD(x) ((float)unscale((x))*10) +#define COORD(x) (unscale<float>((x))*10) namespace Slic3r { @@ -32,8 +32,8 @@ bool SVG::open(const char* afilename, const BoundingBox &bbox, const coord_t bbo this->f = boost::nowide::fopen(afilename, "w"); if (f == NULL) return false; - float w = COORD(bbox.max.x - bbox.min.x + 2 * bbox_offset); - float h = COORD(bbox.max.y - bbox.min.y + 2 * bbox_offset); + float w = COORD(bbox.max(0) - bbox.min(0) + 2 * bbox_offset); + float h = COORD(bbox.max(1) - bbox.min(1) + 2 * bbox_offset); fprintf(this->f, "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n" "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.0//EN\" \"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd\">\n" @@ -50,7 +50,7 @@ SVG::draw(const Line &line, std::string stroke, coordf_t stroke_width) { fprintf(this->f, " <line x1=\"%f\" y1=\"%f\" x2=\"%f\" y2=\"%f\" style=\"stroke: %s; stroke-width: %f\"", - COORD(line.a.x - origin.x), COORD(line.a.y - origin.y), COORD(line.b.x - origin.x), COORD(line.b.y - origin.y), stroke.c_str(), (stroke_width == 0) ? 1.f : COORD(stroke_width)); + COORD(line.a(0) - origin(0)), COORD(line.a(1) - origin(1)), COORD(line.b(0) - origin(0)), COORD(line.b(1) - origin(1)), stroke.c_str(), (stroke_width == 0) ? 1.f : COORD(stroke_width)); if (this->arrows) fprintf(this->f, " marker-end=\"url(#endArrow)\""); fprintf(this->f, "/>\n"); @@ -58,21 +58,21 @@ SVG::draw(const Line &line, std::string stroke, coordf_t stroke_width) void SVG::draw(const ThickLine &line, const std::string &fill, const std::string &stroke, coordf_t stroke_width) { - Pointf dir(line.b.x-line.a.x, line.b.y-line.a.y); - Pointf perp(-dir.y, dir.x); - coordf_t len = sqrt(perp.x*perp.x + perp.y*perp.y); + Vec2d dir(line.b(0)-line.a(0), line.b(1)-line.a(1)); + Vec2d perp(-dir(1), dir(0)); + coordf_t len = sqrt(perp(0)*perp(0) + perp(1)*perp(1)); coordf_t da = coordf_t(0.5)*line.a_width/len; coordf_t db = coordf_t(0.5)*line.b_width/len; fprintf(this->f, " <polygon points=\"%f,%f %f,%f %f,%f %f,%f\" style=\"fill:%s; stroke: %s; stroke-width: %f\"/>\n", - COORD(line.a.x-da*perp.x-origin.x), - COORD(line.a.y-da*perp.y-origin.y), - COORD(line.b.x-db*perp.x-origin.x), - COORD(line.b.y-db*perp.y-origin.y), - COORD(line.b.x+db*perp.x-origin.x), - COORD(line.b.y+db*perp.y-origin.y), - COORD(line.a.x+da*perp.x-origin.x), - COORD(line.a.y+da*perp.y-origin.y), + COORD(line.a(0)-da*perp(0)-origin(0)), + COORD(line.a(1)-da*perp(1)-origin(1)), + COORD(line.b(0)-db*perp(0)-origin(0)), + COORD(line.b(1)-db*perp(1)-origin(1)), + COORD(line.b(0)+db*perp(0)-origin(0)), + COORD(line.b(1)+db*perp(1)-origin(1)), + COORD(line.a(0)+da*perp(0)-origin(0)), + COORD(line.a(1)+da*perp(1)-origin(1)), fill.c_str(), stroke.c_str(), (stroke_width == 0) ? 1.f : COORD(stroke_width)); } @@ -220,7 +220,7 @@ SVG::draw(const Point &point, std::string fill, coord_t iradius) { float radius = (iradius == 0) ? 3.f : COORD(iradius); std::ostringstream svg; - svg << " <circle cx=\"" << COORD(point.x - origin.x) << "\" cy=\"" << COORD(point.y - origin.y) + svg << " <circle cx=\"" << COORD(point(0) - origin(0)) << "\" cy=\"" << COORD(point(1) - origin(1)) << "\" r=\"" << radius << "\" " << "style=\"stroke: none; fill: " << fill << "\" />"; @@ -287,8 +287,8 @@ SVG::get_path_d(const MultiPoint &mp, bool closed) const std::ostringstream d; d << "M "; for (Points::const_iterator p = mp.points.begin(); p != mp.points.end(); ++p) { - d << COORD(p->x - origin.x) << " "; - d << COORD(p->y - origin.y) << " "; + d << COORD((*p)(0) - origin(0)) << " "; + d << COORD((*p)(1) - origin(1)) << " "; } if (closed) d << "z"; return d.str(); @@ -300,8 +300,8 @@ SVG::get_path_d(const ClipperLib::Path &path, double scale, bool closed) const std::ostringstream d; d << "M "; for (ClipperLib::Path::const_iterator p = path.begin(); p != path.end(); ++p) { - d << COORD(scale * p->X - origin.x) << " "; - d << COORD(scale * p->Y - origin.y) << " "; + d << COORD(scale * p->X - origin(0)) << " "; + d << COORD(scale * p->Y - origin(1)) << " "; } if (closed) d << "z"; return d.str(); @@ -311,8 +311,8 @@ void SVG::draw_text(const Point &pt, const char *text, const char *color) { fprintf(this->f, "<text x=\"%f\" y=\"%f\" font-family=\"sans-serif\" font-size=\"20px\" fill=\"%s\">%s</text>", - COORD(pt.x-origin.x), - COORD(pt.y-origin.y), + COORD(pt(0)-origin(0)), + COORD(pt(1)-origin(1)), color, text); } @@ -320,13 +320,13 @@ void SVG::draw_legend(const Point &pt, const char *text, const char *color) { fprintf(this->f, "<circle cx=\"%f\" cy=\"%f\" r=\"10\" fill=\"%s\"/>", - COORD(pt.x-origin.x), - COORD(pt.y-origin.y), + COORD(pt(0)-origin(0)), + COORD(pt(1)-origin(1)), color); fprintf(this->f, "<text x=\"%f\" y=\"%f\" font-family=\"sans-serif\" font-size=\"10px\" fill=\"%s\">%s</text>", - COORD(pt.x-origin.x) + 20.f, - COORD(pt.y-origin.y), + COORD(pt(0)-origin(0)) + 20.f, + COORD(pt(1)-origin(1)), "black", text); } diff --git a/xs/src/libslic3r/Slicing.cpp b/xs/src/libslic3r/Slicing.cpp index e9295d1e3..1bc38502b 100644 --- a/xs/src/libslic3r/Slicing.cpp +++ b/xs/src/libslic3r/Slicing.cpp @@ -561,15 +561,15 @@ int generate_layer_height_texture( void *data, int rows, int cols, bool level_of_detail_2nd_level) { // https://github.com/aschn/gnuplot-colorbrewer - std::vector<Point3> palette_raw; - palette_raw.push_back(Point3(0x01A, 0x098, 0x050)); - palette_raw.push_back(Point3(0x066, 0x0BD, 0x063)); - palette_raw.push_back(Point3(0x0A6, 0x0D9, 0x06A)); - palette_raw.push_back(Point3(0x0D9, 0x0F1, 0x0EB)); - palette_raw.push_back(Point3(0x0FE, 0x0E6, 0x0EB)); - palette_raw.push_back(Point3(0x0FD, 0x0AE, 0x061)); - palette_raw.push_back(Point3(0x0F4, 0x06D, 0x043)); - palette_raw.push_back(Point3(0x0D7, 0x030, 0x027)); + std::vector<Vec3crd> palette_raw; + palette_raw.push_back(Vec3crd(0x01A, 0x098, 0x050)); + palette_raw.push_back(Vec3crd(0x066, 0x0BD, 0x063)); + palette_raw.push_back(Vec3crd(0x0A6, 0x0D9, 0x06A)); + palette_raw.push_back(Vec3crd(0x0D9, 0x0F1, 0x0EB)); + palette_raw.push_back(Vec3crd(0x0FE, 0x0E6, 0x0EB)); + palette_raw.push_back(Vec3crd(0x0FD, 0x0AE, 0x061)); + palette_raw.push_back(Vec3crd(0x0F4, 0x06D, 0x043)); + palette_raw.push_back(Vec3crd(0x0D7, 0x030, 0x027)); // Clear the main texture and the 2nd LOD level. // memset(data, 0, rows * cols * (level_of_detail_2nd_level ? 5 : 4)); @@ -600,25 +600,25 @@ int generate_layer_height_texture( int idx1 = clamp(0, int(palette_raw.size() - 1), int(floor(idxf))); int idx2 = std::min(int(palette_raw.size() - 1), idx1 + 1); coordf_t t = idxf - coordf_t(idx1); - const Point3 &color1 = palette_raw[idx1]; - const Point3 &color2 = palette_raw[idx2]; + const Vec3crd &color1 = palette_raw[idx1]; + const Vec3crd &color2 = palette_raw[idx2]; coordf_t z = cell_to_z * coordf_t(cell); assert(z >= lo && z <= hi); // Intensity profile to visualize the layers. coordf_t intensity = cos(M_PI * 0.7 * (mid - z) / h); // Color mapping from layer height to RGB. - Pointf3 color( - intensity * lerp(coordf_t(color1.x), coordf_t(color2.x), t), - intensity * lerp(coordf_t(color1.y), coordf_t(color2.y), t), - intensity * lerp(coordf_t(color1.z), coordf_t(color2.z), t)); + Vec3d color( + intensity * lerp(coordf_t(color1(0)), coordf_t(color2(0)), t), + intensity * lerp(coordf_t(color1(1)), coordf_t(color2(1)), t), + intensity * lerp(coordf_t(color1(2)), coordf_t(color2(2)), t)); int row = cell / (cols - 1); int col = cell - row * (cols - 1); assert(row >= 0 && row < rows); assert(col >= 0 && col < cols); unsigned char *ptr = (unsigned char*)data + (row * cols + col) * 4; - ptr[0] = (unsigned char)clamp<int>(0, 255, int(floor(color.x + 0.5))); - ptr[1] = (unsigned char)clamp<int>(0, 255, int(floor(color.y + 0.5))); - ptr[2] = (unsigned char)clamp<int>(0, 255, int(floor(color.z + 0.5))); + ptr[0] = (unsigned char)clamp<int>(0, 255, int(floor(color(0) + 0.5))); + ptr[1] = (unsigned char)clamp<int>(0, 255, int(floor(color(1) + 0.5))); + ptr[2] = (unsigned char)clamp<int>(0, 255, int(floor(color(2) + 0.5))); ptr[3] = 255; if (col == 0 && row > 0) { // Duplicate the first value in a row as a last value of the preceding row. @@ -636,21 +636,21 @@ int generate_layer_height_texture( int idx1 = clamp(0, int(palette_raw.size() - 1), int(floor(idxf))); int idx2 = std::min(int(palette_raw.size() - 1), idx1 + 1); coordf_t t = idxf - coordf_t(idx1); - const Point3 &color1 = palette_raw[idx1]; - const Point3 &color2 = palette_raw[idx2]; + const Vec3crd &color1 = palette_raw[idx1]; + const Vec3crd &color2 = palette_raw[idx2]; // Color mapping from layer height to RGB. - Pointf3 color( - lerp(coordf_t(color1.x), coordf_t(color2.x), t), - lerp(coordf_t(color1.y), coordf_t(color2.y), t), - lerp(coordf_t(color1.z), coordf_t(color2.z), t)); + Vec3d color( + lerp(coordf_t(color1(0)), coordf_t(color2(0)), t), + lerp(coordf_t(color1(1)), coordf_t(color2(1)), t), + lerp(coordf_t(color1(2)), coordf_t(color2(2)), t)); int row = cell / (cols1 - 1); int col = cell - row * (cols1 - 1); assert(row >= 0 && row < rows/2); assert(col >= 0 && col < cols/2); unsigned char *ptr = data1 + (row * cols1 + col) * 4; - ptr[0] = (unsigned char)clamp<int>(0, 255, int(floor(color.x + 0.5))); - ptr[1] = (unsigned char)clamp<int>(0, 255, int(floor(color.y + 0.5))); - ptr[2] = (unsigned char)clamp<int>(0, 255, int(floor(color.z + 0.5))); + ptr[0] = (unsigned char)clamp<int>(0, 255, int(floor(color(0) + 0.5))); + ptr[1] = (unsigned char)clamp<int>(0, 255, int(floor(color(1) + 0.5))); + ptr[2] = (unsigned char)clamp<int>(0, 255, int(floor(color(2) + 0.5))); ptr[3] = 255; if (col == 0 && row > 0) { // Duplicate the first value in a row as a last value of the preceding row. diff --git a/xs/src/libslic3r/SlicingAdaptive.cpp b/xs/src/libslic3r/SlicingAdaptive.cpp index ff0da7636..2ef4aec8c 100644 --- a/xs/src/libslic3r/SlicingAdaptive.cpp +++ b/xs/src/libslic3r/SlicingAdaptive.cpp @@ -15,8 +15,8 @@ void SlicingAdaptive::clear() std::pair<float, float> face_z_span(const stl_facet *f) { return std::pair<float, float>( - std::min(std::min(f->vertex[0].z, f->vertex[1].z), f->vertex[2].z), - std::max(std::max(f->vertex[0].z, f->vertex[1].z), f->vertex[2].z)); + std::min(std::min(f->vertex[0](2), f->vertex[1](2)), f->vertex[2](2)), + std::max(std::max(f->vertex[0](2), f->vertex[1](2)), f->vertex[2](2))); } void SlicingAdaptive::prepare() @@ -40,7 +40,7 @@ void SlicingAdaptive::prepare() // 3) Generate Z components of the facet normals. m_face_normal_z.assign(m_faces.size(), 0.f); for (size_t iface = 0; iface < m_faces.size(); ++ iface) - m_face_normal_z[iface] = m_faces[iface]->normal.z; + m_face_normal_z[iface] = m_faces[iface]->normal(2); } float SlicingAdaptive::cusp_height(float z, float cusp_value, int ¤t_facet) diff --git a/xs/src/libslic3r/SupportMaterial.cpp b/xs/src/libslic3r/SupportMaterial.cpp index 0cecf0014..4b7e78976 100644 --- a/xs/src/libslic3r/SupportMaterial.cpp +++ b/xs/src/libslic3r/SupportMaterial.cpp @@ -67,9 +67,9 @@ Point export_support_surface_type_legend_to_svg_box_size() void export_support_surface_type_legend_to_svg(SVG &svg, const Point &pos) { // 1st row - coord_t pos_x0 = pos.x + scale_(1.); + coord_t pos_x0 = pos(0) + scale_(1.); coord_t pos_x = pos_x0; - coord_t pos_y = pos.y + scale_(1.5); + coord_t pos_y = pos(1) + scale_(1.5); coord_t step_x = scale_(10.); svg.draw_legend(Point(pos_x, pos_y), "top contact" , support_surface_type_to_color_name(PrintObjectSupportMaterial::sltTopContact)); pos_x += step_x; @@ -82,7 +82,7 @@ void export_support_surface_type_legend_to_svg(SVG &svg, const Point &pos) svg.draw_legend(Point(pos_x, pos_y), "bottom contact" , support_surface_type_to_color_name(PrintObjectSupportMaterial::sltBottomContact)); // 2nd row pos_x = pos_x0; - pos_y = pos.y+scale_(2.8); + pos_y = pos(1)+scale_(2.8); svg.draw_legend(Point(pos_x, pos_y), "raft interface" , support_surface_type_to_color_name(PrintObjectSupportMaterial::sltRaftInterface)); pos_x += step_x; svg.draw_legend(Point(pos_x, pos_y), "raft base" , support_surface_type_to_color_name(PrintObjectSupportMaterial::sltRaftBase)); @@ -98,8 +98,8 @@ void export_print_z_polygons_to_svg(const char *path, PrintObjectSupportMaterial for (int i = 0; i < n_layers; ++ i) bbox.merge(get_extents(layers[i]->polygons)); Point legend_size = export_support_surface_type_legend_to_svg_box_size(); - Point legend_pos(bbox.min.x, bbox.max.y); - bbox.merge(Point(std::max(bbox.min.x + legend_size.x, bbox.max.x), bbox.max.y + legend_size.y)); + Point legend_pos(bbox.min(0), bbox.max(1)); + bbox.merge(Point(std::max(bbox.min(0) + legend_size(0), bbox.max(0)), bbox.max(1) + legend_size(1))); SVG svg(path, bbox); const float transparency = 0.5f; for (int i = 0; i < n_layers; ++ i) @@ -120,8 +120,8 @@ void export_print_z_polygons_and_extrusions_to_svg( for (int i = 0; i < n_layers; ++ i) bbox.merge(get_extents(layers[i]->polygons)); Point legend_size = export_support_surface_type_legend_to_svg_box_size(); - Point legend_pos(bbox.min.x, bbox.max.y); - bbox.merge(Point(std::max(bbox.min.x + legend_size.x, bbox.max.x), bbox.max.y + legend_size.y)); + Point legend_pos(bbox.min(0), bbox.max(1)); + bbox.merge(Point(std::max(bbox.min(0) + legend_size(0), bbox.max(0)), bbox.max(1) + legend_size(1))); SVG svg(path, bbox); const float transparency = 0.5f; for (int i = 0; i < n_layers; ++ i) @@ -506,8 +506,8 @@ public: for (ExPolygon &island : islands) { BoundingBox bbox = get_extents(island.contour); - auto it_lower = std::lower_bound(m_island_samples.begin(), m_island_samples.end(), bbox.min - Point(1, 1)); - auto it_upper = std::upper_bound(m_island_samples.begin(), m_island_samples.end(), bbox.max + Point(1, 1)); + auto it_lower = std::lower_bound(m_island_samples.begin(), m_island_samples.end(), Point(bbox.min - Point(1, 1))); + auto it_upper = std::upper_bound(m_island_samples.begin(), m_island_samples.end(), Point(bbox.max + Point(1, 1))); samples_inside.clear(); for (auto it = it_lower; it != it_upper; ++ it) if (bbox.contains(*it)) @@ -519,12 +519,12 @@ public: Points::const_iterator i = contour.points.begin(); Points::const_iterator j = contour.points.end() - 1; for (; i != contour.points.end(); j = i ++) { - //FIXME this test is not numerically robust. Particularly, it does not handle horizontal segments at y == point.y well. - // Does the ray with y == point.y intersect this line segment? + //FIXME this test is not numerically robust. Particularly, it does not handle horizontal segments at y == point(1) well. + // Does the ray with y == point(1) intersect this line segment? for (auto &sample_inside : samples_inside) { - if ((i->y > sample_inside.first.y) != (j->y > sample_inside.first.y)) { - double x1 = (double)sample_inside.first.x; - double x2 = (double)i->x + (double)(j->x - i->x) * (double)(sample_inside.first.y - i->y) / (double)(j->y - i->y); + if (((*i)(1) > sample_inside.first(1)) != ((*j)(1) > sample_inside.first(1))) { + double x1 = (double)sample_inside.first(0); + double x2 = (double)(*i)(0) + (double)((*j)(0) - (*i)(0)) * (double)(sample_inside.first(1) - (*i)(1)) / (double)((*j)(1) - (*i)(1)); if (x1 < x2) sample_inside.second = !sample_inside.second; } @@ -585,11 +585,11 @@ private: const Point &p3 = (pt_min == &expoly.contour.points.back()) ? expoly.contour.points.front() : *(pt_min + 1); Vector v = (p3 - p2) + (p1 - p2); - double l2 = double(v.x)*double(v.x)+double(v.y)*double(v.y); + double l2 = double(v(0))*double(v(0))+double(v(1))*double(v(1)); if (l2 == 0.) return p2; double coef = 20. / sqrt(l2); - return Point(p2.x + coef * v.x, p2.y + coef * v.y); + return Point(p2(0) + coef * v(0), p2(1) + coef * v(1)); } static Points island_samples(const ExPolygons &expolygons) @@ -789,7 +789,7 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::top_contact_ // workaround for Clipper bug, see Slic3r::Polygon::clip_as_polyline() for (Polyline &polyline : overhang_perimeters) - polyline.points[0].x += 1; + polyline.points[0](0) += 1; // Trim the perimeters of this layer by the lower layer to get the unsupported pieces of perimeters. overhang_perimeters = diff_pl(overhang_perimeters, lower_grown_slices); @@ -2057,11 +2057,11 @@ void LoopInterfaceProcessor::generate(MyLayerExtruded &top_contact_layer, const const Point &p1 = *(it-1); const Point &p2 = *it; // Intersection of a ray (p1, p2) with a circle placed at center_last, with radius of circle_distance. - const Pointf v_seg(coordf_t(p2.x) - coordf_t(p1.x), coordf_t(p2.y) - coordf_t(p1.y)); - const Pointf v_cntr(coordf_t(p1.x - center_last.x), coordf_t(p1.y - center_last.y)); - coordf_t a = dot(v_seg); - coordf_t b = 2. * dot(v_seg, v_cntr); - coordf_t c = dot(v_cntr) - circle_distance * circle_distance; + const Vec2d v_seg(coordf_t(p2(0)) - coordf_t(p1(0)), coordf_t(p2(1)) - coordf_t(p1(1))); + const Vec2d v_cntr(coordf_t(p1(0) - center_last(0)), coordf_t(p1(1) - center_last(1))); + coordf_t a = v_seg.squaredNorm(); + coordf_t b = 2. * v_seg.dot(v_cntr); + coordf_t c = v_cntr.squaredNorm() - circle_distance * circle_distance; coordf_t disc = b * b - 4. * a * c; if (disc > 0.) { // The circle intersects a ray. Avoid the parts of the segment inside the circle. @@ -2081,7 +2081,7 @@ void LoopInterfaceProcessor::generate(MyLayerExtruded &top_contact_layer, const } seg_current_pt = &p1; seg_current_t = t; - center_last = Point(p1.x + coord_t(v_seg.x * t), p1.y + coord_t(v_seg.y * t)); + center_last = Point(p1(0) + coord_t(v_seg(0) * t), p1(1) + coord_t(v_seg(1) * t)); // It has been verified that the new point is far enough from center_last. // Ensure, that it is far enough from all the centers. std::pair<const Point*, coordf_t> circle_closest = circle_centers_lookup.find(center_last); @@ -2100,9 +2100,9 @@ void LoopInterfaceProcessor::generate(MyLayerExtruded &top_contact_layer, const circle_centers.push_back(center_last); } external_loops.push_back(std::move(contour)); - for (Points::const_iterator it_center = circle_centers.begin(); it_center != circle_centers.end(); ++ it_center) { + for (const Point ¢er : circle_centers) { circles.push_back(circle); - circles.back().translate(*it_center); + circles.back().translate(center); } } } @@ -2359,7 +2359,7 @@ void modulate_extrusion_by_overlapping_layers( (fragment_end.is_start ? &polyline.points.front() : &polyline.points.back()); } private: - ExtrusionPathFragmentEndPointAccessor& operator=(const ExtrusionPathFragmentEndPointAccessor&); + ExtrusionPathFragmentEndPointAccessor& operator=(const ExtrusionPathFragmentEndPointAccessor&) = delete; const std::vector<ExtrusionPathFragment> &m_path_fragments; }; const coord_t search_radius = 7; @@ -2392,7 +2392,7 @@ void modulate_extrusion_by_overlapping_layers( if (end_and_dist2.first == nullptr) { // New fragment connecting to pt_current was not found. // Verify that the last point found is close to the original end point of the unfragmented path. - //const double d2 = pt_end.distance_to_sq(pt_current); + //const double d2 = (pt_end - pt_current).squaredNorm(); //assert(d2 < coordf_t(search_radius * search_radius)); // End of the path. break; @@ -2887,9 +2887,9 @@ void PrintObjectSupportMaterial::clip_by_pillars( BoundingBox bbox; for (LayersPtr::const_iterator it = top_contacts.begin(); it != top_contacts.end(); ++ it) bbox.merge(get_extents((*it)->polygons)); - grid.reserve(size_t(ceil(bb.size().x / pillar_spacing)) * size_t(ceil(bb.size().y / pillar_spacing))); - for (coord_t x = bb.min.x; x <= bb.max.x - pillar_size; x += pillar_spacing) { - for (coord_t y = bb.min.y; y <= bb.max.y - pillar_size; y += pillar_spacing) { + grid.reserve(size_t(ceil(bb.size()(0) / pillar_spacing)) * size_t(ceil(bb.size()(1) / pillar_spacing))); + for (coord_t x = bb.min(0); x <= bb.max(0) - pillar_size; x += pillar_spacing) { + for (coord_t y = bb.min(1); y <= bb.max(1) - pillar_size; y += pillar_spacing) { grid.push_back(pillar); for (size_t i = 0; i < pillar.points.size(); ++ i) grid.back().points[i].translate(Point(x, y)); diff --git a/xs/src/libslic3r/Surface.cpp b/xs/src/libslic3r/Surface.cpp index 384540d87..0e9eca7fd 100644 --- a/xs/src/libslic3r/Surface.cpp +++ b/xs/src/libslic3r/Surface.cpp @@ -106,9 +106,9 @@ Point export_surface_type_legend_to_svg_box_size() void export_surface_type_legend_to_svg(SVG &svg, const Point &pos) { // 1st row - coord_t pos_x0 = pos.x + scale_(1.); + coord_t pos_x0 = pos(0) + scale_(1.); coord_t pos_x = pos_x0; - coord_t pos_y = pos.y + scale_(1.5); + coord_t pos_y = pos(1) + scale_(1.5); coord_t step_x = scale_(10.); svg.draw_legend(Point(pos_x, pos_y), "perimeter" , surface_type_to_color_name(stPerimeter)); pos_x += step_x; @@ -121,7 +121,7 @@ void export_surface_type_legend_to_svg(SVG &svg, const Point &pos) svg.draw_legend(Point(pos_x, pos_y), "invalid" , surface_type_to_color_name(SurfaceType(-1))); // 2nd row pos_x = pos_x0; - pos_y = pos.y+scale_(2.8); + pos_y = pos(1)+scale_(2.8); svg.draw_legend(Point(pos_x, pos_y), "internal" , surface_type_to_color_name(stInternal)); pos_x += step_x; svg.draw_legend(Point(pos_x, pos_y), "internal solid" , surface_type_to_color_name(stInternalSolid)); diff --git a/xs/src/libslic3r/SurfaceCollection.cpp b/xs/src/libslic3r/SurfaceCollection.cpp index 42ddf9574..6db599306 100644 --- a/xs/src/libslic3r/SurfaceCollection.cpp +++ b/xs/src/libslic3r/SurfaceCollection.cpp @@ -170,8 +170,8 @@ void SurfaceCollection::export_to_svg(const char *path, bool show_labels) for (Surfaces::const_iterator surface = this->surfaces.begin(); surface != this->surfaces.end(); ++surface) bbox.merge(get_extents(surface->expolygon)); Point legend_size = export_surface_type_legend_to_svg_box_size(); - Point legend_pos(bbox.min.x, bbox.max.y); - bbox.merge(Point(std::max(bbox.min.x + legend_size.x, bbox.max.x), bbox.max.y + legend_size.y)); + Point legend_pos(bbox.min(0), bbox.max(1)); + bbox.merge(Point(std::max(bbox.min(0) + legend_size(0), bbox.max(0)), bbox.max(1) + legend_size(1))); SVG svg(path, bbox); const float transparency = 0.5f; diff --git a/xs/src/libslic3r/TriangleMesh.cpp b/xs/src/libslic3r/TriangleMesh.cpp index 4c45680b6..6d40731f8 100644 --- a/xs/src/libslic3r/TriangleMesh.cpp +++ b/xs/src/libslic3r/TriangleMesh.cpp @@ -36,13 +36,7 @@ namespace Slic3r { -TriangleMesh::TriangleMesh() - : repaired(false) -{ - stl_initialize(&this->stl); -} - -TriangleMesh::TriangleMesh(const Pointf3s &points, const std::vector<Point3>& facets ) +TriangleMesh::TriangleMesh(const Pointf3s &points, const std::vector<Vec3crd>& facets ) : repaired(false) { stl_initialize(&this->stl); @@ -57,51 +51,22 @@ TriangleMesh::TriangleMesh(const Pointf3s &points, const std::vector<Point3>& fa for (int i = 0; i < stl.stats.number_of_facets; i++) { stl_facet facet; - - const Pointf3& ref_f1 = points[facets[i].x]; - facet.vertex[0].x = ref_f1.x; - facet.vertex[0].y = ref_f1.y; - facet.vertex[0].z = ref_f1.z; - - const Pointf3& ref_f2 = points[facets[i].y]; - facet.vertex[1].x = ref_f2.x; - facet.vertex[1].y = ref_f2.y; - facet.vertex[1].z = ref_f2.z; - - const Pointf3& ref_f3 = points[facets[i].z]; - facet.vertex[2].x = ref_f3.x; - facet.vertex[2].y = ref_f3.y; - facet.vertex[2].z = ref_f3.z; - + facet.vertex[0] = points[facets[i](0)].cast<float>(); + facet.vertex[1] = points[facets[i](1)].cast<float>(); + facet.vertex[2] = points[facets[i](2)].cast<float>(); facet.extra[0] = 0; facet.extra[1] = 0; - float normal[3]; + stl_normal normal; stl_calculate_normal(normal, &facet); stl_normalize_vector(normal); - facet.normal.x = normal[0]; - facet.normal.y = normal[1]; - facet.normal.z = normal[2]; + facet.normal = normal; stl.facet_start[i] = facet; } stl_get_size(&stl); } -TriangleMesh::TriangleMesh(const TriangleMesh &other) : - repaired(false) -{ - stl_initialize(&this->stl); - *this = other; -} - -TriangleMesh::TriangleMesh(TriangleMesh &&other) : - repaired(false) -{ - stl_initialize(&this->stl); - this->swap(other); -} - TriangleMesh& TriangleMesh::operator=(const TriangleMesh &other) { stl_close(&this->stl); @@ -129,42 +94,8 @@ TriangleMesh& TriangleMesh::operator=(const TriangleMesh &other) return *this; } -TriangleMesh& TriangleMesh::operator=(TriangleMesh &&other) -{ - this->swap(other); - return *this; -} - -void -TriangleMesh::swap(TriangleMesh &other) +void TriangleMesh::repair() { - std::swap(this->stl, other.stl); - std::swap(this->repaired, other.repaired); -} - -TriangleMesh::~TriangleMesh() { - stl_close(&this->stl); -} - -void -TriangleMesh::ReadSTLFile(const char* input_file) { - stl_open(&stl, input_file); -} - -void -TriangleMesh::write_ascii(const char* output_file) -{ - stl_write_ascii(&this->stl, output_file, ""); -} - -void -TriangleMesh::write_binary(const char* output_file) -{ - stl_write_binary(&this->stl, output_file, ""); -} - -void -TriangleMesh::repair() { if (this->repaired) return; // admesh fails when repairing empty meshes @@ -261,13 +192,7 @@ void TriangleMesh::check_topology() } } -bool TriangleMesh::is_manifold() const -{ - return this->stl.stats.connected_facets_3_edge == this->stl.stats.number_of_facets; -} - -void -TriangleMesh::reset_repair_stats() { +void TriangleMesh::reset_repair_stats() { this->stl.stats.degenerate_facets = 0; this->stl.stats.edges_fixed = 0; this->stl.stats.facets_removed = 0; @@ -277,8 +202,7 @@ TriangleMesh::reset_repair_stats() { this->stl.stats.normals_fixed = 0; } -bool -TriangleMesh::needed_repair() const +bool TriangleMesh::needed_repair() const { return this->stl.stats.degenerate_facets > 0 || this->stl.stats.edges_fixed > 0 @@ -288,14 +212,8 @@ TriangleMesh::needed_repair() const || this->stl.stats.backwards_edges > 0; } -size_t -TriangleMesh::facets_count() const +void TriangleMesh::WriteOBJFile(char* output_file) { - return this->stl.stats.number_of_facets; -} - -void -TriangleMesh::WriteOBJFile(char* output_file) { stl_generate_shared_vertices(&stl); stl_write_obj(&stl, output_file); } @@ -306,13 +224,9 @@ void TriangleMesh::scale(float factor) stl_invalidate_shared_vertices(&this->stl); } -void TriangleMesh::scale(const Pointf3 &versor) +void TriangleMesh::scale(const Vec3d &versor) { - float fversor[3]; - fversor[0] = versor.x; - fversor[1] = versor.y; - fversor[2] = versor.z; - stl_scale_versor(&this->stl, fversor); + stl_scale_versor(&this->stl, versor.cast<float>()); stl_invalidate_shared_vertices(&this->stl); } @@ -324,17 +238,6 @@ void TriangleMesh::translate(float x, float y, float z) stl_invalidate_shared_vertices(&this->stl); } -void TriangleMesh::rotate(float angle, Pointf3 axis) -{ - if (angle == 0.f) - return; - - axis = normalize(axis); - Eigen::Transform<float, 3, Eigen::Affine> m = Eigen::Transform<float, 3, Eigen::Affine>::Identity(); - m.rotate(Eigen::AngleAxisf(angle, Eigen::Vector3f(axis.x, axis.y, axis.z))); - stl_transform(&stl, (float*)m.data()); -} - void TriangleMesh::rotate(float angle, const Axis &axis) { if (angle == 0.f) @@ -353,19 +256,15 @@ void TriangleMesh::rotate(float angle, const Axis &axis) stl_invalidate_shared_vertices(&this->stl); } -void TriangleMesh::rotate_x(float angle) +void TriangleMesh::rotate(float angle, const Vec3d& axis) { - this->rotate(angle, X); -} - -void TriangleMesh::rotate_y(float angle) -{ - this->rotate(angle, Y); -} + if (angle == 0.f) + return; -void TriangleMesh::rotate_z(float angle) -{ - this->rotate(angle, Z); + Vec3f axis_norm = axis.cast<float>().normalized(); + Transform3f m = Transform3f::Identity(); + m.rotate(Eigen::AngleAxisf(angle, axis_norm)); + stl_transform(&stl, m); } void TriangleMesh::mirror(const Axis &axis) @@ -380,46 +279,27 @@ void TriangleMesh::mirror(const Axis &axis) stl_invalidate_shared_vertices(&this->stl); } -void TriangleMesh::mirror_x() -{ - this->mirror(X); -} - -void TriangleMesh::mirror_y() +void TriangleMesh::transform(const Transform3f& t) { - this->mirror(Y); -} - -void TriangleMesh::mirror_z() -{ - this->mirror(Z); -} - -void TriangleMesh::transform(const float* matrix3x4) -{ - if (matrix3x4 == nullptr) - return; - - stl_transform(&stl, const_cast<float*>(matrix3x4)); - stl_invalidate_shared_vertices(&stl); + stl_transform(&stl, t); } void TriangleMesh::align_to_origin() { this->translate( - -(this->stl.stats.min.x), - -(this->stl.stats.min.y), - -(this->stl.stats.min.z) - ); + - this->stl.stats.min(0), + - this->stl.stats.min(1), + - this->stl.stats.min(2)); } void TriangleMesh::rotate(double angle, Point* center) { if (angle == 0.) return; - this->translate(float(-center->x), float(-center->y), 0); + Vec2f c = center->cast<float>(); + this->translate(-c(0), -c(1), 0); stl_rotate_z(&(this->stl), (float)angle); - this->translate(float(+center->x), float(+center->y), 0); + this->translate(c(0), c(1), 0); } bool TriangleMesh::has_multiple_patches() const @@ -492,14 +372,14 @@ size_t TriangleMesh::number_of_patches() const return num_bodies; } -TriangleMeshPtrs -TriangleMesh::split() const +TriangleMeshPtrs TriangleMesh::split() const { - TriangleMeshPtrs meshes; - std::set<int> seen_facets; + TriangleMeshPtrs meshes; + std::vector<unsigned char> facet_visited(this->stl.stats.number_of_facets, false); // we need neighbors - if (!this->repaired) CONFESS("split() requires repair()"); + if (!this->repaired) + CONFESS("split() requires repair()"); // loop while we have remaining facets for (;;) { @@ -507,46 +387,45 @@ TriangleMesh::split() const std::queue<int> facet_queue; std::deque<int> facets; for (int facet_idx = 0; facet_idx < this->stl.stats.number_of_facets; facet_idx++) { - if (seen_facets.find(facet_idx) == seen_facets.end()) { + if (! facet_visited[facet_idx]) { // if facet was not seen put it into queue and start searching facet_queue.push(facet_idx); break; } } - if (facet_queue.empty()) break; - - while (!facet_queue.empty()) { + if (facet_queue.empty()) + break; + + while (! facet_queue.empty()) { int facet_idx = facet_queue.front(); facet_queue.pop(); - if (seen_facets.find(facet_idx) != seen_facets.end()) continue; - facets.push_back(facet_idx); - for (int j = 0; j <= 2; j++) { - facet_queue.push(this->stl.neighbors_start[facet_idx].neighbor[j]); + if (! facet_visited[facet_idx]) { + facets.emplace_back(facet_idx); + for (int j = 0; j < 3; ++ j) + facet_queue.push(this->stl.neighbors_start[facet_idx].neighbor[j]); + facet_visited[facet_idx] = true; } - seen_facets.insert(facet_idx); } - + TriangleMesh* mesh = new TriangleMesh; - meshes.push_back(mesh); + meshes.emplace_back(mesh); mesh->stl.stats.type = inmemory; mesh->stl.stats.number_of_facets = facets.size(); mesh->stl.stats.original_num_facets = mesh->stl.stats.number_of_facets; stl_clear_error(&mesh->stl); stl_allocate(&mesh->stl); - int first = 1; - for (std::deque<int>::const_iterator facet = facets.begin(); facet != facets.end(); ++facet) { + bool first = true; + for (std::deque<int>::const_iterator facet = facets.begin(); facet != facets.end(); ++ facet) { mesh->stl.facet_start[facet - facets.begin()] = this->stl.facet_start[*facet]; stl_facet_stats(&mesh->stl, this->stl.facet_start[*facet], first); - first = 0; } } return meshes; } -void -TriangleMesh::merge(const TriangleMesh &mesh) +void TriangleMesh::merge(const TriangleMesh &mesh) { // reset stats and metadata int number_of_facets = this->stl.stats.number_of_facets; @@ -577,44 +456,44 @@ ExPolygons TriangleMesh::horizontal_projection() const stl_facet* facet = &this->stl.facet_start[i]; Polygon p; p.points.resize(3); - p.points[0] = Point::new_scale(facet->vertex[0].x, facet->vertex[0].y); - p.points[1] = Point::new_scale(facet->vertex[1].x, facet->vertex[1].y); - p.points[2] = Point::new_scale(facet->vertex[2].x, facet->vertex[2].y); + p.points[0] = Point::new_scale(facet->vertex[0](0), facet->vertex[0](1)); + p.points[1] = Point::new_scale(facet->vertex[1](0), facet->vertex[1](1)); + p.points[2] = Point::new_scale(facet->vertex[2](0), facet->vertex[2](1)); p.make_counter_clockwise(); // do this after scaling, as winding order might change while doing that - pp.push_back(p); + pp.emplace_back(p); } // the offset factor was tuned using groovemount.stl return union_ex(offset(pp, scale_(0.01)), true); } +const float* TriangleMesh::first_vertex() const +{ + return this->stl.facet_start ? &this->stl.facet_start->vertex[0](0) : nullptr; +} + Polygon TriangleMesh::convex_hull() { this->require_shared_vertices(); Points pp; pp.reserve(this->stl.stats.shared_vertices); for (int i = 0; i < this->stl.stats.shared_vertices; ++ i) { - stl_vertex* v = &this->stl.v_shared[i]; - pp.emplace_back(Point::new_scale(v->x, v->y)); + const stl_vertex &v = this->stl.v_shared[i]; + pp.emplace_back(Point::new_scale(v(0), v(1))); } return Slic3r::Geometry::convex_hull(pp); } -BoundingBoxf3 -TriangleMesh::bounding_box() const +BoundingBoxf3 TriangleMesh::bounding_box() const { BoundingBoxf3 bb; bb.defined = true; - bb.min.x = this->stl.stats.min.x; - bb.min.y = this->stl.stats.min.y; - bb.min.z = this->stl.stats.min.z; - bb.max.x = this->stl.stats.max.x; - bb.max.y = this->stl.stats.max.y; - bb.max.z = this->stl.stats.max.z; + bb.min = this->stl.stats.min.cast<double>(); + bb.max = this->stl.stats.max.cast<double>(); return bb; } -BoundingBoxf3 TriangleMesh::transformed_bounding_box(const std::vector<float>& matrix) const +BoundingBoxf3 TriangleMesh::transformed_bounding_box(const Transform3d& t) const { bool has_shared = (stl.v_shared != nullptr); if (!has_shared) @@ -625,16 +504,16 @@ BoundingBoxf3 TriangleMesh::transformed_bounding_box(const std::vector<float>& m if (vertices_count == 0) return BoundingBoxf3(); - Eigen::MatrixXf src_vertices(3, vertices_count); + Eigen::MatrixXd src_vertices(3, vertices_count); if (stl.stats.shared_vertices > 0) { stl_vertex* vertex_ptr = stl.v_shared; for (int i = 0; i < stl.stats.shared_vertices; ++i) { - src_vertices(0, i) = vertex_ptr->x; - src_vertices(1, i) = vertex_ptr->y; - src_vertices(2, i) = vertex_ptr->z; + src_vertices(0, i) = (double)(*vertex_ptr)(0); + src_vertices(1, i) = (double)(*vertex_ptr)(1); + src_vertices(2, i) = (double)(*vertex_ptr)(2); vertex_ptr += 1; } } @@ -646,42 +525,34 @@ BoundingBoxf3 TriangleMesh::transformed_bounding_box(const std::vector<float>& m { for (int i = 0; i < 3; ++i) { - src_vertices(0, v_id) = facet_ptr->vertex[i].x; - src_vertices(1, v_id) = facet_ptr->vertex[i].y; - src_vertices(2, v_id) = facet_ptr->vertex[i].z; + src_vertices(0, v_id) = (double)facet_ptr->vertex[i](0); + src_vertices(1, v_id) = (double)facet_ptr->vertex[i](1); + src_vertices(2, v_id) = (double)facet_ptr->vertex[i](2); + ++v_id; } facet_ptr += 1; - ++v_id; } } if (!has_shared && (stl.stats.shared_vertices > 0)) stl_invalidate_shared_vertices(&stl); - Eigen::Transform<float, 3, Eigen::Affine> m; - ::memcpy((void*)m.data(), (const void*)matrix.data(), 16 * sizeof(float)); - - Eigen::MatrixXf dst_vertices(3, vertices_count); - dst_vertices = m * src_vertices.colwise().homogeneous(); + Eigen::MatrixXd dst_vertices(3, vertices_count); + dst_vertices = t * src_vertices.colwise().homogeneous(); - float min_x = dst_vertices(0, 0); - float max_x = dst_vertices(0, 0); - float min_y = dst_vertices(1, 0); - float max_y = dst_vertices(1, 0); - float min_z = dst_vertices(2, 0); - float max_z = dst_vertices(2, 0); + Vec3d v_min(dst_vertices(0, 0), dst_vertices(1, 0), dst_vertices(2, 0)); + Vec3d v_max = v_min; for (int i = 1; i < vertices_count; ++i) { - min_x = std::min(min_x, dst_vertices(0, i)); - max_x = std::max(max_x, dst_vertices(0, i)); - min_y = std::min(min_y, dst_vertices(1, i)); - max_y = std::max(max_y, dst_vertices(1, i)); - min_z = std::min(min_z, dst_vertices(2, i)); - max_z = std::max(max_z, dst_vertices(2, i)); + for (int j = 0; j < 3; ++j) + { + v_min(j) = std::min(v_min(j), dst_vertices(j, i)); + v_max(j) = std::max(v_max(j), dst_vertices(j, i)); + } } - return BoundingBoxf3(Pointf3((coordf_t)min_x, (coordf_t)min_y, (coordf_t)min_z), Pointf3((coordf_t)max_x, (coordf_t)max_y, (coordf_t)max_z)); + return BoundingBoxf3(v_min, v_max); } TriangleMesh TriangleMesh::convex_hull_3d() const @@ -700,7 +571,7 @@ TriangleMesh TriangleMesh::convex_hull_3d() const for (int i = 0; i < 3; ++i) { const stl_vertex& v = facet_ptr->vertex[i]; - src_vertices.emplace_back(v.x, v.y, v.z); + src_vertices.emplace_back(v(0), v(1), v(2)); } facet_ptr += 1; @@ -720,8 +591,8 @@ TriangleMesh TriangleMesh::convex_hull_3d() const } // Let's collect results: - Pointf3s det_vertices; - std::vector<Point3> facets; + Pointf3s dst_vertices; + std::vector<Vec3crd> facets; auto facet_list = qhull.facetList().toStdVector(); for (const orgQhull::QhullFacet& facet : facet_list) { // iterate through facets @@ -731,25 +602,19 @@ TriangleMesh TriangleMesh::convex_hull_3d() const orgQhull::QhullPoint p = vertices[i].point(); const float* coords = p.coordinates(); - det_vertices.emplace_back(coords[0], coords[1], coords[2]); + dst_vertices.emplace_back(coords[0], coords[1], coords[2]); } - unsigned int size = (unsigned int)det_vertices.size(); + unsigned int size = (unsigned int)dst_vertices.size(); facets.emplace_back(size - 3, size - 2, size - 1); } - TriangleMesh output_mesh(det_vertices, facets); + TriangleMesh output_mesh(dst_vertices, facets); output_mesh.repair(); output_mesh.require_shared_vertices(); return output_mesh; } -const float* TriangleMesh::first_vertex() const -{ - return stl.facet_start ? &stl.facet_start->vertex[0].x : nullptr; -} - -void -TriangleMesh::require_shared_vertices() +void TriangleMesh::require_shared_vertices() { BOOST_LOG_TRIVIAL(trace) << "TriangleMeshSlicer::require_shared_vertices - start"; if (!this->repaired) @@ -769,11 +634,8 @@ TriangleMeshSlicer::TriangleMeshSlicer(TriangleMesh* _mesh) : facets_edges.assign(_mesh->stl.stats.number_of_facets * 3, -1); v_scaled_shared.assign(_mesh->stl.v_shared, _mesh->stl.v_shared + _mesh->stl.stats.shared_vertices); // Scale the copied vertices. - for (int i = 0; i < this->mesh->stl.stats.shared_vertices; ++ i) { - this->v_scaled_shared[i].x /= float(SCALING_FACTOR); - this->v_scaled_shared[i].y /= float(SCALING_FACTOR); - this->v_scaled_shared[i].z /= float(SCALING_FACTOR); - } + for (int i = 0; i < this->mesh->stl.stats.shared_vertices; ++ i) + this->v_scaled_shared[i] *= float(1. / SCALING_FACTOR); // Create a mapping from triangle edge into face. struct EdgeToFace { @@ -847,8 +709,7 @@ TriangleMeshSlicer::TriangleMeshSlicer(TriangleMesh* _mesh) : } } -void -TriangleMeshSlicer::slice(const std::vector<float> &z, std::vector<Polygons>* layers) const +void TriangleMeshSlicer::slice(const std::vector<float> &z, std::vector<Polygons>* layers) const { BOOST_LOG_TRIVIAL(debug) << "TriangleMeshSlicer::slice"; @@ -929,14 +790,14 @@ void TriangleMeshSlicer::_slice_do(size_t facet_idx, std::vector<IntersectionLin const stl_facet &facet = this->mesh->stl.facet_start[facet_idx]; // find facet extents - const float min_z = fminf(facet.vertex[0].z, fminf(facet.vertex[1].z, facet.vertex[2].z)); - const float max_z = fmaxf(facet.vertex[0].z, fmaxf(facet.vertex[1].z, facet.vertex[2].z)); + const float min_z = fminf(facet.vertex[0](2), fminf(facet.vertex[1](2), facet.vertex[2](2))); + const float max_z = fmaxf(facet.vertex[0](2), fmaxf(facet.vertex[1](2), facet.vertex[2](2))); #ifdef SLIC3R_DEBUG printf("\n==> FACET %d (%f,%f,%f - %f,%f,%f - %f,%f,%f):\n", facet_idx, - facet.vertex[0].x, facet.vertex[0].y, facet.vertex[0].z, - facet.vertex[1].x, facet.vertex[1].y, facet.vertex[1].z, - facet.vertex[2].x, facet.vertex[2].y, facet.vertex[2].z); + facet.vertex[0].x, facet.vertex[0].y, facet.vertex[0](2), + facet.vertex[1].x, facet.vertex[1].y, facet.vertex[1](2), + facet.vertex[2].x, facet.vertex[2].y, facet.vertex[2](2)); printf("z: min = %.2f, max = %.2f\n", min_z, max_z); #endif @@ -956,24 +817,24 @@ void TriangleMeshSlicer::_slice_do(size_t facet_idx, std::vector<IntersectionLin if (il.edge_type == feHorizontal) { // Insert all three edges of the face. const int *vertices = this->mesh->stl.v_indices[facet_idx].vertex; - const bool reverse = this->mesh->stl.facet_start[facet_idx].normal.z < 0; + const bool reverse = this->mesh->stl.facet_start[facet_idx].normal(2) < 0; for (int j = 0; j < 3; ++ j) { int a_id = vertices[j % 3]; int b_id = vertices[(j+1) % 3]; if (reverse) std::swap(a_id, b_id); - const stl_vertex *a = &this->v_scaled_shared[a_id]; - const stl_vertex *b = &this->v_scaled_shared[b_id]; - il.a.x = a->x; - il.a.y = a->y; - il.b.x = b->x; - il.b.y = b->y; + const stl_vertex &a = this->v_scaled_shared[a_id]; + const stl_vertex &b = this->v_scaled_shared[b_id]; + il.a(0) = a(0); + il.a(1) = a(1); + il.b(0) = b(0); + il.b(1) = b(1); il.a_id = a_id; il.b_id = b_id; - (*lines)[layer_idx].push_back(il); + (*lines)[layer_idx].emplace_back(il); } } else - (*lines)[layer_idx].push_back(il); + (*lines)[layer_idx].emplace_back(il); } } } @@ -993,7 +854,7 @@ TriangleMeshSlicer::slice(const std::vector<float> &z, std::vector<ExPolygons>* #ifdef SLIC3R_TRIANGLEMESH_DEBUG printf("Layer " PRINTF_ZU " (slice_z = %.2f):\n", layer_id, z[layer_id]); #endif - this->make_expolygons(layers_p[layer_id], &(*layers)[layer_id]); + this->make_expolygons(layers_p[layer_id], &(*layers)[layer_id]); } }); BOOST_LOG_TRIVIAL(debug) << "TriangleMeshSlicer::make_expolygons in parallel - end"; @@ -1013,66 +874,63 @@ bool TriangleMeshSlicer::slice_facet( // Reorder vertices so that the first one is the one with lowest Z. // This is needed to get all intersection lines in a consistent order // (external on the right of the line) - int i = (facet.vertex[1].z == min_z) ? 1 : ((facet.vertex[2].z == min_z) ? 2 : 0); + int i = (facet.vertex[1](2) == min_z) ? 1 : ((facet.vertex[2](2) == min_z) ? 2 : 0); for (int j = i; j - i < 3; ++ j) { // loop through facet edges int edge_id = this->facets_edges[facet_idx * 3 + (j % 3)]; const int *vertices = this->mesh->stl.v_indices[facet_idx].vertex; int a_id = vertices[j % 3]; int b_id = vertices[(j+1) % 3]; - const stl_vertex *a = &this->v_scaled_shared[a_id]; - const stl_vertex *b = &this->v_scaled_shared[b_id]; + const stl_vertex &a = this->v_scaled_shared[a_id]; + const stl_vertex &b = this->v_scaled_shared[b_id]; // Is edge or face aligned with the cutting plane? - if (a->z == slice_z && b->z == slice_z) { + if (a(2) == slice_z && b(2) == slice_z) { // Edge is horizontal and belongs to the current layer. const stl_vertex &v0 = this->v_scaled_shared[vertices[0]]; const stl_vertex &v1 = this->v_scaled_shared[vertices[1]]; const stl_vertex &v2 = this->v_scaled_shared[vertices[2]]; + bool swap = false; if (min_z == max_z) { // All three vertices are aligned with slice_z. line_out->edge_type = feHorizontal; - if (this->mesh->stl.facet_start[facet_idx].normal.z < 0) { + if (this->mesh->stl.facet_start[facet_idx].normal(2) < 0) { // If normal points downwards this is a bottom horizontal facet so we reverse its point order. - std::swap(a, b); - std::swap(a_id, b_id); + swap = true; } - } else if (v0.z < slice_z || v1.z < slice_z || v2.z < slice_z) { + } else if (v0(2) < slice_z || v1(2) < slice_z || v2(2) < slice_z) { // Two vertices are aligned with the cutting plane, the third vertex is below the cutting plane. line_out->edge_type = feTop; - std::swap(a, b); - std::swap(a_id, b_id); + swap = true; } else { // Two vertices are aligned with the cutting plane, the third vertex is above the cutting plane. line_out->edge_type = feBottom; } - line_out->a.x = a->x; - line_out->a.y = a->y; - line_out->b.x = b->x; - line_out->b.y = b->y; - line_out->a_id = a_id; - line_out->b_id = b_id; + line_out->a = to_2d(swap ? b : a).cast<coord_t>(); + line_out->b = to_2d(swap ? a : b).cast<coord_t>(); + line_out->a_id = swap ? b_id : a_id; + line_out->b_id = swap ? a_id : b_id; return true; } - if (a->z == slice_z) { + if (a(2) == slice_z) { // Only point a alings with the cutting plane. points_on_layer[num_points_on_layer ++] = num_points; IntersectionPoint &point = points[num_points ++]; - point.x = a->x; - point.y = a->y; + point(0) = a(0); + point(1) = a(1); point.point_id = a_id; - } else if (b->z == slice_z) { + } else if (b(2) == slice_z) { // Only point b alings with the cutting plane. points_on_layer[num_points_on_layer ++] = num_points; IntersectionPoint &point = points[num_points ++]; - point.x = b->x; - point.y = b->y; + point(0) = b(0); + point(1) = b(1); point.point_id = b_id; - } else if ((a->z < slice_z && b->z > slice_z) || (b->z < slice_z && a->z > slice_z)) { + } else if ((a(2) < slice_z && b(2) > slice_z) || (b(2) < slice_z && a(2) > slice_z)) { // A general case. The face edge intersects the cutting plane. Calculate the intersection point. IntersectionPoint &point = points[num_points ++]; - point.x = b->x + (a->x - b->x) * (slice_z - b->z) / (a->z - b->z); - point.y = b->y + (a->y - b->y) * (slice_z - b->z) / (a->z - b->z); + point(0) = b(0) + (a(0) - b(0)) * (slice_z - b(2)) / (a(2) - b(2)); + point(1) = b(1) + (a(1) - b(1)) * (slice_z - b(2)) / (a(2) - b(2)); point.edge_id = edge_id; } } @@ -1343,8 +1201,8 @@ void TriangleMeshSlicer::make_loops(std::vector<IntersectionLine> &lines, Polygo if ((ip1.edge_id != -1 && ip1.edge_id == ip2.edge_id) || (ip1.point_id != -1 && ip1.point_id == ip2.point_id)) { // The current loop is complete. Add it to the output. - assert(opl.points.front().point_id == opl.points.back().point_id); - assert(opl.points.front().edge_id == opl.points.back().edge_id); + /*assert(opl.points.front().point_id == opl.points.back().point_id); + assert(opl.points.front().edge_id == opl.points.back().edge_id);*/ // Remove the duplicate last point. opl.points.pop_back(); if (opl.points.size() >= 3) { @@ -1353,7 +1211,7 @@ void TriangleMeshSlicer::make_loops(std::vector<IntersectionLine> &lines, Polygo // Orient the patched up polygons CCW. This heuristic may close some holes and cavities. double area = 0.; for (size_t i = 0, j = opl.points.size() - 1; i < opl.points.size(); j = i ++) - area += double(opl.points[j].x + opl.points[i].x) * double(opl.points[i].y - opl.points[j].y); + area += double(opl.points[j](0) + opl.points[i](0)) * double(opl.points[i](1) - opl.points[j](1)); if (area < 0) std::reverse(opl.points.begin(), opl.points.end()); loops->emplace_back(std::move(opl.points)); @@ -1380,9 +1238,9 @@ void TriangleMeshSlicer::make_expolygons_simple(std::vector<IntersectionLine> &l if (loop->area() >= 0.) { ExPolygon ex; ex.contour = *loop; - slices->push_back(ex); + slices->emplace_back(ex); } else { - holes.push_back(*loop); + holes.emplace_back(*loop); } } @@ -1473,8 +1331,8 @@ void TriangleMeshSlicer::make_expolygons(const Polygons &loops, ExPolygons* slic //std::vector<double> area; //std::vector<size_t> sorted_area; // vector of indices //for (Polygons::const_iterator loop = loops.begin(); loop != loops.end(); ++ loop) { - // area.push_back(loop->area()); - // sorted_area.push_back(loop - loops.begin()); + // area.emplace_back(loop->area()); + // sorted_area.emplace_back(loop - loops.begin()); //} // //// outer first @@ -1489,7 +1347,7 @@ void TriangleMeshSlicer::make_expolygons(const Polygons &loops, ExPolygons* slic // would do the same, thus repeating the calculation */ // Polygons::const_iterator loop = loops.begin() + *loop_idx; // if (area[*loop_idx] > +EPSILON) - // p_slices.push_back(*loop); + // p_slices.emplace_back(*loop); // else if (area[*loop_idx] < -EPSILON) // //FIXME This is arbitrary and possibly very slow. // // If the hole is inside a polygon, then there is no need to diff. @@ -1539,20 +1397,20 @@ void TriangleMeshSlicer::cut(float z, TriangleMesh* upper, TriangleMesh* lower) stl_facet* facet = &this->mesh->stl.facet_start[facet_idx]; // find facet extents - float min_z = std::min(facet->vertex[0].z, std::min(facet->vertex[1].z, facet->vertex[2].z)); - float max_z = std::max(facet->vertex[0].z, std::max(facet->vertex[1].z, facet->vertex[2].z)); + float min_z = std::min(facet->vertex[0](2), std::min(facet->vertex[1](2), facet->vertex[2](2))); + float max_z = std::max(facet->vertex[0](2), std::max(facet->vertex[1](2), facet->vertex[2](2))); // intersect facet with cutting plane IntersectionLine line; if (this->slice_facet(scaled_z, *facet, facet_idx, min_z, max_z, &line)) { // Save intersection lines for generating correct triangulations. if (line.edge_type == feTop) { - lower_lines.push_back(line); + lower_lines.emplace_back(line); } else if (line.edge_type == feBottom) { - upper_lines.push_back(line); + upper_lines.emplace_back(line); } else if (line.edge_type != feHorizontal) { - lower_lines.push_back(line); - upper_lines.push_back(line); + lower_lines.emplace_back(line); + upper_lines.emplace_back(line); } } @@ -1567,47 +1425,47 @@ void TriangleMeshSlicer::cut(float z, TriangleMesh* upper, TriangleMesh* lower) // look for the vertex on whose side of the slicing plane there are no other vertices int isolated_vertex; - if ( (facet->vertex[0].z > z) == (facet->vertex[1].z > z) ) { + if ( (facet->vertex[0](2) > z) == (facet->vertex[1](2) > z) ) { isolated_vertex = 2; - } else if ( (facet->vertex[1].z > z) == (facet->vertex[2].z > z) ) { + } else if ( (facet->vertex[1](2) > z) == (facet->vertex[2](2) > z) ) { isolated_vertex = 0; } else { isolated_vertex = 1; } // get vertices starting from the isolated one - stl_vertex* v0 = &facet->vertex[isolated_vertex]; - stl_vertex* v1 = &facet->vertex[(isolated_vertex+1) % 3]; - stl_vertex* v2 = &facet->vertex[(isolated_vertex+2) % 3]; + const stl_vertex &v0 = facet->vertex[isolated_vertex]; + const stl_vertex &v1 = facet->vertex[(isolated_vertex+1) % 3]; + const stl_vertex &v2 = facet->vertex[(isolated_vertex+2) % 3]; // intersect v0-v1 and v2-v0 with cutting plane and make new vertices stl_vertex v0v1, v2v0; - v0v1.x = v1->x + (v0->x - v1->x) * (z - v1->z) / (v0->z - v1->z); - v0v1.y = v1->y + (v0->y - v1->y) * (z - v1->z) / (v0->z - v1->z); - v0v1.z = z; - v2v0.x = v2->x + (v0->x - v2->x) * (z - v2->z) / (v0->z - v2->z); - v2v0.y = v2->y + (v0->y - v2->y) * (z - v2->z) / (v0->z - v2->z); - v2v0.z = z; + v0v1(0) = v1(0) + (v0(0) - v1(0)) * (z - v1(2)) / (v0(2) - v1(2)); + v0v1(1) = v1(1) + (v0(1) - v1(1)) * (z - v1(2)) / (v0(2) - v1(2)); + v0v1(2) = z; + v2v0(0) = v2(0) + (v0(0) - v2(0)) * (z - v2(2)) / (v0(2) - v2(2)); + v2v0(1) = v2(1) + (v0(1) - v2(1)) * (z - v2(2)) / (v0(2) - v2(2)); + v2v0(2) = z; // build the triangular facet stl_facet triangle; triangle.normal = facet->normal; - triangle.vertex[0] = *v0; + triangle.vertex[0] = v0; triangle.vertex[1] = v0v1; triangle.vertex[2] = v2v0; // build the facets forming a quadrilateral on the other side stl_facet quadrilateral[2]; quadrilateral[0].normal = facet->normal; - quadrilateral[0].vertex[0] = *v1; - quadrilateral[0].vertex[1] = *v2; + quadrilateral[0].vertex[0] = v1; + quadrilateral[0].vertex[1] = v2; quadrilateral[0].vertex[2] = v0v1; quadrilateral[1].normal = facet->normal; - quadrilateral[1].vertex[0] = *v2; + quadrilateral[1].vertex[0] = v2; quadrilateral[1].vertex[1] = v2v0; quadrilateral[1].vertex[2] = v0v1; - if (v0->z > z) { + if (v0(2) > z) { if (upper != NULL) stl_add_facet(&upper->stl, &triangle); if (lower != NULL) { stl_add_facet(&lower->stl, &quadrilateral[0]); @@ -1639,13 +1497,11 @@ void TriangleMeshSlicer::cut(float z, TriangleMesh* upper, TriangleMesh* lower) Polygon p = *polygon; p.reverse(); stl_facet facet; - facet.normal.x = 0; - facet.normal.y = 0; - facet.normal.z = -1; + facet.normal = stl_normal(0, 0, -1.f); for (size_t i = 0; i <= 2; ++i) { - facet.vertex[i].x = unscale(p.points[i].x); - facet.vertex[i].y = unscale(p.points[i].y); - facet.vertex[i].z = z; + facet.vertex[i](0) = unscale<float>(p.points[i](0)); + facet.vertex[i](1) = unscale<float>(p.points[i](1)); + facet.vertex[i](2) = z; } stl_add_facet(&upper->stl, &facet); } @@ -1665,13 +1521,11 @@ void TriangleMeshSlicer::cut(float z, TriangleMesh* upper, TriangleMesh* lower) // convert triangles to facets and append them to mesh for (Polygons::const_iterator polygon = triangles.begin(); polygon != triangles.end(); ++polygon) { stl_facet facet; - facet.normal.x = 0; - facet.normal.y = 0; - facet.normal.z = 1; + facet.normal = stl_normal(0, 0, 1.f); for (size_t i = 0; i <= 2; ++i) { - facet.vertex[i].x = unscale(polygon->points[i].x); - facet.vertex[i].y = unscale(polygon->points[i].y); - facet.vertex[i].z = z; + facet.vertex[i](0) = unscale<float>(polygon->points[i](0)); + facet.vertex[i](1) = unscale<float>(polygon->points[i](1)); + facet.vertex[i](2) = z; } stl_add_facet(&lower->stl, &facet); } @@ -1684,19 +1538,19 @@ void TriangleMeshSlicer::cut(float z, TriangleMesh* upper, TriangleMesh* lower) // Generate the vertex list for a cube solid of arbitrary size in X/Y/Z. TriangleMesh make_cube(double x, double y, double z) { - Pointf3 pv[8] = { - Pointf3(x, y, 0), Pointf3(x, 0, 0), Pointf3(0, 0, 0), - Pointf3(0, y, 0), Pointf3(x, y, z), Pointf3(0, y, z), - Pointf3(0, 0, z), Pointf3(x, 0, z) + Vec3d pv[8] = { + Vec3d(x, y, 0), Vec3d(x, 0, 0), Vec3d(0, 0, 0), + Vec3d(0, y, 0), Vec3d(x, y, z), Vec3d(0, y, z), + Vec3d(0, 0, z), Vec3d(x, 0, z) }; - Point3 fv[12] = { - Point3(0, 1, 2), Point3(0, 2, 3), Point3(4, 5, 6), - Point3(4, 6, 7), Point3(0, 4, 7), Point3(0, 7, 1), - Point3(1, 7, 6), Point3(1, 6, 2), Point3(2, 6, 5), - Point3(2, 5, 3), Point3(4, 0, 3), Point3(4, 3, 5) + Vec3crd fv[12] = { + Vec3crd(0, 1, 2), Vec3crd(0, 2, 3), Vec3crd(4, 5, 6), + Vec3crd(4, 6, 7), Vec3crd(0, 4, 7), Vec3crd(0, 7, 1), + Vec3crd(1, 7, 6), Vec3crd(1, 6, 2), Vec3crd(2, 6, 5), + Vec3crd(2, 5, 3), Vec3crd(4, 0, 3), Vec3crd(4, 3, 5) }; - std::vector<Point3> facets(&fv[0], &fv[0]+12); + std::vector<Vec3crd> facets(&fv[0], &fv[0]+12); Pointf3s vertices(&pv[0], &pv[0]+8); TriangleMesh mesh(vertices ,facets); @@ -1708,11 +1562,11 @@ TriangleMesh make_cube(double x, double y, double z) { // Default is 360 sides, angle fa is in radians. TriangleMesh make_cylinder(double r, double h, double fa) { Pointf3s vertices; - std::vector<Point3> facets; + std::vector<Vec3crd> facets; // 2 special vertices, top and bottom center, rest are relative to this - vertices.push_back(Pointf3(0.0, 0.0, 0.0)); - vertices.push_back(Pointf3(0.0, 0.0, h)); + vertices.emplace_back(Vec3d(0.0, 0.0, 0.0)); + vertices.emplace_back(Vec3d(0.0, 0.0, h)); // adjust via rounding to get an even multiple for any provided angle. double angle = (2*PI / floor(2*PI / fa)); @@ -1722,26 +1576,23 @@ TriangleMesh make_cylinder(double r, double h, double fa) { // top and bottom. // Special case: Last line shares 2 vertices with the first line. unsigned id = vertices.size() - 1; - vertices.push_back(Pointf3(sin(0) * r , cos(0) * r, 0)); - vertices.push_back(Pointf3(sin(0) * r , cos(0) * r, h)); + vertices.emplace_back(Vec3d(sin(0) * r , cos(0) * r, 0)); + vertices.emplace_back(Vec3d(sin(0) * r , cos(0) * r, h)); for (double i = 0; i < 2*PI; i+=angle) { - Pointf3 b(0, r, 0); - Pointf3 t(0, r, h); - b.rotate(i, Pointf3(0,0,0)); - t.rotate(i, Pointf3(0,0,h)); - vertices.push_back(b); - vertices.push_back(t); + Vec2d p = Eigen::Rotation2Dd(i) * Eigen::Vector2d(0, r); + vertices.emplace_back(Vec3d(p(0), p(1), 0.)); + vertices.emplace_back(Vec3d(p(0), p(1), h)); id = vertices.size() - 1; - facets.push_back(Point3( 0, id - 1, id - 3)); // top - facets.push_back(Point3(id, 1, id - 2)); // bottom - facets.push_back(Point3(id, id - 2, id - 3)); // upper-right of side - facets.push_back(Point3(id, id - 3, id - 1)); // bottom-left of side + facets.emplace_back(Vec3crd( 0, id - 1, id - 3)); // top + facets.emplace_back(Vec3crd(id, 1, id - 2)); // bottom + facets.emplace_back(Vec3crd(id, id - 2, id - 3)); // upper-right of side + facets.emplace_back(Vec3crd(id, id - 3, id - 1)); // bottom-left of side } // Connect the last set of vertices with the first. - facets.push_back(Point3( 2, 0, id - 1)); - facets.push_back(Point3( 1, 3, id)); - facets.push_back(Point3(id, 3, 2)); - facets.push_back(Point3(id, 2, id - 1)); + facets.emplace_back(Vec3crd( 2, 0, id - 1)); + facets.emplace_back(Vec3crd( 1, 3, id)); + facets.emplace_back(Vec3crd(id, 3, 2)); + facets.emplace_back(Vec3crd(id, 2, id - 1)); TriangleMesh mesh(vertices, facets); return mesh; @@ -1752,7 +1603,7 @@ TriangleMesh make_cylinder(double r, double h, double fa) { // Default angle is 1 degree. TriangleMesh make_sphere(double rho, double fa) { Pointf3s vertices; - std::vector<Point3> facets; + std::vector<Vec3crd> facets; // Algorithm: // Add points one-by-one to the sphere grid and form facets using relative coordinates. @@ -1764,29 +1615,24 @@ TriangleMesh make_sphere(double rho, double fa) { // Ring to be scaled to generate the steps of the sphere std::vector<double> ring; for (double i = 0; i < 2*PI; i+=angle) { - ring.push_back(i); + ring.emplace_back(i); } const size_t steps = ring.size(); const double increment = (double)(1.0 / (double)steps); // special case: first ring connects to 0,0,0 // insert and form facets. - vertices.push_back(Pointf3(0.0, 0.0, -rho)); + vertices.emplace_back(Vec3d(0.0, 0.0, -rho)); size_t id = vertices.size(); for (size_t i = 0; i < ring.size(); i++) { // Fixed scaling const double z = -rho + increment*rho*2.0; // radius of the circle for this step. const double r = sqrt(abs(rho*rho - z*z)); - Pointf3 b(0, r, z); - b.rotate(ring[i], Pointf3(0,0,z)); - vertices.push_back(b); - if (i == 0) { - facets.push_back(Point3(1, 0, ring.size())); - } else { - facets.push_back(Point3(id, 0, id - 1)); - } - id++; + Vec2d b = Eigen::Rotation2Dd(ring[i]) * Eigen::Vector2d(0, r); + vertices.emplace_back(Vec3d(b(0), b(1), z)); + facets.emplace_back((i == 0) ? Vec3crd(1, 0, ring.size()) : Vec3crd(id, 0, id - 1)); + ++ id; } // General case: insert and form facets for each step, joining it to the ring below it. @@ -1795,16 +1641,15 @@ TriangleMesh make_sphere(double rho, double fa) { const double r = sqrt(abs(rho*rho - z*z)); for (size_t i = 0; i < ring.size(); i++) { - Pointf3 b(0, r, z); - b.rotate(ring[i], Pointf3(0,0,z)); - vertices.push_back(b); + Vec2d b = Eigen::Rotation2Dd(ring[i]) * Eigen::Vector2d(0, r); + vertices.emplace_back(Vec3d(b(0), b(1), z)); if (i == 0) { // wrap around - facets.push_back(Point3(id + ring.size() - 1 , id, id - 1)); - facets.push_back(Point3(id, id - ring.size(), id - 1)); + facets.emplace_back(Vec3crd(id + ring.size() - 1 , id, id - 1)); + facets.emplace_back(Vec3crd(id, id - ring.size(), id - 1)); } else { - facets.push_back(Point3(id , id - ring.size(), (id - 1) - ring.size())); - facets.push_back(Point3(id, id - 1 - ring.size() , id - 1)); + facets.emplace_back(Vec3crd(id , id - ring.size(), (id - 1) - ring.size())); + facets.emplace_back(Vec3crd(id, id - 1 - ring.size() , id - 1)); } id++; } @@ -1813,13 +1658,13 @@ TriangleMesh make_sphere(double rho, double fa) { // special case: last ring connects to 0,0,rho*2.0 // only form facets. - vertices.push_back(Pointf3(0.0, 0.0, rho)); + vertices.emplace_back(Vec3d(0.0, 0.0, rho)); for (size_t i = 0; i < ring.size(); i++) { if (i == 0) { // third vertex is on the other side of the ring. - facets.push_back(Point3(id, id - ring.size(), id - 1)); + facets.emplace_back(Vec3crd(id, id - ring.size(), id - 1)); } else { - facets.push_back(Point3(id, id - ring.size() + i, id - ring.size() + (i - 1))); + facets.emplace_back(Vec3crd(id, id - ring.size() + i, id - ring.size() + (i - 1))); } } id++; diff --git a/xs/src/libslic3r/TriangleMesh.hpp b/xs/src/libslic3r/TriangleMesh.hpp index 72e541afc..aebed4a2e 100644 --- a/xs/src/libslic3r/TriangleMesh.hpp +++ b/xs/src/libslic3r/TriangleMesh.hpp @@ -20,35 +20,35 @@ typedef std::vector<TriangleMesh*> TriangleMeshPtrs; class TriangleMesh { public: - TriangleMesh(); - TriangleMesh(const Pointf3s &points, const std::vector<Point3> &facets); - TriangleMesh(const TriangleMesh &other); - TriangleMesh(TriangleMesh &&other); + TriangleMesh() : repaired(false) { stl_initialize(&this->stl); } + TriangleMesh(const Pointf3s &points, const std::vector<Vec3crd> &facets); + TriangleMesh(const TriangleMesh &other) : repaired(false) { stl_initialize(&this->stl); *this = other; } + TriangleMesh(TriangleMesh &&other) : repaired(false) { stl_initialize(&this->stl); this->swap(other); } + ~TriangleMesh() { stl_close(&this->stl); } TriangleMesh& operator=(const TriangleMesh &other); - TriangleMesh& operator=(TriangleMesh &&other); - void swap(TriangleMesh &other); - ~TriangleMesh(); - void ReadSTLFile(const char* input_file); - void write_ascii(const char* output_file); - void write_binary(const char* output_file); + TriangleMesh& operator=(TriangleMesh &&other) { this->swap(other); return *this; } + void swap(TriangleMesh &other) { std::swap(this->stl, other.stl); std::swap(this->repaired, other.repaired); } + void ReadSTLFile(const char* input_file) { stl_open(&stl, input_file); } + void write_ascii(const char* output_file) { stl_write_ascii(&this->stl, output_file, ""); } + void write_binary(const char* output_file) { stl_write_binary(&this->stl, output_file, ""); } void repair(); float volume(); void check_topology(); - bool is_manifold() const; + bool is_manifold() const { return this->stl.stats.connected_facets_3_edge == this->stl.stats.number_of_facets; } void WriteOBJFile(char* output_file); void scale(float factor); - void scale(const Pointf3 &versor); + void scale(const Vec3d &versor); void translate(float x, float y, float z); void rotate(float angle, const Axis &axis); - void rotate(float angle, Pointf3 axis); - void rotate_x(float angle); - void rotate_y(float angle); - void rotate_z(float angle); + void rotate(float angle, const Vec3d& axis); + void rotate_x(float angle) { this->rotate(angle, X); } + void rotate_y(float angle) { this->rotate(angle, Y); } + void rotate_z(float angle) { this->rotate(angle, Z); } void mirror(const Axis &axis); - void mirror_x(); - void mirror_y(); - void mirror_z(); - void transform(const float* matrix3x4); + void mirror_x() { this->mirror(X); } + void mirror_y() { this->mirror(Y); } + void mirror_z() { this->mirror(Z); } + void transform(const Transform3f& t); void align_to_origin(); void rotate(double angle, Point* center); TriangleMeshPtrs split() const; @@ -57,13 +57,13 @@ public: const float* first_vertex() const; Polygon convex_hull(); BoundingBoxf3 bounding_box() const; - // Returns the bbox of this TriangleMesh transformed by the given matrix - BoundingBoxf3 transformed_bounding_box(const std::vector<float>& matrix) const; + // Returns the bbox of this TriangleMesh transformed by the given transformation + BoundingBoxf3 transformed_bounding_box(const Transform3d& t) const; // Returns the convex hull of this TriangleMesh TriangleMesh convex_hull_3d() const; void reset_repair_stats(); bool needed_repair() const; - size_t facets_count() const; + size_t facets_count() const { return this->stl.stats.number_of_facets; } // Returns true, if there are two and more connected patches in the mesh. // Returns false, if one or zero connected patch is in the mesh. diff --git a/xs/src/libslic3r/Utils.hpp b/xs/src/libslic3r/Utils.hpp index 349222854..f1390b8a2 100644 --- a/xs/src/libslic3r/Utils.hpp +++ b/xs/src/libslic3r/Utils.hpp @@ -97,8 +97,9 @@ public: void call(int i) const; void call(int i, int j) const; void call(const std::vector<int>& ints) const; - void call(double d) const; + void call(double a) const; void call(double a, double b) const; + void call(double a, double b, double c) const; void call(double a, double b, double c, double d) const; void call(bool b) const; private: diff --git a/xs/src/libslic3r/libslic3r.h b/xs/src/libslic3r/libslic3r.h index ddd056bc7..925e93031 100644 --- a/xs/src/libslic3r/libslic3r.h +++ b/xs/src/libslic3r/libslic3r.h @@ -45,7 +45,6 @@ typedef double coordf_t; //FIXME Better to use an inline function with an explicit return type. //inline coord_t scale_(coordf_t v) { return coord_t(floor(v / SCALING_FACTOR + 0.5f)); } #define scale_(val) ((val) / SCALING_FACTOR) -#define unscale(val) ((val) * SCALING_FACTOR) #define SCALED_EPSILON scale_(EPSILON) /* Implementation of CONFESS("foo"): */ #ifdef _MSC_VER @@ -102,6 +101,9 @@ inline std::string debug_out_path(const char *name, ...) namespace Slic3r { +template<typename T, typename Q> +inline T unscale(Q v) { return T(v) * T(SCALING_FACTOR); } + enum Axis { X=0, Y, Z, E, F, NUM_AXES }; template <class T> @@ -130,6 +132,17 @@ inline void append(std::vector<T>& dest, std::vector<T>&& src) src.shrink_to_fit(); } +// Casting an std::vector<> from one type to another type without warnings about a loss of accuracy. +template<typename T_TO, typename T_FROM> +std::vector<T_TO> cast(const std::vector<T_FROM> &src) +{ + std::vector<T_TO> dst; + dst.reserve(src.size()); + for (const T_FROM &a : src) + dst.emplace_back((T_TO)a); + return dst; +} + template <typename T> inline void remove_nulls(std::vector<T*> &vec) { diff --git a/xs/src/libslic3r/utils.cpp b/xs/src/libslic3r/utils.cpp index 55164bbdd..95aaf5453 100644 --- a/xs/src/libslic3r/utils.cpp +++ b/xs/src/libslic3r/utils.cpp @@ -251,7 +251,7 @@ void PerlCallback::call(const std::vector<int>& ints) const LEAVE; } -void PerlCallback::call(double d) const +void PerlCallback::call(double a) const { if (!m_callback) return; @@ -259,7 +259,7 @@ void PerlCallback::call(double d) const ENTER; SAVETMPS; PUSHMARK(SP); - XPUSHs(sv_2mortal(newSVnv(d))); + XPUSHs(sv_2mortal(newSVnv(a))); PUTBACK; perl_call_sv(SvRV((SV*)m_callback), G_DISCARD); FREETMPS; @@ -282,6 +282,23 @@ void PerlCallback::call(double a, double b) const LEAVE; } +void PerlCallback::call(double a, double b, double c) const +{ + if (!m_callback) + return; + dSP; + ENTER; + SAVETMPS; + PUSHMARK(SP); + XPUSHs(sv_2mortal(newSVnv(a))); + XPUSHs(sv_2mortal(newSVnv(b))); + XPUSHs(sv_2mortal(newSVnv(c))); + PUTBACK; + perl_call_sv(SvRV((SV*)m_callback), G_DISCARD); + FREETMPS; + LEAVE; +} + void PerlCallback::call(double a, double b, double c, double d) const { if (!m_callback) |