use super::streams::{
encode_level1_length_stream, encode_level1_without_ring_buffer_length_stream,
encode_level2_length_stream, encode_ring_lengths_for_mixed, encode_root_length_stream,
encode_vec2_vertex_stream, normalize_geometry_offsets, normalize_part_offsets_for_rings,
};
use crate::decoder::GeometryType::{LineString, Point, Polygon};
use crate::decoder::{GeoLayout, GeometryType, GeometryValues, LengthType, StreamType};
use crate::encoder::model::StreamCtx;
use crate::encoder::{Codecs, Encoder};
use crate::{MltError, MltResult};
fn non_empty(data: Vec<u32>) -> Option<Vec<u32>> {
if data.is_empty() { None } else { Some(data) }
}
pub(crate) struct GeometrySection02 {
pub(crate) layout: GeoLayout,
types: Vec<u32>,
geo_lengths: Option<Vec<u32>>,
part_lengths: Option<Vec<u32>>,
ring_lengths: Option<Vec<u32>>,
vertices: Vec<i32>,
}
pub(crate) fn encode_geometry02(geometry: GeometryValues) -> MltResult<GeometrySection02> {
let GeometryValues {
vector_types,
geometry_offsets,
part_offsets,
ring_offsets,
index_buffer,
triangles,
vertices,
} = geometry;
let geom_offsets = geometry_offsets.unwrap_or_default();
let part_offsets = part_offsets.unwrap_or_default();
let ring_offsets = ring_offsets.unwrap_or_default();
let vertices = vertices.unwrap_or_default();
if !triangles.unwrap_or_default().is_empty() || !index_buffer.unwrap_or_default().is_empty() {
return Err(MltError::NotImplemented("v2 tessellated geometry layouts"));
}
let part_offsets = if geom_offsets.is_empty()
&& !ring_offsets.is_empty()
&& !part_offsets.is_empty()
&& part_offsets.len() != vector_types.len() + 1
{
normalize_part_offsets_for_rings(&vector_types, &part_offsets, &ring_offsets)
} else {
part_offsets
};
let mut geo_lengths: Option<Vec<u32>> = None;
let mut part_lengths: Option<Vec<u32>> = None;
let mut ring_lengths: Option<Vec<u32>> = None;
if !geom_offsets.is_empty() {
let geom_offsets = if geom_offsets.len() == vector_types.len() + 1 {
geom_offsets
} else {
normalize_geometry_offsets(&vector_types, &geom_offsets)
};
geo_lengths = non_empty(encode_root_length_stream(
&vector_types,
&geom_offsets,
Polygon,
));
if !part_offsets.is_empty() {
if ring_offsets.is_empty() {
part_lengths = non_empty(encode_level1_without_ring_buffer_length_stream(
&vector_types,
&geom_offsets,
&part_offsets,
));
} else {
part_lengths = non_empty(encode_level1_length_stream(
&vector_types,
&geom_offsets,
&part_offsets,
false,
));
ring_lengths = non_empty(encode_level2_length_stream(
&vector_types,
&geom_offsets,
&part_offsets,
&ring_offsets,
));
}
}
} else if !part_offsets.is_empty() {
if ring_offsets.is_empty() {
part_lengths = non_empty(encode_root_length_stream(
&vector_types,
&part_offsets,
Point,
));
} else {
part_lengths = non_empty(encode_root_length_stream(
&vector_types,
&part_offsets,
LineString,
));
let has_line_string = vector_types
.iter()
.copied()
.any(GeometryType::is_linestring);
ring_lengths = non_empty(encode_ring_lengths_for_mixed(
&vector_types,
&part_offsets,
&ring_offsets,
has_line_string,
));
}
}
let layout = GeoLayout::from_streams(
geo_lengths.is_some(),
part_lengths.is_some(),
ring_lengths.is_some(),
)?;
Ok(GeometrySection02 {
layout,
types: vector_types.iter().map(|t| *t as u32).collect(),
geo_lengths,
part_lengths,
ring_lengths,
vertices,
})
}
impl GeometrySection02 {
pub(crate) fn write_to(self, enc: &mut Encoder, codecs: &mut Codecs) -> MltResult<()> {
let ctx = StreamCtx::geom(StreamType::Length(LengthType::VarBinary), "meta");
codecs.write_int_stream(&self.types, &ctx, enc)?;
let lengths = [
(self.geo_lengths, LengthType::Geometries, "geometries"),
(self.part_lengths, LengthType::Parts, "parts"),
(self.ring_lengths, LengthType::Rings, "rings"),
];
for (stream, length_type, name) in lengths {
if let Some(data) = stream {
let ctx = StreamCtx::geom(StreamType::Length(length_type), name);
codecs.write_int_stream(&data, &ctx, enc)?;
}
}
encode_vec2_vertex_stream(&self.vertices, enc, codecs)?;
Ok(())
}
}