diff --git a/galileo-types/Cargo.toml b/galileo-types/Cargo.toml index 4629b5b..4105674 100644 --- a/galileo-types/Cargo.toml +++ b/galileo-types/Cargo.toml @@ -5,8 +5,12 @@ edition.workspace = true authors.workspace = true repository.workspace = true +[features] +default = ["geo-types"] + [dependencies] num-traits = "0.2.17" nalgebra = "0.32" serde = { version = "1.0", features = ["derive"] } -geodesy = "0.11.1" \ No newline at end of file +geodesy = "0.11.1" +geo-types = { version = "0.7", optional = true } \ No newline at end of file diff --git a/galileo-types/src/cartesian/impls/contour.rs b/galileo-types/src/cartesian/impls/contour.rs index 06ca044..39d4019 100644 --- a/galileo-types/src/cartesian/impls/contour.rs +++ b/galileo-types/src/cartesian/impls/contour.rs @@ -2,7 +2,8 @@ use crate::cartesian::rect::Rect; use crate::cartesian::traits::cartesian_point::CartesianPoint2d; use crate::cartesian::traits::contour::CartesianContour; use crate::geo::traits::projection::Projection; -use crate::geometry::{CartesianGeometry2d, Geom, Geometry}; +use crate::geometry::CartesianGeometry2d; +use crate::geometry_type::{ContourGeometryType, GeometryType}; use num_traits::Float; use serde::{Deserialize, Serialize}; @@ -89,11 +90,11 @@ impl

From> for Contour

{ } } -impl

crate::cartesian::traits::contour::ClosedContour for ClosedContour

{ +impl

crate::contour::ClosedContour for ClosedContour

{ type Point = P; - fn iter_points(&self) -> Box + '_> { - Box::new(self.points.iter()) + fn iter_points(&self) -> impl Iterator { + self.points.iter() } } @@ -103,15 +104,15 @@ impl

crate::cartesian::traits::contour::ClosedContour for ClosedContour

{ // } // } -impl

crate::cartesian::traits::contour::Contour for Contour

{ +impl

crate::contour::Contour for Contour

{ type Point = P; fn is_closed(&self) -> bool { self.is_closed } - fn iter_points(&self) -> Box + '_> { - Box::new(self.points.iter()) + fn iter_points(&self) -> impl Iterator { + self.points.iter() } } @@ -120,45 +121,17 @@ impl

crate::cartesian::traits::contour::Contour for Contour

{ // { // } -impl

Geometry for ClosedContour

{ - type Point = P; - - fn project + ?Sized>( - &self, - projection: &Proj, - ) -> Option> { - let points = self - .points - .iter() - .map(|p| projection.project(p)) - .collect::>>()?; - Some(Geom::Line(Contour { - points, - is_closed: true, - })) - } +impl GeometryType for Contour

{ + type Type = ContourGeometryType; + type Space = P::Space; } -impl

Geometry for Contour

{ - type Point = P; - - fn project + ?Sized>( - &self, - projection: &Proj, - ) -> Option> { - let points = self - .points - .iter() - .map(|p| projection.project(p)) - .collect::>>()?; - Some(Geom::Line(Contour { - points, - is_closed: true, - })) - } +impl GeometryType for ClosedContour

{ + type Type = ContourGeometryType; + type Space = P::Space; } -impl CartesianGeometry2d

for Contour

+impl CartesianGeometry2d

for Contour

where N: Float, P: CartesianPoint2d, diff --git a/galileo-types/src/cartesian/impls/multipolygon.rs b/galileo-types/src/cartesian/impls/multipolygon.rs index 7d62683..c38951a 100644 --- a/galileo-types/src/cartesian/impls/multipolygon.rs +++ b/galileo-types/src/cartesian/impls/multipolygon.rs @@ -1,8 +1,8 @@ use crate::cartesian::impls::polygon::Polygon; use crate::cartesian::rect::Rect; use crate::cartesian::traits::cartesian_point::CartesianPoint2d; -use crate::geo::traits::projection::Projection; -use crate::geometry::{CartesianGeometry2d, Geom, Geometry}; +use crate::geometry::CartesianGeometry2d; +use crate::geometry_type::{GeometryType, MultiPolygonGeometryType}; use serde::{Deserialize, Serialize}; #[derive(Debug, Serialize, Deserialize)] @@ -22,29 +22,20 @@ impl

MultiPolygon

{ } } -impl

Geometry for MultiPolygon

{ - type Point = P; +impl

crate::multi_polygon::MultiPolygon for MultiPolygon

{ + type Polygon = Polygon

; - fn project + ?Sized>( - &self, - projection: &Proj, - ) -> Option> { - Some(Geom::MultiPolygon(MultiPolygon { - parts: self - .parts - .iter() - .map(|p| { - p.project(projection).and_then(|p| match p { - Geom::Polygon(v) => Some(v), - _ => None, - }) - }) - .collect::>>>()?, - })) + fn polygons(&self) -> impl Iterator { + self.parts.iter() } } -impl

CartesianGeometry2d

for MultiPolygon

+impl GeometryType for MultiPolygon

{ + type Type = MultiPolygonGeometryType; + type Space = P::Space; +} + +impl CartesianGeometry2d

for MultiPolygon

where P: CartesianPoint2d, { diff --git a/galileo-types/src/cartesian/impls/point.rs b/galileo-types/src/cartesian/impls/point.rs index 163ee42..8eeaea2 100644 --- a/galileo-types/src/cartesian/impls/point.rs +++ b/galileo-types/src/cartesian/impls/point.rs @@ -3,6 +3,7 @@ use crate::cartesian::traits::cartesian_point::{ }; use crate::geo::traits::projection::Projection; use crate::geometry::{Geom, Geometry}; +use crate::geometry_type::{CartesianSpace2d, GeometryType, PointGeometryType}; use crate::point::{CartesianPointType, Point}; pub use nalgebra::Point2; use nalgebra::{Point3, Scalar}; @@ -60,15 +61,9 @@ impl NewCartesianPoint3d for Point3 { } } -impl Geometry for Point2 { - type Point = Point2; - - fn project + ?Sized>( - &self, - projection: &P, - ) -> Option> { - Some(Geom::Point(projection.project(self)?)) - } +impl GeometryType for Point2 { + type Type = PointGeometryType; + type Space = CartesianSpace2d; } impl Geometry for Point3 { diff --git a/galileo-types/src/cartesian/impls/polygon.rs b/galileo-types/src/cartesian/impls/polygon.rs index 2c7aaad..8fbae4b 100644 --- a/galileo-types/src/cartesian/impls/polygon.rs +++ b/galileo-types/src/cartesian/impls/polygon.rs @@ -2,8 +2,8 @@ use crate::cartesian::impls::contour::ClosedContour; use crate::cartesian::rect::Rect; use crate::cartesian::traits::cartesian_point::CartesianPoint2d; use crate::cartesian::traits::polygon::CartesianPolygon; -use crate::geo::traits::projection::Projection; -use crate::geometry::{CartesianGeometry2d, Geom, Geometry}; +use crate::geometry::CartesianGeometry2d; +use crate::geometry_type::{GeometryType, PolygonGeometryType}; use serde::{Deserialize, Serialize}; #[derive(Debug, Clone, Serialize, Deserialize)] @@ -31,14 +31,14 @@ impl

Polygon

{ } } -impl

crate::cartesian::traits::polygon::Polygon for Polygon

{ +impl

crate::polygon::Polygon for Polygon

{ type Contour = ClosedContour

; fn outer_contour(&self) -> &Self::Contour { &self.outer_contour } - fn inner_contours(&self) -> Box + '_> { + fn inner_contours(&self) -> impl Iterator { Box::new(self.inner_contours.iter()) } } @@ -52,34 +52,12 @@ impl

From> for Polygon

{ } } -impl

Geometry for Polygon

{ - type Point = P; - - fn project + ?Sized>( - &self, - projection: &Proj, - ) -> Option> { - let Geom::Line(outer_contour) = self.outer_contour.project(projection)? else { - return None; - }; - let inner_contours = self - .inner_contours - .iter() - .map(|c| { - c.project(projection).and_then(|c| match c { - Geom::Line(contour) => contour.into_closed(), - _ => None, - }) - }) - .collect::>>>()?; - Some(Geom::Polygon(Polygon { - outer_contour: outer_contour.into_closed()?, - inner_contours, - })) - } +impl GeometryType for Polygon

{ + type Type = PolygonGeometryType; + type Space = P::Space; } -impl

CartesianGeometry2d

for Polygon

+impl CartesianGeometry2d

for Polygon

where P: CartesianPoint2d, { diff --git a/galileo-types/src/cartesian/traits/cartesian_point.rs b/galileo-types/src/cartesian/traits/cartesian_point.rs index e7f8f6f..191911a 100644 --- a/galileo-types/src/cartesian/traits/cartesian_point.rs +++ b/galileo-types/src/cartesian/traits/cartesian_point.rs @@ -1,3 +1,6 @@ +use crate::geo::traits::projection::Projection; +use crate::geometry::{Geom, GeometrySpecialization}; +use crate::geometry_type::{CartesianSpace2d, GeometryType, PointGeometryType}; use crate::point::{CartesianPointType, Point, PointHelper}; use nalgebra::{Point2, Scalar, Vector2}; use num_traits::{Bounded, Float, FromPrimitive, Num}; @@ -75,3 +78,17 @@ pub trait CartesianPoint2dFloat: CartesianPoint2d { } impl> CartesianPoint2dFloat for T {} + +impl

GeometrySpecialization for P +where + P: CartesianPoint2d + GeometryType, +{ + type Point = P; + + fn project(&self, projection: &Proj) -> Option> + where + Proj: Projection + ?Sized, + { + Some(Geom::Point(projection.project(self)?)) + } +} diff --git a/galileo-types/src/cartesian/traits/contour.rs b/galileo-types/src/cartesian/traits/contour.rs index 557c172..8471bb8 100644 --- a/galileo-types/src/cartesian/traits/contour.rs +++ b/galileo-types/src/cartesian/traits/contour.rs @@ -1,54 +1,9 @@ use crate::cartesian::traits::cartesian_point::CartesianPoint2d; -use crate::segment::Segment; +use crate::contour::{ClosedContour, Contour}; use num_traits::{One, Zero}; use std::cmp::Ordering; use std::fmt::Debug; -pub trait Contour { - type Point; - - fn is_closed(&self) -> bool; - - fn iter_points(&self) -> Box + '_>; - - fn iter_points_closing(&self) -> Box + '_> - where - Self: Sized, - { - Box::new(ContourPointsIterator::new( - self.iter_points(), - self.is_closed(), - )) - } - - fn iter_segments(&self) -> Box> + '_> - where - Self: Sized, - { - Box::new(ContourSegmentIterator::new(ContourPointsIterator::new( - self.iter_points(), - self.is_closed(), - ))) - } -} - -pub trait ClosedContour { - type Point; - fn iter_points(&self) -> Box + '_>; -} - -impl> Contour for T { - type Point = P; - - fn is_closed(&self) -> bool { - true - } - - fn iter_points(&self) -> Box + '_> { - self.iter_points() - } -} - pub trait CartesianClosedContour { type Point: CartesianPoint2d; @@ -121,72 +76,13 @@ pub trait CartesianContour: Contour { impl, P: CartesianPoint2d> CartesianContour

for T {} -pub struct ContourPointsIterator<'a, P> { - points_iter: Box + 'a>, - is_closed: bool, - first_point: Option<&'a P>, -} - -impl<'a, P: 'a> ContourPointsIterator<'a, P> { - fn new(points_iter: Box + 'a>, is_closed: bool) -> Self { - Self { - points_iter, - is_closed, - first_point: None, - } - } -} - -impl<'a, P> Iterator for ContourPointsIterator<'a, P> { - type Item = &'a P; - - fn next(&mut self) -> Option { - let next = self.points_iter.next(); - if self.is_closed && self.first_point.is_none() { - self.first_point = next; - } - - if next.is_none() { - self.first_point.take() - } else { - next - } - } -} - -pub struct ContourSegmentIterator<'a, P: 'a> { - points_iter: ContourPointsIterator<'a, P>, - prev_point: Option<&'a P>, -} - -impl<'a, P> ContourSegmentIterator<'a, P> { - fn new(points_iter: ContourPointsIterator<'a, P>) -> Self { - Self { - points_iter, - prev_point: None, - } - } -} - -impl<'a, P> Iterator for ContourSegmentIterator<'a, P> { - type Item = Segment<'a, P>; - - fn next(&mut self) -> Option { - let next_point = self.points_iter.next()?; - let prev_point = self.prev_point.replace(next_point); - - match prev_point { - Some(prev) => Some(Segment(prev, next_point)), - None => self.next(), - } - } -} - #[cfg(test)] mod tests { use super::*; use crate::cartesian::impls::contour::ClosedContour; use crate::cartesian::impls::point::Point2d; + use crate::contour::Contour; + use crate::segment::Segment; #[test] fn iter_points_closing() { diff --git a/galileo-types/src/cartesian/traits/polygon.rs b/galileo-types/src/cartesian/traits/polygon.rs index 7e1ba12..be9b652 100644 --- a/galileo-types/src/cartesian/traits/polygon.rs +++ b/galileo-types/src/cartesian/traits/polygon.rs @@ -1,25 +1,9 @@ use crate::cartesian::traits::cartesian_point::CartesianPoint2d; -use crate::cartesian::traits::contour::{ClosedContour, Contour}; +use crate::contour::ClosedContour; +use crate::polygon::Polygon; use crate::segment::Segment; use nalgebra::Point2; -pub trait Polygon { - type Contour: ClosedContour; - - fn outer_contour(&self) -> &Self::Contour; - fn inner_contours(&self) -> Box + '_>; - - fn iter_contours(&self) -> Box + '_> { - Box::new(std::iter::once(self.outer_contour()).chain(self.inner_contours())) - } - - fn iter_segments( - &self, - ) -> Box::Point>> + '_> { - Box::new(self.iter_contours().flat_map(Self::Contour::iter_segments)) - } -} - pub trait CartesianPolygon { type Point: CartesianPoint2d; @@ -74,8 +58,8 @@ where #[cfg(test)] mod tests { - use super::*; use crate::cartesian::impls::point::Point2d; + use crate::cartesian::traits::polygon::*; #[test] fn contains_point() { diff --git a/galileo-types/src/contour.rs b/galileo-types/src/contour.rs new file mode 100644 index 0000000..47e33be --- /dev/null +++ b/galileo-types/src/contour.rs @@ -0,0 +1,158 @@ +use crate::geo::traits::projection::Projection; +use crate::geometry::{Geom, GeometrySpecialization}; +use crate::geometry_type::{ContourGeometryType, GeometryType}; +use crate::segment::Segment; + +pub trait Contour { + type Point; + + fn is_closed(&self) -> bool; + + fn iter_points(&self) -> impl Iterator; + + fn iter_points_closing(&self) -> impl Iterator { + Box::new(ContourPointsIterator::new( + self.iter_points(), + self.is_closed(), + )) + } + + fn iter_segments(&self) -> impl Iterator> { + ContourSegmentIterator::new(ContourPointsIterator::new( + self.iter_points(), + self.is_closed(), + )) + } + + fn project_points( + &self, + projection: &Proj, + ) -> Option> + where + Proj: Projection, + { + Some(crate::cartesian::impls::contour::Contour::new( + self.iter_points() + .map(|p| projection.project(p)) + .collect::>>()?, + self.is_closed(), + )) + } +} + +pub trait ClosedContour { + type Point; + fn iter_points(&self) -> impl Iterator; +} + +impl> Contour for T { + type Point = P; + + fn is_closed(&self) -> bool { + true + } + + fn iter_points(&self) -> impl Iterator { + self.iter_points() + } +} + +pub struct ContourPointsIterator<'a, P, Iter> +where + Iter: Iterator, +{ + points_iter: Iter, + is_closed: bool, + first_point: Option<&'a P>, +} + +impl<'a, P: 'a, Iter> ContourPointsIterator<'a, P, Iter> +where + Iter: Iterator, +{ + fn new(points_iter: Iter, is_closed: bool) -> Self { + Self { + points_iter, + is_closed, + first_point: None, + } + } +} + +impl<'a, P, Iter> Iterator for ContourPointsIterator<'a, P, Iter> +where + Iter: Iterator, +{ + type Item = &'a P; + + fn next(&mut self) -> Option { + let next = self.points_iter.next(); + if self.is_closed && self.first_point.is_none() { + self.first_point = next; + } + + if next.is_none() { + self.first_point.take() + } else { + next + } + } +} + +pub struct ContourSegmentIterator<'a, P: 'a, Iter> +where + Iter: Iterator, +{ + points_iter: ContourPointsIterator<'a, P, Iter>, + prev_point: Option<&'a P>, +} + +impl<'a, P, Iter> ContourSegmentIterator<'a, P, Iter> +where + Iter: Iterator, +{ + fn new(points_iter: ContourPointsIterator<'a, P, Iter>) -> Self { + Self { + points_iter, + prev_point: None, + } + } +} + +impl<'a, P, Iter> Iterator for ContourSegmentIterator<'a, P, Iter> +where + Iter: Iterator, +{ + type Item = Segment<'a, P>; + + fn next(&mut self) -> Option { + let next_point = self.points_iter.next()?; + let prev_point = self.prev_point.replace(next_point); + + match prev_point { + Some(prev) => Some(Segment(prev, next_point)), + None => self.next(), + } + } +} + +impl GeometrySpecialization for C +where + C: Contour + GeometryType, +{ + type Point = C::Point; + + fn project(&self, projection: &Proj) -> Option> + where + Proj: Projection + ?Sized, + { + let points = self + .iter_points() + .map(|p| projection.project(p)) + .collect::>>()?; + Some(Geom::Contour(crate::cartesian::impls::contour::Contour { + points, + is_closed: true, + })) + } +} diff --git a/galileo-types/src/disambig.rs b/galileo-types/src/disambig.rs new file mode 100644 index 0000000..80edad6 --- /dev/null +++ b/galileo-types/src/disambig.rs @@ -0,0 +1,139 @@ +use crate::cartesian::traits::cartesian_point::{CartesianPoint2d, NewCartesianPoint2d}; +use crate::contour::Contour; +use crate::geo::traits::point::{GeoPoint, NewGeoPoint}; +use crate::geometry_type::{AmbiguousSpace, CartesianSpace2d, GeoSpace2d, GeometryType}; +use crate::multi_contour::MultiContour; +use crate::multi_point::MultiPoint; +use crate::multi_polygon::MultiPolygon; +use crate::polygon::Polygon; +use std::marker::PhantomData; + +pub struct Disambig { + inner: T, + space: PhantomData, +} + +impl Disambig { + pub fn new(inner: T) -> Self { + Self { + inner, + space: Default::default(), + } + } +} + +impl Clone for Disambig { + fn clone(&self) -> Self { + Self { + inner: self.inner.clone(), + space: Default::default(), + } + } +} + +impl GeometryType for Disambig { + type Type = T::Type; + type Space = Space; +} + +impl CartesianPoint2d for Disambig { + type Num = T::Num; + + fn x(&self) -> Self::Num { + self.inner.x() + } + + fn y(&self) -> Self::Num { + self.inner.y() + } +} + +impl GeoPoint for Disambig { + type Num = T::Num; + + fn lat(&self) -> Self::Num { + self.inner.lat() + } + + fn lon(&self) -> Self::Num { + self.inner.lon() + } +} + +impl NewCartesianPoint2d for Disambig { + fn new(x: f64, y: f64) -> Self { + Self::new(T::new(x, y)) + } +} + +impl NewGeoPoint for Disambig { + fn latlon(lat: f64, lon: f64) -> Self { + Self::new(T::latlon(lat, lon)) + } +} + +impl Contour for Disambig { + type Point = T::Point; + + fn is_closed(&self) -> bool { + self.inner.is_closed() + } + + fn iter_points(&self) -> impl Iterator { + self.inner.iter_points() + } +} + +impl Polygon for Disambig { + type Contour = T::Contour; + + fn outer_contour(&self) -> &Self::Contour { + self.inner.outer_contour() + } + + fn inner_contours(&self) -> impl Iterator { + self.inner.inner_contours() + } +} + +impl MultiPoint for Disambig { + type Point = T::Point; + + fn iter_points(&self) -> impl Iterator { + self.inner.iter_points() + } +} + +impl MultiContour for Disambig { + type Contour = T::Contour; + + fn contours(&self) -> impl Iterator { + self.inner.contours() + } +} + +impl MultiPolygon for Disambig { + type Polygon = T::Polygon; + + fn polygons(&self) -> impl Iterator { + self.inner.polygons() + } +} + +pub trait Disambiguate { + fn to_geo2d(self) -> Disambig + where + Self: Sized, + { + Disambig::new(self) + } + + fn to_cartesian2d(self) -> Disambig + where + Self: Sized, + { + Disambig::new(self) + } +} + +impl> Disambiguate for T {} diff --git a/galileo-types/src/geo/impls/projection/identity.rs b/galileo-types/src/geo/impls/projection/identity.rs index 6f14660..858ade4 100644 --- a/galileo-types/src/geo/impls/projection/identity.rs +++ b/galileo-types/src/geo/impls/projection/identity.rs @@ -1,28 +1,65 @@ +use crate::cartesian::traits::cartesian_point::{NewCartesianPoint2d, NewCartesianPoint3d}; +use crate::geo::traits::point::NewGeoPoint; use crate::geo::traits::projection::Projection; +use crate::geometry_type::{CartesianSpace2d, CartesianSpace3d, GeoSpace2d}; use std::marker::PhantomData; #[derive(Default)] -pub struct IdentityProjection

{ - phantom: PhantomData

, +pub struct IdentityProjection { + phantom_in: PhantomData, + phantom_out: PhantomData, + phantom_space: PhantomData, } -impl

IdentityProjection

{ +impl IdentityProjection { pub fn new() -> Self { Self { - phantom: Default::default(), + phantom_in: Default::default(), + phantom_out: Default::default(), + phantom_space: Default::default(), } } } -impl Projection for IdentityProjection

{ - type InPoint = P; - type OutPoint = P; +impl Projection + for IdentityProjection +{ + type InPoint = IN; + type OutPoint = OUT; fn project(&self, input: &Self::InPoint) -> Option { - Some(input.clone()) + Some(OUT::new(input.x(), input.y())) } fn unproject(&self, input: &Self::OutPoint) -> Option { - Some(input.clone()) + Some(IN::new(input.x(), input.y())) + } +} + +impl Projection + for IdentityProjection +{ + type InPoint = IN; + type OutPoint = OUT; + + fn project(&self, input: &Self::InPoint) -> Option { + Some(OUT::new(input.x(), input.y(), input.z())) + } + + fn unproject(&self, input: &Self::OutPoint) -> Option { + Some(IN::new(input.x(), input.y(), input.z())) + } +} + +impl Projection for IdentityProjection { + type InPoint = IN; + type OutPoint = OUT; + + fn project(&self, input: &Self::InPoint) -> Option { + Some(OUT::latlon(input.lat(), input.lon())) + } + + fn unproject(&self, input: &Self::OutPoint) -> Option { + Some(IN::latlon(input.lat(), input.lon())) } } diff --git a/galileo-types/src/geo/traits/point.rs b/galileo-types/src/geo/traits/point.rs index dc803ba..085f267 100644 --- a/galileo-types/src/geo/traits/point.rs +++ b/galileo-types/src/geo/traits/point.rs @@ -1,4 +1,7 @@ use crate::geo::datum::Datum; +use crate::geo::traits::projection::Projection; +use crate::geometry::{Geom, GeometrySpecialization}; +use crate::geometry_type::{GeoSpace2d, GeometryType, PointGeometryType}; use crate::point::{GeoPointType, Point, PointHelper}; use num_traits::Float; @@ -33,3 +36,17 @@ pub trait NewGeoPoint: GeoPoint + Sized { } impl PointHelper for T where T: GeoPoint + Point {} + +impl

GeometrySpecialization for P +where + P: GeoPoint + GeometryType, +{ + type Point = P; + + fn project(&self, projection: &Proj) -> Option> + where + Proj: Projection + ?Sized, + { + Some(Geom::Point(projection.project(self)?)) + } +} diff --git a/galileo-types/src/geo_types/coord.rs b/galileo-types/src/geo_types/coord.rs new file mode 100644 index 0000000..be2f45c --- /dev/null +++ b/galileo-types/src/geo_types/coord.rs @@ -0,0 +1,47 @@ +use crate::cartesian::traits::cartesian_point::{CartesianPoint2d, NewCartesianPoint2d}; +use crate::geo::traits::point::{GeoPoint, NewGeoPoint}; +use crate::geometry_type::{AmbiguousSpace, GeometryType, PointGeometryType}; +use geo_types::{coord, Coord, CoordNum}; +use nalgebra::Scalar; +use num_traits::{Bounded, Float, FromPrimitive}; + +impl CartesianPoint2d for Coord { + type Num = T; + + fn x(&self) -> Self::Num { + self.x + } + + fn y(&self) -> Self::Num { + self.y + } +} + +impl NewCartesianPoint2d for Coord { + fn new(x: T, y: T) -> Self { + coord!(x: x, y: y) + } +} + +impl GeometryType for Coord { + type Type = PointGeometryType; + type Space = AmbiguousSpace; +} + +impl GeoPoint for Coord { + type Num = T; + + fn lat(&self) -> Self::Num { + self.y + } + + fn lon(&self) -> Self::Num { + self.x + } +} + +impl NewGeoPoint for Coord { + fn latlon(lat: T, lon: T) -> Self { + coord!(x: lon, y: lat) + } +} diff --git a/galileo-types/src/geo_types/linestring.rs b/galileo-types/src/geo_types/linestring.rs new file mode 100644 index 0000000..f8ff091 --- /dev/null +++ b/galileo-types/src/geo_types/linestring.rs @@ -0,0 +1,24 @@ +use crate::contour::Contour; +use crate::geometry_type::{AmbiguousSpace, ContourGeometryType, GeometryType}; +use geo_types::{Coord, CoordNum, LineString}; + +impl Contour for LineString { + type Point = Coord; + + fn is_closed(&self) -> bool { + LineString::is_closed(self) + } + + fn iter_points(&self) -> impl Iterator { + if self.is_closed() { + self.0[..(self.0.len().max(1) - 1)].iter() + } else { + self.0.iter() + } + } +} + +impl GeometryType for LineString { + type Type = ContourGeometryType; + type Space = AmbiguousSpace; +} diff --git a/galileo-types/src/geo_types/mod.rs b/galileo-types/src/geo_types/mod.rs new file mode 100644 index 0000000..54792ce --- /dev/null +++ b/galileo-types/src/geo_types/mod.rs @@ -0,0 +1,7 @@ +mod coord; +mod linestring; +mod multi_linestring; +mod multi_point; +mod multi_polygon; +mod point; +mod polygon; diff --git a/galileo-types/src/geo_types/multi_linestring.rs b/galileo-types/src/geo_types/multi_linestring.rs new file mode 100644 index 0000000..08a3b2f --- /dev/null +++ b/galileo-types/src/geo_types/multi_linestring.rs @@ -0,0 +1,16 @@ +use crate::geometry_type::{AmbiguousSpace, GeometryType, MultiContourGeometryType}; +use crate::multi_contour::MultiContour; +use geo_types::{CoordNum, LineString, MultiLineString}; + +impl MultiContour for MultiLineString { + type Contour = LineString; + + fn contours(&self) -> impl Iterator { + self.0.iter() + } +} + +impl GeometryType for MultiLineString { + type Type = MultiContourGeometryType; + type Space = AmbiguousSpace; +} diff --git a/galileo-types/src/geo_types/multi_point.rs b/galileo-types/src/geo_types/multi_point.rs new file mode 100644 index 0000000..2d94637 --- /dev/null +++ b/galileo-types/src/geo_types/multi_point.rs @@ -0,0 +1,15 @@ +use crate::geometry_type::{AmbiguousSpace, GeometryType, MultiPointGeometryType}; +use geo_types::{CoordNum, MultiPoint, Point}; + +impl crate::multi_point::MultiPoint for MultiPoint { + type Point = Point; + + fn iter_points(&self) -> impl Iterator { + self.0.iter() + } +} + +impl GeometryType for MultiPoint { + type Type = MultiPointGeometryType; + type Space = AmbiguousSpace; +} diff --git a/galileo-types/src/geo_types/multi_polygon.rs b/galileo-types/src/geo_types/multi_polygon.rs new file mode 100644 index 0000000..d1dd8bf --- /dev/null +++ b/galileo-types/src/geo_types/multi_polygon.rs @@ -0,0 +1,15 @@ +use crate::geometry_type::{AmbiguousSpace, GeometryType, MultiPolygonGeometryType}; +use geo_types::{CoordNum, MultiPolygon, Polygon}; + +impl crate::multi_polygon::MultiPolygon for MultiPolygon { + type Polygon = Polygon; + + fn polygons(&self) -> impl Iterator { + self.0.iter() + } +} + +impl GeometryType for MultiPolygon { + type Type = MultiPolygonGeometryType; + type Space = AmbiguousSpace; +} diff --git a/galileo-types/src/geo_types/point.rs b/galileo-types/src/geo_types/point.rs new file mode 100644 index 0000000..3d2a93a --- /dev/null +++ b/galileo-types/src/geo_types/point.rs @@ -0,0 +1,49 @@ +use crate::cartesian::traits::cartesian_point::{CartesianPoint2d, NewCartesianPoint2d}; +use crate::geo::traits::point::{GeoPoint, NewGeoPoint}; +use crate::geometry_type::{AmbiguousSpace, GeometryType, PointGeometryType}; +use geo_types::{point, CoordNum}; +use nalgebra::Scalar; +use num_traits::{Bounded, Float, FromPrimitive}; + +impl CartesianPoint2d for geo_types::Point { + type Num = T; + + fn x(&self) -> Self::Num { + self.0.x + } + + fn y(&self) -> Self::Num { + self.0.y + } +} + +impl NewCartesianPoint2d + for geo_types::Point +{ + fn new(x: T, y: T) -> Self { + point!(x: x, y: y) + } +} + +impl GeometryType for geo_types::Point { + type Type = PointGeometryType; + type Space = AmbiguousSpace; +} + +impl GeoPoint for geo_types::Point { + type Num = T; + + fn lat(&self) -> Self::Num { + self.y() + } + + fn lon(&self) -> Self::Num { + self.x() + } +} + +impl NewGeoPoint for geo_types::Point { + fn latlon(lat: T, lon: T) -> Self { + point!(x: lon, y: lat) + } +} diff --git a/galileo-types/src/geo_types/polygon.rs b/galileo-types/src/geo_types/polygon.rs new file mode 100644 index 0000000..c12355c --- /dev/null +++ b/galileo-types/src/geo_types/polygon.rs @@ -0,0 +1,20 @@ +use crate::geometry_type::{AmbiguousSpace, GeometryType, PolygonGeometryType}; +use crate::polygon::Polygon; +use geo_types::{CoordNum, LineString}; + +impl Polygon for geo_types::Polygon { + type Contour = LineString; + + fn outer_contour(&self) -> &Self::Contour { + self.exterior() + } + + fn inner_contours(&self) -> impl Iterator { + self.interiors().iter() + } +} + +impl GeometryType for geo_types::Polygon { + type Type = PolygonGeometryType; + type Space = AmbiguousSpace; +} diff --git a/galileo-types/src/geometry.rs b/galileo-types/src/geometry.rs index eda706f..6d0ba64 100644 --- a/galileo-types/src/geometry.rs +++ b/galileo-types/src/geometry.rs @@ -4,20 +4,24 @@ use crate::cartesian::impls::polygon::Polygon; use crate::cartesian::rect::Rect; use crate::cartesian::traits::cartesian_point::CartesianPoint2d; use crate::geo::traits::projection::Projection; +use crate::geometry_type::GeometryType; +use crate::impls::multi_contour::MultiContour; +use crate::impls::multi_point::MultiPoint; pub enum Geom

{ Point(P), - Line(Contour

), + MultiPoint(MultiPoint

), + Contour(Contour

), + MultiContour(MultiContour

), Polygon(Polygon

), MultiPolygon(MultiPolygon

), } pub trait Geometry { type Point; - fn project + ?Sized>( - &self, - projection: &P, - ) -> Option>; + fn project(&self, projection: &Proj) -> Option> + where + Proj: Projection + ?Sized; } pub trait CartesianGeometry2d: Geometry { @@ -37,7 +41,7 @@ impl

From

for Geom

{ impl

From> for Geom

{ fn from(value: Contour

) -> Self { - Self::Line(value) + Self::Contour(value) } } @@ -52,3 +56,31 @@ impl

From> for Geom

{ Self::MultiPolygon(value) } } + +pub trait GeometrySpecialization: GeometryType { + type Point; + + fn project(&self, projection: &Proj) -> Option> + where + Proj: Projection + ?Sized; +} + +impl Geometry for T +where + T: GeometrySpecialization<::Type, ::Space>, +{ + type Point = ::Type, + ::Space, + >>::Point; + + fn project(&self, projection: &Proj) -> Option> + where + Proj: Projection + ?Sized, + { + ::Type, + ::Space, + >>::project(self, projection) + } +} diff --git a/galileo-types/src/geometry_type.rs b/galileo-types/src/geometry_type.rs new file mode 100644 index 0000000..543a755 --- /dev/null +++ b/galileo-types/src/geometry_type.rs @@ -0,0 +1,24 @@ +pub trait GeometryType { + type Type; + type Space; +} + +pub struct PointGeometryType; + +pub struct MultiPointGeometryType; + +pub struct ContourGeometryType; + +pub struct MultiContourGeometryType; + +pub struct PolygonGeometryType; + +pub struct MultiPolygonGeometryType; + +pub struct GeoSpace2d; + +pub struct CartesianSpace2d; + +pub struct CartesianSpace3d; + +pub struct AmbiguousSpace; diff --git a/galileo-types/src/impls/mod.rs b/galileo-types/src/impls/mod.rs new file mode 100644 index 0000000..658e2bc --- /dev/null +++ b/galileo-types/src/impls/mod.rs @@ -0,0 +1,2 @@ +pub mod multi_contour; +pub mod multi_point; diff --git a/galileo-types/src/impls/multi_contour.rs b/galileo-types/src/impls/multi_contour.rs new file mode 100644 index 0000000..82647a4 --- /dev/null +++ b/galileo-types/src/impls/multi_contour.rs @@ -0,0 +1,17 @@ +use crate::cartesian::impls::contour::Contour; + +pub struct MultiContour

(Vec>); + +impl

crate::multi_contour::MultiContour for MultiContour

{ + type Contour = Contour

; + + fn contours(&self) -> impl Iterator { + self.0.iter() + } +} + +impl

From>> for MultiContour

{ + fn from(value: Vec>) -> Self { + Self(value) + } +} diff --git a/galileo-types/src/impls/multi_point.rs b/galileo-types/src/impls/multi_point.rs new file mode 100644 index 0000000..5d53730 --- /dev/null +++ b/galileo-types/src/impls/multi_point.rs @@ -0,0 +1,15 @@ +pub struct MultiPoint

(Vec

); + +impl

crate::multi_point::MultiPoint for MultiPoint

{ + type Point = P; + + fn iter_points(&self) -> impl Iterator { + self.0.iter() + } +} + +impl

From> for MultiPoint

{ + fn from(value: Vec

) -> Self { + Self(value) + } +} diff --git a/galileo-types/src/lib.rs b/galileo-types/src/lib.rs index 6907cb6..94905cc 100644 --- a/galileo-types/src/lib.rs +++ b/galileo-types/src/lib.rs @@ -1,5 +1,16 @@ pub mod cartesian; +pub mod contour; +pub mod disambig; pub mod geo; pub mod geometry; +pub mod geometry_type; +pub mod impls; +pub mod multi_contour; +pub mod multi_point; +pub mod multi_polygon; pub mod point; +pub mod polygon; pub mod segment; + +#[cfg(feature = "geo-types")] +pub mod geo_types; diff --git a/galileo-types/src/multi_contour.rs b/galileo-types/src/multi_contour.rs new file mode 100644 index 0000000..05c491b --- /dev/null +++ b/galileo-types/src/multi_contour.rs @@ -0,0 +1,34 @@ +use crate::contour::Contour; +use crate::geo::traits::projection::Projection; +use crate::geometry::{Geom, Geometry, GeometrySpecialization}; +use crate::geometry_type::{GeometryType, MultiContourGeometryType}; + +pub trait MultiContour { + type Contour: Contour; + + fn contours(&self) -> impl Iterator; +} + +impl GeometrySpecialization for C +where + C: MultiContour + GeometryType, + C::Contour: Geometry, +{ + type Point = ::Point; + + fn project(&self, projection: &Proj) -> Option> + where + Proj: Projection + ?Sized, + { + let contours = self + .contours() + .map(|c| { + c.project(projection).and_then(|c| match c { + Geom::Contour(contour) => Some(contour), + _ => None, + }) + }) + .collect::>>>()?; + Some(Geom::MultiContour(contours.into())) + } +} diff --git a/galileo-types/src/multi_point.rs b/galileo-types/src/multi_point.rs new file mode 100644 index 0000000..986ad90 --- /dev/null +++ b/galileo-types/src/multi_point.rs @@ -0,0 +1,27 @@ +use crate::geo::traits::projection::Projection; +use crate::geometry::{Geom, GeometrySpecialization}; +use crate::geometry_type::{GeometryType, MultiPointGeometryType}; + +pub trait MultiPoint { + type Point; + + fn iter_points(&self) -> impl Iterator; +} + +impl GeometrySpecialization for P +where + P: MultiPoint + GeometryType, +{ + type Point = P::Point; + + fn project(&self, projection: &Proj) -> Option> + where + Proj: Projection + ?Sized, + { + let points = self + .iter_points() + .map(|p| projection.project(p)) + .collect::>>()?; + Some(Geom::MultiPoint(points.into())) + } +} diff --git a/galileo-types/src/multi_polygon.rs b/galileo-types/src/multi_polygon.rs new file mode 100644 index 0000000..3bc776d --- /dev/null +++ b/galileo-types/src/multi_polygon.rs @@ -0,0 +1,34 @@ +use crate::cartesian::impls::polygon::Polygon; +use crate::geo::traits::projection::Projection; +use crate::geometry::{Geom, Geometry, GeometrySpecialization}; +use crate::geometry_type::{GeometryType, MultiPolygonGeometryType}; + +pub trait MultiPolygon { + type Polygon; + + fn polygons(&self) -> impl Iterator; +} + +impl GeometrySpecialization for Poly +where + Poly: MultiPolygon + GeometryType, + Poly::Polygon: Geometry, +{ + type Point = ::Point; + + fn project(&self, projection: &Proj) -> Option> + where + Proj: Projection + ?Sized, + { + let polygons = self + .polygons() + .map(|c| { + c.project(projection).and_then(|c| match c { + Geom::Polygon(polygon) => Some(polygon), + _ => None, + }) + }) + .collect::>>>()?; + Some(Geom::MultiPolygon(polygons.into())) + } +} diff --git a/galileo-types/src/polygon.rs b/galileo-types/src/polygon.rs new file mode 100644 index 0000000..4ca64a7 --- /dev/null +++ b/galileo-types/src/polygon.rs @@ -0,0 +1,52 @@ +use crate::contour::Contour; +use crate::geo::traits::projection::Projection; +use crate::geometry::{Geom, Geometry, GeometrySpecialization}; +use crate::geometry_type::{GeometryType, PolygonGeometryType}; +use crate::segment::Segment; + +pub trait Polygon { + type Contour: Contour; + + fn outer_contour(&self) -> &Self::Contour; + fn inner_contours(&self) -> impl Iterator; + + fn iter_contours(&self) -> impl Iterator { + Box::new(std::iter::once(self.outer_contour()).chain(self.inner_contours())) + } + + fn iter_segments( + &self, + ) -> impl Iterator::Point>> { + Box::new(self.iter_contours().flat_map(Self::Contour::iter_segments)) + } +} + +impl GeometrySpecialization for Poly +where + Poly: Polygon + GeometryType, + Poly::Contour: Geometry, +{ + type Point = ::Point; + + fn project(&self, projection: &Proj) -> Option> + where + Proj: Projection + ?Sized, + { + let Geom::Contour(outer_contour) = self.outer_contour().project(projection)? else { + return None; + }; + let inner_contours = self + .inner_contours() + .map(|c| { + c.project(projection).and_then(|c| match c { + Geom::Contour(contour) => contour.into_closed(), + _ => None, + }) + }) + .collect::>>>()?; + Some(Geom::Polygon(crate::cartesian::impls::polygon::Polygon { + outer_contour: outer_contour.into_closed()?, + inner_contours, + })) + } +} diff --git a/galileo/Cargo.toml b/galileo/Cargo.toml index 8d9a78a..32e0633 100644 --- a/galileo/Cargo.toml +++ b/galileo/Cargo.toml @@ -72,3 +72,5 @@ approx = "0.5" lazy_static = "1.4" geo = "0.27" csv = "1.3" +geo-types = "0.7" +geozero = "0.11" \ No newline at end of file diff --git a/galileo/examples/data/Museums 2021.geojson b/galileo/examples/data/Museums 2021.geojson new file mode 100644 index 0000000..27f63d0 --- /dev/null +++ b/galileo/examples/data/Museums 2021.geojson @@ -0,0 +1 @@ +{"type":"FeatureCollection","features":[{"type":"Feature","properties":{"NAME":"Bankfield Museum","INFORMATION":"http://museums.calderdale.gov.uk/visit/bankfield-museum","Easting":"409110.295","Northing":"426249.673"},"geometry":{"type":"Point","coordinates":[-1.863383,53.732562]}},{"type":"Feature","properties":{"NAME":"Duke of Wellington's Regiment Museum","INFORMATION":"http://museums.calderdale.gov.uk/visit/duke-wellingtons-regiment-museum","Easting":"409110.295","Northing":"426249.673"},"geometry":{"type":"Point","coordinates":[-1.863383,53.732562]}},{"type":"Feature","properties":{"NAME":"Shibden Hall Museum","INFORMATION":"http://museums.calderdale.gov.uk/visit/shibden-hall","Easting":"410656.198","Northing":"425774.815"},"geometry":{"type":"Point","coordinates":[-1.839966,53.728265]}},{"type":"Feature","properties":{"NAME":"Smith Art Gallery","INFORMATION":"http://museums.calderdale.gov.uk/visit/smith-art-gallery","Easting":"414216.415","Northing":"423086.01"},"geometry":{"type":"Point","coordinates":[-1.786128,53.704014]}}]} \ No newline at end of file diff --git a/galileo/examples/feature_layers.rs b/galileo/examples/feature_layers.rs index 8980e31..cc53a79 100644 --- a/galileo/examples/feature_layers.rs +++ b/galileo/examples/feature_layers.rs @@ -7,8 +7,10 @@ use galileo::layer::feature_layer::FeatureLayer; use galileo::primitives::Color; use galileo::render::{PointPaint, PrimitiveId, RenderBundle, UnpackedBundle}; use galileo_types::cartesian::impls::point::{Point2d, Point3d}; +use galileo_types::cartesian::impls::polygon::Polygon; use galileo_types::geo::crs::Crs; use galileo_types::geometry::Geom; +use galileo_types::geometry_type::CartesianSpace2d; use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::{Arc, RwLock}; @@ -122,18 +124,16 @@ pub async fn run(builder: MapBuilder) { struct CountrySymbol {} impl CountrySymbol { - fn get_polygon_symbol(&self, feature: &Country) -> SimplePolygonSymbol { + fn get_polygon_symbol(&self, feature: &Country) -> SimplePolygonSymbol { let stroke_color = feature.color; let fill_color = Color { a: if feature.is_selected() { 255 } else { 150 }, ..stroke_color }; - SimplePolygonSymbol { - fill_color, - stroke_color, - stroke_width: 1.0, - stroke_offset: -0.5, - } + SimplePolygonSymbol::new(fill_color) + .with_stroke_color(stroke_color) + .with_stroke_width(1.0) + .with_stroke_offset(-0.5) } } @@ -153,7 +153,7 @@ impl Symbol> for CountrySymbol { ids.append( &mut self .get_polygon_symbol(feature) - .render(&(), &polygon, bundle), + .render(&(), polygon, bundle), ) } @@ -169,7 +169,9 @@ impl Symbol> for CountrySymbol { let renders_by_feature = render_ids.len() / feature.geometry.parts().len(); let mut next_index = 0; for _ in feature.geometry.parts() { - self.get_polygon_symbol(feature).update( + let polygon_symbol = self.get_polygon_symbol(feature); + as Symbol<(), Polygon>>::update( + &polygon_symbol, &(), &render_ids[next_index..next_index + renders_by_feature], bundle, diff --git a/galileo/examples/georust.rs b/galileo/examples/georust.rs new file mode 100644 index 0000000..cbdd7f4 --- /dev/null +++ b/galileo/examples/georust.rs @@ -0,0 +1,58 @@ +use galileo::galileo_map::MapBuilder; +use galileo::layer::feature_layer::symbol::point::CirclePointSymbol; +use galileo::layer::feature_layer::FeatureLayer; +use galileo::primitives::Color; +use galileo::tile_scheme::TileScheme; +use galileo_types::disambig::{Disambig, Disambiguate}; +use galileo_types::geo::crs::Crs; +use galileo_types::geometry_type::GeoSpace2d; +use galileo_types::latlon; +use geozero::geojson::GeoJson; +use geozero::ToGeo; + +#[cfg(not(target_arch = "wasm32"))] +#[tokio::main] +async fn main() { + env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("info")).init(); + run(MapBuilder::new()).await; +} + +fn load_points() -> Vec> { + let json = include_str!("./data/Museums 2021.geojson"); + let geojson = GeoJson(json); + match geojson.to_geo().unwrap() { + geo_types::Geometry::GeometryCollection(points) => points + .iter() + .map(|p| match p { + geo_types::Geometry::Point(p) => p.to_geo2d(), + _ => panic!("not points"), + }) + .collect(), + _ => panic!("not geometry collection"), + } +} + +pub async fn run(builder: MapBuilder) { + let point_layer = FeatureLayer::new( + load_points(), + CirclePointSymbol::new(Color::RED, 10.0), + Crs::WGS84, + ); + + builder + .center(latlon!(53.732562, -1.863383)) + .resolution(50.0) + .with_raster_tiles( + |index| { + format!( + "https://tile.openstreetmap.org/{}/{}/{}.png", + index.z, index.x, index.y + ) + }, + TileScheme::web(18), + ) + .with_layer(point_layer) + .build() + .await + .run(); +} diff --git a/galileo/examples/lambert.rs b/galileo/examples/lambert.rs index fc26806..280a7e5 100644 --- a/galileo/examples/lambert.rs +++ b/galileo/examples/lambert.rs @@ -8,12 +8,14 @@ use galileo::primitives::Color; use galileo::render::{PrimitiveId, RenderBundle, UnpackedBundle}; use galileo::view::MapView; use galileo_types::cartesian::impls::point::Point2d; +use galileo_types::cartesian::impls::polygon::Polygon; use galileo_types::geo::crs::{Crs, ProjectionType}; use galileo_types::geo::datum::Datum; use galileo_types::geo::impls::point::GeoPoint2d; use galileo_types::geo::traits::point::NewGeoPoint; use galileo_types::geo::traits::projection::{ChainProjection, InvertedProjection, Projection}; use galileo_types::geometry::Geom; +use galileo_types::geometry_type::CartesianSpace2d; use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::{Arc, RwLock}; @@ -105,18 +107,16 @@ pub async fn run(builder: MapBuilder) { struct CountrySymbol {} impl CountrySymbol { - fn get_polygon_symbol(&self, feature: &Country) -> SimplePolygonSymbol { + fn get_polygon_symbol(&self, feature: &Country) -> SimplePolygonSymbol { let stroke_color = feature.color; let fill_color = Color { a: if feature.is_selected() { 255 } else { 150 }, ..stroke_color }; - SimplePolygonSymbol { - fill_color, - stroke_color, - stroke_width: 1.0, - stroke_offset: -0.5, - } + SimplePolygonSymbol::new(fill_color) + .with_stroke_color(stroke_color) + .with_stroke_width(1.0) + .with_stroke_offset(-0.5) } } @@ -136,7 +136,7 @@ impl Symbol> for CountrySymbol { ids.append( &mut self .get_polygon_symbol(feature) - .render(&(), &polygon, bundle), + .render(&(), polygon, bundle), ) } @@ -152,7 +152,9 @@ impl Symbol> for CountrySymbol { let renders_by_feature = render_ids.len() / feature.geometry.parts().len(); let mut next_index = 0; for _ in feature.geometry.parts() { - self.get_polygon_symbol(feature).update( + let polygon_symbol = self.get_polygon_symbol(feature); + as Symbol<(), Polygon>>::update( + &polygon_symbol, &(), &render_ids[next_index..next_index + renders_by_feature], bundle, diff --git a/galileo/src/layer/feature_layer/mod.rs b/galileo/src/layer/feature_layer/mod.rs index d7bdda9..478eaf9 100644 --- a/galileo/src/layer/feature_layer/mod.rs +++ b/galileo/src/layer/feature_layer/mod.rs @@ -5,21 +5,25 @@ use crate::messenger::Messenger; use crate::render::wgpu::WgpuRenderer; use crate::render::{Canvas, PackedBundle, PrimitiveId, Renderer}; use crate::view::MapView; -use galileo_types::cartesian::impls::point::{Point2d, Point3d}; -use galileo_types::cartesian::traits::cartesian_point::CartesianPoint2d; +use galileo_types::cartesian::impls::point::Point2d; +use galileo_types::cartesian::traits::cartesian_point::{ + CartesianPoint2d, NewCartesianPoint2d, NewCartesianPoint3d, +}; use galileo_types::geo::crs::Crs; use galileo_types::geo::impls::point::GeoPoint2d; use galileo_types::geo::impls::projection::identity::IdentityProjection; +use galileo_types::geo::traits::point::NewGeoPoint; use galileo_types::geo::traits::projection::{ChainProjection, InvertedProjection, Projection}; use galileo_types::geometry::{CartesianGeometry2d, Geom, Geometry}; +use galileo_types::geometry_type::{CartesianSpace2d, CartesianSpace3d, GeoSpace2d}; use maybe_sync::{MaybeSend, MaybeSync}; -use std::any::Any; +use std::marker::PhantomData; use std::sync::{Arc, RwLock}; pub mod feature; pub mod symbol; -pub struct FeatureLayer +pub struct FeatureLayer where F: Feature, F::Geom: Geometry, @@ -30,9 +34,11 @@ where feature_render_map: RwLock>>, crs: Crs, messenger: RwLock>>, + + space: PhantomData, } -impl FeatureLayer +impl FeatureLayer where F: Feature, F::Geom: Geometry, @@ -45,11 +51,12 @@ where feature_render_map: RwLock::new(Vec::new()), crs, messenger: RwLock::new(None), + space: Default::default(), } } } -impl FeatureLayer +impl FeatureLayer where P: CartesianPoint2d, F: Feature, @@ -98,7 +105,7 @@ where } } -impl FeatureLayer +impl FeatureLayer where F: Feature, F::Geom: Geometry, @@ -128,20 +135,18 @@ where } } -impl Layer for FeatureLayer +impl Layer for FeatureLayer where + P: NewGeoPoint + 'static, F: Feature + MaybeSend + MaybeSync, - F::Geom: Geometry, + F::Geom: Geometry, S: Symbol> + MaybeSend + MaybeSync, { fn render(&self, position: &MapView, canvas: &mut dyn Canvas) { if self.render_bundle.read().unwrap().is_none() { let mut bundle = canvas.create_bundle(); let mut render_map = self.feature_render_map.write().unwrap(); - let crs = position - .crs() - .get_projection::() - .unwrap(); + let crs = position.crs().get_projection::().unwrap(); for feature in &self.features { let Some(projected) = feature.geometry().project(&(*crs)) else { continue; @@ -164,21 +169,14 @@ where fn set_messenger(&self, messenger: Box) { *self.messenger.write().unwrap() = Some(messenger); } - - fn as_any(&self) -> &dyn Any { - todo!() - } - - fn as_any_mut(&mut self) -> &mut dyn Any { - todo!() - } } -impl Layer for FeatureLayer +impl Layer for FeatureLayer where + P: NewCartesianPoint2d + Clone + 'static, F: Feature + MaybeSend + MaybeSync, - F::Geom: Geometry, - S: Symbol> + MaybeSend + MaybeSync, + F::Geom: Geometry, + S: Symbol> + MaybeSend + MaybeSync, { fn render(&self, view: &MapView, canvas: &mut dyn Canvas) { if self.render_bundle.read().unwrap().is_none() { @@ -187,9 +185,9 @@ where let projection: Box> = if view.crs() == &self.crs { - Box::new(IdentityProjection::new()) + Box::new(IdentityProjection::::new()) } else { - let self_proj = self.crs.get_projection::().unwrap(); + let self_proj = self.crs.get_projection::().unwrap(); let view_proj = view.crs().get_projection().unwrap(); Box::new(ChainProjection::new( Box::new(InvertedProjection::new(self_proj)), @@ -219,20 +217,13 @@ where fn set_messenger(&self, messenger: Box) { *self.messenger.write().unwrap() = Some(messenger); } - - fn as_any(&self) -> &dyn Any { - todo!() - } - - fn as_any_mut(&mut self) -> &mut dyn Any { - todo!() - } } -impl Layer for FeatureLayer +impl Layer for FeatureLayer where + P: NewCartesianPoint3d, F: Feature + MaybeSend + MaybeSync, - F::Geom: Geometry, + F::Geom: Geometry, S: Symbol + MaybeSend + MaybeSync, { fn render(&self, view: &MapView, canvas: &mut dyn Canvas) { @@ -264,12 +255,4 @@ where fn set_messenger(&self, messenger: Box) { *self.messenger.write().unwrap() = Some(messenger); } - - fn as_any(&self) -> &dyn Any { - todo!() - } - - fn as_any_mut(&mut self) -> &mut dyn Any { - todo!() - } } diff --git a/galileo/src/layer/feature_layer/symbol/contour.rs b/galileo/src/layer/feature_layer/symbol/contour.rs index 60a9a2c..d264035 100644 --- a/galileo/src/layer/feature_layer/symbol/contour.rs +++ b/galileo/src/layer/feature_layer/symbol/contour.rs @@ -1,56 +1,115 @@ use crate::layer::feature_layer::symbol::Symbol; use crate::primitives::Color; use crate::render::{LineCap, LinePaint, PrimitiveId, RenderBundle, UnpackedBundle}; -use galileo_types::cartesian::impls::contour::Contour; use galileo_types::cartesian::impls::point::{Point2d, Point3d}; +use galileo_types::cartesian::traits::cartesian_point::NewCartesianPoint3d; +use galileo_types::contour::Contour; use galileo_types::geo::impls::projection::dimensions::AddDimensionProjection; +use galileo_types::geo::impls::projection::identity::IdentityProjection; +use galileo_types::geometry::Geom; +use galileo_types::geometry_type::{CartesianSpace2d, CartesianSpace3d}; +use galileo_types::multi_contour::MultiContour; +use std::marker::PhantomData; -pub struct SimpleContourSymbol { +pub struct SimpleContourSymbol { pub color: Color, pub width: f64, + + space: PhantomData, } -impl Symbol<(), Contour> for SimpleContourSymbol { - fn render( +impl SimpleContourSymbol { + pub fn new(color: Color, width: f64) -> Self { + Self { + color, + width, + space: Default::default(), + } + } + + fn render_internal( &self, - _feature: &(), - geometry: &Contour, + geometry: &galileo_types::cartesian::impls::contour::Contour, bundle: &mut Box, ) -> Vec { - let projection = AddDimensionProjection::new(0.0); - let id = bundle.add_line( - &geometry.project_points(&projection).unwrap(), + vec![bundle.add_line( + geometry, LinePaint { color: self.color, width: self.width, offset: 0.0, line_cap: LineCap::Butt, }, - 10000.0, - ); - - vec![id] + 1000.0, + )] } +} - fn update( +// impl Symbol for SimpleContourSymbol +// where +// C: Contour, +// C::Point: NewCartesianPoint2d, +// { +// fn render( +// &self, +// _feature: &F, +// geometry: &C, +// bundle: &mut Box, +// ) -> Vec { +// let projection = AddDimensionProjection::new(0.0); +// self.render_internal(&geometry.project_points(&projection).unwrap(), bundle) +// } +// +// fn update( +// &self, +// _feature: &F, +// _renders_ids: &[PrimitiveId], +// _bundle: &mut Box, +// ) { +// todo!() +// } +// } + +impl Symbol> for SimpleContourSymbol { + fn render( &self, - _feature: &(), - _renders_ids: &[PrimitiveId], - _bundle: &mut Box, - ) { - todo!() + _feature: &F, + geometry: &Geom, + bundle: &mut Box, + ) -> Vec { + match geometry { + Geom::Contour(contour) => { + let projection = AddDimensionProjection::new(0.0); + self.render_internal(&contour.project_points(&projection).unwrap(), bundle) + } + Geom::MultiContour(contours) => { + let projection = AddDimensionProjection::new(0.0); + contours + .contours() + .flat_map(|c| { + self.render_internal(&c.project_points(&projection).unwrap(), bundle) + }) + .collect() + } + _ => vec![], + } } } -impl Symbol> for SimpleContourSymbol { +impl Symbol for SimpleContourSymbol +where + C: Contour, + C::Point: NewCartesianPoint3d, +{ fn render( &self, _feature: &F, - geometry: &Contour, + geometry: &C, bundle: &mut Box, ) -> Vec { + let projection = IdentityProjection::::new(); let id = bundle.add_line( - geometry, + &geometry.project_points(&projection).unwrap(), LinePaint { color: self.color, width: self.width, diff --git a/galileo/src/layer/feature_layer/symbol/point.rs b/galileo/src/layer/feature_layer/symbol/point.rs index 1941600..30a88f2 100644 --- a/galileo/src/layer/feature_layer/symbol/point.rs +++ b/galileo/src/layer/feature_layer/symbol/point.rs @@ -1,20 +1,32 @@ use crate::layer::feature_layer::symbol::Symbol; use crate::primitives::Color; use crate::render::{PointPaint, PrimitiveId, RenderBundle, UnpackedBundle}; -use galileo_types::cartesian::impls::point::{Point2d, Point3d}; +use galileo_types::cartesian::impls::point::Point3d; +use galileo_types::cartesian::traits::cartesian_point::CartesianPoint2d; use galileo_types::geometry::Geom; +use galileo_types::geometry_type::{CartesianSpace2d, CartesianSpace3d}; +use galileo_types::multi_point::MultiPoint; use nalgebra::Point3; +use std::marker::PhantomData; -pub struct CirclePointSymbol { +pub struct CirclePointSymbol { pub color: Color, pub size: f64, + space: PhantomData, } -impl Symbol> for CirclePointSymbol { - fn render( +impl CirclePointSymbol { + pub fn new(color: Color, size: f64) -> Self { + Self { + color, + size, + space: Default::default(), + } + } + + fn render_internal( &self, - _feature: &T, - geometry: &Point3, + geometry: &Point3d, bundle: &mut Box, ) -> Vec { let paint = PointPaint { @@ -23,6 +35,17 @@ impl Symbol> for CirclePointSymbol { }; vec![bundle.add_point(geometry, paint)] } +} + +impl Symbol> for CirclePointSymbol { + fn render( + &self, + _feature: &T, + geometry: &Point3, + bundle: &mut Box, + ) -> Vec { + self.render_internal(geometry, bundle) + } fn update( &self, @@ -34,7 +57,7 @@ impl Symbol> for CirclePointSymbol { } } -impl Symbol> for CirclePointSymbol { +impl Symbol> for CirclePointSymbol { fn render( &self, feature: &T, @@ -43,6 +66,10 @@ impl Symbol> for CirclePointSymbol { ) -> Vec { match geometry { Geom::Point(p) => self.render(feature, p, bundle), + Geom::MultiPoint(points) => points + .iter_points() + .flat_map(|p| self.render_internal(p, bundle)) + .collect(), _ => vec![], } } @@ -57,15 +84,22 @@ impl Symbol> for CirclePointSymbol { } } -impl Symbol> for CirclePointSymbol { +impl Symbol> for CirclePointSymbol +where + P: CartesianPoint2d, +{ fn render( &self, - feature: &T, - geometry: &Geom, + _feature: &T, + geometry: &Geom

, bundle: &mut Box, ) -> Vec { match geometry { - Geom::Point(p) => self.render(feature, &Point3d::new(p.x, p.y, 0.0), bundle), + Geom::Point(p) => self.render_internal(&Point3d::new(p.x(), p.y(), 0.0), bundle), + Geom::MultiPoint(points) => points + .iter_points() + .flat_map(|p| self.render_internal(&Point3d::new(p.x(), p.y(), 0.0), bundle)) + .collect(), _ => vec![], } } diff --git a/galileo/src/layer/feature_layer/symbol/polygon.rs b/galileo/src/layer/feature_layer/symbol/polygon.rs index 7cf10c6..bf43688 100644 --- a/galileo/src/layer/feature_layer/symbol/polygon.rs +++ b/galileo/src/layer/feature_layer/symbol/polygon.rs @@ -4,24 +4,60 @@ use crate::render::{LineCap, LinePaint, Paint, PrimitiveId, RenderBundle, Unpack use galileo_types::cartesian::impls::point::Point2d; use galileo_types::cartesian::impls::polygon::Polygon; use galileo_types::geo::impls::projection::dimensions::AddDimensionProjection; +use galileo_types::geometry::Geom; +use galileo_types::geometry_type::CartesianSpace2d; +use galileo_types::multi_polygon::MultiPolygon; +use std::marker::PhantomData; -pub struct SimplePolygonSymbol { +#[derive(Debug, Clone, Copy)] +pub struct SimplePolygonSymbol { pub fill_color: Color, pub stroke_color: Color, pub stroke_width: f64, pub stroke_offset: f64, + space: PhantomData, } -impl Symbol<(), Polygon> for SimplePolygonSymbol { - fn render( +impl SimplePolygonSymbol { + pub fn new(fill_color: Color) -> Self { + Self { + fill_color, + stroke_color: Default::default(), + stroke_width: 0.0, + stroke_offset: 0.0, + space: Default::default(), + } + } + + pub fn with_stroke_color(&self, stroke_color: Color) -> Self { + Self { + stroke_color, + ..*self + } + } + + pub fn with_stroke_width(&self, stroke_width: f64) -> Self { + Self { + stroke_width, + ..*self + } + } + + pub fn with_stroke_offset(&self, stroke_offset: f64) -> Self { + Self { + stroke_offset, + ..*self + } + } + + fn render_internal( &self, - _feature: &(), - geometry: &Polygon, + polygon: &Polygon, bundle: &mut Box, ) -> Vec { let mut ids = vec![]; let id = bundle.add_polygon( - geometry, + polygon, Paint { color: self.fill_color, }, @@ -38,23 +74,18 @@ impl Symbol<(), Polygon> for SimplePolygonSymbol { }; let projection = AddDimensionProjection::new(0.0); - for contour in geometry.iter_contours() { + for contour in polygon.iter_contours() { ids.push(bundle.add_line( &contour.project_points(&projection).unwrap().into(), line_paint, - 10000.0, + 1000.0, )); } ids } - fn update( - &self, - _feature: &(), - renders_ids: &[PrimitiveId], - bundle: &mut Box, - ) { + fn update_internal(&self, renders_ids: &[PrimitiveId], bundle: &mut Box) { let poly_paint = Paint { color: self.fill_color, }; @@ -72,3 +103,49 @@ impl Symbol<(), Polygon> for SimplePolygonSymbol { } } } + +impl Symbol> for SimplePolygonSymbol { + fn render( + &self, + _feature: &F, + geometry: &Geom, + bundle: &mut Box, + ) -> Vec { + match geometry { + Geom::Polygon(polygon) => self.render_internal(polygon, bundle), + Geom::MultiPolygon(polygons) => polygons + .polygons() + .flat_map(|p| self.render_internal(p, bundle)) + .collect(), + _ => vec![], + } + } + + fn update( + &self, + _feature: &F, + renders_ids: &[PrimitiveId], + bundle: &mut Box, + ) { + self.update_internal(renders_ids, bundle) + } +} +impl Symbol> for SimplePolygonSymbol { + fn render( + &self, + _feature: &F, + geometry: &Polygon, + bundle: &mut Box, + ) -> Vec { + self.render_internal(geometry, bundle) + } + + fn update( + &self, + _feature: &F, + renders_ids: &[PrimitiveId], + bundle: &mut Box, + ) { + self.update_internal(renders_ids, bundle) + } +} diff --git a/galileo/src/layer/mod.rs b/galileo/src/layer/mod.rs index de87ff9..39f973c 100644 --- a/galileo/src/layer/mod.rs +++ b/galileo/src/layer/mod.rs @@ -2,7 +2,6 @@ use crate::messenger::Messenger; use crate::render::{Canvas, Renderer}; use crate::view::MapView; use maybe_sync::{MaybeSend, MaybeSync}; -use std::any::Any; use std::sync::{Arc, RwLock}; pub mod feature_layer; @@ -14,8 +13,6 @@ pub trait Layer: MaybeSend + MaybeSync { fn render(&self, view: &MapView, canvas: &mut dyn Canvas); fn prepare(&self, view: &MapView, renderer: &Arc>); fn set_messenger(&self, messenger: Box); - fn as_any(&self) -> &dyn Any; - fn as_any_mut(&mut self) -> &mut dyn Any; } impl Layer for Arc> { @@ -30,12 +27,4 @@ impl Layer for Arc> { fn set_messenger(&self, messenger: Box) { self.read().unwrap().set_messenger(messenger) } - - fn as_any(&self) -> &dyn Any { - todo!() - } - - fn as_any_mut(&mut self) -> &mut dyn Any { - todo!() - } } diff --git a/galileo/src/layer/raster_tile.rs b/galileo/src/layer/raster_tile.rs index 9533410..bee0991 100644 --- a/galileo/src/layer/raster_tile.rs +++ b/galileo/src/layer/raster_tile.rs @@ -8,7 +8,6 @@ use crate::tile_scheme::{TileIndex, TileScheme}; use crate::view::MapView; use async_trait::async_trait; use maybe_sync::Mutex; -use std::any::Any; use std::collections::{HashMap, HashSet}; use std::fmt::Debug; use std::sync::{Arc, RwLock}; @@ -234,14 +233,6 @@ impl Layer for RasterTileLayer { fn set_messenger(&self, messenger: Box) { self.tile_provider.set_messenger(messenger); } - - fn as_any(&self) -> &dyn Any { - self - } - - fn as_any_mut(&mut self) -> &mut dyn Any { - todo!() - } } #[cfg_attr(target_arch = "wasm32", async_trait(?Send))] diff --git a/galileo/src/layer/vector_tile_layer/mod.rs b/galileo/src/layer/vector_tile_layer/mod.rs index a521dbe..2a3dd74 100644 --- a/galileo/src/layer/vector_tile_layer/mod.rs +++ b/galileo/src/layer/vector_tile_layer/mod.rs @@ -5,7 +5,6 @@ use crate::render::{Canvas, PackedBundle, Renderer}; use crate::tile_scheme::TileScheme; use crate::view::MapView; use nalgebra::Point2; -use std::any::Any; use std::collections::HashSet; use std::sync::{Arc, RwLock}; @@ -48,14 +47,6 @@ impl Layer for VectorTileLayer fn set_messenger(&self, messenger: Box) { self.tile_provider.set_messenger(messenger); } - - fn as_any(&self) -> &dyn Any { - self - } - - fn as_any_mut(&mut self) -> &mut dyn Any { - self - } } impl VectorTileLayer { diff --git a/galileo/src/primitives.rs b/galileo/src/primitives.rs index 0bc67e8..db5e748 100644 --- a/galileo/src/primitives.rs +++ b/galileo/src/primitives.rs @@ -52,7 +52,13 @@ impl From for String { } impl Color { - pub fn rgba(r: u8, g: u8, b: u8, a: u8) -> Self { + pub const RED: Color = Color::rgba(255, 0, 0, 255); + pub const GREEN: Color = Color::rgba(0, 255, 0, 255); + pub const BLUE: Color = Color::rgba(0, 0, 255, 255); + pub const WHITE: Color = Color::rgba(255, 255, 255, 255); + pub const BLACK: Color = Color::rgba(0, 0, 0, 255); + + pub const fn rgba(r: u8, g: u8, b: u8, a: u8) -> Self { Self { r, g, b, a } } diff --git a/galileo/src/render/wgpu.rs b/galileo/src/render/wgpu.rs index e00b79c..744685f 100644 --- a/galileo/src/render/wgpu.rs +++ b/galileo/src/render/wgpu.rs @@ -478,8 +478,7 @@ impl<'a> Canvas for WgpuCanvas<'a> { ); render_pass.draw_indexed(0..cast.index_count(), 0, 0..1); - if cast.point_buffers.index_count > 0 { - let point_buffers = &cast.point_buffers; + if let Some(point_buffers) = &cast.point_buffers { render_pass.set_pipeline(&self.renderer.point_pipeline); render_pass.set_bind_group(0, &self.renderer.map_view_bind_group, &[]); render_pass.set_vertex_buffer(0, point_buffers.vertex.slice(..)); @@ -716,7 +715,7 @@ impl RenderBundle for WgpuRenderBundle { pub struct WgpuPackedBundle { vertex_buffers: VertexBuffers, wgpu_buffers: WgpuPolygonBuffers, - point_buffers: WgpuPointBuffers, + point_buffers: Option, image_buffers: Vec, primitives: Vec, } @@ -759,43 +758,47 @@ impl WgpuPackedBundle { contents: bytemuck::cast_slice(&vertex_buffers.vertices), }); - let max_point_size = points.iter().fold(0f32, |v, p| v.max(p.size)); - let (point_indices, point_vertices) = create_point(max_point_size); - - let point_index_buffer = - renderer - .device - .create_buffer_init(&wgpu::util::BufferInitDescriptor { - label: None, - contents: bytemuck::cast_slice(&point_indices), - usage: wgpu::BufferUsages::INDEX, - }); - - let point_vertex_buffer = - renderer - .device - .create_buffer_init(&wgpu::util::BufferInitDescriptor { - label: None, - usage: wgpu::BufferUsages::VERTEX, - contents: bytemuck::cast_slice(&point_vertices), - }); - - let point_instance_buffer = - renderer - .device - .create_buffer_init(&wgpu::util::BufferInitDescriptor { - label: None, - usage: wgpu::BufferUsages::VERTEX, - contents: bytemuck::cast_slice(&points), - }); - - let point_buffers = WgpuPointBuffers { - index: point_index_buffer, - vertex: point_vertex_buffer, - instance: point_instance_buffer, - index_count: point_indices.len() as u32, - instance_count: points.len() as u32, - vertices: points, + let point_buffers = if !points.is_empty() { + let max_point_size = points.iter().fold(0f32, |v, p| v.max(p.size)); + let (point_indices, point_vertices) = create_point(max_point_size); + + let point_index_buffer = + renderer + .device + .create_buffer_init(&wgpu::util::BufferInitDescriptor { + label: None, + contents: bytemuck::cast_slice(&point_indices), + usage: wgpu::BufferUsages::INDEX, + }); + + let point_vertex_buffer = + renderer + .device + .create_buffer_init(&wgpu::util::BufferInitDescriptor { + label: None, + usage: wgpu::BufferUsages::VERTEX, + contents: bytemuck::cast_slice(&point_vertices), + }); + + let point_instance_buffer = + renderer + .device + .create_buffer_init(&wgpu::util::BufferInitDescriptor { + label: None, + usage: wgpu::BufferUsages::VERTEX, + contents: bytemuck::cast_slice(&points), + }); + + Some(WgpuPointBuffers { + index: point_index_buffer, + vertex: point_vertex_buffer, + instance: point_instance_buffer, + index_count: point_indices.len() as u32, + instance_count: points.len() as u32, + vertices: points, + }) + } else { + None }; let mut image_buffers = vec![]; @@ -828,7 +831,7 @@ fn create_point(max_size: f32) -> (Vec, Vec) { let center = PointVertex { norm: [0.0, 0.0] }; - const TOLERANCE: f32 = 0.25; + const TOLERANCE: f32 = 0.1; let r = half_size.max(1.0); let steps_count = (std::f32::consts::PI / ((r - TOLERANCE) / (r + TOLERANCE)).acos()).ceil() as usize; @@ -873,7 +876,7 @@ impl PackedBundle for WgpuPackedBundle { struct WgpuUnpackedBundle { vertex_buffers: VertexBuffers, wgpu_buffers: WgpuPolygonBuffers, - point_buffers: WgpuPointBuffers, + point_buffers: Option, images: Vec, primitives: Vec, @@ -989,8 +992,11 @@ impl UnpackedBundle for WgpuUnpackedBundle { let Some(PrimitiveInfo::Point { point_index }) = self.primitives.get(id.0) else { return; }; + let Some(point_buffers) = &mut self.point_buffers else { + return; + }; - let point = &mut self.point_buffers.vertices[*point_index]; + let point = &mut point_buffers.vertices[*point_index]; point.color = paint.color.to_f32_array(); point.size = paint.size as f32;