From ee65c180c2d2ce9cedf6c9b948566f717a371f05 Mon Sep 17 00:00:00 2001 From: LarsBrubaker Date: Sat, 1 May 2021 08:22:21 -0700 Subject: [PATCH] Making scale proportional work on property scalers --- .../ScaleControls/ScaleController.cs | 191 ++++++++++++++++++ .../ScaleWidthDepthEdgeControl.cs | 87 +++----- 2 files changed, 222 insertions(+), 56 deletions(-) create mode 100644 MatterControlLib/DesignTools/EditorTools/ScaleControls/ScaleController.cs diff --git a/MatterControlLib/DesignTools/EditorTools/ScaleControls/ScaleController.cs b/MatterControlLib/DesignTools/EditorTools/ScaleControls/ScaleController.cs new file mode 100644 index 000000000..1e9cb6654 --- /dev/null +++ b/MatterControlLib/DesignTools/EditorTools/ScaleControls/ScaleController.cs @@ -0,0 +1,191 @@ +/* +Copyright (c) 2014, 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; +using MatterHackers.DataConverters3D; +using MatterHackers.MatterControl.DesignTools; +using MatterHackers.MeshVisualizer; +using MatterHackers.VectorMath; +using System; + +namespace MatterHackers.Plugins.EditorTools +{ + public class ScaleController + { + public ScaleStates FinalState; + + public ScaleStates InitialState; + + private IObject3DControlContext context; + + public bool HasChange + { + get + { + if (selectedItem is IObjectWithWidthAndDepth widthDepthItem + && (widthDepthItem.Width != InitialState.Width || widthDepthItem.Depth != InitialState.Depth)) + { + return true; + } + + return false; + } + } + + private IObject3D selectedItem + { + get + { + var selectedItemRoot = context.Scene.SelectedItemRoot; + var selectedItem = context.Scene.SelectedItem; + return (selectedItemRoot == selectedItem) ? selectedItem : null; + } + } + + public void Cancel() + { + if (selectedItem is IObjectWithWidthAndDepth widthDepthItem) + { + widthDepthItem.Width = InitialState.Width; + widthDepthItem.Depth = InitialState.Depth; + } + + selectedItem.Matrix = InitialState.Matrix; + } + + public void ScaleWidth(double newWidth) + { + FinalState = InitialState; + FinalState.Width = newWidth; + if (context.GuiSurface.ModifierKeys == Keys.Shift) + { + ScaleProportional(newWidth / InitialState.Width); + } + + SetItem(selectedItem, FinalState); + } + + public void ScaleDepth(double newDepth) + { + FinalState = InitialState; + FinalState.Depth = newDepth; + if (context.GuiSurface.ModifierKeys == Keys.Shift) + { + ScaleProportional(newDepth / InitialState.Depth); + } + + SetItem(selectedItem, FinalState); + } + + private void ScaleProportional(double scale) + { + FinalState.Width = InitialState.Width * scale; + FinalState.Depth = InitialState.Depth * scale; + FinalState.Height = InitialState.Height * scale; + } + + private void SetItem(IObject3D item, ScaleStates states) + { + if (item is IObjectWithWidthAndDepth widthDepthItem) + { + widthDepthItem.Width = states.Width; + widthDepthItem.Depth = states.Depth; + } + + if (item is IObjectWithHeight heightItem) + { + heightItem.Height = states.Height; + } + + item.Matrix = states.Matrix; + } + + public void SetInitialState(IObject3DControlContext context) + { + this.context = context; + + if (selectedItem is IObjectWithWidthAndDepth widthDepthItem) + { + InitialState.Width = widthDepthItem.Width; + InitialState.Depth = widthDepthItem.Depth; + } + + if (selectedItem is IObjectWithHeight heightItem) + { + InitialState.Height = heightItem.Height; + } + + InitialState.Matrix = selectedItem.Matrix; + } + + public void WidthDepthEditComplete() + { + var doState = FinalState; + doState.Matrix = selectedItem.Matrix; + + var undoState = InitialState; + + EditComplete(undoState, doState); + } + + private void EditComplete(ScaleStates undoState, ScaleStates doState) + { + var undoBuffer = context.Scene.UndoBuffer; + var selectedItem = this.selectedItem; + + undoBuffer.AddAndDo(new UndoRedoActions(async () => + { + SetItem(selectedItem, undoState); + await selectedItem.Rebuild(); + // we set the matrix again after as the rebuild might move the object + selectedItem.Matrix = undoState.Matrix; + selectedItem?.Invalidate(new InvalidateArgs(selectedItem, InvalidateType.DisplayValues)); + }, + async () => + { + SetItem(selectedItem, doState); + await selectedItem.Rebuild(); + // we set the matrix again after as the rebuild might move the object + selectedItem.Matrix = doState.Matrix; + selectedItem?.Invalidate(new InvalidateArgs(selectedItem, InvalidateType.DisplayValues)); + })); + } + + public struct ScaleStates + { + public double Depth; + + public double Height; + + public double Width; + + public Matrix4X4 Matrix { get; set; } + } + } +} \ No newline at end of file diff --git a/MatterControlLib/DesignTools/EditorTools/ScaleControls/ScaleWidthDepthEdgeControl.cs b/MatterControlLib/DesignTools/EditorTools/ScaleControls/ScaleWidthDepthEdgeControl.cs index 12a2a0ec0..bd9ee3ab8 100644 --- a/MatterControlLib/DesignTools/EditorTools/ScaleControls/ScaleWidthDepthEdgeControl.cs +++ b/MatterControlLib/DesignTools/EditorTools/ScaleControls/ScaleWidthDepthEdgeControl.cs @@ -66,8 +66,7 @@ namespace MatterHackers.Plugins.EditorTools private Vector3 initialHitPosition; - private Vector2 sizeOnMouseDown; - private Matrix4X4 matrixOnMouseDown; + private ScaleController scaleController = new ScaleController(); public ScaleWidthDepthEdgeControl(IObject3DControlContext context, int edgeIndex) : base(context) @@ -136,13 +135,7 @@ namespace MatterHackers.Plugins.EditorTools if (selectedItem != null && MouseDownOnControl) { - if (selectedItem is IObjectWithWidthAndDepth widthDepthItem) - { - widthDepthItem.Width = sizeOnMouseDown.X; - widthDepthItem.Depth = sizeOnMouseDown.Y; - } - - selectedItem.Matrix = matrixOnMouseDown; + scaleController.Cancel(); MouseDownOnControl = false; MouseIsOver = false; @@ -228,12 +221,8 @@ namespace MatterHackers.Plugins.EditorTools hitPlane = new PlaneShape(new Plane(planeNormal, mouseEvent3D.info.HitPosition), null); initialHitPosition = mouseEvent3D.info.HitPosition; - if (selectedItem is IObjectWithWidthAndDepth widthDepthItem) - { - sizeOnMouseDown = new Vector2(widthDepthItem.Width, widthDepthItem.Depth); - } - matrixOnMouseDown = selectedItem.Matrix; + scaleController.SetInitialState(Object3DControlContext); Object3DControlContext.Scene.ShowSelectionShadow = false; } @@ -251,9 +240,7 @@ namespace MatterHackers.Plugins.EditorTools xValueDisplayInfo.Visible = true; yValueDisplayInfo.Visible = true; } - else if (!hadClickOnControl - || (selectedItem is IObjectWithWidthAndDepth widthDepthItem - && (widthDepthItem.Width != sizeOnMouseDown.X || widthDepthItem.Depth != sizeOnMouseDown.Y))) + else if (!hadClickOnControl || scaleController.HasChange) { xValueDisplayInfo.Visible = false; yValueDisplayInfo.Visible = false; @@ -274,41 +261,38 @@ namespace MatterHackers.Plugins.EditorTools var deltaAlongStretch = stretchDirection.Dot(delta); // scale it - if (selectedItem is IObjectWithWidthAndDepth widthDepthItem) + var newSize = new Vector2(scaleController.InitialState.Width, scaleController.InitialState.Depth); + if (edgeIndex % 2 == 1) { - var newSize = new Vector3(widthDepthItem.Width, widthDepthItem.Depth, 0); + newSize.X += deltaAlongStretch; + newSize.X = Math.Max(Math.Max(newSize.X, .001), Object3DControlContext.SnapGridDistance); + } + else + { + newSize.Y += deltaAlongStretch; + newSize.Y = Math.Max(Math.Max(newSize.Y, .001), Object3DControlContext.SnapGridDistance); + } + + if (Object3DControlContext.SnapGridDistance > 0) + { + // snap this position to the grid + double snapGridDistance = Object3DControlContext.SnapGridDistance; + + // snap this position to the grid if (edgeIndex % 2 == 1) { - newSize.X = sizeOnMouseDown.X + deltaAlongStretch; - newSize.X = Math.Max(Math.Max(newSize.X, .001), Object3DControlContext.SnapGridDistance); + newSize.X = ((int)((newSize.X / snapGridDistance) + .5)) * snapGridDistance; + scaleController.ScaleWidth(newSize.X); } else { - newSize.Y = sizeOnMouseDown.Y + deltaAlongStretch; - newSize.Y = Math.Max(Math.Max(newSize.Y, .001), Object3DControlContext.SnapGridDistance); + newSize.Y = ((int)((newSize.Y / snapGridDistance) + .5)) * snapGridDistance; + scaleController.ScaleDepth(newSize.Y); } - - if (Object3DControlContext.SnapGridDistance > 0) - { - // snap this position to the grid - double snapGridDistance = Object3DControlContext.SnapGridDistance; - - // snap this position to the grid - if (edgeIndex % 2 == 1) - { - newSize.X = ((int)((newSize.X / snapGridDistance) + .5)) * snapGridDistance; - } - else - { - newSize.Y = ((int)((newSize.Y / snapGridDistance) + .5)) * snapGridDistance; - } - } - - widthDepthItem.Width = newSize.X; - widthDepthItem.Depth = newSize.Y; - selectedItem.Invalidate(new InvalidateArgs(selectedItem, InvalidateType.DisplayValues)); } + selectedItem.Invalidate(new InvalidateArgs(selectedItem, InvalidateType.DisplayValues)); + await selectedItem.Rebuild(); // and keep the locked edge in place @@ -328,14 +312,10 @@ namespace MatterHackers.Plugins.EditorTools if (hadClickOnControl) { if (RootSelection is IObjectWithWidthAndDepth widthDepthItem - && (widthDepthItem.Width != sizeOnMouseDown.X || widthDepthItem.Depth != sizeOnMouseDown.Y)) + && (widthDepthItem.Width != scaleController.InitialState.Width + || widthDepthItem.Depth != scaleController.InitialState.Depth)) { - ScaleWidthDepthCornerControl.SetWidthDepthUndo(RootSelection, - Object3DControlContext.Scene.UndoBuffer, - new Vector2(widthDepthItem.Width, widthDepthItem.Depth), - RootSelection.Matrix, - sizeOnMouseDown, - matrixOnMouseDown); + scaleController.WidthDepthEditComplete(); } Object3DControlContext.Scene.ShowSelectionShadow = true; } @@ -408,12 +388,7 @@ namespace MatterHackers.Plugins.EditorTools newSize.X = xValueDisplayInfo.Value != 0 ? xValueDisplayInfo.Value : widthDepthItem.Width; newSize.Y = yValueDisplayInfo.Value != 0 ? yValueDisplayInfo.Value : widthDepthItem.Depth; - ScaleWidthDepthCornerControl.SetWidthDepthUndo(RootSelection, - Object3DControlContext.Scene.UndoBuffer, - new Vector2(newSize), - ActiveSelectedItem.Matrix, - sizeOnMouseDown, - matrixOnMouseDown); + scaleController.WidthDepthEditComplete(); // and keep the locked edge in place Vector3 newLockedEdge = ObjectSpace.GetEdgePosition(ActiveSelectedItem, edgeIndex + 2);