mattercontrol/TextCreator/CardHolderTool/MeshObjects.cs
2018-01-21 17:03:22 -08:00

934 lines
No EOL
27 KiB
C#

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Threading;
using MatterHackers.Agg;
using MatterHackers.Agg.Font;
using MatterHackers.Agg.Platform;
using MatterHackers.Agg.VertexSource;
using MatterHackers.DataConverters3D;
using MatterHackers.MatterControl.MatterCad;
using MatterHackers.MatterControl.PartPreviewWindow.View3D;
using MatterHackers.PolygonMesh;
using MatterHackers.RenderOpenGl;
using MatterHackers.VectorMath;
namespace MatterHackers.MatterControl.MeshObjects
{
public enum Alignment { X, Y, Z, negX, negY, negZ };
[Flags]
public enum Face
{
Left = 0x01,
Right = 0x02,
Front = 0x04,
Back = 0x08,
Bottom = 0x10,
Top = 0x20,
};
[Flags]
public enum Edge
{
LeftFront = Face.Left | Face.Front,
LeftBack = Face.Left | Face.Back,
LeftBottom = Face.Left | Face.Bottom,
LeftTop = Face.Left | Face.Top,
RightFront = Face.Right | Face.Front,
RightBack = Face.Right | Face.Back,
RightBottom = Face.Right | Face.Bottom,
RightTop = Face.Right | Face.Top,
FrontBottom = Face.Front | Face.Bottom,
FrontTop = Face.Front | Face.Top,
BackBottom = Face.Back | Face.Bottom,
BackTop = Face.Back | Face.Top
}
public class BadSubtract : MatterCadObject3D
{
public BadSubtract()
{
RebuildMeshes();
}
public double Sides { get; set; } = 4;
public override void RebuildMeshes()
{
int sides = 3;
IObject3D keep = new Cylinder(20, 20, sides);
IObject3D subtract = new Cylinder(10, 21, sides);
subtract = new SetCenter(subtract, keep.GetCenter());
IObject3D result = keep.Minus(subtract);
this.SetChildren(result);
}
}
public class SetCenter : Object3D
{
public SetCenter()
{
}
public SetCenter(IObject3D item, Vector3 position)
{
Matrix *= Matrix4X4.CreateTranslation(position - item.GetCenter());
Children.Add(item.Clone());
}
public SetCenter(IObject3D item, double x, double y, double z)
: this(item, new Vector3(x, y, z))
{
}
public SetCenter(IObject3D item, Vector3 offset, bool onX = true, bool onY = true, bool onZ = true)
{
var center = item.GetAxisAlignedBoundingBox(Matrix4X4.Identity).Center;
Vector3 consideredOffset = Vector3.Zero; // zero out anything we don't want
if (onX)
{
consideredOffset.X = offset.X - center.X;
}
if (onY)
{
consideredOffset.Y = offset.Y - center.Y;
}
if (onZ)
{
consideredOffset.Z = offset.Z - center.Z;
}
Matrix *= Matrix4X4.CreateTranslation(consideredOffset);
Children.Add(item.Clone());
}
}
public class Cylinder : Object3D
{
public Cylinder()
{
}
public Cylinder(double radius, double height, int sides, Alignment alignment = Alignment.Z)
: this(radius, radius, height, sides, alignment)
{
}
public Cylinder(double radiusBottom, double radiusTop, double height, int sides, Alignment alignment = Alignment.Z)
{
var path = new VertexStorage();
path.MoveTo(0, -height/2);
path.LineTo(radiusBottom, -height/2);
path.LineTo(radiusTop, height/2);
path.LineTo(0, height/2);
Mesh = VertexSourceToMesh.Revolve(path, sides);
switch (alignment)
{
case Alignment.X:
Matrix = Matrix4X4.CreateRotationY(MathHelper.Tau / 4);
break;
case Alignment.Y:
Matrix = Matrix4X4.CreateRotationX(MathHelper.Tau / 4);
break;
case Alignment.Z:
// This is the natural case (how it was modled)
break;
case Alignment.negX:
Matrix = Matrix4X4.CreateRotationY(-MathHelper.Tau / 4);
break;
case Alignment.negY:
Matrix = Matrix4X4.CreateRotationX(-MathHelper.Tau / 4);
break;
case Alignment.negZ:
Matrix = Matrix4X4.CreateRotationX(MathHelper.Tau / 2);
break;
}
}
}
public class CardHolder : MatterCadObject3D
{
public CardHolder()
{
RebuildMeshes();
}
[DisplayName("Name")]
public string NameToWrite { get; set; } = "MatterHackers";
public override void RebuildMeshes()
{
IObject3D plainCardHolder = Object3D.Load("C:/Temp/CardHolder.stl");
//TypeFace typeFace = TypeFace.LoadSVG("Viking_n.svg");
var letterPrinter = new TypeFacePrinter(NameToWrite);//, new StyledTypeFace(typeFace, 12));
IObject3D nameMesh = new Object3D()
{
Mesh = VertexSourceToMesh.Extrude(letterPrinter, 5)
};
AxisAlignedBoundingBox textBounds = nameMesh.GetAxisAlignedBoundingBox(Matrix4X4.Identity);
var textArea = new Vector2(90, 20);
// test the area that the names will go to
// nameMesh = new Box(textArea.X, textArea.Y, 5);
double scale = Math.Min(textArea.X / textBounds.XSize, textArea.Y / textBounds.YSize);
nameMesh = new Scale(nameMesh, scale, scale, 1);
nameMesh = new Align(nameMesh, Face.Bottom | Face.Front, plainCardHolder, Face.Bottom | Face.Front);
nameMesh = new SetCenter(nameMesh, plainCardHolder.GetCenter(), true, false, false);
nameMesh = new Rotate(nameMesh, MathHelper.DegreesToRadians(-16));
nameMesh = new Translate(nameMesh, 0, 4, 2);
// output two meshes for card holder and text
this.Children.Modify(list =>
{
list.Clear();
list.Add(plainCardHolder);
list.Add(nameMesh);
});
}
}
/*
public class ChairFoot2 : MatterCadObject3D
{
public ChairFoot()
{
RebuildMeshes();
}
[DisplayName("Angle")]
public double AngleDegrees { get; set; } = 3;
// these are the public variables that would be edited
[DisplayName("Final")]
public bool FinalPart { get; set; } = true;
[DisplayName("Height")]
public double HeightFromFloorToBottomOfLeg { get; set; } = 10;
[DisplayName("Inner Size")]
public double InnerSize { get; set; } = 20;
[DisplayName("Reach")]
public double InsideReach { get; set; } = 10;
[DisplayName("Outer Size")]
public double OuterSize { get; set; } = 22;
public override void RebuildMeshes()
{
// This would be better expressed as the desired offset height (height from ground to bottom of chair leg).
double angleRadians = MathHelper.DegreesToRadians(AngleDegrees);
double extraHeightForRotation = Math.Sinh(angleRadians) * OuterSize; // get the distance to clip off the extra bottom
double unclippedFootHeight = HeightFromFloorToBottomOfLeg + extraHeightForRotation;
if (FinalPart)
{
Box chairFootBox = new Box(OuterSize, OuterSize, unclippedFootHeight);
//chairFootBox.BevelEdge(Edge.LeftBack, 2);
//chairFootBox.BevelEdge(Edge.LeftFront, 2);
//chairFootBox.BevelEdge(Edge.RightBack, 2);
//chairFootBox.BevelEdge(Edge.RightFront, 2);
IObject3D chairFoot = chairFootBox;
IObject3D ring = new Cylinder(InnerSize / 2 - 1, InsideReach, 30);
ring -= new Cylinder(ring.XSize / 2 - 2, ring.ZSize + 1, 30);
IObject3D fins = new Box(3, 1, ring.ZSize);
fins = new Translate(fins, 0, 1) + new Translate(fins, 0, -1);
fins -= new Align(new Rotate(new Box(5, 5, 5), 0, MathHelper.DegreesToRadians(45)), Face.Bottom | Face.Left, fins, Face.Top | Face.Left, 0, 0, -fins.XSize);
fins = new Translate(fins, InnerSize / 2 - .1);
ring += new Rotate(fins, 0, 0, MathHelper.DegreesToRadians(45));
ring += new Rotate(fins, 0, 0, MathHelper.DegreesToRadians(45 + 90));
ring += new Rotate(fins, 0, 0, MathHelper.DegreesToRadians(45 + 180));
ring += new Rotate(fins, 0, 0, MathHelper.DegreesToRadians(45 - 90));
chairFoot += new Align(ring, Face.Bottom, chairFoot, Face.Top, 0, 0, -.1);
chairFoot = new Rotate(chairFoot, 0, angleRadians, 0);
IObject3D clipBox = new Align(new Box(OuterSize * 2, OuterSize * 2, unclippedFootHeight), Face.Top, chairFoot, Face.Bottom, 0, 0, extraHeightForRotation);
chairFoot -= clipBox;
chairFoot = new Translate(chairFoot, 0, 0, clipBox.GetAxisAlignedBoundingBox().maxXYZ.Z);
this.Mesh = CsgToMesh.Convert(chairFoot);
}
else // fit part
{
double baseHeight = 3;
double insideHeight = 4;
Box chairFootBox = new Box(OuterSize, OuterSize, baseHeight);
chairFootBox.BevelEdge(Edge.LeftBack, 2);
chairFootBox.BevelEdge(Edge.LeftFront, 2);
chairFootBox.BevelEdge(Edge.RightBack, 2);
chairFootBox.BevelEdge(Edge.RightFront, 2);
IObject3D chairFoot = chairFootBox;
IObject3D ring = new Cylinder(InnerSize / 2 - 1, insideHeight, 30);
ring -= new Cylinder(ring.XSize / 2 - 2, ring.ZSize + 1, 30);
IObject3D fins = new Box(3, 1, ring.ZSize);
fins = new Translate(fins, 0, 1) + new Translate(fins, 0, -1);
fins -= new Align(new Rotate(new Box(5, 5, 5), 0, MathHelper.DegreesToRadians(45)), Face.Bottom | Face.Left, fins, Face.Top | Face.Left, 0, 0, -fins.XSize);
fins = new Translate(fins, InnerSize / 2 - .1);
ring += new Rotate(fins, 0, 0, MathHelper.DegreesToRadians(45));
ring += new Rotate(fins, 0, 0, MathHelper.DegreesToRadians(45 + 90));
ring += new Rotate(fins, 0, 0, MathHelper.DegreesToRadians(45 + 180));
ring += new Rotate(fins, 0, 0, MathHelper.DegreesToRadians(45 - 90));
chairFoot += new Align(ring, Face.Bottom, chairFoot, Face.Top, 0, 0, -.1);
this.Mesh = CsgToMesh.Convert(chairFoot);
}
}
}
*/
public class CubePrimitive : MatterCadObject3D
{
public CubePrimitive()
{
RebuildMeshes();
}
public double Width { get; set; } = 20;
public double Depth { get; set; } = 20;
public double Height { get; set; } = 20;
public override void RebuildMeshes()
{
var aabb = AxisAlignedBoundingBox.Zero;
if (Mesh != null)
{
this.GetAxisAlignedBoundingBox();
}
Mesh = PlatonicSolids.CreateCube(Width, Depth, Height);
Mesh.CleanAndMergMesh(CancellationToken.None);
PlatingHelper.PlaceMeshAtHeight(this, aabb.minXYZ.Z);
}
}
public class CylinderPrimitive : MatterCadObject3D
{
public CylinderPrimitive()
{
RebuildMeshes();
}
public double Diameter { get; set; } = 20;
public double Height { get; set; } = 20;
public int Sides { get; set; } = 30;
public override void RebuildMeshes()
{
var aabb = AxisAlignedBoundingBox.Zero;
if (Mesh != null)
{
this.GetAxisAlignedBoundingBox();
}
var path = new VertexStorage();
path.MoveTo(0, 0);
path.LineTo(Diameter / 2, 0);
path.LineTo(Diameter / 2, Height);
path.LineTo(0, Height);
Mesh = VertexSourceToMesh.Revolve(path, Sides);
Mesh.CleanAndMergMesh(CancellationToken.None);
PlatingHelper.PlaceMeshAtHeight(this, aabb.minXYZ.Z);
}
}
public class ConePrimitive : MatterCadObject3D
{
public ConePrimitive()
{
RebuildMeshes();
}
[DisplayName("Diameter")]
public double Diameter { get; set; } = 20;
//[DisplayName("Top")]
//public double TopDiameter { get; set; } = 0;
public double Height { get; set; } = 20;
public int Sides { get; set; } = 30;
public override void RebuildMeshes()
{
var aabb = AxisAlignedBoundingBox.Zero;
if (Mesh != null)
{
this.GetAxisAlignedBoundingBox();
}
var path = new VertexStorage();
path.MoveTo(0, 0);
path.LineTo(Diameter / 2, 0);
path.LineTo(0, Height);
Mesh = VertexSourceToMesh.Revolve(path, Sides);
Mesh.CleanAndMergMesh(CancellationToken.None);
PlatingHelper.PlaceMeshAtHeight(this, aabb.minXYZ.Z);
}
}
public class TorusPrimitive : MatterCadObject3D
{
public TorusPrimitive()
{
RebuildMeshes();
}
[DisplayName("Inner Diameter")]
public double InnerDiameter { get; set; } = 10;
[DisplayName("Outer Diameter")]
public double OuterDiameter { get; set; } = 20;
[DisplayName("Toroid Sides")]
public int ToroidSides { get; set; } = 20;
[DisplayName("Ring Sides")]
public int PoleSides { get; set; } = 16;
public override void RebuildMeshes()
{
var aabb = AxisAlignedBoundingBox.Zero;
if (Mesh != null)
{
this.GetAxisAlignedBoundingBox();
}
var poleRadius = (OuterDiameter / 2 - InnerDiameter / 2) / 2;
var toroidRadius = InnerDiameter / 2 + poleRadius;
var path = new VertexStorage();
var angleDelta = MathHelper.Tau / PoleSides;
var angle = 0.0;
var circleCenter = new Vector2(toroidRadius, 0);
path.MoveTo(circleCenter + new Vector2(poleRadius * Math.Cos(angle), poleRadius * Math.Sin(angle)));
for (int i = 0; i < PoleSides; i++)
{
angle += angleDelta;
path.LineTo(circleCenter + new Vector2(poleRadius * Math.Cos(angle), poleRadius * Math.Sin(angle)));
}
Mesh = VertexSourceToMesh.Revolve(path, ToroidSides);
Mesh.CleanAndMergMesh(CancellationToken.None);
PlatingHelper.PlaceMeshAtHeight(this, aabb.minXYZ.Z);
}
}
public class SpherePrimitive : MatterCadObject3D
{
public SpherePrimitive()
{
RebuildMeshes();
}
public double Diameter { get; set; } = 20;
[DisplayName("Longitude Sides")]
public int LongitudeSides { get; set; } = 30;
[DisplayName("Latitude Sides")]
public int LatitudeSides { get; set; } = 20;
public override void RebuildMeshes()
{
var aabb = AxisAlignedBoundingBox.Zero;
if (Mesh != null)
{
this.GetAxisAlignedBoundingBox();
}
var path = new VertexStorage();
var angleDelta = MathHelper.Tau / 2 / LatitudeSides;
var angle = -MathHelper.Tau / 4;
var radius = Diameter / 2;
path.MoveTo(new Vector2(radius * Math.Cos(angle), radius * Math.Sin(angle)));
for (int i = 0; i < LatitudeSides; i++)
{
angle += angleDelta;
path.LineTo(new Vector2(radius * Math.Cos(angle), radius * Math.Sin(angle)));
}
Mesh = VertexSourceToMesh.Revolve(path, LongitudeSides);
PlatingHelper.PlaceMeshAtHeight(this, aabb.minXYZ.Z);
}
}
public class CurveTest : MatterCadObject3D
{
private PolygonMesh.Mesh inputMesh;
private PolygonMesh.Mesh transformedMesh;
public CurveTest()
{
var letterPrinter = new TypeFacePrinter("MatterHackers");
inputMesh = VertexSourceToMesh.Extrude(letterPrinter, 5);
transformedMesh = PolygonMesh.Mesh.Copy(inputMesh, CancellationToken.None);
RebuildMeshes();
}
[DisplayName("Angle")]
public double AngleDegrees { get; set; } = 0;
[DisplayName("Bend Up")]
public bool BendCW { get; set; } = true;
public override void RebuildMeshes()
{
if (AngleDegrees > 0)
{
var aabb = inputMesh.GetAxisAlignedBoundingBox();
// find the radius that will make the x-size sweep out the requested angle
// c = Tr ; r = c/T
var angleRadians = MathHelper.DegreesToRadians(AngleDegrees);
var circumference = aabb.XSize * MathHelper.Tau / angleRadians;
var radius = circumference / MathHelper.Tau;
var rotateXyPos = new Vector2(aabb.minXYZ.X, BendCW ? aabb.maxXYZ.Y : aabb.minXYZ.Y);
if (!BendCW)
{
angleRadians = -angleRadians;
}
for (int i = 0; i < transformedMesh.Vertices.Count; i++)
{
var pos = inputMesh.Vertices[i].Position;
var pos2D = new Vector2(pos);
Vector2 rotateSpace = pos2D - rotateXyPos;
var rotateRatio = rotateSpace.X / aabb.XSize;
rotateSpace.X = 0;
rotateSpace.Y += BendCW ? -radius : radius;
rotateSpace.Rotate(angleRadians * rotateRatio);
rotateSpace.Y += BendCW ? radius : -radius; ;
rotateSpace += rotateXyPos;
transformedMesh.Vertices[i].Position = new Vector3(rotateSpace.X, rotateSpace.Y, pos.Z);
}
}
else
{
for (int i = 0; i < transformedMesh.Vertices.Count; i++)
{
transformedMesh.Vertices[i].Position = inputMesh.Vertices[i].Position;
}
}
transformedMesh.MarkAsChanged();
transformedMesh.CalculateNormals();
this.Mesh = transformedMesh;
}
}
public class PinchTest : MatterCadObject3D
{
private PolygonMesh.Mesh inputMesh;
private PolygonMesh.Mesh transformedMesh;
public PinchTest()
{
var letterPrinter = new TypeFacePrinter("MatterHackers");
inputMesh = VertexSourceToMesh.Extrude(letterPrinter, 5);
transformedMesh = PolygonMesh.Mesh.Copy(inputMesh, CancellationToken.None);
RebuildMeshes();
}
[DisplayName("Back Ratio")]
public double PinchRatio { get; set; } = 1;
public override void RebuildMeshes()
{
var aabb = inputMesh.GetAxisAlignedBoundingBox();
for (int i = 0; i < transformedMesh.Vertices.Count; i++)
{
var pos = inputMesh.Vertices[i].Position;
var ratioToApply = PinchRatio;
var distFromCenter = pos.X - aabb.Center.X;
var distanceToPinch = distFromCenter * (1 - PinchRatio);
var delta = (aabb.Center.X + distFromCenter * ratioToApply) - pos.X;
// find out how much to pinch based on y position
var amountOfRatio = (pos.Y - aabb.minXYZ.Y) / aabb.YSize;
transformedMesh.Vertices[i].Position = new Vector3(pos.X + delta * amountOfRatio, pos.Y, pos.Z);
}
transformedMesh.MarkAsChanged();
transformedMesh.CalculateNormals();
this.Mesh = transformedMesh;
}
}
public class PvcT : MatterCadObject3D
{
private int sides = 50;
public PvcT()
{
RebuildMeshes();
}
[DisplayName("Inner Radius")]
public double InnerDiameter { get; set; } = 15;
[DisplayName("Outer Radius")]
public double OuterDiameter { get; set; } = 20;
public double BottomReach { get; set; } = 30;
public double FrontReach { get; set; } = 25;
public double TopReach { get; set; } = 30;
public override void RebuildMeshes()
{
IObject3D topBottomConnect = new Cylinder(OuterDiameter / 2, OuterDiameter, sides, Alignment.Y);
IObject3D frontConnect = new Cylinder(OuterDiameter / 2, OuterDiameter / 2, sides, Alignment.X);
frontConnect = new Align(frontConnect, Face.Right, topBottomConnect, Face.Right);
IObject3D bottomReach = new Rotate(CreateReach(BottomReach), -MathHelper.Tau / 4);
bottomReach = new Align(bottomReach, Face.Back, topBottomConnect, Face.Front, 0, .1);
IObject3D topReach = new Rotate(CreateReach(TopReach), MathHelper.Tau / 4);
topReach = new Align(topReach, Face.Front, topBottomConnect, Face.Back, 0, -.1);
IObject3D frontReach = new Rotate(CreateReach(FrontReach), 0, -MathHelper.Tau / 4);
frontReach = new Align(frontReach, Face.Left, topBottomConnect, Face.Right, -.1);
// output multiple meshes for pipe connector
this.Children.Modify(list =>
{
list.Clear();
list.Add(topBottomConnect);
list.Add(frontConnect);
list.Add(bottomReach);
list.Add(topReach);
list.Add(frontReach);
});
this.Color = Color.Transparent;
this.Mesh = null;
}
private IObject3D CreateReach(double reach)
{
var finWidth = 4.0;
var finLength = InnerDiameter;
var pattern = new VertexStorage();
pattern.MoveTo(0, 0);
pattern.LineTo(finLength/2, 0);
pattern.LineTo(finLength/2, reach - finLength / 8);
pattern.LineTo(finLength/2 - finLength / 8, reach);
pattern.LineTo(-finLength/2 + finLength / 8, reach);
pattern.LineTo(-finLength/2, reach - finLength / 8);
pattern.LineTo(-finLength/2, 0);
var fin1 = new Object3D()
{
Mesh = VertexSourceToMesh.Extrude(pattern, finWidth)
};
fin1 = new Translate(fin1, 0, 0, -finWidth / 2);
//fin1.ChamferEdge(Face.Top | Face.Back, finLength / 8);
//fin1.ChamferEdge(Face.Top | Face.Front, finLength / 8);
fin1 = new Rotate(fin1, -MathHelper.Tau / 4);
var fin2 = new SetCenter(new Rotate(fin1, 0, 0, MathHelper.Tau / 4), fin1.GetCenter());
return new Object3D().SetChildren(new List<IObject3D>() { fin1, fin2 });
}
}
public class RibonWithName : MatterCadObject3D
{
private static TypeFace typeFace = null;
public RibonWithName()
{
RebuildMeshes();
}
[DisplayName("Name")]
public string NameToWrite { get; set; } = "MatterHackers";
public override void RebuildMeshes()
{
IObject3D cancerRibonStl = Object3D.Load("Cancer_Ribbon.stl", CancellationToken.None);
cancerRibonStl = new Rotate(cancerRibonStl, MathHelper.DegreesToRadians(90));
if (typeFace == null)
{
typeFace = TypeFace.LoadFrom(AggContext.StaticData.ReadAllText(Path.Combine("Fonts", "TitilliumWeb-Black.svg")));
}
var letterPrinter = new TypeFacePrinter(NameToWrite.ToUpper(), new StyledTypeFace(typeFace, 12));
IObject3D nameMesh = new Object3D()
{
Mesh = VertexSourceToMesh.Extrude(letterPrinter, 5)
};
AxisAlignedBoundingBox textBounds = nameMesh.GetAxisAlignedBoundingBox();
var textArea = new Vector2(25, 6);
double scale = Math.Min(textArea.X / textBounds.XSize, textArea.Y / textBounds.YSize);
nameMesh = new Scale(nameMesh, scale, scale, 2 / textBounds.ZSize);
nameMesh = new Align(nameMesh, Face.Bottom | Face.Front, cancerRibonStl, Face.Top | Face.Front, 0, 0, -1);
nameMesh = new SetCenter(nameMesh, cancerRibonStl.GetCenter(), true, false, false);
nameMesh = new Rotate(nameMesh, 0, 0, MathHelper.DegreesToRadians(50));
nameMesh = new Translate(nameMesh, -37, -14, -1);
// output two meshes for card holder and text
this.Children.Modify(list =>
{
list.Clear();
list.Add(cancerRibonStl);
list.Add(nameMesh);
});
this.Mesh = null;
}
}
public class Box : Object3D
{
public Box(double x, double y, double z)
{
Mesh = PlatonicSolids.CreateCube(x, y, z);
Mesh.CleanAndMergMesh(CancellationToken.None);
}
}
public static class Object3DExtensions
{
public static IObject3D Translate(this IObject3D objectToTranslate, double x = 0, double y = 0, double z = 0, string name = "")
{
return objectToTranslate.Translate(new Vector3(x, y, z), name);
}
public static IObject3D Translate(this IObject3D objectToTranslate, Vector3 translation, string name = "")
{
objectToTranslate.Matrix *= Matrix4X4.CreateTranslation(translation);
return objectToTranslate;
}
public static IObject3D Minus(this IObject3D a, IObject3D b)
{
var resultsA = a.Clone();
SubtractEditor.Subtract(resultsA.VisibleMeshes().ToList(), b.VisibleMeshes().ToList());
return resultsA;
}
public static Vector3 GetCenter(this IObject3D item)
{
return item.GetAxisAlignedBoundingBox(Matrix4X4.Identity).Center;
}
public static IObject3D SetChildren(this IObject3D parent, IEnumerable<IObject3D> newChildren)
{
parent.Children.Modify((list) =>
{
list.Clear();
list.AddRange(newChildren);
});
return parent;
}
public static void SetChildren(this IObject3D parent, IObject3D newChild)
{
parent.Children.Modify((list) =>
{
list.Clear();
list.Add(newChild);
});
}
}
public class Translate : Object3D
{
public Translate()
{ }
public Translate(IObject3D item, double x = 0, double y = 0, double z = 0)
: this(item, new Vector3(x, y, z))
{
}
public Translate(IObject3D item, Vector3 translation)
{
Matrix *= Matrix4X4.CreateTranslation(translation);
Children.Add(item.Clone());
}
}
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 ot itself.");
}
}
public Align(IObject3D objectToAlign, Face boundingFacesToAlign, double offsetX = 0, double offsetY = 0, double offsetZ = 0, string name = "")
: this(objectToAlign, boundingFacesToAlign, new Vector3(offsetX, offsetY, offsetZ), 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 Rotate : Object3D
{
public Rotate()
{
}
public Rotate(IObject3D item, double x = 0, double y = 0, double z = 0, string name = "")
: this(item, new Vector3(x, y, z), name)
{
}
public Rotate(IObject3D item, Vector3 translation, string name = "")
{
Matrix *= Matrix4X4.CreateRotation(translation);
Children.Add(item.Clone());
}
}
public class Scale : Object3D
{
public Scale()
{
}
public Scale(IObject3D item, double x = 0, double y = 0, double z = 0, string name = "")
: this(item, new Vector3(x, y, z), name)
{
}
public Scale(IObject3D item, Vector3 translation, string name = "")
{
Matrix *= Matrix4X4.CreateScale(translation);
Children.Add(item.Clone());
}
}
public class TestPart : MatterCadObject3D
{
public TestPart()
{
RebuildMeshes();
}
public double XOffset { get; set; } = -.4;
public override void RebuildMeshes()
{
IObject3D boxCombine = new Box(10, 10, 10);
boxCombine = boxCombine.Minus(new Translate(new Box(10, 10, 10), XOffset, -3, 2));
this.SetChildren(boxCombine);
}
}
}