diff --git a/src/mol-math/geometry/centroid-helper.ts b/src/mol-math/geometry/centroid-helper.ts index 7387757fc1a7f3c59388368187d7ad0e20868d1c..637e92483fb869cc9d0d5e31a39d2015c6a411b4 100644 --- a/src/mol-math/geometry/centroid-helper.ts +++ b/src/mol-math/geometry/centroid-helper.ts @@ -5,6 +5,7 @@ */ import { Vec3 } from '../../mol-math/linear-algebra/3d'; +import { Sphere3D } from './primitives/sphere3d'; export { CentroidHelper } @@ -35,6 +36,10 @@ class CentroidHelper { if (d > this.radiusSq) this.radiusSq = d; } + getSphere(): Sphere3D { + return { center: Vec3.clone(this.center), radius: Math.sqrt(this.radiusSq) }; + } + constructor() { } diff --git a/src/mol-model/structure/structure/structure.ts b/src/mol-model/structure/structure/structure.ts index a88ab91f81dc5bca543665ce3ae06658e00093f1..0cf0f2fe7dbcfc5f057301a7d4cb744303261f86 100644 --- a/src/mol-model/structure/structure/structure.ts +++ b/src/mol-model/structure/structure/structure.ts @@ -221,6 +221,13 @@ class Structure { || (this._props.uniqueAtomicResidueIndices = getUniqueAtomicResidueIndices(this)); } + get isAtomic() { + for (const u of this.units) { + if (u.kind !== Unit.Kind.Atomic) return false; + } + return true; + } + /** * Provides mapping for serial element indices accross all units. * diff --git a/src/mol-model/structure/structure/util/boundary.ts b/src/mol-model/structure/structure/util/boundary.ts index 1b9026a6adb7a144f6c14edecd24f19da78f5146..98e7e0968c1394ce7cf104470806b5d9ebe66f78 100644 --- a/src/mol-model/structure/structure/util/boundary.ts +++ b/src/mol-model/structure/structure/util/boundary.ts @@ -9,15 +9,60 @@ import { Box3D, Sphere3D } from '../../../../mol-math/geometry'; import { BoundaryHelper } from '../../../../mol-math/geometry/boundary-helper'; import { Vec3 } from '../../../../mol-math/linear-algebra'; import Structure from '../structure'; +import { CentroidHelper } from '../../../../mol-math/geometry/centroid-helper'; export type Boundary = { box: Box3D, sphere: Sphere3D } -const tmpBox = Box3D.empty() -const tmpSphere = Sphere3D.zero() +const tmpBox = Box3D.empty(); +const tmpSphere = Sphere3D.zero(); +const tmpVec = Vec3.zero(); const boundaryHelper = new BoundaryHelper(); +const centroidHelper = new CentroidHelper(); + +// TODO: show this be enabled? does not solve problem with "renderable bounding spheres" +const CENTROID_COMPUTATION_THRESHOLD = -1; export function computeStructureBoundary(s: Structure): Boundary { + if (s.elementCount <= CENTROID_COMPUTATION_THRESHOLD && s.isAtomic) return computeStructureBoundaryFromElements(s); + return computeStructureBoundaryFromUnits(s); +} + +function computeStructureBoundaryFromElements(s: Structure): Boundary { + centroidHelper.reset(); + + 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 v = tmpVec; + for (const unit of s.units) { + const { x, y, z } = unit.conformation; + const elements = unit.elements; + for (let j = 0, _j = elements.length; j < _j; j++) { + const e = elements[j]; + Vec3.set(v, x(e), y(e), z(e)); + centroidHelper.includeStep(v); + Vec3.min(min, min, v); + Vec3.max(max, max, v); + }; + } + + centroidHelper.finishedIncludeStep(); + + for (const unit of s.units) { + const { x, y, z } = unit.conformation; + const elements = unit.elements; + for (let j = 0, _j = elements.length; j < _j; j++) { + const e = elements[j]; + Vec3.set(v, x(e), y(e), z(e)); + centroidHelper.radiusStep(v); + }; + } + + return { box: { min, max }, sphere: centroidHelper.getSphere() }; +} + +function computeStructureBoundaryFromUnits(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)