@giszhc/three-model-viewer 0.0.0-stage → 1.0.1
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/LICENSE +21 -0
- package/README.md +296 -2
- package/dist/core/EventEmitter.d.ts +9 -0
- package/dist/core/SceneManager.d.ts +28 -0
- package/dist/core/Viewer.d.ts +115 -0
- package/dist/index.cjs +5 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.js +1875 -0
- package/dist/index.js.map +1 -0
- package/dist/index.umd.js +4230 -0
- package/dist/index.umd.js.map +1 -0
- package/dist/loaders/ModelLoader.d.ts +69 -0
- package/dist/loaders/ZipExtractor.d.ts +14 -0
- package/dist/style.css +2 -0
- package/dist/tools/BoundingBoxTool.d.ts +36 -0
- package/dist/tools/CameraTool.d.ts +39 -0
- package/dist/tools/ClippingTool.d.ts +140 -0
- package/dist/tools/MeasurementTool.d.ts +61 -0
- package/dist/tools/ScreenshotTool.d.ts +21 -0
- package/dist/types/index.d.ts +121 -0
- package/dist/utils/math.d.ts +21 -0
- package/dist/utils/snapping.d.ts +14 -0
- package/package.json +67 -3
package/dist/index.js
ADDED
|
@@ -0,0 +1,1875 @@
|
|
|
1
|
+
import * as e from "three";
|
|
2
|
+
import { OrbitControls as t } from "three/addons/controls/OrbitControls.js";
|
|
3
|
+
import { TrackballControls as n } from "three/addons/controls/TrackballControls.js";
|
|
4
|
+
import { CSS2DObject as r, CSS2DRenderer as i } from "three/addons/renderers/CSS2DRenderer.js";
|
|
5
|
+
import * as a from "@tweenjs/tween.js";
|
|
6
|
+
import { OBJLoader as o } from "three/addons/loaders/OBJLoader.js";
|
|
7
|
+
import { MTLLoader as s } from "three/addons/loaders/MTLLoader.js";
|
|
8
|
+
import { acceleratedRaycast as c, computeBoundsTree as l, disposeBoundsTree as u } from "three-mesh-bvh";
|
|
9
|
+
import d from "jszip";
|
|
10
|
+
//#region src/core/SceneManager.ts
|
|
11
|
+
var f = class {
|
|
12
|
+
container;
|
|
13
|
+
scene;
|
|
14
|
+
camera;
|
|
15
|
+
renderer;
|
|
16
|
+
labelRenderer;
|
|
17
|
+
controls;
|
|
18
|
+
lightsGroup;
|
|
19
|
+
gridHelper;
|
|
20
|
+
tweenGroup;
|
|
21
|
+
onBeforeRender;
|
|
22
|
+
animationFrameId = null;
|
|
23
|
+
resizeObserver = null;
|
|
24
|
+
isDestroyed = !1;
|
|
25
|
+
constructor(r) {
|
|
26
|
+
this.container = r.container, this.scene = new e.Scene(), r.background !== void 0 && r.background !== null ? (typeof r.background == "string" || typeof r.background == "number") && (this.scene.background = new e.Color(r.background)) : this.scene.background = new e.Color(1580068);
|
|
27
|
+
let o = this.container.clientWidth || 800, s = this.container.clientHeight || 600;
|
|
28
|
+
if (this.camera = new e.PerspectiveCamera(r.cameraFov ?? 45, o / s, r.cameraNear ?? .1, r.cameraFar ?? 5e3), this.camera.position.set(10, 10, 10), this.renderer = new e.WebGLRenderer({
|
|
29
|
+
antialias: r.antialias ?? !0,
|
|
30
|
+
alpha: r.alpha ?? !1,
|
|
31
|
+
preserveDrawingBuffer: !0,
|
|
32
|
+
powerPreference: "high-performance"
|
|
33
|
+
}), this.renderer.setSize(o, s), this.renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2)), this.renderer.localClippingEnabled = !0, this.renderer.toneMapping = e.ACESFilmicToneMapping, this.renderer.toneMappingExposure = 1, this.renderer.outputColorSpace = e.SRGBColorSpace, this.renderer.domElement.style.display = "block", this.renderer.domElement.style.width = "100%", this.renderer.domElement.style.height = "100%", this.container.appendChild(this.renderer.domElement), this.labelRenderer = new i(), this.labelRenderer.setSize(o, s), this.labelRenderer.domElement.style.position = "absolute", this.labelRenderer.domElement.style.top = "0", this.labelRenderer.domElement.style.left = "0", this.labelRenderer.domElement.style.pointerEvents = "none", this.labelRenderer.domElement.style.width = "100%", this.labelRenderer.domElement.style.height = "100%", this.labelRenderer.domElement.className = "gmv-css2d-container", this.container.appendChild(this.labelRenderer.domElement), (r.controlsType ?? "trackball") === "orbit") {
|
|
34
|
+
let e = new t(this.camera, this.renderer.domElement);
|
|
35
|
+
e.enableDamping = !0, e.dampingFactor = .05, e.screenSpacePanning = !0, this.controls = e;
|
|
36
|
+
} else {
|
|
37
|
+
let e = new n(this.camera, this.renderer.domElement);
|
|
38
|
+
e.rotateSpeed = 2.5, e.zoomSpeed = 1.2, e.panSpeed = .8, e.staticMoving = !1, e.dynamicDampingFactor = .15, this.controls = e;
|
|
39
|
+
}
|
|
40
|
+
this.tweenGroup = new a.Group(), this.lightsGroup = new e.Group(), this.lightsGroup.name = "gmv-lights-group", this.initLights(), this.scene.add(this.lightsGroup), this.gridHelper = new e.GridHelper(50, 50, 4871528, 2963272), this.gridHelper.name = "gmv-grid-helper", this.gridHelper.position.y = 0, this.gridHelper.visible = !1, this.scene.add(this.gridHelper), this.initResizeObserver(), this.startAnimationLoop(), requestAnimationFrame(() => this.handleResize()), setTimeout(() => this.handleResize(), 50);
|
|
41
|
+
}
|
|
42
|
+
initLights() {
|
|
43
|
+
let t = new e.HemisphereLight(16777215, 4674921, 1);
|
|
44
|
+
t.position.set(0, 50, 0), this.lightsGroup.add(t);
|
|
45
|
+
let n = new e.AmbientLight(16777215, .8);
|
|
46
|
+
this.lightsGroup.add(n);
|
|
47
|
+
let r = new e.DirectionalLight(16777215, 1.2);
|
|
48
|
+
r.position.set(50, 100, 50), this.lightsGroup.add(r);
|
|
49
|
+
let i = new e.DirectionalLight(16777215, .7);
|
|
50
|
+
i.position.set(-50, 50, -50), this.lightsGroup.add(i);
|
|
51
|
+
let a = new e.DirectionalLight(16777215, .9);
|
|
52
|
+
a.position.set(0, 0, 1), this.camera.add(a), this.scene.add(this.camera);
|
|
53
|
+
}
|
|
54
|
+
initResizeObserver() {
|
|
55
|
+
this.resizeObserver = new ResizeObserver(() => {
|
|
56
|
+
this.handleResize();
|
|
57
|
+
}), this.resizeObserver.observe(this.container);
|
|
58
|
+
}
|
|
59
|
+
handleResize() {
|
|
60
|
+
if (this.isDestroyed || !this.container) return;
|
|
61
|
+
let e = this.container.clientWidth, t = this.container.clientHeight;
|
|
62
|
+
e !== 0 && t !== 0 && (this.camera.aspect = e / t, this.camera.updateProjectionMatrix(), this.renderer.setSize(e, t), this.labelRenderer.setSize(e, t), "handleResize" in this.controls && typeof this.controls.handleResize == "function" && this.controls.handleResize());
|
|
63
|
+
}
|
|
64
|
+
startAnimationLoop() {
|
|
65
|
+
let e = () => {
|
|
66
|
+
this.isDestroyed || (this.animationFrameId = requestAnimationFrame(e), this.tweenGroup.update(), this.controls.update(), this.onBeforeRender && this.onBeforeRender(), this.renderer.render(this.scene, this.camera), this.labelRenderer.render(this.scene, this.camera));
|
|
67
|
+
};
|
|
68
|
+
this.animationFrameId = requestAnimationFrame(e);
|
|
69
|
+
}
|
|
70
|
+
setBackground(t, n) {
|
|
71
|
+
n || t == null ? (this.scene.background = null, this.renderer.setClearAlpha(0)) : (this.scene.background = new e.Color(t), this.renderer.setClearAlpha(1));
|
|
72
|
+
}
|
|
73
|
+
destroy() {
|
|
74
|
+
this.isDestroyed = !0, this.animationFrameId !== null && cancelAnimationFrame(this.animationFrameId), this.resizeObserver && this.resizeObserver.disconnect(), this.controls.dispose(), this.renderer.dispose(), this.renderer.domElement.parentElement && this.renderer.domElement.parentElement.removeChild(this.renderer.domElement), this.labelRenderer.domElement.parentElement && this.labelRenderer.domElement.parentElement.removeChild(this.labelRenderer.domElement);
|
|
75
|
+
}
|
|
76
|
+
}, p = class {
|
|
77
|
+
events;
|
|
78
|
+
constructor() {
|
|
79
|
+
this.events = /* @__PURE__ */ new Map();
|
|
80
|
+
}
|
|
81
|
+
on(e, t) {
|
|
82
|
+
return this.events.has(e) || this.events.set(e, []), this.events.get(e).push(t), this;
|
|
83
|
+
}
|
|
84
|
+
off(e, t) {
|
|
85
|
+
let n = this.events.get(e);
|
|
86
|
+
if (!n) return this;
|
|
87
|
+
let r = n.indexOf(t);
|
|
88
|
+
return r !== -1 && n.splice(r, 1), this;
|
|
89
|
+
}
|
|
90
|
+
emit(e, ...t) {
|
|
91
|
+
let n = this.events.get(e);
|
|
92
|
+
return !n || n.length === 0 ? !1 : ([...n].forEach((n) => {
|
|
93
|
+
try {
|
|
94
|
+
n(...t);
|
|
95
|
+
} catch (t) {
|
|
96
|
+
console.error(`Error in event listener for "${e}":`, t);
|
|
97
|
+
}
|
|
98
|
+
}), !0);
|
|
99
|
+
}
|
|
100
|
+
removeAllListeners(e) {
|
|
101
|
+
return e ? this.events.delete(e) : this.events.clear(), this;
|
|
102
|
+
}
|
|
103
|
+
}, m = class {
|
|
104
|
+
static async extract(t, n) {
|
|
105
|
+
let r;
|
|
106
|
+
if (n?.(5, "正在读取文件字节流..."), typeof t == "string") {
|
|
107
|
+
let e = await fetch(t);
|
|
108
|
+
if (!e.ok) throw Error(`Failed to fetch zip file: ${e.statusText}`);
|
|
109
|
+
r = await e.arrayBuffer();
|
|
110
|
+
} else r = t instanceof Blob || t instanceof File ? await t.arrayBuffer() : t;
|
|
111
|
+
n?.(15, "正在解压 ZIP 文件包...");
|
|
112
|
+
let i = await d.loadAsync(r), a = /* @__PURE__ */ new Map(), o = null, s = null, c = [
|
|
113
|
+
".png",
|
|
114
|
+
".jpg",
|
|
115
|
+
".jpeg",
|
|
116
|
+
".webp",
|
|
117
|
+
".bmp",
|
|
118
|
+
".tga",
|
|
119
|
+
".dds"
|
|
120
|
+
], l = Object.keys(i.files), u = l.length || 1;
|
|
121
|
+
for (let e = 0; e < l.length; e++) {
|
|
122
|
+
let t = l[e], r = i.files[t];
|
|
123
|
+
if (r.dir || t.includes("__MACOSX") || t.split("/").pop()?.startsWith("._")) continue;
|
|
124
|
+
let d = t.toLowerCase(), f = Math.round(20 + e / u * 35);
|
|
125
|
+
if (d.endsWith(".obj") && !o ? (o = r, n?.(f, `找到模型文件: ${t.split("/").pop()}`)) : d.endsWith(".mtl") && !s && (s = r, n?.(f, `找到材质定义: ${t.split("/").pop()}`)), c.some((e) => d.endsWith(e))) {
|
|
126
|
+
let e = t.split("/").pop() || t;
|
|
127
|
+
n?.(f, `加载贴图: ${e}`);
|
|
128
|
+
let i = await r.async("blob"), o = URL.createObjectURL(i);
|
|
129
|
+
a.set(t, o), a.set(e, o), a.set(e.toLowerCase(), o);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
if (n?.(60, "提取完成,准备解析三维几何网格..."), !o) throw a.forEach((e) => URL.revokeObjectURL(e)), Error("No .obj file found in the zip archive.");
|
|
133
|
+
let f = await o.async("string"), p = o.name, m = null, h = null;
|
|
134
|
+
s && (m = await s.async("string"), h = s.name);
|
|
135
|
+
let g = new e.LoadingManager();
|
|
136
|
+
return g.setURLModifier((e) => {
|
|
137
|
+
let t = decodeURIComponent(e), n = t.split("/").pop()?.split("\\").pop() || t;
|
|
138
|
+
if (a.has(t)) return a.get(t);
|
|
139
|
+
if (a.has(n)) return a.get(n);
|
|
140
|
+
for (let [e, t] of a.entries()) if (e.toLowerCase() === n.toLowerCase()) return t;
|
|
141
|
+
return e;
|
|
142
|
+
}), {
|
|
143
|
+
objContent: f,
|
|
144
|
+
objFileName: p,
|
|
145
|
+
mtlContent: m,
|
|
146
|
+
mtlFileName: h,
|
|
147
|
+
blobUrls: a,
|
|
148
|
+
loadingManager: g,
|
|
149
|
+
dispose: () => {
|
|
150
|
+
a.forEach((e) => {
|
|
151
|
+
try {
|
|
152
|
+
URL.revokeObjectURL(e);
|
|
153
|
+
} catch {}
|
|
154
|
+
}), a.clear();
|
|
155
|
+
}
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
};
|
|
159
|
+
e.BufferGeometry.prototype.computeBoundsTree = l, e.BufferGeometry.prototype.disposeBoundsTree = u, e.Mesh.prototype.raycast = c;
|
|
160
|
+
var h = class {
|
|
161
|
+
currentZipContent = null;
|
|
162
|
+
managedMaterials = [];
|
|
163
|
+
isTextureEnabled = !0;
|
|
164
|
+
displayStyle = "solid";
|
|
165
|
+
plainColor = 5016790;
|
|
166
|
+
currentClippingPlanes = [];
|
|
167
|
+
async loadZip(e, t) {
|
|
168
|
+
this.cleanup();
|
|
169
|
+
let n = await m.extract(e, t);
|
|
170
|
+
this.currentZipContent = n;
|
|
171
|
+
let { objContent: r, mtlContent: i, loadingManager: a } = n;
|
|
172
|
+
t?.(65, "正在解析材质与贴图数据...");
|
|
173
|
+
let c = null;
|
|
174
|
+
i && (c = new s(a).parse(i, ""), c.preload()), t?.(75, "正在解析 OBJ 网格几何数据...");
|
|
175
|
+
let l = new o(a);
|
|
176
|
+
c && l.setMaterials(c);
|
|
177
|
+
let u = typeof r == "string" ? r : new TextDecoder().decode(r), d = l.parse(u);
|
|
178
|
+
t?.(88, "正在建立空间 BVH 加速结构与几何居中...");
|
|
179
|
+
let f = this.postProcessModel(d);
|
|
180
|
+
return t?.(100, "加载完成"), f;
|
|
181
|
+
}
|
|
182
|
+
async loadOBJ(e, t, n) {
|
|
183
|
+
this.cleanup(), n?.(20, "正在加载材质定义...");
|
|
184
|
+
let r = null;
|
|
185
|
+
t && (r = await new s().loadAsync(t), r.preload()), n?.(50, "正在加载 OBJ 模型几何数据...");
|
|
186
|
+
let i = new o();
|
|
187
|
+
r && i.setMaterials(r);
|
|
188
|
+
let a = await i.loadAsync(e, (e) => {
|
|
189
|
+
if (e.lengthComputable && e.total > 0) {
|
|
190
|
+
let t = Math.round(50 + e.loaded / e.total * 35);
|
|
191
|
+
n?.(t, `正在传输模型数据 (${Math.round(e.loaded / e.total * 100)}%)...`);
|
|
192
|
+
}
|
|
193
|
+
});
|
|
194
|
+
n?.(88, "正在建立空间 BVH 加速结构与几何居中...");
|
|
195
|
+
let c = this.postProcessModel(a);
|
|
196
|
+
return n?.(100, "加载完成"), c;
|
|
197
|
+
}
|
|
198
|
+
postProcessModel(t) {
|
|
199
|
+
let n = 0, r = 0;
|
|
200
|
+
this.managedMaterials = [];
|
|
201
|
+
let i = (t) => {
|
|
202
|
+
t && (t.anisotropy = 16, t.generateMipmaps = !0, t.minFilter = e.LinearMipmapLinearFilter, t.magFilter = e.LinearFilter, t.colorSpace = e.SRGBColorSpace, t.needsUpdate = !0);
|
|
203
|
+
}, a = (t) => {
|
|
204
|
+
if (t.side = e.DoubleSide, t.needsUpdate = !0, "color" in t) {
|
|
205
|
+
let e = t;
|
|
206
|
+
i(e.map), "normalMap" in e && i(e.normalMap), "bumpMap" in e && i(e.bumpMap), !e.map && e.color && e.color.getHex() < 2236962 && e.color.setHex(11581636);
|
|
207
|
+
}
|
|
208
|
+
}, o = new e.Box3().setFromObject(t), s = new e.Vector3(), c = new e.Vector3();
|
|
209
|
+
return o.getCenter(s), o.getSize(c), t.traverse((t) => {
|
|
210
|
+
if (t.isMesh) {
|
|
211
|
+
let i = t;
|
|
212
|
+
i.castShadow = !0, i.receiveShadow = !0, i.material ? Array.isArray(i.material) ? i.material.forEach(a) : a(i.material) : i.material = new e.MeshStandardMaterial({
|
|
213
|
+
color: this.plainColor,
|
|
214
|
+
roughness: .45,
|
|
215
|
+
metalness: .12,
|
|
216
|
+
side: e.DoubleSide
|
|
217
|
+
});
|
|
218
|
+
let o = i.geometry;
|
|
219
|
+
if (o) {
|
|
220
|
+
o.translate(-s.x, -s.y, -s.z), o.attributes.normal || o.computeVertexNormals(), o.computeBoundsTree && o.computeBoundsTree(), o.attributes.position && (n += o.attributes.position.count), o.index ? r += o.index.count / 3 : o.attributes.position && (r += o.attributes.position.count / 3);
|
|
221
|
+
let t = new e.MeshStandardMaterial({
|
|
222
|
+
color: this.plainColor,
|
|
223
|
+
roughness: .45,
|
|
224
|
+
metalness: .12,
|
|
225
|
+
side: e.DoubleSide,
|
|
226
|
+
clippingPlanes: this.currentClippingPlanes.length > 0 ? this.currentClippingPlanes : null,
|
|
227
|
+
clipShadows: !0
|
|
228
|
+
}), a = {
|
|
229
|
+
mesh: i,
|
|
230
|
+
originalMaterial: i.material,
|
|
231
|
+
plainMaterial: t
|
|
232
|
+
};
|
|
233
|
+
this.applyStyleToItem(a), this.managedMaterials.push(a);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
}), t.position.set(0, 0, 0), t.rotation.set(0, 0, 0), t.scale.set(1, 1, 1), t.updateMatrixWorld(!0), {
|
|
237
|
+
model: t,
|
|
238
|
+
box: new e.Box3().setFromObject(t),
|
|
239
|
+
size: c,
|
|
240
|
+
center: s,
|
|
241
|
+
vertexCount: n,
|
|
242
|
+
faceCount: Math.round(r)
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
applyStyleToItem(e) {
|
|
246
|
+
let t = this.isTextureEnabled ? e.originalMaterial : e.plainMaterial;
|
|
247
|
+
e.mesh.material = t;
|
|
248
|
+
let n = (e) => {
|
|
249
|
+
e.visible = !0, "wireframe" in e && (e.wireframe = this.displayStyle === "wireframe"), e.needsUpdate = !0;
|
|
250
|
+
};
|
|
251
|
+
Array.isArray(t) ? t.forEach(n) : n(t);
|
|
252
|
+
}
|
|
253
|
+
setDisplayStyle(e) {
|
|
254
|
+
this.displayStyle = e;
|
|
255
|
+
for (let e of this.managedMaterials) this.applyStyleToItem(e);
|
|
256
|
+
}
|
|
257
|
+
getDisplayStyle() {
|
|
258
|
+
return this.displayStyle;
|
|
259
|
+
}
|
|
260
|
+
toggleTexture(e) {
|
|
261
|
+
this.isTextureEnabled = e;
|
|
262
|
+
for (let e of this.managedMaterials) this.applyStyleToItem(e);
|
|
263
|
+
}
|
|
264
|
+
getTextureState() {
|
|
265
|
+
return this.isTextureEnabled;
|
|
266
|
+
}
|
|
267
|
+
setPlainColor(t) {
|
|
268
|
+
this.plainColor = typeof t == "string" ? new e.Color(t).getHex() : Number(t);
|
|
269
|
+
for (let e of this.managedMaterials) e.plainMaterial && "color" in e.plainMaterial && (e.plainMaterial.color.set(this.plainColor), e.plainMaterial.needsUpdate = !0);
|
|
270
|
+
}
|
|
271
|
+
getPlainColor() {
|
|
272
|
+
return this.plainColor;
|
|
273
|
+
}
|
|
274
|
+
getModelTextureSize() {
|
|
275
|
+
let e = 0, t = 0, n = (n) => {
|
|
276
|
+
if ("map" in n && n.map) {
|
|
277
|
+
let r = n.map;
|
|
278
|
+
if (r) {
|
|
279
|
+
let n = r.image || r.source?.data;
|
|
280
|
+
if (n) {
|
|
281
|
+
let r = n.width || 0, i = n.height || 0;
|
|
282
|
+
r > 0 && i > 0 && r * i > e * t && (e = r, t = i);
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
};
|
|
287
|
+
for (let e of this.managedMaterials) Array.isArray(e.originalMaterial) ? e.originalMaterial.forEach(n) : e.originalMaterial && n(e.originalMaterial);
|
|
288
|
+
return e > 0 && t > 0 ? {
|
|
289
|
+
width: e,
|
|
290
|
+
height: t
|
|
291
|
+
} : null;
|
|
292
|
+
}
|
|
293
|
+
getMeshes() {
|
|
294
|
+
return this.managedMaterials.map((e) => e.mesh);
|
|
295
|
+
}
|
|
296
|
+
applyClippingPlanes(e) {
|
|
297
|
+
this.currentClippingPlanes = e;
|
|
298
|
+
for (let t of this.managedMaterials) {
|
|
299
|
+
let n = (t) => {
|
|
300
|
+
t.clippingPlanes = e.length > 0 ? e : null, t.clipShadows = !0, t.needsUpdate = !0;
|
|
301
|
+
};
|
|
302
|
+
Array.isArray(t.originalMaterial) ? t.originalMaterial.forEach(n) : n(t.originalMaterial), n(t.plainMaterial);
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
cleanup() {
|
|
306
|
+
this.currentZipContent &&= (this.currentZipContent.dispose(), null);
|
|
307
|
+
for (let e of this.managedMaterials) e.plainMaterial && e.plainMaterial.dispose(), e.mesh.geometry && e.mesh.geometry.disposeBoundsTree && e.mesh.geometry.disposeBoundsTree();
|
|
308
|
+
this.managedMaterials = [];
|
|
309
|
+
}
|
|
310
|
+
};
|
|
311
|
+
//#endregion
|
|
312
|
+
//#region src/utils/math.ts
|
|
313
|
+
function g(t) {
|
|
314
|
+
let n = t.geometry;
|
|
315
|
+
if (!n) return 0;
|
|
316
|
+
let r = n.attributes.position;
|
|
317
|
+
if (!r) return 0;
|
|
318
|
+
let i = 0, a = new e.Vector3(), o = new e.Vector3(), s = new e.Vector3();
|
|
319
|
+
t.updateMatrixWorld(!0);
|
|
320
|
+
let c = t.matrixWorld;
|
|
321
|
+
if (n.index) {
|
|
322
|
+
let e = n.index;
|
|
323
|
+
for (let t = 0; t < e.count; t += 3) {
|
|
324
|
+
let n = e.getX(t), l = e.getX(t + 1), u = e.getX(t + 2);
|
|
325
|
+
a.fromBufferAttribute(r, n).applyMatrix4(c), o.fromBufferAttribute(r, l).applyMatrix4(c), s.fromBufferAttribute(r, u).applyMatrix4(c), i += v(a, o, s);
|
|
326
|
+
}
|
|
327
|
+
} else for (let e = 0; e < r.count; e += 3) a.fromBufferAttribute(r, e).applyMatrix4(c), o.fromBufferAttribute(r, e + 1).applyMatrix4(c), s.fromBufferAttribute(r, e + 2).applyMatrix4(c), i += v(a, o, s);
|
|
328
|
+
return Math.abs(i);
|
|
329
|
+
}
|
|
330
|
+
function _(t) {
|
|
331
|
+
let n = 0;
|
|
332
|
+
t.traverse((e) => {
|
|
333
|
+
e.isMesh && (n += g(e));
|
|
334
|
+
});
|
|
335
|
+
let r = new e.Box3().setFromObject(t), i = new e.Vector3();
|
|
336
|
+
r.getSize(i);
|
|
337
|
+
let a = i.x * i.y * i.z;
|
|
338
|
+
return {
|
|
339
|
+
meshVolume: n,
|
|
340
|
+
bboxVolume: a
|
|
341
|
+
};
|
|
342
|
+
}
|
|
343
|
+
function v(e, t, n) {
|
|
344
|
+
return e.dot(t.clone().cross(n)) / 6;
|
|
345
|
+
}
|
|
346
|
+
function y(t) {
|
|
347
|
+
let n = t.length;
|
|
348
|
+
if (n < 3) return 0;
|
|
349
|
+
let r = new e.Vector3(0, 0, 0);
|
|
350
|
+
for (let e = 0; e < n; e++) {
|
|
351
|
+
let i = t[e], a = t[(e + 1) % n];
|
|
352
|
+
r.x += (i.y - a.y) * (i.z + a.z), r.y += (i.z - a.z) * (i.x + a.x), r.z += (i.x - a.x) * (i.y + a.y);
|
|
353
|
+
}
|
|
354
|
+
return r.length() * .5;
|
|
355
|
+
}
|
|
356
|
+
function b(e, t = "m", n = 2) {
|
|
357
|
+
return Math.abs(e) < .001 ? `0.00 ${t}` : `${e.toFixed(n)} ${t}`;
|
|
358
|
+
}
|
|
359
|
+
//#endregion
|
|
360
|
+
//#region src/tools/BoundingBoxTool.ts
|
|
361
|
+
var x = class {
|
|
362
|
+
scene;
|
|
363
|
+
boxGroup;
|
|
364
|
+
wireframeBox = null;
|
|
365
|
+
lineX = null;
|
|
366
|
+
lineY = null;
|
|
367
|
+
lineZ = null;
|
|
368
|
+
labelX = null;
|
|
369
|
+
labelY = null;
|
|
370
|
+
labelZ = null;
|
|
371
|
+
currentModel = null;
|
|
372
|
+
isVisible = !1;
|
|
373
|
+
unit = "m";
|
|
374
|
+
localVertices = [];
|
|
375
|
+
worldVertices = [
|
|
376
|
+
new e.Vector3(),
|
|
377
|
+
new e.Vector3(),
|
|
378
|
+
new e.Vector3(),
|
|
379
|
+
new e.Vector3(),
|
|
380
|
+
new e.Vector3(),
|
|
381
|
+
new e.Vector3(),
|
|
382
|
+
new e.Vector3(),
|
|
383
|
+
new e.Vector3()
|
|
384
|
+
];
|
|
385
|
+
modelSize = new e.Vector3();
|
|
386
|
+
constructor(t) {
|
|
387
|
+
this.scene = t, this.boxGroup = new e.Group(), this.boxGroup.name = "gmv-bounding-box-group", this.scene.add(this.boxGroup);
|
|
388
|
+
}
|
|
389
|
+
attachToModel(t, n) {
|
|
390
|
+
this.detach(), this.currentModel = t, this.unit = n?.unit || "m", t.updateMatrixWorld(!0);
|
|
391
|
+
let i = new e.Box3();
|
|
392
|
+
t.traverse((e) => {
|
|
393
|
+
if (e.isMesh) {
|
|
394
|
+
let t = e;
|
|
395
|
+
t.geometry && (t.geometry.boundingBox || t.geometry.computeBoundingBox(), t.geometry.boundingBox && i.union(t.geometry.boundingBox));
|
|
396
|
+
}
|
|
397
|
+
}), i.isEmpty() && i.setFromObject(t);
|
|
398
|
+
let a = i.min, o = i.max;
|
|
399
|
+
i.getSize(this.modelSize), this.localVertices = [
|
|
400
|
+
new e.Vector3(a.x, a.y, a.z),
|
|
401
|
+
new e.Vector3(o.x, a.y, a.z),
|
|
402
|
+
new e.Vector3(a.x, o.y, a.z),
|
|
403
|
+
new e.Vector3(o.x, o.y, a.z),
|
|
404
|
+
new e.Vector3(a.x, a.y, o.z),
|
|
405
|
+
new e.Vector3(o.x, a.y, o.z),
|
|
406
|
+
new e.Vector3(a.x, o.y, o.z),
|
|
407
|
+
new e.Vector3(o.x, o.y, o.z)
|
|
408
|
+
];
|
|
409
|
+
let s = [
|
|
410
|
+
0,
|
|
411
|
+
1,
|
|
412
|
+
2,
|
|
413
|
+
3,
|
|
414
|
+
4,
|
|
415
|
+
5,
|
|
416
|
+
6,
|
|
417
|
+
7,
|
|
418
|
+
0,
|
|
419
|
+
2,
|
|
420
|
+
1,
|
|
421
|
+
3,
|
|
422
|
+
4,
|
|
423
|
+
6,
|
|
424
|
+
5,
|
|
425
|
+
7,
|
|
426
|
+
0,
|
|
427
|
+
4,
|
|
428
|
+
1,
|
|
429
|
+
5,
|
|
430
|
+
2,
|
|
431
|
+
6,
|
|
432
|
+
3,
|
|
433
|
+
7
|
|
434
|
+
], c = new e.BufferGeometry(), l = new Float32Array(s.length * 3);
|
|
435
|
+
c.setAttribute("position", new e.BufferAttribute(l, 3));
|
|
436
|
+
let u = new e.LineBasicMaterial({
|
|
437
|
+
color: n?.color ? new e.Color(n.color) : 54015,
|
|
438
|
+
linewidth: 1,
|
|
439
|
+
transparent: !0,
|
|
440
|
+
opacity: .6,
|
|
441
|
+
depthTest: !0
|
|
442
|
+
});
|
|
443
|
+
this.wireframeBox = new e.LineSegments(c, u), this.boxGroup.add(this.wireframeBox), this.lineX = this.createDynamicLine(15680580), this.lineY = this.createDynamicLine(1096065), this.lineZ = this.createDynamicLine(3900150);
|
|
444
|
+
let d = document.createElement("div");
|
|
445
|
+
d.className = "gmv-dimension-badge dim-x", d.innerHTML = `<span>长 (X):</span> <strong>${b(this.modelSize.x, this.unit)}</strong>`, this.labelX = new r(d), this.boxGroup.add(this.labelX);
|
|
446
|
+
let f = document.createElement("div");
|
|
447
|
+
f.className = "gmv-dimension-badge dim-y", f.innerHTML = `<span>高 (Y):</span> <strong>${b(this.modelSize.y, this.unit)}</strong>`, this.labelY = new r(f), this.boxGroup.add(this.labelY);
|
|
448
|
+
let p = document.createElement("div");
|
|
449
|
+
p.className = "gmv-dimension-badge dim-z", p.innerHTML = `<span>宽 (Z):</span> <strong>${b(this.modelSize.z, this.unit)}</strong>`, this.labelZ = new r(p), this.boxGroup.add(this.labelZ), this.setVisible(n?.visible ?? !1);
|
|
450
|
+
}
|
|
451
|
+
createDynamicLine(t) {
|
|
452
|
+
let n = new e.BufferGeometry().setFromPoints([new e.Vector3(), new e.Vector3()]), r = new e.LineBasicMaterial({
|
|
453
|
+
color: t,
|
|
454
|
+
linewidth: 3,
|
|
455
|
+
depthTest: !1
|
|
456
|
+
}), i = new e.Line(n, r);
|
|
457
|
+
return this.boxGroup.add(i), i;
|
|
458
|
+
}
|
|
459
|
+
update(e) {
|
|
460
|
+
if (!this.isVisible || !this.currentModel || this.localVertices.length < 8) return;
|
|
461
|
+
this.currentModel.updateMatrixWorld(!0);
|
|
462
|
+
let t = this.currentModel.matrixWorld;
|
|
463
|
+
for (let e = 0; e < 8; e++) this.worldVertices[e].copy(this.localVertices[e]).applyMatrix4(t);
|
|
464
|
+
if (this.wireframeBox) {
|
|
465
|
+
let e = [
|
|
466
|
+
0,
|
|
467
|
+
1,
|
|
468
|
+
2,
|
|
469
|
+
3,
|
|
470
|
+
4,
|
|
471
|
+
5,
|
|
472
|
+
6,
|
|
473
|
+
7,
|
|
474
|
+
0,
|
|
475
|
+
2,
|
|
476
|
+
1,
|
|
477
|
+
3,
|
|
478
|
+
4,
|
|
479
|
+
6,
|
|
480
|
+
5,
|
|
481
|
+
7,
|
|
482
|
+
0,
|
|
483
|
+
4,
|
|
484
|
+
1,
|
|
485
|
+
5,
|
|
486
|
+
2,
|
|
487
|
+
6,
|
|
488
|
+
3,
|
|
489
|
+
7
|
|
490
|
+
], t = this.wireframeBox.geometry.attributes.position, n = 0;
|
|
491
|
+
for (let r of e) {
|
|
492
|
+
let e = this.worldVertices[r];
|
|
493
|
+
t.setXYZ(n++, e.x, e.y, e.z);
|
|
494
|
+
}
|
|
495
|
+
t.needsUpdate = !0;
|
|
496
|
+
}
|
|
497
|
+
let n = 0, r = Infinity, i = e.position;
|
|
498
|
+
for (let e = 0; e < 8; e++) {
|
|
499
|
+
let t = this.worldVertices[e].distanceTo(i);
|
|
500
|
+
t < r && (r = t, n = e);
|
|
501
|
+
}
|
|
502
|
+
let a = this.worldVertices[n], o = this.worldVertices[n ^ 1], s = this.worldVertices[n ^ 2], c = this.worldVertices[n ^ 4];
|
|
503
|
+
this.updateLine(this.lineX, a, o), this.updateLine(this.lineY, a, s), this.updateLine(this.lineZ, a, c), this.labelX && this.labelX.position.copy(a).add(o).multiplyScalar(.5), this.labelY && this.labelY.position.copy(a).add(s).multiplyScalar(.5), this.labelZ && this.labelZ.position.copy(a).add(c).multiplyScalar(.5);
|
|
504
|
+
}
|
|
505
|
+
updateLine(e, t, n) {
|
|
506
|
+
if (!e) return;
|
|
507
|
+
let r = e.geometry.attributes.position;
|
|
508
|
+
r.setXYZ(0, t.x, t.y, t.z), r.setXYZ(1, n.x, n.y, n.z), r.needsUpdate = !0;
|
|
509
|
+
}
|
|
510
|
+
setVisible(e) {
|
|
511
|
+
this.isVisible = e, this.boxGroup.visible = e;
|
|
512
|
+
}
|
|
513
|
+
getVisible() {
|
|
514
|
+
return this.isVisible;
|
|
515
|
+
}
|
|
516
|
+
setUnit(e) {
|
|
517
|
+
this.unit = e, this.currentModel && this.attachToModel(this.currentModel, {
|
|
518
|
+
visible: this.isVisible,
|
|
519
|
+
unit: e
|
|
520
|
+
});
|
|
521
|
+
}
|
|
522
|
+
detach() {
|
|
523
|
+
this.wireframeBox &&= (this.wireframeBox.geometry.dispose(), this.wireframeBox.material.dispose(), this.boxGroup.remove(this.wireframeBox), null), this.lineX &&= (this.lineX.geometry.dispose(), this.lineX.material.dispose(), this.boxGroup.remove(this.lineX), null), this.lineY &&= (this.lineY.geometry.dispose(), this.lineY.material.dispose(), this.boxGroup.remove(this.lineY), null), this.lineZ &&= (this.lineZ.geometry.dispose(), this.lineZ.material.dispose(), this.boxGroup.remove(this.lineZ), null), this.labelX &&= (this.boxGroup.remove(this.labelX), null), this.labelY &&= (this.boxGroup.remove(this.labelY), null), this.labelZ &&= (this.boxGroup.remove(this.labelZ), null), this.localVertices = [], this.currentModel = null;
|
|
524
|
+
}
|
|
525
|
+
destroy() {
|
|
526
|
+
this.detach(), this.scene.remove(this.boxGroup);
|
|
527
|
+
}
|
|
528
|
+
}, S = class {
|
|
529
|
+
camera;
|
|
530
|
+
controls;
|
|
531
|
+
tweenGroup;
|
|
532
|
+
currentTween = null;
|
|
533
|
+
isAutoRotating = !1;
|
|
534
|
+
autoRotateAxis = "x";
|
|
535
|
+
autoRotateDirection = "clockwise";
|
|
536
|
+
autoRotateSpeed = 1;
|
|
537
|
+
lockedAxis = null;
|
|
538
|
+
lockedPitchAngle = 0;
|
|
539
|
+
lockedYawAngle = 0;
|
|
540
|
+
constructor(e, t, n) {
|
|
541
|
+
this.camera = e, this.controls = t, this.tweenGroup = n || new a.Group();
|
|
542
|
+
}
|
|
543
|
+
setAutoRotate(e, t, n, r) {
|
|
544
|
+
this.isAutoRotating = e, t !== void 0 && (this.autoRotateAxis = t), n !== void 0 && (this.autoRotateDirection = n), r !== void 0 && (this.autoRotateSpeed = r);
|
|
545
|
+
}
|
|
546
|
+
toggleAutoRotate() {
|
|
547
|
+
return this.isAutoRotating = !this.isAutoRotating, this.isAutoRotating;
|
|
548
|
+
}
|
|
549
|
+
setAutoRotateAxis(e) {
|
|
550
|
+
this.autoRotateAxis = e;
|
|
551
|
+
}
|
|
552
|
+
setAutoRotateDirection(e) {
|
|
553
|
+
this.autoRotateDirection = e;
|
|
554
|
+
}
|
|
555
|
+
setAutoRotateSpeed(e) {
|
|
556
|
+
this.autoRotateSpeed = Math.max(.1, Math.min(10, e));
|
|
557
|
+
}
|
|
558
|
+
getAutoRotateState() {
|
|
559
|
+
return {
|
|
560
|
+
enabled: this.isAutoRotating,
|
|
561
|
+
axis: this.autoRotateAxis,
|
|
562
|
+
direction: this.autoRotateDirection,
|
|
563
|
+
speed: this.autoRotateSpeed
|
|
564
|
+
};
|
|
565
|
+
}
|
|
566
|
+
setLockedAxis(e) {
|
|
567
|
+
this.lockedAxis = e;
|
|
568
|
+
let t = this.camera.position.clone().sub(this.controls.target), n = t.length();
|
|
569
|
+
n > 1e-4 && (this.lockedPitchAngle = Math.asin(Math.max(-1, Math.min(1, t.y / n))), this.lockedYawAngle = Math.atan2(t.z, t.x));
|
|
570
|
+
}
|
|
571
|
+
getLockedAxis() {
|
|
572
|
+
return this.lockedAxis;
|
|
573
|
+
}
|
|
574
|
+
updatePerFrame() {
|
|
575
|
+
let t = this.controls.target, n = this.camera.position.clone().sub(t), r = n.length();
|
|
576
|
+
if (this.isAutoRotating && r > .001) {
|
|
577
|
+
let r = this.autoRotateDirection === "clockwise" ? 1 : -1, i = .008 * this.autoRotateSpeed * r;
|
|
578
|
+
if (this.autoRotateAxis === "x") {
|
|
579
|
+
let t = new e.Vector3(1, 0, 0);
|
|
580
|
+
n.applyAxisAngle(t, i), this.camera.up.applyAxisAngle(t, i);
|
|
581
|
+
} else {
|
|
582
|
+
let t = new e.Vector3(0, 1, 0);
|
|
583
|
+
n.applyAxisAngle(t, i), this.camera.up.applyAxisAngle(t, i);
|
|
584
|
+
}
|
|
585
|
+
this.camera.position.copy(t).add(n), this.camera.lookAt(t);
|
|
586
|
+
}
|
|
587
|
+
if (this.lockedAxis && r > .001) {
|
|
588
|
+
let e = this.camera.position.clone().sub(t), n = e.length();
|
|
589
|
+
if (this.lockedAxis === "x") {
|
|
590
|
+
let r = n * Math.cos(this.lockedPitchAngle), i = n * Math.sin(this.lockedPitchAngle), a = Math.atan2(e.z, e.x);
|
|
591
|
+
e.x = r * Math.cos(a), e.y = i, e.z = r * Math.sin(a), this.camera.position.copy(t).add(e);
|
|
592
|
+
} else if (this.lockedAxis === "y") {
|
|
593
|
+
let r = e.y, i = Math.sqrt(Math.max(0, n * n - r * r));
|
|
594
|
+
e.x = i * Math.cos(this.lockedYawAngle), e.z = i * Math.sin(this.lockedYawAngle), this.camera.position.copy(t).add(e);
|
|
595
|
+
} else this.lockedAxis === "z" && this.camera.up.set(0, 1, 0);
|
|
596
|
+
this.camera.lookAt(t);
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
setView(t, n, r = 600) {
|
|
600
|
+
return new Promise((i) => {
|
|
601
|
+
let o = new e.Box3().setFromObject(n), s = new e.Sphere();
|
|
602
|
+
o.getBoundingSphere(s);
|
|
603
|
+
let c = s.center.clone(), l = Math.max(s.radius, 1);
|
|
604
|
+
this.camera.near = Math.max(.01, l / 500), this.camera.far = Math.max(1e4, l * 50), this.camera.updateProjectionMatrix();
|
|
605
|
+
let u = this.camera.fov * Math.PI / 180, d = l / Math.sin(u / 2) * 1.15, f = new e.Vector3(), p = new e.Vector3(0, 1, 0);
|
|
606
|
+
switch (t) {
|
|
607
|
+
case "front":
|
|
608
|
+
f.set(0, 0, 1);
|
|
609
|
+
break;
|
|
610
|
+
case "back":
|
|
611
|
+
f.set(0, 0, -1);
|
|
612
|
+
break;
|
|
613
|
+
case "left":
|
|
614
|
+
f.set(-1, 0, 0);
|
|
615
|
+
break;
|
|
616
|
+
case "right":
|
|
617
|
+
f.set(1, 0, 0);
|
|
618
|
+
break;
|
|
619
|
+
case "top":
|
|
620
|
+
f.set(0, 1, 1e-4), p.set(0, 0, -1);
|
|
621
|
+
break;
|
|
622
|
+
case "bottom":
|
|
623
|
+
f.set(0, -1, 1e-4), p.set(0, 0, 1);
|
|
624
|
+
break;
|
|
625
|
+
case "isometric":
|
|
626
|
+
f.set(1, 1, 1).normalize();
|
|
627
|
+
break;
|
|
628
|
+
case "isometric-back": f.set(-1, 1, -1).normalize();
|
|
629
|
+
}
|
|
630
|
+
let m = c.clone().add(f.multiplyScalar(d));
|
|
631
|
+
if (this.currentTween &&= (this.currentTween.stop(), null), this.camera.up.copy(p), r <= 0) {
|
|
632
|
+
this.camera.position.copy(m), this.controls.target.copy(c), this.controls.update(), i();
|
|
633
|
+
return;
|
|
634
|
+
}
|
|
635
|
+
let h = this.camera.position.clone(), g = this.controls.target.clone(), _ = { t: 0 };
|
|
636
|
+
this.currentTween = new a.Tween(_, this.tweenGroup).to({ t: 1 }, r).easing(a.Easing.Cubic.Out).onUpdate(() => {
|
|
637
|
+
this.camera.position.lerpVectors(h, m, _.t), this.controls.target.lerpVectors(g, c, _.t), this.controls.update();
|
|
638
|
+
}).onComplete(() => {
|
|
639
|
+
this.camera.position.copy(m), this.controls.target.copy(c), this.controls.update(), this.currentTween = null, i();
|
|
640
|
+
}).start();
|
|
641
|
+
});
|
|
642
|
+
}
|
|
643
|
+
fitToObject(t, n = 500) {
|
|
644
|
+
return new Promise((r) => {
|
|
645
|
+
let i = new e.Box3().setFromObject(t), o = new e.Sphere();
|
|
646
|
+
i.getBoundingSphere(o);
|
|
647
|
+
let s = o.center, c = Math.max(o.radius, 1);
|
|
648
|
+
this.camera.near = Math.max(.01, c / 500), this.camera.far = Math.max(1e4, c * 50), this.camera.updateProjectionMatrix();
|
|
649
|
+
let l = this.camera.fov * Math.PI / 180, u = c / Math.sin(l / 2) * 1.15, d = this.camera.position.clone().sub(this.controls.target).normalize(), f = s.clone().add(d.multiplyScalar(u)), p = this.camera.position.clone(), m = this.controls.target.clone(), h = { t: 0 };
|
|
650
|
+
new a.Tween(h, this.tweenGroup).to({ t: 1 }, n).easing(a.Easing.Cubic.Out).onUpdate(() => {
|
|
651
|
+
this.camera.position.lerpVectors(p, f, h.t), this.controls.target.lerpVectors(m, s, h.t), this.controls.update();
|
|
652
|
+
}).onComplete(() => {
|
|
653
|
+
this.camera.position.copy(f), this.controls.target.copy(s), this.controls.update(), r();
|
|
654
|
+
}).start();
|
|
655
|
+
});
|
|
656
|
+
}
|
|
657
|
+
};
|
|
658
|
+
//#endregion
|
|
659
|
+
//#region src/utils/snapping.ts
|
|
660
|
+
function C(t, n, r, i = 15, a = 800, o = 600) {
|
|
661
|
+
if (!r || r.length === 0) return {
|
|
662
|
+
hit: !1,
|
|
663
|
+
point: null,
|
|
664
|
+
normal: null,
|
|
665
|
+
isVertexSnapped: !1,
|
|
666
|
+
distanceToVertex: Infinity
|
|
667
|
+
};
|
|
668
|
+
let s = new e.Raycaster();
|
|
669
|
+
s.setFromCamera(t, n), s.firstHitOnly = !0;
|
|
670
|
+
let c = s.intersectObjects(r, !0);
|
|
671
|
+
if (c.length === 0) return {
|
|
672
|
+
hit: !1,
|
|
673
|
+
point: null,
|
|
674
|
+
normal: null,
|
|
675
|
+
isVertexSnapped: !1,
|
|
676
|
+
distanceToVertex: Infinity
|
|
677
|
+
};
|
|
678
|
+
let l = c[0], u = l.point.clone(), d = l.face ? l.face.normal.clone() : new e.Vector3(0, 1, 0);
|
|
679
|
+
l.object && d.transformDirection(l.object.matrixWorld);
|
|
680
|
+
let f = null, p = i;
|
|
681
|
+
if (l.face && l.object && l.object.geometry) {
|
|
682
|
+
let r = l.object, i = r.geometry.attributes.position;
|
|
683
|
+
if (i) {
|
|
684
|
+
let s = [
|
|
685
|
+
l.face.a,
|
|
686
|
+
l.face.b,
|
|
687
|
+
l.face.c
|
|
688
|
+
], c = new e.Vector3(), u = new e.Vector3();
|
|
689
|
+
for (let e of s) {
|
|
690
|
+
c.fromBufferAttribute(i, e).applyMatrix4(r.matrixWorld), u.copy(c).project(n);
|
|
691
|
+
let s = (u.x + 1) * .5 * a, l = (-u.y + 1) * .5 * o, d = (t.x + 1) * .5 * a, m = (-t.y + 1) * .5 * o, h = Math.hypot(s - d, l - m);
|
|
692
|
+
h < p && (p = h, f = c.clone());
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
}
|
|
696
|
+
return f ? {
|
|
697
|
+
hit: !0,
|
|
698
|
+
point: f,
|
|
699
|
+
normal: d,
|
|
700
|
+
isVertexSnapped: !0,
|
|
701
|
+
distanceToVertex: p
|
|
702
|
+
} : {
|
|
703
|
+
hit: !0,
|
|
704
|
+
point: u,
|
|
705
|
+
normal: d,
|
|
706
|
+
isVertexSnapped: !1,
|
|
707
|
+
distanceToVertex: Infinity
|
|
708
|
+
};
|
|
709
|
+
}
|
|
710
|
+
//#endregion
|
|
711
|
+
//#region src/tools/ClippingTool.ts
|
|
712
|
+
var w = class {
|
|
713
|
+
scene;
|
|
714
|
+
camera;
|
|
715
|
+
container;
|
|
716
|
+
modelLoader;
|
|
717
|
+
controls = null;
|
|
718
|
+
emitter = null;
|
|
719
|
+
planeX;
|
|
720
|
+
planeY;
|
|
721
|
+
planeZ;
|
|
722
|
+
customPlane = null;
|
|
723
|
+
isEnabled = !1;
|
|
724
|
+
activeAxis = "x";
|
|
725
|
+
helperVisible = !0;
|
|
726
|
+
planesGroup;
|
|
727
|
+
interactive = !1;
|
|
728
|
+
widgets = {};
|
|
729
|
+
isDraggingPlane = !1;
|
|
730
|
+
draggedWidget = null;
|
|
731
|
+
dragStartPointer = new e.Vector2();
|
|
732
|
+
dragStartPosition = 0;
|
|
733
|
+
dragScreenAxis = new e.Vector2();
|
|
734
|
+
dragScreenAxisLenSq = 0;
|
|
735
|
+
raycaster = new e.Raycaster();
|
|
736
|
+
hoveredAxis = null;
|
|
737
|
+
isPickingCustomPoints = !1;
|
|
738
|
+
customPoints = [];
|
|
739
|
+
customMarkersGroup;
|
|
740
|
+
modelBox = new e.Box3();
|
|
741
|
+
onPointerDownBound;
|
|
742
|
+
onPointerMoveBound;
|
|
743
|
+
onPointerMoveDragBound;
|
|
744
|
+
onPointerUpDragBound;
|
|
745
|
+
onDoubleClickBound;
|
|
746
|
+
constructor(t, n, r, i, a, o) {
|
|
747
|
+
this.scene = t, this.camera = n, this.container = r, this.modelLoader = i, this.controls = a || null, this.emitter = o || null, this.planeX = new e.Plane(new e.Vector3(-1, 0, 0), 1e5), this.planeY = new e.Plane(new e.Vector3(0, -1, 0), 1e5), this.planeZ = new e.Plane(new e.Vector3(0, 0, -1), 1e5), this.planesGroup = new e.Group(), this.planesGroup.name = "gmv-interactive-clipping-planes", this.planesGroup.visible = !1, this.scene.add(this.planesGroup), this.customMarkersGroup = new e.Group(), this.customMarkersGroup.name = "gmv-custom-clip-markers", this.scene.add(this.customMarkersGroup), this.onPointerDownBound = this.handlePointerDown.bind(this), this.onPointerMoveBound = this.handlePointerMove.bind(this), this.onPointerMoveDragBound = this.handlePointerMoveDrag.bind(this), this.onPointerUpDragBound = this.handlePointerUpDrag.bind(this), this.onDoubleClickBound = this.handleDoubleClick.bind(this), this.container.addEventListener("pointerdown", this.onPointerDownBound, { capture: !0 }), this.container.addEventListener("pointermove", this.onPointerMoveBound), this.container.addEventListener("dblclick", this.onDoubleClickBound, { capture: !0 });
|
|
748
|
+
}
|
|
749
|
+
setControls(e) {
|
|
750
|
+
this.controls = e;
|
|
751
|
+
}
|
|
752
|
+
setEmitter(e) {
|
|
753
|
+
this.emitter = e;
|
|
754
|
+
}
|
|
755
|
+
setInteractive(e) {
|
|
756
|
+
this.interactive = e && this.isEnabled, !this.interactive && this.container.style.cursor === "grab" && (this.container.style.cursor = "default");
|
|
757
|
+
}
|
|
758
|
+
setModelBounds(e) {
|
|
759
|
+
this.modelBox.copy(e), this.rebuildPlaneWidgets(), this.resetAll();
|
|
760
|
+
}
|
|
761
|
+
rebuildPlaneWidgets() {
|
|
762
|
+
this.clearPlaneWidgets();
|
|
763
|
+
let t = new e.Vector3(2, 2, 2), n = new e.Vector3(0, 0, 0);
|
|
764
|
+
this.modelBox.isEmpty() || (this.modelBox.getSize(t), this.modelBox.getCenter(n));
|
|
765
|
+
let r = Math.max(.001, t.x), i = Math.max(.001, t.y), a = Math.max(.001, t.z);
|
|
766
|
+
this.widgets.x = this.createPlaneWidget("x", 15680580, 16281969, a, i, n), this.widgets.y = this.createPlaneWidget("y", 1096065, 3462041, r, a, n), this.widgets.z = this.createPlaneWidget("z", 3900150, 6333946, r, i, n), this.widgets.x && (this.widgets.x.enabled = !0), this.widgets.y && (this.widgets.y.enabled = !1), this.widgets.z && (this.widgets.z.enabled = !1), this.updateWidgetsVisibility();
|
|
767
|
+
}
|
|
768
|
+
createPlaneWidget(t, n, i, a, o, s) {
|
|
769
|
+
let c = new e.Group();
|
|
770
|
+
c.name = `gmv-clip-plane-${t}`;
|
|
771
|
+
let l = new e.PlaneGeometry(a, o), u = new e.MeshBasicMaterial({
|
|
772
|
+
color: n,
|
|
773
|
+
transparent: !0,
|
|
774
|
+
opacity: .25,
|
|
775
|
+
side: e.DoubleSide,
|
|
776
|
+
depthWrite: !1
|
|
777
|
+
}), d = new e.Mesh(l, u);
|
|
778
|
+
d.userData = { axis: t }, d.renderOrder = 999, c.add(d);
|
|
779
|
+
let f = new e.EdgesGeometry(l), p = new e.LineBasicMaterial({
|
|
780
|
+
color: i,
|
|
781
|
+
transparent: !0,
|
|
782
|
+
opacity: .85
|
|
783
|
+
}), m = new e.LineSegments(f, p);
|
|
784
|
+
c.add(m);
|
|
785
|
+
let h = new e.Group(), g = Math.min(a, o) * .045, _ = new e.MeshBasicMaterial({
|
|
786
|
+
color: i,
|
|
787
|
+
transparent: !0,
|
|
788
|
+
opacity: .9,
|
|
789
|
+
depthTest: !1
|
|
790
|
+
}), v = new e.SphereGeometry(g * .5, 16, 16), y = new e.Mesh(v, _);
|
|
791
|
+
y.userData = { axis: t }, h.add(y);
|
|
792
|
+
let b = new e.CylinderGeometry(g * .12, g * .12, g * 1.8, 12);
|
|
793
|
+
b.rotateX(Math.PI / 2);
|
|
794
|
+
let x = new e.Mesh(b, _);
|
|
795
|
+
x.userData = { axis: t }, h.add(x);
|
|
796
|
+
let S = new e.ConeGeometry(g * .35, g * .65, 16);
|
|
797
|
+
S.rotateX(Math.PI / 2), S.translate(0, 0, g * 1.1);
|
|
798
|
+
let C = new e.Mesh(S, _);
|
|
799
|
+
C.userData = { axis: t }, h.add(C);
|
|
800
|
+
let w = new e.ConeGeometry(g * .35, g * .65, 16);
|
|
801
|
+
w.rotateX(-Math.PI / 2), w.translate(0, 0, -g * 1.1);
|
|
802
|
+
let T = new e.Mesh(w, _);
|
|
803
|
+
T.userData = { axis: t }, h.add(T), h.renderOrder = 1e3, c.add(h);
|
|
804
|
+
let E = [
|
|
805
|
+
d,
|
|
806
|
+
y,
|
|
807
|
+
x,
|
|
808
|
+
C,
|
|
809
|
+
T
|
|
810
|
+
], D = document.createElement("div");
|
|
811
|
+
D.className = `gmv-plane-badge gmv-plane-badge-${t}`, D.textContent = `${t.toUpperCase()} 剖切面`;
|
|
812
|
+
let O = new r(D);
|
|
813
|
+
O.position.set(a / 2 * .68, o / 2 * .68, 0), c.add(O);
|
|
814
|
+
let k = new e.Vector3(1, 0, 0);
|
|
815
|
+
return t === "x" ? (c.rotation.y = Math.PI / 2, c.position.set(s.x, s.y, s.z), k = new e.Vector3(1, 0, 0)) : t === "y" ? (c.rotation.x = -Math.PI / 2, c.position.set(s.x, s.y, s.z), k = new e.Vector3(0, 1, 0)) : (c.rotation.set(0, 0, 0), c.position.set(s.x, s.y, s.z), k = new e.Vector3(0, 0, 1)), this.planesGroup.add(c), {
|
|
816
|
+
axis: t,
|
|
817
|
+
group: c,
|
|
818
|
+
mesh: d,
|
|
819
|
+
border: m,
|
|
820
|
+
arrowGroup: h,
|
|
821
|
+
hitMeshes: E,
|
|
822
|
+
label: O,
|
|
823
|
+
labelText: D,
|
|
824
|
+
meshMat: u,
|
|
825
|
+
borderMat: p,
|
|
826
|
+
arrowMat: _,
|
|
827
|
+
normal: k,
|
|
828
|
+
baseColor: n,
|
|
829
|
+
borderColor: i,
|
|
830
|
+
position: s[t],
|
|
831
|
+
inverted: !1,
|
|
832
|
+
enabled: !1
|
|
833
|
+
};
|
|
834
|
+
}
|
|
835
|
+
clearPlaneWidgets() {
|
|
836
|
+
[
|
|
837
|
+
"x",
|
|
838
|
+
"y",
|
|
839
|
+
"z"
|
|
840
|
+
].forEach((e) => {
|
|
841
|
+
let t = this.widgets[e];
|
|
842
|
+
t && (t.mesh.geometry.dispose(), t.meshMat.dispose(), t.border.geometry.dispose(), t.borderMat.dispose(), t.arrowMat.dispose(), this.planesGroup.remove(t.group));
|
|
843
|
+
}), this.widgets = {};
|
|
844
|
+
}
|
|
845
|
+
updateWidgetsVisibility() {
|
|
846
|
+
this.planesGroup.visible = this.isEnabled && this.helperVisible, this.interactive = this.isEnabled, [
|
|
847
|
+
"x",
|
|
848
|
+
"y",
|
|
849
|
+
"z"
|
|
850
|
+
].forEach((e) => {
|
|
851
|
+
let t = this.widgets[e];
|
|
852
|
+
t && (t.group.visible = this.isEnabled && this.helperVisible && t.enabled);
|
|
853
|
+
});
|
|
854
|
+
}
|
|
855
|
+
setSectioningEnabled(e) {
|
|
856
|
+
if (this.isEnabled = e, this.updateWidgetsVisibility(), e) {
|
|
857
|
+
if (![
|
|
858
|
+
"x",
|
|
859
|
+
"y",
|
|
860
|
+
"z"
|
|
861
|
+
].some((e) => this.widgets[e]?.enabled)) {
|
|
862
|
+
let e = this.widgets[this.activeAxis] || this.widgets.x;
|
|
863
|
+
e && (e.enabled = !0);
|
|
864
|
+
}
|
|
865
|
+
[
|
|
866
|
+
"x",
|
|
867
|
+
"y",
|
|
868
|
+
"z"
|
|
869
|
+
].forEach((e) => {
|
|
870
|
+
let t = this.widgets[e];
|
|
871
|
+
t && t.enabled ? this.setPlanePositionExplicit(e, t.position) : this.disableAxisInternal(e);
|
|
872
|
+
});
|
|
873
|
+
} else this.disableAllAxesPlanes();
|
|
874
|
+
this.applyPlanes(), this.emitSectioningState();
|
|
875
|
+
}
|
|
876
|
+
getSectioningEnabled() {
|
|
877
|
+
return this.isEnabled;
|
|
878
|
+
}
|
|
879
|
+
setAxisEnabled(e, t) {
|
|
880
|
+
let n = this.widgets[e];
|
|
881
|
+
n && (n.enabled = t, t ? (this.activeAxis = e, this.isEnabled && this.setPlanePositionExplicit(e, n.position)) : this.disableAxisInternal(e), this.updateWidgetsVisibility(), this.applyPlanes(), this.emitSectioningState());
|
|
882
|
+
}
|
|
883
|
+
toggleAxis(e, t) {
|
|
884
|
+
let n = this.widgets[e], r = t === void 0 ? !n?.enabled : t;
|
|
885
|
+
return this.setAxisEnabled(e, r), r;
|
|
886
|
+
}
|
|
887
|
+
isAxisEnabled(e) {
|
|
888
|
+
return !!this.widgets[e]?.enabled;
|
|
889
|
+
}
|
|
890
|
+
setSectioningAxis(e) {
|
|
891
|
+
this.activeAxis = e;
|
|
892
|
+
let t = this.widgets[e];
|
|
893
|
+
t && !t.enabled && (t.enabled = !0, this.isEnabled && this.setPlanePositionExplicit(e, t.position)), this.updateWidgetsVisibility(), this.emitSectioningState();
|
|
894
|
+
}
|
|
895
|
+
getSectioningAxis() {
|
|
896
|
+
return this.activeAxis;
|
|
897
|
+
}
|
|
898
|
+
setSectioningHelperVisible(e) {
|
|
899
|
+
this.helperVisible = e, this.updateWidgetsVisibility(), this.emitSectioningState();
|
|
900
|
+
}
|
|
901
|
+
getSectioningHelperVisible() {
|
|
902
|
+
return this.helperVisible;
|
|
903
|
+
}
|
|
904
|
+
setAxisReverse(e, t) {
|
|
905
|
+
let n = this.widgets[e];
|
|
906
|
+
if (n) {
|
|
907
|
+
if (n.inverted = t, this.isEnabled && n.enabled) this.setPlanePositionExplicit(e, n.position);
|
|
908
|
+
else {
|
|
909
|
+
let r = this.modelBox.min[e], i = this.modelBox.max[e] - r, a = i > 0 ? (n.position - r) / i : .5;
|
|
910
|
+
n.labelText.textContent = `${e.toUpperCase()} 剖切面 ${(a * 100).toFixed(0)}%${t ? " (反向)" : ""}`;
|
|
911
|
+
}
|
|
912
|
+
}
|
|
913
|
+
this.emitSectioningState();
|
|
914
|
+
}
|
|
915
|
+
setSectioningReverse(e) {
|
|
916
|
+
this.setAxisReverse(this.activeAxis, e);
|
|
917
|
+
}
|
|
918
|
+
getSectioningReverse() {
|
|
919
|
+
return !!this.widgets[this.activeAxis]?.inverted;
|
|
920
|
+
}
|
|
921
|
+
invertAxis(e) {
|
|
922
|
+
let t = this.widgets[e];
|
|
923
|
+
return t ? (this.setAxisReverse(e, !t.inverted), t.inverted) : !1;
|
|
924
|
+
}
|
|
925
|
+
resetSectioning(t) {
|
|
926
|
+
let n = new e.Vector3(), r = this.modelBox.isEmpty();
|
|
927
|
+
r ? n.set(0, 0, 0) : this.modelBox.getCenter(n), this.clearCustomPlane(), (t ? [t] : [
|
|
928
|
+
"x",
|
|
929
|
+
"y",
|
|
930
|
+
"z"
|
|
931
|
+
]).forEach((e) => {
|
|
932
|
+
let i = this.widgets[e];
|
|
933
|
+
if (i) {
|
|
934
|
+
i.position = n[e], i.inverted = !1, i.group.position.set(n.x, n.y, n.z), t || (i.enabled = e === "x");
|
|
935
|
+
let a = r ? -1 : this.modelBox.min[e], o = (r ? 1 : this.modelBox.max[e]) - a, s = o > 0 && !isNaN(i.position) ? Math.max(0, Math.min(1, (i.position - a) / o)) : .5;
|
|
936
|
+
i.labelText.textContent = `${e.toUpperCase()} 剖切面 ${(s * 100).toFixed(0)}%`;
|
|
937
|
+
}
|
|
938
|
+
}), this.activeAxis = t || "x", this.helperVisible = !0, this.isEnabled = !0, [
|
|
939
|
+
"x",
|
|
940
|
+
"y",
|
|
941
|
+
"z"
|
|
942
|
+
].forEach((e) => {
|
|
943
|
+
let t = this.widgets[e];
|
|
944
|
+
t && t.enabled ? this.setPlanePositionExplicit(e, t.position) : this.disableAxisInternal(e);
|
|
945
|
+
}), this.updateWidgetsVisibility(), this.applyPlanes(), this.emitSectioningState();
|
|
946
|
+
}
|
|
947
|
+
getSectioningState() {
|
|
948
|
+
let e = this.modelBox.isEmpty(), t = e ? -1 : this.modelBox.min.x, n = e ? 1 : this.modelBox.max.x, r = e ? -1 : this.modelBox.min.y, i = e ? 1 : this.modelBox.max.y, a = e ? -1 : this.modelBox.min.z, o = e ? 1 : this.modelBox.max.z, s = (e, t, n) => {
|
|
949
|
+
let r = n - t;
|
|
950
|
+
return isNaN(e) || r <= 0 ? .5 : Math.max(0, Math.min(1, (e - t) / r));
|
|
951
|
+
}, c = this.widgets.x, l = this.widgets.y, u = this.widgets.z, d = {
|
|
952
|
+
x: {
|
|
953
|
+
enabled: c?.enabled ?? !1,
|
|
954
|
+
inverted: c?.inverted ?? !1,
|
|
955
|
+
position: c?.position ?? 0,
|
|
956
|
+
progress: s(c?.position ?? 0, t, n)
|
|
957
|
+
},
|
|
958
|
+
y: {
|
|
959
|
+
enabled: l?.enabled ?? !1,
|
|
960
|
+
inverted: l?.inverted ?? !1,
|
|
961
|
+
position: l?.position ?? 0,
|
|
962
|
+
progress: s(l?.position ?? 0, r, i)
|
|
963
|
+
},
|
|
964
|
+
z: {
|
|
965
|
+
enabled: u?.enabled ?? !1,
|
|
966
|
+
inverted: u?.inverted ?? !1,
|
|
967
|
+
position: u?.position ?? 0,
|
|
968
|
+
progress: s(u?.position ?? 0, a, o)
|
|
969
|
+
}
|
|
970
|
+
}, f = this.widgets[this.activeAxis], p = d[this.activeAxis]?.progress ?? .5, m = f?.position ?? 0, h = f?.inverted ?? !1;
|
|
971
|
+
return {
|
|
972
|
+
enabled: this.isEnabled,
|
|
973
|
+
axes: d,
|
|
974
|
+
helperVisible: this.helperVisible,
|
|
975
|
+
axis: this.activeAxis,
|
|
976
|
+
isReverse: h,
|
|
977
|
+
progress: p,
|
|
978
|
+
position: m
|
|
979
|
+
};
|
|
980
|
+
}
|
|
981
|
+
emitSectioningState() {
|
|
982
|
+
this.emitter && this.emitter.emit("sectioning:change", this.getSectioningState());
|
|
983
|
+
}
|
|
984
|
+
handlePointerDown(t) {
|
|
985
|
+
if (t.button !== 0) return;
|
|
986
|
+
if (this.isPickingCustomPoints) {
|
|
987
|
+
this.handleCustomPointPick(t), t.stopImmediatePropagation(), t.preventDefault();
|
|
988
|
+
return;
|
|
989
|
+
}
|
|
990
|
+
if (!this.interactive || !this.isEnabled || !this.helperVisible) return;
|
|
991
|
+
let n = this.container.getBoundingClientRect(), r = new e.Vector2((t.clientX - n.left) / n.width * 2 - 1, -((t.clientY - n.top) / n.height) * 2 + 1);
|
|
992
|
+
this.raycaster.setFromCamera(r, this.camera);
|
|
993
|
+
let i = [
|
|
994
|
+
"x",
|
|
995
|
+
"y",
|
|
996
|
+
"z"
|
|
997
|
+
].map((e) => this.widgets[e]).filter((e) => !!(e && e.enabled && e.group.visible));
|
|
998
|
+
if (i.length === 0) return;
|
|
999
|
+
let a = null;
|
|
1000
|
+
for (let e of i) {
|
|
1001
|
+
let t = this.raycaster.intersectObjects(e.hitMeshes, !0);
|
|
1002
|
+
if (t.length > 0) {
|
|
1003
|
+
let n = t[0].distance;
|
|
1004
|
+
(!a || n < a.distance) && (a = {
|
|
1005
|
+
widget: e,
|
|
1006
|
+
distance: n
|
|
1007
|
+
});
|
|
1008
|
+
}
|
|
1009
|
+
}
|
|
1010
|
+
if (a) {
|
|
1011
|
+
t.stopImmediatePropagation(), t.preventDefault();
|
|
1012
|
+
let r = a.widget;
|
|
1013
|
+
this.activeAxis = r.axis, this.isDraggingPlane = !0, this.draggedWidget = r, this.controls && (this.controls.enabled = !1, "state" in this.controls && (this.controls.state = -1, this.controls._moveCurr && this.controls._movePrev && this.controls._moveCurr.copy(this.controls._movePrev))), this.container.style.cursor = "grabbing", r.meshMat.opacity = .65, r.arrowMat.opacity = 1, this.dragStartPointer.set(t.clientX, t.clientY), this.dragStartPosition = r.position;
|
|
1014
|
+
let i = new e.Vector3();
|
|
1015
|
+
r.axis === "x" ? i.set(1, 0, 0) : r.axis === "y" ? i.set(0, 1, 0) : i.set(0, 0, 1);
|
|
1016
|
+
let o = r.group.position.clone(), s = r.group.position.clone().add(i), c = o.project(this.camera), l = new e.Vector2((c.x + 1) * n.width / 2, (-c.y + 1) * n.height / 2), u = s.project(this.camera), d = new e.Vector2((u.x + 1) * n.width / 2, (-u.y + 1) * n.height / 2);
|
|
1017
|
+
this.dragScreenAxis.subVectors(d, l), this.dragScreenAxisLenSq = this.dragScreenAxis.lengthSq(), window.addEventListener("pointermove", this.onPointerMoveDragBound, { capture: !0 }), window.addEventListener("pointerup", this.onPointerUpDragBound, { capture: !0 });
|
|
1018
|
+
}
|
|
1019
|
+
}
|
|
1020
|
+
handlePointerMoveDrag(t) {
|
|
1021
|
+
if (!this.isDraggingPlane || !this.draggedWidget) return;
|
|
1022
|
+
t.stopImmediatePropagation(), t.preventDefault();
|
|
1023
|
+
let n = new e.Vector2(t.clientX - this.dragStartPointer.x, t.clientY - this.dragStartPointer.y), r = 0;
|
|
1024
|
+
if (this.dragScreenAxisLenSq > 25) r = this.dragScreenAxis.dot(n) / this.dragScreenAxisLenSq;
|
|
1025
|
+
else {
|
|
1026
|
+
let t = new e.Vector3();
|
|
1027
|
+
this.modelBox.getSize(t);
|
|
1028
|
+
let i = Math.max(.1, t[this.draggedWidget.axis]);
|
|
1029
|
+
r = -n.y / 280 * i;
|
|
1030
|
+
}
|
|
1031
|
+
let i = this.modelBox.min[this.draggedWidget.axis], a = this.modelBox.max[this.draggedWidget.axis], o = this.dragStartPosition + r;
|
|
1032
|
+
o = Math.max(i, Math.min(a, o)), this.setPlanePositionExplicit(this.draggedWidget.axis, o);
|
|
1033
|
+
}
|
|
1034
|
+
handlePointerUpDrag(e) {
|
|
1035
|
+
this.isDraggingPlane && (e.stopImmediatePropagation(), e.preventDefault(), this.isDraggingPlane = !1, this.draggedWidget &&= (this.draggedWidget.meshMat.opacity = .25, this.draggedWidget.arrowMat.opacity = .9, null), this.container.style.cursor = "default", window.removeEventListener("pointermove", this.onPointerMoveDragBound, { capture: !0 }), window.removeEventListener("pointerup", this.onPointerUpDragBound, { capture: !0 }), requestAnimationFrame(() => {
|
|
1036
|
+
this.controls && ("state" in this.controls && (this.controls.state = -1, this.controls._moveCurr && this.controls._movePrev && this.controls._moveCurr.copy(this.controls._movePrev)), this.controls.enabled = !0);
|
|
1037
|
+
}));
|
|
1038
|
+
}
|
|
1039
|
+
handlePointerMove(t) {
|
|
1040
|
+
if (this.isDraggingPlane || this.isPickingCustomPoints || !this.interactive || !this.isEnabled || !this.helperVisible) return;
|
|
1041
|
+
let n = this.container.getBoundingClientRect(), r = new e.Vector2((t.clientX - n.left) / n.width * 2 - 1, -((t.clientY - n.top) / n.height) * 2 + 1);
|
|
1042
|
+
this.raycaster.setFromCamera(r, this.camera);
|
|
1043
|
+
let i = [
|
|
1044
|
+
"x",
|
|
1045
|
+
"y",
|
|
1046
|
+
"z"
|
|
1047
|
+
].map((e) => this.widgets[e]).filter((e) => !!(e && e.enabled && e.group.visible)), a = null;
|
|
1048
|
+
for (let e of i) if (this.raycaster.intersectObjects(e.hitMeshes, !0).length > 0) {
|
|
1049
|
+
a = e.axis;
|
|
1050
|
+
break;
|
|
1051
|
+
}
|
|
1052
|
+
this.setHoveredAxis(a), a ? this.container.style.cursor = "grab" : this.container.style.cursor === "grab" && (this.container.style.cursor = "default");
|
|
1053
|
+
}
|
|
1054
|
+
setHoveredAxis(e) {
|
|
1055
|
+
this.hoveredAxis !== e && (this.hoveredAxis = e, [
|
|
1056
|
+
"x",
|
|
1057
|
+
"y",
|
|
1058
|
+
"z"
|
|
1059
|
+
].forEach((t) => {
|
|
1060
|
+
let n = this.widgets[t];
|
|
1061
|
+
n && (t === e ? (n.meshMat.opacity = .52, n.borderMat.opacity = 1, n.arrowMat.opacity = 1) : (n.meshMat.opacity = .25, n.borderMat.opacity = .85, n.arrowMat.opacity = .9));
|
|
1062
|
+
}));
|
|
1063
|
+
}
|
|
1064
|
+
handleDoubleClick(t) {
|
|
1065
|
+
if (!this.interactive || !this.isEnabled || !this.helperVisible) return;
|
|
1066
|
+
let n = this.container.getBoundingClientRect(), r = new e.Vector2((t.clientX - n.left) / n.width * 2 - 1, -((t.clientY - n.top) / n.height) * 2 + 1);
|
|
1067
|
+
this.raycaster.setFromCamera(r, this.camera);
|
|
1068
|
+
let i = [
|
|
1069
|
+
"x",
|
|
1070
|
+
"y",
|
|
1071
|
+
"z"
|
|
1072
|
+
].map((e) => this.widgets[e]).filter((e) => !!(e && e.enabled && e.group.visible));
|
|
1073
|
+
for (let e of i) if (this.raycaster.intersectObjects(e.hitMeshes, !0).length > 0) {
|
|
1074
|
+
t.stopImmediatePropagation(), t.preventDefault(), this.invertAxis(e.axis);
|
|
1075
|
+
break;
|
|
1076
|
+
}
|
|
1077
|
+
}
|
|
1078
|
+
setPlanePositionExplicit(t, n) {
|
|
1079
|
+
let r = this.widgets[t];
|
|
1080
|
+
if (!r) return;
|
|
1081
|
+
r.position = n, t === "x" ? (r.group.position.x = n, r.inverted ? this.planeX.set(new e.Vector3(1, 0, 0), -n) : this.planeX.set(new e.Vector3(-1, 0, 0), n)) : t === "y" ? (r.group.position.y = n, r.inverted ? this.planeY.set(new e.Vector3(0, 1, 0), -n) : this.planeY.set(new e.Vector3(0, -1, 0), n)) : t === "z" && (r.group.position.z = n, r.inverted ? this.planeZ.set(new e.Vector3(0, 0, 1), -n) : this.planeZ.set(new e.Vector3(0, 0, -1), n)), r.enabled = !0, this.applyPlanes();
|
|
1082
|
+
let i = this.modelBox.min[t], a = this.modelBox.max[t] - i, o = a > 0 ? (n - i) / a : .5;
|
|
1083
|
+
r.labelText.textContent = `${t.toUpperCase()} 剖切面 ${(o * 100).toFixed(0)}%${r.inverted ? " (反向)" : ""}`, this.emitSectioningState(), this.emitter && this.emitter.emit("clipping:change", {
|
|
1084
|
+
axis: t,
|
|
1085
|
+
position: n,
|
|
1086
|
+
progress: o,
|
|
1087
|
+
inverted: r.inverted,
|
|
1088
|
+
enabled: !0
|
|
1089
|
+
});
|
|
1090
|
+
}
|
|
1091
|
+
setAxisProgress(e, t) {
|
|
1092
|
+
let n = this.modelBox.min[e], r = this.modelBox.max[e], i = n + Math.max(0, Math.min(1, t)) * (r - n);
|
|
1093
|
+
this.setPlanePositionExplicit(e, i);
|
|
1094
|
+
}
|
|
1095
|
+
getAxisProgress(e) {
|
|
1096
|
+
let t = this.widgets[e];
|
|
1097
|
+
if (!t) return .5;
|
|
1098
|
+
let n = this.modelBox.min[e], r = this.modelBox.max[e] - n;
|
|
1099
|
+
return r > 0 ? Math.max(0, Math.min(1, (t.position - n) / r)) : .5;
|
|
1100
|
+
}
|
|
1101
|
+
disableAxisInternal(t) {
|
|
1102
|
+
t === "x" ? this.planeX.set(new e.Vector3(-1, 0, 0), 1e5) : t === "y" ? this.planeY.set(new e.Vector3(0, -1, 0), 1e5) : t === "z" && this.planeZ.set(new e.Vector3(0, 0, -1), 1e5);
|
|
1103
|
+
}
|
|
1104
|
+
disableAllAxesPlanes() {
|
|
1105
|
+
[
|
|
1106
|
+
"x",
|
|
1107
|
+
"y",
|
|
1108
|
+
"z"
|
|
1109
|
+
].forEach((e) => {
|
|
1110
|
+
this.disableAxisInternal(e);
|
|
1111
|
+
});
|
|
1112
|
+
}
|
|
1113
|
+
setAxisClipping(e, t, n = !1) {
|
|
1114
|
+
this.activeAxis = e;
|
|
1115
|
+
let r = this.widgets[e];
|
|
1116
|
+
r && (r.inverted = n, r.enabled = !0), this.setSectioningEnabled(!0), this.setAxisProgress(e, t);
|
|
1117
|
+
}
|
|
1118
|
+
disableAxis(e) {
|
|
1119
|
+
this.setAxisEnabled(e, !1);
|
|
1120
|
+
}
|
|
1121
|
+
getAxisState(e) {
|
|
1122
|
+
let t = this.widgets[e];
|
|
1123
|
+
if (!t) return {
|
|
1124
|
+
enabled: !1,
|
|
1125
|
+
progress: .5,
|
|
1126
|
+
inverted: !1,
|
|
1127
|
+
position: 0
|
|
1128
|
+
};
|
|
1129
|
+
let n = this.modelBox.min[e], r = this.modelBox.max[e] - n, i = r > 0 ? (t.position - n) / r : .5;
|
|
1130
|
+
return {
|
|
1131
|
+
enabled: this.isEnabled && t.enabled,
|
|
1132
|
+
progress: i,
|
|
1133
|
+
inverted: t.inverted,
|
|
1134
|
+
position: t.position
|
|
1135
|
+
};
|
|
1136
|
+
}
|
|
1137
|
+
setPlanesVisible(e) {
|
|
1138
|
+
this.setSectioningHelperVisible(e);
|
|
1139
|
+
}
|
|
1140
|
+
getPlanesVisible() {
|
|
1141
|
+
return this.helperVisible;
|
|
1142
|
+
}
|
|
1143
|
+
startCustomClip() {
|
|
1144
|
+
this.cancelCustomClip(), this.isPickingCustomPoints = !0, this.customPoints = [], this.container.style.cursor = "crosshair";
|
|
1145
|
+
}
|
|
1146
|
+
cancelCustomClip() {
|
|
1147
|
+
this.isPickingCustomPoints = !1, this.container.style.cursor = "default", this.clearCustomMarkers();
|
|
1148
|
+
}
|
|
1149
|
+
clearCustomPlane() {
|
|
1150
|
+
this.customPlane = null, this.clearCustomMarkers(), this.applyPlanes();
|
|
1151
|
+
}
|
|
1152
|
+
invertCustomClip() {
|
|
1153
|
+
return this.customPlane ? (this.customPlane.negate(), this.applyPlanes(), !0) : !1;
|
|
1154
|
+
}
|
|
1155
|
+
hasCustomPlane() {
|
|
1156
|
+
return this.customPlane !== null;
|
|
1157
|
+
}
|
|
1158
|
+
handleCustomPointPick(t) {
|
|
1159
|
+
let n = this.container.getBoundingClientRect(), r = C(new e.Vector2((t.clientX - n.left) / n.width * 2 - 1, -((t.clientY - n.top) / n.height) * 2 + 1), this.camera, this.modelLoader.getMeshes(), 15, n.width, n.height);
|
|
1160
|
+
r.hit && r.point && this.addCustomPoint(r.point);
|
|
1161
|
+
}
|
|
1162
|
+
addCustomPoint(t) {
|
|
1163
|
+
this.customPoints.push(t.clone());
|
|
1164
|
+
let n = new e.SphereGeometry(1, 16, 16), r = new e.MeshBasicMaterial({
|
|
1165
|
+
color: 3718648,
|
|
1166
|
+
depthTest: !1
|
|
1167
|
+
}), i = new e.Mesh(n, r);
|
|
1168
|
+
if (i.position.copy(t), i.userData = { fixedScreenRadius: 5.5 }, this.customMarkersGroup.add(i), this.updateSingleMarkerScale(i), this.customPoints.length === 2) {
|
|
1169
|
+
let t = this.customPoints[0], n = this.customPoints[1], r = new e.Vector3().subVectors(n, t);
|
|
1170
|
+
if (r.lengthSq() < 1e-5) {
|
|
1171
|
+
this.customPoints.pop(), this.customMarkersGroup.remove(i);
|
|
1172
|
+
return;
|
|
1173
|
+
}
|
|
1174
|
+
r.normalize();
|
|
1175
|
+
let a = new e.Vector3();
|
|
1176
|
+
this.camera.getWorldDirection(a);
|
|
1177
|
+
let o = new e.Vector3().crossVectors(r, a).normalize();
|
|
1178
|
+
o.lengthSq() < 1e-4 && (o = new e.Vector3().crossVectors(r, this.camera.up).normalize()), this.customPlane = new e.Plane().setFromNormalAndCoplanarPoint(o, t), this.clearCustomMarkers(), this.cancelCustomClip(), this.applyPlanes();
|
|
1179
|
+
}
|
|
1180
|
+
}
|
|
1181
|
+
updatePerFrame(t) {
|
|
1182
|
+
if (this.customMarkersGroup.children.length === 0) return;
|
|
1183
|
+
let n = t || this.container.clientHeight || window.innerHeight || 800, r = this.camera.fov * Math.PI / 180, i = this.camera.position, a = Math.tan(r / 2);
|
|
1184
|
+
this.customMarkersGroup.traverse((t) => {
|
|
1185
|
+
if (t.userData && typeof t.userData.fixedScreenRadius == "number") {
|
|
1186
|
+
let r = t.userData.fixedScreenRadius, o = new e.Vector3();
|
|
1187
|
+
t.getWorldPosition(o);
|
|
1188
|
+
let s = 2 * o.distanceTo(i) * a * r / Math.max(n, 1);
|
|
1189
|
+
t.scale.setScalar(s);
|
|
1190
|
+
}
|
|
1191
|
+
});
|
|
1192
|
+
}
|
|
1193
|
+
updateSingleMarkerScale(t, n) {
|
|
1194
|
+
if (t.userData && typeof t.userData.fixedScreenRadius == "number") {
|
|
1195
|
+
let r = t.userData.fixedScreenRadius, i = n || this.container.clientHeight || window.innerHeight || 800, a = this.camera.fov * Math.PI / 180, o = this.camera.position, s = Math.tan(a / 2), c = new e.Vector3();
|
|
1196
|
+
t.getWorldPosition(c);
|
|
1197
|
+
let l = 2 * c.distanceTo(o) * s * r / Math.max(i, 1);
|
|
1198
|
+
t.scale.setScalar(l);
|
|
1199
|
+
}
|
|
1200
|
+
}
|
|
1201
|
+
clearCustomMarkers() {
|
|
1202
|
+
for (; this.customMarkersGroup.children.length > 0;) {
|
|
1203
|
+
let e = this.customMarkersGroup.children[0];
|
|
1204
|
+
e.geometry && e.geometry.dispose(), e.material && e.material.dispose(), this.customMarkersGroup.remove(e);
|
|
1205
|
+
}
|
|
1206
|
+
}
|
|
1207
|
+
applyPlanes() {
|
|
1208
|
+
let e = [];
|
|
1209
|
+
this.isEnabled && (this.widgets.x?.enabled && e.push(this.planeX), this.widgets.y?.enabled && e.push(this.planeY), this.widgets.z?.enabled && e.push(this.planeZ)), this.customPlane && e.push(this.customPlane), this.modelLoader.applyClippingPlanes(e);
|
|
1210
|
+
}
|
|
1211
|
+
resetAll() {
|
|
1212
|
+
this.isEnabled = !1, this.activeAxis = "x", this.helperVisible = !0, this.disableAllAxesPlanes();
|
|
1213
|
+
let t = new e.Vector3();
|
|
1214
|
+
this.modelBox.getCenter(t), [
|
|
1215
|
+
"x",
|
|
1216
|
+
"y",
|
|
1217
|
+
"z"
|
|
1218
|
+
].forEach((e) => {
|
|
1219
|
+
let n = this.widgets[e];
|
|
1220
|
+
n && (n.enabled = e === "x", n.inverted = !1, n.position = t[e], n.group.position.set(t.x, t.y, t.z), n.labelText.textContent = `${e.toUpperCase()} 剖切面`);
|
|
1221
|
+
}), this.updateWidgetsVisibility(), this.clearCustomPlane(), this.applyPlanes(), this.emitSectioningState();
|
|
1222
|
+
}
|
|
1223
|
+
destroy() {
|
|
1224
|
+
this.cancelCustomClip(), this.resetAll(), this.clearPlaneWidgets(), this.scene.remove(this.planesGroup), this.scene.remove(this.customMarkersGroup), this.container.removeEventListener("pointerdown", this.onPointerDownBound, { capture: !0 }), this.container.removeEventListener("pointermove", this.onPointerMoveBound), this.container.removeEventListener("dblclick", this.onDoubleClickBound, { capture: !0 }), window.removeEventListener("pointermove", this.onPointerMoveDragBound, { capture: !0 }), window.removeEventListener("pointerup", this.onPointerUpDragBound, { capture: !0 });
|
|
1225
|
+
}
|
|
1226
|
+
}, T = class {
|
|
1227
|
+
scene;
|
|
1228
|
+
camera;
|
|
1229
|
+
container;
|
|
1230
|
+
modelLoader;
|
|
1231
|
+
emitter;
|
|
1232
|
+
controls = null;
|
|
1233
|
+
currentMode = "none";
|
|
1234
|
+
unit = "m";
|
|
1235
|
+
measurementGroup;
|
|
1236
|
+
results = [];
|
|
1237
|
+
activePoints = [];
|
|
1238
|
+
activePreviewGroup;
|
|
1239
|
+
activeMarkersGroup;
|
|
1240
|
+
activeLineGroup;
|
|
1241
|
+
snapCursorMesh;
|
|
1242
|
+
onPointerDownBound;
|
|
1243
|
+
onPointerMoveBound;
|
|
1244
|
+
onDoubleClickBound;
|
|
1245
|
+
constructor(t, n, r, i, a, o) {
|
|
1246
|
+
this.scene = t, this.camera = n, this.container = r, this.modelLoader = i, this.emitter = a, this.controls = o || null, this.measurementGroup = new e.Group(), this.measurementGroup.name = "gmv-measurements-group", this.scene.add(this.measurementGroup), this.activePreviewGroup = new e.Group(), this.activePreviewGroup.name = "gmv-measure-preview-group", this.scene.add(this.activePreviewGroup), this.activeMarkersGroup = new e.Group(), this.activeMarkersGroup.name = "gmv-active-markers-group", this.activePreviewGroup.add(this.activeMarkersGroup), this.activeLineGroup = new e.Group(), this.activeLineGroup.name = "gmv-active-line-group", this.activePreviewGroup.add(this.activeLineGroup);
|
|
1247
|
+
let s = new e.SphereGeometry(1, 16, 16), c = new e.MeshBasicMaterial({
|
|
1248
|
+
color: 3718648,
|
|
1249
|
+
transparent: !0,
|
|
1250
|
+
opacity: .9,
|
|
1251
|
+
depthTest: !1
|
|
1252
|
+
});
|
|
1253
|
+
this.snapCursorMesh = new e.Mesh(s, c), this.snapCursorMesh.userData = { fixedScreenRadius: 5.5 }, this.snapCursorMesh.visible = !1, this.scene.add(this.snapCursorMesh), this.onPointerDownBound = this.handlePointerDown.bind(this), this.onPointerMoveBound = this.handlePointerMove.bind(this), this.onDoubleClickBound = this.handleDoubleClick.bind(this);
|
|
1254
|
+
}
|
|
1255
|
+
setControls(e) {
|
|
1256
|
+
this.controls = e;
|
|
1257
|
+
}
|
|
1258
|
+
setUnit(e) {
|
|
1259
|
+
this.unit = e;
|
|
1260
|
+
}
|
|
1261
|
+
setMode(e) {
|
|
1262
|
+
this.currentMode !== e && (this.cancelActive(), this.currentMode = e, e === "none" ? (this.container.style.cursor = "default", this.snapCursorMesh.visible = !1, this.removeListeners()) : (this.container.style.cursor = "crosshair", this.addListeners(), this.emitter.emit("measure:start", e)));
|
|
1263
|
+
}
|
|
1264
|
+
getMode() {
|
|
1265
|
+
return this.currentMode;
|
|
1266
|
+
}
|
|
1267
|
+
getControls() {
|
|
1268
|
+
return this.controls;
|
|
1269
|
+
}
|
|
1270
|
+
addListeners() {
|
|
1271
|
+
this.removeListeners(), this.container.addEventListener("pointerdown", this.onPointerDownBound, { capture: !0 }), this.container.addEventListener("pointermove", this.onPointerMoveBound), this.container.addEventListener("dblclick", this.onDoubleClickBound);
|
|
1272
|
+
}
|
|
1273
|
+
removeListeners() {
|
|
1274
|
+
this.container.removeEventListener("pointerdown", this.onPointerDownBound, { capture: !0 }), this.container.removeEventListener("pointermove", this.onPointerMoveBound), this.container.removeEventListener("dblclick", this.onDoubleClickBound);
|
|
1275
|
+
}
|
|
1276
|
+
handlePointerMove(t) {
|
|
1277
|
+
if (this.currentMode === "none") return;
|
|
1278
|
+
let n = this.container.getBoundingClientRect(), r = C(new e.Vector2((t.clientX - n.left) / n.width * 2 - 1, -((t.clientY - n.top) / n.height) * 2 + 1), this.camera, this.modelLoader.getMeshes(), 15, n.width, n.height);
|
|
1279
|
+
!r.hit || !r.point ? (this.container.style.cursor = "not-allowed", this.snapCursorMesh.visible = !1) : (this.container.style.cursor = "crosshair", this.snapCursorMesh.visible = !0, this.snapCursorMesh.position.copy(r.point), r.isVertexSnapped ? (this.snapCursorMesh.material.color.setHex(16007006), this.snapCursorMesh.userData.fixedScreenRadius = 7.5) : (this.snapCursorMesh.material.color.setHex(3718648), this.snapCursorMesh.userData.fixedScreenRadius = 5.5), this.updateSingleMeshScale(this.snapCursorMesh), this.activePoints.length > 0 && this.updateDynamicPreview(r.point));
|
|
1280
|
+
}
|
|
1281
|
+
handlePointerDown(t) {
|
|
1282
|
+
if (this.currentMode === "none" || t.button !== 0) return;
|
|
1283
|
+
let n = this.container.getBoundingClientRect(), r = C(new e.Vector2((t.clientX - n.left) / n.width * 2 - 1, -((t.clientY - n.top) / n.height) * 2 + 1), this.camera, this.modelLoader.getMeshes(), 15, n.width, n.height);
|
|
1284
|
+
if (!r.hit || !r.point) return;
|
|
1285
|
+
let i = r.point.clone();
|
|
1286
|
+
this.activePoints.push(i), this.addActiveMarker(i), this.emitter.emit("measure:change", [...this.activePoints]), this.currentMode === "distance" && this.activePoints.length === 2 ? this.finishDistanceMeasurement() : this.currentMode === "height" && this.activePoints.length === 2 ? this.finishHeightMeasurement() : this.currentMode === "angle" && this.activePoints.length === 3 && this.finishAngleMeasurement();
|
|
1287
|
+
}
|
|
1288
|
+
addActiveMarker(t) {
|
|
1289
|
+
let n = new e.SphereGeometry(1, 16, 16), r = new e.MeshBasicMaterial({
|
|
1290
|
+
color: 3718648,
|
|
1291
|
+
depthTest: !1
|
|
1292
|
+
}), i = new e.Mesh(n, r);
|
|
1293
|
+
i.position.copy(t), i.userData = { fixedScreenRadius: 5.5 }, this.activeMarkersGroup.add(i), this.updateSingleMeshScale(i);
|
|
1294
|
+
}
|
|
1295
|
+
handleDoubleClick(e) {
|
|
1296
|
+
this.currentMode === "area" && this.activePoints.length >= 3 && this.finishAreaMeasurement();
|
|
1297
|
+
}
|
|
1298
|
+
updateDynamicPreview(t) {
|
|
1299
|
+
this.clearActiveLine();
|
|
1300
|
+
let n = [...this.activePoints, t];
|
|
1301
|
+
if (n.length < 2) return;
|
|
1302
|
+
let r = new e.BufferGeometry().setFromPoints(n), i = new e.LineDashedMaterial({
|
|
1303
|
+
color: 3718648,
|
|
1304
|
+
dashSize: .2,
|
|
1305
|
+
gapSize: .1,
|
|
1306
|
+
depthTest: !1
|
|
1307
|
+
}), a = new e.Line(r, i);
|
|
1308
|
+
a.computeLineDistances(), this.activeLineGroup.add(a);
|
|
1309
|
+
}
|
|
1310
|
+
finishDistanceMeasurement() {
|
|
1311
|
+
let t = this.activePoints[0], n = this.activePoints[1], i = t.distanceTo(n), a = new e.Vector3().addVectors(t, n).multiplyScalar(.5), o = new e.Group(), s = new e.BufferGeometry().setFromPoints([t, n]), c = new e.LineBasicMaterial({
|
|
1312
|
+
color: 3900150,
|
|
1313
|
+
linewidth: 2,
|
|
1314
|
+
depthTest: !1
|
|
1315
|
+
}), l = new e.Line(s, c);
|
|
1316
|
+
o.add(l), this.addEndSphere(o, t, 3900150), this.addEndSphere(o, n, 3900150);
|
|
1317
|
+
let u = document.createElement("div");
|
|
1318
|
+
u.className = "gmv-measure-badge distance", u.innerHTML = `<span>距离:</span> <strong>${b(i, this.unit)}</strong>`;
|
|
1319
|
+
let d = new r(u);
|
|
1320
|
+
d.position.copy(a), o.add(d), this.measurementGroup.add(o);
|
|
1321
|
+
let f = {
|
|
1322
|
+
id: `dist_${Date.now()}`,
|
|
1323
|
+
type: "distance",
|
|
1324
|
+
value: i,
|
|
1325
|
+
formattedValue: b(i, this.unit),
|
|
1326
|
+
unit: this.unit,
|
|
1327
|
+
points: [t, n]
|
|
1328
|
+
};
|
|
1329
|
+
this.results.push(f), this.emitter.emit("measure:complete", f), this.cancelActive(), this.setMode("none");
|
|
1330
|
+
}
|
|
1331
|
+
finishHeightMeasurement() {
|
|
1332
|
+
let t = this.activePoints[0], n = this.activePoints[1], i = Math.abs(n.y - t.y), a = new e.Vector2(t.x, t.z).distanceTo(new e.Vector2(n.x, n.z)), o = t.distanceTo(n), s = new e.Group(), c = new e.BufferGeometry().setFromPoints([t, n]), l = new e.LineDashedMaterial({
|
|
1333
|
+
color: 9741240,
|
|
1334
|
+
dashSize: .15,
|
|
1335
|
+
gapSize: .08,
|
|
1336
|
+
depthTest: !1
|
|
1337
|
+
}), u = new e.Line(c, l);
|
|
1338
|
+
u.computeLineDistances(), s.add(u);
|
|
1339
|
+
let d = new e.Vector3(n.x, t.y, n.z), f = new e.BufferGeometry().setFromPoints([t, d]), p = new e.LineBasicMaterial({
|
|
1340
|
+
color: 1096065,
|
|
1341
|
+
depthTest: !1
|
|
1342
|
+
}), m = new e.Line(f, p);
|
|
1343
|
+
s.add(m);
|
|
1344
|
+
let h = new e.BufferGeometry().setFromPoints([d, n]), g = new e.LineBasicMaterial({
|
|
1345
|
+
color: 15680580,
|
|
1346
|
+
linewidth: 2,
|
|
1347
|
+
depthTest: !1
|
|
1348
|
+
}), _ = new e.Line(h, g);
|
|
1349
|
+
s.add(_), this.addEndSphere(s, t, 1096065), this.addEndSphere(s, n, 15680580), this.addEndSphere(s, d, 16436245, 4);
|
|
1350
|
+
let v = new e.Vector3().addVectors(d, n).multiplyScalar(.5), y = document.createElement("div");
|
|
1351
|
+
y.className = "gmv-measure-badge height", y.innerHTML = `
|
|
1352
|
+
<div><span>高差 (ΔH):</span> <strong>${b(i, this.unit)}</strong></div>
|
|
1353
|
+
<div style="font-size:10px;opacity:0.85;">水平: ${b(a, this.unit)} · 直线: ${b(o, this.unit)}</div>
|
|
1354
|
+
`;
|
|
1355
|
+
let x = new r(y);
|
|
1356
|
+
x.position.copy(v), s.add(x), this.measurementGroup.add(s);
|
|
1357
|
+
let S = {
|
|
1358
|
+
id: `height_${Date.now()}`,
|
|
1359
|
+
type: "height",
|
|
1360
|
+
value: i,
|
|
1361
|
+
formattedValue: b(i, this.unit),
|
|
1362
|
+
unit: this.unit,
|
|
1363
|
+
points: [t, n],
|
|
1364
|
+
extra: {
|
|
1365
|
+
verticalHeight: i,
|
|
1366
|
+
horizontalDistance: a
|
|
1367
|
+
}
|
|
1368
|
+
};
|
|
1369
|
+
this.results.push(S), this.emitter.emit("measure:complete", S), this.cancelActive(), this.setMode("none");
|
|
1370
|
+
}
|
|
1371
|
+
finishAreaMeasurement() {
|
|
1372
|
+
if (this.activePoints.length < 3) return;
|
|
1373
|
+
let t = [...this.activePoints], n = y(t), i = new e.Group(), a = [...t, t[0]], o = new e.BufferGeometry().setFromPoints(a), s = new e.LineBasicMaterial({
|
|
1374
|
+
color: 9133302,
|
|
1375
|
+
linewidth: 2,
|
|
1376
|
+
depthTest: !1
|
|
1377
|
+
}), c = new e.Line(o, s);
|
|
1378
|
+
i.add(c), t.forEach((e) => this.addEndSphere(i, e, 9133302));
|
|
1379
|
+
let l = new e.Vector3();
|
|
1380
|
+
t.forEach((e) => l.add(e)), l.divideScalar(t.length);
|
|
1381
|
+
let u = document.createElement("div");
|
|
1382
|
+
u.className = "gmv-measure-badge area", u.innerHTML = `<span>面积:</span> <strong>${b(n, `${this.unit}²`)}</strong>`;
|
|
1383
|
+
let d = new r(u);
|
|
1384
|
+
d.position.copy(l), i.add(d), this.measurementGroup.add(i);
|
|
1385
|
+
let f = {
|
|
1386
|
+
id: `area_${Date.now()}`,
|
|
1387
|
+
type: "area",
|
|
1388
|
+
value: n,
|
|
1389
|
+
formattedValue: b(n, `${this.unit}²`),
|
|
1390
|
+
unit: `${this.unit}²`,
|
|
1391
|
+
points: t,
|
|
1392
|
+
extra: { area: n }
|
|
1393
|
+
};
|
|
1394
|
+
this.results.push(f), this.emitter.emit("measure:complete", f), this.cancelActive(), this.setMode("none");
|
|
1395
|
+
}
|
|
1396
|
+
finishAngleMeasurement() {
|
|
1397
|
+
if (this.activePoints.length !== 3) return;
|
|
1398
|
+
let t = this.activePoints[0], n = this.activePoints[1], i = this.activePoints[2], a = new e.Vector3().subVectors(t, n).normalize(), o = new e.Vector3().subVectors(i, n).normalize(), s = a.dot(o);
|
|
1399
|
+
s = Math.max(-1, Math.min(1, s));
|
|
1400
|
+
let c = Math.acos(s), l = e.MathUtils.radToDeg(c), u = new e.Group(), d = new e.BufferGeometry().setFromPoints([n, t]), f = new e.BufferGeometry().setFromPoints([n, i]), p = new e.LineBasicMaterial({
|
|
1401
|
+
color: 16096779,
|
|
1402
|
+
linewidth: 2,
|
|
1403
|
+
depthTest: !1
|
|
1404
|
+
});
|
|
1405
|
+
u.add(new e.Line(d, p)), u.add(new e.Line(f, p)), this.addEndSphere(u, t, 16096779), this.addEndSphere(u, i, 16096779), this.addEndSphere(u, n, 15680580, 6.5);
|
|
1406
|
+
let m = Math.min(t.distanceTo(n), i.distanceTo(n)) * .35 || .4, h = [];
|
|
1407
|
+
for (let t = 0; t <= 16; t++) {
|
|
1408
|
+
let r = t / 16, i = new e.Vector3().copy(a).lerp(o, r).normalize().multiplyScalar(m);
|
|
1409
|
+
h.push(new e.Vector3().addVectors(n, i));
|
|
1410
|
+
}
|
|
1411
|
+
let g = new e.BufferGeometry().setFromPoints(h), _ = new e.LineBasicMaterial({
|
|
1412
|
+
color: 16498468,
|
|
1413
|
+
depthTest: !1
|
|
1414
|
+
});
|
|
1415
|
+
u.add(new e.Line(g, _));
|
|
1416
|
+
let v = new e.Vector3().addVectors(a, o).normalize(), y = n.clone().add(v.multiplyScalar(m * 1.3)), b = document.createElement("div");
|
|
1417
|
+
b.className = "gmv-measure-badge angle", b.innerHTML = `<span>角度:</span> <strong>${l.toFixed(1)}°</strong>`;
|
|
1418
|
+
let x = new r(b);
|
|
1419
|
+
x.position.copy(y), u.add(x), this.measurementGroup.add(u);
|
|
1420
|
+
let S = {
|
|
1421
|
+
id: `angle_${Date.now()}`,
|
|
1422
|
+
type: "angle",
|
|
1423
|
+
value: l,
|
|
1424
|
+
formattedValue: `${l.toFixed(1)}°`,
|
|
1425
|
+
unit: "°",
|
|
1426
|
+
points: [
|
|
1427
|
+
t,
|
|
1428
|
+
n,
|
|
1429
|
+
i
|
|
1430
|
+
],
|
|
1431
|
+
extra: { angleDegree: l }
|
|
1432
|
+
};
|
|
1433
|
+
this.results.push(S), this.emitter.emit("measure:complete", S), this.cancelActive(), this.setMode("none");
|
|
1434
|
+
}
|
|
1435
|
+
addEndSphere(t, n, r, i = 5.5) {
|
|
1436
|
+
let a = new e.SphereGeometry(1, 16, 16), o = new e.MeshBasicMaterial({
|
|
1437
|
+
color: r,
|
|
1438
|
+
depthTest: !1
|
|
1439
|
+
}), s = new e.Mesh(a, o);
|
|
1440
|
+
s.position.copy(n), s.userData = { fixedScreenRadius: i }, t.add(s), this.updateSingleMeshScale(s);
|
|
1441
|
+
}
|
|
1442
|
+
undoLastPoint() {
|
|
1443
|
+
if (this.activePoints.length > 0) {
|
|
1444
|
+
if (this.activePoints.pop(), this.activeMarkersGroup.children.length > 0) {
|
|
1445
|
+
let e = this.activeMarkersGroup.children[this.activeMarkersGroup.children.length - 1];
|
|
1446
|
+
this.disposeObjectHierarchy(e), this.activeMarkersGroup.remove(e);
|
|
1447
|
+
}
|
|
1448
|
+
this.clearActiveLine(), this.emitter.emit("measure:change", [...this.activePoints]);
|
|
1449
|
+
}
|
|
1450
|
+
}
|
|
1451
|
+
cancelActive() {
|
|
1452
|
+
this.activePoints = [], this.clearActiveLine(), this.clearActiveMarkers();
|
|
1453
|
+
}
|
|
1454
|
+
clearActiveLine() {
|
|
1455
|
+
for (; this.activeLineGroup.children.length > 0;) {
|
|
1456
|
+
let e = this.activeLineGroup.children[0];
|
|
1457
|
+
this.disposeObjectHierarchy(e), this.activeLineGroup.remove(e);
|
|
1458
|
+
}
|
|
1459
|
+
}
|
|
1460
|
+
clearActiveMarkers() {
|
|
1461
|
+
for (; this.activeMarkersGroup.children.length > 0;) {
|
|
1462
|
+
let e = this.activeMarkersGroup.children[0];
|
|
1463
|
+
this.disposeObjectHierarchy(e), this.activeMarkersGroup.remove(e);
|
|
1464
|
+
}
|
|
1465
|
+
}
|
|
1466
|
+
updatePerFrame(t) {
|
|
1467
|
+
let n = t || this.container.clientHeight || window.innerHeight || 800, r = this.camera.fov * Math.PI / 180, i = this.camera.position, a = Math.tan(r / 2), o = (t) => {
|
|
1468
|
+
if (t.userData && typeof t.userData.fixedScreenRadius == "number") {
|
|
1469
|
+
let r = t.userData.fixedScreenRadius, o = new e.Vector3();
|
|
1470
|
+
t.getWorldPosition(o);
|
|
1471
|
+
let s = 2 * o.distanceTo(i) * a * r / Math.max(n, 1);
|
|
1472
|
+
t.scale.setScalar(s);
|
|
1473
|
+
}
|
|
1474
|
+
};
|
|
1475
|
+
this.snapCursorMesh && this.snapCursorMesh.visible && o(this.snapCursorMesh), this.activeMarkersGroup.traverse(o), this.measurementGroup.traverse(o);
|
|
1476
|
+
}
|
|
1477
|
+
updateSingleMeshScale(t, n) {
|
|
1478
|
+
if (t.userData && typeof t.userData.fixedScreenRadius == "number") {
|
|
1479
|
+
let r = t.userData.fixedScreenRadius, i = n || this.container.clientHeight || window.innerHeight || 800, a = this.camera.fov * Math.PI / 180, o = this.camera.position, s = Math.tan(a / 2), c = new e.Vector3();
|
|
1480
|
+
t.getWorldPosition(c);
|
|
1481
|
+
let l = 2 * c.distanceTo(o) * s * r / Math.max(i, 1);
|
|
1482
|
+
t.scale.setScalar(l);
|
|
1483
|
+
}
|
|
1484
|
+
}
|
|
1485
|
+
clearAll() {
|
|
1486
|
+
for (this.cancelActive(); this.measurementGroup.children.length > 0;) {
|
|
1487
|
+
let e = this.measurementGroup.children[0];
|
|
1488
|
+
this.disposeObjectHierarchy(e), this.measurementGroup.remove(e);
|
|
1489
|
+
}
|
|
1490
|
+
this.snapCursorMesh.visible = !1, this.results = [], this.emitter.emit("measure:clear");
|
|
1491
|
+
}
|
|
1492
|
+
disposeObjectHierarchy(e) {
|
|
1493
|
+
e.traverse((e) => {
|
|
1494
|
+
if (e.isCSS2DObject && e.element) {
|
|
1495
|
+
let t = e.element;
|
|
1496
|
+
t && t.parentElement ? t.parentElement.removeChild(t) : t && t.remove();
|
|
1497
|
+
}
|
|
1498
|
+
if (e.isMesh || e.isLine) {
|
|
1499
|
+
let t = e;
|
|
1500
|
+
t.geometry && t.geometry.dispose(), t.material && (Array.isArray(t.material) ? t.material.forEach((e) => e.dispose()) : t.material.dispose());
|
|
1501
|
+
}
|
|
1502
|
+
});
|
|
1503
|
+
}
|
|
1504
|
+
getResults() {
|
|
1505
|
+
return [...this.results];
|
|
1506
|
+
}
|
|
1507
|
+
destroy() {
|
|
1508
|
+
this.removeListeners(), this.clearAll(), this.scene.remove(this.measurementGroup), this.scene.remove(this.activePreviewGroup), this.scene.remove(this.snapCursorMesh);
|
|
1509
|
+
}
|
|
1510
|
+
}, E = class {
|
|
1511
|
+
renderer;
|
|
1512
|
+
scene;
|
|
1513
|
+
camera;
|
|
1514
|
+
getModel;
|
|
1515
|
+
constructor(e, t, n, r) {
|
|
1516
|
+
this.renderer = e, this.scene = t, this.camera = n, this.getModel = r || (() => null);
|
|
1517
|
+
}
|
|
1518
|
+
getSceneMaxTextureSize() {
|
|
1519
|
+
let e = 0, t = 0;
|
|
1520
|
+
return this.scene.traverse((n) => {
|
|
1521
|
+
if (n.isMesh) {
|
|
1522
|
+
let r = n, i = (n) => {
|
|
1523
|
+
if ("map" in n) {
|
|
1524
|
+
let r = n;
|
|
1525
|
+
if (r.map) {
|
|
1526
|
+
let n = r.map.image || r.map.source?.data;
|
|
1527
|
+
if (n) {
|
|
1528
|
+
let r = n.width || 0, i = n.height || 0;
|
|
1529
|
+
r > 0 && i > 0 && r * i > e * t && (e = r, t = i);
|
|
1530
|
+
}
|
|
1531
|
+
}
|
|
1532
|
+
}
|
|
1533
|
+
};
|
|
1534
|
+
Array.isArray(r.material) ? r.material.forEach(i) : r.material && i(r.material);
|
|
1535
|
+
}
|
|
1536
|
+
}), e > 0 && t > 0 ? {
|
|
1537
|
+
width: e,
|
|
1538
|
+
height: t
|
|
1539
|
+
} : null;
|
|
1540
|
+
}
|
|
1541
|
+
async exportImage(t = {}) {
|
|
1542
|
+
let n = t.originalQuality === !0 || t.scale === "original", r = n ? 1 : typeof t.scale == "number" ? t.scale : 2, i = t.type ?? "image/png", a = t.quality ?? (i === "image/png" ? 1 : .95), o = t.download ?? !1, s = new e.Vector2();
|
|
1543
|
+
this.renderer.getSize(s);
|
|
1544
|
+
let c = this.renderer.getPixelRatio(), l = this.scene.background, u = s.x / s.y, d, f;
|
|
1545
|
+
if (t.targetSize) d = t.targetSize.width, f = t.targetSize.height;
|
|
1546
|
+
else if (n) {
|
|
1547
|
+
let e = this.getSceneMaxTextureSize();
|
|
1548
|
+
if (e && e.width > 0 && e.height > 0) {
|
|
1549
|
+
let t = Math.max(e.width, e.height);
|
|
1550
|
+
u >= 1 ? (d = t, f = Math.round(t / u)) : (f = t, d = Math.round(t * u));
|
|
1551
|
+
} else {
|
|
1552
|
+
let e = Math.max(Math.round(s.x * c), 2048);
|
|
1553
|
+
u >= 1 ? (d = e, f = Math.round(e / u)) : (f = e, d = Math.round(e * u));
|
|
1554
|
+
}
|
|
1555
|
+
} else d = Math.round(s.x * r), f = Math.round(s.y * r);
|
|
1556
|
+
let p = t.filename ?? `model-${n ? `texture-original-${d}x${f}` : `${r}x`}-${Date.now()}.${i === "image/jpeg" ? "jpg" : "png"}`, m = t.modelOnly ?? !0, h = [];
|
|
1557
|
+
t.background !== void 0 && (t.background === null ? (this.scene.background = null, this.renderer.setClearAlpha(0)) : (this.scene.background = new e.Color(t.background), this.renderer.setClearAlpha(1)));
|
|
1558
|
+
try {
|
|
1559
|
+
if (m) {
|
|
1560
|
+
let e = this.getModel(), t = (t) => !!(t.isLight || t.name === "gmv-lights-group" || t.children && t.children.some((e) => e.isLight) || e && (t === e || t.uuid === e.uuid) || t.name === "gmv-current-model");
|
|
1561
|
+
for (let e of this.scene.children) !t(e) && e.visible && (h.push({
|
|
1562
|
+
obj: e,
|
|
1563
|
+
wasVisible: !0
|
|
1564
|
+
}), e.visible = !1);
|
|
1565
|
+
}
|
|
1566
|
+
this.renderer.setPixelRatio(1), this.renderer.setSize(d, f, !1), this.camera.aspect = d / f, this.camera.updateProjectionMatrix();
|
|
1567
|
+
let t = this.camera.fov * Math.PI / 180, n = this.camera.position, r = Math.tan(t / 2);
|
|
1568
|
+
this.scene.traverse((t) => {
|
|
1569
|
+
if (t.userData && typeof t.userData.fixedScreenRadius == "number") {
|
|
1570
|
+
let i = t.userData.fixedScreenRadius, a = new e.Vector3();
|
|
1571
|
+
t.getWorldPosition(a);
|
|
1572
|
+
let o = 2 * a.distanceTo(n) * r * i / Math.max(f, 1);
|
|
1573
|
+
t.scale.setScalar(o);
|
|
1574
|
+
}
|
|
1575
|
+
}), this.renderer.render(this.scene, this.camera);
|
|
1576
|
+
let s = this.renderer.domElement.toDataURL(i, a);
|
|
1577
|
+
if (o) {
|
|
1578
|
+
let e = document.createElement("a");
|
|
1579
|
+
e.download = p, e.href = s, document.body.appendChild(e), e.click(), document.body.removeChild(e);
|
|
1580
|
+
}
|
|
1581
|
+
return s;
|
|
1582
|
+
} finally {
|
|
1583
|
+
if (h.length > 0) for (let { obj: e, wasVisible: t } of h) e.visible = t;
|
|
1584
|
+
this.scene.background = l, this.renderer.setPixelRatio(c), this.renderer.setSize(s.x, s.y, !0), this.camera.aspect = s.x / s.y, this.camera.updateProjectionMatrix();
|
|
1585
|
+
let t = s.y, n = this.camera.fov * Math.PI / 180, r = this.camera.position, i = Math.tan(n / 2);
|
|
1586
|
+
this.scene.traverse((n) => {
|
|
1587
|
+
if (n.userData && typeof n.userData.fixedScreenRadius == "number") {
|
|
1588
|
+
let a = n.userData.fixedScreenRadius, o = new e.Vector3();
|
|
1589
|
+
n.getWorldPosition(o);
|
|
1590
|
+
let s = 2 * o.distanceTo(r) * i * a / Math.max(t, 1);
|
|
1591
|
+
n.scale.setScalar(s);
|
|
1592
|
+
}
|
|
1593
|
+
}), this.renderer.render(this.scene, this.camera);
|
|
1594
|
+
}
|
|
1595
|
+
}
|
|
1596
|
+
}, D = class extends p {
|
|
1597
|
+
sceneManager;
|
|
1598
|
+
modelLoader;
|
|
1599
|
+
boundingBoxTool;
|
|
1600
|
+
cameraTool;
|
|
1601
|
+
clippingTool;
|
|
1602
|
+
measurementTool;
|
|
1603
|
+
screenshotTool;
|
|
1604
|
+
currentModel = null;
|
|
1605
|
+
currentModelInfo = null;
|
|
1606
|
+
unit = "m";
|
|
1607
|
+
defaultShowBoundingBox = !1;
|
|
1608
|
+
constructor(e) {
|
|
1609
|
+
super(), this.unit = e.unit || "m", this.defaultShowBoundingBox = e.showBoundingBox ?? !1, this.sceneManager = new f(e), this.modelLoader = new h(), this.boundingBoxTool = new x(this.sceneManager.scene), this.cameraTool = new S(this.sceneManager.camera, this.sceneManager.controls, this.sceneManager.tweenGroup), this.clippingTool = new w(this.sceneManager.scene, this.sceneManager.camera, this.sceneManager.container, this.modelLoader, this.sceneManager.controls, this), this.measurementTool = new T(this.sceneManager.scene, this.sceneManager.camera, this.sceneManager.container, this.modelLoader, this, this.sceneManager.controls), this.measurementTool.setUnit(this.unit), this.screenshotTool = new E(this.sceneManager.renderer, this.sceneManager.scene, this.sceneManager.camera, () => this.currentModel), this.measurementTool.setUnit(this.unit), this.sceneManager.onBeforeRender = () => {
|
|
1610
|
+
this.boundingBoxTool.update(this.sceneManager.camera), this.cameraTool.updatePerFrame(), this.measurementTool.updatePerFrame(), this.clippingTool.updatePerFrame();
|
|
1611
|
+
};
|
|
1612
|
+
}
|
|
1613
|
+
async loadZip(e) {
|
|
1614
|
+
try {
|
|
1615
|
+
this.emit("load:start", typeof e == "string" ? e : "ZIP File"), this.clearModel();
|
|
1616
|
+
let t = await this.modelLoader.loadZip(e, (e, t) => {
|
|
1617
|
+
this.emit("load:progress", e, t);
|
|
1618
|
+
});
|
|
1619
|
+
return this.setupLoadedModel(t), this.emit("load:success", t), t;
|
|
1620
|
+
} catch (e) {
|
|
1621
|
+
let t = e instanceof Error ? e : Error(String(e));
|
|
1622
|
+
throw this.emit("load:error", t), t;
|
|
1623
|
+
}
|
|
1624
|
+
}
|
|
1625
|
+
async loadOBJ(e, t) {
|
|
1626
|
+
try {
|
|
1627
|
+
this.emit("load:start", e), this.clearModel();
|
|
1628
|
+
let n = await this.modelLoader.loadOBJ(e, t, (e, t) => {
|
|
1629
|
+
this.emit("load:progress", e, t);
|
|
1630
|
+
});
|
|
1631
|
+
return this.setupLoadedModel(n), this.emit("load:success", n), n;
|
|
1632
|
+
} catch (e) {
|
|
1633
|
+
let t = e instanceof Error ? e : Error(String(e));
|
|
1634
|
+
throw this.emit("load:error", t), t;
|
|
1635
|
+
}
|
|
1636
|
+
}
|
|
1637
|
+
loadSampleGeometry(t = "mechanical") {
|
|
1638
|
+
this.clearModel();
|
|
1639
|
+
let n = new e.Group();
|
|
1640
|
+
if (t === "mechanical") {
|
|
1641
|
+
let t = new e.BoxGeometry(6, 1.2, 4), r = new e.MeshStandardMaterial({
|
|
1642
|
+
color: 4674921,
|
|
1643
|
+
metalness: .8,
|
|
1644
|
+
roughness: .3
|
|
1645
|
+
}), i = new e.Mesh(t, r);
|
|
1646
|
+
i.position.y = .6, n.add(i);
|
|
1647
|
+
let a = new e.CylinderGeometry(1.2, 1.2, 3, 32), o = new e.MeshStandardMaterial({
|
|
1648
|
+
color: 165063,
|
|
1649
|
+
metalness: .6,
|
|
1650
|
+
roughness: .2
|
|
1651
|
+
}), s = new e.Mesh(a, o);
|
|
1652
|
+
s.position.set(0, 2.7, 0), n.add(s);
|
|
1653
|
+
let c = new e.TorusGeometry(1.6, .25, 16, 40), l = new e.MeshStandardMaterial({
|
|
1654
|
+
color: 14753096,
|
|
1655
|
+
metalness: .7,
|
|
1656
|
+
roughness: .2
|
|
1657
|
+
}), u = new e.Mesh(c, l);
|
|
1658
|
+
u.rotation.x = Math.PI / 2, u.position.set(0, 3.2, 0), n.add(u);
|
|
1659
|
+
} else if (t === "building") {
|
|
1660
|
+
let t = new e.BoxGeometry(4, 10, 4), r = new e.MeshStandardMaterial({
|
|
1661
|
+
color: 3359061,
|
|
1662
|
+
roughness: .4
|
|
1663
|
+
}), i = new e.Mesh(t, r);
|
|
1664
|
+
i.position.y = 5, n.add(i);
|
|
1665
|
+
let a = new e.ConeGeometry(3, 2.5, 4), o = new e.MeshStandardMaterial({
|
|
1666
|
+
color: 12131356,
|
|
1667
|
+
roughness: .5
|
|
1668
|
+
}), s = new e.Mesh(a, o);
|
|
1669
|
+
s.position.y = 11.25, s.rotation.y = Math.PI / 4, n.add(s);
|
|
1670
|
+
} else {
|
|
1671
|
+
let t = new e.TorusKnotGeometry(2.5, .7, 100, 16), r = new e.MeshStandardMaterial({
|
|
1672
|
+
color: 9133302,
|
|
1673
|
+
metalness: .5,
|
|
1674
|
+
roughness: .2
|
|
1675
|
+
}), i = new e.Mesh(t, r);
|
|
1676
|
+
i.position.y = 3, n.add(i);
|
|
1677
|
+
}
|
|
1678
|
+
let r = this.modelLoader.postProcessModel(n);
|
|
1679
|
+
return this.setupLoadedModel(r), this.emit("load:success", r), r;
|
|
1680
|
+
}
|
|
1681
|
+
setupLoadedModel(e) {
|
|
1682
|
+
this.currentModel = e.model, this.currentModel.name = "gmv-current-model", this.currentModelInfo = e, this.sceneManager.scene.add(this.currentModel), this.boundingBoxTool.attachToModel(this.currentModel, {
|
|
1683
|
+
visible: this.defaultShowBoundingBox,
|
|
1684
|
+
unit: this.unit
|
|
1685
|
+
}), this.clippingTool.setModelBounds(e.box), this.cameraTool.setView("front", this.currentModel, 0);
|
|
1686
|
+
}
|
|
1687
|
+
clearModel() {
|
|
1688
|
+
this.measurementTool.clearAll(), this.clippingTool.resetAll(), this.boundingBoxTool.detach(), this.currentModel &&= (this.sceneManager.scene.remove(this.currentModel), null), this.currentModelInfo = null, this.modelLoader.cleanup();
|
|
1689
|
+
}
|
|
1690
|
+
setBackground(e, t) {
|
|
1691
|
+
this.sceneManager.setBackground(e, t);
|
|
1692
|
+
}
|
|
1693
|
+
setModelDisplayStyle(e) {
|
|
1694
|
+
this.modelLoader.setDisplayStyle(e), this.emit("style:change", e);
|
|
1695
|
+
}
|
|
1696
|
+
getModelDisplayStyle() {
|
|
1697
|
+
return this.modelLoader.getDisplayStyle();
|
|
1698
|
+
}
|
|
1699
|
+
toggleTexture(e) {
|
|
1700
|
+
this.modelLoader.toggleTexture(e), this.emit("texture:toggle", e);
|
|
1701
|
+
}
|
|
1702
|
+
getTextureState() {
|
|
1703
|
+
return this.modelLoader.getTextureState();
|
|
1704
|
+
}
|
|
1705
|
+
setPlainColor(e) {
|
|
1706
|
+
this.modelLoader.setPlainColor(e);
|
|
1707
|
+
}
|
|
1708
|
+
getPlainColor() {
|
|
1709
|
+
return this.modelLoader.getPlainColor();
|
|
1710
|
+
}
|
|
1711
|
+
getModelTextureSize() {
|
|
1712
|
+
return this.modelLoader.getModelTextureSize();
|
|
1713
|
+
}
|
|
1714
|
+
setGridVisible(e) {
|
|
1715
|
+
this.sceneManager.gridHelper.visible = e;
|
|
1716
|
+
}
|
|
1717
|
+
showBoundingBox(e, t) {
|
|
1718
|
+
this.boundingBoxTool.setVisible(e), t?.unit && (this.unit = t.unit, this.boundingBoxTool.setUnit(t.unit), this.measurementTool.setUnit(t.unit));
|
|
1719
|
+
}
|
|
1720
|
+
getBoundingBoxVisible() {
|
|
1721
|
+
return this.boundingBoxTool.getVisible();
|
|
1722
|
+
}
|
|
1723
|
+
setClipping(e, t, n = !1) {
|
|
1724
|
+
this.clippingTool.setAxisClipping(e, t, n);
|
|
1725
|
+
}
|
|
1726
|
+
disableClippingAxis(e) {
|
|
1727
|
+
this.clippingTool.disableAxis(e);
|
|
1728
|
+
}
|
|
1729
|
+
toggleClippingAxis(e, t) {
|
|
1730
|
+
return this.clippingTool.toggleAxis(e, t);
|
|
1731
|
+
}
|
|
1732
|
+
invertClippingAxis(e) {
|
|
1733
|
+
return this.clippingTool.invertAxis(e);
|
|
1734
|
+
}
|
|
1735
|
+
getClippingAxisState(e) {
|
|
1736
|
+
return this.clippingTool.getAxisState(e);
|
|
1737
|
+
}
|
|
1738
|
+
setClippingPlanesVisible(e) {
|
|
1739
|
+
this.clippingTool.setPlanesVisible(e);
|
|
1740
|
+
}
|
|
1741
|
+
getClippingPlanesVisible() {
|
|
1742
|
+
return this.clippingTool.getPlanesVisible();
|
|
1743
|
+
}
|
|
1744
|
+
setSectioningEnabled(e) {
|
|
1745
|
+
this.clippingTool.setSectioningEnabled(e);
|
|
1746
|
+
}
|
|
1747
|
+
getSectioningEnabled() {
|
|
1748
|
+
return this.clippingTool.getSectioningEnabled();
|
|
1749
|
+
}
|
|
1750
|
+
setSectioningAxis(e) {
|
|
1751
|
+
this.clippingTool.setSectioningAxis(e);
|
|
1752
|
+
}
|
|
1753
|
+
getSectioningAxis() {
|
|
1754
|
+
return this.clippingTool.getSectioningAxis();
|
|
1755
|
+
}
|
|
1756
|
+
setSectioningAxisEnabled(e, t) {
|
|
1757
|
+
this.clippingTool.setAxisEnabled(e, t);
|
|
1758
|
+
}
|
|
1759
|
+
toggleSectioningAxis(e, t) {
|
|
1760
|
+
return this.clippingTool.toggleAxis(e, t);
|
|
1761
|
+
}
|
|
1762
|
+
isSectioningAxisEnabled(e) {
|
|
1763
|
+
return this.clippingTool.isAxisEnabled(e);
|
|
1764
|
+
}
|
|
1765
|
+
setSectioningAxisReverse(e, t) {
|
|
1766
|
+
this.clippingTool.setAxisReverse(e, t);
|
|
1767
|
+
}
|
|
1768
|
+
invertSectioningAxis(e) {
|
|
1769
|
+
return this.clippingTool.invertAxis(e);
|
|
1770
|
+
}
|
|
1771
|
+
setSectioningAxisProgress(e, t) {
|
|
1772
|
+
this.clippingTool.setAxisProgress(e, t);
|
|
1773
|
+
}
|
|
1774
|
+
getSectioningAxisProgress(e) {
|
|
1775
|
+
return this.clippingTool.getAxisProgress(e);
|
|
1776
|
+
}
|
|
1777
|
+
setSectioningHelperVisible(e) {
|
|
1778
|
+
this.clippingTool.setSectioningHelperVisible(e);
|
|
1779
|
+
}
|
|
1780
|
+
getSectioningHelperVisible() {
|
|
1781
|
+
return this.clippingTool.getSectioningHelperVisible();
|
|
1782
|
+
}
|
|
1783
|
+
setSectioningReverse(e) {
|
|
1784
|
+
this.clippingTool.setSectioningReverse(e);
|
|
1785
|
+
}
|
|
1786
|
+
getSectioningReverse() {
|
|
1787
|
+
return this.clippingTool.getSectioningReverse();
|
|
1788
|
+
}
|
|
1789
|
+
resetSectioning(e) {
|
|
1790
|
+
this.clippingTool.resetSectioning(e);
|
|
1791
|
+
}
|
|
1792
|
+
getSectioningState() {
|
|
1793
|
+
return this.clippingTool.getSectioningState();
|
|
1794
|
+
}
|
|
1795
|
+
startCustomClip() {
|
|
1796
|
+
this.measurementTool.setMode("none"), this.clippingTool.startCustomClip();
|
|
1797
|
+
}
|
|
1798
|
+
cancelCustomClip() {
|
|
1799
|
+
this.clippingTool.cancelCustomClip();
|
|
1800
|
+
}
|
|
1801
|
+
clearCustomClip() {
|
|
1802
|
+
this.clippingTool.clearCustomPlane();
|
|
1803
|
+
}
|
|
1804
|
+
invertCustomClip() {
|
|
1805
|
+
return this.clippingTool.invertCustomClip();
|
|
1806
|
+
}
|
|
1807
|
+
hasCustomClip() {
|
|
1808
|
+
return this.clippingTool.hasCustomPlane();
|
|
1809
|
+
}
|
|
1810
|
+
resetClipping() {
|
|
1811
|
+
this.clippingTool.resetAll();
|
|
1812
|
+
}
|
|
1813
|
+
setMeasurementMode(e) {
|
|
1814
|
+
e === "none" ? this.clippingTool.setInteractive(!0) : (this.clippingTool.cancelCustomClip(), this.clippingTool.setInteractive(!1)), this.measurementTool.setMode(e);
|
|
1815
|
+
}
|
|
1816
|
+
getMeasurementMode() {
|
|
1817
|
+
return this.measurementTool.getMode();
|
|
1818
|
+
}
|
|
1819
|
+
clearMeasurements() {
|
|
1820
|
+
this.measurementTool.clearAll();
|
|
1821
|
+
}
|
|
1822
|
+
undoMeasurement() {
|
|
1823
|
+
this.measurementTool.undoLastPoint();
|
|
1824
|
+
}
|
|
1825
|
+
getMeasurements() {
|
|
1826
|
+
return this.measurementTool.getResults();
|
|
1827
|
+
}
|
|
1828
|
+
async setView(e, t = 600) {
|
|
1829
|
+
this.currentModel && (await this.cameraTool.setView(e, this.currentModel, t), this.emit("view:change", e));
|
|
1830
|
+
}
|
|
1831
|
+
async fitView(e = 500) {
|
|
1832
|
+
this.currentModel && await this.cameraTool.fitToObject(this.currentModel, e);
|
|
1833
|
+
}
|
|
1834
|
+
setAutoRotate(e, t, n, r) {
|
|
1835
|
+
this.cameraTool.setAutoRotate(e, t, n, r), this.emit("autorotate:change", this.cameraTool.getAutoRotateState());
|
|
1836
|
+
}
|
|
1837
|
+
toggleAutoRotate() {
|
|
1838
|
+
let e = this.cameraTool.toggleAutoRotate();
|
|
1839
|
+
return this.emit("autorotate:change", this.cameraTool.getAutoRotateState()), e;
|
|
1840
|
+
}
|
|
1841
|
+
setAutoRotateAxis(e) {
|
|
1842
|
+
this.cameraTool.setAutoRotateAxis(e), this.emit("autorotate:change", this.cameraTool.getAutoRotateState());
|
|
1843
|
+
}
|
|
1844
|
+
setAutoRotateDirection(e) {
|
|
1845
|
+
this.cameraTool.setAutoRotateDirection(e), this.emit("autorotate:change", this.cameraTool.getAutoRotateState());
|
|
1846
|
+
}
|
|
1847
|
+
setAutoRotateSpeed(e) {
|
|
1848
|
+
this.cameraTool.setAutoRotateSpeed(e), this.emit("autorotate:change", this.cameraTool.getAutoRotateState());
|
|
1849
|
+
}
|
|
1850
|
+
getAutoRotateState() {
|
|
1851
|
+
return this.cameraTool.getAutoRotateState();
|
|
1852
|
+
}
|
|
1853
|
+
setRotationLockedAxis(e) {
|
|
1854
|
+
this.cameraTool.setLockedAxis(e), this.emit("axislock:change", e);
|
|
1855
|
+
}
|
|
1856
|
+
getRotationLockedAxis() {
|
|
1857
|
+
return this.cameraTool.getLockedAxis();
|
|
1858
|
+
}
|
|
1859
|
+
async exportImage(e = {}) {
|
|
1860
|
+
return this.screenshotTool.exportImage(e);
|
|
1861
|
+
}
|
|
1862
|
+
on(e, t) {
|
|
1863
|
+
return super.on(e, t);
|
|
1864
|
+
}
|
|
1865
|
+
off(e, t) {
|
|
1866
|
+
return super.off(e, t);
|
|
1867
|
+
}
|
|
1868
|
+
destroy() {
|
|
1869
|
+
this.clearModel(), this.measurementTool.destroy(), this.clippingTool.destroy(), this.sceneManager.destroy(), this.removeAllListeners();
|
|
1870
|
+
}
|
|
1871
|
+
};
|
|
1872
|
+
//#endregion
|
|
1873
|
+
export { x as BoundingBoxTool, S as CameraTool, w as ClippingTool, p as EventEmitter, T as MeasurementTool, h as ModelLoader, f as SceneManager, E as ScreenshotTool, D as Viewer, m as ZipExtractor, y as compute3DPolygonArea, _ as computeGroupVolume, g as computeMeshVolume, C as findSnapPoint, b as formatUnit };
|
|
1874
|
+
|
|
1875
|
+
//# sourceMappingURL=index.js.map
|