Bladeren bron

mol-math: boundary helper

David Sehnal 6 jaren geleden
bovenliggende
commit
9c44cec978
3 gewijzigde bestanden met toevoegingen van 127 en 82 verwijderingen
  1. 12 5
      src/mol-gl/scene.ts
  2. 115 0
      src/mol-math/geometry/boundary-helper.ts
  3. 0 77
      src/mol-math/geometry/primitives/sphere3d.ts

+ 12 - 5
src/mol-gl/scene.ts

@@ -11,7 +11,9 @@ import { RenderObject, createRenderable } from './render-object';
 import { Object3D } from './object3d';
 import { Sphere3D } from 'mol-math/geometry';
 import { Vec3 } from 'mol-math/linear-algebra';
+import { BoundaryHelper } from 'mol-math/geometry/boundary-helper';
 
+const boundaryHelper = new BoundaryHelper();
 function calculateBoundingSphere(renderableMap: Map<RenderObject, Renderable<RenderableValues & BaseValues>>, boundingSphere: Sphere3D): Sphere3D {
     // let count = 0
     // const center = Vec3.set(boundingSphere.center, 0, 0, 0)
@@ -33,15 +35,20 @@ function calculateBoundingSphere(renderableMap: Map<RenderObject, Renderable<Ren
     // })
     // boundingSphere.radius = radius
 
-    const spheres: Sphere3D[] = [];
+    boundaryHelper.reset(0.1);
+
+    renderableMap.forEach(r => {
+        if (!r.state.visible || !r.boundingSphere.radius) return;
+        boundaryHelper.boundaryStep(r.boundingSphere.center, r.boundingSphere.radius);
+    });
+    boundaryHelper.finishIncludeStep();
     renderableMap.forEach(r => {
         if (!r.state.visible || !r.boundingSphere.radius) return;
-        spheres.push(r.boundingSphere)
+        boundaryHelper.extendStep(r.boundingSphere.center, r.boundingSphere.radius);
     });
-    const bs = Sphere3D.getBoundingSphereFromSpheres(spheres, 0.1);
 
-    Vec3.copy(boundingSphere.center, bs.center);
-    boundingSphere.radius = bs.radius;
+    Vec3.copy(boundingSphere.center, boundaryHelper.center);
+    boundingSphere.radius = boundaryHelper.radius;
 
     return boundingSphere;
 }

+ 115 - 0
src/mol-math/geometry/boundary-helper.ts

@@ -0,0 +1,115 @@
+/**
+ * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ *
+ * @author David Sehnal <david.sehnal@gmail.com>
+ */
+
+import { Vec3 } from 'mol-math/linear-algebra/3d';
+import { Box3D } from './primitives/box3d';
+import { Sphere3D } from './primitives/sphere3d';
+
+export class BoundaryHelper {
+    private count = 0;
+    private extremes = [Vec3.zero(), Vec3.zero(), Vec3.zero(), Vec3.zero(), Vec3.zero(), Vec3.zero()];
+    private u = Vec3.zero();
+    private v = Vec3.zero();
+
+    tolerance = 0;
+    center: Vec3 = Vec3.zero();
+    radius = 0;
+
+    reset(tolerance: number) {
+        Vec3.set(this.center, 0, 0, 0);
+        for (let i = 0; i < 6; i++) {
+            const e = i % 2 === 0 ? Number.MAX_VALUE : -Number.MAX_VALUE;
+            this.extremes[i] = Vec3.create(e, e, e);
+        }
+        this.radius = 0;
+        this.count = 0;
+        this.tolerance = tolerance;
+    }
+
+    boundaryStep(p: Vec3, r: number) {
+        updateExtremeMin(0, this.extremes[0], p, r);
+        updateExtremeMax(0, this.extremes[1], p, r);
+
+        updateExtremeMin(1, this.extremes[2], p, r);
+        updateExtremeMax(1, this.extremes[3], p, r);
+
+        updateExtremeMin(2, this.extremes[4], p, r);
+        updateExtremeMax(2, this.extremes[5], p, r);
+        this.count++;
+    }
+
+    finishIncludeStep() {
+        if (this.count === 0) return;
+
+        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(this.extremes[i], this.extremes[j]);
+                if (d > maxSpan) {
+                    maxSpan = d;
+                    mI = i;
+                    mJ = j;
+                }
+            }
+        }
+
+        Vec3.add(this.center, this.extremes[mI], this.extremes[mJ]);
+        Vec3.scale(this.center, this.center, 0.5);
+        this.radius = Vec3.distance(this.center, this.extremes[mI]);
+    }
+
+    extendStep(p: Vec3, r: number) {
+        const d = Vec3.distance(p, this.center);
+        if ((1 + this.tolerance) * this.radius >= r + d) return;
+
+        Vec3.sub(this.u, p, this.center);
+        Vec3.normalize(this.u, this.u);
+
+        Vec3.scale(this.v, this.u, -this.radius);
+        Vec3.add(this.v, this.v, this.center);
+        Vec3.scale(this.u, this.u, r + d);
+        Vec3.add(this.u, this.u, this.center);
+
+        Vec3.add(this.center, this.u, this.v);
+        Vec3.scale(this.center, this.center, 0.5);
+        this.radius = 0.5 * (r + d + this.radius);
+    }
+
+    getBox(): Box3D {
+        Vec3.copy(this.u, this.extremes[0]);
+        Vec3.copy(this.v, this.extremes[0]);
+
+        for (let i = 1; i < 6; i++) {
+            Vec3.min(this.u, this.u, this.extremes[i]);
+            Vec3.max(this.v, this.v, this.extremes[i]);
+        }
+
+        return { min: Vec3.clone(this.u), max: Vec3.clone(this.v) };
+    }
+
+    getSphere(): Sphere3D {
+        return { center: Vec3.clone(this.center), radius: this.radius };
+    }
+
+    constructor() {
+        this.reset(0);
+    }
+}
+
+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;
+    }
+}

+ 0 - 77
src/mol-math/geometry/primitives/sphere3d.ts

@@ -96,83 +96,6 @@ 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 }