Skip to content

Commit 29b52ed

Browse files
pkaandelf
authored andcommitted
twkb multi-types implementation
1 parent 23c9abb commit 29b52ed

File tree

1 file changed

+175
-5
lines changed

1 file changed

+175
-5
lines changed

src/twkb.rs

Lines changed: 175 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,29 @@ pub struct Polygon {
2929
pub rings: Vec<LineString>,
3030
}
3131

32+
#[derive(PartialEq, Clone, Debug)]
33+
pub struct MultiPoint {
34+
pub points: Vec<Point>,
35+
pub ids: Option<Vec<u64>>,
36+
}
37+
38+
#[derive(PartialEq, Clone, Debug)]
39+
pub struct MultiLineString {
40+
pub lines: Vec<LineString>,
41+
pub ids: Option<Vec<u64>>,
42+
}
43+
44+
#[derive(PartialEq, Clone, Debug)]
45+
pub struct MultiPolygon {
46+
pub polygons: Vec<Polygon>,
47+
pub ids: Option<Vec<u64>>,
48+
}
49+
3250
#[derive(Default,Debug)]
3351
pub struct TwkbInfo {
3452
geom_type: u8,
3553
precision: i8,
36-
has_id_list: bool,
54+
has_idlist: bool,
3755
is_empty_geom: bool,
3856
size: Option<u64>,
3957
has_z: bool,
@@ -57,7 +75,7 @@ pub trait TwkbGeom: fmt::Debug + Sized {
5775
let metadata_header = try!(raw.read_u8());
5876
let has_bbox = (metadata_header & 0b0001) != 0;
5977
let has_size_attribute = (metadata_header & 0b0010) != 0;
60-
twkb_info.has_id_list = (metadata_header & 0b0100) != 0;
78+
twkb_info.has_idlist = (metadata_header & 0b0100) != 0;
6179
let has_ext_prec_info = (metadata_header & 0b1000) != 0;
6280
twkb_info.is_empty_geom = (metadata_header & 0b10000) != 0;
6381
if has_ext_prec_info {
@@ -89,7 +107,7 @@ pub trait TwkbGeom: fmt::Debug + Sized {
89107

90108
fn read_twkb_body<R: Read>(raw: &mut R, twkb_info: &TwkbInfo) -> Result<Self, Error>;
91109

92-
fn read_point<R: Read>(raw: &mut R, twkb_info: &TwkbInfo, x: f64, y: f64, z: Option<f64>, m: Option<f64>)
110+
fn read_relative_point<R: Read>(raw: &mut R, twkb_info: &TwkbInfo, x: f64, y: f64, z: Option<f64>, m: Option<f64>)
93111
-> Result<(f64, f64, Option<f64>, Option<f64>), Error>
94112
{
95113
let x2 = x + try!(read_varint64_as_f64(raw, twkb_info.precision));
@@ -108,6 +126,17 @@ pub trait TwkbGeom: fmt::Debug + Sized {
108126
};
109127
Ok((x2, y2, z2, m2))
110128
}
129+
130+
fn read_idlist<R: Read>(raw: &mut R, size: usize) -> Result<Vec<u64>, Error>
131+
{
132+
let mut idlist = Vec::new();
133+
idlist.reserve(size);
134+
for _ in 0..size {
135+
let id = try!(read_raw_varint64(raw));
136+
idlist.push(id);
137+
}
138+
Ok(idlist)
139+
}
111140
}
112141

113142
// --- helper functions for reading ---
@@ -208,7 +237,7 @@ impl TwkbGeom for LineString {
208237
let mut z = if twkb_info.has_z { Some(0.0) } else { None };
209238
let mut m = if twkb_info.has_m { Some(0.0) } else { None };
210239
for _ in 0..npoints {
211-
let (x2, y2, z2, m2) = try!(Self::read_point(raw, twkb_info, x, y, z, m));
240+
let (x2, y2, z2, m2) = try!(Self::read_relative_point(raw, twkb_info, x, y, z, m));
212241
points.push(Point::new_from_opt_vals(x2, y2, z2, m2));
213242
x = x2; y = y2; z = z2; m = m2;
214243
}
@@ -238,7 +267,7 @@ impl TwkbGeom for Polygon {
238267
points.reserve(npoints as usize);
239268
let (x0, y0, z0, m0) = (x, y, z, m);
240269
for _ in 0..npoints {
241-
let (x2, y2, z2, m2) = try!(Self::read_point(raw, twkb_info, x, y, z, m));
270+
let (x2, y2, z2, m2) = try!(Self::read_relative_point(raw, twkb_info, x, y, z, m));
242271
points.push(Point::new_from_opt_vals(x2, y2, z2, m2));
243272
x = x2; y = y2; z = z2; m = m2;
244273
}
@@ -253,6 +282,126 @@ impl TwkbGeom for Polygon {
253282
}
254283

255284

285+
impl TwkbGeom for MultiPoint {
286+
fn read_twkb_body<R: Read>(raw: &mut R, twkb_info: &TwkbInfo) -> Result<Self, Error> {
287+
// npoints uvarint
288+
// [idlist] varint[]
289+
// pointarray varint[]
290+
let mut points: Vec<Point> = Vec::new();
291+
let mut ids: Option<Vec<u64>> = None;
292+
if !twkb_info.is_empty_geom {
293+
let npoints = try!(read_raw_varint64(raw));
294+
points.reserve(npoints as usize);
295+
296+
if twkb_info.has_idlist {
297+
let idlist = try!(Self::read_idlist(raw, npoints as usize));
298+
ids = Some(idlist);
299+
}
300+
301+
let mut x = 0.0;
302+
let mut y = 0.0;
303+
let mut z = if twkb_info.has_z { Some(0.0) } else { None };
304+
let mut m = if twkb_info.has_m { Some(0.0) } else { None };
305+
for _ in 0..npoints {
306+
let (x2, y2, z2, m2) = try!(Self::read_relative_point(raw, twkb_info, x, y, z, m));
307+
points.push(Point::new_from_opt_vals(x2, y2, z2, m2));
308+
x = x2; y = y2; z = z2; m = m2;
309+
}
310+
}
311+
Ok(MultiPoint {points: points, ids: ids})
312+
}
313+
}
314+
315+
impl TwkbGeom for MultiLineString {
316+
fn read_twkb_body<R: Read>(raw: &mut R, twkb_info: &TwkbInfo) -> Result<Self, Error> {
317+
// nlinestrings uvarint
318+
// [idlist] varint[]
319+
// npoints[0] uvarint
320+
// pointarray[0] varint[]
321+
// ...
322+
// npoints[n] uvarint
323+
// pointarray[n] varint[]
324+
let mut lines: Vec<LineString> = Vec::new();
325+
let mut ids: Option<Vec<u64>> = None;
326+
let nlines = try!(read_raw_varint64(raw));
327+
lines.reserve(nlines as usize);
328+
329+
if twkb_info.has_idlist {
330+
let idlist = try!(Self::read_idlist(raw, nlines as usize));
331+
ids = Some(idlist);
332+
}
333+
334+
let mut x = 0.0;
335+
let mut y = 0.0;
336+
let mut z = if twkb_info.has_z { Some(0.0) } else { None };
337+
let mut m = if twkb_info.has_m { Some(0.0) } else { None };
338+
for _ in 0..nlines {
339+
let mut points: Vec<Point> = Vec::new();
340+
let npoints = try!(read_raw_varint64(raw));
341+
points.reserve(npoints as usize);
342+
for _ in 0..npoints {
343+
let (x2, y2, z2, m2) = try!(Self::read_relative_point(raw, twkb_info, x, y, z, m));
344+
points.push(Point::new_from_opt_vals(x2, y2, z2, m2));
345+
x = x2; y = y2; z = z2; m = m2;
346+
}
347+
lines.push(LineString {points: points});
348+
}
349+
Ok(MultiLineString {lines: lines, ids: ids})
350+
}
351+
}
352+
353+
impl TwkbGeom for MultiPolygon {
354+
fn read_twkb_body<R: Read>(raw: &mut R, twkb_info: &TwkbInfo) -> Result<Self, Error> {
355+
// npolygons uvarint
356+
// [idlist] varint[]
357+
// nrings[0] uvarint
358+
// npoints[0][0] uvarint
359+
// pointarray[0][0] varint[]
360+
// ...
361+
// nrings[n] uvarint
362+
// npoints[n][m] uvarint
363+
// pointarray[n][m] varint[]
364+
let mut polygons: Vec<Polygon> = Vec::new();
365+
let mut ids: Option<Vec<u64>> = None;
366+
let npolygons = try!(read_raw_varint64(raw));
367+
polygons.reserve(npolygons as usize);
368+
369+
if twkb_info.has_idlist {
370+
let idlist = try!(Self::read_idlist(raw, npolygons as usize));
371+
ids = Some(idlist);
372+
}
373+
374+
let mut x = 0.0;
375+
let mut y = 0.0;
376+
let mut z = if twkb_info.has_z { Some(0.0) } else { None };
377+
let mut m = if twkb_info.has_m { Some(0.0) } else { None };
378+
for _ in 0..npolygons {
379+
let mut rings: Vec<LineString> = Vec::new();
380+
let nrings = try!(read_raw_varint64(raw));
381+
rings.reserve(nrings as usize);
382+
for _ in 0..nrings {
383+
let mut points: Vec<Point> = Vec::new();
384+
let npoints = try!(read_raw_varint64(raw));
385+
points.reserve(npoints as usize);
386+
let (x0, y0, z0, m0) = (x, y, z, m);
387+
for _ in 0..npoints {
388+
let (x2, y2, z2, m2) = try!(Self::read_relative_point(raw, twkb_info, x, y, z, m));
389+
points.push(Point::new_from_opt_vals(x2, y2, z2, m2));
390+
x = x2; y = y2; z = z2; m = m2;
391+
}
392+
// close ring, if necessary
393+
if x != x0 && y != y0 && z != z0 && m != m0 {
394+
points.push(Point::new_from_opt_vals(x0, y0, z0, m0));
395+
}
396+
rings.push(LineString {points: points});
397+
}
398+
polygons.push(Polygon {rings: rings});
399+
}
400+
Ok(MultiPolygon {polygons: polygons, ids: ids})
401+
}
402+
}
403+
404+
256405
impl<'a> AsEwkbLineString<'a> for LineString {
257406
type PointType = Point;
258407
type Iter = Iter<'a, Point>;
@@ -332,6 +481,27 @@ fn test_read_polygon() {
332481
assert_eq!(format!("{:?}", poly), "Polygon { rings: [LineString { points: [Point { x: 0, y: 0 }, Point { x: 2, y: 0 }, Point { x: 2, y: 2 }, Point { x: 0, y: 2 }, Point { x: 0, y: 0 }] }, LineString { points: [Point { x: 10, y: 10 }, Point { x: -2, y: 10 }, Point { x: -2, y: -2 }, Point { x: 10, y: -2 }, Point { x: 10, y: 10 }] }] }");
333482
}
334483

484+
#[test]
485+
fn test_read_multipoint() {
486+
let twkb = hex_to_vec("04000214271326"); // SELECT encode(ST_AsTWKB('MULTIPOINT ((10 -20), (0 -0.5))'::geometry), 'hex')
487+
let points = MultiPoint::read_twkb(&mut twkb.as_slice()).unwrap();
488+
assert_eq!(format!("{:?}", points), "MultiPoint { points: [Point { x: 10, y: -20 }, Point { x: 0, y: -1 }], ids: None }");
489+
}
490+
491+
#[test]
492+
fn test_read_multiline() {
493+
let twkb = hex_to_vec("05000202142713260200020400"); // SELECT encode(ST_AsTWKB('MULTILINESTRING ((10 -20, 0 -0.5), (0 0, 2 0))'::geometry), 'hex')
494+
let lines = MultiLineString::read_twkb(&mut twkb.as_slice()).unwrap();
495+
assert_eq!(format!("{:?}", lines), "MultiLineString { lines: [LineString { points: [Point { x: 10, y: -20 }, Point { x: 0, y: -1 }] }, LineString { points: [Point { x: 0, y: 0 }, Point { x: 2, y: 0 }] }], ids: None }");
496+
}
497+
498+
#[test]
499+
fn test_read_multipolygon() {
500+
let twkb = hex_to_vec("060002010500000400000403000003010514141700001718000018"); // SELECT encode(ST_AsTWKB('MULTIPOLYGON (((0 0, 2 0, 2 2, 0 2, 0 0)), ((10 10, -2 10, -2 -2, 10 -2, 10 10)))'::geometry), 'hex')
501+
let polys = MultiPolygon::read_twkb(&mut twkb.as_slice()).unwrap();
502+
assert_eq!(format!("{:?}", polys), "MultiPolygon { polygons: [Polygon { rings: [LineString { points: [Point { x: 0, y: 0 }, Point { x: 2, y: 0 }, Point { x: 2, y: 2 }, Point { x: 0, y: 2 }, Point { x: 0, y: 0 }] }] }, Polygon { rings: [LineString { points: [Point { x: 10, y: 10 }, Point { x: -2, y: 10 }, Point { x: -2, y: -2 }, Point { x: 10, y: -2 }, Point { x: 10, y: 10 }] }] }], ids: None }");
503+
}
504+
335505
#[test]
336506
fn test_write_point() {
337507
let twkb = hex_to_vec("01001427"); // SELECT encode(ST_AsTWKB('POINT(10 -20)'::geometry), 'hex')

0 commit comments

Comments
 (0)