From 69583959e23e42fc4fc2061f2ab7b4a885d97b01 Mon Sep 17 00:00:00 2001 From: Val Erastov Date: Thu, 5 Nov 2015 18:26:34 -0800 Subject: [PATCH] add plane concept --- web/app/3d/ctrl.js | 35 +++++- web/app/3d/main.js | 44 ++++--- web/app/3d/viewer.js | 212 +++++++--------------------------- web/app/3d/wizards/wizards.js | 57 +++++++++ web/app/engine.js | 97 +++++++++++++++- web/app/math/math.js | 4 +- web/app/ui/toolkit.js | 28 ++++- web/app/workbench.js | 17 ++- web/css/toolkit.css | 4 + 9 files changed, 295 insertions(+), 203 deletions(-) diff --git a/web/app/3d/ctrl.js b/web/app/3d/ctrl.js index 4243b1d9..399add27 100644 --- a/web/app/3d/ctrl.js +++ b/web/app/3d/ctrl.js @@ -11,11 +11,12 @@ TCAD.UI = function(app) { var cameraFolder = new tk.Folder("Camera"); var objectsFolder = new tk.Folder("Objects"); var modificationsFolder = new tk.Folder("Modifications"); - var extrude, cut, edit, refreshSketches, showSketches, printSolids, printFace, printFaceId; + var extrude, cut, edit, addPlane, refreshSketches, showSketches, printSolids, printFace, printFaceId; tk.add(mainBox, propFolder); tk.add(propFolder, extrude = new tk.Button("Extrude")); tk.add(propFolder, cut = new tk.Button("Cut")); tk.add(propFolder, edit = new tk.Button("Edit")); + tk.add(propFolder, addPlane = new tk.Button("Add a Plane")); tk.add(propFolder, refreshSketches = new tk.Button("Refresh Sketches")); tk.add(propFolder, showSketches = new tk.CheckBox("Show Sketches", true)); tk.add(mainBox, debugFolder); @@ -111,6 +112,38 @@ TCAD.UI = function(app) { extrude.root.click(cutExtrude(false)); edit.root.click(tk.methodRef(app, "sketchFace")); refreshSketches.root.click(tk.methodRef(app, "refreshSketches")); + addPlane.root.click(function() { + var box = new tk.Box(); + box.root.css({left : (mainBox.root.width() + 10) + 'px', top : 0}); + var folder = new tk.Folder("Add a Plane"); + tk.add(box, folder); + var choice = ['XY', 'XZ', 'ZY']; + var orientation = new tk.InlineRadio(choice, choice, 0); + var depth = new tk.Number("Depth", 0); + + tk.add(folder, orientation); + tk.add(folder, depth); + var wizard = new TCAD.wizards.PlaneWizard(app.viewer); + function onChange() { + wizard.update(orientation.getValue(), depth.input.val()); + } + function close() { + box.close(); + wizard.dispose(); + } + function ok() { + app.craft.modify({ + type: 'PLANE', + solids : [], + params : wizard.operationParams + }); + close(); + } + orientation.root.find('input:radio').change(onChange); + depth.input.on('t-change', onChange); + onChange(); + tk.add(folder, new tk.ButtonRow(["Cancel", "OK"], [close, ok])); + }); printSolids.root.click(function () { app.viewer.scene.children.map(function(o) { if (o.geometry instanceof TCAD.Solid) { diff --git a/web/app/3d/main.js b/web/app/3d/main.js index a4d3225a..1d1ad326 100644 --- a/web/app/3d/main.js +++ b/web/app/3d/main.js @@ -11,7 +11,9 @@ TCAD.App = function() { this.ui = new TCAD.UI(this); this.craft = new TCAD.Craft(this); - this.addBox(); + if (this.id == '$scratch$') { + this.addBox(); + } this._refreshSketches(); this.viewer.render(); @@ -52,22 +54,19 @@ TCAD.App = function() { }; TCAD.App.prototype.findAllSolids = function() { - return this.viewer.scene.children + return this.viewer.workGroup.children .filter(function(obj) {return !!obj.geometry && obj.geometry.tCadId !== undefined} ) .map(function(obj) {return obj.geometry} ) }; TCAD.App.prototype.findFace = function(faceId) { - var solidId = faceId.split(":")[0]; - var children = this.viewer.scene.children; - for (var i = 0; i < children.length; i++) { - var obj = children[i]; - if (!!obj.geometry && obj.geometry.tCadId !== undefined) { - for (var j = 0; j < obj.geometry.polyFaces.length; j++) { - var face = obj.geometry.polyFaces[j]; - if (face.id == faceId) { - return face; - } + var solids = this.findAllSolids(); + for (var i = 0; i < solids.length; i++) { + var solid = solids[i]; + for (var j = 0; j < solid.polyFaces.length; j++) { + var face = solid.polyFaces[j]; + if (face.id == faceId) { + return face; } } } @@ -273,17 +272,16 @@ TCAD.App.prototype.refreshSketches = function() { }; TCAD.App.prototype._refreshSketches = function() { - for (var oi = 0; oi < this.viewer.scene.children.length; ++oi) { - var obj = this.viewer.scene.children[oi]; - if (obj.geometry !== undefined && obj.geometry.polyFaces !== undefined) { - for (var i = 0; i < obj.geometry.polyFaces.length; i++) { - var sketchFace = obj.geometry.polyFaces[i]; - var faceStorageKey = this.faceStorageKey(sketchFace.id); - var savedFace = localStorage.getItem(faceStorageKey); - if (savedFace != null) { - var geom = TCAD.workbench.readSketchGeom(JSON.parse(savedFace)); - sketchFace.syncSketches(geom); - } + var allSolids = this.findAllSolids(); + for (var oi = 0; oi < allSolids.length; ++oi) { + var obj = allSolids[oi]; + for (var i = 0; i < obj.polyFaces.length; i++) { + var sketchFace = obj.polyFaces[i]; + var faceStorageKey = this.faceStorageKey(sketchFace.id); + var savedFace = localStorage.getItem(faceStorageKey); + if (savedFace != null) { + var geom = TCAD.workbench.readSketchGeom(JSON.parse(savedFace)); + sketchFace.syncSketches(geom); } } } diff --git a/web/app/3d/viewer.js b/web/app/3d/viewer.js index 8cd56083..8be0c6c3 100644 --- a/web/app/3d/viewer.js +++ b/web/app/3d/viewer.js @@ -2,9 +2,9 @@ TCAD.DPR = (window.devicePixelRatio) ? window.devicePixelRatio : 1; TCAD.view = {}; -TCAD.view.setFaceColor = function(polyFace, color) { - for (var i = 0; i < polyFace.faces.length; ++i) { - var face = polyFace.faces[i]; +TCAD.view.setFacesColor = function(faces, color) { + for (var i = 0; i < faces.length; ++i) { + var face = faces[i]; if (color == null) { face.color.set(new THREE.Color()); } else { @@ -49,10 +49,6 @@ TCAD.Viewer = function(bus) { } window.addEventListener( 'resize', onWindowResize, false ); - /** - * CONTROLS - **/ - // controls = new THREE.OrbitControls( camera , renderer.domElement); var trackballControls = new THREE.TrackballControls( camera , renderer.domElement); @@ -106,19 +102,10 @@ TCAD.Viewer = function(bus) { updateTransformControls(); } - /** - * TOOLS - **/ - - this.toolMgr = new TCAD.ToolManager(this); - - - /** - * FACE SELECTING - **/ - - - this.selectionMgr = new TCAD.FaceSelectionManager( 0xFAFAD2, 0xFF0000, null); + this.workGroup = new THREE.Object3D(); + this.scene.add(this.workGroup); + this.selectionMgr = new TCAD.SelectionManager( this, 0xFAFAD2, 0xFF0000, null); + var viewer = this; var raycaster = new THREE.Raycaster(); @@ -129,32 +116,11 @@ TCAD.Viewer = function(bus) { var mouse = new THREE.Vector3( x, y, 1 ); raycaster.setFromCamera( mouse, camera ); - return raycaster.intersectObjects( scene.children ); + return raycaster.intersectObjects( viewer.workGroup.children, true ); }; - var scope = this; function onClick(e) { - var intersects = scope.raycast(e); - if (intersects.length === 0) scope.transformControls.detach(); - for (var ii = 0; ii < intersects.length; ii++) { - var pickResult = intersects[ii]; - if (!pickResult.face) continue; - if (pickResult.face.__TCAD_polyFace !== undefined) { - var poly = pickResult.face.__TCAD_polyFace; - if (scope.selectionMgr.contains(poly)) { - scope.toolMgr.handleClick(poly, pickResult); - } else { - if (e.shiftKey) { - scope.transformControls.attach(pickResult.object); - } else { - scope.select(poly); - pickResult.object.geometry.colorsNeedUpdate = true; - } - } - } - render(); - break; - } + viewer.selectionMgr.handlePick(e); } var mouseState = { @@ -162,20 +128,14 @@ TCAD.Viewer = function(bus) { startY : 0 }; - function onMove(e) { - }; - - renderer.domElement.addEventListener('mousemove', function(e){scope.toolMgr.handleMove(e)}, false); - renderer.domElement.addEventListener('mousedown', + renderer.domElement.addEventListener('mousedown', function(e) { mouseState.startX = e.clientX; mouseState.startY = e.clientY; - renderer.domElement.addEventListener('mousemove', onMove, false); }, false); - - renderer.domElement.addEventListener('mouseup', + + renderer.domElement.addEventListener('mouseup', function(e) { - renderer.domElement.removeEventListener('mousemove', onMove); var dx = Math.abs(mouseState.startX - e.clientX); var dy = Math.abs(mouseState.startY - e.clientY); var TOL = 1; @@ -194,139 +154,55 @@ TCAD.Viewer = function(bus) { animate(); }; -TCAD.Viewer.prototype.select = function(polyFace) { - this.selectionMgr.select(polyFace); - this.bus.notify('selection', polyFace); -}; - -TCAD.FaceSelectionManager = function(selectionColor, readOnlyColor, defaultColor) { +TCAD.SelectionManager = function(viewer, selectionColor, readOnlyColor, defaultColor) { + this.viewer = viewer; this.selectionColor = selectionColor; this.readOnlyColor = readOnlyColor; this.defaultColor = defaultColor; this.selection = []; + this.planeSelection = []; }; -TCAD.FaceSelectionManager.prototype.select = function(polyFace) { +TCAD.SelectionManager.prototype.handlePick = function(event) { + + var pickResults = this.viewer.raycast(event); + for (var i = 0; i < pickResults.length; i++) { + var pickResult = pickResults[i]; + if (!!pickResult.face && pickResult.face.__TCAD_polyFace !== undefined) { + var sketchFace = pickResult.face.__TCAD_polyFace; + if (!this.contains(sketchFace)) { + this.select(sketchFace); + pickResult.object.geometry.colorsNeedUpdate = true; + this.viewer.bus.notify('selection', sketchFace); + this.viewer.render(); + break; + } + } + } +}; + +TCAD.SelectionManager.prototype.select = function(sketchFace) { this.clear(); - if (polyFace.curvedSurfaces !== null) { - for (var i = 0; i < polyFace.curvedSurfaces.length; i++) { - var face = polyFace.curvedSurfaces[i]; + if (sketchFace.curvedSurfaces !== null) { + for (var i = 0; i < sketchFace.curvedSurfaces.length; i++) { + var face = sketchFace.curvedSurfaces[i]; this.selection.push(face); - TCAD.view.setFaceColor(face, this.readOnlyColor); + TCAD.view.setFacesColor(face.faces, this.readOnlyColor); } } else { - this.selection.push(polyFace); - TCAD.view.setFaceColor(polyFace, this.selectionColor); + this.selection.push(sketchFace); + TCAD.view.setFacesColor(sketchFace.faces, this.selectionColor); } - }; -TCAD.FaceSelectionManager.prototype.contains = function(polyFace) { - return this.selection.indexOf(polyFace) != -1; +TCAD.SelectionManager.prototype.contains = function(face) { + return this.selection.indexOf(face) != -1; }; -TCAD.FaceSelectionManager.prototype.clear = function() { +TCAD.SelectionManager.prototype.clear = function() { for (var i = 0; i < this.selection.length; ++ i) { - TCAD.view.setFaceColor(this.selection[i], this.defaultColor); + TCAD.view.setFacesColor(this.selection[i].faces, this.defaultColor); } this.selection.length = 0; }; -TCAD.ToolManager = function(viewer) { - this.viewer = viewer; - this.tool = null; -}; - -TCAD.ToolManager.prototype.handleClick = 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.handleClick(face, pickResult); -}; - - -TCAD.ToolManager.prototype.handleMove = function(event) { - if (this.tool == null) { - return; - } - this.tool.handleMove(event, this.viewer); -}; - -TCAD.ToolManager.prototype.commit = function() { - if (this.tool == null) { - return; - } - this.tool.commit(); - this.viewer.render(); - this.tool = null; -}; - -TCAD.PolygonTool = function(workArea, viewer) { - this.workArea = workArea; - this.viewer = viewer; - this.poly = {shell : [], holes : []}; -}; - -TCAD.PolygonTool.prototype.handleClick = function(face, pickResult) { - this.poly.shell.push(new TCAD.Vector().setV(pickResult.point)); - var point = TCAD.utils.createPoint(pickResult.point.x, pickResult.point.y, pickResult.point.z); - this.workArea.sketch.group.add(point); -}; - -TCAD.PolygonTool.prototype.handleMove = function(event, raycast) { - -}; - -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.createSolidMesh(TCAD.geom.extrude(_2d, n.multiply(1.1))); - this.workArea.sketch.group.parent.add(solid); -}; - - -TCAD.LineTool = function(workArea) { - this.workArea = workArea; - this.protoLine = null; -}; - -TCAD.LineTool.prototype.handleClick = function(face, pickResult) { - if (this.protoLine == null) { - this.protoLine = TCAD.utils.createLine(pickResult.point, pickResult.point, 0x0000ff); - this.workArea.sketch.group.add(this.protoLine); - } else { - - } -}; - -TCAD.LineTool.prototype.handleMove = function(event, viewer) { - if (this.protoLine != null) { - var intersects = viewer.raycast(event); - if (intersects.length > 0 && intersects[0].face.__TCAD_polyFace == this.workArea) { - var p = intersects[0].point; - var vertices = this.protoLine.geometry.vertices; - vertices[vertices.length - 1].x = p.x; - vertices[vertices.length - 1].y = p.y; - vertices[vertices.length - 1].z = p.z; - this.protoLine.geometry.verticesNeedUpdate = true; - viewer.render(); - } - } -}; - - -TCAD.LineTool.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.createSolidMesh(TCAD.geom.extrude(_2d, n.multiply(1.1))); -// this.workArea.sketch.group.parent.add(solid); -}; diff --git a/web/app/3d/wizards/wizards.js b/web/app/3d/wizards/wizards.js index 98738c29..ce1f45ff 100644 --- a/web/app/3d/wizards/wizards.js +++ b/web/app/3d/wizards/wizards.js @@ -81,3 +81,60 @@ TCAD.wizards.ExtrudeWizard.prototype.update = function(basis, normal, depth, sca expansionFactor : scale } }; + + +TCAD.wizards.PlaneWizard = function(viewer) { + this.previewGroup = new THREE.Object3D(); + this.viewer = viewer; + viewer.scene.add(this.previewGroup); + this.previewGroup.add(this.plane = this.createPlane()); + this.viewer.render(); + this.operationParams = { + basis : TCAD.math.IDENTITY_BASIS, + depth : 0 + }; +}; + +TCAD.wizards.PlaneWizard.prototype.createPlane = function() { + var geometry = new THREE.PlaneGeometry(750,750,1,1,1); + var material = new THREE.MeshLambertMaterial( { color : TCAD.view.FACE_COLOR, transparent: true, opacity:0.5, side: THREE.DoubleSide }); + var plane = new THREE.Mesh(geometry, material); + return plane; +}; + +TCAD.wizards.PlaneWizard.prototype.update = function(orientation, w) { + if (orientation === 'XY') { + this.plane.rotation.x = 0; + this.plane.rotation.y = 0; + this.plane.rotation.z = 0; + this.plane.position.x = 0; + this.plane.position.y = 0; + this.plane.position.z = w; + this.operationParams.basis = TCAD.math.IDENTITY_BASIS; + } else if (orientation === 'XZ') { + this.plane.rotation.x = Math.PI / 2; + this.plane.rotation.y = 0; + this.plane.rotation.z = 0; + this.plane.position.x = 0; + this.plane.position.y = w; + this.plane.position.z = 0; + this.operationParams.basis = [TCAD.math.AXIS.X, TCAD.math.AXIS.Z, TCAD.math.AXIS.Y]; + } else if (orientation === 'ZY') { + this.plane.rotation.x = 0; + this.plane.rotation.y = Math.PI / 2; + this.plane.rotation.z = 0; + this.plane.position.x = w; + this.plane.position.y = 0; + this.plane.position.z = 0; + this.operationParams.basis = [TCAD.math.AXIS.Z, TCAD.math.AXIS.Y, TCAD.math.AXIS.X]; + } else { + throw orientation + " isn't supported yet"; + } + this.operationParams.depth = w; + this.viewer.render(); +}; + +TCAD.wizards.PlaneWizard.prototype.dispose = function() { + this.viewer.scene.remove(this.previewGroup); + this.viewer.render(); +}; \ No newline at end of file diff --git a/web/app/engine.js b/web/app/engine.js index 1ffdb860..9991e552 100644 --- a/web/app/engine.js +++ b/web/app/engine.js @@ -105,20 +105,80 @@ TCAD.utils.createLine = function (a, b, color) { return new THREE.Line(geometry, material); }; -TCAD.utils.createSolidMesh = function(csg) { - var material = new THREE.MeshPhongMaterial({ +TCAD.utils.createSolidMaterial = function() { + return new THREE.MeshPhongMaterial({ vertexColors: THREE.FaceColors, color: TCAD.view.FACE_COLOR, shininess: 0, polygonOffset : true, polygonOffsetFactor : 4, polygonOffsetUnits : 1 - }); +}; + +TCAD.utils.createSolidMesh = function(csg) { + var material = TCAD.utils.createSolidMaterial(); var geometry = new TCAD.Solid(csg, material); return geometry.meshObject; }; +TCAD.utils.intercept = function(obj, methodName, aspect) { + var originFunc = obj[methodName]; + obj[methodName] = function() { + var $this = this; + aspect(function() {originFunc.apply($this, arguments)}, arguments); + } +}; + +TCAD.utils.createPlane = function(basis, depth, boundingPolygon, shared) { + var tu = TCAD.utils; + + boundingPolygon = boundingPolygon || TCAD.utils.createSquare(800); + shared = shared || tu.createShared(); + + var material = tu.createSolidMaterial(); + material.transparent = true; + material.opacity = 0.5; + material.side = THREE.DoubleSide; + + var tr = new TCAD.Matrix().setBasis(basis); + var shift = basis[2].multiply(depth); + tr.tx = shift.x; + tr.ty = shift.y; + tr.tz = shift.z; + + var currentBounds = new TCAD.BBox(); + var points = boundingPolygon.map(function(p) { currentBounds.checkBounds(p.x, p.y); return tr._apply(p); }); + var polygon = new CSG.Polygon(points.map(function(p){return new CSG.Vertex(TCAD.utils.csgVec(p))}), shared); + var plane = new TCAD.Solid(CSG.fromPolygons([polygon]), material); + plane.wireframeGroup.visible = false; + plane.mergeable = false; + + var sketchFace = plane.polyFaces[0]; + tu.intercept(sketchFace, 'syncSketches', function(invocation, args) { + var geom = args[0]; + invocation(geom); + var bbox = new TCAD.BBox(); + var connections = geom.connections.concat(TCAD.utils.arrFlatten1L(geom.loops)); + for (var i = 0; i < connections.length; ++i) { + var l = connections[i]; + bbox.checkBounds(l.a.x, l.a.y); + bbox.checkBounds(l.b.x, l.b.y); + } + if (bbox.maxX > currentBounds.maxX || bbox.maxY > currentBounds.maxY || bbox.minX < currentBounds.minX || bbox.minY < currentBounds.minY) { + var parent = plane.meshObject.parent; + plane.vanish(); + bbox.expand(20); + var newPlane = TCAD.utils.createPlane(basis, depth, bbox.toPolygon(), sketchFace.csgGroup.shared); + TCAD.SketchFace.prototype.syncSketches.call(newPlane.geometry.polyFaces[0], geom); + parent.add(newPlane); + } + }); + + return plane.meshObject; +}; + + TCAD.utils.fixCCW = function(path, normal) { var _2DTransformation = new TCAD.Matrix().setBasis(TCAD.geom.someBasis(path, normal)).invert(); var path2D = []; @@ -354,6 +414,30 @@ TCAD.BBox = function() { this.center = function() { return new TCAD.Vector(this.minX + (this.maxX - this.minX) / 2, this.minY + (this.maxY - this.minY) / 2, 0) }; + + this.width = function() { + return this.maxX - this.minX; + }; + + this.height = function() { + return this.maxY - this.minY; + }; + + this.expand = function(delta) { + this.minX -= delta; + this.minY -= delta; + this.maxX += delta; + this.maxY += delta; + }; + + this.toPolygon = function() { + return [ + new TCAD.Vector(this.minX, this.minY, 0), + new TCAD.Vector(this.maxX, this.minY, 0), + new TCAD.Vector(this.maxX, this.maxY, 0), + new TCAD.Vector(this.minX, this.maxY, 0) + ]; + } }; TCAD.geom.calculateExtrudedLid = function(sourcePolygon, normal, direction, expansionFactor) { @@ -523,6 +607,7 @@ TCAD.Solid = function(csg, material) { this.polyFaces = []; this.wires = TCAD.struct.hashTable.forEdge(); this.curvedSurfaces = {}; + this.mergeable = true; var scope = this; function threeV(v) {return new THREE.Vector3( v.x, v.y, v.z )} @@ -571,6 +656,12 @@ if (typeof THREE !== "undefined") { TCAD.Solid.prototype = Object.create( THREE.Geometry.prototype ); } +TCAD.Solid.prototype.vanish = function() { + this.meshObject.parent.remove( this.meshObject ); + this.meshObject.material.dispose(); + this.dispose(); +}; + TCAD.Solid.prototype.collectCurvedSurface = function(face) { var derivedFrom = TCAD.utils.getDerivedFrom(face.csgGroup.shared); if (derivedFrom === null || derivedFrom._class !== "TCAD.TWO.Arc" && derivedFrom._class !== "TCAD.TWO.Circle" ) return; diff --git a/web/app/math/math.js b/web/app/math/math.js index 3590bbbd..18ac4fd8 100644 --- a/web/app/math/math.js +++ b/web/app/math/math.js @@ -45,7 +45,9 @@ TCAD.math.AXIS = { X : new TCAD.Vector(1, 0, 0), Y : new TCAD.Vector(0, 1, 0), Z : new TCAD.Vector(0, 0, 1) -}; +}; + +TCAD.math.IDENTITY_BASIS = [TCAD.math.AXIS.X, TCAD.math.AXIS.Y, TCAD.math.AXIS.Z]; TCAD.math.rotateMatrix = function(angle, axis, pivot) { var sin = Math.sin(angle); diff --git a/web/app/ui/toolkit.js b/web/app/ui/toolkit.js index c4176782..72af0bf9 100644 --- a/web/app/ui/toolkit.js +++ b/web/app/ui/toolkit.js @@ -34,13 +34,37 @@ TCAD.toolkit.Button = function(title) { TCAD.toolkit.CheckBox = function(title, checked) { this.root = $('
', - {class: 'tc-row tc-ctrl tc-ctrl-btn'}); + {class: 'tc-row tc-ctrl'}); this.root.append('') this.input = this.root.find("input"); this.input.prop('checked', !!checked); - console.log(this.input); }; +TCAD.toolkit.InlineRadio = function(choiceLabels, choiceValues, checkedIndex) { + var name = 'TCAD.toolkit.InlineRadio_' + (TCAD.toolkit.InlineRadio.COUNTER++) + this.root = $('
', + {class: 'tc-row tc-ctrl tc-inline-radio'}); + this.inputs = []; + for (var i = 0; i < choiceLabels.length; i++) { + var checked = checkedIndex === i ? "checked" : ''; + var label = $(''); + this.inputs.push(label.find("input")); + this.root.append(label); + } + this.inputs[checkedIndex].prop('checked', true); +}; + +TCAD.toolkit.InlineRadio.prototype.getValue = function() { + for (var i = 0; i < this.inputs.length; i++) { + if (this.inputs[i].prop('checked')) { + return this.inputs[i].attr('value'); + } + } + return null; +}; + +TCAD.toolkit.InlineRadio.COUNTER = 0; + TCAD.toolkit.propLayout = function(root, name, valueEl) { root.append($('', {class: 'tc-prop-name', text: name})) .append($('
', {class: 'tc-prop-value'}) diff --git a/web/app/workbench.js b/web/app/workbench.js index f21a49e6..3f58ce9d 100644 --- a/web/app/workbench.js +++ b/web/app/workbench.js @@ -146,7 +146,12 @@ TCAD.craft.extrude = function(app, request) { toMeldWith = toMeldWith.concat(extruded); } - var meld = request.solids[0].csg.union(CSG.fromPolygons(TCAD.craft._triangulateCSG(toMeldWith))); + var solid = request.solids[0]; + + var meld = CSG.fromPolygons(TCAD.craft._triangulateCSG(toMeldWith)); + if (solid.mergeable) { + meld = solid.csg.union(meld); + } face.csgGroup.shared.__tcad.faceId += '$'; return [TCAD.utils.createSolidMesh(meld).geometry]; @@ -759,18 +764,17 @@ TCAD.Craft.prototype.modify = function(request) { var op = TCAD.craft.OPS[request.type]; if (!op) return; - var detachedRequest = TCAD.craft.detach(request); var newSolids = op(this.app, request); if (newSolids == null) return; var i; for (i = 0; i < request.solids.length; i++) { - this.app.viewer.scene.remove( request.solids[i].meshObject ); + request.solids[i].vanish(); } for (i = 0; i < newSolids.length; i++) { - this.app.viewer.scene.add(newSolids[i].meshObject); + this.app.viewer.workGroup.add(newSolids[i].meshObject); } - this.history.push(detachedRequest); + this.history.push(TCAD.craft.detach(request)); this.app.bus.notify('craft'); this.app.viewer.render(); @@ -779,6 +783,9 @@ TCAD.Craft.prototype.modify = function(request) { TCAD.craft.OPS = { CUT : TCAD.craft.cut, PAD : TCAD.craft.extrude, + PLANE : function(app, request) { + return [TCAD.utils.createPlane(request.params.basis, request.params.depth).geometry]; + }, BOX : function(app, request) { return [TCAD.utils.createCSGBox(request.size).geometry]; } diff --git a/web/css/toolkit.css b/web/css/toolkit.css index cf7711d0..6b46a754 100644 --- a/web/css/toolkit.css +++ b/web/css/toolkit.css @@ -126,3 +126,7 @@ .tc-buttons-block { text-align: right; } + +.tc-inline-radio label { + padding-right: 5px; +}