1 package org.lcsim.detector.solids;
2
3 import hep.physics.matrix.BasicMatrix;
4 import hep.physics.vec.Hep3Vector;
5 import hep.physics.vec.VecOp;
6
7 import java.util.List;
8
9
10
11
12
13 public class GeomOp3D
14 {
15
16 public static final double DISTANCE_TOLERANCE = 1E-9;
17 public static final double ANGULAR_TOLERANCE = 1E-9;
18
19
20
21
22 public GeomOp3D()
23 {
24 }
25
26
27
28 public static boolean equals(Point3D point1, Point3D point2)
29 {
30 return intersects(point1, point2);
31 }
32
33 public static boolean equals(Plane3D plane1, Plane3D plane2)
34 {
35
36
37
38
39 return ( parallel(plane1,plane2) &&
40 VecOp.dot(plane1.getNormal(),plane2.getNormal()) > 0 &&
41 Math.abs(plane1.getDistance() - plane2.getDistance()) < DISTANCE_TOLERANCE);
42 }
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57 public static boolean intersects(Point3D point1, Point3D point2)
58 {
59 return (distanceBetween(point1,point2) < DISTANCE_TOLERANCE);
60 }
61
62
63
64
65
66
67
68
69 public static boolean intersects(Point3D point, Line3D line)
70 {
71 return (distanceBetween(point,line) < DISTANCE_TOLERANCE );
72 }
73
74
75
76
77
78
79
80
81 public static boolean intersects(Point3D point, LineSegment3D linesegment)
82 {
83 if ( intersects(point,linesegment.getLine()) )
84 {
85 double length_at_point = VecOp.dot( VecOp.sub(point,linesegment.getStartPoint()), linesegment.getDirection() );
86 return ( (length_at_point + DISTANCE_TOLERANCE) > 0 && (length_at_point - DISTANCE_TOLERANCE < linesegment.getLength()) );
87 }
88 else
89 {
90 return false;
91 }
92 }
93
94
95
96
97
98
99
100
101 public static boolean intersects(Point3D point, Plane3D plane)
102 {
103 return ( Math.abs(distanceBetween(point,plane)) < DISTANCE_TOLERANCE);
104 }
105
106
107
108
109
110
111
112
113
114 public static boolean intersects(Point3D point, Polygon3D polygon)
115 {
116 List<Point3D> vertices = polygon.getClosedVertices();
117
118 double angle_sum = 0.0;
119 for (int ivertex = 0; ivertex < vertices.size()-1; ivertex++)
120 {
121 Hep3Vector v1_vec = VecOp.sub(vertices.get(ivertex),point);
122 Hep3Vector v2_vec = VecOp.sub(vertices.get(ivertex+1),point);
123
124 double v1_mag = v1_vec.magnitude();
125 double v2_mag = v2_vec.magnitude();
126
127 if (v1_mag < DISTANCE_TOLERANCE || v2_mag < DISTANCE_TOLERANCE)
128 {
129 return true;
130 }
131 else
132 {
133 angle_sum += Math.acos(VecOp.dot(v1_vec,v2_vec)/(v1_mag*v2_mag));
134 }
135 }
136
137 if ( Math.abs(angle_sum - 2*Math.PI) < polygon.nSides()*ANGULAR_TOLERANCE && intersects(point,polygon.getPlane()))
138 {
139 return true;
140 }
141 else
142 {
143 return false;
144 }
145 }
146
147
148
149
150
151
152
153
154
155
156
157 public static boolean intersects(Line3D line1, Line3D line2)
158 {
159 return (distanceBetween(line1, line2) < DISTANCE_TOLERANCE);
160 }
161
162
163
164
165
166
167
168
169 public static boolean intersects(Line3D line, LineSegment3D linesegment)
170 {
171 return (distanceBetween(line, linesegment) < DISTANCE_TOLERANCE);
172 }
173
174
175
176
177
178
179
180
181 public static boolean intersects(Line3D line, Plane3D plane)
182 {
183 return ( Math.abs(distanceBetween(line, plane)) < DISTANCE_TOLERANCE);
184 }
185
186
187
188
189
190
191
192
193 public static boolean intersects(Line3D line, Polygon3D polygon)
194 {
195 if (parallel(line,polygon.getPlane()))
196 {
197 if (intersects(line,polygon.getPlane()))
198 {
199 for (LineSegment3D edge : polygon.getEdges())
200 {
201 if (intersects(line,edge)) return true;
202 }
203 return false;
204 }
205 else
206 {
207 return false;
208 }
209 }
210 else
211 {
212 Point3D plane_intersection = intersection(line,polygon.getPlane());
213 return intersects(plane_intersection,polygon);
214 }
215 }
216
217
218
219
220
221
222
223
224
225
226
227
228 public static boolean intersects(LineSegment3D linesegment1, LineSegment3D linesegment2)
229 {
230 return (distanceBetween(linesegment1, linesegment2) < DISTANCE_TOLERANCE);
231 }
232
233
234
235
236
237
238
239
240 public static boolean intersects(LineSegment3D linesegment, Plane3D plane)
241 {
242 double start_distance = distanceBetween(linesegment.getStartPoint(),plane);
243 double end_distance = distanceBetween(linesegment.getEndPoint(),plane);
244 if (Math.abs(start_distance) < DISTANCE_TOLERANCE || Math.abs(end_distance) < DISTANCE_TOLERANCE)
245 {
246 return true;
247 }
248 else if (start_distance * end_distance < 0)
249 {
250 return true;
251 }
252 else
253 {
254 return false;
255 }
256 }
257
258
259
260
261
262
263
264
265 public static boolean intersects(LineSegment3D linesegment, Polygon3D polygon)
266 {
267 Line3D line = linesegment.getLine();
268 Plane3D plane = polygon.getPlane();
269
270 if (parallel(line,plane))
271 {
272 if (intersects(line,plane))
273 {
274 for (LineSegment3D edge : polygon.getEdges())
275 {
276 if (intersects(linesegment,edge)) return true;
277 }
278 return (intersects(linesegment.getStartPoint(),polygon) || intersects(linesegment.getEndPoint(),polygon));
279 }
280 else
281 {
282 return false;
283 }
284 }
285 else
286 {
287 Point3D line_plane_intersection = intersection(line,plane);
288 return (intersects(line_plane_intersection,polygon) && intersects(linesegment,plane));
289 }
290 }
291
292
293
294
295
296
297
298
299
300
301
302 public static boolean intersects(Plane3D plane1, Plane3D plane2)
303 {
304 return (Math.abs(distanceBetween(plane1,plane2)) < DISTANCE_TOLERANCE);
305 }
306
307
308
309
310
311
312
313
314 public static boolean intersects(Plane3D plane, Polygon3D polygon)
315 {
316 boolean pos = false;
317 boolean neg = false;
318 for (Point3D vertex : polygon.getVertices())
319 {
320 if ( VecOp.dot(vertex,polygon.getNormal()) - plane.getDistance() + DISTANCE_TOLERANCE > 0 ) pos = true;
321 if ( VecOp.dot(vertex,polygon.getNormal()) - plane.getDistance() - DISTANCE_TOLERANCE < 0 ) neg = true;
322 if (pos && neg) return true;
323 }
324 return false;
325 }
326
327
328
329
330
331
332
333
334
335
336
337 public static boolean intersects(Polygon3D polygon1, Polygon3D polygon2)
338 {
339 for (LineSegment3D edge : polygon1.getEdges())
340 {
341 if (intersects(edge,polygon2)) return true;
342 }
343 return false;
344 }
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359 public static double distanceBetween(Point3D point1, Point3D point2)
360 {
361 return VecOp.sub(point2,point1).magnitude();
362 }
363
364
365
366
367
368
369
370
371 public static double distanceBetween(Point3D point, Line3D line)
372 {
373 return VecOp.cross(line.getDirection(),VecOp.sub(point,line.getStartPoint())).magnitude();
374 }
375
376
377
378
379
380
381
382
383 public static double distanceBetween(Point3D point, LineSegment3D linesegment)
384 {
385 Hep3Vector diff = VecOp.sub(point,linesegment.getStartPoint());
386 double dot = VecOp.dot(diff,linesegment.getDirection());
387 if (dot <= 0) return distanceBetween(point,linesegment.getStartPoint());
388 else if (dot >= linesegment.getLength()) return distanceBetween(point,linesegment.getEndPoint());
389 else return distanceBetween(point,linesegment.getLine());
390 }
391
392
393
394
395
396
397
398
399 public static double distanceBetween(Point3D point, Plane3D plane)
400 {
401 return VecOp.dot(point,plane.getNormal())-plane.getDistance();
402 }
403
404
405
406
407
408
409
410
411 public static double distanceBetween(Point3D point, Polygon3D polygon)
412 {
413 double distance = Double.POSITIVE_INFINITY;
414
415 double point_plane_distance = distanceBetween(point,polygon.getPlane());
416 Point3D projected_point = new Point3D(VecOp.sub(point,VecOp.mult(point_plane_distance,polygon.getPlane().getNormal())));
417
418 if (intersects(projected_point,polygon))
419 {
420 distance = Math.min(distance,point_plane_distance);
421 }
422 else
423 {
424 for (LineSegment3D edge : polygon.getEdges())
425 {
426 distance = Math.min(distanceBetween(point,edge),distance);
427 }
428 }
429 return distance;
430 }
431
432
433
434
435
436
437
438
439
440
441
442 public static double distanceBetween(Line3D line1, Line3D line2)
443 {
444 Hep3Vector start_diff = VecOp.sub(line2.getStartPoint(),line1.getStartPoint());
445 if (parallel(line1,line2))
446 {
447 return VecOp.cross(start_diff,line1.getDirection()).magnitude();
448 }
449 else
450 {
451 Hep3Vector normal = VecOp.cross(line1.getDirection(),line2.getDirection());
452 double denominator = normal.magnitude();
453 return Math.abs(VecOp.dot(normal,start_diff)/denominator);
454 }
455 }
456
457
458
459
460
461
462
463
464 public static double distanceBetween(Line3D line, LineSegment3D linesegment)
465 {
466 Hep3Vector start_diff = VecOp.sub(linesegment.getStartPoint(),line.getStartPoint());
467 if (parallel(line,linesegment.getLine()))
468 {
469
470 return VecOp.cross(start_diff,line.getDirection()).magnitude();
471 }
472 else
473 {
474 double[] pca = linesPCA(line,linesegment);
475
476
477
478 pca[1] = Math.max(0.0,pca[1]);
479 pca[1] = Math.min(linesegment.getLength(),pca[1]);
480
481
482
483
484 return distanceBetween(line.getEndPoint(pca[0]),linesegment.getLine().getEndPoint(pca[1]));
485 }
486 }
487
488
489
490
491
492
493
494
495 public static double distanceBetween(Line3D line, Plane3D plane)
496 {
497 if (Math.abs(VecOp.dot(line.getDirection(),plane.getNormal())) > DISTANCE_TOLERANCE) return 0;
498 else return distanceBetween(line.getStartPoint(),plane);
499 }
500
501
502
503
504
505
506
507
508 public static double distanceBetween(Line3D line, Polygon3D polygon)
509 {
510 double distance = Double.POSITIVE_INFINITY;
511
512 for (LineSegment3D edge : polygon.getEdges())
513 {
514 distance = Math.min(distance,distanceBetween(line,edge));
515 }
516
517 Point3D plane_intersection = intersection(line,polygon.getPlane());
518 if (intersects(plane_intersection,polygon))
519 {
520 distance = 0;
521 }
522 return distance;
523 }
524
525
526
527
528
529
530
531
532
533
534
535
536 public static double distanceBetween(LineSegment3D linesegment1, LineSegment3D linesegment2)
537 {
538 Hep3Vector start_diff = VecOp.sub(linesegment2.getStartPoint(),linesegment1.getStartPoint());
539 if (parallel(linesegment1.getLine(),linesegment2.getLine()))
540 {
541 Hep3Vector end_diff = VecOp.sub(linesegment2.getEndPoint(),linesegment1.getEndPoint());
542
543 double start_projection = VecOp.dot(start_diff,linesegment1.getDirection());
544 double end_projection = VecOp.dot(end_diff,linesegment1.getDirection());
545 if (start_projection < 0 && end_projection < 0)
546 {
547 if (start_projection < end_projection)
548 {
549 return distanceBetween(linesegment1.getStartPoint(),linesegment2.getEndPoint());
550 }
551 else
552 {
553 return distanceBetween(linesegment1.getStartPoint(),linesegment2.getStartPoint());
554 }
555 }
556 else if (start_projection > linesegment1.getLength() && end_projection > linesegment1.getLength())
557 {
558 if (start_projection > end_projection)
559 {
560 return distanceBetween(linesegment1.getEndPoint(),linesegment2.getEndPoint());
561 }
562 else
563 {
564 return distanceBetween(linesegment1.getEndPoint(),linesegment2.getEndPoint());
565 }
566 }
567 else
568 {
569 return VecOp.cross(start_diff,linesegment1.getDirection()).magnitude();
570 }
571 }
572 else
573 {
574 double[] pca = linesPCA(linesegment1,linesegment2);
575
576 pca[0] = Math.max(0.0,pca[0]);
577 pca[0] = Math.min(linesegment1.getLength(),pca[0]);
578
579 pca[1] = Math.max(0.0,pca[1]);
580 pca[1] = Math.min(linesegment2.getLength(),pca[1]);
581
582 return distanceBetween(linesegment1.getEndPoint(pca[0]),linesegment2.getEndPoint(pca[1]));
583 }
584
585 }
586
587
588
589
590
591
592
593
594 public static double distanceBetween(LineSegment3D linesegment, Plane3D plane)
595 {
596 if (intersects(linesegment,plane))
597 {
598 return 0;
599 }
600 else
601 {
602 return Math.min(distanceBetween(linesegment.getStartPoint(),plane),distanceBetween(linesegment.getEndPoint(),plane));
603 }
604 }
605
606
607
608
609
610
611
612
613 public static double distanceBetween(LineSegment3D linesegment, Polygon3D polygon)
614 {
615 Line3D line = linesegment.getLine();
616 Plane3D plane = polygon.getPlane();
617
618
619 if (!parallel(line,plane))
620 {
621 if (intersects(intersection(line,plane),polygon) && intersects(linesegment,polygon.getPlane())) return 0;
622 }
623
624 double distance = Double.POSITIVE_INFINITY;
625
626 for (LineSegment3D edge : polygon.getEdges())
627 {
628 distance = Math.min(distance,distanceBetween(linesegment,edge));
629 }
630
631
632 for (Point3D endpoint : linesegment.getPoints())
633 {
634 LineSegment3D closest_approach = lineBetween(endpoint,plane);
635 if (intersects(closest_approach.getEndPoint(),polygon))
636 {
637 distance = Math.min(distance,closest_approach.getLength());
638 }
639 }
640
641 return distance;
642 }
643
644
645
646
647
648
649
650
651
652
653
654
655 public static double distanceBetween(Plane3D plane1, Plane3D plane2)
656 {
657 if ( parallel(plane1,plane2) )
658 {
659 return plane2.getDistance()-VecOp.dot(plane1.getNormal(),plane2.getNormal())*plane1.getDistance();
660 }
661 else
662 {
663 return 0;
664 }
665 }
666
667
668
669
670
671
672
673
674 public static double distanceBetween(Plane3D plane, Polygon3D polygon)
675 {
676 if (intersects(plane,polygon)) return 0;
677
678 double abs_distance = Double.POSITIVE_INFINITY;
679 double distance = Double.POSITIVE_INFINITY;
680
681 for (Point3D point : polygon.getVertices())
682 {
683 double vertex_distance = distanceBetween(point,plane);
684 if (Math.abs(vertex_distance) < abs_distance)
685 {
686 abs_distance = Math.abs(vertex_distance);
687 distance = vertex_distance;
688 if (abs_distance < DISTANCE_TOLERANCE) return distance;
689 }
690 }
691 return distance;
692 }
693
694
695
696
697
698
699
700
701
702
703
704
705 public static double distanceBetween(Polygon3D polygon1, Polygon3D polygon2)
706 {
707 double distance = Double.POSITIVE_INFINITY;
708 for (LineSegment3D edge : polygon1.getEdges())
709 {
710 Math.min(distance,distanceBetween(edge,polygon2));
711 if (distance < DISTANCE_TOLERANCE) return 0;
712 }
713 for (LineSegment3D edge : polygon2.getEdges())
714 {
715 Math.min(distance,distanceBetween(edge,polygon1));
716 if (distance < DISTANCE_TOLERANCE) return 0;
717 }
718 return distance;
719 }
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737 public static Point3D intersection(Line3D line, Plane3D plane)
738 {
739 double distance_to_plane = -distanceBetween(line.getStartPoint(),plane);
740 double slope_to_plane = VecOp.dot(line.getDirection(),plane.getNormal());
741 if (slope_to_plane == 0)
742 {
743 throw new RuntimeException("Line is parallel to plane! Please check first with parallel(Line line,Plane plane)");
744 }
745 else
746 {
747 return line.getEndPoint(distance_to_plane/slope_to_plane);
748 }
749 }
750
751
752
753
754
755
756
757
758
759
760
761 public static Line3D intersection(Plane3D plane1, Plane3D plane2)
762 {
763 Hep3Vector direction = VecOp.cross(plane1.getNormal(),plane2.getNormal());
764
765 if (direction.magnitudeSquared() == 0)
766 {
767 throw new RuntimeException("Planes are parallel! Please check first with parallel(Plane plane1,Plane plane2)");
768 }
769
770 double dot_normals = VecOp.dot(plane1.getNormal(),plane2.getNormal());
771
772 double determinant = 1 - Math.pow(dot_normals,2);
773
774 double c1 = (plane1.getDistance()-plane2.getDistance()*dot_normals)/determinant;
775 double c2 = (plane2.getDistance()-plane1.getDistance()*dot_normals)/determinant;
776
777 Point3D point = new Point3D( VecOp.add(VecOp.mult(c1,plane1.getNormal()), VecOp.mult(c2,plane2.getNormal()) ) );
778
779 return new Line3D(point,direction);
780
781 }
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798 public static LineSegment3D lineBetween(Point3D point1, Point3D point2)
799 {
800 return new LineSegment3D(point1, point2);
801 }
802
803
804
805
806
807
808
809
810 public static LineSegment3D lineBetween(Point3D point, Line3D line)
811 {
812 Point3D closest_point = line.getEndPoint(VecOp.dot(VecOp.sub(point,line.getStartPoint()),line.getDirection()));
813 return new LineSegment3D(point,closest_point);
814 }
815
816
817
818
819
820
821
822
823 public static LineSegment3D lineBetween(Point3D point, LineSegment3D linesegment)
824 {
825 Hep3Vector diff = VecOp.sub(point,linesegment.getStartPoint());
826 double dot = VecOp.dot(diff,linesegment.getDirection());
827 if (dot <= 0) return new LineSegment3D(point,linesegment.getStartPoint());
828 else if (dot >= linesegment.getLength()) return new LineSegment3D(point,linesegment.getEndPoint());
829 else return new LineSegment3D(point,linesegment.getEndPoint(dot));
830 }
831
832
833
834
835
836
837
838
839 public static LineSegment3D lineBetween(Point3D point, Plane3D plane)
840 {
841 double distance = VecOp.dot(point,plane.getNormal())-plane.getDistance();
842 Point3D closest_point = new Point3D( VecOp.sub(point,VecOp.mult(distance,plane.getNormal())) );
843 return new LineSegment3D(point,closest_point);
844 }
845
846
847
848
849
850
851
852
853 public static LineSegment3D lineBetween(Point3D point, Polygon3D polygon)
854 {
855 double point_plane_distance = distanceBetween(point,polygon.getPlane());
856 Point3D projected_point = new Point3D(VecOp.sub(point,VecOp.mult(point_plane_distance,polygon.getPlane().getNormal())));
857
858 if (intersects(projected_point,polygon))
859 {
860 return new LineSegment3D(point,projected_point);
861 }
862 else
863 {
864 double distance = Double.POSITIVE_INFINITY;
865 LineSegment3D closest_edge = new LineSegment3D();
866 for (LineSegment3D edge : polygon.getEdges())
867 {
868 if (distanceBetween(point,edge) < distance)
869 {
870 distance = distanceBetween(point,edge);
871 closest_edge = edge;
872 }
873 }
874 return lineBetween(point,closest_edge);
875 }
876 }
877
878
879
880
881
882
883
884
885
886
887
888 public static LineSegment3D lineBetween(Line3D line1, Line3D line2)
889 {
890 if (parallel(line1,line2))
891 {
892 throw new RuntimeException("Lines are parallel! Please check first with parallel(Line line1,Line line2)");
893 }
894 else
895 {
896 double pca[] = linesPCA(line1,line2);
897 return new LineSegment3D(line1.getEndPoint(pca[0]),line2.getEndPoint(pca[1]));
898 }
899 }
900
901
902
903
904
905
906
907
908 public static LineSegment3D lineBetween(Line3D line, LineSegment3D linesegment)
909 {
910 LineSegment3D line_between;
911
912 if (parallel(line,linesegment.getLine()))
913 {
914 throw new RuntimeException("Line and line segment are parallel! Please check first with parallel(Line line,LineSegment linesegment)");
915 }
916 else
917 {
918 double[] pca = linesPCA(line,linesegment);
919
920 if (pca[1]<0.0)
921 {
922 line_between = lineBetween(linesegment.getStartPoint(),line);
923 line_between.reverse();
924 }
925 else if (pca[1]>linesegment.getLength())
926 {
927 line_between = lineBetween(linesegment.getEndPoint(),line);
928 line_between.reverse();
929 }
930 else
931 {
932 line_between = new LineSegment3D(line.getEndPoint(pca[0]),linesegment.getEndPoint(pca[1]));
933 }
934
935 return line_between;
936 }
937 }
938
939
940
941
942
943
944
945
946 public static LineSegment3D lineBetween(Line3D line, Polygon3D polygon)
947 {
948 Point3D plane_intersection = intersection(line,polygon.getPlane());
949 if (intersects(plane_intersection,polygon))
950 {
951 throw new RuntimeException("Line intersects polygon Please check first with intersects(Line line, Polygon polygon)");
952 }
953 else
954 {
955 double distance = Double.POSITIVE_INFINITY;
956 LineSegment3D closest_edge = new LineSegment3D();
957 for (LineSegment3D edge : polygon.getEdges())
958 {
959 if (distanceBetween(line,edge) < distance)
960 {
961 distance = distanceBetween(line,edge);
962 closest_edge = edge;
963 }
964 }
965 return lineBetween(line,closest_edge);
966 }
967 }
968
969
970
971
972
973
974
975
976
977
978
979 public static LineSegment3D lineBetween(LineSegment3D linesegment1, LineSegment3D linesegment2)
980 {
981 Hep3Vector start_diff = VecOp.sub(linesegment2.getStartPoint(),linesegment1.getStartPoint());
982 if (parallel(linesegment1.getLine(),linesegment2.getLine()))
983 {
984 Hep3Vector end_diff = VecOp.sub(linesegment2.getEndPoint(),linesegment1.getEndPoint());
985
986 double start_projection = VecOp.dot(start_diff,linesegment1.getDirection());
987 double end_projection = VecOp.dot(end_diff,linesegment1.getDirection());
988 if (start_projection < 0 && end_projection < 0)
989 {
990 if (start_projection < end_projection)
991 {
992 return new LineSegment3D(linesegment1.getStartPoint(),linesegment2.getEndPoint());
993 }
994 else
995 {
996 return new LineSegment3D(linesegment1.getStartPoint(),linesegment2.getStartPoint());
997 }
998 }
999 else if (start_projection > linesegment1.getLength() && end_projection > linesegment1.getLength())
1000 {
1001 if (start_projection > end_projection)
1002 {
1003 return new LineSegment3D(linesegment1.getEndPoint(),linesegment2.getEndPoint());
1004 }
1005 else
1006 {
1007 return new LineSegment3D(linesegment1.getEndPoint(),linesegment2.getEndPoint());
1008 }
1009 }
1010 else
1011 {
1012 double startpoint1 = Math.max(0,start_projection);
1013 double endpoint1 = Math.min(linesegment1.getLength(),end_projection);
1014 Point3D origin = linesegment1.getEndPoint((startpoint1+endpoint1)/2);
1015
1016 double startpoint2 = (start_projection-startpoint1)/2;
1017 double endpoint2 = (end_projection-endpoint1)/2;
1018 Point3D destination = linesegment2.getEndPoint((startpoint2+endpoint2)/2);
1019
1020 return new LineSegment3D(origin,destination);
1021 }
1022 }
1023 else
1024 {
1025 double[] pca = linesPCA(linesegment1,linesegment2);
1026 pca[0] = Math.max(0.0,pca[0]);
1027 pca[0] = Math.min(linesegment1.getLength(),pca[0]);
1028
1029 pca[1] = Math.max(0.0,pca[1]);
1030 pca[1] = Math.min(linesegment2.getLength(),pca[1]);
1031
1032 return new LineSegment3D(linesegment1.getEndPoint(pca[0]),linesegment2.getEndPoint(pca[1]));
1033 }
1034
1035 }
1036
1037
1038
1039
1040
1041
1042
1043
1044 public static LineSegment3D lineBetween(LineSegment3D linesegment, Plane3D plane)
1045 {
1046 if (intersects(linesegment,plane))
1047 {
1048 throw new RuntimeException("Line segment intersects plane. Please check first with intersects(LineSegment linesegment, Plane plane)");
1049 }
1050 else if (parallel(linesegment,plane))
1051 {
1052 return lineBetween(linesegment.getEndPoint(linesegment.getLength()/2),plane);
1053 }
1054 else
1055 {
1056 if (distanceBetween(linesegment.getStartPoint(),plane) < distanceBetween(linesegment.getEndPoint(),plane))
1057 {
1058 return lineBetween(linesegment.getStartPoint(),plane);
1059 }
1060 else
1061 {
1062 return lineBetween(linesegment.getEndPoint(),plane);
1063 }
1064 }
1065 }
1066
1067
1068
1069
1070
1071
1072
1073
1074 public static LineSegment3D lineBetween(LineSegment3D linesegment, Polygon3D polygon)
1075 {
1076 Line3D line = linesegment.getLine();
1077 Plane3D plane = polygon.getPlane();
1078
1079
1080 if (!parallel(line,plane))
1081 {
1082 if (intersects(intersection(line,plane),polygon) && intersects(linesegment,polygon.getPlane()))
1083 {
1084 throw new RuntimeException("Line segment intersects polygon. Please check first with intersects(LineSegment linesegment, Polygon polygon)");
1085 }
1086 }
1087
1088
1089 double edge_distance = Double.POSITIVE_INFINITY;
1090 LineSegment3D closest_edge = new LineSegment3D();
1091 for (LineSegment3D edge : polygon.getEdges())
1092 {
1093 if (distanceBetween(linesegment,edge) < edge_distance)
1094 {
1095 edge_distance = distanceBetween(linesegment,edge);
1096 closest_edge = edge;
1097 }
1098 }
1099
1100 double endpoint_distance = edge_distance;
1101 LineSegment3D closest_planar_approach = new LineSegment3D();
1102 for (Point3D endpoint : linesegment.getPoints())
1103 {
1104 LineSegment3D closest_approach = lineBetween(endpoint,plane);
1105 if (closest_approach.getLength() < endpoint_distance && intersects(closest_approach.getEndPoint(),polygon))
1106 {
1107 endpoint_distance = closest_approach.getLength();
1108 closest_planar_approach = closest_approach;
1109 }
1110 }
1111
1112 if (endpoint_distance < edge_distance)
1113 {
1114 return closest_planar_approach;
1115 }
1116 else
1117 {
1118 return lineBetween(linesegment,closest_edge);
1119 }
1120 }
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132 public static LineSegment3D lineBetween(Plane3D plane, Polygon3D polygon)
1133 {
1134 if (intersects(plane,polygon))
1135 {
1136 throw new RuntimeException("Plane intersects polygon. Please check first with intersects(Plane plane, Polygon polygon)");
1137 }
1138
1139 double distance = Double.POSITIVE_INFINITY;
1140 LineSegment3D closest_edge = new LineSegment3D();
1141 for (LineSegment3D edge : polygon.getEdges())
1142 {
1143 if (distanceBetween(edge,plane) < distance)
1144 {
1145 distance = distanceBetween(edge,plane);
1146 closest_edge = edge;
1147 }
1148 }
1149 return lineBetween(closest_edge,plane);
1150 }
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164 public static LineSegment3D lineBetween(Polygon3D polygon1, Polygon3D polygon2)
1165 {
1166 double distance = Double.POSITIVE_INFINITY;
1167 LineSegment3D closest_edge = new LineSegment3D();
1168
1169 Plane3D plane = polygon2.getPlane();
1170 for (LineSegment3D edge : polygon1.getEdges())
1171 {
1172 if (distanceBetween(edge,plane) < distance)
1173 {
1174 distance = distanceBetween(edge,plane);
1175 closest_edge = edge;
1176 }
1177 }
1178 if (distance < DISTANCE_TOLERANCE)
1179 {
1180 throw new RuntimeException("Polygons intersect. Please check first with intersects(Polygon polygon1, Polygon polygon2)");
1181 }
1182
1183 plane = polygon1.getPlane();
1184 for (LineSegment3D edge : polygon2.getEdges())
1185 {
1186 if (distanceBetween(edge,plane) < distance)
1187 {
1188 distance = distanceBetween(edge,plane);
1189 closest_edge = edge;
1190 }
1191 }
1192 if (distance < DISTANCE_TOLERANCE)
1193 {
1194 throw new RuntimeException("Polygons intersect. Please check first with intersects(Polygon polygon1, Polygon polygon2)");
1195 }
1196
1197 return lineBetween(closest_edge,plane);
1198
1199 }
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211 public static boolean coplanar(List<Point3D> points)
1212 {
1213 if (points.size()<4) return true;
1214 if (collinear(points)) return true;
1215
1216 Hep3Vector v1 = VecOp.sub(points.get(1),points.get(0));
1217 Hep3Vector v2 = VecOp.sub(points.get(2),points.get(1));
1218
1219
1220 Hep3Vector normal = VecOp.unit(VecOp.cross(v1,v2));
1221
1222 for (int ipoint = 3; ipoint < points.size(); ipoint++)
1223 {
1224 Hep3Vector vtest = VecOp.sub(points.get(ipoint),points.get(ipoint-1));
1225 if (VecOp.dot(vtest,normal) > DISTANCE_TOLERANCE) return false;
1226 }
1227
1228 return true;
1229 }
1230
1231
1232
1233
1234
1235
1236
1237
1238 public static boolean coplanar(Line3D line, Plane3D plane)
1239 {
1240 return (parallel(line,plane) && intersects(line.getStartPoint(),plane));
1241 }
1242
1243
1244
1245
1246
1247
1248
1249 public static boolean collinear(List<Point3D> points)
1250 {
1251 if (points.size()<3) return true;
1252
1253 Hep3Vector direction = VecOp.unit(VecOp.sub(points.get(1),points.get(0)));
1254
1255 for (int ipoint = 2; ipoint < points.size(); ipoint++)
1256 {
1257 Hep3Vector vtest = VecOp.sub(points.get(ipoint),points.get(ipoint-1));
1258 if (VecOp.cross(vtest,direction).magnitude() > DISTANCE_TOLERANCE) return false;
1259 }
1260
1261 return true;
1262 }
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272 public static boolean parallel(Line3D line1, Line3D line2)
1273 {
1274 return VecOp.cross(line1.getDirection(),line2.getDirection()).magnitude() < ANGULAR_TOLERANCE;
1275 }
1276
1277
1278
1279
1280
1281
1282
1283
1284 public static boolean parallel(Line3D line, Plane3D plane)
1285 {
1286 return Math.abs(VecOp.dot(line.getDirection(),plane.getNormal())) < ANGULAR_TOLERANCE;
1287 }
1288
1289
1290
1291
1292
1293
1294
1295
1296 public static boolean parallel(Plane3D plane1, Plane3D plane2)
1297 {
1298 return VecOp.cross(plane1.getNormal(),plane2.getNormal()).magnitude() < ANGULAR_TOLERANCE;
1299 }
1300
1301
1302
1303
1304
1305
1306
1307
1308 public static boolean isNormal(Hep3Vector unit_vector, Plane3D plane)
1309 {
1310 if ( VecOp.cross(unit_vector,plane.getNormal()).magnitude() < ANGULAR_TOLERANCE )
1311 {
1312 return VecOp.dot(unit_vector,plane.getNormal()) > 0;
1313 }
1314 else return false;
1315 }
1316
1317
1318
1319
1320
1321
1322
1323 private static double[] linesPCA(Line3D line1, Line3D line2)
1324 {
1325 Hep3Vector s1 = VecOp.sub(line2.getStartPoint(),line1.getStartPoint());
1326 Hep3Vector s2 = line2.getDirection();
1327 Hep3Vector s3 = VecOp.cross(line1.getDirection(),line2.getDirection());
1328 double[][] s_elements = {s1.v(),s2.v(),s3.v()};
1329 BasicMatrix s = new BasicMatrix(s_elements);
1330 double s_det = s.det();
1331
1332 Hep3Vector t1 = s1;
1333 Hep3Vector t2 = line1.getDirection();
1334 Hep3Vector t3 = s3;
1335 double[][] t_elements = {t1.v(),t2.v(),t3.v()};
1336 BasicMatrix t = new BasicMatrix(t_elements);
1337 t.transpose();
1338 double t_det = t.det();
1339
1340 double denominator = t3.magnitudeSquared();
1341 if (denominator == 0)
1342 {
1343 throw new RuntimeException("Lines must be checked for parallelism before calling linesPCA!!");
1344 }
1345
1346 double s_pca = s_det/denominator;
1347 double t_pca = t_det/denominator;
1348
1349 return new double[]{s_pca,t_pca};
1350 }
1351
1352
1353 }