diff --git a/core/DVector.cs b/core/DVector.cs index fcda514e..ec3a0863 100644 --- a/core/DVector.cs +++ b/core/DVector.cs @@ -41,9 +41,9 @@ public DVector(DVector copy) } } - public DVector(T[] data) + public DVector(T[] data, int? count = null) { - Initialize(data); + Initialize(data, count); } public DVector(IEnumerable init) @@ -279,9 +279,10 @@ public byte[] GetBytes() - public void Initialize(T[] data) + public void Initialize(T[] data, int? count = null) { - int blocks = data.Length / nBlockSize; + int length = count ?? data.Length; + int blocks = length / nBlockSize; Blocks = new List(); int ai = 0; for (int i = 0; i < blocks; ++i) { @@ -290,7 +291,7 @@ public void Initialize(T[] data) Blocks.Add(block); ai += nBlockSize; } - iCurBlockUsed = data.Length - ai; + iCurBlockUsed = length - ai; if (iCurBlockUsed != 0) { T[] last = new T[nBlockSize]; Array.Copy(data, ai, last, 0, iCurBlockUsed); diff --git a/core/Util.cs b/core/Util.cs index aaeb4ff5..0954fdb6 100644 --- a/core/Util.cs +++ b/core/Util.cs @@ -245,7 +245,7 @@ public static void WriteDebugMesh(IMesh mesh, string sPath) StandardMeshWriter.WriteFile(sPath, new List() { new WriteMesh(mesh) }, options); } - public static void WriteDebugMeshAndMarkers(IMesh mesh, List Markers, string sPath, int maxDegreeOfParallelism) + public static void WriteDebugMeshAndMarkers(IMesh mesh, List Markers, string sPath) { WriteOptions options = WriteOptions.Defaults; options.bWriteGroups = true; @@ -254,7 +254,7 @@ public static void WriteDebugMeshAndMarkers(IMesh mesh, List Markers, foreach ( Vector3d v in Markers ) { TrivialBox3Generator boxgen = new TrivialBox3Generator(); boxgen.Box = new Box3d(v, size * Vector3d.One); - boxgen.Generate(maxDegreeOfParallelism); + boxgen.Generate(); DMesh3 m = new DMesh3(); boxgen.MakeMesh(m); meshes.Add(new WriteMesh(m)); diff --git a/geometry3Sharp.csproj b/geometry3Sharp.csproj index 5bd72566..a1dfa126 100644 --- a/geometry3Sharp.csproj +++ b/geometry3Sharp.csproj @@ -44,5 +44,9 @@ + + + + diff --git a/math/MathUtil.cs b/math/MathUtil.cs index 6dfa69d1..9760c357 100644 --- a/math/MathUtil.cs +++ b/math/MathUtil.cs @@ -448,22 +448,26 @@ public static double Area(Vector3d v1, Vector3d v2, Vector3d v3) { public static Vector3d Normal(ref Vector3d v1, ref Vector3d v2, ref Vector3d v3) { Vector3d edge1 = v2 - v1; Vector3d edge2 = v3 - v2; - edge1.Normalize(); - edge2.Normalize(); Vector3d vCross = edge1.Cross(edge2); vCross.Normalize(); return vCross; } - public static Vector3d Normal(Vector3d v1, Vector3d v2, Vector3d v3) { - return Normal(ref v1, ref v2, ref v3); + + public static Vector3d Normal(Vector3d v1, Vector3d v2, Vector3d v3) + { + Vector3d edge1 = v2 - v1; + Vector3d edge2 = v3 - v2; + Vector3d vCross = edge1.Cross(edge2); + vCross.Normalize(); + return vCross; } - /// - /// compute vector in direction of triangle normal (cross-product). No normalization. - /// - /// The normal direction. - public static Vector3d FastNormalDirection(ref Vector3d v1, ref Vector3d v2, ref Vector3d v3) + /// + /// compute vector in direction of triangle normal (cross-product). No normalization. + /// + /// The normal direction. + public static Vector3d FastNormalDirection(ref Vector3d v1, ref Vector3d v2, ref Vector3d v3) { Vector3d edge1 = v2 - v1; Vector3d edge2 = v3 - v1; diff --git a/mesh/MeshDecomposition.cs b/mesh/MeshDecomposition.cs index 67c4488b..dfb2ba39 100644 --- a/mesh/MeshDecomposition.cs +++ b/mesh/MeshDecomposition.cs @@ -1,7 +1,8 @@ -using System; +#nullable enable + +using System; +using System.Buffers; using System.Collections; -using System.Collections.Generic; -using System.Diagnostics; namespace g3 @@ -56,7 +57,7 @@ public MeshDecomposition(DMesh3 mesh, IMeshComponentManager manager) - public void BuildLinear(int maxDegreeOfParallelism) + public void BuildLinear() { int NV = mesh.MaxVertexID; @@ -107,7 +108,7 @@ public void BuildLinear(int maxDegreeOfParallelism) - int[] tri_order = get_tri_order_by_axis_sort(maxDegreeOfParallelism); + int[] tri_order = get_tri_order_by_axis_sort(); int tri_count = tri_order.Length; for (int ii = 0; ii < tri_count; ++ii) { @@ -131,7 +132,7 @@ public void BuildLinear(int maxDegreeOfParallelism) - int[] get_tri_order_by_axis_sort(int maxDegreeOfParallelism) + int[] get_tri_order_by_axis_sort(ArrayPool? arrayPool = null) { int i = 0; int[] tri_order = new int[mesh.TriangleCount]; @@ -142,21 +143,31 @@ int[] get_tri_order_by_axis_sort(int maxDegreeOfParallelism) tri_order[i++] = ti; } - // precompute triangle centroids - wildly expensive to - // do it inline in sort (!) I guess O(N) vs O(N log N) - Vector3d[] centroids = new Vector3d[mesh.MaxTriangleID]; - gParallel.ForEach(mesh.TriangleIndices(), (ti) => { - if (mesh.IsTriangle(ti)) - centroids[ti] = mesh.GetTriCentroid(ti); - }, maxDegreeOfParallelism); - - - Array.Sort(tri_order, (t0, t1) => { - double f0 = centroids[t0].x; - double f1 = centroids[t1].x; - return (f0 == f1) ? 0 : (f0 < f1) ? -1 : 1; - }); + arrayPool ??= ArrayPool.Shared; + Vector3d[] rentedArray = arrayPool.Rent(mesh.MaxTriangleID); + try + { + // precompute triangle centroids - wildly expensive to + // do it inline in sort (!) I guess O(N) vs O(N log N) + Vector3d[] centroids = new Vector3d[mesh.MaxTriangleID]; + for (int tid = 0; tid < mesh.MaxTriangleID; tid++) + { + if (!mesh.IsTriangle(tid)) + continue; + centroids[tid] = mesh.GetTriCentroid(tid); + } + Array.Sort(tri_order, (t0, t1) => + { + double f0 = centroids[t0].x; + double f1 = centroids[t1].x; + return (f0 == f1) ? 0 : (f0 < f1) ? -1 : 1; + }); + } + finally + { + arrayPool.Return(rentedArray); + } return tri_order; } diff --git a/mesh/MeshEditor.cs b/mesh/MeshEditor.cs index 855a7c33..0a2674e9 100644 --- a/mesh/MeshEditor.cs +++ b/mesh/MeshEditor.cs @@ -866,84 +866,84 @@ public bool AppendMesh(IMesh appendMesh, IndexMap mergeMapV, out int[] mapV, int - public void AppendBox(Frame3f frame, float size, int maxDegreeOfParallelism) + public void AppendBox(Frame3f frame, float size) { - AppendBox(frame, size * Vector3f.One, maxDegreeOfParallelism); + AppendBox(frame, size * Vector3f.One); } - public void AppendBox(Frame3f frame, Vector3f size, int maxDegreeOfParallelism) + public void AppendBox(Frame3f frame, Vector3f size) { - AppendBox(frame, size, Colorf.White, maxDegreeOfParallelism); + AppendBox(frame, size, Colorf.White); } - public void AppendBox(Frame3f frame, Vector3f size, Colorf color, int maxDegreeOfParallelism) + public void AppendBox(Frame3f frame, Vector3f size, Colorf color) { TrivialBox3Generator boxgen = new TrivialBox3Generator() { Box = new Box3d(frame, size), NoSharedVertices = false }; - boxgen.Generate(maxDegreeOfParallelism); + boxgen.Generate(); DMesh3 mesh = new DMesh3(); boxgen.MakeMesh(mesh); if (Mesh.HasVertexColors) mesh.EnableVertexColors(color); AppendMesh(mesh, Mesh.AllocateTriangleGroup()); } - public void AppendLine(Segment3d seg, float size, int maxDegreeOfParallelism) + public void AppendLine(Segment3d seg, float size) { Frame3f f = new Frame3f(seg.Center); f.AlignAxis(2, (Vector3f)seg.Direction); - AppendBox(f, new Vector3f(size, size, seg.Extent), maxDegreeOfParallelism); + AppendBox(f, new Vector3f(size, size, seg.Extent)); } - public void AppendLine(Segment3d seg, float size, Colorf color, int maxDegreeOfParallelism) + public void AppendLine(Segment3d seg, float size, Colorf color) { Frame3f f = new Frame3f(seg.Center); f.AlignAxis(2, (Vector3f)seg.Direction); - AppendBox(f, new Vector3f(size, size, seg.Extent), color, maxDegreeOfParallelism); + AppendBox(f, new Vector3f(size, size, seg.Extent), color); } - public static void AppendBox(DMesh3 mesh, Vector3d pos, float size, int maxDegreeOfParallelism) + public static void AppendBox(DMesh3 mesh, Vector3d pos, float size) { MeshEditor editor = new MeshEditor(mesh); - editor.AppendBox(new Frame3f(pos), size, maxDegreeOfParallelism); + editor.AppendBox(new Frame3f(pos), size); } - public static void AppendBox(DMesh3 mesh, Vector3d pos, float size, Colorf color, int maxDegreeOfParallelism) + public static void AppendBox(DMesh3 mesh, Vector3d pos, float size, Colorf color) { MeshEditor editor = new MeshEditor(mesh); - editor.AppendBox(new Frame3f(pos), size*Vector3f.One, color, maxDegreeOfParallelism); + editor.AppendBox(new Frame3f(pos), size*Vector3f.One, color); } - public static void AppendBox(DMesh3 mesh, Vector3d pos, Vector3d normal, float size, int maxDegreeOfParallelism) + public static void AppendBox(DMesh3 mesh, Vector3d pos, Vector3d normal, float size) { MeshEditor editor = new MeshEditor(mesh); - editor.AppendBox(new Frame3f(pos, normal), size, maxDegreeOfParallelism); + editor.AppendBox(new Frame3f(pos, normal), size); } - public static void AppendBox(DMesh3 mesh, Vector3d pos, Vector3d normal, float size, Colorf color, int maxDegreeOfParallelism) + public static void AppendBox(DMesh3 mesh, Vector3d pos, Vector3d normal, float size, Colorf color) { MeshEditor editor = new MeshEditor(mesh); - editor.AppendBox(new Frame3f(pos, normal), size*Vector3f.One, color, maxDegreeOfParallelism); + editor.AppendBox(new Frame3f(pos, normal), size*Vector3f.One, color); } - public static void AppendBox(DMesh3 mesh, Frame3f frame, Vector3f size, Colorf color, int maxDegreeOfParallelism) + public static void AppendBox(DMesh3 mesh, Frame3f frame, Vector3f size, Colorf color) { MeshEditor editor = new MeshEditor(mesh); - editor.AppendBox(frame, size, color, maxDegreeOfParallelism); + editor.AppendBox(frame, size, color); } - public static void AppendLine(DMesh3 mesh, Segment3d seg, float size, int maxDegreeOfParallelism) + public static void AppendLine(DMesh3 mesh, Segment3d seg, float size) { Frame3f f = new Frame3f(seg.Center); f.AlignAxis(2, (Vector3f)seg.Direction); MeshEditor editor = new MeshEditor(mesh); - editor.AppendBox(f, new Vector3f(size, size, seg.Extent), maxDegreeOfParallelism); + editor.AppendBox(f, new Vector3f(size, size, seg.Extent)); } - public void AppendPathSolid(IEnumerable vertices, double radius, Colorf color, int maxDegreeOfParallelism) + public void AppendPathSolid(IEnumerable vertices, double radius, Colorf color) { TubeGenerator tubegen = new TubeGenerator() { Vertices = new List(vertices), Polygon = Polygon2d.MakeCircle(radius, 6), NoSharedVertices = false }; - DMesh3 mesh = tubegen.Generate(maxDegreeOfParallelism).MakeDMesh(); + DMesh3 mesh = tubegen.Generate().MakeDMesh(); if (Mesh.HasVertexColors) mesh.EnableVertexColors(color); AppendMesh(mesh, Mesh.AllocateTriangleGroup()); diff --git a/mesh/MeshNormals.cs b/mesh/MeshNormals.cs index 78fd3e84..42f1f080 100644 --- a/mesh/MeshNormals.cs +++ b/mesh/MeshNormals.cs @@ -1,13 +1,14 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading; +#nullable enable + +using System; +using System.Buffers; +using System.Runtime.InteropServices; namespace g3 { public class MeshNormals { - public IMesh Mesh; + public DMesh3 Mesh; public DVector Normals; /// @@ -16,8 +17,6 @@ public class MeshNormals /// public Func VertexF; - - public enum NormalsTypes { Vertex_OneRingFaceAverage_AreaWeighted @@ -25,7 +24,7 @@ public enum NormalsTypes public NormalsTypes NormalType; - public MeshNormals(IMesh mesh, NormalsTypes eType = NormalsTypes.Vertex_OneRingFaceAverage_AreaWeighted) + public MeshNormals(DMesh3 mesh, NormalsTypes eType = NormalsTypes.Vertex_OneRingFaceAverage_AreaWeighted) { Mesh = mesh; NormalType = eType; @@ -34,12 +33,25 @@ public MeshNormals(IMesh mesh, NormalsTypes eType = NormalsTypes.Vertex_OneRingF } - public void Compute(int maxDegreeOfParallelism) + public void Compute(ArrayPool? arrayPool = null) { - Compute_FaceAvg_AreaWeighted(maxDegreeOfParallelism); + arrayPool ??= ArrayPool.Shared; + Vector3f[] normalsArray = arrayPool.Rent(Mesh.MaxVertexID); + try + { + QuickComputeToArray(Mesh, normalsArray); + int NV = Mesh.MaxVertexID; + if (NV != Normals.size) + Normals.resize(NV); + for (int vid = 0; vid < NV; ++vid) + Normals[vid] = (Vector3d)normalsArray[vid]; + } + finally + { + arrayPool.Return(normalsArray); + } } - public Vector3d this[int vid] { get { return Normals[vid]; } } @@ -59,51 +71,72 @@ public void CopyTo(DMesh3 SetMesh) } } - - - - // TODO: parallel version, cache tri normals - void Compute_FaceAvg_AreaWeighted(int maxDegreeOfParallelism) + public static void QuickCompute(DMesh3 mesh, + ArrayPool? arrayPool = null) { - int NV = Mesh.MaxVertexID; - if ( NV != Normals.size ) - Normals.resize(NV); - for (int i = 0; i < NV; ++i) - Normals[i] = Vector3d.Zero; - - SpinLock Normals_lock = new SpinLock(); - - gParallel.ForEach(Mesh.TriangleIndices(), (ti) => { - Index3i tri = Mesh.GetTriangle(ti); - Vector3d va = Mesh.GetVertex(tri.a); - Vector3d vb = Mesh.GetVertex(tri.b); - Vector3d vc = Mesh.GetVertex(tri.c); - Vector3d N = MathUtil.Normal(ref va, ref vb, ref vc); - double a = MathUtil.Area(ref va, ref vb, ref vc); - bool taken = false; - Normals_lock.Enter(ref taken); - Normals[tri.a] += a * N; - Normals[tri.b] += a * N; - Normals[tri.c] += a * N; - Normals_lock.Exit(); - }, maxDegreeOfParallelism); - - gParallel.BlockStartEnd(0, NV - 1, (vi_start, vi_end) => { - for (int vi = vi_start; vi <= vi_end; vi++) { - if (Normals[vi].LengthSquared > MathUtil.ZeroTolerancef) - Normals[vi] = Normals[vi].Normalized; - } - }, maxDegreeOfParallelism); + arrayPool ??= ArrayPool.Shared; + Vector3f[] normalsArray = arrayPool.Rent(mesh.MaxVertexID); + try + { + QuickComputeToArray(mesh, normalsArray); + CopyToMesh(mesh, normalsArray); + } + finally + { + arrayPool.Return(normalsArray); + } } + private unsafe static void CopyToMesh(DMesh3 mesh, + Vector3f[] probablyLargerNormalsArray, + ArrayPool? arrayPool = null) + { + // Create a temp array + arrayPool ??= ArrayPool.Shared; + float[] floatNormalsArray = arrayPool.Rent(mesh.MaxVertexID * 3); + try + { + fixed (Vector3f* vectorPointer = &probablyLargerNormalsArray[0]) + Marshal.Copy((IntPtr)vectorPointer, + destination: floatNormalsArray, + startIndex: 0, + length: mesh.MaxVertexID * 3); + // We don't need to do mesh.EnableVertexNormals(), + // because it only initializes the buffer + mesh.NormalsBuffer = new DVector(floatNormalsArray, count: mesh.MaxVertexID * 3); + } + finally + { + arrayPool.Return(floatNormalsArray); + } + } - - - public static void QuickCompute(DMesh3 mesh, int maxDegreeOfParallelism) + private static void QuickComputeToArray(DMesh3 mesh, Vector3f[] normalsArray) { - MeshNormals normals = new MeshNormals(mesh); - normals.Compute(maxDegreeOfParallelism); - normals.CopyTo(mesh); + for (int vid = 0; vid < mesh.MaxVertexID; vid++) + normalsArray[vid] = Vector3f.Zero; + for (int tid = 0; tid < mesh.MaxTriangleID; tid++) + { + if (!mesh.IsTriangle(tid)) + continue; + Index3i triangle = mesh.GetTriangle(tid); + Vector3d vertexA = mesh.GetVertexUnsafe(triangle.a); + Vector3d vertexB = mesh.GetVertexUnsafe(triangle.b); + Vector3d vertexC = mesh.GetVertexUnsafe(triangle.c); + Vector3d triangleNormal = MathUtil.Normal(vertexA, vertexB, vertexC); + double triangleArea = MathUtil.Area(vertexA, vertexB, vertexC); + Vector3f areaNormalMultiplication = (Vector3f)(triangleArea * triangleNormal); + normalsArray[triangle.a] += areaNormalMultiplication; + normalsArray[triangle.b] += areaNormalMultiplication; + normalsArray[triangle.c] += areaNormalMultiplication; + } + // Normalize array + for (int vid = 0; vid < mesh.MaxVertexID; vid++) + { + Vector3f vertexNormal = normalsArray[vid]; + if (vertexNormal != Vector3f.Zero) + normalsArray[vid] = vertexNormal.Normalized; + } } diff --git a/mesh_generators/ArrowGenerators.cs b/mesh_generators/ArrowGenerators.cs index 300ffc0a..fa63bed1 100644 --- a/mesh_generators/ArrowGenerators.cs +++ b/mesh_generators/ArrowGenerators.cs @@ -14,7 +14,7 @@ public class Radial3DArrowGenerator : VerticalGeneralizedCylinderGenerator public float TipRadius = 0.0f; public float HeadLength = 0.5f; - override public MeshGenerator Generate(int maxDegreeOfParallelism) + override public MeshGenerator Generate() { Sections = new CircularSection[4]; Sections[0] = new CircularSection(StickRadius, 0.0f); @@ -24,7 +24,7 @@ override public MeshGenerator Generate(int maxDegreeOfParallelism) Capped = true; NoSharedVertices = true; - base.Generate(maxDegreeOfParallelism); + base.Generate(); return this; } diff --git a/mesh_generators/BoxGenerators.cs b/mesh_generators/BoxGenerators.cs index 699351a8..108a09a7 100644 --- a/mesh_generators/BoxGenerators.cs +++ b/mesh_generators/BoxGenerators.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Diagnostics; namespace g3 { @@ -12,7 +11,7 @@ public class TrivialBox3Generator : MeshGenerator public Box3d Box = Box3d.UnitZeroCentered; public bool NoSharedVertices = false; - public override MeshGenerator Generate(int maxDegreeOfParallelism) + public override MeshGenerator Generate() { vertices = new VectorArray3d((NoSharedVertices) ? (4 * 6) : 8); uv = new VectorArray2f(vertices.Count); @@ -74,7 +73,7 @@ public class GridBox3Generator : MeshGenerator public int EdgeVertices = 8; public bool NoSharedVertices = false; - public override MeshGenerator Generate(int maxDegreeOfParallelism) + public override MeshGenerator Generate() { int N = (EdgeVertices > 1) ? EdgeVertices : 2; int Nm2 = N - 2; diff --git a/mesh_generators/CylinderGenerators.cs b/mesh_generators/CylinderGenerators.cs index 1c5484e6..4a899cfd 100644 --- a/mesh_generators/CylinderGenerators.cs +++ b/mesh_generators/CylinderGenerators.cs @@ -19,7 +19,7 @@ public class OpenCylinderGenerator : MeshGenerator // last panel will not have UVs going from 1 to 0 public bool NoSharedVertices = false; - override public MeshGenerator Generate(int maxDegreeOfParallelism) + override public MeshGenerator Generate() { bool bClosed = ((EndAngleDeg - StartAngleDeg) > 359.99f); int nRingSize = (NoSharedVertices && bClosed) ? Slices + 1 : Slices; @@ -81,7 +81,7 @@ public class CappedCylinderGenerator : MeshGenerator // set to true if you are going to texture this cylinder or want sharp edges public bool NoSharedVertices = false; - override public MeshGenerator Generate(int maxDegreeOfParallelism) + override public MeshGenerator Generate() { bool bClosed = ((EndAngleDeg - StartAngleDeg) > 359.99f); int nRingSize = (NoSharedVertices && bClosed) ? Slices + 1 : Slices; @@ -218,7 +218,7 @@ public class ConeGenerator : MeshGenerator public bool NoSharedVertices = false; - override public MeshGenerator Generate(int maxDegreeOfParallelism) + override public MeshGenerator Generate() { bool bClosed = ((EndAngleDeg - StartAngleDeg) > 359.99f); int nRingSize = (NoSharedVertices && bClosed) ? Slices + 1 : Slices; @@ -333,7 +333,7 @@ public class VerticalGeneralizedCylinderGenerator : MeshGenerator public int startCapCenterIndex = -1; public int endCapCenterIndex = -1; - override public MeshGenerator Generate(int maxDegreeOfParallelism) + override public MeshGenerator Generate() { int nRings = (NoSharedVertices) ? 2 * (Sections.Length-1) : Sections.Length; int nRingSize = (NoSharedVertices) ? Slices + 1 : Slices; diff --git a/mesh_generators/DiscGenerators.cs b/mesh_generators/DiscGenerators.cs index d675b9ea..057d8769 100644 --- a/mesh_generators/DiscGenerators.cs +++ b/mesh_generators/DiscGenerators.cs @@ -13,7 +13,7 @@ public class TrivialDiscGenerator : MeshGenerator public float EndAngleDeg = 360.0f; public int Slices = 32; - override public MeshGenerator Generate(int maxDegreeOfParallelism) + override public MeshGenerator Generate() { vertices = new VectorArray3d(Slices + 1); uv = new VectorArray2f(Slices + 1); @@ -64,7 +64,7 @@ public class PuncturedDiscGenerator : MeshGenerator public float EndAngleDeg = 360.0f; public int Slices = 32; - override public MeshGenerator Generate(int maxDegreeOfParallelism) + override public MeshGenerator Generate() { vertices = new VectorArray3d(2*Slices); uv = new VectorArray2f(2*Slices); diff --git a/mesh_generators/GenCylGenerators.cs b/mesh_generators/GenCylGenerators.cs index ce0d824a..49c5996a 100644 --- a/mesh_generators/GenCylGenerators.cs +++ b/mesh_generators/GenCylGenerators.cs @@ -74,7 +74,7 @@ public TubeGenerator(DCurve3 tubePath, Polygon2d tubeShape) - override public MeshGenerator Generate(int maxDegreeOfParallelism) + override public MeshGenerator Generate() { if (Polygon == null) Polygon = Polygon2d.MakeCircle(1.0f, 8); diff --git a/mesh_generators/MeshGenerators.cs b/mesh_generators/MeshGenerators.cs index 81e16a66..67e11a4a 100644 --- a/mesh_generators/MeshGenerators.cs +++ b/mesh_generators/MeshGenerators.cs @@ -19,7 +19,7 @@ abstract public class MeshGenerator - abstract public MeshGenerator Generate(int maxDegreeOfParallelism); + abstract public MeshGenerator Generate(); public virtual void MakeMesh(SimpleMesh m) diff --git a/mesh_generators/PlaneGenerators.cs b/mesh_generators/PlaneGenerators.cs index 7cf43ff8..fa547dbe 100644 --- a/mesh_generators/PlaneGenerators.cs +++ b/mesh_generators/PlaneGenerators.cs @@ -37,7 +37,7 @@ virtual protected Vector3d make_vertex(float x, float y) return v; } - override public MeshGenerator Generate(int maxDegreeOfParallelism) + override public MeshGenerator Generate() { if (MathUtil.InRange(IndicesMap.a, 1, 3) == false || MathUtil.InRange(IndicesMap.b, 1, 3) == false) throw new Exception("TrivialRectGenerator: Invalid IndicesMap!"); @@ -106,7 +106,7 @@ public class GriddedRectGenerator : TrivialRectGenerator { public int EdgeVertices = 8; - override public MeshGenerator Generate(int maxDegreeOfParallelism) + override public MeshGenerator Generate() { if (MathUtil.InRange(IndicesMap.a, 1, 3) == false || MathUtil.InRange(IndicesMap.b, 1, 3) == false) throw new Exception("GriddedRectGenerator: Invalid IndicesMap!"); @@ -227,7 +227,7 @@ public enum UVModes // order is [inner_corner, outer_1, outer_2] static int[] corner_spans = new int[] { 0, 11, 4, 1, 5, 6, 2, 7, 8, 3, 9, 10 }; - override public MeshGenerator Generate(int maxDegreeOfParallelism) + override public MeshGenerator Generate() { int corner_v = 0, corner_t = 0; for (int k = 0; k < 4; ++k) { diff --git a/mesh_generators/PointsMeshGenerators.cs b/mesh_generators/PointsMeshGenerators.cs index ace8b83a..5ef34ea3 100644 --- a/mesh_generators/PointsMeshGenerators.cs +++ b/mesh_generators/PointsMeshGenerators.cs @@ -22,7 +22,7 @@ public PointSplatsGenerator() WantUVs = false; } - public override MeshGenerator Generate(int maxDegreeOfParallelism) + public override MeshGenerator Generate() { int N = (PointIndicesCount == -1) ? PointIndices.Count() : PointIndicesCount; @@ -58,15 +58,14 @@ public override MeshGenerator Generate(int maxDegreeOfParallelism) /// public static DMesh3 Generate(IList indices, Func PointF, Func NormalF, - double radius, - int maxDegreeOfParallelism) + double radius) { var gen = new PointSplatsGenerator() { PointIndices = indices, PointIndicesCount = indices.Count, PointF = PointF, NormalF = NormalF, Radius = radius }; - return gen.Generate(maxDegreeOfParallelism).MakeDMesh(); + return gen.Generate().MakeDMesh(); } } diff --git a/mesh_generators/RevolveGenerator.cs b/mesh_generators/RevolveGenerator.cs index 09b273b5..d0f2f421 100644 --- a/mesh_generators/RevolveGenerator.cs +++ b/mesh_generators/RevolveGenerator.cs @@ -18,7 +18,7 @@ public class Curve3Axis3RevolveGenerator : MeshGenerator public int startCapCenterIndex = -1; public int endCapCenterIndex = -1; - public override MeshGenerator Generate(int maxDegreeOfParallelism) + public override MeshGenerator Generate() { int nRings = Curve.Length; int nRingSize = (NoSharedVertices) ? Slices + 1 : Slices; @@ -172,7 +172,7 @@ public class Curve3Curve3RevolveGenerator : MeshGenerator public int startCapCenterIndex = -1; public int endCapCenterIndex = -1; - public override MeshGenerator Generate(int maxDegreeOfParallelism) + public override MeshGenerator Generate() { double tCurveLen = CurveUtils.ArcLength(Curve); SampledArcLengthParam pAxis = new SampledArcLengthParam(Axis, Axis.Length); diff --git a/mesh_generators/SphereGenerators.cs b/mesh_generators/SphereGenerators.cs index 83990a8a..0b9e2977 100644 --- a/mesh_generators/SphereGenerators.cs +++ b/mesh_generators/SphereGenerators.cs @@ -23,9 +23,9 @@ public enum NormalizationTypes } NormalizationTypes NormalizeType = NormalizationTypes.CubeMapping; - public override MeshGenerator Generate(int maxDegreeOfParallelism) + public override MeshGenerator Generate() { - base.Generate(maxDegreeOfParallelism); + base.Generate(); for ( int i = 0; i < vertices.Count; ++i ) { Vector3d v = vertices[i] - Box.Center; if (NormalizeType == NormalizationTypes.CubeMapping) { diff --git a/mesh_generators/TriangulatedPolygonGenerator.cs b/mesh_generators/TriangulatedPolygonGenerator.cs index c5ca0ca0..8fbab02b 100644 --- a/mesh_generators/TriangulatedPolygonGenerator.cs +++ b/mesh_generators/TriangulatedPolygonGenerator.cs @@ -16,9 +16,9 @@ public class TriangulatedPolygonGenerator : MeshGenerator public int Subdivisions = 1; public MeshInsertPolygon Insert; - override public MeshGenerator Generate(int maxDegreeOfParallelism) + override public MeshGenerator Generate() { - DMesh3 base_mesh = ComputeResult(maxDegreeOfParallelism, out Insert); + DMesh3 base_mesh = ComputeResult(out Insert); DMesh3 compact = new DMesh3(base_mesh, true); @@ -48,7 +48,7 @@ override public MeshGenerator Generate(int maxDegreeOfParallelism) /// coming back than we get by using Generate() api. Note that resulting /// mesh is *not* compacted. /// - public DMesh3 ComputeResult(int maxDegreeOfParallelism, out MeshInsertPolygon insertion) + public DMesh3 ComputeResult(out MeshInsertPolygon insertion) { AxisAlignedBox2d bounds = Polygon.Bounds; double padding = 0.1 * bounds.DiagonalLength; @@ -62,7 +62,7 @@ public DMesh3 ComputeResult(int maxDegreeOfParallelism, out MeshInsertPolygon in rectgen.IndicesMap = new Index2i(1, 2); rectgen.UVMode = UVMode; rectgen.Clockwise = true; // MeshPolygonInserter assumes mesh faces are CW? (except code says CCW...) - rectgen.Generate(maxDegreeOfParallelism); + rectgen.Generate(); DMesh3 base_mesh = new DMesh3(); rectgen.MakeMesh(base_mesh); @@ -76,7 +76,7 @@ public DMesh3 ComputeResult(int maxDegreeOfParallelism, out MeshInsertPolygon in insertion = insert; - bool bOK = insert.Insert(maxDegreeOfParallelism); + bool bOK = insert.Insert(); if (!bOK) throw new Exception("TriangulatedPolygonGenerator: failed to Insert()"); diff --git a/mesh_ops/AutoHoleFill.cs b/mesh_ops/AutoHoleFill.cs index 9fb6a083..5a19ad3b 100644 --- a/mesh_ops/AutoHoleFill.cs +++ b/mesh_ops/AutoHoleFill.cs @@ -62,7 +62,7 @@ public bool Apply(int maxDegreeOfParallelism) else if (type == UseFillType.MinimalFill) bResult = fill_minimal(maxDegreeOfParallelism); else if (type == UseFillType.PlanarSpansFill) - bResult = fill_planar_spans(maxDegreeOfParallelism); + bResult = fill_planar_spans(); else bResult = fill_smooth(maxDegreeOfParallelism); @@ -163,7 +163,7 @@ bool fill_minimal(int maxDegreeOfParallelism) /// 2) /// /// - bool fill_planar_spans(int maxDegreeOfParallelism) + bool fill_planar_spans() { Dictionary> span_sets = find_coplanar_span_sets(Mesh, FillLoop); @@ -179,7 +179,7 @@ bool fill_planar_spans(int maxDegreeOfParallelism) PlanarSpansFiller filler = new PlanarSpansFiller(Mesh, subset); filler.FillTargetEdgeLen = TargetEdgeLength; filler.SetPlane(pos, normal); - filler.Fill(maxDegreeOfParallelism); + filler.Fill(); } } @@ -187,7 +187,7 @@ bool fill_planar_spans(int maxDegreeOfParallelism) PlanarSpansFiller filler = new PlanarSpansFiller(Mesh, spans); filler.FillTargetEdgeLen = TargetEdgeLength; filler.SetPlane(pos, normal); - filler.Fill(maxDegreeOfParallelism); + filler.Fill(); } } diff --git a/mesh_ops/MeshExtrudeFaces.cs b/mesh_ops/MeshExtrudeFaces.cs index 8dd8cfc1..13ec1a95 100644 --- a/mesh_ops/MeshExtrudeFaces.cs +++ b/mesh_ops/MeshExtrudeFaces.cs @@ -75,7 +75,7 @@ public virtual ValidationStatus Validate() /// However changes are not backed out, so if false is returned, input Mesh is in /// undefined state (generally means there are some holes) /// - public virtual bool Extrude(int maxDegreeOfParallelism) + public virtual bool Extrude() { MeshEditor editor = new MeshEditor(Mesh); @@ -85,7 +85,7 @@ public virtual bool Extrude(int maxDegreeOfParallelism) bool bHaveNormals = Mesh.HasVertexNormals; if (!bHaveNormals) { normals = new MeshNormals(Mesh); - normals.Compute(maxDegreeOfParallelism); + normals.Compute(); } ExtrudeVertices = new MeshVertexSelection(Mesh); diff --git a/mesh_ops/MeshExtrudeMesh.cs b/mesh_ops/MeshExtrudeMesh.cs index e6856312..8652777d 100644 --- a/mesh_ops/MeshExtrudeMesh.cs +++ b/mesh_ops/MeshExtrudeMesh.cs @@ -56,13 +56,13 @@ public virtual ValidationStatus Validate() } - public virtual bool Extrude(int maxDegreeOfParallelism) + public virtual bool Extrude() { MeshNormals normals = null; bool bHaveNormals = Mesh.HasVertexNormals; if (!bHaveNormals) { normals = new MeshNormals(Mesh); - normals.Compute(maxDegreeOfParallelism); + normals.Compute(); } InitialLoops = new MeshBoundaryLoops(Mesh); diff --git a/mesh_ops/MeshInsertPolygon.cs b/mesh_ops/MeshInsertPolygon.cs index acbe9ad4..65830167 100644 --- a/mesh_ops/MeshInsertPolygon.cs +++ b/mesh_ops/MeshInsertPolygon.cs @@ -22,11 +22,11 @@ public class MeshInsertPolygon public HashSet InsertedPolygonEdges; public MeshFaceSelection InteriorTriangles; - public bool Insert(int maxDegreeOfParallelism) + public bool Insert() { OuterInsert = new MeshInsertUVPolyCurve(Mesh, Polygon.Outer); Util.gDevAssert(OuterInsert.Validate() == ValidationStatus.Ok); - bool outerApplyOK = OuterInsert.Apply(maxDegreeOfParallelism); + bool outerApplyOK = OuterInsert.Apply(); if (outerApplyOK == false || OuterInsert.Loops.Count == 0) return false; if (SimplifyInsertion) @@ -36,7 +36,7 @@ public bool Insert(int maxDegreeOfParallelism) for (int hi = 0; hi < Polygon.Holes.Count; ++hi) { MeshInsertUVPolyCurve insert = new MeshInsertUVPolyCurve(Mesh, Polygon.Holes[hi]); Util.gDevAssert(insert.Validate() == ValidationStatus.Ok); - insert.Apply(maxDegreeOfParallelism); + insert.Apply(); if (SimplifyInsertion) insert.Simplify(); HoleInserts.Add(insert); diff --git a/mesh_ops/MeshInsertProjectedPolygon.cs b/mesh_ops/MeshInsertProjectedPolygon.cs index 86b0de3a..5b834ae7 100644 --- a/mesh_ops/MeshInsertProjectedPolygon.cs +++ b/mesh_ops/MeshInsertProjectedPolygon.cs @@ -122,7 +122,7 @@ public virtual ValidationStatus Validate() } - public bool Insert(int maxDegreeOfParallelism) + public bool Insert() { Func is_contained_v = (vid) => { Vector3d v = Mesh.GetVertex(vid); @@ -179,7 +179,7 @@ public bool Insert(int maxDegreeOfParallelism) MeshInsertUVPolyCurve insertUV = new MeshInsertUVPolyCurve(roiMesh, Polygon); //insertUV.Validate() - bool bOK = insertUV.Apply(maxDegreeOfParallelism); + bool bOK = insertUV.Apply(); if (!bOK) throw new Exception("insertUV.Apply() failed"); diff --git a/mesh_ops/MeshInsertUVPolyCurve.cs b/mesh_ops/MeshInsertUVPolyCurve.cs index 49db7e53..ff80304d 100644 --- a/mesh_ops/MeshInsertUVPolyCurve.cs +++ b/mesh_ops/MeshInsertUVPolyCurve.cs @@ -308,7 +308,7 @@ int insert_corner_from_bary(int iCorner, int tid, Vector3d bary_coords, return pokeinfo.new_vid; } - public virtual bool Apply(int maxDegreeOfParallelism) + public virtual bool Apply() { HashSet OnCurveVerts = new HashSet(); // original vertices that were epsilon-coincident w/ curve vertices insert_corners(OnCurveVerts); @@ -364,18 +364,25 @@ public virtual bool Apply(int maxDegreeOfParallelism) // [TODO] could walk along mesh from a to b, rather than computing for entire mesh? if ( signs.Length < MaxVID ) signs = new sbyte[2*MaxVID]; - gParallel.ForEach(vertices, (vid) => { - if (Mesh.IsVertex(vid)) { - if (vid == i0_vid || vid == i1_vid) { - signs[vid] = 0; - } else { - Vector2d v2 = PointF(vid); - // tolerance defines band in which we will consider values to be zero - signs[vid] = (sbyte)seg.WhichSide(v2, SpatialEpsilon); - } - } else + // TODO: It used to be a parallel opration, but + // 1. It pollutes the Generate interface + // 2. The operations are instant + for (int vid = 0; vid < MaxVID; vid++) + { + if (!Mesh.IsVertex(vid)) + { signs[vid] = sbyte.MaxValue; - }, maxDegreeOfParallelism); + continue; + } + if (vid == i0_vid || vid == i1_vid) + { + signs[vid] = 0; + continue; + } + Vector2d v2 = PointF(vid); + // tolerance defines band in which we will consider values to be zero + signs[vid] = (sbyte)seg.WhichSide(v2, SpatialEpsilon); + } // have to skip processing of new edges. If edge id // is > max at start, is new. Otherwise if in NewEdges list, also new. diff --git a/mesh_ops/MeshMeshCut.cs b/mesh_ops/MeshMeshCut.cs index 9b3f7ff2..1f5d30a3 100644 --- a/mesh_ops/MeshMeshCut.cs +++ b/mesh_ops/MeshMeshCut.cs @@ -82,12 +82,12 @@ public void RemoveContained(int maxDegreeOfParallelism) } } - public void AppendSegments(double r, int maxDegreeOfParallelism) + public void AppendSegments(double r) { foreach ( var seg in Segments ) { Segment3d s = new Segment3d(seg.v0.v, seg.v1.v); if ( Target.FindEdge(seg.v0.vtx_id, seg.v1.vtx_id) == DMesh3.InvalidID ) - MeshEditor.AppendLine(Target, s, (float)r, maxDegreeOfParallelism); + MeshEditor.AppendLine(Target, s, (float)r); } } @@ -468,7 +468,7 @@ void insert_segment(IntersectSegment seg, int maxDegreeOfParallelism) path.AppendVertex(p0); path.AppendVertex(p1); MeshInsertUVPolyCurve insert = new MeshInsertUVPolyCurve(mesh, path); - insert.Apply(maxDegreeOfParallelism); + insert.Apply(); MeshVertexSelection cutVerts = new MeshVertexSelection(mesh); cutVerts.SelectEdgeVertices(insert.OnCutEdges); diff --git a/mesh_ops/MeshPlaneCut.cs b/mesh_ops/MeshPlaneCut.cs index a8c855e0..f97db954 100644 --- a/mesh_ops/MeshPlaneCut.cs +++ b/mesh_ops/MeshPlaneCut.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using System.Security.Cryptography; namespace g3 { @@ -67,7 +68,7 @@ public virtual ValidationStatus Validate() } - public virtual bool Cut(int maxDegreeOfParallelism) + public virtual bool Cut() { double invalidDist = double.MinValue; @@ -81,13 +82,18 @@ public virtual bool Cut(int maxDegreeOfParallelism) // compute signs int MaxVID = Mesh.MaxVertexID; double[] signs = new double[MaxVID]; - gParallel.ForEach(Interval1i.Range(MaxVID), (vid) => { - if (Mesh.IsVertex(vid)) { - Vector3d v = Mesh.GetVertex(vid); - signs[vid] = (v - PlaneOrigin).Dot(PlaneNormal); - } else - signs[vid] = invalidDist; - }, maxDegreeOfParallelism); + // That used to be a parallel operation, + // but it's pointless as the operation of Dot is cheap + for (int vid = 0; vid < MaxVID; vid++) + { + if (!Mesh.IsVertex(vid)) + { + signs[vid] = invalidDist; + continue; + } + Vector3d v = Mesh.GetVertexUnsafe(vid); + signs[vid] = (v - PlaneOrigin).Dot(PlaneNormal); + } HashSet ZeroEdges = new HashSet(); HashSet ZeroVertices = new HashSet(); diff --git a/mesh_ops/MeshTopology.cs b/mesh_ops/MeshTopology.cs index 7cd0d2c5..fc5512c5 100644 --- a/mesh_ops/MeshTopology.cs +++ b/mesh_ops/MeshTopology.cs @@ -201,7 +201,7 @@ void extract_topology() - public DMesh3 MakeElementsMesh(Polygon2d spanProfile, Polygon2d loopProfile, int maxDegreeOfParallelism) + public DMesh3 MakeElementsMesh(Polygon2d spanProfile, Polygon2d loopProfile) { DMesh3 result = new DMesh3(); validate_topology(); @@ -209,13 +209,13 @@ public DMesh3 MakeElementsMesh(Polygon2d spanProfile, Polygon2d loopProfile, int foreach (EdgeSpan span in Spans) { DCurve3 curve = span.ToCurve(Mesh); TubeGenerator tubegen = new TubeGenerator(curve, spanProfile); - MeshEditor.Append(result, tubegen.Generate(maxDegreeOfParallelism).MakeDMesh()); + MeshEditor.Append(result, tubegen.Generate().MakeDMesh()); } foreach (EdgeLoop loop in Loops) { DCurve3 curve = loop.ToCurve(Mesh); TubeGenerator tubegen = new TubeGenerator(curve, loopProfile); - MeshEditor.Append(result, tubegen.Generate(maxDegreeOfParallelism).MakeDMesh()); + MeshEditor.Append(result, tubegen.Generate().MakeDMesh()); } return result; diff --git a/mesh_ops/PlanarHoleFiller.cs b/mesh_ops/PlanarHoleFiller.cs index 24bb2707..56c71e85 100644 --- a/mesh_ops/PlanarHoleFiller.cs +++ b/mesh_ops/PlanarHoleFiller.cs @@ -166,7 +166,7 @@ public bool Fill(int maxDegreeOfParallelism) EdgeVertices = nDivisions }; } - DMesh3 FillMesh = meshgen.Generate(maxDegreeOfParallelism).MakeDMesh(); + DMesh3 FillMesh = meshgen.Generate().MakeDMesh(); FillMesh.ReverseOrientation(); // why?!? // convenient list @@ -182,7 +182,7 @@ public bool Fill(int maxDegreeOfParallelism) ValidationStatus status = insert.Validate(MathUtil.ZeroTolerancef * scale); bool failed = true; if (status == ValidationStatus.Ok) { - if (insert.Apply(maxDegreeOfParallelism)) { + if (insert.Apply()) { insert.Simplify(); polyVertices[pi] = insert.CurveVertices; failed = (insert.Loops.Count != 1) || diff --git a/mesh_ops/PlanarSpansFiller.cs b/mesh_ops/PlanarSpansFiller.cs index 72d98c43..245e7cf5 100644 --- a/mesh_ops/PlanarSpansFiller.cs +++ b/mesh_ops/PlanarSpansFiller.cs @@ -69,7 +69,7 @@ public void SetPlane(Vector3d origin, Vector3d normal, Vector3d planeX, Vector3d } - public bool Fill(int maxDegreeOfParallelism) + public bool Fill() { compute_polygon(); @@ -101,7 +101,7 @@ public bool Fill(int maxDegreeOfParallelism) EdgeVertices = nDivisions }; } - DMesh3 FillMesh = meshgen.Generate(maxDegreeOfParallelism).MakeDMesh(); + DMesh3 FillMesh = meshgen.Generate().MakeDMesh(); FillMesh.ReverseOrientation(); // why?!? int[] polyVertices = null; @@ -111,7 +111,7 @@ public bool Fill(int maxDegreeOfParallelism) ValidationStatus status = insert.Validate(MathUtil.ZeroTolerancef * scale); bool failed = true; if (status == ValidationStatus.Ok) { - if (insert.Apply(maxDegreeOfParallelism)) { + if (insert.Apply()) { insert.Simplify(); polyVertices = insert.CurveVertices; failed = false; diff --git a/mesh_ops/RemoveOccludedTriangles.cs b/mesh_ops/RemoveOccludedTriangles.cs index 76f11366..08a0d269 100644 --- a/mesh_ops/RemoveOccludedTriangles.cs +++ b/mesh_ops/RemoveOccludedTriangles.cs @@ -134,7 +134,7 @@ public virtual bool Apply(int maxDegreeOfParallelism) MeshNormals normals = null; if (Mesh.HasVertexNormals == false) { normals = new MeshNormals(Mesh); - normals.Compute(maxDegreeOfParallelism); + normals.Compute(); } gParallel.ForEach(Mesh.VertexIndices(), (vid) => { diff --git a/mesh_ops/SmoothedHoleFill.cs b/mesh_ops/SmoothedHoleFill.cs index 7e43c284..b23f3353 100644 --- a/mesh_ops/SmoothedHoleFill.cs +++ b/mesh_ops/SmoothedHoleFill.cs @@ -127,7 +127,7 @@ public bool Apply(int maxDegreeOfParallelism) extrude.ExtrudedPositionF = (v, n, vid) => { return v + OffsetDistance * OffsetDirection; }; - if (!extrude.Extrude(maxDegreeOfParallelism)) + if (!extrude.Extrude()) return false; tris.Select(extrude.JoinTriangles); } diff --git a/test/StandardMeshReaderTests.cs b/test/StandardMeshReaderTests.cs index 347cbe03..d800df18 100644 --- a/test/StandardMeshReaderTests.cs +++ b/test/StandardMeshReaderTests.cs @@ -11,11 +11,10 @@ namespace geometry3sharp.Tests { public class StandardMeshReaderTests { - private static readonly int MaxDegreeOfParallelism = Environment.ProcessorCount; private static string ModelsDirectoryPath => Path.Combine("..", "..", "..", "models"); private static string BoxPathWithoutExtension => Path.Combine(ModelsDirectoryPath, "box"); private static readonly Lazy BoxMesh = - new Lazy(() => new TrivialBox3Generator().Generate(MaxDegreeOfParallelism).MakeDMesh()); + new Lazy(() => new TrivialBox3Generator().Generate().MakeDMesh()); [Fact(Skip = "Use this method to regenerate the box")] public void WriteAllFiles()