2013-07-06 13:26:32 +00:00
|
|
|
#ifndef slic3r_Point_hpp_
|
|
|
|
#define slic3r_Point_hpp_
|
|
|
|
|
2015-12-07 23:39:54 +00:00
|
|
|
#include "libslic3r.h"
|
2018-08-14 16:33:26 +00:00
|
|
|
#include <cstddef>
|
2013-07-15 18:31:43 +00:00
|
|
|
#include <vector>
|
2018-08-14 16:33:26 +00:00
|
|
|
#include <cmath>
|
2014-01-17 13:22:37 +00:00
|
|
|
#include <string>
|
2015-05-02 19:43:22 +00:00
|
|
|
#include <sstream>
|
2017-01-25 17:26:06 +00:00
|
|
|
#include <unordered_map>
|
2013-07-11 16:55:51 +00:00
|
|
|
|
2018-08-14 16:33:26 +00:00
|
|
|
#include <Eigen/Geometry>
|
|
|
|
|
2013-07-07 20:36:14 +00:00
|
|
|
namespace Slic3r {
|
|
|
|
|
2020-11-16 09:20:47 +00:00
|
|
|
class BoundingBox;
|
2013-11-06 22:08:03 +00:00
|
|
|
class Line;
|
2014-05-21 18:08:21 +00:00
|
|
|
class MultiPoint;
|
2013-08-26 22:52:20 +00:00
|
|
|
class Point;
|
2021-04-14 07:22:51 +00:00
|
|
|
using Vector = Point;
|
2013-08-26 22:52:20 +00:00
|
|
|
|
2018-08-14 16:33:26 +00:00
|
|
|
// Eigen types, to replace the Slic3r's own types in the future.
|
|
|
|
// Vector types with a fixed point coordinate base type.
|
2021-04-14 07:22:51 +00:00
|
|
|
using Vec2crd = Eigen::Matrix<coord_t, 2, 1, Eigen::DontAlign>;
|
|
|
|
using Vec3crd = Eigen::Matrix<coord_t, 3, 1, Eigen::DontAlign>;
|
|
|
|
using Vec2i = Eigen::Matrix<int, 2, 1, Eigen::DontAlign>;
|
|
|
|
using Vec3i = Eigen::Matrix<int, 3, 1, Eigen::DontAlign>;
|
|
|
|
using Vec2i32 = Eigen::Matrix<int32_t, 2, 1, Eigen::DontAlign>;
|
|
|
|
using Vec2i64 = Eigen::Matrix<int64_t, 2, 1, Eigen::DontAlign>;
|
|
|
|
using Vec3i32 = Eigen::Matrix<int32_t, 3, 1, Eigen::DontAlign>;
|
|
|
|
using Vec3i64 = Eigen::Matrix<int64_t, 3, 1, Eigen::DontAlign>;
|
2018-08-15 11:51:40 +00:00
|
|
|
|
2018-08-14 16:33:26 +00:00
|
|
|
// Vector types with a double coordinate base type.
|
2021-04-14 07:22:51 +00:00
|
|
|
using Vec2f = Eigen::Matrix<float, 2, 1, Eigen::DontAlign>;
|
|
|
|
using Vec3f = Eigen::Matrix<float, 3, 1, Eigen::DontAlign>;
|
|
|
|
using Vec2d = Eigen::Matrix<double, 2, 1, Eigen::DontAlign>;
|
|
|
|
using Vec3d = Eigen::Matrix<double, 3, 1, Eigen::DontAlign>;
|
|
|
|
|
|
|
|
using Points = std::vector<Point>;
|
|
|
|
using PointPtrs = std::vector<Point*>;
|
|
|
|
using PointConstPtrs = std::vector<const Point*>;
|
|
|
|
using Points3 = std::vector<Vec3crd>;
|
|
|
|
using Pointfs = std::vector<Vec2d>;
|
|
|
|
using Vec2ds = std::vector<Vec2d>;
|
|
|
|
using Pointf3s = std::vector<Vec3d>;
|
|
|
|
|
|
|
|
using Matrix2f = Eigen::Matrix<float, 2, 2, Eigen::DontAlign>;
|
|
|
|
using Matrix2d = Eigen::Matrix<double, 2, 2, Eigen::DontAlign>;
|
|
|
|
using Matrix3f = Eigen::Matrix<float, 3, 3, Eigen::DontAlign>;
|
|
|
|
using Matrix3d = Eigen::Matrix<double, 3, 3, Eigen::DontAlign>;
|
|
|
|
|
|
|
|
using Transform2f = Eigen::Transform<float, 2, Eigen::Affine, Eigen::DontAlign>;
|
|
|
|
using Transform2d = Eigen::Transform<double, 2, Eigen::Affine, Eigen::DontAlign>;
|
|
|
|
using Transform3f = Eigen::Transform<float, 3, Eigen::Affine, Eigen::DontAlign>;
|
|
|
|
using Transform3d = Eigen::Transform<double, 3, Eigen::Affine, Eigen::DontAlign>;
|
2018-08-14 19:33:41 +00:00
|
|
|
|
2021-05-24 12:10:04 +00:00
|
|
|
inline bool operator<(const Vec2d &lhs, const Vec2d &rhs) { return lhs.x() < rhs.x() || (lhs.x() == rhs.x() && lhs.y() < rhs.y()); }
|
2018-08-21 18:34:45 +00:00
|
|
|
|
2021-03-01 17:41:36 +00:00
|
|
|
template<int Options>
|
|
|
|
int32_t cross2(const Eigen::MatrixBase<Eigen::Matrix<int32_t, 2, 1, Options>> &v1, const Eigen::MatrixBase<Eigen::Matrix<int32_t, 2, 1, Options>> &v2) = delete;
|
|
|
|
|
|
|
|
template<typename T, int Options>
|
|
|
|
inline T cross2(const Eigen::MatrixBase<Eigen::Matrix<T, 2, 1, Options>> &v1, const Eigen::MatrixBase<Eigen::Matrix<T, 2, 1, Options>> &v2)
|
|
|
|
{
|
2021-05-24 12:10:04 +00:00
|
|
|
return v1.x() * v2.y() - v1.y() * v2.x();
|
2021-03-01 17:41:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
template<typename Derived, typename Derived2>
|
|
|
|
inline typename Derived::Scalar cross2(const Eigen::MatrixBase<Derived> &v1, const Eigen::MatrixBase<Derived2> &v2)
|
|
|
|
{
|
|
|
|
static_assert(std::is_same<typename Derived::Scalar, typename Derived2::Scalar>::value, "cross2(): Scalar types of 1st and 2nd operand must be equal.");
|
2021-05-24 12:10:04 +00:00
|
|
|
return v1.x() * v2.y() - v1.y() * v2.x();
|
2021-03-01 17:41:36 +00:00
|
|
|
}
|
Removed Point::scale(),translate(),coincides_with(),distance_to(),
distance_to_squared(),perp_distance_to(),negative(),vector_to(),
translate(), distance_to() etc,
replaced with the Eigen equivalents.
2018-08-17 12:14:24 +00:00
|
|
|
|
2020-11-11 15:49:11 +00:00
|
|
|
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()); }
|
2020-06-05 18:19:19 +00:00
|
|
|
|
2020-11-11 15:49:11 +00:00
|
|
|
template<class T, int N, int Options>
|
2021-05-24 12:10:04 +00:00
|
|
|
Eigen::Matrix<T, 2, 1, Eigen::DontAlign> to_2d(const Eigen::MatrixBase<Eigen::Matrix<T, N, 1, Options>> &ptN) { return { ptN.x(), ptN.y() }; }
|
2018-08-21 15:43:05 +00:00
|
|
|
|
2020-11-11 15:49:11 +00:00
|
|
|
template<class T, int Options>
|
2021-05-24 12:10:04 +00:00
|
|
|
Eigen::Matrix<T, 3, 1, Eigen::DontAlign> to_3d(const Eigen::MatrixBase<Eigen::Matrix<T, 2, 1, Options>> & pt, const T z) { return { pt.x(), pt.y(), z }; }
|
2018-09-17 10:15:11 +00:00
|
|
|
|
2018-08-21 15:43:05 +00:00
|
|
|
inline Vec2d unscale(coord_t x, coord_t y) { return Vec2d(unscale<double>(x), unscale<double>(y)); }
|
2021-05-24 12:10:04 +00:00
|
|
|
inline Vec2d unscale(const Vec2crd &pt) { return Vec2d(unscale<double>(pt.x()), unscale<double>(pt.y())); }
|
|
|
|
inline Vec2d unscale(const Vec2d &pt) { return Vec2d(unscale<double>(pt.x()), unscale<double>(pt.y())); }
|
2018-08-21 15:43:05 +00:00
|
|
|
inline Vec3d unscale(coord_t x, coord_t y, coord_t z) { return Vec3d(unscale<double>(x), unscale<double>(y), unscale<double>(z)); }
|
2021-05-24 12:10:04 +00:00
|
|
|
inline Vec3d unscale(const Vec3crd &pt) { return Vec3d(unscale<double>(pt.x()), unscale<double>(pt.y()), unscale<double>(pt.z())); }
|
|
|
|
inline Vec3d unscale(const Vec3d &pt) { return Vec3d(unscale<double>(pt.x()), unscale<double>(pt.y()), unscale<double>(pt.z())); }
|
2018-08-21 15:43:05 +00:00
|
|
|
|
2021-05-24 12:10:04 +00:00
|
|
|
inline std::string to_string(const Vec2crd &pt) { return std::string("[") + std::to_string(pt.x()) + ", " + std::to_string(pt.y()) + "]"; }
|
|
|
|
inline std::string to_string(const Vec2d &pt) { return std::string("[") + std::to_string(pt.x()) + ", " + std::to_string(pt.y()) + "]"; }
|
|
|
|
inline std::string to_string(const Vec3crd &pt) { return std::string("[") + std::to_string(pt.x()) + ", " + std::to_string(pt.y()) + ", " + std::to_string(pt.z()) + "]"; }
|
|
|
|
inline std::string to_string(const Vec3d &pt) { return std::string("[") + std::to_string(pt.x()) + ", " + std::to_string(pt.y()) + ", " + std::to_string(pt.z()) + "]"; }
|
2018-08-17 14:54:07 +00:00
|
|
|
|
2018-08-28 07:03:03 +00:00
|
|
|
std::vector<Vec3f> transform(const std::vector<Vec3f>& points, const Transform3f& t);
|
|
|
|
Pointf3s transform(const Pointf3s& points, const Transform3d& t);
|
|
|
|
|
2020-08-18 11:45:18 +00:00
|
|
|
template<int N, class T> using Vec = Eigen::Matrix<T, N, 1, Eigen::DontAlign, N, 1>;
|
2020-08-18 09:41:14 +00:00
|
|
|
|
2018-08-15 11:51:40 +00:00
|
|
|
class Point : public Vec2crd
|
2013-07-06 13:26:32 +00:00
|
|
|
{
|
2017-07-27 08:39:43 +00:00
|
|
|
public:
|
2021-04-14 07:22:51 +00:00
|
|
|
using coord_type = coord_t;
|
2018-08-14 16:33:26 +00:00
|
|
|
|
2019-10-15 07:40:40 +00:00
|
|
|
Point() : Vec2crd(0, 0) {}
|
2020-03-25 10:07:26 +00:00
|
|
|
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)) {}
|
2019-10-15 07:40:40 +00:00
|
|
|
Point(double x, double y) : Vec2crd(coord_t(lrint(x)), coord_t(lrint(y))) {}
|
2018-08-15 11:51:40 +00:00
|
|
|
Point(const Point &rhs) { *this = rhs; }
|
2019-10-15 07:40:40 +00:00
|
|
|
explicit Point(const Vec2d& rhs) : Vec2crd(coord_t(lrint(rhs.x())), coord_t(lrint(rhs.y()))) {}
|
|
|
|
// This constructor allows you to construct Point from Eigen expressions
|
2018-08-15 11:51:40 +00:00
|
|
|
template<typename OtherDerived>
|
|
|
|
Point(const Eigen::MatrixBase<OtherDerived> &other) : Vec2crd(other) {}
|
2017-08-02 12:24:32 +00:00
|
|
|
static Point new_scale(coordf_t x, coordf_t y) { return Point(coord_t(scale_(x)), coord_t(scale_(y))); }
|
2020-09-17 16:39:28 +00:00
|
|
|
static Point new_scale(const Vec2d &v) { return Point(coord_t(scale_(v.x())), coord_t(scale_(v.y()))); }
|
2017-05-10 09:25:57 +00:00
|
|
|
|
2018-08-15 11:51:40 +00:00
|
|
|
// This method allows you to assign Eigen expressions to MyVectorType
|
|
|
|
template<typename OtherDerived>
|
|
|
|
Point& operator=(const Eigen::MatrixBase<OtherDerived> &other)
|
|
|
|
{
|
Removed Point::scale(),translate(),coincides_with(),distance_to(),
distance_to_squared(),perp_distance_to(),negative(),vector_to(),
translate(), distance_to() etc,
replaced with the Eigen equivalents.
2018-08-17 12:14:24 +00:00
|
|
|
this->Vec2crd::operator=(other);
|
2018-08-15 11:51:40 +00:00
|
|
|
return *this;
|
|
|
|
}
|
2018-08-14 19:33:41 +00:00
|
|
|
|
2021-05-24 12:10:04 +00:00
|
|
|
Point& operator+=(const Point& rhs) { this->x() += rhs.x(); this->y() += rhs.y(); return *this; }
|
|
|
|
Point& operator-=(const Point& rhs) { this->x() -= rhs.x(); this->y() -= rhs.y(); return *this; }
|
|
|
|
Point& operator*=(const double &rhs) { this->x() = coord_t(this->x() * rhs); this->y() = coord_t(this->y() * rhs); return *this; }
|
|
|
|
Point operator*(const double &rhs) { return Point(this->x() * rhs, this->y() * rhs); }
|
2017-05-10 09:25:57 +00:00
|
|
|
|
2020-09-17 16:39:28 +00:00
|
|
|
void rotate(double angle) { this->rotate(std::cos(angle), std::sin(angle)); }
|
|
|
|
void rotate(double cos_a, double sin_a) {
|
2021-05-24 12:10:04 +00:00
|
|
|
double cur_x = (double)this->x();
|
|
|
|
double cur_y = (double)this->y();
|
|
|
|
this->x() = (coord_t)round(cos_a * cur_x - sin_a * cur_y);
|
|
|
|
this->y() = (coord_t)round(cos_a * cur_y + sin_a * cur_x);
|
2020-09-17 16:39:28 +00:00
|
|
|
}
|
|
|
|
|
2018-08-15 11:51:40 +00:00
|
|
|
void rotate(double angle, const Point ¢er);
|
|
|
|
Point rotated(double angle) const { Point res(*this); res.rotate(angle); return res; }
|
2020-11-05 16:32:40 +00:00
|
|
|
Point rotated(double cos_a, double sin_a) const { Point res(*this); res.rotate(cos_a, sin_a); return res; }
|
2018-08-15 11:51:40 +00:00
|
|
|
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;
|
2013-11-22 20:43:35 +00:00
|
|
|
double ccw(const Point &p1, const Point &p2) const;
|
|
|
|
double ccw(const Line &line) const;
|
2014-12-07 18:53:22 +00:00
|
|
|
double ccw_angle(const Point &p1, const Point &p2) const;
|
2018-08-15 11:51:40 +00:00
|
|
|
Point projection_onto(const MultiPoint &poly) const;
|
|
|
|
Point projection_onto(const Line &line) const;
|
2013-07-06 13:26:32 +00:00
|
|
|
};
|
|
|
|
|
2021-05-24 12:10:04 +00:00
|
|
|
inline bool operator<(const Point &l, const Point &r)
|
|
|
|
{
|
|
|
|
return l.x() < r.x() || (l.x() == r.x() && l.y() < r.y());
|
|
|
|
}
|
|
|
|
|
2019-10-15 07:40:40 +00:00
|
|
|
inline bool is_approx(const Point &p1, const Point &p2, coord_t epsilon = coord_t(SCALED_EPSILON))
|
|
|
|
{
|
|
|
|
Point d = (p2 - p1).cwiseAbs();
|
|
|
|
return d.x() < epsilon && d.y() < epsilon;
|
|
|
|
}
|
|
|
|
|
2019-10-15 11:49:28 +00:00
|
|
|
inline bool is_approx(const Vec2f &p1, const Vec2f &p2, float epsilon = float(EPSILON))
|
|
|
|
{
|
|
|
|
Vec2f d = (p2 - p1).cwiseAbs();
|
|
|
|
return d.x() < epsilon && d.y() < epsilon;
|
|
|
|
}
|
|
|
|
|
2019-10-15 07:40:40 +00:00
|
|
|
inline bool is_approx(const Vec2d &p1, const Vec2d &p2, double epsilon = EPSILON)
|
|
|
|
{
|
|
|
|
Vec2d d = (p2 - p1).cwiseAbs();
|
|
|
|
return d.x() < epsilon && d.y() < epsilon;
|
|
|
|
}
|
|
|
|
|
2019-10-15 11:49:28 +00:00
|
|
|
inline bool is_approx(const Vec3f &p1, const Vec3f &p2, float epsilon = float(EPSILON))
|
|
|
|
{
|
|
|
|
Vec3f d = (p2 - p1).cwiseAbs();
|
|
|
|
return d.x() < epsilon && d.y() < epsilon && d.z() < epsilon;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline bool is_approx(const Vec3d &p1, const Vec3d &p2, double epsilon = EPSILON)
|
|
|
|
{
|
|
|
|
Vec3d d = (p2 - p1).cwiseAbs();
|
|
|
|
return d.x() < epsilon && d.y() < epsilon && d.z() < epsilon;
|
|
|
|
}
|
|
|
|
|
2020-11-05 16:32:40 +00:00
|
|
|
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>();
|
|
|
|
}
|
|
|
|
|
2020-11-16 09:20:47 +00:00
|
|
|
extern BoundingBox get_extents(const Points &pts);
|
|
|
|
extern BoundingBox get_extents(const std::vector<Points> &pts);
|
|
|
|
|
2018-05-17 08:37:26 +00:00
|
|
|
namespace int128 {
|
Removed Point::scale(),translate(),coincides_with(),distance_to(),
distance_to_squared(),perp_distance_to(),negative(),vector_to(),
translate(), distance_to() etc,
replaced with the Eigen equivalents.
2018-08-17 12:14:24 +00:00
|
|
|
// Exact orientation predicate,
|
|
|
|
// returns +1: CCW, 0: collinear, -1: CW.
|
2018-08-17 14:54:07 +00:00
|
|
|
int orient(const Vec2crd &p1, const Vec2crd &p2, const Vec2crd &p3);
|
Removed Point::scale(),translate(),coincides_with(),distance_to(),
distance_to_squared(),perp_distance_to(),negative(),vector_to(),
translate(), distance_to() etc,
replaced with the Eigen equivalents.
2018-08-17 12:14:24 +00:00
|
|
|
// Exact orientation predicate,
|
|
|
|
// returns +1: CCW, 0: collinear, -1: CW.
|
2018-08-17 14:54:07 +00:00
|
|
|
int cross(const Vec2crd &v1, const Vec2crd &v2);
|
2018-05-17 08:37:26 +00:00
|
|
|
}
|
|
|
|
|
2017-01-25 17:26:06 +00:00
|
|
|
// To be used by std::unordered_map, std::unordered_multimap and friends.
|
2016-11-29 18:29:24 +00:00
|
|
|
struct PointHash {
|
2018-08-17 14:54:07 +00:00
|
|
|
size_t operator()(const Vec2crd &pt) const {
|
2021-05-24 12:10:04 +00:00
|
|
|
return std::hash<coord_t>()(pt.x()) ^ std::hash<coord_t>()(pt.y());
|
2016-11-29 18:29:24 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2017-01-25 17:26:06 +00:00
|
|
|
// A generic class to search for a closest Point in a given radius.
|
|
|
|
// It uses std::unordered_multimap to implement an efficient 2D spatial hashing.
|
|
|
|
// The PointAccessor has to return const Point*.
|
|
|
|
// If a nullptr is returned, it is ignored by the query.
|
|
|
|
template<typename ValueType, typename PointAccessor> class ClosestPointInRadiusLookup
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
ClosestPointInRadiusLookup(coord_t search_radius, PointAccessor point_accessor = PointAccessor()) :
|
|
|
|
m_search_radius(search_radius), m_point_accessor(point_accessor), m_grid_log2(0)
|
|
|
|
{
|
|
|
|
// Resolution of a grid, twice the search radius + some epsilon.
|
|
|
|
coord_t gridres = 2 * m_search_radius + 4;
|
|
|
|
m_grid_resolution = gridres;
|
|
|
|
assert(m_grid_resolution > 0);
|
|
|
|
assert(m_grid_resolution < (coord_t(1) << 30));
|
|
|
|
// Compute m_grid_log2 = log2(m_grid_resolution)
|
|
|
|
if (m_grid_resolution > 32767) {
|
|
|
|
m_grid_resolution >>= 16;
|
|
|
|
m_grid_log2 += 16;
|
|
|
|
}
|
|
|
|
if (m_grid_resolution > 127) {
|
|
|
|
m_grid_resolution >>= 8;
|
|
|
|
m_grid_log2 += 8;
|
|
|
|
}
|
|
|
|
if (m_grid_resolution > 7) {
|
|
|
|
m_grid_resolution >>= 4;
|
|
|
|
m_grid_log2 += 4;
|
|
|
|
}
|
|
|
|
if (m_grid_resolution > 1) {
|
|
|
|
m_grid_resolution >>= 2;
|
|
|
|
m_grid_log2 += 2;
|
|
|
|
}
|
|
|
|
if (m_grid_resolution > 0)
|
|
|
|
++ m_grid_log2;
|
|
|
|
m_grid_resolution = 1 << m_grid_log2;
|
|
|
|
assert(m_grid_resolution >= gridres);
|
|
|
|
assert(gridres > m_grid_resolution / 2);
|
|
|
|
}
|
|
|
|
|
|
|
|
void insert(const ValueType &value) {
|
2018-08-17 14:54:07 +00:00
|
|
|
const Vec2crd *pt = m_point_accessor(value);
|
2017-01-25 17:26:06 +00:00
|
|
|
if (pt != nullptr)
|
2018-08-17 14:54:07 +00:00
|
|
|
m_map.emplace(std::make_pair(Vec2crd(pt->x()>>m_grid_log2, pt->y()>>m_grid_log2), value));
|
2017-01-25 17:26:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void insert(ValueType &&value) {
|
2018-08-17 14:54:07 +00:00
|
|
|
const Vec2crd *pt = m_point_accessor(value);
|
2017-01-25 17:26:06 +00:00
|
|
|
if (pt != nullptr)
|
2018-08-17 14:54:07 +00:00
|
|
|
m_map.emplace(std::make_pair(Vec2crd(pt->x()>>m_grid_log2, pt->y()>>m_grid_log2), std::move(value)));
|
2017-01-25 17:26:06 +00:00
|
|
|
}
|
|
|
|
|
2018-12-11 15:33:43 +00:00
|
|
|
// Erase a data point equal to value. (ValueType has to declare the operator==).
|
|
|
|
// Returns true if the data point equal to value was found and removed.
|
|
|
|
bool erase(const ValueType &value) {
|
|
|
|
const Point *pt = m_point_accessor(value);
|
|
|
|
if (pt != nullptr) {
|
|
|
|
// Range of fragment starts around grid_corner, close to pt.
|
2021-05-24 12:10:04 +00:00
|
|
|
auto range = m_map.equal_range(Point((*pt).x()>>m_grid_log2, (*pt).y()>>m_grid_log2));
|
2018-12-11 15:33:43 +00:00
|
|
|
// Remove the first item.
|
|
|
|
for (auto it = range.first; it != range.second; ++ it) {
|
|
|
|
if (it->second == value) {
|
|
|
|
m_map.erase(it);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2017-01-25 17:26:06 +00:00
|
|
|
// Return a pair of <ValueType*, distance_squared>
|
2018-08-17 14:54:07 +00:00
|
|
|
std::pair<const ValueType*, double> find(const Vec2crd &pt) {
|
2017-01-25 17:26:06 +00:00
|
|
|
// 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.
|
2021-05-24 12:10:04 +00:00
|
|
|
Vec2crd grid_corner((pt.x()+(m_grid_resolution>>1))>>m_grid_log2, (pt.y()+(m_grid_resolution>>1))>>m_grid_log2);
|
2017-01-25 17:26:06 +00:00
|
|
|
// 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.
|
2021-05-24 12:10:04 +00:00
|
|
|
auto range = m_map.equal_range(Vec2crd(grid_corner.x() + neighbor_x, grid_corner.y() + neighbor_y));
|
2017-01-25 17:26:06 +00:00
|
|
|
// Find the map entry closest to pt.
|
|
|
|
for (auto it = range.first; it != range.second; ++it) {
|
|
|
|
const ValueType &value = it->second;
|
2018-08-17 14:54:07 +00:00
|
|
|
const Vec2crd *pt2 = m_point_accessor(value);
|
2017-01-25 17:26:06 +00:00
|
|
|
if (pt2 != nullptr) {
|
2019-03-11 16:18:38 +00:00
|
|
|
const double d2 = (pt - *pt2).cast<double>().squaredNorm();
|
2017-01-25 17:26:06 +00:00
|
|
|
if (d2 < dist_min) {
|
|
|
|
dist_min = d2;
|
|
|
|
value_min = &value;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-12-11 15:33:43 +00:00
|
|
|
return (value_min != nullptr && dist_min < coordf_t(m_search_radius) * coordf_t(m_search_radius)) ?
|
2017-01-25 17:26:06 +00:00
|
|
|
std::make_pair(value_min, dist_min) :
|
|
|
|
std::make_pair(nullptr, std::numeric_limits<double>::max());
|
|
|
|
}
|
|
|
|
|
2020-11-10 12:56:12 +00:00
|
|
|
// 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.
|
2021-05-24 12:10:04 +00:00
|
|
|
Vec2crd grid_corner((pt.x()+(m_grid_resolution>>1))>>m_grid_log2, (pt.y()+(m_grid_resolution>>1))>>m_grid_log2);
|
2020-11-10 12:56:12 +00:00
|
|
|
// 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.
|
2021-05-24 12:10:04 +00:00
|
|
|
auto range = m_map.equal_range(Vec2crd(grid_corner.x() + neighbor_x, grid_corner.y() + neighbor_y));
|
2020-11-10 12:56:12 +00:00
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
|
2017-01-25 17:26:06 +00:00
|
|
|
private:
|
2021-04-14 07:22:51 +00:00
|
|
|
using map_type = typename std::unordered_multimap<Vec2crd, ValueType, PointHash>;
|
2017-01-25 17:26:06 +00:00
|
|
|
PointAccessor m_point_accessor;
|
|
|
|
map_type m_map;
|
|
|
|
coord_t m_search_radius;
|
|
|
|
coord_t m_grid_resolution;
|
|
|
|
coord_t m_grid_log2;
|
|
|
|
};
|
|
|
|
|
2018-08-21 19:05:24 +00:00
|
|
|
std::ostream& operator<<(std::ostream &stm, const Vec2d &pointf);
|
2013-12-20 19:54:11 +00:00
|
|
|
|
2020-03-27 08:05:26 +00:00
|
|
|
|
|
|
|
// /////////////////////////////////////////////////////////////////////////////
|
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
|
2021-04-08 13:29:40 +00:00
|
|
|
// Align a coordinate to a grid. The coordinate may be negative,
|
|
|
|
// the aligned value will never be bigger than the original one.
|
|
|
|
inline coord_t align_to_grid(const coord_t coord, const coord_t spacing) {
|
|
|
|
// Current C++ standard defines the result of integer division to be rounded to zero,
|
|
|
|
// for both positive and negative numbers. Here we want to round down for negative
|
|
|
|
// numbers as well.
|
|
|
|
coord_t aligned = (coord < 0) ?
|
|
|
|
((coord - spacing + 1) / spacing) * spacing :
|
|
|
|
(coord / spacing) * spacing;
|
|
|
|
assert(aligned <= coord);
|
|
|
|
return aligned;
|
|
|
|
}
|
|
|
|
inline Point align_to_grid(Point coord, Point spacing)
|
|
|
|
{ return Point(align_to_grid(coord.x(), spacing.x()), align_to_grid(coord.y(), spacing.y())); }
|
|
|
|
inline coord_t align_to_grid(coord_t coord, coord_t spacing, coord_t base)
|
|
|
|
{ return base + align_to_grid(coord - base, spacing); }
|
|
|
|
inline 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())); }
|
|
|
|
|
2016-12-08 14:16:09 +00:00
|
|
|
} // namespace Slic3r
|
2013-07-07 20:36:14 +00:00
|
|
|
|
2014-01-09 16:26:39 +00:00
|
|
|
// start Boost
|
2016-03-14 06:51:35 +00:00
|
|
|
#include <boost/version.hpp>
|
2014-04-24 11:43:24 +00:00
|
|
|
#include <boost/polygon/polygon.hpp>
|
2014-01-09 16:26:39 +00:00
|
|
|
namespace boost { namespace polygon {
|
|
|
|
template <>
|
2021-04-14 07:22:51 +00:00
|
|
|
struct geometry_concept<Slic3r::Point> { using type = point_concept; };
|
2014-01-09 16:26:39 +00:00
|
|
|
|
|
|
|
template <>
|
2016-12-08 14:16:09 +00:00
|
|
|
struct point_traits<Slic3r::Point> {
|
2021-04-14 07:22:51 +00:00
|
|
|
using coordinate_type = coord_t;
|
2014-01-09 16:26:39 +00:00
|
|
|
|
2016-12-08 14:16:09 +00:00
|
|
|
static inline coordinate_type get(const Slic3r::Point& point, orientation_2d orient) {
|
2021-01-29 15:34:22 +00:00
|
|
|
return static_cast<coordinate_type>(point((orient == HORIZONTAL) ? 0 : 1));
|
2014-01-09 16:26:39 +00:00
|
|
|
}
|
|
|
|
};
|
2014-04-24 11:43:24 +00:00
|
|
|
|
|
|
|
template <>
|
2016-12-08 14:16:09 +00:00
|
|
|
struct point_mutable_traits<Slic3r::Point> {
|
2021-04-14 07:22:51 +00:00
|
|
|
using coordinate_type = coord_t;
|
2016-12-08 14:16:09 +00:00
|
|
|
static inline void set(Slic3r::Point& point, orientation_2d orient, coord_t value) {
|
2020-05-21 15:47:17 +00:00
|
|
|
point((orient == HORIZONTAL) ? 0 : 1) = value;
|
2014-04-24 11:43:24 +00:00
|
|
|
}
|
2016-12-08 14:16:09 +00:00
|
|
|
static inline Slic3r::Point construct(coord_t x_value, coord_t y_value) {
|
2020-05-21 15:47:17 +00:00
|
|
|
return Slic3r::Point(x_value, y_value);
|
2014-04-24 11:43:24 +00:00
|
|
|
}
|
|
|
|
};
|
2014-01-09 16:26:39 +00:00
|
|
|
} }
|
|
|
|
// end Boost
|
|
|
|
|
2019-06-26 14:29:12 +00:00
|
|
|
// Serialization through the Cereal library
|
|
|
|
namespace cereal {
|
|
|
|
// template<class Archive> void serialize(Archive& archive, Slic3r::Vec2crd &v) { archive(v.x(), v.y()); }
|
|
|
|
// template<class Archive> void serialize(Archive& archive, Slic3r::Vec3crd &v) { archive(v.x(), v.y(), v.z()); }
|
|
|
|
template<class Archive> void serialize(Archive& archive, Slic3r::Vec2i &v) { archive(v.x(), v.y()); }
|
|
|
|
template<class Archive> void serialize(Archive& archive, Slic3r::Vec3i &v) { archive(v.x(), v.y(), v.z()); }
|
|
|
|
// template<class Archive> void serialize(Archive& archive, Slic3r::Vec2i64 &v) { archive(v.x(), v.y()); }
|
|
|
|
// template<class Archive> void serialize(Archive& archive, Slic3r::Vec3i64 &v) { archive(v.x(), v.y(), v.z()); }
|
|
|
|
template<class Archive> void serialize(Archive& archive, Slic3r::Vec2f &v) { archive(v.x(), v.y()); }
|
|
|
|
template<class Archive> void serialize(Archive& archive, Slic3r::Vec3f &v) { archive(v.x(), v.y(), v.z()); }
|
|
|
|
template<class Archive> void serialize(Archive& archive, Slic3r::Vec2d &v) { archive(v.x(), v.y()); }
|
|
|
|
template<class Archive> void serialize(Archive& archive, Slic3r::Vec3d &v) { archive(v.x(), v.y(), v.z()); }
|
|
|
|
|
|
|
|
template<class Archive> void load(Archive& archive, Slic3r::Matrix2f &m) { archive.loadBinary((char*)m.data(), sizeof(float) * 4); }
|
|
|
|
template<class Archive> void save(Archive& archive, Slic3r::Matrix2f &m) { archive.saveBinary((char*)m.data(), sizeof(float) * 4); }
|
|
|
|
}
|
|
|
|
|
2013-07-06 13:26:32 +00:00
|
|
|
#endif
|