protected static List <TPVertexFlags> CreateToolpathVertexFlags <TSegment>(FillCurve <TSegment> curve) where TSegment : IFillSegment, new() { var flags = new List <TPVertexFlags>(curve.Elements.Count + 1); for (int i = 0; i < curve.Elements.Count + 1; i++) { var flag = TPVertexFlags.None; if (i == 0) { flag = TPVertexFlags.IsPathStart; } else { var segInfo = curve.Elements[i - 1].Edge; if (segInfo.IsConnector) { flag = TPVertexFlags.IsConnector; } } flags.Add(flag); } return(flags); }
protected FillCurveSet2d ComputeFillPaths(GeneralPolygon2d poly, SegmentSet2d polyCache) { var stepSpans = ComputeSegments(poly, polyCache); // [TODO] need a pathfinder here, that can chain segments efficiently // (for now just do dumb things?) FillCurveSet2d paths = new FillCurveSet2d(); foreach (var seglist in stepSpans) { foreach (Segment2d seg in seglist) { // Discard paths that are too short if (seg.Length < MinPathLengthMM) { continue; } var fill_seg = new FillCurve <FillSegment>() { FillType = FillType, }; fill_seg.BeginCurve(seg.P0); fill_seg.AddToCurve(seg.P1, new FillSegment()); paths.Append(fill_seg); } } return(paths); }
protected void BuildCurveConcrete <TSegment>(FillCurve <TSegment> curve, double useSpeed) where TSegment : IFillSegment, new() { var vertices = curve.Vertices().ToList(); var flags = CreateToolpathVertexFlags(curve); var dimensions = GetFillDimensions(curve); Builder.AppendExtrude(vertices, useSpeed, dimensions, curve.FillType, curve.IsHoleShell, flags); }
protected virtual void BuildCurve(FillCurve curve, double useSpeed) { if (!(curve is FillCurve <FillSegment> o)) { throw new NotImplementedException($"FillPathScheduler2d.BuildCurve does not support type {curve.GetType()}."); } BuildCurveConcrete(o, useSpeed); }
protected static FillCurve OrientCurve(FillCurve curve, Vector2d currentPos2) { if (curve.Entry.DistanceSquared(currentPos2) > curve.Exit.DistanceSquared(currentPos2)) { return(curve.Reversed()); } return(curve); }
protected void AssertValidCurve(FillCurve curve) { int N = curve.ElementCount; if (N < 1) { StackFrame frame = new StackFrame(1); var method = frame.GetMethod(); var type = method.DeclaringType; var name = method.Name; throw new ArgumentException($"{type}.{name}: degenerate curve; must have at least 1 edge."); } }
// [TODO] would it ever make sense to break polyline to avoid huge travel?? public virtual void AppendFillCurve(FillCurve curve) { Vector3d currentPos = Builder.Position; Vector2d currentPos2 = currentPos.xy; AssertValidCurve(curve); var oriented = OrientCurve(curve, currentPos2); AppendTravel(currentPos2, oriented.Entry); BuildCurve(oriented, SelectSpeed(oriented)); }
// (approximately) clip insetPoly to band around clipPoly. // vertices are discarded if outside clipPoly, or within clip_dist // remaining polylines are returned // In all-pass case currently returns polyline w/ explicit first==last vertices public List <FillBase> clip_to_band(Polygon2d insetpoly, GeneralPolygon2d clipPoly, double clip_dist) { double clipSqr = clip_dist * clip_dist; int N = insetpoly.VertexCount; Vector2d[] midline = new Vector2d[N]; bool[] clipped = new bool[N]; int nClipped = 0; for (int i = 0; i < N; ++i) { Vector2d po = insetpoly[i]; if (clipPoly.Contains(po) == false) { clipped[i] = true; nClipped++; continue; } int iHole, iSeg; double segT; double distSqr = clipPoly.DistanceSquared(po, out iHole, out iSeg, out segT); if (distSqr < clipSqr) { clipped[i] = true; nClipped++; continue; } // not ideal... midline[i] = po; } if (nClipped == N) { return(new List <FillBase>()); } if (nClipped == 0) { var all = new FillCurve <FillSegment>(midline); return(new List <FillBase>() { all.CloseCurve() }); } return(find_polygon_spans(midline, clipped)); }
private FillCurve <FillSegment> SimplifyPath(FillCurve <FillSegment> path) { var simp = new PolySimplification2(new PolyLine2d(path.Vertices())); switch (SimplifyAmount) { default: case SimplificationLevel.Minor: simp.SimplifyDeviationThreshold = ToolWidth / 4; break; case SimplificationLevel.Moderate: simp.SimplifyDeviationThreshold = ToolWidth / 2; break; case SimplificationLevel.Aggressive: simp.SimplifyDeviationThreshold = ToolWidth; break; } simp.Simplify(); path = new FillCurve <FillSegment>(simp.Result.ToArray()) { FillType = this.FillType }; return(path); }
private FillCurveSet2d WalkPathGraph(DGraph2 pathGraph) { var boundaries = IdentifyBoundaryHashSet(pathGraph); var paths = new FillCurveSet2d(); // walk paths from boundary vertices while (boundaries.Count > 0) { int start_vid = boundaries.First(); boundaries.Remove(start_vid); int vid = start_vid; int eid = pathGraph.GetVtxEdges(vid)[0]; var path = new FillCurve <FillSegment>() { FillType = this.FillType }; path.BeginCurve(pathGraph.GetVertex(vid)); while (true) { Index2i next = DGraph2Util.NextEdgeAndVtx(eid, vid, pathGraph); eid = next.a; vid = next.b; int gid = pathGraph.GetEdgeGroup(eid); if (gid < 0) { path.AddToCurve(pathGraph.GetVertex(vid), new FillSegment(true)); } else { path.AddToCurve(pathGraph.GetVertex(vid)); } if (boundaries.Contains(vid)) { boundaries.Remove(vid); break; } } // discard paths that are too short if (path.TotalLength() < MinPathLengthMM) { continue; } // run polyline simplification to get rid of unneccesary detail in connectors // [TODO] we could do this at graph level...) // [TODO] maybe should be checking for collisions? we could end up creating // non-trivial overlaps here... if (SimplifyAmount != SimplificationLevel.None && path.Elements.Count > 1) { path = SimplifyPath(path); } paths.Append(path); } return(paths); }
public void Append(FillCurve curve) { Curves.Add(curve); }
public abstract void Extend(FillCurve other, double vertexComparisonTolerance = 1e-6);