Source file Broadphase.ml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
type box = Vec2.t * Vec2.t
type method_ = All_pairs | Grid | Sort_and_sweep
let methods = [ All_pairs; Grid; Sort_and_sweep ]
let name = function All_pairs -> "all pairs" | Grid -> "grid" | Sort_and_sweep -> "sort and sweep"
type result = { pairs : (int * int) list; tests : int }
let ordered i j = if i < j then (i, j) else (j, i)
let all_pairs (boxes : box array) : result =
let n = Array.length boxes in
let pairs = ref [] in
for i = 0 to n - 1 do
for j = i + 1 to n - 1 do
if Collide.bounds_overlap boxes.(i) boxes.(j) then pairs := (i, j) :: !pairs
done
done;
{ pairs = List.rev !pairs; tests = n * (n - 1) / 2 }
let cell_size (boxes : box array) : float =
Array.fold_left (fun m ((x0, y0), (x1, y1)) -> Float.max m (Float.max (x1 -. x0) (y1 -. y0))) 0. boxes
let grid ?cell (boxes : box array) : result =
let cell = match cell with Some c -> c | None -> cell_size boxes in
let cell = if cell > 0. then cell else 1. in
let index v = int_of_float (Float.floor (v /. cell)) in
let cells : (int * int, int list) Hashtbl.t = Hashtbl.create 64 in
boxes
|> Array.iteri (fun i ((x0, y0), (x1, y1)) ->
for cx = index x0 to index x1 do
for cy = index y0 to index y1 do
Hashtbl.replace cells (cx, cy) (i :: Option.value ~default:[] (Hashtbl.find_opt cells (cx, cy)))
done
done);
let tested = Hashtbl.create 64 and pairs = ref [] in
cells
|> Hashtbl.iter (fun _ inside ->
List.iter
(fun i ->
List.iter
(fun j ->
if i < j && not (Hashtbl.mem tested (i, j)) then (
Hashtbl.add tested (i, j) ();
if Collide.bounds_overlap boxes.(i) boxes.(j) then pairs := (i, j) :: !pairs))
inside)
inside);
{ pairs = List.sort compare !pairs; tests = Hashtbl.length tested }
let sort_and_sweep (boxes : box array) : result =
let left i = fst (fst boxes.(i)) and right i = fst (snd boxes.(i)) in
let order = List.sort (fun i j -> compare (left i) (left j)) (List.init (Array.length boxes) Fun.id) in
let tests = ref 0 and pairs = ref [] in
let (_ : int list) =
List.fold_left
(fun active i ->
let active = List.filter (fun a -> right a >= left i) active in
List.iter
(fun a ->
incr tests;
if Collide.bounds_overlap boxes.(a) boxes.(i) then pairs := ordered a i :: !pairs)
active;
i :: active)
[] order
in
{ pairs = List.sort compare !pairs; tests = !tests }
let pairs (m : method_) (boxes : box array) : result =
match m with All_pairs -> all_pairs boxes | Grid -> grid boxes | Sort_and_sweep -> sort_and_sweep boxes