Skip to content
This repository was archived by the owner on Nov 19, 2020. It is now read-only.

Commit e226f7c

Browse files
committed
Optimise data structures being used by Graham Convex Hull implementation
1 parent 8532311 commit e226f7c

File tree

1 file changed

+34
-35
lines changed

1 file changed

+34
-35
lines changed

Sources/Accord.Math/AForge.Math/Geometry/GrahamConvexHull.cs

Lines changed: 34 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -60,87 +60,86 @@ public List<IntPoint> FindHull(List<IntPoint> points)
6060
return new List<IntPoint>(points);
6161
}
6262

63-
List<PointToProcess> pointsToProcess = new List<PointToProcess>();
64-
65-
// convert input points to points we can process
66-
foreach (IntPoint point in points)
67-
{
68-
pointsToProcess.Add(new PointToProcess(point));
69-
}
70-
7163
// find a point, with lowest X and lowest Y
7264
int firstCornerIndex = 0;
73-
PointToProcess firstCorner = pointsToProcess[0];
65+
IntPoint pointFirstCorner = points[0];
7466

75-
for (int i = 1, n = pointsToProcess.Count; i < n; i++)
67+
for (int i = 1, n = points.Count; i < n; i++)
7668
{
77-
if ((pointsToProcess[i].X < firstCorner.X) ||
78-
((pointsToProcess[i].X == firstCorner.X) && (pointsToProcess[i].Y < firstCorner.Y)))
69+
if ((points[i].X < pointFirstCorner.X) ||
70+
((points[i].X == pointFirstCorner.X) && (points[i].Y < pointFirstCorner.Y)))
7971
{
80-
firstCorner = pointsToProcess[i];
72+
pointFirstCorner = points[i];
8173
firstCornerIndex = i;
8274
}
8375
}
8476

85-
// remove the just found point
86-
pointsToProcess.RemoveAt(firstCornerIndex);
77+
// convert input points to points we can process
78+
PointToProcess firstCorner = new PointToProcess(pointFirstCorner);
79+
// Points to process must exclude the first corner that we've already found
80+
PointToProcess[] arrPointsToProcess = new PointToProcess[points.Count - 1];
81+
for (int i = 0; i < points.Count - 1; i++)
82+
{
83+
IntPoint point = points[i >= firstCornerIndex ? i + 1 : i];
84+
arrPointsToProcess[i] = new PointToProcess(point);
85+
}
8786

8887
// find K (tangent of line's angle) and distance to the first corner
89-
for (int i = 0, n = pointsToProcess.Count; i < n; i++)
88+
for (int i = 0, n = arrPointsToProcess.Length; i < n; i++)
9089
{
91-
int dx = pointsToProcess[i].X - firstCorner.X;
92-
int dy = pointsToProcess[i].Y - firstCorner.Y;
90+
int dx = arrPointsToProcess[i].X - firstCorner.X;
91+
int dy = arrPointsToProcess[i].Y - firstCorner.Y;
9392

9493
// don't need square root, since it is not important in our case
95-
pointsToProcess[i].Distance = dx * dx + dy * dy;
94+
arrPointsToProcess[i].Distance = dx * dx + dy * dy;
9695
// tangent of lines angle
97-
pointsToProcess[i].K = (dx == 0) ? float.PositiveInfinity : (float)dy / dx;
96+
arrPointsToProcess[i].K = (dx == 0) ? float.PositiveInfinity : (float) dy / dx;
9897
}
9998

10099
// sort points by angle and distance
101-
pointsToProcess.Sort();
100+
Array.Sort(arrPointsToProcess);
102101

103-
List<PointToProcess> convexHullTemp = new List<PointToProcess>();
102+
// Convert points to process to a queue. Continually removing the first item of an array list
103+
// is highly inefficient
104+
Queue<PointToProcess> queuePointsToProcess = new Queue<PointToProcess>(arrPointsToProcess);
105+
106+
LinkedList<PointToProcess> convexHullTemp = new LinkedList<PointToProcess>();
104107

105108
// add first corner, which is always on the hull
106-
convexHullTemp.Add(firstCorner);
109+
PointToProcess prevPoint = convexHullTemp.AddLast(firstCorner).Value;
107110
// add another point, which forms a line with lowest slope
108-
convexHullTemp.Add(pointsToProcess[0]);
109-
pointsToProcess.RemoveAt(0);
110-
111-
PointToProcess lastPoint = convexHullTemp[1];
112-
PointToProcess prevPoint = convexHullTemp[0];
111+
PointToProcess lastPoint = convexHullTemp.AddLast(queuePointsToProcess.Dequeue()).Value;
113112

114-
while (pointsToProcess.Count != 0)
113+
while (queuePointsToProcess.Count != 0)
115114
{
116-
PointToProcess newPoint = pointsToProcess[0];
115+
PointToProcess newPoint = queuePointsToProcess.Peek();
117116

118117
// skip any point, which has the same slope as the last one or
119118
// has 0 distance to the first point
120119
if ((newPoint.K == lastPoint.K) || (newPoint.Distance == 0))
121120
{
122-
pointsToProcess.RemoveAt(0);
121+
queuePointsToProcess.Dequeue();
123122
continue;
124123
}
125124

126125
// check if current point is on the left side from two last points
127126
if ((newPoint.X - prevPoint.X) * (lastPoint.Y - newPoint.Y) - (lastPoint.X - newPoint.X) * (newPoint.Y - prevPoint.Y) < 0)
128127
{
129128
// add the point to the hull
130-
convexHullTemp.Add(newPoint);
129+
convexHullTemp.AddLast(newPoint);
131130
// and remove it from the list of points to process
132-
pointsToProcess.RemoveAt(0);
131+
queuePointsToProcess.Dequeue();
133132

134133
prevPoint = lastPoint;
135134
lastPoint = newPoint;
136135
}
137136
else
138137
{
139138
// remove the last point from the hull
140-
convexHullTemp.RemoveAt(convexHullTemp.Count - 1);
139+
convexHullTemp.RemoveLast();
141140

142141
lastPoint = prevPoint;
143-
prevPoint = convexHullTemp[convexHullTemp.Count - 2];
142+
prevPoint = convexHullTemp.Last.Previous.Value;
144143
}
145144
}
146145

0 commit comments

Comments
 (0)