UNPKG

molstar

Version:

A comprehensive macromolecular library.

231 lines (230 loc) 8.7 kB
/** * Copyright (c) 2018-2025 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 { OrderedSet } from '../../../mol-data/int'; import { Sphere3D } from './sphere3d'; import { Vec3 } from '../../linear-algebra/3d/vec3'; function Box3D() { return Box3D.zero(); } (function (Box3D) { function create(min, max) { return { min, max }; } Box3D.create = create; function zero() { return { min: Vec3(), max: Vec3() }; } Box3D.zero = zero; function copy(out, a) { Vec3.copy(out.min, a.min); Vec3.copy(out.max, a.max); return out; } Box3D.copy = copy; function set(out, min, max) { Vec3.copy(out.min, min); Vec3.copy(out.max, max); return out; } Box3D.set = set; function clone(a) { return copy(zero(), a); } Box3D.clone = clone; const tmpV = Vec3(); /** Get box from sphere, uses extrema if available */ function fromSphere3D(out, sphere) { if (Sphere3D.hasExtrema(sphere) && sphere.extrema.length >= 14) { // 14 extrema with coarse boundary helper return fromVec3Array(out, sphere.extrema); } Vec3.set(tmpV, sphere.radius, sphere.radius, sphere.radius); Vec3.sub(out.min, sphere.center, tmpV); Vec3.add(out.max, sphere.center, tmpV); return out; } Box3D.fromSphere3D = fromSphere3D; function addVec3Array(out, array) { for (let i = 0, il = array.length; i < il; i++) { add(out, array[i]); } return out; } Box3D.addVec3Array = addVec3Array; function fromVec3Array(out, array) { setEmpty(out); addVec3Array(out, array); return out; } Box3D.fromVec3Array = fromVec3Array; function addSphere3D(out, sphere) { if (Sphere3D.hasExtrema(sphere) && sphere.extrema.length >= 14) { // 14 extrema with coarse boundary helper return addVec3Array(out, sphere.extrema); } add(out, Vec3.subScalar(tmpV, sphere.center, sphere.radius)); add(out, Vec3.addScalar(tmpV, sphere.center, sphere.radius)); return out; } Box3D.addSphere3D = addSphere3D; function intersectsSphere3D(box, sphere) { // Find the point on the AABB closest to the sphere center. Vec3.clamp(tmpV, sphere.center, box.min, box.max); // If that point is inside the sphere, the AABB and sphere intersect. return Vec3.squaredDistance(tmpV, sphere.center) <= (sphere.radius * sphere.radius); } Box3D.intersectsSphere3D = intersectsSphere3D; function computeBounding(data) { 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 { x, y, z, indices } = data; for (let t = 0, _t = OrderedSet.size(indices); t < _t; t++) { const i = OrderedSet.getAt(indices, t); min[0] = Math.min(x[i], min[0]); min[1] = Math.min(y[i], min[1]); min[2] = Math.min(z[i], min[2]); max[0] = Math.max(x[i], max[0]); max[1] = Math.max(y[i], max[1]); max[2] = Math.max(z[i], max[2]); } return { min, max }; } Box3D.computeBounding = computeBounding; /** Get size/extent of the box */ function size(size, box) { return Vec3.sub(size, box.max, box.min); } Box3D.size = size; const tmpSizeV = Vec3(); /** Get volume of the box */ function volume(box) { size(tmpSizeV, box); return tmpSizeV[0] * tmpSizeV[1] * tmpSizeV[2]; } Box3D.volume = volume; /** Sets min to Number.MAX_VALUE and max to -Number.MAX_VALUE */ function setEmpty(box) { Vec3.set(box.min, Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE); Vec3.set(box.max, -Number.MAX_VALUE, -Number.MAX_VALUE, -Number.MAX_VALUE); return box; } Box3D.setEmpty = setEmpty; /** Add point to box */ function add(box, point) { Vec3.min(box.min, box.min, point); Vec3.max(box.max, box.max, point); return box; } Box3D.add = add; /** Expand box by delta */ function expand(out, box, delta) { Vec3.sub(out.min, box.min, delta); Vec3.add(out.max, box.max, delta); return out; } Box3D.expand = expand; function expandUniformly(out, box, delta) { Vec3.subScalar(out.min, box.min, delta); Vec3.addScalar(out.max, box.max, delta); return out; } Box3D.expandUniformly = expandUniformly; function scale(out, box, scale) { Vec3.scale(out.min, box.min, scale); Vec3.scale(out.max, box.max, scale); return out; } Box3D.scale = scale; const tmpTransformV = Vec3(); /** Transform box with a Mat4 */ function transform(out, box, m) { const [minX, minY, minZ] = box.min; const [maxX, maxY, maxZ] = box.max; setEmpty(out); add(out, Vec3.transformMat4(tmpTransformV, Vec3.set(tmpTransformV, minX, minY, minZ), m)); add(out, Vec3.transformMat4(tmpTransformV, Vec3.set(tmpTransformV, minX, minY, maxZ), m)); add(out, Vec3.transformMat4(tmpTransformV, Vec3.set(tmpTransformV, minX, maxY, minZ), m)); add(out, Vec3.transformMat4(tmpTransformV, Vec3.set(tmpTransformV, minX, maxY, maxZ), m)); add(out, Vec3.transformMat4(tmpTransformV, Vec3.set(tmpTransformV, maxX, minY, minZ), m)); add(out, Vec3.transformMat4(tmpTransformV, Vec3.set(tmpTransformV, maxX, minY, maxZ), m)); add(out, Vec3.transformMat4(tmpTransformV, Vec3.set(tmpTransformV, maxX, maxY, minZ), m)); add(out, Vec3.transformMat4(tmpTransformV, Vec3.set(tmpTransformV, maxX, maxY, maxZ), m)); return out; } Box3D.transform = transform; function containsVec3(box, v) { return !(v[0] < box.min[0] || v[0] > box.max[0] || v[1] < box.min[1] || v[1] > box.max[1] || v[2] < box.min[2] || v[2] > box.max[2]); } Box3D.containsVec3 = containsVec3; function overlaps(a, b) { return !(a.max[0] < b.min[0] || a.min[0] > b.max[0] || a.max[1] < b.min[1] || a.min[1] > b.max[1] || a.max[2] < b.min[2] || a.min[2] > b.max[2]); } Box3D.overlaps = overlaps; function containsSphere3D(box, s) { const c = s.center; const r = s.radius; return (c[0] - r < box.min[0] || c[0] + r > box.max[0] || c[1] - r < box.min[1] || c[1] + r > box.max[1] || c[2] - r < box.min[2] || c[2] + r > box.max[2]) ? false : true; } Box3D.containsSphere3D = containsSphere3D; function nearestIntersectionWithRay(out, box, origin, dir) { const [minX, minY, minZ] = box.min; const [maxX, maxY, maxZ] = box.max; const [x, y, z] = origin; const invDirX = 1.0 / dir[0]; const invDirY = 1.0 / dir[1]; const invDirZ = 1.0 / dir[2]; let tmin, tmax, tymin, tymax, tzmin, tzmax; if (invDirX >= 0) { tmin = (minX - x) * invDirX; tmax = (maxX - x) * invDirX; } else { tmin = (maxX - x) * invDirX; tmax = (minX - x) * invDirX; } if (invDirY >= 0) { tymin = (minY - y) * invDirY; tymax = (maxY - y) * invDirY; } else { tymin = (maxY - y) * invDirY; tymax = (minY - y) * invDirY; } if (invDirZ >= 0) { tzmin = (minZ - z) * invDirZ; tzmax = (maxZ - z) * invDirZ; } else { tzmin = (maxZ - z) * invDirZ; tzmax = (minZ - z) * invDirZ; } if (tymin > tmin) tmin = tymin; if (tymax < tmax) tmax = tymax; if (tzmin > tmin) tmin = tzmin; if (tzmax < tmax) tmax = tzmax; Vec3.scale(out, dir, tmin); return Vec3.set(out, out[0] + x, out[1] + y, out[2] + z); } Box3D.nearestIntersectionWithRay = nearestIntersectionWithRay; function center(out, box) { return Vec3.center(out, box.max, box.min); } Box3D.center = center; function exactEquals(a, b) { return Vec3.exactEquals(a.min, b.min) && Vec3.exactEquals(a.max, b.max); } Box3D.exactEquals = exactEquals; function equals(a, b) { return Vec3.equals(a.min, b.min) && Vec3.equals(a.max, b.max); } Box3D.equals = equals; })(Box3D || (Box3D = {})); export { Box3D };