public void Finalize(int maxObjectHeight, int moveSpeed, string endCode) { WriteFanCommand(0); WriteRetraction(); //返回原来位置 setZ(maxObjectHeight + 5000); WriteMove(GetPositionXY(), moveSpeed, 0); //WriteCode(endCode); //WriteComment("filament used = {0:0.0}".FormatWith(GetTotalFilamentUsed(0) + GetTotalFilamentUsed(1))); //WriteComment("filament used extruder 1 (mm) = {0:0.0}".FormatWith(GetTotalFilamentUsed(0))); //WriteComment("filament used extruder 2 (mm) = {0:0.0}".FormatWith(GetTotalFilamentUsed(1))); //WriteComment("total print time (s) = {0:0}".FormatWith(GetTotalPrintTime())); LogOutput.Log("Print time: {0}\n".FormatWith((int)(GetTotalPrintTime()))); LogOutput.Log("Filament: {0}\n".FormatWith((int)(GetTotalFilamentUsed(0)))); LogOutput.Log("Filament2: {0}\n".FormatWith((int)(GetTotalFilamentUsed(1)))); if (GetOutputType() == ConfigConstants.OUTPUT_TYPE.ULTIGCODE) { string numberString; numberString = "{0}".FormatWith((int)(GetTotalPrintTime())); //replaceTagInStart("<__TIME__>", numberString); numberString = "{0}".FormatWith((int)(GetTotalFilamentUsed(0))); //replaceTagInStart("<FILAMENT>", numberString); numberString = "{0}".FormatWith((int)(GetTotalFilamentUsed(1))); //replaceTagInStart("<FILAMEN2>", numberString); } }
public static void InitializeLayerPathing(ConfigSettings config, Polygons extraPathingConsideration, List <ExtruderLayers> extruders) { for (int layerIndex = 0; layerIndex < extruders[0].Layers.Count; layerIndex++) { if (MatterSlice.Canceled) { return; } LogOutput.Log("Generating Outlines {0}/{1}\n".FormatWith(layerIndex + 1, extruders[0].Layers.Count)); long avoidInset = config.ExtrusionWidth_um * 3 / 2; var allOutlines = new Polygons(); for (int extruderIndex = 0; extruderIndex < extruders.Count; extruderIndex++) { allOutlines.AddRange(extruders[extruderIndex].Layers[layerIndex].AllOutlines); } var boundary = allOutlines.GetBounds(); var extraBoundary = extraPathingConsideration.GetBounds(); boundary.ExpandToInclude(extraBoundary); boundary.Inflate(config.ExtrusionWidth_um * 10); var pathFinder = new Pathfinding.PathFinder(allOutlines, avoidInset, boundary, config.AvoidCrossingPerimeters); // assign the same pathing to all extruders for this layer for (int extruderIndex = 0; extruderIndex < extruders.Count; extruderIndex++) { extruders[extruderIndex].Layers[layerIndex].PathFinder = pathFinder; } } }
public void InitializeLayerData(ExtruderData slicer, ConfigSettings config, int extruderIndex, int extruderCount, Polygons extraPathingConsideration) { for (int layerIndex = 0; layerIndex < slicer.layers.Count; layerIndex++) { int start = slicer.layers.Count * extruderIndex; LogOutput.Log("Generating Layer Outlines {0}/{1}\n".FormatWith(start + layerIndex + 1, extruderCount * slicer.layers.Count)); if (config.outputOnlyFirstLayer && layerIndex > 0) { break; } Layers.Add(new SliceLayer()); Layers[layerIndex].LayerZ = slicer.layers[layerIndex].Z; Layers[layerIndex].AllOutlines = slicer.layers[layerIndex].PolygonList; Layers[layerIndex].AllOutlines = Layers[layerIndex].AllOutlines.GetCorrectedWinding(); long avoidInset = config.ExtrusionWidth_um * 3 / 2; var boundary = Layers[layerIndex].AllOutlines.GetBounds(); var extraBoundary = extraPathingConsideration.GetBounds(); boundary.ExpandToInclude(extraBoundary); boundary.Inflate(config.ExtrusionWidth_um * 10); Layers[layerIndex].PathFinder = new Pathfinding.PathFinder(Layers[layerIndex].AllOutlines, avoidInset, boundary); } }
public static int ProcessArgs(string[] args) { if (args.Length == 0) { print_usage(); return(0); } ConfigSettings config = new ConfigSettings(); fffProcessor processor = new fffProcessor(config); LogOutput.Log("\nMatterSlice version {0}\n\n".FormatWith(ConfigConstants.VERSION)); if (ProcessArgs(args, config, processor) == 0) { return(0); } if (!Canceled) { processor.DoProcessing(); } if (!Canceled) { processor.finalize(); } if (Canceled) { processor.Cancel(); } Canceled = true; return(0); }
public void Finalize(long maxObjectHeight, int moveSpeed, string endCode) { WriteFanCommand(0); WriteCode(endCode); WriteComment("filament used = {0:0.0}".FormatWith(GetTotalFilamentUsed(0) + GetTotalFilamentUsed(1))); WriteComment("filament used extruder 1 (mm) = {0:0.0}".FormatWith(GetTotalFilamentUsed(0))); WriteComment("filament used extruder 2 (mm) = {0:0.0}".FormatWith(GetTotalFilamentUsed(1))); WriteComment("total print time (s) = {0:0}".FormatWith(GetTotalPrintTime())); LogOutput.Log("Print time: {0}\n".FormatWith((int)(GetTotalPrintTime()))); LogOutput.Log("Filament: {0}\n".FormatWith((int)(GetTotalFilamentUsed(0)))); LogOutput.Log("Filament2: {0}\n".FormatWith((int)(GetTotalFilamentUsed(1)))); }
public bool LoadStlFile(string input_filename) { preSetup(config.extrusionWidth_um); timeKeeper.Restart(); LogOutput.Log("Loading {0} from disk...\n".FormatWith(input_filename)); if (!SimpleModel.loadModelFromFile(simpleModel, input_filename, config.modelRotationMatrix)) { LogOutput.LogError("Failed to load model: {0}\n".FormatWith(input_filename)); return false; } LogOutput.Log("Loaded from disk in {0:0.0}s\n".FormatWith(timeKeeper.Elapsed.Seconds)); return true; }
private void sliceModels(SliceDataStorage storage) { timeKeeper.Restart(); #if false optomizedModel.saveDebugSTL("debug_output.stl"); #endif LogOutput.Log("Slicing model...\n"); List<Slicer> slicerList = new List<Slicer>(); for (int volumeIndex = 0; volumeIndex < optomizedModel.volumes.Count; volumeIndex++) { Slicer slicer = new Slicer(optomizedModel.volumes[volumeIndex], config); slicerList.Add(slicer); } #if false slicerList[0].DumpSegmentsToGcode("Volume 0 Segments.gcode"); slicerList[0].DumpPolygonsToGcode("Volume 0 Polygons.gcode"); //slicerList[0].DumpPolygonsToHTML("Volume 0 Polygons.html"); #endif LogOutput.Log("Sliced model in {0:0.0}s\n".FormatWith(timeKeeper.Elapsed.Seconds)); timeKeeper.Restart(); LogOutput.Log("Generating support map...\n"); storage.support.GenerateSupportGrid(optomizedModel, config); storage.modelSize = optomizedModel.size_um; storage.modelMin = optomizedModel.minXYZ_um; storage.modelMax = optomizedModel.maxXYZ_um; LogOutput.Log("Generating layer parts...\n"); for (int volumeIndex = 0; volumeIndex < slicerList.Count; volumeIndex++) { storage.volumes.Add(new SliceVolumeStorage()); LayerPart.CreateLayerParts(storage.volumes[volumeIndex], slicerList[volumeIndex], config.repairOverlaps); if (config.enableRaft) { //Add the raft offset to each layer. for (int layerNr = 0; layerNr < storage.volumes[volumeIndex].layers.Count; layerNr++) { storage.volumes[volumeIndex].layers[layerNr].printZ += config.raftBaseThickness_um + config.raftInterfaceThicknes_um; } } } LogOutput.Log("Generated layer parts in {0:0.0}s\n".FormatWith(timeKeeper.Elapsed.Seconds)); timeKeeper.Restart(); }
public void TellFileSize() { double fsize = gcodeFileStream.BaseStream.Length; if (fsize > 1024 * 1024) { fsize /= 1024.0 * 1024.0; LogOutput.Log("Wrote {0:0.0} MB.\n".FormatWith(fsize)); } if (fsize > 1024) { fsize /= 1024.0; LogOutput.Log("Wrote {0:0.0} kilobytes.\n".FormatWith(fsize)); } }
public void DoProcessing() { if (!gcode.IsOpened()) { return; } timeKeeper.Restart(); LogOutput.Log("Analyzing and optimizing model...\n"); optomizedModel = new OptimizedModel(simpleModel); if (MatterSlice.Canceled) { return; } optomizedModel.SetPositionAndSize(simpleModel, config.positionToPlaceObjectCenter_um.X, config.positionToPlaceObjectCenter_um.Y, -config.bottomClipAmount_um, config.centerObjectInXy); for (int volumeIndex = 0; volumeIndex < simpleModel.volumes.Count; volumeIndex++) { LogOutput.Log(" Face counts: {0} . {1} {2:0.0}%\n".FormatWith((int)simpleModel.volumes[volumeIndex].faceTriangles.Count, (int)optomizedModel.volumes[volumeIndex].facesTriangle.Count, (double)(optomizedModel.volumes[volumeIndex].facesTriangle.Count) / (double)(simpleModel.volumes[volumeIndex].faceTriangles.Count) * 100)); LogOutput.Log(" Vertex counts: {0} . {1} {2:0.0}%\n".FormatWith((int)simpleModel.volumes[volumeIndex].faceTriangles.Count * 3, (int)optomizedModel.volumes[volumeIndex].vertices.Count, (double)(optomizedModel.volumes[volumeIndex].vertices.Count) / (double)(simpleModel.volumes[volumeIndex].faceTriangles.Count * 3) * 100)); } LogOutput.Log("Optimize model {0:0.0}s \n".FormatWith(timeKeeper.Elapsed.Seconds)); timeKeeper.Reset(); Stopwatch timeKeeperTotal = new Stopwatch(); timeKeeperTotal.Start(); preSetup(config.extrusionWidth_um); sliceModels(storage); processSliceData(storage); if (MatterSlice.Canceled) { return; } writeGCode(storage); if (MatterSlice.Canceled) { return; } LogOutput.logProgress("process", 1, 1); //Report to the GUI that a file has been fully processed. LogOutput.Log("Total time elapsed {0:0.00}s.\n".FormatWith(timeKeeperTotal.Elapsed.Seconds)); }
private void writeGCode(SliceDataStorage storage) { gcode.WriteComment("filamentDiameter = {0}".FormatWith(config.filamentDiameter)); gcode.WriteComment("extrusionWidth = {0}".FormatWith(config.extrusionWidth)); gcode.WriteComment("firstLayerExtrusionWidth = {0}".FormatWith(config.firstLayerExtrusionWidth)); gcode.WriteComment("layerThickness = {0}".FormatWith(config.layerThickness)); gcode.WriteComment("firstLayerThickness = {0}".FormatWith(config.firstLayerThickness)); if (fileNumber == 1) { if (gcode.GetOutputType() == ConfigConstants.OUTPUT_TYPE.ULTIGCODE) { gcode.WriteComment("TYPE:UltiGCode"); gcode.WriteComment("TIME:<__TIME__>"); gcode.WriteComment("MATERIAL:<FILAMENT>"); gcode.WriteComment("MATERIAL2:<FILAMEN2>"); } gcode.WriteCode(config.startCode); if (gcode.GetOutputType() == ConfigConstants.OUTPUT_TYPE.BFB) { gcode.WriteComment("enable auto-retraction"); gcode.WriteLine("M227 S{0} P{1}".FormatWith(config.retractionOnTravel * 2560, config.retractionOnTravel * 2560)); } } else { gcode.WriteFanCommand(0); gcode.ResetExtrusionValue(); gcode.WriteRetraction(); gcode.setZ(maxObjectHeight + 5000); gcode.WriteMove(gcode.GetPositionXY(), config.travelSpeed, 0); gcode.WriteMove(new IntPoint(storage.modelMin.x, storage.modelMin.y), config.travelSpeed, 0); } fileNumber++; int totalLayers = storage.volumes[0].layers.Count; // let's remove any of the layers on top that are empty { for (int layerIndex = totalLayers - 1; layerIndex >= 0; layerIndex--) { bool layerHasData = false; foreach (SliceVolumeStorage currentVolume in storage.volumes) { SliceLayer currentLayer = currentVolume.layers[layerIndex]; for (int partIndex = 0; partIndex < currentVolume.layers[layerIndex].parts.Count; partIndex++) { SliceLayerPart currentPart = currentLayer.parts[partIndex]; if (currentPart.TotalOutline.Count > 0) { layerHasData = true; break; } } } if (layerHasData) { break; } totalLayers--; } } gcode.WriteComment("Layer count: {0}".FormatWith(totalLayers)); // keep the raft generation code inside of raft Raft.GenerateRaftGCodeIfRequired(storage, config, gcode); int volumeIndex = 0; for (int layerIndex = 0; layerIndex < totalLayers; layerIndex++) { if (MatterSlice.Canceled) { return; } LogOutput.Log("Writing Layers {0}/{1}\n".FormatWith(layerIndex + 1, totalLayers)); LogOutput.logProgress("export", layerIndex + 1, totalLayers); int extrusionWidth_um = config.extrusionWidth_um; if (layerIndex == 0) { extrusionWidth_um = config.firstLayerExtrusionWidth_um; } if (layerIndex == 0) { skirtConfig.setData(config.firstLayerSpeed, extrusionWidth_um, "SKIRT"); inset0Config.setData(config.firstLayerSpeed, extrusionWidth_um, "WALL-OUTER"); insetXConfig.setData(config.firstLayerSpeed, extrusionWidth_um, "WALL-INNER"); fillConfig.setData(config.firstLayerSpeed, extrusionWidth_um, "FILL", false); bridgConfig.setData(config.firstLayerSpeed, extrusionWidth_um, "BRIDGE"); supportNormalConfig.setData(config.firstLayerSpeed, config.supportExtrusionWidth_um, "SUPPORT"); supportInterfaceConfig.setData(config.firstLayerSpeed, config.extrusionWidth_um, "SUPPORT-INTERFACE"); } else { skirtConfig.setData(config.insidePerimetersSpeed, extrusionWidth_um, "SKIRT"); inset0Config.setData(config.outsidePerimeterSpeed, extrusionWidth_um, "WALL-OUTER"); insetXConfig.setData(config.insidePerimetersSpeed, extrusionWidth_um, "WALL-INNER"); fillConfig.setData(config.infillSpeed, extrusionWidth_um, "FILL", false); bridgConfig.setData(config.bridgeSpeed, extrusionWidth_um, "BRIDGE"); supportNormalConfig.setData(config.supportMaterialSpeed, config.supportExtrusionWidth_um, "SUPPORT"); supportInterfaceConfig.setData(config.supportMaterialSpeed, config.extrusionWidth_um, "SUPPORT-INTERFACE"); } gcode.WriteComment("LAYER:{0}".FormatWith(layerIndex)); if (layerIndex == 0) { gcode.SetExtrusion(config.firstLayerThickness_um, config.filamentDiameter_um, config.extrusionMultiplier); } else { gcode.SetExtrusion(config.layerThickness_um, config.filamentDiameter_um, config.extrusionMultiplier); } GCodePlanner gcodeLayer = new GCodePlanner(gcode, config.travelSpeed, config.minimumTravelToCauseRetraction_um); // get the correct height for this layer int z = config.firstLayerThickness_um + layerIndex * config.layerThickness_um; if (config.enableRaft) { z += config.raftBaseThickness_um + config.raftInterfaceThicknes_um + config.raftSurfaceLayers * config.raftSurfaceThickness_um; if (layerIndex == 0) { // We only raise the first layer of the print up by the air gap. // To give it: // Less press into the raft // More time to cool // more surface area to air while extruding z += config.raftAirGap_um; } } gcode.setZ(z); // We only create the skirt if we are on layer 0 and the first volume and there is no raft. if (layerIndex == 0 && volumeIndex == 0 && !Raft.ShouldGenerateRaft(config)) { AddSkirtToGCode(storage, gcodeLayer, volumeIndex, layerIndex); } bool printSupportFirst = (storage.support.generated && config.supportExtruder >= 0 && config.supportExtruder == gcodeLayer.getExtruder()); if (printSupportFirst) { AddSupportToGCode(storage, gcodeLayer, layerIndex, config); } int fanSpeedPercent = GetFanSpeed(layerIndex, gcodeLayer); for (int volumeCnt = 0; volumeCnt < storage.volumes.Count; volumeCnt++) { if (volumeCnt > 0) { volumeIndex = (volumeIndex + 1) % storage.volumes.Count; } AddVolumeLayerToGCode(storage, gcodeLayer, volumeIndex, layerIndex, extrusionWidth_um, fanSpeedPercent); } if (!printSupportFirst) { AddSupportToGCode(storage, gcodeLayer, layerIndex, config); } //Finish the layer by applying speed corrections for minimum layer times. gcodeLayer.ForceMinimumLayerTime(config.minimumLayerTimeSeconds, config.minimumPrintingSpeed); gcode.WriteFanCommand(fanSpeedPercent); int currentLayerThickness_um = config.layerThickness_um; if (layerIndex <= 0) { currentLayerThickness_um = config.firstLayerThickness_um; } gcodeLayer.WriteGCode(config.doCoolHeadLift, currentLayerThickness_um); } LogOutput.Log("Wrote layers in {0:0.00}s.\n".FormatWith(timeKeeper.Elapsed.Seconds)); timeKeeper.Restart(); gcode.TellFileSize(); gcode.WriteFanCommand(0); //Store the object height for when we are printing multiple objects, as we need to clear every one of them when moving to the next position. maxObjectHeight = Math.Max(maxObjectHeight, storage.modelSize.z); }
private void processSliceData(SliceDataStorage storage) { if (config.continuousSpiralOuterPerimeter) { config.numberOfTopLayers = 0; config.infillPercent = 0; } MultiVolumes.RemoveVolumesIntersections(storage.volumes); MultiVolumes.OverlapMultipleVolumesSlightly(storage.volumes, config.multiVolumeOverlapPercent); #if False LayerPart.dumpLayerparts(storage, "output.html"); #endif int totalLayers = storage.volumes[0].layers.Count; #if DEBUG for (int volumeIndex = 1; volumeIndex < storage.volumes.Count; volumeIndex++) { if (totalLayers != storage.volumes[volumeIndex].layers.Count) { throw new Exception("All the valumes must have the same number of layers (they just can have empty layers)."); } } #endif for (int layerIndex = 0; layerIndex < totalLayers; layerIndex++) { for (int volumeIndex = 0; volumeIndex < storage.volumes.Count; volumeIndex++) { if (MatterSlice.Canceled) { return; } int insetCount = config.numberOfPerimeters; if (config.continuousSpiralOuterPerimeter && (int)(layerIndex) < config.numberOfBottomLayers && layerIndex % 2 == 1) { //Add extra insets every 2 layers when spiralizing, this makes bottoms of cups watertight. insetCount += 5; } SliceLayer layer = storage.volumes[volumeIndex].layers[layerIndex]; int extrusionWidth = config.extrusionWidth_um; if (layerIndex == 0) { extrusionWidth = config.firstLayerExtrusionWidth_um; } Inset.generateInsets(layer, extrusionWidth, insetCount); } LogOutput.Log("Creating Insets {0}/{1}\n".FormatWith(layerIndex + 1, totalLayers)); } if (config.wipeShieldDistanceFromShapes_um > 0) { CreateWipeShields(storage, totalLayers); } LogOutput.Log("Generated inset in {0:0.0}s\n".FormatWith(timeKeeper.Elapsed.Seconds)); timeKeeper.Restart(); for (int layerIndex = 0; layerIndex < totalLayers; layerIndex++) { if (MatterSlice.Canceled) { return; } //Only generate bottom and top layers and infill for the first X layers when spiralize is choosen. if (!config.continuousSpiralOuterPerimeter || (int)(layerIndex) < config.numberOfBottomLayers) { for (int volumeIndex = 0; volumeIndex < storage.volumes.Count; volumeIndex++) { int extrusionWidth = config.extrusionWidth_um; if (layerIndex == 0) { extrusionWidth = config.firstLayerExtrusionWidth_um; } TopsAndBottoms.GenerateTopAndBottom(layerIndex, storage.volumes[volumeIndex], extrusionWidth, config.numberOfBottomLayers, config.numberOfTopLayers); } } LogOutput.Log("Creating Top & Bottom Layers {0}/{1}\n".FormatWith(layerIndex + 1, totalLayers)); } LogOutput.Log("Generated top bottom layers in {0:0.0}s\n".FormatWith(timeKeeper.Elapsed.Seconds)); timeKeeper.Restart(); if (config.wipeTowerSize_um > 0) { Polygon p = new Polygon(); storage.wipeTower.Add(p); p.Add(new IntPoint(storage.modelMin.x - 3000, storage.modelMax.y + 3000)); p.Add(new IntPoint(storage.modelMin.x - 3000, storage.modelMax.y + 3000 + config.wipeTowerSize_um)); p.Add(new IntPoint(storage.modelMin.x - 3000 - config.wipeTowerSize_um, storage.modelMax.y + 3000 + config.wipeTowerSize_um)); p.Add(new IntPoint(storage.modelMin.x - 3000 - config.wipeTowerSize_um, storage.modelMax.y + 3000)); storage.wipePoint = new IntPoint(storage.modelMin.x - 3000 - config.wipeTowerSize_um / 2, storage.modelMax.y + 3000 + config.wipeTowerSize_um / 2); } if (config.enableRaft) { Raft.GenerateRaftOutlines(storage, config.raftExtraDistanceAroundPart_um, config); Skirt.generateSkirt(storage, config.skirtDistance_um + config.raftBaseLineSpacing_um, config.raftBaseLineSpacing_um, config.numberOfSkirtLoops, config.skirtMinLength_um, config.raftBaseThickness_um, config); } else { Skirt.generateSkirt(storage, config.skirtDistance_um, config.firstLayerExtrusionWidth_um, config.numberOfSkirtLoops, config.skirtMinLength_um, config.firstLayerThickness_um, config); } }
public static int ProcessArgs(string[] args) { if (args.Length == 0) { print_usage(); return(0); } ConfigSettings config = new ConfigSettings(); fffProcessor processor = new fffProcessor(config); LogOutput.Log("\nMatterSlice version {0}\n\n".FormatWith(ConfigConstants.VERSION)); for (int argn = 0; argn < args.Length; argn++) { string str = args[argn]; if (str[0] == '-') { for (int stringIndex = 1; stringIndex < str.Length; stringIndex++) { switch (str[stringIndex]) { case 'h': print_usage(); return(0); case 'v': LogOutput.verbose_level++; break; case 'o': argn++; if (!processor.SetTargetFile(args[argn])) { LogOutput.LogError("Failed to open {0} for output.\n".FormatWith(args[argn])); return(1); } break; case 'c': { // Read a config file from the given path argn++; if (!config.ReadSettings(args[argn])) { LogOutput.LogError("Failed to read config '{0}'\n".FormatWith(args[argn])); } } break; case 'd': config.DumpSettings("settings.ini"); break; case 's': { argn++; int equalsPos = args[argn].IndexOf('='); if (equalsPos != -1) { string key = args[argn].Substring(0, equalsPos); string value = args[argn].Substring(equalsPos + 1); if (key.Length > 1) { if (!config.SetSetting(key, value)) { LogOutput.LogError("Setting not found: {0} {1}\n".FormatWith(key, value)); } } } } break; case 'm': argn++; throw new NotImplementedException("m"); #if false sscanf(argv[argn], "%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf", &config.matrix.m[0][0], &config.matrix.m[0][1], &config.matrix.m[0][2], &config.matrix.m[1][0], &config.matrix.m[1][1], &config.matrix.m[1][2], &config.matrix.m[2][0], &config.matrix.m[2][1], &config.matrix.m[2][2]); #endif //break; default: throw new NotImplementedException("Unknown option: {0}\n".FormatWith(str)); //LogOutput.logError("Unknown option: {0}\n".FormatWith(str)); //break; } } } else { processor.LoadStlFile(args[argn]); } } if (!Canceled) { processor.DoProcessing(); } if (!Canceled) { processor.finalize(); } if (Canceled) { processor.Cancel(); } return(0); }
public ExtruderData(OptimizedMesh ov, ConfigSettings config) { int initialLayerThickness_um = config.FirstLayerThickness_um; int layerThickness_um = config.LayerThickness_um; modelSize = ov.containingCollection.size_um; modelMin = ov.containingCollection.minXYZ_um; long heightWithoutFirstLayer = modelSize.Z - initialLayerThickness_um + Math.Max(0, modelMin.Z); int countOfNormalThicknessLayers = Math.Max(0, (int)((heightWithoutFirstLayer / (double)layerThickness_um) + .5)); int layerCount = countOfNormalThicknessLayers; if (initialLayerThickness_um > 0) { // we have to add in the first layer (that is a different size) layerCount++; } if (config.outputOnlyFirstLayer) { layerCount = 1; } LogOutput.Log(string.Format("Layer count: {0}\n", layerCount)); layers.Capacity = layerCount; for (int layerIndex = 0; layerIndex < layerCount; layerIndex++) { long z; if (layerIndex == 0) { z = initialLayerThickness_um / 2; } else { z = initialLayerThickness_um + layerThickness_um / 2 + layerThickness_um * (layerIndex - 1); } layers.Add(new MeshProcessingLayer(z)); } for (int faceIndex = 0; faceIndex < ov.facesTriangle.Count; faceIndex++) { if (MatterSlice.Canceled) { return; } IntPoint p0 = ov.vertices[ov.facesTriangle[faceIndex].vertexIndex[0]].position; IntPoint p1 = ov.vertices[ov.facesTriangle[faceIndex].vertexIndex[1]].position; IntPoint p2 = ov.vertices[ov.facesTriangle[faceIndex].vertexIndex[2]].position; long minZ = p0.Z; long maxZ = p0.Z; if (p1.Z < minZ) { minZ = p1.Z; } if (p2.Z < minZ) { minZ = p2.Z; } if (p1.Z > maxZ) { maxZ = p1.Z; } if (p2.Z > maxZ) { maxZ = p2.Z; } for (int layerIndex = 0; layerIndex < layers.Count; layerIndex++) { long z = layers[layerIndex].Z; if (z < minZ || z > maxZ) { continue; } SlicePerimeterSegment polyCrossingAtThisZ; if (p0.Z < z && p1.Z >= z && p2.Z >= z) { // p1 p2 // -------- // p0 polyCrossingAtThisZ = GetCrossingAtZ(p0, p2, p1, z); } else if (p0.Z >= z && p1.Z < z && p2.Z < z) { // p0 // -------- // p1 p2 polyCrossingAtThisZ = GetCrossingAtZ(p0, p1, p2, z); } else if (p1.Z < z && p0.Z >= z && p2.Z >= z) { // p0 p2 // -------- // p1 polyCrossingAtThisZ = GetCrossingAtZ(p1, p0, p2, z); } else if (p1.Z >= z && p0.Z < z && p2.Z < z) { // p1 // -------- // p0 p2 polyCrossingAtThisZ = GetCrossingAtZ(p1, p2, p0, z); } else if (p2.Z < z && p1.Z >= z && p0.Z >= z) { // p1 p0 // -------- // p2 polyCrossingAtThisZ = GetCrossingAtZ(p2, p1, p0, z); } else if (p2.Z >= z && p1.Z < z && p0.Z < z) { // p2 // -------- // p1 p0 polyCrossingAtThisZ = GetCrossingAtZ(p2, p0, p1, z); } else { //Not all cases create a segment, because a point of a face could create just a dot, and two touching faces // on the slice would create two segments continue; } polyCrossingAtThisZ.hasBeenAddedToPolygon = false; layers[layerIndex].SegmentList.Add(polyCrossingAtThisZ); } } for (int layerIndex = 0; layerIndex < layers.Count; layerIndex++) { LogOutput.Log($"Slicing model {layerIndex + 1}/{layers.Count}\n"); layers[layerIndex].MakePolygons(); } }
public Slicer(OptimizedVolume ov, ConfigSettings config) { int initialLayerThickness_um = config.firstLayerThickness_um; int layerThickness_um = config.layerThickness_um; ConfigConstants.REPAIR_OUTLINES outlineRepairTypes = config.repairOutlines; modelSize = ov.parentModel.size_um; modelMin = ov.parentModel.minXYZ_um; int heightWithoutFirstLayer = modelSize.z - initialLayerThickness_um - config.bottomClipAmount_um; int countOfNormalThicknessLayers = Math.Max(0, (int)((heightWithoutFirstLayer / (double)layerThickness_um) + .5)); int layerCount = countOfNormalThicknessLayers; if (initialLayerThickness_um > 0) { // we have to add in the first layer (that is a differnt size) layerCount++; } LogOutput.Log(string.Format("Layer count: {0}\n", layerCount)); layers.Capacity = layerCount; for (int layerIndex = 0; layerIndex < layerCount; layerIndex++) { int z; if (layerIndex == 0) { z = initialLayerThickness_um / 2; } else { z = initialLayerThickness_um + layerThickness_um / 2 + layerThickness_um * (layerIndex - 1); } layers.Add(new SlicerLayer(z)); } for (int faceIndex = 0; faceIndex < ov.facesTriangle.Count; faceIndex++) { Point3 p0 = ov.vertices[ov.facesTriangle[faceIndex].vertexIndex[0]].position; Point3 p1 = ov.vertices[ov.facesTriangle[faceIndex].vertexIndex[1]].position; Point3 p2 = ov.vertices[ov.facesTriangle[faceIndex].vertexIndex[2]].position; int minZ = p0.z; int maxZ = p0.z; if (p1.z < minZ) { minZ = p1.z; } if (p2.z < minZ) { minZ = p2.z; } if (p1.z > maxZ) { maxZ = p1.z; } if (p2.z > maxZ) { maxZ = p2.z; } for (int layerIndex = 0; layerIndex < layers.Count; layerIndex++) { int z = layers[layerIndex].Z; if (z < minZ || z > maxZ) { continue; } SlicerSegment polyCrossingAtThisZ; if (p0.z < z && p1.z >= z && p2.z >= z) { // p1 p2 // -------- // p0 polyCrossingAtThisZ = GetCrossingAtZ(p0, p2, p1, z); } else if (p0.z >= z && p1.z < z && p2.z < z) { // p0 // -------- // p1 p2 polyCrossingAtThisZ = GetCrossingAtZ(p0, p1, p2, z); } else if (p1.z < z && p0.z >= z && p2.z >= z) { // p0 p2 // -------- // p1 polyCrossingAtThisZ = GetCrossingAtZ(p1, p0, p2, z); } else if (p1.z >= z && p0.z < z && p2.z < z) { // p1 // -------- // p0 p2 polyCrossingAtThisZ = GetCrossingAtZ(p1, p2, p0, z); } else if (p2.z < z && p1.z >= z && p0.z >= z) { // p1 p0 // -------- // p2 polyCrossingAtThisZ = GetCrossingAtZ(p2, p1, p0, z); } else if (p2.z >= z && p1.z < z && p0.z < z) { // p2 // -------- // p1 p0 polyCrossingAtThisZ = GetCrossingAtZ(p2, p0, p1, z); } else { //Not all cases create a segment, because a point of a face could create just a dot, and two touching faces // on the slice would create two segments continue; } polyCrossingAtThisZ.hasBeenAddedToPolygon = false; layers[layerIndex].SegmentList.Add(polyCrossingAtThisZ); } } for (int layerIndex = 0; layerIndex < layers.Count; layerIndex++) { layers[layerIndex].MakePolygons(outlineRepairTypes); } }