jagua_rs/collision_detection/quadtree/
qt_hazard_vec.rs1use crate::collision_detection::hazards::HazKey;
2use crate::collision_detection::hazards::filter::HazardFilter;
3use crate::collision_detection::quadtree::QTHazPresence;
4use crate::collision_detection::quadtree::QTHazard;
5use std::cmp::Ordering;
6use std::ops::Not;
7
8#[derive(Clone, Debug, Default)]
13pub struct QTHazardVec {
14 hazards: Vec<QTHazard>,
15 n_active_edges: usize,
17}
18
19impl QTHazardVec {
20 pub fn new() -> Self {
21 Self::default()
22 }
23
24 pub fn add(&mut self, haz: QTHazard) {
25 debug_assert!(!matches!(haz.presence, QTHazPresence::None));
26 debug_assert!(
27 self.hazards
28 .iter()
29 .filter(|other| other.entity == haz.entity || other.hkey == haz.hkey)
30 .count()
31 == 0,
32 "More than one hazard from same entity or key in the vector! (This should never happen!)"
33 );
34 match self
35 .hazards
36 .binary_search_by(|probe| order_by_descending_strength(probe, &haz))
37 {
38 Ok(pos) | Err(pos) => {
39 self.n_active_edges += haz.n_edges();
40 self.hazards.insert(pos, haz);
41 }
42 }
43 }
44
45 pub fn remove(&mut self, hkey: HazKey) -> Option<QTHazard> {
46 let pos = self.hazards.iter().position(|ch| ch.hkey == hkey);
47 match pos {
48 Some(pos) => {
49 let haz = self.hazards.remove(pos);
50 self.n_active_edges -= haz.n_edges();
51 Some(haz)
52 }
53 None => None,
54 }
55 }
56
57 #[inline(always)]
58 pub fn strongest(&self, filter: &impl HazardFilter) -> Option<&QTHazard> {
61 debug_assert!(assert_caches_correct(self));
62 self.iter().find(|hz| !filter.is_irrelevant(hz.hkey))
63 }
64
65 pub fn is_empty(&self) -> bool {
66 self.hazards.is_empty()
67 }
68
69 pub fn len(&self) -> usize {
70 self.hazards.len()
71 }
72 pub fn no_partial_hazards(&self) -> bool {
73 self.hazards
74 .iter()
75 .any(|hz| matches!(hz.presence, QTHazPresence::Partial(_)))
76 .not()
77 }
78
79 pub fn iter(&self) -> impl Iterator<Item = &QTHazard> {
80 self.hazards.iter()
81 }
82
83 pub fn n_active_edges(&self) -> usize {
84 debug_assert!(assert_caches_correct(self));
85 self.n_active_edges
86 }
87}
88
89fn order_by_descending_strength(qth1: &QTHazard, qth2: &QTHazard) -> Ordering {
90 let qth_presence_sortkey = |qth: &QTHazard| match qth.presence {
91 QTHazPresence::None => 0,
92 QTHazPresence::Partial(_) => 1,
93 QTHazPresence::Entire => 2,
94 };
95
96 qth_presence_sortkey(qth1)
98 .cmp(&qth_presence_sortkey(qth2))
99 .reverse()
100}
101
102fn assert_caches_correct(qthazard_vec: &QTHazardVec) -> bool {
103 assert!(
104 qthazard_vec
105 .hazards
106 .windows(2)
107 .all(|w| order_by_descending_strength(&w[0], &w[1]) != Ordering::Greater),
108 "Hazards are not sorted correctly!"
109 );
110 assert_eq!(
111 qthazard_vec
112 .hazards
113 .iter()
114 .map(|hz| hz.n_edges())
115 .sum::<usize>(),
116 qthazard_vec.n_active_edges,
117 "Active edges count is not correct!"
118 );
119 true
120}