Browse Source

improve Sphere3D.expand & Box3D.fromSphere3D

- ensure extrema are within radius
- avoid degenerate box for low number of points
Alexander Rose 3 years ago
parent
commit
5128d0f405

+ 3 - 1
src/mol-math/geometry/primitives/box3d.ts

@@ -32,7 +32,9 @@ namespace Box3D {
 
     /** Get box from sphere, uses extrema if available */
     export function fromSphere3D(out: Box3D, sphere: Sphere3D): Box3D {
-        if (Sphere3D.hasExtrema(sphere)) return fromVec3Array(out, sphere.extrema);
+        if (Sphere3D.hasExtrema(sphere) && sphere.extrema.length >= 14) { // 14 extrema with coarse boundary helper
+            return fromVec3Array(out, sphere.extrema);
+        }
         const r = Vec3.create(sphere.radius, sphere.radius, sphere.radius);
         Vec3.sub(out.min, sphere.center, r);
         Vec3.add(out.max, sphere.center, r);

+ 13 - 6
src/mol-math/geometry/primitives/sphere3d.ts

@@ -212,19 +212,26 @@ namespace Sphere3D {
             Axes3D.scale(axes, Axes3D.normalize(axes, axes), delta);
 
             setExtrema(out, sphere.extrema.map(e => {
-                Vec3.sub(tmpDir, e, sphere.center);
-                const out = Vec3.clone(e);
+                Vec3.normalize(tmpDir, Vec3.sub(tmpDir, e, sphere.center));
+                const o = Vec3.clone(e);
 
                 const sA = Vec3.dot(tmpDir, axes.dirA) < 0 ? -1 : 1;
-                Vec3.scaleAndAdd(out, out, axes.dirA, sA);
+                Vec3.scaleAndAdd(o, o, axes.dirA, sA);
 
                 const sB = Vec3.dot(tmpDir, axes.dirB) < 0 ? -1 : 1;
-                Vec3.scaleAndAdd(out, out, axes.dirB, sB);
+                Vec3.scaleAndAdd(o, o, axes.dirB, sB);
 
                 const sC = Vec3.dot(tmpDir, axes.dirC) < 0 ? -1 : 1;
-                Vec3.scaleAndAdd(out, out, axes.dirC, sC);
+                Vec3.scaleAndAdd(o, o, axes.dirC, sC);
 
-                return out;
+                if (Vec3.distance(out.center, o) > out.radius) {
+                    if (sphere.extrema.length >= 14) { // 14 extrema with coarse boundary helper
+                        Vec3.normalize(tmpDir, Vec3.sub(tmpDir, o, sphere.center));
+                    }
+                    Vec3.scaleAndAdd(o, out.center, tmpDir, out.radius);
+                }
+
+                return o;
             }));
         }
         return out;