UNPKG

@kitware/vtk.js

Version:

Visualization Toolkit for the Web

259 lines (237 loc) 7.63 kB
import { m as macro } from '../../macros2.js'; import Constants from './Line/Constants.js'; import vtkCell from './Cell.js'; import { d as dot, f as distance2BetweenPoints, s as subtract, g as solveLinearSystem } from '../Core/Math/index.js'; import { quat } from 'gl-matrix'; const { IntersectionState } = Constants; // ---------------------------------------------------------------------------- // Global methods // ---------------------------------------------------------------------------- function distanceToLine(x, p1, p2, closestPoint = null) { const outObj = { t: Number.MIN_VALUE, distance: 0 }; const p21 = []; let closest; // Determine appropriate vector p21[0] = p2[0] - p1[0]; p21[1] = p2[1] - p1[1]; p21[2] = p2[2] - p1[2]; // Get parametric location const num = p21[0] * (x[0] - p1[0]) + p21[1] * (x[1] - p1[1]) + p21[2] * (x[2] - p1[2]); const denom = dot(p21, p21); // trying to avoid an expensive fabs let tolerance = 1e-5 * num; if (denom !== 0.0) { outObj.t = num / denom; } if (tolerance < 0.0) { tolerance = -tolerance; } if (-tolerance < denom && denom < tolerance) { closest = p1; } else if (denom <= 0.0 || outObj.t < 0.0) { // If parametric coordinate is within 0<=p<=1, then the point is closest to // the line. Otherwise, it's closest to a point at the end of the line. closest = p1; } else if (outObj.t > 1.0) { closest = p2; } else { closest = p21; p21[0] = p1[0] + outObj.t * p21[0]; p21[1] = p1[1] + outObj.t * p21[1]; p21[2] = p1[2] + outObj.t * p21[2]; } if (closestPoint) { closestPoint[0] = closest[0]; closestPoint[1] = closest[1]; closestPoint[2] = closest[2]; } outObj.distance = distance2BetweenPoints(closest, x); return outObj; } function intersection(a1, a2, b1, b2, u, v) { const a21 = []; const b21 = []; const b1a1 = []; u[0] = 0.0; v[0] = 0.0; // Determine line vectors. subtract(a2, a1, a21); subtract(b2, b1, b21); subtract(b1, a1, b1a1); // Compute the system (least squares) matrix. const A = [dot(a21, a21), -dot(a21, b21), -dot(a21, b21), dot(b21, b21)]; // Compute the least squares system constant term. const c = []; c[0] = dot(a21, b1a1); c[1] = -dot(b21, b1a1); // Solve the system of equations if (solveLinearSystem(A, c, 2) === 0) { // The lines are colinear. Therefore, one of the four endpoints is the // point of closest approach let minDist = Number.MAX_VALUE; const p = [a1, a2, b1, b2]; const l1 = [b1, b1, a1, a1]; const l2 = [b2, b2, a2, a2]; [v[0], v[0], u[0], u[0]]; [u[0], u[0], v[0], v[0]]; let obj; for (let i = 0; i < 4; i++) { obj = distanceToLine(p[i], l1[i], l2[i]); if (obj.distance < minDist) { minDist = obj.distance; obj.t; } } return IntersectionState.ON_LINE; } u[0] = c[0]; v[0] = c[1]; // Check parametric coordinates for intersection. if (u[0] >= 0.0 && u[0] <= 1.0 && v[0] >= 0.0 && v[0] <= 1.0) { return IntersectionState.YES_INTERSECTION; } return IntersectionState.NO_INTERSECTION; } // ---------------------------------------------------------------------------- // Static API // ---------------------------------------------------------------------------- const STATIC = { distanceToLine, intersection }; // ---------------------------------------------------------------------------- // vtkLine methods // ---------------------------------------------------------------------------- function vtkLine(publicAPI, model) { // Set our className model.classHierarchy.push('vtkLine'); function isBetweenPoints(t) { return t >= 0.0 && t <= 1.0; } publicAPI.getCellDimension = () => 1; publicAPI.intersectWithLine = (p1, p2, tol, x, pcoords) => { const outObj = { intersect: 0, t: Number.MAX_VALUE, subId: 0, betweenPoints: null }; pcoords[1] = 0.0; pcoords[2] = 0.0; const projXYZ = []; const a1 = []; const a2 = []; model.points.getPoint(0, a1); model.points.getPoint(1, a2); const u = []; const v = []; const intersect = intersection(p1, p2, a1, a2, u, v); outObj.t = u[0]; outObj.betweenPoints = isBetweenPoints(outObj.t); pcoords[0] = v[0]; if (intersect === IntersectionState.YES_INTERSECTION) { // make sure we are within tolerance for (let i = 0; i < 3; i++) { x[i] = a1[i] + pcoords[0] * (a2[i] - a1[i]); projXYZ[i] = p1[i] + outObj.t * (p2[i] - p1[i]); } if (distance2BetweenPoints(x, projXYZ) <= tol * tol) { outObj.intersect = 1; return outObj; } } else { let outDistance; // check to see if it lies within tolerance // one of the parametric coords must be outside 0-1 if (outObj.t < 0.0) { outDistance = distanceToLine(p1, a1, a2, x); if (outDistance.distance <= tol * tol) { outObj.t = 0.0; outObj.intersect = 1; outObj.betweenPoints = true; // Intersection is near p1 return outObj; } return outObj; } if (outObj.t > 1.0) { outDistance = distanceToLine(p2, a1, a2, x); if (outDistance.distance <= tol * tol) { outObj.t = 1.0; outObj.intersect = 1; outObj.betweenPoints = true; // Intersection is near p2 return outObj; } return outObj; } if (pcoords[0] < 0.0) { pcoords[0] = 0.0; outDistance = distanceToLine(a1, p1, p2, x); outObj.t = outDistance.t; if (outDistance.distance <= tol * tol) { outObj.intersect = 1; return outObj; } return outObj; } if (pcoords[0] > 1.0) { pcoords[0] = 1.0; outDistance = distanceToLine(a2, p1, p2, x); outObj.t = outDistance.t; if (outDistance.distance <= tol * tol) { outObj.intersect = 1; return outObj; } return outObj; } } return outObj; }; publicAPI.evaluateLocation = (pcoords, x, weights) => { const a1 = []; const a2 = []; model.points.getPoint(0, a1); model.points.getPoint(1, a2); for (let i = 0; i < 3; i++) { x[i] = a1[i] + pcoords[0] * (a2[i] - a1[i]); } weights[0] = 1.0 - pcoords[0]; weights[1] = pcoords[0]; }; publicAPI.evaluateOrientation = (pcoords, q, weights) => { if (model.orientations) { quat.slerp(q, model.orientations[0], model.orientations[1], pcoords[0]); weights[0] = 1.0 - pcoords[0]; weights[1] = pcoords[0]; return true; } return false; }; } // ---------------------------------------------------------------------------- // Object factory // ---------------------------------------------------------------------------- const DEFAULT_VALUES = { orientations: null // an array of two quat or null }; // ---------------------------------------------------------------------------- function extend(publicAPI, model, initialValues = {}) { Object.assign(model, DEFAULT_VALUES, initialValues); vtkCell.extend(publicAPI, model, initialValues); macro.setGet(publicAPI, model, ['orientations']); vtkLine(publicAPI, model); } // ---------------------------------------------------------------------------- const newInstance = macro.newInstance(extend, 'vtkLine'); // ---------------------------------------------------------------------------- var vtkLine$1 = { newInstance, extend, ...STATIC, ...Constants }; export { STATIC, vtkLine$1 as default, extend, newInstance };