四分木空間分割とは

# 前書き

こちらのサイト（[その８ 4分木空間分割を最適化する！（理屈編）](http://marupeke296.com/COL_2D_No8_QuadTree.html)）を
読んで、曖昧ながらも理解できたのでその備忘録

リンク先のサイトで完結しているので頭のいい人は以下の文章は見なくていいです。

# 四分木空間分割

図1
<img width="600" alt="1.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/649673/c63239e8-d45a-ffb3-b4d1-9858932eaab3.png">
オブジェクトA～Gのすべての衝突判定を行うとして
考えなしに行う場合、
AとB～G、BとC～G、CとD～G、…
と衝突判定をすると思うが、左上にあるAと右下にあるGは明らかに衝突し得ないため、そもそも判定を行わないようにしたい。

そこで空間を再帰的に四分割し衝突している可能性があるオブジェクトのみで衝突判定を行うようにする。
図1では空間を四分割し、さらに分割された空間を四分割している。
以後、四分割は再帰的に2回行うものとする。

## 空間の分割

次のように分割された空間に識別番号を付ける。
色付きの数字は二進数、黒色の数字は十進数を表わしている。

四分割0回
<img width="600" alt="2.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/649673/a58c8447-3983-769d-e560-45d3c949ad46.png">

四分割1回
<img width="600" alt="3.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/649673/45fc95f5-9bcd-045a-11f3-910ec6c5fe02.png">
四分割2回
<img width="600" alt="4.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/649673/80751edd-8aed-3895-bfbe-c5f32a1d069c.png">
四分割された空間は左上、右上、左下、右下の順に二進数で00、01、10、11と識別番号が割り当てられる。
親空間が存在する場合は、親空間の識別番号が先頭につく。
（つまり、**自身の識別番号から親の識別番号を知ることができる。**）

## 属している空間を求める

図1の各オブジェクトがどの空間に属するか考える。

図1
<img width="600" alt="1.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/649673/c63239e8-d45a-ffb3-b4d1-9858932eaab3.png">
Aは四分割2回の0～3番に属しているように見えるが、それらはAを内包していないため違う。
四分割1回の0番はAを内包しているため、Aは四分割1回の0番に属すことになる。

各オブジェクトは次の空間に属している。

|オブジェクト|四分割回数|番号|
|---|---|---|
|A|1回|0番|
|B|2回|4番|
|C|2回|7番|
|D|0回|0番|
|E|1回|2番|
|F|2回|14番|
|G|1回|3番|

ツリーで表わすとこうなる。
<img width="500" alt="5.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/649673/a7e8f4b6-1c75-059a-916f-7f0a5118c116.png">
仮にオブジェクトHが1回0番に属している場合はA、Dと、
1回1番に属している場合はB、C、Dと、
0回0番に属している場合は全オブジェクトと衝突判定をすればよい。

つまり特定のオブジェクトの衝突判定は、
・そのノードに属する全オブジェクト
・そのノードの再帰的な親ノードに属する全オブジェクト
・そのノードの再帰的な子ノードに属する全オブジェクト
にする必要がある。

それはさておき、**上にのせた各オブジェクトの属する空間は私が目で判定したものであり、
実際はプログラムで判定しなければならない。**

次の手順でオブジェクトの属する空間を求めることが出来る。

1. オブジェクトの左上と右下の点の座標が属する四分割2回の空間の番号を求める。
1. 左上と右下の四分割2回の空間番号でビットごとの排他的論理和をとり、オブジェクトが四分割の何回目（Nとする）の空間に属しているかを求める。
1. 左上（右下でもよい）の四分割2回の空間番号と2.で求めたNから、オブジェクトが四分割N回の何番に属しているのかを求める。

実際にオブジェクトGが属する空間を求めてみる。
なおオブジェクトGの左上の座標は(80, 60)、右下の座標は(90, 90)とする。

### 1. 左上と右下の座標の空間番号を求める。

座標のx, yを四分割2回の空間の幅（$= 100 \ \div \ 2 ^ 2 \ = \ 25$）で割り、小数点以下を切り捨てると四分割2回0番からx軸方向の何番目、y軸方向の何番目の空間が対象か分かる。

オブジェクトGの左上と右下の座標
左上： $(80, 60) \rightarrow (3.2, 2.4) \rightarrow (3, 2)$ 四分割2回0番からx軸方向の3番目、y軸方向の2番目の空間に属している。
右下： $(90, 90) \rightarrow (3.6, 3.6) \rightarrow (3, 3)$ 四分割2回0番からx軸方向の3番目、y軸方向の3番目の空間に属している。

<details><summary>細かいこと</summary><div>
x, yが100のときx軸方向、y軸方向の4番目になるけど空間なくねという疑問があるかもしれないが、普通に3番目と見なせばよい。
以上
</div></details>

さて、xy軸方向何番目の位置にある空間か分かったので対応表を作り、それを利用して空間番号を求めてもいいが、ビットをいじくりまわしても求めることができる。

オブジェクトGの左上と右下の座標を用いて説明する。
上手い説明できないので読者はエスパーになってもらいたい。
理解できない場合は[冒頭のサイト](http://marupeke296.com/COL_2D_No8_QuadTree.html)の「点の座標値から所属するモートン空間番号を出す」を参考

左上の座標は四分割2回からx軸方向の3番目、y軸方向の2番目の空間に属している。
x軸方向の3番目 → 3 → 二進数で011 → (x1, x2, x3) = (0, 1, 1)と定義
y軸方向の2番目 → 2 → 二進数で010 → (y1, y2, y3) = (0, 1, 0)と定義
二進数 y1 x1 y2 x2 y3 x3 → 0 0 1 1 0 1 → 001101 → 十進数で13 → 四分割2回の13番の空間に属していると分かる。

同様に
右下の座標は四分割2回からx軸方向の3番目、y軸方向の3番目の空間に属している。
x軸方向の3番目 → 3 → 二進数で011 → (x1, x2, x3) = (0, 1, 1)と定義
y軸方向の3番目 → 3 → 二進数で011 → (y1, y2, y3) = (0, 1, 1)と定義
二進数 y1 x1 y2 x2 y3 x3 → 0 0 1 1 1 1 → 001111 → 十進数で15 → 四分割2回の15番の空間に属していると分かる。

<details><summary>雑な証明</summary><div>
何故このようなことができるのかは以下の図から何となく察してもらいたい。
（自分の知能じゃ言葉でうまく説明できない）

<img width="600" alt="44.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/649673/d00f7cd6-40ba-e114-b390-000cbd52d96f.png">
<img width="700" alt="45.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/649673/33a68bae-6aa8-a3f8-bd6f-166eb90a64d4.png">
</div></details>

### 2. オブジェクトの属している空間が四分割何回目か求める。

左上と右下の四分割2回の空間番号でビットごとの排他的論理和をとると、オブジェクトが四分割の何回目の空間に属しているかが分かる。

オブジェクトGの左上の座標は四分割2回の13番、右下の座標は四分割2回の15番なので
$13 \ \oplus \ 15 \ = \ (001101)_2 \ \oplus \ (001111)_2 \ = \ (000010)_2$となる。
<img width="600" alt="6.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/649673/7d97a0ec-0a98-5a6b-40d4-02e2dc7b3054.png">
四分割0回のXORが0 → オブジェクトGは四分割0回のどこかの空間に属している。
四分割1回のXORが0 → オブジェクトGは四分割1回のどこかの空間に属している。
四分割2回のXORが0でない → オブジェクトGは四分割2回のどこかの空間に属していない。

よってオブジェクトGが四分割1回のいずれかの空間に属していることが分かった。

証明は属するときのパターンで0になること、属さないときに0にならないことを四分割の図を眺めれば何となく分かるので略

### 3. オブジェクトの属している空間番号を求める。

2.よりオブジェクトGが四分割1回のどこかの空間に属していることが分かった。
そして空間番号の[識別ルール](#空間の分割)より、オブジェクトGの内の点が属する四分割2回の空間の番号から自身を含んでいる四分割N回（N < 2）の空間の番号を知ることができる。
オブジェクトGの左上の座標が属している四分割2回の空間の番号は001101なので四分割1回の空間番号が$(11)_2 \ = \ 3$となり、オブジェクトGは四分割2回の3番の空間に属していることが分かった。

## 全オブジェクトとの衝突判定

[属している空間を求める](#属している空間を求める)にも書いたが
あるオブジェクトの衝突判定は、
・そのノードに属する全オブジェクト
・そのノードの再帰的な親ノードに属する全オブジェクト
・そのノードの再帰的な子ノードに属する全オブジェクト
にする必要がある。

<img width="500" alt="5.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/649673/a7e8f4b6-1c75-059a-916f-7f0a5118c116.png">

よってオブジェクトA～Gのすべての衝突判定をする場合
$(D, A), \ (D, B), \ (D, C), \ (D, E), \ (D, G), \ (D, F), \ (G, F)$
と行えばよい。

なお[冒頭のサイト](http://marupeke296.com/COL_2D_No8_QuadTree.html)の「④ 1回の木巡回で衝突判定を終わらせる」は
<img width="600" alt="7.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/649673/6c0d7626-8e25-1805-0899-a656f9bdb556.png">
と探索するより
<img width="600" alt="8.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/649673/e08c0345-30bd-be54-70e7-c2e3a2ee5c0c.png">
とした方がロジック的によくない？ということを言っている。（多分）

終わり。

# その他、参考にしたサイト

[四分木探索（理論編）](https://geolog.mydns.jp/1st.geocities.jp/shift486909/program/QuadTree1.html)
[超高速2D当たり判定プログラムを作りたかった](https://qiita.com/bearjiro/items/1078db2d78f92898b813)