@kitware/vtk.js
Version:
Visualization Toolkit for the Web
256 lines (230 loc) • 8.03 kB
JavaScript
import { s as subtract, d as dot, j as cross, k as add } from '../Core/Math/index.js';
import { m as macro } from '../../macros2.js';
import vtkImplicitFunction from './ImplicitFunction.js';
const PLANE_TOLERANCE = 1.0e-6;
const COINCIDE = 'coincide';
const DISJOINT = 'disjoint';
// ----------------------------------------------------------------------------
// Global methods
// ----------------------------------------------------------------------------
function evaluate(normal, origin, x) {
return normal[0] * (x[0] - origin[0]) + normal[1] * (x[1] - origin[1]) + normal[2] * (x[2] - origin[2]);
}
function distanceToPlane(x, origin, normal) {
const distance = normal[0] * (x[0] - origin[0]) + normal[1] * (x[1] - origin[1]) + normal[2] * (x[2] - origin[2]);
return Math.abs(distance);
}
function projectPoint(x, origin, normal, xproj) {
const xo = [];
subtract(x, origin, xo);
const t = dot(normal, xo);
xproj[0] = x[0] - t * normal[0];
xproj[1] = x[1] - t * normal[1];
xproj[2] = x[2] - t * normal[2];
}
function projectVector(v, normal, vproj) {
const t = dot(v, normal);
let n2 = dot(normal, normal);
if (n2 === 0) {
n2 = 1.0;
}
vproj[0] = v[0] - t * normal[0] / n2;
vproj[1] = v[1] - t * normal[1] / n2;
vproj[2] = v[2] - t * normal[2] / n2;
return vproj;
}
function generalizedProjectPoint(x, origin, normal, xproj) {
const xo = [];
subtract(x, origin, xo);
const t = dot(normal, xo);
const n2 = dot(normal, normal);
if (n2 !== 0) {
xproj[0] = x[0] - t * normal[0] / n2;
xproj[1] = x[1] - t * normal[1] / n2;
xproj[2] = x[2] - t * normal[2] / n2;
} else {
xproj[0] = x[0];
xproj[1] = x[1];
xproj[2] = x[2];
}
}
function intersectWithLine(p1, p2, origin, normal) {
const outObj = {
intersection: false,
betweenPoints: false,
t: Number.MAX_VALUE,
x: []
};
const p21 = [];
const p1Origin = [];
// Compute line vector
subtract(p2, p1, p21);
subtract(origin, p1, p1Origin);
// Compute denominator. If ~0, line and plane are parallel.
// const num = vtkMath.dot(normal, origin) - vtkMath.dot(normal, p1);
const num = dot(normal, p1Origin);
const den = dot(normal, p21);
// If denominator with respect to numerator is "zero", then the line and
// plane are considered parallel.
let fabsden;
let fabstolerance;
// Trying to avoid an expensive call to fabs()
if (den < 0.0) {
fabsden = -den;
} else {
fabsden = den;
}
if (num < 0.0) {
fabstolerance = -num * PLANE_TOLERANCE;
} else {
fabstolerance = num * PLANE_TOLERANCE;
}
if (fabsden <= fabstolerance) {
return outObj;
}
// Where on the line between p1 and p2 is the intersection
// If between 0 and 1, it is between the two points. If < 0 it's before p1, if > 1 it's after p2
outObj.t = num / den;
outObj.x[0] = p1[0] + outObj.t * p21[0];
outObj.x[1] = p1[1] + outObj.t * p21[1];
outObj.x[2] = p1[2] + outObj.t * p21[2];
outObj.intersection = true;
outObj.betweenPoints = outObj.t >= 0.0 && outObj.t <= 1.0;
return outObj;
}
function intersectWithPlane(plane1Origin, plane1Normal, plane2Origin, plane2Normal) {
const outObj = {
intersection: false,
l0: [],
l1: [],
error: null
};
const cross$1 = [];
cross(plane1Normal, plane2Normal, cross$1);
const absCross = cross$1.map(n => Math.abs(n));
// test if the two planes are parallel
if (absCross[0] + absCross[1] + absCross[2] < PLANE_TOLERANCE) {
// test if disjoint or coincide
const v = [];
subtract(plane1Origin, plane2Origin, v);
if (dot(plane1Normal, v) === 0) {
outObj.error = COINCIDE;
} else {
outObj.error = DISJOINT;
}
return outObj;
}
// Plane1 and Plane2 intersect in a line
// first determine max abs coordinate of the cross product
let maxc;
if (absCross[0] > absCross[1] && absCross[0] > absCross[2]) {
maxc = 'x';
} else if (absCross[1] > absCross[2]) {
maxc = 'y';
} else {
maxc = 'z';
}
// To get a point on the intersect line, zero the max coord, and solve for the other two
const iP = []; // intersectionPoint
// the constants in the 2 plane equations
const d1 = -dot(plane1Normal, plane1Origin);
const d2 = -dot(plane2Normal, plane2Origin);
// eslint-disable-next-line default-case
switch (maxc) {
case 'x':
// intersect with x=0
iP[0] = 0;
iP[1] = (d2 * plane1Normal[2] - d1 * plane2Normal[2]) / cross$1[0];
iP[2] = (d1 * plane2Normal[1] - d2 * plane1Normal[1]) / cross$1[0];
break;
case 'y':
// intersect with y=0
iP[0] = (d1 * plane2Normal[2] - d2 * plane1Normal[2]) / cross$1[1];
iP[1] = 0;
iP[2] = (d2 * plane1Normal[0] - d1 * plane2Normal[0]) / cross$1[1];
break;
case 'z':
// intersect with z=0
iP[0] = (d2 * plane1Normal[1] - d1 * plane2Normal[1]) / cross$1[2];
iP[1] = (d1 * plane2Normal[0] - d2 * plane1Normal[0]) / cross$1[2];
iP[2] = 0;
break;
}
outObj.l0 = iP;
add(iP, cross$1, outObj.l1);
outObj.intersection = true;
return outObj;
}
// ----------------------------------------------------------------------------
// Static API
// ----------------------------------------------------------------------------
const STATIC = {
evaluate,
distanceToPlane,
projectPoint,
projectVector,
generalizedProjectPoint,
intersectWithLine,
intersectWithPlane,
DISJOINT,
COINCIDE
};
// ----------------------------------------------------------------------------
// vtkPlane methods
// ----------------------------------------------------------------------------
function vtkPlane(publicAPI, model) {
// Set our className
model.classHierarchy.push('vtkPlane');
publicAPI.distanceToPlane = x => distanceToPlane(x, model.origin, model.normal);
publicAPI.projectPoint = (x, xproj) => {
projectPoint(x, model.origin, model.normal, xproj);
};
publicAPI.projectVector = (v, vproj) => projectVector(v, model.normal, vproj);
publicAPI.push = distance => {
if (distance === 0.0) {
return;
}
for (let i = 0; i < 3; i++) {
model.origin[i] += distance * model.normal[i];
}
};
publicAPI.generalizedProjectPoint = (x, xproj) => {
generalizedProjectPoint(x, model.origin, model.normal, xproj);
};
publicAPI.evaluateFunction = (x, y, z) => {
if (!Array.isArray(x)) {
return model.normal[0] * (x - model.origin[0]) + model.normal[1] * (y - model.origin[1]) + model.normal[2] * (z - model.origin[2]);
}
return model.normal[0] * (x[0] - model.origin[0]) + model.normal[1] * (x[1] - model.origin[1]) + model.normal[2] * (x[2] - model.origin[2]);
};
publicAPI.evaluateGradient = xyz => {
const retVal = [model.normal[0], model.normal[1], model.normal[2]];
return retVal;
};
publicAPI.intersectWithLine = (p1, p2) => intersectWithLine(p1, p2, model.origin, model.normal);
publicAPI.intersectWithPlane = (planeOrigin, planeNormal) => intersectWithPlane(planeOrigin, planeNormal, model.origin, model.normal);
}
// ----------------------------------------------------------------------------
// Object factory
// ----------------------------------------------------------------------------
const DEFAULT_VALUES = {
normal: [0.0, 0.0, 1.0],
origin: [0.0, 0.0, 0.0]
};
// ----------------------------------------------------------------------------
function extend(publicAPI, model, initialValues = {}) {
Object.assign(model, DEFAULT_VALUES, initialValues);
// Object methods
vtkImplicitFunction.extend(publicAPI, model, initialValues);
macro.setGetArray(publicAPI, model, ['normal', 'origin'], 3);
vtkPlane(publicAPI, model);
}
// ----------------------------------------------------------------------------
const newInstance = macro.newInstance(extend, 'vtkPlane');
// ----------------------------------------------------------------------------
var vtkPlane$1 = {
newInstance,
extend,
...STATIC
};
export { STATIC, vtkPlane$1 as default, extend, newInstance, vtkPlane };