Skip to content
Snippets Groups Projects
Commit 03668216 authored by Alexander Rose's avatar Alexander Rose
Browse files

use EPOS-based boundary-helper throughout

parent 37ef2348
Branches
No related tags found
No related merge requests found
......@@ -6,7 +6,7 @@
import { Sphere3D } from '../../mol-math/geometry'
import { Vec3 } from '../../mol-math/linear-algebra'
import { EposHelper, HierarchyHelper } from '../../mol-math/geometry/epos-helper';
import { BoundaryHelper, HierarchyHelper } from '../../mol-math/geometry/boundary-helper';
export function calculateTextureInfo (n: number, itemSize: number) {
const sqN = Math.sqrt(n)
......@@ -78,8 +78,8 @@ export function printImageData(imageData: ImageData, scale = 1, pixelated = fals
//
const v = Vec3.zero()
const eposHelperCoarse = new EposHelper('14')
const eposHelperFine = new EposHelper('98')
const eposHelperCoarse = new BoundaryHelper('14')
const eposHelperFine = new BoundaryHelper('98')
const hierarchyHelperCoarse = new HierarchyHelper('14')
const hierarchyHelperFine = new HierarchyHelper('98')
......
......@@ -14,9 +14,9 @@ import { Sphere3D } from '../mol-math/geometry';
import { CommitQueue } from './commit-queue';
import { now } from '../mol-util/now';
import { arraySetRemove } from '../mol-util/array';
import { EposHelper } from '../mol-math/geometry/epos-helper';
import { BoundaryHelper } from '../mol-math/geometry/boundary-helper';
const eposHelper = new EposHelper('98')
const eposHelper = new BoundaryHelper('98')
function calculateBoundingSphere(renderables: Renderable<RenderableValues & BaseValues>[], boundingSphere: Sphere3D): Sphere3D {
eposHelper.reset();
......
/**
* Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
* Copyright (c) 2020 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>
*/
import { Vec3 } from '../../mol-math/linear-algebra/3d';
import { Vec3 } from '../linear-algebra/3d';
import { CentroidHelper } from './centroid-helper';
import { Sphere3D } from '../geometry';
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
*/
// implementing http://www.ep.liu.se/ecp/034/009/ecp083409.pdf
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();
private dir: Vec3[]
private minDist: number[] = []
private maxDist: number[] = []
private extrema: Vec3[] = []
centroidHelper = new CentroidHelper()
tolerance = 0;
center: Vec3 = Vec3.zero();
radius = 0;
private computeExtrema(i: number, p: Vec3) {
const d = Vec3.dot(this.dir[i], p)
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;
Vec3.set(this.extremes[i], e, e, e);
if (d < this.minDist[i]) {
this.minDist[i] = d
Vec3.copy(this.extrema[i * 2], p)
}
if (d > this.maxDist[i]) {
this.maxDist[i] = d
Vec3.copy(this.extrema[i * 2 + 1], p)
}
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);
private computeSphereExtrema(i: number, center: Vec3, radius: number) {
const d = Vec3.dot(this.dir[i], center)
updateExtremeMin(1, this.extremes[2], p, r);
updateExtremeMax(1, this.extremes[3], p, r);
if (d - radius < this.minDist[i]) {
this.minDist[i] = d - radius
Vec3.scaleAndSub(this.extrema[i * 2], center, this.dir[i], radius)
}
if (d + radius > this.maxDist[i]) {
this.maxDist[i] = d + radius
Vec3.scaleAndAdd(this.extrema[i * 2 + 1], center, this.dir[i], radius)
}
}
updateExtremeMin(2, this.extremes[4], p, r);
updateExtremeMax(2, this.extremes[5], p, r);
this.count++;
includeStep(p: Vec3) {
for (let i = 0, il = this.dir.length; i < il; ++i) {
this.computeExtrema(i, p)
}
}
finishBoundaryStep() {
if (this.count === 0) return;
includeSphereStep(center: Vec3, radius: number) {
for (let i = 0, il = this.dir.length; i < il; ++i) {
this.computeSphereExtrema(i, center, radius)
}
}
let maxSpan = 0, mI = 0, mJ = 0;
finishedIncludeStep() {
for (let i = 0; i < this.extrema.length; i++) {
this.centroidHelper.includeStep(this.extrema[i]);
}
this.centroidHelper.finishedIncludeStep();
}
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;
radiusStep(p: Vec3) {
this.centroidHelper.radiusStep(p);
}
radiusSphereStep(center: Vec3, radius: number) {
this.centroidHelper.radiusSphereStep(center, radius);
}
getHierarchyInput() {
const sphere = this.centroidHelper.getSphere();
const normal = Vec3()
const t = sphere.radius * this.hierarchyThresholdFactor
let maxDist = -Infinity
let belowThreshold = false
for (let i = 0; i < this.extrema.length; i += 2) {
const halfDist = Vec3.distance(this.extrema[i], this.extrema[i + 1]) / 2
if (halfDist > maxDist) {
maxDist = halfDist
Vec3.normalize(normal, Vec3.sub(normal, this.extrema[i], this.extrema[i + 1]))
}
if (halfDist < t) belowThreshold = true
}
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]);
return belowThreshold ? { sphere, normal } : false
}
extendStep(p: Vec3, r: number) {
const d = Vec3.distance(p, this.center);
if ((1 + this.tolerance) * this.radius >= r + d) return;
getSphere(sphere?: Sphere3D) {
return this.centroidHelper.getSphere(sphere)
}
Vec3.sub(this.u, p, this.center);
Vec3.normalize(this.u, this.u);
getBox(box?: Box3D) {
// TODO can we get a tighter box from the extrema???
if (!box) box = Box3D()
return Box3D.fromSphere3D(box, this.centroidHelper.getSphere())
}
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);
reset() {
for (let i = 0, il = this.dir.length; i < il; ++i) {
this.minDist[i] = Infinity
this.maxDist[i] = -Infinity
this.extrema[i * 2] = Vec3()
this.extrema[i * 2 + 1] = Vec3()
}
this.centroidHelper.reset()
}
Vec3.add(this.center, this.u, this.v);
Vec3.scale(this.center, this.center, 0.5);
this.radius = 0.5 * (r + d + this.radius);
constructor(quality: EposQuality, private hierarchyThresholdFactor = 0.66) {
this.dir = getEposDir(quality)
this.reset()
}
}
getBox(): Box3D {
Vec3.copy(this.u, this.extremes[0]);
Vec3.copy(this.v, this.extremes[0]);
const tmpV = Vec3()
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]);
export class HierarchyHelper {
private sphere = Sphere3D()
private normal = Vec3()
private helperA = new BoundaryHelper(this.quality)
private helperB = new BoundaryHelper(this.quality)
private checkSide(p: Vec3) {
return Vec3.dot(this.normal, Vec3.sub(tmpV, this.sphere.center, p)) > 0
}
includeStep(p: Vec3) {
if (this.checkSide(p)) {
this.helperA.includeStep(p)
} else {
this.helperB.includeStep(p)
}
}
return { min: Vec3.clone(this.u), max: Vec3.clone(this.v) };
finishedIncludeStep() {
this.helperA.finishedIncludeStep();
this.helperB.finishedIncludeStep();
}
getSphere(): Sphere3D {
return { center: Vec3.clone(this.center), radius: this.radius };
radiusStep(p: Vec3) {
if (this.checkSide(p)) {
this.helperA.radiusStep(p)
} else {
this.helperB.radiusStep(p)
}
}
constructor() {
this.reset(0);
getSphere(): Sphere3D.Hierarchy {
return {
center: this.sphere.center,
radius: this.sphere.radius,
hierarchy: [this.helperA.getSphere(), this.helperB.getSphere()]
}
}
function updateExtremeMin(d: number, e: Vec3, center: Vec3, r: number) {
if (center[d] - r < e[d]) {
Vec3.copy(e, center);
e[d] -= r;
reset(sphere: Sphere3D, normal: Vec3) {
Sphere3D.copy(this.sphere, sphere)
Vec3.copy(this.normal, normal)
this.helperA.reset()
this.helperB.reset()
}
constructor(private quality: EposQuality) { }
}
function updateExtremeMax(d: number, e: Vec3, center: Vec3, r: number) {
if (center[d] + r > e[d]) {
Vec3.copy(e, center);
e[d] += r;
type EposQuality = '6' | '14' | '26' | '98'
function getEposDir(quality: EposQuality) {
let dir: number[][]
switch (quality) {
case '6': dir = [ ...Type001 ]; break
case '14': dir = [ ...Type001, ...Type111 ]; break
case '26': dir = [ ...Type001, ...Type111, ...Type011 ]; break
case '98': dir = [ ...Type001, ...Type111, ...Type011, ...Type012, ...Type112, ...Type122 ]; break
}
return dir.map(a => {
const v = Vec3.create(a[0], a[1], a[2])
return Vec3.normalize(v, v)
})
}
const Type001 = [
[1, 0, 0], [0, 1, 0], [0, 0, 1]
]
const Type111 = [
[1, 1, 1], [-1, 1, 1], [-1, -1, 1], [1, -1, 1]
]
const Type011 = [
[1, 1, 0], [1, -1, 0], [1, 0, 1], [1, 0, -1], [0, 1, 1], [0, 1, -1]
]
const Type012 = [
[0, 1, 2], [0, 2, 1], [1, 0, 2], [2, 0, 1], [1, 2, 0], [2, 1, 0],
[0, 1, -2], [0, 2, -1], [1, 0, -2], [2, 0, -1], [1, -2, 0], [2, -1, 0]
]
const Type112 = [
[1, 1, 2], [2, 1, 1], [1, 2, 1], [1, -1, 2], [1, 1, -2], [1, -1, -2],
[2, -1, 1], [2, 1, -1], [2, -1, -1], [1, -2, 1], [1, 2, -1], [1, -2, -1]
]
const Type122 = [
[2, 2, 1], [1, 2, 2], [2, 1, 2], [2, -2, 1], [2, 2, -1], [2, -2, -1],
[1, -2, 2], [1, 2, -2], [1, -2, -2], [2, -1, 2], [2, 1, -2], [2, -1, -2]
]
\ No newline at end of file
/**
* Copyright (c) 2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
import { Vec3 } from '../linear-algebra/3d';
import { CentroidHelper } from './centroid-helper';
import { Sphere3D } from '../geometry';
// implementing http://www.ep.liu.se/ecp/034/009/ecp083409.pdf
export class EposHelper {
private dir: Vec3[]
private minDist: number[] = []
private maxDist: number[] = []
private extrema: Vec3[] = []
centroidHelper = new CentroidHelper()
private computeExtrema(i: number, p: Vec3) {
const d = Vec3.dot(this.dir[i], p)
if (d < this.minDist[i]) {
this.minDist[i] = d
Vec3.copy(this.extrema[i * 2], p)
}
if (d > this.maxDist[i]) {
this.maxDist[i] = d
Vec3.copy(this.extrema[i * 2 + 1], p)
}
}
private computeSphereExtrema(i: number, center: Vec3, radius: number) {
const d = Vec3.dot(this.dir[i], center)
if (d - radius < this.minDist[i]) {
this.minDist[i] = d - radius
Vec3.scaleAndSub(this.extrema[i * 2], center, this.dir[i], radius)
}
if (d + radius > this.maxDist[i]) {
this.maxDist[i] = d + radius
Vec3.scaleAndAdd(this.extrema[i * 2 + 1], center, this.dir[i], radius)
}
}
includeStep(p: Vec3) {
for (let i = 0, il = this.dir.length; i < il; ++i) {
this.computeExtrema(i, p)
}
}
includeSphereStep(center: Vec3, radius: number) {
for (let i = 0, il = this.dir.length; i < il; ++i) {
this.computeSphereExtrema(i, center, radius)
}
}
finishedIncludeStep() {
for (let i = 0; i < this.extrema.length; i++) {
this.centroidHelper.includeStep(this.extrema[i]);
}
this.centroidHelper.finishedIncludeStep();
}
radiusStep(p: Vec3) {
this.centroidHelper.radiusStep(p);
}
radiusSphereStep(center: Vec3, radius: number) {
this.centroidHelper.radiusSphereStep(center, radius);
}
getHierarchyInput() {
const sphere = this.centroidHelper.getSphere();
const normal = Vec3()
const t = sphere.radius * this.hierarchyThresholdFactor
let maxDist = -Infinity
let belowThreshold = false
for (let i = 0; i < this.extrema.length; i += 2) {
const halfDist = Vec3.distance(this.extrema[i], this.extrema[i + 1]) / 2
if (halfDist > maxDist) {
maxDist = halfDist
Vec3.normalize(normal, Vec3.sub(normal, this.extrema[i], this.extrema[i + 1]))
}
if (halfDist < t) belowThreshold = true
}
return belowThreshold ? { sphere, normal } : false
}
getSphere(sphere?: Sphere3D) {
return this.centroidHelper.getSphere(sphere)
}
reset() {
for (let i = 0, il = this.dir.length; i < il; ++i) {
this.minDist[i] = Infinity
this.maxDist[i] = -Infinity
this.extrema[i * 2] = Vec3()
this.extrema[i * 2 + 1] = Vec3()
}
this.centroidHelper.reset()
}
constructor(quality: EposQuality, private hierarchyThresholdFactor = 0.66) {
this.dir = getEposDir(quality)
this.reset()
}
}
const tmpV = Vec3()
export class HierarchyHelper {
private sphere = Sphere3D()
private normal = Vec3()
private helperA = new EposHelper(this.quality)
private helperB = new EposHelper(this.quality)
private checkSide(p: Vec3) {
return Vec3.dot(this.normal, Vec3.sub(tmpV, this.sphere.center, p)) > 0
}
includeStep(p: Vec3) {
if (this.checkSide(p)) {
this.helperA.includeStep(p)
} else {
this.helperB.includeStep(p)
}
}
finishedIncludeStep() {
this.helperA.finishedIncludeStep();
this.helperB.finishedIncludeStep();
}
radiusStep(p: Vec3) {
if (this.checkSide(p)) {
this.helperA.radiusStep(p)
} else {
this.helperB.radiusStep(p)
}
}
getSphere(): Sphere3D.Hierarchy {
return {
center: this.sphere.center,
radius: this.sphere.radius,
hierarchy: [this.helperA.getSphere(), this.helperB.getSphere()]
}
}
reset(sphere: Sphere3D, normal: Vec3) {
Sphere3D.copy(this.sphere, sphere)
Vec3.copy(this.normal, normal)
this.helperA.reset()
this.helperB.reset()
}
constructor(private quality: EposQuality) { }
}
type EposQuality = '6' | '14' | '26' | '98'
function getEposDir(quality: EposQuality) {
let dir: number[][]
switch (quality) {
case '6': dir = [ ...Type001 ]; break
case '14': dir = [ ...Type001, ...Type111 ]; break
case '26': dir = [ ...Type001, ...Type111, ...Type011 ]; break
case '98': dir = [ ...Type001, ...Type111, ...Type011, ...Type012, ...Type112, ...Type122 ]; break
}
return dir.map(a => {
const v = Vec3.create(a[0], a[1], a[2])
return Vec3.normalize(v, v)
})
}
const Type001 = [
[1, 0, 0], [0, 1, 0], [0, 0, 1]
]
const Type111 = [
[1, 1, 1], [-1, 1, 1], [-1, -1, 1], [1, -1, 1]
]
const Type011 = [
[1, 1, 0], [1, -1, 0], [1, 0, 1], [1, 0, -1], [0, 1, 1], [0, 1, -1]
]
const Type012 = [
[0, 1, 2], [0, 2, 1], [1, 0, 2], [2, 0, 1], [1, 2, 0], [2, 1, 0],
[0, 1, -2], [0, 2, -1], [1, 0, -2], [2, 0, -1], [1, -2, 0], [2, -1, 0]
]
const Type112 = [
[1, 1, 2], [2, 1, 1], [1, 2, 1], [1, -1, 2], [1, 1, -2], [1, -1, -2],
[2, -1, 1], [2, 1, -1], [2, -1, -1], [1, -2, 1], [1, 2, -1], [1, -2, -1]
]
const Type122 = [
[2, 2, 1], [1, 2, 2], [2, 1, 2], [2, -2, 1], [2, 2, -1], [2, -2, -1],
[1, -2, 2], [1, 2, -2], [1, -2, -2], [2, -1, 2], [2, 1, -2], [2, -1, -2]
]
\ No newline at end of file
......@@ -166,21 +166,27 @@ function _build(state: BuildState): Grid3D {
}
}
const boundaryHelper = new BoundaryHelper();
const boundaryHelperCoarse = new BoundaryHelper('14');
const boundaryHelperFine = new BoundaryHelper('98');
function getBoundaryHelper(count: number) {
return count > 500_000 ? boundaryHelperCoarse : boundaryHelperFine
}
function getBoundary(data: PositionData) {
const { x, y, z, radius, indices } = data;
const p = Vec3();
boundaryHelper.reset(0);
const boundaryHelper = getBoundaryHelper(OrderedSet.size(indices));
boundaryHelper.reset();
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.includeSphereStep(p, (radius && radius[i]) || 0);
}
boundaryHelper.finishBoundaryStep();
boundaryHelper.finishedIncludeStep();
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);
boundaryHelper.radiusSphereStep(p, (radius && radius[i]) || 0);
}
return { boundingBox: boundaryHelper.getBox(), boundingSphere: boundaryHelper.getSphere() };
......
......@@ -8,6 +8,7 @@
import { Vec3, Mat4 } from '../../linear-algebra'
import { PositionData } from '../common'
import { OrderedSet } from '../../../mol-data/int';
import { Sphere3D } from './sphere3d';
interface Box3D { min: Vec3, max: Vec3 }
......@@ -29,6 +30,13 @@ namespace Box3D {
return copy(empty(), a);
}
export function fromSphere3D(out: Box3D, sphere: Sphere3D): Box3D {
const r = Vec3.create(sphere.radius, sphere.radius, sphere.radius)
Vec3.sub(out.min, sphere.center, r)
Vec3.add(out.max, sphere.center, r)
return out
}
export function computeBounding(data: PositionData): Box3D {
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);
......
......@@ -11,7 +11,6 @@ import { OrderedSet } from '../../../mol-data/int';
import { NumberArray } from '../../../mol-util/type-helpers';
import { Box3D } from './box3d';
import { Axes3D } from './axes3d';
import { BoundaryHelper } from '../boundary-helper';
type Sphere3D = Sphere3D.Data | Sphere3D.Hierarchy
......@@ -111,15 +110,6 @@ namespace Sphere3D {
return out
}
const boundaryHelper = new BoundaryHelper();
export function fromSphere3Ds(spheres: Sphere3D[]): Sphere3D {
boundaryHelper.reset(0);
for (const s of spheres) boundaryHelper.boundaryStep(s.center, s.radius);
boundaryHelper.finishBoundaryStep();
for (const s of spheres) boundaryHelper.extendStep(s.center, s.radius);
return boundaryHelper.getSphere();
}
const tmpAddVec3 = Vec3()
export function addVec3(out: Sphere3D, s: Sphere3D, v: Vec3) {
const d = Vec3.distance(s.center, v)
......
......@@ -14,6 +14,7 @@ import { PrincipalAxes } from '../mol-math/linear-algebra/matrix/principal-axes'
import { ParamDefinition } from '../mol-util/param-definition';
import { shallowEqual } from '../mol-util';
import { FiniteArray } from '../mol-util/type-helpers';
import { BoundaryHelper } from '../mol-math/geometry/boundary-helper';
/** A Loci that includes every loci */
export const EveryLoci = { kind: 'every-loci' as 'every-loci' }
......@@ -65,9 +66,14 @@ type Loci = StructureElement.Loci | Structure.Loci | Bond.Loci | EveryLoci | Emp
namespace Loci {
export interface Bundle<L extends number> { loci: FiniteArray<Loci, L> }
const boundaryHelper = new BoundaryHelper('98');
export function getBundleBoundingSphere(bundle: Bundle<any>): Sphere3D {
const spheres = bundle.loci.map(l => getBoundingSphere(l)).filter(s => !!s)
return Sphere3D.fromSphere3Ds(spheres as Sphere3D[])
const spheres = bundle.loci.map(l => getBoundingSphere(l)).filter(s => !!s) as Sphere3D[]
boundaryHelper.reset();
for (const s of spheres) boundaryHelper.includeSphereStep(s.center, s.radius);
boundaryHelper.finishedIncludeStep();
for (const s of spheres) boundaryHelper.radiusSphereStep(s.center, s.radius);
return boundaryHelper.getSphere();
}
export function areEqual(lociA: Loci, lociB: Loci) {
......
/**
* Copyright (c) 2017-2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
* Copyright (c) 2017-2020 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>
......@@ -7,7 +7,6 @@
import { UniqueArray } from '../../../../mol-data/generic';
import { OrderedSet, SortedArray, Interval } from '../../../../mol-data/int';
import { BoundaryHelper } from '../../../../mol-math/geometry/boundary-helper';
import { Vec3 } from '../../../../mol-math/linear-algebra';
import { MolScriptBuilder as MS } from '../../../../mol-script/language/builder';
import Structure from '../structure';
......@@ -22,6 +21,7 @@ import { ChainIndex } from '../../model/indexing';
import { PrincipalAxes } from '../../../../mol-math/linear-algebra/matrix/principal-axes';
import { NumberArray } from '../../../../mol-util/type-helpers';
import StructureProperties from '../properties';
import { BoundaryHelper } from '../../../../mol-math/geometry/boundary-helper';
/** Represents multiple structure element index locations */
export interface Loci {
......@@ -456,10 +456,10 @@ export namespace Loci {
//
const boundaryHelper = new BoundaryHelper();
const boundaryHelper = new BoundaryHelper('98');
const tempPosBoundary = Vec3.zero();
export function getBoundary(loci: Loci): Boundary {
boundaryHelper.reset(0);
boundaryHelper.reset();
for (const e of loci.elements) {
const { indices } = e;
......@@ -468,10 +468,10 @@ export namespace Loci {
for (let i = 0, _i = OrderedSet.size(indices); i < _i; i++) {
const eI = elements[OrderedSet.getAt(indices, i)];
pos(eI, tempPosBoundary);
boundaryHelper.boundaryStep(tempPosBoundary, r(eI));
boundaryHelper.includeSphereStep(tempPosBoundary, r(eI));
}
}
boundaryHelper.finishBoundaryStep();
boundaryHelper.finishedIncludeStep();
for (const e of loci.elements) {
const { indices } = e;
const pos = e.unit.conformation.position, r = e.unit.conformation.r;
......@@ -479,7 +479,7 @@ export namespace Loci {
for (let i = 0, _i = OrderedSet.size(indices); i < _i; i++) {
const eI = elements[OrderedSet.getAt(indices, i)];
pos(eI, tempPosBoundary);
boundaryHelper.extendStep(tempPosBoundary, r(eI));
boundaryHelper.radiusSphereStep(tempPosBoundary, r(eI));
}
}
......
/**
* Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
* Copyright (c) 2018-2020 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>
*/
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';
import { BoundaryHelper } from '../../../../mol-math/geometry/boundary-helper';
export type Boundary = { box: Box3D, sphere: Sphere3D }
const tmpBox = Box3D.empty();
const tmpSphere = Sphere3D.zero();
const tmpVec = Vec3.zero();
const tmpBox = Box3D();
const tmpSphere = Sphere3D();
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;
const boundaryHelper = new BoundaryHelper('98');
export function computeStructureBoundary(s: Structure): Boundary {
if (s.elementCount <= CENTROID_COMPUTATION_THRESHOLD && s.isAtomic) return computeStructureBoundaryFromElements(s);
return computeStructureBoundaryFromUnits(s);
}
export 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() };
}
export 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)
const { units } = s;
boundaryHelper.reset(0);
boundaryHelper.reset();
for (let i = 0, _i = units.length; i < _i; i++) {
const u = units[i];
......@@ -79,18 +34,18 @@ export function computeStructureBoundaryFromUnits(s: Structure): Boundary {
Vec3.min(min, min, invariantBoundary.box.min);
Vec3.max(max, max, invariantBoundary.box.max);
boundaryHelper.boundaryStep(invariantBoundary.sphere.center, invariantBoundary.sphere.radius);
boundaryHelper.includeSphereStep(invariantBoundary.sphere.center, invariantBoundary.sphere.radius);
} else {
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);
boundaryHelper.includeSphereStep(tmpSphere.center, tmpSphere.radius);
}
}
boundaryHelper.finishBoundaryStep();
boundaryHelper.finishedIncludeStep();
for (let i = 0, _i = units.length; i < _i; i++) {
const u = units[i];
......@@ -98,10 +53,10 @@ export function computeStructureBoundaryFromUnits(s: Structure): Boundary {
const o = u.conformation.operator;
if (o.isIdentity) {
boundaryHelper.extendStep(invariantBoundary.sphere.center, invariantBoundary.sphere.radius);
boundaryHelper.radiusSphereStep(invariantBoundary.sphere.center, invariantBoundary.sphere.radius);
} else {
Sphere3D.transform(tmpSphere, invariantBoundary.sphere, o.matrix);
boundaryHelper.extendStep(tmpSphere.center, tmpSphere.radius);
boundaryHelper.radiusSphereStep(tmpSphere.center, tmpSphere.radius);
}
}
......
......@@ -13,13 +13,13 @@ import { Boundary } from '../../../mol-model/structure/structure/util/boundary';
import { PrincipalAxes } from '../../../mol-math/linear-algebra/matrix/principal-axes';
import { structureElementStatsLabel } from '../../../mol-theme/label';
import { OrderedSet } from '../../../mol-data/int';
import { BoundaryHelper } from '../../../mol-math/geometry/boundary-helper';
import { arrayRemoveAtInPlace } from '../../../mol-util/array';
import { EmptyLoci, Loci } from '../../../mol-model/loci';
import { StateObject, StateSelection } from '../../../mol-state';
import { PluginStateObject } from '../../objects';
import { StructureSelectionQuery } from '../../helpers/structure-selection-query';
import { Task } from '../../../mol-task';
import { BoundaryHelper } from '../../../mol-math/geometry/boundary-helper';
interface StructureSelectionManagerState {
entries: Map<string, SelectionEntry>,
......@@ -27,7 +27,7 @@ interface StructureSelectionManagerState {
stats?: SelectionStats
}
const boundaryHelper = new BoundaryHelper();
const boundaryHelper = new BoundaryHelper('98');
const HISTORY_CAPACITY = 8;
export type StructureSelectionModifier = 'add' | 'remove' | 'set'
......@@ -288,7 +288,7 @@ export class StructureSelectionManager extends PluginComponent<StructureSelectio
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)
boundaryHelper.reset(0);
boundaryHelper.reset();
const boundaries: Boundary[] = []
this.entries.forEach(v => {
......@@ -302,14 +302,12 @@ export class StructureSelectionManager extends PluginComponent<StructureSelectio
const { box, sphere } = boundaries[i];
Vec3.min(min, min, box.min);
Vec3.max(max, max, box.max);
boundaryHelper.boundaryStep(sphere.center, sphere.radius)
boundaryHelper.includeSphereStep(sphere.center, sphere.radius)
}
boundaryHelper.finishBoundaryStep();
boundaryHelper.finishedIncludeStep();
for (let i = 0, il = boundaries.length; i < il; ++i) {
const { sphere } = boundaries[i];
boundaryHelper.extendStep(sphere.center, sphere.radius);
boundaryHelper.radiusSphereStep(sphere.center, sphere.radius);
}
return { box: { min, max }, sphere: boundaryHelper.getSphere() };
......
......@@ -64,7 +64,7 @@ function createLabelText(ctx: VisualContext, structure: Structure, theme: Theme,
//
const tmpVec = Vec3();
const boundaryHelper = new BoundaryHelper();
const boundaryHelper = new BoundaryHelper('98');
function createChainText(ctx: VisualContext, structure: Structure, theme: Theme, props: LabelTextProps, text?: Text): Text {
const l = StructureElement.Location.create(structure);
......@@ -117,20 +117,20 @@ function createResidueText(ctx: VisualContext, structure: Structure, theme: Them
j++;
while (j < jl && residueIndex[elements[j]] === rI) j++;
boundaryHelper.reset(0);
boundaryHelper.reset();
for (let eI = start; eI < j; eI++) {
pos(elements[eI], tmpVec);
boundaryHelper.boundaryStep(tmpVec, 0);
boundaryHelper.includeStep(tmpVec);
}
boundaryHelper.finishBoundaryStep();
boundaryHelper.finishedIncludeStep();
for (let eI = start; eI < j; eI++) {
pos(elements[eI], tmpVec);
boundaryHelper.extendStep(tmpVec, 0);
boundaryHelper.radiusStep(tmpVec);
}
l.element = elements[start];
const { center, radius } = boundaryHelper
const { center, radius } = boundaryHelper.getSphere()
const authSeqId = auth_seq_id(l)
const compId = label_comp_id(l)
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please to comment