jsketcher/web/app/cad/craft/datum/datumObject.js
2022-08-15 23:47:20 -07:00

183 lines
No EOL
4.8 KiB
JavaScript

import {BufferGeometry, Line, LineBasicMaterial, MeshBasicMaterial, Object3D, Vector3} from 'three';
import CSysObject3D from './csysObject';
import {NOOP} from 'gems/func';
import {createExpensiveSetter, createReactiveState} from 'scene/utils/stateUpdater';
export default class DatumObject3D extends Object3D {
static AXIS = {
X: 1,
Y: 2,
Z: 3,
};
constructor(csys, viewer) {
super();
this.viewer = viewer;
this.csys = csys.clone();
this.csysObj = new CSysObject3D(this.csys, this.viewer.sceneSetup, {
createHandle: true,
handleMaterial: () => new MeshBasicMaterial({
transparent: true,
opacity: 0.5,
color: 0xAA8439,
visible: false
})
});
addOnHoverBehaviour(this.csysObj.xAxis.handle, this.viewer);
addOnHoverBehaviour(this.csysObj.yAxis.handle, this.viewer);
addOnHoverBehaviour(this.csysObj.zAxis.handle, this.viewer);
this.add(this.csysObj);
this.exitEditMode = NOOP;
this.beingDraggedAxis = null;
this.freezeDragging = false;
}
setMoveMode(axis) {
this.exitEditMode();
let dir, color;
if (axis === DatumObject3D.AXIS.X) {
dir = this.csys.x;
color = 0xff0000;
} else if (axis === DatumObject3D.AXIS.Y) {
dir = this.csys.y;
color = 0x00ff00;
} else if (axis === DatumObject3D.AXIS.Z) {
dir = this.csys.z;
color = 0x0000ff;
} else {
return;
}
this.beingDraggedAxis = dir;
const ext = dir.multiply(this.viewer.sceneSetup.workingSphere);
const material = new LineBasicMaterial({color});
const geometry = new BufferGeometry().setFromPoints( [
new Vector3().copy(this.csys.origin.minus(ext)),
new Vector3().copy(this.csys.origin.plus(ext))
]);
const line = new Line(geometry, material);
this.add(line);
this.exitEditMode = () => {
this.beingDraggedAxis = null;
this.remove(line);
geometry.dispose();
material.dispose();
this.exitEditMode = NOOP;
}
}
dragStart(e, axis) {
this.dragInfo = {
csysOrigin: this.csys.origin.copy(),
originViewCoord: this.viewer.sceneSetup.modelToScreen(this.csys.origin),
startX: e.offsetX,
startY: e.offsetY,
};
switch (axis) {
case this.csysObj.xAxis:
this.setMoveMode(DatumObject3D.AXIS.X);
break;
case this.csysObj.yAxis:
this.setMoveMode(DatumObject3D.AXIS.Y);
break;
case this.csysObj.zAxis:
default:
this.setMoveMode(DatumObject3D.AXIS.Z);
break;
}
}
dragMove({mouseEvent: e}) {
if (this.beingDraggedAxis) {
const dir = this.beingDraggedAxis;
const traveledX = e.offsetX - this.dragInfo.startX;
const traveledY = e.offsetY - this.dragInfo.startY;
const raycaster = this.viewer.sceneSetup.createRaycaster(this.dragInfo.originViewCoord.x + traveledX, this.dragInfo.originViewCoord.y + traveledY);
this.csys.origin.setV(this.dragInfo.csysOrigin);
//see nurbs-ext - rays intersection
const zRef = dir.cross(raycaster.ray.direction);
const n2 = zRef.cross(raycaster.ray.direction)._normalize();
const u = n2.dot(this.csys.origin.minus(raycaster.ray.origin)._negate()) / n2.dot(dir);
const delta = dir.multiply(u);
this.csys.origin._plus(delta);
if (e.shiftKey) {
roundVector(this.csys.origin);
}
this.viewer.requestRender();
this.onMove(this.dragInfo.csysOrigin, this.csys.origin, delta);
}
}
onMove(begin, end, delta) {
}
dragDrop() {
this.exitEditMode();
this.viewer.requestRender();
}
dispose() {
this.exitEditMode();
this.csysObj.dispose();
}
}
function addOnHoverBehaviour(handle, viewer) {
handle.onMouseDown = function(e) {
const datum = this.parent.parent.parent;
if (datum.freezeDragging) {
return;
}
e.startDrag(datum);
datum.dragStart(e.mouseEvent, this.parent);
};
const defaultColor = handle.material.color.getHex();
const setColor = createExpensiveSetter(color => handle.material.color.setHex(color));
const handleState = createReactiveState({
selected: null,
visible: true
},
state => {
if (state.selected !== null) {
handle.material.visible = true;
setColor(state.selected);
} else {
setColor(defaultColor);
handle.material.visible = state.hovered;
}
viewer.requestRender();
});
handle.onMouseEnter = function() {
handleState('hovered', true);
};
handle.onMouseLeave = function() {
handleState('hovered', false);
};
handle.setSelected = value => handleState('selected', value);
}
function roundVector(v) {
v.x = Math.round(v.x);
v.y = Math.round(v.y);
v.z = Math.round(v.z);
}