Sign in

    #@totto2727/geo/geo/2d

    totto2727/geo/geo/2d owns planar and geographic algorithms over the values in totto2727/geo/geo/2d/type, including measurements, topology, transforms, hulls, simplification, boolean operations, buffering, triangulation, and clustering.

    #Usage

    Measure a parcel boundary and calculate its centre for placing a label:

    ///|
    test "measure a parcel boundary" {
    let parcel = @type.Polygon::Polygon(
    @type.LineString::from_tuples([
    (0.0, 0.0),
    (10.0, 0.0),
    (10.0, 10.0),
    (0.0, 10.0),
    (0.0, 0.0),
    ]),
    [],
    )
    @test.assert_eq(HasArea::unsigned_area(parcel), 100.0)
    @test.assert_eq(
    HasCentroid::centroid(parcel),
    Some(@type.Point::from_tuple((5.0, 5.0))),
    )
    }

    #API

    This README was generated from the share-artifact skill and README template.

    Bounded

    pub(open) trait Bounded {
    fn bbox(Self) ->
    Rect
    ?
    }

    Anything that has a bounding rectangle. Geometries which can be empty return None.
    impl Bounded for Coord

    ClosestPoint

    pub(open) trait ClosestPoint {
    fn closest_point(Self,
    Coord
    ) -> Closest
    }

    Computes the closest point on self to a target coordinate.

    Contains

    pub(open) trait Contains {
    fn contains(Self,
    Geometry
    ) -> Bool
    }

    Predicate trait: self.contains(other) returns true when self spatially contains other (strictly interior per OGC Contains semantics — boundary points return false).

    CoordsCarrier

    pub(open) trait CoordsCarrier {
    fn coords(Self) -> Array[
    Coord
    ]
    }

    Anything that produces a sequence of Coords (lossless representation of all the geometry's coordinates, including interior rings).

    Covers

    pub(open) trait Covers {
    fn covers(Self,
    Geometry
    ) -> Bool
    }

    Predicate trait: self.covers(other) returns true when every point of other lies in self (interior or boundary).

    Densify

    pub(open) trait Densify {
    fn densify(Self, Double) -> Self
    }

    Densification with a maximum segment length. Returns a value of the same type with extra coords inserted along long segments.

    ExteriorCoordsCarrier

    pub(open) trait ExteriorCoordsCarrier {
    fn exterior_coords(Self) -> Array[
    Coord
    ]
    }

    Anything whose exterior coordinates can be enumerated. For shapes without interior rings this is identical to CoordsCarrier::coords; for Polygon / MultiPolygon / Geometry it excludes interior rings.

    HasArea

    pub(open) trait HasArea {
    fn signed_area(Self) -> Double
    fn unsigned_area(Self) -> Double
    }

    Anything that has a planar area (including signed area for orientation).
    impl HasArea for Geometry
    impl HasArea for Polygon
    impl HasArea for Rect
    impl HasArea for Triangle

    HasDimensions

    pub(open) trait HasDimensions {
    fn dimensions(Self) -> Dimensions
    }

    Anything whose dimensionality (Empty / 0D / 1D / 2D) can be computed.

    HasEuclideanLength

    pub(open) trait HasEuclideanLength {
    fn euclidean_length(Self) -> Double
    }

    Anything that has a planar Euclidean length (the physical "how long is this thing in coordinate units"): segment length, line string length, multi line string total length. Distinct from HasLength, which is the collection cardinality (how many components / coords).

    Intersects

    pub(open) trait Intersects {
    fn intersects(Self,
    Geometry
    ) -> Bool
    }

    Predicate trait: self.intersects(other) returns true when self and other share at least one point.

    MapCoords

    pub(open) trait MapCoords {
    fn map_coords(Self, (
    Coord
    ) ->
    Coord
    ) -> Self
    }

    Anything whose coordinates can be transformed pointwise by a function Coord -> Coord, returning a value of the same type.

    Orient

    pub(open) trait Orient {
    fn orient(Self, OrientDirection) -> Self
    }

    Predicate trait: self.orient(direction) returns a copy of self with rings re-oriented per the requested winding convention. Mirrors upstream geo::algorithm::orient::Orient.

    RemoveRepeatedPoints

    pub(open) trait RemoveRepeatedPoints {
    fn remove_repeated_points(Self) -> Self
    }

    Returns a copy of self with consecutive duplicate coordinates removed. Mirrors upstream geo::algorithm::remove_repeated_points::RemoveRepeatedPoints.

    Simplify

    pub(open) trait Simplify {
    fn simplify(Self, Double) -> Self
    }

    RDP simplification with epsilon. Returns a value of the same type with near-collinear coords removed.

    Within

    pub(open) trait Within {
    fn within(Self,
    Geometry
    ) -> Bool
    }

    Predicate trait: self.within(other) is equivalent to other.contains(self).

    AffineRow

    pub struct AffineRow {
    scale : Double
    skew : Double
    translate : Double
    } derive(Eq,
    Debug
    )

    One row of the affine matrix: output = scale * own_axis + skew * other_axis + translate.

    AffineRow::AffineRow

    fn AffineRow::AffineRow(scale : Double, skew : Double, translate : Double) -> AffineRow

    Canonical constructor for AffineRow.

    AffineTransform

    pub struct AffineTransform {
    row_x : AffineRow
    row_y : AffineRow
    } derive(Eq,
    Debug
    )

    2D affine transformation: a pair of rows of the underlying 3×3 row-major matrix. The implicit third row is [0, 0, 1].

    AffineTransform::AffineTransform

    fn AffineTransform::AffineTransform(row_x : AffineRow, row_y : AffineRow) -> AffineTransform

    Canonical constructor for AffineTransform.

    AffineTransform::apply

    Apply this transform to a coordinate.

    AffineTransform::compose

    Compose two affine transforms: applying self.compose(other) to a coord is equivalent to first applying self, then other. In matrix terms the result is other * self.

    AffineTransform::compose_many

    fn AffineTransform::compose_many(self : AffineTransform, transforms : Array[AffineTransform]) -> AffineTransform

    Post-compose a sequence of transforms: self ∘ transforms[0] ∘ … ∘ transforms[n-1]. Equivalent to transforms.fold(identity, compose).

    AffineTransform::identity

    The identity affine transform: (x, y) -> (x, y).

    AffineTransform::inverse

    Returns the inverse transform if det != 0.0, otherwise None.

    Matrix:
    [[a, b, xoff], inverse: [[ e/det, -b/det, (b*yoff - e*xoff)/det], [d, e, yoff], [-d/det, a/det, (d*xoff - a*yoff)/det], [0, 0, 1]] [ 0, 0, 1 ]]

    AffineTransform::is_identity

    fn AffineTransform::is_identity(self : AffineTransform) -> Bool

    Returns whether this transform is exactly the identity matrix (all fields compare equal to the identity values).

    AffineTransform::rotate_around

    fn AffineTransform::rotate_around(degrees : Double, origin :
    Coord
    ) -> AffineTransform

    A pure rotation by degrees (CCW positive) about origin.

    AffineTransform::rotate_origin

    fn AffineTransform::rotate_origin(degrees : Double) -> AffineTransform

    A rotation around the origin by degrees (CCW positive).

    Upstream Rust matrix is [[cos, -sin, 0], [sin, cos, 0], [0,0,1]]:
    • row x: a=cos, b=-sin → scale=cos, skew=-sin
    • row y: d=sin, e=cos → skew=sin, scale=cos

    AffineTransform::rotated

    Returns a copy of self post-composed with a rotation about origin.

    AffineTransform::scale_around

    fn AffineTransform::scale_around(xfact : Double, yfact : Double, origin :
    Coord
    ) -> AffineTransform

    A pure scaling by (xfact, yfact) about origin.

    AffineTransform::scale_xy

    fn AffineTransform::scale_xy(xfact : Double, yfact : Double) -> AffineTransform

    A pure (axis-aligned) scaling by (xfact, yfact).

    AffineTransform::scaled

    fn AffineTransform::scaled(self : AffineTransform, xfact : Double, yfact : Double, origin :
    Coord
    ) -> AffineTransform

    Returns a copy of self post-composed with a scale about origin.

    AffineTransform::skew_around

    fn AffineTransform::skew_around(xs_degrees : Double, ys_degrees : Double, origin :
    Coord
    ) -> AffineTransform

    Skew (shear) by xs_degrees and ys_degrees about origin.

    AffineTransform::skew_origin

    fn AffineTransform::skew_origin(xs_degrees : Double, ys_degrees : Double) -> AffineTransform

    Skew (shear) around the origin by xs_degrees and ys_degrees.

    Upstream Rust matrix is [[1, tan(xs), 0], [tan(ys), 1, 0], [0,0,1]]:
    • row x: a=1, b=tan(xs) → scale=1, skew=tan(xs)
    • row y: d=tan(ys), e=1 → skew=tan(ys), scale=1

    AffineTransform::skewed

    fn AffineTransform::skewed(self : AffineTransform, xs : Double, ys : Double, origin :
    Coord
    ) -> AffineTransform

    Returns a copy of self post-composed with a skew about origin.

    AffineTransform::transform

    fn[T : MapCoords] AffineTransform::transform(self : AffineTransform, x : T) -> T

    Apply this transform to any value that supports per-coordinate mapping (MapCoords). Works on every concrete geometry (Point, Polygon, …) as well as the dispatch-on-enum Geometry.

    AffineTransform::translate_xy

    fn AffineTransform::translate_xy(xoff : Double, yoff : Double) -> AffineTransform

    A pure translation by (xoff, yoff).

    AffineTransform::translated

    fn AffineTransform::translated(self : AffineTransform, xoff : Double, yoff : Double) -> AffineTransform

    Returns a copy of self post-composed with a translation (xoff, yoff).

    BufferEndCap

    pub(all) enum BufferEndCap {
    Round
    Square
    Flat
    } derive(Eq,
    Debug
    )

    End-cap style for line buffering.

    BufferJoin

    pub(all) enum BufferJoin {
    Round
    Miter
    Bevel
    } derive(Eq,
    Debug
    )

    Join style for corners.

    BufferOptions

    pub(all) struct BufferOptions {
    end_cap : BufferEndCap
    join : BufferJoin
    miter_limit : Double
    arc_segments : Int
    } derive(Eq,
    Debug
    )

    Buffer/offset configuration.

    BufferOptions::default

    fn BufferOptions::default() -> BufferOptions

    Default options: Round end caps, Round joins, miter limit 4.0, 8 segments per quarter arc.

    Closest

    pub(all) enum Closest {
    Intersection(
    Coord
    )
    SinglePoint(
    Coord
    )
    Indeterminate
    } derive(Eq,
    Debug
    )

    Result of querying the closest point on a geometry.

    CoordIndex

    pub(all) struct CoordIndex(Int) derive(Eq,
    Debug
    )

    Identifies which coordinate within a linear geometry produced a validation problem. 0-indexed.

    CoordPos

    pub(all) enum CoordPos {
    OnBoundary
    Inside
    Outside
    } derive(Eq,
    Debug
    )

    The position of a Coord relative to a geometry.

    DelaunayTriangle

    pub struct DelaunayTriangle {
    a : Int
    b : Int
    c : Int
    } derive(Eq,
    Debug
    )

    One triangle in the triangulation, identified by indices into the original points array passed to delaunay_triangulation.

    Dimensions

    pub(all) enum Dimensions {
    Empty
    ZeroDimensional
    OneDimensional
    TwoDimensional
    } derive(Eq,
    Debug
    )

    Geometries can have 0, 1, or 2 dimensions, plus a special Empty dimensionality (for empty collections / linestrings).

    Dimensions::rank

    fn Dimensions::rank(self : Dimensions) -> Int

    Compares dimensions in the natural ordering Empty < ZeroDimensional < OneDimensional < TwoDimensional. Returns the integer rank.

    GeometryIndex

    pub(all) struct GeometryIndex(Int) derive(Eq,
    Debug
    )

    Identifies which sub-geometry within a Multi* or GeometryCollection produced a validation problem. 0-indexed.

    HaversineMeasure

    pub(all) struct HaversineMeasure {
    radius : Double
    } derive(Eq)

    A sphere parameterised by its radius (typically in meters). The standard Earth radius is grs80_mean_radius (6371008.8 m, IUGG recommendation).

    HaversineMeasure::bearing

    Great-circle bearing from origin to destination.

    Units

    • origin, destination: Points where x=longitude, y=latitude in degrees
    • returns: degrees (North=0°, East=90°, South=180°, West=270°)

    test "haversine_bearing - east is 90" { let origin = @type.Point::from_tuple((0.0, 0.0)) let dest = @type.Point::from_tuple((1.0, 0.0)) let m = haversine() let b = m.bearing(origin, dest) assert_true((b - 90.0).abs() < 1.0e-6) }

    HaversineMeasure::destination

    fn HaversineMeasure::destination(self : HaversineMeasure, origin :
    Point
    , bearing : Double, distance : Double) ->
    Point

    Destination point after travelling distance meters from origin along bearing degrees (North=0°, East=90°).

    Units

    • origin: Point where x=longitude, y=latitude in degrees
    • bearing: degrees
    • distance: meters
    • returns: Point where x=longitude, y=latitude in degrees

    test "haversine_destination - north 100km from equator" { let origin = @type.Point::from_tuple((0.0, 0.0)) let m = haversine() let dest = m.destination(origin, 0.0, 100_000.0) assert_true((dest.y() - 0.899320363724538).abs() < 1.0e-10) }

    HaversineMeasure::distance

    The haversine distance between two points on a sphere.

    Units

    • origin, destination: Points where x=longitude, y=latitude in degrees
    • returns: meters (same unit as the sphere radius)

    test "haversine_distance - New York to London" { let nyc = @type.Point::from_tuple((-74.006, 40.7128)) let london = @type.Point::from_tuple((-0.1278, 51.5074)) let m = haversine() let d = m.distance(nyc, london) assert_true((d - 5_570_230.0).abs() < 10.0) }

    HaversineMeasure::new

    fn HaversineMeasure::new(radius : Double) -> HaversineMeasure

    HaversineMeasure::radius

    fn HaversineMeasure::radius(self : HaversineMeasure) -> Double

    IntersectionMatrix

    pub struct IntersectionMatrix {
    cells : Array[Dimensions]
    }

    The 9-element DE-9IM intersection matrix. Cells are stored row-major in the order [II, IB, IE, BI, BB, BE, EI, EB, EE] where row = position-in-A and col = position-in-B (I = Interior, B = Boundary, E = Exterior). Each cell records the dimensionality of the intersection of the two corresponding regions.

    IntersectionMatrix::empty

    Construct a matrix with all cells set to Empty.

    IntersectionMatrix::get

    Read the cell at (row, col) where row indexes A's position (Interior / Boundary / Exterior) and col indexes B's position.

    IntersectionMatrix::is_contains

    fn IntersectionMatrix::is_contains(self : IntersectionMatrix) -> Bool

    a.contains(b) per OGC: matches DE-9IM [T*****FF*]. Strict interior inclusion — a point on a's boundary does not count.

    IntersectionMatrix::is_covered_by

    fn IntersectionMatrix::is_covered_by(self : IntersectionMatrix) -> Bool

    a.is_covered_by(b): the transpose of is_covers. Matches one of [T*F**F***], [*TF**F***], [**FT*F***], [**F*TF***].

    IntersectionMatrix::is_covers

    fn IntersectionMatrix::is_covers(self : IntersectionMatrix) -> Bool

    a.covers(b): every point of b lies in a (interior or boundary). Matches one of [T*****FF*], [*T****FF*], [***T**FF*], [****T*FF*].

    IntersectionMatrix::is_crosses

    fn IntersectionMatrix::is_crosses(self : IntersectionMatrix) -> Bool

    a.crosses(b): their intersection is non-empty but smaller- dimensional than the maximum of the two operands. Two polygons cannot cross. Two lines cross iff their intersection is a single point.

    IntersectionMatrix::is_disjoint

    fn IntersectionMatrix::is_disjoint(self : IntersectionMatrix) -> Bool

    Two geometries are disjoint iff none of II, IB, BI, BB records any intersection. Matches DE-9IM [FF*FF****].

    IntersectionMatrix::is_equals

    fn IntersectionMatrix::is_equals(self : IntersectionMatrix) -> Bool

    a.equals(b) topologically: matches DE-9IM [T*F**FFF*]. Both geometries occupy exactly the same point set.

    IntersectionMatrix::is_intersects

    fn IntersectionMatrix::is_intersects(self : IntersectionMatrix) -> Bool

    is_intersects is the negation of is_disjoint.

    IntersectionMatrix::is_overlaps

    fn IntersectionMatrix::is_overlaps(self : IntersectionMatrix) -> Bool

    a.overlaps(b): same dimension, interiors overlap, neither covers the other. Matches [1*T***T**] (line / line) or [T*T***T**] (point / point or polygon / polygon).

    IntersectionMatrix::is_touches

    fn IntersectionMatrix::is_touches(self : IntersectionMatrix) -> Bool

    a.touches(b): at least one point in common, but interiors do not intersect. Matches [FT*******], [F**T*****], or [F***T****].

    IntersectionMatrix::is_within

    fn IntersectionMatrix::is_within(self : IntersectionMatrix) -> Bool

    a.within(b) per OGC: matches DE-9IM [T*F**F***]. The transpose of is_contains.

    LineIntersection

    pub(all) enum LineIntersection {
    SinglePoint(
    Coord
    , Bool)
    Collinear(
    Line
    )
    } derive(Eq,
    Debug
    )

    The result of intersecting two line segments.

    OrientDirection

    pub(all) enum OrientDirection {
    Default
    Reversed
    } derive(Eq,
    Debug
    )

    The convention for ring orientation in a Polygon.

    Orientation

    pub(all) enum Orientation {
    CounterClockwise
    Clockwise
    Collinear
    } derive(Eq,
    Debug
    )

    Orientation of three coordinates p, q, r in the plane.

    Outcome

    Indices and coordinates of the extreme points of a geometry along the four cardinal directions.

    RhumbMeasure

    pub(all) struct RhumbMeasure {
    radius : Double
    } derive(Eq)

    A sphere parameterised by its radius for rhumb-line calculations.

    RhumbMeasure::bearing

    Returns the rhumb-line bearing (constant azimuth) from origin to destination.

    Units

    • origin, destination: Points where x=longitude, y=latitude
    • returns: degrees (North=0°, East=90°)

    RhumbMeasure::destination

    fn RhumbMeasure::destination(self : RhumbMeasure, origin :
    Point
    , bearing : Double, distance : Double) ->
    Point

    Destination point after travelling distance meters from origin along a constant bearing (rhumb line).

    Units

    • origin: Point where x=longitude, y=latitude in degrees
    • bearing: degrees (North=0°, East=90°)
    • distance: meters
    • returns: Point where x=longitude, y=latitude

    RhumbMeasure::distance

    Rhumb-line (loxodrome) distance between two points on a sphere.

    Units

    • origin, destination: Points where x=longitude, y=latitude in degrees
    • returns: meters

    test "rhumb_distance - NY to London longer than great-circle" { let nyc = @type.Point::from_tuple((-74.006, 40.7128)) let london = @type.Point::from_tuple((-0.1278, 51.5074)) let d = rhumb().distance(nyc, london) assert_true(d > 5_790_000.0 && d < 5_800_000.0) }

    RhumbMeasure::new

    fn RhumbMeasure::new(radius : Double) -> RhumbMeasure

    RingRole

    pub(all) enum RingRole {
    Exterior
    Interior(Int)
    } derive(Eq,
    Debug
    )

    Identifies which ring within a Polygon produced a validation problem.

    ValidationProblem

    pub(all) enum ValidationProblem {
    TooFewPoints
    RingNotClosed(RingRole)
    RingTooFewPoints(RingRole)
    SelfIntersection(RingRole)
    NonFiniteCoord(RingRole, CoordIndex)
    NonFiniteLineStringCoord(CoordIndex)
    NonFinitePointCoord
    NonFiniteRectCoord(CoordIndex)
    LineIdenticalCoords
    LineNonFiniteCoord(CoordIndex)
    TriangleNonFiniteCoord(CoordIndex)
    TriangleIdenticalCoords(CoordIndex, CoordIndex)
    TriangleCollinearCoords
    MultiGeometryProblem(GeometryIndex, ValidationProblem)
    InteriorRingNotContained(RingRole)
    IntersectingRingsOnLine(RingRole, RingRole)
    IntersectingRingsOnArea(RingRole, RingRole)
    ElementsOverlap(GeometryIndex, GeometryIndex)
    ElementsTouchOnLine(GeometryIndex, GeometryIndex)
    } derive(Eq,
    Debug
    )

    A specific validation issue detected on a geometry.

    Variants that report ring-level problems carry a RingRole to identify whether the problem occurred on the exterior ring or a specific interior ring. Variants that report coordinate-level problems carry a CoordIndex. Multi-geometry variants wrap child problems with a GeometryIndex.

    Checks deferred to later milestones

    The following upstream checks depend on DE-9IM relate (ms-20) and/or PreparedGeometry caching (ms-18) and are deferred:
    • InteriorRingNotContainedInExteriorRing
    • IntersectingRingsOnALine / IntersectingRingsOnAnArea
    • MultiPolygon ElementsOverlaps / ElementsTouchOnALine

    Their variant slots are reserved but they are not yet produced.

    VoronoiEdge

    One edge of a Voronoi diagram. For an interior edge both endpoints are circumcenters of adjacent Delaunay triangles; for a boundary edge that would extend to infinity, the unbounded endpoint is replaced by the projection onto the supplied bbox.

    WindingOrder

    pub(all) enum WindingOrder {
    Clockwise
    CounterClockwise
    } derive(Eq,
    Debug
    )

    The winding order of a LineString ring.

    TOLERANCE

    let TOLERANCE : Double

    Default tolerance for approximate Euclidean comparisons.

    Sized to absorb the cumulative round-off of a few floating-point operations (trigonometric / affine transforms / dot products) — about seven orders of magnitude looser than the machine epsilon @robust.EPSILON ≈ 1.11e-16. Use this when comparing coordinates that are mathematically equal but went through several float operations; for exact-equality checks compare with @test.assert_eq (or ==) directly.

    buffer_line_string

    Buffer a LineString: produces a MultiPolygon of all points within distance of the line. Self-intersecting lines are unioned into their multi-polygon components.

    test "buffer_line_string - flat caps rectangle" { let ls = @type.LineString::from_tuples([(0.0, 0.0), (1.0, 0.0)]) let opts = BufferOptions::{ end_cap: Flat, join: Round, miter_limit: 4.0, arc_segments: 8 } let mp = buffer_line_string(ls, 0.1, opts) assert_true(mp.polygons().length() > 0) }

    buffer_point

    Buffer a Point: produces a Polygon approximating a circle of radius distance around the point.

    test "buffer_point - radius 1 yields circle" { let p = @type.Point::from_tuple((0.0, 0.0)) let opts = BufferOptions::default() let poly = buffer_point(p, 1.0, opts) // exterior should have 4 * arc_segments + 1 = 33 coords assert_true(poly.exterior().coords().length() == 33) // vertices should be approximately 1.0 from center (discounting closing coord) let cs = poly.exterior().coords() for i = 0; i < cs.length() - 1; i = i + 1 { let d = @math.sqrt((cs[i].x() - 0.0)*(cs[i].x() - 0.0) + (cs[i].y() - 0.0)*(cs[i].y() - 0.0)) assert_true((d - 1.0).abs() < 0.01) } }

    buffer_polygon

    Buffer a Polygon: positive distance = outward expansion; negative = inward shrinkage.

    test "buffer_polygon - positive distance enlarges square" { let sq = @type.Polygon::Polygon( @type.LineString::from_tuples([(0.0, 0.0), (1.0, 0.0), (1.0, 1.0), (0.0, 1.0), (0.0, 0.0)]), [], ) let opts = BufferOptions::default() let result = buffer_polygon(sq, 0.1, opts) assert_true(result.polygons().length() > 0) }

    chaikin_smoothing

    Performs one iteration of Chaikin smoothing: each segment (p_i, p_{i+1}) becomes two new coords at 1/4 and 3/4 along the segment. Repeated for n_iterations rounds. The first and last coords are preserved for open linestrings; closed linestrings smooth uniformly.

    chamberlain_duquette_signed_area_geometry

    fn chamberlain_duquette_signed_area_geometry(g :
    Geometry
    ) -> Double

    Signed Chamberlain-Duquette spherical area of a Geometry. Per upstream: non-area geometries (Point/Line/LineString/MultiPoint/MultiLineString) return 0. Rect and Triangle delegate to their to_polygon(). GeometryCollection sums per-component signed areas.

    chamberlain_duquette_unsigned_area_geometry

    fn chamberlain_duquette_unsigned_area_geometry(g :
    Geometry
    ) -> Double

    Unsigned (absolute) Chamberlain-Duquette spherical area of a Geometry (meters²).

    test "chamberlain_duquette_unsigned_area_geometry - square" { let ring = @type.LineString::from_tuples([ (0.0, 0.0), (1.0, 0.0), (1.0, 1.0), (0.0, 1.0), (0.0, 0.0), ]) let geometry = @type.Geometry::Polygon(@type.Polygon::Polygon(ring, [])) let area = chamberlain_duquette_unsigned_area_geometry(geometry) assert_true(area > 1.0e10) }

    clip_line_string

    Clips a LineString against a Polygon. Returns a MultiLineString containing the segments that lie inside the polygon. Adjacent sub-segments that share a coordinate are joined into a single LineString.

    contains_geometry

    Generic Geometry-based contains. Currently dispatches the common pairs.

    coord_on_line

    Returns whether coord lies on the segment line (including endpoints).

    coords_count

    Returns the count of coordinates in the geometry (the length of the array returned by coords_of_geometry).

    covers_geometry

    Generic geometry-based covers.

    cross_track_distance

    Cross-track distance from p to the great circle through line_point_a and line_point_b. Uses the same mean-Earth radius as Haversine() (GRS80 mean radius, 6_371_008.8 m). Result is in meters.

    test "cross_track_distance - one degree off the equator" { let p = @type.Point::from_tuple((1.0, 1.0)) let a = @type.Point::from_tuple((0.0, 0.0)) let b = @type.Point::from_tuple((2.0, 0.0)) let distance = cross_track_distance(p, a, b) assert_true(distance > 100_000.0 && distance < 120_000.0) }

    dbscan

    fn dbscan(points : Array[
    Point
    ], eps : Double, min_pts : Int) -> Array[Int]

    DBSCAN cluster labels for each input point.

    eps is the neighbourhood radius (Euclidean, not squared) and min_pts is the minimum number of points (including the point itself) required for a point to qualify as a core point. Returns labels where 0 denotes noise and 1, 2, … denote cluster IDs in the order clusters are discovered.

    Edge cases mirror georust/geo:
    • Empty input → empty result.
    • min_pts <= 0 or min_pts > points.length() → every label is 0.
    • With min_pts == 1, every point seeds its own cluster (no noise).
    • With eps == 0 and distinct coordinates, every label is 0 — each neighbourhood holds only the point itself, which is < 2.

    dbscan_outliers

    fn dbscan_outliers(points : Array[
    Point
    ], eps : Double, min_pts : Int) -> Array[Int]

    Returns the indices of points classified as noise (label 0) by dbscan. Equivalent to running dbscan and collecting every index whose label is 0.

    delaunay_concave_hull

    fn delaunay_concave_hull(points : Array[
    Coord
    ], concavity : Double) ->
    LineString
    ?

    Compute the concave hull of a point set by trimming long edges from the Delaunay triangulation. concavity is the trim multiplier: triangulation edges longer than concavity * mean_edge_length are removed and the boundary of the surviving triangle set is returned. concavity = +inf keeps every triangle (= convex hull); smaller values follow the input more closely. Values <= 0 cause every triangle to be removed and return None.

    Returns a closed LineString (first == last) or None when the underlying Delaunay triangulation is empty (fewer than 3 points or all collinear), every triangle is trimmed, or the boundary walker fails to assemble a single ring.

    delaunay_triangles_to_geometries

    Convert a DelaunayTriangle index list back into actual Triangle geometries by indexing into the original points array.

    delaunay_triangulation

    fn delaunay_triangulation(points : Array[
    Coord
    ]) -> Array[DelaunayTriangle]?

    Compute the Delaunay triangulation of a set of 2D points using the Bowyer-Watson incremental algorithm.

    Returns Some(triangles) where each triangle is given as a triple of indices into points, in CCW order. Returns None when the triangulation is empty: fewer than 3 input points, all points coincident, or all points collinear.

    densify_haversine_line

    fn densify_haversine_line(line :
    Line
    , max_segment_length : Double) ->
    LineString

    Densifies a Line along a haversine path. Returns a LineString starting from line.start(), ending at line.end(), with intermediate great-circle points inserted as needed.

    test "densify_haversine_line - inserts intermediate points" { let line = @type.Line::from_tuples((0.0, 0.0), (1.0, 0.0)) let result = densify_haversine_line(line, 50_000.0) assert_true(result.coords().length() >= 3) }

    densify_haversine_line_string

    fn densify_haversine_line_string(ls :
    LineString
    , max_segment_length : Double) ->
    LineString

    Densifies a LineString along haversine paths. Empty input returns LineString::empty(). Single-coord input returns the input unchanged.

    densify_haversine_multi_line_string

    fn densify_haversine_multi_line_string(mls :
    MultiLineString
    , max_segment_length : Double) ->
    MultiLineString

    Densifies all line strings of a MultiLineString along haversine paths.

    densify_haversine_multi_polygon

    fn densify_haversine_multi_polygon(mp :
    MultiPolygon
    , max_segment_length : Double) ->
    MultiPolygon

    Densifies all polygons of a MultiPolygon along haversine paths.

    densify_haversine_polygon

    fn densify_haversine_polygon(polygon :
    Polygon
    , max_segment_length : Double) ->
    Polygon

    Densifies all rings of a Polygon along haversine paths.

    dimensions_less

    fn dimensions_less(a : Dimensions, b : Dimensions) -> Bool

    Returns whether a has strictly less dimensionality than b.

    dot_product

    Inner / dot product: a · b = a.x * b.x + a.y * b.y.

    earcut

    fn earcut(vertices : Array[Double], hole_indices : Array[Int], dims : Int) -> Array[Int]?

    Triangulate a 2D polygon (with optional holes) using the Mapbox earcut algorithm. vertices is a flat array [x0, y0, x1, y1, …]. Each entry of hole_indices is a vertex index (not coordinate index) where a hole ring begins. dims should be 2 (other values short-circuit to an empty result, matching the upstream).

    Returns Some(indices) where every 3 consecutive ints form one triangle (each int is a vertex index), or None for malformed input such as an odd-length vertices array.

    euclidean_bearing

    fn euclidean_bearing(origin :
    Coord
    , destination :
    Coord
    ) -> Double

    Bearing in degrees from origin to destination in a planar Euclidean frame. 0 is east (positive x); angle increases counter-clockwise. Returns NaN if origin == destination.

    euclidean_destination

    fn euclidean_destination(origin :
    Coord
    , bearing_degrees : Double, distance : Double) ->
    Coord

    Returns the destination coordinate when starting at origin, heading at bearing degrees (0 = east, CCW), and travelling distance units in a planar Euclidean frame.

    euclidean_distance_coord_to_line

    fn euclidean_distance_coord_to_line(p :
    Coord
    , l :
    Line
    ) -> Double

    Euclidean distance from a coordinate to a line segment, clamped to the segment's bounds.

    euclidean_distance_coord_to_line_string

    fn euclidean_distance_coord_to_line_string(p :
    Coord
    , ls :
    LineString
    ) -> Double

    Euclidean distance from a coordinate to a LineString. Returns Double::infinity() if the line string has fewer than 2 coordinates.

    euclidean_distance_coords

    fn euclidean_distance_coords(a :
    Coord
    , b :
    Coord
    ) -> Double

    Euclidean distance between two coordinates.

    euclidean_distance_point_to_line

    fn euclidean_distance_point_to_line(p :
    Point
    , l :
    Line
    ) -> Double

    Euclidean distance from a point to a line segment.

    euclidean_distance_points

    fn euclidean_distance_points(a :
    Point
    , b :
    Point
    ) -> Double

    Euclidean distance between two points.

    euclidean_distance_squared_coords

    fn euclidean_distance_squared_coords(a :
    Coord
    , b :
    Coord
    ) -> Double

    Squared Euclidean distance between two coordinates (skips the sqrt).

    extremes_of_coords

    fn extremes_of_coords(coords : Array[
    Coord
    ]) -> Outcome?

    Returns the extremes (xmin, xmax, ymin, ymax) of a coordinate array. Returns None for an empty array.

    frechet_distance

    Discrete Fréchet distance between two LineStrings. Returns 0 for two empty linestrings; returns infinity if exactly one is empty.

    has_segment_intersection

    fn has_segment_intersection(segments : Array[
    Line
    ]) -> Bool

    Returns true iff any segment in the input intersects another. Short circuits on the first detected intersection (any flavour: single point or collinear overlap).

    hausdorff_distance_coords

    Hausdorff distance between two arrays of coordinates: the maximum, in either direction, of the distance from any coord in one set to its nearest in the other.

    hausdorff_distance_geometry

    Hausdorff distance between two geometries via their full coord arrays.

    haversine

    fn haversine() -> HaversineMeasure

    Standard Earth mean radius (GRS80 R₁ = 6,371,008.8 m).

    haversine_length

    fn haversine_length(ls :
    LineString
    ) -> Double

    Great-circle (spherical) length of a line string. Sums the haversine distances between consecutive coordinate pairs.

    test "haversine_length - 1 degree at equator ~111km" { let ls = @type.LineString::from_tuples([(0.0, 0.0), (1.0, 0.0)]) let len = haversine_length(ls) assert_true((len - 111_319.49).abs() < 1.0) }

    indexed_contains_polygons

    fn indexed_contains_polygons(polygons : Array[
    Polygon
    ]) -> ((
    Coord
    ) -> Bool)

    Pre-indexed contains predicate over a fixed set of polygons.

    The R*-tree is built over the polygons' bounding rectangles. A query coordinate is first narrowed to the candidate polygons whose bbox covers it (locate_at_point), then verified against the precise contains_polygon_coord test. Boundary coords return false per OGC Contains semantics, mirroring the underlying predicate.

    Polygons whose bounding rect is None (empty polygons) are skipped at build time and never participate in queries.

    indexed_intersecting_polygons

    fn indexed_intersecting_polygons(polygons : Array[
    Polygon
    ]) -> ((
    Polygon
    ) -> Array[Int])

    Pre-indexed pairwise polygon-intersection lookup.

    The R*-tree is built over the input polygons' bounding rectangles. Given a query polygon, the closure narrows to candidates whose bbox intersects the query bbox (query_rect_intersection), then keeps only the indices that pass intersects_polygon_polygon. The result is in the rtree's traversal order (no insertion-order guarantee).

    Polygons whose bounding rect is None (empty polygons, both indexed and query-side) never appear in the result. An empty input array produces a closure that always returns [].

    indexed_nearest_point

    Pre-indexed nearest-neighbor lookup over a fixed set of points.

    The R*-tree is built over degenerate point rects (min == max ==p.coord()), so the tree's own query_nearest already returns the correct answer without an extra precise pass. Empty input → closure returns None for every query.

    intersection_polygon_rect

    Deprecated: use polygon_intersection after converting the rect to a polygon. Preserved for backward compatibility.

    intersection_sutherland_hodgman

    Deprecated: use polygon_intersection. Preserved as a thin wrapper that returns the first (and usually only) polygon in the result, or an empty polygon if the result is empty. The previous Sutherland-Hodgman implementation imposed a "convex clip" precondition; this wrapper now supports general polygons via Greiner-Hörmann.

    intersects_geometry

    Returns whether two Geometry values intersect. Currently dispatches the most common pairs through the per-type functions above; uncommon pairs (e.g. GeometryCollection vs GeometryCollection) recurse.

    is_convex

    Returns Some(true) if the linestring is convex, Some(false) if not, and None if the linestring has too few coords or is degenerate.

    strict = true requires the strict variant: no three consecutive coords may be collinear. The default is_convex uses strict = false.

    is_finite

    fn is_finite(c :
    Coord
    ) -> Bool

    Returns whether both x and y are finite (not NaN, not infinity).

    is_strictly_convex

    fn is_strictly_convex(ls :
    LineString
    ) -> Bool

    is_valid

    Returns whether g has no validation problems.

    k_nearest_concave_hull

    Compute the concave hull of a point set using the k-nearest-neighbour algorithm of Moreira & Santos (2007).

    k controls concavity: larger values approach the convex hull, smaller values follow the input more closely. Values below 3 are clamped to 3 (the minimum that admits a non-degenerate boundary walk). When the algorithm cannot complete with a given k it retries with max(k + 1, ceil(k * 1.5)); once k >= n the convex hull is returned as a fallback.

    Returns the concave hull as a closed LineString (first == last), or None when the input has fewer than 3 distinct points or all points are collinear.

    kmeans

    fn kmeans(points : Array[
    Point
    ], k : Int, max_iter : Int) -> (Array[
    Coord
    ], Array[Int])?

    K-means clustering with k clusters and at most max_iter Lloyd iterations.

    Returns Some((centroids, labels)) where centroids[j] is the final coordinate of cluster j and labels[i] is the cluster assignment (0..k-1) for points[i]. Returns None for invalid configurations:
    • points.length() == 0 — no points to cluster.
    • k <= 0 — at least one cluster is required.
    • k > points.length() — not enough points to fill the clusters.

    Initialisation: the first k input points seed the centroids. k-means++ is left as a follow-up; for well-separated clusters in the test set this baseline already converges to the global minimum.

    Empty clusters produced during iteration keep their previous centroid (no farthest-point recovery). Convergence is declared when no assignment changes between two consecutive iterations.

    left

    Rotate this coordinate around the origin by 90 degrees clockwise: (x, y) -> (-y, x).

    line_interpolate_point

    fn line_interpolate_point(line :
    Line
    , fraction : Double) ->
    Point

    Returns the point along line at the given fraction of its length (0.0 = start, 1.0 = end). Values outside [0, 1] are clamped.

    line_intersection

    Returns the intersection of two line segments, if any.

    line_locate_point

    fn line_locate_point(line :
    Line
    , target :
    Coord
    ) -> Double?

    Returns the fraction (0..=1) along the line line corresponding to the closest point to target. Returns None when the line is degenerate (zero length).

    line_string_interpolate_point

    fn line_string_interpolate_point(ls :
    LineString
    , fraction : Double) ->
    Point
    ?

    Returns the point along linestring at the given fraction of its total length. Returns None for empty / single-coord linestrings.

    line_string_locate_point

    fn line_string_locate_point(ls :
    LineString
    , target :
    Coord
    ) -> Double?

    Returns the normalised position (0..=1) of the closest point on a linestring to target, where the position is measured by total length.

    magnitude

    fn magnitude(c :
    Coord
    ) -> Double

    Euclidean distance from this coordinate to the origin: sqrt(x² + y²).

    magnitude_squared

    fn magnitude_squared(c :
    Coord
    ) -> Double

    Squared distance from this coordinate to the origin (avoids the sqrt when it is not needed): x² + y².

    orient

    Returns the Orientation of three coordinates using a robust predicate (@robust.orient2d). This corresponds to RobustKernel::orient2d in the Rust geo crate.

    point_at_distance_between

    fn point_at_distance_between(start :
    Point
    , end :
    Point
    , meters_from_start : Double) ->
    Point

    Returns a Point along the great-circle arc between start and end at the given distance meters_from_start from start.

    point_at_ratio_between

    fn point_at_ratio_between(start :
    Point
    , end :
    Point
    , ratio_from_start : Double) ->
    Point

    Returns a Point along the great-circle arc between start and end at fractional ratio ratio_from_start (0.0 = start, 1.0 = end).

    polygon_difference

    Boolean difference: points in a but not in b.

    polygon_intersection

    Boolean intersection: returns the points inside both polygons.

    polygon_union

    Boolean union: returns points inside either polygon.

    polygon_xor

    Symmetric difference: points in exactly one of the polygons. Implemented as (a \ b) ∪ (b \ a) and concatenated.

    relate

    Compute the DE-9IM intersection matrix for two geometries. Triangle, Rect, and Line are reduced to Polygon / LineString first.

    relate_contains

    Convenience: derive contains from the matrix.

    relate_covers

    Convenience: derive covers from the matrix.

    relate_crosses

    Convenience: derive crosses from the matrix.

    relate_disjoint

    Convenience: derive disjoint from the matrix.

    relate_equals

    Convenience: derive equals from the matrix.

    relate_intersects

    Convenience: derive intersects from the matrix.

    relate_overlaps

    Convenience: derive overlaps from the matrix.

    relate_touches

    Convenience: derive touches from the matrix.

    relate_within

    Convenience: derive within from the matrix.

    repair_polygon

    Repair a self-intersecting polygon by decomposing it into simple components. Delegates to the boolean-ops engine: self-union naturally splits tangled rings into separate non-self-crossing components.

    test "repair_polygon - bow-tie decomposes" { let ls = @type.LineString::from_tuples([ (0.0, 0.0), (1.0, 1.0), (1.0, 0.0), (0.0, 1.0), (0.0, 0.0), ]) let poly = @type.Polygon::Polygon(ls, []) let result = repair_polygon(poly) assert_true(result.polygons().length() >= 1) }

    reverse_line_string

    Reverses the order of coordinates in a LineString, returning a new LineString.

    rhumb

    fn rhumb() -> RhumbMeasure

    Standard Earth mean radius for rhumb calculations.

    rhumb_length

    fn rhumb_length(ls :
    LineString
    ) -> Double

    Rhumb-line (loxodrome) length of a line string. Sums the rhumb distances between consecutive coordinate pairs.

    test "rhumb_length - simple 2-point line" { let ls = @type.LineString::from_tuples([(0.0, 0.0), (1.0, 0.0)]) let len = rhumb_length(ls) assert_true(len > 111_000.0) }

    Rotate this coordinate around the origin by 90 degrees anti-clockwise: (x, y) -> (y, -x).

    rotate_geometry_around

    Rotate a geometry around pivot by degrees (CCW positive).

    rotate_geometry_around_centroid

    fn rotate_geometry_around_centroid(g :
    Geometry
    , degrees : Double) ->
    Geometry

    Rotate a geometry around its centroid (or 0 if centroid undefined).

    scale_geometry

    Uniform scale around the origin.

    scale_geometry_around

    Scale a geometry by (xfact, yfact) around origin.

    segment_intersections

    Returns all intersection points among the given line segments. Each intersection is reported once even if multiple segments share it (deduplication uses the module-wide TOLERANCE on both axes).

    Endpoint touches count as intersections (matching line_intersection, where a shared endpoint produces SinglePoint(c, proper=false)).

    For a collinear-overlapping pair, both endpoints of the shared sub-segment are emitted (deduplicated against any other reported intersections).

    simplify_line_string_indices

    fn simplify_line_string_indices(ls :
    LineString
    , epsilon : Double) -> Array[Int]

    Returns the indices of the coordinates retained when simplifying with the RDP algorithm.

    simplify_vw_line_string

    Simplifies a line string using the Visvalingam-Whyatt algorithm. Points whose associated triangle has 2area below epsilon * 2 are iteratively removed. (Note: the threshold here is direct area not 2area, matching geo's sense.)

    skew_geometry

    fn skew_geometry(g :
    Geometry
    , xs_degrees : Double, ys_degrees : Double) ->
    Geometry

    Skew (shear) a geometry by xs and ys degrees, around the origin.

    skew_geometry_around

    fn skew_geometry_around(g :
    Geometry
    , xs_degrees : Double, ys_degrees : Double, pivot :
    Coord
    ) ->
    Geometry

    Skew a geometry around the given pivot.

    stitch_line_strings

    Stitch two LineStrings sharing an endpoint. Returns the concatenated result preserving a's start coordinate. Handles end-to-start and end-to-end joins. Returns None if no endpoint matches.

    test "stitch - two lines sharing endpoint" { let a = @type.LineString::from_tuples([(0.0, 0.0), (1.0, 0.0)]) let b = @type.LineString::from_tuples([(1.0, 0.0), (1.0, 1.0)]) match stitch_line_strings(a, b) { Some(ls) => { let cs = ls.coords() assert_true(cs.length() == 4) assert_true(cs[0] == @type.Coord::Coord(0.0, 0.0)) assert_true(cs[3] == @type.Coord::Coord(1.0, 1.0)) } None => assert_true(false) } }

    translate_geometry

    fn translate_geometry(g :
    Geometry
    , xoff : Double, yoff : Double) ->
    Geometry

    Translate a geometry by (xoff, yoff). Callers working with concrete MapCoords types (e.g. Polygon, Point) can call AffineTransform::translate_xy(xoff, yoff).transform(value) directly.

    try_normalize

    Try to normalise this vector. Returns None if the result is not finite (e.g. the input has zero magnitude that rounds to 0, or NaN / infinite components).

    unary_union

    Union of every polygon in mp. Currently an O(n²) fold (each input is merged into the running accumulator pairwise). The i_overlay sweep-based large-array optimization is deferred.

    validation_problems

    Returns the validation problems detected on a geometry. An empty array indicates the geometry is valid.

    Checks performed per geometry type:
    • Point: non-finite coord
    • Line: identical coords, non-finite coords (with index)
    • LineString: too few points, non-finite coords (with index)
    • Polygon: too few points in ring (with RingRole), ring not closed (with RingRole), self-intersection (with RingRole), non-finite coords (with RingRole + CoordIndex)
    • Triangle: non-finite coords (with CoordIndex), identical coords, collinear coords
    • Rect: non-finite corners (with CoordIndex)
    • Multi* / GeometryCollection: per-element validation (with GeometryIndex wrapping)

    Deferred checks (require ms-18 / ms-20):
    • Polygon interior ring containment
    • Polygon ring-ring intersection on line / area
    • MultiPolygon element overlap / touch-on-line

    vincenty_distance

    Returns the distance in meters between two points on the WGS84 ellipsoid using Vincenty's iterative formula. Returns None if the algorithm fails to converge (typically for nearly antipodal points).

    Units

    • a, b: Points where x=longitude, y=latitude in degrees
    • returns: Some(distance_meters) or None

    test "vincenty_distance - coincident points" { let p = @type.Point::from_tuple((12.3, 4.56)) match vincenty_distance(p, p) { Some(d) => assert_true(d.abs() < 1.0e-3) None => assert_true(false) } }

    vincenty_length

    fn vincenty_length(ls :
    LineString
    ) -> Double?

    Vincenty (ellipsoidal) length of a line string. Sums the vincenty distances between consecutive coordinate pairs. Returns None if any segment fails to converge.

    test "vincenty_length - short segment" { let ls = @type.LineString::from_tuples([(17.072561, 48.154563), (17.064064, 48.158800)]) match vincenty_length(ls) { Some(d) => assert_true((d - 788.4148295236967).abs() < 0.01) None => assert_true(false) } }

    voronoi_diagram

    Compute the Voronoi diagram of a set of 2D points by triangulating then taking the dual. Returns the list of Voronoi edges, or None when the underlying Delaunay triangulation is empty (fewer than 3 points or all collinear).

    bbox is used to clip the unbounded boundary edges. Pass a Rect that comfortably contains all input points (e.g. an expanded bounding rect).

    voronoi_vertices

    Compute just the Voronoi vertices — one circumcenter per Delaunay triangle, in triangulation order. Returns None when the underlying Delaunay triangulation is empty.

    Degenerate triangles whose circumcenter cannot be computed (zero determinant, i.e. collinear corners — shouldn't occur for a valid Delaunay output) are skipped, so the returned array length may be at most the triangle count.

    wedge_product

    2D wedge / cross product: a ∧ b = a.x * b.y - a.y * b.x.

    winding_order

    Returns the winding order of a closed LineString. Returns None if the signed area is zero (degenerate or open).

    within_geometry

    within(a, b) is the inverse of contains(b, a).