use nalgebra::*;
use num_traits::cast::AsPrimitive;
use parry2d::bounding_volume::*;
use parry2d::math::Real;
use pi_link_list::{Iter, LinkList, Node};
use pi_null::*;
use pi_slotmap::*;
type List<K, T> = LinkList<K, T, SecondaryMap<K, Node<K, T>>>;
pub struct MapInfo {
pub bounds: Aabb,
pub width: usize,
pub height: usize,
pub amount: usize,
size: Vector2<Real>,
}
impl MapInfo {
pub fn calc_tile_index(&self, loc: Point2<Real>) -> (usize, usize) {
let x = if loc[0] <= self.bounds.mins[0] {
0
} else if loc[0] >= self.bounds.maxs[0] {
self.width - 1
} else {
((loc[0] - self.bounds.mins[0]) * self.width as Real / self.size[0]).as_()
};
let y = if loc[1] <= self.bounds.mins[1] {
0
} else if loc[1] >= self.bounds.maxs[1] {
self.height - 1
} else {
((loc[1] - self.bounds.mins[1]) * self.height as Real / self.size[1]).as_()
};
(x, y)
}
pub fn tile_index(&self, x: usize, y: usize) -> usize {
y * self.width + x
}
pub fn tile_xy(&self, tile_index: usize) -> (usize, usize) {
(tile_index % self.width, tile_index / self.width)
}
}
pub struct TileMap<K: Key, T> {
ab_map: SecondaryMap<K, Node<K, (Aabb, T)>>,
tiles: Vec<List<K, (Aabb, T)>>,
pub info: MapInfo,
pub node_max_half_size: Vector2<Real>,
}
impl<K: Key, T> TileMap<K, T> {
pub fn new(bounds: Aabb, width: usize, height: usize) -> Self {
let amount = width * height;
let mut tiles = Vec::with_capacity(amount);
tiles.resize_with(amount, Default::default);
let size = bounds.extents();
let info = MapInfo {
bounds,
height,
width,
amount,
size,
};
TileMap {
ab_map: Default::default(),
tiles,
info,
node_max_half_size: Vector2::zeros(),
}
}
pub fn get_node_max_half_size(&self) -> &Vector2<Real> {
&self.node_max_half_size
}
pub fn set_node_max_half_size(&mut self, half_size: Vector2<Real>) {
self.node_max_half_size = half_size;
}
fn update_node_max_half_size(&mut self, aabb: Aabb) {
let size = aabb.half_extents();
if size.x > self.node_max_half_size.x {
self.node_max_half_size.x = size.x;
}
if size.y > self.node_max_half_size.y {
self.node_max_half_size.y = size.y;
}
}
pub fn get_tile_index(&self, loc: Point2<Real>) -> usize {
let (x, y) = self.info.calc_tile_index(loc);
self.info.tile_index(x, y)
}
pub fn get_tile_iter<'a>(
&'a self,
tile_index: usize,
) -> (
usize,
Iter<'a, K, (Aabb, T), SecondaryMap<K, Node<K, (Aabb, T)>>>,
) {
let list = &self.tiles[tile_index];
(list.len(), list.iter(&self.ab_map))
}
pub fn query_iter(&self, aabb: &Aabb) -> (usize, QueryIter) {
let (x_start, y_start) = self
.info
.calc_tile_index(aabb.mins - self.node_max_half_size);
let (x_end, y_end) = self
.info
.calc_tile_index(aabb.maxs + self.node_max_half_size);
(
(x_end - x_start + 1) * (y_end - y_start + 1),
QueryIter {
width: self.info.width,
x_start,
x_end,
y_start,
y_end,
cur_x: x_start,
},
)
}
pub fn query<A>(
&self,
aabb: &Aabb,
arg: &mut A,
ab_func: fn(arg: &mut A, id: K, aabb: &Aabb, bind: &T),
) {
let (_, tile_it) = self.query_iter(aabb);
for tile_index in tile_it {
let (_, it) = self.get_tile_iter(tile_index);
for (id, node) in it {
ab_func(arg, id, &node.0, &node.1);
}
}
}
pub fn add(&mut self, id: K, aabb: Aabb, bind: T) -> bool {
let center = aabb.center();
let tile_index = self.get_tile_index(center);
match self.ab_map.insert(id, Node::new((aabb, bind))) {
Some(_) => return false,
None => (),
}
self.update_node_max_half_size(aabb);
self.tiles[tile_index].link_before(id, K::null(), &mut self.ab_map);
true
}
pub fn iter(&self) -> pi_slotmap::secondary::Iter<K, Node<K, (Aabb, T)>> {
self.ab_map.iter()
}
pub fn get(&self, id: K) -> Option<&(Aabb, T)> {
match self.ab_map.get(id) {
Some(node) => Some(&node),
None => None,
}
}
pub unsafe fn get_unchecked(&self, id: K) -> &(Aabb, T) {
&self.ab_map.get_unchecked(id)
}
pub unsafe fn get_mut(&mut self, id: K) -> Option<&mut T> {
match self.ab_map.get_mut(id) {
Some(n) => Some(&mut n.1),
None => None,
}
}
pub unsafe fn get_unchecked_mut(&mut self, id: K) -> &mut T {
&mut self.ab_map.get_unchecked_mut(id).1
}
pub fn contains_key(&self, id: K) -> bool {
self.ab_map.contains_key(id)
}
pub fn update(&mut self, id: K, aabb: Aabb) -> bool {
let node = match self.ab_map.get_mut(id) {
Some(n) => n,
_ => return false,
};
let (new_x, new_y) = self.info.calc_tile_index(aabb.center());
let (x, y) = self.info.calc_tile_index(node.0.center());
node.0 = aabb;
self.move_from_to(id, x, y, new_x, new_y);
self.update_node_max_half_size(aabb);
true
}
pub fn shift(&mut self, id: K, distance: Vector2<Real>) -> bool {
let node = match self.ab_map.get_mut(id) {
Some(n) => n,
_ => return false,
};
let aabb = Aabb::new(node.0.mins + distance, node.0.maxs + distance);
let (new_x, new_y) = self.info.calc_tile_index(aabb.center());
let (x, y) = self.info.calc_tile_index(node.0.center());
node.0 = aabb;
self.move_from_to(id, x, y, new_x, new_y);
true
}
pub fn move_to(&mut self, id: K, loc: Point2<Real>) -> bool {
let node = match self.ab_map.get_mut(id) {
Some(n) => n,
_ => return false,
};
let (new_x, new_y) = self.info.calc_tile_index(loc);
let center = node.0.center();
let (x, y) = self.info.calc_tile_index(center);
let d = loc - center;
node.0 = Aabb::new(node.0.mins + d, node.0.maxs + d);
self.move_from_to(id, x, y, new_x, new_y);
true
}
fn move_from_to(&mut self, id: K, x: usize, y: usize, new_x: usize, new_y: usize) {
if x == new_x && y == new_y {
return;
}
let new_tile_index = self.info.tile_index(new_x, new_y);
let tile_index = self.info.tile_index(x, y);
self.tiles[tile_index].unlink(id, &mut self.ab_map);
self.tiles[new_tile_index].link_before(id, K::null(), &mut self.ab_map);
}
pub fn update_bind(&mut self, id: K, bind: T) -> bool {
match self.ab_map.get_mut(id) {
Some(node) => {
node.1 = bind;
true
}
_ => false,
}
}
pub fn remove(&mut self, id: K) -> Option<(Aabb, T)> {
let node = match self.ab_map.get(id) {
Some(n) => n,
_ => return None,
};
let tile_index = self.get_tile_index(node.0.center());
self.tiles[tile_index].unlink(id, &mut self.ab_map);
self.ab_map.remove(id).map(|n| n.take())
}
pub fn get_tile_index_by_id(&self, id: K) -> usize {
let node = match self.ab_map.get(id) {
Some(n) => n,
_ => return Null::null(),
};
let (x, y) = self.info.calc_tile_index(node.0.center());
self.info.tile_index(x, y)
}
pub fn len(&self) -> usize {
self.ab_map.len()
}
}
#[derive(Debug, Clone, Default)]
pub struct QueryIter {
width: usize,
x_start: usize,
x_end: usize,
y_start: usize,
y_end: usize,
cur_x: usize,
}
impl Iterator for QueryIter {
type Item = usize;
fn next(&mut self) -> Option<Self::Item> {
if self.y_start > self.y_end {
return None;
}
let index = self.y_start * self.width + self.cur_x;
if self.cur_x < self.x_end {
self.cur_x += 1;
} else {
self.cur_x = self.x_start;
self.y_start += 1;
}
Some(index)
}
}
#[test]
fn test1() {
use pi_slotmap::{DefaultKey, SlotMap};
println!("test1-----------------------------------------");
let mut tree = TileMap::new(
Aabb::new(
Point2::new(-1024f32, -1024f32),
Point2::new(3072f32, 3072f32),
),
10,
10,
);
let mut slot_map = SlotMap::new();
let mut keys = Vec::new();
keys.push(DefaultKey::null());
for i in 0..1 {
keys.push(slot_map.insert(()));
tree.add(
keys.last().unwrap().clone(),
Aabb::new(Point2::new(0.0, 0.0), Point2::new(1.0, 1.0)),
i + 1,
);
}
for i in 1..tree.ab_map.len() + 1 {
println!(
"10000, id:{}, ab: {:?}, index: {:?}",
i,
tree.ab_map.get(keys[i]).unwrap(),
tree.get_tile_index_by_id(keys[i])
);
}
tree.update(
keys[1],
Aabb::new(Point2::new(0.0, 0.0), Point2::new(1000.0, 700.0)),
);
for i in 1..tree.ab_map.len() + 1 {
println!(
"20000, id:{}, ab: {:?}, index: {:?}",
i,
tree.ab_map.get(keys[i]).unwrap(),
tree.get_tile_index_by_id(keys[i])
);
}
for i in 1..tree.ab_map.len() + 1 {
println!(
"30000, id:{}, ab: {:?}, index: {:?}",
i,
tree.ab_map.get(keys[i]).unwrap(),
tree.get_tile_index_by_id(keys[i])
);
}
for i in 1..6 {
keys.push(slot_map.insert(()));
tree.add(
keys.last().unwrap().clone(),
Aabb::new(Point2::new(0.0, 0.0), Point2::new(1.0, 1.0)),
i + 3,
);
}
for i in 1..tree.ab_map.len() + 1 {
let index = tree.get_tile_index_by_id(keys[i]);
let (len, mut iter) = tree.get_tile_iter(index);
println!(
"00001, id:{}, ab: {:?}, index: {:?}, iter:{:?}",
i,
tree.ab_map.get(keys[i]).unwrap(),
index,
(len, iter.next())
);
}
tree.update(
keys[2],
Aabb::new(Point2::new(0.0, 0.0), Point2::new(1000.0, 700.0)),
);
tree.update(
keys[3],
Aabb::new(Point2::new(0.0, 0.0), Point2::new(1000.0, 700.0)),
);
tree.update(
keys[4],
Aabb::new(Point2::new(0.0, 700.0), Point2::new(1000.0, 1400.0)),
);
tree.update(
keys[5],
Aabb::new(Point2::new(0.0, 1400.0), Point2::new(1000.0, 1470.0)),
);
tree.update(
keys[6],
Aabb::new(Point2::new(0.0, 1470.0), Point2::new(1000.0, 1540.0)),
);
tree.update(
keys[1],
Aabb::new(Point2::new(0.0, 0.0), Point2::new(1000.0, 700.0)),
);
for i in 1..tree.ab_map.len() + 1 {
println!(
"00002, id:{}, ab: {:?}, index: {:?}",
i,
tree.ab_map.get(keys[i]).unwrap(),
tree.get_tile_index_by_id(keys[i])
);
}
let aabb = Aabb::new(Point2::new(500f32, 500f32), Point2::new(1100f32, 1100f32));
let (len, iter) = tree.query_iter(&aabb);
println!("query_iter count:{},", len);
for i in iter {
println!(
"id:{}, xy: {:?}",
i,
tree.info.tile_xy(i),
);
}
}