Skip to content
Snippets Groups Projects
Commit f72d70b7 authored by David Sehnal's avatar David Sehnal
Browse files

mol-model: use boundary helper

parent 9c44cec9
No related branches found
No related tags found
No related merge requests found
......@@ -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);
......
......@@ -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;
......
......@@ -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);
......
......@@ -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() };
}
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment