public void QueueAirGappedBottomLayer(ConfigSettings config, GCodePlanner gcodeLayer, int layerIndex, GCodePathConfig supportNormalConfig) { // normal support Polygons currentAirGappedBottoms = airGappedBottomOutlines[layerIndex]; currentAirGappedBottoms = currentAirGappedBottoms.Offset(-config.ExtrusionWidth_um / 2); List <Polygons> supportIslands = currentAirGappedBottoms.ProcessIntoSeparatIslands(); foreach (Polygons islandOutline in supportIslands) { Polygons islandInfillLines = new Polygons(); // render a grid of support if (config.GenerateSupportPerimeter) { Polygons outlines = Clipper.CleanPolygons(islandOutline, config.ExtrusionWidth_um / 4); gcodeLayer.QueuePolygonsByOptimizer(outlines, supportNormalConfig); } Polygons infillOutline = islandOutline.Offset(-config.ExtrusionWidth_um / 2); switch (config.SupportType) { case ConfigConstants.SUPPORT_TYPE.GRID: Infill.GenerateGridInfill(config, infillOutline, islandInfillLines, config.SupportInfillStartingAngle, config.SupportLineSpacing_um); break; case ConfigConstants.SUPPORT_TYPE.LINES: Infill.GenerateLineInfill(config, infillOutline, islandInfillLines, config.SupportInfillStartingAngle, config.SupportLineSpacing_um); break; } gcodeLayer.QueuePolygonsByOptimizer(islandInfillLines, supportNormalConfig); } }
public bool QueueNormalSupportLayer(ConfigSettings config, GCodePlanner gcodeLayer, int layerIndex, GCodePathConfig supportNormalConfig) { // normal support Polygons currentSupportOutlines = supportOutlines[layerIndex]; currentSupportOutlines = currentSupportOutlines.Offset(-supportNormalConfig.lineWidth_um / 2); List <Polygons> supportIslands = currentSupportOutlines.ProcessIntoSeparatIslands(); bool outputPaths = false; foreach (Polygons islandOutline in supportIslands) { // force a retract if changing islands if (config.RetractWhenChangingIslands) { gcodeLayer.ForceRetract(); } Polygons islandInfillLines = new Polygons(); // render a grid of support if (config.GenerateSupportPerimeter || layerIndex == 0) { Polygons outlines = Clipper.CleanPolygons(islandOutline, config.ExtrusionWidth_um / 4); if (gcodeLayer.QueuePolygonsByOptimizer(outlines, supportNormalConfig)) { outputPaths = true; } } Polygons infillOutline = islandOutline.Offset(-supportNormalConfig.lineWidth_um / 2); if (layerIndex == 0) { // on the first layer print this as solid Infill.GenerateLineInfill(config, infillOutline, islandInfillLines, config.SupportInfillStartingAngle, config.ExtrusionWidth_um); } else { switch (config.SupportType) { case ConfigConstants.SUPPORT_TYPE.GRID: Infill.GenerateGridInfill(config, infillOutline, islandInfillLines, config.SupportInfillStartingAngle, config.SupportLineSpacing_um); break; case ConfigConstants.SUPPORT_TYPE.LINES: Infill.GenerateLineInfill(config, infillOutline, islandInfillLines, config.SupportInfillStartingAngle, config.SupportLineSpacing_um); break; } } if (gcodeLayer.QueuePolygonsByOptimizer(islandInfillLines, supportNormalConfig)) { outputPaths |= true; } } return(outputPaths); }
public void QueueAirGappedBottomLayer(ConfigSettings config, LayerGCodePlanner gcodeLayer, int layerIndex, GCodePathConfig supportNormalConfig) { // normal support Polygons currentAirGappedBottoms = AirGappedBottomOutlines[layerIndex]; List <Polygons> supportIslands = currentAirGappedBottoms.ProcessIntoSeparateIslands(); foreach (Polygons supportIsland in supportIslands) { PathFinder pathFinder = null; if (config.AvoidCrossingPerimeters) { pathFinder = new PathFinder(supportIsland, -config.ExtrusionWidth_um / 2, useInsideCache: config.AvoidCrossingPerimeters, name: "air gap"); } // force a retract if changing islands if (config.RetractWhenChangingIslands) { gcodeLayer.ForceRetract(); } var infillOffset = -config.ExtrusionWidth_um + config.InfillExtendIntoPerimeter_um; // make a border if layer 0 if (config.GenerateSupportPerimeter || layerIndex == 0) { var closedLoop = supportNormalConfig.ClosedLoop; supportNormalConfig.ClosedLoop = true; gcodeLayer.QueuePolygonsByOptimizer(supportIsland.Offset(-config.ExtrusionWidth_um / 2), pathFinder, supportNormalConfig, layerIndex); infillOffset = config.ExtrusionWidth_um * -2 + config.InfillExtendIntoPerimeter_um; supportNormalConfig.ClosedLoop = closedLoop; } Polygons infillOutline = supportIsland.Offset(infillOffset); Polygons islandInfillLines = new Polygons(); switch (config.SupportType) { case ConfigConstants.SUPPORT_TYPE.GRID: Infill.GenerateGridInfill(config, infillOutline, islandInfillLines, config.SupportInfillStartingAngle, config.SupportLineSpacing_um); break; case ConfigConstants.SUPPORT_TYPE.LINES: Infill.GenerateLineInfill(config, infillOutline, islandInfillLines, config.SupportInfillStartingAngle, config.SupportLineSpacing_um); break; } gcodeLayer.QueuePolygonsByOptimizer(islandInfillLines, pathFinder, supportNormalConfig, 0); } }
public void QueueAirGappedBottomLayer(ConfigSettings config, LayerGCodePlanner gcodeLayer, int layerIndex, GCodePathConfig supportNormalConfig, PathFinder pathFinder) { // normal support Polygons currentAirGappedBottoms = AirGappedBottomOutlines[layerIndex]; List <Polygons> supportIslands = currentAirGappedBottoms.ProcessIntoSeparateIslands(); foreach (Polygons supportIsland in supportIslands) { var allSupport = new Polygons(); // force a retract if changing islands if (config.RetractWhenChangingIslands) { gcodeLayer.ForceRetract(); } var infillOffset = -config.ExtrusionWidth_um + config.InfillExtendIntoPerimeter_um; // make a border if layer 0 if (config.GenerateSupportPerimeter || layerIndex == 0) { allSupport.AddRange(supportIsland.Offset(config.ExtrusionWidth_um / 2)); infillOffset = config.ExtrusionWidth_um * -2 + config.InfillExtendIntoPerimeter_um; } Polygons infillOutline = supportIsland.Offset(infillOffset); var islandInfillLines = new Polygons(); switch (config.SupportType) { case SUPPORT_TYPE.GRID: Infill.GenerateGridInfill(config, infillOutline, islandInfillLines, config.SupportInfillStartingAngle, config.SupportLineSpacing_um); break; case SUPPORT_TYPE.LINES: Infill.GenerateLineInfill(config, infillOutline, islandInfillLines, config.SupportInfillStartingAngle, config.SupportLineSpacing_um); break; } allSupport.AddRange(islandInfillLines); gcodeLayer.QueuePolygonsByOptimizer(allSupport, pathFinder, supportNormalConfig, layerIndex); } }
private void WriteSupportPolygons(SliceDataStorage storage, GCodePlanner gcodeLayer, int layerIndex, ConfigSettings config, Polygons supportPolygons, SupportType interfaceLayer) { for (int volumeIndex = 0; volumeIndex < storage.volumes.Count; volumeIndex++) { SliceLayer layer = storage.volumes[volumeIndex].layers[layerIndex]; for (int partIndex = 0; partIndex < layer.parts.Count; partIndex++) { supportPolygons = supportPolygons.CreateDifference(layer.parts[partIndex].TotalOutline.Offset(config.supportXYDistance_um)); } } //Contract and expand the support polygons so small sections are removed and the final polygon is smoothed a bit. supportPolygons = supportPolygons.Offset(-config.extrusionWidth_um * 1); supportPolygons = supportPolygons.Offset(config.extrusionWidth_um * 1); List<Polygons> supportIslands = supportPolygons.CreateLayerOutlines(PolygonsHelper.LayerOpperation.EvenOdd); PathOrderOptimizer islandOrderOptimizer = new PathOrderOptimizer(gcode.GetPositionXY()); for (int islandIndex = 0; islandIndex < supportIslands.Count; islandIndex++) { islandOrderOptimizer.AddPolygon(supportIslands[islandIndex][0]); } islandOrderOptimizer.Optimize(); for (int islandIndex = 0; islandIndex < supportIslands.Count; islandIndex++) { Polygons island = supportIslands[islandOrderOptimizer.bestPolygonOrderIndex[islandIndex]]; Polygons supportLines = new Polygons(); if (config.supportLineSpacing_um > 0) { switch (interfaceLayer) { case SupportType.Interface: Infill.GenerateLineInfill(config, island, ref supportLines, config.supportInfillStartingAngle + 90, config.extrusionWidth_um); break; case SupportType.General: switch (config.supportType) { case ConfigConstants.SUPPORT_TYPE.GRID: Infill.GenerateGridInfill(config, island, ref supportLines, config.supportInfillStartingAngle, config.supportLineSpacing_um); break; case ConfigConstants.SUPPORT_TYPE.LINES: Infill.GenerateLineInfill(config, island, ref supportLines, config.supportInfillStartingAngle, config.supportLineSpacing_um); break; } break; default: throw new NotImplementedException(); } } if (config.avoidCrossingPerimeters) { gcodeLayer.SetOuterPerimetersToAvoidCrossing(island); } switch (interfaceLayer) { case SupportType.Interface: gcodeLayer.WritePolygonsByOptimizer(supportLines, supportInterfaceConfig); break; case SupportType.General: if (config.supportType == ConfigConstants.SUPPORT_TYPE.GRID) { gcodeLayer.WritePolygonsByOptimizer(island, supportNormalConfig); } gcodeLayer.WritePolygonsByOptimizer(supportLines, supportNormalConfig); break; default: throw new NotImplementedException(); } gcodeLayer.SetOuterPerimetersToAvoidCrossing(null); } }
private void CalculateInfillData(SliceDataStorage storage, int volumeIndex, int layerIndex, SliceLayerPart part, ref Polygons fillPolygons, ref Polygons bridgePolygons) { // generate infill the bottom layers including bridging foreach (Polygons outline in part.SolidBottomOutlines.CreateLayerOutlines(PolygonsHelper.LayerOpperation.EvenOdd)) { if (layerIndex > 0) { double bridgeAngle; if (Bridge.BridgeAngle(outline, storage.volumes[volumeIndex].layers[layerIndex - 1], out bridgeAngle)) { Infill.GenerateLinePaths(outline, ref bridgePolygons, config.extrusionWidth_um, config.infillExtendIntoPerimeter_um, bridgeAngle); } else { Infill.GenerateLinePaths(outline, ref fillPolygons, config.extrusionWidth_um, config.infillExtendIntoPerimeter_um, config.infillStartingAngle); } } else { Infill.GenerateLinePaths(outline, ref fillPolygons, config.firstLayerExtrusionWidth_um, config.infillExtendIntoPerimeter_um, config.infillStartingAngle); } } // generate infill for the top layers foreach (Polygons outline in part.SolidTopOutlines.CreateLayerOutlines(PolygonsHelper.LayerOpperation.EvenOdd)) { Infill.GenerateLinePaths(outline, ref fillPolygons, config.extrusionWidth_um, config.infillExtendIntoPerimeter_um, config.infillStartingAngle); } // generate infill intermediate layers foreach (Polygons outline in part.SolidInfillOutlines.CreateLayerOutlines(PolygonsHelper.LayerOpperation.EvenOdd)) { if (true) // use the old infill method { Infill.GenerateLinePaths(outline, ref fillPolygons, config.extrusionWidth_um, config.infillExtendIntoPerimeter_um, config.infillStartingAngle + 90 * (layerIndex % 2)); } else // use the new concentric infill (not tested enough yet) have to handle some bad casses better { double oldInfillPercent = config.infillPercent; config.infillPercent = 100; Infill.GenerateConcentricInfill(config, outline, ref fillPolygons); config.infillPercent = oldInfillPercent; } } double fillAngle = config.infillStartingAngle; // generate the infill for this part on this layer if (config.infillPercent > 0) { switch (config.infillType) { case ConfigConstants.INFILL_TYPE.LINES: if ((layerIndex & 1) == 1) { fillAngle += 90; } Infill.GenerateLineInfill(config, part.InfillOutlines, ref fillPolygons, fillAngle); break; case ConfigConstants.INFILL_TYPE.GRID: Infill.GenerateGridInfill(config, part.InfillOutlines, ref fillPolygons, fillAngle); break; case ConfigConstants.INFILL_TYPE.TRIANGLES: Infill.GenerateTriangleInfill(config, part.InfillOutlines, ref fillPolygons, fillAngle); break; case ConfigConstants.INFILL_TYPE.HEXAGON: Infill.GenerateHexagonInfill(config, part.InfillOutlines, ref fillPolygons, fillAngle, layerIndex); break; case ConfigConstants.INFILL_TYPE.CONCENTRIC: Infill.GenerateConcentricInfill(config, part.InfillOutlines, ref fillPolygons); break; default: throw new NotImplementedException(); } } }
public bool QueueNormalSupportLayer(ConfigSettings config, LayerGCodePlanner gcodeLayer, int layerIndex, GCodePathConfig supportNormalConfig, PathFinder pathFinder) { var foundSupport = false; // normal support Polygons currentSupportOutlines = SparseSupportOutlines[layerIndex]; List <Polygons> supportIslands = currentSupportOutlines.ProcessIntoSeparateIslands(); var infillOutlines = new List <Polygons>(); for (int i = 0; i < supportIslands.Count; i++) { infillOutlines.Add(null); } Agg.Parallel.For(0, supportIslands.Count, (index) => { var infillOffset = -config.ExtrusionWidth_um + config.InfillExtendIntoPerimeter_um; var supportIsland = supportIslands[index]; infillOutlines[index] = supportIsland.Offset(infillOffset); }); for (int i = 0; i < supportIslands.Count; i++) { var allSupport = new Polygons(); var supportIsland = supportIslands[i]; // force a retract if changing islands if (config.RetractWhenChangingIslands) { gcodeLayer.ForceRetract(); } // make a border if layer 0 if (config.GenerateSupportPerimeter || layerIndex == 0) { allSupport.AddRange(supportIsland.Offset(config.ExtrusionWidth_um / 2)); } var islandInfillLines = new Polygons(); if (layerIndex == 0) { // on the first layer print this as solid Infill.GenerateLineInfill(config, infillOutlines[i], islandInfillLines, config.SupportInfillStartingAngle, config.ExtrusionWidth_um); } else { switch (config.SupportType) { case SUPPORT_TYPE.GRID: Infill.GenerateGridInfill(config, infillOutlines[i], islandInfillLines, config.SupportInfillStartingAngle, config.SupportLineSpacing_um); break; case SUPPORT_TYPE.LINES: Infill.GenerateLineInfill(config, infillOutlines[i], islandInfillLines, config.SupportInfillStartingAngle, config.SupportLineSpacing_um); break; } } allSupport.AddRange(islandInfillLines); if (gcodeLayer.QueuePolygonsByOptimizer(allSupport, pathFinder, supportNormalConfig, 0)) { foundSupport = true; } } return(foundSupport); }
private void CalculateInfillData(SliceDataStorage storage, int volumeIndex, int layerIndex, int extrusionWidth_um, SliceLayerPart part, ref Polygons fillPolygons, ref Polygons bridgePolygons) { // generate infill for outline including bridging foreach (Polygons outline in part.skinOutline.SplitIntoParts()) { double partFillAngle = config.infillStartingAngle; if ((layerIndex & 1) == 1) { partFillAngle += 90; } if (layerIndex > 0) { double bridgeAngle; if (Bridge.BridgeAngle(outline, storage.volumes[volumeIndex].layers[layerIndex - 1], out bridgeAngle)) { Infill.GenerateLinePaths(outline, ref bridgePolygons, extrusionWidth_um, config.infillExtendIntoPerimeter_um, bridgeAngle); } else { Infill.GenerateLinePaths(outline, ref fillPolygons, extrusionWidth_um, config.infillExtendIntoPerimeter_um, partFillAngle); } } else { Infill.GenerateLinePaths(outline, ref fillPolygons, extrusionWidth_um, config.infillExtendIntoPerimeter_um, partFillAngle); } } double fillAngle = config.infillStartingAngle; // generate the infill for this part on this layer if (config.infillPercent > 0) { switch (config.infillType) { case ConfigConstants.INFILL_TYPE.LINES: if ((layerIndex & 1) == 1) { fillAngle += 90; } Infill.GenerateLineInfill(config, part.sparseOutline, ref fillPolygons, extrusionWidth_um, fillAngle); break; case ConfigConstants.INFILL_TYPE.GRID: Infill.GenerateGridInfill(config, part.sparseOutline, ref fillPolygons, extrusionWidth_um, fillAngle); break; case ConfigConstants.INFILL_TYPE.TRIANGLES: Infill.GenerateTriangleInfill(config, part.sparseOutline, ref fillPolygons, extrusionWidth_um, fillAngle); break; case ConfigConstants.INFILL_TYPE.HEXAGON: Infill.GenerateHexagonInfill(config, part.sparseOutline, ref fillPolygons, extrusionWidth_um, fillAngle, layerIndex); break; case ConfigConstants.INFILL_TYPE.CONCENTRIC: Infill.generateConcentricInfill(config, part.sparseOutline, ref fillPolygons, extrusionWidth_um, fillAngle); break; default: throw new NotImplementedException(); } } }
public bool QueueNormalSupportLayer(ConfigSettings config, LayerGCodePlanner gcodeLayer, int layerIndex, GCodePathConfig supportNormalConfig) { // normal support Polygons currentSupportOutlines = SparseSupportOutlines[layerIndex]; List <Polygons> supportIslands = currentSupportOutlines.ProcessIntoSeparateIslands(); List <PathFinder> pathFinders = new List <PathFinder>(); List <Polygons> infillOutlines = new List <Polygons>(); for (int i = 0; i < supportIslands.Count; i++) { pathFinders.Add(null); infillOutlines.Add(null); } Agg.Parallel.For(0, supportIslands.Count, (index) => { var infillOffset = -config.ExtrusionWidth_um + config.InfillExtendIntoPerimeter_um; var supportIsland = supportIslands[index]; infillOutlines[index] = supportIsland.Offset(infillOffset); if (config.AvoidCrossingPerimeters) { pathFinders[index] = new PathFinder(infillOutlines[index], -config.ExtrusionWidth_um / 2, useInsideCache: config.AvoidCrossingPerimeters, name: "normal support"); } }); bool outputPaths = false; for (int i = 0; i < supportIslands.Count; i++) { var supportIsland = supportIslands[i]; // force a retract if changing islands if (config.RetractWhenChangingIslands) { gcodeLayer.ForceRetract(); } // make a border if layer 0 if (config.GenerateSupportPerimeter || layerIndex == 0) { if (gcodeLayer.QueuePolygonsByOptimizer(supportIsland.Offset(-config.ExtrusionWidth_um / 2), pathFinders[i], supportNormalConfig, 0)) { outputPaths = true; } } Polygons islandInfillLines = new Polygons(); if (layerIndex == 0) { // on the first layer print this as solid Infill.GenerateLineInfill(config, infillOutlines[i], islandInfillLines, config.SupportInfillStartingAngle, config.ExtrusionWidth_um); } else { switch (config.SupportType) { case ConfigConstants.SUPPORT_TYPE.GRID: Infill.GenerateGridInfill(config, infillOutlines[i], islandInfillLines, config.SupportInfillStartingAngle, config.SupportLineSpacing_um); break; case ConfigConstants.SUPPORT_TYPE.LINES: Infill.GenerateLineInfill(config, infillOutlines[i], islandInfillLines, config.SupportInfillStartingAngle, config.SupportLineSpacing_um); break; } } if (gcodeLayer.QueuePolygonsByOptimizer(islandInfillLines, pathFinders[i], supportNormalConfig, 0)) { outputPaths |= true; } } return(outputPaths); }