Skip to content

Commit

Permalink
Merge pull request #6 from JeroenGar/feature/quadrant_corner_order
Browse files Browse the repository at this point in the history
Feature/quadrant corner order
  • Loading branch information
JeroenGar authored Dec 6, 2024
2 parents 849856d + d2aa096 commit 9dad9e1
Show file tree
Hide file tree
Showing 3 changed files with 87 additions and 68 deletions.
89 changes: 36 additions & 53 deletions jagua-rs/src/geometry/primitives/aa_rectangle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,45 +34,6 @@ impl AARectangle {
}
}

/// Returns the top-edge along y_max
pub fn top_edge(&self) -> Edge {
Edge::new(Point(self.x_max, self.y_max), Point(self.x_min, self.y_max))
}

/// Returns the bottom-edge along y_min
pub fn bottom_edge(&self) -> Edge {
Edge::new(Point(self.x_min, self.y_min), Point(self.x_max, self.y_min))
}

/// Returns the left-edge along x_min
pub fn left_edge(&self) -> Edge {
Edge::new(Point(self.x_min, self.y_max), Point(self.x_min, self.y_min))
}

/// Returns the right-edge along x_max
pub fn right_edge(&self) -> Edge {
Edge::new(Point(self.x_max, self.y_min), Point(self.x_max, self.y_max))
}

pub fn edges(&self) -> [Edge; 4] {
[
self.top_edge(),
self.bottom_edge(),
self.left_edge(),
self.right_edge(),
]
}

/// Returns the four corners in the following order: NW,NE,SW,SE
pub fn corners(&self) -> [Point; 4] {
[
Point(self.x_min, self.y_min),
Point(self.x_max, self.y_min),
Point(self.x_min, self.y_max),
Point(self.x_max, self.y_max),
]
}

/// Returns the relation between self and another AARectangle
pub fn relation_to(&self, other: &AARectangle) -> GeoRelation {
if self.collides_with(other) {
Expand Down Expand Up @@ -150,20 +111,43 @@ impl AARectangle {
self
}

/// For all quadrants, contains indices of the two neighbors of the quadrant at that index
pub const QUADRANT_NEIGHBOR_LAYOUT: [[usize; 2]; 4] = [[1, 2], [0, 3], [0, 3], [1, 2]];
/// For all quadrants, contains indices of the two neighbors of the quadrant at that index.
pub const QUADRANT_NEIGHBOR_LAYOUT: [[usize; 2]; 4] = [[1, 3], [0, 2], [1, 3], [0, 2]];

/// Returns the 4 quadrants of the rectangle, in the order NW, NE, SW, SE
/// Returns the 4 quadrants of the rectangle.
/// Ordered in the same way as quadrants in a cartesian plane:
/// <https://en.wikipedia.org/wiki/Quadrant_(plane_geometry)>
pub fn quadrants(&self) -> [Self; 4] {
let Point(x_mid, y_mid) = self.centroid();
let (x_min, y_min, x_max, y_max) = (self.x_min, self.y_min, self.x_max, self.y_max);
let mid = self.centroid();
let corners = self.corners();

let q1 = Edge::new(corners[0], mid).bbox();
let q2 = Edge::new(corners[1], mid).bbox();
let q3 = Edge::new(corners[2], mid).bbox();
let q4 = Edge::new(corners[3], mid).bbox();

let rect_nw = AARectangle::new(x_min, y_mid, x_mid, y_max);
let rect_ne = AARectangle::new(x_mid, y_mid, x_max, y_max);
let rect_sw = AARectangle::new(x_min, y_min, x_mid, y_mid);
let rect_se = AARectangle::new(x_mid, y_min, x_max, y_mid);
[q1, q2, q3, q4]
}

/// Returns the four corners, in the same order as [AARectangle::quadrants].
pub fn corners(&self) -> [Point; 4] {
[
Point(self.x_max, self.y_max),
Point(self.x_min, self.y_max),
Point(self.x_min, self.y_min),
Point(self.x_max, self.y_min),
]
}

[rect_nw, rect_ne, rect_sw, rect_se]
/// Returns the four edges of the rectangle, in the same order as [AARectangle::quadrants].
pub fn edges(&self) -> [Edge; 4] {
let c = self.corners();
[
Edge::new(c[0], c[1]),
Edge::new(c[1], c[2]),
Edge::new(c[2], c[3]),
Edge::new(c[3], c[0]),
]
}

pub fn width(&self) -> fsize {
Expand Down Expand Up @@ -293,10 +277,9 @@ impl CollidesWith<Edge> for AARectangle {
}

//The only possible that remains is that the edge collides with one of the edges of the AARectangle
edge.collides_with(&self.top_edge())
|| edge.collides_with(&self.bottom_edge())
|| edge.collides_with(&self.right_edge())
|| edge.collides_with(&self.left_edge())
self.edges()
.iter()
.any(|rect_edge| edge.collides_with(rect_edge))
}
}

Expand Down
27 changes: 27 additions & 0 deletions jagua-rs/src/geometry/primitives/circle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,33 @@ impl DistanceFrom<Circle> for Circle {
}
}

impl DistanceFrom<Edge> for Circle {
fn sq_distance(&self, e: &Edge) -> fsize {
self.distance(e).powi(2)
}

fn distance(&self, e: &Edge) -> fsize {
match self.distance_from_border(e) {
(GeoPosition::Interior, _) => 0.0,
(GeoPosition::Exterior, d) => d,
}
}

fn distance_from_border(&self, e: &Edge) -> (GeoPosition, fsize) {
let distance_to_center = e.distance(&self.center);
if distance_to_center < self.radius {
(GeoPosition::Interior, self.radius - distance_to_center)
} else {
(GeoPosition::Exterior, distance_to_center - self.radius)
}
}

fn sq_distance_from_border(&self, e: &Edge) -> (GeoPosition, fsize) {
let (pos, distance) = self.distance_from_border(e);
(pos, distance.powi(2))
}
}

impl Shape for Circle {
fn centroid(&self) -> Point {
self.center
Expand Down
39 changes: 24 additions & 15 deletions jagua-rs/src/util/assertions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -437,21 +437,30 @@ pub fn hpg_update_no_affected_cells_remain(
}
}

/// Checks if the quadrants follow the layout set in [AARectangle::QUADRANT_NEIGHBOR_LAYOUT]
pub fn quadrants_have_valid_layout(quadrants: &[&AARectangle; 4]) -> bool {
//check top border
let [nw, ne, sw, se] = quadrants;

//check exterior borders
assert_eq!(nw.y_max, ne.y_max, "Top border does not match");
assert_eq!(sw.y_min, se.y_min, "Bottom border does not match");
assert_eq!(nw.x_min, sw.x_min, "Left border does not match");
assert_eq!(ne.x_max, se.x_max, "Right border does not match");

//check interior borders
assert_eq!(nw.x_max, ne.x_min, "Top interior border does not match");
assert_eq!(sw.x_max, se.x_min, "Bottom interior border does not match");
assert_eq!(nw.y_min, sw.y_max, "Left interior border does not match");
assert_eq!(ne.y_min, se.y_max, "Right interior border does not match");

let layout = AARectangle::QUADRANT_NEIGHBOR_LAYOUT;
for (idx, q) in quadrants.iter().enumerate() {
//make sure they share two points (an edge) with each neighbor
let [n_0, n_1] = layout[idx];
let q_corners = q.corners();
let n_0_corners = quadrants[n_0].corners();
let n_1_corners = quadrants[n_1].corners();

assert_eq!(
2,
n_0_corners
.iter()
.filter(|c| q_corners.iter().find(|qc| qc == c).is_some())
.count()
);
assert_eq!(
2,
n_1_corners
.iter()
.filter(|c| q_corners.iter().find(|qc| qc == c).is_some())
.count()
);
}
true
}

0 comments on commit 9dad9e1

Please sign in to comment.