diff --git a/CHANGELOG.md b/CHANGELOG.md index 810d7bfd82ec51aac6a61334f67f19657ad8db73..aeac889940b2d93a7bc88ed2732c34840e08f617 100644 --- a/CHANGELOG.md +++ b/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 diff --git a/src/mol-gl/renderable/util.ts b/src/mol-gl/renderable/util.ts index cb54c9a737dd471d6b3cf3e6b3571111618abbf6..c642c6507a62e48bfda5e4d0a3cdc131a5e1ec49 100644 --- a/src/mol-gl/renderable/util.ts +++ b/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); } } diff --git a/src/mol-gl/scene.ts b/src/mol-gl/scene.ts index b8a8252b941c13baff32c3951cd8b1193c1f664f..a8d32ab433578eadd79980ce165fb49dc9864cfe 100644 --- a/src/mol-gl/scene.ts +++ b/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; }, }; diff --git a/src/mol-math/geometry/boundary-helper.ts b/src/mol-math/geometry/boundary-helper.ts index c49ff1afddb6bd9a9816495bb94a963afc1ae87e..6f91c16ea78f011c7a4b63be520df1fbfc942b6e 100644 --- a/src/mol-math/geometry/boundary-helper.ts +++ b/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(); } } diff --git a/src/mol-math/geometry/symmetry-operator.ts b/src/mol-math/geometry/symmetry-operator.ts index cbc2a5eda01f3d26d0f059e3e496d6743f8a4de9..279478b5e2f4bcc20aa5a2aeef4d221fbaa3e0af 100644 --- a/src/mol-math/geometry/symmetry-operator.ts +++ b/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> { diff --git a/src/mol-model/structure/structure/unit.ts b/src/mol-model/structure/structure/unit.ts index b6c8fc172ce33c6e4c4fec473c3788d661dbb7f5..6f6d1a814f71bd7dd1f5933d68c521d399c05ab6 100644 --- a/src/mol-model/structure/structure/unit.ts +++ b/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()); } diff --git a/src/mol-repr/representation.ts b/src/mol-repr/representation.ts index ef534488d887eace73375402f9c1dacddfc631fd..4718fc6662f38afc276bd10aecfaaf80c696a2c7 100644 --- a/src/mol-repr/representation.ts +++ b/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(); + } } // diff --git a/src/mol-repr/structure/registry.ts b/src/mol-repr/structure/registry.ts index 8b5c5a5b5a451894a79339e952ccd3b82ca66945..348b19b5a534eadb0ead6cf2571a909ac8cdaafe 100644 --- a/src/mol-repr/structure/registry.ts +++ b/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, diff --git a/src/mol-repr/structure/units-representation.ts b/src/mol-repr/structure/units-representation.ts index b713ede00253e42f34151a19bd149f1157fd7e06..a286188a54102892db8a07baaf137b747c0683ce 100644 --- a/src/mol-repr/structure/units-representation.ts +++ b/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); } } diff --git a/src/mol-theme/theme.ts b/src/mol-theme/theme.ts index 1ba9a7e3f07c8b37c69963aa047a387bc0099be6..84aac3d8f3a94f8897313ec885c0c9f462140412 100644 --- a/src/mol-theme/theme.ts +++ b/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(); + } } \ No newline at end of file