Revise slicing to run as async tasks

- MatterHackers/MCCentral#1308
Change slicing thread system to run as async method
- MatterHackers/MCCentral#1941
Selecting 'Print' then viewing gcode does not show any gcode
This commit is contained in:
John Lewin 2017-10-16 17:09:00 -07:00
parent 306a0320fe
commit fe6e93acef
14 changed files with 95 additions and 267 deletions

View file

@ -28,13 +28,10 @@ either expressed or implied, of the FreeBSD Project.
*/
using System;
using MatterHackers.Agg;
using MatterHackers.Agg.Platform;
using MatterHackers.Agg.UI;
using MatterHackers.Localizations;
using MatterHackers.MatterControl.PrinterCommunication;
using MatterHackers.MatterControl.SlicerConfiguration;
using MatterHackers.SerialPortCommunication.FrostedSerial;
namespace MatterHackers.MatterControl.ActionBar
{

View file

@ -1054,7 +1054,7 @@ namespace MatterHackers.MatterControl
private string doNotAskAgainMessage = "Don't remind me again".Localize();
public async void PrintPart(PrintItemWrapper printItem, bool overrideAllowGCode = false)
public async void PrintPart(PrintItemWrapper printItem, PrinterConfig printer, View3DWidget view3DWidget, SliceProgressReporter reporter, bool overrideAllowGCode = false)
{
try
{
@ -1091,10 +1091,12 @@ namespace MatterHackers.MatterControl
&& hideGCodeWarning == null
&& !overrideAllowGCode)
{
CheckBox hideGCodeWarningCheckBox = new CheckBox(doNotAskAgainMessage);
hideGCodeWarningCheckBox.TextColor = ActiveTheme.Instance.PrimaryTextColor;
hideGCodeWarningCheckBox.Margin = new BorderDouble(top: 6, left: 6);
hideGCodeWarningCheckBox.HAnchor = Agg.UI.HAnchor.Left;
var hideGCodeWarningCheckBox = new CheckBox(doNotAskAgainMessage)
{
TextColor = ActiveTheme.Instance.PrimaryTextColor,
Margin = new BorderDouble(top: 6, left: 6),
HAnchor = Agg.UI.HAnchor.Left
};
hideGCodeWarningCheckBox.Click += (sender, e) =>
{
if (hideGCodeWarningCheckBox.Checked)
@ -1110,17 +1112,15 @@ namespace MatterHackers.MatterControl
UiThread.RunOnIdle(() =>
{
StyledMessageBox.ShowMessageBox(
(bool messageBoxResponse) =>
async (messageBoxResponse) =>
{
if (messageBoxResponse)
{
this.ActivePrinter.Connection.CommunicationState = CommunicationStates.PreparingToPrint;
PrintItemWrapper partToPrint = printItem;
SlicingQueue.Instance.QueuePartForSlicing(partToPrint);
partToPrint.SlicingDone += partToPrint_SliceDone;
partToPrint_SliceDone(printItem);
}
},
gcodeWarningMessage,
"The file you are attempting to print is a GCode file.\n\nIt is recommended that you only print Gcode files known to match your printer's configuration.\n\nAre you sure you want to print this GCode file?".Localize(),
"Warning - GCode file".Localize(),
new GuiWidget[]
{
@ -1134,9 +1134,14 @@ namespace MatterHackers.MatterControl
else
{
this.ActivePrinter.Connection.CommunicationState = CommunicationStates.PreparingToPrint;
PrintItemWrapper partToPrint = printItem;
SlicingQueue.Instance.QueuePartForSlicing(partToPrint);
partToPrint.SlicingDone += partToPrint_SliceDone;
await ApplicationController.Instance.SliceFileLoadOutput(
printer,
printItem,
view3DWidget,
reporter);
partToPrint_SliceDone(printItem);
}
}
}
@ -1147,23 +1152,19 @@ namespace MatterHackers.MatterControl
}
}
private string gcodeWarningMessage = "The file you are attempting to print is a GCode file.\n\nIt is recommended that you only print Gcode files known to match your printer's configuration.\n\nAre you sure you want to print this GCode file?".Localize();
public void PrintActivePartIfPossible(PrintItemWrapper printItem, bool overrideAllowGCode = false)
{
if (this.ActivePrinter.Connection.CommunicationState == CommunicationStates.Connected
|| this.ActivePrinter.Connection.CommunicationState == CommunicationStates.FinishedPrint)
{
PrintPart(printItem, overrideAllowGCode);
//PrintPart(printItem, overrideAllowGCode);
}
}
private void partToPrint_SliceDone(object sender, EventArgs e)
private void partToPrint_SliceDone(PrintItemWrapper partToPrint)
{
PrintItemWrapper partToPrint = sender as PrintItemWrapper;
if (partToPrint != null)
{
partToPrint.SlicingDone -= partToPrint_SliceDone;
string gcodePathAndFileName = partToPrint.GetGCodePathAndFileName();
if (gcodePathAndFileName != "")
{
@ -1220,6 +1221,25 @@ namespace MatterHackers.MatterControl
}
}
public async Task SliceFileLoadOutput(PrinterConfig printer, PrintItemWrapper printItem, View3DWidget view3DWidget, SliceProgressReporter reporter)
{
var gcodeLoadCancellationTokenSource = new CancellationTokenSource();
// Save any pending changes
await view3DWidget.PersistPlateIfNeeded();
// Slice
reporter?.StartReporting();
await Slicer.SliceFileAsync(printItem, reporter);
reporter?.EndReporting();
// Load
printer.Bed.LoadGCode(
printItem.GetGCodePathAndFileName(),
gcodeLoadCancellationTokenSource.Token,
view3DWidget.gcodeViewer.LoadProgress_Changed);
}
public class CloudSyncEventArgs : EventArgs
{
public bool IsAuthenticated { get; set; }

View file

@ -128,7 +128,7 @@ namespace MatterHackers.MatterControl.Library.Export
var printItem = ApplicationController.Instance.ActivePrinter.Bed.printItem;
// - Slice
await SlicingQueue.SliceFileAsync(printItem, null);
await Slicer.SliceFileAsync(printItem, null);
// - Return
fileToProcess = printItem.GetGCodePathAndFileName();

View file

@ -394,7 +394,6 @@ namespace MatterHackers.MatterControl
}
//Close connection to the local datastore
ApplicationController.Instance.ActivePrinter.Connection.HaltConnectionThread();
SlicingQueue.Instance.ShutDownSlicingThread();
ApplicationController.Instance.OnApplicationClosed();
Datastore.Instance.Exit();

View file

@ -85,6 +85,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
View3DWidget.AutoRotate.Disabled,
viewControls3D,
theme,
this,
editorType: (isPrinterType) ? MeshViewerWidget.EditorType.Printer : MeshViewerWidget.EditorType.Part);
topToBottom = new FlowLayoutWidget(FlowDirection.TopToBottom);

View file

@ -69,11 +69,13 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
private CancellationTokenSource gcodeLoadCancellationTokenSource;
private FlowLayoutWidget dynamicPanel;
private PrinterTabPage printerTabPage;
public PrinterActionsBar(PrinterConfig printer, PrinterTabPage printerTabPage, ThemeConfig theme)
{
this.printer = printer;
this.printerTabPage = printerTabPage;
this.HAnchor = HAnchor.Stretch;
this.VAnchor = VAnchor.Fit;
@ -274,8 +276,14 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
startPrintButton.Margin = defaultMargin;
startPrintButton.Click += (s, e) =>
{
UiThread.RunOnIdle(() =>
UiThread.RunOnIdle(async () =>
{
await ApplicationController.Instance.SliceFileLoadOutput(
printer,
printer.Bed.printItem,
printerTabPage.view3DWidget,
null);
ApplicationController.Instance.PrintActivePartIfPossible(printer.Bed.printItem);
});
};

View file

@ -37,6 +37,7 @@ using MatterHackers.Agg.UI;
using MatterHackers.GCodeVisualizer;
using MatterHackers.Localizations;
using MatterHackers.MatterControl.CustomWidgets;
using MatterHackers.MatterControl.PrintQueue;
using MatterHackers.MatterControl.SlicerConfiguration;
namespace MatterHackers.MatterControl.PartPreviewWindow
@ -118,32 +119,17 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
if (printer.Settings.PrinterSelected)
{
var printItem = printer.Bed.printItem;
if (printer.Settings.IsValid() && printItem != null)
if (printer.Settings.IsValid() && printer.Bed.printItem != null)
{
activelySlicing = true;
try
{
var sliceProgressReporter = new SliceProgressReporter(this.PopupContent, printer);
sliceProgressReporter.StartReporting();
// Save any pending changes before starting the print
await printerTabPage.view3DWidget.PersistPlateIfNeeded();
await SlicingQueue.SliceFileAsync(printItem, sliceProgressReporter);
sliceProgressReporter.EndReporting();
var gcodeLoadCancellationTokenSource = new CancellationTokenSource();
this.printer.Bed.LoadGCode(printItem.GetGCodePathAndFileName(), gcodeLoadCancellationTokenSource.Token, printerTabPage.view3DWidget.gcodeViewer.LoadProgress_Changed);
printerTabPage.ViewMode = PartViewMode.Layers3D;
// HACK: directly fire method which previously ran on SlicingDone event on PrintItemWrapper
UiThread.RunOnIdle(() => printerTabPage.view3DWidget.gcodeViewer.CreateAndAddChildren(printer));
await ApplicationController.Instance.SliceFileLoadOutput(
printer,
printer.Bed.printItem,
printerTabPage.view3DWidget,
new SliceProgressReporter(this.PopupContent, printer));
}
catch (Exception ex)
{

View file

@ -102,12 +102,18 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
private BedConfig sceneContext;
public View3DWidget(PrinterConfig printer, BedConfig sceneContext, AutoRotate autoRotate, ViewControls3D viewControls3D, ThemeConfig theme, MeshViewerWidget.EditorType editorType = MeshViewerWidget.EditorType.Part)
private PrinterConfig printer;
private PrinterTabBase printerTabBase;
public View3DWidget(PrinterConfig printer, BedConfig sceneContext, AutoRotate autoRotate, ViewControls3D viewControls3D, ThemeConfig theme, PrinterTabBase printerTabBase, MeshViewerWidget.EditorType editorType = MeshViewerWidget.EditorType.Part)
{
var smallMarginButtonFactory = theme.SmallMarginButtonFactory;
this.sceneContext = sceneContext;
this.printerTabBase = printerTabBase;
this.Scene = sceneContext.Scene;
this.printer = printer;
this.TrackballTumbleWidget = new TrackballTumbleWidget(sceneContext.World)
{
@ -507,11 +513,25 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
meshViewerWidget.AfterDraw += AfterDraw3DContent;
sceneContext.LoadedGCodeChanged += SceneContext_LoadedGCodeChanged;
this.SwitchStateToEditing();
this.InteractionLayer.DrawGlOpaqueContent += Draw_GlOpaqueContent;
}
private void SceneContext_LoadedGCodeChanged(object sender, EventArgs e)
{
if (printerTabBase is PrinterTabPage printerTabPage)
{
// When GCode changes, switch to the 3D layer view
printerTabPage.ViewMode = PartViewMode.Layers3D;
// HACK: directly fire method which previously ran on SlicingDone event on PrintItemWrapper
UiThread.RunOnIdle(() => printerTabPage.view3DWidget.gcodeViewer.CreateAndAddChildren(printer));
}
}
private GuiWidget CreateActionSeparator()
{
return new VerticalLine(60)
@ -781,6 +801,8 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
// Not needed but safer than without
viewControls3D.TransformStateChanged -= ViewControls3D_TransformStateChanged;
sceneContext.LoadedGCodeChanged -= SceneContext_LoadedGCodeChanged;
if (meshViewerWidget != null)
{
meshViewerWidget.AfterDraw -= AfterDraw3DContent;

View file

@ -1988,7 +1988,6 @@ namespace MatterHackers.MatterControl.PrinterCommunication
break;
case CommunicationStates.PreparingToPrint:
SlicingQueue.Instance.CancelCurrentSlicing();
CommunicationState = CommunicationStates.Connected;
break;
}

View file

@ -46,8 +46,6 @@ namespace MatterHackers.MatterControl.PrintQueue
private List<PrintItem> allFilesToExport;
private List<string> savedGCodeFileNames;
public event EventHandler UpdatePartStatus;
public event EventHandler<StringEventArgs> StartingNextPart;
public event EventHandler DoneSaving;
@ -105,9 +103,11 @@ namespace MatterHackers.MatterControl.PrintQueue
string extension = Path.GetExtension(printItemWrapper.FileLocation).ToUpper();
if ((extension != "" && MeshFileIo.ValidFileExtensions().Contains(extension)))
{
SlicingQueue.Instance.QueuePartForSlicing(printItemWrapper);
printItemWrapper.SlicingDone += sliceItem_Done;
printItemWrapper.SlicingOutputMessage += printItemWrapper_SlicingOutputMessage;
Slicer.SliceFileAsync(printItemWrapper, null).ContinueWith((task) =>
{
Console.WriteLine("Part Slicing Completed");
});
}
else if (Path.GetExtension(printItemWrapper.FileLocation).ToUpper() == ".GCODE")
{
@ -117,21 +117,11 @@ namespace MatterHackers.MatterControl.PrintQueue
}
}
private void printItemWrapper_SlicingOutputMessage(object sender, EventArgs e)
{
StringEventArgs message = (StringEventArgs)e;
if (UpdatePartStatus != null)
{
UpdatePartStatus(this, message);
}
}
private void sliceItem_Done(object sender, EventArgs e)
{
PrintItemWrapper sliceItem = (PrintItemWrapper)sender;
sliceItem.SlicingDone -= sliceItem_Done;
sliceItem.SlicingOutputMessage -= printItemWrapper_SlicingOutputMessage;
if (File.Exists(sliceItem.FileLocation))
{
@ -141,17 +131,11 @@ namespace MatterHackers.MatterControl.PrintQueue
itemCountBeingWorkedOn++;
if (itemCountBeingWorkedOn < allFilesToExport.Count)
{
if (StartingNextPart != null)
{
StartingNextPart(this, new StringEventArgs(ItemNameBeingWorkedOn));
}
StartingNextPart?.Invoke(this, new StringEventArgs(ItemNameBeingWorkedOn));
}
else
{
if (UpdatePartStatus != null)
{
UpdatePartStatus(this, new StringEventArgs("Calculating Total filament mm..."));
}
//UpdatePartStatus(this, new StringEventArgs("Calculating Total filament mm..."));
if (savedGCodeFileNames.Count > 0)
{

View file

@ -68,7 +68,6 @@ namespace MatterHackers.MatterControl.PrintQueue
public class PrintItemWrapper
{
public event EventHandler SlicingDone;
public event EventHandler<StringEventArgs> SlicingOutputMessage;
private string fileNotFound = "File Not Found\n'{0}'".Localize();
private string readyToPrint = "Ready to Print".Localize();
@ -271,7 +270,6 @@ namespace MatterHackers.MatterControl.PrintQueue
public void OnSlicingOutputMessage(EventArgs e)
{
SlicingOutputMessage?.Invoke(this, e as StringEventArgs);
}
}
}

View file

@ -244,14 +244,14 @@ namespace MatterHackers.MatterControl.SlicerConfiguration
get
{
StringBuilder newStartGCode = new StringBuilder();
foreach (string line in PreStartGCode(SlicingQueue.extrudersUsed))
foreach (string line in PreStartGCode(Slicer.extrudersUsed))
{
newStartGCode.Append(line + "\n");
}
newStartGCode.Append(GCodeProcessing.ReplaceMacroValues(base.Value));
foreach (string line in PostStartGCode(SlicingQueue.extrudersUsed))
foreach (string line in PostStartGCode(Slicer.extrudersUsed))
{
newStartGCode.Append("\n");
newStartGCode.Append(line);

View file

@ -30,7 +30,6 @@ either expressed or implied, of the FreeBSD Project.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
@ -38,78 +37,21 @@ using MatterHackers.Agg;
using MatterHackers.Agg.Platform;
using MatterHackers.Agg.UI;
using MatterHackers.DataConverters3D;
using MatterHackers.Localizations;
using MatterHackers.MatterControl.DataStorage;
using MatterHackers.MatterControl.PrintQueue;
using MatterHackers.MatterControl.SettingsManagement;
using MatterHackers.PolygonMesh;
using MatterHackers.PolygonMesh.Processors;
namespace MatterHackers.MatterControl.SlicerConfiguration
{
public class SlicingQueue
public class Slicer
{
static Dictionary<Mesh, MeshPrintOutputSettings> meshPrintOutputSettings = new Dictionary<Mesh, MeshPrintOutputSettings>();
private static Thread slicePartThread = null;
private static List<PrintItemWrapper> listOfSlicingItems = new List<PrintItemWrapper>();
private static bool haltSlicingThread = false;
private SlicingQueue()
{
if (slicePartThread == null)
{
slicePartThread = new Thread(CreateSlicedPartsThread);
slicePartThread.Name = "slicePartThread";
slicePartThread.IsBackground = true;
slicePartThread.Start();
}
}
private static SlicingQueue instance;
static public SlicingQueue Instance
{
get
{
if (instance == null)
{
instance = new SlicingQueue();
}
return instance;
}
}
public void QueuePartForSlicing(PrintItemWrapper itemToQueue)
{
itemToQueue.DoneSlicing = false;
string preparingToSliceModelTxt = "Preparing to slice model".Localize();
string peparingToSliceModelFull = string.Format("{0}...", preparingToSliceModelTxt);
itemToQueue.OnSlicingOutputMessage(new StringEventArgs(peparingToSliceModelFull));
lock(listOfSlicingItems)
{
//Add to thumbnail generation queue
listOfSlicingItems.Add(itemToQueue);
}
}
public void ShutDownSlicingThread()
{
haltSlicingThread = true;
}
private static string macQuotes(string textLine)
{
if (textLine.StartsWith("\"") && textLine.EndsWith("\""))
{
return textLine;
}
else
{
return "\"" + textLine.Replace("\"", "\\\"") + "\"";
}
}
public static List<bool> extrudersUsed = new List<bool>();
public static bool runInProcess = true;
private static Process slicerProcess = null;
public static string[] GetStlFileLocations(string fileToSlice, ref string mergeRules)
{
@ -285,106 +227,6 @@ namespace MatterHackers.MatterControl.SlicerConfiguration
return filePath;
}
private static string SaveAndGetFilePathForMaterial(MeshGroup extruderMeshGroup, List<int> materialIndexsToSaveInThisSTL)
{
string folderToSaveStlsTo = Path.Combine(ApplicationDataStorage.ApplicationUserDataPath, "data", "temp", "amf_to_stl");
// Create directory if needed
Directory.CreateDirectory(folderToSaveStlsTo);
string filePath = Path.Combine(folderToSaveStlsTo, Path.ChangeExtension(Path.GetRandomFileName(), ".stl"));
MeshFileIo.Save(
extruderMeshGroup,
filePath,
new MeshOutputSettings());
return filePath;
}
public static bool runInProcess = false;
private static Process slicerProcess = null;
private class SliceMessageReporter : IProgress<string>
{
private PrintItemWrapper printItem;
public SliceMessageReporter(PrintItemWrapper printItem)
{
this.printItem = printItem;
}
public void Report(string message)
{
UiThread.RunOnIdle(() =>
{
printItem.OnSlicingOutputMessage(new StringEventArgs(message));
});
}
}
private static void CreateSlicedPartsThread()
{
Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture;
while (!haltSlicingThread)
{
if (listOfSlicingItems.Count > 0)
{
PrintItemWrapper itemToSlice = listOfSlicingItems[0];
/*
*
#if false
Mesh loadedMesh = StlProcessing.Load(fileToSlice);
SliceLayers layers = new SliceLayers();
layers.GetPerimetersForAllLayers(loadedMesh, .2, .2);
layers.DumpSegmentsToGcode("test.gcode");
#endif
* */
if (File.Exists(itemToSlice.FileLocation))
{
itemToSlice.CurrentlySlicing = true;
string gcodeFilePath = itemToSlice.GetGCodePathAndFileName();
var reporter = new SliceMessageReporter(itemToSlice);
if (AggContext.OperatingSystem == OSType.Android
|| AggContext.OperatingSystem == OSType.Mac
|| runInProcess)
{
itemCurrentlySlicing = itemToSlice;
MatterHackers.MatterSlice.LogOutput.GetLogWrites += SendProgressToItem;
SliceFile(itemToSlice.FileLocation, gcodeFilePath, reporter);
MatterHackers.MatterSlice.LogOutput.GetLogWrites -= SendProgressToItem;
itemCurrentlySlicing = null;
}
else
{
SliceFile(itemToSlice.FileLocation, gcodeFilePath, reporter);
}
}
UiThread.RunOnIdle(() =>
{
itemToSlice.CurrentlySlicing = false;
itemToSlice.DoneSlicing = true;
});
lock (listOfSlicingItems)
{
listOfSlicingItems.RemoveAt(0);
}
}
Thread.Sleep(100);
}
}
public static async Task SliceFileAsync(PrintItemWrapper printItem, IProgress<string> progressReporter)
{
string gcodeFilePath = printItem.GetGCodePathAndFileName();
@ -395,11 +237,6 @@ namespace MatterHackers.MatterControl.SlicerConfiguration
progressReporter));
}
public static async Task SliceFileAsync(string sourceFile, string gcodeFilePath, IProgress<string> progressReporter)
{
await Task.Run(() => SliceFile(sourceFile, gcodeFilePath, progressReporter));
}
private static void SliceFile(string sourceFile, string gcodeFilePath, IProgress<string> progressReporter)
{
string mergeRules = "";
@ -544,29 +381,6 @@ namespace MatterHackers.MatterControl.SlicerConfiguration
}
}
private static PrintItemWrapper itemCurrentlySlicing;
private static void SendProgressToItem(object sender, EventArgs args)
{
string message = sender as string;
if (message != null)
{
message = message.Replace("=>", "").Trim();
if (message.Contains(".gcode"))
{
message = "Saving intermediate file";
}
message += "...";
UiThread.RunOnIdle(() =>
{
if (itemCurrentlySlicing != null)
{
itemCurrentlySlicing.OnSlicingOutputMessage(new StringEventArgs(message));
}
});
}
}
internal void CancelCurrentSlicing()
{
if (slicerProcess != null)

@ -1 +1 @@
Subproject commit e3904219692faa02136ec4fd1ce32ee04c045ded
Subproject commit 8c237ae40704765d41e3f08083927bd4b666b399