ecitygml-core 0.0.2-alpha.3

Core primitives and operations for processing CityGML data.
Documentation
use crate::model::common::{FeatureRef, FeatureRefMut, TopLevelFeatureRef};
use crate::model::core::{
    AbstractFeature, AbstractFeatureWithLifespan, AsAbstractFeature, AsAbstractFeatureWithLifespan,
    AsAbstractFeatureWithLifespanMut, CityObjectProperty,
};
use egml::model::base::Id;
use egml::model::geometry::Envelope;
use nalgebra::Isometry3;
use rayon::prelude::*;

#[derive(Debug, Clone, PartialEq)]
pub struct CityModel {
    pub(crate) abstract_feature_with_lifespan: AbstractFeatureWithLifespan,
    pub city_object_members: Vec<CityObjectProperty>,
}

impl CityModel {
    pub fn new(abstract_feature_with_lifespan: AbstractFeatureWithLifespan) -> Self {
        Self {
            abstract_feature_with_lifespan,
            city_object_members: Default::default(),
        }
    }

    pub fn iter_features<'a>(&'a self) -> impl Iterator<Item = FeatureRef<'a>> + 'a {
        self.city_object_members
            .iter()
            .flat_map(|p| p.object.as_ref())
            .flat_map(|x| x.iter_features())
    }

    pub fn recompute_child_bounding_shapes(&mut self) {
        self.city_object_members
            .par_iter_mut()
            .filter_map(|x| x.object.as_mut())
            .for_each(|current_city_object| {
                current_city_object.for_each_feature_mut(&mut |mut x: FeatureRefMut<'_>| {
                    x.recompute_bounding_shape()
                })
            });
    }

    pub fn apply_transform(&mut self, m: &Isometry3<f64>) {
        self.city_object_members
            .par_iter_mut()
            .filter_map(|x| x.object.as_mut())
            .for_each(|x| x.apply_transform(m));
    }

    pub fn from_city_models(city_models: Vec<Self>) -> Self {
        let abstract_feature = AbstractFeature::new(Id::generate_uuid_v4());
        let abstract_feature_with_lifespan = AbstractFeatureWithLifespan::new(abstract_feature);
        let mut combined_city_model = CityModel::new(abstract_feature_with_lifespan);

        let combined_city_object_members: Vec<CityObjectProperty> = city_models
            .into_iter()
            .flat_map(|x| x.city_object_members)
            .collect();
        combined_city_model.set_city_object_members(combined_city_object_members);

        combined_city_model
    }

    pub fn is_empty(&self) -> bool {
        self.city_object_members.is_empty()
    }

    pub fn city_object_members(&self) -> &Vec<CityObjectProperty> {
        &self.city_object_members
    }

    pub fn city_object_members_len(&self) -> usize {
        self.city_object_members.len()
    }

    pub fn set_city_object_members(&mut self, values: Vec<CityObjectProperty>) {
        self.city_object_members = values;
    }

    pub fn iter_top_level_features(&self) -> impl Iterator<Item = TopLevelFeatureRef<'_>> + '_ {
        self.city_object_members
            .iter()
            .flat_map(|p| p.object.as_ref())
            .filter_map(|x| x.try_into().ok())
    }

    pub fn filter_city_objects_by_envelope(&mut self, filter_envelope: &Envelope) {
        self.city_object_members.retain(|obj| {
            if let Some(x) = obj.object.as_ref() {
                x.bounded_by()
                    .is_some_and(|env| filter_envelope.contains_envelope_partially(env))
            } else {
                false
            }
        });
    }
}

impl AsAbstractFeatureWithLifespan for CityModel {
    fn abstract_feature_with_lifespan(&self) -> &AbstractFeatureWithLifespan {
        &self.abstract_feature_with_lifespan
    }
}

impl AsAbstractFeatureWithLifespanMut for CityModel {
    fn abstract_feature_with_lifespan_mut(&mut self) -> &mut AbstractFeatureWithLifespan {
        &mut self.abstract_feature_with_lifespan
    }
}

crate::impl_abstract_feature_with_lifespan_traits!(CityModel);