fix a bug when two merge faces make a cut and create a new curve/edge

forbid partially tangent edges with new curve - should be handled level before
update tests
This commit is contained in:
Val Erastov 2018-02-07 00:45:01 -08:00
parent 9eb2400a01
commit 3b575c149d
3 changed files with 71 additions and 32 deletions

View file

@ -168,12 +168,23 @@ function replaceEdges() {
}
function replaceMergedFaces(facesData, mergedFaces) {
function addDecayed(he, out) {
let decayed = EdgeSolveData.get(he).decayed;
if (decayed) {
decayed.forEach(de => addDecayed(de, out));
} else {
out.push(he);
}
}
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();
@ -654,6 +665,10 @@ function intersectFaces(shellA, shellB, operationType) {
__DEBUG__.AddCurve(curve);
}
if (hasCoincidentEdge(curve, faceA) || hasCoincidentEdge(curve, faceB)) {
continue;
}
curve = fixCurveDirection(curve, faceA.surface, faceB.surface, operationType);
const nodes = [];
collectNodesOfIntersectionOfFace(curve, faceA, nodes, A);
@ -740,6 +755,15 @@ function nodeByPoint(nodes, point, u, curve, vertex) {
return node;
}
function hasCoincidentEdge(curve, face) {
for (let edge of face.edges) {
if (curveAndEdgeCoincident(curve, edge)) {
return true;
}
}
return false;
}
function collectNodesOfIntersectionOfFace(curve, face, nodes, operand) {
for (let loop of face.loops) {
collectNodesOfIntersection(curve, loop, nodes, operand);
@ -749,27 +773,9 @@ function collectNodesOfIntersectionOfFace(curve, face, nodes, operand) {
function collectNodesOfIntersection(curve, loop, nodes, operand) {
// __DEBUG__.AddCurve(curve, 0xffffff);
let skippedEnclosures = new Set();
let coincidentEdges = new Set();
for (let edge of loop.halfEdges) {
if (curveAndEdgeCoincident(curve, edge)) {
coincidentEdges.add(edge);
}
}
let encloses = loop.encloses;
for (let [a, b, v] of encloses) {
if (coincidentEdges.has(a)) {
let sameDir = a.tangentAtStart().dot(curve.tangentAtPoint(a.vertexA.point)) > 0;
let vertex = sameDir ? a.vertexA : a.vertexB;
skippedEnclosures.add(vertex);
let node = nodeByPoint(nodes, vertex.point, undefined, curve, vertex);
node.leaves[operand] = true;
}
}
for (let [a, b, v] of encloses) {
if (coincidentEdges.has(a) && coincidentEdges.has(b)) {
continue;
}
if (skippedEnclosures.has(v)) {
continue;
}
@ -786,9 +792,7 @@ function collectNodesOfIntersection(curve, loop, nodes, operand) {
}
}
for (let edge of loop.halfEdges) {
if (!coincidentEdges.has(edge)) {
intersectCurveWithEdge(curve, edge, nodes, operand);
}
intersectCurveWithEdge(curve, edge, nodes, operand);
}
}
@ -909,16 +913,29 @@ function splitEdgeByVertex(edge, vertex) {
h2.next = halfEdge.next;
h2.next.prev = h2;
EdgeSolveData.createIfEmpty(halfEdge).decayed = [h1, h2];
}
updateInLoop(edge.halfEdge1, edge1.halfEdge1, edge2.halfEdge1);
updateInLoop(edge.halfEdge2, edge2.halfEdge2, edge1.halfEdge2);
EdgeSolveData.transfer(edge.halfEdge1, edge1.halfEdge1);
EdgeSolveData.transfer(edge.halfEdge1, edge2.halfEdge1);
function transferPriority(from, to) {
let priority = getPriority(from);
if (priority !== 0) {
EdgeSolveData.setPriority(to, priority);
}
}
EdgeSolveData.transfer(edge.halfEdge2, edge2.halfEdge2);
EdgeSolveData.transfer(edge.halfEdge2, edge1.halfEdge2);
transferPriority(edge.halfEdge1, edge1.halfEdge1);
transferPriority(edge.halfEdge1, edge2.halfEdge1);
transferPriority(edge.halfEdge2, edge2.halfEdge2);
transferPriority(edge.halfEdge2, edge1.halfEdge2);
if (isEdgeTransferred(edge)) {
markEdgeTransferred(edge1);
markEdgeTransferred(edge2);
}
return [edge1, edge2];
}
@ -1026,10 +1043,6 @@ EdgeSolveData.clear = function(edge) {
delete edge.data[MY];
};
EdgeSolveData.transfer = function(from, to) {
to.data[MY] = from.data[MY];
};
EdgeSolveData.setPriority = function(halfEdge, value) {
EdgeSolveData.createIfEmpty(halfEdge).priority = value;
};
@ -1232,13 +1245,19 @@ function isSameEdge(e1, e2) {
function curveAndEdgeCoincident(curve, edge) {
let tess = edge.tessellate();
//Do reverese to optimaze a bit because the first point is usually checked
//Do reverse to optimize a bit because the first point is usually checked
let touches = 0;
for (let i = tess.length - 1; i >= 0; i--) {
let pt1 = tess[i];
let pt2 = curve.point(curve.param(pt1));
if (!veq(pt1, pt2)) {
if (touches > 1) {
//partial tangency should be handled before face-face intersection analysis
throw new CadError('BOOLEAN_INVALID_RESULT', {edge});
}
return false;
}
touches++;
}
return true;
}

View file

@ -20,7 +20,7 @@ export default defineTests([
'expected': {
'format': 'LOOPS',
'vertices': [[-293, 148, 0], [-293, 148, 112], [-159, 233, 62], [-159, 75, 62], [-159, 75, 112], [-159, 233, 112], [-115, 261, 112], [-115, 261, 62], [-110, 48, 112], [-110, 48, 62], [-38, 9, 0], [-38, 9, 112], [-12, 326, 0], [-12, 326, 112], [38, 48, 62], [38, 48, 112], [38, 261, 62], [38, 261, 112], [332, 110, 0], [332, 110, 112]],
'faces': [[[19, 18, 12, 13]], [[11, 10, 18, 19]], [[9, 3, 4, 1, 0, 10, 11, 8]], [[2, 7, 6, 13, 12, 0, 1, 5]], [[0, 12, 18, 10]], [[15, 17, 16, 14]], [[6, 7, 16, 17]], [[2, 5, 4, 3]], [[9, 8, 15, 14]], [[7, 2, 3, 9, 14, 16]], [[1, 4, 5]], [[6, 17, 15, 8, 11, 19, 13]]]
'faces': [[[19, 18, 12, 13]], [[11, 10, 18, 19]], [[9, 3, 4, 1, 0, 10, 11, 8]], [[2, 7, 6, 13, 12, 0, 1, 5]], [[0, 12, 18, 10]], [[15, 17, 16, 14]], [[6, 7, 16, 17]], [[2, 5, 4, 3]], [[9, 8, 15, 14]], [[7, 2, 3, 9, 14, 16]], [[4, 5, 1]], [[6, 17, 15, 8, 11, 19, 13]]]
}
},
{
@ -54,7 +54,7 @@ export default defineTests([
'expected': {
'format': 'LOOPS',
'vertices': [[-300, 13, 17], [-300, 13, 250], [-300, 250, 17], [-300, 250, 250], [-250, -250, -250], [-250, -250, 250], [-250, 13, 17], [-250, 13, 250], [-250, 250, -250], [-250, 250, 17], [-250, 250, 250], [-120, -250, -49], [-120, -250, 172], [-120, 250, -49], [-120, 250, 172], [-107, -155, 250], [-107, -155, 300], [-107, 53, 250], [-107, 53, 300], [-82, 200, -160], [-82, 200, -49], [-82, 200, 172], [-82, 200, 210], [-82, 250, -160], [-82, 250, -49], [-82, 250, 172], [-82, 250, 210], [-60, 200, 172], [-60, -73, -250], [-60, -73, -49], [-60, -73, 172], [-60, -73, 300], [-60, 53, 250], [-60, 53, 300], [-60, 200, -160], [-60, 200, 210], [-60, 212, -250], [-60, 212, -160], [-60, 212, 210], [-60, 212, 250], [-60, 200, -49], [70, 212, -160], [70, 212, 172], [70, 212, 210], [70, 250, -160], [70, 250, -49], [70, 250, 172], [70, 250, 210], [70, 212, -49], [107, -250, -49], [107, -250, 172], [107, -73, 172], [107, -73, -49], [107, 212, -49], [107, 212, 172], [107, 250, -49], [107, 250, 172], [140, -155, 250], [140, -155, 300], [140, -73, 250], [140, -73, 300], [220, -73, -250], [220, -73, 250], [220, 42, -155], [220, 42, -44], [220, 188, -155], [220, 188, -44], [220, 212, -250], [220, 212, 250], [250, -250, -250], [250, -250, 250], [250, 42, -155], [250, 42, -44], [250, 188, -155], [250, 188, -44], [250, 250, -250], [250, 250, 250]],
'faces': [[[1, 0, 6, 7]], [[0, 2, 9, 6]], [[0, 1, 3, 2]], [[6, 9, 8, 4, 5, 7]], [[17, 18, 33, 32]], [[58, 57, 59, 60]], [[16, 15, 57, 58]], [[18, 17, 15, 16]], [[58, 60, 31, 33, 18, 16]], [[1, 7, 5, 70, 76, 10, 3], [17, 32, 39, 68, 62, 59, 57, 15]], [[56, 55, 53, 54]], [[49, 50, 51, 52]], [[21, 27, 30, 51, 50, 12, 14, 25]], [[42, 46, 56, 54]], [[11, 13, 14, 12]], [[40, 20, 24, 13, 11, 49, 52, 29]], [[45, 48, 53, 55]], [[5, 4, 69, 70], [50, 49, 11, 12]], [[67, 61, 62, 68], [63, 65, 66, 64]], [[61, 28, 29, 52, 51, 30, 31, 60, 59, 62]], [[34, 40, 29, 28, 36, 37]], [[27, 35, 38, 39, 32, 33, 31, 30]], [[38, 43, 42, 54, 53, 48, 41, 37, 36, 67, 68, 39]], [[8, 75, 69, 4], [67, 36, 28, 61]], [[72, 64, 66, 74]], [[71, 63, 64, 72]], [[73, 65, 63, 71]], [[74, 66, 65, 73]], [[70, 69, 75, 76], [73, 71, 72, 74]], [[41, 48, 45, 44]], [[42, 43, 47, 46]], [[37, 41, 44, 23, 19, 34]], [[24, 20, 19, 23]], [[21, 25, 26, 22]], [[43, 38, 35, 22, 26, 47]], [[35, 27, 21, 22]], [[40, 34, 19, 20]], [[2, 3, 10, 76, 75, 8, 9], [56, 46, 47, 26, 25, 14, 13, 24, 23, 44, 45, 55]]]
'faces': [[[1, 0, 6, 7]], [[0, 2, 9, 6]], [[0, 1, 3, 2]], [[6, 9, 8, 4, 5, 7]], [[17, 18, 33, 32]], [[58, 57, 59, 60]], [[16, 15, 57, 58]], [[18, 17, 15, 16]], [[58, 60, 31, 33, 18, 16]], [[5, 70, 76, 10, 3, 1, 7], [17, 32, 39, 68, 62, 59, 57, 15]], [[56, 55, 53, 54]], [[49, 50, 51, 52]], [[21, 27, 30, 51, 50, 12, 14, 25]], [[42, 46, 56, 54]], [[11, 13, 14, 12]], [[40, 20, 24, 13, 11, 49, 52, 29]], [[45, 48, 53, 55]], [[5, 4, 69, 70], [50, 49, 11, 12]], [[67, 61, 62, 68], [63, 65, 66, 64]], [[61, 28, 29, 52, 51, 30, 31, 60, 59, 62]], [[34, 40, 29, 28, 36, 37]], [[27, 35, 38, 39, 32, 33, 31, 30]], [[38, 43, 42, 54, 53, 48, 41, 37, 36, 67, 68, 39]], [[8, 75, 69, 4], [67, 36, 28, 61]], [[72, 64, 66, 74]], [[71, 63, 64, 72]], [[73, 65, 63, 71]], [[74, 66, 65, 73]], [[70, 69, 75, 76], [73, 71, 72, 74]], [[41, 48, 45, 44]], [[42, 43, 47, 46]], [[37, 41, 44, 23, 19, 34]], [[24, 20, 19, 23]], [[21, 25, 26, 22]], [[43, 38, 35, 22, 26, 47]], [[35, 27, 21, 22]], [[40, 34, 19, 20]], [[9, 2, 3, 10, 76, 75, 8], [46, 47, 26, 25, 14, 13, 24, 23, 44, 45, 55, 56]]]
}
}

View file

@ -98,6 +98,26 @@ export default defineTests([
'vertices': [[-250, -250, -250], [-250, -250, 250], [-250, -1, -250], [-250, -1, 91], [-250, 250, 91], [-250, 250, 250], [-200, -1, -250], [-200, -1, 91], [-200, 250, -250], [-200, 250, 91], [250, -250, -250], [250, -250, 250], [250, 250, -250], [250, 250, 250]],
'faces': [[[10, 11, 1, 0]], [[12, 13, 11, 10]], [[5, 1, 11, 13]], [[6, 8, 12, 10, 0, 2]], [[6, 2, 3, 7]], [[3, 4, 9, 7]], [[8, 6, 7, 9]], [[8, 9, 4, 5, 13, 12]], [[4, 3, 2, 0, 1, 5]]]
}
},
{
'name': 'MergedFacesCreateIntersectionCurve',
'state': {
'sketches': {
'1:5': {'Segment': [[[92, 144], [351, 144]], [[351, 144], [351, -106]], [[351, -106], [92, -106]], [[92, -106], [92, 144]]]},
'0:2': {'Segment': [[[-172, 145], [30, 145]], [[30, 145], [30, -99]], [[30, -99], [-172, -99]], [[-172, -99], [-172, 145]]]}
},
'operations': [{'type': 'BOX', 'params': {'width': 500, 'height': 500, 'depth': 500}}, {
'type': 'CUT',
'params': {'value': 50, 'prism': 1, 'angle': 0, 'rotation': 0, 'face': '0:2'}
}, {'type': 'CUT', 'params': {'value': 50, 'prism': 1, 'angle': 0, 'rotation': 0, 'face': '1:5'}}]
},
'expected': {
'format': 'LOOPS',
'vertices': [[-250, -250, -250], [-250, -250, 250], [-250, 200, -106], [-250, 200, 144], [-250, 250, -250], [-250, 250, -106], [-250, 250, 144], [-250, 250, 250], [-92, 200, -106], [-92, 200, 144], [-92, 250, -106], [-92, 250, 144], [-30, 200, -99], [-30, 200, 145], [-30, 250, -99], [-30, 250, 145], [172, 200, -99], [172, 200, 145], [172, 250, -99], [172, 250, 145], [250, -250, -250], [250, -250, 250], [250, 250, -250], [250, 250, 250]],
'faces': [[[0, 20, 21, 1]], [[20, 22, 23, 21]], [[3, 2, 5, 4, 0, 1, 7, 6]], [[23, 7, 1, 21]], [[22, 20, 0, 4]], [[17, 19, 18, 16]], [[16, 18, 14, 12]], [[12, 14, 15, 13]], [[13, 15, 19, 17]], [[11, 10, 8, 9]], [[5, 2, 8, 10]], [[3, 6, 11, 9]], [[2, 3, 9, 8]], [[16, 12, 13, 17]], [[10, 11, 6, 7, 23, 22, 4, 5], [15, 14, 18, 19]]]
}
}
]);