From 43780d3188aa6d578230350b701f48d8065d8388 Mon Sep 17 00:00:00 2001 From: Val Erastov Date: Thu, 16 Mar 2017 02:45:27 -0700 Subject: [PATCH] extrude operation on top of BREP framework --- web/app/3d/actions/operation-actions.js | 4 +- web/app/3d/craft/brep/cut-extrude.js | 51 ++++++++++---------- web/app/3d/craft/brep/wizards/cut-extrude.js | 4 +- web/app/3d/craft/mesh/wizards/extrude.js | 2 +- web/app/3d/craft/mesh/workbench.js | 2 +- web/app/3d/craft/operations.js | 6 +-- web/app/3d/menu/menu-config.js | 4 +- web/app/3d/modeler-app.js | 5 +- web/app/3d/sample.js | 2 +- web/app/3d/ui/ctrl.js | 12 ++--- web/app/3d/ui/keymaps/default.js | 2 +- web/app/3d/ui/modifications-panel.js | 5 +- web/app/brep/brep-builder.js | 20 +++++++- web/app/ui/toolkit.js | 6 ++- 14 files changed, 72 insertions(+), 53 deletions(-) diff --git a/web/app/3d/actions/operation-actions.js b/web/app/3d/actions/operation-actions.js index 3f807af1..432727fa 100644 --- a/web/app/3d/actions/operation-actions.js +++ b/web/app/3d/actions/operation-actions.js @@ -14,7 +14,7 @@ export const CUT = mergeInfo('CUT', { info: 'makes a cut based on 2D sketch' }); -export const PAD = mergeInfo('PAD', { +export const EXTRUDE = mergeInfo('EXTRUDE', { info: 'extrudes 2D sketch' }); @@ -55,7 +55,7 @@ export const IMPORT_STL = mergeInfo('IMPORT_STL', { }); requiresFaceSelection(CUT, 1); -requiresFaceSelection(PAD, 1); +requiresFaceSelection(EXTRUDE, 1); requiresFaceSelection(REVOLVE, 1); requiresSolidSelection(INTERSECTION, 2); diff --git a/web/app/3d/craft/brep/cut-extrude.js b/web/app/3d/craft/brep/cut-extrude.js index 241c13dc..18fdaf3a 100644 --- a/web/app/3d/craft/brep/cut-extrude.js +++ b/web/app/3d/craft/brep/cut-extrude.js @@ -1,9 +1,9 @@ -import {Matrix3, ORIGIN} from '../../../math/l3space' +import {Matrix3, BasisForPlane, ORIGIN} from '../../../math/l3space' import * as math from '../../../math/math' import Vector from '../../../math/vector' import {Extruder} from '../../../brep/brep-builder' import {BREPValidator} from '../../../brep/brep-validator' -import {subtract} from '../../../brep/operations/boolean' +import {subtract, union} from '../../../brep/operations/boolean' import {Loop} from '../../../brep/topo/loop' import {Shell} from '../../../brep/topo/shell' import {ReadSketchFromFace} from './sketch-reader' @@ -11,24 +11,25 @@ import {ReadSketchFromFace} from './sketch-reader' import {BREPSceneSolid} from '../../scene/brep-scene-object' export function Extrude(app, params) { - + return doOperation(app, params, false); } export function Cut(app, params) { + return doOperation(app, params, true); +} + +export function doOperation(app, params, cut) { const face = app.findFace(params.face); const solid = face.solid; - const sketch = ReadSketchFromFace(app, face); - //for (let polygon of sketch) { - // if (!Loop.isPolygonCCWOnSurface(polygon, face.brepFace.surface)) { - // polygon.reverse(); - // } - //} - - const extruder = new ParametricExtruder(face, params); - const cutter = combineCutters(sketch.map(s => extruder.extrude(s, face.brepFace.surface.normal))) ; - BREPValidator.validateToConsole(cutter); - const result = subtract(solid.shell, cutter); + const extruder = new ParametricExtruder(params); + let normal = face.brepFace.surface.normal; + if (!cut) normal = normal.negate(); + const operand = combineShells(sketch.map(s => extruder.extrude(s, normal))); + BREPValidator.validateToConsole(operand); + + const op = cut ? subtract : union; + const result = op(solid.shell, operand); for (let newFace of result.faces) { if (newFace.id == face.id) { newFace.id = undefined; @@ -41,30 +42,29 @@ export function Cut(app, params) { } } -function combineCutters(cutters) { - if (cutters.length == 1) { - return cutters[0]; +function combineShells(shells) { + if (shells.length == 1) { + return shells[0]; } const cutter = new Shell(); - cutters.forEach(c => c.faces.forEach(f => cutter.faces.push(f))); + shells.forEach(c => c.faces.forEach(f => cutter.faces.push(f))); return cutter; } export class ParametricExtruder extends Extruder { - constructor(face, params) { + constructor(params) { super(); - this.face = face; this.params = params; } prepareLidCalculation(baseNormal, lidNormal) { let target; + this.basis = BasisForPlane(baseNormal); if (this.params.rotation != 0) { - const basis = this.face.basis(); - target = Matrix3.rotateMatrix(this.params.rotation * Math.PI / 180, basis[0], ORIGIN).apply(lidNormal); + target = Matrix3.rotateMatrix(this.params.rotation * Math.PI / 180, this.basis[0], ORIGIN).apply(lidNormal); if (this.params.angle != 0) { - target = Matrix3.rotateMatrix(this.params.angle * Math.PI / 180, basis[2], ORIGIN)._apply(target); + target = Matrix3.rotateMatrix(this.params.angle * Math.PI / 180, this.basis[2], ORIGIN)._apply(target); } target._multiply(Math.abs(this.params.value)); } else { @@ -73,10 +73,11 @@ export class ParametricExtruder extends Extruder { this.target = target; } - calculateLid(basePoints) { + calculateLid(basePoints, baseNormal, lidNormal) { if (this.params.prism != 1) { const scale = this.params.prism; - const _3Dtr = this.face.brepFace.surface.get3DTransformation(); + + const _3Dtr = new Matrix3().setBasis(this.basis); const _2Dtr = _3Dtr.invert(); const poly2d = basePoints.map(p => _2Dtr.apply(p)); basePoints = math.polygonOffset(poly2d, scale).map(p => _3Dtr.apply(p)); diff --git a/web/app/3d/craft/brep/wizards/cut-extrude.js b/web/app/3d/craft/brep/wizards/cut-extrude.js index 3aa4c404..89704e34 100644 --- a/web/app/3d/craft/brep/wizards/cut-extrude.js +++ b/web/app/3d/craft/brep/wizards/cut-extrude.js @@ -27,7 +27,7 @@ export class CutWizard extends PreviewWizard { export class ExtrudeWizard extends PreviewWizard { constructor(app, initialState) { - super(app, 'EXTRUDE', METADATA, new ExtrudePreviewer(false), initialState) + super(app, 'EXTRUDE', METADATA, initialState) } createPreviewObject(app, params) { @@ -48,7 +48,7 @@ export class ExtrudePreviewer extends SketchBasedPreviewer { } createImpl(app, params, sketch, face) { - const parametricExtruder = new ParametricExtruder(face, params); + const parametricExtruder = new ParametricExtruder(params); const surface = face.brepFace.surface; const baseNormal = this.inversed ? surface.normal : surface.normal.negate(); diff --git a/web/app/3d/craft/mesh/wizards/extrude.js b/web/app/3d/craft/mesh/wizards/extrude.js index 2a8703f7..ed50a14c 100644 --- a/web/app/3d/craft/mesh/wizards/extrude.js +++ b/web/app/3d/craft/mesh/wizards/extrude.js @@ -96,7 +96,7 @@ ExtrudeWizard.prototype.getParams = function() { ExtrudeWizard.prototype.createRequest = function(done) { done({ - type : this.invert ? 'CUT' : 'PAD', + type : this.invert ? 'CUT' : 'EXTRUDE', solids : [this.app.findSolidByCadId(this.face.solid.tCadId)], face : this.app.findFace(this.face.id), params : this.operationParams, diff --git a/web/app/3d/craft/mesh/workbench.js b/web/app/3d/craft/mesh/workbench.js index 2a1b4e3b..6e7dfda2 100644 --- a/web/app/3d/craft/mesh/workbench.js +++ b/web/app/3d/craft/mesh/workbench.js @@ -793,7 +793,7 @@ function materialize(index, detachedConfig) { export const MESH_OPERATIONS = { CUT : cut, - PAD : extrude, + EXTRUDE : extrude, REVOLVE : performRevolve, PLANE : function(app, request) { let basis, depth = request.params.depth; diff --git a/web/app/3d/craft/operations.js b/web/app/3d/craft/operations.js index a8d3ca71..2d8c1d23 100644 --- a/web/app/3d/craft/operations.js +++ b/web/app/3d/craft/operations.js @@ -10,13 +10,11 @@ export const CUT = { action: (app, params) => Cut(app, params) }; -export const PAD = { +export const EXTRUDE = { icon: 'img/3d/extrude', label: 'Extrude', info: (p) => '(' + r(p.value) + ')', - action: (app, request) => { - - } + action: (app, params) => Extrude(app, params) }; export const REVOLVE = { diff --git a/web/app/3d/menu/menu-config.js b/web/app/3d/menu/menu-config.js index c29c4e66..38c39eb4 100644 --- a/web/app/3d/menu/menu-config.js +++ b/web/app/3d/menu/menu-config.js @@ -8,7 +8,7 @@ export const craft = { label: 'craft', cssIcons: ['magic'], info: 'set of available craft operations on a solid', - actions: ['PAD', 'CUT', 'REVOLVE', 'SHELL'] + actions: ['EXTRUDE', 'CUT', 'REVOLVE', 'SHELL'] }; export const primitives = { @@ -29,7 +29,7 @@ export const main = { label: 'start', cssIcons: ['rocket'], info: 'common set of actions', - actions: ['PAD', 'CUT', 'SHELL', '-', 'INTERSECTION', 'DIFFERENCE', 'UNION', '-', 'PLANE', 'BOX', 'SPHERE', '-', + actions: ['EXTRUDE', 'CUT', 'SHELL', '-', 'INTERSECTION', 'DIFFERENCE', 'UNION', '-', 'PLANE', 'BOX', 'SPHERE', '-', 'EditFace', '-', 'DeselectAll', 'RefreshSketches'] }; diff --git a/web/app/3d/modeler-app.js b/web/app/3d/modeler-app.js index aae543e7..55ac63c7 100644 --- a/web/app/3d/modeler-app.js +++ b/web/app/3d/modeler-app.js @@ -20,7 +20,6 @@ import '../../css/app3d.less' import * as BREPBuilder from '../brep/brep-builder' import * as BREPPrimitives from '../brep/brep-primitives' import * as BREPBool from '../brep/operations/boolean' -import * as BREPMeshBool from './craft/mesh/mesh-boolean' import {BREPValidator} from '../brep/brep-validator' import {BREPSceneSolid} from './scene/brep-scene-object' import TPI from './tpi' @@ -262,7 +261,7 @@ App.prototype.BREPMeshTestImpl = function() { //addToScene(box2); //addToScene(box3); - let result = BREPMeshBool.subtract(box1, box2); + //let result = BREPMeshBool.subtract(box1, box2); //result = BREPBool.subtract(result, box3); //this.addShellOnScene(result); //addToScene(box1); @@ -548,7 +547,7 @@ App.prototype.extrude = function() { var app = this; var solids = [polyFace.solid]; this.craft.modify({ - type: 'PAD', + type: 'EXTRUDE', solids : solids, face : polyFace, height : height diff --git a/web/app/3d/sample.js b/web/app/3d/sample.js index a1064db6..66a0f557 100644 --- a/web/app/3d/sample.js +++ b/web/app/3d/sample.js @@ -1,5 +1,5 @@ export function init() { - localStorage.setItem("TCAD.projects.sample", '{"history":[{"type":"PLANE","solids":[],"params":{"basis":[[1,0,0],[0,0,1],[0,1,0]],"depth":"0"},"protoParams":["XZ","0"]},{"type":"PAD","solids":[0],"face":"0:0","params":{"target":[0,-50,0],"expansionFactor":"1"},"protoParams":["50","1","0","0"]},{"type":"PAD","solids":[1],"face":"1:1","params":{"target":[0,-50,0],"expansionFactor":"1"},"protoParams":["50","1","0","0"]},{"type":"CUT","solids":[2],"face":"2:0","params":{"target":[0,252,0],"expansionFactor":"1"},"protoParams":["252","1","0","0"]},{"type":"CUT","solids":[3],"face":"1:1$","params":{"target":[0,50,0],"expansionFactor":"1"},"protoParams":["50","1","0","0"]}]}'); + localStorage.setItem("TCAD.projects.sample", '{"history":[{"type":"PLANE","solids":[],"params":{"basis":[[1,0,0],[0,0,1],[0,1,0]],"depth":"0"},"protoParams":["XZ","0"]},{"type":"EXTRUDE","solids":[0],"face":"0:0","params":{"target":[0,-50,0],"expansionFactor":"1"},"protoParams":["50","1","0","0"]},{"type":"EXTRUDE","solids":[1],"face":"1:1","params":{"target":[0,-50,0],"expansionFactor":"1"},"protoParams":["50","1","0","0"]},{"type":"CUT","solids":[2],"face":"2:0","params":{"target":[0,252,0],"expansionFactor":"1"},"protoParams":["252","1","0","0"]},{"type":"CUT","solids":[3],"face":"1:1$","params":{"target":[0,50,0],"expansionFactor":"1"},"protoParams":["50","1","0","0"]}]}'); localStorage.setItem("TCAD.projects.sample.sketch.0:0", '{"layers":[{"name":"_dim","style":{"lineWidth":1,"strokeStyle":"#bcffc1","fillStyle":"#00FF00"},"data":[]},{"name":"__bounds__","style":{"lineWidth":2,"strokeStyle":"#fff5c3","fillStyle":"#000000"},"data":[{"id":6,"_class":"TCAD.TWO.Segment","aux":true,"edge":0,"points":[[0,[1,-400],[2,400]],[3,[4,-400],[5,-400]]]},{"id":13,"_class":"TCAD.TWO.Segment","aux":true,"edge":2,"points":[[7,[8,-400],[9,-400]],[10,[11,400],[12,-400]]]},{"id":20,"_class":"TCAD.TWO.Segment","aux":true,"edge":4,"points":[[14,[15,400],[16,-400]],[17,[18,400],[19,400]]]},{"id":27,"_class":"TCAD.TWO.Segment","aux":true,"edge":6,"points":[[21,[22,400],[23,400]],[24,[25,-400],[26,400]]]}]},{"name":"sketch","style":{"lineWidth":2,"strokeStyle":"#ffffff","fillStyle":"#000000"},"data":[{"id":34,"_class":"TCAD.TWO.Segment","points":[[28,[29,-80.41502600578134],[30,240.48794311524324]],[31,[32,252.10163324769275],[33,71.15131239804411]]]},{"id":41,"_class":"TCAD.TWO.Segment","points":[[35,[36,255.946878629896],[37,-145.76094357167156]],[38,[39,-91.17342089039929],[40,-338.36716169336114]]]},{"id":48,"_class":"TCAD.TWO.Segment","points":[[42,[43,-172.00749593627577],[44,-240.71428346724593]],[45,[46,-88.51020843368133],[47,-140.46311545122035]]]},{"id":55,"_class":"TCAD.TWO.Segment","points":[[49,[50,-102.18982576106004],[51,18.31440664196805]],[52,[53,-182.7982464866314],[54,86.82364838151852]]]},{"id":72,"_class":"TCAD.TWO.Arc","points":[[63,[64,255.946878629896],[65,-145.76094357167156]],[66,[67,252.10163324769275],[68,71.15131239804411]],[69,[70,196.33682709088268],[71,-38.32745196977044]]]},{"id":83,"_class":"TCAD.TWO.Arc","points":[[74,[75,-80.41502600578134],[76,240.48794311524324]],[77,[78,-182.7982464866314],[79,86.82364838151852]],[80,[81,-122.59914075444685],[82,157.65429488839598]]]},{"id":94,"_class":"TCAD.TWO.Arc","points":[[85,[86,-88.51020843368133],[87,-140.46311545122035]],[88,[89,-102.18982576106004],[90,18.31440664196805]],[91,[92,-175.53398017227],[93,-67.98267439986091]]]},{"id":105,"_class":"TCAD.TWO.Arc","points":[[96,[97,-172.00749593627577],[98,-240.71428346724593]],[99,[100,-91.17342089039929],[101,-338.36716169336114]],[102,[103,-122.4591797419898],[104,-281.9821285194346]]]}]},{"name":"_construction_","style":{"lineWidth":1,"strokeStyle":"#aaaaaa","fillStyle":"#000000"},"data":[]}],"constraints":[["Tangent",[72,41]],["Tangent",[72,34]],["coi",[63,35]],["coi",[66,31]],["Tangent",[83,34]],["Tangent",[83,55]],["coi",[74,28]],["coi",[77,52]],["Tangent",[94,48]],["Tangent",[94,55]],["coi",[85,45]],["coi",[88,49]],["Tangent",[105,48]],["Tangent",[105,41]],["coi",[96,42]],["coi",[99,38]]],"boundary":{"lines":[{"a":{"x":-400,"y":400},"b":{"x":-400,"y":-400}},{"a":{"x":-400,"y":-400},"b":{"x":400,"y":-400}},{"a":{"x":400,"y":-400},"b":{"x":400,"y":400}},{"a":{"x":400,"y":400},"b":{"x":-400,"y":400}}],"arcs":[],"circles":[]}}'); localStorage.setItem("TCAD.projects.sample.sketch.1:0", '{"boundary":{"lines":[{"a":{"x":80.41502600578134,"y":240.48794311524324},"b":{"x":-252.10163324769275,"y":71.15131239804411}},{"a":{"x":-255.946878629896,"y":-145.76094357167156},"b":{"x":91.17342089039929,"y":-338.36716169336114}},{"a":{"x":172.00749593627577,"y":-240.71428346724593},"b":{"x":88.51020843368133,"y":-140.46311545122035}},{"a":{"x":102.18982576106004,"y":18.31440664196805},"b":{"x":182.7982464866314,"y":86.82364838151852}}],"arcs":[{"a":{"x":-252.10163324769275,"y":71.15131239804411},"b":{"x":-255.946878629896,"y":-145.76094357167156},"c":{"x":-196.33682672526209,"y":-38.32745176660378}},{"a":{"x":91.17342089039929,"y":-338.36716169336114},"b":{"x":172.00749593627577,"y":-240.71428346724593},"c":{"x":122.45917974196499,"y":-281.98212851943595}},{"a":{"x":102.18982576106004,"y":18.31440664196805},"b":{"x":88.51020843368133,"y":-140.46311545122035},"c":{"x":175.5339801724776,"y":-67.98267439979745}},{"a":{"x":182.7982464866314,"y":86.82364838151852},"b":{"x":80.41502600578134,"y":240.48794311524324},"c":{"x":122.59914075460381,"y":157.65429488902345}}],"circles":[]}}'); localStorage.setItem("TCAD.projects.sample.sketch.1:1", '{"layers":[{"name":"_dim","style":{"lineWidth":1,"strokeStyle":"#bcffc1","fillStyle":"#00FF00"},"data":[]},{"name":"__bounds__","style":{"lineWidth":2,"strokeStyle":"#fff5c3","fillStyle":"#000000"},"data":[{"id":6,"_class":"TCAD.TWO.Segment","aux":true,"edge":0,"points":[[0,[1,-91.17342089039929],[2,-338.36716169336114]],[3,[4,255.946878629896],[5,-145.76094357167156]]]},{"id":13,"_class":"TCAD.TWO.Segment","aux":true,"edge":2,"points":[[7,[8,252.10163324769275],[9,71.15131239804411]],[10,[11,-80.41502600578134],[12,240.48794311524324]]]},{"id":20,"_class":"TCAD.TWO.Segment","aux":true,"edge":4,"points":[[14,[15,-182.7982464866314],[16,86.82364838151852]],[17,[18,-102.18982576106004],[19,18.31440664196805]]]},{"id":27,"_class":"TCAD.TWO.Segment","aux":true,"edge":6,"points":[[21,[22,-88.51020843368133],[23,-140.46311545122035]],[24,[25,-172.00749593627577],[26,-240.71428346724593]]]},{"id":37,"_class":"TCAD.TWO.Arc","aux":true,"edge":8,"points":[[28,[29,255.946878629896],[30,-145.76094357167156]],[31,[32,252.10163324769275],[33,71.15131239804411]],[34,[35,196.33682672526209],[36,-38.32745176660376]]]},{"id":48,"_class":"TCAD.TWO.Arc","aux":true,"edge":10,"points":[[39,[40,-80.41502600578134],[41,240.48794311524324]],[42,[43,-182.7982464866314],[44,86.82364838151852]],[45,[46,-122.59914075460384],[47,157.65429488902345]]]},{"id":59,"_class":"TCAD.TWO.Arc","aux":true,"edge":12,"points":[[50,[51,-88.51020843368133],[52,-140.46311545122035]],[53,[54,-102.18982576106004],[55,18.31440664196805]],[56,[57,-175.5339801724776],[58,-67.98267439979745]]]},{"id":70,"_class":"TCAD.TWO.Arc","aux":true,"edge":14,"points":[[61,[62,-172.00749593627577],[63,-240.71428346724593]],[64,[65,-91.17342089039929],[66,-338.36716169336114]],[67,[68,-122.45917974196257],[69,-281.982128519434]]]}]},{"name":"sketch","style":{"lineWidth":2,"strokeStyle":"#ffffff","fillStyle":"#000000"},"data":[{"id":75,"_class":"TCAD.TWO.Circle","c":[72,[73,-122.59914075460384],[74,157.65429488902345]],"r":92.9565103454672},{"id":77,"_class":"TCAD.TWO.EndPoint","location":[77,[78,30.202166630027865],[79,-54.24889318543422]]},{"id":83,"_class":"TCAD.TWO.Circle","c":[80,[81,-122.45917974196257],[82,-281.982128519434]],"r":64.48310377876552}]},{"name":"_construction_","style":{"lineWidth":1,"strokeStyle":"#aaaaaa","fillStyle":"#000000"},"data":[]}],"constraints":[["RR",[48,75]],["coi",[72,45]],["coi",[80,67]],["RR",[83,70]]]}'); diff --git a/web/app/3d/ui/ctrl.js b/web/app/3d/ui/ctrl.js index 52fff4bc..7bed6980 100644 --- a/web/app/3d/ui/ctrl.js +++ b/web/app/3d/ui/ctrl.js @@ -6,9 +6,8 @@ import ToolBar from './toolbar' import * as MenuConfig from '../menu/menu-config' import * as Operations from '../craft/operations' import Menu from '../menu/menu' -import {CutWizard} from '../craft/brep/wizards/cut-extrude' +import {ExtrudeWizard, CutWizard} from '../craft/brep/wizards/cut-extrude' -import {ExtrudeWizard as MeshExtrudeWizard} from '../craft/mesh/wizards/extrude' import {RevolveWizard} from '../craft/mesh/wizards/revolve' import {PlaneWizard} from '../craft/mesh/wizards/plane' import {BoxWizard} from '../craft/brep/wizards/box' @@ -45,7 +44,7 @@ function UI(app) { var ui = this; this.app.bus.subscribe("showSketches", (enabled) => { - var solids = app.findAllSolids(); + var solids = app.findAllSolidsOnScene(); for (var i = 0; i < solids.length; i++) { for (var j = 0; j < solids[i].sceneFaces.length; j++) { var face = solids[i].sceneFaces[j]; @@ -73,12 +72,11 @@ UI.prototype.createCraftToolBar = function (vertPos) { var toolBar = new ToolBar(this.app); toolBar.add(this.app.actionManager.actions['PLANE']); toolBar.add(this.app.actionManager.actions['EditFace']); - toolBar.add(this.app.actionManager.actions['PAD']); + toolBar.add(this.app.actionManager.actions['EXTRUDE']); toolBar.add(this.app.actionManager.actions['CUT']); toolBar.add(this.app.actionManager.actions['REVOLVE']); - $('#viewer-container').append(toolBar.node); toolBar.node.css({left: '10px',top : vertPos + 'px'}); return toolBar; @@ -172,8 +170,8 @@ UI.prototype.createWizard = function(type, overridingHistory, initParams, face) let wizard = null; if ('CUT' === type) { wizard = new CutWizard(this.app, initParams); - } else if ('PAD' === type) { - wizard = new MeshExtrudeWizard(this.app, face, false, initParams); + } else if ('EXTRUDE' === type) { + wizard = new ExtrudeWizard(this.app, initParams); } else if ('REVOLVE' === type) { wizard = new RevolveWizard(this.app, face, initParams); } else if ('PLANE' === type) { diff --git a/web/app/3d/ui/keymaps/default.js b/web/app/3d/ui/keymaps/default.js index 8299d375..27d71b53 100644 --- a/web/app/3d/ui/keymaps/default.js +++ b/web/app/3d/ui/keymaps/default.js @@ -1,7 +1,7 @@ export const keymap = { 'CUT': 'C', - 'PAD': 'E', + 'EXTRUDE': 'E', 'ZoomIn': '+', 'ZoomOut': '-', 'menu.craft': 'shift+C', diff --git a/web/app/3d/ui/modifications-panel.js b/web/app/3d/ui/modifications-panel.js index 1fc420d6..45a987d6 100644 --- a/web/app/3d/ui/modifications-panel.js +++ b/web/app/3d/ui/modifications-panel.js @@ -41,7 +41,10 @@ ModificationsPanel.prototype.updateList = function() { id : i, info: this.app.ui.getInfoForOp(op), OnBind : (dom, data) => { - dom.css('background-image', 'url('+ getIconForOp(op)+')'); + const icon = getIconForOp(op); + if (icon) { + dom.css('background-image', 'url('+ icon+')'); + } if (!op.face) { dom.find('.require-face').addClass('action-disabled'); } diff --git a/web/app/brep/brep-builder.js b/web/app/brep/brep-builder.js index 2face889..a729e261 100644 --- a/web/app/brep/brep-builder.js +++ b/web/app/brep/brep-builder.js @@ -6,8 +6,23 @@ import {HalfEdge, Edge} from './topo/edge' import {Line} from './geom/impl/line' import {Plane} from './geom/impl/plane' import {Point} from './geom/point' +import {BasisForPlane, Matrix3} from '../math/l3space' import * as cad_utils from '../3d/cad-utils' +import * as math from '../math/math' +function isCCW(points, normal) { + const tr2d = new Matrix3().setBasis(BasisForPlane(normal)).invert(); + const points2d = points.map(p => tr2d.apply(p)); + return math.isCCW(points2d); +} + +function checkCCW(points, normal) { + if (!isCCW(points, normal)) { + points = points.slice(); + points.reverse(); + } + return points; +} export function createPrism(basePoints, height) { return new SimpleExtruder(height).extrude(basePoints, cad_utils.normalOfCCWSeq(basePoints)); @@ -21,8 +36,9 @@ export class Extruder { calculateLid(basePoints) { throw 'not implemented'; } - + extrude(basePoints, normal) { + basePoints = checkCCW(basePoints, normal); const baseLoop = createPlaneLoop(basePoints.map(p => new Vertex(p))); const baseFace = createPlaneFace(normal, baseLoop); const lidNormal = normal.multiply(-1); @@ -30,7 +46,7 @@ export class Extruder { this.prepareLidCalculation(normal, lidNormal); //iterateSegments(basePoints.map(p => new Vertex(p.plus(offVector))), (a, b) => lidSegments.push({a, b})); - const lidPoints = this.calculateLid(basePoints).reverse(); + const lidPoints = this.calculateLid(basePoints, normal, lidNormal).reverse(); const lidLoop = createPlaneLoop(lidPoints.map(p => new Vertex(p))); const shell = new Shell(); diff --git a/web/app/ui/toolkit.js b/web/app/ui/toolkit.js index ddb93972..c9c8fead 100644 --- a/web/app/ui/toolkit.js +++ b/web/app/ui/toolkit.js @@ -299,7 +299,11 @@ Bus.prototype.notify = function(event, data, sender) { const callback = listenerList[i][0]; const listenerId = listenerList[i][1]; if (sender == undefined || listenerId == null || listenerId != sender) { - callback(data); + try { + callback(data); + } catch(e) { + console.error(e); + } } } }