Fixed integer overflow in LinearAlg2D::isInsideCorner().
This commit is contained in:
parent
b97c05176a
commit
e99b579f93
1 changed files with 17 additions and 26 deletions
|
@ -16,9 +16,8 @@ namespace Slic3r::Arachne::LinearAlg2D
|
|||
*
|
||||
* Test whether the \p query_point is inside of a polygon w.r.t a single corner.
|
||||
*/
|
||||
inline static bool isInsideCorner(const Point a, const Point b, const Point c, const Vec2i64 query_point) {
|
||||
|
||||
|
||||
inline static bool isInsideCorner(const Point &a, const Point &b, const Point &c, const Vec2i64 &query_point)
|
||||
{
|
||||
// Visualisation for the algorithm below:
|
||||
//
|
||||
// query
|
||||
|
@ -32,47 +31,39 @@ inline static bool isInsideCorner(const Point a, const Point b, const Point c, c
|
|||
// a c
|
||||
//
|
||||
|
||||
auto normal = [](const Point& p0, coord_t len) -> Point
|
||||
{
|
||||
auto normal = [](const Point &p0, coord_t len) -> Point {
|
||||
int64_t _len = p0.cast<int64_t>().norm();
|
||||
if (_len < 1)
|
||||
return Point(len, 0);
|
||||
return {len, 0};
|
||||
return (p0.cast<int64_t>() * int64_t(len) / _len).cast<coord_t>();
|
||||
};
|
||||
|
||||
auto rotate_90_degree_ccw = [](const Vec2i64 &p) -> Vec2i64 {
|
||||
return Vec2i64(-p.y(), p.x());
|
||||
auto rotate_90_degree_ccw = [](const Vec2d &p) -> Vec2d {
|
||||
return {-p.y(), p.x()};
|
||||
};
|
||||
|
||||
constexpr coord_t normal_length = 10000; //Create a normal vector of reasonable length in order to reduce rounding error.
|
||||
const Point ba = normal(a - b, normal_length);
|
||||
const Point bc = normal(c - b, normal_length);
|
||||
const Vec2i64 bq = query_point - b.cast<int64_t>();
|
||||
const Vec2i64 perpendicular = rotate_90_degree_ccw(bq); //The query projects to this perpendicular to coordinate 0.
|
||||
const Vec2d bq = query_point.cast<double>() - b.cast<double>();
|
||||
const Vec2d perpendicular = rotate_90_degree_ccw(bq); //The query projects to this perpendicular to coordinate 0.
|
||||
|
||||
assert(ba.cast<double>().dot(perpendicular.cast<double>()) <= double(std::numeric_limits<int64_t>::max()) && ba.cast<double>().dot(perpendicular.cast<double>()) >= double(std::numeric_limits<int64_t>::lowest()));
|
||||
assert(bc.cast<double>().dot(perpendicular.cast<double>()) <= double(std::numeric_limits<int64_t>::max()) && bc.cast<double>().dot(perpendicular.cast<double>()) >= double(std::numeric_limits<int64_t>::lowest()));
|
||||
|
||||
const int64_t project_a_perpendicular = ba.cast<int64_t>().dot(perpendicular); //Project vertex A on the perpendicular line.
|
||||
const int64_t project_c_perpendicular = bc.cast<int64_t>().dot(perpendicular); //Project vertex C on the perpendicular line.
|
||||
if ((project_a_perpendicular > 0) != (project_c_perpendicular > 0)) //Query is between A and C on the projection.
|
||||
const double project_a_perpendicular = ba.cast<double>().dot(perpendicular); //Project vertex A on the perpendicular line.
|
||||
const double project_c_perpendicular = bc.cast<double>().dot(perpendicular); //Project vertex C on the perpendicular line.
|
||||
if ((project_a_perpendicular > 0.) != (project_c_perpendicular > 0.)) //Query is between A and C on the projection.
|
||||
{
|
||||
return project_a_perpendicular > 0; //Due to the winding order of corner ABC, this means that the query is inside.
|
||||
return project_a_perpendicular > 0.; //Due to the winding order of corner ABC, this means that the query is inside.
|
||||
}
|
||||
else //Beyond either A or C, but it could still be inside of the polygon.
|
||||
{
|
||||
assert(ba.cast<double>().dot(bq.cast<double>()) <= double(std::numeric_limits<int64_t>::max()) && ba.cast<double>().dot(bq.cast<double>()) >= double(std::numeric_limits<int64_t>::lowest()));
|
||||
assert(bc.cast<double>().dot(bq.cast<double>()) <= double(std::numeric_limits<int64_t>::max()) && bc.cast<double>().dot(bq.cast<double>()) >= double(std::numeric_limits<int64_t>::lowest()));
|
||||
|
||||
const int64_t project_a_parallel = ba.cast<int64_t>().dot(bq); //Project not on the perpendicular, but on the original.
|
||||
const int64_t project_c_parallel = bc.cast<int64_t>().dot(bq);
|
||||
const double project_a_parallel = ba.cast<double>().dot(bq); //Project not on the perpendicular, but on the original.
|
||||
const double project_c_parallel = bc.cast<double>().dot(bq);
|
||||
|
||||
//Either:
|
||||
// * A is to the right of B (project_a_perpendicular > 0) and C is below A (project_c_parallel < project_a_parallel), or
|
||||
// * A is to the left of B (project_a_perpendicular < 0) and C is above A (project_c_parallel > project_a_parallel).
|
||||
return (project_c_parallel < project_a_parallel) == (project_a_perpendicular > 0);
|
||||
return (project_c_parallel < project_a_parallel) == (project_a_perpendicular > 0.);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*!
|
||||
|
@ -86,7 +77,7 @@ inline static bool isInsideCorner(const Point a, const Point b, const Point c, c
|
|||
* \param b the to point of the line
|
||||
* \return a positive value when \p p lies to the left of the line from \p a to \p b
|
||||
*/
|
||||
static inline int64_t pointIsLeftOfLine(const Point& p, const Point& a, const Point& b)
|
||||
static inline int64_t pointIsLeftOfLine(const Point &p, const Point &a, const Point &b)
|
||||
{
|
||||
return int64_t(b.x() - a.x()) * int64_t(p.y() - a.y()) - int64_t(b.y() - a.y()) * int64_t(p.x() - a.x());
|
||||
}
|
||||
|
@ -108,7 +99,7 @@ static inline int64_t pointIsLeftOfLine(const Point& p, const Point& a, const Po
|
|||
* \param c end of second line segment
|
||||
* \return the angle in radians between 0 and 2 * pi of the corner in \p b
|
||||
*/
|
||||
static inline float getAngleLeft(const Point& a, const Point& b, const Point& c)
|
||||
static inline float getAngleLeft(const Point &a, const Point &b, const Point &c)
|
||||
{
|
||||
const Vec2i64 ba = (a - b).cast<int64_t>();
|
||||
const Vec2i64 bc = (c - b).cast<int64_t>();
|
||||
|
|
Loading…
Reference in a new issue