1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package com.irurueta.geometry;
17
18 import com.irurueta.algebra.AlgebraException;
19 import com.irurueta.algebra.ArrayUtils;
20 import com.irurueta.algebra.LUDecomposer;
21 import com.irurueta.algebra.Matrix;
22 import com.irurueta.algebra.RQDecomposer;
23 import com.irurueta.algebra.SingularValueDecomposer;
24 import com.irurueta.algebra.Utils;
25 import com.irurueta.algebra.WrongSizeException;
26
27 import java.io.Serializable;
28 import java.util.Arrays;
29
30
31
32
33
34
35 @SuppressWarnings("DuplicatedCode")
36 public class ProjectiveTransformation3D extends Transformation3D implements Serializable {
37
38
39
40
41 public static final int NUM_TRANSLATION_COORDS = 3;
42
43
44
45
46
47 public static final int NUM_PROJECTIVE_PARAMS = 4;
48
49
50
51
52 public static final int INHOM_COORDS = 3;
53
54
55
56
57 public static final int HOM_COORDS = 4;
58
59
60
61
62 public static final double EPS = 1e-12;
63
64
65
66
67
68 private static final double LARGE_ROTATION_MATRIX_THRESHOLD = 1.0;
69
70
71
72
73 private Matrix t;
74
75
76
77
78 private boolean normalized;
79
80
81
82
83
84 public ProjectiveTransformation3D() {
85 super();
86 try {
87 t = Matrix.identity(HOM_COORDS, HOM_COORDS);
88 } catch (final WrongSizeException ignore) {
89
90 }
91 normalize();
92 }
93
94
95
96
97
98
99
100
101
102
103 public ProjectiveTransformation3D(final Matrix t) {
104 setT(t);
105 normalize();
106 }
107
108
109
110
111
112
113
114
115 public ProjectiveTransformation3D(final double scale) {
116 final var diag = new double[HOM_COORDS];
117 Arrays.fill(diag, scale);
118
119 diag[HOM_COORDS - 1] = 1.0;
120 t = Matrix.diagonal(diag);
121 normalize();
122 }
123
124
125
126
127
128
129
130 public ProjectiveTransformation3D(final Rotation3D rotation) {
131 t = rotation.asHomogeneousMatrix();
132 normalize();
133 }
134
135
136
137
138
139
140
141
142
143
144 public ProjectiveTransformation3D(final double scale, final Rotation3D rotation) {
145 try {
146 final var diag = new double[INHOM_COORDS];
147 Arrays.fill(diag, scale);
148 final var a = Matrix.diagonal(diag);
149 a.multiply(rotation.asInhomogeneousMatrix());
150 t = Matrix.identity(HOM_COORDS, HOM_COORDS);
151 t.setSubmatrix(0, 0, INHOM_COORDS - 1,
152 INHOM_COORDS - 1, a);
153 } catch (final WrongSizeException ignore) {
154
155 }
156 normalize();
157 }
158
159
160
161
162
163
164
165
166
167
168 public ProjectiveTransformation3D(final AffineParameters3D params, final Rotation3D rotation) {
169 try {
170 final var a = params.asMatrix();
171 a.multiply(rotation.asInhomogeneousMatrix());
172 t = Matrix.identity(HOM_COORDS, HOM_COORDS);
173 t.setSubmatrix(0, 0, INHOM_COORDS - 1, INHOM_COORDS - 1, a);
174 } catch (final WrongSizeException ignore) {
175
176 }
177 normalize();
178 }
179
180
181
182
183
184
185
186
187
188
189 public ProjectiveTransformation3D(final double[] translation) {
190 if (translation.length != NUM_TRANSLATION_COORDS) {
191 throw new IllegalArgumentException();
192 }
193
194 try {
195 t = Matrix.identity(HOM_COORDS, HOM_COORDS);
196 t.setSubmatrix(0, 3, 2, 3, translation);
197 } catch (final WrongSizeException ignore) {
198
199 }
200 normalize();
201 }
202
203
204
205
206
207
208
209
210
211
212
213
214
215 public ProjectiveTransformation3D(final Matrix a, final double[] translation) {
216 if (translation.length != NUM_TRANSLATION_COORDS) {
217 throw new IllegalArgumentException();
218 }
219
220 try {
221 t = Matrix.identity(HOM_COORDS, HOM_COORDS);
222 t.setSubmatrix(0, 0, INHOM_COORDS - 1,
223 INHOM_COORDS - 1, a);
224 t.setSubmatrix(0, HOM_COORDS - 1, translation.length - 1,
225 HOM_COORDS - 1, translation);
226 } catch (final WrongSizeException ignore) {
227
228 }
229 normalize();
230 }
231
232
233
234
235
236
237
238
239
240
241
242
243
244 public ProjectiveTransformation3D(final double scale, final double[] translation) {
245 if (translation.length != NUM_TRANSLATION_COORDS) {
246 throw new IllegalArgumentException();
247 }
248
249 final var diag = new double[HOM_COORDS];
250 Arrays.fill(diag, scale);
251
252 diag[HOM_COORDS - 1] = 1.0;
253 t = Matrix.diagonal(diag);
254
255
256 t.setSubmatrix(0, HOM_COORDS - 1, translation.length - 1,
257 HOM_COORDS - 1, translation);
258 normalize();
259 }
260
261
262
263
264
265
266
267
268
269
270
271
272 public ProjectiveTransformation3D(final Rotation3D rotation, final double[] translation) {
273 if (translation.length != NUM_TRANSLATION_COORDS) {
274 throw new IllegalArgumentException();
275 }
276
277 t = rotation.asHomogeneousMatrix();
278
279
280 t.setSubmatrix(0, HOM_COORDS - 1, translation.length - 1,
281 HOM_COORDS - 1, translation);
282 normalize();
283 }
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299 public ProjectiveTransformation3D(final double scale, final Rotation3D rotation, final double[] translation) {
300 if (translation.length != NUM_TRANSLATION_COORDS) {
301 throw new IllegalArgumentException();
302 }
303
304 try {
305 final var diag = new double[INHOM_COORDS];
306 Arrays.fill(diag, scale);
307 final var a = Matrix.diagonal(diag);
308 a.multiply(rotation.asInhomogeneousMatrix());
309
310 t = Matrix.identity(HOM_COORDS, HOM_COORDS);
311
312 t.setSubmatrix(0, 0, INHOM_COORDS - 1,
313 INHOM_COORDS - 1, a);
314
315 t.setSubmatrix(0, HOM_COORDS - 1, translation.length - 1,
316 HOM_COORDS - 1, translation);
317 } catch (final WrongSizeException ignore) {
318
319 }
320 normalize();
321 }
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339 public ProjectiveTransformation3D(final double scale, final Rotation3D rotation, final double[] translation,
340 final double[] projectiveParameters) {
341 if (translation.length != NUM_TRANSLATION_COORDS) {
342 throw new IllegalArgumentException();
343 }
344 if (projectiveParameters.length != HOM_COORDS) {
345 throw new IllegalArgumentException();
346 }
347
348 try {
349 final var value = projectiveParameters[HOM_COORDS - 1];
350 final var diag = new double[INHOM_COORDS];
351 Arrays.fill(diag, scale);
352 final var a = Matrix.diagonal(diag);
353 a.multiply(rotation.asInhomogeneousMatrix());
354
355 t = Matrix.identity(HOM_COORDS, HOM_COORDS);
356
357 t.setSubmatrix(0, 0, INHOM_COORDS - 1,
358 INHOM_COORDS - 1, a);
359
360 t.setSubmatrix(0, HOM_COORDS - 1, translation.length - 1,
361 HOM_COORDS - 1, translation);
362 t.multiplyByScalar(value);
363
364 t.setSubmatrix(HOM_COORDS - 1, 0, HOM_COORDS - 1,
365 HOM_COORDS - 1, projectiveParameters);
366 } catch (final WrongSizeException ignore) {
367
368 }
369 normalize();
370 }
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386 public ProjectiveTransformation3D(final AffineParameters3D params, final Rotation3D rotation,
387 final double[] translation) {
388 if (translation.length != NUM_TRANSLATION_COORDS) {
389 throw new IllegalArgumentException();
390 }
391
392 try {
393 final var a = params.asMatrix();
394 a.multiply(rotation.asInhomogeneousMatrix());
395 t = Matrix.identity(HOM_COORDS, HOM_COORDS);
396
397 t.setSubmatrix(0, 0, INHOM_COORDS - 1,
398 INHOM_COORDS - 1, a);
399
400 t.setSubmatrix(0, HOM_COORDS - 1, translation.length - 1,
401 HOM_COORDS - 1, translation);
402 } catch (final WrongSizeException ignore) {
403
404 }
405 normalize();
406 }
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424 public ProjectiveTransformation3D(final AffineParameters3D params, final Rotation3D rotation,
425 final double[] translation, final double[] projectiveParameters) {
426 if (translation.length != NUM_TRANSLATION_COORDS) {
427 throw new IllegalArgumentException();
428 }
429 if (projectiveParameters.length != HOM_COORDS) {
430 throw new IllegalArgumentException();
431 }
432
433 try {
434 final var a = params.asMatrix();
435 a.multiply(rotation.asInhomogeneousMatrix());
436 t = Matrix.identity(HOM_COORDS, HOM_COORDS);
437
438 t.setSubmatrix(0, 0, INHOM_COORDS - 1,
439 INHOM_COORDS - 1, a);
440
441 t.setSubmatrix(0, HOM_COORDS - 1, translation.length - 1,
442 HOM_COORDS - 1, translation);
443 final var value = projectiveParameters[HOM_COORDS - 1];
444 t.multiplyByScalar(value);
445
446 t.setSubmatrix(HOM_COORDS - 1, 0, HOM_COORDS - 1,
447 HOM_COORDS - 1, projectiveParameters);
448 } catch (final WrongSizeException ignore) {
449
450 }
451 normalize();
452 }
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477 public ProjectiveTransformation3D(
478 final Point3D inputPoint1, final Point3D inputPoint2, final Point3D inputPoint3, final Point3D inputPoint4,
479 final Point3D inputPoint5, final Point3D outputPoint1, final Point3D outputPoint2,
480 final Point3D outputPoint3, final Point3D outputPoint4, final Point3D outputPoint5)
481 throws CoincidentPointsException {
482 try {
483 t = new Matrix(HOM_COORDS, HOM_COORDS);
484 } catch (final WrongSizeException ignore) {
485
486 }
487 setTransformationFromPoints(inputPoint1, inputPoint2, inputPoint3, inputPoint4, inputPoint5, outputPoint1,
488 outputPoint2, outputPoint3, outputPoint4, outputPoint5);
489 }
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514 public ProjectiveTransformation3D(
515 final Plane inputPlane1, final Plane inputPlane2, final Plane inputPlane3, final Plane inputPlane4,
516 final Plane inputPlane5, final Plane outputPlane1, final Plane outputPlane2, final Plane outputPlane3,
517 final Plane outputPlane4, final Plane outputPlane5) throws CoincidentPlanesException {
518 setTransformationFromPlanes(inputPlane1, inputPlane2, inputPlane3, inputPlane4, inputPlane5, outputPlane1,
519 outputPlane2, outputPlane3, outputPlane4, outputPlane5);
520 }
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536 public ProjectiveTransformation3D(
537 final Line3D inputLine1, final Line3D inputLine2, final Line3D inputLine3, final Line3D outputLine1,
538 final Line3D outputLine2, final Line3D outputLine3) throws CoincidentLinesException {
539 setTransformationFromLines(inputLine1, inputLine2, inputLine3, outputLine1, outputLine2, outputLine3);
540 }
541
542
543
544
545
546
547
548
549
550
551
552 public Matrix getT() {
553 return t;
554 }
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569 public final void setT(final Matrix t) {
570 if (t.getRows() != HOM_COORDS || t.getColumns() != HOM_COORDS) {
571 throw new IllegalArgumentException();
572 }
573
574 this.t = t;
575 normalized = false;
576 }
577
578
579
580
581
582
583
584
585
586
587
588 public static boolean isDegenerate(final Matrix t) {
589 if (t.getRows() != HOM_COORDS || t.getColumns() != HOM_COORDS) {
590 throw new IllegalArgumentException();
591 }
592
593 try {
594 final var decomposer = new LUDecomposer(t);
595 decomposer.decompose();
596 return decomposer.isSingular();
597 } catch (final AlgebraException e) {
598
599
600 return true;
601 }
602 }
603
604
605
606
607
608
609
610 public boolean isDegenerate() {
611 return isDegenerate(t);
612 }
613
614
615
616
617
618
619
620 public Matrix getA() {
621 final var a = t.getSubmatrix(0, 0, INHOM_COORDS - 1,
622 INHOM_COORDS - 1);
623 a.multiplyByScalar(1.0 / t.getElementAt(HOM_COORDS - 1, HOM_COORDS - 1));
624 return a;
625 }
626
627
628
629
630
631
632
633
634
635
636 public final void setA(final Matrix a) {
637 if (a == null) {
638 throw new NullPointerException();
639 }
640 if (a.getRows() != INHOM_COORDS || a.getColumns() != INHOM_COORDS) {
641 throw new IllegalArgumentException();
642 }
643
644 t.setSubmatrix(0, 0, INHOM_COORDS - 1,
645 INHOM_COORDS - 1, a.multiplyByScalarAndReturnNew(t.getElementAt(HOM_COORDS - 1,
646 HOM_COORDS - 1)));
647 normalized = false;
648 }
649
650
651
652
653 public final void normalize() {
654 if (!normalized) {
655 final var norm = Utils.normF(t);
656 if (norm > EPS) {
657 t.multiplyByScalar(1.0 / norm);
658 }
659 normalized = true;
660 }
661 }
662
663
664
665
666
667
668
669
670
671
672 public Rotation3D getRotation() throws AlgebraException {
673
674
675 normalize();
676 final var decomposer = new RQDecomposer(t.getSubmatrix(0, 0,
677 INHOM_COORDS - 1, INHOM_COORDS - 1));
678 try {
679 decomposer.decompose();
680
681 return new MatrixRotation3D(decomposer.getQ(), LARGE_ROTATION_MATRIX_THRESHOLD);
682 } catch (final InvalidRotationMatrixException ignore) {
683 return null;
684 }
685 }
686
687
688
689
690
691
692
693
694
695
696 public void setRotation(final Rotation3D rotation) throws AlgebraException {
697 final var rotMatrix = rotation.asInhomogeneousMatrix();
698
699
700 final var decomposer = new RQDecomposer(t.getSubmatrix(0, 0,
701 INHOM_COORDS - 1, INHOM_COORDS - 1));
702 decomposer.decompose();
703
704 final var localA = decomposer.getR();
705 localA.multiply(rotMatrix);
706 t.setSubmatrix(0, 0, INHOM_COORDS - 1, INHOM_COORDS - 1,
707 localA);
708 normalized = false;
709 }
710
711
712
713
714
715
716
717
718
719
720 public void addRotation(final Rotation3D rotation) throws AlgebraException {
721 final var localRotation = getRotation();
722 localRotation.combine(rotation);
723 setRotation(localRotation);
724 }
725
726
727
728
729
730
731
732
733
734
735
736
737 public void setScale(final double scale) throws AlgebraException {
738 normalize();
739 final var value = t.getElementAt(HOM_COORDS - 1, HOM_COORDS - 1);
740 final var decomposer = new RQDecomposer(t.getSubmatrix(0, 0,
741 INHOM_COORDS - 1, INHOM_COORDS - 1));
742 decomposer.decompose();
743
744 final var localA = decomposer.getR();
745 localA.setElementAt(0, 0, scale * value);
746 localA.setElementAt(1, 1, scale * value);
747 localA.setElementAt(2, 2, scale * value);
748 localA.multiply(decomposer.getQ());
749 t.setSubmatrix(0, 0, INHOM_COORDS - 1, INHOM_COORDS - 1,
750 localA);
751 normalized = false;
752 }
753
754
755
756
757
758
759
760
761
762
763
764 public AffineParameters3D getAffineParameters() throws AlgebraException {
765 final var parameters = new AffineParameters3D();
766 getAffineParameters(parameters);
767 return parameters;
768 }
769
770
771
772
773
774
775
776
777
778
779
780
781 public void getAffineParameters(final AffineParameters3D result) throws AlgebraException {
782 normalize();
783 final var value = t.getElementAt(HOM_COORDS - 1, HOM_COORDS - 1);
784 final var decomposer = new RQDecomposer(t.getSubmatrix(0, 0,
785 INHOM_COORDS - 1, INHOM_COORDS - 1));
786 decomposer.decompose();
787 final var r = decomposer.getR();
788 r.multiplyByScalar(1.0 / value);
789 result.fromMatrix(r);
790 }
791
792
793
794
795
796
797
798
799
800
801
802 public void setAffineParameters(final AffineParameters3D parameters) throws AlgebraException {
803 normalize();
804 final var value = t.getElementAt(HOM_COORDS - 1, HOM_COORDS - 1);
805 final var decomposer = new RQDecomposer(t.getSubmatrix(0, 0,
806 INHOM_COORDS - 1, INHOM_COORDS - 1));
807 decomposer.decompose();
808 final var params = parameters.asMatrix();
809 final var rotation = decomposer.getQ();
810
811
812
813 params.multiply(rotation);
814
815 params.multiplyByScalar(value);
816 t.setSubmatrix(0, 0, INHOM_COORDS - 1, INHOM_COORDS - 1,
817 params);
818 normalized = false;
819 }
820
821
822
823
824
825
826
827
828
829
830
831
832 public double[] getProjectiveParameters() {
833
834 return t.getSubmatrixAsArray(HOM_COORDS - 1, 0, HOM_COORDS - 1,
835 HOM_COORDS - 1, true);
836 }
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851 public final void setProjectiveParameters(final double[] params) {
852 if (params.length != HOM_COORDS) {
853 throw new IllegalArgumentException();
854 }
855
856 t.setSubmatrix(HOM_COORDS - 1, 0, HOM_COORDS - 1,
857 HOM_COORDS - 1, params);
858 normalized = false;
859 }
860
861
862
863
864
865
866
867
868
869
870 public double[] getTranslation() {
871 normalize();
872 final var translation = t.getSubmatrixAsArray(0, HOM_COORDS - 1,
873 INHOM_COORDS - 1, HOM_COORDS - 1);
874 final var value = t.getElementAt(HOM_COORDS - 1, HOM_COORDS - 1);
875 ArrayUtils.multiplyByScalar(translation, 1.0 / value, translation);
876 return translation;
877 }
878
879
880
881
882
883
884
885
886
887
888
889 public void getTranslation(final double[] out) throws WrongSizeException {
890 t.getSubmatrixAsArray(0, HOM_COORDS - 1, INHOM_COORDS - 1,
891 HOM_COORDS - 1, out);
892 final var value = t.getElementAt(HOM_COORDS - 1, HOM_COORDS - 1);
893 ArrayUtils.multiplyByScalar(out, 1.0 / value, out);
894 }
895
896
897
898
899
900
901
902
903
904 public void setTranslation(final double[] translation) {
905 if (translation.length != NUM_TRANSLATION_COORDS) {
906 throw new IllegalArgumentException();
907 }
908
909 final var value = t.getElementAt(HOM_COORDS - 1, HOM_COORDS - 1);
910 final var translation2 = ArrayUtils.multiplyByScalarAndReturnNew(translation, value);
911 t.setSubmatrix(0, HOM_COORDS - 1, translation2.length - 1,
912 HOM_COORDS - 1, translation2);
913 normalized = false;
914 }
915
916
917
918
919
920
921
922
923
924
925 public void addTranslation(final double[] translation) {
926 final var currentTranslation = getTranslation();
927 ArrayUtils.sum(currentTranslation, translation, currentTranslation);
928 setTranslation(currentTranslation);
929 }
930
931
932
933
934
935
936 public double getTranslationX() {
937 normalize();
938 return t.getElementAt(0, HOM_COORDS - 1) / t.getElementAt(
939 HOM_COORDS - 1, HOM_COORDS - 1);
940 }
941
942
943
944
945
946
947 public void setTranslationX(final double translationX) {
948 t.setElementAt(0, HOM_COORDS - 1, translationX * t.getElementAt(
949 HOM_COORDS - 1, HOM_COORDS - 1));
950 normalized = false;
951 }
952
953
954
955
956
957
958 public double getTranslationY() {
959 normalize();
960 return t.getElementAt(1, HOM_COORDS - 1) / t.getElementAt(
961 HOM_COORDS - 1, HOM_COORDS - 1);
962 }
963
964
965
966
967
968
969 public void setTranslationY(final double translationY) {
970 t.setElementAt(1, HOM_COORDS - 1, translationY * t.getElementAt(
971 HOM_COORDS - 1, HOM_COORDS - 1));
972 normalized = false;
973 }
974
975
976
977
978
979
980 public double getTranslationZ() {
981 normalize();
982 return t.getElementAt(2, HOM_COORDS - 1) / t.getElementAt(
983 HOM_COORDS - 1, HOM_COORDS - 1);
984 }
985
986
987
988
989
990
991 public void setTranslationZ(final double translationZ) {
992 t.setElementAt(2, HOM_COORDS - 1, translationZ * t.getElementAt(
993 HOM_COORDS - 1, HOM_COORDS - 1));
994 normalized = false;
995 }
996
997
998
999
1000
1001
1002
1003
1004
1005 public void setTranslation(final double translationX, final double translationY, final double translationZ) {
1006 setTranslationX(translationX);
1007 setTranslationY(translationY);
1008 setTranslationZ(translationZ);
1009 }
1010
1011
1012
1013
1014
1015
1016
1017 public void setTranslation(final Point3D translation) {
1018 setTranslation(translation.getInhomX(), translation.getInhomY(), translation.getInhomZ());
1019 }
1020
1021
1022
1023
1024
1025
1026
1027 public Point3D getTranslationPoint() {
1028 final var out = Point3D.create();
1029 getTranslationPoint(out);
1030 return out;
1031 }
1032
1033
1034
1035
1036
1037
1038
1039 public void getTranslationPoint(final Point3D out) {
1040 out.setInhomogeneousCoordinates(getTranslationX(), getTranslationY(), getTranslationZ());
1041 }
1042
1043
1044
1045
1046
1047
1048
1049 public void addTranslationX(final double translationX) {
1050 setTranslationX(getTranslationX() + translationX);
1051 }
1052
1053
1054
1055
1056
1057
1058
1059 public void addTranslationY(final double translationY) {
1060 setTranslationY(getTranslationY() + translationY);
1061 }
1062
1063
1064
1065
1066
1067
1068
1069 public void addTranslationZ(final double translationZ) {
1070 setTranslationZ(getTranslationZ() + translationZ);
1071 }
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081 public void addTranslation(final double translationX, final double translationY, final double translationZ) {
1082 addTranslationX(translationX);
1083 addTranslationY(translationY);
1084 addTranslationZ(translationZ);
1085 }
1086
1087
1088
1089
1090
1091
1092
1093
1094 public void addTranslation(final Point3D translation) {
1095 addTranslation(translation.getInhomX(), translation.getInhomY(), translation.getInhomZ());
1096 }
1097
1098
1099
1100
1101
1102
1103
1104
1105 @Override
1106 public Matrix asMatrix() {
1107 return new Matrix(t);
1108 }
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118 @Override
1119 public void asMatrix(final Matrix m) {
1120 if (m.getRows() != HOM_COORDS || m.getColumns() != HOM_COORDS) {
1121 throw new IllegalArgumentException();
1122 }
1123
1124 m.copyFrom(t);
1125 }
1126
1127
1128
1129
1130
1131
1132
1133
1134 @Override
1135 public void transform(final Point3D inputPoint, final Point3D outputPoint) {
1136 inputPoint.normalize();
1137 normalize();
1138 try {
1139 final var point = new Matrix(Point3D.POINT3D_HOMOGENEOUS_COORDINATES_LENGTH, 1);
1140 point.setElementAtIndex(0, inputPoint.getHomX());
1141 point.setElementAtIndex(1, inputPoint.getHomY());
1142 point.setElementAtIndex(2, inputPoint.getHomZ());
1143 point.setElementAtIndex(3, inputPoint.getHomW());
1144
1145 final var transformedPoint = t.multiplyAndReturnNew(point);
1146
1147 outputPoint.setHomogeneousCoordinates(
1148 transformedPoint.getElementAtIndex(0),
1149 transformedPoint.getElementAtIndex(1),
1150 transformedPoint.getElementAtIndex(2),
1151 transformedPoint.getElementAtIndex(3));
1152 } catch (final WrongSizeException ignore) {
1153
1154 }
1155 }
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169 @Override
1170 public void transform(final Quadric inputQuadric, final Quadric outputQuadric) throws NonSymmetricMatrixException,
1171 AlgebraException {
1172
1173
1174
1175
1176
1177
1178
1179
1180 inputQuadric.normalize();
1181
1182 final var q = inputQuadric.asMatrix();
1183 normalize();
1184
1185 final var invT = inverseAndReturnNew().asMatrix();
1186
1187 var norm = Utils.normF(invT);
1188 invT.multiplyByScalar(1.0 / norm);
1189
1190 final var m = invT.transposeAndReturnNew();
1191 try {
1192 m.multiply(q);
1193 m.multiply(invT);
1194 } catch (final WrongSizeException ignore) {
1195
1196 }
1197
1198
1199
1200 norm = Utils.normF(m);
1201 m.multiplyByScalar(1.0 / norm);
1202
1203 outputQuadric.setParameters(m);
1204 }
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219 @Override
1220 public void transform(final DualQuadric inputDualQuadric, final DualQuadric outputDualQuadric)
1221 throws NonSymmetricMatrixException, AlgebraException {
1222
1223
1224
1225
1226
1227
1228
1229 inputDualQuadric.normalize();
1230 normalize();
1231
1232 final var dualQ = inputDualQuadric.asMatrix();
1233 final var transT = t.transposeAndReturnNew();
1234
1235 final var m = t.multiplyAndReturnNew(dualQ);
1236 m.multiply(transT);
1237
1238
1239
1240 final var norm = Utils.normF(m);
1241 m.multiplyByScalar(1.0 / norm);
1242
1243 outputDualQuadric.setParameters(m);
1244 }
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256 @Override
1257 public void transform(final Plane inputPlane, final Plane outputPlane) throws AlgebraException {
1258
1259
1260
1261
1262
1263
1264
1265 inputPlane.normalize();
1266 normalize();
1267
1268 final var invT = inverseAndReturnNew().asMatrix();
1269 final var l = Matrix.newFromArray(inputPlane.asArray());
1270
1271 invT.transpose();
1272 invT.multiply(l);
1273
1274 outputPlane.setParameters(invT.toArray());
1275 }
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287 @Override
1288 public void transform(final PinholeCamera inputCamera, final PinholeCamera outputCamera) throws AlgebraException {
1289
1290 inputCamera.normalize();
1291 normalize();
1292
1293 final var invT = inverseAndReturnNew().asMatrix();
1294 final var c = inputCamera.getInternalMatrix();
1295 c.multiply(invT);
1296 outputCamera.setInternalMatrix(c);
1297 }
1298
1299
1300
1301
1302
1303
1304
1305 public void inverse() throws AlgebraException {
1306 inverse(this);
1307 }
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317 public Transformation3D inverseAndReturnNew() throws AlgebraException {
1318 final var result = new ProjectiveTransformation3D();
1319 inverse(result);
1320 return result;
1321 }
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331 protected void inverse(final ProjectiveTransformation3D result) throws AlgebraException {
1332 result.t = Utils.inverse(t);
1333 result.normalized = false;
1334 }
1335
1336
1337
1338
1339
1340
1341
1342
1343 public void combine(final ProjectiveTransformation3D transformation) {
1344 combine(transformation, this);
1345 }
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357 public ProjectiveTransformation3D combineAndReturnNew(final ProjectiveTransformation3D transformation) {
1358 final var result = new ProjectiveTransformation3D();
1359 combine(transformation, result);
1360 return result;
1361 }
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372 private void combine(final ProjectiveTransformation3D inputTransformation,
1373 final ProjectiveTransformation3D outputTransformation) {
1374
1375
1376 normalize();
1377 inputTransformation.normalize();
1378
1379 try {
1380 outputTransformation.t = this.t.multiplyAndReturnNew(inputTransformation.t);
1381 outputTransformation.normalized = false;
1382 } catch (final WrongSizeException ignore) {
1383
1384 }
1385 }
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410 public final void setTransformationFromPoints(
1411 final Point3D inputPoint1, final Point3D inputPoint2, final Point3D inputPoint3, final Point3D inputPoint4,
1412 final Point3D inputPoint5, final Point3D outputPoint1, final Point3D outputPoint2,
1413 final Point3D outputPoint3, final Point3D outputPoint4, final Point3D outputPoint5)
1414 throws CoincidentPointsException {
1415
1416
1417 inputPoint1.normalize();
1418 inputPoint2.normalize();
1419 inputPoint3.normalize();
1420 inputPoint4.normalize();
1421 inputPoint5.normalize();
1422
1423 outputPoint1.normalize();
1424 outputPoint2.normalize();
1425 outputPoint3.normalize();
1426 outputPoint4.normalize();
1427 outputPoint5.normalize();
1428
1429
1430
1431
1432 Matrix m = null;
1433 try {
1434
1435 m = new Matrix(15, 16);
1436
1437
1438 var iX = inputPoint1.getHomX();
1439 var iY = inputPoint1.getHomY();
1440 var iZ = inputPoint1.getHomZ();
1441 var iW = inputPoint1.getHomW();
1442
1443 var oX = outputPoint1.getHomX();
1444 var oY = outputPoint1.getHomY();
1445 var oZ = outputPoint1.getHomZ();
1446 var oW = outputPoint1.getHomW();
1447
1448 var oWiX = oW * iX;
1449 var oWiY = oW * iY;
1450 var oWiZ = oW * iZ;
1451 var oWiW = oW * iW;
1452
1453 var oXiX = oX * iX;
1454 var oXiY = oX * iY;
1455 var oXiZ = oX * iZ;
1456 var oXiW = oX * iW;
1457
1458 var oYiX = oY * iX;
1459 var oYiY = oY * iY;
1460 var oYiZ = oY * iZ;
1461 var oYiW = oY * iW;
1462
1463 var oZiX = oZ * iX;
1464 var oZiY = oZ * iY;
1465 var oZiZ = oZ * iZ;
1466 var oZiW = oZ * iW;
1467
1468 var tmp = oWiX * oWiX + oWiY * oWiY + oWiZ * oWiZ + oWiW * oWiW;
1469 var norm = Math.sqrt(tmp + oXiX * oXiX + oXiY * oXiY + oXiZ * oXiZ + oXiW * oXiW);
1470
1471 m.setElementAt(0, 0, oWiX / norm);
1472 m.setElementAt(0, 1, oWiY / norm);
1473 m.setElementAt(0, 2, oWiZ / norm);
1474 m.setElementAt(0, 3, oWiW / norm);
1475
1476 m.setElementAt(0, 12, -oXiX / norm);
1477 m.setElementAt(0, 13, -oXiY / norm);
1478 m.setElementAt(0, 14, -oXiZ / norm);
1479 m.setElementAt(0, 15, -oXiW / norm);
1480
1481 norm = Math.sqrt(tmp + oYiX * oYiX + oYiY * oYiY + oYiZ * oYiZ + oYiW * oYiW);
1482
1483 m.setElementAt(1, 4, oWiX / norm);
1484 m.setElementAt(1, 5, oWiY / norm);
1485 m.setElementAt(1, 6, oWiZ / norm);
1486 m.setElementAt(1, 7, oWiW / norm);
1487
1488 m.setElementAt(1, 12, -oYiX / norm);
1489 m.setElementAt(1, 13, -oYiY / norm);
1490 m.setElementAt(1, 14, -oYiZ / norm);
1491 m.setElementAt(1, 15, -oYiW / norm);
1492
1493 norm = Math.sqrt(tmp + oZiX * oZiX + oZiY * oZiY + oZiZ * oZiZ + oZiW * oZiW);
1494
1495 m.setElementAt(2, 8, oWiX / norm);
1496 m.setElementAt(2, 9, oWiY / norm);
1497 m.setElementAt(2, 10, oWiZ / norm);
1498 m.setElementAt(2, 11, oWiW / norm);
1499
1500 m.setElementAt(2, 12, -oZiX / norm);
1501 m.setElementAt(2, 13, -oZiY / norm);
1502 m.setElementAt(2, 14, -oZiZ / norm);
1503 m.setElementAt(2, 15, -oZiW / norm);
1504
1505
1506 iX = inputPoint2.getHomX();
1507 iY = inputPoint2.getHomY();
1508 iZ = inputPoint2.getHomZ();
1509 iW = inputPoint2.getHomW();
1510
1511 oX = outputPoint2.getHomX();
1512 oY = outputPoint2.getHomY();
1513 oZ = outputPoint2.getHomZ();
1514 oW = outputPoint2.getHomW();
1515
1516 oWiX = oW * iX;
1517 oWiY = oW * iY;
1518 oWiZ = oW * iZ;
1519 oWiW = oW * iW;
1520
1521 oXiX = oX * iX;
1522 oXiY = oX * iY;
1523 oXiZ = oX * iZ;
1524 oXiW = oX * iW;
1525
1526 oYiX = oY * iX;
1527 oYiY = oY * iY;
1528 oYiZ = oY * iZ;
1529 oYiW = oY * iW;
1530
1531 oZiX = oZ * iX;
1532 oZiY = oZ * iY;
1533 oZiZ = oZ * iZ;
1534 oZiW = oZ * iW;
1535
1536 tmp = oWiX * oWiX + oWiY * oWiY + oWiZ * oWiZ + oWiW * oWiW;
1537 norm = Math.sqrt(tmp + oXiX * oXiX + oXiY * oXiY + oXiZ * oXiZ + oXiW * oXiW);
1538
1539 m.setElementAt(3, 0, oWiX / norm);
1540 m.setElementAt(3, 1, oWiY / norm);
1541 m.setElementAt(3, 2, oWiZ / norm);
1542 m.setElementAt(3, 3, oWiW / norm);
1543
1544 m.setElementAt(3, 12, -oXiX / norm);
1545 m.setElementAt(3, 13, -oXiY / norm);
1546 m.setElementAt(3, 14, -oXiZ / norm);
1547 m.setElementAt(3, 15, -oXiW / norm);
1548
1549 norm = Math.sqrt(tmp + oYiX * oYiX + oYiY * oYiY + oYiZ * oYiZ + oYiW * oYiW);
1550
1551 m.setElementAt(4, 4, oWiX / norm);
1552 m.setElementAt(4, 5, oWiY / norm);
1553 m.setElementAt(4, 6, oWiZ / norm);
1554 m.setElementAt(4, 7, oWiW / norm);
1555
1556 m.setElementAt(4, 12, -oYiX / norm);
1557 m.setElementAt(4, 13, -oYiY / norm);
1558 m.setElementAt(4, 14, -oYiZ / norm);
1559 m.setElementAt(4, 15, -oYiW / norm);
1560
1561 norm = Math.sqrt(tmp + oZiX * oZiX + oZiY * oZiY + oZiZ * oZiZ + oZiW * oZiW);
1562
1563 m.setElementAt(5, 8, oWiX / norm);
1564 m.setElementAt(5, 9, oWiY / norm);
1565 m.setElementAt(5, 10, oWiZ / norm);
1566 m.setElementAt(5, 11, oWiW / norm);
1567
1568 m.setElementAt(5, 12, -oZiX / norm);
1569 m.setElementAt(5, 13, -oZiY / norm);
1570 m.setElementAt(5, 14, -oZiZ / norm);
1571 m.setElementAt(5, 15, -oZiW / norm);
1572
1573
1574 iX = inputPoint3.getHomX();
1575 iY = inputPoint3.getHomY();
1576 iZ = inputPoint3.getHomZ();
1577 iW = inputPoint3.getHomW();
1578
1579 oX = outputPoint3.getHomX();
1580 oY = outputPoint3.getHomY();
1581 oZ = outputPoint3.getHomZ();
1582 oW = outputPoint3.getHomW();
1583
1584 oWiX = oW * iX;
1585 oWiY = oW * iY;
1586 oWiZ = oW * iZ;
1587 oWiW = oW * iW;
1588
1589 oXiX = oX * iX;
1590 oXiY = oX * iY;
1591 oXiZ = oX * iZ;
1592 oXiW = oX * iW;
1593
1594 oYiX = oY * iX;
1595 oYiY = oY * iY;
1596 oYiZ = oY * iZ;
1597 oYiW = oY * iW;
1598
1599 oZiX = oZ * iX;
1600 oZiY = oZ * iY;
1601 oZiZ = oZ * iZ;
1602 oZiW = oZ * iW;
1603
1604 tmp = oWiX * oWiX + oWiY * oWiY + oWiZ * oWiZ + oWiW * oWiW;
1605 norm = Math.sqrt(tmp + oXiX * oXiX + oXiY * oXiY + oXiZ * oXiZ + oXiW * oXiW);
1606
1607 m.setElementAt(6, 0, oWiX / norm);
1608 m.setElementAt(6, 1, oWiY / norm);
1609 m.setElementAt(6, 2, oWiZ / norm);
1610 m.setElementAt(6, 3, oWiW / norm);
1611
1612 m.setElementAt(6, 12, -oXiX / norm);
1613 m.setElementAt(6, 13, -oXiY / norm);
1614 m.setElementAt(6, 14, -oXiZ / norm);
1615 m.setElementAt(6, 15, -oXiW / norm);
1616
1617 norm = Math.sqrt(tmp + oYiX * oYiX + oYiY * oYiY + oYiZ * oYiZ + oYiW * oYiW);
1618
1619 m.setElementAt(7, 4, oWiX / norm);
1620 m.setElementAt(7, 5, oWiY / norm);
1621 m.setElementAt(7, 6, oWiZ / norm);
1622 m.setElementAt(7, 7, oWiW / norm);
1623
1624 m.setElementAt(7, 12, -oYiX / norm);
1625 m.setElementAt(7, 13, -oYiY / norm);
1626 m.setElementAt(7, 14, -oYiZ / norm);
1627 m.setElementAt(7, 15, -oYiW / norm);
1628
1629 norm = Math.sqrt(tmp + oZiX * oZiX + oZiY * oZiY + oZiZ * oZiZ + oZiW * oZiW);
1630
1631 m.setElementAt(8, 8, oWiX / norm);
1632 m.setElementAt(8, 9, oWiY / norm);
1633 m.setElementAt(8, 10, oWiZ / norm);
1634 m.setElementAt(8, 11, oWiW / norm);
1635
1636 m.setElementAt(8, 12, -oZiX / norm);
1637 m.setElementAt(8, 13, -oZiY / norm);
1638 m.setElementAt(8, 14, -oZiZ / norm);
1639 m.setElementAt(8, 15, -oZiW / norm);
1640
1641
1642 iX = inputPoint4.getHomX();
1643 iY = inputPoint4.getHomY();
1644 iZ = inputPoint4.getHomZ();
1645 iW = inputPoint4.getHomW();
1646
1647 oX = outputPoint4.getHomX();
1648 oY = outputPoint4.getHomY();
1649 oZ = outputPoint4.getHomZ();
1650 oW = outputPoint4.getHomW();
1651
1652 oWiX = oW * iX;
1653 oWiY = oW * iY;
1654 oWiZ = oW * iZ;
1655 oWiW = oW * iW;
1656
1657 oXiX = oX * iX;
1658 oXiY = oX * iY;
1659 oXiZ = oX * iZ;
1660 oXiW = oX * iW;
1661
1662 oYiX = oY * iX;
1663 oYiY = oY * iY;
1664 oYiZ = oY * iZ;
1665 oYiW = oY * iW;
1666
1667 oZiX = oZ * iX;
1668 oZiY = oZ * iY;
1669 oZiZ = oZ * iZ;
1670 oZiW = oZ * iW;
1671
1672 tmp = oWiX * oWiX + oWiY * oWiY + oWiZ * oWiZ + oWiW * oWiW;
1673 norm = Math.sqrt(tmp + oXiX * oXiX + oXiY * oXiY + oXiZ * oXiZ + oXiW * oXiW);
1674
1675 m.setElementAt(9, 0, oWiX / norm);
1676 m.setElementAt(9, 1, oWiY / norm);
1677 m.setElementAt(9, 2, oWiZ / norm);
1678 m.setElementAt(9, 3, oWiW / norm);
1679
1680 m.setElementAt(9, 12, -oXiX / norm);
1681 m.setElementAt(9, 13, -oXiY / norm);
1682 m.setElementAt(9, 14, -oXiZ / norm);
1683 m.setElementAt(9, 15, -oXiW / norm);
1684
1685 norm = Math.sqrt(tmp + oYiX * oYiX + oYiY * oYiY + oYiZ * oYiZ + oYiW * oYiW);
1686
1687 m.setElementAt(10, 4, oWiX / norm);
1688 m.setElementAt(10, 5, oWiY / norm);
1689 m.setElementAt(10, 6, oWiZ / norm);
1690 m.setElementAt(10, 7, oWiW / norm);
1691
1692 m.setElementAt(10, 12, -oYiX / norm);
1693 m.setElementAt(10, 13, -oYiY / norm);
1694 m.setElementAt(10, 14, -oYiZ / norm);
1695 m.setElementAt(10, 15, -oYiW / norm);
1696
1697 norm = Math.sqrt(tmp + oZiX * oZiX + oZiY * oZiY + oZiZ * oZiZ + oZiW * oZiW);
1698
1699 m.setElementAt(11, 8, oWiX / norm);
1700 m.setElementAt(11, 9, oWiY / norm);
1701 m.setElementAt(11, 10, oWiZ / norm);
1702 m.setElementAt(11, 11, oWiW / norm);
1703
1704 m.setElementAt(11, 12, -oZiX / norm);
1705 m.setElementAt(11, 13, -oZiY / norm);
1706 m.setElementAt(11, 14, -oZiZ / norm);
1707 m.setElementAt(11, 15, -oZiW / norm);
1708
1709
1710 iX = inputPoint5.getHomX();
1711 iY = inputPoint5.getHomY();
1712 iZ = inputPoint5.getHomZ();
1713 iW = inputPoint5.getHomW();
1714
1715 oX = outputPoint5.getHomX();
1716 oY = outputPoint5.getHomY();
1717 oZ = outputPoint5.getHomZ();
1718 oW = outputPoint5.getHomW();
1719
1720 oWiX = oW * iX;
1721 oWiY = oW * iY;
1722 oWiZ = oW * iZ;
1723 oWiW = oW * iW;
1724
1725 oXiX = oX * iX;
1726 oXiY = oX * iY;
1727 oXiZ = oX * iZ;
1728 oXiW = oX * iW;
1729
1730 oYiX = oY * iX;
1731 oYiY = oY * iY;
1732 oYiZ = oY * iZ;
1733 oYiW = oY * iW;
1734
1735 oZiX = oZ * iX;
1736 oZiY = oZ * iY;
1737 oZiZ = oZ * iZ;
1738 oZiW = oZ * iW;
1739
1740 tmp = oWiX * oWiX + oWiY * oWiY + oWiZ * oWiZ + oWiW * oWiW;
1741 norm = Math.sqrt(tmp + oXiX * oXiX + oXiY * oXiY + oXiZ * oXiZ + oXiW * oXiW);
1742
1743 m.setElementAt(12, 0, oWiX / norm);
1744 m.setElementAt(12, 1, oWiY / norm);
1745 m.setElementAt(12, 2, oWiZ / norm);
1746 m.setElementAt(12, 3, oWiW / norm);
1747
1748 m.setElementAt(12, 12, -oXiX / norm);
1749 m.setElementAt(12, 13, -oXiY / norm);
1750 m.setElementAt(12, 14, -oXiZ / norm);
1751 m.setElementAt(12, 15, -oXiW / norm);
1752
1753 norm = Math.sqrt(tmp + oYiX * oYiX + oYiY * oYiY + oYiZ * oYiZ + oYiW * oYiW);
1754
1755 m.setElementAt(13, 4, oWiX / norm);
1756 m.setElementAt(13, 5, oWiY / norm);
1757 m.setElementAt(13, 6, oWiZ / norm);
1758 m.setElementAt(13, 7, oWiW / norm);
1759
1760 m.setElementAt(13, 12, -oYiX / norm);
1761 m.setElementAt(13, 13, -oYiY / norm);
1762 m.setElementAt(13, 14, -oYiZ / norm);
1763 m.setElementAt(13, 15, -oYiW / norm);
1764
1765 norm = Math.sqrt(tmp + oZiX * oZiX + oZiY * oZiY + oZiZ * oZiZ + oZiW * oZiW);
1766
1767 m.setElementAt(14, 8, oWiX / norm);
1768 m.setElementAt(14, 9, oWiY / norm);
1769 m.setElementAt(14, 10, oWiZ / norm);
1770 m.setElementAt(14, 11, oWiW / norm);
1771
1772 m.setElementAt(14, 12, -oZiX / norm);
1773 m.setElementAt(14, 13, -oZiY / norm);
1774 m.setElementAt(14, 14, -oZiZ / norm);
1775 m.setElementAt(14, 15, -oZiW / norm);
1776 } catch (final WrongSizeException ignore) {
1777
1778 }
1779
1780
1781 Matrix v;
1782 try {
1783 final var decomposer = new SingularValueDecomposer(m);
1784 decomposer.decompose();
1785
1786
1787
1788 if (decomposer.getRank() < 15) {
1789 throw new CoincidentPointsException();
1790 }
1791 v = decomposer.getV();
1792
1793
1794 t.setSubmatrix(0, 0, HOM_COORDS - 1, HOM_COORDS - 1,
1795 v.getSubmatrix(0, 15, 15, 15).toArray(), false);
1796 normalized = true;
1797
1798 } catch (final AlgebraException e) {
1799 throw new CoincidentPointsException(e);
1800 }
1801 }
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826 public final void setTransformationFromPlanes(
1827 final Plane inputPlane1, final Plane inputPlane2, final Plane inputPlane3, final Plane inputPlane4,
1828 final Plane inputPlane5, final Plane outputPlane1, final Plane outputPlane2, final Plane outputPlane3,
1829 final Plane outputPlane4, final Plane outputPlane5) throws CoincidentPlanesException {
1830
1831
1832 inputPlane1.normalize();
1833 inputPlane2.normalize();
1834 inputPlane3.normalize();
1835 inputPlane4.normalize();
1836 inputPlane5.normalize();
1837
1838 outputPlane1.normalize();
1839 outputPlane2.normalize();
1840 outputPlane3.normalize();
1841 outputPlane4.normalize();
1842 outputPlane5.normalize();
1843
1844
1845
1846
1847 Matrix m = null;
1848 try {
1849
1850 m = new Matrix(15, 16);
1851
1852
1853 var iA = inputPlane1.getA();
1854 var iB = inputPlane1.getB();
1855 var iC = inputPlane1.getC();
1856 var iD = inputPlane1.getD();
1857
1858 var oA = outputPlane1.getA();
1859 var oB = outputPlane1.getB();
1860 var oC = outputPlane1.getC();
1861 var oD = outputPlane1.getD();
1862
1863 var oDiA = oD * iA;
1864 var oDiB = oD * iB;
1865 var oDiC = oD * iC;
1866 var oDiD = oD * iD;
1867
1868 var oAiA = oA * iA;
1869 var oAiB = oA * iB;
1870 var oAiC = oA * iC;
1871 var oAiD = oA * iD;
1872
1873 var oBiA = oB * iA;
1874 var oBiB = oB * iB;
1875 var oBiC = oB * iC;
1876 var oBiD = oB * iD;
1877
1878 var oCiA = oC * iA;
1879 var oCiB = oC * iB;
1880 var oCiC = oC * iC;
1881 var oCiD = oC * iD;
1882
1883 var tmp = oDiA * oDiA + oDiB * oDiB + oDiC * oDiC + oDiD * oDiD;
1884 var norm = Math.sqrt(tmp + oAiA * oAiA + oAiB * oAiB + oAiC * oAiC + oAiD * oAiD);
1885
1886 m.setElementAt(0, 0, oDiA / norm);
1887 m.setElementAt(0, 1, oDiB / norm);
1888 m.setElementAt(0, 2, oDiC / norm);
1889 m.setElementAt(0, 3, oDiD / norm);
1890
1891 m.setElementAt(0, 12, -oAiA / norm);
1892 m.setElementAt(0, 13, -oAiB / norm);
1893 m.setElementAt(0, 14, -oAiC / norm);
1894 m.setElementAt(0, 15, -oAiD / norm);
1895
1896 norm = Math.sqrt(tmp + oBiA * oBiA + oBiB * oBiB + oBiC * oBiC + oBiD * oBiD);
1897
1898 m.setElementAt(1, 4, oDiA / norm);
1899 m.setElementAt(1, 5, oDiB / norm);
1900 m.setElementAt(1, 6, oDiC / norm);
1901 m.setElementAt(1, 7, oDiD / norm);
1902
1903 m.setElementAt(1, 12, -oBiA / norm);
1904 m.setElementAt(1, 13, -oBiB / norm);
1905 m.setElementAt(1, 14, -oBiC / norm);
1906 m.setElementAt(1, 15, -oBiD / norm);
1907
1908 norm = Math.sqrt(tmp + oCiA * oCiA + oCiB * oCiB + oCiC * oCiC + oCiD * oCiD);
1909
1910 m.setElementAt(2, 8, oDiA / norm);
1911 m.setElementAt(2, 9, oDiB / norm);
1912 m.setElementAt(2, 10, oDiC / norm);
1913 m.setElementAt(2, 11, oDiD / norm);
1914
1915 m.setElementAt(2, 12, -oCiA / norm);
1916 m.setElementAt(2, 13, -oCiB / norm);
1917 m.setElementAt(2, 14, -oCiC / norm);
1918 m.setElementAt(2, 15, -oCiD / norm);
1919
1920
1921 iA = inputPlane2.getA();
1922 iB = inputPlane2.getB();
1923 iC = inputPlane2.getC();
1924 iD = inputPlane2.getD();
1925
1926 oA = outputPlane2.getA();
1927 oB = outputPlane2.getB();
1928 oC = outputPlane2.getC();
1929 oD = outputPlane2.getD();
1930
1931 oDiA = oD * iA;
1932 oDiB = oD * iB;
1933 oDiC = oD * iC;
1934 oDiD = oD * iD;
1935
1936 oAiA = oA * iA;
1937 oAiB = oA * iB;
1938 oAiC = oA * iC;
1939 oAiD = oA * iD;
1940
1941 oBiA = oB * iA;
1942 oBiB = oB * iB;
1943 oBiC = oB * iC;
1944 oBiD = oB * iD;
1945
1946 oCiA = oC * iA;
1947 oCiB = oC * iB;
1948 oCiC = oC * iC;
1949 oCiD = oC * iD;
1950
1951 tmp = oDiA * oDiA + oDiB * oDiB + oDiC * oDiC + oDiD * oDiD;
1952 norm = Math.sqrt(tmp + oAiA * oAiA + oAiB * oAiB + oAiC * oAiC + oAiD * oAiD);
1953
1954 m.setElementAt(3, 0, oDiA / norm);
1955 m.setElementAt(3, 1, oDiB / norm);
1956 m.setElementAt(3, 2, oDiC / norm);
1957 m.setElementAt(3, 3, oDiD / norm);
1958
1959 m.setElementAt(3, 12, -oAiA / norm);
1960 m.setElementAt(3, 13, -oAiB / norm);
1961 m.setElementAt(3, 14, -oAiC / norm);
1962 m.setElementAt(3, 15, -oAiD / norm);
1963
1964 norm = Math.sqrt(tmp + oBiA * oBiA + oBiB * oBiB + oBiC * oBiC + oBiD * oBiD);
1965
1966 m.setElementAt(4, 4, oDiA / norm);
1967 m.setElementAt(4, 5, oDiB / norm);
1968 m.setElementAt(4, 6, oDiC / norm);
1969 m.setElementAt(4, 7, oDiD / norm);
1970
1971 m.setElementAt(4, 12, -oBiA / norm);
1972 m.setElementAt(4, 13, -oBiB / norm);
1973 m.setElementAt(4, 14, -oBiC / norm);
1974 m.setElementAt(4, 15, -oBiD / norm);
1975
1976 norm = Math.sqrt(tmp + oCiA * oCiA + oCiB * oCiB + oCiC * oCiC + oCiD * oCiD);
1977
1978 m.setElementAt(5, 8, oDiA / norm);
1979 m.setElementAt(5, 9, oDiB / norm);
1980 m.setElementAt(5, 10, oDiC / norm);
1981 m.setElementAt(5, 11, oDiD / norm);
1982
1983 m.setElementAt(5, 12, -oCiA / norm);
1984 m.setElementAt(5, 13, -oCiB / norm);
1985 m.setElementAt(5, 14, -oCiC / norm);
1986 m.setElementAt(5, 15, -oCiD / norm);
1987
1988
1989 iA = inputPlane3.getA();
1990 iB = inputPlane3.getB();
1991 iC = inputPlane3.getC();
1992 iD = inputPlane3.getD();
1993
1994 oA = outputPlane3.getA();
1995 oB = outputPlane3.getB();
1996 oC = outputPlane3.getC();
1997 oD = outputPlane3.getD();
1998
1999 oDiA = oD * iA;
2000 oDiB = oD * iB;
2001 oDiC = oD * iC;
2002 oDiD = oD * iD;
2003
2004 oAiA = oA * iA;
2005 oAiB = oA * iB;
2006 oAiC = oA * iC;
2007 oAiD = oA * iD;
2008
2009 oBiA = oB * iA;
2010 oBiB = oB * iB;
2011 oBiC = oB * iC;
2012 oBiD = oB * iD;
2013
2014 oCiA = oC * iA;
2015 oCiB = oC * iB;
2016 oCiC = oC * iC;
2017 oCiD = oC * iD;
2018
2019 tmp = oDiA * oDiA + oDiB * oDiB + oDiC * oDiC + oDiD * oDiD;
2020 norm = Math.sqrt(tmp + oAiA * oAiA + oAiB * oAiB + oAiC * oAiC + oAiD * oAiD);
2021
2022 m.setElementAt(6, 0, oDiA / norm);
2023 m.setElementAt(6, 1, oDiB / norm);
2024 m.setElementAt(6, 2, oDiC / norm);
2025 m.setElementAt(6, 3, oDiD / norm);
2026
2027 m.setElementAt(6, 12, -oAiA / norm);
2028 m.setElementAt(6, 13, -oAiB / norm);
2029 m.setElementAt(6, 14, -oAiC / norm);
2030 m.setElementAt(6, 15, -oAiD / norm);
2031
2032 norm = Math.sqrt(tmp + oBiA * oBiA + oBiB * oBiB + oBiC * oBiC + oBiD * oBiD);
2033
2034 m.setElementAt(7, 4, oDiA / norm);
2035 m.setElementAt(7, 5, oDiB / norm);
2036 m.setElementAt(7, 6, oDiC / norm);
2037 m.setElementAt(7, 7, oDiD / norm);
2038
2039 m.setElementAt(7, 12, -oBiA / norm);
2040 m.setElementAt(7, 13, -oBiB / norm);
2041 m.setElementAt(7, 14, -oBiC / norm);
2042 m.setElementAt(7, 15, -oBiD / norm);
2043
2044 norm = Math.sqrt(tmp + oCiA * oCiA + oCiB * oCiB + oCiC * oCiC + oCiD * oCiD);
2045
2046 m.setElementAt(8, 8, oDiA / norm);
2047 m.setElementAt(8, 9, oDiB / norm);
2048 m.setElementAt(8, 10, oDiC / norm);
2049 m.setElementAt(8, 11, oDiD / norm);
2050
2051 m.setElementAt(8, 12, -oCiA / norm);
2052 m.setElementAt(8, 13, -oCiB / norm);
2053 m.setElementAt(8, 14, -oCiC / norm);
2054 m.setElementAt(8, 15, -oCiD / norm);
2055
2056
2057 iA = inputPlane4.getA();
2058 iB = inputPlane4.getB();
2059 iC = inputPlane4.getC();
2060 iD = inputPlane4.getD();
2061
2062 oA = outputPlane4.getA();
2063 oB = outputPlane4.getB();
2064 oC = outputPlane4.getC();
2065 oD = outputPlane4.getD();
2066
2067 oDiA = oD * iA;
2068 oDiB = oD * iB;
2069 oDiC = oD * iC;
2070 oDiD = oD * iD;
2071
2072 oAiA = oA * iA;
2073 oAiB = oA * iB;
2074 oAiC = oA * iC;
2075 oAiD = oA * iD;
2076
2077 oBiA = oB * iA;
2078 oBiB = oB * iB;
2079 oBiC = oB * iC;
2080 oBiD = oB * iD;
2081
2082 oCiA = oC * iA;
2083 oCiB = oC * iB;
2084 oCiC = oC * iC;
2085 oCiD = oC * iD;
2086
2087 tmp = oDiA * oDiA + oDiB * oDiB + oDiC * oDiC + oDiD * oDiD;
2088 norm = Math.sqrt(tmp + oAiA * oAiA + oAiB * oAiB + oAiC * oAiC + oAiD * oAiD);
2089
2090 m.setElementAt(9, 0, oDiA / norm);
2091 m.setElementAt(9, 1, oDiB / norm);
2092 m.setElementAt(9, 2, oDiC / norm);
2093 m.setElementAt(9, 3, oDiD / norm);
2094
2095 m.setElementAt(9, 12, -oAiA / norm);
2096 m.setElementAt(9, 13, -oAiB / norm);
2097 m.setElementAt(9, 14, -oAiC / norm);
2098 m.setElementAt(9, 15, -oAiD / norm);
2099
2100 norm = Math.sqrt(tmp + oBiA * oBiA + oBiB * oBiB + oBiC * oBiC + oBiD * oBiD);
2101
2102 m.setElementAt(10, 4, oDiA / norm);
2103 m.setElementAt(10, 5, oDiB / norm);
2104 m.setElementAt(10, 6, oDiC / norm);
2105 m.setElementAt(10, 7, oDiD / norm);
2106
2107 m.setElementAt(10, 12, -oBiA / norm);
2108 m.setElementAt(10, 13, -oBiB / norm);
2109 m.setElementAt(10, 14, -oBiC / norm);
2110 m.setElementAt(10, 15, -oBiD / norm);
2111
2112 norm = Math.sqrt(tmp + oCiA * oCiA + oCiB * oCiB + oCiC * oCiC + oCiD * oCiD);
2113
2114 m.setElementAt(11, 8, oDiA / norm);
2115 m.setElementAt(11, 9, oDiB / norm);
2116 m.setElementAt(11, 10, oDiC / norm);
2117 m.setElementAt(11, 11, oDiD / norm);
2118
2119 m.setElementAt(11, 12, -oCiA / norm);
2120 m.setElementAt(11, 13, -oCiB / norm);
2121 m.setElementAt(11, 14, -oCiC / norm);
2122 m.setElementAt(11, 15, -oCiD / norm);
2123
2124
2125 iA = inputPlane5.getA();
2126 iB = inputPlane5.getB();
2127 iC = inputPlane5.getC();
2128 iD = inputPlane5.getD();
2129
2130 oA = outputPlane5.getA();
2131 oB = outputPlane5.getB();
2132 oC = outputPlane5.getC();
2133 oD = outputPlane5.getD();
2134
2135 oDiA = oD * iA;
2136 oDiB = oD * iB;
2137 oDiC = oD * iC;
2138 oDiD = oD * iD;
2139
2140 oAiA = oA * iA;
2141 oAiB = oA * iB;
2142 oAiC = oA * iC;
2143 oAiD = oA * iD;
2144
2145 oBiA = oB * iA;
2146 oBiB = oB * iB;
2147 oBiC = oB * iC;
2148 oBiD = oB * iD;
2149
2150 oCiA = oC * iA;
2151 oCiB = oC * iB;
2152 oCiC = oC * iC;
2153 oCiD = oC * iD;
2154
2155 tmp = oDiA * oDiA + oDiB * oDiB + oDiC * oDiC + oDiD * oDiD;
2156 norm = Math.sqrt(tmp + oAiA * oAiA + oAiB * oAiB + oAiC * oAiC + oAiD * oAiD);
2157
2158 m.setElementAt(12, 0, oDiA / norm);
2159 m.setElementAt(12, 1, oDiB / norm);
2160 m.setElementAt(12, 2, oDiC / norm);
2161 m.setElementAt(12, 3, oDiD / norm);
2162
2163 m.setElementAt(12, 12, -oAiA / norm);
2164 m.setElementAt(12, 13, -oAiB / norm);
2165 m.setElementAt(12, 14, -oAiC / norm);
2166 m.setElementAt(12, 15, -oAiD / norm);
2167
2168 norm = Math.sqrt(tmp + oBiA * oBiA + oBiB * oBiB + oBiC * oBiC + oBiD * oBiD);
2169
2170 m.setElementAt(13, 4, oDiA / norm);
2171 m.setElementAt(13, 5, oDiB / norm);
2172 m.setElementAt(13, 6, oDiC / norm);
2173 m.setElementAt(13, 7, oDiD / norm);
2174
2175 m.setElementAt(13, 12, -oBiA / norm);
2176 m.setElementAt(13, 13, -oBiB / norm);
2177 m.setElementAt(13, 14, -oBiC / norm);
2178 m.setElementAt(13, 15, -oBiD / norm);
2179
2180 norm = Math.sqrt(tmp + oCiA * oCiA + oCiB * oCiB + oCiC * oCiC + oCiD * oCiD);
2181
2182 m.setElementAt(14, 8, oDiA / norm);
2183 m.setElementAt(14, 9, oDiB / norm);
2184 m.setElementAt(14, 10, oDiC / norm);
2185 m.setElementAt(14, 11, oDiD / norm);
2186
2187 m.setElementAt(14, 12, -oCiA / norm);
2188 m.setElementAt(14, 13, -oCiB / norm);
2189 m.setElementAt(14, 14, -oCiC / norm);
2190 m.setElementAt(14, 15, -oCiD / norm);
2191 } catch (final WrongSizeException ignore) {
2192
2193 }
2194
2195
2196 Matrix v;
2197 try {
2198 final var decomposer = new SingularValueDecomposer(m);
2199 decomposer.decompose();
2200
2201
2202
2203 if (decomposer.getRank() < 15) {
2204 throw new CoincidentPlanesException();
2205 }
2206
2207 v = decomposer.getV();
2208
2209
2210 final var transInvT = new Matrix(HOM_COORDS, HOM_COORDS);
2211 transInvT.setSubmatrix(0, 0, HOM_COORDS - 1,
2212 HOM_COORDS - 1,
2213 v.getSubmatrix(0, 15, 15, 15).toArray(),
2214 false);
2215
2216 transInvT.transpose();
2217 t = Utils.inverse(transInvT);
2218
2219 normalized = false;
2220
2221 } catch (final AlgebraException e) {
2222 throw new CoincidentPlanesException(e);
2223 }
2224 }
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240 public final void setTransformationFromLines(
2241 final Line3D inputLine1, final Line3D inputLine2, final Line3D inputLine3, final Line3D outputLine1,
2242 final Line3D outputLine2, final Line3D outputLine3) throws CoincidentLinesException {
2243 try {
2244 setTransformationFromPlanes(inputLine1.getPlane1(), inputLine1.getPlane2(), inputLine2.getPlane1(),
2245 inputLine2.getPlane2(), inputLine3.getPlane1(), outputLine1.getPlane1(), outputLine1.getPlane2(),
2246 outputLine2.getPlane1(), outputLine2.getPlane2(), outputLine3.getPlane1());
2247 } catch (final CoincidentPlanesException e) {
2248 throw new CoincidentLinesException(e);
2249 }
2250 }
2251 }