diff options
Diffstat (limited to 'src/libslic3r/Point.hpp')
-rw-r--r-- | src/libslic3r/Point.hpp | 153 |
1 files changed, 132 insertions, 21 deletions
diff --git a/src/libslic3r/Point.hpp b/src/libslic3r/Point.hpp index dced5c02a..a6525af4e 100644 --- a/src/libslic3r/Point.hpp +++ b/src/libslic3r/Point.hpp @@ -13,6 +13,7 @@ namespace Slic3r { +class BoundingBox; class Line; class MultiPoint; class Point; @@ -24,7 +25,9 @@ typedef Eigen::Matrix<coord_t, 2, 1, Eigen::DontAlign> Vec2crd; typedef Eigen::Matrix<coord_t, 3, 1, Eigen::DontAlign> Vec3crd; typedef Eigen::Matrix<int, 2, 1, Eigen::DontAlign> Vec2i; typedef Eigen::Matrix<int, 3, 1, Eigen::DontAlign> Vec3i; +typedef Eigen::Matrix<int32_t, 2, 1, Eigen::DontAlign> Vec2i32; typedef Eigen::Matrix<int64_t, 2, 1, Eigen::DontAlign> Vec2i64; +typedef Eigen::Matrix<int32_t, 3, 1, Eigen::DontAlign> Vec3i32; typedef Eigen::Matrix<int64_t, 3, 1, Eigen::DontAlign> Vec3i64; // Vector types with a double coordinate base type. @@ -53,20 +56,20 @@ 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)); } +// One likely does not want to perform the cross product with a 32bit accumulator. +//inline int32_t cross2(const Vec2i32 &v1, const Vec2i32 &v2) { return v1(0) * v2(1) - v1(1) * v2(0); } 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)); } +template<typename T, int Options> +inline Eigen::Matrix<T, 2, 1, Eigen::DontAlign> perp(const Eigen::MatrixBase<Eigen::Matrix<T, 2, 1, Options>> &v) { return Eigen::Matrix<T, 2, 1, Eigen::DontAlign>(- v.y(), v.x()); } -inline Vec3d to_3d(const Vec2d &v, double z) { return Vec3d(v(0), v(1), z); } -inline Vec3f to_3d(const Vec2f &v, float z) { return Vec3f(v(0), v(1), z); } -inline Vec3i64 to_3d(const Vec2i64 &v, float z) { return Vec3i64(int64_t(v(0)), int64_t(v(1)), int64_t(z)); } -inline Vec3crd to_3d(const Vec3crd &p, coord_t z) { return Vec3crd(p(0), p(1), z); } +template<class T, int N, int Options> +Eigen::Matrix<T, 2, 1, Eigen::DontAlign> to_2d(const Eigen::MatrixBase<Eigen::Matrix<T, N, 1, Options>> &ptN) { return { ptN(0), ptN(1) }; } + +template<class T, int Options> +Eigen::Matrix<T, 3, 1, Eigen::DontAlign> to_3d(const Eigen::MatrixBase<Eigen::Matrix<T, 2, 1, Options>> & pt, const T z) { return { pt(0), pt(1), z }; } 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))); } @@ -83,14 +86,16 @@ inline std::string to_string(const Vec3d &pt) { return std::string("[") + std: std::vector<Vec3f> transform(const std::vector<Vec3f>& points, const Transform3f& t); Pointf3s transform(const Pointf3s& points, const Transform3d& t); +template<int N, class T> using Vec = Eigen::Matrix<T, N, 1, Eigen::DontAlign, N, 1>; + class Point : public Vec2crd { public: typedef coord_t coord_type; Point() : Vec2crd(0, 0) {} - Point(coord_t x, coord_t y) : Vec2crd(x, y) {} - Point(int64_t x, int64_t y) : Vec2crd(coord_t(x), coord_t(y)) {} // for Clipper + Point(int32_t x, int32_t y) : Vec2crd(coord_t(x), coord_t(y)) {} + Point(int64_t x, int64_t y) : Vec2crd(coord_t(x), coord_t(y)) {} Point(double x, double y) : Vec2crd(coord_t(lrint(x)), coord_t(lrint(y))) {} Point(const Point &rhs) { *this = rhs; } explicit Point(const Vec2d& rhs) : Vec2crd(coord_t(lrint(rhs.x())), coord_t(lrint(rhs.y()))) {} @@ -98,6 +103,7 @@ public: 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))); } + static Point new_scale(const Vec2d &v) { return Point(coord_t(scale_(v.x())), coord_t(scale_(v.y()))); } // This method allows you to assign Eigen expressions to MyVectorType template<typename OtherDerived> @@ -112,10 +118,19 @@ public: Point& operator+=(const Point& rhs) { (*this)(0) += rhs(0); (*this)(1) += rhs(1); return *this; } Point& operator-=(const Point& rhs) { (*this)(0) -= rhs(0); (*this)(1) -= rhs(1); return *this; } Point& operator*=(const double &rhs) { (*this)(0) = coord_t((*this)(0) * rhs); (*this)(1) = coord_t((*this)(1) * rhs); return *this; } + Point operator*(const double &rhs) { return Point((*this)(0) * rhs, (*this)(1) * rhs); } + + void rotate(double angle) { this->rotate(std::cos(angle), std::sin(angle)); } + void rotate(double cos_a, double sin_a) { + double cur_x = (double)(*this)(0); + double cur_y = (double)(*this)(1); + (*this)(0) = (coord_t)round(cos_a * cur_x - sin_a * cur_y); + (*this)(1) = (coord_t)round(cos_a * cur_y + sin_a * cur_x); + } - 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 cos_a, double sin_a) const { Point res(*this); res.rotate(cos_a, sin_a); 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; @@ -158,6 +173,15 @@ inline bool is_approx(const Vec3d &p1, const Vec3d &p2, double epsilon = EPSILON return d.x() < epsilon && d.y() < epsilon && d.z() < epsilon; } +inline Point lerp(const Point &a, const Point &b, double t) +{ + assert((t >= -EPSILON) && (t <= 1. + EPSILON)); + return ((1. - t) * a.cast<double>() + t * b.cast<double>()).cast<coord_t>(); +} + +extern BoundingBox get_extents(const Points &pts); +extern BoundingBox get_extents(const std::vector<Points> &pts); + namespace int128 { // Exact orientation predicate, // returns +1: CCW, 0: collinear, -1: CW. @@ -275,6 +299,33 @@ public: std::make_pair(nullptr, std::numeric_limits<double>::max()); } + // Returns all pairs of values and squared distances. + std::vector<std::pair<const ValueType*, double>> find_all(const Vec2crd &pt) { + // Iterate over 4 closest grid cells around pt, + // Round pt to a closest grid_cell corner. + Vec2crd grid_corner((pt(0)+(m_grid_resolution>>1))>>m_grid_log2, (pt(1)+(m_grid_resolution>>1))>>m_grid_log2); + // For four neighbors of grid_corner: + std::vector<std::pair<const ValueType*, double>> out; + const double r2 = double(m_search_radius) * m_search_radius; + for (coord_t neighbor_y = -1; neighbor_y < 1; ++ neighbor_y) { + for (coord_t neighbor_x = -1; neighbor_x < 1; ++ neighbor_x) { + // Range of fragment starts around grid_corner, close to pt. + auto range = m_map.equal_range(Vec2crd(grid_corner(0) + neighbor_x, grid_corner(1) + neighbor_y)); + // Find the map entry closest to pt. + for (auto it = range.first; it != range.second; ++it) { + const ValueType &value = it->second; + const Vec2crd *pt2 = m_point_accessor(value); + if (pt2 != nullptr) { + const double d2 = (pt - *pt2).cast<double>().squaredNorm(); + if (d2 <= r2) + out.emplace_back(&value, d2); + } + } + } + } + return out; + } + private: typedef typename std::unordered_multimap<Vec2crd, ValueType, PointHash> map_type; PointAccessor m_point_accessor; @@ -286,6 +337,72 @@ private: std::ostream& operator<<(std::ostream &stm, const Vec2d &pointf); + +// ///////////////////////////////////////////////////////////////////////////// +// Type safe conversions to and from scaled and unscaled coordinates +// ///////////////////////////////////////////////////////////////////////////// + +// Semantics are the following: +// Upscaling (scaled()): only from floating point types (or Vec) to either +// floating point or integer 'scaled coord' coordinates. +// Downscaling (unscaled()): from arithmetic (or Vec) to floating point only + +// Conversion definition from unscaled to floating point scaled +template<class Tout, + class Tin, + class = FloatingOnly<Tin>> +inline constexpr FloatingOnly<Tout> scaled(const Tin &v) noexcept +{ + return Tout(v / Tin(SCALING_FACTOR)); +} + +// Conversion definition from unscaled to integer 'scaled coord'. +// TODO: is the rounding necessary? Here it is commented out to show that +// it can be different for integers but it does not have to be. Using +// std::round means loosing noexcept and constexpr modifiers +template<class Tout = coord_t, class Tin, class = FloatingOnly<Tin>> +inline constexpr ScaledCoordOnly<Tout> scaled(const Tin &v) noexcept +{ + //return static_cast<Tout>(std::round(v / SCALING_FACTOR)); + return Tout(v / Tin(SCALING_FACTOR)); +} + +// Conversion for Eigen vectors (N dimensional points) +template<class Tout = coord_t, + class Tin, + int N, + class = FloatingOnly<Tin>, + int...EigenArgs> +inline Eigen::Matrix<ArithmeticOnly<Tout>, N, EigenArgs...> +scaled(const Eigen::Matrix<Tin, N, EigenArgs...> &v) +{ + return (v / SCALING_FACTOR).template cast<Tout>(); +} + +// Conversion from arithmetic scaled type to floating point unscaled +template<class Tout = double, + class Tin, + class = ArithmeticOnly<Tin>, + class = FloatingOnly<Tout>> +inline constexpr Tout unscaled(const Tin &v) noexcept +{ + return Tout(v * Tout(SCALING_FACTOR)); +} + +// Unscaling for Eigen vectors. Input base type can be arithmetic, output base +// type can only be floating point. +template<class Tout = double, + class Tin, + int N, + class = ArithmeticOnly<Tin>, + class = FloatingOnly<Tout>, + int...EigenArgs> +inline constexpr Eigen::Matrix<Tout, N, EigenArgs...> +unscaled(const Eigen::Matrix<Tin, N, EigenArgs...> &v) noexcept +{ + return v.template cast<Tout>() * SCALING_FACTOR; +} + } // namespace Slic3r // start Boost @@ -300,7 +417,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) ? (coordinate_type)point(0) : (coordinate_type)point(1); + return (coordinate_type)point((orient == HORIZONTAL) ? 0 : 1); } }; @@ -308,16 +425,10 @@ namespace boost { namespace polygon { struct point_mutable_traits<Slic3r::Point> { typedef coord_t coordinate_type; static inline void set(Slic3r::Point& point, orientation_2d orient, coord_t value) { - if (orient == HORIZONTAL) - point(0) = value; - else - point(1) = value; + point((orient == HORIZONTAL) ? 0 : 1) = value; } static inline Slic3r::Point construct(coord_t x_value, coord_t y_value) { - Slic3r::Point retval; - retval(0) = x_value; - retval(1) = y_value; - return retval; + return Slic3r::Point(x_value, y_value); } }; } } |