use super::model::VertexBufferType;
use super::streams::{
dict_may_be_beneficial, encode_hilbert_vertex_streams, encode_level1_length_stream,
encode_level1_without_ring_buffer_length_stream, encode_level2_length_stream,
encode_morton_vertex_streams, encode_ring_lengths_for_mixed, encode_root_length_stream,
encode_vec2_vertex_stream, normalize_geometry_offsets, normalize_part_offsets_for_rings,
seed_curve_caches, write_geo_u32_stream,
};
use crate::decoder::GeometryType::{LineString, Point, Polygon};
use crate::decoder::{
ColumnType, GeometryType, GeometryValues, LengthType, Levels, LogicalEncoding, OffsetType,
StreamType, VertexLogical, decode_topology,
};
use crate::encoder::model::StreamCtx;
use crate::encoder::{Codecs, Encoder};
use crate::{Decoder, MltError, MltResult};
impl GeometryValues {
#[hotpath::measure]
pub fn write_to(self, enc: &mut Encoder, codecs: &mut Codecs) -> MltResult<()> {
let Self {
vector_types,
geometry_offsets,
part_offsets,
ring_offsets,
index_buffer,
triangle_offsets,
vertices,
#[cfg(feature = "unstable-v2")]
z_step: _,
} = self;
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 index_buffer = index_buffer.unwrap_or_default();
let triangle_offsets = triangle_offsets.unwrap_or_default();
let vertices = vertices.unwrap_or_default();
let (triangle_offsets, index_buffer) = if index_buffer.is_empty() {
(Vec::new(), Vec::new())
} else {
(triangle_offsets, index_buffer)
};
seed_curve_caches(enc, &vertices);
let meta: Vec<u32> = vector_types.iter().map(|t| *t as u32).collect();
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
};
enc.write_column_type(ColumnType::Geometry)?;
let stream_count_pos = enc.data().len();
enc.data_mut().push(0); let mut n: u8 = 0;
let ctx = StreamCtx::geom(StreamType::Length(LengthType::VarBinary), "meta");
codecs.write_int_stream(&meta, &ctx, enc)?;
n += 1;
let mut seen = Levels::default();
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)
};
let data = encode_root_length_stream(&vector_types, &geom_offsets, Polygon);
let ctx = StreamCtx::geom(StreamType::Length(LengthType::Geometries), "geometries");
n += write_length(data, ctx, enc, codecs, &mut seen.geometries)?;
if !part_offsets.is_empty() {
if ring_offsets.is_empty() {
let data = encode_level1_without_ring_buffer_length_stream(
&vector_types,
&geom_offsets,
&part_offsets,
);
let ctx = StreamCtx::geom(StreamType::Length(LengthType::Parts), "no_rings");
n += write_length(data, ctx, enc, codecs, &mut seen.parts)?;
} else {
let data = encode_level1_length_stream(
&vector_types,
&geom_offsets,
&part_offsets,
false,
);
let ctx = StreamCtx::geom(StreamType::Length(LengthType::Parts), "rings");
n += write_length(data, ctx, enc, codecs, &mut seen.parts)?;
let data = encode_level2_length_stream(
&vector_types,
&geom_offsets,
&part_offsets,
&ring_offsets,
);
let ctx = StreamCtx::geom(StreamType::Length(LengthType::Rings), "rings2");
n += write_length(data, ctx, enc, codecs, &mut seen.rings)?;
}
}
} else if !part_offsets.is_empty() {
if ring_offsets.is_empty() {
let data = encode_root_length_stream(&vector_types, &part_offsets, Point);
let ctx = StreamCtx::geom(StreamType::Length(LengthType::Parts), "no_rings");
n += write_length(data, ctx, enc, codecs, &mut seen.parts)?;
} else {
let ctx = StreamCtx::geom(StreamType::Length(LengthType::Geometries), "geometries");
n += write_length(Vec::new(), ctx, enc, codecs, &mut seen.geometries)?;
let data = encode_root_length_stream(&vector_types, &part_offsets, LineString);
let ctx = StreamCtx::geom(StreamType::Length(LengthType::Parts), "parts");
n += write_length(data, ctx, enc, codecs, &mut seen.parts)?;
let has_line_string = vector_types
.iter()
.copied()
.any(GeometryType::is_linestring);
let data = encode_ring_lengths_for_mixed(
&vector_types,
&part_offsets,
&ring_offsets,
has_line_string,
);
let ctx = StreamCtx::geom(StreamType::Length(LengthType::Rings), "parts_ring");
n += write_length(data, ctx, enc, codecs, &mut seen.rings)?;
}
}
let (triangles, index_buffer) =
feature_relative_triangles(vector_types, seen, triangle_offsets, index_buffer)?;
let ctx = StreamCtx::geom(StreamType::Length(LengthType::Triangles), "triangles");
n += write_geo_u32_stream(&triangles, ctx, enc, codecs)?;
let ctx = StreamCtx::geom(StreamType::Offset(OffsetType::Index), "triangles_indexes");
n += write_geo_u32_stream(&index_buffer, ctx, enc, codecs)?;
if let Some(forced) = enc.override_vertex_buffer_type() {
n += match forced {
VertexBufferType::Vec2 => encode_vec2_vertex_stream(&vertices, enc, codecs)?,
VertexBufferType::Morton => encode_morton_vertex_streams(&vertices, enc, codecs)?,
VertexBufferType::Hilbert => encode_hilbert_vertex_streams(&vertices, enc, codecs)?,
VertexBufferType::Rans => {
return Err(MltError::UnsupportedLogicalEncoding(
LogicalEncoding::Vertex(VertexLogical::Rans),
"v1, which has no rANS vertex coding",
));
}
};
} else if dict_may_be_beneficial(&vertices, enc) {
let mut winner_size: usize = usize::MAX;
let mut winner_stream_cnt: u8 = 0;
let mut alt = enc.try_alternatives();
alt.with(|e| {
let ds = e.data().len();
let ms = e.meta().len();
winner_stream_cnt = encode_vec2_vertex_stream(&vertices, e, codecs)?;
winner_size = (e.data().len() - ds) + (e.meta().len() - ms);
Ok(())
})?;
alt.with(|e| {
let ds = e.data().len();
let ms = e.meta().len();
let cnt = encode_hilbert_vertex_streams(&vertices, e, codecs)?;
let size = (e.data().len() - ds) + (e.meta().len() - ms);
if size < winner_size {
winner_stream_cnt = cnt;
winner_size = size;
}
Ok(())
})?;
alt.with(|e| {
let ds = e.data().len();
let ms = e.meta().len();
let cnt = encode_morton_vertex_streams(&vertices, e, codecs)?;
let size = (e.data().len() - ds) + (e.meta().len() - ms);
if size < winner_size {
winner_stream_cnt = cnt;
}
Ok(())
})?;
drop(alt);
n += winner_stream_cnt;
} else {
n += encode_vec2_vertex_stream(&vertices, enc, codecs)?;
}
debug_assert!(n <= 127, "geometry stream count must fit in one byte");
enc.data_mut()[stream_count_pos] = n;
Ok(())
}
}
fn write_length(
data: Vec<u32>,
ctx: StreamCtx,
enc: &mut Encoder,
codecs: &mut Codecs,
seen: &mut Option<Vec<u32>>,
) -> MltResult<u8> {
let n = write_geo_u32_stream(&data, ctx, enc, codecs)?;
if n != 0 {
*seen = Some(data);
}
Ok(n)
}
fn feature_relative_triangles(
vector_types: Vec<GeometryType>,
seen: Levels,
triangle_offsets: Vec<u32>,
index_buffer: Vec<u32>,
) -> MltResult<(Vec<u32>, Vec<u32>)> {
if index_buffer.is_empty() {
return Ok((Vec::new(), Vec::new()));
}
let triangles = triangle_offsets.windows(2).map(|w| w[1] - w[0]).collect();
let mut dec = Decoder::default();
let offsets = decode_topology(&vector_types, seen, &mut dec)?;
let mut dense = GeometryValues {
vector_types,
geometry_offsets: offsets.geometries,
part_offsets: offsets.parts,
ring_offsets: offsets.rings,
index_buffer: Some(index_buffer),
triangle_offsets: Some(triangle_offsets),
vertices: None,
#[cfg(feature = "unstable-v2")]
z_step: None,
};
dense.rebase_indices_to_feature()?;
Ok((triangles, dense.index_buffer.unwrap_or_default()))
}