diff --git a/web/app/cad/sketch/sketchModel.js b/web/app/cad/sketch/sketchModel.js index cad1c46e..fc59b8cc 100644 --- a/web/app/cad/sketch/sketchModel.js +++ b/web/app/cad/sketch/sketchModel.js @@ -146,6 +146,10 @@ export class BezierCurve extends SketchPrimitive { tessellateImpl(resolution) { return LUT(this.a, this.b, this.cp1, this.cp2, 10); } + + toVerbNurbs(tr) { + return new verb.geom.BezierCurve([tr(this.a).data(), tr(this.cp1).data(), tr(this.cp2).data(), tr(this.b).data()], null); + } } export class EllipticalArc extends SketchPrimitive { diff --git a/web/test/cases/craftExtrude.js b/web/test/cases/craftExtrude.js deleted file mode 100644 index 9b6cc1da..00000000 --- a/web/test/cases/craftExtrude.js +++ /dev/null @@ -1,40 +0,0 @@ -import {assertEmpty, assertEquals, assertFaceIsPlane, assertTrue} from '../utils/asserts'; -import sketchObjectGlobalId from '../../app/cad/sketch/sketchObjectGlobalId'; - -export const TEST_MODE = 'modellerUI'; - -export function testExtrudeFromSketch2(env, ui) { - // globalSketchId(sketchId, seg1.id) -} - -export function testExtrudeFromSketch(env, ui) { - ui.openWizard('PLANE'); - ui.wizardOK(); - ui.selectFaces([0, 0, -10], [0, 0, 10]); - let sketchedFace = ui.context.services.selection.face.single; - let sketcherUI = ui.openSketcher(); - let seg1 = sketcherUI.addSegment(-100, -100, 100, -100); - let seg2 = sketcherUI.addSegment(100, -100, 100, 100); - let seg3 = sketcherUI.addSegment(100, 100, -100, 100); - let seg4 = sketcherUI.addSegment(-100, 100, -100, -100); - - ui.commitSketch(); - - ui.selectFaces([0, 0, -10], [0, 0, 10]); - - - ui.openWizard('EXTRUDE'); - ui.wizardContext.updateParam('value', 200); - ui.wizardOK(); - - let [leftFace] = ui.rayCastFaces([-200, 0, 100], [200, 0, 100]); - - let sketchId = sketchedFace.defaultSketchId; - - assertTrue(leftFace.brepFace.data.productionInfo.originatedFromPrimitive, - sketchObjectGlobalId(sketchId, seg3.id)); - - assertTrue(leftFace.brepFace.data.productionInfo.role, "sweep"); - - env.done(); -} diff --git a/web/test/cases/craftExtrudeBasicShapes.js b/web/test/cases/craftExtrudeBasicShapes.js new file mode 100644 index 00000000..816287de --- /dev/null +++ b/web/test/cases/craftExtrudeBasicShapes.js @@ -0,0 +1,211 @@ +import {assertFaceOrigination, assertFaceRole} from '../utils/asserts'; + +export const TEST_MODE = 'modellerUI'; + +export function testExtrudeFromSketch(env, ui) { + let sketcherUI = ui.createPlaneAndOpenSketcher(); + let sketchedFace = ui.context.services.selection.face.single; + let seg1 = sketcherUI.addSegment(-100, -100, 100, -100); + let seg2 = sketcherUI.addSegment(100, -100, 100, 100); + let seg3 = sketcherUI.addSegment(100, 100, -100, 100); + let seg4 = sketcherUI.addSegment(-100, 100, -100, -100); + + ui.commitSketch(); + + ui.selectFaces([0, 0, -10], [0, 0, 10]); + + + ui.openWizard('EXTRUDE'); + ui.wizardContext.updateParam('value', 200); + ui.wizardOK(); + + let [leftFace] = ui.rayCastFaces([-110, 0, 100], [-90, 0, 100]); + let [rightFace] = ui.rayCastFaces([110, 0, 100], [90, 0, 100]); + + let [topFace] = ui.rayCastFaces([0, 110, 100], [0, 90, 100]); + let [bottomFace] = ui.rayCastFaces([0, -110, 100], [0, -90, 100]); + + let [frontFace] = ui.rayCastFaces([0, 0, 210], [0, 0, 190]); + let [backFace] = ui.rayCastFaces([0, 0, -10], [0, 0, 10]); + + + assertFaceRole(leftFace, "sweep"); + assertFaceRole(rightFace, "sweep"); + assertFaceRole(topFace, "sweep"); + assertFaceRole(bottomFace, "sweep"); + assertFaceRole(frontFace, "top"); + assertFaceRole(backFace, "bottom"); + + let sketchId = sketchedFace.defaultSketchId; + + assertFaceOrigination(bottomFace, sketchId, seg1.id); + assertFaceOrigination(rightFace, sketchId, seg2.id); + assertFaceOrigination(topFace, sketchId, seg3.id); + assertFaceOrigination(leftFace, sketchId, seg4.id); + + env.done(); +} + +export function testExtrudeArc(env, ui) { + let sketcherUI = ui.createPlaneAndOpenSketcher(); + let sketchedFace = ui.context.services.selection.face.single; + let arc = sketcherUI.addArc(0, 0, 100, 0, -100, 0); + let segment = sketcherUI.addSegment(100, 0, -100, 0); + + // let gauge = ui.prismSurfaceGauge([-100, -100, 0], [100, -100, 0], [50, 50, 0], [-50, 50, 0] ); + // + // ui.__DEBUG__.AddParametricSurface(gauge.surface); + + ui.commitSketch(); + + ui.selectFaces([0, 0, -10], [0, 0, 10]); + + ui.openWizard('EXTRUDE'); + ui.wizardContext.updateParam('value', 200); + + ui.wizardOK(); + + let [curvedFace] = ui.rayCastFaces([0, 110, 100], [0, 90, 100]); + let [flatFace] = ui.rayCastFaces([0, -10, 100], [0, 10, 100]); + let [topFace] = ui.rayCastFaces([0, 50, 210], [0, 50, 190]); + let [bottomFace] = ui.rayCastFaces([0, 50, -10], [0, 50, 10]); + + + assertFaceRole(curvedFace, "sweep"); + assertFaceRole(flatFace, "sweep"); + assertFaceRole(topFace, "top"); + assertFaceRole(bottomFace, "bottom"); + + let sketchId = sketchedFace.defaultSketchId; + + assertFaceOrigination(curvedFace, sketchId, arc.id); + assertFaceOrigination(flatFace, sketchId, segment.id); + + env.done(); +} + +export function testExtrudeCircle(env, ui) { + let sketcherUI = ui.createPlaneAndOpenSketcher(); + let sketchedFace = ui.context.services.selection.face.single; + let circle = sketcherUI.addCircle(100, 100, 100); + + ui.commitSketch(); + + ui.selectFaces([0, 0, -10], [0, 0, 10]); + + ui.openWizard('EXTRUDE'); + ui.wizardContext.updateParam('value', 200); + + ui.wizardOK(); + + let [curvedFace] = ui.rayCastFaces([100, -10, 100], [100, 10, 100]); + let [topFace] = ui.rayCastFaces([100, 100, 210], [100, 100, 190]); + let [bottomFace] = ui.rayCastFaces([100, 100, -10], [100, 100, 10]); + + + assertFaceRole(curvedFace, "sweep"); + assertFaceRole(topFace, "top"); + assertFaceRole(bottomFace, "bottom"); + + let sketchId = sketchedFace.defaultSketchId; + + assertFaceOrigination(curvedFace, sketchId, circle.id); + + env.done(); +} + +export function testExtrudeEllipse(env, ui) { + let sketcherUI = ui.createPlaneAndOpenSketcher(); + let sketchedFace = ui.context.services.selection.face.single; + let ellipse = sketcherUI.addEllipse(-100, 100, 100, 100, 0, 150); + + ui.commitSketch(); + + ui.selectFaces([0, 0, -10], [0, 0, 10]); + + ui.openWizard('EXTRUDE'); + ui.wizardContext.updateParam('value', 200); + + ui.wizardOK(); + + let [curvedFace] = ui.rayCastFaces([0, 151, 100], [0, 149, 100]); + let [topFace] = ui.rayCastFaces([0, 100, 201],[0, 100, 199]); + let [bottomFace] = ui.rayCastFaces([0, 100, -1],[0, 100, 1]); + + + assertFaceRole(curvedFace, "sweep"); + assertFaceRole(topFace, "top"); + assertFaceRole(bottomFace, "bottom"); + + let sketchId = sketchedFace.defaultSketchId; + + assertFaceOrigination(curvedFace, sketchId, ellipse.id); + + env.done(); +} + +export function testExtrudeEllipticalArc(env, ui) { + let sketcherUI = ui.createPlaneAndOpenSketcher(); + let sketchedFace = ui.context.services.selection.face.single; + let eArc = sketcherUI.addEllipticalArc(-100, 100, 100, 100, 0, 150); + sketcherUI.move(100, 100, -50, 170); + sketcherUI.addSegment(eArc.a.x, eArc.a.y, eArc.b.x, eArc.b.y); + + ui.commitSketch(); + + ui.selectFaces([0, 0, -10], [0, 0, 10]); + + ui.openWizard('EXTRUDE'); + ui.wizardContext.updateParam('value', 200); + + ui.wizardOK(); + + let [curvedFace] = ui.rayCastFaces([-110, 100, 100], [-90, 100, 100]); + let [topFace] = ui.rayCastFaces([0, 100, 201],[0, 100, 199]); + let [bottomFace] = ui.rayCastFaces([0, 100, -1],[0, 100, 1]); + + + assertFaceRole(curvedFace, "sweep"); + assertFaceRole(topFace, "top"); + assertFaceRole(bottomFace, "bottom"); + + let sketchId = sketchedFace.defaultSketchId; + + assertFaceOrigination(curvedFace, sketchId, eArc.id); + + env.done(); +} + +export function testExtrudeBezier(env, ui) { + let sketcherUI = ui.createPlaneAndOpenSketcher(); + let sketchedFace = ui.context.services.selection.face.single; + let bezier = sketcherUI.addBezier(-100, 100, 100, 100, 0, 150); + sketcherUI.move(bezier.cp2.x, bezier.cp2.y, bezier.cp2.x, bezier.cp1.y); + + sketcherUI.addSegment(bezier.a.x, bezier.a.y, 0, 0); + sketcherUI.addSegment(bezier.b.x, bezier.b.y, 0, 0); + + ui.commitSketch(); + + ui.selectFaces([0, 0, -10], [0, 0, 10]); + + ui.openWizard('EXTRUDE'); + ui.wizardContext.updateParam('value', 200); + + ui.wizardOK(); + + let [curvedFace] = ui.rayCastFaces([0, 178, 50], [0, 170, 50]); + let [topFace] = ui.rayCastFaces([0, 100, 201],[0, 100, 199]); + let [bottomFace] = ui.rayCastFaces([0, 100, -1],[0, 100, 1]); + + + assertFaceRole(curvedFace, "sweep"); + assertFaceRole(topFace, "top"); + assertFaceRole(bottomFace, "bottom"); + + let sketchId = sketchedFace.defaultSketchId; + + assertFaceOrigination(curvedFace, sketchId, bezier.id); + + env.done(); +} diff --git a/web/test/cases/craftExtrudeOptions.js b/web/test/cases/craftExtrudeOptions.js new file mode 100644 index 00000000..70618fe5 --- /dev/null +++ b/web/test/cases/craftExtrudeOptions.js @@ -0,0 +1,24 @@ +import {assertFaceOrigination, assertFaceRole} from '../utils/asserts'; + +export const TEST_MODE = 'modellerUI'; + +export function testExtrudePrism(env, ui) { + let sketcherUI = ui.createPlaneAndOpenSketcher(); + let sketchedFace = ui.context.services.selection.face.single; + let [S1, S2, S3, S4] = sketcherUI.addPolygon(-100, -100, 100, 100); + + // let gauge = ui.prismSurfaceGauge([-100, -100, 0], [100, -100, 0], [50, 50, 0], [-50, 50, 0] ); + // + // ui.__DEBUG__.AddParametricSurface(gauge.surface); + + ui.commitSketch(); + + ui.selectFaces([0, 0, -10], [0, 0, 10]); + + ui.openWizard('EXTRUDE'); + ui.wizardContext.updateParam('value', 2000); + ui.wizardContext.updateParam('prism', 0.1); + ui.wizardOK(); + env.fail(); + env.done(); +} diff --git a/web/test/suites.js b/web/test/suites.js index 5b3c618b..af414b47 100644 --- a/web/test/suites.js +++ b/web/test/suites.js @@ -2,6 +2,13 @@ import * as test from './test'; import * as modes from './modes'; export default { + + Craft: [ + TestCase('craftPlane'), + TestCase('craftExtrudeBasicShapes'), + TestCase('craftExtrudeOptions'), + ], + SketcherObjects: [ TestCase('segment'), TestCase('arc'), @@ -22,11 +29,6 @@ export default { ], - Craft: [ - TestCase('craftPlane'), - TestCase('craftExtrude'), - ], - BREP: [ TestCase('brep-bool'), TestCase('brep-bool-wizard-based'), diff --git a/web/test/utils/asserts.js b/web/test/utils/asserts.js index 61968732..e926ac55 100644 --- a/web/test/utils/asserts.js +++ b/web/test/utils/asserts.js @@ -1,4 +1,5 @@ import {FailError} from '../test'; +import sketchObjectGlobalId from '../../app/cad/sketch/sketchObjectGlobalId'; export function fail(msg, optionalMsg) { throw new FailError(msg + (optionalMsg === undefined ? '' : ' ' + optionalMsg)); @@ -46,4 +47,13 @@ export function assertPoint2DEquals(expected, actial, msg) { export function assertFaceIsPlane(face) { assertTrue(face.shell.surfacePrototype !== undefined); +} + +export function assertFaceOrigination(face, sketchId, primitiveId) { + assertEquals(sketchObjectGlobalId(sketchId, primitiveId), + face.productionInfo.originatedFromPrimitive); +} + +export function assertFaceRole(face, expectedRole) { + assertEquals(expectedRole, face.productionInfo.role); } \ No newline at end of file diff --git a/web/test/utils/sketcher-utils.js b/web/test/utils/sketcher-utils.js index 0295cf46..6ef4c442 100644 --- a/web/test/utils/sketcher-utils.js +++ b/web/test/utils/sketcher-utils.js @@ -26,6 +26,11 @@ export function clickXY(app, x, y, attrs) { app.viewer.toolManager.tool.mouseup(new TestMouseEvent(x, y, 'mouseup', attrs)); } +export function moveAndClickXY(app, x, y, attrs) { + app.viewer.toolManager.tool.mousemove(new TestMouseEvent(x, y, 'mousedown', attrs)); + clickXY(app, x, y, attrs); +} + export function move(app, from, to) { const toolManager = app.viewer.toolManager; toolManager.tool.mousedown(new TestMouseEvent(from.x, from.y)); @@ -33,6 +38,18 @@ export function move(app, from, to) { toolManager.tool.mouseup(new TestMouseEvent(to.x, to.y)); } +export function moveInModel(app, fromX, fromY, toX, toY) { + const toolManager = app.viewer.toolManager; + [fromX, fromY] = modelToScreen(app.viewer, fromX, fromY); + [toX, toY] = modelToScreen(app.viewer, toX, toY); + + toolManager.tool.mousemove(new TestMouseEvent(fromX, fromY)); + toolManager.tool.mousedown(new TestMouseEvent(fromX, fromY)); + toolManager.tool.mousemove(new TestMouseEvent(toX, toY)); + toolManager.tool.mouseup(new TestMouseEvent(toX, toY)); +} + + export function addSegment(app, aX, aY, bX, bY) { app.actions['addSegment'].action(); const tool = app.viewer.toolManager.tool; @@ -54,6 +71,70 @@ export function addSegmentInModel(app, aX, aY, bX, bY) { return addSegment(app, aX, aY, bX, bY); } +export function addArc(app, cX, cY, aX, aY, bX, bY) { + + [aX, aY] = modelToScreen(app.viewer, aX, aY); + [bX, bY] = modelToScreen(app.viewer, bX, bY); + [cX, cY] = modelToScreen(app.viewer, cX, cY); + + app.actions['addArc'].action(); + + moveAndClickXY(app, cX, cY); + moveAndClickXY(app, aX, aY); + let arc = app.viewer.toolManager.tool.arc; + moveAndClickXY(app, bX, bY); + app.viewer.toolManager.releaseControl(); + return arc; +} + +export function addCircle(app, cX, cY, R) { + let [rX, rY] = modelToScreen(app.viewer, cX + R, cY); + [cX, cY] = modelToScreen(app.viewer, cX, cY); + app.actions['addCircle'].action(); + moveAndClickXY(app, cX, cY); + let circle = app.viewer.toolManager.tool.circle; + moveAndClickXY(app, rX, rY); + app.viewer.toolManager.releaseControl(); + return circle; +} + +export function addEllipse(app, aX, aY, bX, bY, rX, rY) { + [aX, aY] = modelToScreen(app.viewer, aX, aY); + [bX, bY] = modelToScreen(app.viewer, bX, bY); + [rX, rY] = modelToScreen(app.viewer, rX, rY); + app.actions['addEllipse'].action(); + moveAndClickXY(app, aX, aY); + let ellipse = app.viewer.toolManager.tool.ellipse; + moveAndClickXY(app, bX, bY); + moveAndClickXY(app, rX, rY); + app.viewer.toolManager.releaseControl(); + return ellipse; +} + +export function addEllipticalArc(app, aX, aY, bX, bY, rX, rY) { + [aX, aY] = modelToScreen(app.viewer, aX, aY); + [bX, bY] = modelToScreen(app.viewer, bX, bY); + [rX, rY] = modelToScreen(app.viewer, rX, rY); + app.actions['addEllipticalArc'].action(); + moveAndClickXY(app, aX, aY); + let ellipse = app.viewer.toolManager.tool.ellipse; + moveAndClickXY(app, bX, bY); + moveAndClickXY(app, rX, rY); + app.viewer.toolManager.releaseControl(); + return ellipse; +} + +export function addBezier(app, aX, aY, bX, bY) { + [aX, aY] = modelToScreen(app.viewer, aX, aY); + [bX, bY] = modelToScreen(app.viewer, bX, bY); + app.actions['addBezierCurve'].action(); + moveAndClickXY(app, aX, aY); + let curve = app.viewer.toolManager.tool.curve; + moveAndClickXY(app, bX, bY); + app.viewer.toolManager.releaseControl(); + return curve; +} + export function polyLine(app) { app.actions['addMultiSegment'].action(); const tool = app.viewer.toolManager.tool; diff --git a/web/test/utils/subjects/modeller/modellerUISubject.js b/web/test/utils/subjects/modeller/modellerUISubject.js index c5e92196..8ead484b 100644 --- a/web/test/utils/subjects/modeller/modellerUISubject.js +++ b/web/test/utils/subjects/modeller/modellerUISubject.js @@ -1,4 +1,3 @@ -import {TestMouseEvent} from '../../mouse-event'; import {getAttribute} from '../../../../../modules/scene/objectData'; import {FACE} from '../../../../app/cad/scene/entites'; import {createSubjectFromInPlaceSketcher} from './sketcherUISubject'; @@ -71,11 +70,20 @@ export default ctx => { ctx.services.action.run('sketchSaveAndExit'); } + function createPlaneAndOpenSketcher() { + openWizard('PLANE'); + wizardOK(); + selectFaces([0, 0, -10], [0, 0, 10]); + return openSketcher(); + } + return { context: ctx, openWizard, wizardOK, sceneMouseEvent, clickOnScene, rayCastFaces, selectFaces, openSketcher, commitSketch, - get wizardContext() { return getWizardContext()} + get wizardContext() { return getWizardContext()}, + createPlaneAndOpenSketcher, + __DEBUG__: ctx.services.debug.utils }; } diff --git a/web/test/utils/subjects/modeller/sketcherUISubject.js b/web/test/utils/subjects/modeller/sketcherUISubject.js index ee089c19..94a31ae2 100644 --- a/web/test/utils/subjects/modeller/sketcherUISubject.js +++ b/web/test/utils/subjects/modeller/sketcherUISubject.js @@ -2,7 +2,6 @@ import * as sketcher_utils from '../../../utils/sketcher-utils' import {decapitalize} from '../../../../../modules/gems/capitalize'; export function createSubjectFromInPlaceSketcher(ctx) { - let actions = {}; for (const actionId of Object.keys(ctx.streams.action.state)) { @@ -10,7 +9,8 @@ export function createSubjectFromInPlaceSketcher(ctx) { let oldId = decapitalize(actionId.substring(6)); actions[oldId] = { action: () => ctx.services.action.run(actionId) - } + }; + actions.addBezierCurve = actions.addCubicBezierSpline; } } @@ -18,9 +18,25 @@ export function createSubjectFromInPlaceSketcher(ctx) { viewer: ctx.services.sketcher.inPlaceEditor.viewer, actions }; - + + const addSegment = sketcher_utils.addSegmentInModel.bind(this, oldStyleSketcherApp); + const addArc = sketcher_utils.addArc.bind(this, oldStyleSketcherApp); + const addCircle = sketcher_utils.addCircle.bind(this, oldStyleSketcherApp); + const addEllipse = sketcher_utils.addEllipse.bind(this, oldStyleSketcherApp); + const addEllipticalArc = sketcher_utils.addEllipticalArc.bind(this, oldStyleSketcherApp); + const addBezier = sketcher_utils.addBezier.bind(this, oldStyleSketcherApp); + const move = sketcher_utils.moveInModel.bind(this, oldStyleSketcherApp); + function addPolygon(x0, y0, x1, y1) { + return [ + addSegment(x0, y0, x1, y0), + addSegment(x1, y0, x1, y1), + addSegment(x1, y1, x0, y1), + addSegment(x0, y1, x0, y0) + ]; + } + return { - addSegment: sketcher_utils.addSegmentInModel.bind(this, oldStyleSketcherApp) + addSegment, addPolygon, addArc, addCircle, addEllipse, addEllipticalArc, addBezier, move } } \ No newline at end of file