use an immutable vector (always of length 4) for representing quad tree's internal nodes

This commit is contained in:
2025-01-31 06:24:51 +00:00
parent 76c5f9d662
commit 547b5bac97
3 changed files with 54 additions and 47 deletions

View File

@@ -38,14 +38,17 @@ struct
fun foldRegion (rx, ry, rw, rh, env, state, tree) = fun foldRegion (rx, ry, rw, rh, env, state, tree) =
case tree of case tree of
NODE {topLeft, topRight, bottomLeft, bottomRight, x, y, w, h} => NODE {nodes, x, y, w, h} =>
if isCollidingPlus (rx, ry, rw, rh, x, y, w, h) then if isCollidingPlus (rx, ry, rw, rh, x, y, w, h) then
let let
val state = foldRegion (rx, ry, rw, rh, env, state, topLeft) val state =
val state = foldRegion (rx, ry, rw, rh, env, state, topRight) foldRegion (rx, ry, rw, rh, env, state, Vector.sub (nodes, tlIdx))
val state = foldRegion (rx, ry, rw, rh, env, state, bottomLeft) val state =
foldRegion (rx, ry, rw, rh, env, state, Vector.sub (nodes, trIdx))
val state =
foldRegion (rx, ry, rw, rh, env, state, Vector.sub (nodes, blIdx))
in in
foldRegion (rx, ry, rw, rh, env, state, bottomRight) foldRegion (rx, ry, rw, rh, env, state, Vector.sub (nodes, brIdx))
end end
else else
state state

View File

@@ -4,10 +4,7 @@ sig
datatype t = datatype t =
NODE of NODE of
{ topLeft: t { nodes: t vector
, topRight: t
, bottomLeft: t
, bottomRight: t
, x: int , x: int
, y: int , y: int
, w: int , w: int
@@ -15,6 +12,11 @@ sig
} }
| LEAF of {items: item vector, x: int, y: int, w: int, h: int} | LEAF of {items: item vector, x: int, y: int, w: int, h: int}
val tlIdx: int
val trIdx: int
val blIdx: int
val brIdx: int
val isColliding: int * int * int * int * val isColliding: int * int * int * int *
int * int * int * int int * int * int * int
-> bool -> bool
@@ -50,10 +52,7 @@ struct
datatype t = datatype t =
NODE of NODE of
{ topLeft: t { nodes: t vector
, topRight: t
, bottomLeft: t
, bottomRight: t
, x: int , x: int
, y: int , y: int
, w: int , w: int
@@ -61,6 +60,11 @@ struct
} }
| LEAF of {items: item vector, x: int, y: int, w: int, h: int} | LEAF of {items: item vector, x: int, y: int, w: int, h: int}
val tlIdx = 0
val trIdx = 1
val blIdx = 2
val brIdx = 3
fun isColliding (ix, iy, ifx, ify, cx, cy, cfx, cfy) = fun isColliding (ix, iy, ifx, ify, cx, cy, cfx, cfy) =
ix < cfx andalso ifx > cx andalso iy < cfy andalso ify > cy ix < cfx andalso ifx > cx andalso iy < cfy andalso ify > cy

View File

@@ -97,10 +97,7 @@ struct
val br = mkBottomRight (x, y, w, h, br) val br = mkBottomRight (x, y, w, h, br)
in in
NODE NODE
{ topLeft = tl { nodes = Vector.fromList [tl, tr, bl, br]
, topRight = tr
, bottomLeft = bl
, bottomRight = br
, x = x , x = x
, y = y , y = y
, w = w , w = w
@@ -130,22 +127,19 @@ struct
fun insert (iX, iY, iW, iH, itemID, tree: t) = fun insert (iX, iY, iW, iH, itemID, tree: t) =
case tree of case tree of
NODE {topLeft, topRight, bottomLeft, bottomRight, x, y, w, h} => NODE {nodes, x, y, w, h} =>
if isCollidingPlus (iX, iY, iW, iH, x, y, w, h) then if isCollidingPlus (iX, iY, iW, iH, x, y, w, h) then
let let
(* we are not necessarily inserting into all nodes. (* we are not necessarily inserting into all nodes.
* If isCollidingPlus returns false recursively, * If isCollidingPlus returns false recursively,
* we return the same node back. *) * we return the same node back. *)
val tl = insert (iX, iY, iW, iH, itemID, topLeft) val tl = insert (iX, iY, iW, iH, itemID, Vector.sub (nodes, tlIdx))
val tr = insert (iX, iY, iW, iH, itemID, topRight) val tr = insert (iX, iY, iW, iH, itemID, Vector.sub (nodes, trIdx))
val bl = insert (iX, iY, iW, iH, itemID, bottomLeft) val bl = insert (iX, iY, iW, iH, itemID, Vector.sub (nodes, blIdx))
val br = insert (iX, iY, iW, iH, itemID, bottomRight) val br = insert (iX, iY, iW, iH, itemID, Vector.sub (nodes, brIdx))
in in
NODE NODE
{ topLeft = tl { nodes = Vector.fromList [tl, tr, bl, br]
, topRight = tr
, bottomLeft = bl
, bottomRight = br
, x = x , x = x
, y = y , y = y
, w = w , w = w
@@ -206,16 +200,19 @@ struct
fun getCollisionsAll (iX, iY, iW, iH, itemID, acc, tree) = fun getCollisionsAll (iX, iY, iW, iH, itemID, acc, tree) =
case tree of case tree of
NODE {topLeft, topRight, bottomLeft, bottomRight, x, y, w, h} => NODE {nodes, x, y, w, h} =>
if isCollidingPlus (iX, iY, iW, iH, x, y, w, h) then if isCollidingPlus (iX, iY, iW, iH, x, y, w, h) then
let let
val acc = getCollisionsAll (iX, iY, iW, iH, itemID, acc, topLeft) val acc =
getCollisionsAll (iX, iY, iW, iH, itemID, acc, Vector.sub (nodes, tlIdx))
val acc = getCollisionsAll (iX, iY, iW, iH, itemID, acc, topRight) val acc =
getCollisionsAll (iX, iY, iW, iH, itemID, acc, Vector.sub (nodes, trIdx))
val acc = getCollisionsAll (iX, iY, iW, iH, itemID, acc, bottomLeft) val acc =
getCollisionsAll (iX, iY, iW, iH, itemID, acc, Vector.sub (nodes, blIdx))
in in
getCollisionsAll (iX, iY, iW, iH, itemID, acc, bottomRight) getCollisionsAll (iX, iY, iW, iH, itemID, acc, Vector.sub (nodes, brIdx))
end end
else else
acc acc
@@ -227,17 +224,20 @@ struct
fun helpGetCollisions (iX, iY, iW, iH, itemID, acc, tree: t) = fun helpGetCollisions (iX, iY, iW, iH, itemID, acc, tree: t) =
case tree of case tree of
NODE {topLeft, topRight, bottomLeft, bottomRight, x, y, w, h} => NODE {nodes, x, y, w, h} =>
if isCollidingPlus (iX, iY, iW, iH, x, y, w, h) then if isCollidingPlus (iX, iY, iW, iH, x, y, w, h) then
let let
val acc = helpGetCollisions (iX, iY, iW, iH, itemID, acc, topLeft) val acc =
helpGetCollisions (iX, iY, iW, iH, itemID, acc, Vector.sub (nodes, tlIdx))
val acc = helpGetCollisions (iX, iY, iW, iH, itemID, acc, topRight) val acc =
helpGetCollisions (iX, iY, iW, iH, itemID, acc, Vector.sub (nodes, trIdx))
val acc = helpGetCollisions val acc =
(iX, iY, iW, iH, itemID, acc, bottomLeft) helpGetCollisions (iX, iY, iW, iH, itemID, acc, Vector.sub (nodes, blIdx))
in in
helpGetCollisions (iX, iY, iW, iH, itemID, acc, bottomRight) helpGetCollisions
(iX, iY, iW, iH, itemID, acc, Vector.sub (nodes, brIdx))
end end
else else
acc acc
@@ -263,12 +263,12 @@ struct
fun hasCollisionAt (iX, iY, iW, iH, itemID, tree) = fun hasCollisionAt (iX, iY, iW, iH, itemID, tree) =
case tree of case tree of
NODE {topLeft, topRight, bottomLeft, bottomRight, x, y, w, h} => NODE {nodes, x, y, w, h} =>
if isCollidingPlus (iX, iY, iW, iH, x, y, w, h) then if isCollidingPlus (iX, iY, iW, iH, x, y, w, h) then
hasCollisionAt (iX, iY, iW, iH, itemID, topLeft) hasCollisionAt (iX, iY, iW, iH, itemID, Vector.sub (nodes, tlIdx))
orelse hasCollisionAt (iX, iY, iW, iH, itemID, topRight) orelse hasCollisionAt (iX, iY, iW, iH, itemID, Vector.sub (nodes, trIdx))
orelse hasCollisionAt (iX, iY, iW, iH, itemID, bottomLeft) orelse hasCollisionAt (iX, iY, iW, iH, itemID, Vector.sub (nodes, blIdx))
orelse hasCollisionAt (iX, iY, iW, iH, itemID, bottomRight) orelse hasCollisionAt (iX, iY, iW, iH, itemID, Vector.sub (nodes, brIdx))
else else
false false
| LEAF {items, x, y, w, h} => | LEAF {items, x, y, w, h} =>
@@ -290,13 +290,13 @@ struct
fun getItemID (iX, iY, iW, iH, tree) = fun getItemID (iX, iY, iW, iH, tree) =
case tree of case tree of
NODE {topLeft, topRight, bottomLeft, bottomRight, x, y, w, h} => NODE {nodes, x, y, w, h} =>
if isCollidingPlus (iX, iY, iW, iH, x, y, w, h) then if isCollidingPlus (iX, iY, iW, iH, x, y, w, h) then
let let
val try1 = getItemID (iX, iY, iW, iH, topLeft) val try1 = getItemID (iX, iY, iW, iH, Vector.sub (nodes, tlIdx))
val try2 = getItemID (iX, iY, iW, iH, topRight) val try2 = getItemID (iX, iY, iW, iH, Vector.sub (nodes, trIdx))
val try3 = getItemID (iX, iY, iW, iH, bottomLeft) val try3 = getItemID (iX, iY, iW, iH, Vector.sub (nodes, blIdx))
val try4 = getItemID (iX, iY, iW, iH, bottomRight) val try4 = getItemID (iX, iY, iW, iH, Vector.sub (nodes, brIdx))
(* get max: we assume query was narrow enough (* get max: we assume query was narrow enough
* that only one ID is valid *) * that only one ID is valid *)