diff --git a/MatterControlLib/DesignTools/EditorTools/ScaleControls/ScaleHeightControl.cs b/MatterControlLib/DesignTools/EditorTools/ScaleControls/ScaleHeightControl.cs index bae90d2a8..1f9f08a62 100644 --- a/MatterControlLib/DesignTools/EditorTools/ScaleControls/ScaleHeightControl.cs +++ b/MatterControlLib/DesignTools/EditorTools/ScaleControls/ScaleHeightControl.cs @@ -358,11 +358,7 @@ namespace MatterHackers.Plugins.EditorTools Vector3 arrowCenter = topPosition; arrowCenter.Z += arrowSize / 2 * distBetweenPixelsWorldSpace; - var normal = Vector3.UnitZ.Transform(selectedItem.Matrix); - var up = Vector3.UnitX.Transform(selectedItem.Matrix); - var rotation = Matrix4X4.LookAt(Vector3.Zero, normal, up); - rotation = Matrix4X4.Identity; - + var rotation = Matrix4X4.CreateRotation(new Quaternion(selectedItem.Matrix)); TotalTransform = rotation * Matrix4X4.CreateScale(distBetweenPixelsWorldSpace) * Matrix4X4.CreateTranslation(arrowCenter); } diff --git a/MatterControlLib/DesignTools/EditorTools/ScaleControls/ScaleMatrixCornerControl.cs b/MatterControlLib/DesignTools/EditorTools/ScaleControls/ScaleMatrixCornerControl.cs index 20e567dda..78d84d38b 100644 --- a/MatterControlLib/DesignTools/EditorTools/ScaleControls/ScaleMatrixCornerControl.cs +++ b/MatterControlLib/DesignTools/EditorTools/ScaleControls/ScaleMatrixCornerControl.cs @@ -189,29 +189,8 @@ namespace MatterHackers.Plugins.EditorTools if (e != null) { Vector3 startPosition = GetCornerPosition(selectedItem, quadrantIndex); - Vector3 endPosition = GetCornerPosition(selectedItem, (quadrantIndex + 1) % 4); - - Frustum clippingFrustum = Object3DControlContext.World.GetClippingFrustum(); - - if (clippingFrustum.ClipLine(ref startPosition, ref endPosition)) - { - if (e.ZBuffered) - { - Object3DControlContext.World.Render3DLine(clippingFrustum, startPosition, endPosition, theme.TextColor, width: GuiWidget.DeviceScale); - } - else - { - // render on top of everything very lightly - Object3DControlContext.World.Render3DLine(clippingFrustum, startPosition, endPosition, new Color(theme.TextColor, Constants.LineAlpha), false, GuiWidget.DeviceScale); - } - } - - // Vector3 startScreenSpace = Object3DControlContext.World.GetScreenSpace(startPosition); - // e.graphics2D.Circle(startScreenSpace.x, startScreenSpace.y, 5, theme.PrimaryAccentColor); - - // Vector2 startScreenPosition = Object3DControlContext.World.GetScreenPosition(startPosition); - // e.graphics2D.Circle(startScreenPosition.x, startScreenPosition.y, 5, theme.PrimaryAccentColor); + Object3DControlContext.World.Render3DLine(startPosition, endPosition, theme.TextColor.WithAlpha(e.Alpha0to255), e.ZBuffered, GuiWidget.DeviceScale); } } diff --git a/MatterControlLib/DesignTools/EditorTools/ScaleControls/ScaleWidthDepthCornerControl.cs b/MatterControlLib/DesignTools/EditorTools/ScaleControls/ScaleWidthDepthCornerControl.cs new file mode 100644 index 000000000..1d53768ac --- /dev/null +++ b/MatterControlLib/DesignTools/EditorTools/ScaleControls/ScaleWidthDepthCornerControl.cs @@ -0,0 +1,525 @@ +/* +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; +using MatterHackers.Agg.UI; +using MatterHackers.DataConverters3D; +using MatterHackers.MatterControl; +using MatterHackers.MatterControl.CustomWidgets; +using MatterHackers.MatterControl.DesignTools; +using MatterHackers.MatterControl.PartPreviewWindow; +using MatterHackers.MeshVisualizer; +using MatterHackers.PolygonMesh; +using MatterHackers.RayTracer; +using MatterHackers.RenderOpenGl; +using MatterHackers.VectorMath; +using System; + +namespace MatterHackers.Plugins.EditorTools +{ + public class ScaleWidthDepthCornerControl : Object3DControl + { + /// + /// Edge starting from the back (+y) going ccw + /// + private readonly int quadrantIndex; + + private readonly Mesh minXminYMesh; + + private readonly double selectCubeSize = 7 * GuiWidget.DeviceScale; + + private readonly ThemeConfig theme; + + private readonly InlineEditControl xValueDisplayInfo; + + private readonly InlineEditControl yValueDisplayInfo; + + private bool hadClickOnControl; + + private PlaneShape hitPlane; + + private Vector3 initialHitPosition; + + private Vector2 sizeOnMouseDown; + + public ScaleWidthDepthCornerControl(IObject3DControlContext context, int quadrant) + : base(context) + { + theme = MatterControl.AppContext.Theme; + + xValueDisplayInfo = new InlineEditControl() + { + ForceHide = ForceHideScale, + GetDisplayString = (value) => "{0:0.0}".FormatWith(value), + }; + + xValueDisplayInfo.EditComplete += EditComplete; + + xValueDisplayInfo.VisibleChanged += (s, e) => + { + if (!xValueDisplayInfo.Visible) + { + hadClickOnControl = false; + } + }; + + yValueDisplayInfo = new InlineEditControl() + { + ForceHide = ForceHideScale, + GetDisplayString = (value) => "{0:0.0}".FormatWith(value) + }; + + yValueDisplayInfo.EditComplete += EditComplete; + + yValueDisplayInfo.VisibleChanged += (s, e) => + { + if (!yValueDisplayInfo.Visible) + { + hadClickOnControl = false; + } + }; + + Object3DControlContext.GuiSurface.AddChild(xValueDisplayInfo); + Object3DControlContext.GuiSurface.AddChild(yValueDisplayInfo); + + this.quadrantIndex = quadrant; + + DrawOnTop = true; + + minXminYMesh = PlatonicSolids.CreateCube(selectCubeSize, selectCubeSize, selectCubeSize); + + CollisionVolume = minXminYMesh.CreateBVHData(); + + Object3DControlContext.GuiSurface.BeforeDraw += Object3DControl_BeforeDraw; + } + + public IObject3D ActiveSelectedItem { get; set; } + + private double LineLength => 35 * GuiWidget.DeviceScale; + + public override void CancelOperation() + { + IObject3D selectedItem = RootSelection; + if (selectedItem != null + && MouseDownOnControl) + { + if (selectedItem is IObjectWithWidthAndDepth widthDepthItem) + { + widthDepthItem.Width = sizeOnMouseDown.X; + widthDepthItem.Depth = sizeOnMouseDown.Y; + } + + MouseDownOnControl = false; + MouseIsOver = false; + + Object3DControlContext.Scene.DrawSelection = true; + Object3DControlContext.Scene.ShowSelectionShadow = true; + } + + base.CancelOperation(); + } + + public override void Dispose() + { + yValueDisplayInfo.Close(); + xValueDisplayInfo.Close(); + Object3DControlContext.GuiSurface.BeforeDraw -= Object3DControl_BeforeDraw; + } + + public override void Draw(DrawGlContentEventArgs e) + { + bool shouldDrawScaleControls = true; + if (Object3DControlContext.SelectedObject3DControl != null + && Object3DControlContext.SelectedObject3DControl as ScaleMatrixEdgeControl == null) + { + shouldDrawScaleControls = false; + } + + var selectedItem = RootSelection; + + if (selectedItem != null) + { + // Ensures that functions in this scope run against the original instance reference rather than the + // current value, thus avoiding null reference errors that would occur otherwise + + if (shouldDrawScaleControls) + { + // don't draw if any other control is dragging + if (MouseIsOver || MouseDownOnControl) + { + GLHelper.Render(minXminYMesh, theme.PrimaryAccentColor.WithAlpha(e.Alpha0to255), TotalTransform, RenderTypes.Shaded); + } + else + { + GLHelper.Render(minXminYMesh, theme.TextColor.Blend(theme.BackgroundColor, .35).WithAlpha(e.Alpha0to255), TotalTransform, RenderTypes.Shaded); + } + } + + if (hitPlane != null) + { + //Object3DControlContext.World.RenderPlane(hitPlane.Plane, Color.Red, true, 30, 3); + Object3DControlContext.World.RenderPlane(initialHitPosition, hitPlane.Plane.Normal, Color.Red, true, 30, 3); + } + } + + if (e != null && selectedItem != null) + { + Vector3 startPosition = ObjectSpace.GetCornerPosition(selectedItem, quadrantIndex); + Vector3 endPosition = ObjectSpace.GetCornerPosition(selectedItem, (quadrantIndex + 1) % 4); + Object3DControlContext.World.Render3DLine(startPosition, endPosition, theme.TextColor.WithAlpha(e.Alpha0to255), e.ZBuffered, GuiWidget.DeviceScale); + } + + if (MouseIsOver || MouseDownOnControl) + { + DrawMeasureLines(e, quadrantIndex); + DrawMeasureLines(e, quadrantIndex + 1); + } + + base.Draw(e); + } + + public override void OnMouseDown(Mouse3DEventArgs mouseEvent3D) + { + var selectedItem = RootSelection; + ActiveSelectedItem = selectedItem; + + if (mouseEvent3D.MouseEvent2D.Button == MouseButtons.Left + && mouseEvent3D.info != null + && selectedItem != null) + { + hadClickOnControl = true; + + xValueDisplayInfo.Visible = true; + yValueDisplayInfo.Visible = true; + + var edge0 = ObjectSpace.GetEdgePosition(selectedItem, quadrantIndex); + var edge1 = ObjectSpace.GetEdgePosition(selectedItem, quadrantIndex + 1); + var edge3 = ObjectSpace.GetEdgePosition(selectedItem, quadrantIndex + 2); + + var normal01 = (edge1 - edge0).GetNormal(); + var normal03 = (edge3 - edge0).GetNormal(); + var planeNormal = normal01.Cross(normal03).GetNormal(); + hitPlane = new PlaneShape(new Plane(planeNormal, edge0), null); + + initialHitPosition = mouseEvent3D.info.HitPosition; + if (selectedItem is IObjectWithWidthAndDepth widthDepthItem) + { + sizeOnMouseDown = new Vector2(widthDepthItem.Width, widthDepthItem.Depth); + } + + Object3DControlContext.Scene.ShowSelectionShadow = false; + } + + base.OnMouseDown(mouseEvent3D); + } + + public override async void OnMouseMove(Mouse3DEventArgs mouseEvent3D, bool mouseIsOver) + { + var selectedItem = RootSelection; + ActiveSelectedItem = selectedItem; + + if (MouseIsOver || MouseDownOnControl) + { + xValueDisplayInfo.Visible = true; + yValueDisplayInfo.Visible = true; + } + else if (!hadClickOnControl + || (selectedItem is IObjectWithWidthAndDepth widthDepthItem + && (widthDepthItem.Width != sizeOnMouseDown.X || widthDepthItem.Depth != sizeOnMouseDown.Y))) + { + xValueDisplayInfo.Visible = false; + yValueDisplayInfo.Visible = false; + } + + if (MouseDownOnControl && hitPlane != null) + { + var info = hitPlane.GetClosestIntersection(mouseEvent3D.MouseRay); + + if (info != null + && selectedItem != null) + { + var delta = info.HitPosition - initialHitPosition; + + var lockedEdge = ObjectSpace.GetEdgePosition(selectedItem, quadrantIndex + 2); + + var stretchDirection = (ObjectSpace.GetEdgePosition(selectedItem, quadrantIndex) - lockedEdge).GetNormal(); + var deltaAlongStretch = stretchDirection.Dot(delta); + + // scale it + if (selectedItem is IObjectWithWidthAndDepth widthDepthItem) + { + var newSize = new Vector3(widthDepthItem.Width, widthDepthItem.Depth, 0); + if (quadrantIndex % 2 == 1) + { + newSize.X = sizeOnMouseDown.X + deltaAlongStretch; + newSize.X = Math.Max(Math.Max(newSize.X, .001), Object3DControlContext.SnapGridDistance); + } + else + { + newSize.Y = sizeOnMouseDown.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 (quadrantIndex % 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)); + } + + await selectedItem.Rebuild(); + + // and keep the locked edge in place + Vector3 newLockedEdge = ObjectSpace.GetEdgePosition(selectedItem, quadrantIndex + 2); + + selectedItem.Matrix *= Matrix4X4.CreateTranslation(lockedEdge - newLockedEdge); + + Invalidate(); + } + } + + base.OnMouseMove(mouseEvent3D, mouseIsOver); + } + + public override void OnMouseUp(Mouse3DEventArgs mouseEvent3D) + { + if (hadClickOnControl + && RootSelection is IObjectWithWidthAndDepth widthDepthItem + && (widthDepthItem.Width != sizeOnMouseDown.X || widthDepthItem.Depth != sizeOnMouseDown.Y)) + { + SetWidthDepthUndo(new Vector2(widthDepthItem.Width, widthDepthItem.Depth), sizeOnMouseDown); + Object3DControlContext.Scene.ShowSelectionShadow = true; + } + + base.OnMouseUp(mouseEvent3D); + } + + public override void SetPosition(IObject3D selectedItem, MeshSelectInfo selectInfo) + { + // create the transform for the box + Vector3 cornerPosition = ObjectSpace.GetCornerPosition(selectedItem, quadrantIndex); + + Vector3 boxCenter = cornerPosition; + + double distBetweenPixelsWorldSpace = Object3DControlContext.World.GetWorldUnitsPerScreenPixelAtPosition(cornerPosition); + switch (quadrantIndex) + { + case 0: + boxCenter.X += selectCubeSize / 2 * distBetweenPixelsWorldSpace; + boxCenter.Y += selectCubeSize / 2 * distBetweenPixelsWorldSpace; + break; + + case 1: + boxCenter.X -= selectCubeSize / 2 * distBetweenPixelsWorldSpace; + boxCenter.Y += selectCubeSize / 2 * distBetweenPixelsWorldSpace; + break; + + case 2: + boxCenter.X -= selectCubeSize / 2 * distBetweenPixelsWorldSpace; + boxCenter.Y -= selectCubeSize / 2 * distBetweenPixelsWorldSpace; + break; + + case 3: + boxCenter.X += selectCubeSize / 2 * distBetweenPixelsWorldSpace; + boxCenter.Y -= selectCubeSize / 2 * distBetweenPixelsWorldSpace; + break; + } + + boxCenter.Z += selectCubeSize / 2 * distBetweenPixelsWorldSpace; + + var rotation = Matrix4X4.CreateRotation(new Quaternion(selectedItem.Matrix)); + + var centerMatrix = Matrix4X4.CreateTranslation(boxCenter); + centerMatrix = rotation * Matrix4X4.CreateScale(distBetweenPixelsWorldSpace) * centerMatrix; + TotalTransform = centerMatrix; + } + + private void DrawMeasureLines(DrawGlContentEventArgs e, int quadrant) + { + var (start0, end0, start1, end1) = GetMeasureLine(quadrant); + + var color = theme.TextColor.WithAlpha(e.Alpha0to255); + if (!e.ZBuffered) + { + theme.TextColor.WithAlpha(Constants.LineAlpha); + } + + Frustum clippingFrustum = Object3DControlContext.World.GetClippingFrustum(); + + Object3DControlContext.World.Render3DLine(clippingFrustum, start0, end0, color, e.ZBuffered, GuiWidget.DeviceScale); + Object3DControlContext.World.Render3DLine(clippingFrustum, start1, end1, color, e.ZBuffered, GuiWidget.DeviceScale); + var start = (start0 + end0) / 2; + var end = (start1 + end1) / 2; + Object3DControlContext.World.Render3DLine(clippingFrustum, start, end, color, e.ZBuffered, GuiWidget.DeviceScale * 1.2, true, true); + } + + private void EditComplete(object s, EventArgs e) + { + if (ActiveSelectedItem is IObjectWithWidthAndDepth widthDepthItem) + { + Vector3 lockedEdge = ObjectSpace.GetEdgePosition(ActiveSelectedItem, quadrantIndex + 2); + + Vector3 newSize = Vector3.Zero; + newSize.X = xValueDisplayInfo.Value != 0 ? xValueDisplayInfo.Value : widthDepthItem.Width; + newSize.Y = yValueDisplayInfo.Value != 0 ? yValueDisplayInfo.Value : widthDepthItem.Depth; + + SetWidthDepthUndo(new Vector2(newSize), sizeOnMouseDown); + + // and keep the locked edge in place + Vector3 newLockedEdge = ObjectSpace.GetEdgePosition(ActiveSelectedItem, quadrantIndex + 2); + + ActiveSelectedItem.Matrix *= Matrix4X4.CreateTranslation(lockedEdge - newLockedEdge); + } + + Invalidate(); + } + + private bool ForceHideScale() + { + var selectedItem = RootSelection; + // if the selection changes + if (selectedItem != ActiveSelectedItem) + { + return true; + } + + // if another control gets a hover + if (Object3DControlContext.HoveredObject3DControl != this + && Object3DControlContext.HoveredObject3DControl != null) + { + return true; + } + + // if we clicked on the control + if (hadClickOnControl) + { + return false; + } + + return false; + } + + private (Vector3 start0, Vector3 end0, Vector3 start1, Vector3 end1) GetMeasureLine(int quadrant) + { + var selectedItem = RootSelection; + var corner = new Vector3[4]; + var screen = new Vector3[4]; + for (int i = 0; i < 4; i++) + { + corner[i] = ObjectSpace.GetCornerPosition(selectedItem, quadrant + i); + screen[i] = Object3DControlContext.World.GetScreenSpace(corner[i]); + } + + var start = corner[0]; + var direction = (start - corner[1]).GetNormal(); + var end = corner[3]; + // find out which side we should render on (the one closer to the screen) + if (screen[0].Z > screen[1].Z) + { + start = corner[1]; + end = corner[2]; + direction = (start - corner[0]).GetNormal(); + } + + var startScale = Object3DControlContext.World.GetWorldUnitsPerScreenPixelAtPosition(start); + var endScale = Object3DControlContext.World.GetWorldUnitsPerScreenPixelAtPosition(end); + var offset = .3; + var start0 = start + direction * LineLength * offset * startScale; + var end0 = start + direction * LineLength * (1 + offset) * endScale; + var start1 = end + direction * LineLength * offset * endScale; + var end1 = end + direction * LineLength * (1 + offset) * endScale; + return (start0, end0, start1, end1); + } + + private void Object3DControl_BeforeDraw(object sender, DrawEventArgs drawEvent) + { + var selectedItem = RootSelection; + + if (selectedItem != null) + { + if (MouseIsOver || MouseDownOnControl) + { + var (start0, end0, start1, end1) = GetMeasureLine(quadrantIndex); + var start = (start0 + end0) / 2; + var end = (start1 + end1) / 2; + var screenStart = Object3DControlContext.World.GetScreenPosition(start); + var screenEnd = Object3DControlContext.World.GetScreenPosition(end); + + if (quadrantIndex % 2 == 1) + { + xValueDisplayInfo.Value = (start - end).Length; + xValueDisplayInfo.OriginRelativeParent = (screenStart + screenEnd) / 2 - xValueDisplayInfo.LocalBounds.Center; + } + else + { + yValueDisplayInfo.Value = (start - end).Length; + yValueDisplayInfo.OriginRelativeParent = (screenStart + screenEnd) / 2 - yValueDisplayInfo.LocalBounds.Center; + } + } + } + } + + private void SetWidthDepthUndo(Vector2 doWidthDepth, Vector2 undoWidthDepth) + { + var selectedItem = RootSelection; + if (selectedItem is IObjectWithWidthAndDepth widthDepthItem) + { + var undoBuffer = Object3DControlContext.Scene.UndoBuffer; + undoBuffer.AddAndDo(new UndoRedoActions(async () => + { + widthDepthItem.Width = undoWidthDepth.X; + widthDepthItem.Depth = undoWidthDepth.Y; + await selectedItem.Rebuild(); + selectedItem?.Invalidate(new InvalidateArgs(selectedItem, InvalidateType.Properties)); + }, + async () => + { + widthDepthItem.Width = doWidthDepth.X; + widthDepthItem.Depth = doWidthDepth.Y; + await selectedItem.Rebuild(); + selectedItem?.Invalidate(new InvalidateArgs(selectedItem, InvalidateType.Properties)); + })); + } + } + } +} \ No newline at end of file diff --git a/MatterControlLib/DesignTools/EditorTools/ScaleControls/ScaleWidthDepthControl.cs b/MatterControlLib/DesignTools/EditorTools/ScaleControls/ScaleWidthDepthEdgeControl.cs similarity index 84% rename from MatterControlLib/DesignTools/EditorTools/ScaleControls/ScaleWidthDepthControl.cs rename to MatterControlLib/DesignTools/EditorTools/ScaleControls/ScaleWidthDepthEdgeControl.cs index acb7c8662..03860287c 100644 --- a/MatterControlLib/DesignTools/EditorTools/ScaleControls/ScaleWidthDepthControl.cs +++ b/MatterControlLib/DesignTools/EditorTools/ScaleControls/ScaleWidthDepthEdgeControl.cs @@ -43,7 +43,7 @@ using System; namespace MatterHackers.Plugins.EditorTools { - public class ScaleWidthDepthControl : Object3DControl + public class ScaleWidthDepthEdgeControl : Object3DControl { /// /// Edge starting from the back (+y) going ccw @@ -66,11 +66,9 @@ namespace MatterHackers.Plugins.EditorTools private Vector3 initialHitPosition; - private Vector3 originalPointToMove; - private Vector2 sizeOnMouseDown; - public ScaleWidthDepthControl(IObject3DControlContext context, int edgeIndex) + public ScaleWidthDepthEdgeControl(IObject3DControlContext context, int edgeIndex) : base(context) { theme = MatterControl.AppContext.Theme; @@ -129,64 +127,8 @@ namespace MatterHackers.Plugins.EditorTools public IObject3D ActiveSelectedItem { get; set; } - private double DistToStart => 10 * GuiWidget.DeviceScale; - private double LineLength => 35 * GuiWidget.DeviceScale; - public static Vector3 GetScalingConsideringShiftKey(AxisAlignedBoundingBox originalSelectedBounds, - AxisAlignedBoundingBox mouseDownSelectedBounds, - Vector3 newSize, - Keys modifierKeys) - { - var minimumSize = .1; - var scaleAmount = Vector3.One; - - if (originalSelectedBounds.XSize <= 0 - || originalSelectedBounds.YSize <= 0 - || originalSelectedBounds.ZSize <= 0) - { - // don't scale if any dimension will go to 0 - return scaleAmount; - } - - if (modifierKeys == Keys.Shift) - { - newSize.X = newSize.X <= minimumSize ? minimumSize : newSize.X; - newSize.Y = newSize.Y <= minimumSize ? minimumSize : newSize.Y; - newSize.Z = newSize.Z <= minimumSize ? minimumSize : newSize.Z; - - scaleAmount.X = mouseDownSelectedBounds.XSize / originalSelectedBounds.XSize; - scaleAmount.Y = mouseDownSelectedBounds.YSize / originalSelectedBounds.YSize; - scaleAmount.Z = mouseDownSelectedBounds.ZSize / originalSelectedBounds.ZSize; - - double scaleFromOriginal = Math.Max(newSize.X / mouseDownSelectedBounds.XSize, newSize.Y / mouseDownSelectedBounds.YSize); - scaleFromOriginal = Math.Max(scaleFromOriginal, newSize.Z / mouseDownSelectedBounds.ZSize); - scaleAmount *= scaleFromOriginal; - } - else - { - if (newSize.X > 0) - { - newSize.X = newSize.X <= minimumSize ? minimumSize : newSize.X; - scaleAmount.X = newSize.X / originalSelectedBounds.XSize; - } - - if (newSize.Y > 0) - { - newSize.Y = newSize.Y <= minimumSize ? minimumSize : newSize.Y; - scaleAmount.Y = newSize.Y / originalSelectedBounds.YSize; - } - - if (newSize.Z > 0) - { - newSize.Z = newSize.Z <= minimumSize ? minimumSize : newSize.Z; - scaleAmount.Z = newSize.Z / originalSelectedBounds.ZSize; - } - } - - return scaleAmount; - } - public override void CancelOperation() { IObject3D selectedItem = RootSelection; @@ -211,6 +153,7 @@ namespace MatterHackers.Plugins.EditorTools public override void Dispose() { + xValueDisplayInfo.Close(); yValueDisplayInfo.Close(); Object3DControlContext.GuiSurface.BeforeDraw -= Object3DControl_BeforeDraw; } @@ -259,42 +202,6 @@ namespace MatterHackers.Plugins.EditorTools base.Draw(e); } - public Vector3 GetCornerPosition(IObject3D item, int quadrantIndex) - { - quadrantIndex = quadrantIndex % 4; - AxisAlignedBoundingBox originalSelectedBounds = item.GetAxisAlignedBoundingBox(item.Matrix.Inverted); - Vector3 cornerPosition = originalSelectedBounds.GetBottomCorner(quadrantIndex); - - return cornerPosition.Transform(item.Matrix); - } - - public Vector3 GetEdgePosition(IObject3D item, int edegIndex) - { - edegIndex = edegIndex % 4; - AxisAlignedBoundingBox aabb = item.GetAxisAlignedBoundingBox(item.Matrix.Inverted); - var edgePosition = default(Vector3); - switch (edegIndex) - { - case 0: - edgePosition = new Vector3(aabb.Center.X, aabb.MaxXYZ.Y, aabb.MinXYZ.Z); - break; - - case 1: - edgePosition = new Vector3(aabb.MinXYZ.X, aabb.Center.Y, aabb.MinXYZ.Z); - break; - - case 2: - edgePosition = new Vector3(aabb.Center.X, aabb.MinXYZ.Y, aabb.MinXYZ.Z); - break; - - case 3: - edgePosition = new Vector3(aabb.MaxXYZ.X, aabb.Center.Y, aabb.MinXYZ.Z); - break; - } - - return edgePosition.Transform(item.Matrix); - } - public override void OnMouseDown(Mouse3DEventArgs mouseEvent3D) { var selectedItem = RootSelection; @@ -309,9 +216,8 @@ namespace MatterHackers.Plugins.EditorTools xValueDisplayInfo.Visible = true; yValueDisplayInfo.Visible = true; - var edge = GetEdgePosition(selectedItem, edgeIndex); - var otherSide = GetEdgePosition(selectedItem, edgeIndex + 2); - originalPointToMove = edge; + var edge = ObjectSpace.GetEdgePosition(selectedItem, edgeIndex); + var otherSide = ObjectSpace.GetEdgePosition(selectedItem, edgeIndex + 2); var upNormal = (edge - otherSide).GetNormal(); var sideNormal = upNormal.Cross(mouseEvent3D.MouseRay.directionNormal).GetNormal(); @@ -357,9 +263,9 @@ namespace MatterHackers.Plugins.EditorTools { var delta = info.HitPosition - initialHitPosition; - var lockedEdge = GetEdgePosition(selectedItem, edgeIndex + 2); + var lockedEdge = ObjectSpace.GetEdgePosition(selectedItem, edgeIndex + 2); - var stretchDirection = (GetEdgePosition(selectedItem, edgeIndex) - lockedEdge).GetNormal(); + var stretchDirection = (ObjectSpace.GetEdgePosition(selectedItem, edgeIndex) - lockedEdge).GetNormal(); var deltaAlongStretch = stretchDirection.Dot(delta); // scale it @@ -401,7 +307,7 @@ namespace MatterHackers.Plugins.EditorTools await selectedItem.Rebuild(); // and keep the locked edge in place - Vector3 newLockedEdge = GetEdgePosition(selectedItem, edgeIndex + 2); + Vector3 newLockedEdge = ObjectSpace.GetEdgePosition(selectedItem, edgeIndex + 2); selectedItem.Matrix *= Matrix4X4.CreateTranslation(lockedEdge - newLockedEdge); @@ -428,7 +334,7 @@ namespace MatterHackers.Plugins.EditorTools public override void SetPosition(IObject3D selectedItem, MeshSelectInfo selectInfo) { // create the transform for the box - Vector3 edgePosition = GetEdgePosition(selectedItem, edgeIndex); + Vector3 edgePosition = ObjectSpace.GetEdgePosition(selectedItem, edgeIndex); Vector3 boxCenter = edgePosition; @@ -454,8 +360,10 @@ namespace MatterHackers.Plugins.EditorTools boxCenter.Z += selectCubeSize / 2 * distBetweenPixelsWorldSpace; + var rotation = Matrix4X4.CreateRotation(new Quaternion(selectedItem.Matrix)); + var centerMatrix = Matrix4X4.CreateTranslation(boxCenter); - centerMatrix = Matrix4X4.CreateScale(distBetweenPixelsWorldSpace) * centerMatrix; + centerMatrix = rotation * Matrix4X4.CreateScale(distBetweenPixelsWorldSpace) * centerMatrix; TotalTransform = centerMatrix; } @@ -482,7 +390,7 @@ namespace MatterHackers.Plugins.EditorTools { if (ActiveSelectedItem is IObjectWithWidthAndDepth widthDepthItem) { - Vector3 lockedEdge = GetEdgePosition(ActiveSelectedItem, edgeIndex + 2); + Vector3 lockedEdge = ObjectSpace.GetEdgePosition(ActiveSelectedItem, edgeIndex + 2); Vector3 newSize = Vector3.Zero; newSize.X = xValueDisplayInfo.Value != 0 ? xValueDisplayInfo.Value : widthDepthItem.Width; @@ -491,7 +399,7 @@ namespace MatterHackers.Plugins.EditorTools SetWidthDepthUndo(new Vector2(newSize), sizeOnMouseDown); // and keep the locked edge in place - Vector3 newLockedEdge = GetEdgePosition(ActiveSelectedItem, edgeIndex + 2); + Vector3 newLockedEdge = ObjectSpace.GetEdgePosition(ActiveSelectedItem, edgeIndex + 2); ActiveSelectedItem.Matrix *= Matrix4X4.CreateTranslation(lockedEdge - newLockedEdge); } @@ -526,9 +434,9 @@ namespace MatterHackers.Plugins.EditorTools private Vector3 GetDeltaToOtherSideXy(IObject3D selectedItem, int quadrantIndex) { - Vector3 cornerPosition = GetCornerPosition(selectedItem, quadrantIndex); - Vector3 cornerPositionCcw = GetCornerPosition(selectedItem, quadrantIndex + 1); - Vector3 cornerPositionCw = GetCornerPosition(selectedItem, quadrantIndex + 3); + Vector3 cornerPosition = ObjectSpace.GetCornerPosition(selectedItem, quadrantIndex); + Vector3 cornerPositionCcw = ObjectSpace.GetCornerPosition(selectedItem, quadrantIndex + 1); + Vector3 cornerPositionCw = ObjectSpace.GetCornerPosition(selectedItem, quadrantIndex + 3); double xDirection = cornerPositionCcw.X - cornerPosition.X; if (xDirection == 0) @@ -552,7 +460,7 @@ namespace MatterHackers.Plugins.EditorTools var screen = new Vector3[4]; for (int i = 0; i < 4; i++) { - corner[i] = GetCornerPosition(selectedItem, edgeIndex + i); + corner[i] = ObjectSpace.GetCornerPosition(selectedItem, edgeIndex + i); screen[i] = Object3DControlContext.World.GetScreenSpace(corner[i]); } @@ -628,4 +536,43 @@ namespace MatterHackers.Plugins.EditorTools } } } + + public static class ObjectSpace + { + public static Vector3 GetCornerPosition(IObject3D item, int quadrantIndex) + { + quadrantIndex %= 4; + AxisAlignedBoundingBox originalSelectedBounds = item.GetAxisAlignedBoundingBox(item.Matrix.Inverted); + Vector3 cornerPosition = originalSelectedBounds.GetBottomCorner(quadrantIndex); + + return cornerPosition.Transform(item.Matrix); + } + + public static Vector3 GetEdgePosition(IObject3D item, int edegIndex) + { + edegIndex %= 4; + AxisAlignedBoundingBox aabb = item.GetAxisAlignedBoundingBox(item.Matrix.Inverted); + var edgePosition = default(Vector3); + switch (edegIndex) + { + case 0: + edgePosition = new Vector3(aabb.Center.X, aabb.MaxXYZ.Y, aabb.MinXYZ.Z); + break; + + case 1: + edgePosition = new Vector3(aabb.MinXYZ.X, aabb.Center.Y, aabb.MinXYZ.Z); + break; + + case 2: + edgePosition = new Vector3(aabb.Center.X, aabb.MinXYZ.Y, aabb.MinXYZ.Z); + break; + + case 3: + edgePosition = new Vector3(aabb.MaxXYZ.X, aabb.Center.Y, aabb.MinXYZ.Z); + break; + } + + return edgePosition.Transform(item.Matrix); + } + } } \ No newline at end of file diff --git a/MatterControlLib/PartPreviewWindow/View3D/Object3DControlsLayer.cs b/MatterControlLib/PartPreviewWindow/View3D/Object3DControlsLayer.cs index b9c4cf697..7e30b00cf 100644 --- a/MatterControlLib/PartPreviewWindow/View3D/Object3DControlsLayer.cs +++ b/MatterControlLib/PartPreviewWindow/View3D/Object3DControlsLayer.cs @@ -190,10 +190,11 @@ namespace MatterHackers.MatterControl.PartPreviewWindow if (selectedItem is IObjectWithWidthAndDepth widthAndDepth) { - Object3DControls.Add(new ScaleWidthDepthControl(this, 0)); - Object3DControls.Add(new ScaleWidthDepthControl(this, 1)); - Object3DControls.Add(new ScaleWidthDepthControl(this, 2)); - Object3DControls.Add(new ScaleWidthDepthControl(this, 3)); + Object3DControls.Add(new ScaleWidthDepthCornerControl(this, 0)); + //Object3DControls.Add(new ScaleWidthDepthEdgeControl(this, 0)); + //Object3DControls.Add(new ScaleWidthDepthEdgeControl(this, 1)); + //Object3DControls.Add(new ScaleWidthDepthEdgeControl(this, 2)); + //Object3DControls.Add(new ScaleWidthDepthEdgeControl(this, 3)); } else { diff --git a/Submodules/agg-sharp b/Submodules/agg-sharp index d86aca050..fd267bedf 160000 --- a/Submodules/agg-sharp +++ b/Submodules/agg-sharp @@ -1 +1 @@ -Subproject commit d86aca05037188d3a43909ee1042327a461f9ff2 +Subproject commit fd267bedf9a7b6c4d50afe59beb7e776073fb2be