Add async Slice method, move into PrinterActionsBar, switch after

This commit is contained in:
John Lewin 2017-06-29 19:42:20 -07:00
parent e814314466
commit 50957e856b
4 changed files with 283 additions and 173 deletions

View file

@ -109,7 +109,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
public class PrinterTabPage : GuiWidget public class PrinterTabPage : GuiWidget
{ {
private View3DWidget modelViewer; private View3DWidget modelViewer;
private ViewGcodeBasic gcodeViewer; internal ViewGcodeBasic gcodeViewer;
private PrintItemWrapper printItem; private PrintItemWrapper printItem;
private ViewControls3D viewControls3D; private ViewControls3D viewControls3D;
@ -160,7 +160,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
this.AddChild(topToBottom); this.AddChild(topToBottom);
// Must come after we have an instance of View3DWidget an its undo buffer // Must come after we have an instance of View3DWidget an its undo buffer
topToBottom.AddChild(new PrinterActionsBar(modelViewer) topToBottom.AddChild(new PrinterActionsBar(modelViewer, this)
{ {
Padding = new BorderDouble(bottom: 2) Padding = new BorderDouble(bottom: 2)
}); });
@ -241,6 +241,12 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
sideBar.AddPage("Terminal".Localize(), terminalControls); sideBar.AddPage("Terminal".Localize(), terminalControls);
} }
public void SwitchToLayerView()
{
gcodeViewer.Visible = true;
modelViewer.ShowSliceLayers = true;
}
public void ToggleView() public void ToggleView()
{ {
gcodeViewer.Visible = !gcodeViewer.Visible; gcodeViewer.Visible = !gcodeViewer.Visible;

View file

@ -36,6 +36,7 @@ using MatterHackers.MatterControl.CustomWidgets;
using MatterHackers.MatterControl.EeProm; using MatterHackers.MatterControl.EeProm;
using MatterHackers.MatterControl.PrinterCommunication; using MatterHackers.MatterControl.PrinterCommunication;
using MatterHackers.MatterControl.SlicerConfiguration; using MatterHackers.MatterControl.SlicerConfiguration;
using MatterHackers.MeshVisualizer;
namespace MatterHackers.MatterControl.PartPreviewWindow namespace MatterHackers.MatterControl.PartPreviewWindow
{ {
@ -48,10 +49,39 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
private OverflowDropdown overflowDropdown; private OverflowDropdown overflowDropdown;
public PrinterActionsBar(View3DWidget modelViewer) private SliceProgressReporter sliceProgressReporter;
public class SliceProgressReporter : IProgress<string>
{
private MeshViewerWidget meshViewer;
public SliceProgressReporter(MeshViewerWidget meshViewer)
{
this.meshViewer = meshViewer;
}
public void StartReporting()
{
meshViewer.BeginProgressReporting("Slicing Part");
}
public void EndReporting()
{
meshViewer.EndProgressReporting();
}
public void Report(string value)
{
meshViewer.partProcessingInfo.centeredInfoDescription.Text = value;
}
}
public PrinterActionsBar(View3DWidget modelViewer, PartPreviewContent.PrinterTabPage printerTabPage)
{ {
UndoBuffer undoBuffer = modelViewer.UndoBuffer; UndoBuffer undoBuffer = modelViewer.UndoBuffer;
sliceProgressReporter = new SliceProgressReporter(modelViewer.meshViewerWidget);
this.HAnchor = HAnchor.ParentLeftRight; this.HAnchor = HAnchor.ParentLeftRight;
this.VAnchor = VAnchor.FitToChildren; this.VAnchor = VAnchor.FitToChildren;
@ -65,6 +95,55 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
var initialMargin = buttonFactory.Margin; var initialMargin = buttonFactory.Margin;
var sliceButton = buttonFactory.Generate("Slice".Localize());
sliceButton.ToolTipText = "Slice Parts".Localize();
sliceButton.Name = "Generate Gcode Button";
sliceButton.Margin = new BorderDouble(8, 0);
sliceButton.Click += async (s, e) =>
{
if (ActiveSliceSettings.Instance.PrinterSelected)
{
var printItem = ApplicationController.Instance.ActivePrintItem;
if (ActiveSliceSettings.Instance.IsValid() && printItem != null)
{
sliceButton.Enabled = false;
try
{
sliceProgressReporter.StartReporting();
// Save any pending changes before starting the print
await ApplicationController.Instance.ActiveView3DWidget.PersistPlateIfNeeded();
await SlicingQueue.SliceFileAsync(printItem, sliceProgressReporter);
sliceProgressReporter.EndReporting();
printerTabPage.SwitchToLayerView();
// HACK: directly fire method which previously ran on SlicingDone event on PrintItemWrapper
UiThread.RunOnIdle(printerTabPage.gcodeViewer.CreateAndAddChildren);
}
catch (Exception ex)
{
Console.WriteLine("Error slicing file: " + ex.Message);
}
sliceButton.Enabled = true;
};
}
else
{
UiThread.RunOnIdle(() =>
{
StyledMessageBox.ShowMessageBox(null, "Oops! Please select a printer in order to continue slicing.", "Select Printer", StyledMessageBox.MessageType.OK);
});
}
};
this.AddChild(sliceButton);
this.AddChild(new TemperatureWidgetExtruder(ApplicationController.Instance.Theme.MenuButtonFactory) this.AddChild(new TemperatureWidgetExtruder(ApplicationController.Instance.Theme.MenuButtonFactory)
{ {
Margin = new BorderDouble(right: 10) Margin = new BorderDouble(right: 10)

View file

@ -59,7 +59,6 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
private GCode2DWidget gcode2DWidget; private GCode2DWidget gcode2DWidget;
private PrintItemWrapper printItem => ApplicationController.Instance.ActivePrintItem; private PrintItemWrapper printItem => ApplicationController.Instance.ActivePrintItem;
private bool startedSliceFromGenerateButton = false; private bool startedSliceFromGenerateButton = false;
private Button generateGCodeButton;
private FlowLayoutWidget buttonBottomPanel; private FlowLayoutWidget buttonBottomPanel;
private FlowLayoutWidget layerSelectionButtonsPanel; private FlowLayoutWidget layerSelectionButtonsPanel;
@ -183,7 +182,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
private GCodeFile loadedGCode => printer.BedPlate.LoadedGCode; private GCodeFile loadedGCode => printer.BedPlate.LoadedGCode;
private void CreateAndAddChildren() internal void CreateAndAddChildren()
{ {
CloseAllChildren(); CloseAllChildren();
@ -202,39 +201,12 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
buttonBottomPanel.Padding = new BorderDouble(3, 3); buttonBottomPanel.Padding = new BorderDouble(3, 3);
buttonBottomPanel.BackgroundColor = ActiveTheme.Instance.PrimaryBackgroundColor; buttonBottomPanel.BackgroundColor = ActiveTheme.Instance.PrimaryBackgroundColor;
generateGCodeButton = buttonFactory.Generate("Generate".Localize());
generateGCodeButton.Name = "Generate Gcode Button";
generateGCodeButton.Click += (s, e) =>
{
UiThread.RunOnIdle(() =>
{
if (ActiveSliceSettings.Instance.PrinterSelected)
{
// Save any pending changes before starting the print
ApplicationController.Instance.ActiveView3DWidget.PersistPlateIfNeeded().ContinueWith((t) =>
{
if (ActiveSliceSettings.Instance.IsValid() && printItem != null)
{
generateGCodeButton.Visible = false;
SlicingQueue.Instance.QueuePartForSlicing(printItem);
startedSliceFromGenerateButton = true;
}
});
}
else
{
StyledMessageBox.ShowMessageBox(null, "Oops! Please select a printer in order to continue slicing.", "Select Printer", StyledMessageBox.MessageType.OK);
}
});
};
buttonBottomPanel.AddChild(generateGCodeButton);
layerSelectionButtonsPanel = new FlowLayoutWidget(FlowDirection.RightToLeft); layerSelectionButtonsPanel = new FlowLayoutWidget(FlowDirection.RightToLeft);
layerSelectionButtonsPanel.HAnchor = HAnchor.ParentLeftRight; layerSelectionButtonsPanel.HAnchor = HAnchor.ParentLeftRight;
layerSelectionButtonsPanel.Padding = new BorderDouble(0); layerSelectionButtonsPanel.Padding = new BorderDouble(0);
GuiWidget holdPanelOpen = new GuiWidget(1, generateGCodeButton.Height); GuiWidget holdPanelOpen = new GuiWidget(1, 40);
layerSelectionButtonsPanel.AddChild(holdPanelOpen); layerSelectionButtonsPanel.AddChild(holdPanelOpen);
if (windowMode == WindowMode.StandAlone) if (windowMode == WindowMode.StandAlone)
@ -252,6 +224,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
HAnchor = HAnchor.ParentLeftRight, HAnchor = HAnchor.ParentLeftRight,
VAnchor = VAnchor.ParentBottomTop VAnchor = VAnchor.ParentBottomTop
}; };
string firstProcessingMessage = "Press 'Add' to select an item.".Localize(); string firstProcessingMessage = "Press 'Add' to select an item.".Localize();
if (printItem != null) if (printItem != null)
@ -292,10 +265,6 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
} }
} }
} }
else
{
generateGCodeButton.Visible = false;
}
SetProcessingMessage(firstProcessingMessage); SetProcessingMessage(firstProcessingMessage);
@ -523,8 +492,6 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
{ {
printItem.SlicingOutputMessage -= sliceItem_SlicingOutputMessage; printItem.SlicingOutputMessage -= sliceItem_SlicingOutputMessage;
printItem.SlicingDone -= sliceItem_Done; printItem.SlicingDone -= sliceItem_Done;
generateGCodeButton.Visible = false;
} }
} }
@ -589,8 +556,6 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
// register for done slicing and slicing messages // register for done slicing and slicing messages
printItem.SlicingOutputMessage += sliceItem_SlicingOutputMessage; printItem.SlicingOutputMessage += sliceItem_SlicingOutputMessage;
printItem.SlicingDone += sliceItem_Done; printItem.SlicingDone += sliceItem_Done;
generateGCodeButton.Visible = true;
} }
SetSyncToPrintVisibility(); SetSyncToPrintVisibility();
} }

View file

@ -33,6 +33,7 @@ using System.Diagnostics;
using System.Globalization; using System.Globalization;
using System.IO; using System.IO;
using System.Threading; using System.Threading;
using System.Threading.Tasks;
using MatterHackers.Agg; using MatterHackers.Agg;
using MatterHackers.Agg.PlatformAbstract; using MatterHackers.Agg.PlatformAbstract;
using MatterHackers.Agg.UI; using MatterHackers.Agg.UI;
@ -293,6 +294,24 @@ namespace MatterHackers.MatterControl.SlicerConfiguration
public static bool runInProcess = false; public static bool runInProcess = false;
private static Process slicerProcess = null; 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() private static void CreateSlicedPartsThread()
{ {
Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture; Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture;
@ -302,148 +321,41 @@ namespace MatterHackers.MatterControl.SlicerConfiguration
if (listOfSlicingItems.Count > 0) if (listOfSlicingItems.Count > 0)
{ {
PrintItemWrapper itemToSlice = listOfSlicingItems[0]; PrintItemWrapper itemToSlice = listOfSlicingItems[0];
string mergeRules = "";
string[] stlFileLocations = GetStlFileLocations(itemToSlice.FileLocation, ref mergeRules);
string fileToSlice = stlFileLocations[0];
// check that the STL file is currently on disk /*
if (File.Exists(fileToSlice)) *
#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; itemToSlice.CurrentlySlicing = true;
string configFilePath = Path.Combine(
ApplicationDataStorage.Instance.GCodeOutputPath,
string.Format("config_{0}.ini", ActiveSliceSettings.Instance.GetLongHashCode().ToString()));
string gcodeFilePath = itemToSlice.GetGCodePathAndFileName(); string gcodeFilePath = itemToSlice.GetGCodePathAndFileName();
bool gcodeFileIsComplete = itemToSlice.IsGCodeFileComplete(gcodeFilePath);
if (!File.Exists(gcodeFilePath) || !gcodeFileIsComplete) var reporter = new SliceMessageReporter(itemToSlice);
if (OsInformation.OperatingSystem == OSType.Android
|| OsInformation.OperatingSystem == OSType.Mac
|| runInProcess)
{ {
string commandArgs = "";
EngineMappingsMatterSlice.WriteSliceSettingsFile(configFilePath); itemCurrentlySlicing = itemToSlice;
if (mergeRules == "") MatterHackers.MatterSlice.LogOutput.GetLogWrites += SendProgressToItem;
{
commandArgs = $"-v -o \"{gcodeFilePath}\" -c \"{configFilePath}\"";
}
else
{
commandArgs = $"-b {mergeRules} -v -o \"{gcodeFilePath}\" -c \"{configFilePath}\"";
}
foreach (string filename in stlFileLocations) SliceFile(itemToSlice.FileLocation, gcodeFilePath, itemToSlice.IsGCodeFileComplete(gcodeFilePath), reporter);
{
commandArgs += $" \"{filename}\"";
}
#if false
Mesh loadedMesh = StlProcessing.Load(fileToSlice);
SliceLayers layers = new SliceLayers();
layers.GetPerimetersForAllLayers(loadedMesh, .2, .2);
layers.DumpSegmentsToGcode("test.gcode");
#endif
if (OsInformation.OperatingSystem == OSType.Android MatterHackers.MatterSlice.LogOutput.GetLogWrites -= SendProgressToItem;
|| OsInformation.OperatingSystem == OSType.Mac itemCurrentlySlicing = null;
|| runInProcess)
{
itemCurrentlySlicing = itemToSlice;
MatterHackers.MatterSlice.LogOutput.GetLogWrites += SendProgressToItem;
MatterSlice.MatterSlice.ProcessArgs(commandArgs);
MatterHackers.MatterSlice.LogOutput.GetLogWrites -= SendProgressToItem;
itemCurrentlySlicing = null;
}
else
{
slicerProcess = new Process()
{
StartInfo = new ProcessStartInfo()
{
Arguments = commandArgs,
CreateNoWindow = true,
WindowStyle = ProcessWindowStyle.Hidden,
RedirectStandardError = true,
RedirectStandardOutput = true,
FileName = MatterSliceInfo.GetEnginePath(),
UseShellExecute = false
}
};
slicerProcess.OutputDataReceived += (sender, args) =>
{
if (args.Data != null)
{
string message = args.Data.Replace("=>", "").Trim();
if (message.Contains(".gcode"))
{
message = "Saving intermediate file";
}
message += "...";
UiThread.RunOnIdle(() =>
{
itemToSlice.OnSlicingOutputMessage(new StringEventArgs(message));
});
}
};
slicerProcess.Start();
slicerProcess.BeginOutputReadLine();
string stdError = slicerProcess.StandardError.ReadToEnd();
slicerProcess.WaitForExit();
lock(slicerProcess)
{
slicerProcess = null;
}
}
} }
else
try
{
if (File.Exists(gcodeFilePath)
&& File.Exists(configFilePath))
{
// make sure we have not already written the settings onto this file
bool fileHasSettings = false;
int bufferSize = 32000;
using (Stream fileStream = File.OpenRead(gcodeFilePath))
{
// Read the tail of the file to determine if the given token exists
byte[] buffer = new byte[bufferSize];
fileStream.Seek(Math.Max(0, fileStream.Length - bufferSize), SeekOrigin.Begin);
int numBytesRead = fileStream.Read(buffer, 0, bufferSize);
string fileEnd = System.Text.Encoding.UTF8.GetString(buffer);
if (fileEnd.Contains("GCode settings used"))
{
fileHasSettings = true;
}
}
if (!fileHasSettings)
{
using (StreamWriter gcodeWriter = File.AppendText(gcodeFilePath))
{
string oemName = "MatterControl";
if (OemSettings.Instance.WindowTitleExtra != null && OemSettings.Instance.WindowTitleExtra.Trim().Length > 0)
{
oemName += $" - {OemSettings.Instance.WindowTitleExtra}";
}
gcodeWriter.WriteLine("; {0} Version {1} Build {2} : GCode settings used", oemName, VersionInfo.Instance.ReleaseVersion, VersionInfo.Instance.BuildVersion);
gcodeWriter.WriteLine("; Date {0} Time {1}:{2:00}", DateTime.Now.Date, DateTime.Now.Hour, DateTime.Now.Minute);
foreach (string line in File.ReadLines(configFilePath))
{
gcodeWriter.WriteLine("; {0}", line);
}
}
}
}
}
catch (Exception)
{ {
SliceFile(itemToSlice.FileLocation, gcodeFilePath, itemToSlice.IsGCodeFileComplete(gcodeFilePath), reporter);
} }
} }
@ -453,7 +365,7 @@ namespace MatterHackers.MatterControl.SlicerConfiguration
itemToSlice.DoneSlicing = true; itemToSlice.DoneSlicing = true;
}); });
lock(listOfSlicingItems) lock (listOfSlicingItems)
{ {
listOfSlicingItems.RemoveAt(0); listOfSlicingItems.RemoveAt(0);
} }
@ -463,6 +375,154 @@ namespace MatterHackers.MatterControl.SlicerConfiguration
} }
} }
public static async Task SliceFileAsync(PrintItemWrapper printItem, IProgress<string> progressReporter)
{
string gcodeFilePath = printItem.GetGCodePathAndFileName();
await Task.Run(() => SliceFile(
printItem.FileLocation,
gcodeFilePath,
printItem.IsGCodeFileComplete(gcodeFilePath),
progressReporter));
}
public static async Task SliceFileAsync(string sourceFile, string gcodeFilePath, bool gcodeFileIsComplete, IProgress<string> progressReporter)
{
await Task.Run(() => SliceFile(sourceFile, gcodeFilePath, gcodeFileIsComplete, progressReporter));
}
private static void SliceFile(string sourceFile, string gcodeFilePath, bool gcodeFileIsComplete, IProgress<string> progressReporter)
{
string mergeRules = "";
string[] stlFileLocations = GetStlFileLocations(sourceFile, ref mergeRules);
string fileToSlice = stlFileLocations[0];
// check that the STL file is currently on disk
if (File.Exists(fileToSlice))
{
string configFilePath = Path.Combine(
ApplicationDataStorage.Instance.GCodeOutputPath,
string.Format("config_{0}.ini", ActiveSliceSettings.Instance.GetLongHashCode().ToString()));
if (!File.Exists(gcodeFilePath) || !gcodeFileIsComplete)
{
string commandArgs;
EngineMappingsMatterSlice.WriteSliceSettingsFile(configFilePath);
if (mergeRules == "")
{
commandArgs = $"-v -o \"{gcodeFilePath}\" -c \"{configFilePath}\"";
}
else
{
commandArgs = $"-b {mergeRules} -v -o \"{gcodeFilePath}\" -c \"{configFilePath}\"";
}
foreach (string filename in stlFileLocations)
{
commandArgs += $" \"{filename}\"";
}
if (OsInformation.OperatingSystem == OSType.Android
|| OsInformation.OperatingSystem == OSType.Mac
|| runInProcess)
{
MatterSlice.MatterSlice.ProcessArgs(commandArgs);
}
else
{
slicerProcess = new Process()
{
StartInfo = new ProcessStartInfo()
{
Arguments = commandArgs,
CreateNoWindow = true,
WindowStyle = ProcessWindowStyle.Hidden,
RedirectStandardError = true,
RedirectStandardOutput = true,
FileName = MatterSliceInfo.GetEnginePath(),
UseShellExecute = false
}
};
slicerProcess.OutputDataReceived += (sender, args) =>
{
if (args.Data != null)
{
string message = args.Data.Replace("=>", "").Trim();
if (message.Contains(".gcode"))
{
message = "Saving intermediate file";
}
message += "...";
progressReporter.Report(message);
}
};
slicerProcess.Start();
slicerProcess.BeginOutputReadLine();
string stdError = slicerProcess.StandardError.ReadToEnd();
slicerProcess.WaitForExit();
lock (slicerProcess)
{
slicerProcess = null;
}
}
}
try
{
if (File.Exists(gcodeFilePath)
&& File.Exists(configFilePath))
{
// make sure we have not already written the settings onto this file
bool fileHasSettings = false;
int bufferSize = 32000;
using (Stream fileStream = File.OpenRead(gcodeFilePath))
{
// Read the tail of the file to determine if the given token exists
byte[] buffer = new byte[bufferSize];
fileStream.Seek(Math.Max(0, fileStream.Length - bufferSize), SeekOrigin.Begin);
int numBytesRead = fileStream.Read(buffer, 0, bufferSize);
string fileEnd = System.Text.Encoding.UTF8.GetString(buffer);
if (fileEnd.Contains("GCode settings used"))
{
fileHasSettings = true;
}
}
if (!fileHasSettings)
{
using (StreamWriter gcodeWriter = File.AppendText(gcodeFilePath))
{
string oemName = "MatterControl";
if (OemSettings.Instance.WindowTitleExtra != null && OemSettings.Instance.WindowTitleExtra.Trim().Length > 0)
{
oemName += $" - {OemSettings.Instance.WindowTitleExtra}";
}
gcodeWriter.WriteLine("; {0} Version {1} Build {2} : GCode settings used", oemName, VersionInfo.Instance.ReleaseVersion, VersionInfo.Instance.BuildVersion);
gcodeWriter.WriteLine("; Date {0} Time {1}:{2:00}", DateTime.Now.Date, DateTime.Now.Hour, DateTime.Now.Minute);
foreach (string line in File.ReadLines(configFilePath))
{
gcodeWriter.WriteLine("; {0}", line);
}
}
}
}
}
catch (Exception)
{
}
}
}
private static PrintItemWrapper itemCurrentlySlicing; private static PrintItemWrapper itemCurrentlySlicing;
private static void SendProgressToItem(object sender, EventArgs args) private static void SendProgressToItem(object sender, EventArgs args)