@giszhc/three-model-viewer 1.0.0 → 1.1.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/README.md CHANGED
@@ -3,7 +3,7 @@
3
3
  > 🚀 现代化、高内聚的 Web 3D 模型检视与工程测量 SDK。基于 **Three.js** 与 **TypeScript** 构建,专为 Web 端三维轻量化展示、尺寸标注、空间测量与截面剖切量身定制。
4
4
 
5
5
  [![Live Demo](https://img.shields.io/badge/Demo-在线实时体验-0ea5e9?style=flat-square&logo=github)](https://giszhc.github.io/three-model-viewer/)
6
- [![npm version](https://img.shields.io/badge/npm-v1.0.0-blue.svg)](https://www.npmjs.com/package/@giszhc/three-model-viewer)
6
+ [![npm version](https://img.shields.io/badge/npm-v1.1.0-blue.svg)](https://www.npmjs.com/package/@giszhc/three-model-viewer)
7
7
  [![TypeScript](https://img.shields.io/badge/TypeScript-Ready-3178c6.svg)](https://www.typescriptlang.org/)
8
8
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
9
9
 
@@ -13,7 +13,8 @@
13
13
 
14
14
  ## 🌟 核心特性
15
15
 
16
- - 📦 **多源格式无缝加载**:支持 `OBJ`、`MTL`,以及包含模型和图片贴图的 `ZIP` 压缩包在浏览器**纯内存解压加载**,无需后端转码服务。
16
+ - 📦 **全能 3D 格式无缝加载**:原生支持 `GLB`、`GLTF`(内置 **DRACO 网格压缩解压**、**KTX2 / Basis Universal 纹理压缩** 与 **Meshopt 压缩**,支持骨骼与关键帧动画)、`OBJ`、`MTL`,以及包含模型和图片贴图的 `ZIP` 压缩包在浏览器**纯内存解压加载**,无需后端转码服务。
17
+ - 🎬 **骨骼与模型动画播放**:针对 GLTF / GLB 格式模型自动识别内置动画剪辑(Animation Clips),提供播放、暂停、多动作切换与 0.5x~2.0x 倍速控制。
17
18
  - 📏 **动态长宽高范围框**:实时绘制模型包围盒与三向尺寸引导线。**随着模型旋转,长宽高标签与指示线自动在当前的三个轴向空间自适应展示**。
18
19
  - 🎯 **严格模型表面约束与磁吸**:所有测量与自定义剖切交互**严格限制在模型表面**,模型外部点击自动拦截;内置 BVH 空间索引,鼠标靠近网格顶点时自动实现**毫秒级磁吸(Snapping)**;**表面标点与指示光标采用屏幕空间恒定像素渲染(Screen-Space Fixed Size),放大缩小模型时标点尺寸始终固定不畸变**。
19
20
  - 📐 **全功能工程级测量 (单次测量即退,严防误触)**:
@@ -141,9 +142,38 @@ fileInput.addEventListener('change', async (e) => {
141
142
 
142
143
  | 方法名 | 参数 | 描述 |
143
144
  | :--- | :--- | :--- |
144
- | `loadZip(source)` | `File \| Blob \| ArrayBuffer \| string` | 加载包含 `.obj`、`.mtl` 和贴图图片的 ZIP 压缩包 |
145
+ | `loadGLB(source)` | `string \| ArrayBuffer \| Blob \| File` | 加载独立 `.glb` 二进制 3D 模型(支持骨骼动画与 DRACO 压缩) |
146
+ | `loadGLTF(source)` | `string \| ArrayBuffer` | 加载 `.gltf` 场景定义 |
147
+ | `loadZip(source)` | `File \| Blob \| ArrayBuffer \| string` | 加载包含 `.glb`、`.gltf` 或 `.obj`+`.mtl`+贴图的 ZIP 压缩包 |
145
148
  | `loadOBJ(objUrl, mtlUrl?)` | `string, string?` | 通过 URL 直接加载 OBJ 及可选的 MTL 材质文件 |
146
- | `clearModel()` | - | 清除当前加载的模型并释放内存资源 |
149
+ | `loadFiles(files)` | `FileList \| File[]` | 智能识别并加载所选文件列表(支持 GLB/GLTF/ZIP/OBJ 多文件关联) |
150
+ | `loadFromUrl(url)` | `string` | 自动根据在线直链后缀识别并加载模型 |
151
+ | `clearModel()` | - | 清除当前加载的模型、停止动画并释放内存资源 |
152
+
153
+ ### 2. 动画控制系统 (`Animations`)
154
+
155
+ 针对包含内置动画剪辑(Animation Clips)的 GLTF/GLB 模型:
156
+
157
+ ```typescript
158
+ // 1. 获取当前模型包含的所有动作剪辑名称列表
159
+ const clips = viewer.getAnimations(); // ['Idle', 'Walk', 'Run']
160
+
161
+ // 2. 播放指定动作 (支持动作名称或数字索引)
162
+ viewer.playAnimation('Run');
163
+ // 或 viewer.playAnimation(0);
164
+
165
+ // 3. 暂停、继续与停止动画
166
+ viewer.pauseAnimation(); // 暂停当前动作
167
+ viewer.resumeAnimation(); // 从暂停位置继续播放
168
+ viewer.stopAnimation(); // 停止并回到起始帧
169
+
170
+ // 4. 获取当前播放动作与状态
171
+ const currentClip = viewer.getCurrentAnimation();
172
+ const isPlaying = viewer.isAnimationPlaying();
173
+
174
+ // 5. 调节播放速度 (0.5x, 1.0x, 2.0x 等)
175
+ viewer.setAnimationSpeed(1.5);
176
+ ```
147
177
 
148
178
  ### 2. 测量系统 (`Measurement`)
149
179
 
@@ -20,6 +20,12 @@ export declare class Viewer extends EventEmitter {
20
20
  currentModelInfo: ModelLoadResult | null;
21
21
  private unit;
22
22
  private defaultShowBoundingBox;
23
+ private animationMixer;
24
+ private animationClips;
25
+ private activeAction;
26
+ private currentAnimationName;
27
+ private animationClock;
28
+ private isAnimationActive;
23
29
  constructor(options: ViewerOptions);
24
30
  /**
25
31
  * Load model from a ZIP file containing .obj, .mtl and textures
@@ -29,6 +35,23 @@ export declare class Viewer extends EventEmitter {
29
35
  * Load model directly from OBJ URL and optional MTL URL
30
36
  */
31
37
  loadOBJ(objUrl: string, mtlUrl?: string): Promise<ModelLoadResult>;
38
+ /**
39
+ * Load model from a GLTF URL or ArrayBuffer
40
+ */
41
+ loadGLTF(source: string | ArrayBuffer): Promise<ModelLoadResult>;
42
+ /**
43
+ * Load GLB binary model from File, Blob, ArrayBuffer, or online URL
44
+ */
45
+ loadGLB(source: string | ArrayBuffer | Blob | File): Promise<ModelLoadResult>;
46
+ /**
47
+ * Automatically detect and load multiple selected or drag-dropped files
48
+ * (Supports .zip, .glb, .gltf + companion .bin / textures, .obj + .mtl / textures)
49
+ */
50
+ loadFiles(files: FileList | File[]): Promise<ModelLoadResult>;
51
+ /**
52
+ * Automatically load 3D model from an online URL (.glb, .gltf, .zip, .obj)
53
+ */
54
+ loadFromUrl(url: string): Promise<ModelLoadResult>;
32
55
  /**
33
56
  * Loads a built-in sample geometry (convenient for immediate testing and demo playground)
34
57
  */
@@ -111,5 +134,37 @@ export declare class Viewer extends EventEmitter {
111
134
  exportImage(options?: ExportImageOptions): Promise<string>;
112
135
  on<K extends keyof ViewerEvents>(event: K, listener: ViewerEvents[K]): this;
113
136
  off<K extends keyof ViewerEvents>(event: K, listener: ViewerEvents[K]): this;
137
+ /**
138
+ * Returns list of animation clip names available in the current model
139
+ */
140
+ getAnimations(): string[];
141
+ /**
142
+ * Returns name of the currently active animation
143
+ */
144
+ getCurrentAnimation(): string | null;
145
+ /**
146
+ * Play an animation by name or clip index
147
+ */
148
+ playAnimation(nameOrIndex?: string | number): void;
149
+ /**
150
+ * Pause playback of the active animation
151
+ */
152
+ pauseAnimation(): void;
153
+ /**
154
+ * Resume playback of paused animation
155
+ */
156
+ resumeAnimation(): void;
157
+ /**
158
+ * Stop active animation and reset to start frame
159
+ */
160
+ stopAnimation(): void;
161
+ /**
162
+ * Check whether animation is actively playing
163
+ */
164
+ isAnimationPlaying(): boolean;
165
+ /**
166
+ * Set playback timeScale speed factor (e.g. 0.5, 1.0, 2.0)
167
+ */
168
+ setAnimationSpeed(speed: number): void;
114
169
  destroy(): void;
115
170
  }
package/dist/index.cjs CHANGED
@@ -1,5 +1,5 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});var e=Object.create,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,i=Object.getPrototypeOf,a=Object.prototype.hasOwnProperty,o=(e,i,o,s)=>{if(i&&typeof i==`object`||typeof i==`function`)for(var c=r(i),l=0,u=c.length,d;l<u;l++)d=c[l],!a.call(e,d)&&d!==o&&t(e,d,{get:(e=>i[e]).bind(null,d),enumerable:!(s=n(i,d))||s.enumerable});return e},s=(n,r,s)=>(s=n==null?{}:e(i(n)),o(r||!n||!n.__esModule||!a.call(n,`default`)?t(s,`default`,{value:n,enumerable:!0}):s,n));let c=require("three");c=s(c,1);let l=require("three/addons/controls/OrbitControls.js"),u=require("three/addons/controls/TrackballControls.js"),d=require("three/addons/renderers/CSS2DRenderer.js"),f=require("@tweenjs/tween.js");f=s(f,1);let p=require("three/addons/loaders/OBJLoader.js"),m=require("three/addons/loaders/MTLLoader.js"),h=require("three-mesh-bvh"),g=require("jszip");g=s(g,1);var _=class{container;scene;camera;renderer;labelRenderer;controls;lightsGroup;gridHelper;tweenGroup;onBeforeRender;animationFrameId=null;resizeObserver=null;isDestroyed=!1;constructor(e){this.container=e.container,this.scene=new c.Scene,e.background!==void 0&&e.background!==null?(typeof e.background==`string`||typeof e.background==`number`)&&(this.scene.background=new c.Color(e.background)):this.scene.background=new c.Color(1580068);let t=this.container.clientWidth||800,n=this.container.clientHeight||600;if(this.camera=new c.PerspectiveCamera(e.cameraFov??45,t/n,e.cameraNear??.1,e.cameraFar??5e3),this.camera.position.set(10,10,10),this.renderer=new c.WebGLRenderer({antialias:e.antialias??!0,alpha:e.alpha??!1,preserveDrawingBuffer:!0,powerPreference:`high-performance`}),this.renderer.setSize(t,n),this.renderer.setPixelRatio(Math.min(window.devicePixelRatio,2)),this.renderer.localClippingEnabled=!0,this.renderer.toneMapping=c.ACESFilmicToneMapping,this.renderer.toneMappingExposure=1,this.renderer.outputColorSpace=c.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 d.CSS2DRenderer,this.labelRenderer.setSize(t,n),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),(e.controlsType??`trackball`)===`orbit`){let e=new l.OrbitControls(this.camera,this.renderer.domElement);e.enableDamping=!0,e.dampingFactor=.05,e.screenSpacePanning=!0,this.controls=e}else{let e=new u.TrackballControls(this.camera,this.renderer.domElement);e.rotateSpeed=2.5,e.zoomSpeed=1.2,e.panSpeed=.8,e.staticMoving=!1,e.dynamicDampingFactor=.15,this.controls=e}this.tweenGroup=new f.Group,this.lightsGroup=new c.Group,this.lightsGroup.name=`gmv-lights-group`,this.initLights(),this.scene.add(this.lightsGroup),this.gridHelper=new c.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)}initLights(){let e=new c.HemisphereLight(16777215,4674921,1);e.position.set(0,50,0),this.lightsGroup.add(e);let t=new c.AmbientLight(16777215,.8);this.lightsGroup.add(t);let n=new c.DirectionalLight(16777215,1.2);n.position.set(50,100,50),this.lightsGroup.add(n);let r=new c.DirectionalLight(16777215,.7);r.position.set(-50,50,-50),this.lightsGroup.add(r);let i=new c.DirectionalLight(16777215,.9);i.position.set(0,0,1),this.camera.add(i),this.scene.add(this.camera)}initResizeObserver(){this.resizeObserver=new ResizeObserver(()=>{this.handleResize()}),this.resizeObserver.observe(this.container)}handleResize(){if(this.isDestroyed||!this.container)return;let e=this.container.clientWidth,t=this.container.clientHeight;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())}startAnimationLoop(){let e=()=>{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))};this.animationFrameId=requestAnimationFrame(e)}setBackground(e,t){t||e==null?(this.scene.background=null,this.renderer.setClearAlpha(0)):(this.scene.background=new c.Color(e),this.renderer.setClearAlpha(1))}destroy(){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)}},v=class{events;constructor(){this.events=new Map}on(e,t){return this.events.has(e)||this.events.set(e,[]),this.events.get(e).push(t),this}off(e,t){let n=this.events.get(e);if(!n)return this;let r=n.indexOf(t);return r!==-1&&n.splice(r,1),this}emit(e,...t){let n=this.events.get(e);return!n||n.length===0?!1:([...n].forEach(n=>{try{n(...t)}catch(t){console.error(`Error in event listener for "${e}":`,t)}}),!0)}removeAllListeners(e){return e?this.events.delete(e):this.events.clear(),this}},y=class{static async extract(e,t){let n;if(t?.(5,`正在读取文件字节流...`),typeof e==`string`){let t=await fetch(e);if(!t.ok)throw Error(`Failed to fetch zip file: ${t.statusText}`);n=await t.arrayBuffer()}else n=e instanceof Blob||e instanceof File?await e.arrayBuffer():e;t?.(15,`正在解压 ZIP 文件包...`);let r=await g.default.loadAsync(n),i=new Map,a=null,o=null,s=[`.png`,`.jpg`,`.jpeg`,`.webp`,`.bmp`,`.tga`,`.dds`],l=Object.keys(r.files),u=l.length||1;for(let e=0;e<l.length;e++){let n=l[e],c=r.files[n];if(c.dir||n.includes(`__MACOSX`)||n.split(`/`).pop()?.startsWith(`._`))continue;let d=n.toLowerCase(),f=Math.round(20+e/u*35);if(d.endsWith(`.obj`)&&!a?(a=c,t?.(f,`找到模型文件: ${n.split(`/`).pop()}`)):d.endsWith(`.mtl`)&&!o&&(o=c,t?.(f,`找到材质定义: ${n.split(`/`).pop()}`)),s.some(e=>d.endsWith(e))){let e=n.split(`/`).pop()||n;t?.(f,`加载贴图: ${e}`);let r=await c.async(`blob`),a=URL.createObjectURL(r);i.set(n,a),i.set(e,a),i.set(e.toLowerCase(),a)}}if(t?.(60,`提取完成,准备解析三维几何网格...`),!a)throw i.forEach(e=>URL.revokeObjectURL(e)),Error(`No .obj file found in the zip archive.`);let d=await a.async(`string`),f=a.name,p=null,m=null;o&&(p=await o.async(`string`),m=o.name);let h=new c.LoadingManager;return h.setURLModifier(e=>{let t=decodeURIComponent(e),n=t.split(`/`).pop()?.split(`\\`).pop()||t;if(i.has(t))return i.get(t);if(i.has(n))return i.get(n);for(let[e,t]of i.entries())if(e.toLowerCase()===n.toLowerCase())return t;return e}),{objContent:d,objFileName:f,mtlContent:p,mtlFileName:m,blobUrls:i,loadingManager:h,dispose:()=>{i.forEach(e=>{try{URL.revokeObjectURL(e)}catch{}}),i.clear()}}}};c.BufferGeometry.prototype.computeBoundsTree=h.computeBoundsTree,c.BufferGeometry.prototype.disposeBoundsTree=h.disposeBoundsTree,c.Mesh.prototype.raycast=h.acceleratedRaycast;var b=class{currentZipContent=null;managedMaterials=[];isTextureEnabled=!0;displayStyle=`solid`;plainColor=5016790;currentClippingPlanes=[];async loadZip(e,t){this.cleanup();let n=await y.extract(e,t);this.currentZipContent=n;let{objContent:r,mtlContent:i,loadingManager:a}=n;t?.(65,`正在解析材质与贴图数据...`);let o=null;i&&(o=new m.MTLLoader(a).parse(i,``),o.preload()),t?.(75,`正在解析 OBJ 网格几何数据...`);let s=new p.OBJLoader(a);o&&s.setMaterials(o);let c=typeof r==`string`?r:new TextDecoder().decode(r),l=s.parse(c);t?.(88,`正在建立空间 BVH 加速结构与几何居中...`);let u=this.postProcessModel(l);return t?.(100,`加载完成`),u}async loadOBJ(e,t,n){this.cleanup(),n?.(20,`正在加载材质定义...`);let r=null;t&&(r=await new m.MTLLoader().loadAsync(t),r.preload()),n?.(50,`正在加载 OBJ 模型几何数据...`);let i=new p.OBJLoader;r&&i.setMaterials(r);let a=await i.loadAsync(e,e=>{if(e.lengthComputable&&e.total>0){let t=Math.round(50+e.loaded/e.total*35);n?.(t,`正在传输模型数据 (${Math.round(e.loaded/e.total*100)}%)...`)}});n?.(88,`正在建立空间 BVH 加速结构与几何居中...`);let o=this.postProcessModel(a);return n?.(100,`加载完成`),o}postProcessModel(e){let t=0,n=0;this.managedMaterials=[];let r=e=>{e&&(e.anisotropy=16,e.generateMipmaps=!0,e.minFilter=c.LinearMipmapLinearFilter,e.magFilter=c.LinearFilter,e.colorSpace=c.SRGBColorSpace,e.needsUpdate=!0)},i=e=>{if(e.side=c.DoubleSide,e.needsUpdate=!0,`color`in e){let t=e;r(t.map),`normalMap`in t&&r(t.normalMap),`bumpMap`in t&&r(t.bumpMap),!t.map&&t.color&&t.color.getHex()<2236962&&t.color.setHex(11581636)}},a=new c.Box3().setFromObject(e),o=new c.Vector3,s=new c.Vector3;return a.getCenter(o),a.getSize(s),e.traverse(e=>{if(e.isMesh){let r=e;r.castShadow=!0,r.receiveShadow=!0,r.material?Array.isArray(r.material)?r.material.forEach(i):i(r.material):r.material=new c.MeshStandardMaterial({color:this.plainColor,roughness:.45,metalness:.12,side:c.DoubleSide});let a=r.geometry;if(a){a.translate(-o.x,-o.y,-o.z),a.attributes.normal||a.computeVertexNormals(),a.computeBoundsTree&&a.computeBoundsTree(),a.attributes.position&&(t+=a.attributes.position.count),a.index?n+=a.index.count/3:a.attributes.position&&(n+=a.attributes.position.count/3);let e=new c.MeshStandardMaterial({color:this.plainColor,roughness:.45,metalness:.12,side:c.DoubleSide,clippingPlanes:this.currentClippingPlanes.length>0?this.currentClippingPlanes:null,clipShadows:!0}),i={mesh:r,originalMaterial:r.material,plainMaterial:e};this.applyStyleToItem(i),this.managedMaterials.push(i)}}}),e.position.set(0,0,0),e.rotation.set(0,0,0),e.scale.set(1,1,1),e.updateMatrixWorld(!0),{model:e,box:new c.Box3().setFromObject(e),size:s,center:o,vertexCount:t,faceCount:Math.round(n)}}applyStyleToItem(e){let t=this.isTextureEnabled?e.originalMaterial:e.plainMaterial;e.mesh.material=t;let n=e=>{e.visible=!0,`wireframe`in e&&(e.wireframe=this.displayStyle===`wireframe`),e.needsUpdate=!0};Array.isArray(t)?t.forEach(n):n(t)}setDisplayStyle(e){this.displayStyle=e;for(let e of this.managedMaterials)this.applyStyleToItem(e)}getDisplayStyle(){return this.displayStyle}toggleTexture(e){this.isTextureEnabled=e;for(let e of this.managedMaterials)this.applyStyleToItem(e)}getTextureState(){return this.isTextureEnabled}setPlainColor(e){this.plainColor=typeof e==`string`?new c.Color(e).getHex():Number(e);for(let e of this.managedMaterials)e.plainMaterial&&`color`in e.plainMaterial&&(e.plainMaterial.color.set(this.plainColor),e.plainMaterial.needsUpdate=!0)}getPlainColor(){return this.plainColor}getModelTextureSize(){let e=0,t=0,n=n=>{if(`map`in n&&n.map){let r=n.map;if(r){let n=r.image||r.source?.data;if(n){let r=n.width||0,i=n.height||0;r>0&&i>0&&r*i>e*t&&(e=r,t=i)}}}};for(let e of this.managedMaterials)Array.isArray(e.originalMaterial)?e.originalMaterial.forEach(n):e.originalMaterial&&n(e.originalMaterial);return e>0&&t>0?{width:e,height:t}:null}getMeshes(){return this.managedMaterials.map(e=>e.mesh)}applyClippingPlanes(e){this.currentClippingPlanes=e;for(let t of this.managedMaterials){let n=t=>{t.clippingPlanes=e.length>0?e:null,t.clipShadows=!0,t.needsUpdate=!0};Array.isArray(t.originalMaterial)?t.originalMaterial.forEach(n):n(t.originalMaterial),n(t.plainMaterial)}}cleanup(){this.currentZipContent&&=(this.currentZipContent.dispose(),null);for(let e of this.managedMaterials)e.plainMaterial&&e.plainMaterial.dispose(),e.mesh.geometry&&e.mesh.geometry.disposeBoundsTree&&e.mesh.geometry.disposeBoundsTree();this.managedMaterials=[]}};function x(e){let t=e.geometry;if(!t)return 0;let n=t.attributes.position;if(!n)return 0;let r=0,i=new c.Vector3,a=new c.Vector3,o=new c.Vector3;e.updateMatrixWorld(!0);let s=e.matrixWorld;if(t.index){let e=t.index;for(let t=0;t<e.count;t+=3){let c=e.getX(t),l=e.getX(t+1),u=e.getX(t+2);i.fromBufferAttribute(n,c).applyMatrix4(s),a.fromBufferAttribute(n,l).applyMatrix4(s),o.fromBufferAttribute(n,u).applyMatrix4(s),r+=C(i,a,o)}}else for(let e=0;e<n.count;e+=3)i.fromBufferAttribute(n,e).applyMatrix4(s),a.fromBufferAttribute(n,e+1).applyMatrix4(s),o.fromBufferAttribute(n,e+2).applyMatrix4(s),r+=C(i,a,o);return Math.abs(r)}function S(e){let t=0;e.traverse(e=>{e.isMesh&&(t+=x(e))});let n=new c.Box3().setFromObject(e),r=new c.Vector3;n.getSize(r);let i=r.x*r.y*r.z;return{meshVolume:t,bboxVolume:i}}function C(e,t,n){return e.dot(t.clone().cross(n))/6}function w(e){let t=e.length;if(t<3)return 0;let n=new c.Vector3(0,0,0);for(let r=0;r<t;r++){let i=e[r],a=e[(r+1)%t];n.x+=(i.y-a.y)*(i.z+a.z),n.y+=(i.z-a.z)*(i.x+a.x),n.z+=(i.x-a.x)*(i.y+a.y)}return n.length()*.5}function T(e,t=`m`,n=2){return Math.abs(e)<.001?`0.00 ${t}`:`${e.toFixed(n)} ${t}`}var E=class{scene;boxGroup;wireframeBox=null;lineX=null;lineY=null;lineZ=null;labelX=null;labelY=null;labelZ=null;currentModel=null;isVisible=!1;unit=`m`;localVertices=[];worldVertices=[new c.Vector3,new c.Vector3,new c.Vector3,new c.Vector3,new c.Vector3,new c.Vector3,new c.Vector3,new c.Vector3];modelSize=new c.Vector3;constructor(e){this.scene=e,this.boxGroup=new c.Group,this.boxGroup.name=`gmv-bounding-box-group`,this.scene.add(this.boxGroup)}attachToModel(e,t){this.detach(),this.currentModel=e,this.unit=t?.unit||`m`,e.updateMatrixWorld(!0);let n=new c.Box3;e.traverse(e=>{if(e.isMesh){let t=e;t.geometry&&(t.geometry.boundingBox||t.geometry.computeBoundingBox(),t.geometry.boundingBox&&n.union(t.geometry.boundingBox))}}),n.isEmpty()&&n.setFromObject(e);let r=n.min,i=n.max;n.getSize(this.modelSize),this.localVertices=[new c.Vector3(r.x,r.y,r.z),new c.Vector3(i.x,r.y,r.z),new c.Vector3(r.x,i.y,r.z),new c.Vector3(i.x,i.y,r.z),new c.Vector3(r.x,r.y,i.z),new c.Vector3(i.x,r.y,i.z),new c.Vector3(r.x,i.y,i.z),new c.Vector3(i.x,i.y,i.z)];let a=[0,1,2,3,4,5,6,7,0,2,1,3,4,6,5,7,0,4,1,5,2,6,3,7],o=new c.BufferGeometry,s=new Float32Array(a.length*3);o.setAttribute(`position`,new c.BufferAttribute(s,3));let l=new c.LineBasicMaterial({color:t?.color?new c.Color(t.color):54015,linewidth:1,transparent:!0,opacity:.6,depthTest:!0});this.wireframeBox=new c.LineSegments(o,l),this.boxGroup.add(this.wireframeBox),this.lineX=this.createDynamicLine(15680580),this.lineY=this.createDynamicLine(1096065),this.lineZ=this.createDynamicLine(3900150);let u=document.createElement(`div`);u.className=`gmv-dimension-badge dim-x`,u.innerHTML=`<span>长 (X):</span> <strong>${T(this.modelSize.x,this.unit)}</strong>`,this.labelX=new d.CSS2DObject(u),this.boxGroup.add(this.labelX);let f=document.createElement(`div`);f.className=`gmv-dimension-badge dim-y`,f.innerHTML=`<span>高 (Y):</span> <strong>${T(this.modelSize.y,this.unit)}</strong>`,this.labelY=new d.CSS2DObject(f),this.boxGroup.add(this.labelY);let p=document.createElement(`div`);p.className=`gmv-dimension-badge dim-z`,p.innerHTML=`<span>宽 (Z):</span> <strong>${T(this.modelSize.z,this.unit)}</strong>`,this.labelZ=new d.CSS2DObject(p),this.boxGroup.add(this.labelZ),this.setVisible(t?.visible??!1)}createDynamicLine(e){let t=new c.BufferGeometry().setFromPoints([new c.Vector3,new c.Vector3]),n=new c.LineBasicMaterial({color:e,linewidth:3,depthTest:!1}),r=new c.Line(t,n);return this.boxGroup.add(r),r}update(e){if(!this.isVisible||!this.currentModel||this.localVertices.length<8)return;this.currentModel.updateMatrixWorld(!0);let t=this.currentModel.matrixWorld;for(let e=0;e<8;e++)this.worldVertices[e].copy(this.localVertices[e]).applyMatrix4(t);if(this.wireframeBox){let e=[0,1,2,3,4,5,6,7,0,2,1,3,4,6,5,7,0,4,1,5,2,6,3,7],t=this.wireframeBox.geometry.attributes.position,n=0;for(let r of e){let e=this.worldVertices[r];t.setXYZ(n++,e.x,e.y,e.z)}t.needsUpdate=!0}let n=0,r=1/0,i=e.position;for(let e=0;e<8;e++){let t=this.worldVertices[e].distanceTo(i);t<r&&(r=t,n=e)}let a=this.worldVertices[n],o=this.worldVertices[n^1],s=this.worldVertices[n^2],c=this.worldVertices[n^4];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)}updateLine(e,t,n){if(!e)return;let r=e.geometry.attributes.position;r.setXYZ(0,t.x,t.y,t.z),r.setXYZ(1,n.x,n.y,n.z),r.needsUpdate=!0}setVisible(e){this.isVisible=e,this.boxGroup.visible=e}getVisible(){return this.isVisible}setUnit(e){this.unit=e,this.currentModel&&this.attachToModel(this.currentModel,{visible:this.isVisible,unit:e})}detach(){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}destroy(){this.detach(),this.scene.remove(this.boxGroup)}},D=class{camera;controls;tweenGroup;currentTween=null;isAutoRotating=!1;autoRotateAxis=`x`;autoRotateDirection=`clockwise`;autoRotateSpeed=1;lockedAxis=null;lockedPitchAngle=0;lockedYawAngle=0;constructor(e,t,n){this.camera=e,this.controls=t,this.tweenGroup=n||new f.Group}setAutoRotate(e,t,n,r){this.isAutoRotating=e,t!==void 0&&(this.autoRotateAxis=t),n!==void 0&&(this.autoRotateDirection=n),r!==void 0&&(this.autoRotateSpeed=r)}toggleAutoRotate(){return this.isAutoRotating=!this.isAutoRotating,this.isAutoRotating}setAutoRotateAxis(e){this.autoRotateAxis=e}setAutoRotateDirection(e){this.autoRotateDirection=e}setAutoRotateSpeed(e){this.autoRotateSpeed=Math.max(.1,Math.min(10,e))}getAutoRotateState(){return{enabled:this.isAutoRotating,axis:this.autoRotateAxis,direction:this.autoRotateDirection,speed:this.autoRotateSpeed}}setLockedAxis(e){this.lockedAxis=e;let t=this.camera.position.clone().sub(this.controls.target),n=t.length();n>1e-4&&(this.lockedPitchAngle=Math.asin(Math.max(-1,Math.min(1,t.y/n))),this.lockedYawAngle=Math.atan2(t.z,t.x))}getLockedAxis(){return this.lockedAxis}updatePerFrame(){let e=this.controls.target,t=this.camera.position.clone().sub(e),n=t.length();if(this.isAutoRotating&&n>.001){let n=this.autoRotateDirection===`clockwise`?1:-1,r=.008*this.autoRotateSpeed*n;if(this.autoRotateAxis===`x`){let e=new c.Vector3(1,0,0);t.applyAxisAngle(e,r),this.camera.up.applyAxisAngle(e,r)}else{let e=new c.Vector3(0,1,0);t.applyAxisAngle(e,r),this.camera.up.applyAxisAngle(e,r)}this.camera.position.copy(e).add(t),this.camera.lookAt(e)}if(this.lockedAxis&&n>.001){let t=this.camera.position.clone().sub(e),n=t.length();if(this.lockedAxis===`x`){let r=n*Math.cos(this.lockedPitchAngle),i=n*Math.sin(this.lockedPitchAngle),a=Math.atan2(t.z,t.x);t.x=r*Math.cos(a),t.y=i,t.z=r*Math.sin(a),this.camera.position.copy(e).add(t)}else if(this.lockedAxis===`y`){let r=t.y,i=Math.sqrt(Math.max(0,n*n-r*r));t.x=i*Math.cos(this.lockedYawAngle),t.z=i*Math.sin(this.lockedYawAngle),this.camera.position.copy(e).add(t)}else this.lockedAxis===`z`&&this.camera.up.set(0,1,0);this.camera.lookAt(e)}}setView(e,t,n=600){return new Promise(r=>{let i=new c.Box3().setFromObject(t),a=new c.Sphere;i.getBoundingSphere(a);let o=a.center.clone(),s=Math.max(a.radius,1);this.camera.near=Math.max(.01,s/500),this.camera.far=Math.max(1e4,s*50),this.camera.updateProjectionMatrix();let l=this.camera.fov*Math.PI/180,u=s/Math.sin(l/2)*1.15,d=new c.Vector3,p=new c.Vector3(0,1,0);switch(e){case`front`:d.set(0,0,1);break;case`back`:d.set(0,0,-1);break;case`left`:d.set(-1,0,0);break;case`right`:d.set(1,0,0);break;case`top`:d.set(0,1,1e-4),p.set(0,0,-1);break;case`bottom`:d.set(0,-1,1e-4),p.set(0,0,1);break;case`isometric`:d.set(1,1,1).normalize();break;case`isometric-back`:d.set(-1,1,-1).normalize()}let m=o.clone().add(d.multiplyScalar(u));if(this.currentTween&&=(this.currentTween.stop(),null),this.camera.up.copy(p),n<=0){this.camera.position.copy(m),this.controls.target.copy(o),this.controls.update(),r();return}let h=this.camera.position.clone(),g=this.controls.target.clone(),_={t:0};this.currentTween=new f.Tween(_,this.tweenGroup).to({t:1},n).easing(f.Easing.Cubic.Out).onUpdate(()=>{this.camera.position.lerpVectors(h,m,_.t),this.controls.target.lerpVectors(g,o,_.t),this.controls.update()}).onComplete(()=>{this.camera.position.copy(m),this.controls.target.copy(o),this.controls.update(),this.currentTween=null,r()}).start()})}fitToObject(e,t=500){return new Promise(n=>{let r=new c.Box3().setFromObject(e),i=new c.Sphere;r.getBoundingSphere(i);let a=i.center,o=Math.max(i.radius,1);this.camera.near=Math.max(.01,o/500),this.camera.far=Math.max(1e4,o*50),this.camera.updateProjectionMatrix();let s=this.camera.fov*Math.PI/180,l=o/Math.sin(s/2)*1.15,u=this.camera.position.clone().sub(this.controls.target).normalize(),d=a.clone().add(u.multiplyScalar(l)),p=this.camera.position.clone(),m=this.controls.target.clone(),h={t:0};new f.Tween(h,this.tweenGroup).to({t:1},t).easing(f.Easing.Cubic.Out).onUpdate(()=>{this.camera.position.lerpVectors(p,d,h.t),this.controls.target.lerpVectors(m,a,h.t),this.controls.update()}).onComplete(()=>{this.camera.position.copy(d),this.controls.target.copy(a),this.controls.update(),n()}).start()})}};function O(e,t,n,r=15,i=800,a=600){if(!n||n.length===0)return{hit:!1,point:null,normal:null,isVertexSnapped:!1,distanceToVertex:1/0};let o=new c.Raycaster;o.setFromCamera(e,t),o.firstHitOnly=!0;let s=o.intersectObjects(n,!0);if(s.length===0)return{hit:!1,point:null,normal:null,isVertexSnapped:!1,distanceToVertex:1/0};let l=s[0],u=l.point.clone(),d=l.face?l.face.normal.clone():new c.Vector3(0,1,0);l.object&&d.transformDirection(l.object.matrixWorld);let f=null,p=r;if(l.face&&l.object&&l.object.geometry){let n=l.object,r=n.geometry.attributes.position;if(r){let o=[l.face.a,l.face.b,l.face.c],s=new c.Vector3,u=new c.Vector3;for(let c of o){s.fromBufferAttribute(r,c).applyMatrix4(n.matrixWorld),u.copy(s).project(t);let o=(u.x+1)*.5*i,l=(-u.y+1)*.5*a,d=(e.x+1)*.5*i,m=(-e.y+1)*.5*a,h=Math.hypot(o-d,l-m);h<p&&(p=h,f=s.clone())}}}return f?{hit:!0,point:f,normal:d,isVertexSnapped:!0,distanceToVertex:p}:{hit:!0,point:u,normal:d,isVertexSnapped:!1,distanceToVertex:1/0}}var k=class{scene;camera;container;modelLoader;controls=null;emitter=null;planeX;planeY;planeZ;customPlane=null;isEnabled=!1;activeAxis=`x`;helperVisible=!0;planesGroup;interactive=!1;widgets={};isDraggingPlane=!1;draggedWidget=null;dragStartPointer=new c.Vector2;dragStartPosition=0;dragScreenAxis=new c.Vector2;dragScreenAxisLenSq=0;raycaster=new c.Raycaster;hoveredAxis=null;isPickingCustomPoints=!1;customPoints=[];customMarkersGroup;modelBox=new c.Box3;onPointerDownBound;onPointerMoveBound;onPointerMoveDragBound;onPointerUpDragBound;onDoubleClickBound;constructor(e,t,n,r,i,a){this.scene=e,this.camera=t,this.container=n,this.modelLoader=r,this.controls=i||null,this.emitter=a||null,this.planeX=new c.Plane(new c.Vector3(-1,0,0),1e5),this.planeY=new c.Plane(new c.Vector3(0,-1,0),1e5),this.planeZ=new c.Plane(new c.Vector3(0,0,-1),1e5),this.planesGroup=new c.Group,this.planesGroup.name=`gmv-interactive-clipping-planes`,this.planesGroup.visible=!1,this.scene.add(this.planesGroup),this.customMarkersGroup=new c.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})}setControls(e){this.controls=e}setEmitter(e){this.emitter=e}setInteractive(e){this.interactive=e&&this.isEnabled,!this.interactive&&this.container.style.cursor===`grab`&&(this.container.style.cursor=`default`)}setModelBounds(e){this.modelBox.copy(e),this.rebuildPlaneWidgets(),this.resetAll()}rebuildPlaneWidgets(){this.clearPlaneWidgets();let e=new c.Vector3(2,2,2),t=new c.Vector3(0,0,0);this.modelBox.isEmpty()||(this.modelBox.getSize(e),this.modelBox.getCenter(t));let n=Math.max(.001,e.x),r=Math.max(.001,e.y),i=Math.max(.001,e.z);this.widgets.x=this.createPlaneWidget(`x`,15680580,16281969,i,r,t),this.widgets.y=this.createPlaneWidget(`y`,1096065,3462041,n,i,t),this.widgets.z=this.createPlaneWidget(`z`,3900150,6333946,n,r,t),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()}createPlaneWidget(e,t,n,r,i,a){let o=new c.Group;o.name=`gmv-clip-plane-${e}`;let s=new c.PlaneGeometry(r,i),l=new c.MeshBasicMaterial({color:t,transparent:!0,opacity:.25,side:c.DoubleSide,depthWrite:!1}),u=new c.Mesh(s,l);u.userData={axis:e},u.renderOrder=999,o.add(u);let f=new c.EdgesGeometry(s),p=new c.LineBasicMaterial({color:n,transparent:!0,opacity:.85}),m=new c.LineSegments(f,p);o.add(m);let h=new c.Group,g=Math.min(r,i)*.045,_=new c.MeshBasicMaterial({color:n,transparent:!0,opacity:.9,depthTest:!1}),v=new c.SphereGeometry(g*.5,16,16),y=new c.Mesh(v,_);y.userData={axis:e},h.add(y);let b=new c.CylinderGeometry(g*.12,g*.12,g*1.8,12);b.rotateX(Math.PI/2);let x=new c.Mesh(b,_);x.userData={axis:e},h.add(x);let S=new c.ConeGeometry(g*.35,g*.65,16);S.rotateX(Math.PI/2),S.translate(0,0,g*1.1);let C=new c.Mesh(S,_);C.userData={axis:e},h.add(C);let w=new c.ConeGeometry(g*.35,g*.65,16);w.rotateX(-Math.PI/2),w.translate(0,0,-g*1.1);let T=new c.Mesh(w,_);T.userData={axis:e},h.add(T),h.renderOrder=1e3,o.add(h);let E=[u,y,x,C,T],D=document.createElement(`div`);D.className=`gmv-plane-badge gmv-plane-badge-${e}`,D.textContent=`${e.toUpperCase()} 剖切面`;let O=new d.CSS2DObject(D);O.position.set(r/2*.68,i/2*.68,0),o.add(O);let k=new c.Vector3(1,0,0);return e===`x`?(o.rotation.y=Math.PI/2,o.position.set(a.x,a.y,a.z),k=new c.Vector3(1,0,0)):e===`y`?(o.rotation.x=-Math.PI/2,o.position.set(a.x,a.y,a.z),k=new c.Vector3(0,1,0)):(o.rotation.set(0,0,0),o.position.set(a.x,a.y,a.z),k=new c.Vector3(0,0,1)),this.planesGroup.add(o),{axis:e,group:o,mesh:u,border:m,arrowGroup:h,hitMeshes:E,label:O,labelText:D,meshMat:l,borderMat:p,arrowMat:_,normal:k,baseColor:t,borderColor:n,position:a[e],inverted:!1,enabled:!1}}clearPlaneWidgets(){[`x`,`y`,`z`].forEach(e=>{let t=this.widgets[e];t&&(t.mesh.geometry.dispose(),t.meshMat.dispose(),t.border.geometry.dispose(),t.borderMat.dispose(),t.arrowMat.dispose(),this.planesGroup.remove(t.group))}),this.widgets={}}updateWidgetsVisibility(){this.planesGroup.visible=this.isEnabled&&this.helperVisible,this.interactive=this.isEnabled,[`x`,`y`,`z`].forEach(e=>{let t=this.widgets[e];t&&(t.group.visible=this.isEnabled&&this.helperVisible&&t.enabled)})}setSectioningEnabled(e){if(this.isEnabled=e,this.updateWidgetsVisibility(),e){if(![`x`,`y`,`z`].some(e=>this.widgets[e]?.enabled)){let e=this.widgets[this.activeAxis]||this.widgets.x;e&&(e.enabled=!0)}[`x`,`y`,`z`].forEach(e=>{let t=this.widgets[e];t&&t.enabled?this.setPlanePositionExplicit(e,t.position):this.disableAxisInternal(e)})}else this.disableAllAxesPlanes();this.applyPlanes(),this.emitSectioningState()}getSectioningEnabled(){return this.isEnabled}setAxisEnabled(e,t){let n=this.widgets[e];n&&(n.enabled=t,t?(this.activeAxis=e,this.isEnabled&&this.setPlanePositionExplicit(e,n.position)):this.disableAxisInternal(e),this.updateWidgetsVisibility(),this.applyPlanes(),this.emitSectioningState())}toggleAxis(e,t){let n=this.widgets[e],r=t===void 0?!n?.enabled:t;return this.setAxisEnabled(e,r),r}isAxisEnabled(e){return!!this.widgets[e]?.enabled}setSectioningAxis(e){this.activeAxis=e;let t=this.widgets[e];t&&!t.enabled&&(t.enabled=!0,this.isEnabled&&this.setPlanePositionExplicit(e,t.position)),this.updateWidgetsVisibility(),this.emitSectioningState()}getSectioningAxis(){return this.activeAxis}setSectioningHelperVisible(e){this.helperVisible=e,this.updateWidgetsVisibility(),this.emitSectioningState()}getSectioningHelperVisible(){return this.helperVisible}setAxisReverse(e,t){let n=this.widgets[e];if(n){if(n.inverted=t,this.isEnabled&&n.enabled)this.setPlanePositionExplicit(e,n.position);else{let r=this.modelBox.min[e],i=this.modelBox.max[e]-r,a=i>0?(n.position-r)/i:.5;n.labelText.textContent=`${e.toUpperCase()} 剖切面 ${(a*100).toFixed(0)}%${t?` (反向)`:``}`}}this.emitSectioningState()}setSectioningReverse(e){this.setAxisReverse(this.activeAxis,e)}getSectioningReverse(){return!!this.widgets[this.activeAxis]?.inverted}invertAxis(e){let t=this.widgets[e];return t?(this.setAxisReverse(e,!t.inverted),t.inverted):!1}resetSectioning(e){let t=new c.Vector3,n=this.modelBox.isEmpty();n?t.set(0,0,0):this.modelBox.getCenter(t),this.clearCustomPlane(),(e?[e]:[`x`,`y`,`z`]).forEach(r=>{let i=this.widgets[r];if(i){i.position=t[r],i.inverted=!1,i.group.position.set(t.x,t.y,t.z),e||(i.enabled=r===`x`);let a=n?-1:this.modelBox.min[r],o=(n?1:this.modelBox.max[r])-a,s=o>0&&!isNaN(i.position)?Math.max(0,Math.min(1,(i.position-a)/o)):.5;i.labelText.textContent=`${r.toUpperCase()} 剖切面 ${(s*100).toFixed(0)}%`}}),this.activeAxis=e||`x`,this.helperVisible=!0,this.isEnabled=!0,[`x`,`y`,`z`].forEach(e=>{let t=this.widgets[e];t&&t.enabled?this.setPlanePositionExplicit(e,t.position):this.disableAxisInternal(e)}),this.updateWidgetsVisibility(),this.applyPlanes(),this.emitSectioningState()}getSectioningState(){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)=>{let r=n-t;return isNaN(e)||r<=0?.5:Math.max(0,Math.min(1,(e-t)/r))},c=this.widgets.x,l=this.widgets.y,u=this.widgets.z,d={x:{enabled:c?.enabled??!1,inverted:c?.inverted??!1,position:c?.position??0,progress:s(c?.position??0,t,n)},y:{enabled:l?.enabled??!1,inverted:l?.inverted??!1,position:l?.position??0,progress:s(l?.position??0,r,i)},z:{enabled:u?.enabled??!1,inverted:u?.inverted??!1,position:u?.position??0,progress:s(u?.position??0,a,o)}},f=this.widgets[this.activeAxis],p=d[this.activeAxis]?.progress??.5,m=f?.position??0,h=f?.inverted??!1;return{enabled:this.isEnabled,axes:d,helperVisible:this.helperVisible,axis:this.activeAxis,isReverse:h,progress:p,position:m}}emitSectioningState(){this.emitter&&this.emitter.emit(`sectioning:change`,this.getSectioningState())}handlePointerDown(e){if(e.button!==0)return;if(this.isPickingCustomPoints){this.handleCustomPointPick(e),e.stopImmediatePropagation(),e.preventDefault();return}if(!this.interactive||!this.isEnabled||!this.helperVisible)return;let t=this.container.getBoundingClientRect(),n=new c.Vector2((e.clientX-t.left)/t.width*2-1,-((e.clientY-t.top)/t.height)*2+1);this.raycaster.setFromCamera(n,this.camera);let r=[`x`,`y`,`z`].map(e=>this.widgets[e]).filter(e=>!!(e&&e.enabled&&e.group.visible));if(r.length===0)return;let i=null;for(let e of r){let t=this.raycaster.intersectObjects(e.hitMeshes,!0);if(t.length>0){let n=t[0].distance;(!i||n<i.distance)&&(i={widget:e,distance:n})}}if(i){e.stopImmediatePropagation(),e.preventDefault();let n=i.widget;this.activeAxis=n.axis,this.isDraggingPlane=!0,this.draggedWidget=n,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`,n.meshMat.opacity=.65,n.arrowMat.opacity=1,this.dragStartPointer.set(e.clientX,e.clientY),this.dragStartPosition=n.position;let r=new c.Vector3;n.axis===`x`?r.set(1,0,0):n.axis===`y`?r.set(0,1,0):r.set(0,0,1);let a=n.group.position.clone(),o=n.group.position.clone().add(r),s=a.project(this.camera),l=new c.Vector2((s.x+1)*t.width/2,(-s.y+1)*t.height/2),u=o.project(this.camera),d=new c.Vector2((u.x+1)*t.width/2,(-u.y+1)*t.height/2);this.dragScreenAxis.subVectors(d,l),this.dragScreenAxisLenSq=this.dragScreenAxis.lengthSq(),window.addEventListener(`pointermove`,this.onPointerMoveDragBound,{capture:!0}),window.addEventListener(`pointerup`,this.onPointerUpDragBound,{capture:!0})}}handlePointerMoveDrag(e){if(!this.isDraggingPlane||!this.draggedWidget)return;e.stopImmediatePropagation(),e.preventDefault();let t=new c.Vector2(e.clientX-this.dragStartPointer.x,e.clientY-this.dragStartPointer.y),n=0;if(this.dragScreenAxisLenSq>25)n=this.dragScreenAxis.dot(t)/this.dragScreenAxisLenSq;else{let e=new c.Vector3;this.modelBox.getSize(e);let r=Math.max(.1,e[this.draggedWidget.axis]);n=-t.y/280*r}let r=this.modelBox.min[this.draggedWidget.axis],i=this.modelBox.max[this.draggedWidget.axis],a=this.dragStartPosition+n;a=Math.max(r,Math.min(i,a)),this.setPlanePositionExplicit(this.draggedWidget.axis,a)}handlePointerUpDrag(e){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(()=>{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)}))}handlePointerMove(e){if(this.isDraggingPlane||this.isPickingCustomPoints||!this.interactive||!this.isEnabled||!this.helperVisible)return;let t=this.container.getBoundingClientRect(),n=new c.Vector2((e.clientX-t.left)/t.width*2-1,-((e.clientY-t.top)/t.height)*2+1);this.raycaster.setFromCamera(n,this.camera);let r=[`x`,`y`,`z`].map(e=>this.widgets[e]).filter(e=>!!(e&&e.enabled&&e.group.visible)),i=null;for(let e of r)if(this.raycaster.intersectObjects(e.hitMeshes,!0).length>0){i=e.axis;break}this.setHoveredAxis(i),i?this.container.style.cursor=`grab`:this.container.style.cursor===`grab`&&(this.container.style.cursor=`default`)}setHoveredAxis(e){this.hoveredAxis!==e&&(this.hoveredAxis=e,[`x`,`y`,`z`].forEach(t=>{let n=this.widgets[t];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))}))}handleDoubleClick(e){if(!this.interactive||!this.isEnabled||!this.helperVisible)return;let t=this.container.getBoundingClientRect(),n=new c.Vector2((e.clientX-t.left)/t.width*2-1,-((e.clientY-t.top)/t.height)*2+1);this.raycaster.setFromCamera(n,this.camera);let r=[`x`,`y`,`z`].map(e=>this.widgets[e]).filter(e=>!!(e&&e.enabled&&e.group.visible));for(let t of r)if(this.raycaster.intersectObjects(t.hitMeshes,!0).length>0){e.stopImmediatePropagation(),e.preventDefault(),this.invertAxis(t.axis);break}}setPlanePositionExplicit(e,t){let n=this.widgets[e];if(!n)return;n.position=t,e===`x`?(n.group.position.x=t,n.inverted?this.planeX.set(new c.Vector3(1,0,0),-t):this.planeX.set(new c.Vector3(-1,0,0),t)):e===`y`?(n.group.position.y=t,n.inverted?this.planeY.set(new c.Vector3(0,1,0),-t):this.planeY.set(new c.Vector3(0,-1,0),t)):e===`z`&&(n.group.position.z=t,n.inverted?this.planeZ.set(new c.Vector3(0,0,1),-t):this.planeZ.set(new c.Vector3(0,0,-1),t)),n.enabled=!0,this.applyPlanes();let r=this.modelBox.min[e],i=this.modelBox.max[e]-r,a=i>0?(t-r)/i:.5;n.labelText.textContent=`${e.toUpperCase()} 剖切面 ${(a*100).toFixed(0)}%${n.inverted?` (反向)`:``}`,this.emitSectioningState(),this.emitter&&this.emitter.emit(`clipping:change`,{axis:e,position:t,progress:a,inverted:n.inverted,enabled:!0})}setAxisProgress(e,t){let n=this.modelBox.min[e],r=this.modelBox.max[e],i=n+Math.max(0,Math.min(1,t))*(r-n);this.setPlanePositionExplicit(e,i)}getAxisProgress(e){let t=this.widgets[e];if(!t)return .5;let n=this.modelBox.min[e],r=this.modelBox.max[e]-n;return r>0?Math.max(0,Math.min(1,(t.position-n)/r)):.5}disableAxisInternal(e){e===`x`?this.planeX.set(new c.Vector3(-1,0,0),1e5):e===`y`?this.planeY.set(new c.Vector3(0,-1,0),1e5):e===`z`&&this.planeZ.set(new c.Vector3(0,0,-1),1e5)}disableAllAxesPlanes(){[`x`,`y`,`z`].forEach(e=>{this.disableAxisInternal(e)})}setAxisClipping(e,t,n=!1){this.activeAxis=e;let r=this.widgets[e];r&&(r.inverted=n,r.enabled=!0),this.setSectioningEnabled(!0),this.setAxisProgress(e,t)}disableAxis(e){this.setAxisEnabled(e,!1)}getAxisState(e){let t=this.widgets[e];if(!t)return{enabled:!1,progress:.5,inverted:!1,position:0};let n=this.modelBox.min[e],r=this.modelBox.max[e]-n,i=r>0?(t.position-n)/r:.5;return{enabled:this.isEnabled&&t.enabled,progress:i,inverted:t.inverted,position:t.position}}setPlanesVisible(e){this.setSectioningHelperVisible(e)}getPlanesVisible(){return this.helperVisible}startCustomClip(){this.cancelCustomClip(),this.isPickingCustomPoints=!0,this.customPoints=[],this.container.style.cursor=`crosshair`}cancelCustomClip(){this.isPickingCustomPoints=!1,this.container.style.cursor=`default`,this.clearCustomMarkers()}clearCustomPlane(){this.customPlane=null,this.clearCustomMarkers(),this.applyPlanes()}invertCustomClip(){return this.customPlane?(this.customPlane.negate(),this.applyPlanes(),!0):!1}hasCustomPlane(){return this.customPlane!==null}handleCustomPointPick(e){let t=this.container.getBoundingClientRect(),n=O(new c.Vector2((e.clientX-t.left)/t.width*2-1,-((e.clientY-t.top)/t.height)*2+1),this.camera,this.modelLoader.getMeshes(),15,t.width,t.height);n.hit&&n.point&&this.addCustomPoint(n.point)}addCustomPoint(e){this.customPoints.push(e.clone());let t=new c.SphereGeometry(1,16,16),n=new c.MeshBasicMaterial({color:3718648,depthTest:!1}),r=new c.Mesh(t,n);if(r.position.copy(e),r.userData={fixedScreenRadius:5.5},this.customMarkersGroup.add(r),this.updateSingleMarkerScale(r),this.customPoints.length===2){let e=this.customPoints[0],t=this.customPoints[1],n=new c.Vector3().subVectors(t,e);if(n.lengthSq()<1e-5){this.customPoints.pop(),this.customMarkersGroup.remove(r);return}n.normalize();let i=new c.Vector3;this.camera.getWorldDirection(i);let a=new c.Vector3().crossVectors(n,i).normalize();a.lengthSq()<1e-4&&(a=new c.Vector3().crossVectors(n,this.camera.up).normalize()),this.customPlane=new c.Plane().setFromNormalAndCoplanarPoint(a,e),this.clearCustomMarkers(),this.cancelCustomClip(),this.applyPlanes()}}updatePerFrame(e){if(this.customMarkersGroup.children.length===0)return;let t=e||this.container.clientHeight||window.innerHeight||800,n=this.camera.fov*Math.PI/180,r=this.camera.position,i=Math.tan(n/2);this.customMarkersGroup.traverse(e=>{if(e.userData&&typeof e.userData.fixedScreenRadius==`number`){let n=e.userData.fixedScreenRadius,a=new c.Vector3;e.getWorldPosition(a);let o=2*a.distanceTo(r)*i*n/Math.max(t,1);e.scale.setScalar(o)}})}updateSingleMarkerScale(e,t){if(e.userData&&typeof e.userData.fixedScreenRadius==`number`){let n=e.userData.fixedScreenRadius,r=t||this.container.clientHeight||window.innerHeight||800,i=this.camera.fov*Math.PI/180,a=this.camera.position,o=Math.tan(i/2),s=new c.Vector3;e.getWorldPosition(s);let l=2*s.distanceTo(a)*o*n/Math.max(r,1);e.scale.setScalar(l)}}clearCustomMarkers(){for(;this.customMarkersGroup.children.length>0;){let e=this.customMarkersGroup.children[0];e.geometry&&e.geometry.dispose(),e.material&&e.material.dispose(),this.customMarkersGroup.remove(e)}}applyPlanes(){let e=[];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)}resetAll(){this.isEnabled=!1,this.activeAxis=`x`,this.helperVisible=!0,this.disableAllAxesPlanes();let e=new c.Vector3;this.modelBox.getCenter(e),[`x`,`y`,`z`].forEach(t=>{let n=this.widgets[t];n&&(n.enabled=t===`x`,n.inverted=!1,n.position=e[t],n.group.position.set(e.x,e.y,e.z),n.labelText.textContent=`${t.toUpperCase()} 剖切面`)}),this.updateWidgetsVisibility(),this.clearCustomPlane(),this.applyPlanes(),this.emitSectioningState()}destroy(){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})}},A=class{scene;camera;container;modelLoader;emitter;controls=null;currentMode=`none`;unit=`m`;measurementGroup;results=[];activePoints=[];activePreviewGroup;activeMarkersGroup;activeLineGroup;snapCursorMesh;onPointerDownBound;onPointerMoveBound;onDoubleClickBound;constructor(e,t,n,r,i,a){this.scene=e,this.camera=t,this.container=n,this.modelLoader=r,this.emitter=i,this.controls=a||null,this.measurementGroup=new c.Group,this.measurementGroup.name=`gmv-measurements-group`,this.scene.add(this.measurementGroup),this.activePreviewGroup=new c.Group,this.activePreviewGroup.name=`gmv-measure-preview-group`,this.scene.add(this.activePreviewGroup),this.activeMarkersGroup=new c.Group,this.activeMarkersGroup.name=`gmv-active-markers-group`,this.activePreviewGroup.add(this.activeMarkersGroup),this.activeLineGroup=new c.Group,this.activeLineGroup.name=`gmv-active-line-group`,this.activePreviewGroup.add(this.activeLineGroup);let o=new c.SphereGeometry(1,16,16),s=new c.MeshBasicMaterial({color:3718648,transparent:!0,opacity:.9,depthTest:!1});this.snapCursorMesh=new c.Mesh(o,s),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)}setControls(e){this.controls=e}setUnit(e){this.unit=e}setMode(e){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)))}getMode(){return this.currentMode}getControls(){return this.controls}addListeners(){this.removeListeners(),this.container.addEventListener(`pointerdown`,this.onPointerDownBound,{capture:!0}),this.container.addEventListener(`pointermove`,this.onPointerMoveBound),this.container.addEventListener(`dblclick`,this.onDoubleClickBound)}removeListeners(){this.container.removeEventListener(`pointerdown`,this.onPointerDownBound,{capture:!0}),this.container.removeEventListener(`pointermove`,this.onPointerMoveBound),this.container.removeEventListener(`dblclick`,this.onDoubleClickBound)}handlePointerMove(e){if(this.currentMode===`none`)return;let t=this.container.getBoundingClientRect(),n=O(new c.Vector2((e.clientX-t.left)/t.width*2-1,-((e.clientY-t.top)/t.height)*2+1),this.camera,this.modelLoader.getMeshes(),15,t.width,t.height);!n.hit||!n.point?(this.container.style.cursor=`not-allowed`,this.snapCursorMesh.visible=!1):(this.container.style.cursor=`crosshair`,this.snapCursorMesh.visible=!0,this.snapCursorMesh.position.copy(n.point),n.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(n.point))}handlePointerDown(e){if(this.currentMode===`none`||e.button!==0)return;let t=this.container.getBoundingClientRect(),n=O(new c.Vector2((e.clientX-t.left)/t.width*2-1,-((e.clientY-t.top)/t.height)*2+1),this.camera,this.modelLoader.getMeshes(),15,t.width,t.height);if(!n.hit||!n.point)return;let r=n.point.clone();this.activePoints.push(r),this.addActiveMarker(r),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()}addActiveMarker(e){let t=new c.SphereGeometry(1,16,16),n=new c.MeshBasicMaterial({color:3718648,depthTest:!1}),r=new c.Mesh(t,n);r.position.copy(e),r.userData={fixedScreenRadius:5.5},this.activeMarkersGroup.add(r),this.updateSingleMeshScale(r)}handleDoubleClick(e){this.currentMode===`area`&&this.activePoints.length>=3&&this.finishAreaMeasurement()}updateDynamicPreview(e){this.clearActiveLine();let t=[...this.activePoints,e];if(t.length<2)return;let n=new c.BufferGeometry().setFromPoints(t),r=new c.LineDashedMaterial({color:3718648,dashSize:.2,gapSize:.1,depthTest:!1}),i=new c.Line(n,r);i.computeLineDistances(),this.activeLineGroup.add(i)}finishDistanceMeasurement(){let e=this.activePoints[0],t=this.activePoints[1],n=e.distanceTo(t),r=new c.Vector3().addVectors(e,t).multiplyScalar(.5),i=new c.Group,a=new c.BufferGeometry().setFromPoints([e,t]),o=new c.LineBasicMaterial({color:3900150,linewidth:2,depthTest:!1}),s=new c.Line(a,o);i.add(s),this.addEndSphere(i,e,3900150),this.addEndSphere(i,t,3900150);let l=document.createElement(`div`);l.className=`gmv-measure-badge distance`,l.innerHTML=`<span>距离:</span> <strong>${T(n,this.unit)}</strong>`;let u=new d.CSS2DObject(l);u.position.copy(r),i.add(u),this.measurementGroup.add(i);let f={id:`dist_${Date.now()}`,type:`distance`,value:n,formattedValue:T(n,this.unit),unit:this.unit,points:[e,t]};this.results.push(f),this.emitter.emit(`measure:complete`,f),this.cancelActive(),this.setMode(`none`)}finishHeightMeasurement(){let e=this.activePoints[0],t=this.activePoints[1],n=Math.abs(t.y-e.y),r=new c.Vector2(e.x,e.z).distanceTo(new c.Vector2(t.x,t.z)),i=e.distanceTo(t),a=new c.Group,o=new c.BufferGeometry().setFromPoints([e,t]),s=new c.LineDashedMaterial({color:9741240,dashSize:.15,gapSize:.08,depthTest:!1}),l=new c.Line(o,s);l.computeLineDistances(),a.add(l);let u=new c.Vector3(t.x,e.y,t.z),f=new c.BufferGeometry().setFromPoints([e,u]),p=new c.LineBasicMaterial({color:1096065,depthTest:!1}),m=new c.Line(f,p);a.add(m);let h=new c.BufferGeometry().setFromPoints([u,t]),g=new c.LineBasicMaterial({color:15680580,linewidth:2,depthTest:!1}),_=new c.Line(h,g);a.add(_),this.addEndSphere(a,e,1096065),this.addEndSphere(a,t,15680580),this.addEndSphere(a,u,16436245,4);let v=new c.Vector3().addVectors(u,t).multiplyScalar(.5),y=document.createElement(`div`);y.className=`gmv-measure-badge height`,y.innerHTML=`
2
- <div><span>高差 (ΔH):</span> <strong>${T(n,this.unit)}</strong></div>
3
- <div style="font-size:10px;opacity:0.85;">水平: ${T(r,this.unit)} · 直线: ${T(i,this.unit)}</div>
4
- `;let b=new d.CSS2DObject(y);b.position.copy(v),a.add(b),this.measurementGroup.add(a);let x={id:`height_${Date.now()}`,type:`height`,value:n,formattedValue:T(n,this.unit),unit:this.unit,points:[e,t],extra:{verticalHeight:n,horizontalDistance:r}};this.results.push(x),this.emitter.emit(`measure:complete`,x),this.cancelActive(),this.setMode(`none`)}finishAreaMeasurement(){if(this.activePoints.length<3)return;let e=[...this.activePoints],t=w(e),n=new c.Group,r=[...e,e[0]],i=new c.BufferGeometry().setFromPoints(r),a=new c.LineBasicMaterial({color:9133302,linewidth:2,depthTest:!1}),o=new c.Line(i,a);n.add(o),e.forEach(e=>this.addEndSphere(n,e,9133302));let s=new c.Vector3;e.forEach(e=>s.add(e)),s.divideScalar(e.length);let l=document.createElement(`div`);l.className=`gmv-measure-badge area`,l.innerHTML=`<span>面积:</span> <strong>${T(t,`${this.unit}²`)}</strong>`;let u=new d.CSS2DObject(l);u.position.copy(s),n.add(u),this.measurementGroup.add(n);let f={id:`area_${Date.now()}`,type:`area`,value:t,formattedValue:T(t,`${this.unit}²`),unit:`${this.unit}²`,points:e,extra:{area:t}};this.results.push(f),this.emitter.emit(`measure:complete`,f),this.cancelActive(),this.setMode(`none`)}finishAngleMeasurement(){if(this.activePoints.length!==3)return;let e=this.activePoints[0],t=this.activePoints[1],n=this.activePoints[2],r=new c.Vector3().subVectors(e,t).normalize(),i=new c.Vector3().subVectors(n,t).normalize(),a=r.dot(i);a=Math.max(-1,Math.min(1,a));let o=Math.acos(a),s=c.MathUtils.radToDeg(o),l=new c.Group,u=new c.BufferGeometry().setFromPoints([t,e]),f=new c.BufferGeometry().setFromPoints([t,n]),p=new c.LineBasicMaterial({color:16096779,linewidth:2,depthTest:!1});l.add(new c.Line(u,p)),l.add(new c.Line(f,p)),this.addEndSphere(l,e,16096779),this.addEndSphere(l,n,16096779),this.addEndSphere(l,t,15680580,6.5);let m=Math.min(e.distanceTo(t),n.distanceTo(t))*.35||.4,h=[];for(let e=0;e<=16;e++){let n=e/16,a=new c.Vector3().copy(r).lerp(i,n).normalize().multiplyScalar(m);h.push(new c.Vector3().addVectors(t,a))}let g=new c.BufferGeometry().setFromPoints(h),_=new c.LineBasicMaterial({color:16498468,depthTest:!1});l.add(new c.Line(g,_));let v=new c.Vector3().addVectors(r,i).normalize(),y=t.clone().add(v.multiplyScalar(m*1.3)),b=document.createElement(`div`);b.className=`gmv-measure-badge angle`,b.innerHTML=`<span>角度:</span> <strong>${s.toFixed(1)}°</strong>`;let x=new d.CSS2DObject(b);x.position.copy(y),l.add(x),this.measurementGroup.add(l);let S={id:`angle_${Date.now()}`,type:`angle`,value:s,formattedValue:`${s.toFixed(1)}°`,unit:`°`,points:[e,t,n],extra:{angleDegree:s}};this.results.push(S),this.emitter.emit(`measure:complete`,S),this.cancelActive(),this.setMode(`none`)}addEndSphere(e,t,n,r=5.5){let i=new c.SphereGeometry(1,16,16),a=new c.MeshBasicMaterial({color:n,depthTest:!1}),o=new c.Mesh(i,a);o.position.copy(t),o.userData={fixedScreenRadius:r},e.add(o),this.updateSingleMeshScale(o)}undoLastPoint(){if(this.activePoints.length>0){if(this.activePoints.pop(),this.activeMarkersGroup.children.length>0){let e=this.activeMarkersGroup.children[this.activeMarkersGroup.children.length-1];this.disposeObjectHierarchy(e),this.activeMarkersGroup.remove(e)}this.clearActiveLine(),this.emitter.emit(`measure:change`,[...this.activePoints])}}cancelActive(){this.activePoints=[],this.clearActiveLine(),this.clearActiveMarkers()}clearActiveLine(){for(;this.activeLineGroup.children.length>0;){let e=this.activeLineGroup.children[0];this.disposeObjectHierarchy(e),this.activeLineGroup.remove(e)}}clearActiveMarkers(){for(;this.activeMarkersGroup.children.length>0;){let e=this.activeMarkersGroup.children[0];this.disposeObjectHierarchy(e),this.activeMarkersGroup.remove(e)}}updatePerFrame(e){let t=e||this.container.clientHeight||window.innerHeight||800,n=this.camera.fov*Math.PI/180,r=this.camera.position,i=Math.tan(n/2),a=e=>{if(e.userData&&typeof e.userData.fixedScreenRadius==`number`){let n=e.userData.fixedScreenRadius,a=new c.Vector3;e.getWorldPosition(a);let o=2*a.distanceTo(r)*i*n/Math.max(t,1);e.scale.setScalar(o)}};this.snapCursorMesh&&this.snapCursorMesh.visible&&a(this.snapCursorMesh),this.activeMarkersGroup.traverse(a),this.measurementGroup.traverse(a)}updateSingleMeshScale(e,t){if(e.userData&&typeof e.userData.fixedScreenRadius==`number`){let n=e.userData.fixedScreenRadius,r=t||this.container.clientHeight||window.innerHeight||800,i=this.camera.fov*Math.PI/180,a=this.camera.position,o=Math.tan(i/2),s=new c.Vector3;e.getWorldPosition(s);let l=2*s.distanceTo(a)*o*n/Math.max(r,1);e.scale.setScalar(l)}}clearAll(){for(this.cancelActive();this.measurementGroup.children.length>0;){let e=this.measurementGroup.children[0];this.disposeObjectHierarchy(e),this.measurementGroup.remove(e)}this.snapCursorMesh.visible=!1,this.results=[],this.emitter.emit(`measure:clear`)}disposeObjectHierarchy(e){e.traverse(e=>{if(e.isCSS2DObject&&e.element){let t=e.element;t&&t.parentElement?t.parentElement.removeChild(t):t&&t.remove()}if(e.isMesh||e.isLine){let t=e;t.geometry&&t.geometry.dispose(),t.material&&(Array.isArray(t.material)?t.material.forEach(e=>e.dispose()):t.material.dispose())}})}getResults(){return[...this.results]}destroy(){this.removeListeners(),this.clearAll(),this.scene.remove(this.measurementGroup),this.scene.remove(this.activePreviewGroup),this.scene.remove(this.snapCursorMesh)}},j=class{renderer;scene;camera;getModel;constructor(e,t,n,r){this.renderer=e,this.scene=t,this.camera=n,this.getModel=r||(()=>null)}getSceneMaxTextureSize(){let e=0,t=0;return this.scene.traverse(n=>{if(n.isMesh){let r=n,i=n=>{if(`map`in n){let r=n;if(r.map){let n=r.map.image||r.map.source?.data;if(n){let r=n.width||0,i=n.height||0;r>0&&i>0&&r*i>e*t&&(e=r,t=i)}}}};Array.isArray(r.material)?r.material.forEach(i):r.material&&i(r.material)}}),e>0&&t>0?{width:e,height:t}:null}async exportImage(e={}){let t=e.originalQuality===!0||e.scale===`original`,n=t?1:typeof e.scale==`number`?e.scale:2,r=e.type??`image/png`,i=e.quality??(r===`image/png`?1:.95),a=e.download??!1,o=new c.Vector2;this.renderer.getSize(o);let s=this.renderer.getPixelRatio(),l=this.scene.background,u=o.x/o.y,d,f;if(e.targetSize)d=e.targetSize.width,f=e.targetSize.height;else if(t){let e=this.getSceneMaxTextureSize();if(e&&e.width>0&&e.height>0){let t=Math.max(e.width,e.height);u>=1?(d=t,f=Math.round(t/u)):(f=t,d=Math.round(t*u))}else{let e=Math.max(Math.round(o.x*s),2048);u>=1?(d=e,f=Math.round(e/u)):(f=e,d=Math.round(e*u))}}else d=Math.round(o.x*n),f=Math.round(o.y*n);let p=e.filename??`model-${t?`texture-original-${d}x${f}`:`${n}x`}-${Date.now()}.${r===`image/jpeg`?`jpg`:`png`}`,m=e.modelOnly??!0,h=[];e.background!==void 0&&(e.background===null?(this.scene.background=null,this.renderer.setClearAlpha(0)):(this.scene.background=new c.Color(e.background),this.renderer.setClearAlpha(1)));try{if(m){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`);for(let e of this.scene.children)!t(e)&&e.visible&&(h.push({obj:e,wasVisible:!0}),e.visible=!1)}this.renderer.setPixelRatio(1),this.renderer.setSize(d,f,!1),this.camera.aspect=d/f,this.camera.updateProjectionMatrix();let e=this.camera.fov*Math.PI/180,t=this.camera.position,n=Math.tan(e/2);this.scene.traverse(e=>{if(e.userData&&typeof e.userData.fixedScreenRadius==`number`){let r=e.userData.fixedScreenRadius,i=new c.Vector3;e.getWorldPosition(i);let a=2*i.distanceTo(t)*n*r/Math.max(f,1);e.scale.setScalar(a)}}),this.renderer.render(this.scene,this.camera);let o=this.renderer.domElement.toDataURL(r,i);if(a){let e=document.createElement(`a`);e.download=p,e.href=o,document.body.appendChild(e),e.click(),document.body.removeChild(e)}return o}finally{if(h.length>0)for(let{obj:e,wasVisible:t}of h)e.visible=t;this.scene.background=l,this.renderer.setPixelRatio(s),this.renderer.setSize(o.x,o.y,!0),this.camera.aspect=o.x/o.y,this.camera.updateProjectionMatrix();let e=o.y,t=this.camera.fov*Math.PI/180,n=this.camera.position,r=Math.tan(t/2);this.scene.traverse(t=>{if(t.userData&&typeof t.userData.fixedScreenRadius==`number`){let i=t.userData.fixedScreenRadius,a=new c.Vector3;t.getWorldPosition(a);let o=2*a.distanceTo(n)*r*i/Math.max(e,1);t.scale.setScalar(o)}}),this.renderer.render(this.scene,this.camera)}}},M=class extends v{sceneManager;modelLoader;boundingBoxTool;cameraTool;clippingTool;measurementTool;screenshotTool;currentModel=null;currentModelInfo=null;unit=`m`;defaultShowBoundingBox=!1;constructor(e){super(),this.unit=e.unit||`m`,this.defaultShowBoundingBox=e.showBoundingBox??!1,this.sceneManager=new _(e),this.modelLoader=new b,this.boundingBoxTool=new E(this.sceneManager.scene),this.cameraTool=new D(this.sceneManager.camera,this.sceneManager.controls,this.sceneManager.tweenGroup),this.clippingTool=new k(this.sceneManager.scene,this.sceneManager.camera,this.sceneManager.container,this.modelLoader,this.sceneManager.controls,this),this.measurementTool=new A(this.sceneManager.scene,this.sceneManager.camera,this.sceneManager.container,this.modelLoader,this,this.sceneManager.controls),this.measurementTool.setUnit(this.unit),this.screenshotTool=new j(this.sceneManager.renderer,this.sceneManager.scene,this.sceneManager.camera,()=>this.currentModel),this.measurementTool.setUnit(this.unit),this.sceneManager.onBeforeRender=()=>{this.boundingBoxTool.update(this.sceneManager.camera),this.cameraTool.updatePerFrame(),this.measurementTool.updatePerFrame(),this.clippingTool.updatePerFrame()}}async loadZip(e){try{this.emit(`load:start`,typeof e==`string`?e:`ZIP File`),this.clearModel();let t=await this.modelLoader.loadZip(e,(e,t)=>{this.emit(`load:progress`,e,t)});return this.setupLoadedModel(t),this.emit(`load:success`,t),t}catch(e){let t=e instanceof Error?e:Error(String(e));throw this.emit(`load:error`,t),t}}async loadOBJ(e,t){try{this.emit(`load:start`,e),this.clearModel();let n=await this.modelLoader.loadOBJ(e,t,(e,t)=>{this.emit(`load:progress`,e,t)});return this.setupLoadedModel(n),this.emit(`load:success`,n),n}catch(e){let t=e instanceof Error?e:Error(String(e));throw this.emit(`load:error`,t),t}}loadSampleGeometry(e=`mechanical`){this.clearModel();let t=new c.Group;if(e===`mechanical`){let e=new c.BoxGeometry(6,1.2,4),n=new c.MeshStandardMaterial({color:4674921,metalness:.8,roughness:.3}),r=new c.Mesh(e,n);r.position.y=.6,t.add(r);let i=new c.CylinderGeometry(1.2,1.2,3,32),a=new c.MeshStandardMaterial({color:165063,metalness:.6,roughness:.2}),o=new c.Mesh(i,a);o.position.set(0,2.7,0),t.add(o);let s=new c.TorusGeometry(1.6,.25,16,40),l=new c.MeshStandardMaterial({color:14753096,metalness:.7,roughness:.2}),u=new c.Mesh(s,l);u.rotation.x=Math.PI/2,u.position.set(0,3.2,0),t.add(u)}else if(e===`building`){let e=new c.BoxGeometry(4,10,4),n=new c.MeshStandardMaterial({color:3359061,roughness:.4}),r=new c.Mesh(e,n);r.position.y=5,t.add(r);let i=new c.ConeGeometry(3,2.5,4),a=new c.MeshStandardMaterial({color:12131356,roughness:.5}),o=new c.Mesh(i,a);o.position.y=11.25,o.rotation.y=Math.PI/4,t.add(o)}else{let e=new c.TorusKnotGeometry(2.5,.7,100,16),n=new c.MeshStandardMaterial({color:9133302,metalness:.5,roughness:.2}),r=new c.Mesh(e,n);r.position.y=3,t.add(r)}let n=this.modelLoader.postProcessModel(t);return this.setupLoadedModel(n),this.emit(`load:success`,n),n}setupLoadedModel(e){this.currentModel=e.model,this.currentModel.name=`gmv-current-model`,this.currentModelInfo=e,this.sceneManager.scene.add(this.currentModel),this.boundingBoxTool.attachToModel(this.currentModel,{visible:this.defaultShowBoundingBox,unit:this.unit}),this.clippingTool.setModelBounds(e.box),this.cameraTool.setView(`front`,this.currentModel,0)}clearModel(){this.measurementTool.clearAll(),this.clippingTool.resetAll(),this.boundingBoxTool.detach(),this.currentModel&&=(this.sceneManager.scene.remove(this.currentModel),null),this.currentModelInfo=null,this.modelLoader.cleanup()}setBackground(e,t){this.sceneManager.setBackground(e,t)}setModelDisplayStyle(e){this.modelLoader.setDisplayStyle(e),this.emit(`style:change`,e)}getModelDisplayStyle(){return this.modelLoader.getDisplayStyle()}toggleTexture(e){this.modelLoader.toggleTexture(e),this.emit(`texture:toggle`,e)}getTextureState(){return this.modelLoader.getTextureState()}setPlainColor(e){this.modelLoader.setPlainColor(e)}getPlainColor(){return this.modelLoader.getPlainColor()}getModelTextureSize(){return this.modelLoader.getModelTextureSize()}setGridVisible(e){this.sceneManager.gridHelper.visible=e}showBoundingBox(e,t){this.boundingBoxTool.setVisible(e),t?.unit&&(this.unit=t.unit,this.boundingBoxTool.setUnit(t.unit),this.measurementTool.setUnit(t.unit))}getBoundingBoxVisible(){return this.boundingBoxTool.getVisible()}setClipping(e,t,n=!1){this.clippingTool.setAxisClipping(e,t,n)}disableClippingAxis(e){this.clippingTool.disableAxis(e)}toggleClippingAxis(e,t){return this.clippingTool.toggleAxis(e,t)}invertClippingAxis(e){return this.clippingTool.invertAxis(e)}getClippingAxisState(e){return this.clippingTool.getAxisState(e)}setClippingPlanesVisible(e){this.clippingTool.setPlanesVisible(e)}getClippingPlanesVisible(){return this.clippingTool.getPlanesVisible()}setSectioningEnabled(e){this.clippingTool.setSectioningEnabled(e)}getSectioningEnabled(){return this.clippingTool.getSectioningEnabled()}setSectioningAxis(e){this.clippingTool.setSectioningAxis(e)}getSectioningAxis(){return this.clippingTool.getSectioningAxis()}setSectioningAxisEnabled(e,t){this.clippingTool.setAxisEnabled(e,t)}toggleSectioningAxis(e,t){return this.clippingTool.toggleAxis(e,t)}isSectioningAxisEnabled(e){return this.clippingTool.isAxisEnabled(e)}setSectioningAxisReverse(e,t){this.clippingTool.setAxisReverse(e,t)}invertSectioningAxis(e){return this.clippingTool.invertAxis(e)}setSectioningAxisProgress(e,t){this.clippingTool.setAxisProgress(e,t)}getSectioningAxisProgress(e){return this.clippingTool.getAxisProgress(e)}setSectioningHelperVisible(e){this.clippingTool.setSectioningHelperVisible(e)}getSectioningHelperVisible(){return this.clippingTool.getSectioningHelperVisible()}setSectioningReverse(e){this.clippingTool.setSectioningReverse(e)}getSectioningReverse(){return this.clippingTool.getSectioningReverse()}resetSectioning(e){this.clippingTool.resetSectioning(e)}getSectioningState(){return this.clippingTool.getSectioningState()}startCustomClip(){this.measurementTool.setMode(`none`),this.clippingTool.startCustomClip()}cancelCustomClip(){this.clippingTool.cancelCustomClip()}clearCustomClip(){this.clippingTool.clearCustomPlane()}invertCustomClip(){return this.clippingTool.invertCustomClip()}hasCustomClip(){return this.clippingTool.hasCustomPlane()}resetClipping(){this.clippingTool.resetAll()}setMeasurementMode(e){e===`none`?this.clippingTool.setInteractive(!0):(this.clippingTool.cancelCustomClip(),this.clippingTool.setInteractive(!1)),this.measurementTool.setMode(e)}getMeasurementMode(){return this.measurementTool.getMode()}clearMeasurements(){this.measurementTool.clearAll()}undoMeasurement(){this.measurementTool.undoLastPoint()}getMeasurements(){return this.measurementTool.getResults()}async setView(e,t=600){this.currentModel&&(await this.cameraTool.setView(e,this.currentModel,t),this.emit(`view:change`,e))}async fitView(e=500){this.currentModel&&await this.cameraTool.fitToObject(this.currentModel,e)}setAutoRotate(e,t,n,r){this.cameraTool.setAutoRotate(e,t,n,r),this.emit(`autorotate:change`,this.cameraTool.getAutoRotateState())}toggleAutoRotate(){let e=this.cameraTool.toggleAutoRotate();return this.emit(`autorotate:change`,this.cameraTool.getAutoRotateState()),e}setAutoRotateAxis(e){this.cameraTool.setAutoRotateAxis(e),this.emit(`autorotate:change`,this.cameraTool.getAutoRotateState())}setAutoRotateDirection(e){this.cameraTool.setAutoRotateDirection(e),this.emit(`autorotate:change`,this.cameraTool.getAutoRotateState())}setAutoRotateSpeed(e){this.cameraTool.setAutoRotateSpeed(e),this.emit(`autorotate:change`,this.cameraTool.getAutoRotateState())}getAutoRotateState(){return this.cameraTool.getAutoRotateState()}setRotationLockedAxis(e){this.cameraTool.setLockedAxis(e),this.emit(`axislock:change`,e)}getRotationLockedAxis(){return this.cameraTool.getLockedAxis()}async exportImage(e={}){return this.screenshotTool.exportImage(e)}on(e,t){return super.on(e,t)}off(e,t){return super.off(e,t)}destroy(){this.clearModel(),this.measurementTool.destroy(),this.clippingTool.destroy(),this.sceneManager.destroy(),this.removeAllListeners()}};exports.BoundingBoxTool=E,exports.CameraTool=D,exports.ClippingTool=k,exports.EventEmitter=v,exports.MeasurementTool=A,exports.ModelLoader=b,exports.SceneManager=_,exports.ScreenshotTool=j,exports.Viewer=M,exports.ZipExtractor=y,exports.compute3DPolygonArea=w,exports.computeGroupVolume=S,exports.computeMeshVolume=x,exports.findSnapPoint=O,exports.formatUnit=T;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});var e=Object.create,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,i=Object.getPrototypeOf,a=Object.prototype.hasOwnProperty,o=(e,i,o,s)=>{if(i&&typeof i==`object`||typeof i==`function`)for(var c=r(i),l=0,u=c.length,d;l<u;l++)d=c[l],!a.call(e,d)&&d!==o&&t(e,d,{get:(e=>i[e]).bind(null,d),enumerable:!(s=n(i,d))||s.enumerable});return e},s=(n,r,s)=>(s=n==null?{}:e(i(n)),o(r||!n||!n.__esModule||!a.call(n,`default`)?t(s,`default`,{value:n,enumerable:!0}):s,n));let c=require("three");c=s(c,1);let l=require("three/addons/controls/OrbitControls.js"),u=require("three/addons/controls/TrackballControls.js"),d=require("three/addons/renderers/CSS2DRenderer.js"),f=require("@tweenjs/tween.js");f=s(f,1);let p=require("three/addons/loaders/OBJLoader.js"),m=require("three/addons/loaders/MTLLoader.js"),h=require("three/addons/loaders/GLTFLoader.js"),g=require("three/addons/loaders/DRACOLoader.js"),_=require("three/addons/loaders/KTX2Loader.js"),v=require("three/addons/libs/meshopt_decoder.module.js"),y=require("three-mesh-bvh"),b=require("jszip");b=s(b,1);var x=class{container;scene;camera;renderer;labelRenderer;controls;lightsGroup;gridHelper;tweenGroup;onBeforeRender;animationFrameId=null;resizeObserver=null;isDestroyed=!1;constructor(e){this.container=e.container,this.scene=new c.Scene,e.background!==void 0&&e.background!==null?(typeof e.background==`string`||typeof e.background==`number`)&&(this.scene.background=new c.Color(e.background)):this.scene.background=new c.Color(1580068);let t=this.container.clientWidth||800,n=this.container.clientHeight||600;if(this.camera=new c.PerspectiveCamera(e.cameraFov??45,t/n,e.cameraNear??.1,e.cameraFar??5e3),this.camera.position.set(10,10,10),this.renderer=new c.WebGLRenderer({antialias:e.antialias??!0,alpha:e.alpha??!1,preserveDrawingBuffer:!0,powerPreference:`high-performance`}),this.renderer.setSize(t,n),this.renderer.setPixelRatio(Math.min(window.devicePixelRatio,2)),this.renderer.localClippingEnabled=!0,this.renderer.toneMapping=c.ACESFilmicToneMapping,this.renderer.toneMappingExposure=1,this.renderer.outputColorSpace=c.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 d.CSS2DRenderer,this.labelRenderer.setSize(t,n),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),(e.controlsType??`trackball`)===`orbit`){let e=new l.OrbitControls(this.camera,this.renderer.domElement);e.enableDamping=!0,e.dampingFactor=.05,e.screenSpacePanning=!0,this.controls=e}else{let e=new u.TrackballControls(this.camera,this.renderer.domElement);e.rotateSpeed=2.5,e.zoomSpeed=1.2,e.panSpeed=.8,e.staticMoving=!1,e.dynamicDampingFactor=.15,this.controls=e}this.tweenGroup=new f.Group,this.lightsGroup=new c.Group,this.lightsGroup.name=`gmv-lights-group`,this.initLights(),this.scene.add(this.lightsGroup),this.gridHelper=new c.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)}initLights(){let e=new c.HemisphereLight(16777215,4674921,1);e.position.set(0,50,0),this.lightsGroup.add(e);let t=new c.AmbientLight(16777215,.8);this.lightsGroup.add(t);let n=new c.DirectionalLight(16777215,1.2);n.position.set(50,100,50),this.lightsGroup.add(n);let r=new c.DirectionalLight(16777215,.7);r.position.set(-50,50,-50),this.lightsGroup.add(r);let i=new c.DirectionalLight(16777215,.9);i.position.set(0,0,1),this.camera.add(i),this.scene.add(this.camera)}initResizeObserver(){this.resizeObserver=new ResizeObserver(()=>{this.handleResize()}),this.resizeObserver.observe(this.container)}handleResize(){if(this.isDestroyed||!this.container)return;let e=this.container.clientWidth,t=this.container.clientHeight;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())}startAnimationLoop(){let e=()=>{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))};this.animationFrameId=requestAnimationFrame(e)}setBackground(e,t){t||e==null?(this.scene.background=null,this.renderer.setClearAlpha(0)):(this.scene.background=new c.Color(e),this.renderer.setClearAlpha(1))}destroy(){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)}},S=class{events;constructor(){this.events=new Map}on(e,t){return this.events.has(e)||this.events.set(e,[]),this.events.get(e).push(t),this}off(e,t){let n=this.events.get(e);if(!n)return this;let r=n.indexOf(t);return r!==-1&&n.splice(r,1),this}emit(e,...t){let n=this.events.get(e);return!n||n.length===0?!1:([...n].forEach(n=>{try{n(...t)}catch(t){console.error(`Error in event listener for "${e}":`,t)}}),!0)}removeAllListeners(e){return e?this.events.delete(e):this.events.clear(),this}},C=class{static async extract(e,t){let n;if(t?.(5,`正在读取压缩包文件流...`),typeof e==`string`){let t=await fetch(e);if(!t.ok)throw Error(`Failed to fetch zip file: ${t.statusText}`);n=await t.arrayBuffer()}else n=e instanceof Blob||e instanceof File?await e.arrayBuffer():e;t?.(15,`正在解压 ZIP 文件包...`);let r=await b.default.loadAsync(n),i=new Map,a=null,o=null,s=null,l=null,u=[`.png`,`.jpg`,`.jpeg`,`.webp`,`.bmp`,`.tga`,`.dds`,`.hdr`,`.svg`,`.ktx2`],d=Object.keys(r.files),f=d.length||1;for(let e=0;e<d.length;e++){let n=d[e],c=r.files[n];if(c.dir||n.includes(`__MACOSX`)||n.split(`/`).pop()?.startsWith(`._`))continue;let p=n.toLowerCase(),m=n.split(`/`).pop()||n,h=Math.round(20+e/f*35);if(p.endsWith(`.glb`)&&!a?(a=c,t?.(h,`找到 GLB 二进制模型: ${m}`)):p.endsWith(`.gltf`)&&!o?(o=c,t?.(h,`找到 GLTF 场景定义: ${m}`)):p.endsWith(`.obj`)&&!s?(s=c,t?.(h,`找到 OBJ 网格模型: ${m}`)):p.endsWith(`.mtl`)&&!l&&(l=c,t?.(h,`找到 MTL 材质定义: ${m}`)),p.endsWith(`.bin`)){t?.(h,`加载二进制缓冲区: ${m}`);let e=await c.async(`blob`),r=URL.createObjectURL(e);i.set(n,r),i.set(m,r),i.set(m.toLowerCase(),r)}if(u.some(e=>p.endsWith(e))){t?.(h,`加载贴图资源: ${m}`);let e=await c.async(`blob`),r=URL.createObjectURL(e);i.set(n,r),i.set(m,r),i.set(m.toLowerCase(),r)}}t?.(60,`ZIP 资源索引提取完毕,准备解析三维模型网格...`);let p;if(a)p=`glb`;else if(o)p=`gltf`;else if(s)p=`obj`;else throw i.forEach(e=>URL.revokeObjectURL(e)),Error(`ZIP 压缩包中未检测到支持的 3D 模型文件(需要包含 .glb, .gltf 或 .obj 文件)`);let m,h,g=null,_=null,v,y;p===`glb`?(v=await a.async(`arraybuffer`),y=a.name):p===`gltf`?(v=await o.async(`string`),y=o.name):(m=await s.async(`string`),h=s.name,l&&(g=await l.async(`string`),_=l.name));let x=new c.LoadingManager;return x.setURLModifier(e=>{let t=decodeURIComponent(e).replace(/^\.\//,``),n=t.split(`/`).pop()?.split(`\\`).pop()||t;if(i.has(e))return i.get(e);if(i.has(t))return i.get(t);if(i.has(n))return i.get(n);let r=n.toLowerCase();for(let[e,t]of i.entries())if(e.toLowerCase()===r||e.toLowerCase().endsWith(`/`+r))return t;return e}),{format:p,objContent:m,objFileName:h,mtlContent:g,mtlFileName:_,gltfContent:v,gltfFileName:y,blobUrls:i,loadingManager:x,dispose:()=>{i.forEach(e=>{try{URL.revokeObjectURL(e)}catch{}}),i.clear()}}}};c.BufferGeometry.prototype.computeBoundsTree=y.computeBoundsTree,c.BufferGeometry.prototype.disposeBoundsTree=y.disposeBoundsTree,c.Mesh.prototype.raycast=y.acceleratedRaycast;var w=class{currentZipContent=null;customBlobUrls=[];managedMaterials=[];isTextureEnabled=!0;displayStyle=`solid`;plainColor=5016790;currentClippingPlanes=[];dracoDecoderPath=`https://www.gstatic.com/draco/versioned/decoders/1.5.7/`;dracoLoader=null;ktx2TranscoderPath=`https://cdn.jsdelivr.net/npm/three@0.186.1/examples/jsm/libs/basis/`;ktx2Loader=null;renderer=null;constructor(e,t){typeof e==`string`?(this.dracoDecoderPath=e,t&&(this.renderer=t)):typeof e==`object`&&e&&(e.dracoDecoderPath&&(this.dracoDecoderPath=e.dracoDecoderPath),e.ktx2TranscoderPath&&(this.ktx2TranscoderPath=e.ktx2TranscoderPath),this.renderer=e.renderer||t||null)}setRenderer(e){this.renderer=e,this.ktx2Loader&&this.ktx2Loader.detectSupport(e)}setDracoDecoderPath(e){this.dracoDecoderPath=e,this.dracoLoader&&this.dracoLoader.setDecoderPath(e)}setKTX2TranscoderPath(e){this.ktx2TranscoderPath=e,this.ktx2Loader&&this.ktx2Loader.setTranscoderPath(e)}getDracoLoader(){return this.dracoLoader||(this.dracoLoader=new g.DRACOLoader,this.dracoLoader.setDecoderPath(this.dracoDecoderPath)),this.dracoLoader}getKTX2Loader(){if(!this.ktx2Loader){if(this.ktx2Loader=new _.KTX2Loader,this.ktx2Loader.setTranscoderPath(this.ktx2TranscoderPath),this.renderer)this.ktx2Loader.detectSupport(this.renderer);else if(typeof document<`u`)try{let e=document.createElement(`canvas`),t=new c.WebGLRenderer({canvas:e});this.ktx2Loader.detectSupport(t),t.dispose()}catch(e){console.warn(`KTX2Loader: Failed to auto-detect WebGL compressed texture support`,e)}}return this.ktx2Loader}createGLTFLoader(e){let t=new h.GLTFLoader(e);return t.setDRACOLoader(this.getDracoLoader()),t.setKTX2Loader(this.getKTX2Loader()),t.setMeshoptDecoder(v.MeshoptDecoder),t}async loadZip(e,t){this.cleanup();let n=await C.extract(e,t);if(this.currentZipContent=n,n.format===`glb`||n.format===`gltf`){t?.(70,`正在解析 GLTF/GLB 网格结构与材质贴图...`);let e=this.createGLTFLoader(n.loadingManager),r=n.gltfContent,i=await new Promise((t,n)=>{e.parse(r,``,e=>t(e),e=>n(e))});t?.(88,`正在建立空间 BVH 加速结构与几何居中...`);let a=this.postProcessModel(i.scene,i.animations,n.format);return t?.(100,`加载完成`),a}let{objContent:r,mtlContent:i,loadingManager:a}=n;t?.(65,`正在解析材质与贴图数据...`);let o=null;i&&(o=new m.MTLLoader(a).parse(i,``),o.preload()),t?.(75,`正在解析 OBJ 网格几何数据...`);let s=new p.OBJLoader(a);o&&s.setMaterials(o);let c=typeof r==`string`?r:new TextDecoder().decode(r),l=s.parse(c);t?.(88,`正在建立空间 BVH 加速结构与几何居中...`);let u=this.postProcessModel(l,[],`obj`);return t?.(100,`加载完成`),u}async loadGLTF(e,t,n){this.cleanup();let r=this.createGLTFLoader(t),i,a=typeof e==`string`&&/\.glb(\?.*)?$/i.test(e);typeof e==`string`?(n?.(30,`正在请求 GLTF/GLB 模型数据...`),i=await r.loadAsync(e,e=>{if(e.lengthComputable&&e.total>0){let t=Math.round(30+e.loaded/e.total*50);n?.(t,`正在传输模型数据 (${Math.round(e.loaded/e.total*100)}%)...`)}})):(n?.(60,`正在解析 GLTF/GLB 二进制数据流...`),i=await new Promise((t,n)=>{r.parse(e,``,e=>t(e),e=>n(e))})),n?.(88,`正在建立空间 BVH 加速结构与几何居中...`);let o=this.postProcessModel(i.scene,i.animations,a?`glb`:`gltf`);return n?.(100,`加载完成`),o}async loadGLB(e,t){if(e instanceof Blob||e instanceof File){let n=await e.arrayBuffer();return this.loadGLTF(n,void 0,t)}return this.loadGLTF(e,void 0,t)}async loadOBJ(e,t,n,r){this.cleanup(),r?.(20,`正在加载材质定义...`);let i=null;t&&(i=await new m.MTLLoader(n).loadAsync(t),i.preload()),r?.(50,`正在加载 OBJ 模型几何数据...`);let a=new p.OBJLoader(n);i&&a.setMaterials(i);let o=await a.loadAsync(e,e=>{if(e.lengthComputable&&e.total>0){let t=Math.round(50+e.loaded/e.total*35);r?.(t,`正在传输模型数据 (${Math.round(e.loaded/e.total*100)}%)...`)}});r?.(88,`正在建立空间 BVH 加速结构与几何居中...`);let s=this.postProcessModel(o,[],`obj`);return r?.(100,`加载完成`),s}async loadFiles(e,t){let n=Array.from(e);if(n.length===0)throw Error(`未选择任何文件`);let r=n.find(e=>e.name.toLowerCase().endsWith(`.zip`));if(r)return this.loadZip(r,t);let i=n.find(e=>e.name.toLowerCase().endsWith(`.glb`));if(i)return this.loadGLB(i,t);let a=n.find(e=>e.name.toLowerCase().endsWith(`.gltf`));if(a){t?.(15,`正在建立 GLTF 关联资源映射表...`);let e=new Map;for(let t of n){let n=URL.createObjectURL(t);this.customBlobUrls.push(n),e.set(t.name,n),e.set(t.name.toLowerCase(),n)}let r=new c.LoadingManager;r.setURLModifier(t=>{let n=decodeURIComponent(t).replace(/^\.\//,``),r=n.split(`/`).pop()?.split(`\\`).pop()||n;if(e.has(t))return e.get(t);if(e.has(n))return e.get(n);if(e.has(r))return e.get(r);let i=r.toLowerCase();for(let[t,n]of e.entries())if(t.toLowerCase()===i||t.toLowerCase().endsWith(`/`+i))return n;return t});let i=await a.text();return this.loadGLTF(i,r,t)}let o=n.find(e=>e.name.toLowerCase().endsWith(`.obj`));if(o){let e=n.find(e=>e.name.toLowerCase().endsWith(`.mtl`)),r=new Map;for(let e of n){let t=URL.createObjectURL(e);this.customBlobUrls.push(t),r.set(e.name,t),r.set(e.name.toLowerCase(),t)}let i=new c.LoadingManager;i.setURLModifier(e=>{let t=decodeURIComponent(e).replace(/^\.\//,``),n=t.split(`/`).pop()?.split(`\\`).pop()||t;if(r.has(e))return r.get(e);if(r.has(t))return r.get(t);if(r.has(n))return r.get(n);let i=n.toLowerCase();for(let[e,t]of r.entries())if(e.toLowerCase()===i||e.toLowerCase().endsWith(`/`+i))return t;return e});let a=r.get(o.name),s=e?r.get(e.name):void 0;return this.loadOBJ(a,s,i,t)}throw Error(`未识别到支持的 3D 模型文件(请提供 .glb, .gltf, .obj 或 .zip 格式)`)}postProcessModel(e,t,n=`obj`){let r=0,i=0;this.managedMaterials=[];let a=(e,t=!0)=>{e&&(e.anisotropy=16,e.generateMipmaps=!0,e.minFilter=c.LinearMipmapLinearFilter,e.magFilter=c.LinearFilter,t&&!e.colorSpace&&(e.colorSpace=c.SRGBColorSpace),e.needsUpdate=!0)},o=e=>{if(e.side=c.DoubleSide,e.needsUpdate=!0,`color`in e){let t=e;a(t.map,!0),`emissiveMap`in t&&a(t.emissiveMap,!0),`normalMap`in t&&a(t.normalMap,!1),`bumpMap`in t&&a(t.bumpMap,!1),`roughnessMap`in t&&a(t.roughnessMap,!1),`metalnessMap`in t&&a(t.metalnessMap,!1),`aoMap`in t&&a(t.aoMap,!1),n===`obj`&&!t.map&&t.color&&t.color.getHex()<2236962&&t.color.setHex(11581636)}};e.updateMatrixWorld(!0);let s=new c.Box3().setFromObject(e),l=new c.Vector3,u=new c.Vector3;s.getCenter(l),s.getSize(u),e.traverse(e=>{if(e.isMesh){let t=e;t.castShadow=!0,t.receiveShadow=!0,t.material?Array.isArray(t.material)?t.material.forEach(o):o(t.material):t.material=new c.MeshStandardMaterial({color:this.plainColor,roughness:.45,metalness:.12,side:c.DoubleSide});let n=t.geometry;if(n){n.attributes.normal||n.computeVertexNormals(),n.computeBoundsTree&&n.computeBoundsTree(),n.attributes.position&&(r+=n.attributes.position.count),n.index?i+=n.index.count/3:n.attributes.position&&(i+=n.attributes.position.count/3);let e=new c.MeshStandardMaterial({color:this.plainColor,roughness:.45,metalness:.12,side:c.DoubleSide,clippingPlanes:this.currentClippingPlanes.length>0?this.currentClippingPlanes:null,clipShadows:!0}),a={mesh:t,originalMaterial:t.material,plainMaterial:e};this.applyStyleToItem(a),this.managedMaterials.push(a)}}});let d=new c.Group;return d.name=`gmv-model-root`,e.position.set(-l.x,-l.y,-l.z),d.add(e),d.updateMatrixWorld(!0),{model:d,box:new c.Box3().setFromObject(d),size:u,center:l,vertexCount:r,faceCount:Math.round(i),animations:t||[],format:n}}applyStyleToItem(e){let t=this.isTextureEnabled?e.originalMaterial:e.plainMaterial;e.mesh.material=t;let n=e=>{e.visible=!0,`wireframe`in e&&(e.wireframe=this.displayStyle===`wireframe`),e.needsUpdate=!0};Array.isArray(t)?t.forEach(n):n(t)}setDisplayStyle(e){this.displayStyle=e;for(let e of this.managedMaterials)this.applyStyleToItem(e)}getDisplayStyle(){return this.displayStyle}toggleTexture(e){this.isTextureEnabled=e;for(let e of this.managedMaterials)this.applyStyleToItem(e)}getTextureState(){return this.isTextureEnabled}setPlainColor(e){this.plainColor=typeof e==`string`?new c.Color(e).getHex():Number(e);for(let e of this.managedMaterials)e.plainMaterial&&`color`in e.plainMaterial&&(e.plainMaterial.color.set(this.plainColor),e.plainMaterial.needsUpdate=!0)}getPlainColor(){return this.plainColor}getModelTextureSize(){let e=0,t=0,n=n=>{if(`map`in n&&n.map){let r=n.map;if(r){let n=r.image||r.source?.data;if(n){let r=n.width||0,i=n.height||0;r>0&&i>0&&r*i>e*t&&(e=r,t=i)}}}};for(let e of this.managedMaterials)Array.isArray(e.originalMaterial)?e.originalMaterial.forEach(n):e.originalMaterial&&n(e.originalMaterial);return e>0&&t>0?{width:e,height:t}:null}getMeshes(){return this.managedMaterials.map(e=>e.mesh)}applyClippingPlanes(e){this.currentClippingPlanes=e;for(let t of this.managedMaterials){let n=t=>{t.clippingPlanes=e.length>0?e:null,t.clipShadows=!0,t.needsUpdate=!0};Array.isArray(t.originalMaterial)?t.originalMaterial.forEach(n):n(t.originalMaterial),n(t.plainMaterial)}}cleanup(){this.currentZipContent&&=(this.currentZipContent.dispose(),null),this.customBlobUrls.length>0&&(this.customBlobUrls.forEach(e=>{try{URL.revokeObjectURL(e)}catch{}}),this.customBlobUrls=[]);for(let e of this.managedMaterials)e.plainMaterial&&e.plainMaterial.dispose(),e.mesh.geometry&&e.mesh.geometry.disposeBoundsTree&&e.mesh.geometry.disposeBoundsTree();this.managedMaterials=[]}destroy(){this.cleanup(),this.dracoLoader&&=(this.dracoLoader.dispose(),null),this.ktx2Loader&&=(this.ktx2Loader.dispose(),null)}};function T(e){let t=e.geometry;if(!t)return 0;let n=t.attributes.position;if(!n)return 0;let r=0,i=new c.Vector3,a=new c.Vector3,o=new c.Vector3;e.updateMatrixWorld(!0);let s=e.matrixWorld;if(t.index){let e=t.index;for(let t=0;t<e.count;t+=3){let c=e.getX(t),l=e.getX(t+1),u=e.getX(t+2);i.fromBufferAttribute(n,c).applyMatrix4(s),a.fromBufferAttribute(n,l).applyMatrix4(s),o.fromBufferAttribute(n,u).applyMatrix4(s),r+=D(i,a,o)}}else for(let e=0;e<n.count;e+=3)i.fromBufferAttribute(n,e).applyMatrix4(s),a.fromBufferAttribute(n,e+1).applyMatrix4(s),o.fromBufferAttribute(n,e+2).applyMatrix4(s),r+=D(i,a,o);return Math.abs(r)}function E(e){let t=0;e.traverse(e=>{e.isMesh&&(t+=T(e))});let n=new c.Box3().setFromObject(e),r=new c.Vector3;n.getSize(r);let i=r.x*r.y*r.z;return{meshVolume:t,bboxVolume:i}}function D(e,t,n){return e.dot(t.clone().cross(n))/6}function O(e){let t=e.length;if(t<3)return 0;let n=new c.Vector3(0,0,0);for(let r=0;r<t;r++){let i=e[r],a=e[(r+1)%t];n.x+=(i.y-a.y)*(i.z+a.z),n.y+=(i.z-a.z)*(i.x+a.x),n.z+=(i.x-a.x)*(i.y+a.y)}return n.length()*.5}function k(e,t=`m`,n=2){return Math.abs(e)<.001?`0.00 ${t}`:`${e.toFixed(n)} ${t}`}var A=class{scene;boxGroup;wireframeBox=null;lineX=null;lineY=null;lineZ=null;labelX=null;labelY=null;labelZ=null;currentModel=null;isVisible=!1;unit=`m`;localVertices=[];worldVertices=[new c.Vector3,new c.Vector3,new c.Vector3,new c.Vector3,new c.Vector3,new c.Vector3,new c.Vector3,new c.Vector3];modelSize=new c.Vector3;constructor(e){this.scene=e,this.boxGroup=new c.Group,this.boxGroup.name=`gmv-bounding-box-group`,this.scene.add(this.boxGroup)}attachToModel(e,t){this.detach(),this.currentModel=e,this.unit=t?.unit||`m`,e.updateMatrixWorld(!0);let n=new c.Box3,r=e.matrixWorld.clone().invert();e.traverse(e=>{if(e.isMesh){let t=e;if(t.geometry&&(t.geometry.boundingBox||t.geometry.computeBoundingBox(),t.geometry.boundingBox)){let e=t.matrixWorld.clone().premultiply(r),i=t.geometry.boundingBox.clone().applyMatrix4(e);n.union(i)}}}),n.isEmpty()&&n.setFromObject(e);let i=n.min,a=n.max;n.getSize(this.modelSize),this.localVertices=[new c.Vector3(i.x,i.y,i.z),new c.Vector3(a.x,i.y,i.z),new c.Vector3(i.x,a.y,i.z),new c.Vector3(a.x,a.y,i.z),new c.Vector3(i.x,i.y,a.z),new c.Vector3(a.x,i.y,a.z),new c.Vector3(i.x,a.y,a.z),new c.Vector3(a.x,a.y,a.z)];let o=[0,1,2,3,4,5,6,7,0,2,1,3,4,6,5,7,0,4,1,5,2,6,3,7],s=new c.BufferGeometry,l=new Float32Array(o.length*3);s.setAttribute(`position`,new c.BufferAttribute(l,3));let u=new c.LineBasicMaterial({color:t?.color?new c.Color(t.color):54015,linewidth:1,transparent:!0,opacity:.6,depthTest:!0});this.wireframeBox=new c.LineSegments(s,u),this.boxGroup.add(this.wireframeBox),this.lineX=this.createDynamicLine(15680580),this.lineY=this.createDynamicLine(1096065),this.lineZ=this.createDynamicLine(3900150);let f=document.createElement(`div`);f.className=`gmv-dimension-badge dim-x`,f.innerHTML=`<span>长 (X):</span> <strong>${k(this.modelSize.x,this.unit)}</strong>`,this.labelX=new d.CSS2DObject(f),this.boxGroup.add(this.labelX);let p=document.createElement(`div`);p.className=`gmv-dimension-badge dim-y`,p.innerHTML=`<span>高 (Y):</span> <strong>${k(this.modelSize.y,this.unit)}</strong>`,this.labelY=new d.CSS2DObject(p),this.boxGroup.add(this.labelY);let m=document.createElement(`div`);m.className=`gmv-dimension-badge dim-z`,m.innerHTML=`<span>宽 (Z):</span> <strong>${k(this.modelSize.z,this.unit)}</strong>`,this.labelZ=new d.CSS2DObject(m),this.boxGroup.add(this.labelZ),this.setVisible(t?.visible??!1)}createDynamicLine(e){let t=new c.BufferGeometry().setFromPoints([new c.Vector3,new c.Vector3]),n=new c.LineBasicMaterial({color:e,linewidth:3,depthTest:!1}),r=new c.Line(t,n);return this.boxGroup.add(r),r}update(e){if(!this.isVisible||!this.currentModel||this.localVertices.length<8)return;this.currentModel.updateMatrixWorld(!0);let t=this.currentModel.matrixWorld;for(let e=0;e<8;e++)this.worldVertices[e].copy(this.localVertices[e]).applyMatrix4(t);if(this.wireframeBox){let e=[0,1,2,3,4,5,6,7,0,2,1,3,4,6,5,7,0,4,1,5,2,6,3,7],t=this.wireframeBox.geometry.attributes.position,n=0;for(let r of e){let e=this.worldVertices[r];t.setXYZ(n++,e.x,e.y,e.z)}t.needsUpdate=!0}let n=0,r=1/0,i=e.position;for(let e=0;e<8;e++){let t=this.worldVertices[e].distanceTo(i);t<r&&(r=t,n=e)}let a=this.worldVertices[n],o=this.worldVertices[n^1],s=this.worldVertices[n^2],c=this.worldVertices[n^4];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)}updateLine(e,t,n){if(!e)return;let r=e.geometry.attributes.position;r.setXYZ(0,t.x,t.y,t.z),r.setXYZ(1,n.x,n.y,n.z),r.needsUpdate=!0}setVisible(e){this.isVisible=e,this.boxGroup.visible=e}getVisible(){return this.isVisible}setUnit(e){this.unit=e,this.currentModel&&this.attachToModel(this.currentModel,{visible:this.isVisible,unit:e})}detach(){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}destroy(){this.detach(),this.scene.remove(this.boxGroup)}},j=class{camera;controls;tweenGroup;currentTween=null;isAutoRotating=!1;autoRotateAxis=`x`;autoRotateDirection=`clockwise`;autoRotateSpeed=1;lockedAxis=null;lockedPitchAngle=0;lockedYawAngle=0;constructor(e,t,n){this.camera=e,this.controls=t,this.tweenGroup=n||new f.Group}setAutoRotate(e,t,n,r){this.isAutoRotating=e,t!==void 0&&(this.autoRotateAxis=t),n!==void 0&&(this.autoRotateDirection=n),r!==void 0&&(this.autoRotateSpeed=r)}toggleAutoRotate(){return this.isAutoRotating=!this.isAutoRotating,this.isAutoRotating}setAutoRotateAxis(e){this.autoRotateAxis=e}setAutoRotateDirection(e){this.autoRotateDirection=e}setAutoRotateSpeed(e){this.autoRotateSpeed=Math.max(.1,Math.min(10,e))}getAutoRotateState(){return{enabled:this.isAutoRotating,axis:this.autoRotateAxis,direction:this.autoRotateDirection,speed:this.autoRotateSpeed}}setLockedAxis(e){this.lockedAxis=e;let t=this.camera.position.clone().sub(this.controls.target),n=t.length();n>1e-4&&(this.lockedPitchAngle=Math.asin(Math.max(-1,Math.min(1,t.y/n))),this.lockedYawAngle=Math.atan2(t.z,t.x))}getLockedAxis(){return this.lockedAxis}updatePerFrame(){let e=this.controls.target,t=this.camera.position.clone().sub(e),n=t.length();if(this.isAutoRotating&&n>.001){let n=this.autoRotateDirection===`clockwise`?1:-1,r=.008*this.autoRotateSpeed*n;if(this.autoRotateAxis===`x`){let e=new c.Vector3(1,0,0);t.applyAxisAngle(e,r),this.camera.up.applyAxisAngle(e,r)}else{let e=new c.Vector3(0,1,0);t.applyAxisAngle(e,r),this.camera.up.applyAxisAngle(e,r)}this.camera.position.copy(e).add(t),this.camera.lookAt(e)}if(this.lockedAxis&&n>.001){let t=this.camera.position.clone().sub(e),n=t.length();if(this.lockedAxis===`x`){let r=n*Math.cos(this.lockedPitchAngle),i=n*Math.sin(this.lockedPitchAngle),a=Math.atan2(t.z,t.x);t.x=r*Math.cos(a),t.y=i,t.z=r*Math.sin(a),this.camera.position.copy(e).add(t)}else if(this.lockedAxis===`y`){let r=t.y,i=Math.sqrt(Math.max(0,n*n-r*r));t.x=i*Math.cos(this.lockedYawAngle),t.z=i*Math.sin(this.lockedYawAngle),this.camera.position.copy(e).add(t)}else this.lockedAxis===`z`&&this.camera.up.set(0,1,0);this.camera.lookAt(e)}}setView(e,t,n=600){return new Promise(r=>{let i=new c.Box3().setFromObject(t),a=new c.Sphere;i.getBoundingSphere(a);let o=a.center.clone(),s=Math.max(a.radius,1);this.camera.near=Math.max(.01,s/500),this.camera.far=Math.max(1e4,s*50),this.camera.updateProjectionMatrix();let l=this.camera.fov*Math.PI/180,u=s/Math.sin(l/2)*1.15,d=new c.Vector3,p=new c.Vector3(0,1,0);switch(e){case`front`:d.set(0,0,1);break;case`back`:d.set(0,0,-1);break;case`left`:d.set(-1,0,0);break;case`right`:d.set(1,0,0);break;case`top`:d.set(0,1,1e-4),p.set(0,0,-1);break;case`bottom`:d.set(0,-1,1e-4),p.set(0,0,1);break;case`isometric`:d.set(1,1,1).normalize();break;case`isometric-back`:d.set(-1,1,-1).normalize()}let m=o.clone().add(d.multiplyScalar(u));if(this.currentTween&&=(this.currentTween.stop(),null),this.camera.up.copy(p),n<=0){this.camera.position.copy(m),this.controls.target.copy(o),this.controls.update(),r();return}let h=this.camera.position.clone(),g=this.controls.target.clone(),_={t:0};this.currentTween=new f.Tween(_,this.tweenGroup).to({t:1},n).easing(f.Easing.Cubic.Out).onUpdate(()=>{this.camera.position.lerpVectors(h,m,_.t),this.controls.target.lerpVectors(g,o,_.t),this.controls.update()}).onComplete(()=>{this.camera.position.copy(m),this.controls.target.copy(o),this.controls.update(),this.currentTween=null,r()}).start()})}fitToObject(e,t=500){return new Promise(n=>{let r=new c.Box3().setFromObject(e),i=new c.Sphere;r.getBoundingSphere(i);let a=i.center,o=Math.max(i.radius,1);this.camera.near=Math.max(.01,o/500),this.camera.far=Math.max(1e4,o*50),this.camera.updateProjectionMatrix();let s=this.camera.fov*Math.PI/180,l=o/Math.sin(s/2)*1.15,u=this.camera.position.clone().sub(this.controls.target).normalize(),d=a.clone().add(u.multiplyScalar(l)),p=this.camera.position.clone(),m=this.controls.target.clone(),h={t:0};new f.Tween(h,this.tweenGroup).to({t:1},t).easing(f.Easing.Cubic.Out).onUpdate(()=>{this.camera.position.lerpVectors(p,d,h.t),this.controls.target.lerpVectors(m,a,h.t),this.controls.update()}).onComplete(()=>{this.camera.position.copy(d),this.controls.target.copy(a),this.controls.update(),n()}).start()})}};function M(e,t,n,r=15,i=800,a=600){if(!n||n.length===0)return{hit:!1,point:null,normal:null,isVertexSnapped:!1,distanceToVertex:1/0};let o=new c.Raycaster;o.setFromCamera(e,t),o.firstHitOnly=!0;let s=o.intersectObjects(n,!0);if(s.length===0)return{hit:!1,point:null,normal:null,isVertexSnapped:!1,distanceToVertex:1/0};let l=s[0],u=l.point.clone(),d=l.face?l.face.normal.clone():new c.Vector3(0,1,0);l.object&&d.transformDirection(l.object.matrixWorld);let f=null,p=r;if(l.face&&l.object&&l.object.geometry){let n=l.object,r=n.geometry.attributes.position;if(r){let o=[l.face.a,l.face.b,l.face.c],s=new c.Vector3,u=new c.Vector3;for(let c of o){s.fromBufferAttribute(r,c).applyMatrix4(n.matrixWorld),u.copy(s).project(t);let o=(u.x+1)*.5*i,l=(-u.y+1)*.5*a,d=(e.x+1)*.5*i,m=(-e.y+1)*.5*a,h=Math.hypot(o-d,l-m);h<p&&(p=h,f=s.clone())}}}return f?{hit:!0,point:f,normal:d,isVertexSnapped:!0,distanceToVertex:p}:{hit:!0,point:u,normal:d,isVertexSnapped:!1,distanceToVertex:1/0}}var N=class{scene;camera;container;modelLoader;controls=null;emitter=null;planeX;planeY;planeZ;customPlane=null;isEnabled=!1;activeAxis=`x`;helperVisible=!0;planesGroup;interactive=!1;widgets={};isDraggingPlane=!1;draggedWidget=null;dragStartPointer=new c.Vector2;dragStartPosition=0;dragScreenAxis=new c.Vector2;dragScreenAxisLenSq=0;raycaster=new c.Raycaster;hoveredAxis=null;isPickingCustomPoints=!1;customPoints=[];customMarkersGroup;modelBox=new c.Box3;onPointerDownBound;onPointerMoveBound;onPointerMoveDragBound;onPointerUpDragBound;onDoubleClickBound;constructor(e,t,n,r,i,a){this.scene=e,this.camera=t,this.container=n,this.modelLoader=r,this.controls=i||null,this.emitter=a||null,this.planeX=new c.Plane(new c.Vector3(-1,0,0),1e5),this.planeY=new c.Plane(new c.Vector3(0,-1,0),1e5),this.planeZ=new c.Plane(new c.Vector3(0,0,-1),1e5),this.planesGroup=new c.Group,this.planesGroup.name=`gmv-interactive-clipping-planes`,this.planesGroup.visible=!1,this.scene.add(this.planesGroup),this.customMarkersGroup=new c.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})}setControls(e){this.controls=e}setEmitter(e){this.emitter=e}setInteractive(e){this.interactive=e&&this.isEnabled,!this.interactive&&this.container.style.cursor===`grab`&&(this.container.style.cursor=`default`)}setModelBounds(e){this.modelBox.copy(e),this.rebuildPlaneWidgets(),this.resetAll()}rebuildPlaneWidgets(){this.clearPlaneWidgets();let e=new c.Vector3(2,2,2),t=new c.Vector3(0,0,0);this.modelBox.isEmpty()||(this.modelBox.getSize(e),this.modelBox.getCenter(t));let n=Math.max(.001,e.x),r=Math.max(.001,e.y),i=Math.max(.001,e.z);this.widgets.x=this.createPlaneWidget(`x`,15680580,16281969,i,r,t),this.widgets.y=this.createPlaneWidget(`y`,1096065,3462041,n,i,t),this.widgets.z=this.createPlaneWidget(`z`,3900150,6333946,n,r,t),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()}createPlaneWidget(e,t,n,r,i,a){let o=new c.Group;o.name=`gmv-clip-plane-${e}`;let s=new c.PlaneGeometry(r,i),l=new c.MeshBasicMaterial({color:t,transparent:!0,opacity:.25,side:c.DoubleSide,depthWrite:!1}),u=new c.Mesh(s,l);u.userData={axis:e},u.renderOrder=999,o.add(u);let f=new c.EdgesGeometry(s),p=new c.LineBasicMaterial({color:n,transparent:!0,opacity:.85}),m=new c.LineSegments(f,p);o.add(m);let h=new c.Group,g=Math.min(r,i)*.045,_=new c.MeshBasicMaterial({color:n,transparent:!0,opacity:.9,depthTest:!1}),v=new c.SphereGeometry(g*.5,16,16),y=new c.Mesh(v,_);y.userData={axis:e},h.add(y);let b=new c.CylinderGeometry(g*.12,g*.12,g*1.8,12);b.rotateX(Math.PI/2);let x=new c.Mesh(b,_);x.userData={axis:e},h.add(x);let S=new c.ConeGeometry(g*.35,g*.65,16);S.rotateX(Math.PI/2),S.translate(0,0,g*1.1);let C=new c.Mesh(S,_);C.userData={axis:e},h.add(C);let w=new c.ConeGeometry(g*.35,g*.65,16);w.rotateX(-Math.PI/2),w.translate(0,0,-g*1.1);let T=new c.Mesh(w,_);T.userData={axis:e},h.add(T),h.renderOrder=1e3,o.add(h);let E=[u,y,x,C,T],D=document.createElement(`div`);D.className=`gmv-plane-badge gmv-plane-badge-${e}`,D.textContent=`${e.toUpperCase()} 剖切面`;let O=new d.CSS2DObject(D);O.position.set(r/2*.68,i/2*.68,0),o.add(O);let k=new c.Vector3(1,0,0);return e===`x`?(o.rotation.y=Math.PI/2,o.position.set(a.x,a.y,a.z),k=new c.Vector3(1,0,0)):e===`y`?(o.rotation.x=-Math.PI/2,o.position.set(a.x,a.y,a.z),k=new c.Vector3(0,1,0)):(o.rotation.set(0,0,0),o.position.set(a.x,a.y,a.z),k=new c.Vector3(0,0,1)),this.planesGroup.add(o),{axis:e,group:o,mesh:u,border:m,arrowGroup:h,hitMeshes:E,label:O,labelText:D,meshMat:l,borderMat:p,arrowMat:_,normal:k,baseColor:t,borderColor:n,position:a[e],inverted:!1,enabled:!1}}clearPlaneWidgets(){[`x`,`y`,`z`].forEach(e=>{let t=this.widgets[e];t&&(t.mesh.geometry.dispose(),t.meshMat.dispose(),t.border.geometry.dispose(),t.borderMat.dispose(),t.arrowMat.dispose(),this.planesGroup.remove(t.group))}),this.widgets={}}updateWidgetsVisibility(){this.planesGroup.visible=this.isEnabled&&this.helperVisible,this.interactive=this.isEnabled,[`x`,`y`,`z`].forEach(e=>{let t=this.widgets[e];t&&(t.group.visible=this.isEnabled&&this.helperVisible&&t.enabled)})}setSectioningEnabled(e){if(this.isEnabled=e,this.updateWidgetsVisibility(),e){if(![`x`,`y`,`z`].some(e=>this.widgets[e]?.enabled)){let e=this.widgets[this.activeAxis]||this.widgets.x;e&&(e.enabled=!0)}[`x`,`y`,`z`].forEach(e=>{let t=this.widgets[e];t&&t.enabled?this.setPlanePositionExplicit(e,t.position):this.disableAxisInternal(e)})}else this.disableAllAxesPlanes();this.applyPlanes(),this.emitSectioningState()}getSectioningEnabled(){return this.isEnabled}setAxisEnabled(e,t){let n=this.widgets[e];n&&(n.enabled=t,t?(this.activeAxis=e,this.isEnabled&&this.setPlanePositionExplicit(e,n.position)):this.disableAxisInternal(e),this.updateWidgetsVisibility(),this.applyPlanes(),this.emitSectioningState())}toggleAxis(e,t){let n=this.widgets[e],r=t===void 0?!n?.enabled:t;return this.setAxisEnabled(e,r),r}isAxisEnabled(e){return!!this.widgets[e]?.enabled}setSectioningAxis(e){this.activeAxis=e;let t=this.widgets[e];t&&!t.enabled&&(t.enabled=!0,this.isEnabled&&this.setPlanePositionExplicit(e,t.position)),this.updateWidgetsVisibility(),this.emitSectioningState()}getSectioningAxis(){return this.activeAxis}setSectioningHelperVisible(e){this.helperVisible=e,this.updateWidgetsVisibility(),this.emitSectioningState()}getSectioningHelperVisible(){return this.helperVisible}setAxisReverse(e,t){let n=this.widgets[e];if(n){if(n.inverted=t,this.isEnabled&&n.enabled)this.setPlanePositionExplicit(e,n.position);else{let r=this.modelBox.min[e],i=this.modelBox.max[e]-r,a=i>0?(n.position-r)/i:.5;n.labelText.textContent=`${e.toUpperCase()} 剖切面 ${(a*100).toFixed(0)}%${t?` (反向)`:``}`}}this.emitSectioningState()}setSectioningReverse(e){this.setAxisReverse(this.activeAxis,e)}getSectioningReverse(){return!!this.widgets[this.activeAxis]?.inverted}invertAxis(e){let t=this.widgets[e];return t?(this.setAxisReverse(e,!t.inverted),t.inverted):!1}resetSectioning(e){let t=new c.Vector3,n=this.modelBox.isEmpty();n?t.set(0,0,0):this.modelBox.getCenter(t),this.clearCustomPlane(),(e?[e]:[`x`,`y`,`z`]).forEach(r=>{let i=this.widgets[r];if(i){i.position=t[r],i.inverted=!1,i.group.position.set(t.x,t.y,t.z),e||(i.enabled=r===`x`);let a=n?-1:this.modelBox.min[r],o=(n?1:this.modelBox.max[r])-a,s=o>0&&!isNaN(i.position)?Math.max(0,Math.min(1,(i.position-a)/o)):.5;i.labelText.textContent=`${r.toUpperCase()} 剖切面 ${(s*100).toFixed(0)}%`}}),this.activeAxis=e||`x`,this.helperVisible=!0,this.isEnabled=!0,[`x`,`y`,`z`].forEach(e=>{let t=this.widgets[e];t&&t.enabled?this.setPlanePositionExplicit(e,t.position):this.disableAxisInternal(e)}),this.updateWidgetsVisibility(),this.applyPlanes(),this.emitSectioningState()}getSectioningState(){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)=>{let r=n-t;return isNaN(e)||r<=0?.5:Math.max(0,Math.min(1,(e-t)/r))},c=this.widgets.x,l=this.widgets.y,u=this.widgets.z,d={x:{enabled:c?.enabled??!1,inverted:c?.inverted??!1,position:c?.position??0,progress:s(c?.position??0,t,n)},y:{enabled:l?.enabled??!1,inverted:l?.inverted??!1,position:l?.position??0,progress:s(l?.position??0,r,i)},z:{enabled:u?.enabled??!1,inverted:u?.inverted??!1,position:u?.position??0,progress:s(u?.position??0,a,o)}},f=this.widgets[this.activeAxis],p=d[this.activeAxis]?.progress??.5,m=f?.position??0,h=f?.inverted??!1;return{enabled:this.isEnabled,axes:d,helperVisible:this.helperVisible,axis:this.activeAxis,isReverse:h,progress:p,position:m}}emitSectioningState(){this.emitter&&this.emitter.emit(`sectioning:change`,this.getSectioningState())}handlePointerDown(e){if(e.button!==0)return;if(this.isPickingCustomPoints){this.handleCustomPointPick(e),e.stopImmediatePropagation(),e.preventDefault();return}if(!this.interactive||!this.isEnabled||!this.helperVisible)return;let t=this.container.getBoundingClientRect(),n=new c.Vector2((e.clientX-t.left)/t.width*2-1,-((e.clientY-t.top)/t.height)*2+1);this.raycaster.setFromCamera(n,this.camera);let r=[`x`,`y`,`z`].map(e=>this.widgets[e]).filter(e=>!!(e&&e.enabled&&e.group.visible));if(r.length===0)return;let i=null;for(let e of r){let t=this.raycaster.intersectObjects(e.hitMeshes,!0);if(t.length>0){let n=t[0].distance;(!i||n<i.distance)&&(i={widget:e,distance:n})}}if(i){e.stopImmediatePropagation(),e.preventDefault();let n=i.widget;this.activeAxis=n.axis,this.isDraggingPlane=!0,this.draggedWidget=n,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`,n.meshMat.opacity=.65,n.arrowMat.opacity=1,this.dragStartPointer.set(e.clientX,e.clientY),this.dragStartPosition=n.position;let r=new c.Vector3;n.axis===`x`?r.set(1,0,0):n.axis===`y`?r.set(0,1,0):r.set(0,0,1);let a=n.group.position.clone(),o=n.group.position.clone().add(r),s=a.project(this.camera),l=new c.Vector2((s.x+1)*t.width/2,(-s.y+1)*t.height/2),u=o.project(this.camera),d=new c.Vector2((u.x+1)*t.width/2,(-u.y+1)*t.height/2);this.dragScreenAxis.subVectors(d,l),this.dragScreenAxisLenSq=this.dragScreenAxis.lengthSq(),window.addEventListener(`pointermove`,this.onPointerMoveDragBound,{capture:!0}),window.addEventListener(`pointerup`,this.onPointerUpDragBound,{capture:!0})}}handlePointerMoveDrag(e){if(!this.isDraggingPlane||!this.draggedWidget)return;e.stopImmediatePropagation(),e.preventDefault();let t=new c.Vector2(e.clientX-this.dragStartPointer.x,e.clientY-this.dragStartPointer.y),n=0;if(this.dragScreenAxisLenSq>25)n=this.dragScreenAxis.dot(t)/this.dragScreenAxisLenSq;else{let e=new c.Vector3;this.modelBox.getSize(e);let r=Math.max(.1,e[this.draggedWidget.axis]);n=-t.y/280*r}let r=this.modelBox.min[this.draggedWidget.axis],i=this.modelBox.max[this.draggedWidget.axis],a=this.dragStartPosition+n;a=Math.max(r,Math.min(i,a)),this.setPlanePositionExplicit(this.draggedWidget.axis,a)}handlePointerUpDrag(e){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(()=>{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)}))}handlePointerMove(e){if(this.isDraggingPlane||this.isPickingCustomPoints||!this.interactive||!this.isEnabled||!this.helperVisible)return;let t=this.container.getBoundingClientRect(),n=new c.Vector2((e.clientX-t.left)/t.width*2-1,-((e.clientY-t.top)/t.height)*2+1);this.raycaster.setFromCamera(n,this.camera);let r=[`x`,`y`,`z`].map(e=>this.widgets[e]).filter(e=>!!(e&&e.enabled&&e.group.visible)),i=null;for(let e of r)if(this.raycaster.intersectObjects(e.hitMeshes,!0).length>0){i=e.axis;break}this.setHoveredAxis(i),i?this.container.style.cursor=`grab`:this.container.style.cursor===`grab`&&(this.container.style.cursor=`default`)}setHoveredAxis(e){this.hoveredAxis!==e&&(this.hoveredAxis=e,[`x`,`y`,`z`].forEach(t=>{let n=this.widgets[t];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))}))}handleDoubleClick(e){if(!this.interactive||!this.isEnabled||!this.helperVisible)return;let t=this.container.getBoundingClientRect(),n=new c.Vector2((e.clientX-t.left)/t.width*2-1,-((e.clientY-t.top)/t.height)*2+1);this.raycaster.setFromCamera(n,this.camera);let r=[`x`,`y`,`z`].map(e=>this.widgets[e]).filter(e=>!!(e&&e.enabled&&e.group.visible));for(let t of r)if(this.raycaster.intersectObjects(t.hitMeshes,!0).length>0){e.stopImmediatePropagation(),e.preventDefault(),this.invertAxis(t.axis);break}}setPlanePositionExplicit(e,t){let n=this.widgets[e];if(!n)return;n.position=t,e===`x`?(n.group.position.x=t,n.inverted?this.planeX.set(new c.Vector3(1,0,0),-t):this.planeX.set(new c.Vector3(-1,0,0),t)):e===`y`?(n.group.position.y=t,n.inverted?this.planeY.set(new c.Vector3(0,1,0),-t):this.planeY.set(new c.Vector3(0,-1,0),t)):e===`z`&&(n.group.position.z=t,n.inverted?this.planeZ.set(new c.Vector3(0,0,1),-t):this.planeZ.set(new c.Vector3(0,0,-1),t)),n.enabled=!0,this.applyPlanes();let r=this.modelBox.min[e],i=this.modelBox.max[e]-r,a=i>0?(t-r)/i:.5;n.labelText.textContent=`${e.toUpperCase()} 剖切面 ${(a*100).toFixed(0)}%${n.inverted?` (反向)`:``}`,this.emitSectioningState(),this.emitter&&this.emitter.emit(`clipping:change`,{axis:e,position:t,progress:a,inverted:n.inverted,enabled:!0})}setAxisProgress(e,t){let n=this.modelBox.min[e],r=this.modelBox.max[e],i=n+Math.max(0,Math.min(1,t))*(r-n);this.setPlanePositionExplicit(e,i)}getAxisProgress(e){let t=this.widgets[e];if(!t)return .5;let n=this.modelBox.min[e],r=this.modelBox.max[e]-n;return r>0?Math.max(0,Math.min(1,(t.position-n)/r)):.5}disableAxisInternal(e){e===`x`?this.planeX.set(new c.Vector3(-1,0,0),1e5):e===`y`?this.planeY.set(new c.Vector3(0,-1,0),1e5):e===`z`&&this.planeZ.set(new c.Vector3(0,0,-1),1e5)}disableAllAxesPlanes(){[`x`,`y`,`z`].forEach(e=>{this.disableAxisInternal(e)})}setAxisClipping(e,t,n=!1){this.activeAxis=e;let r=this.widgets[e];r&&(r.inverted=n,r.enabled=!0),this.setSectioningEnabled(!0),this.setAxisProgress(e,t)}disableAxis(e){this.setAxisEnabled(e,!1)}getAxisState(e){let t=this.widgets[e];if(!t)return{enabled:!1,progress:.5,inverted:!1,position:0};let n=this.modelBox.min[e],r=this.modelBox.max[e]-n,i=r>0?(t.position-n)/r:.5;return{enabled:this.isEnabled&&t.enabled,progress:i,inverted:t.inverted,position:t.position}}setPlanesVisible(e){this.setSectioningHelperVisible(e)}getPlanesVisible(){return this.helperVisible}startCustomClip(){this.cancelCustomClip(),this.isPickingCustomPoints=!0,this.customPoints=[],this.container.style.cursor=`crosshair`}cancelCustomClip(){this.isPickingCustomPoints=!1,this.container.style.cursor=`default`,this.clearCustomMarkers()}clearCustomPlane(){this.customPlane=null,this.clearCustomMarkers(),this.applyPlanes()}invertCustomClip(){return this.customPlane?(this.customPlane.negate(),this.applyPlanes(),!0):!1}hasCustomPlane(){return this.customPlane!==null}handleCustomPointPick(e){let t=this.container.getBoundingClientRect(),n=M(new c.Vector2((e.clientX-t.left)/t.width*2-1,-((e.clientY-t.top)/t.height)*2+1),this.camera,this.modelLoader.getMeshes(),15,t.width,t.height);n.hit&&n.point&&this.addCustomPoint(n.point)}addCustomPoint(e){this.customPoints.push(e.clone());let t=new c.SphereGeometry(1,16,16),n=new c.MeshBasicMaterial({color:3718648,depthTest:!1}),r=new c.Mesh(t,n);if(r.position.copy(e),r.userData={fixedScreenRadius:5.5},this.customMarkersGroup.add(r),this.updateSingleMarkerScale(r),this.customPoints.length===2){let e=this.customPoints[0],t=this.customPoints[1],n=new c.Vector3().subVectors(t,e);if(n.lengthSq()<1e-5){this.customPoints.pop(),this.customMarkersGroup.remove(r);return}n.normalize();let i=new c.Vector3;this.camera.getWorldDirection(i);let a=new c.Vector3().crossVectors(n,i).normalize();a.lengthSq()<1e-4&&(a=new c.Vector3().crossVectors(n,this.camera.up).normalize()),this.customPlane=new c.Plane().setFromNormalAndCoplanarPoint(a,e),this.clearCustomMarkers(),this.cancelCustomClip(),this.applyPlanes()}}updatePerFrame(e){if(this.customMarkersGroup.children.length===0)return;let t=e||this.container.clientHeight||window.innerHeight||800,n=this.camera.fov*Math.PI/180,r=this.camera.position,i=Math.tan(n/2);this.customMarkersGroup.traverse(e=>{if(e.userData&&typeof e.userData.fixedScreenRadius==`number`){let n=e.userData.fixedScreenRadius,a=new c.Vector3;e.getWorldPosition(a);let o=2*a.distanceTo(r)*i*n/Math.max(t,1);e.scale.setScalar(o)}})}updateSingleMarkerScale(e,t){if(e.userData&&typeof e.userData.fixedScreenRadius==`number`){let n=e.userData.fixedScreenRadius,r=t||this.container.clientHeight||window.innerHeight||800,i=this.camera.fov*Math.PI/180,a=this.camera.position,o=Math.tan(i/2),s=new c.Vector3;e.getWorldPosition(s);let l=2*s.distanceTo(a)*o*n/Math.max(r,1);e.scale.setScalar(l)}}clearCustomMarkers(){for(;this.customMarkersGroup.children.length>0;){let e=this.customMarkersGroup.children[0];e.geometry&&e.geometry.dispose(),e.material&&e.material.dispose(),this.customMarkersGroup.remove(e)}}applyPlanes(){let e=[];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)}resetAll(){this.isEnabled=!1,this.activeAxis=`x`,this.helperVisible=!0,this.disableAllAxesPlanes();let e=new c.Vector3;this.modelBox.getCenter(e),[`x`,`y`,`z`].forEach(t=>{let n=this.widgets[t];n&&(n.enabled=t===`x`,n.inverted=!1,n.position=e[t],n.group.position.set(e.x,e.y,e.z),n.labelText.textContent=`${t.toUpperCase()} 剖切面`)}),this.updateWidgetsVisibility(),this.clearCustomPlane(),this.applyPlanes(),this.emitSectioningState()}destroy(){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})}},P=class{scene;camera;container;modelLoader;emitter;controls=null;currentMode=`none`;unit=`m`;measurementGroup;results=[];activePoints=[];activePreviewGroup;activeMarkersGroup;activeLineGroup;snapCursorMesh;onPointerDownBound;onPointerMoveBound;onDoubleClickBound;constructor(e,t,n,r,i,a){this.scene=e,this.camera=t,this.container=n,this.modelLoader=r,this.emitter=i,this.controls=a||null,this.measurementGroup=new c.Group,this.measurementGroup.name=`gmv-measurements-group`,this.scene.add(this.measurementGroup),this.activePreviewGroup=new c.Group,this.activePreviewGroup.name=`gmv-measure-preview-group`,this.scene.add(this.activePreviewGroup),this.activeMarkersGroup=new c.Group,this.activeMarkersGroup.name=`gmv-active-markers-group`,this.activePreviewGroup.add(this.activeMarkersGroup),this.activeLineGroup=new c.Group,this.activeLineGroup.name=`gmv-active-line-group`,this.activePreviewGroup.add(this.activeLineGroup);let o=new c.SphereGeometry(1,16,16),s=new c.MeshBasicMaterial({color:3718648,transparent:!0,opacity:.9,depthTest:!1});this.snapCursorMesh=new c.Mesh(o,s),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)}setControls(e){this.controls=e}setUnit(e){this.unit=e}setMode(e){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)))}getMode(){return this.currentMode}getControls(){return this.controls}addListeners(){this.removeListeners(),this.container.addEventListener(`pointerdown`,this.onPointerDownBound,{capture:!0}),this.container.addEventListener(`pointermove`,this.onPointerMoveBound),this.container.addEventListener(`dblclick`,this.onDoubleClickBound)}removeListeners(){this.container.removeEventListener(`pointerdown`,this.onPointerDownBound,{capture:!0}),this.container.removeEventListener(`pointermove`,this.onPointerMoveBound),this.container.removeEventListener(`dblclick`,this.onDoubleClickBound)}handlePointerMove(e){if(this.currentMode===`none`)return;let t=this.container.getBoundingClientRect(),n=M(new c.Vector2((e.clientX-t.left)/t.width*2-1,-((e.clientY-t.top)/t.height)*2+1),this.camera,this.modelLoader.getMeshes(),15,t.width,t.height);!n.hit||!n.point?(this.container.style.cursor=`not-allowed`,this.snapCursorMesh.visible=!1):(this.container.style.cursor=`crosshair`,this.snapCursorMesh.visible=!0,this.snapCursorMesh.position.copy(n.point),n.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(n.point))}handlePointerDown(e){if(this.currentMode===`none`||e.button!==0)return;let t=this.container.getBoundingClientRect(),n=M(new c.Vector2((e.clientX-t.left)/t.width*2-1,-((e.clientY-t.top)/t.height)*2+1),this.camera,this.modelLoader.getMeshes(),15,t.width,t.height);if(!n.hit||!n.point)return;let r=n.point.clone();this.activePoints.push(r),this.addActiveMarker(r),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()}addActiveMarker(e){let t=new c.SphereGeometry(1,16,16),n=new c.MeshBasicMaterial({color:3718648,depthTest:!1}),r=new c.Mesh(t,n);r.position.copy(e),r.userData={fixedScreenRadius:5.5},this.activeMarkersGroup.add(r),this.updateSingleMeshScale(r)}handleDoubleClick(e){this.currentMode===`area`&&this.activePoints.length>=3&&this.finishAreaMeasurement()}updateDynamicPreview(e){this.clearActiveLine();let t=[...this.activePoints,e];if(t.length<2)return;let n=new c.BufferGeometry().setFromPoints(t),r=new c.LineDashedMaterial({color:3718648,dashSize:.2,gapSize:.1,depthTest:!1}),i=new c.Line(n,r);i.computeLineDistances(),this.activeLineGroup.add(i)}finishDistanceMeasurement(){let e=this.activePoints[0],t=this.activePoints[1],n=e.distanceTo(t),r=new c.Vector3().addVectors(e,t).multiplyScalar(.5),i=new c.Group,a=new c.BufferGeometry().setFromPoints([e,t]),o=new c.LineBasicMaterial({color:3900150,linewidth:2,depthTest:!1}),s=new c.Line(a,o);i.add(s),this.addEndSphere(i,e,3900150),this.addEndSphere(i,t,3900150);let l=document.createElement(`div`);l.className=`gmv-measure-badge distance`,l.innerHTML=`<span>距离:</span> <strong>${k(n,this.unit)}</strong>`;let u=new d.CSS2DObject(l);u.position.copy(r),i.add(u),this.measurementGroup.add(i);let f={id:`dist_${Date.now()}`,type:`distance`,value:n,formattedValue:k(n,this.unit),unit:this.unit,points:[e,t]};this.results.push(f),this.emitter.emit(`measure:complete`,f),this.cancelActive(),this.setMode(`none`)}finishHeightMeasurement(){let e=this.activePoints[0],t=this.activePoints[1],n=Math.abs(t.y-e.y),r=new c.Vector2(e.x,e.z).distanceTo(new c.Vector2(t.x,t.z)),i=e.distanceTo(t),a=new c.Group,o=new c.BufferGeometry().setFromPoints([e,t]),s=new c.LineDashedMaterial({color:9741240,dashSize:.15,gapSize:.08,depthTest:!1}),l=new c.Line(o,s);l.computeLineDistances(),a.add(l);let u=new c.Vector3(t.x,e.y,t.z),f=new c.BufferGeometry().setFromPoints([e,u]),p=new c.LineBasicMaterial({color:1096065,depthTest:!1}),m=new c.Line(f,p);a.add(m);let h=new c.BufferGeometry().setFromPoints([u,t]),g=new c.LineBasicMaterial({color:15680580,linewidth:2,depthTest:!1}),_=new c.Line(h,g);a.add(_),this.addEndSphere(a,e,1096065),this.addEndSphere(a,t,15680580),this.addEndSphere(a,u,16436245,4);let v=new c.Vector3().addVectors(u,t).multiplyScalar(.5),y=document.createElement(`div`);y.className=`gmv-measure-badge height`,y.innerHTML=`
2
+ <div><span>高差 (ΔH):</span> <strong>${k(n,this.unit)}</strong></div>
3
+ <div style="font-size:10px;opacity:0.85;">水平: ${k(r,this.unit)} · 直线: ${k(i,this.unit)}</div>
4
+ `;let b=new d.CSS2DObject(y);b.position.copy(v),a.add(b),this.measurementGroup.add(a);let x={id:`height_${Date.now()}`,type:`height`,value:n,formattedValue:k(n,this.unit),unit:this.unit,points:[e,t],extra:{verticalHeight:n,horizontalDistance:r}};this.results.push(x),this.emitter.emit(`measure:complete`,x),this.cancelActive(),this.setMode(`none`)}finishAreaMeasurement(){if(this.activePoints.length<3)return;let e=[...this.activePoints],t=O(e),n=new c.Group,r=[...e,e[0]],i=new c.BufferGeometry().setFromPoints(r),a=new c.LineBasicMaterial({color:9133302,linewidth:2,depthTest:!1}),o=new c.Line(i,a);n.add(o),e.forEach(e=>this.addEndSphere(n,e,9133302));let s=new c.Vector3;e.forEach(e=>s.add(e)),s.divideScalar(e.length);let l=document.createElement(`div`);l.className=`gmv-measure-badge area`,l.innerHTML=`<span>面积:</span> <strong>${k(t,`${this.unit}²`)}</strong>`;let u=new d.CSS2DObject(l);u.position.copy(s),n.add(u),this.measurementGroup.add(n);let f={id:`area_${Date.now()}`,type:`area`,value:t,formattedValue:k(t,`${this.unit}²`),unit:`${this.unit}²`,points:e,extra:{area:t}};this.results.push(f),this.emitter.emit(`measure:complete`,f),this.cancelActive(),this.setMode(`none`)}finishAngleMeasurement(){if(this.activePoints.length!==3)return;let e=this.activePoints[0],t=this.activePoints[1],n=this.activePoints[2],r=new c.Vector3().subVectors(e,t).normalize(),i=new c.Vector3().subVectors(n,t).normalize(),a=r.dot(i);a=Math.max(-1,Math.min(1,a));let o=Math.acos(a),s=c.MathUtils.radToDeg(o),l=new c.Group,u=new c.BufferGeometry().setFromPoints([t,e]),f=new c.BufferGeometry().setFromPoints([t,n]),p=new c.LineBasicMaterial({color:16096779,linewidth:2,depthTest:!1});l.add(new c.Line(u,p)),l.add(new c.Line(f,p)),this.addEndSphere(l,e,16096779),this.addEndSphere(l,n,16096779),this.addEndSphere(l,t,15680580,6.5);let m=Math.min(e.distanceTo(t),n.distanceTo(t))*.35||.4,h=[];for(let e=0;e<=16;e++){let n=e/16,a=new c.Vector3().copy(r).lerp(i,n).normalize().multiplyScalar(m);h.push(new c.Vector3().addVectors(t,a))}let g=new c.BufferGeometry().setFromPoints(h),_=new c.LineBasicMaterial({color:16498468,depthTest:!1});l.add(new c.Line(g,_));let v=new c.Vector3().addVectors(r,i).normalize(),y=t.clone().add(v.multiplyScalar(m*1.3)),b=document.createElement(`div`);b.className=`gmv-measure-badge angle`,b.innerHTML=`<span>角度:</span> <strong>${s.toFixed(1)}°</strong>`;let x=new d.CSS2DObject(b);x.position.copy(y),l.add(x),this.measurementGroup.add(l);let S={id:`angle_${Date.now()}`,type:`angle`,value:s,formattedValue:`${s.toFixed(1)}°`,unit:`°`,points:[e,t,n],extra:{angleDegree:s}};this.results.push(S),this.emitter.emit(`measure:complete`,S),this.cancelActive(),this.setMode(`none`)}addEndSphere(e,t,n,r=5.5){let i=new c.SphereGeometry(1,16,16),a=new c.MeshBasicMaterial({color:n,depthTest:!1}),o=new c.Mesh(i,a);o.position.copy(t),o.userData={fixedScreenRadius:r},e.add(o),this.updateSingleMeshScale(o)}undoLastPoint(){if(this.activePoints.length>0){if(this.activePoints.pop(),this.activeMarkersGroup.children.length>0){let e=this.activeMarkersGroup.children[this.activeMarkersGroup.children.length-1];this.disposeObjectHierarchy(e),this.activeMarkersGroup.remove(e)}this.clearActiveLine(),this.emitter.emit(`measure:change`,[...this.activePoints])}}cancelActive(){this.activePoints=[],this.clearActiveLine(),this.clearActiveMarkers()}clearActiveLine(){for(;this.activeLineGroup.children.length>0;){let e=this.activeLineGroup.children[0];this.disposeObjectHierarchy(e),this.activeLineGroup.remove(e)}}clearActiveMarkers(){for(;this.activeMarkersGroup.children.length>0;){let e=this.activeMarkersGroup.children[0];this.disposeObjectHierarchy(e),this.activeMarkersGroup.remove(e)}}updatePerFrame(e){let t=e||this.container.clientHeight||window.innerHeight||800,n=this.camera.fov*Math.PI/180,r=this.camera.position,i=Math.tan(n/2),a=e=>{if(e.userData&&typeof e.userData.fixedScreenRadius==`number`){let n=e.userData.fixedScreenRadius,a=new c.Vector3;e.getWorldPosition(a);let o=2*a.distanceTo(r)*i*n/Math.max(t,1);e.scale.setScalar(o)}};this.snapCursorMesh&&this.snapCursorMesh.visible&&a(this.snapCursorMesh),this.activeMarkersGroup.traverse(a),this.measurementGroup.traverse(a)}updateSingleMeshScale(e,t){if(e.userData&&typeof e.userData.fixedScreenRadius==`number`){let n=e.userData.fixedScreenRadius,r=t||this.container.clientHeight||window.innerHeight||800,i=this.camera.fov*Math.PI/180,a=this.camera.position,o=Math.tan(i/2),s=new c.Vector3;e.getWorldPosition(s);let l=2*s.distanceTo(a)*o*n/Math.max(r,1);e.scale.setScalar(l)}}clearAll(){for(this.cancelActive();this.measurementGroup.children.length>0;){let e=this.measurementGroup.children[0];this.disposeObjectHierarchy(e),this.measurementGroup.remove(e)}this.snapCursorMesh.visible=!1,this.results=[],this.emitter.emit(`measure:clear`)}disposeObjectHierarchy(e){e.traverse(e=>{if(e.isCSS2DObject&&e.element){let t=e.element;t&&t.parentElement?t.parentElement.removeChild(t):t&&t.remove()}if(e.isMesh||e.isLine){let t=e;t.geometry&&t.geometry.dispose(),t.material&&(Array.isArray(t.material)?t.material.forEach(e=>e.dispose()):t.material.dispose())}})}getResults(){return[...this.results]}destroy(){this.removeListeners(),this.clearAll(),this.scene.remove(this.measurementGroup),this.scene.remove(this.activePreviewGroup),this.scene.remove(this.snapCursorMesh)}},F=class{renderer;scene;camera;getModel;constructor(e,t,n,r){this.renderer=e,this.scene=t,this.camera=n,this.getModel=r||(()=>null)}getSceneMaxTextureSize(){let e=0,t=0;return this.scene.traverse(n=>{if(n.isMesh){let r=n,i=n=>{if(`map`in n){let r=n;if(r.map){let n=r.map.image||r.map.source?.data;if(n){let r=n.width||0,i=n.height||0;r>0&&i>0&&r*i>e*t&&(e=r,t=i)}}}};Array.isArray(r.material)?r.material.forEach(i):r.material&&i(r.material)}}),e>0&&t>0?{width:e,height:t}:null}async exportImage(e={}){let t=e.originalQuality===!0||e.scale===`original`,n=t?1:typeof e.scale==`number`?e.scale:2,r=e.type??`image/png`,i=e.quality??(r===`image/png`?1:.95),a=e.download??!1,o=new c.Vector2;this.renderer.getSize(o);let s=this.renderer.getPixelRatio(),l=this.scene.background,u=o.x/o.y,d,f;if(e.targetSize)d=e.targetSize.width,f=e.targetSize.height;else if(t){let e=this.getSceneMaxTextureSize();if(e&&e.width>0&&e.height>0){let t=Math.max(e.width,e.height);u>=1?(d=t,f=Math.round(t/u)):(f=t,d=Math.round(t*u))}else{let e=Math.max(Math.round(o.x*s),2048);u>=1?(d=e,f=Math.round(e/u)):(f=e,d=Math.round(e*u))}}else d=Math.round(o.x*n),f=Math.round(o.y*n);let p=e.filename??`model-${t?`texture-original-${d}x${f}`:`${n}x`}-${Date.now()}.${r===`image/jpeg`?`jpg`:`png`}`,m=e.modelOnly??!0,h=[];e.background!==void 0&&(e.background===null?(this.scene.background=null,this.renderer.setClearAlpha(0)):(this.scene.background=new c.Color(e.background),this.renderer.setClearAlpha(1)));try{if(m){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`);for(let e of this.scene.children)!t(e)&&e.visible&&(h.push({obj:e,wasVisible:!0}),e.visible=!1)}this.renderer.setPixelRatio(1),this.renderer.setSize(d,f,!1),this.camera.aspect=d/f,this.camera.updateProjectionMatrix();let e=this.camera.fov*Math.PI/180,t=this.camera.position,n=Math.tan(e/2);this.scene.traverse(e=>{if(e.userData&&typeof e.userData.fixedScreenRadius==`number`){let r=e.userData.fixedScreenRadius,i=new c.Vector3;e.getWorldPosition(i);let a=2*i.distanceTo(t)*n*r/Math.max(f,1);e.scale.setScalar(a)}}),this.renderer.render(this.scene,this.camera);let o=this.renderer.domElement.toDataURL(r,i);if(a){let e=document.createElement(`a`);e.download=p,e.href=o,document.body.appendChild(e),e.click(),document.body.removeChild(e)}return o}finally{if(h.length>0)for(let{obj:e,wasVisible:t}of h)e.visible=t;this.scene.background=l,this.renderer.setPixelRatio(s),this.renderer.setSize(o.x,o.y,!0),this.camera.aspect=o.x/o.y,this.camera.updateProjectionMatrix();let e=o.y,t=this.camera.fov*Math.PI/180,n=this.camera.position,r=Math.tan(t/2);this.scene.traverse(t=>{if(t.userData&&typeof t.userData.fixedScreenRadius==`number`){let i=t.userData.fixedScreenRadius,a=new c.Vector3;t.getWorldPosition(a);let o=2*a.distanceTo(n)*r*i/Math.max(e,1);t.scale.setScalar(o)}}),this.renderer.render(this.scene,this.camera)}}},I=class extends S{sceneManager;modelLoader;boundingBoxTool;cameraTool;clippingTool;measurementTool;screenshotTool;currentModel=null;currentModelInfo=null;unit=`m`;defaultShowBoundingBox=!1;animationMixer=null;animationClips=[];activeAction=null;currentAnimationName=null;animationClock=new c.Clock;isAnimationActive=!1;constructor(e){super(),this.unit=e.unit||`m`,this.defaultShowBoundingBox=e.showBoundingBox??!1,this.sceneManager=new x(e),this.modelLoader=new w({dracoDecoderPath:e.dracoDecoderPath,ktx2TranscoderPath:e.ktx2TranscoderPath,renderer:this.sceneManager.renderer}),this.boundingBoxTool=new A(this.sceneManager.scene),this.cameraTool=new j(this.sceneManager.camera,this.sceneManager.controls,this.sceneManager.tweenGroup),this.clippingTool=new N(this.sceneManager.scene,this.sceneManager.camera,this.sceneManager.container,this.modelLoader,this.sceneManager.controls,this),this.measurementTool=new P(this.sceneManager.scene,this.sceneManager.camera,this.sceneManager.container,this.modelLoader,this,this.sceneManager.controls),this.measurementTool.setUnit(this.unit),this.screenshotTool=new F(this.sceneManager.renderer,this.sceneManager.scene,this.sceneManager.camera,()=>this.currentModel),this.measurementTool.setUnit(this.unit),this.sceneManager.onBeforeRender=()=>{if(this.animationMixer&&this.isAnimationActive){let e=this.animationClock.getDelta();this.animationMixer.update(e)}this.boundingBoxTool.update(this.sceneManager.camera),this.cameraTool.updatePerFrame(),this.measurementTool.updatePerFrame(),this.clippingTool.updatePerFrame()}}async loadZip(e){try{this.emit(`load:start`,typeof e==`string`?e:`ZIP File`),this.clearModel();let t=await this.modelLoader.loadZip(e,(e,t)=>{this.emit(`load:progress`,e,t)});return this.setupLoadedModel(t),this.emit(`load:success`,t),t}catch(e){let t=e instanceof Error?e:Error(String(e));throw this.emit(`load:error`,t),t}}async loadOBJ(e,t){try{this.emit(`load:start`,e),this.clearModel();let n=await this.modelLoader.loadOBJ(e,t,void 0,(e,t)=>{this.emit(`load:progress`,e,t)});return this.setupLoadedModel(n),this.emit(`load:success`,n),n}catch(e){let t=e instanceof Error?e:Error(String(e));throw this.emit(`load:error`,t),t}}async loadGLTF(e){try{this.emit(`load:start`,typeof e==`string`?e:`GLTF Data`),this.clearModel();let t=await this.modelLoader.loadGLTF(e,void 0,(e,t)=>{this.emit(`load:progress`,e,t)});return this.setupLoadedModel(t),this.emit(`load:success`,t),t}catch(e){let t=e instanceof Error?e:Error(String(e));throw this.emit(`load:error`,t),t}}async loadGLB(e){try{let t=typeof e==`string`?e:e instanceof File?e.name:`GLB Model`;this.emit(`load:start`,t),this.clearModel();let n=await this.modelLoader.loadGLB(e,(e,t)=>{this.emit(`load:progress`,e,t)});return this.setupLoadedModel(n),this.emit(`load:success`,n),n}catch(e){let t=e instanceof Error?e:Error(String(e));throw this.emit(`load:error`,t),t}}async loadFiles(e){try{let t=Array.from(e)[0]?.name||`Files`;this.emit(`load:start`,t),this.clearModel();let n=await this.modelLoader.loadFiles(e,(e,t)=>{this.emit(`load:progress`,e,t)});return this.setupLoadedModel(n),this.emit(`load:success`,n),n}catch(e){let t=e instanceof Error?e:Error(String(e));throw this.emit(`load:error`,t),t}}async loadFromUrl(e){let t=e.split(`?`)[0].toLowerCase();if(t.endsWith(`.glb`))return this.loadGLB(e);if(t.endsWith(`.gltf`))return this.loadGLTF(e);if(t.endsWith(`.zip`))return this.loadZip(e);if(t.endsWith(`.obj`))return this.loadOBJ(e);try{return await this.loadGLB(e)}catch{try{return await this.loadZip(e)}catch{return await this.loadOBJ(e)}}}loadSampleGeometry(e=`mechanical`){this.clearModel();let t=new c.Group;if(e===`mechanical`){let e=new c.BoxGeometry(6,1.2,4),n=new c.MeshStandardMaterial({color:4674921,metalness:.8,roughness:.3}),r=new c.Mesh(e,n);r.position.y=.6,t.add(r);let i=new c.CylinderGeometry(1.2,1.2,3,32),a=new c.MeshStandardMaterial({color:165063,metalness:.6,roughness:.2}),o=new c.Mesh(i,a);o.position.set(0,2.7,0),t.add(o);let s=new c.TorusGeometry(1.6,.25,16,40),l=new c.MeshStandardMaterial({color:14753096,metalness:.7,roughness:.2}),u=new c.Mesh(s,l);u.rotation.x=Math.PI/2,u.position.set(0,3.2,0),t.add(u)}else if(e===`building`){let e=new c.BoxGeometry(4,10,4),n=new c.MeshStandardMaterial({color:3359061,roughness:.4}),r=new c.Mesh(e,n);r.position.y=5,t.add(r);let i=new c.ConeGeometry(3,2.5,4),a=new c.MeshStandardMaterial({color:12131356,roughness:.5}),o=new c.Mesh(i,a);o.position.y=11.25,o.rotation.y=Math.PI/4,t.add(o)}else{let e=new c.TorusKnotGeometry(2.5,.7,100,16),n=new c.MeshStandardMaterial({color:9133302,metalness:.5,roughness:.2}),r=new c.Mesh(e,n);r.position.y=3,t.add(r)}let n=this.modelLoader.postProcessModel(t);return this.setupLoadedModel(n),this.emit(`load:success`,n),n}setupLoadedModel(e){this.currentModel=e.model,this.currentModel.name=`gmv-current-model`,this.currentModelInfo=e,this.sceneManager.scene.add(this.currentModel),e.animations&&e.animations.length>0?(this.animationClips=e.animations,this.animationMixer=new c.AnimationMixer(this.currentModel),this.playAnimation(0)):(this.animationClips=[],this.animationMixer=null,this.activeAction=null,this.currentAnimationName=null,this.isAnimationActive=!1),this.boundingBoxTool.attachToModel(this.currentModel,{visible:this.defaultShowBoundingBox,unit:this.unit}),this.clippingTool.setModelBounds(e.box),this.cameraTool.setView(`front`,this.currentModel,0)}clearModel(){this.animationMixer&&=(this.animationMixer.stopAllAction(),this.currentModel&&this.animationMixer.uncacheRoot(this.currentModel),null),this.animationClips=[],this.activeAction=null,this.currentAnimationName=null,this.isAnimationActive=!1,this.measurementTool.clearAll(),this.clippingTool.resetAll(),this.boundingBoxTool.detach(),this.currentModel&&=(this.sceneManager.scene.remove(this.currentModel),null),this.currentModelInfo=null,this.modelLoader.cleanup()}setBackground(e,t){this.sceneManager.setBackground(e,t)}setModelDisplayStyle(e){this.modelLoader.setDisplayStyle(e),this.emit(`style:change`,e)}getModelDisplayStyle(){return this.modelLoader.getDisplayStyle()}toggleTexture(e){this.modelLoader.toggleTexture(e),this.emit(`texture:toggle`,e)}getTextureState(){return this.modelLoader.getTextureState()}setPlainColor(e){this.modelLoader.setPlainColor(e)}getPlainColor(){return this.modelLoader.getPlainColor()}getModelTextureSize(){return this.modelLoader.getModelTextureSize()}setGridVisible(e){this.sceneManager.gridHelper.visible=e}showBoundingBox(e,t){this.boundingBoxTool.setVisible(e),t?.unit&&(this.unit=t.unit,this.boundingBoxTool.setUnit(t.unit),this.measurementTool.setUnit(t.unit))}getBoundingBoxVisible(){return this.boundingBoxTool.getVisible()}setClipping(e,t,n=!1){this.clippingTool.setAxisClipping(e,t,n)}disableClippingAxis(e){this.clippingTool.disableAxis(e)}toggleClippingAxis(e,t){return this.clippingTool.toggleAxis(e,t)}invertClippingAxis(e){return this.clippingTool.invertAxis(e)}getClippingAxisState(e){return this.clippingTool.getAxisState(e)}setClippingPlanesVisible(e){this.clippingTool.setPlanesVisible(e)}getClippingPlanesVisible(){return this.clippingTool.getPlanesVisible()}setSectioningEnabled(e){this.clippingTool.setSectioningEnabled(e)}getSectioningEnabled(){return this.clippingTool.getSectioningEnabled()}setSectioningAxis(e){this.clippingTool.setSectioningAxis(e)}getSectioningAxis(){return this.clippingTool.getSectioningAxis()}setSectioningAxisEnabled(e,t){this.clippingTool.setAxisEnabled(e,t)}toggleSectioningAxis(e,t){return this.clippingTool.toggleAxis(e,t)}isSectioningAxisEnabled(e){return this.clippingTool.isAxisEnabled(e)}setSectioningAxisReverse(e,t){this.clippingTool.setAxisReverse(e,t)}invertSectioningAxis(e){return this.clippingTool.invertAxis(e)}setSectioningAxisProgress(e,t){this.clippingTool.setAxisProgress(e,t)}getSectioningAxisProgress(e){return this.clippingTool.getAxisProgress(e)}setSectioningHelperVisible(e){this.clippingTool.setSectioningHelperVisible(e)}getSectioningHelperVisible(){return this.clippingTool.getSectioningHelperVisible()}setSectioningReverse(e){this.clippingTool.setSectioningReverse(e)}getSectioningReverse(){return this.clippingTool.getSectioningReverse()}resetSectioning(e){this.clippingTool.resetSectioning(e)}getSectioningState(){return this.clippingTool.getSectioningState()}startCustomClip(){this.measurementTool.setMode(`none`),this.clippingTool.startCustomClip()}cancelCustomClip(){this.clippingTool.cancelCustomClip()}clearCustomClip(){this.clippingTool.clearCustomPlane()}invertCustomClip(){return this.clippingTool.invertCustomClip()}hasCustomClip(){return this.clippingTool.hasCustomPlane()}resetClipping(){this.clippingTool.resetAll()}setMeasurementMode(e){e===`none`?this.clippingTool.setInteractive(!0):(this.clippingTool.cancelCustomClip(),this.clippingTool.setInteractive(!1)),this.measurementTool.setMode(e)}getMeasurementMode(){return this.measurementTool.getMode()}clearMeasurements(){this.measurementTool.clearAll()}undoMeasurement(){this.measurementTool.undoLastPoint()}getMeasurements(){return this.measurementTool.getResults()}async setView(e,t=600){this.currentModel&&(await this.cameraTool.setView(e,this.currentModel,t),this.emit(`view:change`,e))}async fitView(e=500){this.currentModel&&await this.cameraTool.fitToObject(this.currentModel,e)}setAutoRotate(e,t,n,r){this.cameraTool.setAutoRotate(e,t,n,r),this.emit(`autorotate:change`,this.cameraTool.getAutoRotateState())}toggleAutoRotate(){let e=this.cameraTool.toggleAutoRotate();return this.emit(`autorotate:change`,this.cameraTool.getAutoRotateState()),e}setAutoRotateAxis(e){this.cameraTool.setAutoRotateAxis(e),this.emit(`autorotate:change`,this.cameraTool.getAutoRotateState())}setAutoRotateDirection(e){this.cameraTool.setAutoRotateDirection(e),this.emit(`autorotate:change`,this.cameraTool.getAutoRotateState())}setAutoRotateSpeed(e){this.cameraTool.setAutoRotateSpeed(e),this.emit(`autorotate:change`,this.cameraTool.getAutoRotateState())}getAutoRotateState(){return this.cameraTool.getAutoRotateState()}setRotationLockedAxis(e){this.cameraTool.setLockedAxis(e),this.emit(`axislock:change`,e)}getRotationLockedAxis(){return this.cameraTool.getLockedAxis()}async exportImage(e={}){return this.screenshotTool.exportImage(e)}on(e,t){return super.on(e,t)}off(e,t){return super.off(e,t)}getAnimations(){return this.animationClips.map((e,t)=>e.name||`Animation ${t+1}`)}getCurrentAnimation(){return this.currentAnimationName}playAnimation(e=0){if(!this.animationMixer||this.animationClips.length===0)return;let t;if(t=typeof e==`number`?this.animationClips[e]:this.animationClips.find((t,n)=>t.name===e||`Animation ${n+1}`===e),t||=this.animationClips[0],!t)return;let n=this.animationMixer.clipAction(t);this.activeAction&&this.activeAction!==n?(this.activeAction.fadeOut(.3),n.reset().fadeIn(.3).play()):n.play(),this.activeAction=n,this.currentAnimationName=t.name||`Animation 1`,this.isAnimationActive=!0,this.animationClock.getDelta(),this.emit(`animation:play`,this.currentAnimationName)}pauseAnimation(){this.isAnimationActive=!1,this.emit(`animation:pause`)}resumeAnimation(){this.animationMixer&&this.activeAction&&(this.isAnimationActive=!0,this.animationClock.getDelta(),this.emit(`animation:play`,this.currentAnimationName||``))}stopAnimation(){this.isAnimationActive=!1,this.activeAction&&this.activeAction.stop(),this.emit(`animation:stop`)}isAnimationPlaying(){return this.isAnimationActive}setAnimationSpeed(e){this.animationMixer&&(this.animationMixer.timeScale=Math.max(0,e),this.emit(`animation:speed`,e))}destroy(){this.clearModel(),this.modelLoader.destroy(),this.measurementTool.destroy(),this.clippingTool.destroy(),this.sceneManager.destroy(),this.removeAllListeners()}};exports.BoundingBoxTool=A,exports.CameraTool=j,exports.ClippingTool=N,exports.EventEmitter=S,exports.MeasurementTool=P,exports.ModelLoader=w,exports.SceneManager=x,exports.ScreenshotTool=F,exports.Viewer=I,exports.ZipExtractor=C,exports.compute3DPolygonArea=O,exports.computeGroupVolume=E,exports.computeMeshVolume=T,exports.findSnapPoint=M,exports.formatUnit=k;
5
5
  //# sourceMappingURL=index.cjs.map