ecitygml-core 0.0.1-alpha.13

Core primitives and operations for processing CityGML data.
Documentation
use crate::model::building::Building;
use crate::model::city_furniture::CityFurniture;
use crate::model::core::{
    AbstractFeature, AsAbstractFeature, AsAbstractFeatureMut, CityObjectKind, CityObjectRef,
};
use crate::model::transportation::Road;
use crate::model::vegetation::SolitaryVegetationObject;
use crate::operations::{Visitable, Visitor};
use egml::model::base::Id;
use egml::model::geometry::Envelope;
use nalgebra::Isometry3;
use rayon::prelude::*;

#[derive(Debug, Clone, PartialEq)]
pub struct CityModel {
    pub abstract_feature: AbstractFeature,
    pub city_objects: Vec<CityObjectKind>,
}

impl CityModel {
    pub fn new(abstract_feature: AbstractFeature, city_objects: Vec<CityObjectKind>) -> Self {
        Self {
            abstract_feature,
            city_objects,
        }
    }

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

        let combined_city_objects: Vec<CityObjectKind> = city_models
            .into_iter()
            .flat_map(|x| x.city_objects)
            .collect();

        CityModel::new(abstract_feature, combined_city_objects)
    }

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

    pub fn city_objects(&self) -> &Vec<CityObjectKind> {
        &self.city_objects
    }

    pub fn city_objects_len(&self) -> usize {
        self.city_objects.len()
    }

    pub fn iter_city_object<'a>(&'a self) -> impl Iterator<Item = CityObjectRef<'a>> + 'a {
        self.city_objects.iter().flat_map(|x| x.iter_city_object())
    }

    pub fn refresh_bounded_by_recursive(&mut self) {
        self.city_objects
            .par_iter_mut()
            .for_each(|x| x.refresh_bounded_by_recursive());

        let envelopes: Vec<&Envelope> = self
            .city_objects
            .iter()
            .filter_map(|x| x.bounded_by())
            .collect();

        self.set_bounded_by(Envelope::from_envelopes(&envelopes));
    }

    pub fn apply_transform_recursive(&mut self, m: &Isometry3<f64>) {
        self.city_objects
            .par_iter_mut()
            .for_each(|x| x.apply_transform_recursive(m));
    }

    pub fn filter_city_objects_by_envelope(&mut self, filter_envelope: &Envelope) {
        self.city_objects.retain(|obj| {
            obj.bounded_by()
                .is_some_and(|env| filter_envelope.contains_envelope_partially(env))
        });
    }

    pub fn roads(&self) -> Vec<&Road> {
        self.city_objects
            .iter()
            .filter_map(|x| match x {
                CityObjectKind::Road(x) => Some(x),
                _ => None,
            })
            .collect()
    }

    pub fn buildings(&self) -> Vec<&Building> {
        self.city_objects
            .iter()
            .filter_map(|x| match x {
                CityObjectKind::Building(x) => Some(x),
                _ => None,
            })
            .collect()
    }

    pub fn solitary_vegetation_objects(&self) -> Vec<&SolitaryVegetationObject> {
        self.city_objects
            .iter()
            .filter_map(|x| match x {
                CityObjectKind::SolitaryVegetationObject(x) => Some(x),
                _ => None,
            })
            .collect()
    }

    pub fn city_furniture_objects(&self) -> Vec<&CityFurniture> {
        self.city_objects
            .iter()
            .filter_map(|x| match x {
                CityObjectKind::CityFurniture(x) => Some(x),
                _ => None,
            })
            .collect()
    }
}

impl AsAbstractFeature for CityModel {
    fn abstract_feature(&self) -> &AbstractFeature {
        &self.abstract_feature
    }
}

impl AsAbstractFeatureMut for CityModel {
    fn abstract_feature_mut(&mut self) -> &mut AbstractFeature {
        &mut self.abstract_feature
    }
}

impl Visitable for CityModel {
    fn accept<V: Visitor>(&self, visitor: &mut V) {
        visitor.visit_city_model(self);

        for feature in &self.city_objects {
            match feature {
                CityObjectKind::Building(x) => {
                    x.accept(visitor);
                }
                CityObjectKind::BuildingConstructiveElement(x) => {
                    x.accept(visitor);
                }
                CityObjectKind::CityFurniture(x) => {
                    x.accept(visitor);
                }
                CityObjectKind::ReliefFeature(x) => {
                    x.accept(visitor);
                }
                CityObjectKind::Road(x) => {
                    x.accept(visitor);
                }
                CityObjectKind::SolitaryVegetationObject(x) => {
                    x.accept(visitor);
                }
                CityObjectKind::TinRelief(x) => {
                    x.accept(visitor);
                }
                CityObjectKind::TrafficSpace(x) => {
                    x.accept(visitor);
                }
                CityObjectKind::AuxiliaryTrafficSpace(x) => {
                    x.accept(visitor);
                }
                CityObjectKind::TrafficArea(x) => {
                    x.accept(visitor);
                }
                CityObjectKind::AuxiliaryTrafficArea(x) => {
                    x.accept(visitor);
                }
                CityObjectKind::Section(x) => {
                    x.accept(visitor);
                }
                CityObjectKind::Intersection(x) => {
                    x.accept(visitor);
                }
                CityObjectKind::DoorSurface(x) => {
                    x.accept(visitor);
                }
                CityObjectKind::GroundSurface(x) => {
                    x.accept(visitor);
                }
                CityObjectKind::RoofSurface(x) => {
                    x.accept(visitor);
                }
                CityObjectKind::WallSurface(x) => {
                    x.accept(visitor);
                }
                CityObjectKind::WindowSurface(x) => {
                    x.accept(visitor);
                }
            }
        }
    }
}