Skip to content

Commit

Permalink
Support running map without a window (Maximkaaa#34)
Browse files Browse the repository at this point in the history
* Add an example to draw map to a file
* Support GeoJson loading
* Add examples description
  • Loading branch information
Maximkaaa authored Jan 31, 2024
1 parent 7ff4173 commit b567845
Show file tree
Hide file tree
Showing 41 changed files with 1,174 additions and 199 deletions.
4 changes: 3 additions & 1 deletion galileo-types/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,6 @@ num-traits = "0.2.17"
nalgebra = "0.32"
serde = { version = "1.0", features = ["derive"] }
geodesy = "0.11.1"
geo-types = { version = "0.7", optional = true }
geo-types = { version = "0.7", optional = true }
geojson = { version = "0.24", optional = true }
thiserror = "1.0"
26 changes: 0 additions & 26 deletions galileo-types/src/cartesian/impls/contour.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,5 @@
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;
use crate::geometry_type::{ContourGeometryType, GeometryType};
use num_traits::Float;
use serde::{Deserialize, Serialize};

#[derive(Debug, Clone, Serialize, Deserialize)]
Expand Down Expand Up @@ -130,24 +125,3 @@ impl<P: GeometryType> GeometryType for ClosedContour<P> {
type Type = ContourGeometryType;
type Space = P::Space;
}

impl<N, P: GeometryType> CartesianGeometry2d<P> for Contour<P>
where
N: Float,
P: CartesianPoint2d<Num = N>,
{
fn is_point_inside<Other: CartesianPoint2d<Num = P::Num>>(
&self,
point: &Other,
tolerance: P::Num,
) -> bool {
let Some(distance) = self.distance_to_point_sq(point) else {
return false;
};
distance <= tolerance * tolerance
}

fn bounding_rectangle(&self) -> Rect<P::Num> {
todo!()
}
}
22 changes: 0 additions & 22 deletions galileo-types/src/cartesian/impls/multipolygon.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
use crate::cartesian::impls::polygon::Polygon;
use crate::cartesian::rect::Rect;
use crate::cartesian::traits::cartesian_point::CartesianPoint2d;
use crate::geometry::CartesianGeometry2d;
use crate::geometry_type::{GeometryType, MultiPolygonGeometryType};
use serde::{Deserialize, Serialize};

Expand Down Expand Up @@ -34,22 +31,3 @@ impl<P: GeometryType> GeometryType for MultiPolygon<P> {
type Type = MultiPolygonGeometryType;
type Space = P::Space;
}

impl<P: GeometryType> CartesianGeometry2d<P> for MultiPolygon<P>
where
P: CartesianPoint2d,
{
fn is_point_inside<Other: CartesianPoint2d<Num = P::Num>>(
&self,
point: &Other,
tolerance: P::Num,
) -> bool {
self.parts
.iter()
.any(|p| p.is_point_inside(point, tolerance))
}

fn bounding_rectangle(&self) -> Rect<P::Num> {
todo!()
}
}
21 changes: 0 additions & 21 deletions galileo-types/src/cartesian/impls/polygon.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,4 @@
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::geometry::CartesianGeometry2d;
use crate::geometry_type::{GeometryType, PolygonGeometryType};
use serde::{Deserialize, Serialize};

Expand Down Expand Up @@ -63,20 +59,3 @@ impl<P: GeometryType> GeometryType for Polygon<P> {
type Type = PolygonGeometryType;
type Space = P::Space;
}

impl<P: GeometryType> CartesianGeometry2d<P> for Polygon<P>
where
P: CartesianPoint2d,
{
fn is_point_inside<Other: CartesianPoint2d<Num = P::Num>>(
&self,
point: &Other,
_tolerance: P::Num,
) -> bool {
self.contains_point(point)
}

fn bounding_rectangle(&self) -> Rect<P::Num> {
todo!()
}
}
14 changes: 14 additions & 0 deletions galileo-types/src/cartesian/rect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -208,3 +208,17 @@ impl<N: Num + Copy + PartialOrd + Scalar + FromPrimitive> FromIterator<Rect<N>>
curr
}
}

impl<N: Num + Copy + PartialOrd + Scalar + FromPrimitive> FromIterator<Rect<N>>
for Option<Rect<N>>
{
fn from_iter<T: IntoIterator<Item = Rect<N>>>(iter: T) -> Self {
let mut iter = iter.into_iter();
let mut prev = iter.next()?;
for next in iter {
prev = prev.merge(next);
}

Some(prev)
}
}
19 changes: 12 additions & 7 deletions galileo-types/src/cartesian/size.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,14 @@
use num_traits::real::Real;
use num_traits::FromPrimitive;
use num_traits::{FromPrimitive, NumCast};

#[derive(Debug, Clone, Copy, Default)]
pub struct Size<Num: num_traits::Num + PartialOrd + Copy = f64> {
width: Num,
height: Num,
}

impl<Num: Real + FromPrimitive> Size<Num> {
impl<Num: num_traits::Num + FromPrimitive + PartialOrd + Copy + NumCast> Size<Num> {
pub fn new(width: Num, height: Num) -> Self {
Self {
width: width.max(Num::zero()),
height: height.max(Num::zero()),
}
Self { width, height }
}

pub fn width(&self) -> Num {
Expand All @@ -34,4 +30,13 @@ impl<Num: Real + FromPrimitive> Size<Num> {
pub fn is_zero(&self) -> bool {
self.width.is_zero() || self.height.is_zero()
}

pub fn cast<T: num_traits::Num + FromPrimitive + PartialOrd + Copy + NumCast>(
&self,
) -> Size<T> {
Size {
width: NumCast::from(self.width).unwrap(),
height: NumCast::from(self.height).unwrap(),
}
}
}
22 changes: 20 additions & 2 deletions galileo-types/src/cartesian/traits/cartesian_point.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use crate::cartesian::rect::Rect;
use crate::geo::traits::projection::Projection;
use crate::geometry::{Geom, GeometrySpecialization};
use crate::geometry::{CartesianGeometry2dSpecialization, Geom, GeometrySpecialization};
use crate::geometry_type::{CartesianSpace2d, GeometryType, PointGeometryType};
use crate::point::{CartesianPointType, Point, PointHelper};
use nalgebra::{Point2, Scalar, Vector2};
Expand Down Expand Up @@ -85,10 +86,27 @@ where
{
type Point = P;

fn project<Proj>(&self, projection: &Proj) -> Option<Geom<Proj::OutPoint>>
fn project_spec<Proj>(&self, projection: &Proj) -> Option<Geom<Proj::OutPoint>>
where
Proj: Projection<InPoint = Self::Point> + ?Sized,
{
Some(Geom::Point(projection.project(self)?))
}
}

impl<P> CartesianGeometry2dSpecialization<P, PointGeometryType> for P
where
P: CartesianPoint2d + GeometryType<Type = PointGeometryType, Space = CartesianSpace2d>,
{
fn is_point_inside_spec<Other: CartesianPoint2d<Num = P::Num>>(
&self,
point: &Other,
tolerance: P::Num,
) -> bool {
self.distance_sq(point) < tolerance * tolerance
}

fn bounding_rectangle_spec(&self) -> Option<Rect<P::Num>> {
Some(Rect::from_point(self))
}
}
28 changes: 25 additions & 3 deletions galileo-types/src/contour.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use crate::cartesian::rect::Rect;
use crate::cartesian::traits::cartesian_point::CartesianPoint2d;
use crate::geo::traits::projection::Projection;
use crate::geometry::{Geom, GeometrySpecialization};
use crate::geometry_type::{ContourGeometryType, GeometryType};
use crate::geometry::{CartesianGeometry2dSpecialization, Geom, Geometry, GeometrySpecialization};
use crate::geometry_type::{CartesianSpace2d, ContourGeometryType, GeometryType};
use crate::segment::Segment;

pub trait Contour {
Expand Down Expand Up @@ -142,7 +144,7 @@ where
{
type Point = C::Point;

fn project<Proj>(&self, projection: &Proj) -> Option<Geom<Proj::OutPoint>>
fn project_spec<Proj>(&self, projection: &Proj) -> Option<Geom<Proj::OutPoint>>
where
Proj: Projection<InPoint = Self::Point> + ?Sized,
{
Expand All @@ -156,3 +158,23 @@ where
}))
}
}

impl<P, C> CartesianGeometry2dSpecialization<P, ContourGeometryType> for C
where
P: CartesianPoint2d,
C: Contour<Point = P>
+ GeometryType<Type = ContourGeometryType, Space = CartesianSpace2d>
+ Geometry<Point = P>,
{
fn is_point_inside_spec<Other: CartesianPoint2d<Num = P::Num>>(
&self,
_point: &Other,
_tolerance: P::Num,
) -> bool {
todo!()
}

fn bounding_rectangle_spec(&self) -> Option<Rect<P::Num>> {
Rect::from_points(self.iter_points())
}
}
7 changes: 7 additions & 0 deletions galileo-types/src/error.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
use thiserror::Error;

#[derive(Debug, Error)]
pub enum GalileoTypesError {
#[error("invalid input geometry: {0}")]
Conversion(String),
}
2 changes: 1 addition & 1 deletion galileo-types/src/geo/traits/point.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ where
{
type Point = P;

fn project<Proj>(&self, projection: &Proj) -> Option<Geom<Proj::OutPoint>>
fn project_spec<Proj>(&self, projection: &Proj) -> Option<Geom<Proj::OutPoint>>
where
Proj: Projection<InPoint = Self::Point> + ?Sized,
{
Expand Down
78 changes: 78 additions & 0 deletions galileo-types/src/geojson/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
use crate::cartesian::impls::contour::Contour;
use crate::cartesian::impls::multipolygon::MultiPolygon;
use crate::cartesian::impls::polygon::Polygon;
use crate::geo::traits::projection::Projection;
use crate::geojson::point::GeoJsonPoint;
use crate::geometry::{Geom, Geometry};
use crate::impls::multi_contour::MultiContour;
use crate::impls::multi_point::MultiPoint;
use geojson::{LineStringType, PolygonType, Position, Value};

// mod line;
mod point;

impl Geometry for geojson::Geometry {
type Point = GeoJsonPoint;

fn project<Proj>(&self, projection: &Proj) -> Option<Geom<Proj::OutPoint>>
where
Proj: Projection<InPoint = Self::Point> + ?Sized,
{
match &self.value {
Value::Point(p) => GeoJsonPoint::try_from(p.clone()).ok()?.project(projection),
Value::MultiPoint(points) => convert_multi_point(points)?.project(projection),
Value::LineString(points) => convert_contour(points)?.project(projection),
Value::MultiLineString(lines) => convert_multi_contour(lines)?.project(projection),
Value::Polygon(polygon) => convert_polygon(polygon)?.project(projection),
Value::MultiPolygon(mp) => convert_multi_polygon(mp)?.project(projection),
Value::GeometryCollection(_) => todo!(),
}
}
}

fn convert_contour(line_string: &LineStringType) -> Option<Contour<GeoJsonPoint>> {
let is_closed = line_string.len() > 0 && line_string[0] == line_string[line_string.len() - 1];
Some(Contour::new(
line_string
.iter()
.map(|p| GeoJsonPoint::try_from(p.clone()).ok())
.collect::<Option<Vec<_>>>()?,
is_closed,
))
}

fn convert_multi_point(points: &Vec<Position>) -> Option<MultiPoint<GeoJsonPoint>> {
Some(MultiPoint::from(
points
.iter()
.map(|p| GeoJsonPoint::try_from(p.clone()).ok())
.collect::<Option<Vec<_>>>()?,
))
}

fn convert_multi_contour(lines: &Vec<LineStringType>) -> Option<MultiContour<GeoJsonPoint>> {
Some(MultiContour::from(
lines
.iter()
.map(|l| convert_contour(l))
.collect::<Option<Vec<_>>>()?,
))
}

fn convert_polygon(polygon: &PolygonType) -> Option<Polygon<GeoJsonPoint>> {
Some(Polygon::new(
convert_contour(&polygon[0])?.into_closed()?,
polygon[1..]
.iter()
.map(|p| convert_contour(p).and_then(|c| c.into_closed()))
.collect::<Option<Vec<_>>>()?,
))
}

fn convert_multi_polygon(mp: &Vec<PolygonType>) -> Option<MultiPolygon<GeoJsonPoint>> {
Some(MultiPolygon::from(
mp.iter()
.map(|p| convert_polygon(p))
.collect::<Option<Vec<_>>>()?,
))
}
43 changes: 43 additions & 0 deletions galileo-types/src/geojson/point.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
use crate::error::GalileoTypesError;
use crate::geo::traits::point::{GeoPoint, NewGeoPoint};
use crate::geometry_type::{GeoSpace2d, GeometryType, PointGeometryType};
use geojson::Position;

pub struct GeoJsonPoint(Position);

impl TryFrom<Position> for GeoJsonPoint {
type Error = GalileoTypesError;

fn try_from(value: Position) -> Result<Self, Self::Error> {
if value.len() < 2 {
Err(GalileoTypesError::Conversion(
"point must contain at least 2 dimensions".to_string(),
))
} else {
Ok(GeoJsonPoint(value))
}
}
}

impl GeometryType for GeoJsonPoint {
type Type = PointGeometryType;
type Space = GeoSpace2d;
}

impl GeoPoint for GeoJsonPoint {
type Num = f64;

fn lat(&self) -> Self::Num {
self.0[1]
}

fn lon(&self) -> Self::Num {
self.0[0]
}
}

impl NewGeoPoint for GeoJsonPoint {
fn latlon(lat: f64, lon: f64) -> Self {
Self(vec![lon, lat])
}
}
Loading

0 comments on commit b567845

Please sign in to comment.