From 91961ec2162c3b9e1313c59ecfb10a2410460fbc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=B2=20P=2E?= Date: Sun, 11 Jan 2026 22:27:27 +0100 Subject: [PATCH] Fix clipping state bug (partial) --- js/scene.js | 64 +++++++++++++++++++++++++++++------------------------ js/state.js | 7 +++++- 2 files changed, 41 insertions(+), 30 deletions(-) diff --git a/js/scene.js b/js/scene.js index 1b0dd4d..94c1379 100644 --- a/js/scene.js +++ b/js/scene.js @@ -30,12 +30,13 @@ Scene.UI.toggleClipper = function(triggerSelector, targetSelector) { trigger.addEventListener( 'click', () => { - console.log('Clipping enabled?', AppState.clipping.enabled); - toolbar.classList.toggle('d-none'); const aoCurrentState = AppState.ambientOcclusion; if (!AppState.clipping.enabled) { AppState.clipping.enabled = true; + + if (AppState.clipping.controls) AppState.clipping.controls.enabled = true; + Scene.toggleAmbientOcclusion(false); const btns = toolbar.querySelectorAll('button'); @@ -58,7 +59,7 @@ Scene.UI.toggleClipper = function(triggerSelector, targetSelector) { }); } else if (event.target.id === 'clipY') { - // Clip along Y... + // Clip along Y Scene.addClippingPlane('y', -1); event.target.classList.add('border', 'border-2', 'border-warning'); btns.forEach(btn => { @@ -68,7 +69,7 @@ Scene.UI.toggleClipper = function(triggerSelector, targetSelector) { }) } else if (event.target.id === 'clipZ') { - // Clip along Z... + // Clip along Z Scene.addClippingPlane('z', 1); event.target.classList.add('border', 'border-2', 'border-warning'); btns.forEach(btn => { @@ -81,8 +82,15 @@ Scene.UI.toggleClipper = function(triggerSelector, targetSelector) { } else { AppState.clipping.enabled = false; ATON.disableClipPlanes(); + // Disable DragControls to avoid invoking events... + if (AppState.clipping.controls) { + AppState.clipping.controls.deactivate(); + AppState.clipping.controls.dispose(); + AppState.clipping.controls = null; + } AppState.root.remove(AppState.clipping.helper); AppState.clipping.helper = null; + AppState.clipping.plane = null; let noBorder = trigger.className.replace(/ border.*$/g, ''); trigger.className = noBorder; Scene.toggleAmbientOcclusion(aoCurrentState); @@ -140,12 +148,11 @@ Scene.getRootBoundingBox = function() { /** * - * @param {THREE.Vector3} rootBBoxSize - The size of the bounding box for the root object + * @param {THREE.Sphere} boundingSphere - The bounding sphere for the main node * @returns {THREE.Mesh} */ -Scene.createClippingPlaneMesh = function(rootBBoxSize) { - //const averageDim = (Number(rootBBoxSize.x) + Number(rootBBoxSize.y) + Number(rootBBoxSize.z)) / 3; - const planeSize = rootBBoxSize.length() * 1.2; +Scene.createClippingPlaneMesh = function (boundingSphere) { + const planeSize = boundingSphere.radius * 1.5; const mesh = new THREE.Mesh( new THREE.PlaneGeometry(planeSize, planeSize), new THREE.MeshBasicMaterial({ color: 0xffff00, opacity: 0.1, side: THREE.DoubleSide, transparent: true }) @@ -175,17 +182,19 @@ Scene.dragClipper = function(planeMesh, axis) { ATON.Nav.setUserControl(false); }); - const bboxData = AppState.clipping.rootBoundingBox ?? this.getRootBoundingBox(); - controls.addEventListener('drag', function (event) { + controls.addEventListener('drag', function(event) { const point = event.object.position; - Scene.updateClipper(AppState.clipping.vector, point, bboxData); + Scene.updateClipper(AppState.clipping.vector, point); for (const a of excludedAxes) { event.object.position[a] = startPosition[a]; } }); + controls.addEventListener('dragend', function (event) { ATON.Nav.setUserControl(true); }); + + AppState.clipping.controls = controls; } /** @@ -195,9 +204,9 @@ Scene.dragClipper = function(planeMesh, axis) { */ Scene.addClippingPlane = function(axis, orientation = -1) { axis = axis.toLowerCase(); - const bboxData = AppState.clipping.rootBoundingBox ?? this.getRootBoundingBox(); + const bound = AppState.clipping.boundingSphere; - if (!bboxData) return; + if (!bound) return; const vector = [ axis === 'x' ? orientation : 0, @@ -209,7 +218,7 @@ Scene.addClippingPlane = function(axis, orientation = -1) { // First, add a default clipping plane // at a default point (calculated...) - const defaultPoint = bboxData.center.clone(); + const defaultPoint = bound.center.clone(); Scene.activateClipper(vector, axis, defaultPoint); } @@ -221,32 +230,22 @@ Scene.addClippingPlane = function(axis, orientation = -1) { * @param {?THREE.Vector3} point - The queried scene point */ Scene.activateClipper = function(vector, axis, point = null) { - point ??= ATON.getSceneQueriedPoint(); - const bboxData = AppState.clipping.rootBoundingBox ?? this.getRootBoundingBox(); - - if (point) { - Scene.updateClipper(vector, point, bboxData); - Scene.dragClipper(AppState.clipping.helper, axis); - } + Scene.updateClipper(vector, point); + Scene.dragClipper(AppState.clipping.helper, axis); } /** * * @param {THREE.Vector3} vector * @param {THREE.Vector3} point - * @param {Object} bboxData */ -Scene.updateClipper = function(vector, point, bboxData) { - // First remove any existing clipping planes - ATON.disableClipPlanes(); +Scene.updateClipper = function(vector, point) { // Normal of the clipping plane along the Y axis facing down const normal = new THREE.Vector3(...vector).normalize(); - //const constant = -normal.dot(point); - const plane = ATON.addClipPlane(normal, point); + const plane = AppState.clipping.plane ?? ATON.addClipPlane(normal, point); // Add a visible plane helper for the clipping plane - const visiblePlane = AppState.clipping.helper ?? Scene.createClippingPlaneMesh(bboxData.size); + const visiblePlane = AppState.clipping.helper ?? Scene.createClippingPlaneMesh(AppState.clipping.boundingSphere); - // Remove any already visbile helper plane if (!AppState.clipping.helper) { AppState.root.add(visiblePlane); AppState.clipping.helper = visiblePlane; @@ -254,6 +253,9 @@ Scene.updateClipper = function(vector, point, bboxData) { visiblePlane.position.copy(point); visiblePlane.lookAt(point.clone().add(normal)); + + plane.setFromNormalAndCoplanarPoint(normal, point); + AppState.clipping.plane = plane; } /** @@ -482,6 +484,8 @@ Scene.openScene = function(marker) { setSceneStatus(marker.id, true); // Load 3D model let mainNode = ATON.createSceneNode(marker.label).load(marker.model); + // TODO: only for the main ('larger') node in the scene + AppState.mainNodeId = marker.label; ATON.setMainPanorama(marker.pano); //mainNode.setMaterial(new THREE.MeshPhongMaterial(material)); // TODO: hardcoded... @@ -497,6 +501,8 @@ Scene.openScene = function(marker) { AppState.ambientOcclusion = true; AppState.root = ATON.getRootScene(); + // ATON.Node.getBound() returns a THREE.Sphere object + AppState.clipping.boundingSphere = mainNode.getBound(); // TODO: set the scene as current!! setCurrentScene(marker.id); diff --git a/js/state.js b/js/state.js index e098330..6f681d7 100644 --- a/js/state.js +++ b/js/state.js @@ -1,6 +1,7 @@ export const AppState = { // The root scene object root: null, + mainNodeId: null, initialRotation: null, camera: ATON.Nav._camera, renderer: ATON._renderer, @@ -11,8 +12,12 @@ export const AppState = { map : null, clipping : { enabled: false, + plane : null, + controls: null, + onDrag: null, helper : null, - rootBoundingBox: null, + // Change to boundingSphere + boundingSphere: null, listeners: { button: false, plane: false,