#![allow(private_interfaces)]
use std::ops::Index;
use super::{quad_tree::NodeID, tree_impl::Node};
use crate::collision::{CollisionQuery, Relation};
use bevy_ecs::entity::EntityHashSet;
pub(crate) struct QueryTree {
pub(crate) nodes: *const Node,
pub(crate) max_length: usize,
}
impl Index<usize> for QueryTree {
type Output = Node;
fn index(&self, index: usize) -> &Self::Output {
unsafe { &*self.nodes.add(index) }
}
}
pub struct QOr<T>(core::marker::PhantomData<T>);
pub struct QNot<T>(core::marker::PhantomData<T>);
#[allow(missing_docs)]
pub trait QRelation {
fn filter(qt: &QueryTree, boundary: &dyn CollisionQuery) -> EntityHashSet;
fn all(qt: &QueryTree, id: NodeID) -> EntityHashSet {
let mut res = EntityHashSet::default();
let mut x = vec![id];
while let Some(id) = x.pop() {
res.extend(qt[id].entities.read().keys().cloned());
if !qt[id].is_leaf() && (id << 2) + 4 < qt.max_length {
for i in (id << 2) + 1..=(id << 2) + 4 {
x.push(i);
}
}
}
res
}
}
pub struct Disjoint;
pub struct Overlap;
pub struct Contain;
pub struct Contained;
pub struct All;
impl QRelation for All {
fn filter(qt: &QueryTree, _: &dyn CollisionQuery) -> EntityHashSet {
Self::all(qt, 0)
}
}
impl QRelation for Disjoint {
fn filter(qt: &QueryTree, boundary: &dyn CollisionQuery) -> EntityHashSet {
let mut res = EntityHashSet::default();
let mut x = vec![0];
while let Some(id) = x.pop() {
match boundary.query(&qt[id].outlet_boundary) {
Relation::Disjoint => res.extend(All::all(qt, id)),
Relation::Overlap | Relation::Contained => {
for (entity, shape) in qt[id].entities.read().iter() {
if boundary.query(shape.as_ref()) == Relation::Disjoint {
res.insert(*entity);
}
}
if !qt[id].is_leaf() && (id << 2) + 4 < qt.max_length {
for i in (id << 2) + 1..=(id << 2) + 4 {
x.push(i);
}
}
}
Relation::Contain => {}
}
}
res
}
}
impl QRelation for Overlap {
fn filter(qt: &QueryTree, boundary: &dyn CollisionQuery) -> EntityHashSet {
let mut res = EntityHashSet::default();
let mut x = vec![0];
while let Some(id) = x.pop() {
match boundary.query(&qt[id].outlet_boundary) {
Relation::Disjoint | Relation::Contain => {}
Relation::Overlap | Relation::Contained => {
for (entity, shape) in qt[id].entities.read().iter() {
if boundary.query(shape.as_ref()) == Relation::Overlap {
res.insert(*entity);
}
}
if !qt[id].is_leaf() && (id << 2) + 4 < qt.max_length {
for i in (id << 2) + 1..=(id << 2) + 4 {
x.push(i);
}
}
}
}
}
res
}
}
impl QRelation for Contain {
fn filter(qt: &QueryTree, boundary: &dyn CollisionQuery) -> EntityHashSet {
let mut res = EntityHashSet::default();
let mut x = vec![0];
while let Some(id) = x.pop() {
match boundary.query(&qt[id].outlet_boundary) {
Relation::Disjoint => {}
Relation::Contain => res.extend(All::all(qt, id)),
Relation::Overlap | Relation::Contained => {
for (entity, shape) in qt[id].entities.read().iter() {
if boundary.query(shape.as_ref()) == Relation::Contain {
res.insert(*entity);
}
}
if !qt[id].is_leaf() && (id << 2) + 4 < qt.max_length {
for i in (id << 2) + 1..=(id << 2) + 4 {
x.push(i);
}
}
}
}
}
res
}
}
impl QRelation for Contained {
fn filter(qt: &QueryTree, boundary: &dyn CollisionQuery) -> EntityHashSet {
let mut res = EntityHashSet::default();
let mut x = vec![0];
while let Some(id) = x.pop() {
match boundary.query(&qt[id].outlet_boundary) {
Relation::Disjoint | Relation::Contain | Relation::Overlap => {}
Relation::Contained => {
for (entity, shape) in qt[id].entities.read().iter() {
if boundary.query(shape.as_ref()) == Relation::Contained {
res.insert(*entity);
}
}
if !qt[id].is_leaf() && (id << 2) + 4 < qt.max_length {
for i in (id << 2) + 1..=(id << 2) + 4 {
x.push(i);
}
}
}
}
}
res
}
}
macro_rules! impl_or_relation {
($($t: ident),+) => {
impl<$($t),+> QRelation for QOr<($($t),+,)>
where $($t: QRelation),+
{
fn filter(
qt: &QueryTree,
boundary: &dyn CollisionQuery,
) -> EntityHashSet {
let mut res = EntityHashSet::default();
$(res.extend($t::filter(qt, boundary));)+
res
}
}
};
}
impl_or_relation!(R0);
impl_or_relation!(R0, R1);
impl_or_relation!(R0, R1, R2);
impl_or_relation!(R0, R1, R2, R3);
macro_rules! impl_not_relation {
($($r: ident), +) => {
$(
impl QRelation for QNot<$r> {
fn filter(
qt: &QueryTree,
boundary: &dyn CollisionQuery,
) -> EntityHashSet {
let tmp = $r::filter(qt, boundary);
let mut res = All::all(qt, 0);
for entity in tmp.iter() {
res.remove(entity);
}
res
}
}
)+
};
}
impl_not_relation!(Contain, Contained, Overlap, Disjoint);