1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.geometry.enclosing.euclidean.threed;
18
19 import java.util.Arrays;
20 import java.util.Collections;
21 import java.util.List;
22
23 import org.apache.commons.geometry.core.precision.DoublePrecisionContext;
24 import org.apache.commons.geometry.enclosing.EnclosingBall;
25 import org.apache.commons.geometry.enclosing.SupportBallGenerator;
26 import org.apache.commons.geometry.enclosing.euclidean.twod.DiskGenerator;
27 import org.apache.commons.geometry.euclidean.threed.EmbeddingPlane;
28 import org.apache.commons.geometry.euclidean.threed.Planes;
29 import org.apache.commons.geometry.euclidean.threed.Vector3D;
30 import org.apache.commons.geometry.euclidean.twod.Vector2D;
31 import org.apache.commons.numbers.fraction.BigFraction;
32
33
34
35 public class SphereGenerator implements SupportBallGenerator<Vector3D> {
36
37
38 private final DoublePrecisionContext precision;
39
40
41
42
43 public SphereGenerator(final DoublePrecisionContext precision) {
44 this.precision = precision;
45 }
46
47
48 @Override
49 public EnclosingBall<Vector3D> ballOnSupport(final List<Vector3D> support) {
50 if (support.isEmpty()) {
51 return new EnclosingBall<>(Vector3D.ZERO, Double.NEGATIVE_INFINITY, Collections.emptyList());
52 }
53 final Vector3D vA = support.get(0);
54 if (support.size() < 2) {
55 return new EnclosingBall<>(vA, 0, Collections.singletonList(vA));
56 }
57 final Vector3D vB = support.get(1);
58 if (support.size() < 3) {
59 return new EnclosingBall<>(Vector3D.linearCombination(0.5, vA, 0.5, vB),
60 0.5 * vA.distance(vB),
61 Arrays.asList(vA, vB));
62 }
63 final Vector3D vC = support.get(2);
64 if (support.size() < 4) {
65 final EmbeddingPlane p = Planes.fromPoints(vA, vB, vC, precision).getEmbedding();
66 final EnclosingBall<Vector2D> disk =
67 new DiskGenerator().ballOnSupport(Arrays.asList(p.toSubspace(vA),
68 p.toSubspace(vB),
69 p.toSubspace(vC)));
70
71
72 return new EnclosingBall<>(p.toSpace(disk.getCenter()),
73 disk.getRadius(),
74 Arrays.asList(vA, vB, vC));
75
76 }
77 final Vector3D vD = support.get(3);
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101 final BigFraction[] c2 = {
102 BigFraction.from(vA.getX()), BigFraction.from(vB.getX()),
103 BigFraction.from(vC.getX()), BigFraction.from(vD.getX())
104 };
105 final BigFraction[] c3 = {
106 BigFraction.from(vA.getY()), BigFraction.from(vB.getY()),
107 BigFraction.from(vC.getY()), BigFraction.from(vD.getY())
108 };
109 final BigFraction[] c4 = {
110 BigFraction.from(vA.getZ()), BigFraction.from(vB.getZ()),
111 BigFraction.from(vC.getZ()), BigFraction.from(vD.getZ())
112 };
113 final BigFraction[] c1 = {
114 c2[0].multiply(c2[0]).add(c3[0].multiply(c3[0])).add(c4[0].multiply(c4[0])),
115 c2[1].multiply(c2[1]).add(c3[1].multiply(c3[1])).add(c4[1].multiply(c4[1])),
116 c2[2].multiply(c2[2]).add(c3[2].multiply(c3[2])).add(c4[2].multiply(c4[2])),
117 c2[3].multiply(c2[3]).add(c3[3].multiply(c3[3])).add(c4[3].multiply(c4[3]))
118 };
119 final BigFraction twoM11 = minor(c2, c3, c4).multiply(2);
120 final BigFraction m12 = minor(c1, c3, c4);
121 final BigFraction m13 = minor(c1, c2, c4);
122 final BigFraction m14 = minor(c1, c2, c3);
123 final BigFraction centerX = m12.divide(twoM11);
124 final BigFraction centerY = m13.divide(twoM11).negate();
125 final BigFraction centerZ = m14.divide(twoM11);
126 final BigFraction dx = c2[0].subtract(centerX);
127 final BigFraction dy = c3[0].subtract(centerY);
128 final BigFraction dz = c4[0].subtract(centerZ);
129 final BigFraction r2 = dx.multiply(dx).add(dy.multiply(dy)).add(dz.multiply(dz));
130 return new EnclosingBall<>(Vector3D.of(centerX.doubleValue(),
131 centerY.doubleValue(),
132 centerZ.doubleValue()),
133 Math.sqrt(r2.doubleValue()),
134 Arrays.asList(vA, vB, vC, vD));
135 }
136
137
138
139
140
141
142
143 private BigFraction minor(final BigFraction[] c1, final BigFraction[] c2, final BigFraction[] c3) {
144 return c2[0].multiply(c3[1]).multiply(c1[2].subtract(c1[3])).
145 add(c2[0].multiply(c3[2]).multiply(c1[3].subtract(c1[1]))).
146 add(c2[0].multiply(c3[3]).multiply(c1[1].subtract(c1[2]))).
147 add(c2[1].multiply(c3[0]).multiply(c1[3].subtract(c1[2]))).
148 add(c2[1].multiply(c3[2]).multiply(c1[0].subtract(c1[3]))).
149 add(c2[1].multiply(c3[3]).multiply(c1[2].subtract(c1[0]))).
150 add(c2[2].multiply(c3[0]).multiply(c1[1].subtract(c1[3]))).
151 add(c2[2].multiply(c3[1]).multiply(c1[3].subtract(c1[0]))).
152 add(c2[2].multiply(c3[3]).multiply(c1[0].subtract(c1[1]))).
153 add(c2[3].multiply(c3[0]).multiply(c1[2].subtract(c1[1]))).
154 add(c2[3].multiply(c3[1]).multiply(c1[0].subtract(c1[2]))).
155 add(c2[3].multiply(c3[2]).multiply(c1[1].subtract(c1[0])));
156 }
157 }