Skip to content

Commit cdbff53

Browse files
authored
Merge pull request #123 from georust/kyle/geo-traits
Implement geo-traits for reading from WKT
2 parents b2f7399 + 779e519 commit cdbff53

File tree

10 files changed

+590
-0
lines changed

10 files changed

+590
-0
lines changed

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ edition = "2021"
1111

1212
[dependencies]
1313
geo-types = { version = "0.7.8", optional = true }
14+
geo-traits = "0.2"
1415
num-traits = "0.2"
1516
serde = { version = "1.0", default-features = false, optional = true }
1617
thiserror = "1.0.23"

src/lib.rs

Lines changed: 194 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,10 @@ use std::default::Default;
8080
use std::fmt;
8181
use std::str::FromStr;
8282

83+
use geo_traits::{
84+
GeometryCollectionTrait, GeometryTrait, LineStringTrait, MultiLineStringTrait, MultiPointTrait,
85+
MultiPolygonTrait, PointTrait, PolygonTrait,
86+
};
8387
use num_traits::{Float, Num, NumCast};
8488

8589
use crate::tokenizer::{PeekableTokens, Token, Tokens};
@@ -397,6 +401,196 @@ where
397401
}
398402
}
399403

404+
impl<T: WktNum> GeometryTrait for Wkt<T> {
405+
type T = T;
406+
type PointType<'b> = Point<T> where Self: 'b;
407+
type LineStringType<'b> = LineString<T> where Self: 'b;
408+
type PolygonType<'b> = Polygon<T> where Self: 'b;
409+
type MultiPointType<'b> = MultiPoint<T> where Self: 'b;
410+
type MultiLineStringType<'b> = MultiLineString<T> where Self: 'b;
411+
type MultiPolygonType<'b> = MultiPolygon<T> where Self: 'b;
412+
type GeometryCollectionType<'b> = GeometryCollection<T> where Self: 'b;
413+
type RectType<'b> = geo_traits::UnimplementedRect<T> where Self: 'b;
414+
type LineType<'b> = geo_traits::UnimplementedLine<T> where Self: 'b;
415+
type TriangleType<'b> = geo_traits::UnimplementedTriangle<T> where Self: 'b;
416+
417+
fn dim(&self) -> geo_traits::Dimensions {
418+
match self {
419+
Wkt::Point(geom) => PointTrait::dim(geom),
420+
Wkt::LineString(geom) => LineStringTrait::dim(geom),
421+
Wkt::Polygon(geom) => PolygonTrait::dim(geom),
422+
Wkt::MultiPoint(geom) => MultiPointTrait::dim(geom),
423+
Wkt::MultiLineString(geom) => MultiLineStringTrait::dim(geom),
424+
Wkt::MultiPolygon(geom) => MultiPolygonTrait::dim(geom),
425+
Wkt::GeometryCollection(geom) => GeometryCollectionTrait::dim(geom),
426+
}
427+
}
428+
429+
fn as_type(
430+
&self,
431+
) -> geo_traits::GeometryType<
432+
'_,
433+
Point<T>,
434+
LineString<T>,
435+
Polygon<T>,
436+
MultiPoint<T>,
437+
MultiLineString<T>,
438+
MultiPolygon<T>,
439+
GeometryCollection<T>,
440+
Self::RectType<'_>,
441+
Self::TriangleType<'_>,
442+
Self::LineType<'_>,
443+
> {
444+
match self {
445+
Wkt::Point(geom) => geo_traits::GeometryType::Point(geom),
446+
Wkt::LineString(geom) => geo_traits::GeometryType::LineString(geom),
447+
Wkt::Polygon(geom) => geo_traits::GeometryType::Polygon(geom),
448+
Wkt::MultiPoint(geom) => geo_traits::GeometryType::MultiPoint(geom),
449+
Wkt::MultiLineString(geom) => geo_traits::GeometryType::MultiLineString(geom),
450+
Wkt::MultiPolygon(geom) => geo_traits::GeometryType::MultiPolygon(geom),
451+
Wkt::GeometryCollection(geom) => geo_traits::GeometryType::GeometryCollection(geom),
452+
}
453+
}
454+
}
455+
456+
impl<T: WktNum> GeometryTrait for &Wkt<T> {
457+
type T = T;
458+
type PointType<'b> = Point<T> where Self: 'b;
459+
type LineStringType<'b> = LineString<T> where Self: 'b;
460+
type PolygonType<'b> = Polygon<T> where Self: 'b;
461+
type MultiPointType<'b> = MultiPoint<T> where Self: 'b;
462+
type MultiLineStringType<'b> = MultiLineString<T> where Self: 'b;
463+
type MultiPolygonType<'b> = MultiPolygon<T> where Self: 'b;
464+
type GeometryCollectionType<'b> = GeometryCollection<T> where Self: 'b;
465+
type RectType<'b> = geo_traits::UnimplementedRect<T> where Self: 'b;
466+
type LineType<'b> = geo_traits::UnimplementedLine<T> where Self: 'b;
467+
type TriangleType<'b> = geo_traits::UnimplementedTriangle<T> where Self: 'b;
468+
469+
fn dim(&self) -> geo_traits::Dimensions {
470+
match self {
471+
Wkt::Point(geom) => PointTrait::dim(geom),
472+
Wkt::LineString(geom) => LineStringTrait::dim(geom),
473+
Wkt::Polygon(geom) => PolygonTrait::dim(geom),
474+
Wkt::MultiPoint(geom) => MultiPointTrait::dim(geom),
475+
Wkt::MultiLineString(geom) => MultiLineStringTrait::dim(geom),
476+
Wkt::MultiPolygon(geom) => MultiPolygonTrait::dim(geom),
477+
Wkt::GeometryCollection(geom) => GeometryCollectionTrait::dim(geom),
478+
}
479+
}
480+
481+
fn as_type(
482+
&self,
483+
) -> geo_traits::GeometryType<
484+
'_,
485+
Point<T>,
486+
LineString<T>,
487+
Polygon<T>,
488+
MultiPoint<T>,
489+
MultiLineString<T>,
490+
MultiPolygon<T>,
491+
GeometryCollection<T>,
492+
Self::RectType<'_>,
493+
Self::TriangleType<'_>,
494+
Self::LineType<'_>,
495+
> {
496+
match self {
497+
Wkt::Point(geom) => geo_traits::GeometryType::Point(geom),
498+
Wkt::LineString(geom) => geo_traits::GeometryType::LineString(geom),
499+
Wkt::Polygon(geom) => geo_traits::GeometryType::Polygon(geom),
500+
Wkt::MultiPoint(geom) => geo_traits::GeometryType::MultiPoint(geom),
501+
Wkt::MultiLineString(geom) => geo_traits::GeometryType::MultiLineString(geom),
502+
Wkt::MultiPolygon(geom) => geo_traits::GeometryType::MultiPolygon(geom),
503+
Wkt::GeometryCollection(geom) => geo_traits::GeometryType::GeometryCollection(geom),
504+
}
505+
}
506+
}
507+
508+
// Specialized implementations on each WKT concrete type.
509+
510+
macro_rules! impl_specialization {
511+
($geometry_type:ident) => {
512+
impl<T: WktNum> GeometryTrait for $geometry_type<T> {
513+
type T = T;
514+
type PointType<'b> = Point<Self::T> where Self: 'b;
515+
type LineStringType<'b> = LineString<Self::T> where Self: 'b;
516+
type PolygonType<'b> = Polygon<Self::T> where Self: 'b;
517+
type MultiPointType<'b> = MultiPoint<Self::T> where Self: 'b;
518+
type MultiLineStringType<'b> = MultiLineString<Self::T> where Self: 'b;
519+
type MultiPolygonType<'b> = MultiPolygon<Self::T> where Self: 'b;
520+
type GeometryCollectionType<'b> = GeometryCollection<Self::T> where Self: 'b;
521+
type RectType<'b> = geo_traits::UnimplementedRect<T> where Self: 'b;
522+
type LineType<'b> = geo_traits::UnimplementedLine<T> where Self: 'b;
523+
type TriangleType<'b> = geo_traits::UnimplementedTriangle<T> where Self: 'b;
524+
525+
fn dim(&self) -> geo_traits::Dimensions {
526+
geo_traits::Dimensions::Xy
527+
}
528+
529+
fn as_type(
530+
&self,
531+
) -> geo_traits::GeometryType<
532+
'_,
533+
Point<T>,
534+
LineString<T>,
535+
Polygon<T>,
536+
MultiPoint<T>,
537+
MultiLineString<T>,
538+
MultiPolygon<T>,
539+
GeometryCollection<T>,
540+
Self::RectType<'_>,
541+
Self::TriangleType<'_>,
542+
Self::LineType<'_>,
543+
> {
544+
geo_traits::GeometryType::$geometry_type(self)
545+
}
546+
}
547+
548+
impl<'a, T: WktNum + 'a> GeometryTrait for &'a $geometry_type<T> {
549+
type T = T;
550+
type PointType<'b> = Point<Self::T> where Self: 'b;
551+
type LineStringType<'b> = LineString<Self::T> where Self: 'b;
552+
type PolygonType<'b> = Polygon<Self::T> where Self: 'b;
553+
type MultiPointType<'b> = MultiPoint<Self::T> where Self: 'b;
554+
type MultiLineStringType<'b> = MultiLineString<Self::T> where Self: 'b;
555+
type MultiPolygonType<'b> = MultiPolygon<Self::T> where Self: 'b;
556+
type GeometryCollectionType<'b> = GeometryCollection<Self::T> where Self: 'b;
557+
type RectType<'b> = geo_traits::UnimplementedRect<T> where Self: 'b;
558+
type LineType<'b> = geo_traits::UnimplementedLine<T> where Self: 'b;
559+
type TriangleType<'b> = geo_traits::UnimplementedTriangle<T> where Self: 'b;
560+
561+
fn dim(&self) -> geo_traits::Dimensions {
562+
geo_traits::Dimensions::Xy
563+
}
564+
565+
fn as_type(
566+
&self,
567+
) -> geo_traits::GeometryType<
568+
'_,
569+
Point<T>,
570+
LineString<T>,
571+
Polygon<T>,
572+
MultiPoint<T>,
573+
MultiLineString<T>,
574+
MultiPolygon<T>,
575+
GeometryCollection<T>,
576+
Self::RectType<'_>,
577+
Self::TriangleType<'_>,
578+
Self::LineType<'_>,
579+
> {
580+
geo_traits::GeometryType::$geometry_type(self)
581+
}
582+
}
583+
};
584+
}
585+
586+
impl_specialization!(Point);
587+
impl_specialization!(LineString);
588+
impl_specialization!(Polygon);
589+
impl_specialization!(MultiPoint);
590+
impl_specialization!(MultiLineString);
591+
impl_specialization!(MultiPolygon);
592+
impl_specialization!(GeometryCollection);
593+
400594
fn infer_geom_dimension<T: WktNum + FromStr + Default>(
401595
tokens: &mut PeekableTokens<T>,
402596
) -> Result<Dimension, &'static str> {

src/types/coord.rs

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15+
use geo_traits::CoordTrait;
16+
1517
use crate::tokenizer::{PeekableTokens, Token};
1618
use crate::types::Dimension;
1719
use crate::{FromTokens, WktNum};
@@ -96,6 +98,100 @@ where
9698
}
9799
}
98100

101+
impl<T: WktNum> CoordTrait for Coord<T> {
102+
type T = T;
103+
104+
fn dim(&self) -> geo_traits::Dimensions {
105+
match (self.z.is_some(), self.m.is_some()) {
106+
(true, true) => geo_traits::Dimensions::Xyzm,
107+
(true, false) => geo_traits::Dimensions::Xyz,
108+
(false, true) => geo_traits::Dimensions::Xym,
109+
(false, false) => geo_traits::Dimensions::Xy,
110+
}
111+
}
112+
113+
fn x(&self) -> Self::T {
114+
self.x
115+
}
116+
117+
fn y(&self) -> Self::T {
118+
self.y
119+
}
120+
121+
fn nth_or_panic(&self, n: usize) -> Self::T {
122+
let has_z = self.z.is_some();
123+
let has_m = self.m.is_some();
124+
match n {
125+
0 => self.x,
126+
1 => self.y,
127+
2 => {
128+
if has_z {
129+
self.z.unwrap()
130+
} else if has_m {
131+
self.m.unwrap()
132+
} else {
133+
panic!("n out of range")
134+
}
135+
}
136+
3 => {
137+
if has_z && has_m {
138+
self.m.unwrap()
139+
} else {
140+
panic!("n out of range")
141+
}
142+
}
143+
_ => panic!("n out of range"),
144+
}
145+
}
146+
}
147+
148+
impl<T: WktNum> CoordTrait for &Coord<T> {
149+
type T = T;
150+
151+
fn dim(&self) -> geo_traits::Dimensions {
152+
match (self.z.is_some(), self.m.is_some()) {
153+
(true, true) => geo_traits::Dimensions::Xyzm,
154+
(true, false) => geo_traits::Dimensions::Xyz,
155+
(false, true) => geo_traits::Dimensions::Xym,
156+
(false, false) => geo_traits::Dimensions::Xy,
157+
}
158+
}
159+
160+
fn x(&self) -> Self::T {
161+
self.x
162+
}
163+
164+
fn y(&self) -> Self::T {
165+
self.y
166+
}
167+
168+
fn nth_or_panic(&self, n: usize) -> Self::T {
169+
let has_z = self.z.is_some();
170+
let has_m = self.m.is_some();
171+
match n {
172+
0 => self.x,
173+
1 => self.y,
174+
2 => {
175+
if has_z {
176+
self.z.unwrap()
177+
} else if has_m {
178+
self.m.unwrap()
179+
} else {
180+
panic!("n out of range")
181+
}
182+
}
183+
3 => {
184+
if has_z && has_m {
185+
self.m.unwrap()
186+
} else {
187+
panic!("n out of range")
188+
}
189+
}
190+
_ => panic!("n out of range"),
191+
}
192+
}
193+
}
194+
99195
#[cfg(test)]
100196
mod tests {
101197
use super::Coord;

src/types/geometrycollection.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15+
use geo_traits::{GeometryCollectionTrait, GeometryTrait};
16+
1517
use crate::tokenizer::{PeekableTokens, Token};
1618
use crate::types::Dimension;
1719
use crate::{FromTokens, Wkt, WktNum};
@@ -84,6 +86,28 @@ where
8486
}
8587
}
8688

89+
impl<T: WktNum> GeometryCollectionTrait for GeometryCollection<T> {
90+
type T = T;
91+
type GeometryType<'a> = &'a Wkt<T> where Self: 'a;
92+
93+
fn dim(&self) -> geo_traits::Dimensions {
94+
// TODO: infer dimension from empty WKT
95+
if self.0.is_empty() {
96+
geo_traits::Dimensions::Xy
97+
} else {
98+
self.0[0].dim()
99+
}
100+
}
101+
102+
fn num_geometries(&self) -> usize {
103+
self.0.len()
104+
}
105+
106+
unsafe fn geometry_unchecked(&self, i: usize) -> Self::GeometryType<'_> {
107+
self.0.get_unchecked(i)
108+
}
109+
}
110+
87111
#[cfg(test)]
88112
mod tests {
89113
use super::GeometryCollection;

0 commit comments

Comments
 (0)