//----------------------------------------------------------------------------- // 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 // sel. //----------------------------------------------------------------------------- void SSurface::MakeSectionEdgesInto(SShell *shell, SEdgeList *sel, SBezierList *sbl) { STrimBy *stb; for(stb = trim.First(); stb; stb = trim.NextAfter(stb)) { SCurve *sc = shell->curve.FindById(stb->curve); SBezier *sb = &(sc->exact); if(sbl && sc->isExact && (sb->deg != 1 || !sel)) { double ts, tf; if(stb->backwards) { sb->ClosestPointTo(stb->start, &tf); sb->ClosestPointTo(stb->finish, &ts); } else { sb->ClosestPointTo(stb->start, &ts); sb->ClosestPointTo(stb->finish, &tf); } SBezier junk_bef, keep_aft; sb->SplitAt(ts, &junk_bef, &keep_aft); // In the kept piece, the range that used to go from ts to 1 // now goes from 0 to 1; so rescale tf appropriately. tf = (tf - ts)/(1 - ts); SBezier keep_bef, junk_aft; 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, AS_XYZ, sc, stb); } } }