Merge pull request #3910 from larsbrubaker/master

Check that loaded gcode has a print time > 30 seconds or warn
This commit is contained in:
johnlewin 2018-10-29 17:22:33 -07:00 committed by GitHub
commit dadf384ecb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 152 additions and 158 deletions

View file

@ -117,17 +117,6 @@ namespace MatterControl.Printing
GCodeCommandQueue.Insert(insertIndex, printerMachineInstruction);
}
public static GCodeFile ParseGCodeString(string gcodeContents,
Vector4 maxAccelerationMmPerS2,
Vector4 maxVelocityMmPerS,
Vector4 velocitySameAsStopMmPerS,
Vector4 speedMultiplier,
CancellationToken cancellationToken)
{
return ParseFileContents(gcodeContents,
maxAccelerationMmPerS2, maxVelocityMmPerS, velocitySameAsStopMmPerS, speedMultiplier, cancellationToken, null);
}
public static GCodeMemoryFile Load(Stream fileStream,
Vector4 maxAccelerationMmPerS2,
Vector4 maxVelocityMmPerS,
@ -140,9 +129,11 @@ namespace MatterControl.Printing
{
using (var reader = new StreamReader(fileStream))
{
return ParseFileContents(reader.ReadToEnd(),
var gcodeMemoryFile = ParseFileContents(reader.ReadToEnd(),
maxAccelerationMmPerS2, maxVelocityMmPerS, velocitySameAsStopMmPerS, speedMultiplier,
cancellationToken, progressReporter);
return gcodeMemoryFile;
}
}
catch (Exception e)
@ -213,7 +204,7 @@ namespace MatterControl.Printing
return crCount + 1;
}
public static GCodeMemoryFile ParseFileContents(string gCodeString,
private static GCodeMemoryFile ParseFileContents(string gCodeString,
Vector4 maxAccelerationMmPerS2,
Vector4 maxVelocityMmPerS,
Vector4 velocitySameAsStopMmPerS,

View file

@ -570,7 +570,7 @@ namespace MatterHackers.MatterControl
new SceneSelectionOperation()
{
TitleResolver = () => "Duplicate".Localize(),
Action = (scene) => scene.DuplicateItem(),
Action = (scene) => scene.DuplicateItem(5),
IsEnabled = (scene) => scene.SelectedItem != null,
Icon = AggContext.StaticData.LoadIcon("duplicate.png").SetPreMultiply(),
},
@ -2441,6 +2441,23 @@ If you experience adhesion problems, please re-run leveling."
});
});
if (printer.Bed.LoadedGCode is GCodeMemoryFile gcodeMemoryFile)
{
// try to validate the gcode file and warn if it seems invalid.
// for now the definition of invalid is that it has a print time of < 30 seconds
var estimatedPrintSeconds = gcodeMemoryFile.EstimatedPrintSeconds();
if (estimatedPrintSeconds < 30)
{
var message = "The time to print this G-Code is estimated to be {0} seconds.\n\nPlease check your part for errors if this is unexpected."
.Localize()
.FormatWith((int)estimatedPrintSeconds);
UiThread.RunOnIdle(() =>
{
StyledMessageBox.ShowMessageBox(message, "Warning, very short print".Localize());
});
}
}
return Task.CompletedTask;
});

View file

@ -136,12 +136,10 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
speedsWidget.Visible = renderSpeeds;
// Single instance shared across widgets
var gcodeDetails = new GCodeDetails(printer, printer.Bed.LoadedGCode);
loadedGCodeSection.AddChild(
new SectionWidget(
"Details".Localize(),
new GCodeDetailsView(gcodeDetails, theme)
new GCodeDetailsView(printer.Bed.LoadedGCode, printer, theme)
{
HAnchor = HAnchor.Stretch,
Margin = new BorderDouble(bottom: 3),
@ -156,7 +154,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
loadedGCodeSection.AddChild(
new SectionWidget(
"Layer".Localize(),
new GCodeLayerDetailsView(gcodeDetails, sceneContext, theme)
new GCodeLayerDetailsView(printer.Bed.LoadedGCode, sceneContext, theme)
{
HAnchor = HAnchor.Stretch,
Margin = new BorderDouble(bottom: 3),

View file

@ -33,120 +33,34 @@ using MatterHackers.MatterControl.SlicerConfiguration;
namespace MatterHackers.MatterControl.PartPreviewWindow
{
public class GCodeDetails
public static class GCodeDetails
{
private GCodeFile loadedGCode;
private PrinterConfig printer;
public GCodeDetails(PrinterConfig printer, GCodeFile loadedGCode)
public static string LayerTime(this GCodeFile loadedGCode, int activeLayerIndex)
{
this.printer = printer;
this.loadedGCode = loadedGCode;
return loadedGCode.InstructionTime(activeLayerIndex, activeLayerIndex + 1);
}
public string SecondsToTime(double seconds)
public static string LayerTimeToHere(this GCodeFile loadedGCode, int activeLayerIndex)
{
int secondsRemaining = (int)seconds;
int hoursRemaining = (int)(secondsRemaining / (60 * 60));
int minutesRemaining = (int)(secondsRemaining / 60 - hoursRemaining * 60);
secondsRemaining = secondsRemaining % 60;
if (hoursRemaining > 0)
{
return $"{hoursRemaining} h, {minutesRemaining} min";
}
else if(minutesRemaining > 10)
{
return $"{minutesRemaining} min";
}
else
{
return $"{minutesRemaining} min {secondsRemaining} s";
}
return loadedGCode.InstructionTime(0, activeLayerIndex + 1);
}
public string EstimatedPrintTime
public static string LayerTimeFromeHere(this GCodeFile loadedGCode, int activeLayerIndex)
{
get
{
if (loadedGCode == null || loadedGCode.LayerCount == 0)
{
return "---";
}
return SecondsToTime(loadedGCode.Instruction(0).secondsToEndFromHere);
}
return loadedGCode.InstructionTime(activeLayerIndex + 1, int.MaxValue);
}
public double EstimatedPrintSeconds
{
get
{
if (loadedGCode == null || loadedGCode.LayerCount == 0)
{
return 0;
}
return loadedGCode.Instruction(0).secondsToEndFromHere;
}
}
public string FilamentUsed => string.Format("{0:0.0} mm", loadedGCode.GetFilamentUsedMm(printer.Settings.GetValue<double>(SettingsKey.filament_diameter)));
public string FilamentVolume => string.Format("{0:0.00} cm³", loadedGCode.GetFilamentCubicMm(printer.Settings.GetValue<double>(SettingsKey.filament_diameter)) / 1000);
public string EstimatedMass => this.TotalMass <= 0 ? "Unknown" : string.Format("{0:0.00} g", this.TotalMass);
public string EstimatedCost => this.TotalCost <= 0 ? "Unknown" : string.Format("${0:0.00}", this.TotalCost);
public double TotalMass
{
get
{
double filamentDiameter = printer.Settings.GetValue<double>(SettingsKey.filament_diameter);
double filamentDensity = printer.Settings.GetValue<double>(SettingsKey.filament_density);
return loadedGCode.GetFilamentWeightGrams(filamentDiameter, filamentDensity);
}
}
public double GetLayerHeight(int layerIndex)
public static string EstimatedPrintTime(this GCodeFile loadedGCode)
{
if (loadedGCode == null || loadedGCode.LayerCount == 0)
{
return 0;
return "---";
}
return loadedGCode.GetLayerHeight(layerIndex);
return SecondsToTime(loadedGCode.Instruction(0).secondsToEndFromHere);
}
internal object GetLayerTop(int layerIndex)
{
if (loadedGCode == null || loadedGCode.LayerCount == 0)
{
return 0;
}
return loadedGCode.GetLayerTop(layerIndex);
}
public string LayerTime(int activeLayerIndex)
{
return InstructionTime(activeLayerIndex, activeLayerIndex + 1);
}
public string LayerTimeToHere(int activeLayerIndex)
{
return InstructionTime(0, activeLayerIndex + 1);
}
public string LayerTimeFromeHere(int activeLayerIndex)
{
return InstructionTime(activeLayerIndex + 1, int.MaxValue);
}
private string InstructionTime(int startLayer, int endLayer)
private static string InstructionTime(this GCodeFile loadedGCode, int startLayer, int endLayer)
{
if (loadedGCode == null || loadedGCode.LayerCount == 0)
{
@ -160,7 +74,89 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
return SecondsToTime(secondsToEndFromStart - secondsToEndFromEnd);
}
public string GetLayerFanSpeeds(int activeLayerIndex)
public static string SecondsToTime(double seconds)
{
int secondsRemaining = (int)seconds;
int hoursRemaining = (int)(secondsRemaining / (60 * 60));
int minutesRemaining = (int)(secondsRemaining / 60 - hoursRemaining * 60);
secondsRemaining = secondsRemaining % 60;
if (hoursRemaining > 0)
{
return $"{hoursRemaining} h, {minutesRemaining} min";
}
else if (minutesRemaining > 10)
{
return $"{minutesRemaining} min";
}
else
{
return $"{minutesRemaining} min {secondsRemaining} s";
}
}
public static double EstimatedPrintSeconds(this GCodeFile loadedGCode)
{
if (loadedGCode == null || loadedGCode.LayerCount == 0)
{
return 0;
}
return loadedGCode.Instruction(0).secondsToEndFromHere;
}
public static string FilamentUsed(this GCodeFile loadedGCode, PrinterConfig printer)
{
return string.Format("{0:0.0} mm", loadedGCode.GetFilamentUsedMm(printer.Settings.GetValue<double>(SettingsKey.filament_diameter)));
}
public static string FilamentVolume(this GCodeFile loadedGCode, PrinterConfig printer)
{
return string.Format("{0:0.00} cm³", loadedGCode.GetFilamentCubicMm(printer.Settings.GetValue<double>(SettingsKey.filament_diameter)) / 1000);
}
public static string EstimatedMass(this GCodeFile loadedGCode, PrinterConfig printer)
{
var totalMass = TotalCost(loadedGCode, printer);
return totalMass <= 0 ? "Unknown" : string.Format("{0:0.00} g", totalMass);
}
public static string EstimatedCost(this GCodeFile loadedGCode, PrinterConfig printer)
{
var totalMass = TotalCost(loadedGCode, printer);
return totalMass <= 0 ? "Unknown" : string.Format("${0:0.00}", totalMass);
}
public static double TotalMass(this GCodeFile loadedGCode, PrinterConfig printer)
{
double filamentDiameter = printer.Settings.GetValue<double>(SettingsKey.filament_diameter);
double filamentDensity = printer.Settings.GetValue<double>(SettingsKey.filament_density);
return loadedGCode.GetFilamentWeightGrams(filamentDiameter, filamentDensity);
}
public static double GetLayerHeight(this GCodeFile loadedGCode, int layerIndex)
{
if (loadedGCode == null || loadedGCode.LayerCount == 0)
{
return 0;
}
return loadedGCode.GetLayerHeight(layerIndex);
}
internal static object GetLayerTop(this GCodeFile loadedGCode, int layerIndex)
{
if (loadedGCode == null || loadedGCode.LayerCount == 0)
{
return 0;
}
return loadedGCode.GetLayerTop(layerIndex);
}
public static string GetLayerFanSpeeds(this GCodeFile loadedGCode, int activeLayerIndex)
{
if (loadedGCode == null || loadedGCode.LayerCount == 0)
{
@ -198,13 +194,10 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
return fanSpeeds;
}
public double TotalCost
public static double TotalCost(this GCodeFile loadedGCode, PrinterConfig printer)
{
get
{
double filamentCost = printer.Settings.GetValue<double>(SettingsKey.filament_cost);
return this.TotalMass / 1000 * filamentCost;
}
double filamentCost = printer.Settings.GetValue<double>(SettingsKey.filament_cost);
return loadedGCode.TotalMass(printer) / 1000 * filamentCost;
}
}
}

View file

@ -29,6 +29,7 @@ either expressed or implied, of the FreeBSD Project.
using System;
using System.Linq;
using MatterControl.Printing;
using MatterHackers.Agg;
using MatterHackers.Agg.UI;
using MatterHackers.Localizations;
@ -41,29 +42,27 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
{
private EventHandler unregisterEvents;
private ThemeConfig theme;
private GCodeDetails gcodeDetails;
public GCodeDetailsView(GCodeDetails gcodeDetails, ThemeConfig theme)
public GCodeDetailsView(GCodeFile gCodeMemoryFile, PrinterConfig printerConfig, ThemeConfig theme)
: base(FlowDirection.TopToBottom)
{
this.gcodeDetails = gcodeDetails;
this.theme = theme;
// put in the print time
AddSetting("Print Time".Localize(), gcodeDetails.EstimatedPrintTime);
AddSetting("Print Time".Localize(), gCodeMemoryFile.EstimatedPrintTime());
// show the filament used
AddSetting("Filament Length".Localize(), gcodeDetails.FilamentUsed);
AddSetting("Filament Length".Localize(), gCodeMemoryFile.FilamentUsed(printerConfig));
AddSetting("Filament Volume".Localize(), gcodeDetails.FilamentVolume);
AddSetting("Filament Volume".Localize(), gCodeMemoryFile.FilamentVolume(printerConfig));
// Cost info is only displayed when available - conditionalCostPanel is invisible when cost <= 0
TextWidget costTextWidget = AddSetting("Estimated Cost".Localize(), gcodeDetails.EstimatedCost);
TextWidget costTextWidget = AddSetting("Estimated Cost".Localize(), gCodeMemoryFile.EstimatedCost(printerConfig));
TextWidget massTextWidget = AddSetting("Estimated Mass".Localize(), gcodeDetails.EstimatedMass);
TextWidget massTextWidget = AddSetting("Estimated Mass".Localize(), gCodeMemoryFile.EstimatedMass(printerConfig));
var conditionalCostContainer = costTextWidget.Parent;
conditionalCostContainer.Visible = gcodeDetails.TotalCost > 0;
conditionalCostContainer.Visible = gCodeMemoryFile.TotalCost(printerConfig) > 0;
PrinterSettings.SettingChanged.RegisterEvent((s, e) =>
{
@ -73,32 +72,18 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
|| stringEvent.Data == SettingsKey.filament_diameter
|| stringEvent.Data == SettingsKey.filament_density)
{
massTextWidget.Text = gcodeDetails.EstimatedMass;
conditionalCostContainer.Visible = gcodeDetails.TotalCost > 0;
massTextWidget.Text = gCodeMemoryFile.EstimatedMass(printerConfig);
conditionalCostContainer.Visible = gCodeMemoryFile.TotalCost(printerConfig) > 0;
if (gcodeDetails.TotalCost > 0)
if (gCodeMemoryFile.TotalCost(printerConfig) > 0)
{
costTextWidget.Text = gcodeDetails.EstimatedCost;
costTextWidget.Text = gCodeMemoryFile.EstimatedCost(printerConfig);
}
}
}
}, ref unregisterEvents);
}
public override void OnLoad(EventArgs args)
{
// try to validate the gcode file and warn if it seems invalid.
// for now the definition of invalid is that it has a print time of < 30 seconds
if(gcodeDetails.EstimatedPrintSeconds < 30)
{
var message = "The time to print this G-Code is estimated to be {0} seconds.\n\nPlease check your part for errors if this is unexpected.".Localize();
message = message.FormatWith((int)gcodeDetails.EstimatedPrintSeconds);
StyledMessageBox.ShowMessageBox(message, "Warning, very short print".Localize());
}
base.OnLoad(args);
}
TextWidget AddSetting(string title, string value)
{
var textWidget = new TextWidget(value, textColor: theme.Colors.PrimaryTextColor, pointSize: theme.DefaultFontSize)

View file

@ -28,6 +28,7 @@ either expressed or implied, of the FreeBSD Project.
*/
using System;
using MatterControl.Printing;
using MatterHackers.Agg.UI;
using MatterHackers.Localizations;
using MatterHackers.MatterControl.ConfigurationPage;
@ -38,7 +39,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
{
private ThemeConfig theme;
public GCodeLayerDetailsView(GCodeDetails gcodeDetails, BedConfig sceneContext, ThemeConfig theme)
public GCodeLayerDetailsView(GCodeFile gCodeMemoryFile, BedConfig sceneContext, ThemeConfig theme)
: base(FlowDirection.TopToBottom)
{
this.theme = theme;
@ -54,12 +55,12 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
void UpdateLayerDisplay(object sender, EventArgs e)
{
layerIndex.Text = $"{sceneContext.ActiveLayerIndex + 1}";
layerTime.Text = gcodeDetails.LayerTime(sceneContext.ActiveLayerIndex);
layerTimeToHere.Text = gcodeDetails.LayerTimeToHere(sceneContext.ActiveLayerIndex);
layerTimeFromHere.Text = gcodeDetails.LayerTimeFromeHere(sceneContext.ActiveLayerIndex);
layerHeight.Text = $"{gcodeDetails.GetLayerHeight(sceneContext.ActiveLayerIndex):0.###}";
layerWidth.Text = $"{gcodeDetails.GetLayerTop(sceneContext.ActiveLayerIndex):0.###}";
var fanSpeed = gcodeDetails.GetLayerFanSpeeds(sceneContext.ActiveLayerIndex);
layerTime.Text = gCodeMemoryFile.LayerTime(sceneContext.ActiveLayerIndex);
layerTimeToHere.Text = gCodeMemoryFile.LayerTimeToHere(sceneContext.ActiveLayerIndex);
layerTimeFromHere.Text = gCodeMemoryFile.LayerTimeFromeHere(sceneContext.ActiveLayerIndex);
layerHeight.Text = $"{gCodeMemoryFile.GetLayerHeight(sceneContext.ActiveLayerIndex):0.###}";
layerWidth.Text = $"{gCodeMemoryFile.GetLayerTop(sceneContext.ActiveLayerIndex):0.###}";
var fanSpeed = gCodeMemoryFile.GetLayerFanSpeeds(sceneContext.ActiveLayerIndex);
layerFanSpeeds.Text = string.IsNullOrWhiteSpace(fanSpeed) ? "Unchanged" : fanSpeed;
}

View file

@ -48,6 +48,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
{
public static class SceneActions
{
private static int pastObjectXOffset = 5;
public static List<IObject3D> GetSelectedItems(this InteractiveScene scene)
{
var selectedItem = scene.SelectedItem;
@ -187,6 +188,8 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
{
Clipboard.Instance.SetText("!--IObjectSelection--!");
ApplicationController.ClipboardItem = selectedItem.Clone();
// put it back in right where we cut it from
pastObjectXOffset = 0;
scene.DeleteSelection();
}
@ -199,6 +202,8 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
{
Clipboard.Instance.SetText("!--IObjectSelection--!");
ApplicationController.ClipboardItem = selectedItem.Clone();
// when we copy an object put it back in with a slight offset
pastObjectXOffset = 5;
}
}
@ -224,12 +229,14 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
{
if (Clipboard.Instance.GetText() == "!--IObjectSelection--!")
{
scene.DuplicateItem(ApplicationController.ClipboardItem);
scene.DuplicateItem(pastObjectXOffset, ApplicationController.ClipboardItem);
// each time we put in the object offset it a bit more
pastObjectXOffset += 5;
}
}
}
public static async void DuplicateItem(this InteractiveScene scene, IObject3D sourceItem = null)
public static async void DuplicateItem(this InteractiveScene scene, double xOffset, IObject3D sourceItem = null)
{
if (sourceItem == null)
{
@ -255,6 +262,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
foreach(var item in copyList)
{
var clonedItem = item.Clone();
clonedItem.Translate(xOffset);
// make the name unique
var newName = agg_basics.GetNonCollidingName(item.Name, scene.DescendantsAndSelf().Select((d) => d.Name));
clonedItem.Name = newName;
@ -268,6 +276,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
{
var clonedItem = sourceItem.Clone();
clonedItem.Translate(xOffset);
// make the name unique
var newName = agg_basics.GetNonCollidingName(sourceItem.Name, scene.DescendantsAndSelf().Select((d) => d.Name));
clonedItem.Name = newName;