use crate::backend::default::geometry::{
GeometryCore, GeometryInstanceData, ThemedMaterials, ThemedTextures,
};
use crate::cityjson::core::appearance::ThemeName;
use crate::cityjson::core::coordinate::Coordinate;
use crate::resources::handles::{
GeometryTemplateHandle, MaterialHandle, SemanticHandle, TextureHandle,
};
use crate::resources::id::ResourceId32;
use crate::resources::mapping::textures::TextureMapCore;
use crate::resources::mapping::{MaterialMap, SemanticMap, SemanticOrMaterialMap, TextureMap};
use crate::resources::storage::StringStorage;
use crate::v2_0::Vertices;
use crate::v2_0::boundary::Boundary;
use crate::v2_0::boundary::{BoundaryCoordinates, BoundaryUniqueCoordinates};
use crate::v2_0::vertex::{VertexIndex, VertexRef};
use std::marker::PhantomData;
use std::ops::{Deref, Index};
pub mod semantic;
pub use crate::backend::default::geometry::AffineTransform3D;
pub use crate::cityjson::core::geometry::{GeometryType, LoD};
#[derive(Clone, Debug)]
pub struct Geometry<VR: VertexRef, SS: StringStorage> {
inner: GeometryCore<VR, ResourceId32, SS>,
}
#[derive(Clone, Debug, PartialEq)]
pub struct StoredGeometryParts<VR: VertexRef, SS: StringStorage> {
pub type_geometry: GeometryType,
pub lod: Option<LoD>,
pub boundaries: Option<Boundary<VR>>,
pub semantics: Option<SemanticMap<VR>>,
pub materials: Option<Vec<(ThemeName<SS>, MaterialMap<VR>)>>,
pub textures: Option<Vec<(ThemeName<SS>, TextureMap<VR>)>>,
pub instance: Option<StoredGeometryInstance<VR>>,
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct StoredGeometryInstance<VR: VertexRef> {
pub template: GeometryTemplateHandle,
pub reference_point: VertexIndex<VR>,
pub transformation: AffineTransform3D,
}
#[derive(Clone, Copy, Debug)]
pub struct GeometryInstanceView<'a, VR: VertexRef> {
inner: &'a GeometryInstanceData<VR, ResourceId32>,
}
impl<VR: VertexRef> GeometryInstanceView<'_, VR> {
#[must_use]
pub fn template(&self) -> GeometryTemplateHandle {
GeometryTemplateHandle::from_raw(*self.inner.template())
}
#[must_use]
pub fn reference_point(&self) -> VertexIndex<VR> {
*self.inner.reference_point()
}
#[must_use]
pub fn transformation(&self) -> AffineTransform3D {
*self.inner.transformation()
}
}
#[derive(Clone, Copy, Debug)]
pub struct GeometryView<'a, VR: VertexRef, SS: StringStorage> {
geometry: &'a Geometry<VR, SS>,
instance: Option<GeometryInstanceView<'a, VR>>,
}
#[derive(Clone, Copy, Debug)]
pub struct HandleOptionSlice<'a, H> {
raw: &'a [Option<ResourceId32>],
_marker: PhantomData<H>,
}
impl<'a, H> HandleOptionSlice<'a, H> {
fn new(raw: &'a [Option<ResourceId32>]) -> Self {
Self {
raw,
_marker: PhantomData,
}
}
#[inline]
fn as_handle_slice(&self) -> &'a [Option<H>] {
const {
assert!(
std::mem::size_of::<Option<H>>() == std::mem::size_of::<Option<ResourceId32>>()
);
assert!(
std::mem::align_of::<Option<H>>() == std::mem::align_of::<Option<ResourceId32>>()
);
}
unsafe { std::slice::from_raw_parts(self.raw.as_ptr().cast::<Option<H>>(), self.raw.len()) }
}
#[must_use]
pub fn len(&self) -> usize {
self.raw.len()
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.raw.is_empty()
}
#[must_use]
pub fn get(&self, index: usize) -> Option<&'a Option<H>> {
self.as_handle_slice().get(index)
}
pub fn iter(&self) -> std::slice::Iter<'a, Option<H>> {
self.as_handle_slice().iter()
}
}
impl<H> Index<usize> for HandleOptionSlice<'_, H> {
type Output = Option<H>;
fn index(&self, index: usize) -> &Self::Output {
&self.as_handle_slice()[index]
}
}
impl<'a, H: 'a> IntoIterator for HandleOptionSlice<'a, H> {
type Item = &'a Option<H>;
type IntoIter = std::slice::Iter<'a, Option<H>>;
fn into_iter(self) -> Self::IntoIter {
self.as_handle_slice().iter()
}
}
impl<'a, H: 'a> IntoIterator for &'_ HandleOptionSlice<'a, H> {
type Item = &'a Option<H>;
type IntoIter = std::slice::Iter<'a, Option<H>>;
fn into_iter(self) -> Self::IntoIter {
self.as_handle_slice().iter()
}
}
#[derive(Clone, Copy, Debug)]
pub struct SemanticMapView<'a, VR: VertexRef> {
inner: &'a SemanticOrMaterialMap<VR, ResourceId32>,
}
impl<'a, VR: VertexRef> SemanticMapView<'a, VR> {
#[allow(clippy::trivially_copy_pass_by_ref)]
#[must_use]
pub fn points(&self) -> HandleOptionSlice<'a, SemanticHandle> {
HandleOptionSlice::new(self.inner.points())
}
#[allow(clippy::trivially_copy_pass_by_ref)]
#[must_use]
pub fn linestrings(&self) -> HandleOptionSlice<'a, SemanticHandle> {
HandleOptionSlice::new(self.inner.linestrings())
}
#[allow(clippy::trivially_copy_pass_by_ref)]
#[must_use]
pub fn surfaces(&self) -> HandleOptionSlice<'a, SemanticHandle> {
HandleOptionSlice::new(self.inner.surfaces())
}
}
#[derive(Clone, Copy, Debug)]
pub struct MaterialMapView<'a, VR: VertexRef> {
inner: &'a SemanticOrMaterialMap<VR, ResourceId32>,
}
impl<'a, VR: VertexRef> MaterialMapView<'a, VR> {
#[allow(clippy::trivially_copy_pass_by_ref)]
#[must_use]
pub fn points(&self) -> HandleOptionSlice<'a, MaterialHandle> {
HandleOptionSlice::new(self.inner.points())
}
#[allow(clippy::trivially_copy_pass_by_ref)]
#[must_use]
pub fn linestrings(&self) -> HandleOptionSlice<'a, MaterialHandle> {
HandleOptionSlice::new(self.inner.linestrings())
}
#[allow(clippy::trivially_copy_pass_by_ref)]
#[must_use]
pub fn surfaces(&self) -> HandleOptionSlice<'a, MaterialHandle> {
HandleOptionSlice::new(self.inner.surfaces())
}
}
#[derive(Clone, Copy, Debug)]
pub struct MaterialThemesView<'a, VR: VertexRef, SS: StringStorage> {
items: &'a [(ThemeName<SS>, SemanticOrMaterialMap<VR, ResourceId32>)],
}
impl<'a, VR: VertexRef, SS: StringStorage> MaterialThemesView<'a, VR, SS> {
#[must_use]
pub fn len(&self) -> usize {
self.items.len()
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.items.is_empty()
}
pub fn iter(&self) -> impl Iterator<Item = (&'a ThemeName<SS>, MaterialMapView<'a, VR>)> + 'a {
self.items
.iter()
.map(|(theme, map)| (theme, MaterialMapView { inner: map }))
}
#[must_use]
pub fn first(&self) -> Option<(&'a ThemeName<SS>, MaterialMapView<'a, VR>)> {
self.items
.first()
.map(|(theme, map)| (theme, MaterialMapView { inner: map }))
}
}
#[derive(Clone, Copy, Debug)]
pub struct TextureMapView<'a, VR: VertexRef> {
inner: &'a TextureMapCore<VR, ResourceId32>,
}
impl<'a, VR: VertexRef> TextureMapView<'a, VR> {
#[allow(clippy::trivially_copy_pass_by_ref)]
#[must_use]
pub fn vertices(&self) -> &'a [Option<VertexIndex<VR>>] {
self.inner.vertices()
}
#[allow(clippy::trivially_copy_pass_by_ref)]
#[must_use]
pub fn rings(&self) -> &'a [VertexIndex<VR>] {
self.inner.rings()
}
#[allow(clippy::trivially_copy_pass_by_ref)]
#[must_use]
pub fn ring_textures(&self) -> HandleOptionSlice<'a, TextureHandle> {
HandleOptionSlice::new(self.inner.ring_textures())
}
}
#[derive(Clone, Copy, Debug)]
pub struct TextureThemesView<'a, VR: VertexRef, SS: StringStorage> {
items: &'a [(ThemeName<SS>, TextureMapCore<VR, ResourceId32>)],
}
impl<'a, VR: VertexRef, SS: StringStorage> TextureThemesView<'a, VR, SS> {
#[must_use]
pub fn len(&self) -> usize {
self.items.len()
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.items.is_empty()
}
pub fn iter(&self) -> impl Iterator<Item = (&'a ThemeName<SS>, TextureMapView<'a, VR>)> + 'a {
self.items
.iter()
.map(|(theme, map)| (theme, TextureMapView { inner: map }))
}
#[must_use]
pub fn first(&self) -> Option<(&'a ThemeName<SS>, TextureMapView<'a, VR>)> {
self.items
.first()
.map(|(theme, map)| (theme, TextureMapView { inner: map }))
}
}
impl<VR: VertexRef, SS: StringStorage> Geometry<VR, SS> {
#[must_use]
pub fn from_stored_parts(parts: StoredGeometryParts<VR, SS>) -> Self {
let semantics = parts.semantics.map(SemanticMap::into_raw);
let materials = parts.materials.map(|items| {
items
.into_iter()
.map(|(theme, map)| (theme, map.into_raw()))
.collect()
});
let textures = parts.textures.map(|items| {
items
.into_iter()
.map(|(theme, map)| (theme, map.into_raw()))
.collect()
});
let instance = parts.instance.map(|instance| {
GeometryInstanceData::new(
instance.template.to_raw(),
instance.reference_point,
instance.transformation,
)
});
Self::from_raw_parts(
parts.type_geometry,
parts.lod,
parts.boundaries,
semantics,
materials,
textures,
instance,
)
}
pub(crate) fn from_raw_parts(
type_geometry: GeometryType,
lod: Option<LoD>,
boundaries: Option<Boundary<VR>>,
semantics: Option<SemanticOrMaterialMap<VR, ResourceId32>>,
materials: Option<ThemedMaterials<VR, ResourceId32, SS>>,
textures: Option<ThemedTextures<VR, ResourceId32, SS>>,
instance: Option<GeometryInstanceData<VR, ResourceId32>>,
) -> Self {
Self {
inner: GeometryCore::new(
type_geometry,
lod,
boundaries,
semantics,
materials,
textures,
instance,
),
}
}
pub(crate) fn raw(&self) -> &GeometryCore<VR, ResourceId32, SS> {
&self.inner
}
pub fn type_geometry(&self) -> &GeometryType {
self.inner.type_geometry()
}
pub fn lod(&self) -> Option<&LoD> {
self.inner.lod()
}
pub fn boundaries(&self) -> Option<&Boundary<VR>> {
self.inner.boundaries()
}
#[must_use]
pub fn coordinates<'a, V: Coordinate>(
&'a self,
vertices: &'a Vertices<VR, V>,
) -> Option<BoundaryCoordinates<'a, VR, V>> {
self.boundaries()
.map(|boundary| boundary.coordinates(vertices))
}
pub fn unique_vertex_indices<'a>(
&'a self,
scratch: &'a mut Vec<VertexIndex<VR>>,
) -> Option<&'a [VertexIndex<VR>]> {
self.boundaries()
.map(|boundary| boundary.unique_vertex_indices(scratch))
}
#[must_use]
pub fn unique_coordinates<'a, V: Coordinate>(
&'a self,
vertices: &'a Vertices<VR, V>,
scratch: &'a mut Vec<VertexIndex<VR>>,
) -> Option<BoundaryUniqueCoordinates<'a, VR, V>> {
self.boundaries()
.map(|boundary| boundary.unique_coordinates(vertices, scratch))
}
pub fn semantics(&self) -> Option<SemanticMapView<'_, VR>> {
self.inner
.semantics()
.map(|inner| SemanticMapView { inner })
}
pub fn materials(&self) -> Option<MaterialThemesView<'_, VR, SS>> {
self.inner
.materials()
.map(|items| MaterialThemesView { items })
}
pub fn textures(&self) -> Option<TextureThemesView<'_, VR, SS>> {
self.inner
.textures()
.map(|items| TextureThemesView { items })
}
pub fn instance(&self) -> Option<GeometryInstanceView<'_, VR>> {
self.inner
.instance()
.map(|inner| GeometryInstanceView { inner })
}
}
impl<'a, VR: VertexRef, SS: StringStorage> GeometryView<'a, VR, SS> {
pub(crate) fn from_geometry(
geometry: &'a Geometry<VR, SS>,
instance: Option<GeometryInstanceView<'a, VR>>,
) -> Self {
Self { geometry, instance }
}
#[must_use]
pub fn geometry(&self) -> &'a Geometry<VR, SS> {
self.geometry
}
#[must_use]
pub fn instance(&self) -> Option<GeometryInstanceView<'a, VR>> {
self.instance
}
}
impl<VR: VertexRef, SS: StringStorage> Deref for GeometryView<'_, VR, SS> {
type Target = Geometry<VR, SS>;
fn deref(&self) -> &Self::Target {
self.geometry
}
}