Skip to content

Commit 6fcf907

Browse files
committed
Add support for GML MultiPolygon
1 parent 2d09880 commit 6fcf907

File tree

1 file changed

+46
-45
lines changed

1 file changed

+46
-45
lines changed

src/main.rs

Lines changed: 46 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -71,36 +71,39 @@ struct Geometry {
7171
rings: Vec<Vec<f64>>
7272
}
7373
impl Geometry {
74-
fn new() -> Geometry {
75-
Geometry { gtype: 0, dims: 2, srid: 4326, rings: Vec::new() }
76-
}
77-
fn reset(&mut self) {
78-
self.gtype = 0;
79-
self.dims = 2;
80-
self.srid = 4326;
81-
self.rings.clear();
74+
fn new(gtype: u8) -> Geometry {
75+
Geometry { gtype, dims: 2, srid: 4326, rings: Vec::new() }
8276
}
8377
}
8478

85-
fn gml_to_ewkb(cell: &RefCell<String>, geom: &Geometry) {
86-
let mut ewkb = vec![1, geom.gtype, 0, 0];
87-
let code = match geom.dims {
88-
2 => 32,
89-
3 => 32 | 128,
90-
_ => {
91-
eprintln!("GML number of dimensions {} not supported", geom.dims);
92-
32
93-
}
94-
};
95-
ewkb.push(code);
96-
ewkb.extend_from_slice(&geom.srid.to_le_bytes());
97-
ewkb.extend_from_slice(&(geom.rings.len() as u32).to_le_bytes());
98-
for ring in geom.rings.iter() {
99-
ewkb.extend_from_slice(&((ring.len() as u32)/geom.dims as u32).to_le_bytes());
100-
for pos in ring.iter() {
101-
ewkb.extend_from_slice(&pos.to_le_bytes());
79+
fn gml_to_ewkb(cell: &RefCell<String>, coll: &Vec<Geometry>) {
80+
let mut ewkb: Vec<u8> = vec![];
81+
82+
// if coll.len() > 1 {
83+
ewkb.extend_from_slice(&[1, 6, 0, 0, 0]);
84+
ewkb.extend_from_slice(&(coll.len() as u32).to_le_bytes());
85+
// }
86+
87+
for geom in coll {
88+
let code = match geom.dims {
89+
2 => 32, // Indicate EWKB where the srid follows this byte
90+
3 => 32 | 128, // Add bit to indicate the presense of Z values
91+
_ => {
92+
eprintln!("GML number of dimensions {} not supported", geom.dims);
93+
32
94+
}
95+
};
96+
ewkb.extend_from_slice(&[1, geom.gtype, 0, 0, code]);
97+
ewkb.extend_from_slice(&geom.srid.to_le_bytes());
98+
ewkb.extend_from_slice(&(geom.rings.len() as u32).to_le_bytes());
99+
for ring in geom.rings.iter() {
100+
ewkb.extend_from_slice(&((ring.len() as u32)/geom.dims as u32).to_le_bytes());
101+
for pos in ring.iter() {
102+
ewkb.extend_from_slice(&pos.to_le_bytes());
103+
}
102104
}
103105
}
106+
104107
let mut value = cell.borrow_mut();
105108
for byte in ewkb.iter() {
106109
value.push_str(&format!("{:02X}", byte));
@@ -191,8 +194,7 @@ fn main() -> std::io::Result<()> {
191194
let mut text = String::new();
192195
let mut gmltoewkb = false;
193196
let mut gmlpos = false;
194-
let mut gmlint = false;
195-
let mut gmlgeom = Geometry::new();
197+
let mut gmlcoll: Vec<Geometry> = vec![];
196198
let start = Instant::now();
197199
loop {
198200
match reader.read_event(&mut buf) {
@@ -217,14 +219,18 @@ fn main() -> std::io::Result<()> {
217219
value = value.split_off(i+2);
218220
}
219221
match value.parse::<u32>() {
220-
Ok(int) => gmlgeom.srid = int,
222+
Ok(int) => {
223+
if let Some(geom) = gmlcoll.last_mut() { geom.srid = int };
224+
},
221225
Err(_) => eprintln!("Invalid srsName {} in GML", value)
222226
}
223227
},
224228
Ok("srsDimension") => {
225229
let value = reader.decode(&attr.value).unwrap();
226230
match value.parse::<u8>() {
227-
Ok(int) => gmlgeom.dims = int,
231+
Ok(int) => {
232+
if let Some(geom) = gmlcoll.last_mut() { geom.dims = int };
233+
},
228234
Err(_) => eprintln!("Invalid srsDimension {} in GML", value)
229235
}
230236
}
@@ -236,17 +242,14 @@ fn main() -> std::io::Result<()> {
236242
match reader.decode(e.name()) {
237243
Err(_) => (),
238244
Ok(tag) => match tag {
239-
"gml:Point" => gmlgeom.gtype = 1,
240-
"gml:LineString" => gmlgeom.gtype = 2,
241-
"gml:Polygon" => gmlgeom.gtype = 3,
245+
"gml:Point" => gmlcoll.push(Geometry::new(1)),
246+
"gml:LineString" => gmlcoll.push(Geometry::new(2)),
247+
"gml:Polygon" => gmlcoll.push(Geometry::new(3)),
242248
"gml:MultiPolygon" => (),
243249
"gml:polygonMember" => (),
244250
"gml:exterior" => (),
245-
"gml:interior" => {
246-
eprintln!("GML polygon interior ring not yet supported; ignored");
247-
gmlint = true;
248-
},
249-
"gml:LinearRing" => gmlgeom.rings.push(Vec::new()),
251+
"gml:interior" => (),
252+
"gml:LinearRing" => gmlcoll.last_mut().unwrap().rings.push(Vec::new()),
250253
"gml:posList" => gmlpos = true,
251254
_ => eprintln!("GML type {} not supported", tag)
252255
}
@@ -314,10 +317,10 @@ fn main() -> std::io::Result<()> {
314317
continue;
315318
}
316319
else if gmltoewkb {
317-
if gmlpos && !gmlint {
320+
if gmlpos {
318321
let value = String::from(&e.unescape_and_decode(&reader).unwrap());
319322
for pos in value.split(' ') {
320-
gmlgeom.rings.last_mut().unwrap().push(pos.parse().unwrap());
323+
gmlcoll.last_mut().unwrap().rings.last_mut().unwrap().push(pos.parse().unwrap());
321324
}
322325
}
323326
continue;
@@ -352,15 +355,14 @@ fn main() -> std::io::Result<()> {
352355
}
353356
},
354357
Ok(Event::End(_)) => {
355-
if path == table.path {
358+
if path == table.path { // This is an end tag of the row path
356359
if filtered {
357360
filtered = false;
358361
filtercount += 1;
359362
}
360363
else {
361364

362-
// End tag of a subtable; write the first column value of the parent table as the first column of the subtable
363-
if !tables.is_empty() {
365+
if !tables.is_empty() { // This is a subtable; write the first column value of the parent table as the first column of the subtable (for use as a foreign key)
364366
table.write(&tables.last().unwrap().columns[0].value.borrow());
365367
table.write("\t");
366368
}
@@ -401,12 +403,11 @@ fn main() -> std::io::Result<()> {
401403
}
402404
else if gmltoewkb {
403405
if gmlpos && (tag == "/gml:posList") { gmlpos = false; }
404-
if gmlint && (tag == "/gml:interior") { gmlint = false; }
405406
for i in 0..table.columns.len() {
406407
if path == table.columns[i].path {
407408
gmltoewkb = false;
408-
gml_to_ewkb(&table.columns[i].value, &gmlgeom);
409-
gmlgeom.reset();
409+
gml_to_ewkb(&table.columns[i].value, &gmlcoll);
410+
gmlcoll.clear();
410411
break;
411412
}
412413
}

0 commit comments

Comments
 (0)