From c1e7e134a403c8715c3c2aa05a48f43fc13f751b Mon Sep 17 00:00:00 2001 From: Val Erastov Date: Thu, 15 Feb 2018 21:31:03 -0800 Subject: [PATCH] fixing extrude when all edges are coincident --- web/app/brep/operations/boolean.js | 99 +++++++++++++++++++----------- web/test/cases/brep-bool-topo.js | 64 +++++++++++++++++++ 2 files changed, 128 insertions(+), 35 deletions(-) diff --git a/web/app/brep/operations/boolean.js b/web/app/brep/operations/boolean.js index 880a8d2f..b2d0d4dd 100644 --- a/web/app/brep/operations/boolean.js +++ b/web/app/brep/operations/boolean.js @@ -178,19 +178,21 @@ function replaceMergedFaces(facesData, mergedFaces) { filterInPlace(facesData, ({face}) => mergedFaces.find(({originFaces}) => originFaces.indexOf(face) > -1) === undefined ); - for (let {mergedLoops, referenceSurface, originFaces} of mergedFaces) { - let fakeFace = new Face(referenceSurface); - for (let mergedLoop of mergedLoops) { - let actualHalfEdges = []; - mergedLoop.halfEdges.forEach(he => addDecayed(he, actualHalfEdges)); - mergedLoop.halfEdges = actualHalfEdges; - fakeFace.innerLoops.push(mergedLoop); - mergedLoop.face = fakeFace; - mergedLoop.link(); - } - facesData.push(initSolveDataForFace(fakeFace)); - for (let originFace of originFaces) { - originFace.data[MY].newEdges.forEach(e => addNewEdge(fakeFace, e)); + for (let {facePrototypes, originFaces} of mergedFaces) { + for (let {loops, surface} of facePrototypes) { + let fakeFace = new Face(surface); + for (let loop of loops) { + let actualHalfEdges = []; + loop.halfEdges.forEach(he => addDecayed(he, actualHalfEdges)); + loop.halfEdges = actualHalfEdges; + fakeFace.innerLoops.push(loop); + loop.face = fakeFace; + loop.link(); + } + facesData.push(initSolveDataForFace(fakeFace)); + for (let originFace of originFaces) { + originFace.data[MY].newEdges.forEach(e => addNewEdge(fakeFace, e)); + } } } } @@ -316,9 +318,6 @@ function mergeFaces(facesA, facesB, opType) { } } - let originFace = facesA[0]; - let referenceSurface = createBoundingNurbs(allPoints, originFace.surface.simpleSurface); - let valid = new Set(); let invalid = new Set(); @@ -346,6 +345,7 @@ function mergeFaces(facesA, facesB, opType) { function checkCoincidentEdges(edgeA, edgeB) { if (isSameEdge(edgeA, edgeB)) { + EdgeSolveData.markCollision(edgeA, edgeB); coincidentEdges.add(edgeA); coincidentEdges.add(edgeB); markEdgeTransferred(edgeA.edge); @@ -407,29 +407,42 @@ function mergeFaces(facesA, facesB, opType) { } } - let graph = new EdgeGraph(); - let discardedEdges = new Set(); - for (let face of originFaces) { - for (let edge of face.edges) { - discardedEdges.add(edge); - if (!invalid.has(edge)) { - graph.add(edge); + + + let facePrototypes = []; + let leftovers = null; + for (let referenceFace of originFaces) { + + let graph = new EdgeGraph(); + for (let face of originFaces) { + for (let edge of face.edges) { + if (!invalid.has(edge) && (leftovers == null || leftovers.has(edge))) { + graph.add(edge); + } } } + + leftovers = new Set(graph.graphEdges); + let detectedLoops = detectLoops(referenceFace.surface, graph); + + for (let loop of detectedLoops) { + for (let edge of loop.halfEdges) { + // EdgeSolveData.setPriority(edge, 1); + leftovers.delete(edge); + } + } + + + if (detectedLoops.length !== 0) { + facePrototypes.push({ + loops: detectedLoops, + surface: createBoundingNurbs(allPoints, referenceFace.surface.simpleSurface), + }); + } } - let detectedLoops = detectLoops(originFace.surface, graph); - // for (let loop of detectedLoops) { - // for (let edge of loop.halfEdges) { - // // EdgeSolveData.setPriority(edge, 1); - // discardedEdges.delete(edge); - // } - // } - - return { - mergedLoops: detectedLoops, - referenceSurface, + facePrototypes, originFaces }; } @@ -466,7 +479,8 @@ function filterFaces(faces) { function doesFaceContainNewEdge(face) { for (let e of face.edges) { - if (getPriority(e) > 0 || getPriority(e.twin()) > 0) { + if (getPriority(e) > 0 || getPriority(e.twin()) > 0 || + EdgeSolveData.get(e).affected === true) { return true; } } @@ -1056,6 +1070,21 @@ EdgeSolveData.setPriority = function(halfEdge, value) { EdgeSolveData.createIfEmpty(halfEdge).priority = value; }; +EdgeSolveData.markAffected = function(halfEdge) { + EdgeSolveData.createIfEmpty(halfEdge).affected = true; +}; + +EdgeSolveData.markCollision = function(halfEdge1, halfEdge2) { + + function markNeighborhoodAffected(edge) { + EdgeSolveData.markAffected(edge); + EdgeSolveData.markAffected(edge.next); + EdgeSolveData.markAffected(edge.prev); + } + markNeighborhoodAffected(halfEdge1); + markNeighborhoodAffected(halfEdge2); +}; + EdgeSolveData.addPriority = function(halfEdge, value) { EdgeSolveData.createIfEmpty(halfEdge).priority += value; }; diff --git a/web/test/cases/brep-bool-topo.js b/web/test/cases/brep-bool-topo.js index bb1c9cd9..d4f925c0 100644 --- a/web/test/cases/brep-bool-topo.js +++ b/web/test/cases/brep-bool-topo.js @@ -66,6 +66,22 @@ export default defineTests([ } }, + { + 'name': 'Adjacent2Edges2FaceExtrude', + 'state': { + 'sketches': {'0:3': {'Segment': [[[-21, 250], [250, 250]], [[250, 250], [250, -8]], [[250, -8], [-21, -8]], [[-21, -8], [-21, 250]]]}}, + 'operations': [{'type': 'BOX', 'params': {'width': 500, 'height': 500, 'depth': 500}}, { + 'type': 'EXTRUDE', + 'params': {'value': 50, 'prism': 1, 'angle': 0, 'rotation': 0, 'face': '0:3'} + }] + }, + 'expected': { + 'format': 'LOOPS', + 'vertices': [[-300, -8, -21], [-300, -8, 250], [-300, 250, -21], [-300, 250, 250], [-250, -250, -250], [-250, -250, 250], [-250, -8, -21], [-250, -8, 250], [-250, 250, -250], [-250, 250, -21], [-250, 250, 250], [250, -250, -250], [250, -250, 250], [250, 250, -250], [250, 250, 250]], + 'faces': [[[11, 12, 5, 4]], [[13, 14, 12, 11]], [[11, 4, 8, 13]], [[0, 6, 7, 1]], [[2, 9, 6, 0]], [[3, 2, 0, 1]], [[2, 3, 10, 14, 13, 8, 9]], [[7, 6, 9, 8, 4, 5]], [[3, 1, 7, 5, 12, 14, 10]]] + } + }, + { 'name': 'VertexOnEdge', 'state': { @@ -181,6 +197,54 @@ export default defineTests([ 'vertices': [[-250, -250, -250], [-250, -250, 250], [-250, -8, 250], [-250, -8, 464], [-250, 250, -250], [-250, 250, -21], [-250, 426, -21], [-250, 426, 464], [250, -250, -250], [250, -250, 250], [250, -8, 250], [250, -8, 464], [250, 250, -250], [250, 250, -21], [250, 426, -21], [250, 426, 464]], 'faces': [[[8, 9, 1, 0]], [[5, 13, 12, 4]], [[10, 2, 1, 9]], [[8, 0, 4, 12]], [[13, 5, 6, 14]], [[2, 10, 11, 3]], [[15, 7, 3, 11]], [[14, 6, 7, 15]], [[12, 13, 14, 15, 11, 10, 9, 8]], [[3, 7, 6, 5, 4, 0, 1, 2]]] } + }, + + { + 'name': 'StickingOut2FacesExtrude', + 'state': { + 'sketches': {'0:3': {'Segment': [[[-21, 426], [464, 426]], [[464, 426], [464, -8]], [[464, -8], [-21, -8]], [[-21, -8], [-21, 426]]]}}, + 'operations': [{'type': 'BOX', 'params': {'width': 500, 'height': 500, 'depth': 500}}, { + 'type': 'EXTRUDE', + 'params': {'value': 50, 'prism': 1, 'angle': 0, 'rotation': 0, 'face': '0:3'} + }] + }, + 'expected': { + 'format': 'LOOPS', + 'vertices': [[-300, -8, -21], [-300, -8, 464], [-300, 426, -21], [-300, 426, 464], [-250, -250, -250], [-250, -250, 250], [-250, -8, -21], [-250, -8, 250], [-250, -8, 464], [-250, 250, -250], [-250, 250, -21], [-250, 250, 250], [-250, 426, -21], [-250, 426, 464], [250, -250, -250], [250, -250, 250], [250, 250, -250], [250, 250, 250]], + 'faces': [[[14, 15, 5, 4]], [[16, 17, 15, 14]], [[10, 11, 17, 16, 9]], [[7, 5, 15, 17, 11]], [[14, 4, 9, 16]], [[3, 13, 12, 2]], [[1, 8, 13, 3]], [[0, 6, 7, 8, 1]], [[2, 12, 10, 6, 0]], [[3, 2, 0, 1]], [[7, 6, 10, 9, 4, 5]], [[7, 11, 10, 12, 13, 8]]] + } + }, + + { + 'name': 'AllEdgesAdjacentExtrude', + 'state': { + 'sketches': {'0:3': {'Segment': [[[-250, 250], [250, 250]], [[250, 250], [250, -250]], [[250, -250], [-250, -250]], [[-250, -250], [-250, 250]]]}}, + 'operations': [{'type': 'BOX', 'params': {'width': 500, 'height': 500, 'depth': 500}}, { + 'type': 'EXTRUDE', + 'params': {'value': 50, 'prism': 1, 'angle': 0, 'rotation': 0, 'face': '0:3'} + }] + }, + 'expected': { + 'format': 'LOOPS', + 'vertices': [[-300, -250, -250], [-300, -250, 250], [-300, 250, -250], [-300, 250, 250], [-250, -250, -250], [-250, -250, 250], [-250, 250, -250], [-250, 250, 250], [250, -250, -250], [250, -250, 250], [250, 250, -250], [250, 250, 250]], + 'faces': [[[10, 11, 9, 8]], [[3, 2, 0, 1]], [[1, 0, 4, 8, 9, 5]], [[2, 3, 7, 11, 10, 6]], [[3, 1, 5, 9, 11, 7]], [[0, 2, 6, 10, 8, 4]]] + } + }, + + { + 'name': 'AllEdgesAdjacentCut', + 'state': { + 'sketches': {'0:3': {'Segment': [[[-250, 250], [250, 250]], [[250, 250], [250, -250]], [[250, -250], [-250, -250]], [[-250, -250], [-250, 250]]]}}, + 'operations': [{'type': 'BOX', 'params': {'width': 500, 'height': 500, 'depth': 500}}, { + 'type': 'CUT', + 'params': {'value': 50, 'prism': 1, 'angle': 0, 'rotation': 0, 'face': '0:3'} + }] + }, + 'expected': { + 'format': 'LOOPS', + 'vertices': [[-200, -250, -250], [-200, -250, 250], [-200, 250, -250], [-200, 250, 250], [250, -250, -250], [250, -250, 250], [250, 250, -250], [250, 250, 250]], + 'faces': [[[6, 7, 5, 4]], [[3, 2, 0, 1]], [[1, 0, 4, 5]], [[2, 3, 7, 6]], [[3, 1, 5, 7]], [[0, 2, 6, 4]]] + } } ]);