Bladeren bron

mol-model: use boundary helper

David Sehnal 6 jaren geleden
bovenliggende
commit
f72d70b7c1

+ 1 - 1
src/mol-gl/scene.ts

@@ -41,7 +41,7 @@ function calculateBoundingSphere(renderableMap: Map<RenderObject, Renderable<Ren
         if (!r.state.visible || !r.boundingSphere.radius) return;
         boundaryHelper.boundaryStep(r.boundingSphere.center, r.boundingSphere.radius);
     });
-    boundaryHelper.finishIncludeStep();
+    boundaryHelper.finishBoundaryStep();
     renderableMap.forEach(r => {
         if (!r.state.visible || !r.boundingSphere.radius) return;
         boundaryHelper.extendStep(r.boundingSphere.center, r.boundingSphere.radius);

+ 10 - 1
src/mol-math/geometry/boundary-helper.ts

@@ -8,6 +8,15 @@ import { Vec3 } from 'mol-math/linear-algebra/3d';
 import { Box3D } from './primitives/box3d';
 import { Sphere3D } from './primitives/sphere3d';
 
+/**
+ * Usage:
+ *
+ * 1. .reset(tolerance); tolerance plays part in the "extend" step
+ * 2. for each point/sphere call boundaryStep()
+ * 3. .finishBoundaryStep
+ * 4. for each point/sphere call extendStep
+ * 5. use .center/.radius or call getSphere/getBox
+ */
 export class BoundaryHelper {
     private count = 0;
     private extremes = [Vec3.zero(), Vec3.zero(), Vec3.zero(), Vec3.zero(), Vec3.zero(), Vec3.zero()];
@@ -41,7 +50,7 @@ export class BoundaryHelper {
         this.count++;
     }
 
-    finishIncludeStep() {
+    finishBoundaryStep() {
         if (this.count === 0) return;
 
         let maxSpan = 0, mI = 0, mJ = 0;

+ 22 - 2
src/mol-math/geometry/lookup3d/grid.ts

@@ -11,6 +11,7 @@ import { Sphere3D } from '../primitives/sphere3d';
 import { PositionData } from '../common';
 import { Vec3 } from '../../linear-algebra';
 import { OrderedSet } from 'mol-data/int';
+import { BoundaryHelper } from '../boundary-helper';
 
 interface GridLookup3D<T = number> extends Lookup3D<T> {
     readonly buckets: { readonly offset: ArrayLike<number>, readonly count: ArrayLike<number>, readonly array: ArrayLike<number> }
@@ -163,11 +164,30 @@ function _build(state: BuildState): Grid3D {
     }
 }
 
+const boundaryHelper = new BoundaryHelper();
+function getBoundary(data: PositionData) {
+    const { x, y, z, radius, indices } = data;
+    const p = Vec3.zero();
+    boundaryHelper.reset(0);
+    for (let t = 0, _t = OrderedSet.size(indices); t < _t; t++) {
+        const i = OrderedSet.getAt(indices, t);
+        Vec3.set(p, x[i], y[i], z[i]);
+        boundaryHelper.boundaryStep(p, (radius && radius[i]) || 0);
+    }
+    boundaryHelper.finishBoundaryStep();
+    for (let t = 0, _t = OrderedSet.size(indices); t < _t; t++) {
+        const i = OrderedSet.getAt(indices, t);
+        Vec3.set(p, x[i], y[i], z[i]);
+        boundaryHelper.extendStep(p, (radius && radius[i]) || 0);
+    }
+
+    return { boundingBox: boundaryHelper.getBox(), boundingSphere: boundaryHelper.getSphere() };
+}
+
 function build(data: PositionData, cellSize?: Vec3) {
-    const boundingBox = Box3D.computeBounding(data);
+    const { boundingBox, boundingSphere } = getBoundary(data);
     // need to expand the grid bounds to avoid rounding errors
     const expandedBox = Box3D.expand(Box3D.empty(), boundingBox, Vec3.create(0.5, 0.5, 0.5));
-    const boundingSphere = Sphere3D.computeBounding(data);
     const { indices } = data;
 
     const S = Vec3.sub(Vec3.zero(), expandedBox.max, expandedBox.min);

+ 35 - 77
src/mol-model/structure/structure/util/boundary.ts

@@ -5,102 +5,60 @@
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
  */
 
-import Structure from '../structure'
-import Unit from '../unit';
-import { Box3D, Sphere3D, SymmetryOperator } from 'mol-math/geometry';
+import { Box3D, Sphere3D } from 'mol-math/geometry';
+import { BoundaryHelper } from 'mol-math/geometry/boundary-helper';
 import { Vec3 } from 'mol-math/linear-algebra';
-import { SortedArray } from 'mol-data/int';
-import { ElementIndex } from '../../model/indexing';
+import Structure from '../structure';
 
 export type Boundary = { box: Box3D, sphere: Sphere3D }
 
-function computeElementsPositionBoundary(elements: SortedArray<ElementIndex>, position: SymmetryOperator.CoordinateMapper): Boundary {
-    const min = Vec3.create(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE)
-    const max = Vec3.create(-Number.MAX_VALUE, -Number.MAX_VALUE, -Number.MAX_VALUE)
-    const center = Vec3.zero()
-
-    let radiusSq = 0
-    let size = 0
-
-    const p = Vec3.zero()
-
-    size += elements.length
-    for (let j = 0, _j = elements.length; j < _j; j++) {
-        position(elements[j], p)
-        Vec3.min(min, min, p)
-        Vec3.max(max, max, p)
-        Vec3.add(center, center, p)
-    }
-
-    if (size > 0) Vec3.scale(center, center, 1/size)
-
-    for (let j = 0, _j = elements.length; j < _j; j++) {
-        position(elements[j], p)
-        const d = Vec3.squaredDistance(p, center)
-        if (d > radiusSq) radiusSq = d
-    }
-
-    return {
-        box: { min, max },
-        sphere: { center, radius: Math.sqrt(radiusSq) }
-    }
-}
-
-function computeInvariantUnitBoundary(u: Unit): Boundary {
-    return computeElementsPositionBoundary(u.elements, u.conformation.invariantPosition)
-}
-
-export function computeUnitBoundary(u: Unit): Boundary {
-    return computeElementsPositionBoundary(u.elements, u.conformation.position)
-}
-
 const tmpBox = Box3D.empty()
 const tmpSphere = Sphere3D.zero()
 
+const boundaryHelper = new BoundaryHelper();
+
 export function computeStructureBoundary(s: Structure): Boundary {
     const min = Vec3.create(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE)
     const max = Vec3.create(-Number.MAX_VALUE, -Number.MAX_VALUE, -Number.MAX_VALUE)
-    const center = Vec3.zero()
 
-    const { units } = s
+    const { units } = s;
+
+    boundaryHelper.reset(0);
+
+    for (let i = 0, _i = units.length; i < _i; i++) {
+        const u = units[i];
+        const invariantBoundary = u.lookup3d.boundary;
+        const o = u.conformation.operator;
+
+        if (o.isIdentity) {
+            Vec3.min(min, min, invariantBoundary.box.min);
+            Vec3.max(max, max, invariantBoundary.box.max);
 
-    const boundaryMap: Map<number, Boundary> = new Map()
-    function getInvariantBoundary(u: Unit) {
-        let boundary: Boundary
-        if (boundaryMap.has(u.invariantId)) {
-            boundary = boundaryMap.get(u.invariantId)!
+            boundaryHelper.boundaryStep(invariantBoundary.sphere.center, invariantBoundary.sphere.radius);
         } else {
-            boundary = computeInvariantUnitBoundary(u)
-            boundaryMap.set(u.invariantId, boundary)
+            Box3D.transform(tmpBox, invariantBoundary.box, o.matrix);
+            Vec3.min(min, min, tmpBox.min);
+            Vec3.max(max, max, tmpBox.max);
+
+            Sphere3D.transform(tmpSphere, invariantBoundary.sphere, o.matrix);
+            boundaryHelper.boundaryStep(tmpSphere.center, tmpSphere.radius);
         }
-        return boundary
     }
 
-    let radius = 0
-    let size = 0
+    boundaryHelper.finishBoundaryStep();
 
     for (let i = 0, _i = units.length; i < _i; i++) {
-        const u = units[i]
-        const invariantBoundary = getInvariantBoundary(u)
-        const m = u.conformation.operator.matrix
-        size += u.elements.length
-        Box3D.transform(tmpBox, invariantBoundary.box, m)
-        Vec3.min(min, min, tmpBox.min)
-        Vec3.max(max, max, tmpBox.max)
-        Sphere3D.transform(tmpSphere, invariantBoundary.sphere, m)
-        Vec3.scaleAndAdd(center, center, tmpSphere.center, u.elements.length)
-    }
-
-    if (size > 0) Vec3.scale(center, center, 1/size)
+        const u = units[i];
+        const invariantBoundary = u.lookup3d.boundary;
+        const o = u.conformation.operator;
 
-    for (let i = 0, _i = units.length; i < _i; i++) {
-        const u = units[i]
-        const invariantBoundary = getInvariantBoundary(u)
-        const m = u.conformation.operator.matrix
-        Sphere3D.transform(tmpSphere, invariantBoundary.sphere, m)
-        const d = Vec3.distance(tmpSphere.center, center) + tmpSphere.radius
-        if (d > radius) radius = d
+        if (o.isIdentity) {
+            boundaryHelper.extendStep(invariantBoundary.sphere.center, invariantBoundary.sphere.radius);
+        } else {
+            Sphere3D.transform(tmpSphere, invariantBoundary.sphere, o.matrix);
+            boundaryHelper.extendStep(tmpSphere.center, tmpSphere.radius);
+        }
     }
 
-    return { box: { min, max }, sphere: { center, radius } }
+    return { box: { min, max }, sphere: boundaryHelper.getSphere() };
 }