@realsee/dnalogel 4.0.0-webgpu.3 → 4.0.0-webgpu.4

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.
Files changed (147) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/dist/floorplan.js +1 -1
  3. package/dist/index.d.ts +1 -1
  4. package/dist/index.js +270 -35
  5. package/dist/index.js.map +1 -0
  6. package/dist/internal/{BasePlugin-CT5K8m36.js → BasePlugin-DC5m72La.js} +3 -3
  7. package/dist/internal/{BasePlugin-CT5K8m36.js.map → BasePlugin-DC5m72La.js.map} +1 -1
  8. package/dist/internal/BasePluginWithData-D_0W46_q.js +7 -0
  9. package/dist/internal/{BasePluginWithData-9z4tpAT4.js.map → BasePluginWithData-D_0W46_q.js.map} +1 -1
  10. package/dist/internal/{BetterTween-BX0aTvP1.js → BetterTween-DmptqE8m.js} +2 -2
  11. package/dist/internal/{BetterTween-BX0aTvP1.js.map → BetterTween-DmptqE8m.js.map} +1 -1
  12. package/dist/internal/{CSS3DRenderPlugin-ccSpcvwd.js → CSS3DRenderPlugin-CEatgl0m.js} +3 -3
  13. package/dist/internal/CSS3DRenderPlugin-CEatgl0m.js.map +1 -0
  14. package/dist/internal/{Controller-Csut_kcH.js → Controller-D6o4OGWJ.js} +8 -8
  15. package/dist/internal/{Controller-Csut_kcH.js.map → Controller-D6o4OGWJ.js.map} +1 -1
  16. package/dist/internal/{FiveDomEvents-3H9NvDOz.js → FiveDomEvents-BUBLFzti.js} +2 -2
  17. package/dist/internal/{FiveDomEvents-3H9NvDOz.js.map → FiveDomEvents-BUBLFzti.js.map} +1 -1
  18. package/dist/internal/FivePuppet-C6QmVY70.js +67 -0
  19. package/dist/internal/FivePuppet-C6QmVY70.js.map +1 -0
  20. package/dist/internal/{PointHelper-D565h9b_.js → PointHelper-DIhgdjY2.js} +48 -48
  21. package/dist/internal/{PointHelper-D565h9b_.js.map → PointHelper-DIhgdjY2.js.map} +1 -1
  22. package/dist/internal/{Polygon-CBGvYUfJ.js → Polygon-D3xIL1Pl.js} +30 -30
  23. package/dist/internal/{Polygon-CBGvYUfJ.js.map → Polygon-D3xIL1Pl.js.map} +1 -1
  24. package/dist/internal/{Prism-Dm5ESkgg.js → Prism-CJlyAEAU.js} +13 -13
  25. package/dist/internal/{Prism-Dm5ESkgg.js.map → Prism-CJlyAEAU.js.map} +1 -1
  26. package/dist/internal/{Rectangle-D-zkDycu.js → Rectangle-BpL9lNKU.js} +118 -129
  27. package/dist/internal/Rectangle-BpL9lNKU.js.map +1 -0
  28. package/dist/internal/{Work-DF8j5GnL.js → Work-BE4AgdwH.js} +9 -9
  29. package/dist/internal/{Work-DF8j5GnL.js.map → Work-BE4AgdwH.js.map} +1 -1
  30. package/dist/internal/{animationFrame-XGKHIeQK.js → animationFrame-CacKXN8l.js} +14 -3
  31. package/dist/internal/animationFrame-CacKXN8l.js.map +1 -0
  32. package/dist/internal/{area-maker-Bd9l2pIp.js → area-maker-Bnhx4SkH.js} +4 -4
  33. package/dist/internal/{area-maker-Bd9l2pIp.js.map → area-maker-Bnhx4SkH.js.map} +1 -1
  34. package/dist/internal/{boundingBox-DvCor5Hd.js → boundingBox-CIqXgNXW.js} +2 -2
  35. package/dist/internal/{boundingBox-DvCor5Hd.js.map → boundingBox-CIqXgNXW.js.map} +1 -1
  36. package/dist/internal/{camera-movement-CwI7UqUk.js → camera-movement-C1pwfMk_.js} +2 -2
  37. package/dist/internal/camera-movement-C1pwfMk_.js.map +1 -0
  38. package/dist/internal/{changeMode-BVGYCoqu.js → changeMode-D_I2AOjH.js} +2 -2
  39. package/dist/internal/{changeMode-BVGYCoqu.js.map → changeMode-D_I2AOjH.js.map} +1 -1
  40. package/dist/internal/{controller-BWkZT0l1.js → controller-DIDtFrBE.js} +1991 -2050
  41. package/dist/internal/controller-DIDtFrBE.js.map +1 -0
  42. package/dist/internal/{cruise-C3F0eNQ-.js → cruise-B50Tcq66.js} +2 -2
  43. package/dist/internal/{cruise-C3F0eNQ-.js.map → cruise-B50Tcq66.js.map} +1 -1
  44. package/dist/internal/{current-pano-image-DKUWluR-.js → current-pano-image-BCFr6njt.js} +4 -4
  45. package/dist/internal/{current-pano-image-DKUWluR-.js.map → current-pano-image-BCFr6njt.js.map} +1 -1
  46. package/dist/internal/{defaultUrls-CjKkS9k9.js → defaultUrls-CfMtGzqM.js} +14 -3
  47. package/dist/internal/defaultUrls-CfMtGzqM.js.map +1 -0
  48. package/dist/internal/{fire-scene-CczaBz2_.js → fire-scene-BzZGvyh_.js} +9 -4
  49. package/dist/internal/fire-scene-BzZGvyh_.js.map +1 -0
  50. package/dist/internal/{fiveModelLoad-mg-TnpnM.js → fiveModelLoad-BUIBYxzp.js} +2 -2
  51. package/dist/internal/{fiveModelLoad-mg-TnpnM.js.map → fiveModelLoad-BUIBYxzp.js.map} +1 -1
  52. package/dist/internal/{floorplan-KWlIsTvO.js → floorplan-C8BGw87S.js} +5 -5
  53. package/dist/internal/{floorplan-KWlIsTvO.js.map → floorplan-C8BGw87S.js.map} +1 -1
  54. package/dist/internal/{generatePolygonGeometry-B_5JFq8y.js → generatePolygonGeometry-BOnzdCaG.js} +181 -178
  55. package/dist/internal/generatePolygonGeometry-BOnzdCaG.js.map +1 -0
  56. package/dist/internal/{lookObject-wesf8xt6.js → lookObject-DuRab5wf.js} +2 -2
  57. package/dist/internal/{lookObject-wesf8xt6.js.map → lookObject-DuRab5wf.js.map} +1 -1
  58. package/dist/internal/{measure-BX6boAC7.js → measure-B4jFwdQ6.js} +5 -5
  59. package/dist/internal/{measure-BX6boAC7.js.map → measure-B4jFwdQ6.js.map} +1 -1
  60. package/dist/internal/{model-chassis-compass-InVNmOAQ.js → model-chassis-compass-C6NTVMLo.js} +2 -2
  61. package/dist/internal/{model-chassis-compass-InVNmOAQ.js.map → model-chassis-compass-C6NTVMLo.js.map} +1 -1
  62. package/dist/internal/{model-entry-door-guide-wZbyY77a.js → model-entry-door-guide-DnGTLY2s.js} +2 -2
  63. package/dist/internal/{model-entry-door-guide-wZbyY77a.js.map → model-entry-door-guide-DnGTLY2s.js.map} +1 -1
  64. package/dist/internal/{model-maker-uO8xlTuO.js → model-maker-B1mnDdKY.js} +15 -15
  65. package/dist/internal/{model-maker-uO8xlTuO.js.map → model-maker-B1mnDdKY.js.map} +1 -1
  66. package/dist/internal/{model-tv-video-DzXb2JRf.js → model-tv-video-BP-7HoDC.js} +2 -2
  67. package/dist/internal/{model-tv-video-DzXb2JRf.js.map → model-tv-video-BP-7HoDC.js.map} +1 -1
  68. package/dist/internal/{model-view-CBeeMM98.js → model-view-BWUU0-uq.js} +2 -2
  69. package/dist/internal/{model-view-CBeeMM98.js.map → model-view-BWUU0-uq.js.map} +1 -1
  70. package/dist/internal/object3d-helper-CbRRhnLV.js +7 -0
  71. package/dist/internal/{object3d-helper-DDYsVPN6.js.map → object3d-helper-CbRRhnLV.js.map} +1 -1
  72. package/dist/internal/{pano-compass-jSr629BP.js → pano-compass-BRTM0dCc.js} +7 -7
  73. package/dist/internal/{pano-compass-jSr629BP.js.map → pano-compass-BRTM0dCc.js.map} +1 -1
  74. package/dist/internal/{pano-door-label-DKoYIKLa.js → pano-door-label-BLjYGZrr.js} +3 -3
  75. package/dist/internal/{pano-door-label-DKoYIKLa.js.map → pano-door-label-BLjYGZrr.js.map} +1 -1
  76. package/dist/internal/{pano-measure-DW9mdx1O.js → pano-measure-BIgCWkVJ.js} +14 -14
  77. package/dist/internal/{pano-measure-DW9mdx1O.js.map → pano-measure-BIgCWkVJ.js.map} +1 -1
  78. package/dist/internal/{pano-ruler-pro-D7q0Ob21.js → pano-ruler-pro-D9yTbHJz.js} +2 -2
  79. package/dist/internal/{pano-ruler-pro-D7q0Ob21.js.map → pano-ruler-pro-D9yTbHJz.js.map} +1 -1
  80. package/dist/internal/{pano-spatial-tag-D0qn-__S.js → pano-spatial-tag-B7Gxn3BS.js} +3 -3
  81. package/dist/internal/{pano-spatial-tag-D0qn-__S.js.map → pano-spatial-tag-B7Gxn3BS.js.map} +1 -1
  82. package/dist/internal/{pano-tag-BW5MXXws.js → pano-tag-Bchz-jED.js} +2 -2
  83. package/dist/internal/{pano-tag-BW5MXXws.js.map → pano-tag-Bchz-jED.js.map} +1 -1
  84. package/dist/internal/{pano-video-Bmud_CAn.js → pano-video-BufYQMqo.js} +3 -3
  85. package/dist/internal/{pano-video-Bmud_CAn.js.map → pano-video-BufYQMqo.js.map} +1 -1
  86. package/dist/internal/{pipeline-DDqgb1gw.js → pipeline-t_3IMXKB.js} +4 -4
  87. package/dist/internal/{pipeline-DDqgb1gw.js.map → pipeline-t_3IMXKB.js.map} +1 -1
  88. package/dist/internal/{sculpt-BNkLJR6p.js → sculpt-BCK4PMwL.js} +64 -63
  89. package/dist/internal/{sculpt-BNkLJR6p.js.map → sculpt-BCK4PMwL.js.map} +1 -1
  90. package/dist/internal/tagPosition-DA9YguT8.js +176 -0
  91. package/dist/internal/tagPosition-DA9YguT8.js.map +1 -0
  92. package/dist/internal/withResolvers-DVr4bnnk.js +15 -0
  93. package/dist/internal/withResolvers-DVr4bnnk.js.map +1 -0
  94. package/dist/plugins/area-maker.js +1 -1
  95. package/dist/plugins/camera-movement.js +1 -1
  96. package/dist/plugins/cruise.js +2 -2
  97. package/dist/plugins/css3d-render.js +1 -1
  98. package/dist/plugins/current-pano-image.js +1 -1
  99. package/dist/plugins/digital-performance.d.ts +1 -1
  100. package/dist/plugins/digital-performance.js +1 -1
  101. package/dist/plugins/fire-scene.d.ts +1 -1
  102. package/dist/plugins/fire-scene.js +1 -1
  103. package/dist/plugins/guide-line.js +1 -1
  104. package/dist/plugins/measure.js +1 -1
  105. package/dist/plugins/model-chassis-compass.js +1 -1
  106. package/dist/plugins/model-entry-door-guide.js +1 -1
  107. package/dist/plugins/model-maker.d.ts +1 -1
  108. package/dist/plugins/model-maker.js +1 -1
  109. package/dist/plugins/model-tv-video.js +1 -1
  110. package/dist/plugins/model-view.js +1 -1
  111. package/dist/plugins/object3d-helper.d.ts +1 -1
  112. package/dist/plugins/object3d-helper.js +3 -1
  113. package/dist/plugins/pano-compass.js +1 -1
  114. package/dist/plugins/pano-door-label.js +1 -1
  115. package/dist/plugins/pano-measure.js +1 -1
  116. package/dist/plugins/pano-ruler-pro.js +1 -1
  117. package/dist/plugins/pano-spatial-tag.js +1 -1
  118. package/dist/plugins/pano-tag.d.ts +1 -1
  119. package/dist/plugins/pano-tag.js +4 -1
  120. package/dist/plugins/pano-video.js +1 -1
  121. package/dist/plugins/pipeline.js +1 -1
  122. package/dist/plugins/sculpt.d.ts +1 -1
  123. package/dist/plugins/sculpt.js +7 -1
  124. package/dist/types/public/index.d.ts +2 -0
  125. package/dist/types/public/plugins/digital-performance.d.ts +1 -0
  126. package/dist/types/public/plugins/fire-scene.d.ts +1 -0
  127. package/dist/types/public/plugins/model-maker.d.ts +1 -0
  128. package/dist/types/public/plugins/object3d-helper.d.ts +1 -0
  129. package/dist/types/public/plugins/pano-tag.d.ts +2 -0
  130. package/dist/types/public/plugins/sculpt.d.ts +8 -0
  131. package/dist/types/public/utils.d.ts +5 -0
  132. package/dist/utils.d.ts +1 -1
  133. package/dist/utils.js +16 -50
  134. package/package.json +1 -1
  135. package/dist/internal/BasePluginWithData-9z4tpAT4.js +0 -7
  136. package/dist/internal/CSS3DRenderPlugin-ccSpcvwd.js.map +0 -1
  137. package/dist/internal/Rectangle-D-zkDycu.js.map +0 -1
  138. package/dist/internal/animationFrame-XGKHIeQK.js.map +0 -1
  139. package/dist/internal/blink-DD_0mH-m.js +0 -113
  140. package/dist/internal/blink-DD_0mH-m.js.map +0 -1
  141. package/dist/internal/camera-movement-CwI7UqUk.js.map +0 -1
  142. package/dist/internal/controller-BWkZT0l1.js.map +0 -1
  143. package/dist/internal/defaultUrls-CjKkS9k9.js.map +0 -1
  144. package/dist/internal/fire-scene-CczaBz2_.js.map +0 -1
  145. package/dist/internal/generatePolygonGeometry-B_5JFq8y.js.map +0 -1
  146. package/dist/internal/object3d-helper-DDYsVPN6.js +0 -7
  147. package/dist/utils.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"measure-BX6boAC7.js","names":["Subscribe","PointSelector","bindFiveOwner","LineMesh","IObject3D","THREERaycaster","FiveDomEvents","Cursor","vectorIsEqual","PointMesh","LineWithDotsMesh","PolygonMesh","THREE","validatePolygon","points","isLine","vector01","i","vector","plane","index","point","MeasureMesh","config","isPolygon","isff","addEvent","object","event","method","useCapture","removeEvent","getMods","modsKeys","key","modsCodes","modifier","getKeys","keys","compareArray","arr1","a1","a2","arr2","isIndex","getLayoutIndependentKeyCode","eventKey","keyMap","modifierMap2","_keyMap","_modifier","modifierMap","_mods","_handlers","k","_downKeys","winListendFocus","winListendFullscreen","_scope","elementEventMap","code","x","getKey","getModifier","setScope","scope","getScope","getPressedKeyCodes","getPressedKeyString","c","getAllKeyCodes","result","v","filter","target","flag","isInput","tagName","isPressed","keyCode","deleteScope","handlers","removeKeyEvent","element","newScope","clearModifier","unbind","args","keysInfo","eachUnbind","info","unbindKeys","originKey","splitKey","len","lastKey","mods","unbindElements","isUnbind","record","eventHandler","handler","modifiersMatch","y","dispatch","asterisk","hotkeys","keyNum","keyName","e","handlerKey","keyLen","keyShortcut","_downKeysCurrent","a","hotkeys2","keyup","keydown","capture","single","option","opts","currentKey","finalKey","keydownListener","keyupListenr","listener","onFullscreenChange","fullscreenListener","webkitListener","trigger","item","shortcut","data","values","el","_api","_hotkeys","deep","MeasureController","five","defaultConfig","measureMesh","temp_previewPoint","temp_previewLine","temp_previewPolygon","temp_verticalLine1","temp_verticalLine2","temp_verticalPoint","currentVerticalPoint","isRightTriangleShowing","isShiftPressed","onKeyDown","onKeyUp","removeTempMesh","onIntersectionUpdate","intersection","lastPoint","verticalPoint","onSelect","targetPoint","undo","onFinished","finalReason","keepMesh","\"__five_pano_index\"","enable","unit","precision","dom","items","raycaster","panoIndex","direction","intersect","distanceToPoint","mode","clickedMeasureMesh","clientX","clientY","deleteMesh","containerElement","hoveredMeasureMesh","unHoveredMeasureMesh","cleanup","pointMesh","pressTimer","isLongPressTriggered","actualPointIndex","onPointerDown","pointerDownPosition","globalMoveHandler","onPointerUp","onClick","p","mouseDownPosition","isDragMode","newPoints","updatedPointIndex","lastPointIndex","isLiveUpdate","lineMesh","positions","updatedPosition","firstPointMesh","lastPointMesh","pointIndex","finalPoints","originalMeshState","opacity","isRepositioning","dashed","fiveElement","currentIntersection","onGlobalMouseMove","rect","intersects","onGlobalTouchMove","touch","onGlobalMouseUp","onGlobalTouchEnd","onGlobalClick","indicator","style","mousePosition","pointScreenPosition","globalMouseCleanup","onGlobalTouchStart","allHits","loopIndex","screenDistance","b","closestHit","syntheticEvent","pointerX","pointer","pointerY","screenPosition","screenX","screenY","dx","dy","MeasurePlugin"],"sources":["../../src/MeasurePlugin/utils/validatePolygon.ts","../../src/MeasurePlugin/utils/MeasureMesh.ts","../../../node_modules/hotkeys-js/dist/hotkeys-js.js","../../src/MeasurePlugin/Controller.ts","../../src/MeasurePlugin/index.ts"],"sourcesContent":["import { vectorIsEqual } from '../../shared-utils/three/vectorIsEqual'\nimport * as THREE from 'three/webgpu'\n\nexport function validatePolygon(points: THREE.Vector3[]): boolean {\n if (points.length < 3) return false\n\n if (!vectorIsEqual(points[0], points.at(-1))) return false\n\n // 检查所有点不是一条直线\n let isLine = true\n const vector01 = new THREE.Vector3().subVectors(points[1], points[0]).normalize()\n for (let i = 2; i < points.length; i++) {\n const vector = new THREE.Vector3().subVectors(points[i], points[0]).normalize()\n if (!vectorIsEqual(vector, vector01) && !vectorIsEqual(vector, vector01.clone().negate())) {\n isLine = false\n break\n }\n }\n\n if (isLine) return false\n\n // 检查所有点是不是一个平面\n const plane = new THREE.Plane().setFromCoplanarPoints(points[0], points[1], points[2])\n const isPolygon = points.every((point, index) => {\n if (index < 3) return true\n return plane.distanceToPoint(point) < 0.000001\n })\n\n return isPolygon\n}\n","import type * as THREE from 'three/webgpu'\nimport { IObject3D } from '../../shared-utils/three/IObject3D'\nimport { LineWithDotsMesh } from '../../Sculpt/Meshes/LineWithDots'\nimport { PolygonMesh, type PolygonStyle } from '../../Sculpt/Meshes/Polygon'\nimport { validatePolygon } from './validatePolygon'\nimport type { Color } from '../../Sculpt/typings/style'\nimport type { LineMeshStyle } from '../../Sculpt/typings'\n\nexport class MeasureMesh extends IObject3D {\n public readonly name = 'MeasureMesh'\n public readonly isMeasureMesh = true\n\n public points: THREE.Vector3[] = []\n public isPolygon = false\n public selected = false\n public line: LineWithDotsMesh\n public polygon: PolygonMesh\n\n public constructor(config?: { lineStyle?: Partial<LineMeshStyle>; polygonStyle?: Partial<PolygonStyle> }) {\n super()\n this.line = new LineWithDotsMesh(config?.lineStyle)\n this.polygon = new PolygonMesh(config?.polygonStyle)\n this.add(this.line)\n }\n\n public changeConfig(config?: { lineStyle?: Partial<LineMeshStyle>; polygonStyle?: Partial<PolygonStyle> }) {\n this.line.setStyle(config?.lineStyle)\n this.polygon.setStyle(config?.polygonStyle)\n }\n\n public setPoints(points: THREE.Vector3[]) {\n this.points = points\n this.line.setPoints(this.points)\n\n const isPolygon = validatePolygon(this.points)\n this.isPolygon = isPolygon\n if (isPolygon) {\n this.addIfNotExists(this.polygon)\n this.polygon.setPoints(this.points)\n }\n }\n\n public select() {\n this.highlight(0x3377ff)\n this.selected = true\n }\n\n public unselect() {\n this.unhighlight()\n this.selected = false\n }\n\n public hover() {\n if (!this.selected) {\n this.highlight()\n }\n }\n\n public unhover() {\n if (!this.selected) {\n this.unhighlight()\n }\n }\n\n private highlight(color?: Color) {\n this.line.highlight({ color })\n this.polygon.highlight({ color })\n }\n\n private unhighlight() {\n this.line.unhighlight()\n this.polygon.unhighlight()\n }\n}\n","/*!\n * hotkeys-js v4.0.8\n * A simple micro-library for defining and dispatching keyboard shortcuts. It has no dependencies.\n * \n * @author kenny wong <wowohoo@qq.com>\n * @license MIT\n * @homepage https://jaywcjlove.github.io/hotkeys-js\n */\nconst isff = typeof navigator !== \"undefined\" ? navigator.userAgent.toLowerCase().indexOf(\"firefox\") > 0 : false;\nfunction addEvent(object, event, method, useCapture) {\n if (object.addEventListener) {\n object.addEventListener(event, method, useCapture);\n } else if (object.attachEvent) {\n object.attachEvent(`on${event}`, method);\n }\n}\nfunction removeEvent(object, event, method, useCapture) {\n if (!object) return;\n if (object.removeEventListener) {\n object.removeEventListener(event, method, useCapture);\n } else if (object.detachEvent) {\n object.detachEvent(`on${event}`, method);\n }\n}\nfunction getMods(modifier, key) {\n const modsKeys = key.slice(0, key.length - 1);\n const modsCodes = [];\n for (let i = 0; i < modsKeys.length; i++) {\n modsCodes.push(modifier[modsKeys[i].toLowerCase()]);\n }\n return modsCodes;\n}\nfunction getKeys(key) {\n if (typeof key !== \"string\") key = \"\";\n key = key.replace(/\\s/g, \"\");\n const keys = key.split(\",\");\n let index = keys.lastIndexOf(\"\");\n for (; index >= 0; ) {\n keys[index - 1] += \",\";\n keys.splice(index, 1);\n index = keys.lastIndexOf(\"\");\n }\n return keys;\n}\nfunction compareArray(a1, a2) {\n const arr1 = a1.length >= a2.length ? a1 : a2;\n const arr2 = a1.length >= a2.length ? a2 : a1;\n let isIndex = true;\n for (let i = 0; i < arr1.length; i++) {\n if (arr2.indexOf(arr1[i]) === -1) isIndex = false;\n }\n return isIndex;\n}\nfunction getLayoutIndependentKeyCode(event, keyMap, modifierMap2) {\n let key = event.keyCode || event.which || event.charCode;\n if (event.key) {\n const eventKey = event.key.toLowerCase();\n if (eventKey in keyMap) {\n return keyMap[eventKey];\n }\n if (eventKey in modifierMap2) {\n return modifierMap2[eventKey];\n }\n if (/^[0-9]$/.test(event.key)) {\n return event.key.charCodeAt(0);\n }\n if (/^[a-z]$/i.test(event.key)) {\n return event.key.toUpperCase().charCodeAt(0);\n }\n }\n if (event.code && /^Key[A-Z]$/.test(event.code)) {\n key = event.code.charCodeAt(3);\n }\n return key;\n}\nconst _keyMap = {\n backspace: 8,\n \"⌫\": 8,\n tab: 9,\n clear: 12,\n enter: 13,\n \"↩\": 13,\n return: 13,\n esc: 27,\n escape: 27,\n space: 32,\n left: 37,\n up: 38,\n right: 39,\n down: 40,\n /// https://w3c.github.io/uievents/#events-keyboard-key-location\n arrowup: 38,\n arrowdown: 40,\n arrowleft: 37,\n arrowright: 39,\n del: 46,\n delete: 46,\n ins: 45,\n insert: 45,\n home: 36,\n end: 35,\n pageup: 33,\n pagedown: 34,\n capslock: 20,\n num_0: 96,\n num_1: 97,\n num_2: 98,\n num_3: 99,\n num_4: 100,\n num_5: 101,\n num_6: 102,\n num_7: 103,\n num_8: 104,\n num_9: 105,\n num_multiply: 106,\n num_add: 107,\n num_enter: 108,\n num_subtract: 109,\n num_decimal: 110,\n num_divide: 111,\n \"⇪\": 20,\n \",\": 188,\n \".\": 190,\n \"/\": 191,\n \"`\": 192,\n \"-\": isff ? 173 : 189,\n \"=\": isff ? 61 : 187,\n \";\": isff ? 59 : 186,\n \"'\": 222,\n \"{\": 219,\n \"}\": 221,\n \"[\": 219,\n \"]\": 221,\n \"\\\\\": 220\n};\nconst _modifier = {\n // shiftKey\n \"⇧\": 16,\n shift: 16,\n // altKey\n \"⌥\": 18,\n alt: 18,\n option: 18,\n // ctrlKey\n \"⌃\": 17,\n ctrl: 17,\n control: 17,\n // metaKey\n \"⌘\": 91,\n cmd: 91,\n meta: 91,\n command: 91\n};\nconst modifierMap = {\n 16: \"shiftKey\",\n 18: \"altKey\",\n 17: \"ctrlKey\",\n 91: \"metaKey\",\n shiftKey: 16,\n ctrlKey: 17,\n altKey: 18,\n metaKey: 91\n};\nconst _mods = {\n 16: false,\n 18: false,\n 17: false,\n 91: false\n};\nconst _handlers = {};\nfor (let k = 1; k < 20; k++) {\n _keyMap[`f${k}`] = 111 + k;\n}\nlet _downKeys = [];\nlet winListendFocus = null;\nlet winListendFullscreen = null;\nlet _scope = \"all\";\nconst elementEventMap = /* @__PURE__ */ new Map();\nconst code = (x) => _keyMap[x.toLowerCase()] || _modifier[x.toLowerCase()] || x.toUpperCase().charCodeAt(0);\nconst getKey = (x) => Object.keys(_keyMap).find((k) => _keyMap[k] === x);\nconst getModifier = (x) => Object.keys(_modifier).find((k) => _modifier[k] === x);\nconst setScope = (scope) => {\n _scope = scope || \"all\";\n};\nconst getScope = () => {\n return _scope || \"all\";\n};\nconst getPressedKeyCodes = () => {\n return _downKeys.slice(0);\n};\nconst getPressedKeyString = () => {\n return _downKeys.map(\n (c) => getKey(c) || getModifier(c) || String.fromCharCode(c)\n );\n};\nconst getAllKeyCodes = () => {\n const result = [];\n Object.keys(_handlers).forEach((k) => {\n _handlers[k].forEach(({ key, scope, mods, shortcut }) => {\n result.push({\n scope,\n shortcut,\n mods,\n keys: key.split(\"+\").map((v) => code(v))\n });\n });\n });\n return result;\n};\nconst filter = (event) => {\n const target = event.target || event.srcElement;\n const { tagName } = target;\n let flag = true;\n const isInput = tagName === \"INPUT\" && ![\n \"checkbox\",\n \"radio\",\n \"range\",\n \"button\",\n \"file\",\n \"reset\",\n \"submit\",\n \"color\"\n ].includes(target.type);\n if (target.isContentEditable || (isInput || tagName === \"TEXTAREA\" || tagName === \"SELECT\") && !target.readOnly) {\n flag = false;\n }\n return flag;\n};\nconst isPressed = (keyCode) => {\n if (typeof keyCode === \"string\") {\n keyCode = code(keyCode);\n }\n return _downKeys.indexOf(keyCode) !== -1;\n};\nconst deleteScope = (scope, newScope) => {\n let handlers;\n let i;\n if (!scope) scope = getScope();\n for (const key in _handlers) {\n if (Object.prototype.hasOwnProperty.call(_handlers, key)) {\n handlers = _handlers[key];\n for (i = 0; i < handlers.length; ) {\n if (handlers[i].scope === scope) {\n const deleteItems = handlers.splice(i, 1);\n deleteItems.forEach(({ element }) => removeKeyEvent(element));\n } else {\n i++;\n }\n }\n }\n }\n if (getScope() === scope) setScope(newScope || \"all\");\n};\nfunction clearModifier(event) {\n let key = getLayoutIndependentKeyCode(event, _keyMap, _modifier);\n if (event.key && event.key.toLowerCase() === \"capslock\") {\n key = code(event.key);\n }\n const i = _downKeys.indexOf(key);\n if (i >= 0) {\n _downKeys.splice(i, 1);\n }\n if (event.key && event.key.toLowerCase() === \"meta\") {\n _downKeys.splice(0, _downKeys.length);\n }\n if (key === 93 || key === 224) key = 91;\n if (key in _mods) {\n _mods[key] = false;\n for (const k in _modifier)\n if (_modifier[k] === key) hotkeys[k] = false;\n }\n}\nconst unbind = (keysInfo, ...args) => {\n if (typeof keysInfo === \"undefined\") {\n Object.keys(_handlers).forEach((key) => {\n if (Array.isArray(_handlers[key])) {\n _handlers[key].forEach((info) => eachUnbind(info));\n }\n delete _handlers[key];\n });\n removeKeyEvent(null);\n } else if (Array.isArray(keysInfo)) {\n keysInfo.forEach((info) => {\n if (info.key) eachUnbind(info);\n });\n } else if (typeof keysInfo === \"object\") {\n if (keysInfo.key) eachUnbind(keysInfo);\n } else if (typeof keysInfo === \"string\") {\n let [scope, method] = args;\n if (typeof scope === \"function\") {\n method = scope;\n scope = \"\";\n }\n eachUnbind({\n key: keysInfo,\n scope,\n method,\n splitKey: \"+\"\n });\n }\n};\nconst eachUnbind = ({\n key,\n scope,\n method,\n splitKey = \"+\"\n}) => {\n const multipleKeys = getKeys(key);\n multipleKeys.forEach((originKey) => {\n const unbindKeys = originKey.split(splitKey);\n const len = unbindKeys.length;\n const lastKey = unbindKeys[len - 1];\n const keyCode = lastKey === \"*\" ? \"*\" : code(lastKey);\n if (!_handlers[keyCode]) return;\n if (!scope) scope = getScope();\n const mods = len > 1 ? getMods(_modifier, unbindKeys) : [];\n const unbindElements = [];\n _handlers[keyCode] = _handlers[keyCode].filter((record) => {\n const isMatchingMethod = method ? record.method === method : true;\n const isUnbind = isMatchingMethod && record.scope === scope && compareArray(record.mods, mods);\n if (isUnbind) unbindElements.push(record.element);\n return !isUnbind;\n });\n unbindElements.forEach((element) => removeKeyEvent(element));\n });\n};\nfunction eventHandler(event, handler, scope, element) {\n if (handler.element !== element) {\n return;\n }\n let modifiersMatch;\n if (handler.scope === scope || handler.scope === \"all\") {\n modifiersMatch = handler.mods.length > 0;\n for (const y in _mods) {\n if (Object.prototype.hasOwnProperty.call(_mods, y)) {\n if (!_mods[y] && handler.mods.indexOf(+y) > -1 || _mods[y] && handler.mods.indexOf(+y) === -1) {\n modifiersMatch = false;\n }\n }\n }\n if (handler.mods.length === 0 && !_mods[16] && !_mods[18] && !_mods[17] && !_mods[91] || modifiersMatch || handler.shortcut === \"*\") {\n handler.keys = [];\n handler.keys = handler.keys.concat(_downKeys);\n if (handler.method(event, handler) === false) {\n if (event.preventDefault) event.preventDefault();\n else event.returnValue = false;\n if (event.stopPropagation) event.stopPropagation();\n if (event.cancelBubble) event.cancelBubble = true;\n }\n }\n }\n}\nfunction dispatch(event, element) {\n const asterisk = _handlers[\"*\"];\n let key = getLayoutIndependentKeyCode(event, _keyMap, _modifier);\n if (event.key && event.key.toLowerCase() === \"capslock\") {\n return;\n }\n const filterFn = hotkeys.filter || filter;\n if (!filterFn.call(this, event)) return;\n if (key === 93 || key === 224) key = 91;\n if (_downKeys.indexOf(key) === -1 && key !== 229) _downKeys.push(key);\n [\"metaKey\", \"ctrlKey\", \"altKey\", \"shiftKey\"].forEach((keyName) => {\n const keyNum = modifierMap[keyName];\n if (event[keyName] && _downKeys.indexOf(keyNum) === -1) {\n _downKeys.push(keyNum);\n } else if (!event[keyName] && _downKeys.indexOf(keyNum) > -1) {\n _downKeys.splice(_downKeys.indexOf(keyNum), 1);\n } else if (keyName === \"metaKey\" && event[keyName]) {\n _downKeys = _downKeys.filter((k) => k in modifierMap || k === key);\n }\n });\n if (key in _mods) {\n _mods[key] = true;\n for (const k in _modifier) {\n if (Object.prototype.hasOwnProperty.call(_modifier, k)) {\n const eventKey = modifierMap[_modifier[k]];\n hotkeys[k] = event[eventKey];\n }\n }\n if (!asterisk) return;\n }\n for (const e in _mods) {\n if (Object.prototype.hasOwnProperty.call(_mods, e)) {\n _mods[e] = event[modifierMap[e]];\n }\n }\n if (event.getModifierState && !(event.altKey && !event.ctrlKey) && event.getModifierState(\"AltGraph\")) {\n if (_downKeys.indexOf(17) === -1) {\n _downKeys.push(17);\n }\n if (_downKeys.indexOf(18) === -1) {\n _downKeys.push(18);\n }\n _mods[17] = true;\n _mods[18] = true;\n }\n const scope = getScope();\n if (asterisk) {\n for (let i = 0; i < asterisk.length; i++) {\n if (asterisk[i].scope === scope && (event.type === \"keydown\" && asterisk[i].keydown || event.type === \"keyup\" && asterisk[i].keyup)) {\n eventHandler(event, asterisk[i], scope, element);\n }\n }\n }\n if (!(key in _handlers)) return;\n const handlerKey = _handlers[key];\n const keyLen = handlerKey.length;\n for (let i = 0; i < keyLen; i++) {\n if (event.type === \"keydown\" && handlerKey[i].keydown || event.type === \"keyup\" && handlerKey[i].keyup) {\n if (handlerKey[i].key) {\n const record = handlerKey[i];\n const { splitKey } = record;\n const keyShortcut = record.key.split(splitKey);\n const _downKeysCurrent = [];\n for (let a = 0; a < keyShortcut.length; a++) {\n _downKeysCurrent.push(code(keyShortcut[a]));\n }\n if (_downKeysCurrent.sort().join(\"\") === _downKeys.sort().join(\"\")) {\n eventHandler(event, record, scope, element);\n }\n }\n }\n }\n}\nconst hotkeys = function hotkeys2(key, option, method) {\n _downKeys = [];\n const keys = getKeys(key);\n let mods = [];\n let scope = \"all\";\n let element = document;\n let i = 0;\n let keyup = false;\n let keydown = true;\n let splitKey = \"+\";\n let capture = false;\n let single = false;\n if (method === void 0 && typeof option === \"function\") {\n method = option;\n }\n if (Object.prototype.toString.call(option) === \"[object Object]\") {\n const opts = option;\n if (opts.scope) scope = opts.scope;\n if (opts.element) element = opts.element;\n if (opts.keyup) keyup = opts.keyup;\n if (opts.keydown !== void 0) keydown = opts.keydown;\n if (opts.capture !== void 0) capture = opts.capture;\n if (typeof opts.splitKey === \"string\") splitKey = opts.splitKey;\n if (opts.single === true) single = true;\n }\n if (typeof option === \"string\") scope = option;\n if (single) unbind(key, scope);\n for (; i < keys.length; i++) {\n const currentKey = keys[i].split(splitKey);\n mods = [];\n if (currentKey.length > 1) mods = getMods(_modifier, currentKey);\n let finalKey = currentKey[currentKey.length - 1];\n finalKey = finalKey === \"*\" ? \"*\" : code(finalKey);\n if (!(finalKey in _handlers)) _handlers[finalKey] = [];\n _handlers[finalKey].push({\n keyup,\n keydown,\n scope,\n mods,\n shortcut: keys[i],\n method,\n key: keys[i],\n splitKey,\n element\n });\n }\n if (typeof element !== \"undefined\" && typeof window !== \"undefined\") {\n if (!elementEventMap.has(element)) {\n const keydownListener = (event = window.event) => dispatch(event, element);\n const keyupListenr = (event = window.event) => {\n dispatch(event, element);\n clearModifier(event);\n };\n elementEventMap.set(element, { keydownListener, keyupListenr, capture });\n addEvent(element, \"keydown\", keydownListener, capture);\n addEvent(element, \"keyup\", keyupListenr, capture);\n }\n if (!winListendFocus) {\n const listener = () => {\n _downKeys = [];\n };\n winListendFocus = { listener, capture };\n addEvent(window, \"focus\", listener, capture);\n }\n if (!winListendFullscreen && typeof document !== \"undefined\") {\n const onFullscreenChange = () => {\n _downKeys = [];\n for (const k in _mods) _mods[k] = false;\n for (const k in _modifier) hotkeys2[k] = false;\n };\n const fullscreenListener = onFullscreenChange;\n const webkitListener = onFullscreenChange;\n document.addEventListener(\"fullscreenchange\", fullscreenListener);\n document.addEventListener(\"webkitfullscreenchange\", webkitListener);\n winListendFullscreen = { fullscreen: fullscreenListener, webkit: webkitListener };\n }\n }\n};\nfunction trigger(shortcut, scope = \"all\") {\n Object.keys(_handlers).forEach((key) => {\n const dataList = _handlers[key].filter(\n (item) => item.scope === scope && (item.shortcut === shortcut || item.shortcut === \"*\")\n );\n dataList.forEach((data) => {\n if (data && data.method) {\n data.method({}, data);\n }\n });\n });\n}\nfunction removeKeyEvent(element) {\n const values = Object.values(_handlers).flat();\n const findindex = values.findIndex(({ element: el }) => el === element);\n if (findindex < 0 && element) {\n const { keydownListener, keyupListenr, capture } = elementEventMap.get(element) || {};\n if (keydownListener && keyupListenr) {\n removeEvent(element, \"keyup\", keyupListenr, capture);\n removeEvent(element, \"keydown\", keydownListener, capture);\n elementEventMap.delete(element);\n }\n }\n if (values.length <= 0 || elementEventMap.size <= 0) {\n const eventKeys = Array.from(elementEventMap.keys());\n eventKeys.forEach((el) => {\n const { keydownListener, keyupListenr, capture } = elementEventMap.get(el) || {};\n if (keydownListener && keyupListenr) {\n removeEvent(el, \"keyup\", keyupListenr, capture);\n removeEvent(el, \"keydown\", keydownListener, capture);\n elementEventMap.delete(el);\n }\n });\n elementEventMap.clear();\n Object.keys(_handlers).forEach((key) => delete _handlers[key]);\n if (winListendFocus) {\n const { listener, capture } = winListendFocus;\n removeEvent(window, \"focus\", listener, capture);\n winListendFocus = null;\n }\n if (winListendFullscreen && typeof document !== \"undefined\") {\n document.removeEventListener(\"fullscreenchange\", winListendFullscreen.fullscreen);\n document.removeEventListener(\"webkitfullscreenchange\", winListendFullscreen.webkit);\n winListendFullscreen = null;\n }\n }\n}\nconst _api = {\n getPressedKeyString,\n setScope,\n getScope,\n deleteScope,\n getPressedKeyCodes,\n getAllKeyCodes,\n isPressed,\n filter,\n trigger,\n unbind,\n keyMap: _keyMap,\n modifier: _modifier,\n modifierMap\n};\nfor (const a in _api) {\n const key = a;\n if (Object.prototype.hasOwnProperty.call(_api, key)) {\n hotkeys[key] = _api[key];\n }\n}\nif (typeof window !== \"undefined\") {\n const _hotkeys = window.hotkeys;\n hotkeys.noConflict = (deep) => {\n if (deep && window.hotkeys === hotkeys) {\n window.hotkeys = _hotkeys;\n }\n return hotkeys;\n };\n window.hotkeys = hotkeys;\n}\nexport {\n hotkeys as default\n};\n//# sourceMappingURL=hotkeys-js.js.map\n","import { bindFiveOwner } from '../shared-utils/five/getFiveFromParentChain'\nimport type { Five, Mode } from '@realsee/five-webgpu'\nimport * as THREE from 'three/webgpu'\nimport { FiveDomEvents, PointSelector, type FiveDomEvent, type PointIntersection } from '../shared-utils'\nimport { MeasureMesh } from './utils/MeasureMesh'\nimport { PointMesh } from '../Sculpt/Meshes/Point'\nimport { LineWithDotsMesh } from '../Sculpt/Meshes/LineWithDots'\nimport { LineMesh } from '../Sculpt/Meshes/Line'\nimport hotkeys from 'hotkeys-js'\nimport { PolygonMesh, type PolygonStyle } from '../Sculpt/Meshes/Polygon'\nimport { validatePolygon } from './utils/validatePolygon'\nimport { Subscribe } from '../shared-utils/Subscribe'\nimport { IObject3D } from '../shared-utils/three/IObject3D'\nimport { Cursor } from '../Sculpt/utils/Modules/Cursor'\nimport type { LineMeshStyle } from '../Sculpt/typings'\nimport type { Overwrite } from '../typings/utils.type'\nimport type { MeasurePluginConfig } from '.'\nimport { THREERaycaster } from '../shared-utils/three/core/Raycaster'\n\n// 测量结束的原因枚举\nexport type MeasureEndReason =\n | 'enter' // 按Enter键完成\n | 'escape' // 按Esc键取消\n | 'polygon' // 自动完成多边形\n | 'mode_change' // 模式改变\n | 'pano_move' // 全景移动\n | 'floor_change' // 楼层改变\n | 'points_insufficient' // 点数不足(少于2个点)\n | 'external' // 外部调用结束\n\n// 测量插件事件类型\nexport type MeasurePluginEventMap = {\n measureEnd: (reason: MeasureEndReason, points: THREE.Vector3[]) => void\n undo: () => void\n}\n\nexport class MeasureController extends Subscribe<MeasurePluginEventMap> {\n public readonly name = 'MeasurePlugin'\n\n public currentMeasureMesh?: MeasureMesh | null\n\n private five: Five\n\n private group: Overwrite<IObject3D, { children: Array<MeasureMesh> }>\n\n // 当前测量结束的原因\n private currentEndReason: MeasureEndReason = 'enter'\n\n // Repositioning state\n private repositioningState: {\n measureMesh: MeasureMesh\n pointIndex: number\n originalOpacity: number\n originalMeshState: any[]\n isDragMode?: boolean\n mouseDownPosition?: { x: number; y: number }\n hasMoved?: boolean\n } | null = null\n\n // Long press visual feedback\n private longPressIndicator: HTMLElement | null = null\n\n // Global cleanup function for mouse/touch listeners\n private cleanupGlobalListeners?: () => void\n\n // Global touch handler for endpoint long press\n private globalTouchHandler: {\n isSetup: boolean\n onTouchStart: (e: TouchEvent) => void\n onTouchEnd: (e: TouchEvent) => void\n } | null = null\n\n public get pointSelector() {\n if (this._pointSelector) return this._pointSelector\n this._pointSelector = new PointSelector(this.five, { mode: 'cursor', helper: { pointHelper: 'highlight' }, skipPanorama: true })\n return this._pointSelector\n }\n private _pointSelector: PointSelector\n\n private get fiveDomEvents() {\n if (this._fiveDomEvents) return this._fiveDomEvents\n this._fiveDomEvents = new FiveDomEvents(this.five, { fiveModels: null })\n return this._fiveDomEvents\n }\n private _fiveDomEvents: FiveDomEvents\n\n private get cursor() {\n if (this._cursor) return this._cursor\n this._cursor = new Cursor()\n return this._cursor\n }\n private _cursor: Cursor\n\n public get config() {\n return this._config\n }\n\n public set config(config: MeasurePluginConfig) {\n this._config = config\n this.lineStyle.lengthUnit = config.unit\n this.polygonStyle.lengthUnit = config.unit\n\n // Apply lengthEnable setting if provided\n if (config.lengthEnable !== undefined) {\n this.lineStyle.lengthEnable = config.lengthEnable\n this.polygonStyle.lengthEnable = config.lengthEnable\n }\n\n // Apply precision setting if provided (only for length labels, not area)\n if (config.precision !== undefined) {\n this.lineStyle.precision = config.precision\n }\n\n this.group?.children?.forEach((item) => item.changeConfig({ lineStyle: this.lineStyle, polygonStyle: this.polygonStyle }))\n }\n\n private _config?: MeasurePluginConfig\n\n private lineStyle: Partial<LineMeshStyle> = {\n lengthEnable: true,\n occlusionVisibility: true,\n lengthUnit: 'm',\n precision: 2,\n }\n private polygonStyle: Partial<PolygonStyle> = {\n lengthEnable: true,\n occlusionVisibility: true,\n opacity: 0.2,\n lengthUnit: 'm',\n }\n\n public constructor(five: Five, config?: MeasurePluginConfig) {\n super()\n\n this.five = five\n\n // Initialize with default config\n const defaultConfig: MeasurePluginConfig = { unit: 'm', lengthEnable: true, precision: 2 }\n this.config = config ? { ...defaultConfig, ...config } : defaultConfig\n\n this.group = new IObject3D() as any\n this.group.name = 'MeasureGroup'\n bindFiveOwner(this.group, this.five)\n this.five.scene.add(this.group)\n\n // Add global event listeners\n this.five.on('panoArrived', this.onMoveToPano)\n this.five.on('modeChange', this.onModeChange)\n hotkeys('delete, backspace', this.deleteSelectedMesh)\n\n // Initialize event listeners for any existing meshes\n // This ensures event listeners work properly when loading from saved data\n this.initEventListeners()\n }\n\n /**\n * @description Initialize event listeners for all existing meshes\n */\n public initEventListeners = () => {\n // Add event listeners to all existing meshes\n this.group.children.forEach(this.addMeshEventListeners)\n }\n\n /**\n * @description 开始测量\n */\n public measure = () => {\n // Cancel any active repositioning first\n if (this.repositioningState) {\n this.cancelRepositioning()\n }\n\n this.listener.addMeasureListener()\n\n // Instead of removing all click listeners, just unbind global shortcut keys\n hotkeys.unbind('delete, backspace')\n\n // 取消所有选中态\n this.group.children.forEach((item) => item.unselect())\n this.cursor.removeDeleteButton()\n\n const measureMesh = new MeasureMesh({\n lineStyle: this.lineStyle,\n polygonStyle: this.polygonStyle,\n })\n this.currentMeasureMesh = measureMesh\n measureMesh.line.setStyle({ cssStyle: 'pointer-events: none;' })\n\n this.pointSelector.actionIfNoIntersection = 'disable'\n this.updateSelectAdsorbedHelper()\n\n const temp_previewPoint = new PointMesh({ occlusionMode: 'depthTest', occlusionVisibility: true })\n const temp_previewLine = new LineWithDotsMesh({ ...this.lineStyle, dashed: true, cssStyle: 'pointer-events: none;' })\n const temp_previewPolygon = new PolygonMesh(this.polygonStyle)\n // 直角三角形的两条直角边\n const temp_verticalLine1 = new LineMesh({\n ...this.lineStyle,\n lineOpacity: 0.5,\n lineColor: 0x33ffdd,\n dashed: true,\n cssStyle: 'pointer-events: none; opacity: 0.5;',\n })\n const temp_verticalLine2 = new LineMesh({\n ...this.lineStyle,\n lineOpacity: 0.5,\n lineColor: 0x33ffdd,\n dashed: true,\n cssStyle: 'pointer-events: none; opacity: 0.5;',\n })\n const temp_verticalPoint = new PointMesh({ occlusionMode: 'depthTest', occlusionVisibility: true, color: 0x33ffdd, opacity: 0.5 })\n\n // Track the current vertical point for Shift+click functionality\n let currentVerticalPoint: THREE.Vector3 | null = null\n let isRightTriangleShowing = false\n let isShiftPressed = false\n\n // Track Shift key state during measurement\n const onKeyDown = (e: KeyboardEvent) => {\n if (e.key === 'Shift') {\n isShiftPressed = true\n }\n }\n\n const onKeyUp = (e: KeyboardEvent) => {\n if (e.key === 'Shift') {\n isShiftPressed = false\n }\n }\n\n const removeTempMesh = () => {\n temp_previewPoint.removeFromParent()\n temp_previewLine.removeFromParent()\n temp_previewPolygon.removeFromParent()\n temp_verticalLine1.removeFromParent()\n temp_verticalLine2.removeFromParent()\n temp_verticalPoint.removeFromParent()\n }\n\n this.group.add(measureMesh)\n\n // Add Shift key listeners\n document.addEventListener('keydown', onKeyDown)\n document.addEventListener('keyup', onKeyUp)\n\n const onIntersectionUpdate = (intersection?: PointIntersection) => {\n if (!intersection) {\n removeTempMesh()\n // Reset triangle state\n currentVerticalPoint = null\n isRightTriangleShowing = false\n return\n }\n\n if (measureMesh.points.length === 0) {\n this.pointSelector.actionIfNoIntersection = 'disable'\n this.group.addIfNotExists(temp_previewPoint)\n temp_previewPoint.position.copy(intersection.point)\n // Reset triangle state\n currentVerticalPoint = null\n isRightTriangleShowing = false\n }\n if (measureMesh.points.length >= 1) {\n this.pointSelector.actionIfNoIntersection = 'virtualPoint'\n temp_previewPoint.removeFromParent()\n this.group.addIfNotExists(temp_previewLine)\n\n // Update temp_previewLine style before setting points to ensure labels use current precision\n temp_previewLine.setStyle({ ...this.lineStyle, dashed: true, cssStyle: 'pointer-events: none;' })\n\n // 预览线作为斜边\n temp_previewLine.setPoints([measureMesh.points.at(-1), intersection.point])\n // 绘制直角三角形的两条直角边\n if (!intersection.isAdsorbed) {\n const lastPoint = measureMesh.points.at(-1)\n // 判断是不是垂直的趋势\n const isWantUp = Math.abs(intersection.point.y - lastPoint.y) > 0.2\n if (isWantUp) {\n const verticalPoint = new THREE.Vector3(intersection.point.x, lastPoint.y, intersection.point.z)\n // Update vertical lines style before setting points to ensure labels use current precision\n temp_verticalLine1.setStyle({\n ...this.lineStyle,\n lineOpacity: 0.5,\n lineColor: 0x33ffdd,\n dashed: true,\n cssStyle: 'pointer-events: none; opacity: 0.5;',\n })\n temp_verticalLine2.setStyle({\n ...this.lineStyle,\n lineOpacity: 0.5,\n lineColor: 0x33ffdd,\n dashed: true,\n cssStyle: 'pointer-events: none; opacity: 0.5;',\n })\n temp_verticalLine1.setPoints([lastPoint, verticalPoint])\n temp_verticalLine2.setPoints([verticalPoint, intersection.point])\n temp_verticalPoint.position.copy(verticalPoint)\n // Update tracked variables\n currentVerticalPoint = verticalPoint.clone()\n isRightTriangleShowing = true\n } else {\n let verticalPoint = new THREE.Vector3()\n if (Math.abs(intersection.point.x - lastPoint.x) < Math.abs(intersection.point.z - lastPoint.z)) {\n verticalPoint = new THREE.Vector3(intersection.point.x, lastPoint.y, lastPoint.z)\n } else {\n verticalPoint = new THREE.Vector3(lastPoint.x, lastPoint.y, intersection.point.z)\n }\n // Update vertical lines style before setting points to ensure labels use current precision\n temp_verticalLine1.setStyle({\n ...this.lineStyle,\n lineOpacity: 0.5,\n lineColor: 0x33ffdd,\n dashed: true,\n cssStyle: 'pointer-events: none; opacity: 0.5;',\n })\n temp_verticalLine2.setStyle({\n ...this.lineStyle,\n lineOpacity: 0.5,\n lineColor: 0x33ffdd,\n dashed: true,\n cssStyle: 'pointer-events: none; opacity: 0.5;',\n })\n temp_verticalLine1.setPoints([lastPoint, verticalPoint])\n temp_verticalLine2.setPoints([verticalPoint, intersection.point])\n temp_verticalPoint.position.copy(verticalPoint)\n // Update tracked variables\n currentVerticalPoint = verticalPoint.clone()\n isRightTriangleShowing = true\n }\n this.group.addIfNotExists(temp_verticalLine1, temp_verticalLine2, temp_verticalPoint)\n } else {\n temp_verticalLine1.removeFromParent()\n temp_verticalLine2.removeFromParent()\n temp_verticalPoint.removeFromParent()\n // Reset triangle state when snapping to geometry\n currentVerticalPoint = null\n isRightTriangleShowing = false\n }\n }\n if (measureMesh.points.length >= 2) {\n const points = [...measureMesh.points, intersection.point]\n const isPolygon = validatePolygon(points)\n if (isPolygon) {\n // Update temp_previewPolygon style before setting points to ensure labels use current precision\n temp_previewPolygon.setStyle({ ...this.polygonStyle })\n temp_previewPolygon.setPoints(points)\n this.group.addIfNotExists(temp_previewPolygon)\n } else {\n temp_previewPolygon.removeFromParent()\n }\n }\n }\n\n const onSelect = (intersection?: PointIntersection) => {\n if (!intersection) return\n\n let targetPoint = intersection.point\n\n // If Shift is pressed, triangle is showing, and we have a vertical point, use the vertical point\n if (isShiftPressed && isRightTriangleShowing && currentVerticalPoint && measureMesh.points.length >= 1) {\n targetPoint = currentVerticalPoint.clone()\n }\n\n removeTempMesh()\n\n measureMesh.setPoints([...measureMesh.points, targetPoint])\n this.updateSelectAdsorbedHelper()\n\n if (measureMesh.isPolygon) {\n this.currentEndReason = 'polygon'\n this.pointSelector.disable()\n }\n }\n\n const undo = () => {\n measureMesh?.setPoints(measureMesh.points.slice(0, -1))\n removeTempMesh()\n this.pointSelector.pointSelectorHelper?.magnifier?.render()\n this.updateSelectAdsorbedHelper()\n this.five.needsRender = true\n }\n\n const onFinished = () => {\n this.pointSelector.off('intersectionUpdate', onIntersectionUpdate)\n this.pointSelector.off('select', onSelect)\n this.pointSelector.off('disable', onFinished)\n this.off('undo', undo)\n\n // Remove Shift key listeners\n document.removeEventListener('keydown', onKeyDown)\n document.removeEventListener('keyup', onKeyUp)\n\n measureMesh.line.setStyle({ cssStyle: 'pointer-events: auto;' })\n\n removeTempMesh()\n\n let finalReason = this.currentEndReason\n let keepMesh = true\n\n // escape: mesh 已在 cancel() 中被移除\n if (finalReason === 'escape') {\n keepMesh = false\n } else if (measureMesh.points.length < 2) {\n // points_insufficient: 点数不足,移除 mesh\n measureMesh.removeFromParent()\n finalReason = 'points_insufficient'\n keepMesh = false\n } else {\n // 保留 mesh,添加事件监听器\n this.addMeshEventListeners(measureMesh)\n }\n\n ;(measureMesh as any)['__five_pano_index'] = this.five.panoIndex\n this.currentMeasureMesh = null\n\n // Add measure listener after completing\n this.listener.removeMeasureListener()\n\n // 如果不保留 mesh,传空数组;否则传实际点数组\n this.emit('measureEnd', finalReason, keepMesh ? measureMesh.points : [])\n\n // 重置为默认原因\n this.currentEndReason = 'enter'\n }\n\n this.on('undo', undo)\n this.pointSelector.on('intersectionUpdate', onIntersectionUpdate)\n this.pointSelector.on('select', onSelect)\n this.pointSelector.on('disable', onFinished)\n\n // 开始测量\n this.pointSelector.enable()\n }\n\n /**\n * @description 结束测量\n */\n public endMeasure = () => {\n this.currentEndReason = 'external'\n this.pointSelector.disable()\n }\n\n /**\n * @description 通过Enter键结束测量\n */\n private endMeasureByEnter = () => {\n this.currentEndReason = 'enter'\n this.endMeasure()\n }\n\n /**\n * @description 通过模式改变结束测量\n */\n private endMeasureByModeChange = () => {\n this.currentEndReason = 'mode_change'\n this.endMeasure()\n }\n\n /**\n * @description 通过全景移动结束测量\n */\n private endMeasureByPanoMove = () => {\n this.currentEndReason = 'pano_move'\n this.endMeasure()\n }\n\n /**\n * @description 通过楼层改变结束测量\n */\n private endMeasureByFloorChange = () => {\n this.currentEndReason = 'floor_change'\n this.endMeasure()\n }\n\n /**\n * Enable or disable the display of length measurements\n * @param enable - Whether to display length measurements\n */\n public setLengthEnable = (enable: boolean) => {\n // Update style configurations\n this.lineStyle.lengthEnable = enable\n this.polygonStyle.lengthEnable = enable\n\n // Update all existing measurements without disrupting event listeners\n this.group.children.forEach((item) => {\n item.changeConfig({\n lineStyle: { ...this.lineStyle },\n polygonStyle: { ...this.polygonStyle },\n })\n\n // Re-add event listeners to this specific item without clearing others\n this.addMeshEventListeners(item)\n })\n\n // Update current measurement if exists\n if (this.currentMeasureMesh) {\n this.currentMeasureMesh.changeConfig({\n lineStyle: { ...this.lineStyle },\n polygonStyle: { ...this.polygonStyle },\n })\n }\n\n // Render the changes\n this.five.needsRender = true\n }\n\n /**\n * Switch the measurement unit without resetting the plugin\n * @param unit - The new unit to use ('m' for metric, 'ft' for imperial, or 'mm' for millimeters)\n */\n public setUnit = (unit: 'm' | 'ft' | 'mm') => {\n if (this._config) {\n this._config.unit = unit\n }\n\n // Update style configurations\n this.lineStyle.lengthUnit = unit\n this.polygonStyle.lengthUnit = unit\n\n // Update all existing measurements without disrupting event listeners\n this.group.children.forEach((item) => {\n try {\n item.changeConfig({\n lineStyle: { ...this.lineStyle },\n polygonStyle: { ...this.polygonStyle },\n })\n\n // Re-add event listeners to this specific item without clearing others\n this.addMeshEventListeners(item)\n } catch (error) {\n // Silent error handling\n }\n })\n\n // Update current measurement if exists\n if (this.currentMeasureMesh) {\n try {\n this.currentMeasureMesh.changeConfig({\n lineStyle: { ...this.lineStyle },\n polygonStyle: { ...this.polygonStyle },\n })\n } catch (error) {\n // Silent error handling\n }\n }\n\n // Trigger re-render to update the view\n this.five.needsRender = true\n }\n\n /**\n * Set the precision for length measurements\n * @param precision - For metric (`m`): decimal places. For imperial (`ft`): inch fraction denominator (1 | 4 | 8 | 16).\n * Area measurements remain at fixed 2 decimal places.\n */\n public setPrecision = (precision: number) => {\n if (this._config) {\n this._config.precision = precision\n }\n\n // Update style configuration (only applies to length measurements, not area)\n this.lineStyle.precision = precision\n\n // Update all existing measurements without disrupting event listeners\n this.group.children.forEach((item) => {\n try {\n item.changeConfig({\n lineStyle: { ...this.lineStyle },\n polygonStyle: { ...this.polygonStyle },\n })\n\n // Re-add event listeners to this specific item without clearing others\n this.addMeshEventListeners(item)\n } catch (error) {\n // Silent error handling\n }\n })\n\n // Update current measurement if exists\n if (this.currentMeasureMesh) {\n try {\n this.currentMeasureMesh.changeConfig({\n lineStyle: { ...this.lineStyle },\n polygonStyle: { ...this.polygonStyle },\n })\n } catch (error) {\n // Silent error handling\n }\n }\n\n // Trigger re-render to update the view\n this.five.needsRender = true\n }\n\n /**\n * @description 取消本次测量\n */\n public cancel = () => {\n this.currentEndReason = 'escape'\n this.currentMeasureMesh?.removeFromParent()\n this.pointSelector.disable()\n }\n\n /**\n * @description 撤销上一步\n */\n public undo = () => {\n this.emit('undo')\n }\n\n /**\n * @description 清空正在测量的内容\n */\n public clearCurrentMeasure = () => {\n this.currentMeasureMesh?.removeFromParent()\n this.currentMeasureMesh = null\n this.pointSelector.disable()\n }\n\n /**\n * @description 清空所有测量内容\n */\n public clear = () => {\n this.currentMeasureMesh = null\n this.pointSelector.disable()\n\n // Remove event listeners from all meshes before removing them\n this.group.children.forEach(this.removeMeshEventListeners)\n\n this.group.removeChildren()\n this.cursor.removeDeleteButton()\n }\n\n public dispose = () => {\n this.listener.removeMeasureListener()\n this.listener.removeClickListener()\n\n this.pointSelector.disable()\n\n // Dispose global touch handler\n this.disposeGlobalTouchHandler()\n\n this.clear()\n }\n\n\n private listener = {\n // 点击事件\n addClickListener: () => {\n // Instead of clearing all listeners, which causes the odd/even issue,\n // we'll add listeners to meshes that don't have them yet\n\n // Add event listeners for global events\n this.five.on('panoArrived', this.onMoveToPano)\n this.five.on('modeChange', this.onModeChange)\n hotkeys('delete, backspace', this.deleteSelectedMesh)\n\n // Ensure all existing meshes have event listeners\n this.initEventListeners()\n },\n removeClickListener: () => {\n this.group.children.forEach((item) => {\n item.line.doms?.forEach((dom) => {\n if (dom?.container) {\n dom.container.onclick = null\n dom.container.onmouseenter = null\n dom.container.onmouseleave = null\n }\n })\n if (item.polygon.areaDom?.container) {\n item.polygon.areaDom.container.onclick = null\n item.polygon.areaDom.container.onmouseenter = null\n item.polygon.areaDom.container.onmouseleave = null\n }\n })\n this.fiveDomEvents.clear()\n this.five.off('panoArrived', this.onMoveToPano)\n this.five.off('modeChange', this.onModeChange)\n hotkeys.unbind('delete, backspace')\n },\n // 绘制快捷键\n addMeasureListener: () => {\n hotkeys('ctrl+z, command+z', this.undo)\n hotkeys('esc', this.cancel)\n hotkeys('enter', this.endMeasureByEnter)\n\n this.five.on('mode.change', this.endMeasureByModeChange)\n this.five.on('pano.moveTo', this.endMeasureByPanoMove)\n this.five.on('model.changeShownFloor', this.endMeasureByFloorChange)\n },\n removeMeasureListener: () => {\n hotkeys.unbind('ctrl+z, command+z')\n hotkeys.unbind('esc')\n hotkeys.unbind('enter')\n\n this.five.off('mode.change', this.endMeasureByModeChange)\n this.five.off('pano.moveTo', this.endMeasureByPanoMove)\n this.five.off('model.changeShownFloor', this.endMeasureByFloorChange)\n },\n }\n\n private onMoveToPano = (panoIndex: number) => {\n const items = this.group.children.filter((item) => item !== this.currentMeasureMesh)\n const raycaster = new THREERaycaster()\n\n items.forEach((item) => {\n item.unselect()\n\n // 如果当前点位和item的绘制点位相同,则直接显示\n if ((item as any)['__five_pano_index'] === panoIndex) {\n item.visible = true\n return\n }\n\n // check intersect\n const needShow = item.line.points?.some((point) => {\n // raycaster.setFromCamera\n const direction = point.clone().sub(this.five.camera.position).normalize()\n raycaster.set(this.five.camera.position, direction)\n const intersect = this.five.model.intersectRaycaster(raycaster)?.[0]?.point\n if (!intersect) return true\n const distanceError = 0.01\n const distanceToPoint = point.distanceTo(this.five.camera.position)\n const distanceToIntersect = intersect.distanceTo(this.five.camera.position)\n const canSee = distanceToIntersect + distanceError > distanceToPoint\n return canSee\n })\n\n if (needShow) {\n item.visible = true\n } else {\n item.visible = false\n }\n\n this.five.needsRender = true\n })\n }\n\n private onModeChange = (mode: Mode) => {\n if (mode === 'Mapview') {\n this.group.children.forEach((item) => {\n item.visible = true\n })\n }\n }\n\n private onClick = ({ origDomEvent: event, target }: Pick<FiveDomEvent, 'origDomEvent' | 'target'>) => {\n const clickedMeasureMesh = target as MeasureMesh\n\n if (!clickedMeasureMesh) return\n\n if (clickedMeasureMesh.selected) {\n clickedMeasureMesh.unselect()\n this.cursor.removeDeleteButton()\n return\n }\n\n let clientX: number | undefined\n let clientY: number | undefined\n\n // 使用类型守卫和联合类型来处理不同类型的事件\n if (event) {\n // 检查是否为触摸事件\n if ('touches' in event && event.touches && event.touches[0]) {\n clientX = event.touches[0].clientX\n clientY = event.touches[0].clientY\n }\n // 检查是否为鼠标事件\n else if ('clientX' in event && 'clientY' in event) {\n clientX = event.clientX as number\n clientY = event.clientY as number\n }\n }\n\n if (clientX === undefined || clientY === undefined) return\n\n this.group.children.forEach((item) => item.unselect())\n\n clickedMeasureMesh.select()\n\n const deleteMesh = () => {\n // Remove event listeners before removing the mesh\n this.removeMeshEventListeners(clickedMeasureMesh)\n\n // Remove the mesh\n clickedMeasureMesh.removeFromParent()\n this.cursor.removeDeleteButton()\n this.five.needsRender = true\n }\n\n // 获取容器元素,添加 fallback\n const containerElement = this.five.getElement()?.parentElement || document.body\n\n this.cursor.showDeleteButton({\n clientX,\n clientY,\n container: containerElement,\n onClick: deleteMesh,\n })\n\n this.five.once('cameraUpdate', () => {\n clickedMeasureMesh.unselect()\n this.cursor.removeDeleteButton()\n })\n }\n\n private onHover = ({ target }: Pick<FiveDomEvent, 'target'>) => {\n if (this.currentMeasureMesh) return\n\n const hoveredMeasureMesh = target as MeasureMesh\n if (!hoveredMeasureMesh) return\n hoveredMeasureMesh.hover()\n }\n\n private onUnHover = ({ target }: Pick<FiveDomEvent, 'target'>) => {\n if (this.currentMeasureMesh) return\n\n const unHoveredMeasureMesh = target as MeasureMesh\n if (!unHoveredMeasureMesh) return\n unHoveredMeasureMesh.unhover()\n }\n\n private deleteSelectedMesh = () => {\n const needsDeleteMeshes = this.group.children.filter((item) => item.selected)\n\n needsDeleteMeshes.forEach((item) => {\n // Remove event listeners before removing the mesh\n this.removeMeshEventListeners(item)\n\n // Remove the mesh\n item.removeFromParent()\n })\n\n this.cursor.removeDeleteButton()\n this.five.needsRender = true\n }\n\n // Helper method to remove all event listeners from a mesh\n private removeMeshEventListeners = (item: MeasureMesh) => {\n // Remove long press listeners from endpoints\n item.line.pointMeshes?.forEach((pointMesh) => {\n const cleanup = (pointMesh as any).__longPressCleanup\n if (cleanup) {\n cleanup()\n delete (pointMesh as any).__longPressCleanup\n }\n })\n\n // Remove DOM event listeners\n item.line.doms?.forEach((dom) => {\n if (dom?.container) {\n dom.container.onclick = null\n dom.container.onmouseenter = null\n dom.container.onmouseleave = null\n }\n })\n\n if (item.polygon.areaDom?.container) {\n item.polygon.areaDom.container.onclick = null\n item.polygon.areaDom.container.onmouseenter = null\n item.polygon.areaDom.container.onmouseleave = null\n }\n\n // Remove THREE.js event listeners\n this.fiveDomEvents.removeEventListener(item, 'click')\n this.fiveDomEvents.removeEventListener(item, 'hover')\n this.fiveDomEvents.removeEventListener(item, 'unHover')\n }\n\n private updateSelectAdsorbedHelper = () => {\n if (!this.currentMeasureMesh || this.currentMeasureMesh.points.length === 0) {\n this.pointSelector.setAdherePoints(null)\n this.pointSelector.adhereLine = []\n this.pointSelector.adherePlane = []\n return\n }\n\n if (this.currentMeasureMesh.points.length >= 1) {\n this.pointSelector.setAdherePoints([this.currentMeasureMesh.points[0]])\n const lastPoint = this.currentMeasureMesh.points.at(-1)\n // xyz三轴吸附\n this.pointSelector.adhereLine = [\n new THREE.Line3(new THREE.Vector3(1, 0, 0).add(lastPoint), new THREE.Vector3(-1, 0, 0).add(lastPoint)),\n new THREE.Line3(new THREE.Vector3(0, 1, 0).add(lastPoint), new THREE.Vector3(0, -1, 0).add(lastPoint)),\n new THREE.Line3(new THREE.Vector3(0, 0, 1).add(lastPoint), new THREE.Vector3(0, 0, -1).add(lastPoint)),\n ]\n this.pointSelector.adherePlane = []\n }\n\n if (this.currentMeasureMesh.points.length >= 3) {\n const plane = new THREE.Plane().setFromCoplanarPoints(\n this.currentMeasureMesh.points[0],\n this.currentMeasureMesh.points[1],\n this.currentMeasureMesh.points[2],\n )\n this.pointSelector.adherePlane = [plane]\n } else {\n this.pointSelector.adherePlane = []\n }\n }\n\n private addMeshEventListeners = (item: MeasureMesh) => {\n // First remove any existing event listeners to prevent duplicates\n this.removeMeshEventListeners(item)\n\n // Add long press functionality to endpoints\n this.addEndpointLongPressListeners(item)\n\n // Add DOM event listeners for labels\n item.line.doms?.forEach((dom) => {\n if (dom?.container) {\n dom.container.onclick = (event) => this.onClick({ origDomEvent: event, target: item })\n dom.container.onmouseenter = () => this.onHover({ target: item })\n dom.container.onmouseleave = () => this.onUnHover({ target: item })\n }\n })\n\n if (item.polygon.areaDom?.container) {\n item.polygon.areaDom.container.onclick = (event) => this.onClick({ origDomEvent: event, target: item })\n item.polygon.areaDom.container.onmouseenter = () => this.onHover({ target: item })\n item.polygon.areaDom.container.onmouseleave = () => this.onUnHover({ target: item })\n }\n\n // Add THREE.js event listeners for the mesh\n this.fiveDomEvents.addEventListener(item, 'click', this.onClick)\n this.fiveDomEvents.addEventListener(item, 'hover', this.onHover)\n this.fiveDomEvents.addEventListener(item, 'unHover', this.onUnHover)\n }\n\n private addEndpointLongPressListeners = (item: MeasureMesh) => {\n // Setup global touch handler if not already done\n this.setupGlobalTouchHandler()\n\n // Add long press functionality to each endpoint\n item.line.pointMeshes.forEach((pointMesh, index) => {\n let pressTimer: NodeJS.Timeout | undefined\n let isLongPressTriggered = false\n\n // For closed polygons, we need to map point mesh index to actual point index\n // In closed polygons, the last point is a duplicate of the first point\n let actualPointIndex = index\n if (item.isPolygon && item.points.length > 3) {\n // For closed polygons, if this is the last point mesh, it corresponds to point index 0\n if (index === item.line.pointMeshes.length - 1) {\n actualPointIndex = 0\n }\n // Also handle case where there are extra point meshes due to geometry recreation\n if (index >= item.points.length) {\n actualPointIndex = 0 // Map any extra point meshes to the first point\n }\n }\n\n // Unified handler for mouse and touch down events\n const onPointerDown = (event: FiveDomEvent) => {\n // Don't activate repositioning if we're currently drawing a measurement\n if (this.currentMeasureMesh) {\n return\n }\n\n isLongPressTriggered = false\n\n // Store initial pointer position for drag detection\n let pointerDownPosition: { x: number; y: number } | null = null\n if (event.origDomEvent) {\n if ('clientX' in event.origDomEvent && 'clientY' in event.origDomEvent) {\n // Mouse event\n pointerDownPosition = {\n x: event.origDomEvent.clientX as number,\n y: event.origDomEvent.clientY as number,\n }\n } else if ('touches' in event.origDomEvent && event.origDomEvent.touches && event.origDomEvent.touches[0]) {\n // Touch event\n pointerDownPosition = {\n x: event.origDomEvent.touches[0].clientX,\n y: event.origDomEvent.touches[0].clientY,\n }\n } else if ('changedTouches' in event.origDomEvent && event.origDomEvent.changedTouches && event.origDomEvent.changedTouches[0]) {\n // Touch end event uses changedTouches\n pointerDownPosition = {\n x: event.origDomEvent.changedTouches[0].clientX,\n y: event.origDomEvent.changedTouches[0].clientY,\n }\n }\n }\n\n // Prevent Five canvas events during long press\n event.stopPropagation()\n if (event.origDomEvent) {\n event.origDomEvent.preventDefault()\n event.origDomEvent.stopPropagation()\n }\n\n // Show long press visual feedback\n this.showLongPressIndicator(pointMesh, pointerDownPosition)\n\n // Add global pointer move listener to detect movement away from button\n const globalMoveHandler = (e: MouseEvent | TouchEvent) => {\n if (pointerDownPosition) {\n let clientX: number, clientY: number\n if ('touches' in e && e.touches[0]) {\n clientX = e.touches[0].clientX\n clientY = e.touches[0].clientY\n } else if ('clientX' in e) {\n clientX = e.clientX\n clientY = e.clientY\n } else {\n return\n }\n\n const distance = Math.sqrt(Math.pow(clientX - pointerDownPosition.x, 2) + Math.pow(clientY - pointerDownPosition.y, 2))\n // If pointer moves more than 10 pixels away, cancel long press\n if (distance > 10) {\n this.hideLongPressIndicator()\n if (pressTimer) {\n clearTimeout(pressTimer)\n pressTimer = undefined\n }\n this.cleanupGlobalListeners?.()\n }\n }\n }\n\n // Store cleanup function for easy access\n this.cleanupGlobalListeners = () => {\n document.removeEventListener('mousemove', globalMoveHandler as EventListener)\n document.removeEventListener('touchmove', globalMoveHandler as EventListener)\n }\n\n document.addEventListener('mousemove', globalMoveHandler as EventListener)\n document.addEventListener('touchmove', globalMoveHandler as EventListener, { passive: false })\n\n pressTimer = setTimeout(() => {\n isLongPressTriggered = true\n this.cleanupGlobalListeners?.()\n\n // Hide the indicator when repositioning starts\n this.hideLongPressIndicator()\n\n // Start repositioning mode with pointer position tracking - use actualPointIndex\n this.startRepositioning(item, actualPointIndex, true, pointerDownPosition) // Set isDragMode to true\n }, 500) // 500ms for long press\n }\n\n const onPointerUp = () => {\n if (pressTimer) {\n clearTimeout(pressTimer)\n pressTimer = undefined\n }\n\n // Clean up global move listeners\n this.cleanupGlobalListeners?.()\n\n // Hide the indicator if still showing\n this.hideLongPressIndicator()\n\n // If we were in repositioning mode and pointer was released\n if (isLongPressTriggered && this.repositioningState) {\n if (this.repositioningState.isDragMode && this.repositioningState.hasMoved) {\n // Let the global pointer up handler confirm the repositioning\n } else if (!this.repositioningState.isDragMode) {\n // Click mode - stay in repositioning for point-and-click\n }\n isLongPressTriggered = false\n }\n }\n\n const onClick = (event: FiveDomEvent) => {\n // Prevent normal click action if long press was triggered\n if (isLongPressTriggered) {\n event.stopPropagation()\n isLongPressTriggered = false\n return false\n }\n }\n\n // Add event listeners to the point mesh for mouse events\n this.fiveDomEvents.addEventListener(pointMesh, 'mousedown', onPointerDown)\n this.fiveDomEvents.addEventListener(pointMesh, 'mouseup', onPointerUp)\n this.fiveDomEvents.addEventListener(pointMesh, 'click', onClick)\n\n // Store reference to handlers for touch events (handled by global touch handler)\n // Use actualPointIndex instead of loop index\n ;(pointMesh as any).__longPressHandlers = {\n onPointerDown,\n onPointerUp,\n onClick,\n measureMesh: item,\n pointIndex: actualPointIndex, // Use the corrected point index\n }\n\n // Store cleanup function\n ;(pointMesh as any).__longPressCleanup = () => {\n if (pressTimer) {\n clearTimeout(pressTimer)\n }\n this.cleanupGlobalListeners?.()\n this.hideLongPressIndicator()\n this.fiveDomEvents.removeEventListener(pointMesh, 'mousedown', onPointerDown)\n this.fiveDomEvents.removeEventListener(pointMesh, 'mouseup', onPointerUp)\n this.fiveDomEvents.removeEventListener(pointMesh, 'click', onClick)\n\n // Remove handler references\n delete (pointMesh as any).__longPressHandlers\n }\n })\n }\n\n /**\n * @description Load measurement data from external source\n * @param data Array of point data for measurements\n */\n public load = (data: { points: THREE.Vector3[] }[]) => {\n // Clear existing measurements\n this.clear()\n\n // Create new meshes from the data\n data.forEach((item) => {\n const measureMesh = new MeasureMesh({\n lineStyle: this.lineStyle,\n polygonStyle: this.polygonStyle,\n })\n\n // Labels inherit the Five owner from the scene parent.\n this.group.add(measureMesh)\n measureMesh.setPoints(item.points)\n\n // Add event listeners to the loaded mesh\n this.addMeshEventListeners(measureMesh)\n\n // Set pano index\n ;(measureMesh as any)['__five_pano_index'] = this.five.panoIndex\n })\n\n this.five.needsRender = true\n }\n\n /**\n * Start repositioning an endpoint\n */\n private startRepositioning = (\n measureMesh: MeasureMesh,\n pointIndex: number,\n isDragMode = false,\n mouseDownPosition?: { x: number; y: number } | null,\n ) => {\n // Don't start repositioning if already in measure mode or already repositioning\n if (this.currentMeasureMesh || this.repositioningState) {\n return\n }\n\n // Store original state\n this.repositioningState = {\n measureMesh,\n pointIndex,\n originalOpacity: measureMesh.line.lineOpacity,\n originalMeshState: measureMesh.points.map((p) => p.clone()),\n isDragMode,\n mouseDownPosition: mouseDownPosition || undefined,\n hasMoved: false,\n }\n\n // Apply preview styling (lower opacity, dashed lines)\n this.applyRepositioningStyle(measureMesh, true)\n\n // Prevent Five canvas interactions during repositioning\n this.five.on('wantsGesture', this.preventFiveGestures)\n\n if (isDragMode) {\n // For drag mode, use global mouse events since PointSelector stops when mouse is held down\n this.enableGlobalMouseTracking()\n } else {\n // For click mode, use PointSelector normally\n this.pointSelector.actionIfNoIntersection = 'virtualPoint'\n this.pointSelector.enable()\n this.pointSelector.on('intersectionUpdate', this.onRepositioningMove)\n this.pointSelector.on('select', this.onRepositioningConfirm)\n this.pointSelector.on('disable', this.cancelRepositioning)\n }\n\n // Add escape key listener\n hotkeys('esc', this.cancelRepositioning)\n }\n\n /**\n * Helper method to safely update polygon points while maintaining closure\n */\n private updatePolygonPoints = (\n measureMesh: MeasureMesh,\n newPoints: THREE.Vector3[],\n updatedPointIndex?: number,\n isLiveUpdate = false,\n ) => {\n // Ensure polygon closure is maintained for closed polygons\n if (measureMesh.isPolygon && newPoints.length > 3 && updatedPointIndex !== undefined) {\n const lastPointIndex = newPoints.length - 1\n\n // If updating first point, also update last point\n if (updatedPointIndex === 0) {\n newPoints[lastPointIndex] = newPoints[0].clone()\n }\n // If updating last point, also update first point\n else if (updatedPointIndex === lastPointIndex) {\n newPoints[0] = newPoints[lastPointIndex].clone()\n }\n }\n\n // Update internal points array\n measureMesh.points = newPoints\n\n if (isLiveUpdate && this.repositioningState) {\n // During live repositioning, update geometry directly without recreating point meshes\n // This prevents interference with ongoing repositioning\n\n // Update line geometry manually\n const lineMesh = measureMesh.line as any\n lineMesh.points = newPoints\n\n if (newPoints.length >= 2) {\n const positions = newPoints.flatMap((v) => [v.x, v.y, v.z])\n lineMesh.line1.geometry.setPositions(positions)\n lineMesh.line1.computeLineDistances()\n }\n\n // Update point mesh positions visually so they follow the mouse\n if (updatedPointIndex !== undefined && measureMesh.line.pointMeshes) {\n const updatedPosition = newPoints[updatedPointIndex]\n\n // For closed polygons, handle first/last point synchronization\n if (measureMesh.isPolygon && newPoints.length > 3) {\n const lastPointIndex = newPoints.length - 1\n\n if (updatedPointIndex === 0) {\n // Moving first point, also move last point mesh\n const firstPointMesh = measureMesh.line.pointMeshes[0]\n const lastPointMesh = measureMesh.line.pointMeshes[lastPointIndex]\n if (firstPointMesh) firstPointMesh.position.copy(updatedPosition)\n if (lastPointMesh) lastPointMesh.position.copy(updatedPosition)\n } else if (updatedPointIndex === lastPointIndex) {\n // Moving last point, also move first point mesh\n const firstPointMesh = measureMesh.line.pointMeshes[0]\n const lastPointMesh = measureMesh.line.pointMeshes[lastPointIndex]\n if (firstPointMesh) firstPointMesh.position.copy(updatedPosition)\n if (lastPointMesh) lastPointMesh.position.copy(updatedPosition)\n } else {\n // Moving a middle point\n const pointMesh = measureMesh.line.pointMeshes[updatedPointIndex]\n if (pointMesh) pointMesh.position.copy(updatedPosition)\n }\n } else {\n // Not a closed polygon, just update the single point\n const pointMesh = measureMesh.line.pointMeshes[updatedPointIndex]\n if (pointMesh) pointMesh.position.copy(updatedPosition)\n }\n }\n\n // Update polygon geometry if it exists\n if (measureMesh.isPolygon) {\n measureMesh.polygon.setPoints(newPoints)\n }\n } else {\n // When not in live update mode (final confirmation), use proper setPoints\n // This ensures all meshes are properly recreated\n measureMesh.line.setPoints(newPoints)\n\n if (measureMesh.isPolygon) {\n measureMesh.polygon.setPoints(newPoints)\n }\n }\n }\n\n /**\n * Handle mouse movement during repositioning\n */\n private onRepositioningMove = (intersection?: PointIntersection) => {\n if (!this.repositioningState || !intersection) {\n return\n }\n\n const { measureMesh, pointIndex } = this.repositioningState\n\n // Mark that mouse has moved (any intersection update means movement)\n this.repositioningState.hasMoved = true\n\n // Create new points array\n const newPoints = [...measureMesh.points]\n newPoints[pointIndex] = intersection.point.clone()\n\n // Use the helper method with live update mode to avoid recreating point meshes\n this.updatePolygonPoints(measureMesh, newPoints, pointIndex, true)\n\n this.five.needsRender = true\n }\n\n /**\n * Confirm repositioning with click\n */\n private onRepositioningConfirm = (intersection?: PointIntersection) => {\n if (!this.repositioningState || !intersection) return\n\n const { measureMesh, pointIndex } = this.repositioningState\n\n // Finalize the position\n const newPoints = [...measureMesh.points]\n newPoints[pointIndex] = intersection.point.clone()\n\n // Use helper method in final mode to properly recreate point meshes\n this.updatePolygonPoints(measureMesh, newPoints, pointIndex, false)\n\n // Restore normal styling\n this.applyRepositioningStyle(measureMesh, false)\n\n // Re-add event listeners since setPoints() recreates pointMeshes\n this.addEndpointLongPressListeners(measureMesh)\n\n // Clean up repositioning state\n this.cleanupRepositioning()\n }\n\n /**\n * Confirm repositioning when drag ends (mouse up after long press drag)\n */\n private confirmRepositioningOnDragEnd = () => {\n if (!this.repositioningState) return\n\n const { measureMesh, pointIndex } = this.repositioningState\n\n // Use the current position (already updated by onRepositioningMove)\n // Apply the helper method in final mode to ensure proper point mesh recreation\n const finalPoints = [...measureMesh.points]\n this.updatePolygonPoints(measureMesh, finalPoints, pointIndex, false)\n\n // Restore normal styling\n this.applyRepositioningStyle(measureMesh, false)\n\n // Re-add event listeners since setPoints() recreates pointMeshes\n this.addEndpointLongPressListeners(measureMesh)\n\n // Clean up repositioning state\n this.cleanupRepositioning()\n }\n\n /**\n * Cancel repositioning (restore original position)\n */\n private cancelRepositioning = () => {\n if (!this.repositioningState) return\n\n const { measureMesh, originalMeshState } = this.repositioningState\n\n // Restore original points using the helper method in final mode to properly recreate point meshes\n this.updatePolygonPoints(measureMesh, originalMeshState, undefined, false)\n\n // Restore normal styling\n this.applyRepositioningStyle(measureMesh, false)\n\n // Re-add event listeners since setPoints() recreates pointMeshes\n this.addEndpointLongPressListeners(measureMesh)\n\n // Clean up repositioning state\n this.cleanupRepositioning()\n }\n\n /**\n * Apply or remove repositioning preview styling\n */\n private applyRepositioningStyle = (measureMesh: MeasureMesh, isRepositioning: boolean) => {\n const opacity = isRepositioning ? 0.4 : 1.0\n const dashed = isRepositioning\n\n // Apply to line\n measureMesh.line.setStyle({\n lineOpacity: opacity,\n dashed: dashed,\n cssStyle: isRepositioning ? 'pointer-events: none;' : 'pointer-events: auto;',\n })\n\n // Apply to polygon if exists\n if (measureMesh.isPolygon) {\n measureMesh.polygon.setStyle({\n opacity: opacity * 0.3, // Even more transparent for area\n })\n }\n\n // Apply to endpoints\n measureMesh.line.pointMeshes.forEach((pointMesh) => {\n pointMesh.setStyle({\n opacity: opacity,\n })\n })\n }\n\n /**\n * Enable global mouse tracking for drag mode (when PointSelector can't track due to mouse being held down)\n */\n private enableGlobalMouseTracking = () => {\n const fiveElement = this.five.getElement()\n if (!fiveElement) return\n\n let currentIntersection: any = null\n\n const onGlobalMouseMove = (event: MouseEvent) => {\n if (!this.repositioningState) return\n\n // Convert mouse position to NDC coordinates\n const rect = fiveElement.getBoundingClientRect()\n const x = ((event.clientX - rect.left) / rect.width) * 2 - 1\n const y = -((event.clientY - rect.top) / rect.height) * 2 + 1\n\n // Create raycaster from mouse position\n const raycaster = new THREE.Raycaster()\n raycaster.setFromCamera(new THREE.Vector2(x, y), this.five.camera)\n\n // Get intersection with model\n const intersects = this.five.model.intersectRaycaster(raycaster)\n if (intersects && intersects.length > 0) {\n currentIntersection = {\n point: intersects[0].point,\n distance: intersects[0].distance,\n face: intersects[0].face,\n raycaster,\n }\n this.onRepositioningMove(currentIntersection)\n } else {\n // Create virtual point if no model intersection\n const virtualPoint = raycaster.ray.origin.clone().add(raycaster.ray.direction.clone().multiplyScalar(5))\n currentIntersection = {\n point: virtualPoint,\n distance: 5,\n raycaster,\n isVirtual: true,\n }\n this.onRepositioningMove(currentIntersection)\n }\n }\n\n const onGlobalTouchMove = (event: TouchEvent) => {\n if (!this.repositioningState || !event.touches[0]) return\n\n // Convert touch position to NDC coordinates\n const rect = fiveElement.getBoundingClientRect()\n const touch = event.touches[0]\n const x = ((touch.clientX - rect.left) / rect.width) * 2 - 1\n const y = -((touch.clientY - rect.top) / rect.height) * 2 + 1\n\n // Create raycaster from touch position\n const raycaster = new THREE.Raycaster()\n raycaster.setFromCamera(new THREE.Vector2(x, y), this.five.camera)\n\n // Get intersection with model\n const intersects = this.five.model.intersectRaycaster(raycaster)\n if (intersects && intersects.length > 0) {\n currentIntersection = {\n point: intersects[0].point,\n distance: intersects[0].distance,\n face: intersects[0].face,\n raycaster,\n }\n this.onRepositioningMove(currentIntersection)\n } else {\n // Create virtual point if no model intersection\n const virtualPoint = raycaster.ray.origin.clone().add(raycaster.ray.direction.clone().multiplyScalar(5))\n currentIntersection = {\n point: virtualPoint,\n distance: 5,\n raycaster,\n isVirtual: true,\n }\n this.onRepositioningMove(currentIntersection)\n }\n }\n\n const onGlobalMouseUp = (event: MouseEvent) => {\n if (!this.repositioningState) return\n\n // Confirm repositioning with current position\n if (currentIntersection) {\n this.onRepositioningConfirm(currentIntersection)\n } else {\n // Fallback: confirm with current position\n this.confirmRepositioningOnDragEnd()\n }\n }\n\n const onGlobalTouchEnd = (event: TouchEvent) => {\n if (!this.repositioningState) return\n\n // Confirm repositioning with current position\n if (currentIntersection) {\n this.onRepositioningConfirm(currentIntersection)\n } else {\n // Fallback: confirm with current position\n this.confirmRepositioningOnDragEnd()\n }\n }\n\n const onGlobalClick = (event: MouseEvent) => {\n if (!this.repositioningState) return\n\n if (currentIntersection) {\n this.onRepositioningConfirm(currentIntersection)\n }\n }\n\n // Add global event listeners for both mouse and touch\n document.addEventListener('mousemove', onGlobalMouseMove)\n document.addEventListener('mouseup', onGlobalMouseUp)\n document.addEventListener('click', onGlobalClick)\n document.addEventListener('touchmove', onGlobalTouchMove, { passive: false })\n document.addEventListener('touchend', onGlobalTouchEnd, { passive: false })\n\n // Store cleanup function\n ;(this.repositioningState as any).__globalMouseCleanup = () => {\n document.removeEventListener('mousemove', onGlobalMouseMove)\n document.removeEventListener('mouseup', onGlobalMouseUp)\n document.removeEventListener('click', onGlobalClick)\n document.removeEventListener('touchmove', onGlobalTouchMove)\n document.removeEventListener('touchend', onGlobalTouchEnd)\n }\n }\n\n /**\n * Show long press visual feedback circle\n */\n private showLongPressIndicator = (pointMesh: PointMesh, mousePosition?: { x: number; y: number } | null) => {\n // Hide any existing indicator first\n this.hideLongPressIndicator()\n\n const fiveElement = this.five.getElement()\n if (!fiveElement) return\n\n // Prevent Five gestures while indicator is showing\n this.five.on('wantsGesture', this.preventFiveGestures)\n\n // Create indicator element\n const indicator = document.createElement('div')\n indicator.style.position = 'absolute'\n indicator.style.width = '80px'\n indicator.style.height = '80px'\n indicator.style.border = '6px solid #f0f0f0'\n indicator.style.borderRadius = '50%'\n indicator.style.pointerEvents = 'none'\n indicator.style.zIndex = '10000'\n indicator.style.boxSizing = 'border-box'\n indicator.style.animation = 'longPressShrink 500ms linear forwards'\n\n // Add CSS animation keyframes if not already added\n if (!document.querySelector('#longpress-keyframes')) {\n const style = document.createElement('style')\n style.id = 'longpress-keyframes'\n style.textContent = `\n @keyframes longPressShrink {\n from {\n transform: translate(-50%, -50%) scale(1);\n opacity: 0.8;\n }\n to {\n transform: translate(-50%, -50%) scale(0);\n opacity: 1;\n }\n }\n `\n document.head.appendChild(style)\n }\n\n // Position the indicator\n if (mousePosition) {\n indicator.style.left = `${mousePosition.x}px`\n indicator.style.top = `${mousePosition.y}px`\n indicator.style.transform = 'translate(-50%, -50%)'\n } else {\n // Fallback: position at point mesh screen position\n const pointWorldPosition = pointMesh.getWorldPosition(new THREE.Vector3())\n const pointScreenPosition = pointWorldPosition.clone().project(this.five.camera)\n const rect = fiveElement.getBoundingClientRect()\n\n const x = ((pointScreenPosition.x + 1) * rect.width) / 2 + rect.left\n const y = ((-pointScreenPosition.y + 1) * rect.height) / 2 + rect.top\n\n indicator.style.left = `${x}px`\n indicator.style.top = `${y}px`\n indicator.style.transform = 'translate(-50%, -50%)'\n }\n\n // Add to page\n document.body.appendChild(indicator)\n this.longPressIndicator = indicator\n }\n\n /**\n * Hide long press visual feedback circle\n */\n private hideLongPressIndicator = () => {\n if (this.longPressIndicator) {\n this.longPressIndicator.remove()\n this.longPressIndicator = null\n\n // Re-enable Five gestures when indicator is hidden\n this.five.off('wantsGesture', this.preventFiveGestures)\n }\n }\n\n /**\n * Prevent Five canvas gestures during repositioning\n */\n private preventFiveGestures = (): false => {\n return false // Prevent all Five gestures during repositioning\n }\n\n /**\n * Clean up repositioning state and event listeners\n */\n private cleanupRepositioning = () => {\n if (this.repositioningState) {\n // Clean up global mouse tracking if it was enabled\n const globalMouseCleanup = (this.repositioningState as any).__globalMouseCleanup\n if (globalMouseCleanup) {\n globalMouseCleanup()\n }\n\n // Clean up PointSelector if it was used (click mode)\n if (!this.repositioningState.isDragMode) {\n this.pointSelector.off('intersectionUpdate', this.onRepositioningMove)\n this.pointSelector.off('select', this.onRepositioningConfirm)\n this.pointSelector.off('disable', this.cancelRepositioning)\n this.pointSelector.disable()\n }\n }\n\n // Remove Five gesture prevention\n this.five.off('wantsGesture', this.preventFiveGestures)\n\n // Remove escape key listener\n hotkeys.unbind('esc', this.cancelRepositioning)\n\n this.repositioningState = null\n this.five.needsRender = true\n }\n\n private setupGlobalTouchHandler = () => {\n if (this.globalTouchHandler?.isSetup) return\n\n const fiveElement = this.five.getElement()\n if (!fiveElement) return\n\n const onGlobalTouchStart = (e: TouchEvent) => {\n if (this.currentMeasureMesh) return // Don't activate during drawing\n\n const touch = e.touches[0]\n if (!touch) return\n\n // Check if touch is on any point mesh by doing raycasting\n const rect = fiveElement.getBoundingClientRect()\n const x = ((touch.clientX - rect.left) / rect.width) * 2 - 1\n const y = -((touch.clientY - rect.top) / rect.height) * 2 + 1\n\n const raycaster = new THREE.Raycaster()\n raycaster.setFromCamera(new THREE.Vector2(x, y), this.five.camera)\n\n // Configure raycaster for different types of geometry\n // Points (used by PointMesh) need a higher threshold for reliable detection\n raycaster.params.Points.threshold = 0.5 // Increased threshold for better point detection\n raycaster.params.Line.threshold = 0.1\n raycaster.params.Mesh = {}\n\n // Collect all potential hits with their distances\n const allHits: { pointMesh: any; handlers: any; distance: number; measureMesh: any; pointIndex: number }[] = []\n\n // Check all point meshes from all measurements\n for (const measureMesh of this.group.children) {\n // Safety check: ensure measureMesh and its line property exist\n if (!measureMesh || !measureMesh.line || !measureMesh.line.pointMeshes) {\n continue\n }\n\n for (let loopIndex = 0; loopIndex < measureMesh.line.pointMeshes.length; loopIndex++) {\n const pointMesh = measureMesh.line.pointMeshes[loopIndex]\n if (!pointMesh) continue\n\n // PointMesh has fontMesh and backgroundMesh children - intersect with both\n const intersects = raycaster.intersectObject(pointMesh, true) // true = recursive to check children\n if (intersects.length > 0) {\n const handlers = (pointMesh as any).__longPressHandlers\n if (handlers) {\n // For point intersections, distance checking is less reliable\n // Instead, let's rely on the raycaster threshold and screen distance\n const screenDistance = this.calculateScreenDistance(touch, pointMesh, fiveElement)\n\n if (screenDistance < 30) {\n // Within 30 pixels on screen\n allHits.push({\n pointMesh,\n handlers,\n distance: screenDistance, // Use screen distance for sorting\n measureMesh: handlers.measureMesh,\n pointIndex: handlers.pointIndex, // Use the STORED pointIndex, not the loop index\n })\n }\n }\n }\n }\n }\n\n if (allHits.length > 0) {\n // Sort by screen distance (closest first) and take the closest hit\n allHits.sort((a, b) => a.distance - b.distance)\n const closestHit = allHits[0]\n\n // Don't start if already repositioning\n if (this.repositioningState) {\n return\n }\n\n // Create a synthetic FiveDomEvent\n const syntheticEvent: FiveDomEvent = {\n type: 'mousedown',\n target: closestHit.pointMesh,\n origDomEvent: e,\n raycaster,\n intersects: [{ distance: 0 }] as any, // Use dummy distance since we're using screen distance\n stopPropagation: () => {\n e.stopPropagation()\n },\n }\n\n // Additional validation before calling handler\n if (closestHit.handlers && typeof closestHit.handlers.onPointerDown === 'function') {\n closestHit.handlers.onPointerDown(syntheticEvent)\n }\n }\n }\n\n const onGlobalTouchEnd = (e: TouchEvent) => {\n // Only call onPointerUp for handlers that actually exist and are valid\n // We need to be more careful here to avoid the undefined error\n for (const measureMesh of this.group.children) {\n // Safety check: ensure measureMesh and its line property exist\n if (!measureMesh || !measureMesh.line || !measureMesh.line.pointMeshes) {\n continue\n }\n\n for (const pointMesh of measureMesh.line.pointMeshes) {\n if (!pointMesh) continue\n\n const handlers = (pointMesh as any).__longPressHandlers\n if (handlers && typeof handlers.onPointerUp === 'function') {\n handlers.onPointerUp()\n }\n }\n }\n }\n\n // Add global touch listeners to the Five canvas element\n fiveElement.addEventListener('touchstart', onGlobalTouchStart, { passive: false })\n fiveElement.addEventListener('touchend', onGlobalTouchEnd, { passive: false })\n\n this.globalTouchHandler = {\n isSetup: true,\n onTouchStart: onGlobalTouchStart,\n onTouchEnd: onGlobalTouchEnd,\n }\n }\n\n // Remove the stub methods since they're not needed\n private disposeGlobalTouchHandler = () => {\n if (this.globalTouchHandler?.isSetup) {\n const fiveElement = this.five.getElement()\n if (fiveElement) {\n fiveElement.removeEventListener('touchstart', this.globalTouchHandler.onTouchStart)\n fiveElement.removeEventListener('touchend', this.globalTouchHandler.onTouchEnd)\n }\n this.globalTouchHandler = null\n }\n }\n\n /**\n * Calculate screen distance between touch/mouse point and point mesh\n */\n private calculateScreenDistance = (\n pointer: Touch | { clientX: number; clientY: number },\n pointMesh: any,\n fiveElement: HTMLElement,\n ): number => {\n // Get pointer position in screen coordinates\n const pointerX = pointer.clientX\n const pointerY = pointer.clientY\n\n // Get point mesh world position\n const worldPosition = pointMesh.getWorldPosition(new THREE.Vector3())\n\n // Project world position to screen coordinates\n const screenPosition = worldPosition.clone().project(this.five.camera)\n\n // Convert NDC to screen pixels\n const rect = fiveElement.getBoundingClientRect()\n const screenX = ((screenPosition.x + 1) * rect.width) / 2 + rect.left\n const screenY = ((-screenPosition.y + 1) * rect.height) / 2 + rect.top\n\n // Calculate distance in pixels\n const dx = pointerX - screenX\n const dy = pointerY - screenY\n return Math.sqrt(dx * dx + dy * dy)\n }\n}\n","import type { Five } from '@realsee/five-webgpu'\nimport { MeasureController } from './Controller'\n\nexport type MeasurePluginConfig = {\n unit: 'm' | 'ft' | 'mm'\n lengthEnable?: boolean\n /**\n * @description Length label precision.\n * - When unit is `m`: number of decimal places.\n * - When unit is `ft`: inch fraction denominator (`1` | `4` | `8` | `16` for 1\" / 1/4\" / 1/8\" / 1/16\").\n * Area measurements remain at fixed 2 decimal places.\n * @default 2\n */\n precision?: number\n}\n\n// 导出测量相关类型\nexport type { MeasureEndReason, MeasurePluginEventMap } from './Controller'\n\n// 导出多边形验证工具函数\nexport { validatePolygon } from './utils/validatePolygon'\n\nexport const MeasurePlugin = (five: Five, config?: MeasurePluginConfig) => new MeasureController(five, config)\n"],"ignoreList":[2],"mappings":"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"}
1
+ {"version":3,"file":"measure-B4jFwdQ6.js","names":["Subscribe","PointSelector","bindFiveOwner","LineMesh","IObject3D","THREERaycaster","FiveDomEvents","Cursor","vectorIsEqual","PointMesh","LineWithDotsMesh","PolygonMesh","THREE","validatePolygon","points","isLine","vector01","i","vector","plane","index","point","MeasureMesh","config","isPolygon","isff","addEvent","object","event","method","useCapture","removeEvent","getMods","modsKeys","key","modsCodes","modifier","getKeys","keys","compareArray","arr1","a1","a2","arr2","isIndex","getLayoutIndependentKeyCode","eventKey","keyMap","modifierMap2","_keyMap","_modifier","modifierMap","_mods","_handlers","k","_downKeys","winListendFocus","winListendFullscreen","_scope","elementEventMap","code","x","getKey","getModifier","setScope","scope","getScope","getPressedKeyCodes","getPressedKeyString","c","getAllKeyCodes","result","v","filter","target","flag","isInput","tagName","isPressed","keyCode","deleteScope","handlers","removeKeyEvent","element","newScope","clearModifier","unbind","args","keysInfo","eachUnbind","info","unbindKeys","originKey","splitKey","len","lastKey","mods","unbindElements","isUnbind","record","eventHandler","handler","modifiersMatch","y","dispatch","asterisk","hotkeys","keyNum","keyName","e","handlerKey","keyLen","keyShortcut","_downKeysCurrent","a","hotkeys2","keyup","keydown","capture","single","option","opts","currentKey","finalKey","keydownListener","keyupListenr","listener","onFullscreenChange","fullscreenListener","webkitListener","trigger","item","shortcut","data","values","el","_api","_hotkeys","deep","MeasureController","five","defaultConfig","measureMesh","temp_previewPoint","temp_previewLine","temp_previewPolygon","temp_verticalLine1","temp_verticalLine2","temp_verticalPoint","currentVerticalPoint","isRightTriangleShowing","isShiftPressed","onKeyDown","onKeyUp","removeTempMesh","onIntersectionUpdate","intersection","lastPoint","verticalPoint","onSelect","targetPoint","undo","onFinished","finalReason","keepMesh","\"__five_pano_index\"","enable","unit","precision","dom","items","raycaster","panoIndex","direction","intersect","distanceToPoint","mode","clickedMeasureMesh","clientX","clientY","deleteMesh","containerElement","hoveredMeasureMesh","unHoveredMeasureMesh","cleanup","pointMesh","pressTimer","isLongPressTriggered","actualPointIndex","onPointerDown","pointerDownPosition","globalMoveHandler","onPointerUp","onClick","p","mouseDownPosition","isDragMode","newPoints","updatedPointIndex","lastPointIndex","isLiveUpdate","lineMesh","positions","updatedPosition","firstPointMesh","lastPointMesh","pointIndex","finalPoints","originalMeshState","opacity","isRepositioning","dashed","fiveElement","currentIntersection","onGlobalMouseMove","rect","intersects","onGlobalTouchMove","touch","onGlobalMouseUp","onGlobalTouchEnd","onGlobalClick","indicator","style","mousePosition","pointScreenPosition","globalMouseCleanup","onGlobalTouchStart","allHits","loopIndex","screenDistance","b","closestHit","syntheticEvent","pointerX","pointer","pointerY","screenPosition","screenX","screenY","dx","dy","MeasurePlugin"],"sources":["../../src/MeasurePlugin/utils/validatePolygon.ts","../../src/MeasurePlugin/utils/MeasureMesh.ts","../../../node_modules/hotkeys-js/dist/hotkeys-js.js","../../src/MeasurePlugin/Controller.ts","../../src/MeasurePlugin/index.ts"],"sourcesContent":["import { vectorIsEqual } from '../../shared-utils/three/vectorIsEqual'\nimport * as THREE from 'three/webgpu'\n\nexport function validatePolygon(points: THREE.Vector3[]): boolean {\n if (points.length < 3) return false\n\n if (!vectorIsEqual(points[0], points.at(-1))) return false\n\n // 检查所有点不是一条直线\n let isLine = true\n const vector01 = new THREE.Vector3().subVectors(points[1], points[0]).normalize()\n for (let i = 2; i < points.length; i++) {\n const vector = new THREE.Vector3().subVectors(points[i], points[0]).normalize()\n if (!vectorIsEqual(vector, vector01) && !vectorIsEqual(vector, vector01.clone().negate())) {\n isLine = false\n break\n }\n }\n\n if (isLine) return false\n\n // 检查所有点是不是一个平面\n const plane = new THREE.Plane().setFromCoplanarPoints(points[0], points[1], points[2])\n const isPolygon = points.every((point, index) => {\n if (index < 3) return true\n return plane.distanceToPoint(point) < 0.000001\n })\n\n return isPolygon\n}\n","import type * as THREE from 'three/webgpu'\nimport { IObject3D } from '../../shared-utils/three/IObject3D'\nimport { LineWithDotsMesh } from '../../Sculpt/Meshes/LineWithDots'\nimport { PolygonMesh, type PolygonStyle } from '../../Sculpt/Meshes/Polygon'\nimport { validatePolygon } from './validatePolygon'\nimport type { Color } from '../../Sculpt/typings/style'\nimport type { LineMeshStyle } from '../../Sculpt/typings'\n\nexport class MeasureMesh extends IObject3D {\n public readonly name = 'MeasureMesh'\n public readonly isMeasureMesh = true\n\n public points: THREE.Vector3[] = []\n public isPolygon = false\n public selected = false\n public line: LineWithDotsMesh\n public polygon: PolygonMesh\n\n public constructor(config?: { lineStyle?: Partial<LineMeshStyle>; polygonStyle?: Partial<PolygonStyle> }) {\n super()\n this.line = new LineWithDotsMesh(config?.lineStyle)\n this.polygon = new PolygonMesh(config?.polygonStyle)\n this.add(this.line)\n }\n\n public changeConfig(config?: { lineStyle?: Partial<LineMeshStyle>; polygonStyle?: Partial<PolygonStyle> }) {\n this.line.setStyle(config?.lineStyle)\n this.polygon.setStyle(config?.polygonStyle)\n }\n\n public setPoints(points: THREE.Vector3[]) {\n this.points = points\n this.line.setPoints(this.points)\n\n const isPolygon = validatePolygon(this.points)\n this.isPolygon = isPolygon\n if (isPolygon) {\n this.addIfNotExists(this.polygon)\n this.polygon.setPoints(this.points)\n }\n }\n\n public select() {\n this.highlight(0x3377ff)\n this.selected = true\n }\n\n public unselect() {\n this.unhighlight()\n this.selected = false\n }\n\n public hover() {\n if (!this.selected) {\n this.highlight()\n }\n }\n\n public unhover() {\n if (!this.selected) {\n this.unhighlight()\n }\n }\n\n private highlight(color?: Color) {\n this.line.highlight({ color })\n this.polygon.highlight({ color })\n }\n\n private unhighlight() {\n this.line.unhighlight()\n this.polygon.unhighlight()\n }\n}\n","/*!\n * hotkeys-js v4.0.8\n * A simple micro-library for defining and dispatching keyboard shortcuts. It has no dependencies.\n * \n * @author kenny wong <wowohoo@qq.com>\n * @license MIT\n * @homepage https://jaywcjlove.github.io/hotkeys-js\n */\nconst isff = typeof navigator !== \"undefined\" ? navigator.userAgent.toLowerCase().indexOf(\"firefox\") > 0 : false;\nfunction addEvent(object, event, method, useCapture) {\n if (object.addEventListener) {\n object.addEventListener(event, method, useCapture);\n } else if (object.attachEvent) {\n object.attachEvent(`on${event}`, method);\n }\n}\nfunction removeEvent(object, event, method, useCapture) {\n if (!object) return;\n if (object.removeEventListener) {\n object.removeEventListener(event, method, useCapture);\n } else if (object.detachEvent) {\n object.detachEvent(`on${event}`, method);\n }\n}\nfunction getMods(modifier, key) {\n const modsKeys = key.slice(0, key.length - 1);\n const modsCodes = [];\n for (let i = 0; i < modsKeys.length; i++) {\n modsCodes.push(modifier[modsKeys[i].toLowerCase()]);\n }\n return modsCodes;\n}\nfunction getKeys(key) {\n if (typeof key !== \"string\") key = \"\";\n key = key.replace(/\\s/g, \"\");\n const keys = key.split(\",\");\n let index = keys.lastIndexOf(\"\");\n for (; index >= 0; ) {\n keys[index - 1] += \",\";\n keys.splice(index, 1);\n index = keys.lastIndexOf(\"\");\n }\n return keys;\n}\nfunction compareArray(a1, a2) {\n const arr1 = a1.length >= a2.length ? a1 : a2;\n const arr2 = a1.length >= a2.length ? a2 : a1;\n let isIndex = true;\n for (let i = 0; i < arr1.length; i++) {\n if (arr2.indexOf(arr1[i]) === -1) isIndex = false;\n }\n return isIndex;\n}\nfunction getLayoutIndependentKeyCode(event, keyMap, modifierMap2) {\n let key = event.keyCode || event.which || event.charCode;\n if (event.key) {\n const eventKey = event.key.toLowerCase();\n if (eventKey in keyMap) {\n return keyMap[eventKey];\n }\n if (eventKey in modifierMap2) {\n return modifierMap2[eventKey];\n }\n if (/^[0-9]$/.test(event.key)) {\n return event.key.charCodeAt(0);\n }\n if (/^[a-z]$/i.test(event.key)) {\n return event.key.toUpperCase().charCodeAt(0);\n }\n }\n if (event.code && /^Key[A-Z]$/.test(event.code)) {\n key = event.code.charCodeAt(3);\n }\n return key;\n}\nconst _keyMap = {\n backspace: 8,\n \"⌫\": 8,\n tab: 9,\n clear: 12,\n enter: 13,\n \"↩\": 13,\n return: 13,\n esc: 27,\n escape: 27,\n space: 32,\n left: 37,\n up: 38,\n right: 39,\n down: 40,\n /// https://w3c.github.io/uievents/#events-keyboard-key-location\n arrowup: 38,\n arrowdown: 40,\n arrowleft: 37,\n arrowright: 39,\n del: 46,\n delete: 46,\n ins: 45,\n insert: 45,\n home: 36,\n end: 35,\n pageup: 33,\n pagedown: 34,\n capslock: 20,\n num_0: 96,\n num_1: 97,\n num_2: 98,\n num_3: 99,\n num_4: 100,\n num_5: 101,\n num_6: 102,\n num_7: 103,\n num_8: 104,\n num_9: 105,\n num_multiply: 106,\n num_add: 107,\n num_enter: 108,\n num_subtract: 109,\n num_decimal: 110,\n num_divide: 111,\n \"⇪\": 20,\n \",\": 188,\n \".\": 190,\n \"/\": 191,\n \"`\": 192,\n \"-\": isff ? 173 : 189,\n \"=\": isff ? 61 : 187,\n \";\": isff ? 59 : 186,\n \"'\": 222,\n \"{\": 219,\n \"}\": 221,\n \"[\": 219,\n \"]\": 221,\n \"\\\\\": 220\n};\nconst _modifier = {\n // shiftKey\n \"⇧\": 16,\n shift: 16,\n // altKey\n \"⌥\": 18,\n alt: 18,\n option: 18,\n // ctrlKey\n \"⌃\": 17,\n ctrl: 17,\n control: 17,\n // metaKey\n \"⌘\": 91,\n cmd: 91,\n meta: 91,\n command: 91\n};\nconst modifierMap = {\n 16: \"shiftKey\",\n 18: \"altKey\",\n 17: \"ctrlKey\",\n 91: \"metaKey\",\n shiftKey: 16,\n ctrlKey: 17,\n altKey: 18,\n metaKey: 91\n};\nconst _mods = {\n 16: false,\n 18: false,\n 17: false,\n 91: false\n};\nconst _handlers = {};\nfor (let k = 1; k < 20; k++) {\n _keyMap[`f${k}`] = 111 + k;\n}\nlet _downKeys = [];\nlet winListendFocus = null;\nlet winListendFullscreen = null;\nlet _scope = \"all\";\nconst elementEventMap = /* @__PURE__ */ new Map();\nconst code = (x) => _keyMap[x.toLowerCase()] || _modifier[x.toLowerCase()] || x.toUpperCase().charCodeAt(0);\nconst getKey = (x) => Object.keys(_keyMap).find((k) => _keyMap[k] === x);\nconst getModifier = (x) => Object.keys(_modifier).find((k) => _modifier[k] === x);\nconst setScope = (scope) => {\n _scope = scope || \"all\";\n};\nconst getScope = () => {\n return _scope || \"all\";\n};\nconst getPressedKeyCodes = () => {\n return _downKeys.slice(0);\n};\nconst getPressedKeyString = () => {\n return _downKeys.map(\n (c) => getKey(c) || getModifier(c) || String.fromCharCode(c)\n );\n};\nconst getAllKeyCodes = () => {\n const result = [];\n Object.keys(_handlers).forEach((k) => {\n _handlers[k].forEach(({ key, scope, mods, shortcut }) => {\n result.push({\n scope,\n shortcut,\n mods,\n keys: key.split(\"+\").map((v) => code(v))\n });\n });\n });\n return result;\n};\nconst filter = (event) => {\n const target = event.target || event.srcElement;\n const { tagName } = target;\n let flag = true;\n const isInput = tagName === \"INPUT\" && ![\n \"checkbox\",\n \"radio\",\n \"range\",\n \"button\",\n \"file\",\n \"reset\",\n \"submit\",\n \"color\"\n ].includes(target.type);\n if (target.isContentEditable || (isInput || tagName === \"TEXTAREA\" || tagName === \"SELECT\") && !target.readOnly) {\n flag = false;\n }\n return flag;\n};\nconst isPressed = (keyCode) => {\n if (typeof keyCode === \"string\") {\n keyCode = code(keyCode);\n }\n return _downKeys.indexOf(keyCode) !== -1;\n};\nconst deleteScope = (scope, newScope) => {\n let handlers;\n let i;\n if (!scope) scope = getScope();\n for (const key in _handlers) {\n if (Object.prototype.hasOwnProperty.call(_handlers, key)) {\n handlers = _handlers[key];\n for (i = 0; i < handlers.length; ) {\n if (handlers[i].scope === scope) {\n const deleteItems = handlers.splice(i, 1);\n deleteItems.forEach(({ element }) => removeKeyEvent(element));\n } else {\n i++;\n }\n }\n }\n }\n if (getScope() === scope) setScope(newScope || \"all\");\n};\nfunction clearModifier(event) {\n let key = getLayoutIndependentKeyCode(event, _keyMap, _modifier);\n if (event.key && event.key.toLowerCase() === \"capslock\") {\n key = code(event.key);\n }\n const i = _downKeys.indexOf(key);\n if (i >= 0) {\n _downKeys.splice(i, 1);\n }\n if (event.key && event.key.toLowerCase() === \"meta\") {\n _downKeys.splice(0, _downKeys.length);\n }\n if (key === 93 || key === 224) key = 91;\n if (key in _mods) {\n _mods[key] = false;\n for (const k in _modifier)\n if (_modifier[k] === key) hotkeys[k] = false;\n }\n}\nconst unbind = (keysInfo, ...args) => {\n if (typeof keysInfo === \"undefined\") {\n Object.keys(_handlers).forEach((key) => {\n if (Array.isArray(_handlers[key])) {\n _handlers[key].forEach((info) => eachUnbind(info));\n }\n delete _handlers[key];\n });\n removeKeyEvent(null);\n } else if (Array.isArray(keysInfo)) {\n keysInfo.forEach((info) => {\n if (info.key) eachUnbind(info);\n });\n } else if (typeof keysInfo === \"object\") {\n if (keysInfo.key) eachUnbind(keysInfo);\n } else if (typeof keysInfo === \"string\") {\n let [scope, method] = args;\n if (typeof scope === \"function\") {\n method = scope;\n scope = \"\";\n }\n eachUnbind({\n key: keysInfo,\n scope,\n method,\n splitKey: \"+\"\n });\n }\n};\nconst eachUnbind = ({\n key,\n scope,\n method,\n splitKey = \"+\"\n}) => {\n const multipleKeys = getKeys(key);\n multipleKeys.forEach((originKey) => {\n const unbindKeys = originKey.split(splitKey);\n const len = unbindKeys.length;\n const lastKey = unbindKeys[len - 1];\n const keyCode = lastKey === \"*\" ? \"*\" : code(lastKey);\n if (!_handlers[keyCode]) return;\n if (!scope) scope = getScope();\n const mods = len > 1 ? getMods(_modifier, unbindKeys) : [];\n const unbindElements = [];\n _handlers[keyCode] = _handlers[keyCode].filter((record) => {\n const isMatchingMethod = method ? record.method === method : true;\n const isUnbind = isMatchingMethod && record.scope === scope && compareArray(record.mods, mods);\n if (isUnbind) unbindElements.push(record.element);\n return !isUnbind;\n });\n unbindElements.forEach((element) => removeKeyEvent(element));\n });\n};\nfunction eventHandler(event, handler, scope, element) {\n if (handler.element !== element) {\n return;\n }\n let modifiersMatch;\n if (handler.scope === scope || handler.scope === \"all\") {\n modifiersMatch = handler.mods.length > 0;\n for (const y in _mods) {\n if (Object.prototype.hasOwnProperty.call(_mods, y)) {\n if (!_mods[y] && handler.mods.indexOf(+y) > -1 || _mods[y] && handler.mods.indexOf(+y) === -1) {\n modifiersMatch = false;\n }\n }\n }\n if (handler.mods.length === 0 && !_mods[16] && !_mods[18] && !_mods[17] && !_mods[91] || modifiersMatch || handler.shortcut === \"*\") {\n handler.keys = [];\n handler.keys = handler.keys.concat(_downKeys);\n if (handler.method(event, handler) === false) {\n if (event.preventDefault) event.preventDefault();\n else event.returnValue = false;\n if (event.stopPropagation) event.stopPropagation();\n if (event.cancelBubble) event.cancelBubble = true;\n }\n }\n }\n}\nfunction dispatch(event, element) {\n const asterisk = _handlers[\"*\"];\n let key = getLayoutIndependentKeyCode(event, _keyMap, _modifier);\n if (event.key && event.key.toLowerCase() === \"capslock\") {\n return;\n }\n const filterFn = hotkeys.filter || filter;\n if (!filterFn.call(this, event)) return;\n if (key === 93 || key === 224) key = 91;\n if (_downKeys.indexOf(key) === -1 && key !== 229) _downKeys.push(key);\n [\"metaKey\", \"ctrlKey\", \"altKey\", \"shiftKey\"].forEach((keyName) => {\n const keyNum = modifierMap[keyName];\n if (event[keyName] && _downKeys.indexOf(keyNum) === -1) {\n _downKeys.push(keyNum);\n } else if (!event[keyName] && _downKeys.indexOf(keyNum) > -1) {\n _downKeys.splice(_downKeys.indexOf(keyNum), 1);\n } else if (keyName === \"metaKey\" && event[keyName]) {\n _downKeys = _downKeys.filter((k) => k in modifierMap || k === key);\n }\n });\n if (key in _mods) {\n _mods[key] = true;\n for (const k in _modifier) {\n if (Object.prototype.hasOwnProperty.call(_modifier, k)) {\n const eventKey = modifierMap[_modifier[k]];\n hotkeys[k] = event[eventKey];\n }\n }\n if (!asterisk) return;\n }\n for (const e in _mods) {\n if (Object.prototype.hasOwnProperty.call(_mods, e)) {\n _mods[e] = event[modifierMap[e]];\n }\n }\n if (event.getModifierState && !(event.altKey && !event.ctrlKey) && event.getModifierState(\"AltGraph\")) {\n if (_downKeys.indexOf(17) === -1) {\n _downKeys.push(17);\n }\n if (_downKeys.indexOf(18) === -1) {\n _downKeys.push(18);\n }\n _mods[17] = true;\n _mods[18] = true;\n }\n const scope = getScope();\n if (asterisk) {\n for (let i = 0; i < asterisk.length; i++) {\n if (asterisk[i].scope === scope && (event.type === \"keydown\" && asterisk[i].keydown || event.type === \"keyup\" && asterisk[i].keyup)) {\n eventHandler(event, asterisk[i], scope, element);\n }\n }\n }\n if (!(key in _handlers)) return;\n const handlerKey = _handlers[key];\n const keyLen = handlerKey.length;\n for (let i = 0; i < keyLen; i++) {\n if (event.type === \"keydown\" && handlerKey[i].keydown || event.type === \"keyup\" && handlerKey[i].keyup) {\n if (handlerKey[i].key) {\n const record = handlerKey[i];\n const { splitKey } = record;\n const keyShortcut = record.key.split(splitKey);\n const _downKeysCurrent = [];\n for (let a = 0; a < keyShortcut.length; a++) {\n _downKeysCurrent.push(code(keyShortcut[a]));\n }\n if (_downKeysCurrent.sort().join(\"\") === _downKeys.sort().join(\"\")) {\n eventHandler(event, record, scope, element);\n }\n }\n }\n }\n}\nconst hotkeys = function hotkeys2(key, option, method) {\n _downKeys = [];\n const keys = getKeys(key);\n let mods = [];\n let scope = \"all\";\n let element = document;\n let i = 0;\n let keyup = false;\n let keydown = true;\n let splitKey = \"+\";\n let capture = false;\n let single = false;\n if (method === void 0 && typeof option === \"function\") {\n method = option;\n }\n if (Object.prototype.toString.call(option) === \"[object Object]\") {\n const opts = option;\n if (opts.scope) scope = opts.scope;\n if (opts.element) element = opts.element;\n if (opts.keyup) keyup = opts.keyup;\n if (opts.keydown !== void 0) keydown = opts.keydown;\n if (opts.capture !== void 0) capture = opts.capture;\n if (typeof opts.splitKey === \"string\") splitKey = opts.splitKey;\n if (opts.single === true) single = true;\n }\n if (typeof option === \"string\") scope = option;\n if (single) unbind(key, scope);\n for (; i < keys.length; i++) {\n const currentKey = keys[i].split(splitKey);\n mods = [];\n if (currentKey.length > 1) mods = getMods(_modifier, currentKey);\n let finalKey = currentKey[currentKey.length - 1];\n finalKey = finalKey === \"*\" ? \"*\" : code(finalKey);\n if (!(finalKey in _handlers)) _handlers[finalKey] = [];\n _handlers[finalKey].push({\n keyup,\n keydown,\n scope,\n mods,\n shortcut: keys[i],\n method,\n key: keys[i],\n splitKey,\n element\n });\n }\n if (typeof element !== \"undefined\" && typeof window !== \"undefined\") {\n if (!elementEventMap.has(element)) {\n const keydownListener = (event = window.event) => dispatch(event, element);\n const keyupListenr = (event = window.event) => {\n dispatch(event, element);\n clearModifier(event);\n };\n elementEventMap.set(element, { keydownListener, keyupListenr, capture });\n addEvent(element, \"keydown\", keydownListener, capture);\n addEvent(element, \"keyup\", keyupListenr, capture);\n }\n if (!winListendFocus) {\n const listener = () => {\n _downKeys = [];\n };\n winListendFocus = { listener, capture };\n addEvent(window, \"focus\", listener, capture);\n }\n if (!winListendFullscreen && typeof document !== \"undefined\") {\n const onFullscreenChange = () => {\n _downKeys = [];\n for (const k in _mods) _mods[k] = false;\n for (const k in _modifier) hotkeys2[k] = false;\n };\n const fullscreenListener = onFullscreenChange;\n const webkitListener = onFullscreenChange;\n document.addEventListener(\"fullscreenchange\", fullscreenListener);\n document.addEventListener(\"webkitfullscreenchange\", webkitListener);\n winListendFullscreen = { fullscreen: fullscreenListener, webkit: webkitListener };\n }\n }\n};\nfunction trigger(shortcut, scope = \"all\") {\n Object.keys(_handlers).forEach((key) => {\n const dataList = _handlers[key].filter(\n (item) => item.scope === scope && (item.shortcut === shortcut || item.shortcut === \"*\")\n );\n dataList.forEach((data) => {\n if (data && data.method) {\n data.method({}, data);\n }\n });\n });\n}\nfunction removeKeyEvent(element) {\n const values = Object.values(_handlers).flat();\n const findindex = values.findIndex(({ element: el }) => el === element);\n if (findindex < 0 && element) {\n const { keydownListener, keyupListenr, capture } = elementEventMap.get(element) || {};\n if (keydownListener && keyupListenr) {\n removeEvent(element, \"keyup\", keyupListenr, capture);\n removeEvent(element, \"keydown\", keydownListener, capture);\n elementEventMap.delete(element);\n }\n }\n if (values.length <= 0 || elementEventMap.size <= 0) {\n const eventKeys = Array.from(elementEventMap.keys());\n eventKeys.forEach((el) => {\n const { keydownListener, keyupListenr, capture } = elementEventMap.get(el) || {};\n if (keydownListener && keyupListenr) {\n removeEvent(el, \"keyup\", keyupListenr, capture);\n removeEvent(el, \"keydown\", keydownListener, capture);\n elementEventMap.delete(el);\n }\n });\n elementEventMap.clear();\n Object.keys(_handlers).forEach((key) => delete _handlers[key]);\n if (winListendFocus) {\n const { listener, capture } = winListendFocus;\n removeEvent(window, \"focus\", listener, capture);\n winListendFocus = null;\n }\n if (winListendFullscreen && typeof document !== \"undefined\") {\n document.removeEventListener(\"fullscreenchange\", winListendFullscreen.fullscreen);\n document.removeEventListener(\"webkitfullscreenchange\", winListendFullscreen.webkit);\n winListendFullscreen = null;\n }\n }\n}\nconst _api = {\n getPressedKeyString,\n setScope,\n getScope,\n deleteScope,\n getPressedKeyCodes,\n getAllKeyCodes,\n isPressed,\n filter,\n trigger,\n unbind,\n keyMap: _keyMap,\n modifier: _modifier,\n modifierMap\n};\nfor (const a in _api) {\n const key = a;\n if (Object.prototype.hasOwnProperty.call(_api, key)) {\n hotkeys[key] = _api[key];\n }\n}\nif (typeof window !== \"undefined\") {\n const _hotkeys = window.hotkeys;\n hotkeys.noConflict = (deep) => {\n if (deep && window.hotkeys === hotkeys) {\n window.hotkeys = _hotkeys;\n }\n return hotkeys;\n };\n window.hotkeys = hotkeys;\n}\nexport {\n hotkeys as default\n};\n//# sourceMappingURL=hotkeys-js.js.map\n","import { bindFiveOwner } from '../shared-utils/five/getFiveFromParentChain'\nimport type { Five, Mode } from '@realsee/five-webgpu'\nimport * as THREE from 'three/webgpu'\nimport { FiveDomEvents, PointSelector, type FiveDomEvent, type PointIntersection } from '../shared-utils'\nimport { MeasureMesh } from './utils/MeasureMesh'\nimport { PointMesh } from '../Sculpt/Meshes/Point'\nimport { LineWithDotsMesh } from '../Sculpt/Meshes/LineWithDots'\nimport { LineMesh } from '../Sculpt/Meshes/Line'\nimport hotkeys from 'hotkeys-js'\nimport { PolygonMesh, type PolygonStyle } from '../Sculpt/Meshes/Polygon'\nimport { validatePolygon } from './utils/validatePolygon'\nimport { Subscribe } from '../shared-utils/Subscribe'\nimport { IObject3D } from '../shared-utils/three/IObject3D'\nimport { Cursor } from '../Sculpt/utils/Modules/Cursor'\nimport type { LineMeshStyle } from '../Sculpt/typings'\nimport type { Overwrite } from '../typings/utils.type'\nimport type { MeasurePluginConfig } from '.'\nimport { THREERaycaster } from '../shared-utils/three/core/Raycaster'\n\n// 测量结束的原因枚举\nexport type MeasureEndReason =\n | 'enter' // 按Enter键完成\n | 'escape' // 按Esc键取消\n | 'polygon' // 自动完成多边形\n | 'mode_change' // 模式改变\n | 'pano_move' // 全景移动\n | 'floor_change' // 楼层改变\n | 'points_insufficient' // 点数不足(少于2个点)\n | 'external' // 外部调用结束\n\n// 测量插件事件类型\nexport type MeasurePluginEventMap = {\n measureEnd: (reason: MeasureEndReason, points: THREE.Vector3[]) => void\n undo: () => void\n}\n\nexport class MeasureController extends Subscribe<MeasurePluginEventMap> {\n public readonly name = 'MeasurePlugin'\n\n public currentMeasureMesh?: MeasureMesh | null\n\n private five: Five\n\n private group: Overwrite<IObject3D, { children: Array<MeasureMesh> }>\n\n // 当前测量结束的原因\n private currentEndReason: MeasureEndReason = 'enter'\n\n // Repositioning state\n private repositioningState: {\n measureMesh: MeasureMesh\n pointIndex: number\n originalOpacity: number\n originalMeshState: any[]\n isDragMode?: boolean\n mouseDownPosition?: { x: number; y: number }\n hasMoved?: boolean\n } | null = null\n\n // Long press visual feedback\n private longPressIndicator: HTMLElement | null = null\n\n // Global cleanup function for mouse/touch listeners\n private cleanupGlobalListeners?: () => void\n\n // Global touch handler for endpoint long press\n private globalTouchHandler: {\n isSetup: boolean\n onTouchStart: (e: TouchEvent) => void\n onTouchEnd: (e: TouchEvent) => void\n } | null = null\n\n public get pointSelector() {\n if (this._pointSelector) return this._pointSelector\n this._pointSelector = new PointSelector(this.five, { mode: 'cursor', helper: { pointHelper: 'highlight' }, skipPanorama: true })\n return this._pointSelector\n }\n private _pointSelector: PointSelector\n\n private get fiveDomEvents() {\n if (this._fiveDomEvents) return this._fiveDomEvents\n this._fiveDomEvents = new FiveDomEvents(this.five, { fiveModels: null })\n return this._fiveDomEvents\n }\n private _fiveDomEvents: FiveDomEvents\n\n private get cursor() {\n if (this._cursor) return this._cursor\n this._cursor = new Cursor()\n return this._cursor\n }\n private _cursor: Cursor\n\n public get config() {\n return this._config\n }\n\n public set config(config: MeasurePluginConfig) {\n this._config = config\n this.lineStyle.lengthUnit = config.unit\n this.polygonStyle.lengthUnit = config.unit\n\n // Apply lengthEnable setting if provided\n if (config.lengthEnable !== undefined) {\n this.lineStyle.lengthEnable = config.lengthEnable\n this.polygonStyle.lengthEnable = config.lengthEnable\n }\n\n // Apply precision setting if provided (only for length labels, not area)\n if (config.precision !== undefined) {\n this.lineStyle.precision = config.precision\n }\n\n this.group?.children?.forEach((item) => item.changeConfig({ lineStyle: this.lineStyle, polygonStyle: this.polygonStyle }))\n }\n\n private _config?: MeasurePluginConfig\n\n private lineStyle: Partial<LineMeshStyle> = {\n lengthEnable: true,\n occlusionVisibility: true,\n lengthUnit: 'm',\n precision: 2,\n }\n private polygonStyle: Partial<PolygonStyle> = {\n lengthEnable: true,\n occlusionVisibility: true,\n opacity: 0.2,\n lengthUnit: 'm',\n }\n\n public constructor(five: Five, config?: MeasurePluginConfig) {\n super()\n\n this.five = five\n\n // Initialize with default config\n const defaultConfig: MeasurePluginConfig = { unit: 'm', lengthEnable: true, precision: 2 }\n this.config = config ? { ...defaultConfig, ...config } : defaultConfig\n\n this.group = new IObject3D() as any\n this.group.name = 'MeasureGroup'\n bindFiveOwner(this.group, this.five)\n this.five.scene.add(this.group)\n\n // Add global event listeners\n this.five.on('panoArrived', this.onMoveToPano)\n this.five.on('modeChange', this.onModeChange)\n hotkeys('delete, backspace', this.deleteSelectedMesh)\n\n // Initialize event listeners for any existing meshes\n // This ensures event listeners work properly when loading from saved data\n this.initEventListeners()\n }\n\n /**\n * @description Initialize event listeners for all existing meshes\n */\n public initEventListeners = () => {\n // Add event listeners to all existing meshes\n this.group.children.forEach(this.addMeshEventListeners)\n }\n\n /**\n * @description 开始测量\n */\n public measure = () => {\n // Cancel any active repositioning first\n if (this.repositioningState) {\n this.cancelRepositioning()\n }\n\n this.listener.addMeasureListener()\n\n // Instead of removing all click listeners, just unbind global shortcut keys\n hotkeys.unbind('delete, backspace')\n\n // 取消所有选中态\n this.group.children.forEach((item) => item.unselect())\n this.cursor.removeDeleteButton()\n\n const measureMesh = new MeasureMesh({\n lineStyle: this.lineStyle,\n polygonStyle: this.polygonStyle,\n })\n this.currentMeasureMesh = measureMesh\n measureMesh.line.setStyle({ cssStyle: 'pointer-events: none;' })\n\n this.pointSelector.actionIfNoIntersection = 'disable'\n this.updateSelectAdsorbedHelper()\n\n const temp_previewPoint = new PointMesh({ occlusionMode: 'depthTest', occlusionVisibility: true })\n const temp_previewLine = new LineWithDotsMesh({ ...this.lineStyle, dashed: true, cssStyle: 'pointer-events: none;' })\n const temp_previewPolygon = new PolygonMesh(this.polygonStyle)\n // 直角三角形的两条直角边\n const temp_verticalLine1 = new LineMesh({\n ...this.lineStyle,\n lineOpacity: 0.5,\n lineColor: 0x33ffdd,\n dashed: true,\n cssStyle: 'pointer-events: none; opacity: 0.5;',\n })\n const temp_verticalLine2 = new LineMesh({\n ...this.lineStyle,\n lineOpacity: 0.5,\n lineColor: 0x33ffdd,\n dashed: true,\n cssStyle: 'pointer-events: none; opacity: 0.5;',\n })\n const temp_verticalPoint = new PointMesh({ occlusionMode: 'depthTest', occlusionVisibility: true, color: 0x33ffdd, opacity: 0.5 })\n\n // Track the current vertical point for Shift+click functionality\n let currentVerticalPoint: THREE.Vector3 | null = null\n let isRightTriangleShowing = false\n let isShiftPressed = false\n\n // Track Shift key state during measurement\n const onKeyDown = (e: KeyboardEvent) => {\n if (e.key === 'Shift') {\n isShiftPressed = true\n }\n }\n\n const onKeyUp = (e: KeyboardEvent) => {\n if (e.key === 'Shift') {\n isShiftPressed = false\n }\n }\n\n const removeTempMesh = () => {\n temp_previewPoint.removeFromParent()\n temp_previewLine.removeFromParent()\n temp_previewPolygon.removeFromParent()\n temp_verticalLine1.removeFromParent()\n temp_verticalLine2.removeFromParent()\n temp_verticalPoint.removeFromParent()\n }\n\n this.group.add(measureMesh)\n\n // Add Shift key listeners\n document.addEventListener('keydown', onKeyDown)\n document.addEventListener('keyup', onKeyUp)\n\n const onIntersectionUpdate = (intersection?: PointIntersection) => {\n if (!intersection) {\n removeTempMesh()\n // Reset triangle state\n currentVerticalPoint = null\n isRightTriangleShowing = false\n return\n }\n\n if (measureMesh.points.length === 0) {\n this.pointSelector.actionIfNoIntersection = 'disable'\n this.group.addIfNotExists(temp_previewPoint)\n temp_previewPoint.position.copy(intersection.point)\n // Reset triangle state\n currentVerticalPoint = null\n isRightTriangleShowing = false\n }\n if (measureMesh.points.length >= 1) {\n this.pointSelector.actionIfNoIntersection = 'virtualPoint'\n temp_previewPoint.removeFromParent()\n this.group.addIfNotExists(temp_previewLine)\n\n // Update temp_previewLine style before setting points to ensure labels use current precision\n temp_previewLine.setStyle({ ...this.lineStyle, dashed: true, cssStyle: 'pointer-events: none;' })\n\n // 预览线作为斜边\n temp_previewLine.setPoints([measureMesh.points.at(-1), intersection.point])\n // 绘制直角三角形的两条直角边\n if (!intersection.isAdsorbed) {\n const lastPoint = measureMesh.points.at(-1)\n // 判断是不是垂直的趋势\n const isWantUp = Math.abs(intersection.point.y - lastPoint.y) > 0.2\n if (isWantUp) {\n const verticalPoint = new THREE.Vector3(intersection.point.x, lastPoint.y, intersection.point.z)\n // Update vertical lines style before setting points to ensure labels use current precision\n temp_verticalLine1.setStyle({\n ...this.lineStyle,\n lineOpacity: 0.5,\n lineColor: 0x33ffdd,\n dashed: true,\n cssStyle: 'pointer-events: none; opacity: 0.5;',\n })\n temp_verticalLine2.setStyle({\n ...this.lineStyle,\n lineOpacity: 0.5,\n lineColor: 0x33ffdd,\n dashed: true,\n cssStyle: 'pointer-events: none; opacity: 0.5;',\n })\n temp_verticalLine1.setPoints([lastPoint, verticalPoint])\n temp_verticalLine2.setPoints([verticalPoint, intersection.point])\n temp_verticalPoint.position.copy(verticalPoint)\n // Update tracked variables\n currentVerticalPoint = verticalPoint.clone()\n isRightTriangleShowing = true\n } else {\n let verticalPoint = new THREE.Vector3()\n if (Math.abs(intersection.point.x - lastPoint.x) < Math.abs(intersection.point.z - lastPoint.z)) {\n verticalPoint = new THREE.Vector3(intersection.point.x, lastPoint.y, lastPoint.z)\n } else {\n verticalPoint = new THREE.Vector3(lastPoint.x, lastPoint.y, intersection.point.z)\n }\n // Update vertical lines style before setting points to ensure labels use current precision\n temp_verticalLine1.setStyle({\n ...this.lineStyle,\n lineOpacity: 0.5,\n lineColor: 0x33ffdd,\n dashed: true,\n cssStyle: 'pointer-events: none; opacity: 0.5;',\n })\n temp_verticalLine2.setStyle({\n ...this.lineStyle,\n lineOpacity: 0.5,\n lineColor: 0x33ffdd,\n dashed: true,\n cssStyle: 'pointer-events: none; opacity: 0.5;',\n })\n temp_verticalLine1.setPoints([lastPoint, verticalPoint])\n temp_verticalLine2.setPoints([verticalPoint, intersection.point])\n temp_verticalPoint.position.copy(verticalPoint)\n // Update tracked variables\n currentVerticalPoint = verticalPoint.clone()\n isRightTriangleShowing = true\n }\n this.group.addIfNotExists(temp_verticalLine1, temp_verticalLine2, temp_verticalPoint)\n } else {\n temp_verticalLine1.removeFromParent()\n temp_verticalLine2.removeFromParent()\n temp_verticalPoint.removeFromParent()\n // Reset triangle state when snapping to geometry\n currentVerticalPoint = null\n isRightTriangleShowing = false\n }\n }\n if (measureMesh.points.length >= 2) {\n const points = [...measureMesh.points, intersection.point]\n const isPolygon = validatePolygon(points)\n if (isPolygon) {\n // Update temp_previewPolygon style before setting points to ensure labels use current precision\n temp_previewPolygon.setStyle({ ...this.polygonStyle })\n temp_previewPolygon.setPoints(points)\n this.group.addIfNotExists(temp_previewPolygon)\n } else {\n temp_previewPolygon.removeFromParent()\n }\n }\n }\n\n const onSelect = (intersection?: PointIntersection) => {\n if (!intersection) return\n\n let targetPoint = intersection.point\n\n // If Shift is pressed, triangle is showing, and we have a vertical point, use the vertical point\n if (isShiftPressed && isRightTriangleShowing && currentVerticalPoint && measureMesh.points.length >= 1) {\n targetPoint = currentVerticalPoint.clone()\n }\n\n removeTempMesh()\n\n measureMesh.setPoints([...measureMesh.points, targetPoint])\n this.updateSelectAdsorbedHelper()\n\n if (measureMesh.isPolygon) {\n this.currentEndReason = 'polygon'\n this.pointSelector.disable()\n }\n }\n\n const undo = () => {\n measureMesh?.setPoints(measureMesh.points.slice(0, -1))\n removeTempMesh()\n this.pointSelector.pointSelectorHelper?.magnifier?.render()\n this.updateSelectAdsorbedHelper()\n this.five.needsRender = true\n }\n\n const onFinished = () => {\n this.pointSelector.off('intersectionUpdate', onIntersectionUpdate)\n this.pointSelector.off('select', onSelect)\n this.pointSelector.off('disable', onFinished)\n this.off('undo', undo)\n\n // Remove Shift key listeners\n document.removeEventListener('keydown', onKeyDown)\n document.removeEventListener('keyup', onKeyUp)\n\n measureMesh.line.setStyle({ cssStyle: 'pointer-events: auto;' })\n\n removeTempMesh()\n\n let finalReason = this.currentEndReason\n let keepMesh = true\n\n // escape: mesh 已在 cancel() 中被移除\n if (finalReason === 'escape') {\n keepMesh = false\n } else if (measureMesh.points.length < 2) {\n // points_insufficient: 点数不足,移除 mesh\n measureMesh.removeFromParent()\n finalReason = 'points_insufficient'\n keepMesh = false\n } else {\n // 保留 mesh,添加事件监听器\n this.addMeshEventListeners(measureMesh)\n }\n\n ;(measureMesh as any)['__five_pano_index'] = this.five.panoIndex\n this.currentMeasureMesh = null\n\n // Add measure listener after completing\n this.listener.removeMeasureListener()\n\n // 如果不保留 mesh,传空数组;否则传实际点数组\n this.emit('measureEnd', finalReason, keepMesh ? measureMesh.points : [])\n\n // 重置为默认原因\n this.currentEndReason = 'enter'\n }\n\n this.on('undo', undo)\n this.pointSelector.on('intersectionUpdate', onIntersectionUpdate)\n this.pointSelector.on('select', onSelect)\n this.pointSelector.on('disable', onFinished)\n\n // 开始测量\n this.pointSelector.enable()\n }\n\n /**\n * @description 结束测量\n */\n public endMeasure = () => {\n this.currentEndReason = 'external'\n this.pointSelector.disable()\n }\n\n /**\n * @description 通过Enter键结束测量\n */\n private endMeasureByEnter = () => {\n this.currentEndReason = 'enter'\n this.endMeasure()\n }\n\n /**\n * @description 通过模式改变结束测量\n */\n private endMeasureByModeChange = () => {\n this.currentEndReason = 'mode_change'\n this.endMeasure()\n }\n\n /**\n * @description 通过全景移动结束测量\n */\n private endMeasureByPanoMove = () => {\n this.currentEndReason = 'pano_move'\n this.endMeasure()\n }\n\n /**\n * @description 通过楼层改变结束测量\n */\n private endMeasureByFloorChange = () => {\n this.currentEndReason = 'floor_change'\n this.endMeasure()\n }\n\n /**\n * Enable or disable the display of length measurements\n * @param enable - Whether to display length measurements\n */\n public setLengthEnable = (enable: boolean) => {\n // Update style configurations\n this.lineStyle.lengthEnable = enable\n this.polygonStyle.lengthEnable = enable\n\n // Update all existing measurements without disrupting event listeners\n this.group.children.forEach((item) => {\n item.changeConfig({\n lineStyle: { ...this.lineStyle },\n polygonStyle: { ...this.polygonStyle },\n })\n\n // Re-add event listeners to this specific item without clearing others\n this.addMeshEventListeners(item)\n })\n\n // Update current measurement if exists\n if (this.currentMeasureMesh) {\n this.currentMeasureMesh.changeConfig({\n lineStyle: { ...this.lineStyle },\n polygonStyle: { ...this.polygonStyle },\n })\n }\n\n // Render the changes\n this.five.needsRender = true\n }\n\n /**\n * Switch the measurement unit without resetting the plugin\n * @param unit - The new unit to use ('m' for metric, 'ft' for imperial, or 'mm' for millimeters)\n */\n public setUnit = (unit: 'm' | 'ft' | 'mm') => {\n if (this._config) {\n this._config.unit = unit\n }\n\n // Update style configurations\n this.lineStyle.lengthUnit = unit\n this.polygonStyle.lengthUnit = unit\n\n // Update all existing measurements without disrupting event listeners\n this.group.children.forEach((item) => {\n try {\n item.changeConfig({\n lineStyle: { ...this.lineStyle },\n polygonStyle: { ...this.polygonStyle },\n })\n\n // Re-add event listeners to this specific item without clearing others\n this.addMeshEventListeners(item)\n } catch (error) {\n // Silent error handling\n }\n })\n\n // Update current measurement if exists\n if (this.currentMeasureMesh) {\n try {\n this.currentMeasureMesh.changeConfig({\n lineStyle: { ...this.lineStyle },\n polygonStyle: { ...this.polygonStyle },\n })\n } catch (error) {\n // Silent error handling\n }\n }\n\n // Trigger re-render to update the view\n this.five.needsRender = true\n }\n\n /**\n * Set the precision for length measurements\n * @param precision - For metric (`m`): decimal places. For imperial (`ft`): inch fraction denominator (1 | 4 | 8 | 16).\n * Area measurements remain at fixed 2 decimal places.\n */\n public setPrecision = (precision: number) => {\n if (this._config) {\n this._config.precision = precision\n }\n\n // Update style configuration (only applies to length measurements, not area)\n this.lineStyle.precision = precision\n\n // Update all existing measurements without disrupting event listeners\n this.group.children.forEach((item) => {\n try {\n item.changeConfig({\n lineStyle: { ...this.lineStyle },\n polygonStyle: { ...this.polygonStyle },\n })\n\n // Re-add event listeners to this specific item without clearing others\n this.addMeshEventListeners(item)\n } catch (error) {\n // Silent error handling\n }\n })\n\n // Update current measurement if exists\n if (this.currentMeasureMesh) {\n try {\n this.currentMeasureMesh.changeConfig({\n lineStyle: { ...this.lineStyle },\n polygonStyle: { ...this.polygonStyle },\n })\n } catch (error) {\n // Silent error handling\n }\n }\n\n // Trigger re-render to update the view\n this.five.needsRender = true\n }\n\n /**\n * @description 取消本次测量\n */\n public cancel = () => {\n this.currentEndReason = 'escape'\n this.currentMeasureMesh?.removeFromParent()\n this.pointSelector.disable()\n }\n\n /**\n * @description 撤销上一步\n */\n public undo = () => {\n this.emit('undo')\n }\n\n /**\n * @description 清空正在测量的内容\n */\n public clearCurrentMeasure = () => {\n this.currentMeasureMesh?.removeFromParent()\n this.currentMeasureMesh = null\n this.pointSelector.disable()\n }\n\n /**\n * @description 清空所有测量内容\n */\n public clear = () => {\n this.currentMeasureMesh = null\n this.pointSelector.disable()\n\n // Remove event listeners from all meshes before removing them\n this.group.children.forEach(this.removeMeshEventListeners)\n\n this.group.removeChildren()\n this.cursor.removeDeleteButton()\n }\n\n public dispose = () => {\n this.listener.removeMeasureListener()\n this.listener.removeClickListener()\n\n this.pointSelector.disable()\n\n // Dispose global touch handler\n this.disposeGlobalTouchHandler()\n\n this.clear()\n }\n\n\n private listener = {\n // 点击事件\n addClickListener: () => {\n // Instead of clearing all listeners, which causes the odd/even issue,\n // we'll add listeners to meshes that don't have them yet\n\n // Add event listeners for global events\n this.five.on('panoArrived', this.onMoveToPano)\n this.five.on('modeChange', this.onModeChange)\n hotkeys('delete, backspace', this.deleteSelectedMesh)\n\n // Ensure all existing meshes have event listeners\n this.initEventListeners()\n },\n removeClickListener: () => {\n this.group.children.forEach((item) => {\n item.line.doms?.forEach((dom) => {\n if (dom?.container) {\n dom.container.onclick = null\n dom.container.onmouseenter = null\n dom.container.onmouseleave = null\n }\n })\n if (item.polygon.areaDom?.container) {\n item.polygon.areaDom.container.onclick = null\n item.polygon.areaDom.container.onmouseenter = null\n item.polygon.areaDom.container.onmouseleave = null\n }\n })\n this.fiveDomEvents.clear()\n this.five.off('panoArrived', this.onMoveToPano)\n this.five.off('modeChange', this.onModeChange)\n hotkeys.unbind('delete, backspace')\n },\n // 绘制快捷键\n addMeasureListener: () => {\n hotkeys('ctrl+z, command+z', this.undo)\n hotkeys('esc', this.cancel)\n hotkeys('enter', this.endMeasureByEnter)\n\n this.five.on('mode.change', this.endMeasureByModeChange)\n this.five.on('pano.moveTo', this.endMeasureByPanoMove)\n this.five.on('model.changeShownFloor', this.endMeasureByFloorChange)\n },\n removeMeasureListener: () => {\n hotkeys.unbind('ctrl+z, command+z')\n hotkeys.unbind('esc')\n hotkeys.unbind('enter')\n\n this.five.off('mode.change', this.endMeasureByModeChange)\n this.five.off('pano.moveTo', this.endMeasureByPanoMove)\n this.five.off('model.changeShownFloor', this.endMeasureByFloorChange)\n },\n }\n\n private onMoveToPano = (panoIndex: number) => {\n const items = this.group.children.filter((item) => item !== this.currentMeasureMesh)\n const raycaster = new THREERaycaster()\n\n items.forEach((item) => {\n item.unselect()\n\n // 如果当前点位和item的绘制点位相同,则直接显示\n if ((item as any)['__five_pano_index'] === panoIndex) {\n item.visible = true\n return\n }\n\n // check intersect\n const needShow = item.line.points?.some((point) => {\n // raycaster.setFromCamera\n const direction = point.clone().sub(this.five.camera.position).normalize()\n raycaster.set(this.five.camera.position, direction)\n const intersect = this.five.model.intersectRaycaster(raycaster)?.[0]?.point\n if (!intersect) return true\n const distanceError = 0.01\n const distanceToPoint = point.distanceTo(this.five.camera.position)\n const distanceToIntersect = intersect.distanceTo(this.five.camera.position)\n const canSee = distanceToIntersect + distanceError > distanceToPoint\n return canSee\n })\n\n if (needShow) {\n item.visible = true\n } else {\n item.visible = false\n }\n\n this.five.needsRender = true\n })\n }\n\n private onModeChange = (mode: Mode) => {\n if (mode === 'Mapview') {\n this.group.children.forEach((item) => {\n item.visible = true\n })\n }\n }\n\n private onClick = ({ origDomEvent: event, target }: Pick<FiveDomEvent, 'origDomEvent' | 'target'>) => {\n const clickedMeasureMesh = target as MeasureMesh\n\n if (!clickedMeasureMesh) return\n\n if (clickedMeasureMesh.selected) {\n clickedMeasureMesh.unselect()\n this.cursor.removeDeleteButton()\n return\n }\n\n let clientX: number | undefined\n let clientY: number | undefined\n\n // 使用类型守卫和联合类型来处理不同类型的事件\n if (event) {\n // 检查是否为触摸事件\n if ('touches' in event && event.touches && event.touches[0]) {\n clientX = event.touches[0].clientX\n clientY = event.touches[0].clientY\n }\n // 检查是否为鼠标事件\n else if ('clientX' in event && 'clientY' in event) {\n clientX = event.clientX as number\n clientY = event.clientY as number\n }\n }\n\n if (clientX === undefined || clientY === undefined) return\n\n this.group.children.forEach((item) => item.unselect())\n\n clickedMeasureMesh.select()\n\n const deleteMesh = () => {\n // Remove event listeners before removing the mesh\n this.removeMeshEventListeners(clickedMeasureMesh)\n\n // Remove the mesh\n clickedMeasureMesh.removeFromParent()\n this.cursor.removeDeleteButton()\n this.five.needsRender = true\n }\n\n // 获取容器元素,添加 fallback\n const containerElement = this.five.getElement()?.parentElement || document.body\n\n this.cursor.showDeleteButton({\n clientX,\n clientY,\n container: containerElement,\n onClick: deleteMesh,\n })\n\n this.five.once('cameraUpdate', () => {\n clickedMeasureMesh.unselect()\n this.cursor.removeDeleteButton()\n })\n }\n\n private onHover = ({ target }: Pick<FiveDomEvent, 'target'>) => {\n if (this.currentMeasureMesh) return\n\n const hoveredMeasureMesh = target as MeasureMesh\n if (!hoveredMeasureMesh) return\n hoveredMeasureMesh.hover()\n }\n\n private onUnHover = ({ target }: Pick<FiveDomEvent, 'target'>) => {\n if (this.currentMeasureMesh) return\n\n const unHoveredMeasureMesh = target as MeasureMesh\n if (!unHoveredMeasureMesh) return\n unHoveredMeasureMesh.unhover()\n }\n\n private deleteSelectedMesh = () => {\n const needsDeleteMeshes = this.group.children.filter((item) => item.selected)\n\n needsDeleteMeshes.forEach((item) => {\n // Remove event listeners before removing the mesh\n this.removeMeshEventListeners(item)\n\n // Remove the mesh\n item.removeFromParent()\n })\n\n this.cursor.removeDeleteButton()\n this.five.needsRender = true\n }\n\n // Helper method to remove all event listeners from a mesh\n private removeMeshEventListeners = (item: MeasureMesh) => {\n // Remove long press listeners from endpoints\n item.line.pointMeshes?.forEach((pointMesh) => {\n const cleanup = (pointMesh as any).__longPressCleanup\n if (cleanup) {\n cleanup()\n delete (pointMesh as any).__longPressCleanup\n }\n })\n\n // Remove DOM event listeners\n item.line.doms?.forEach((dom) => {\n if (dom?.container) {\n dom.container.onclick = null\n dom.container.onmouseenter = null\n dom.container.onmouseleave = null\n }\n })\n\n if (item.polygon.areaDom?.container) {\n item.polygon.areaDom.container.onclick = null\n item.polygon.areaDom.container.onmouseenter = null\n item.polygon.areaDom.container.onmouseleave = null\n }\n\n // Remove THREE.js event listeners\n this.fiveDomEvents.removeEventListener(item, 'click')\n this.fiveDomEvents.removeEventListener(item, 'hover')\n this.fiveDomEvents.removeEventListener(item, 'unHover')\n }\n\n private updateSelectAdsorbedHelper = () => {\n if (!this.currentMeasureMesh || this.currentMeasureMesh.points.length === 0) {\n this.pointSelector.setAdherePoints(null)\n this.pointSelector.adhereLine = []\n this.pointSelector.adherePlane = []\n return\n }\n\n if (this.currentMeasureMesh.points.length >= 1) {\n this.pointSelector.setAdherePoints([this.currentMeasureMesh.points[0]])\n const lastPoint = this.currentMeasureMesh.points.at(-1)\n // xyz三轴吸附\n this.pointSelector.adhereLine = [\n new THREE.Line3(new THREE.Vector3(1, 0, 0).add(lastPoint), new THREE.Vector3(-1, 0, 0).add(lastPoint)),\n new THREE.Line3(new THREE.Vector3(0, 1, 0).add(lastPoint), new THREE.Vector3(0, -1, 0).add(lastPoint)),\n new THREE.Line3(new THREE.Vector3(0, 0, 1).add(lastPoint), new THREE.Vector3(0, 0, -1).add(lastPoint)),\n ]\n this.pointSelector.adherePlane = []\n }\n\n if (this.currentMeasureMesh.points.length >= 3) {\n const plane = new THREE.Plane().setFromCoplanarPoints(\n this.currentMeasureMesh.points[0],\n this.currentMeasureMesh.points[1],\n this.currentMeasureMesh.points[2],\n )\n this.pointSelector.adherePlane = [plane]\n } else {\n this.pointSelector.adherePlane = []\n }\n }\n\n private addMeshEventListeners = (item: MeasureMesh) => {\n // First remove any existing event listeners to prevent duplicates\n this.removeMeshEventListeners(item)\n\n // Add long press functionality to endpoints\n this.addEndpointLongPressListeners(item)\n\n // Add DOM event listeners for labels\n item.line.doms?.forEach((dom) => {\n if (dom?.container) {\n dom.container.onclick = (event) => this.onClick({ origDomEvent: event, target: item })\n dom.container.onmouseenter = () => this.onHover({ target: item })\n dom.container.onmouseleave = () => this.onUnHover({ target: item })\n }\n })\n\n if (item.polygon.areaDom?.container) {\n item.polygon.areaDom.container.onclick = (event) => this.onClick({ origDomEvent: event, target: item })\n item.polygon.areaDom.container.onmouseenter = () => this.onHover({ target: item })\n item.polygon.areaDom.container.onmouseleave = () => this.onUnHover({ target: item })\n }\n\n // Add THREE.js event listeners for the mesh\n this.fiveDomEvents.addEventListener(item, 'click', this.onClick)\n this.fiveDomEvents.addEventListener(item, 'hover', this.onHover)\n this.fiveDomEvents.addEventListener(item, 'unHover', this.onUnHover)\n }\n\n private addEndpointLongPressListeners = (item: MeasureMesh) => {\n // Setup global touch handler if not already done\n this.setupGlobalTouchHandler()\n\n // Add long press functionality to each endpoint\n item.line.pointMeshes.forEach((pointMesh, index) => {\n let pressTimer: NodeJS.Timeout | undefined\n let isLongPressTriggered = false\n\n // For closed polygons, we need to map point mesh index to actual point index\n // In closed polygons, the last point is a duplicate of the first point\n let actualPointIndex = index\n if (item.isPolygon && item.points.length > 3) {\n // For closed polygons, if this is the last point mesh, it corresponds to point index 0\n if (index === item.line.pointMeshes.length - 1) {\n actualPointIndex = 0\n }\n // Also handle case where there are extra point meshes due to geometry recreation\n if (index >= item.points.length) {\n actualPointIndex = 0 // Map any extra point meshes to the first point\n }\n }\n\n // Unified handler for mouse and touch down events\n const onPointerDown = (event: FiveDomEvent) => {\n // Don't activate repositioning if we're currently drawing a measurement\n if (this.currentMeasureMesh) {\n return\n }\n\n isLongPressTriggered = false\n\n // Store initial pointer position for drag detection\n let pointerDownPosition: { x: number; y: number } | null = null\n if (event.origDomEvent) {\n if ('clientX' in event.origDomEvent && 'clientY' in event.origDomEvent) {\n // Mouse event\n pointerDownPosition = {\n x: event.origDomEvent.clientX as number,\n y: event.origDomEvent.clientY as number,\n }\n } else if ('touches' in event.origDomEvent && event.origDomEvent.touches && event.origDomEvent.touches[0]) {\n // Touch event\n pointerDownPosition = {\n x: event.origDomEvent.touches[0].clientX,\n y: event.origDomEvent.touches[0].clientY,\n }\n } else if ('changedTouches' in event.origDomEvent && event.origDomEvent.changedTouches && event.origDomEvent.changedTouches[0]) {\n // Touch end event uses changedTouches\n pointerDownPosition = {\n x: event.origDomEvent.changedTouches[0].clientX,\n y: event.origDomEvent.changedTouches[0].clientY,\n }\n }\n }\n\n // Prevent Five canvas events during long press\n event.stopPropagation()\n if (event.origDomEvent) {\n event.origDomEvent.preventDefault()\n event.origDomEvent.stopPropagation()\n }\n\n // Show long press visual feedback\n this.showLongPressIndicator(pointMesh, pointerDownPosition)\n\n // Add global pointer move listener to detect movement away from button\n const globalMoveHandler = (e: MouseEvent | TouchEvent) => {\n if (pointerDownPosition) {\n let clientX: number, clientY: number\n if ('touches' in e && e.touches[0]) {\n clientX = e.touches[0].clientX\n clientY = e.touches[0].clientY\n } else if ('clientX' in e) {\n clientX = e.clientX\n clientY = e.clientY\n } else {\n return\n }\n\n const distance = Math.sqrt(Math.pow(clientX - pointerDownPosition.x, 2) + Math.pow(clientY - pointerDownPosition.y, 2))\n // If pointer moves more than 10 pixels away, cancel long press\n if (distance > 10) {\n this.hideLongPressIndicator()\n if (pressTimer) {\n clearTimeout(pressTimer)\n pressTimer = undefined\n }\n this.cleanupGlobalListeners?.()\n }\n }\n }\n\n // Store cleanup function for easy access\n this.cleanupGlobalListeners = () => {\n document.removeEventListener('mousemove', globalMoveHandler as EventListener)\n document.removeEventListener('touchmove', globalMoveHandler as EventListener)\n }\n\n document.addEventListener('mousemove', globalMoveHandler as EventListener)\n document.addEventListener('touchmove', globalMoveHandler as EventListener, { passive: false })\n\n pressTimer = setTimeout(() => {\n isLongPressTriggered = true\n this.cleanupGlobalListeners?.()\n\n // Hide the indicator when repositioning starts\n this.hideLongPressIndicator()\n\n // Start repositioning mode with pointer position tracking - use actualPointIndex\n this.startRepositioning(item, actualPointIndex, true, pointerDownPosition) // Set isDragMode to true\n }, 500) // 500ms for long press\n }\n\n const onPointerUp = () => {\n if (pressTimer) {\n clearTimeout(pressTimer)\n pressTimer = undefined\n }\n\n // Clean up global move listeners\n this.cleanupGlobalListeners?.()\n\n // Hide the indicator if still showing\n this.hideLongPressIndicator()\n\n // If we were in repositioning mode and pointer was released\n if (isLongPressTriggered && this.repositioningState) {\n if (this.repositioningState.isDragMode && this.repositioningState.hasMoved) {\n // Let the global pointer up handler confirm the repositioning\n } else if (!this.repositioningState.isDragMode) {\n // Click mode - stay in repositioning for point-and-click\n }\n isLongPressTriggered = false\n }\n }\n\n const onClick = (event: FiveDomEvent) => {\n // Prevent normal click action if long press was triggered\n if (isLongPressTriggered) {\n event.stopPropagation()\n isLongPressTriggered = false\n return false\n }\n }\n\n // Add event listeners to the point mesh for mouse events\n this.fiveDomEvents.addEventListener(pointMesh, 'mousedown', onPointerDown)\n this.fiveDomEvents.addEventListener(pointMesh, 'mouseup', onPointerUp)\n this.fiveDomEvents.addEventListener(pointMesh, 'click', onClick)\n\n // Store reference to handlers for touch events (handled by global touch handler)\n // Use actualPointIndex instead of loop index\n ;(pointMesh as any).__longPressHandlers = {\n onPointerDown,\n onPointerUp,\n onClick,\n measureMesh: item,\n pointIndex: actualPointIndex, // Use the corrected point index\n }\n\n // Store cleanup function\n ;(pointMesh as any).__longPressCleanup = () => {\n if (pressTimer) {\n clearTimeout(pressTimer)\n }\n this.cleanupGlobalListeners?.()\n this.hideLongPressIndicator()\n this.fiveDomEvents.removeEventListener(pointMesh, 'mousedown', onPointerDown)\n this.fiveDomEvents.removeEventListener(pointMesh, 'mouseup', onPointerUp)\n this.fiveDomEvents.removeEventListener(pointMesh, 'click', onClick)\n\n // Remove handler references\n delete (pointMesh as any).__longPressHandlers\n }\n })\n }\n\n /**\n * @description Load measurement data from external source\n * @param data Array of point data for measurements\n */\n public load = (data: { points: THREE.Vector3[] }[]) => {\n // Clear existing measurements\n this.clear()\n\n // Create new meshes from the data\n data.forEach((item) => {\n const measureMesh = new MeasureMesh({\n lineStyle: this.lineStyle,\n polygonStyle: this.polygonStyle,\n })\n\n // Labels inherit the Five owner from the scene parent.\n this.group.add(measureMesh)\n measureMesh.setPoints(item.points)\n\n // Add event listeners to the loaded mesh\n this.addMeshEventListeners(measureMesh)\n\n // Set pano index\n ;(measureMesh as any)['__five_pano_index'] = this.five.panoIndex\n })\n\n this.five.needsRender = true\n }\n\n /**\n * Start repositioning an endpoint\n */\n private startRepositioning = (\n measureMesh: MeasureMesh,\n pointIndex: number,\n isDragMode = false,\n mouseDownPosition?: { x: number; y: number } | null,\n ) => {\n // Don't start repositioning if already in measure mode or already repositioning\n if (this.currentMeasureMesh || this.repositioningState) {\n return\n }\n\n // Store original state\n this.repositioningState = {\n measureMesh,\n pointIndex,\n originalOpacity: measureMesh.line.lineOpacity,\n originalMeshState: measureMesh.points.map((p) => p.clone()),\n isDragMode,\n mouseDownPosition: mouseDownPosition || undefined,\n hasMoved: false,\n }\n\n // Apply preview styling (lower opacity, dashed lines)\n this.applyRepositioningStyle(measureMesh, true)\n\n // Prevent Five canvas interactions during repositioning\n this.five.on('wantsGesture', this.preventFiveGestures)\n\n if (isDragMode) {\n // For drag mode, use global mouse events since PointSelector stops when mouse is held down\n this.enableGlobalMouseTracking()\n } else {\n // For click mode, use PointSelector normally\n this.pointSelector.actionIfNoIntersection = 'virtualPoint'\n this.pointSelector.enable()\n this.pointSelector.on('intersectionUpdate', this.onRepositioningMove)\n this.pointSelector.on('select', this.onRepositioningConfirm)\n this.pointSelector.on('disable', this.cancelRepositioning)\n }\n\n // Add escape key listener\n hotkeys('esc', this.cancelRepositioning)\n }\n\n /**\n * Helper method to safely update polygon points while maintaining closure\n */\n private updatePolygonPoints = (\n measureMesh: MeasureMesh,\n newPoints: THREE.Vector3[],\n updatedPointIndex?: number,\n isLiveUpdate = false,\n ) => {\n // Ensure polygon closure is maintained for closed polygons\n if (measureMesh.isPolygon && newPoints.length > 3 && updatedPointIndex !== undefined) {\n const lastPointIndex = newPoints.length - 1\n\n // If updating first point, also update last point\n if (updatedPointIndex === 0) {\n newPoints[lastPointIndex] = newPoints[0].clone()\n }\n // If updating last point, also update first point\n else if (updatedPointIndex === lastPointIndex) {\n newPoints[0] = newPoints[lastPointIndex].clone()\n }\n }\n\n // Update internal points array\n measureMesh.points = newPoints\n\n if (isLiveUpdate && this.repositioningState) {\n // During live repositioning, update geometry directly without recreating point meshes\n // This prevents interference with ongoing repositioning\n\n // Update line geometry manually\n const lineMesh = measureMesh.line as any\n lineMesh.points = newPoints\n\n if (newPoints.length >= 2) {\n const positions = newPoints.flatMap((v) => [v.x, v.y, v.z])\n lineMesh.line1.geometry.setPositions(positions)\n lineMesh.line1.computeLineDistances()\n }\n\n // Update point mesh positions visually so they follow the mouse\n if (updatedPointIndex !== undefined && measureMesh.line.pointMeshes) {\n const updatedPosition = newPoints[updatedPointIndex]\n\n // For closed polygons, handle first/last point synchronization\n if (measureMesh.isPolygon && newPoints.length > 3) {\n const lastPointIndex = newPoints.length - 1\n\n if (updatedPointIndex === 0) {\n // Moving first point, also move last point mesh\n const firstPointMesh = measureMesh.line.pointMeshes[0]\n const lastPointMesh = measureMesh.line.pointMeshes[lastPointIndex]\n if (firstPointMesh) firstPointMesh.position.copy(updatedPosition)\n if (lastPointMesh) lastPointMesh.position.copy(updatedPosition)\n } else if (updatedPointIndex === lastPointIndex) {\n // Moving last point, also move first point mesh\n const firstPointMesh = measureMesh.line.pointMeshes[0]\n const lastPointMesh = measureMesh.line.pointMeshes[lastPointIndex]\n if (firstPointMesh) firstPointMesh.position.copy(updatedPosition)\n if (lastPointMesh) lastPointMesh.position.copy(updatedPosition)\n } else {\n // Moving a middle point\n const pointMesh = measureMesh.line.pointMeshes[updatedPointIndex]\n if (pointMesh) pointMesh.position.copy(updatedPosition)\n }\n } else {\n // Not a closed polygon, just update the single point\n const pointMesh = measureMesh.line.pointMeshes[updatedPointIndex]\n if (pointMesh) pointMesh.position.copy(updatedPosition)\n }\n }\n\n // Update polygon geometry if it exists\n if (measureMesh.isPolygon) {\n measureMesh.polygon.setPoints(newPoints)\n }\n } else {\n // When not in live update mode (final confirmation), use proper setPoints\n // This ensures all meshes are properly recreated\n measureMesh.line.setPoints(newPoints)\n\n if (measureMesh.isPolygon) {\n measureMesh.polygon.setPoints(newPoints)\n }\n }\n }\n\n /**\n * Handle mouse movement during repositioning\n */\n private onRepositioningMove = (intersection?: PointIntersection) => {\n if (!this.repositioningState || !intersection) {\n return\n }\n\n const { measureMesh, pointIndex } = this.repositioningState\n\n // Mark that mouse has moved (any intersection update means movement)\n this.repositioningState.hasMoved = true\n\n // Create new points array\n const newPoints = [...measureMesh.points]\n newPoints[pointIndex] = intersection.point.clone()\n\n // Use the helper method with live update mode to avoid recreating point meshes\n this.updatePolygonPoints(measureMesh, newPoints, pointIndex, true)\n\n this.five.needsRender = true\n }\n\n /**\n * Confirm repositioning with click\n */\n private onRepositioningConfirm = (intersection?: PointIntersection) => {\n if (!this.repositioningState || !intersection) return\n\n const { measureMesh, pointIndex } = this.repositioningState\n\n // Finalize the position\n const newPoints = [...measureMesh.points]\n newPoints[pointIndex] = intersection.point.clone()\n\n // Use helper method in final mode to properly recreate point meshes\n this.updatePolygonPoints(measureMesh, newPoints, pointIndex, false)\n\n // Restore normal styling\n this.applyRepositioningStyle(measureMesh, false)\n\n // Re-add event listeners since setPoints() recreates pointMeshes\n this.addEndpointLongPressListeners(measureMesh)\n\n // Clean up repositioning state\n this.cleanupRepositioning()\n }\n\n /**\n * Confirm repositioning when drag ends (mouse up after long press drag)\n */\n private confirmRepositioningOnDragEnd = () => {\n if (!this.repositioningState) return\n\n const { measureMesh, pointIndex } = this.repositioningState\n\n // Use the current position (already updated by onRepositioningMove)\n // Apply the helper method in final mode to ensure proper point mesh recreation\n const finalPoints = [...measureMesh.points]\n this.updatePolygonPoints(measureMesh, finalPoints, pointIndex, false)\n\n // Restore normal styling\n this.applyRepositioningStyle(measureMesh, false)\n\n // Re-add event listeners since setPoints() recreates pointMeshes\n this.addEndpointLongPressListeners(measureMesh)\n\n // Clean up repositioning state\n this.cleanupRepositioning()\n }\n\n /**\n * Cancel repositioning (restore original position)\n */\n private cancelRepositioning = () => {\n if (!this.repositioningState) return\n\n const { measureMesh, originalMeshState } = this.repositioningState\n\n // Restore original points using the helper method in final mode to properly recreate point meshes\n this.updatePolygonPoints(measureMesh, originalMeshState, undefined, false)\n\n // Restore normal styling\n this.applyRepositioningStyle(measureMesh, false)\n\n // Re-add event listeners since setPoints() recreates pointMeshes\n this.addEndpointLongPressListeners(measureMesh)\n\n // Clean up repositioning state\n this.cleanupRepositioning()\n }\n\n /**\n * Apply or remove repositioning preview styling\n */\n private applyRepositioningStyle = (measureMesh: MeasureMesh, isRepositioning: boolean) => {\n const opacity = isRepositioning ? 0.4 : 1.0\n const dashed = isRepositioning\n\n // Apply to line\n measureMesh.line.setStyle({\n lineOpacity: opacity,\n dashed: dashed,\n cssStyle: isRepositioning ? 'pointer-events: none;' : 'pointer-events: auto;',\n })\n\n // Apply to polygon if exists\n if (measureMesh.isPolygon) {\n measureMesh.polygon.setStyle({\n opacity: opacity * 0.3, // Even more transparent for area\n })\n }\n\n // Apply to endpoints\n measureMesh.line.pointMeshes.forEach((pointMesh) => {\n pointMesh.setStyle({\n opacity: opacity,\n })\n })\n }\n\n /**\n * Enable global mouse tracking for drag mode (when PointSelector can't track due to mouse being held down)\n */\n private enableGlobalMouseTracking = () => {\n const fiveElement = this.five.getElement()\n if (!fiveElement) return\n\n let currentIntersection: any = null\n\n const onGlobalMouseMove = (event: MouseEvent) => {\n if (!this.repositioningState) return\n\n // Convert mouse position to NDC coordinates\n const rect = fiveElement.getBoundingClientRect()\n const x = ((event.clientX - rect.left) / rect.width) * 2 - 1\n const y = -((event.clientY - rect.top) / rect.height) * 2 + 1\n\n // Create raycaster from mouse position\n const raycaster = new THREE.Raycaster()\n raycaster.setFromCamera(new THREE.Vector2(x, y), this.five.camera)\n\n // Get intersection with model\n const intersects = this.five.model.intersectRaycaster(raycaster)\n if (intersects && intersects.length > 0) {\n currentIntersection = {\n point: intersects[0].point,\n distance: intersects[0].distance,\n face: intersects[0].face,\n raycaster,\n }\n this.onRepositioningMove(currentIntersection)\n } else {\n // Create virtual point if no model intersection\n const virtualPoint = raycaster.ray.origin.clone().add(raycaster.ray.direction.clone().multiplyScalar(5))\n currentIntersection = {\n point: virtualPoint,\n distance: 5,\n raycaster,\n isVirtual: true,\n }\n this.onRepositioningMove(currentIntersection)\n }\n }\n\n const onGlobalTouchMove = (event: TouchEvent) => {\n if (!this.repositioningState || !event.touches[0]) return\n\n // Convert touch position to NDC coordinates\n const rect = fiveElement.getBoundingClientRect()\n const touch = event.touches[0]\n const x = ((touch.clientX - rect.left) / rect.width) * 2 - 1\n const y = -((touch.clientY - rect.top) / rect.height) * 2 + 1\n\n // Create raycaster from touch position\n const raycaster = new THREE.Raycaster()\n raycaster.setFromCamera(new THREE.Vector2(x, y), this.five.camera)\n\n // Get intersection with model\n const intersects = this.five.model.intersectRaycaster(raycaster)\n if (intersects && intersects.length > 0) {\n currentIntersection = {\n point: intersects[0].point,\n distance: intersects[0].distance,\n face: intersects[0].face,\n raycaster,\n }\n this.onRepositioningMove(currentIntersection)\n } else {\n // Create virtual point if no model intersection\n const virtualPoint = raycaster.ray.origin.clone().add(raycaster.ray.direction.clone().multiplyScalar(5))\n currentIntersection = {\n point: virtualPoint,\n distance: 5,\n raycaster,\n isVirtual: true,\n }\n this.onRepositioningMove(currentIntersection)\n }\n }\n\n const onGlobalMouseUp = (event: MouseEvent) => {\n if (!this.repositioningState) return\n\n // Confirm repositioning with current position\n if (currentIntersection) {\n this.onRepositioningConfirm(currentIntersection)\n } else {\n // Fallback: confirm with current position\n this.confirmRepositioningOnDragEnd()\n }\n }\n\n const onGlobalTouchEnd = (event: TouchEvent) => {\n if (!this.repositioningState) return\n\n // Confirm repositioning with current position\n if (currentIntersection) {\n this.onRepositioningConfirm(currentIntersection)\n } else {\n // Fallback: confirm with current position\n this.confirmRepositioningOnDragEnd()\n }\n }\n\n const onGlobalClick = (event: MouseEvent) => {\n if (!this.repositioningState) return\n\n if (currentIntersection) {\n this.onRepositioningConfirm(currentIntersection)\n }\n }\n\n // Add global event listeners for both mouse and touch\n document.addEventListener('mousemove', onGlobalMouseMove)\n document.addEventListener('mouseup', onGlobalMouseUp)\n document.addEventListener('click', onGlobalClick)\n document.addEventListener('touchmove', onGlobalTouchMove, { passive: false })\n document.addEventListener('touchend', onGlobalTouchEnd, { passive: false })\n\n // Store cleanup function\n ;(this.repositioningState as any).__globalMouseCleanup = () => {\n document.removeEventListener('mousemove', onGlobalMouseMove)\n document.removeEventListener('mouseup', onGlobalMouseUp)\n document.removeEventListener('click', onGlobalClick)\n document.removeEventListener('touchmove', onGlobalTouchMove)\n document.removeEventListener('touchend', onGlobalTouchEnd)\n }\n }\n\n /**\n * Show long press visual feedback circle\n */\n private showLongPressIndicator = (pointMesh: PointMesh, mousePosition?: { x: number; y: number } | null) => {\n // Hide any existing indicator first\n this.hideLongPressIndicator()\n\n const fiveElement = this.five.getElement()\n if (!fiveElement) return\n\n // Prevent Five gestures while indicator is showing\n this.five.on('wantsGesture', this.preventFiveGestures)\n\n // Create indicator element\n const indicator = document.createElement('div')\n indicator.style.position = 'absolute'\n indicator.style.width = '80px'\n indicator.style.height = '80px'\n indicator.style.border = '6px solid #f0f0f0'\n indicator.style.borderRadius = '50%'\n indicator.style.pointerEvents = 'none'\n indicator.style.zIndex = '10000'\n indicator.style.boxSizing = 'border-box'\n indicator.style.animation = 'longPressShrink 500ms linear forwards'\n\n // Add CSS animation keyframes if not already added\n if (!document.querySelector('#longpress-keyframes')) {\n const style = document.createElement('style')\n style.id = 'longpress-keyframes'\n style.textContent = `\n @keyframes longPressShrink {\n from {\n transform: translate(-50%, -50%) scale(1);\n opacity: 0.8;\n }\n to {\n transform: translate(-50%, -50%) scale(0);\n opacity: 1;\n }\n }\n `\n document.head.appendChild(style)\n }\n\n // Position the indicator\n if (mousePosition) {\n indicator.style.left = `${mousePosition.x}px`\n indicator.style.top = `${mousePosition.y}px`\n indicator.style.transform = 'translate(-50%, -50%)'\n } else {\n // Fallback: position at point mesh screen position\n const pointWorldPosition = pointMesh.getWorldPosition(new THREE.Vector3())\n const pointScreenPosition = pointWorldPosition.clone().project(this.five.camera)\n const rect = fiveElement.getBoundingClientRect()\n\n const x = ((pointScreenPosition.x + 1) * rect.width) / 2 + rect.left\n const y = ((-pointScreenPosition.y + 1) * rect.height) / 2 + rect.top\n\n indicator.style.left = `${x}px`\n indicator.style.top = `${y}px`\n indicator.style.transform = 'translate(-50%, -50%)'\n }\n\n // Add to page\n document.body.appendChild(indicator)\n this.longPressIndicator = indicator\n }\n\n /**\n * Hide long press visual feedback circle\n */\n private hideLongPressIndicator = () => {\n if (this.longPressIndicator) {\n this.longPressIndicator.remove()\n this.longPressIndicator = null\n\n // Re-enable Five gestures when indicator is hidden\n this.five.off('wantsGesture', this.preventFiveGestures)\n }\n }\n\n /**\n * Prevent Five canvas gestures during repositioning\n */\n private preventFiveGestures = (): false => {\n return false // Prevent all Five gestures during repositioning\n }\n\n /**\n * Clean up repositioning state and event listeners\n */\n private cleanupRepositioning = () => {\n if (this.repositioningState) {\n // Clean up global mouse tracking if it was enabled\n const globalMouseCleanup = (this.repositioningState as any).__globalMouseCleanup\n if (globalMouseCleanup) {\n globalMouseCleanup()\n }\n\n // Clean up PointSelector if it was used (click mode)\n if (!this.repositioningState.isDragMode) {\n this.pointSelector.off('intersectionUpdate', this.onRepositioningMove)\n this.pointSelector.off('select', this.onRepositioningConfirm)\n this.pointSelector.off('disable', this.cancelRepositioning)\n this.pointSelector.disable()\n }\n }\n\n // Remove Five gesture prevention\n this.five.off('wantsGesture', this.preventFiveGestures)\n\n // Remove escape key listener\n hotkeys.unbind('esc', this.cancelRepositioning)\n\n this.repositioningState = null\n this.five.needsRender = true\n }\n\n private setupGlobalTouchHandler = () => {\n if (this.globalTouchHandler?.isSetup) return\n\n const fiveElement = this.five.getElement()\n if (!fiveElement) return\n\n const onGlobalTouchStart = (e: TouchEvent) => {\n if (this.currentMeasureMesh) return // Don't activate during drawing\n\n const touch = e.touches[0]\n if (!touch) return\n\n // Check if touch is on any point mesh by doing raycasting\n const rect = fiveElement.getBoundingClientRect()\n const x = ((touch.clientX - rect.left) / rect.width) * 2 - 1\n const y = -((touch.clientY - rect.top) / rect.height) * 2 + 1\n\n const raycaster = new THREE.Raycaster()\n raycaster.setFromCamera(new THREE.Vector2(x, y), this.five.camera)\n\n // Configure raycaster for different types of geometry\n // Points (used by PointMesh) need a higher threshold for reliable detection\n raycaster.params.Points.threshold = 0.5 // Increased threshold for better point detection\n raycaster.params.Line.threshold = 0.1\n raycaster.params.Mesh = {}\n\n // Collect all potential hits with their distances\n const allHits: { pointMesh: any; handlers: any; distance: number; measureMesh: any; pointIndex: number }[] = []\n\n // Check all point meshes from all measurements\n for (const measureMesh of this.group.children) {\n // Safety check: ensure measureMesh and its line property exist\n if (!measureMesh || !measureMesh.line || !measureMesh.line.pointMeshes) {\n continue\n }\n\n for (let loopIndex = 0; loopIndex < measureMesh.line.pointMeshes.length; loopIndex++) {\n const pointMesh = measureMesh.line.pointMeshes[loopIndex]\n if (!pointMesh) continue\n\n // PointMesh has fontMesh and backgroundMesh children - intersect with both\n const intersects = raycaster.intersectObject(pointMesh, true) // true = recursive to check children\n if (intersects.length > 0) {\n const handlers = (pointMesh as any).__longPressHandlers\n if (handlers) {\n // For point intersections, distance checking is less reliable\n // Instead, let's rely on the raycaster threshold and screen distance\n const screenDistance = this.calculateScreenDistance(touch, pointMesh, fiveElement)\n\n if (screenDistance < 30) {\n // Within 30 pixels on screen\n allHits.push({\n pointMesh,\n handlers,\n distance: screenDistance, // Use screen distance for sorting\n measureMesh: handlers.measureMesh,\n pointIndex: handlers.pointIndex, // Use the STORED pointIndex, not the loop index\n })\n }\n }\n }\n }\n }\n\n if (allHits.length > 0) {\n // Sort by screen distance (closest first) and take the closest hit\n allHits.sort((a, b) => a.distance - b.distance)\n const closestHit = allHits[0]\n\n // Don't start if already repositioning\n if (this.repositioningState) {\n return\n }\n\n // Create a synthetic FiveDomEvent\n const syntheticEvent: FiveDomEvent = {\n type: 'mousedown',\n target: closestHit.pointMesh,\n origDomEvent: e,\n raycaster,\n intersects: [{ distance: 0 }] as any, // Use dummy distance since we're using screen distance\n stopPropagation: () => {\n e.stopPropagation()\n },\n }\n\n // Additional validation before calling handler\n if (closestHit.handlers && typeof closestHit.handlers.onPointerDown === 'function') {\n closestHit.handlers.onPointerDown(syntheticEvent)\n }\n }\n }\n\n const onGlobalTouchEnd = (e: TouchEvent) => {\n // Only call onPointerUp for handlers that actually exist and are valid\n // We need to be more careful here to avoid the undefined error\n for (const measureMesh of this.group.children) {\n // Safety check: ensure measureMesh and its line property exist\n if (!measureMesh || !measureMesh.line || !measureMesh.line.pointMeshes) {\n continue\n }\n\n for (const pointMesh of measureMesh.line.pointMeshes) {\n if (!pointMesh) continue\n\n const handlers = (pointMesh as any).__longPressHandlers\n if (handlers && typeof handlers.onPointerUp === 'function') {\n handlers.onPointerUp()\n }\n }\n }\n }\n\n // Add global touch listeners to the Five canvas element\n fiveElement.addEventListener('touchstart', onGlobalTouchStart, { passive: false })\n fiveElement.addEventListener('touchend', onGlobalTouchEnd, { passive: false })\n\n this.globalTouchHandler = {\n isSetup: true,\n onTouchStart: onGlobalTouchStart,\n onTouchEnd: onGlobalTouchEnd,\n }\n }\n\n // Remove the stub methods since they're not needed\n private disposeGlobalTouchHandler = () => {\n if (this.globalTouchHandler?.isSetup) {\n const fiveElement = this.five.getElement()\n if (fiveElement) {\n fiveElement.removeEventListener('touchstart', this.globalTouchHandler.onTouchStart)\n fiveElement.removeEventListener('touchend', this.globalTouchHandler.onTouchEnd)\n }\n this.globalTouchHandler = null\n }\n }\n\n /**\n * Calculate screen distance between touch/mouse point and point mesh\n */\n private calculateScreenDistance = (\n pointer: Touch | { clientX: number; clientY: number },\n pointMesh: any,\n fiveElement: HTMLElement,\n ): number => {\n // Get pointer position in screen coordinates\n const pointerX = pointer.clientX\n const pointerY = pointer.clientY\n\n // Get point mesh world position\n const worldPosition = pointMesh.getWorldPosition(new THREE.Vector3())\n\n // Project world position to screen coordinates\n const screenPosition = worldPosition.clone().project(this.five.camera)\n\n // Convert NDC to screen pixels\n const rect = fiveElement.getBoundingClientRect()\n const screenX = ((screenPosition.x + 1) * rect.width) / 2 + rect.left\n const screenY = ((-screenPosition.y + 1) * rect.height) / 2 + rect.top\n\n // Calculate distance in pixels\n const dx = pointerX - screenX\n const dy = pointerY - screenY\n return Math.sqrt(dx * dx + dy * dy)\n }\n}\n","import type { Five } from '@realsee/five-webgpu'\nimport { MeasureController } from './Controller'\n\nexport type MeasurePluginConfig = {\n unit: 'm' | 'ft' | 'mm'\n lengthEnable?: boolean\n /**\n * @description Length label precision.\n * - When unit is `m`: number of decimal places.\n * - When unit is `ft`: inch fraction denominator (`1` | `4` | `8` | `16` for 1\" / 1/4\" / 1/8\" / 1/16\").\n * Area measurements remain at fixed 2 decimal places.\n * @default 2\n */\n precision?: number\n}\n\n// 导出测量相关类型\nexport type { MeasureEndReason, MeasurePluginEventMap } from './Controller'\n\n// 导出多边形验证工具函数\nexport { validatePolygon } from './utils/validatePolygon'\n\nexport const MeasurePlugin = (five: Five, config?: MeasurePluginConfig) => new MeasureController(five, config)\n"],"ignoreList":[2],"mappings":"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"}