Skip to content

Commit 13dfc5b

Browse files
authored
Add Convex Hull in Pascal (TheRenegadeCoder#4803)
1 parent 62015f9 commit 13dfc5b

File tree

1 file changed

+192
-0
lines changed

1 file changed

+192
-0
lines changed

archive/p/pascal/convex_hull.pas

Lines changed: 192 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,192 @@
1+
program ConvexHull;
2+
3+
{$mode objfpc}{$H+}
4+
5+
uses
6+
Classes,
7+
Generics.Collections,
8+
Sysutils;
9+
10+
type
11+
TPoint = record
12+
X, Y: integer;
13+
end;
14+
15+
TPointList = specialize TList<TPoint>;
16+
TIntegerList = specialize TList<integer>;
17+
18+
procedure ShowUsage;
19+
begin
20+
Writeln('Usage: please provide at least 3 x and y coordinates as separate lists (e.g. "100, 440, 210")');
21+
Halt(1);
22+
end;
23+
24+
function ParseIntegerList(const S: string): TIntegerList;
25+
var
26+
Tokens: TStringArray;
27+
Token: string;
28+
Value: integer;
29+
begin
30+
if S.Trim.IsEmpty then
31+
ShowUsage;
32+
33+
Tokens := S.Split([',']);
34+
Result := TIntegerList.Create;
35+
for Token in Tokens do
36+
begin
37+
if not TryStrToInt(Trim(Token), Value) then
38+
begin
39+
Result.Free;
40+
ShowUsage;
41+
end;
42+
Result.Add(Value);
43+
end;
44+
45+
if Result.Count < 3 then
46+
begin
47+
Result.Free;
48+
ShowUsage;
49+
end;
50+
end;
51+
52+
function CheckListLengths(const Xs, Ys: TIntegerList): boolean;
53+
begin
54+
if Xs.Count <> Ys.Count then
55+
Exit(False);
56+
57+
if Xs.Count < 3 then
58+
Exit(false);
59+
60+
Result := True;
61+
end;
62+
63+
procedure QuickSortPoints(List: TPointList; Lo, Hi: integer);
64+
var
65+
i, j: integer;
66+
Pivot, Temp: TPoint;
67+
68+
procedure SwapElements(Index1, Index2: integer);
69+
var
70+
Temp: TPoint;
71+
begin
72+
Temp := List[Index1];
73+
List[Index1] := List[Index2];
74+
List[Index2] := Temp;
75+
end;
76+
77+
begin
78+
while Lo < Hi do
79+
begin
80+
i := Lo;
81+
j := Hi;
82+
Pivot := List[Lo + (Hi - Lo) div 2];
83+
84+
repeat
85+
while (List[i].X < Pivot.X) or ((List[i].X = Pivot.X) and
86+
(List[i].Y < Pivot.Y)) do
87+
Inc(i);
88+
while (List[j].X > Pivot.X) or ((List[j].X = Pivot.X) and
89+
(List[j].Y > Pivot.Y)) do
90+
Dec(j);
91+
92+
if i <= j then
93+
begin
94+
SwapElements(i, j);
95+
Inc(i);
96+
Dec(j);
97+
end;
98+
until i > j;
99+
100+
if (j - Lo) < (Hi - i) then
101+
begin
102+
if Lo < j then QuickSortPoints(List, Lo, j);
103+
Lo := i;
104+
end
105+
else
106+
begin
107+
if i < Hi then QuickSortPoints(List, i, Hi);
108+
Hi := j;
109+
end;
110+
end;
111+
end;
112+
113+
function Cross(const O, A, B: TPoint): int64;
114+
begin
115+
Result := int64(A.X - O.X) * (B.Y - O.Y) - int64(A.Y - O.Y) * (B.X - O.X);
116+
end;
117+
118+
procedure BuildHull(const Points: TPointList; Hull: TPointList);
119+
var
120+
PointCount, i: integer;
121+
CurrentIndex, NextIndex, LeftmostIndex: integer;
122+
begin
123+
PointCount := Points.Count;
124+
if PointCount < 3 then
125+
begin
126+
Hull.AddRange(Points);
127+
Exit;
128+
end;
129+
130+
// Find the leftmost point (with lowest X; if tie, highest Y)
131+
LeftmostIndex := 0;
132+
for i := 1 to PointCount - 1 do
133+
if (Points[i].X < Points[LeftmostIndex].X) or
134+
((Points[i].X = Points[LeftmostIndex].X) and
135+
(Points[i].Y > Points[LeftmostIndex].Y)) then
136+
LeftmostIndex := i;
137+
138+
CurrentIndex := LeftmostIndex;
139+
repeat
140+
Hull.Add(Points[CurrentIndex]);
141+
142+
NextIndex := (CurrentIndex + 1) mod PointCount;
143+
for i := 0 to PointCount - 1 do
144+
if Cross(Points[CurrentIndex], Points[i], Points[NextIndex]) < 0 then
145+
NextIndex := i;
146+
147+
CurrentIndex := NextIndex;
148+
until CurrentIndex = LeftmostIndex;
149+
end;
150+
151+
var
152+
Xs, Ys: TIntegerList;
153+
Points, Hull: TPointList;
154+
i: integer;
155+
Pt: TPoint;
156+
begin
157+
if ParamCount <> 2 then
158+
ShowUsage;
159+
160+
Xs := ParseIntegerList(ParamStr(1));
161+
Ys := ParseIntegerList(ParamStr(2));
162+
163+
if not CheckListLengths(Xs, Ys) then
164+
begin
165+
Xs.Free;
166+
Ys.Free;
167+
ShowUsage;
168+
end;
169+
170+
Points := TPointList.Create;
171+
Hull := TPointList.Create;
172+
try
173+
for i := 0 to Xs.Count - 1 do
174+
begin
175+
Pt.X := Xs[i];
176+
Pt.Y := Ys[i];
177+
Points.Add(Pt);
178+
end;
179+
180+
QuickSortPoints(Points, 0, Points.Count - 1);
181+
BuildHull(Points, Hull);
182+
183+
for i := 0 to Hull.Count - 1 do
184+
Writeln('(', Hull[i].X, ', ', Hull[i].Y, ')');
185+
186+
finally
187+
Xs.Free;
188+
Ys.Free;
189+
Points.Free;
190+
Hull.Free;
191+
end;
192+
end.

0 commit comments

Comments
 (0)