2 import java
.util
.ArrayList
;
3 import java
.util
.Arrays
;
4 import java
.util
.Collections
;
8 * @author romis_000, Johan
10 public class ConvexPolygon
{
12 private ArrayList
<PointDouble
> points
= new ArrayList
<PointDouble
>();
14 public ConvexPolygon(ArrayList
<PointDouble
> points
) {
18 public ArrayList
<PointDouble
> getPointDoubles() {
22 public double[] GetXPointDoubles() {
23 double xpoints
[] = new double[this.points
.size()];
25 for (PointDouble p
: this.points
) {
32 public double[] GetYPointDoubles() {
33 double ypoints
[] = new double[this.points
.size()];
35 for (PointDouble p
: this.points
) {
42 public double[][] getVertices() {
43 double[][] vertices
= new double[points
.size()][2];
44 for (int i
= 0; i
< points
.size(); ++i
) {
45 vertices
[i
][0] = points
.get(i
).x
;
46 vertices
[i
][1] = points
.get(i
).y
;
52 * Returns the axis corresponding to the edges of the polygon, used to check
53 * for detection collision
55 public PointDouble
[] Getaxes() {
56 PointDouble
[] axes
= new PointDouble
[this.points
.size()];
57 for (int i
= 0; i
< this.points
.size(); i
++) {
58 // get the current vertex
59 PointDouble v1
= new PointDouble(this.points
.get(i
).getX(), this.points
.get(i
).getY());
60 // get the next vertex
61 PointDouble v2
= new PointDouble(this.points
.get(i
+ 1 == this.points
.size() ?
0 : i
+ 1).getX(), this.points
.get(i
+ 1 == this.points
.size() ?
0 : i
+ 1).getY());
62 // subtract the two to get the edge vector
63 PointDouble edge
= new PointDouble((v1
.x
+ (-v2
.x
)), (v1
.y
+ (-v2
.y
)));
64 // get either perpendicular vector
65 PointDouble normal
= new PointDouble((-edge
.y
), edge
.x
);
66 // the perp method is just (x, y) => (-y, x) or (y, -x)
73 * Checks if the polygon is convex
75 public boolean isConvex() {
76 PointDouble prev
= points
.get(points
.size() - 2);
77 PointDouble curr
= points
.get(points
.size() - 1);
78 PointDouble next
= points
.get(0);
79 // Are the first two selected edges making a turnleft ?
80 boolean isCCW
= turnLeft(prev
, curr
, next
);
81 // Verify if all the edges are making the same type of angle as the first two
82 for (int i
= 1; i
< points
.size(); i
++) {
86 if (turnLeft(prev
, curr
, next
) != isCCW
) {
94 * Checks if a given point is within the polygon
96 public boolean contain(PointDouble p
) {
97 PointDouble prev
= points
.get(points
.size() - 1);
99 PointDouble next
= points
.get(0);
100 // Is the point left or right of the selected edge ?
101 boolean isCCW
= turnLeft(prev
, curr
, next
);
102 // Is the point the same side of every other edges of the polygon ?
103 for (int i
= 1; i
< points
.size(); i
++) {
105 next
= points
.get(i
);
106 if (turnLeft(prev
, curr
, next
) != isCCW
) {
114 * Check the sign of the angle between vectors [p1, p2] and [p2, p3]
115 * with the cross product
117 public boolean turnLeft(PointDouble p1
, PointDouble p2
, PointDouble p3
) {
118 return ((p2
.getX() - p1
.getX()) * (p3
.getY()
119 - p2
.getY()) - (p3
.getX() - p2
.getX()) * (p2
.getY() - p1
.getY())) > 0;
123 * Checks if the vertices of the polygon are in counter-clock wise order
124 * The vertices of the polygon need to be sorted for this test
126 public boolean isCCW() {
127 double min
= points
.get(0).getY();
129 for (int i
= 1; i
< points
.size() - 1; i
++) {
130 if (points
.get(i
).getY() < min
) {
131 min
= points
.get(i
).getY();
135 PointDouble prev
= points
.get((minIndex
- 1 + points
.size()) % points
.size());
136 PointDouble next
= points
.get((minIndex
+ 1) % points
.size());
137 return turnLeft(prev
, points
.get(minIndex
), next
);
141 * Calculates the convex hull of list of points
142 * Using the monotone chain algorithm
144 public ConvexPolygon
convexHull(ArrayList
<PointDouble
> points
) {
145 Collections
.sort(points
, new PointXCompare());
146 int n
= points
.size();
148 ArrayList
<PointDouble
> pl1
= new ArrayList
<PointDouble
>();
149 ArrayList
<PointDouble
> pl2
= new ArrayList
<PointDouble
>();
150 for (int i
= 0; i
< n
; i
++) {
151 while (pl2
.size() >= 2 && !(turnLeft(pl2
.get(pl2
.size() - 2), pl2
.get(pl2
.size() - 1), points
.get(i
)))) {
152 pl2
.remove(pl2
.get(pl2
.size() - 1));
154 pl2
.add(points
.get(i
));
156 for (int i
= n
- 1; i
>= 0; i
--) {
157 while (pl1
.size() >= 2 && !(turnLeft(pl1
.get(pl1
.size() - 2), pl1
.get(pl1
.size() - 1), points
.get(i
)))) {
158 pl1
.remove(pl1
.get(pl1
.size() - 1));
160 pl1
.add(points
.get(i
));
162 pl1
.remove(pl1
.size() - 1);
163 pl2
.remove(pl2
.size() - 1);
165 return new ConvexPolygon(pl2
);
169 * Translates the polygon from the given numbers
171 public void translate(double x
, double y
) {
172 for (PointDouble p
: this.points
) {
179 * Checks for an intersection between the polygon and the second given
182 public Boolean
intersects(ConvexPolygon pol2
) {
183 PointDouble
[] axes1
= this.Getaxes();
184 PointDouble
[] axes2
= pol2
.Getaxes();
185 for (int i
= 0; i
< axes1
.length
; i
++) {
186 PointDouble axis
= axes1
[i
];
187 // project both shapes onto the axis
188 Projection p1
= this.project(axis
);
189 Projection p2
= pol2
.project(axis
);
190 // do the projections overlap?
191 if (!p1
.overlap(p2
)) {
192 // then we can guarantee that the shapes do not overlap
196 for (int i
= 0; i
< axes2
.length
; i
++) {
197 PointDouble axis
= axes2
[i
];
198 Projection p1
= this.project(axis
);
199 Projection p2
= pol2
.project(axis
);
200 if (!p1
.overlap(p2
)) {
208 * Generates a projection of an edge of the polygon on a given axis
210 public Projection
project(PointDouble axis
) {
211 double min
= ((axis
.x
* this.points
.get(0).x
) + (axis
.y
* this.points
.get(0).y
));
213 for (int i
= 1; i
< this.points
.size(); i
++) {
214 double p
= ((axis
.x
* this.points
.get(i
).x
) + (axis
.y
* this.points
.get(i
).y
));
217 } else if (p
> max
) {
221 Projection proj
= new Projection(min
, max
);
225 public Boolean
hasVertex(PointDouble pt
) {
226 for (int i
= 0; i
< this.points
.size(); i
++) {
227 //for (int i = 0; i < this.points.size() - 1; i++) {
228 if (this.points
.get(i
).equals(pt
)) {
235 public Boolean
deleteVertex(PointDouble pt
) {
236 if (this.points
.size() > 3) {
237 for (int i
= 0; i
< this.points
.size(); i
++) {
238 if (this.points
.get(i
).equals(pt
)) {
239 this.points
.remove(i
);
248 * Sorts the vertices of the polygon in an order specified by the sorter
251 public void sortVertices(PolygonSorter sorter
) {
252 PointDouble
[] arrPointDoubles
= points
.toArray(new PointDouble
[points
.size()]);
253 Arrays
.sort(arrPointDoubles
, sorter
);
255 points
.addAll(Arrays
.asList(arrPointDoubles
));
259 * Add a vertex to the polygon
260 * Return true if the vertex is added to the polygon
261 * Return false otherwise, which means that the addition
262 * of the vertex would have made it concave.
264 public Boolean
addVertex(PointDouble pt
) {
265 // Make a temporary list to check some properties of the new polygon
266 ArrayList
<PointDouble
> tempList
= new ArrayList
<>(Arrays
.asList(this.points
.toArray(new PointDouble
[this.points
.size()])));
268 // Create a temporary polygon
269 ConvexPolygon tempPolygon
= new ConvexPolygon(tempList
);
271 tempPolygon
.sortVertices(new AntiClockSort(tempPolygon
.getVertices()));
272 // We need the new polygon to be convex, or we can't accept to add the new vertex.
273 if (tempPolygon
.isConvex()) {
274 this.points
= tempPolygon
.points
;