Merge branch '2.19.2'
This commit is contained in:
commit
6731fdc5d8
168 changed files with 13231 additions and 7124 deletions
|
|
@ -132,7 +132,7 @@ namespace MatterHackers.MatterControl
|
|||
}
|
||||
else if (AggContext.OperatingSystem == OSType.X11)
|
||||
{
|
||||
return "tar.gz";
|
||||
return "deb";
|
||||
}
|
||||
else if (AggContext.OperatingSystem == OSType.Android)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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];
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
||||
|
|
|
|||
|
|
@ -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; }
|
||||
|
|
|
|||
|
|
@ -212,6 +212,11 @@ namespace MatterHackers.MatterControl.CustomWidgets
|
|||
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return textWidget?.Text ?? "";
|
||||
}
|
||||
|
||||
#region Properties
|
||||
|
||||
public bool Checked { get; set; }
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
@ -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
|
||||
{
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
|
|
|
|||
286
MatterControlLib/DesignTools/OpenSCAD/OpenSCADBuilder.cs
Normal file
286
MatterControlLib/DesignTools/OpenSCAD/OpenSCADBuilder.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
54
MatterControlLib/DesignTools/OpenSCAD/OpenScadObject3D.cs
Normal file
54
MatterControlLib/DesignTools/OpenSCAD/OpenScadObject3D.cs
Normal 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; }
|
||||
}
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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)
|
||||
|
|
|
|||
195
MatterControlLib/DesignTools/Operations/CurveObject3D_2.cs
Normal file
195
MatterControlLib/DesignTools/Operations/CurveObject3D_2.cs
Normal 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;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
114
MatterControlLib/DesignTools/Operations/MirrorObject3D_2.cs
Normal file
114
MatterControlLib/DesignTools/Operations/MirrorObject3D_2.cs
Normal 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;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
117
MatterControlLib/DesignTools/Operations/PinchObject3D_2.cs
Normal file
117
MatterControlLib/DesignTools/Operations/PinchObject3D_2.cs
Normal 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;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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))
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
|
|||
521
MatterControlLib/DesignTools/SupportGenerator.cs
Normal file
521
MatterControlLib/DesignTools/SupportGenerator.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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(),
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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();
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
208
MatterControlLib/PartPreviewWindow/View3D/MaterialRendering.cs
Normal file
208
MatterControlLib/PartPreviewWindow/View3D/MaterialRendering.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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++;
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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; }
|
||||
|
|
|
|||
|
|
@ -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
Loading…
Add table
Add a link
Reference in a new issue