Add CDT.Comparison.Benchmarks — 6-library CDT/Delaunay performance comparison (Windows + Linux)#12
Conversation
Co-authored-by: MichaCo <5837539+MichaCo@users.noreply.github.com>
Co-authored-by: MichaCo <5837539+MichaCo@users.noreply.github.com>
Co-authored-by: MichaCo <5837539+MichaCo@users.noreply.github.com>
Co-authored-by: MichaCo <5837539+MichaCo@users.noreply.github.com>
Co-authored-by: MichaCo <5837539+MichaCo@users.noreply.github.com>
Co-authored-by: MichaCo <5837539+MichaCo@users.noreply.github.com>
Co-authored-by: MichaCo <5837539+MichaCo@users.noreply.github.com>
Co-authored-by: MichaCo <5837539+MichaCo@users.noreply.github.com>
Co-authored-by: MichaCo <5837539+MichaCo@users.noreply.github.com>
Co-authored-by: MichaCo <5837539+MichaCo@users.noreply.github.com>
|
…-dep error messages Co-authored-by: MichaCo <5837539+MichaCo@users.noreply.github.com>
Done in commit Cross-platform native build (csproj)
CMakeLists.txt (C++ wrapper)
Missing dependency error messages
README — Windows prerequisites
|
|
@copilot now, when I run and compare the returned values from all libs All return around 5000, except Poly2Tri which returns only 130. How can that be? Is that a bug in our code or is it just doing something fundamentally different? |
…e count Co-authored-by: MichaCo <5837539+MichaCo@users.noreply.github.com>
Co-authored-by: MichaCo <5837539+MichaCo@users.noreply.github.com>
... Not a bug in our adapter — it's a known limitation of Poly2Tri's algorithm. Root cause: Poly2Tri's sweep-line internally uses precision thresholds relative to the bounding box. The Sweden dataset has geographic coordinates (bbox ≈13×14 degrees, minimum inter-point separation ≈0.006 degrees → ratio ≈0.00046). Many points fall below Poly2Tri's internal epsilon for that coordinate range and are silently skipped. Running the dataset through This is a well-known Poly2Tri constraint: the algorithm was designed for integer-like or small normalised coordinates, not arbitrary floating-point geographic data. All other libraries in the benchmark (CDT.NET, Triangle.NET, NTS, artem-ogre/CDT, Spade) handle geographic-scale coordinates correctly. I've added a detailed |
Lets add another library instead
|
…_package) Co-authored-by: MichaCo <5837539+MichaCo@users.noreply.github.com>
…orkflow Co-authored-by: MichaCo <5837539+MichaCo@users.noreply.github.com>
…direct_traits.hpp) Co-authored-by: MichaCo <5837539+MichaCo@users.noreply.github.com>
…tforms) Co-authored-by: MichaCo <5837539+MichaCo@users.noreply.github.com>
…both green Co-authored-by: MichaCo <5837539+MichaCo@users.noreply.github.com>
... Done in commit
|
|
@copilot Run the benchmarks and update the results and conclusions |
Co-authored-by: MichaCo <5837539+MichaCo@users.noreply.github.com>
Results updated in commit Constrained CDT (Constrained Sweden, ~2 600 pts + edges, AMD EPYC 7763, .NET 10.0.2):
Vertices-only (Delaunay):
CDT.NET is ~2× faster than CGAL on both categories. CGAL uses a half-edge DCEL data structure with more bookkeeping overhead; CDT.NET's compact flat-array design wins on throughput. |
|
@copilot can you change the Comparison csproj build the native things only once until we delete the binaries with dotnet clean ? |
…ppers Co-authored-by: MichaCo <5837539+MichaCo@users.noreply.github.com>
Done in commit Root cause: Fix: The path expression is now inlined directly in each Condition="!Exists('$(OutputPath)$(_NativeLibPrefix)cdt_wrapper$(_NativeLibExt)')"A Verified on Linux:
|
|
@copilot exclude CDT.Comparison.Benchmarks from the normal CI/CD build pipeline. Takes too long and we don't actually need it for running tests or generating the nuget |
Co-authored-by: MichaCo <5837539+MichaCo@users.noreply.github.com>
Done in commit Changes made:
All existing behaviour — test coverage, PR comment, NuGet publish — is preserved. |
SummarySummary
CoverageCDT.Core - 85%
|
Adds a new
benchmark/CDT.Comparison.Benchmarks/project that benchmarks CDT.NET against five other triangulation libraries across two categories: VerticesOnly (unconstrained Delaunay) and Constrained (full CDT with edges). Dataset: Constrained Sweden (~2 600 vertices, ~2 600 constraint edges).Libraries
Unofficial.Triangle.NET0.0.1NetTopologySuite2.6.0Structure
InputReader— shared loader for the existing.txttest input format (same files used byCDT.Tests)staticclass acceptingdouble[] xs/ys+int[] ev1/ev2; benchmark methods are one-liners[ShortRunJob]+[MemoryDiagnoser]+[GroupBenchmarksBy(ByCategory)]with CDT.NET as[Baseline]per groupBeforeTargets="Build"targets — no manual steps required on any platform:native/cdt_wrapper/— CMake + FetchContent (artem-ogre/CDTpinned to tag1.4.4)native/cgal_wrapper/— CMake + FetchContent (CGAL 6.1.1 library ZIP + 38 Boost sub-library ZIPs, ~20 MB total, no system install needed)native/spade_wrapper/— Cargo (spade = "2.15.0")Native Build Caching
Native wrappers are built only once — subsequent
dotnet buildinvocations (including C#-only changes) skip cmake/cargo entirely by checking whether the output library already exists in$(OutputPath). Runningdotnet cleanremoves the copied native libraries, causing them to be rebuilt on the nextdotnet build.Cross-platform support (Windows, Linux, macOS)
cdt_wrapper.dll,cgal_wrapper.dllspade_wrapper.dlllibcdt_wrapper.dylib,libcgal_wrapper.dyliblibspade_wrapper.dyliblibcdt_wrapper.so,libcgal_wrapper.solibspade_wrapper.soIf
cmakeorcargoare not on PATH,dotnet buildemits a clear error message with the install URL rather than a cryptic failure.CI/CD
CDT.Comparison.Benchmarksis excluded from the normal CI/CD pipeline — the existing workflow builds onlyCDT.Core,CDT.Tests,CDT.Benchmarks, andCDT.Viz, and runs tests againstCDT.Testsdirectly. This keeps CI fast and unaffected by the native build prerequisites (cmake, cargo, C++ compiler) that are only needed when running the comparison benchmarks locally.Results (AMD EPYC 7763, .NET 10.0.2, ShortRunJob, Constrained Sweden ~2 600 pts)
Constrained CDT:
Vertices-only (Delaunay):
CDT.NET is within ≤13% of the original C++ implementation and Spade on constrained triangulation, ~2× faster than CGAL, and allocates 5–120× less memory than Triangle.NET and NTS.
Notes
cmake+ C++17 compiler andcargoat build time; internet access needed for FetchContent / crates.io on first build. See README for full prerequisites per platform..gitignore(native/*/build/,native/*/target/).Original prompt
Goal
Research and add a new benchmark project that compares the performance of CDT.NET (this repo) against other C# Constrained Delaunay Triangulation (CDT) libraries available on NuGet.
Context
The repository already has a benchmark project at
benchmark/CDT.Benchmarks/using BenchmarkDotNet targetingnet10.0. The main library is atsrc/CDT.Core/CDT.Core.csproj.Key types in CDT.NET:
Triangulation<T>— main CDT class, generic over floating-point typeV2d<T>— 2D point/vertexEdge— constraint edge (pair of vertex indices)VertexInsertionOrder— enum (AsProvided,Auto)InsertVertices(IReadOnlyList<V2d<T>>),InsertEdges(IReadOnlyList<Edge>),EraseSuperTriangle()/EraseOuterTriangles()/EraseOuterTrianglesAndHoles()Existing benchmark input files are in
test/CDT.Tests/inputs/*.txt(format:nVerts nEdges\n x y\n... v1 v2\n...) and are copied to the benchmark output underinputs/.What to build
Create a new benchmark project:
benchmark/CDT.Comparison.Benchmarks/1. Research — C# CDT libraries to include
Find and include at least these well-known NuGet packages (use latest stable versions):
src/CDT.CoreTriangle.NETorTriangleDelaunatorSharpSearch NuGet for any additional C# CDT/Delaunay libraries that support constrained edges. Include any you find that are:
2. Project file:
benchmark/CDT.Comparison.Benchmarks/CDT.Comparison.Benchmarks.csproj3. Benchmark classes
Create
benchmark/CDT.Comparison.Benchmarks/ComparisonBenchmarks.cswith:BenchmarkInputReaderthat loads the same.txtfilesConstrained Sweden.txt)[BenchmarkCategory]to group by operation type[MemoryDiagnoser]to capture allocations[ShortRunJob]for quick runsFor libraries that don't support constrained edges natively, only include a "vertices only" benchmark and add a comment explaining why.
4. Adapter pattern
For each competing library, create a thin adapter class/method that:
List<(double X, double Y)>points andList<(int V1, int V2)>edgesinttriangle count to prevent dead-code elimination)This keeps the benchmark methods clean.
5. Program entry point
benchmark/CDT.Comparison.Benchmarks/Program.cs:6. Add to solution
Update
CDT.NET.slnxto include the new project.7. README section (optional but nice)
Add a
benchmark/CDT.Comparison.Benchmarks/README.mdexplaining:Constraints
net10.0BenchmarkDotNetversion0.15.8(same as existing benchmark project)benchmark/CDT.Benchmarks/must not be modifiedThis pull request was created from Copilot chat.
✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.