use super::model::VertexBufferType;
use super::streams::{
dict_may_be_beneficial, encode_hilbert_vertex_streams02, encode_hilbert_xyz_vertex_streams02,
encode_level1_length_stream, encode_level1_without_ring_buffer_length_stream,
encode_level2_length_stream, encode_morton_vertex_streams02, encode_ring_lengths_for_mixed,
encode_root_length_stream, encode_vec2_delta2_vertex_stream02, encode_vec2_vertex_stream02,
encode_vec3_vertex_stream02, normalize_geometry_offsets, normalize_part_offsets_for_rings,
seed_curve_caches, xyz_dict_may_be_beneficial,
};
use crate::decoder::GeometryType::{LineString, Point, Polygon};
use crate::decoder::stream::header02::{Family, WordWidth};
use crate::decoder::{
GeoLayout, GeometryType, GeometryValues, LengthType, OffsetType, StreamType, Topology,
VertexStorage,
};
use crate::encoder::model::StreamCtx;
use crate::encoder::{Codecs, Encoder};
use crate::tile::ZStep;
use crate::{MltError, MltResult};
fn non_empty(data: Vec<u32>) -> Option<Vec<u32>> {
if data.is_empty() { None } else { Some(data) }
}
struct Tessellation {
triangles: Vec<u32>,
index_buffer: Vec<u32>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) enum Outlines {
Keep,
DropForPolygons,
}
pub(crate) struct GeometrySection02 {
types: Vec<GeometryType>,
geo_lengths: Option<Vec<u32>>,
topology: Topology,
tessellation: Option<Tessellation>,
vertices: Vec<i32>,
z_step: Option<ZStep>,
}
pub(crate) fn encode_geometry02(
geometry: GeometryValues,
outlines: Outlines,
) -> MltResult<GeometrySection02> {
let GeometryValues {
vector_types,
geometry_offsets,
part_offsets,
ring_offsets,
index_buffer,
triangle_offsets,
vertices,
z_step,
} = 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();
let triangles = triangle_offsets
.unwrap_or_default()
.windows(2)
.map(|w| w[1] - w[0])
.collect();
let index_buffer = index_buffer.unwrap_or_default();
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 mut topology = match (part_lengths, ring_lengths) {
(None, None) => Topology::Flat,
(Some(parts), None) => Topology::Parts(parts),
(Some(parts), Some(rings)) => Topology::PartsAndRings { parts, rings },
(None, Some(_)) => return Err(MltError::RingLengthsWithoutPartLengths),
};
let tessellation = (!index_buffer.is_empty()).then_some(Tessellation {
triangles,
index_buffer,
});
if tessellation.is_some() {
let polygons_only = vector_types.iter().all(|t| t.is_polygon());
if outlines == Outlines::DropForPolygons && polygons_only {
topology = Topology::Flat;
geo_lengths = None;
} else {
topology = topology.with_rings();
geo_lengths.get_or_insert_with(Vec::new);
}
}
Ok(GeometrySection02 {
types: vector_types,
geo_lengths,
topology,
tessellation,
vertices,
z_step,
})
}
pub(crate) struct GeometryHeader02 {
pub(crate) layout: GeoLayout,
pub(crate) uniform_type: Option<GeometryType>,
}
impl GeometrySection02 {
fn uniform_type(&self) -> Option<GeometryType> {
let (first, rest) = self.types.split_first()?;
rest.iter().all(|t| t == first).then_some(*first)
}
fn layout(&self, vertices: VertexStorage) -> GeoLayout {
if self.tessellation.is_some() {
GeoLayout::tessellated(self.geo_lengths.is_some())
} else {
GeoLayout::from_topology(&self.topology, self.geo_lengths.is_some(), vertices)
}
}
pub(crate) fn write_to(
self,
enc: &mut Encoder,
codecs: &mut Codecs,
) -> MltResult<GeometryHeader02> {
enc.family_context = Family::Int(WordWidth::W32);
let uniform_type = self.uniform_type();
if uniform_type.is_none() {
let types: Vec<u32> = self.types.iter().map(|t| *t as u32).collect();
let ctx = StreamCtx::geom(StreamType::Length(LengthType::VarBinary), "meta");
codecs.write_int_stream(&types, &ctx, enc)?;
}
let (part_lengths, ring_lengths) = self.topology.streams();
let lengths = [
(
self.geo_lengths.as_deref(),
LengthType::Geometries,
"geometries",
),
(part_lengths, LengthType::Parts, "parts"),
(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)?;
}
}
if let Some(tess) = &self.tessellation {
let ctx = StreamCtx::geom(StreamType::Length(LengthType::Triangles), "triangles");
codecs.write_int_stream(&tess.triangles, &ctx, enc)?;
let ctx = StreamCtx::geom(StreamType::Offset(OffsetType::Index), "triangles_indexes");
codecs.write_int_stream(&tess.index_buffer, &ctx, enc)?;
}
let tessellated = self.tessellation.is_some();
let vertices = match self.z_step {
Some(step) => write_xyz_vertices(&self.vertices, step, tessellated, enc, codecs)?,
None => write_vertices(&self.vertices, tessellated, enc, codecs)?,
};
Ok(GeometryHeader02 {
layout: self.layout(vertices),
uniform_type,
})
}
}
fn write_vertices(
vertices: &[i32],
tessellated: bool,
enc: &mut Encoder,
codecs: &mut Codecs,
) -> MltResult<VertexStorage> {
seed_curve_caches(enc, vertices);
enc.family_context = Family::Vertex;
if tessellated {
write_plain_vertices(vertices, enc, codecs)?;
return Ok(VertexStorage::Plain);
}
if let Some(forced) = enc.override_vertex_buffer_type() {
return Ok(match forced {
VertexBufferType::Vec2 => {
encode_vec2_vertex_stream02(vertices, enc, codecs)?;
VertexStorage::Plain
}
VertexBufferType::Morton => {
encode_morton_vertex_streams02(vertices, enc, codecs)?;
VertexStorage::Dict
}
VertexBufferType::Hilbert => {
encode_hilbert_vertex_streams02(vertices, enc, codecs)?;
VertexStorage::Dict
}
});
}
if !dict_may_be_beneficial(vertices, enc) {
write_plain_vertices(vertices, enc, codecs)?;
return Ok(VertexStorage::Plain);
}
keep_shortest(
enc,
codecs,
&[
(VertexStorage::Plain, &|enc, codecs| {
write_plain_vertices(vertices, enc, codecs)
}),
(VertexStorage::Dict, &|enc, codecs| {
encode_hilbert_vertex_streams02(vertices, enc, codecs)
}),
(VertexStorage::Dict, &|enc, codecs| {
encode_morton_vertex_streams02(vertices, enc, codecs)
}),
],
)
}
type VertexCandidate<'a> = (
VertexStorage,
&'a dyn Fn(&mut Encoder, &mut Codecs) -> MltResult<()>,
);
fn keep_shortest(
enc: &mut Encoder,
codecs: &mut Codecs,
candidates: &[VertexCandidate<'_>],
) -> MltResult<VertexStorage> {
let mut winner = VertexStorage::Plain;
let mut winner_size = usize::MAX;
let mut alt = enc.try_alternatives();
for &(storage, write) in candidates {
alt.with(|enc| {
let (data, meta) = (enc.data().len(), enc.meta().len());
enc.family_context = Family::Vertex;
write(enc, codecs)?;
let size = (enc.data().len() - data) + (enc.meta().len() - meta);
if size < winner_size {
winner = storage;
winner_size = size;
}
Ok(())
})?;
}
drop(alt);
Ok(winner)
}
fn write_xyz_vertices(
vertices: &[i32],
step: ZStep,
tessellated: bool,
enc: &mut Encoder,
codecs: &mut Codecs,
) -> MltResult<VertexStorage> {
if enc.hilbert_cache.is_none() || enc.morton_cache.is_none() {
let xy: Vec<i32> = vertices
.as_chunks::<3>()
.0
.iter()
.flat_map(|&[x, y, _]| [x, y])
.collect();
seed_curve_caches(enc, &xy);
}
enc.family_context = Family::Vertex;
if tessellated {
encode_vec3_vertex_stream02(vertices, step, enc, codecs)?;
return Ok(VertexStorage::Plain);
}
if let Some(forced) = enc.override_vertex_buffer_type() {
return match forced {
VertexBufferType::Vec2 => {
encode_vec3_vertex_stream02(vertices, step, enc, codecs)?;
Ok(VertexStorage::Plain)
}
VertexBufferType::Hilbert => {
encode_hilbert_xyz_vertex_streams02(vertices, step, enc, codecs)?;
Ok(VertexStorage::Dict)
}
VertexBufferType::Morton => Err(MltError::NotImplemented(
"Morton vertices with z coordinates, since a Morton code spans only x and y",
)),
};
}
if !xyz_dict_may_be_beneficial(vertices, enc) {
encode_vec3_vertex_stream02(vertices, step, enc, codecs)?;
return Ok(VertexStorage::Plain);
}
keep_shortest(
enc,
codecs,
&[
(VertexStorage::Plain, &|enc, codecs| {
encode_vec3_vertex_stream02(vertices, step, enc, codecs)
}),
(VertexStorage::Dict, &|enc, codecs| {
encode_hilbert_xyz_vertex_streams02(vertices, step, enc, codecs)
}),
],
)
}
fn write_plain_vertices(vertices: &[i32], enc: &mut Encoder, codecs: &mut Codecs) -> MltResult<()> {
if vertices.is_empty() || !enc.config().allow_delta2() {
return encode_vec2_vertex_stream02(vertices, enc, codecs);
}
let mut alt = enc.try_alternatives();
alt.with(|enc| encode_vec2_vertex_stream02(vertices, enc, codecs))?;
alt.with(|enc| encode_vec2_delta2_vertex_stream02(vertices, enc, codecs))
}