2 Copyright (c) 2003-2006 Niels Kokholm and Peter Sestoft
3 Permission is hereby granted, free of charge, to any person obtaining a copy
4 of this software and associated documentation files (the "Software"), to deal
5 in the Software without restriction, including without limitation the rights
6 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 copies of the Software, and to permit persons to whom the Software is
8 furnished to do so, subject to the following conditions:
10 The above copyright notice and this permission notice shall be included in
11 all copies or substantial portions of the Software.
13 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 // csc /r:C5.dll GConvexHull.cs
30 // Find the convex hull of a point set in the plane
32 // An implementation of Graham's (1972) point elimination algorithm,
33 // as modified by Andrew (1979) to find lower and upper hull separately.
35 // This implementation correctly handle duplicate points, and
36 // multiple points with the same x-coordinate.
38 // 1. Sort the points lexicographically by increasing (x,y), thus
39 // finding also a leftmost point L and a rightmost point R.
40 // 2. Partition the point set into two lists, upper and lower, according as
41 // point is above or below the segment LR. The upper list begins with
42 // L and ends with R; the lower list begins with R and ends with L.
43 // 3. Traverse the point lists clockwise, eliminating all but the extreme
44 // points (thus eliminating also duplicate points).
45 // 4. Join the point lists (in clockwise order) in an array,
46 // leaving out L from lower and R from upper.
48 public class Convexhull
50 public static Point
[] ConvexHull(Point
[] pts
)
52 // 1. Sort points lexicographically by increasing (x, y)
55 Point left
= pts
[0], right
= pts
[N
- 1];
56 // 2. Partition into lower hull and upper hull
57 IList
<Point
> lower
= new LinkedList
<Point
>(),
58 upper
= new LinkedList
<Point
>();
59 lower
.InsertFirst(left
); upper
.InsertLast(left
);
60 for (int i
= 0; i
< N
; i
++)
62 double det
= Point
.Area2(left
, right
, pts
[i
]);
64 lower
.InsertFirst(pts
[i
]);
66 upper
.InsertLast(pts
[i
]);
68 lower
.InsertFirst(right
);
69 upper
.InsertLast(right
);
70 // 3. Eliminate points not on the hull
73 // 4. Join the lower and upper hull, leaving out lower.Last and upper.Last
74 Point
[] res
= new Point
[lower
.Count
+ upper
.Count
- 2];
75 lower
[0, lower
.Count
- 1].CopyTo(res
, 0);
76 upper
[0, upper
.Count
- 1].CopyTo(res
, lower
.Count
- 1);
81 public static void Eliminate(IList
<Point
> lst
)
83 IList
<Point
> view
= lst
.View(0, 0);
85 while (view
.TrySlide(slide
, 3))
86 if (Point
.Area2(view
[0], view
[1], view
[2]) < 0) // right turn
91 slide
= view
.Offset
!= 0 ? -1 : 0;
96 // ------------------------------------------------------------
98 // Points in the plane
100 public class Point
: IComparable
<Point
>
102 private static readonly C5Random rnd
= new C5Random(42);
104 public readonly double x
, y
;
106 public Point(double x
, double y
)
108 this.x
= x
; this.y
= y
;
111 public override string ToString()
113 return "(" + x
+ ", " + y
+ ")";
116 public static Point
Random(int w
, int h
)
118 return new Point(rnd
.Next(w
), rnd
.Next(h
));
121 public bool Equals(Point p2
)
123 return x
== p2
.x
&& y
== p2
.y
;
126 public int CompareTo(Point p2
)
128 int major
= x
.CompareTo(p2
.x
);
129 return major
!= 0 ? major
: y
.CompareTo(p2
.y
);
132 // Twice the signed area of the triangle (p0, p1, p2)
133 public static double Area2(Point p0
, Point p1
, Point p2
)
135 return p0
.x
* (p1
.y
- p2
.y
) + p1
.x
* (p2
.y
- p0
.y
) + p2
.x
* (p0
.y
- p1
.y
);
139 // ------------------------------------------------------------
143 static void Main(String
[] args
)
145 if (args
.Length
== 1)
147 string arg
= args
[0];
148 int N
= int.Parse(arg
);
149 Point
[] pts
= new Point
[N
];
150 for (int i
= 0; i
< N
; i
++)
151 pts
[i
] = Point
.Random(500, 500);
152 Point
[] chpts
= Convexhull
.ConvexHull(pts
);
153 Console
.WriteLine("Area is " + Area(chpts
));
157 Console
.WriteLine("Usage: GConvexHull <pointcount>\n");
160 // The area of a polygon (represented by an array of ordered vertices)
161 public static double Area(Point
[] pts
)
164 Point origo
= new Point(0, 0);
166 for (int i
= 0; i
< N
; i
++)
167 area2
+= Point
.Area2(origo
, pts
[i
], pts
[(i
+ 1) % N
]);
168 return Math
.Abs(area2
/ 2);
171 public static void Print(Point
[] pts
)
174 for (int i
= 0; i
< N
; i
++)
175 Console
.WriteLine(pts
[i
]);