@kitware/vtk.js 29.1.1 → 29.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Common/Core/DataArray.js +3 -0
- package/Common/DataModel/BoundingBox.d.ts +2 -2
- package/Common/DataModel/BoundingBox.js +2 -2
- package/Common/DataModel/Box.d.ts +23 -1
- package/Common/DataModel/Box.js +86 -3
- package/Common/DataModel/ITKHelper.js +1 -1
- package/Rendering/Core/CellPicker.js +20 -9
- package/package.json +1 -1
package/Common/Core/DataArray.js
CHANGED
|
@@ -514,6 +514,9 @@ function extend(publicAPI, model) {
|
|
|
514
514
|
// Object methods
|
|
515
515
|
obj(publicAPI, model);
|
|
516
516
|
set(publicAPI, model, ['name', 'numberOfComponents']);
|
|
517
|
+
if (model.size % model.numberOfComponents !== 0) {
|
|
518
|
+
throw new RangeError('model.size is not a multiple of model.numberOfComponents');
|
|
519
|
+
}
|
|
517
520
|
|
|
518
521
|
// Object specific methods
|
|
519
522
|
vtkDataArray(publicAPI, model);
|
|
@@ -202,7 +202,7 @@ export function getMaxPoint(bounds: Bounds): Vector3;
|
|
|
202
202
|
export function getCorners(bounds: Bounds, corners: Vector3[]): Vector3[];
|
|
203
203
|
|
|
204
204
|
/**
|
|
205
|
-
* Computes the two corner
|
|
205
|
+
* Computes the two corner points with min and max coords.
|
|
206
206
|
* @param {Bounds} bounds
|
|
207
207
|
* @param {Vector3} point1
|
|
208
208
|
* @param {Vector3} point2
|
|
@@ -502,7 +502,7 @@ declare class BoundingBox {
|
|
|
502
502
|
getCorners(bounds: Bounds, corners: Vector3[]): Vector3[];
|
|
503
503
|
|
|
504
504
|
/**
|
|
505
|
-
* Computes the two corner
|
|
505
|
+
* Computes the two corner points with min and max coords.
|
|
506
506
|
* @param {Bounds} bounds
|
|
507
507
|
* @param {Vector3} point1
|
|
508
508
|
* @param {Vector3} point2
|
|
@@ -210,7 +210,7 @@ function getCorners(bounds, corners) {
|
|
|
210
210
|
return corners;
|
|
211
211
|
}
|
|
212
212
|
|
|
213
|
-
// Computes the two corners with minimal and
|
|
213
|
+
// Computes the two corners with minimal and maximal coordinates
|
|
214
214
|
function computeCornerPoints(bounds, point1, point2) {
|
|
215
215
|
point1[0] = bounds[0];
|
|
216
216
|
point1[1] = bounds[2];
|
|
@@ -318,7 +318,7 @@ function intersectBox(bounds, origin, dir, coord, tolerance) {
|
|
|
318
318
|
}
|
|
319
319
|
}
|
|
320
320
|
|
|
321
|
-
// Check for
|
|
321
|
+
// Check for value intersection along line
|
|
322
322
|
if (maxT[whichPlane] > 1.0 || maxT[whichPlane] < 0.0) {
|
|
323
323
|
return 0;
|
|
324
324
|
}
|
|
@@ -6,6 +6,11 @@ export interface IBoxInitialValues {
|
|
|
6
6
|
bbox?: Bounds;
|
|
7
7
|
}
|
|
8
8
|
|
|
9
|
+
export interface IBoxIntersections {
|
|
10
|
+
t1, t2: number;
|
|
11
|
+
x1, x2: Vector3;
|
|
12
|
+
}
|
|
13
|
+
|
|
9
14
|
export interface vtkBox extends vtkObject {
|
|
10
15
|
|
|
11
16
|
/**
|
|
@@ -26,6 +31,16 @@ export interface vtkBox extends vtkObject {
|
|
|
26
31
|
*/
|
|
27
32
|
evaluateFunction(x: Vector3): number;
|
|
28
33
|
|
|
34
|
+
/**
|
|
35
|
+
* Intersect box with line and return the parametric values and points of the two intercepts
|
|
36
|
+
* @param bounds
|
|
37
|
+
* @param p1
|
|
38
|
+
* @param p2
|
|
39
|
+
* returns @object IBoxIntersections {t1, t2, x1, x2} object containing the t1, t2 parametric values and
|
|
40
|
+
* x1, x2 coordinates of the line intercept points in the bounding box or undefined
|
|
41
|
+
*/
|
|
42
|
+
intersectWithLine(p1: Vector3, p2: Vector3) : IBoxIntersections | undefined;
|
|
43
|
+
|
|
29
44
|
/**
|
|
30
45
|
*
|
|
31
46
|
* @param {Number} x The x coordinate.
|
|
@@ -61,6 +76,12 @@ export function extend(publicAPI: object, model: object, initialValues?: IBoxIni
|
|
|
61
76
|
*/
|
|
62
77
|
export function newInstance(initialValues?: IBoxInitialValues): vtkBox;
|
|
63
78
|
|
|
79
|
+
//------------------------------------------------------------------------------
|
|
80
|
+
// Bounding box intersection code from David Gobbi. Go through the
|
|
81
|
+
// bounding planes one at a time and compute the parametric coordinate
|
|
82
|
+
// of each intersection and return the parametric values and the calculated points
|
|
83
|
+
export function intersectWithLine(bounds, p1, p2): IBoxIntersections | undefined;
|
|
84
|
+
|
|
64
85
|
/**
|
|
65
86
|
* vtkBox provides methods for creating a 1D cubic spline object from given
|
|
66
87
|
* parameters, and allows for the calculation of the spline value and derivative
|
|
@@ -68,6 +89,7 @@ export function newInstance(initialValues?: IBoxInitialValues): vtkBox;
|
|
|
68
89
|
*/
|
|
69
90
|
export declare const vtkBox: {
|
|
70
91
|
newInstance: typeof newInstance,
|
|
71
|
-
extend: typeof extend
|
|
92
|
+
extend: typeof extend,
|
|
93
|
+
intersectWithLine: typeof intersectWithLine
|
|
72
94
|
};
|
|
73
95
|
export default vtkBox;
|
package/Common/DataModel/Box.js
CHANGED
|
@@ -5,6 +5,88 @@ import vtkBoundingBox from './BoundingBox.js';
|
|
|
5
5
|
// Global methods
|
|
6
6
|
// ----------------------------------------------------------------------------
|
|
7
7
|
|
|
8
|
+
//------------------------------------------------------------------------------
|
|
9
|
+
// Bounding box intersection code from David Gobbi. Go through the
|
|
10
|
+
// bounding planes one at a time and compute the parametric coordinate
|
|
11
|
+
// of each intersection and return the parametric values and the calculated points
|
|
12
|
+
function intersectWithLine(bounds, p1, p2) {
|
|
13
|
+
let plane1 = -1;
|
|
14
|
+
let plane2 = -1;
|
|
15
|
+
let t1 = 0.0;
|
|
16
|
+
let t2 = 1.0;
|
|
17
|
+
for (let j = 0; j < 3; j++) {
|
|
18
|
+
for (let k = 0; k < 2; k++) {
|
|
19
|
+
// Compute distances of p1 and p2 from the plane along the plane normal
|
|
20
|
+
const i = 2 * j + k;
|
|
21
|
+
const d1 = (bounds[i] - p1[j]) * (1 - 2 * k);
|
|
22
|
+
const d2 = (bounds[i] - p2[j]) * (1 - 2 * k);
|
|
23
|
+
|
|
24
|
+
// If both distances are positive, both points are outside
|
|
25
|
+
if (d1 > 0 && d2 > 0) {
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
// If one of the distances is positive, the line crosses the plane
|
|
29
|
+
if (d1 > 0 || d2 > 0) {
|
|
30
|
+
// Compute fractional distance "t" of the crossing between p1 & p2
|
|
31
|
+
let t = 0.0;
|
|
32
|
+
if (d1 !== 0) {
|
|
33
|
+
t = d1 / (d1 - d2);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// If point p1 was clipped, adjust t1
|
|
37
|
+
if (d1 > 0) {
|
|
38
|
+
if (t >= t1) {
|
|
39
|
+
t1 = t;
|
|
40
|
+
plane1 = i;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
// else point p2 was clipped, so adjust t2
|
|
44
|
+
else if (t <= t2) {
|
|
45
|
+
t2 = t;
|
|
46
|
+
plane2 = i;
|
|
47
|
+
}
|
|
48
|
+
// If this happens, there's no line left
|
|
49
|
+
if (t1 > t2) {
|
|
50
|
+
// Allow for planes that are coincident or slightly inverted
|
|
51
|
+
if (plane1 < 0 || plane2 < 0) {
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
function getValues(plane, t) {
|
|
59
|
+
const x = [0, 0, 0];
|
|
60
|
+
for (let count = 0; count < 2; count++) {
|
|
61
|
+
for (let i = 0; i < 3; i++) {
|
|
62
|
+
if (plane === 2 * i || plane === 2 * i + 1) {
|
|
63
|
+
x[i] = bounds[plane];
|
|
64
|
+
} else {
|
|
65
|
+
x[i] = p1[i] * (1.0 - t) + p2[i] * t;
|
|
66
|
+
if (x[i] < bounds[2 * i]) {
|
|
67
|
+
x[i] = bounds[2 * i];
|
|
68
|
+
}
|
|
69
|
+
if (x[i] > bounds[2 * i + 1]) {
|
|
70
|
+
x[i] = bounds[2 * i + 1];
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return x;
|
|
76
|
+
}
|
|
77
|
+
const x1 = getValues(plane1, t1);
|
|
78
|
+
const x2 = getValues(plane2, t2);
|
|
79
|
+
const outObject = {
|
|
80
|
+
t1,
|
|
81
|
+
t2,
|
|
82
|
+
x1,
|
|
83
|
+
x2
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
// eslint-disable-next-line consistent-return
|
|
87
|
+
return outObject;
|
|
88
|
+
}
|
|
89
|
+
|
|
8
90
|
// ----------------------------------------------------------------------------
|
|
9
91
|
// Static API
|
|
10
92
|
// ----------------------------------------------------------------------------
|
|
@@ -14,7 +96,6 @@ const STATIC = {};
|
|
|
14
96
|
// ----------------------------------------------------------------------------
|
|
15
97
|
// vtkBox methods
|
|
16
98
|
// ----------------------------------------------------------------------------
|
|
17
|
-
|
|
18
99
|
function vtkBox(publicAPI, model) {
|
|
19
100
|
// Set our className
|
|
20
101
|
model.classHierarchy.push('vtkBox');
|
|
@@ -67,7 +148,7 @@ function vtkBox(publicAPI, model) {
|
|
|
67
148
|
dist = point[i] - maxPoint[i];
|
|
68
149
|
}
|
|
69
150
|
if (dist > minDistance) {
|
|
70
|
-
// remember, it's
|
|
151
|
+
// remember, it's negative
|
|
71
152
|
minDistance = dist;
|
|
72
153
|
}
|
|
73
154
|
} // end if inside
|
|
@@ -103,6 +184,7 @@ function vtkBox(publicAPI, model) {
|
|
|
103
184
|
publicAPI.modified();
|
|
104
185
|
};
|
|
105
186
|
publicAPI.addBox = other => publicAPI.addBounds(other.getBounds());
|
|
187
|
+
publicAPI.intersectWithLine = (p1, p2) => intersectWithLine(model.bbox, p1, p2);
|
|
106
188
|
}
|
|
107
189
|
|
|
108
190
|
// ----------------------------------------------------------------------------
|
|
@@ -133,7 +215,8 @@ const newInstance = macro.newInstance(extend, 'vtkBox');
|
|
|
133
215
|
var vtkBox$1 = {
|
|
134
216
|
newInstance,
|
|
135
217
|
extend,
|
|
218
|
+
intersectWithLine,
|
|
136
219
|
...STATIC
|
|
137
220
|
};
|
|
138
221
|
|
|
139
|
-
export { STATIC, vtkBox$1 as default, extend, newInstance };
|
|
222
|
+
export { STATIC, vtkBox$1 as default, extend, intersectWithLine, newInstance };
|
|
@@ -241,7 +241,7 @@ function convertItkToVtkPolyData(itkPolyData) {
|
|
|
241
241
|
vtkClass: 'vtkPoints',
|
|
242
242
|
name: '_points',
|
|
243
243
|
numberOfComponents: 3,
|
|
244
|
-
size: itkPolyData.
|
|
244
|
+
size: itkPolyData.points.length,
|
|
245
245
|
dataType: 'Float32Array',
|
|
246
246
|
buffer: itkPolyData.points.buffer,
|
|
247
247
|
values: itkPolyData.points
|
|
@@ -5,10 +5,11 @@ import vtkPicker from './Picker.js';
|
|
|
5
5
|
import vtkPolyLine from '../../Common/DataModel/PolyLine.js';
|
|
6
6
|
import vtkTriangle from '../../Common/DataModel/Triangle.js';
|
|
7
7
|
import vtkQuad from '../../Common/DataModel/Quad.js';
|
|
8
|
-
import { l as normalize, G as isIdentity3x3 } from '../../Common/Core/Math/index.js';
|
|
8
|
+
import { l as normalize, G as isIdentity3x3, e as distance2BetweenPoints } from '../../Common/Core/Math/index.js';
|
|
9
9
|
import { CellType } from '../../Common/DataModel/CellTypes/Constants.js';
|
|
10
10
|
import { vec3, vec4 } from 'gl-matrix';
|
|
11
11
|
import vtkMatrixBuilder from '../../Common/Core/MatrixBuilder.js';
|
|
12
|
+
import vtkBox from '../../Common/DataModel/Box.js';
|
|
12
13
|
|
|
13
14
|
// ----------------------------------------------------------------------------
|
|
14
15
|
// Global methods
|
|
@@ -159,8 +160,8 @@ function vtkCellPicker(publicAPI, model) {
|
|
|
159
160
|
};
|
|
160
161
|
publicAPI.intersectWithLine = (p1, p2, tol, actor, mapper) => {
|
|
161
162
|
let tMin = Number.MAX_VALUE;
|
|
162
|
-
|
|
163
|
-
|
|
163
|
+
let t1 = 0.0;
|
|
164
|
+
let t2 = 1.0;
|
|
164
165
|
const vtkCellPickerPlaneTol = 1e-14;
|
|
165
166
|
const clipLine = clipLineWithPlane(mapper, model.transformMatrix, p1, p2);
|
|
166
167
|
if (mapper && !clipLine.intersect) {
|
|
@@ -174,7 +175,13 @@ function vtkCellPicker(publicAPI, model) {
|
|
|
174
175
|
model.pCoords = pickData.pCoords;
|
|
175
176
|
}
|
|
176
177
|
} else if (mapper.isA('vtkVolumeMapper')) {
|
|
177
|
-
|
|
178
|
+
// we calculate here the parametric intercept points between the ray and the bounding box, so
|
|
179
|
+
// if the application defines for some reason a too large ray length (1e6), it restrict the calculation
|
|
180
|
+
// to the vtkVolume actor bounding box
|
|
181
|
+
const interceptionObject = vtkBox.intersectWithLine(mapper.getBounds(), p1, p2);
|
|
182
|
+
t1 = interceptionObject?.t1 > clipLine.t1 ? interceptionObject.t1 : clipLine.t1;
|
|
183
|
+
t2 = interceptionObject?.t2 < clipLine.t2 ? interceptionObject.t2 : clipLine.t2;
|
|
184
|
+
tMin = publicAPI.intersectVolumeWithLine(p1, p2, t1, t2, tol, actor);
|
|
178
185
|
} else if (mapper.isA('vtkMapper')) {
|
|
179
186
|
tMin = publicAPI.intersectActorWithLine(p1, p2, t1, t2, tol, mapper);
|
|
180
187
|
}
|
|
@@ -255,16 +262,19 @@ function vtkCellPicker(publicAPI, model) {
|
|
|
255
262
|
const x1 = [0, 0, 0];
|
|
256
263
|
const x2 = [0, 0, 0];
|
|
257
264
|
for (let i = 0; i < 3; i++) {
|
|
258
|
-
x1[i] = (
|
|
259
|
-
x2[i] = (
|
|
265
|
+
x1[i] = (q1[i] - origin[i]) / spacing[i];
|
|
266
|
+
x2[i] = (q2[i] - origin[i]) / spacing[i];
|
|
260
267
|
}
|
|
261
268
|
const x = [0, 0, 0, 0];
|
|
262
269
|
const xi = [0, 0, 0];
|
|
263
270
|
const sliceSize = dims[1] * dims[0];
|
|
264
271
|
const rowSize = dims[0];
|
|
265
|
-
|
|
272
|
+
// here the step is the 1 over the distance between volume index location x1 and x2
|
|
273
|
+
const step = 1 / Math.sqrt(distance2BetweenPoints(x1, x2));
|
|
266
274
|
let insideVolume;
|
|
267
|
-
|
|
275
|
+
// here we reinterpret the t value as the distance between x1 and x2
|
|
276
|
+
// When calculating the tMin, we weight t between t1 and t2 values
|
|
277
|
+
for (let t = 0; t < 1; t += step) {
|
|
268
278
|
// calculate the location of the point
|
|
269
279
|
insideVolume = true;
|
|
270
280
|
for (let j = 0; j < 3; j++) {
|
|
@@ -297,7 +307,8 @@ function vtkCellPicker(publicAPI, model) {
|
|
|
297
307
|
value = Math.floor((value - oRange[0]) * scale);
|
|
298
308
|
const opacity = tmpTable[value];
|
|
299
309
|
if (opacity > model.opacityThreshold) {
|
|
300
|
-
tMin
|
|
310
|
+
// returning the tMin to the original scale, if t1 > 0 or t2 < 1
|
|
311
|
+
tMin = t1 * (1.0 - t) + t2 * t;
|
|
301
312
|
break;
|
|
302
313
|
}
|
|
303
314
|
}
|