Пример #1
0
//-----------------------------------------------------------------------------
// 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);
        }
    }
}