Browse Source

Merge pull request #692 from molstar/misc2

Misc2
Alexander Rose 2 years ago
parent
commit
b5e45aae95

+ 5 - 0
CHANGELOG.md

@@ -17,7 +17,12 @@ Note that since we don't clearly distinguish between a public and private interf
     - Update clip `defines` only when changed
     - Check for identity in structure/unit areEqual methods
     - Avoid cloning of structure representation parameters
+    - Make SymmetryOperator.createMapping monomorphic
+    - Improve bonding-sphere calculation
+    - Defer Scene properties calculation (markerAverage, opacityAverage, hasOpaque)
+    - Improve checks in in UnitsRepresentation setVisualState
 - Add StructureElement.Loci.forEachLocation
+- Add RepresentationRegistry.clear and ThemeRegistry.clear
 
 ## [v3.28.0] - 2022-12-20
 

+ 14 - 10
src/mol-gl/renderable/util.ts

@@ -1,5 +1,5 @@
 /**
- * Copyright (c) 2018-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ * Copyright (c) 2018-2023 mol* contributors, licensed under MIT, See LICENSE file for more info.
  *
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
  */
@@ -10,6 +10,10 @@ import { BoundaryHelper } from '../../mol-math/geometry/boundary-helper';
 import { TextureFilter } from '../webgl/texture';
 import { arrayMinMax } from '../../mol-util/array';
 
+// avoiding namespace lookup improved performance in Chrome (Aug 2020)
+const v3fromArray = Vec3.fromArray;
+const v3transformMat4Offset = Vec3.transformMat4Offset;
+
 export function calculateTextureInfo(n: number, itemSize: number) {
     n = Math.max(n, 2); // observed issues with 1 pixel textures
     const sqN = Math.sqrt(n);
@@ -137,21 +141,21 @@ export function calculateInvariantBoundingSphere(position: Float32Array, positio
 
     boundaryHelper.reset();
     for (let i = 0, _i = positionCount * 3; i < _i; i += step) {
-        Vec3.fromArray(v, position, i);
+        v3fromArray(v, position, i);
         boundaryHelper.includePosition(v);
     }
     boundaryHelper.finishedIncludeStep();
     for (let i = 0, _i = positionCount * 3; i < _i; i += step) {
-        Vec3.fromArray(v, position, i);
+        v3fromArray(v, position, i);
         boundaryHelper.radiusPosition(v);
     }
 
     const sphere = boundaryHelper.getSphere();
 
-    if (positionCount <= 98) {
+    if (positionCount <= 14) {
         const extrema: Vec3[] = [];
         for (let i = 0, _i = positionCount * 3; i < _i; i += step) {
-            extrema.push(Vec3.fromArray(Vec3(), position, i));
+            extrema.push(v3fromArray(Vec3(), position, i));
         }
         Sphere3D.setExtrema(sphere, extrema);
     }
@@ -174,28 +178,28 @@ export function calculateTransformBoundingSphere(invariantBoundingSphere: Sphere
     const { center, radius, extrema } = invariantBoundingSphere;
 
     // only use extrema if there are not too many transforms
-    if (extrema && transformCount < 50) {
+    if (extrema && transformCount <= 14) {
         for (let i = 0, _i = transformCount; i < _i; ++i) {
             for (const e of extrema) {
-                Vec3.transformMat4Offset(v, e, transform, 0, 0, i * 16);
+                v3transformMat4Offset(v, e, transform, 0, 0, i * 16);
                 boundaryHelper.includePosition(v);
             }
         }
         boundaryHelper.finishedIncludeStep();
         for (let i = 0, _i = transformCount; i < _i; ++i) {
             for (const e of extrema) {
-                Vec3.transformMat4Offset(v, e, transform, 0, 0, i * 16);
+                v3transformMat4Offset(v, e, transform, 0, 0, i * 16);
                 boundaryHelper.radiusPosition(v);
             }
         }
     } else {
         for (let i = 0, _i = transformCount; i < _i; ++i) {
-            Vec3.transformMat4Offset(v, center, transform, 0, 0, i * 16);
+            v3transformMat4Offset(v, center, transform, 0, 0, i * 16);
             boundaryHelper.includePositionRadius(v, radius);
         }
         boundaryHelper.finishedIncludeStep();
         for (let i = 0, _i = transformCount; i < _i; ++i) {
-            Vec3.transformMat4Offset(v, center, transform, 0, 0, i * 16);
+            v3transformMat4Offset(v, center, transform, 0, 0, i * 16);
             boundaryHelper.radiusPositionRadius(v, radius);
         }
     }

+ 26 - 10
src/mol-gl/scene.ts

@@ -1,5 +1,5 @@
 /**
- * Copyright (c) 2018-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ * Copyright (c) 2018-2023 mol* contributors, licensed under MIT, See LICENSE file for more info.
  *
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
  * @author David Sehnal <david.sehnal@gmail.com>
@@ -105,6 +105,10 @@ namespace Scene {
         let boundingSphereDirty = true;
         let boundingSphereVisibleDirty = true;
 
+        let markerAverageDirty = true;
+        let opacityAverageDirty = true;
+        let hasOpaqueDirty = true;
+
         let markerAverage = 0;
         let opacityAverage = 0;
         let hasOpaque = false;
@@ -165,9 +169,9 @@ namespace Scene {
             }
 
             renderables.sort(renderableSort);
-            markerAverage = calculateMarkerAverage();
-            opacityAverage = calculateOpacityAverage();
-            hasOpaque = calculateHasOpaque();
+            markerAverageDirty = true;
+            opacityAverageDirty = true;
+            hasOpaqueDirty = true;
             return true;
         }
 
@@ -189,9 +193,9 @@ namespace Scene {
             const newVisibleHash = computeVisibleHash();
             if (newVisibleHash !== visibleHash) {
                 boundingSphereVisibleDirty = true;
-                markerAverage = calculateMarkerAverage();
-                opacityAverage = calculateOpacityAverage();
-                hasOpaque = calculateHasOpaque();
+                markerAverageDirty = true;
+                opacityAverageDirty = true;
+                hasOpaqueDirty = true;
                 visibleHash = newVisibleHash;
                 return true;
             } else {
@@ -268,9 +272,9 @@ namespace Scene {
                 } else {
                     syncVisibility();
                 }
-                markerAverage = calculateMarkerAverage();
-                opacityAverage = calculateOpacityAverage();
-                hasOpaque = calculateHasOpaque();
+                markerAverageDirty = true;
+                opacityAverageDirty = true;
+                hasOpaqueDirty = true;
             },
             add: (o: GraphicsRenderObject) => commitQueue.add(o),
             remove: (o: GraphicsRenderObject) => commitQueue.remove(o),
@@ -311,12 +315,24 @@ namespace Scene {
                 return boundingSphereVisible;
             },
             get markerAverage() {
+                if (markerAverageDirty) {
+                    markerAverage = calculateMarkerAverage();
+                    markerAverageDirty = false;
+                }
                 return markerAverage;
             },
             get opacityAverage() {
+                if (opacityAverageDirty) {
+                    opacityAverage = calculateOpacityAverage();
+                    opacityAverageDirty = false;
+                }
                 return opacityAverage;
             },
             get hasOpaque() {
+                if (hasOpaqueDirty) {
+                    hasOpaque = calculateHasOpaque();
+                    hasOpaqueDirty = false;
+                }
                 return hasOpaque;
             },
         };

+ 6 - 4
src/mol-math/geometry/boundary-helper.ts

@@ -1,5 +1,5 @@
 /**
- * Copyright (c) 2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ * Copyright (c) 2020-2023 mol* contributors, licensed under MIT, See LICENSE file for more info.
  *
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
  */
@@ -13,6 +13,7 @@ import { Box3D } from './primitives/box3d';
 
 export class BoundaryHelper {
     private dir: Vec3[];
+    private dirLength: number;
 
     private minDist: number[] = [];
     private maxDist: number[] = [];
@@ -56,13 +57,13 @@ export class BoundaryHelper {
     }
 
     includePosition(p: Vec3) {
-        for (let i = 0, il = this.dir.length; i < il; ++i) {
+        for (let i = 0; i < this.dirLength; ++i) {
             this.computeExtrema(i, p);
         }
     }
 
     includePositionRadius(center: Vec3, radius: number) {
-        for (let i = 0, il = this.dir.length; i < il; ++i) {
+        for (let i = 0; i < this.dirLength; ++i) {
             this.computeSphereExtrema(i, center, radius);
         }
     }
@@ -101,7 +102,7 @@ export class BoundaryHelper {
     }
 
     reset() {
-        for (let i = 0, il = this.dir.length; i < il; ++i) {
+        for (let i = 0; i < this.dirLength; ++i) {
             this.minDist[i] = Infinity;
             this.maxDist[i] = -Infinity;
             this.extrema[i * 2] = Vec3();
@@ -112,6 +113,7 @@ export class BoundaryHelper {
 
     constructor(quality: EposQuality) {
         this.dir = getEposDir(quality);
+        this.dirLength = this.dir.length;
         this.reset();
     }
 }

+ 9 - 5
src/mol-math/geometry/symmetry-operator.ts

@@ -1,5 +1,5 @@
 /**
- * Copyright (c) 2017-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ * Copyright (c) 2017-2023 mol* contributors, licensed under MIT, See LICENSE file for more info.
  *
  * @author David Sehnal <david.sehnal@gmail.com>
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
@@ -177,11 +177,15 @@ namespace SymmetryOperator {
 
     export interface Coordinates { x: ArrayLike<number>, y: ArrayLike<number>, z: ArrayLike<number> }
 
-    export function createMapping<T extends number>(operator: SymmetryOperator, coords: Coordinates, radius?: ((index: T) => number)): ArrayMapping<T> {
-        const invariantPosition = SymmetryOperator.createCoordinateMapper(SymmetryOperator.Default, coords);
-        const position = operator.isIdentity ? invariantPosition : SymmetryOperator.createCoordinateMapper(operator, coords);
+    function _createMapping<T extends number>(operator: SymmetryOperator, coords: Coordinates, radius: ((index: T) => number)): ArrayMapping<T> {
+        const invariantPosition = createCoordinateMapper(SymmetryOperator.Default, coords);
+        const position = operator.isIdentity ? invariantPosition : createCoordinateMapper(operator, coords);
         const { x, y, z } = createProjections(operator, coords);
-        return { operator, coordinates: coords, invariantPosition, position, x, y, z, r: radius ? radius : _zeroRadius };
+        return { operator, coordinates: coords, invariantPosition, position, x, y, z, r: radius };
+    }
+
+    export function createMapping<T extends number>(operator: SymmetryOperator, coords: Coordinates, radius: ((index: T) => number) = _zeroRadius) {
+        return _createMapping(operator, coords, radius);
     }
 
     export function createCoordinateMapper<T extends number>(t: SymmetryOperator, coords: Coordinates): CoordinateMapper<T> {

+ 2 - 2
src/mol-model/structure/structure/unit.ts

@@ -1,5 +1,5 @@
 /**
- * Copyright (c) 2017-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ * Copyright (c) 2017-2023 mol* contributors, licensed under MIT, See LICENSE file for more info.
  *
  * @author David Sehnal <david.sehnal@gmail.com>
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
@@ -46,7 +46,7 @@ namespace Unit {
 
     export function create<K extends Kind>(id: number, invariantId: number, chainGroupId: number, traits: Traits, kind: Kind, model: Model, operator: SymmetryOperator, elements: StructureElement.Set, props?: K extends Kind.Atomic ? AtomicProperties : CoarseProperties): Unit {
         switch (kind) {
-            case Kind.Atomic: return new Atomic(id, invariantId, chainGroupId, traits, model, elements, SymmetryOperator.createMapping(operator, model.atomicConformation, void 0), props ?? AtomicProperties());
+            case Kind.Atomic: return new Atomic(id, invariantId, chainGroupId, traits, model, elements, SymmetryOperator.createMapping(operator, model.atomicConformation), props ?? AtomicProperties());
             case Kind.Spheres: return createCoarse(id, invariantId, chainGroupId, traits, model, Kind.Spheres, elements, SymmetryOperator.createMapping(operator, model.coarseConformation.spheres, getSphereRadiusFunc(model)), props ?? CoarseProperties());
             case Kind.Gaussians: return createCoarse(id, invariantId, chainGroupId, traits, model, Kind.Gaussians, elements, SymmetryOperator.createMapping(operator, model.coarseConformation.gaussians, getGaussianRadiusFunc(model)), props ?? CoarseProperties());
         }

+ 7 - 1
src/mol-repr/representation.ts

@@ -1,5 +1,5 @@
 /**
- * Copyright (c) 2018-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ * Copyright (c) 2018-2023 mol* contributors, licensed under MIT, See LICENSE file for more info.
  *
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
  */
@@ -135,6 +135,12 @@ export class RepresentationRegistry<D, S extends Representation.State> {
     getApplicableTypes(data: D) {
         return getTypes(this.getApplicableList(data));
     }
+
+    clear() {
+        this._list.length = 0;
+        this._map.clear();
+        this._name.clear();
+    }
 }
 
 //

+ 1 - 1
src/mol-repr/structure/registry.ts

@@ -41,7 +41,7 @@ export namespace StructureRepresentationRegistry {
         'carbohydrate': CarbohydrateRepresentationProvider,
         'ellipsoid': EllipsoidRepresentationProvider,
         'gaussian-surface': GaussianSurfaceRepresentationProvider,
-        'gaussian-volume': GaussianVolumeRepresentationProvider, // TODO disabled for now, needs more work
+        'gaussian-volume': GaussianVolumeRepresentationProvider,
         'label': LabelRepresentationProvider,
         'line': LineRepresentationProvider,
         'molecular-surface': MolecularSurfaceRepresentationProvider,

+ 7 - 3
src/mol-repr/structure/units-representation.ts

@@ -1,5 +1,5 @@
 /**
- * Copyright (c) 2018-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ * Copyright (c) 2018-2023 mol* contributors, licensed under MIT, See LICENSE file for more info.
  *
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
  * @author David Sehnal <david.sehnal@gmail.com>
@@ -232,12 +232,16 @@ export function UnitsRepresentation<P extends StructureParams>(label: string, ct
         if (substance !== undefined) visual.setSubstance(substance, webgl);
         if (clipping !== undefined) visual.setClipping(clipping);
         if (themeStrength !== undefined) visual.setThemeStrength(themeStrength);
-        if (transform !== undefined) visual.setTransform(transform);
+        if (transform !== undefined) {
+            if (transform !== _state.transform || !Mat4.areEqual(transform, _state.transform, EPSILON)) {
+                visual.setTransform(transform);
+            }
+        }
         if (unitTransforms !== undefined) {
             if (unitTransforms) {
                 // console.log(group.hashCode, unitTransforms.getSymmetryGroupTransforms(group))
                 visual.setTransform(undefined, unitTransforms.getSymmetryGroupTransforms(group));
-            } else {
+            } else if (unitTransforms !== _state.unitTransforms) {
                 visual.setTransform(undefined, null);
             }
         }

+ 7 - 1
src/mol-theme/theme.ts

@@ -1,5 +1,5 @@
 /**
- * Copyright (c) 2018-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ * Copyright (c) 2018-2023 mol* contributors, licensed under MIT, See LICENSE file for more info.
  *
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
  */
@@ -156,4 +156,10 @@ export class ThemeRegistry<T extends ColorTheme<any, any> | SizeTheme<any>> {
     getApplicableTypes(ctx: ThemeDataContext) {
         return getTypes(this.getApplicableList(ctx));
     }
+
+    clear() {
+        this._list.length = 0;
+        this._map.clear();
+        this._name.clear();
+    }
 }