///|
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))),
)
}impl Bounded for GeometryCollectionimpl Bounded for LineStringimpl Bounded for MultiLineStringimpl Bounded for MultiPointimpl Bounded for MultiPolygonimpl ClosestPoint for LineStringimpl Contains for GeometryCollectionimpl Contains for LineStringimpl Contains for MultiLineStringimpl Contains for MultiPointimpl Contains for MultiPolygonimpl CoordPositionFor for Geometryimpl CoordPositionFor for LineStringimpl CoordPositionFor for MultiPolygonimpl CoordsCarrier for GeometryCollectionimpl CoordsCarrier for LineStringimpl CoordsCarrier for MultiLineStringimpl CoordsCarrier for MultiPointimpl CoordsCarrier for MultiPolygonimpl Covers for GeometryCollectionimpl Covers for LineStringimpl Covers for MultiLineStringimpl Covers for MultiPointimpl Covers for MultiPolygonpub(open) trait Densify {
fn densify(Self, Double) -> Self
}impl Densify for LineStringimpl ExteriorCoordsCarrier for MultiPolygonpub(open) trait HasArea {
fn signed_area(Self) -> Double
fn unsigned_area(Self) -> Double
}impl HasArea for MultiPolygonimpl HasCentroid for Geometryimpl HasCentroid for LineStringimpl HasCentroid for MultiPolygonimpl HasCentroid for Polygonimpl HasConvexHull for Geometryimpl HasConvexHull for LineStringimpl HasConvexHull for MultiPointimpl HasConvexHull for Polygonimpl HasDimensions for Geometryimpl HasDimensions for LineStringimpl HasDimensions for Rectpub(open) trait HasEuclideanLength {
fn euclidean_length(Self) -> Double
}impl HasEuclideanLength for Lineimpl HasEuclideanLength for LineStringimpl HasEuclideanLength for MultiLineStringimpl HasExtremes for Geometryimpl HasExtremes for GeometryCollectionimpl HasExtremes for Lineimpl HasExtremes for LineStringimpl HasExtremes for MultiLineStringimpl HasExtremes for MultiPointimpl HasExtremes for MultiPolygonimpl HasExtremes for Pointimpl HasExtremes for Polygonimpl HasExtremes for Rectimpl HasExtremes for Triangleimpl Intersects for Geometryimpl Intersects for GeometryCollectionimpl Intersects for Lineimpl Intersects for LineStringimpl Intersects for MultiLineStringimpl Intersects for MultiPointimpl Intersects for MultiPolygonimpl Intersects for Pointimpl Intersects for Polygonimpl Intersects for Rectimpl Intersects for Triangleimpl LinesCarrier for GeometryCollectionimpl LinesCarrier for LineStringimpl LinesCarrier for MultiLineStringimpl LinesCarrier for MultiPolygonimpl MapCoords for GeometryCollectionimpl MapCoords for LineStringimpl MapCoords for MultiLineStringimpl MapCoords for MultiPointimpl MapCoords for MultiPolygonimpl Orient for MultiPolygonpub(open) trait RemoveRepeatedPoints {
fn remove_repeated_points(Self) -> Self
}impl RemoveRepeatedPoints for LineStringimpl RemoveRepeatedPoints for Polygonpub(open) trait Simplify {
fn simplify(Self, Double) -> Self
}impl Simplify for LineStringimpl Within for GeometryCollectionimpl Within for LineStringimpl Within for MultiLineStringimpl Within for MultiPointimpl Within for MultiPolygonfn AffineTransform::compose_many(self : AffineTransform, transforms : Array[AffineTransform]) -> AffineTransform[[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 ]]fn AffineTransform::rotated(self : AffineTransform, degrees : Double, origin : Coord) -> AffineTransformfn AffineTransform::scaled(self : AffineTransform, xfact : Double, yfact : Double, origin : Coord) -> AffineTransformfn AffineTransform::skew_around(xs_degrees : Double, ys_degrees : Double, origin : Coord) -> AffineTransformfn AffineTransform::skewed(self : AffineTransform, xs : Double, ys : Double, origin : Coord) -> AffineTransformfn AffineTransform::translated(self : AffineTransform, xoff : Double, yoff : Double) -> AffineTransformpub(all) struct BufferOptions {
end_cap : BufferEndCap
join : BufferJoin
miter_limit : Double
arc_segments : Int
} derive(Eq, Debug)fn HaversineMeasure::bearing(_self : HaversineMeasure, origin : Point, destination : Point) -> Doubletest "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)
}fn HaversineMeasure::destination(self : HaversineMeasure, origin : Point, bearing : Double, distance : Double) -> Pointtest "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)
}fn HaversineMeasure::distance(self : HaversineMeasure, origin : Point, destination : Point) -> Doubletest "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)
}fn RhumbMeasure::destination(self : RhumbMeasure, origin : Point, bearing : Double, distance : Double) -> Pointtest "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)
}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)let TOLERANCE : Doubletest "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)
}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)
}
}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)
}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)
}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)
}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)
}fn densify_haversine_multi_line_string(mls : MultiLineString, max_segment_length : Double) -> MultiLineStringtest "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)
}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)
}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)
}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)
}
}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)
}
}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)
}
}Install
Download zipMoonBit port of georust/geo: 2D planar geospatial primitives and algorithms