NURBS boolean improvement.
The 3-plane intersection code fails to converge when a curve joins two tangent NURBS patches. This adds a new function for intersecting exact curves with a surface to avoid those failures. Fixes simplified test model for issue #315.
This commit is contained in:
parent
f9529916c4
commit
4cceaa5310
@ -88,8 +88,15 @@ SCurve SCurve::MakeCopySplitAgainst(SShell *agnstA, SShell *agnstB,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// We're keeping the intersection, so actually refine it.
|
// We're keeping the intersection, so actually refine it. Finding the intersection
|
||||||
|
// to within EPS is important to match the ends of different chopped trim curves.
|
||||||
|
// The general 3-surface intersection fails to refine for trims where surfaces
|
||||||
|
// are tangent at the curve, but those trims are usually exact, so…
|
||||||
|
if(isExact) {
|
||||||
|
(pi->srf)->PointOnCurve(&exact, &(puv.x), &(puv.y));
|
||||||
|
} else {
|
||||||
(pi->srf)->PointOnSurfaces(srfA, srfB, &(puv.x), &(puv.y));
|
(pi->srf)->PointOnSurfaces(srfA, srfB, &(puv.x), &(puv.y));
|
||||||
|
}
|
||||||
pi->p = (pi->srf)->PointAt(puv);
|
pi->p = (pi->srf)->PointAt(puv);
|
||||||
}
|
}
|
||||||
il.RemoveTagged();
|
il.RemoveTagged();
|
||||||
|
@ -634,3 +634,58 @@ void SSurface::PointOnSurfaces(SSurface *s1, SSurface *s2, double *up, double *v
|
|||||||
dbp("didn't converge (three surfaces intersecting)");
|
dbp("didn't converge (three surfaces intersecting)");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SSurface::PointOnCurve(const SBezier *curve, double *up, double *vp)
|
||||||
|
{
|
||||||
|
Vector tu,tv,n;
|
||||||
|
double u = *up, v = *vp;
|
||||||
|
Vector ps = PointAt(u, v);
|
||||||
|
// Get initial guesses for t on the curve
|
||||||
|
double tCurve = 0.5;
|
||||||
|
curve->ClosestPointTo(ps, &tCurve, /*mustConverge=*/false);
|
||||||
|
if(tCurve < 0.0) tCurve = 0.0;
|
||||||
|
if(tCurve > 1.0) tCurve = 1.0;
|
||||||
|
|
||||||
|
for(int i = 0; i < 30; i++) {
|
||||||
|
// Approximate the surface by a plane
|
||||||
|
Vector ps = PointAt(u, v);
|
||||||
|
TangentsAt(u, v, &tu, &tv);
|
||||||
|
n = tu.Cross(tv).WithMagnitude(1);
|
||||||
|
|
||||||
|
// point on curve and tangent line direction
|
||||||
|
Vector pc = curve->PointAt(tCurve);
|
||||||
|
Vector tc = curve->TangentAt(tCurve);
|
||||||
|
|
||||||
|
if(ps.Equals(pc, RATPOLY_EPS)) {
|
||||||
|
*up = u;
|
||||||
|
*vp = v;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//pi is where the curve tangent line intersects the surface tangent plane
|
||||||
|
Vector pi;
|
||||||
|
double d = tc.Dot(n);
|
||||||
|
if (fabs(d) < 1e-10) { // parallel line and plane, guess the average rather than fail
|
||||||
|
pi = pc.Plus(ps).ScaledBy(0.5);
|
||||||
|
} else {
|
||||||
|
pi = pc.Minus(tc.ScaledBy(pc.Minus(ps).Dot(n)/d));
|
||||||
|
}
|
||||||
|
|
||||||
|
// project the point onto the tangent plane and line
|
||||||
|
{
|
||||||
|
Vector n = tu.Cross(tv);
|
||||||
|
Vector ty = n.Cross(tu).ScaledBy(1.0/tu.MagSquared());
|
||||||
|
Vector tx = tv.Cross(n).ScaledBy(1.0/tv.MagSquared());
|
||||||
|
|
||||||
|
Vector dp = pi.Minus(ps);
|
||||||
|
double du = dp.Dot(tx), dv = dp.Dot(ty);
|
||||||
|
|
||||||
|
u += du / tx.MagSquared();
|
||||||
|
v += dv / ty.MagSquared();
|
||||||
|
}
|
||||||
|
tCurve += pi.Minus(pc).Dot(tc) / tc.MagSquared();
|
||||||
|
if(tCurve < 0.0) tCurve = 0.0;
|
||||||
|
if(tCurve > 1.0) tCurve = 1.0;
|
||||||
|
}
|
||||||
|
dbp("didn't converge (surface and curve intersecting)");
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -332,6 +332,7 @@ public:
|
|||||||
bool PointIntersectingLine(Vector p0, Vector p1, double *u, double *v) const;
|
bool PointIntersectingLine(Vector p0, Vector p1, double *u, double *v) const;
|
||||||
Vector ClosestPointOnThisAndSurface(SSurface *srf2, Vector p);
|
Vector ClosestPointOnThisAndSurface(SSurface *srf2, Vector p);
|
||||||
void PointOnSurfaces(SSurface *s1, SSurface *s2, double *u, double *v);
|
void PointOnSurfaces(SSurface *s1, SSurface *s2, double *u, double *v);
|
||||||
|
void PointOnCurve(const SBezier *curve, double *up, double *vp);
|
||||||
Vector PointAt(double u, double v) const;
|
Vector PointAt(double u, double v) const;
|
||||||
Vector PointAt(Point2d puv) const;
|
Vector PointAt(Point2d puv) const;
|
||||||
void TangentsAt(double u, double v, Vector *tu, Vector *tv) const;
|
void TangentsAt(double u, double v, Vector *tu, Vector *tv) const;
|
||||||
|
@ -341,7 +341,11 @@ void SSurface::IntersectAgainst(SSurface *b, SShell *agnstA, SShell *agnstB,
|
|||||||
Vector p = si->p;
|
Vector p = si->p;
|
||||||
double u, v;
|
double u, v;
|
||||||
srfB->ClosestPointTo(p, &u, &v);
|
srfB->ClosestPointTo(p, &u, &v);
|
||||||
|
if(sc->isExact) {
|
||||||
|
srfB->PointOnCurve(&(sc->exact), &u, &v);
|
||||||
|
} else {
|
||||||
srfB->PointOnSurfaces(srfA, other, &u, &v);
|
srfB->PointOnSurfaces(srfA, other, &u, &v);
|
||||||
|
}
|
||||||
p = srfB->PointAt(u, v);
|
p = srfB->PointAt(u, v);
|
||||||
if(!spl.ContainsPoint(p)) {
|
if(!spl.ContainsPoint(p)) {
|
||||||
SPoint sp;
|
SPoint sp;
|
||||||
|
Loading…
Reference in New Issue
Block a user