use crate::model::geometry::aggregates::AggregationType;
use crate::model::geometry::primitives::{
AbstractSurface, AsAbstractSurface, AsAbstractSurfaceMut, SurfaceProperty, TriangulatedSurface,
};
use crate::model::geometry::{DirectPosition, Envelope};
use crate::{Error, impl_abstract_surface_traits};
use nalgebra::Isometry3;
use rayon::iter::IntoParallelRefMutIterator;
use rayon::iter::ParallelIterator;
#[derive(Debug, Clone, PartialEq)]
pub struct CompositeSurface {
pub(crate) abstract_surface: AbstractSurface,
surface_member: Vec<SurfaceProperty>,
aggregation_type: AggregationType,
}
impl CompositeSurface {
pub fn new(
surface_members: impl IntoIterator<Item = SurfaceProperty>,
aggregation_type: AggregationType,
) -> Result<Self, Error> {
let surface_members: Vec<SurfaceProperty> = surface_members.into_iter().collect();
if surface_members.is_empty() {
return Err(Error::TooFewElements {
geometry: "gml:CompositeSurface",
minimum: 1,
spec: Some("OGC 07-036 §10.5.11.4"),
id: None,
detail: None,
});
}
Ok(CompositeSurface {
abstract_surface: AbstractSurface::default(),
surface_member: surface_members,
aggregation_type,
})
}
pub fn surface_member(&self) -> &[SurfaceProperty] {
&self.surface_member
}
pub fn set_surface_member(&mut self, surface_members: Vec<SurfaceProperty>) {
self.surface_member = surface_members;
}
pub fn push_surface_member(&mut self, member: SurfaceProperty) {
self.surface_member.push(member);
}
pub fn extend_surface_members(&mut self, members: impl IntoIterator<Item = SurfaceProperty>) {
self.surface_member.extend(members);
}
pub fn aggregation_type(&self) -> AggregationType {
self.aggregation_type
}
pub fn set_aggregation_type(&mut self, aggregation_type: AggregationType) {
self.aggregation_type = aggregation_type;
}
}
impl CompositeSurface {
pub fn surface_member_count(&self) -> usize {
self.surface_member.len()
}
pub fn triangulate(&self) -> Result<TriangulatedSurface, Error> {
let triangulated_surfaces = self
.surface_member
.iter()
.flat_map(|x| x.object.as_ref())
.map(|x| x.triangulate())
.collect::<Result<Vec<TriangulatedSurface>, Error>>()?;
TriangulatedSurface::from_triangulated_surfaces(triangulated_surfaces)
}
pub fn compute_envelope(&self) -> Option<Envelope> {
let envelopes: Vec<Envelope> = self
.surface_member
.iter()
.flat_map(|x| x.object.as_ref())
.flat_map(|x| x.compute_envelope())
.collect::<Vec<_>>();
Envelope::from_envelopes(&envelopes)
}
pub fn area_3d(&self) -> Result<f64, Error> {
self.surface_member
.iter()
.map(|s| {
s.object
.as_ref()
.ok_or_else(|| Error::UnresolvedSurfaceReference {
href: s.href.clone(),
})
.and_then(|kind| kind.area_3d())
})
.collect::<Result<Vec<f64>, Error>>()
.map(|area_3ds| area_3ds.into_iter().sum())
}
pub fn apply_transform(&mut self, m: &Isometry3<f64>) {
self.surface_member
.par_iter_mut()
.flat_map(|x| x.object.as_mut())
.for_each(|x| x.apply_transform(m));
}
pub fn points(&self) -> Vec<&DirectPosition> {
todo!("needs to be implemented")
}
}
impl AsAbstractSurface for CompositeSurface {
fn abstract_surface(&self) -> &AbstractSurface {
&self.abstract_surface
}
}
impl AsAbstractSurfaceMut for CompositeSurface {
fn abstract_surface_mut(&mut self) -> &mut AbstractSurface {
&mut self.abstract_surface
}
}
impl_abstract_surface_traits!(CompositeSurface);