diff --git a/CPP/CMakeLists.txt b/CPP/CMakeLists.txt index 2ad05657..1e8b0271 100644 --- a/CPP/CMakeLists.txt +++ b/CPP/CMakeLists.txt @@ -228,6 +228,7 @@ endif() set(ClipperTests_SRC Tests/TestExportHeaders.cpp + Tests/TestIsCollinear.cpp Tests/TestLines.cpp Tests/TestOffsets.cpp Tests/TestOffsetOrientation.cpp diff --git a/CPP/Clipper2Lib/include/clipper2/clipper.core.h b/CPP/Clipper2Lib/include/clipper2/clipper.core.h index 4e9be2f5..598db49a 100644 --- a/CPP/Clipper2Lib/include/clipper2/clipper.core.h +++ b/CPP/Clipper2Lib/include/clipper2/clipper.core.h @@ -663,10 +663,10 @@ namespace Clipper2Lib inline bool IsCollinear(const Point& pt1, const Point& sharedPt, const Point& pt2) // #777 { - const double a = static_cast(sharedPt.x - pt1.x); - const double b = static_cast(pt2.y - sharedPt.y); - const double c = static_cast(sharedPt.y - pt1.y); - const double d = static_cast(pt2.x - sharedPt.x); + const auto a = static_cast(sharedPt.x - pt1.x); + const auto b = static_cast(pt2.y - sharedPt.y); + const auto c = static_cast(sharedPt.y - pt1.y); + const auto d = static_cast(pt2.x - sharedPt.x); return a * b == c * d; } diff --git a/CPP/Tests/TestIsCollinear.cpp b/CPP/Tests/TestIsCollinear.cpp new file mode 100644 index 00000000..72c04780 --- /dev/null +++ b/CPP/Tests/TestIsCollinear.cpp @@ -0,0 +1,13 @@ +#include +#include "clipper2/clipper.core.h" + +TEST(Clipper2Tests, TestIsCollinear) { + // a large integer not representable by double + const int64_t i = 9007199254740993; + + const Clipper2Lib::Point64 pt1(0, 0); + const Clipper2Lib::Point64 sharedPt(i, i * 10); + const Clipper2Lib::Point64 pt2(i * 10, i * 100); + + EXPECT_TRUE(IsCollinear(pt1, sharedPt, pt2)); +} diff --git a/CSharp/Clipper2Lib/Clipper.Core.cs b/CSharp/Clipper2Lib/Clipper.Core.cs index 0979e7df..ea840abf 100644 --- a/CSharp/Clipper2Lib/Clipper.Core.cs +++ b/CSharp/Clipper2Lib/Clipper.Core.cs @@ -604,9 +604,8 @@ internal static double CrossProduct(Point64 pt1, Point64 pt2, Point64 pt3) [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static bool IsCollinear(Point64 pt1, Point64 pt2, Point64 pt3) { - // typecast to double to avoid potential int overflow - return (double) (pt2.X - pt1.X) * (double) (pt3.Y - pt2.Y) == - (double) (pt2.Y - pt1.Y) * (double) (pt3.X - pt2.X); + return (pt2.X - pt1.X) * (pt3.Y - pt2.Y) == + (pt2.Y - pt1.Y) * (pt3.X - pt2.X); } [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/Delphi/Clipper2Lib/Clipper.Core.pas b/Delphi/Clipper2Lib/Clipper.Core.pas index a306a9ab..71aee7c0 100644 --- a/Delphi/Clipper2Lib/Clipper.Core.pas +++ b/Delphi/Clipper2Lib/Clipper.Core.pas @@ -1866,7 +1866,7 @@ function IsPositive(const path: TPathD): Boolean; function IsCollinear(const pt1, pt2, pt3: TPoint64): Boolean; var - a,b,c,d: double; // avoids potential int overflow + a,b,c,d: Int64; begin a := (pt2.X - pt1.X); b := (pt2.Y - pt1.Y);