xl-public-utils 1.0.8 → 1.0.10

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 CHANGED
@@ -1,4 +1,16 @@
1
+ import vtkPolyData from "@kitware/vtk.js/Common/DataModel/PolyData";
1
2
  declare module "xl-public-utils" {
3
+
4
+ export type Mesh = {
5
+ /**
6
+ * 点信息
7
+ */
8
+ vertices: number[][] | vec3[];
9
+ /**
10
+ * 面信息
11
+ */
12
+ faces: number[][] | vec3[];
13
+ };
2
14
  export interface QrCodeOptions {
3
15
  /** 二维码类型,具体支持请查看文档 */
4
16
  bcid?: string; // 默认值 'qrcode'
@@ -262,12 +274,22 @@ declare module "xl-public-utils" {
262
274
  export function createStlBlob(mesh: vtkPolyData): Blob;
263
275
  /**
264
276
  * 将网格压缩为drc文件,导出drc需要先加载draco_encode.js,并调用initDrcCoder初始化
265
- * @param {vtkPolyData | Mesh} mesh 网格文件
277
+ * @param {vtkPolyData} mesh 网格文件
278
+ * @param {number} byteLength=14 压缩率
279
+ * @returns {Blob} drc文件
280
+ */
281
+ export function createDrcBlob(
282
+ mesh: vtkPolyData,
283
+ byteLength?: number
284
+ ): Blob;
285
+ /**
286
+ * 将网格压缩为drc文件,导出drc需要先加载draco_encode.js,并调用initDrcCoder初始化
287
+ * @param {Mesh} mesh 网格文件
266
288
  * @param {number} byteLength=14 压缩率
267
289
  * @returns {Blob} drc文件
268
290
  */
269
291
  export function createDrcBlob(
270
- mesh: vtkPolyData | Mesh,
292
+ mesh: Mesh,
271
293
  byteLength?: number
272
294
  ): Blob;
273
295
  /**
@@ -360,16 +382,20 @@ declare module "xl-public-utils" {
360
382
  ): mat3;
361
383
  /**
362
384
  * 将polyData转换为Base64string
363
- * @param {vtkPolyData | Mesh} mesh 网格数据
385
+ * @param {vtkPolyData} mesh 网格数据
364
386
  * @param {mat4} [matrix] 变换矩阵
365
387
  * @param {number} byteLength=14 压缩率
366
388
  * @returns {string} drc压缩之后的网格base64
367
389
  */
368
- export function enCodeMeshToBase64(
369
- mesh: vtkPolyData | Mesh,
370
- matrix?: mat4,
371
- byteLength?: number
372
- ): string;
390
+ export function enCodeMeshToBase64(mesh: vtkPolyData,matrix?: mat4,byteLength?: number): string;
391
+ /**
392
+ * 将polyData转换为Base64string
393
+ * @param {Mesh} mesh 网格数据
394
+ * @param {mat4} [matrix] 变换矩阵
395
+ * @param {number} byteLength=14 压缩率
396
+ * @returns {string} drc压缩之后的网格base64
397
+ */
398
+ export function enCodeMeshToBase64(mesh: Mesh,matrix?: mat4,byteLength?: number): string;
373
399
  /**
374
400
  * 将一圈有序点按指定size进行平滑
375
401
  * @param {vec3[]} points 一圈有序点
@@ -466,12 +492,6 @@ declare module "xl-public-utils" {
466
492
  * @returns {Plane| null} 拟合的平面
467
493
  */
468
494
  export function pcaFitPlane(points: vec3[]): Plane | null;
469
- /**
470
- * 计算一组 3D 点的最佳拟合平面(最小二乘法)。
471
- * @param {Array<vec3>} points - 3D 点数组,每个点是一个 vec3 向量。
472
- * @returns {Plane|null} - 返回平面的 origin(质心)和 normal(法向量),如果点数少于 3 个则返回 null。
473
- */
474
- export function leastSquaresFitPlane(points: Array<vec3>): Plane | null;
475
495
  export type Position = {
476
496
  /**
477
497
  * 对应vtk坐标系的x值
@@ -503,16 +523,6 @@ declare module "xl-public-utils" {
503
523
  */
504
524
  z: vec3;
505
525
  };
506
- export type Mesh = {
507
- /**
508
- * 点信息
509
- */
510
- vertices: number[][] | vec3[];
511
- /**
512
- * 面信息
513
- */
514
- faces: number[][] | vec3[];
515
- };
516
526
  export type Plane = {
517
527
  /**
518
528
  * 对应vtk坐标系的x值
@@ -562,16 +572,6 @@ declare module "xl-public-utils" {
562
572
  normals?: Float32Array;
563
573
  };
564
574
  export type Decoder = any;
565
- export type Mesh = {
566
- /**
567
- * 点信息
568
- */
569
- vertices: number[][] | vec3[];
570
- /**
571
- * 面信息
572
- */
573
- faces: number[][] | vec3[];
574
- };
575
575
  /**
576
576
  * @typedef {Object} AttrOption
577
577
  * @property {number[]} [colors] 颜色数组
@@ -650,13 +650,25 @@ declare module "xl-public-utils" {
650
650
  */
651
651
  /**
652
652
  * 使用drc压缩网格信息
653
- * @param {Mesh | vtkPolyData} mesh
653
+ * @param {vtkPolyData} mesh
654
+ * @param {number} byteLength=14 压缩率
655
+ * @param {AttrOption} [attr] 其他需要压缩的属性
656
+ * @returns {Int8Array} 压缩之后的DRC数据
657
+ */
658
+ export function enCodeMesh(
659
+ mesh: vtkPolyData,
660
+ byteLength?: number,
661
+ attr?: AttrOption
662
+ ): Int8Array;
663
+ /**
664
+ * 使用drc压缩网格信息
665
+ * @param {Mesh} mesh
654
666
  * @param {number} byteLength=14 压缩率
655
667
  * @param {AttrOption} [attr] 其他需要压缩的属性
656
668
  * @returns {Int8Array} 压缩之后的DRC数据
657
669
  */
658
670
  export function enCodeMesh(
659
- mesh: Mesh | vtkPolyData,
671
+ mesh: Mesh,
660
672
  byteLength?: number,
661
673
  attr?: AttrOption
662
674
  ): Int8Array;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "xl-public-utils",
3
- "version": "1.0.8",
3
+ "version": "1.0.10",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "module": "index.js",
package/src/drcUtils.js CHANGED
@@ -301,7 +301,12 @@ export function enCodeMesh(mesh, byteLength = 14, attr = undefined) {
301
301
  let faces = [];
302
302
  let vertices = [];
303
303
  if(mesh.vertices && mesh.faces) {
304
- vertices = mesh.vertices;
304
+ for(let i =0; i<mesh.vertices.length; i++) {
305
+ const vertice = mesh.vertices[i];
306
+ vertices.push(vertice[0]);
307
+ vertices.push(vertice[1]);
308
+ vertices.push(vertice[2]);
309
+ }
305
310
  for(let i = 0; i < mesh.faces.length; i++) {
306
311
  const face = mesh.faces[i];
307
312
  faces.push(face[0]);
package/src/vtkUtils.js CHANGED
@@ -10,7 +10,7 @@ import vtkPLYReader from '@kitware/vtk.js/IO/Geometry/PLYReader';
10
10
  import vtkSTLReader from '@kitware/vtk.js/IO/Geometry/STLReader';
11
11
  import vtkDracoReader from '@kitware/vtk.js/IO/Geometry/DracoReader';
12
12
  import vtkTriangleFilter from "@kitware/vtk.js/Filters/General/TriangleFilter";
13
- import { vec3, mat4, mat3 } from 'gl-matrix';
13
+ import { vec3, mat4, mat3, quat } from 'gl-matrix';
14
14
  import { exportBinarySTL } from './exportSTL.js';
15
15
  import { writePLY } from "./exportPLY.js";
16
16
  import { enCodeMesh } from './drcUtils.js';
@@ -619,40 +619,46 @@ export function calculateSimpleLerp(from, to, step) {
619
619
  /**
620
620
  * 将 mat3 解析为 3 个自由度的 欧拉角(Eular)(弧度)
621
621
  * @param {mat3} rmat 3 * 3的矩阵
622
- * @param {[number, number, number]} eular 输出的欧拉角度数(弧度)
622
+ * @param {[number, number, number]} euler 输出的欧拉角度数(弧度)
623
623
  * @returns {[number, number, number]} 3个自由度的欧拉角
624
624
  * @example
625
625
  * const mt4: mat4;
626
626
  * const mt3 = mat3.fromMat4(mt3, mt4);
627
627
  * mat3.transpose(mt3, mt3);
628
- * let eular = [0, 0, 0];
629
- * convMatrix2EularZYX(mt3, eular);
630
- */
631
- export function convMatrix2EularZYX(rmat, eular) {
632
- function fclamp(v, min, max) {
633
- if (v <= min) return min;
634
- if (v >= max) return max;
635
- return v;
628
+ * let euler = [0, 0, 0];
629
+ * convMatrix2EularZYX(mt3, euler);
630
+ */
631
+ export function convMatrix2EularZYX(rmat, euler) {
632
+ const R = mat3.transpose(mat3.create(),rmat);
633
+ // 计算pitch(绕Y轴)
634
+ const pitch = Math.atan2(-R[6], Math.sqrt(R[7] * R[7] + R[8] * R[8]));
635
+
636
+ // 处理万向节死锁(Gimbal Lock)
637
+ if (Math.abs(pitch - Math.PI/2) < 1e-3) { // pitch接近90度
638
+ vec3.set(
639
+ euler,
640
+ 0.0, // roll
641
+ Math.PI/2, // pitch
642
+ Math.atan2(R[1], R[0]), // yaw
643
+ );
644
+ }
645
+ else if (Math.abs(pitch + Math.PI/2) < 1e-3) { // pitch接近-90度
646
+ vec3.set(
647
+ euler,
648
+ 0.0, // roll
649
+ -Math.PI/2, // pitch
650
+ -Math.atan2(R[1], R[0]), // yaw
651
+ );
636
652
  }
637
- const m11 = rmat[0],
638
- m12 = rmat[1],
639
- m13 = rmat[2];
640
- const m21 = rmat[3],
641
- m22 = rmat[4],
642
- m23 = rmat[5];
643
- const m31 = rmat[6],
644
- m32 = rmat[7],
645
- m33 = rmat[8];
646
-
647
- eular[1] = Math.asin(-fclamp(m31, -1, 1));
648
- if (Math.abs(m31) < 0.9999999) {
649
- eular[0] = Math.atan2(m32, m33);
650
- eular[2] = Math.atan2(m21, m11);
651
- } else {
652
- eular[0] = 0;
653
- eular[2] = Math.atan2(-m12, m22);
653
+ else {
654
+ vec3.set(
655
+ euler,
656
+ Math.atan2(R[7], R[8]), // roll
657
+ pitch, // pitch
658
+ Math.atan2(R[3], R[0]), // yaw
659
+ );
654
660
  }
655
- return eular;
661
+ return euler;
656
662
  }
657
663
 
658
664
 
@@ -668,7 +674,7 @@ export function convMatrix2EularZYX(rmat, eular) {
668
674
  * const rotateY = 0.5;
669
675
  * const rotateZ = 0.5;
670
676
  * const mt3 = mat3.create();
671
- * convEular2matrixZYX(mt3, [rotateX, rotateY, rotateZ])
677
+ * convEular2matrixZYX(mt3, rotateX, rotateY, rotateZ)
672
678
  */
673
679
  export function convEular2matrixZYX(rmat, xangle, yangle, zangle) {
674
680
  let UnitZ = vec3.create();
@@ -739,8 +745,11 @@ export function enCodeMeshToBase64(mesh, matrix = undefined, byteLength = 14) {
739
745
  * @returns {vec3[]} 平滑之后的点
740
746
  */
741
747
 
742
- export function smaPoint(points, smaSize = 3) {
748
+ export function smoothLoop(points, smaSize = 3) {
743
749
  const newPoints = [];
750
+ if(points.length < smaSize) {
751
+ return points;
752
+ }
744
753
  for (let i = 0; i < points.length; i++) {
745
754
  const step = Math.floor(smaSize / 2);
746
755
  const sumPoint = vec3.clone(points[i]);
@@ -760,13 +769,16 @@ export function smaPoint(points, smaSize = 3) {
760
769
  /**
761
770
  * 将一段有序点按指定size进行平滑
762
771
  * @param {vec3[]} points 一段有序点
763
- * @param {number} smaSize=3 平滑点的数量通常值为奇数
772
+ * @param {number} smoothSize=3 平滑点的数量通常值为奇数
764
773
  * @returns {vec3[]} 平滑之后的点
765
774
  */
766
- export function smaPointNotRound(points, smaSize = 3) {
775
+ export function smoothCurve(points, smoothSize = 3) {
767
776
  const newPoints= [];
777
+ if(points.length < smoothSize) {
778
+ return points;
779
+ }
768
780
  for (let i = 0; i < points.length; i++) {
769
- const step = Math.floor(smaSize / 2);
781
+ const step = Math.floor(smoothSize / 2);
770
782
  let sumPoint = vec3.clone(points[i]);
771
783
  for (let j = 1; j <= step; j++) {
772
784
  let lastIndex = i - j;
@@ -786,7 +798,7 @@ export function smaPointNotRound(points, smaSize = 3) {
786
798
  if (vec3.equals(sumPoint, points[i])) {
787
799
  centerPoint = sumPoint;
788
800
  } else {
789
- centerPoint = vec3.scale(vec3.create(), sumPoint, 1 / smaSize);
801
+ centerPoint = vec3.scale(vec3.create(), sumPoint, 1 / smoothSize);
790
802
  }
791
803
  newPoints.push(centerPoint);
792
804
  }
@@ -970,63 +982,38 @@ export function pcaFitPlane(points) {
970
982
  }
971
983
  }
972
984
 
973
-
974
985
  /**
975
- * 计算一组 3D 点的最佳拟合平面(最小二乘法)。
976
- * @param {Array<vec3>} points - 3D 点数组,每个点是一个 vec3 向量。
977
- * @returns {Plane|null} - 返回平面的 origin(质心)和 normal(法向量),如果点数少于 3 个则返回 null。
986
+ * 计算曲线长度
987
+ * @param {vec3[]} points 曲线
988
+ * @returns {number} 曲线长度
978
989
  */
979
- export function leastSquaresFitPlane(points) {
980
- if (points.length < 3) {
981
- return null;
982
- }
983
990
 
984
- // Step 1: 计算质心(origin)
985
- let centroid = vec3.create();
986
- for (let point of points) {
987
- vec3.add(centroid, centroid, point);
991
+ export function getCurveLength(points) {
992
+ let dist = 0;
993
+ for (let i = 1; i < points.length; i++) {
994
+ dist += vec3.dist(points[i - 1], points[i]);
988
995
  }
989
- vec3.scale(centroid, centroid, 1 / points.length);
990
-
991
- // Step 2: 构建协方差矩阵
992
- let xx = 0, xy = 0, xz = 0;
993
- let yy = 0, yz = 0, zz = 0;
996
+ return dist;
997
+ }
994
998
 
995
- for (let point of points) {
996
- let r = vec3.sub(vec3.create(), point, centroid); // r = point - centroid
997
999
 
998
- xx += r[0] * r[0];
999
- xy += r[0] * r[1];
1000
- xz += r[0] * r[2];
1001
- yy += r[1] * r[1];
1002
- yz += r[1] * r[2];
1003
- zz += r[2] * r[2];
1000
+ /**
1001
+ *
1002
+ * @param {vec3[]} points 曲线
1003
+ * @param {number} dist 目标点距离,绝对距离或者相对距离
1004
+ * @param {boolean} [absDist=true] 是否使用绝对距离
1005
+ * @returns
1006
+ */
1007
+ export function getCurvePointIndexByLength(points, dist, absDist = true) {
1008
+ let allDist = getCurvePointDist(points);
1009
+ const targetDist = absDist ? dist : dist * allDist;
1010
+ let targetDistanceSubs = [targetDist];
1011
+ let distance = 0;
1012
+ for (let i = 1; i < points.length; i++) {
1013
+ distance += vec3.dist(points[i], points[i - 1])
1014
+ targetDistanceSubs.push(Math.abs(distance - targetDist))
1004
1015
  }
1005
-
1006
- // 协方差矩阵
1007
- const covarianceMatrix = mat3.fromValues(
1008
- xx, xy, xz,
1009
- xy, yy, yz,
1010
- xz, yz, zz
1011
- );
1012
-
1013
- // Step 3: 计算协方差矩阵的特征值和特征向量
1014
- const eigenVectors = mat3.create();
1015
- const eigenValues = vec3.create();
1016
- mat3.eigenDecomposition(eigenValues, eigenVectors, covarianceMatrix);
1017
-
1018
- // Step 4: 选择最小特征值对应的特征向量作为法向量
1019
- const minEigenIndex = eigenValues.indexOf(Math.min(...eigenValues));
1020
- const normal = vec3.fromValues(
1021
- eigenVectors[3 * minEigenIndex + 0],
1022
- eigenVectors[3 * minEigenIndex + 1],
1023
- eigenVectors[3 * minEigenIndex + 2]
1024
- );
1025
-
1026
- vec3.normalize(normal, normal); // 单位化法向量
1027
-
1028
- return {
1029
- origin: centroid,
1030
- normal: normal
1031
- };
1016
+ const minSub = Math.min(...targetDistanceSubs);
1017
+ const targetIndex = targetDistanceSubs.findIndex(i => i === minSub)
1018
+ return targetIndex;
1032
1019
  }
@@ -306,12 +306,6 @@ export function loadMeshData(file: string | File | Blob, type?: "drc" | "stl" |
306
306
  * @returns {Plane| null} 拟合的平面
307
307
  */
308
308
  export function pcaFitPlane(points: vec3[]): Plane | null;
309
- /**
310
- * 计算一组 3D 点的最佳拟合平面(最小二乘法)。
311
- * @param {Array<vec3>} points - 3D 点数组,每个点是一个 vec3 向量。
312
- * @returns {Plane|null} - 返回平面的 origin(质心)和 normal(法向量),如果点数少于 3 个则返回 null。
313
- */
314
- export function leastSquaresFitPlane(points: Array<vec3>): Plane | null;
315
309
  /**
316
310
  * 计算 w2l(word 2 local, word to local) 的变换矩阵
317
311
  * @param {vec3} center 中心点