1 package org.opentrafficsim.core.geometry;
2
3 import static org.junit.Assert.assertEquals;
4 import static org.junit.Assert.assertFalse;
5 import static org.junit.Assert.assertNotEquals;
6 import static org.junit.Assert.assertTrue;
7 import static org.junit.Assert.fail;
8
9 import java.awt.geom.Path2D;
10 import java.awt.geom.PathIterator;
11 import java.awt.geom.Rectangle2D;
12 import java.util.ArrayList;
13 import java.util.List;
14
15 import org.junit.Test;
16 import org.locationtech.jts.geom.Coordinate;
17 import org.locationtech.jts.geom.CoordinateSequence;
18 import org.locationtech.jts.geom.Geometry;
19 import org.locationtech.jts.geom.GeometryFactory;
20 import org.locationtech.jts.geom.LineString;
21 import org.locationtech.jts.geom.impl.CoordinateArraySequence;
22
23
24
25
26
27
28
29
30
31
32
33
34 public class OTSShapeTest
35 {
36
37
38
39
40 @Test
41 public final void testOTSShape() throws OTSGeometryException
42 {
43 OTSPoint3D p1 = new OTSPoint3D(1, 2, 3);
44 OTSPoint3D p2 = new OTSPoint3D(10, 2, 3);
45 OTSPoint3D p3 = new OTSPoint3D(11, 22, 3);
46
47 OTSShape s = new OTSShape(p1, p2, p3);
48 verifyShape(s, true, p1, p2, p3);
49 s = new OTSShape(new Coordinate[] {p1.getCoordinate(), p2.getCoordinate(), p3.getCoordinate()});
50 verifyShape(s, true, p1, p2, p3);
51 GeometryFactory factory = new GeometryFactory();
52 CoordinateSequence cs =
53 new CoordinateArraySequence(new Coordinate[] {p1.getCoordinate(), p2.getCoordinate(), p3.getCoordinate()});
54 LineString ls = new LineString(cs, factory);
55 s = new OTSShape(ls);
56 verifyShape(s, true, p1, p2, p3);
57 Geometry g = ls;
58 s = new OTSShape(g);
59 verifyShape(s, true, p1, p2, p3);
60 List<OTSPoint3D> list = new ArrayList<>();
61 list.add(p1);
62 list.add(p2);
63 list.add(p3);
64 s = new OTSShape(list);
65 verifyShape(s, true, p1, p2, p3);
66 Path2D path = new Path2D.Double();
67 path.moveTo(p1.x, p1.y);
68 path.lineTo(p2.x, p2.y);
69 path.lineTo(p3.x, p3.y);
70 s = new OTSShape(path);
71 verifyShape(s, false, p1, p2, p3);
72 Path2D shape = s.getShape();
73 PathIterator pi = shape.getPathIterator(null);
74 assertFalse(pi.isDone());
75 double[] coords = new double[6];
76 assertEquals("must be SEG_MOVETO", PathIterator.SEG_MOVETO, pi.currentSegment(coords));
77 assertEquals("x", p1.x, coords[0], 0.00001);
78 assertEquals("y", p1.y, coords[1], 0.00001);
79 pi.next();
80 assertFalse(pi.isDone());
81 assertEquals("must be SEG_LINETO", PathIterator.SEG_LINETO, pi.currentSegment(coords));
82 assertEquals("x", p2.x, coords[0], 0.00001);
83 assertEquals("y", p2.y, coords[1], 0.00001);
84 pi.next();
85 assertFalse(pi.isDone());
86 assertEquals("must be SEG_LINETO", PathIterator.SEG_LINETO, pi.currentSegment(coords));
87 assertEquals("x", p3.x, coords[0], 0.00001);
88 assertEquals("y", p3.y, coords[1], 0.00001);
89 pi.next();
90 assertFalse(pi.isDone());
91 assertEquals("must be SEG_CLOSE", PathIterator.SEG_CLOSE, pi.currentSegment(coords));
92 pi.next();
93 assertTrue(pi.isDone());
94 Path2D shape2 = s.getShape();
95 assertEquals("repeated get returns same thing", shape, shape2);
96 OTSPoint3D insidePoint = new OTSPoint3D(5, 5, 5);
97 assertTrue("shape contains inSide point", s.contains(insidePoint));
98 OTSPoint3D outsidePoint = new OTSPoint3D(-1, -2, -3);
99 assertFalse("shape does not contains unrelated point", s.contains(outsidePoint));
100 outsidePoint = new OTSPoint3D(0, 5, 5);
101 assertFalse("shape does not contains unrelated point", s.contains(outsidePoint));
102 outsidePoint = new OTSPoint3D(12, 5, 5);
103 assertFalse("shape does not contains unrelated point", s.contains(outsidePoint));
104 outsidePoint = new OTSPoint3D(5, 30, 5);
105 assertFalse("shape does not contains unrelated point", s.contains(outsidePoint));
106 Rectangle2D inRect = new Rectangle2D.Double(5, 5, 1, 1);
107 assertTrue("rectangle is inside shape", s.contains(inRect));
108 Rectangle2D partlyOutRect = new Rectangle2D.Double(5, 5, 20, 1);
109 assertFalse("Rectangle is not fully inside shape", s.contains(partlyOutRect));
110 partlyOutRect = new Rectangle2D.Double(5, 5, 1, 30);
111 assertFalse("Rectangle is not fully inside shape", s.contains(partlyOutRect));
112 assertTrue("toString result contains class name", s.toString().contains("OTSShape"));
113 path.closePath();
114 OTSShape s2 = new OTSShape(path);
115
116
117 assertNotEquals("shape from closed path is not equal to shape from unclosed path", s, s2);
118 assertEquals("Size of shape from closed path is one longer than size of shape from unclosed path", s.size() + 1,
119 s2.size());
120 for (int index = 0; index < s.size(); index++)
121 {
122 assertEquals("point at index matches", s.getCoordinates()[index], s2.getCoordinates()[index]);
123 }
124 assertEquals("Last coordinate of closed shape equals first coordinate", s2.getCoordinates()[0],
125 s2.getCoordinates()[s2.size() - 1]);
126 }
127
128
129
130
131
132 @Test
133 public final void testIntersects() throws OTSGeometryException
134 {
135 double radius = 10;
136 double cx = 5;
137 double cy = -5;
138 OTSShape reference = new OTSShape(makePolygon(cx, cy, radius, 18));
139 for (int dx = -20; dx <= 20; dx++)
140 {
141 for (int dy = -20; dy <= 20; dy++)
142 {
143 boolean hit = true;
144 double distance = Math.sqrt(dx * dx + dy * dy);
145 double radius2 = 2;
146 if (distance > radius + radius2)
147 {
148 hit = false;
149 }
150 else if (distance > radius + radius2 - 0.1)
151 {
152 continue;
153 }
154 OTSShape other = new OTSShape(makePolygon(cx + dx, cy + dy, radius2, 16));
155 if (hit)
156 {
157 assertTrue("shapes hit", reference.intersects(other));
158 }
159 else
160 {
161 assertFalse("shapes do not hit", reference.intersects(other));
162 }
163 }
164 }
165 reference =
166 new OTSShape(new OTSPoint3D[] {new OTSPoint3D(0, 0, 0), new OTSPoint3D(10, 0, 0), new OTSPoint3D(10, 10, 0)});
167
168 for (int dx = -20; dx <= 20; dx++)
169 {
170 OTSShape other = new OTSShape(
171 new OTSPoint3D[] {new OTSPoint3D(dx, 0, 0), new OTSPoint3D(dx + 5, 0, 0), new OTSPoint3D(dx, -20, 0)});
172 boolean hit = dx >= -5 && dx <= 10;
173 if (hit)
174 {
175 assertTrue("shapes hit", reference.intersects(other));
176 }
177 else
178 {
179 assertFalse("shapes do not hit", reference.intersects(other));
180 }
181 }
182
183 for (int dy = -20; dy <= 20; dy++)
184 {
185 OTSShape other = new OTSShape(
186 new OTSPoint3D[] {new OTSPoint3D(20, dy, 0), new OTSPoint3D(10, dy, 0), new OTSPoint3D(10, dy + 10, 0)});
187 boolean hit = dy >= -10 && dy <= 10;
188 if (hit)
189 {
190 assertTrue("shapes hit", reference.intersects(other));
191 }
192 else
193 {
194 assertFalse("shapes do not hit", reference.intersects(other));
195 }
196 }
197
198 OTSShape vertical = new OTSShape(new OTSPoint3D[] {new OTSPoint3D(-1, -10, 0), new OTSPoint3D(1, -10, 0),
199 new OTSPoint3D(1, 10, 0), new OTSPoint3D(-1, 10, 0), new OTSPoint3D(-1, -10, 0)});
200 OTSShape horizontal = new OTSShape(new OTSPoint3D[] {new OTSPoint3D(-10, -1, 0), new OTSPoint3D(10, -1, 0),
201 new OTSPoint3D(10, 1, 0), new OTSPoint3D(-10, 1, 0), new OTSPoint3D(-10, -1, 0)});
202 assertTrue("shapes hit", vertical.intersects(horizontal));
203 }
204
205
206
207
208
209 @Test
210 public final void testCleanConstructors() throws OTSGeometryException
211 {
212 try
213 {
214 OTSShape.createAndCleanOTSShape(new OTSPoint3D[] {});
215 fail("empty array should have thrown an OTSGeometryException");
216 }
217 catch (OTSGeometryException oge)
218 {
219
220 }
221 try
222 {
223 OTSShape.createAndCleanOTSShape(new OTSPoint3D[] {new OTSPoint3D(1, 2, 3)});
224 fail("array of one point should have thrown an OTSGeometryException");
225 }
226 catch (OTSGeometryException oge)
227 {
228
229 }
230 try
231 {
232 OTSShape.createAndCleanOTSShape(new OTSPoint3D[] {new OTSPoint3D(1, 2, 3), new OTSPoint3D(1, 2, 3)});
233 fail("array of two identical points should have thrown an OTSGeometryException");
234 }
235 catch (OTSGeometryException oge)
236 {
237
238 }
239 try
240 {
241 OTSShape.createAndCleanOTSShape(
242 new OTSPoint3D[] {new OTSPoint3D(1, 2, 3), new OTSPoint3D(1, 2, 3), new OTSPoint3D(1, 2, 3)});
243 fail("array of three identical points should have thrown an OTSGeometryException");
244 }
245 catch (OTSGeometryException oge)
246 {
247
248 }
249
250 OTSShape.createAndCleanOTSShape(new OTSPoint3D[] {new OTSPoint3D(1, 2, 3), new OTSPoint3D(1, 2, 1)});
251 OTSShape.createAndCleanOTSShape(
252 new OTSPoint3D[] {new OTSPoint3D(1, 2, 3), new OTSPoint3D(1, 3, 3), new OTSPoint3D(1, 2, 3)});
253 List<OTSPoint3D> points = new ArrayList<>();
254 points.add(new OTSPoint3D(1, 2, 3));
255 points.add(new OTSPoint3D(1, 2, 3));
256 points.add(new OTSPoint3D(1, 2, 3));
257 points.add(new OTSPoint3D(1, 2, 3));
258 try
259 {
260 OTSShape.createAndCleanOTSShape(points);
261 fail("list of four identical points should have thrown an OTSGeometryException");
262 }
263 catch (OTSGeometryException oge)
264 {
265
266 }
267
268 assertEquals("list now has only one point", 1, points.size());
269 }
270
271
272
273
274
275
276
277
278
279
280 private List<OTSPoint3D> makePolygon(final double centerX, final double centerY, final double radius, final int size)
281 throws OTSGeometryException
282 {
283 List<OTSPoint3D> points = new ArrayList<>(size);
284 for (int i = 0; i < size; i++)
285 {
286 double angle = Math.PI * 2 * i / size;
287 points.add(new OTSPoint3D(centerX + radius * Math.cos(angle), centerY + radius * Math.sin(angle)));
288 }
289 return points;
290 }
291
292
293
294
295
296
297
298
299 private void verifyShape(final OTSShape shape, final boolean verifyZ, final OTSPoint3D... points)
300 throws OTSGeometryException
301 {
302 assertEquals("shape contains correct number of points", shape.size(), points.length);
303 for (int i = 0; i < points.length; i++)
304 {
305 assertEquals("point 1 matches x", points[i].x, shape.get(i).x, 0.0001);
306 assertEquals("point 1 matches y", points[i].y, shape.get(i).y, 0.0001);
307 if (verifyZ)
308 {
309 assertEquals("point 1 matches z", points[i].z, shape.get(i).z, 0.0001);
310 }
311 else
312 {
313 assertEquals("point 1 z is 0", 0, shape.get(i).z, 0.0000001);
314 }
315 }
316 }
317
318 }