diff --git a/MatterControl.csproj b/MatterControl.csproj
index 80dd2f301..1783d0a78 100644
--- a/MatterControl.csproj
+++ b/MatterControl.csproj
@@ -549,10 +549,6 @@
{9B062971-A88E-4A3D-B3C9-12B78D15FA66}
clipper_library
-
- {7E61A5BD-E78F-4B80-88C9-3821B4FA062E}
- Csg
-
{04667764-DC7B-4B95-AEF6-B4E6C87A54E9}
DataConverters3D
diff --git a/PartPreviewWindow/View3D/Actions/SubtractEditor.cs b/PartPreviewWindow/View3D/Actions/SubtractEditor.cs
index bbbeca726..09b686284 100644
--- a/PartPreviewWindow/View3D/Actions/SubtractEditor.cs
+++ b/PartPreviewWindow/View3D/Actions/SubtractEditor.cs
@@ -184,55 +184,66 @@ namespace MatterHackers.MatterControl.PartPreviewWindow.View3D
var removeObjects = participants.Where((obj) => obj.OutputType == PrintOutputTypes.Hole).ToList();
var keepObjects = participants.Where((obj) => obj.OutputType != PrintOutputTypes.Hole).ToList();
- if (removeObjects.Any()
- && keepObjects.Any())
- {
- var totalOperations = removeObjects.Count * keepObjects.Count;
- double amountPerOperation = 1.0 / totalOperations;
- double percentCompleted = 0;
-
- foreach (var remove in removeObjects)
- {
- foreach (var keep in keepObjects)
- {
- progressStatus.Status = "Copy Remove";
- reporter.Report(progressStatus);
- var transformedRemove = Mesh.Copy(remove.Mesh, CancellationToken.None);
- transformedRemove.Transform(remove.WorldMatrix(null));
-
- progressStatus.Status = "Copy Keep";
- reporter.Report(progressStatus);
- var transformedKeep = Mesh.Copy(keep.Mesh, CancellationToken.None);
- transformedKeep.Transform(keep.WorldMatrix(null));
-
- progressStatus.Status = "Do CSG";
- reporter.Report(progressStatus);
- transformedKeep = PolygonMesh.Csg.CsgOperations.Subtract(transformedKeep, transformedRemove, (status, progress0To1) =>
- {
- // Abort if flagged
- cancellationToken.ThrowIfCancellationRequested();
-
- progressStatus.Status = status;
- progressStatus.Progress0To1 = percentCompleted + amountPerOperation * progress0To1;
- reporter.Report(progressStatus);
- }, cancellationToken);
- var inverse = keep.WorldMatrix(null);
- inverse.Invert();
- transformedKeep.Transform(inverse);
-
- keep.Mesh = transformedKeep;
- view3DWidget.Invalidate();
-
- percentCompleted += amountPerOperation;
- progressStatus.Progress0To1 = percentCompleted;
- reporter.Report(progressStatus);
- }
-
- remove.Visible = false;
- }
- }
+ Subtract(keepObjects, removeObjects, cancellationToken, reporter);
return Task.CompletedTask;
});
}
+
+ public static void Subtract(List keepObjects, List removeObjects)
+ {
+ Subtract(keepObjects, removeObjects, CancellationToken.None, null);
+ }
+
+ public static void Subtract(List keepObjects, List removeObjects, CancellationToken cancellationToken, IProgress reporter)
+ {
+ if (removeObjects.Any()
+ && keepObjects.Any())
+ {
+ var totalOperations = removeObjects.Count * keepObjects.Count;
+ double amountPerOperation = 1.0 / totalOperations;
+ double percentCompleted = 0;
+
+ ProgressStatus progressStatus = new ProgressStatus();
+ foreach (var remove in removeObjects)
+ {
+ foreach (var keep in keepObjects)
+ {
+ progressStatus.Status = "Copy Remove";
+ reporter?.Report(progressStatus);
+ var transformedRemove = Mesh.Copy(remove.Mesh, CancellationToken.None);
+ transformedRemove.Transform(remove.WorldMatrix(null));
+
+ progressStatus.Status = "Copy Keep";
+ reporter?.Report(progressStatus);
+ var transformedKeep = Mesh.Copy(keep.Mesh, CancellationToken.None);
+ transformedKeep.Transform(keep.WorldMatrix(null));
+
+ progressStatus.Status = "Do CSG";
+ reporter?.Report(progressStatus);
+ transformedKeep = PolygonMesh.Csg.CsgOperations.Subtract(transformedKeep, transformedRemove, (status, progress0To1) =>
+ {
+ // Abort if flagged
+ cancellationToken.ThrowIfCancellationRequested();
+
+ progressStatus.Status = status;
+ progressStatus.Progress0To1 = percentCompleted + amountPerOperation * progress0To1;
+ reporter?.Report(progressStatus);
+ }, cancellationToken);
+ var inverse = keep.WorldMatrix(null);
+ inverse.Invert();
+ transformedKeep.Transform(inverse);
+
+ keep.Mesh = transformedKeep;
+ keep.Invalidate();
+
+ percentCompleted += amountPerOperation;
+ progressStatus.Progress0To1 = percentCompleted;
+ reporter?.Report(progressStatus);
+ }
+
+ remove.Visible = false;
+ }
+ }
+ }
}
}
\ No newline at end of file
diff --git a/PartPreviewWindow/View3D/View3DWidget.cs b/PartPreviewWindow/View3D/View3DWidget.cs
index e8a821dbc..601e98ecb 100644
--- a/PartPreviewWindow/View3D/View3DWidget.cs
+++ b/PartPreviewWindow/View3D/View3DWidget.cs
@@ -854,6 +854,11 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
activeButtonBeforeMouseOverride = viewControls3D.ActiveButton;
viewControls3D.ActiveButton = ViewControls3DButtons.Translate;
}
+ else if(Keyboard.IsKeyDown(Keys.Alt))
+ {
+ activeButtonBeforeMouseOverride = viewControls3D.ActiveButton;
+ viewControls3D.ActiveButton = ViewControls3DButtons.Scale;
+ }
else
{
activeButtonBeforeMouseOverride = viewControls3D.ActiveButton;
diff --git a/Submodules/agg-sharp b/Submodules/agg-sharp
index d826d9291..8f747f763 160000
--- a/Submodules/agg-sharp
+++ b/Submodules/agg-sharp
@@ -1 +1 @@
-Subproject commit d826d929111ca15c045bedb64b9dee560824ea3f
+Subproject commit 8f747f76300429070c357dc37c5f0b3f0fe79703
diff --git a/Tests/MatterControl.Tests/MatterControl/ReleaseBuildTests.cs b/Tests/MatterControl.Tests/MatterControl/ReleaseBuildTests.cs
index 3064e65bc..e704fc573 100644
--- a/Tests/MatterControl.Tests/MatterControl/ReleaseBuildTests.cs
+++ b/Tests/MatterControl.Tests/MatterControl/ReleaseBuildTests.cs
@@ -41,7 +41,6 @@ namespace MatterControl.Tests
string knownAssemblies = @"MatterHackers.VectorMath.dll
AGG.dll
MatterHackers.PolygonMesh.dll
- MatterHackers.Csg.dll
clipper_library.dll
MatterHackers.Agg.UI.dll
Tesselate.dll
diff --git a/TextCreator/CardHolderTool/CardHolder.cs b/TextCreator/CardHolderTool/CardHolder.cs
deleted file mode 100644
index a208d5c75..000000000
--- a/TextCreator/CardHolderTool/CardHolder.cs
+++ /dev/null
@@ -1,621 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.ComponentModel;
-using System.IO;
-using System.Linq;
-using System.Reflection;
-using System.Threading;
-using MatterHackers.Agg;
-using MatterHackers.Agg.Font;
-using MatterHackers.Agg.Platform;
-using MatterHackers.Agg.UI;
-using MatterHackers.Csg;
-using MatterHackers.Csg.Solids;
-using MatterHackers.Csg.Transform;
-using MatterHackers.DataConverters3D;
-using MatterHackers.Localizations;
-using MatterHackers.MatterControl.CustomWidgets;
-using MatterHackers.MatterControl.PartPreviewWindow;
-using MatterHackers.RenderOpenGl;
-using MatterHackers.VectorMath;
-
-namespace MatterHackers.MatterControl.SimplePartScripting
-{
- public abstract class MatterCadObject3D : Object3D
- {
- public override string ActiveEditor { get; set; } = "MatterCadEditor";
-
- public abstract void RebuildMeshes();
- }
-
- public class MatterCadEditor : IObject3DEditor
- {
- private View3DWidget view3DWidget;
- private IObject3D item;
-
- public string Name => "MatterCad";
-
- public bool Unlocked { get; } = true;
-
- public IEnumerable SupportedTypes() => new Type[]
- {
- typeof(MatterCadObject3D),
- };
-
- public GuiWidget Create(IObject3D item, View3DWidget view3DWidget, ThemeConfig theme)
- {
- this.view3DWidget = view3DWidget;
- this.item = item;
-
- var mainContainer = new FlowLayoutWidget(FlowDirection.TopToBottom)
- {
- HAnchor = HAnchor.Stretch
- };
-
- if (item is MatterCadObject3D)
- {
- ModifyCadObject(view3DWidget, mainContainer, theme);
- }
-
- mainContainer.MinimumSize = new Vector2(250, 0);
- return mainContainer;
- }
-
- private void ModifyCadObject(View3DWidget view3DWidget, FlowLayoutWidget tabContainer, ThemeConfig theme)
- {
- var allowedTypes = new Type[] { typeof(double), typeof(string), typeof(bool) };
-
- var ownedPropertiesOnly = System.Reflection.BindingFlags.Public
- | System.Reflection.BindingFlags.Instance
- | System.Reflection.BindingFlags.DeclaredOnly;
-
- var editableProperties = this.item.GetType().GetProperties(ownedPropertiesOnly)
- .Where(pi => allowedTypes.Contains(pi.PropertyType)
- && pi.GetGetMethod() != null)
- .Select(p => new
- {
- Value = p.GetGetMethod().Invoke(this.item, null),
- DisplayName = GetDisplayName(p),
- PropertyInfo = p
- });
-
- foreach (var property in editableProperties)
- {
- // create a double editor
- if (property.Value is double doubleValue)
- {
- FlowLayoutWidget rowContainer = CreateSettingsRow(property.DisplayName.Localize());
- var doubleEditWidget = new MHNumberEdit(doubleValue, pixelWidth: 50 * GuiWidget.DeviceScale, allowNegatives: true, allowDecimals: true, increment: .05)
- {
- SelectAllOnFocus = true,
- VAnchor = VAnchor.Center
- };
- doubleEditWidget.ActuallNumberEdit.EditComplete += (s, e) =>
- {
- double editValue;
- if (double.TryParse(doubleEditWidget.Text, out editValue))
- {
- property.PropertyInfo.GetSetMethod().Invoke(this.item, new Object[] { editValue });
- }
- ((MatterCadObject3D)item).RebuildMeshes();
- };
- rowContainer.AddChild(doubleEditWidget);
- tabContainer.AddChild(rowContainer);
- }
- // create a bool editor
- else if (property.Value is bool boolValue)
- {
- FlowLayoutWidget rowContainer = CreateSettingsRow(property.DisplayName.Localize());
-
- var doubleEditWidget = new CheckBox("");
- doubleEditWidget.Checked = boolValue;
- doubleEditWidget.CheckedStateChanged += (s, e) =>
- {
- property.PropertyInfo.GetSetMethod().Invoke(this.item, new Object[] { doubleEditWidget.Checked });
- ((MatterCadObject3D)item).RebuildMeshes();
- };
- rowContainer.AddChild(doubleEditWidget);
- tabContainer.AddChild(rowContainer);
- }
- // create a bool editor
- else if (property.Value is string stringValue)
- {
- FlowLayoutWidget rowContainer = CreateSettingsRow(property.DisplayName.Localize());
- var textEditWidget = new MHTextEditWidget(stringValue, pixelWidth: 150 * GuiWidget.DeviceScale)
- {
- SelectAllOnFocus = true,
- VAnchor = VAnchor.Center
- };
- textEditWidget.ActualTextEditWidget.EditComplete += (s, e) =>
- {
- property.PropertyInfo.GetSetMethod().Invoke(this.item, new Object[] { textEditWidget.Text });
- ((MatterCadObject3D)item).RebuildMeshes();
- };
- rowContainer.AddChild(textEditWidget);
- tabContainer.AddChild(rowContainer);
- }
- }
-
- var updateButton = theme.ButtonFactory.Generate("Update".Localize());
- updateButton.Margin = new BorderDouble(5);
- updateButton.HAnchor = HAnchor.Right;
- updateButton.Click += (s, e) =>
- {
- ((MatterCadObject3D)item).RebuildMeshes();
- };
- tabContainer.AddChild(updateButton);
- }
-
- private string GetDisplayName(PropertyInfo prop)
- {
- var nameAttribute = prop.GetCustomAttributes(true).OfType().FirstOrDefault();
- return nameAttribute?.DisplayName ?? prop.Name;
- }
-
- private static FlowLayoutWidget CreateSettingsRow(string labelText)
- {
- var rowContainer = new FlowLayoutWidget(FlowDirection.LeftToRight)
- {
- HAnchor = HAnchor.Stretch,
- Padding = new BorderDouble(5)
- };
-
- var label = new TextWidget(labelText + ":", textColor: ActiveTheme.Instance.PrimaryTextColor)
- {
- Margin = new BorderDouble(0, 0, 3, 0),
- VAnchor = VAnchor.Center
- };
- rowContainer.AddChild(label);
-
- rowContainer.AddChild(new HorizontalSpacer());
-
- return rowContainer;
- }
- }
-
- public class TestPart : MatterCadObject3D
- {
- public double XOffset { get; set; } = -.4;
-
- public TestPart()
- {
- RebuildMeshes();
- }
-
- public override void RebuildMeshes()
- {
- CsgObject boxCombine = new Box(10, 10, 10);
- boxCombine -= new Translate(new Box(10, 10, 10), XOffset, -3, 2);
- this.Mesh = CsgToMesh.Convert(boxCombine);
- }
- }
-
- public class BadSubtract : MatterCadObject3D
- {
- public double Sides { get; set; } = 4;
-
- public BadSubtract()
- {
- RebuildMeshes();
- }
-
- public override void RebuildMeshes()
- {
- int sides = 3;
- CsgObject keep = new Cylinder(20, 20, sides);
- CsgObject subtract = new Cylinder(10, 21, sides);
- subtract = new SetCenter(subtract, keep.GetCenter());
- CsgObject result = keep - subtract;
- this.Mesh = CsgToMesh.Convert(result);
- }
- }
-
- public class CardHolder : MatterCadObject3D
- {
- [DisplayName("Name")]
- public string NameToWrite { get; set; } = "MatterHackers";
-
- public CardHolder()
- {
- RebuildMeshes();
- }
-
- public override void RebuildMeshes()
- {
- CsgObject plainCardHolder = new MeshContainer("PlainBusinessCardHolder.stl");
-
- //TypeFace typeFace = TypeFace.LoadSVG("Viking_n.svg");
-
- var letterPrinter = new TypeFacePrinter(NameToWrite);//, new StyledTypeFace(typeFace, 12));
- PolygonMesh.Mesh textMesh = VertexSourceToMesh.Extrude(letterPrinter, 5);
-
- CsgObject nameMesh = new MeshContainer(textMesh);
-
- AxisAlignedBoundingBox textBounds = textMesh.GetAxisAlignedBoundingBox();
- var textArea = new Vector2(85, 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.Top | Face.Front, plainCardHolder, Face.Bottom | Face.Front);
- nameMesh = new SetCenter(nameMesh, plainCardHolder.GetCenter(), true, false, false);
-
- nameMesh = new Rotate(nameMesh, MathHelper.DegreesToRadians(18));
- nameMesh = new Translate(nameMesh, 0, 2, 16);
-
- // output one combined mesh
- //plainCardHolder += nameMesh;
- //SetAndInvalidateMesh(CsgToMesh.Convert(plainCardHolder));
-
- // output two meshes for card holder and text
- this.Children.Modify(list =>
- {
- list.Clear();
- list.AddRange(new[]
- {
- new Object3D()
- {
- Mesh = CsgToMesh.Convert(plainCardHolder)
- },
- new Object3D()
- {
- Mesh = CsgToMesh.Convert(nameMesh)
- }
- });
- });
-
- this.Mesh = null;
- }
- }
-
- public class PvcT : MatterCadObject3D
- {
- [DisplayName("Outer Radius")]
- public double OuterDiameter { get; set; } = 20;
-
- [DisplayName("Inner Radius")]
- public double InnerDiameter { get; set; } = 15;
-
- public double BottomReach { get; set; } = 30;
- public double TopReach { get; set; } = 30;
- public double FrontReach { get; set; } = 25;
-
- private int sides = 50;
-
- public PvcT()
- {
- RebuildMeshes();
- }
-
- public override void RebuildMeshes()
- {
- CsgObject topBottomConnect = new Cylinder(OuterDiameter/2, OuterDiameter, sides, Alignment.y);
- CsgObject frontConnect = new Cylinder(OuterDiameter/2, OuterDiameter/2, sides, Alignment.x);
- frontConnect = new Align(frontConnect, Face.Right, topBottomConnect, Face.Right);
-
- CsgObject bottomReach = new Rotate(CreateReach(BottomReach), -MathHelper.Tau / 4);
- bottomReach = new Align(bottomReach, Face.Back, topBottomConnect, Face.Front, 0, 1);
-
- CsgObject topReach = new Rotate(CreateReach(TopReach), MathHelper.Tau / 4);
- topReach = new Align(topReach, Face.Front, topBottomConnect, Face.Back, 0, -1);
-
- CsgObject 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.AddRange(new[]
- {
- new Object3D()
- {
- Mesh = CsgToMesh.Convert(topBottomConnect),
- Color = Color.LightGray
- },
- new Object3D()
- {
- Mesh = CsgToMesh.Convert(frontConnect),
- Color = Color.LightGray
- },
- new Object3D()
- {
- Mesh = CsgToMesh.Convert(bottomReach),
- Color = Color.White
- },
- new Object3D()
- {
- Mesh = CsgToMesh.Convert(topReach),
- Color = Color.White
- },
- new Object3D()
- {
- Mesh = CsgToMesh.Convert(frontReach),
- Color = Color.White
- }
- });
- });
-
- this.Color = Color.Transparent;
- this.Mesh = null;
- }
-
- private CsgObject CreateReach(double reach)
- {
- var finWidth = 4.0;
- var finLength = InnerDiameter;
- var fin1 = new Box(finWidth, finLength, reach);
- fin1.ChamferEdge(Face.Top | Face.Back, finLength / 8);
- fin1.ChamferEdge(Face.Top | Face.Front, finLength / 8);
- CsgObject fin2 = new Rotate(fin1, 0, 0, MathHelper.Tau / 4);
-
- return fin1 + fin2;
- }
- }
-
- public class RibonWithName : MatterCadObject3D
- {
- [DisplayName("Name")]
- public string NameToWrite { get; set; } = "MatterHackers";
-
- static TypeFace typeFace = null;
-
- public RibonWithName()
- {
- RebuildMeshes();
- }
-
- public override void RebuildMeshes()
- {
- CsgObject cancerRibonStl = new MeshContainer("Cancer_Ribbon.stl");
-
- 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));
- PolygonMesh.Mesh textMesh = VertexSourceToMesh.Extrude(letterPrinter, 5);
-
- CsgObject nameMesh = new MeshContainer(textMesh);
-
- AxisAlignedBoundingBox textBounds = textMesh.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
-
- this.Children.Modify(list =>
- {
- list.Clear();
- list.AddRange(new[]
- {
- new Object3D()
- {
- Mesh = CsgToMesh.Convert(cancerRibonStl)
- },
- new Object3D()
- {
- Mesh = CsgToMesh.Convert(nameMesh)
- }
- });
- });
-
- this.Mesh = null;
- }
- }
-
- public class PinchTest : MatterCadObject3D
- {
- [DisplayName("Back Ratio")]
- public double PinchRatio { get; set; } = 1;
- PolygonMesh.Mesh inputMesh;
- PolygonMesh.Mesh transformedMesh;
-
- public PinchTest()
- {
- var letterPrinter = new TypeFacePrinter("MatterHackers");
- inputMesh = VertexSourceToMesh.Extrude(letterPrinter, 5);
- transformedMesh = PolygonMesh.Mesh.Copy(inputMesh, CancellationToken.None);
-
- RebuildMeshes();
- }
-
- 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 CurveTest : MatterCadObject3D
- {
- [DisplayName("Bend Up")]
- public bool BendCW { get; set; } = true;
-
- [DisplayName("Angle")]
- public double AngleDegrees { get; set; } = 0;
- PolygonMesh.Mesh inputMesh;
- PolygonMesh.Mesh transformedMesh;
-
- public CurveTest()
- {
- var letterPrinter = new TypeFacePrinter("MatterHackers");
- inputMesh = VertexSourceToMesh.Extrude(letterPrinter, 5);
- transformedMesh = PolygonMesh.Mesh.Copy(inputMesh, CancellationToken.None);
-
- RebuildMeshes();
- }
-
- 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 ChairFoot : MatterCadObject3D
- {
- // 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("Outer Size")]
- public double OuterSize { get; set; } = 22;
-
- [DisplayName("Inner Size")]
- public double InnerSize { get; set; } = 20;
- [DisplayName("Reach")]
- public double InsideReach { get; set; } = 10;
-
- [DisplayName("Angle")]
- public double AngleDegrees { get; set; } = 3;
-
- public ChairFoot()
- {
- RebuildMeshes();
- }
-
- 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);
- CsgObject chairFoot = chairFootBox;
-
- CsgObject ring = new Cylinder(InnerSize / 2 - 1, InsideReach, 30);
- ring -= new Cylinder(ring.XSize / 2 - 2, ring.ZSize + 1, 30);
-
- CsgObject 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);
- CsgObject 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);
- CsgObject chairFoot = chairFootBox;
-
- CsgObject ring = new Cylinder(InnerSize / 2 - 1, insideHeight, 30);
- ring -= new Cylinder(ring.XSize / 2 - 2, ring.ZSize + 1, 30);
-
- CsgObject 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);
- }
- }
- }
-}
diff --git a/TextCreator/CardHolderTool/MatterCadEditor.cs b/TextCreator/CardHolderTool/MatterCadEditor.cs
new file mode 100644
index 000000000..15f74a00c
--- /dev/null
+++ b/TextCreator/CardHolderTool/MatterCadEditor.cs
@@ -0,0 +1,166 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Linq;
+using System.Reflection;
+using MatterHackers.Agg;
+using MatterHackers.Agg.UI;
+using MatterHackers.DataConverters3D;
+using MatterHackers.Localizations;
+using MatterHackers.MatterControl.CustomWidgets;
+using MatterHackers.MatterControl.PartPreviewWindow;
+using MatterHackers.VectorMath;
+
+namespace MatterHackers.MatterControl.MatterCad
+{
+ public class MatterCadEditor : IObject3DEditor
+ {
+ private IObject3D item;
+ private View3DWidget view3DWidget;
+ public string Name => "MatterCad";
+
+ public bool Unlocked { get; } = true;
+
+ public GuiWidget Create(IObject3D item, View3DWidget view3DWidget, ThemeConfig theme)
+ {
+ this.view3DWidget = view3DWidget;
+ this.item = item;
+
+ var mainContainer = new FlowLayoutWidget(FlowDirection.TopToBottom)
+ {
+ HAnchor = HAnchor.Stretch
+ };
+
+ if (item is MatterCadObject3D)
+ {
+ ModifyCadObject(view3DWidget, mainContainer, theme);
+ }
+
+ mainContainer.MinimumSize = new Vector2(250, 0);
+ return mainContainer;
+ }
+
+ public IEnumerable SupportedTypes() => new Type[]
+ {
+ typeof(MatterCadObject3D),
+ };
+
+ private static FlowLayoutWidget CreateSettingsRow(string labelText)
+ {
+ var rowContainer = new FlowLayoutWidget(FlowDirection.LeftToRight)
+ {
+ HAnchor = HAnchor.Stretch,
+ Padding = new BorderDouble(5)
+ };
+
+ var label = new TextWidget(labelText + ":", textColor: ActiveTheme.Instance.PrimaryTextColor)
+ {
+ Margin = new BorderDouble(0, 0, 3, 0),
+ VAnchor = VAnchor.Center
+ };
+ rowContainer.AddChild(label);
+
+ rowContainer.AddChild(new HorizontalSpacer());
+
+ return rowContainer;
+ }
+
+ private string GetDisplayName(PropertyInfo prop)
+ {
+ var nameAttribute = prop.GetCustomAttributes(true).OfType().FirstOrDefault();
+ return nameAttribute?.DisplayName ?? prop.Name;
+ }
+
+ private void ModifyCadObject(View3DWidget view3DWidget, FlowLayoutWidget tabContainer, ThemeConfig theme)
+ {
+ var allowedTypes = new Type[] { typeof(double), typeof(string), typeof(bool) };
+
+ var ownedPropertiesOnly = System.Reflection.BindingFlags.Public
+ | System.Reflection.BindingFlags.Instance
+ | System.Reflection.BindingFlags.DeclaredOnly;
+
+ var editableProperties = this.item.GetType().GetProperties(ownedPropertiesOnly)
+ .Where(pi => allowedTypes.Contains(pi.PropertyType)
+ && pi.GetGetMethod() != null)
+ .Select(p => new
+ {
+ Value = p.GetGetMethod().Invoke(this.item, null),
+ DisplayName = GetDisplayName(p),
+ PropertyInfo = p
+ });
+
+ foreach (var property in editableProperties)
+ {
+ // create a double editor
+ if (property.Value is double doubleValue)
+ {
+ FlowLayoutWidget rowContainer = CreateSettingsRow(property.DisplayName.Localize());
+ var doubleEditWidget = new MHNumberEdit(doubleValue, pixelWidth: 50 * GuiWidget.DeviceScale, allowNegatives: true, allowDecimals: true, increment: .05)
+ {
+ SelectAllOnFocus = true,
+ VAnchor = VAnchor.Center
+ };
+ doubleEditWidget.ActuallNumberEdit.EditComplete += (s, e) =>
+ {
+ double editValue;
+ if (double.TryParse(doubleEditWidget.Text, out editValue))
+ {
+ property.PropertyInfo.GetSetMethod().Invoke(this.item, new Object[] { editValue });
+ }
+ ((MatterCadObject3D)item).RebuildMeshes();
+ };
+ rowContainer.AddChild(doubleEditWidget);
+ tabContainer.AddChild(rowContainer);
+ }
+ // create a bool editor
+ else if (property.Value is bool boolValue)
+ {
+ FlowLayoutWidget rowContainer = CreateSettingsRow(property.DisplayName.Localize());
+
+ var doubleEditWidget = new CheckBox("");
+ doubleEditWidget.Checked = boolValue;
+ doubleEditWidget.CheckedStateChanged += (s, e) =>
+ {
+ property.PropertyInfo.GetSetMethod().Invoke(this.item, new Object[] { doubleEditWidget.Checked });
+ ((MatterCadObject3D)item).RebuildMeshes();
+ };
+ rowContainer.AddChild(doubleEditWidget);
+ tabContainer.AddChild(rowContainer);
+ }
+ // create a bool editor
+ else if (property.Value is string stringValue)
+ {
+ FlowLayoutWidget rowContainer = CreateSettingsRow(property.DisplayName.Localize());
+ var textEditWidget = new MHTextEditWidget(stringValue, pixelWidth: 150 * GuiWidget.DeviceScale)
+ {
+ SelectAllOnFocus = true,
+ VAnchor = VAnchor.Center
+ };
+ textEditWidget.ActualTextEditWidget.EditComplete += (s, e) =>
+ {
+ property.PropertyInfo.GetSetMethod().Invoke(this.item, new Object[] { textEditWidget.Text });
+ ((MatterCadObject3D)item).RebuildMeshes();
+ };
+ rowContainer.AddChild(textEditWidget);
+ tabContainer.AddChild(rowContainer);
+ }
+ }
+
+ var updateButton = theme.ButtonFactory.Generate("Update".Localize());
+ updateButton.Margin = new BorderDouble(5);
+ updateButton.HAnchor = HAnchor.Right;
+ updateButton.Click += (s, e) =>
+ {
+ ((MatterCadObject3D)item).RebuildMeshes();
+ };
+ tabContainer.AddChild(updateButton);
+ }
+ }
+
+ public abstract class MatterCadObject3D : Object3D
+ {
+ public override string ActiveEditor { get; set; } = "MatterCadEditor";
+
+ public abstract void RebuildMeshes();
+ }
+}
\ No newline at end of file
diff --git a/TextCreator/CardHolderTool/MeshObjects.cs b/TextCreator/CardHolderTool/MeshObjects.cs
new file mode 100644
index 000000000..f9cbd9654
--- /dev/null
+++ b/TextCreator/CardHolderTool/MeshObjects.cs
@@ -0,0 +1,771 @@
+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 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() { 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 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);
+ }
+ }
+}
\ No newline at end of file
diff --git a/TextCreator/TextCreator.csproj b/TextCreator/TextCreator.csproj
index e568ded3a..a84689d94 100644
--- a/TextCreator/TextCreator.csproj
+++ b/TextCreator/TextCreator.csproj
@@ -56,7 +56,8 @@
-
+
+
@@ -70,10 +71,6 @@
{9B062971-A88E-4A3D-B3C9-12B78D15FA66}
clipper_library
-
- {7E61A5BD-E78F-4B80-88C9-3821B4FA062E}
- Csg
-
{94838988-523C-4B11-AD82-8B9B76F23A31}
DataConverters2D