1 package com.github.celldynamics.quimp.geom;
2
3 import java.util.ArrayList;
4 import java.util.Iterator;
5 import java.util.List;
6
7 import org.scijava.vecmath.Point2d;
8 import org.scijava.vecmath.Tuple2d;
9 import org.scijava.vecmath.Vector2d;
10 import org.slf4j.Logger;
11 import org.slf4j.LoggerFactory;
12
13
14
15
16
17
18
19 public class BasicPolygons {
20
21
22
23
24 static final Logger LOGGER = LoggerFactory.getLogger(BasicPolygons.class.getName());
25
26
27
28
29 public BasicPolygons() {
30
31 }
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46 public double getPolyArea(final List<? extends Tuple2d> p) {
47 int i;
48 int j;
49 double area = 0;
50
51 for (i = 0; i < p.size(); i++) {
52 j = (i + 1) % p.size();
53 Tuple2d pi = p.get(i);
54 Tuple2d pj = p.get(j);
55 area += pi.getX() * pj.getY();
56 area -= pi.getY() * pj.getX();
57 }
58 area /= 2.0;
59 return (Math.abs(area));
60 }
61
62
63
64
65
66
67
68 public double getPolyPerim(final List<? extends Tuple2d> p) {
69 int i;
70 int j;
71 double len = 0;
72 ArrayList<Vector2d> tmpV = new ArrayList<>();
73
74 for (i = 0; i < p.size(); i++) {
75 j = (i + 1) % p.size();
76 Tuple2d first = p.get(i);
77 Tuple2d second = p.get(j);
78 Vector2d tmp = new Vector2d(second.getX() - first.getX(), second.getY() - first.getY());
79 tmpV.add(tmp);
80 }
81 for (Vector2d v : tmpV) {
82 len += v.length();
83 }
84 return len;
85 }
86
87
88
89
90
91
92
93
94
95
96 public boolean isPointInside(final List<? extends Tuple2d> p, final Tuple2d testP) {
97 double angle = 0;
98 Point2d p1 = null;
99 Point2d p2 = null;
100 for (int i = 0; i < p.size(); i++) {
101 p1 = new Point2d(p.get(i).getX() - testP.getX(), p.get(i).getY() - testP.getY());
102 p2 = new Point2d(p.get((i + 1) % p.size()).getX() - testP.getX(),
103 p.get((i + 1) % p.size()).getY() - testP.getY());
104 angle += angle2D(p1, p2);
105 }
106 return Math.abs(angle) >= Math.PI;
107 }
108
109
110
111
112
113
114
115
116 private double angle2D(Point2d p1, Point2d p2) {
117 double dtheta = Math.atan2(p2.y, p2.x) - Math.atan2(p1.y, p1.x);
118 while (dtheta > Math.PI) {
119 dtheta -= 2.0 * Math.PI;
120 }
121 while (dtheta < -1.0 * Math.PI) {
122 dtheta += 2.0 * Math.PI;
123 }
124 return dtheta;
125 }
126
127
128
129
130
131
132
133
134
135
136 public boolean areAllPointsInside(final List<? extends Tuple2d> polygon,
137 final List<? extends Tuple2d> testP) {
138 boolean result = true;
139 Iterator<? extends Tuple2d> it = testP.iterator();
140 while (it.hasNext() && result) {
141 result = isPointInside(polygon, it.next());
142 }
143 return result;
144 }
145
146
147
148
149
150
151
152
153
154
155 public boolean areAllPointOutside(final List<? extends Tuple2d> polygon,
156 final List<? extends Tuple2d> testP) {
157 boolean result = false;
158 Iterator<? extends Tuple2d> it = testP.iterator();
159 while (it.hasNext() && !result) {
160 result = isPointInside(polygon, it.next());
161 }
162 return !result;
163 }
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178 public Point2d polygonCenterOfMass(final List<? extends Tuple2d> polygon) {
179
180 int n = polygon.size();
181 Point2d[] polygonTmp = new Point2d[n];
182
183 for (int q = 0; q < n; q++) {
184 polygonTmp[q] = new Point2d(polygon.get(q));
185 }
186
187 double cx = 0;
188 double cy = 0;
189 double a = getPolyArea(polygon);
190 if (a == 0) {
191 throw new IllegalArgumentException("Defective polygon, area is 0");
192 }
193 int i;
194 int j;
195
196 double factor = 0;
197 for (i = 0; i < n; i++) {
198 j = (i + 1) % n;
199 factor = (polygonTmp[i].x * polygonTmp[j].y - polygonTmp[j].x * polygonTmp[i].y);
200 cx += (polygonTmp[i].x + polygonTmp[j].x) * factor;
201 cy += (polygonTmp[i].y + polygonTmp[j].y) * factor;
202 }
203 factor = 1.0 / (6.0 * a);
204 cx *= factor;
205 cy *= factor;
206 return new Point2d(Math.abs(cx), Math.abs((cy)));
207 }
208
209 }