CDT.NET 1.0.0-beta1

This is a prerelease version of CDT.NET.
There is a newer prerelease version of this package available.
See the version list below for details.
dotnet add package CDT.NET --version 1.0.0-beta1
                    
NuGet\Install-Package CDT.NET -Version 1.0.0-beta1
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="CDT.NET" Version="1.0.0-beta1" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="CDT.NET" Version="1.0.0-beta1" />
                    
Directory.Packages.props
<PackageReference Include="CDT.NET" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add CDT.NET --version 1.0.0-beta1
                    
#r "nuget: CDT.NET, 1.0.0-beta1"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package CDT.NET@1.0.0-beta1
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=CDT.NET&version=1.0.0-beta1&prerelease
                    
Install as a Cake Addin
#tool nuget:?package=CDT.NET&version=1.0.0-beta1&prerelease
                    
Install as a Cake Tool

CDT.NET

Build NuGet

A C# port of the artem-ogre/CDT Constrained Delaunay Triangulation library.

Credits: This library is a C# port of the excellent CDT C++ library by Artem Amirkhanov and contributors, licensed under MPL 2.0. For full algorithm documentation, research references, and in-depth API documentation please refer to the original C++ repository and its online documentation.

What is CDT?

CDT is a library for generating Constrained and Conforming Delaunay Triangulations. It produces triangulations from a set of points and optional boundary/constraint edges. Unlike a plain Delaunay triangulation, CDT guarantees that the constraint edges you specify will appear in the final mesh.

Features

  • Constrained Delaunay Triangulation — force specific edges into the triangulation
  • Conforming Delaunay Triangulation — split edges and add Steiner points until constraint edges are present in the triangulation
  • Convex-hull triangulation — triangulate all points without any constraints
  • Automatic hole detection — use EraseOuterTrianglesAndHoles to remove outer regions and holes based on even–odd winding depth
  • Robust geometric predicates — numerically stable orientation and in-circle tests
  • KD-tree spatial indexing — fast nearest-neighbor lookup during vertex insertion
  • Duplicate handling — utilities to remove duplicate vertices and remap edges before triangulation
  • Intersecting constraint edges — optionally resolve by splitting edges at the intersection point
  • Multi-target: .NET 8 and .NET 10

Pre-conditions (same as the C++ original):

  • No duplicate vertices (use CdtUtils.RemoveDuplicatesAndRemapEdges to clean input)
  • No two constraint edges may intersect (or pass IntersectingConstraintEdges.TryResolve)

Post-conditions:

  • All triangles have counter-clockwise (CCW) winding in a coordinate system where X points right and Y points up.

Installation

dotnet add package CDT.NET

Usage

Delaunay triangulation (convex hull, no constraints)

Insert vertices and call EraseSuperTriangle to get the convex-hull triangulation.

using CDT;

var vertices = new List<V2d<double>>
{
    new(0, 0), new(4, 0), new(4, 4), new(0, 4), new(2, 2),
};

var cdt = new Triangulation<double>();
cdt.InsertVertices(vertices);
cdt.EraseSuperTriangle(); // produces convex hull

IReadOnlyList<Triangle>    triangles  = cdt.Triangles;
IReadOnlyList<V2d<double>> points     = cdt.Vertices;
HashSet<Edge>              allEdges   = CdtUtils.ExtractEdgesFromTriangles(triangles);

Constrained Delaunay triangulation (bounded domain)

Insert boundary edges, then call EraseOuterTriangles to keep only the region inside the boundary.

using CDT;

var vertices = new List<V2d<double>>
{
    new(0, 0), new(4, 0), new(4, 4), new(0, 4),
};
var edges = new List<Edge>
{
    new(0, 1), new(1, 2), new(2, 3), new(3, 0), // square boundary
};

var cdt = new Triangulation<double>();
cdt.InsertVertices(vertices);
cdt.InsertEdges(edges);
cdt.EraseOuterTriangles(); // removes everything outside the boundary

IReadOnlyList<Triangle> triangles = cdt.Triangles;
IReadOnlySet<Edge>      fixedEdges = cdt.FixedEdges; // the constraint edges

Auto-detect boundaries and holes

Use EraseOuterTrianglesAndHoles to automatically remove the outer region and fill holes. The algorithm uses an even–odd depth rule: depth 0 = outside, depth 1 = inside, depth 2 = hole, etc.

using CDT;

// Outer square (vertices 0-3) + inner square hole (vertices 4-7)
var vertices = new List<V2d<double>>
{
    new(0, 0), new(6, 0), new(6, 6), new(0, 6), // outer square
    new(2, 2), new(4, 2), new(4, 4), new(2, 4), // inner hole
};
var edges = new List<Edge>
{
    new(0, 1), new(1, 2), new(2, 3), new(3, 0), // outer boundary (CCW)
    new(4, 7), new(7, 6), new(6, 5), new(5, 4), // inner hole (CW — opposite winding)
};

var cdt = new Triangulation<double>();
cdt.InsertVertices(vertices);
cdt.InsertEdges(edges);
cdt.EraseOuterTrianglesAndHoles();

IReadOnlyList<Triangle> triangles = cdt.Triangles;

Conforming Delaunay triangulation

Use ConformToEdges instead of InsertEdges. The algorithm may split constraint edges and insert Steiner points (midpoints) until the constraint is represented in the triangulation.

using CDT;

var vertices = new List<V2d<double>>
{
    new(0, 0), new(4, 0), new(4, 4), new(0, 4),
};
var edges = new List<Edge>
{
    new(0, 1), new(1, 2), new(2, 3), new(3, 0),
};

var cdt = new Triangulation<double>();
cdt.InsertVertices(vertices);
cdt.ConformToEdges(edges); // may add Steiner points
cdt.EraseOuterTriangles();

Removing duplicate vertices and remapping edges

Input data often contains duplicate vertices (e.g., from shared polygon boundaries). Use CdtUtils.RemoveDuplicatesAndRemapEdges to clean up before triangulation.

using CDT;

var vertices = new List<V2d<double>>
{
    new(0, 0), new(4, 0), new(4, 4), new(0, 4),
    new(0, 0), // duplicate of vertex 0
};
var edges = new List<Edge>
{
    new(0, 4), // will be remapped since vertex 4 is a duplicate of vertex 0
    new(1, 2),
};

CdtUtils.RemoveDuplicatesAndRemapEdges(vertices, edges);
// vertices now has 4 entries; degenerate self-edges like (0,0) can be dropped

var cdt = new Triangulation<double>();
cdt.InsertVertices(vertices);
cdt.InsertEdges(edges.Where(e => e.V1 != e.V2).ToList());
cdt.EraseSuperTriangle();

Resolving intersecting constraint edges

By default, intersecting constraint edges throw an exception. Pass IntersectingConstraintEdges.TryResolve to split them at their intersection point instead.

using CDT;

// Two diagonals of a unit square that cross each other
var vertices = new List<V2d<double>>
{
    new(0, 0), new(1, 0), new(1, 1), new(0, 1),
};
var edges = new List<Edge>
{
    new(0, 2), // diagonal ↗
    new(1, 3), // diagonal ↖ — intersects (0,2)
};

var cdt = new Triangulation<double>(
    VertexInsertionOrder.Auto,
    IntersectingConstraintEdges.TryResolve,
    minDistToConstraintEdge: 0.0);

cdt.InsertVertices(vertices);
cdt.InsertEdges(edges); // intersection is resolved by inserting a new vertex
cdt.EraseSuperTriangle();

Building

dotnet build

Testing

dotnet run --project test/CDT.Tests

Benchmarking

dotnet run -c Release --project benchmark/CDT.Benchmarks

License

Mozilla Public License Version 2.0

This software is based in part on CDT — C++ library for constrained Delaunay triangulation: Copyright © 2019 Leica Geosystems Technology AB
Copyright © The CDT Contributors
Licensed under the MPL-2.0 license.

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • net10.0

    • No dependencies.
  • net8.0

    • No dependencies.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.0.0-beta2 26 2/24/2026
1.0.0-beta1 36 2/22/2026