Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions rust/mlt-nom/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ hex = "0.4.3"
integer-encoding = "4.0.2"
num-traits = "0.2.19"
num_enum = "0.7.4"
strum = { version = "0.27.0", default-features = false, features = ["derive"] }
thiserror = "2.0.11"
zigzag = "0.1.0"

Expand All @@ -36,3 +37,4 @@ pedantic = { level = "warn", priority = -1 }
missing_errors_doc = "allow"
multiple_crate_versions = "allow"
missing_panics_doc = "allow"
too_many_lines = "allow"
16 changes: 7 additions & 9 deletions rust/mlt-nom/src/decodable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,16 @@ pub trait Decodable<'a>: Sized {
/// Borrow the decoded data if available
fn borrow_decoded(&self) -> Option<&Self::DecodedType>;

fn materialize(&mut self) -> Result<&Self::DecodedType, MltError> {
fn materialize(&mut self) -> Result<&Self, MltError> {
if self.is_raw() {
// Temporarily replace self with a default value to take ownership of the raw data
let raw = self.take_raw().expect("Expected raw data");
*self = Self::new_decoded(Self::DecodedType::from_raw(raw)?);
let Some(raw) = self.take_raw() else {
return Err(MltError::DecodeError("Expected raw data".to_string()))?;
};
let res = Self::DecodedType::from_raw(raw)?;
*self = Self::new_decoded(res);
}
Ok(self.borrow_decoded().expect("Expected decoded data"))
}

fn ensure_decoded(&mut self) -> Result<(), MltError> {
self.materialize()?;
Ok(())
Ok(self)
}
}

Expand Down
2 changes: 2 additions & 0 deletions rust/mlt-nom/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ pub type MltRefResult<'a, T> = Result<(&'a [u8], T), MltError>;
#[derive(Debug, thiserror::Error)]
#[non_exhaustive]
pub enum MltError {
#[error("{0}")]
DecodeError(String),
#[error("Integer overflow")]
IntegerOverflow,
#[error("multiple ID columns found (only one allowed)")]
Expand Down
41 changes: 28 additions & 13 deletions rust/mlt-nom/src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -179,21 +179,36 @@ pub struct OptSeq<'a, T>(pub Option<&'a [T]>);

impl<T: Display + Debug> Debug for OptSeq<'_, T> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
if let Some(v) = self.0 {
write!(
f,
"[{}{}; {}]",
v.iter()
.take(8)
.map(ToString::to_string)
.collect::<Vec<_>>()
.join(","),
if v.len() > 8 { ", ..." } else { "" },
v.len()
)
write_seq(f, self.0, ToString::to_string)
}
}

pub struct OptSeqOpt<'a, T>(pub Option<&'a [Option<T>]>);

impl<T: Display + Debug> Debug for OptSeqOpt<'_, T> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write_seq(f, self.0, |opt| match opt {
Some(val) => val.to_string(),
None => "None".to_string(),
})
}
}

fn write_seq<T>(
f: &mut Formatter,
value: Option<&[T]>,
to_str: fn(&T) -> String,
) -> std::fmt::Result {
if let Some(v) = value {
let items = v.iter().take(8).map(to_str).collect::<Vec<_>>().join(",");
write!(f, "[{items}")?;
if v.len() > 8 {
write!(f, ", ...; {}]", v.len())
} else {
write!(f, "None")
write!(f, "]")
}
} else {
write!(f, "None")
}
}

Expand Down
218 changes: 171 additions & 47 deletions rust/mlt-nom/src/v01/geometry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ pub struct DecodedGeometry {
}

/// Types of geometries supported in MLT
#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, TryFromPrimitive)]
#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, TryFromPrimitive, strum::Display)]
#[repr(u8)]
pub enum GeometryType {
Point,
Expand Down Expand Up @@ -94,9 +94,7 @@ impl<'a> Geometry<'a> {
impl Debug for DecodedGeometry {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("DecodedGeometry")
// .field("vector_type", &self.vector_type)
// .field("vertex_buffer_type", &self.vertex_buffer_type)
.field("vector_types", &self.vector_types)
.field("vector_types", &OptSeq(Some(&self.vector_types)))
.field(
"geometry_offsets",
&OptSeq(self.geometry_offsets.as_deref()),
Expand All @@ -115,7 +113,6 @@ impl<'a> FromRaw<'a> for DecodedGeometry {
type Input = RawGeometry<'a>;

fn from_raw(RawGeometry { meta, items }: RawGeometry<'a>) -> Result<Self, MltError> {
// let vector_type = Self::get_vector_type_int_stream(&meta);
let vector_types = decode_geometry_types(meta)?;
let mut geometry_offsets: Option<Vec<u32>> = None;
let mut part_offsets: Option<Vec<u32>> = None;
Expand All @@ -133,13 +130,17 @@ impl<'a> FromRaw<'a> for DecodedGeometry {
let v = stream.decode_bits_u32()?.decode_i32()?;
vertices.set_once(v)?;
}
_ => todo!("Geometry stream cannot have Data physical type: {v:?}"),
v => Err(MltError::DecodeError(format!(
"Geometry stream cannot have Data physical type {v:?}"
)))?,
},
PhysicalStreamType::Offset(v) => {
let target = match v {
OffsetType::Vertex => &mut vertex_offsets,
OffsetType::Index => &mut index_buffer,
_ => todo!("Geometry stream cannot have Offset physical type: {v:?}"),
v => Err(MltError::DecodeError(format!(
"Geometry stream cannot have Offset physical type {v:?}"
)))?,
};
target.set_once(stream.decode_bits_u32()?.decode_u32()?)?;
}
Expand All @@ -149,7 +150,9 @@ impl<'a> FromRaw<'a> for DecodedGeometry {
LengthType::Parts => &mut part_offsets,
LengthType::Rings => &mut ring_offsets,
LengthType::Triangles => &mut triangles,
_ => todo!("Geometry stream cannot have Length physical type: {v:?}"),
v => Err(MltError::DecodeError(format!(
"Geometry stream cannot have Length physical type {v:?}"
)))?,
};
// LogicalStream2<U> -> LogicalStream -> trait LogicalStreamDecoder<T>
target.set_once(stream.decode_bits_u32()?.decode_u32()?)?;
Expand All @@ -162,7 +165,9 @@ impl<'a> FromRaw<'a> for DecodedGeometry {
// topology data are present in the tile
//
// return FlatGpuVector::new(vector_types, triangles, index_buffer, vertices);
todo!("index_buffer.is_some() && part_offsets.is_none() case is not implemented");
return Err(MltError::NotImplemented(
"index_buffer.is_some() && part_offsets.is_none() case is not implemented",
));
}

// Use decode_root_length_stream if geometry_offsets is present
Expand All @@ -172,39 +177,41 @@ impl<'a> FromRaw<'a> for DecodedGeometry {
&offsets,
GeometryType::Polygon,
));
if let Some(_part_offsets) = part_offsets.take() {
if let Some(_ring_offsets) = ring_offsets.take() {
// auto partOffsetsCopy = partOffsets;
// decodeLevel1LengthStream(geometryTypes,
// geometryOffsets,
// partOffsetsCopy,
// /*isLineStringPresent=*/false,
// partOffsets);
// auto ringOffsetsCopy = ringOffsets;
// decodeLevel2LengthStream(geometryTypes, geometryOffsets, partOffsets, ringOffsetsCopy, ringOffsets);
todo!(
"geometry_offsets with part_offsets and ring_offsets case is not implemented"
);
if let Some(part_offsets_copy) = part_offsets.take() {
if let Some(ring_offsets_copy) = ring_offsets.take() {
part_offsets = Some(decode_level1_length_stream(
&vector_types,
geometry_offsets.as_ref().unwrap(),
&part_offsets_copy,
false, // isLineStringPresent
));
ring_offsets = Some(decode_level2_length_stream(
&vector_types,
geometry_offsets.as_ref().unwrap(),
part_offsets.as_ref().unwrap(),
&ring_offsets_copy,
));
} else {
// auto partOffsetsCopy = partOffsets;
// decodeLevel1WithoutRingBufferLengthStream(
// geometryTypes, geometryOffsets, partOffsetsCopy, partOffsets);
todo!("geometry_offsets with part_offsets case is not implemented");
part_offsets = Some(decode_level1_without_ring_buffer_length_stream(
&vector_types,
geometry_offsets.as_ref().unwrap(),
&part_offsets_copy,
));
}
}
} else if let Some(offsets) = part_offsets.take() {
if let Some(_ring_offsets) = ring_offsets {
if let Some(ring_offsets_copy) = ring_offsets.take() {
part_offsets = Some(decode_root_length_stream(
&vector_types,
&offsets,
GeometryType::LineString,
));
// decodeLevel1LengthStream(geometryTypes,
// partOffsets,
// ringOffsetsCopy,
// /*isLineStringPresent=*/true,
// ringOffsets);
todo!("part_offsets with ring_offsets case is not implemented");
ring_offsets = Some(decode_level1_length_stream(
&vector_types,
part_offsets.as_ref().unwrap(),
&ring_offsets_copy,
true, // isLineStringPresent
));
} else {
part_offsets = Some(decode_root_length_stream(
&vector_types,
Expand All @@ -214,22 +221,10 @@ impl<'a> FromRaw<'a> for DecodedGeometry {
}
}

if let Some(index_buffer) = index_buffer {
// Case when the indices of a Polygon outline are encoded in the tile

/* return
std::make_unique<geometry::FlatGpuVector>(
std::move(geometryTypes),
std::move(triangles),
std::move(indexBuffer),
std::move(vertices),
geometry::TopologyVector(std::move(geometryOffsets), std::move(partOffsets), std::move(ringOffsets));
*/
todo!("index_buffer.is_some() case is not implemented");
}
// Case when the indices of a Polygon outline are encoded in the tile
// This is handled by including index_buffer in the DecodedGeometry

Ok(DecodedGeometry {
// vector_type,
// vertex_buffer_type: VertexBufferType::Vec2, // Morton not supported yet
vector_types,
geometry_offsets,
Expand Down Expand Up @@ -297,3 +292,132 @@ fn decode_root_length_stream(
}
root_buffer_offsets
}

/// Case where no ring buffer exists so no `MultiPolygon` or `Polygon` geometry is part of the buffer
fn decode_level1_without_ring_buffer_length_stream(
geometry_types: &[GeometryType],
root_offset_buffer: &[u32],
level1_length_buffer: &[u32],
) -> Vec<u32> {
let final_size = root_offset_buffer[root_offset_buffer.len() - 1] as usize + 1;
let mut level1_buffer_offsets = Vec::with_capacity(final_size);
level1_buffer_offsets.push(0);
let mut previous_offset = 0_u32;
let mut level1_offset_buffer_counter = 1_usize;
let mut level1_length_counter = 0_usize;

for (i, &geometry_type) in geometry_types.iter().enumerate() {
let num_geometries = (root_offset_buffer[i + 1] - root_offset_buffer[i]) as usize;

if geometry_type == GeometryType::MultiLineString
|| geometry_type == GeometryType::LineString
{
// For MultiLineString and LineString a value in the level1LengthBuffer exists
for _j in 0..num_geometries {
previous_offset += level1_length_buffer[level1_length_counter];
level1_length_counter += 1;
level1_buffer_offsets.push(previous_offset);
level1_offset_buffer_counter += 1;
}
} else {
// For MultiPoint and Point no value in level1LengthBuffer exists
for _j in 0..num_geometries {
previous_offset += 1;
level1_buffer_offsets.push(previous_offset);
level1_offset_buffer_counter += 1;
}
}
}

level1_buffer_offsets
}

fn decode_level1_length_stream(
geometry_types: &[GeometryType],
root_offset_buffer: &[u32],
level1_length_buffer: &[u32],
is_line_string_present: bool,
) -> Vec<u32> {
let final_size = root_offset_buffer[root_offset_buffer.len() - 1] as usize + 1;
let mut level1_buffer_offsets = Vec::with_capacity(final_size);
level1_buffer_offsets.push(0);
let mut previous_offset = 0_u32;
let mut level1_buffer_counter = 1_usize;
let mut level1_length_buffer_counter = 0_usize;

for (i, &geometry_type) in geometry_types.iter().enumerate() {
let num_geometries = (root_offset_buffer[i + 1] - root_offset_buffer[i]) as usize;

if geometry_type == GeometryType::MultiPolygon
|| geometry_type == GeometryType::Polygon
|| (is_line_string_present
&& (geometry_type == GeometryType::MultiLineString
|| geometry_type == GeometryType::LineString))
{
// For MultiPolygon, Polygon and in some cases for MultiLineString and LineString
// a value in the level1LengthBuffer exists
for _j in 0..num_geometries {
previous_offset += level1_length_buffer[level1_length_buffer_counter];
level1_length_buffer_counter += 1;
level1_buffer_offsets.push(previous_offset);
level1_buffer_counter += 1;
}
} else {
// For MultiPoint and Point and in some cases for MultiLineString and LineString
// no value in the level1LengthBuffer exists
for _j in 0..num_geometries {
previous_offset += 1;
level1_buffer_offsets.push(previous_offset);
level1_buffer_counter += 1;
}
}
}

level1_buffer_offsets
}

fn decode_level2_length_stream(
geometry_types: &[GeometryType],
root_offset_buffer: &[u32],
level1_offset_buffer: &[u32],
level2_length_buffer: &[u32],
) -> Vec<u32> {
let final_size = level1_offset_buffer[level1_offset_buffer.len() - 1] as usize + 1;
let mut level2_buffer_offsets = Vec::with_capacity(final_size);
level2_buffer_offsets.push(0);
let mut previous_offset = 0_u32;
let mut level1_offset_buffer_counter = 1_usize;
let mut level2_offset_buffer_counter = 1_usize;
let mut level2_length_buffer_counter = 0_usize;

for (i, &geometry_type) in geometry_types.iter().enumerate() {
let num_geometries = (root_offset_buffer[i + 1] - root_offset_buffer[i]) as usize;

if geometry_type != GeometryType::Point && geometry_type != GeometryType::MultiPoint {
// For MultiPolygon, MultiLineString, Polygon and LineString a value in level2LengthBuffer
// exists
for _j in 0..num_geometries {
let num_parts = (level1_offset_buffer[level1_offset_buffer_counter]
- level1_offset_buffer[level1_offset_buffer_counter - 1])
as usize;
level1_offset_buffer_counter += 1;
for _k in 0..num_parts {
previous_offset += level2_length_buffer[level2_length_buffer_counter];
level2_length_buffer_counter += 1;
level2_buffer_offsets.push(previous_offset);
level2_offset_buffer_counter += 1;
}
}
} else {
// For MultiPoint and Point no value in level2LengthBuffer exists
for _j in 0..num_geometries {
previous_offset += 1;
level2_buffer_offsets.push(previous_offset);
level2_offset_buffer_counter += 1;
level1_offset_buffer_counter += 1;
}
}
}

level2_buffer_offsets
}
Loading