Took out legacy csg code
refactoring
This commit is contained in:
parent
d5ac8376aa
commit
9cfc85f90e
60 changed files with 67 additions and 1807 deletions
Binary file not shown.
|
|
@ -1,567 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2019, Lars Brubaker, John Lewin
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
The views and conclusions contained in the software and documentation are those
|
||||
of the authors and should not be interpreted as representing official policies,
|
||||
either expressed or implied, of the FreeBSD Project.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
using ClipperLib;
|
||||
using DualContouring;
|
||||
using g3;
|
||||
using gs;
|
||||
using MatterHackers.Agg;
|
||||
using MatterHackers.MatterControl.DesignTools;
|
||||
using MatterHackers.VectorMath;
|
||||
|
||||
namespace MatterHackers.PolygonMesh
|
||||
{
|
||||
using Polygon = List<IntPoint>;
|
||||
|
||||
public enum CsgModes
|
||||
{
|
||||
Union,
|
||||
Subtract,
|
||||
Intersect
|
||||
}
|
||||
|
||||
public enum IplicitSurfaceMethod
|
||||
{
|
||||
[Description("Faster but less accurate")]
|
||||
Grid,
|
||||
[Description("Slower but more accurate")]
|
||||
Exact
|
||||
};
|
||||
|
||||
public enum ProcessingModes
|
||||
{
|
||||
[Description("Default CSG processing")]
|
||||
Polygons,
|
||||
[Description("Use libigl (windows only)")]
|
||||
libigl,
|
||||
[Description("Experimental Marching Cubes")]
|
||||
Marching_Cubes,
|
||||
[Description("Experimental Dual Contouring")]
|
||||
Dual_Contouring,
|
||||
}
|
||||
|
||||
public enum ProcessingResolution
|
||||
{
|
||||
_64 = 6,
|
||||
_128 = 7,
|
||||
_256 = 8,
|
||||
_512 = 9,
|
||||
}
|
||||
|
||||
public static class BooleanProcessing
|
||||
{
|
||||
private const string BooleanAssembly = "609_Boolean_bin.dll";
|
||||
|
||||
[DllImport(BooleanAssembly, CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern int DeleteDouble(ref IntPtr handle);
|
||||
|
||||
[DllImport(BooleanAssembly, CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern int DeleteInt(ref IntPtr handle);
|
||||
|
||||
[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(IEnumerable<(Mesh mesh, Matrix4X4 matrix)> items,
|
||||
CsgModes operation,
|
||||
ProcessingModes processingMode,
|
||||
ProcessingResolution inputResolution,
|
||||
ProcessingResolution outputResolution,
|
||||
IProgress<ProgressStatus> reporter,
|
||||
CancellationToken cancellationToken,
|
||||
double amountPerOperation = 1,
|
||||
double ratioCompleted = 0)
|
||||
{
|
||||
if (processingMode == ProcessingModes.Polygons)
|
||||
{
|
||||
var csgBySlicing = new CsgBySlicing();
|
||||
csgBySlicing.Setup(items, null, cancellationToken);
|
||||
|
||||
return csgBySlicing.Calculate(operation,
|
||||
(ratio, message) =>
|
||||
{
|
||||
reporter?.Report(new ProgressStatus()
|
||||
{
|
||||
Progress0To1 = ratio * amountPerOperation + ratioCompleted,
|
||||
Status = message
|
||||
});
|
||||
|
||||
},
|
||||
cancellationToken);
|
||||
}
|
||||
else if (processingMode == ProcessingModes.libigl)
|
||||
{
|
||||
return ExactLegacy(items, operation, processingMode, inputResolution, outputResolution, reporter, cancellationToken);
|
||||
}
|
||||
else
|
||||
{
|
||||
return AsImplicitMeshes(items, operation, processingMode, inputResolution, outputResolution);
|
||||
}
|
||||
}
|
||||
|
||||
private static Mesh AsImplicitMeshes(IEnumerable<(Mesh mesh, Matrix4X4 matrix)> items,
|
||||
CsgModes operation,
|
||||
ProcessingModes processingMode,
|
||||
ProcessingResolution inputResolution,
|
||||
ProcessingResolution outputResolution)
|
||||
{
|
||||
Mesh implicitResult = null;
|
||||
|
||||
var implicitMeshs = new List<BoundedImplicitFunction3d>();
|
||||
foreach (var (mesh, matrix) in items)
|
||||
{
|
||||
var meshCopy = mesh.Copy(CancellationToken.None);
|
||||
meshCopy.Transform(matrix);
|
||||
|
||||
implicitMeshs.Add(GetImplicitFunction(meshCopy, processingMode == ProcessingModes.Polygons, 1 << (int)inputResolution));
|
||||
}
|
||||
|
||||
DMesh3 GenerateMeshF(BoundedImplicitFunction3d root, int numCells)
|
||||
{
|
||||
var bounds = root.Bounds();
|
||||
|
||||
var c = new MarchingCubesPro()
|
||||
{
|
||||
Implicit = root,
|
||||
RootMode = MarchingCubesPro.RootfindingModes.LerpSteps, // cube-edge convergence method
|
||||
RootModeSteps = 5, // number of iterations
|
||||
Bounds = bounds,
|
||||
CubeSize = bounds.MaxDim / numCells,
|
||||
};
|
||||
|
||||
c.Bounds.Expand(3 * c.CubeSize); // leave a buffer of cells
|
||||
c.Generate();
|
||||
|
||||
MeshNormals.QuickCompute(c.Mesh); // generate normals
|
||||
return c.Mesh;
|
||||
}
|
||||
|
||||
switch (operation)
|
||||
{
|
||||
case CsgModes.Union:
|
||||
if (processingMode == ProcessingModes.Dual_Contouring)
|
||||
{
|
||||
var union = new ImplicitNaryUnion3d()
|
||||
{
|
||||
Children = implicitMeshs
|
||||
};
|
||||
var bounds = union.Bounds();
|
||||
var size = bounds.Max - bounds.Min;
|
||||
var root = Octree.BuildOctree((pos) =>
|
||||
{
|
||||
var pos2 = new Vector3d(pos.X, pos.Y, pos.Z);
|
||||
return union.Value(ref pos2);
|
||||
}, new Vector3(bounds.Min.x, bounds.Min.y, bounds.Min.z),
|
||||
new Vector3(size.x, size.y, size.z),
|
||||
(int)outputResolution,
|
||||
.001);
|
||||
implicitResult = Octree.GenerateMeshFromOctree(root);
|
||||
}
|
||||
else
|
||||
{
|
||||
implicitResult = GenerateMeshF(new ImplicitNaryUnion3d()
|
||||
{
|
||||
Children = implicitMeshs
|
||||
}, 1 << (int)outputResolution).ToMesh();
|
||||
}
|
||||
break;
|
||||
|
||||
case CsgModes.Subtract:
|
||||
{
|
||||
if (processingMode == ProcessingModes.Dual_Contouring)
|
||||
{
|
||||
var subtract = new ImplicitNaryIntersection3d()
|
||||
{
|
||||
Children = implicitMeshs
|
||||
};
|
||||
var bounds = subtract.Bounds();
|
||||
var root = Octree.BuildOctree((pos) =>
|
||||
{
|
||||
var pos2 = new Vector3d(pos.X, pos.Y, pos.Z);
|
||||
return subtract.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);
|
||||
implicitResult = Octree.GenerateMeshFromOctree(root);
|
||||
}
|
||||
else
|
||||
{
|
||||
implicitResult = GenerateMeshF(new ImplicitNaryDifference3d()
|
||||
{
|
||||
A = implicitMeshs.First(),
|
||||
BSet = implicitMeshs.GetRange(0, implicitMeshs.Count - 1)
|
||||
}, 1 << (int)outputResolution).ToMesh();
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case CsgModes.Intersect:
|
||||
if (processingMode == ProcessingModes.Dual_Contouring)
|
||||
{
|
||||
var intersect = new ImplicitNaryIntersection3d()
|
||||
{
|
||||
Children = implicitMeshs
|
||||
};
|
||||
var bounds = intersect.Bounds();
|
||||
var root = Octree.BuildOctree((pos) =>
|
||||
{
|
||||
var pos2 = new Vector3d(pos.X, pos.Y, pos.Z);
|
||||
return intersect.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);
|
||||
implicitResult = Octree.GenerateMeshFromOctree(root);
|
||||
}
|
||||
else
|
||||
{
|
||||
implicitResult = GenerateMeshF(new ImplicitNaryIntersection3d()
|
||||
{
|
||||
Children = implicitMeshs
|
||||
}, 1 << (int)outputResolution).ToMesh();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return implicitResult;
|
||||
}
|
||||
|
||||
private static Mesh ExactLegacy(IEnumerable<(Mesh mesh, Matrix4X4 matrix)> items,
|
||||
CsgModes operation,
|
||||
ProcessingModes processingMode,
|
||||
ProcessingResolution inputResolution,
|
||||
ProcessingResolution outputResolution,
|
||||
IProgress<ProgressStatus> reporter,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var progressStatus = new ProgressStatus();
|
||||
var totalOperations = items.Count() - 1;
|
||||
double amountPerOperation = 1.0 / totalOperations;
|
||||
double ratioCompleted = 0;
|
||||
|
||||
var first = true;
|
||||
var resultsMesh = items.First().mesh;
|
||||
var firstWorldMatrix = items.First().matrix;
|
||||
|
||||
foreach (var (mesh, matrix) in items)
|
||||
{
|
||||
if (first)
|
||||
{
|
||||
first = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
var itemWorldMatrix = matrix;
|
||||
resultsMesh = Do(
|
||||
// other mesh
|
||||
resultsMesh,
|
||||
firstWorldMatrix,
|
||||
mesh,
|
||||
itemWorldMatrix,
|
||||
// operation
|
||||
operation,
|
||||
processingMode,
|
||||
inputResolution,
|
||||
outputResolution,
|
||||
// reporting
|
||||
reporter,
|
||||
amountPerOperation,
|
||||
ratioCompleted,
|
||||
progressStatus,
|
||||
cancellationToken);
|
||||
|
||||
// after the first union we are working with the transformed mesh and don't need the first transform
|
||||
firstWorldMatrix = Matrix4X4.Identity;
|
||||
|
||||
ratioCompleted += amountPerOperation;
|
||||
progressStatus.Progress0To1 = ratioCompleted;
|
||||
reporter?.Report(progressStatus);
|
||||
}
|
||||
|
||||
return resultsMesh;
|
||||
}
|
||||
|
||||
public static Mesh Do(Mesh inMeshA,
|
||||
Matrix4X4 matrixA,
|
||||
// mesh B
|
||||
Mesh inMeshB,
|
||||
Matrix4X4 matrixB,
|
||||
// operation
|
||||
CsgModes operation,
|
||||
ProcessingModes processingMode = ProcessingModes.Polygons,
|
||||
ProcessingResolution inputResolution = ProcessingResolution._64,
|
||||
ProcessingResolution outputResolution = ProcessingResolution._64,
|
||||
// reporting
|
||||
IProgress<ProgressStatus> reporter = null,
|
||||
double amountPerOperation = 1,
|
||||
double ratioCompleted = 0,
|
||||
ProgressStatus progressStatus = null,
|
||||
CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
bool externalAssemblyExists = File.Exists(BooleanAssembly);
|
||||
if (processingMode == ProcessingModes.Polygons)
|
||||
{
|
||||
return BooleanProcessing.DoArray(new (Mesh, Matrix4X4)[] { (inMeshA, matrixA), (inMeshB, matrixB) },
|
||||
operation,
|
||||
processingMode,
|
||||
inputResolution,
|
||||
outputResolution,
|
||||
reporter,
|
||||
cancellationToken,
|
||||
amountPerOperation,
|
||||
ratioCompleted);
|
||||
}
|
||||
else if (processingMode == ProcessingModes.libigl)
|
||||
{
|
||||
// only try to run the improved booleans if we are 64 bit and it is there
|
||||
if (externalAssemblyExists && IntPtr.Size == 8)
|
||||
{
|
||||
IntPtr pVc = IntPtr.Zero;
|
||||
IntPtr pFc = IntPtr.Zero;
|
||||
try
|
||||
{
|
||||
double[] va;
|
||||
int[] fa;
|
||||
va = inMeshA.Vertices.ToDoubleArray(matrixA);
|
||||
fa = inMeshA.Faces.ToIntArray();
|
||||
double[] vb;
|
||||
int[] fb;
|
||||
vb = inMeshB.Vertices.ToDoubleArray(matrixB);
|
||||
fb = inMeshB.Faces.ToIntArray();
|
||||
|
||||
DoBooleanOperation(va,
|
||||
va.Length,
|
||||
fa,
|
||||
fa.Length,
|
||||
// object B
|
||||
vb,
|
||||
vb.Length,
|
||||
fb,
|
||||
fb.Length,
|
||||
// operation
|
||||
(int)operation,
|
||||
// results
|
||||
out pVc,
|
||||
out int vcCount,
|
||||
out pFc,
|
||||
out int fcCount);
|
||||
|
||||
var vcArray = new double[vcCount];
|
||||
Marshal.Copy(pVc, vcArray, 0, vcCount);
|
||||
|
||||
var fcArray = new int[fcCount];
|
||||
Marshal.Copy(pFc, fcArray, 0, fcCount);
|
||||
|
||||
return new Mesh(vcArray, fcArray);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// ApplicationController.Instance.LogInfo("Error performing boolean operation: ");
|
||||
// ApplicationController.Instance.LogInfo(ex.Message);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (pVc != IntPtr.Zero)
|
||||
{
|
||||
DeleteDouble(ref pVc);
|
||||
}
|
||||
|
||||
if (pFc != IntPtr.Zero)
|
||||
{
|
||||
DeleteInt(ref pFc);
|
||||
}
|
||||
|
||||
if (progressStatus != null)
|
||||
{
|
||||
progressStatus.Progress0To1 = ratioCompleted + amountPerOperation;
|
||||
reporter.Report(progressStatus);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine($"libigl skipped - AssemblyExists: {externalAssemblyExists}; Is64Bit: {IntPtr.Size == 8};");
|
||||
|
||||
var meshA = inMeshA.Copy(CancellationToken.None);
|
||||
meshA.Transform(matrixA);
|
||||
|
||||
var meshB = inMeshB.Copy(CancellationToken.None);
|
||||
meshB.Transform(matrixB);
|
||||
|
||||
switch (operation)
|
||||
{
|
||||
case CsgModes.Union:
|
||||
return Csg.CsgOperations.Union(meshA,
|
||||
meshB,
|
||||
(status, progress0To1) =>
|
||||
{
|
||||
// Abort if flagged
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
progressStatus.Status = status;
|
||||
progressStatus.Progress0To1 = ratioCompleted + (amountPerOperation * progress0To1);
|
||||
reporter?.Report(progressStatus);
|
||||
},
|
||||
cancellationToken);
|
||||
|
||||
case CsgModes.Subtract:
|
||||
return Csg.CsgOperations.Subtract(meshA,
|
||||
meshB,
|
||||
(status, progress0To1) =>
|
||||
{
|
||||
progressStatus.Status = status;
|
||||
progressStatus.Progress0To1 = ratioCompleted + (amountPerOperation * progress0To1);
|
||||
reporter?.Report(progressStatus);
|
||||
},
|
||||
cancellationToken);
|
||||
|
||||
case CsgModes.Intersect:
|
||||
return Csg.CsgOperations.Intersect(meshA,
|
||||
meshB,
|
||||
(status, progress0To1) =>
|
||||
{
|
||||
// Abort if flagged
|
||||
cancellationToken.ThrowIfCancellationRequested(); progressStatus.Status = status;
|
||||
progressStatus.Progress0To1 = ratioCompleted + (amountPerOperation * progress0To1);
|
||||
reporter.Report(progressStatus);
|
||||
},
|
||||
cancellationToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var meshA = inMeshA.Copy(CancellationToken.None);
|
||||
meshA.Transform(matrixA);
|
||||
|
||||
var meshB = inMeshB.Copy(CancellationToken.None);
|
||||
meshB.Transform(matrixB);
|
||||
|
||||
if (meshA.Faces.Count < 4)
|
||||
{
|
||||
return meshB;
|
||||
}
|
||||
else if (meshB.Faces.Count < 4)
|
||||
{
|
||||
return meshA;
|
||||
}
|
||||
|
||||
var implicitA = GetImplicitFunction(meshA, processingMode == ProcessingModes.Polygons, (int)inputResolution);
|
||||
var implicitB = GetImplicitFunction(meshB, processingMode == ProcessingModes.Polygons, (int)inputResolution);
|
||||
|
||||
DMesh3 GenerateMeshF(BoundedImplicitFunction3d root, int numCells)
|
||||
{
|
||||
var bounds = root.Bounds();
|
||||
|
||||
var c = new MarchingCubes()
|
||||
{
|
||||
Implicit = root,
|
||||
RootMode = MarchingCubes.RootfindingModes.LerpSteps, // cube-edge convergence method
|
||||
RootModeSteps = 5, // number of iterations
|
||||
Bounds = bounds,
|
||||
CubeSize = bounds.MaxDim / numCells,
|
||||
};
|
||||
|
||||
c.Bounds.Expand(3 * c.CubeSize); // leave a buffer of cells
|
||||
c.Generate();
|
||||
|
||||
MeshNormals.QuickCompute(c.Mesh); // generate normals
|
||||
return c.Mesh;
|
||||
}
|
||||
|
||||
var marchingCells = 1 << (int)outputResolution;
|
||||
switch (operation)
|
||||
{
|
||||
case CsgModes.Union:
|
||||
return GenerateMeshF(new ImplicitUnion3d()
|
||||
{
|
||||
A = implicitA,
|
||||
B = implicitB
|
||||
}, marchingCells).ToMesh();
|
||||
|
||||
case CsgModes.Subtract:
|
||||
return GenerateMeshF(new ImplicitDifference3d()
|
||||
{
|
||||
A = implicitA,
|
||||
B = implicitB
|
||||
}, marchingCells).ToMesh();
|
||||
|
||||
case CsgModes.Intersect:
|
||||
return GenerateMeshF(new ImplicitIntersection3d()
|
||||
{
|
||||
A = implicitA,
|
||||
B = implicitB
|
||||
}, marchingCells).ToMesh();
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
class MWNImplicit : BoundedImplicitFunction3d
|
||||
{
|
||||
public DMeshAABBTree3 MeshAABBTree3;
|
||||
public AxisAlignedBox3d Bounds() { return MeshAABBTree3.Bounds; }
|
||||
public double Value(ref Vector3d pt)
|
||||
{
|
||||
return -(MeshAABBTree3.FastWindingNumber(pt) - 0.5);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static BoundedImplicitFunction3d GetImplicitFunction(Mesh mesh, bool exact, int numCells)
|
||||
{
|
||||
var meshA3 = mesh.ToDMesh3();
|
||||
|
||||
// Interesting experiment, this produces an extremely accurate surface representation but is quite slow (even though fast) compared to voxel lookups.
|
||||
if (exact)
|
||||
{
|
||||
DMeshAABBTree3 meshAABBTree3 = new DMeshAABBTree3(meshA3, true);
|
||||
meshAABBTree3.FastWindingNumber(Vector3d.Zero); // build approximation
|
||||
return new MWNImplicit()
|
||||
{
|
||||
MeshAABBTree3 = meshAABBTree3
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
double meshCellsize = meshA3.CachedBounds.MaxDim / numCells;
|
||||
var signedDistance = new MeshSignedDistanceGrid(meshA3, meshCellsize);
|
||||
signedDistance.Compute();
|
||||
return new DenseGridTrilinearImplicit(signedDistance.Grid, signedDistance.GridOrigin, signedDistance.CellSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,314 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2019, Lars Brubaker, John Lewin
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
The views and conclusions contained in the software and documentation are those
|
||||
of the authors and should not be interpreted as representing official policies,
|
||||
either expressed or implied, of the FreeBSD Project.
|
||||
*/
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using ClipperLib;
|
||||
using MatterHackers.DataConverters3D;
|
||||
using MatterHackers.PolygonMesh.Csg;
|
||||
using MatterHackers.VectorMath;
|
||||
|
||||
namespace MatterHackers.PolygonMesh
|
||||
{
|
||||
using Polygon = List<IntPoint>;
|
||||
using Polygons = List<List<IntPoint>>;
|
||||
|
||||
public class CoPlanarFaces
|
||||
{
|
||||
private new Dictionary<Plane, Dictionary<int, List<(int sourceFaceIndex, int destFaceIndex)>>> coPlanarFaces
|
||||
= new Dictionary<Plane, Dictionary<int, List<(int sourceFaceIndex, int destFaceIndex)>>>();
|
||||
|
||||
public IEnumerable<Plane> Planes
|
||||
{
|
||||
get
|
||||
{
|
||||
foreach (var plane in coPlanarFaces.Keys)
|
||||
{
|
||||
yield return plane;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<int> MeshIndicesForPlane(Plane plane)
|
||||
{
|
||||
foreach (var kvp in coPlanarFaces[plane])
|
||||
{
|
||||
yield return kvp.Key;
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<(int sourceFaceIndex, int destFaceIndex)> FacesSetsForPlaneAndMesh(Plane plane, int meshIndex)
|
||||
{
|
||||
if (coPlanarFaces[plane].ContainsKey(meshIndex))
|
||||
{
|
||||
foreach (var faceIndices in coPlanarFaces[plane][meshIndex])
|
||||
{
|
||||
yield return faceIndices;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static Polygon GetFacePolygon(Mesh mesh1, int faceIndex, Matrix4X4 meshTo0Plane)
|
||||
{
|
||||
var facePolygon = new Polygon();
|
||||
var vertices = mesh1.Vertices;
|
||||
var face = mesh1.Faces[faceIndex];
|
||||
var vertIndices = new int[] { face.v0, face.v1, face.v2 };
|
||||
var vertsOnPlane = new Vector3[3];
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
vertsOnPlane[i] = Vector3Ex.Transform(vertices[vertIndices[i]].AsVector3(), meshTo0Plane);
|
||||
var pointOnPlane = new IntPoint(vertsOnPlane[i].X, vertsOnPlane[i].Y);
|
||||
facePolygon.Add(pointOnPlane);
|
||||
}
|
||||
|
||||
return facePolygon;
|
||||
|
||||
}
|
||||
|
||||
public void SubtractFaces(Plane plane, List<Mesh> transformedMeshes, Mesh resultsMesh, Matrix4X4 flattenedMatrix, HashSet<int> faceIndicesToRemove)
|
||||
{
|
||||
// get all meshes that have faces on this plane
|
||||
var meshesWithFaces = MeshIndicesForPlane(plane).ToList();
|
||||
|
||||
// we need more than one mesh and one of them needs to be the source (mesh 0)
|
||||
if (meshesWithFaces.Count < 2
|
||||
|| !meshesWithFaces.Contains(0))
|
||||
{
|
||||
// no faces to add
|
||||
return;
|
||||
}
|
||||
|
||||
// sort them so we can process each group into intersections
|
||||
meshesWithFaces.Sort();
|
||||
|
||||
// add the faces that we should
|
||||
foreach (var meshIndex in meshesWithFaces)
|
||||
{
|
||||
foreach (var faces in FacesSetsForPlaneAndMesh(plane, meshIndex))
|
||||
{
|
||||
faceIndicesToRemove.Add(faces.destFaceIndex);
|
||||
}
|
||||
}
|
||||
|
||||
// subtract every face from the mesh 0 faces
|
||||
// teselate and add what is left
|
||||
var keepPolygons = new Polygons();
|
||||
foreach (var keepFaceSets in FacesSetsForPlaneAndMesh(plane, 0))
|
||||
{
|
||||
var facePolygon = GetFacePolygon(transformedMeshes[0], keepFaceSets.sourceFaceIndex, flattenedMatrix);
|
||||
keepPolygons = keepPolygons.Union(facePolygon);
|
||||
}
|
||||
|
||||
// iterate all the meshes that need to be subtracted
|
||||
var removePoygons = new Polygons();
|
||||
for (int removeMeshIndex = 1; removeMeshIndex < meshesWithFaces.Count; removeMeshIndex++)
|
||||
{
|
||||
foreach (var removeFaceSets in FacesSetsForPlaneAndMesh(plane, removeMeshIndex))
|
||||
{
|
||||
removePoygons = removePoygons.Union(GetFacePolygon(transformedMeshes[removeMeshIndex], removeFaceSets.sourceFaceIndex, flattenedMatrix));
|
||||
}
|
||||
}
|
||||
|
||||
var polygonShape = new Polygons();
|
||||
var clipper = new Clipper();
|
||||
clipper.AddPaths(keepPolygons, PolyType.ptSubject, true);
|
||||
clipper.AddPaths(removePoygons, PolyType.ptClip, true);
|
||||
clipper.Execute(ClipType.ctDifference, polygonShape);
|
||||
|
||||
// teselate and add all the new polygons
|
||||
var countPreAdd = resultsMesh.Faces.Count;
|
||||
polygonShape.Vertices(1).TriangulateFaces(null, resultsMesh, 0, flattenedMatrix.Inverted);
|
||||
EnsureFaceNormals(plane, resultsMesh, countPreAdd);
|
||||
}
|
||||
|
||||
private static void EnsureFaceNormals(Plane plane, Mesh resultsMesh, int countPreAdd)
|
||||
{
|
||||
if (countPreAdd >= resultsMesh.Faces.Count)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Check that the new face normals are pointed in the right direction
|
||||
if ((new Vector3(resultsMesh.Faces[countPreAdd].normal) - plane.Normal).LengthSquared > .1)
|
||||
{
|
||||
for (int i = countPreAdd; i < resultsMesh.Faces.Count; i++)
|
||||
{
|
||||
resultsMesh.FlipFace(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void IntersectFaces(Plane plane, List<Mesh> transformedMeshes, Mesh resultsMesh, Matrix4X4 flattenedMatrix, HashSet<int> faceIndicesToRemove)
|
||||
{
|
||||
// get all meshes that have faces on this plane
|
||||
var meshesWithFaces = MeshIndicesForPlane(plane).ToList();
|
||||
|
||||
// we need more than one mesh
|
||||
if (meshesWithFaces.Count < 2)
|
||||
{
|
||||
// no faces to add
|
||||
return;
|
||||
}
|
||||
|
||||
// add the faces that we should remove
|
||||
foreach (var meshIndex in meshesWithFaces)
|
||||
{
|
||||
foreach (var faces in FacesSetsForPlaneAndMesh(plane, meshIndex))
|
||||
{
|
||||
faceIndicesToRemove.Add(faces.destFaceIndex);
|
||||
}
|
||||
}
|
||||
|
||||
var polygonsByMesh = new List<Polygons>();
|
||||
// iterate all the meshes that need to be intersected
|
||||
for (int meshIndex = 0; meshIndex < meshesWithFaces.Count; meshIndex++)
|
||||
{
|
||||
var unionedPoygons = new Polygons();
|
||||
foreach (var removeFaceSets in FacesSetsForPlaneAndMesh(plane, meshIndex))
|
||||
{
|
||||
unionedPoygons = unionedPoygons.Union(GetFacePolygon(transformedMeshes[meshIndex], removeFaceSets.sourceFaceIndex, flattenedMatrix));
|
||||
}
|
||||
|
||||
polygonsByMesh.Add(unionedPoygons);
|
||||
}
|
||||
|
||||
var total = new Polygons(polygonsByMesh[0]);
|
||||
for (int i = 1; i < polygonsByMesh.Count; i++)
|
||||
{
|
||||
var polygonShape = new Polygons();
|
||||
var clipper = new Clipper();
|
||||
clipper.AddPaths(total, PolyType.ptSubject, true);
|
||||
clipper.AddPaths(polygonsByMesh[i], PolyType.ptClip, true);
|
||||
clipper.Execute(ClipType.ctIntersection, polygonShape);
|
||||
|
||||
total = polygonShape;
|
||||
}
|
||||
|
||||
// teselate and add all the new polygons
|
||||
var countPreAdd = resultsMesh.Faces.Count;
|
||||
total.Vertices(1).TriangulateFaces(null, resultsMesh, 0, flattenedMatrix.Inverted);
|
||||
EnsureFaceNormals(plane, resultsMesh, countPreAdd);
|
||||
}
|
||||
|
||||
public void UnionFaces(Plane plane, List<Mesh> transformedMeshes, Mesh resultsMesh, Matrix4X4 flattenedMatrix)
|
||||
{
|
||||
// get all meshes that have faces on this plane
|
||||
var meshesWithFaces = MeshIndicesForPlane(plane).ToList();
|
||||
|
||||
if (meshesWithFaces.Count < 2)
|
||||
{
|
||||
// no faces to add
|
||||
return;
|
||||
}
|
||||
|
||||
// sort them so we can process each group into intersections
|
||||
meshesWithFaces.Sort();
|
||||
|
||||
var meshPolygons = new List<Polygons>();
|
||||
for (int i = 0; i < meshesWithFaces.Count; i++)
|
||||
{
|
||||
meshPolygons.Add(new Polygons());
|
||||
var addedFaces = new HashSet<int>();
|
||||
foreach (var (sourceFaceIndex, destFaceIndex) in this.FacesSetsForPlaneAndMesh(plane, i))
|
||||
{
|
||||
if (!addedFaces.Contains(sourceFaceIndex))
|
||||
{
|
||||
meshPolygons[i].Add(GetFacePolygon(transformedMeshes[i], sourceFaceIndex, flattenedMatrix));
|
||||
addedFaces.Add(sourceFaceIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var intersectionSets = new List<Polygons>();
|
||||
// now intersect each set of meshes to get all the sets of intersections
|
||||
for (int i = 0; i < meshesWithFaces.Count; i++)
|
||||
{
|
||||
// add all the faces for mesh j
|
||||
for (int j = i + 1; j < meshesWithFaces.Count; j++)
|
||||
{
|
||||
var clipper = new Clipper();
|
||||
clipper.AddPaths(meshPolygons[i], PolyType.ptSubject, true);
|
||||
clipper.AddPaths(meshPolygons[j], PolyType.ptClip, true);
|
||||
|
||||
var intersection = new Polygons();
|
||||
clipper.Execute(ClipType.ctIntersection, intersection);
|
||||
|
||||
intersectionSets.Add(intersection);
|
||||
}
|
||||
}
|
||||
|
||||
// now union all the intersections
|
||||
var totalSlices = new Polygons(intersectionSets[0]);
|
||||
for (int i = 1; i < intersectionSets.Count; i++)
|
||||
{
|
||||
// clip against the slice based on the parameters
|
||||
var clipper = new Clipper();
|
||||
clipper.AddPaths(totalSlices, PolyType.ptSubject, true);
|
||||
clipper.AddPaths(intersectionSets[i], PolyType.ptClip, true);
|
||||
clipper.Execute(ClipType.ctUnion, totalSlices);
|
||||
}
|
||||
|
||||
// teselate and add all the new polygons
|
||||
var countPreAdd = resultsMesh.Faces.Count;
|
||||
totalSlices.Vertices(1).TriangulateFaces(null, resultsMesh, 0, flattenedMatrix.Inverted);
|
||||
EnsureFaceNormals(plane, resultsMesh, countPreAdd);
|
||||
}
|
||||
|
||||
public void StoreFaceAdd(PlaneNormalXSorter planeSorter,
|
||||
Plane facePlane,
|
||||
int sourceMeshIndex,
|
||||
int sourceFaceIndex,
|
||||
int destFaceIndex)
|
||||
{
|
||||
// look through all the planes that are close to this one
|
||||
var plane = planeSorter.FindPlane(facePlane, .02, .0002);
|
||||
if (plane != null)
|
||||
{
|
||||
facePlane = plane.Value;
|
||||
}
|
||||
else
|
||||
{
|
||||
int a = 0;
|
||||
}
|
||||
|
||||
if (!coPlanarFaces.ContainsKey(facePlane))
|
||||
{
|
||||
coPlanarFaces[facePlane] = new Dictionary<int, List<(int sourceFace, int destFace)>>();
|
||||
}
|
||||
|
||||
if (!coPlanarFaces[facePlane].ContainsKey(sourceMeshIndex))
|
||||
{
|
||||
coPlanarFaces[facePlane][sourceMeshIndex] = new List<(int sourceFace, int destFace)>();
|
||||
}
|
||||
|
||||
coPlanarFaces[facePlane][sourceMeshIndex].Add((sourceFaceIndex, destFaceIndex));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,322 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2019, Lars Brubaker, John Lewin
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
The views and conclusions contained in the software and documentation are those
|
||||
of the authors and should not be interpreted as representing official policies,
|
||||
either expressed or implied, of the FreeBSD Project.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using ClipperLib;
|
||||
using MatterHackers.Agg;
|
||||
using MatterHackers.DataConverters3D;
|
||||
using MatterHackers.PolygonMesh.Csg;
|
||||
using MatterHackers.PolygonMesh.Processors;
|
||||
using MatterHackers.RayTracer;
|
||||
using MatterHackers.VectorMath;
|
||||
|
||||
namespace MatterHackers.PolygonMesh
|
||||
{
|
||||
using Polygons = List<List<IntPoint>>;
|
||||
|
||||
public class CsgBySlicing
|
||||
{
|
||||
private int totalOperations;
|
||||
private List<Mesh> transformedMeshes;
|
||||
private List<ITraceable> bvhAccelerators;
|
||||
private List<List<Plane>> plansByMesh;
|
||||
private PlaneNormalXSorter planeSorter;
|
||||
private Dictionary<Plane, (Matrix4X4 matrix, Matrix4X4 inverted)> transformTo0Planes;
|
||||
|
||||
public CsgBySlicing()
|
||||
{
|
||||
}
|
||||
|
||||
public void Setup(IEnumerable<(Mesh mesh, Matrix4X4 matrix)> meshAndMatrix,
|
||||
Action<double, string> progressReporter,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
totalOperations = 0;
|
||||
transformedMeshes = new List<Mesh>();
|
||||
bvhAccelerators = new List<ITraceable>();
|
||||
foreach (var (mesh, matrix) in meshAndMatrix)
|
||||
{
|
||||
totalOperations += mesh.Faces.Count;
|
||||
var meshCopy = mesh.Copy(cancellationToken);
|
||||
transformedMeshes.Add(meshCopy);
|
||||
meshCopy.Transform(matrix);
|
||||
bvhAccelerators.Add(MeshToBVH.Convert(meshCopy));
|
||||
}
|
||||
|
||||
plansByMesh = new List<List<Plane>>();
|
||||
var uniquePlanes = new HashSet<Plane>();
|
||||
for (int i = 0; i < transformedMeshes.Count; i++)
|
||||
{
|
||||
var mesh = transformedMeshes[i];
|
||||
plansByMesh.Add(new List<Plane>());
|
||||
for (int j = 0; j < transformedMeshes[i].Faces.Count; j++)
|
||||
{
|
||||
var face = mesh.Faces[j];
|
||||
var cutPlane = new Plane(mesh.Vertices[face.v0].AsVector3(), mesh.Vertices[face.v1].AsVector3(), mesh.Vertices[face.v2].AsVector3());
|
||||
plansByMesh[i].Add(cutPlane);
|
||||
uniquePlanes.Add(cutPlane);
|
||||
}
|
||||
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
planeSorter = new PlaneNormalXSorter(uniquePlanes);
|
||||
transformTo0Planes = new Dictionary<Plane, (Matrix4X4 matrix, Matrix4X4 inverted)>();
|
||||
foreach (var plane in uniquePlanes)
|
||||
{
|
||||
var matrix = SliceLayer.GetTransformTo0Plane(plane);
|
||||
transformTo0Planes[plane] = (matrix, matrix.Inverted);
|
||||
}
|
||||
}
|
||||
|
||||
public Mesh Calculate(CsgModes operation,
|
||||
Action<double, string> progressReporter,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
double amountPerOperation = 1.0 / totalOperations;
|
||||
double ratioCompleted = 0;
|
||||
|
||||
var resultsMesh = new Mesh();
|
||||
|
||||
// keep track of all the faces added by their plane
|
||||
var coPlanarFaces = new CoPlanarFaces();
|
||||
|
||||
for (var mesh1Index = 0; mesh1Index < transformedMeshes.Count; mesh1Index++)
|
||||
{
|
||||
var mesh1 = transformedMeshes[mesh1Index];
|
||||
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
for (int faceIndex = 0; faceIndex < mesh1.Faces.Count; faceIndex++)
|
||||
{
|
||||
var face = mesh1.Faces[faceIndex];
|
||||
|
||||
var cutPlane = plansByMesh[mesh1Index][faceIndex];
|
||||
var totalSlice = new Polygons();
|
||||
var firstSlice = true;
|
||||
|
||||
var transformTo0Plane = transformTo0Planes[cutPlane].matrix;
|
||||
for (var sliceMeshIndex = 0; sliceMeshIndex < transformedMeshes.Count; sliceMeshIndex++)
|
||||
{
|
||||
if (mesh1Index == sliceMeshIndex)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var mesh2 = transformedMeshes[sliceMeshIndex];
|
||||
// calculate and add the PWN face from the loops
|
||||
var slice = SliceLayer.CreateSlice(mesh2, cutPlane, transformTo0Plane, bvhAccelerators[sliceMeshIndex]);
|
||||
if (firstSlice)
|
||||
{
|
||||
totalSlice = slice;
|
||||
firstSlice = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
totalSlice = totalSlice.Union(slice);
|
||||
}
|
||||
}
|
||||
|
||||
// now we have the total loops that this polygon can intersect from the other meshes
|
||||
// make a polygon for this face
|
||||
var facePolygon = CoPlanarFaces.GetFacePolygon(mesh1, faceIndex, transformTo0Plane);
|
||||
|
||||
var polygonShape = new Polygons();
|
||||
// clip against the slice based on the parameters
|
||||
var clipper = new Clipper();
|
||||
clipper.AddPath(facePolygon, PolyType.ptSubject, true);
|
||||
clipper.AddPaths(totalSlice, PolyType.ptClip, true);
|
||||
var expectedFaceNormal = face.normal;
|
||||
|
||||
switch (operation)
|
||||
{
|
||||
case CsgModes.Union:
|
||||
clipper.Execute(ClipType.ctDifference, polygonShape);
|
||||
break;
|
||||
|
||||
case CsgModes.Subtract:
|
||||
if (mesh1Index == 0)
|
||||
{
|
||||
clipper.Execute(ClipType.ctDifference, polygonShape);
|
||||
}
|
||||
else
|
||||
{
|
||||
expectedFaceNormal *= -1;
|
||||
clipper.Execute(ClipType.ctIntersection, polygonShape);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case CsgModes.Intersect:
|
||||
clipper.Execute(ClipType.ctIntersection, polygonShape);
|
||||
break;
|
||||
}
|
||||
|
||||
var faceCountPreAdd = resultsMesh.Faces.Count;
|
||||
|
||||
if (polygonShape.Count == 1
|
||||
&& polygonShape[0].Count == 3
|
||||
&& facePolygon.Contains(polygonShape[0][0])
|
||||
&& facePolygon.Contains(polygonShape[0][1])
|
||||
&& facePolygon.Contains(polygonShape[0][2]))
|
||||
{
|
||||
resultsMesh.AddFaceCopy(mesh1, faceIndex);
|
||||
}
|
||||
else
|
||||
{
|
||||
var preAddCount = resultsMesh.Vertices.Count;
|
||||
// mesh the new polygon and add it to the resultsMesh
|
||||
polygonShape.Vertices(1).TriangulateFaces(null, resultsMesh, 0, transformTo0Planes[cutPlane].inverted);
|
||||
var postAddCount = resultsMesh.Vertices.Count;
|
||||
|
||||
for (int addedIndex = preAddCount; addedIndex < postAddCount; addedIndex++)
|
||||
{
|
||||
// TODO: map all the added vertices that can be back to the original polygon positions
|
||||
for (int meshIndex = 0; meshIndex < transformedMeshes.Count; meshIndex++)
|
||||
{
|
||||
var bvhAccelerator = bvhAccelerators[meshIndex];
|
||||
var mesh = transformedMeshes[meshIndex];
|
||||
var addedPosition = resultsMesh.Vertices[addedIndex];
|
||||
var touchingBvhItems = bvhAccelerator.GetTouching(new Vector3(addedPosition), .0001);
|
||||
foreach (var touchingBvhItem in touchingBvhItems)
|
||||
{
|
||||
if (touchingBvhItem is TriangleShape triangleShape)
|
||||
{
|
||||
var sourceFaceIndex = triangleShape.Index;
|
||||
var sourceFace = mesh.Faces[sourceFaceIndex];
|
||||
var sourceVertexIndices = new int[] { sourceFace.v0, sourceFace.v1, sourceFace.v2 };
|
||||
foreach (var sourceVertexIndex in sourceVertexIndices)
|
||||
{
|
||||
var sourcePosition = mesh.Vertices[sourceVertexIndex];
|
||||
var deltaSquared = (addedPosition - sourcePosition).LengthSquared;
|
||||
if (deltaSquared > 0 && deltaSquared < .00001)
|
||||
{
|
||||
// add the vertex and set the face position index to the new vertex
|
||||
resultsMesh.Vertices[addedIndex] = sourcePosition;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (resultsMesh.Faces.Count - faceCountPreAdd > 0)
|
||||
{
|
||||
// keep track of the adds so we can process the coplanar faces after
|
||||
for (int i = faceCountPreAdd; i < resultsMesh.Faces.Count; i++)
|
||||
{
|
||||
coPlanarFaces.StoreFaceAdd(planeSorter, cutPlane, mesh1Index, faceIndex, i);
|
||||
// make sure our added faces are the right direction
|
||||
if (resultsMesh.Faces[i].normal.Dot(expectedFaceNormal) < 0)
|
||||
{
|
||||
resultsMesh.FlipFace(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
else // we did not add any faces but we will still keep track of this polygons plan
|
||||
{
|
||||
coPlanarFaces.StoreFaceAdd(planeSorter, cutPlane, mesh1Index, faceIndex, -1);
|
||||
}
|
||||
|
||||
ratioCompleted += amountPerOperation;
|
||||
progressReporter?.Invoke(ratioCompleted, "");
|
||||
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// handle the co-planar faces
|
||||
ProcessCoplanarFaces(operation, resultsMesh, coPlanarFaces);
|
||||
|
||||
resultsMesh.CleanAndMerge();
|
||||
return resultsMesh;
|
||||
}
|
||||
|
||||
private void ProcessCoplanarFaces(CsgModes operation, Mesh resultsMesh, CoPlanarFaces coPlanarFaces)
|
||||
{
|
||||
var faceIndicesToRemove = new HashSet<int>();
|
||||
foreach (var plane in coPlanarFaces.Planes)
|
||||
{
|
||||
var meshIndices = coPlanarFaces.MeshIndicesForPlane(plane);
|
||||
if (meshIndices.Count() > 1)
|
||||
{
|
||||
// check if more than one mesh has this polygons on this plan
|
||||
var flattenedMatrix = transformTo0Planes[plane].matrix;
|
||||
|
||||
// depending on the operation add or remove polygons that are planar
|
||||
switch (operation)
|
||||
{
|
||||
case CsgModes.Union:
|
||||
coPlanarFaces.UnionFaces(plane, transformedMeshes, resultsMesh, flattenedMatrix);
|
||||
break;
|
||||
|
||||
case CsgModes.Subtract:
|
||||
coPlanarFaces.SubtractFaces(plane, transformedMeshes, resultsMesh, flattenedMatrix, faceIndicesToRemove);
|
||||
break;
|
||||
|
||||
case CsgModes.Intersect:
|
||||
coPlanarFaces.IntersectFaces(plane, transformedMeshes, resultsMesh, flattenedMatrix, faceIndicesToRemove);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// now rebuild the face list without the remove polygons
|
||||
if (faceIndicesToRemove.Count > 0)
|
||||
{
|
||||
var newFaces = new FaceList();
|
||||
for (int i = 0; i < resultsMesh.Faces.Count; i++)
|
||||
{
|
||||
// if the face is NOT in the remove faces
|
||||
if (!faceIndicesToRemove.Contains(i))
|
||||
{
|
||||
var face = resultsMesh.Faces[i];
|
||||
newFaces.Add(face);
|
||||
}
|
||||
}
|
||||
|
||||
resultsMesh.Faces = newFaces;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,50 +0,0 @@
|
|||
using System;
|
||||
using g3;
|
||||
using MatterHackers.PolygonMesh;
|
||||
using MatterHackers.VectorMath;
|
||||
|
||||
namespace MatterHackers.MatterControl.DesignTools
|
||||
{
|
||||
public static class MeshExtensions
|
||||
{
|
||||
public static DMesh3 ToDMesh3(this Mesh inMesh)
|
||||
{
|
||||
var outMesh = new DMesh3();
|
||||
foreach (var vertex in inMesh.Vertices)
|
||||
{
|
||||
outMesh.AppendVertex(new Vector3d(vertex.X, vertex.Y, vertex.Z));
|
||||
}
|
||||
|
||||
foreach (var face in inMesh.Faces)
|
||||
{
|
||||
outMesh.AppendTriangle(face.v0, face.v1, face.v2);
|
||||
}
|
||||
|
||||
return outMesh;
|
||||
}
|
||||
|
||||
public static Mesh ToMesh(this DMesh3 mesh)
|
||||
{
|
||||
var outMesh = new Mesh();
|
||||
int[] mapV = new int[mesh.MaxVertexID];
|
||||
int nAccumCountV = 0;
|
||||
foreach (int vi in mesh.VertexIndices())
|
||||
{
|
||||
mapV[vi] = nAccumCountV++;
|
||||
Vector3d v = mesh.GetVertex(vi);
|
||||
outMesh.Vertices.Add(new Vector3(v[0], v[1], v[2]));
|
||||
}
|
||||
|
||||
foreach (int ti in mesh.TriangleIndices())
|
||||
{
|
||||
Index3i t = mesh.GetTriangle(ti);
|
||||
t[0] = mapV[t[0]];
|
||||
t[1] = mapV[t[1]];
|
||||
t[2] = mapV[t[2]];
|
||||
outMesh.Faces.Add(t[0], t[1], t[2], outMesh.Vertices);
|
||||
}
|
||||
|
||||
return outMesh;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,93 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2019, Lars Brubaker, John Lewin
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
The views and conclusions contained in the software and documentation are those
|
||||
of the authors and should not be interpreted as representing official policies,
|
||||
either expressed or implied, of the FreeBSD Project.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using ClipperLib;
|
||||
using MatterHackers.VectorMath;
|
||||
|
||||
namespace MatterHackers.PolygonMesh
|
||||
{
|
||||
public class PlaneNormalXSorter : IComparer<Plane>
|
||||
{
|
||||
private readonly List<Plane> planes;
|
||||
|
||||
public PlaneNormalXSorter(IEnumerable<Plane> inputPlanes)
|
||||
{
|
||||
planes = new List<Plane>(inputPlanes);
|
||||
planes.Sort(this);
|
||||
}
|
||||
|
||||
public int Compare(Plane a, Plane b)
|
||||
{
|
||||
return a.Normal.X.CompareTo(b.Normal.X);
|
||||
}
|
||||
|
||||
public Plane? FindPlane(Plane searchPlane,
|
||||
double distanceErrorValue = .01,
|
||||
double normalErrorValue = .0001)
|
||||
{
|
||||
Plane testPlane = searchPlane;
|
||||
int index = planes.BinarySearch(testPlane, this);
|
||||
if (index < 0)
|
||||
{
|
||||
index = ~index;
|
||||
}
|
||||
// we have the starting index now get all the vertices that are close enough starting from here
|
||||
for (int i = index; i < planes.Count; i++)
|
||||
{
|
||||
if (Math.Abs(planes[i].Normal.X - searchPlane.Normal.X) > normalErrorValue)
|
||||
{
|
||||
// we are too far away in x, we are done with this direction
|
||||
break;
|
||||
}
|
||||
|
||||
if (planes[i].Equals(searchPlane, distanceErrorValue, normalErrorValue))
|
||||
{
|
||||
return planes[i];
|
||||
}
|
||||
}
|
||||
for (int i = index - 1; i >= 0; i--)
|
||||
{
|
||||
if (Math.Abs(planes[i].Normal.X - searchPlane.Normal.X) > normalErrorValue)
|
||||
{
|
||||
// we are too far away in x, we are done with this direction
|
||||
break;
|
||||
}
|
||||
|
||||
if (planes[i].Equals(searchPlane, distanceErrorValue, normalErrorValue))
|
||||
{
|
||||
return planes[i];
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -9,8 +9,8 @@
|
|||
<RootNamespace>MatterControl</RootNamespace>
|
||||
<AssemblyName>MatterControl</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.7.1</TargetFrameworkVersion>
|
||||
<RuntimeIdentifier>win</RuntimeIdentifier>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<RuntimeIdentifier>win</RuntimeIdentifier>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<!--See the following for details on netstandard2 binding workround: https://github.com/dotnet/standard/issues/481-->
|
||||
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||
<RestoreProjectStyle>PackageReference</RestoreProjectStyle>
|
||||
|
|
@ -122,21 +122,9 @@
|
|||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="609_Boolean_bin.dll">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="application.ico">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="libgmp-10.dll">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="libigl_boolean.exe">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="libmpfr-4.dll">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<None Include="StaticData\MatterControl EULA.txt" />
|
||||
<None Include="StaticData\BuildInfo.txt" />
|
||||
<None Include="StaticData\License\agg-sharp.txt" />
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ using MatterHackers.Agg.VertexSource;
|
|||
using MatterHackers.DataConverters3D;
|
||||
using MatterHackers.MatterControl.CustomWidgets;
|
||||
using MatterHackers.MatterControl.DesignTools.Operations;
|
||||
using MatterHackers.PolygonMesh.Processors;
|
||||
using MatterHackers.VectorMath;
|
||||
|
||||
namespace MatterHackers.MatterControl.DesignTools
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ using MatterHackers.DataConverters3D;
|
|||
using MatterHackers.MatterControl.CustomWidgets;
|
||||
using MatterHackers.MatterControl.DesignTools.Operations;
|
||||
using MatterHackers.MatterControl.Plugins.BrailleBuilder;
|
||||
using MatterHackers.PolygonMesh.Processors;
|
||||
using MatterHackers.VectorMath;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Converters;
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ using MatterHackers.Agg.UI;
|
|||
using MatterHackers.Agg.VertexSource;
|
||||
using MatterHackers.DataConverters3D;
|
||||
using MatterHackers.MatterControl.DesignTools.Operations;
|
||||
using MatterHackers.PolygonMesh.Processors;
|
||||
using MatterHackers.VectorMath;
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ using System.Threading.Tasks;
|
|||
using MatterHackers.Agg.VertexSource;
|
||||
using MatterHackers.DataConverters3D;
|
||||
using MatterHackers.MatterControl.DesignTools.Operations;
|
||||
using MatterHackers.PolygonMesh.Processors;
|
||||
using MatterHackers.VectorMath;
|
||||
|
||||
namespace MatterHackers.MatterControl.DesignTools
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ using MatterHackers.Agg.Font;
|
|||
using MatterHackers.Agg.UI;
|
||||
using MatterHackers.DataConverters3D;
|
||||
using MatterHackers.MatterControl.DesignTools.Operations;
|
||||
using MatterHackers.PolygonMesh.Processors;
|
||||
using MatterHackers.VectorMath;
|
||||
|
||||
namespace MatterHackers.MatterControl.DesignTools
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ using MatterHackers.Agg.UI;
|
|||
using MatterHackers.DataConverters3D;
|
||||
using MatterHackers.Localizations;
|
||||
using MatterHackers.PolygonMesh;
|
||||
using MatterHackers.PolygonMesh.Csg;
|
||||
|
||||
namespace MatterHackers.MatterControl.PartPreviewWindow.View3D
|
||||
{
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ using MatterHackers.Agg.UI;
|
|||
using MatterHackers.DataConverters3D;
|
||||
using MatterHackers.Localizations;
|
||||
using MatterHackers.PolygonMesh;
|
||||
using MatterHackers.PolygonMesh.Csg;
|
||||
|
||||
namespace MatterHackers.MatterControl.PartPreviewWindow.View3D
|
||||
{
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ using MatterHackers.DataConverters3D;
|
|||
using MatterHackers.Localizations;
|
||||
using MatterHackers.MatterControl.DesignTools.Operations;
|
||||
using MatterHackers.PolygonMesh;
|
||||
using MatterHackers.PolygonMesh.Processors;
|
||||
|
||||
namespace MatterHackers.MatterControl.DesignTools
|
||||
{
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ using MatterHackers.Localizations;
|
|||
using MatterHackers.MatterControl.DesignTools.Operations;
|
||||
using MatterHackers.PolygonMesh;
|
||||
using MatterHackers.PolygonMesh.Csg;
|
||||
using MatterHackers.PolygonMesh.Processors;
|
||||
using MatterHackers.VectorMath;
|
||||
using Polygons = System.Collections.Generic.List<System.Collections.Generic.List<ClipperLib.IntPoint>>;
|
||||
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ using MatterHackers.DataConverters3D;
|
|||
using MatterHackers.Localizations;
|
||||
using MatterHackers.MatterControl.DesignTools.Operations;
|
||||
using MatterHackers.PolygonMesh;
|
||||
using MatterHackers.PolygonMesh.Processors;
|
||||
|
||||
namespace MatterHackers.MatterControl.DesignTools
|
||||
{
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ using MatterHackers.Agg.VertexSource;
|
|||
using MatterHackers.DataConverters3D;
|
||||
using MatterHackers.MatterControl.DesignTools.Operations;
|
||||
using MatterHackers.MatterControl.PartPreviewWindow;
|
||||
using MatterHackers.PolygonMesh.Processors;
|
||||
using Newtonsoft.Json;
|
||||
using System.Collections.Generic;
|
||||
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ using MatterHackers.DataConverters2D;
|
|||
using MatterHackers.DataConverters3D;
|
||||
using MatterHackers.Localizations;
|
||||
using MatterHackers.MatterControl.PartPreviewWindow;
|
||||
using MatterHackers.PolygonMesh.Processors;
|
||||
|
||||
namespace MatterHackers.MatterControl.DesignTools.Operations
|
||||
{
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ using MatterHackers.Localizations;
|
|||
using MatterHackers.MatterControl.PartPreviewWindow;
|
||||
using MatterHackers.Plugins.EditorTools;
|
||||
using MatterHackers.PolygonMesh;
|
||||
using MatterHackers.PolygonMesh.Processors;
|
||||
using MatterHackers.VectorMath;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ using MatterHackers.Agg.VertexSource;
|
|||
using MatterHackers.DataConverters3D;
|
||||
using MatterHackers.MatterControl.PartPreviewWindow;
|
||||
using MatterHackers.PolygonMesh;
|
||||
using MatterHackers.PolygonMesh.Processors;
|
||||
using MatterHackers.VectorMath;
|
||||
|
||||
namespace MatterHackers.MatterControl.DesignTools.Operations
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ using MatterHackers.DataConverters2D;
|
|||
using MatterHackers.DataConverters3D;
|
||||
using MatterHackers.Localizations;
|
||||
using MatterHackers.MatterControl.PartPreviewWindow;
|
||||
using MatterHackers.PolygonMesh.Processors;
|
||||
|
||||
namespace MatterHackers.MatterControl.DesignTools.Operations
|
||||
{
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ using MatterHackers.Localizations;
|
|||
using MatterHackers.MatterControl.DesignTools.Operations;
|
||||
using MatterHackers.MatterControl.PartPreviewWindow;
|
||||
using MatterHackers.PolygonMesh;
|
||||
using MatterHackers.PolygonMesh.Processors;
|
||||
using MatterHackers.RenderOpenGl;
|
||||
using MatterHackers.VectorMath;
|
||||
using Newtonsoft.Json;
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ using MatterHackers.DataConverters2D;
|
|||
using MatterHackers.DataConverters3D;
|
||||
using MatterHackers.Localizations;
|
||||
using MatterHackers.MatterControl.PartPreviewWindow;
|
||||
using MatterHackers.PolygonMesh.Processors;
|
||||
using Polygon = System.Collections.Generic.List<ClipperLib.IntPoint>;
|
||||
using Polygons = System.Collections.Generic.List<System.Collections.Generic.List<ClipperLib.IntPoint>>;
|
||||
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ using MatterHackers.Localizations;
|
|||
using MatterHackers.MatterControl.DesignTools.Operations;
|
||||
using MatterHackers.PolygonMesh;
|
||||
using MatterHackers.PolygonMesh.Csg;
|
||||
using MatterHackers.PolygonMesh.Processors;
|
||||
using MatterHackers.VectorMath;
|
||||
using Polygons = System.Collections.Generic.List<System.Collections.Generic.List<ClipperLib.IntPoint>>;
|
||||
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ using MatterHackers.DataConverters3D;
|
|||
using MatterHackers.Localizations;
|
||||
using MatterHackers.MatterControl.DesignTools.Operations;
|
||||
using MatterHackers.PolygonMesh;
|
||||
using MatterHackers.PolygonMesh.Processors;
|
||||
using static gs.MeshAutoRepair;
|
||||
|
||||
namespace MatterHackers.MatterControl.DesignTools
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ using MatterHackers.DataConverters3D;
|
|||
using MatterHackers.Localizations;
|
||||
using MatterHackers.MatterControl.PartPreviewWindow;
|
||||
using MatterHackers.PolygonMesh.Csg;
|
||||
using MatterHackers.PolygonMesh.Processors;
|
||||
using MatterHackers.RenderOpenGl;
|
||||
using MatterHackers.RenderOpenGl.OpenGl;
|
||||
using MatterHackers.VectorMath;
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ using MatterHackers.Localizations;
|
|||
using MatterHackers.MatterControl.DesignTools.Operations;
|
||||
using MatterHackers.MatterControl.PartPreviewWindow;
|
||||
using MatterHackers.PolygonMesh;
|
||||
using MatterHackers.PolygonMesh.Processors;
|
||||
using MatterHackers.VectorMath;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ using MatterHackers.DataConverters3D;
|
|||
using MatterHackers.Localizations;
|
||||
using MatterHackers.MatterControl.PartPreviewWindow;
|
||||
using MatterHackers.Plugins.EditorTools;
|
||||
using MatterHackers.PolygonMesh.Processors;
|
||||
using MatterHackers.VectorMath;
|
||||
|
||||
namespace MatterHackers.MatterControl.DesignTools
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ using MatterHackers.Localizations;
|
|||
using MatterHackers.MatterControl.DesignTools.Operations;
|
||||
using MatterHackers.MatterControl.PartPreviewWindow;
|
||||
using MatterHackers.Plugins.EditorTools;
|
||||
using MatterHackers.PolygonMesh.Processors;
|
||||
using MatterHackers.VectorMath;
|
||||
|
||||
namespace MatterHackers.MatterControl.DesignTools
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ using MatterHackers.Agg.VertexSource;
|
|||
using MatterHackers.DataConverters3D;
|
||||
using MatterHackers.Localizations;
|
||||
using MatterHackers.MatterControl.PartPreviewWindow;
|
||||
using MatterHackers.PolygonMesh.Processors;
|
||||
using MatterHackers.VectorMath;
|
||||
|
||||
namespace MatterHackers.MatterControl.DesignTools
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ using MatterHackers.DataConverters3D;
|
|||
using MatterHackers.Localizations;
|
||||
using MatterHackers.MatterControl.PartPreviewWindow;
|
||||
using MatterHackers.Plugins.EditorTools;
|
||||
using MatterHackers.PolygonMesh.Processors;
|
||||
using MatterHackers.VectorMath;
|
||||
|
||||
namespace MatterHackers.MatterControl.DesignTools
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ using MatterHackers.DataConverters3D;
|
|||
using MatterHackers.Localizations;
|
||||
using MatterHackers.MatterControl.PartPreviewWindow;
|
||||
using MatterHackers.Plugins.EditorTools;
|
||||
using MatterHackers.PolygonMesh.Processors;
|
||||
using MatterHackers.VectorMath;
|
||||
|
||||
namespace MatterHackers.MatterControl.DesignTools
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ using MatterHackers.DataConverters3D;
|
|||
using MatterHackers.Localizations;
|
||||
using MatterHackers.MatterControl.PartPreviewWindow;
|
||||
using MatterHackers.Plugins.EditorTools;
|
||||
using MatterHackers.PolygonMesh.Processors;
|
||||
using MatterHackers.VectorMath;
|
||||
|
||||
namespace MatterHackers.MatterControl.DesignTools
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ using MatterHackers.DataConverters3D;
|
|||
using MatterHackers.Localizations;
|
||||
using MatterHackers.MatterControl.PartPreviewWindow;
|
||||
using MatterHackers.Plugins.EditorTools;
|
||||
using MatterHackers.PolygonMesh.Processors;
|
||||
using MatterHackers.VectorMath;
|
||||
|
||||
namespace MatterHackers.MatterControl.DesignTools
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ using MatterHackers.DataConverters3D;
|
|||
using MatterHackers.Localizations;
|
||||
using MatterHackers.MatterControl.PartPreviewWindow;
|
||||
using MatterHackers.PolygonMesh;
|
||||
using MatterHackers.PolygonMesh.Processors;
|
||||
using MatterHackers.VectorMath;
|
||||
|
||||
namespace MatterHackers.MatterControl.DesignTools
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ using MatterHackers.Localizations;
|
|||
using MatterHackers.MatterControl.PartPreviewWindow;
|
||||
using MatterHackers.Plugins.EditorTools;
|
||||
using MatterHackers.PolygonMesh;
|
||||
using MatterHackers.PolygonMesh.Processors;
|
||||
using MatterHackers.VectorMath;
|
||||
|
||||
namespace MatterHackers.MatterControl.DesignTools
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ using MatterHackers.DataConverters3D;
|
|||
using MatterHackers.Localizations;
|
||||
using MatterHackers.MatterControl.PartPreviewWindow;
|
||||
using MatterHackers.PolygonMesh;
|
||||
using MatterHackers.PolygonMesh.Processors;
|
||||
using MatterHackers.VectorMath;
|
||||
|
||||
namespace MatterHackers.MatterControl.DesignTools
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ using MatterHackers.DataConverters3D.UndoCommands;
|
|||
using MatterHackers.Localizations;
|
||||
using MatterHackers.MatterControl.DesignTools.Operations;
|
||||
using MatterHackers.PolygonMesh;
|
||||
using MatterHackers.PolygonMesh.Processors;
|
||||
using MatterHackers.VectorMath;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Converters;
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ using MatterHackers.Localizations;
|
|||
using MatterHackers.MatterControl.DesignTools.Operations;
|
||||
using MatterHackers.MatterControl.PartPreviewWindow;
|
||||
using MatterHackers.PolygonMesh;
|
||||
using MatterHackers.PolygonMesh.Processors;
|
||||
using MatterHackers.VectorMath;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Converters;
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ using MatterHackers.DataConverters3D;
|
|||
using MatterHackers.Localizations;
|
||||
using MatterHackers.MatterControl.PartPreviewWindow;
|
||||
using MatterHackers.Plugins.EditorTools;
|
||||
using MatterHackers.PolygonMesh.Processors;
|
||||
using MatterHackers.VectorMath;
|
||||
|
||||
namespace MatterHackers.MatterControl.DesignTools
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ using MatterHackers.Agg.VertexSource;
|
|||
using MatterHackers.DataConverters3D;
|
||||
using MatterHackers.Localizations;
|
||||
using MatterHackers.MatterControl.PartPreviewWindow;
|
||||
using MatterHackers.PolygonMesh.Processors;
|
||||
using MatterHackers.VectorMath;
|
||||
|
||||
namespace MatterHackers.MatterControl.DesignTools
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ using MatterHackers.Agg.VertexSource;
|
|||
using MatterHackers.DataConverters3D;
|
||||
using MatterHackers.Localizations;
|
||||
using MatterHackers.MatterControl.PartPreviewWindow;
|
||||
using MatterHackers.PolygonMesh.Processors;
|
||||
using MatterHackers.VectorMath;
|
||||
|
||||
namespace MatterHackers.MatterControl.DesignTools
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ using MatterHackers.Agg.VertexSource;
|
|||
using MatterHackers.DataConverters3D;
|
||||
using MatterHackers.Localizations;
|
||||
using MatterHackers.PolygonMesh;
|
||||
using MatterHackers.PolygonMesh.Processors;
|
||||
using MatterHackers.VectorMath;
|
||||
|
||||
namespace MatterHackers.MatterControl.DesignTools
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ using MatterHackers.Agg.VertexSource;
|
|||
using MatterHackers.DataConverters3D;
|
||||
using MatterHackers.Localizations;
|
||||
using MatterHackers.PolygonMesh;
|
||||
using MatterHackers.PolygonMesh.Processors;
|
||||
using MatterHackers.VectorMath;
|
||||
|
||||
namespace MatterHackers.MatterControl.DesignTools
|
||||
|
|
|
|||
|
|
@ -28,7 +28,6 @@ either expressed or implied, of the FreeBSD Project.
|
|||
*/
|
||||
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
|
@ -38,7 +37,7 @@ using MatterHackers.DataConverters3D;
|
|||
using MatterHackers.Localizations;
|
||||
using MatterHackers.MatterControl.DesignTools;
|
||||
using MatterHackers.MatterControl.DesignTools.Operations;
|
||||
using MatterHackers.PolygonMesh;
|
||||
using MatterHackers.PolygonMesh.Csg;
|
||||
using MatterHackers.VectorMath;
|
||||
|
||||
namespace MatterHackers.MatterControl.PartPreviewWindow.View3D
|
||||
|
|
@ -191,17 +190,12 @@ namespace MatterHackers.MatterControl.PartPreviewWindow.View3D
|
|||
}
|
||||
}
|
||||
|
||||
private bool ProcessPolygons
|
||||
{
|
||||
get => Processing == ProcessingModes.Polygons || Processing == ProcessingModes.libigl;
|
||||
}
|
||||
|
||||
public void UpdateControls(PublicPropertyChange change)
|
||||
{
|
||||
change.SetRowVisible(nameof(InputResolution), () => !ProcessPolygons);
|
||||
change.SetRowVisible(nameof(OutputResolution), () => !ProcessPolygons);
|
||||
change.SetRowVisible(nameof(MeshAnalysis), () => !ProcessPolygons);
|
||||
change.SetRowVisible(nameof(InputResolution), () => !ProcessPolygons && MeshAnalysis == IplicitSurfaceMethod.Grid);
|
||||
change.SetRowVisible(nameof(InputResolution), () => Processing != ProcessingModes.Polygons);
|
||||
change.SetRowVisible(nameof(OutputResolution), () => Processing != ProcessingModes.Polygons);
|
||||
change.SetRowVisible(nameof(MeshAnalysis), () => Processing != ProcessingModes.Polygons);
|
||||
change.SetRowVisible(nameof(InputResolution), () => Processing != ProcessingModes.Polygons && MeshAnalysis == IplicitSurfaceMethod.Grid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ using MatterHackers.DataConverters3D;
|
|||
using MatterHackers.Localizations;
|
||||
using MatterHackers.MatterControl.DesignTools;
|
||||
using MatterHackers.MatterControl.DesignTools.Operations;
|
||||
using MatterHackers.PolygonMesh;
|
||||
using MatterHackers.PolygonMesh.Csg;
|
||||
using MatterHackers.VectorMath;
|
||||
|
||||
namespace MatterHackers.MatterControl.PartPreviewWindow.View3D
|
||||
|
|
@ -191,17 +191,12 @@ namespace MatterHackers.MatterControl.PartPreviewWindow.View3D
|
|||
}
|
||||
}
|
||||
|
||||
private bool ProcessPolygons
|
||||
{
|
||||
get => Processing == ProcessingModes.Polygons || Processing == ProcessingModes.libigl;
|
||||
}
|
||||
|
||||
public void UpdateControls(PublicPropertyChange change)
|
||||
{
|
||||
change.SetRowVisible(nameof(InputResolution), () => !ProcessPolygons);
|
||||
change.SetRowVisible(nameof(OutputResolution), () => !ProcessPolygons);
|
||||
change.SetRowVisible(nameof(MeshAnalysis), () => !ProcessPolygons);
|
||||
change.SetRowVisible(nameof(InputResolution), () => !ProcessPolygons && MeshAnalysis == IplicitSurfaceMethod.Grid);
|
||||
change.SetRowVisible(nameof(InputResolution), () => Processing != ProcessingModes.Polygons);
|
||||
change.SetRowVisible(nameof(OutputResolution), () => Processing != ProcessingModes.Polygons);
|
||||
change.SetRowVisible(nameof(MeshAnalysis), () => Processing != ProcessingModes.Polygons);
|
||||
change.SetRowVisible(nameof(InputResolution), () => Processing != ProcessingModes.Polygons && MeshAnalysis == IplicitSurfaceMethod.Grid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@ using MatterHackers.DataConverters3D;
|
|||
using MatterHackers.Localizations;
|
||||
using MatterHackers.MatterControl.DesignTools;
|
||||
using MatterHackers.PolygonMesh;
|
||||
using MatterHackers.PolygonMesh.Csg;
|
||||
using MatterHackers.VectorMath;
|
||||
|
||||
namespace MatterHackers.MatterControl.PartPreviewWindow.View3D
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ using MatterHackers.Localizations;
|
|||
using MatterHackers.MatterControl.DesignTools;
|
||||
using MatterHackers.MatterControl.DesignTools.Operations;
|
||||
using MatterHackers.PolygonMesh;
|
||||
using MatterHackers.RenderOpenGl;
|
||||
using MatterHackers.PolygonMesh.Csg;
|
||||
using MatterHackers.VectorMath;
|
||||
|
||||
namespace MatterHackers.MatterControl.PartPreviewWindow.View3D
|
||||
|
|
@ -302,17 +302,12 @@ namespace MatterHackers.MatterControl.PartPreviewWindow.View3D
|
|||
}
|
||||
}
|
||||
|
||||
private bool ProcessPolygons
|
||||
{
|
||||
get => Processing == ProcessingModes.Polygons || Processing == ProcessingModes.libigl;
|
||||
}
|
||||
|
||||
public void UpdateControls(PublicPropertyChange change)
|
||||
{
|
||||
change.SetRowVisible(nameof(InputResolution), () => !ProcessPolygons);
|
||||
change.SetRowVisible(nameof(OutputResolution), () => !ProcessPolygons);
|
||||
change.SetRowVisible(nameof(MeshAnalysis), () => !ProcessPolygons);
|
||||
change.SetRowVisible(nameof(InputResolution), () => !ProcessPolygons && MeshAnalysis == IplicitSurfaceMethod.Grid);
|
||||
change.SetRowVisible(nameof(InputResolution), () => Processing != ProcessingModes.Polygons);
|
||||
change.SetRowVisible(nameof(OutputResolution), () => Processing != ProcessingModes.Polygons);
|
||||
change.SetRowVisible(nameof(MeshAnalysis), () => Processing != ProcessingModes.Polygons);
|
||||
change.SetRowVisible(nameof(InputResolution), () => Processing != ProcessingModes.Polygons && MeshAnalysis == IplicitSurfaceMethod.Grid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -42,6 +42,7 @@ using MatterHackers.DataConverters3D;
|
|||
using MatterHackers.Localizations;
|
||||
using MatterHackers.MatterControl.DesignTools;
|
||||
using MatterHackers.PolygonMesh;
|
||||
using MatterHackers.PolygonMesh.Csg;
|
||||
|
||||
namespace MatterHackers.MatterControl.PartPreviewWindow.View3D
|
||||
{
|
||||
|
|
|
|||
|
|
@ -39,8 +39,7 @@ using MatterHackers.DataConverters3D;
|
|||
using MatterHackers.Localizations;
|
||||
using MatterHackers.MatterControl.DesignTools;
|
||||
using MatterHackers.MatterControl.DesignTools.Operations;
|
||||
using MatterHackers.PolygonMesh;
|
||||
using MatterHackers.RenderOpenGl;
|
||||
using MatterHackers.PolygonMesh.Csg;
|
||||
using MatterHackers.VectorMath;
|
||||
|
||||
namespace MatterHackers.MatterControl.PartPreviewWindow.View3D
|
||||
|
|
@ -323,17 +322,12 @@ namespace MatterHackers.MatterControl.PartPreviewWindow.View3D
|
|||
}
|
||||
}
|
||||
|
||||
private bool ProcessPolygons
|
||||
{
|
||||
get => Processing == ProcessingModes.Polygons || Processing == ProcessingModes.libigl;
|
||||
}
|
||||
|
||||
public void UpdateControls(PublicPropertyChange change)
|
||||
{
|
||||
change.SetRowVisible(nameof(InputResolution), () => !ProcessPolygons);
|
||||
change.SetRowVisible(nameof(OutputResolution), () => !ProcessPolygons);
|
||||
change.SetRowVisible(nameof(MeshAnalysis), () => !ProcessPolygons);
|
||||
change.SetRowVisible(nameof(InputResolution), () => !ProcessPolygons && MeshAnalysis == IplicitSurfaceMethod.Grid);
|
||||
change.SetRowVisible(nameof(InputResolution), () => Processing != ProcessingModes.Polygons);
|
||||
change.SetRowVisible(nameof(OutputResolution), () => Processing != ProcessingModes.Polygons);
|
||||
change.SetRowVisible(nameof(MeshAnalysis), () => Processing != ProcessingModes.Polygons);
|
||||
change.SetRowVisible(nameof(InputResolution), () => Processing != ProcessingModes.Polygons && MeshAnalysis == IplicitSurfaceMethod.Grid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -40,6 +40,7 @@ using MatterHackers.DataConverters3D;
|
|||
using MatterHackers.Localizations;
|
||||
using MatterHackers.MatterControl.DesignTools;
|
||||
using MatterHackers.MatterControl.DesignTools.Operations;
|
||||
using MatterHackers.PolygonMesh.Processors;
|
||||
using MatterHackers.RenderOpenGl;
|
||||
|
||||
using MatterHackers.VectorMath;
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ using MatterHackers.DataConverters3D;
|
|||
using MatterHackers.MatterControl.SlicerConfiguration;
|
||||
using MatterHackers.MeshVisualizer;
|
||||
using MatterHackers.PolygonMesh;
|
||||
using MatterHackers.PolygonMesh.Processors;
|
||||
using MatterHackers.RenderOpenGl;
|
||||
using MatterHackers.VectorMath;
|
||||
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
Subproject commit f98d2331a1f7e2443bb8423c666229544e75b32b
|
||||
Subproject commit 0d19f03006c3716dad9c0b3677ff0c64969dfa85
|
||||
|
|
@ -18,8 +18,8 @@
|
|||
<RootNamespace>MatterControl.Tests</RootNamespace>
|
||||
<AssemblyName>MatterControl.Tests</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.7.1</TargetFrameworkVersion>
|
||||
<RuntimeIdentifier>win</RuntimeIdentifier>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<RuntimeIdentifier>win</RuntimeIdentifier>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir>
|
||||
<TargetFrameworkProfile />
|
||||
<NuGetPackageImportStamp>
|
||||
|
|
@ -53,7 +53,6 @@
|
|||
<Compile Include="MatterControl\ImportSettingsTests.cs" />
|
||||
<Compile Include="MatterControl\AssetManagerTests.cs" />
|
||||
<Compile Include="MatterControl\MeshRebuildTests.cs" />
|
||||
<Compile Include="MatterControl\MeshCsgTests.cs" />
|
||||
<Compile Include="MatterControl\PrinterSettingsTests.cs" />
|
||||
<Compile Include="MatterControl\SliceSettingsFieldTests.cs" />
|
||||
<Compile Include="MatterControl\SettingsParseTests.cs" />
|
||||
|
|
@ -131,10 +130,6 @@
|
|||
<Project>{CD8A3D1A-24D5-4184-8CF3-7B2AD5CD7A71}</Project>
|
||||
<Name>PlatformWin32</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\Submodules\agg-sharp\PolygonMesh\Net3dBool\Net3dBool.csproj">
|
||||
<Project>{7ee4636d-8a92-4015-9562-7fcd6add0645}</Project>
|
||||
<Name>Net3dBool</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\Submodules\agg-sharp\PolygonMesh\PolygonMesh.csproj">
|
||||
<Project>{86f6aaf2-9b50-40b8-a427-1897d76471c5}</Project>
|
||||
<Name>PolygonMesh</Name>
|
||||
|
|
|
|||
|
|
@ -1,396 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2014, Lars Brubaker
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
The views and conclusions contained in the software and documentation are those
|
||||
of the authors and should not be interpreted as representing official policies,
|
||||
either expressed or implied, of the FreeBSD Project.
|
||||
*/
|
||||
#define DEBUG_INTO_TGAS
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using MatterHackers.Agg;
|
||||
using MatterHackers.Agg.Platform;
|
||||
using MatterHackers.DataConverters3D;
|
||||
using MatterHackers.MatterControl.DesignTools;
|
||||
using MatterHackers.MatterControl.DesignTools.Operations;
|
||||
using MatterHackers.MatterControl.Tests.Automation;
|
||||
using MatterHackers.PolygonMesh.Csg;
|
||||
using MatterHackers.PolygonMesh.Processors;
|
||||
using MatterHackers.VectorMath;
|
||||
using Net3dBool;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace MatterHackers.PolygonMesh.UnitTests
|
||||
{
|
||||
[TestFixture, Category("Agg.PolygonMesh.Csg")]
|
||||
public class MeshCsgTests
|
||||
{
|
||||
[Test]
|
||||
public void CsgCylinderMinusCylinder()
|
||||
{
|
||||
//StaticData.RootPath = TestContext.CurrentContext.ResolveProjectPath(4, "StaticData"));
|
||||
//MatterControlUtilities.OverrideAppDataLocation(TestContext.CurrentContext.ResolveProjectPath(4));
|
||||
|
||||
//StaticData.RootPath = TestContext.CurrentContext.ResolveProjectPath(5, "MatterControl", "StaticData"));
|
||||
//MatterControlUtilities.OverrideAppDataLocation(TestContext.CurrentContext.ResolveProjectPath(5));
|
||||
|
||||
//// check that we subtract two 3 sided cylinders
|
||||
//{
|
||||
// double topHeight = 10;
|
||||
// int sides = 3;
|
||||
// IObject3D keep = CylinderObject3D.Create(20, topHeight * 2, sides);
|
||||
// IObject3D subtract = CylinderObject3D.Create(10, topHeight * 2, sides);
|
||||
|
||||
// var keepMesh = keep.Mesh;
|
||||
// var subtractMesh = subtract.Mesh;
|
||||
|
||||
// if (false)
|
||||
// {
|
||||
// var split1 = new DebugFace()
|
||||
// {
|
||||
// EvaluateHeight = topHeight,
|
||||
// FileName = "Split1"
|
||||
// };
|
||||
|
||||
// BooleanModeller.Object1SplitFace = split1.Split;
|
||||
// BooleanModeller.Object1SplitResults = split1.Result;
|
||||
|
||||
// BooleanModeller.Object1ClassifyFace = split1.Classify1;
|
||||
// BooleanModeller.Object2ClassifyFace = split1.Classify2;
|
||||
// }
|
||||
|
||||
// var resultMesh = keepMesh.Subtract(subtractMesh, null, CancellationToken.None);
|
||||
|
||||
// // this is for debugging the operation
|
||||
// //split1.FinishOutput();
|
||||
// //resultMesh.Save("c:/temp/mesh1.stl", CancellationToken.None);
|
||||
|
||||
// var topZero = new Vector3(0, 0, topHeight);
|
||||
// foreach (var topVertex in keepMesh.Vertices
|
||||
// .Where((v) => v.Position.Z == topHeight && v.Position != topZero)
|
||||
// .Select((gv) => gv.Position))
|
||||
// {
|
||||
// Assert.IsTrue(resultMesh.Vertices.Where((v) => v.Position == topVertex).Any(), "Have all top vertexes");
|
||||
// }
|
||||
// foreach (var topVertex in subtractMesh.Vertices
|
||||
// .Where((v) => v.Position.Z == topHeight && v.Position != topZero)
|
||||
// .Select((gv) => gv.Position))
|
||||
// {
|
||||
// Assert.IsTrue(resultMesh.Vertices.Where((v) => v.Position == topVertex).Any(), "Have all top vertexes");
|
||||
// }
|
||||
//}
|
||||
|
||||
//// check that we subtract two 3 side cylinders
|
||||
//{
|
||||
// int sides = 3;
|
||||
// IObject3D keep = CylinderObject3D.Create(20, 20, sides);
|
||||
// IObject3D subtract = CylinderObject3D.Create(10, 22, sides);
|
||||
|
||||
// var keepMesh = keep.Mesh;
|
||||
// var subtractMesh = subtract.Mesh;
|
||||
|
||||
// if (false)
|
||||
// {
|
||||
// var split1 = new DebugFace()
|
||||
// {
|
||||
// EvaluateHeight = 10,
|
||||
// FileName = "Split2"
|
||||
// };
|
||||
|
||||
// BooleanModeller.Object1SplitFace = split1.Split;
|
||||
// BooleanModeller.Object1SplitResults = split1.Result;
|
||||
// }
|
||||
|
||||
// var resultMesh = keepMesh.Subtract(subtractMesh, null, CancellationToken.None);
|
||||
|
||||
// // this is for debugging the operation
|
||||
// //split1.FinishOutput();
|
||||
// //resultMesh.Save("c:/temp/mesh2.stl", CancellationToken.None);
|
||||
|
||||
// foreach (var topVertex in keepMesh.Vertices
|
||||
// .Where((v) => v.Position.Z == 10 && v.Position != new Vector3(0, 0, 10))
|
||||
// .Select((gv) => gv.Position))
|
||||
// {
|
||||
// Assert.IsTrue(resultMesh.Vertices.Where((v) => v.Position == topVertex).Any(), "Have all top vertexes");
|
||||
// }
|
||||
// foreach (var topVertex in subtractMesh.Vertices
|
||||
// .Where((v) => v.Position.Z == 11 && v.Position != new Vector3(0, 0, 11))
|
||||
// .Select((gv) => gv.Position))
|
||||
// {
|
||||
// Assert.IsTrue(resultMesh.Vertices
|
||||
// .Where((v) => v.Position.Equals(new Vector3(topVertex.X, topVertex.Y, 10), .0001))
|
||||
// .Any(), "Have all top vertexes");
|
||||
// }
|
||||
//}
|
||||
}
|
||||
}
|
||||
|
||||
public class DebugFace
|
||||
{
|
||||
private int currentIndex;
|
||||
private StringBuilder allSplitPolygonDebug = new StringBuilder();
|
||||
private StringBuilder allResultsPolygonDebug = new StringBuilder();
|
||||
private StringBuilder classifiedFaces1 = new StringBuilder();
|
||||
private StringBuilder classifiedFaces2 = new StringBuilder();
|
||||
private StringBuilder htmlContent = new StringBuilder();
|
||||
private StringBuilder individualPolygonDebug = new StringBuilder();
|
||||
|
||||
public string FileName { get; set; } = "DebugFace";
|
||||
public double EvaluateHeight { get; set; } = -3;
|
||||
int svgHeight = 540;
|
||||
int svgWidth = 540;
|
||||
Vector2 offset = new Vector2(10, 18);
|
||||
double scale = 13;
|
||||
|
||||
public void Result(List<CsgFace> splitResults)
|
||||
{
|
||||
if (splitResults.Count > 0
|
||||
&& FaceAtHeight(splitResults[0], EvaluateHeight))
|
||||
{
|
||||
individualPolygonDebug.AppendLine($"<br>Result: {currentIndex}</br>");
|
||||
individualPolygonDebug.AppendLine($"<svg height='{svgHeight}' width='{svgWidth}'>");
|
||||
foreach (var face in splitResults)
|
||||
{
|
||||
individualPolygonDebug.AppendLine(GetCoords(face));
|
||||
allResultsPolygonDebug.AppendLine(GetCoords(face));
|
||||
}
|
||||
individualPolygonDebug.AppendLine("</svg>");
|
||||
}
|
||||
}
|
||||
|
||||
public void Split(CsgFace faceToSplit, CsgFace splitAtFace)
|
||||
{
|
||||
if (FaceAtHeight(faceToSplit, EvaluateHeight))
|
||||
{
|
||||
allSplitPolygonDebug.AppendLine(GetCoords(faceToSplit));
|
||||
|
||||
if (currentIndex == 0)
|
||||
{
|
||||
htmlContent.AppendLine("<!DOCTYPE html>");
|
||||
htmlContent.AppendLine("<html>");
|
||||
htmlContent.AppendLine("<body>");
|
||||
htmlContent.AppendLine("<br>Full</br>");
|
||||
}
|
||||
|
||||
currentIndex++;
|
||||
individualPolygonDebug.AppendLine($"<br>{currentIndex}</br>");
|
||||
individualPolygonDebug.AppendLine($"<svg height='{svgHeight}' width='{svgWidth}'>");
|
||||
individualPolygonDebug.AppendLine(GetCoords(faceToSplit));
|
||||
individualPolygonDebug.AppendLine(GetCoords(splitAtFace));
|
||||
individualPolygonDebug.AppendLine("</svg>");
|
||||
}
|
||||
}
|
||||
|
||||
public void FinishOutput()
|
||||
{
|
||||
htmlContent.AppendLine($"<svg height='{svgHeight}' width='{svgWidth}'>");
|
||||
htmlContent.Append(allSplitPolygonDebug.ToString());
|
||||
htmlContent.AppendLine("</svg>");
|
||||
|
||||
htmlContent.AppendLine($"<svg height='{svgHeight}' width='{svgWidth}'>");
|
||||
htmlContent.Append(allResultsPolygonDebug.ToString());
|
||||
htmlContent.AppendLine("</svg>");
|
||||
|
||||
htmlContent.Append(individualPolygonDebug.ToString());
|
||||
|
||||
htmlContent.AppendLine($"<svg height='{svgHeight}' width='{svgWidth}'>");
|
||||
htmlContent.Append(classifiedFaces1.ToString());
|
||||
htmlContent.AppendLine("</svg>");
|
||||
|
||||
htmlContent.AppendLine($"<svg height='{svgHeight}' width='{svgWidth}'>");
|
||||
htmlContent.Append(classifiedFaces2.ToString());
|
||||
htmlContent.AppendLine("</svg>");
|
||||
|
||||
htmlContent.AppendLine("</body>");
|
||||
htmlContent.AppendLine("</html>");
|
||||
|
||||
File.WriteAllText($"C:/Temp/{FileName}.html", htmlContent.ToString());
|
||||
}
|
||||
|
||||
public static bool AreEqual(double a, double b, double errorRange = .001)
|
||||
{
|
||||
if (a < b + errorRange
|
||||
&& a > b - errorRange)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool FaceAtHeight(CsgFace face, double height)
|
||||
{
|
||||
if (!AreEqual(face.v1.Position.Z, height))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!AreEqual(face.v2.Position.Z, height))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!AreEqual(face.v3.Position.Z, height))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool FaceAtXy(Vector3[] face, double x, double y)
|
||||
{
|
||||
if (!AreEqual(face[0].X, x)
|
||||
|| !AreEqual(face[0].Y, y))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!AreEqual(face[1].X, x)
|
||||
|| !AreEqual(face[1].Y, y))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!AreEqual(face[2].X, x)
|
||||
|| !AreEqual(face[2].Y, y))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public string GetCoords(CsgFace face)
|
||||
{
|
||||
return GetCoords(face, Color.Black, new Color(Color.Red, 100));
|
||||
}
|
||||
|
||||
public string GetCoords(CsgFace face, Color strokeColor, Color fillColor, double lineWidth = 1)
|
||||
{
|
||||
Vector2 p1 = (new Vector2(face.v1.Position.X, -face.v1.Position.Y) + offset) * scale;
|
||||
Vector2 p2 = (new Vector2(face.v2.Position.X, -face.v2.Position.Y) + offset) * scale;
|
||||
Vector2 p3 = (new Vector2(face.v3.Position.X, -face.v3.Position.Y) + offset) * scale;
|
||||
string coords = $"{p1.X:0.0}, {p1.Y:0.0}";
|
||||
coords += $", {p2.X:0.0}, {p2.Y:0.0}";
|
||||
coords += $", {p3.X:0.0}, {p3.Y:0.0}";
|
||||
return $"<polygon points=\"{coords}\" style=\"fill: {fillColor.Html}; stroke: {strokeColor}; stroke - width:.1\" />";
|
||||
}
|
||||
|
||||
public static bool HasPosition(Vector3[] face, Vector3 position)
|
||||
{
|
||||
if (face[0].Equals(position, .0001))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (face[1].Equals(position, .0001))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (face[2].Equals(position, .0001))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public void Classify1(CsgFace face)
|
||||
{
|
||||
//if (FaceAtHeight(face, EvaluateHeight))
|
||||
{
|
||||
Color color = new Color();
|
||||
switch (face.Status)
|
||||
{
|
||||
case FaceStatus.Unknown:
|
||||
color = Color.Cyan;
|
||||
break;
|
||||
case FaceStatus.Inside:
|
||||
color = Color.Green;
|
||||
break;
|
||||
case FaceStatus.Outside:
|
||||
color = Color.Red;
|
||||
break;
|
||||
case FaceStatus.Same:
|
||||
color = Color.Gray;
|
||||
break;
|
||||
case FaceStatus.Opposite:
|
||||
color = Color.Yellow;
|
||||
break;
|
||||
case FaceStatus.Boundary:
|
||||
color = Color.Indigo;
|
||||
break;
|
||||
default:
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
// make it transparent
|
||||
color = new Color(color, 100);
|
||||
|
||||
classifiedFaces1.AppendLine(GetCoords(face, Color.Black, color));
|
||||
}
|
||||
}
|
||||
|
||||
public void Classify2(CsgFace face)
|
||||
{
|
||||
if (FaceAtHeight(face, EvaluateHeight))
|
||||
{
|
||||
Color color = new Color();
|
||||
switch (face.Status)
|
||||
{
|
||||
case FaceStatus.Unknown:
|
||||
color = Color.Cyan;
|
||||
break;
|
||||
case FaceStatus.Inside:
|
||||
color = Color.Green;
|
||||
break;
|
||||
case FaceStatus.Outside:
|
||||
color = Color.Red;
|
||||
break;
|
||||
case FaceStatus.Same:
|
||||
color = Color.Gray;
|
||||
break;
|
||||
case FaceStatus.Opposite:
|
||||
color = Color.Yellow;
|
||||
break;
|
||||
case FaceStatus.Boundary:
|
||||
color = Color.Indigo;
|
||||
break;
|
||||
default:
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
// make it transparent
|
||||
color = new Color(color, 100);
|
||||
|
||||
classifiedFaces2.AppendLine(GetCoords(face, Color.Black, color));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -31,7 +31,6 @@ using System.Threading;
|
|||
using MatterHackers.Agg.Platform;
|
||||
using MatterHackers.MatterControl.Tests.Automation;
|
||||
using MatterHackers.PolygonMesh;
|
||||
using MatterHackers.PolygonMesh.Csg;
|
||||
using MatterHackers.PolygonMesh.Processors;
|
||||
using MatterHackers.VectorMath;
|
||||
using NUnit.Framework;
|
||||
|
|
|
|||
BIN
libgmp-10.dll
BIN
libgmp-10.dll
Binary file not shown.
Binary file not shown.
BIN
libmpfr-4.dll
BIN
libmpfr-4.dll
Binary file not shown.
Loading…
Add table
Add a link
Reference in a new issue