|
@@ -96,6 +96,83 @@ namespace Sphere3D {
|
|
|
return (Math.abs(ar - br) <= EPSILON.Value * Math.max(1.0, Math.abs(ar), Math.abs(br)) &&
|
|
|
Vec3.equals(a.center, b.center));
|
|
|
}
|
|
|
+
|
|
|
+ function updateExtremeMin(d: number, e: Vec3, center: Vec3, r: number) {
|
|
|
+ if (center[d] - r < e[d]) {
|
|
|
+ Vec3.copy(e, center);
|
|
|
+ e[d] -= r;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ function updateExtremeMax(d: number, e: Vec3, center: Vec3, r: number) {
|
|
|
+ if (center[d] + r > e[d]) {
|
|
|
+ Vec3.copy(e, center);
|
|
|
+ e[d] += r;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ export function getBoundingSphereFromSpheres(spheres: Sphere3D[], tolerance: number): Sphere3D {
|
|
|
+ if (spheres.length === 0) {
|
|
|
+ return { center: Vec3.zero(), radius: 0.1 };
|
|
|
+ }
|
|
|
+
|
|
|
+ const extremes: Vec3[] = [];
|
|
|
+ for (let i = 0; i < 6; i++) {
|
|
|
+ const e = i % 2 === 0 ? Number.MAX_VALUE : -Number.MAX_VALUE;
|
|
|
+ extremes[i] = Vec3.create(e, e, e);
|
|
|
+ }
|
|
|
+ const u = Vec3.zero(), v = Vec3.zero();
|
|
|
+
|
|
|
+ let m = 0;
|
|
|
+ for (const s of spheres) {
|
|
|
+ updateExtremeMin(0, extremes[0], s.center, s.radius);
|
|
|
+ updateExtremeMax(0, extremes[1], s.center, s.radius);
|
|
|
+
|
|
|
+ updateExtremeMin(1, extremes[2], s.center, s.radius);
|
|
|
+ updateExtremeMax(1, extremes[3], s.center, s.radius);
|
|
|
+
|
|
|
+ updateExtremeMin(2, extremes[4], s.center, s.radius);
|
|
|
+ updateExtremeMax(2, extremes[5], s.center, s.radius);
|
|
|
+ if (s.radius > m) m = s.radius;
|
|
|
+ }
|
|
|
+
|
|
|
+ let maxSpan = 0, mI = 0, mJ = 0;
|
|
|
+
|
|
|
+ for (let i = 0; i < 5; i++) {
|
|
|
+ for (let j = i + 1; j < 6; j++) {
|
|
|
+ const d = Vec3.squaredDistance(extremes[i], extremes[j]);
|
|
|
+ if (d > maxSpan) {
|
|
|
+ maxSpan = d;
|
|
|
+ mI = i;
|
|
|
+ mJ = j;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ const center = Vec3.zero();
|
|
|
+ Vec3.add(center, extremes[mI], extremes[mJ]);
|
|
|
+ Vec3.scale(center, center, 0.5);
|
|
|
+ let radius = Vec3.distance(center, extremes[mI]);
|
|
|
+
|
|
|
+ for (const s of spheres) {
|
|
|
+ const d = Vec3.distance(s.center, center);
|
|
|
+ if ((1 + tolerance) * radius >= s.radius + d) continue;
|
|
|
+
|
|
|
+ Vec3.sub(u, s.center, center);
|
|
|
+ Vec3.normalize(u, u);
|
|
|
+
|
|
|
+ Vec3.scale(v, u, -radius);
|
|
|
+ Vec3.add(v, v, center);
|
|
|
+ Vec3.scale(u, u, s.radius + d);
|
|
|
+ Vec3.add(u, u, center);
|
|
|
+
|
|
|
+ Vec3.add(center, u, v);
|
|
|
+ Vec3.scale(center, center, 0.5);
|
|
|
+ radius = Vec3.distance(center, u);
|
|
|
+ }
|
|
|
+
|
|
|
+ return { center, radius };
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
export { Sphere3D }
|