void Group::AssembleLoops(bool *allClosed, bool *allCoplanar, bool *allNonZeroLen) { SBezierList sbl = {}; int i; for(i = 0; i < SK.entity.n; i++) { Entity *e = &(SK.entity.elem[i]); if(e->group.v != h.v) continue; if(e->construction) continue; if(e->forceHidden) continue; e->GenerateBezierCurves(&sbl); } SBezier *sb; *allNonZeroLen = true; for(sb = sbl.l.First(); sb; sb = sbl.l.NextAfter(sb)) { for(i = 1; i <= sb->deg; i++) { if(!(sb->ctrl[i]).Equals(sb->ctrl[0])) { break; } } if(i > sb->deg) { // This is a zero-length edge. *allNonZeroLen = false; polyError.errorPointAt = sb->ctrl[0]; goto done; } } // Try to assemble all these Beziers into loops. The closed loops go into // bezierLoops, with the outer loops grouped with their holes. The // leftovers, if any, go in bezierOpens. bezierLoops.FindOuterFacesFrom(&sbl, &polyLoops, NULL, SS.ChordTolMm(), allClosed, &(polyError.notClosedAt), allCoplanar, &(polyError.errorPointAt), &bezierOpens); done: sbl.Clear(); }
void GraphicsWindow::SplitLinesOrCurves(void) { if(!LockedInWorkplane()) { Error("Must be sketching in workplane to split."); return; } GroupSelection(); if(!(gs.n == 2 &&(gs.lineSegments + gs.circlesOrArcs + gs.cubics + gs.periodicCubics) == 2)) { Error("Select two entities that intersect each other (e.g. two lines " "or two circles or a circle and a line)."); return; } hEntity ha = gs.entity[0], hb = gs.entity[1]; Entity *ea = SK.GetEntity(ha), *eb = SK.GetEntity(hb); // Compute the possibly-rational Bezier curves for each of these entities SBezierList sbla, sblb; ZERO(&sbla); ZERO(&sblb); ea->GenerateBezierCurves(&sbla); eb->GenerateBezierCurves(&sblb); // and then compute the points where they intersect, based on those curves. SPointList inters; ZERO(&inters); sbla.AllIntersectionsWith(&sblb, &inters); if(inters.l.n > 0) { Vector pi; // If there's multiple points, then take the one closest to the // mouse pointer. double dmin = VERY_POSITIVE; SPoint *sp; for(sp = inters.l.First(); sp; sp = inters.l.NextAfter(sp)) { double d = ProjectPoint(sp->p).DistanceTo(currentMousePosition); if(d < dmin) { dmin = d; pi = sp->p; } } SS.UndoRemember(); hEntity hia = SplitEntity(ha, pi), hib = SplitEntity(hb, pi); // SplitEntity adds the coincident constraints to join the split halves // of each original entity; and then we add the constraint to join // the two entities together at the split point. if(hia.v && hib.v) { Constraint::ConstrainCoincident(hia, hib); } } else { Error("Can't split; no intersection found."); } // All done, clean up and regenerate. inters.Clear(); sbla.Clear(); sblb.Clear(); ClearSelection(); SS.later.generateAll = true; }
void SolveSpace::ExportViewOrWireframeTo(char *filename, bool wireframe) { int i; SEdgeList edges; ZERO(&edges); SBezierList beziers; ZERO(&beziers); SMesh *sm = NULL; if(SS.GW.showShaded) { Group *g = SK.GetGroup(SS.GW.activeGroup); g->GenerateDisplayItems(); sm = &(g->displayMesh); } if(sm && sm->IsEmpty()) { sm = NULL; } for(i = 0; i < SK.entity.n; i++) { Entity *e = &(SK.entity.elem[i]); if(!e->IsVisible()) continue; if(e->construction) continue; if(SS.exportPwlCurves || (sm && !SS.GW.showHdnLines) || fabs(SS.exportOffset) > LENGTH_EPS) { // We will be doing hidden line removal, which we can't do on // exact curves; so we need things broken down to pwls. Same // problem with cutter radius compensation. e->GenerateEdges(&edges); } else { e->GenerateBezierCurves(&beziers); } } if(SS.GW.showEdges) { Group *g = SK.GetGroup(SS.GW.activeGroup); g->GenerateDisplayItems(); SEdgeList *selr = &(g->displayEdges); SEdge *se; for(se = selr->l.First(); se; se = selr->l.NextAfter(se)) { edges.AddEdge(se->a, se->b, Style::SOLID_EDGE); } } if(SS.GW.showConstraints) { Constraint *c; for(c = SK.constraint.First(); c; c = SK.constraint.NextAfter(c)) { c->GetEdges(&edges); } } if(wireframe) { VectorFileWriter *out = VectorFileWriter::ForFile(filename); if(out) { ExportWireframeCurves(&edges, &beziers, out); } } else { Vector u = SS.GW.projRight, v = SS.GW.projUp, n = u.Cross(v), origin = SS.GW.offset.ScaledBy(-1); VectorFileWriter *out = VectorFileWriter::ForFile(filename); if(out) { ExportLinesAndMesh(&edges, &beziers, sm, u, v, n, origin, SS.CameraTangent()*SS.GW.scale, out); } if(out && !out->HasCanvasSize()) { // These file formats don't have a canvas size, so they just // get exported in the raw coordinate system. So indicate what // that was on-screen. SS.justExportedInfo.draw = true; SS.justExportedInfo.pt = origin; SS.justExportedInfo.u = u; SS.justExportedInfo.v = v; InvalidateGraphics(); } } edges.Clear(); beziers.Clear(); }