@2112-lab/central-plant 0.1.4 → 0.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/_virtual/_rollupPluginBabelHelpers.js +432 -1
- package/dist/cjs/node_modules/@2112-lab/pathfinder/dist/index.esm.js +1448 -1
- package/dist/cjs/node_modules/three/examples/jsm/controls/OrbitControls.js +1853 -1
- package/dist/cjs/node_modules/three/examples/jsm/exporters/GLTFExporter.js +3537 -1
- package/dist/cjs/node_modules/three/examples/jsm/exporters/OBJExporter.js +305 -1
- package/dist/cjs/node_modules/three/examples/jsm/exporters/PLYExporter.js +542 -1
- package/dist/cjs/node_modules/three/examples/jsm/exporters/STLExporter.js +218 -1
- package/dist/cjs/node_modules/three/examples/jsm/loaders/DRACOLoader.js +683 -1
- package/dist/cjs/node_modules/three/examples/jsm/loaders/GLTFLoader.js +4811 -1
- package/dist/cjs/node_modules/three/examples/jsm/loaders/RGBELoader.js +480 -1
- package/dist/cjs/node_modules/three/examples/jsm/renderers/CSS2DRenderer.js +309 -1
- package/dist/cjs/node_modules/three/examples/jsm/utils/BufferGeometryUtils.js +120 -1
- package/dist/cjs/src/analysis/analysis.js +560 -1
- package/dist/cjs/src/analysis/testing.js +958 -1
- package/dist/cjs/src/core/centralPlant.js +1149 -1
- package/dist/cjs/src/core/debugLogger.js +175 -1
- package/dist/cjs/src/core/mathUtils.js +574 -1
- package/dist/cjs/src/core/nameUtils.js +93 -1
- package/dist/cjs/src/data/export.js +716 -1
- package/dist/cjs/src/data/import.js +380 -1
- package/dist/cjs/src/data/numerics.js +522 -1
- package/dist/cjs/src/helpers/sceneHelper.js +572 -1
- package/dist/cjs/src/index.js +69 -1
- package/dist/cjs/src/managers/components/animationManager.js +123 -1
- package/dist/cjs/src/managers/components/componentManager.js +332 -1
- package/dist/cjs/src/managers/components/pathfindingManager.js +1441 -1
- package/dist/cjs/src/managers/controls/TransformControls.js +1063 -1
- package/dist/cjs/src/managers/controls/cameraControlsManager.js +79 -1
- package/dist/cjs/src/managers/controls/dragDropManager.js +1026 -1
- package/dist/cjs/src/managers/controls/keyboardControlsManager.js +395 -1
- package/dist/cjs/src/managers/controls/transformControlsManager.js +1807 -1
- package/dist/cjs/src/managers/environment/environmentManager.js +714 -1
- package/dist/cjs/src/managers/environment/textureConfig.js +229 -1
- package/dist/cjs/src/managers/scene/sceneExportManager.js +264 -1
- package/dist/cjs/src/managers/scene/sceneInitializationManager.js +346 -1
- package/dist/cjs/src/managers/scene/sceneOperationsManager.js +1509 -1
- package/dist/cjs/src/managers/scene/sceneTooltipsManager.js +661 -1
- package/dist/cjs/src/managers/system/disposalManager.js +444 -1
- package/dist/cjs/src/managers/system/hotReloadManager.js +291 -1
- package/dist/cjs/src/managers/system/performanceMonitor.js +863 -1
- package/dist/cjs/src/rendering/modelPreloader.js +369 -1
- package/dist/cjs/src/rendering/rendering2D.js +631 -1
- package/dist/cjs/src/rendering/rendering3D.js +685 -1
- package/dist/esm/_virtual/_rollupPluginBabelHelpers.js +396 -1
- package/dist/esm/node_modules/@2112-lab/pathfinder/dist/index.esm.js +1444 -1
- package/dist/esm/node_modules/three/examples/jsm/controls/OrbitControls.js +1849 -1
- package/dist/esm/node_modules/three/examples/jsm/exporters/GLTFExporter.js +3533 -1
- package/dist/esm/node_modules/three/examples/jsm/exporters/OBJExporter.js +301 -1
- package/dist/esm/node_modules/three/examples/jsm/exporters/PLYExporter.js +538 -1
- package/dist/esm/node_modules/three/examples/jsm/exporters/STLExporter.js +214 -1
- package/dist/esm/node_modules/three/examples/jsm/loaders/DRACOLoader.js +679 -1
- package/dist/esm/node_modules/three/examples/jsm/loaders/GLTFLoader.js +4807 -1
- package/dist/esm/node_modules/three/examples/jsm/loaders/RGBELoader.js +476 -1
- package/dist/esm/node_modules/three/examples/jsm/renderers/CSS2DRenderer.js +304 -1
- package/dist/esm/node_modules/three/examples/jsm/utils/BufferGeometryUtils.js +116 -1
- package/dist/esm/src/analysis/analysis.js +536 -1
- package/dist/esm/src/analysis/testing.js +954 -1
- package/dist/esm/src/core/centralPlant.js +1144 -1
- package/dist/esm/src/core/debugLogger.js +167 -1
- package/dist/esm/src/core/mathUtils.js +570 -1
- package/dist/esm/src/core/nameUtils.js +87 -1
- package/dist/esm/src/data/export.js +712 -1
- package/dist/esm/src/data/import.js +356 -1
- package/dist/esm/src/data/numerics.js +518 -1
- package/dist/esm/src/helpers/sceneHelper.js +547 -1
- package/dist/esm/src/index.js +35 -1
- package/dist/esm/src/managers/components/animationManager.js +119 -1
- package/dist/esm/src/managers/components/componentManager.js +328 -1
- package/dist/esm/src/managers/components/pathfindingManager.js +1417 -1
- package/dist/esm/src/managers/controls/TransformControls.js +1057 -1
- package/dist/esm/src/managers/controls/cameraControlsManager.js +75 -1
- package/dist/esm/src/managers/controls/dragDropManager.js +1002 -1
- package/dist/esm/src/managers/controls/keyboardControlsManager.js +371 -1
- package/dist/esm/src/managers/controls/transformControlsManager.js +1782 -1
- package/dist/esm/src/managers/environment/environmentManager.js +690 -1
- package/dist/esm/src/managers/environment/textureConfig.js +202 -1
- package/dist/esm/src/managers/scene/sceneExportManager.js +260 -1
- package/dist/esm/src/managers/scene/sceneInitializationManager.js +322 -1
- package/dist/esm/src/managers/scene/sceneOperationsManager.js +1485 -1
- package/dist/esm/src/managers/scene/sceneTooltipsManager.js +637 -1
- package/dist/esm/src/managers/system/disposalManager.js +440 -1
- package/dist/esm/src/managers/system/hotReloadManager.js +287 -1
- package/dist/esm/src/managers/system/performanceMonitor.js +858 -1
- package/dist/esm/src/rendering/modelPreloader.js +364 -1
- package/dist/esm/src/rendering/rendering2D.js +627 -1
- package/dist/esm/src/rendering/rendering3D.js +661 -1
- package/package.json +1 -1
|
@@ -1 +1,1782 @@
|
|
|
1
|
-
import{createClass as t,createForOfIteratorHelper as i,objectSpread2 as s,classCallCheck as e}from"../../../_virtual/_rollupPluginBabelHelpers.js";import*as n from"three";import{TransformControls as h}from"./TransformControls.js";var o=function(){return t(function t(i,s,n){var h=arguments.length>3&&void 0!==arguments[3]?arguments[3]:null;e(this,t),this.scene=i,this.camera=s,this.renderer=n,this.orbitControls=h,this.transformControls=null,this.boundingBoxHelper=null,this.boundingBoxCache=new WeakMap,this.selectedObject=null,this.currentMode="translate",this.currentSpace="world",this.forceInvisible=!1,this.eventHandlers={keydown:null,click:null,transformStart:null,transformEnd:null,transforming:null},this.clickTiming={lastClickTime:0,lastClickedObject:null,doubleClickDelay:300},this.transformState={isTransforming:!1,initialTransform:null,currentTransform:null},this.config={size:1,enabled:!0,showX:!0,showY:!0,showZ:!0,snap:null,translationSnap:null,rotationSnap:null,scaleSnap:null,showBoundingBox:!0,boundingBoxColor:65280,useBoundingBoxSelection:!0},this.callbacks={onObjectSelect:null,onTransformStart:null,onTransform:null,onTransformEnd:null,onModeChange:null,onObjectRemoved:null},this.init()},[{key:"init",value:function(){this.createTransformControls(),this.setupEventListeners(),this.setupKeyboardControls()}},{key:"on",value:function(t){t.onObjectSelect&&(this.callbacks.onObjectSelect=t.onObjectSelect),t.onTransformStart&&(this.callbacks.onTransformStart=t.onTransformStart),t.onTransform&&(this.callbacks.onTransform=t.onTransform),t.onTransformEnd&&(this.callbacks.onTransformEnd=t.onTransformEnd),t.onModeChange&&(this.callbacks.onModeChange=t.onModeChange),t.onObjectRemoved&&(this.callbacks.onObjectRemoved=t.onObjectRemoved)}},{key:"createTransformControls",value:function(){this.transformControls=new h(this.camera,this.renderer.domElement),this.transformControls.setMode(this.currentMode),this.transformControls.setSpace(this.currentSpace),this.transformControls.setSize(this.config.size),this.transformControls.setDelay(this.clickTiming),this.transformControls.showX=this.config.showX,this.transformControls.showY=this.config.showY,this.transformControls.showZ=this.config.showZ,this.transformControls.showXY=!1,this.transformControls.showYZ=!1,this.transformControls.showXZ=!1,this.transformControls.isTransformControls=!0,this.transformControls.userData={isTransformControls:!0},this.scene.add(this.transformControls),this.transformControls.enabled=!1,this.t()}},{key:"setupEventListeners",value:function(){var t=this;this.eventHandlers.transformStart=function(){t.transformState.isTransforming=!0,t.selectedObject&&(t.transformState.initialTransform={position:t.selectedObject.position.clone(),rotation:t.selectedObject.rotation.clone(),scale:t.selectedObject.scale.clone()}),t.orbitControls&&(t.orbitControls.enabled=!1),t.callbacks.onTransformStart&&t.callbacks.onTransformStart(t.selectedObject,t.currentMode)},this.eventHandlers.transformEnd=function(){if(t.transformState.isTransforming=!1,t.orbitControls&&(t.orbitControls.enabled=!0),t.selectedObject&&(t.transformState.currentTransform={position:t.selectedObject.position.clone(),rotation:t.selectedObject.rotation.clone(),scale:t.selectedObject.scale.clone()},t.boundingBoxCache.has(t.selectedObject)&&t.boundingBoxCache.delete(t.selectedObject)),t.callbacks.onTransformEnd&&t.callbacks.onTransformEnd(t.selectedObject,t.transformState.initialTransform,t.transformState.currentTransform,t.currentMode),"undefined"!=typeof window){var i,s=new CustomEvent("sceneUpdateComplete",{detail:{timestamp:Date.now(),transformType:t.currentMode,objectName:(null===(i=t.selectedObject)||void 0===i?void 0:i.name)||"unknown"}});window.dispatchEvent(s)}},this.eventHandlers.transforming=function(){if(t.selectedObject&&t.boundingBoxCache.has(t.selectedObject)&&t.boundingBoxCache.delete(t.selectedObject),t.updateBoundingBox(),t.callbacks.onTransform&&t.callbacks.onTransform(t.selectedObject,t.currentMode),"undefined"!=typeof window){var i,s=new CustomEvent("sceneUpdateComplete",{detail:{timestamp:Date.now(),transformType:t.currentMode,objectName:(null===(i=t.selectedObject)||void 0===i?void 0:i.name)||"unknown",isTransforming:!0}});window.dispatchEvent(s)}},this.transformControls&&(this.eventHandlers.transformStart&&this.transformControls.removeEventListener("mouseDown",this.eventHandlers.transformStart),this.eventHandlers.transformEnd&&this.transformControls.removeEventListener("mouseUp",this.eventHandlers.transformEnd),this.eventHandlers.transforming&&this.transformControls.removeEventListener("objectChange",this.eventHandlers.transforming),this.transformControls.addEventListener("mouseDown",this.eventHandlers.transformStart),this.transformControls.addEventListener("mouseUp",this.eventHandlers.transformEnd),this.transformControls.addEventListener("objectChange",this.eventHandlers.transforming))}},{key:"setupKeyboardControls",value:function(){var t=this;this.eventHandlers.keydown=function(i){if(t.transformControls.enabled&&!t.transformState.isTransforming&&(!i.ctrlKey||"KeyZ"!==i.code))switch(i.code){case"KeyG":t.setMode("translate");break;case"KeyR":t.setMode("rotate");break;case"KeyS":t.setMode("scale");break;case"KeyW":t.setSpace("world");break;case"KeyL":t.setSpace("local");break;case"Escape":t.deselectObject();break;case"KeyX":t.setAxisConstraint("X");break;case"KeyY":t.setAxisConstraint("Y");break;case"KeyZ":i.ctrlKey||t.setAxisConstraint("Z");break;case"ShiftLeft":case"ShiftRight":t.clearAxisConstraint();break;case"Backspace":t.handleObjectRemoval()}},window.addEventListener("keydown",this.eventHandlers.keydown)}},{key:"setupObjectSelection",value:function(){var t=this,i=arguments.length>0&&void 0!==arguments[0]?arguments[0]:null,s=new n.Raycaster,e=new n.Vector2;this.eventHandlers.click=function(n){if(!t.transformState.isTransforming){var h=Date.now(),o=h-t.clickTiming.lastClickTime;t.i(n,e),s.setFromCamera(e,t.camera);var a=t.h(s,i),l=a===t.clickTiming.lastClickedObject,r=o<t.clickTiming.doubleClickDelay;l&&r&&null!==a?(t.selectObject(a),t.clickTiming.lastClickTime=0,t.clickTiming.lastClickedObject=null):(t.deselectObject(),a&&t.selectObjectForTransformOnly(a),t.clickTiming.lastClickTime=h,t.clickTiming.lastClickedObject=a)}},this.renderer.domElement.addEventListener("click",this.eventHandlers.click)}},{key:"_calculateMousePosition",value:function(t,i){var s=this.renderer.domElement.getBoundingClientRect();i.x=(t.clientX-s.left)/s.width*2-1,i.y=-(t.clientY-s.top)/s.height*2+1}},{key:"_findTargetObject",value:function(t,i){if(this.config.useBoundingBoxSelection){var s=this.o(t,i);if(s)return s}return this.l(t,i)}},{key:"_findTargetViaBoundingBox",value:function(t,i){var s=this.intersectObjectsBoundingBoxes(t,i);if(s.length>0){var e=s[0].object;if(this.u(e))return e}return null}},{key:"_findTargetViaMesh",value:function(t,i){var s=t.intersectObjects(this.scene.children,!0);if(s.length>0){var e=s[0].object;if(e=this.v(e),(i?i(e):this.isSelectableObject(e))&&this.u(e)){this.config.useBoundingBoxSelection;return e}}return null}},{key:"_resolveHierarchyTarget",value:function(t){var i,s,e;return this.isConnectorOrb(t)?t:null!==(i=t.parent)&&void 0!==i&&null!==(i=i.name)&&void 0!==i&&i.includes(" Component")?t.parent:null!==(s=t.parent)&&void 0!==s&&null!==(s=s.parent)&&void 0!==s&&null!==(s=s.name)&&void 0!==s&&s.includes(" Component")?t.parent.parent:(null!==(e=t.userData)&&void 0!==e&&e.isPipeSegment,t)}},{key:"_isValidSelectableObject",value:function(t){return!(!t||!t.parent)&&!!(t.position&&t.rotation&&t.scale&&t.updateMatrixWorld)}},{key:"isConnectorOrb",value:function(t){if(!t||!t.isObject3D)return!1;if(!t.isMesh||!t.geometry)return!1;var i="CONNECTOR-GEO"===t.geometry.uuid,s="SphereGeometry"===t.geometry.type&&t.geometry.parameters&&.2===t.geometry.parameters.radius,e=t.name&&t.name.toLowerCase().includes("connector");return(i||s)&&e}},{key:"isSelectableObject",value:function(t){var i,s,e,n,h,o,a,l;if(!t||!t.isObject3D)return!1;if(t.userData&&t.userData.isPipeSegment,t.isTransformControls||t.isTransformControlsPlane||t.isTransformControlsGizmo)return!1;var r=t.isHelper||(null===(i=t.userData)||void 0===i?void 0:i.isHelper)||(null===(s=t.userData)||void 0===s?void 0:s.isBoundingBox),u=null===(e=t.userData)||void 0===e?void 0:e.isBaseGround,c=null===(n=t.userData)||void 0===n?void 0:n.isBrickWall;if(r||u||c||!t.visible)return!1;if(t.name&&t.name.toLowerCase().includes("polyline")&&(null===(h=t.userData)||void 0===h||!h.isPipeSegment)&&(null===(o=t.userData)||void 0===o||!o.isPipeJunction))return!1;var v=!0===(null===(a=t.userData)||void 0===a?void 0:a.isPipeSegment),f=!0===(null===(l=t.userData)||void 0===l?void 0:l.isPipeJunction),d=t.name&&t.name.includes(" Component"),y=this.isConnectorOrb(t);return d||y||v||f}},{key:"selectObject",value:function(t){if(!t||!t.isObject3D)return!1;this.selectedObject=t,t.updateMatrixWorld(!0);var i=(new n.Box3).setFromObject(t);return this.boundingBoxCache.set(t,i),this.transformControls.attach(t),this.transformControls.updateInteractionTime&&this.transformControls.updateInteractionTime(),this.createBoundingBox(t),this.forceInvisible?(this.transformControls.enabled=!1,this.t()):(this.transformControls.enabled=this.config.enabled,this.k()),this.callbacks.onObjectSelect&&this.callbacks.onObjectSelect(t),!0}},{key:"selectObjectForTransformOnly",value:function(t){if(!t||!t.isObject3D)return!1;this.selectedObject=t,t.updateMatrixWorld(!0);var i=(new n.Box3).setFromObject(t);return this.boundingBoxCache.set(t,i),this.transformControls.attach(t),this.transformControls.updateInteractionTime&&this.transformControls.updateInteractionTime(),this.createBoundingBox(t),this.forceInvisible?(this.transformControls.enabled=!1,this.t()):(this.transformControls.enabled=!0,this.k()),!0}},{key:"deselectObject",value:function(){this.selectedObject,this.removeBoundingBox(),this.selectedObject=null,this.transformControls&&(this.transformControls.detach(),this.transformControls.enabled=!1,this.t()),this.callbacks.onObjectSelect&&this.callbacks.onObjectSelect(null)}},{key:"createBoundingBox",value:function(t){if(this.config.showBoundingBox&&(this.removeBoundingBox(),t))try{this.boundingBoxHelper=new n.BoxHelper(t,this.config.boundingBoxColor),this.boundingBoxHelper.isHelper=!0,this.boundingBoxHelper.userData={isBoundingBox:!0},this.scene.add(this.boundingBoxHelper)}catch(t){}}},{key:"removeBoundingBox",value:function(){if(this.boundingBoxHelper)try{this.boundingBoxHelper.parent&&this.boundingBoxHelper.parent.remove(this.boundingBoxHelper),this.boundingBoxHelper.geometry&&this.boundingBoxHelper.geometry.dispose(),this.boundingBoxHelper.material&&this.boundingBoxHelper.material.dispose()}catch(t){}finally{this.boundingBoxHelper=null}}},{key:"updateBoundingBox",value:function(){if(this.boundingBoxHelper&&this.selectedObject)try{if(this.selectedObject.updateMatrixWorld(!0),this.boundingBoxHelper.update(),this.boundingBoxCache.has(this.selectedObject)){var t=(new n.Box3).setFromObject(this.selectedObject);this.boundingBoxCache.set(this.selectedObject,t)}}catch(t){this.createBoundingBox(this.selectedObject)}}},{key:"setBoundingBoxVisibility",value:function(t){this.config.showBoundingBox=t,t&&this.selectedObject&&!this.boundingBoxHelper?this.createBoundingBox(this.selectedObject):!t&&this.boundingBoxHelper&&this.removeBoundingBox()}},{key:"setBoundingBoxColor",value:function(t){this.config.boundingBoxColor=t,this.boundingBoxHelper&&this.boundingBoxHelper.material&&this.boundingBoxHelper.material.color.setHex(t)}},{key:"setMode",value:function(t){if(["translate","rotate","scale"].includes(t)){var i=this.currentMode;this.currentMode=t,this.transformControls.setMode(t),this.callbacks.onModeChange&&this.callbacks.onModeChange(t,i)}}},{key:"setSpace",value:function(t){if(["world","local"].includes(t)){this.currentSpace;this.currentSpace=t,this.transformControls.setSpace(t)}}},{key:"setAxisConstraint",value:function(t){["X","Y","Z"].includes(t)&&(this.transformControls.showX=!1,this.transformControls.showY=!1,this.transformControls.showZ=!1,this.transformControls["show".concat(t)]=!0)}},{key:"clearAxisConstraint",value:function(){this.transformControls.showX=this.config.showX,this.transformControls.showY=this.config.showY,this.transformControls.showZ=this.config.showZ}},{key:"setSnap",value:function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};void 0!==t.translation&&(this.config.translationSnap=t.translation,this.transformControls.setTranslationSnap(t.translation)),void 0!==t.rotation&&(this.config.rotationSnap=t.rotation,this.transformControls.setRotationSnap(t.rotation)),void 0!==t.scale&&(this.config.scaleSnap=t.scale,this.transformControls.setScaleSnap(t.scale))}},{key:"snapValues",get:function(){return{translation:this.config.translationSnap||.5,rotation:this.config.rotationSnap||Math.PI/2,scale:this.config.scaleSnap||.1}}},{key:"setSize",value:function(t){this.config.size=t,this.transformControls.setSize(t)}},{key:"setEnabled",value:function(t){this.config.enabled=t,this.selectedObject&&(this.transformControls.enabled=t)}},{key:"setShowPlanes",value:function(t){return!!this.transformControls&&(this.transformControls.showXY=t,this.transformControls.showYZ=t,this.transformControls.showXZ=t,!0)}},{key:"ensureSceneAttachment",value:function(){var t=!(arguments.length>0&&void 0!==arguments[0])||arguments[0];return!this.transformControls&&this.scene&&this.camera&&this.renderer?(this.createTransformControls(),this.setupEventListeners(),t||(this.transformControls.visible=!1),!0):!(!this.transformControls||!this.scene)&&(this.scene.children.includes(this.transformControls)?!this.transformControls.visible&&t?(this.transformControls.visible=!0,!0):this.transformControls.visible&&!t?(this.transformControls.visible=!1,!0):!(!this.transformControls.parent||this.transformControls.parent===this.scene)&&(this.transformControls.parent.remove(this.transformControls),this.scene.add(this.transformControls),!0):(this.scene.add(this.transformControls),this.transformControls.enabled=!1,this.selectedObject&&(this.transformControls.attach(this.selectedObject),this.transformControls.enabled=this.config.enabled),t||(this.transformControls.visible=!1),!0))}},{key:"getTransformData",value:function(){if(!this.selectedObject)return null;var t={position:this.selectedObject.position.clone(),rotation:this.selectedObject.rotation.clone(),scale:this.selectedObject.scale.clone()},i=this.getWorldTransformData();return{object:this.selectedObject,position:t.position,rotation:t.rotation,scale:t.scale,worldPosition:i.position,worldRotation:i.rotation,worldScale:i.scale,mode:this.currentMode,space:this.currentSpace,isTransforming:this.transformState.isTransforming}}},{key:"getWorldTransformData",value:function(){if(!this.selectedObject)return null;this.selectedObject.updateMatrixWorld(!0);var t=new n.Vector3;this.selectedObject.getWorldPosition(t);var i=new n.Quaternion;this.selectedObject.getWorldQuaternion(i);var s=new n.Euler;s.setFromQuaternion(i);var e=new n.Vector3;return this.selectedObject.getWorldScale(e),{position:t,rotation:s,scale:e}}},{key:"updateObjectTransform",value:function(t,i,s){var e=arguments.length>3&&void 0!==arguments[3]&&arguments[3];if(this.selectedObject){var n=this.selectedObject,h=parseFloat(s);if(!isNaN(h)){if(e)this.updateWorldTransform(n,t,i,h);else switch(t){case"position":n.position[i]=h;break;case"rotation":n.rotation[i]=h*(Math.PI/180);break;case"scale":n.scale[i]=h;break;default:return}this.transformControls&&this.transformControls.updateMatrixWorld(),this.updateBoundingBox()}}}},{key:"updateWorldTransform",value:function(t,i,s,e){switch(t.updateMatrixWorld(!0),i){case"position":this.setWorldPosition(t,s,e);break;case"rotation":this.setWorldRotation(t,s,e);break;case"scale":this.setWorldScale(t,s,e)}}},{key:"setWorldPosition",value:function(t,i,s){var e=new n.Vector3;if(t.getWorldPosition(e),e[i]=s,t.parent){var h=new n.Matrix4;h.copy(t.parent.matrixWorld).invert(),e.applyMatrix4(h)}t.position.copy(e)}},{key:"setWorldRotation",value:function(t,i,s){var e=new n.Quaternion;t.getWorldQuaternion(e);var h=new n.Euler;h.setFromQuaternion(e),h[i]=s*(Math.PI/180);var o=new n.Quaternion;if(o.setFromEuler(h),t.parent){var a=new n.Quaternion;t.parent.getWorldQuaternion(a),a.invert(),o.premultiply(a)}t.quaternion.copy(o)}},{key:"setWorldScale",value:function(t,i,s){var e=new n.Vector3;t.getWorldScale(e);var h=s/e[i];t.scale[i]*=h}},{key:"getSelectableObjectsWithBounds",value:function(){var t=this,i=arguments.length>0&&void 0!==arguments[0]?arguments[0]:null,s=[];return this.scene.traverse(function(e){var h,o;if(e&&e.isObject3D&&!(e.isTransformControls||e.isTransformControlsPlane||e.isTransformControlsGizmo||e.isHelper||null!==(h=e.userData)&&void 0!==h&&h.isHelper||null!==(o=e.userData)&&void 0!==o&&o.isBoundingBox))try{if(i?i(e):t.isSelectableObject(e)){e.updateMatrixWorld(!0);var a=t.boundingBoxCache.get(e);a&&e!==t.selectedObject||(a=(new n.Box3).setFromObject(e),t.boundingBoxCache.set(e,a)),s.push({object:e,boundingBox:a})}}catch(t){}}),s}},{key:"intersectObjectsBoundingBoxes",value:function(t){var s,e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null,h=this.getSelectableObjectsWithBounds(e),o=[],a=i(h);try{for(a.s();!(s=a.n()).done;){var l=s.value,r=l.object,u=l.boundingBox,c=t.ray.intersectBox(u,new n.Vector3);if(c){var v=t.ray.origin.distanceTo(c);o.push({object:r,point:c,distance:v,boundingBox:u})}}}catch(t){a.e(t)}finally{a.f()}return o.sort(function(t,i){return t.distance-i.distance}),o}},{key:"setBoundingBoxSelection",value:function(t){this.config.useBoundingBoxSelection=t}},{key:"handleObjectRemoval",value:function(){var t;this.selectedObject&&"gateway"===(null===(t=this.selectedObject.userData)||void 0===t?void 0:t.componentType)&&this.handleGatewayRemoval()}},{key:"handleGatewayRemoval",value:function(){var t,i=this.selectedObject,e={uuid:i.uuid,userData:s({},i.userData),position:i.position.clone(),connections:(null===(t=i.userData)||void 0===t?void 0:t.connections)||null};i.userData.origin="computed",this.deselectObject(),this.callbacks.onObjectRemoved&&this.callbacks.onObjectRemoved(e)}},{key:"dispose",value:function(){this.eventHandlers.keydown&&window.removeEventListener("keydown",this.eventHandlers.keydown),this.eventHandlers.click&&this.renderer.domElement.removeEventListener("click",this.eventHandlers.click),this.removeBoundingBox(),this.selectedObject&&this.deselectObject(),this.transformControls&&(this.eventHandlers.transformStart&&this.transformControls.removeEventListener("mouseDown",this.eventHandlers.transformStart),this.eventHandlers.transformEnd&&this.transformControls.removeEventListener("mouseUp",this.eventHandlers.transformEnd),this.eventHandlers.transforming&&this.transformControls.removeEventListener("objectChange",this.eventHandlers.transforming),this.transformControls.detach(),this.scene&&this.transformControls.parent===this.scene&&this.scene.remove(this.transformControls),this.transformControls.dispose(),this.transformControls=null),this.selectedObject=null,this.orbitControls=null}},{key:"forceHide",value:function(){this.transformControls&&(this.t(),this.transformControls.enabled=!1)}},{key:"_hideTransformControls",value:function(){this.transformControls&&(this.transformControls.visible=!1,this.transformControls.m&&(this.transformControls.m.visible=!1),this.transformControls.p&&(this.transformControls.p.visible=!1))}},{key:"_showTransformControls",value:function(){this.transformControls&&(this.transformControls.visible=!0,this.transformControls.m&&(this.transformControls.m.visible=!0),this.transformControls.p&&(this.transformControls.p.visible=!0))}},{key:"getVisibilityState",value:function(){var t;return this.transformControls?{exists:!0,visible:this.transformControls.visible,enabled:this.transformControls.enabled,gizmoVisible:this.transformControls.m?this.transformControls.m.visible:"N/A",planeVisible:this.transformControls.p?this.transformControls.p.visible:"N/A",hasSelectedObject:!!this.selectedObject,selectedObjectName:(null===(t=this.selectedObject)||void 0===t?void 0:t.name)||"none"}:{exists:!1}}},{key:"_forceHideAllGizmoComponents",value:function(){if(this.transformControls&&this.transformControls.m){var t=this.transformControls.m;t.visible=!1,t.gizmo&&Object.keys(t.gizmo).forEach(function(i){t.gizmo[i]&&(t.gizmo[i].visible=!1)}),t.helper&&Object.keys(t.helper).forEach(function(i){t.helper[i]&&(t.helper[i].visible=!1)}),this.transformControls.p&&(this.transformControls.p.visible=!1)}}},{key:"_hidePlaneHelpers",value:function(){if(this.transformControls&&this.transformControls.m){var t=this.transformControls.m;if(t.gizmo&&t.gizmo.translate)t.gizmo.translate.traverse(function(t){"XY"!==t.name&&"YZ"!==t.name&&"XZ"!==t.name||(t.visible=!1)});if(t.picker&&t.picker.translate)t.picker.translate.traverse(function(t){"XY"!==t.name&&"YZ"!==t.name&&"XZ"!==t.name||(t.visible=!1)})}}},{key:"_showPlaneHelpers",value:function(){if(this.transformControls&&this.transformControls.m){var t=this.transformControls.m;if(t.gizmo&&t.gizmo.translate)t.gizmo.translate.traverse(function(t){"XY"!==t.name&&"YZ"!==t.name&&"XZ"!==t.name||(t.visible=!0)});if(t.picker&&t.picker.translate)t.picker.translate.traverse(function(t){"XY"!==t.name&&"YZ"!==t.name&&"XZ"!==t.name||(t.visible=!0)})}}}])}();function a(t,i,s){return new o(t,i,s,arguments.length>3&&void 0!==arguments[3]?arguments[3]:null)}export{o as TransformControlsManager,a as createTransformControls};
|
|
1
|
+
import { createClass as _createClass, createForOfIteratorHelper as _createForOfIteratorHelper, objectSpread2 as _objectSpread2, classCallCheck as _classCallCheck } from '../../../_virtual/_rollupPluginBabelHelpers.js';
|
|
2
|
+
import * as THREE from 'three';
|
|
3
|
+
import { TransformControls } from './TransformControls.js';
|
|
4
|
+
|
|
5
|
+
var TransformControlsManager = /*#__PURE__*/function () {
|
|
6
|
+
function TransformControlsManager(scene, camera, renderer) {
|
|
7
|
+
var orbitControls = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : null;
|
|
8
|
+
_classCallCheck(this, TransformControlsManager);
|
|
9
|
+
this.scene = scene;
|
|
10
|
+
this.camera = camera;
|
|
11
|
+
this.renderer = renderer;
|
|
12
|
+
this.orbitControls = orbitControls;
|
|
13
|
+
// Transform control instance
|
|
14
|
+
this.transformControls = null;
|
|
15
|
+
// Bounding box helper for visual feedback
|
|
16
|
+
this.boundingBoxHelper = null;
|
|
17
|
+
|
|
18
|
+
// Cache for object bounding boxes to improve performance
|
|
19
|
+
this.boundingBoxCache = new WeakMap();
|
|
20
|
+
|
|
21
|
+
// Currently selected object
|
|
22
|
+
this.selectedObject = null;
|
|
23
|
+
|
|
24
|
+
// Transform mode: 'translate', 'rotate', 'scale'
|
|
25
|
+
this.currentMode = 'translate';
|
|
26
|
+
|
|
27
|
+
// Transform space: 'world' or 'local'
|
|
28
|
+
this.currentSpace = 'world';
|
|
29
|
+
|
|
30
|
+
// Flag to force controls to stay invisible (used during scene loading)
|
|
31
|
+
this.forceInvisible = false;
|
|
32
|
+
|
|
33
|
+
// Event handlers storage
|
|
34
|
+
this.eventHandlers = {
|
|
35
|
+
keydown: null,
|
|
36
|
+
click: null,
|
|
37
|
+
transformStart: null,
|
|
38
|
+
transformEnd: null,
|
|
39
|
+
transforming: null
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
// Click timing for double-click detection
|
|
43
|
+
this.clickTiming = {
|
|
44
|
+
lastClickTime: 0,
|
|
45
|
+
lastClickedObject: null,
|
|
46
|
+
doubleClickDelay: 300 // milliseconds
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
// Transform state tracking
|
|
50
|
+
this.transformState = {
|
|
51
|
+
isTransforming: false,
|
|
52
|
+
initialTransform: null,
|
|
53
|
+
currentTransform: null
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
// Configuration options
|
|
57
|
+
this.config = {
|
|
58
|
+
size: 1,
|
|
59
|
+
enabled: true,
|
|
60
|
+
showX: true,
|
|
61
|
+
showY: true,
|
|
62
|
+
showZ: true,
|
|
63
|
+
snap: null,
|
|
64
|
+
// Snap value for transformations
|
|
65
|
+
translationSnap: null,
|
|
66
|
+
rotationSnap: null,
|
|
67
|
+
scaleSnap: null,
|
|
68
|
+
showBoundingBox: true,
|
|
69
|
+
// Show bounding box on selection
|
|
70
|
+
boundingBoxColor: 0x00ff00,
|
|
71
|
+
// Green bounding box by default
|
|
72
|
+
useBoundingBoxSelection: true // Use bounding box-based selection instead of mesh selection
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
// Callbacks for external event handling
|
|
76
|
+
this.callbacks = {
|
|
77
|
+
onObjectSelect: null,
|
|
78
|
+
onTransformStart: null,
|
|
79
|
+
onTransform: null,
|
|
80
|
+
onTransformEnd: null,
|
|
81
|
+
onModeChange: null,
|
|
82
|
+
onObjectRemoved: null
|
|
83
|
+
};
|
|
84
|
+
this.init();
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Initialize the transform controls
|
|
89
|
+
*/
|
|
90
|
+
return _createClass(TransformControlsManager, [{
|
|
91
|
+
key: "init",
|
|
92
|
+
value: function init() {
|
|
93
|
+
this.createTransformControls();
|
|
94
|
+
this.setupEventListeners();
|
|
95
|
+
this.setupKeyboardControls();
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Register event callbacks
|
|
100
|
+
* @param {Object} callbacks - Object containing callback functions
|
|
101
|
+
* @param {Function} callbacks.onObjectSelect - Called when an object is selected/deselected
|
|
102
|
+
* @param {Function} callbacks.onTransformStart - Called when transform starts
|
|
103
|
+
* @param {Function} callbacks.onTransform - Called during transform
|
|
104
|
+
* @param {Function} callbacks.onTransformEnd - Called when transform ends
|
|
105
|
+
* @param {Function} callbacks.onModeChange - Called when transform mode changes
|
|
106
|
+
* @param {Function} callbacks.onObjectRemoved - Called when an object is removed
|
|
107
|
+
*/
|
|
108
|
+
}, {
|
|
109
|
+
key: "on",
|
|
110
|
+
value: function on(callbacks) {
|
|
111
|
+
if (callbacks.onObjectSelect) {
|
|
112
|
+
this.callbacks.onObjectSelect = callbacks.onObjectSelect;
|
|
113
|
+
}
|
|
114
|
+
if (callbacks.onTransformStart) {
|
|
115
|
+
this.callbacks.onTransformStart = callbacks.onTransformStart;
|
|
116
|
+
}
|
|
117
|
+
if (callbacks.onTransform) {
|
|
118
|
+
this.callbacks.onTransform = callbacks.onTransform;
|
|
119
|
+
}
|
|
120
|
+
if (callbacks.onTransformEnd) {
|
|
121
|
+
this.callbacks.onTransformEnd = callbacks.onTransformEnd;
|
|
122
|
+
}
|
|
123
|
+
if (callbacks.onModeChange) {
|
|
124
|
+
this.callbacks.onModeChange = callbacks.onModeChange;
|
|
125
|
+
}
|
|
126
|
+
if (callbacks.onObjectRemoved) {
|
|
127
|
+
this.callbacks.onObjectRemoved = callbacks.onObjectRemoved;
|
|
128
|
+
}
|
|
129
|
+
console.log('🔗 Transform controls callbacks registered');
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Create and configure transform controls
|
|
133
|
+
*/
|
|
134
|
+
}, {
|
|
135
|
+
key: "createTransformControls",
|
|
136
|
+
value: function createTransformControls() {
|
|
137
|
+
this.transformControls = new TransformControls(this.camera, this.renderer.domElement);
|
|
138
|
+
this.transformControls.setMode(this.currentMode);
|
|
139
|
+
this.transformControls.setSpace(this.currentSpace);
|
|
140
|
+
this.transformControls.setSize(this.config.size);
|
|
141
|
+
this.transformControls.setDelay(this.clickTiming);
|
|
142
|
+
|
|
143
|
+
// Configure axes visibility
|
|
144
|
+
this.transformControls.showX = this.config.showX;
|
|
145
|
+
this.transformControls.showY = this.config.showY;
|
|
146
|
+
this.transformControls.showZ = this.config.showZ;
|
|
147
|
+
|
|
148
|
+
// Hide multi-axis plane helpers by default (only allow single-axis translation)
|
|
149
|
+
this.transformControls.showXY = false;
|
|
150
|
+
this.transformControls.showYZ = false;
|
|
151
|
+
this.transformControls.showXZ = false;
|
|
152
|
+
|
|
153
|
+
// Mark as transform controls for scene filtering
|
|
154
|
+
this.transformControls.isTransformControls = true;
|
|
155
|
+
this.transformControls.userData = {
|
|
156
|
+
isTransformControls: true
|
|
157
|
+
};
|
|
158
|
+
// Add to scene
|
|
159
|
+
this.scene.add(this.transformControls);
|
|
160
|
+
|
|
161
|
+
// Initially disabled and invisible
|
|
162
|
+
this.transformControls.enabled = false;
|
|
163
|
+
this._hideTransformControls();
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Setup event listeners for transform controls
|
|
168
|
+
*/
|
|
169
|
+
}, {
|
|
170
|
+
key: "setupEventListeners",
|
|
171
|
+
value: function setupEventListeners() {
|
|
172
|
+
var _this = this;
|
|
173
|
+
// Transform start event
|
|
174
|
+
this.eventHandlers.transformStart = function () {
|
|
175
|
+
console.log("transformControls transformStart");
|
|
176
|
+
_this.transformState.isTransforming = true;
|
|
177
|
+
if (_this.selectedObject) {
|
|
178
|
+
// Store initial transform state
|
|
179
|
+
_this.transformState.initialTransform = {
|
|
180
|
+
position: _this.selectedObject.position.clone(),
|
|
181
|
+
rotation: _this.selectedObject.rotation.clone(),
|
|
182
|
+
scale: _this.selectedObject.scale.clone()
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// Disable orbit controls during transformation
|
|
187
|
+
if (_this.orbitControls) {
|
|
188
|
+
_this.orbitControls.enabled = false;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// Execute callback
|
|
192
|
+
if (_this.callbacks.onTransformStart) {
|
|
193
|
+
_this.callbacks.onTransformStart(_this.selectedObject, _this.currentMode);
|
|
194
|
+
}
|
|
195
|
+
console.log("\uD83D\uDD27 Transform started: ".concat(_this.currentMode, " mode"));
|
|
196
|
+
};
|
|
197
|
+
|
|
198
|
+
// Transform end event
|
|
199
|
+
this.eventHandlers.transformEnd = function () {
|
|
200
|
+
_this.transformState.isTransforming = false;
|
|
201
|
+
|
|
202
|
+
// Re-enable orbit controls
|
|
203
|
+
if (_this.orbitControls) {
|
|
204
|
+
_this.orbitControls.enabled = true;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// Store final transform state
|
|
208
|
+
if (_this.selectedObject) {
|
|
209
|
+
_this.transformState.currentTransform = {
|
|
210
|
+
position: _this.selectedObject.position.clone(),
|
|
211
|
+
rotation: _this.selectedObject.rotation.clone(),
|
|
212
|
+
scale: _this.selectedObject.scale.clone()
|
|
213
|
+
};
|
|
214
|
+
|
|
215
|
+
// Clear bounding box cache for the transformed object to ensure selection uses updated position
|
|
216
|
+
if (_this.boundingBoxCache.has(_this.selectedObject)) {
|
|
217
|
+
_this.boundingBoxCache.delete(_this.selectedObject);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// Execute callback
|
|
222
|
+
if (_this.callbacks.onTransformEnd) {
|
|
223
|
+
_this.callbacks.onTransformEnd(_this.selectedObject, _this.transformState.initialTransform, _this.transformState.currentTransform, _this.currentMode);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// Dispatch custom scene update event after transform completes
|
|
227
|
+
if (typeof window !== 'undefined') {
|
|
228
|
+
var _this$selectedObject;
|
|
229
|
+
console.log('📡 Dispatching sceneUpdateComplete event after transform');
|
|
230
|
+
var sceneCompleteEvent = new CustomEvent('sceneUpdateComplete', {
|
|
231
|
+
detail: {
|
|
232
|
+
timestamp: Date.now(),
|
|
233
|
+
transformType: _this.currentMode,
|
|
234
|
+
objectName: ((_this$selectedObject = _this.selectedObject) === null || _this$selectedObject === void 0 ? void 0 : _this$selectedObject.name) || 'unknown'
|
|
235
|
+
}
|
|
236
|
+
});
|
|
237
|
+
window.dispatchEvent(sceneCompleteEvent);
|
|
238
|
+
}
|
|
239
|
+
console.log("\u2705 Transform completed: ".concat(_this.currentMode, " mode"));
|
|
240
|
+
};
|
|
241
|
+
// Transform changing event
|
|
242
|
+
this.eventHandlers.transforming = function () {
|
|
243
|
+
// Clear the bounding box cache for the selected object during transformation
|
|
244
|
+
if (_this.selectedObject && _this.boundingBoxCache.has(_this.selectedObject)) {
|
|
245
|
+
_this.boundingBoxCache.delete(_this.selectedObject);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
// Update bounding box during transformation
|
|
249
|
+
_this.updateBoundingBox();
|
|
250
|
+
if (_this.callbacks.onTransform) {
|
|
251
|
+
_this.callbacks.onTransform(_this.selectedObject, _this.currentMode);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
// Dispatch custom scene update event during transform (optional - fires continuously)
|
|
255
|
+
if (typeof window !== 'undefined') {
|
|
256
|
+
var _this$selectedObject2;
|
|
257
|
+
var sceneCompleteEvent = new CustomEvent('sceneUpdateComplete', {
|
|
258
|
+
detail: {
|
|
259
|
+
timestamp: Date.now(),
|
|
260
|
+
transformType: _this.currentMode,
|
|
261
|
+
objectName: ((_this$selectedObject2 = _this.selectedObject) === null || _this$selectedObject2 === void 0 ? void 0 : _this$selectedObject2.name) || 'unknown',
|
|
262
|
+
isTransforming: true
|
|
263
|
+
}
|
|
264
|
+
});
|
|
265
|
+
window.dispatchEvent(sceneCompleteEvent);
|
|
266
|
+
}
|
|
267
|
+
};
|
|
268
|
+
// First remove any existing listeners to prevent duplicates
|
|
269
|
+
if (this.transformControls) {
|
|
270
|
+
// Remove existing listeners if they exist
|
|
271
|
+
if (this.eventHandlers.transformStart) {
|
|
272
|
+
this.transformControls.removeEventListener('mouseDown', this.eventHandlers.transformStart);
|
|
273
|
+
}
|
|
274
|
+
if (this.eventHandlers.transformEnd) {
|
|
275
|
+
this.transformControls.removeEventListener('mouseUp', this.eventHandlers.transformEnd);
|
|
276
|
+
}
|
|
277
|
+
if (this.eventHandlers.transforming) {
|
|
278
|
+
this.transformControls.removeEventListener('objectChange', this.eventHandlers.transforming);
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
// Add event listeners
|
|
282
|
+
this.transformControls.addEventListener('mouseDown', this.eventHandlers.transformStart);
|
|
283
|
+
this.transformControls.addEventListener('mouseUp', this.eventHandlers.transformEnd);
|
|
284
|
+
this.transformControls.addEventListener('objectChange', this.eventHandlers.transforming);
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
/**
|
|
288
|
+
* Setup keyboard controls for transform modes
|
|
289
|
+
*/
|
|
290
|
+
}, {
|
|
291
|
+
key: "setupKeyboardControls",
|
|
292
|
+
value: function setupKeyboardControls() {
|
|
293
|
+
var _this2 = this;
|
|
294
|
+
this.eventHandlers.keydown = function (event) {
|
|
295
|
+
// Only handle keys when transform controls are active
|
|
296
|
+
if (!_this2.transformControls.enabled || _this2.transformState.isTransforming) {
|
|
297
|
+
return;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
// Check for Ctrl+Z (undo) - don't handle it here, let it pass through
|
|
301
|
+
if (event.ctrlKey && event.code === 'KeyZ') {
|
|
302
|
+
return; // Let the KeyboardControlsManager handle Ctrl+Z
|
|
303
|
+
}
|
|
304
|
+
switch (event.code) {
|
|
305
|
+
case 'KeyG':
|
|
306
|
+
// Translate mode
|
|
307
|
+
_this2.setMode('translate');
|
|
308
|
+
break;
|
|
309
|
+
case 'KeyR':
|
|
310
|
+
// Rotate mode
|
|
311
|
+
_this2.setMode('rotate');
|
|
312
|
+
break;
|
|
313
|
+
case 'KeyS':
|
|
314
|
+
// Scale mode
|
|
315
|
+
_this2.setMode('scale');
|
|
316
|
+
break;
|
|
317
|
+
case 'KeyW':
|
|
318
|
+
// World space
|
|
319
|
+
_this2.setSpace('world');
|
|
320
|
+
break;
|
|
321
|
+
case 'KeyL':
|
|
322
|
+
// Local space
|
|
323
|
+
_this2.setSpace('local');
|
|
324
|
+
break;
|
|
325
|
+
case 'Escape':
|
|
326
|
+
// Deselect object
|
|
327
|
+
_this2.deselectObject();
|
|
328
|
+
break;
|
|
329
|
+
case 'KeyX':
|
|
330
|
+
// X-axis constraint
|
|
331
|
+
_this2.setAxisConstraint('X');
|
|
332
|
+
break;
|
|
333
|
+
case 'KeyY':
|
|
334
|
+
// Y-axis constraint
|
|
335
|
+
_this2.setAxisConstraint('Y');
|
|
336
|
+
break;
|
|
337
|
+
case 'KeyZ':
|
|
338
|
+
// Z-axis constraint (only if not Ctrl+Z)
|
|
339
|
+
if (!event.ctrlKey) {
|
|
340
|
+
_this2.setAxisConstraint('Z');
|
|
341
|
+
}
|
|
342
|
+
break;
|
|
343
|
+
case 'ShiftLeft':
|
|
344
|
+
case 'ShiftRight':
|
|
345
|
+
// Multi-axis constraint
|
|
346
|
+
_this2.clearAxisConstraint();
|
|
347
|
+
break;
|
|
348
|
+
case 'Backspace':
|
|
349
|
+
// Remove selected object
|
|
350
|
+
_this2.handleObjectRemoval();
|
|
351
|
+
break;
|
|
352
|
+
}
|
|
353
|
+
};
|
|
354
|
+
window.addEventListener('keydown', this.eventHandlers.keydown);
|
|
355
|
+
}
|
|
356
|
+
/**
|
|
357
|
+
* Setup mouse-based object selection
|
|
358
|
+
* @param {Function} objectFilter - Optional function to filter selectable objects
|
|
359
|
+
*/
|
|
360
|
+
}, {
|
|
361
|
+
key: "setupObjectSelection",
|
|
362
|
+
value: function setupObjectSelection() {
|
|
363
|
+
var _this3 = this;
|
|
364
|
+
var objectFilter = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;
|
|
365
|
+
var raycaster = new THREE.Raycaster();
|
|
366
|
+
var mouse = new THREE.Vector2();
|
|
367
|
+
|
|
368
|
+
// Single click handler with double-click detection
|
|
369
|
+
this.eventHandlers.click = function (event) {
|
|
370
|
+
// Skip if currently transforming
|
|
371
|
+
if (_this3.transformState.isTransforming) {
|
|
372
|
+
return;
|
|
373
|
+
}
|
|
374
|
+
var currentTime = Date.now();
|
|
375
|
+
var timeSinceLastClick = currentTime - _this3.clickTiming.lastClickTime;
|
|
376
|
+
|
|
377
|
+
// Calculate mouse position and set up raycaster
|
|
378
|
+
_this3._calculateMousePosition(event, mouse);
|
|
379
|
+
raycaster.setFromCamera(mouse, _this3.camera);
|
|
380
|
+
|
|
381
|
+
// Find target object using appropriate selection method
|
|
382
|
+
var targetObject = _this3._findTargetObject(raycaster, objectFilter);
|
|
383
|
+
|
|
384
|
+
// Check if this is a double-click: same object clicked within delay time
|
|
385
|
+
var isSameObject = targetObject === _this3.clickTiming.lastClickedObject;
|
|
386
|
+
var isWithinDelay = timeSinceLastClick < _this3.clickTiming.doubleClickDelay;
|
|
387
|
+
var isDoubleClick = isSameObject && isWithinDelay && targetObject !== null;
|
|
388
|
+
if (isDoubleClick) {
|
|
389
|
+
// Double-click on same object: Full selection including tooltips
|
|
390
|
+
_this3.selectObject(targetObject);
|
|
391
|
+
|
|
392
|
+
// Reset click timing to prevent triple-click issues
|
|
393
|
+
_this3.clickTiming.lastClickTime = 0;
|
|
394
|
+
_this3.clickTiming.lastClickedObject = null;
|
|
395
|
+
} else {
|
|
396
|
+
// Single click: Transform controls and bounding box only
|
|
397
|
+
// Always deselect first (this clears tooltips via the callback)
|
|
398
|
+
_this3.deselectObject();
|
|
399
|
+
|
|
400
|
+
// Then select the new object if there is one (this shows transform controls and bounding box)
|
|
401
|
+
if (targetObject) {
|
|
402
|
+
_this3.selectObjectForTransformOnly(targetObject);
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
// Update click timing
|
|
406
|
+
_this3.clickTiming.lastClickTime = currentTime;
|
|
407
|
+
_this3.clickTiming.lastClickedObject = targetObject;
|
|
408
|
+
}
|
|
409
|
+
};
|
|
410
|
+
this.renderer.domElement.addEventListener('click', this.eventHandlers.click);
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
/**
|
|
414
|
+
* Calculate normalized mouse position from click event
|
|
415
|
+
* @param {Event} event - The click event (single or double)
|
|
416
|
+
* @param {THREE.Vector2} mouse - Vector2 to store mouse position
|
|
417
|
+
* @private
|
|
418
|
+
*/
|
|
419
|
+
}, {
|
|
420
|
+
key: "_calculateMousePosition",
|
|
421
|
+
value: function _calculateMousePosition(event, mouse) {
|
|
422
|
+
var rect = this.renderer.domElement.getBoundingClientRect();
|
|
423
|
+
mouse.x = (event.clientX - rect.left) / rect.width * 2 - 1;
|
|
424
|
+
mouse.y = -((event.clientY - rect.top) / rect.height) * 2 + 1;
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
/**
|
|
428
|
+
* Find the target object for selection using configured selection method
|
|
429
|
+
* @param {THREE.Raycaster} raycaster - The raycaster for intersection testing
|
|
430
|
+
* @param {Function} objectFilter - Optional function to filter selectable objects
|
|
431
|
+
* @returns {THREE.Object3D|null} The target object or null if nothing selectable
|
|
432
|
+
* @private
|
|
433
|
+
*/
|
|
434
|
+
}, {
|
|
435
|
+
key: "_findTargetObject",
|
|
436
|
+
value: function _findTargetObject(raycaster, objectFilter) {
|
|
437
|
+
// Try bounding box selection first if enabled
|
|
438
|
+
if (this.config.useBoundingBoxSelection) {
|
|
439
|
+
var targetObject = this._findTargetViaBoundingBox(raycaster, objectFilter);
|
|
440
|
+
if (targetObject) {
|
|
441
|
+
return targetObject;
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
// Fall back to mesh-based selection
|
|
446
|
+
return this._findTargetViaMesh(raycaster, objectFilter);
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
/**
|
|
450
|
+
* Find target object using bounding box intersection
|
|
451
|
+
* @param {THREE.Raycaster} raycaster - The raycaster for intersection testing
|
|
452
|
+
* @param {Function} objectFilter - Optional function to filter selectable objects
|
|
453
|
+
* @returns {THREE.Object3D|null} The target object or null if nothing found
|
|
454
|
+
* @private
|
|
455
|
+
*/
|
|
456
|
+
}, {
|
|
457
|
+
key: "_findTargetViaBoundingBox",
|
|
458
|
+
value: function _findTargetViaBoundingBox(raycaster, objectFilter) {
|
|
459
|
+
var intersections = this.intersectObjectsBoundingBoxes(raycaster, objectFilter);
|
|
460
|
+
if (intersections.length > 0) {
|
|
461
|
+
var targetObject = intersections[0].object;
|
|
462
|
+
if (this._isValidSelectableObject(targetObject)) {
|
|
463
|
+
console.log("\uD83D\uDCE6 Object selected via bounding box: ".concat(targetObject.name || targetObject.uuid));
|
|
464
|
+
return targetObject;
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
return null;
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
/**
|
|
471
|
+
* Find target object using mesh intersection
|
|
472
|
+
* @param {THREE.Raycaster} raycaster - The raycaster for intersection testing
|
|
473
|
+
* @param {Function} objectFilter - Optional function to filter selectable objects
|
|
474
|
+
* @returns {THREE.Object3D|null} The target object or null if nothing found
|
|
475
|
+
* @private
|
|
476
|
+
*/
|
|
477
|
+
}, {
|
|
478
|
+
key: "_findTargetViaMesh",
|
|
479
|
+
value: function _findTargetViaMesh(raycaster, objectFilter) {
|
|
480
|
+
var intersections = raycaster.intersectObjects(this.scene.children, true);
|
|
481
|
+
if (intersections.length > 0) {
|
|
482
|
+
var targetObject = intersections[0].object;
|
|
483
|
+
|
|
484
|
+
// Resolve the correct object in the hierarchy
|
|
485
|
+
targetObject = this._resolveHierarchyTarget(targetObject);
|
|
486
|
+
|
|
487
|
+
// Check if selectable
|
|
488
|
+
var isSelectable = objectFilter ? objectFilter(targetObject) : this.isSelectableObject(targetObject);
|
|
489
|
+
if (isSelectable && this._isValidSelectableObject(targetObject)) {
|
|
490
|
+
var method = this.config.useBoundingBoxSelection ? ' (fallback)' : '';
|
|
491
|
+
console.log("\uD83C\uDFAF Object selected via mesh".concat(method, ": ").concat(targetObject.name || targetObject.uuid));
|
|
492
|
+
return targetObject;
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
return null;
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
/**
|
|
499
|
+
* Resolve the correct target object in the hierarchy
|
|
500
|
+
* @param {THREE.Object3D} object - The initially intersected object
|
|
501
|
+
* @returns {THREE.Object3D} The resolved target object
|
|
502
|
+
* @private
|
|
503
|
+
*/
|
|
504
|
+
}, {
|
|
505
|
+
key: "_resolveHierarchyTarget",
|
|
506
|
+
value: function _resolveHierarchyTarget(object) {
|
|
507
|
+
var _object$parent, _object$parent2, _object$userData;
|
|
508
|
+
// Keep connector orbs as direct targets
|
|
509
|
+
if (this.isConnectorOrb(object)) {
|
|
510
|
+
console.log('🔴 Connector orb clicked directly - using connector for transform controls');
|
|
511
|
+
return object;
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
// Look for component parent in hierarchy
|
|
515
|
+
if ((_object$parent = object.parent) !== null && _object$parent !== void 0 && (_object$parent = _object$parent.name) !== null && _object$parent !== void 0 && _object$parent.includes(' Component')) {
|
|
516
|
+
console.log('🎯 Using parent GLB model for transform controls');
|
|
517
|
+
return object.parent;
|
|
518
|
+
}
|
|
519
|
+
if ((_object$parent2 = object.parent) !== null && _object$parent2 !== void 0 && (_object$parent2 = _object$parent2.parent) !== null && _object$parent2 !== void 0 && (_object$parent2 = _object$parent2.name) !== null && _object$parent2 !== void 0 && _object$parent2.includes(' Component')) {
|
|
520
|
+
console.log('🎯 Using grandparent GLB model for transform controls');
|
|
521
|
+
return object.parent.parent;
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
// Debug logging for pipe segments
|
|
525
|
+
if ((_object$userData = object.userData) !== null && _object$userData !== void 0 && _object$userData.isPipeSegment) {
|
|
526
|
+
console.log('🔍 Found pipe segment in selection:', object.name, object.userData);
|
|
527
|
+
}
|
|
528
|
+
return object;
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
/**
|
|
532
|
+
* Check if an object is valid for selection (has required properties and is in scene)
|
|
533
|
+
* @param {THREE.Object3D} object - The object to validate
|
|
534
|
+
* @returns {boolean} Whether the object is valid for selection
|
|
535
|
+
* @private
|
|
536
|
+
*/
|
|
537
|
+
}, {
|
|
538
|
+
key: "_isValidSelectableObject",
|
|
539
|
+
value: function _isValidSelectableObject(object) {
|
|
540
|
+
// Safety check: ensure object is still valid and in the scene
|
|
541
|
+
if (!object || !object.parent) {
|
|
542
|
+
console.warn('⚠️ Selected object is no longer valid or in scene');
|
|
543
|
+
return false;
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
// Verify object has all required Three.js properties
|
|
547
|
+
if (!object.position || !object.rotation || !object.scale || !object.updateMatrixWorld) {
|
|
548
|
+
console.warn('❌ Object missing required Three.js properties for transform controls');
|
|
549
|
+
return false;
|
|
550
|
+
}
|
|
551
|
+
return true;
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
/**
|
|
555
|
+
* Check if an object is a connector orb
|
|
556
|
+
* @param {THREE.Object3D} object - The object to check
|
|
557
|
+
* @returns {boolean} Whether the object is a connector orb
|
|
558
|
+
*/
|
|
559
|
+
}, {
|
|
560
|
+
key: "isConnectorOrb",
|
|
561
|
+
value: function isConnectorOrb(object) {
|
|
562
|
+
// Basic safety checks
|
|
563
|
+
if (!object || !object.isObject3D) {
|
|
564
|
+
return false;
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
// Check if it's a mesh with connector geometry
|
|
568
|
+
if (!object.isMesh || !object.geometry) {
|
|
569
|
+
return false;
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
// Check for CONNECTOR-GEO geometry uuid
|
|
573
|
+
var hasConnectorGeometry = object.geometry.uuid === 'CONNECTOR-GEO';
|
|
574
|
+
|
|
575
|
+
// Check for SphereGeometry with radius 0.2
|
|
576
|
+
var isSphereConnector = object.geometry.type === 'SphereGeometry' && object.geometry.parameters && object.geometry.parameters.radius === 0.2;
|
|
577
|
+
|
|
578
|
+
// Check if name includes connector
|
|
579
|
+
var hasConnectorName = object.name && object.name.toLowerCase().includes('connector');
|
|
580
|
+
return (hasConnectorGeometry || isSphereConnector) && hasConnectorName;
|
|
581
|
+
}
|
|
582
|
+
/**
|
|
583
|
+
* Default object selection filter
|
|
584
|
+
* @param {THREE.Object3D} object - The object to check
|
|
585
|
+
* @returns {boolean} Whether the object can be selected
|
|
586
|
+
*/
|
|
587
|
+
}, {
|
|
588
|
+
key: "isSelectableObject",
|
|
589
|
+
value: function isSelectableObject(object) {
|
|
590
|
+
var _object$userData2, _object$userData3, _object$userData4, _object$userData5, _object$userData6, _object$userData7, _object$userData8, _object$userData9;
|
|
591
|
+
// Basic safety checks
|
|
592
|
+
if (!object || !object.isObject3D) {
|
|
593
|
+
return false;
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
// Debug logging for pipe segments
|
|
597
|
+
if (object.userData && object.userData.isPipeSegment) {
|
|
598
|
+
console.log('🔍 Found pipe segment in selection check:', object.name, object.userData);
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
// Skip transform controls and their children
|
|
602
|
+
if (object.isTransformControls || object.isTransformControlsPlane || object.isTransformControlsGizmo) {
|
|
603
|
+
return false;
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
// Skip helpers and special objects
|
|
607
|
+
var isHelper = object.isHelper || ((_object$userData2 = object.userData) === null || _object$userData2 === void 0 ? void 0 : _object$userData2.isHelper) || ((_object$userData3 = object.userData) === null || _object$userData3 === void 0 ? void 0 : _object$userData3.isBoundingBox);
|
|
608
|
+
var isBaseGround = (_object$userData4 = object.userData) === null || _object$userData4 === void 0 ? void 0 : _object$userData4.isBaseGround;
|
|
609
|
+
var isBrickWall = (_object$userData5 = object.userData) === null || _object$userData5 === void 0 ? void 0 : _object$userData5.isBrickWall;
|
|
610
|
+
if (isHelper || isBaseGround || isBrickWall || !object.visible) {
|
|
611
|
+
return false;
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
// Allow pipe segments and junctions to be selected, but exclude parent polyline objects
|
|
615
|
+
if (object.name && object.name.toLowerCase().includes('polyline') && !((_object$userData6 = object.userData) !== null && _object$userData6 !== void 0 && _object$userData6.isPipeSegment) && !((_object$userData7 = object.userData) !== null && _object$userData7 !== void 0 && _object$userData7.isPipeJunction)) {
|
|
616
|
+
console.log('❌ Polyline parent object excluded from selection:', object.name);
|
|
617
|
+
return false;
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
// Check for pipe segments and junctions
|
|
621
|
+
var isPipeSegment = ((_object$userData8 = object.userData) === null || _object$userData8 === void 0 ? void 0 : _object$userData8.isPipeSegment) === true;
|
|
622
|
+
var isPipeJunction = ((_object$userData9 = object.userData) === null || _object$userData9 === void 0 ? void 0 : _object$userData9.isPipeJunction) === true;
|
|
623
|
+
|
|
624
|
+
// Check for GLB models
|
|
625
|
+
var isGLBModel = object.name && object.name.includes(' Component');
|
|
626
|
+
|
|
627
|
+
// Check for connector orbs
|
|
628
|
+
var isConnector = this.isConnectorOrb(object);
|
|
629
|
+
return isGLBModel || isConnector || isPipeSegment || isPipeJunction;
|
|
630
|
+
}
|
|
631
|
+
/**
|
|
632
|
+
* Select an object for transformation
|
|
633
|
+
* @param {THREE.Object3D} object - The object to select
|
|
634
|
+
*/
|
|
635
|
+
}, {
|
|
636
|
+
key: "selectObject",
|
|
637
|
+
value: function selectObject(object) {
|
|
638
|
+
if (!object || !object.isObject3D) {
|
|
639
|
+
console.warn('⚠️ Invalid object provided for selection');
|
|
640
|
+
return false;
|
|
641
|
+
}
|
|
642
|
+
this.selectedObject = object;
|
|
643
|
+
|
|
644
|
+
// Force object matrix update to ensure correct transforms
|
|
645
|
+
object.updateMatrixWorld(true);
|
|
646
|
+
|
|
647
|
+
// Refresh bounding box cache for this object
|
|
648
|
+
var updatedBoundingBox = new THREE.Box3().setFromObject(object);
|
|
649
|
+
this.boundingBoxCache.set(object, updatedBoundingBox);
|
|
650
|
+
|
|
651
|
+
// Attach transform controls
|
|
652
|
+
this.transformControls.attach(object);
|
|
653
|
+
|
|
654
|
+
// Update interaction time to reset delay
|
|
655
|
+
if (this.transformControls.updateInteractionTime) {
|
|
656
|
+
this.transformControls.updateInteractionTime();
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
// Create and show bounding box if enabled
|
|
660
|
+
this.createBoundingBox(object);
|
|
661
|
+
|
|
662
|
+
// Only enable if not forcing invisibility
|
|
663
|
+
if (!this.forceInvisible) {
|
|
664
|
+
this.transformControls.enabled = this.config.enabled;
|
|
665
|
+
this._showTransformControls();
|
|
666
|
+
} else {
|
|
667
|
+
console.log('🔒 Transform controls kept invisible despite object selection');
|
|
668
|
+
this.transformControls.enabled = false;
|
|
669
|
+
this._hideTransformControls();
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
// Execute callback
|
|
673
|
+
if (this.callbacks.onObjectSelect) {
|
|
674
|
+
this.callbacks.onObjectSelect(object);
|
|
675
|
+
}
|
|
676
|
+
console.log("\uD83C\uDFAF Object selected: ".concat(object.name || object.uuid));
|
|
677
|
+
return true;
|
|
678
|
+
} /**
|
|
679
|
+
* Select object for transform controls and bounding box only (no tooltip callback)
|
|
680
|
+
* @param {THREE.Object3D} object - The object to select
|
|
681
|
+
* @returns {boolean} True if selection successful
|
|
682
|
+
*/
|
|
683
|
+
}, {
|
|
684
|
+
key: "selectObjectForTransformOnly",
|
|
685
|
+
value: function selectObjectForTransformOnly(object) {
|
|
686
|
+
if (!object || !object.isObject3D) {
|
|
687
|
+
console.warn('⚠️ Invalid object provided for selection');
|
|
688
|
+
return false;
|
|
689
|
+
}
|
|
690
|
+
this.selectedObject = object;
|
|
691
|
+
|
|
692
|
+
// Force object matrix update to ensure correct transforms
|
|
693
|
+
object.updateMatrixWorld(true);
|
|
694
|
+
|
|
695
|
+
// Refresh bounding box cache for this object
|
|
696
|
+
var updatedBoundingBox = new THREE.Box3().setFromObject(object);
|
|
697
|
+
this.boundingBoxCache.set(object, updatedBoundingBox);
|
|
698
|
+
|
|
699
|
+
// Attach transform controls
|
|
700
|
+
this.transformControls.attach(object);
|
|
701
|
+
|
|
702
|
+
// Update interaction time to reset delay
|
|
703
|
+
if (this.transformControls.updateInteractionTime) {
|
|
704
|
+
this.transformControls.updateInteractionTime();
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
// Create and show bounding box if enabled
|
|
708
|
+
this.createBoundingBox(object);
|
|
709
|
+
|
|
710
|
+
// Only enable if not forcing invisibility
|
|
711
|
+
if (!this.forceInvisible) {
|
|
712
|
+
this.transformControls.enabled = true;
|
|
713
|
+
this._showTransformControls();
|
|
714
|
+
} else {
|
|
715
|
+
console.log('🔒 Transform controls kept invisible despite object selection');
|
|
716
|
+
this.transformControls.enabled = false;
|
|
717
|
+
this._hideTransformControls();
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
// NOTE: We deliberately do NOT call any callback here
|
|
721
|
+
// This allows transform controls and bounding box to show without triggering tooltips
|
|
722
|
+
|
|
723
|
+
console.log("\uD83C\uDFAF Object selected for transform only: ".concat(object.name || object.uuid));
|
|
724
|
+
return true;
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
/**
|
|
728
|
+
* Deselect the currently selected object
|
|
729
|
+
*/
|
|
730
|
+
}, {
|
|
731
|
+
key: "deselectObject",
|
|
732
|
+
value: function deselectObject() {
|
|
733
|
+
if (this.selectedObject) {
|
|
734
|
+
console.log("\uD83D\uDD04 Object deselected: ".concat(this.selectedObject.name || this.selectedObject.uuid));
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
// Remove bounding box
|
|
738
|
+
this.removeBoundingBox();
|
|
739
|
+
this.selectedObject = null;
|
|
740
|
+
// Detach and hide transform controls
|
|
741
|
+
if (this.transformControls) {
|
|
742
|
+
// First detach from object
|
|
743
|
+
this.transformControls.detach();
|
|
744
|
+
this.transformControls.enabled = false;
|
|
745
|
+
|
|
746
|
+
// Properly hide all transform control components
|
|
747
|
+
this._hideTransformControls();
|
|
748
|
+
console.log("\uD83D\uDD12 Transform controls hidden after deselection");
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
// Execute callback
|
|
752
|
+
if (this.callbacks.onObjectSelect) {
|
|
753
|
+
this.callbacks.onObjectSelect(null);
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
|
|
757
|
+
/**
|
|
758
|
+
* Create and display a bounding box for the selected object
|
|
759
|
+
* @param {THREE.Object3D} object - The object to create a bounding box for
|
|
760
|
+
*/
|
|
761
|
+
}, {
|
|
762
|
+
key: "createBoundingBox",
|
|
763
|
+
value: function createBoundingBox(object) {
|
|
764
|
+
// Skip if bounding box is disabled
|
|
765
|
+
if (!this.config.showBoundingBox) {
|
|
766
|
+
return;
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
// Remove any existing bounding box first
|
|
770
|
+
this.removeBoundingBox();
|
|
771
|
+
if (!object) {
|
|
772
|
+
return;
|
|
773
|
+
}
|
|
774
|
+
try {
|
|
775
|
+
// Create a BoxHelper to show the bounding box
|
|
776
|
+
this.boundingBoxHelper = new THREE.BoxHelper(object, this.config.boundingBoxColor);
|
|
777
|
+
|
|
778
|
+
// Mark it as a helper to avoid selection
|
|
779
|
+
this.boundingBoxHelper.isHelper = true;
|
|
780
|
+
this.boundingBoxHelper.userData = {
|
|
781
|
+
isBoundingBox: true
|
|
782
|
+
};
|
|
783
|
+
console.log("this.boundingBoxHelper object:", object);
|
|
784
|
+
|
|
785
|
+
// Add to scene
|
|
786
|
+
this.scene.add(this.boundingBoxHelper);
|
|
787
|
+
console.log("\uD83D\uDCE6 Bounding box created for: ".concat(object.name || object.uuid));
|
|
788
|
+
} catch (error) {
|
|
789
|
+
console.warn('⚠️ Failed to create bounding box:', error);
|
|
790
|
+
}
|
|
791
|
+
}
|
|
792
|
+
|
|
793
|
+
/**
|
|
794
|
+
* Remove the current bounding box helper
|
|
795
|
+
*/
|
|
796
|
+
}, {
|
|
797
|
+
key: "removeBoundingBox",
|
|
798
|
+
value: function removeBoundingBox() {
|
|
799
|
+
if (this.boundingBoxHelper) {
|
|
800
|
+
try {
|
|
801
|
+
// Remove from scene
|
|
802
|
+
if (this.boundingBoxHelper.parent) {
|
|
803
|
+
this.boundingBoxHelper.parent.remove(this.boundingBoxHelper);
|
|
804
|
+
}
|
|
805
|
+
|
|
806
|
+
// Dispose geometry and material if they exist
|
|
807
|
+
if (this.boundingBoxHelper.geometry) {
|
|
808
|
+
this.boundingBoxHelper.geometry.dispose();
|
|
809
|
+
}
|
|
810
|
+
if (this.boundingBoxHelper.material) {
|
|
811
|
+
this.boundingBoxHelper.material.dispose();
|
|
812
|
+
}
|
|
813
|
+
console.log('📦 Bounding box removed');
|
|
814
|
+
} catch (error) {
|
|
815
|
+
console.warn('⚠️ Error removing bounding box:', error);
|
|
816
|
+
} finally {
|
|
817
|
+
this.boundingBoxHelper = null;
|
|
818
|
+
}
|
|
819
|
+
}
|
|
820
|
+
}
|
|
821
|
+
|
|
822
|
+
/**
|
|
823
|
+
* Update the bounding box to match the current object state
|
|
824
|
+
* Call this after any transformation to keep the bounding box in sync
|
|
825
|
+
*/
|
|
826
|
+
}, {
|
|
827
|
+
key: "updateBoundingBox",
|
|
828
|
+
value: function updateBoundingBox() {
|
|
829
|
+
if (this.boundingBoxHelper && this.selectedObject) {
|
|
830
|
+
try {
|
|
831
|
+
// Force object matrix update to ensure correct bounding box
|
|
832
|
+
this.selectedObject.updateMatrixWorld(true);
|
|
833
|
+
|
|
834
|
+
// Update bounding box
|
|
835
|
+
this.boundingBoxHelper.update();
|
|
836
|
+
|
|
837
|
+
// Also update the cached bounding box if it exists
|
|
838
|
+
if (this.boundingBoxCache.has(this.selectedObject)) {
|
|
839
|
+
var updatedBoundingBox = new THREE.Box3().setFromObject(this.selectedObject);
|
|
840
|
+
this.boundingBoxCache.set(this.selectedObject, updatedBoundingBox);
|
|
841
|
+
}
|
|
842
|
+
} catch (error) {
|
|
843
|
+
console.warn('⚠️ Error updating bounding box:', error);
|
|
844
|
+
// If update fails, recreate the bounding box
|
|
845
|
+
this.createBoundingBox(this.selectedObject);
|
|
846
|
+
}
|
|
847
|
+
}
|
|
848
|
+
}
|
|
849
|
+
|
|
850
|
+
/**
|
|
851
|
+
* Set bounding box visibility
|
|
852
|
+
* @param {boolean} show - Whether to show the bounding box
|
|
853
|
+
*/
|
|
854
|
+
}, {
|
|
855
|
+
key: "setBoundingBoxVisibility",
|
|
856
|
+
value: function setBoundingBoxVisibility(show) {
|
|
857
|
+
this.config.showBoundingBox = show;
|
|
858
|
+
if (show && this.selectedObject && !this.boundingBoxHelper) {
|
|
859
|
+
// Create bounding box if it doesn't exist and we have a selected object
|
|
860
|
+
this.createBoundingBox(this.selectedObject);
|
|
861
|
+
} else if (!show && this.boundingBoxHelper) {
|
|
862
|
+
// Remove bounding box if it exists and we're hiding it
|
|
863
|
+
this.removeBoundingBox();
|
|
864
|
+
}
|
|
865
|
+
console.log("\uD83D\uDCE6 Bounding box visibility: ".concat(show ? 'enabled' : 'disabled'));
|
|
866
|
+
}
|
|
867
|
+
|
|
868
|
+
/**
|
|
869
|
+
* Set bounding box color
|
|
870
|
+
* @param {number} color - The color value (hex)
|
|
871
|
+
*/
|
|
872
|
+
}, {
|
|
873
|
+
key: "setBoundingBoxColor",
|
|
874
|
+
value: function setBoundingBoxColor(color) {
|
|
875
|
+
this.config.boundingBoxColor = color;
|
|
876
|
+
|
|
877
|
+
// Update existing bounding box color if it exists
|
|
878
|
+
if (this.boundingBoxHelper && this.boundingBoxHelper.material) {
|
|
879
|
+
this.boundingBoxHelper.material.color.setHex(color);
|
|
880
|
+
}
|
|
881
|
+
console.log("\uD83D\uDCE6 Bounding box color set to: 0x".concat(color.toString(16).padStart(6, '0')));
|
|
882
|
+
}
|
|
883
|
+
|
|
884
|
+
/**
|
|
885
|
+
* Set the transformation mode
|
|
886
|
+
* @param {'translate' | 'rotate' | 'scale'} mode - The transformation mode
|
|
887
|
+
*/
|
|
888
|
+
}, {
|
|
889
|
+
key: "setMode",
|
|
890
|
+
value: function setMode(mode) {
|
|
891
|
+
if (!['translate', 'rotate', 'scale'].includes(mode)) {
|
|
892
|
+
console.warn("\u26A0\uFE0F Invalid transform mode: ".concat(mode));
|
|
893
|
+
return;
|
|
894
|
+
}
|
|
895
|
+
var previousMode = this.currentMode;
|
|
896
|
+
this.currentMode = mode;
|
|
897
|
+
this.transformControls.setMode(mode);
|
|
898
|
+
|
|
899
|
+
// Execute callback
|
|
900
|
+
if (this.callbacks.onModeChange) {
|
|
901
|
+
this.callbacks.onModeChange(mode, previousMode);
|
|
902
|
+
}
|
|
903
|
+
console.log("\uD83D\uDD27 Transform mode changed: ".concat(previousMode, " \u2192 ").concat(mode));
|
|
904
|
+
}
|
|
905
|
+
|
|
906
|
+
/**
|
|
907
|
+
* Set the transformation space
|
|
908
|
+
* @param {'world' | 'local'} space - The transformation space
|
|
909
|
+
*/
|
|
910
|
+
}, {
|
|
911
|
+
key: "setSpace",
|
|
912
|
+
value: function setSpace(space) {
|
|
913
|
+
if (!['world', 'local'].includes(space)) {
|
|
914
|
+
console.warn("\u26A0\uFE0F Invalid transform space: ".concat(space));
|
|
915
|
+
return;
|
|
916
|
+
}
|
|
917
|
+
var previousSpace = this.currentSpace;
|
|
918
|
+
this.currentSpace = space;
|
|
919
|
+
this.transformControls.setSpace(space);
|
|
920
|
+
console.log("\uD83C\uDF10 Transform space changed: ".concat(previousSpace, " \u2192 ").concat(space));
|
|
921
|
+
}
|
|
922
|
+
|
|
923
|
+
/**
|
|
924
|
+
* Set axis constraint for transformations
|
|
925
|
+
* @param {'X' | 'Y' | 'Z'} axis - The axis to constrain to
|
|
926
|
+
*/
|
|
927
|
+
}, {
|
|
928
|
+
key: "setAxisConstraint",
|
|
929
|
+
value: function setAxisConstraint(axis) {
|
|
930
|
+
if (!['X', 'Y', 'Z'].includes(axis)) {
|
|
931
|
+
console.warn("\u26A0\uFE0F Invalid axis constraint: ".concat(axis));
|
|
932
|
+
return;
|
|
933
|
+
}
|
|
934
|
+
|
|
935
|
+
// Reset all axes first
|
|
936
|
+
this.transformControls.showX = false;
|
|
937
|
+
this.transformControls.showY = false;
|
|
938
|
+
this.transformControls.showZ = false;
|
|
939
|
+
|
|
940
|
+
// Enable only the specified axis
|
|
941
|
+
this.transformControls["show".concat(axis)] = true;
|
|
942
|
+
console.log("\uD83D\uDD12 Axis constraint set: ".concat(axis, "-axis only"));
|
|
943
|
+
}
|
|
944
|
+
|
|
945
|
+
/**
|
|
946
|
+
* Clear axis constraints (show all axes)
|
|
947
|
+
*/
|
|
948
|
+
}, {
|
|
949
|
+
key: "clearAxisConstraint",
|
|
950
|
+
value: function clearAxisConstraint() {
|
|
951
|
+
this.transformControls.showX = this.config.showX;
|
|
952
|
+
this.transformControls.showY = this.config.showY;
|
|
953
|
+
this.transformControls.showZ = this.config.showZ;
|
|
954
|
+
console.log('🔓 Axis constraints cleared');
|
|
955
|
+
}
|
|
956
|
+
|
|
957
|
+
/**
|
|
958
|
+
* Set snapping values for transformations
|
|
959
|
+
* @param {Object} snapConfig - Snap configuration
|
|
960
|
+
* @param {number} snapConfig.translation - Translation snap value
|
|
961
|
+
* @param {number} snapConfig.rotation - Rotation snap value (in radians)
|
|
962
|
+
* @param {number} snapConfig.scale - Scale snap value
|
|
963
|
+
*/
|
|
964
|
+
}, {
|
|
965
|
+
key: "setSnap",
|
|
966
|
+
value: function setSnap() {
|
|
967
|
+
var snapConfig = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
968
|
+
if (snapConfig.translation !== undefined) {
|
|
969
|
+
this.config.translationSnap = snapConfig.translation;
|
|
970
|
+
this.transformControls.setTranslationSnap(snapConfig.translation);
|
|
971
|
+
}
|
|
972
|
+
if (snapConfig.rotation !== undefined) {
|
|
973
|
+
this.config.rotationSnap = snapConfig.rotation;
|
|
974
|
+
this.transformControls.setRotationSnap(snapConfig.rotation);
|
|
975
|
+
}
|
|
976
|
+
if (snapConfig.scale !== undefined) {
|
|
977
|
+
this.config.scaleSnap = snapConfig.scale;
|
|
978
|
+
this.transformControls.setScaleSnap(snapConfig.scale);
|
|
979
|
+
}
|
|
980
|
+
console.log('📏 Snap values updated:', snapConfig);
|
|
981
|
+
}
|
|
982
|
+
|
|
983
|
+
/**
|
|
984
|
+
* Get the current snap values
|
|
985
|
+
* @return {Object} The current snap values for translation, rotation, and scale
|
|
986
|
+
*/
|
|
987
|
+
}, {
|
|
988
|
+
key: "snapValues",
|
|
989
|
+
get: function get() {
|
|
990
|
+
return {
|
|
991
|
+
translation: this.config.translationSnap || 0.5,
|
|
992
|
+
// Default to 0.5 if not set
|
|
993
|
+
rotation: this.config.rotationSnap || Math.PI / 2,
|
|
994
|
+
// Default to 90 degrees if not set
|
|
995
|
+
scale: this.config.scaleSnap || 0.1 // Default to 0.1 if not set
|
|
996
|
+
};
|
|
997
|
+
}
|
|
998
|
+
|
|
999
|
+
/**
|
|
1000
|
+
* Set the size of the transform controls
|
|
1001
|
+
* @param {number} size - The size of the transform controls
|
|
1002
|
+
*/
|
|
1003
|
+
}, {
|
|
1004
|
+
key: "setSize",
|
|
1005
|
+
value: function setSize(size) {
|
|
1006
|
+
this.config.size = size;
|
|
1007
|
+
this.transformControls.setSize(size);
|
|
1008
|
+
console.log("\uD83D\uDCCF Transform controls size set to: ".concat(size));
|
|
1009
|
+
}
|
|
1010
|
+
/**
|
|
1011
|
+
* Enable or disable the transform controls
|
|
1012
|
+
* @param {boolean} enabled - Whether to enable the controls
|
|
1013
|
+
*/
|
|
1014
|
+
}, {
|
|
1015
|
+
key: "setEnabled",
|
|
1016
|
+
value: function setEnabled(enabled) {
|
|
1017
|
+
this.config.enabled = enabled;
|
|
1018
|
+
if (this.selectedObject) {
|
|
1019
|
+
this.transformControls.enabled = enabled;
|
|
1020
|
+
}
|
|
1021
|
+
console.log("\uD83D\uDD04 Transform controls ".concat(enabled ? 'enabled' : 'disabled'));
|
|
1022
|
+
}
|
|
1023
|
+
|
|
1024
|
+
/**
|
|
1025
|
+
* Configure whether multi-axis plane helpers are shown
|
|
1026
|
+
* @param {boolean} showPlanes - Whether to show multi-axis translation planes (XY, YZ, XZ)
|
|
1027
|
+
*/
|
|
1028
|
+
}, {
|
|
1029
|
+
key: "setShowPlanes",
|
|
1030
|
+
value: function setShowPlanes(showPlanes) {
|
|
1031
|
+
if (!this.transformControls) {
|
|
1032
|
+
console.warn('⚠️ Cannot configure plane helpers: transform controls not available');
|
|
1033
|
+
return false;
|
|
1034
|
+
}
|
|
1035
|
+
|
|
1036
|
+
// Set the plane visibility properties directly
|
|
1037
|
+
this.transformControls.showXY = showPlanes;
|
|
1038
|
+
this.transformControls.showYZ = showPlanes;
|
|
1039
|
+
this.transformControls.showXZ = showPlanes;
|
|
1040
|
+
console.log("\uD83D\uDD27 Multi-axis planes ".concat(showPlanes ? 'enabled' : 'disabled'));
|
|
1041
|
+
return true;
|
|
1042
|
+
}
|
|
1043
|
+
/**
|
|
1044
|
+
* Ensure transform controls are properly attached to the scene
|
|
1045
|
+
* This method helps recover from scene operations that might detach the controls
|
|
1046
|
+
*/
|
|
1047
|
+
}, {
|
|
1048
|
+
key: "ensureSceneAttachment",
|
|
1049
|
+
value: function ensureSceneAttachment() {
|
|
1050
|
+
var allowVisible = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
|
|
1051
|
+
// If transform controls don't exist, recreate them
|
|
1052
|
+
if (!this.transformControls && this.scene && this.camera && this.renderer) {
|
|
1053
|
+
console.log('🔧 Transform controls missing, recreating...');
|
|
1054
|
+
this.createTransformControls();
|
|
1055
|
+
this.setupEventListeners();
|
|
1056
|
+
console.log('✅ Transform controls recreated and attached to scene');
|
|
1057
|
+
if (!allowVisible) {
|
|
1058
|
+
this.transformControls.visible = false;
|
|
1059
|
+
console.log('🔧 Setting newly created transform controls to invisible');
|
|
1060
|
+
}
|
|
1061
|
+
return true;
|
|
1062
|
+
}
|
|
1063
|
+
if (!this.transformControls || !this.scene) {
|
|
1064
|
+
console.warn('⚠️ Cannot ensure attachment: missing transform controls or scene');
|
|
1065
|
+
return false;
|
|
1066
|
+
}
|
|
1067
|
+
|
|
1068
|
+
// Check if transform controls are still in the scene
|
|
1069
|
+
var isAttached = this.scene.children.includes(this.transformControls);
|
|
1070
|
+
if (!isAttached) {
|
|
1071
|
+
console.log('🔧 Re-attaching transform controls to scene...');
|
|
1072
|
+
this.scene.add(this.transformControls);
|
|
1073
|
+
|
|
1074
|
+
// Reset state after reattachment
|
|
1075
|
+
this.transformControls.enabled = false;
|
|
1076
|
+
if (this.selectedObject) {
|
|
1077
|
+
// If there was a selected object, reattach it
|
|
1078
|
+
this.transformControls.attach(this.selectedObject);
|
|
1079
|
+
this.transformControls.enabled = this.config.enabled;
|
|
1080
|
+
}
|
|
1081
|
+
|
|
1082
|
+
// Control visibility based on allowVisible parameter
|
|
1083
|
+
if (!allowVisible) {
|
|
1084
|
+
this.transformControls.visible = false;
|
|
1085
|
+
console.log('🔧 Keeping reattached transform controls invisible');
|
|
1086
|
+
}
|
|
1087
|
+
console.log('✅ Transform controls reattached to scene');
|
|
1088
|
+
return true;
|
|
1089
|
+
}
|
|
1090
|
+
// Only make visible if allowVisible is true
|
|
1091
|
+
if (!this.transformControls.visible && allowVisible) {
|
|
1092
|
+
console.log('🔧 Transform controls were invisible, making visible');
|
|
1093
|
+
this.transformControls.visible = true;
|
|
1094
|
+
return true;
|
|
1095
|
+
} else if (this.transformControls.visible && !allowVisible) {
|
|
1096
|
+
console.log('🔧 Transform controls were visible, making invisible');
|
|
1097
|
+
this.transformControls.visible = false;
|
|
1098
|
+
return true;
|
|
1099
|
+
}
|
|
1100
|
+
|
|
1101
|
+
// Check if the transform controls have a parent but it's not the scene
|
|
1102
|
+
if (this.transformControls.parent && this.transformControls.parent !== this.scene) {
|
|
1103
|
+
console.log('🔧 Transform controls have wrong parent, re-attaching to scene...');
|
|
1104
|
+
this.transformControls.parent.remove(this.transformControls);
|
|
1105
|
+
this.scene.add(this.transformControls);
|
|
1106
|
+
return true;
|
|
1107
|
+
}
|
|
1108
|
+
return false;
|
|
1109
|
+
}
|
|
1110
|
+
|
|
1111
|
+
/**
|
|
1112
|
+
* Get the current transformation data
|
|
1113
|
+
* @returns {Object} Current transformation state
|
|
1114
|
+
*/
|
|
1115
|
+
}, {
|
|
1116
|
+
key: "getTransformData",
|
|
1117
|
+
value: function getTransformData() {
|
|
1118
|
+
if (!this.selectedObject) {
|
|
1119
|
+
return null;
|
|
1120
|
+
}
|
|
1121
|
+
|
|
1122
|
+
// Get local transforms (existing)
|
|
1123
|
+
var localTransforms = {
|
|
1124
|
+
position: this.selectedObject.position.clone(),
|
|
1125
|
+
rotation: this.selectedObject.rotation.clone(),
|
|
1126
|
+
scale: this.selectedObject.scale.clone()
|
|
1127
|
+
};
|
|
1128
|
+
|
|
1129
|
+
// Get world transforms (new)
|
|
1130
|
+
var worldTransforms = this.getWorldTransformData();
|
|
1131
|
+
return {
|
|
1132
|
+
object: this.selectedObject,
|
|
1133
|
+
position: localTransforms.position,
|
|
1134
|
+
rotation: localTransforms.rotation,
|
|
1135
|
+
scale: localTransforms.scale,
|
|
1136
|
+
worldPosition: worldTransforms.position,
|
|
1137
|
+
worldRotation: worldTransforms.rotation,
|
|
1138
|
+
worldScale: worldTransforms.scale,
|
|
1139
|
+
mode: this.currentMode,
|
|
1140
|
+
space: this.currentSpace,
|
|
1141
|
+
isTransforming: this.transformState.isTransforming
|
|
1142
|
+
};
|
|
1143
|
+
}
|
|
1144
|
+
|
|
1145
|
+
/**
|
|
1146
|
+
* Get world transformation data for the selected object
|
|
1147
|
+
* @returns {Object} World transformation data
|
|
1148
|
+
*/
|
|
1149
|
+
}, {
|
|
1150
|
+
key: "getWorldTransformData",
|
|
1151
|
+
value: function getWorldTransformData() {
|
|
1152
|
+
if (!this.selectedObject) {
|
|
1153
|
+
return null;
|
|
1154
|
+
}
|
|
1155
|
+
|
|
1156
|
+
// Ensure the object's world matrix is up to date
|
|
1157
|
+
this.selectedObject.updateMatrixWorld(true);
|
|
1158
|
+
|
|
1159
|
+
// Get world position
|
|
1160
|
+
var worldPosition = new THREE.Vector3();
|
|
1161
|
+
this.selectedObject.getWorldPosition(worldPosition);
|
|
1162
|
+
|
|
1163
|
+
// Get world quaternion
|
|
1164
|
+
var worldQuaternion = new THREE.Quaternion();
|
|
1165
|
+
this.selectedObject.getWorldQuaternion(worldQuaternion);
|
|
1166
|
+
|
|
1167
|
+
// Convert quaternion to Euler rotation
|
|
1168
|
+
var worldRotation = new THREE.Euler();
|
|
1169
|
+
worldRotation.setFromQuaternion(worldQuaternion);
|
|
1170
|
+
|
|
1171
|
+
// Get world scale
|
|
1172
|
+
var worldScale = new THREE.Vector3();
|
|
1173
|
+
this.selectedObject.getWorldScale(worldScale);
|
|
1174
|
+
return {
|
|
1175
|
+
position: worldPosition,
|
|
1176
|
+
rotation: worldRotation,
|
|
1177
|
+
scale: worldScale
|
|
1178
|
+
};
|
|
1179
|
+
}
|
|
1180
|
+
|
|
1181
|
+
/**
|
|
1182
|
+
* Update object transform using world coordinates
|
|
1183
|
+
* @param {string} type - Transform type: 'position', 'rotation', 'scale'
|
|
1184
|
+
* @param {string} axis - Axis: 'x', 'y', 'z'
|
|
1185
|
+
* @param {number|string} value - The world coordinate value to set
|
|
1186
|
+
* @param {boolean} useWorldCoords - Whether to interpret the value as world coordinates
|
|
1187
|
+
*/
|
|
1188
|
+
}, {
|
|
1189
|
+
key: "updateObjectTransform",
|
|
1190
|
+
value: function updateObjectTransform(type, axis, value) {
|
|
1191
|
+
var useWorldCoords = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
|
|
1192
|
+
if (!this.selectedObject) {
|
|
1193
|
+
console.warn('⚠️ No object selected for transformation');
|
|
1194
|
+
return;
|
|
1195
|
+
}
|
|
1196
|
+
var object = this.selectedObject;
|
|
1197
|
+
var numericValue = parseFloat(value);
|
|
1198
|
+
if (isNaN(numericValue)) {
|
|
1199
|
+
console.warn('⚠️ Invalid numeric value for transform:', value);
|
|
1200
|
+
return;
|
|
1201
|
+
}
|
|
1202
|
+
if (useWorldCoords) {
|
|
1203
|
+
// Update using world coordinates
|
|
1204
|
+
this.updateWorldTransform(object, type, axis, numericValue);
|
|
1205
|
+
} else {
|
|
1206
|
+
// Update using local coordinates (existing behavior)
|
|
1207
|
+
switch (type) {
|
|
1208
|
+
case 'position':
|
|
1209
|
+
object.position[axis] = numericValue;
|
|
1210
|
+
break;
|
|
1211
|
+
case 'rotation':
|
|
1212
|
+
// Convert from degrees to radians
|
|
1213
|
+
object.rotation[axis] = numericValue * (Math.PI / 180);
|
|
1214
|
+
break;
|
|
1215
|
+
case 'scale':
|
|
1216
|
+
object.scale[axis] = numericValue;
|
|
1217
|
+
break;
|
|
1218
|
+
default:
|
|
1219
|
+
console.warn("\u26A0\uFE0F Unknown transform type: ".concat(type));
|
|
1220
|
+
return;
|
|
1221
|
+
}
|
|
1222
|
+
} // Update transform controls to reflect the change
|
|
1223
|
+
if (this.transformControls) {
|
|
1224
|
+
this.transformControls.updateMatrixWorld();
|
|
1225
|
+
}
|
|
1226
|
+
|
|
1227
|
+
// Update bounding box to reflect the change
|
|
1228
|
+
this.updateBoundingBox();
|
|
1229
|
+
var coordType = useWorldCoords ? 'world' : 'local';
|
|
1230
|
+
console.log("\uD83D\uDD04 Updated ".concat(coordType, " ").concat(type, ".").concat(axis, " to ").concat(numericValue, " for ").concat(object.name));
|
|
1231
|
+
}
|
|
1232
|
+
|
|
1233
|
+
/**
|
|
1234
|
+
* Update object transform using world coordinates
|
|
1235
|
+
* @param {THREE.Object3D} object - The object to transform
|
|
1236
|
+
* @param {string} type - Transform type: 'position', 'rotation', 'scale'
|
|
1237
|
+
* @param {string} axis - Axis: 'x', 'y', 'z'
|
|
1238
|
+
* @param {number} worldValue - The world coordinate value
|
|
1239
|
+
*/
|
|
1240
|
+
}, {
|
|
1241
|
+
key: "updateWorldTransform",
|
|
1242
|
+
value: function updateWorldTransform(object, type, axis, worldValue) {
|
|
1243
|
+
// Ensure matrices are up to date
|
|
1244
|
+
object.updateMatrixWorld(true);
|
|
1245
|
+
switch (type) {
|
|
1246
|
+
case 'position':
|
|
1247
|
+
this.setWorldPosition(object, axis, worldValue);
|
|
1248
|
+
break;
|
|
1249
|
+
case 'rotation':
|
|
1250
|
+
this.setWorldRotation(object, axis, worldValue);
|
|
1251
|
+
break;
|
|
1252
|
+
case 'scale':
|
|
1253
|
+
this.setWorldScale(object, axis, worldValue);
|
|
1254
|
+
break;
|
|
1255
|
+
default:
|
|
1256
|
+
console.warn("\u26A0\uFE0F Unknown transform type: ".concat(type));
|
|
1257
|
+
}
|
|
1258
|
+
}
|
|
1259
|
+
|
|
1260
|
+
/**
|
|
1261
|
+
* Set world position for a specific axis
|
|
1262
|
+
* @param {THREE.Object3D} object - The object
|
|
1263
|
+
* @param {string} axis - The axis ('x', 'y', or 'z')
|
|
1264
|
+
* @param {number} worldValue - The world position value
|
|
1265
|
+
*/
|
|
1266
|
+
}, {
|
|
1267
|
+
key: "setWorldPosition",
|
|
1268
|
+
value: function setWorldPosition(object, axis, worldValue) {
|
|
1269
|
+
// Get current world position
|
|
1270
|
+
var currentWorldPos = new THREE.Vector3();
|
|
1271
|
+
object.getWorldPosition(currentWorldPos);
|
|
1272
|
+
|
|
1273
|
+
// Update the specific axis
|
|
1274
|
+
currentWorldPos[axis] = worldValue;
|
|
1275
|
+
|
|
1276
|
+
// Convert world position back to local position
|
|
1277
|
+
if (object.parent) {
|
|
1278
|
+
var parentMatrixInverse = new THREE.Matrix4();
|
|
1279
|
+
parentMatrixInverse.copy(object.parent.matrixWorld).invert();
|
|
1280
|
+
currentWorldPos.applyMatrix4(parentMatrixInverse);
|
|
1281
|
+
}
|
|
1282
|
+
|
|
1283
|
+
// Set the local position
|
|
1284
|
+
object.position.copy(currentWorldPos);
|
|
1285
|
+
}
|
|
1286
|
+
|
|
1287
|
+
/**
|
|
1288
|
+
* Set world rotation for a specific axis
|
|
1289
|
+
* @param {THREE.Object3D} object - The object
|
|
1290
|
+
* @param {string} axis - The axis ('x', 'y', or 'z')
|
|
1291
|
+
* @param {number} worldValue - The world rotation value in degrees
|
|
1292
|
+
*/
|
|
1293
|
+
}, {
|
|
1294
|
+
key: "setWorldRotation",
|
|
1295
|
+
value: function setWorldRotation(object, axis, worldValue) {
|
|
1296
|
+
// Get current world quaternion
|
|
1297
|
+
var currentWorldQuat = new THREE.Quaternion();
|
|
1298
|
+
object.getWorldQuaternion(currentWorldQuat);
|
|
1299
|
+
|
|
1300
|
+
// Convert to Euler
|
|
1301
|
+
var currentWorldEuler = new THREE.Euler();
|
|
1302
|
+
currentWorldEuler.setFromQuaternion(currentWorldQuat);
|
|
1303
|
+
|
|
1304
|
+
// Update the specific axis (convert degrees to radians)
|
|
1305
|
+
currentWorldEuler[axis] = worldValue * (Math.PI / 180);
|
|
1306
|
+
|
|
1307
|
+
// Convert back to quaternion
|
|
1308
|
+
var newWorldQuat = new THREE.Quaternion();
|
|
1309
|
+
newWorldQuat.setFromEuler(currentWorldEuler);
|
|
1310
|
+
|
|
1311
|
+
// Convert world quaternion back to local rotation
|
|
1312
|
+
if (object.parent) {
|
|
1313
|
+
var parentWorldQuat = new THREE.Quaternion();
|
|
1314
|
+
object.parent.getWorldQuaternion(parentWorldQuat);
|
|
1315
|
+
parentWorldQuat.invert();
|
|
1316
|
+
newWorldQuat.premultiply(parentWorldQuat);
|
|
1317
|
+
}
|
|
1318
|
+
|
|
1319
|
+
// Set the local rotation
|
|
1320
|
+
object.quaternion.copy(newWorldQuat);
|
|
1321
|
+
}
|
|
1322
|
+
|
|
1323
|
+
/**
|
|
1324
|
+
* Set world scale for a specific axis
|
|
1325
|
+
* @param {THREE.Object3D} object - The object
|
|
1326
|
+
* @param {string} axis - The axis ('x', 'y', or 'z')
|
|
1327
|
+
* @param {number} worldValue - The world scale value
|
|
1328
|
+
*/
|
|
1329
|
+
}, {
|
|
1330
|
+
key: "setWorldScale",
|
|
1331
|
+
value: function setWorldScale(object, axis, worldValue) {
|
|
1332
|
+
// Get current world scale
|
|
1333
|
+
var currentWorldScale = new THREE.Vector3();
|
|
1334
|
+
object.getWorldScale(currentWorldScale);
|
|
1335
|
+
|
|
1336
|
+
// Calculate the scale factor needed
|
|
1337
|
+
var scaleFactor = worldValue / currentWorldScale[axis];
|
|
1338
|
+
|
|
1339
|
+
// Apply to local scale
|
|
1340
|
+
object.scale[axis] *= scaleFactor;
|
|
1341
|
+
}
|
|
1342
|
+
/**
|
|
1343
|
+
* Get selectable objects with their bounding boxes for ray intersection testing
|
|
1344
|
+
* @param {Function} objectFilter - Optional function to filter selectable objects
|
|
1345
|
+
* @returns {Array} Array of objects with their bounding boxes
|
|
1346
|
+
*/
|
|
1347
|
+
}, {
|
|
1348
|
+
key: "getSelectableObjectsWithBounds",
|
|
1349
|
+
value: function getSelectableObjectsWithBounds() {
|
|
1350
|
+
var _this4 = this;
|
|
1351
|
+
var objectFilter = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;
|
|
1352
|
+
var objectsWithBounds = [];
|
|
1353
|
+
|
|
1354
|
+
// Traverse scene to find selectable objects
|
|
1355
|
+
this.scene.traverse(function (object) {
|
|
1356
|
+
var _object$userData0, _object$userData1;
|
|
1357
|
+
// Skip invalid objects and helpers early
|
|
1358
|
+
if (!object || !object.isObject3D) {
|
|
1359
|
+
return;
|
|
1360
|
+
}
|
|
1361
|
+
|
|
1362
|
+
// Skip transform controls and their children
|
|
1363
|
+
if (object.isTransformControls || object.isTransformControlsPlane || object.isTransformControlsGizmo) {
|
|
1364
|
+
return;
|
|
1365
|
+
}
|
|
1366
|
+
|
|
1367
|
+
// Skip other helpers and special objects
|
|
1368
|
+
if (object.isHelper || (_object$userData0 = object.userData) !== null && _object$userData0 !== void 0 && _object$userData0.isHelper || (_object$userData1 = object.userData) !== null && _object$userData1 !== void 0 && _object$userData1.isBoundingBox) {
|
|
1369
|
+
return;
|
|
1370
|
+
}
|
|
1371
|
+
try {
|
|
1372
|
+
// Apply filter (use provided filter or default isSelectableObject method)
|
|
1373
|
+
var isSelectable = objectFilter ? objectFilter(object) : _this4.isSelectableObject(object);
|
|
1374
|
+
if (isSelectable) {
|
|
1375
|
+
// Force object matrix update to ensure correct bounding box
|
|
1376
|
+
object.updateMatrixWorld(true);
|
|
1377
|
+
|
|
1378
|
+
// Get or compute bounding box
|
|
1379
|
+
var boundingBox = _this4.boundingBoxCache.get(object);
|
|
1380
|
+
|
|
1381
|
+
// Always recompute bounding box for recently transformed objects
|
|
1382
|
+
// or if no cached bounding box exists
|
|
1383
|
+
if (!boundingBox || object === _this4.selectedObject) {
|
|
1384
|
+
// Compute and cache bounding box
|
|
1385
|
+
boundingBox = new THREE.Box3().setFromObject(object);
|
|
1386
|
+
_this4.boundingBoxCache.set(object, boundingBox);
|
|
1387
|
+
}
|
|
1388
|
+
objectsWithBounds.push({
|
|
1389
|
+
object: object,
|
|
1390
|
+
boundingBox: boundingBox
|
|
1391
|
+
});
|
|
1392
|
+
}
|
|
1393
|
+
} catch (error) {
|
|
1394
|
+
// Silently skip objects that cause errors during filtering
|
|
1395
|
+
console.warn('⚠️ Skipping object due to filter error:', object.type || 'unknown', error.message);
|
|
1396
|
+
}
|
|
1397
|
+
});
|
|
1398
|
+
return objectsWithBounds;
|
|
1399
|
+
}
|
|
1400
|
+
|
|
1401
|
+
/**
|
|
1402
|
+
* Test ray intersection with object bounding boxes
|
|
1403
|
+
* @param {THREE.Raycaster} raycaster - The raycaster to test intersections with
|
|
1404
|
+
* @param {Function} objectFilter - Optional function to filter selectable objects
|
|
1405
|
+
* @returns {Array} Array of intersection results sorted by distance
|
|
1406
|
+
*/
|
|
1407
|
+
}, {
|
|
1408
|
+
key: "intersectObjectsBoundingBoxes",
|
|
1409
|
+
value: function intersectObjectsBoundingBoxes(raycaster) {
|
|
1410
|
+
var objectFilter = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
|
|
1411
|
+
var objectsWithBounds = this.getSelectableObjectsWithBounds(objectFilter);
|
|
1412
|
+
var intersections = [];
|
|
1413
|
+
var _iterator = _createForOfIteratorHelper(objectsWithBounds),
|
|
1414
|
+
_step;
|
|
1415
|
+
try {
|
|
1416
|
+
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
1417
|
+
var item = _step.value;
|
|
1418
|
+
var object = item.object,
|
|
1419
|
+
boundingBox = item.boundingBox;
|
|
1420
|
+
|
|
1421
|
+
// Test ray intersection with bounding box
|
|
1422
|
+
var intersection = raycaster.ray.intersectBox(boundingBox, new THREE.Vector3());
|
|
1423
|
+
if (intersection) {
|
|
1424
|
+
// Calculate distance from ray origin to intersection point
|
|
1425
|
+
var distance = raycaster.ray.origin.distanceTo(intersection);
|
|
1426
|
+
intersections.push({
|
|
1427
|
+
object: object,
|
|
1428
|
+
point: intersection,
|
|
1429
|
+
distance: distance,
|
|
1430
|
+
boundingBox: boundingBox
|
|
1431
|
+
});
|
|
1432
|
+
}
|
|
1433
|
+
}
|
|
1434
|
+
|
|
1435
|
+
// Sort by distance (closest first)
|
|
1436
|
+
} catch (err) {
|
|
1437
|
+
_iterator.e(err);
|
|
1438
|
+
} finally {
|
|
1439
|
+
_iterator.f();
|
|
1440
|
+
}
|
|
1441
|
+
intersections.sort(function (a, b) {
|
|
1442
|
+
return a.distance - b.distance;
|
|
1443
|
+
});
|
|
1444
|
+
return intersections;
|
|
1445
|
+
}
|
|
1446
|
+
|
|
1447
|
+
/**
|
|
1448
|
+
* Toggle between bounding box-based and mesh-based selection
|
|
1449
|
+
* @param {boolean} useBoundingBox - Whether to use bounding box selection
|
|
1450
|
+
*/
|
|
1451
|
+
}, {
|
|
1452
|
+
key: "setBoundingBoxSelection",
|
|
1453
|
+
value: function setBoundingBoxSelection(useBoundingBox) {
|
|
1454
|
+
this.config.useBoundingBoxSelection = useBoundingBox;
|
|
1455
|
+
console.log("\uD83C\uDFAF Selection method: ".concat(useBoundingBox ? 'Bounding Box' : 'Mesh-based'));
|
|
1456
|
+
}
|
|
1457
|
+
|
|
1458
|
+
/**
|
|
1459
|
+
* Handle object removal when backspace is pressed
|
|
1460
|
+
*/
|
|
1461
|
+
}, {
|
|
1462
|
+
key: "handleObjectRemoval",
|
|
1463
|
+
value: function handleObjectRemoval() {
|
|
1464
|
+
var _this$selectedObject$;
|
|
1465
|
+
if (!this.selectedObject) {
|
|
1466
|
+
return;
|
|
1467
|
+
}
|
|
1468
|
+
|
|
1469
|
+
// Check if the object is a gateway
|
|
1470
|
+
if (((_this$selectedObject$ = this.selectedObject.userData) === null || _this$selectedObject$ === void 0 ? void 0 : _this$selectedObject$.componentType) === 'gateway') {
|
|
1471
|
+
console.log('🔧 Gateway detected - converting from declared to computed');
|
|
1472
|
+
this.handleGatewayRemoval();
|
|
1473
|
+
}
|
|
1474
|
+
}
|
|
1475
|
+
|
|
1476
|
+
/**
|
|
1477
|
+
* Handle gateway removal by converting from declared to computed
|
|
1478
|
+
*/
|
|
1479
|
+
}, {
|
|
1480
|
+
key: "handleGatewayRemoval",
|
|
1481
|
+
value: function handleGatewayRemoval() {
|
|
1482
|
+
var _gateway$userData;
|
|
1483
|
+
var gateway = this.selectedObject;
|
|
1484
|
+
|
|
1485
|
+
// Store gateway information before removal
|
|
1486
|
+
var gatewayInfo = {
|
|
1487
|
+
uuid: gateway.uuid,
|
|
1488
|
+
userData: _objectSpread2({}, gateway.userData),
|
|
1489
|
+
position: gateway.position.clone(),
|
|
1490
|
+
connections: ((_gateway$userData = gateway.userData) === null || _gateway$userData === void 0 ? void 0 : _gateway$userData.connections) || null
|
|
1491
|
+
};
|
|
1492
|
+
console.log('🔧 Converting gateway from declared to computed:', gatewayInfo);
|
|
1493
|
+
|
|
1494
|
+
// Change origin from 'declared' to 'computed'
|
|
1495
|
+
gateway.userData.origin = 'computed';
|
|
1496
|
+
|
|
1497
|
+
// Deselect the object
|
|
1498
|
+
this.deselectObject();
|
|
1499
|
+
|
|
1500
|
+
// Emit the object removed event
|
|
1501
|
+
if (this.callbacks.onObjectRemoved) {
|
|
1502
|
+
this.callbacks.onObjectRemoved(gatewayInfo);
|
|
1503
|
+
}
|
|
1504
|
+
}
|
|
1505
|
+
|
|
1506
|
+
/**
|
|
1507
|
+
* Cleanup and dispose of the transform controls
|
|
1508
|
+
*/
|
|
1509
|
+
}, {
|
|
1510
|
+
key: "dispose",
|
|
1511
|
+
value: function dispose() {
|
|
1512
|
+
// Remove event listeners
|
|
1513
|
+
if (this.eventHandlers.keydown) {
|
|
1514
|
+
window.removeEventListener('keydown', this.eventHandlers.keydown);
|
|
1515
|
+
}
|
|
1516
|
+
if (this.eventHandlers.click) {
|
|
1517
|
+
this.renderer.domElement.removeEventListener('click', this.eventHandlers.click);
|
|
1518
|
+
}
|
|
1519
|
+
|
|
1520
|
+
// Remove bounding box helper
|
|
1521
|
+
this.removeBoundingBox();
|
|
1522
|
+
|
|
1523
|
+
// Deselect any object first
|
|
1524
|
+
if (this.selectedObject) {
|
|
1525
|
+
this.deselectObject();
|
|
1526
|
+
}
|
|
1527
|
+
|
|
1528
|
+
// Dispose transform controls
|
|
1529
|
+
if (this.transformControls) {
|
|
1530
|
+
// Remove event listeners from transform controls
|
|
1531
|
+
if (this.eventHandlers.transformStart) {
|
|
1532
|
+
this.transformControls.removeEventListener('mouseDown', this.eventHandlers.transformStart);
|
|
1533
|
+
}
|
|
1534
|
+
if (this.eventHandlers.transformEnd) {
|
|
1535
|
+
this.transformControls.removeEventListener('mouseUp', this.eventHandlers.transformEnd);
|
|
1536
|
+
}
|
|
1537
|
+
if (this.eventHandlers.transforming) {
|
|
1538
|
+
this.transformControls.removeEventListener('objectChange', this.eventHandlers.transforming);
|
|
1539
|
+
}
|
|
1540
|
+
|
|
1541
|
+
// Detach from any objects
|
|
1542
|
+
this.transformControls.detach();
|
|
1543
|
+
|
|
1544
|
+
// Remove from scene if still attached
|
|
1545
|
+
if (this.scene && this.transformControls.parent === this.scene) {
|
|
1546
|
+
this.scene.remove(this.transformControls);
|
|
1547
|
+
}
|
|
1548
|
+
|
|
1549
|
+
// Dispose and null the reference
|
|
1550
|
+
this.transformControls.dispose();
|
|
1551
|
+
this.transformControls = null;
|
|
1552
|
+
}
|
|
1553
|
+
|
|
1554
|
+
// Clear references - but keep scene, camera, and renderer references for reuse
|
|
1555
|
+
this.selectedObject = null;
|
|
1556
|
+
// Don't null these out: this.scene, this.camera, this.renderer
|
|
1557
|
+
this.orbitControls = null;
|
|
1558
|
+
console.log('🧹 Transform controls disposed');
|
|
1559
|
+
}
|
|
1560
|
+
/**
|
|
1561
|
+
* Force hide the transform controls (debugging method)
|
|
1562
|
+
*/
|
|
1563
|
+
}, {
|
|
1564
|
+
key: "forceHide",
|
|
1565
|
+
value: function forceHide() {
|
|
1566
|
+
if (this.transformControls) {
|
|
1567
|
+
this._hideTransformControls();
|
|
1568
|
+
this.transformControls.enabled = false;
|
|
1569
|
+
console.log('🔒 Transform controls force hidden');
|
|
1570
|
+
}
|
|
1571
|
+
}
|
|
1572
|
+
|
|
1573
|
+
/**
|
|
1574
|
+
* Properly hide transform controls including all child components
|
|
1575
|
+
* @private
|
|
1576
|
+
*/
|
|
1577
|
+
}, {
|
|
1578
|
+
key: "_hideTransformControls",
|
|
1579
|
+
value: function _hideTransformControls() {
|
|
1580
|
+
if (!this.transformControls) return;
|
|
1581
|
+
|
|
1582
|
+
// Hide main transform controls
|
|
1583
|
+
this.transformControls.visible = false;
|
|
1584
|
+
|
|
1585
|
+
// Also hide gizmo and plane components explicitly
|
|
1586
|
+
if (this.transformControls._gizmo) {
|
|
1587
|
+
this.transformControls._gizmo.visible = false;
|
|
1588
|
+
}
|
|
1589
|
+
if (this.transformControls._plane) {
|
|
1590
|
+
this.transformControls._plane.visible = false;
|
|
1591
|
+
}
|
|
1592
|
+
}
|
|
1593
|
+
|
|
1594
|
+
/**
|
|
1595
|
+
* Properly show transform controls including all child components
|
|
1596
|
+
* @private
|
|
1597
|
+
*/
|
|
1598
|
+
}, {
|
|
1599
|
+
key: "_showTransformControls",
|
|
1600
|
+
value: function _showTransformControls() {
|
|
1601
|
+
if (!this.transformControls) return;
|
|
1602
|
+
|
|
1603
|
+
// Show main transform controls
|
|
1604
|
+
this.transformControls.visible = true;
|
|
1605
|
+
|
|
1606
|
+
// Also show gizmo and plane components explicitly
|
|
1607
|
+
if (this.transformControls._gizmo) {
|
|
1608
|
+
this.transformControls._gizmo.visible = true;
|
|
1609
|
+
}
|
|
1610
|
+
if (this.transformControls._plane) {
|
|
1611
|
+
this.transformControls._plane.visible = true;
|
|
1612
|
+
}
|
|
1613
|
+
}
|
|
1614
|
+
|
|
1615
|
+
/**
|
|
1616
|
+
* Check the current visibility state of transform controls (debugging method)
|
|
1617
|
+
*/
|
|
1618
|
+
}, {
|
|
1619
|
+
key: "getVisibilityState",
|
|
1620
|
+
value: function getVisibilityState() {
|
|
1621
|
+
var _this$selectedObject3;
|
|
1622
|
+
if (!this.transformControls) {
|
|
1623
|
+
return {
|
|
1624
|
+
exists: false
|
|
1625
|
+
};
|
|
1626
|
+
}
|
|
1627
|
+
return {
|
|
1628
|
+
exists: true,
|
|
1629
|
+
visible: this.transformControls.visible,
|
|
1630
|
+
enabled: this.transformControls.enabled,
|
|
1631
|
+
gizmoVisible: this.transformControls._gizmo ? this.transformControls._gizmo.visible : 'N/A',
|
|
1632
|
+
planeVisible: this.transformControls._plane ? this.transformControls._plane.visible : 'N/A',
|
|
1633
|
+
hasSelectedObject: !!this.selectedObject,
|
|
1634
|
+
selectedObjectName: ((_this$selectedObject3 = this.selectedObject) === null || _this$selectedObject3 === void 0 ? void 0 : _this$selectedObject3.name) || 'none'
|
|
1635
|
+
};
|
|
1636
|
+
}
|
|
1637
|
+
/**
|
|
1638
|
+
* Force hide all gizmo components to prevent any visibility override
|
|
1639
|
+
* This is necessary because Three.js TransformControls has internal logic that can show gizmos
|
|
1640
|
+
*/
|
|
1641
|
+
}, {
|
|
1642
|
+
key: "_forceHideAllGizmoComponents",
|
|
1643
|
+
value: function _forceHideAllGizmoComponents() {
|
|
1644
|
+
if (!this.transformControls || !this.transformControls._gizmo) {
|
|
1645
|
+
return;
|
|
1646
|
+
}
|
|
1647
|
+
var gizmo = this.transformControls._gizmo;
|
|
1648
|
+
|
|
1649
|
+
// Hide main gizmo
|
|
1650
|
+
gizmo.visible = false;
|
|
1651
|
+
|
|
1652
|
+
// Hide all mode-specific gizmos
|
|
1653
|
+
if (gizmo.gizmo) {
|
|
1654
|
+
Object.keys(gizmo.gizmo).forEach(function (mode) {
|
|
1655
|
+
if (gizmo.gizmo[mode]) {
|
|
1656
|
+
gizmo.gizmo[mode].visible = false;
|
|
1657
|
+
}
|
|
1658
|
+
});
|
|
1659
|
+
}
|
|
1660
|
+
|
|
1661
|
+
// Hide all helpers
|
|
1662
|
+
if (gizmo.helper) {
|
|
1663
|
+
Object.keys(gizmo.helper).forEach(function (mode) {
|
|
1664
|
+
if (gizmo.helper[mode]) {
|
|
1665
|
+
gizmo.helper[mode].visible = false;
|
|
1666
|
+
}
|
|
1667
|
+
});
|
|
1668
|
+
}
|
|
1669
|
+
|
|
1670
|
+
// Also hide the plane
|
|
1671
|
+
if (this.transformControls._plane) {
|
|
1672
|
+
this.transformControls._plane.visible = false;
|
|
1673
|
+
}
|
|
1674
|
+
console.log('🔒 All gizmo components force hidden');
|
|
1675
|
+
}
|
|
1676
|
+
|
|
1677
|
+
/**
|
|
1678
|
+
* Hide multi-axis plane helpers (XY, YZ, XZ) to only allow single-axis translation
|
|
1679
|
+
* @private
|
|
1680
|
+
*/
|
|
1681
|
+
}, {
|
|
1682
|
+
key: "_hidePlaneHelpers",
|
|
1683
|
+
value: function _hidePlaneHelpers() {
|
|
1684
|
+
console.log('🔧 _hidePlaneHelpers called');
|
|
1685
|
+
if (!this.transformControls) {
|
|
1686
|
+
console.warn('⚠️ Cannot hide plane helpers: transform controls not available');
|
|
1687
|
+
return;
|
|
1688
|
+
}
|
|
1689
|
+
if (!this.transformControls._gizmo) {
|
|
1690
|
+
console.warn('⚠️ Cannot hide plane helpers: gizmo not available');
|
|
1691
|
+
return;
|
|
1692
|
+
}
|
|
1693
|
+
var gizmo = this.transformControls._gizmo;
|
|
1694
|
+
console.log('🔍 Gizmo structure:', {
|
|
1695
|
+
hasGizmo: !!gizmo.gizmo,
|
|
1696
|
+
hasTranslate: !!(gizmo.gizmo && gizmo.gizmo.translate),
|
|
1697
|
+
hasPicker: !!gizmo.picker,
|
|
1698
|
+
hasTranslatePicker: !!(gizmo.picker && gizmo.picker.translate)
|
|
1699
|
+
});
|
|
1700
|
+
var hiddenCount = 0;
|
|
1701
|
+
|
|
1702
|
+
// Hide plane helpers in translate gizmo
|
|
1703
|
+
if (gizmo.gizmo && gizmo.gizmo.translate) {
|
|
1704
|
+
var translateGizmo = gizmo.gizmo.translate;
|
|
1705
|
+
console.log('🔍 Translate gizmo children count:', translateGizmo.children.length);
|
|
1706
|
+
translateGizmo.traverse(function (child) {
|
|
1707
|
+
if (child.name === 'XY' || child.name === 'YZ' || child.name === 'XZ') {
|
|
1708
|
+
child.visible = false;
|
|
1709
|
+
hiddenCount++;
|
|
1710
|
+
console.log("\uD83D\uDD12 Hidden plane helper: ".concat(child.name));
|
|
1711
|
+
}
|
|
1712
|
+
});
|
|
1713
|
+
}
|
|
1714
|
+
|
|
1715
|
+
// Hide plane helpers in translate picker
|
|
1716
|
+
if (gizmo.picker && gizmo.picker.translate) {
|
|
1717
|
+
var translatePicker = gizmo.picker.translate;
|
|
1718
|
+
console.log('🔍 Translate picker children count:', translatePicker.children.length);
|
|
1719
|
+
translatePicker.traverse(function (child) {
|
|
1720
|
+
if (child.name === 'XY' || child.name === 'YZ' || child.name === 'XZ') {
|
|
1721
|
+
child.visible = false;
|
|
1722
|
+
hiddenCount++;
|
|
1723
|
+
console.log("\uD83D\uDD12 Hidden plane picker: ".concat(child.name));
|
|
1724
|
+
}
|
|
1725
|
+
});
|
|
1726
|
+
}
|
|
1727
|
+
console.log("\u2705 Multi-axis plane helpers hidden - total hidden: ".concat(hiddenCount));
|
|
1728
|
+
}
|
|
1729
|
+
|
|
1730
|
+
/**
|
|
1731
|
+
* Show multi-axis plane helpers (XY, YZ, XZ) to allow multi-axis translation
|
|
1732
|
+
* @private
|
|
1733
|
+
*/
|
|
1734
|
+
}, {
|
|
1735
|
+
key: "_showPlaneHelpers",
|
|
1736
|
+
value: function _showPlaneHelpers() {
|
|
1737
|
+
if (!this.transformControls || !this.transformControls._gizmo) {
|
|
1738
|
+
console.warn('⚠️ Cannot show plane helpers: transform controls or gizmo not available');
|
|
1739
|
+
return;
|
|
1740
|
+
}
|
|
1741
|
+
var gizmo = this.transformControls._gizmo;
|
|
1742
|
+
|
|
1743
|
+
// Show plane helpers in translate gizmo
|
|
1744
|
+
if (gizmo.gizmo && gizmo.gizmo.translate) {
|
|
1745
|
+
var translateGizmo = gizmo.gizmo.translate;
|
|
1746
|
+
translateGizmo.traverse(function (child) {
|
|
1747
|
+
if (child.name === 'XY' || child.name === 'YZ' || child.name === 'XZ') {
|
|
1748
|
+
child.visible = true;
|
|
1749
|
+
console.log("\uD83D\uDC41\uFE0F Shown plane helper: ".concat(child.name));
|
|
1750
|
+
}
|
|
1751
|
+
});
|
|
1752
|
+
}
|
|
1753
|
+
|
|
1754
|
+
// Show plane helpers in translate picker
|
|
1755
|
+
if (gizmo.picker && gizmo.picker.translate) {
|
|
1756
|
+
var translatePicker = gizmo.picker.translate;
|
|
1757
|
+
translatePicker.traverse(function (child) {
|
|
1758
|
+
if (child.name === 'XY' || child.name === 'YZ' || child.name === 'XZ') {
|
|
1759
|
+
child.visible = true;
|
|
1760
|
+
console.log("\uD83D\uDC41\uFE0F Shown plane picker: ".concat(child.name));
|
|
1761
|
+
}
|
|
1762
|
+
});
|
|
1763
|
+
}
|
|
1764
|
+
console.log('✅ Multi-axis plane helpers shown - multi-axis translation enabled');
|
|
1765
|
+
}
|
|
1766
|
+
}]);
|
|
1767
|
+
}();
|
|
1768
|
+
|
|
1769
|
+
/**
|
|
1770
|
+
* Utility function to create a transform controls manager
|
|
1771
|
+
* @param {THREE.Scene} scene - The Three.js scene
|
|
1772
|
+
* @param {THREE.Camera} camera - The camera
|
|
1773
|
+
* @param {THREE.WebGLRenderer} renderer - The renderer
|
|
1774
|
+
* @param {OrbitControls} orbitControls - Optional orbit controls to disable during transformation
|
|
1775
|
+
* @returns {TransformControlsManager} Transform controls manager instance
|
|
1776
|
+
*/
|
|
1777
|
+
function createTransformControls(scene, camera, renderer) {
|
|
1778
|
+
var orbitControls = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : null;
|
|
1779
|
+
return new TransformControlsManager(scene, camera, renderer, orbitControls);
|
|
1780
|
+
}
|
|
1781
|
+
|
|
1782
|
+
export { TransformControlsManager, createTransformControls };
|