mirror of
https://github.com/gittrahan/support-fins.git
synced 2026-10-22 03:42:40 -05:00
section view: review fixes -- a tap on the plane's handle no longer falls through to a pick (the handle clears its axis on release before app.js reads it, so the press is remembered); Move shows one arrow along the cut's normal; the cut turns and reseats with the part
This commit is contained in:
1 parent
736cf9e5d1
commit
1a2b3effbf
3 files changed
+40
-5
No files matched your search
+5
-1
@@ -68,6 +68,7 @@ addEventListener('keydown', (e) => {
|
||||
// One set of viewport listeners, routed by mode: remove, then draw, then lay flat.
|
||||
|
||||
let pressAt = null;
|
||||
let pressOnPlane = false; // the press landed on the section plane's handle
|
||||
renderer.domElement.addEventListener('pointermove', (ev) => {
|
||||
// The section plane's handle is under the pointer or being dragged: it owns the
|
||||
// pointer, and no pick should light up through it.
|
||||
@@ -109,6 +110,9 @@ renderer.domElement.addEventListener('pointerleave', () => {
|
||||
|
||||
renderer.domElement.addEventListener('pointerdown', (e) => {
|
||||
pressAt = { x: e.clientX, y: e.clientY };
|
||||
// Read at the press: the plane's TransformControls listens first, so it has set
|
||||
// its axis by now -- and on release it clears it before this module's pointerup.
|
||||
pressOnPlane = planeBusy();
|
||||
});
|
||||
|
||||
renderer.domElement.addEventListener('pointerup', (e) => {
|
||||
@@ -119,7 +123,7 @@ renderer.domElement.addEventListener('pointerup', (e) => {
|
||||
// a drag is an orbit, not a pick
|
||||
if (Math.hypot(e.clientX - from.x, e.clientY - from.y) > 4) return;
|
||||
// a click on the section plane's handle is the handle's, not a pick
|
||||
if (planeBusy()) return;
|
||||
if (pressOnPlane) return;
|
||||
|
||||
// A right CLICK cancels; a right DRAG is an orbit or pan (the Onshape preset
|
||||
// orbits on it) and leaves the wall in progress alone. Decided here, on release,
|
||||
|
||||
+2
-1
@@ -8,7 +8,7 @@ import * as THREE from 'three';
|
||||
import { buildTopology, analyze, DEFAULT_THRESHOLD, MIN_REGION_AREA } from '../overhangs.js';
|
||||
import { el } from './dom.js';
|
||||
import { scene, controls, frame, clip } from './scene.js';
|
||||
import { setSection } from './section.js';
|
||||
import { setSection, followPart } from './section.js';
|
||||
import { removeMode, cancelRemove, resetRemovals } from './remove.js';
|
||||
import { resetHistory } from './history.js';
|
||||
import { importNote, renderImportNote } from './io.js';
|
||||
@@ -271,6 +271,7 @@ export function shade() {
|
||||
updateLayerView(size);
|
||||
updateLoadReadout();
|
||||
syncLoadUI(); // re-light the pad button for the load's new world direction
|
||||
followPart(); // a section cut turns and reseats with the part
|
||||
return size;
|
||||
}
|
||||
|
||||
|
||||
+33
-3
@@ -8,8 +8,10 @@
|
||||
* array, and switching the section on puts `plane` in it. Picks skip what the cut
|
||||
* hides (keptHit), so a click lands on the surface you can see, not the one cut away.
|
||||
*
|
||||
* `plane` is in WORLD space and stays put while the part turns. Its normal points
|
||||
* at the side that is KEPT (three.js discards where the signed distance is < 0).
|
||||
* `plane` is in world space, but the cut is held in the PART's frame (followPart):
|
||||
* turn the part and the cut turns with it, so it stays on the bore it was opening.
|
||||
* Its normal points at the side that is KEPT (three.js discards where the signed
|
||||
* distance is < 0).
|
||||
*/
|
||||
import * as THREE from 'three';
|
||||
import { TransformControls } from 'three/addons/controls/TransformControls.js';
|
||||
@@ -40,11 +42,14 @@ scene.add(handle);
|
||||
|
||||
export const planeGizmo = new TransformControls(camera, renderer.domElement);
|
||||
planeGizmo.setSize(0.7);
|
||||
// Local space: Move's one arrow slides the cut along its own normal, straight
|
||||
// through the part, whatever way it has been turned.
|
||||
planeGizmo.setSpace('local');
|
||||
planeGizmo.attach(handle);
|
||||
const planeHelper = planeGizmo.getHelper ? planeGizmo.getHelper() : planeGizmo;
|
||||
scene.add(planeHelper);
|
||||
planeGizmo.addEventListener('dragging-changed', (e) => { controls.enabled = !e.value; });
|
||||
planeGizmo.addEventListener('objectChange', syncPlane);
|
||||
planeGizmo.addEventListener('objectChange', () => { syncPlane(); holdInPart(); });
|
||||
// Same 5 degree snap as the part's rings; Shift frees it.
|
||||
const SNAP = THREE.MathUtils.degToRad(5);
|
||||
planeGizmo.setRotationSnap(SNAP);
|
||||
@@ -59,6 +64,27 @@ function syncPlane() {
|
||||
plane.setFromNormalAndCoplanarPoint(nrm, handle.position);
|
||||
}
|
||||
|
||||
// The handle's pose in the part's frame, so the cut follows the part when it turns.
|
||||
const inPart = new THREE.Matrix4();
|
||||
const m4 = new THREE.Matrix4();
|
||||
|
||||
/** Remember where the handle sits on the part (after the user or a button moved it). */
|
||||
function holdInPart() {
|
||||
if (!part) return;
|
||||
part.updateMatrixWorld();
|
||||
handle.updateMatrix();
|
||||
inPart.copy(part.matrixWorld).invert().multiply(handle.matrix);
|
||||
}
|
||||
|
||||
/** The part turned or reseated (part.js shade): carry the cut along with it. */
|
||||
export function followPart() {
|
||||
if (!sectionOn || !part || planeGizmo.dragging) return;
|
||||
part.updateMatrixWorld();
|
||||
m4.multiplyMatrices(part.matrixWorld, inPart);
|
||||
m4.decompose(handle.position, handle.quaternion, handle.scale);
|
||||
syncPlane();
|
||||
}
|
||||
|
||||
/** The part's world-space box: where the plane starts and how big it draws. */
|
||||
function partBox() {
|
||||
return new THREE.Box3().setFromObject(part);
|
||||
@@ -76,6 +102,7 @@ function placeThroughCentre(n) {
|
||||
partBox().getCenter(handle.position);
|
||||
handle.quaternion.setFromUnitVectors(new THREE.Vector3(0, 0, 1), n.clone().normalize());
|
||||
syncPlane();
|
||||
holdInPart();
|
||||
}
|
||||
|
||||
/** The first hit the cut leaves visible (hits come sorted nearest first). */
|
||||
@@ -94,6 +121,8 @@ function syncGizmo() {
|
||||
planeGizmo.enabled = on;
|
||||
if (!on) planeGizmo.axis = null;
|
||||
if (handleMode) planeGizmo.setMode(handleMode);
|
||||
// Move shows only the normal arrow: sliding the cut within its own plane does nothing.
|
||||
planeGizmo.showX = planeGizmo.showY = handleMode !== 'translate';
|
||||
planeHelper.visible = on;
|
||||
handle.visible = sectionOn;
|
||||
}
|
||||
@@ -143,6 +172,7 @@ for (const [id, mode] of [['section-move', 'translate'], ['section-turn', 'rotat
|
||||
el('section-flip').addEventListener('click', () => {
|
||||
handle.rotateX(Math.PI);
|
||||
syncPlane();
|
||||
holdInPart();
|
||||
});
|
||||
|
||||
const AXES = { x: new THREE.Vector3(1, 0, 0), y: new THREE.Vector3(0, 1, 0),
|
||||
|
||||
Reference in new issue
Block a user