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
16 import com.vividsolutions.jts.geom.Coordinate;
17 import com.vividsolutions.jts.geom.CoordinateSequence;
18 import com.vividsolutions.jts.geom.Geometry;
19 import com.vividsolutions.jts.geom.GeometryFactory;
20 import com.vividsolutions.jts.geom.LineString;
21 import com.vividsolutions.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 }
114
115
116
117
118
119 @Test
120 public final void testIntersects() throws OTSGeometryException
121 {
122 double radius = 10;
123 double cx = 5;
124 double cy = -5;
125 OTSShape reference = new OTSShape(makePolygon(cx, cy, radius, 18));
126 for (int dx = -20; dx <= 20; dx++)
127 {
128 for (int dy = -20; dy <= 20; dy++)
129 {
130 boolean hit = true;
131 double distance = Math.sqrt(dx * dx + dy * dy);
132 double radius2 = 2;
133 if (distance > radius + radius2)
134 {
135 hit = false;
136 }
137 else if (distance > radius + radius2 - 0.1)
138 {
139 continue;
140 }
141 OTSShape other = new OTSShape(makePolygon(cx + dx, cy + dy, radius2, 16));
142 if (hit)
143 {
144 assertTrue("shapes hit", reference.intersects(other));
145 }
146 else
147 {
148 assertFalse("shapes do not hit", reference.intersects(other));
149 }
150 }
151 }
152 reference =
153 new OTSShape(new OTSPoint3D[] { new OTSPoint3D(0, 0, 0), new OTSPoint3D(10, 0, 0), new OTSPoint3D(10, 10, 0) });
154
155 for (int dx = -20; dx <= 20; dx++)
156 {
157 OTSShape other = new OTSShape(
158 new OTSPoint3D[] { new OTSPoint3D(dx, 0, 0), new OTSPoint3D(dx + 5, 0, 0), new OTSPoint3D(dx, -20, 0) });
159 boolean hit = dx >= -5 && dx <= 10;
160 if (hit)
161 {
162 assertTrue("shapes hit", reference.intersects(other));
163 }
164 else
165 {
166 assertFalse("shapes do not hit", reference.intersects(other));
167 }
168 }
169
170 for (int dy = -20; dy <= 20; dy++)
171 {
172 OTSShape other = new OTSShape(
173 new OTSPoint3D[] { new OTSPoint3D(20, dy, 0), new OTSPoint3D(10, dy, 0), new OTSPoint3D(10, dy + 10, 0) });
174 boolean hit = dy >= -10 && dy <= 10;
175 if (hit)
176 {
177 assertTrue("shapes hit", reference.intersects(other));
178 }
179 else
180 {
181 assertFalse("shapes do not hit", reference.intersects(other));
182 }
183 }
184
185 OTSShape vertical = new OTSShape(new OTSPoint3D[] { new OTSPoint3D(-1, -10, 0), new OTSPoint3D(1, -10, 0),
186 new OTSPoint3D(1, 10, 0), new OTSPoint3D(-1, 10, 0), new OTSPoint3D(-1, -10, 0) });
187 OTSShape horizontal = new OTSShape(new OTSPoint3D[] { new OTSPoint3D(-10, -1, 0), new OTSPoint3D(10, -1, 0),
188 new OTSPoint3D(10, 1, 0), new OTSPoint3D(-10, 1, 0), new OTSPoint3D(-10, -1, 0) });
189 assertTrue("shapes hit", vertical.intersects(horizontal));
190 }
191
192
193
194
195
196 @Test
197 public final void testCleanConstructors() throws OTSGeometryException
198 {
199 try
200 {
201 OTSShape.createAndCleanOTSShape(new OTSPoint3D[] {});
202 fail("empty array should have thrown an OTSGeometryException");
203 }
204 catch (OTSGeometryException oge)
205 {
206
207 }
208 try
209 {
210 OTSShape.createAndCleanOTSShape(new OTSPoint3D[] { new OTSPoint3D(1, 2, 3) });
211 fail("array of one point should have thrown an OTSGeometryException");
212 }
213 catch (OTSGeometryException oge)
214 {
215
216 }
217 try
218 {
219 OTSShape.createAndCleanOTSShape(new OTSPoint3D[] { new OTSPoint3D(1, 2, 3), new OTSPoint3D(1, 2, 3) });
220 fail("array of two identical points should have thrown an OTSGeometryException");
221 }
222 catch (OTSGeometryException oge)
223 {
224
225 }
226 try
227 {
228 OTSShape.createAndCleanOTSShape(
229 new OTSPoint3D[] { new OTSPoint3D(1, 2, 3), new OTSPoint3D(1, 2, 3), new OTSPoint3D(1, 2, 3) });
230 fail("array of three identical points should have thrown an OTSGeometryException");
231 }
232 catch (OTSGeometryException oge)
233 {
234
235 }
236
237 OTSShape.createAndCleanOTSShape(new OTSPoint3D[] { new OTSPoint3D(1, 2, 3), new OTSPoint3D(1, 2, 1) });
238 OTSShape.createAndCleanOTSShape(
239 new OTSPoint3D[] { new OTSPoint3D(1, 2, 3), new OTSPoint3D(1, 3, 3), new OTSPoint3D(1, 2, 3) });
240 List<OTSPoint3D> points = new ArrayList<>();
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 points.add(new OTSPoint3D(1, 2, 3));
245 try
246 {
247 OTSShape.createAndCleanOTSShape(points);
248 fail("list of four identical points should have thrown an OTSGeometryException");
249 }
250 catch (OTSGeometryException oge)
251 {
252
253 }
254
255 assertEquals("list now has only one point", 1, points.size());
256 }
257
258
259
260
261
262
263
264
265
266
267 private List<OTSPoint3D> makePolygon(final double centerX, final double centerY, final double radius, final int size)
268 throws OTSGeometryException
269 {
270 List<OTSPoint3D> points = new ArrayList<>(size);
271 for (int i = 0; i < size; i++)
272 {
273 double angle = Math.PI * 2 * i / size;
274 points.add(new OTSPoint3D(centerX + radius * Math.cos(angle), centerY + radius * Math.sin(angle)));
275 }
276 return points;
277 }
278
279
280
281
282
283
284
285
286 private void verifyShape(final OTSShape shape, final boolean verifyZ, final OTSPoint3D... points)
287 throws OTSGeometryException
288 {
289 assertEquals("shape contains correct number of points", shape.size(), points.length);
290 for (int i = 0; i < points.length; i++)
291 {
292 assertEquals("point 1 matches x", points[i].x, shape.get(i).x, 0.0001);
293 assertEquals("point 1 matches y", points[i].y, shape.get(i).y, 0.0001);
294 if (verifyZ)
295 {
296 assertEquals("point 1 matches z", points[i].z, shape.get(i).z, 0.0001);
297 }
298 else
299 {
300 assertEquals("point 1 z is 0", 0, shape.get(i).z, 0.0000001);
301 }
302 }
303 }
304
305 }