From 702d01a62a5d21235e39a6afeecf04b0178543a5 Mon Sep 17 00:00:00 2001 From: Val Erastov Date: Wed, 4 Jan 2017 14:49:27 -0800 Subject: [PATCH] feature request: Allow plane to be created relative to face with offset from face. #17 --- web/app/3d/cad-utils.js | 11 +++------- web/app/3d/solid.js | 28 +++++++++++++++++-------- web/app/3d/ui/ctrl.js | 2 +- web/app/3d/wizards/plane.js | 41 +++++++++++++++++++++++++++++-------- web/app/3d/workbench.js | 12 ++++++++++- 5 files changed, 68 insertions(+), 26 deletions(-) diff --git a/web/app/3d/cad-utils.js b/web/app/3d/cad-utils.js index 81a5b3fa..f56d672f 100644 --- a/web/app/3d/cad-utils.js +++ b/web/app/3d/cad-utils.js @@ -177,18 +177,13 @@ export function createPlane(basis, depth) { var plane = new Solid(CSG.fromPolygons([polygon]), material, 'PLANE'); plane.wireframeGroup.visible = false; plane.mergeable = false; - var _3d = tr.invert(); function setBounds(bbox) { - var corner = new Vector(bbox.minX, bbox.minY, 0); - var size = new Vector(bbox.width(), bbox.height(), 1); - _3d._apply(size); - _3d._apply(corner); - plane.mesh.scale.set(size.x, size.y, size.z); - plane.mesh.position.set(corner.x, corner.y, corner.z); currentBounds = bbox; - var poly = new CSG.Polygon(bbox.toPolygon().map(function(p){return new CSG.Vertex(csgVec( _3d._apply(p) ))}), shared); + const poly = new CSG.Polygon(bbox.toPolygon().map(function(p){p.z = depth; return new CSG.Vertex(csgVec( tr._apply(p) ))}), shared); plane.csg = CSG.fromPolygons([poly]); + plane.dropGeometry(); + plane.createGeometry(); } var bb = new BBox(); bb.checkBounds(-400, -400); diff --git a/web/app/3d/solid.js b/web/app/3d/solid.js index 6fad6319..3b1ee291 100644 --- a/web/app/3d/solid.js +++ b/web/app/3d/solid.js @@ -15,25 +15,37 @@ export function Solid(csg, material, type, id) { this.cadGroup = new THREE.Object3D(); this.cadGroup.__tcad_solid = this; - var geometry = new THREE.Geometry(); - geometry.dynamic = true; - this.mesh = new THREE.Mesh(geometry, material); - this.cadGroup.add(this.mesh); - this.tCadId = Counters.solid ++; this.id = id === undefined ? this.tCadId : id; // to keep identity through the history this.faceCounter = 0; this.wireframeGroup = new THREE.Object3D(); this.cadGroup.add(this.wireframeGroup); + this.mergeable = true; + this.material = material; + this.createGeometry(); +} + +Solid.prototype.createGeometry = function() { + const geometry = new THREE.Geometry(); + geometry.dynamic = true; + this.mesh = new THREE.Mesh(geometry, this.material); + this.cadGroup.add(this.mesh); this.polyFaces = []; this.wires = HashTable.forEdge(); this.curvedSurfaces = {}; - this.mergeable = true; this.setupGeometry(); -} +}; + +Solid.prototype.dropGeometry = function() { + this.cadGroup.remove( this.mesh ); + this.mesh.geometry.dispose(); + for(let i = this.wireframeGroup.children.length-1; i >=0 ; i--){ + this.wireframeGroup.remove(this.wireframeGroup.children[i]); + } +}; function groupCSG(csg) { var csgPolygons = csg.toPolygons(); @@ -101,7 +113,7 @@ Solid.prototype.setupGeometry = function() { Solid.prototype.vanish = function() { this.cadGroup.parent.remove( this.cadGroup ); - this.mesh.material.dispose(); + this.material.dispose(); this.mesh.geometry.dispose(); }; diff --git a/web/app/3d/ui/ctrl.js b/web/app/3d/ui/ctrl.js index e65a0ceb..02cb4b72 100644 --- a/web/app/3d/ui/ctrl.js +++ b/web/app/3d/ui/ctrl.js @@ -173,7 +173,7 @@ UI.prototype.createWizard = function(type, overridingHistory, initParams, face) } else if ('REVOLVE' === type) { wizard = new RevolveWizard(this.app, face, initParams); } else if ('PLANE' === type) { - wizard = new PlaneWizard(this.app.viewer, initParams); + wizard = new PlaneWizard(this.app, initParams); } else if ('BOX' === type) { wizard = new BoxWizard(this.app.viewer, initParams); } else if ('SPHERE' === type) { diff --git a/web/app/3d/wizards/plane.js b/web/app/3d/wizards/plane.js index 2214965e..cd738c07 100644 --- a/web/app/3d/wizards/plane.js +++ b/web/app/3d/wizards/plane.js @@ -2,23 +2,35 @@ import {AXIS, IDENTITY_BASIS} from '../../math/l3space' import * as tk from '../../ui/toolkit.js' import {FACE_COLOR} from '../cad-utils' import {Wizard} from './wizard-commons' +import {Matrix3} from '../../math/l3space' -export function PlaneWizard(viewer, initParams) { - Wizard.call(this, viewer, initParams); +export function PlaneWizard(app, initParams) { + Wizard.call(this, app.viewer, initParams); + this.app = app; this.previewGroup = new THREE.Object3D(); this.viewer.scene.add(this.previewGroup); this.previewGroup.add(this.plane = this.createPlane()); this.operationParams = { basis : IDENTITY_BASIS, - depth : 0 + depth : 0, + relativeToFaceId: '' }; + this.selectionListener = () => { + const face = this.app.viewer.selectionMgr.selection[0]; + if (face) { + this.ui.relativeToFace.input.val(face.id); + this.synch(); + } + }; + app.bus.subscribe('selection', this.selectionListener); + this.focus = () => this.ui.depth.input.focus(); this.synch(); } PlaneWizard.prototype = Object.create( Wizard.prototype ); -PlaneWizard.prototype.DEFAULT_PARAMS = ['XY', 0]; +PlaneWizard.prototype.DEFAULT_PARAMS = ['XY', 0, '']; PlaneWizard.prototype.title = function() { return "Add a Plane"; @@ -30,8 +42,17 @@ PlaneWizard.prototype.createPlane = function() { return new THREE.Mesh(geometry, material); }; -PlaneWizard.prototype.update = function(orientation, w) { - if (orientation === 'XY') { +PlaneWizard.prototype.update = function(orientation, w, relativeToFaceId) { + if (relativeToFaceId != '') { + const face = this.app.findFace(relativeToFaceId); + const m = new THREE.Matrix4(); + m.makeBasis.apply(m, face.basis()); + const wVec = new THREE.Vector3(0, 0, w + face.depth()); + wVec.applyMatrix4(m); + m.setPosition(wVec); + this.plane.matrix.identity(); + this.plane.applyMatrix(m); + } else if (orientation === 'XY') { this.plane.rotation.x = 0; this.plane.rotation.y = 0; this.plane.rotation.z = 0; @@ -59,16 +80,20 @@ PlaneWizard.prototype.update = function(orientation, w) { throw orientation + " isn't supported yet"; } this.operationParams.depth = w; + this.operationParams.relativeToFaceId = relativeToFaceId; this.viewer.render(); }; -PlaneWizard.prototype.createUI = function(orientation, w) { +PlaneWizard.prototype.createUI = function(orientation, w, relativeToFaceId) { const folder = this.ui.folder; const choice = ['XY', 'XZ', 'ZY']; this.ui.orientation = new tk.InlineRadio(choice, choice, choice.indexOf(orientation)); this.ui.depth = new tk.Number("Depth", w); + this.ui.relativeToFace = new tk.Text("Relative to Face", relativeToFaceId === undefined ? '' : relativeToFaceId); tk.add(folder, this.ui.orientation); + tk.add(folder, this.ui.relativeToFace); tk.add(folder, this.ui.depth); + var onChange = tk.methodRef(this, "synch"); this.ui.orientation.root.find('input:radio').change(onChange); this.ui.depth.input.on('t-change', onChange); @@ -80,7 +105,7 @@ PlaneWizard.prototype.synch = function() { }; PlaneWizard.prototype.getParams = function() { - return [this.ui.orientation.getValue(), this.ui.depth.input.val()] + return [this.ui.orientation.getValue(), parseFloat(this.ui.depth.input.val()), this.ui.relativeToFace.input.val()] }; PlaneWizard.prototype.createRequest = function(done) { diff --git a/web/app/3d/workbench.js b/web/app/3d/workbench.js index 383623e1..b020becf 100644 --- a/web/app/3d/workbench.js +++ b/web/app/3d/workbench.js @@ -902,7 +902,17 @@ export const OPERATIONS = { PAD : extrude, REVOLVE : performRevolve, PLANE : function(app, request) { - return [cad_utils.createPlane(request.params.basis, request.params.depth)]; + let basis, depth = request.params.depth; + const relativeToFaceId = request.params.relativeToFaceId; + if (relativeToFaceId != undefined && relativeToFaceId != '') { + const face = app.findFace(relativeToFaceId); + if (!face) return; + basis = face.basis(); + depth += face.depth(); + } else { + basis = request.params.basis; + } + return [cad_utils.createPlane(basis, depth)]; }, BOX : function(app, request) { var p = request.params;