From 6e28eb2ed5fbb23b9e6a0f6a5c8aef8fe7a223ca Mon Sep 17 00:00:00 2001 From: Val Erastov Date: Tue, 19 Aug 2014 23:18:43 -0700 Subject: [PATCH] implement editing --- web/app/ctrl.js | 24 ++++--- web/app/engine.js | 79 ++++++++++++++------- web/app/main.js | 2 +- web/app/vector.js | 9 +++ web/app/viewer.js | 170 +++++++++++++++++++++++++++++----------------- 5 files changed, 189 insertions(+), 95 deletions(-) diff --git a/web/app/ctrl.js b/web/app/ctrl.js index 8feb1534..8f6d892f 100644 --- a/web/app/ctrl.js +++ b/web/app/ctrl.js @@ -1,5 +1,6 @@ -TCAD.UI = function() { +TCAD.UI = function(viewer) { + this.viewer = viewer; this.dat = new dat.GUI(); var gui = this.dat; @@ -7,17 +8,24 @@ TCAD.UI = function() { gui.TEXT_OPEN = 'Open FFF'; var actionsF = gui.addFolder('Add Object'); - actionsF.add(this.actions.add, 'box'); + var actions = new TCAD.UI.Actions(this); + actionsF.add(actions.tools, 'polygon'); + actionsF.add(actions.tools, 'commit'); actionsF.open(); // var propsF = gui.addFolder('Properties'); // propsF.add(object3DProto.position, 'x'); -} +}; -TCAD.UI.prototype.actions = { - add : { - box : function() { - alert("got it!"); +TCAD.UI.Actions = function(scope) { + + this.tools = { + polygon : function() { + scope.viewer.toolMgr.tool = new TCAD.PolygonTool(scope.viewer.selectionMgr.selection[0]); + }, + + commit : function() { + scope.viewer.toolMgr.commit(); } } -} +}; diff --git a/web/app/engine.js b/web/app/engine.js index 4a449f1b..bf41572c 100644 --- a/web/app/engine.js +++ b/web/app/engine.js @@ -26,12 +26,35 @@ TCAD.utils.checkPolygon = function(poly) { } }; -TCAD.utils.fixCCW = function(shell) { - if (!TCAD.geom.isCCW(shell)) { - shell = shell.slice(0); - shell.reverse(); +TCAD.utils.createPoint = function() { + var g = new THREE.PlaneGeometry(0.05, 0.05); + var m = new THREE.MeshBasicMaterial({color: 0x0000ff, side: THREE.DoubleSide}); + return new THREE.Mesh(g, m); +}; + +TCAD.utils.createSolid = function(faces) { + var geometry = new TCAD.Solid(faces); + geometry.dynamic = true; //true by default + var material = new THREE.MeshPhongMaterial({ + vertexColors: THREE.FaceColors, + color: '#B0C4DE', + shininess: 0 + }); + return new THREE.Mesh( geometry, material ); +}; + +TCAD.utils.fixCCW = function(path, normal) { + var _2DTransformation = new TCAD.Matrix().setBasis(TCAD.geom.someBasis(path, normal)).invert(); + var path2D = []; + for (var i = 0; i < path.length; ++i) { + path2D[i] = _2DTransformation.apply(path[i]); } - return shell; + + if (!TCAD.geom.isCCW(path2D)) { + path = path.slice(0); + path.reverse(); + } + return path; }; TCAD.TOLERANCE = 0.000001; @@ -55,6 +78,17 @@ TCAD.utils.equal = function(v1, v2) { }; TCAD.geom = {}; + +TCAD.geom.someBasis = function(twoPointsOnPlane, normal) { + var a = twoPointsOnPlane[0]; + var b = twoPointsOnPlane[1]; + + var x = b.minus(a).normalize(); + var y = normal.cross(x).normalize(); + + return [x, y, normal]; +}; + TCAD.geom.normalOfCCWSeq = function(ccwSequence) { var a = ccwSequence[0]; var b = ccwSequence[1]; @@ -82,8 +116,8 @@ TCAD.geom.area = function (contour) { return a * 0.5; }; -TCAD.geom.isCCW = function(vertices) { - return TCAD.geom.area(vertices) >= 0; +TCAD.geom.isCCW = function(path2D) { + return TCAD.geom.area(path2D) >= 0; }; TCAD.geom.extrude = function(source, target) { @@ -100,14 +134,16 @@ TCAD.geom.extrude = function(source, target) { var lid = source.shift(target).flip(); poly.push(lid); - + var lidShell = lid.shell.slice(0); + lidShell.reverse(); + var n = source.shell.length; for ( var p = n - 1, i = 0; i < n; p = i ++ ) { var face = new TCAD.Polygon([ - source.shell[p], source.shell[i], - lid.shell[i], - lid.shell[p] + source.shell[p], + lidShell[p], + lidShell[i] ]); poly.push(face); } @@ -134,7 +170,7 @@ TCAD.Solid = function(polygons) { for ( var h = 0; h < poly.holes; ++ h ) { pushVertices(poly.holes[ h ]); } - var polyFace = {faces : [], polygon : poly}; + var polyFace = {faces : [], polygon : poly, sketch : null}; for ( var i = 0; i < faces.length; ++ i ) { @@ -183,7 +219,7 @@ TCAD.Polygon = function(shell, holes, normal) { if (normal === undefined) { normal = TCAD.geom.normalOfCCWSeq(shell); } else { - shell = TCAD.utils.fixCCW(shell); + shell = TCAD.utils.fixCCW(shell, normal); } this.normal = normal; @@ -191,16 +227,6 @@ TCAD.Polygon = function(shell, holes, normal) { this.holes = holes; }; -TCAD.Polygon.prototype.someBasis = function() { - var a = this.shell[0]; - var b = this.shell[1]; - - var x = b.minus(a).normalize(); - var y = this.normal.cross(x).normalize(); - - return [x, y, this.normal]; -}; - TCAD.Polygon.prototype.reverse = function(triangle) { var first = triangle[0]; triangle[0] = triangle[2]; @@ -230,7 +256,7 @@ TCAD.Polygon.prototype.shift = function(target) { TCAD.Polygon.prototype.triangulate = function() { - var _3dTransformation = new TCAD.Matrix().setBasis(this.someBasis()); + var _3dTransformation = new TCAD.Matrix().setBasis(TCAD.geom.someBasis(this.shell, this.normal)); var _2dTransformation = _3dTransformation.invert(); var i, h; @@ -247,3 +273,8 @@ TCAD.Polygon.prototype.triangulate = function() { } return THREE.Shape.Utils.triangulateShape( shell, holes ); }; + + +TCAD.Sketch = function() { + this.group = new THREE.Object3D(); +}; \ No newline at end of file diff --git a/web/app/main.js b/web/app/main.js index 2c10b489..afc327fd 100644 --- a/web/app/main.js +++ b/web/app/main.js @@ -3,6 +3,6 @@ TCAD = {}; TCAD.App = function() { this.viewer = new TCAD.Viewer(); - this.ui = new TCAD.UI(); + this.ui = new TCAD.UI(this.viewer); }; diff --git a/web/app/vector.js b/web/app/vector.js index 8c05992f..3df7eac4 100644 --- a/web/app/vector.js +++ b/web/app/vector.js @@ -10,12 +10,21 @@ TCAD.Vector.prototype.set = function(x, y, z) { this.x = x; this.y = y; this.z = z; + return this; }; TCAD.Vector.prototype.set3 = function(data) { this.x = data[0]; this.y = data[1]; this.z = data[2]; + return this; +}; + +TCAD.Vector.prototype.setV = function(data) { + this.x = data.x; + this.y = data.y; + this.z = data.z; + return this; }; TCAD.Vector.prototype.multiply = function(factor) { diff --git a/web/app/viewer.js b/web/app/viewer.js index 0375bf7f..6a586ad1 100644 --- a/web/app/viewer.js +++ b/web/app/viewer.js @@ -16,6 +16,7 @@ TCAD.Viewer = function() { var scene = new THREE.Scene(); var camera = new THREE.PerspectiveCamera( 75, aspect(), 0.1, 1000 ); + camera.position.z = 5; var light = new THREE.PointLight( 0xffffff); light.position.set( 10, 10, 10 ); @@ -25,7 +26,12 @@ TCAD.Viewer = function() { renderer.setClearColor(0x808080, 1); renderer.setSize( window.innerWidth, window.innerHeight ); document.body.appendChild( renderer.domElement ); - + function render() { +// console.log("render"); + light.position.set(camera.position.x, camera.position.y, camera.position.z); + renderer.render(scene, camera); + } + this.render = render; function onWindowResize() { camera.aspect = aspect(); @@ -37,56 +43,18 @@ TCAD.Viewer = function() { // var geometry = new THREE.BoxGeometry(1,1,1); - // var geometry = new TCAD.Solid([TCAD.utils.createSquare(1)]); - var geometry = new TCAD.Solid(TCAD.utils.createBox(1)); - - var material = new THREE.MeshPhongMaterial( new THREE.MeshPhongMaterial({ - - vertexColors: THREE.FaceColors, - // light -// specular: '#a9fcff', - // intermediate - color: '#B0C4DE', - // dark -// emissive: '#006063', - shininess: 0 - })); -// material = new THREE.MeshNormalMaterial( { shading: THREE.FlatShading, color: '#B0C4DE' } ); -// material = new THREE.MeshBasicMaterial( { color: 0x00ff00, wireframe : false, vertexColors: THREE.FaceColors } ); - -// var shader = THREE.ShaderLib['normal']; -// material = new THREE.ShaderMaterial( { -// uniforms: THREE.UniformsUtils.clone( shader.uniforms ), -// vertexShader: shader.vertexShader, -// fragmentShader: shader.fragmentShader.replace(/gl_FragColor.+\n/, 'gl_FragColor = vec4( 0.5, opacity );') -// }); - - -// material = new THREE.ShaderMaterial({ -// fragmentShader: "void main() { \n" + -// "gl_FragColor = vec4(1.0, 0.0, 1.0, 1.0); \n" + -// "}" -// }); - - - var cube = new THREE.Mesh( geometry, material ); -// cube.dynamic = true; - scene.add( cube ); - - camera.position.z = 5; - - cube.rotation.x += 1; - cube.rotation.y += 1; - - + var box = TCAD.utils.createSolid(TCAD.utils.createBox(1)); + scene.add( box ); + + /** * CONTROLS **/ // controls = new THREE.OrbitControls( camera , renderer.domElement); - controls = new THREE.TrackballControls( camera , renderer.domElement); + var controls = new THREE.TrackballControls( camera , renderer.domElement); // document.addEventListener( 'mousemove', function(){ @@ -107,21 +75,25 @@ TCAD.Viewer = function() { controls.addEventListener( 'change', render ); + /** + * TOOLS + **/ + + this.toolMgr = new TCAD.ToolManager(this); + + /** * FACE SELECTING **/ - var selectionMgr = new TCAD.FaceSelectionManager( 0xFAFAD2, 0xB0C4DE) + this.selectionMgr = new TCAD.FaceSelectionManager( 0xFAFAD2, 0xB0C4DE); var projector = new THREE.Projector(); var raycaster = new THREE.Raycaster(); - var mouse = new THREE.Vector3(0, 0, 0); - raycaster.ray.direction.set(0, -1, 0); - var pickReq = { }; - function pick(event) { + this.raycast = function(event) { var x = ( event.clientX / window.innerWidth ) * 2 - 1; var y = - ( event.clientY / window.innerHeight ) * 2 + 1; @@ -130,24 +102,44 @@ TCAD.Viewer = function() { var ray = projector.pickingRay(mouse.clone(), camera); var intersects = ray.intersectObjects( scene.children ); if (intersects.length > 0) { - var picked = intersects[0]; - if (picked.face.__TCAD_polyFace !== undefined) { - var poly = picked.face.__TCAD_polyFace; - selectionMgr.select(poly); - picked.object.geometry.colorsNeedUpdate = true; + var pickResult = intersects[0]; + if (pickResult.face.__TCAD_polyFace !== undefined) { + var poly = pickResult.face.__TCAD_polyFace; + if (this.selectionMgr.contains(poly)) { + this.toolMgr.handle(poly, pickResult); + } else { + this.selectionMgr.select(poly); + pickResult.object.geometry.colorsNeedUpdate = true; + } } render(); } - } - renderer.domElement.addEventListener('mousedown', pick, false); + }; + + var scope = this; + + var mouseState = { + moved : false + }; - - function render() { -// console.log("render"); - light.position.set(camera.position.x, camera.position.y, camera.position.z); - renderer.render(scene, camera); + function onMove() { + mouseState.moved = true; } + renderer.domElement.addEventListener('mousedown', + function() { + mouseState.moved = false; + renderer.domElement.addEventListener('mousemove', onMove, false); + }, false); + + renderer.domElement.addEventListener('mouseup', + function(e) { + renderer.domElement.removeEventListener('mousemove', onMove); + if (!mouseState.moved) { + scope.raycast(e); + } + } , false); + function animate() { // console.log("animate"); requestAnimationFrame( animate ); @@ -170,9 +162,63 @@ TCAD.FaceSelectionManager.prototype.select = function(polyFace) { TCAD.view.setFaceColor(polyFace, this.selectionColor); }; +TCAD.FaceSelectionManager.prototype.contains = function(polyFace) { + return this.selection.indexOf(polyFace) != -1; +}; + TCAD.FaceSelectionManager.prototype.clear = function() { for (var i = 0; i < this.selection.length; ++ i) { TCAD.view.setFaceColor(this.selection[i], this.defaultColor); } this.selection.length = 0; -}; \ No newline at end of file +}; + +TCAD.ToolManager = function(viewer) { + this.viewer = viewer; + this.tool = null; +}; + +TCAD.ToolManager.prototype.handle = function(face, pickResult) { + if (this.tool == null) { + return; + } + if (this.tool.workArea != face) { + return; + } + if (this.tool.workArea.sketch == null) { + this.tool.workArea.sketch = new TCAD.Sketch(); + pickResult.object.parent.add(this.tool.workArea.sketch.group); + } + this.tool.handle(face, pickResult); +}; + +TCAD.ToolManager.prototype.commit = function() { + if (this.tool == null) { + return; + } + this.tool.commit(); + this.viewer.render(); +}; + +TCAD.PolygonTool = function(workArea) { + this.workArea = workArea; + this.poly = {shell : [], holes : []}; +}; + +TCAD.PolygonTool.prototype.handle = function(face, pickResult) { + this.poly.shell.push(new TCAD.Vector().setV(pickResult.point)); + var point = TCAD.utils.createPoint(); + point.position.x = pickResult.point.x; + point.position.y = pickResult.point.y; + point.position.z = pickResult.point.z; + this.workArea.sketch.group.add(point); +}; + +TCAD.PolygonTool.prototype.commit = function() { + var n = this.workArea.polygon.normal; + var _2d = new TCAD.Polygon(this.poly.shell, this.poly.holes, n); + + var solid = TCAD.utils.createSolid(TCAD.geom.extrude(_2d, n.multiply(1.1))); + this.workArea.sketch.group.parent.add(solid); +}; +