Skip to content

Commit

Permalink
hazard module cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
JeroenGar committed Feb 2, 2024
1 parent 8e86863 commit 90ca9fa
Show file tree
Hide file tree
Showing 31 changed files with 309 additions and 317 deletions.
8 changes: 4 additions & 4 deletions assets/config_lbf.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"cde_config": {
"quadtree": {
"FixedDepth": 4
"FixedDepth": 8
},
"haz_prox": {
"Enabled": {
Expand All @@ -21,10 +21,10 @@
}
},
"deterministic_mode": true,
"n_samples_per_item": 5000,
"ls_samples_fraction": 0.2,
"n_samples_per_item": 50000,
"ls_samples_fraction": 0.5,
"svg_draw_options": {
"quadtree": false,
"quadtree": true,
"haz_prox_grid": false,
"surrogate": false
}
Expand Down
46 changes: 23 additions & 23 deletions jaguars/src/collision_detection/cd_engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ use tribool::Tribool;

use crate::collision_detection::cde_snapshot::CDESnapshot;
use crate::collision_detection::haz_prox_grid::hazard_proximity_grid::{HazardProximityGrid, PendingChangesErr};
use crate::collision_detection::hazards::hazard::Hazard;
use crate::collision_detection::hazards::hazard_entity::HazardEntity;
use crate::collision_detection::hazard::Hazard;
use crate::collision_detection::hazard::HazardEntity;
use crate::collision_detection::quadtree::qt_node::QTNode;
use crate::geometry::fail_fast::sp_surrogate::SPSurrogate;
use crate::geometry::geo_enums::{GeoPosition, GeoRelation};
Expand Down Expand Up @@ -64,13 +64,13 @@ impl CDEngine {
//UPDATE ---------------------------------------------------------------------------------------

pub fn register_hazard(&mut self, hazard: Hazard) {
debug_assert!(self.dynamic_hazards.iter().find(|h| h.entity() == hazard.entity()).is_none(), "Hazard already registered");
let hazard_in_uncommitted_deregs = self.uncommited_deregisters.iter().position(|h| h.entity() == hazard.entity());
debug_assert!(self.dynamic_hazards.iter().find(|h| h.entity == hazard.entity).is_none(), "Hazard already registered");
let hazard_in_uncommitted_deregs = self.uncommited_deregisters.iter().position(|h| h.entity == hazard.entity);

let hazard = match hazard_in_uncommitted_deregs {
Some(index) => {
let unc_hazard = self.uncommited_deregisters.swap_remove(index);
self.quadtree.activate_hazard(unc_hazard.entity());
self.quadtree.activate_hazard(&unc_hazard.entity);
unc_hazard
}
None => {
Expand All @@ -85,7 +85,7 @@ impl CDEngine {
}

pub fn deregister_hazard(&mut self, hazard_entity: &HazardEntity, commit_instantly: bool) {
let haz_index = self.dynamic_hazards.iter().position(|h| h.entity() == hazard_entity).expect("Hazard not found");
let haz_index = self.dynamic_hazards.iter().position(|h| &h.entity == hazard_entity).expect("Hazard not found");

let hazard = self.dynamic_hazards.swap_remove(haz_index);

Expand All @@ -112,34 +112,34 @@ impl CDEngine {

pub fn restore(&mut self, snapshot: &CDESnapshot) {
//Quadtree
let mut hazards_to_remove = self.dynamic_hazards.iter().map(|h| h.entity().clone()).collect::<IndexSet<HazardEntity>>();
let mut hazards_to_remove = self.dynamic_hazards.iter().map(|h| h.entity.clone()).collect::<IndexSet<HazardEntity>>();
debug_assert!(hazards_to_remove.len() == self.dynamic_hazards.len());
let mut hazards_to_add = vec![];

for hazard in snapshot.dynamic_hazards().iter() {
let hazard_already_present = hazards_to_remove.swap_remove(hazard.entity());
let hazard_already_present = hazards_to_remove.swap_remove(&hazard.entity);
if !hazard_already_present {
hazards_to_add.push(hazard.clone());
}
}

//Hazards currently registered in the CDE, but not in the snapshot
for hazard in hazards_to_remove.iter() {
let haz_index = self.dynamic_hazards.iter().position(|h| h.entity() == hazard).expect("Hazard not found");
for haz_entity in hazards_to_remove.iter() {
let haz_index = self.dynamic_hazards.iter().position(|h| &h.entity == haz_entity).expect("Hazard not found");
self.dynamic_hazards.swap_remove(haz_index);
self.quadtree.deregister_hazard(&hazard);
self.quadtree.deregister_hazard(&haz_entity);
}

//Some of the uncommitted deregisters might be in present in snapshot, if so we can just reactivate them
for unc_haz in self.uncommited_deregisters.drain(..) {
if let Some(pos) = hazards_to_add.iter().position(|h| h.entity() == unc_haz.entity()) {
if let Some(pos) = hazards_to_add.iter().position(|h| &h.entity == &unc_haz.entity) {
//the uncommitted removed hazard needs to be activated again
self.quadtree.activate_hazard(unc_haz.entity());
self.quadtree.activate_hazard(&unc_haz.entity);
self.dynamic_hazards.push(unc_haz);
hazards_to_add.swap_remove(pos);
} else {
//uncommitted deregister is not preset in the snapshot, delete it from the quadtree
self.quadtree.deregister_hazard(unc_haz.entity());
self.quadtree.deregister_hazard(&unc_haz.entity);
}
}

Expand All @@ -158,7 +158,7 @@ impl CDEngine {

fn commit_deregisters(&mut self) {
for uc_haz in self.uncommited_deregisters.drain(..) {
self.quadtree.deregister_hazard(uc_haz.entity());
self.quadtree.deregister_hazard(&uc_haz.entity);
}
self.haz_prox_grid.as_mut().map(|hpg| hpg.flush_deregisters(self.dynamic_hazards.iter()));
}
Expand Down Expand Up @@ -286,9 +286,9 @@ impl CDEngine {

if !circle_center_in_qt && colliding_entities.is_empty() {
// The circle center is outside the quadtree
if !ignored_entities.contains(&&HazardEntity::BinOuter) {
if !ignored_entities.contains(&&HazardEntity::BinExterior) {
//Add the bin as a hazard, unless it is ignored
colliding_entities.push(HazardEntity::BinOuter);
colliding_entities.push(HazardEntity::BinExterior);
}
}

Expand All @@ -297,23 +297,23 @@ impl CDEngine {

fn collision_by_containment(&self, shape: &SimplePolygon, ignored_entities: &[HazardEntity]) -> bool
{
//collect all active and non-ignored hazards
//collect all active and non-ignored hazard_filters
let mut relevant_hazards = self.all_hazards()
.filter(|h| h.is_active() && !ignored_entities.contains(h.entity()));
.filter(|h| h.active && !ignored_entities.contains(&h.entity));

relevant_hazards.any(|haz| {
//Due to possible fp issues, we check if the bboxes are "almost" related
//"almost" meaning that, when edges are very close together, they are considered equal.
//Some relations which would normally be seen as Intersecting are now being considered Enclosed/Surrounding
let haz_shape = haz.shape().as_ref();
let haz_shape = haz.shape.as_ref();
let bbox_relation = haz_shape.bbox().almost_relation_to(&shape.bbox());

let (s_mu, s_omega) = match bbox_relation {
GeoRelation::Surrounding => (shape, haz_shape), //inclusion possible
GeoRelation::Enclosed => (haz_shape, shape), //inclusion possible
GeoRelation::Disjoint | GeoRelation::Intersecting => {
//no inclusion is possible
return match haz.entity().presence() {
return match haz.entity.presence() {
GeoPosition::Interior => false,
GeoPosition::Exterior => true,
}
Expand All @@ -323,14 +323,14 @@ impl CDEngine {
if std::ptr::eq(haz_shape, s_omega) {
//s_omega is registered in the quadtree.
//maybe the quadtree can help us.
match self.quadtree.point_definitely_collides_with(&s_mu.poi().center(), haz.entity()).try_into() {
match self.quadtree.point_definitely_collides_with(&s_mu.poi().center(), &haz.entity).try_into() {
Ok(collides) => return collides,
Err(_) => (), //no definitive answer
}
}
let inclusion = s_omega.collides_with(&s_mu.poi().center());

match haz.entity().presence() {
match haz.entity.presence() {
GeoPosition::Interior => inclusion,
GeoPosition::Exterior => !inclusion,
}
Expand Down
2 changes: 1 addition & 1 deletion jaguars/src/collision_detection/cde_snapshot.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::collision_detection::haz_prox_grid::grid::Grid;
use crate::collision_detection::haz_prox_grid::hpg_cell::HPGCell;
use crate::collision_detection::hazards::hazard::Hazard;
use crate::collision_detection::hazard::Hazard;

//Snapshot of the CDE state at a given time.
//Can be used to restore the CDE to a previous state.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::cmp::Ordering;

use crate::collision_detection::hazards::hazard::Hazard;
use crate::collision_detection::hazard::Hazard;
use crate::geometry::geo_traits::{DistanceFrom, Shape};
use crate::geometry::primitives::aa_rectangle::AARectangle;
use crate::geometry::primitives::point::Point;
Expand Down Expand Up @@ -72,8 +72,8 @@ pub fn generate(bbox: AARectangle, hazards: &[Hazard], target_n_cells: usize) ->

fn distance_to_hazard<'a, I>(point: &Point, hazards: I) -> f64 where I: Iterator<Item=&'a Hazard> {
hazards.map(|haz| {
let (pos, prox) = haz.shape().distance_from_border(point);
match pos == haz.entity().presence() {
let (pos, prox) = haz.shape.distance_from_border(point);
match pos == haz.entity.presence() {
true => -prox, //cell in hazard, negative distance
false => prox
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ use itertools::Itertools;
use crate::collision_detection::haz_prox_grid::boundary_fill::BoundaryFillGrid;
use crate::collision_detection::haz_prox_grid::grid::Grid;
use crate::collision_detection::haz_prox_grid::grid_generator;
use crate::collision_detection::haz_prox_grid::hpg_cell::{HPCellUpdate, HPGCell};
use crate::collision_detection::hazards::hazard::Hazard;
use crate::collision_detection::hazards::hazard_entity::HazardEntity;
use crate::collision_detection::haz_prox_grid::hpg_cell::{HPGCellUpdate, HPGCell};
use crate::collision_detection::hazard::Hazard;
use crate::collision_detection::hazard::HazardEntity;
use crate::geometry::geo_traits::Shape;
use crate::geometry::primitives::aa_rectangle::AARectangle;

Expand Down Expand Up @@ -53,7 +53,7 @@ impl HazardProximityGrid {

pub fn register_hazard(&mut self, to_register: &Hazard) {
let seed_bbox = {
let shape_bbox = to_register.shape().bbox();
let shape_bbox = to_register.shape.bbox();
AARectangle::new(
shape_bbox.x_min() - self.cell_radius,
shape_bbox.y_min() - self.cell_radius,
Expand All @@ -68,13 +68,13 @@ impl HazardProximityGrid {
let cell = self.grid.elements_mut()[next_dot_index].as_mut();
if let Some(cell) = cell {
match cell.register_hazard(to_register) {
HPCellUpdate::Affected => {
HPGCellUpdate::Affected => {
b_fill.queue_neighbors(next_dot_index, &self.grid);
}
HPCellUpdate::Unaffected => {
HPGCellUpdate::Unaffected => {
b_fill.queue_neighbors(next_dot_index, &self.grid);
}
HPCellUpdate::Boundary => ()
HPGCellUpdate::Boundary => ()
}
}
}
Expand All @@ -87,7 +87,7 @@ impl HazardProximityGrid {
let undetected = self.grid.elements_mut().iter_mut().enumerate()
.flat_map(|(i, cell)| cell.as_mut().map(|cell| (i, cell)))
.map(|(i, cell)| (i, cell.register_hazard(to_register)))
.filter(|(_i, res)| res == &HPCellUpdate::Affected)
.filter(|(_i, res)| res == &HPGCellUpdate::Affected)
.map(|(i, _res)| i)
.collect_vec();

Expand Down Expand Up @@ -115,9 +115,9 @@ impl HazardProximityGrid {
for cell in self.grid.elements_mut().iter_mut().flatten() {
let result = cell.deregister_hazards(iter::once(to_deregister), remaining.clone());
match result {
HPCellUpdate::Affected => (),
HPCellUpdate::Unaffected => (),
HPCellUpdate::Boundary => unreachable!()
HPGCellUpdate::Affected => (),
HPGCellUpdate::Unaffected => (),
HPGCellUpdate::Boundary => unreachable!()
}
}
}
Expand Down
58 changes: 31 additions & 27 deletions jaguars/src/collision_detection/haz_prox_grid/hpg_cell.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ use std::cmp::Ordering;
use itertools::Itertools;

use crate::collision_detection::haz_prox_grid::proximity::Proximity;
use crate::collision_detection::hazards::hazard::Hazard;
use crate::collision_detection::hazards::hazard_entity::HazardEntity;
use crate::collision_detection::hazard::Hazard;
use crate::collision_detection::hazard::HazardEntity;
use crate::entities::item::Item;
use crate::geometry::geo_enums::GeoPosition;
use crate::geometry::geo_traits::{DistanceFrom, Shape};
Expand All @@ -18,11 +18,12 @@ pub struct HPGCell {
bbox: AARectangle,
centroid: Point,
radius: f64,
///Proximity of closest hazard which is universally applicable (bin or item)
uni_haz_prox: (Proximity, HazardEntity),
//proximity of closest hazard which is universally applicable (bin or item)
///Proximity of universal static hazard_filters
static_uni_haz_prox: (Proximity, HazardEntity),
//proximity of universal static hazards
qz_haz_prox: [Proximity; N_QUALITIES], //proximity of closest quality zone for each quality
///proximity of closest quality zone for each quality
qz_haz_prox: [Proximity; N_QUALITIES],
}

impl HPGCell {
Expand All @@ -32,19 +33,19 @@ impl HPGCell {
let centroid = bbox.centroid();
let radius = f64::sqrt(f64::powi(bbox.width() / 2.0, 2) + f64::powi(bbox.height() / 2.0, 2));

let mut static_uni_haz_prox = (Proximity::default(), HazardEntity::BinOuter);
let mut static_uni_haz_prox = (Proximity::default(), HazardEntity::BinExterior);
let mut qz_haz_prox = [Proximity::default(); N_QUALITIES];

for hazard in static_hazards {
let (pos, distance) = hazard.shape().distance_from_border(&centroid);
let prox = match pos == hazard.entity().presence() {
let (pos, distance) = hazard.shape.distance_from_border(&centroid);
let prox = match pos == hazard.entity.presence() {
true => Proximity::new(GeoPosition::Interior, distance), //cell in hazard, negative distance
false => Proximity::new(GeoPosition::Exterior, distance)
};
match hazard.entity() {
HazardEntity::BinOuter | HazardEntity::BinHole { .. } => {
match &hazard.entity {
HazardEntity::BinExterior | HazardEntity::BinHole { .. } => {
if prox < static_uni_haz_prox.0 {
static_uni_haz_prox = (prox, hazard.entity().clone());
static_uni_haz_prox = (prox, hazard.entity.clone());
}
}
HazardEntity::QualityZoneInferior { quality, .. } => {
Expand All @@ -71,12 +72,12 @@ impl HPGCell {
//negative distance if inside of circle.
//This serves as an lowerbound for the distance to the item itself.
let mut bounding_pole_distances: Vec<(&Hazard, Option<Proximity>)> = to_register
.filter(|haz| haz.is_active())
.filter(|haz| haz.active)
.map(|haz| {
match haz.entity().presence() {
match haz.entity.presence() {
GeoPosition::Exterior => (haz, None), //bounding poles only applicable for hazard inside the shape
GeoPosition::Interior => {
let pole_bounding_circle = haz.shape().surrogate().poles_bounding_circle();
let pole_bounding_circle = haz.shape.surrogate().poles_bounding_circle();
let proximity = pole_bounding_circle.distance_from_border(&self.centroid);
let proximity = Proximity::new(proximity.0, proximity.1.abs());
(haz, Some(proximity))
Expand Down Expand Up @@ -111,42 +112,42 @@ impl HPGCell {
}
}

pub fn register_hazard(&mut self, to_register: &Hazard) -> HPCellUpdate {
pub fn register_hazard(&mut self, to_register: &Hazard) -> HPGCellUpdate {
let current_prox = self.universal_hazard_proximity().0;

//For dynamic hazards, the surrogate poles are used to calculate the distance to the hazard (overestimation, but fast)
let haz_prox = match to_register.entity().presence() {
GeoPosition::Interior => distance_to_surrogate_poles_border(self, to_register.shape().surrogate().poles()),
//For dynamic hazard_filters, the surrogate poles are used to calculate the distance to the hazard (overestimation, but fast)
let haz_prox = match to_register.entity.presence() {
GeoPosition::Interior => distance_to_surrogate_poles_border(self, to_register.shape.surrogate().poles()),
GeoPosition::Exterior => unreachable!("No implementation yet for dynamic exterior hazards")
};

match haz_prox.cmp(&current_prox) {
Ordering::Less => {
//new hazard is closer
self.uni_haz_prox = (haz_prox, to_register.entity().clone());
HPCellUpdate::Affected
self.uni_haz_prox = (haz_prox, to_register.entity.clone());
HPGCellUpdate::Affected
}
_ => {
if haz_prox.distance_from_border > current_prox.distance_from_border + 2.0 * self.radius {
HPCellUpdate::Boundary
HPGCellUpdate::Boundary
} else {
HPCellUpdate::Unaffected
HPGCellUpdate::Unaffected
}
}
}
}

pub fn deregister_hazards<'a, 'b, I, J>(&mut self, mut to_deregister: J, remaining: I) -> HPCellUpdate
pub fn deregister_hazards<'a, 'b, I, J>(&mut self, mut to_deregister: J, remaining: I) -> HPGCellUpdate
where I: Iterator<Item=&'a Hazard>, J: Iterator<Item=&'b HazardEntity>
{
if to_deregister.contains(&self.uni_haz_prox.1) {
//closest current hazard has to be deregistered
self.uni_haz_prox = self.static_uni_haz_prox.clone();

self.register_hazards(remaining);
HPCellUpdate::Affected
HPGCellUpdate::Affected
} else {
HPCellUpdate::Unaffected
HPGCellUpdate::Unaffected
}
}

Expand Down Expand Up @@ -206,8 +207,11 @@ pub fn distance_to_surrogate_poles_border(hp_cell: &HPGCell, poles: &[Circle]) -
}

#[derive(Debug, Clone, Copy, PartialEq)]
pub enum HPCellUpdate {
pub enum HPGCellUpdate {
///Update affected the cell
Affected,
///Update did not affect the cell, but its neighbors can be affected
Unaffected,
Boundary, //Unaffected and its neighbors are also guaranteed to be unaffected
///Update did not affect the cell and its neighbors are also guaranteed to be unaffected
Boundary,
}
Loading

0 comments on commit 90ca9fa

Please sign in to comment.