1 package org.opentrafficsim.core.geometry;
2
3 import java.awt.geom.Point2D;
4 import java.io.Serializable;
5
6 import javax.media.j3d.BoundingSphere;
7 import javax.media.j3d.Bounds;
8 import javax.vecmath.Point3d;
9
10 import org.djunits.unit.LengthUnit;
11 import org.djunits.value.vdouble.scalar.Length;
12
13 import com.vividsolutions.jts.geom.Coordinate;
14 import com.vividsolutions.jts.geom.Point;
15
16 import nl.tudelft.simulation.dsol.animation.Locatable;
17 import nl.tudelft.simulation.language.d3.CartesianPoint;
18 import nl.tudelft.simulation.language.d3.DirectedPoint;
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33 public class OTSPoint3D implements Locatable, Serializable
34 {
35
36 private static final long serialVersionUID = 20150722L;
37
38
39 @SuppressWarnings("checkstyle:visibilitymodifier")
40 public final double x;
41
42
43 @SuppressWarnings("checkstyle:visibilitymodifier")
44 public final double y;
45
46
47 @SuppressWarnings("checkstyle:visibilitymodifier")
48 public final double z;
49
50
51
52
53
54
55
56 public OTSPoint3D(final double x, final double y, final double z)
57 {
58 this.x = x;
59 this.y = y;
60 this.z = z;
61 }
62
63
64
65
66 public OTSPoint3D(final double[] xyz)
67 {
68 this(xyz[0], xyz[1], (xyz.length > 2) ? xyz[2] : 0.0);
69 }
70
71
72
73
74 public OTSPoint3D(final OTSPoint3D point)
75 {
76 this(point.x, point.y, point.z);
77 }
78
79
80
81
82
83 public OTSPoint3D(final Point3d point)
84 {
85 this(point.x, point.y, point.z);
86 }
87
88
89
90
91
92 public OTSPoint3D(final CartesianPoint point)
93 {
94 this(point.x, point.y, point.z);
95 }
96
97
98
99
100
101 public OTSPoint3D(final DirectedPoint point)
102 {
103 this(point.x, point.y, point.z);
104 }
105
106
107
108
109
110 public OTSPoint3D(final Point2D point2d)
111 {
112 this(point2d.getX(), point2d.getY(), 0.0);
113 }
114
115
116
117
118
119 public OTSPoint3D(final Coordinate coordinate)
120 {
121 this(coordinate.x, coordinate.y, Double.isNaN(coordinate.z) ? 0.0 : coordinate.z);
122 }
123
124
125
126
127
128 public OTSPoint3D(final Point point)
129 {
130 this(point.getX(), point.getY(), 0.0);
131 }
132
133
134
135
136
137
138 public OTSPoint3D(final double x, final double y)
139 {
140 this(x, y, 0.0);
141 }
142
143
144
145
146
147
148
149
150 public static OTSPoint3D interpolate(final double ratio, final OTSPoint3D zeroValue, final OTSPoint3D oneValue)
151 {
152 double complement = 1 - ratio;
153 return new OTSPoint3D(complement * zeroValue.x + ratio * oneValue.x, complement * zeroValue.y + ratio * oneValue.y,
154 complement * zeroValue.z + ratio * oneValue.z);
155 }
156
157
158
159
160
161
162
163
164
165
166 public static OTSPoint3D intersectionOfLineSegments(final OTSPoint3D line1P1, final OTSPoint3D line1P2,
167 final OTSPoint3D line2P1, final OTSPoint3D line2P2)
168 {
169 double denominator =
170 (line2P2.y - line2P1.y) * (line1P2.x - line1P1.x) - (line2P2.x - line2P1.x) * (line1P2.y - line1P1.y);
171 if (denominator == 0f)
172 {
173 return null;
174 }
175 double uA =
176 ((line2P2.x - line2P1.x) * (line1P1.y - line2P1.y) - (line2P2.y - line2P1.y) * (line1P1.x - line2P1.x))
177 / denominator;
178 if ((uA < 0f) || (uA > 1f))
179 {
180 return null;
181 }
182 double uB =
183 ((line1P2.x - line1P1.x) * (line1P1.y - line2P1.y) - (line1P2.y - line1P1.y) * (line1P1.x - line2P1.x))
184 / denominator;
185 if (uB < 0 || uB > 1)
186 {
187 return null;
188 }
189 return new OTSPoint3D(line1P1.x + uA * (line1P2.x - line1P1.x), line1P1.y + uA * (line1P2.y - line1P1.y), 0);
190 }
191
192
193
194
195
196
197
198
199
200
201 public static OTSPoint3D intersectionOfLines(final OTSPoint3D line1P1, final OTSPoint3D line1P2, final OTSPoint3D line2P1,
202 final OTSPoint3D line2P2)
203 {
204 double determinant =
205 (line1P1.x - line1P2.x) * (line2P1.y - line2P2.y) - (line1P1.y - line1P2.y) * (line2P1.x - line2P2.x);
206 if (Math.abs(determinant) < 0.0000001)
207 {
208 return null;
209 }
210 return new OTSPoint3D(
211 ((line1P1.x * line1P2.y - line1P1.y * line1P2.x) * (line2P1.x - line2P2.x) - (line1P1.x - line1P2.x)
212 * (line2P1.x * line2P2.y - line2P1.y * line2P2.x))
213 / determinant,
214 ((line1P1.x * line1P2.y - line1P1.y * line1P2.x) * (line2P1.y - line2P2.y) - (line1P1.y - line1P2.y)
215 * (line2P1.x * line2P2.y - line2P1.y * line2P2.x))
216 / determinant);
217 }
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245 public final OTSPoint3D closestPointOnSegment(final OTSPoint3D segmentPoint1, final OTSPoint3D segmentPoint2)
246 {
247 double dX = segmentPoint2.x - segmentPoint1.x;
248 double dY = segmentPoint2.y - segmentPoint1.y;
249 if ((0 == dX) && (0 == dY))
250 {
251 return segmentPoint1;
252 }
253 final double u = ((this.x - segmentPoint1.x) * dX + (this.y - segmentPoint1.y) * dY) / (dX * dX + dY * dY);
254 if (u < 0)
255 {
256 return segmentPoint1;
257 }
258 else if (u > 1)
259 {
260 return segmentPoint2;
261 }
262 else
263 {
264 return interpolate(u, segmentPoint1, segmentPoint2);
265
266 }
267 }
268
269
270
271
272
273
274
275
276 private OTSPoint3D internalClosestPointOnLine(final OTSLine3D line, final boolean useHorizontalDistance)
277 {
278 OTSPoint3D prevPoint = null;
279 double distance = Double.MAX_VALUE;
280 OTSPoint3D result = null;
281 for (OTSPoint3D nextPoint : line.getPoints())
282 {
283 if (null != prevPoint)
284 {
285 OTSPoint3D closest = closestPointOnSegment(prevPoint, nextPoint);
286 double thisDistance = useHorizontalDistance ? horizontalDistanceSI(closest) : distanceSI(closest);
287 if (thisDistance < distance)
288 {
289 result = closest;
290 distance = thisDistance;
291 }
292 }
293 prevPoint = nextPoint;
294 }
295 return result;
296 }
297
298
299
300
301
302
303 public final OTSPoint3D closestPointOnLine(final OTSLine3D line)
304 {
305 return internalClosestPointOnLine(line, false);
306 }
307
308
309
310
311
312
313
314 public final OTSPoint3D closestPointOnLine2D(final OTSLine3D line)
315 {
316 return internalClosestPointOnLine(line, true);
317 }
318
319
320
321
322
323 public final double distanceSI(final OTSPoint3D point)
324 {
325 double dx = point.x - this.x;
326 double dy = point.y - this.y;
327 double dz = point.z - this.z;
328
329 return Math.sqrt(dx * dx + dy * dy + dz * dz);
330 }
331
332
333
334
335
336 public final double horizontalDistanceSI(final OTSPoint3D point)
337 {
338 double dx = point.x - this.x;
339 double dy = point.y - this.y;
340
341 return Math.sqrt(dx * dx + dy * dy);
342 }
343
344
345
346
347
348 public final Length horizontalDistance(final OTSPoint3D point)
349 {
350 return new Length(horizontalDistanceSI(point), LengthUnit.SI);
351 }
352
353
354
355
356
357 public final Length distance(final OTSPoint3D point)
358 {
359 return new Length(distanceSI(point), LengthUnit.SI);
360 }
361
362
363
364
365 public final Coordinate getCoordinate()
366 {
367 return new Coordinate(this.x, this.y, this.z);
368 }
369
370
371
372
373 public final DirectedPoint getDirectedPoint()
374 {
375 return new DirectedPoint(this.x, this.y, this.z);
376 }
377
378
379
380
381 public final Point2D getPoint2D()
382 {
383 return new Point2D.Double(this.x, this.y);
384 }
385
386
387 @Override
388 public final DirectedPoint getLocation()
389 {
390 return getDirectedPoint();
391 }
392
393
394
395
396 @Override
397 public final Bounds getBounds()
398 {
399 return new BoundingSphere(new Point3d(0.0, 0.0, 0.0), 0.5);
400 }
401
402
403 @Override
404 @SuppressWarnings("checkstyle:designforextension")
405 public String toString()
406 {
407 return String.format("(%.3f,%.3f,%.3f)", this.x, this.y, this.z);
408 }
409
410
411 @Override
412 @SuppressWarnings("checkstyle:designforextension")
413 public int hashCode()
414 {
415 final int prime = 31;
416 int result = 1;
417 long temp;
418 temp = Double.doubleToLongBits(this.x);
419 result = prime * result + (int) (temp ^ (temp >>> 32));
420 temp = Double.doubleToLongBits(this.y);
421 result = prime * result + (int) (temp ^ (temp >>> 32));
422 temp = Double.doubleToLongBits(this.z);
423 result = prime * result + (int) (temp ^ (temp >>> 32));
424 return result;
425 }
426
427
428 @Override
429 @SuppressWarnings({ "checkstyle:designforextension", "checkstyle:needbraces" })
430 public boolean equals(final Object obj)
431 {
432 if (this == obj)
433 return true;
434 if (obj == null)
435 return false;
436 if (getClass() != obj.getClass())
437 return false;
438 OTSPoint3D other = (OTSPoint3D) obj;
439 if (Double.doubleToLongBits(this.x) != Double.doubleToLongBits(other.x))
440 return false;
441 if (Double.doubleToLongBits(this.y) != Double.doubleToLongBits(other.y))
442 return false;
443 if (Double.doubleToLongBits(this.z) != Double.doubleToLongBits(other.z))
444 return false;
445 return true;
446 }
447
448 }