xl-public-utils 1.0.4 → 1.0.5
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/index.d.ts +15 -35
- package/index.js +2 -1
- package/package.json +12 -4
- package/src/drcUtils.mjs +353 -0
- package/src/exportPLY.mjs +285 -0
- package/src/exportSTL.mjs +222 -0
- package/src/qrcode.mjs +16 -16
- package/src/utils.mjs +43 -1
- package/src/vtkUtils.mjs +780 -1
- package/tsconfig.json +9 -0
- package/types/bwip-js.d.mts +106 -0
- package/types/bwipp.d.mts +5 -0
- package/types/drcUtils.d.mts +129 -0
- package/types/exportPLY.d.mts +16 -0
- package/types/exportSTL.d.mts +20 -0
- package/types/qrcode.d.mts +92 -0
- package/types/utils.d.mts +28 -0
- package/types/vtkUtils.d.mts +320 -0
package/src/vtkUtils.mjs
CHANGED
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
import vtkRenderer from "@kitware/vtk.js/Rendering/Core/Renderer";
|
|
2
|
-
|
|
2
|
+
import vtkInteractorStyleManipulator from "@kitware/vtk.js/Interaction/Style/InteractorStyleManipulator"
|
|
3
|
+
import vtkMouseCameraTrackballPanManipulator from "@kitware/vtk.js/Interaction/Manipulators/MouseCameraTrackballPanManipulator";
|
|
4
|
+
import vtkMouseCameraTrackballRotateManipulator from "@kitware/vtk.js/Interaction/Manipulators/MouseCameraTrackballRotateManipulator";
|
|
5
|
+
import vtkMouseCameraTrackballZoomManipulator from "@kitware/vtk.js/Interaction/Manipulators/MouseCameraTrackballZoomManipulator";
|
|
6
|
+
import vtkRenderWindowInteractor from "@kitware/vtk.js/Rendering/Core/RenderWindowInteractor";
|
|
7
|
+
import vtkMatrixBuilder from "@kitware/vtk.js/Common/Core/MatrixBuilder";
|
|
8
|
+
import { vec3, mat4, mat3 } from 'gl-matrix';
|
|
9
|
+
import vtkPolyData from "@kitware/vtk.js/Common/DataModel/PolyData";
|
|
10
|
+
import { exportBinarySTL } from './exportSTL.mjs';
|
|
11
|
+
import { writePLY } from "./exportPLY.mjs";
|
|
12
|
+
import { enCodeMesh } from './drcUtils.mjs';
|
|
13
|
+
import { int8ArrayToBase64 } from "./utils.mjs";
|
|
3
14
|
|
|
4
15
|
/**
|
|
5
16
|
* 计算屏幕坐标到三维坐标
|
|
@@ -25,4 +36,772 @@ export function computeDisplayToWorld(renderer, x, y, z) {
|
|
|
25
36
|
export function computeWorldToDisplay(renderer, x, y, z) {
|
|
26
37
|
const view = renderer.getRenderWindow().getViews()[0];
|
|
27
38
|
return view.worldToDisplay(x, y, z, renderer);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* 计算 w2l(word 2 local, word to local) 的变换矩阵
|
|
43
|
+
* @param {vec3} center 中心点
|
|
44
|
+
* @param {vec3} xaxis x轴
|
|
45
|
+
* @param {vec3} yaxis y轴
|
|
46
|
+
* @param {vec3} zaxis z轴
|
|
47
|
+
* @returns { mat4 } 变换矩阵
|
|
48
|
+
*/
|
|
49
|
+
|
|
50
|
+
export function getW2LMatrix(
|
|
51
|
+
center,
|
|
52
|
+
xaxis,
|
|
53
|
+
yaxis,
|
|
54
|
+
zaxis
|
|
55
|
+
) {
|
|
56
|
+
let rmat = mat4.create();
|
|
57
|
+
rmat[0] = xaxis[0];
|
|
58
|
+
rmat[4] = xaxis[1];
|
|
59
|
+
rmat[8] = xaxis[2];
|
|
60
|
+
rmat[12] = 0;
|
|
61
|
+
|
|
62
|
+
rmat[1] = yaxis[0];
|
|
63
|
+
rmat[5] = yaxis[1];
|
|
64
|
+
rmat[9] = yaxis[2];
|
|
65
|
+
rmat[13] = 0;
|
|
66
|
+
|
|
67
|
+
rmat[2] = zaxis[0];
|
|
68
|
+
rmat[6] = zaxis[1];
|
|
69
|
+
rmat[10] = zaxis[2];
|
|
70
|
+
rmat[14] = 0;
|
|
71
|
+
|
|
72
|
+
rmat[3] = 0;
|
|
73
|
+
rmat[7] = 0;
|
|
74
|
+
rmat[11] = 0;
|
|
75
|
+
rmat[15] = 1;
|
|
76
|
+
|
|
77
|
+
mat4.invert(rmat, rmat);
|
|
78
|
+
|
|
79
|
+
let tmat = mat4.create();
|
|
80
|
+
mat4.identity(tmat);
|
|
81
|
+
tmat[3] = -center[0];
|
|
82
|
+
tmat[7] = -center[1];
|
|
83
|
+
tmat[11] = -center[2];
|
|
84
|
+
mat4.multiply(rmat, tmat, rmat);
|
|
85
|
+
|
|
86
|
+
return mat4.transpose(rmat, rmat);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Alias for {@link getW2LMatrix}
|
|
92
|
+
* @function
|
|
93
|
+
*/
|
|
94
|
+
export const getmatw2l = getW2LMatrix;
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* 计算 l2w(local 2 word, local to word) 的变换矩阵
|
|
98
|
+
* @param {vec3} center 中心点
|
|
99
|
+
* @param {vec3} xaxis x轴
|
|
100
|
+
* @param {vec3} yaxis y轴
|
|
101
|
+
* @param {vec3} zaxis z轴
|
|
102
|
+
* @returns { mat4 } 变换矩阵
|
|
103
|
+
*/
|
|
104
|
+
|
|
105
|
+
export function getL2WMatrix(
|
|
106
|
+
center,
|
|
107
|
+
xaxis,
|
|
108
|
+
yaxis,
|
|
109
|
+
zaxis
|
|
110
|
+
) {
|
|
111
|
+
let rmat = mat4.create();
|
|
112
|
+
rmat[0] = xaxis[0];
|
|
113
|
+
rmat[4] = xaxis[1];
|
|
114
|
+
rmat[8] = xaxis[2];
|
|
115
|
+
rmat[12] = 0;
|
|
116
|
+
|
|
117
|
+
rmat[1] = yaxis[0];
|
|
118
|
+
rmat[5] = yaxis[1];
|
|
119
|
+
rmat[9] = yaxis[2];
|
|
120
|
+
rmat[13] = 0;
|
|
121
|
+
|
|
122
|
+
rmat[2] = zaxis[0];
|
|
123
|
+
rmat[6] = zaxis[1];
|
|
124
|
+
rmat[10] = zaxis[2];
|
|
125
|
+
rmat[14] = 0;
|
|
126
|
+
|
|
127
|
+
rmat[3] = 0;
|
|
128
|
+
rmat[7] = 0;
|
|
129
|
+
rmat[11] = 0;
|
|
130
|
+
rmat[15] = 1;
|
|
131
|
+
|
|
132
|
+
let tmat = mat4.create();
|
|
133
|
+
mat4.identity(tmat);
|
|
134
|
+
tmat[3] = center[0];
|
|
135
|
+
tmat[7] = center[1];
|
|
136
|
+
tmat[11] = center[2];
|
|
137
|
+
|
|
138
|
+
mat4.multiply(rmat, rmat, tmat);
|
|
139
|
+
return mat4.transpose(rmat, rmat);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Alias for {@link getL2WMatrix}
|
|
145
|
+
* @function
|
|
146
|
+
*/
|
|
147
|
+
export const getmatofl2w = getL2WMatrix;
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* 返回交互的interactorStyle
|
|
151
|
+
* @returns {vtkInteractorStyleManipulator} 交互的interactorStyle
|
|
152
|
+
*/
|
|
153
|
+
export function make3DInteractorStyle() {
|
|
154
|
+
const interactorStyle = vtkInteractorStyleManipulator.newInstance();
|
|
155
|
+
const cameraRotate = vtkMouseCameraTrackballRotateManipulator.newInstance({
|
|
156
|
+
button: 1,
|
|
157
|
+
});
|
|
158
|
+
const cameraPan = vtkMouseCameraTrackballPanManipulator.newInstance({
|
|
159
|
+
button: 3,
|
|
160
|
+
});
|
|
161
|
+
// const cameraPanControl = vtkMouseCameraTrackballPanManipulator.newInstance({
|
|
162
|
+
// button: 1,
|
|
163
|
+
// shift: true,
|
|
164
|
+
// });
|
|
165
|
+
// const cameraRoll = vtkMouseCameraTrackballRollManipulator.newInstance({
|
|
166
|
+
// button: 3,
|
|
167
|
+
// control: true,
|
|
168
|
+
// });
|
|
169
|
+
const cameraZoom = vtkMouseCameraTrackballZoomManipulator.newInstance({
|
|
170
|
+
button: 2,
|
|
171
|
+
});
|
|
172
|
+
const cameraZoomDrag = vtkMouseCameraTrackballZoomManipulator.newInstance({
|
|
173
|
+
scrollEnabled: true,
|
|
174
|
+
dragEnabled: false,
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
interactorStyle.addMouseManipulator(cameraRotate);
|
|
178
|
+
interactorStyle.addMouseManipulator(cameraPan);
|
|
179
|
+
// interactorStyle.addMouseManipulator(cameraPanControl);
|
|
180
|
+
// interactorStyle.addMouseManipulator(cameraRoll);
|
|
181
|
+
// interactorStyle.addMouseManipulator(cameraZoom);
|
|
182
|
+
interactorStyle.addMouseManipulator(cameraZoomDrag);
|
|
183
|
+
return interactorStyle;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* 移除并返回当前renderWindow的所有鼠标交互设定
|
|
188
|
+
* @param {vtkRenderWindowInteractor} interactor vtkRenderWindowInteractor
|
|
189
|
+
* @returns {any[]} 当前鼠标的所有交互Manipulators
|
|
190
|
+
*/
|
|
191
|
+
|
|
192
|
+
export function removeMouseInteraction(interactor) {
|
|
193
|
+
const interactorStyle = interactor.getInteractorStyle();
|
|
194
|
+
const mm = interactorStyle.getMouseManipulators();
|
|
195
|
+
interactorStyle.removeAllMouseManipulators();
|
|
196
|
+
return mm;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* 给当前窗口设置交互Maintainers
|
|
201
|
+
* @param {vtkRenderWindowInteractor} interactor vtkRenderWindowInteractor
|
|
202
|
+
* @param {any[]} mm 所有的交互Maintainers
|
|
203
|
+
* @returns {void}
|
|
204
|
+
*/
|
|
205
|
+
export function resetAllMouseMaintainers(interactor, mm) {
|
|
206
|
+
const interactorStyle = interactor.getInteractorStyle();
|
|
207
|
+
mm.forEach(element => {
|
|
208
|
+
interactorStyle.addMouseManipulator(element);
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* 将点投影到平面上
|
|
214
|
+
* @param {vec3} point 需要投影的点
|
|
215
|
+
* @param {vec3} origin 平面中心点
|
|
216
|
+
* @param {vec3} normal 平面法向量
|
|
217
|
+
* @returns {vec3} 投影到平面之后的点
|
|
218
|
+
*/
|
|
219
|
+
export function projectPointToPlane(point, origin, normal) {
|
|
220
|
+
const xo = vec3.sub(vec3.create(), point, origin);
|
|
221
|
+
let t = vec3.dot(normal, xo);
|
|
222
|
+
let xproj = vec3.sub(vec3.create(), point, vec3.scale(vec3.create(), normal, t));
|
|
223
|
+
return xproj;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* 将向量投影到面上
|
|
228
|
+
*
|
|
229
|
+
* @param {vec3} vec - The vector to project.
|
|
230
|
+
* @param {vec3} norm - The normal vector of the plane (assumed to be normalized).
|
|
231
|
+
* @returns {vec3} - The projected vector on the plane.
|
|
232
|
+
*/
|
|
233
|
+
export function projectVecToPlane(vec, norm) {
|
|
234
|
+
// Calculate the dot product of the vector and the normal
|
|
235
|
+
const dotProduct = vec3.dot(vec, norm);
|
|
236
|
+
|
|
237
|
+
// Calculate the projection vector along the normal direction
|
|
238
|
+
const projectionOnNormal = vec3.scale(vec3.create(), norm, dotProduct);
|
|
239
|
+
|
|
240
|
+
// Subtract the projection on the normal from the original vector
|
|
241
|
+
const projectedVec = vec3.subtract(vec3.create(), vec, projectionOnNormal);
|
|
242
|
+
|
|
243
|
+
return projectedVec;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* 将直线外一点投影到直线(两个点)上
|
|
249
|
+
* @param {vec3} point 直线外一点
|
|
250
|
+
* @param {vec3} begin 直线开始点
|
|
251
|
+
* @param {vec3} end 直线结束点
|
|
252
|
+
* @returns {vec3} 投影后的点
|
|
253
|
+
*/
|
|
254
|
+
export function projectPointOnPoints(point, begin, end) {
|
|
255
|
+
const dx = begin[0] - end[0];
|
|
256
|
+
const dy = begin[1] - end[1];
|
|
257
|
+
const dz = begin[2] - end[2];
|
|
258
|
+
const EPS = 0.00000001;
|
|
259
|
+
|
|
260
|
+
// 确保两个点不是同一个点
|
|
261
|
+
if (Math.abs(dx) < EPS && Math.abs(dy) < EPS && Math.abs(dz) < EPS) {
|
|
262
|
+
return begin;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
//计算斜率
|
|
266
|
+
let u =
|
|
267
|
+
(point[0] - begin[0]) * (begin[0] - end[0]) +
|
|
268
|
+
(point[1] - begin[1]) * (begin[1] - end[1]) +
|
|
269
|
+
(point[2] - begin[2]) * (begin[2] - end[2]);
|
|
270
|
+
u = u / (Math.pow(dx, 2) + Math.pow(dy, 2) + Math.pow(dz, 2));
|
|
271
|
+
|
|
272
|
+
return vec3.set(
|
|
273
|
+
vec3.create(),
|
|
274
|
+
begin[0] + u * dx,
|
|
275
|
+
begin[1] + u * dy,
|
|
276
|
+
begin[2] + u * dz
|
|
277
|
+
);
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
/**
|
|
281
|
+
* 将点投影到直线(point+dir)上
|
|
282
|
+
* @param {vec3} point 直线外的点
|
|
283
|
+
* @param {vec3} linePoint 直线任意一点
|
|
284
|
+
* @param {vec3} lineDir 直线方向
|
|
285
|
+
* @returns {vec3} 投影到直线上后的点
|
|
286
|
+
*/
|
|
287
|
+
|
|
288
|
+
export function projectPointToLine(
|
|
289
|
+
point,
|
|
290
|
+
linePoint,
|
|
291
|
+
lineDir,
|
|
292
|
+
) {
|
|
293
|
+
const t =
|
|
294
|
+
vec3.dot(vec3.sub(vec3.create(), point, linePoint), lineDir) /
|
|
295
|
+
vec3.squaredLength(lineDir);
|
|
296
|
+
return vec3.add(
|
|
297
|
+
vec3.create(),
|
|
298
|
+
linePoint,
|
|
299
|
+
vec3.scale(vec3.create(), lineDir, t)
|
|
300
|
+
);
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
/**
|
|
304
|
+
* 获取曲线外一点到曲线最近点的索引
|
|
305
|
+
* @param {vec3} point 曲线外一点
|
|
306
|
+
* @param {vec3[]} points 曲线
|
|
307
|
+
* @returns {number} 返回离点最近的曲线点索引
|
|
308
|
+
*/
|
|
309
|
+
export function getPointToPointsMinIndex(point, points) {
|
|
310
|
+
let index = 0;
|
|
311
|
+
let dist = vec3.dist(point, points[0]);
|
|
312
|
+
for (let i = 1; i < points.length; i++) {
|
|
313
|
+
const iDist = vec3.dist(point, points[i]);
|
|
314
|
+
if (iDist < dist) {
|
|
315
|
+
dist = iDist;
|
|
316
|
+
index = i;
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
return index;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
/**
|
|
323
|
+
* 获取点到曲线的最近距离
|
|
324
|
+
* @param {vec3} point 曲线外一点
|
|
325
|
+
* @param {vec3[]} points 曲线
|
|
326
|
+
* @returns {number} 返回点到曲线的最近距离
|
|
327
|
+
*/
|
|
328
|
+
export function getPointToPointsMinDist(point, points) {
|
|
329
|
+
let dist = vec3.dist(point, points[0]);
|
|
330
|
+
for (let i = 1; i < points.length; i++) {
|
|
331
|
+
const iDist = vec3.dist(point, points[i]);
|
|
332
|
+
if (iDist < dist) {
|
|
333
|
+
dist = iDist;
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
return dist;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
|
|
340
|
+
/**
|
|
341
|
+
* 获取点到曲线的最近点
|
|
342
|
+
* @param {vec3} point 曲线外一点
|
|
343
|
+
* @param {vec3[]} points 曲线
|
|
344
|
+
* @returns {vec3} 返回点到曲线的最近点
|
|
345
|
+
*/
|
|
346
|
+
|
|
347
|
+
export function getPointToPointsMinPoint(point, points) {
|
|
348
|
+
const index = getPointToPointsMinIndex(point, points);
|
|
349
|
+
return points[index];
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
|
|
353
|
+
/**
|
|
354
|
+
* 获取直线外一点到直线的距离
|
|
355
|
+
* @param {vec3} point 直线外一点
|
|
356
|
+
* @param {vec3} begin 直线开始点
|
|
357
|
+
* @param {vec3} end 直线结束点
|
|
358
|
+
* @returns {number} 点到直线的距离
|
|
359
|
+
*/
|
|
360
|
+
|
|
361
|
+
export function getPointToLineDist(point, begin, end) {
|
|
362
|
+
const linePoint = projectPointOnPoints(point, begin, end);
|
|
363
|
+
return vec3.dist(linePoint, point);
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
/**
|
|
367
|
+
* 计算点到平面的距离
|
|
368
|
+
* @param {vec3} point 任意一点
|
|
369
|
+
* @param {vec3} origin 平面上一点
|
|
370
|
+
* @param {vec3} normal 平面法向量,要求单位化
|
|
371
|
+
* @returns {number}
|
|
372
|
+
*/
|
|
373
|
+
export function getPointToPlaneDist(point, origin, normal) {
|
|
374
|
+
return vec3.dot(vec3.sub(vec3.create(), point, origin), normal);
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
|
|
378
|
+
/**
|
|
379
|
+
* 对一个polydata应用矩阵变化,直接改变点位置
|
|
380
|
+
* @param {mat4} mt4 变换矩阵
|
|
381
|
+
* @param {vtkPolyData} data 需要应用变换的polydata
|
|
382
|
+
*/
|
|
383
|
+
|
|
384
|
+
export function pointsApplyMat4(mt4, data) {
|
|
385
|
+
vtkMatrixBuilder
|
|
386
|
+
.buildFromDegree()
|
|
387
|
+
.multiply(mt4)
|
|
388
|
+
.apply(data.getPoints().getData());
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
/**
|
|
392
|
+
* 将点应用矩阵变换
|
|
393
|
+
* @param {vec3} point 三维点
|
|
394
|
+
* @param {mat4} matrix 变换矩阵
|
|
395
|
+
* @returns {vec3} 应用矩阵变换之后的点
|
|
396
|
+
*/
|
|
397
|
+
export function pointTransformByMat4(point, matrix) {
|
|
398
|
+
return vec3.transformMat4(vec3.create(), point, matrix);
|
|
399
|
+
}
|
|
400
|
+
/**
|
|
401
|
+
* 将向量应用矩阵变换
|
|
402
|
+
* @param {vec3} vec 向量
|
|
403
|
+
* @param {mat4} matrix 变换矩阵
|
|
404
|
+
* @returns {vec3} 应用矩阵变换之后的向量
|
|
405
|
+
*/
|
|
406
|
+
export function vecTransfromByMat4(vec, matrix) {
|
|
407
|
+
const newMatrix = mat4.clone(matrix);
|
|
408
|
+
newMatrix[12] = 0;
|
|
409
|
+
newMatrix[13] = 0;
|
|
410
|
+
newMatrix[14] = 0;
|
|
411
|
+
return vec3.transformMat4(vec3.create(), vec, newMatrix);
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
/**
|
|
415
|
+
* 获取mesh的ply文件Blob
|
|
416
|
+
* @param {vtkPolyData} mesh 网格polydata
|
|
417
|
+
* @param {'ascii' | 'binary'} [format='ascii'] format 导出文件格式
|
|
418
|
+
* @returns {Blob} 网格的ply文件Blob
|
|
419
|
+
*/
|
|
420
|
+
export function createPlyBlob(mesh, format = 'ascii') {
|
|
421
|
+
// const data = deduplicatePolyData(mesh)
|
|
422
|
+
// const deduplicateData = deduplicatePolyData(mesh);
|
|
423
|
+
const fileContents = writePLY(mesh, format);
|
|
424
|
+
const blob = new Blob([fileContents], { type: "application/octet-steam" });
|
|
425
|
+
return blob;
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
/**
|
|
429
|
+
* 获取mesh的stl文件Blob,由于STL文件过大,只使用Binary格式
|
|
430
|
+
* @param {vtkPolyData} mesh 网格polydata
|
|
431
|
+
* @returns {Blob} 网格的BinarySTL文件Blob
|
|
432
|
+
*/
|
|
433
|
+
export function createStlBlob(mesh) {
|
|
434
|
+
const blob = exportBinarySTL(mesh);
|
|
435
|
+
return blob;
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
/**
|
|
439
|
+
* 将网格压缩为drc文件,导出drc需要先加载draco_encode.js,并调用initDrcCoder初始化
|
|
440
|
+
* @param {vtkPolyData} mesh 网格文件
|
|
441
|
+
* @returns {Blob} drc文件
|
|
442
|
+
*/
|
|
443
|
+
export function createDrcBlob(mesh) {
|
|
444
|
+
const blob = new Blob([enCodeMesh(mesh)]);
|
|
445
|
+
return blob;
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
|
|
449
|
+
/**
|
|
450
|
+
* 将网格输出为对应类型的Blob,均采用默认参数,导出drc需要先加载draco_encode.js,并调用initDrcCoder初始化
|
|
451
|
+
* @param {vtkPolyData} mesh 网格文件
|
|
452
|
+
* @param {'ply' | 'stl' | 'drc' } type 输出类型
|
|
453
|
+
* @returns {Blob} 对应类型的Blob
|
|
454
|
+
*/
|
|
455
|
+
|
|
456
|
+
export function createMeshTypeBlob(
|
|
457
|
+
mesh,
|
|
458
|
+
type
|
|
459
|
+
) {
|
|
460
|
+
if (type !== "ply" && type !== "stl" && type !== "drc") {
|
|
461
|
+
return null;
|
|
462
|
+
}
|
|
463
|
+
switch (type) {
|
|
464
|
+
case "ply":
|
|
465
|
+
return createPlyBlob(mesh);
|
|
466
|
+
case "stl":
|
|
467
|
+
return createStlBlob(mesh);
|
|
468
|
+
case "drc":
|
|
469
|
+
return createDrcBlob(mesh);
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
|
|
474
|
+
/**
|
|
475
|
+
* vtkPolyData的顶点去重
|
|
476
|
+
* 用于3倍顶点的stl和老版本的vtkMarchingCube
|
|
477
|
+
* @param {vtkPolyData} data 网格的vtkPolyData
|
|
478
|
+
* @returns {vtkPolyData} 去重之后的vtkPolyData
|
|
479
|
+
*/
|
|
480
|
+
export const deduplicatePolyData = (data) => {
|
|
481
|
+
const OFFSET_BOUNDS = 10;
|
|
482
|
+
const vMap = new Map();
|
|
483
|
+
const vIndexMap = new Map();
|
|
484
|
+
const cMap = new Map();
|
|
485
|
+
const vertices = data.getPoints().getData();
|
|
486
|
+
const hasColorInfo = !!data.getPointData().getScalars();
|
|
487
|
+
const colors = hasColorInfo
|
|
488
|
+
? data.getPointData().getScalars().getData()
|
|
489
|
+
: new Uint8Array(vertices.length);
|
|
490
|
+
let vInc = 0; // 顶点新索引
|
|
491
|
+
// 更新顶点map:vMap和顶点映射map:vIndexMap
|
|
492
|
+
for (let i = 0; i < vertices.length; i += 3) {
|
|
493
|
+
// const key: string = `${vertices[i]},${vertices[i + 1]},${vertices[i + 2]}`
|
|
494
|
+
const key = `${(vertices[i] * Math.pow(10, OFFSET_BOUNDS)).toFixed(
|
|
495
|
+
0
|
|
496
|
+
)},${(vertices[i + 1] * Math.pow(10, OFFSET_BOUNDS)).toFixed(0)},${(
|
|
497
|
+
vertices[i + 2] * Math.pow(10, OFFSET_BOUNDS)
|
|
498
|
+
).toFixed(0)}`;
|
|
499
|
+
if (vMap.get(key) !== undefined) {
|
|
500
|
+
vIndexMap.set(i / 3, vMap.get(key));
|
|
501
|
+
} else {
|
|
502
|
+
vIndexMap.set(i / 3, vInc);
|
|
503
|
+
hasColorInfo && cMap.set(vInc, [colors[i], colors[i + 1], colors[i + 2]]);
|
|
504
|
+
vMap.set(key, vInc);
|
|
505
|
+
vInc++;
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
const tVertices = new Float32Array(vMap.size * 3);
|
|
509
|
+
const tColors = new Uint8Array(vMap.size * 3).fill(255);
|
|
510
|
+
|
|
511
|
+
for (let k of vMap.keys()) {
|
|
512
|
+
const j = vMap.get(k) * 3;
|
|
513
|
+
[tVertices[j], tVertices[j + 1], tVertices[j + 2]] = k
|
|
514
|
+
.split(",")
|
|
515
|
+
.map((e) => +e * Math.pow(10, -OFFSET_BOUNDS));
|
|
516
|
+
const t = cMap.get(vMap.get(k));
|
|
517
|
+
hasColorInfo && ([tColors[j], tColors[j + 1], tColors[j + 2]] = t);
|
|
518
|
+
}
|
|
519
|
+
const faces = data.getPolys().getData();
|
|
520
|
+
const tFaces = new Int32Array(faces);
|
|
521
|
+
for (let i = 0; i < faces.length; i += 4) {
|
|
522
|
+
tFaces[i] = 3;
|
|
523
|
+
tFaces[i + 1] = vIndexMap.get(faces[i + 1]);
|
|
524
|
+
tFaces[i + 2] = vIndexMap.get(faces[i + 2]);
|
|
525
|
+
tFaces[i + 3] = vIndexMap.get(faces[i + 3]);
|
|
526
|
+
}
|
|
527
|
+
const p = vtkPolyData.newInstance();
|
|
528
|
+
p.getPoints().setData(tVertices);
|
|
529
|
+
p.getPolys().setData(tFaces);
|
|
530
|
+
return p;
|
|
531
|
+
};
|
|
532
|
+
|
|
533
|
+
/**
|
|
534
|
+
* 计算一组三维点的中心点
|
|
535
|
+
* @param {vec3[]} points 三维点数组
|
|
536
|
+
* @returns {vec3} 中心点
|
|
537
|
+
*/
|
|
538
|
+
|
|
539
|
+
export function getPointsCenter(points) {
|
|
540
|
+
let sumPoints = vec3.create();
|
|
541
|
+
for (let i = 0; i < points.length; i++) {
|
|
542
|
+
vec3.add(sumPoints, sumPoints, points[i]);
|
|
543
|
+
}
|
|
544
|
+
return vec3.scale(vec3.create(), sumPoints, 1 / points.length);
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
/**
|
|
548
|
+
* @typedef Position
|
|
549
|
+
* @property {number} x 对应vtk坐标系的x值
|
|
550
|
+
* @property {number} y 对应vtk坐标系的y值
|
|
551
|
+
* @property {number} z 0
|
|
552
|
+
*/
|
|
553
|
+
|
|
554
|
+
/**
|
|
555
|
+
* 计算js事件对应vtk事件的position
|
|
556
|
+
* @param {HTMLElement} el vtkViewDom
|
|
557
|
+
* @param {MouseEvent} event 二维鼠标事件
|
|
558
|
+
* @returns {Position} 对应vtk坐标系的xyz值
|
|
559
|
+
*/
|
|
560
|
+
export function getScreenEventPositionFor(el, event) {
|
|
561
|
+
var canvas = el.getElementsByTagName("canvas")[0];
|
|
562
|
+
|
|
563
|
+
var bounds = canvas.getBoundingClientRect();
|
|
564
|
+
var scaleX = canvas.width / bounds.width;
|
|
565
|
+
var scaleY = canvas.height / bounds.height;
|
|
566
|
+
var position = {
|
|
567
|
+
x: scaleX * (event.clientX - bounds.left),
|
|
568
|
+
y: scaleY * (bounds.height - event.clientY + bounds.top),
|
|
569
|
+
z: 0,
|
|
570
|
+
};
|
|
571
|
+
return position;
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
/**
|
|
575
|
+
* 将数值数组转换为vec3数组
|
|
576
|
+
* @param {number[] | Float32Array} dataList
|
|
577
|
+
* @returns {vec3[]} 格式化之后的数组
|
|
578
|
+
*/
|
|
579
|
+
|
|
580
|
+
export function formatNumberArrayToVec3Array(dataList) {
|
|
581
|
+
const vec3Data = [];
|
|
582
|
+
for (let i = 0; i < dataList.length / 3; i++) {
|
|
583
|
+
const data = [
|
|
584
|
+
dataList[i * 3],
|
|
585
|
+
dataList[i * 3 + 1],
|
|
586
|
+
dataList[i * 3 + 2],
|
|
587
|
+
];
|
|
588
|
+
vec3Data.push(data);
|
|
589
|
+
}
|
|
590
|
+
return vec3Data;
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
|
|
594
|
+
/**
|
|
595
|
+
* 简单的数值平均插值
|
|
596
|
+
* @param {number} from 开始数值
|
|
597
|
+
* @param {number} to 结束数值
|
|
598
|
+
* @param {number} step 步长
|
|
599
|
+
* @returns {number[]} 插值的数值
|
|
600
|
+
*/
|
|
601
|
+
export function calculateSimpleLerp(from, to, step) {
|
|
602
|
+
let lerps = [];
|
|
603
|
+
let temp = from;
|
|
604
|
+
const a = (to - from) / (step + 1);
|
|
605
|
+
for (let i = 0; i < step; i++) {
|
|
606
|
+
lerps.push((temp += a));
|
|
607
|
+
}
|
|
608
|
+
return lerps;
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
/**
|
|
612
|
+
* 将 mat3 解析为 3 个自由度的 欧拉角(Eular)(弧度)
|
|
613
|
+
* @param {mat3} rmat 3 * 3的矩阵
|
|
614
|
+
* @param {[number, number, number]} eular 输出的欧拉角度数(弧度)
|
|
615
|
+
* @returns {[number, number, number]} 3个自由度的欧拉角
|
|
616
|
+
* @example
|
|
617
|
+
* const mt4: mat4;
|
|
618
|
+
* const mt3 = mat3.fromMat4(mt3, mt4);
|
|
619
|
+
* mat3.transpose(mt3, mt3);
|
|
620
|
+
* let eular = [0, 0, 0];
|
|
621
|
+
* convMatrix2EularZYX(mt3, eular);
|
|
622
|
+
*/
|
|
623
|
+
export function convMatrix2EularZYX(rmat, eular) {
|
|
624
|
+
function fclamp(v, min, max) {
|
|
625
|
+
if (v <= min) return min;
|
|
626
|
+
if (v >= max) return max;
|
|
627
|
+
return v;
|
|
628
|
+
}
|
|
629
|
+
const m11 = rmat[0],
|
|
630
|
+
m12 = rmat[1],
|
|
631
|
+
m13 = rmat[2];
|
|
632
|
+
const m21 = rmat[3],
|
|
633
|
+
m22 = rmat[4],
|
|
634
|
+
m23 = rmat[5];
|
|
635
|
+
const m31 = rmat[6],
|
|
636
|
+
m32 = rmat[7],
|
|
637
|
+
m33 = rmat[8];
|
|
638
|
+
|
|
639
|
+
eular[1] = Math.asin(-fclamp(m31, -1, 1));
|
|
640
|
+
if (Math.abs(m31) < 0.9999999) {
|
|
641
|
+
eular[0] = Math.atan2(m32, m33);
|
|
642
|
+
eular[2] = Math.atan2(m21, m11);
|
|
643
|
+
} else {
|
|
644
|
+
eular[0] = 0;
|
|
645
|
+
eular[2] = Math.atan2(-m12, m22);
|
|
646
|
+
}
|
|
647
|
+
return eular;
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
|
|
651
|
+
/**
|
|
652
|
+
* 将欧拉角(Eular)转换为mat3
|
|
653
|
+
* @param {mat3} rmat 变换矩阵
|
|
654
|
+
* @param {number} xangle 对应欧拉角x 弧度
|
|
655
|
+
* @param {number} yangle 对应欧拉角y 弧度
|
|
656
|
+
* @param {number} zangle 对应欧拉加z 弧度
|
|
657
|
+
* @returns {mat3} 对应变换矩阵
|
|
658
|
+
* @example
|
|
659
|
+
* const rotateX = 0.5;
|
|
660
|
+
* const rotateY = 0.5;
|
|
661
|
+
* const rotateZ = 0.5;
|
|
662
|
+
* const mt3 = mat3.create();
|
|
663
|
+
* convEular2matrixZYX(mt3, [rotateX, rotateY, rotateZ])
|
|
664
|
+
*/
|
|
665
|
+
export function convEular2matrixZYX(rmat, xangle, yangle, zangle) {
|
|
666
|
+
let UnitZ = vec3.create();
|
|
667
|
+
vec3.set(UnitZ, 0, 0, 1);
|
|
668
|
+
// let UnitZ = getLocalAxis(0, 0, 1);
|
|
669
|
+
let qz = quat.create();
|
|
670
|
+
quat.setAxisAngle(qz, UnitZ, zangle);
|
|
671
|
+
quat.normalize(qz, qz);
|
|
672
|
+
|
|
673
|
+
let UnitY = vec3.create();
|
|
674
|
+
vec3.set(UnitY, 0, 1, 0);
|
|
675
|
+
// let UnitY = getLocalAxis(0, 1, 0);
|
|
676
|
+
vec3.transformQuat(UnitY, UnitY, qz);
|
|
677
|
+
vec3.normalize(UnitY, UnitY);
|
|
678
|
+
|
|
679
|
+
let qy = quat.create();
|
|
680
|
+
quat.setAxisAngle(qy, UnitY, yangle);
|
|
681
|
+
quat.normalize(qy, qy);
|
|
682
|
+
|
|
683
|
+
let UnitX = vec3.create();
|
|
684
|
+
vec3.set(UnitX, 1, 0, 0);
|
|
685
|
+
// let UnitX = getLocalAxis(1, 0, 0);
|
|
686
|
+
vec3.transformQuat(UnitX, UnitX, qz);
|
|
687
|
+
vec3.transformQuat(UnitX, UnitX, qy);
|
|
688
|
+
vec3.normalize(UnitX, UnitX);
|
|
689
|
+
|
|
690
|
+
let qx = quat.create();
|
|
691
|
+
quat.setAxisAngle(qx, UnitX, xangle);
|
|
692
|
+
quat.normalize(qx, qx);
|
|
693
|
+
|
|
694
|
+
//instrinsic qx*qy*qz
|
|
695
|
+
quat.multiply(qx, qx, qy);
|
|
696
|
+
quat.multiply(qx, qx, qz);
|
|
697
|
+
|
|
698
|
+
let qx2 = quat.create();
|
|
699
|
+
quat.multiply(qx2, qy, qx);
|
|
700
|
+
quat.multiply(qx2, qz, qx2);
|
|
701
|
+
|
|
702
|
+
mat3.fromQuat(rmat, qx);
|
|
703
|
+
// mat3.transpose(rmat, rmat);
|
|
704
|
+
// console.log('🚀 ~ mat3', rmat)
|
|
705
|
+
return rmat;
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
/**
|
|
709
|
+
* 将drc
|
|
710
|
+
* @param {vtkPolyData} mesh 网格polyData
|
|
711
|
+
* @param {mat4} [matrix] 变换矩阵
|
|
712
|
+
* @returns {string} drc压缩之后的网格base64
|
|
713
|
+
*/
|
|
714
|
+
export function enCodeMeshToBase64(mesh, matrix = undefined) {
|
|
715
|
+
const encodePolydata = vtkPolyData.newInstance();
|
|
716
|
+
encodePolydata.getPoints().setData([...mesh.getPoints().getData()]);
|
|
717
|
+
encodePolydata.getPolys().setData([...mesh.getPolys().getData()]);
|
|
718
|
+
if(matrix) {
|
|
719
|
+
pointsApplyMat4(matrix, encodePolydata);
|
|
720
|
+
}
|
|
721
|
+
return int8ArrayToBase64(enCodeMesh(encodePolydata))
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
/**
|
|
725
|
+
* 将一圈有序点按指定size进行平滑
|
|
726
|
+
* @param {vce3[]} points 一圈有序点
|
|
727
|
+
* @param {number} smaSize=3 平滑点的数量通常值为奇数
|
|
728
|
+
* @returns {vec3[]} 平滑之后的点
|
|
729
|
+
*/
|
|
730
|
+
|
|
731
|
+
export function smaPoint(points, smaSize = 3) {
|
|
732
|
+
const newPoints = [];
|
|
733
|
+
for (let i = 0; i < points.length; i++) {
|
|
734
|
+
const step = Math.floor(smaSize / 2);
|
|
735
|
+
const sumPoint = vec3.clone(points[i]);
|
|
736
|
+
for (let j = 1; j <= step; j++) {
|
|
737
|
+
let lastIndex = i - j;
|
|
738
|
+
let nextIndex = i + j;
|
|
739
|
+
if (lastIndex < 0) lastIndex = points.length + lastIndex;
|
|
740
|
+
if (nextIndex > points.length - 1) nextIndex = nextIndex - points.length;
|
|
741
|
+
vec3.add(sumPoint, sumPoint, points[lastIndex]);
|
|
742
|
+
vec3.add(sumPoint, sumPoint, points[nextIndex]);
|
|
743
|
+
}
|
|
744
|
+
const centerPoint = vec3.scale(vec3.create(), sumPoint, 1 / smaSize);
|
|
745
|
+
newPoints.push(centerPoint);
|
|
746
|
+
}
|
|
747
|
+
return newPoints;
|
|
748
|
+
}
|
|
749
|
+
/**
|
|
750
|
+
* 将一段有序点按指定size进行平滑
|
|
751
|
+
* @param {vce3[]} points 一段有序点
|
|
752
|
+
* @param {number} smaSize=3 平滑点的数量通常值为奇数
|
|
753
|
+
* @returns {vec3[]} 平滑之后的点
|
|
754
|
+
*/
|
|
755
|
+
export function smaPointNotRound(points, smaSize = 3) {
|
|
756
|
+
const newPoints= [];
|
|
757
|
+
for (let i = 0; i < points.length; i++) {
|
|
758
|
+
const step = Math.floor(smaSize / 2);
|
|
759
|
+
let sumPoint = vec3.clone(points[i]);
|
|
760
|
+
for (let j = 1; j <= step; j++) {
|
|
761
|
+
let lastIndex = i - j;
|
|
762
|
+
let nextIndex = i + j;
|
|
763
|
+
if (lastIndex < 0) {
|
|
764
|
+
sumPoint = points[i];
|
|
765
|
+
break;
|
|
766
|
+
}
|
|
767
|
+
if (nextIndex > points.length - 1) {
|
|
768
|
+
sumPoint = points[i];
|
|
769
|
+
break;
|
|
770
|
+
}
|
|
771
|
+
vec3.add(sumPoint, sumPoint, points[lastIndex]);
|
|
772
|
+
vec3.add(sumPoint, sumPoint, points[nextIndex]);
|
|
773
|
+
}
|
|
774
|
+
let centerPoint;
|
|
775
|
+
if (vec3.equals(sumPoint, points[i])) {
|
|
776
|
+
centerPoint = sumPoint;
|
|
777
|
+
} else {
|
|
778
|
+
centerPoint = vec3.scale(vec3.create(), sumPoint, 1 / smaSize);
|
|
779
|
+
}
|
|
780
|
+
newPoints.push(centerPoint);
|
|
781
|
+
}
|
|
782
|
+
return newPoints;
|
|
783
|
+
}
|
|
784
|
+
|
|
785
|
+
/**
|
|
786
|
+
* 表示一个包含三个轴向的对象
|
|
787
|
+
* @typedef {Object} AxisObject
|
|
788
|
+
* @property {vec3} x - x轴
|
|
789
|
+
* @property {vec3} y - y轴
|
|
790
|
+
* @property {vec3} z - z轴
|
|
791
|
+
*/
|
|
792
|
+
|
|
793
|
+
/**
|
|
794
|
+
* 获取一个矩阵的三个轴向
|
|
795
|
+
* @param {mat4} matrix 4 * 4 的矩阵
|
|
796
|
+
* @returns {AxisObject} 三个轴向
|
|
797
|
+
*/
|
|
798
|
+
|
|
799
|
+
export function getAxisFormMat4(matrix) {
|
|
800
|
+
let axis_x = vec3.fromValues(matrix[0], matrix[1], matrix[2]);
|
|
801
|
+
let axis_y = vec3.fromValues(matrix[4], matrix[5], matrix[6]);
|
|
802
|
+
let axis_z = vec3.fromValues(matrix[8], matrix[9], matrix[10]);
|
|
803
|
+
vec3.normalize(axis_x, axis_x);
|
|
804
|
+
vec3.normalize(axis_y, axis_y);
|
|
805
|
+
vec3.normalize(axis_z, axis_z);
|
|
806
|
+
return { x: axis_x, y: axis_y, z: axis_z };
|
|
28
807
|
}
|