GeomPP 0.7.0
See the version list below for details.
dotnet add package GeomPP --version 0.7.0
NuGet\Install-Package GeomPP -Version 0.7.0
<PackageReference Include="GeomPP" Version="0.7.0" />
<PackageVersion Include="GeomPP" Version="0.7.0" />
<PackageReference Include="GeomPP" />
paket add GeomPP --version 0.7.0
#r "nuget: GeomPP, 0.7.0"
#:package GeomPP@0.7.0
#addin nuget:?package=GeomPP&version=0.7.0
#tool nuget:?package=GeomPP&version=0.7.0
GeomPP — C# Bindings
C++/CLI bindings for geompp, targeting Windows x64.
Available on NuGet as GeomPP.
Supports .NET 8 (and later) and .NET Framework 4.8.
Changelog — full release notes for every version.
Install
dotnet add package GeomPP
or in your .csproj:
<PackageReference Include="GeomPP" Version="0.7.0" />
Quick start
Example 1 — LineSegment3D intersection
The code:
using G = GeomPP;
G.Precision.DecimalPrecision = G.Precision.DP_THREE;
var s1 = G.LineSegment3D.Make(new G.Point3D(1, 0, 0), new G.Point3D(-1, 0, 2));
var s2 = G.LineSegment3D.Make(new G.Point3D(0, 1, 0), new G.Point3D(0, -1, 2));
Console.WriteLine($"s1 = {s1}");
Console.WriteLine($"s2 = {s2}");
var result = s1.Intersection(s2);
if (result is G.Point3D p) {
Console.WriteLine("OK: " + p.ToWkt()); // expects POINT (0 0 1)
} else {
Console.WriteLine("FAIL: no intersection");
}
Output:
s1 = LINESTRING (1 0 0, -1 0 2)
s2 = LINESTRING (0 1 0, 0 -1 2)
intersection found: POINT (0 0 1)
intersection written to intersection.wkt
Example 2 — Load geometries from an .lsv file
An .lsv file is a plain-text list of WKT geometries, one per line:
POINT (1 2 3)
POINT (4 5 6)
LINESTRING (0 0 0, 1 1 1)
LINESTRING (2 0 0, 2 3 4)
LINE (0 0 0, 1 0 0)
RAY (0 0 0, 0 1 0)
using G = GeomPP;
G.Precision.DecimalPrecision = G.Precision.DP_THREE;
var parser = G.WktParser.Open("sample_geometries.lsv");
if (!parser.HasNext()) {
Console.WriteLine("no geometries found");
return;
}
while (parser.HasNext()) {
var item = parser.Next();
if (item == null) {
Console.WriteLine("skipped unrecognised line");
continue;
}
Console.WriteLine(G.WktParser.ToWkt(item));
}
Output:
POINT (1 2 3)
POINT (4 5 6)
LINESTRING (0 0 0, 1 1 1)
LINESTRING (2 0 0, 2 3 4)
LINE (0 0 0, 1 0 0)
RAY (0 0 0, 0 1 0)
Example 3 — are_coplanar, winding order, and polygon with holes
using GeomPP;
using Geompp.Extensions;
Precision.DecimalPrecision = Precision.DP_THREE;
var flat = new List<Point3D> {
new Point3D(0,0,0), new Point3D(1,0,0),
new Point3D(0,1,0), new Point3D(1,1,0)
};
var skew = new List<Point3D> {
new Point3D(0,0,0), new Point3D(1,0,0),
new Point3D(0,1,0), new Point3D(0,0,1)
};
Console.WriteLine(flat.AreCoplanar()); // True — all on the XY plane
Console.WriteLine(skew.AreCoplanar()); // False — spans 3D space
// Closest world-axis plane and winding check
var plane = flat.ClosestWorldPlaneTo();
Console.WriteLine(plane.Normal()); // (0, 0, 1) → XY plane
Console.WriteLine(flat.AreCCW()); // True — CCW on the XY plane
Console.WriteLine(flat.AreCW()); // False
// Polygon3D requires CCW outer ring and CW holes
var outer = new List<Point3D> {
new Point3D(0,0,0), new Point3D(4,0,0),
new Point3D(4,4,0), new Point3D(0,4,0)
};
var hole = new List<Point3D> {
new Point3D(1,3,0), new Point3D(3,3,0),
new Point3D(3,1,0), new Point3D(1,1,0)
};
var poly = Polygon3D.Make(outer, new List<List<Point3D>> { hole });
Console.WriteLine(poly.Size()); // 4
Output:
True
False
VECTOR (0 0 1)
True
False
4
Precision
All floating-point comparisons go through a thread-local precision setting:
G.Precision.DecimalPrecision = G.Precision.DP_THREE; // 3 decimal places (default)
G.Precision.DecimalPrecision = G.Precision.DP_SIX; // 6 decimal places
G.Precision.DecimalPrecision = G.Precision.DP_NINE; // 9 decimal places
double eps = G.Precision.Epsilon; // current epsilon (10^-N)
Supported types
| Type | 2D | 3D |
|---|---|---|
Point |
✓ | ✓ |
Vector |
✓ | ✓ |
Line |
✓ | ✓ |
Ray |
✓ | ✓ |
LineSegment |
✓ | ✓ |
Polyline |
✓ | ✓ |
Triangle |
✓ | ✓ |
Polygon |
✓ | ✓ |
BBox |
✓ | ✓ |
Plane |
— | ✓ |
GeometryCollection |
✓ | ✓ |
WktParser |
✓ | ✓ |
All types expose ToWkt(), FromWkt(), ToFile(), FromFile(), AlmostEquals(), and the same
operators available in the C++ library.
Intersection methods return object (null when there is no intersection); use C# pattern matching
to extract the result type:
var result = line.Intersection(segment);
if (result is G.Point2D p) { /* point intersection */ }
if (result is G.LineSegment2D s) { /* overlap */ }
Platform note
GeomPP is built with C++/CLI and is Windows x64 only. It will not run on Linux, macOS, or 32-bit processes.
Build on Windows x64 manually
If you want to built from this source files, use these commands
Build the C# DLL
# from the main directory, geompp
# if you want to build for .Net 8
msbuild geompp_csharp\GeomPP.vcxproj /p:Platform=x64 /p:GeomppBuildRoot="$PWD\build_win" [/p:Configuration=Release]
# if you want to build for .Net Framework 4.8
msbuild geompp_csharp\GeomPP_Net48.vcxproj /p:Platform=x64 /p:GeomppBuildRoot="$PWD\build_win" [/p:Configuration=Release]
# run smoke tests, after build from the main directory geompp
dotnet test geompp_csharp\tests\GeomPPTests.csproj [-p:GeomPPConfiguration=Release]
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0-windows7.0 is compatible. |
| .NET Framework | net48 is compatible. net481 was computed. |
-
.NETFramework 4.8
- No dependencies.
-
net10.0-windows7.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 |
|---|---|---|
| 0.17.3 | 98 | 8/15/2026 |
| 0.17.2 | 92 | 8/14/2026 |
| 0.16.2 | 87 | 8/6/2026 |
| 0.15.1 | 119 | 7/24/2026 |
| 0.14.0 | 104 | 7/21/2026 |
| 0.13.0 | 117 | 7/9/2026 |
| 0.12.0 | 103 | 7/8/2026 |
| 0.11.0 | 110 | 7/4/2026 |
| 0.10.1 | 124 | 6/23/2026 |
| 0.9.1 | 222 | 6/17/2026 |
| 0.8.2 | 117 | 5/18/2026 |
| 0.8.0 | 111 | 5/18/2026 |
| 0.7.0 | 104 | 5/6/2026 |
| 0.6.0 | 104 | 5/4/2026 |
| 0.5.0 | 103 | 5/1/2026 |
| 0.4.0 | 115 | 4/27/2026 |
| 0.1.2 | 124 | 4/13/2026 |
| 0.1.1 | 123 | 4/13/2026 |
| 0.1.0 | 125 | 4/9/2026 |
> C++ library — tagged `v0.7.0` · C# / NuGet — tagged `csharp-v0.7.0` · Python / PyPI — tagged `python-v0.7.0`
> Touches `Triangle2D`, `Triangle3D`, `Polygon2D`, `Polygon3D`.
### Added
**C++ core**
- `Triangle2D::Location(Point2D const&)` → `std::optional<std::tuple<double, double>>` — returns barycentric coordinates `(s, t)` where `P = P0 + s·(P1−P0) + t·(P2−P0)`, if the point is inside or on the boundary; `nullopt` if outside. Inverse of `Interpolate`. Implemented via 2D perpendicular dot products (`u.Perp()` / `v.Perp()`).
- `Triangle3D::Location(Point3D const&)` → `std::optional<std::tuple<double, double>>` — same semantics; returns `nullopt` also when the point is off the triangle's plane. Implemented via 3D cross-product isolating each barycentric coordinate without any 2D projection.
- `Polygon2D::IsOnBoundary(Point2D const&) const` — returns `true` if the point lies exactly on an edge (outer ring or any hole boundary); uses `LineSegment2D::Contains` per edge, which tolerates floating-point rounding up to `DECIMAL_PRECISION` digits.
- `Polygon3D::IsOnBoundary(Point3D const&) const` — same semantics; rejects off-plane points immediately, then projects to 2D and delegates to `Polygon2D::IsOnBoundary`.
**Python / PyPI**
- `Triangle2D.location(point)` → `tuple[float, float] | None` — Python binding for the new `Location` method.
- `Triangle3D.location(point)` → `tuple[float, float] | None` — Python binding for the new `Location` method.
- `Polygon2D.is_on_boundary(point)` → `bool` — Python binding for the new method.
- `Polygon3D.is_on_boundary(point)` → `bool` — Python binding for the new method.
**C# / NuGet**
- `Triangle2D.Location(Point2D^ point)` → `Tuple<double, double>^` (or `null` if outside) — C# binding for the new `Location` method.
- `Triangle3D.Location(Point3D^ point)` → `Tuple<double, double>^` (or `null` if off-plane or outside) — C# binding for the new `Location` method.
- `Polygon2D.IsOnBoundary(Point2D^ point)` → `bool` — C# binding for the new method.
- `Polygon3D.IsOnBoundary(Point3D^ point)` → `bool` — C# binding for the new method.
### Changed
**C++ core**
- `Triangle2D::Contains(Point2D const&)` — rewritten to delegate entirely to `Location(point).has_value()`. Behavior is unchanged; implementation is now consistent and symmetric with `Interpolate`.
- `Triangle3D::Contains(Point3D const&)` — was an unimplemented stub (`throw std::runtime_error("not implemented")`); now fully implemented. Rejects off-plane points via `BBox3D` and plane check, then delegates to `Location(point).has_value()`. No 2D projection is performed.
- `Polygon2D::Contains(Point2D const&)` — was an unimplemented stub; now implemented using a winding-number algorithm with boundary-inclusive semantics: calls `IsOnBoundary` first, then falls back to winding number for strictly interior points.
- `Polygon3D::Contains(Point3D const&)` — was an unimplemented stub; now implemented. Returns `false` immediately for off-plane points; projects to 2D and applies the winding-number algorithm for in-plane points.
### Fixed
**C++ core**
- `Polygon2D::Contains(Point2D const&)` — fixed inverted boundary logic: `IsOnBoundary` is called first and short-circuits to `true`; previously the order was reversed, causing interior points to return `false`.
- `Polygon2D::FromWkt` / `Polygon3D::FromWkt` — were throwing for valid WKT strings in C++ tests (leftover `EXPECT_ANY_THROW` from when the function was a stub); tests updated to expect successful parse and verify vertex count and first point.
- `Triangle3DTest::Contains_OnBoundary` — off-plane assertion changed from `z=0.001` to `z=0.01`; with `DECIMAL_PRECISION=3` the epsilon is exactly `0.001`, so the old value was within tolerance and the point was classified as on-plane.
### Tests
**C++ (`geompp_tests`)**
- `test_triangle2d.cpp`: `Location` test rewritten — `check_inside` / `check_outside` lambdas that assert `Location` value AND `Contains` status together; round-trip A (`Interpolate(Location(p)) == p`) and round-trip B (`Location(Interpolate(s,t)) == (s,t)`).
- `test_triangle3d.cpp`: `Location` test added — same `check_inside` / `check_outside` / round-trip structure; off-plane point asserts both `Location == nullopt` and `Contains == false`.
- `test_triangle3d.cpp`: `Contains_OnBoundary` — off-plane assertion fixed to `z=0.01`.
- `test_polygon2d.cpp`: `Contains` test completed — interior, near-corner, exterior, and polygon-with-hole cases. `Contains_OnBoundary` — vertices, edge midpoints, and hole boundary. `IsOnBoundary_True` / `IsOnBoundary_False` — explicit standalone tests. `Wkt` and `FromFile` updated to verify successful round-trip.
- `test_polygon3d.cpp`: same coverage as 2D plus off-plane and YZ-plane cases.
**Python (`geompp_python/tests`)**
- `TestTriangle2D.test_location`: rewritten with `check_inside`/`check_outside` helpers and both round-trips.
- `TestTriangle3D.test_location`: added — same structure, including off-plane case.
- `TestPolygon2D.test_contains`: completed — interior, near-corner, exterior, polygon-with-hole, and boundary cases.
- `TestPolygon3D.test_contains`: completed — same plus off-plane assertion.
- `TestPolygon2D.test_is_on_boundary`: vertices, edge midpoints, interior/exterior false cases, hole boundary true and false cases.
- `TestPolygon3D.test_is_on_boundary`: same in 3D plus off-plane false case.
**C# (`geompp_csharp/tests`)**
- `Triangle2D` — `Location_Vertices_ReturnExpectedCoords_2D`, `Location_Centroid_OneThirdEach_2D`, `Location_NullImpliesNotContained_2D`, `Location_RoundTrip_A_And_B_2D`: each asserts `Location` value AND paired `Contains` call; round-trips A and B included.
- `Triangle3D` — `Location_Vertices_ReturnExpectedCoords`, `Location_Centroid_OneThirdEach`, `Location_NullImpliesNotContained`, `Location_RoundTrip_A_And_B`: same relationship-focused structure.
- `Polygon2D` — `Contains_Interior_True`, `Contains_Exterior_False`, `Contains_WithHole`, `Contains_OnBoundary_True`, `IsOnBoundary_OnEdge_True`, `IsOnBoundary_Interior_False` added.
- `Polygon3D` — `Contains_Interior_True`, `Contains_OffPlane_False`, `Contains_WithHole`, `Contains_OnBoundary_True`, `IsOnBoundary_OnEdge_True`, `IsOnBoundary_Interior_False` added.
- `Triangle3D` — `Contains_Interior_True`, `Contains_OffPlane_False` added (delegating to `Location`).
---