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

mol-math: boundary helper

parent edda4fe0
Branches
Tags
No related merge requests found
......@@ -11,7 +11,9 @@ import { RenderObject, createRenderable } from './render-object';
import { Object3D } from './object3d';
import { Sphere3D } from 'mol-math/geometry';
import { Vec3 } from 'mol-math/linear-algebra';
import { BoundaryHelper } from 'mol-math/geometry/boundary-helper';
const boundaryHelper = new BoundaryHelper();
function calculateBoundingSphere(renderableMap: Map<RenderObject, Renderable<RenderableValues & BaseValues>>, boundingSphere: Sphere3D): Sphere3D {
// let count = 0
// const center = Vec3.set(boundingSphere.center, 0, 0, 0)
......@@ -33,15 +35,20 @@ function calculateBoundingSphere(renderableMap: Map<RenderObject, Renderable<Ren
// })
// boundingSphere.radius = radius
const spheres: Sphere3D[] = [];
boundaryHelper.reset(0.1);
renderableMap.forEach(r => {
if (!r.state.visible || !r.boundingSphere.radius) return;
boundaryHelper.boundaryStep(r.boundingSphere.center, r.boundingSphere.radius);
});
boundaryHelper.finishIncludeStep();
renderableMap.forEach(r => {
if (!r.state.visible || !r.boundingSphere.radius) return;
spheres.push(r.boundingSphere)
boundaryHelper.extendStep(r.boundingSphere.center, r.boundingSphere.radius);
});
const bs = Sphere3D.getBoundingSphereFromSpheres(spheres, 0.1);
Vec3.copy(boundingSphere.center, bs.center);
boundingSphere.radius = bs.radius;
Vec3.copy(boundingSphere.center, boundaryHelper.center);
boundingSphere.radius = boundaryHelper.radius;
return boundingSphere;
}
......
/**
* Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author David Sehnal <david.sehnal@gmail.com>
*/
import { Vec3 } from 'mol-math/linear-algebra/3d';
import { Box3D } from './primitives/box3d';
import { Sphere3D } from './primitives/sphere3d';
export class BoundaryHelper {
private count = 0;
private extremes = [Vec3.zero(), Vec3.zero(), Vec3.zero(), Vec3.zero(), Vec3.zero(), Vec3.zero()];
private u = Vec3.zero();
private v = Vec3.zero();
tolerance = 0;
center: Vec3 = Vec3.zero();
radius = 0;
reset(tolerance: number) {
Vec3.set(this.center, 0, 0, 0);
for (let i = 0; i < 6; i++) {
const e = i % 2 === 0 ? Number.MAX_VALUE : -Number.MAX_VALUE;
this.extremes[i] = Vec3.create(e, e, e);
}
this.radius = 0;
this.count = 0;
this.tolerance = tolerance;
}
boundaryStep(p: Vec3, r: number) {
updateExtremeMin(0, this.extremes[0], p, r);
updateExtremeMax(0, this.extremes[1], p, r);
updateExtremeMin(1, this.extremes[2], p, r);
updateExtremeMax(1, this.extremes[3], p, r);
updateExtremeMin(2, this.extremes[4], p, r);
updateExtremeMax(2, this.extremes[5], p, r);
this.count++;
}
finishIncludeStep() {
if (this.count === 0) return;
let maxSpan = 0, mI = 0, mJ = 0;
for (let i = 0; i < 5; i++) {
for (let j = i + 1; j < 6; j++) {
const d = Vec3.squaredDistance(this.extremes[i], this.extremes[j]);
if (d > maxSpan) {
maxSpan = d;
mI = i;
mJ = j;
}
}
}
Vec3.add(this.center, this.extremes[mI], this.extremes[mJ]);
Vec3.scale(this.center, this.center, 0.5);
this.radius = Vec3.distance(this.center, this.extremes[mI]);
}
extendStep(p: Vec3, r: number) {
const d = Vec3.distance(p, this.center);
if ((1 + this.tolerance) * this.radius >= r + d) return;
Vec3.sub(this.u, p, this.center);
Vec3.normalize(this.u, this.u);
Vec3.scale(this.v, this.u, -this.radius);
Vec3.add(this.v, this.v, this.center);
Vec3.scale(this.u, this.u, r + d);
Vec3.add(this.u, this.u, this.center);
Vec3.add(this.center, this.u, this.v);
Vec3.scale(this.center, this.center, 0.5);
this.radius = 0.5 * (r + d + this.radius);
}
getBox(): Box3D {
Vec3.copy(this.u, this.extremes[0]);
Vec3.copy(this.v, this.extremes[0]);
for (let i = 1; i < 6; i++) {
Vec3.min(this.u, this.u, this.extremes[i]);
Vec3.max(this.v, this.v, this.extremes[i]);
}
return { min: Vec3.clone(this.u), max: Vec3.clone(this.v) };
}
getSphere(): Sphere3D {
return { center: Vec3.clone(this.center), radius: this.radius };
}
constructor() {
this.reset(0);
}
}
function updateExtremeMin(d: number, e: Vec3, center: Vec3, r: number) {
if (center[d] - r < e[d]) {
Vec3.copy(e, center);
e[d] -= r;
}
}
function updateExtremeMax(d: number, e: Vec3, center: Vec3, r: number) {
if (center[d] + r > e[d]) {
Vec3.copy(e, center);
e[d] += r;
}
}
\ No newline at end of file
......@@ -96,83 +96,6 @@ namespace Sphere3D {
return (Math.abs(ar - br) <= EPSILON.Value * Math.max(1.0, Math.abs(ar), Math.abs(br)) &&
Vec3.equals(a.center, b.center));
}
function updateExtremeMin(d: number, e: Vec3, center: Vec3, r: number) {
if (center[d] - r < e[d]) {
Vec3.copy(e, center);
e[d] -= r;
}
}
function updateExtremeMax(d: number, e: Vec3, center: Vec3, r: number) {
if (center[d] + r > e[d]) {
Vec3.copy(e, center);
e[d] += r;
}
}
export function getBoundingSphereFromSpheres(spheres: Sphere3D[], tolerance: number): Sphere3D {
if (spheres.length === 0) {
return { center: Vec3.zero(), radius: 0.1 };
}
const extremes: Vec3[] = [];
for (let i = 0; i < 6; i++) {
const e = i % 2 === 0 ? Number.MAX_VALUE : -Number.MAX_VALUE;
extremes[i] = Vec3.create(e, e, e);
}
const u = Vec3.zero(), v = Vec3.zero();
let m = 0;
for (const s of spheres) {
updateExtremeMin(0, extremes[0], s.center, s.radius);
updateExtremeMax(0, extremes[1], s.center, s.radius);
updateExtremeMin(1, extremes[2], s.center, s.radius);
updateExtremeMax(1, extremes[3], s.center, s.radius);
updateExtremeMin(2, extremes[4], s.center, s.radius);
updateExtremeMax(2, extremes[5], s.center, s.radius);
if (s.radius > m) m = s.radius;
}
let maxSpan = 0, mI = 0, mJ = 0;
for (let i = 0; i < 5; i++) {
for (let j = i + 1; j < 6; j++) {
const d = Vec3.squaredDistance(extremes[i], extremes[j]);
if (d > maxSpan) {
maxSpan = d;
mI = i;
mJ = j;
}
}
}
const center = Vec3.zero();
Vec3.add(center, extremes[mI], extremes[mJ]);
Vec3.scale(center, center, 0.5);
let radius = Vec3.distance(center, extremes[mI]);
for (const s of spheres) {
const d = Vec3.distance(s.center, center);
if ((1 + tolerance) * radius >= s.radius + d) continue;
Vec3.sub(u, s.center, center);
Vec3.normalize(u, u);
Vec3.scale(v, u, -radius);
Vec3.add(v, v, center);
Vec3.scale(u, u, s.radius + d);
Vec3.add(u, u, center);
Vec3.add(center, u, v);
Vec3.scale(center, center, 0.5);
radius = Vec3.distance(center, u);
}
return { center, radius };
}
}
export { Sphere3D }
\ 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