Merged Arrange and Align
First pass on Bake and Remove for FitToBounds
This commit is contained in:
parent
0e0d2bf4f7
commit
6e5674a279
8 changed files with 342 additions and 350 deletions
|
|
@ -348,11 +348,11 @@ namespace MatterHackers.MatterControl
|
|||
new SceneSelectionSeparator(),
|
||||
new SceneSelectionOperation()
|
||||
{
|
||||
TitleResolver = () => "Arrange".Localize(),
|
||||
TitleResolver = () => "Align".Localize(),
|
||||
Action = (scene) =>
|
||||
{
|
||||
scene.AddSelectionAsChildren(new Arrange3D());
|
||||
if(scene.SelectedItem is Arrange3D arange)
|
||||
scene.AddSelectionAsChildren(new Align3D());
|
||||
if(scene.SelectedItem is Align3D arange)
|
||||
{
|
||||
arange.Rebuild(null);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,13 +28,20 @@ either expressed or implied, of the FreeBSD Project.
|
|||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using MatterHackers.Agg.Transform;
|
||||
using MatterHackers.Agg.UI;
|
||||
using MatterHackers.Agg.VertexSource;
|
||||
using MatterHackers.DataConverters3D;
|
||||
using MatterHackers.VectorMath;
|
||||
|
||||
namespace MatterHackers.MatterControl.DesignTools.Operations
|
||||
{
|
||||
using Aabb = AxisAlignedBoundingBox;
|
||||
|
||||
public enum Align { None, Min, Center, Max }
|
||||
|
||||
public enum Alignment { X, Y, Z, negX, negY, negZ };
|
||||
|
||||
[Flags]
|
||||
|
|
@ -74,109 +81,6 @@ namespace MatterHackers.MatterControl.DesignTools.Operations
|
|||
Top = 0x20,
|
||||
};
|
||||
|
||||
public class Align : Object3D
|
||||
{
|
||||
public Align()
|
||||
{
|
||||
}
|
||||
|
||||
public Align(IObject3D objectToAlign, Face boundingFacesToAlign, IObject3D objectToAlignTo, Face boundingFacesToAlignTo, double offsetX = 0, double offsetY = 0, double offsetZ = 0, string name = "")
|
||||
: this(objectToAlign, boundingFacesToAlign, GetPositionToAlignTo(objectToAlignTo, boundingFacesToAlignTo, new Vector3(offsetX, offsetY, offsetZ)), name)
|
||||
{
|
||||
if (objectToAlign == objectToAlignTo)
|
||||
{
|
||||
throw new Exception("You cannot align an object to itself.");
|
||||
}
|
||||
}
|
||||
|
||||
public Align(IObject3D objectToAlign, Face boundingFacesToAlign, double positionToAlignToX = 0, double positionToAlignToY = 0, double positionToAlignToZ = 0, string name = "")
|
||||
: this(objectToAlign, boundingFacesToAlign, new Vector3(positionToAlignToX, positionToAlignToY, positionToAlignToZ), name)
|
||||
{
|
||||
}
|
||||
|
||||
public Align(IObject3D objectToAlign, Face boundingFacesToAlign, Vector3 positionToAlignTo, double offsetX, double offsetY, double offsetZ, string name = "")
|
||||
: this(objectToAlign, boundingFacesToAlign, positionToAlignTo + new Vector3(offsetX, offsetY, offsetZ), name)
|
||||
{
|
||||
}
|
||||
|
||||
public Align(IObject3D item, Face boundingFacesToAlign, Vector3 positionToAlignTo, string name = "")
|
||||
{
|
||||
AxisAlignedBoundingBox bounds = item.GetAxisAlignedBoundingBox();
|
||||
|
||||
if (IsSet(boundingFacesToAlign, Face.Left, Face.Right))
|
||||
{
|
||||
positionToAlignTo.X = positionToAlignTo.X - bounds.minXYZ.X;
|
||||
}
|
||||
if (IsSet(boundingFacesToAlign, Face.Right, Face.Left))
|
||||
{
|
||||
positionToAlignTo.X = positionToAlignTo.X - bounds.minXYZ.X - (bounds.maxXYZ.X - bounds.minXYZ.X);
|
||||
}
|
||||
if (IsSet(boundingFacesToAlign, Face.Front, Face.Back))
|
||||
{
|
||||
positionToAlignTo.Y = positionToAlignTo.Y - bounds.minXYZ.Y;
|
||||
}
|
||||
if (IsSet(boundingFacesToAlign, Face.Back, Face.Front))
|
||||
{
|
||||
positionToAlignTo.Y = positionToAlignTo.Y - bounds.minXYZ.Y - (bounds.maxXYZ.Y - bounds.minXYZ.Y);
|
||||
}
|
||||
if (IsSet(boundingFacesToAlign, Face.Bottom, Face.Top))
|
||||
{
|
||||
positionToAlignTo.Z = positionToAlignTo.Z - bounds.minXYZ.Z;
|
||||
}
|
||||
if (IsSet(boundingFacesToAlign, Face.Top, Face.Bottom))
|
||||
{
|
||||
positionToAlignTo.Z = positionToAlignTo.Z - bounds.minXYZ.Z - (bounds.maxXYZ.Z - bounds.minXYZ.Z);
|
||||
}
|
||||
|
||||
Matrix *= Matrix4X4.CreateTranslation(positionToAlignTo);
|
||||
Children.Add(item.Clone());
|
||||
}
|
||||
|
||||
public static Vector3 GetPositionToAlignTo(IObject3D objectToAlignTo, Face boundingFacesToAlignTo, Vector3 extraOffset)
|
||||
{
|
||||
Vector3 positionToAlignTo = new Vector3();
|
||||
if (IsSet(boundingFacesToAlignTo, Face.Left, Face.Right))
|
||||
{
|
||||
positionToAlignTo.X = objectToAlignTo.GetAxisAlignedBoundingBox().minXYZ.X;
|
||||
}
|
||||
if (IsSet(boundingFacesToAlignTo, Face.Right, Face.Left))
|
||||
{
|
||||
positionToAlignTo.X = objectToAlignTo.GetAxisAlignedBoundingBox().maxXYZ.X;
|
||||
}
|
||||
if (IsSet(boundingFacesToAlignTo, Face.Front, Face.Back))
|
||||
{
|
||||
positionToAlignTo.Y = objectToAlignTo.GetAxisAlignedBoundingBox().minXYZ.Y;
|
||||
}
|
||||
if (IsSet(boundingFacesToAlignTo, Face.Back, Face.Front))
|
||||
{
|
||||
positionToAlignTo.Y = objectToAlignTo.GetAxisAlignedBoundingBox().maxXYZ.Y;
|
||||
}
|
||||
if (IsSet(boundingFacesToAlignTo, Face.Bottom, Face.Top))
|
||||
{
|
||||
positionToAlignTo.Z = objectToAlignTo.GetAxisAlignedBoundingBox().minXYZ.Z;
|
||||
}
|
||||
if (IsSet(boundingFacesToAlignTo, Face.Top, Face.Bottom))
|
||||
{
|
||||
positionToAlignTo.Z = objectToAlignTo.GetAxisAlignedBoundingBox().maxXYZ.Z;
|
||||
}
|
||||
return positionToAlignTo + extraOffset;
|
||||
}
|
||||
|
||||
private static bool IsSet(Face variableToCheck, Face faceToCheckFor, Face faceToAssertNot)
|
||||
{
|
||||
if ((variableToCheck & faceToCheckFor) != 0)
|
||||
{
|
||||
if ((variableToCheck & faceToAssertNot) != 0)
|
||||
{
|
||||
throw new Exception("You cannot have both " + faceToCheckFor.ToString() + " and " + faceToAssertNot.ToString() + " set when calling Align. The are mutually exclusive.");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public class Align2D : VertexSourceApplyTransform
|
||||
{
|
||||
public Align2D()
|
||||
|
|
@ -264,4 +168,292 @@ namespace MatterHackers.MatterControl.DesignTools.Operations
|
|||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public class Align3D : Object3D, IRebuildable, IPropertyGridModifier
|
||||
{
|
||||
// We need to serialize this so we can remove the arrange and get back to the objects before arranging
|
||||
public List<Aabb> OriginalChildrenBounds = new List<Aabb>();
|
||||
|
||||
public Align3D()
|
||||
{
|
||||
Name = "Align";
|
||||
}
|
||||
|
||||
public Align3D(IObject3D objectToAlign, Face boundingFacesToAlign, IObject3D objectToAlignTo, Face boundingFacesToAlignTo, double offsetX = 0, double offsetY = 0, double offsetZ = 0, string name = "")
|
||||
: this(objectToAlign, boundingFacesToAlign, GetPositionToAlignTo(objectToAlignTo, boundingFacesToAlignTo, new Vector3(offsetX, offsetY, offsetZ)), name)
|
||||
{
|
||||
if (objectToAlign == objectToAlignTo)
|
||||
{
|
||||
throw new Exception("You cannot align an object to itself.");
|
||||
}
|
||||
}
|
||||
|
||||
public Align3D(IObject3D objectToAlign, Face boundingFacesToAlign, double positionToAlignToX = 0, double positionToAlignToY = 0, double positionToAlignToZ = 0, string name = "")
|
||||
: this(objectToAlign, boundingFacesToAlign, new Vector3(positionToAlignToX, positionToAlignToY, positionToAlignToZ), name)
|
||||
{
|
||||
}
|
||||
|
||||
public Align3D(IObject3D objectToAlign, Face boundingFacesToAlign, Vector3 positionToAlignTo, double offsetX, double offsetY, double offsetZ, string name = "")
|
||||
: this(objectToAlign, boundingFacesToAlign, positionToAlignTo + new Vector3(offsetX, offsetY, offsetZ), name)
|
||||
{
|
||||
}
|
||||
|
||||
public Align3D(IObject3D item, Face boundingFacesToAlign, Vector3 positionToAlignTo, string name = "")
|
||||
{
|
||||
AxisAlignedBoundingBox bounds = item.GetAxisAlignedBoundingBox();
|
||||
|
||||
if (IsSet(boundingFacesToAlign, Face.Left, Face.Right))
|
||||
{
|
||||
positionToAlignTo.X = positionToAlignTo.X - bounds.minXYZ.X;
|
||||
}
|
||||
if (IsSet(boundingFacesToAlign, Face.Right, Face.Left))
|
||||
{
|
||||
positionToAlignTo.X = positionToAlignTo.X - bounds.minXYZ.X - (bounds.maxXYZ.X - bounds.minXYZ.X);
|
||||
}
|
||||
if (IsSet(boundingFacesToAlign, Face.Front, Face.Back))
|
||||
{
|
||||
positionToAlignTo.Y = positionToAlignTo.Y - bounds.minXYZ.Y;
|
||||
}
|
||||
if (IsSet(boundingFacesToAlign, Face.Back, Face.Front))
|
||||
{
|
||||
positionToAlignTo.Y = positionToAlignTo.Y - bounds.minXYZ.Y - (bounds.maxXYZ.Y - bounds.minXYZ.Y);
|
||||
}
|
||||
if (IsSet(boundingFacesToAlign, Face.Bottom, Face.Top))
|
||||
{
|
||||
positionToAlignTo.Z = positionToAlignTo.Z - bounds.minXYZ.Z;
|
||||
}
|
||||
if (IsSet(boundingFacesToAlign, Face.Top, Face.Bottom))
|
||||
{
|
||||
positionToAlignTo.Z = positionToAlignTo.Z - bounds.minXYZ.Z - (bounds.maxXYZ.Z - bounds.minXYZ.Z);
|
||||
}
|
||||
|
||||
Matrix *= Matrix4X4.CreateTranslation(positionToAlignTo);
|
||||
Children.Add(item.Clone());
|
||||
}
|
||||
|
||||
[DisplayName("X")]
|
||||
[Icons(new string[] { "424.png", "align_left.png", "align_center_x.png", "align_right.png" })]
|
||||
public Align XAlign { get; set; } = Align.None;
|
||||
|
||||
[DisplayName("Start X")]
|
||||
[Icons(new string[] { "424.png", "align_to_left.png", "align_to_center_x.png", "align_to_right.png" })]
|
||||
public Align XAlignTo { get; set; } = Align.None;
|
||||
|
||||
[DisplayName("Offset X")]
|
||||
public double XOffset { get; set; } = 0;
|
||||
|
||||
[DisplayName("Y")]
|
||||
[Icons(new string[] { "424.png", "align_bottom.png", "align_center_y.png", "align_top.png" })]
|
||||
public Align YAlign { get; set; } = Align.None;
|
||||
|
||||
[DisplayName("Start Y")]
|
||||
[Icons(new string[] { "424.png", "align_to_bottom.png", "align_to_center_y.png", "align_to_top.png" })]
|
||||
public Align YAlignTo { get; set; } = Align.None;
|
||||
|
||||
[DisplayName("Offset Y")]
|
||||
public double YOffset { get; set; } = 0;
|
||||
|
||||
[DisplayName("Z")]
|
||||
[Icons(new string[] { "424.png", "align_bottom.png", "align_center_y.png", "align_top.png" })]
|
||||
public Align ZAlign { get; set; } = Align.None;
|
||||
|
||||
[DisplayName("Start Z")]
|
||||
[Icons(new string[] { "424.png", "align_to_bottom.png", "align_to_center_y.png", "align_to_top.png" })]
|
||||
public Align ZAlignTo { get; set; } = Align.None;
|
||||
|
||||
[DisplayName("Offset Z")]
|
||||
public double ZOffset { get; set; } = 0;
|
||||
|
||||
public bool Advanced { get; set; } = false;
|
||||
|
||||
public override bool CanBake => true;
|
||||
|
||||
public override bool CanRemove => true;
|
||||
|
||||
private List<Aabb> CurrentChildrenBounds
|
||||
{
|
||||
get
|
||||
{
|
||||
List<Aabb> currentChildrenBounds = new List<Aabb>();
|
||||
this.Children.Modify(list =>
|
||||
{
|
||||
foreach (var child in list)
|
||||
{
|
||||
currentChildrenBounds.Add(child.GetAxisAlignedBoundingBox());
|
||||
}
|
||||
});
|
||||
|
||||
return currentChildrenBounds;
|
||||
}
|
||||
}
|
||||
|
||||
public static Vector3 GetPositionToAlignTo(IObject3D objectToAlignTo, Face boundingFacesToAlignTo, Vector3 extraOffset)
|
||||
{
|
||||
Vector3 positionToAlignTo = new Vector3();
|
||||
if (IsSet(boundingFacesToAlignTo, Face.Left, Face.Right))
|
||||
{
|
||||
positionToAlignTo.X = objectToAlignTo.GetAxisAlignedBoundingBox().minXYZ.X;
|
||||
}
|
||||
if (IsSet(boundingFacesToAlignTo, Face.Right, Face.Left))
|
||||
{
|
||||
positionToAlignTo.X = objectToAlignTo.GetAxisAlignedBoundingBox().maxXYZ.X;
|
||||
}
|
||||
if (IsSet(boundingFacesToAlignTo, Face.Front, Face.Back))
|
||||
{
|
||||
positionToAlignTo.Y = objectToAlignTo.GetAxisAlignedBoundingBox().minXYZ.Y;
|
||||
}
|
||||
if (IsSet(boundingFacesToAlignTo, Face.Back, Face.Front))
|
||||
{
|
||||
positionToAlignTo.Y = objectToAlignTo.GetAxisAlignedBoundingBox().maxXYZ.Y;
|
||||
}
|
||||
if (IsSet(boundingFacesToAlignTo, Face.Bottom, Face.Top))
|
||||
{
|
||||
positionToAlignTo.Z = objectToAlignTo.GetAxisAlignedBoundingBox().minXYZ.Z;
|
||||
}
|
||||
if (IsSet(boundingFacesToAlignTo, Face.Top, Face.Bottom))
|
||||
{
|
||||
positionToAlignTo.Z = objectToAlignTo.GetAxisAlignedBoundingBox().maxXYZ.Z;
|
||||
}
|
||||
return positionToAlignTo + extraOffset;
|
||||
}
|
||||
|
||||
public void Rebuild(UndoBuffer undoBuffer)
|
||||
{
|
||||
var aabb = this.GetAxisAlignedBoundingBox();
|
||||
|
||||
// TODO: check if the has code for the children
|
||||
if (OriginalChildrenBounds.Count == 0)
|
||||
{
|
||||
this.Children.Modify(list =>
|
||||
{
|
||||
foreach (var child in list)
|
||||
{
|
||||
OriginalChildrenBounds.Add(child.GetAxisAlignedBoundingBox());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
var currentChildrenBounds = CurrentChildrenBounds;
|
||||
this.Children.Modify(list =>
|
||||
{
|
||||
var firstBounds = currentChildrenBounds[0];
|
||||
int i = 0;
|
||||
foreach (var child in list)
|
||||
{
|
||||
if (i > 0)
|
||||
{
|
||||
if (XAlign == Align.None)
|
||||
{
|
||||
// make sure it is where it started
|
||||
AlignAxis(0, Align.Min, currentChildrenBounds[i].minXYZ.X, 0, child);
|
||||
}
|
||||
else
|
||||
{
|
||||
AlignAxis(0, XAlign, GetAlignToOffset(currentChildrenBounds, 0, (!Advanced || XAlignTo == Align.None) ? XAlign : XAlignTo), XOffset, child);
|
||||
}
|
||||
if (YAlign == Align.None)
|
||||
{
|
||||
AlignAxis(1, Align.Min, currentChildrenBounds[i].minXYZ.Y, 0, child);
|
||||
}
|
||||
else
|
||||
{
|
||||
AlignAxis(1, YAlign, GetAlignToOffset(currentChildrenBounds, 1, (!Advanced || YAlignTo == Align.None) ? YAlign : YAlignTo), YOffset, child);
|
||||
}
|
||||
if (ZAlign == Align.None)
|
||||
{
|
||||
AlignAxis(2, Align.Min, currentChildrenBounds[i].minXYZ.Z, 0, child);
|
||||
}
|
||||
else
|
||||
{
|
||||
AlignAxis(2, ZAlign, GetAlignToOffset(currentChildrenBounds, 2, (!Advanced || ZAlignTo == Align.None) ? ZAlign : ZAlignTo), ZOffset, child);
|
||||
}
|
||||
}
|
||||
i++;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public override void Remove()
|
||||
{
|
||||
// put everything back to where it was before the arange started
|
||||
if (OriginalChildrenBounds.Count == Children.Count)
|
||||
{
|
||||
int i = 0;
|
||||
foreach (var child in Children)
|
||||
{
|
||||
// Where you are minus where you started to get back to where you started
|
||||
child.Translate(-(child.GetAxisAlignedBoundingBox().minXYZ - OriginalChildrenBounds[i].minXYZ));
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
base.Remove();
|
||||
}
|
||||
|
||||
public void UpdateControls(PublicPropertyEditor editor)
|
||||
{
|
||||
editor.GetEditRow(nameof(XAlignTo)).Visible = Advanced;
|
||||
editor.GetEditRow(nameof(XOffset)).Visible = Advanced;
|
||||
editor.GetEditRow(nameof(YAlignTo)).Visible = Advanced;
|
||||
editor.GetEditRow(nameof(YOffset)).Visible = Advanced;
|
||||
editor.GetEditRow(nameof(ZAlignTo)).Visible = Advanced;
|
||||
editor.GetEditRow(nameof(ZOffset)).Visible = Advanced;
|
||||
}
|
||||
|
||||
private static bool IsSet(Face variableToCheck, Face faceToCheckFor, Face faceToAssertNot)
|
||||
{
|
||||
if ((variableToCheck & faceToCheckFor) != 0)
|
||||
{
|
||||
if ((variableToCheck & faceToAssertNot) != 0)
|
||||
{
|
||||
throw new Exception("You cannot have both " + faceToCheckFor.ToString() + " and " + faceToAssertNot.ToString() + " set when calling Align. The are mutually exclusive.");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private void AlignAxis(int axis, Align align, double alignTo, double offset,
|
||||
IObject3D item)
|
||||
{
|
||||
var aabb = item.GetAxisAlignedBoundingBox();
|
||||
var translate = Vector3.Zero;
|
||||
|
||||
switch (align)
|
||||
{
|
||||
case Align.Min:
|
||||
translate[axis] = alignTo - aabb.minXYZ[axis] + offset;
|
||||
break;
|
||||
|
||||
case Align.Center:
|
||||
translate[axis] = alignTo - aabb.Center[axis] + offset;
|
||||
break;
|
||||
|
||||
case Align.Max:
|
||||
translate[axis] = alignTo - aabb.maxXYZ[axis] + offset;
|
||||
break;
|
||||
}
|
||||
|
||||
item.Translate(translate);
|
||||
}
|
||||
|
||||
private double GetAlignToOffset(List<Aabb> currentChildrenBounds, int axis, Align alignTo)
|
||||
{
|
||||
switch (alignTo)
|
||||
{
|
||||
case Align.Min:
|
||||
return currentChildrenBounds[0].minXYZ[axis];
|
||||
|
||||
case Align.Center:
|
||||
return currentChildrenBounds[0].Center[axis];
|
||||
|
||||
case Align.Max:
|
||||
return currentChildrenBounds[0].maxXYZ[axis];
|
||||
|
||||
default:
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,234 +0,0 @@
|
|||
/*
|
||||
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.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using MatterHackers.Agg.UI;
|
||||
using MatterHackers.DataConverters3D;
|
||||
using MatterHackers.Localizations;
|
||||
using MatterHackers.VectorMath;
|
||||
|
||||
namespace MatterHackers.MatterControl.DesignTools.Operations
|
||||
{
|
||||
using Aabb = AxisAlignedBoundingBox;
|
||||
|
||||
public class Arrange3D : Object3D, IRebuildable, IPropertyGridModifier
|
||||
{
|
||||
// We need to serialize this so we can remove the arrange and get back to the objects before arranging
|
||||
public List<Aabb> OriginalChildrenBounds = new List<Aabb>();
|
||||
List<Aabb> CurrentChildrenBounds
|
||||
{
|
||||
get
|
||||
{
|
||||
List<Aabb> currentChildrenBounds = new List<Aabb>();
|
||||
this.Children.Modify(list =>
|
||||
{
|
||||
foreach (var child in list)
|
||||
{
|
||||
currentChildrenBounds.Add(child.GetAxisAlignedBoundingBox());
|
||||
}
|
||||
});
|
||||
|
||||
return currentChildrenBounds;
|
||||
}
|
||||
}
|
||||
|
||||
public Arrange3D()
|
||||
{
|
||||
Name = "Arrange".Localize();
|
||||
}
|
||||
|
||||
public enum Align { None, Min, Center, Max }
|
||||
|
||||
public override bool CanBake => true;
|
||||
|
||||
public override bool CanRemove => true;
|
||||
|
||||
[DisplayName("X")]
|
||||
[Icons(new string[] { "424.png", "align_left.png", "align_center_x.png", "align_right.png" })]
|
||||
public Align XAlign { get; set; } = Align.None;
|
||||
|
||||
[DisplayName("Start X")]
|
||||
[Icons(new string[] { "424.png", "align_to_left.png", "align_to_center_x.png", "align_to_right.png" })]
|
||||
public Align XAlignTo { get; set; } = Align.None;
|
||||
|
||||
[DisplayName("Offset X")]
|
||||
public double XOffset { get; set; } = 0;
|
||||
|
||||
[DisplayName("Y")]
|
||||
[Icons(new string[] { "424.png", "align_bottom.png", "align_center_y.png", "align_top.png" })]
|
||||
public Align YAlign { get; set; } = Align.None;
|
||||
|
||||
[DisplayName("Start Y")]
|
||||
[Icons(new string[] { "424.png", "align_to_bottom.png", "align_to_center_y.png", "align_to_top.png" })]
|
||||
public Align YAlignTo { get; set; } = Align.None;
|
||||
|
||||
[DisplayName("Offset Y")]
|
||||
public double YOffset { get; set; } = 0;
|
||||
|
||||
[DisplayName("Z")]
|
||||
[Icons(new string[] { "424.png", "align_bottom.png", "align_center_y.png", "align_top.png" })]
|
||||
public Align ZAlign { get; set; } = Align.None;
|
||||
|
||||
[DisplayName("Start Z")]
|
||||
[Icons(new string[] { "424.png", "align_to_bottom.png", "align_to_center_y.png", "align_to_top.png" })]
|
||||
public Align ZAlignTo { get; set; } = Align.None;
|
||||
|
||||
[DisplayName("Offset Z")]
|
||||
public double ZOffset { get; set; } = 0;
|
||||
|
||||
public bool Advanced { get; set; } = false;
|
||||
|
||||
public void Rebuild(UndoBuffer undoBuffer)
|
||||
{
|
||||
var aabb = this.GetAxisAlignedBoundingBox();
|
||||
|
||||
// TODO: check if the has code for the children
|
||||
if (OriginalChildrenBounds.Count == 0)
|
||||
{
|
||||
this.Children.Modify(list =>
|
||||
{
|
||||
foreach (var child in list)
|
||||
{
|
||||
OriginalChildrenBounds.Add(child.GetAxisAlignedBoundingBox());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
var currentChildrenBounds = CurrentChildrenBounds;
|
||||
this.Children.Modify(list =>
|
||||
{
|
||||
var firstBounds = currentChildrenBounds[0];
|
||||
int i = 0;
|
||||
foreach (var child in list)
|
||||
{
|
||||
if (i > 0)
|
||||
{
|
||||
if (XAlign == Align.None)
|
||||
{
|
||||
// make sure it is where it started
|
||||
AlignAxis(0, Align.Min, currentChildrenBounds[i].minXYZ.X, 0, child);
|
||||
}
|
||||
else
|
||||
{
|
||||
AlignAxis(0, XAlign, GetAlignToOffset(currentChildrenBounds, 0, (!Advanced || XAlignTo == Align.None) ? XAlign : XAlignTo), XOffset, child);
|
||||
}
|
||||
if (YAlign == Align.None)
|
||||
{
|
||||
AlignAxis(1, Align.Min, currentChildrenBounds[i].minXYZ.Y, 0, child);
|
||||
}
|
||||
else
|
||||
{
|
||||
AlignAxis(1, YAlign, GetAlignToOffset(currentChildrenBounds, 1, (!Advanced || YAlignTo == Align.None) ? YAlign : YAlignTo), YOffset, child);
|
||||
}
|
||||
if (ZAlign == Align.None)
|
||||
{
|
||||
AlignAxis(2, Align.Min, currentChildrenBounds[i].minXYZ.Z, 0, child);
|
||||
}
|
||||
else
|
||||
{
|
||||
AlignAxis(2, ZAlign, GetAlignToOffset(currentChildrenBounds, 2, (!Advanced || ZAlignTo == Align.None) ? ZAlign : ZAlignTo), ZOffset, child);
|
||||
}
|
||||
}
|
||||
i++;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public override void Remove()
|
||||
{
|
||||
// put everything back to where it was before the arange started
|
||||
if (OriginalChildrenBounds.Count == Children.Count)
|
||||
{
|
||||
int i = 0;
|
||||
foreach (var child in Children)
|
||||
{
|
||||
// Where you are minus where you started to get back to where you started
|
||||
child.Translate(-(child.GetAxisAlignedBoundingBox().minXYZ - OriginalChildrenBounds[i].minXYZ));
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
base.Remove();
|
||||
}
|
||||
|
||||
public void UpdateControls(PublicPropertyEditor editor)
|
||||
{
|
||||
editor.GetEditRow(nameof(XAlignTo)).Visible = Advanced;
|
||||
editor.GetEditRow(nameof(XOffset)).Visible = Advanced;
|
||||
editor.GetEditRow(nameof(YAlignTo)).Visible = Advanced;
|
||||
editor.GetEditRow(nameof(YOffset)).Visible = Advanced;
|
||||
editor.GetEditRow(nameof(ZAlignTo)).Visible = Advanced;
|
||||
editor.GetEditRow(nameof(ZOffset)).Visible = Advanced;
|
||||
}
|
||||
|
||||
private void AlignAxis(int axis, Align align, double alignTo, double offset,
|
||||
IObject3D item)
|
||||
{
|
||||
var aabb = item.GetAxisAlignedBoundingBox();
|
||||
var translate = Vector3.Zero;
|
||||
|
||||
switch (align)
|
||||
{
|
||||
case Align.Min:
|
||||
translate[axis] = alignTo - aabb.minXYZ[axis] + offset;
|
||||
break;
|
||||
|
||||
case Align.Center:
|
||||
translate[axis] = alignTo - aabb.Center[axis] + offset;
|
||||
break;
|
||||
|
||||
case Align.Max:
|
||||
translate[axis] = alignTo - aabb.maxXYZ[axis] + offset;
|
||||
break;
|
||||
}
|
||||
|
||||
item.Translate(translate);
|
||||
}
|
||||
|
||||
private double GetAlignToOffset(List<Aabb> currentChildrenBounds, int axis, Align alignTo)
|
||||
{
|
||||
switch (alignTo)
|
||||
{
|
||||
case Align.Min:
|
||||
return currentChildrenBounds[0].minXYZ[axis];
|
||||
|
||||
case Align.Center:
|
||||
return currentChildrenBounds[0].Center[axis];
|
||||
|
||||
case Align.Max:
|
||||
return currentChildrenBounds[0].maxXYZ[axis];
|
||||
|
||||
default:
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -60,6 +60,41 @@ namespace MatterHackers.MatterControl.DesignTools.Operations
|
|||
{
|
||||
}
|
||||
|
||||
public override void Bake()
|
||||
{
|
||||
// push our matrix into our children
|
||||
foreach (var child in this.Children)
|
||||
{
|
||||
child.Matrix *= this.Matrix;
|
||||
}
|
||||
|
||||
// push child into children
|
||||
ItemToScale.Matrix *= ScaleItem.Matrix;
|
||||
|
||||
// add our children to our parent and remove from parent
|
||||
this.Parent.Children.Modify(list =>
|
||||
{
|
||||
list.Remove(this);
|
||||
list.AddRange(ScaleItem.Children);
|
||||
});
|
||||
}
|
||||
|
||||
public override void Remove()
|
||||
{
|
||||
// push our matrix into inner children
|
||||
foreach (var child in ScaleItem.Children)
|
||||
{
|
||||
child.Matrix *= this.Matrix;
|
||||
}
|
||||
|
||||
// add inner children to our parent and remove from parent
|
||||
this.Parent.Children.Modify(list =>
|
||||
{
|
||||
list.Remove(this);
|
||||
list.AddRange(ScaleItem.Children);
|
||||
});
|
||||
}
|
||||
|
||||
protected override void OnInvalidate()
|
||||
{
|
||||
// If the child bounds changed than adjust the scale control
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ namespace MatterHackers.MatterControl.DesignTools.Operations
|
|||
fit.Rebuild(null);
|
||||
}
|
||||
|
||||
var align = this.Descendants<Arrange3D>().FirstOrDefault();
|
||||
var align = this.Descendants<Align3D>().FirstOrDefault();
|
||||
if (align != null)
|
||||
{
|
||||
align.Rebuild(null);
|
||||
|
|
|
|||
|
|
@ -95,14 +95,13 @@
|
|||
<Compile Include="DesignTools\Interfaces\IEditorDraw.cs" />
|
||||
<Compile Include="DesignTools\Interfaces\IPropertyGridModifier.cs" />
|
||||
<Compile Include="DesignTools\Interfaces\IRebuildable.cs" />
|
||||
<Compile Include="DesignTools\Operations\Arrange3D.cs" />
|
||||
<Compile Include="DesignTools\Operations\Align3D.cs" />
|
||||
<Compile Include="DesignTools\Operations\ArrayAdvanced3D.cs" />
|
||||
<Compile Include="DesignTools\Operations\ArrayLinear3D.cs" />
|
||||
<Compile Include="DesignTools\Operations\ArrayRadial3D.cs" />
|
||||
<Compile Include="DesignTools\Operations\BendObject3D.cs" />
|
||||
<Compile Include="DesignTools\Operations\FitToBounds3D.cs" />
|
||||
<Compile Include="DesignTools\Operations\Object3DExtensions.cs" />
|
||||
<Compile Include="DesignTools\Operations\Align.cs" />
|
||||
<Compile Include="DesignTools\Operations\Package3D.cs" />
|
||||
<Compile Include="DesignTools\Operations\Rotate.cs" />
|
||||
<Compile Include="DesignTools\Operations\Scale.cs" />
|
||||
|
|
|
|||
|
|
@ -91,7 +91,7 @@ namespace MatterHackers.MatterControl.DesignTools
|
|||
};
|
||||
textObject.Rebuild(null);
|
||||
IObject3D letterObject = new Rotate(textObject, -MathHelper.Tau / 4);
|
||||
letterObject = new Align(letterObject, Face.Bottom | Face.Front, brailleLetter, Face.Top | Face.Front, 0, 0, 3.5);
|
||||
letterObject = new Align3D(letterObject, Face.Bottom | Face.Front, brailleLetter, Face.Top | Face.Front, 0, 0, 3.5);
|
||||
letterObject = new SetCenter(letterObject, brailleLetter.GetCenter(), true, false, false);
|
||||
this.Children.Add(letterObject);
|
||||
|
||||
|
|
@ -106,13 +106,13 @@ namespace MatterHackers.MatterControl.DesignTools
|
|||
Matrix = Matrix4X4.CreateRotationX(MathHelper.Tau / 4)
|
||||
};
|
||||
|
||||
basePlate = new Align(basePlate, Face.Bottom | Face.Back, brailleLetter, Face.Bottom | Face.Back);
|
||||
basePlate = new Align3D(basePlate, Face.Bottom | Face.Back, brailleLetter, Face.Bottom | Face.Back);
|
||||
basePlate = new SetCenter(basePlate, brailleLetter.GetCenter(), true, false, false);
|
||||
this.Children.Add(basePlate);
|
||||
|
||||
IObject3D underline = new CubeObject3D(basePlate.XSize(), .2, 1);
|
||||
underline = new Align(underline, Face.Bottom, brailleLetter, Face.Top);
|
||||
underline = new Align(underline, Face.Back | Face.Left, basePlate, Face.Front | Face.Left, 0, .01);
|
||||
underline = new Align3D(underline, Face.Bottom, brailleLetter, Face.Top);
|
||||
underline = new Align3D(underline, Face.Back | Face.Left, basePlate, Face.Front | Face.Left, 0, .01);
|
||||
this.Children.Add(underline);
|
||||
|
||||
if (aabb.ZSize > 0)
|
||||
|
|
|
|||
|
|
@ -194,8 +194,8 @@ namespace MatterHackers.MatterControl.DesignTools
|
|||
Mesh = VertexSourceToMesh.Extrude(basePath, BaseHeight)
|
||||
};
|
||||
|
||||
basePlate = new Align(basePlate, Face.Top, textObject, Face.Bottom, 0, 0, .01);
|
||||
basePlate = new Align(basePlate, Face.Left | Face.Front,
|
||||
basePlate = new Align3D(basePlate, Face.Top, textObject, Face.Bottom, 0, 0, .01);
|
||||
basePlate = new Align3D(basePlate, Face.Left | Face.Front,
|
||||
size.Left - padding/2,
|
||||
size.Bottom - padding/2);
|
||||
this.Children.Add(basePlate);
|
||||
|
|
@ -234,7 +234,7 @@ namespace MatterHackers.MatterControl.DesignTools
|
|||
Matrix = Matrix4X4.CreateRotationX(MathHelper.Tau / 4)
|
||||
};
|
||||
|
||||
chainHook = new Align(chainHook, Face.Left | Face.Bottom | Face.Back, basePlate, Face.Right | Face.Bottom | Face.Back, -.01);
|
||||
chainHook = new Align3D(chainHook, Face.Left | Face.Bottom | Face.Back, basePlate, Face.Right | Face.Bottom | Face.Back, -.01);
|
||||
|
||||
this.Children.Add(chainHook);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue