Merge pull request #3910 from larsbrubaker/master
Check that loaded gcode has a print time > 30 seconds or warn
This commit is contained in:
commit
dadf384ecb
7 changed files with 152 additions and 158 deletions
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue