int StepFileWriter::ExportCurveLoop(SBezierLoop *loop, bool inner) { if(loop->l.n < 1) oops(); List<int> listOfTrims; ZERO(&listOfTrims); SBezier *sb = &(loop->l.elem[loop->l.n - 1]); // Generate "exactly closed" contours, with the same vertex id for the // finish of a previous edge and the start of the next one. So we need // the finish of the last Bezier in the loop before we start our process. fprintf(f, "#%d=CARTESIAN_POINT('',(%.10f,%.10f,%.10f));\n", id, CO(sb->Finish())); fprintf(f, "#%d=VERTEX_POINT('',#%d);\n", id+1, id); int lastFinish = id + 1, prevFinish = lastFinish; id += 2; for(sb = loop->l.First(); sb; sb = loop->l.NextAfter(sb)) { int curveId = ExportCurve(sb); int thisFinish; if(loop->l.NextAfter(sb) != NULL) { fprintf(f, "#%d=CARTESIAN_POINT('',(%.10f,%.10f,%.10f));\n", id, CO(sb->Finish())); fprintf(f, "#%d=VERTEX_POINT('',#%d);\n", id+1, id); thisFinish = id + 1; id += 2; } else { thisFinish = lastFinish; } fprintf(f, "#%d=EDGE_CURVE('',#%d,#%d,#%d,%s);\n", id, prevFinish, thisFinish, curveId, ".T."); fprintf(f, "#%d=ORIENTED_EDGE('',*,*,#%d,.T.);\n", id+1, id); int oe = id+1; listOfTrims.Add(&oe); id += 2; prevFinish = thisFinish; } fprintf(f, "#%d=EDGE_LOOP('',(", id); int *oe; for(oe = listOfTrims.First(); oe; oe = listOfTrims.NextAfter(oe)) { fprintf(f, "#%d", *oe); if(listOfTrims.NextAfter(oe) != NULL) fprintf(f, ","); } fprintf(f, "));\n"); int fb = id + 1; fprintf(f, "#%d=%s('',#%d,.T.);\n", fb, inner ? "FACE_BOUND" : "FACE_OUTER_BOUND", id); id += 2; listOfTrims.Clear(); return fb; }
//----------------------------------------------------------------------------- // Assemble curves in sbl into a single loop. The curves may appear in any // direction (start to finish, or finish to start), and will be reversed if // necessary. The curves in the returned loop are removed from sbl, even if // the loop cannot be closed. //----------------------------------------------------------------------------- SBezierLoop SBezierLoop::FromCurves(SBezierList *sbl, bool *allClosed, SEdge *errorAt) { SBezierLoop loop; ZERO(&loop); if(sbl->l.n < 1) return loop; sbl->l.ClearTags(); SBezier *first = &(sbl->l.elem[0]); first->tag = 1; loop.l.Add(first); Vector start = first->Start(); Vector hanging = first->Finish(); int auxA = first->auxA; sbl->l.RemoveTagged(); while(sbl->l.n > 0 && !hanging.Equals(start)) { int i; bool foundNext = false; for(i = 0; i < sbl->l.n; i++) { SBezier *test = &(sbl->l.elem[i]); if((test->Finish()).Equals(hanging) && test->auxA == auxA) { test->Reverse(); // and let the next test catch it } if((test->Start()).Equals(hanging) && test->auxA == auxA) { test->tag = 1; loop.l.Add(test); hanging = test->Finish(); sbl->l.RemoveTagged(); foundNext = true; break; } } if(!foundNext) { // The loop completed without finding the hanging edge, so // it's an open loop errorAt->a = hanging; errorAt->b = start; *allClosed = false; return loop; } } if(hanging.Equals(start)) { *allClosed = true; } else { // We ran out of edges without forming a closed loop. errorAt->a = hanging; errorAt->b = start; *allClosed = false; } return loop; }
void SShell::MakeFromExtrusionOf(SBezierLoopSet *sbls, Vector t0, Vector t1, RgbaColor color) { // Make the extrusion direction consistent with respect to the normal // of the sketch we're extruding. if((t0.Minus(t1)).Dot(sbls->normal) < 0) { swap(t0, t1); } // Define a coordinate system to contain the original sketch, and get // a bounding box in that csys Vector n = sbls->normal.ScaledBy(-1); Vector u = n.Normal(0), v = n.Normal(1); Vector orig = sbls->point; double umax = 1e-10, umin = 1e10; sbls->GetBoundingProjd(u, orig, &umin, &umax); double vmax = 1e-10, vmin = 1e10; sbls->GetBoundingProjd(v, orig, &vmin, &vmax); // and now fix things up so that all u and v lie between 0 and 1 orig = orig.Plus(u.ScaledBy(umin)); orig = orig.Plus(v.ScaledBy(vmin)); u = u.ScaledBy(umax - umin); v = v.ScaledBy(vmax - vmin); // So we can now generate the top and bottom surfaces of the extrusion, // planes within a translated (and maybe mirrored) version of that csys. SSurface s0, s1; s0 = SSurface::FromPlane(orig.Plus(t0), u, v); s0.color = color; s1 = SSurface::FromPlane(orig.Plus(t1).Plus(u), u.ScaledBy(-1), v); s1.color = color; hSSurface hs0 = surface.AddAndAssignId(&s0), hs1 = surface.AddAndAssignId(&s1); // Now go through the input curves. For each one, generate its surface // of extrusion, its two translated trim curves, and one trim line. We // go through by loops so that we can assign the lines correctly. SBezierLoop *sbl; for(sbl = sbls->l.First(); sbl; sbl = sbls->l.NextAfter(sbl)) { SBezier *sb; List<TrimLine> trimLines = {}; for(sb = sbl->l.First(); sb; sb = sbl->l.NextAfter(sb)) { // Generate the surface of extrusion of this curve, and add // it to the list SSurface ss = SSurface::FromExtrusionOf(sb, t0, t1); ss.color = color; hSSurface hsext = surface.AddAndAssignId(&ss); // Translate the curve by t0 and t1 to produce two trim curves SCurve sc = {}; sc.isExact = true; sc.exact = sb->TransformedBy(t0, Quaternion::IDENTITY, 1.0); (sc.exact).MakePwlInto(&(sc.pts)); sc.surfA = hs0; sc.surfB = hsext; hSCurve hc0 = curve.AddAndAssignId(&sc); sc = {}; sc.isExact = true; sc.exact = sb->TransformedBy(t1, Quaternion::IDENTITY, 1.0); (sc.exact).MakePwlInto(&(sc.pts)); sc.surfA = hs1; sc.surfB = hsext; hSCurve hc1 = curve.AddAndAssignId(&sc); STrimBy stb0, stb1; // The translated curves trim the flat top and bottom surfaces. stb0 = STrimBy::EntireCurve(this, hc0, false); stb1 = STrimBy::EntireCurve(this, hc1, true); (surface.FindById(hs0))->trim.Add(&stb0); (surface.FindById(hs1))->trim.Add(&stb1); // The translated curves also trim the surface of extrusion. stb0 = STrimBy::EntireCurve(this, hc0, true); stb1 = STrimBy::EntireCurve(this, hc1, false); (surface.FindById(hsext))->trim.Add(&stb0); (surface.FindById(hsext))->trim.Add(&stb1); // And form the trim line Vector pt = sb->Finish(); sc = {}; sc.isExact = true; sc.exact = SBezier::From(pt.Plus(t0), pt.Plus(t1)); (sc.exact).MakePwlInto(&(sc.pts)); hSCurve hl = curve.AddAndAssignId(&sc); // save this for later TrimLine tl; tl.hc = hl; tl.hs = hsext; trimLines.Add(&tl); } int i; for(i = 0; i < trimLines.n; i++) { TrimLine *tl = &(trimLines.elem[i]); SSurface *ss = surface.FindById(tl->hs); TrimLine *tlp = &(trimLines.elem[WRAP(i-1, trimLines.n)]); STrimBy stb; stb = STrimBy::EntireCurve(this, tl->hc, true); ss->trim.Add(&stb); stb = STrimBy::EntireCurve(this, tlp->hc, false); ss->trim.Add(&stb); (curve.FindById(tl->hc))->surfA = ss->h; (curve.FindById(tlp->hc))->surfB = ss->h; } trimLines.Clear(); } }