diff --git a/MatterControlLib/ApplicationView/SceneOperations.cs b/MatterControlLib/ApplicationView/SceneOperations.cs index 8d54683a9..af21920fc 100644 --- a/MatterControlLib/ApplicationView/SceneOperations.cs +++ b/MatterControlLib/ApplicationView/SceneOperations.cs @@ -409,7 +409,7 @@ namespace MatterHackers.MatterControl { var scene = sceneContext.Scene; var sceneItem = scene.SelectedItem; - if (sceneItem is IPathObject imageObject) + if (sceneItem is IPathObject pathObject) { var extrude = new LinearExtrudeObject3D(); @@ -432,6 +432,40 @@ namespace MatterHackers.MatterControl }; } + public static SceneOperation RevolveOperation() + { + return new SceneOperation("Revolve") + { + OperationType = typeof(IPathObject), + TitleResolver = () => "Revolve".Localize(), + ResultType = typeof(RevolveObject3D), + Action = (sceneContext) => + { + var scene = sceneContext.Scene; + var sceneItem = scene.SelectedItem; + if (sceneItem is IPathObject pathObject) + { + var revolve = new RevolveObject3D(); + + var itemClone = sceneItem.Clone(); + revolve.Children.Add(itemClone); + revolve.Matrix = itemClone.Matrix; + itemClone.Matrix = Matrix4X4.Identity; + + using (new SelectionMaintainer(scene)) + { + scene.UndoBuffer.AddAndDo(new ReplaceCommand(new[] { sceneItem }, new[] { revolve })); + } + + revolve.Invalidate(InvalidateType.Properties); + } + }, + Icon = (invertIcon) => AggContext.StaticData.LoadIcon("revolve.png", 16, 16, invertIcon).SetPreMultiply(), + HelpTextResolver = () => "*A path must be selected*".Localize(), + IsEnabled = (sceneContext) => sceneContext.Scene.SelectedItem != null && sceneContext.Scene.SelectedItem is IPathObject, + }; + } + public static SceneOperation MakeComponentOperation() { return new SceneOperation("Make Component") @@ -754,6 +788,7 @@ namespace MatterHackers.MatterControl Operations = new List() { LinearExtrudeOperation(), + RevolveOperation(), SmoothPathOperation(), InflatePathOperation(), OutlinePathOperation(), diff --git a/MatterControlLib/DesignTools/Operations/Image/ImageToPathObject3D.cs b/MatterControlLib/DesignTools/Operations/Image/ImageToPathObject3D.cs index 34cee84db..77b0c4307 100644 --- a/MatterControlLib/DesignTools/Operations/Image/ImageToPathObject3D.cs +++ b/MatterControlLib/DesignTools/Operations/Image/ImageToPathObject3D.cs @@ -51,7 +51,7 @@ using Polygons = System.Collections.Generic.List true; + + [JsonIgnore] + private IVertexSource VertexSource + { + get + { + var item = this.Descendants().Where((d) => d is IPathObject).FirstOrDefault(); + if (item is IPathObject pathItem) + { + return pathItem.VertexSource; + } + + return null; + } + } + + public void AddObject3DControls(Object3DControlsLayer object3DControlsLayer) + { + object3DControlsLayer.AddControls(ControlTypes.Standard2D); + } + + public override void Flatten(UndoBuffer undoBuffer) + { + if (Mesh == null) + { + Remove(undoBuffer); + } + else + { + // only keep the mesh and get rid of everything else + using (RebuildLock()) + { + var meshOnlyItem = new Object3D() + { + Mesh = this.Mesh.Copy(CancellationToken.None) + }; + + meshOnlyItem.CopyProperties(this, Object3DPropertyFlags.All); + + // and replace us with the children + undoBuffer.AddAndDo(new ReplaceCommand(new[] { this }, new[] { meshOnlyItem })); + } + + Invalidate(InvalidateType.Children); + } + } + + public RevolveObject3D() + { + Name = "Revolve".Localize(); + } + + public override async void OnInvalidate(InvalidateArgs eventArgs) + { + if ((eventArgs.InvalidateType.HasFlag(InvalidateType.Path) + || eventArgs.InvalidateType.HasFlag(InvalidateType.Children)) + && eventArgs.Source != this + && !RebuildLocked) + { + await Rebuild(); + } + else if (eventArgs.InvalidateType.HasFlag(InvalidateType.Properties) + && eventArgs.Source == this) + { + await Rebuild(); + } + else + { + base.OnInvalidate(eventArgs); + } + } + + public override Task Rebuild() + { + this.DebugDepth("Rebuild"); + bool valuesChanged = false; + + if (Advanced && (StartingAngle > 0 || EndingAngle < 360)) + { + Sides = agg_basics.Clamp(Sides, 1, 360, ref valuesChanged); + } + else + { + Sides = agg_basics.Clamp(Sides, 3, 360, ref valuesChanged); + } + + StartingAngle = agg_basics.Clamp(StartingAngle, 0, 360 - .01, ref valuesChanged); + EndingAngle = agg_basics.Clamp(EndingAngle, StartingAngle + .01, 360, ref valuesChanged); + + if (valuesChanged) + { + Invalidate(InvalidateType.DisplayValues); + } + + var rebuildLock = RebuildLock(); + // now create a long running task to process the image + return ApplicationController.Instance.Tasks.Execute( + "Revolve".Localize(), + null, + (reporter, cancellationToken) => + { + var vertexSource = this.VertexSource; + var bounds = vertexSource.GetBounds(); + vertexSource = vertexSource.Translate(-bounds.Left - AxisPosition, 0); + if (!Advanced) + { + Mesh = VertexSourceToMesh.Revolve(vertexSource, Sides); + } + else + { + Mesh = VertexSourceToMesh.Revolve(vertexSource, + Sides, + MathHelper.DegreesToRadians(StartingAngle), + MathHelper.DegreesToRadians(EndingAngle)); + } + + if (Mesh.Vertices.Count == 0) + { + Mesh = null; + } + + rebuildLock.Dispose(); + Parent?.Invalidate(new InvalidateArgs(this, InvalidateType.Mesh)); + return Task.CompletedTask; + }); + } + } +} \ No newline at end of file diff --git a/MatterControlLib/DesignTools/Operations/Path/InflatePathObject3D.cs b/MatterControlLib/DesignTools/Operations/Path/InflatePathObject3D.cs index 10d0b9b05..1d491a11d 100644 --- a/MatterControlLib/DesignTools/Operations/Path/InflatePathObject3D.cs +++ b/MatterControlLib/DesignTools/Operations/Path/InflatePathObject3D.cs @@ -48,7 +48,7 @@ namespace MatterHackers.MatterControl.DesignTools.Operations Sharp, } - public class InflatePathObject3D : Object3D, IPathObject, IEditorDraw + public class InflatePathObject3D : Object3D, IPathObject, IEditorDraw, IObject3DControlsProvider { public IVertexSource VertexSource { get; set; } = new VertexStorage(); @@ -63,6 +63,11 @@ namespace MatterHackers.MatterControl.DesignTools.Operations [EnumDisplay(Mode = EnumDisplayAttribute.PresentationMode.Buttons)] public ExpandStyles Style { get; set; } = ExpandStyles.Sharp; + public void AddObject3DControls(Object3DControlsLayer object3DControlsLayer) + { + object3DControlsLayer.AddControls(ControlTypes.Standard2D); + } + public override async void OnInvalidate(InvalidateArgs invalidateType) { if ((invalidateType.InvalidateType.HasFlag(InvalidateType.Children) diff --git a/MatterControlLib/DesignTools/Operations/Path/OutlinePathObject3D.cs b/MatterControlLib/DesignTools/Operations/Path/OutlinePathObject3D.cs index 69fa61984..2d85cf50f 100644 --- a/MatterControlLib/DesignTools/Operations/Path/OutlinePathObject3D.cs +++ b/MatterControlLib/DesignTools/Operations/Path/OutlinePathObject3D.cs @@ -44,7 +44,7 @@ using MatterHackers.MatterControl.PartPreviewWindow; namespace MatterHackers.MatterControl.DesignTools.Operations { - public class OutlinePathObject3D : Object3D, IPathObject, IEditorDraw + public class OutlinePathObject3D : Object3D, IPathObject, IEditorDraw, IObject3DControlsProvider { public IVertexSource VertexSource { get; set; } = new VertexStorage(); @@ -85,6 +85,11 @@ namespace MatterHackers.MatterControl.DesignTools.Operations } } + public void AddObject3DControls(Object3DControlsLayer object3DControlsLayer) + { + object3DControlsLayer.AddControls(ControlTypes.Standard2D); + } + public override Task Rebuild() { this.DebugDepth("Rebuild"); diff --git a/MatterControlLib/DesignTools/Operations/Path/SmoothPathObject3D.cs b/MatterControlLib/DesignTools/Operations/Path/SmoothPathObject3D.cs index f48ec473a..9ce86fe67 100644 --- a/MatterControlLib/DesignTools/Operations/Path/SmoothPathObject3D.cs +++ b/MatterControlLib/DesignTools/Operations/Path/SmoothPathObject3D.cs @@ -43,7 +43,7 @@ using Polygons = System.Collections.Generic.List - /// Add in MoveInZ, SelectionShadow & SnappingIndicators - /// - public void AddDefaultControls() + public void AddControls(ControlTypes controls) { - Object3DControls.Add(new MoveInZControl(this)); - Object3DControls.Add(new SelectionShadow(this)); - Object3DControls.Add(new SnappingIndicators(this)); + if (controls.HasFlag(ControlTypes.RotateXYZ)) + { + Object3DControls.Add(new RotateCornerControl(this, 0)); + Object3DControls.Add(new RotateCornerControl(this, 1)); + Object3DControls.Add(new RotateCornerControl(this, 2)); + } + + if (controls.HasFlag(ControlTypes.RotateZ)) + { + Object3DControls.Add(new RotateCornerControl(this, 2)); + } + + if (controls.HasFlag(ControlTypes.MoveInZ)) + { + Object3DControls.Add(new MoveInZControl(this)); + } + + if (controls.HasFlag(ControlTypes.ScaleMatrixXY)) + { + Object3DControls.Add(new ScaleCornerControl(this, 0)); + Object3DControls.Add(new ScaleCornerControl(this, 1)); + Object3DControls.Add(new ScaleCornerControl(this, 2)); + Object3DControls.Add(new ScaleCornerControl(this, 3)); + } + + if (controls.HasFlag(ControlTypes.Shadow)) + { + Object3DControls.Add(new SelectionShadow(this)); + } + + if (controls.HasFlag(ControlTypes.SnappingIndicators)) + { + Object3DControls.Add(new SnappingIndicators(this)); + } } public void AddWorldRotateControls() { - Object3DControls.Add(new RotateCornerControl(this, 0)); - Object3DControls.Add(new RotateCornerControl(this, 1)); - Object3DControls.Add(new RotateCornerControl(this, 2)); } private void DisposeCurrentSelectionObject3DControls() diff --git a/StaticData/Icons/revolve.png b/StaticData/Icons/revolve.png new file mode 100644 index 000000000..94b69d5af Binary files /dev/null and b/StaticData/Icons/revolve.png differ