Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implement 3D and Measure support for geo types
This PR focuses on `geo-types` only, making it possible to merge without conflicts because it no longer uses local relative paths. This is a part of #742. It also bumps geo-types requirements to 0.7.4. This PR changes the underlying geo-type data structures to support 3D data and measurement values (M and Z values). The PR attempts to cause relatively minor disruptions to the existing users (see breaking changes below). My knowledge of the actual geo algorithms is limited, so please ping me for any specific algo change. Many other pending PRs are included here - most of them can be merged without affecting existing users, and will make reviewing this PR easier. See the list below. All geo type structs have been renamed from `Foo<T>(...)` to `FooTZM<T,Z,M>(...)`, and several type aliases were added: ```rust // old pub struct LineString<T: CoordNum>(pub Vec<Coordinate<T>>); // new pub struct LineStringTZM<T: CoordNum, Z: ZCoord, M: Measure>(pub Vec<CoordTZM<T, Z, M>>); pub type LineString<T> = LineStringTZM<T, NoValue, NoValue>; pub type LineStringM<T, M> = LineStringTZM<T, NoValue, M>; pub type LineStringZ<T> = LineStringTZM<T, T, NoValue>; pub type LineStringZM<T, M> = LineStringTZM<T, T, M>; ``` `NoValue` is an empty struct that behaves just like a number. It supports all math and comparison operations. This means that a `Z` or `M` value can be manipulated without checking if it is actually there. This code works for Z and M being either a number or a NoValue: ```rust pub struct NoValue; impl<T: CoordNum, Z: ZCoord, M: Measure> Sub for CoordTZM<T, Z, M> { type Output = Self; fn sub(self, rhs: Self) -> Self { coord! { x: self.x - rhs.x, y: self.y - rhs.y, z: self.z - rhs.z, m: self.m - rhs.m, } } } ``` Function implementations can keep just the original 2D `<T>` variant, or add support for 3D `<Z>` and/or the Measure `<M>`. The above example works for all combinations of objects. This function only works for 2D objects with and without the Measure (Z is set to `NoValue` by `LineM` type alias. ```rust impl<T: CoordNum, M: Measure> LineM<T, M> { /// Calculate the slope (Δy/Δx). pub fn slope(&self) -> T { self.dy() / self.dx() } } ``` It will not be possible to use implicit type constructor for tuples because type aliases do not support them. Most geo types will have a `new(...)` fn if they didn't have one before. ```rust // old MultiPoint(vec![...]); ...iter().map(MultiPoint); // new MultiPoint::new(vec![...]); ...iter().map(MultiPoint::new); ``` Destructuring assignments seem to require real type rather than an alias. ```rust // old let Point(c) = p; // new let PointTZM(c) = p; ```
- Loading branch information