diff --git a/web/app/cad/craft/datum/datumObject.js b/web/app/cad/craft/datum/datumObject.js index 7081fdb1..401caeb3 100644 --- a/web/app/cad/craft/datum/datumObject.js +++ b/web/app/cad/craft/datum/datumObject.js @@ -94,7 +94,7 @@ export default class DatumObject3D extends Object3D { } } - dragMove(e) { + dragMove({mouseEvent: e}) { if (this.beingDraggedAxis) { let dir = this.beingDraggedAxis; @@ -128,7 +128,7 @@ export default class DatumObject3D extends Object3D { onMove(begin, end, delta) { } - dragDrop(e) { + dragDrop() { this.exitEditMode(); this.viewer.requestRender(); } @@ -140,13 +140,13 @@ export default class DatumObject3D extends Object3D { } function addOnHoverBehaviour(handle, viewer) { - handle.onMouseDown = function(e, hits, startDrag) { + handle.onMouseDown = function(e) { let datum = this.parent.parent.parent; if (datum.freezeDragging) { return; } - startDrag(datum); - datum.dragStart(e, this.parent); + e.startDrag(datum); + datum.dragStart(e.mouseEvent, this.parent); }; let defaultColor = handle.material.color.getHex(); diff --git a/web/app/cad/model/mface.js b/web/app/cad/model/mface.js index afc6f745..2caa7ca2 100644 --- a/web/app/cad/model/mface.js +++ b/web/app/cad/model/mface.js @@ -4,6 +4,8 @@ import {BasisForPlane} from '../../math/l3space'; import {MSketchObject} from './msketchObject'; import {EMPTY_ARRAY} from 'gems/iterables'; import CSys from '../../math/csys'; +import {MSketchLoop} from './mloop'; +import {sketchObjects} from '../../sketcher/fetchers'; export class MFace extends MObject { @@ -14,6 +16,7 @@ export class MFace extends MObject { this.shell = shell; this.surface = surface; this.sketchObjects = []; + this.sketchLoops = []; this._csys = csys } @@ -93,6 +96,17 @@ export class MFace extends MObject { addSketchObjects(sketch.constructionSegments); addSketchObjects(sketch.connections); addSketchObjects(sketch.loops); + + + + const index = new Map(); + this.sketchObjects.forEach(o => index.set(o.sketchPrimitive, o)); + + this.sketchLoops = sketch.fetchContours().map((contour, i) => { + let loopSketchObjects = contour.segments.map(s => index.get(s)); + return new MSketchLoop(this.id + '/L:' + i, this, loopSketchObjects, contour); + }); + } findSketchObjectById(sketchObjectId) { diff --git a/web/app/cad/model/mloop.js b/web/app/cad/model/mloop.js new file mode 100644 index 00000000..0bcad2d7 --- /dev/null +++ b/web/app/cad/model/mloop.js @@ -0,0 +1,25 @@ +import {MObject} from './mobject'; + +export class MLoop extends MObject { + + static TYPE = 'loop'; + + constructor(id) { + super(MLoop.TYPE, id); + } + +} + +export class MSketchLoop extends MObject { + + static TYPE = 'loop'; + + constructor(id, face, sketchObjects, contour) { + super(id); + this.face = face; + this.sketchObjects = sketchObjects; + this.contour = contour; + } + +} + diff --git a/web/app/cad/scene/controls/mouseEventSystemPlugin.js b/web/app/cad/scene/controls/mouseEventSystemPlugin.js index 37cb3e94..30f26059 100644 --- a/web/app/cad/scene/controls/mouseEventSystemPlugin.js +++ b/web/app/cad/scene/controls/mouseEventSystemPlugin.js @@ -1,9 +1,11 @@ -import {findAncestor} from 'scene/sceneGraph'; export function activate(context) { const {services, streams} = context; - let domElement = services.viewer.sceneSetup.domElement(); - + const domElement = services.viewer.sceneSetup.domElement(); + const event = { + viewer: services.viewer + }; + domElement.addEventListener('mousedown', mousedown, false); domElement.addEventListener('mouseup', mouseup, false); domElement.addEventListener('mousemove', mousemove, false); @@ -13,50 +15,56 @@ export function activate(context) { let toDrag = null; let pressed = new Set(); - function startDrag(objectToDrag, e) { + event.startDrag = objectToDrag => { if (toDrag) { - stopDrag(e); + stopDrag(); } toDrag = objectToDrag; services.viewer.sceneSetup.trackballControls.enabled = false; - } + }; - function stopDrag(e) { - toDrag.dragDrop(e); + function stopDrag() { + toDrag.dragDrop(event); toDrag = null; services.viewer.sceneSetup.trackballControls.enabled = true; } function mousedown(e) { + event.mouseEvent = e; pressed.clear(); let hits = performRaycast(e); + event.hits = hits; + for (let hit of hits) { let obj = hit.object; if (obj && obj.onMouseDown) { - obj.onMouseDown(e, hits, objectToDrag => startDrag(objectToDrag, e)); + obj.onMouseDown(event); } pressed.add(obj); - if (!hit.object.passMouseEvent || !hit.object.passMouseEvent(e, hits)) { + if (!hit.object.passMouseEvent || !hit.object.passMouseEvent(event)) { break; } } } function mouseup(e) { + event.mouseEvent = e; if (toDrag) { stopDrag(e); mousemove(e); } else { let hits = performRaycast(e); + event.hits = hits; + for (let hit of hits) { let obj = hit.object; if (obj && obj.onMouseUp) { - obj.onMouseUp(e, hits); + obj.onMouseUp(event); } if (pressed.has(obj) && obj.onMouseClick) { - obj.onMouseClick(e, hits); + obj.onMouseClick(event); } - if (!hit.object.passMouseEvent || !hit.object.passMouseEvent(e, hits)) { + if (!hit.object.passMouseEvent || !hit.object.passMouseEvent(event)) { break; } } @@ -68,32 +76,34 @@ export function activate(context) { let valid = new Set(); function mousemove(e) { - + event.mouseEvent = e; + if (toDrag) { - toDrag.dragMove(e); + toDrag.dragMove(event); } else { let hits = performRaycast(e); - + event.hits = hits; + valid.clear(); for (let hit of hits) { valid.add(hit.object); - if (!hit.object.passMouseEvent || !hit.object.passMouseEvent(e, hits)) { + if (!hit.object.passMouseEvent || !hit.object.passMouseEvent(event)) { break; } } - entered.forEach(e => { - if (!valid.has(e) && e.onMouseLeave) { - e.onMouseLeave(e, hits); + entered.forEach(el => { + if (!valid.has(el) && el.onMouseLeave) { + el.onMouseLeave(event); } }); - valid.forEach(e => { - if (!entered.has(e) && e.onMouseEnter) { - e.onMouseEnter(e, hits); + valid.forEach(el => { + if (!entered.has(el) && el.onMouseEnter) { + el.onMouseEnter(event); } - if (e.onMouseMove) { - e.onMouseMove(e, hits); + if (el.onMouseMove) { + el.onMouseMove(event); } }); diff --git a/web/app/cad/scene/views/datumView.js b/web/app/cad/scene/views/datumView.js index 37807f60..1c97dcc3 100644 --- a/web/app/cad/scene/views/datumView.js +++ b/web/app/cad/scene/views/datumView.js @@ -36,7 +36,7 @@ export default class DatumView extends View { viewer.requestRender(); } - onMouseLeave(e, hits, behindHits) { + onMouseLeave(e) { this.mouseInside = false; this.updateVisibility(); this.material.color.setHex(0xFFFFFF); @@ -53,7 +53,7 @@ export default class DatumView extends View { viewer.requestRender(); } - onMouseClick(e) { + onMouseClick({mouseEvent: e}) { selectDatum(datum); showDatumMenu({ x: e.offsetX, @@ -72,18 +72,18 @@ export default class DatumView extends View { mouseInside; - onMouseEnter(e, hits) { + onMouseEnter(e) { this.mouseInside = true; this.parent.parent.menuButton.updateVisibility(); } - onMouseLeave(e, hits) { + onMouseLeave(e) { this.mouseInside = false; this.parent.parent.menuButton.updateVisibility(); } - passMouseEvent(e, hits) { + passMouseEvent(e) { return true; } } diff --git a/web/app/cad/scene/views/faceView.js b/web/app/cad/scene/views/faceView.js index 8eb9c343..134c17db 100644 --- a/web/app/cad/scene/views/faceView.js +++ b/web/app/cad/scene/views/faceView.js @@ -4,6 +4,7 @@ import {FACE} from '../entites'; import * as SceneGraph from '../../../../../modules/scene/sceneGraph'; import {SketchObjectView} from './sketchObjectView'; import {View} from './view'; +import {SketchLoopView} from './sketchLoopView'; export class SketchingView extends View { @@ -11,6 +12,7 @@ export class SketchingView extends View { super(face); this.sketchGroup = SceneGraph.createGroup(); this.sketchObjectViews = []; + this.sketchLoopViews = []; this.rootGroup = SceneGraph.createGroup(); SceneGraph.addToGroup(this.rootGroup, this.sketchGroup); } @@ -25,13 +27,18 @@ export class SketchingView extends View { SceneGraph.addToGroup(this.sketchGroup, sov.rootGroup); this.sketchObjectViews.push(sov); } + this.model.sketchLoops.forEach(mLoop => { + let loopView = new SketchLoopView(mLoop); + SceneGraph.addToGroup(this.sketchGroup, loopView.rootGroup); + this.sketchLoopViews.push(loopView); + }); } disposeSketch() { - for (let sov of this.sketchObjectViews) { - sov.dispose(); - } + this.sketchObjectViews.forEach(o => o.dispose()); + this.sketchLoopViews.forEach(o => o.dispose()); this.sketchObjectViews = []; + this.sketchLoopViews = []; } dispose() { diff --git a/web/app/cad/scene/views/shellView.js b/web/app/cad/scene/views/shellView.js index e0be6ab3..7b9c8e40 100644 --- a/web/app/cad/scene/views/shellView.js +++ b/web/app/cad/scene/views/shellView.js @@ -55,6 +55,8 @@ export class ShellView extends View { } dispose() { + this.mesh.material.dispose(); + this.mesh.geometry.dispose(); for (let faceView of this.faceViews) { faceView.dispose(); } diff --git a/web/app/cad/scene/views/sketchLoopView.js b/web/app/cad/scene/views/sketchLoopView.js new file mode 100644 index 00000000..2670defc --- /dev/null +++ b/web/app/cad/scene/views/sketchLoopView.js @@ -0,0 +1,62 @@ +import {View} from './view'; +import * as SceneGraph from 'scene/sceneGraph'; +import {tessellateLoopsOnSurface} from '../../tess/brep-tess'; +import {createSolidMaterial} from '../wrappers/sceneObject'; +import {DoubleSide, Geometry, Mesh} from 'three'; +import {surfaceAndPolygonsToGeom} from '../wrappers/brepSceneObject'; +import {TriangulatePolygons} from '../../tess/triangulation'; +import Vector from '../../../../../modules/math/vector'; + +export class SketchLoopView extends View { + constructor(mLoop) { + super(mLoop); + this.rootGroup = SceneGraph.createGroup(); + + const geometry = new Geometry(); + geometry.dynamic = true; + this.mesh = new Mesh(geometry, createSolidMaterial({ + color: 0xDBFFD9, + side: DoubleSide, + polygonOffset: true, + polygonOffsetFactor: 1, + polygonOffsetUnits: 0.1, + visible: false + })); + let surface = mLoop.face.surface; + let tess; + if (surface.simpleSurface && surface.simpleSurface.isPlane) { + let polygon = mLoop.contour.tessellateInCoordinateSystem(mLoop.face.csys); + tess = TriangulatePolygons([polygon], mLoop.face.csys.z, v => v.data(), arr => new Vector().set3(arr)); + } else { + tess = tessellateLoopsOnSurface(surface, [mLoop.contour], contour => contour.segments, + seg => seg.toNurbs(mLoop.face.csys), + seg => seg.inverted); + } + + surfaceAndPolygonsToGeom(surface, tess, this.mesh.geometry); + this.mesh.geometry.mergeVertices(); + this.rootGroup.add(this.mesh); + this.mesh.onMouseEnter = (e) => { + this.mesh.material.visible = true; + e.viewer.requestRender(); + }; + this.mesh.onMouseLeave = (e) => { + this.mesh.material.visible = false; + e.viewer.requestRender(); + }; + } + + mark(color) { + + } + + withdraw(color) { + + } + + dispose() { + this.mesh.material.dispose(); + this.mesh.geometry.dispose(); + super.dispose(); + } +} \ No newline at end of file diff --git a/web/app/cad/scene/wrappers/brepSceneObject.js b/web/app/cad/scene/wrappers/brepSceneObject.js index c29fc826..f4a010dc 100644 --- a/web/app/cad/scene/wrappers/brepSceneObject.js +++ b/web/app/cad/scene/wrappers/brepSceneObject.js @@ -184,10 +184,15 @@ export function tessDataToGeom(tessellation, geom) { export function brepFaceToGeom(brepFace, geom) { const polygons = brepTess(brepFace); - const isPlane = brepFace.simpleSurface && brepFace.simpleSurface.isPlane; + return surfaceAndPolygonsToGeom(brepFace.surface, polygons, geom); +} + +export function surfaceAndPolygonsToGeom(surface, polygons, geom) { + + const isPlane = surface.simpleSurface && surface.simpleSurface.isPlane; let normalOrNormals; if (isPlane) { - normalOrNormals = brepFace.surface.normalInMiddle().three(); + normalOrNormals = surface.normalInMiddle().three(); } for (let p = 0; p < polygons.length; ++p) { const off = geom.vertices.length; @@ -204,7 +209,7 @@ export function brepFaceToGeom(brepFace, geom) { const c = i + off; if (!isPlane) { - normalOrNormals = [firstVertex, poly[i - 1], poly[i]].map(v => brepFace.surface.normal(v)); + normalOrNormals = [firstVertex, poly[i - 1], poly[i]].map(v => surface.normal(v)); } const face = new THREE.Face3(a, b, c, normalOrNormals); geom.faces.push(face); diff --git a/web/app/cad/sketch/sketchModel.js b/web/app/cad/sketch/sketchModel.js index 0e75514c..6a4762bc 100644 --- a/web/app/cad/sketch/sketchModel.js +++ b/web/app/cad/sketch/sketchModel.js @@ -261,38 +261,14 @@ export class Contour { this.segments.push(obj); } - tessellateOnSurface(csys) { - const cc = new CompositeCurve(); - const tr = csys.outTransformation; - - let prev = null; - let firstPoint = null; + tessellateInCoordinateSystem(csys) { + let out = []; for (let segIdx = 0; segIdx < this.segments.length; ++segIdx) { let segment = this.segments[segIdx]; - let tessellation = segment.tessellate(RESOLUTION); - - tessellation = tessellation.map(p => tr(p)); - - const n = tessellation.length; - prev = prev == null ? tessellation[0] : prev; - tessellation[0] = prev; // this magic is to keep identity of same vectors - if (firstPoint == null) firstPoint = tessellation[0]; - - if (segIdx == this.segments.length - 1) { - tessellation[n - 1] = firstPoint; - } - - cc.add(segment.toNurbs(csys), prev, segment); - prev = tessellation[n - 1]; - - //It might be an optimization for segments - // for (let i = 1; i < n; ++i) { - // const curr = tessellation[i]; - // cc.add(new Line.fromSegment(prev, curr), prev, segment); - // prev = curr; - // } + segment.toNurbs(csys).tessellate().forEach(p => out.push(p)); + out.pop(); } - return cc; + return out; } transferInCoordinateSystem(csys) { diff --git a/web/app/cad/tess/brep-tess.js b/web/app/cad/tess/brep-tess.js index a3b03995..ad2ef2e6 100644 --- a/web/app/cad/tess/brep-tess.js +++ b/web/app/cad/tess/brep-tess.js @@ -4,32 +4,36 @@ import libtess from 'libtess' import tessellateSurface from '../../brep/geom/surfaces/surfaceTess'; export default function A(face) { + return tessellateLoopsOnSurface(face.surface, face.loops, loop => loop, seg => e.edge.curve, seg => seg.inverted) +} + +export function tessellateLoopsOnSurface(surface, curveContours, getLoop, getCurve, isInverted) { let loops = []; - for (let loop of face.loops) { + for (let contour of curveContours) { let pipLoop = []; loops.push(pipLoop); - for (let e of loop.halfEdges) { - let curvePoints = e.edge.curve.tessellate(); - if (e.inverted) { + for (let segment of getLoop(contour)) { + let curvePoints = getCurve(segment).tessellate(); + if (isInverted(segment)) { curvePoints.reverse(); } curvePoints.pop(); for (let point of curvePoints) { - let wp = face.surface.workingPoint(point); + let wp = surface.workingPoint(point); pipLoop.push(wp); } } } - let tess = tessellateSurface(face.surface.impl); - let nurbsTriangles = tess.faces.map(f => f.map(i => face.surface.createWorkingPoint(tess.uvs[i], Vector.fromData(tess.points[i])))); + let tess = tessellateSurface(surface.impl); + let nurbsTriangles = tess.faces.map(f => f.map(i => surface.createWorkingPoint(tess.uvs[i], Vector.fromData(tess.points[i])))); let paths = clip(nurbsTriangles, loops); let triangles = tessPaths(paths); - let out = convertPoints(triangles, p => face.surface.workingPointTo3D(p) ); + let out = convertPoints(triangles, p => surface.workingPointTo3D(p) ); // __DEBUG__.AddPointPolygons(out, 0x00ffff); return out; }