xl-public-utils 1.0.13 → 1.0.15
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 +27 -1
- package/index.js +2 -1
- package/package.json +1 -1
- package/src/meshUtils.js +110 -0
- package/src/threeFont/index.js +38 -2
- package/src/vtkUtils.js +94 -0
package/index.d.ts
CHANGED
|
@@ -682,6 +682,32 @@ declare module "xl-public-utils" {
|
|
|
682
682
|
*/
|
|
683
683
|
export function initDrcCoder(): void;
|
|
684
684
|
}
|
|
685
|
+
export namespace meshUtils {
|
|
686
|
+
/**
|
|
687
|
+
* * 生成一个六边形网格 polyData
|
|
688
|
+
* @param { number } rows 行数
|
|
689
|
+
* @param { number } cols 列数
|
|
690
|
+
* @param { number } radius 半径
|
|
691
|
+
* @param { number } wall 壁厚
|
|
692
|
+
* @param { number } height 高度
|
|
693
|
+
* @param { vec3 } center 中心位置
|
|
694
|
+
* @param { vec3 } axisX 朝向 X 轴,默认 [1, 0, 0]
|
|
695
|
+
* @param { vec3 } axisY 朝向 Y 轴,默认 [0, 1, 0]
|
|
696
|
+
* @param { vec3 } axisZ 朝向 Z 轴,默认 [0, 0, 1]
|
|
697
|
+
* @returns { vtkPolyData } polydata 六边形网格
|
|
698
|
+
*/
|
|
699
|
+
export function createHexagonPolydata(
|
|
700
|
+
rows:number,
|
|
701
|
+
cols: number,
|
|
702
|
+
radius: number,
|
|
703
|
+
wall: number,
|
|
704
|
+
height: number,
|
|
705
|
+
center: vec3 = [0, 0, 0],
|
|
706
|
+
axisX: vec3 = [1, 0, 0],
|
|
707
|
+
axisY: vec3 = [0, 1, 0],
|
|
708
|
+
axisZ: vec3 = [0, 0, 1]
|
|
709
|
+
): vtkPolyData
|
|
710
|
+
}
|
|
685
711
|
|
|
686
712
|
export namespace utils {
|
|
687
713
|
/**
|
|
@@ -988,7 +1014,7 @@ declare module "xl-public-utils" {
|
|
|
988
1014
|
bevelSize: number;
|
|
989
1015
|
bevelEnabled: boolean;
|
|
990
1016
|
}
|
|
991
|
-
|
|
1017
|
+
export interface IndexData { zeroIndexs: number[], oneIndexs: number[] };
|
|
992
1018
|
export class FontManager {
|
|
993
1019
|
private constructor(); // 使用单例模式
|
|
994
1020
|
static Mgr(): FontManager;
|
package/index.js
CHANGED
|
@@ -3,5 +3,6 @@ import * as utils from './src/utils.js'
|
|
|
3
3
|
import * as qrcode from './src/qrcode.js'
|
|
4
4
|
import * as BwipJs from './src/bwip-js.js';
|
|
5
5
|
import * as drcUtils from './src/drcUtils.js';
|
|
6
|
+
import * as meshUtils from './src/meshUtils.js';
|
|
6
7
|
import FontManager from './src/threeFont/index.js';
|
|
7
|
-
export { vtkUtils, utils, qrcode, BwipJs, drcUtils, FontManager };
|
|
8
|
+
export { vtkUtils, utils, qrcode, BwipJs, drcUtils, FontManager, meshUtils };
|
package/package.json
CHANGED
package/src/meshUtils.js
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { ExtrudeGeometry } from './threeFont/TextGeometry/ExtrudeGeometry.js';
|
|
2
|
+
import { Shape } from './threeFont/Curve/Shape.js';
|
|
3
|
+
import { vec3, mat4 } from 'gl-matrix';
|
|
4
|
+
import vtkPolyData from '@kitware/vtk.js/Common/DataModel/PolyData.js';
|
|
5
|
+
import { clonePolyData, createPolyData, getL2WMatrix, getPolydataCenterOffset, mergePolyData, pointsApplyMat4 } from './vtkUtils.js';
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* * 生成六边形 Geometry
|
|
10
|
+
*/
|
|
11
|
+
export function createHexagonGeometry(radius, height, wallThickness) {
|
|
12
|
+
// 创建外六边形
|
|
13
|
+
const outerShape = new Shape();
|
|
14
|
+
for (let i = 0; i < 6; i++) {
|
|
15
|
+
const angle = (i / 6) * Math.PI * 2;
|
|
16
|
+
const x = Math.cos(angle) * radius;
|
|
17
|
+
const y = Math.sin(angle) * radius;
|
|
18
|
+
if (i === 0) {
|
|
19
|
+
outerShape.moveTo(x, y);
|
|
20
|
+
} else {
|
|
21
|
+
outerShape.lineTo(x, y);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// 计算正确的内半径(关键修正)
|
|
26
|
+
const innerRadius = radius - wallThickness / Math.cos(Math.PI / 6); // 壁厚在半径方向的分量
|
|
27
|
+
|
|
28
|
+
if (innerRadius > 0) {
|
|
29
|
+
const innerShape = new Shape();
|
|
30
|
+
for (let i = 0; i < 6; i++) {
|
|
31
|
+
const angle = (i / 6) * Math.PI * 2;
|
|
32
|
+
const x = Math.cos(angle) * innerRadius;
|
|
33
|
+
const y = Math.sin(angle) * innerRadius;
|
|
34
|
+
if (i === 0) {
|
|
35
|
+
innerShape.moveTo(x, y);
|
|
36
|
+
} else {
|
|
37
|
+
innerShape.lineTo(x, y);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
outerShape.holes.push(innerShape);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// 挤出几何体
|
|
44
|
+
const extrudeSettings = {
|
|
45
|
+
depth: height,
|
|
46
|
+
bevelEnabled: false
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
return new ExtrudeGeometry(outerShape, extrudeSettings);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* * 生成一个六边形网格 polyData
|
|
54
|
+
* @param { number } rows 行数
|
|
55
|
+
* @param { number } cols 列数
|
|
56
|
+
* @param { number } radius 半径
|
|
57
|
+
* @param { number } wall 壁厚
|
|
58
|
+
* @param { number } height 高度
|
|
59
|
+
* @param { vec3 } center 中心位置
|
|
60
|
+
* @param { vec3 } axisX 朝向 X 轴,默认 [1, 0, 0]
|
|
61
|
+
* @param { vec3 } axisY 朝向 Y 轴,默认 [0, 1, 0]
|
|
62
|
+
* @param { vec3 } axisZ 朝向 Z 轴,默认 [0, 0, 1]
|
|
63
|
+
* @returns { vtkPolyData } polydata 六边形网格
|
|
64
|
+
*/
|
|
65
|
+
export function createHexagonPolydata(
|
|
66
|
+
rows,
|
|
67
|
+
cols,
|
|
68
|
+
radius,
|
|
69
|
+
wall,
|
|
70
|
+
height,
|
|
71
|
+
center = [0, 0, 0],
|
|
72
|
+
axisX = [1, 0, 0],
|
|
73
|
+
axisY = [0, 1, 0],
|
|
74
|
+
axisZ = [0, 0, 1]
|
|
75
|
+
) {
|
|
76
|
+
// 计算偏移量(根据OpenSCAD代码和形状调整)
|
|
77
|
+
const z = Math.sqrt(3); // sqrt(3);
|
|
78
|
+
const _wall = wall / Math.sqrt(2); //六边形网格边上有重叠
|
|
79
|
+
|
|
80
|
+
const a = radius * 1.5 - _wall / 2 / z;
|
|
81
|
+
const b = (radius / 2) * z - _wall / 2 / z;
|
|
82
|
+
|
|
83
|
+
const geometry = createHexagonGeometry(radius, height, _wall);
|
|
84
|
+
const polyData = createPolyData(geometry.vertices, geometry.faces);
|
|
85
|
+
|
|
86
|
+
let polyDataArr = [];
|
|
87
|
+
// 生成网格
|
|
88
|
+
for (let i = 0; i < rows; i++) {
|
|
89
|
+
let q = i % 2; // 奇偶行偏移
|
|
90
|
+
for (let j = 1; j <= cols; j++) {
|
|
91
|
+
let _polyData = clonePolyData(polyData);
|
|
92
|
+
|
|
93
|
+
// 根据形状和OpenSCAD公式计算位置
|
|
94
|
+
let x = i * a;
|
|
95
|
+
let y = j * b * 2 + q * b - b;
|
|
96
|
+
let _trans = mat4.fromTranslation(mat4.create(), [x, y, 0]);
|
|
97
|
+
pointsApplyMat4(_trans, _polyData);
|
|
98
|
+
polyDataArr.push(_polyData);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const resultPolyData = mergePolyData(polyDataArr);
|
|
103
|
+
const _offset = getPolydataCenterOffset(resultPolyData);
|
|
104
|
+
const offsetM4 = mat4.translate(mat4.create(), mat4.create(), [_offset.x, _offset.y, 0]);
|
|
105
|
+
pointsApplyMat4(offsetM4, resultPolyData);
|
|
106
|
+
|
|
107
|
+
const _matrix = getL2WMatrix(center, axisX, axisY, axisZ);
|
|
108
|
+
pointsApplyMat4(_matrix, resultPolyData);
|
|
109
|
+
return resultPolyData;
|
|
110
|
+
}
|
package/src/threeFont/index.js
CHANGED
|
@@ -68,7 +68,7 @@ class FontManager {
|
|
|
68
68
|
* @param {string} text
|
|
69
69
|
* @param {string} fontName
|
|
70
70
|
* @param {vec3} scale
|
|
71
|
-
* @returns {{ polyData:
|
|
71
|
+
* @returns {{ polyData: vtkPolyData, indexData: { zeroIndexs: number[], oneIndexs: number[] } }}
|
|
72
72
|
*/
|
|
73
73
|
generateShapes(text, fontName = 'defaultFont', scale = [0.018, 0.018, 0.018]) {
|
|
74
74
|
const scaleM4 = mat4.scale(mat4.create(), mat4.create(), scale);
|
|
@@ -87,7 +87,9 @@ class FontManager {
|
|
|
87
87
|
|
|
88
88
|
let polyData = this.createPolyData(extrude.vertices, extrude.faces);
|
|
89
89
|
polyData = deduplicatePolyData(polyData);
|
|
90
|
+
polyData = this.reIndexPolyData(polyData);
|
|
90
91
|
const indexData = this.getPointsMapData(polyData);
|
|
92
|
+
// console.log(indexData);
|
|
91
93
|
|
|
92
94
|
const _polyData = clonePolyData(polyData);
|
|
93
95
|
pointsApplyMat4(scaleM4, _polyData);
|
|
@@ -103,7 +105,7 @@ class FontManager {
|
|
|
103
105
|
|
|
104
106
|
/**
|
|
105
107
|
* 获取前后层顶点索引映射数据
|
|
106
|
-
* @param {
|
|
108
|
+
* @param {vtkPolyData} polydata
|
|
107
109
|
* @returns {{ zeroIndexs: number[], oneIndexs: number[] }}
|
|
108
110
|
*/
|
|
109
111
|
getPointsMapData(polydata) {
|
|
@@ -134,6 +136,40 @@ class FontManager {
|
|
|
134
136
|
oneIndexs
|
|
135
137
|
};
|
|
136
138
|
}
|
|
139
|
+
/**
|
|
140
|
+
*
|
|
141
|
+
* @param {vtkPolyData} polydata
|
|
142
|
+
* @returns {vtkPolyData} 重组索引之后的polydata
|
|
143
|
+
*/
|
|
144
|
+
reIndexPolyData(polydata) {
|
|
145
|
+
const indexData = this.getPointsMapData(polydata);
|
|
146
|
+
const allIndexData = [...indexData.zeroIndexs, ...indexData.oneIndexs]
|
|
147
|
+
const nowPoints = polydata.getPoints().getData();
|
|
148
|
+
const nowFaces = polydata.getPolys().getData();
|
|
149
|
+
const newPoints = new Float32Array(nowPoints.length);
|
|
150
|
+
const indexMap = {};
|
|
151
|
+
for(let i = 0; i < allIndexData.length; i++) {
|
|
152
|
+
const index = allIndexData[i];
|
|
153
|
+
const x = nowPoints[index * 3];
|
|
154
|
+
const y = nowPoints[index * 3 + 1];
|
|
155
|
+
const z = nowPoints[index * 3 + 2];
|
|
156
|
+
newPoints[i * 3] = x
|
|
157
|
+
newPoints[i * 3 + 1] = y
|
|
158
|
+
newPoints[i * 3 + 2] = z
|
|
159
|
+
indexMap[index] = i;
|
|
160
|
+
}
|
|
161
|
+
for(let i =0; i< nowFaces.length; i += 4) {
|
|
162
|
+
const p1 = nowFaces[i + 1];
|
|
163
|
+
const p2 = nowFaces[i + 2]
|
|
164
|
+
const p3 = nowFaces[i + 3]
|
|
165
|
+
nowFaces[i + 1] = indexMap[p1]
|
|
166
|
+
nowFaces[i + 2] = indexMap[p2]
|
|
167
|
+
nowFaces[i + 3] = indexMap[p3]
|
|
168
|
+
}
|
|
169
|
+
polydata.getPoints().setData(newPoints);
|
|
170
|
+
polydata.getPolys().setData(nowFaces);
|
|
171
|
+
return polydata
|
|
172
|
+
}
|
|
137
173
|
|
|
138
174
|
/**
|
|
139
175
|
* 创建 vtkPolyData 对象
|
package/src/vtkUtils.js
CHANGED
|
@@ -10,6 +10,9 @@ 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 vtkPoints from '@kitware/vtk.js/Common/Core/Points';
|
|
14
|
+
import vtkCellArray from '@kitware/vtk.js/Common/Core/CellArray';
|
|
15
|
+
import vtkAppendPolyData from '@kitware/vtk.js/Filters/General/AppendPolyData';
|
|
13
16
|
import { vec3, mat4, mat3, quat } from 'gl-matrix';
|
|
14
17
|
import { exportBinarySTL } from './exportSTL.js';
|
|
15
18
|
import { writePLY } from "./exportPLY.js";
|
|
@@ -1043,4 +1046,95 @@ export function clonePolyData(originalPolyData) {
|
|
|
1043
1046
|
const originalCells = originalPolyData.getPolys().getData();
|
|
1044
1047
|
clonedPolyData.getPolys().setData([...originalCells]);
|
|
1045
1048
|
return clonedPolyData;
|
|
1049
|
+
}
|
|
1050
|
+
|
|
1051
|
+
/**
|
|
1052
|
+
* 根据点和面创建一个vtkPolydata
|
|
1053
|
+
* @param {number[] | TypedArray} verts
|
|
1054
|
+
* @param {number[] | TypedArray} faces
|
|
1055
|
+
* @returns { vtkPolyData } 生成出来的vtkPolydata
|
|
1056
|
+
*/
|
|
1057
|
+
export function createPolyData(verts, faces) {
|
|
1058
|
+
let values_v = Object.values(verts);
|
|
1059
|
+
let values_f = Object.values(faces);
|
|
1060
|
+
let _verts = [];
|
|
1061
|
+
let _faces = [];
|
|
1062
|
+
values_v.forEach((v) => _verts.push(parseFloat(v)));
|
|
1063
|
+
values_f.forEach((f) => _faces.push(parseInt(f)));
|
|
1064
|
+
|
|
1065
|
+
const vpoints = vtkPoints.newInstance();
|
|
1066
|
+
const cellArray = vtkCellArray.newInstance();
|
|
1067
|
+
|
|
1068
|
+
vpoints.setData(_verts, 3);
|
|
1069
|
+
cellArray.setNumberOfComponents(4);
|
|
1070
|
+
cellArray.setData(_faces);
|
|
1071
|
+
|
|
1072
|
+
const polyData = vtkPolyData.newInstance();
|
|
1073
|
+
polyData.setPoints(vpoints);
|
|
1074
|
+
polyData.setPolys(cellArray);
|
|
1075
|
+
return polyData;
|
|
1076
|
+
}
|
|
1077
|
+
|
|
1078
|
+
|
|
1079
|
+
/**
|
|
1080
|
+
* 合并多个polydata
|
|
1081
|
+
* @param {vtkPolyData[]} params 多个polyData
|
|
1082
|
+
* @returns { vtkPolyData } 合并之后的polydata
|
|
1083
|
+
*/
|
|
1084
|
+
export function mergePolyData(params) {
|
|
1085
|
+
const appendPolyData = vtkAppendPolyData.newInstance();
|
|
1086
|
+
params.forEach(data => {
|
|
1087
|
+
appendPolyData.addInputData(data);
|
|
1088
|
+
});
|
|
1089
|
+
return appendPolyData.getOutputData();
|
|
1090
|
+
}
|
|
1091
|
+
|
|
1092
|
+
/**
|
|
1093
|
+
* 计算网格的boundingBox
|
|
1094
|
+
* @param { vtkPolyData } polydata 网格数据
|
|
1095
|
+
* @returns 返回网格的boundingBox
|
|
1096
|
+
*/
|
|
1097
|
+
export function computeBoundingBox(polydata) {
|
|
1098
|
+
// 初始化最小值和最大值
|
|
1099
|
+
const min = vec3.fromValues(Infinity, Infinity, Infinity);
|
|
1100
|
+
const max = vec3.fromValues(-Infinity, -Infinity, -Infinity);
|
|
1101
|
+
|
|
1102
|
+
// 从 vtkPolyData 中提取顶点数据(假设是 Float32Array 格式)
|
|
1103
|
+
const points = polydata.getPoints().getData();
|
|
1104
|
+
const numPoints = points.length / 3;
|
|
1105
|
+
|
|
1106
|
+
// 遍历所有顶点
|
|
1107
|
+
for (let i = 0; i < numPoints; i++) {
|
|
1108
|
+
const x = points[i * 3];
|
|
1109
|
+
const y = points[i * 3 + 1];
|
|
1110
|
+
const z = points[i * 3 + 2];
|
|
1111
|
+
|
|
1112
|
+
// 更新最小值和最大值
|
|
1113
|
+
min[0] = Math.min(min[0], x);
|
|
1114
|
+
min[1] = Math.min(min[1], y);
|
|
1115
|
+
min[2] = Math.min(min[2], z);
|
|
1116
|
+
|
|
1117
|
+
max[0] = Math.max(max[0], x);
|
|
1118
|
+
max[1] = Math.max(max[1], y);
|
|
1119
|
+
max[2] = Math.max(max[2], z);
|
|
1120
|
+
}
|
|
1121
|
+
|
|
1122
|
+
return { min, max };
|
|
1123
|
+
}
|
|
1124
|
+
|
|
1125
|
+
/**
|
|
1126
|
+
* 计算网格移动到相对自己中心位置的xyz偏移量
|
|
1127
|
+
* @param { vtkPolyData } _polydata 网格
|
|
1128
|
+
* @returns {{x: number, y: number, z: number}} 网格自己居中所需要的xyz偏移量
|
|
1129
|
+
*/
|
|
1130
|
+
export function getPolydataCenterOffset(_polydata) {
|
|
1131
|
+
const _boundBox = computeBoundingBox(_polydata);
|
|
1132
|
+
const _width = Math.abs(_boundBox.min[0] - _boundBox.max[0]);
|
|
1133
|
+
const _height = Math.abs(_boundBox.min[1] - _boundBox.max[1]);
|
|
1134
|
+
const _surface =Math.abs(_boundBox.min[2] - _boundBox.max[2]);
|
|
1135
|
+
return {
|
|
1136
|
+
x: -(_boundBox.max[0] - _width / 2),
|
|
1137
|
+
y: -(_boundBox.max[1] - _height / 2),
|
|
1138
|
+
z: -(_boundBox.max[2] - _surface / 2),
|
|
1139
|
+
};
|
|
1046
1140
|
}
|