From eed7f4229ffa3e369452efbe8dc6c3b7fe776044 Mon Sep 17 00:00:00 2001 From: Yijun Zhao Date: Wed, 7 Feb 2024 17:45:56 +0800 Subject: [PATCH] Support parse POINTZ, POINTM and POINTZM --- src/lib.rs | 56 ++++++++++++++++++++++++++++++++++++++++++++++ src/types/coord.rs | 25 ++++++++++++++++----- src/types/point.rs | 1 - 3 files changed, 75 insertions(+), 7 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 5a5132d..c9b1ad0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -168,6 +168,37 @@ where let x = as FromTokens>::from_tokens_with_parens(tokens); x.map(|y| y.as_item()) } + w if w.eq_ignore_ascii_case("POINTZ") => { + let x = as FromTokens>::from_tokens_with_parens(tokens)?; + if let Some(coord) = &x.0 { + if coord.z.is_none() { + return Err("POINTZ must have a z-coordinate."); + } + } + Ok(x.as_item()) + } + w if w.eq_ignore_ascii_case("POINTM") => { + let mut x = as FromTokens>::from_tokens_with_parens(tokens)?; + if let Some(coord) = &mut x.0 { + if coord.z.is_none() { + return Err("POINTM must have a linear referencing system."); + } else { + coord.m = coord.z.take(); + } + } + Ok(x.as_item()) + } + w if w.eq_ignore_ascii_case("POINTZM") => { + let x = as FromTokens>::from_tokens_with_parens(tokens)?; + if let Some(coord) = &x.0 { + if coord.z.is_none() || coord.m.is_none() { + return Err( + "POINTZM must have z-coordinate and linear referencing system.", + ); + } + } + Ok(x.as_item()) + } w if w.eq_ignore_ascii_case("LINESTRING") || w.eq_ignore_ascii_case("LINEARRING") => { let x = as FromTokens>::from_tokens_with_parens(tokens); x.map(|y| y.as_item()) @@ -360,6 +391,31 @@ mod tests { ); } + #[test] + fn test_points() { + // point(x, y) + let wkt = >::from_str("POINT (10 20.1)").ok().unwrap(); + assert!(matches!(wkt.item, Geometry::Point(_))); + + // point(x, y, z) + let wkt = >::from_str("POINTZ (10 20.1 5)").ok().unwrap(); + assert!(matches!(wkt.item, Geometry::Point(_))); + + // point(x, y, m) + let wkt = >::from_str("POINTM (10 20.1 80)").ok().unwrap(); + match wkt.item { + Geometry::Point(p) => assert_eq!( + format!("{:?}", p), + "Point(Some(Coord { x: 10.0, y: 20.1, z: None, m: Some(80.0) }))" + ), + _ => panic!("excepted to be parsed as a POINT"), + } + + // point(x, y, z, m) + let wkt = >::from_str("POINTZM (10 20.1 5 80)").ok().unwrap(); + assert!(matches!(wkt.item, Geometry::Point(_))); + } + #[test] fn support_jts_linearring() { let wkt: Wkt = Wkt::from_str("linearring (10 20, 30 40)").ok().unwrap(); diff --git a/src/types/coord.rs b/src/types/coord.rs index e740ed9..bb42c9e 100644 --- a/src/types/coord.rs +++ b/src/types/coord.rs @@ -57,12 +57,25 @@ where Some(Token::Number(n)) => n, _ => return Err("Expected a number for the Y coordinate"), }; - Ok(Coord { - x, - y, - z: None, - m: None, - }) + + let mut z = None; + let mut m = None; + + if let Some(Ok(Token::Number(_))) = tokens.peek() { + z = match tokens.next().transpose()? { + Some(Token::Number(n)) => Some(n), + _ => None, + }; + + if let Some(Ok(Token::Number(_))) = tokens.peek() { + m = match tokens.next().transpose()? { + Some(Token::Number(n)) => Some(n), + _ => None, + }; + } + } + + Ok(Coord { x, y, z, m }) } } diff --git a/src/types/point.rs b/src/types/point.rs index 3239637..66b3ebc 100644 --- a/src/types/point.rs +++ b/src/types/point.rs @@ -104,7 +104,6 @@ mod tests { >::from_str("POINT ()").err().unwrap(); >::from_str("POINT (10)").err().unwrap(); >::from_str("POINT 10").err().unwrap(); - >::from_str("POINT (10 -20 40)").err().unwrap(); } #[test]