// Ported from georust/geo
// https://github.com/georust/geo/blob/main/geo/src/algorithm/orient.rs
///|
/// The convention for ring orientation in a `Polygon`.
pub(all) enum OrientDirection {
/// CCW exterior, CW interiors (the default per the OGC SFA / GeoJSON
/// canonical orientation).
Default
/// CW exterior, CCW interiors.
Reversed
} derive(Eq, Debug)
///|
/// Returns a `LineString` with the requested winding order.
fn ensure_winding(
ls : @type.LineString,
desired : WindingOrder,
) -> @type.LineString {
match winding_order(ls) {
Some(actual) => if actual == desired { ls } else { reverse_line_string(ls) }
None => ls
}
}
///|
/// Returns a `Polygon` with the rings re-oriented per `direction`.
fn orient_polygon(
polygon : @type.Polygon,
direction : OrientDirection,
) -> @type.Polygon {
let (exterior_winding, interior_winding) = match direction {
Default => (WindingOrder::CounterClockwise, WindingOrder::Clockwise)
Reversed => (WindingOrder::Clockwise, WindingOrder::CounterClockwise)
}
let exterior = ensure_winding(polygon.exterior(), exterior_winding)
let interiors = polygon
.interiors()
.map(fn(i) { ensure_winding(i, interior_winding) })
@type.Polygon::Polygon(exterior, interiors)
}
///|
/// Re-orient every polygon in a multi polygon.
fn orient_multi_polygon(
mp : @type.MultiPolygon,
direction : OrientDirection,
) -> @type.MultiPolygon {
let polygons = mp.polygons().map(fn(p) { orient_polygon(p, direction) })
@type.MultiPolygon::MultiPolygon(polygons)
}
// MARK: trait Orient + impls ------------------------------------------------
///|
/// 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`.
pub(open) trait Orient {
fn orient(Self, OrientDirection) -> Self
}
///|
pub impl Orient for @type.Polygon with fn orient(self, direction) {
orient_polygon(self, direction)
}
///|
pub impl Orient for @type.MultiPolygon with fn orient(self, direction) {
orient_multi_polygon(self, direction)
}