diff --git a/web/app/cad/craft/datum/datumObject.js b/web/app/cad/craft/datum/datumObject.js index e616cf4b..aa301828 100644 --- a/web/app/cad/craft/datum/datumObject.js +++ b/web/app/cad/craft/datum/datumObject.js @@ -3,7 +3,6 @@ import {Geometry, Line, LineBasicMaterial, MeshBasicMaterial, Object3D, Vector3} import CSysObject3D from './csysObject'; import {NOOP} from 'gems/func'; -import {findAncestor} from '../../../../../modules/scene/sceneGraph'; export default class DatumObject3D extends Object3D { @@ -32,6 +31,7 @@ export default class DatumObject3D extends Object3D { this.add(this.csysObj); this.exitEditMode = NOOP; this.beingDraggedAxis = null; + this.freezeDragging = false; } setMoveMode(axis) { @@ -136,6 +136,9 @@ export default class DatumObject3D extends Object3D { function addOnHoverBehaviour(handle, viewer) { handle.onMouseDown = function(e, hits, startDrag) { let datum = this.parent.parent.parent; + if (datum.freezeDraggin) { + return; + } startDrag(datum); datum.dragStart(e, this.parent); }; diff --git a/web/app/cad/craft/datum/move/moveDatumOpSchema.js b/web/app/cad/craft/datum/move/moveDatumOpSchema.js index 6b212ee8..87205ddd 100644 --- a/web/app/cad/craft/datum/move/moveDatumOpSchema.js +++ b/web/app/cad/craft/datum/move/moveDatumOpSchema.js @@ -1,6 +1,7 @@ export default { datum: { - type: 'datum' + type: 'datum', + defaultValue: {type: 'selection'} }, x: { type: 'number', diff --git a/web/app/cad/craft/datum/move/moveDatumOperation.js b/web/app/cad/craft/datum/move/moveDatumOperation.js index 188268c4..a0500bc3 100644 --- a/web/app/cad/craft/datum/move/moveDatumOperation.js +++ b/web/app/cad/craft/datum/move/moveDatumOperation.js @@ -51,12 +51,8 @@ function previewer(ctx, initialParams, updateParams) { function dispose() { datum3D.csys.copy(mDatum.csys); datum3D.finishOperation(); - datum3D.operationStarted = false; - datum3D.exitEditMode(); - datum3D.applyMove = NOOP; } - update(initialParams); return { diff --git a/web/app/cad/craft/datum/rotate/RotateDatumWizard.jsx b/web/app/cad/craft/datum/rotate/RotateDatumWizard.jsx new file mode 100644 index 00000000..3052f090 --- /dev/null +++ b/web/app/cad/craft/datum/rotate/RotateDatumWizard.jsx @@ -0,0 +1,15 @@ +import React from 'react'; +import {Group} from '../../wizard/components/form/Form'; +import {NumberField, RadioButtonsField} from '../../wizard/components/form/Fields'; +import {RadioButton} from 'ui/components/controls/RadioButtons'; + +export default function RotateDatumWizard() { + return + + + + + + + ; +} \ No newline at end of file diff --git a/web/app/cad/craft/datum/rotate/rotateDatumOpSchema.js b/web/app/cad/craft/datum/rotate/rotateDatumOpSchema.js new file mode 100644 index 00000000..ed531811 --- /dev/null +++ b/web/app/cad/craft/datum/rotate/rotateDatumOpSchema.js @@ -0,0 +1,15 @@ +export default { + datum: { + type: 'datum', + defaultValue: {type: 'selection'} + }, + axis: { + type: 'enum', + values: ['X', 'Y', 'Z'], + defaultValue: 'X' + }, + angle: { + type: 'number', + defaultValue: 0 + } +} \ No newline at end of file diff --git a/web/app/cad/craft/datum/rotate/rotateDatumOperation.js b/web/app/cad/craft/datum/rotate/rotateDatumOperation.js new file mode 100644 index 00000000..fdb0b164 --- /dev/null +++ b/web/app/cad/craft/datum/rotate/rotateDatumOperation.js @@ -0,0 +1,79 @@ +import schema from './rotateDatumOpSchema'; +import {MDatum} from '../../../model/mdatum'; +import RotateDatumWizard from './RotateDatumWizard'; +import {Matrix3, ORIGIN} from '../../../../math/l3space'; +import {DEG_RAD} from '../../../../math/math'; + + +function rotate(params, {cadRegistry}) { + + let mDatum = cadRegistry.findDatum(params.datum); + + let axis = mDatum.csys[params.axis.toLowerCase()]; + + let csys = mDatum.csys.clone(); + + applyRotation(mDatum.csys, csys, params.angle, axis); + + return { + outdated: [mDatum], + created: [new MDatum(csys)] + } +} + +let auxMatrix = new Matrix3(); + +function previewer(ctx, initialParams) { + + let mDatum = ctx.services.cadRegistry.findDatum(initialParams.datum); + + if (!mDatum) { + return null; + } + let view = mDatum.ext.view; + if (!view) { + return null; + } + + let datum3D = view.rootGroup; + datum3D.beginOperation(true); + + function update(params) { + let axis = mDatum.csys[params.axis.toLowerCase()]; + applyRotation(mDatum.csys, datum3D.csys, params.angle, axis); + } + + function dispose() { + datum3D.csys.copy(mDatum.csys); + datum3D.finishOperation(); + } + + + update(initialParams); + + return { + update, dispose + } +} + +function applyRotation(origCsys, csys, angle, axis) { + auxMatrix.rotate(angle * DEG_RAD, axis, ORIGIN); + auxMatrix.__apply(origCsys.x, csys.x); + auxMatrix.__apply(origCsys.y, csys.y); + auxMatrix.__apply(origCsys.z, csys.z); +} + +export default { + id: 'DATUM_ROTATE', + label: 'Rotate Datum', + icon: 'img/cad/plane', + info: 'rotates a datum', + paramsInfo: ({axis, angle}) => `${axis} - ${angle}`, + previewer, + run: rotate, + form: RotateDatumWizard, + schema +}; + + + diff --git a/web/app/cad/part/menuConfig.js b/web/app/cad/part/menuConfig.js index 6ba4f466..9cf10aa7 100644 --- a/web/app/cad/part/menuConfig.js +++ b/web/app/cad/part/menuConfig.js @@ -43,7 +43,7 @@ export default [ label: 'datum', cssIcons: ['magic'], info: 'operations on datum', - actions: ['DATUM_MOVE'] + actions: ['DATUM_ROTATE', 'DATUM_MOVE'] // actions: ['DATUM_MOVE', 'DATUM_ROTATE', 'DATUM_REBASE', '-', 'PLANE_FROM_DATUM', 'BOX', 'SPHERE', 'TORUS', // 'CONE', 'CYLINDER'] }, diff --git a/web/app/cad/part/partOperationsPlugin.js b/web/app/cad/part/partOperationsPlugin.js index cb6e6e4b..d6ee32dc 100644 --- a/web/app/cad/part/partOperationsPlugin.js +++ b/web/app/cad/part/partOperationsPlugin.js @@ -6,6 +6,7 @@ import filletOperation from '../craft/fillet/filletOperation'; import revolveOperation from '../craft/revolve/revolveOperation'; import createDatumOperation from '../craft/datum/create/createDatumOperation'; import moveDatumOperation from '../craft/datum/move/moveDatumOperation'; +import rotateDatumOperation from '../craft/datum/rotate/rotateDatumOperation'; export function activate({services}) { services.operation.registerOperations([ @@ -16,6 +17,7 @@ export function activate({services}) { revolveOperation, filletOperation, createDatumOperation, - moveDatumOperation + moveDatumOperation, + rotateDatumOperation ]) } \ No newline at end of file diff --git a/web/app/cad/scene/controls/pickControlPlugin.js b/web/app/cad/scene/controls/pickControlPlugin.js index 33c5540e..a840c2ee 100644 --- a/web/app/cad/scene/controls/pickControlPlugin.js +++ b/web/app/cad/scene/controls/pickControlPlugin.js @@ -1,6 +1,6 @@ import * as mask from 'gems/mask' import {getAttribute, setAttribute} from 'scene/objectData'; -import {FACE, EDGE, SKETCH_OBJECT} from '../entites'; +import {FACE, EDGE, SKETCH_OBJECT, DATUM} from '../entites'; import {state} from 'lstream'; export const PICK_KIND = { @@ -9,7 +9,7 @@ export const PICK_KIND = { EDGE: mask.type(3) }; -const SELECTABLE_ENTITIES = [FACE, EDGE, SKETCH_OBJECT]; +const SELECTABLE_ENTITIES = [FACE, EDGE, SKETCH_OBJECT, DATUM]; export function activate(context) { const {services, streams} = context; @@ -130,10 +130,8 @@ export function defineStreams({streams}) { streams.selection = { }; SELECTABLE_ENTITIES.forEach(entity => { - let selectionState = state([]); streams.selection[entity] = state([]); }); - } function initStateAndServices({streams, services}) { diff --git a/web/app/cad/scene/viewSyncPlugin.js b/web/app/cad/scene/viewSyncPlugin.js index 7c53cd0a..e292f17f 100644 --- a/web/app/cad/scene/viewSyncPlugin.js +++ b/web/app/cad/scene/viewSyncPlugin.js @@ -16,7 +16,7 @@ export function activate(context) { streams.sketcher.update.attach(mFace => mFace.ext.view.updateSketch()); } -function sceneSynchronizer({services: {cadScene, cadRegistry, viewer, wizard, action}}) { +function sceneSynchronizer({services: {cadScene, cadRegistry, viewer, wizard, action, selection}}) { return function() { let wgChildren = cadScene.workGroup.children; let existent = new Set(); @@ -42,7 +42,10 @@ function sceneSynchronizer({services: {cadScene, cadRegistry, viewer, wizard, ac } else if (model instanceof MShell) { modelView = new ShellView(model); } else if (model instanceof MDatum) { - modelView = new DatumView(model, viewer, wizard.open, (e) => action.run('menu.datum', e)); + modelView = new DatumView(model, viewer, + wizard.open, + datumId => selection.datum.select([datumId]), + e => action.run('menu.datum', e)); } else { console.warn('unsupported model ' + model); } diff --git a/web/app/cad/scene/views/datumView.js b/web/app/cad/scene/views/datumView.js index ec1aeaaa..64b3ff0d 100644 --- a/web/app/cad/scene/views/datumView.js +++ b/web/app/cad/scene/views/datumView.js @@ -4,10 +4,11 @@ import {DATUM} from '../entites'; import {setAttribute} from 'scene/objectData'; import {Mesh, MeshBasicMaterial, PolyhedronGeometry, SphereGeometry} from 'three'; import {CSYS_SIZE_MODEL} from '../../craft/datum/csysObject'; +import {NOOP} from '../../../../../modules/gems/func'; export default class DatumView extends View { - constructor(datum, viewer, beginOperation, showDatumMenu) { + constructor(datum, viewer, beginOperation, selectDatum, showDatumMenu) { super(datum); class MenuButton extends Mesh { @@ -54,6 +55,7 @@ export default class DatumView extends View { } onMouseClick(e) { + selectDatum(datum.id); showDatumMenu({ x: e.offsetX, y: e.offsetY @@ -101,23 +103,24 @@ export default class DatumView extends View { dragStart(e, axis) { if (!this.operationStarted) { - beginOperation('DATUM_MOVE', { - datum: datum.id - }); + selectDatum(datum.id); + beginOperation('DATUM_MOVE'); this.beginOperation(); } super.dragStart(e, axis); } - beginOperation() { + beginOperation(freezeDragging = false) { + this.freezeDragging = freezeDragging; this.operationStarted = true; this.menuButton.updateVisibility(); } finishOperation() { + this.freezeDragging = false; this.operationStarted = false; + this.exitEditMode(); this.menuButton.updateVisibility(); - this.exitEditMode(); } dispose() { diff --git a/web/app/math/l3space.js b/web/app/math/l3space.js index a01c426f..c716807e 100644 --- a/web/app/math/l3space.js +++ b/web/app/math/l3space.js @@ -39,6 +39,13 @@ Matrix3.prototype.setBasis = function(basis) { return this; }; +Matrix3.prototype.setBasisAxises = function(x, y, z) { + this.mxx = x.x; this.mxy = y.x; this.mxz = z.x; this.tx = 0; + this.myx = x.y; this.myy = y.y; this.myz = z.y; this.ty = 0; + this.mzx = x.z; this.mzy = y.z; this.mzz = z.z; this.tz = 0; + return this; +}; + Matrix3.prototype.scale = function(dx, dy, dz) { this.mxx *= dx; this.myy *= dy; @@ -143,7 +150,7 @@ Matrix3.prototype.__invert = function(out) { return out; }; -Matrix3.prototype.combine = function(transform) { +Matrix3.prototype.combine = function(transform, out) { var txx = transform.mxx; var txy = transform.mxy; var txz = transform.mxz; @@ -157,7 +164,7 @@ Matrix3.prototype.combine = function(transform) { var tzz = transform.mzz; var ttz = transform.tz; - var m = new Matrix3(); + var m = out || new Matrix3(); m.mxx = (this.mxx * txx + this.mxy * tyx + this.mxz * tzx); m.mxy = (this.mxx * txy + this.mxy * tyy + this.mxz * tzy); m.mxz = (this.mxx * txz + this.mxy * tyz + this.mxz * tzz); @@ -207,11 +214,15 @@ Matrix3.prototype.__apply3 = function([x, y, z], out) { return out; }; -Matrix3.rotateMatrix = function(angle, axis, pivot) { +Matrix3.prototype.rotate = function(angle, axis, pivot) { + return Matrix3.rotateMatrix(angle, axis, pivot, this); +}; + +Matrix3.rotateMatrix = function(angle, axis, pivot, matrix) { var sin = Math.sin(angle); var cos = Math.cos(angle); var axisX, axisY, axisZ; - var m = new Matrix3(); + var m = matrix || new Matrix3(); if (axis === AXIS.X || axis === AXIS.Y || axis === AXIS.Z) { axisX = axis.x; diff --git a/web/app/math/math.js b/web/app/math/math.js index f8c54052..199c076c 100644 --- a/web/app/math/math.js +++ b/web/app/math/math.js @@ -245,4 +245,6 @@ export function perpendicularVector(v) { .sort((a, b) => vec.lengthSq(b) - vec.lengthSq(a))[0]; } +export const DEG_RAD = Math.PI / 180.0; + export const sq = (a) => a * a;