diff --git a/web/app/3d/ctrl.js b/web/app/3d/ctrl.js index 49f4f986..a9b6ea03 100644 --- a/web/app/3d/ctrl.js +++ b/web/app/3d/ctrl.js @@ -2,6 +2,27 @@ TCAD.UI = function(app) { this.app = app; this.viewer = app.viewer; + + var box = new TCAD.toolkit.Box(); + var propFolder = new TCAD.toolkit.Folder("Solid's Properties"); + var cameraFolder = new TCAD.toolkit.Folder("Camera"); + var objectsFolder = new TCAD.toolkit.Folder("Objects"); + var modificationsFolder = new TCAD.toolkit.Folder("Modifications"); + TCAD.toolkit.add(box, propFolder); + TCAD.toolkit.add(propFolder, new TCAD.toolkit.Button("Extrude")); + TCAD.toolkit.add(propFolder, new TCAD.toolkit.Button("Cut")); + TCAD.toolkit.add(propFolder, new TCAD.toolkit.Button("Edit")); + TCAD.toolkit.add(propFolder, new TCAD.toolkit.Button("Refresh Sketches")); + TCAD.toolkit.add(propFolder, new TCAD.toolkit.Text("Message")); + TCAD.toolkit.add(box, cameraFolder); + TCAD.toolkit.add(cameraFolder, new TCAD.toolkit.Number("x")); + TCAD.toolkit.add(cameraFolder, new TCAD.toolkit.Number("y")); + TCAD.toolkit.add(cameraFolder, new TCAD.toolkit.Number("z")); + TCAD.toolkit.add(box, objectsFolder); + TCAD.toolkit.add(box, modificationsFolder); + this.modificationsTreeComp = new TCAD.toolkit.Tree(); + TCAD.toolkit.add(cameraFolder, this.modificationsTreeComp); + this.dat = new dat.GUI(); var ui = this; var gui = this.dat; diff --git a/web/app/3d/main.js b/web/app/3d/main.js index d527df48..06866b5b 100644 --- a/web/app/3d/main.js +++ b/web/app/3d/main.js @@ -156,10 +156,15 @@ TCAD.App.prototype.extrude = function() { } var polyFace = this.viewer.selectionMgr.selection[0]; var height = prompt("Height", "50"); - + if (!height) return; + var app = this; - this.craft.modify(polyFace.solid, function() { - return TCAD.craft.extrude(app, polyFace, polyFace.solid.polyFaces, height); + var solids = [polyFace.solid]; + this.craft.modify({ + type: 'PAD', + solids : solids, + face : polyFace, + height : height }); }; @@ -170,12 +175,16 @@ TCAD.App.prototype.cut = function() { } var polyFace = this.viewer.selectionMgr.selection[0]; var depth = prompt("Depth", "50"); + if (!depth) return; var app = this; - this.craft.modify(polyFace.solid, function() { - return TCAD.craft.cut(app, polyFace, polyFace.solid.polyFaces, depth); + var solids = [polyFace.solid]; + this.craft.modify({ + type: 'CUT', + solids : solids, + face : polyFace, + depth : depth }); - }; TCAD.App.prototype.refreshSketches = function() { diff --git a/web/app/engine.js b/web/app/engine.js index 331ecfc9..66eb323f 100644 --- a/web/app/engine.js +++ b/web/app/engine.js @@ -107,6 +107,12 @@ TCAD.utils.fixCCW = function(path, normal) { return path; }; +TCAD.utils.addAll = function(arr, arrToAdd) { + for (var i = 0; i < arrToAdd.length; i++) { + arr.push(arrToAdd[i]); + } +}; + TCAD.TOLERANCE = 1E-6; TCAD.utils.areEqual = function(v1, v2, tolerance) { @@ -320,7 +326,7 @@ TCAD.geom.extrude = function(source, target) { return poly; }; -TCAD.geom.FACE_COUNTER = 0; +TCAD.geom.SOLID_COUNTER = 0; /** @constructor */ TCAD.Solid = function(polygons, material) { @@ -329,6 +335,9 @@ TCAD.Solid = function(polygons, material) { this.meshObject = new THREE.Mesh(this, material); + this.id = TCAD.geom.SOLID_COUNTER ++; + this.faceCounter = 0; + this.polyFaces = []; var scope = this; function pushVertices(vertices) { @@ -423,7 +432,7 @@ TCAD.SketchFace = function(solid, poly) { var proto = poly.__face; poly.__face = this; if (proto === undefined) { - this.id = TCAD.geom.FACE_COUNTER++; + this.id = solid.id + ":" + (solid.faceCounter++); this.sketchGeom = null; } else { this.id = proto.id; diff --git a/web/app/ui/toolkit.js b/web/app/ui/toolkit.js new file mode 100644 index 00000000..f79ba70a --- /dev/null +++ b/web/app/ui/toolkit.js @@ -0,0 +1,62 @@ +TCAD.toolkit = {}; + +TCAD.toolkit.add = function(parent, child) { + parent.content.append(child.root); +}; + +TCAD.toolkit.Box = function() { + this.root = this.content = $('
'); + this.root.addClass('tc-box'); + this.root.appendTo('body'); +}; + +TCAD.toolkit.Folder = function(title) { + this.root = $('
', {class: 'tc-folder'}); + this.content = $('
', {class: 'tc-scroll'}); + this.root.append($('
', {text: title, class: 'tc-row tc-title'})); + this.root.append(this.content); +}; + +TCAD.toolkit.Button = function(title) { + this.root = $('
', + {class: 'tc-row tc-ctrl tc-ctrl-btn', text: title}); +}; + +TCAD.toolkit.propLayout = function(root, name, valueEl) { + root.append($('', {class: 'tc-prop-name', text: name})) + .append($('
', {class: 'tc-prop-value'}) + .append(valueEl)); +}; + +TCAD.toolkit.Number = function(name) { + this.root = $('
', {class: 'tc-row tc-ctrl tc-ctrl-number'}); + TCAD.toolkit.propLayout(this.root, name, $('')) +}; + +TCAD.toolkit.Text = function(name) { + this.root = $('
', {class: 'tc-row tc-ctrl tc-ctrl-text'}); + TCAD.toolkit.propLayout(this.root, name, $('')) +}; + +TCAD.toolkit.Tree = function() { + this.root = $('
', {class: 'tc-tree'}); +}; + +TCAD.toolkit.Tree.prototype.set = function(data) { + this.root.empty(); + this._fill(this.root, data.children); +}; + +TCAD.toolkit.Tree.prototype._fill = function(parent, data) { + parent.append($('
', {text : data.name})); + if (data.children !== undefined && data.children.length !== 0) { + var ul = $('
    '); + parent.append(ul); + for (var i = 0; i < data.children.length; i++) { + var li = $('
  • '); + ul.append(li); + var child = data.children[i]; + this._fill(li, child); + } + } +}; diff --git a/web/app/workbench.js b/web/app/workbench.js index 7eb19b10..4a532765 100644 --- a/web/app/workbench.js +++ b/web/app/workbench.js @@ -72,38 +72,6 @@ TCAD.workbench.serializeSolid = function(solid) { return data; }; -TCAD.workbench.applyHistory = function(history) { - - for (var hi = 0; hi < history.length; ++hi) { - var mod = history[hi]; - switch (mod.operation) { - } - - } -}; - -TCAD.workbench.Cut = function() { - - this.depth = null; - - this.load = function(data) { - this.depth = data.depth; - }; - - this.save = function() { - return { - depth : this.depth - }; - }; - - this.apply = function(app, face, faces) { - TCAD.craft.cut(app, face, faces, this.depth); - }; -}; - -TCAD.workbench.Cut.prototype.TYPE = 'CUT'; - - TCAD.craft = {}; TCAD.craft.getSketchedPolygons3D = function(app, face) { @@ -142,16 +110,18 @@ TCAD.craft.getSketchedPolygons3D = function(app, face) { return sketchedPolygons; }; -TCAD.craft.extrude = function(app, face, faces, height) { +TCAD.craft.extrude = function(app, request) { + var face = request.face; var sketchedPolygons = TCAD.craft.getSketchedPolygons3D(app, face); if (sketchedPolygons == null) return null; - var newSolidFaces = []; + var faces = TCAD.craft.collectFaces(request.solids); + var normal = face.polygon.normal; var toMeldWith = []; for (var i = 0; i < sketchedPolygons.length; i++) { - var extruded = TCAD.geom.extrude(sketchedPolygons[i], normal.multiply(height)); + var extruded = TCAD.geom.extrude(sketchedPolygons[i], normal.multiply(request.height)); toMeldWith = toMeldWith.concat(TCAD.craft._makeFromPolygons(extruded)); } var work = TCAD.craft._makeFromPolygons(faces.map(function(f){ return f.polygon })); @@ -218,7 +188,7 @@ TCAD.craft._mergeCSGPolygons = function (__cgsPolygons, allPoints) { vertices: cp.vertices.map(function (cv) { return vec(cv.pos) }), - csgInfo : cp.shared.__tcad, + shared : cp.shared.__tcad, normal: vec(cp.plane.normal), w: cp.plane.w }; @@ -450,7 +420,7 @@ TCAD.craft._mergeCSGPolygons = function (__cgsPolygons, allPoints) { vertices : path, normal : csgData.normal, w : csgData.w, - csgInfo : csgData.csgInfo + shared : csgData.shared }); } } @@ -526,7 +496,10 @@ TCAD.craft._makeFromPolygons = function(polygons) { } var pid = poly.id; var shared = new CSG.Polygon.Shared([pid, pid, pid, pid]); - shared.__tcad = poly.csgInfo; + shared.__tcad = { + csgInfo : poly.csgInfo, + face : poly.__face + }; var refs = poly.triangulate(); for ( var i = 0; i < refs.length; ++ i ) { var a = refs[i][0] + off; @@ -628,7 +601,7 @@ TCAD.craft.reconstruct = function (cut) { return { vertices : path.vertices.map(function(v) {return tr.apply(v);}), normal : path.normal, - csgInfo : path.csgInfo + shared : path.shared } }); @@ -715,7 +688,10 @@ TCAD.craft.reconstruct = function (cut) { var p = new TCAD.Polygon(path.vertices, path.holes.map(function (path) { return path.vertices }), path.normal); - p.csgInfo = path.csgInfo; + if (path.shared !== undefined) { + p.csgInfo = path.shared.csgInfo; + p.__face = path.shared.face; + } return p; }) ); @@ -724,17 +700,25 @@ TCAD.craft.reconstruct = function (cut) { return result; }; -TCAD.craft.cut = function(app, face, faces, depth) { +TCAD.craft.collectFaces = function(solids) { + var faces = []; + for (var i = 0; i < solids.length; i++) { + TCAD.utils.addAll(faces, solids[i].polyFaces); + } + return faces; +}; +TCAD.craft.cut = function(app, request) { + var face = request.face; var sketchedPolygons = TCAD.craft.getSketchedPolygons3D(app, face); if (sketchedPolygons == null) return null; - var newSolidFaces = []; + var faces = TCAD.craft.collectFaces(request.solids); var normal = face.polygon.normal; var cutter = []; for (var i = 0; i < sketchedPolygons.length; i++) { - var extruded = TCAD.geom.extrude(sketchedPolygons[i], normal.multiply( - depth)); + var extruded = TCAD.geom.extrude(sketchedPolygons[i], normal.multiply( - request.depth)); cutter = cutter.concat(TCAD.craft._makeFromPolygons(extruded)); } var work = TCAD.craft._makeFromPolygons(faces.map(function(f){ return f.polygon })); @@ -754,15 +738,45 @@ TCAD.Craft = function(app) { TCAD.Craft.prototype.current = function() { return this.history[this.history.length - 1]; }; - -TCAD.Craft.prototype.modify = function(solid, modification) { - var faces = modification(); - if (faces == null) return; - this.app.viewer.scene.remove( solid.meshObject ); - this.app.viewer.scene.add(TCAD.utils.createSolidMesh(faces)); +TCAD.craft.detach = function(request) { + var detachedConfig = {}; + for (var prop in request) { + if (request.hasOwnProperty(prop)) { + var value = request[prop]; + if (typeof(value) === 'object' && value.id !== undefined) { + detachedConfig[prop] = value.id; + } else { + detachedConfig[prop] = value; + } + } + } + return detachedConfig +}; + +TCAD.Craft.prototype.modify = function(request) { + + var op = TCAD.craft.OPS[request.type]; + if (!op) return; + + var detachedRequest = TCAD.craft.detach(request); + var newFaces = op(this.app, request); + + if (newFaces == null) return; + for (var i = 0; i < request.solids.length; i++) { + var solid = request.solids[i]; + this.app.viewer.scene.remove( solid.meshObject ); + } + this.app.viewer.scene.add(TCAD.utils.createSolidMesh(newFaces)); + this.history.push(detachedRequest); + this.app.bus.notify('operation'); //REMOVE IT this.app._refreshSketches(); this.app.viewer.render(); }; + +TCAD.craft.OPS = { + CUT : TCAD.craft.cut, + PAD : TCAD.craft.extrude +}; diff --git a/web/css/toolkit.css b/web/css/toolkit.css new file mode 100644 index 00000000..a1b34807 --- /dev/null +++ b/web/css/toolkit.css @@ -0,0 +1,99 @@ + +.tc-box { + position: absolute; + margin-left: 0; margin-top: 0; + top: 0; left: 0; + width : 250px; height: 300px; + background-color: #000; +} + +.tc-row { + height: 27px; + line-height: 27px; + overflow: hidden; + padding: 0 4px 0 5px; + border-bottom: 1px solid #2c2c2c; +} + +.tc-title { + padding-left: 16px; + background: black url(data:image/gif;base64,R0lGODlhBQAFAJEAAP////Pz8////////yH5BAEAAAIALAAAAAAFAAUAAAIIlI+hKgFxoCgAOw==) 6px 10px no-repeat; + cursor: pointer; +} + +.tc-folder { + color: #eee; + font: 11px 'Lucida Grande', sans-serif; + background-color: #1a1a1a; +} + +.tc-ctrl { + border-left: 3px solid #e61d5f; +} + +.tc-ctrl-btn { + border-left: 3px solid #e61d5f; + cursor: pointer; +} + +.tc-ctrl-btn:hover { + background-color: #000; +} + +.tc-prop-name { + cursor: default; + float: left; + clear: left; + width: 40%; + overflow: hidden; + text-overflow: ellipsis; +} + +.tc-prop-value { + float: left; + width: 60%; +} + +.tc-ctrl input[type=text] { + color: #2fa1d6; + background: #303030; + outline: none; + border: 0; + margin-top: 4px; + padding: 3px; + width: 100%; + float: right; +} + +.tc-ctrl-text input[type=text] { + color:#1ed36f; +} + +.tc-ctrl input[type=text]:focus { + color: #eee; +} + +.tc-scroll { + overflow-y: auto; + overflow-x: hidden; +} + +.tc-scroll::-webkit-scrollbar { + width: 2px; +} + +.tc-scroll::-webkit-scrollbar-track { + background:#eee; + border: thin solid lightgray; + box-shadow: 0px 0px 3px #dfdfdf inset; + border-radius:10px; +} +.tc-scroll::-webkit-scrollbar-thumb { + background:#999; + border: thin solid gray; + border-radius:10px; +} + +.tc-scroll::-webkit-scrollbar-thumb:hover { + background:#7d7d7d; +} diff --git a/web/index.html b/web/index.html index 32d18711..ce488e0f 100644 --- a/web/index.html +++ b/web/index.html @@ -8,7 +8,10 @@ overflow: hidden; } + + + @@ -24,6 +27,7 @@ +