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.
This commit is contained in:
parent
6b5936b2f6
commit
ab10e38d44
@ -20,6 +20,32 @@ void SShell::MakeFromIntersectionOf(SShell *a, SShell *b) {
|
|||||||
MakeFromBoolean(a, b, SSurface::CombineAs::INTERSECTION);
|
MakeFromBoolean(a, b, SSurface::CombineAs::INTERSECTION);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We will be inserting existing verticies into curves to split them
|
||||||
|
// todo: this is only using the ends of exact curves, and it is only
|
||||||
|
// using them to split existing curves, not new intersections.
|
||||||
|
// It resolves some issues but we could do better. We will need to
|
||||||
|
// reorder things so the surface intersection curves exist prior to
|
||||||
|
// splitting any curves at all in order to have their verticies too.
|
||||||
|
// Better still would be to get curve/surface intersection to work
|
||||||
|
// more reliably at the edges - maybe do curve/curve tests as part
|
||||||
|
// of the curve-surface intersection test.
|
||||||
|
static void FindVertsOnCurve(List<SInter> *l, const SCurve *curve, SShell *sh) {
|
||||||
|
for(auto sc : sh->curve) {
|
||||||
|
if(!sc.isExact) continue;
|
||||||
|
for(int i=0; i<2; i++) {
|
||||||
|
Vector pt = sc.exact.ctrl[ i==0 ? 0 : sc.exact.deg ];
|
||||||
|
double t;
|
||||||
|
curve->exact.ClosestPointTo(pt, &t, /*must converge=*/ false);
|
||||||
|
double d = pt.Minus(curve->exact.PointAt(t)).Magnitude();
|
||||||
|
if((t>LENGTH_EPS) && (t<(1.0-LENGTH_EPS)) && (d < LENGTH_EPS)) {
|
||||||
|
SInter inter;
|
||||||
|
inter.p = pt;
|
||||||
|
l->Add(&inter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// Take our original pwl curve. Wherever an edge intersects a surface within
|
// Take our original pwl curve. Wherever an edge intersects a surface within
|
||||||
// either agnstA or agnstB, split the piecewise linear element. Then refine
|
// either agnstA or agnstB, split the piecewise linear element. Then refine
|
||||||
@ -35,12 +61,19 @@ SCurve SCurve::MakeCopySplitAgainst(SShell *agnstA, SShell *agnstB,
|
|||||||
ret = *this;
|
ret = *this;
|
||||||
ret.pts = {};
|
ret.pts = {};
|
||||||
|
|
||||||
|
// First find any vertex that lies on our curve.
|
||||||
|
List<SInter> vertpts = {};
|
||||||
|
if(agnstA)
|
||||||
|
FindVertsOnCurve(&vertpts, this, agnstA);
|
||||||
|
if(agnstB)
|
||||||
|
FindVertsOnCurve(&vertpts, this, agnstB);
|
||||||
|
|
||||||
const SCurvePt *p = pts.First();
|
const SCurvePt *p = pts.First();
|
||||||
ssassert(p != NULL, "Cannot split an empty curve");
|
ssassert(p != NULL, "Cannot split an empty curve");
|
||||||
SCurvePt prev = *p;
|
SCurvePt prev = *p;
|
||||||
ret.pts.Add(p);
|
ret.pts.Add(p);
|
||||||
p = pts.NextAfter(p);
|
p = pts.NextAfter(p);
|
||||||
|
|
||||||
for(; p; p = pts.NextAfter(p)) {
|
for(; p; p = pts.NextAfter(p)) {
|
||||||
List<SInter> il = {};
|
List<SInter> il = {};
|
||||||
|
|
||||||
@ -100,12 +133,22 @@ SCurve SCurve::MakeCopySplitAgainst(SShell *agnstA, SShell *agnstB,
|
|||||||
pi->p = (pi->srf)->PointAt(puv);
|
pi->p = (pi->srf)->PointAt(puv);
|
||||||
}
|
}
|
||||||
il.RemoveTagged();
|
il.RemoveTagged();
|
||||||
|
}
|
||||||
|
// Now add any vertex that is on this segment
|
||||||
|
const Vector lineStart = prev.p;
|
||||||
|
const Vector lineDirection = (p->p).Minus(prev.p);
|
||||||
|
for(auto vtx : vertpts) {
|
||||||
|
double t = (vtx.p.Minus(lineStart)).DivProjected(lineDirection);
|
||||||
|
if((0.0 < t) && (t < 1.0)) {
|
||||||
|
il.Add(&vtx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(!il.IsEmpty()) {
|
||||||
|
SInter *pi;
|
||||||
|
|
||||||
// And now sort them in order along the line. Note that we must
|
// And now sort them in order along the line. Note that we must
|
||||||
// do that after refining, in case the refining would make two
|
// do that after refining, in case the refining would make two
|
||||||
// points switch places.
|
// points switch places.
|
||||||
const Vector lineStart = prev.p;
|
|
||||||
const Vector lineDirection = (p->p).Minus(prev.p);
|
|
||||||
std::sort(il.begin(), il.end(), [&](const SInter &a, const SInter &b) {
|
std::sort(il.begin(), il.end(), [&](const SInter &a, const SInter &b) {
|
||||||
double ta = (a.p.Minus(lineStart)).DivProjected(lineDirection);
|
double ta = (a.p.Minus(lineStart)).DivProjected(lineDirection);
|
||||||
double tb = (b.p.Minus(lineStart)).DivProjected(lineDirection);
|
double tb = (b.p.Minus(lineStart)).DivProjected(lineDirection);
|
||||||
@ -133,6 +176,7 @@ SCurve SCurve::MakeCopySplitAgainst(SShell *agnstA, SShell *agnstB,
|
|||||||
ret.pts.Add(p);
|
ret.pts.Add(p);
|
||||||
prev = *p;
|
prev = *p;
|
||||||
}
|
}
|
||||||
|
vertpts.Clear();
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user