xl-public-utils 1.0.9 → 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,5 +1,16 @@
1
1
  import vtkPolyData from "@kitware/vtk.js/Common/DataModel/PolyData";
2
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
+ };
3
14
  export interface QrCodeOptions {
4
15
  /** 二维码类型,具体支持请查看文档 */
5
16
  bcid?: string; // 默认值 'qrcode'
@@ -481,12 +492,6 @@ declare module "xl-public-utils" {
481
492
  * @returns {Plane| null} 拟合的平面
482
493
  */
483
494
  export function pcaFitPlane(points: vec3[]): Plane | null;
484
- /**
485
- * 计算一组 3D 点的最佳拟合平面(最小二乘法)。
486
- * @param {Array<vec3>} points - 3D 点数组,每个点是一个 vec3 向量。
487
- * @returns {Plane|null} - 返回平面的 origin(质心)和 normal(法向量),如果点数少于 3 个则返回 null。
488
- */
489
- export function leastSquaresFitPlane(points: Array<vec3>): Plane | null;
490
495
  export type Position = {
491
496
  /**
492
497
  * 对应vtk坐标系的x值
@@ -518,16 +523,6 @@ declare module "xl-public-utils" {
518
523
  */
519
524
  z: vec3;
520
525
  };
521
- export type Mesh = {
522
- /**
523
- * 点信息
524
- */
525
- vertices: number[][] | vec3[];
526
- /**
527
- * 面信息
528
- */
529
- faces: number[][] | vec3[];
530
- };
531
526
  export type Plane = {
532
527
  /**
533
528
  * 对应vtk坐标系的x值
@@ -577,16 +572,6 @@ declare module "xl-public-utils" {
577
572
  normals?: Float32Array;
578
573
  };
579
574
  export type Decoder = any;
580
- export type Mesh = {
581
- /**
582
- * 点信息
583
- */
584
- vertices: number[][] | vec3[];
585
- /**
586
- * 面信息
587
- */
588
- faces: number[][] | vec3[];
589
- };
590
575
  /**
591
576
  * @typedef {Object} AttrOption
592
577
  * @property {number[]} [colors] 颜色数组
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "xl-public-utils",
3
- "version": "1.0.9",
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 中心点