private static List <Polygons> CreateInterfaceLayers(List <Polygons> inputPolys, int numInterfaceLayers) { int numLayers = inputPolys.Count; List <Polygons> allInterfaceLayers = CreateEmptyPolygons(numLayers); if (numInterfaceLayers > 0) { for (int layerIndex = 0; layerIndex < numLayers; layerIndex++) { Polygons requiredInterfacePolys = inputPolys[layerIndex].DeepCopy(); if (layerIndex < numLayers - 1) { Polygons intersectionsAbove = inputPolys[layerIndex + 1].DeepCopy(); for (int aboveIndex = layerIndex + 2; aboveIndex < Math.Min(layerIndex + numInterfaceLayers + 1, numLayers); aboveIndex++) { intersectionsAbove = intersectionsAbove.CreateIntersection(inputPolys[aboveIndex]); intersectionsAbove = Clipper.CleanPolygons(intersectionsAbove, cleanDistance_um); } requiredInterfacePolys = requiredInterfacePolys.CreateDifference(intersectionsAbove); requiredInterfacePolys = Clipper.CleanPolygons(requiredInterfacePolys, cleanDistance_um); } allInterfaceLayers[layerIndex] = requiredInterfacePolys; } } return(allInterfaceLayers); }
private static List <Polygons> AccumulateDownPolygons(ConfigSettings config, List <Polygons> inputPolys, List <Polygons> allPartOutlines) { int numLayers = inputPolys.Count; long nozzleSize = config.ExtrusionWidth_um; List <Polygons> allDownOutlines = CreateEmptyPolygons(numLayers); for (int layerIndex = numLayers - 2; layerIndex >= 0; layerIndex--) { Polygons aboveRequiredSupport = inputPolys[layerIndex + 1]; // get all the polygons above us Polygons accumulatedAbove = allDownOutlines[layerIndex + 1].CreateUnion(aboveRequiredSupport); // add in the support on this level Polygons curRequiredSupport = inputPolys[layerIndex]; Polygons totalSupportThisLayer = accumulatedAbove.CreateUnion(curRequiredSupport); // remove the solid polygons on this level Polygons remainingAbove = totalSupportThisLayer.CreateDifference(allPartOutlines[layerIndex]); allDownOutlines[layerIndex] = Clipper.CleanPolygons(remainingAbove, cleanDistance_um); } return(allDownOutlines); }
public static void generateTopAndBottomLayers(int layerIndex, SliceVolumeStorage storage, int extrusionWidth, int downSkinCount, int upSkinCount) { SliceLayer layer = storage.layers[layerIndex]; for (int partNr = 0; partNr < layer.parts.Count; partNr++) { SliceLayerPart part = layer.parts[partNr]; Polygons upskin = part.insets[part.insets.Count - 1].Offset(-extrusionWidth / 2); Polygons downskin = upskin; if (part.insets.Count > 1) { // Add thin wall filling by taking the area between the insets. Polygons thinWalls = part.insets[0].Offset(-extrusionWidth / 2).CreateDifference(part.insets[1].Offset(extrusionWidth / 2)); upskin.AddAll(thinWalls); downskin.AddAll(thinWalls); } if (layerIndex - downSkinCount >= 0) { SliceLayer layer2 = storage.layers[layerIndex - downSkinCount]; for (int partIndex = 0; partIndex < layer2.parts.Count; partIndex++) { if (part.boundaryBox.hit(layer2.parts[partIndex].boundaryBox)) { downskin = downskin.CreateDifference(layer2.parts[partIndex].insets[layer2.parts[partIndex].insets.Count - 1]); } } } if (layerIndex + upSkinCount < storage.layers.Count) { SliceLayer layer2 = storage.layers[layerIndex + upSkinCount]; for (int partIndex = 0; partIndex < layer2.parts.Count; partIndex++) { if (part.boundaryBox.hit(layer2.parts[partIndex].boundaryBox)) { upskin = upskin.CreateDifference(layer2.parts[partIndex].insets[layer2.parts[partIndex].insets.Count - 1]); } } } part.skinOutline = upskin.CreateUnion(downskin); double minAreaSize = (2 * Math.PI * (extrusionWidth / 1000.0) * (extrusionWidth / 1000.0)) * 0.3; for (int outlineIndex = 0; outlineIndex < part.skinOutline.Count; outlineIndex++) { double area = Math.Abs(part.skinOutline[outlineIndex].Area()) / 1000.0 / 1000.0; if (area < minAreaSize) // Only create an up/down skin if the area is large enough. So you do not create tiny blobs of "trying to fill" { part.skinOutline.RemoveAt(outlineIndex); outlineIndex -= 1; } } } }
private static Polygons RemoveIslandsFromPolygons(List <LayerIsland> islands, Aabb boundsToConsider, Polygons polygonsToSubtractFrom) { for (int islandIndex = 0; islandIndex < islands.Count; islandIndex++) { if (boundsToConsider.Hit(islands[islandIndex].BoundingBox)) { polygonsToSubtractFrom = polygonsToSubtractFrom.CreateDifference(islands[islandIndex].InsetToolPaths[islands[islandIndex].InsetToolPaths.Count - 1]); polygonsToSubtractFrom = Clipper.CleanPolygons(polygonsToSubtractFrom, cleanDistance_um); } } return(polygonsToSubtractFrom); }
private static Polygons RemoveAdditionalOutlinesForPart(SliceLayer layerToSubtract, SliceLayerPart partToUseAsBounds, Polygons polygonsToSubtractFrom) { for (int partIndex = 0; partIndex < layerToSubtract.parts.Count; partIndex++) { if (partToUseAsBounds.BoundingBox.Hit(layerToSubtract.parts[partIndex].BoundingBox)) { polygonsToSubtractFrom = polygonsToSubtractFrom.CreateDifference(layerToSubtract.parts[partIndex].Insets[layerToSubtract.parts[partIndex].Insets.Count - 1]); polygonsToSubtractFrom = Clipper.CleanPolygons(polygonsToSubtractFrom, cleanDistance_um); } } return(polygonsToSubtractFrom); }
private static List <Polygons> CalculateDifferencePerLayer(List <Polygons> inputPolys, List <Polygons> outlinesToRemove) { int numLayers = inputPolys.Count; List <Polygons> diferenceLayers = CreateEmptyPolygons(numLayers); for (int layerIndex = numLayers - 2; layerIndex >= 0; layerIndex--) { Polygons curRequiredSupport = inputPolys[layerIndex]; Polygons totalSupportThisLayer = curRequiredSupport.CreateDifference(outlinesToRemove[layerIndex]); diferenceLayers[layerIndex] = Clipper.CleanPolygons(totalSupportThisLayer, cleanDistance_um); } return(diferenceLayers); }
private static List <Polygons> FindAllPotentialSupportOutlines(List <Polygons> inputPolys, long supportWidth_um) { int numLayers = inputPolys.Count; List <Polygons> allPotentialSupportOutlines = CreateEmptyPolygons(numLayers); // calculate all the non-supported areas for (int layerIndex = numLayers - 2; layerIndex >= 0; layerIndex--) { Polygons aboveLayerPolys = inputPolys[layerIndex + 1]; Polygons curLayerPolys = inputPolys[layerIndex].Offset(supportWidth_um); Polygons areasNeedingSupport = aboveLayerPolys.CreateDifference(curLayerPolys); allPotentialSupportOutlines[layerIndex] = Clipper.CleanPolygons(areasNeedingSupport, cleanDistance_um); } return(allPotentialSupportOutlines); }
private static List <Polygons> ClipToXyDistance(List <Polygons> inputPolys, List <Polygons> allPartOutlines, ConfigSettings config) { int numLayers = inputPolys.Count; List <Polygons> clippedToXyOutlines = CreateEmptyPolygons(numLayers); for (int layerIndex = numLayers - 2; layerIndex >= 0; layerIndex--) { Polygons curRequiredSupport = inputPolys[layerIndex]; Polygons expandedlayerPolys = allPartOutlines[layerIndex].Offset(config.SupportXYDistance_um); Polygons totalSupportThisLayer = curRequiredSupport.CreateDifference(expandedlayerPolys); clippedToXyOutlines[layerIndex] = Clipper.CleanPolygons(totalSupportThisLayer, cleanDistance_um); } return(clippedToXyOutlines); }
private static List <Polygons> AccumulateDownPolygons(ConfigSettings config, List <Polygons> inputPolys, List <Polygons> allPartOutlines) { int numLayers = inputPolys.Count; long nozzleSize = config.ExtrusionWidth_um; long areaToTryAndBe = 20 * 20 * nozzleSize * nozzleSize; // 10 x 10 mm approximately (assuming .5 nozzle) List <Polygons> allDownOutlines = CreateEmptyPolygons(numLayers); for (int layerIndex = numLayers - 2; layerIndex >= 0; layerIndex--) { Polygons aboveRequiredSupport = inputPolys[layerIndex + 1]; // get all the polygons above us Polygons accumulatedAbove = allDownOutlines[layerIndex + 1].CreateUnion(aboveRequiredSupport); // experimental and not working well enough yet if (config.MinimizeSupportColumns) { // reduce the amount of support material used for (int i = accumulatedAbove.Count - 1; i >= 0; i--) { Polygon polygon = accumulatedAbove[i]; double polyArea = polygon.Area(); if (polyArea > areaToTryAndBe) { Polygons offsetPolygons = new Polygons() { polygon }.Offset(-config.ExtrusionWidth_um / 2); accumulatedAbove.RemoveAt(i); foreach (Polygon polyToAdd in offsetPolygons) { accumulatedAbove.Insert(i, polyToAdd); } } else if (polyArea < areaToTryAndBe * .9) { Polygons offsetPolygons = new Polygons() { polygon }.Offset(config.ExtrusionWidth_um / 2); accumulatedAbove.RemoveAt(i); foreach (Polygon polyToAdd in offsetPolygons) { accumulatedAbove.Insert(i, polyToAdd); } } } } // add in the support on this level Polygons curRequiredSupport = inputPolys[layerIndex]; Polygons totalSupportThisLayer = accumulatedAbove.CreateUnion(curRequiredSupport); // remove the solid polygons on this level Polygons remainingAbove = totalSupportThisLayer.CreateDifference(allPartOutlines[layerIndex]); allDownOutlines[layerIndex] = Clipper.CleanPolygons(remainingAbove, cleanDistance_um); } return(allDownOutlines); }
public static void generateSparse(int layerIndex, SliceVolumeStorage storage, int extrusionWidth, int downSkinCount, int upSkinCount) { SliceLayer layer = storage.layers[layerIndex]; for (int partNr = 0; partNr < layer.parts.Count; partNr++) { SliceLayerPart part = layer.parts[partNr]; Polygons sparse = part.insets[part.insets.Count - 1].Offset(-extrusionWidth / 2); Polygons downskin = sparse; Polygons upskin = sparse; if ((int)(layerIndex - downSkinCount) >= 0) { SliceLayer layer2 = storage.layers[layerIndex - downSkinCount]; for (int partNr2 = 0; partNr2 < layer2.parts.Count; partNr2++) { if (part.boundaryBox.hit(layer2.parts[partNr2].boundaryBox)) { if (layer2.parts[partNr2].insets.Count > 1) { downskin = downskin.CreateDifference(layer2.parts[partNr2].insets[layer2.parts[partNr2].insets.Count - 2]); } else { downskin = downskin.CreateDifference(layer2.parts[partNr2].insets[layer2.parts[partNr2].insets.Count - 1]); } } } } if ((int)(layerIndex + upSkinCount) < (int)storage.layers.Count) { SliceLayer layer2 = storage.layers[layerIndex + upSkinCount]; for (int partNr2 = 0; partNr2 < layer2.parts.Count; partNr2++) { if (part.boundaryBox.hit(layer2.parts[partNr2].boundaryBox)) { if (layer2.parts[partNr2].insets.Count > 1) { upskin = upskin.CreateDifference(layer2.parts[partNr2].insets[layer2.parts[partNr2].insets.Count - 2]); } else { upskin = upskin.CreateDifference(layer2.parts[partNr2].insets[layer2.parts[partNr2].insets.Count - 1]); } } } } Polygons result = upskin.CreateUnion(downskin); double minAreaSize = 3.0;//(2 * M_PI * ((double)(config.extrusionWidth) / 1000.0) * ((double)(config.extrusionWidth) / 1000.0)) * 3; for (int i = 0; i < result.Count; i++) { double area = Math.Abs(result[i].Area()) / 1000.0 / 1000.0; if (area < minAreaSize) /* Only create an up/down skin if the area is large enough. So you do not create tiny blobs of "trying to fill" */ { result.RemoveAt(i); i -= 1; } } part.sparseOutline = sparse.CreateDifference(result); } }
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); } }
public static void GenerateTopAndBottom(int layerIndex, SliceVolumeStorage storage, int extrusionWidth, int downLayerCount, int upLayerCount) { SliceLayer layer = storage.layers[layerIndex]; for (int partIndex = 0; partIndex < layer.parts.Count; partIndex++) { SliceLayerPart part = layer.parts[partIndex]; Polygons insetWithOffset = part.Insets[part.Insets.Count - 1].Offset(-extrusionWidth / 2); Polygons infillOutlines = new Polygons(insetWithOffset); // calculate the bottom outlines if (downLayerCount > 0) { Polygons bottomOutlines = new Polygons(insetWithOffset); if (layerIndex - 1 >= 0) { bottomOutlines = RemoveAdditionalOutlinesForPart(storage.layers[layerIndex - 1], part, bottomOutlines); RemoveSmallAreas(extrusionWidth, bottomOutlines); } infillOutlines = infillOutlines.CreateDifference(bottomOutlines); infillOutlines = Clipper.CleanPolygons(infillOutlines, cleanDistance_um); part.SolidBottomOutlines = bottomOutlines; } // calculate the top outlines if (upLayerCount > 0) { Polygons topOutlines = new Polygons(insetWithOffset); topOutlines = topOutlines.CreateDifference(part.SolidBottomOutlines); topOutlines = Clipper.CleanPolygons(topOutlines, cleanDistance_um); if (part.Insets.Count > 1) { // Add thin wall filling by taking the area between the insets. Polygons thinWalls = part.Insets[0].Offset(-extrusionWidth / 2).CreateDifference(part.Insets[1].Offset(extrusionWidth / 2)); topOutlines.AddAll(thinWalls); } if (layerIndex + 1 < storage.layers.Count) { topOutlines = RemoveAdditionalOutlinesForPart(storage.layers[layerIndex + 1], part, topOutlines); RemoveSmallAreas(extrusionWidth, topOutlines); } infillOutlines = infillOutlines.CreateDifference(topOutlines); infillOutlines = Clipper.CleanPolygons(infillOutlines, cleanDistance_um); part.SolidTopOutlines = topOutlines; } // calculate the solid infill outlines if (upLayerCount > 1 || downLayerCount > 1) { Polygons solidInfillOutlines = new Polygons(insetWithOffset); solidInfillOutlines = solidInfillOutlines.CreateDifference(part.SolidBottomOutlines); solidInfillOutlines = Clipper.CleanPolygons(solidInfillOutlines, cleanDistance_um); solidInfillOutlines = solidInfillOutlines.CreateDifference(part.SolidTopOutlines); solidInfillOutlines = Clipper.CleanPolygons(solidInfillOutlines, cleanDistance_um); int upEnd = layerIndex + upLayerCount + 1; if (upEnd <= storage.layers.Count && layerIndex - downLayerCount >= 0) { Polygons totalPartsToRemove = new Polygons(insetWithOffset); int upStart = layerIndex + 2; for (int layerToTest = upStart; layerToTest < upEnd; layerToTest++) { totalPartsToRemove = AddAllOutlines(storage.layers[layerToTest], part, totalPartsToRemove); totalPartsToRemove = Clipper.CleanPolygons(totalPartsToRemove, cleanDistance_um); } int downStart = layerIndex - 1; int downEnd = layerIndex - downLayerCount; for (int layerToTest = downStart; layerToTest >= downEnd; layerToTest--) { totalPartsToRemove = AddAllOutlines(storage.layers[layerToTest], part, totalPartsToRemove); totalPartsToRemove = Clipper.CleanPolygons(totalPartsToRemove, cleanDistance_um); } solidInfillOutlines = solidInfillOutlines.CreateDifference(totalPartsToRemove); RemoveSmallAreas(extrusionWidth, solidInfillOutlines); solidInfillOutlines = Clipper.CleanPolygons(solidInfillOutlines, cleanDistance_um); } part.SolidInfillOutlines = solidInfillOutlines; infillOutlines = infillOutlines.CreateDifference(solidInfillOutlines); } RemoveSmallAreas(extrusionWidth, infillOutlines); infillOutlines = Clipper.CleanPolygons(infillOutlines, cleanDistance_um); part.InfillOutlines = infillOutlines; } }
public void GenerateTopAndBottoms(int layerIndex, int extrusionWidth_um, int outerPerimeterWidth_um, int downLayerCount, int upLayerCount) { ExtruderLayers extruder = this; SliceLayer layer = extruder.Layers[layerIndex]; for (int islandIndex = 0; islandIndex < layer.Islands.Count; islandIndex++) { LayerIsland island = layer.Islands[islandIndex]; // this is the entire extrusion width to make sure we are outside of the extrusion line Polygons lastInset = island.InsetToolPaths[island.InsetToolPaths.Count - 1]; Polygons insetWithOffset = lastInset.Offset(-extrusionWidth_um); Polygons infillOutlines = new Polygons(insetWithOffset); // calculate the bottom outlines if (downLayerCount > 0) { Polygons bottomOutlines = new Polygons(insetWithOffset); if (layerIndex - 1 >= 0) { bottomOutlines = RemoveIslandsFromPolygons(extruder.Layers[layerIndex - 1].Islands, island.BoundingBox, bottomOutlines); bottomOutlines.RemoveSmallAreas(extrusionWidth_um); } infillOutlines = infillOutlines.CreateDifference(bottomOutlines); infillOutlines = Clipper.CleanPolygons(infillOutlines, cleanDistance_um); island.SolidBottomToolPaths = bottomOutlines; } // calculate the top outlines if (upLayerCount > 0) { Polygons topOutlines = new Polygons(insetWithOffset); topOutlines = topOutlines.CreateDifference(island.SolidBottomToolPaths); topOutlines = Clipper.CleanPolygons(topOutlines, cleanDistance_um); for (int insetIndex = 0; insetIndex < island.InsetToolPaths.Count - 1; insetIndex++) { // Add thin wall filling by taking the area between the insets. Polygons largerInset = island.InsetToolPaths[insetIndex].Offset(-extrusionWidth_um / 2); Polygons smallerInset = island.InsetToolPaths[insetIndex + 1].Offset(extrusionWidth_um / 2); Polygons thinWalls = largerInset.CreateDifference(smallerInset).Offset(-extrusionWidth_um/4); if (thinWalls.Count > 0) { topOutlines.AddAll(thinWalls); } } if (layerIndex + 1 < extruder.Layers.Count) { // Remove the top layer that is above this one to get only the data that is a top layer on this layer. topOutlines = RemoveIslandsFromPolygons(extruder.Layers[layerIndex + 1].Islands, island.BoundingBox, topOutlines); } topOutlines.RemoveSmallAreas(extrusionWidth_um); infillOutlines = infillOutlines.CreateDifference(topOutlines); infillOutlines = Clipper.CleanPolygons(infillOutlines, cleanDistance_um); island.SolidTopToolPaths = topOutlines; } // calculate the solid infill outlines if (upLayerCount > 1 || downLayerCount > 1) { Polygons solidInfillOutlines = new Polygons(insetWithOffset); solidInfillOutlines = solidInfillOutlines.CreateDifference(island.SolidBottomToolPaths); solidInfillOutlines = Clipper.CleanPolygons(solidInfillOutlines, cleanDistance_um); solidInfillOutlines = solidInfillOutlines.CreateDifference(island.SolidTopToolPaths); solidInfillOutlines = Clipper.CleanPolygons(solidInfillOutlines, cleanDistance_um); int upEnd = layerIndex + upLayerCount + 1; if (upEnd <= extruder.Layers.Count && layerIndex - downLayerCount >= 0) { Polygons totalPartsToRemove = new Polygons(insetWithOffset); int upStart = layerIndex + 2; for (int layerToTest = upStart; layerToTest < upEnd; layerToTest++) { totalPartsToRemove = AddIslandsToPolygons(extruder.Layers[layerToTest].Islands, island.BoundingBox, totalPartsToRemove); totalPartsToRemove = Clipper.CleanPolygons(totalPartsToRemove, cleanDistance_um); } int downStart = layerIndex - 1; int downEnd = layerIndex - downLayerCount; for (int layerToTest = downStart; layerToTest >= downEnd; layerToTest--) { totalPartsToRemove = AddIslandsToPolygons(extruder.Layers[layerToTest].Islands, island.BoundingBox, totalPartsToRemove); totalPartsToRemove = Clipper.CleanPolygons(totalPartsToRemove, cleanDistance_um); } solidInfillOutlines = solidInfillOutlines.CreateDifference(totalPartsToRemove); solidInfillOutlines.RemoveSmallAreas(extrusionWidth_um); solidInfillOutlines = Clipper.CleanPolygons(solidInfillOutlines, cleanDistance_um); } island.SolidInfillToolPaths = solidInfillOutlines; infillOutlines = infillOutlines.CreateDifference(solidInfillOutlines); } infillOutlines.RemoveSmallAreas(extrusionWidth_um); infillOutlines = Clipper.CleanPolygons(infillOutlines, cleanDistance_um); island.InfillToolPaths = infillOutlines; } }
private static Polygons RemoveIslandsFromPolygons(List<LayerIsland> islands, Aabb boundsToConsider, Polygons polygonsToSubtractFrom) { for (int islandIndex = 0; islandIndex < islands.Count; islandIndex++) { if (boundsToConsider.Hit(islands[islandIndex].BoundingBox)) { polygonsToSubtractFrom = polygonsToSubtractFrom.CreateDifference(islands[islandIndex].InsetToolPaths[islands[islandIndex].InsetToolPaths.Count - 1]); polygonsToSubtractFrom = Clipper.CleanPolygons(polygonsToSubtractFrom, cleanDistance_um); } } return polygonsToSubtractFrom; }
public void GenerateTopAndBottoms(ConfigSettings config, int layerIndex, int extrusionWidth_um, int outerPerimeterWidth_um, int downLayerCount, int upLayerCount, long infillExtendIntoPerimeter_um) { var clippingOffset = infillExtendIntoPerimeter_um * 2; ExtruderLayers extruder = this; SliceLayer layer = extruder.Layers[layerIndex]; for (int islandIndex = 0; islandIndex < layer.Islands.Count; islandIndex++) { LayerIsland island = layer.Islands[islandIndex]; if (island.InsetToolPaths.Count == 0) { continue; } // this is the entire extrusion width to make sure we are outside of the extrusion line Polygons lastInset = island.InsetToolPaths[island.InsetToolPaths.Count - 1]; Polygons infillRegionPath = lastInset.Offset(-extrusionWidth_um); Polygons sparseInfillPaths = new Polygons(infillRegionPath); // calculate the bottom outlines if (downLayerCount > 0) { Polygons bottomOutlines = new Polygons(infillRegionPath); if (layerIndex - 1 >= 0) { var previousLayer = extruder.Layers[layerIndex - 1]; bottomOutlines = RemoveIslandsFromPolygons(previousLayer.Islands, island.BoundingBox, bottomOutlines); bottomOutlines.RemoveSmallAreas(extrusionWidth_um); } sparseInfillPaths = sparseInfillPaths.CreateDifference(bottomOutlines); sparseInfillPaths = Clipper.CleanPolygons(sparseInfillPaths, cleanDistance_um); island.BottomPaths = bottomOutlines; } // calculate the top outlines if (upLayerCount > 0) { Polygons topOutlines = new Polygons(infillRegionPath); topOutlines = topOutlines.CreateDifference(island.BottomPaths.Offset(clippingOffset)); topOutlines = Clipper.CleanPolygons(topOutlines, cleanDistance_um); if (layerIndex + 1 < extruder.Layers.Count) { // Remove the top layer that is above this one to get only the data that is a top layer on this layer. topOutlines = RemoveIslandsFromPolygons(extruder.Layers[layerIndex + 1].Islands, island.BoundingBox, topOutlines); } topOutlines.RemoveSmallAreas(extrusionWidth_um); sparseInfillPaths = sparseInfillPaths.CreateDifference(topOutlines.Offset(clippingOffset)); sparseInfillPaths = Clipper.CleanPolygons(sparseInfillPaths, cleanDistance_um); island.TopPaths = topOutlines; } if (upLayerCount <= 0 && downLayerCount <= 0) { // Assign infill directly if no top/bottom solid layers island.SparseInfillPaths = sparseInfillPaths; } else { // calculate the solid infill outlines Polygons solidInfillPaths = new Polygons(infillRegionPath); // remove all the top layers solidInfillPaths = solidInfillPaths.CreateDifference(island.BottomPaths.Offset(clippingOffset)); solidInfillPaths = Clipper.CleanPolygons(solidInfillPaths, cleanDistance_um); // remove all the bottom layers solidInfillPaths = solidInfillPaths.CreateDifference(island.TopPaths.Offset(clippingOffset)); solidInfillPaths = Clipper.CleanPolygons(solidInfillPaths, cleanDistance_um); int upEnd = layerIndex + upLayerCount + 1; if (upEnd <= extruder.Layers.Count && layerIndex - downLayerCount >= 0) { // find all the regions that have more top and bottom layers than should be solid (will remain sparse) Polygons regionsThatWillBeSparse = new Polygons(infillRegionPath); int upStart = layerIndex + 2; for (int layerToTest = upStart; layerToTest < upEnd; layerToTest++) { regionsThatWillBeSparse = IntersectWithPolygons(extruder.Layers[layerToTest].Islands, island.BoundingBox, regionsThatWillBeSparse); regionsThatWillBeSparse = Clipper.CleanPolygons(regionsThatWillBeSparse, cleanDistance_um); } // find all the solid infill bottom layers int downStart = layerIndex - 1; int downEnd = layerIndex - downLayerCount; for (int layerToTest = downStart; layerToTest >= downEnd; layerToTest--) { regionsThatWillBeSparse = IntersectWithPolygons(extruder.Layers[layerToTest].Islands, island.BoundingBox, regionsThatWillBeSparse); regionsThatWillBeSparse = Clipper.CleanPolygons(regionsThatWillBeSparse, cleanDistance_um); } solidInfillPaths = solidInfillPaths.CreateDifference(regionsThatWillBeSparse); solidInfillPaths.RemoveSmallAreas(extrusionWidth_um); solidInfillPaths = Clipper.CleanPolygons(solidInfillPaths, cleanDistance_um); } // remove the solid infill from the sparse infill sparseInfillPaths = sparseInfillPaths.CreateDifference(solidInfillPaths.Offset(clippingOffset)); sparseInfillPaths.RemoveSmallAreas(extrusionWidth_um); sparseInfillPaths = Clipper.CleanPolygons(sparseInfillPaths, cleanDistance_um); island.SparseInfillPaths = sparseInfillPaths; if (config == null || // this is to make our tests test the bridgeOverInfill config.BridgeOverInfill) { // no figure out what partof the solid infill is actuall first top layers and switch it to that // we can only have a first topy layer at the bottom of the top layers if (layerIndex == extruder.Layers.Count - upLayerCount) { // all of it is first top layers island.FirstTopPaths = solidInfillPaths; solidInfillPaths = new Polygons(); } else if (layerIndex > 0 && layerIndex < extruder.Layers.Count - upLayerCount) { // Intersect the current solid layer with the previous spars layer // that will be all of the new solid layers that are currently on sparse layer var firstTopPaths = new Polygons(solidInfillPaths); firstTopPaths = IntersectWithSparsePolygons(extruder.Layers[layerIndex - 1].Islands, island.BoundingBox, firstTopPaths); firstTopPaths.RemoveSmallAreas(extrusionWidth_um); firstTopPaths = Clipper.CleanPolygons(firstTopPaths, cleanDistance_um); if (firstTopPaths.Count > 0) { solidInfillPaths = solidInfillPaths.CreateDifference(firstTopPaths.Offset(clippingOffset)); solidInfillPaths.RemoveSmallAreas(extrusionWidth_um); solidInfillPaths = Clipper.CleanPolygons(solidInfillPaths, cleanDistance_um); island.FirstTopPaths = firstTopPaths; } } } island.SolidInfillPaths = solidInfillPaths; } } }
public void GenerateTopAndBottoms(int layerIndex, int extrusionWidth_um, int outerPerimeterWidth_um, int downLayerCount, int upLayerCount) { ExtruderLayers extruder = this; SliceLayer layer = extruder.Layers[layerIndex]; for (int islandIndex = 0; islandIndex < layer.Islands.Count; islandIndex++) { LayerIsland island = layer.Islands[islandIndex]; // this is the entire extrusion width to make sure we are outside of the extrusion line Polygons lastInset = island.InsetToolPaths[island.InsetToolPaths.Count - 1]; Polygons insetWithOffset = lastInset.Offset(-extrusionWidth_um); Polygons infillOutlines = new Polygons(insetWithOffset); // calculate the bottom outlines if (downLayerCount > 0) { Polygons bottomOutlines = new Polygons(insetWithOffset); if (layerIndex - 1 >= 0) { bottomOutlines = RemoveIslandsFromPolygons(extruder.Layers[layerIndex - 1].Islands, island.BoundingBox, bottomOutlines); bottomOutlines.RemoveSmallAreas(extrusionWidth_um); } infillOutlines = infillOutlines.CreateDifference(bottomOutlines); infillOutlines = Clipper.CleanPolygons(infillOutlines, cleanDistance_um); island.SolidBottomToolPaths = bottomOutlines; } // calculate the top outlines if (upLayerCount > 0) { Polygons topOutlines = new Polygons(insetWithOffset); topOutlines = topOutlines.CreateDifference(island.SolidBottomToolPaths); topOutlines = Clipper.CleanPolygons(topOutlines, cleanDistance_um); for (int insetIndex = 0; insetIndex < island.InsetToolPaths.Count - 1; insetIndex++) { // Add thin wall filling by taking the area between the insets. Polygons largerInset = island.InsetToolPaths[insetIndex].Offset(-extrusionWidth_um / 2); Polygons smallerInset = island.InsetToolPaths[insetIndex + 1].Offset(extrusionWidth_um / 2); Polygons thinWalls = largerInset.CreateDifference(smallerInset).Offset(-extrusionWidth_um / 4); if (thinWalls.Count > 0) { topOutlines.AddAll(thinWalls); } } if (layerIndex + 1 < extruder.Layers.Count) { // Remove the top layer that is above this one to get only the data that is a top layer on this layer. topOutlines = RemoveIslandsFromPolygons(extruder.Layers[layerIndex + 1].Islands, island.BoundingBox, topOutlines); } topOutlines.RemoveSmallAreas(extrusionWidth_um); infillOutlines = infillOutlines.CreateDifference(topOutlines); infillOutlines = Clipper.CleanPolygons(infillOutlines, cleanDistance_um); island.SolidTopToolPaths = topOutlines; } // calculate the solid infill outlines if (upLayerCount > 1 || downLayerCount > 1) { Polygons solidInfillOutlines = new Polygons(insetWithOffset); solidInfillOutlines = solidInfillOutlines.CreateDifference(island.SolidBottomToolPaths); solidInfillOutlines = Clipper.CleanPolygons(solidInfillOutlines, cleanDistance_um); solidInfillOutlines = solidInfillOutlines.CreateDifference(island.SolidTopToolPaths); solidInfillOutlines = Clipper.CleanPolygons(solidInfillOutlines, cleanDistance_um); int upEnd = layerIndex + upLayerCount + 1; if (upEnd <= extruder.Layers.Count && layerIndex - downLayerCount >= 0) { Polygons totalPartsToRemove = new Polygons(insetWithOffset); int upStart = layerIndex + 2; for (int layerToTest = upStart; layerToTest < upEnd; layerToTest++) { totalPartsToRemove = AddIslandsToPolygons(extruder.Layers[layerToTest].Islands, island.BoundingBox, totalPartsToRemove); totalPartsToRemove = Clipper.CleanPolygons(totalPartsToRemove, cleanDistance_um); } int downStart = layerIndex - 1; int downEnd = layerIndex - downLayerCount; for (int layerToTest = downStart; layerToTest >= downEnd; layerToTest--) { totalPartsToRemove = AddIslandsToPolygons(extruder.Layers[layerToTest].Islands, island.BoundingBox, totalPartsToRemove); totalPartsToRemove = Clipper.CleanPolygons(totalPartsToRemove, cleanDistance_um); } solidInfillOutlines = solidInfillOutlines.CreateDifference(totalPartsToRemove); solidInfillOutlines.RemoveSmallAreas(extrusionWidth_um); solidInfillOutlines = Clipper.CleanPolygons(solidInfillOutlines, cleanDistance_um); } island.SolidInfillToolPaths = solidInfillOutlines; infillOutlines = infillOutlines.CreateDifference(solidInfillOutlines); } infillOutlines.RemoveSmallAreas(extrusionWidth_um); infillOutlines = Clipper.CleanPolygons(infillOutlines, cleanDistance_um); island.InfillToolPaths = infillOutlines; } }
public static void GenerateTopAndBottom(int layerIndex, SliceVolumeStorage storage, int extrusionWidth, ConfigSettings config) { var downLayerCount = config.numberOfBottomLayers; var upLayerCount = config.numberOfTopLayers; SliceLayer layer = storage.layers[layerIndex]; for (int partIndex = 0; partIndex < layer.parts.Count; partIndex++) { SliceLayerPart part = layer.parts[partIndex]; Polygons insetWithOffset = part.Insets[part.Insets.Count - 1].Offset(-extrusionWidth / 2); Polygons infillOutlines = new Polygons(insetWithOffset); // calculate the bottom outlines if (downLayerCount > 0) { Polygons bottomOutlines = new Polygons(insetWithOffset); if (layerIndex - 1 >= 0) { bottomOutlines = RemoveAdditionalOutlinesForPart(storage.layers[layerIndex - 1], part, bottomOutlines); RemoveSmallAreas(extrusionWidth, bottomOutlines); } infillOutlines = infillOutlines.CreateDifference(bottomOutlines); infillOutlines = Clipper.CleanPolygons(infillOutlines, cleanDistance_um); part.SolidBottomOutlines = bottomOutlines; } // calculate the top outlines if (upLayerCount > 0) { Polygons topOutlines = new Polygons(insetWithOffset); topOutlines = topOutlines.CreateDifference(part.SolidBottomOutlines); topOutlines = Clipper.CleanPolygons(topOutlines, cleanDistance_um); if (part.Insets.Count > 1) { // Add thin wall filling by taking the area between the insets. Polygons thinWalls = part.Insets[0].Offset(-extrusionWidth / 2).CreateDifference(part.Insets[1].Offset(extrusionWidth / 2)); topOutlines.AddAll(thinWalls); } if (layerIndex + 1 < storage.layers.Count) { topOutlines = RemoveAdditionalOutlinesForPart(storage.layers[layerIndex + 1], part, topOutlines); RemoveSmallAreas(extrusionWidth, topOutlines); } infillOutlines = infillOutlines.CreateDifference(topOutlines); infillOutlines = Clipper.CleanPolygons(infillOutlines, cleanDistance_um); part.SolidTopOutlines = topOutlines; } // calculate the solid infill outlines if (upLayerCount > 1 || downLayerCount > 1) { var solidInfillOutlines = new Polygons(insetWithOffset); solidInfillOutlines = solidInfillOutlines.CreateDifference(part.SolidBottomOutlines); solidInfillOutlines = Clipper.CleanPolygons(solidInfillOutlines, cleanDistance_um); solidInfillOutlines = solidInfillOutlines.CreateDifference(part.SolidTopOutlines); solidInfillOutlines = Clipper.CleanPolygons(solidInfillOutlines, cleanDistance_um); var upStart = layerIndex + 2; var upEnd = layerIndex + upLayerCount + 1; var downStart = layerIndex - 1; var downEnd = layerIndex - downLayerCount; if (upEnd <= storage.layers.Count && downEnd >= 0) { var makeInfillSolid = false; var totalPartsToRemove = new Polygons(insetWithOffset); for (var layerToTest = upStart; layerToTest < upEnd; layerToTest++) { totalPartsToRemove = AddAllOutlines(storage.layers[layerToTest], part, totalPartsToRemove, ref makeInfillSolid, config); totalPartsToRemove = Clipper.CleanPolygons(totalPartsToRemove, cleanDistance_um); if (makeInfillSolid) { break; } } for (var layerToTest = downStart; layerToTest >= downEnd; layerToTest--) { totalPartsToRemove = AddAllOutlines(storage.layers[layerToTest], part, totalPartsToRemove, ref makeInfillSolid, config); totalPartsToRemove = Clipper.CleanPolygons(totalPartsToRemove, cleanDistance_um); if (makeInfillSolid) { break; } } if (!makeInfillSolid) { solidInfillOutlines = solidInfillOutlines.CreateDifference(totalPartsToRemove); RemoveSmallAreas(extrusionWidth, solidInfillOutlines); } solidInfillOutlines = Clipper.CleanPolygons(solidInfillOutlines, cleanDistance_um); } part.SolidInfillOutlines = solidInfillOutlines; infillOutlines = infillOutlines.CreateDifference(solidInfillOutlines); Polygons totalInfillOutlines = null; double totalInfillArea = 0.0; if (config.infillSolidProportion > 0) { totalInfillOutlines = infillOutlines.CreateUnion(solidInfillOutlines); totalInfillArea = totalInfillOutlines.TotalArea(); } if (config.infillSolidProportion > 0) { var solidInfillArea = solidInfillOutlines.TotalArea(); if (solidInfillArea > totalInfillArea * config.infillSolidProportion) { solidInfillOutlines = solidInfillOutlines.CreateUnion(infillOutlines); infillOutlines = new Polygons(); part.SolidInfillOutlines = solidInfillOutlines; } var solidTopOutlinesArea = part.SolidTopOutlines.TotalArea(); if (totalInfillArea < solidTopOutlinesArea * config.infillSolidProportion / 2) { var totalSolidTop = totalInfillOutlines.CreateUnion(part.SolidTopOutlines); part.SolidTopOutlines = totalSolidTop; part.SolidInfillOutlines = new Polygons(); infillOutlines = part.InfillOutlines = new Polygons(); } var solidBottomOutlinesArea = part.SolidBottomOutlines.TotalArea(); if (totalInfillArea < solidBottomOutlinesArea * config.infillSolidProportion / 2) { var totalSolidBottom = totalInfillOutlines.CreateUnion(part.SolidBottomOutlines); part.SolidBottomOutlines = totalSolidBottom; part.SolidInfillOutlines = new Polygons(); infillOutlines = part.InfillOutlines = new Polygons(); } } if (config.minInfillArea_mm2 > 0) { var infillArea = infillOutlines.TotalArea() / 1e6; // convert from um2 to mm2 if (infillArea < config.minInfillArea_mm2) { solidInfillOutlines = solidInfillOutlines.CreateUnion(infillOutlines); infillOutlines = new Polygons(); part.SolidInfillOutlines = solidInfillOutlines; } } } RemoveSmallAreas(extrusionWidth, infillOutlines); infillOutlines = Clipper.CleanPolygons(infillOutlines, cleanDistance_um); part.InfillOutlines = infillOutlines; } }