//----------------------------------------------------------------------------- // 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); } } }
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; }