diff --git a/MatterControl.MeshOperations/BooleanProcessing.cs b/MatterControl.MeshOperations/BooleanProcessing.cs index 3dbce2cd4..0f328c1e6 100644 --- a/MatterControl.MeshOperations/BooleanProcessing.cs +++ b/MatterControl.MeshOperations/BooleanProcessing.cs @@ -29,6 +29,7 @@ either expressed or implied, of the FreeBSD Project. using System; using System.IO; +using System.Linq; using System.Runtime.InteropServices; using System.Threading; using MatterHackers.Agg; @@ -37,6 +38,13 @@ using MatterHackers.VectorMath; namespace MatterHackers.MatterControl.PartPreviewWindow.View3D { + public enum CsgModes + { + Union, + Subtract, + Intersect + } + public static class BooleanProcessing { private const string BooleanAssembly = "609_Boolean_bin.dll"; @@ -50,13 +58,58 @@ namespace MatterHackers.MatterControl.PartPreviewWindow.View3D [DllImport(BooleanAssembly, CallingConvention = CallingConvention.Cdecl)] public static extern void DoBooleanOperation(double[] va, int vaCount, int[] fa, int faCount, double[] vb, int vbCount, int[] fb, int fbCount, int operation, out IntPtr pVc, out int vcCount, out IntPtr pVf, out int vfCount); + public static Mesh DoArray(System.Collections.Generic.IEnumerable<(Mesh mesh, Matrix4X4 matrix)> items, + CsgModes operation, + IProgress reporter, + CancellationToken cancellationToken) + { + var progressStatus = new ProgressStatus(); + var totalOperations = items.Count() - 1; + double amountPerOperation = 1.0 / totalOperations; + double percentCompleted = 0; + + var first = items.First(); + var resultsMesh = first.mesh; + var firstWorldMatrix = first.matrix; + + foreach (var item in items) + { + if (item != first) + { + var itemWorldMatrix = item.matrix; + resultsMesh = BooleanProcessing.Do(item.mesh, + itemWorldMatrix, + // other mesh + resultsMesh, + firstWorldMatrix, + // operation + operation, + // reporting + reporter, + amountPerOperation, + percentCompleted, + progressStatus, + cancellationToken); + + // after the first union we are working with the transformed mesh and don't need the first transform + firstWorldMatrix = Matrix4X4.Identity; + + percentCompleted += amountPerOperation; + progressStatus.Progress0To1 = percentCompleted; + reporter?.Report(progressStatus); + } + } + + return resultsMesh; + } + public static Mesh Do(Mesh inMeshA, Matrix4X4 matrixA, // mesh B Mesh inMeshB, Matrix4X4 matrixB, // operation - int operation, + CsgModes operation, // reporting IProgress reporter, double amountPerOperation, @@ -91,7 +144,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow.View3D fb, fb.Length, // operation - operation, + (int)operation, // results out pVc, out int vcCount, @@ -143,7 +196,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow.View3D switch (operation) { - case 0: + case CsgModes.Union: return PolygonMesh.Csg.CsgOperations.Union(meshA, meshB, (status, progress0To1) => @@ -157,7 +210,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow.View3D }, cancellationToken); - case 1: + case CsgModes.Subtract: return PolygonMesh.Csg.CsgOperations.Subtract(meshA, meshB, (status, progress0To1) => @@ -171,7 +224,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow.View3D }, cancellationToken); - case 2: + case CsgModes.Intersect: return PolygonMesh.Csg.CsgOperations.Intersect(meshA, meshB, (status, progress0To1) => diff --git a/MatterControlLib/DesignTools/Obsolete/IntersectionObject3D.cs b/MatterControlLib/DesignTools/Obsolete/IntersectionObject3D.cs index 21dc5a187..208757fbb 100644 --- a/MatterControlLib/DesignTools/Obsolete/IntersectionObject3D.cs +++ b/MatterControlLib/DesignTools/Obsolete/IntersectionObject3D.cs @@ -119,7 +119,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow.View3D { var result = BooleanProcessing.Do(remove.Mesh, remove.WorldMatrix(), first.Mesh, first.WorldMatrix(), - 2, reporter, amountPerOperation, percentCompleted, progressStatus, cancellationToken); + CsgModes.Intersect, reporter, amountPerOperation, percentCompleted, progressStatus, cancellationToken); var inverse = first.WorldMatrix(); inverse.Invert(); diff --git a/MatterControlLib/DesignTools/Operations/HollowOutObject3D.cs b/MatterControlLib/DesignTools/Operations/HollowOutObject3D.cs index 252083e0f..a36dbce60 100644 --- a/MatterControlLib/DesignTools/Operations/HollowOutObject3D.cs +++ b/MatterControlLib/DesignTools/Operations/HollowOutObject3D.cs @@ -51,6 +51,8 @@ namespace MatterHackers.MatterControl.DesignTools public double Distance { get; set; } = 2; + public int NumCells { get; set; } = 64; + private static DMesh3 GenerateMeshF(BoundedImplicitFunction3d root, int numcells) { var bounds = root.Bounds(); @@ -71,14 +73,13 @@ namespace MatterHackers.MatterControl.DesignTools return c.Mesh; } - public static Mesh HollowOut(Mesh inMesh, double distance) + public static Mesh HollowOut(Mesh inMesh, double distance, int numCells) { // Convert to DMesh3 var mesh = inMesh.ToDMesh3(); // Create instance of BoundedImplicitFunction3d interface - int numcells = 64; - double meshCellsize = mesh.CachedBounds.MaxDim / numcells; + double meshCellsize = mesh.CachedBounds.MaxDim / numCells; var levelSet = new MeshSignedDistanceGrid(mesh, meshCellsize) { @@ -96,11 +97,11 @@ namespace MatterHackers.MatterControl.DesignTools A = implicitMesh, Offset = -distance }, - 128); + numCells); // make sure it is a reasonable number of polygons - var reducer = new Reducer(insetMesh); - reducer.ReduceToTriangleCount(Math.Max(inMesh.Faces.Count / 2, insetMesh.TriangleCount / 10)); + // var reducer = new Reducer(insetMesh); + // reducer.ReduceToTriangleCount(Math.Max(inMesh.Faces.Count / 2, insetMesh.TriangleCount / 10)); // Convert to PolygonMesh and reverse faces var interior = insetMesh.ToMesh(); @@ -132,7 +133,7 @@ namespace MatterHackers.MatterControl.DesignTools { var newMesh = new Object3D() { - Mesh = HollowOut(sourceItem.Mesh, this.Distance) + Mesh = HollowOut(sourceItem.Mesh, this.Distance, this.NumCells) }; newMesh.CopyProperties(sourceItem, Object3DPropertyFlags.All); this.Children.Add(newMesh); diff --git a/MatterControlLib/PartPreviewWindow/View3D/Actions/CombineObject3D_2.cs b/MatterControlLib/PartPreviewWindow/View3D/Actions/CombineObject3D_2.cs index 26716a23b..60c11ef13 100644 --- a/MatterControlLib/PartPreviewWindow/View3D/Actions/CombineObject3D_2.cs +++ b/MatterControlLib/PartPreviewWindow/View3D/Actions/CombineObject3D_2.cs @@ -103,48 +103,17 @@ namespace MatterHackers.MatterControl.PartPreviewWindow.View3D return; } - var first = participants.First(); - var resultsMesh = first.Mesh; - var firstWorldMatrix = first.WorldMatrix(SourceContainer); - - var totalOperations = participants.Count() - 1; - double amountPerOperation = 1.0 / totalOperations; - double percentCompleted = 0; - - var progressStatus = new ProgressStatus(); - foreach (var item in participants) - { - if (item != first) - { - var itemWorldMatrix = item.WorldMatrix(SourceContainer); - resultsMesh = BooleanProcessing.Do(item.Mesh, - itemWorldMatrix, - // other mesh - resultsMesh, - firstWorldMatrix, - // operation - 0, - // reporting - reporter, - amountPerOperation, - percentCompleted, - progressStatus, - cancellationToken); - - // after the first union we are working with the transformed mesh and don't need the first transform - firstWorldMatrix = Matrix4X4.Identity; - - percentCompleted += amountPerOperation; - progressStatus.Progress0To1 = percentCompleted; - reporter?.Report(progressStatus); - } - } + var items = participants.Select(i => (i.Mesh, i.WorldMatrix(SourceContainer))); + var resultsMesh = BooleanProcessing.DoArray(items, + CsgModes.Union, + reporter, + cancellationToken); var resultsItem = new Object3D() { Mesh = resultsMesh }; - resultsItem.CopyProperties(first, Object3DPropertyFlags.All & (~Object3DPropertyFlags.Matrix)); + resultsItem.CopyProperties(participants.First(), Object3DPropertyFlags.All & (~Object3DPropertyFlags.Matrix)); this.Children.Add(resultsItem); SourceContainer.Visible = false; } diff --git a/MatterControlLib/PartPreviewWindow/View3D/Actions/IntersectionObject3D_2.cs b/MatterControlLib/PartPreviewWindow/View3D/Actions/IntersectionObject3D_2.cs index 42d9cd66b..6d5c0b7e3 100644 --- a/MatterControlLib/PartPreviewWindow/View3D/Actions/IntersectionObject3D_2.cs +++ b/MatterControlLib/PartPreviewWindow/View3D/Actions/IntersectionObject3D_2.cs @@ -119,7 +119,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow.View3D var itemWorldMatrix = item.WorldMatrix(SourceContainer); resultsMesh = BooleanProcessing.Do(item.Mesh, itemWorldMatrix, resultsMesh, firstWorldMatrix, - 2, + CsgModes.Intersect, reporter, amountPerOperation, percentCompleted, progressStatus, cancellationToken); // after the first union we are working with the transformed mesh and don't need the first transform firstWorldMatrix = Matrix4X4.Identity; diff --git a/MatterControlLib/PartPreviewWindow/View3D/Actions/SubtractAndReplaceObject3D.cs b/MatterControlLib/PartPreviewWindow/View3D/Actions/SubtractAndReplaceObject3D.cs index b83e68ae2..fa786c02a 100644 --- a/MatterControlLib/PartPreviewWindow/View3D/Actions/SubtractAndReplaceObject3D.cs +++ b/MatterControlLib/PartPreviewWindow/View3D/Actions/SubtractAndReplaceObject3D.cs @@ -121,9 +121,9 @@ namespace MatterHackers.MatterControl.PartPreviewWindow.View3D // remove the paint from the original var subtract = BooleanProcessing.Do(keep.obj3D.Mesh, keep.matrix, - paint.obj3D.Mesh, paint.matrix, 1, reporter, amountPerOperation, percentCompleted, progressStatus, cancellationToken); + paint.obj3D.Mesh, paint.matrix, CsgModes.Subtract, reporter, amountPerOperation, percentCompleted, progressStatus, cancellationToken); var intersect = BooleanProcessing.Do(keep.obj3D.Mesh, keep.matrix, - paint.obj3D.Mesh, paint.matrix, 2, reporter, amountPerOperation, percentCompleted, progressStatus, cancellationToken); + paint.obj3D.Mesh, paint.matrix, CsgModes.Intersect, reporter, amountPerOperation, percentCompleted, progressStatus, cancellationToken); var inverseKeep = keep.matrix.Inverted; subtract.Transform(inverseKeep); diff --git a/MatterControlLib/PartPreviewWindow/View3D/Actions/SubtractAndReplaceObject3D_2.cs b/MatterControlLib/PartPreviewWindow/View3D/Actions/SubtractAndReplaceObject3D_2.cs index 915284612..b3d699a0a 100644 --- a/MatterControlLib/PartPreviewWindow/View3D/Actions/SubtractAndReplaceObject3D_2.cs +++ b/MatterControlLib/PartPreviewWindow/View3D/Actions/SubtractAndReplaceObject3D_2.cs @@ -267,7 +267,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow.View3D paint.Mesh, paint.WorldMatrix(SourceContainer), // operation type - 2, + CsgModes.Intersect, // reporting data reporter, amountPerOperation, @@ -281,7 +281,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow.View3D paint.Mesh, paint.WorldMatrix(SourceContainer), // operation type - 1, + CsgModes.Subtract, // reporting data reporter, amountPerOperation, diff --git a/MatterControlLib/PartPreviewWindow/View3D/Actions/SubtractObject3D.cs b/MatterControlLib/PartPreviewWindow/View3D/Actions/SubtractObject3D.cs index 5f893074a..aea510a11 100644 --- a/MatterControlLib/PartPreviewWindow/View3D/Actions/SubtractObject3D.cs +++ b/MatterControlLib/PartPreviewWindow/View3D/Actions/SubtractObject3D.cs @@ -161,7 +161,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow.View3D progressStatus.Status = "Do CSG"; reporter?.Report(progressStatus); var result = BooleanProcessing.Do(keep.obj3D.Mesh, keep.matrix, - remove.obj3D.Mesh, remove.matrix, 1, reporter, amountPerOperation, percentCompleted, progressStatus, cancellationToken); + remove.obj3D.Mesh, remove.matrix, CsgModes.Subtract, reporter, amountPerOperation, percentCompleted, progressStatus, cancellationToken); var inverse = keep.matrix.Inverted; result.Transform(inverse); diff --git a/MatterControlLib/PartPreviewWindow/View3D/Actions/SubtractObject3D_2.cs b/MatterControlLib/PartPreviewWindow/View3D/Actions/SubtractObject3D_2.cs index 66d5c6193..113d6f8c4 100644 --- a/MatterControlLib/PartPreviewWindow/View3D/Actions/SubtractObject3D_2.cs +++ b/MatterControlLib/PartPreviewWindow/View3D/Actions/SubtractObject3D_2.cs @@ -209,7 +209,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow.View3D remove.Mesh, remove.WorldMatrix(SourceContainer), // operation type - 1, + CsgModes.Subtract, // reporting reporter, amountPerOperation,