Skip to content

Commit 2171b20

Browse files
authored
Merge pull request #2515 from WesleyTheGeolien/vtkQuad
Implement vtkQuad
2 parents 7845f6a + eac6167 commit 2171b20

File tree

7 files changed

+674
-82
lines changed

7 files changed

+674
-82
lines changed
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
export const QuadWithLineIntersectionState = {
2+
NO_INTERSECTION: 0,
3+
YES_INTERSECTION: 1,
4+
};
5+
6+
export default {
7+
QuadWithLineIntersectionState,
8+
};
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
import { Vector3, Vector4 } from '../../../types';
2+
import vtkCell, { ICellInitialValues } from '../Cell';
3+
import { IIntersectWithLine } from '../Triangle';
4+
5+
export interface IQuadInitialValues extends ICellInitialValues {}
6+
7+
export interface vtkQuad extends vtkCell {
8+
getCellType(): number;
9+
/**
10+
* Get the topological dimensional of the cell (0, 1, 2 or 3).
11+
*/
12+
getCellDimension(): number;
13+
getNumberOfEdges(): number;
14+
getNumberOfFaces(): number;
15+
16+
/**
17+
* Compute the intersection point of the intersection between quad and
18+
* line defined by p1 and p2. tol Tolerance use for the position evaluation
19+
* x is the point which intersect triangle (computed in function) pcoords
20+
* parametric coordinates (computed in function) A javascript object is
21+
* returned :
22+
*
23+
* ```js
24+
* {
25+
* evaluation: define if the triangle has been intersected or not
26+
* subId: always set to 0
27+
* t: parametric coordinate along the line.
28+
* betweenPoints: Define if the intersection is between input points
29+
* }
30+
* ```
31+
*
32+
* @param {Vector3} p1 The first point coordinate.
33+
* @param {Vector3} p2 The second point coordinate.
34+
* @param {Number} tol The tolerance to use.
35+
* @param {Vector3} x The point which intersect triangle.
36+
* @param {Vector3} pcoords The parametric coordinates.
37+
*/
38+
intersectWithLine(
39+
p1: Vector3,
40+
p2: Vector3,
41+
tol: number,
42+
x: Vector3,
43+
pcoords: Vector3
44+
): IIntersectWithLine;
45+
46+
/**
47+
* Determine global coordinate (x]) from subId and parametric coordinates.
48+
* @param {Vector3} pcoords The parametric coordinates.
49+
* @param {Vector3} x The x point coordinate.
50+
* @param {Number[]} weights The number of weights.
51+
*/
52+
evaluateLocation(pcoords: Vector3, x: Vector3, weights: number[]): void;
53+
54+
/*
55+
* Compute iso-parametric interpolation functions
56+
* @param {Vector3} pcoords The parametric coordinates.
57+
* @param {Vector4} sf out weights.
58+
*/
59+
interpolationFunctions(pcoords: Vector3, sf: Vector4);
60+
}
61+
62+
/**
63+
* Method used to decorate a given object (publicAPI+model) with vtkQuad characteristics.
64+
*
65+
* @param publicAPI object on which methods will be bounds (public)
66+
* @param model object on which data structure will be bounds (protected)
67+
* @param {IQuadInitialValues} [initialValues] (default: {})
68+
*/
69+
export function extend(
70+
publicAPI: object,
71+
model: object,
72+
initialValues?: IQuadInitialValues
73+
): void;
74+
75+
/**
76+
* Method used to create a new instance of vtkQuad.
77+
* @param {IQuadInitialValues} [initialValues] for pre-setting some of its content
78+
*/
79+
export function newInstance(initialValues?: IQuadInitialValues): vtkQuad;
80+
81+
/**
82+
* vtkQuad is a cell which represents a quadrilateral. It may contain static
83+
* methods to make some computations directly link to quads.
84+
*
85+
* @see vtkCell
86+
*/
87+
export declare const vtkQuad: {
88+
newInstance: typeof newInstance;
89+
extend: typeof extend;
90+
};
91+
export default vtkQuad;
Lines changed: 260 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,260 @@
1+
import macro from 'vtk.js/Sources/macros';
2+
import vtkCell from 'vtk.js/Sources/Common/DataModel/Cell';
3+
import * as vtkMath from 'vtk.js/Sources/Common/Core/Math';
4+
import { CellType } from 'vtk.js/Sources/Common/DataModel/CellTypes/Constants';
5+
import vtkTriangle from 'vtk.js/Sources/Common/DataModel/Triangle';
6+
import vtkPoints from 'vtk.js/Sources/Common/Core/Points';
7+
8+
function intersectionStruct() {
9+
return {
10+
intersected: false,
11+
subId: -1,
12+
x: [0.0, 0.0, 0.0],
13+
pCoords: [0.0, 0.0, 0.0],
14+
t: -1,
15+
};
16+
}
17+
18+
function vtkQuad(publicAPI, model) {
19+
// Set our className
20+
model.classHierarchy.push('vtkQuad');
21+
22+
publicAPI.getCellDimension = () => 2;
23+
publicAPI.getCellType = () => CellType.VTK_QUAD;
24+
publicAPI.getNumberOfEdges = () => 4;
25+
publicAPI.getNumberOfFaces = () => 0;
26+
27+
publicAPI.intersectWithLine = (p1, p2, tol, x, pcoords) => {
28+
let outObj = {
29+
subId: 0,
30+
t: Number.MAX_VALUE,
31+
intersect: 0,
32+
betweenPoints: false,
33+
};
34+
let diagonalCase;
35+
const point0 = model.points.getPoint(0, []);
36+
const point1 = model.points.getPoint(1, []);
37+
const point2 = model.points.getPoint(2, []);
38+
const point3 = model.points.getPoint(3, []);
39+
const d1 = vtkMath.distance2BetweenPoints(point0, point2);
40+
const d2 = vtkMath.distance2BetweenPoints(point1, point3);
41+
42+
/* Figure out how to uniquely tessellate the quad. Watch out for
43+
* equivalent triangulations (i.e., the triangulation is equivalent
44+
* no matter where the diagonal). In this case use the point ids as
45+
* a tie breaker to ensure unique triangulation across the quad.
46+
*/
47+
48+
// rare case; discriminate based on point id
49+
if (d1 === d2) {
50+
// find the maximum id
51+
let id;
52+
let maxId = 0;
53+
let maxIdx = 0;
54+
for (let i = 0; i < 4; i++) {
55+
id = model.pointsIds[i];
56+
if (id > maxId) {
57+
maxId = id;
58+
maxIdx = i;
59+
}
60+
}
61+
if (maxIdx === 0 || maxIdx === 2) {
62+
diagonalCase = 0;
63+
} else {
64+
diagonalCase = 1;
65+
}
66+
} else if (d1 < d2) {
67+
diagonalCase = 0;
68+
} else {
69+
diagonalCase = 1;
70+
}
71+
let points = null;
72+
if (!model.triangle) {
73+
model.triangle = vtkTriangle.newInstance();
74+
points = vtkPoints.newInstance();
75+
points.setNumberOfPoints(3);
76+
model.triangle.initialize(points);
77+
} else {
78+
points = model.triangle.getPoints();
79+
}
80+
81+
let firstIntersect;
82+
const firstIntersectTmpObj = intersectionStruct();
83+
84+
let secondIntersect;
85+
const secondIntersectTmpObj = intersectionStruct();
86+
87+
let useFirstIntersection;
88+
let useSecondIntersection;
89+
90+
switch (diagonalCase) {
91+
case 0:
92+
points.setPoint(0, ...point0);
93+
points.setPoint(1, ...point1);
94+
points.setPoint(2, ...point2);
95+
firstIntersect = model.triangle.intersectWithLine(
96+
p1,
97+
p2,
98+
tol,
99+
firstIntersectTmpObj.x,
100+
firstIntersectTmpObj.pCoords
101+
);
102+
103+
points.setPoint(0, ...point2);
104+
points.setPoint(1, ...point3);
105+
points.setPoint(2, ...point0);
106+
secondIntersect = model.triangle.intersectWithLine(
107+
p1,
108+
p2,
109+
tol,
110+
secondIntersectTmpObj.x,
111+
secondIntersectTmpObj.pCoords
112+
);
113+
114+
useFirstIntersection =
115+
firstIntersect.intersect && secondIntersect.intersect
116+
? firstIntersect.t <= secondIntersect.t
117+
: firstIntersect.intersect;
118+
119+
useSecondIntersection =
120+
firstIntersect.intersect && secondIntersect.intersect
121+
? secondIntersect.t < firstIntersect.t
122+
: secondIntersect.intersect;
123+
124+
if (useFirstIntersection) {
125+
outObj = firstIntersect;
126+
127+
x[0] = firstIntersectTmpObj.x[0];
128+
x[1] = firstIntersectTmpObj.x[1];
129+
x[2] = firstIntersectTmpObj.x[2];
130+
131+
pcoords[0] =
132+
firstIntersectTmpObj.pCoords[0] + firstIntersectTmpObj.pCoords[1];
133+
pcoords[1] = firstIntersectTmpObj.pCoords[1];
134+
pcoords[2] = firstIntersectTmpObj.pCoords[2];
135+
} else if (useSecondIntersection) {
136+
outObj = secondIntersect;
137+
x[0] = secondIntersectTmpObj.x[0];
138+
x[1] = secondIntersectTmpObj.x[1];
139+
x[2] = secondIntersectTmpObj.x[2];
140+
141+
pcoords[0] =
142+
1.0 -
143+
(secondIntersectTmpObj.pCoords[0] +
144+
secondIntersectTmpObj.pCoords[1]);
145+
pcoords[1] = 1 - secondIntersectTmpObj.pCoords[1];
146+
pcoords[2] = secondIntersectTmpObj.pCoords[2];
147+
}
148+
149+
break;
150+
case 1:
151+
points.setPoint(0, ...point0);
152+
points.setPoint(1, ...point1);
153+
points.setPoint(2, ...point3);
154+
firstIntersect = model.triangle.intersectWithLine(
155+
p1,
156+
p2,
157+
tol,
158+
firstIntersectTmpObj.x,
159+
firstIntersectTmpObj.pCoords
160+
);
161+
162+
points.setPoint(0, ...point2);
163+
points.setPoint(1, ...point3);
164+
points.setPoint(2, ...point1);
165+
secondIntersect = model.triangle.intersectWithLine(
166+
p1,
167+
p2,
168+
tol,
169+
secondIntersectTmpObj.x,
170+
secondIntersectTmpObj.pCoords
171+
);
172+
173+
useFirstIntersection =
174+
firstIntersect.intersect && secondIntersect.intersect
175+
? firstIntersect.t <= secondIntersect.t
176+
: firstIntersect.intersect;
177+
178+
useSecondIntersection =
179+
firstIntersect.intersect && secondIntersect.intersect
180+
? secondIntersect.t < firstIntersect.t
181+
: secondIntersect.intersect;
182+
183+
if (useFirstIntersection) {
184+
outObj = firstIntersect;
185+
x[0] = firstIntersectTmpObj.x[0];
186+
x[1] = firstIntersectTmpObj.x[1];
187+
x[2] = firstIntersectTmpObj.x[2];
188+
189+
pcoords[0] = firstIntersectTmpObj.pCoords[0];
190+
pcoords[1] = firstIntersectTmpObj.pCoords[1];
191+
pcoords[2] = firstIntersectTmpObj.pCoords[2];
192+
} else if (useSecondIntersection) {
193+
outObj = secondIntersect;
194+
195+
x[0] = secondIntersectTmpObj.x[0];
196+
x[1] = secondIntersectTmpObj.x[1];
197+
x[2] = secondIntersectTmpObj.x[2];
198+
pcoords[0] = 1 - secondIntersectTmpObj.pCoords[0];
199+
pcoords[1] = 1 - secondIntersectTmpObj.pCoords[1];
200+
pcoords[2] = secondIntersectTmpObj.pCoords[2];
201+
}
202+
break;
203+
default:
204+
break;
205+
}
206+
return outObj;
207+
};
208+
209+
publicAPI.interpolationFunctions = (pcoords, weights) => {
210+
const rm = 1 - pcoords[0];
211+
const sm = 1 - pcoords[1];
212+
213+
weights[0] = rm * sm;
214+
weights[1] = pcoords[0] * sm;
215+
weights[2] = pcoords[0] * pcoords[1];
216+
weights[3] = rm * pcoords[1];
217+
};
218+
219+
publicAPI.evaluateLocation = (pcoords, x, weights) => {
220+
const point = [];
221+
222+
// Calculate the weights
223+
publicAPI.interpolationFunctions(pcoords, weights);
224+
225+
x[0] = 0.0;
226+
x[1] = 0.0;
227+
x[2] = 0.0;
228+
229+
for (let i = 0; i < 4; i++) {
230+
model.points.getPoint(i, point);
231+
for (let j = 0; j < 3; j++) {
232+
x[j] += point[j] * weights[i];
233+
}
234+
}
235+
};
236+
}
237+
238+
// ----------------------------------------------------------------------------
239+
// Object factory
240+
// ----------------------------------------------------------------------------
241+
242+
const DEFAULT_VALUES = {};
243+
244+
// ----------------------------------------------------------------------------
245+
246+
export function extend(publicAPI, model, initialValues = {}) {
247+
Object.assign(model, DEFAULT_VALUES, initialValues);
248+
249+
vtkCell.extend(publicAPI, model, initialValues);
250+
251+
vtkQuad(publicAPI, model);
252+
}
253+
254+
// ----------------------------------------------------------------------------
255+
256+
export const newInstance = macro.newInstance(extend, 'vtkQuad');
257+
258+
// ----------------------------------------------------------------------------
259+
260+
export default { newInstance, extend };

0 commit comments

Comments
 (0)