From bf18085e89f5689e69f0a038bff7e2f549f2ff11 Mon Sep 17 00:00:00 2001 From: LarsBrubaker Date: Sat, 17 Mar 2018 20:53:36 -0700 Subject: [PATCH] Added new fit to bounds This should allow use objects like card holder alignment made aabb rendering more generic Added editor draw to objects --- ApplicationView/ApplicationController.cs | 18 ++ .../IEditorDraw.cs} | 48 +----- DesignTools/Operations/ArrayLinearObject3D.cs | 1 - DesignTools/Operations/FitToBounds.cs | 155 ++++++++++++++++++ DesignTools/Primitives/CubeObject3D.cs | 1 + DesignTools/PublicPropertyEditor.cs | 9 + MatterControl.csproj | 3 +- PartPreviewWindow/View3D/MeshViewerWidget.cs | 46 +++--- Submodules/agg-sharp | 2 +- 9 files changed, 215 insertions(+), 68 deletions(-) rename DesignTools/{Operations/ScaleObject3D.cs => Interfaces/IEditorDraw.cs} (63%) create mode 100644 DesignTools/Operations/FitToBounds.cs diff --git a/ApplicationView/ApplicationController.cs b/ApplicationView/ApplicationController.cs index 2eb48fadb..fe016de48 100644 --- a/ApplicationView/ApplicationController.cs +++ b/ApplicationView/ApplicationController.cs @@ -40,6 +40,7 @@ using MatterHackers.MatterControl.DataStorage; using MatterHackers.MatterControl.PrinterCommunication; using MatterHackers.MatterControl.PrintQueue; using MatterHackers.MatterControl.SlicerConfiguration; +using MatterHackers.MatterControl.DesignTools.Operations; using Newtonsoft.Json; using System.Collections.ObjectModel; @@ -458,6 +459,23 @@ namespace MatterHackers.MatterControl Icon = AggContext.StaticData.LoadIcon("array_advanced.png").SetPreMultiply(), IsEnabled = (scene) => scene.HasSelection && !(scene.SelectedItem is SelectionGroup), }, + new SceneSelectionOperation() + { + TitleResolver = () => "Fit to Bounds".Localize(), + Action = (scene) => + { + var selectedItem = scene.SelectedItem; + scene.SelectedItem = null; + var fit = FitToBounds.Create(selectedItem.Clone()); + fit.MakeNameNonColliding(); + + scene.UndoBuffer.AddAndDo(new ReplaceCommand(new List { selectedItem }, new List { fit })); + + scene.SelectedItem = fit; + }, + //Icon = AggContext.StaticData.LoadIcon("array_linear.png").SetPreMultiply(), + IsEnabled = (scene) => scene.HasSelection && !(scene.SelectedItem is SelectionGroup), + }, #if DEBUG // keep this work in progress to the editor for now new SceneSelectionSeparator(), new SceneSelectionOperation() diff --git a/DesignTools/Operations/ScaleObject3D.cs b/DesignTools/Interfaces/IEditorDraw.cs similarity index 63% rename from DesignTools/Operations/ScaleObject3D.cs rename to DesignTools/Interfaces/IEditorDraw.cs index 431899ebf..b62da6b74 100644 --- a/DesignTools/Operations/ScaleObject3D.cs +++ b/DesignTools/Interfaces/IEditorDraw.cs @@ -27,52 +27,14 @@ 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.UI; -using MatterHackers.DataConverters3D; -using MatterHackers.VectorMath; +using MatterHackers.MatterControl.PartPreviewWindow; -namespace MatterHackers.MatterControl.DesignTools.Operations +namespace MatterHackers.MatterControl.DesignTools { - public class ScaleObject3D : Object3D, IRebuildable + public interface IEditorDraw { - public ScaleObject3D() - { - } - - public override bool CanRemove => true; - public override bool CanBake => true; - - public override void Remove() - { - throw new NotImplementedException(); - } - - public void Rebuild(UndoBuffer undoBuffer) - { - var aabb = this.GetAxisAlignedBoundingBox(); - - // TODO: check if the has code for the children - //if (ChildrenBounds.Count == 0) - { - this.Children.Modify(list => - { - foreach (var child in list) - { - //ChildrenBounds.Add(child.GetAxisAlignedBoundingBox()); - } - }); - } - - this.Children.Modify(list => - { -// var firstBounds = ChildrenBounds[0]; - int i = 0; - foreach (var child in list) - { - i++; - } - }); - } + void DrawEditor(object sender, DrawEventArgs e); } } \ No newline at end of file diff --git a/DesignTools/Operations/ArrayLinearObject3D.cs b/DesignTools/Operations/ArrayLinearObject3D.cs index 25684cd56..d9a42b929 100644 --- a/DesignTools/Operations/ArrayLinearObject3D.cs +++ b/DesignTools/Operations/ArrayLinearObject3D.cs @@ -41,7 +41,6 @@ namespace MatterHackers.MatterControl.DesignTools.Operations { Name = "Linear Array".Localize(); } - public override bool CanBake => true; public override bool CanRemove => true; diff --git a/DesignTools/Operations/FitToBounds.cs b/DesignTools/Operations/FitToBounds.cs new file mode 100644 index 000000000..7732172c6 --- /dev/null +++ b/DesignTools/Operations/FitToBounds.cs @@ -0,0 +1,155 @@ +/* +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.Drawing; +using System.Linq; +using MatterHackers.Agg.UI; +using MatterHackers.DataConverters3D; +using MatterHackers.MatterControl.PartPreviewWindow; +using MatterHackers.MeshVisualizer; +using MatterHackers.RenderOpenGl; +using MatterHackers.RenderOpenGl.OpenGl; +using MatterHackers.VectorMath; + +namespace MatterHackers.MatterControl.DesignTools.Operations +{ + public enum MaintainRatio { None, X_Y, X_Y_Z } + + public class FitToBounds : Object3D, IRebuildable, IEditorDraw + { + public double Width { get; set; } + public double Depth { get; set; } + public double Height { get; set; } + + public MaintainRatio MaintainRatio { get; set; } = MaintainRatio.X_Y; + public bool StretchX { get; set; } = true; + public bool StretchY { get; set; } = true; + public bool StretchZ { get; set; } = true; + + IObject3D ScaleItem => Children.First(); + IObject3D ItemToScale => Children.First().Children.First(); + + public FitToBounds() + { + } + + protected override void OnInvalidate() + { + // If the child bounds changed than adjust the scale control + base.OnInvalidate(); + } + + public static FitToBounds Create(IObject3D itemToFit) + { + FitToBounds fitToBounds = new FitToBounds(); + var aabb = itemToFit.GetAxisAlignedBoundingBox(); + + fitToBounds.Width = aabb.XSize; + fitToBounds.Depth = aabb.YSize; + fitToBounds.Height = aabb.ZSize; + + var scaleItem = new Object3D(); + fitToBounds.Children.Add(scaleItem); + scaleItem.Children.Add(itemToFit); + + return fitToBounds; + } + + public void Rebuild(UndoBuffer undoBuffer) + { + 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); + } + } + + private void AdjustChildSize(object sender, EventArgs e) + { + var aabb = ItemToScale.GetAxisAlignedBoundingBox(); + ScaleItem.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; + } + ScaleItem.Matrix = Object3DExtensions.ApplyAtPosition(ScaleItem.Matrix, Matrix4X4.CreateScale(scale), aabb.Center); + } + + public void DrawEditor(object sender, DrawEventArgs e) + { + if (sender is InteractionLayer layer + && layer.Scene.SelectedItem == this) + { + var aabb = ItemToScale.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); + // GLHelper.Render3DLine(layer.World, left, right, Agg.Color.Red); + layer.World.RenderAabb(bounds, worldMatrix, Agg.Color.Red, 1); + // turn the lighting back on + GL.Enable(EnableCap.Lighting); + } + } + } +} \ No newline at end of file diff --git a/DesignTools/Primitives/CubeObject3D.cs b/DesignTools/Primitives/CubeObject3D.cs index 08f118f3e..47cc836f4 100644 --- a/DesignTools/Primitives/CubeObject3D.cs +++ b/DesignTools/Primitives/CubeObject3D.cs @@ -78,6 +78,7 @@ namespace MatterHackers.MatterControl.DesignTools var aabb = this.GetAxisAlignedBoundingBox(); Mesh = PlatonicSolids.CreateCube(Width, Depth, Height); + if (aabb.ZSize > 0) { // If the part was already created and at a height, maintain the height. diff --git a/DesignTools/PublicPropertyEditor.cs b/DesignTools/PublicPropertyEditor.cs index aef58324b..524ce9685 100644 --- a/DesignTools/PublicPropertyEditor.cs +++ b/DesignTools/PublicPropertyEditor.cs @@ -77,6 +77,15 @@ namespace MatterHackers.MatterControl.DesignTools HAnchor = HAnchor.Stretch }; + if(item is IEditorDraw editorDraw) + { + view3DWidget.InteractionLayer.DrawGlOpaqueContent += editorDraw.DrawEditor; + mainContainer.Closed += (s, e) => + { + view3DWidget.InteractionLayer.DrawGlOpaqueContent -= editorDraw.DrawEditor; + }; + } + if (this.item != null) { ModifyObject(view3DWidget, mainContainer, theme); diff --git a/MatterControl.csproj b/MatterControl.csproj index f753c12da..f7844de89 100644 --- a/MatterControl.csproj +++ b/MatterControl.csproj @@ -92,6 +92,7 @@ + @@ -99,11 +100,11 @@ + - diff --git a/PartPreviewWindow/View3D/MeshViewerWidget.cs b/PartPreviewWindow/View3D/MeshViewerWidget.cs index ecec03ec8..2da54e955 100644 --- a/PartPreviewWindow/View3D/MeshViewerWidget.cs +++ b/PartPreviewWindow/View3D/MeshViewerWidget.cs @@ -63,6 +63,26 @@ namespace MatterHackers.MeshVisualizer public static class MaterialRendering { + public static void RenderAabb(this WorldView world, AxisAlignedBoundingBox bounds, Matrix4X4 matrix, Color color, double width) + { + GLHelper.PrepareFor3DLineRender(true); + + Frustum frustum = world.GetClippingFrustum(); + for (int i = 0; i < 4; i++) + { + Vector3 bottomStartPosition = Vector3.Transform(bounds.GetBottomCorner(i), matrix); + Vector3 bottomEndPosition = Vector3.Transform(bounds.GetBottomCorner((i + 1) % 4), matrix); + Vector3 topStartPosition = Vector3.Transform(bounds.GetTopCorner(i), matrix); + Vector3 topEndPosition = Vector3.Transform(bounds.GetTopCorner((i + 1) % 4), matrix); + + GLHelper.Render3DLineNoPrep(frustum, world, bottomStartPosition, bottomEndPosition, color, width); + GLHelper.Render3DLineNoPrep(frustum, world, topStartPosition, topEndPosition, color, width); + GLHelper.Render3DLineNoPrep(frustum, world, topStartPosition, bottomStartPosition, color, width); + } + + GL.Enable(EnableCap.Lighting); + } + public static Color Color(int materialIndex) { return ColorF.FromHSL(Math.Max(materialIndex, 0) / 10.0, .99, .49).ToColor(); @@ -521,9 +541,7 @@ namespace MatterHackers.MeshVisualizer if (totalVertices > maxVerticesToRenderOutline && scene.DebugItem == null) { - GLHelper.PrepareFor3DLineRender(true); - RenderAABB(frustum, object3D.GetAxisAlignedBoundingBox(Matrix4X4.Identity), Matrix4X4.Identity, selectionColor, selectionHighlightWidth); - GL.Enable(EnableCap.Lighting); + World.RenderAabb(object3D.GetAxisAlignedBoundingBox(Matrix4X4.Identity), Matrix4X4.Identity, selectionColor, selectionHighlightWidth); } else { @@ -538,8 +556,7 @@ namespace MatterHackers.MeshVisualizer var aabb = object3D.GetAxisAlignedBoundingBox(Matrix4X4.Identity); - GLHelper.PrepareFor3DLineRender(true); - RenderAABB(frustum, aabb, Matrix4X4.Identity, debugBorderColor, 1); + World.RenderAabb(aabb, Matrix4X4.Identity, debugBorderColor, 1); if (item.mesh != null) { @@ -656,12 +673,12 @@ namespace MatterHackers.MeshVisualizer if(!renderedAnything) { - RenderAABB(frustum, renderData.Mesh.GetAxisAlignedBoundingBox(), renderData.WorldMatrix(), selectionColor, selectionHighlightWidth); + World.RenderAabb(renderData.Mesh.GetAxisAlignedBoundingBox(), renderData.WorldMatrix(), selectionColor, selectionHighlightWidth); } } else // just render the bounding box { - RenderAABB(frustum, renderData.Mesh.GetAxisAlignedBoundingBox(), renderData.WorldMatrix(), selectionColor, selectionHighlightWidth); + World.RenderAabb(renderData.Mesh.GetAxisAlignedBoundingBox(), renderData.WorldMatrix(), selectionColor, selectionHighlightWidth); } } @@ -676,21 +693,6 @@ namespace MatterHackers.MeshVisualizer return 2.0f * t * (1.0f - t) + 0.5; } - void RenderAABB(Frustum frustum, AxisAlignedBoundingBox bounds, Matrix4X4 matrix, Color color, double width) - { - for (int i = 0; i < 4; i++) - { - Vector3 bottomStartPosition = Vector3.Transform(bounds.GetBottomCorner(i), matrix); - Vector3 bottomEndPosition = Vector3.Transform(bounds.GetBottomCorner((i + 1) % 4), matrix); - Vector3 topStartPosition = Vector3.Transform(bounds.GetTopCorner(i), matrix); - Vector3 topEndPosition = Vector3.Transform(bounds.GetTopCorner((i + 1) % 4), matrix); - - GLHelper.Render3DLineNoPrep(frustum, World, bottomStartPosition, bottomEndPosition, color, width); - GLHelper.Render3DLineNoPrep(frustum, World, topStartPosition, topEndPosition, color, width); - GLHelper.Render3DLineNoPrep(frustum, World, topStartPosition, bottomStartPosition, color, width); - } - } - public enum EditorType { Printer, Part } public EditorType EditorMode { get; set; } = EditorType.Part; diff --git a/Submodules/agg-sharp b/Submodules/agg-sharp index a20e22e4c..11517c930 160000 --- a/Submodules/agg-sharp +++ b/Submodules/agg-sharp @@ -1 +1 @@ -Subproject commit a20e22e4c02539f81a657db103e1589f2326ebdd +Subproject commit 11517c9302bd8ad6161de3192168d47ec8e03d5a