C# binding for cavalier_contours, a high-performance 2D polyline/shape library for offsetting, combining, and more. 1
- High Performance: Built on the fast Rust cavalier_contours library 1
- Polyline Operations: Create, modify, and analyze 2D polylines with arc support
- Boolean Operations: Union (OR), Intersection (AND), Difference (NOT), and XOR operations
- Parallel Offsetting: Generate offset polylines with various join types
- Geometric Queries: Area calculation, path length, winding number, point-in-polygon tests
- Spatial Indexing: AABB (Axis-Aligned Bounding Box) indexing for fast spatial queries
- Memory Safe: Proper resource management with IDisposable pattern
- Cross-Platform: Supports Windows x64 (more platforms coming soon)
dotnet add package CavalierContoursSharpusing CavalierContoursSharp;
// Create an empty polyline
using var polyline = new Polyline();
// Add vertices
polyline.AddVertex(0, 0);
polyline.AddVertex(10, 0);
polyline.AddVertex(10, 10);
polyline.AddVertex(0, 10);
// Make it closed
polyline.IsClosed = true;
// Get properties
Console.WriteLine($"Area: {polyline.Area}");
Console.WriteLine($"Path Length: {polyline.PathLength}");
Console.WriteLine($"Vertex Count: {polyline.VertexCount}");// Create a polyline with arc segments using bulge values
var vertices = new[]
{
new CavcVertex(0, 0, 0), // Straight line to next vertex
new CavcVertex(10, 0, 0.5), // Arc to next vertex (bulge = 0.5)
new CavcVertex(10, 10, 0), // Straight line to next vertex
new CavcVertex(0, 10, 0) // Straight line back to start
};
using var polyline = new Polyline(vertices, true); // true = closed// Create two overlapping squares
using var square1 = new Polyline(new[]
{
new CavcVertex(0, 0),
new CavcVertex(10, 0),
new CavcVertex(10, 10),
new CavcVertex(0, 10)
}, true);
using var square2 = new Polyline(new[]
{
new CavcVertex(5, 5),
new CavcVertex(15, 5),
new CavcVertex(15, 15),
new CavcVertex(5, 15)
}, true);
// Perform boolean operations
var (union, _) = square1.BooleanOperation(square2, BooleanOp.Or);
var (intersection, _) = square1.BooleanOperation(square2, BooleanOp.And);
var (difference, _) = square1.BooleanOperation(square2, BooleanOp.Not);
var (xor, _) = square1.BooleanOperation(square2, BooleanOp.Xor);
// Remember to dispose results
union.Dispose();
intersection.Dispose();
difference.Dispose();
xor.Dispose();using var polyline = new Polyline(new[]
{
new CavcVertex(0, 0),
new CavcVertex(10, 0),
new CavcVertex(10, 10),
new CavcVertex(0, 10)
}, true);
// Create offset polylines
using var offsetResults = polyline.ParallelOffset(2.0); // Offset by 2 units
foreach (var offsetPolyline in offsetResults)
{
Console.WriteLine($"Offset polyline area: {offsetPolyline.Area}");
offsetPolyline.Dispose();
}using var polyline = new Polyline(new[]
{
new CavcVertex(0, 0),
new CavcVertex(10, 0),
new CavcVertex(10, 10),
new CavcVertex(0, 10)
}, true);
// Point-in-polygon test
int windingNumber = polyline.GetWindingNumber(5, 5); // Inside: winding number = 1
int windingNumber2 = polyline.GetWindingNumber(15, 15); // Outside: winding number = 0
// Get bounding box
if (polyline.GetExtents(out double minX, out double minY, out double maxX, out double maxY))
{
Console.WriteLine($"Bounds: ({minX}, {minY}) to ({maxX}, {maxY})");
}
// Transform operations
polyline.Scale(2.0); // Scale by factor of 2
polyline.Translate(5, 5); // Move by (5, 5)
polyline.InvertDirection(); // Reverse vertex orderusing var polyline = new Polyline();
// Add vertices one by one
polyline.AddVertex(0, 0, 0); // x, y, bulge
polyline.AddVertex(10, 0, 0.5); // Arc segment
polyline.AddVertex(10, 10, 0);
// Get and modify vertices
var vertex = polyline.GetVertex(1);
vertex.Bulge = 0.2; // Change arc curvature
polyline.SetVertex(1, vertex);
// Get all vertices
var allVertices = polyline.GetVertices();
// Iterate through vertices
foreach (var v in polyline)
{
Console.WriteLine($"Vertex: ({v.X}, {v.Y}), Bulge: {v.Bulge}");
}Bulge values define arc segments between vertices:
bulge = 0: Straight line segmentbulge > 0: Arc curves to the left (counter-clockwise)bulge < 0: Arc curves to the right (clockwise)bulge = 1: Perfect semicirclebulge = tan(θ/4)where θ is the arc's central angle
Polyline: Main class representing a 2D polyline with vertices and arcsCavcVertex: Structure representing a vertex with X, Y coordinates and bulge valuePolylineList: Collection of polylines returned by boolean operationsBooleanOp: Enumeration of boolean operation types (Or, And, Not, Xor)CavcAabbIndex: Spatial index for fast geometric queries
- Vertex Management:
AddVertex(),GetVertex(),SetVertex(),RemoveVertex() - Boolean Operations:
BooleanOperation() - Offsetting:
ParallelOffset() - Geometric Queries:
GetWindingNumber(),GetExtents(),Area,PathLength - Transformations:
Scale(),Translate(),InvertDirection() - Spatial Indexing:
CreateAabbIndex(),CreateApproximateAabbIndex()
- Always dispose of
PolylineandPolylineListobjects to free native memory - Use
usingstatements for automatic disposal - Boolean operations and offsetting can return multiple result polylines
- AABB indexing significantly speeds up spatial queries for complex polylines
- Windows x64: ✅ Fully supported
- Linux x64: 🚧 Coming soon
- macOS: 🚧 Coming soon
Contributions are welcome! Please feel free to submit issues and pull requests.
This project is licensed under the MIT License - see the LICENSE file for details.
- cavalier_contours - The original Rust library 1
- Interactive Web Demo - Try the library online 5