use std::sync::{
Arc,
atomic::{AtomicBool, Ordering},
};
use geo::Intersects as _;
use crate::{BoxedImageDataRef, BoxedLayer, ImageFeature, Layer, geometry};
pub trait Feature: Send + Sync
{
fn geometry(&self) -> Option<geo::Geometry>;
fn image<'a>(&'a self) -> Option<ImageFeature<BoxedImageDataRef<'a>>>;
fn geometry_type(&self) -> geometry::GeometryType;
fn element_geometry_type(&self) -> geometry::GeometryType;
fn intersects(&self, rect: geo::Rect) -> bool;
}
pub trait GeometryRef: Send + Sync
{
fn geometry_ref(&self) -> &geo::Geometry;
}
impl<T> Feature for T
where
T: GeometryRef,
{
fn geometry(&self) -> Option<geo::Geometry>
{
Some(self.geometry_ref().to_owned())
}
fn image(&self) -> Option<ImageFeature<BoxedImageDataRef<'_>>>
{
None
}
fn geometry_type(&self) -> geometry::GeometryType
{
use crate::geometry::GeometryExt;
self.geometry_ref().geometry_type()
}
fn element_geometry_type(&self) -> geometry::GeometryType
{
use crate::geometry::GeometryExt;
self.geometry_ref().element_geometry_type()
}
fn intersects(&self, rect: geo::Rect) -> bool
{
self.geometry_ref().intersects(&rect)
}
}
struct MapLayer<TFeature: Feature>
{
name: String,
layer: BoxedLayer<TFeature>,
visible: AtomicBool,
}
pub struct Map<TFeature: Feature>
{
layers: Vec<MapLayer<TFeature>>,
}
ccutils::assert_impl_all!(for(TFeature: Feature) Map<TFeature>: Sync);
ccutils::assert_impl_all!(for(TFeature: Feature) Map<TFeature>: Send);
impl<TFeature: Feature> Default for Map<TFeature>
{
fn default() -> Self
{
Self::new()
}
}
impl<TFeature: Feature> Map<TFeature>
{
pub fn new() -> Self
{
Self {
layers: Default::default(),
}
}
pub fn add_visible_layer(
&mut self,
name: impl Into<String>,
layer: impl Layer<TFeature> + 'static,
)
{
let name = name.into();
let layer = Box::new(layer);
self.layers.push(MapLayer {
name,
layer,
visible: AtomicBool::new(true),
});
}
pub fn hide_layer<'a>(&mut self, name: impl Into<&'a str>)
{
let name = name.into();
self.layers.iter_mut().for_each(|l| {
if l.name == name
{
l.visible.store(false, Ordering::Relaxed);
}
});
}
pub fn visible_layers(&self) -> impl Iterator<Item = &BoxedLayer<TFeature>>
{
self
.layers
.iter()
.filter(|l| l.visible.load(Ordering::Relaxed))
.map(|ml| &ml.layer)
}
pub fn is_visible<'a>(&self, name: impl Into<&'a str>) -> bool
{
let name = name.into();
self
.layers
.iter()
.find_map(|l| {
if l.name == name
{
Some(l.visible.load(Ordering::Relaxed))
}
else
{
None
}
})
.unwrap_or(false)
}
pub fn maybe_update_visibility<'a>(&self, name: impl Into<&'a str>, visibility: bool) -> bool
{
let name = name.into();
self
.layers
.iter()
.find_map(|l| {
if l.name == name
{
Some(l.visible.swap(visibility, Ordering::Relaxed) != visibility)
}
else
{
None
}
})
.unwrap_or(false)
}
}
pub struct MapBuilder<TFeature: Feature>
{
map: Map<TFeature>,
}
impl<TFeature: Feature> Default for MapBuilder<TFeature>
{
fn default() -> Self
{
Self::new()
}
}
impl<TFeature: Feature> MapBuilder<TFeature>
{
pub fn new() -> Self
{
Self { map: Map::new() }
}
pub fn add_visible_layer(
mut self,
name: impl Into<String>,
layer: impl Layer<TFeature> + 'static,
) -> Self
{
self.map.add_visible_layer(name, layer);
self
}
}
impl<TFeature: Feature> From<MapBuilder<TFeature>> for Map<TFeature>
{
fn from(val: MapBuilder<TFeature>) -> Self
{
val.map
}
}
impl<TFeature: Feature> From<MapBuilder<TFeature>> for Arc<Map<TFeature>>
{
fn from(val: MapBuilder<TFeature>) -> Self
{
Arc::new(val.into())
}
}