Clean up the marching step size / chord tol stuff, and add code to
export an inexact curve by approximating it with piecwise cubic segments (whose endpoints lie exactly on the curve, and with exact tangent directions at the endpoints). [git-p4: depot-paths = "//depot/solvespace/": change = 1995]solver
parent
684ba7deb1
commit
bd36221219
|
@ -261,6 +261,26 @@ void SSurface::MakeEdgesInto(SShell *shell, SEdgeList *sel, bool asUv,
|
|||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Compute the exact tangent to the intersection curve between two surfaces,
|
||||
// by taking the cross product of the surface normals. We choose the direction
|
||||
// of this tangent so that its dot product with dir is positive.
|
||||
//-----------------------------------------------------------------------------
|
||||
Vector SSurface::ExactSurfaceTangentAt(Vector p, SSurface *srfA, SSurface *srfB,
|
||||
Vector dir)
|
||||
{
|
||||
Point2d puva, puvb;
|
||||
srfA->ClosestPointTo(p, &puva);
|
||||
srfB->ClosestPointTo(p, &puvb);
|
||||
Vector ts = (srfA->NormalAt(puva)).Cross(
|
||||
(srfB->NormalAt(puvb)));
|
||||
ts = ts.WithMagnitude(1);
|
||||
if(ts.Dot(dir) < 0) {
|
||||
ts = ts.ScaledBy(-1);
|
||||
}
|
||||
return ts;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Report our trim curves. If a trim curve is exact and sbl is not null, then
|
||||
// add its exact form to sbl. Otherwise, add its piecewise linearization to
|
||||
|
@ -293,6 +313,76 @@ void SSurface::MakeSectionEdgesInto(SShell *shell,
|
|||
keep_aft.SplitAt(tf, &keep_bef, &junk_aft);
|
||||
|
||||
sbl->l.Add(&keep_bef);
|
||||
} else if(sbl && !sel && !sc->isExact) {
|
||||
// We must approximate this trim curve, as piecewise cubic sections.
|
||||
SSurface *srfA = shell->surface.FindById(sc->surfA),
|
||||
*srfB = shell->surface.FindById(sc->surfB);
|
||||
|
||||
Vector s = stb->backwards ? stb->finish : stb->start,
|
||||
f = stb->backwards ? stb->start : stb->finish;
|
||||
|
||||
int sp, fp;
|
||||
for(sp = 0; sp < sc->pts.n; sp++) {
|
||||
if(s.Equals(sc->pts.elem[sp].p)) break;
|
||||
}
|
||||
if(sp >= sc->pts.n) return;
|
||||
for(fp = sp; fp < sc->pts.n; fp++) {
|
||||
if(f.Equals(sc->pts.elem[fp].p)) break;
|
||||
}
|
||||
if(fp >= sc->pts.n) return;
|
||||
// So now the curve we want goes from elem[sp] to elem[fp]
|
||||
|
||||
while(sp < fp) {
|
||||
// Initially, we'll try approximating the entire trim curve
|
||||
// as a single Bezier segment
|
||||
int fpt = fp;
|
||||
|
||||
for(;;) {
|
||||
// So construct a cubic Bezier with the correct endpoints
|
||||
// and tangents for the current span.
|
||||
Vector st = sc->pts.elem[sp].p,
|
||||
ft = sc->pts.elem[fpt].p,
|
||||
sf = ft.Minus(st);
|
||||
double m = sf.Magnitude() / 3;
|
||||
|
||||
Vector stan = ExactSurfaceTangentAt(st, srfA, srfB, sf),
|
||||
ftan = ExactSurfaceTangentAt(ft, srfA, srfB, sf);
|
||||
|
||||
SBezier sb = SBezier::From(st,
|
||||
st.Plus (stan.WithMagnitude(m)),
|
||||
ft.Minus(ftan.WithMagnitude(m)),
|
||||
ft);
|
||||
|
||||
// And test how much this curve deviates from the
|
||||
// intermediate points (if any).
|
||||
int i;
|
||||
bool tooFar = false;
|
||||
for(i = sp + 1; i <= (fpt - 1); i++) {
|
||||
Vector p = sc->pts.elem[i].p;
|
||||
double t;
|
||||
sb.ClosestPointTo(p, &t, false);
|
||||
Vector pp = sb.PointAt(t);
|
||||
if((pp.Minus(p)).Magnitude() > SS.ChordTolMm()/2) {
|
||||
tooFar = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(tooFar) {
|
||||
// Deviates by too much, so try a shorter span
|
||||
fpt--;
|
||||
continue;
|
||||
} else {
|
||||
// Okay, so use this piece and break.
|
||||
sbl->l.Add(&sb);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// And continue interpolating, starting wherever the curve
|
||||
// we just generated finishes.
|
||||
sp = fpt;
|
||||
}
|
||||
} else {
|
||||
if(sel) MakeTrimEdgesInto(sel, false, sc, stb);
|
||||
}
|
||||
|
|
|
@ -278,6 +278,8 @@ public:
|
|||
void MakeTrimEdgesInto(SEdgeList *sel, bool asUv, SCurve *sc, STrimBy *stb);
|
||||
void MakeEdgesInto(SShell *shell, SEdgeList *sel, bool asUv,
|
||||
SShell *useCurvesFrom=NULL);
|
||||
Vector ExactSurfaceTangentAt(Vector p, SSurface *srfA, SSurface *srfB,
|
||||
Vector dir);
|
||||
void MakeSectionEdgesInto(SShell *shell, SEdgeList *sel, SBezierList *sbl);
|
||||
void MakeClassifyingBsp(SShell *shell, SShell *useCurvesFrom);
|
||||
double ChordToleranceForEdge(Vector a, Vector b);
|
||||
|
|
|
@ -349,6 +349,12 @@ void SSurface::IntersectAgainst(SSurface *b, SShell *agnstA, SShell *agnstB,
|
|||
spl.l.ClearTags();
|
||||
spl.l.elem[0].tag = 1;
|
||||
spl.l.RemoveTagged();
|
||||
|
||||
// Our chord tolerance is whatever the user specified
|
||||
double maxtol = SS.ChordTolMm();
|
||||
int maxsteps = max(300, SS.maxSegments*3);
|
||||
|
||||
// The curve starts at our starting point.
|
||||
SCurvePt padd;
|
||||
ZERO(&padd);
|
||||
padd.vertex = true;
|
||||
|
@ -357,11 +363,11 @@ void SSurface::IntersectAgainst(SSurface *b, SShell *agnstA, SShell *agnstB,
|
|||
|
||||
Point2d pa, pb;
|
||||
Vector np, npc;
|
||||
bool fwd;
|
||||
// Better to start with a too-small step, so that we don't miss
|
||||
// features of the curve entirely.
|
||||
bool fwd;
|
||||
double tol, step = SS.ChordTolMm();
|
||||
for(a = 0; a < 100; a++) {
|
||||
double tol, step = maxtol;
|
||||
for(a = 0; a < maxsteps; a++) {
|
||||
ClosestPointTo(start, &pa);
|
||||
b->ClosestPointTo(start, &pb);
|
||||
|
||||
|
@ -378,10 +384,8 @@ void SSurface::IntersectAgainst(SSurface *b, SShell *agnstA, SShell *agnstB,
|
|||
}
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
do {
|
||||
if(i++ > 20) break;
|
||||
|
||||
int i;
|
||||
for(i = 0; i < 20; i++) {
|
||||
Vector dp = nb.Cross(na);
|
||||
if(!fwd) dp = dp.ScaledBy(-1);
|
||||
dp = dp.WithMagnitude(step);
|
||||
|
@ -390,24 +394,30 @@ void SSurface::IntersectAgainst(SSurface *b, SShell *agnstA, SShell *agnstB,
|
|||
npc = ClosestPointOnThisAndSurface(b, np);
|
||||
tol = (npc.Minus(np)).Magnitude();
|
||||
|
||||
if(tol > SS.ChordTolMm()*0.8) {
|
||||
if(tol > maxtol*0.8) {
|
||||
step *= 0.95;
|
||||
} else {
|
||||
step /= 0.95;
|
||||
}
|
||||
} while(tol > SS.ChordTolMm() || tol < SS.ChordTolMm()/2);
|
||||
|
||||
if((tol < maxtol) && (tol > maxtol/2)) {
|
||||
// If we meet the chord tolerance test, and we're
|
||||
// not too fine, then we break out.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
SPoint *sp;
|
||||
for(sp = spl.l.First(); sp; sp = spl.l.NextAfter(sp)) {
|
||||
if((sp->p).OnLineSegment(start, npc, 2*SS.ChordTolMm())) {
|
||||
sp->tag = 1;
|
||||
a = 1000;
|
||||
a = maxsteps;
|
||||
npc = sp->p;
|
||||
}
|
||||
}
|
||||
|
||||
padd.p = npc;
|
||||
padd.vertex = (a == 1000);
|
||||
padd.vertex = (a == maxsteps);
|
||||
sc.pts.Add(&padd);
|
||||
|
||||
start = npc;
|
||||
|
@ -419,7 +429,6 @@ void SSurface::IntersectAgainst(SSurface *b, SShell *agnstA, SShell *agnstB,
|
|||
SCurve split = sc.MakeCopySplitAgainst(agnstA, agnstB, this, b);
|
||||
sc.Clear();
|
||||
into->curve.AddAndAssignId(&split);
|
||||
break;
|
||||
}
|
||||
spl.Clear();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue