PointPicker

Introduction

vtkPointPicker is used to select a point by shooting a ray into a graphics window
and intersecting with actor’s defining geometry - specifically its points.
Beside returning coordinates, actor, and mapper, vtkPointPicker returns the id of the point
projecting closest onto the ray (within the specified tolerance).
Ties are broken (i.e., multiple points all projecting within the tolerance along
the pick ray) by choosing the point closest to the ray origin (i.e., closest to the eye).

See Also

vtkPicker

vtkCellPicker

Methods

extend

Method use to decorate a given object (publicAPI+model) with vtkPointPicker 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 IPointPickerInitialValues No (default: {})

getPointIJK

getPointIJKByReference

getPointId

Get the id of the picked point.
If PointId = -1, nothing was picked.

getUseCells

intersectActorWithLine

Argument Type Required Description
p1 Vector3 Yes
p2 Vector3 Yes
tol Number Yes
mapper vtkMapper Yes

intersectWithLine

Argument Type Required Description
p1 Vector3 Yes
p2 Vector3 Yes
tol Number Yes
mapper vtkMapper Yes

newInstance

Method use to create a new instance of vtkPointPicker

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

setUseCells

Specify whether the point search should be based on cell points or directly on the point list.

Argument Type Required Description
useCells Yes

Source

index.d.ts
import vtkPicker, { IPickerInitialValues } from "../Picker";
import vtkMapper from "../Mapper";
import { Vector3 } from "../../../types";

interface IPointPickerInitialValues extends IPickerInitialValues {
pointId?: number;
pointIJK?: number[];
useCells?: boolean;
}

export interface vtkPointPicker extends vtkPicker {

/**
*
*/
getPointIJK(): number[];

/**
*
*/
getPointIJKByReference(): number[];

/**
* Get the id of the picked point.
* If PointId = -1, nothing was picked.
*/
getPointId(): number;

/**
*
*/
getUseCells(): boolean;

/**
*
* @param {Vector3} p1
* @param {Vector3} p2
* @param {Number} tol
* @param {vtkMapper} mapper
*/
intersectWithLine(p1: Vector3, p2: Vector3, tol: number, mapper: vtkMapper): number;

/**
*
* @param {Vector3} p1
* @param {Vector3} p2
* @param {Number} tol
* @param {vtkMapper} mapper
*/
intersectActorWithLine(p1: Vector3, p2: Vector3, tol: number, mapper: vtkMapper): number;

/**
* Specify whether the point search should be based on cell points or directly on the point list.
* @param useCells
*/
setUseCells(useCells: boolean): boolean;
}

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

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

/**
* vtkPointPicker is used to select a point by shooting a ray into a graphics window
* and intersecting with actor's defining geometry - specifically its points.
* Beside returning coordinates, actor, and mapper, vtkPointPicker returns the id of the point
* projecting closest onto the ray (within the specified tolerance).
* Ties are broken (i.e., multiple points all projecting within the tolerance along
* the pick ray) by choosing the point closest to the ray origin (i.e., closest to the eye).
*
* @see [vtkPicker](./Rendering_Core_Picker.html)
* @see [vtkCellPicker](./Rendering_Core_CellPicker.html)
*/
export declare const vtkPointPicker: {
newInstance: typeof newInstance,
extend: typeof extend,
};
export default vtkPointPicker;
index.js
import macro from 'vtk.js/Sources/macros';
import * as vtkMath from 'vtk.js/Sources/Common/Core/Math';
import vtkPicker from 'vtk.js/Sources/Rendering/Core/Picker';

const { vtkErrorMacro } = macro;

// ----------------------------------------------------------------------------
// vtkPointPicker methods
// ----------------------------------------------------------------------------

function vtkPointPicker(publicAPI, model) {
// Set our className
model.classHierarchy.push('vtkPointPicker');

publicAPI.intersectWithLine = (p1, p2, tol, actor, mapper) => {
let tMin = Number.MAX_VALUE;

if (mapper.isA('vtkImageMapper') || mapper.isA('vtkImageArrayMapper')) {
const pickData = mapper.intersectWithLineForPointPicking(p1, p2);
if (pickData) {
tMin = pickData.t;
model.pointIJK = pickData.ijk;
}
} else if (mapper.isA('vtkMapper')) {
tMin = publicAPI.intersectActorWithLine(p1, p2, tol, mapper);
}

return tMin;
};

publicAPI.intersectActorWithLine = (p1, p2, tol, mapper) => {
// Get dataset
const input = mapper.getInputData();

// Determine appropriate info
let ptId = 0;
const numPts = input.getPoints().getNumberOfPoints();

if (numPts <= ptId) {
return 2.0;
}

const ray = [];
for (let i = 0; i < 3; i++) {
ray[i] = p2[i] - p1[i];
}

const rayFactor = vtkMath.dot(ray, ray);
if (rayFactor === 0.0) {
vtkErrorMacro('Cannot process points');
return 2.0;
}

let t;
let minPtId = -1;
let tMin = Number.MAX_VALUE;
let minPtDist = Number.MAX_VALUE;
const projXYZ = [];
const minXYZ = [];
const x = [];
const points = input.getPoints();

if (model.useCells) {
const cellData = input.getPolys().getData();
const nbPointsPerCell = cellData[0];
const nbCells = input.getPolys().getNumberOfCells();

for (let cellID = 0; cellID < nbCells; cellID++) {
const firstPointIndex = cellID * nbPointsPerCell + 1;
const lastPointIndex = firstPointIndex + nbPointsPerCell;

for (
let pointIndex = firstPointIndex;
pointIndex < lastPointIndex;
pointIndex++
) {
const pointDataIndex = cellData[pointIndex];
points.getPoint(pointDataIndex, x);

t =
(ray[0] * (x[0] - p1[0]) +
ray[1] * (x[1] - p1[1]) +
ray[2] * (x[2] - p1[2])) /
rayFactor;

// If we find a point closer than we currently have, see whether it
// lies within the pick tolerance and clipping planes. We keep track
// of the point closest to the line (use a fudge factor for points
// nearly the same distance away.)
if (t >= 0.0 && t <= 1.0 && t <= tMin + model.tolerance) {
let maxDist = 0.0;
for (let i = 0; i < 3; i++) {
projXYZ[i] = p1[i] + t * ray[i];
const dist = Math.abs(x[i] - projXYZ[i]);
if (dist > maxDist) {
maxDist = dist;
}
} // end for i
if (maxDist <= tol && maxDist < minPtDist) {
// within tolerance
minPtId = ptId;
minXYZ[0] = x[0];
minXYZ[1] = x[1];
minXYZ[2] = x[2];
minPtDist = maxDist;
tMin = t;
}
}
} // end for pointIndex
} // end for cellID
} else {
// end if model.useCells
for (ptId = 0; ptId < numPts; ptId++) {
points.getPoint(ptId, x);

t =
(ray[0] * (x[0] - p1[0]) +
ray[1] * (x[1] - p1[1]) +
ray[2] * (x[2] - p1[2])) /
rayFactor;

// If we find a point closer than we currently have, see whether it
// lies within the pick tolerance and clipping planes. We keep track
// of the point closest to the line (use a fudge factor for points
// nearly the same distance away.)
if (t >= 0.0 && t <= 1.0 && t <= tMin + model.tolerance) {
let maxDist = 0.0;
for (let i = 0; i < 3; i++) {
projXYZ[i] = p1[i] + t * ray[i];
const dist = Math.abs(x[i] - projXYZ[i]);
if (dist > maxDist) {
maxDist = dist;
}
} // end for i
if (maxDist <= tol && maxDist < minPtDist) {
// within tolerance
minPtId = ptId;
minXYZ[0] = x[0];
minXYZ[1] = x[1];
minXYZ[2] = x[2];
minPtDist = maxDist;
tMin = t;
}
}
}
}

model.pointId = minPtId;
return tMin;
};
}

// ----------------------------------------------------------------------------
// Object factory
// ----------------------------------------------------------------------------

const DEFAULT_VALUES = {
pointId: -1,
pointIJK: [],
useCells: false,
};

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

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

// Inheritance
vtkPicker.extend(publicAPI, model, initialValues);

macro.getArray(publicAPI, model, ['pointIJK']);
macro.get(publicAPI, model, ['pointId']);
macro.setGet(publicAPI, model, ['useCells']);

vtkPointPicker(publicAPI, model);
}

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

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

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

export default { newInstance, extend };