Line

Introduction

vtkLine is a cell which representant a line.
It contains static method to make some computations directly link to line.

See Also

vtkCell

Methods

distanceToLine

Compute the distance from x to the line composed by p1 and p2. If an object
is set as a fourth argument, then the closest point on the line from x will
be set into it.

{
t: tolerance of the distance
distance: quared distance between closest point and x
}
Argument Type Required Description
x Vector3 Yes
p1 Vector3 Yes
p2 Vector3 Yes
closestPoint Vector3 No

evaluateLocation

Determine the global coordinates x' and parametric coordinates pcoords’ in the cell.

evaluateOrientation

Determine the global orientation q' and parametric coordinates pcoords’ in the cell.
Use slerp to interpolate orientation
Returns wether the orientation has been set in `q’

extend

Method used to decorate a given object (publicAPI+model) with vtkLine characteristics.

Argument Type Required Description
publicAPI Yes object on which methods will be bounds (public)
model Yes object on which data structure will be bounds (protected)
initialValues ILineInitialValues No (default: {})

getCellDimension

Get the topological dimensional of the cell (0, 1, 2 or 3).

getOrientations

Get the list of orientations (a list of quat) for each point of the line.
Can be null if the line is not oriented

intersectWithLine

Compute the intersection point of the intersection between line and line
defined by p1 and p2. tol Tolerance use for the position evaluation x is
the point which intersect triangle (computed in function) pcoords
parametric coordinates (computed in function) A javascript object is
returned :

{
evaluation: define if the line has been intersected or not
subId: always set to 0
t: tolerance of the intersection
}
Argument Type Required Description
p1 Vector3 Yes The first point coordinate.
p2 Vector3 Yes The second point coordinate.
tol Number Yes The tolerance to use.
x Vector3 Yes The point which intersect triangle.
pcoords Vector3 Yes The parametric coordinates.

intersection

Performs intersection of two finite 3D lines. An intersection is found if the
projection of the two lines onto the plane perpendicular to the cross product
of the two lines intersect, and if the distance between the closest * points
of approach are within a relative tolerance. The parameters (u,v) are the
parametric coordinates of the lines at the position of closest approach.
Careful, u and v are filled inside the function. Outside the function, they
have to be access with : u[0] and v[0] return IntersectionState enum :

enum IntersectionState {
NO_INTERSECTION,
YES_INTERSECTION,
ON_LINE
}
Argument Type Required Description
a1 Vector3 Yes
a2 Vector3 Yes
b1 Vector3 Yes
b2 Vector3 Yes
u Vector3 Yes
v Vector3 Yes

newInstance

Method used to create a new instance of vtkLine.

Argument Type Required Description
initialValues ILineInitialValues No for pre-setting some of its content

setOrientations

Argument Type Required Description
orientations Yes The list of orientation per point of the centerline

Source

Constants.js
export const IntersectionState = {
NO_INTERSECTION: 0,
YES_INTERSECTION: 1,
ON_LINE: 2,
};

export default {
IntersectionState,
};
index.d.ts
import { quat } from 'gl-matrix';
import { Vector3, Vector2, Nullable } from '../../../types';
import vtkCell from '../Cell';

export enum IntersectionState {
NO_INTERSECTION,
YES_INTERSECTION,
ON_LINE,
}

export interface ILineInitialValues {
orientations: Nullable<quat[]>;
}

export interface IIntersectWithLine {
intersect: number;
t: number;
subId: number;
evaluation?: number;
betweenPoints?: boolean;
}

interface IDistanceToLine {
t: number;
distance: number;
}

export interface vtkLine extends vtkCell {
/**
* Get the topological dimensional of the cell (0, 1, 2 or 3).
*/
getCellDimension(): number;

/**
* Get the list of orientations (a list of quat) for each point of the line.
* Can be null if the line is not oriented
*/
getOrientations(): Nullable<quat[]>;

/**
* @see getOrientations
* @param orientations The list of orientation per point of the centerline
*/
setOrientations(orientations: Nullable<quat[]>): boolean;

/**
* Compute the intersection point of the intersection between line and line
* defined by p1 and p2. tol Tolerance use for the position evaluation x is
* the point which intersect triangle (computed in function) pcoords
* parametric coordinates (computed in function) A javascript object is
* returned :
*
* ```js
* {
* evaluation: define if the line has been intersected or not
* subId: always set to 0
* t: tolerance of the intersection
* }
* ```
* @param {Vector3} p1 The first point coordinate.
* @param {Vector3} p2 The second point coordinate.
* @param {Number} tol The tolerance to use.
* @param {Vector3} x The point which intersect triangle.
* @param {Vector3} pcoords The parametric coordinates.
*/
intersectWithLine(
p1: Vector3,
p2: Vector3,
tol: number,
x: Vector3,
pcoords: Vector3
): IIntersectWithLine;

/**
* Determine the global coordinates `x' and parametric coordinates `pcoords' in the cell.
*/
evaluateLocation(pcoords: Vector3, x: Vector3, weights: Vector2): void;

/**
* Determine the global orientation `q' and parametric coordinates `pcoords' in the cell.
* Use slerp to interpolate orientation
* Returns wether the orientation has been set in `q'
*/
evaluateOrientation(pcoords: Vector3, q: quat, weights: Vector2): boolean;
}

/**
* Method used to decorate a given object (publicAPI+model) with vtkLine characteristics.
*
* @param publicAPI object on which methods will be bounds (public)
* @param model object on which data structure will be bounds (protected)
* @param {ILineInitialValues} [initialValues] (default: {})
*/
export function extend(
publicAPI: object,
model: object,
initialValues?: ILineInitialValues
): void;

/**
* Method used to create a new instance of vtkLine.
* @param {ILineInitialValues} [initialValues] for pre-setting some of its content
*/
export function newInstance(initialValues?: ILineInitialValues): vtkLine;

/**
* Compute the distance from x to the line composed by p1 and p2. If an object
* is set as a fourth argument, then the closest point on the line from x will
* be set into it.
*
* ```js
* {
* t: tolerance of the distance
* distance: quared distance between closest point and x
* }
* ```
* @static
* @param {Vector3} x
* @param {Vector3} p1
* @param {Vector3} p2
* @param {Vector3} [closestPoint]
*/
export function distanceToLine(
x: Vector3,
p1: Vector3,
p2: Vector3,
closestPoint?: Vector3
): IDistanceToLine;

/**
* Performs intersection of two finite 3D lines. An intersection is found if the
* projection of the two lines onto the plane perpendicular to the cross product
* of the two lines intersect, and if the distance between the closest * points
* of approach are within a relative tolerance. The parameters (u,v) are the
* parametric coordinates of the lines at the position of closest approach.
* Careful, u and v are filled inside the function. Outside the function, they
* have to be access with : u[0] and v[0] return IntersectionState enum :
*
* ```js
* enum IntersectionState {
* NO_INTERSECTION,
* YES_INTERSECTION,
* ON_LINE
* }
* ```
* @static
* @param {Vector3} a1
* @param {Vector3} a2
* @param {Vector3} b1
* @param {Vector3} b2
* @param {Vector3} u
* @param {Vector3} v
*/
export function intersection(
a1: Vector3,
a2: Vector3,
b1: Vector3,
b2: Vector3,
u: Vector3,
v: Vector3
): IntersectionState;

/**
* vtkLine is a cell which representant a line.
* It contains static method to make some computations directly link to line.
*
* @see vtkCell
*/
export declare const vtkLine: {
newInstance: typeof newInstance;
extend: typeof extend;
distanceToLine: typeof distanceToLine;
intersection: typeof intersection;
};
export default vtkLine;
index.js
import macro from 'vtk.js/Sources/macros';
import Constants from 'vtk.js/Sources/Common/DataModel/Line/Constants';
import vtkCell from 'vtk.js/Sources/Common/DataModel/Cell';
import * as vtkMath from 'vtk.js/Sources/Common/Core/Math';
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 = vtkMath.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 = vtkMath.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.
vtkMath.subtract(a2, a1, a21);
vtkMath.subtract(b2, b1, b21);
vtkMath.subtract(b1, a1, b1a1);

// Compute the system (least squares) matrix.
const A = [
vtkMath.dot(a21, a21),
-vtkMath.dot(a21, b21),
-vtkMath.dot(a21, b21),
vtkMath.dot(b21, b21),
];

// Compute the least squares system constant term.
const c = [];
c[0] = vtkMath.dot(a21, b1a1);
c[1] = -vtkMath.dot(b21, b1a1);
// Solve the system of equations
if (vtkMath.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];
const uv1 = [v[0], v[0], u[0], u[0]];
const uv2 = [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;
uv1[i] = obj.t;
uv2[i] = i % 2;
}
}
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
// ----------------------------------------------------------------------------

export 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 (vtkMath.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
};

// ----------------------------------------------------------------------------

export function extend(publicAPI, model, initialValues = {}) {
Object.assign(model, DEFAULT_VALUES, initialValues);

vtkCell.extend(publicAPI, model, initialValues);

macro.setGet(publicAPI, model, ['orientations']);

vtkLine(publicAPI, model);
}

// ----------------------------------------------------------------------------

export const newInstance = macro.newInstance(extend, 'vtkLine');

// ----------------------------------------------------------------------------

export default { newInstance, extend, ...STATIC, ...Constants };