From 72a2574ae34750d77f124bb7fa2e707622759ddd Mon Sep 17 00:00:00 2001 From: Greg Meess Date: Mon, 19 Aug 2019 15:58:15 -0700 Subject: [PATCH] Refactor to allow custom FillElement data types --- .../curve/PolySimplification2.cs | 18 +- gsCore/gsSlicer/tests/CalculateExtrusion.cs | 8 - .../toolpathing/FillPathScheduler2d.cs | 43 +- .../toolpathing/ParallelLinesFillPolygon.cs | 14 +- .../toolpathing/SortingScheduler2d.cs | 4 +- gsCore/gsSlicer/toolpaths/FillCurveSet2d.cs | 91 +---- gsCore/gsSlicer/toolpaths/FillElements2d.cs | 371 ++++++++++-------- .../gsSlicer/toolpaths/ToolpathSetBuilder.cs | 2 +- 8 files changed, 254 insertions(+), 297 deletions(-) diff --git a/gsCore/geometry3Sharp/curve/PolySimplification2.cs b/gsCore/geometry3Sharp/curve/PolySimplification2.cs index acce4bd..f1ac03c 100644 --- a/gsCore/geometry3Sharp/curve/PolySimplification2.cs +++ b/gsCore/geometry3Sharp/curve/PolySimplification2.cs @@ -51,32 +51,24 @@ public class PolySimplification2 public List Result; - public PolySimplification2(Polygon2d polygon) + public PolySimplification2(IEnumerable vertices, bool loop) { - Vertices = new List(polygon.Vertices); - IsLoop = true; + Vertices = new List(vertices); + IsLoop = loop; } - public PolySimplification2(PolyLine2d polycurve) - { - Vertices = new List(polycurve.Vertices); - IsLoop = false; - } - - - /// /// simplify outer and holes of a polygon solid with same thresholds /// public static void Simplify(GeneralPolygon2d solid, double deviationThresh) { - PolySimplification2 simp = new PolySimplification2(solid.Outer); + PolySimplification2 simp = new PolySimplification2(solid.Outer.Vertices, true); simp.SimplifyDeviationThreshold = deviationThresh; simp.Simplify(); solid.Outer.SetVertices(simp.Result, true); foreach (var hole in solid.Holes) { - PolySimplification2 holesimp = new PolySimplification2(hole); + PolySimplification2 holesimp = new PolySimplification2(hole.Vertices, true); holesimp.SimplifyDeviationThreshold = deviationThresh; holesimp.Simplify(); hole.SetVertices(holesimp.Result, true); diff --git a/gsCore/gsSlicer/tests/CalculateExtrusion.cs b/gsCore/gsSlicer/tests/CalculateExtrusion.cs index 98a339a..7e993cd 100644 --- a/gsCore/gsSlicer/tests/CalculateExtrusion.cs +++ b/gsCore/gsSlicer/tests/CalculateExtrusion.cs @@ -170,13 +170,5 @@ public void Calculate(Vector3d vStartPos, double fStartA, bool alreadyInRetract ExtrusionLength = curA; } // Calculate() - - - bool is_connection(Index3i flags) { - return (flags.a & (int)TPVertexFlags.IsConnector) != 0; - } - - - } } diff --git a/gsCore/gsSlicer/toolpathing/FillPathScheduler2d.cs b/gsCore/gsSlicer/toolpathing/FillPathScheduler2d.cs index 2729169..c14b1b2 100644 --- a/gsCore/gsSlicer/toolpathing/FillPathScheduler2d.cs +++ b/gsCore/gsSlicer/toolpathing/FillPathScheduler2d.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using g3; namespace gs @@ -84,7 +85,7 @@ public virtual void AppendPolygon2d(FillPolygon2d poly) loopV.Add(poly[k]); } - double useSpeed = select_speed(poly); + double useSpeed = select_speed(poly.TypeFlags); Builder.AppendExtrude(loopV, useSpeed, poly.TypeFlags, null); } @@ -137,22 +138,20 @@ public virtual void AppendPolyline2d(FillPolyline2d curve) List loopV; List flags = null; - if (bReverse) { - loopV = new List(N); - for (int i = N - 1; i >= 0; --i) - loopV.Add(curve[i]); - if (curve.HasFlags) { - flags = new List(N); - for (int i = N - 1; i >= 0; --i) - flags.Add(curve.GetFlag(i)); - } - } else { - loopV = new List(curve); - if (curve.HasFlags) - flags = new List(curve.Flags()); - } - double useSpeed = select_speed(curve); + loopV = new List(N); + flags = new List(N); + + var range = Enumerable.Range(0, N); + if (bReverse) range.Reverse(); + + foreach (int i in range) + { + var point = curve.GetPoint(i, bReverse); + loopV.Add(point.Vertex); + flags.Add(point.SegmentInfo != null && point.SegmentInfo.IsConnector ? TPVertexFlags.IsConnector : TPVertexFlags.None ); + } + double useSpeed = select_speed(curve.TypeFlags); Vector2d dimensions = GCodeUtil.UnspecifiedDimensions; if (curve.CustomThickness > 0) @@ -162,22 +161,26 @@ public virtual void AppendPolyline2d(FillPolyline2d curve) } + bool HasTypeFlag(FillTypeFlags typeFlags, FillTypeFlags f) + { + return (typeFlags & f) != 0; + } // 1) If we have "careful" speed hint set, use CarefulExtrudeSpeed // (currently this is only set on first layer) // 2) if this is an outer perimeter, scale by outer perimeter speed multiplier // 3) if we are being "careful" and this is support, also use that multiplier // (bit of a hack, currently means on first layer we do support extra slow) - double select_speed(FillCurve2d pathCurve) + double select_speed(FillTypeFlags flags) { - bool bIsSupport = pathCurve.HasTypeFlag(FillTypeFlags.SupportMaterial); - bool bIsOuterPerimeter = pathCurve.HasTypeFlag(FillTypeFlags.OuterPerimeter); + bool bIsSupport = HasTypeFlag(flags, FillTypeFlags.SupportMaterial); + bool bIsOuterPerimeter = HasTypeFlag(flags, FillTypeFlags.OuterPerimeter); bool bCareful = (SpeedHint == SchedulerSpeedHint.Careful); double useSpeed = bCareful ? Settings.CarefulExtrudeSpeed : Settings.RapidExtrudeSpeed; if (bIsOuterPerimeter || (bCareful && bIsSupport)) useSpeed *= Settings.OuterPerimeterSpeedX; - bool bIsBridgeSupport = pathCurve.HasTypeFlag(FillTypeFlags.BridgeSupport); + bool bIsBridgeSupport = HasTypeFlag(flags, FillTypeFlags.BridgeSupport); if (bIsBridgeSupport) useSpeed = Settings.CarefulExtrudeSpeed * Settings.BridgeExtrudeSpeedX; diff --git a/gsCore/gsSlicer/toolpathing/ParallelLinesFillPolygon.cs b/gsCore/gsSlicer/toolpathing/ParallelLinesFillPolygon.cs index fa06887..b5924d6 100644 --- a/gsCore/gsSlicer/toolpathing/ParallelLinesFillPolygon.cs +++ b/gsCore/gsSlicer/toolpathing/ParallelLinesFillPolygon.cs @@ -145,9 +145,12 @@ protected FillCurveSet2d ComputeFillPaths(GeneralPolygon2d poly) eid = next.a; vid = next.b; int gid = pathGraph.GetEdgeGroup(eid); - if (gid < 0) { - path.AppendVertex(pathGraph.GetVertex(vid), TPVertexFlags.IsConnector); - } else { + if (gid < 0) + { + path.AppendVertex(pathGraph.GetVertex(vid), new FillSegmentInfo() { IsConnector = true }); + } + else + { path.AppendVertex(pathGraph.GetVertex(vid)); } @@ -161,13 +164,12 @@ protected FillCurveSet2d ComputeFillPaths(GeneralPolygon2d poly) if (path.ArcLength < 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 checkign for collisions? we could end up creating + // [TODO] maybe should be checking for collisions? we could end up creating // non-trivial overlaps here... if ( SimplifyAmount != SimplificationLevel.None && path.VertexCount > 2 ) { - PolySimplification2 simp = new PolySimplification2(path); + PolySimplification2 simp = new PolySimplification2(path.Vertices, false); switch (SimplifyAmount) { default: case SimplificationLevel.Minor: diff --git a/gsCore/gsSlicer/toolpathing/SortingScheduler2d.cs b/gsCore/gsSlicer/toolpathing/SortingScheduler2d.cs index ad26fa0..a2e0ef1 100644 --- a/gsCore/gsSlicer/toolpathing/SortingScheduler2d.cs +++ b/gsCore/gsSlicer/toolpathing/SortingScheduler2d.cs @@ -91,10 +91,10 @@ public void SortAndAppendTo(Vector2d startPoint, IFillPathScheduler2d scheduler) } o.TypeFlags = loop.curve.TypeFlags; paths.Append(o); - OutPoint = o.Vertices[0]; + OutPoint = o[0]; } else { paths.Append(loop.curve); - OutPoint = loop.curve.Vertices[0]; + OutPoint = loop.curve[0]; } } else { // span diff --git a/gsCore/gsSlicer/toolpaths/FillCurveSet2d.cs b/gsCore/gsSlicer/toolpaths/FillCurveSet2d.cs index ab0b04a..dfdac01 100644 --- a/gsCore/gsSlicer/toolpaths/FillCurveSet2d.cs +++ b/gsCore/gsSlicer/toolpaths/FillCurveSet2d.cs @@ -12,18 +12,17 @@ namespace gs /// public class FillCurveSet2d { - public List Loops = new List(); - public List Curves = new List(); + public List Loops = new List(); + public List Curves = new List(); public FillCurveSet2d() { } - public void Append(GeneralPolygon2d poly, FillTypeFlags typeFlags) { - Loops.Add(new FillPolygon2d(poly.Outer) { TypeFlags = typeFlags }); + Loops.Add(new FillPolygon2d(poly.Outer.VerticesItr(false)) { TypeFlags = typeFlags }); foreach (var h in poly.Holes) - Loops.Add(new FillPolygon2d(h) { TypeFlags = typeFlags }); + Loops.Add(new FillPolygon2d(h.VerticesItr(false)) { TypeFlags = typeFlags }); } public void Append(List polys, FillTypeFlags typeFlags) { @@ -32,7 +31,7 @@ public void Append(List polys, FillTypeFlags typeFlags) { } public void Append(Polygon2d poly, FillTypeFlags typeFlags) { - Loops.Add(new FillPolygon2d(poly) { TypeFlags = typeFlags } ); + Loops.Add(new FillPolygon2d(poly.VerticesItr(false)) { TypeFlags = typeFlags } ); } public void Append(List polys, FillTypeFlags typeFlags) { @@ -40,21 +39,21 @@ public void Append(List polys, FillTypeFlags typeFlags) { Append(p, typeFlags); } - public void Append(FillPolygon2d loop) { + public void Append(IFillElementPolygon loop) { Loops.Add(loop); } - public void Append(List loops) { + public void Append(List loops) { foreach ( var l in loops ) Loops.Add(l); } - public void Append(FillPolyline2d curve) { + public void Append(IFillElementPolyline curve) { Curves.Add(curve); } - public void Append(List curves) { + public void Append(List curves) { foreach (var p in curves) Append(p); } @@ -86,77 +85,5 @@ public double TotalLength() len += curve.ArcLength; return len; } - - - // DEPRECATED - remove? - // this connects up the paths with small connectors? used in DenseLinesFillPolygon - public void OptimizeCurves(double max_dist, Func ValidateF) { - int[] which = new int[4]; - double[] dists = new double[4]; - for (int ci = 0; ci < Curves.Count; ++ci ) { - FillPolyline2d l0 = Curves[ci]; - - // find closest viable connection - int iClosest = -1; - int iClosestCase = -1; - for (int cj = ci + 1; cj < Curves.Count; ++cj) { - FillPolyline2d l1 = Curves[cj]; - dists[0] = l0.Start.Distance(l1.Start); which[0] = 0; - dists[1] = l0.Start.Distance(l1.End); which[1] = 1; - dists[2] = l0.End.Distance(l1.Start); which[2] = 2; - dists[3] = l0.End.Distance(l1.End); which[3] = 3; - Array.Sort(dists, which); - - for (int k = 0; k < 4 && iClosest != cj; ++k) { - if (dists[k] > max_dist) - continue; - Segment2d connector = get_case(l0, l1, which[k]); - if (ValidateF(connector) == false) - continue; - iClosest = cj; - iClosestCase = which[k]; - } - } - - if (iClosest == -1) - continue; - - // [TODO] it would be better to preserve start/direction of - // longest path, if possible. Maybe make that an option? - - // ok we will join ci w/ iClosest. May need reverse one - FillPolyline2d ljoin = Curves[iClosest]; - if (iClosestCase == 0) { - l0.Reverse(); - } else if (iClosestCase == 1) { - l0.Reverse(); - ljoin.Reverse(); - } else if (iClosestCase == 3) { - ljoin.Reverse(); - } - - // now we are in straight-append order - l0.AppendVertices(ljoin); - Curves.RemoveAt(iClosest); - - // force check again w/ this curve - ci--; - } - - } - - - static Segment2d get_case(FillPolyline2d l0, FillPolyline2d l1, int which) { - if (which == 0) - return new Segment2d(l0.Start, l1.Start); - else if (which == 1) - return new Segment2d(l0.Start, l1.End); - else if (which == 2) - return new Segment2d(l0.End, l1.Start); - else - return new Segment2d(l0.End, l1.End); - } - - } } diff --git a/gsCore/gsSlicer/toolpaths/FillElements2d.cs b/gsCore/gsSlicer/toolpaths/FillElements2d.cs index d681fd8..66d89af 100644 --- a/gsCore/gsSlicer/toolpaths/FillElements2d.cs +++ b/gsCore/gsSlicer/toolpaths/FillElements2d.cs @@ -24,193 +24,234 @@ public enum FillTypeFlags BridgeSupport = 1<<11 } + public class FillVertexInfo + { + } - - /// - /// things that are common to FillPolyline2d and FillPolygon2d - /// - public interface FillCurve2d + public class FillSegmentInfo : ICloneable { - bool HasTypeFlag(FillTypeFlags f); + public bool IsConnector; + public bool IsSupport; + + public object Clone() + { + return (FillSegmentInfo)this.MemberwiseClone(); + } - double CustomThickness { get; } + public void Reverse() + { + } } + public interface IFillElementPolygon + { + FillTypeFlags TypeFlags { get; set; } + double Perimeter { get; } + } + public interface IFillElementPolyline + { + FillTypeFlags TypeFlags { get; set; } + double ArcLength { get; } + } - /// - /// Additive polygon fill curve - /// - public class FillPolygon2d : Polygon2d, FillCurve2d + /// + /// Things that are common to FillPolylineGeneric and FillPolylineGeneric + /// + public abstract class FillElement + where TVertexInfo : FillVertexInfo, new() + where TSegmentInfo : FillSegmentInfo, new() { - public FillTypeFlags TypeFlags = FillTypeFlags.Unknown; + public class PointData + { + public Vector2d Vertex; + public TVertexInfo VertexInfo; + public TSegmentInfo SegmentInfo; + } + } - public bool HasTypeFlag(FillTypeFlags f) { - return (TypeFlags & f) != 0; - } + /// + /// Additive polygon fill curve + /// + public abstract class FillPolygonGeneric : + FillElement, IFillElementPolygon + where TVertexInfo : FillVertexInfo, new() + where TSegmentInfo : FillSegmentInfo, new() + { + protected Polygon2d Polygon = new Polygon2d(); + protected List VertexInfo = new List(); + protected List SegmentInfo = new List(); + + public bool HasTypeFlag(FillTypeFlags f) { return (TypeFlags & f) == f; } + public double CustomThickness { get; set; } + + // Expose some properties & methods from underlying Polygon + public int VertexCount { get => Polygon.VertexCount; } + public double Perimeter { get => Polygon.Perimeter; } + public Vector2d this[int i] { get => Polygon[i]; } + public IEnumerable Vertices { get => Polygon.VerticesItr(false); } + public FillTypeFlags TypeFlags { get; set; } = FillTypeFlags.Unknown; + + public Segment2d Segment(int i) { return Polygon.Segment(i); } + public double DistanceSquared(Vector2d pt, out int iNearSeg, out double fNearSegT) + { + return Polygon.DistanceSquared(pt, out iNearSeg, out fNearSegT); + } - public double CustomThickness { get; set; } + public void AppendVertex(Vector2d pt, TVertexInfo vInfo = null, TSegmentInfo sInfo = null) + { + Polygon.AppendVertex(pt); + VertexInfo.Add(vInfo); - public FillPolygon2d() : base() - { - CustomThickness = 0; - } + if (Polygon.VertexCount > 0) + SegmentInfo.Add(sInfo); + else if (sInfo != null) + throw new Exception("Cannot add SegmentInfo to the first vertex."); + } - public FillPolygon2d(Vector2d[] v) : base(v) - { - CustomThickness = 0; - } + public void AppendVertex(Vector2d pt, TSegmentInfo sInfo) + { + AppendVertex(pt, null, sInfo); + } - public FillPolygon2d(Polygon2d p) : base(p) - { - CustomThickness = 0; - } - } + public PointData GetPoint(int i, bool reverse) + { + if (reverse) + { + var segReversed = (TSegmentInfo)SegmentInfo[i].Clone(); + segReversed?.Reverse(); + return new PointData() + { + Vertex = Polygon[i], + VertexInfo = VertexInfo[i], + SegmentInfo = segReversed, + }; + } + else + { + return new PointData() + { + Vertex = Polygon[i], + VertexInfo = VertexInfo[i], + SegmentInfo = SegmentInfo[(i + Polygon.VertexCount - 1) % Polygon.VertexCount] + }; + } + } + } + + /// + /// Additive polyline fill curve + /// + public abstract class FillPolylineGeneric : + FillElement, IFillElementPolyline + where TVertexInfo : FillVertexInfo, new() + where TSegmentInfo : FillSegmentInfo, new() + { + public FillTypeFlags TypeFlags { get; set; } = FillTypeFlags.Unknown; + public bool HasTypeFlag(FillTypeFlags f) { return (TypeFlags & f) == f; } + public double CustomThickness { get; set; } + + // Expose some properties & methods from underlying Polyline + public int VertexCount { get => Polyline.VertexCount; } + public double ArcLength { get => Polyline.ArcLength; } + public Vector2d Start { get => Polyline.Vertices[0]; } + public Vector2d End { get => Polyline.Vertices[Polyline.VertexCount - 1]; } + public IEnumerable Vertices { get => Polyline.Vertices; } + public Segment2d Segment(int i) { return Polyline.Segment(i); } + public Vector2d this[int i] { get => Polyline[i]; } + + protected PolyLine2d Polyline = new PolyLine2d(); + protected List VertexInfo = new List(); + protected List SegmentInfo = new List(); + + public void AppendVertex(Vector2d pt, TVertexInfo vInfo = null, TSegmentInfo sInfo = null) + { + Polyline.AppendVertex(pt); + VertexInfo.Add(vInfo); + + if (Polyline.VertexCount > 0) + SegmentInfo.Add(sInfo); + else if (sInfo != null) + throw new Exception("Cannot add SegmentInfo to the first vertex."); + } + + public void AppendVertex(Vector2d pt, TSegmentInfo sInfo) + { + AppendVertex(pt, null, sInfo); + } + public PointData GetPoint(int i, bool reverse) + { + if (reverse) + { + + var segReversed = i >= SegmentInfo.Count - 1 ? null : (TSegmentInfo)SegmentInfo[i]?.Clone(); + segReversed?.Reverse(); + return new PointData() + { + Vertex = Polyline[i], + VertexInfo = VertexInfo[i], + SegmentInfo = segReversed, + }; + } + else + { + return new PointData() + { + Vertex = Polyline[i], + VertexInfo = VertexInfo[i], + SegmentInfo = i == 0 ? null : SegmentInfo[i - 1] + }; + } + } + public void Reverse() + { + // Reverse Lists + Polyline.Reverse(); + VertexInfo.Reverse(); + SegmentInfo.Reverse(); + // Reverse each segment in case segment data is directional + foreach (var seg in SegmentInfo) + seg?.Reverse(); + } + } - /// - /// Additive polyline fill curve - /// - public class FillPolyline2d : PolyLine2d, FillCurve2d + public class FillPolygon2d : FillPolygonGeneric { - public FillTypeFlags TypeFlags = FillTypeFlags.Unknown; - - public bool HasTypeFlag(FillTypeFlags f) { - return (TypeFlags & f) == f; - } - - // [TODO] maybe remove? see below. - List flags; - bool has_flags = false; - - - public double CustomThickness { get; set; } - - - public FillPolyline2d() : base() - { - CustomThickness = 0; - } - - public FillPolyline2d(Vector2d[] v) : base(v) - { - CustomThickness = 0; - } - - public FillPolyline2d(PolyLine2d p) : base(p) - { - CustomThickness = 0; - } - - void alloc_flags() - { - if (flags == null) { - flags = new List(); - for (int i = 0; i < vertices.Count; ++i) - flags.Add(TPVertexFlags.None); - } - } - - public override void AppendVertex(Vector2d v) - { - base.AppendVertex(v); - if (flags != null) - flags.Add(TPVertexFlags.None); - } - public override void AppendVertices(IEnumerable v) - { - base.AppendVertices(v); - if (flags != null) { - foreach (var x in v) - flags.Add(TPVertexFlags.None); - } - } - - public override void Reverse() - { - base.Reverse(); - if (flags != null) - flags.Reverse(); - } - public override void Simplify(double clusterTol = 0.0001, - double lineDeviationTol = 0.01, - bool bSimplifyStraightLines = true) - { - int n = vertices.Count; - - int i, k, pv; // misc counters - Vector2d[] vt = new Vector2d[n]; // vertex buffer - bool has_flags = HasFlags; - TPVertexFlags[] vf = (has_flags) ? new TPVertexFlags[n] : null; - bool[] mk = new bool[n]; - for (i = 0; i < n; ++i) // marker buffer - mk[i] = false; - - // STAGE 1. Vertex Reduction within tolerance of prior vertex cluster - double clusterTol2 = clusterTol * clusterTol; - vt[0] = vertices[0]; // start at the beginning - for (i = k = 1, pv = 0; i < n; i++) { - if ((vertices[i] - vertices[pv]).LengthSquared < clusterTol2) - continue; - if (has_flags) - vf[k] = flags[i]; - vt[k++] = vertices[i]; - pv = i; - } - if (pv < n - 1) - vt[k++] = vertices[n - 1]; // finish at the end - - // STAGE 2. Douglas-Peucker polyline simplification - if (lineDeviationTol > 0) { - mk[0] = mk[k - 1] = true; // mark the first and last vertices - simplifyDP(lineDeviationTol, vt, 0, k - 1, mk); - } else { - for (i = 0; i < k; ++i) - mk[i] = true; - } + public FillPolygon2d() + { } - // copy marked vertices back to this polygon - vertices = new List(); - flags = (has_flags) ? new List() : null; - for (i = 0; i < k; ++i) { - if (mk[i]) { - vertices.Add(vt[i]); - if (has_flags) - flags.Add(vf[i]); - } - } - Timestamp++; + public FillPolygon2d(IEnumerable vertices) + { + foreach (var v in vertices) + AppendVertex(v); + } + + } - return; + public class FillPolyline2d : FillPolylineGeneric + { + public FillPolyline2d() + { } + + public FillPolyline2d(IEnumerable vertices) + { + foreach (var v in vertices) + AppendVertex(v); } + public void Trim(double v) + { + Polyline.Trim(v); - public void AppendVertex(Vector2d v, TPVertexFlags flag) - { - alloc_flags(); - base.AppendVertex(v); - flags.Add(flag); - has_flags = true; - } - public void AppendVertices(IEnumerable v, IEnumerable f) - { - alloc_flags(); - base.AppendVertices(v); - flags.AddRange(f); - has_flags = true; - } - - - // [RMS] this is *only* used for PathUtil.ConnectorVFlags. Maybe remove this capability? - public TPVertexFlags GetFlag(int i) { return (flags == null) ? TPVertexFlags.None : flags[i]; } - public void SetFlag(int i, TPVertexFlags flag) { alloc_flags(); flags[i] = flag; } - - public bool HasFlags { - get { return flags != null && has_flags; } - } - public IReadOnlyList Flags() { return flags.AsReadOnly(); } - } + // Remove any vertex info that was trimmed away. + VertexInfo.RemoveRange(Polyline.VertexCount, VertexInfo.Count - Polyline.VertexCount); + + // Remove any segment info that was trimmed away. + VertexInfo.RemoveRange(Polyline.VertexCount - 1, SegmentInfo.Count - 1 - Polyline.VertexCount); + } + } } diff --git a/gsCore/gsSlicer/toolpaths/ToolpathSetBuilder.cs b/gsCore/gsSlicer/toolpaths/ToolpathSetBuilder.cs index 2c38f45..bd72e89 100644 --- a/gsCore/gsSlicer/toolpaths/ToolpathSetBuilder.cs +++ b/gsCore/gsSlicer/toolpaths/ToolpathSetBuilder.cs @@ -147,7 +147,7 @@ public virtual Vector3d AppendExtrude(List toPoints, extrusion.TypeModifiers = pathTypeFlags; extrusion.AppendVertex(new PrintVertex(currentPos, NO_RATE, useDims), TPVertexFlags.IsPathStart); - for (int k = 0; k < toPoints.Count; ++k) { + for (int k = 1; k < toPoints.Count; ++k) { Vector3d pos = new Vector3d(toPoints[k].x, toPoints[k].y, currentPos.z); TPVertexFlags flag = (k == toPoints.Count - 1) ? TPVertexFlags.IsPathEnd : TPVertexFlags.None; extrusion.AppendVertex(new PrintVertex(pos, fSpeed, useDims), flag);