Skip to main content

box2d_rs/
b2_dynamic_tree.rs

1use crate::b2_collision::*;
2use crate::b2_growable_stack::B2growableStack;
3use crate::b2_math::*;
4use crate::b2_common::*;
5use crate::private::collision::b2_dynamic_tree as private;
6
7pub const B2_NULL_NODE: i32 = -1;
8
9/// A node in the dynamic tree. The client does not interact with this directly.
10#[derive(Default, Clone, Debug)]
11pub struct B2treeNode<UserDataType> {
12	/// Enlarged AABB
13	pub(crate) aabb: B2AABB,
14
15	pub(crate) user_data: Option<UserDataType>,
16
17	//box2d-rs: parent=next for free nodes
18	//union
19	//{
20	//	 parent:i32,
21	//	 next:i32,
22	//},
23	pub(crate) parent: i32,
24
25	pub(crate) child1: i32,
26	pub(crate) child2: i32,
27
28	// leaf = 0, free node = -1
29	pub(crate) height: i32,
30
31	pub(crate) moved: bool,
32}
33
34impl<UserDataType> B2treeNode<UserDataType> {
35	pub fn is_leaf(&self) -> bool {
36		return self.child1 == B2_NULL_NODE;
37	}
38}
39
40/// A dynamic AABB tree broad-phase, inspired by Nathanael Presson's btDbvt.
41/// A dynamic tree arranges data in a binary tree to accelerate
42/// queries such as volume queries and ray casts. Leafs are proxies
43/// with an AABB. In the tree we expand the proxy AABB by b2_fatAABBFactor
44/// so that the proxy AABB is bigger than the client object. This allows the client
45/// object to move by small amounts without triggering a tree update.
46///
47/// Nodes are pooled and relocatable, so we use node indices rather than pointers.
48#[derive(Default, Clone, Debug)]
49pub struct B2dynamicTree<UserDataType> {
50	pub(crate) m_root: i32,
51
52	pub(crate) m_nodes: Vec<B2treeNode<UserDataType>>,
53	pub(crate) m_node_count: i32,
54	pub(crate) m_node_capacity: i32,
55
56	pub(crate) m_free_list: i32,
57
58	pub(crate) m_insertion_count: i32,
59}
60
61impl<UserDataType: Clone + Default> B2dynamicTree<UserDataType> {
62	/// Constructing the tree initializes the node pool.
63	pub fn new() -> Self {
64		return private::b2_dynamic_tree();
65	}
66
67	/// destroy the tree, freeing the node pool.
68	//~B2dynamicTree();
69
70	/// create a proxy. Provide a tight fitting AABB and a user_data pointer.
71	pub fn create_proxy(&mut self, aabb: B2AABB, user_data: &UserDataType) -> i32 {
72		return private::create_proxy(self, aabb, user_data);
73	}
74
75	/// destroy a proxy. This asserts if the id is invalid.
76	pub fn destroy_proxy(&mut self, proxy_id: i32) {
77		private::destroy_proxy(self, proxy_id);
78	}
79
80	/// Move a proxy with a swepted AABB. If the proxy has moved outside of its fattened AABB,
81	/// then the proxy is removed from the tree and re-inserted. Otherwise
82	/// the function returns immediately.
83	/// 
84	/// @return true if the proxy was re-inserted.
85	pub fn move_proxy(&mut self, proxy_id: i32, aabb1: B2AABB, displacement: B2vec2) -> bool {
86		return private::move_proxy(self, proxy_id, aabb1, displacement);
87	}
88
89	/// Get proxy user data.
90	/// 
91	/// @return the proxy user data or 0 if the id is invalid.
92	pub fn get_user_data(&self, proxy_id: i32) -> Option<UserDataType> {
93		return inline::get_user_data(self, proxy_id);
94	}
95
96	pub fn was_moved(&self, proxy_id: i32) -> bool {
97		return inline::was_moved(self, proxy_id);
98	}
99	pub fn clear_moved(&mut self, proxy_id: i32) {
100		inline::clear_moved(self, proxy_id);
101	}
102
103	/// Get the fat AABB for a proxy.
104	pub fn get_fat_aabb(&self, proxy_id: i32) -> B2AABB {
105		return inline::get_fat_aabb(self, proxy_id);
106	}
107
108	/// query an AABB for overlapping proxies. The callback class
109	/// is called for each proxy that overlaps the supplied AABB.
110	pub fn query<F:  QueryCallback>(&self, callback: F, aabb: B2AABB) {
111		inline::query(self, callback, aabb);
112	}
113
114	/// Ray-cast against the proxies in the tree. This relies on the callback
115	/// to perform a exact ray-cast in the case were the proxy contains a shape.
116	/// The callback also performs the any collision filtering. This has performance
117	/// roughly equal to k * log(n), where k is the number of collisions and n is the
118	/// number of proxies in the tree.
119	/// * `input` - the ray-cast input data. The ray extends from p1 to p1 + max_fraction * (p2 - p1).
120	/// * `callback` - a callback class that is called for each proxy that is hit by the ray.
121	pub fn ray_cast<T: RayCastCallback>(&self, callback: T, input: &B2rayCastInput) {
122		inline::ray_cast(self, callback, input);
123	}
124
125	/// Validate this tree. For testing.
126	pub fn validate(&self) {
127		private::validate(self);
128	}
129
130	/// Compute the height of the binary tree in O(n) time. Should not be
131	/// called often.
132	pub fn get_height(&self) -> i32 {
133		return private::get_height(self);
134	}
135
136	/// Get the maximum balance of an node in the tree. The balance is the difference
137	/// in height of the two children of a node.
138	pub fn get_max_balance(&self) -> i32 {
139		return private::get_max_balance(self);
140	}
141
142	/// Get the ratio of the sum of the node areas to the root area.
143	pub fn get_area_ration(&self) -> f32 {
144		return private::get_area_ratio(self);
145	}
146
147	/// Build an optimal tree. Very expensive. For testing.
148	pub fn rebuild_bottom_up(&mut self) {
149		private::rebuild_bottom_up(self);
150	}
151
152	/// Shift the world origin. Useful for large worlds.
153	/// The shift formula is: position -= new_origin
154	/// * `new_origin` - the new origin with respect to the old origin
155	pub fn shift_origin(&mut self, new_origin: B2vec2) {
156		private::shift_origin(self, new_origin);
157	}
158
159	pub(crate) fn allocate_node(&mut self) -> i32 {
160		return private::allocate_node(self);
161	}
162	pub(crate) fn free_node(&mut self, node: i32) {
163		private::free_node(self, node);
164	}
165
166	pub(crate) fn insert_leaf(&mut self, node: i32) {
167		private::insert_leaf(self, node);
168	}
169	pub(crate) fn remove_leaf(&mut self, node: i32) {
170		private::remove_leaf(self, node);
171	}
172
173	pub(crate) fn balance(&mut self, index: i32) -> i32 {
174		return private::balance(self, index);
175	}
176
177	pub(crate) fn compute_height(&self) -> i32 {
178		return private::compute_height(self);
179	}
180	pub(crate) fn compute_height_by_node(&self, node_id: i32) -> i32 {
181		return private::compute_height_by_node(self, node_id);
182	}
183
184	pub(crate) fn validate_structure(&self, index: i32) {
185		private::validate_structure(self, index);
186	}
187	pub(crate) fn validate_metrics(&self, index: i32) {
188		private::validate_metrics(self, index);
189	}
190}
191
192// pub trait QueryCallback {
193// 	fn query_callback(&mut self, proxy_id: i32) -> bool;
194// }
195pub trait QueryCallback: FnMut(i32) -> bool {}
196impl <F> QueryCallback for F where F: FnMut(i32) -> bool {}
197
198// pub trait RayCastCallback {
199// 	fn ray_cast_callback(&mut self, input: &B2rayCastInput, proxy_id: i32) -> f32;
200// }
201pub trait RayCastCallback: FnMut(&B2rayCastInput, i32) -> f32 {}
202impl <F> RayCastCallback for F where F: FnMut(&B2rayCastInput, i32) -> f32 {}
203
204mod inline {
205	use super::*;
206
207	pub fn get_user_data<UserDataType: Clone + Default>(
208		self_: &B2dynamicTree<UserDataType>,
209		proxy_id: i32,
210	) -> Option<UserDataType> {
211		//b2_assert(0 <= proxy_id && proxy_id < self_.m_nodeCapacity);
212		return self_.m_nodes[proxy_id as usize].user_data.clone();
213	}
214
215	pub fn was_moved<UserDataType: Clone + Default>(
216		self_: &B2dynamicTree<UserDataType>,
217		proxy_id: i32,
218	) -> bool {
219		//b2_assert(0 <= proxy_id && proxy_id < self_.m_nodeCapacity);
220		return self_.m_nodes[proxy_id as usize].moved;
221	}
222
223	pub fn clear_moved<UserDataType: Clone + Default>(
224		self_: &mut B2dynamicTree<UserDataType>,
225		proxy_id: i32,
226	) {
227		//b2_assert(0 <= proxy_id && proxy_id < self_.m_nodeCapacity);
228		self_.m_nodes[proxy_id as usize].moved = false;
229	}
230
231	pub fn get_fat_aabb<UserDataType: Clone + Default>(
232		self_: &B2dynamicTree<UserDataType>,
233		proxy_id: i32,
234	) -> B2AABB {
235		//b2_assert(0 <= proxy_id && proxy_id < self_.m_nodeCapacity);
236		return self_.m_nodes[proxy_id as usize].aabb;
237	}
238
239	pub fn query<UserDataType, F:  QueryCallback>(
240		self_: &B2dynamicTree<UserDataType>,
241		mut callback: F,
242		aabb: B2AABB,
243	) {
244		let mut stack = B2growableStack::<i32, 256>::new();
245		stack.push(&self_.m_root);
246
247		while stack.get_count() > 0 {
248			let node_id: i32 = stack.pop();
249			if node_id == B2_NULL_NODE {
250				continue;
251			}
252
253			let node = &self_.m_nodes[node_id as usize];
254
255			if b2_test_overlap(node.aabb, aabb) {
256				if node.is_leaf() {
257					let proceed: bool = callback(node_id);
258					if proceed == false {
259						return;
260					}
261				} else {
262					stack.push(&node.child1);
263					stack.push(&node.child2);
264				}
265			}
266		}
267	}
268
269	pub fn ray_cast<T: RayCastCallback, UserDataType>(
270		self_: &B2dynamicTree<UserDataType>,
271		mut callback: T,
272		input: &B2rayCastInput,
273	) {
274		let p1: B2vec2 = input.p1;
275		let p2: B2vec2 = input.p2;
276		let mut r: B2vec2 = p2 - p1;
277		b2_assert(r.length_squared() > 0.0);
278		r.normalize();
279
280		// v is perpendicular to the segment.
281		let v: B2vec2 = b2_cross_scalar_by_vec(1.0, r);
282		let abs_v: B2vec2 = b2_abs_vec2(v);
283
284		// Separating axis for segment (Gino, p80).
285		// |dot(v, p1 - c)| > dot(|v|, h)
286
287		let mut max_fraction: f32 = input.max_fraction;
288
289		// Build a bounding box for the segment.
290		let mut segment_aabb = B2AABB::default();
291		{
292			let t: B2vec2 = p1 + max_fraction * (p2 - p1);
293			segment_aabb.lower_bound = b2_min_vec2(p1, t);
294			segment_aabb.upper_bound = b2_max_vec2(p1, t);
295		}
296
297		let mut stack = B2growableStack::<i32, 256>::new();
298		stack.push(&self_.m_root);
299
300		while stack.get_count() > 0 {
301			let node_id: i32 = stack.pop();
302			if node_id == B2_NULL_NODE {
303				continue;
304			}
305
306			let node = &self_.m_nodes[node_id as usize];
307
308			if b2_test_overlap(node.aabb, segment_aabb) == false {
309				continue;
310			}
311
312			// Separating axis for segment (Gino, p80).
313			// |dot(v, p1 - c)| > dot(|v|, h)
314			let c: B2vec2 = node.aabb.get_center();
315			let h: B2vec2 = node.aabb.get_extents();
316			let separation: f32 = b2_abs(b2_dot(v, p1 - c)) - b2_dot(abs_v, h);
317			if separation > 0.0 {
318				continue;
319			}
320
321			if node.is_leaf() {
322				let sub_input = B2rayCastInput {
323					p1: input.p1,
324					p2: input.p2,
325					max_fraction: max_fraction,
326				};
327
328				let value: f32 = callback(&sub_input, node_id);
329
330				if value == 0.0 {
331					// The client has terminated the ray cast.
332					return;
333				}
334
335				if value > 0.0 {
336					// update segment bounding box.
337					max_fraction = value;
338					let t: B2vec2 = p1 + max_fraction * (p2 - p1);
339					segment_aabb.lower_bound = b2_min_vec2(p1, t);
340					segment_aabb.upper_bound = b2_max_vec2(p1, t);
341				}
342			} else {
343				stack.push(&node.child1);
344				stack.push(&node.child2);
345			}
346		}
347	}
348}