-
Notifications
You must be signed in to change notification settings - Fork 47
Expand file tree
/
Copy pathwkb.rs
More file actions
194 lines (175 loc) · 6.83 KB
/
Copy pathwkb.rs
File metadata and controls
194 lines (175 loc) · 6.83 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
use arrow_array::OffsetSizeTrait;
use arrow_array::builder::GenericBinaryBuilder;
use geo_traits::{
GeometryCollectionTrait, GeometryTrait, GeometryType, LineStringTrait, MultiLineStringTrait,
MultiPointTrait, MultiPolygonTrait, PointTrait, PolygonTrait,
};
use geoarrow_schema::WkbType;
use wkb::Endianness;
use wkb::writer::{
write_geometry_collection, write_line_string, write_multi_line_string, write_multi_point,
write_multi_polygon, write_point, write_polygon,
};
use crate::array::WKBArray;
use crate::capacity::WKBCapacity;
/// The GeoArrow equivalent to `Vec<Option<WKB>>`: a mutable collection of WKB buffers.
///
/// Converting a [`WKBBuilder`] into a [`WKBArray`] is `O(1)`.
#[derive(Debug)]
pub struct WKBBuilder<O: OffsetSizeTrait>(GenericBinaryBuilder<O>, WkbType);
impl<O: OffsetSizeTrait> WKBBuilder<O> {
/// Creates a new empty [`WKBBuilder`].
pub fn new(typ: WkbType) -> Self {
Self::with_capacity(typ, Default::default())
}
/// Initializes a new [`WKBBuilder`] with a pre-allocated capacity of slots and values.
pub fn with_capacity(typ: WkbType, capacity: WKBCapacity) -> Self {
Self(
GenericBinaryBuilder::with_capacity(
capacity.offsets_capacity,
capacity.buffer_capacity,
),
typ,
)
}
/// Creates a new empty [`WKBBuilder`] with a capacity inferred by the provided geometry
/// iterator.
pub fn with_capacity_from_iter<'a>(
geoms: impl Iterator<Item = Option<&'a (impl GeometryTrait<T = f64> + 'a)>>,
typ: WkbType,
) -> Self {
let counter = WKBCapacity::from_geometries(geoms);
Self::with_capacity(typ, counter)
}
// Upstream APIs don't exist for this yet. To implement this without upstream changes, we could
// change to using manual `Vec`'s ourselves
// pub fn reserve(&mut self, capacity: WKBCapacity) {
// }
/// Push a Point onto the end of this builder
#[inline]
pub fn push_point(&mut self, geom: Option<&impl PointTrait<T = f64>>) {
if let Some(geom) = geom {
write_point(&mut self.0, geom, Endianness::LittleEndian).unwrap();
self.0.append_value("")
} else {
self.0.append_null();
}
}
/// Push a LineString onto the end of this builder
#[inline]
pub fn push_line_string(&mut self, geom: Option<&impl LineStringTrait<T = f64>>) {
if let Some(geom) = geom {
write_line_string(&mut self.0, geom, Endianness::LittleEndian).unwrap();
self.0.append_value("")
} else {
self.0.append_null()
}
}
/// Push a Polygon onto the end of this builder
#[inline]
pub fn push_polygon(&mut self, geom: Option<&impl PolygonTrait<T = f64>>) {
if let Some(geom) = geom {
write_polygon(&mut self.0, geom, Endianness::LittleEndian).unwrap();
self.0.append_value("")
} else {
self.0.append_null()
}
}
/// Push a MultiPoint onto the end of this builder
#[inline]
pub fn push_multi_point(&mut self, geom: Option<&impl MultiPointTrait<T = f64>>) {
if let Some(geom) = geom {
write_multi_point(&mut self.0, geom, Endianness::LittleEndian).unwrap();
self.0.append_value("")
} else {
self.0.append_null()
}
}
/// Push a MultiLineString onto the end of this builder
#[inline]
pub fn push_multi_line_string(&mut self, geom: Option<&impl MultiLineStringTrait<T = f64>>) {
if let Some(geom) = geom {
write_multi_line_string(&mut self.0, geom, Endianness::LittleEndian).unwrap();
self.0.append_value("")
} else {
self.0.append_null()
}
}
/// Push a MultiPolygon onto the end of this builder
#[inline]
pub fn push_multi_polygon(&mut self, geom: Option<&impl MultiPolygonTrait<T = f64>>) {
if let Some(geom) = geom {
write_multi_polygon(&mut self.0, geom, Endianness::LittleEndian).unwrap();
self.0.append_value("")
} else {
self.0.append_null()
}
}
/// Push a Geometry onto the end of this builder
#[inline]
pub fn push_geometry(&mut self, geom: Option<&impl GeometryTrait<T = f64>>) {
use GeometryType::*;
// TODO: call wkb::write_geometry directly
if let Some(geom) = geom {
match geom.as_type() {
Point(point) => self.push_point(Some(point)),
LineString(line_string) => self.push_line_string(Some(line_string)),
Polygon(polygon) => self.push_polygon(Some(polygon)),
MultiPoint(multi_point) => self.push_multi_point(Some(multi_point)),
MultiLineString(multi_line_string) => {
self.push_multi_line_string(Some(multi_line_string))
}
MultiPolygon(multi_polygon) => self.push_multi_polygon(Some(multi_polygon)),
GeometryCollection(geometry_collection) => {
self.push_geometry_collection(Some(geometry_collection))
}
Rect(_) | Line(_) | Triangle(_) => todo!(),
}
} else {
self.0.append_null()
}
}
/// Push a GeometryCollection onto the end of this builder
#[inline]
pub fn push_geometry_collection(
&mut self,
geom: Option<&impl GeometryCollectionTrait<T = f64>>,
) {
if let Some(geom) = geom {
write_geometry_collection(&mut self.0, geom, Endianness::LittleEndian).unwrap();
self.0.append_value("")
} else {
self.0.append_null()
}
}
/// Extend this builder from an iterator of Geometries.
pub fn extend_from_iter<'a>(
&mut self,
geoms: impl Iterator<Item = Option<&'a (impl GeometryTrait<T = f64> + 'a)>>,
) {
geoms
.into_iter()
.for_each(|maybe_geom| self.push_geometry(maybe_geom));
}
/// Create this builder from a slice of Geometries.
pub fn from_geometries(geoms: &[impl GeometryTrait<T = f64>], typ: WkbType) -> Self {
let mut array = Self::with_capacity_from_iter(geoms.iter().map(Some), typ);
array.extend_from_iter(geoms.iter().map(Some));
array
}
/// Create this builder from a slice of nullable Geometries.
pub fn from_nullable_geometries(
geoms: &[Option<impl GeometryTrait<T = f64>>],
typ: WkbType,
) -> Self {
let mut array = Self::with_capacity_from_iter(geoms.iter().map(|x| x.as_ref()), typ);
array.extend_from_iter(geoms.iter().map(|x| x.as_ref()));
array
}
/// Consume this builder and convert to a [WKBArray].
///
/// This is `O(1)`.
pub fn finish(mut self) -> WKBArray<O> {
WKBArray::new(self.0.finish(), self.1.metadata().clone())
}
}