diff --git a/web/app/3d/actions/core-actions.js b/web/app/3d/actions/core-actions.js index aaa245b2..6ca79073 100644 --- a/web/app/3d/actions/core-actions.js +++ b/web/app/3d/actions/core-actions.js @@ -7,7 +7,7 @@ export const EditFace = { info: 'open sketcher for a face/plane', listens: ['selection'], update: ActionHelpers.checkForSelectedFaces(1), - invoke: (app) => app.sketchSelectedFace() + invoke: (app) => app.editFace() }; export const Save = { diff --git a/web/app/3d/modeler-app.js b/web/app/3d/modeler-app.js index 6c7970e9..be67b4be 100644 --- a/web/app/3d/modeler-app.js +++ b/web/app/3d/modeler-app.js @@ -72,7 +72,7 @@ function App() { } App.prototype.BREPTest = function() { - setTimeout(() => this.BREPTestImpl1()); + setTimeout(() => this.BREPTestImpl()); }; App.prototype.BREPTestImpl1 = function() { @@ -104,7 +104,8 @@ App.prototype.BREPTestImpl = function() { this.viewer.workGroup.add(sceneSolid.cadGroup); }; const box1 = BREPPrimitives.box(500, 500, 500); - const box2 = BREPPrimitives.box(250, 250, 500, new Matrix3().translate(25, 25, 250)); + const box2 = BREPPrimitives.box(250, 250, 750, new Matrix3().translate(25, 25, 0)); + const box3 = BREPPrimitives.box(150, 600, 350, new Matrix3().translate(25, 25, -250)); BREPValidator.validateToConsole(box1); @@ -113,8 +114,10 @@ App.prototype.BREPTestImpl = function() { //addToScene(box1); //addToScene(box2); + //addToScene(box3); - const result = BREPBool.subtract(box1, box2); + let result = BREPBool.subtract(box1, box2); + result = BREPBool.subtract(result, box3); addToScene(result); this.viewer.render() @@ -212,7 +215,7 @@ App.prototype.projectStorageKey = function(polyFaceId) { }; -App.prototype.sketchSelectedFace = function() { +App.prototype.editFace = function() { if (this.viewer.selectionMgr.selection.length == 0) { return; } diff --git a/web/app/3d/selection.js b/web/app/3d/selection.js index 9260a81e..d00e9a55 100644 --- a/web/app/3d/selection.js +++ b/web/app/3d/selection.js @@ -12,9 +12,9 @@ class AbstractSelectionManager { return this.selection.indexOf(face) != -1; } - pick(sketchFace) { - if (!this.contains(sketchFace)) { - this.select(sketchFace); + pick(object) { + if (!this.contains(object)) { + this.select(object); return true; } return false; @@ -77,43 +77,8 @@ export class SelectionManager extends AbstractSelectionManager { this.defaultColor = defaultColor; this.readOnlyColor = readOnlyColor; this.planeSelection = []; - - this.basisGroup = new THREE.Object3D(); - var length = 200; - var arrowLength = length * 0.2; - var arrowHead = arrowLength * 0.4; - - function createArrow(axis, color) { - var arrow = new THREE.ArrowHelper(axis, new THREE.Vector3(0, 0, 0), length, color, arrowLength, arrowHead); - arrow.updateMatrix(); - arrow.matrixAutoUpdate = false; - arrow.line.renderOrder = 1e11; - arrow.cone.renderOrder = 1e11; - arrow.line.material.linewidth = 1/DPR; - arrow.line.material.depthWrite = false; - arrow.line.material.depthTest = false; - arrow.cone.material.depthWrite = false; - arrow.cone.material.depthTest = false; - return arrow; - } - - var xAxis = createArrow(new THREE.Vector3(1, 0, 0), 0xFF0000); - var yAxis = createArrow(new THREE.Vector3(0, 1, 0), 0x00FF00); - this.basisGroup.add(xAxis); - this.basisGroup.add(yAxis); } - updateBasis(basis, depth) { - this.basisGroup.matrix.identity(); - var mx = new THREE.Matrix4(); - mx.makeBasis(basis[0].three(), basis[1].three(), basis[2].three()); - var depthOff = new THREE.Vector3(0, 0, depth); - depthOff.applyMatrix4(mx); - mx.setPosition(depthOff); - this.basisGroup.applyMatrix(mx); - } - - select(sketchFace) { this.clear(); if (sketchFace.curvedSurfaces !== null) { @@ -124,8 +89,8 @@ export class SelectionManager extends AbstractSelectionManager { } } else { this.selection.push(sketchFace); - this.updateBasis(sketchFace.basis(), sketchFace.depth()); - sketchFace.solid.cadGroup.add(this.basisGroup); + this.viewer.updateBasis(sketchFace.basis(), sketchFace.depth()); + this.viewer.showBasis(); setFacesColor(sketchFace.faces, this.selectionColor); } sketchFace.solid.mesh.geometry.colorsNeedUpdate = true; @@ -144,11 +109,47 @@ export class SelectionManager extends AbstractSelectionManager { setFacesColor(selectee.faces, this.defaultColor); selectee.solid.mesh.geometry.colorsNeedUpdate = true; } - if (this.basisGroup.parent !== null ) this.basisGroup.parent.remove( this.basisGroup ); + this.viewer.hideBasis(); this.selection.length = 0; } } +export class BREPFaceSelectionManager extends AbstractSelectionManager { + + constructor(viewer, selectionColor, readOnlyColor, defaultColor) { + super(viewer); + this.selectionColor = selectionColor; + this.defaultColor = defaultColor; + this.readOnlyColor = readOnlyColor; + } + + select(face) { + this.clear(); + this.selection.push(face); + setFacesColor(face.meshFaces, this.selectionColor); + + face.solid.mesh.geometry.colorsNeedUpdate = true; + this.viewer.bus.notify('selection', face); + this.viewer.render(); + } + + deselectAll() { + this.clear(); + this.viewer.bus.notify('selection', null); + this.viewer.render(); + } + + clear() { + for (let selectee of this.selection) { + setFacesColor(selectee.meshFaces, this.defaultColor); + selectee.solid.mesh.geometry.colorsNeedUpdate = true; + } + this.viewer.hideBasis(); + this.selection.length = 0; + } + +} + function setFacesColor(faces, color) { for (let face of faces) { if (color == null) { @@ -158,4 +159,3 @@ function setFacesColor(faces, color) { } } } - diff --git a/web/app/3d/viewer.js b/web/app/3d/viewer.js index aa0dccfb..5f9833bd 100644 --- a/web/app/3d/viewer.js +++ b/web/app/3d/viewer.js @@ -2,7 +2,7 @@ import * as cad_utils from './cad-utils' import {Matrix3, AXIS, ORIGIN} from '../math/l3space' import DPR from '../utils/dpr' import * as mask from '../utils/mask'; -import {SelectionManager, SketchSelectionManager} from './selection' +import {SelectionManager, BREPFaceSelectionManager, SketchSelectionManager} from './selection' function Viewer(bus, container) { this.bus = bus; @@ -92,7 +92,9 @@ function Viewer(bus, container) { this.workGroup = new THREE.Object3D(); this.scene.add(this.workGroup); + this.createBasisGroup(); this.selectionMgr = new SelectionManager( this, 0xFAFAD2, 0xFF0000, null); + this.brepSelectionMgr = new BREPFaceSelectionManager( this, 0xFAFAD2, 0xFF0000, null); this.sketchSelectionMgr = new SketchSelectionManager( this, new THREE.LineBasicMaterial({color: 0xFF0000, linewidth: 6/DPR})); var viewer = this; @@ -159,6 +161,53 @@ function Viewer(bus, container) { this.animate(); } +Viewer.prototype.createBasisGroup = function() { + this.basisGroup = new THREE.Object3D(); + var length = 200; + var arrowLength = length * 0.2; + var arrowHead = arrowLength * 0.4; + + function createArrow(axis, color) { + var arrow = new THREE.ArrowHelper(axis, new THREE.Vector3(0, 0, 0), length, color, arrowLength, arrowHead); + arrow.updateMatrix(); + arrow.matrixAutoUpdate = false; + arrow.line.renderOrder = 1e11; + arrow.cone.renderOrder = 1e11; + arrow.line.material.linewidth = 1/DPR; + arrow.line.material.depthWrite = false; + arrow.line.material.depthTest = false; + arrow.cone.material.depthWrite = false; + arrow.cone.material.depthTest = false; + return arrow; + } + + var xAxis = createArrow(new THREE.Vector3(1, 0, 0), 0xFF0000); + var yAxis = createArrow(new THREE.Vector3(0, 1, 0), 0x00FF00); + this.basisGroup.add(xAxis); + this.basisGroup.add(yAxis); +}; + +Viewer.prototype.updateBasis = function(basis, depth){ + this.basisGroup.matrix.identity(); + var mx = new THREE.Matrix4(); + mx.makeBasis(basis[0].three(), basis[1].three(), basis[2].three()); + var depthOff = new THREE.Vector3(0, 0, depth); + depthOff.applyMatrix4(mx); + mx.setPosition(depthOff); + this.basisGroup.applyMatrix(mx); +}; + +Viewer.prototype.showBasis = function(){ + this.workGroup.add(this.basisGroup); +}; + +Viewer.prototype.hideBasis = function(){ + if (this.basisGroup.parent !== null ) { + this.basisGroup.parent.remove( this.basisGroup ); + } +}; + + Viewer.prototype.lookAt = function(obj) { var box = new THREE.Box3(); box.setFromObject(obj); @@ -189,7 +238,9 @@ export const PICK_KIND = { FACE: mask.type(1), SKETCH: mask.type(2), EDGE: mask.type(3), - VERTEX: mask.type(4) + VERTEX: mask.type(4), + TOPO_FACE: mask.type(5), + TOPO_EDGE: mask.type(6) }; Viewer.prototype.raycastObjects = function(event, kind, visitor) { @@ -206,12 +257,20 @@ Viewer.prototype.raycastObjects = function(event, kind, visitor) { if (!visitor(pickResult.object, PICK_KIND.SKETCH)) { break; } + } else if (mask.is(kind, PICK_KIND.TOPO_FACE) && !!pickResult.face && pickResult.face.__TCAD_TOPO) { + if (!visitor(pickResult.face.__TCAD_TOPO, PICK_KIND.TOPO_FACE)) { + break; + } + } else if (mask.is(kind, PICK_KIND.TOPO_EDGE) && pickResult.object instanceof THREE.Line && pickResult.object.__TCAD_TOPO) { + if (!visitor(pickResult.object.__TCAD_TOPO, PICK_KIND.TOPO_EDGE)) { + break; + } } } }; Viewer.prototype.handlePick = function(event) { - this.raycastObjects(event, PICK_KIND.FACE | PICK_KIND.SKETCH, (object, kind) => { + this.raycastObjects(event, PICK_KIND.FACE | PICK_KIND.SKETCH | PICK_KIND.TOPO_FACE | PICK_KIND.TOPO_EDGE, (object, kind) => { if (kind == PICK_KIND.FACE) { if (this.selectionMgr.pick(object)) { return false; @@ -220,6 +279,10 @@ Viewer.prototype.handlePick = function(event) { if (this.sketchSelectionMgr.pick(object)) { return false; } + } else if (kind == PICK_KIND.TOPO_FACE) { + this.brepSelectionMgr.select(object); + } else if (kind == PICK_KIND.TOPO_EDGE) { + //this.brepSelectionMgr.selectEdge(object); } return true; }); diff --git a/web/app/brep/viz/scene-solid.js b/web/app/brep/viz/scene-solid.js index 53e3178b..ac9162a6 100644 --- a/web/app/brep/viz/scene-solid.js +++ b/web/app/brep/viz/scene-solid.js @@ -16,7 +16,7 @@ export class SceneSolid { this.mesh = new THREE.Mesh(geometry, createSolidMaterial()); this.cadGroup.add(this.mesh); - this.polyFaces = []; + this.sceneFaces = []; this.createFaces(); this.createEdges(); this.createVertices(); @@ -27,8 +27,8 @@ export class SceneSolid { let gIdx = 0; const geom = this.mesh.geometry; for (let brepFace of this.shell.faces) { - const polyFace = new SceneFace(brepFace); - this.polyFaces.push(polyFace); + const sceneFace = new SceneFace(brepFace, this); + this.sceneFaces.push(sceneFace); const polygons = triangulate(brepFace); for (let p = 0; p < polygons.length; ++p) { const poly = polygons[p]; @@ -45,20 +45,16 @@ export class SceneSolid { const b = i - 1 + off; const c = i + off; const face = new THREE.Face3(a, b, c); - polyFace.faces.push(face); - face.__TCAD_polyFace = polyFace; + sceneFace.meshFaces.push(face); + face.__TCAD_TOPO = sceneFace; face.normal = normal; face.materialIndex = gIdx ++; geom.faces.push(face); if (brepFace.debugName == 'base') { face.color.set(new THREE.Color().setHex( 0x000077 )); } - if (brepFace.debugName == 'wall_3') { - face.color.set(new THREE.Color().setHex( 0x007700 )); - } - } - //view.setFaceColor(polyFace, utils.isSmoothPiece(group.shared) ? 0xFF0000 : null); + //view.setFaceColor(sceneFace, utils.isSmoothPiece(group.shared) ? 0xFF0000 : null); off = geom.vertices.length; } } @@ -71,7 +67,7 @@ export class SceneSolid { for (let halfEdge of face.outerLoop.halfEdges) { if (!visited.has(halfEdge.edge)) { visited.add(halfEdge.edge); - this.addLineToScene(halfEdge.vertexA.point, halfEdge.vertexB.point, halfEdge.edge); + this.addLineToScene(halfEdge.vertexA.point.three(), halfEdge.vertexB.point.three(), halfEdge.edge); } } } @@ -96,9 +92,10 @@ const WIREFRAME_MATERIAL = new THREE.LineBasicMaterial({color: 0xff0000, linewid class SceneFace { - constructor(brepFace) { + constructor(brepFace, solid) { + this.solid = solid; this.brepFace = brepFace; - this.faces = []; + this.meshFaces = []; } }