|
@@ -10,12 +10,14 @@ import { Vec3 } from '../linear-algebra';
|
|
|
import { OrderedSet } from '../../mol-data/int';
|
|
|
import { BoundaryHelper } from './boundary-helper';
|
|
|
import { Box3D, Sphere3D } from '../geometry';
|
|
|
-import { EPSILON } from '../linear-algebra/3d/common';
|
|
|
+import { EPSILON, equalEps } from '../linear-algebra/3d/common';
|
|
|
|
|
|
export type Boundary = { readonly box: Box3D, readonly sphere: Sphere3D }
|
|
|
|
|
|
// avoiding namespace lookup improved performance in Chrome (Aug 2020)
|
|
|
const v3set = Vec3.set;
|
|
|
+const v3copy = Vec3.copy;
|
|
|
+const v3distance = Vec3.distance;
|
|
|
const v3squaredDistance = Vec3.squaredDistance;
|
|
|
|
|
|
const boundaryHelperCoarse = new BoundaryHelper('14');
|
|
@@ -58,31 +60,50 @@ export function getBoundary(data: PositionData): Boundary {
|
|
|
return { box: boundaryHelper.getBox(), sphere };
|
|
|
}
|
|
|
|
|
|
+const extremPoint = Vec3();
|
|
|
export function tryAdjustBoundary(data: PositionData, boundary: Boundary): Boundary | undefined {
|
|
|
const { x, y, z, indices } = data;
|
|
|
const n = OrderedSet.size(indices);
|
|
|
const { center, radius } = boundary.sphere;
|
|
|
|
|
|
+ const threshold = (radius / 100) * 5;
|
|
|
+ const upper = radius + threshold;
|
|
|
+ const upperSq = upper * upper;
|
|
|
+
|
|
|
let maxDistSq = 0;
|
|
|
for (let t = 0; t < n; t++) {
|
|
|
const i = OrderedSet.getAt(indices, t);
|
|
|
v3set(p, x[i], y[i], z[i]);
|
|
|
const distSq = v3squaredDistance(p, center);
|
|
|
- if (distSq > maxDistSq) maxDistSq = distSq;
|
|
|
+ if (distSq > upperSq) return;
|
|
|
+
|
|
|
+ if (distSq > maxDistSq) {
|
|
|
+ maxDistSq = distSq;
|
|
|
+ v3copy(extremPoint, p);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
const adjustedRadius = Math.sqrt(maxDistSq);
|
|
|
- const deltaRadius = adjustedRadius - radius;
|
|
|
- const absDeltaRadius = Math.abs(deltaRadius);
|
|
|
|
|
|
- if (absDeltaRadius < EPSILON) {
|
|
|
+ if (equalEps(adjustedRadius, radius, EPSILON)) {
|
|
|
return boundary;
|
|
|
- } else if (absDeltaRadius < (radius / 100) * 5) {
|
|
|
- // TODO: The expanded sphere extrema are not correct if the principal axes differ
|
|
|
+ } else if (equalEps(adjustedRadius, radius, threshold)) {
|
|
|
+ if (Sphere3D.hasExtrema(boundary.sphere)) {
|
|
|
+ let flag = false;
|
|
|
+ for (const e of boundary.sphere.extrema) {
|
|
|
+ if (v3distance(e, extremPoint) < threshold * 2) {
|
|
|
+ flag = true;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (!flag) return;
|
|
|
+ }
|
|
|
+
|
|
|
+ const deltaRadius = adjustedRadius - radius;
|
|
|
const sphere = Sphere3D.expand(Sphere3D(), boundary.sphere, deltaRadius);
|
|
|
const box = Box3D.fromSphere3D(Box3D(), sphere);
|
|
|
return { box, sphere };
|
|
|
- } else {
|
|
|
- return undefined;
|
|
|
}
|
|
|
+
|
|
|
+ return;
|
|
|
}
|