Making it possible to select dual contouring for CSG

This commit is contained in:
LarsBrubaker 2021-07-14 07:16:44 -07:00
parent bc232506af
commit e685fa12a2
11 changed files with 170 additions and 79 deletions

View file

@ -53,7 +53,7 @@ namespace MatterHackers.PolygonMesh
Intersect
}
public enum IplicitSurfaceMesh
public enum IplicitSurfaceMethod
{
[Description("Faster but less accurate")]
Grid,
@ -63,10 +63,16 @@ namespace MatterHackers.PolygonMesh
public enum ProcessingModes
{
Exact,
Volume_64,
Volume_128,
Volume_256,
Polygons,
Marching_Cubes,
Dual_Contouring,
}
public enum ProcessingResolution
{
_64 = 6,
_128 = 7,
_256 = 8,
}
private const string BooleanAssembly = "609_Boolean_bin.dll";
@ -82,12 +88,13 @@ namespace MatterHackers.PolygonMesh
public static Mesh DoArray(IEnumerable<(Mesh mesh, Matrix4X4 matrix)> items,
CsgModes operation,
bool exactSurface,
ProcessingModes processingMode,
ProcessingResolution inputResolution,
ProcessingResolution outputResolution,
IProgress<ProgressStatus> reporter,
CancellationToken cancellationToken)
{
if (processingMode == ProcessingModes.Exact)
if (processingMode == ProcessingModes.Polygons)
{
var progressStatus = new ProgressStatus();
var totalOperations = items.Count() - 1;
@ -115,6 +122,8 @@ namespace MatterHackers.PolygonMesh
// operation
operation,
processingMode,
inputResolution,
outputResolution,
// reporting
reporter,
amountPerOperation,
@ -134,24 +143,10 @@ namespace MatterHackers.PolygonMesh
}
else
{
var resolution = 64;
switch (processingMode)
{
case ProcessingModes.Volume_128:
resolution = 128;
break;
case ProcessingModes.Volume_256:
resolution = 256;
break;
}
var marchingCells = resolution;
var implicitCells = exactSurface ? 0 : resolution * 4;
var implicitMeshs = new List<BoundedImplicitFunction3d>();
foreach (var item in items)
{
implicitMeshs.Add(GetImplicitFromMesh(item.mesh, item.matrix, implicitCells));
implicitMeshs.Add(GetImplicitFunction(item.mesh, item.matrix, processingMode == ProcessingModes.Polygons, 1 << (int)inputResolution));
}
DMesh3 GenerateMeshF(BoundedImplicitFunction3d root, int numCells)
@ -177,6 +172,7 @@ namespace MatterHackers.PolygonMesh
switch (operation)
{
case CsgModes.Union:
if (processingMode == ProcessingModes.Dual_Contouring)
{
var bounds = implicitMeshs.First().Bounds();
var root = Octree.BuildOctree((pos) =>
@ -185,17 +181,45 @@ namespace MatterHackers.PolygonMesh
return implicitMeshs.First().Value(ref pos2);
}, new Vector3(bounds.Min.x, bounds.Min.y, bounds.Min.z),
new Vector3(bounds.Width, bounds.Depth, bounds.Height),
5,
(int)outputResolution,
.001);
return Octree.GenerateMeshFromOctree(root);
}
else
{
return GenerateMeshF(new ImplicitNaryUnion3d()
{
Children = implicitMeshs
}, marchingCells).ToMesh();
}, 1 << (int)outputResolution).ToMesh();
}
case CsgModes.Subtract:
{
if (processingMode == ProcessingModes.Dual_Contouring)
{
var bounds = implicitMeshs.First().Bounds();
var root = Octree.BuildOctree((pos) =>
{
var pos2 = new Vector3d(pos.X, pos.Y, pos.Z);
return implicitMeshs.First().Value(ref pos2);
}, new Vector3(bounds.Min.x, bounds.Min.y, bounds.Min.z),
new Vector3(bounds.Width, bounds.Depth, bounds.Height),
(int)outputResolution,
.001);
return Octree.GenerateMeshFromOctree(root);
}
else
{
return GenerateMeshF(new ImplicitNaryDifference3d()
{
A = implicitMeshs.First(),
BSet = implicitMeshs.GetRange(0, implicitMeshs.Count - 1)
}, 1 << (int)outputResolution).ToMesh();
}
}
case CsgModes.Intersect:
if (processingMode == ProcessingModes.Dual_Contouring)
{
var bounds = implicitMeshs.First().Bounds();
var root = Octree.BuildOctree((pos) =>
@ -204,22 +228,17 @@ namespace MatterHackers.PolygonMesh
return implicitMeshs.First().Value(ref pos2);
}, new Vector3(bounds.Min.x, bounds.Min.y, bounds.Min.z),
new Vector3(bounds.Width, bounds.Depth, bounds.Height),
5,
(int)outputResolution,
.001);
return Octree.GenerateMeshFromOctree(root);
return GenerateMeshF(new ImplicitNaryDifference3d()
{
A = implicitMeshs.First(),
BSet = implicitMeshs.GetRange(0, implicitMeshs.Count - 1)
}, marchingCells).ToMesh();
}
case CsgModes.Intersect:
return GenerateMeshF(new ImplicitNaryIntersection3d()
else
{
Children = implicitMeshs
}, marchingCells).ToMesh();
return GenerateMeshF(new ImplicitNaryIntersection3d()
{
Children = implicitMeshs
}, 1 << (int)outputResolution).ToMesh();
}
}
}
@ -234,6 +253,8 @@ namespace MatterHackers.PolygonMesh
// operation
CsgModes operation,
ProcessingModes processingMode,
ProcessingResolution inputResolution,
ProcessingResolution outputResolution,
// reporting
IProgress<ProgressStatus> reporter,
double amountPerOperation,
@ -242,7 +263,7 @@ namespace MatterHackers.PolygonMesh
CancellationToken cancellationToken)
{
bool externalAssemblyExists = File.Exists(BooleanAssembly);
if (processingMode == ProcessingModes.Exact)
if (processingMode == ProcessingModes.Polygons)
{
// only try to run the improved booleans if we are 64 bit and it is there
if (externalAssemblyExists && IntPtr.Size == 8)
@ -361,21 +382,8 @@ namespace MatterHackers.PolygonMesh
}
else
{
var resolution = 64;
switch (processingMode)
{
case ProcessingModes.Volume_128:
resolution = 128;
break;
case ProcessingModes.Volume_256:
resolution = 256;
break;
}
var marchingCells = resolution;
var implicitCells = resolution;
var implicitA = GetImplicitFromMesh(inMeshA, matrixA, implicitCells);
var implicitB = GetImplicitFromMesh(inMeshB, matrixB, implicitCells);
var implicitA = GetImplicitFunction(inMeshA, matrixA, processingMode == ProcessingModes.Polygons, (int)inputResolution);
var implicitB = GetImplicitFunction(inMeshB, matrixB, processingMode == ProcessingModes.Polygons, (int)inputResolution);
DMesh3 GenerateMeshF(BoundedImplicitFunction3d root, int numCells)
{
@ -397,6 +405,7 @@ namespace MatterHackers.PolygonMesh
return c.Mesh;
}
var marchingCells = 1 << (int)outputResolution;
switch (operation)
{
case CsgModes.Union:
@ -435,7 +444,8 @@ namespace MatterHackers.PolygonMesh
}
}
public static BoundedImplicitFunction3d GetImplicitFromMesh(Mesh mesh, Matrix4X4 matrix, int numCells)
public static BoundedImplicitFunction3d GetImplicitFunction(Mesh mesh, Matrix4X4 matrix, bool exact, int numCells)
{
var meshCopy = mesh.Copy(CancellationToken.None);
meshCopy.Transform(matrix);
@ -443,7 +453,7 @@ namespace MatterHackers.PolygonMesh
var meshA3 = meshCopy.ToDMesh3();
// Interesting experiment, this produces an extremely accurate surface representation but is quite slow (even though fast) compared to voxel lookups.
if (numCells == 0)
if (exact)
{
DMeshAABBTree3 meshAABBTree3 = new DMeshAABBTree3(meshA3, true);
meshAABBTree3.FastWindingNumber(Vector3d.Zero); // build approximation

View file

@ -137,7 +137,9 @@ namespace MatterHackers.MatterControl.PartPreviewWindow.View3D
first.Mesh,
first.WorldMatrix(),
BooleanProcessing.CsgModes.Union,
BooleanProcessing.ProcessingModes.Exact,
BooleanProcessing.ProcessingModes.Polygons,
BooleanProcessing.ProcessingResolution._64,
BooleanProcessing.ProcessingResolution._64,
reporter,
amountPerOperation,
percentCompleted,

View file

@ -123,7 +123,9 @@ namespace MatterHackers.MatterControl.PartPreviewWindow.View3D
first.Mesh,
first.WorldMatrix(),
BooleanProcessing.CsgModes.Intersect,
BooleanProcessing.ProcessingModes.Exact,
BooleanProcessing.ProcessingModes.Polygons,
BooleanProcessing.ProcessingResolution._64,
BooleanProcessing.ProcessingResolution._64,
reporter,
amountPerOperation,
percentCompleted,

View file

@ -104,7 +104,7 @@ namespace MatterHackers.MatterControl.DesignTools
{
shape = new Box()
{
Size = new Vector3(Size, Size * .8, Size * .6)
Size = new Vector3(Size, Size, Size)
};
}

View file

@ -42,19 +42,24 @@ using MatterHackers.PolygonMesh;
namespace MatterHackers.MatterControl.PartPreviewWindow.View3D
{
public class CombineObject3D_2 : OperationSourceContainerObject3D
public class CombineObject3D_2 : OperationSourceContainerObject3D, IPropertyGridModifier
{
public CombineObject3D_2()
{
Name = "Combine";
}
[EnumDisplay(Mode = EnumDisplayAttribute.PresentationMode.Buttons)]
public BooleanProcessing.ProcessingModes Processing { get; set; } = BooleanProcessing.ProcessingModes.Polygons;
[EnumDisplay(Mode = EnumDisplayAttribute.PresentationMode.Buttons)]
public BooleanProcessing.ProcessingModes Processing { get; set; } = BooleanProcessing.ProcessingModes.Exact;
public BooleanProcessing.ProcessingResolution OutputResolution { get; set; } = BooleanProcessing.ProcessingResolution._64;
[EnumDisplay(Mode = EnumDisplayAttribute.PresentationMode.Buttons)]
public BooleanProcessing.IplicitSurfaceMesh MeshAnalysis { get; set; }
public BooleanProcessing.IplicitSurfaceMethod MeshAnalysis { get; set; }
[EnumDisplay(Mode = EnumDisplayAttribute.PresentationMode.Buttons)]
public BooleanProcessing.ProcessingResolution InputResolution { get; set; } = BooleanProcessing.ProcessingResolution._64;
public override Task Rebuild()
{
@ -115,8 +120,9 @@ namespace MatterHackers.MatterControl.PartPreviewWindow.View3D
var items = participants.Select(i => (i.Mesh, i.WorldMatrix(SourceContainer)));
var resultsMesh = BooleanProcessing.DoArray(items,
BooleanProcessing.CsgModes.Union,
MeshAnalysis == BooleanProcessing.IplicitSurfaceMesh.Exact,
Processing,
InputResolution,
OutputResolution,
reporter,
cancellationToken);
@ -128,5 +134,13 @@ namespace MatterHackers.MatterControl.PartPreviewWindow.View3D
this.Children.Add(resultsItem);
SourceContainer.Visible = false;
}
public void UpdateControls(PublicPropertyChange change)
{
change.SetRowVisible(nameof(InputResolution), () => Processing != BooleanProcessing.ProcessingModes.Polygons);
change.SetRowVisible(nameof(OutputResolution), () => Processing != BooleanProcessing.ProcessingModes.Polygons);
change.SetRowVisible(nameof(MeshAnalysis), () => Processing != BooleanProcessing.ProcessingModes.Polygons);
change.SetRowVisible(nameof(InputResolution), () => Processing != BooleanProcessing.ProcessingModes.Polygons && MeshAnalysis == BooleanProcessing.IplicitSurfaceMethod.Grid);
}
}
}

View file

@ -42,7 +42,7 @@ using MatterHackers.VectorMath;
namespace MatterHackers.MatterControl.PartPreviewWindow.View3D
{
public class IntersectionObject3D_2 : OperationSourceContainerObject3D
public class IntersectionObject3D_2 : OperationSourceContainerObject3D, IPropertyGridModifier
{
public IntersectionObject3D_2()
{
@ -50,10 +50,16 @@ namespace MatterHackers.MatterControl.PartPreviewWindow.View3D
}
[EnumDisplay(Mode = EnumDisplayAttribute.PresentationMode.Buttons)]
public BooleanProcessing.ProcessingModes Processing { get; set; } = BooleanProcessing.ProcessingModes.Exact;
public BooleanProcessing.ProcessingModes Processing { get; set; } = BooleanProcessing.ProcessingModes.Polygons;
[EnumDisplay(Mode = EnumDisplayAttribute.PresentationMode.Buttons)]
public BooleanProcessing.IplicitSurfaceMesh MeshAnalysis { get; set; }
public BooleanProcessing.ProcessingResolution OutputResolution { get; set; } = BooleanProcessing.ProcessingResolution._64;
[EnumDisplay(Mode = EnumDisplayAttribute.PresentationMode.Buttons)]
public BooleanProcessing.IplicitSurfaceMethod MeshAnalysis { get; set; }
[EnumDisplay(Mode = EnumDisplayAttribute.PresentationMode.Buttons)]
public BooleanProcessing.ProcessingResolution InputResolution { get; set; } = BooleanProcessing.ProcessingResolution._64;
public override Task Rebuild()
{
@ -114,8 +120,9 @@ namespace MatterHackers.MatterControl.PartPreviewWindow.View3D
var items = participants.Select(i => (i.Mesh, i.WorldMatrix(SourceContainer)));
var resultsMesh = BooleanProcessing.DoArray(items,
BooleanProcessing.CsgModes.Intersect,
MeshAnalysis == BooleanProcessing.IplicitSurfaceMesh.Exact,
Processing,
InputResolution,
OutputResolution,
reporter,
cancellationToken);
@ -127,5 +134,13 @@ namespace MatterHackers.MatterControl.PartPreviewWindow.View3D
this.Children.Add(resultsItem);
SourceContainer.Visible = false;
}
public void UpdateControls(PublicPropertyChange change)
{
change.SetRowVisible(nameof(InputResolution), () => Processing != BooleanProcessing.ProcessingModes.Polygons);
change.SetRowVisible(nameof(OutputResolution), () => Processing != BooleanProcessing.ProcessingModes.Polygons);
change.SetRowVisible(nameof(MeshAnalysis), () => Processing != BooleanProcessing.ProcessingModes.Polygons);
change.SetRowVisible(nameof(InputResolution), () => Processing != BooleanProcessing.ProcessingModes.Polygons && MeshAnalysis == BooleanProcessing.IplicitSurfaceMethod.Grid);
}
}
}

View file

@ -125,7 +125,9 @@ namespace MatterHackers.MatterControl.PartPreviewWindow.View3D
paint.obj3D.Mesh,
paint.matrix,
BooleanProcessing.CsgModes.Subtract,
BooleanProcessing.ProcessingModes.Exact,
BooleanProcessing.ProcessingModes.Polygons,
BooleanProcessing.ProcessingResolution._64,
BooleanProcessing.ProcessingResolution._64,
reporter,
amountPerOperation,
percentCompleted,
@ -137,7 +139,9 @@ namespace MatterHackers.MatterControl.PartPreviewWindow.View3D
paint.obj3D.Mesh,
paint.matrix,
BooleanProcessing.CsgModes.Intersect,
BooleanProcessing.ProcessingModes.Exact,
BooleanProcessing.ProcessingModes.Polygons,
BooleanProcessing.ProcessingResolution._64,
BooleanProcessing.ProcessingResolution._64,
reporter,
amountPerOperation,
percentCompleted,
@ -163,7 +167,9 @@ namespace MatterHackers.MatterControl.PartPreviewWindow.View3D
intersect,
Matrix4X4.Identity,
BooleanProcessing.CsgModes.Subtract,
BooleanProcessing.ProcessingModes.Exact,
BooleanProcessing.ProcessingModes.Polygons,
BooleanProcessing.ProcessingResolution._64,
BooleanProcessing.ProcessingResolution._64,
reporter,
amountPerOperation,
percentCompleted,

View file

@ -46,22 +46,31 @@ using MatterHackers.VectorMath;
namespace MatterHackers.MatterControl.PartPreviewWindow.View3D
{
[ShowUpdateButton]
public class SubtractAndReplaceObject3D_2 : OperationSourceContainerObject3D, ISelectableChildContainer, ISelectedEditorDraw
public class SubtractAndReplaceObject3D_2 : OperationSourceContainerObject3D, ISelectableChildContainer, ISelectedEditorDraw, IPropertyGridModifier
{
public SubtractAndReplaceObject3D_2()
{
Name = "Subtract and Replace";
}
[EnumDisplay(Mode = EnumDisplayAttribute.PresentationMode.Buttons)]
public BooleanProcessing.ProcessingModes Processing { get; set; } = BooleanProcessing.ProcessingModes.Exact;
[HideFromEditor]
public SelectedChildren ComputedChildren { get; set; } = new SelectedChildren();
[DisplayName("Part(s) to Subtract and Replace")]
public SelectedChildren SelectedChildren { get; set; } = new SelectedChildren();
[EnumDisplay(Mode = EnumDisplayAttribute.PresentationMode.Buttons)]
public BooleanProcessing.ProcessingModes Processing { get; set; } = BooleanProcessing.ProcessingModes.Polygons;
[EnumDisplay(Mode = EnumDisplayAttribute.PresentationMode.Buttons)]
public BooleanProcessing.ProcessingResolution OutputResolution { get; set; } = BooleanProcessing.ProcessingResolution._64;
[EnumDisplay(Mode = EnumDisplayAttribute.PresentationMode.Buttons)]
public BooleanProcessing.IplicitSurfaceMethod MeshAnalysis { get; set; }
[EnumDisplay(Mode = EnumDisplayAttribute.PresentationMode.Buttons)]
public BooleanProcessing.ProcessingResolution InputResolution { get; set; } = BooleanProcessing.ProcessingResolution._64;
public void DrawEditor(Object3DControlsLayer layer, List<Object3DView> transparentMeshes, DrawEventArgs e)
{
var parentOfSourceItems = this.SourceContainer.DescendantsAndSelfMultipleChildrenFirstOrSelf();
@ -272,6 +281,8 @@ namespace MatterHackers.MatterControl.PartPreviewWindow.View3D
// operation type
BooleanProcessing.CsgModes.Intersect,
Processing,
InputResolution,
OutputResolution,
// reporting data
reporter,
amountPerOperation,
@ -287,6 +298,8 @@ namespace MatterHackers.MatterControl.PartPreviewWindow.View3D
// operation type
BooleanProcessing.CsgModes.Subtract,
Processing,
InputResolution,
OutputResolution,
// reporting data
reporter,
amountPerOperation,
@ -336,5 +349,13 @@ namespace MatterHackers.MatterControl.PartPreviewWindow.View3D
SourceContainer.Visible = false;
}
}
public void UpdateControls(PublicPropertyChange change)
{
change.SetRowVisible(nameof(InputResolution), () => Processing != BooleanProcessing.ProcessingModes.Polygons);
change.SetRowVisible(nameof(OutputResolution), () => Processing != BooleanProcessing.ProcessingModes.Polygons);
change.SetRowVisible(nameof(MeshAnalysis), () => Processing != BooleanProcessing.ProcessingModes.Polygons);
change.SetRowVisible(nameof(InputResolution), () => Processing != BooleanProcessing.ProcessingModes.Polygons && MeshAnalysis == BooleanProcessing.IplicitSurfaceMethod.Grid);
}
}
}

View file

@ -166,7 +166,9 @@ namespace MatterHackers.MatterControl.PartPreviewWindow.View3D
remove.obj3D.Mesh,
remove.matrix,
BooleanProcessing.CsgModes.Subtract,
BooleanProcessing.ProcessingModes.Exact,
BooleanProcessing.ProcessingModes.Polygons,
BooleanProcessing.ProcessingResolution._64,
BooleanProcessing.ProcessingResolution._64,
reporter,
amountPerOperation,
percentCompleted,

View file

@ -46,19 +46,28 @@ using MatterHackers.VectorMath;
namespace MatterHackers.MatterControl.PartPreviewWindow.View3D
{
[ShowUpdateButton]
public class SubtractObject3D_2 : OperationSourceContainerObject3D, ISelectableChildContainer, ISelectedEditorDraw
public class SubtractObject3D_2 : OperationSourceContainerObject3D, ISelectableChildContainer, ISelectedEditorDraw, IPropertyGridModifier
{
public SubtractObject3D_2()
{
Name = "Subtract";
}
[EnumDisplay(Mode = EnumDisplayAttribute.PresentationMode.Buttons)]
public BooleanProcessing.ProcessingModes Processing { get; set; } = BooleanProcessing.ProcessingModes.Exact;
[DisplayName("Part(s) to Subtract")]
public SelectedChildren SelectedChildren { get; set; } = new SelectedChildren();
[EnumDisplay(Mode = EnumDisplayAttribute.PresentationMode.Buttons)]
public BooleanProcessing.ProcessingModes Processing { get; set; } = BooleanProcessing.ProcessingModes.Polygons;
[EnumDisplay(Mode = EnumDisplayAttribute.PresentationMode.Buttons)]
public BooleanProcessing.ProcessingResolution OutputResolution { get; set; } = BooleanProcessing.ProcessingResolution._64;
[EnumDisplay(Mode = EnumDisplayAttribute.PresentationMode.Buttons)]
public BooleanProcessing.IplicitSurfaceMethod MeshAnalysis { get; set; }
[EnumDisplay(Mode = EnumDisplayAttribute.PresentationMode.Buttons)]
public BooleanProcessing.ProcessingResolution InputResolution { get; set; } = BooleanProcessing.ProcessingResolution._64;
public void DrawEditor(Object3DControlsLayer layer, List<Object3DView> transparentMeshes, DrawEventArgs e)
{
if (layer.Scene.SelectedItem != null
@ -218,6 +227,8 @@ namespace MatterHackers.MatterControl.PartPreviewWindow.View3D
// operation type
BooleanProcessing.CsgModes.Subtract,
Processing,
InputResolution,
OutputResolution,
// reporting
reporter,
amountPerOperation,
@ -282,5 +293,13 @@ namespace MatterHackers.MatterControl.PartPreviewWindow.View3D
}
}
}
public void UpdateControls(PublicPropertyChange change)
{
change.SetRowVisible(nameof(InputResolution), () => Processing != BooleanProcessing.ProcessingModes.Polygons);
change.SetRowVisible(nameof(OutputResolution), () => Processing != BooleanProcessing.ProcessingModes.Polygons);
change.SetRowVisible(nameof(MeshAnalysis), () => Processing != BooleanProcessing.ProcessingModes.Polygons);
change.SetRowVisible(nameof(InputResolution), () => Processing != BooleanProcessing.ProcessingModes.Polygons && MeshAnalysis == BooleanProcessing.IplicitSurfaceMethod.Grid);
}
}
}

@ -1 +1 @@
Subproject commit afd8e1a909a478b9058724e6cc571144cb6d7c59
Subproject commit 14faf919e05defb28b2df2ea39a30853002cb300