diff --git a/components/tachart/tachartutils.pas b/components/tachart/tachartutils.pas
index 486a67eb72..dd423c500d 100644
--- a/components/tachart/tachartutils.pas
+++ b/components/tachart/tachartutils.pas
@@ -188,7 +188,9 @@ procedure ExpandRect(var ARect: TDoubleRect; const APoint: TDoublePoint); inline
function GetIntervals(AMin, AMax: Double; AInverted: Boolean): TDoubleDynArray;
-function IsPointOnLine(const AP, A1, A2: TPoint): Boolean;
+function IsPointOnLine(const AP, A1, A2: TPoint): Boolean; inline;
+function IsPointInRect(const AP, A1, A2: TPoint): Boolean; inline;
+function IsLineIntersectsLine(const AA, AB, AC, AD: TPoint): Boolean;
function LineIntersectsRect(
var AA, AB: TDoublePoint; const ARect: TDoubleRect): Boolean;
@@ -221,6 +223,8 @@ operator =(const A, B: TMethod): Boolean; overload; inline;
implementation
+function PointLineSide(AP, A1, A2: TPoint): TValueSign; forward;
+
function BoundsSize(ALeft, ATop: Integer; ASize: TSize): TRect; inline;
begin
Result := Bounds(ALeft, ATop, ASize.cx, ASize.cy);
@@ -418,10 +422,30 @@ end;
function IsPointOnLine(const AP, A1, A2: TPoint): Boolean;
begin
- Result :=
- SafeInRange(AP.X, A1.X, A2.X) and
- SafeInRange(AP.Y, A1.Y, A2.Y) and
- ((AP.X - A1.X) * (A2.Y - A1.Y) = (AP.Y - A1.Y) * (A2.X - A1.X));
+ Result := IsPointInRect(AP, A1, A2) and (PointLineSide(AP, A1, A2) = 0);
+end;
+
+function IsPointInRect(const AP, A1, A2: TPoint): Boolean;
+begin
+ Result := SafeInRange(AP.X, A1.X, A2.X) and SafeInRange(AP.Y, A1.Y, A2.Y);
+end;
+
+function IsLineIntersectsLine(const AA, AB, AC, AD: TPoint): Boolean;
+var
+ sa, sb, sc, sd: TValueSign;
+begin
+ sa := PointLineSide(AA, AC, AD);
+ sb := PointLineSide(AB, AC, AD);
+ if (sa = 0) and (sb = 0) then
+ // All points are on the same infinite line.
+ Result :=
+ IsPointInRect(AA, AC, AD) or IsPointInRect(AB, AC, AD) or
+ IsPointInRect(AC, AA, AB) or IsPointInRect(AD, AA, AB)
+ else begin
+ sc := PointLineSide(AC, AA, AB);
+ sd := PointLineSide(AD, AA, AB);
+ Result := (sa * sb <= 0) and (sc * sd <= 0);
+ end;
end;
function LineIntersectsRect(
@@ -498,6 +522,15 @@ begin
Result := Abs(A.Y - B.Y);
end;
+function PointLineSide(AP, A1, A2: TPoint): TValueSign;
+var
+ a1x, a1y: Int64;
+begin
+ a1x := A1.X;
+ a1y := A1.Y;
+ Result := Sign((AP.X - a1x) * (A2.Y - a1y) - (AP.Y - a1y) * (A2.X - a1x));
+end;
+
function RectIntersectsRect(
var ARect: TDoubleRect; const AFixed: TDoubleRect): Boolean;
diff --git a/components/tachart/test/UtilsTest.pas b/components/tachart/test/UtilsTest.pas
index 6d31326cdc..90e30a0bfb 100644
--- a/components/tachart/test/UtilsTest.pas
+++ b/components/tachart/test/UtilsTest.pas
@@ -46,6 +46,7 @@ type
private
procedure AssertEquals(const Expected, Actual: TDoublePoint); overload;
published
+ procedure TestLineIntersectsLine;
procedure TestLineIntersectsRect;
procedure TestPointOnLine;
end;
@@ -128,6 +129,23 @@ begin
AssertEquals(Expected.Y, Actual.Y);
end;
+procedure TGeometryTest.TestLineIntersectsLine;
+var
+ p1, p2: TPoint;
+begin
+ p1 := Point(0, 0);
+ p2 := Point(1, 1);
+ AssertTrue(IsLineIntersectsLine(Point(1, 0), Point(0, 1), p1, p2));
+ AssertTrue(IsLineIntersectsLine(Point(1, 0), Point(0, 0), p1, p2));
+ AssertTrue(IsLineIntersectsLine(Point(1, 1), Point(2, 2), p1, p2));
+ AssertFalse(IsLineIntersectsLine(Point(2, 2), Point(3, 3), p1, p2));
+ AssertTrue(IsLineIntersectsLine(Point(2, 0), Point(0, 2), p1, p2));
+ AssertFalse(IsLineIntersectsLine(Point(3, 0), Point(0, 3), p1, p2));
+ p2 := Point(1, 0);
+ AssertTrue(IsLineIntersectsLine(Point(0, 0), Point(2, 0), p1, p2));
+ AssertFalse(IsLineIntersectsLine(Point(0, 1), Point(1, 1), p1, p2));
+end;
+
procedure TGeometryTest.TestLineIntersectsRect;
var
r: TDoubleRect = (a: (X: 0; Y: 0); b: (X: 20; Y: 10));
diff --git a/components/tachart/test/test.lpi b/components/tachart/test/test.lpi
index b5df494230..f95e949520 100644
--- a/components/tachart/test/test.lpi
+++ b/components/tachart/test/test.lpi
@@ -62,6 +62,12 @@
+
+
+
+
+
+