Пример #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);
        }
    }
}
Пример #2
0
hEntity GraphicsWindow::SplitCubic(hEntity he, Vector pinter) {
    // Save the original endpoints, since we're about to delete this entity.
    Entity *e01 = SK.GetEntity(he);
    SBezierList sbl;
    ZERO(&sbl);
    e01->GenerateBezierCurves(&sbl);

    hEntity hep0 = e01->point[0],
            hep1 = e01->point[3+e01->extraPoints],
            hep0n = Entity::NO_ENTITY, // the new start point
            hep1n = Entity::NO_ENTITY, // the new finish point
            hepin = Entity::NO_ENTITY; // the intersection point

    // The curve may consist of multiple cubic segments. So find which one
    // contains the intersection point.
    double t;
    int i, j;
    for(i = 0; i < sbl.l.n; i++) {
        SBezier *sb = &(sbl.l.elem[i]);
        if(sb->deg != 3) oops();

        sb->ClosestPointTo(pinter, &t, false);
        if(pinter.Equals(sb->PointAt(t))) {
            // Split that segment at the intersection.
            SBezier b0i, bi1, b01 = *sb;
            b01.SplitAt(t, &b0i, &bi1);

            // Add the two cubic segments this one gets split into.
            hRequest r0i = AddRequest(Request::CUBIC, false),
                     ri1 = AddRequest(Request::CUBIC, false);
            // Don't get entities till after adding, realloc issues

            Entity *e0i = SK.GetEntity(r0i.entity(0)),
                   *ei1 = SK.GetEntity(ri1.entity(0));

            for(j = 0; j <= 3; j++) {
                SK.GetEntity(e0i->point[j])->PointForceTo(b0i.ctrl[j]);
            }
            for(j = 0; j <= 3; j++) {
                SK.GetEntity(ei1->point[j])->PointForceTo(bi1.ctrl[j]);
            }

            Constraint::ConstrainCoincident(e0i->point[3], ei1->point[0]);
            if(i == 0) hep0n = e0i->point[0];
            hep1n = ei1->point[3];
            hepin = e0i->point[3];
        } else {
            hRequest r = AddRequest(Request::CUBIC, false);
            Entity *e = SK.GetEntity(r.entity(0));

            for(j = 0; j <= 3; j++) {
                SK.GetEntity(e->point[j])->PointForceTo(sb->ctrl[j]);
            }

            if(i == 0) hep0n = e->point[0];
            hep1n = e->point[3];
        }
    }

    sbl.Clear();

    ReplacePointInConstraints(hep0, hep0n);
    ReplacePointInConstraints(hep1, hep1n);
    return hepin;
}