mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-08-15 13:06:03 +08:00
Fixed integer overflow in LinearAlg2D::isInsideCorner().
This commit is contained in:
parent
b97c05176a
commit
e99b579f93
@ -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.
|
* 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:
|
// Visualisation for the algorithm below:
|
||||||
//
|
//
|
||||||
// query
|
// query
|
||||||
@ -32,47 +31,39 @@ inline static bool isInsideCorner(const Point a, const Point b, const Point c, c
|
|||||||
// a 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();
|
int64_t _len = p0.cast<int64_t>().norm();
|
||||||
if (_len < 1)
|
if (_len < 1)
|
||||||
return Point(len, 0);
|
return {len, 0};
|
||||||
return (p0.cast<int64_t>() * int64_t(len) / _len).cast<coord_t>();
|
return (p0.cast<int64_t>() * int64_t(len) / _len).cast<coord_t>();
|
||||||
};
|
};
|
||||||
|
|
||||||
auto rotate_90_degree_ccw = [](const Vec2i64 &p) -> Vec2i64 {
|
auto rotate_90_degree_ccw = [](const Vec2d &p) -> Vec2d {
|
||||||
return Vec2i64(-p.y(), p.x());
|
return {-p.y(), p.x()};
|
||||||
};
|
};
|
||||||
|
|
||||||
constexpr coord_t normal_length = 10000; //Create a normal vector of reasonable length in order to reduce rounding error.
|
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 ba = normal(a - b, normal_length);
|
||||||
const Point bc = normal(c - b, normal_length);
|
const Point bc = normal(c - b, normal_length);
|
||||||
const Vec2i64 bq = query_point - b.cast<int64_t>();
|
const Vec2d bq = query_point.cast<double>() - b.cast<double>();
|
||||||
const Vec2i64 perpendicular = rotate_90_degree_ccw(bq); //The query projects to this perpendicular to coordinate 0.
|
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()));
|
const double project_a_perpendicular = ba.cast<double>().dot(perpendicular); //Project vertex A on the perpendicular line.
|
||||||
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 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.
|
||||||
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.
|
|
||||||
{
|
{
|
||||||
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.
|
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()));
|
const double project_a_parallel = ba.cast<double>().dot(bq); //Project not on the perpendicular, but on the original.
|
||||||
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 double project_c_parallel = bc.cast<double>().dot(bq);
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
//Either:
|
//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 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).
|
// * 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
|
* \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
|
* \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());
|
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
|
* \param c end of second line segment
|
||||||
* \return the angle in radians between 0 and 2 * pi of the corner in \p b
|
* \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 ba = (a - b).cast<int64_t>();
|
||||||
const Vec2i64 bc = (c - b).cast<int64_t>();
|
const Vec2i64 bc = (c - b).cast<int64_t>();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user