1use std::collections::BTreeMap;
4
5use serde::{Deserialize, Serialize};
6use serde_json::Value;
7
8use crate::frames::Layer;
9use crate::v01::{Id, ParsedProperty};
10use crate::{Decoder, MltResult};
11
12pub type Geom32 = geo_types::Geometry<i32>;
14
15pub type Coord32 = geo_types::Coord<i32>;
17
18pub type Geom16 = geo_types::Geometry<i16>;
20
21pub type Coord16 = geo_types::Coord<i16>;
23
24#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
26pub struct FeatureCollection {
27 #[serde(rename = "type")]
28 pub ty: String,
29 pub features: Vec<Feature>,
30}
31
32impl FeatureCollection {
33 pub fn from_layers(
35 layers: &mut [Layer<'_>],
36 dec: &mut Decoder,
37 ) -> MltResult<FeatureCollection> {
38 let mut features = Vec::new();
39 for layer in layers.iter_mut() {
40 let l = layer.decoded_layer01_mut(dec)?;
41 l.decode_properties(dec)?;
42 let geom = l.geometry.as_parsed()?;
43 let ids: Option<&[Option<u64>]> = l.id.as_ref().and_then(|v| {
44 if let Id::Parsed(d) = v {
45 Some(d.values())
46 } else {
47 None
48 }
49 });
50 for i in 0..geom.vector_types.len() {
51 let geometry = geom.to_geojson(i)?;
52 let mut properties = BTreeMap::new();
53 for prop in &l.properties {
54 let prop = prop.as_parsed()?;
55 if let ParsedProperty::SharedDict(dict) = prop {
58 for item in &dict.items {
59 if let Some(s) = item.get(dict, i) {
60 let key = format!("{}{}", dict.prefix, item.suffix);
61 properties.insert(key, Value::String(s.to_string()));
62 }
63 }
64 } else if let Some(val) = prop.to_geojson(i) {
65 properties.insert(prop.name().to_string(), val);
66 }
67 }
68 properties.insert("_layer".into(), Value::String(l.name.to_string()));
69 properties.insert("_extent".into(), Value::Number(l.extent.into()));
70 features.push(Feature {
71 geometry,
72 id: ids.and_then(|v| v.get(i).copied().flatten()),
73 properties,
74 ty: "Feature".into(),
75 });
76 }
77 }
78 Ok(FeatureCollection {
79 features,
80 ty: "FeatureCollection".into(),
81 })
82 }
83}
84
85#[derive(Debug, Clone, PartialEq, Deserialize)]
87pub struct Feature {
88 #[serde(with = "geom_serde")]
89 pub geometry: Geom32,
90 #[serde(skip_serializing_if = "Option::is_none")]
91 pub id: Option<u64>,
92 pub properties: BTreeMap<String, Value>,
93 #[serde(rename = "type")]
94 pub ty: String,
95}
96
97struct Geom32Wire<'a>(&'a Geom32);
98impl Serialize for Geom32Wire<'_> {
99 fn serialize<S: serde::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
100 geom_serde::serialize(self.0, s)
101 }
102}
103
104impl Serialize for Feature {
106 fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
107 use serde::ser::SerializeMap as _;
108 let len = 3 + usize::from(self.id.is_some());
109 let mut map = serializer.serialize_map(Some(len))?;
110 map.serialize_entry("type", &self.ty)?;
111 if let Some(id) = self.id {
112 map.serialize_entry("id", &id)?;
113 }
114 map.serialize_entry("properties", &self.properties)?;
115 map.serialize_entry("geometry", &Geom32Wire(&self.geometry))?;
116 map.end()
117 }
118}
119
120mod geom_serde {
123 use geo_types::{
124 Geometry, LineString, MultiLineString, MultiPoint, MultiPolygon, Point, Polygon,
125 };
126 use serde::{Deserialize, Deserializer, Serializer};
127 use serde_json::Value;
128
129 use crate::geojson::Geom32;
130
131 type Arr = [i32; 2];
132
133 fn ls_arr(ls: &LineString<i32>) -> Vec<Arr> {
134 ls.0.iter().copied().map(Into::into).collect()
135 }
136
137 fn poly_arr(poly: &Polygon<i32>) -> Vec<Vec<Arr>> {
138 std::iter::once(poly.exterior())
139 .chain(poly.interiors())
140 .map(ls_arr)
141 .collect()
142 }
143
144 fn arr_ls(v: Vec<Arr>) -> LineString<i32> {
145 LineString::from(v)
146 }
147
148 fn arr_poly(rings: Vec<Vec<Arr>>) -> Polygon<i32> {
149 let mut it = rings.into_iter();
150 let ext = it.next().map_or_else(|| LineString(vec![]), arr_ls);
151 Polygon::new(ext, it.map(arr_ls).collect())
152 }
153
154 pub fn serialize<S: Serializer>(g: &Geom32, s: S) -> Result<S::Ok, S::Error> {
155 use serde::ser::{Error, SerializeMap as _};
156
157 let mut m = s.serialize_map(Some(2))?;
158 let (ty, coords): (&str, Value) = match g {
159 Geometry::Point(p) => ("Point", serde_json::to_value(Arr::from(*p)).unwrap()),
160 Geometry::LineString(ls) => ("LineString", serde_json::to_value(ls_arr(ls)).unwrap()),
161 Geometry::Polygon(poly) => ("Polygon", serde_json::to_value(poly_arr(poly)).unwrap()),
162 Geometry::MultiPoint(mp) => (
163 "MultiPoint",
164 serde_json::to_value(mp.0.iter().copied().map(Arr::from).collect::<Vec<_>>())
165 .unwrap(),
166 ),
167 Geometry::MultiLineString(mls) => (
168 "MultiLineString",
169 serde_json::to_value(mls.iter().map(ls_arr).collect::<Vec<_>>()).unwrap(),
170 ),
171 Geometry::MultiPolygon(mpoly) => (
172 "MultiPolygon",
173 serde_json::to_value(mpoly.iter().map(poly_arr).collect::<Vec<_>>()).unwrap(),
174 ),
175 _ => return Err(Error::custom("unsupported geometry variant")),
176 };
177 m.serialize_entry("type", ty)?;
178 m.serialize_entry("coordinates", &coords)?;
179 m.end()
180 }
181
182 pub fn deserialize<'de, D: Deserializer<'de>>(d: D) -> Result<Geom32, D::Error> {
183 use serde::de::Error as _;
184
185 fn parse<T: serde::de::DeserializeOwned, E: serde::de::Error>(v: Value) -> Result<T, E> {
186 serde_json::from_value(v).map_err(E::custom)
187 }
188
189 #[derive(Deserialize)]
190 struct Wire {
191 #[serde(rename = "type")]
192 ty: String,
193 coordinates: Value,
194 }
195
196 let Wire { ty, coordinates: c } = Wire::deserialize(d)?;
197 Ok(match ty.as_str() {
198 "Point" => Geometry::Point(Point::from(parse::<Arr, _>(c)?)),
199 "LineString" => Geometry::LineString(arr_ls(parse(c)?)),
200 "Polygon" => Geometry::Polygon(arr_poly(parse(c)?)),
201 "MultiPoint" => {
202 let v: Vec<Arr> = parse(c)?;
203 Geometry::MultiPoint(MultiPoint(v.into_iter().map(Point::from).collect()))
204 }
205 "MultiLineString" => {
206 let v: Vec<Vec<Arr>> = parse(c)?;
207 Geometry::MultiLineString(MultiLineString(v.into_iter().map(arr_ls).collect()))
208 }
209 "MultiPolygon" => {
210 let v: Vec<Vec<Vec<Arr>>> = parse(c)?;
211 Geometry::MultiPolygon(MultiPolygon(v.into_iter().map(arr_poly).collect()))
212 }
213 _ => {
214 return Err(D::Error::unknown_variant(
215 &ty,
216 &[
217 "Point",
218 "LineString",
219 "Polygon",
220 "MultiPoint",
221 "MultiLineString",
222 "MultiPolygon",
223 ],
224 ));
225 }
226 })
227 }
228}