Skip to content

Commit 194945f

Browse files
committed
Add vertexes to curve intersection list in addition to surface intersections.
Sometimes a vertex can be used to split a curve where surface intersections can't. Those unsplit curves can cause boolean failures.
1 parent d72eba8 commit 194945f

File tree

1 file changed

+46
-4
lines changed

1 file changed

+46
-4
lines changed

src/srf/boolean.cpp

Lines changed: 46 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,29 @@ void SShell::MakeFromIntersectionOf(SShell *a, SShell *b) {
2020
MakeFromBoolean(a, b, SSurface::CombineAs::INTERSECTION);
2121
}
2222

23+
// We will be inserting existing verticies into curves to split them
24+
// todo: this is only using the ends of exact curves, and it is only
25+
// using them to split existing curves, not new intersections.
26+
// It resolves some issues but we could do better. We will need to
27+
// reorder things so the surface intersection curves exist prior to
28+
// splitting any curves at all in order to have their verticies too.
29+
static void FindVertsOnCurve(List<SInter> *l, const SCurve *curve, SShell *sh) {
30+
for(auto sc : sh->curve) {
31+
if(!sc.isExact) continue;
32+
for(int i=0; i<2; i++) {
33+
Vector pt = sc.exact.ctrl[ i==0 ? 0 : sc.exact.deg ];
34+
double t;
35+
curve->exact.ClosestPointTo(pt, &t, /*must converge=*/ false);
36+
double d = pt.Minus(curve->exact.PointAt(t)).Magnitude();
37+
if((t>LENGTH_EPS) && (t<(1.0-LENGTH_EPS)) && (d < LENGTH_EPS)) {
38+
SInter inter;
39+
inter.p = pt;
40+
l->Add(&inter);
41+
}
42+
}
43+
}
44+
}
45+
2346
//-----------------------------------------------------------------------------
2447
// Take our original pwl curve. Wherever an edge intersects a surface within
2548
// either agnstA or agnstB, split the piecewise linear element. Then refine
@@ -35,12 +58,21 @@ SCurve SCurve::MakeCopySplitAgainst(SShell *agnstA, SShell *agnstB,
3558
ret = *this;
3659
ret.pts = {};
3760

61+
// First find any vertex that lies on our curve.
62+
List<SInter> vertpts = {};
63+
if(agnstA)
64+
FindVertsOnCurve(&vertpts, this, agnstA);
65+
if(agnstB)
66+
FindVertsOnCurve(&vertpts, this, agnstB);
67+
3868
const SCurvePt *p = pts.First();
3969
ssassert(p != NULL, "Cannot split an empty curve");
4070
SCurvePt prev = *p;
4171
ret.pts.Add(p);
4272
p = pts.NextAfter(p);
43-
73+
74+
if(vertpts.n > 0) dbp("Verts on curve: %d", vertpts.n);
75+
4476
for(; p; p = pts.NextAfter(p)) {
4577
List<SInter> il = {};
4678

@@ -100,12 +132,21 @@ SCurve SCurve::MakeCopySplitAgainst(SShell *agnstA, SShell *agnstB,
100132
pi->p = (pi->srf)->PointAt(puv);
101133
}
102134
il.RemoveTagged();
103-
135+
}
136+
// Now add any vertex that is on this segment
137+
const Vector lineStart = prev.p;
138+
const Vector lineDirection = (p->p).Minus(prev.p);
139+
for(auto vtx : vertpts) {
140+
double t = (vtx.p.Minus(lineStart)).DivProjected(lineDirection);
141+
if((0.0 < t) && (t < 1.0)) {
142+
il.Add(&vtx);
143+
}
144+
}
145+
if(!il.IsEmpty()) {
146+
SInter *pi;
104147
// And now sort them in order along the line. Note that we must
105148
// do that after refining, in case the refining would make two
106149
// points switch places.
107-
const Vector lineStart = prev.p;
108-
const Vector lineDirection = (p->p).Minus(prev.p);
109150
std::sort(il.begin(), il.end(), [&](const SInter &a, const SInter &b) {
110151
double ta = (a.p.Minus(lineStart)).DivProjected(lineDirection);
111152
double tb = (b.p.Minus(lineStart)).DivProjected(lineDirection);
@@ -133,6 +174,7 @@ SCurve SCurve::MakeCopySplitAgainst(SShell *agnstA, SShell *agnstB,
133174
ret.pts.Add(p);
134175
prev = *p;
135176
}
177+
vertpts.Clear();
136178
return ret;
137179
}
138180

0 commit comments

Comments
 (0)