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 +11 -26
- package/package.json +1 -1
- package/src/drcUtils.js +6 -1
- package/src/vtkUtils.js +73 -86
- package/types/vtkUtils.d.ts +0 -6
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
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
|
-
|
|
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]}
|
|
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
|
|
629
|
-
* convMatrix2EularZYX(mt3,
|
|
630
|
-
*/
|
|
631
|
-
export function convMatrix2EularZYX(rmat,
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
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
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
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
|
|
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,
|
|
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
|
|
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}
|
|
772
|
+
* @param {number} smoothSize=3 平滑点的数量通常值为奇数
|
|
764
773
|
* @returns {vec3[]} 平滑之后的点
|
|
765
774
|
*/
|
|
766
|
-
export function
|
|
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(
|
|
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 /
|
|
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
|
-
*
|
|
976
|
-
* @param {
|
|
977
|
-
* @returns {
|
|
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
|
-
|
|
985
|
-
let
|
|
986
|
-
for (let
|
|
987
|
-
|
|
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
|
-
|
|
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
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
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
|
-
|
|
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
|
}
|
package/types/vtkUtils.d.ts
CHANGED
|
@@ -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 中心点
|