public NewSupport(ConfigSettings config, List <ExtruderLayers> Extruders, ExtruderLayers userGeneratedSupport, long grabDistance_um) { cleanDistance_um = config.ExtrusionWidth_um / 10; long supportWidth_um = (long)(config.ExtrusionWidth_um * (100 - config.SupportPercent) / 100); // create starting support outlines List <Polygons> allPartOutlines = CalculateAllPartOutlines(config, Extruders); _InsetPartOutlines = CreateInsetPartOutlines(allPartOutlines, config.ExtrusionWidth_um / 2); int numSupportLayers = userGeneratedSupport.Layers.Count; SparseSupportOutlines = CreateEmptyPolygons(numSupportLayers); // calculate the combined outlines for everything for (int layerIndex = 0; layerIndex < numSupportLayers; layerIndex++) { SparseSupportOutlines[layerIndex] = userGeneratedSupport.Layers[layerIndex].AllOutlines.DeepCopy(); } SparseSupportOutlines = ExpandToEasyGrabDistance(SparseSupportOutlines, grabDistance_um - supportWidth_um); // remove the actual parts from the support data SparseSupportOutlines = ClipToXyDistance(SparseSupportOutlines, _InsetPartOutlines, config); // create the interface layers InterfaceLayers = CreateInterfaceLayers(SparseSupportOutlines, config.SupportInterfaceLayers); // and the bottom support layers AirGappedBottomOutlines = CreateAirGappedBottomLayers(SparseSupportOutlines, _InsetPartOutlines); // remove the interface layers from the normal support layers SparseSupportOutlines = CalculateDifferencePerLayer(SparseSupportOutlines, InterfaceLayers); // remove the airGappedBottomOutlines layers from the normal support layers SparseSupportOutlines = CalculateDifferencePerLayer(SparseSupportOutlines, AirGappedBottomOutlines); }
public SupportLayers(ConfigSettings config, List <ExtruderLayers> extruders, ExtruderLayers userGeneratedSupport) { cleanDistance_um = config.ExtrusionWidth_um / 10; // create starting support outlines List <Polygons> allPartOutlines = CalculateAllPartOutlines(config, extruders); _InsetPartOutlines = CreateInsetPartOutlines(allPartOutlines, config.ExtrusionWidth_um / 2); if (userGeneratedSupport == null) { long supportWidth_um = (long)(config.ExtrusionWidth_um * (100 - config.SupportPercent) / 100); _AllUnsupportedAreas = FindAllUnsupportedAreas(_InsetPartOutlines, supportWidth_um); _RequiredSupportAreas = RemoveSelfSupportedAreas(_AllUnsupportedAreas, supportWidth_um); if (!config.GenerateInternalSupport) { _RequiredSupportAreas = RemoveSupportFromInternalSpaces(_RequiredSupportAreas, _InsetPartOutlines); } SparseSupportOutlines = AccumulateDownPolygons(config, _RequiredSupportAreas, _InsetPartOutlines); SparseSupportOutlines = ExpandToEasyGrabDistance(SparseSupportOutlines, config.SupportGrabDistance_um - supportWidth_um); } else { int numSupportLayers = userGeneratedSupport.Layers.Count; SparseSupportOutlines = CreateEmptyPolygons(numSupportLayers); // calculate the combined outlines for everything for (int layerIndex = 0; layerIndex < numSupportLayers; layerIndex++) { SparseSupportOutlines[layerIndex] = userGeneratedSupport.Layers[layerIndex].AllOutlines.DeepCopy(); } } // remove the actual parts from the support data SparseSupportOutlines = ClipToXyDistance(SparseSupportOutlines, _InsetPartOutlines, config); // create the interface layers InterfaceLayers = CreateInterfaceLayers(SparseSupportOutlines, config.SupportInterfaceLayers); // and the bottom support layers AirGappedBottomOutlines = CreateAirGappedBottomLayers(SparseSupportOutlines, _InsetPartOutlines); // remove the interface layers from the normal support layers SparseSupportOutlines = CalculateDifferencePerLayer(SparseSupportOutlines, InterfaceLayers); // remove the airGappedBottomOutlines layers from the normal support layers SparseSupportOutlines = CalculateDifferencePerLayer(SparseSupportOutlines, AirGappedBottomOutlines); // make sure we don't print an interface layer where there is a bottom layer InterfaceLayers = CalculateDifferencePerLayer(InterfaceLayers, AirGappedBottomOutlines); }
public void CreateWipeTower(int totalLayers, ConfigSettings config, ExtruderLayers wipeTowerLayers) { if (wipeTowerLayers != null && wipeTowerLayers.Layers.Count > 0 && wipeTowerLayers.Layers[0].AllOutlines.Count > 0) { for (int i = 0; i < wipeTowerLayers.Layers.Count; i++) { var layer = wipeTowerLayers.Layers[i]; if (layer.AllOutlines.PolygonLength() > 0) { this.WipeTower.Add(layer.AllOutlines); } else { this.WipeTower.Add(this.WipeTower[i - 1]); } } } else if (config.WipeTowerSize_um < 1 || LastLayerWithChange(config) == -1) { return; } else { var wipeTowerShape = new Polygon(); var size = config.WipeTowerSize_um; WipeCenter_um = new IntPoint(this.modelMin.X - 3000 - size / 2, this.modelMax.Y + 3000 + size / 2); var points = 100; for (int i = 0; i < points; i++) { var angle = Math.PI * 2 * i / points; wipeTowerShape.Add(WipeCenter_um + new IntPoint(Math.Cos(angle) * size / 2, Math.Sin(angle) * size / 2)); } this.WipeTower.Add(new Polygons() { wipeTowerShape }); } var wipeTowerBounds = this.WipeTower[0].GetBounds(); WipeCenter_um = new IntPoint( wipeTowerBounds.minX + (wipeTowerBounds.maxX - wipeTowerBounds.minX) / 2, wipeTowerBounds.minY + (wipeTowerBounds.maxY - wipeTowerBounds.minY) / 2); }
public void GenerateTopAndBottoms(ConfigSettings config, int layerIndex, long extrusionWidth_um, long outerPerimeterWidth_um, int downLayerCount, int upLayerCount, long infillExtendIntoPerimeter_um) { var clippingOffset = infillExtendIntoPerimeter_um * 2; ExtruderLayers extruder = this; SliceLayer layer = extruder.Layers[layerIndex]; Agg.Parallel.For(0, layer.Islands.Count, (islandIndex) => // for (int islandIndex = 0; islandIndex < layer.Islands.Count; islandIndex++) { LayerIsland island = layer.Islands[islandIndex]; if (island.InsetToolPaths.Count == 0) { return; } // 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; Agg.Parallel.For(upStart, upEnd, (layerToTest) => // 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 = Math.Max(0, layerIndex - 1); int downEnd = Math.Max(0, layerIndex - downLayerCount); Agg.Parallel.For(downStart, downEnd, (layerToTest) => // 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) { // now figure out what part of the solid infill is actually first top layers and switch it to that // we can only have a first top y 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; } }
private static ExtruderLayers CreateLayerData(List<Polygons> totalLayerOutlines) { int numLayers = totalLayerOutlines.Count; ExtruderLayers layerData = new ExtruderLayers(); layerData.Layers = new List<SliceLayer>(); for (int layerIndex = 0; layerIndex < numLayers; layerIndex++) { SliceLayer layer = new SliceLayer(); layer.AllOutlines = totalLayerOutlines[layerIndex]; layerData.Layers.Add(layer); } return layerData; }