summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJovansonlee Cesar <ivanceras@gmail.com>2021-07-12 20:37:56 +0800
committerJovansonlee Cesar <ivanceras@gmail.com>2021-07-12 20:37:56 +0800
commit039c74fefaab4c7226de57f258072fb6a5974722 (patch)
tree81c8d55990f7da6ea9c6398f247f767fce119845
parentd379b7fe9ae6fa79d553715329d638301600319f (diff)
Initial migration from ncollide2d to parry2d
-rw-r--r--svgbob/Cargo.toml2
-rw-r--r--svgbob/src/buffer/cell_buffer/cell.rs13
-rw-r--r--svgbob/src/buffer/fragment_buffer/fragment.rs50
-rw-r--r--svgbob/src/buffer/fragment_buffer/fragment/circle.rs58
-rw-r--r--svgbob/src/buffer/fragment_buffer/fragment/line.rs22
-rw-r--r--svgbob/src/buffer/fragment_buffer/fragment/polygon.rs6
-rw-r--r--svgbob/src/buffer/fragment_buffer/fragment/rect.rs20
-rw-r--r--svgbob/src/util.rs8
8 files changed, 109 insertions, 70 deletions
diff --git a/svgbob/Cargo.toml b/svgbob/Cargo.toml
index 794c21b..d4da08e 100644
--- a/svgbob/Cargo.toml
+++ b/svgbob/Cargo.toml
@@ -11,7 +11,7 @@ license = "Apache-2.0"
[dependencies]
nalgebra = "0.28"
-ncollide2d = "0.31"
+ncollide2d = { version = "0.6", package = "parry2d"}
lazy_static = "1.3.0"
sauron = { version = "0.34" }
unicode-width = "0.1.5"
diff --git a/svgbob/src/buffer/cell_buffer/cell.rs b/svgbob/src/buffer/cell_buffer/cell.rs
index 098e6d5..079a7f7 100644
--- a/svgbob/src/buffer/cell_buffer/cell.rs
+++ b/svgbob/src/buffer/cell_buffer/cell.rs
@@ -3,7 +3,7 @@ use ncollide2d::query::PointQuery;
use ncollide2d::{
bounding_volume::AABB,
math::Isometry,
- query::{proximity, Proximity},
+ query::intersection_test,
shape::{Polyline, Segment},
};
use std::{cmp, cmp::Ordering, fmt};
@@ -125,7 +125,7 @@ impl Cell {
/// the bounding box of this cell
#[inline]
- fn bounding_box(&self) -> AABB<f32> {
+ fn bounding_box(&self) -> AABB {
let start = Point::new(
self.x as f32 * Self::width(),
self.y as f32 * Self::height(),
@@ -140,7 +140,7 @@ impl Cell {
/// Convert the bounding box aabb to polyline segment
/// the dots from top-left, top-right, bottom-right, bottom-left then closing to top-left
/// The polyline is then used to testing for intersection with the line segment
- fn polyline(&self) -> Polyline<f32> {
+ fn polyline(&self) -> Polyline {
let aabb = self.bounding_box();
let min = aabb.mins;
let max = aabb.maxs;
@@ -172,14 +172,13 @@ impl Cell {
pub fn is_intersected(&self, start: Point, end: Point) -> bool {
let pl = self.polyline();
let segment = Segment::new(*start, *end);
- let prox = proximity(
+ intersection_test(
&Isometry::identity(),
&pl,
&Isometry::identity(),
&segment,
- 0.0,
- );
- prox == Proximity::Intersecting
+ )
+ .expect("must pass intersection test")
}
/// check if this cell is bounded by the lower bound and upper bound
diff --git a/svgbob/src/buffer/fragment_buffer/fragment.rs b/svgbob/src/buffer/fragment_buffer/fragment.rs
index 95e31e5..ae0b2b4 100644
--- a/svgbob/src/buffer/fragment_buffer/fragment.rs
+++ b/svgbob/src/buffer/fragment_buffer/fragment.rs
@@ -6,10 +6,11 @@ pub use line::Line;
pub use marker_line::{Marker, MarkerLine};
use ncollide2d::bounding_volume::BoundingVolume;
use ncollide2d::query::PointQuery;
+use ncollide2d::shape::ConvexPolygon;
use ncollide2d::{
bounding_volume::AABB,
math::Isometry,
- query::{proximity, Proximity},
+ query::intersection_test,
shape::{Polyline, Segment, Shape},
};
pub use polygon::{Polygon, PolygonTag};
@@ -298,40 +299,42 @@ impl Fragment {
}
/// check if this fragment is intersecting with this bounding box
- pub fn is_intersecting(&self, bbox: &AABB<f32>) -> bool {
- let bbox: Polyline<f32> = Polyline::new(
- vec![
- *Point::new(bbox.mins.x, bbox.mins.y),
- *Point::new(bbox.maxs.x, bbox.mins.y),
- *Point::new(bbox.maxs.x, bbox.maxs.y),
- *Point::new(bbox.mins.x, bbox.maxs.y),
- ],
- None,
- );
+ /// Note: if intersection logic requires testing the solid shape inside the polygon
+ /// use the ConvexPolygon of each shape instead of Polyline
+ pub fn is_intersecting(&self, bbox: &AABB) -> bool {
+ let points = vec![
+ *Point::new(bbox.mins.x, bbox.mins.y),
+ *Point::new(bbox.maxs.x, bbox.mins.y),
+ *Point::new(bbox.maxs.x, bbox.maxs.y),
+ *Point::new(bbox.mins.x, bbox.maxs.y),
+ ];
+ let bbox = Polyline::new(points, None);
let identity = Isometry::identity();
match self {
Fragment::Line(line) => {
- let segment: Segment<f32> = line.clone().into();
- proximity(&identity, &segment, &identity, &bbox, 0.0)
- == Proximity::Intersecting
+ let segment: Segment = line.clone().into();
+ let res =
+ intersection_test(&identity, &segment, &identity, &bbox)
+ .expect("must pass");
+ println!("res: {}", res);
+ res
}
Fragment::Rect(rect) => {
- let polyline: Polyline<f32> = rect.clone().into();
- proximity(&identity, &polyline, &identity, &bbox, 0.0)
- == Proximity::Intersecting
+ let polyline: Polyline = rect.clone().into();
+ intersection_test(&identity, &polyline, &identity, &bbox)
+ .expect("must pass")
}
Fragment::Circle(circle) => {
- // do not include the small circles
- let polyline: Polyline<f32> = circle.clone().into();
- proximity(&identity, &polyline, &identity, &bbox, 0.0)
- == Proximity::Intersecting
+ let polyline: Polyline = circle.clone().into();
+ intersection_test(&identity, &polyline, &identity, &bbox)
+ .expect("must pass")
}
_ => false,
}
}
/// check if this fragment can be contain in the specified bounding box `bbox`
- pub fn is_inside(&self, bbox: &AABB<f32>) -> bool {
+ pub fn is_inside(&self, bbox: &AABB) -> bool {
let (start, end) = self.bounds();
let frag_bound = AABB::new(*start, *end);
bbox.contains(&frag_bound)
@@ -939,6 +942,9 @@ mod tests {
let line1 = line(CellGrid::a(), CellGrid::y());
assert!(line1.hit(CellGrid::g(), CellGrid::s()));
+ let rect_gs = rect(CellGrid::g(), CellGrid::s(), false, false);
+ assert!(!rect_gs.hit(CellGrid::a(), CellGrid::y()));
+
let rect1 = rect(CellGrid::a(), CellGrid::y(), false, false);
assert!(!rect1.hit(CellGrid::g(), CellGrid::s()));
}
diff --git a/svgbob/src/buffer/fragment_buffer/fragment/circle.rs b/svgbob/src/buffer/fragment_buffer/fragment/circle.rs
index f43428a..058b738 100644
--- a/svgbob/src/buffer/fragment_buffer/fragment/circle.rs
+++ b/svgbob/src/buffer/fragment_buffer/fragment/circle.rs
@@ -1,5 +1,6 @@
use crate::{fragment::Bounds, util, Cell, Point};
-use ncollide2d::procedural;
+use nalgebra::Point2;
+use ncollide2d::shape::ConvexPolygon;
use ncollide2d::shape::Polyline;
use std::{cmp::Ordering, fmt};
@@ -30,11 +31,18 @@ impl Circle {
fn top_left_bound(&self) -> Point {
Point::new(self.center.x - self.radius, self.center.y - self.radius)
}
+ fn top_right_bound(&self) -> Point {
+ Point::new(self.center.x + self.radius, self.center.y - self.radius)
+ }
fn bottom_right_bound(&self) -> Point {
Point::new(self.center.x + self.radius, self.center.y + self.radius)
}
+ fn bottom_left_bound(&self) -> Point {
+ Point::new(self.center.x - self.radius, self.center.y + self.radius)
+ }
+
/// offset the circles parameter from the arg cell
pub(in crate) fn absolute_position(&self, cell: Cell) -> Self {
Circle {
@@ -107,19 +115,47 @@ impl PartialEq for Circle {
}
}
-impl Into<Polyline<f32>> for Circle {
- fn into(self) -> Polyline<f32> {
- use nalgebra::Point2;
- let pl = procedural::circle(&(self.radius * 2.0), 64);
- let mut points = pl.coords().to_vec();
- let orig_len = points.len();
- points.dedup();
+impl Into<Polyline> for Circle {
+ fn into(self) -> Polyline {
+ let points: Vec<Point2<f32>> = extract_circle_points(self.radius, 64)
+ .into_iter()
+ .map(|p| Point2::new(p.x + self.center.x, p.y + self.center.y))
+ .collect();
+
+ Polyline::new(points, None)
+ }
+}
- let adjusted: Vec<Point2<f32>> = points
+impl Into<ConvexPolygon> for Circle {
+ fn into(self) -> ConvexPolygon {
+ let points: Vec<Point2<f32>> = extract_circle_points(self.radius, 64)
.into_iter()
- .map(|p| *Point::new(p.x + self.center.x, p.y + self.center.y))
+ .map(|p| Point2::new(p.x + self.center.x, p.y + self.center.y))
.collect();
- Polyline::new(adjusted, None)
+ ConvexPolygon::from_convex_polyline(points)
+ .expect("must create a convex polygon")
+ }
+}
+
+fn extract_circle_points(radius: f32, nsubdivs: u32) -> Vec<Point> {
+ let two_pi = std::f32::consts::TAU;
+ let dtheta = two_pi / nsubdivs as f32;
+ push_xy_arc(radius, nsubdivs, dtheta)
+}
+
+/// Pushes a discretized counterclockwise circle to a buffer.
+/// The circle is contained on the plane spanned by the `x` and `y` axis.
+fn push_xy_arc(radius: f32, nsubdiv: u32, dtheta: f32) -> Vec<Point> {
+ let mut out: Vec<Point> = vec![];
+ let mut curr_theta: f32 = 0.0;
+
+ for _ in 0..nsubdiv {
+ let x = curr_theta.cos() * radius;
+ let y = curr_theta.sin() * radius;
+ out.push(Point::new(x, y));
+
+ curr_theta = curr_theta + dtheta;
}
+ out
}
diff --git a/svgbob/src/buffer/fragment_buffer/fragment/line.rs b/svgbob/src/buffer/fragment_buffer/fragment/line.rs
index 2360bb7..54c135b 100644
--- a/svgbob/src/buffer/fragment_buffer/fragment/line.rs
+++ b/svgbob/src/buffer/fragment_buffer/fragment/line.rs
@@ -4,11 +4,7 @@ use crate::{
util, Direction, Point,
};
use ncollide2d::query::PointQuery;
-use ncollide2d::{
- bounding_volume::AABB,
- query::{proximity, Proximity},
- shape::Polyline,
-};
+use ncollide2d::{bounding_volume::AABB, shape::Polyline};
use ncollide2d::{
math::Isometry,
shape::{Segment, Shape},
@@ -535,8 +531,8 @@ impl<MSG> Into<Node<MSG>> for Line {
}
}
-impl Into<Segment<f32>> for Line {
- fn into(self) -> Segment<f32> {
+impl Into<Segment> for Line {
+ fn into(self) -> Segment {
Segment::new(*self.start, *self.end)
}
}
@@ -638,18 +634,6 @@ mod tests {
assert!(line2.is_touching(&line1));
assert!(util::is_collinear(&line1.start, &line1.end, &line2.start));
assert!(util::is_collinear(&line2.start, &line2.end, &line1.end));
- let area1 = ncollide2d::utils::triangle_area(
- &line1.start,
- &line1.end,
- &line2.start,
- );
- println!("area1: {}", area1);
- let area2 = ncollide2d::utils::triangle_area(
- &line1.start,
- &line1.end,
- &line2.end,
- );
- println!("area2: {}", area2);
assert!(line1.can_merge(&line2));
}
diff --git a/svgbob/src/buffer/fragment_buffer/fragment/polygon.rs b/svgbob/src/buffer/fragment_buffer/fragment/polygon.rs
index f61e53c..d2d0815 100644
--- a/svgbob/src/buffer/fragment_buffer/fragment/polygon.rs
+++ b/svgbob/src/buffer/fragment_buffer/fragment/polygon.rs
@@ -175,7 +175,7 @@ impl Polygon {
impl Bounds for Polygon {
fn bounds(&self) -> (Point, Point) {
- let pl: Polyline<f32> = self.clone().into();
+ let pl: Polyline = self.clone().into();
let aabb = pl.local_aabb();
(Point::from(*aabb.mins), Point::from(*aabb.maxs))
}
@@ -195,8 +195,8 @@ impl fmt::Display for Polygon {
}
}
-impl Into<Polyline<f32>> for Polygon {
- fn into(self) -> Polyline<f32> {
+impl Into<Polyline> for Polygon {
+ fn into(self) -> Polyline {
let points: Vec<Point2<f32>> =
self.points.iter().map(|p| **p).collect();
Polyline::new(points, None)
diff --git a/svgbob/src/buffer/fragment_buffer/fragment/rect.rs b/svgbob/src/buffer/fragment_buffer/fragment/rect.rs
index 27264a8..0978bf4 100644
--- a/svgbob/src/buffer/fragment_buffer/fragment/rect.rs
+++ b/svgbob/src/buffer/fragment_buffer/fragment/rect.rs
@@ -1,6 +1,5 @@
use crate::{fragment::Bounds, util, Cell, Point};
-use std::fmt;
-
+use ncollide2d::shape::ConvexPolygon;
use ncollide2d::shape::{Polyline, Segment, Shape};
use sauron::{
html::attributes::*,
@@ -8,6 +7,7 @@ use sauron::{
Node,
};
use std::cmp::Ordering;
+use std::fmt;
#[derive(Debug, Clone)]
pub struct Rect {
@@ -120,8 +120,8 @@ impl fmt::Display for Rect {
}
}
-impl Into<Polyline<f32>> for Rect {
- fn into(self) -> Polyline<f32> {
+impl Into<Polyline> for Rect {
+ fn into(self) -> Polyline {
Polyline::new(
vec![
*self.start,
@@ -135,6 +135,18 @@ impl Into<Polyline<f32>> for Rect {
}
}
+impl Into<ConvexPolygon> for Rect {
+ fn into(self) -> ConvexPolygon {
+ ConvexPolygon::from_convex_polyline(vec![
+ *self.start,
+ *Point::new(self.end.x, self.start.y),
+ *self.end,
+ *Point::new(self.start.x, self.end.y),
+ ])
+ .expect("must create a convex polygon")
+ }
+}
+
impl<MSG> Into<Node<MSG>> for Rect {
fn into(self) -> Node<MSG> {
rect(
diff --git a/svgbob/src/util.rs b/svgbob/src/util.rs
index 4253c5f..499bf9f 100644
--- a/svgbob/src/util.rs
+++ b/svgbob/src/util.rs
@@ -1,4 +1,5 @@
use crate::Point;
+use ncollide2d::shape::Triangle;
use ncollide2d::{bounding_volume::AABB, math::Isometry, query::PointQuery};
use std::cmp::Ordering;
@@ -27,7 +28,7 @@ pub fn ord(f1: f32, f2: f32) -> Ordering {
/// clips a line to the bounding box of this whole grid
/// and approximate each point to the closes intersection
fn clip_line_internal(
- aabb: &AABB<f32>,
+ aabb: &AABB,
start: Point,
end: Point,
) -> Option<(Point, Point)> {
@@ -45,7 +46,7 @@ fn clip_line_internal(
/// clip a line but do not extend the points
pub fn clip_line(
- aabb: &AABB<f32>,
+ aabb: &AABB,
start: Point,
end: Point,
) -> Option<(Point, Point)> {
@@ -74,7 +75,8 @@ pub fn clip_line(
/// the threshold are of 0.01 is used since
/// lines may not be very aligned.
pub fn is_collinear(a: &Point, b: &Point, c: &Point) -> bool {
- ncollide2d::utils::triangle_area(a, b, c) < 0.01
+ use std::ops::Deref;
+ Triangle::new(*a.deref(), *b.deref(), *c.deref()).area() < 0.01
}
pub fn pad(v: f32) -> f32 {