namespace TriangleNet.Examples { using System; using System.Collections.Concurrent; using System.IO; using System.Linq; using System.Threading.Tasks; using TriangleNet; using TriangleNet.Geometry; using TriangleNet.IO; using TriangleNet.Meshing; using TriangleNet.Meshing.Algorithm; /// /// Processing meshes in parallel. /// public class ExamplePar { #region Point set triangulation /// /// Triangulate a given number of random point sets in parallel. /// public static bool Run(int n = 1000) { // Use thread-safe random source. var random = Random.Shared; // Generate a random set of sizes. var sizes = Enumerable.Range(0, n).Select(_ => random.Next(500, 5000)); var queue = new ConcurrentQueue(sizes); int concurrencyLevel = Environment.ProcessorCount / 2; var tasks = new Task[concurrencyLevel]; for (int i = 0; i < concurrencyLevel; i++) { tasks[i] = Task.Run(() => { // Each task has it's own triangle pool and predicates instance. var pool = new TrianglePool(); var predicates = new RobustPredicates(); // The factory methods return the above instances. var config = new Configuration() { Predicates = () => predicates, TrianglePool = () => pool.Restart() }; var triangulator = new Dwyer(); var result = new MeshResult(); var bounds = new Rectangle(0d, 0d, 1000d, 1000d); while (queue.Count > 0) { if (queue.TryDequeue(out int size)) { var points = Generate.RandomPoints(size, bounds); var mesh = triangulator.Triangulate(points, config); ProcessMesh(mesh, result); } } pool.Clear(); return result; }); } Task.WaitAll(tasks); int numberOfTriangles = tasks.Sum(t => t.Result.NumberOfTriangles); int invalid = tasks.Sum(t => t.Result.Invalid); Console.WriteLine("Total number of triangles processed: {0}", numberOfTriangles); if (invalid > 0) { Console.WriteLine(" Number of invalid triangulations: {0}", invalid); } return invalid == 0; } #endregion #region Polygon triangulation /// /// Reads all .poly files from given directory and processes them in parallel. /// public static bool Run(string dir) { var files = Directory.EnumerateFiles(dir, "*.poly", SearchOption.AllDirectories); var queue = new ConcurrentQueue(files); int concurrencyLevel = Environment.ProcessorCount / 2; var tasks = new Task[concurrencyLevel]; for (int i = 0; i < concurrencyLevel; i++) { tasks[i] = Task.Run(() => { // Each task has it's own triangle pool and predicates instance. var pool = new TrianglePool(); var predicates = new RobustPredicates(); // The factory methods return the above instances. var config = new Configuration() { Predicates = () => predicates, TrianglePool = () => pool.Restart() }; var mesher = new GenericMesher(config); var result = new MeshResult(); while (queue.Count > 0) { if (queue.TryDequeue(out var file)) { var poly = FileProcessor.Read(file); var mesh = mesher.Triangulate(poly); ProcessMesh(mesh, result); } } pool.Clear(); return result; }); } Task.WaitAll(tasks); int numberOfTriangles = tasks.Sum(t => t.Result.NumberOfTriangles); int invalid = tasks.Sum(t => t.Result.Invalid); Console.WriteLine("Total number of triangles processed: {0}", numberOfTriangles); if (invalid > 0) { Console.WriteLine(" Number of invalid triangulations: {0}", invalid); } return invalid == 0; } private static void ProcessMesh(IMesh mesh, MeshResult result) { result.NumberOfTriangles += mesh.Triangles.Count; if (!MeshValidator.IsConsistent((Mesh)mesh)) { result.Invalid += 1; } } class MeshResult { public int NumberOfTriangles; public int Invalid; } #endregion } }