Skip to content

Commit

Permalink
Debug layer and serialization
Browse files Browse the repository at this point in the history
  • Loading branch information
kvark committed Oct 6, 2020
1 parent 13b9fcf commit fa4a63e
Show file tree
Hide file tree
Showing 11 changed files with 439 additions and 266 deletions.
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@ rust:
script:
- cargo build
- cargo doc
- cargo test
- cargo test --all-features
- if [ "$TRAVIS_RUST_VERSION" == "nightly" ]; then (cargo bench); fi
7 changes: 6 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,15 +1,20 @@
[package]
name = "plane-split"
version = "0.17.0"
version = "0.17.1"
description = "Plane splitting"
authors = ["Dzmitry Malyshau <kvark@mozilla.com>"]
license = "MPL-2.0"
repository = "https://github.com/servo/plane-split"
keywords = ["geometry", "math"]
documentation = "https://docs.rs/plane-split"

[features]
default = ["debug"]
debug = ["serde", "euclid/serde"]

[dependencies]
binary-space-partition = "0.1.2"
euclid = "0.22"
log = "0.4"
num-traits = {version = "0.2", default-features = false}
serde = { version = "1.0", features = ["serde_derive"], optional = true }
4 changes: 2 additions & 2 deletions benches/split.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ extern crate euclid;
extern crate plane_split;
extern crate test;

use std::sync::Arc;
use euclid::vec3;
use plane_split::{BspSplitter, Splitter, make_grid};
use plane_split::{make_grid, BspSplitter, Splitter};
use std::sync::Arc;

#[bench]
fn bench_bsp(b: &mut test::Bencher) {
Expand Down
46 changes: 27 additions & 19 deletions src/bsp.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,24 @@
use {Intersection, Plane, Polygon, Splitter};
use is_zero;
use {Intersection, Plane, Polygon, Splitter};

use binary_space_partition::{BspNode, Plane as BspPlane, PlaneCut};
use euclid::{Point3D, Vector3D};
use euclid::approxeq::ApproxEq;
use euclid::{Point3D, Vector3D};
use num_traits::{Float, One, Zero};

use std::{fmt, iter, ops};


impl<T, U, A> BspPlane for Polygon<T, U, A> where
T: Copy + fmt::Debug + ApproxEq<T> +
ops::Sub<T, Output=T> + ops::Add<T, Output=T> +
ops::Mul<T, Output=T> + ops::Div<T, Output=T> +
Zero + Float,
impl<T, U, A> BspPlane for Polygon<T, U, A>
where
T: Copy
+ fmt::Debug
+ ApproxEq<T>
+ ops::Sub<T, Output = T>
+ ops::Add<T, Output = T>
+ ops::Mul<T, Output = T>
+ ops::Div<T, Output = T>
+ Zero
+ Float,
U: fmt::Debug,
A: Copy + fmt::Debug,
{
Expand Down Expand Up @@ -83,11 +88,8 @@ impl<T, U, A> BspPlane for Polygon<T, U, A> where
}
}

PlaneCut::Cut {
front,
back,
}
},
PlaneCut::Cut { front, back }
}
}
}

Expand All @@ -96,7 +98,6 @@ impl<T, U, A> BspPlane for Polygon<T, U, A> where
}
}


/// Binary Space Partitioning splitter, uses a BSP tree.
pub struct BspSplitter<T, U, A> {
tree: BspNode<Polygon<T, U, A>>,
Expand All @@ -113,11 +114,18 @@ impl<T, U, A> BspSplitter<T, U, A> {
}
}

impl<T, U, A> Splitter<T, U, A> for BspSplitter<T, U, A> where
T: Copy + fmt::Debug + ApproxEq<T> +
ops::Sub<T, Output=T> + ops::Add<T, Output=T> +
ops::Mul<T, Output=T> + ops::Div<T, Output=T> +
Zero + One + Float,
impl<T, U, A> Splitter<T, U, A> for BspSplitter<T, U, A>
where
T: Copy
+ fmt::Debug
+ ApproxEq<T>
+ ops::Sub<T, Output = T>
+ ops::Add<T, Output = T>
+ ops::Mul<T, Output = T>
+ ops::Div<T, Output = T>
+ Zero
+ One
+ Float,
U: fmt::Debug,
A: Copy + fmt::Debug + Default,
{
Expand Down
75 changes: 36 additions & 39 deletions src/clip.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
use {Intersection, NegativeHemisphereError, Plane, Polygon};

use euclid::{Trig, Rect, Scale, Transform3D, Vector3D};
use euclid::approxeq::ApproxEq;
use euclid::{Rect, Scale, Transform3D, Trig, Vector3D};
use num_traits::{Float, One, Zero};

use std::{fmt, iter, mem, ops};


/// A helper object to clip polygons by a number of planes.
#[derive(Debug)]
pub struct Clipper<T, U, A> {
Expand All @@ -16,13 +15,20 @@ pub struct Clipper<T, U, A> {
}

impl<
T: Copy + fmt::Debug + ApproxEq<T> +
ops::Sub<T, Output=T> + ops::Add<T, Output=T> +
ops::Mul<T, Output=T> + ops::Div<T, Output=T> +
Zero + One + Float,
U: fmt::Debug,
A: Copy + fmt::Debug,
> Clipper<T, U, A> {
T: Copy
+ fmt::Debug
+ ApproxEq<T>
+ ops::Sub<T, Output = T>
+ ops::Add<T, Output = T>
+ ops::Mul<T, Output = T>
+ ops::Div<T, Output = T>
+ Zero
+ One
+ Float,
U: fmt::Debug,
A: Copy + fmt::Debug,
> Clipper<T, U, A>
{
/// Create a new clipper object.
pub fn new() -> Self {
Clipper {
Expand All @@ -49,33 +55,26 @@ impl<
Some(bounds) => {
let mx = Vector3D::new(t.m11, t.m21, t.m31);
let left = bounds.origin.x;
let plane_left = Plane::from_unnormalized(
mx - mw * Scale::new(left),
t.m41 - t.m44 * left,
)?;
let plane_left =
Plane::from_unnormalized(mx - mw * Scale::new(left), t.m41 - t.m44 * left)?;
let right = bounds.origin.x + bounds.size.width;
let plane_right = Plane::from_unnormalized(
mw * Scale::new(right) - mx,
t.m44 * right - t.m41,
)?;
let plane_right =
Plane::from_unnormalized(mw * Scale::new(right) - mx, t.m44 * right - t.m41)?;

let my = Vector3D::new(t.m12, t.m22, t.m32);
let top = bounds.origin.y;
let plane_top = Plane::from_unnormalized(
my - mw * Scale::new(top),
t.m42 - t.m44 * top,
)?;
let plane_top =
Plane::from_unnormalized(my - mw * Scale::new(top), t.m42 - t.m44 * top)?;
let bottom = bounds.origin.y + bounds.size.height;
let plane_bottom = Plane::from_unnormalized(
mw * Scale::new(bottom) - my,
t.m44 * bottom - t.m42,
)?;

Some(plane_left
.into_iter()
.chain(plane_right)
.chain(plane_top)
.chain(plane_bottom)
let plane_bottom =
Plane::from_unnormalized(mw * Scale::new(bottom) - my, t.m44 * bottom - t.m42)?;

Some(
plane_left
.into_iter()
.chain(plane_right)
.chain(plane_top)
.chain(plane_bottom),
)
}
None => None,
Expand All @@ -84,8 +83,7 @@ impl<
Ok(bounds_iter_maybe
.into_iter()
.flat_map(|pi| pi)
.chain(plane_positive)
)
.chain(plane_positive))
}

/// Add a clipping plane to the list. The plane will clip everything behind it,
Expand All @@ -112,17 +110,15 @@ impl<
iter::once(poly)
.chain(res1)
.chain(res2)
.filter(|p| clip.signed_distance_sum_to(p) > T::zero())
.filter(|p| clip.signed_distance_sum_to(p) > T::zero()),
);
continue
continue;
}
Intersection::Coplanar => {
let ndot = poly.plane.normal.dot(clip.normal);
clip.offset - ndot * poly.plane.offset
}
Intersection::Outside => {
clip.signed_distance_sum_to(&poly)
}
Intersection::Outside => clip.signed_distance_sum_to(&poly),
};

if dist > T::zero() {
Expand Down Expand Up @@ -157,7 +153,8 @@ impl<
self.clips.pop();
}

let polys = self.results
let polys = self
.results
.drain(..)
.flat_map(move |poly| poly.transform(transform));
Ok(polys)
Expand Down
74 changes: 74 additions & 0 deletions src/debug.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
use crate::{Polygon, Splitter};
use serde::{Serialize, Serializer};

/// Serialized work for a plane splitter.
pub struct Dump<T, U, A> {
/// input polygons
pub input: Vec<Polygon<T, U, A>>,
/// view used to sort
pub view: euclid::Vector3D<T, U>,
/// split polygons
pub output: Vec<Polygon<T, U, A>>,
}

impl<T: Serialize, U, A: Serialize> Serialize for Dump<T, U, A> {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
use serde::ser::SerializeStruct;
let mut me = serializer.serialize_struct("Dump", 3)?;
me.serialize_field("input", &self.input)?;
me.serialize_field("view", &self.view)?;
me.serialize_field("output", &self.output)?;
me.end()
}
}

/// Debug layer that records the interface into a dump.
pub struct DebugLayer<T, U, A, Z> {
/// Actual plane splitting implementation.
inner: Z,
/// Dump of the work.
dump: Dump<T, U, A>,
}

impl<T: Default, U, A, Z> DebugLayer<T, U, A, Z> {
/// Create a new debug layer.
pub fn new(inner: Z) -> Self {
DebugLayer {
inner,
dump: Dump {
input: Vec::new(),
view: Default::default(),
output: Vec::new(),
},
}
}

/// Get the current work dump.
pub fn dump(&self) -> &Dump<T, U, A> {
&self.dump
}
}

impl<T: Clone, U, A: Copy, Z: Splitter<T, U, A>> Splitter<T, U, A> for DebugLayer<T, U, A, Z> {
fn reset(&mut self) {
self.dump.input.clear();
self.inner.reset();
}

/// Add a new polygon and return a slice of the subdivisions
/// that avoid collision with any of the previously added polygons.
fn add(&mut self, polygon: Polygon<T, U, A>) {
self.dump.input.push(polygon.clone());
self.inner.add(polygon);
}

/// Sort the produced polygon set by the ascending distance across
/// the specified view vector. Return the sorted slice.
fn sort(&mut self, view: euclid::Vector3D<T, U>) -> &[Polygon<T, U, A>] {
self.dump.view = view.clone();
let sorted = self.inner.sort(view);
self.dump.output.clear();
self.dump.output.extend_from_slice(sorted);
sorted
}
}

0 comments on commit fa4a63e

Please sign in to comment.