use crate::{Plane, PlaneCut, Polygon};
use euclid::default::{Point3D, Vector3D};
use smallvec::SmallVec;
use std::fmt;
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct PolygonIdx(usize);
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct NodeIdx(usize);
pub struct BspSplitter<A: Copy> {
result: Vec<Polygon<A>>,
nodes: Vec<BspNode>,
polygons: Vec<Polygon<A>>,
}
impl<A: Copy> BspSplitter<A> {
pub fn new() -> Self {
BspSplitter {
result: Vec::new(),
nodes: vec![BspNode::new()],
polygons: Vec::new(),
}
}
}
impl<A> BspSplitter<A>
where
A: Copy + fmt::Debug + Default,
{
pub fn reset(&mut self) {
self.polygons.clear();
self.nodes.clear();
self.nodes.push(BspNode::new());
}
pub fn add(&mut self, poly: Polygon<A>) {
let root = NodeIdx(0);
self.insert(root, &poly);
}
pub fn sort(&mut self, view: Vector3D<f64>) -> &[Polygon<A>] {
let poly = Polygon {
points: [Point3D::origin(); 4],
plane: Plane {
normal: -view, offset: 0.0,
},
anchor: A::default(),
};
let root = NodeIdx(0);
let mut result = std::mem::take(&mut self.result);
result.clear();
self.order(root, &poly, &mut result);
self.result = result;
&self.result
}
pub fn solve(&mut self, input: &[Polygon<A>], view: Vector3D<f64>) -> &[Polygon<A>]
where
A: Copy,
{
self.reset();
for p in input {
self.add(p.clone());
}
self.sort(view)
}
fn insert(&mut self, node_idx: NodeIdx, value: &Polygon<A>) {
let node = &mut self.nodes[node_idx.0];
if node.values.is_empty() {
node.values.push(add_polygon(&mut self.polygons, value));
return;
}
let mut front: SmallVec<[Polygon<A>; 2]> = SmallVec::new();
let mut back: SmallVec<[Polygon<A>; 2]> = SmallVec::new();
let first = node.values[0].0;
match self.polygons[first].cut(value, &mut front, &mut back) {
PlaneCut::Sibling => {
node.values.push(add_polygon(&mut self.polygons, value));
}
PlaneCut::Cut => {
if front.len() != 0 {
if self.nodes[node_idx.0].front.is_none() {
self.nodes[node_idx.0].front = Some(add_node(&mut self.nodes));
}
let node_front = self.nodes[node_idx.0].front.unwrap();
for p in &front {
self.insert(node_front, p)
}
}
if back.len() != 0 {
if self.nodes[node_idx.0].back.is_none() {
self.nodes[node_idx.0].back = Some(add_node(&mut self.nodes));
}
let node_back = self.nodes[node_idx.0].back.unwrap();
for p in &back {
self.insert(node_back, p)
}
}
}
}
}
pub fn order(&self, node: NodeIdx, base: &Polygon<A>, out: &mut Vec<Polygon<A>>) {
let node = &self.nodes[node.0];
let (former, latter) = match node.values.first() {
None => return,
Some(first) => {
if base.is_aligned(&self.polygons[first.0]) {
(node.front, node.back)
} else {
(node.back, node.front)
}
}
};
if let Some(node) = former {
self.order(node, base, out);
}
out.reserve(node.values.len());
for poly_idx in &node.values {
out.push(self.polygons[poly_idx.0].clone());
}
if let Some(node) = latter {
self.order(node, base, out);
}
}
}
pub fn add_polygon<A: Copy>(polygons: &mut Vec<Polygon<A>>, poly: &Polygon<A>) -> PolygonIdx {
let index = PolygonIdx(polygons.len());
polygons.push(poly.clone());
index
}
pub fn add_node(nodes: &mut Vec<BspNode>) -> NodeIdx {
let index = NodeIdx(nodes.len());
nodes.push(BspNode::new());
index
}
#[derive(Clone, Debug)]
pub struct BspNode {
values: SmallVec<[PolygonIdx; 4]>,
front: Option<NodeIdx>,
back: Option<NodeIdx>,
}
impl BspNode {
pub fn new() -> Self {
BspNode {
values: SmallVec::new(),
front: None,
back: None,
}
}
}