1 package org.opentrafficsim.core.geometry;
2
3 import java.awt.geom.Line2D;
4 import java.awt.geom.Path2D;
5 import java.awt.geom.Point2D;
6 import java.awt.geom.Rectangle2D;
7 import java.util.ArrayList;
8 import java.util.Arrays;
9 import java.util.List;
10
11 import org.locationtech.jts.geom.Coordinate;
12 import org.locationtech.jts.geom.Geometry;
13 import org.locationtech.jts.geom.LineString;
14
15
16
17
18
19
20
21
22
23 public class OtsShape extends OtsLine3d
24 {
25
26 private static final long serialVersionUID = 20160331;
27
28
29 private Path2D shape = null;
30
31
32
33
34
35
36
37 public OtsShape(final OtsPoint3d... points) throws OtsGeometryException
38 {
39 super(points);
40 }
41
42
43
44
45
46
47
48 public OtsShape(final Coordinate[] coordinates) throws OtsGeometryException
49 {
50 super(coordinates);
51 }
52
53
54
55
56
57
58
59 public OtsShape(final LineString lineString) throws OtsGeometryException
60 {
61 super(lineString);
62 }
63
64
65
66
67
68
69
70 public OtsShape(final Geometry geometry) throws OtsGeometryException
71 {
72 super(geometry);
73 }
74
75
76
77
78
79
80
81 public OtsShape(final List<OtsPoint3d> pointList) throws OtsGeometryException
82 {
83 super(pointList);
84 }
85
86
87
88
89
90
91
92 public OtsShape(final Path2D path) throws OtsGeometryException
93 {
94 super(path);
95 }
96
97
98
99
100 public final synchronized Path2D getShape()
101 {
102 if (this.shape == null)
103 {
104 calculateShape();
105 }
106 return this.shape;
107 }
108
109
110
111
112 private synchronized void calculateShape()
113 {
114 this.shape = new Path2D.Double();
115 this.shape.moveTo(getPoints()[0].x, getPoints()[0].y);
116 for (int i = 1; i < getPoints().length; i++)
117 {
118 this.shape.lineTo(getPoints()[i].x, getPoints()[i].y);
119 }
120 this.shape.closePath();
121 }
122
123
124
125
126
127 public final synchronized boolean contains(final OtsPoint3d point)
128 {
129 return getShape().contains(point.x, point.y);
130 }
131
132
133
134
135
136
137
138
139 public final synchronized boolean contains(final Rectangle2D rectangle)
140 {
141 return getShape().contains(rectangle);
142 }
143
144
145
146
147
148 public final synchronized boolean intersects(final OtsShape otsShape)
149 {
150
151 if (!getEnvelope().project().intersects(otsShape.getEnvelope().project()))
152 {
153 return false;
154 }
155
156
157 for (OtsPoint3d p : getPoints())
158 {
159 if (otsShape.contains(p))
160 {
161 return true;
162 }
163 }
164
165
166 for (OtsPoint3d p : otsShape.getPoints())
167 {
168 if (contains(p))
169 {
170 return true;
171 }
172 }
173
174
175 Point2D prevPoint = getPoints()[this.size() - 1].getPoint2D();
176
177
178 for (OtsPoint3d point : this.getPoints())
179 {
180 Point2D nextPoint = point.getPoint2D();
181 Line2D.Double line1 = new Line2D.Double(prevPoint, nextPoint);
182
183
184
185 Point2D otherPrevPoint = otsShape.getPoints()[otsShape.size() - 1].getPoint2D();
186 for (OtsPoint3d otherPoint : otsShape.getPoints())
187 {
188 Point2D otherNextPoint = otherPoint.getPoint2D();
189
190
191 Line2D.Double line2 = new Line2D.Double(otherPrevPoint, otherNextPoint);
192 if (line1.intersectsLine(line2))
193 {
194 double p1x = line1.getX1(), p1y = line1.getY1(), d1x = line1.getX2() - p1x, d1y = line1.getY2() - p1y;
195 double p2x = line2.getX1(), p2y = line2.getY1(), d2x = line2.getX2() - p2x, d2y = line2.getY2() - p2y;
196
197 double det = d2x * d1y - d2y * d1x;
198 if (det == 0)
199 {
200
201
202
203
204
205
206 Point2D p1s = line1.getP1(), p1e = line1.getP2(), p2s = line2.getP1(), p2e = line2.getP2();
207 if ((p1s.equals(p2s) && p1e.equals(p2e)) || (p1s.equals(p2e) && p1e.equals(p2s)))
208 {
209 return true;
210 }
211 if (p1s.equals(p2s) && line1.ptLineDist(p2e) > 0 && line2.ptLineDist(p1e) > 0)
212 {
213 return true;
214 }
215 if (p1e.equals(p2e) && line1.ptLineDist(p2s) > 0 && line2.ptLineDist(p1s) > 0)
216 {
217 return true;
218 }
219 if (p1s.equals(p2e) && line1.ptLineDist(p2s) > 0 && line2.ptLineDist(p1e) > 0)
220 {
221 return true;
222 }
223 if (p1e.equals(p2s) && line1.ptLineDist(p2e) > 0 && line2.ptLineDist(p1s) > 0)
224 {
225 return true;
226 }
227 }
228 else
229 {
230 double z = (d2x * (p2y - p1y) + d2y * (p1x - p2x)) / det;
231 if (Math.abs(z) < 10.0 * Math.ulp(1.0) || Math.abs(z - 1.0) > 10.0 * Math.ulp(1.0))
232 {
233 return true;
234 }
235 }
236
237 }
238 otherPrevPoint = otherNextPoint;
239 }
240 prevPoint = nextPoint;
241 }
242 return false;
243 }
244
245
246
247
248
249
250
251 public static OtsShape createAndCleanOtsShape(final OtsPoint3d[] points) throws OtsGeometryException
252 {
253 if (points.length < 2)
254 {
255 throw new OtsGeometryException(
256 "Degenerate OtsLine3d; has " + points.length + " point" + (points.length != 1 ? "s" : ""));
257 }
258 return createAndCleanOtsShape(new ArrayList<>(Arrays.asList(points)));
259 }
260
261
262
263
264
265
266
267
268 public static OtsShape createAndCleanOtsShape(final List<OtsPoint3d> pointList) throws OtsGeometryException
269 {
270
271 int i = 1;
272 while (i < pointList.size())
273 {
274 if (pointList.get(i - 1).equals(pointList.get(i)))
275 {
276 pointList.remove(i);
277 }
278 else
279 {
280 i++;
281 }
282 }
283 return new OtsShape(pointList);
284 }
285
286
287
288
289
290
291 public static void main(final String[] args) throws OtsGeometryException
292 {
293 OtsShape s1 = new OtsShape(new OtsPoint3d(0, 0), new OtsPoint3d(10, 0), new OtsPoint3d(10, 10), new OtsPoint3d(0, 10));
294 OtsShape s2 = new OtsShape(new OtsPoint3d(5, 5), new OtsPoint3d(15, 5), new OtsPoint3d(15, 15), new OtsPoint3d(5, 15));
295 System.out.println("s1.intersect(s2): " + s1.intersects(s2));
296 System.out.println("s1.intersect(s1): " + s1.intersects(s1));
297 OtsShape s3 =
298 new OtsShape(new OtsPoint3d(25, 25), new OtsPoint3d(35, 25), new OtsPoint3d(35, 35), new OtsPoint3d(25, 35));
299 System.out.println("s1.intersect(s3): " + s1.intersects(s3));
300 }
301
302
303 @Override
304 public final String toString()
305 {
306 return "OtsShape [shape=" + super.toString() + "]";
307 }
308 }