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