Skip to content

Commit af3b0be

Browse files
committed
wip: proj transform
1 parent 373b731 commit af3b0be

3 files changed

Lines changed: 146 additions & 0 deletions

File tree

geozero/Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ with-postgis-sqlx = ["with-wkb", "sqlx/postgres"]
2424
with-postgis-postgres = ["with-wkb", "postgres-types", "bytes"]
2525
with-mvt = ["prost"]
2626
with-tessellator = ["lyon"]
27+
with-proj = ["proj", "delegate"]
2728

2829
[dependencies]
2930
thiserror = "1.0"
@@ -40,6 +41,8 @@ postgres-types = { version = "0.2", optional = true }
4041
bytes = { version = "1.1", optional = true }
4142
prost = { version = "0.9.0", optional = true }
4243
wkt = { version = "0.10.0", optional = true }
44+
proj = { version = "0.25.2", optional = true }
45+
delegate = { version = "0.6.2", optional = true }
4346

4447
[dev-dependencies]
4548
seek_bufread = "1.2"

geozero/src/lib.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ pub mod error;
3333
mod feature_processor;
3434
mod geometry_processor;
3535
mod multiplex;
36+
mod proj;
3637
mod property_processor;
3738

3839
pub use api::*;
@@ -72,6 +73,9 @@ pub mod svg;
7273
#[cfg(feature = "with-svg")]
7374
pub use crate::svg::conversion::*;
7475

76+
#[cfg(feature = "with-proj")]
77+
pub use crate::proj::ToProjected;
78+
7579
#[cfg(feature = "with-tesselator")]
7680
pub mod tessellator;
7781

geozero/src/proj.rs

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
use crate::error::Result;
2+
use crate::{
3+
ColumnValue, CoordDimensions, FeatureProcessor, GeomProcessor, GeozeroDatasource,
4+
PropertyProcessor,
5+
};
6+
7+
use delegate::delegate;
8+
use proj::Proj;
9+
10+
use std::rc::Rc;
11+
12+
/// ```
13+
/// use proj::Proj;
14+
/// use geozero::{ToProjected, ProcessToJson, wkt::WktStr};
15+
///
16+
/// // Convert from [NAD 83 US Survey Feet](https://epsg.io/2230) to [NAD 83 Meters](https://epsg.io/26946) Using EPSG Codes
17+
/// let from = "EPSG:2230";
18+
/// let to = "EPSG:26946";
19+
/// let proj = Proj::new_known_crs(from, to, None).unwrap();
20+
///
21+
/// let wkt = WktStr("POINT (4760096.421921 3744293.729449)");
22+
/// let expected = r#"{"type": "Point", "coordinates": [1450880.2910605022,1141263.0111604782]}"#;
23+
/// assert_eq!(expected, &wkt.to_projected(proj).to_json().unwrap());
24+
/// ```
25+
pub trait ToProjected: GeozeroDatasource + Sized {
26+
fn to_projected(self, proj: Proj) -> ProjectorReader<Self>;
27+
}
28+
29+
impl<Input: GeozeroDatasource> ToProjected for Input {
30+
fn to_projected(self, proj: Proj) -> ProjectorReader<Input> {
31+
ProjectorReader {
32+
proj: Rc::new(proj),
33+
input: self,
34+
}
35+
}
36+
}
37+
38+
pub struct ProjectorReader<Input: GeozeroDatasource> {
39+
proj: Rc<Proj>,
40+
input: Input,
41+
}
42+
43+
struct ProjWriter<'a> {
44+
proj: Rc<Proj>,
45+
output: &'a mut dyn FeatureProcessor,
46+
}
47+
48+
impl<Input: GeozeroDatasource> GeozeroDatasource for ProjectorReader<Input> {
49+
fn process<P: FeatureProcessor>(&mut self, processor: &mut P) -> Result<()> {
50+
let mut wrapped = ProjWriter {
51+
proj: self.proj.clone(),
52+
output: processor,
53+
};
54+
self.input.process(&mut wrapped)
55+
}
56+
}
57+
58+
impl FeatureProcessor for ProjWriter<'_> {
59+
delegate! {
60+
to self.output {
61+
fn dataset_begin(&mut self, name: Option<&str>) -> Result<()>;
62+
fn dataset_end(&mut self) -> Result<()>;
63+
fn feature_begin(&mut self, idx: u64) -> Result<()>;
64+
fn feature_end(&mut self, idx: u64) -> Result<()>;
65+
fn properties_begin(&mut self) -> Result<()>;
66+
fn properties_end(&mut self) -> Result<()>;
67+
fn geometry_begin(&mut self) -> Result<()>;
68+
fn geometry_end(&mut self) -> Result<()>;
69+
}
70+
}
71+
}
72+
73+
impl PropertyProcessor for ProjWriter<'_> {
74+
delegate! {
75+
to self.output {
76+
fn property(&mut self, idx: usize, name: &str, value: &ColumnValue) -> Result<bool>;
77+
}
78+
}
79+
}
80+
81+
impl GeomProcessor for ProjWriter<'_> {
82+
fn coordinate(
83+
&mut self,
84+
x: f64,
85+
y: f64,
86+
z: Option<f64>,
87+
m: Option<f64>,
88+
t: Option<f64>,
89+
tm: Option<u64>,
90+
idx: usize,
91+
) -> Result<()> {
92+
let (x, y) = self.proj.convert((x, y)).unwrap();
93+
self.output.coordinate(x, y, z, m, t, tm, idx)
94+
}
95+
96+
fn xy(&mut self, x: f64, y: f64, idx: usize) -> Result<()> {
97+
let (x, y) = self.proj.convert((x, y)).unwrap();
98+
self.output.xy(x, y, idx)
99+
}
100+
101+
delegate! {
102+
to self.output {
103+
fn dimensions(&self) -> CoordDimensions;
104+
fn multi_dim(&self) -> bool;
105+
fn srid(&mut self, srid: Option<i32>) -> Result<()>;
106+
fn empty_point(&mut self, idx: usize) -> Result<()>;
107+
fn point_begin(&mut self, idx: usize) -> Result<()>;
108+
fn point_end(&mut self, idx: usize) -> Result<()>;
109+
fn multipoint_begin(&mut self, size: usize, idx: usize) -> Result<()>;
110+
fn multipoint_end(&mut self, idx: usize) -> Result<()>;
111+
fn linestring_begin(&mut self, tagged: bool, size: usize, idx: usize) -> Result<()>;
112+
fn linestring_end(&mut self, tagged: bool, idx: usize) -> Result<()>;
113+
fn multilinestring_begin(&mut self, size: usize, idx: usize) -> Result<()>;
114+
fn multilinestring_end(&mut self, idx: usize) -> Result<()>;
115+
fn polygon_begin(&mut self, tagged: bool, size: usize, idx: usize) -> Result<()>;
116+
fn polygon_end(&mut self, tagged: bool, idx: usize) -> Result<()>;
117+
fn multipolygon_begin(&mut self, size: usize, idx: usize) -> Result<()>;
118+
fn multipolygon_end(&mut self, idx: usize) -> Result<()>;
119+
fn geometrycollection_begin(&mut self, size: usize, idx: usize) -> Result<()>;
120+
fn geometrycollection_end(&mut self, idx: usize) -> Result<()>;
121+
fn circularstring_begin(&mut self, size: usize, idx: usize) -> Result<()>;
122+
fn circularstring_end(&mut self, idx: usize) -> Result<()>;
123+
fn compoundcurve_begin(&mut self, size: usize, idx: usize) -> Result<()>;
124+
fn compoundcurve_end(&mut self, idx: usize) -> Result<()>;
125+
fn curvepolygon_begin(&mut self, size: usize, idx: usize) -> Result<()>;
126+
fn curvepolygon_end(&mut self, idx: usize) -> Result<()>;
127+
fn multicurve_begin(&mut self, size: usize, idx: usize) -> Result<()>;
128+
fn multicurve_end(&mut self, idx: usize) -> Result<()>;
129+
fn multisurface_begin(&mut self, size: usize, idx: usize) -> Result<()>;
130+
fn multisurface_end(&mut self, idx: usize) -> Result<()>;
131+
fn triangle_begin(&mut self, tagged: bool, size: usize, idx: usize) -> Result<()>;
132+
fn triangle_end(&mut self, tagged: bool, idx: usize) -> Result<()>;
133+
fn polyhedralsurface_begin(&mut self, size: usize, idx: usize) -> Result<()>;
134+
fn polyhedralsurface_end(&mut self, idx: usize) -> Result<()>;
135+
fn tin_begin(&mut self, size: usize, idx: usize) -> Result<()>;
136+
fn tin_end(&mut self, idx: usize) -> Result<()>;
137+
}
138+
}
139+
}

0 commit comments

Comments
 (0)