#![allow(clippy::mut_from_ref)]
use {
crate::{
geometry::{Point, Aabb, Real, VectorExt, DistPoint},
sdf::{SDF, Lipschitz},
},
quadtree::{
Quadtree, Node, Refine, Dim, Branching, Children, child_rect, child_rects
},
std::{
sync::Arc,
fmt::{Debug, Formatter}
},
nalgebra::Scalar,
};
#[cfg(test)] mod tests;
pub mod quadtree;
#[derive(Clone)]
pub struct Primitive<Float: Scalar, const D: usize> {
pub f: Arc<dyn Fn(Point<Float, D>) -> Float + Send + Sync>,
pub lipschitz: Float,
}
impl<_Float: Real, const D: usize> Primitive<_Float, D> {
pub fn new(f: impl Fn(Point<_Float, D>) -> _Float + Send + Sync + 'static) -> Self {
Self { f: Arc::new(f), lipschitz: _Float::one() }
}
pub fn with_lipschitz(mut self, lipschitz: _Float) -> Self {
self.lipschitz = lipschitz;
self
}
pub fn from_shape<S>(shape: S) -> Self
where
S: SDF<_Float, D> + Lipschitz<_Float> + Send + Sync + 'static,
{
let lipschitz = shape.lipschitz();
Self { f: Arc::new(move |p| shape.sdf(p)), lipschitz }
}
}
#[derive(Clone)]
pub struct ADF<Float: Scalar, const D: usize> {
pub tree: Quadtree<Vec<Primitive<Float, D>>, Float, D>,
prune_subdiv: u32,
lipschitz_max: Float,
}
impl <_Float: Real, const D: usize> SDF<_Float, D> for &[Primitive<_Float, D>] {
fn sdf(&self, pixel: Point<_Float, D>) -> _Float {
self.iter()
.map(|p| (p.f)(pixel))
.reduce(|a, b| if a <= b { a } else { b })
.unwrap_or(_Float::max_value() / (_Float::one() + _Float::one()))
}
}
fn bucket_lipschitz<_Float: Real, const D: usize>(bucket: &[Primitive<_Float, D>]) -> _Float {
bucket.iter().map(|p| p.lipschitz).fold(_Float::one(), _Float::max)
}
pub fn sdf_geq_everywhere<_Float, F, G, const D: usize>(
f: F,
g: G,
domain: Aabb<_Float, D>,
l_f: _Float,
l_g: _Float,
max_subdiv: u32,
) -> bool
where
_Float: Real,
F: Fn(Point<_Float, D>) -> _Float,
G: Fn(Point<_Float, D>) -> _Float,
Dim<D>: Branching,
{
let two = _Float::one() + _Float::one();
let l_sum = l_f + l_g;
let mut stack = vec![(domain, 0u32)];
while let Some((rect, depth)) = stack.pop() {
let diff = f(rect.center()) - g(rect.center());
if diff < _Float::zero() {
return false; }
let half_diag = rect.size().length() / two;
if diff >= l_sum * half_diag {
continue; }
if depth >= max_subdiv {
return false; }
for sub in child_rects(rect) {
stack.push((sub, depth + 1));
}
}
true
}
impl <_Float: Real + Send + Sync, const D: usize> ADF<_Float, D>
where
Dim<D>: Branching,
Children<Vec<Primitive<_Float, D>>, D>: Send,
{
pub fn new(max_depth: u8, init: Vec<Primitive<_Float, D>>) -> Self {
let lipschitz_max = bucket_lipschitz(&init);
Self {
tree: Quadtree::new(max_depth, init),
prune_subdiv: 8,
lipschitz_max,
}
}
pub fn with_prune_subdiv(mut self, subdiv: u32) -> Self {
self.prune_subdiv = subdiv;
self
}
pub fn insert_sdf_domain(
&mut self,
domain: Aabb<_Float, D>,
f: Arc<dyn Fn(Point<_Float, D>) -> _Float + Send + Sync>
) -> bool {
self.insert_primitive_domain(domain, Primitive { f, lipschitz: _Float::one() })
}
pub fn insert_primitive_domain(
&mut self,
domain: Aabb<_Float, D>,
prim: Primitive<_Float, D>
) -> bool {
self.insert_where(move |node| node.rect.intersects(&domain), prim)
}
pub fn insert_at_maximum(
&mut self,
p: DistPoint<_Float, _Float, D>,
prim: Primitive<_Float, D>
) -> bool {
self.insert_within(p.point, p.distance, prim)
}
pub fn insert_within(
&mut self,
center: Point<_Float, D>,
radius: _Float,
prim: Primitive<_Float, D>
) -> bool {
let two = _Float::one() + _Float::one();
self.insert_where(move |node| {
let dist = (center - node.rect.clamp_point(¢er)).length();
let half_diag = node.rect.size().length() / two;
node.data.as_slice().sdf(node.rect.center())
+ bucket_lipschitz(&node.data) * half_diag > dist - radius
}, prim)
}
fn insert_where(
&mut self,
keep: impl Fn(&Node<Vec<Primitive<_Float, D>>, _Float, D>) -> bool + Sync,
prim: Primitive<_Float, D>
) -> bool {
const BUCKET_SIZE: usize = 3;
self.lipschitz_max = self.lipschitz_max.max(prim.lipschitz);
let subdiv = self.prune_subdiv;
let max_depth = self.tree.max_depth;
self.tree.refine_leaves(keep, |node| {
let f = &prim.f;
let l_bucket = bucket_lipschitz(&node.data);
if sdf_geq_everywhere(
f.as_ref(), |p| node.data.as_slice().sdf(p),
node.rect, prim.lipschitz, l_bucket, subdiv
) {
return Refine::None;
}
if sdf_geq_everywhere(
|p| node.data.as_slice().sdf(p), f.as_ref(),
node.rect, l_bucket, prim.lipschitz, subdiv
) {
return Refine::SetData(vec![prim.clone()]);
}
let prune = |data: &[Primitive<_Float, D>], rect| {
let mut g = vec![];
for (i, p_i) in data.iter().enumerate() {
let sdf_old = |p|
data.iter().enumerate()
.filter_map(|(j, p_j)| if i != j { Some((p_j.f)(p)) } else { None })
.fold(_Float::max_value() / (_Float::one() + _Float::one()), |a, b| a.min(b));
let l_old = data.iter().enumerate()
.filter_map(|(j, p_j)| (i != j).then_some(p_j.lipschitz))
.fold(_Float::one(), _Float::max);
if !sdf_geq_everywhere((p_i.f).as_ref(), sdf_old, rect, p_i.lipschitz, l_old, subdiv) {
g.push(p_i.clone())
}
}
g
};
if node.depth == max_depth || node.data.len() < BUCKET_SIZE {
let mut data = node.data.clone();
data.push(prim.clone());
Refine::SetData(data)
} else {
let mut combined = node.data.clone();
combined.push(prim.clone());
Refine::Subdivide(<Dim<D> as Branching>::children_from_fn(
|i| prune(combined.as_slice(), child_rect(node.rect, i))))
}
})
}
pub fn update_domain(&self, p: DistPoint<_Float, _Float, D>) -> Aabb<_Float, D> {
let (x0, d) = (p.point, p.distance);
let two = _Float::one() + _Float::one();
let l = self.lipschitz_max;
let mut bounds: Option<Aabb<_Float, D>> = None;
self.tree.visit_leaves(
|node| {
let half_diag = node.rect.size().length() / two;
let dist = (x0 - node.rect.clamp_point(&x0)).length();
self.sdf(node.rect.center()) + l * half_diag <= dist - d
},
|leaf| {
bounds = Some(match bounds {
Some(b) => b.merge(&leaf.rect),
None => leaf.rect,
});
},
);
bounds.unwrap()
}
#[allow(invalid_reference_casting)]
pub unsafe fn as_mut(&self) -> &mut Self {
&mut *(self as *const Self).cast_mut()
}
}
impl <_Float: Real, const D: usize> SDF<_Float, D> for ADF<_Float, D>
where
Dim<D>: Branching,
{
fn sdf(&self, pixel: Point<_Float, D>) -> _Float {
match self.tree.pt_to_node(pixel) {
Some(node) => node.data.as_slice().sdf(pixel),
None => self.tree.root().data.as_slice().sdf(pixel),
}}}
impl <_Float: Real, const D: usize> crate::geometry::BoundingBox<_Float, D> for ADF<_Float, D> {
fn bounding_box(&self) -> Aabb<_Float, D> {
Aabb::unit()
}}
impl <_Float: Real, const D: usize> Debug for ADF<_Float, D>
where
Dim<D>: Branching,
{
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
use humansize::{FileSize, file_size_opts as options};
let mut max_depth = 0u8;
let mut bucket_slots = 0usize;
self.tree.traverse(&mut |node| {
max_depth = max_depth.max(node.depth);
bucket_slots += node.data.len();
Ok(())
}).ok();
let total_size = std::mem::size_of::<Self>()
+ self.tree.node_count()
* std::mem::size_of::<Node<Vec<Primitive<_Float, D>>, _Float, D>>()
+ bucket_slots * std::mem::size_of::<Primitive<_Float, D>>();
f.debug_struct("ADF")
.field("total_nodes", &self.tree.node_count())
.field("max_depth", &max_depth)
.field("size", &total_size.file_size(options::BINARY).unwrap())
.finish()
}
}