public void Build(ToolpathSet toolpaths, Interval1d zrange, double cellSize = 2.0) { segments = new DVector <Segment2d>(); grid = new SegmentHashGrid2d <int>(cellSize, -1); Action <LinearToolpath3 <PrintVertex> > processPathF = (polyPath) => { if (polyPath.Type != ToolpathTypes.Deposition || polyPath.IsPlanar == false) { return; } if ((polyPath.TypeModifiers & FillTypeFlags.OutermostShell) == 0) { return; } Vector3d v0 = polyPath.Start.Position; Vector3d v1 = polyPath.End.Position; if (zrange.Contains(v0.z) == false || zrange.Contains(v1.z) == false) { return; } append_path(polyPath, cellSize); }; process_linear_paths(toolpaths, processPathF); }
// utility stuff that could go somewhere else... static void ProcessLinearPaths(ToolpathSet pathSetIn, Action <LinearToolpath3 <PrintVertex> > processF) { Action <IToolpath> drawPath = (path) => { if (path is LinearToolpath3 <PrintVertex> ) { processF(path as LinearToolpath3 <PrintVertex>); } // else we might have other path type... }; Action <IToolpathSet> drawPaths = null; drawPaths = (pathList) => { foreach (IToolpath path in pathList) { if (path is IToolpathSet) { drawPaths(path as IToolpathSet); } else { drawPath(path); } } }; drawPaths(pathSetIn); }
private void BuildToolPaths(GenerationTask generationTask, PrintSettings settings) { lock (active_compute_lock) { DebugUtil.Log("[ToolpathGenerator] Spawning Compute!!"); generationTask.Compute(settings); if (generationTask.Success) { CurrentGCode = generationTask.gcode; Toolpaths = generationTask.paths; LayerInfo = generationTask.layerInfo; Settings = generationTask.PrintSettings; Slices = generationTask.SliceSet; ToolpathsValid = true; ToolpathsFailed = false; //CC.Objects.SetToolpaths(this); } else { CurrentGCode = null; Toolpaths = null; LayerInfo = null; Settings = null; Slices = null; ToolpathsValid = false; ToolpathsFailed = true; } } }
public List <PolyLine2d> GetPolylinesForLayer(int layer) { ToolpathSet pathSetIn = Paths; SKColor extrudeColor = SkiaUtil.Color(0, 0, 0, 255); Interval1d layer_zrange = Layers.GetLayerZInterval(layer); List <PolyLine2d> polylines = new List <PolyLine2d>(); Action <LinearToolpath3 <PrintVertex> > drawPath3F = (polyPath) => { Vector3d v0 = polyPath.Start.Position; if (layer_zrange.Contains(v0.z) == false) { return; } if (polyPath.Type != ToolpathTypes.Deposition) { return; } PolyLine2d pline = new PolyLine2d(); for (int i = 0; i < polyPath.VertexCount; ++i) { pline.AppendVertex(polyPath[i].Position.xy); } polylines.Add(pline); }; ProcessLinearPaths(pathSetIn, drawPath3F); return(polylines); }
public void SetPaths(ToolpathSet paths, SingleMaterialFFFSettings knownSettings = null) { Paths = paths; double layer_height = (knownSettings != null) ? knownSettings.LayerHeightMM : 0; Layers = new LayersDetector(Paths, layer_height); CurrentLayer = 0; }
private void DrawFill(ToolpathSet pathSetIn, SKCanvas baseCanvas) { SKColor fillColor = SkiaUtil.Color(255, 0, 255, 255); SKRect bounds = baseCanvas.LocalClipBounds; SKBitmap blitBitmap = new SKBitmap(PixelDimensions.x, PixelDimensions.y, SkiaUtil.ColorType(), SKAlphaType.Premul); IntPtr len; using (var skSurface = SKSurface.Create(blitBitmap.Info.Width, blitBitmap.Info.Height, SkiaUtil.ColorType(), SKAlphaType.Premul, blitBitmap.GetPixels(out len), blitBitmap.Info.RowBytes)) { var canvas = skSurface.Canvas; canvas.Clear(SkiaUtil.Color(255, 255, 255, 255)); using (var paint = new SKPaint()) { paint.IsAntialias = true; paint.StrokeWidth = dimensionScale * PathDiameterMM; paint.Style = SKPaintStyle.Stroke; paint.StrokeCap = SKStrokeCap.Round; paint.StrokeJoin = SKStrokeJoin.Round; paint.Color = fillColor; Action <LinearToolpath3 <PrintVertex> > drawPath3F = (polyPath) => { if (polyPath.Type != ToolpathTypes.Deposition) { return; } Vector3d v0 = polyPath.Start.Position; byte layer_alpha = LayerFilterF(v0); if (layer_alpha != 255) { return; } SKPath path = MakePath(polyPath, SceneToSkiaF); canvas.DrawPath(path, paint); }; ProcessLinearPaths(pathSetIn, drawPath3F); } } SKPaint blitPaint = new SKPaint(); blitPaint.IsAntialias = false; blitPaint.BlendMode = SKBlendMode.SrcOver; blitPaint.Color = SkiaUtil.Color(0, 0, 0, 64); baseCanvas.DrawBitmap(blitBitmap, 0, 0, blitPaint); blitPaint.Dispose(); blitBitmap.Dispose(); }
/// <summary> /// Point of this function is to be same as DrawFill (ie draw 'tubes') but to draw /// in such a way that overlap regions are highlighted. However it does not work yet, /// need to draw continuous SKPaths as much as possible but break at direction changes. /// </summary> private void DrawFillOverlaps(ToolpathSet pathSetIn, SKCanvas baseCanvas) { SKColor fillColor = SkiaUtil.Color(255, 0, 255, 64); using (var paint = new SKPaint()) { paint.IsAntialias = true; paint.StrokeWidth = dimensionScale * PathDiameterMM; paint.Style = SKPaintStyle.Stroke; paint.StrokeCap = SKStrokeCap.Round; paint.StrokeJoin = SKStrokeJoin.Round; paint.Color = fillColor; Action <LinearToolpath3 <PrintVertex> > drawPath3F = (polyPath) => { if (polyPath.Type != ToolpathTypes.Deposition) { return; } Vector3d v0 = polyPath.Start.Position; byte layer_alpha = LayerFilterF(v0); if (layer_alpha != 255) { return; } // draw each segment separately. results in lots of duplicate-circles, no good //for (int i = 1; i < polyPath.VertexCount; i++) { // SKPoint a = SceneToSkiaF(polyPath[i - 1].Position.xy); // SKPoint b = SceneToSkiaF(polyPath[i].Position.xy); // baseCanvas.DrawLine(a.X, a.Y, b.X, b.Y, paint); //} // draw full path in one shot. Only shows overlaps between separate paths. //SKPath path = MakePath(polyPath, SceneToSkiaF); //baseCanvas.DrawPath(path, paint); // draw w/ angle threshold List <SKPath> paths = MakePathSegments(polyPath, SceneToSkiaF, 45); foreach (var path in paths) { baseCanvas.DrawPath(path, paint); } }; ProcessLinearPaths(pathSetIn, drawPath3F); } }
/// <summary> /// Point of this function is to be same as DrawFill (ie draw 'tubes') but to draw /// in such a way that overlap regions are highlighted. However it does not work yet, /// need to draw continuous SKPaths as much as possible but break at direction changes. /// </summary> private void DrawFillOverlapsIntegrate(ToolpathSet pathSetIn, SKCanvas baseCanvas) { SKColor fillColor = SkiaUtil.Color(255, 0, 255, 5); float path_diam = dimensionScale * PathDiameterMM; float spot_r = path_diam * 0.5f; float spacing = 1.0f / dimensionScale; using (var paint = new SKPaint()) { paint.IsAntialias = true; paint.StrokeWidth = 1.0f; paint.Style = SKPaintStyle.Fill; paint.Color = fillColor; Action <LinearToolpath3 <PrintVertex> > drawPath3F = (polyPath) => { if (polyPath.Type != ToolpathTypes.Deposition) { return; } Vector3d v0 = polyPath.Start.Position; byte layer_alpha = LayerFilterF(v0); if (layer_alpha != 255) { return; } // draw each segment separately. results in lots of duplicate-circles, no good for (int i = 1; i < polyPath.VertexCount; i++) { Vector2d a = polyPath[i - 1].Position.xy; Vector2d b = polyPath[i].Position.xy; double len = a.Distance(b); int n = (int)(len / spacing) + 1; int stop = (i == polyPath.VertexCount - 1) ? n : n - 1; for (int k = 0; k <= stop; ++k) { double t = (double)k / (double)n; Vector2d p = Vector2d.Lerp(a, b, t); SKPoint pk = SceneToSkiaF(p); baseCanvas.DrawCircle(pk.X, pk.Y, spot_r, paint); } } }; ProcessLinearPaths(pathSetIn, drawPath3F); } }
public virtual ToolpathSO Create(ToolpathSet toolpaths, SingleMaterialFFFSettings settings, SOMaterial setMaterial) { AssignSOMaterial(setMaterial); // need to do this to setup BaseSO material stack parentGO = GameObjectFactory.CreateParentGO(UniqueNames.GetNext("Toolpath")); Toolpaths = toolpaths; Settings = settings; polylines_valid = false; PolylinePool = new fGameObjectPool <fPolylineGameObject>(allocate_polyline_go); PolylinePool.FreeF = (go) => { //go.SetVertices(EmptyToolpathCurve, false, true); }; return(this); }
public void InvalidateToolpaths() { cancel_active_compute(); CurrentGCode = null; Toolpaths = null; LayerInfo = null; Settings = null; Slices = null; ToolpathsValid = false; ToolpathsFailed = false; // [TODO] do via event? CC.Objects.DiscardToolpaths(); ToolpathsInvalidatedEvent?.Invoke(); }
private void DrawPathLabels(ToolpathSet pathSetIn, SKCanvas canvas, SKPaint paint) { int counter = 1; paint.Style = SKPaintStyle.StrokeAndFill; paint.IsAntialias = true; paint.Color = SKColors.Black; paint.StrokeWidth = 1; paint.TextSize = 15.0f; Action <LinearToolpath3 <PrintVertex> > drawLabelF = (polyPath) => { Vector3d v0 = polyPath.Start.Position; byte layer_alpha = LayerFilterF(v0); if (layer_alpha < 255) { return; } if (polyPath.Type != ToolpathTypes.Cut) { return; } string label = string.Format("{0}", counter++); paint.Color = SKColors.Black; Vector3d vPos = v0; float shiftX = 0, shiftY = 0; if (polyPath.Type == ToolpathTypes.Travel) { vPos = (polyPath.Start.Position + polyPath.End.Position) * 0.5; } else if (polyPath.Type == ToolpathTypes.PlaneChange) { shiftY = paint.TextSize * 0.5f; //shiftX = -paint.TextSize * 0.5f; paint.Color = SKColors.DarkRed; } SKPoint pos = SceneToSkiaF(vPos.xy); canvas.DrawText(label, pos.X + shiftX, pos.Y + shiftY, paint); }; ProcessLinearPaths(pathSetIn, drawLabelF); }
void process_linear_paths(ToolpathSet ToolpathSetIn, Action <LinearToolpath3 <PrintVertex> > processF) { Action <IToolpathSet> pathsF = null; pathsF = (pathList) => { foreach (IToolpath path in pathList) { if (path is IToolpathSet) { pathsF(path as IToolpathSet); } else if (path is LinearToolpath3 <PrintVertex> ) { processF(path as LinearToolpath3 <PrintVertex>); } } }; pathsF(ToolpathSetIn); }
bool process_completed_compute() { if (active_compute != null) { if (active_compute.Finished) { lock (active_compute_lock) { if (active_compute.Success) { CurrentGCode = active_compute.gcode; Toolpaths = active_compute.paths; LayerInfo = active_compute.layerInfo; Settings = active_compute.PrintSettings; Slices = active_compute.SliceSet; ToolpathsValid = true; ToolpathsFailed = false; ToolpathsProgressEvent?.Invoke(new ToolpathProgressStatus(1, 1)); CC.Objects.SetToolpaths(this); } else { CurrentGCode = null; Toolpaths = null; LayerInfo = null; Settings = null; Slices = null; ToolpathsValid = false; ToolpathsFailed = true; // notify of failure here? ToolpathsProgressEvent?.Invoke(ToolpathProgressStatus.Failed); } active_compute = null; active_compute_thread = null; return(true); } } } return(false); }
private void DrawLayerPoints(ToolpathSet pathSetIn, SKCanvas canvas, SKPaint paint) { SKColor pointColor = SkiaUtil.Color(0, 0, 0, 255); float pointR = 1.5f; Action <LinearToolpath3 <PrintVertex> > drawPathPoints = (polyPath) => { if (LayerFilterF(polyPath.Start.Position) < 255) { return; } paint.Color = SkiaUtil.Color(pointColor, 255); paint.StrokeWidth = 1; for (int vi = 0; vi < polyPath.VertexCount; vi++) { Vector2f pt = (Vector2f)SceneXFormF(polyPath[vi].Position.xy); paint.Style = SKPaintStyle.Fill; canvas.DrawCircle(pt.x, pt.y, pointR, paint); } }; ProcessLinearPaths(pathSetIn, drawPathPoints); }
static void LoadGCodeFile(string sPath) { GenericGCodeParser parser = new GenericGCodeParser(); GCodeFile gcode; using (FileStream fs = new FileStream(sPath, FileMode.Open, FileAccess.Read)) { using (TextReader reader = new StreamReader(fs)) { gcode = parser.Parse(reader); } } GCodeToToolpaths converter = new GCodeToToolpaths(); MakerbotInterpreter interpreter = new MakerbotInterpreter(); interpreter.AddListener(converter); InterpretArgs interpArgs = new InterpretArgs(); interpreter.Interpret(gcode, interpArgs); ToolpathSet Paths = converter.PathSet; View.SetPaths(Paths); }
private void MarkFloatingEndpointsAndCorners(ToolpathSet pathSetIn, SKCanvas canvas, SKPaint paint) { double FloatingStartDistThreshMM = PathDiameterMM * 0.6f; float FloatCircleRadius = MapDimension(PathDiameterMM * 0.5f, SceneToSkiaF); paint.Style = SKPaintStyle.Stroke; paint.IsAntialias = true; paint.Color = SKColors.Black; paint.StrokeWidth = 4; SKColor start_color = SKColors.Red.WithAlpha(128); SKColor end_color = SKColors.Orange.WithAlpha(128); Action <LinearToolpath3 <PrintVertex> > drawFloatF = (polyPath) => { if (polyPath.Type != ToolpathTypes.Deposition) { return; } Vector3d v0 = polyPath.Start.Position; byte layer_alpha = LayerFilterF(v0); if (layer_alpha < 255) { return; } Vector2d nearPt; for (int k = 0; k < polyPath.VertexCount; ++k) { if (k > 0 && k < polyPath.VertexCount - 1) { double angle = polyPath.PlanarAngleD(k); if (angle > 179) { continue; } } Vector2d v = polyPath[k].Position.xy; double dist = find_below_nearest(v, FloatingStartDistThreshMM, out nearPt); if (dist == double.MaxValue) { paint.Color = start_color; SKPoint c = SceneToSkiaF(v), n = SceneToSkiaF(nearPt); canvas.DrawCircle(c.X, c.Y, FloatCircleRadius, paint); } } //Vector2d nearPt; //double dist = find_below_nearest(v0.xy, 4*FloatingStartDistThreshMM, out nearPt); //if ( dist < double.MaxValue && dist > FloatingStartDistThreshMM) { // paint.Color = start_color; // SKPoint c = SceneToSkiaF(v0.xy), n = SceneToSkiaF(nearPt); // canvas.DrawCircle(c.X, c.Y, FloatCircleRadius, paint); // paint.Color = SKColors.DarkRed; // canvas.DrawLine(c.X, c.Y, n.X, n.Y, paint); //} //Vector3d v1 = polyPath.End.Position; //double dist2 = find_below_nearest(v1.xy, 4*FloatingStartDistThreshMM, out nearPt); //if (dist2 < double.MaxValue && dist2 > FloatingStartDistThreshMM) { // paint.Color = end_color; // SKPoint c = SceneToSkiaF(v1.xy), n = SceneToSkiaF(nearPt); // canvas.DrawCircle(c.X, c.Y, FloatCircleRadius, paint); // paint.Color = SKColors.DarkOrange; // canvas.DrawLine(c.X, c.Y, n.X, n.Y, paint); //} }; ProcessLinearPaths(pathSetIn, drawFloatF); }
public GenericPathsAssembler() { AccumulatedPaths = new ToolpathSet(); }
public virtual void AppendPaths(ToolpathSet paths) { Assembler.AppendPaths(paths); }
public void ComputeOnBackgroundThread() { Deviation = null; DebugUtil.Log(SO.GetToolpathStats()); ToolpathSet paths = SO.GetToolpaths(); PlanarSliceStack slices = SO.GetSlices(); var settings = SO.GetSettings(); // AAHHH double bed_width = settings.Machine.BedSizeXMM; double bed_height = settings.Machine.BedSizeYMM; Vector3d origin = new Vector3d(-bed_width / 2, -bed_height / 2, 0); if (settings is gs.info.MakerbotSettings) { origin = Vector3d.Zero; } List <DeviationPt> points = new List <DeviationPt>(); SpinLock pointsLock = new SpinLock(); Action <DeviationPt> appendPointF = (pt) => { bool entered = false; pointsLock.Enter(ref entered); points.Add(pt); pointsLock.Exit(); }; double tolerance = settings.Machine.NozzleDiamMM * 0.5 + DeviationToleranceMM; gParallel.ForEach(Interval1i.Range(slices.Count), (slicei) => { PlanarSlice slice = slices[slicei]; //Interval1d zrange = (slicei < slices.Count - 1) ? // new Interval1d(slice.Z, slices[slicei + 1].Z - 0.5*settings.LayerHeightMM) : // new Interval1d(slice.Z, slice.Z + 0.5*settings.LayerHeightMM); double dz = 0.5 * settings.LayerHeightMM; Interval1d zrange = new Interval1d(slice.Z - dz, slice.Z + dz); double cellSize = 2.0f; ToolpathsLayerGrid grid = new ToolpathsLayerGrid(); grid.Build(paths, zrange, cellSize); foreach (GeneralPolygon2d poly in slice.Solids) { measure_poly(poly.Outer, slice.Z, grid, tolerance, appendPointF); foreach (var hole in poly.Holes) { measure_poly(poly.Outer, slice.Z, grid, tolerance, appendPointF); } } }); int N = points.Count; for (int k = 0; k < N; ++k) { DeviationPt pt = points[k]; Vector3d v = origin + pt.pos; v = MeshTransforms.ConvertZUpToYUp(v); pt.pos = MeshTransforms.FlipLeftRightCoordSystems(v); points[k] = pt; } Deviation = new DeviationData(); Deviation.DeviationPoints = points; OnGeometryUpdateRequired?.Invoke(this); }
private void DrawLayerPaths(ToolpathSet pathSetIn, SKCanvas canvas, SKPaint paint) { SKColor extrudeColor = SkiaUtil.Color(0, 0, 0, 255); SKColor travelColor = SkiaUtil.Color(0, 255, 0, 128); SKColor supportColor = SkiaUtil.Color(0, 200, 200, 255); SKColor bridgeColor = SkiaUtil.Color(200, 100, 0, 255); SKColor startColor = SkiaUtil.Color(255, 0, 0, 128); SKColor planeColor = SkiaUtil.Color(0, 0, 255, 128); float pointR = 3f; Action <LinearToolpath3 <PrintVertex> > drawPath3F = (polyPath) => { Vector3d v0 = polyPath.Start.Position; byte layer_alpha = LayerFilterF(v0); if (layer_alpha == 0) { return; } bool is_below = (layer_alpha < 255); SKPath path = MakePath(polyPath, SceneToSkiaF); if (polyPath.Type == ToolpathTypes.Deposition) { if ((polyPath.TypeModifiers & FillTypeFlags.SupportMaterial) != 0) { paint.Color = supportColor; } else if ((polyPath.TypeModifiers & FillTypeFlags.BridgeSupport) != 0) { paint.Color = bridgeColor; } else { paint.Color = extrudeColor; } paint.StrokeWidth = 1.5f; } else if (polyPath.Type == ToolpathTypes.Travel) { if (is_below) { return; } if (ShowTravels == false) { return; } paint.Color = travelColor; paint.StrokeWidth = 3; } else if (polyPath.Type == ToolpathTypes.PlaneChange) { if (is_below) { return; } if (ShowTravels == false) { return; } paint.StrokeWidth = 0.5f; paint.Color = planeColor; } else { if (is_below) { return; } paint.Color = startColor; } paint.Color = SkiaUtil.Color(paint.Color, layer_alpha); if (is_below) { paint.StrokeWidth = 6; } canvas.DrawPath(path, paint); paint.StrokeWidth = 1; if (is_below == false && ShowPathStartPoints) { Vector2f pt = SceneXFormF(polyPath.Start.Position.xy); if (polyPath.Type == ToolpathTypes.Deposition) { canvas.DrawCircle(pt.x, pt.y, pointR, paint); } else if (polyPath.Type == ToolpathTypes.Travel) { canvas.DrawCircle(pt.x, pt.y, pointR, paint); } else if (polyPath.Type == ToolpathTypes.PlaneChange) { paint.Style = SKPaintStyle.Fill; canvas.DrawCircle(pt.x, pt.y, 4f, paint); paint.Style = SKPaintStyle.Stroke; } } }; ProcessLinearPaths(pathSetIn, drawPath3F); }
public void Compute() { RequestCancel = false; printer = new SingleMaterialFFFPrintGenerator(Meshes, SliceSet, PrintSettings); if (PrintSettings.EnableSupportReleaseOpt) { printer.LayerPostProcessor = new SupportConnectionPostProcessor() { ZOffsetMM = PrintSettings.SupportReleaseGap }; } // if we aren't interpreting GCode, we want generator to return its path set printer.AccumulatePathSet = (InterpretGCodePaths == false); // set clip region Box2d clip_box = new Box2d(Vector2d.Zero, new Vector2d(CC.Settings.BedSizeXMM / 2, CC.Settings.BedSizeYMM / 2)); printer.PathClipRegions = new List <GeneralPolygon2d>() { new GeneralPolygon2d(new Polygon2d(clip_box.ComputeVertices())) }; printer.ErrorF = (msg, trace) => { if (RequestCancel == false) { DebugUtil.Log(2, "Slicer Error! msg: {0} stack {1}", msg, trace); } }; DebugUtil.Log(2, "Generating gcode..."); try { if (printer.Generate() == false) { throw new Exception("generate failed"); // this will be caught below } gcode = printer.Result; //DebugUtil.Log(2, "Interpreting gcode..."); if (InterpretGCodePaths) { GCodeToToolpaths converter = new GCodeToToolpaths(); MakerbotInterpreter interpreter = new MakerbotInterpreter(); interpreter.AddListener(converter); InterpretArgs interpArgs = new InterpretArgs(); interpreter.Interpret(gcode, interpArgs); paths = converter.PathSet; } else { paths = printer.AccumulatedPaths; } //DebugUtil.Log(2, "Detecting layers..."); layerInfo = new LayersDetector(paths); Success = true; } catch (Exception e) { DebugUtil.Log("ToolpathGenerator.Compute: exception: " + e.Message); Success = false; } Finished = true; }
static GCodeFile generate_cnc_test(MeshPlanarMillSlicer.Result sliceSets, RepRapSettings settings, out ToolpathSet AccumulatedPaths) { int PLUNGE_SPEED = 800; AccumulatedPaths = new ToolpathSet(); GCodeFileAccumulator file_accumulator = new GCodeFileAccumulator(); GCodeBuilder builder = new GCodeBuilder(file_accumulator); BaseThreeAxisMillingCompiler Compiler = new BaseThreeAxisMillingCompiler(builder, settings, GenericMillingAssembler.Factory); Compiler.Begin(); /* * Clearing pass */ PlanarSliceStack clearingSlices = sliceSets.Clearing; int N = clearingSlices.Count; // assuming origin is at top of stock so we actaully are going down in Z layers for (int k = 0; k < N; ++k) { clearingSlices[k].Z = -(sliceSets.TopZ - clearingSlices[k].Z); } for (int layeri = 0; layeri < N; layeri++) { PlanarSlice slice = clearingSlices[layeri]; Compiler.AppendComment(string.Format("clearing layer {0} - {1}mm", layeri, slice.Z)); ToolpathSetBuilder layer_builder = new ToolpathSetBuilder() { MoveType = ToolpathTypes.Cut }; layer_builder.Initialize(Compiler.ToolPosition); // To do a layer-change, we need to plunge down at the first scheduled cutting position. // However we will not know that until we schedule the first set of paths. // So, we configure SequentialScheduler2d to call this function when it knows this information, // and then we can travel to the new XY position before we plunge to new Z Action <List <FillCurveSet2d>, SequentialScheduler2d> DoZChangeF = (curves, scheduler) => { Vector2d startPosXY = (curves[0].Loops.Count > 0) ? curves[0].Loops[0].Start : curves[0].Curves[0].Start; Vector3d startPosXYZ = new Vector3d(startPosXY.x, startPosXY.y, slice.Z); // TODO: we should retract at faster speed here? maybe use custom function that does this better? layer_builder.AppendTravel(startPosXYZ, PLUNGE_SPEED); scheduler.OnAppendCurveSetsF = null; }; SequentialScheduler2d layerScheduler = new SequentialScheduler2d(layer_builder, settings) { ExtrudeOnShortTravels = true, ShortTravelDistance = settings.Machine.NozzleDiamMM * 1.5 }; layerScheduler.OnAppendCurveSetsF = DoZChangeF; GroupScheduler2d groupScheduler = new GroupScheduler2d(layerScheduler, Compiler.ToolPosition.xy); foreach (GeneralPolygon2d shape in slice.Solids) { ShellsFillPolygon shells_gen = new ShellsFillPolygon(shape) { PathSpacing = settings.ShellsFillPathSpacingMM(), ToolWidth = settings.Machine.NozzleDiamMM, Layers = 10, OuterShellLast = false, DiscardTinyPerimterLengthMM = 1, DiscardTinyPolygonAreaMM2 = 1 }; shells_gen.Compute(); groupScheduler.BeginGroup(); groupScheduler.AppendCurveSets(shells_gen.Shells); groupScheduler.EndGroup(); } Compiler.AppendPaths(layer_builder.Paths, settings); AccumulatedPaths.Append(layer_builder.Paths); } /* * Horizontal finish pass */ PlanarSliceStack horzSlices = sliceSets.HorizontalFinish; int NH = horzSlices.Count; // assuming origin is at top of stock so we actaully are going down in Z layers for (int k = 0; k < NH; ++k) { horzSlices[k].Z = -(sliceSets.TopZ - horzSlices[k].Z); } for (int layeri = 0; layeri < NH; layeri++) { PlanarSlice slice = horzSlices[layeri]; Compiler.AppendComment(string.Format("horz finish layer {0} - {1}mm", layeri, slice.Z)); ToolpathSetBuilder layer_builder = new ToolpathSetBuilder() { MoveType = ToolpathTypes.Cut }; layer_builder.Initialize(Compiler.ToolPosition); Action <List <FillCurveSet2d>, SequentialScheduler2d> DoZChangeF = (curves, scheduler) => { Vector2d startPosXY = (curves[0].Loops.Count > 0) ? curves[0].Loops[0].Start : curves[0].Curves[0].Start; Vector3d startPosXYZ = new Vector3d(startPosXY.x, startPosXY.y, slice.Z); // TODO: we should retract at faster speed here? maybe use custom function that does this better? layer_builder.AppendTravel(startPosXYZ, PLUNGE_SPEED); scheduler.OnAppendCurveSetsF = null; }; SequentialScheduler2d layerScheduler = new SequentialScheduler2d(layer_builder, settings) { ExtrudeOnShortTravels = true, ShortTravelDistance = settings.Machine.NozzleDiamMM * 1.5 }; layerScheduler.OnAppendCurveSetsF = DoZChangeF; GroupScheduler2d groupScheduler = new GroupScheduler2d(layerScheduler, Compiler.ToolPosition.xy); foreach (GeneralPolygon2d shape in slice.Solids) { ShellsFillPolygon shells_gen = new ShellsFillPolygon(shape) { //InsetFromInputPolygonX = 0.0, PathSpacing = settings.ShellsFillPathSpacingMM(), ToolWidth = settings.Machine.NozzleDiamMM, Layers = 10, OuterShellLast = false, PreserveInputInsetTopology = false, DiscardTinyPerimterLengthMM = 1, DiscardTinyPolygonAreaMM2 = 1 }; shells_gen.Compute(); groupScheduler.BeginGroup(); groupScheduler.AppendCurveSets(shells_gen.Shells); groupScheduler.EndGroup(); } Compiler.AppendPaths(layer_builder.Paths, settings); AccumulatedPaths.Append(layer_builder.Paths); } // return to home position ToolpathSetBuilder finishBuilder = new ToolpathSetBuilder() { MoveType = ToolpathTypes.Cut }; finishBuilder.Initialize(Compiler.ToolPosition); finishBuilder.AppendTravel(Vector3d.Zero, PLUNGE_SPEED); Compiler.AppendPaths(finishBuilder.Paths, settings); Compiler.End(); return(file_accumulator.File); }