Merge branch '2.19.2'

This commit is contained in:
LarsBrubaker 2019-02-03 13:34:11 -08:00
commit 6731fdc5d8
168 changed files with 13231 additions and 7124 deletions

View file

@ -132,7 +132,7 @@ namespace MatterHackers.MatterControl
}
else if (AggContext.OperatingSystem == OSType.X11)
{
return "tar.gz";
return "deb";
}
else if (AggContext.OperatingSystem == OSType.Android)
{

View file

@ -71,6 +71,7 @@ namespace MatterHackers.MatterControl
using MatterHackers.MatterControl.Library;
using MatterHackers.MatterControl.PartPreviewWindow;
using MatterHackers.MatterControl.PartPreviewWindow.View3D;
using MatterHackers.MatterControl.Plugins;
using MatterHackers.MatterControl.PrinterControls.PrinterConnections;
using MatterHackers.MatterControl.Tour;
using MatterHackers.PolygonMesh;
@ -596,7 +597,7 @@ namespace MatterHackers.MatterControl
});
});
scene.UndoBuffer.AddAndDo(new ReplaceCommand(selectedItem.Children.ToList(), new List<IObject3D> { newGroup }));
scene.UndoBuffer.AddAndDo(new ReplaceCommand(selectedItem.Children.ToList(), new[] { newGroup }));
newGroup.MakeNameNonColliding();
@ -651,7 +652,6 @@ namespace MatterHackers.MatterControl
var selectedItem = scene.SelectedItem;
var align = new AlignObject3D();
align.AddSelectionAsChildren(scene, selectedItem);
align.Invalidate(new InvalidateArgs(align, InvalidateType.Properties, null));
},
Icon = AggContext.StaticData.LoadIcon("align_left_dark.png", 16, 16, theme.InvertIcons).SetPreMultiply(),
IsEnabled = (scene) => scene.SelectedItem is SelectionGroupObject3D,
@ -674,9 +674,9 @@ namespace MatterHackers.MatterControl
new SceneSelectionSeparator(),
new SceneSelectionOperation()
{
OperationType = typeof(CombineObject3D),
OperationType = typeof(CombineObject3D_2),
TitleResolver = () => "Combine".Localize(),
Action = (sceneContext) => new CombineObject3D().WrapSelectedItemAndSelect(sceneContext.Scene),
Action = (sceneContext) => new CombineObject3D_2().WrapSelectedItemAndSelect(sceneContext.Scene),
Icon = AggContext.StaticData.LoadIcon("combine.png").SetPreMultiply(),
IsEnabled = (scene) =>
{
@ -694,11 +694,15 @@ namespace MatterHackers.MatterControl
},
new SceneSelectionOperation()
{
OperationType = typeof(IntersectionObject3D),
OperationType = typeof(IntersectionObject3D_2),
TitleResolver = () => "Intersect".Localize(),
Action = (sceneContext) => new IntersectionObject3D().WrapSelectedItemAndSelect(sceneContext.Scene),
Action = (sceneContext) => new IntersectionObject3D_2().WrapSelectedItemAndSelect(sceneContext.Scene),
Icon = AggContext.StaticData.LoadIcon("intersect.png"),
IsEnabled = (scene) => scene.SelectedItem is SelectionGroupObject3D,
IsEnabled = (scene) =>
{
var selectedItem = scene.SelectedItem;
return selectedItem != null && selectedItem.VisibleMeshes().Count() > 1;
},
},
new SceneSelectionOperation()
{
@ -717,7 +721,6 @@ namespace MatterHackers.MatterControl
{
var array = new ArrayLinearObject3D();
array.AddSelectionAsChildren(sceneContext.Scene, sceneContext.Scene.SelectedItem);
array.Invalidate(new InvalidateArgs(array, InvalidateType.Properties, null));
},
Icon = AggContext.StaticData.LoadIcon("array_linear.png").SetPreMultiply(),
IsEnabled = (scene) => scene.SelectedItem != null && !(scene.SelectedItem is SelectionGroupObject3D),
@ -730,7 +733,6 @@ namespace MatterHackers.MatterControl
{
var array = new ArrayRadialObject3D();
array.AddSelectionAsChildren(sceneContext.Scene, sceneContext.Scene.SelectedItem);
array.Invalidate(new InvalidateArgs(array, InvalidateType.Properties, null));
},
Icon = AggContext.StaticData.LoadIcon("array_radial.png").SetPreMultiply(),
IsEnabled = (scene) => scene.SelectedItem != null && !(scene.SelectedItem is SelectionGroupObject3D),
@ -743,7 +745,6 @@ namespace MatterHackers.MatterControl
{
var array = new ArrayAdvancedObject3D();
array.AddSelectionAsChildren(sceneContext.Scene, sceneContext.Scene.SelectedItem);
array.Invalidate(new InvalidateArgs(array, InvalidateType.Properties, null));
},
Icon = AggContext.StaticData.LoadIcon("array_advanced.png").SetPreMultiply(),
IsEnabled = (scene) => scene.SelectedItem != null && !(scene.SelectedItem is SelectionGroupObject3D),
@ -751,11 +752,11 @@ namespace MatterHackers.MatterControl
new SceneSelectionSeparator(),
new SceneSelectionOperation()
{
OperationType = typeof(PinchObject3D),
OperationType = typeof(PinchObject3D_2),
TitleResolver = () => "Pinch".Localize(),
Action = (sceneContext) =>
{
var pinch = new PinchObject3D();
var pinch = new PinchObject3D_2();
pinch.WrapSelectedItemAndSelect(sceneContext.Scene);
},
Icon = AggContext.StaticData.LoadIcon("pinch.png", 16, 16, theme.InvertIcons),
@ -763,11 +764,11 @@ namespace MatterHackers.MatterControl
},
new SceneSelectionOperation()
{
OperationType = typeof(CurveObject3D),
OperationType = typeof(CurveObject3D_2),
TitleResolver = () => "Curve".Localize(),
Action = (sceneContext) =>
{
var curve = new CurveObject3D();
var curve = new CurveObject3D_2();
curve.WrapSelectedItemAndSelect(sceneContext.Scene);
},
Icon = AggContext.StaticData.LoadIcon("curve.png", 16, 16, theme.InvertIcons),
@ -781,12 +782,13 @@ namespace MatterHackers.MatterControl
{
var scene = sceneContext.Scene;
var selectedItem = scene.SelectedItem;
scene.SelectedItem = null;
var fit = FitToBoundsObject3D_2.Create(selectedItem.Clone());
fit.MakeNameNonColliding();
using (new SelectionMaintainer(scene))
{
var fit = FitToBoundsObject3D_2.Create(selectedItem.Clone()).Result;
fit.MakeNameNonColliding();
scene.UndoBuffer.AddAndDo(new ReplaceCommand(new List<IObject3D> { selectedItem }, new List<IObject3D> { fit }));
scene.SelectedItem = fit;
scene.UndoBuffer.AddAndDo(new ReplaceCommand(new[] { selectedItem }, new[] { fit }));
}
},
Icon = AggContext.StaticData.LoadIcon("fit.png", 16, 16, theme.InvertIcons),
IsEnabled = (scene) => scene.SelectedItem != null && !(scene.SelectedItem is SelectionGroupObject3D),
@ -1101,6 +1103,7 @@ namespace MatterHackers.MatterControl
this.Library.ContentProviders.Add(new[] { "stl", "obj", "amf", "mcx" }, new MeshContentProvider());
this.Library.ContentProviders.Add("gcode", new GCodeContentProvider());
this.Library.ContentProviders.Add(new[] { "png", "gif", "jpg", "jpeg" }, new ImageContentProvider());
this.Library.ContentProviders.Add(new[] { "scad" }, new OpenScadContentProvider());
this.Graph.RegisterOperation(
new NodeOperation()
@ -1113,9 +1116,20 @@ namespace MatterHackers.MatterControl
{
if (sceneItem is IObject3D imageObject)
{
// TODO: make it look like this (and get rid of all the other stuff)
//scene.Replace(sceneItem, new ImageToPathObject3D(sceneItem.Clone()));
var path = new ImageToPathObject3D();
sceneItem.WrapWith(path, scene);
path.Invalidate(new InvalidateArgs(path, InvalidateType.Properties, null));
var itemClone = sceneItem.Clone();
path.Children.Add(itemClone);
path.Matrix = itemClone.Matrix;
itemClone.Matrix = Matrix4X4.Identity;
scene.UndoBuffer.AddAndDo(new ReplaceCommand(new[] { sceneItem }, new[] { path }));
scene.SelectedItem = null;
scene.SelectedItem = path;
path.Invalidate(InvalidateType.Properties);
}
return Task.CompletedTask;
@ -1132,11 +1146,12 @@ namespace MatterHackers.MatterControl
ResultType = typeof(TranslateObject3D),
Operation = (sceneItem, scene) =>
{
var selectedItem = scene.SelectedItem;
scene.SelectedItem = null;
var scale = new TranslateObject3D();
scale.WrapItem(selectedItem, scene.UndoBuffer);
scene.SelectedItem = scale;
var items = scene.GetSelectedItems();
using (new SelectionMaintainer(scene))
{
var translate = new TranslateObject3D();
translate.WrapItems(items, scene.UndoBuffer);
}
return Task.CompletedTask;
},
@ -1152,11 +1167,12 @@ namespace MatterHackers.MatterControl
ResultType = typeof(RotateObject3D_2),
Operation = (sceneItem, scene) =>
{
var selectedItem = scene.SelectedItem;
scene.SelectedItem = null;
var rotate = new RotateObject3D_2();
rotate.WrapItem(selectedItem, scene.UndoBuffer);
scene.SelectedItem = rotate;
var items = scene.GetSelectedItems();
using (new SelectionMaintainer(scene))
{
var rotate = new RotateObject3D_2();
rotate.WrapItems(items, scene.UndoBuffer);
}
return Task.CompletedTask;
},
@ -1172,12 +1188,12 @@ namespace MatterHackers.MatterControl
ResultType = typeof(ScaleObject3D),
Operation = (sceneItem, scene) =>
{
var selectedItem = scene.SelectedItem;
scene.SelectedItem = null;
var scale = new ScaleObject3D();
scale.WrapItem(selectedItem, scene.UndoBuffer);
scene.SelectedItem = scale;
var items = scene.GetSelectedItems();
using (new SelectionMaintainer(scene))
{
var scale = new ScaleObject3D();
scale.WrapItems(items, scene.UndoBuffer);
}
return Task.CompletedTask;
},
IconCollector = (theme) => AggContext.StaticData.LoadIcon("scale_32x32.png", 16, 16, theme.InvertIcons)
@ -1192,8 +1208,7 @@ namespace MatterHackers.MatterControl
ResultType = typeof(ComponentObject3D),
Operation = (sceneItem, scene) =>
{
var imageObject = scene.SelectedItem;
scene.SelectedItem = null;
var imageObject = sceneItem.Clone() as ImageObject3D;
var path = new ImageToPathObject3D();
path.Children.Add(imageObject);
@ -1224,35 +1239,30 @@ namespace MatterHackers.MatterControl
}
};
// Invalidate image to kick off rebuild of ImageConverter stack
imageObject.Invalidate(new InvalidateArgs(imageObject, InvalidateType.Image, null));
component.Matrix = imageObject.Matrix;
imageObject.Matrix = Matrix4X4.Identity;
// Swap original item with new wrapping component
scene.Children.Modify(children =>
using (new SelectionMaintainer(scene))
{
children.Remove(imageObject);
children.Add(component);
});
scene.SelectedItem = component;
scene.UndoBuffer.AddAndDo(new ReplaceCommand(new[] { sceneItem }, new[] { component }));
} // Invalidate image to kick off rebuild of ImageConverter stack
imageObject.Invalidate(InvalidateType.Image);
return Task.CompletedTask;
},
IconCollector = (theme) => AggContext.StaticData.LoadIcon("140.png", 16, 16, theme.InvertIcons)
});
this.Graph.PrimaryOperations.Add(typeof(ImageObject3D), new List<NodeOperation> { this.Graph.Operations["ImageConverter"] });
this.Graph.RegisterOperation(
new NodeOperation()
{
OperationID = "Mirror",
Title = "Mirror".Localize(),
MappedTypes = new List<Type> { typeof(IObject3D) },
ResultType = typeof(MirrorObject3D),
ResultType = typeof(MirrorObject3D_2),
Operation = (sceneItem, scene) =>
{
var mirror = new MirrorObject3D();
var mirror = new MirrorObject3D_2();
mirror.WrapSelectedItemAndSelect(scene);
return Task.CompletedTask;
@ -1278,24 +1288,24 @@ namespace MatterHackers.MatterControl
}
// Dump selection forcing collapse of selection group
scene.SelectedItem = null;
var component = new ComponentObject3D
using (new SelectionMaintainer(scene))
{
Name = "New Component",
Finalized = false
};
var component = new ComponentObject3D
{
Name = "New Component",
Finalized = false
};
// Copy an selected item into the component as a clone
component.Children.Modify(children =>
{
children.AddRange(items.Select(o => o.Clone()));
});
// Copy an selected item into the component as a clone
component.Children.Modify(children =>
{
children.AddRange(items.Select(o => o.Clone()));
});
component.MakeNameNonColliding();
component.MakeNameNonColliding();
scene.UndoBuffer.AddAndDo(new ReplaceCommand(items, new[] { component }));
scene.SelectedItem = component;
scene.UndoBuffer.AddAndDo(new ReplaceCommand(items, new[] { component }));
}
return Task.CompletedTask;
},
@ -1351,8 +1361,17 @@ namespace MatterHackers.MatterControl
if (sceneItem is IPathObject imageObject)
{
var extrude = new LinearExtrudeObject3D();
sceneItem.WrapWith(extrude, scene);
extrude.Invalidate(new InvalidateArgs(extrude, InvalidateType.Properties, null));
var itemClone = sceneItem.Clone();
extrude.Children.Add(itemClone);
extrude.Matrix = itemClone.Matrix;
itemClone.Matrix = Matrix4X4.Identity;
using (new SelectionMaintainer(scene))
{
scene.UndoBuffer.AddAndDo(new ReplaceCommand(new[] { sceneItem }, new[] { extrude }));
}
extrude.Invalidate(InvalidateType.Properties);
}
return Task.CompletedTask;
@ -1372,8 +1391,16 @@ namespace MatterHackers.MatterControl
if (sceneItem is IPathObject imageObject)
{
var smoothPath = new SmoothPathObject3D();
sceneItem.WrapWith(smoothPath, scene);
smoothPath.Invalidate(new InvalidateArgs(smoothPath, InvalidateType.Properties, null));
var itemClone = sceneItem.Clone();
smoothPath.Children.Add(itemClone);
smoothPath.Matrix = itemClone.Matrix;
itemClone.Matrix = Matrix4X4.Identity;
using (new SelectionMaintainer(scene))
{
scene.UndoBuffer.AddAndDo(new ReplaceCommand(new[] { sceneItem }, new[] { smoothPath }));
}
smoothPath.Invalidate(InvalidateType.Properties);
}
return Task.CompletedTask;
@ -1393,8 +1420,16 @@ namespace MatterHackers.MatterControl
if (sceneItem is IPathObject imageObject)
{
var inflatePath = new InflatePathObject3D();
sceneItem.WrapWith(inflatePath, scene);
inflatePath.Invalidate(new InvalidateArgs(inflatePath, InvalidateType.Properties, null));
var itemClone = sceneItem.Clone();
inflatePath.Children.Add(itemClone);
inflatePath.Matrix = itemClone.Matrix;
itemClone.Matrix = Matrix4X4.Identity;
using (new SelectionMaintainer(scene))
{
scene.UndoBuffer.AddAndDo(new ReplaceCommand(new[] { sceneItem }, new[] { inflatePath }));
}
inflatePath.Invalidate(InvalidateType.Properties);
}
return Task.CompletedTask;
@ -1420,7 +1455,7 @@ namespace MatterHackers.MatterControl
};
newChild.Matrix = Matrix4X4.Identity;
baseMesh.Children.Add(newChild);
baseMesh.Invalidate(new InvalidateArgs(baseMesh, InvalidateType.Properties, null));
baseMesh.Invalidate(InvalidateType.Properties);
scene.UndoBuffer.AddAndDo(
new ReplaceCommand(
@ -1459,6 +1494,12 @@ namespace MatterHackers.MatterControl
mappedEditors.Add(editor);
}
}
this.Graph.PrimaryOperations.Add(typeof(ImageObject3D), new List<NodeOperation> { this.Graph.Operations["ImageConverter"], this.Graph.Operations["ImageToPath"], });
this.Graph.PrimaryOperations.Add(typeof(ImageToPathObject3D), new List<NodeOperation> { this.Graph.Operations["LinearExtrude"], this.Graph.Operations["SmoothPath"], this.Graph.Operations["InflatePath"] });
this.Graph.PrimaryOperations.Add(typeof(SmoothPathObject3D), new List<NodeOperation> { this.Graph.Operations["LinearExtrude"], this.Graph.Operations["InflatePath"] });
this.Graph.PrimaryOperations.Add(typeof(InflatePathObject3D), new List<NodeOperation> { this.Graph.Operations["LinearExtrude"] });
this.Graph.PrimaryOperations.Add(typeof(Object3D), new List<NodeOperation> { this.Graph.Operations["Scale"] });
}
public void Connection_ErrorReported(object sender, string line)
@ -2339,7 +2380,7 @@ namespace MatterHackers.MatterControl
AddPrintersTabRightElement?.Invoke(this, new WidgetSourceEventArgs(sourceExentionArea));
}
public async Task PrintPart(EditContext editContext, PrinterConfig printer, IProgress<ProgressStatus> reporter, CancellationToken cancellationToken, bool overrideAllowGCode = false)
public async Task PrintPart(EditContext editContext, PrinterConfig printer, IProgress<ProgressStatus> reporter, CancellationToken cancellationToken)
{
var partFilePath = editContext.SourceFilePath;
var gcodeFilePath = editContext.GCodeFilePath(printer);
@ -2364,19 +2405,12 @@ namespace MatterHackers.MatterControl
printer.Connection.PrintingItemName = printItemName;
var errors = printer.ValidateSettings();
if(errors.Count > 0)
if(errors.Any(e => e.ErrorLevel == ValidationErrorLevel.Error))
{
this.ShowValidationErrors("Export Error".Localize(), errors);
}
else // there are no errors continue printing
{
// last let's check if there is any support in the scene and if it looks like it is needed
if (GenerateSupportPanel.RequiresSupport(printer.Bed.Scene))
{
var warning = "Some of the parts appear to require support. Consider canceling this print then adding support to get the best results possible.".Localize();
StyledMessageBox.ShowMessageBox(warning, "Warning: Support Required".Localize());
}
// check that current bed temp is within 10 degrees of leveling temp
var enabled = printer.Settings.GetValue<bool>(SettingsKey.print_leveling_enabled);
var required = printer.Settings.GetValue<bool>(SettingsKey.print_leveling_required_to_print);
@ -2411,47 +2445,53 @@ If you experience adhesion problems, please re-run leveling."
string hideGCodeWarning = ApplicationSettings.Instance.get(ApplicationSettingsKey.HideGCodeWarning);
if (Path.GetExtension(partFilePath).ToUpper() == ".GCODE"
&& hideGCodeWarning == null
&& !overrideAllowGCode)
if (Path.GetExtension(partFilePath).ToUpper() == ".GCODE")
{
var hideGCodeWarningCheckBox = new CheckBox("Don't remind me again".Localize())
if (hideGCodeWarning != "true")
{
TextColor = this.Theme.TextColor,
Margin = new BorderDouble(top: 6, left: 6),
HAnchor = Agg.UI.HAnchor.Left
};
hideGCodeWarningCheckBox.Click += (sender, e) =>
{
if (hideGCodeWarningCheckBox.Checked)
var hideGCodeWarningCheckBox = new CheckBox("Don't remind me again".Localize())
{
ApplicationSettings.Instance.set(ApplicationSettingsKey.HideGCodeWarning, "true");
}
else
TextColor = this.Theme.TextColor,
Margin = new BorderDouble(top: 6, left: 6),
HAnchor = Agg.UI.HAnchor.Left
};
hideGCodeWarningCheckBox.Click += (sender, e) =>
{
ApplicationSettings.Instance.set(ApplicationSettingsKey.HideGCodeWarning, null);
}
};
if (hideGCodeWarningCheckBox.Checked)
{
ApplicationSettings.Instance.set(ApplicationSettingsKey.HideGCodeWarning, "true");
}
else
{
ApplicationSettings.Instance.set(ApplicationSettingsKey.HideGCodeWarning, null);
}
};
UiThread.RunOnIdle(() =>
{
StyledMessageBox.ShowMessageBox(
(messageBoxResponse) =>
{
if (messageBoxResponse)
UiThread.RunOnIdle(() =>
{
StyledMessageBox.ShowMessageBox(
(messageBoxResponse) =>
{
if (messageBoxResponse)
{
printer.Connection.CommunicationState = CommunicationStates.PreparingToPrint;
this.ArchiveAndStartPrint(partFilePath, gcodeFilePath, printer);
}
},
"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[]
{
printer.Connection.CommunicationState = CommunicationStates.PreparingToPrint;
this.ArchiveAndStartPrint(partFilePath, gcodeFilePath, printer);
}
},
"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[]
{
hideGCodeWarningCheckBox
},
StyledMessageBox.MessageType.YES_NO);
});
},
StyledMessageBox.MessageType.YES_NO);
});
}
else
{
printer.Connection.CommunicationState = CommunicationStates.PreparingToPrint;
this.ArchiveAndStartPrint(partFilePath, gcodeFilePath, printer);
}
}
else
{
@ -2484,28 +2524,19 @@ If you experience adhesion problems, please re-run leveling."
{
UiThread.RunOnIdle(() =>
{
// Project to newline separated Error/Details/Location string
var formattedErrors = errors.Select(err =>
var dialogPage = new DialogPage("Close".Localize())
{
string location = null;
string valueDetails = null;
HAnchor = HAnchor.Stretch,
WindowTitle = windowTitle,
HeaderText = "Action Required".Localize()
};
if (err is SettingsValidationError settingsError)
{
location = settingsError.Location;
valueDetails = settingsError.ValueDetails;
}
dialogPage.ContentRow.AddChild(new ValidationErrorsPanel(errors, AppContext.Theme)
{
HAnchor = HAnchor.Stretch
});
// Conditionally combine Error/Details/Location when not empty
return err.Error +
((string.IsNullOrWhiteSpace(err.Details)) ? "" : $"\n\n{err.Details}") +
((string.IsNullOrWhiteSpace(valueDetails)) ? "" : $"\n\n{valueDetails}") +
((string.IsNullOrWhiteSpace(location)) ? "" : $"\n\n{location}");
}).ToArray();
StyledMessageBox.ShowMessageBox(
string.Join("\n__________________\n\n", formattedErrors),
windowTitle);
DialogWindow.Show(dialogPage);
});
}
@ -2644,20 +2675,31 @@ If you experience adhesion problems, please re-run leveling."
{
// read the last few k of the file and see if it says "filament used". We use this marker to tell if the file finished writing
int bufferSize = 32000;
int padding = 100;
using (Stream fileStream = new FileStream(gcodeFilePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
byte[] buffer = new byte[bufferSize];
fileStream.Seek(Math.Max(0, fileStream.Length - bufferSize), SeekOrigin.Begin);
int numBytesRead = fileStream.Read(buffer, 0, bufferSize);
fileStream.Close();
string fileEnd = System.Text.Encoding.UTF8.GetString(buffer);
if (fileEnd.Contains("filament used"))
int i = 1;
bool readToStart = false;
do
{
await printer.Connection.StartPrint(gcodeFilePath);
MonitorPrintTask(printer);
return;
}
var buffer = new byte[bufferSize + 100];
// fileStream.Seek(Math.Max(0, fileStream.Length - bufferSize), SeekOrigin.Begin);
fileStream.Position = Math.Max(0, fileStream.Length - (bufferSize * i++) - padding);
readToStart = fileStream.Position == 0;
int numBytesRead = fileStream.Read(buffer, 0, bufferSize + padding);
string fileEnd = System.Text.Encoding.UTF8.GetString(buffer);
if (fileEnd.Contains("filament used"))
{
await printer.Connection.StartPrint(gcodeFilePath);
MonitorPrintTask(printer);
return;
}
} while (!readToStart);
}
}
}
@ -3046,6 +3088,7 @@ If you experience adhesion problems, please re-run leveling."
private static Stopwatch timer;
public static bool EnableF5Collect { get; set; }
public static bool EnableNetworkTraffic { get; set; } = true;
public static SystemWindow LoadRootWindow(int width, int height)
{

View file

@ -39,11 +39,13 @@ using Newtonsoft.Json;
namespace MatterHackers.MatterControl
{
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using MatterHackers.Agg;
using MatterHackers.DataConverters3D;
using MatterHackers.GCodeVisualizer;
using MatterHackers.Localizations;
using MatterHackers.MatterControl.DataStorage;
using MatterHackers.MatterControl.Library;
using MatterHackers.MatterControl.PartPreviewWindow;
using MatterHackers.MeshVisualizer;
@ -229,6 +231,68 @@ namespace MatterHackers.MatterControl
return insertionGroup;
}
public async void AddToPlate(string[] filesToLoadIncludingZips)
{
if (filesToLoadIncludingZips?.Any() == true)
{
var scene = this.Scene;
// When a single GCode file is selected, swap the plate to the new GCode content
if (filesToLoadIncludingZips.Count() == 1
&& filesToLoadIncludingZips.FirstOrDefault() is string firstFilePath
&& Path.GetExtension(firstFilePath).ToUpper() == ".GCODE")
{
// Special case for GCode which changes loaded scene to special mode for GCode
await this.LoadContent(
new EditContext()
{
SourceItem = new FileSystemFileItem(firstFilePath),
ContentStore = null // No content store for GCode, otherwise PlatingHistory
});
return;
}
var filePaths = await Task.Run(() =>
{
var filesToLoad = new List<string>();
foreach (string loadedFileName in filesToLoadIncludingZips)
{
string extension = Path.GetExtension(loadedFileName).ToUpper();
if ((extension != ""
&& extension != ".ZIP"
&& extension != ".GCODE"
&& ApplicationController.Instance.Library.IsContentFileType(loadedFileName))
)
{
filesToLoad.Add(loadedFileName);
}
else if (extension == ".ZIP")
{
List<PrintItem> partFiles = ProjectFileHandler.ImportFromProjectArchive(loadedFileName);
if (partFiles != null)
{
foreach (PrintItem part in partFiles)
{
string itemExtension = Path.GetExtension(part.FileLocation).ToUpper();
if (itemExtension != ".GCODE")
{
filesToLoad.Add(part.FileLocation);
}
}
}
}
}
return filesToLoad;
});
var itemCache = new Dictionary<string, IObject3D>();
this.AddToPlate(filePaths.Select(f => new FileSystemFileItem(f)));
}
}
/// <summary>
/// Loads content to the bed and prepares edit/persistence context for use
/// </summary>
@ -525,7 +589,7 @@ namespace MatterHackers.MatterControl
0,
1,
this.GetRenderType,
MeshViewerWidget.GetExtruderColor);
MaterialRendering.Color);
GCodeRenderer.ExtruderWidth = this.Printer.Settings.GetValue<double>(SettingsKey.nozzle_diameter);

View file

@ -103,14 +103,17 @@ namespace MatterHackers.MatterControl
});
};
popupMenu.CreateSeparator();
menuItem = popupMenu.CreateMenuItem("Check For Update".Localize(), AggContext.StaticData.LoadIcon("update.png", 16, 16, menuTheme.InvertIcons));
menuItem.Click += (s, e) => UiThread.RunOnIdle(() =>
if (Application.EnableNetworkTraffic)
{
UpdateControlData.Instance.CheckForUpdate();
DialogWindow.Show<CheckForUpdatesPage>();
});
popupMenu.CreateSeparator();
menuItem = popupMenu.CreateMenuItem("Check For Update".Localize(), AggContext.StaticData.LoadIcon("update.png", 16, 16, menuTheme.InvertIcons));
menuItem.Click += (s, e) => UiThread.RunOnIdle(() =>
{
UpdateControlData.Instance.CheckForUpdate();
DialogWindow.Show<CheckForUpdatesPage>();
});
}
popupMenu.CreateSeparator();

View file

@ -119,7 +119,7 @@ namespace MatterHackers.MatterControl
}
string fileHashCode = HashGenerator.ComputeFileSHA1(fileLocation);
long settingsHashCode = printer.Settings.GetLongHashCode();
ulong settingsHashCode = printer.Settings.GetLongHashCode();
return Path.Combine(
ApplicationDataStorage.Instance.GCodeOutputPath,

View file

@ -29,20 +29,59 @@ either expressed or implied, of the FreeBSD Project.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using MatterHackers.Agg;
using MatterHackers.Agg.UI;
using MatterHackers.Localizations;
using MatterHackers.MatterControl.DesignTools;
using MatterHackers.MatterControl.PartPreviewWindow;
using MatterHackers.MatterControl.SlicerConfiguration;
namespace MatterHackers.MatterControl
{
public static class SettingsValidation
{
public static List<ValidationError> ValidateSettings(this PrinterConfig printer)
/// <summary>
/// Validates the printer settings satisfy all requirements
/// </summary>
/// <param name="printer">The printer to validate</param>
/// <returns>A list of all warnings and errors</returns>
public static List<ValidationError> ValidateSettings(this PrinterConfig printer, SettingsContext settings = null)
{
var settings = printer.Settings;
if (settings == null)
{
settings = new SettingsContext(printer, null, NamedSettingsLayers.All);
}
var errors = new List<ValidationError>();
// last let's check if there is any support in the scene and if it looks like it is needed
var supportGenerator = new SupportGenerator(printer.Bed.Scene);
if (supportGenerator.RequiresSupport())
{
errors.Add(new ValidationError()
{
Error = "Unsupported Parts Detected".Localize(),
Details = "Some parts are unsupported and require support structures to print correctly".Localize(),
ErrorLevel = ValidationErrorLevel.Warning,
FixAction = new NamedAction()
{
Title = "Generate Supports".Localize(),
Action = () =>
{
// Find and InvokeClick on the Generate Supports toolbar button
var sharedParent = ApplicationController.Instance.DragDropData.View3DWidget.Parents<GuiWidget>().FirstOrDefault(w => w.Name == "View3DContainerParent");
if (sharedParent != null)
{
var supportsPopup = sharedParent.FindDescendant("Support SplitButton");
supportsPopup.InvokeClick();
}
}
}
});
}
try
{
if (settings.GetValue<bool>(SettingsKey.validate_layer_height))
@ -306,6 +345,57 @@ namespace MatterHackers.MatterControl
return errors;
}
/// <summary>
/// Validates printer satisfies all requirements
/// </summary>
/// <param name="printer">The printer to validate</param>
/// <returns>A list of all warnings and errors</returns>
public static List<ValidationError> Validate(this PrinterConfig printer)
{
var errors = new List<ValidationError>();
var printerIsConnected = printer.Connection.CommunicationState != PrinterCommunication.CommunicationStates.Disconnected;
if (!printerIsConnected)
{
errors.Add(new ValidationError()
{
Error = "Printer Disconnected".Localize(),
Details = "Connect to your printer to continue".Localize()
});
}
// TODO: Consider splitting out each individual requirement in PrinterNeedsToRunSetup and reporting validation in a more granular fashion
if (ApplicationController.PrinterNeedsToRunSetup(printer))
{
errors.Add(new ValidationError()
{
Error = "Printer Setup Required".Localize(),
Details = "Printer Setup must be run before printing".Localize(),
FixAction = new NamedAction()
{
ID = "SetupPrinter",
Title = "Setup".Localize() + "...",
Action = () =>
{
UiThread.RunOnIdle(async () =>
{
await ApplicationController.Instance.PrintPart(
printer.Bed.EditContext,
printer,
null,
CancellationToken.None);
});
}
}
});
}
// Concat printer and settings errors
errors.AddRange(printer.ValidateSettings());
return errors;
}
private static string GetSettingsName(string settingsKey)
{
var settingData = PrinterSettings.SettingsData[settingsKey];

View file

@ -103,9 +103,7 @@ namespace MatterHackers.MatterControl.ConfigurationPage.PrintLeveling
UiThread.RunOnIdle(() => NextButton.InvokeClick());
}
if (numberOfSamples-- > 0
&& !this.HasBeenClosed)
else if (!this.HasBeenClosed)
{
// add the next request for probe
printer.Connection.QueueLine("G30");

View file

@ -56,7 +56,7 @@ namespace MatterHackers.MatterControl.ConfigurationPage.PrintLeveling
+ " • " + "Remove the paper".Localize() + "\n"
+ "\n"
+ "If you wish to re-calibrate your probe in the future:".Localize() + "\n"
+ " 1. Select the 'Controls' tab on the right" + "\n"
+ " 1. Select the 'Controls' tab on the right".Localize() + "\n"
+ " 2. Look for the calibration section (pictured below)".Localize() + "\n";
contentRow.AddChild(this.CreateTextField(calibrated));

View file

@ -36,33 +36,6 @@ using MatterHackers.MatterControl;
namespace MatterHackers.Agg.UI
{
public class NamedAction
{
public string Title { get; set; }
public string Shortcut { get; set; }
public Action Action { get; set; }
public ImageBuffer Icon { get; set; }
public Func<bool> IsEnabled { get; set; }
public string ID { get; internal set; }
}
public class ActionSeparator : NamedAction
{
}
public class NamedBoolAction : NamedAction
{
public Func<bool> GetIsActive { get; set; }
public Action<bool> SetIsActive { get; set; }
}
public abstract class LocalizedAction
{
public Func<string> TitleResolver { get; set; }
public string Title => this.TitleResolver?.Invoke();
public ImageBuffer Icon { get; set; }
}
public class SceneSelectionOperation : LocalizedAction
{
public Action<BedConfig> Action { get; set; }

View file

@ -212,6 +212,11 @@ namespace MatterHackers.MatterControl.CustomWidgets
}
public override string ToString()
{
return textWidget?.Text ?? "";
}
#region Properties
public bool Checked { get; set; }

View file

@ -27,8 +27,9 @@ of the authors and should not be interpreted as representing official policies,
either expressed or implied, of the FreeBSD Project.
*/
using System;
using System.Threading.Tasks;
using MatterHackers.Agg;
using MatterHackers.Agg.UI;
using MatterHackers.Agg.VertexSource;
using MatterHackers.DataConverters3D;
using MatterHackers.MatterControl.CustomWidgets;
@ -44,92 +45,93 @@ namespace MatterHackers.MatterControl.DesignTools
{
}
public static BrailleCardObject3D Create()
public static async Task<BrailleCardObject3D> Create()
{
var item = new BrailleCardObject3D();
item.Rebuild(null);
await item.Rebuild();
return item;
}
public override bool CanFlatten => true;
public char Letter { get; set; } = 'a';
public double BaseHeight { get; set; } = 4;
public override void OnInvalidate(InvalidateArgs invalidateType)
public override async void OnInvalidate(InvalidateArgs invalidateType)
{
if (invalidateType.InvalidateType == InvalidateType.Properties
if (invalidateType.InvalidateType.HasFlag(InvalidateType.Properties)
&& invalidateType.Source == this)
{
Rebuild(null);
}
else
{
base.OnInvalidate(invalidateType);
await Rebuild();
}
base.OnInvalidate(invalidateType);
}
public void Rebuild(UndoBuffer undoBuffer)
override public async Task Rebuild()
{
using (RebuildLock())
{
var aabb = this.GetAxisAlignedBoundingBox();
this.Children.Modify(list =>
using (new CenterAndHeightMantainer(this))
{
this.Children.Modify(list =>
{
list.Clear();
});
var brailleLetter = new BrailleObject3D()
{
TextToEncode = Letter.ToString(),
BaseHeight = BaseHeight,
};
brailleLetter.Rebuild(null);
this.Children.Add(brailleLetter);
var brailleLetter = new BrailleObject3D()
{
TextToEncode = Letter.ToString(),
BaseHeight = BaseHeight,
};
await brailleLetter.Rebuild();
this.Children.Add(brailleLetter);
var textObject = new TextObject3D()
{
PointSize = 46,
Color = Color.LightBlue,
NameToWrite = Letter.ToString(),
Height = BaseHeight
};
var textObject = new TextObject3D()
{
PointSize = 46,
Color = Color.LightBlue,
NameToWrite = Letter.ToString(),
Height = BaseHeight
};
textObject.Invalidate(new InvalidateArgs(textObject, InvalidateType.Properties, null));
IObject3D letterObject = new RotateObject3D(textObject, MathHelper.Tau / 4);
letterObject = new AlignObject3D(letterObject, FaceAlign.Bottom | FaceAlign.Front, brailleLetter, FaceAlign.Top | FaceAlign.Front, 0, 0, 3.5);
letterObject = new SetCenterObject3D(letterObject, brailleLetter.GetCenter(), true, false, false);
this.Children.Add(letterObject);
await textObject.Rebuild();
IObject3D letterObject = new RotateObject3D_2(textObject, Vector3.UnitX, -90);
await letterObject.Rebuild();
var scaleRatio = Math.Max(letterObject.XSize() / 17, letterObject.ZSize() / 17);
if (scaleRatio > 1)
{
letterObject = new ScaleObject3D(letterObject, 1.0/scaleRatio, 1, 1.0/scaleRatio);
}
letterObject = new AlignObject3D(letterObject, FaceAlign.Bottom | FaceAlign.Front, brailleLetter, FaceAlign.Top | FaceAlign.Front, 0, 0, 3.5);
letterObject = new SetCenterObject3D(letterObject, brailleLetter.GetCenter(), true, false, false);
this.Children.Add(letterObject);
var basePath = new RoundedRect(0, 0, 22, 34, 3)
{
ResolutionScale = 10
};
var basePath = new RoundedRect(0, 0, 22, 34, 3)
{
ResolutionScale = 10
};
IObject3D basePlate = new Object3D()
{
Mesh = VertexSourceToMesh.Extrude(basePath, BaseHeight),
Matrix = Matrix4X4.CreateRotationX(MathHelper.Tau / 4)
};
IObject3D basePlate = new Object3D()
{
Mesh = VertexSourceToMesh.Extrude(basePath, BaseHeight),
Matrix = Matrix4X4.CreateRotationX(MathHelper.Tau / 4)
};
basePlate = new AlignObject3D(basePlate, FaceAlign.Bottom | FaceAlign.Back, brailleLetter, FaceAlign.Bottom | FaceAlign.Back);
basePlate = new SetCenterObject3D(basePlate, brailleLetter.GetCenter(), true, false, false);
this.Children.Add(basePlate);
basePlate = new AlignObject3D(basePlate, FaceAlign.Bottom | FaceAlign.Back, brailleLetter, FaceAlign.Bottom | FaceAlign.Back);
basePlate = new SetCenterObject3D(basePlate, brailleLetter.GetCenter(), true, false, false);
this.Children.Add(basePlate);
IObject3D underline = new CubeObject3D(basePlate.XSize(), .2, 1);
underline = new AlignObject3D(underline, FaceAlign.Bottom, brailleLetter, FaceAlign.Top);
underline = new AlignObject3D(underline, FaceAlign.Back | FaceAlign.Left, basePlate, FaceAlign.Front | FaceAlign.Left, 0, .01);
this.Children.Add(underline);
if (aabb.ZSize > 0)
{
// If the part was already created and at a height, maintain the height.
PlatingHelper.PlaceMeshAtHeight(this, aabb.MinXYZ.Z);
IObject3D underline = CubeObject3D.Create(basePlate.XSize(), .2, 1);
underline = new AlignObject3D(underline, FaceAlign.Bottom, brailleLetter, FaceAlign.Top);
underline = new AlignObject3D(underline, FaceAlign.Back | FaceAlign.Left, basePlate, FaceAlign.Front | FaceAlign.Left, 0, .01);
this.Children.Add(underline);
}
}
Invalidate(new InvalidateArgs(this, InvalidateType.Content));
Invalidate(InvalidateType.Children);
}
}
}

View file

@ -29,6 +29,7 @@ either expressed or implied, of the FreeBSD Project.
using System.ComponentModel;
using System.IO;
using System.Threading.Tasks;
using MatterHackers.Agg;
using MatterHackers.Agg.Font;
using MatterHackers.Agg.Platform;
@ -55,14 +56,14 @@ namespace MatterHackers.MatterControl.DesignTools
public BrailleObject3D(string textToEncode)
{
TextToEncode = textToEncode;
Rebuild(null);
Rebuild();
}
public static BrailleObject3D Create()
{
var item = new BrailleObject3D();
item.Rebuild(null);
item.Rebuild();
return item;
}
@ -84,190 +85,184 @@ namespace MatterHackers.MatterControl.DesignTools
static TypeFace typeFace = TypeFace.LoadFrom(AggContext.StaticData.ReadAllText(Path.Combine("Fonts", "Braille.svg")));
public override void OnInvalidate(InvalidateArgs invalidateType)
public override async void OnInvalidate(InvalidateArgs invalidateType)
{
if (invalidateType.InvalidateType == InvalidateType.Properties
if (invalidateType.InvalidateType.HasFlag(InvalidateType.Properties)
&& invalidateType.Source == this)
{
Rebuild(null);
}
else
{
base.OnInvalidate(invalidateType);
await Rebuild();
}
base.OnInvalidate(invalidateType);
}
public void Rebuild(UndoBuffer undoBuffer)
override public Task Rebuild()
{
using (RebuildLock())
{
var aabb = this.GetAxisAlignedBoundingBox();
this.Children.Modify(list =>
using (new CenterAndHeightMantainer(this))
{
this.Children.Modify(list =>
{
list.Clear();
});
var brailleText = TextToEncode;
if (UseGrade2)
{
brailleText = BrailleGrade2.ConvertString(brailleText);
}
var brailleText = TextToEncode;
if (UseGrade2)
{
brailleText = BrailleGrade2.ConvertString(brailleText);
}
double pointSize = 18.5;
double pointsToMm = 0.352778;
IObject3D textObject = new Object3D();
var offest = 0.0;
double pointSize = 18.5;
double pointsToMm = 0.352778;
IObject3D textObject = new Object3D();
var offest = 0.0;
TypeFacePrinter textPrinter;
if (RenderAsBraille)
{
textPrinter = new TypeFacePrinter(brailleText, new StyledTypeFace(typeFace, pointSize));
}
else
{
textPrinter = new TypeFacePrinter(brailleText, new StyledTypeFace(ApplicationController.GetTypeFace(NamedTypeFace.Liberation_Mono), pointSize));
}
foreach (var letter in brailleText.ToCharArray())
{
IObject3D letterObject;
TypeFacePrinter letterPrinter;
TypeFacePrinter textPrinter;
if (RenderAsBraille)
{
letterPrinter = new TypeFacePrinter(letter.ToString(), new StyledTypeFace(typeFace, pointSize));
var scalledLetterPrinter = new VertexSourceApplyTransform(letterPrinter, Affine.NewScaling(pointsToMm));
// add all the spheres to letterObject
letterObject = new Object3D();
var vertexCount = 0;
var positionSum = Vector2.Zero;
var lastPosition = Vector2.Zero;
// find each dot outline and get it's center and place a sphere there
foreach (var vertex in scalledLetterPrinter.Vertices())
{
switch (vertex.command)
{
case Agg.ShapePath.FlagsAndCommand.Stop:
case Agg.ShapePath.FlagsAndCommand.EndPoly:
case Agg.ShapePath.FlagsAndCommand.FlagClose:
case Agg.ShapePath.FlagsAndCommand.MoveTo:
if (vertexCount > 0)
{
var center = positionSum / vertexCount;
double radius = 1.44 / 2;// (center - lastPosition).Length;
var sphere = new HalfSphereObject3D(radius * 2, 15)
{
Color = Color.LightBlue
};
sphere.Translate(center.X, center.Y);
letterObject.Children.Add(sphere);
}
vertexCount = 0;
positionSum = Vector2.Zero;
break;
case Agg.ShapePath.FlagsAndCommand.Curve3:
case Agg.ShapePath.FlagsAndCommand.Curve4:
case Agg.ShapePath.FlagsAndCommand.LineTo:
vertexCount++;
lastPosition = vertex.position;
positionSum += lastPosition;
break;
}
}
textPrinter = new TypeFacePrinter(brailleText, new StyledTypeFace(typeFace, pointSize));
}
else
{
letterPrinter = new TypeFacePrinter(letter.ToString(), new StyledTypeFace(ApplicationController.GetTypeFace(NamedTypeFace.Liberation_Mono), pointSize));
var scalledLetterPrinter = new VertexSourceApplyTransform(letterPrinter, Affine.NewScaling(pointsToMm));
letterObject = new Object3D()
{
Mesh = VertexSourceToMesh.Extrude(scalledLetterPrinter, 1),
Color = Color.LightBlue
};
textPrinter = new TypeFacePrinter(brailleText, new StyledTypeFace(ApplicationController.GetTypeFace(NamedTypeFace.Liberation_Mono), pointSize));
}
letterObject.Matrix = Matrix4X4.CreateTranslation(offest, 0, 0);
textObject.Children.Add(letterObject);
offest += letterPrinter.GetSize(letter.ToString()).X * pointsToMm;
}
// add a plate under the dots
var padding = .9 * pointSize * pointsToMm / 2;
var size = textPrinter.LocalBounds * pointsToMm;
// make the base
var basePath = new VertexStorage();
basePath.MoveTo(0, 0);
basePath.LineTo(size.Width + padding, 0);
basePath.LineTo(size.Width + padding, size.Height + padding);
basePath.LineTo(padding, size.Height + padding);
basePath.LineTo(0, size.Height);
IObject3D basePlate = new Object3D()
{
Mesh = VertexSourceToMesh.Extrude(basePath, BaseHeight)
};
basePlate = new AlignObject3D(basePlate, FaceAlign.Top, textObject, FaceAlign.Bottom, 0, 0, .01);
basePlate = new AlignObject3D(basePlate, FaceAlign.Left | FaceAlign.Front,
size.Left - padding / 2,
size.Bottom - padding / 2);
this.Children.Add(basePlate);
basePlate.Matrix *= Matrix4X4.CreateRotationX(MathHelper.Tau / 4);
// add an optional chain hook
if (AddHook)
{
// x 10 to make it smoother
double edgeWidth = 3;
double height = basePlate.ZSize();
IVertexSource leftSideObject = new RoundedRect(0, 0, height / 2, height, 0)
foreach (var letter in brailleText.ToCharArray())
{
ResolutionScale = 10
IObject3D letterObject;
TypeFacePrinter letterPrinter;
if (RenderAsBraille)
{
letterPrinter = new TypeFacePrinter(letter.ToString(), new StyledTypeFace(typeFace, pointSize));
var scalledLetterPrinter = new VertexSourceApplyTransform(letterPrinter, Affine.NewScaling(pointsToMm));
// add all the spheres to letterObject
letterObject = new Object3D();
var vertexCount = 0;
var positionSum = Vector2.Zero;
var lastPosition = Vector2.Zero;
// find each dot outline and get it's center and place a sphere there
foreach (var vertex in scalledLetterPrinter.Vertices())
{
switch (vertex.command)
{
case Agg.ShapePath.FlagsAndCommand.Stop:
case Agg.ShapePath.FlagsAndCommand.EndPoly:
case Agg.ShapePath.FlagsAndCommand.FlagClose:
case Agg.ShapePath.FlagsAndCommand.MoveTo:
if (vertexCount > 0)
{
var center = positionSum / vertexCount;
double radius = 1.44 / 2;// (center - lastPosition).Length;
var sphere = new HalfSphereObject3D(radius * 2, 15)
{
Color = Color.LightBlue
};
sphere.Translate(center.X, center.Y);
letterObject.Children.Add(sphere);
}
vertexCount = 0;
positionSum = Vector2.Zero;
break;
case Agg.ShapePath.FlagsAndCommand.Curve3:
case Agg.ShapePath.FlagsAndCommand.Curve4:
case Agg.ShapePath.FlagsAndCommand.LineTo:
vertexCount++;
lastPosition = vertex.position;
positionSum += lastPosition;
break;
}
}
}
else
{
letterPrinter = new TypeFacePrinter(letter.ToString(), new StyledTypeFace(ApplicationController.GetTypeFace(NamedTypeFace.Liberation_Mono), pointSize));
var scalledLetterPrinter = new VertexSourceApplyTransform(letterPrinter, Affine.NewScaling(pointsToMm));
letterObject = new Object3D()
{
Mesh = VertexSourceToMesh.Extrude(scalledLetterPrinter, 1),
Color = Color.LightBlue
};
}
letterObject.Matrix = Matrix4X4.CreateTranslation(offest, 0, 0);
textObject.Children.Add(letterObject);
offest += letterPrinter.GetSize(letter.ToString()).X * pointsToMm;
}
// add a plate under the dots
var padding = .9 * pointSize * pointsToMm / 2;
var size = textPrinter.LocalBounds * pointsToMm;
// make the base
var basePath = new VertexStorage();
basePath.MoveTo(0, 0);
basePath.LineTo(size.Width + padding, 0);
basePath.LineTo(size.Width + padding, size.Height + padding);
basePath.LineTo(padding, size.Height + padding);
basePath.LineTo(0, size.Height);
IObject3D basePlate = new Object3D()
{
Mesh = VertexSourceToMesh.Extrude(basePath, BaseHeight)
};
IVertexSource cicleObject = new Ellipse(0, 0, height / 2, height / 2)
basePlate = new AlignObject3D(basePlate, FaceAlign.Top, textObject, FaceAlign.Bottom, 0, 0, .01);
basePlate = new AlignObject3D(basePlate, FaceAlign.Left | FaceAlign.Front,
size.Left - padding / 2,
size.Bottom - padding / 2);
this.Children.Add(basePlate);
basePlate.Matrix *= Matrix4X4.CreateRotationX(MathHelper.Tau / 4);
// add an optional chain hook
if (AddHook)
{
ResolutionScale = 10
};
// x 10 to make it smoother
double edgeWidth = 3;
double height = basePlate.ZSize();
IVertexSource leftSideObject = new RoundedRect(0, 0, height / 2, height, 0)
{
ResolutionScale = 10
};
cicleObject = new Align2D(cicleObject, Side2D.Left | Side2D.Bottom, leftSideObject, Side2D.Left | Side2D.Bottom, -.01);
IVertexSource holeObject = new Ellipse(0, 0, height / 2 - edgeWidth, height / 2 - edgeWidth)
{
ResolutionScale = 10
};
holeObject = new SetCenter2D(holeObject, cicleObject.GetBounds().Center);
IVertexSource cicleObject = new Ellipse(0, 0, height / 2, height / 2)
{
ResolutionScale = 10
};
IVertexSource hookPath = leftSideObject.Plus(cicleObject);
hookPath = hookPath.Minus(holeObject);
cicleObject = new Align2D(cicleObject, Side2D.Left | Side2D.Bottom, leftSideObject, Side2D.Left | Side2D.Bottom, -.01);
IVertexSource holeObject = new Ellipse(0, 0, height / 2 - edgeWidth, height / 2 - edgeWidth)
{
ResolutionScale = 10
};
holeObject = new SetCenter2D(holeObject, cicleObject.GetBounds().Center);
IObject3D chainHook = new Object3D()
{
Mesh = VertexSourceToMesh.Extrude(hookPath, BaseHeight),
Matrix = Matrix4X4.CreateRotationX(MathHelper.Tau / 4)
};
IVertexSource hookPath = leftSideObject.Plus(cicleObject);
hookPath = hookPath.Minus(holeObject);
chainHook = new AlignObject3D(chainHook, FaceAlign.Left | FaceAlign.Bottom | FaceAlign.Back, basePlate, FaceAlign.Right | FaceAlign.Bottom | FaceAlign.Back, -.01);
IObject3D chainHook = new Object3D()
{
Mesh = VertexSourceToMesh.Extrude(hookPath, BaseHeight),
Matrix = Matrix4X4.CreateRotationX(MathHelper.Tau / 4)
};
this.Children.Add(chainHook);
}
chainHook = new AlignObject3D(chainHook, FaceAlign.Left | FaceAlign.Bottom | FaceAlign.Back, basePlate, FaceAlign.Right | FaceAlign.Bottom | FaceAlign.Back, -.01);
// add the object that is the dots
this.Children.Add(textObject);
textObject.Matrix *= Matrix4X4.CreateRotationX(MathHelper.Tau / 4);
this.Children.Add(chainHook);
}
if (aabb.ZSize > 0)
{
// If the part was already created and at a height, maintain the height.
PlatingHelper.PlaceMeshAtHeight(this, aabb.MinXYZ.Z);
// add the object that is the dots
this.Children.Add(textObject);
textObject.Matrix *= Matrix4X4.CreateRotationX(MathHelper.Tau / 4);
}
}
Invalidate(new InvalidateArgs(this, InvalidateType.Content));
Invalidate(InvalidateType.Children);
return Task.CompletedTask;
}
}
}

View file

@ -65,28 +65,29 @@ namespace MatterHackers.MatterControl.Plugins.Lithophane
public Vector3 ImageOffset { get; private set; } = Vector3.Zero;
public override void OnInvalidate(InvalidateArgs invalidateType)
public override void OnInvalidate(InvalidateArgs invalidateArgs)
{
if ((invalidateType.InvalidateType == InvalidateType.Content
|| invalidateType.InvalidateType == InvalidateType.Matrix
|| invalidateType.InvalidateType == InvalidateType.Mesh)
&& invalidateType.Source != this
var invalidateType = invalidateArgs.InvalidateType;
if ((invalidateType.HasFlag(InvalidateType.Children)
|| invalidateArgs.InvalidateType.HasFlag(InvalidateType.Matrix)
|| invalidateArgs.InvalidateType.HasFlag(InvalidateType.Mesh))
&& invalidateArgs.Source != this
&& !RebuildLocked)
{
Rebuild(null);
Rebuild();
}
else if (invalidateType.InvalidateType == InvalidateType.Properties
&& invalidateType.Source == this)
else if (invalidateArgs.InvalidateType.HasFlag(InvalidateType.Properties)
&& invalidateArgs.Source == this)
{
Rebuild(null);
Rebuild();
}
else
{
base.OnInvalidate(invalidateType);
base.OnInvalidate(invalidateArgs);
}
}
private void Rebuild(UndoBuffer undoBuffer)
override public Task Rebuild()
{
this.DebugDepth("Rebuild");
var activeImage = AggContext.ImageIO.LoadImage(this.Image.AssetPath);
@ -113,8 +114,12 @@ namespace MatterHackers.MatterControl.Plugins.Lithophane
// Apply offset
this.Matrix *= Matrix4X4.CreateTranslation(-this.ImageOffset);
Invalidate(InvalidateType.Children);
return Task.CompletedTask;
});
return Task.CompletedTask;
}
}
}

View file

@ -27,8 +27,12 @@ of the authors and should not be interpreted as representing official policies,
either expressed or implied, of the FreeBSD Project.
*/
/*********************************************************************/
/**************************** OBSOLETE! ******************************/
/************************ USE NEWER VERSION **************************/
/*********************************************************************/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
@ -36,11 +40,10 @@ using MatterHackers.Agg;
using MatterHackers.Agg.UI;
using MatterHackers.DataConverters3D;
using MatterHackers.Localizations;
using MatterHackers.MatterControl.DesignTools;
using MatterHackers.PolygonMesh;
namespace MatterHackers.MatterControl.PartPreviewWindow.View3D
{
[Obsolete("Use CombineObject3D_2 instead", false)]
public class CombineObject3D : MeshWrapperObject3D
{
public CombineObject3D()
@ -50,27 +53,29 @@ namespace MatterHackers.MatterControl.PartPreviewWindow.View3D
public override async void OnInvalidate(InvalidateArgs invalidateType)
{
if ((invalidateType.InvalidateType == InvalidateType.Content
|| invalidateType.InvalidateType == InvalidateType.Matrix
|| invalidateType.InvalidateType == InvalidateType.Mesh)
if ((invalidateType.InvalidateType.HasFlag(InvalidateType.Children)
|| invalidateType.InvalidateType.HasFlag(InvalidateType.Matrix)
|| invalidateType.InvalidateType.HasFlag(InvalidateType.Mesh))
&& invalidateType.Source != this
&& !RebuildLocked)
{
await Rebuild();
invalidateType = new InvalidateArgs(this, InvalidateType.Content, invalidateType.UndoBuffer);
}
else if (invalidateType.InvalidateType == InvalidateType.Properties
else if (invalidateType.InvalidateType.HasFlag(InvalidateType.Properties)
&& invalidateType.Source == this)
{
await Rebuild();
invalidateType = new InvalidateArgs(this, InvalidateType.Content, invalidateType.UndoBuffer);
}
base.OnInvalidate(invalidateType);
else
{
base.OnInvalidate(invalidateType);
}
}
public override Task Rebuild()
{
this.DebugDepth("Rebuild");
var rebuildLocks = this.RebuilLockAll();
// spin up a task to remove holes from the objects in the group
@ -90,12 +95,8 @@ namespace MatterHackers.MatterControl.PartPreviewWindow.View3D
{
}
UiThread.RunOnIdle(() =>
{
rebuildLocks.Dispose();
base.Invalidate(new InvalidateArgs(this, InvalidateType.Content));
});
rebuildLocks.Dispose();
Invalidate(InvalidateType.Children);
return Task.CompletedTask;
});
}
@ -138,7 +139,6 @@ namespace MatterHackers.MatterControl.PartPreviewWindow.View3D
{
first.Mesh = result;
}
item.Visible = false;
percentCompleted += amountPerOperation;
progressStatus.Progress0To1 = percentCompleted;

View file

@ -27,18 +27,23 @@ of the authors and should not be interpreted as representing official policies,
either expressed or implied, of the FreeBSD Project.
*/
/*********************************************************************/
/**************************** OBSOLETE! ******************************/
/************************ USE NEWER VERSION **************************/
/*********************************************************************/
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using MatterHackers.Agg;
using MatterHackers.Agg.UI;
using MatterHackers.DataConverters3D;
using MatterHackers.Localizations;
using MatterHackers.MatterControl.DesignTools.Operations;
using MatterHackers.MatterControl.PartPreviewWindow;
using MatterHackers.MatterControl.PartPreviewWindow.View3D;
using MatterHackers.MeshVisualizer;
@ -103,30 +108,69 @@ namespace MatterHackers.MatterControl.DesignTools
}
}
[Obsolete("Use CurveObject3D_2 instead", false)]
public class CurveObject3D : MeshWrapperObject3D, IEditorDraw
{
public double Diameter { get; set; } = double.MinValue;
[Range(0, 100, ErrorMessage = "Value for {0} must be between {1} and {2}.")]
[Description("Where to start the bend as a percent of the width of the part")]
public double StartPercent { get; set; } = 50;
[DisplayName("Bend Up")]
public bool BendCcw { get; set; } = true;
[Range(3, 360, ErrorMessage = "Value for {0} must be between {1} and {2}.")]
[Description("Ensures the rotated part has a minimum number of sides per complete rotation")]
public double MinSidesPerRotation { get; set; } = 3;
// holds where we rotate the object
Vector2 rotationCenter;
private Vector2 rotationCenter;
public CurveObject3D()
{
Name = "Curve".Localize();
}
private void Rebuild(UndoBuffer undoBuffer)
[DisplayName("Bend Up")]
public bool BendCcw { get; set; } = true;
public double Diameter { get; set; } = double.MinValue;
[Range(3, 360, ErrorMessage = "Value for {0} must be between {1} and {2}.")]
[Description("Ensures the rotated part has a minimum number of sides per complete rotation")]
public double MinSidesPerRotation { get; set; } = 3;
[Range(0, 100, ErrorMessage = "Value for {0} must be between {1} and {2}.")]
[Description("Where to start the bend as a percent of the width of the part")]
public double StartPercent { get; set; } = 50;
public void DrawEditor(object sender, DrawEventArgs e)
{
if (sender is InteractionLayer layer
&& layer.Scene.SelectedItem != null
&& layer.Scene.SelectedItem.DescendantsAndSelf().Where((i) => i == this).Any())
{
// we want to measure the
var currentMatrixInv = Matrix.Inverted;
var aabb = this.GetAxisAlignedBoundingBox(currentMatrixInv);
layer.World.RenderCylinderOutline(this.WorldMatrix(), new Vector3(rotationCenter, aabb.Center.Z), Diameter, aabb.ZSize, 30, Color.Red);
}
// turn the lighting back on
GL.Enable(EnableCap.Lighting);
}
public override void OnInvalidate(InvalidateArgs invalidateType)
{
if ((invalidateType.InvalidateType.HasFlag(InvalidateType.Children)
|| invalidateType.InvalidateType.HasFlag(InvalidateType.Matrix)
|| invalidateType.InvalidateType.HasFlag(InvalidateType.Mesh))
&& invalidateType.Source != this
&& !RebuildLocked)
{
Rebuild();
}
else if (invalidateType.InvalidateType.HasFlag(InvalidateType.Properties)
&& invalidateType.Source == this)
{
Rebuild();
}
else
{
base.OnInvalidate(invalidateType);
}
}
override public Task Rebuild()
{
this.DebugDepth("Rebuild");
bool propertyUpdated = Diameter == double.MinValue;
@ -231,49 +275,13 @@ namespace MatterHackers.MatterControl.DesignTools
Matrix = currentMatrix;
}
base.OnInvalidate(new InvalidateArgs(this, InvalidateType.Mesh));
if(propertyUpdated)
Invalidate(InvalidateType.Mesh);
if (propertyUpdated)
{
base.OnInvalidate(new InvalidateArgs(this, InvalidateType.Properties));
}
}
public override void OnInvalidate(InvalidateArgs invalidateType)
{
if ((invalidateType.InvalidateType == InvalidateType.Content
|| invalidateType.InvalidateType == InvalidateType.Matrix
|| invalidateType.InvalidateType == InvalidateType.Mesh)
&& invalidateType.Source != this
&& !RebuildLocked)
{
Rebuild(null);
}
else if (invalidateType.InvalidateType == InvalidateType.Properties
&& invalidateType.Source == this)
{
Rebuild(null);
}
else
{
base.OnInvalidate(invalidateType);
}
}
public void DrawEditor(object sender, DrawEventArgs e)
{
if (sender is InteractionLayer layer
&& layer.Scene.SelectedItem != null
&& layer.Scene.SelectedItem.DescendantsAndSelf().Where((i) => i == this).Any())
{
// we want to measure the
var currentMatrixInv = Matrix.Inverted;
var aabb = this.GetAxisAlignedBoundingBox(currentMatrixInv);
layer.World.RenderCylinderOutline(this.WorldMatrix(), new Vector3(rotationCenter, aabb.Center.Z), Diameter, aabb.ZSize, 30, Color.Red);
Invalidate(InvalidateType.Properties);
}
// turn the lighting back on
GL.Enable(EnableCap.Lighting);
return Task.CompletedTask;
}
}
}

View file

@ -27,9 +27,15 @@ of the authors and should not be interpreted as representing official policies,
either expressed or implied, of the FreeBSD Project.
*/
/*********************************************************************/
/**************************** OBSOLETE! ******************************/
/************************ USE NEWER VERSION **************************/
/*********************************************************************/
using System;
using System.ComponentModel;
using System.Linq;
using System.Threading.Tasks;
using MatterHackers.Agg;
using MatterHackers.Agg.UI;
using MatterHackers.DataConverters3D;
@ -96,7 +102,7 @@ namespace MatterHackers.MatterControl.DesignTools.Operations
list.AddRange(ScaleItem.Children);
});
}
Invalidate(new InvalidateArgs(this, InvalidateType.Content));
Invalidate(InvalidateType.Children);
}
public override void Remove(UndoBuffer undoBuffer)
@ -117,23 +123,23 @@ namespace MatterHackers.MatterControl.DesignTools.Operations
});
}
Invalidate(new InvalidateArgs(this, InvalidateType.Content));
Invalidate(InvalidateType.Children);
}
public override void OnInvalidate(InvalidateArgs invalidateType)
{
if ((invalidateType.InvalidateType == InvalidateType.Content
|| invalidateType.InvalidateType == InvalidateType.Matrix
|| invalidateType.InvalidateType == InvalidateType.Mesh)
if ((invalidateType.InvalidateType.HasFlag(InvalidateType.Children)
|| invalidateType.InvalidateType.HasFlag(InvalidateType.Matrix)
|| invalidateType.InvalidateType.HasFlag(InvalidateType.Mesh))
&& invalidateType.Source != this
&& !RebuildLocked)
{
Rebuild(null);
Rebuild();
}
else if (invalidateType.InvalidateType == InvalidateType.Properties
else if (invalidateType.InvalidateType.HasFlag(InvalidateType.Properties)
&& invalidateType.Source == this)
{
Rebuild(null);
Rebuild();
}
else
{
@ -159,23 +165,19 @@ namespace MatterHackers.MatterControl.DesignTools.Operations
return fitToBounds;
}
public void Rebuild(UndoBuffer undoBuffer)
override public Task Rebuild()
{
this.DebugDepth("Rebuild");
using (RebuildLock())
{
var aabb = this.GetAxisAlignedBoundingBox();
AdjustChildSize(null, null);
if (aabb.ZSize > 0)
using (new CenterAndHeightMantainer(this))
{
// If the part was already created and at a height, maintain the height.
PlatingHelper.PlaceMeshAtHeight(this, aabb.MinXYZ.Z);
AdjustChildSize(null, null);
}
}
base.Invalidate(new InvalidateArgs(this, InvalidateType.Matrix));
Invalidate(InvalidateType.Matrix);
return Task.CompletedTask;
}
public override AxisAlignedBoundingBox GetAxisAlignedBoundingBox(Matrix4X4 matrix)

View file

@ -27,8 +27,12 @@ of the authors and should not be interpreted as representing official policies,
either expressed or implied, of the FreeBSD Project.
*/
/*********************************************************************/
/**************************** OBSOLETE! ******************************/
/************************ USE NEWER VERSION **************************/
/*********************************************************************/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
@ -36,11 +40,10 @@ using MatterHackers.Agg;
using MatterHackers.Agg.UI;
using MatterHackers.DataConverters3D;
using MatterHackers.Localizations;
using MatterHackers.MatterControl.DesignTools;
using MatterHackers.PolygonMesh;
namespace MatterHackers.MatterControl.PartPreviewWindow.View3D
{
[Obsolete("Use IntersectionObject3D_2 instead", false)]
public class IntersectionObject3D : MeshWrapperObject3D
{
public IntersectionObject3D()
@ -50,23 +53,23 @@ namespace MatterHackers.MatterControl.PartPreviewWindow.View3D
public override async void OnInvalidate(InvalidateArgs invalidateType)
{
if ((invalidateType.InvalidateType == InvalidateType.Content
|| invalidateType.InvalidateType == InvalidateType.Matrix
|| invalidateType.InvalidateType == InvalidateType.Mesh)
if ((invalidateType.InvalidateType.HasFlag(InvalidateType.Children)
|| invalidateType.InvalidateType.HasFlag(InvalidateType.Matrix)
|| invalidateType.InvalidateType.HasFlag(InvalidateType.Mesh))
&& invalidateType.Source != this
&& !RebuildLocked)
{
await Rebuild();
invalidateType = new InvalidateArgs(this, InvalidateType.Content, invalidateType.UndoBuffer);
}
else if (invalidateType.InvalidateType == InvalidateType.Properties
else if (invalidateType.InvalidateType.HasFlag(InvalidateType.Properties)
&& invalidateType.Source == this)
{
await Rebuild();
invalidateType = new InvalidateArgs(this, InvalidateType.Content, invalidateType.UndoBuffer);
}
base.OnInvalidate(invalidateType);
else
{
base.OnInvalidate(invalidateType);
}
}
public override Task Rebuild()
@ -82,23 +85,16 @@ namespace MatterHackers.MatterControl.PartPreviewWindow.View3D
{
Intersect(cancellationToken, reporter);
}
catch { }
UiThread.RunOnIdle(() =>
catch
{
rebuildLocks.Dispose();
base.Invalidate(new InvalidateArgs(this, InvalidateType.Content));
});
}
rebuildLocks.Dispose();
Invalidate(InvalidateType.Children);
return Task.CompletedTask;
});
}
public void Intersect()
{
Intersect(CancellationToken.None, null);
}
private void Intersect(CancellationToken cancellationToken, IProgress<ProgressStatus> reporter)
{
ResetMeshWrapperMeshes(Object3DPropertyFlags.All, cancellationToken);

View file

@ -27,18 +27,18 @@ of the authors and should not be interpreted as representing official policies,
either expressed or implied, of the FreeBSD Project.
*/
using System;
using System.ComponentModel;
using System.Linq;
/*********************************************************************/
/**************************** OBSOLETE! ******************************/
/************************ USE NEWER VERSION **************************/
/*********************************************************************/
using System.Threading;
using MatterHackers.Agg.UI;
using System.Threading.Tasks;
using MatterHackers.DataConverters3D;
using MatterHackers.Localizations;
using MatterHackers.MatterControl.DesignTools.Operations;
using MatterHackers.MatterControl.PartPreviewWindow.View3D;
using MatterHackers.PolygonMesh;
using MatterHackers.VectorMath;
using Newtonsoft.Json;
namespace MatterHackers.MatterControl.DesignTools
{
@ -53,7 +53,7 @@ namespace MatterHackers.MatterControl.DesignTools
Name = "Mirror".Localize();
}
private void Rebuild(UndoBuffer undoBuffer)
public override Task Rebuild()
{
this.DebugDepth("Rebuild");
@ -88,30 +88,30 @@ namespace MatterHackers.MatterControl.DesignTools
item.meshCopy.Mesh.Transform(meshCopyToThis * mirrorMatrix * meshCopyToThis.Inverted);
item.meshCopy.Mesh.ReverseFaces();
item.meshCopy.Mesh.CalculateNormals();
item.meshCopy.Mesh.MarkAsChanged();
}
this.Matrix = oldMatrix;
}
base.Invalidate(new InvalidateArgs(this, InvalidateType.Content));
Invalidate(InvalidateType.Children);
return Task.CompletedTask;
}
public override void OnInvalidate(InvalidateArgs invalidateType)
{
if ((invalidateType.InvalidateType == InvalidateType.Content
|| invalidateType.InvalidateType == InvalidateType.Matrix
|| invalidateType.InvalidateType == InvalidateType.Mesh)
if ((invalidateType.InvalidateType.HasFlag(InvalidateType.Children)
|| invalidateType.InvalidateType.HasFlag(InvalidateType.Matrix)
|| invalidateType.InvalidateType.HasFlag(InvalidateType.Mesh))
&& invalidateType.Source != this
&& !RebuildLocked)
{
Rebuild(null);
Rebuild();
}
else if (invalidateType.InvalidateType == InvalidateType.Properties
else if (invalidateType.InvalidateType.HasFlag(InvalidateType.Properties)
&& invalidateType.Source == this)
{
Rebuild(null);
Rebuild();
}
else
{

View file

@ -27,17 +27,25 @@ of the authors and should not be interpreted as representing official policies,
either expressed or implied, of the FreeBSD Project.
*/
/*********************************************************************/
/**************************** OBSOLETE! ******************************/
/************************ USE NEWER VERSION **************************/
/*********************************************************************/
using MatterHackers.Agg.UI;
using MatterHackers.DataConverters3D;
using MatterHackers.Localizations;
using MatterHackers.MatterControl.PartPreviewWindow.View3D;
using MatterHackers.PolygonMesh;
using MatterHackers.VectorMath;
using System;
using System.ComponentModel;
using System.Threading;
using System.Threading.Tasks;
namespace MatterHackers.MatterControl.DesignTools
{
[Obsolete("Use PinchObject3D_2 instead", false)]
public class PinchObject3D : MeshWrapperObject3D
{
public PinchObject3D()
@ -50,18 +58,18 @@ namespace MatterHackers.MatterControl.DesignTools
public override void OnInvalidate(InvalidateArgs invalidateType)
{
if ((invalidateType.InvalidateType == InvalidateType.Content
|| invalidateType.InvalidateType == InvalidateType.Matrix
|| invalidateType.InvalidateType == InvalidateType.Mesh)
if ((invalidateType.InvalidateType.HasFlag(InvalidateType.Children)
|| invalidateType.InvalidateType.HasFlag(InvalidateType.Matrix)
|| invalidateType.InvalidateType.HasFlag(InvalidateType.Mesh))
&& invalidateType.Source != this
&& !RebuildLocked)
{
Rebuild(null);
Rebuild();
}
else if (invalidateType.InvalidateType == InvalidateType.Properties
else if (invalidateType.InvalidateType.HasFlag(InvalidateType.Properties)
&& invalidateType.Source == this)
{
Rebuild(null);
Rebuild();
}
else
{
@ -69,7 +77,7 @@ namespace MatterHackers.MatterControl.DesignTools
}
}
private void Rebuild(UndoBuffer undoBuffer)
override public Task Rebuild()
{
this.DebugDepth("Rebuild");
@ -117,7 +125,8 @@ namespace MatterHackers.MatterControl.DesignTools
Matrix = currentMatrix;
}
base.Invalidate(new InvalidateArgs(this, InvalidateType.Content));
Invalidate(InvalidateType.Children);
return Task.CompletedTask;
}
}
}

View file

@ -27,11 +27,14 @@ of the authors and should not be interpreted as representing official policies,
either expressed or implied, of the FreeBSD Project.
*/
using MatterHackers.Agg.UI;
/*********************************************************************/
/**************************** OBSOLETE! ******************************/
/************************ USE NEWER VERSION **************************/
/*********************************************************************/
using MatterHackers.DataConverters3D;
using MatterHackers.Localizations;
using MatterHackers.VectorMath;
using Newtonsoft.Json;
using System;
using System.ComponentModel;
using System.Threading.Tasks;
@ -77,44 +80,38 @@ namespace MatterHackers.MatterControl.DesignTools.Operations
using (RebuildLock())
{
var startingAabb = this.GetAxisAlignedBoundingBox();
// remove whatever rotation has been applied (they go in reverse order)
Matrix = Matrix4X4.Identity;
// add the current rotation
Matrix = this.ApplyAtPosition(startingAabb.Center, Matrix4X4.CreateRotationX(MathHelper.DegreesToRadians(RotationXDegrees)));
Matrix = this.ApplyAtPosition(startingAabb.Center, Matrix4X4.CreateRotationY(MathHelper.DegreesToRadians(RotationYDegrees)));
Matrix = this.ApplyAtPosition(startingAabb.Center, Matrix4X4.CreateRotationZ(MathHelper.DegreesToRadians(RotationZDegrees)));
if (startingAabb.ZSize > 0)
using (new CenterAndHeightMantainer(this))
{
// If the part was already created and at a height, maintain the height.
PlatingHelper.PlaceMeshAtHeight(this, startingAabb.MinXYZ.Z);
var startingAabb = this.GetAxisAlignedBoundingBox();
// remove whatever rotation has been applied (they go in reverse order)
Matrix = Matrix4X4.Identity;
// add the current rotation
Matrix = this.ApplyAtPosition(startingAabb.Center, Matrix4X4.CreateRotationX(MathHelper.DegreesToRadians(RotationXDegrees)));
Matrix = this.ApplyAtPosition(startingAabb.Center, Matrix4X4.CreateRotationY(MathHelper.DegreesToRadians(RotationYDegrees)));
Matrix = this.ApplyAtPosition(startingAabb.Center, Matrix4X4.CreateRotationZ(MathHelper.DegreesToRadians(RotationZDegrees)));
}
}
Invalidate(new InvalidateArgs(this, InvalidateType.Matrix, null));
Invalidate(InvalidateType.Matrix);
return Task.CompletedTask;
}
public override void OnInvalidate(InvalidateArgs invalidateType)
public override async void OnInvalidate(InvalidateArgs invalidateType)
{
if ((invalidateType.InvalidateType == InvalidateType.Content
|| invalidateType.InvalidateType == InvalidateType.Matrix
|| invalidateType.InvalidateType == InvalidateType.Mesh)
if ((invalidateType.InvalidateType.HasFlag(InvalidateType.Children)
|| invalidateType.InvalidateType.HasFlag(InvalidateType.Matrix)
|| invalidateType.InvalidateType.HasFlag(InvalidateType.Mesh))
&& invalidateType.Source != this
&& !RebuildLocked)
{
Rebuild();
invalidateType = new InvalidateArgs(this, InvalidateType.Matrix, invalidateType.UndoBuffer);
await Rebuild();
}
else if (invalidateType.InvalidateType == InvalidateType.Properties
else if (invalidateType.InvalidateType.HasFlag(InvalidateType.Properties)
&& invalidateType.Source == this)
{
Rebuild();
invalidateType = new InvalidateArgs(this, InvalidateType.Matrix, invalidateType.UndoBuffer);
await Rebuild();
}
base.OnInvalidate(invalidateType);

View file

@ -0,0 +1,286 @@
/*
Copyright (c) 2019, Lars Brubaker, John Lewin
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
The views and conclusions contained in the software and documentation are those
of the authors and should not be interpreted as representing official policies,
either expressed or implied, of the FreeBSD Project.
*/
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using MatterHackers.Agg;
using MatterHackers.Agg.Platform;
using MatterHackers.Agg.UI;
using MatterHackers.DataConverters3D;
using MatterHackers.Localizations;
using MatterHackers.MatterControl.CustomWidgets;
using MatterHackers.MatterControl.DataStorage;
using MatterHackers.MatterControl.PartPreviewWindow;
using MatterHackers.PolygonMesh.Processors;
using Newtonsoft.Json;
namespace MatterHackers.MatterControl.Library
{
public class OpenSCADBuilder : IObject3DEditor
{
private View3DWidget view3DWidget;
private OpenScadObject3D item;
public string Name => "Builder";
public bool Unlocked { get; } = true;
private string compilerPath = UserSettings.Instance.get(UserSettingsKey.OpenScadPath) ?? "/usr/bin/openscad";
public IEnumerable<Type> SupportedTypes() => new Type[]
{
typeof(OpenScadObject3D)
};
public static Dictionary<string, string> LoadVariablesFromAsset(string assetName)
{
string assetPath = Path.Combine(ApplicationDataStorage.Instance.ApplicationLibraryDataPath, assetName + ".scad");
string assetInfoPath = Path.ChangeExtension(assetPath, ".json");
string script = File.ReadAllText(assetPath);
string json = File.ReadAllText(assetInfoPath);
var info = JsonConvert.DeserializeObject<MetaInfo>(json);
var dictionary = new Dictionary<string, string>();
foreach (var field in info.Fields)
{
var match = Regex.Match(script, $"({field.Key}\\s*=\\s*)(\\d+)");
if (match.Success)
{
dictionary[field.Key] = match.Groups[2].Value;
}
}
return dictionary;
}
public GuiWidget Create(IObject3D object3D, ThemeConfig theme)
{
this.item = object3D as OpenScadObject3D;
var mainContainer = new FlowLayoutWidget(FlowDirection.TopToBottom)
{
HAnchor = HAnchor.Absolute,
Width = 225
};
FlowLayoutWidget actionButtons = new FlowLayoutWidget();
mainContainer.AddChild(actionButtons);
// TODO: This should use the same renaming and asset system as stl/amf assets
string assetInfoPath = Path.ChangeExtension(item.ScriptPath, ".json");
bool isGenerator = File.Exists(assetInfoPath);
if (isGenerator)
{
BuildGeneratorUI(theme, mainContainer, item.ScriptPath, assetInfoPath);
}
else
{
var editButton = new TextButton("Edit".Localize(), theme)
{
Margin = 5,
ToolTipText = "Edit OpenSCAD script".Localize()
};
editButton.Click += (s, e) =>
{
Process.Start(item.ScriptPath);
};
actionButtons.AddChild(editButton);
var updateButton = new TextButton("Update".Localize(), theme)
{
Margin = 5,
ToolTipText = "Compile model".Localize()
};
if (!File.Exists(compilerPath))
{
updateButton.Enabled = false;
updateButton.ToolTipText = "OpenSCAD not installed".Localize();
}
updateButton.Click += async (s, e) =>
{
using (var meshStream = AggContext.StaticData.OpenStream(Path.Combine("Stls", "openscad_logo.stl")))
{
this.item.Mesh = Object3D.Load(meshStream, ".stl", CancellationToken.None).Mesh;
}
// TODO: Use assets system
string outputPath = Path.ChangeExtension(item.ScriptPath, ".stl");
int err = await Task.Run(() => ExecuteScript(item.ScriptPath, outputPath));
if (err == 0)
{
// Reload the mesh
this.item.Mesh = StlProcessing.Load(outputPath, CancellationToken.None);
}
};
actionButtons.AddChild(updateButton);
}
return mainContainer;
}
private void BuildGeneratorUI(ThemeConfig theme, FlowLayoutWidget mainContainer, string assetPath, string assetInfoPath)
{
// TODO: When an OpenSCAD script is added to the scene, we need to load the script and extract
// the hard-coded variable values into the .Variables property for their default values or the
// meta info file would need to include this hard-coded info
// Load the OpenSCAD script
// Load the script meta info
// Walk the UI elements exposed by the meta info, constructing widgets bound to replacement data
// When the build button is clicked, perform the replacements defined by the meta info and widgets.
// - Walk the meta info
// - Grab the values from the linked widgets
// - Load the script text
// - Perform the regex replaces against the script source
// - Execute the script, writing the results to a target file
// - Use the mesh loader to load the mesh
// - Replace the mesh in the scene with the newly generated content
string scriptText = File.ReadAllText(assetPath);
MetaInfo info = null;
string json = File.ReadAllText(assetInfoPath);
info = JsonConvert.DeserializeObject<MetaInfo>(json);
if (info != null)
{
FlowLayoutWidget rowContainer;
foreach (var field in info.Fields)
{
string key = field.Key;
string latest;
this.item.Variables.TryGetValue(field.Key, out latest);
rowContainer = CreateSettingsRow(field.Title, theme);
if (field.Type == "text")
{
double val;
double.TryParse(latest, out val);
var editor = new MHNumberEdit(val, theme, pixelWidth: 50 * GuiWidget.DeviceScale, allowDecimals: true, increment: .05)
{
SelectAllOnFocus = true,
VAnchor = VAnchor.Center
};
editor.ActuallNumberEdit.KeyPressed += (s, e) =>
{
var editWidget = s as NumberEdit;
this.item.Variables[key] = editWidget.Text;
};
rowContainer.AddChild(editor);
}
else if (field.Type == "bool")
{
var checkbox = new CheckBox("")
{
Checked = latest == "true"
};
checkbox.Click += (sender, e) =>
{
this.item.Variables[key] = ((CheckBox)sender).Checked.ToString().ToLower();
};
rowContainer.AddChild(checkbox);
}
mainContainer.AddChild(rowContainer);
}
}
else
{
// TODO: some fallback ui?
}
}
private int ExecuteScript(string sourcePath, string outputPath)
{
var process = new Process()
{
StartInfo = new ProcessStartInfo(
compilerPath,
$"-o \"{outputPath}\" \"{sourcePath}\"")
};
Console.Write(process.StartInfo.FileName);
Console.WriteLine(process.StartInfo.Arguments);
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardError = true;
process.Start();
process.WaitForExit();
string error = process.StandardError.ReadToEnd();
if (process.ExitCode != 0)
{
UiThread.RunOnIdle(() =>
{
StyledMessageBox.ShowMessageBox(error, "Error compiling OpenSCAD script".Localize());
});
}
return process.ExitCode;
}
private static FlowLayoutWidget CreateSettingsRow(string labelText, ThemeConfig theme)
{
var rowContainer = new FlowLayoutWidget(FlowDirection.LeftToRight)
{
HAnchor = HAnchor.Stretch,
Padding = new BorderDouble(5)
};
var label = new TextWidget(labelText + ":", textColor: theme.TextColor, pointSize: theme.DefaultFontSize)
{
Margin = new BorderDouble(0, 0, 3, 0),
VAnchor = VAnchor.Center
};
rowContainer.AddChild(label);
rowContainer.AddChild(new HorizontalSpacer());
return rowContainer;
}
}
}

View file

@ -0,0 +1,54 @@
/*
Copyright (c) 2019, Lars Brubaker, John Lewin
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
The views and conclusions contained in the software and documentation are those
of the authors and should not be interpreted as representing official policies,
either expressed or implied, of the FreeBSD Project.
*/
using System.Collections.Generic;
using MatterHackers.DataConverters3D;
namespace MatterHackers.MatterControl.Library
{
public class OpenScadObject3D : Object3D
{
public string AssetName { get; set; }
public string AssetUrl { get; set; }
public Dictionary<string, string> Variables = new Dictionary<string, string>();
public string ScriptPath { get; set; }
}
public class MetaInfo
{
public List<Field> Fields { get; set; }
}
public class Field
{
public string Title { get; set; }
public string Key { get; set; }
public string Type { get; set; }
}
}

View file

@ -31,8 +31,11 @@ using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using MatterHackers.Agg.UI;
using MatterHackers.DataConverters3D;
using MatterHackers.MatterControl.PartPreviewWindow.View3D;
using MatterHackers.VectorMath;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
@ -91,6 +94,7 @@ namespace MatterHackers.MatterControl.DesignTools.Operations
{
// We need to serialize this so we can remove the arrange and get back to the objects before arranging
public List<Aabb> OriginalChildrenBounds = new List<Aabb>();
private SelectedChildren _anchorObjectSelector = new SelectedChildren();
public AlignObject3D()
{
@ -151,7 +155,34 @@ namespace MatterHackers.MatterControl.DesignTools.Operations
[ShowAsList]
[DisplayName("Primary")]
public SelectedChildren AnchorObjectSelector { get; set; } = new SelectedChildren();
public SelectedChildren AnchorObjectSelector
{
get
{
if (Children.Count > 0)
{
if (_anchorObjectSelector.Count != 1)
{
_anchorObjectSelector.Clear();
_anchorObjectSelector.Add(Children.First().ID);
}
if (!this.Children.Any(c => c.ID == _anchorObjectSelector[0]))
{
// we don't have an id of any of our current children
_anchorObjectSelector.Clear();
_anchorObjectSelector.Add(Children.First().ID);
}
}
else
{
_anchorObjectSelector.Clear();
}
return _anchorObjectSelector;
}
set => _anchorObjectSelector = value;
}
public bool Advanced { get; set; } = false;
@ -160,7 +191,7 @@ namespace MatterHackers.MatterControl.DesignTools.Operations
public Align XAlign { get; set; } = Align.None;
[DisplayName("Anchor")]
[Icons(new string[] { "424.png", "align_to_left.png", "align_to_center_x.png", "align_to_right.png", "" }, InvertIcons = true)]
[Icons(new string[] { "424.png", "align_to_left.png", "align_to_center_x.png", "align_to_right.png", "align_origin.png" }, InvertIcons = true)]
public Align XAlignTo { get; set; } = Align.None;
[DisplayName("Offset")]
@ -171,7 +202,7 @@ namespace MatterHackers.MatterControl.DesignTools.Operations
public Align YAlign { get; set; } = Align.None;
[DisplayName("Anchor")]
[Icons(new string[] { "424.png", "align_to_bottom.png", "align_to_center_y.png", "align_to_top.png", "" }, InvertIcons = true)]
[Icons(new string[] { "424.png", "align_to_bottom.png", "align_to_center_y.png", "align_to_top.png", "align_origin.png" }, InvertIcons = true)]
public Align YAlignTo { get; set; } = Align.None;
[DisplayName("Offset")]
@ -182,7 +213,7 @@ namespace MatterHackers.MatterControl.DesignTools.Operations
public Align ZAlign { get; set; } = Align.None;
[DisplayName("Anchor")]
[Icons(new string[] { "424.png", "align_to_bottom.png", "align_to_center_y.png", "align_to_top.png", "" }, InvertIcons = true)]
[Icons(new string[] { "424.png", "align_to_bottom.png", "align_to_center_y.png", "align_to_top.png", "align_origin.png" }, InvertIcons = true)]
public Align ZAlignTo { get; set; } = Align.None;
[DisplayName("Offset")]
@ -212,12 +243,7 @@ namespace MatterHackers.MatterControl.DesignTools.Operations
{
get
{
if (AnchorObjectSelector.Count == 1)
{
return this.Children.Where(c => c.ID == AnchorObjectSelector[0]).FirstOrDefault();
}
return null;
return this.Children.Where(c => c.ID == AnchorObjectSelector[0]).FirstOrDefault();
}
}
@ -227,16 +253,16 @@ namespace MatterHackers.MatterControl.DesignTools.Operations
get
{
int index = 0;
foreach(var child in this.Children)
{
if(child.ID == AnchorObjectSelector[0])
foreach (var child in this.Children)
{
if (child == AnchorObject)
{
return index;
}
index++;
}
return -1;
return 0;
}
}
@ -270,42 +296,31 @@ namespace MatterHackers.MatterControl.DesignTools.Operations
return positionToAlignTo + extraOffset;
}
public override void OnInvalidate(InvalidateArgs invalidateType)
public override async void OnInvalidate(InvalidateArgs invalidateType)
{
if ((invalidateType.InvalidateType == InvalidateType.Content
|| invalidateType.InvalidateType == InvalidateType.Matrix
|| invalidateType.InvalidateType == InvalidateType.Mesh)
if ((invalidateType.InvalidateType.HasFlag(InvalidateType.Children)
|| invalidateType.InvalidateType.HasFlag(InvalidateType.Matrix)
|| invalidateType.InvalidateType.HasFlag(InvalidateType.Mesh))
&& invalidateType.Source != this
&& !RebuildLocked)
{
Rebuild(null);
await Rebuild();
}
else if (invalidateType.InvalidateType == InvalidateType.Properties
else if (invalidateType.InvalidateType.HasFlag(InvalidateType.Properties)
&& invalidateType.Source == this)
{
Rebuild(null);
}
else
{
base.OnInvalidate(invalidateType);
await Rebuild();
}
// and also always pass back the actual type
base.OnInvalidate(invalidateType);
}
private void Rebuild(UndoBuffer undoBuffer)
public override Task Rebuild()
{
this.DebugDepth("Rebuild");
var childrenIds = Children.Select(c => c.ID).ToArray();
if(childrenIds.Length == 0)
{
AnchorObjectSelector.Clear();
}
else if (AnchorObjectSelector.Count != 1
|| !AnchorObjectSelector.Where(i => childrenIds.Contains(i)).Any())
{
AnchorObjectSelector.Clear();
AnchorObjectSelector.Add(childrenIds[0]);
}
// if the count of our children changed clear our cache of the bounds
if (Children.Count != OriginalChildrenBounds.Count)
@ -372,63 +387,34 @@ namespace MatterHackers.MatterControl.DesignTools.Operations
i++;
}
// the align all the objects to it
// then align all the objects to it
i = 0;
foreach (var child in list)
{
if (XAlign != Align.None
&& i != anchorIndex)
{
if (XAlign == Align.Origin)
{
// find the origin in world space of the child
var firstOrigin = Vector3Ex.Transform(Vector3.Zero, AnchorObject.WorldMatrix());
var childOrigin = Vector3Ex.Transform(Vector3.Zero, child.WorldMatrix());
child.Translate(new Vector3(-(childOrigin - firstOrigin).X + (Advanced ? XOffset : 0), 0, 0));
}
else
{
AlignAxis(0, XAlign, GetAlignToOffset(CurrentChildrenBounds, 0, (!Advanced || XAlignTo == Align.None) ? XAlign : XAlignTo), XOffset, child);
}
AlignAxis(0, XAlign, GetAlignToOffset(CurrentChildrenBounds, 0, (!Advanced || XAlignTo == Align.None) ? XAlign : XAlignTo), XOffset, child);
}
if (YAlign != Align.None
&& i != anchorIndex)
{
if (YAlign == Align.Origin)
{
// find the origin in world space of the child
var firstOrigin = Vector3Ex.Transform(Vector3.Zero, AnchorObject.WorldMatrix());
var childOrigin = Vector3Ex.Transform(Vector3.Zero, child.WorldMatrix());
child.Translate(new Vector3(0, -(childOrigin - firstOrigin).Y + (Advanced ? YOffset : 0), 0));
}
else
{
AlignAxis(1, YAlign, GetAlignToOffset(CurrentChildrenBounds, 1, (!Advanced || YAlignTo == Align.None) ? YAlign : YAlignTo), YOffset, child);
}
AlignAxis(1, YAlign, GetAlignToOffset(CurrentChildrenBounds, 1, (!Advanced || YAlignTo == Align.None) ? YAlign : YAlignTo), YOffset, child);
}
if (ZAlign != Align.None
&& i != anchorIndex)
{
if (ZAlign == Align.Origin)
{
// find the origin in world space of the child
var firstOrigin = Vector3Ex.Transform(Vector3.Zero, AnchorObject.WorldMatrix());
var childOrigin = Vector3Ex.Transform(Vector3.Zero, child.WorldMatrix());
child.Translate(new Vector3(0, 0, -(childOrigin - firstOrigin).Z + (Advanced ? ZOffset : 0)));
}
else
{
AlignAxis(2, ZAlign, GetAlignToOffset(CurrentChildrenBounds, 2, (!Advanced || ZAlignTo == Align.None) ? ZAlign : ZAlignTo), ZOffset, child);
}
AlignAxis(2, ZAlign, GetAlignToOffset(CurrentChildrenBounds, 2, (!Advanced || ZAlignTo == Align.None) ? ZAlign : ZAlignTo), ZOffset, child);
}
i++;
}
}));
}
Invalidate(new InvalidateArgs(this, InvalidateType.Matrix, null));
Invalidate(InvalidateType.Matrix);
return Task.CompletedTask;
}
public override void Remove(UndoBuffer undoBuffer)
@ -450,21 +436,21 @@ namespace MatterHackers.MatterControl.DesignTools.Operations
base.Remove(undoBuffer);
}
Invalidate(new InvalidateArgs(this, InvalidateType.Content));
Invalidate(InvalidateType.Children);
}
public void UpdateControls(PublicPropertyChange change)
{
var editRow = change.Context.GetEditRow(nameof(XAlignTo));
if (editRow != null) editRow.Visible = Advanced && XAlign != Align.Origin;
if (editRow != null) editRow.Visible = Advanced;
editRow = change.Context.GetEditRow(nameof(XOffset));
if (editRow != null) editRow.Visible = Advanced;
editRow = change.Context.GetEditRow(nameof(YAlignTo));
if (editRow != null) editRow.Visible = Advanced && YAlign != Align.Origin;
if (editRow != null) editRow.Visible = Advanced;
editRow = change.Context.GetEditRow(nameof(YOffset));
if (editRow != null) editRow.Visible = Advanced;
editRow = change.Context.GetEditRow(nameof(ZAlignTo));
if (editRow != null) editRow.Visible = Advanced && ZAlign != Align.Origin;
if (editRow != null) editRow.Visible = Advanced;
editRow = change.Context.GetEditRow(nameof(ZOffset));
if (editRow != null) editRow.Visible = Advanced;
}
@ -501,6 +487,12 @@ namespace MatterHackers.MatterControl.DesignTools.Operations
case Align.Max:
translate[axis] = alignTo - aabb.MaxXYZ[axis] + offset;
break;
case Align.Origin:
// find the origin in world space of the item
var itemOrigin = Vector3Ex.Transform(Vector3.Zero, item.WorldMatrix());
translate[axis] = alignTo - itemOrigin[axis] + offset;
break;
}
item.Translate(translate);
@ -519,6 +511,9 @@ namespace MatterHackers.MatterControl.DesignTools.Operations
case Align.Max:
return currentChildrenBounds[AnchorObjectIndex].MaxXYZ[axis];
case Align.Origin:
return Vector3Ex.Transform(Vector3.Zero, AnchorObject.WorldMatrix())[axis];
default:
throw new NotImplementedException();
}

View file

@ -32,10 +32,11 @@ using MatterHackers.DataConverters3D;
using MatterHackers.Localizations;
using MatterHackers.VectorMath;
using System.Linq;
using System.Threading.Tasks;
namespace MatterHackers.MatterControl.DesignTools.Operations
{
public class ArrayAdvancedObject3D : Object3D
public class ArrayAdvancedObject3D : OperationSourceContainerObject3D
{
public ArrayAdvancedObject3D()
{
@ -56,72 +57,52 @@ namespace MatterHackers.MatterControl.DesignTools.Operations
public bool ScaleOffset { get; set; } = true;
public override void Flatten(UndoBuffer undoBuffer)
public override async Task Rebuild()
{
OperationSourceObject3D.Flatten(this);
var rebuildLock = this.RebuildLock();
SourceContainer.Visible = true;
base.Flatten(undoBuffer);
}
public override void OnInvalidate(InvalidateArgs invalidateType)
{
if ((invalidateType.InvalidateType == InvalidateType.Content
|| invalidateType.InvalidateType == InvalidateType.Matrix
|| invalidateType.InvalidateType == InvalidateType.Mesh)
&& invalidateType.Source != this
&& !RebuildLocked)
{
Rebuild(null);
}
else if (invalidateType.InvalidateType == InvalidateType.Properties
&& invalidateType.Source == this)
{
Rebuild(null);
}
else
{
base.OnInvalidate(invalidateType);
}
}
private void Rebuild(UndoBuffer undoBuffer)
{
this.DebugDepth("Rebuild");
this.Children.Modify(list =>
{
IObject3D lastChild = list.First();
list.Clear();
list.Add(lastChild);
var offset = Offset;
for (int i = 1; i < Count; i++)
await ApplicationController.Instance.Tasks.Execute(
"Advanced Array".Localize(),
null,
(reporter, cancellationToken) =>
{
var rotateRadians = MathHelper.DegreesToRadians(Rotate);
if (ScaleOffset)
this.DebugDepth("Rebuild");
var sourceContainer = SourceContainer;
this.Children.Modify(list =>
{
offset *= Scale;
}
list.Clear();
list.Add(sourceContainer);
var lastChild = sourceContainer.Children.First();
list.Add(lastChild.Clone());
var offset = Offset;
for (int i = 1; i < Count; i++)
{
var rotateRadians = MathHelper.DegreesToRadians(Rotate);
if (ScaleOffset)
{
offset *= Scale;
}
var next = lastChild.Clone();
offset = Vector3Ex.Transform(offset, Matrix4X4.CreateRotationZ(rotateRadians));
next.Matrix *= Matrix4X4.CreateTranslation(offset);
var next = lastChild.Clone();
offset = Vector3Ex.Transform(offset, Matrix4X4.CreateRotationZ(rotateRadians));
next.Matrix *= Matrix4X4.CreateTranslation(offset);
if (RotatePart)
{
next.Matrix = next.ApplyAtBoundsCenter(Matrix4X4.CreateRotationZ(rotateRadians));
}
if (RotatePart)
{
next.Matrix = next.ApplyAtBoundsCenter(Matrix4X4.CreateRotationZ(rotateRadians));
}
next.Matrix = next.ApplyAtBoundsCenter(Matrix4X4.CreateScale(Scale));
list.Add(next);
lastChild = next;
}
});
}
public override void Remove(UndoBuffer undoBuffer)
{
OperationSourceObject3D.Remove(this);
base.Remove(undoBuffer);
next.Matrix = next.ApplyAtBoundsCenter(Matrix4X4.CreateScale(Scale));
list.Add(next);
lastChild = next;
}
});
SourceContainer.Visible = false;
rebuildLock.Dispose();
Invalidate(InvalidateType.Children);
return Task.CompletedTask;
});
}
}
}

View file

@ -27,17 +27,18 @@ of the authors and should not be interpreted as representing official policies,
either expressed or implied, of the FreeBSD Project.
*/
using MatterHackers.Agg.UI;
using MatterHackers.DataConverters3D;
using MatterHackers.Localizations;
using MatterHackers.MatterControl.DesignTools.EditableTypes;
using MatterHackers.VectorMath;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace MatterHackers.MatterControl.DesignTools.Operations
{
public class ArrayLinearObject3D : Object3D
public class ArrayLinearObject3D : OperationSourceContainerObject3D
{
public ArrayLinearObject3D()
{
@ -48,68 +49,46 @@ namespace MatterHackers.MatterControl.DesignTools.Operations
public int Count { get; set; } = 3;
public DirectionVector Direction { get; set; } = new DirectionVector { Normal = new Vector3(1, 0, 0) };
public double Distance { get; set; } = 30;
public override void Flatten(UndoBuffer undoBuffer)
public override async Task Rebuild()
{
OperationSourceObject3D.Flatten(this);
var rebuildLock = this.RebuildLock();
SourceContainer.Visible = true;
base.Flatten(undoBuffer);
}
public override void OnInvalidate(InvalidateArgs invalidateType)
{
if ((invalidateType.InvalidateType == InvalidateType.Content
|| invalidateType.InvalidateType == InvalidateType.Matrix
|| invalidateType.InvalidateType == InvalidateType.Mesh)
&& invalidateType.Source != this
&& !RebuildLocked)
{
Rebuild(null);
}
else if (invalidateType.InvalidateType == InvalidateType.Properties
&& invalidateType.Source == this)
{
Rebuild(null);
}
else
{
base.OnInvalidate(invalidateType);
}
}
private void Rebuild(UndoBuffer undoBuffer)
{
using (this.RebuildLock())
{
this.DebugDepth("Rebuild");
var sourceContainer = OperationSourceObject3D.GetOrCreateSourceContainer(this);
this.Children.Modify(list =>
await ApplicationController.Instance.Tasks.Execute(
"Linear Array".Localize(),
null,
(reporter, cancellationToken) =>
{
list.Clear();
// add back in the sourceContainer
list.Add(sourceContainer);
// get the source item
var sourceItem = sourceContainer.Children.First();
this.DebugDepth("Rebuild");
for (int i = 0; i < Math.Max(Count, 1); i++)
using (new CenterAndHeightMantainer(this))
{
var next = sourceItem.Clone();
next.Matrix = sourceItem.Matrix * Matrix4X4.CreateTranslation(Direction.Normal.GetNormal() * Distance * i);
list.Add(next);
var newChildren = new List<IObject3D>();
newChildren.Add(SourceContainer);
var arrayItem = SourceContainer.Children.First();
// add in all the array items
for (int i = 0; i < Math.Max(Count, 1); i++)
{
var next = arrayItem.Clone();
next.Matrix = arrayItem.Matrix * Matrix4X4.CreateTranslation(Direction.Normal.GetNormal() * Distance * i);
newChildren.Add(next);
}
Children.Modify(list =>
{
list.Clear();
list.AddRange(newChildren);
});
}
SourceContainer.Visible = false;
rebuildLock.Dispose();
Invalidate(InvalidateType.Children);
return Task.CompletedTask;
});
}
this.Invalidate(new InvalidateArgs(this, InvalidateType.Content));
}
public override void Remove(UndoBuffer undoBuffer)
{
OperationSourceObject3D.Remove(this);
base.Remove(undoBuffer);
}
}
}

View file

@ -37,10 +37,11 @@ using MatterHackers.VectorMath;
using System;
using System.ComponentModel;
using System.Linq;
using System.Threading.Tasks;
namespace MatterHackers.MatterControl.DesignTools.Operations
{
public class ArrayRadialObject3D : Object3D, IEditorDraw
public class ArrayRadialObject3D : OperationSourceContainerObject3D, IEditorDraw
{
public ArrayRadialObject3D()
{
@ -65,97 +66,70 @@ namespace MatterHackers.MatterControl.DesignTools.Operations
[Description("Keep the entire extents of the part within the angle described.")]
private bool KeepInAngle { get; set; } = false;
public override void Flatten(UndoBuffer undoBuffer)
public override async Task Rebuild()
{
OperationSourceObject3D.Flatten(this);
base.Flatten(undoBuffer);
}
public override void OnInvalidate(InvalidateArgs invalidateType)
{
if ((invalidateType.InvalidateType == InvalidateType.Content
|| invalidateType.InvalidateType == InvalidateType.Matrix
|| invalidateType.InvalidateType == InvalidateType.Mesh)
&& invalidateType.Source != this
&& !RebuildLocked)
// check if we have initialized the Axis
if (Axis.Origin.X == double.NegativeInfinity)
{
Rebuild(null);
// make it something reasonable (just to the left of the aabb of the object)
Axis.Origin = this.GetAxisAlignedBoundingBox().Center - new Vector3(-30, 0, 0);
}
else if (invalidateType.InvalidateType == InvalidateType.Properties
&& invalidateType.Source == this)
{
Rebuild(null);
}
else
{
base.OnInvalidate(invalidateType);
}
}
private void Rebuild(UndoBuffer undoBuffer)
{
using (this.RebuildLock())
{
this.DebugDepth("Rebuild");
var aabb = this.GetAxisAlignedBoundingBox();
var rebuildLock = this.RebuildLock();
SourceContainer.Visible = true;
// check if we have initialized the Axis
if (Axis.Origin.X == double.NegativeInfinity)
await ApplicationController.Instance.Tasks.Execute(
"Radial Array".Localize(),
null,
(reporter, cancellationToken) =>
{
// make it something reasonable (just to the left of the aabb of the object)
Axis.Origin = aabb.Center - new Vector3(-30, 0, 0);
}
this.DebugDepth("Rebuild");
var aabb = this.GetAxisAlignedBoundingBox();
// make sure our length is in the right axis
for (int i = 0; i < 3; i++)
{
if (Axis.Normal[i] != 0 && Axis.Origin[i] == 0)
// make sure our length is in the right axis
for (int i = 0; i < 3; i++)
{
var newOrigin = Vector3.Zero;
newOrigin[i] = Math.Max(aabb.Center[0] - Axis.Origin[0],
Math.Max(aabb.Center[1] - Axis.Origin[1],
aabb.Center[2] - Axis.Origin[2]));
}
}
var sourceContainer = OperationSourceObject3D.GetOrCreateSourceContainer(this);
this.Children.Modify(list =>
{
list.Clear();
// add back in the sourceContainer
list.Add(sourceContainer);
// get the source item
var sourceItem = sourceContainer.Children.First();
var offset = Vector3.Zero;
for (int i = 0; i < Math.Max(Count, 1); i++)
{
var next = sourceItem.Clone();
var normal = Axis.Normal.GetNormal();
var angleRadians = MathHelper.DegreesToRadians(Angle) / Count * i;
next.Rotate(Axis.Origin, normal, angleRadians);
if (!RotatePart)
if (Axis.Normal[i] != 0 && Axis.Origin[i] == 0)
{
var nextAabb = next.GetAxisAlignedBoundingBox();
next.Rotate(nextAabb.Center, normal, -angleRadians);
var newOrigin = Vector3.Zero;
newOrigin[i] = Math.Max(aabb.Center[0] - Axis.Origin[0],
Math.Max(aabb.Center[1] - Axis.Origin[1],
aabb.Center[2] - Axis.Origin[2]));
}
list.Add(next);
}
var sourceContainer = SourceContainer;
this.Children.Modify(list =>
{
list.Clear();
// add back in the sourceContainer
list.Add(sourceContainer);
// get the source item
var sourceItem = sourceContainer.Children.First();
var offset = Vector3.Zero;
for (int i = 0; i < Math.Max(Count, 1); i++)
{
var next = sourceItem.Clone();
var normal = Axis.Normal.GetNormal();
var angleRadians = MathHelper.DegreesToRadians(Angle) / Count * i;
next.Rotate(Axis.Origin, normal, angleRadians);
if (!RotatePart)
{
var nextAabb = next.GetAxisAlignedBoundingBox();
next.Rotate(nextAabb.Center, normal, -angleRadians);
}
list.Add(next);
}
});
SourceContainer.Visible = false;
rebuildLock.Dispose();
Invalidate(InvalidateType.Children);
return Task.CompletedTask;
});
}
this.Invalidate(new InvalidateArgs(this, InvalidateType.Content));
}
public override void Remove(UndoBuffer undoBuffer)
{
OperationSourceObject3D.Remove(this);
base.Remove(undoBuffer);
}
public void DrawEditor(object sender, DrawEventArgs e)

View file

@ -0,0 +1,195 @@
/*
Copyright (c) 2018, Lars Brubaker, John Lewin
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
The views and conclusions contained in the software and documentation are those
of the authors and should not be interpreted as representing official policies,
either expressed or implied, of the FreeBSD Project.
*/
using System;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using MatterHackers.Agg;
using MatterHackers.Agg.UI;
using MatterHackers.DataConverters3D;
using MatterHackers.Localizations;
using MatterHackers.MatterControl.DesignTools.Operations;
using MatterHackers.MatterControl.PartPreviewWindow;
using MatterHackers.MeshVisualizer;
using MatterHackers.PolygonMesh;
using MatterHackers.RenderOpenGl.OpenGl;
using MatterHackers.VectorMath;
namespace MatterHackers.MatterControl.DesignTools
{
public class CurveObject3D_2 : OperationSourceContainerObject3D, IEditorDraw
{
// this needs to serialize but not be editable
public Vector3 rotationOffset;
public CurveObject3D_2()
{
Name = "Curve".Localize();
}
[DisplayName("Bend Up")]
public bool BendCcw { get; set; } = true;
public double Diameter { get; set; } = double.MinValue;
[Range(3, 360, ErrorMessage = "Value for {0} must be between {1} and {2}.")]
[Description("Ensures the rotated part has a minimum number of sides per complete rotation")]
public double MinSidesPerRotation { get; set; } = 3;
[Range(0, 100, ErrorMessage = "Value for {0} must be between {1} and {2}.")]
[Description("Where to start the bend as a percent of the width of the part")]
public double StartPercent { get; set; } = 50;
public void DrawEditor(object sender, DrawEventArgs e)
{
if (sender is InteractionLayer layer
&& layer.Scene.SelectedItem != null
&& layer.Scene.SelectedItem.DescendantsAndSelf().Where((i) => i == this).Any())
{
// we want to measure the
var currentMatrixInv = Matrix.Inverted;
var aabb = this.GetAxisAlignedBoundingBox(currentMatrixInv);
layer.World.RenderCylinderOutline(this.WorldMatrix(), Vector3.Zero, Diameter, aabb.ZSize, 30, Color.Red);
}
// turn the lighting back on
GL.Enable(EnableCap.Lighting);
}
public override Task Rebuild()
{
this.DebugDepth("Rebuild");
bool propertyUpdated = Diameter == double.MinValue;
if (StartPercent < 0
|| StartPercent > 100)
{
StartPercent = Math.Min(100, Math.Max(0, StartPercent));
propertyUpdated = true;
}
var originalAabb = this.GetAxisAlignedBoundingBox();
var rebuildLocks = this.RebuilLockAll();
return ApplicationController.Instance.Tasks.Execute(
"Curve".Localize(),
null,
(reporter, cancellationToken) =>
{
using (new CenterAndHeightMantainer(this))
{
this.Translate(-rotationOffset);
SourceContainer.Visible = true;
RemoveAllButSource();
// remember the current matrix then clear it so the parts will rotate at the original wrapped position
var currentMatrix = Matrix;
Matrix = Matrix4X4.Identity;
var aabb = this.GetAxisAlignedBoundingBox();
if (Diameter == double.MinValue)
{
// uninitialized set to a reasonable value
Diameter = (int)aabb.XSize;
// TODO: ensure that the editor display value is updated
}
if (Diameter > 0)
{
var radius = Diameter / 2;
var circumference = MathHelper.Tau * radius;
var rotationCenter = new Vector3(aabb.MinXYZ.X + (aabb.MaxXYZ.X - aabb.MinXYZ.X) * (StartPercent / 100), aabb.MaxXYZ.Y + radius, aabb.Center.Z);
rotationOffset = rotationCenter;
if (!BendCcw)
{
// fix the stored center so we draw correctly
rotationOffset.Y = aabb.MinXYZ.Y - radius;
}
foreach (var sourceItem in SourceContainer.VisibleMeshes())
{
var originalMesh = sourceItem.Mesh;
var transformedMesh = originalMesh.Copy(CancellationToken.None);
var itemMatrix = sourceItem.WorldMatrix(SourceContainer);
if (!BendCcw)
{
// rotate around so it will bend correctly
itemMatrix *= Matrix4X4.CreateTranslation(0, -aabb.MaxXYZ.Y, 0);
itemMatrix *= Matrix4X4.CreateRotationX(MathHelper.Tau / 2);
itemMatrix *= Matrix4X4.CreateTranslation(0, aabb.MaxXYZ.Y - aabb.YSize, 0);
}
var invItemMatrix = itemMatrix.Inverted;
for (int i = 0; i < transformedMesh.Vertices.Count; i++)
{
var worldPosition = transformedMesh.Vertices[i].Transform((Matrix4X4)itemMatrix);
var angleToRotate = ((worldPosition.X - rotationCenter.X) / circumference) * MathHelper.Tau - MathHelper.Tau / 4;
var distanceFromCenter = rotationCenter.Y - worldPosition.Y;
var rotatePosition = new Vector3Float(Math.Cos(angleToRotate), Math.Sin(angleToRotate), 0) * distanceFromCenter;
rotatePosition.Z = worldPosition.Z;
var worldWithBend = rotatePosition + new Vector3Float(rotationCenter.X, radius + aabb.MaxXYZ.Y, 0);
transformedMesh.Vertices[i] = worldWithBend.Transform(invItemMatrix) - new Vector3Float(rotationOffset);
}
transformedMesh.MarkAsChanged();
transformedMesh.CalculateNormals();
var newMesh = new Object3D()
{
Mesh = transformedMesh
};
newMesh.CopyWorldProperties(sourceItem, this, Object3DPropertyFlags.All);
this.Children.Add(newMesh);
}
// set the matrix back
Matrix = currentMatrix;
this.Translate(new Vector3(rotationOffset));
SourceContainer.Visible = false;
rebuildLocks.Dispose();
}
Invalidate(InvalidateType.Children);
}
return Task.CompletedTask;
});
}
}
}

View file

@ -38,6 +38,7 @@ using MatterHackers.VectorMath;
using System;
using System.ComponentModel;
using System.Linq;
using System.Threading.Tasks;
namespace MatterHackers.MatterControl.DesignTools.Operations
{
@ -57,33 +58,34 @@ namespace MatterHackers.MatterControl.DesignTools.Operations
Name = "Fit to Bounds".Localize();
}
public override bool CanFlatten => true;
private IObject3D FitBounds => Children.Last();
public static FitToBoundsObject3D_2 Create(IObject3D itemToFit)
public static async Task<FitToBoundsObject3D_2> Create(IObject3D itemToFit)
{
var fitToBounds = new FitToBoundsObject3D_2();
using (fitToBounds.RebuildLock())
{
var aabb = itemToFit.GetAxisAlignedBoundingBox();
var bounds = new Object3D()
using (new CenterAndHeightMantainer(itemToFit))
{
Visible = false,
Color = new Color(Color.Red, 100),
Mesh = PlatonicSolids.CreateCube()
};
var aabb = itemToFit.GetAxisAlignedBoundingBox();
var bounds = new Object3D()
{
Visible = false,
Color = new Color(Color.Red, 100),
Mesh = PlatonicSolids.CreateCube()
};
// add all the children
var scaleItem = new Object3D();
fitToBounds.Children.Add(scaleItem);
scaleItem.Children.Add(itemToFit);
fitToBounds.Children.Add(bounds);
// add all the children
var scaleItem = new Object3D();
fitToBounds.Children.Add(scaleItem);
scaleItem.Children.Add(itemToFit);
fitToBounds.Children.Add(bounds);
fitToBounds.boundsSize.X = aabb.XSize;
fitToBounds.boundsSize.Y = aabb.YSize;
fitToBounds.boundsSize.Z = aabb.ZSize;
fitToBounds.Rebuild(null);
fitToBounds.boundsSize.X = aabb.XSize;
fitToBounds.boundsSize.Y = aabb.YSize;
fitToBounds.boundsSize.Z = aabb.ZSize;
await fitToBounds.Rebuild();
}
}
return fitToBounds;
@ -95,7 +97,7 @@ namespace MatterHackers.MatterControl.DesignTools.Operations
&& layer.Scene.SelectedItem != null
&& layer.Scene.SelectedItem.DescendantsAndSelf().Where((i) => i == this).Any())
{
var aabb = SourceItem.GetAxisAlignedBoundingBox();
var aabb = SourceItems.GetAxisAlignedBoundingBox();
var center = aabb.Center;
var worldMatrix = this.WorldMatrix();
@ -135,64 +137,58 @@ namespace MatterHackers.MatterControl.DesignTools.Operations
return base.GetAxisAlignedBoundingBox(matrix);
}
public override void OnInvalidate(InvalidateArgs invalidateType)
public override async void OnInvalidate(InvalidateArgs invalidateType)
{
if ((invalidateType.InvalidateType == InvalidateType.Content
|| invalidateType.InvalidateType == InvalidateType.Matrix
|| invalidateType.InvalidateType == InvalidateType.Mesh)
if ((invalidateType.InvalidateType.HasFlag(InvalidateType.Children)
|| invalidateType.InvalidateType.HasFlag(InvalidateType.Matrix)
|| invalidateType.InvalidateType.HasFlag(InvalidateType.Mesh))
&& invalidateType.Source != this
&& !RebuildLocked)
{
Rebuild(null);
await Rebuild();
}
else if (invalidateType.InvalidateType == InvalidateType.Properties
else if (invalidateType.InvalidateType.HasFlag(InvalidateType.Properties)
&& invalidateType.Source == this)
{
Rebuild(null);
await Rebuild();
}
else if ((invalidateType.InvalidateType == InvalidateType.Properties
|| invalidateType.InvalidateType == InvalidateType.Matrix
|| invalidateType.InvalidateType == InvalidateType.Mesh
|| invalidateType.InvalidateType == InvalidateType.Content))
else if (invalidateType.InvalidateType.HasFlag(InvalidateType.Properties)
|| invalidateType.InvalidateType.HasFlag(InvalidateType.Matrix)
|| invalidateType.InvalidateType.HasFlag(InvalidateType.Mesh)
|| invalidateType.InvalidateType.HasFlag(InvalidateType.Children))
{
cacheThisMatrix = Matrix4X4.Identity;
base.OnInvalidate(invalidateType);
}
else
{
base.OnInvalidate(invalidateType);
}
base.OnInvalidate(invalidateType);
}
public void Rebuild(UndoBuffer undoBuffer)
public override Task Rebuild()
{
this.DebugDepth("Rebuild");
using (RebuildLock())
{
var aabb = this.GetAxisAlignedBoundingBox();
AdjustChildSize(null, null);
UpdateBoundsItem();
cacheRequestedMatrix = new Matrix4X4();
var after = this.GetAxisAlignedBoundingBox();
if (aabb.ZSize > 0)
using (new CenterAndHeightMantainer(this))
{
// If the part was already created and at a height, maintain the height.
PlatingHelper.PlaceMeshAtHeight(this, aabb.MinXYZ.Z);
AdjustChildSize(null, null);
UpdateBoundsItem();
cacheRequestedMatrix = new Matrix4X4();
var after = this.GetAxisAlignedBoundingBox();
}
}
base.Invalidate(new InvalidateArgs(this, InvalidateType.Matrix));
Invalidate(InvalidateType.Matrix);
return Task.CompletedTask;
}
private void AdjustChildSize(object sender, EventArgs e)
{
if (Children.Count > 0)
{
var aabb = SourceItem.GetAxisAlignedBoundingBox();
var aabb = SourceItems.GetAxisAlignedBoundingBox();
TransformItem.Matrix = Matrix4X4.Identity;
var scale = Vector3.One;
if (StretchX)
@ -265,7 +261,10 @@ namespace MatterHackers.MatterControl.DesignTools.Operations
set
{
boundsSize.X = value;
Rebuild(null);
if (this.Children.Count() > 0)
{
Rebuild();
}
}
}
@ -276,7 +275,10 @@ namespace MatterHackers.MatterControl.DesignTools.Operations
set
{
boundsSize.Y = value;
Rebuild(null);
if (this.Children.Count() > 0)
{
Rebuild();
}
}
}
@ -287,7 +289,10 @@ namespace MatterHackers.MatterControl.DesignTools.Operations
set
{
boundsSize.Z = value;
Rebuild(null);
if (this.Children.Count() > 0)
{
Rebuild();
}
}
}

View file

@ -306,25 +306,22 @@ namespace MatterHackers.MatterControl.DesignTools
}
}
public override void OnInvalidate(InvalidateArgs invalidateType)
public override async void OnInvalidate(InvalidateArgs invalidateType)
{
if (invalidateType.InvalidateType == InvalidateType.Image
if (invalidateType.InvalidateType.HasFlag(InvalidateType.Image)
&& invalidateType.Source != this
&& !RebuildLocked)
{
Rebuild(null);
await Rebuild();
}
else if (invalidateType.InvalidateType == InvalidateType.Properties
else if (invalidateType.InvalidateType.HasFlag(InvalidateType.Properties)
&& invalidateType.Source == this)
{
UpdateHistogramDisplay();
Rebuild(null);
base.OnInvalidate(invalidateType);
}
else
{
base.OnInvalidate(invalidateType);
await Rebuild();
}
base.OnInvalidate(invalidateType);
}
private Color GetRGBA(byte[] buffer, int offset)
@ -332,8 +329,10 @@ namespace MatterHackers.MatterControl.DesignTools
return new Color(buffer[offset + 2], buffer[offset + 1], buffer[offset + 0], buffer[offset + 3]);
}
private void Rebuild(UndoBuffer undoBuffer)
public override Task Rebuild()
{
this.DebugDepth("Rebuild");
bool propertyUpdated = false;
var minSeparation = .01;
if (RangeStart < 0
@ -361,35 +360,35 @@ namespace MatterHackers.MatterControl.DesignTools
}
propertyUpdated = true;
}
var rebuildLock = RebuildLock();
// now create a long running task to process the image
ApplicationController.Instance.Tasks.Execute(
"Calculate Path".Localize(),
null,
(reporter, cancellationToken) =>
{
var progressStatus = new ProgressStatus();
this.GenerateMarchingSquaresAndLines(
(progress0to1, status) =>
return ApplicationController.Instance.Tasks.Execute(
"Calculate Path".Localize(),
null,
(reporter, cancellationToken) =>
{
var progressStatus = new ProgressStatus();
this.GenerateMarchingSquaresAndLines(
(progress0to1, status) =>
{
progressStatus.Progress0To1 = progress0to1;
progressStatus.Status = status;
reporter.Report(progressStatus);
},
Image,
ThresholdFunction);
if (propertyUpdated)
{
progressStatus.Progress0To1 = progress0to1;
progressStatus.Status = status;
reporter.Report(progressStatus);
},
Image,
ThresholdFunction);
UpdateHistogramDisplay();
Invalidate(InvalidateType.Properties);
}
rebuildLock.Dispose();
Invalidate(new InvalidateArgs(this, InvalidateType.Path, null));
return Task.CompletedTask;
});
if (propertyUpdated)
{
UpdateHistogramDisplay();
Invalidate(new InvalidateArgs(this, InvalidateType.Properties, null));
}
rebuildLock.Dispose();
Invalidate(InvalidateType.Path);
return Task.CompletedTask;
});
}
}
}

View file

@ -41,6 +41,7 @@ namespace MatterHackers.MatterControl.DesignTools
using MatterHackers.PolygonMesh;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
public class LinearExtrudeObject3D : Object3D
{
@ -76,10 +77,10 @@ namespace MatterHackers.MatterControl.DesignTools
meshOnlyItem.CopyProperties(this, Object3DPropertyFlags.All);
// and replace us with the children
undoBuffer.AddAndDo(new ReplaceCommand(new List<IObject3D> { this }, new List<IObject3D> { meshOnlyItem }));
undoBuffer.AddAndDo(new ReplaceCommand(new[] { this }, new[] { meshOnlyItem }));
}
Invalidate(new InvalidateArgs(this, InvalidateType.Content));
Invalidate(InvalidateType.Children);
}
public LinearExtrudeObject3D()
@ -87,41 +88,48 @@ namespace MatterHackers.MatterControl.DesignTools
Name = "Linear Extrude".Localize();
}
public override void OnInvalidate(InvalidateArgs invalidateType)
public override async void OnInvalidate(InvalidateArgs eventArgs)
{
if ((invalidateType.InvalidateType == InvalidateType.Content
|| invalidateType.InvalidateType == InvalidateType.Matrix
|| invalidateType.InvalidateType == InvalidateType.Mesh
|| invalidateType.InvalidateType == InvalidateType.Path)
&& invalidateType.Source != this
if ((eventArgs.InvalidateType.HasFlag(InvalidateType.Path)
|| eventArgs.InvalidateType.HasFlag(InvalidateType.Children))
&& eventArgs.Source != this
&& !RebuildLocked)
{
Rebuild(null);
await Rebuild();
}
else if (invalidateType.InvalidateType == InvalidateType.Properties
&& invalidateType.Source == this)
else if (eventArgs.InvalidateType.HasFlag(InvalidateType.Properties)
&& eventArgs.Source == this)
{
Rebuild(null);
await Rebuild();
}
else
{
base.OnInvalidate(invalidateType);
base.OnInvalidate(eventArgs);
}
}
private void Rebuild(UndoBuffer undoBuffer)
public override Task Rebuild()
{
using (RebuildLock())
{
var vertexSource = this.VertexSource;
Mesh = VertexSourceToMesh.Extrude(this.VertexSource, Height);
if (Mesh.Vertices.Count == 0)
{
Mesh = null;
}
}
this.DebugDepth("Rebuild");
Invalidate(new InvalidateArgs(this, InvalidateType.Mesh));
var rebuildLock = RebuildLock();
// now create a long running task to process the image
return ApplicationController.Instance.Tasks.Execute(
"Linear Extrude".Localize(),
null,
(reporter, cancellationToken) =>
{
var vertexSource = this.VertexSource;
Mesh = VertexSourceToMesh.Extrude(this.VertexSource, Height);
if (Mesh.Vertices.Count == 0)
{
Mesh = null;
}
rebuildLock.Dispose();
Invalidate(InvalidateType.Mesh);
return Task.CompletedTask;
});
}
}
}

View file

@ -0,0 +1,114 @@
/*
Copyright (c) 2018, Lars Brubaker, John Lewin
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
The views and conclusions contained in the software and documentation are those
of the authors and should not be interpreted as representing official policies,
either expressed or implied, of the FreeBSD Project.
*/
using System;
using System.Threading;
using System.Threading.Tasks;
using MatterHackers.DataConverters3D;
using MatterHackers.Localizations;
using MatterHackers.MatterControl.DesignTools.Operations;
using MatterHackers.MatterControl.PartPreviewWindow.View3D;
using MatterHackers.PolygonMesh;
using MatterHackers.VectorMath;
namespace MatterHackers.MatterControl.DesignTools
{
public class MirrorObject3D_2 : OperationSourceContainerObject3D
{
public MirrorObject3D_2()
{
Name = "Mirror".Localize();
}
public enum MirrorAxis { X_Axis, Y_Axis, Z_Axis };
public MirrorAxis MirrorOn { get; set; } = MirrorAxis.X_Axis;
public override Task Rebuild()
{
this.DebugDepth("Rebuild");
var rebuildLock = this.RebuildLock();
return ApplicationController.Instance.Tasks.Execute(
"Mirror".Localize(),
null,
(reporter, cancellationToken) =>
{
SourceContainer.Visible = true;
RemoveAllButSource();
var oldMatrix = this.Matrix;
this.Matrix = Matrix4X4.Identity;
var mirrorMatrix = Matrix4X4.Identity;
switch (MirrorOn)
{
case MirrorAxis.X_Axis:
mirrorMatrix = this.ApplyAtBoundsCenter(Matrix4X4.CreateScale(-1, 1, 1));
break;
case MirrorAxis.Y_Axis:
mirrorMatrix = this.ApplyAtBoundsCenter(Matrix4X4.CreateScale(1, -1, 1));
break;
case MirrorAxis.Z_Axis:
mirrorMatrix = this.ApplyAtBoundsCenter(Matrix4X4.CreateScale(1, 1, -1));
break;
}
foreach (var sourceItem in SourceContainer.VisibleMeshes())
{
var originalMesh = sourceItem.Mesh;
var transformedMesh = originalMesh.Copy(CancellationToken.None);
var sourceToThisMatrix = sourceItem.WorldMatrix(this);
// move it to us then mirror then move it back
transformedMesh.Transform(sourceToThisMatrix * mirrorMatrix * sourceToThisMatrix.Inverted);
transformedMesh.ReverseFaces();
var newMesh = new Object3D()
{
Mesh = transformedMesh
};
newMesh.CopyWorldProperties(sourceItem, this, Object3DPropertyFlags.All);
this.Children.Add(newMesh);
}
this.Matrix = oldMatrix;
SourceContainer.Visible = false;
rebuildLock.Dispose();
Invalidate(InvalidateType.Children);
return Task.CompletedTask;
});
}
}
}

View file

@ -41,6 +41,7 @@ using MatterHackers.Agg.VertexSource;
using MatterHackers.DataConverters2D;
using MatterHackers.DataConverters3D;
using MatterHackers.DataConverters3D.UndoCommands;
using MatterHackers.MatterControl.PartPreviewWindow;
using MatterHackers.MatterControl.PartPreviewWindow.View3D;
using MatterHackers.VectorMath;
@ -230,19 +231,37 @@ namespace MatterHackers.MatterControl.DesignTools.Operations
return output;
}
public static IObject3D Plus(this IObject3D a, IObject3D b)
/// <summary>
/// Union a and b together. This can either return a single item with a mesh on it
/// or a group item that has the a and be itmes as children
/// </summary>
/// <param name="a"></param>
/// <param name="b"></param>
/// <param name="doMeshCombine"></param>
/// <returns></returns>
public static IObject3D Plus(this IObject3D a, IObject3D b, bool doMeshCombine = false)
{
var combine = new CombineObject3D();
combine.Children.Add(a.Clone());
combine.Children.Add(b.Clone());
combine.Combine();
var finalMesh = combine.VisibleMeshes().First().Mesh;
return new Object3D()
if (doMeshCombine)
{
Mesh = finalMesh
};
var combine = new CombineObject3D_2();
combine.Children.Add(a.Clone());
combine.Children.Add(b.Clone());
combine.Combine();
var finalMesh = combine.VisibleMeshes().First().Mesh;
return new Object3D()
{
Mesh = finalMesh
};
}
else
{
var group = new GroupObject3D();
group.Children.Add(a);
group.Children.Add(b);
return group;
}
}
public static IObject3D Minus(this IObject3D a, IObject3D b)
@ -287,81 +306,31 @@ namespace MatterHackers.MatterControl.DesignTools.Operations
return item.GetAxisAlignedBoundingBox().ZSize;
}
public static void AddSelectionAsChildren(this IObject3D newParent, InteractiveScene scene, IObject3D selectedItem)
public static async void AddSelectionAsChildren(this IObject3D newParent, InteractiveScene scene, IObject3D selectedItem)
{
if (selectedItem != null)
{
List<IObject3D> itemsToReplace;
var selectedItems = scene.GetSelectedItems();
if (selectedItem is SelectionGroupObject3D)
using (new SelectionMaintainer(scene))
{
itemsToReplace = selectedItem.Children.ToList();
foreach (var child in itemsToReplace)
using (selectedItem.Parent.RebuildLock())
{
newParent.Children.Add(child.Clone());
foreach (var item in selectedItems)
{
newParent.Children.Add(item.Clone());
}
newParent.MakeNameNonColliding();
scene.UndoBuffer.AddAndDo(
new ReplaceCommand(
selectedItems,
new[] { newParent }));
}
await newParent.Rebuild();
}
else
{
itemsToReplace = new List<IObject3D> { selectedItem };
newParent.Children.Add(selectedItem.Clone());
}
scene.SelectedItem = null;
newParent.MakeNameNonColliding();
scene.UndoBuffer.AddAndDo(
new ReplaceCommand(
itemsToReplace,
new List<IObject3D> { newParent }));
SelectModifiedItem(selectedItem, newParent, scene);
}
}
public static void WrapWith(this IObject3D originalItem, IObject3D wrapper, InteractiveScene scene)
{
// make sure we walk to the top of a mesh wrapper stack before we wrap the item (all mesh wrappers should be under the add)
while(originalItem.Parent is ModifiedMeshObject3D modifiedMesh)
{
originalItem = modifiedMesh;
}
using (originalItem.RebuildLock())
{
originalItem.Parent.Children.Modify(list =>
{
list.Remove(originalItem);
wrapper.Matrix = originalItem.Matrix;
originalItem.Matrix = Matrix4X4.Identity;
wrapper.Children.Add(originalItem);
list.Add(wrapper);
});
SelectModifiedItem(originalItem, wrapper, scene);
}
}
private static void SelectModifiedItem(IObject3D originalItem, IObject3D wrapper, InteractiveScene scene)
{
if (scene != null)
{
var topParent = wrapper.Parents<IObject3D>().LastOrDefault((i) => i.Parent != null);
UiThread.RunOnIdle(() =>
{
var sceneSelection = topParent != null ? topParent : wrapper;
scene.SelectedItem = sceneSelection;
if (sceneSelection != originalItem)
{
// select the sub item in the tree view
//scene.SelectedItem = originalItem;
}
});
}
}

View file

@ -27,109 +27,227 @@ of the authors and should not be interpreted as representing official policies,
either expressed or implied, of the FreeBSD Project.
*/
using MatterHackers.DataConverters3D;
using MatterHackers.Localizations;
using System;
using System.Collections.Generic;
using System.Linq;
using MatterHackers.Agg.UI;
using MatterHackers.DataConverters3D;
using MatterHackers.DataConverters3D.UndoCommands;
using MatterHackers.Localizations;
using MatterHackers.MatterControl.PartPreviewWindow;
using Newtonsoft.Json;
namespace MatterHackers.MatterControl.DesignTools.Operations
{
public class OperationSourceContainerObject3D : Object3D
{
public override bool CanFlatten => true;
[JsonIgnore]
public IObject3D SourceContainer
{
get
{
IObject3D sourceContainer = this.Children.FirstOrDefault(c => c is OperationSourceObject3D);
if (sourceContainer == null)
{
using (this.RebuildLock())
{
sourceContainer = new OperationSourceObject3D();
// Move all the children to sourceContainer
this.Children.Modify(thisChildren =>
{
sourceContainer.Children.Modify(sourceChildren =>
{
foreach (var child in thisChildren)
{
sourceChildren.Add(child);
}
});
// and then add the source container to this
thisChildren.Clear();
thisChildren.Add(sourceContainer);
});
}
}
return sourceContainer;
}
}
public override void Flatten(UndoBuffer undoBuffer)
{
using (RebuildLock())
{
List<IObject3D> newChildren = new List<IObject3D>();
// push our matrix into a copy of our children
foreach (var child in this.Children)
{
if (!(child is OperationSourceObject3D))
{
var newChild = child.Clone();
newChildren.Add(newChild);
newChild.Matrix *= this.Matrix;
var flags = Object3DPropertyFlags.Visible;
if (this.Color.alpha != 0) flags |= Object3DPropertyFlags.Color;
if (this.OutputType != PrintOutputTypes.Default) flags |= Object3DPropertyFlags.OutputType;
if (this.MaterialIndex != -1) flags |= Object3DPropertyFlags.MaterialIndex;
newChild.CopyProperties(this, flags);
}
}
if (newChildren.Count > 1)
{
// wrap the children in an object so they remain a group
var group = new Object3D();
group.Children.Modify((groupList) =>
{
groupList.AddRange(newChildren);
});
newChildren.Clear();
newChildren.Add(group);
}
// add flatten to the name to show what happened
newChildren[0].Name = this.Name + " - " + "Flattened".Localize();
// and replace us with the children
var replaceCommand = new ReplaceCommand(new[] { this }, newChildren);
if (undoBuffer != null)
{
undoBuffer.AddAndDo(replaceCommand);
}
else
{
replaceCommand.Do();
}
foreach (var child in newChildren[0].DescendantsAndSelf())
{
child.MakeNameNonColliding();
}
}
Invalidate(InvalidateType.Children);
}
public override async void OnInvalidate(InvalidateArgs invalidateType)
{
// TODO: color and output type could have special consideration that would not require a rebulid
// They could jus propagate the color and output type to the corecty child and everything would be good
if ((invalidateType.InvalidateType.HasFlag(InvalidateType.Children)
|| invalidateType.InvalidateType.HasFlag(InvalidateType.Matrix)
|| invalidateType.InvalidateType.HasFlag(InvalidateType.Mesh)
|| invalidateType.InvalidateType.HasFlag(InvalidateType.Color)
|| invalidateType.InvalidateType.HasFlag(InvalidateType.OutputType))
&& invalidateType.Source != this
&& !RebuildLocked)
{
await Rebuild();
}
else if (invalidateType.InvalidateType.HasFlag(InvalidateType.Properties)
&& invalidateType.Source == this)
{
await Rebuild();
}
else
{
base.OnInvalidate(invalidateType);
}
}
public override void Remove(UndoBuffer undoBuffer)
{
using (RebuildLock())
{
List<IObject3D> newChildren = new List<IObject3D>();
// push our matrix into a copy of our children
foreach (var child in this.SourceContainer.Children)
{
var newChild = child.Clone();
newChildren.Add(newChild);
newChild.Matrix *= this.Matrix;
var flags = Object3DPropertyFlags.Visible;
if (this.Color.alpha != 0) flags |= Object3DPropertyFlags.Color;
if (this.OutputType != PrintOutputTypes.Default) flags |= Object3DPropertyFlags.OutputType;
if (this.MaterialIndex != -1) flags |= Object3DPropertyFlags.MaterialIndex;
newChild.CopyProperties(this, flags);
}
// and replace us with the children
var replaceCommand = new ReplaceCommand(new[] { this }, newChildren);
if (undoBuffer != null)
{
undoBuffer.AddAndDo(replaceCommand);
}
else
{
replaceCommand.Do();
}
}
Invalidate(InvalidateType.Children);
}
public void RemoveAllButSource()
{
var sourceContainer = SourceContainer;
this.Children.Modify(list =>
{
list.Clear();
list.Add(sourceContainer);
});
}
public async void WrapSelectedItemAndSelect(InteractiveScene scene)
{
using (RebuildLock())
{
var selectedItems = scene.GetSelectedItems();
if (selectedItems.Count > 0)
{
// clear the selected item
scene.SelectedItem = null;
using (RebuildLock())
{
var clonedItemsToAdd = new List<IObject3D>(selectedItems.Select((i) => i.Clone()));
Children.Modify((list) =>
{
list.Clear();
foreach (var child in clonedItemsToAdd)
{
list.Add(child);
}
});
}
scene.UndoBuffer.AddAndDo(
new ReplaceCommand(
new List<IObject3D>(selectedItems),
new List<IObject3D> { this }));
await this.Rebuild();
}
}
// and select this
scene.SelectedItem = this;
this.Invalidate(InvalidateType.Children);
}
}
public class OperationSourceObject3D : Object3D
{
public OperationSourceObject3D()
{
Visible = false;
Name = "Source".Localize();
}
public override bool Visible { get => base.Visible; set => base.Visible = value; }
/// <summary>
/// This function will return the source container and if it does not find one will:
/// <para>find the first child of the parent widget</para>
/// <para>remove it from parent</item>
/// <para>create a new OperationSource</para>
/// <para>add the first child to the OperationSource</para>
/// <para>add the OperationSource to the parent</para>
/// </summary>
/// <param name="parent"></param>
/// <returns>The existing or created OperationSource</returns>
public static IObject3D GetOrCreateSourceContainer(IObject3D parent)
{
IObject3D sourceContainer;
using (parent.RebuildLock())
{
sourceContainer = parent.Children.FirstOrDefault(c => c is OperationSourceObject3D);
if (sourceContainer == null)
{
sourceContainer = new OperationSourceObject3D();
// Move first child to sourceContainer
var firstChild = parent.Children.First();
parent.Children.Remove(firstChild);
sourceContainer.Children.Add(firstChild);
}
}
return sourceContainer;
}
/// <summary>
/// Flatten the children of an object that has an OperationSource in it
/// </summary>
/// <param name="item"></param>
public static void Flatten(IObject3D item)
{
using (item.RebuildLock())
{
// The idea is we leave everything but the source and that is the applied operation
item.Children.Modify(list =>
{
var sourceItem = list.FirstOrDefault(c => c is OperationSourceObject3D);
if (sourceItem != null)
{
list.Remove(sourceItem);
}
if (list.Count > 1)
{
// wrap the children in an object so they remain a group
var group = new Object3D();
group.Children.Modify((groupList) =>
{
groupList.AddRange(list);
});
list.Clear();
list.Add(group);
}
});
}
}
/// <summary>
/// Prepare the children of an object that contains an OpperationSource to be removed
/// </summary>
/// <param name="parent"></param>
internal static void Remove(IObject3D parent)
{
using (parent.RebuildLock())
{
parent.Children.Modify(list =>
{
var sourceItem = list.FirstOrDefault(c => c is OperationSourceObject3D);
if (sourceItem != null)
{
IObject3D firstChild = sourceItem.Children.First();
if (firstChild != null)
{
list.Clear();
list.Add(firstChild);
}
}
});
}
}
}
}

View file

@ -42,6 +42,7 @@ namespace MatterHackers.MatterControl.DesignTools.Operations
using System;
using System.ComponentModel;
using System.Linq;
using System.Threading.Tasks;
using Polygons = List<List<IntPoint>>;
public class InflatePathObject3D : Object3D, IPathObject, IEditorDraw
@ -58,18 +59,18 @@ namespace MatterHackers.MatterControl.DesignTools.Operations
public override void OnInvalidate(InvalidateArgs invalidateType)
{
if ((invalidateType.InvalidateType == InvalidateType.Content
|| invalidateType.InvalidateType == InvalidateType.Matrix
|| invalidateType.InvalidateType == InvalidateType.Path)
if ((invalidateType.InvalidateType.HasFlag(InvalidateType.Children)
|| invalidateType.InvalidateType.HasFlag(InvalidateType.Matrix)
|| invalidateType.InvalidateType.HasFlag(InvalidateType.Path))
&& invalidateType.Source != this
&& !RebuildLocked)
{
Rebuild(null);
Rebuild();
}
else if (invalidateType.InvalidateType == InvalidateType.Properties
else if (invalidateType.InvalidateType.HasFlag(InvalidateType.Properties)
&& invalidateType.Source == this)
{
Rebuild(null);
Rebuild();
}
else
{
@ -77,7 +78,7 @@ namespace MatterHackers.MatterControl.DesignTools.Operations
}
}
private void Rebuild(UndoBuffer undoBuffer)
override public Task Rebuild()
{
this.DebugDepth("Rebuild");
using (RebuildLock())
@ -85,7 +86,8 @@ namespace MatterHackers.MatterControl.DesignTools.Operations
InsetPath();
}
Invalidate(new InvalidateArgs(this, InvalidateType.Path));
Invalidate(InvalidateType.Path);
return Task.CompletedTask;
}
private void InsetPath()

View file

@ -41,6 +41,7 @@ namespace MatterHackers.MatterControl.DesignTools.Operations
using Newtonsoft.Json;
using System;
using System.Linq;
using System.Threading.Tasks;
using Polygon = List<IntPoint>;
using Polygons = List<List<IntPoint>>;
@ -56,20 +57,20 @@ namespace MatterHackers.MatterControl.DesignTools.Operations
public double SmoothDistance { get; set; } = .3;
public int Iterations { get; set; } = 3;
public override void OnInvalidate(InvalidateArgs invalidateType)
public override async void OnInvalidate(InvalidateArgs invalidateType)
{
if ((invalidateType.InvalidateType == InvalidateType.Content
|| invalidateType.InvalidateType == InvalidateType.Matrix
|| invalidateType.InvalidateType == InvalidateType.Path)
if ((invalidateType.InvalidateType.HasFlag(InvalidateType.Children)
|| invalidateType.InvalidateType.HasFlag(InvalidateType.Matrix)
|| invalidateType.InvalidateType.HasFlag(InvalidateType.Path))
&& invalidateType.Source != this
&& !RebuildLocked)
{
Rebuild(null);
await Rebuild();
}
else if (invalidateType.InvalidateType == InvalidateType.Properties
else if (invalidateType.InvalidateType.HasFlag(InvalidateType.Properties)
&& invalidateType.Source == this)
{
Rebuild(null);
await Rebuild();
}
else
{
@ -77,15 +78,22 @@ namespace MatterHackers.MatterControl.DesignTools.Operations
}
}
private void Rebuild(UndoBuffer undoBuffer)
public override Task Rebuild()
{
this.DebugDepth("Rebuild");
using (RebuildLock())
{
DoSmoothing((long)(SmoothDistance * 1000), Iterations);
}
Invalidate(new InvalidateArgs(this, InvalidateType.Path));
var rebuildLock = RebuildLock();
return ApplicationController.Instance.Tasks.Execute(
"Smooth Path".Localize(),
null,
(reporter, cancellationToken) =>
{
DoSmoothing((long)(SmoothDistance * 1000), Iterations);
rebuildLock.Dispose();
Invalidate(InvalidateType.Path);
return Task.CompletedTask;
});
}
private void DoSmoothing(long maxDist, int interations)

View file

@ -0,0 +1,117 @@
/*
Copyright (c) 2018, Lars Brubaker, John Lewin
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
The views and conclusions contained in the software and documentation are those
of the authors and should not be interpreted as representing official policies,
either expressed or implied, of the FreeBSD Project.
*/
using MatterHackers.DataConverters3D;
using MatterHackers.Localizations;
using MatterHackers.MatterControl.DesignTools.Operations;
using MatterHackers.PolygonMesh;
using MatterHackers.VectorMath;
using System.ComponentModel;
using System.Threading;
using System.Threading.Tasks;
namespace MatterHackers.MatterControl.DesignTools
{
public class PinchObject3D_2 : OperationSourceContainerObject3D
{
public PinchObject3D_2()
{
Name = "Pinch".Localize();
}
[DisplayName("Back Ratio")]
public double PinchRatio { get; set; } = .5;
public override Task Rebuild()
{
this.DebugDepth("Rebuild");
var rebuildLocks = this.RebuilLockAll();
return ApplicationController.Instance.Tasks.Execute(
"Pinch".Localize(),
null,
(reporter, cancellationToken) =>
{
SourceContainer.Visible = true;
RemoveAllButSource();
// remember the current matrix then clear it so the parts will rotate at the original wrapped position
var currentMatrix = Matrix;
Matrix = Matrix4X4.Identity;
var aabb = SourceContainer.GetAxisAlignedBoundingBox();
foreach (var sourceItem in SourceContainer.VisibleMeshes())
{
var originalMesh = sourceItem.Mesh;
var transformedMesh = originalMesh.Copy(CancellationToken.None);
var itemMatrix = sourceItem.WorldMatrix(SourceContainer);
var invItemMatrix = itemMatrix.Inverted;
for (int i = 0; i < originalMesh.Vertices.Count; i++)
{
var pos = originalMesh.Vertices[i];
pos = pos.Transform(itemMatrix);
var ratioToApply = PinchRatio;
var distFromCenter = pos.X - aabb.Center.X;
var distanceToPinch = distFromCenter * (1 - PinchRatio);
var delta = (aabb.Center.X + distFromCenter * ratioToApply) - pos.X;
// find out how much to pinch based on y position
var amountOfRatio = (pos.Y - aabb.MinXYZ.Y) / aabb.YSize;
var newPos = new Vector3Float(pos.X + delta * amountOfRatio, pos.Y, pos.Z);
transformedMesh.Vertices[i] = newPos.Transform(invItemMatrix);
}
transformedMesh.MarkAsChanged();
transformedMesh.CalculateNormals();
var newMesh = new Object3D()
{
Mesh = transformedMesh
};
newMesh.CopyWorldProperties(sourceItem, this, Object3DPropertyFlags.All);
this.Children.Add(newMesh);
}
// set the matrix back
Matrix = currentMatrix;
SourceContainer.Visible = false;
rebuildLocks.Dispose();
Invalidate(InvalidateType.Children);
return Task.CompletedTask;
});
}
}
}

View file

@ -35,6 +35,7 @@ using MatterHackers.MatterControl.PartPreviewWindow;
using MatterHackers.MeshVisualizer;
using MatterHackers.VectorMath;
using Newtonsoft.Json;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Threading.Tasks;
@ -48,30 +49,38 @@ namespace MatterHackers.MatterControl.DesignTools.Operations
Name = "Rotate".Localize();
}
public RotateObject3D_2(IObject3D itemToRotate, Vector3 normal, double angleDegrees)
: this()
{
WrapItems(new IObject3D[] { itemToRotate });
RotateAbout.Normal = normal;
AngleDegrees = angleDegrees;
}
public RotateObject3D_2(IObject3D itemToRotate, double xRadians = 0, double yRadians = 0, double zRadians = 0, string name = "")
: this()
{
WrapItem(itemToRotate);
WrapItems(new IObject3D[] { itemToRotate });
// TODO: set the rotation
//RotateAbout.Normal = Vector3.UnitZ.TransformNormal(Matrix4X4.CreateRotation(new Vector3(xRadians, yRadians, zRadians)));
}
public RotateObject3D_2(IObject3D itemToRotate, Vector3 translation, string name = "")
: this(itemToRotate, translation.X, translation.Y, translation.Z, name)
public RotateObject3D_2(IObject3D itemToRotate, Vector3 rotation, string name = "")
: this(itemToRotate, rotation.X, rotation.Y, rotation.Z, name)
{
}
public override void WrapItem(IObject3D item, UndoBuffer undoBuffer = null)
public override void WrapItems(IEnumerable<IObject3D> items, UndoBuffer undoBuffer = null)
{
base.WrapItem(item, undoBuffer);
base.WrapItems(items, undoBuffer);
// use source item as the wrape may have cloned it
var aabb = SourceItem.GetAxisAlignedBoundingBox();
var aabb = SourceItems.GetAxisAlignedBoundingBox();
this.RotateAbout.Origin = aabb.Center;
}
public override bool CanFlatten => true;
#region // editable properties
public DirectionAxis RotateAbout { get; set; } = new DirectionAxis() { Origin = Vector3.Zero, Normal = Vector3.UnitZ };
[DisplayName("Angle")]
@ -102,20 +111,20 @@ namespace MatterHackers.MatterControl.DesignTools.Operations
}
}
public override void OnInvalidate(InvalidateArgs invalidateArgs)
public override async void OnInvalidate(InvalidateArgs invalidateArgs)
{
if ((invalidateArgs.InvalidateType == InvalidateType.Content
|| invalidateArgs.InvalidateType == InvalidateType.Matrix
|| invalidateArgs.InvalidateType == InvalidateType.Mesh)
if ((invalidateArgs.InvalidateType.HasFlag(InvalidateType.Children)
|| invalidateArgs.InvalidateType.HasFlag(InvalidateType.Matrix)
|| invalidateArgs.InvalidateType.HasFlag(InvalidateType.Mesh))
&& invalidateArgs.Source != this
&& !RebuildLocked)
{
Rebuild();
await Rebuild();
}
else if (invalidateArgs.InvalidateType == InvalidateType.Properties
else if (invalidateArgs.InvalidateType.HasFlag(InvalidateType.Properties)
&& invalidateArgs.Source == this)
{
Rebuild();
await Rebuild();
}
base.OnInvalidate(invalidateArgs);
@ -129,7 +138,7 @@ namespace MatterHackers.MatterControl.DesignTools.Operations
TransformItem.Matrix = RotationMatrix;
}
Invalidate(new InvalidateArgs(this, InvalidateType.Matrix, null));
Invalidate(InvalidateType.Matrix);
return Task.CompletedTask;
}

View file

@ -36,6 +36,7 @@ using MatterHackers.MeshVisualizer;
using MatterHackers.VectorMath;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Threading.Tasks;
@ -58,22 +59,23 @@ namespace MatterHackers.MatterControl.DesignTools.Operations
public ScaleObject3D(IObject3D itemToScale, Vector3 scale)
: this()
{
WrapItem(itemToScale);
WrapItems(new IObject3D[] { itemToScale });
ScaleRatio = scale;
Rebuild();
}
public override void WrapItem(IObject3D item, UndoBuffer undoBuffer = null)
public override void WrapItems(IEnumerable<IObject3D> items, UndoBuffer undoBuffer = null)
{
base.WrapItem(item, undoBuffer);
base.WrapItems(items, undoBuffer);
// use source item as it may be a copy of item by the time we have wrapped it
var aabb = SourceItem.GetAxisAlignedBoundingBox();
var aabb = SourceItems.GetAxisAlignedBoundingBox();
var newCenter = new Vector3(aabb.Center.X, aabb.Center.Y, aabb.MinXYZ.Z);
SourceItem.Translate(-newCenter);
SourceItems.Translate(-newCenter);
this.Translate(newCenter);
}
public override bool CanFlatten => true;
// this is the size we actually serialize
public Vector3 ScaleRatio = Vector3.One;
@ -91,7 +93,7 @@ namespace MatterHackers.MatterControl.DesignTools.Operations
return ScaleRatio.X * 100;
}
return ScaleRatio.X * SourceItem.XSize();
return ScaleRatio.X * SourceItems.GetAxisAlignedBoundingBox().XSize;
}
set
@ -102,7 +104,7 @@ namespace MatterHackers.MatterControl.DesignTools.Operations
}
else
{
ScaleRatio.X = value / SourceItem.XSize();
ScaleRatio.X = value / SourceItems.GetAxisAlignedBoundingBox().XSize;
}
}
}
@ -118,7 +120,7 @@ namespace MatterHackers.MatterControl.DesignTools.Operations
return ScaleRatio.Y * 100;
}
return ScaleRatio.Y * SourceItem.YSize();
return ScaleRatio.Y * SourceItems.GetAxisAlignedBoundingBox().YSize;
}
set
@ -129,7 +131,7 @@ namespace MatterHackers.MatterControl.DesignTools.Operations
}
else
{
ScaleRatio.Y = value / SourceItem.YSize();
ScaleRatio.Y = value / SourceItems.GetAxisAlignedBoundingBox().YSize;
}
}
}
@ -145,7 +147,7 @@ namespace MatterHackers.MatterControl.DesignTools.Operations
return ScaleRatio.Z * 100;
}
return ScaleRatio.Z * SourceItem.ZSize();
return ScaleRatio.Z * SourceItems.GetAxisAlignedBoundingBox().ZSize;
}
set
@ -156,7 +158,7 @@ namespace MatterHackers.MatterControl.DesignTools.Operations
}
else
{
ScaleRatio.Z = value / SourceItem.ZSize();
ScaleRatio.Z = value / SourceItems.GetAxisAlignedBoundingBox().ZSize;
}
}
}
@ -183,23 +185,25 @@ namespace MatterHackers.MatterControl.DesignTools.Operations
}
}
public override void OnInvalidate(InvalidateArgs invalidateArgs)
public async override void OnInvalidate(InvalidateArgs invalidateArgs)
{
if ((invalidateArgs.InvalidateType == InvalidateType.Content
|| invalidateArgs.InvalidateType == InvalidateType.Matrix
|| invalidateArgs.InvalidateType == InvalidateType.Mesh)
if ((invalidateArgs.InvalidateType.HasFlag(InvalidateType.Children)
|| invalidateArgs.InvalidateType.HasFlag(InvalidateType.Matrix)
|| invalidateArgs.InvalidateType.HasFlag(InvalidateType.Mesh))
&& invalidateArgs.Source != this
&& !RebuildLocked)
{
Rebuild();
await Rebuild();
}
else if (invalidateArgs.InvalidateType == InvalidateType.Properties
else if (invalidateArgs.InvalidateType.HasFlag(InvalidateType.Properties)
&& invalidateArgs.Source == this)
{
Rebuild();
await Rebuild();
}
else
{
base.OnInvalidate(invalidateArgs);
}
base.OnInvalidate(invalidateArgs);
}
public override Task Rebuild()
@ -213,7 +217,7 @@ namespace MatterHackers.MatterControl.DesignTools.Operations
TransformItem.Matrix *= Matrix4X4.CreateTranslation(ScaleAbout);
}
Invalidate(new InvalidateArgs(this, InvalidateType.Matrix, null));
Invalidate(InvalidateType.Matrix);
return Task.CompletedTask;
}
@ -259,7 +263,7 @@ namespace MatterHackers.MatterControl.DesignTools.Operations
else if(change.Changed == nameof(UsePercentage))
{
// make sure we update the controls on screen to reflect the different data type
base.OnInvalidate(new InvalidateArgs(this, InvalidateType.Properties));
Invalidate(InvalidateType.Properties);
}
else if (change.Changed == nameof(MaitainProportions))
{

View file

@ -29,25 +29,40 @@ either expressed or implied, of the FreeBSD Project.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using MatterHackers.Agg;
using MatterHackers.Agg.UI;
using MatterHackers.DataConverters3D;
using MatterHackers.DataConverters3D.UndoCommands;
using MatterHackers.Localizations;
using MatterHackers.MatterControl.PartPreviewWindow;
using MatterHackers.MatterControl.PartPreviewWindow.View3D;
using MatterHackers.MeshVisualizer;
using MatterHackers.RenderOpenGl;
using MatterHackers.RenderOpenGl.OpenGl;
using MatterHackers.VectorMath;
using Newtonsoft.Json;
using static MatterHackers.DataConverters3D.Object3DExtensions;
namespace MatterHackers.MatterControl.DesignTools.Operations
{
public abstract class TransformWrapperObject3D : Object3D
{
public TransformWrapperObject3D()
{
Name = "Transform Wrapper".Localize();
}
public override bool CanFlatten => true;
[JsonIgnore]
public SafeList<IObject3D> SourceItems
{
get
{
if (TransformItem?.Children.Count > 0)
{
return TransformItem.Children;
}
return null;
}
}
protected IObject3D TransformItem
{
get
@ -61,78 +76,6 @@ namespace MatterHackers.MatterControl.DesignTools.Operations
}
}
[JsonIgnore]
public IObject3D SourceItem
{
get
{
if (TransformItem?.Children.Count > 0)
{
return TransformItem.Children.First();
}
return null;
}
}
public TransformWrapperObject3D()
{
Name = "Transform Wrapper".Localize();
}
public virtual void WrapItem(IObject3D item, UndoBuffer undoBuffer = null)
{
using (item.RebuilLockAll())
{
RebuildLock parentLock = null;
if (item.Parent != null)
{
parentLock = item.Parent.RebuildLock();
}
if (item is SelectionGroupObject3D)
{
throw new Exception("The selection should have been cleared before you wrap this item");
}
while (item.Parent is ModifiedMeshObject3D)
{
item = item.Parent;
}
// if the items we are replacing ar already in a list
if (item.Parent != null)
{
var firstChild = new Object3D();
this.Children.Add(firstChild);
if (undoBuffer != null)
{
IObject3D replaceItem = item.Clone();
firstChild.Children.Add(replaceItem);
var replace = new ReplaceCommand(new List<IObject3D> { item }, new List<IObject3D> { this });
undoBuffer.AddAndDo(replace);
}
else
{
item.Parent.Children.Modify(list =>
{
list.Remove(item);
list.Add(this);
});
firstChild.Children.Add(item);
}
}
else // just add them
{
var firstChild = new Object3D();
firstChild.Children.Add(item);
this.Children.Add(firstChild);
}
parentLock?.Dispose();
}
}
public override void Flatten(UndoBuffer undoBuffer)
{
using (RebuildLock())
@ -144,7 +87,10 @@ namespace MatterHackers.MatterControl.DesignTools.Operations
}
// push child into children
SourceItem.Matrix *= TransformItem.Matrix;
foreach (var item in SourceItems)
{
item.Matrix *= TransformItem.Matrix;
}
// add our children to our parent and remove from parent
this.Parent.Children.Modify(list =>
@ -153,7 +99,7 @@ namespace MatterHackers.MatterControl.DesignTools.Operations
list.AddRange(TransformItem.Children);
});
}
Invalidate(new InvalidateArgs(this, InvalidateType.Content));
Invalidate(InvalidateType.Children);
}
public override void Remove(UndoBuffer undoBuffer)
@ -174,7 +120,53 @@ namespace MatterHackers.MatterControl.DesignTools.Operations
});
}
Invalidate(new InvalidateArgs(this, InvalidateType.Content));
Invalidate(InvalidateType.Children);
}
public virtual void WrapItems(IEnumerable<IObject3D> items, UndoBuffer undoBuffer = null)
{
var parent = items.First().Parent;
RebuildLocks parentLock = (parent == null) ? null : parent.RebuilLockAll();
var firstChild = new Object3D();
this.Children.Add(firstChild);
// if the items we are replacing are already in a list
if (parent != null)
{
if (undoBuffer != null)
{
foreach (var item in items)
{
firstChild.Children.Add(item.Clone());
}
var replace = new ReplaceCommand(items, new[] { this });
undoBuffer.AddAndDo(replace);
}
else
{
parent.Children.Modify(list =>
{
foreach (var item in items)
{
list.Remove(item);
firstChild.Children.Add(item);
}
list.Add(this);
});
}
}
else // just add them
{
firstChild.Children.Modify(list =>
{
list.AddRange(items);
});
}
parentLock?.Dispose();
parent?.Invalidate(new InvalidateArgs(parent, InvalidateType.Children));
}
}
}

View file

@ -32,6 +32,7 @@ using MatterHackers.DataConverters3D;
using MatterHackers.Localizations;
using MatterHackers.VectorMath;
using System.Linq;
using System.Threading.Tasks;
namespace MatterHackers.MatterControl.DesignTools.Operations
{
@ -52,13 +53,11 @@ namespace MatterHackers.MatterControl.DesignTools.Operations
{
using (this.RebuildLock())
{
WrapItem(itemToTranslate);
WrapItems(new IObject3D[] { itemToTranslate });
Matrix = Matrix4X4.CreateTranslation(translation);
}
}
public override bool CanFlatten => true;
public static TranslateObject3D Create(IObject3D itemToTranslate)
{
var translate = new TranslateObject3D();
@ -79,18 +78,18 @@ namespace MatterHackers.MatterControl.DesignTools.Operations
public override void OnInvalidate(InvalidateArgs invalidateType)
{
if ((invalidateType.InvalidateType == InvalidateType.Content
|| invalidateType.InvalidateType == InvalidateType.Matrix
|| invalidateType.InvalidateType == InvalidateType.Mesh)
if ((invalidateType.InvalidateType.HasFlag(InvalidateType.Children)
|| invalidateType.InvalidateType.HasFlag(InvalidateType.Matrix)
|| invalidateType.InvalidateType.HasFlag(InvalidateType.Mesh))
&& invalidateType.Source != this
&& !RebuildLocked)
{
Rebuild(null);
Rebuild();
}
else if (invalidateType.InvalidateType == InvalidateType.Properties
else if (invalidateType.InvalidateType.HasFlag(InvalidateType.Properties)
&& invalidateType.Source == this)
{
Rebuild(null);
Rebuild();
}
else
{
@ -98,7 +97,7 @@ namespace MatterHackers.MatterControl.DesignTools.Operations
}
}
private void Rebuild(UndoBuffer undoBuffer)
public override Task Rebuild()
{
this.DebugDepth("Rebuild");
@ -108,7 +107,8 @@ namespace MatterHackers.MatterControl.DesignTools.Operations
TransformItem.Matrix = Matrix4X4.CreateTranslation(Translation);
}
Invalidate(new InvalidateArgs(this, InvalidateType.Matrix, null));
Invalidate(InvalidateType.Matrix);
return Task.CompletedTask;
}
}
}

View file

@ -30,6 +30,7 @@ either expressed or implied, of the FreeBSD Project.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using ClipperLib;
using MatterHackers.Agg.Transform;
using MatterHackers.Agg.UI;
@ -37,6 +38,7 @@ using MatterHackers.Agg.VertexSource;
using MatterHackers.DataConverters2D;
using MatterHackers.DataConverters3D;
using MatterHackers.Localizations;
using MatterHackers.MatterControl.DesignTools.Operations;
using MatterHackers.VectorMath;
using Newtonsoft.Json;
@ -66,22 +68,17 @@ namespace MatterHackers.MatterControl.DesignTools
{
using (RebuildLock())
{
var startingAabb = this.GetAxisAlignedBoundingBox();
var firstChild = this.Children.FirstOrDefault();
// only keep the first object
this.Children.Modify(list =>
using (new CenterAndHeightMantainer(this))
{
list.Clear();
// add back in the sourceContainer
list.Add(firstChild);
});
var firstChild = this.Children.FirstOrDefault();
if (startingAabb.ZSize > 0)
{
// If the part was already created and at a height, maintain the height.
PlatingHelper.PlaceMeshAtHeight(this, startingAabb.MinXYZ.Z);
// only keep the first object
this.Children.Modify(list =>
{
list.Clear();
// add back in the sourceContainer
list.Add(firstChild);
});
}
}
@ -106,68 +103,67 @@ namespace MatterHackers.MatterControl.DesignTools
}
}
public static BaseObject3D Create()
public static async Task<BaseObject3D> Create()
{
var item = new BaseObject3D();
item.Rebuild(null);
await item.Rebuild();
return item;
}
public override void OnInvalidate(InvalidateArgs invalidateType)
public override async void OnInvalidate(InvalidateArgs invalidateType)
{
if ((invalidateType.InvalidateType == InvalidateType.Content
|| invalidateType.InvalidateType == InvalidateType.Matrix
|| invalidateType.InvalidateType == InvalidateType.Path
|| invalidateType.InvalidateType == InvalidateType.Mesh)
if ((invalidateType.InvalidateType.HasFlag(InvalidateType.Children)
|| invalidateType.InvalidateType.HasFlag(InvalidateType.Matrix)
|| invalidateType.InvalidateType.HasFlag(InvalidateType.Path)
|| invalidateType.InvalidateType.HasFlag(InvalidateType.Mesh))
&& invalidateType.Source != this
&& !RebuildLocked)
{
Rebuild(null);
await Rebuild();
}
else if (invalidateType.InvalidateType == InvalidateType.Properties
else if (invalidateType.InvalidateType.HasFlag(InvalidateType.Properties)
&& invalidateType.Source == this)
{
Rebuild(null);
}
else
{
base.OnInvalidate(invalidateType);
await Rebuild();
}
base.OnInvalidate(invalidateType);
}
private void Rebuild(UndoBuffer undoBuffer)
public override Task Rebuild()
{
this.DebugDepth("Rebuild");
using (RebuildLock())
{
var startingAabb = this.GetAxisAlignedBoundingBox();
var rebuildLock = this.RebuildLock();
var firstChild = this.Children.FirstOrDefault();
// remove the base mesh we added
this.Children.Modify(list =>
return ApplicationController.Instance.Tasks.Execute(
"Base".Localize(),
null,
(reporter, cancellationToken) =>
{
list.Clear();
// add back in the sourceContainer
list.Add(firstChild);
using (new CenterAndHeightMantainer(this))
{
var firstChild = this.Children.FirstOrDefault();
// remove the base mesh we added
this.Children.Modify(list =>
{
list.Clear();
// add back in the sourceContainer
list.Add(firstChild);
});
// and create the base
var vertexSource = this.VertexSource;
// Convert VertexSource into expected Polygons
Polygons polygonShape = (vertexSource == null) ? null : vertexSource.CreatePolygons();
GenerateBase(polygonShape, firstChild.GetAxisAlignedBoundingBox().MinXYZ.Z);
}
rebuildLock.Dispose();
Invalidate(InvalidateType.Children);
return Task.CompletedTask;
});
// and create the base
var vertexSource = this.VertexSource;
// Convert VertexSource into expected Polygons
Polygons polygonShape = (vertexSource == null) ? null : vertexSource.CreatePolygons();
GenerateBase(polygonShape, firstChild.GetAxisAlignedBoundingBox().MinXYZ.Z);
if (startingAabb.ZSize > 0)
{
// If the part was already created and at a height, maintain the height.
PlatingHelper.PlaceMeshAtHeight(this, startingAabb.MinXYZ.Z);
}
}
Invalidate(new InvalidateArgs(this, InvalidateType.Mesh));
}
private static Polygon GetBoundingPolygon(Polygons basePolygons)

View file

@ -27,18 +27,21 @@ of the authors and should not be interpreted as representing official policies,
either expressed or implied, of the FreeBSD Project.
*/
using System.Collections.Generic;
using System.Linq;
using MatterHackers.Agg.UI;
using MatterHackers.DataConverters3D;
using MatterHackers.DataConverters3D.UndoCommands;
using MatterHackers.Localizations;
using MatterHackers.MatterControl.CustomWidgets;
using MatterHackers.MatterControl.DesignTools.Operations;
using System.Collections.Generic;
using MatterHackers.Localizations;
namespace MatterHackers.MatterControl.DesignTools
{
public class ComponentObject3D : Object3D, IVisualLeafNode
{
private const string imageConverterComponentID = "4D9BD8DB-C544-4294-9C08-4195A409217A";
public ComponentObject3D()
{
}
@ -73,7 +76,7 @@ namespace MatterHackers.MatterControl.DesignTools
newChildren.Add(meshOnlyItem);
}
if(newChildren.Count > 1)
if (newChildren.Count > 1)
{
var group = new GroupObject3D();
group.Name = this.Name;
@ -84,16 +87,52 @@ namespace MatterHackers.MatterControl.DesignTools
newChildren.Clear();
newChildren.Add(group);
}
else if(newChildren.Count == 1)
else if (newChildren.Count == 1)
{
newChildren[0].Name = this.Name;
}
// and replace us with the children
undoBuffer.AddAndDo(new ReplaceCommand(new List<IObject3D> { this }, newChildren));
undoBuffer.AddAndDo(new ReplaceCommand(new[] { this }, newChildren));
}
Invalidate(new InvalidateArgs(this, InvalidateType.Content, undoBuffer));
Invalidate(InvalidateType.Children);
}
public override void Remove(UndoBuffer undoBuffer)
{
// Custom remove for ImageConverter
if (this.ComponentID == imageConverterComponentID)
{
var parent = this.Parent;
using (RebuildLock())
{
if (this.Descendants<ImageObject3D>().FirstOrDefault() is ImageObject3D imageObject3D)
{
imageObject3D.Matrix = this.Matrix;
if (undoBuffer != null)
{
undoBuffer.AddAndDo(new ReplaceCommand(new[] { this }, new[] { imageObject3D }));
}
else
{
parent.Children.Modify(list =>
{
list.Remove(this);
list.Add(imageObject3D);
});
}
}
}
parent.Invalidate(new InvalidateArgs(this, InvalidateType.Children));
}
else
{
base.Remove(undoBuffer);
}
}
}
}

View file

@ -30,11 +30,13 @@ either expressed or implied, of the FreeBSD Project.
using System;
using System.ComponentModel;
using System.Threading;
using System.Threading.Tasks;
using MatterHackers.Agg;
using MatterHackers.Agg.UI;
using MatterHackers.Agg.VertexSource;
using MatterHackers.DataConverters3D;
using MatterHackers.Localizations;
using MatterHackers.MatterControl.DesignTools.Operations;
using MatterHackers.PolygonMesh;
using MatterHackers.VectorMath;
@ -48,10 +50,11 @@ namespace MatterHackers.MatterControl.DesignTools
Color = Operations.Object3DExtensions.PrimitiveColors["Cone"];
}
public static ConeObject3D Create()
public static async Task<ConeObject3D> Create()
{
var item = new ConeObject3D();
item.Rebuild(null);
await item.Rebuild();
return item;
}
@ -61,46 +64,45 @@ namespace MatterHackers.MatterControl.DesignTools
public double Height { get; set; } = 20;
public int Sides { get; set; } = 40;
public override void OnInvalidate(InvalidateArgs invalidateType)
public override async void OnInvalidate(InvalidateArgs invalidateType)
{
if (invalidateType.InvalidateType == InvalidateType.Properties
if (invalidateType.InvalidateType.HasFlag(InvalidateType.Properties)
&& invalidateType.Source == this)
{
Rebuild(null);
}
else
{
base.OnInvalidate(invalidateType);
await Rebuild();
}
base.OnInvalidate(invalidateType);
}
private void Rebuild(UndoBuffer undoBuffer)
private Task Rebuild()
{
this.DebugDepth("Rebuild");
bool changed = false;
using (RebuildLock())
{
Sides = agg_basics.Clamp(Sides, 3, 360, ref changed);
var aabb = this.GetAxisAlignedBoundingBox();
this.DebugDepth("Rebuild");
var path = new VertexStorage();
path.MoveTo(0, 0);
path.LineTo(Diameter / 2, 0);
path.LineTo(0, Height);
var rebuildLock = this.RebuildLock();
Mesh = VertexSourceToMesh.Revolve(path, Sides);
if (aabb.ZSize > 0)
return ApplicationController.Instance.Tasks.Execute(
"Cone".Localize(),
null,
(reporter, cancellationToken) =>
{
// If the part was already created and at a height, maintain the height.
PlatingHelper.PlaceMeshAtHeight(this, aabb.MinXYZ.Z);
}
}
Sides = agg_basics.Clamp(Sides, 3, 360, ref changed);
using (new CenterAndHeightMantainer(this))
{
Invalidate(new InvalidateArgs(this, InvalidateType.Mesh));
if (changed)
{
base.OnInvalidate(new InvalidateArgs(this, InvalidateType.Properties));
}
var path = new VertexStorage();
path.MoveTo(0, 0);
path.LineTo(Diameter / 2, 0);
path.LineTo(0, Height);
Mesh = VertexSourceToMesh.Revolve(path, Sides);
}
rebuildLock.Dispose();
Invalidate(InvalidateType.Children);
return Task.CompletedTask;
});
}
}
}

View file

@ -27,10 +27,12 @@ of the authors and should not be interpreted as representing official policies,
either expressed or implied, of the FreeBSD Project.
*/
using System.Threading.Tasks;
using MatterHackers.Agg;
using MatterHackers.Agg.UI;
using MatterHackers.DataConverters3D;
using MatterHackers.Localizations;
using MatterHackers.MatterControl.DesignTools.Operations;
using MatterHackers.PolygonMesh;
namespace MatterHackers.MatterControl.DesignTools
@ -43,15 +45,6 @@ namespace MatterHackers.MatterControl.DesignTools
Color = Operations.Object3DExtensions.PrimitiveColors["Cube"];
}
public CubeObject3D(double width, double depth, double height)
: this()
{
Width = width;
Depth = depth;
Height = height;
Rebuild(null);
}
public double Width { get; set; } = 20;
public double Depth { get; set; } = 20;
public double Height { get; set; } = 20;
@ -59,7 +52,7 @@ namespace MatterHackers.MatterControl.DesignTools
public static CubeObject3D Create()
{
var item = new CubeObject3D();
item.Rebuild(null);
item.Rebuild();
return item;
}
@ -72,40 +65,33 @@ namespace MatterHackers.MatterControl.DesignTools
Height = z,
};
item.Rebuild(null);
item.Rebuild();
return item;
}
public override void OnInvalidate(InvalidateArgs invalidateType)
{
if (invalidateType.InvalidateType == InvalidateType.Properties
if (invalidateType.InvalidateType.HasFlag(InvalidateType.Properties)
&& invalidateType.Source == this)
{
Rebuild(null);
}
else
{
base.OnInvalidate(invalidateType);
Rebuild();
}
base.OnInvalidate(invalidateType);
}
private void Rebuild(UndoBuffer undoBuffer)
public override Task Rebuild()
{
this.DebugDepth("Rebuild");
using (RebuildLock())
{
var aabb = this.GetAxisAlignedBoundingBox();
Mesh = PlatonicSolids.CreateCube(Width, Depth, Height);
if (aabb.ZSize > 0)
using (new CenterAndHeightMantainer(this))
{
// If the part was already created and at a height, maintain the height.
PlatingHelper.PlaceMeshAtHeight(this, aabb.MinXYZ.Z);
Mesh = PlatonicSolids.CreateCube(Width, Depth, Height);
}
}
Invalidate(new InvalidateArgs(this, InvalidateType.Mesh));
return Task.CompletedTask;
}
}
}

View file

@ -35,6 +35,7 @@ using MatterHackers.Localizations;
using MatterHackers.MatterControl.DesignTools.Operations;
using MatterHackers.VectorMath;
using System;
using System.Threading.Tasks;
namespace MatterHackers.MatterControl.DesignTools
{
@ -53,7 +54,7 @@ namespace MatterHackers.MatterControl.DesignTools
Height = height;
Sides = sides;
Rebuild(null);
Rebuild();
}
public static CylinderObject3D Create(double diameter, double height, int sides, Alignment alignment = Alignment.Z)
@ -77,7 +78,7 @@ namespace MatterHackers.MatterControl.DesignTools
Sides = sides,
};
item.Rebuild(null);
item.Rebuild();
switch (alignment)
{
case Alignment.X:
@ -106,7 +107,7 @@ namespace MatterHackers.MatterControl.DesignTools
{
var item = new CylinderObject3D();
item.Rebuild(null);
item.Rebuild();
return item;
}
@ -121,18 +122,16 @@ namespace MatterHackers.MatterControl.DesignTools
public override void OnInvalidate(InvalidateArgs invalidateType)
{
if (invalidateType.InvalidateType == InvalidateType.Properties
if (invalidateType.InvalidateType.HasFlag(InvalidateType.Properties)
&& invalidateType.Source == this)
{
Rebuild(null);
}
else
{
base.OnInvalidate(invalidateType);
Rebuild();
}
base.OnInvalidate(invalidateType);
}
private void Rebuild(UndoBuffer undoBuffer)
override public Task Rebuild()
{
this.DebugDepth("Rebuild");
bool changed = false;
@ -143,41 +142,38 @@ namespace MatterHackers.MatterControl.DesignTools
Height = Math.Max(Height, .001);
Diameter = Math.Max(Diameter, .1);
var aabb = this.GetAxisAlignedBoundingBox();
if (!Advanced)
using (new CenterAndHeightMantainer(this))
{
var path = new VertexStorage();
path.MoveTo(0, -Height / 2);
path.LineTo(Diameter / 2, -Height / 2);
path.LineTo(Diameter / 2, Height / 2);
path.LineTo(0, Height / 2);
if (!Advanced)
{
var path = new VertexStorage();
path.MoveTo(0, -Height / 2);
path.LineTo(Diameter / 2, -Height / 2);
path.LineTo(Diameter / 2, Height / 2);
path.LineTo(0, Height / 2);
Mesh = VertexSourceToMesh.Revolve(path, Sides);
}
else
{
var path = new VertexStorage();
path.MoveTo(0, -Height / 2);
path.LineTo(Diameter / 2, -Height / 2);
path.LineTo(DiameterTop / 2, Height / 2);
path.LineTo(0, Height / 2);
Mesh = VertexSourceToMesh.Revolve(path, Sides);
}
else
{
var path = new VertexStorage();
path.MoveTo(0, -Height / 2);
path.LineTo(Diameter / 2, -Height / 2);
path.LineTo(DiameterTop / 2, Height / 2);
path.LineTo(0, Height / 2);
Mesh = VertexSourceToMesh.Revolve(path, Sides, MathHelper.DegreesToRadians(StartingAngle), MathHelper.DegreesToRadians(EndingAngle));
}
if (aabb.ZSize > 0)
{
// If the part was already created and at a height, maintain the height.
PlatingHelper.PlaceMeshAtHeight(this, aabb.MinXYZ.Z);
Mesh = VertexSourceToMesh.Revolve(path, Sides, MathHelper.DegreesToRadians(StartingAngle), MathHelper.DegreesToRadians(EndingAngle));
}
}
}
Invalidate(new InvalidateArgs(this, InvalidateType.Mesh));
Invalidate(InvalidateType.Mesh);
if (changed)
{
base.OnInvalidate(new InvalidateArgs(this, InvalidateType.Properties));
Invalidate(InvalidateType.Properties);
}
return Task.CompletedTask;
}
public void UpdateControls(PublicPropertyChange change)

View file

@ -29,11 +29,13 @@ either expressed or implied, of the FreeBSD Project.
using System;
using System.ComponentModel;
using System.Threading.Tasks;
using MatterHackers.Agg;
using MatterHackers.Agg.UI;
using MatterHackers.Agg.VertexSource;
using MatterHackers.DataConverters3D;
using MatterHackers.Localizations;
using MatterHackers.MatterControl.DesignTools.Operations;
using MatterHackers.VectorMath;
namespace MatterHackers.MatterControl.DesignTools
@ -50,7 +52,7 @@ namespace MatterHackers.MatterControl.DesignTools
{
var item = new HalfCylinderObject3D();
item.Rebuild(null);
item.Rebuild();
return item;
}
@ -60,51 +62,46 @@ namespace MatterHackers.MatterControl.DesignTools
public override void OnInvalidate(InvalidateArgs invalidateType)
{
if (invalidateType.InvalidateType == InvalidateType.Properties
if (invalidateType.InvalidateType.HasFlag(InvalidateType.Properties)
&& invalidateType.Source == this)
{
Rebuild(null);
}
else
{
base.OnInvalidate(invalidateType);
Rebuild();
}
base.OnInvalidate(invalidateType);
}
private void Rebuild(UndoBuffer undoBuffer)
override public Task Rebuild()
{
this.DebugDepth("Rebuild");
bool changed = false;
using (RebuildLock())
{
Sides = agg_basics.Clamp(Sides, 3, 180, ref changed);
var aabb = this.GetAxisAlignedBoundingBox();
var path = new VertexStorage();
path.MoveTo(Width / 2, 0);
for (int i = 1; i < Sides; i++)
using (new CenterAndHeightMantainer(this))
{
var angle = MathHelper.Tau * i / 2 / (Sides - 1);
path.LineTo(Math.Cos(angle) * Width / 2, Math.Sin(angle) * Width / 2);
}
var path = new VertexStorage();
path.MoveTo(Width / 2, 0);
var mesh = VertexSourceToMesh.Extrude(path, Depth);
mesh.Transform(Matrix4X4.CreateRotationX(MathHelper.Tau / 4));
Mesh = mesh;
for (int i = 1; i < Sides; i++)
{
var angle = MathHelper.Tau * i / 2 / (Sides - 1);
path.LineTo(Math.Cos(angle) * Width / 2, Math.Sin(angle) * Width / 2);
}
if (aabb.ZSize > 0)
{
// If the part was already created and at a height, maintain the height.
PlatingHelper.PlaceMeshAtHeight(this, aabb.MinXYZ.Z);
var mesh = VertexSourceToMesh.Extrude(path, Depth);
mesh.Transform(Matrix4X4.CreateRotationX(MathHelper.Tau / 4));
Mesh = mesh;
}
}
Invalidate(new InvalidateArgs(this, InvalidateType.Mesh));
Invalidate(InvalidateType.Mesh);
if (changed)
{
base.OnInvalidate(new InvalidateArgs(this, InvalidateType.Properties));
Invalidate(InvalidateType.Properties);
}
return Task.CompletedTask;
}
}
}

View file

@ -29,11 +29,13 @@ either expressed or implied, of the FreeBSD Project.
using System;
using System.ComponentModel;
using System.Threading.Tasks;
using MatterHackers.Agg;
using MatterHackers.Agg.UI;
using MatterHackers.Agg.VertexSource;
using MatterHackers.DataConverters3D;
using MatterHackers.Localizations;
using MatterHackers.MatterControl.DesignTools.Operations;
using MatterHackers.VectorMath;
namespace MatterHackers.MatterControl.DesignTools
@ -51,14 +53,14 @@ namespace MatterHackers.MatterControl.DesignTools
this.Diameter = diametar;
this.LatitudeSides = sides;
this.LongitudeSides = sides;
Rebuild(null);
Rebuild();
}
public static HalfSphereObject3D Create()
{
var item = new HalfSphereObject3D();
item.Rebuild(null);
item.Rebuild();
return item;
}
@ -68,18 +70,16 @@ namespace MatterHackers.MatterControl.DesignTools
public override void OnInvalidate(InvalidateArgs invalidateType)
{
if (invalidateType.InvalidateType == InvalidateType.Properties
if (invalidateType.InvalidateType.HasFlag(InvalidateType.Properties)
&& invalidateType.Source == this)
{
Rebuild(null);
}
else
{
base.OnInvalidate(invalidateType);
Rebuild();
}
base.OnInvalidate(invalidateType);
}
private void Rebuild(UndoBuffer undoBuffer)
override public Task Rebuild()
{
this.DebugDepth("Rebuild");
bool changed = false;
@ -88,33 +88,31 @@ namespace MatterHackers.MatterControl.DesignTools
LatitudeSides = agg_basics.Clamp(LatitudeSides, 3, 180, ref changed);
LongitudeSides = agg_basics.Clamp(LongitudeSides, 3, 360, ref changed);
var aabb = this.GetAxisAlignedBoundingBox();
var radius = Diameter / 2;
var angleDelta = MathHelper.Tau / 4 / LatitudeSides;
var angle = 0.0;
var path = new VertexStorage();
path.MoveTo(0, 0);
path.LineTo(new Vector2(radius * Math.Cos(angle), radius * Math.Sin(angle)));
for (int i = 0; i < LatitudeSides; i++)
using (new CenterAndHeightMantainer(this))
{
angle += angleDelta;
var radius = Diameter / 2;
var angleDelta = MathHelper.Tau / 4 / LatitudeSides;
var angle = 0.0;
var path = new VertexStorage();
path.MoveTo(0, 0);
path.LineTo(new Vector2(radius * Math.Cos(angle), radius * Math.Sin(angle)));
}
for (int i = 0; i < LatitudeSides; i++)
{
angle += angleDelta;
path.LineTo(new Vector2(radius * Math.Cos(angle), radius * Math.Sin(angle)));
}
Mesh = VertexSourceToMesh.Revolve(path, LongitudeSides);
if (aabb.ZSize > 0)
{
// If the part was already created and at a height, maintain the height.
PlatingHelper.PlaceMeshAtHeight(this, aabb.MinXYZ.Z);
Mesh = VertexSourceToMesh.Revolve(path, LongitudeSides);
}
}
Invalidate(new InvalidateArgs(this, InvalidateType.Mesh));
Invalidate(InvalidateType.Mesh);
if (changed)
{
base.OnInvalidate(new InvalidateArgs(this, InvalidateType.Properties));
Invalidate(InvalidateType.Properties);
}
return Task.CompletedTask;
}
}
}

View file

@ -29,11 +29,13 @@ either expressed or implied, of the FreeBSD Project.
using System;
using System.ComponentModel;
using System.Threading.Tasks;
using MatterHackers.Agg;
using MatterHackers.Agg.UI;
using MatterHackers.Agg.VertexSource;
using MatterHackers.DataConverters3D;
using MatterHackers.Localizations;
using MatterHackers.MatterControl.DesignTools.Operations;
using MatterHackers.VectorMath;
namespace MatterHackers.MatterControl.DesignTools
@ -50,7 +52,7 @@ namespace MatterHackers.MatterControl.DesignTools
{
var item = new HalfWedgeObject3D();
item.Rebuild(null);
item.Rebuild();
return item;
}
@ -60,10 +62,10 @@ namespace MatterHackers.MatterControl.DesignTools
public override void OnInvalidate(InvalidateArgs invalidateType)
{
if (invalidateType.InvalidateType == InvalidateType.Properties
if (invalidateType.InvalidateType.HasFlag(InvalidateType.Properties)
&& invalidateType.Source == this)
{
Rebuild(null);
Rebuild();
}
else
{
@ -71,29 +73,26 @@ namespace MatterHackers.MatterControl.DesignTools
}
}
private void Rebuild(UndoBuffer undoBuffer)
override public Task Rebuild()
{
this.DebugDepth("Rebuild");
using (RebuildLock())
{
var aabb = this.GetAxisAlignedBoundingBox();
var path = new VertexStorage();
path.MoveTo(0, 0);
path.LineTo(Width, 0);
path.LineTo(Width / 2, Height);
var mesh = VertexSourceToMesh.Extrude(path, Depth);
mesh.Transform(Matrix4X4.CreateRotationX(MathHelper.Tau / 4));
Mesh = mesh;
if (aabb.ZSize > 0)
using (new CenterAndHeightMantainer(this))
{
// If the part was already created and at a height, maintain the height.
PlatingHelper.PlaceMeshAtHeight(this, aabb.MinXYZ.Z);
var path = new VertexStorage();
path.MoveTo(0, 0);
path.LineTo(Width, 0);
path.LineTo(Width / 2, Height);
var mesh = VertexSourceToMesh.Extrude(path, Depth);
mesh.Transform(Matrix4X4.CreateRotationX(MathHelper.Tau / 4));
Mesh = mesh;
}
}
Invalidate(new InvalidateArgs(this, InvalidateType.Mesh));
Invalidate(InvalidateType.Mesh);
return Task.CompletedTask;
}
}
}

View file

@ -30,6 +30,7 @@ either expressed or implied, of the FreeBSD Project.
using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using MatterHackers.Agg;
using MatterHackers.Agg.Image;
using MatterHackers.Agg.ImageProcessing;
@ -101,7 +102,7 @@ namespace MatterHackers.MatterControl.DesignTools
}
// send the invalidate on image change
this.OnInvalidate(new InvalidateArgs(this, InvalidateType.Content));
Invalidate(InvalidateType.Image);
}
return _image;
@ -118,7 +119,7 @@ namespace MatterHackers.MatterControl.DesignTools
_invert = value;
_image = null;
this.OnInvalidate(new InvalidateArgs(this, InvalidateType.Image));
Invalidate(InvalidateType.Image);
}
}
}
@ -172,6 +173,13 @@ namespace MatterHackers.MatterControl.DesignTools
public double ScaleMmPerPixels { get; private set; }
public override Task Rebuild()
{
InitMesh();
return base.Rebuild();
}
private Mesh InitMesh()
{
if (!string.IsNullOrWhiteSpace(this.AssetPath))

View file

@ -28,11 +28,12 @@ either expressed or implied, of the FreeBSD Project.
*/
using System;
using MatterHackers.Agg;
using System.Threading.Tasks;
using MatterHackers.Agg.UI;
using MatterHackers.Agg.VertexSource;
using MatterHackers.DataConverters3D;
using MatterHackers.Localizations;
using MatterHackers.MatterControl.DesignTools.Operations;
using MatterHackers.VectorMath;
namespace MatterHackers.MatterControl.DesignTools
@ -49,7 +50,7 @@ namespace MatterHackers.MatterControl.DesignTools
{
var item = new PyramidObject3D();
item.Rebuild(null);
item.Rebuild();
return item;
}
@ -59,10 +60,10 @@ namespace MatterHackers.MatterControl.DesignTools
public override void OnInvalidate(InvalidateArgs invalidateType)
{
if (invalidateType.InvalidateType == InvalidateType.Properties
if (invalidateType.InvalidateType.HasFlag(InvalidateType.Properties)
&& invalidateType.Source == this)
{
Rebuild(null);
Rebuild();
}
else
{
@ -70,30 +71,26 @@ namespace MatterHackers.MatterControl.DesignTools
}
}
private void Rebuild(UndoBuffer undoBuffer)
override public Task Rebuild()
{
this.DebugDepth("Rebuild");
using (RebuildLock())
{
var aabb = this.GetAxisAlignedBoundingBox();
var path = new VertexStorage();
path.MoveTo(0, 0);
path.LineTo(Math.Sqrt(2), 0);
path.LineTo(0, Height);
var mesh = VertexSourceToMesh.Revolve(path, 4);
mesh.Transform(Matrix4X4.CreateRotationZ(MathHelper.DegreesToRadians(45)) * Matrix4X4.CreateScale(Width / 2, Depth / 2, 1));
Mesh = mesh;
if (aabb.ZSize > 0)
using (new CenterAndHeightMantainer(this))
{
// If the part was already created and at a height, maintain the height.
PlatingHelper.PlaceMeshAtHeight(this, aabb.MinXYZ.Z);
var path = new VertexStorage();
path.MoveTo(0, 0);
path.LineTo(Math.Sqrt(2), 0);
path.LineTo(0, Height);
var mesh = VertexSourceToMesh.Revolve(path, 4);
mesh.Transform(Matrix4X4.CreateRotationZ(MathHelper.DegreesToRadians(45)) * Matrix4X4.CreateScale(Width / 2, Depth / 2, 1));
Mesh = mesh;
}
}
Invalidate(new InvalidateArgs(this, InvalidateType.Mesh));
Invalidate(InvalidateType.Mesh);
return Task.CompletedTask;
}
}
}

View file

@ -30,11 +30,13 @@ either expressed or implied, of the FreeBSD Project.
using System;
using System.ComponentModel;
using System.Threading;
using System.Threading.Tasks;
using MatterHackers.Agg;
using MatterHackers.Agg.UI;
using MatterHackers.Agg.VertexSource;
using MatterHackers.DataConverters3D;
using MatterHackers.Localizations;
using MatterHackers.MatterControl.DesignTools.Operations;
using MatterHackers.PolygonMesh;
using MatterHackers.VectorMath;
@ -56,14 +58,14 @@ namespace MatterHackers.MatterControl.DesignTools
this.Height = height;
this.Sides = sides;
Rebuild(null);
Rebuild();
}
public static RingObject3D Create()
{
var item = new RingObject3D();
item.Rebuild(null);
item.Rebuild();
return item;
}
@ -78,10 +80,10 @@ namespace MatterHackers.MatterControl.DesignTools
public override void OnInvalidate(InvalidateArgs invalidateType)
{
if (invalidateType.InvalidateType == InvalidateType.Properties
if (invalidateType.InvalidateType.HasFlag(InvalidateType.Properties)
&& invalidateType.Source == this)
{
Rebuild(null);
Rebuild();
}
else
{
@ -89,7 +91,7 @@ namespace MatterHackers.MatterControl.DesignTools
}
}
private void Rebuild(UndoBuffer undoBuffer)
override public Task Rebuild()
{
this.DebugDepth("Rebuild");
bool changed = false;
@ -98,41 +100,38 @@ namespace MatterHackers.MatterControl.DesignTools
InnerDiameter = agg_basics.Clamp(InnerDiameter, 0, OuterDiameter - .1, ref changed);
Sides = agg_basics.Clamp(Sides, 3, 360, ref changed);
var aabb = this.GetAxisAlignedBoundingBox();
var startingAngle = StartingAngle;
var endingAngle = EndingAngle;
if (!Advanced)
using (new CenterAndHeightMantainer(this))
{
startingAngle = 0;
endingAngle = 360;
}
var startingAngle = StartingAngle;
var endingAngle = EndingAngle;
if (!Advanced)
{
startingAngle = 0;
endingAngle = 360;
}
var innerDiameter = Math.Min(OuterDiameter - .1, InnerDiameter);
var innerDiameter = Math.Min(OuterDiameter - .1, InnerDiameter);
var path = new VertexStorage();
path.MoveTo(OuterDiameter / 2, -Height / 2);
path.LineTo(OuterDiameter / 2, Height / 2);
path.LineTo(innerDiameter / 2, Height / 2);
path.LineTo(innerDiameter / 2, -Height / 2);
path.LineTo(OuterDiameter / 2, -Height / 2);
var path = new VertexStorage();
path.MoveTo(OuterDiameter / 2, -Height / 2);
path.LineTo(OuterDiameter / 2, Height / 2);
path.LineTo(innerDiameter / 2, Height / 2);
path.LineTo(innerDiameter / 2, -Height / 2);
path.LineTo(OuterDiameter / 2, -Height / 2);
var startAngle = MathHelper.Range0ToTau(MathHelper.DegreesToRadians(startingAngle));
var endAngle = MathHelper.Range0ToTau(MathHelper.DegreesToRadians(endingAngle));
Mesh = VertexSourceToMesh.Revolve(path, Sides, startAngle, endAngle);
if (aabb.ZSize > 0)
{
// If the part was already created and at a height, maintain the height.
PlatingHelper.PlaceMeshAtHeight(this, aabb.MinXYZ.Z);
var startAngle = MathHelper.Range0ToTau(MathHelper.DegreesToRadians(startingAngle));
var endAngle = MathHelper.Range0ToTau(MathHelper.DegreesToRadians(endingAngle));
Mesh = VertexSourceToMesh.Revolve(path, Sides, startAngle, endAngle);
}
}
Invalidate(new InvalidateArgs(this, InvalidateType.Mesh));
Invalidate(InvalidateType.Mesh);
if (changed)
{
base.OnInvalidate(new InvalidateArgs(this, InvalidateType.Properties));
Invalidate(InvalidateType.Properties);
}
return Task.CompletedTask;
}
public void UpdateControls(PublicPropertyChange change)

View file

@ -29,11 +29,13 @@ either expressed or implied, of the FreeBSD Project.
using System;
using System.ComponentModel;
using System.Threading.Tasks;
using MatterHackers.Agg;
using MatterHackers.Agg.UI;
using MatterHackers.Agg.VertexSource;
using MatterHackers.DataConverters3D;
using MatterHackers.Localizations;
using MatterHackers.MatterControl.DesignTools.Operations;
using MatterHackers.VectorMath;
namespace MatterHackers.MatterControl.DesignTools
@ -52,14 +54,14 @@ namespace MatterHackers.MatterControl.DesignTools
Diameter = diameter;
Sides = sides;
Rebuild(null);
Rebuild();
}
public static SphereObject3D Create()
{
var item = new SphereObject3D();
item.Rebuild(null);
item.Rebuild();
return item;
}
@ -73,10 +75,10 @@ namespace MatterHackers.MatterControl.DesignTools
public override void OnInvalidate(InvalidateArgs invalidateType)
{
if (invalidateType.InvalidateType == InvalidateType.Properties
if (invalidateType.InvalidateType.HasFlag(InvalidateType.Properties)
&& invalidateType.Source == this)
{
Rebuild(null);
Rebuild();
}
else
{
@ -84,7 +86,7 @@ namespace MatterHackers.MatterControl.DesignTools
}
}
private void Rebuild(UndoBuffer undoBuffer)
override public Task Rebuild()
{
this.DebugDepth("Rebuild");
bool changed = false;
@ -93,49 +95,47 @@ namespace MatterHackers.MatterControl.DesignTools
Sides = agg_basics.Clamp(Sides, 3, 360, ref changed);
LatitudeSides = agg_basics.Clamp(LatitudeSides, 3, 360, ref changed);
var aabb = this.GetAxisAlignedBoundingBox();
var startingAngle = StartingAngle;
var endingAngle = EndingAngle;
var latitudeSides = LatitudeSides;
if (!Advanced)
using (new CenterAndHeightMantainer(this))
{
startingAngle = 0;
endingAngle = 360;
latitudeSides = Sides;
}
var startingAngle = StartingAngle;
var endingAngle = EndingAngle;
var latitudeSides = LatitudeSides;
if (!Advanced)
{
startingAngle = 0;
endingAngle = 360;
latitudeSides = Sides;
}
var path = new VertexStorage();
var angleDelta = MathHelper.Tau / 2 / latitudeSides;
var angle = -MathHelper.Tau / 4;
var radius = Diameter / 2;
path.MoveTo(new Vector2(radius * Math.Cos(angle), radius * Math.Sin(angle)));
for (int i = 0; i < latitudeSides; i++)
{
angle += angleDelta;
path.LineTo(new Vector2(radius * Math.Cos(angle), radius * Math.Sin(angle)));
}
var path = new VertexStorage();
var angleDelta = MathHelper.Tau / 2 / latitudeSides;
var angle = -MathHelper.Tau / 4;
var radius = Diameter / 2;
path.MoveTo(new Vector2(radius * Math.Cos(angle), radius * Math.Sin(angle)));
for (int i = 0; i < latitudeSides; i++)
{
angle += angleDelta;
path.LineTo(new Vector2(radius * Math.Cos(angle), radius * Math.Sin(angle)));
}
var startAngle = MathHelper.Range0ToTau(MathHelper.DegreesToRadians(startingAngle));
var endAngle = MathHelper.Range0ToTau(MathHelper.DegreesToRadians(endingAngle));
var steps = Math.Max(1, (int)(Sides * MathHelper.Tau / Math.Abs(MathHelper.GetDeltaAngle(startAngle, endAngle)) + .5));
Mesh = VertexSourceToMesh.Revolve(path,
steps,
startAngle,
endAngle);
if (aabb.ZSize > 0)
{
// If the part was already created and at a height, maintain the height.
PlatingHelper.PlaceMeshAtHeight(this, aabb.MinXYZ.Z);
var startAngle = MathHelper.Range0ToTau(MathHelper.DegreesToRadians(startingAngle));
var endAngle = MathHelper.Range0ToTau(MathHelper.DegreesToRadians(endingAngle));
var steps = Math.Max(1, (int)(Sides * MathHelper.Tau / Math.Abs(MathHelper.GetDeltaAngle(startAngle, endAngle)) + .5));
Mesh = VertexSourceToMesh.Revolve(path,
steps,
startAngle,
endAngle);
}
}
Invalidate(new InvalidateArgs(this, InvalidateType.Mesh));
Invalidate(InvalidateType.Mesh);
if (changed)
{
base.OnInvalidate(new InvalidateArgs(this, InvalidateType.Properties));
Invalidate(InvalidateType.Properties);
}
return Task.CompletedTask;
}
public void UpdateControls(PublicPropertyChange change)

View file

@ -43,6 +43,8 @@ using MatterHackers.VectorMath;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using System.Threading.Tasks;
using System;
using System.Linq;
namespace MatterHackers.MatterControl.DesignTools
{
@ -54,11 +56,12 @@ namespace MatterHackers.MatterControl.DesignTools
Color = Operations.Object3DExtensions.PrimitiveColors["Text"];
}
public static TextObject3D Create()
public static async Task<TextObject3D> Create()
{
var item = new TextObject3D();
item.Invalidate(new InvalidateArgs(null, InvalidateType.Content, null));
await item.Rebuild();
return item;
}
@ -80,74 +83,93 @@ namespace MatterHackers.MatterControl.DesignTools
// change this from a text object to a group
var newContainer = new GroupObject3D();
newContainer.CopyProperties(this, Object3DPropertyFlags.All);
int index = 0;
foreach (var child in this.Children)
{
newContainer.Children.Add(child.Clone());
var clone = child.Clone();
var newName = index < NameToWrite.Length ? NameToWrite[index++].ToString() : "Letter".Localize();
clone.Name = MapIfSymbol(newName);
newContainer.Children.Add(clone);
}
undoBuffer.AddAndDo(new ReplaceCommand(new List<IObject3D> { this }, new List<IObject3D> { newContainer }));
undoBuffer.AddAndDo(new ReplaceCommand(new[] { this }, new[] { newContainer }));
newContainer.Name = this.Name + " - " + "Flattened".Localize();
}
private string MapIfSymbol(string newName)
{
switch(newName)
{
case " ":
return "space";
}
return newName;
}
public override async void OnInvalidate(InvalidateArgs invalidateType)
{
if ((invalidateType.InvalidateType == InvalidateType.Content
|| invalidateType.InvalidateType == InvalidateType.Matrix
|| invalidateType.InvalidateType == InvalidateType.Mesh)
if ((invalidateType.InvalidateType.HasFlag(InvalidateType.Children)
|| invalidateType.InvalidateType.HasFlag(InvalidateType.Matrix)
|| invalidateType.InvalidateType.HasFlag(InvalidateType.Mesh))
&& invalidateType.Source != this
&& !RebuildLocked)
{
await Rebuild();
invalidateType = new InvalidateArgs(this, InvalidateType.Content, invalidateType.UndoBuffer);
}
else if (invalidateType.InvalidateType == InvalidateType.Properties
else if (invalidateType.InvalidateType.HasFlag(InvalidateType.Properties)
&& invalidateType.Source == this)
{
await Rebuild();
invalidateType = new InvalidateArgs(this, InvalidateType.Content, invalidateType.UndoBuffer);
}
base.OnInvalidate(invalidateType);
else
{
base.OnInvalidate(invalidateType);
}
}
public override Task Rebuild()
{
return Task.Run((System.Action)(() =>
{
using (RebuildLock())
this.DebugDepth("Rebuild");
var rebuildLock = RebuildLock();
return ApplicationController.Instance.Tasks.Execute(
"Mirror".Localize(),
null,
(reporter, cancellationToken) =>
{
var aabb = (this).GetAxisAlignedBoundingBox();
this.Children.Modify((List<IObject3D> list) =>
using (new CenterAndHeightMantainer(this))
{
list.Clear();
var offest = 0.0;
double pointsToMm = 0.352778;
foreach (var letter in NameToWrite.ToCharArray())
this.Children.Modify((List<IObject3D> list) =>
{
var letterPrinter = new TypeFacePrinter(letter.ToString(), new StyledTypeFace(ApplicationController.GetTypeFace(Font), PointSize))
list.Clear();
var offest = 0.0;
double pointsToMm = 0.352778;
foreach (var letter in NameToWrite.ToCharArray())
{
ResolutionScale = 10
};
var scalledLetterPrinter = new VertexSourceApplyTransform(letterPrinter, Affine.NewScaling(pointsToMm));
IObject3D letterObject = new Object3D()
{
Mesh = VertexSourceToMesh.Extrude(scalledLetterPrinter, Height)
};
var letterPrinter = new TypeFacePrinter(letter.ToString(), new StyledTypeFace(ApplicationController.GetTypeFace(Font), PointSize))
{
ResolutionScale = 10
};
var scalledLetterPrinter = new VertexSourceApplyTransform(letterPrinter, Affine.NewScaling(pointsToMm));
IObject3D letterObject = new Object3D()
{
Mesh = VertexSourceToMesh.Extrude(scalledLetterPrinter, Height)
};
letterObject.Matrix = Matrix4X4.CreateTranslation(offest, 0, 0);
list.Add(letterObject);
letterObject.Matrix = Matrix4X4.CreateTranslation(offest, 0, 0);
list.Add(letterObject);
offest += letterPrinter.GetSize(letter.ToString()).X * pointsToMm;
}
});
if (aabb.ZSize > 0)
{
// If the part was already created and at a height, maintain the height.
PlatingHelper.PlaceMeshAtHeight(this, (double)aabb.MinXYZ.Z);
offest += letterPrinter.GetSize(letter.ToString()).X * pointsToMm;
}
});
}
}
}));
rebuildLock.Dispose();
Invalidate(InvalidateType.Children);
return Task.CompletedTask;
});
}
}
}

View file

@ -27,8 +27,10 @@ of the authors and should not be interpreted as representing official policies,
either expressed or implied, of the FreeBSD Project.
*/
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Threading.Tasks;
using MatterHackers.Agg;
using MatterHackers.Agg.Font;
using MatterHackers.Agg.Transform;
@ -58,7 +60,7 @@ namespace MatterHackers.MatterControl.DesignTools
{
var item = new TextPathObject3D();
item.Rebuild(null);
item.Rebuild();
return item;
}
@ -84,23 +86,23 @@ namespace MatterHackers.MatterControl.DesignTools
{
newContainer.Children.Add(child.Clone());
}
undoBuffer.AddAndDo(new ReplaceCommand(new List<IObject3D> { this }, new List<IObject3D> { newContainer }));
undoBuffer.AddAndDo(new ReplaceCommand(new[] { this }, new[] { newContainer }));
}
public override void OnInvalidate(InvalidateArgs invalidateType)
{
if ((invalidateType.InvalidateType == InvalidateType.Content
|| invalidateType.InvalidateType == InvalidateType.Matrix
|| invalidateType.InvalidateType == InvalidateType.Mesh)
if ((invalidateType.InvalidateType.HasFlag(InvalidateType.Children)
|| invalidateType.InvalidateType.HasFlag(InvalidateType.Matrix)
|| invalidateType.InvalidateType.HasFlag(InvalidateType.Mesh))
&& invalidateType.Source != this
&& !RebuildLocked)
{
Rebuild(null);
Rebuild();
}
else if (invalidateType.InvalidateType == InvalidateType.Properties
else if (invalidateType.InvalidateType.HasFlag(InvalidateType.Properties)
&& invalidateType.Source == this)
{
Rebuild(null);
Rebuild();
}
else
{
@ -108,19 +110,22 @@ namespace MatterHackers.MatterControl.DesignTools
}
}
private void Rebuild(UndoBuffer undoBuffer)
override public Task Rebuild()
{
this.DebugDepth("Rebuild");
using (RebuildLock())
{
double pointsToMm = 0.352778;
var printer = new TypeFacePrinter(Text, new StyledTypeFace(ApplicationController.GetTypeFace(Font), PointSize))
{
ResolutionScale = 10
};
var scalledLetterPrinter = new VertexSourceApplyTransform(printer, Affine.NewScaling(pointsToMm));
var scaledLetterPrinter = new VertexSourceApplyTransform(printer, Affine.NewScaling(pointsToMm));
var vertexSource = new VertexStorage();
foreach (var vertex in scalledLetterPrinter.Vertices())
foreach (var vertex in scaledLetterPrinter.Vertices())
{
if (vertex.IsMoveTo)
{
@ -135,11 +140,14 @@ namespace MatterHackers.MatterControl.DesignTools
vertexSource.ClosePolygon();
}
}
VertexSource = vertexSource;
this.VertexSource = vertexSource;
base.Mesh = null;
}
Invalidate(new InvalidateArgs(this, InvalidateType.Content));
Invalidate(InvalidateType.Path);
return Task.CompletedTask;
}
public override Mesh Mesh
@ -150,8 +158,13 @@ namespace MatterHackers.MatterControl.DesignTools
{
using (this.RebuildLock())
{
// TODO: Revise fallback mesh
base.Mesh = this.InitMesh() ?? PlatonicSolids.CreateCube(100, 100, 0.2);
var bounds = this.VertexSource.GetBounds();
var center = bounds.Center;
var mesh = PlatonicSolids.CreateCube(Math.Max(8, bounds.Width), Math.Max(8, bounds.Height), 0.2);
mesh.Translate(new Vector3(center.X, center.Y, 0));
base.Mesh = mesh;
}
}

View file

@ -28,11 +28,13 @@ either expressed or implied, of the FreeBSD Project.
*/
using System;
using System.Threading.Tasks;
using MatterHackers.Agg;
using MatterHackers.Agg.UI;
using MatterHackers.Agg.VertexSource;
using MatterHackers.DataConverters3D;
using MatterHackers.Localizations;
using MatterHackers.MatterControl.DesignTools.Operations;
using MatterHackers.VectorMath;
namespace MatterHackers.MatterControl.DesignTools
@ -48,7 +50,7 @@ namespace MatterHackers.MatterControl.DesignTools
public static TorusObject3D Create()
{
var item = new TorusObject3D();
item.Rebuild(null);
item.Rebuild();
return item;
}
@ -64,10 +66,10 @@ namespace MatterHackers.MatterControl.DesignTools
public override void OnInvalidate(InvalidateArgs invalidateType)
{
if (invalidateType.InvalidateType == InvalidateType.Properties
if (invalidateType.InvalidateType.HasFlag(InvalidateType.Properties)
&& invalidateType.Source == this)
{
Rebuild(null);
Rebuild();
}
else
{
@ -75,7 +77,7 @@ namespace MatterHackers.MatterControl.DesignTools
}
}
private void Rebuild(UndoBuffer undoBuffer)
override public Task Rebuild()
{
this.DebugDepth("Rebuild");
bool changed = false;
@ -99,40 +101,37 @@ namespace MatterHackers.MatterControl.DesignTools
var innerDiameter = Math.Min(OuterDiameter - .1, InnerDiameter);
var aabb = this.GetAxisAlignedBoundingBox();
var poleRadius = (OuterDiameter / 2 - innerDiameter / 2) / 2;
var toroidRadius = innerDiameter / 2 + poleRadius;
var path = new VertexStorage();
var angleDelta = MathHelper.Tau / ringSides;
var ringStartAngle = MathHelper.DegreesToRadians(ringPhaseAngle);
var ringAngle = ringStartAngle;
var circleCenter = new Vector2(toroidRadius, 0);
path.MoveTo(circleCenter + new Vector2(poleRadius * Math.Cos(ringStartAngle), poleRadius * Math.Sin(ringStartAngle)));
for (int i = 0; i < ringSides - 1; i++)
using (new CenterAndHeightMantainer(this))
{
ringAngle += angleDelta;
path.LineTo(circleCenter + new Vector2(poleRadius * Math.Cos(ringAngle), poleRadius * Math.Sin(ringAngle)));
}
var poleRadius = (OuterDiameter / 2 - innerDiameter / 2) / 2;
var toroidRadius = innerDiameter / 2 + poleRadius;
var path = new VertexStorage();
var angleDelta = MathHelper.Tau / ringSides;
var ringStartAngle = MathHelper.DegreesToRadians(ringPhaseAngle);
var ringAngle = ringStartAngle;
var circleCenter = new Vector2(toroidRadius, 0);
path.MoveTo(circleCenter + new Vector2(poleRadius * Math.Cos(ringStartAngle), poleRadius * Math.Sin(ringStartAngle)));
for (int i = 0; i < ringSides - 1; i++)
{
ringAngle += angleDelta;
path.LineTo(circleCenter + new Vector2(poleRadius * Math.Cos(ringAngle), poleRadius * Math.Sin(ringAngle)));
}
path.LineTo(circleCenter + new Vector2(poleRadius * Math.Cos(ringStartAngle), poleRadius * Math.Sin(ringStartAngle)));
path.LineTo(circleCenter + new Vector2(poleRadius * Math.Cos(ringStartAngle), poleRadius * Math.Sin(ringStartAngle)));
var startAngle = MathHelper.Range0ToTau(MathHelper.DegreesToRadians(startingAngle));
var endAngle = MathHelper.Range0ToTau(MathHelper.DegreesToRadians(endingAngle));
Mesh = VertexSourceToMesh.Revolve(path, Sides, startAngle, endAngle);
if (aabb.ZSize > 0)
{
// If the part was already created and at a height, maintain the height.
PlatingHelper.PlaceMeshAtHeight(this, aabb.MinXYZ.Z);
var startAngle = MathHelper.Range0ToTau(MathHelper.DegreesToRadians(startingAngle));
var endAngle = MathHelper.Range0ToTau(MathHelper.DegreesToRadians(endingAngle));
Mesh = VertexSourceToMesh.Revolve(path, Sides, startAngle, endAngle);
}
}
Invalidate(new InvalidateArgs(this, InvalidateType.Mesh));
Invalidate(InvalidateType.Mesh);
if (changed)
{
base.OnInvalidate(new InvalidateArgs(this, InvalidateType.Properties));
Invalidate(InvalidateType.Properties);
}
return Task.CompletedTask;
}
public void UpdateControls(PublicPropertyChange change)

View file

@ -29,6 +29,7 @@ either expressed or implied, of the FreeBSD Project.
using System;
using System.ComponentModel;
using System.Threading.Tasks;
using MatterHackers.Agg;
using MatterHackers.Agg.UI;
using MatterHackers.Agg.VertexSource;
@ -51,7 +52,7 @@ namespace MatterHackers.MatterControl.DesignTools
{
var item = new WedgeObject3D();
item.Rebuild(null);
item.Rebuild();
return item;
}
@ -61,10 +62,10 @@ namespace MatterHackers.MatterControl.DesignTools
public override void OnInvalidate(InvalidateArgs invalidateType)
{
if (invalidateType.InvalidateType == InvalidateType.Properties
if (invalidateType.InvalidateType.HasFlag(InvalidateType.Properties)
&& invalidateType.Source == this)
{
Rebuild(null);
Rebuild();
}
else
{
@ -72,28 +73,26 @@ namespace MatterHackers.MatterControl.DesignTools
}
}
private void Rebuild(UndoBuffer undoBuffer)
override public Task Rebuild()
{
this.DebugDepth("Rebuild");
using (RebuildLock())
{
var aabb = this.GetAxisAlignedBoundingBox();
var path = new VertexStorage();
path.MoveTo(0, 0);
path.LineTo(Width, 0);
path.LineTo(0, Height);
Mesh = VertexSourceToMesh.Extrude(path, Depth);
Mesh.Transform(Matrix4X4.CreateRotationX(MathHelper.Tau / 4));
if (aabb.ZSize > 0)
using (new CenterAndHeightMantainer(this))
{
// If the part was already created and at a height, maintain the height.
PlatingHelper.PlaceMeshAtHeight(this, aabb.MinXYZ.Z);
var path = new VertexStorage();
path.MoveTo(0, 0);
path.LineTo(Width, 0);
path.LineTo(0, Height);
Mesh = VertexSourceToMesh.Extrude(path, Depth);
Mesh.Transform(Matrix4X4.CreateRotationX(MathHelper.Tau / 4));
}
}
Invalidate(new InvalidateArgs(this, InvalidateType.Mesh));
Invalidate(InvalidateType.Mesh);
return Task.CompletedTask;
}
}
}

View file

@ -194,7 +194,7 @@ namespace MatterHackers.MatterControl.DesignTools
};
updateButton.Click += (s, e) =>
{
context.item.Invalidate(new InvalidateArgs(context.item, InvalidateType.Properties, undoBuffer));
context.item.Invalidate(new InvalidateArgs(context.item, InvalidateType.Properties));
};
mainContainer.AddChild(updateButton);
}
@ -206,16 +206,21 @@ namespace MatterHackers.MatterControl.DesignTools
return mainContainer;
}
private static FlowLayoutWidget CreateSettingsRow(EditableProperty property, UIField field)
private static FlowLayoutWidget CreateSettingsRow(EditableProperty property, UIField field, ThemeConfig theme = null)
{
var row = CreateSettingsRow(property.DisplayName.Localize(), property.Description.Localize());
var row = CreateSettingsRow(property.DisplayName.Localize(), property.Description.Localize(), theme);
row.AddChild(field.Content);
return row;
}
public static FlowLayoutWidget CreateSettingsRow(string labelText, string toolTipText = null)
public static FlowLayoutWidget CreateSettingsRow(string labelText, string toolTipText = null, ThemeConfig theme = null)
{
if (theme == null)
{
theme = AppContext.Theme;
}
var rowContainer = new FlowLayoutWidget(FlowDirection.LeftToRight)
{
HAnchor = HAnchor.Stretch,
@ -223,12 +228,11 @@ namespace MatterHackers.MatterControl.DesignTools
ToolTipText = toolTipText
};
var label = new TextWidget(labelText + ":", pointSize: 11, textColor: AppContext.Theme.TextColor)
rowContainer.AddChild(new TextWidget(labelText + ":", pointSize: 11, textColor: theme.TextColor)
{
Margin = new BorderDouble(0, 0, 3, 0),
VAnchor = VAnchor.Center
};
rowContainer.AddChild(label);
VAnchor = VAnchor.Center,
});
rowContainer.AddChild(new HorizontalSpacer());
@ -308,18 +312,27 @@ namespace MatterHackers.MatterControl.DesignTools
}
//field.Content
undoBuffer.AddAndDo(new UndoRedoActions(() =>
if (undoBuffer != null)
{
property.SetValue(valueFromString(oldValue));
object3D?.Invalidate(new InvalidateArgs(context.item, InvalidateType.Properties, undoBuffer));
propertyGridModifier?.UpdateControls(new PublicPropertyChange(context, property.PropertyInfo.Name));
},
() =>
undoBuffer.AddAndDo(new UndoRedoActions(() =>
{
property.SetValue(valueFromString(oldValue));
object3D?.Invalidate(new InvalidateArgs(context.item, InvalidateType.Properties));
propertyGridModifier?.UpdateControls(new PublicPropertyChange(context, property.PropertyInfo.Name));
},
() =>
{
property.SetValue(valueFromString(newValue));
object3D?.Invalidate(new InvalidateArgs(context.item, InvalidateType.Properties));
propertyGridModifier?.UpdateControls(new PublicPropertyChange(context, property.PropertyInfo.Name));
}));
}
else
{
property.SetValue(valueFromString(newValue));
object3D?.Invalidate(new InvalidateArgs(context.item, InvalidateType.Properties, undoBuffer));
object3D?.Invalidate(new InvalidateArgs(context.item, InvalidateType.Properties));
propertyGridModifier?.UpdateControls(new PublicPropertyChange(context, property.PropertyInfo.Name));
}));
}
};
}
@ -333,7 +346,7 @@ namespace MatterHackers.MatterControl.DesignTools
void RefreshField(object s, InvalidateArgs e)
{
if (e.InvalidateType == InvalidateType.Properties)
if (e.InvalidateType.HasFlag(InvalidateType.Properties))
{
double newValue = (double)property.Value;
if (newValue != field.DoubleValue)
@ -355,7 +368,7 @@ namespace MatterHackers.MatterControl.DesignTools
field.ValueChanged += (s, e) =>
{
property.SetValue(field.Color);
object3D?.Invalidate(new InvalidateArgs(context.item, InvalidateType.Properties, undoBuffer));
object3D?.Invalidate(new InvalidateArgs(context.item, InvalidateType.Properties));
propertyGridModifier?.UpdateControls(new PublicPropertyChange(context, property.PropertyInfo.Name));
};
@ -397,7 +410,7 @@ namespace MatterHackers.MatterControl.DesignTools
field.ValueChanged += (s, e) =>
{
property.SetValue(field.DirectionVector);
object3D?.Invalidate(new InvalidateArgs(context.item, InvalidateType.Properties, undoBuffer));
object3D?.Invalidate(new InvalidateArgs(context.item, InvalidateType.Properties));
propertyGridModifier?.UpdateControls(new PublicPropertyChange(context, property.PropertyInfo.Name));
};
@ -445,7 +458,7 @@ namespace MatterHackers.MatterControl.DesignTools
Normal = field1.DirectionVector.Normal,
Origin = property.Item.Children.First().GetAxisAlignedBoundingBox().Center + field2.Vector3
});
object3D?.Invalidate(new InvalidateArgs(context.item, InvalidateType.Properties, undoBuffer));
object3D?.Invalidate(new InvalidateArgs(context.item, InvalidateType.Properties));
propertyGridModifier?.UpdateControls(new PublicPropertyChange(context, property.PropertyInfo.Name));
};
field2.ValueChanged += (s, e) =>
@ -455,7 +468,7 @@ namespace MatterHackers.MatterControl.DesignTools
Normal = field1.DirectionVector.Normal,
Origin = property.Item.Children.First().GetAxisAlignedBoundingBox().Center + field2.Vector3
});
object3D?.Invalidate(new InvalidateArgs(context.item, InvalidateType.Properties, undoBuffer));
object3D?.Invalidate(new InvalidateArgs(context.item, InvalidateType.Properties));
propertyGridModifier?.UpdateControls(new PublicPropertyChange(context, property.PropertyInfo.Name));
};
@ -521,7 +534,7 @@ namespace MatterHackers.MatterControl.DesignTools
void RefreshField(object s, InvalidateArgs e)
{
if (e.InvalidateType == InvalidateType.Properties)
if (e.InvalidateType.HasFlag(InvalidateType.Properties))
{
int newValue = (int)property.Value;
if (newValue != field.IntValue)
@ -577,7 +590,7 @@ namespace MatterHackers.MatterControl.DesignTools
field.ValueChanged += (s, e) =>
{
property.SetValue(Convert.ToChar(field.Value));
object3D?.Invalidate(new InvalidateArgs(context.item, InvalidateType.Properties, undoBuffer));
object3D?.Invalidate(new InvalidateArgs(context.item, InvalidateType.Properties));
propertyGridModifier?.UpdateControls(new PublicPropertyChange(context, property.PropertyInfo.Name));
};
@ -610,11 +623,11 @@ namespace MatterHackers.MatterControl.DesignTools
field.ValueChanged += (s, e) =>
{
property.SetValue(Enum.Parse(property.PropertyType, field.Value));
object3D?.Invalidate(new InvalidateArgs(context.item, InvalidateType.Properties, undoBuffer));
object3D?.Invalidate(new InvalidateArgs(context.item, InvalidateType.Properties));
propertyGridModifier?.UpdateControls(new PublicPropertyChange(context, property.PropertyInfo.Name));
};
rowContainer = CreateSettingsRow(property, field);
rowContainer = CreateSettingsRow(property, field, theme);
}
// Use known IObject3D editors
else if (propertyValue is IObject3D item

View file

@ -0,0 +1,521 @@
/*
Copyright (c) 2019, Lars Brubaker, John Lewin
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
The views and conclusions contained in the software and documentation are those
of the authors and should not be interpreted as representing official policies,
either expressed or implied, of the FreeBSD Project.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using MatterHackers.Agg;
using MatterHackers.Agg.Image;
using MatterHackers.DataConverters3D;
using MatterHackers.MatterControl.PartPreviewWindow;
using MatterHackers.PolygonMesh;
using MatterHackers.RayTracer;
using MatterHackers.VectorMath;
namespace MatterHackers.MatterControl.DesignTools
{
public static class FaceListExtensions
{
public static IPrimitive CreateTraceData(this FaceList faceList, List<Vector3> vertexList, int maxRecursion = int.MaxValue)
{
var allPolys = new List<IPrimitive>();
foreach (var face in faceList)
{
allPolys.Add(new TriangleShape(vertexList[face.v0], vertexList[face.v1], vertexList[face.v2], null));
}
return BoundingVolumeHierarchy.CreateNewHierachy(allPolys, maxRecursion);
}
public static IPrimitive CreateTraceData(this FaceList faceList, List<Vector3Float> vertexList, int maxRecursion = int.MaxValue)
{
var allPolys = new List<IPrimitive>();
foreach (var face in faceList)
{
allPolys.Add(new TriangleShape(vertexList[face.v0], vertexList[face.v1], vertexList[face.v2], null));
}
return BoundingVolumeHierarchy.CreateNewHierachy(allPolys, maxRecursion);
}
}
[HideFromTreeViewAttribute, Immutable]
public class GeneratedSupportObject3D : Object3D
{
public GeneratedSupportObject3D()
{
OutputType = PrintOutputTypes.Support;
}
}
public class SupportGenerator
{
private InteractiveScene scene;
public SupportGenerator(InteractiveScene scene)
{
this.scene = scene;
}
public enum SupportGenerationType { Normal, From_Bed }
public double MaxOverHangAngle
{
get
{
if (UserSettings.Instance.get(UserSettingsKey.SupportMaxOverHangAngle) == null)
{
return 45;
}
var value = UserSettings.Instance.GetValue<double>(UserSettingsKey.SupportMaxOverHangAngle);
if (value < 0)
{
return 0;
}
if (value > 90)
{
value = 90;
}
return value;
}
set
{
UserSettings.Instance.set(UserSettingsKey.SupportMaxOverHangAngle, value.ToString());
}
}
public double PillarSize
{
get
{
var value = UserSettings.Instance.GetValue<double>(UserSettingsKey.SupportPillarSize);
if (value < 1.5)
{
return 1.5;
}
return value;
}
set
{
UserSettings.Instance.set(UserSettingsKey.SupportPillarSize, value.ToString());
}
}
public SupportGenerationType SupportType
{
get
{
var supportString = UserSettings.Instance.get(UserSettingsKey.SupportGenerationType);
if (Enum.TryParse(supportString, out SupportGenerationType supportType))
{
return supportType;
}
return SupportGenerationType.Normal;
}
set
{
UserSettings.Instance.set(UserSettingsKey.SupportGenerationType, value.ToString());
}
}
/// <summary>
/// The amount to reduce the pillars so they are separated in the 3D view
/// </summary>
private double reduceAmount => .99;
public Task Create(IProgress<ProgressStatus> progress, CancellationToken cancelationToken)
{
ProgressStatus status = new ProgressStatus();
status.Status = "Enter";
progress.Report(status);
// Get visible meshes for each of them
var supportCandidates = scene.Children.SelectMany(i => i.VisibleMeshes());
AxisAlignedBoundingBox allBounds = AxisAlignedBoundingBox.Empty();
foreach (var candidate in supportCandidates)
{
allBounds += candidate.GetAxisAlignedBoundingBox(candidate.Matrix.Inverted * candidate.WorldMatrix());
}
// create the gird of possible support
var gridBounds = new RectangleDouble(Math.Floor((double)(allBounds.MinXYZ.X / PillarSize)),
Math.Floor((double)(allBounds.MinXYZ.Y / PillarSize)),
Math.Ceiling(allBounds.MaxXYZ.X / PillarSize),
Math.Ceiling(allBounds.MaxXYZ.Y / PillarSize));
var partBounds = new RectangleDouble(gridBounds.Left * PillarSize,
gridBounds.Bottom * PillarSize,
gridBounds.Right * PillarSize,
gridBounds.Top * PillarSize);
int gridWidth = (int)gridBounds.Width;
int gridHeight = (int)gridBounds.Height;
var supportGrid = new List<List<List<(bool isBottom, double z)>>>();
for (int x = 0; x < gridWidth; x++)
{
supportGrid.Add(new List<List<(bool, double)>>());
for (int y = 0; y < gridHeight; y++)
{
supportGrid[x].Add(new List<(bool, double)>());
}
}
// get all the support plane intersections
status.Status = "Trace";
progress.Report(status);
var detectedPlanes = DetectRequiredSupportByTracing(gridBounds, supportCandidates);
status.Status = "Columns";
progress.Report(status);
AddSupportColumns(gridBounds, detectedPlanes);
// this is the theory for regions rather than pillars
// separate the faces into face patch groups (these are the new support tops)
// project all the vertices of each patch group down until they hit an up face in the scene (or 0)
// make a new patch group at the z of the hit (these will be the bottoms)
// find the outline of the patch groups (these will be the walls of the top and bottom patches
// make a new mesh object with the top, bottom and walls, add it to the scene and mark it as support
return Task.CompletedTask;
}
public void RemoveExisting()
{
scene.SelectedItem = null;
var existingSupports = scene.Descendants().Where(i => i.GetType() == typeof(GeneratedSupportObject3D));
scene.UndoBuffer.AddAndDo(new DeleteCommand(scene, existingSupports.ToList()));
}
public bool RequiresSupport()
{
bool supportInScene = scene.VisibleMeshes().Any(i => i.WorldOutputType() == PrintOutputTypes.Support);
if (!supportInScene)
{
// there is no support in the scene check if there are faces that require support
var supportCandidates = scene.VisibleMeshes().Where(i => i.OutputType != PrintOutputTypes.Support);
// find all the faces that are candidates for support
foreach (var item in supportCandidates)
{
var matrix = item.WorldMatrix(scene);
for (int faceIndex = 0; faceIndex < item.Mesh.Faces.Count; faceIndex++)
{
bool aboveBed = false;
var face = item.Mesh.Faces[faceIndex];
var verts = new int[] { face.v0, face.v1, face.v2 };
foreach (var vertex in verts)
{
if (item.Mesh.Vertices[vertex].Transform(matrix).Z > .01)
{
aboveBed = true;
break;
}
}
if (aboveBed)
{
var face0Normal = item.Mesh.Faces[faceIndex].normal.TransformNormal(matrix).GetNormal();
var angle = MathHelper.RadiansToDegrees(Math.Acos(face0Normal.Dot(-Vector3Float.UnitZ)));
if (angle < MaxOverHangAngle)
{
// TODO: consider how much area all supported polygons represent
return true;
}
}
}
}
}
return false;
}
private void AddSupportColumn(IObject3D holder, double gridX, double gridY, double bottomZ, double topZ)
{
if (topZ - bottomZ < .01)
{
// less than 10 micros high, don't ad it
return;
}
var support = new GeneratedSupportObject3D()
{
Mesh = PlatonicSolids.CreateCube(1, 1, 1)
};
support.Matrix = Matrix4X4.CreateScale(PillarSize - reduceAmount, PillarSize - reduceAmount, topZ - bottomZ)
* Matrix4X4.CreateTranslation(gridX, gridY, bottomZ + (topZ - bottomZ) / 2);
holder.Children.Add(support);
}
private void AddSupportColumns(RectangleDouble gridBounds, Dictionary<(int x, int y), List<(double z, bool bottom)>> detectedPlanes)
{
IObject3D supportColumnsToAdd = new Object3D();
bool fromBed = SupportType == SupportGenerationType.From_Bed;
var halfPillar = PillarSize / 2;
foreach (var kvp in detectedPlanes)
{
if (kvp.Value.Count == 0)
{
continue;
}
int i = 0;
kvp.Value.Sort((a, b) =>
{
return a.z.CompareTo(b.z);
});
var yPos = (gridBounds.Bottom + kvp.Key.y) * PillarSize + halfPillar;
var xPos = (gridBounds.Left + kvp.Key.x) * PillarSize + halfPillar;
if (fromBed)
{
i = GetNextBottom(i, kvp.Value);
if (i < kvp.Value.Count
&& kvp.Value[i].bottom)
{
AddSupportColumn(supportColumnsToAdd, xPos, yPos, 0, kvp.Value[i].z + .01);
}
}
else
{
double lastTopZ = 0;
int lastBottom = i;
do
{
// if the first plane is a top, move to the last top before we find a bottom
if (i == 0
&& !kvp.Value[i].bottom)
{
i = GetNextTop(i + 1, kvp.Value);
if (i < kvp.Value.Count)
{
lastTopZ = kvp.Value[i].z;
}
}
lastBottom = i;
// find all open arreas in the list and add support
i = GetNextBottom(i, kvp.Value);
if (i < kvp.Value.Count
&& kvp.Value[i].bottom)
{
AddSupportColumn(supportColumnsToAdd, xPos, yPos, lastTopZ, kvp.Value[i].z);
}
i = GetNextTop(i + 1, kvp.Value);
if (i < kvp.Value.Count)
{
lastTopZ = kvp.Value[i].z;
}
} while (i != lastBottom && i < kvp.Value.Count);
}
}
scene.UndoBuffer.AddAndDo(new InsertCommand(scene, supportColumnsToAdd.Children, false));
}
private Dictionary<(int x, int y), List<(double z, bool bottom)>> DetectRequiredSupportByTracing(RectangleDouble gridBounds, IEnumerable<IObject3D> supportCandidates)
{
var traceData = GetTraceData(supportCandidates);
// keep a list of all the detected planes in each support column
var detectedPlanes = new Dictionary<(int x, int y), List<(double z, bool bottom)>>();
int gridWidth = (int)gridBounds.Width;
int gridHeight = (int)gridBounds.Height;
// at the center of every grid item add in a list of all the top faces to look down from
for (int y = 0; y < gridHeight; y++)
{
for (int x = 0; x < gridWidth; x++)
{
IntersectInfo upHit = null;
for (double yOffset = -1; yOffset <= 1; yOffset++)
{
for (double xOffset = -1; xOffset <= 1; xOffset++)
{
var halfPillar = PillarSize / 2;
var yPos = (gridBounds.Bottom + y) * PillarSize + halfPillar + (yOffset * halfPillar);
var xPos = (gridBounds.Left + x) * PillarSize + halfPillar + (xOffset * halfPillar);
// detect all the bottom plans (surfaces that might need support
var upRay = new Ray(new Vector3(xPos + .000013, yPos - .00027, 0), Vector3.UnitZ, intersectionType: IntersectionType.FrontFace);
do
{
upHit = traceData.GetClosestIntersection(upRay);
if (upHit != null)
{
if (!detectedPlanes.ContainsKey((x, y)))
{
detectedPlanes.Add((x, y), new List<(double z, bool bottom)>());
// add a single plane at the bed so we always know the bed is a top
//detectedPlanes[(x, y)].Add((0, false));
}
detectedPlanes[(x, y)].Add((upHit.HitPosition.Z, true));
// make a new ray just past the last hit to keep looking for up hits
upRay = new Ray(new Vector3(xPos, yPos, upHit.HitPosition.Z + .001), Vector3.UnitZ, intersectionType: IntersectionType.FrontFace);
}
} while (upHit != null);
// detect all the up plans (surfaces that will have support on top of them)
upRay = new Ray(new Vector3(xPos + .000013, yPos - .00027, 0), Vector3.UnitZ, intersectionType: IntersectionType.BackFace);
do
{
upHit = traceData.GetClosestIntersection(upRay);
if (upHit != null)
{
if (!detectedPlanes.ContainsKey((x, y)))
{
detectedPlanes.Add((x, y), new List<(double z, bool bottom)>());
// add a single plane at the bed so we always know the bed is a top
//detectedPlanes[(x, y)].Add((0, false));
}
detectedPlanes[(x, y)].Add((upHit.HitPosition.Z, false));
// make a new ray just past the last hit to keep looking for up hits
upRay = new Ray(new Vector3(xPos, yPos, upHit.HitPosition.Z + .001), Vector3.UnitZ, intersectionType: IntersectionType.BackFace);
}
} while (upHit != null);
}
}
}
}
return detectedPlanes;
}
public static int GetNextBottom(int i, List<(double z, bool bottom)> planes)
{
// first skip all the tops
while (i < planes.Count
&& !planes[i].bottom)
{
i++;
}
// then look for the last bottom before next top
while (i < planes.Count
&& planes[i].bottom
&& planes.Count > i + 1
&& planes[i + 1].bottom)
{
i++;
}
return i;
}
public static int GetNextTop(int i, List<(double z, bool bottom)> planes)
{
while (i < planes.Count
&& planes[i].bottom)
{
i++;
}
return i;
}
// function to get all the columns that need support generation
private IEnumerable<(int x, int y)> GetSupportCorrodinates(ImageBuffer supportNeededImage)
{
var buffer = supportNeededImage.GetBuffer();
// check if the image has any alpha set to something other than 255
for (int y = 0; y < supportNeededImage.Height; y++)
{
var yOffset = supportNeededImage.GetBufferOffsetY(y);
for (int x = 0; x < supportNeededImage.Width; x++)
{
// get the alpha at this pixel
//if (buffer[yOffset + x] > 0)
{
yield return (x, y);
}
}
}
}
private IPrimitive GetTraceData(IEnumerable<IObject3D> supportCandidates)
{
List<Vector3Float> supportVerts;
FaceList supportFaces;
// find all the faces that are candidates for support
supportVerts = new List<Vector3Float>();
supportFaces = new FaceList();
foreach (var item in supportCandidates)
{
// add all the down faces to supportNeededImage
var matrix = item.WorldMatrix(scene);
for (int faceIndex = 0; faceIndex < item.Mesh.Faces.Count; faceIndex++)
{
var face0Normal = item.Mesh.Faces[faceIndex].normal.TransformNormal(matrix).GetNormal();
var angle = MathHelper.RadiansToDegrees(Math.Acos(face0Normal.Dot(-Vector3Float.UnitZ)));
// check if the face is pointing in the up direction at all
bool isUpFace = angle >= 90;
// check if the face is pointing down
if (angle <= MaxOverHangAngle
|| isUpFace)
{
var face = item.Mesh.Faces[faceIndex];
var verts = new int[] { face.v0, face.v1, face.v2 };
var p0 = item.Mesh.Vertices[face.v0].Transform(matrix);
var p1 = item.Mesh.Vertices[face.v1].Transform(matrix);
var p2 = item.Mesh.Vertices[face.v2].Transform(matrix);
var vc = supportVerts.Count;
supportVerts.Add(p0);
supportVerts.Add(p1);
supportVerts.Add(p2);
supportFaces.Add(vc, vc + 1, vc + 2, face0Normal);
}
}
}
return supportFaces.CreateTraceData(supportVerts);
}
}
}

View file

@ -0,0 +1,71 @@
/*
Copyright (c) 2017, John Lewin
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
The views and conclusions contained in the software and documentation are those
of the authors and should not be interpreted as representing official policies,
either expressed or implied, of the FreeBSD Project.
*/
using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using MatterHackers.Agg.Image;
using MatterHackers.Agg.Platform;
using MatterHackers.DataConverters3D;
using MatterHackers.MatterControl.Library;
using MatterHackers.PolygonMesh;
namespace MatterHackers.MatterControl.Plugins
{
/// <summary>
/// Converts OpenSCAD documents into IObject3D content
/// </summary>
public class OpenScadContentProvider : ISceneContentProvider
{
public Task<IObject3D> CreateItem(ILibraryItem item, Action<double, string> reporter)
{
Mesh logomesh = null;
using (var meshStream = AggContext.StaticData.OpenStream(Path.Combine("Stls", "openscad_logo.stl")))
{
logomesh = Object3D.Load(meshStream, ".stl", CancellationToken.None).Mesh;
}
return Task.FromResult<IObject3D>(new OpenScadObject3D()
{
Mesh = logomesh,
// Set after load below
ScriptPath = (item as ILibraryAssetStream)?.AssetPath
});
}
public Task<ImageBuffer> GetThumbnail(ILibraryItem item, int width, int height)
{
return Task.FromResult<ImageBuffer>(null);
}
public ImageBuffer DefaultImage => AggContext.StaticData.LoadIcon("140.png", 16, 16);
}
}

View file

@ -40,6 +40,7 @@ using MatterHackers.Agg.Platform;
using MatterHackers.Agg.UI;
using MatterHackers.DataConverters3D;
using MatterHackers.Localizations;
using MatterHackers.MatterControl.DesignTools;
using MatterHackers.MatterControl.PartPreviewWindow;
using MatterHackers.MatterControl.PrinterCommunication.Io;
using MatterHackers.MatterControl.PrintQueue;
@ -194,6 +195,8 @@ namespace MatterHackers.MatterControl.Library.Export
// TODO: Prior code bypassed GCodeOverridePath mechanisms in EditContext. Consolidating into a single pathway
string gcodePath = printer.Bed.EditContext.GCodeFilePath(printer);
var errors = new List<ValidationError>();
if (ApplicationSettings.ValidFileExtensions.IndexOf(sourceExtension, StringComparison.OrdinalIgnoreCase) >= 0
|| string.Equals(sourceExtension, ".mcx", StringComparison.OrdinalIgnoreCase))
{
@ -217,9 +220,9 @@ namespace MatterHackers.MatterControl.Library.Export
printer.Settings.SetValue(SettingsKey.spiral_vase, "1");
}
var errors = printer.ValidateSettings();
errors = printer.ValidateSettings();
if(errors.Count > 0)
if(errors.Any(e => e.ErrorLevel == ValidationErrorLevel.Error))
{
return errors;
}
@ -246,7 +249,8 @@ namespace MatterHackers.MatterControl.Library.Export
ApplyStreamPipelineAndExport(gcodePath, outputPath);
// last let's check if there is any support in the scene and if it looks like it is needed
if (GenerateSupportPanel.RequiresSupport(printer.Bed.Scene))
var supportGenerator = new SupportGenerator(printer.Bed.Scene);
if (supportGenerator.RequiresSupport())
{
UiThread.RunOnIdle(() =>
{
@ -255,7 +259,7 @@ namespace MatterHackers.MatterControl.Library.Export
});
}
return null;
return errors;
}
}
catch

View file

@ -71,7 +71,7 @@ namespace MatterHackers.MatterControl.Library
{ DateCreated = new System.DateTime(index++) },
new GeneratorItem(
() => "Text".Localize(),
() => TextObject3D.Create())
() => TextObject3D.Create().Result)
{ DateCreated = new System.DateTime(index++) },
#if DEBUG
new GeneratorItem(
@ -85,7 +85,7 @@ namespace MatterHackers.MatterControl.Library
{ DateCreated = new System.DateTime(index++) },
new GeneratorItem(
() => "Cone".Localize(),
() => ConeObject3D.Create())
() => ConeObject3D.Create().Result)
{ DateCreated = new System.DateTime(index++) },
new GeneratorItem(
() => "Half Cylinder".Localize(),

View file

@ -64,6 +64,7 @@ namespace MatterHackers.MatterControl.Library
{
this.CustomSearch = this;
this.ID = "SqliteContainer" + collectionID;
this.IsProtected = false;
this.ChildContainers = new List<ILibraryContainerLink>();
this.Items = new List<ILibraryItem>();
@ -87,7 +88,7 @@ namespace MatterHackers.MatterControl.Library
IEnumerable<ILibraryContainerLink> childContainers = childCollections.Select(c => new SqliteLibraryContainerLink()
{
ContainerID = c.Id,
CollectionID = c.Id,
Name = c.Name
});
@ -200,7 +201,7 @@ namespace MatterHackers.MatterControl.Library
}
else if (selectedItem is SqliteLibraryContainerLink containerLink)
{
string sql = $"SELECT * FROM PrintItemCollection WHERE ID = {containerLink.ContainerID}";
string sql = $"SELECT * FROM PrintItemCollection WHERE ID = {containerLink.CollectionID}";
var container = Datastore.Instance.dbSQLite.Query<PrintItemCollection>(sql).FirstOrDefault();
if (container != null)
@ -261,9 +262,9 @@ namespace MatterHackers.MatterControl.Library
public class SqliteLibraryContainerLink : ILibraryContainerLink
{
public string ID { get; } = Guid.NewGuid().ToString();
public string ID => "SqliteContainer" + this.CollectionID;
public int ContainerID { get; set; }
public int CollectionID { get; set; }
public string Name { get; set; }
@ -280,7 +281,7 @@ namespace MatterHackers.MatterControl.Library
public Task<ILibraryContainer> GetContainer(Action<double, string> reportProgress)
{
return Task.FromResult<ILibraryContainer>(
new SqliteLibraryContainer(this.ContainerID)
new SqliteLibraryContainer(this.CollectionID)
{
Name = this.Name,
});

View file

@ -147,7 +147,7 @@ namespace MatterHackers.MatterControl.Library
this.Children.Remove(placeholderItem);
this.Collapse();
this.Invalidate(new InvalidateArgs(this, InvalidateType.Content));
this.Invalidate(InvalidateType.Children);
}));
}

View file

@ -688,10 +688,10 @@ namespace MatterHackers.MatterControl.PrintLibrary
switch (selectedLibraryItems.FirstOrDefault())
{
case SDCardFileItem sdcardItem:
// TODO: Confirm SD printing?
// TODO: Need to rewrite library menu item validation can write one off validations like below so we don't end up here
// - ActiveSliceSettings.Instance.GetValue<bool>(SettingsKey.has_sd_card_reader)
printer.Connection.StartSdCardPrint(sdcardItem.Name.ToLower());
// TODO: Confirm SD printing?
// TODO: Need to rewrite library menu item validation can write one off validations like below so we don't end up here
// - ActiveSliceSettings.Instance.GetValue<bool>(SettingsKey.has_sd_card_reader)
printer.Connection.StartSdCardPrint(sdcardItem.Name.ToLower());
break;
case FileSystemFileItem fileItem when Path.GetExtension(fileItem.FileName).IndexOf(".gco", StringComparison.OrdinalIgnoreCase) == 0:
if (printer != null)

View file

@ -82,7 +82,6 @@ namespace MatterHackers.MatterControl.CustomWidgets
this.LibraryContext = context;
// Set Display Attributes
this.MinimumSize = new Vector2(0, 200);
this.AnchorAll();
this.AutoScroll = true;
this.ScrollArea.Padding = new BorderDouble(3);

View file

@ -50,27 +50,6 @@ namespace MatterHackers.MatterControl
public static class CreateDiscreteMeshes
{
public static List<List<int>> GetFacesSharingVertex(List<Vector3Float> vertexList, FaceList faces)
{
var sharingList = new List<List<int>>(vertexList.Count);
for(int i=0; i<vertexList.Count; i++)
{
sharingList.Add(new List<int>());
}
for (int faceIndex = 0; faceIndex < faces.Count; faceIndex++)
{
var face = faces[faceIndex];
var vertices = new int[] { face.v0, face.v1, face.v2 };
for (int vertexIndex = 0; vertexIndex < 3; vertexIndex++)
{
sharingList[vertexIndex].Add(faceIndex);
}
}
return sharingList;
}
public static List<Mesh> SplitVolumesIntoMeshes(Mesh meshToSplit, CancellationToken cancellationToken, Action<double, string> reportProgress)
{
Stopwatch maxProgressReport = Stopwatch.StartNew();
@ -80,8 +59,8 @@ namespace MatterHackers.MatterControl
var attachedFaces = new Stack<int>();
int faceCount = meshToSplit.Faces.Count;
var facesSharingVertex = GetFacesSharingVertex(meshToSplit.Vertices, meshToSplit.Faces);
var facesSharingVertex = meshToSplit.NewVertexFaceLists();
for (int faceIndex = 0; faceIndex < faceCount; faceIndex++)
{
if (reportProgress != null)
@ -110,7 +89,7 @@ namespace MatterHackers.MatterControl
foreach (var attachedVertex in vertices)
{
foreach (var sharedFaceIndex in facesSharingVertex[attachedVertex])
foreach (var sharedFaceIndex in facesSharingVertex[attachedVertex].Faces)
{
if (!facesThatHaveBeenAdded.Contains(sharedFaceIndex))
{

View file

@ -27,9 +27,8 @@ of the authors and should not be interpreted as representing official policies,
either expressed or implied, of the FreeBSD Project.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
using MatterHackers.Agg;
using MatterHackers.Agg.UI;
@ -44,30 +43,17 @@ using MatterHackers.VectorMath;
namespace MatterHackers.MatterControl.PartPreviewWindow
{
[HideFromTreeViewAttribute, Immutable]
public class GeneratedSupportObject3D : Object3D
{
public GeneratedSupportObject3D()
{
OutputType = PrintOutputTypes.Support;
}
}
public class GenerateSupportPanel : FlowLayoutWidget
{
/// <summary>
/// The amount to reduce the pillars so they are separated in the 3D view
/// </summary>
private double reduceAmount => PillarSize / 8;
private InteractiveScene scene;
private SupportGenerator supportGenerator;
private ThemeConfig theme;
public GenerateSupportPanel(ThemeConfig theme, InteractiveScene scene)
: base(FlowDirection.TopToBottom)
{
supportGenerator = new SupportGenerator(scene);
this.theme = theme;
this.scene = scene;
this.VAnchor = VAnchor.Fit;
this.HAnchor = HAnchor.Absolute;
@ -75,34 +61,57 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
this.BackgroundColor = theme.BackgroundColor;
this.Padding = theme.DefaultContainerPadding;
// put in support pillar size
// Add an editor field for the SupportGenerator.SupportType
PropertyInfo propertyInfo = typeof(SupportGenerator).GetProperty(nameof(SupportGenerator.SupportType));
// support pillar resolution
var editor = PublicPropertyEditor.CreatePropertyEditor(
new EditableProperty(propertyInfo, supportGenerator),
null,
new PPEContext(),
theme);
if (editor != null)
{
this.AddChild(editor);
}
// put in support pillar size
var pillarSizeField = new DoubleField(theme);
pillarSizeField.Initialize(0);
pillarSizeField.DoubleValue = PillarSize;
pillarSizeField.DoubleValue = supportGenerator.PillarSize;
pillarSizeField.ValueChanged += (s, e) =>
{
PillarSize = pillarSizeField.DoubleValue;
supportGenerator.PillarSize = pillarSizeField.DoubleValue;
// in case it was corrected set it back again
if (pillarSizeField.DoubleValue != supportGenerator.PillarSize)
{
pillarSizeField.DoubleValue = supportGenerator.PillarSize;
}
};
var pillarRow = PublicPropertyEditor.CreateSettingsRow("Pillar Size".Localize(), "The width and depth of the support pillars".Localize());
var pillarRow = PublicPropertyEditor.CreateSettingsRow("Pillar Size".Localize(), "The width and depth of the support pillars".Localize(), theme);
pillarRow.AddChild(pillarSizeField.Content);
this.AddChild(pillarRow);
// put in the angle setting
var overHangField = new DoubleField(theme);
overHangField.Initialize(0);
overHangField.DoubleValue = MaxOverHangAngle;
overHangField.DoubleValue = supportGenerator.MaxOverHangAngle;
overHangField.ValueChanged += (s, e) =>
{
MaxOverHangAngle = overHangField.DoubleValue;
supportGenerator.MaxOverHangAngle = overHangField.DoubleValue;
// in case it was corrected set it back again
if (overHangField.DoubleValue != supportGenerator.MaxOverHangAngle)
{
overHangField.DoubleValue = supportGenerator.MaxOverHangAngle;
}
};
var overHangRow = PublicPropertyEditor.CreateSettingsRow("Overhang Angle".Localize(), "The angle to generate support for".Localize());
var overHangRow = PublicPropertyEditor.CreateSettingsRow("Overhang Angle".Localize(), "The angle to generate support for".Localize(), theme);
overHangRow.AddChild(overHangField.Content);
this.AddChild(overHangRow);
// Button Row
var buttonRow = new FlowLayoutWidget()
{
HAnchor = HAnchor.Stretch,
@ -116,7 +125,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
// add 'Remove Auto Supports' button
var removeButton = theme.CreateDialogButton("Remove".Localize());
removeButton.ToolTipText = "Remove all auto generated supports".Localize();
removeButton.Click += (s, e) => RemoveExisting();
removeButton.Click += (s, e) => supportGenerator.RemoveExisting();
buttonRow.AddChild(removeButton);
// add 'Generate Supports' button
@ -127,239 +136,12 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
theme.ApplyPrimaryActionStyle(generateButton);
}
public static double MaxOverHangAngle { get; private set; } = 45;
public double PillarSize { get; private set; } = 4;
private void AddSupportColumn(IObject3D holder, double gridX, double gridY, double bottomZ, double topZ)
{
if(topZ - bottomZ < .01)
{
// less than 10 micros high, don't ad it
return;
}
holder.Children.Add(new GeneratedSupportObject3D()
{
Mesh = PlatonicSolids.CreateCube(PillarSize - reduceAmount, PillarSize - reduceAmount, topZ - bottomZ),
Matrix = Matrix4X4.CreateTranslation(gridX, gridY, bottomZ + (topZ - bottomZ) / 2)
});
}
private Task Rebuild()
{
return ApplicationController.Instance.Tasks.Execute(
"Create Support".Localize(),
null,
(reporter, cancellationToken) =>
{
// Get visible meshes for each of them
var visibleMeshes = scene.Children.SelectMany(i => i.VisibleMeshes());
var selectedItem = scene.SelectedItem;
if (selectedItem != null)
{
visibleMeshes = selectedItem.VisibleMeshes();
}
var supportCandidates = visibleMeshes.Where(i => i.OutputType != PrintOutputTypes.Support);
// find all the faces that are candidates for support
var upVerts = new List<Vector3Float>();
var upFaces = new FaceList();
var downVerts = new List<Vector3Float>();
var downFaces = new FaceList();
foreach (var item in supportCandidates)
{
var matrix = item.WorldMatrix(scene);
for (int faceIndex = 0; faceIndex < item.Mesh.Faces.Count; faceIndex++)
{
var face0Normal = item.Mesh.Faces[faceIndex].normal.TransformNormal(matrix).GetNormal();
var angle = MathHelper.RadiansToDegrees(Math.Acos(face0Normal.Dot(-Vector3Float.UnitZ)));
if (angle < MaxOverHangAngle)
{
var face = item.Mesh.Faces[faceIndex];
var verts = new int[] { face.v0, face.v1, face.v2 };
var fc = downVerts.Count;
downVerts.Add(item.Mesh.Vertices[face.v0].Transform(matrix));
downVerts.Add(item.Mesh.Vertices[face.v1].Transform(matrix));
downVerts.Add(item.Mesh.Vertices[face.v2].Transform(matrix));
downFaces.Add(fc, fc + 1, fc + 2, downVerts);
}
if (angle > 0)
{
var face = item.Mesh.Faces[faceIndex];
var verts = new int[] { face.v0, face.v1, face.v2 };
var fc = upFaces.Count;
upVerts.Add(item.Mesh.Vertices[face.v0].Transform(matrix));
upVerts.Add(item.Mesh.Vertices[face.v1].Transform(matrix));
upVerts.Add(item.Mesh.Vertices[face.v2].Transform(matrix));
upFaces.Add(fc, fc + 1, fc + 2, upVerts);
}
}
}
if (downFaces.Count > 0)
{
var downTraceData = downFaces.CreateTraceData(downVerts, 0);
var upTraceData = upFaces.CreateTraceData(upVerts, 0);
// get the bounds of all verts
var bounds = downVerts.Bounds();
// create the gird of possible support
var gridBounds = new RectangleDouble(Math.Floor((double)(bounds.MinXYZ.X / PillarSize)),
Math.Floor((double)(bounds.MinXYZ.Y / PillarSize)),
Math.Ceiling(bounds.MaxXYZ.X / PillarSize),
Math.Ceiling(bounds.MaxXYZ.Y / PillarSize));
var supportGrid = new List<List<double>>((int)(gridBounds.Width * gridBounds.Height));
IObject3D holder = new Object3D();
// at the center of every grid item add in a list of all the top faces to look down from
for (int y = 0; y < gridBounds.Height; y++)
{
var yPos = (gridBounds.Bottom + y) * PillarSize;
for (int x = 0; x < gridBounds.Width; x++)
{
var xPos = (gridBounds.Left + x) * PillarSize;
IntersectInfo upHit = null;
var upRay = new Ray(new Vector3(xPos, yPos, 0), Vector3.UnitZ, intersectionType: IntersectionType.Both);
do
{
upHit = downTraceData.GetClosestIntersection(upRay);
if (upHit != null)
{
// we found a ceiling above this spot, look down from that to find the first floor
var downRay = new Ray(new Vector3(upHit.HitPosition.X, upHit.HitPosition.Y, upHit.HitPosition.Z - .001), -Vector3.UnitZ, intersectionType: IntersectionType.Both);
var downHit = upTraceData.GetClosestIntersection(downRay);
if (downHit != null)
{
AddSupportColumn(holder, downHit.HitPosition.X, downHit.HitPosition.Y, downHit.HitPosition.Z, upHit.HitPosition.Z);
}
else
{
// did not find a hit, go to the bed
AddSupportColumn(holder, upHit.HitPosition.X, upHit.HitPosition.Y, upRay.origin.Z, upHit.HitPosition.Z);
}
// make a new ray just past the last hit to keep looking for up hits
upRay = new Ray(new Vector3(xPos, yPos, upHit.HitPosition.Z + .001), Vector3.UnitZ, intersectionType: IntersectionType.Both);
}
} while (upHit != null);
}
}
// foreach face set the support heights in the overlapped support grid
// foreach grid column that has data
// trace down from the top to the first bottom hit (or bed)
// add a support column
var first = downFaces.First();
var position = downVerts[first.v0];
//AddSupportColumn(position.X, position.Y, position.Z, 0);
scene.Children.Modify(list =>
{
list.AddRange(holder.Children);
});
}
// this is the theory for regions rather than pillars
// separate the faces into face patch groups (these are the new support tops)
// project all the vertices of each patch group down until they hit an up face in the scene (or 0)
// make a new patch group at the z of the hit (these will be the bottoms)
// find the outline of the patch groups (these will be the walls of the top and bottom patches
// make a new mesh object with the top, bottom and walls, add it to the scene and mark it as support
return Task.CompletedTask;
});
}
private void RemoveExisting()
{
var existingSupports = scene.Children.Where(i => i.GetType() == typeof(GeneratedSupportObject3D));
scene.Children.Modify((list) =>
{
foreach (var item in existingSupports)
{
list.Remove(item);
}
});
}
public static bool RequiresSupport(InteractiveScene scene)
{
bool supportInScene = scene.VisibleMeshes().Any(i => i.WorldOutputType() == PrintOutputTypes.Support);
if (!supportInScene)
{
// there is no support in the scene check if there are faces that require support
var supportCandidates = scene.VisibleMeshes().Where(i => i.OutputType != PrintOutputTypes.Support);
// find all the faces that are candidates for support
foreach (var item in supportCandidates)
{
var matrix = item.WorldMatrix(scene);
for (int faceIndex = 0; faceIndex < item.Mesh.Faces.Count; faceIndex++)
{
bool aboveBed = false;
var face = item.Mesh.Faces[faceIndex];
var verts = new int[] { face.v0, face.v1, face.v2 };
foreach(var vertex in verts)
{
if(item.Mesh.Vertices[vertex].Transform(matrix).Z > .01)
{
aboveBed = true;
break;
}
}
if (aboveBed)
{
var face0Normal = item.Mesh.Faces[faceIndex].normal.TransformNormal(matrix).GetNormal();
var angle = MathHelper.RadiansToDegrees(Math.Acos(face0Normal.Dot(-Vector3Float.UnitZ)));
if (angle < MaxOverHangAngle)
{
// TODO: consider how much area all supported polygons represent
return true;
}
}
}
}
}
return false;
}
}
public static class FaceListExtensions
{
public static IPrimitive CreateTraceData(this FaceList faceList, List<Vector3> vertexList, int maxRecursion = int.MaxValue)
{
var allPolys = new List<IPrimitive>();
foreach (var face in faceList)
{
allPolys.Add(new TriangleShape(vertexList[face.v0], vertexList[face.v1], vertexList[face.v2], null));
}
return BoundingVolumeHierarchy.CreateNewHierachy(allPolys, maxRecursion);
}
public static IPrimitive CreateTraceData(this FaceList faceList, List<Vector3Float> vertexList, int maxRecursion = int.MaxValue)
{
var allPolys = new List<IPrimitive>();
foreach (var face in faceList)
{
allPolys.Add(new TriangleShape(vertexList[face.v0], vertexList[face.v1], vertexList[face.v2], null));
}
return BoundingVolumeHierarchy.CreateNewHierachy(allPolys, maxRecursion);
null, supportGenerator.Create
);
}
}
}

View file

@ -98,28 +98,36 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
// Force common padding into top region
tabControl.TabBar.Padding = theme.TabbarPadding.Clone(top: theme.TabbarPadding.Top * 2, bottom: 0);
// add in the update available button
updateAvailableButton = new LinkLabel("Update Available".Localize(), theme)
if (Application.EnableNetworkTraffic)
{
Visible = false,
Name = "Update Available Link",
ToolTipText = "There is a new update available for download".Localize(),
VAnchor = VAnchor.Center,
Margin = new BorderDouble(10, 0)
};
// add in the update available button
updateAvailableButton = new LinkLabel("Update Available".Localize(), theme)
{
Visible = false,
Name = "Update Available Link",
ToolTipText = "There is a new update available for download".Localize(),
VAnchor = VAnchor.Center,
Margin = new BorderDouble(10, 0)
};
// Register listeners
UserSettings.Instance.SettingChanged += SetLinkButtonsVisibility;
// Register listeners
UserSettings.Instance.SettingChanged += SetLinkButtonsVisibility;
SetLinkButtonsVisibility(this, null);
SetLinkButtonsVisibility(this, null);
updateAvailableButton.Click += (s, e) => UiThread.RunOnIdle(() =>
{
UpdateControlData.Instance.CheckForUpdate();
DialogWindow.Show<CheckForUpdatesPage>();
});
updateAvailableButton.Click += (s, e) => UiThread.RunOnIdle(() =>
{
UpdateControlData.Instance.CheckForUpdate();
DialogWindow.Show<CheckForUpdatesPage>();
});
tabControl.TabBar.ActionArea.AddChild(updateAvailableButton);
tabControl.TabBar.ActionArea.AddChild(updateAvailableButton);
UpdateControlData.Instance.UpdateStatusChanged.RegisterEvent((s, e) =>
{
SetLinkButtonsVisibility(s, new StringEventArgs("Unknown"));
}, ref unregisterEvents);
}
this.AddChild(tabControl);
@ -266,11 +274,6 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
ApplicationController.Instance.ShellFileOpened += this.Instance_OpenNewFile;
UpdateControlData.Instance.UpdateStatusChanged.RegisterEvent((s, e) =>
{
SetLinkButtonsVisibility(s, new StringEventArgs("Unknown"));
}, ref unregisterEvents);
ApplicationController.Instance.MainView = this;
}

View file

@ -139,10 +139,10 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
{
switch (item)
{
case TransformWrapperObject3D fitToBounds3D:
case TransformWrapperObject3D transformWrapperObject3D:
return new ObjectView()
{
Children = new IObject3D[] { fitToBounds3D.SourceItem },
Children = transformWrapperObject3D.SourceItems,
Name = item.Name,
Source = item
};
@ -172,6 +172,15 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
Source = item
};
case OperationSourceContainerObject3D operationSourceContainerObject3D:
return new ObjectView()
{
Children = item.Children.OfType<OperationSourceObject3D>().ToList(),
Name = operationSourceContainerObject3D.Name,
Source = item
};
default:
return new ObjectView(item);
}

View file

@ -130,16 +130,6 @@ namespace MatterHackers.MatterControl
object3D.Matrix *= Matrix4X4.CreateTranslation(new Vector3(0, 0, -boundsCenter.Z + bounds.ZSize / 2));
}
public static void PlaceMeshAtHeight(IObject3D objectToMove, double zHeight)
{
AxisAlignedBoundingBox bounds = objectToMove.GetAxisAlignedBoundingBox(Matrix4X4.Identity);
if (bounds.MinXYZ.Z != zHeight)
{
objectToMove.Matrix *= Matrix4X4.CreateTranslation(new Vector3(0, 0, zHeight - bounds.MinXYZ.Z));
}
}
/// <summary>
/// Moves the target object to the first non-colliding position, starting from the lower left corner of the bounding box containing all sceneItems
/// </summary>

View file

@ -75,10 +75,12 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
public ArrowDirection ArrowDirection
{
get => _arrow;
protected set
set
{
_arrow = value;
this.RebuildShape();
switch (_arrow)
{
case ArrowDirection.Top:

View file

@ -641,7 +641,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
if (doSlicing)
{
var errors = printer.ValidateSettings();
if(errors.Count > 0)
if(errors.Any(err => err.ErrorLevel == ValidationErrorLevel.Error))
{
doSlicing = false;
ApplicationController.Instance.ShowValidationErrors("Slicing Error".Localize(), errors);

View file

@ -90,14 +90,17 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
{
if (this.item.CanFlatten)
{
this.item.Flatten(view3DWidget.Scene.UndoBuffer);
var item = this.item;
using (new SelectionMaintainer(view3DWidget.Scene))
{
item.Flatten(view3DWidget.Scene.UndoBuffer);
}
}
else
{
// try to ungroup it
sceneContext.Scene.UngroupSelection();
}
scene.SelectedItem = null;
};
toolbar.AddChild(flattenButton);
@ -110,17 +113,10 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
};
removeButton.Click += (s, e) =>
{
var rootSelection = scene.SelectedItemRoot;
var removeItem = item;
removeItem.Remove(view3DWidget.Scene.UndoBuffer);
scene.SelectedItem = null;
// Only restore the root selection if it wasn't the item removed
if (removeItem != rootSelection)
var item = this.item;
using (new SelectionMaintainer(view3DWidget.Scene))
{
scene.SelectedItem = rootSelection;
item.Remove(view3DWidget.Scene.UndoBuffer);
}
};
toolbar.AddChild(removeButton);
@ -221,7 +217,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
var button = new IconButton(primaryAction.IconCollector(theme), theme)
{
//Name = namedAction.Title + " Button",
//ToolTipText = namedAction.Title,
ToolTipText = primaryAction.Title,
Margin = theme.ButtonSpacing,
BackgroundColor = theme.ToolbarButtonBackground,
HoverColor = theme.ToolbarButtonHover,
@ -447,6 +443,10 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
|| selectedItem.CanFlatten);
removeButton.Enabled = selectedItem != null;
overflowButton.Enabled = selectedItem != null;
if(selectedItem == null)
{
primaryActionsPanel.RemoveAllChildren();
}
}
}
}

View file

@ -33,6 +33,7 @@ using System.Linq;
using MatterHackers.Agg;
using MatterHackers.Agg.UI;
using MatterHackers.DataConverters3D;
using MatterHackers.MatterControl.CustomWidgets;
using MatterHackers.MatterControl.SlicerConfiguration;
using MatterHackers.VectorMath;
@ -87,6 +88,9 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
{
public static void ShowPopover(this SystemWindow systemWindow, MatePoint anchor, MatePoint popup, RectangleDouble altBounds = default(RectangleDouble), double secondsToClose = 0)
{
var settingsRow = anchor.Widget as SettingsRow;
var popoverWidget = popup.Widget as SliceSettingsPopover;
var hookedWidgets = new HashSet<GuiWidget>();
void anchor_Closed(object sender, EventArgs e)
{
@ -127,7 +131,22 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
if (screenPosition.X + popup.Widget.Width > systemWindow.Width
|| screenPosition.X < 0)
{
xPosition = GetXAnchor(anchor.AltMate, popup.AltMate, popup.Widget, bounds);
var altXPosition = GetXAnchor(anchor.AltMate, popup.AltMate, popup.Widget, bounds);
var altScreenPosition = anchorLeft + altXPosition;
// Prefer clipping on edge revealed by resize
if ((popup.AltMate.Right && altScreenPosition.X > -15)
|| (popup.AltMate.Left && altScreenPosition.X + popup.Widget.Width < systemWindow.Width))
{
xPosition = altXPosition;
if (settingsRow != null
&& popoverWidget != null)
{
popoverWidget.ArrowDirection = settingsRow.ArrowDirection == ArrowDirection.Left ? ArrowDirection.Right : ArrowDirection.Left;
}
}
}
popupPosition += xPosition;
@ -142,6 +161,11 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
|| screenPosition.Y < 0))
{
yPosition = GetYAnchor(anchor.AltMate, popup.AltMate, popup.Widget, bounds);
if (settingsRow != null)
{
settingsRow.ArrowDirection = settingsRow.ArrowDirection == ArrowDirection.Top ? ArrowDirection.Bottom: ArrowDirection.Top;
}
}
popup.Widget.Closed += anchor_Closed;

View file

@ -0,0 +1,137 @@
/*
Copyright (c) 2017, Lars Brubaker, John Lewin
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
The views and conclusions contained in the software and documentation are those
of the authors and should not be interpreted as representing official policies,
either expressed or implied, of the FreeBSD Project.
*/
using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using MatterHackers.Agg;
using MatterHackers.DataConverters3D;
using MatterHackers.Localizations;
using MatterHackers.MatterControl.DesignTools.Operations;
using MatterHackers.VectorMath;
namespace MatterHackers.MatterControl.PartPreviewWindow.View3D
{
public class CombineObject3D_2 : OperationSourceContainerObject3D
{
public CombineObject3D_2()
{
Name = "Combine";
}
public override Task Rebuild()
{
this.DebugDepth("Rebuild");
var rebuildLocks = this.RebuilLockAll();
return ApplicationController.Instance.Tasks.Execute(
"Combine".Localize(),
null,
(reporter, cancellationToken) =>
{
var progressStatus = new ProgressStatus();
reporter.Report(progressStatus);
try
{
Combine(cancellationToken, reporter);
}
catch
{
}
rebuildLocks.Dispose();
Invalidate(InvalidateType.Children);
return Task.CompletedTask;
});
}
public void Combine()
{
Combine(CancellationToken.None, null);
}
public void Combine(CancellationToken cancellationToken, IProgress<ProgressStatus> reporter)
{
SourceContainer.Visible = true;
RemoveAllButSource();
var participants = SourceContainer.VisibleMeshes();
if (participants.Count() < 2)
{
if(participants.Count() == 1)
{
var newMesh = new Object3D();
newMesh.CopyProperties(participants.First(), Object3DPropertyFlags.All);
newMesh.Mesh = participants.First().Mesh;
this.Children.Add(newMesh);
SourceContainer.Visible = false;
}
return;
}
var first = participants.First();
var resultsMesh = first.Mesh;
var firstWorldMatrix = first.WorldMatrix(SourceContainer);
var totalOperations = participants.Count() - 1;
double amountPerOperation = 1.0 / totalOperations;
double percentCompleted = 0;
ProgressStatus progressStatus = new ProgressStatus();
foreach (var item in participants)
{
if (item != first)
{
var itemWorldMatrix = item.WorldMatrix(SourceContainer);
resultsMesh = BooleanProcessing.Do(item.Mesh, itemWorldMatrix,
resultsMesh, firstWorldMatrix,
0,
reporter, amountPerOperation, percentCompleted, progressStatus, cancellationToken);
// after the first union we are working with the transformed mesh and don't need the first transform
firstWorldMatrix = Matrix4X4.Identity;
percentCompleted += amountPerOperation;
progressStatus.Progress0To1 = percentCompleted;
reporter?.Report(progressStatus);
}
}
var resultsItem = new Object3D()
{
Mesh = resultsMesh
};
resultsItem.CopyProperties(first, Object3DPropertyFlags.All & (~Object3DPropertyFlags.Matrix));
this.Children.Add(resultsItem);
SourceContainer.Visible = false;
}
}
}

View file

@ -115,7 +115,7 @@ namespace MatterHackers.MatterControl.DesignTools
thumbnailWidget.Image = SetImage(theme, imageObject);
column.Invalidate();
imageObject.Invalidate(new InvalidateArgs(imageObject, InvalidateType.Image));
imageObject.Invalidate(InvalidateType.Image);
};
pasteMenu.Enabled = Clipboard.Instance.ContainsImage;
@ -172,7 +172,7 @@ namespace MatterHackers.MatterControl.DesignTools
thumbnailWidget.Image = SetImage(theme, imageObject);
column.Invalidate();
imageObject.Invalidate(new InvalidateArgs(imageObject, InvalidateType.Image));
imageObject.Invalidate(InvalidateType.Image);
});
});
};
@ -202,7 +202,7 @@ namespace MatterHackers.MatterControl.DesignTools
imageObject.Invalidated += (s, e) =>
{
if (e.InvalidateType == InvalidateType.Image
if (e.InvalidateType.HasFlag(InvalidateType.Image)
&& activeImage != imageObject.Image)
{
thumbnailImage = SetImage(theme, imageObject);

View file

@ -0,0 +1,138 @@
/*
Copyright (c) 2017, Lars Brubaker, John Lewin
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
The views and conclusions contained in the software and documentation are those
of the authors and should not be interpreted as representing official policies,
either expressed or implied, of the FreeBSD Project.
*/
using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using MatterHackers.Agg;
using MatterHackers.Agg.UI;
using MatterHackers.DataConverters3D;
using MatterHackers.Localizations;
using MatterHackers.MatterControl.DesignTools.Operations;
using MatterHackers.VectorMath;
namespace MatterHackers.MatterControl.PartPreviewWindow.View3D
{
public class IntersectionObject3D_2 : OperationSourceContainerObject3D
{
public IntersectionObject3D_2()
{
Name = "Intersection";
}
public override Task Rebuild()
{
this.DebugDepth("Rebuild");
var rebuildLocks = this.RebuilLockAll();
return ApplicationController.Instance.Tasks.Execute(
"Intersection".Localize(),
null,
(reporter, cancellationToken) =>
{
var progressStatus = new ProgressStatus();
reporter.Report(progressStatus);
try
{
Intersect(cancellationToken, reporter);
}
catch
{
}
rebuildLocks.Dispose();
Invalidate(InvalidateType.Children);
return Task.CompletedTask;
});
}
public void Intersect()
{
Intersect(CancellationToken.None, null);
}
private void Intersect(CancellationToken cancellationToken, IProgress<ProgressStatus> reporter)
{
SourceContainer.Visible = true;
RemoveAllButSource();
var participants = SourceContainer.VisibleMeshes();
if (participants.Count() < 2)
{
if (participants.Count() == 1)
{
var newMesh = new Object3D();
newMesh.CopyProperties(participants.First(), Object3DPropertyFlags.All);
newMesh.Mesh = participants.First().Mesh;
this.Children.Add(newMesh);
SourceContainer.Visible = false;
}
return;
}
var first = participants.First();
var resultsMesh = first.Mesh;
var firstWorldMatrix = first.WorldMatrix(SourceContainer);
var totalOperations = participants.Count() - 1;
double amountPerOperation = 1.0 / totalOperations;
double percentCompleted = 0;
ProgressStatus progressStatus = new ProgressStatus();
foreach (var item in participants)
{
if (item != first)
{
var itemWorldMatrix = item.WorldMatrix(SourceContainer);
resultsMesh = BooleanProcessing.Do(item.Mesh, itemWorldMatrix,
resultsMesh, firstWorldMatrix,
2,
reporter, amountPerOperation, percentCompleted, progressStatus, cancellationToken);
// after the first union we are working with the transformed mesh and don't need the first transform
firstWorldMatrix = Matrix4X4.Identity;
percentCompleted += amountPerOperation;
progressStatus.Progress0To1 = percentCompleted;
reporter?.Report(progressStatus);
}
}
var resultsItem = new Object3D()
{
Mesh = resultsMesh
};
resultsItem.CopyProperties(first, Object3DPropertyFlags.All & (~Object3DPropertyFlags.Matrix));
this.Children.Add(resultsItem);
SourceContainer.Visible = false;
}
}
}

View file

@ -122,7 +122,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow.View3D
}
}
Invalidate(new InvalidateArgs(this, InvalidateType.Content, undoBuffer));
Invalidate(InvalidateType.Children);
}
/// <summary>
@ -187,7 +187,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow.View3D
// collapse our children into our parent
// and replace us with the children
var replaceCommand = new ReplaceCommand(new List<IObject3D> { this }, thisClone.Children.ToList());
var replaceCommand = new ReplaceCommand(new[] { this }, thisClone.Children.ToList());
if (undoBuffer != null)
{
undoBuffer.AddAndDo(replaceCommand);
@ -199,7 +199,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow.View3D
}
}
Invalidate(new InvalidateArgs(this, InvalidateType.Content));
Invalidate(InvalidateType.Children);
}
public void ResetMeshWrapperMeshes(Object3DPropertyFlags flags, CancellationToken cancellationToken)
@ -266,7 +266,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow.View3D
}
}
Invalidate(new InvalidateArgs(this, InvalidateType.Properties, null));
Invalidate(InvalidateType.Properties);
}
public void WrapItems(List<IObject3D> items)
@ -290,7 +290,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow.View3D
this.MakeNameNonColliding();
}
Invalidate(new InvalidateArgs(this, InvalidateType.Properties, null));
Invalidate(InvalidateType.Properties);
}
private void AddMeshWrapperToAllChildren()

View file

@ -49,12 +49,12 @@ namespace MatterHackers.MatterControl.PartPreviewWindow.View3D
var firstChild = this.Children.FirstOrDefault();
if (firstChild != null)
{
if (invalidateType.InvalidateType == InvalidateType.Color)
if (invalidateType.InvalidateType.HasFlag(InvalidateType.Color))
{
this.Color = firstChild.Color;
}
if (invalidateType.InvalidateType == InvalidateType.Material)
if (invalidateType.InvalidateType.HasFlag(InvalidateType.Material))
{
this.MaterialIndex = firstChild.MaterialIndex;
}

View file

@ -57,23 +57,23 @@ namespace MatterHackers.MatterControl.PartPreviewWindow.View3D
public override async void OnInvalidate(InvalidateArgs invalidateType)
{
if ((invalidateType.InvalidateType == InvalidateType.Content
|| invalidateType.InvalidateType == InvalidateType.Matrix
|| invalidateType.InvalidateType == InvalidateType.Mesh)
if ((invalidateType.InvalidateType.HasFlag(InvalidateType.Children)
|| invalidateType.InvalidateType.HasFlag(InvalidateType.Matrix)
|| invalidateType.InvalidateType.HasFlag(InvalidateType.Mesh))
&& invalidateType.Source != this
&& !RebuildLocked)
{
await Rebuild();
invalidateType = new InvalidateArgs(this, InvalidateType.Content, invalidateType.UndoBuffer);
}
else if (invalidateType.InvalidateType == InvalidateType.Properties
else if (invalidateType.InvalidateType.HasFlag(InvalidateType.Properties)
&& invalidateType.Source == this)
{
await Rebuild();
invalidateType = new InvalidateArgs(this, InvalidateType.Content, invalidateType.UndoBuffer);
}
base.OnInvalidate(invalidateType);
else
{
base.OnInvalidate(invalidateType);
}
}
public void SubtractAndReplace()
@ -172,12 +172,8 @@ namespace MatterHackers.MatterControl.PartPreviewWindow.View3D
{
}
UiThread.RunOnIdle(() =>
{
rebuildLocks.Dispose();
base.Invalidate(new InvalidateArgs(this, InvalidateType.Content));
});
rebuildLocks.Dispose();
Invalidate(InvalidateType.Children);
return Task.CompletedTask;
});
}

View file

@ -27,22 +27,24 @@ of the authors and should not be interpreted as representing official policies,
either expressed or implied, of the FreeBSD Project.
*/
/*********************************************************************/
/**************************** OBSOLETE! ******************************/
/************************ USE NEWER VERSION **************************/
/*********************************************************************/
using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using MatterHackers.Agg;
using MatterHackers.Agg.UI;
using MatterHackers.DataConverters3D;
using MatterHackers.Localizations;
using MatterHackers.MatterControl.DataStorage;
using MatterHackers.MatterControl.DesignTools;
using MatterHackers.PolygonMesh.Processors;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace MatterHackers.MatterControl.PartPreviewWindow.View3D
{
[Obsolete("Use SubtractObject3D_2 instead", false)]
[ShowUpdateButton]
public class SubtractObject3D : MeshWrapperObject3D, ISelectableChildContainer
{
@ -55,6 +57,53 @@ namespace MatterHackers.MatterControl.PartPreviewWindow.View3D
public SelectedChildren SelectedChildren => ItemsToSubtract;
public override async void OnInvalidate(InvalidateArgs invalidateType)
{
if ((invalidateType.InvalidateType.HasFlag(InvalidateType.Children)
|| invalidateType.InvalidateType.HasFlag(InvalidateType.Matrix)
|| invalidateType.InvalidateType.HasFlag(InvalidateType.Mesh))
&& invalidateType.Source != this
&& !RebuildLocked)
{
await Rebuild();
}
else if (invalidateType.InvalidateType.HasFlag(InvalidateType.Properties)
&& invalidateType.Source == this)
{
await Rebuild();
}
base.OnInvalidate(invalidateType);
}
public override Task Rebuild()
{
this.DebugDepth("Rebuild");
var rebuildLocks = this.RebuilLockAll();
// spin up a task to remove holes from the objects in the group
return ApplicationController.Instance.Tasks.Execute(
"Subtract".Localize(),
null,
(reporter, cancellationToken) =>
{
var progressStatus = new ProgressStatus();
reporter.Report(progressStatus);
try
{
Subtract(cancellationToken, reporter);
}
catch
{
}
rebuildLocks.Dispose();
Invalidate(InvalidateType.Children);
return Task.CompletedTask;
});
}
public void Subtract()
{
Subtract(CancellationToken.None, null);
@ -66,13 +115,13 @@ namespace MatterHackers.MatterControl.PartPreviewWindow.View3D
bool ItemInSubtractList(IObject3D item)
{
if(ItemsToSubtract.Contains(item.ID))
if (ItemsToSubtract.Contains(item.ID))
{
return true;
}
// check if the wrapped item is in the subtract list
if(item.Children.Count > 0 && ItemsToSubtract.Contains(item.Children.First().ID))
if (item.Children.Count > 0 && ItemsToSubtract.Contains(item.Children.First().ID))
{
return true;
}
@ -128,58 +177,5 @@ namespace MatterHackers.MatterControl.PartPreviewWindow.View3D
}
}
}
public override async void OnInvalidate(InvalidateArgs invalidateType)
{
if ((invalidateType.InvalidateType == InvalidateType.Content
|| invalidateType.InvalidateType == InvalidateType.Matrix
|| invalidateType.InvalidateType == InvalidateType.Mesh)
&& invalidateType.Source != this
&& !RebuildLocked)
{
await Rebuild();
invalidateType = new InvalidateArgs(this, InvalidateType.Content, invalidateType.UndoBuffer);
}
else if (invalidateType.InvalidateType == InvalidateType.Properties
&& invalidateType.Source == this)
{
await Rebuild();
invalidateType = new InvalidateArgs(this, InvalidateType.Content, invalidateType.UndoBuffer);
}
base.OnInvalidate(invalidateType);
}
public override Task Rebuild()
{
this.DebugDepth("Rebuild");
var rebuildLocks = this.RebuilLockAll();
// spin up a task to remove holes from the objects in the group
return ApplicationController.Instance.Tasks.Execute(
"Subtract".Localize(),
null,
(reporter, cancellationToken) =>
{
var progressStatus = new ProgressStatus();
reporter.Report(progressStatus);
try
{
Subtract(cancellationToken, reporter);
}
catch
{
}
UiThread.RunOnIdle(() =>
{
rebuildLocks.Dispose();
base.Invalidate(new InvalidateArgs(this, InvalidateType.Content));
});
return Task.CompletedTask;
});
}
}
}

View file

@ -0,0 +1,191 @@
/*
Copyright (c) 2017, Lars Brubaker, John Lewin
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
The views and conclusions contained in the software and documentation are those
of the authors and should not be interpreted as representing official policies,
either expressed or implied, of the FreeBSD Project.
*/
using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using MatterHackers.Agg;
using MatterHackers.Agg.UI;
using MatterHackers.DataConverters3D;
using MatterHackers.Localizations;
using MatterHackers.MatterControl.DesignTools;
using MatterHackers.MatterControl.DesignTools.Operations;
namespace MatterHackers.MatterControl.PartPreviewWindow.View3D
{
public class SubtractObject3D_2 : OperationSourceContainerObject3D, ISelectableChildContainer
{
public SubtractObject3D_2()
{
Name = "Subtract";
}
public SelectedChildren ItemsToSubtract { get; set; } = new SelectedChildren();
public SelectedChildren SelectedChildren => ItemsToSubtract;
public override async void OnInvalidate(InvalidateArgs invalidateType)
{
if ((invalidateType.InvalidateType.HasFlag(InvalidateType.Children)
|| invalidateType.InvalidateType.HasFlag(InvalidateType.Matrix)
|| invalidateType.InvalidateType.HasFlag(InvalidateType.Mesh))
&& invalidateType.Source != this
&& !RebuildLocked)
{
await Rebuild();
}
else if (invalidateType.InvalidateType.HasFlag(InvalidateType.Properties)
&& invalidateType.Source == this)
{
await Rebuild();
}
base.OnInvalidate(invalidateType);
}
public override Task Rebuild()
{
this.DebugDepth("Rebuild");
var rebuildLocks = this.RebuilLockAll();
// spin up a task to remove holes from the objects in the group
return ApplicationController.Instance.Tasks.Execute(
"Subtract".Localize(),
null,
(reporter, cancellationToken) =>
{
var progressStatus = new ProgressStatus();
reporter.Report(progressStatus);
try
{
Subtract(cancellationToken, reporter);
}
catch
{
}
rebuildLocks.Dispose();
Invalidate(InvalidateType.Children);
return Task.CompletedTask;
});
}
public void Subtract()
{
Subtract(CancellationToken.None, null);
}
private void Subtract(CancellationToken cancellationToken, IProgress<ProgressStatus> reporter)
{
SourceContainer.Visible = true;
RemoveAllButSource();
var participants = SourceContainer.VisibleMeshes();
if (participants.Count() < 2)
{
if (participants.Count() == 1)
{
var newMesh = new Object3D();
newMesh.CopyProperties(participants.First(), Object3DPropertyFlags.All);
newMesh.Mesh = participants.First().Mesh;
this.Children.Add(newMesh);
SourceContainer.Visible = false;
}
return;
}
bool ItemInSubtractList(IObject3D item)
{
if (ItemsToSubtract.Contains(item.ID))
{
return true;
}
// check if the wrapped item is in the subtract list
if (item.Children.Count > 0 && ItemsToSubtract.Contains(item.Children.First().ID))
{
return true;
}
return false;
}
var removeObjects = this.Children
.Where((i) => ItemInSubtractList(i))
.SelectMany((h) => h.DescendantsAndSelf())
.Where((c) => c.OwnerID == this.ID).ToList();
var keepObjects = this.Children
.Where((i) => !ItemInSubtractList(i))
.SelectMany((h) => h.DescendantsAndSelf())
.Where((c) => c.OwnerID == this.ID).ToList();
if (removeObjects.Any()
&& keepObjects.Any())
{
var totalOperations = removeObjects.Count * keepObjects.Count;
double amountPerOperation = 1.0 / totalOperations;
double percentCompleted = 0;
ProgressStatus progressStatus = new ProgressStatus();
foreach (var remove in removeObjects.Select((r) => (obj3D: r, matrix: r.WorldMatrix())).ToList())
{
foreach (var keep in keepObjects.Select((r) => (obj3D: r, matrix: r.WorldMatrix())).ToList())
{
progressStatus.Status = "Copy Remove";
reporter?.Report(progressStatus);
progressStatus.Status = "Copy Keep";
reporter?.Report(progressStatus);
progressStatus.Status = "Do CSG";
reporter?.Report(progressStatus);
var result = BooleanProcessing.Do(keep.obj3D.Mesh, keep.matrix,
remove.obj3D.Mesh, remove.matrix, 1, reporter, amountPerOperation, percentCompleted, progressStatus, cancellationToken);
var inverse = keep.matrix.Inverted;
result.Transform(inverse);
using (keep.obj3D.RebuildLock())
{
keep.obj3D.Mesh = result;
}
percentCompleted += amountPerOperation;
progressStatus.Progress0To1 = percentCompleted;
reporter?.Report(progressStatus);
}
remove.obj3D.Visible = false;
SourceContainer.Visible = false;
}
}
}
}
}

View file

@ -136,7 +136,6 @@ namespace MatterHackers.MatterControl
private static ImageBuffer CreateCircularBedGridImage(PrinterConfig printer)
{
Vector3 displayVolumeToBuild = Vector3.ComponentMax(printer.Bed.ViewerVolume, new Vector3(1, 1, 1));
double sizeForMarking = Math.Max(displayVolumeToBuild.X, displayVolumeToBuild.Y);
double cmPerLine = 10;
int skip = 1;
@ -153,6 +152,7 @@ namespace MatterHackers.MatterControl
var bedplateImage = new ImageBuffer(1024, 1024);
Graphics2D graphics2D = bedplateImage.NewGraphics2D();
graphics2D.Clear(bedBaseColor);
var originPixels = new Vector2();
{

View file

@ -0,0 +1,44 @@
/*
Copyright (c) 2019, Lars Brubaker
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
The views and conclusions contained in the software and documentation are those
of the authors and should not be interpreted as representing official policies,
either expressed or implied, of the FreeBSD Project.
*/
using MatterHackers.Agg.UI;
namespace MatterHackers.MeshVisualizer
{
public class DrawGlContentEventArgs : DrawEventArgs
{
public bool ZBuffered { get; }
public DrawGlContentEventArgs(bool zBuffered, DrawEventArgs e)
: base(e.Graphics2D)
{
ZBuffered = zBuffered;
}
}
}

View file

@ -0,0 +1,208 @@
/*
Copyright (c) 2019, Lars Brubaker
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
The views and conclusions contained in the software and documentation are those
of the authors and should not be interpreted as representing official policies,
either expressed or implied, of the FreeBSD Project.
*/
using System;
using MatterHackers.Agg;
using MatterHackers.MatterControl.DesignTools.EditableTypes;
using MatterHackers.RenderOpenGl;
using MatterHackers.RenderOpenGl.OpenGl;
using MatterHackers.VectorMath;
namespace MatterHackers.MeshVisualizer
{
public static class MaterialRendering
{
public static void RenderCylinderOutline(this WorldView world, Matrix4X4 worldMatrix, Vector3 center, double Diameter, double Height, int sides, Color color, double lineWidth = 1, double extendLineLength = 0)
{
GLHelper.PrepareFor3DLineRender(true);
Frustum frustum = world.GetClippingFrustum();
for (int i = 0; i < sides; i++)
{
var rotatedPoint = new Vector3(Math.Cos(MathHelper.Tau * i / sides), Math.Sin(MathHelper.Tau * i / sides), 0) * Diameter / 2;
var sideTop = Vector3Ex.Transform(center + rotatedPoint + new Vector3(0, 0, Height / 2), worldMatrix);
var sideBottom = Vector3Ex.Transform(center + rotatedPoint + new Vector3(0, 0, -Height / 2), worldMatrix);
var rotated2Point = new Vector3(Math.Cos(MathHelper.Tau * (i + 1) / sides), Math.Sin(MathHelper.Tau * (i + 1) / sides), 0) * Diameter / 2;
var topStart = sideTop;
var topEnd = Vector3Ex.Transform(center + rotated2Point + new Vector3(0, 0, Height / 2), worldMatrix);
var bottomStart = sideBottom;
var bottomEnd = Vector3Ex.Transform(center + rotated2Point + new Vector3(0, 0, -Height / 2), worldMatrix);
if (extendLineLength > 0)
{
GLHelper.ExtendLineEnds(ref sideTop, ref sideBottom, extendLineLength);
}
world.Render3DLineNoPrep(frustum, sideTop, sideBottom, color, lineWidth);
world.Render3DLineNoPrep(frustum, topStart, topEnd, color, lineWidth);
world.Render3DLineNoPrep(frustum, bottomStart, bottomEnd, color, lineWidth);
}
// turn the lighting back on
GL.Enable(EnableCap.Lighting);
}
public static void RenderAabb(this WorldView world, AxisAlignedBoundingBox bounds, Matrix4X4 matrix, Color color, double width, double extendLineLength = 0)
{
GLHelper.PrepareFor3DLineRender(true);
Frustum frustum = world.GetClippingFrustum();
for (int i = 0; i < 4; i++)
{
Vector3 sideStartPosition = Vector3Ex.Transform(bounds.GetBottomCorner(i), matrix);
Vector3 sideEndPosition = Vector3Ex.Transform(bounds.GetTopCorner(i), matrix);
Vector3 bottomStartPosition = sideStartPosition;
Vector3 bottomEndPosition = Vector3Ex.Transform(bounds.GetBottomCorner((i + 1) % 4), matrix);
Vector3 topStartPosition = sideEndPosition;
Vector3 topEndPosition = Vector3Ex.Transform(bounds.GetTopCorner((i + 1) % 4), matrix);
if (extendLineLength > 0)
{
GLHelper.ExtendLineEnds(ref sideStartPosition, ref sideEndPosition, extendLineLength);
GLHelper.ExtendLineEnds(ref topStartPosition, ref topEndPosition, extendLineLength);
GLHelper.ExtendLineEnds(ref bottomStartPosition, ref bottomEndPosition, extendLineLength);
}
// draw each of the edge lines (4) and their touching top and bottom lines (2 each)
world.Render3DLineNoPrep(frustum, sideStartPosition, sideEndPosition, color, width);
world.Render3DLineNoPrep(frustum, topStartPosition, topEndPosition, color, width);
world.Render3DLineNoPrep(frustum, bottomStartPosition, bottomEndPosition, color, width);
}
GL.Enable(EnableCap.Lighting);
}
public static void RenderAxis(this WorldView world, Vector3 position, Matrix4X4 matrix, double size, double lineWidth)
{
GLHelper.PrepareFor3DLineRender(true);
Frustum frustum = world.GetClippingFrustum();
Vector3 length = Vector3.One * size;
for (int i = 0; i < 3; i++)
{
var min = position;
min[i] -= length[i];
Vector3 start = Vector3Ex.Transform(min, matrix);
var max = position;
max[i] += length[i];
Vector3 end = Vector3Ex.Transform(max, matrix);
var color = Agg.Color.Red;
switch (i)
{
case 1:
color = Agg.Color.Green;
break;
case 2:
color = Agg.Color.Blue;
break;
}
// draw each of the edge lines (4) and their touching top and bottom lines (2 each)
world.Render3DLineNoPrep(frustum, start, end, color, lineWidth);
}
GL.Enable(EnableCap.Lighting);
}
public static void RenderDirectionAxis(this WorldView world, DirectionAxis axis, Matrix4X4 matrix, double size)
{
GLHelper.PrepareFor3DLineRender(true);
Frustum frustum = world.GetClippingFrustum();
Vector3 length = axis.Normal * size;
var color = Agg.Color.Red;
// draw center line
{
var min = axis.Origin - length;
Vector3 start = Vector3Ex.Transform(min, matrix);
var max = axis.Origin + length;
Vector3 end = Vector3Ex.Transform(max, matrix);
world.Render3DLineNoPrep(frustum, start, end, color, 1);
}
var perpendicular = Vector3.GetPerpendicular(axis.Normal, Vector3.Zero).GetNormal();
// draw some lines to mark the rotation plane
int count = 20;
bool first = true;
var firstEnd = Vector3.Zero;
var lastEnd = Vector3.Zero;
var center = Vector3Ex.Transform(axis.Origin, matrix);
for (int i = 0; i < count; i++)
{
var rotation = size/4 * Vector3Ex.Transform(perpendicular, Matrix4X4.CreateRotation(axis.Normal, MathHelper.Tau * i / count));
// draw center line
var max = axis.Origin + rotation;
Vector3 end = Vector3Ex.Transform(max, matrix);
world.Render3DLineNoPrep(frustum, center, end, color, 1);
if (!first)
{
world.Render3DLineNoPrep(frustum, end, lastEnd, color, 1);
}
else
{
firstEnd = end;
}
lastEnd = end;
first = false;
}
world.Render3DLineNoPrep(frustum, firstEnd, lastEnd, color, 1);
GL.Enable(EnableCap.Lighting);
}
/// <summary>
/// Get the color for a given extruder, falling back to extruder 0 color on -1 (unassigned)
/// </summary>
/// <param name="materialIndex">The extruder/material index to resolve</param>
/// <returns>The color for the given extruder</returns>
public static Color Color(int materialIndex)
{
return ColorF.FromHSL(Math.Max(materialIndex, 0) / 10.0, .99, .49).ToColor();
}
/// <summary>
/// Get the color for a given extruder, falling back to the supplied color on -1 (unassigned)
/// </summary>
/// <param name="materialIndex">The extruder/material index to resolve</param>
/// <param name="unassignedColor">The color to use when the extruder/material has not been assigned</param>
/// <returns>The color for the given extruder</returns>
public static Color Color(int materialIndex, Color unassignedColor)
{
return (materialIndex == -1) ? unassignedColor : ColorF.FromHSL(materialIndex / 10.0, .99, .49).ToColor();
}
}
}

View file

@ -1,5 +1,5 @@
/*
Copyright (c) 2014, Lars Brubaker
Copyright (c) 2019, Lars Brubaker
All rights reserved.
Redistribution and use in source and binary forms, with or without
@ -40,7 +40,6 @@ using MatterHackers.DataConverters3D;
using MatterHackers.Localizations;
using MatterHackers.MatterControl;
using MatterHackers.MatterControl.DesignTools;
using MatterHackers.MatterControl.DesignTools.EditableTypes;
using MatterHackers.MatterControl.DesignTools.Operations;
using MatterHackers.MatterControl.PartPreviewWindow;
using MatterHackers.MatterControl.PartPreviewWindow.View3D;
@ -52,187 +51,6 @@ using static MatterHackers.Agg.Easing;
namespace MatterHackers.MeshVisualizer
{
public class DrawGlContentEventArgs : DrawEventArgs
{
public bool ZBuffered { get; }
public DrawGlContentEventArgs(bool zBuffered, DrawEventArgs e)
: base(e.Graphics2D)
{
ZBuffered = zBuffered;
}
}
public static class MaterialRendering
{
public static void RenderCylinderOutline(this WorldView world, Matrix4X4 worldMatrix, Vector3 center, double Diameter, double Height, int sides, Color color, double lineWidth = 1, double extendLineLength = 0)
{
GLHelper.PrepareFor3DLineRender(true);
Frustum frustum = world.GetClippingFrustum();
for (int i = 0; i < sides; i++)
{
var rotatedPoint = new Vector3(Math.Cos(MathHelper.Tau * i / sides), Math.Sin(MathHelper.Tau * i / sides), 0) * Diameter / 2;
var sideTop = Vector3Ex.Transform(center + rotatedPoint + new Vector3(0, 0, Height / 2), worldMatrix);
var sideBottom = Vector3Ex.Transform(center + rotatedPoint + new Vector3(0, 0, -Height / 2), worldMatrix);
var rotated2Point = new Vector3(Math.Cos(MathHelper.Tau * (i + 1) / sides), Math.Sin(MathHelper.Tau * (i + 1) / sides), 0) * Diameter / 2;
var topStart = sideTop;
var topEnd = Vector3Ex.Transform(center + rotated2Point + new Vector3(0, 0, Height / 2), worldMatrix);
var bottomStart = sideBottom;
var bottomEnd = Vector3Ex.Transform(center + rotated2Point + new Vector3(0, 0, -Height / 2), worldMatrix);
if (extendLineLength > 0)
{
GLHelper.ExtendLineEnds(ref sideTop, ref sideBottom, extendLineLength);
}
world.Render3DLineNoPrep(frustum, sideTop, sideBottom, color, lineWidth);
world.Render3DLineNoPrep(frustum, topStart, topEnd, color, lineWidth);
world.Render3DLineNoPrep(frustum, bottomStart, bottomEnd, color, lineWidth);
}
// turn the lighting back on
GL.Enable(EnableCap.Lighting);
}
public static void RenderAabb(this WorldView world, AxisAlignedBoundingBox bounds, Matrix4X4 matrix, Color color, double width, double extendLineLength = 0)
{
GLHelper.PrepareFor3DLineRender(true);
Frustum frustum = world.GetClippingFrustum();
for (int i = 0; i < 4; i++)
{
Vector3 sideStartPosition = Vector3Ex.Transform(bounds.GetBottomCorner(i), matrix);
Vector3 sideEndPosition = Vector3Ex.Transform(bounds.GetTopCorner(i), matrix);
Vector3 bottomStartPosition = sideStartPosition;
Vector3 bottomEndPosition = Vector3Ex.Transform(bounds.GetBottomCorner((i + 1) % 4), matrix);
Vector3 topStartPosition = sideEndPosition;
Vector3 topEndPosition = Vector3Ex.Transform(bounds.GetTopCorner((i + 1) % 4), matrix);
if (extendLineLength > 0)
{
GLHelper.ExtendLineEnds(ref sideStartPosition, ref sideEndPosition, extendLineLength);
GLHelper.ExtendLineEnds(ref topStartPosition, ref topEndPosition, extendLineLength);
GLHelper.ExtendLineEnds(ref bottomStartPosition, ref bottomEndPosition, extendLineLength);
}
// draw each of the edge lines (4) and their touching top and bottom lines (2 each)
world.Render3DLineNoPrep(frustum, sideStartPosition, sideEndPosition, color, width);
world.Render3DLineNoPrep(frustum, topStartPosition, topEndPosition, color, width);
world.Render3DLineNoPrep(frustum, bottomStartPosition, bottomEndPosition, color, width);
}
GL.Enable(EnableCap.Lighting);
}
public static void RenderAxis(this WorldView world, Vector3 position, Matrix4X4 matrix, double size, double lineWidth)
{
GLHelper.PrepareFor3DLineRender(true);
Frustum frustum = world.GetClippingFrustum();
Vector3 length = Vector3.One * size;
for (int i = 0; i < 3; i++)
{
var min = position;
min[i] -= length[i];
Vector3 start = Vector3Ex.Transform(min, matrix);
var max = position;
max[i] += length[i];
Vector3 end = Vector3Ex.Transform(max, matrix);
var color = Agg.Color.Red;
switch (i)
{
case 1:
color = Agg.Color.Green;
break;
case 2:
color = Agg.Color.Blue;
break;
}
// draw each of the edge lines (4) and their touching top and bottom lines (2 each)
world.Render3DLineNoPrep(frustum, start, end, color, lineWidth);
}
GL.Enable(EnableCap.Lighting);
}
public static void RenderDirectionAxis(this WorldView world, DirectionAxis axis, Matrix4X4 matrix, double size)
{
GLHelper.PrepareFor3DLineRender(true);
Frustum frustum = world.GetClippingFrustum();
Vector3 length = axis.Normal * size;
var color = Agg.Color.Red;
// draw center line
{
var min = axis.Origin - length;
Vector3 start = Vector3Ex.Transform(min, matrix);
var max = axis.Origin + length;
Vector3 end = Vector3Ex.Transform(max, matrix);
world.Render3DLineNoPrep(frustum, start, end, color, 1);
}
var perpendicular = Vector3.GetPerpendicular(axis.Normal, Vector3.Zero).GetNormal();
// draw some lines to mark the rotation plane
int count = 20;
bool first = true;
var firstEnd = Vector3.Zero;
var lastEnd = Vector3.Zero;
var center = Vector3Ex.Transform(axis.Origin, matrix);
for (int i = 0; i < count; i++)
{
var rotation = size/4 * Vector3Ex.Transform(perpendicular, Matrix4X4.CreateRotation(axis.Normal, MathHelper.Tau * i / count));
// draw center line
var max = axis.Origin + rotation;
Vector3 end = Vector3Ex.Transform(max, matrix);
world.Render3DLineNoPrep(frustum, center, end, color, 1);
if (!first)
{
world.Render3DLineNoPrep(frustum, end, lastEnd, color, 1);
}
else
{
firstEnd = end;
}
lastEnd = end;
first = false;
}
world.Render3DLineNoPrep(frustum, firstEnd, lastEnd, color, 1);
GL.Enable(EnableCap.Lighting);
}
/// <summary>
/// Get the color for a given extruder, falling back to extruder 0 color on -1 (unassigned)
/// </summary>
/// <param name="materialIndex">The extruder/material index to resolve</param>
/// <returns>The color for the given extruder</returns>
public static Color Color(int materialIndex)
{
return ColorF.FromHSL(Math.Max(materialIndex, 0) / 10.0, .99, .49).ToColor();
}
/// <summary>
/// Get the color for a given extruder, falling back to the supplied color on -1 (unassigned)
/// </summary>
/// <param name="materialIndex">The extruder/material index to resolve</param>
/// <param name="unassignedColor">The color to use when the extruder/material has not been assigned</param>
/// <returns>The color for the given extruder</returns>
public static Color Color(int materialIndex, Color unassignedColor)
{
return (materialIndex == -1) ? unassignedColor : ColorF.FromHSL(materialIndex / 10.0, .99, .49).ToColor();
}
}
public class MeshViewerWidget : GuiWidget
{
private static ImageBuffer ViewOnlyTexture;
@ -442,11 +260,6 @@ namespace MatterHackers.MeshVisualizer
return base.FindDescendants(namesToSearchFor, foundChildren, touchingBounds, seachType, allowInvalidItems);
}
public static Color GetExtruderColor(int extruderIndex)
{
return MaterialRendering.Color(extruderIndex);
}
public void CreateGlDataObject(IObject3D item)
{
if(item.Mesh != null)
@ -763,6 +576,7 @@ namespace MatterHackers.MeshVisualizer
wireColor = lightWireframe;
break;
}
// Draw transparent objects
foreach (var item in transparentMeshes)
{
@ -816,7 +630,6 @@ namespace MatterHackers.MeshVisualizer
{
var bedColor = theme.ResolveColor(Color.White, theme.BackgroundColor.WithAlpha(111));
if (!lookingDownOnBed)
{
bedColor = new Color(bedColor, bedColor.alpha / 4);

View file

@ -1,5 +1,5 @@
/*
Copyright (c) 2018, Lars Brubaker, John Lewin
Copyright (c) 2019, Lars Brubaker, John Lewin
All rights reserved.
Redistribution and use in source and binary forms, with or without
@ -37,7 +37,6 @@ using MatterHackers.Localizations;
using MatterHackers.MatterControl.CustomWidgets;
using MatterHackers.MatterControl.Library;
using MatterHackers.MatterControl.SlicerConfiguration;
using MatterHackers.MeshVisualizer;
using MatterHackers.VectorMath;
namespace MatterHackers.MatterControl.PartPreviewWindow
@ -74,13 +73,13 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
allUiFields.Clear();
var column = new FlowLayoutWidget(FlowDirection.TopToBottom)
var printPanel = new FlowLayoutWidget(FlowDirection.TopToBottom)
{
Padding = theme.DefaultContainerPadding,
BackgroundColor = menuTheme.BackgroundColor
};
column.AddChild(new TextWidget("Options".Localize(), textColor: menuTheme.TextColor)
printPanel.AddChild(new TextWidget("Options".Localize(), textColor: menuTheme.TextColor)
{
HAnchor = HAnchor.Left
});
@ -94,7 +93,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
MinimumSize = new Vector2(400, 65),
Margin = new BorderDouble(top: 10),
};
column.AddChild(optionsPanel);
printPanel.AddChild(optionsPanel);
foreach (var key in new[] { SettingsKey.layer_height, SettingsKey.fill_density, SettingsKey.create_raft })
{
@ -118,14 +117,14 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
anySettingOverridden |= printer.Settings.GetValue<bool>(SettingsKey.spiral_vase);
anySettingOverridden |= !string.IsNullOrWhiteSpace(printer.Settings.GetValue(SettingsKey.layer_to_pause));
var sectionWidget = new SectionWidget("Advanced", subPanel, menuTheme, expanded: anySettingOverridden)
var sectionWidget = new SectionWidget("Advanced".Localize(), subPanel, menuTheme, expanded: anySettingOverridden)
{
Name = "Advanced Section",
HAnchor = HAnchor.Stretch,
VAnchor = VAnchor.Fit,
Margin = 0
};
column.AddChild(sectionWidget);
printPanel.AddChild(sectionWidget);
foreach (var key in new[] { SettingsKey.spiral_vase, SettingsKey.layer_to_pause })
{
@ -154,39 +153,22 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
var printerReadyToTakeCommands = printer.Connection.CommunicationState == PrinterCommunication.CommunicationStates.FinishedPrint
|| printer.Connection.CommunicationState == PrinterCommunication.CommunicationStates.Connected;
var printerIsConnected = printer.Connection.CommunicationState != PrinterCommunication.CommunicationStates.Disconnected;
var printerNeedsToRunSetup = ApplicationController.PrinterNeedsToRunSetup(printer);
// add the start print button
var setupRow = new FlowLayoutWidget()
{
HAnchor = HAnchor.Stretch
};
var printingMessage = "";
// Perform validation before popup
var errors = printer.Validate();
if (!printerIsConnected)
{
printingMessage = "Need to connect before printing".Localize();
}
else if(printerNeedsToRunSetup)
{
printingMessage = "Setup needs to be run before printing".Localize();
}
if (!string.IsNullOrEmpty(printingMessage))
{
setupRow.AddChild(new TextWidget(printingMessage, textColor: menuTheme.TextColor)
{
VAnchor = VAnchor.Center,
AutoExpandBoundsToText = true,
});
}
// Enable print option when no validation Errors exists
var printEnabled = !errors.Any(err => err.ErrorLevel == ValidationErrorLevel.Error);
var startPrintButton = new TextButton("Start Print".Localize(), menuTheme)
{
Name = "Start Print Button",
Enabled = printerIsConnected && !printerNeedsToRunSetup
Enabled = printEnabled
};
startPrintButton.Click += (s, e) =>
@ -212,47 +194,80 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
this.CloseMenu();
};
var hasErrors = errors.Any(e => e.ErrorLevel == ValidationErrorLevel.Error);
var hasErrorsOrWarnings = errors.Any();
if (hasErrorsOrWarnings)
{
string label = hasErrors ? "Action Required".Localize() : "Action Recommended".Localize();
setupRow.AddChild(new TextWidget(label, textColor: (hasErrors ? Color.Red : theme.PrimaryAccentColor), pointSize: theme.DefaultFontSize)
{
VAnchor = VAnchor.Bottom,
AutoExpandBoundsToText = true,
});
}
setupRow.AddChild(new HorizontalSpacer());
setupRow.AddChild(startPrintButton);
column.AddChild(setupRow);
printPanel.AddChild(setupRow);
if (!printerNeedsToRunSetup)
if (printEnabled)
{
theme.ApplyPrimaryActionStyle(startPrintButton);
}
// put in setup if needed
if (printerNeedsToRunSetup && printerIsConnected)
else
{
// add the finish setup button
var finishSetupButton = new TextButton("Setup...".Localize(), theme)
{
Name = "Finish Setup Button",
ToolTipText = "Run setup configuration for printer.".Localize(),
Margin = theme.ButtonSpacing,
Enabled = printerReadyToTakeCommands,
HAnchor = HAnchor.Right,
VAnchor = VAnchor.Absolute,
};
theme.ApplyPrimaryActionStyle(finishSetupButton);
finishSetupButton.Click += (s, e) =>
{
UiThread.RunOnIdle(async () =>
{
await ApplicationController.Instance.PrintPart(
printer.Bed.EditContext,
printer,
null,
CancellationToken.None);
});
this.CloseMenu();
};
column.AddChild(finishSetupButton);
startPrintButton.BackgroundColor = theme.MinimalShade;
}
return column;
if (hasErrorsOrWarnings)
{
var errorsPanel = new ValidationErrorsPanel(errors, menuTheme);
// Conditional layout for right or bottom errors panel alignment
var layoutStyle = FlowDirection.TopToBottom;
//var layoutStyle = FlowDirection.LeftToRight;
if (layoutStyle == FlowDirection.LeftToRight)
{
errorsPanel.HAnchor = HAnchor.Absolute;
errorsPanel.VAnchor = VAnchor.Fit | VAnchor.Top;
errorsPanel.BackgroundColor = theme.ResolveColor(menuTheme.BackgroundColor, theme.PrimaryAccentColor.WithAlpha(30));
errorsPanel.Width = 350;
errorsPanel.Load += (s, e) =>
{
errorsPanel.Parent.BackgroundColor = Color.Transparent;
};
}
else
{
errorsPanel.HAnchor = HAnchor.Stretch;
errorsPanel.VAnchor = VAnchor.Fit;
errorsPanel.Margin = 3;
}
// Instead of the typical case where the print panel is returned, wrap and append validation errors panel
var errorsContainer = new FlowLayoutWidget(layoutStyle)
{
HAnchor = HAnchor.Fit,
VAnchor = VAnchor.Fit,
BackgroundColor = layoutStyle == FlowDirection.TopToBottom ? printPanel.BackgroundColor : Color.Transparent
};
// Clear bottom padding
printPanel.Padding = printPanel.Padding.Clone(bottom: 2);
errorsContainer.AddChild(printPanel);
errorsContainer.AddChild(errorsPanel);
return errorsContainer;
}
return printPanel;
};
this.AddChild(new TextButton("Print".Localize(), theme)

View file

@ -103,7 +103,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
if (doSlicing)
{
var errors = printer.ValidateSettings();
if (errors.Count > 0)
if (errors.Any(e => e.ErrorLevel == ValidationErrorLevel.Error))
{
doSlicing = false;
ApplicationController.Instance.ShowValidationErrors("Slicing Error".Localize(), errors);

View file

@ -0,0 +1,113 @@
/*
Copyright (c) 2019, Lars Brubaker, John Lewin
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
The views and conclusions contained in the software and documentation are those
of the authors and should not be interpreted as representing official policies,
either expressed or implied, of the FreeBSD Project.
*/
using System.Collections.Generic;
using System.Linq;
using MatterHackers.Agg;
using MatterHackers.Agg.Platform;
using MatterHackers.Agg.UI;
using MatterHackers.Localizations;
using MatterHackers.MatterControl.CustomWidgets;
namespace MatterHackers.MatterControl.PartPreviewWindow
{
public class ValidationErrorsPanel : FlowLayoutWidget
{
public ValidationErrorsPanel(IEnumerable<ValidationError> errors, ThemeConfig theme)
: base (FlowDirection.TopToBottom)
{
this.HAnchor = HAnchor.Absolute;
this.VAnchor = VAnchor.Fit | VAnchor;
this.BackgroundColor = theme.ResolveColor(theme.BackgroundColor, theme.PrimaryAccentColor.WithAlpha(30));
var errorImage = AggContext.StaticData.LoadIcon("SettingsGroupError_16x.png", 16, 16, theme.InvertIcons);
var warningImage = AggContext.StaticData.LoadIcon("SettingsGroupWarning_16x.png", 16, 16, theme.InvertIcons);
var infoImage = AggContext.StaticData.LoadIcon("StatusInfoTip_16x.png", 16, 16);
var fixIcon = AggContext.StaticData.LoadIcon("noun_1306.png", 16, 16, theme.InvertIcons);
foreach (var validationError in errors.OrderByDescending(e => e.ErrorLevel))
{
string errorText, errorDetails;
var settingsValidationError = validationError as SettingsValidationError;
if (settingsValidationError != null)
{
errorText = string.Format(
"{0} {1}",
settingsValidationError.PresentationName,
validationError.ErrorLevel == ValidationErrorLevel.Error ? "Error".Localize() : "Warning".Localize());
errorDetails = validationError.Error;
}
else
{
errorText = validationError.Error;
errorDetails = validationError.Details ?? "";
}
var row = new SettingsRow(errorText, errorDetails, theme, validationError.ErrorLevel == ValidationErrorLevel.Error ? errorImage : warningImage)
{
ArrowDirection = ArrowDirection.Left
};
if (validationError.FixAction is NamedAction action)
{
// Show fix button
var button = new IconButton(fixIcon, theme)
{
ToolTipText = action.Title
};
if (!string.IsNullOrEmpty(action.ID))
{
button.Name = action.ID;
}
button.Click += (s, e) =>
{
action.Action.Invoke();
};
row.AddChild(button);
}
else
{
// Show info indicator hinting that hover will reveal additional details
var button = new IconButton(infoImage, theme)
{
Selectable = false
};
row.AddChild(button);
}
this.AddChild(row);
}
}
}
}

View file

@ -73,7 +73,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
var selectedItem = scene.SelectedItem;
if (selectedItem != null)
{
if(selectedItem.CanFlatten)
if (selectedItem.CanFlatten)
{
selectedItem.Flatten(scene.UndoBuffer);
scene.SelectedItem = null;
@ -102,30 +102,10 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
scene.SelectedItem = null;
progressStatus.Status = "Copy".Localize();
reporter.Report(progressStatus);
var ungroupMesh = selectedItem.Mesh.Copy(cancellationToken, (progress0To1, processingState) =>
{
progressStatus.Progress0To1 = progress0To1 * .2;
progressStatus.Status = processingState;
reporter.Report(progressStatus);
});
if(cancellationToken.IsCancellationRequested)
{
return Task.CompletedTask;
}
progressStatus.Status = "Clean".Localize();
reporter.Report(progressStatus);
if (cancellationToken.IsCancellationRequested)
{
return Task.CompletedTask;
}
using (selectedItem.RebuildLock())
{
selectedItem.Mesh = ungroupMesh;
}
// try to cut it up into multiple meshes
progressStatus.Status = "Split".Localize();
var discreetMeshes = CreateDiscreteMeshes.SplitVolumesIntoMeshes(ungroupMesh, cancellationToken, (double progress0To1, string processingState) =>
var discreetMeshes = CreateDiscreteMeshes.SplitVolumesIntoMeshes(selectedItem.Mesh, cancellationToken, (double progress0To1, string processingState) =>
{
progressStatus.Progress0To1 = .5 + progress0To1 * .5;
progressStatus.Status = processingState;
@ -150,14 +130,14 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
Mesh = mesh,
}));
foreach(var item in addItems)
foreach (var item in addItems)
{
item.CopyProperties(selectedItem, Object3DPropertyFlags.All);
item.Visible = true;
}
// add and do the undo data
scene.UndoBuffer.AddAndDo(new ReplaceCommand(new List<IObject3D> { selectedItem }, addItems));
scene.UndoBuffer.AddAndDo(new ReplaceCommand(new[] { selectedItem }, addItems));
foreach (var item in addItems)
{
@ -266,7 +246,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
// the selection is a group of objects that need to be copied
var copyList = sourceItem.Children.ToList();
scene.SelectedItem = null;
foreach(var item in copyList)
foreach (var item in copyList)
{
var clonedItem = item.Clone();
clonedItem.Translate(xOffset);
@ -348,6 +328,8 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
public static void MakeLowestFaceFlat(this InteractiveScene scene, IObject3D objectToLayFlatGroup)
{
var preLayFlatMatrix = objectToLayFlatGroup.Matrix;
bool firstVertex = true;
IObject3D objectToLayFlat = objectToLayFlatGroup;
@ -398,39 +380,53 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
}
int faceToLayFlat = -1;
double lowestAngleOfAnyFace = double.MaxValue;
double largestAreaOfAnyFace = 0;
var facesSharingLowestVertex = meshWithLowest.Faces
.Select((face, i) => new { face, i })
.Where(faceAndIndex => meshWithLowest.Vertices[faceAndIndex.face.v0] == sourceVertexPosition
|| meshWithLowest.Vertices[faceAndIndex.face.v1] == sourceVertexPosition
|| meshWithLowest.Vertices[faceAndIndex.face.v2] == sourceVertexPosition)
.Select(j => j.i);
var lowestFacesByAngle = facesSharingLowestVertex.OrderBy(i =>
{
var face = meshWithLowest.Faces[i];
var worldNormal = face.normal.TransformNormal(itemToLayFlat.WorldMatrix());
return worldNormal.CalculateAngle(-Vector3Float.UnitZ);
});
// Check all the faces that are connected to the lowest point to find out which one to lay flat.
for (int faceIndex=0; faceIndex<meshWithLowest.Faces.Count; faceIndex++)
foreach (var faceIndex in lowestFacesByAngle)
{
var face = meshWithLowest.Faces[faceIndex];
if (meshWithLowest.Vertices[face.v0] != sourceVertexPosition
&& meshWithLowest.Vertices[face.v1] != sourceVertexPosition
&& meshWithLowest.Vertices[face.v2] != sourceVertexPosition)
{
// this face does not contain the vertex
continue;
}
double biggestAngleToFaceVertex = double.MinValue;
var faceIndices = new int[] { face.v0, face.v1, face.v2 };
foreach (var vi in faceIndices)
var worldNormal = face.normal.TransformNormal(itemToLayFlat.WorldMatrix());
var worldAngleDegrees = MathHelper.RadiansToDegrees(worldNormal.CalculateAngle(-Vector3Float.UnitZ));
double largestAreaFound = 0;
var faceVeretexIndices = new int[] { face.v0, face.v1, face.v2 };
foreach (var vi in faceVeretexIndices)
{
if (meshWithLowest.Vertices[vi] != lowestPosition)
{
var faceVertexPosition = meshWithLowest.Vertices[vi].Transform(itemToLayFlat.WorldMatrix());
var pointRelLowest = faceVertexPosition - lowestPosition;
double xLeg = new Vector2(pointRelLowest.X, pointRelLowest.Y).Length;
double yLeg = pointRelLowest.Z;
double angle = Math.Atan2(yLeg, xLeg);
if (angle > biggestAngleToFaceVertex)
var planSurfaceArea = 0.0;
foreach (var coPlanarFace in meshWithLowest.GetCoplanerFaces(faceIndex))
{
biggestAngleToFaceVertex = angle;
planSurfaceArea += meshWithLowest.GetSurfaceArea(coPlanarFace);
}
if (largestAreaOfAnyFace == 0
|| (planSurfaceArea > largestAreaFound
&& worldAngleDegrees < 45))
{
largestAreaFound = planSurfaceArea;
}
}
}
if (biggestAngleToFaceVertex < lowestAngleOfAnyFace)
if (largestAreaFound > largestAreaOfAnyFace)
{
lowestAngleOfAnyFace = biggestAngleToFaceVertex;
largestAreaOfAnyFace = largestAreaFound;
faceToLayFlat = faceIndex;
}
}
@ -461,6 +457,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
}
PlatingHelper.PlaceOnBed(objectToLayFlatGroup);
scene.UndoBuffer.Add(new TransformCommand(objectToLayFlatGroup, preLayFlatMatrix, objectToLayFlatGroup.Matrix));
}
internal class ArrangeUndoCommand : IUndoRedoCommand

View file

@ -36,66 +36,58 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
{
public class DeleteCommand : IUndoRedoCommand
{
private List<IObject3D> items = new List<IObject3D>();
private List<(IObject3D parent, IObject3D item)> items = new List<(IObject3D parent, IObject3D item)>();
private InteractiveScene scene;
public DeleteCommand(InteractiveScene scene, IObject3D deletingItem)
{
this.scene = scene;
if (deletingItem is SelectionGroupObject3D)
{
var childrenToAdd = deletingItem.Children;
// push whatever happened to the selection into the objects before saving them
scene.ClearSelection();
// save them in our list
foreach (var item in childrenToAdd)
{
items.Add(item);
}
SetDeletionObjects(scene, deletingItem.Children);
}
else
{
this.items.Add(deletingItem);
SetDeletionObjects(scene, new IObject3D[] { deletingItem });
}
}
public DeleteCommand(InteractiveScene scene, IEnumerable<IObject3D> deletingItems)
{
SetDeletionObjects(scene, deletingItems);
}
private void SetDeletionObjects(InteractiveScene scene, IEnumerable<IObject3D> deletingItems)
{
this.scene = scene;
scene.ClearSelection();
// save them in our list
foreach (var item in deletingItems)
{
items.Add((item.Parent, item));
}
}
public void Do()
{
scene.ClearSelection();
scene.Children.Modify(list =>
using (new SelectionMaintainer(scene))
{
foreach (var item in items)
foreach(var item in items)
{
list.Remove(item);
item.parent.Children.Remove(item.item);
}
});
scene.SelectLastChild();
scene.Invalidate(new InvalidateArgs(null, InvalidateType.Content));
}
}
public void Undo()
{
scene.Children.Modify(list =>
using (new SelectionMaintainer(scene))
{
foreach (var item in items)
{
list.Add(item);
item.parent.Children.Add(item.item);
}
});
scene.ClearSelection();
foreach (var item in items)
{
scene.AddToSelection(item);
}
scene.Invalidate(new InvalidateArgs(null, InvalidateType.Content));
}
}
}

View file

@ -38,18 +38,20 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
{
private IEnumerable<IObject3D> items;
private InteractiveScene scene;
private bool selectAfterInsert;
bool firstPass = true;
public InsertCommand(InteractiveScene scene, IObject3D insertingItem)
: this(scene, new IObject3D[] { insertingItem })
public InsertCommand(InteractiveScene scene, IObject3D insertingItem, bool selectAfterInsert = true)
: this(scene, new IObject3D[] { insertingItem }, selectAfterInsert)
{
}
public InsertCommand(InteractiveScene scene, IEnumerable<IObject3D> insertingItem)
public InsertCommand(InteractiveScene scene, IEnumerable<IObject3D> insertingItem, bool selectAfterInsert = true)
{
this.scene = scene;
this.items = insertingItem;
this.selectAfterInsert = selectAfterInsert;
}
public void Do()
@ -62,12 +64,15 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
scene.Children.Modify(list => list.AddRange(items));
scene.SelectedItem = null;
foreach(var item in items)
if (selectAfterInsert)
{
scene.AddToSelection(item);
foreach (var item in items)
{
scene.AddToSelection(item);
}
}
scene.Invalidate(new InvalidateArgs(null, InvalidateType.Content));
scene.Invalidate(new InvalidateArgs(null, InvalidateType.Children));
}
public void Undo()
@ -86,7 +91,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
scene.SelectedItem = null;
}
scene.Invalidate(new InvalidateArgs(null, InvalidateType.Content));
scene.Invalidate(new InvalidateArgs(null, InvalidateType.Children));
}
}
}

View file

@ -68,7 +68,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
});
scene.SelectLastChild();
scene.Invalidate(new InvalidateArgs(null, InvalidateType.Content));
scene.Invalidate(new InvalidateArgs(null, InvalidateType.Children));
}
public void Undo()
@ -93,7 +93,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
});
scene.SelectLastChild();
scene.Invalidate(new InvalidateArgs(null, InvalidateType.Content));
scene.Invalidate(new InvalidateArgs(null, InvalidateType.Children));
}
}
}

View file

@ -238,8 +238,8 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
SplitterSize = theme.SplitterWidth,
SplitterBackground = theme.SplitterBackground
};
historyAndProperties.Panel1.MinimumSize = new Vector2(0, 120);
historyAndProperties.Panel2.MinimumSize = new Vector2(0, 120);
historyAndProperties.Panel1.MinimumSize = new Vector2(0, 60);
historyAndProperties.Panel2.MinimumSize = new Vector2(0, 60);
modelViewSidePanel.AddChild(historyAndProperties);
@ -382,6 +382,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
private void RebuildTree()
{
rebuildTreePending = false;
workspaceName.Text = sceneContext.Scene.Name ?? "";
// Top level selection only - rebuild tree
@ -391,7 +392,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
foreach (var child in sceneContext.Scene.Children)
{
if (child.GetType().IsDefined(typeof(HideFromTreeViewAttribute), false))
if (child is GeneratedSupportObject3D)
{
continue;
}
@ -416,202 +417,141 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
{
bool invertIcons = ApplicationController.Instance.MenuTheme.InvertIcons;
return new Dictionary<string, NamedAction>()
// Build workspace actions, each having a unique ID
var actions = new []
{
new NamedAction()
{
"Insert",
new NamedAction()
ID = "Print",
Title = "Print".Localize(),
Shortcut = "Ctrl+P",
Action = this.PushToPrinterAndPrint,
IsEnabled = () => sceneContext.EditableScene
|| (sceneContext.EditContext.SourceItem is ILibraryAsset libraryAsset
&& string.Equals(Path.GetExtension(libraryAsset.FileName) ,".gcode" ,StringComparison.OrdinalIgnoreCase))
},
new NamedAction()
{
ID = "Cut",
Title = "Cut".Localize(),
Shortcut = "Ctrl+X",
Action = () =>
{
ID = "Insert",
Title = "Insert".Localize(),
Icon = AggContext.StaticData.LoadIcon("cube.png", 16, 16, invertIcons),
Action = () =>
{
var extensionsWithoutPeriod = new HashSet<string>(ApplicationSettings.OpenDesignFileParams.Split('|').First().Split(',').Select(s => s.Trim().Trim('.')));
foreach(var extension in ApplicationController.Instance.Library.ContentProviders.Keys)
{
extensionsWithoutPeriod.Add(extension.ToUpper());
}
var extensionsArray = extensionsWithoutPeriod.OrderBy(t => t).ToArray();
string filter = string.Format(
"{0}|{1}",
string.Join(",", extensionsArray),
string.Join("", extensionsArray.Select(e => $"*.{e.ToLower()};").ToArray()));
UiThread.RunOnIdle(() =>
{
AggContext.FileDialogs.OpenFileDialog(
new OpenFileDialogParams(filter, multiSelect: true),
(openParams) =>
sceneContext.Scene.Cut();
},
IsEnabled = () => sceneContext.Scene.SelectedItem != null
},
new NamedAction()
{
ID = "Copy",
Title = "Copy".Localize(),
Shortcut = "Ctrl+C",
Action = () =>
{
sceneContext.Scene.Copy();
},
IsEnabled = () => sceneContext.Scene.SelectedItem != null
},
new NamedAction()
{
ID = "Paste",
Title = "Paste".Localize(),
Shortcut = "Ctrl+V",
Action = () =>
{
sceneContext.Paste();
},
IsEnabled = () => Clipboard.Instance.ContainsImage || Clipboard.Instance.GetText() == "!--IObjectSelection--!"
},
new NamedAction()
{
ID = "Delete",
Icon = AggContext.StaticData.LoadIcon("remove.png").SetPreMultiply(),
Title = "Remove".Localize(),
Action = sceneContext.Scene.DeleteSelection,
IsEnabled = () => sceneContext.Scene.SelectedItem != null
},
new NamedAction()
{
ID = "Export",
Title = "Export".Localize(),
Icon = AggContext.StaticData.LoadIcon("cube_export.png", 16, 16, invertIcons),
Action = () =>
{
ApplicationController.Instance.ExportLibraryItems(
new[] { new InMemoryLibraryItem(sceneContext.Scene)},
centerOnBed: false,
printer: printer);
},
IsEnabled = () => sceneContext.EditableScene
|| (sceneContext.EditContext.SourceItem is ILibraryAsset libraryAsset
&& string.Equals(Path.GetExtension(libraryAsset.FileName) ,".gcode" ,StringComparison.OrdinalIgnoreCase))
},
new NamedAction()
{
ID = "Save",
Title = "Save".Localize(),
Shortcut = "Ctrl+S",
Action = () =>
{
ApplicationController.Instance.Tasks.Execute("Saving".Localize(), printer, sceneContext.SaveChanges).ConfigureAwait(false);
},
IsEnabled = () => sceneContext.EditableScene
},
new NamedAction()
{
ID = "SaveAs",
Title = "Save As".Localize(),
Action = () => UiThread.RunOnIdle(() =>
{
DialogWindow.Show(
new SaveAsPage(
async (newName, destinationContainer) =>
{
// Save to the destination provider
if (destinationContainer is ILibraryWritableContainer writableContainer)
{
ViewControls3D.LoadAndAddPartsToPlate(this, openParams.FileNames, sceneContext);
});
});
}
}
},
{
"Print",
new NamedAction()
{
ID = "Print",
Title = "Print".Localize(),
Shortcut = "Ctrl+P",
Action = this.PushToPrinterAndPrint,
IsEnabled = () => sceneContext.EditableScene
|| (sceneContext.EditContext.SourceItem is ILibraryAsset libraryAsset
&& string.Equals(Path.GetExtension(libraryAsset.FileName) ,".gcode" ,StringComparison.OrdinalIgnoreCase))
}
},
{
"Cut",
new NamedAction()
{
ID = "Cut",
Title = "Cut".Localize(),
Shortcut = "Ctrl+X",
Action = () =>
{
sceneContext.Scene.Cut();
},
IsEnabled = () => sceneContext.Scene.SelectedItem != null
}
},
{
"Copy",
new NamedAction()
{
ID = "Copy",
Title = "Copy".Localize(),
Shortcut = "Ctrl+C",
Action = () =>
{
sceneContext.Scene.Copy();
},
IsEnabled = () => sceneContext.Scene.SelectedItem != null
}
},
{
"Paste",
new NamedAction()
{
ID = "Paste",
Title = "Paste".Localize(),
Shortcut = "Ctrl+V",
Action = () =>
{
sceneContext.Paste();
},
IsEnabled = () => Clipboard.Instance.ContainsImage || Clipboard.Instance.GetText() == "!--IObjectSelection--!"
}
},
{
"Delete",
new NamedAction()
{
ID = "Delete",
Icon = AggContext.StaticData.LoadIcon("remove.png").SetPreMultiply(),
Title = "Remove".Localize(),
Action = sceneContext.Scene.DeleteSelection,
IsEnabled = () => sceneContext.Scene.SelectedItem != null
}
},
{
"Export",
new NamedAction()
{
ID = "Export",
Title = "Export".Localize(),
Icon = AggContext.StaticData.LoadIcon("cube_export.png", 16, 16, invertIcons),
Action = () =>
{
ApplicationController.Instance.ExportLibraryItems(
new[] { new InMemoryLibraryItem(sceneContext.Scene)},
centerOnBed: false,
printer: printer);
},
IsEnabled = () => sceneContext.EditableScene
|| (sceneContext.EditContext.SourceItem is ILibraryAsset libraryAsset
&& string.Equals(Path.GetExtension(libraryAsset.FileName) ,".gcode" ,StringComparison.OrdinalIgnoreCase))
}
},
{
"Save",
new NamedAction()
{
ID = "Save",
Title = "Save".Localize(),
Shortcut = "Ctrl+S",
Action = () =>
{
ApplicationController.Instance.Tasks.Execute("Saving".Localize(), printer, sceneContext.SaveChanges).ConfigureAwait(false);
},
IsEnabled = () => sceneContext.EditableScene
}
},
{
"SaveAs",
new NamedAction()
{
ID = "SaveAs",
Title = "Save As".Localize(),
Action = () => UiThread.RunOnIdle(() =>
{
DialogWindow.Show(
new SaveAsPage(
async (newName, destinationContainer) =>
{
// Save to the destination provider
if (destinationContainer is ILibraryWritableContainer writableContainer)
// Wrap stream with ReadOnlyStream library item and add to container
writableContainer.Add(new[]
{
// Wrap stream with ReadOnlyStream library item and add to container
writableContainer.Add(new[]
new InMemoryLibraryItem(sceneContext.Scene)
{
new InMemoryLibraryItem(sceneContext.Scene)
{
Name = newName
}
});
Name = newName
}
});
destinationContainer.Dispose();
}
}));
}),
IsEnabled = () => sceneContext.EditableScene
}
destinationContainer.Dispose();
}
}));
}),
IsEnabled = () => sceneContext.EditableScene
},
new NamedAction()
{
"ArrangeAll",
new NamedAction()
ID = "ArrangeAll",
Title = "Arrange All Parts".Localize(),
Action = () =>
{
ID = "ArrangeAll",
Title = "Arrange All Parts".Localize(),
Action = () =>
{
sceneContext.Scene.AutoArrangeChildren(this.BedCenter);
},
IsEnabled = () => sceneContext.EditableScene
}
sceneContext.Scene.AutoArrangeChildren(this.BedCenter);
},
IsEnabled = () => sceneContext.EditableScene
},
new NamedAction()
{
"ClearBed",
new NamedAction()
ID = "ClearBed",
Title = "Clear Bed".Localize(),
Action = () =>
{
ID = "ClearBed",
Title = "Clear Bed".Localize(),
Action = () =>
UiThread.RunOnIdle(() =>
{
UiThread.RunOnIdle(() =>
{
this.ClearPlate();
});
}
this.ClearPlate();
});
}
}
};
// Construct dictionary from workspace actions by ID
return actions.ToDictionary(a => a.ID);
}
private void ViewState_ViewModeChanged(object sender, ViewModeChangedEventArgs e)
@ -1068,7 +1008,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
this.deferEditorTillMouseUp = false;
Scene_SelectionChanged(null, null);
Scene.Invalidate(new InvalidateArgs(null, InvalidateType.Content, null));
Scene.Invalidate(new InvalidateArgs(null, InvalidateType.Children));
// Set focus to View3DWidget after drag-drop
UiThread.RunOnIdle(this.Focus);
@ -1881,18 +1821,26 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
// TODO: Consider if we should always allow DragDrop or if we should prevent during printer or other scenarios
private bool AllowDragDrop() => true;
private bool rebuildTreePending = false;
private void Scene_Invalidated(object sender, InvalidateArgs e)
{
if (e.InvalidateType == InvalidateType.Content)
if (e.InvalidateType.HasFlag(InvalidateType.Children)
&& !rebuildTreePending)
{
rebuildTreePending = true;
UiThread.RunOnIdle(this.RebuildTree);
}
if (e.InvalidateType == InvalidateType.Name)
if (e.InvalidateType.HasFlag(InvalidateType.Name))
{
// clear and restore the selection so we have the name change
var lastSelectedItem = Scene.SelectedItem;
UiThread.RunOnIdle(this.RebuildTree);
if (!rebuildTreePending)
{
rebuildTreePending = true;
UiThread.RunOnIdle(this.RebuildTree);
}
Scene.SelectedItem = null;
Scene.SelectedItem = lastSelectedItem;
}

View file

@ -325,7 +325,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
undoButton = new IconButton(AggContext.StaticData.LoadIcon("Undo_grey_16x.png", 16, 16, theme.InvertIcons), theme)
{
Name = "3D View Undo",
ToolTipText = "Undo",
ToolTipText = "Undo".Localize(),
Enabled = false,
Margin = theme.ButtonSpacing,
VAnchor = VAnchor.Center
@ -341,7 +341,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
{
Name = "3D View Redo",
Margin = theme.ButtonSpacing,
ToolTipText = "Redo",
ToolTipText = "Redo".Localize(),
Enabled = false,
VAnchor = VAnchor.Center
};
@ -527,7 +527,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
new OpenFileDialogParams(filter, multiSelect: true),
(openParams) =>
{
ViewControls3D.LoadAndAddPartsToPlate(this, openParams.FileNames, ApplicationController.Instance.DragDropData.SceneContext);
sceneContext.AddToPlate(openParams.FileNames);
});
}, .1);
};
@ -791,117 +791,6 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
return saveButton;
}
public static async void LoadAndAddPartsToPlate(GuiWidget originatingWidget, string[] filesToLoad, BedConfig sceneContext)
{
if (filesToLoad != null && filesToLoad.Length > 0)
{
await Task.Run(() => loadAndAddPartsToPlate(filesToLoad, sceneContext));
if (originatingWidget.HasBeenClosed)
{
return;
}
var scene = sceneContext.Scene;
bool addingOnlyOneItem = scene.Children.Count == scene.Children.Count + 1;
if (scene.HasChildren())
{
if (addingOnlyOneItem)
{
// if we are only adding one part to the plate set the selection to it
scene.SelectLastChild();
}
}
scene.Invalidate(new InvalidateArgs(null, InvalidateType.Content, null));
}
}
private static async Task loadAndAddPartsToPlate(string[] filesToLoadIncludingZips, BedConfig sceneContext)
{
if (filesToLoadIncludingZips?.Any() == true)
{
var scene = sceneContext.Scene;
// When a single GCode file is selected, swap the plate to the new GCode content
if (filesToLoadIncludingZips.Count() == 1
&& filesToLoadIncludingZips.FirstOrDefault() is string firstFilePath
&& Path.GetExtension(firstFilePath).ToUpper() == ".GCODE")
{
// Special case for GCode which changes loaded scene to special mode for GCode
await sceneContext.LoadContent(
new EditContext()
{
SourceItem = new FileSystemFileItem(firstFilePath),
ContentStore = null // No content store for GCode, otherwise PlatingHistory
});
return;
}
var filesToLoad = new List<string>();
foreach (string loadedFileName in filesToLoadIncludingZips)
{
string extension = Path.GetExtension(loadedFileName).ToUpper();
if ((extension != ""
&& extension != ".ZIP"
&& extension != ".GCODE"
&& ApplicationController.Instance.Library.IsContentFileType(loadedFileName))
)
{
filesToLoad.Add(loadedFileName);
}
else if (extension == ".ZIP")
{
List<PrintItem> partFiles = ProjectFileHandler.ImportFromProjectArchive(loadedFileName);
if (partFiles != null)
{
foreach (PrintItem part in partFiles)
{
string itemExtension = Path.GetExtension(part.FileLocation).ToUpper();
if (itemExtension != ".GCODE")
{
filesToLoad.Add(part.FileLocation);
}
}
}
}
}
var itemCache = new Dictionary<string, IObject3D>();
foreach (string filePath in filesToLoad)
{
var libraryItem = new FileSystemFileItem(filePath);
IObject3D object3D = null;
await ApplicationController.Instance.Tasks.Execute("Loading".Localize() + " " + Path.GetFileName(filePath), sceneContext.Printer, async (progressReporter, cancellationToken) =>
{
var progressStatus = new ProgressStatus();
progressReporter.Report(progressStatus);
object3D = await libraryItem.CreateContent((double progress0To1, string processingState) =>
{
progressStatus.Progress0To1 = progress0To1;
progressStatus.Status = processingState;
progressReporter.Report(progressStatus);
});
});
if (object3D != null)
{
scene.Children.Modify(list => list.Add(object3D));
PlatingHelper.MoveToOpenPositionRelativeGroup(object3D, scene.Children);
}
}
}
}
public override void OnClosed(EventArgs e)
{
// Unregister listeners

View file

@ -44,8 +44,6 @@ namespace MatterHackers.MatterControl.PrinterCommunication.Io
{
internal class PositionSensorData
{
public bool RecievingData { get; internal set; }
public double LastSensorDistance { get; internal set; }
public double LastStepperDistance { get; internal set; }
public int ExtrusionDiscrepency { get; internal set; }
@ -86,23 +84,23 @@ namespace MatterHackers.MatterControl.PrinterCommunication.Io
{
if (sensorDistance < -1 || sensorDistance > 1)
{
positionSensorData.RecievingData = true;
printer.Connection.FilamentPositionSensorDetected = true;
}
if (positionSensorData.RecievingData)
if (printer.Connection.FilamentPositionSensorDetected)
{
GCodeFile.GetFirstNumberAfter("STEPPER:", line, ref stepperDistance);
var stepperDelta = Math.Abs(stepperDistance - positionSensorData.LastStepperDistance);
// if we think we should have move the filament by more than 1mm
if (stepperDelta > .2)
if (stepperDelta > 1)
{
var sensorDelta = Math.Abs(sensorDistance - positionSensorData.LastSensorDistance);
// check if the sensor data is within a tolerance of the stepper data
var deltaRatio = sensorDelta / stepperDelta;
if (deltaRatio < .9 || deltaRatio > 1.1)
if (deltaRatio < .5 || deltaRatio > 2)
{
// we have a repartable discrepency set a runout state
positionSensorData.ExtrusionDiscrepency++;

View file

@ -2451,6 +2451,13 @@ You will then need to logout and log back in to the computer for the changes to
set => printLevelingStream6.AllowLeveling = value;
}
/// <summary>
/// This gets set by the Pause Handling Stream when a change in the position sensor is seen.
/// It is improtant that this is not persisted, it is meant to function correctly if the user
/// plugs in or removes a filament position sensor.
/// </summary>
public bool FilamentPositionSensorDetected { get; internal set; }
public void TurnOffBedAndExtruders(TurnOff turnOffTime)
{
if (turnOffTime == TurnOff.Now)

View file

@ -44,6 +44,9 @@ namespace MatterHackers.MatterControl
public const string NotificationEmailAddress = nameof(NotificationEmailAddress);
public const string NotificationPhoneNumber = nameof(NotificationPhoneNumber);
public const string OpenScadPath = nameof(OpenScadPath);
public const string SupportGenerationType = nameof(SupportGenerationType);
public const string SupportMaxOverHangAngle = nameof(SupportMaxOverHangAngle);
public const string SupportPillarSize = nameof(SupportPillarSize);
public const string PopupLibraryWidth = nameof(PopupLibraryWidth);
public const string PrintHistoryFilterShowCompleted = nameof(PrintHistoryFilterShowCompleted);
public const string PrintNotificationsEnabled = nameof(PrintNotificationsEnabled);

View file

@ -137,6 +137,9 @@ namespace MatterHackers.MatterControl
#endif
}
// Add public accessor for content panel
public FlowLayoutWidget ContentRow => contentRow;
public DialogWindow DialogWindow { get; set; }
public string WindowTitle { get; set; }

View file

@ -48,7 +48,11 @@ namespace MatterHackers.MatterControl.SetupWizard
var profile = ProfileManager.Instance[printer.Settings.ID];
// Download the specified json profile
var printerSettings = await ApplicationController.GetPrinterProfileAsync(profile, profileToken);
PrinterSettings printerSettings = null;
if (Application.EnableNetworkTraffic)
{
await ApplicationController.GetPrinterProfileAsync(profile, profileToken);
}
if (printerSettings != null)
{
// Persist downloaded profile

Some files were not shown because too many files have changed in this diff Show more