Prechádzať zdrojové kódy

boundary calculation optimizations

- fast path for single transform renderables
- check conformation when remapping unit
Alexander Rose 4 rokov pred
rodič
commit
51c180a8f4

+ 9 - 1
src/mol-gl/renderable/util.ts

@@ -5,7 +5,7 @@
  */
 
 import { Sphere3D } from '../../mol-math/geometry';
-import { Vec3 } from '../../mol-math/linear-algebra';
+import { Vec3, Mat4 } from '../../mol-math/linear-algebra';
 import { BoundaryHelper } from '../../mol-math/geometry/boundary-helper';
 
 export function calculateTextureInfo (n: number, itemSize: number) {
@@ -118,7 +118,15 @@ export function calculateInvariantBoundingSphere(position: Float32Array, positio
     return sphere;
 }
 
+const _mat4 = Mat4();
+
 export function calculateTransformBoundingSphere(invariantBoundingSphere: Sphere3D, transform: Float32Array, transformCount: number): Sphere3D {
+    if (transformCount === 1) {
+        Mat4.fromArray(_mat4, transform, 0);
+        const s = Sphere3D.clone(invariantBoundingSphere);
+        return Mat4.isIdentity(_mat4) ? s : Sphere3D.transform(s, s, _mat4);
+    }
+
     const boundaryHelper = getHelper(transformCount);
     boundaryHelper.reset();
 

+ 6 - 1
src/mol-math/geometry/boundary.ts

@@ -10,6 +10,7 @@ import { Vec3 } from '../linear-algebra';
 import { OrderedSet } from '../../mol-data/int';
 import { BoundaryHelper } from './boundary-helper';
 import { Box3D, Sphere3D } from '../geometry';
+import { EPSILON } from '../linear-algebra/3d/common';
 
 export type Boundary = { readonly box: Box3D, readonly sphere: Sphere3D }
 
@@ -72,7 +73,11 @@ export function tryAdjustBoundary(data: PositionData, boundary: Boundary): Bound
 
     const adjustedRadius = Math.sqrt(maxDistSq);
     const deltaRadius = adjustedRadius - radius;
-    if (Math.abs(deltaRadius) < (radius / 100) * 5) {
+    const absDeltaRadius = Math.abs(deltaRadius);
+
+    if (absDeltaRadius < EPSILON) {
+        return boundary;
+    } else if (absDeltaRadius < (radius / 100) * 5) {
         // TODO: The expanded sphere extrema are not correct if the principal axes differ
         const sphere = Sphere3D.expand(Sphere3D(), boundary.sphere, deltaRadius);
         const box = Box3D.fromSphere3D(Box3D(), sphere);

+ 22 - 18
src/mol-model/structure/structure/unit.ts

@@ -67,6 +67,14 @@ namespace Unit {
         return unitIndexMap;
     }
 
+    function getTransformHash(units: Unit[]) {
+        const ids: number[] = [];
+        for (let i = 0, _i = units.length; i < _i; i++) {
+            ids.push(units[i].id);
+        }
+        return hashFnv32a(ids);
+    }
+
     export function SymmetryGroup(units: Unit[]) {
         const props: {
             unitIndexMap?: IntMap<number>
@@ -81,7 +89,7 @@ namespace Unit {
                 return props.unitIndexMap;
             },
             hashCode: hashUnit(units[0]),
-            transformHash: hashFnv32a(units.map(u => u.id))
+            transformHash: getTransformHash(units)
         };
     }
 
@@ -207,8 +215,8 @@ namespace Unit {
 
         remapModel(model: Model) {
             let boundary = this.props.boundary;
-            if (boundary) {
-                const { x, y, z } = this.model.atomicConformation;
+            if (boundary && !Unit.isSameConformation(this, model)) {
+                const { x, y, z } = model.atomicConformation;
                 boundary = tryAdjustBoundary({ x, y, z, indices: this.elements }, boundary);
             }
             const props = { ...this.props, bonds: tryRemapBonds(this, this.props.bonds, model), boundary, lookup3d: undefined, principalAxes: undefined };
@@ -357,24 +365,16 @@ namespace Unit {
 
         remapModel(model: Model): Unit.Spheres | Unit.Gaussians {
             const coarseConformation = this.getCoarseConformation();
+            const modelCoarseConformation = getCoarseConformation(this.kind, model);
             let boundary = this.props.boundary;
             if (boundary) {
-                const { x, y, z } = coarseConformation;
+                const { x, y, z } = modelCoarseConformation;
                 boundary = tryAdjustBoundary({ x, y, z, indices: this.elements }, boundary);
             }
             const props = { ...this.props, boundary, lookup3d: undefined, principalAxes: undefined };
-            let conformation: SymmetryOperator.ArrayMapping<ElementIndex>;
-            if (this.kind === Kind.Spheres) {
-                conformation = coarseConformation !== model.coarseConformation.spheres
-                    ? SymmetryOperator.createMapping(this.conformation.operator, coarseConformation)
-                    : this.conformation;
-            } else if (this.kind === Kind.Gaussians) {
-                conformation = coarseConformation !== model.coarseConformation.gaussians
-                    ? SymmetryOperator.createMapping(this.conformation.operator, coarseConformation)
-                    : this.conformation;
-            } else {
-                throw new Error('unexpected unit kind');
-            }
+            const conformation = coarseConformation !== modelCoarseConformation
+                ? SymmetryOperator.createMapping(this.conformation.operator, modelCoarseConformation)
+                : this.conformation;
             return new Coarse(this.id, this.invariantId, this.chainGroupId, this.traits, model, this.kind, this.elements, conformation, props) as Unit.Spheres | Unit.Gaussians; // TODO get rid of casting
         }
 
@@ -413,7 +413,7 @@ namespace Unit {
         }
 
         private getCoarseConformation() {
-            return this.kind === Kind.Spheres ? this.model.coarseConformation.spheres : this.model.coarseConformation.gaussians;
+            return getCoarseConformation(this.kind, this.model);
         }
 
         constructor(id: number, invariantId: number, chainGroupId: number, traits: Traits, model: Model, kind: K, elements: StructureElement.Set, conformation: SymmetryOperator.ArrayMapping<ElementIndex>, props: CoarseProperties) {
@@ -432,6 +432,10 @@ namespace Unit {
         }
     }
 
+    function getCoarseConformation(kind: Kind, model: Model) {
+        return kind === Kind.Spheres ? model.coarseConformation.spheres : model.coarseConformation.gaussians;
+    }
+
     interface CoarseProperties extends BaseProperties { }
 
     function CoarseProperties(props?: CoarseProperties): CoarseProperties {
@@ -485,7 +489,7 @@ namespace Unit {
         return isSameConformation(a, model) ? old : void 0;
     }
 
-    function isSameConformation(a: Atomic, model: Model) {
+    export function isSameConformation(a: Atomic, model: Model) {
         const xs = a.elements;
         const { x: xa, y: ya, z: za } = a.conformation.coordinates;
         const { x: xb, y: yb, z: zb } = model.atomicConformation;