mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-08-17 17:59:16 +02:00
TAChart: Add IsPointInPolygon and IsPolygonIntersectsPolygon utility functions
git-svn-id: trunk@26699 -
This commit is contained in:
parent
761b821f12
commit
aa11530e5a
@ -54,6 +54,8 @@ type
|
|||||||
);
|
);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
TPointArray = array of TPoint;
|
||||||
|
|
||||||
TChartDistance = 0..MaxInt;
|
TChartDistance = 0..MaxInt;
|
||||||
|
|
||||||
TPointDistFunc = function (const A, B: TPoint): Integer;
|
TPointDistFunc = function (const A, B: TPoint): Integer;
|
||||||
@ -189,8 +191,11 @@ procedure ExpandRect(var ARect: TDoubleRect; const APoint: TDoublePoint); inline
|
|||||||
function GetIntervals(AMin, AMax: Double; AInverted: Boolean): TDoubleDynArray;
|
function GetIntervals(AMin, AMax: Double; AInverted: Boolean): TDoubleDynArray;
|
||||||
|
|
||||||
function IsPointOnLine(const AP, A1, A2: TPoint): Boolean; inline;
|
function IsPointOnLine(const AP, A1, A2: TPoint): Boolean; inline;
|
||||||
|
function IsPointInPolygon(
|
||||||
|
const AP: TPoint; const APolygon: array of TPoint): Boolean;
|
||||||
function IsPointInRect(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 IsLineIntersectsLine(const AA, AB, AC, AD: TPoint): Boolean;
|
||||||
|
function IsPolygonIntersectsPolygon(const AP1, AP2: array of TPoint): Boolean;
|
||||||
function LineIntersectsRect(
|
function LineIntersectsRect(
|
||||||
var AA, AB: TDoublePoint; const ARect: TDoubleRect): Boolean;
|
var AA, AB: TDoublePoint; const ARect: TDoubleRect): Boolean;
|
||||||
|
|
||||||
@ -425,6 +430,40 @@ begin
|
|||||||
Result := IsPointInRect(AP, A1, A2) and (PointLineSide(AP, A1, A2) = 0);
|
Result := IsPointInRect(AP, A1, A2) and (PointLineSide(AP, A1, A2) = 0);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function IsPointInPolygon(
|
||||||
|
const AP: TPoint; const APolygon: array of TPoint): Boolean;
|
||||||
|
var
|
||||||
|
i, count: Integer;
|
||||||
|
p1, p2: TPoint;
|
||||||
|
s1, s2: TValueSign;
|
||||||
|
begin
|
||||||
|
if Length(APolygon) = 0 then exit(false);
|
||||||
|
p1 := APolygon[High(APolygon)];
|
||||||
|
for i := 0 to High(APolygon) do begin
|
||||||
|
p2 := APolygon[i];
|
||||||
|
if IsPointOnLine(AP, p1, p2) then exit(true);
|
||||||
|
p1 := p2;
|
||||||
|
end;
|
||||||
|
count := 0;
|
||||||
|
p1 := APolygon[High(APolygon)];
|
||||||
|
for i := 0 to High(APolygon) do begin
|
||||||
|
p2 := APolygon[i];
|
||||||
|
s1 := Sign(p1.Y - AP.Y);
|
||||||
|
s2 := Sign(p2.Y - AP.Y);
|
||||||
|
case s1 * s2 of
|
||||||
|
-1: count += Ord(PointLineSide(AP, p1, p2) = Sign(p1.Y - p2.Y));
|
||||||
|
0: if s1 + s2 = 1 then begin
|
||||||
|
if s1 = 0 then
|
||||||
|
count += Ord(p1.X >= AP.X)
|
||||||
|
else
|
||||||
|
count += Ord(p2.X >= AP.X)
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
p1 := p2;
|
||||||
|
end;
|
||||||
|
Result := count mod 2 = 1;
|
||||||
|
end;
|
||||||
|
|
||||||
function IsPointInRect(const AP, A1, A2: TPoint): Boolean;
|
function IsPointInRect(const AP, A1, A2: TPoint): Boolean;
|
||||||
begin
|
begin
|
||||||
Result := SafeInRange(AP.X, A1.X, A2.X) and SafeInRange(AP.Y, A1.Y, A2.Y);
|
Result := SafeInRange(AP.X, A1.X, A2.X) and SafeInRange(AP.Y, A1.Y, A2.Y);
|
||||||
@ -448,6 +487,24 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function IsPolygonIntersectsPolygon(const AP1, AP2: array of TPoint): Boolean;
|
||||||
|
var
|
||||||
|
i, j: Integer;
|
||||||
|
p1, p2: TPoint;
|
||||||
|
begin
|
||||||
|
if (Length(AP1) = 0) or (Length(AP2) = 0) then exit(false);
|
||||||
|
if IsPointInPolygon(AP1[0], AP2) or IsPointInPolygon(AP2[0], AP1) then
|
||||||
|
exit(true);
|
||||||
|
for i := 0 to High(AP1) do begin
|
||||||
|
p1 := AP1[i];
|
||||||
|
p2 := AP1[(i + 1) mod Length(AP1)];
|
||||||
|
for j := 0 to High(AP2) do
|
||||||
|
if IsLineIntersectsLine(p1, p2, AP2[j], AP2[(j + 1) mod Length(AP2)]) then
|
||||||
|
exit(true);
|
||||||
|
end;
|
||||||
|
Result := false;
|
||||||
|
end;
|
||||||
|
|
||||||
function LineIntersectsRect(
|
function LineIntersectsRect(
|
||||||
var AA, AB: TDoublePoint; const ARect: TDoubleRect): Boolean;
|
var AA, AB: TDoublePoint; const ARect: TDoubleRect): Boolean;
|
||||||
var
|
var
|
||||||
|
@ -49,6 +49,8 @@ type
|
|||||||
procedure TestLineIntersectsLine;
|
procedure TestLineIntersectsLine;
|
||||||
procedure TestLineIntersectsRect;
|
procedure TestLineIntersectsRect;
|
||||||
procedure TestPointOnLine;
|
procedure TestPointOnLine;
|
||||||
|
procedure TestPointInPolygon;
|
||||||
|
procedure TestPolygonIntersectsPolygon;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
@ -183,6 +185,27 @@ begin
|
|||||||
Check(p1, p2, DoublePoint(11.6667, 10), DoublePoint(13.3333, 0));
|
Check(p1, p2, DoublePoint(11.6667, 10), DoublePoint(13.3333, 0));
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TGeometryTest.TestPointInPolygon;
|
||||||
|
var
|
||||||
|
p: TPoint;
|
||||||
|
r: array [1..4] of TPoint =
|
||||||
|
((X: 0; Y: 0), (X: 10; Y: 0), (X: 10; Y: 5), (X: 0; Y: 5));
|
||||||
|
begin
|
||||||
|
p := Point(1, 1);
|
||||||
|
AssertFalse(IsPointInPolygon(p, []));
|
||||||
|
|
||||||
|
AssertTrue(IsPointInPolygon(p, [Point(0, 0), Point(0, 2), Point(3, 0)]));
|
||||||
|
AssertTrue(IsPointInPolygon(p, [Point(0, 0), Point(0, 2), Point(3, 1)]));
|
||||||
|
AssertTrue(IsPointInPolygon(p, [Point(0, 0), Point(0, 2), Point(1, 1)]));
|
||||||
|
AssertFalse(IsPointInPolygon(p, [Point(2, 0), Point(2, 2), Point(3, 1)]));
|
||||||
|
AssertFalse(IsPointInPolygon(p, [Point(2, 0), Point(1, 2), Point(0, 10)]));
|
||||||
|
|
||||||
|
AssertTrue(IsPointInPolygon(Point(5, 5), r));
|
||||||
|
AssertTrue(IsPointInPolygon(Point(10, 5), r));
|
||||||
|
AssertFalse(IsPointInPolygon(Point(11, 5), r));
|
||||||
|
AssertFalse(IsPointInPolygon(Point(0, -1), r));
|
||||||
|
end;
|
||||||
|
|
||||||
procedure TGeometryTest.TestPointOnLine;
|
procedure TGeometryTest.TestPointOnLine;
|
||||||
begin
|
begin
|
||||||
AssertTrue(IsPointOnLine(Point(0, 0), Point(-1, -1), Point(1, 1)));
|
AssertTrue(IsPointOnLine(Point(0, 0), Point(-1, -1), Point(1, 1)));
|
||||||
@ -195,6 +218,29 @@ begin
|
|||||||
AssertFalse(IsPointOnLine(Point(0, 1), Point(-1, 0), Point(1, 0)));
|
AssertFalse(IsPointOnLine(Point(0, 1), Point(-1, 0), Point(1, 0)));
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TGeometryTest.TestPolygonIntersectsPolygon;
|
||||||
|
|
||||||
|
function OffsetPolygon(AP: array of TPoint; AOffset: TPoint): TPointArray;
|
||||||
|
var
|
||||||
|
i: Integer;
|
||||||
|
begin
|
||||||
|
SetLength(Result, Length(AP));
|
||||||
|
for i := 0 to High(AP) do
|
||||||
|
Result[i] := AP[i] + AOffset;
|
||||||
|
end;
|
||||||
|
|
||||||
|
var
|
||||||
|
p1: array [1..4] of TPoint =
|
||||||
|
((X: 0; Y: 0), (X: 10; Y: 0), (X: 10; Y: 5), (X: 0; Y: 5));
|
||||||
|
begin
|
||||||
|
AssertTrue(IsPolygonIntersectsPolygon(p1, OffsetPolygon(p1, Point(0, 0))));
|
||||||
|
AssertTrue(IsPolygonIntersectsPolygon(p1, OffsetPolygon(p1, Point(1, 1))));
|
||||||
|
AssertTrue(IsPolygonIntersectsPolygon(p1, OffsetPolygon(p1, Point(5, 0))));
|
||||||
|
AssertTrue(IsPolygonIntersectsPolygon(p1, OffsetPolygon(p1, Point(10, 0))));
|
||||||
|
AssertFalse(IsPolygonIntersectsPolygon(p1, OffsetPolygon(p1, Point(11, 0))));
|
||||||
|
AssertFalse(IsPolygonIntersectsPolygon(p1, OffsetPolygon(p1, Point(0, -6))));
|
||||||
|
end;
|
||||||
|
|
||||||
initialization
|
initialization
|
||||||
|
|
||||||
RegisterTests([TIntervalListTest, TGeometryTest]);
|
RegisterTests([TIntervalListTest, TGeometryTest]);
|
||||||
|
Loading…
Reference in New Issue
Block a user