@giszhc/three-model-viewer 0.0.0-stage → 1.0.0

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/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