1   package org.opentrafficsim.core.geometry;
2   
3   import java.awt.geom.Point2D;
4   import java.io.Serializable;
5   import java.util.ArrayList;
6   import java.util.List;
7   
8   import javax.media.j3d.BoundingSphere;
9   import javax.media.j3d.Bounds;
10  import javax.vecmath.Point3d;
11  
12  import org.djunits.unit.LengthUnit;
13  import org.djunits.value.vdouble.scalar.Direction;
14  import org.djunits.value.vdouble.scalar.Length;
15  import org.locationtech.jts.geom.Coordinate;
16  import org.locationtech.jts.geom.Point;
17  
18  import nl.tudelft.simulation.dsol.animation.Locatable;
19  import nl.tudelft.simulation.language.d3.CartesianPoint;
20  import nl.tudelft.simulation.language.d3.DirectedPoint;
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  public class OTSPoint3D implements Locatable, Serializable
36  {
37      
38      private static final long serialVersionUID = 20150722L;
39  
40      
41      @SuppressWarnings("checkstyle:visibilitymodifier")
42      public final double x;
43  
44      
45      @SuppressWarnings("checkstyle:visibilitymodifier")
46      public final double y;
47  
48      
49      @SuppressWarnings("checkstyle:visibilitymodifier")
50      public final double z;
51  
52      
53  
54  
55  
56  
57  
58      public OTSPoint3D(final double x, final double y, final double z)
59      {
60          this.x = x;
61          this.y = y;
62          this.z = z;
63      }
64  
65      
66  
67  
68      public OTSPoint3D(final double[] xyz)
69      {
70          this(xyz[0], xyz[1], (xyz.length > 2) ? xyz[2] : 0.0);
71      }
72  
73      
74  
75  
76      public OTSPoint3Deometry/OTSPoint3D.html#OTSPoint3D">OTSPoint3D(final OTSPoint3D point)
77      {
78          this(point.x, point.y, point.z);
79      }
80  
81      
82  
83  
84  
85      public OTSPoint3D(final Point3d point)
86      {
87          this(point.x, point.y, point.z);
88      }
89  
90      
91  
92  
93  
94      public OTSPoint3D(final CartesianPoint point)
95      {
96          this(point.x, point.y, point.z);
97      }
98  
99      
100 
101 
102 
103     public OTSPoint3D(final DirectedPoint point)
104     {
105         this(point.x, point.y, point.z);
106     }
107 
108     
109 
110 
111 
112     public OTSPoint3D(final Point2D point2d)
113     {
114         this(point2d.getX(), point2d.getY(), 0.0);
115     }
116 
117     
118 
119 
120 
121     public OTSPoint3D(final Coordinate coordinate)
122     {
123         this(coordinate.x, coordinate.y, Double.isNaN(coordinate.getZ()) ? 0.0 : coordinate.getZ());
124     }
125 
126     
127 
128 
129 
130     public OTSPoint3D(final Point point)
131     {
132         this(point.getX(), point.getY(), 0.0);
133     }
134 
135     
136 
137 
138 
139 
140     public OTSPoint3D(final double x, final double y)
141     {
142         this(x, y, 0.0);
143     }
144 
145     
146 
147 
148 
149 
150 
151 
152     public static OTSPoint3D interpolate(finalOTSPoint3DPoint3D.html#OTSPoint3D">OTSPoint3Ddouble ratio, final OTSPoint3DPoint3D.html#OTSPoint3D">OTSPoint3D zeroValue, final OTSPoint3D oneValue)
153     {
154         double complement = 1 - ratio;
155         return new OTSPoint3D(complement * zeroValue.x + ratio * oneValue.x, complement * zeroValue.y + ratio * oneValue.y,
156                 complement * zeroValue.z + ratio * oneValue.z);
157     }
158 
159     
160 
161 
162 
163 
164 
165 
166 
167 
168 
169     @Deprecated
170     public static OTSPoint3DTSPoint3D.html#OTSPoint3D">OTSPoint3Dt3D">OTSPoint3D intersectionOfLineSegmentsDumb(final OTSPoint3DTSPoint3D.html#OTSPoint3D">OTSPoint3D line1P1, final OTSPoint3D line1P2,
171             final OTSPoint3DTSPoint3D.html#OTSPoint3D">OTSPoint3D line2P1, final OTSPoint3D line2P2)
172     {
173         double denominator =
174                 (line2P2.y - line2P1.y) * (line1P2.x - line1P1.x) - (line2P2.x - line2P1.x) * (line1P2.y - line1P1.y);
175         if (denominator == 0f)
176         {
177             return null; 
178         }
179         double uA = ((line2P2.x - line2P1.x) * (line1P1.y - line2P1.y) - (line2P2.y - line2P1.y) * (line1P1.x - line2P1.x))
180                 / denominator;
181         if ((uA < 0f) || (uA > 1f))
182         {
183             return null; 
184         }
185         double uB = ((line1P2.x - line1P1.x) * (line1P1.y - line2P1.y) - (line1P2.y - line1P1.y) * (line1P1.x - line2P1.x))
186                 / denominator;
187         if (uB < 0 || uB > 1)
188         {
189             return null; 
190         }
191         return new OTSPoint3D(line1P1.x + uA * (line1P2.x - line1P1.x), line1P1.y + uA * (line1P2.y - line1P1.y), 0);
192     }
193 
194     
195 
196 
197 
198 
199 
200 
201 
202 
203     public static OTSPoint3DTSPoint3D.html#OTSPoint3D">OTSPoint3DPoint3D">OTSPoint3D intersectionOfLineSegments(final OTSPoint3DTSPoint3D.html#OTSPoint3D">OTSPoint3D line1P1, final OTSPoint3D line1P2,
204             final OTSPoint3DTSPoint3D.html#OTSPoint3D">OTSPoint3D line2P1, final OTSPoint3D line2P2)
205     {
206         double l1p1x = line1P1.x;
207         double l1p1y = line1P1.y;
208         double l1p2x = line1P2.x - l1p1x;
209         double l1p2y = line1P2.y - l1p1y;
210         double l2p1x = line2P1.x - l1p1x;
211         double l2p1y = line2P1.y - l1p1y;
212         double l2p2x = line2P2.x - l1p1x;
213         double l2p2y = line2P2.y - l1p1y;
214         double denominator = (l2p2y - l2p1y) * l1p2x - (l2p2x - l2p1x) * l1p2y;
215         if (denominator == 0f)
216         {
217             return null; 
218         }
219         double uA = ((l2p2x - l2p1x) * (-l2p1y) - (l2p2y - l2p1y) * (-l2p1x)) / denominator;
220         
221         if ((uA < 0f) || (uA > 1f))
222         {
223             return null; 
224         }
225         double uB = (l1p2y * l2p1x - l1p2x * l2p1y) / denominator;
226         
227         if (uB < 0 || uB > 1)
228         {
229             return null; 
230         }
231         return new OTSPoint3D(line1P1.x + uA * l1p2x, line1P1.y + uA * l1p2y, 0);
232     }
233 
234     
235 
236 
237 
238 
239 
240 
241 
242 
243     @Deprecated
244     public static OTSPoint3DTSPoint3D.html#OTSPoint3D">OTSPoint3DOTSPoint3D">OTSPoint3D intersectionOfLinesDumb(final OTSPoint3DTSPoint3D.html#OTSPoint3D">OTSPoint3D line1P1, final OTSPoint3D line1P2,
245             final OTSPoint3DTSPoint3D.html#OTSPoint3D">OTSPoint3D line2P1, final OTSPoint3D line2P2)
246     {
247         double determinant =
248                 (line1P1.x - line1P2.x) * (line2P1.y - line2P2.y) - (line1P1.y - line1P2.y) * (line2P1.x - line2P2.x);
249         if (Math.abs(determinant) < 0.0000001)
250         {
251             return null;
252         }
253         return new OTSPoint3D(
254                 ((line1P1.x * line1P2.y - line1P1.y * line1P2.x) * (line2P1.x - line2P2.x)
255                         - (line1P1.x - line1P2.x) * (line2P1.x * line2P2.y - line2P1.y * line2P2.x)) / determinant,
256                 ((line1P1.x * line1P2.y - line1P1.y * line1P2.x) * (line2P1.y - line2P2.y)
257                         - (line1P1.y - line1P2.y) * (line2P1.x * line2P2.y - line2P1.y * line2P2.x)) / determinant);
258     }
259 
260     
261 
262 
263 
264 
265 
266 
267 
268 
269     public static OTSPoint3DTSPoint3D.html#OTSPoint3D">OTSPoint3DTSPoint3D.html#OTSPoint3D">OTSPoint3Dtml#OTSPoint3D">OTSPoint3D intersectionOfLines(final OTSPoint3DTSPoint3D.html#OTSPoint3D">OTSPoint3DTSPoint3D.html#OTSPoint3D">OTSPoint3D line1P1, final OTSPoint3DTSPoint3D.html#OTSPoint3D">OTSPoint3D line1P2, final OTSPoint3D line2P1,
270             final OTSPoint3D line2P2)
271     {
272         double l1p1x = line1P1.x;
273         double l1p1y = line1P1.y;
274         double l1p2x = line1P2.x - l1p1x;
275         double l1p2y = line1P2.y - l1p1y;
276         double l2p1x = line2P1.x - l1p1x;
277         double l2p1y = line2P1.y - l1p1y;
278         double l2p2x = line2P2.x - l1p1x;
279         double l2p2y = line2P2.y - l1p1y;
280         double determinant = (0 - l1p2x) * (l2p1y - l2p2y) - (0 - l1p2y) * (l2p1x - l2p2x);
281         if (Math.abs(determinant) < 0.0000001)
282         {
283             return null;
284         }
285         return new OTSPoint3D(l1p1x + (l1p2x * (l2p1x * l2p2y - l2p1y * l2p2x)) / determinant,
286                 l1p1y + (l1p2y * (l2p1x * l2p2y - l2p1y * l2p2x)) / determinant);
287     }
288 
289     
290 
291 
292 
293 
294 
295 
296 
297 
298 
299 
300     public final OTSPoint3Dt3D.html#OTSPoint3D">OTSPoint3Dl#OTSPoint3D">OTSPoint3D closestPointOnSegment(final OTSPoint3Dt3D.html#OTSPoint3D">OTSPoint3D segmentPoint1, final OTSPoint3D segmentPoint2)
301     {
302         double dX = segmentPoint2.x - segmentPoint1.x;
303         double dY = segmentPoint2.y - segmentPoint1.y;
304         if ((0 == dX) && (0 == dY))
305         {
306             return segmentPoint1;
307         }
308         final double u = ((this.x - segmentPoint1.x) * dX + (this.y - segmentPoint1.y) * dY) / (dX * dX + dY * dY);
309         if (u < 0)
310         {
311             return segmentPoint1;
312         }
313         else if (u > 1)
314         {
315             return segmentPoint2;
316         }
317         else
318         {
319             return interpolate(u, segmentPoint1, segmentPoint2);
320         }
321     }
322 
323     
324 
325 
326 
327 
328 
329 
330     private OTSPoint3D internalClosestPointOnLine(final OTSLine3D line, final boolean useHorizontalDistance)
331     {
332         OTSPoint3D prevPoint = null;
333         double distance = Double.MAX_VALUE;
334         OTSPoint3D result = null;
335         for (OTSPoint3D nextPoint : line.getPoints())
336         {
337             if (null != prevPoint)
338             {
339                 OTSPoint3D closest = closestPointOnSegment(prevPoint, nextPoint);
340                 double thisDistance = useHorizontalDistance ? horizontalDistanceSI(closest) : distanceSI(closest);
341                 if (thisDistance < distance)
342                 {
343                     result = closest;
344                     distance = thisDistance;
345                 }
346             }
347             prevPoint = nextPoint;
348         }
349         return result;
350     }
351 
352     
353 
354 
355 
356 
357     public final OTSPoint3D closestPointOnLine(final OTSLine3D line)
358     {
359         return internalClosestPointOnLine(line, false);
360     }
361 
362     
363 
364 
365 
366 
367 
368     public final OTSPoint3D closestPointOnLine2D(final OTSLine3D line)
369     {
370         return internalClosestPointOnLine(line, true);
371     }
372 
373     
374 
375 
376 
377     public final OTSPoint3D normalize()
378     {
379         double length = Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z);
380         return this.translate(length);
381     }
382 
383     
384 
385 
386 
387 
388     public final OTSPoint3D translate(final double factor)
389     {
390         return new OTSPoint3D(this.x / factor, this.y / factor, this.z / factor);
391     }
392 
393     
394 
395 
396 
397 
398 
399 
400 
401 
402     public static final List<OTSPoint3D> circleCenter(final OTSPoint3DOTSPoint3D.html#OTSPoint3D">OTSPoint3D point1, final OTSPoint3D point2, final double radius)
403     {
404         List<OTSPoint3D> result = new ArrayList<>();
405         OTSPoint3D m = interpolate(0.5, point1, point2);
406         double h = point1.distanceSI(m);
407         if (radius < h) 
408         {
409             return result;
410         }
411         if (radius == h) 
412         {
413             result.add(m);
414             return result;
415         }
416         OTSPoint3Dmetry/OTSPoint3D.html#OTSPoint3D">OTSPoint3D p = new OTSPoint3D(point2.y - point1.y, point1.x - point2.x).normalize();
417         double d = Math.sqrt(radius * radius - h * h); 
418         d = Math.sqrt(radius * radius - h * h);
419         result.add(new OTSPoint3D(m.x + d * p.x, m.y + d * p.y, m.z));
420         result.add(new OTSPoint3D(m.x - d * p.x, m.y - d * p.y, m.z));
421         return result;
422     }
423 
424     
425 
426 
427 
428 
429 
430 
431 
432     public static final List<OTSPoint3D> circleIntersections(final OTSPoint3D center1, final double radius1,
433             final OTSPoint3D center2, final double radius2)
434     {
435         List<OTSPoint3D> center = new ArrayList<>();
436         OTSPoint3D m = interpolate(radius1 / (radius1 + radius2), center1, center2);
437         double h = center1.distanceSI(m);
438         if (radius1 < h) 
439         {
440             return center;
441         }
442         if (radius1 == h) 
443         {
444             center.add(m);
445             return center;
446         }
447         OTSPoint3Dmetry/OTSPoint3D.html#OTSPoint3D">OTSPoint3D p = new OTSPoint3D(center2.y - center1.y, center1.x - center2.x).normalize();
448         double d = Math.sqrt(radius1 * radius1 - h * h); 
449         center.add(new OTSPoint3D(m.x + d * p.x, m.y + d * p.y, m.z));
450         center.add(new OTSPoint3D(m.x - d * p.x, m.y - d * p.y, m.z));
451         return center;
452     }
453 
454     
455 
456 
457 
458     public final double distanceSI(final OTSPoint3D point)
459     {
460         double dx = point.x - this.x;
461         double dy = point.y - this.y;
462         double dz = point.z - this.z;
463 
464         return Math.sqrt(dx * dx + dy * dy + dz * dz);
465     }
466 
467     
468 
469 
470 
471     public final double horizontalDistanceSI(final OTSPoint3D point)
472     {
473         double dx = point.x - this.x;
474         double dy = point.y - this.y;
475 
476         return Math.sqrt(dx * dx + dy * dy);
477     }
478 
479     
480 
481 
482 
483     public final Length horizontalDistance(final OTSPoint3D point)
484     {
485         return new Length(horizontalDistanceSI(point), LengthUnit.SI);
486     }
487 
488     
489 
490 
491 
492 
493     public final Length distance(final OTSPoint3D point)
494     {
495         return new Length(distanceSI(point), LengthUnit.SI);
496     }
497 
498     
499 
500 
501 
502 
503     public final double horizontalDirectionSI(final OTSPoint3D point)
504     {
505         return Math.atan2(point.y - this.y, point.x - this.x);
506     }
507 
508     
509 
510 
511 
512 
513     public final Direction horizontalDirection(final OTSPoint3D point)
514     {
515         return Direction.instantiateSI(Math.atan2(point.y - this.y, point.x - this.x));
516     }
517 
518     
519 
520 
521     public final Coordinate getCoordinate()
522     {
523         return new Coordinate(this.x, this.y, this.z);
524     }
525 
526     
527 
528 
529     public final DirectedPoint getDirectedPoint()
530     {
531         return new DirectedPoint(this.x, this.y, this.z);
532     }
533 
534     
535 
536 
537     public final Point2D getPoint2D()
538     {
539         return new Point2D.Double(this.x, this.y);
540     }
541 
542     
543     @Override
544     public final DirectedPoint getLocation()
545     {
546         return getDirectedPoint();
547     }
548 
549     
550 
551 
552     @Override
553     public final Bounds getBounds()
554     {
555         return new BoundingSphere(new Point3d(0.0, 0.0, 0.0), 0.5);
556     }
557 
558     
559     @Override
560     @SuppressWarnings("checkstyle:designforextension")
561     public String toString()
562     {
563         return String.format("(%.3f,%.3f,%.3f)", this.x, this.y, this.z);
564     }
565 
566     
567     @Override
568     @SuppressWarnings("checkstyle:designforextension")
569     public int hashCode()
570     {
571         final int prime = 31;
572         int result = 1;
573         long temp;
574         temp = Double.doubleToLongBits(this.x);
575         result = prime * result + (int) (temp ^ (temp >>> 32));
576         temp = Double.doubleToLongBits(this.y);
577         result = prime * result + (int) (temp ^ (temp >>> 32));
578         temp = Double.doubleToLongBits(this.z);
579         result = prime * result + (int) (temp ^ (temp >>> 32));
580         return result;
581     }
582 
583     
584     @Override
585     @SuppressWarnings({ "checkstyle:designforextension", "checkstyle:needbraces" })
586     public boolean equals(final Object obj)
587     {
588         if (this == obj)
589             return true;
590         if (obj == null)
591             return false;
592         if (getClass() != obj.getClass())
593             return false;
594         OTSPoint3D../../../org/opentrafficsim/core/geometry/OTSPoint3D.html#OTSPoint3D">OTSPoint3D other = (OTSPoint3D) obj;
595         if (Double.doubleToLongBits(this.x) != Double.doubleToLongBits(other.x))
596             return false;
597         if (Double.doubleToLongBits(this.y) != Double.doubleToLongBits(other.y))
598             return false;
599         if (Double.doubleToLongBits(this.z) != Double.doubleToLongBits(other.z))
600             return false;
601         return true;
602     }
603 
604 }