diff --git a/ApplicationView/ApplicationController.cs b/ApplicationView/ApplicationController.cs index d0011eb65..2ce79088e 100644 --- a/ApplicationView/ApplicationController.cs +++ b/ApplicationView/ApplicationController.cs @@ -723,6 +723,23 @@ namespace MatterHackers.MatterControl }, iconCollector: () => AggContext.StaticData.LoadIcon("noun_479927.png", ApplicationController.Instance.MenuTheme.InvertIcons)); + this.Graph.RegisterOperation( + typeof(IObject3D), + "Translate".Localize(), + (sceneItem, scene) => + { + var selectedItem = scene.SelectedItem; + scene.SelectedItem = null; + var translate = TranslateObject3D.Create(selectedItem.Clone()); + translate.MakeNameNonColliding(); + + scene.UndoBuffer.AddAndDo(new ReplaceCommand(new List { selectedItem }, new List { translate })); + scene.SelectedItem = translate; + + return Task.CompletedTask; + }, + iconCollector: () => AggContext.StaticData.LoadIcon(Path.Combine("ViewTransformControls", "translate.png"), ApplicationController.Instance.MenuTheme.InvertIcons)); + this.Graph.RegisterOperation( typeof(IObject3D), "Rotate".Localize(), @@ -738,7 +755,7 @@ namespace MatterHackers.MatterControl return Task.CompletedTask; }, - iconCollector: () => AggContext.StaticData.LoadIcon("icon_rotate_32x32.png", ApplicationController.Instance.MenuTheme.InvertIcons)); + iconCollector: () => AggContext.StaticData.LoadIcon(Path.Combine("ViewTransformControls", "rotate.png"), ApplicationController.Instance.MenuTheme.InvertIcons)); this.Graph.RegisterOperation( typeof(IPathObject), diff --git a/DesignTools/Operations/FitToBoundsObject3D.cs b/DesignTools/Obsolete/FitToBoundsObject3D.cs similarity index 100% rename from DesignTools/Operations/FitToBoundsObject3D.cs rename to DesignTools/Obsolete/FitToBoundsObject3D.cs diff --git a/DesignTools/Operations/RotateObject3D.cs b/DesignTools/Obsolete/RotateObject3D.cs similarity index 97% rename from DesignTools/Operations/RotateObject3D.cs rename to DesignTools/Obsolete/RotateObject3D.cs index 6770ed390..f40341460 100644 --- a/DesignTools/Operations/RotateObject3D.cs +++ b/DesignTools/Obsolete/RotateObject3D.cs @@ -32,10 +32,12 @@ using MatterHackers.DataConverters3D; using MatterHackers.Localizations; using MatterHackers.VectorMath; using Newtonsoft.Json; +using System; using System.ComponentModel; namespace MatterHackers.MatterControl.DesignTools.Operations { + [Obsolete("Not used anymore. Replaced with FitToBoundsObject3D_2", false)] public class RotateObject3D : Object3D { [DisplayName("X")] diff --git a/DesignTools/Operations/FitToBoundsObject3D_2.cs b/DesignTools/Operations/FitToBoundsObject3D_2.cs index 2aab3bd65..bd6a5d158 100644 --- a/DesignTools/Operations/FitToBoundsObject3D_2.cs +++ b/DesignTools/Operations/FitToBoundsObject3D_2.cs @@ -27,9 +27,6 @@ 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; using MatterHackers.Agg; using MatterHackers.Agg.UI; using MatterHackers.DataConverters3D; @@ -38,22 +35,182 @@ using MatterHackers.MatterControl.PartPreviewWindow; using MatterHackers.MeshVisualizer; using MatterHackers.PolygonMesh; using MatterHackers.VectorMath; +using System; +using System.ComponentModel; +using System.Linq; namespace MatterHackers.MatterControl.DesignTools.Operations { public class FitToBoundsObject3D_2 : TransformWrapperObject3D, IEditorDraw { - Vector3 boundsSize; - public double Width + private Vector3 boundsSize; + + private AxisAlignedBoundingBox cacheAabb; + + private Vector3 cacheBounds; + + private Matrix4X4 cacheMatrix; + + public FitToBoundsObject3D_2() { - get => boundsSize.X; - set + Name = "Fit to Bounds".Localize(); + } + + public override bool CanApply => true; + public override bool CanRemove => true; + private IObject3D FitBounds => Children.Last(); + + public static FitToBoundsObject3D_2 Create(IObject3D itemToFit) + { + var fitToBounds = new FitToBoundsObject3D_2(); + var aabb = itemToFit.GetAxisAlignedBoundingBox(); + + var bounds = new Object3D() { - boundsSize.X = value; - UpdateBoundsItem(); + 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); + + fitToBounds.SizeX = aabb.XSize; + fitToBounds.SizeY = aabb.YSize; + fitToBounds.SizeZ = aabb.ZSize; + + return fitToBounds; + } + + 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()) + { + var aabb = SourceItem.GetAxisAlignedBoundingBox(); + + var center = aabb.Center; + var worldMatrix = this.WorldMatrix(); + + var minXyz = center - new Vector3(SizeX / 2, SizeY / 2, SizeZ / 2); + var maxXyz = center + new Vector3(SizeX / 2, SizeY / 2, SizeZ / 2); + var bounds = new AxisAlignedBoundingBox(minXyz, maxXyz); + //var leftW = Vector3.Transform(, worldMatrix); + var right = Vector3.Transform(center + new Vector3(SizeX / 2, 0, 0), worldMatrix); + // layer.World.Render3DLine(left, right, Agg.Color.Red); + layer.World.RenderAabb(bounds, worldMatrix, Agg.Color.Red, 1, 1); } } + public override AxisAlignedBoundingBox GetAxisAlignedBoundingBox(Matrix4X4 matrix) + { + if (Children.Count == 2) + { + if (cacheMatrix != matrix + || cacheBounds != boundsSize) + { + using (FitBounds.RebuildLock()) + { + FitBounds.Visible = true; + cacheAabb = base.GetAxisAlignedBoundingBox(matrix); + FitBounds.Visible = false; + } + cacheMatrix = matrix; + cacheBounds = boundsSize; + } + + return cacheAabb; + } + + return base.GetAxisAlignedBoundingBox(matrix); + } + + 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 Rebuild(UndoBuffer undoBuffer) + { + this.DebugDepth("Rebuild"); + using (RebuildLock()) + { + UpdateBoundsItem(); + + var aabb = this.GetAxisAlignedBoundingBox(); + + AdjustChildSize(null, null); + + if (aabb.ZSize > 0) + { + // If the part was already created and at a height, maintain the height. + PlatingHelper.PlaceMeshAtHeight(this, aabb.minXYZ.Z); + } + } + + base.Invalidate(new InvalidateArgs(this, InvalidateType.Matrix)); + } + + private void AdjustChildSize(object sender, EventArgs e) + { + var aabb = SourceItem.GetAxisAlignedBoundingBox(); + TransformItem.Matrix = Matrix4X4.Identity; + var scale = Vector3.One; + if (StretchX) + { + scale.X = SizeX / aabb.XSize; + } + if (StretchY) + { + scale.Y = SizeY / aabb.YSize; + } + if (StretchZ) + { + scale.Z = SizeZ / aabb.ZSize; + } + + switch (MaintainRatio) + { + case MaintainRatio.None: + break; + + case MaintainRatio.X_Y: + var minXy = Math.Min(scale.X, scale.Y); + scale.X = minXy; + scale.Y = minXy; + break; + + case MaintainRatio.X_Y_Z: + var minXyz = Math.Min(Math.Min(scale.X, scale.Y), scale.Z); + scale.X = minXyz; + scale.Y = minXyz; + scale.Z = minXyz; + break; + } + + TransformItem.Matrix = Object3DExtensions.ApplyAtPosition(TransformItem.Matrix, aabb.Center, Matrix4X4.CreateScale(scale)); + } + private void UpdateBoundsItem() { if (Children.Count == 2) @@ -76,7 +233,24 @@ namespace MatterHackers.MatterControl.DesignTools.Operations } } - public double Depth + #region // editable properties + + [Description("Set the rules for how to maintain the part while scaling.")] + public MaintainRatio MaintainRatio { get; set; } = MaintainRatio.X_Y; + + [DisplayName("Width")] + public double SizeX + { + get => boundsSize.X; + set + { + boundsSize.X = value; + UpdateBoundsItem(); + } + } + + [DisplayName("Depth")] + public double SizeY { get => boundsSize.Y; set @@ -85,7 +259,9 @@ namespace MatterHackers.MatterControl.DesignTools.Operations UpdateBoundsItem(); } } - public double Height + + [DisplayName("Height")] + public double SizeZ { get => boundsSize.Z; set @@ -95,172 +271,15 @@ namespace MatterHackers.MatterControl.DesignTools.Operations } } - private IObject3D FitBounds => Children.Last(); - - [Description("Set the rules for how to maintain the part while scaling.")] - public MaintainRatio MaintainRatio { get; set; } = MaintainRatio.X_Y; [Description("Allows you turn turn on and off applying the fit to the x axis.")] public bool StretchX { get; set; } = true; + [Description("Allows you turn turn on and off applying the fit to the y axis.")] public bool StretchY { get; set; } = true; + [Description("Allows you turn turn on and off applying the fit to the z axis.")] public bool StretchZ { get; set; } = true; - public FitToBoundsObject3D_2() - { - Name = "Fit to Bounds".Localize(); - } - - 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 static FitToBoundsObject3D_2 Create(IObject3D itemToFit) - { - var fitToBounds = new FitToBoundsObject3D_2(); - 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); - - fitToBounds.Width = aabb.XSize; - fitToBounds.Depth = aabb.YSize; - fitToBounds.Height = aabb.ZSize; - - return fitToBounds; - } - - public void Rebuild(UndoBuffer undoBuffer) - { - this.DebugDepth("Rebuild"); - using (RebuildLock()) - { - UpdateBoundsItem(); - - var aabb = this.GetAxisAlignedBoundingBox(); - - AdjustChildSize(null, null); - - if (aabb.ZSize > 0) - { - // If the part was already created and at a height, maintain the height. - PlatingHelper.PlaceMeshAtHeight(this, aabb.minXYZ.Z); - } - } - - base.Invalidate(new InvalidateArgs(this, InvalidateType.Matrix)); - } - - Matrix4X4 cacheMatrix; - Vector3 cacheBounds; - AxisAlignedBoundingBox cacheAabb; - public override AxisAlignedBoundingBox GetAxisAlignedBoundingBox(Matrix4X4 matrix) - { - if (Children.Count == 2) - { - if (cacheMatrix != matrix - || cacheBounds != boundsSize) - { - using (FitBounds.RebuildLock()) - { - FitBounds.Visible = true; - cacheAabb = base.GetAxisAlignedBoundingBox(matrix); - FitBounds.Visible = false; - } - cacheMatrix = matrix; - cacheBounds = boundsSize; - } - - return cacheAabb; - } - - return base.GetAxisAlignedBoundingBox(matrix); - } - - private void AdjustChildSize(object sender, EventArgs e) - { - var aabb = SourceItem.GetAxisAlignedBoundingBox(); - TransformItem.Matrix = Matrix4X4.Identity; - var scale = Vector3.One; - if (StretchX) - { - scale.X = Width / aabb.XSize; - } - if (StretchY) - { - scale.Y = Depth / aabb.YSize; - } - if (StretchZ) - { - scale.Z = Height / aabb.ZSize; - } - - switch (MaintainRatio) - { - case MaintainRatio.None: - break; - case MaintainRatio.X_Y: - var minXy = Math.Min(scale.X, scale.Y); - scale.X = minXy; - scale.Y = minXy; - break; - case MaintainRatio.X_Y_Z: - var minXyz = Math.Min(Math.Min(scale.X, scale.Y), scale.Z); - scale.X = minXyz; - scale.Y = minXyz; - scale.Z = minXyz; - break; - } - - TransformItem.Matrix = Object3DExtensions.ApplyAtPosition(TransformItem.Matrix, aabb.Center, Matrix4X4.CreateScale(scale)); - } - - 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()) - { - var aabb = SourceItem.GetAxisAlignedBoundingBox(); - - var center = aabb.Center; - var worldMatrix = this.WorldMatrix(); - - var minXyz = center - new Vector3(Width / 2, Depth / 2, Height / 2); - var maxXyz = center + new Vector3(Width / 2, Depth / 2, Height / 2); - var bounds = new AxisAlignedBoundingBox(minXyz, maxXyz); - //var leftW = Vector3.Transform(, worldMatrix); - var right = Vector3.Transform(center + new Vector3(Width / 2, 0, 0), worldMatrix); - // layer.World.Render3DLine(left, right, Agg.Color.Red); - layer.World.RenderAabb(bounds, worldMatrix, Agg.Color.Red, 1, 1); - } - } + #endregion // editable properties } } \ No newline at end of file diff --git a/DesignTools/Operations/RotateObject3D_2.cs b/DesignTools/Operations/RotateObject3D_2.cs index 2b954272e..c731104e6 100644 --- a/DesignTools/Operations/RotateObject3D_2.cs +++ b/DesignTools/Operations/RotateObject3D_2.cs @@ -30,30 +30,25 @@ 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.MatterControl.PartPreviewWindow; using MatterHackers.MeshVisualizer; -using MatterHackers.RenderOpenGl.OpenGl; using MatterHackers.VectorMath; using Newtonsoft.Json; using System.ComponentModel; using System.Linq; -using MatterHackers.MatterControl.DesignTools.EditableTypes; -using System; namespace MatterHackers.MatterControl.DesignTools.Operations { public class RotateObject3D_2 : TransformWrapperObject3D, IEditorDraw { - public DirectionAxis RotateAbout { get; set; } = new DirectionAxis() { Origin = Vector3.NegativeInfinity, Normal = Vector3.UnitZ }; - [DisplayName("Angle")] - public double AngleDegrees { get; set; } = 0; - public RotateObject3D_2() { Name = "Rotate".Localize(); } public RotateObject3D_2(IObject3D item, double xRadians = 0, double yRadians = 0, double zRadians = 0, string name = "") + : this() { Children.Add(item.Clone()); @@ -65,6 +60,15 @@ namespace MatterHackers.MatterControl.DesignTools.Operations { } + public override bool CanApply => true; + public override bool CanRemove => true; + + #region // editable properties + public DirectionAxis RotateAbout { get; set; } = new DirectionAxis() { Origin = Vector3.NegativeInfinity, Normal = Vector3.UnitZ }; + [DisplayName("Angle")] + public double AngleDegrees { get; set; } = 0; + #endregion + [JsonIgnore] public Matrix4X4 RotationMatrix { @@ -79,17 +83,28 @@ namespace MatterHackers.MatterControl.DesignTools.Operations } } - private void Rebuild(UndoBuffer undoBuffer) + public static RotateObject3D_2 Create(IObject3D itemToRotate) { - this.DebugDepth("Rebuild"); + var rotate = new RotateObject3D_2(); + var aabb = itemToRotate.GetAxisAlignedBoundingBox(); - using (RebuildLock()) + rotate.RotateAbout.Origin = aabb.Center; + + var rotateItem = new Object3D(); + rotate.Children.Add(rotateItem); + rotateItem.Children.Add(itemToRotate); + + return rotate; + } + + 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()) { - // set the matrix for the inner object - TransformItem.Matrix = RotationMatrix; + layer.World.RenderDirectionAxis(RotateAbout, this.WorldMatrix(), 30); } - - Invalidate(new InvalidateArgs(this, InvalidateType.Matrix, null)); } public override void OnInvalidate(InvalidateArgs invalidateType) @@ -126,28 +141,17 @@ namespace MatterHackers.MatterControl.DesignTools.Operations } } - public void DrawEditor(object sender, DrawEventArgs e) + private void Rebuild(UndoBuffer undoBuffer) { - if (sender is InteractionLayer layer - && layer.Scene.SelectedItem != null - && layer.Scene.SelectedItem.DescendantsAndSelf().Where((i) => i == this).Any()) + this.DebugDepth("Rebuild"); + + using (RebuildLock()) { - layer.World.RenderDirectionAxis(RotateAbout, this.WorldMatrix(), 30); + // set the matrix for the inner object + TransformItem.Matrix = RotationMatrix; } - } - public static RotateObject3D_2 Create(IObject3D itemToRotate) - { - var rotate = new RotateObject3D_2(); - var aabb = itemToRotate.GetAxisAlignedBoundingBox(); - - rotate.RotateAbout.Origin = aabb.Center; - - var rotateItem = new Object3D(); - rotate.Children.Add(rotateItem); - rotateItem.Children.Add(itemToRotate); - - return rotate; + Invalidate(new InvalidateArgs(this, InvalidateType.Matrix, null)); } } } \ No newline at end of file diff --git a/DesignTools/Operations/TranslateObject3D.cs b/DesignTools/Operations/TranslateObject3D.cs index c226ad4e8..26246b0a1 100644 --- a/DesignTools/Operations/TranslateObject3D.cs +++ b/DesignTools/Operations/TranslateObject3D.cs @@ -27,15 +27,19 @@ 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.VectorMath; +using System.Linq; namespace MatterHackers.MatterControl.DesignTools.Operations { - public class TranslateObject3D : Object3D + public class TranslateObject3D : TransformWrapperObject3D { public TranslateObject3D() { + Name = "Translate".Localize(); } public TranslateObject3D(IObject3D item, double x = 0, double y = 0, double z = 0) @@ -43,10 +47,84 @@ namespace MatterHackers.MatterControl.DesignTools.Operations { } - public TranslateObject3D(IObject3D item, Vector3 translation) + public TranslateObject3D(IObject3D itemToTranslate, Vector3 translation) + : this() { - Matrix *= Matrix4X4.CreateTranslation(translation); - Children.Add(item.Clone()); + var translate = this; + var aabb = itemToTranslate.GetAxisAlignedBoundingBox(); + + var translateItem = new Object3D(); + translate.Children.Add(translateItem); + translateItem.Children.Add(itemToTranslate); + } + + public override bool CanApply => true; + + public override bool CanRemove => true; + + public static TranslateObject3D Create(IObject3D itemToTranslate) + { + var translate = new TranslateObject3D(); + var aabb = itemToTranslate.GetAxisAlignedBoundingBox(); + + var translateItem = new Object3D(); + translate.Children.Add(translateItem); + translateItem.Children.Add(itemToTranslate); + + return translate; + } + + #region // editable properties + + public Vector3 Translation { get; set; } = Vector3.Zero; + + #endregion // editable 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.Color) + { + var sourceItem = OperationSourceObject3D.GetOrCreateSourceContainer(this).Children.FirstOrDefault(); + foreach (var item in Children) + { + if (item != sourceItem) + { + item.Color = sourceItem.Color; + } + } + + base.OnInvalidate(invalidateType); + } + else if (invalidateType.InvalidateType == InvalidateType.Properties + && invalidateType.Source == this) + { + Rebuild(null); + } + else + { + base.OnInvalidate(invalidateType); + } + } + + private void Rebuild(UndoBuffer undoBuffer) + { + this.DebugDepth("Rebuild"); + + using (RebuildLock()) + { + // set the matrix for the inner object + TransformItem.Matrix = Matrix4X4.CreateTranslation(Translation); + } + + Invalidate(new InvalidateArgs(this, InvalidateType.Matrix, null)); } } } \ No newline at end of file diff --git a/MatterControl.csproj b/MatterControl.csproj index eb45208fa..d36d6905a 100644 --- a/MatterControl.csproj +++ b/MatterControl.csproj @@ -97,7 +97,7 @@ - + @@ -111,7 +111,7 @@ - + diff --git a/Submodules/agg-sharp b/Submodules/agg-sharp index 41db892c4..bb0881cd1 160000 --- a/Submodules/agg-sharp +++ b/Submodules/agg-sharp @@ -1 +1 @@ -Subproject commit 41db892c4b7790e3eb5c92896ed536cdfa722d2d +Subproject commit bb0881cd16ffb3498c8089cc6695d76629b3d332