fix quad tree queries (queries should not choose only one quadrant because they may validly visit two or more quadrants if query covers two leaf nodes), resulting in regressions. Fix one regression: reimplement wall patches (this time also optimised because there is no intgermediary list)

This commit is contained in:
2025-01-27 04:52:49 +00:00
parent 1c4ff62744
commit b7a609b447
3 changed files with 372 additions and 599 deletions

View File

@@ -526,14 +526,14 @@ struct
#platID enemy #platID enemy
else eID else eID
in in
if eID = #nextPlatID enemy then if eID = ~1 orelse pID = ~1 then
getLandingPatches (eID, platforms, enemy, acc)
else if eID = ~1 orelse pID = ~1 then
(* without checking that neither of these are ~1 (* without checking that neither of these are ~1
* (which means there is no platform below the enemy/player) * (which means there is no platform below the enemy/player)
* there is a subscript error because the PathFinding.start * there is a subscript error because the PathFinding.start
* function expects neither of these values to be ~1. *) * function expects neither of these values to be ~1. *)
getPatrollPatches (enemy, wallTree, platformTree, acc) getPatrollPatches (enemy, wallTree, platformTree, acc)
else if eID = #nextPlatID enemy then
getLandingPatches (eID, platforms, enemy, acc)
else if eID = pID then else if eID = pID then
getPatrollPatches (enemy, wallTree, platformTree, acc) getPatrollPatches (enemy, wallTree, platformTree, acc)
else else

View File

@@ -100,45 +100,68 @@ struct
QuadTree.getItemID (x, y, width, height, 0, 0, ww, wh, tree) QuadTree.getItemID (x, y, width, height, 0, 0, ww, wh, tree)
end end
fun getWallPatches (walls: wall vector, lst, acc) = fun getWallPatches (x, y, walls, wallTree, acc) =
let let
open QuadTree val size = Fn.entitySize
val moveBy = Fn.moveBy
val ww = Constants.worldWidth
val wh = Constants.worldHeight
(* check collision with wall to the left *)
val acc =
let
val leftWallID = QuadTree.getItemID
(x - 1, y, 1, 1, 0, 0, ww, wh, wallTree)
in in
case lst of if leftWallID <> ~1 then
(QUERY_ON_LEFT_SIDE, wallID) :: tl =>
let let
val {x = wallX, width = wallWidth, ...} = val {x = wallX, width = wallWidth, ...} =
Vector.sub (walls, wallID - 1) Vector.sub (walls, leftWallID - 1)
val newX = wallX + wallWidth val newX = wallX + wallWidth
val acc = Fn.W_X newX :: acc
in in
getWallPatches (walls, tl, acc) Fn.W_X newX :: acc
end end
| (QUERY_ON_RIGHT_SIDE, wallID) :: tl => else
acc
end
(* check collision with wall to the right *)
val acc =
let let
val {x = wallX, width = wallWidth, ...} = val rightWallID = QuadTree.getItemID
Vector.sub (walls, wallID - 1) (x + size - 1, y, 1, 1, 0, 0, ww, wh, wallTree)
val newX = wallX - Fn.entitySize
val acc = Fn.W_X newX :: acc
in in
getWallPatches (walls, tl, acc) if rightWallID <> ~1 then
end
| (QUERY_ON_BOTTOM_SIDE, wallID) :: tl =>
let let
val {y = wallY, ...} = Vector.sub (walls, wallID - 1) val {x = wallX, ...} = Vector.sub (walls, rightWallID - 1)
val newY = wallY - Fn.entitySize val newX = wallX - size
val acc = Fn.W_Y_AXIS ON_GROUND :: Fn.W_Y newY :: acc
in in
getWallPatches (walls, tl, acc) Fn.W_X newX :: acc
end end
| (QUERY_ON_TOP_SIDE, wallID) :: tl => getWallPatches (walls, tl, acc) else
| [] => acc acc
end end
fun getEnvironmentPatches (input, walls, wallTree, platforms, platformTree) = (* check collision with wall below *)
val downWallID = QuadTree.getItemID
(x + moveBy + 1, y + size, 1, 1, 0, 0, ww, wh, wallTree)
in
if downWallID <> ~1 then
let
val {y = wallY, ...} = Vector.sub (walls, downWallID - 1)
val newY = wallY - size
in
Fn.W_Y_AXIS ON_GROUND :: Fn.W_Y newY :: acc
end
else
acc
end
fun getEnvironmentPatches
(input, walls: wall vector, wallTree, platforms, platformTree) =
let let
(* react to platform and wall collisions *) (* react to platform and wall collisions *)
val x = Fn.getX input val x = Fn.getX input
@@ -199,16 +222,11 @@ struct
else Fn.W_Y_AXIS FALLING :: acc else Fn.W_Y_AXIS FALLING :: acc
| _ => acc | _ => acc
val wallCollisions = QuadTree.getCollisionSides val acc = getWallPatches (x, y, walls, wallTree, acc)
(x, y, size, size, 0, 0, ww, wh, 0, wallTree)
val acc = getWallPatches (walls, wallCollisions, acc)
val standPlatID = standingOnAreaID (x, y, platformTree) val standPlatID = standingOnAreaID (x, y, platformTree)
in in
if standPlatID <> ~1 then if standPlatID <> ~1 then Fn.W_PLAT_ID standPlatID :: acc else acc
Fn.W_PLAT_ID standPlatID :: acc
else
acc
end end
end end

View File

@@ -4,10 +4,6 @@ sig
val empty: t val empty: t
val whichQuadrant: int * int * int * int *
int * int * int * int
-> QuadTreeType.quadrant
datatype collision_side = datatype collision_side =
QUERY_ON_LEFT_SIDE QUERY_ON_LEFT_SIDE
| QUERY_ON_TOP_SIDE | QUERY_ON_TOP_SIDE
@@ -50,6 +46,43 @@ struct
type item = QuadTreeType.item type item = QuadTreeType.item
fun visitTopLeft (iX, iY, iW, iH, qX, qY, qW, qH) =
let
val midX = qW div 2 + qX
val midY = qH div 2 + qY
in
iX <= midX andalso iY <= midY
end
fun visitTopRight (iX, iY, iW, iH, qX, qY, qW, qH) =
let
val midX = qW div 2 + qX
val midY = qH div 2 + qY
in
iX >= midX andalso iY <= midY
end
fun visitBottomLeft (iX, iY, iW, iH, qX, qY, qW, qH) =
let
val midX = qW div 2 + qX
val midY = qH div 2 + qY
val iFinishY = iY + iH
in
iX <= midX andalso iFinishY >= midY
end
fun visitBottomRight (iX, iY, iW, iH, qX, qY, qW, qH) =
let
val midX = qW div 2 + qX
val midY = qH div 2 + qY
val iFinishX = iX + iH
val iFinishY = iY + iH
in
iFinishX >= midX andalso iFinishY >= midY
end
fun mkItem (id, startX, startY, width, height) : item = fun mkItem (id, startX, startY, width, height) : item =
{ itemID = id { itemID = id
, startX = startX , startX = startX
@@ -58,6 +91,21 @@ struct
, height = height , height = height
} }
fun itemToString {itemID, startX, startY, width, height} =
String.concat [
"{itemID = ",
Int.toString itemID,
", startX = ",
Int.toString startX,
", startY = ",
Int.toString startY,
", width = ",
Int.toString width,
", height = ",
Int.toString height,
"}"
]
type t = QuadTreeType.t type t = QuadTreeType.t
val empty = LEAF (Vector.fromList []) val empty = LEAF (Vector.fromList [])
@@ -433,6 +481,19 @@ struct
LEAF elements LEAF elements
end end
fun isBetween (start, checkStart, finish, checkFinish) =
(* if check containhs start/finish *)
(checkStart <= start andalso checkFinish >= finish)
orelse
(* if start/finish containhs check *)
(start <= checkStart andalso finish >= checkFinish)
orelse
(* if checkStart between start and finish *)
(start <= checkStart andalso finish >= checkStart)
orelse
(* if checkFinish is between start and finish *)
(start <= checkFinish andalso finish >= checkFinish)
fun isColliding (iX, iY, iW, iH, itemID, checkWith: item) = fun isColliding (iX, iY, iW, iH, itemID, checkWith: item) =
let let
val itemEndX = iX + iW val itemEndX = iX + iW
@@ -441,8 +502,9 @@ struct
val endX = startX + width val endX = startX + width
val endY = startY + height val endY = startY + height
in in
iX < endX andalso itemEndX > startX andalso iY < endY isBetween (iX, startX, itemEndX, endX) andalso
andalso itemEndY > startY andalso itemID <> checkID isBetween (iY, startY, itemEndY, endY) andalso
itemID <> checkID
end end
fun getCollisionsVec (iX, iY, iW, iH, itemID, pos, elements, acc) = fun getCollisionsVec (iX, iY, iW, iH, itemID, pos, elements, acc) =
@@ -500,133 +562,53 @@ struct
(* get colliding elements in this node first *) (* get colliding elements in this node first *)
val acc = getCollisionsVec val acc = getCollisionsVec
(itemX, itemY, itemWidth, itemHeight, itemID, 0, elements, acc) (itemX, itemY, itemWidth, itemHeight, itemID, 0, elements, acc)
val halfWidth = quadWidth div 2
val halfHeight = quadHeight div 2
in
(case
whichQuadrant
( itemX
, itemY
, itemWidth
, itemHeight
, quadX
, quadY
, quadWidth
, quadHeight
)
of
TOP_LEFT =>
helpGetCollisions
( itemX
, itemY
, itemWidth
, itemHeight
, quadX
, quadY
, halfWidth
, halfHeight
, itemID
, acc
, topLeft
)
| TOP_RIGHT =>
helpGetCollisions
( itemX
, itemY
, itemWidth
, itemHeight
, quadX + halfWidth
, quadY
, halfWidth
, halfHeight
, itemID
, acc
, topRight
)
| BOTTOM_LEFT =>
helpGetCollisions
( itemX
, itemY
, itemWidth
, itemHeight
, quadX
, quadY + halfHeight
, halfWidth
, halfHeight
, itemID
, acc
, bottomLeft
)
| BOTTOM_RIGHT =>
helpGetCollisions
( itemX
, itemY
, itemWidth
, itemHeight
, quadX + halfWidth
, quadY + halfHeight
, halfWidth
, halfHeight
, itemID
, acc
, bottomRight
)
| PARENT_QUADRANT =>
(* In this function, PARENT_QUADRANT means
* that the item is not in any of the main quadrants
* but may possibly in the parent quadrant OR
* it may be in any of the child quadrants.
* So descend down on all the children, accumulating acc.
* *)
let
val acc = getCollisionsAll
( itemX
, itemY
, itemWidth
, itemHeight
, halfWidth
, halfHeight
, itemID
, acc
, topLeft
)
val acc = getCollisionsAll val halfW = quadWidth div 2
( itemX val halfH = quadHeight div 2
, itemY
, itemWidth
, itemHeight
, halfWidth
, halfHeight
, itemID
, acc
, topRight
)
val acc = getCollisionsAll val midX = halfW + quadX
( itemX val midY = halfH + quadY
, itemY
, itemWidth val iX = itemX
, itemHeight val iY = itemY
, halfWidth val iW = itemWidth
, halfHeight val iH = itemHeight
, itemID
, acc val qX = quadX
, bottomLeft val qY = quadY
) val qW = quadWidth
val qH = quadHeight
val vtl = visitTopLeft (iX, iY, iW, iH, qX, qY, qW, qH)
val vtr = visitTopRight (iX, iY, iW, iH, qX, qY, qW, qH)
val vbl = visitBottomLeft (iX, iY, iW, iH, qX, qY, qW, qH)
val vbr = visitBottomRight (iX, iY, iW, iH, qX, qY, qW, qH)
val acc =
if vtl then
helpGetCollisions
(iX, iY, iW, iH, qX, qY, halfW, halfH, itemID, acc, topLeft)
else acc
val acc =
if vtr then
helpGetCollisions
(iX, iY, iW, iH, midX, qY, halfW, halfH, itemID, acc, topRight)
else acc
val acc =
if vbl then
helpGetCollisions
(iX, iY, iW, iH, qX, midY, halfW, halfH, itemID, acc, bottomLeft)
else acc
val acc =
if vbl then
helpGetCollisions
(iX, iY, iW, iH, midX, midY, halfW, halfH, itemID, acc, bottomRight)
else acc
in in
getCollisionsAll acc
( itemX
, itemY
, itemWidth
, itemHeight
, halfWidth
, halfHeight
, itemID
, acc
, bottomRight
)
end)
end end
| LEAF elements => | LEAF elements =>
getCollisionsVec getCollisionsVec
@@ -769,133 +751,53 @@ struct
(* get colliding elements in this node first *) (* get colliding elements in this node first *)
val acc = getCollisionSideVec val acc = getCollisionSideVec
(itemX, itemY, itemWidth, itemHeight, itemID, 0, elements, acc) (itemX, itemY, itemWidth, itemHeight, itemID, 0, elements, acc)
val halfWidth = quadWidth div 2
val halfHeight = quadHeight div 2
in
(case
whichQuadrant
( itemX
, itemY
, itemWidth
, itemHeight
, quadX
, quadY
, quadWidth
, quadHeight
)
of
TOP_LEFT =>
helpGetCollisionSides
( itemX
, itemY
, itemWidth
, itemHeight
, quadX
, quadY
, halfWidth
, halfHeight
, itemID
, acc
, topLeft
)
| TOP_RIGHT =>
helpGetCollisionSides
( itemX
, itemY
, itemWidth
, itemHeight
, quadX + halfWidth
, quadY
, halfWidth
, halfHeight
, itemID
, acc
, topRight
)
| BOTTOM_LEFT =>
helpGetCollisionSides
( itemX
, itemY
, itemWidth
, itemHeight
, quadX
, quadY + halfHeight
, halfWidth
, halfHeight
, itemID
, acc
, bottomLeft
)
| BOTTOM_RIGHT =>
helpGetCollisionSides
( itemX
, itemY
, itemWidth
, itemHeight
, quadX + halfWidth
, quadY + halfHeight
, halfWidth
, halfHeight
, itemID
, acc
, bottomRight
)
| PARENT_QUADRANT =>
(* In this function, PARENT_QUADRANT means
* that the item is not in any of the main quadrants
* but may possibly in the parent quadrant OR
* it may be in any of the child quadrants.
* So descend down on all the children, accumulating acc.
* *)
let
val acc = getCollisionSidesAll
( itemX
, itemY
, itemWidth
, itemHeight
, halfWidth
, halfHeight
, itemID
, acc
, topLeft
)
val acc = getCollisionSidesAll val halfW = quadWidth div 2
( itemX val halfH = quadHeight div 2
, itemY
, itemWidth
, itemHeight
, halfWidth
, halfHeight
, itemID
, acc
, topRight
)
val acc = getCollisionSidesAll val midX = halfW + quadX
( itemX val midY = halfH + quadY
, itemY
, itemWidth val iX = itemX
, itemHeight val iY = itemY
, halfWidth val iW = itemWidth
, halfHeight val iH = itemHeight
, itemID
, acc val qX = quadX
, bottomLeft val qY = quadY
) val qW = quadWidth
val qH = quadHeight
val vtl = visitTopLeft (iX, iY, iW, iH, qX, qY, qW, qH)
val vtr = visitTopRight (iX, iY, iW, iH, qX, qY, qW, qH)
val vbl = visitBottomLeft (iX, iY, iW, iH, qX, qY, qW, qH)
val vbr = visitBottomRight (iX, iY, iW, iH, qX, qY, qW, qH)
val acc =
if vtl then
helpGetCollisionSides
(iX, iY, iW, iH, qX, qY, halfW, halfH, itemID, acc, topLeft)
else acc
val acc =
if vtr then
helpGetCollisionSides
(iX, iY, iW, iH, midX, qY, halfW, halfH, itemID, acc, topRight)
else acc
val acc =
if vbl then
helpGetCollisionSides
(iX, iY, iW, iH, qX, midY, halfW, halfH, itemID, acc, bottomLeft)
else acc
val acc =
if vbl then
helpGetCollisionSides
(iX, iY, iW, iH, midX, midY, halfW, halfH, itemID, acc, bottomRight)
else acc
in in
getCollisionSidesAll acc
( itemX
, itemY
, itemWidth
, itemHeight
, halfWidth
, halfHeight
, itemID
, acc
, bottomRight
)
end)
end end
| LEAF elements => | LEAF elements =>
getCollisionSideVec getCollisionSideVec
@@ -990,133 +892,53 @@ struct
(* get colliding elements in this node first *) (* get colliding elements in this node first *)
val acc = getCollisionsBelowVec val acc = getCollisionsBelowVec
(itemX, itemY, itemWidth, itemHeight, itemID, 0, elements, acc) (itemX, itemY, itemWidth, itemHeight, itemID, 0, elements, acc)
val halfWidth = quadWidth div 2
val halfHeight = quadHeight div 2
in
(case
whichQuadrant
( itemX
, itemY
, itemWidth
, itemHeight
, quadX
, quadY
, quadWidth
, quadHeight
)
of
TOP_LEFT =>
helpGetCollisionsBelow
( itemX
, itemY
, itemWidth
, itemHeight
, quadX
, quadY
, halfWidth
, halfHeight
, itemID
, acc
, topLeft
)
| TOP_RIGHT =>
helpGetCollisionsBelow
( itemX
, itemY
, itemWidth
, itemHeight
, quadX + halfWidth
, quadY
, halfWidth
, halfHeight
, itemID
, acc
, topRight
)
| BOTTOM_LEFT =>
helpGetCollisionsBelow
( itemX
, itemY
, itemWidth
, itemHeight
, quadX
, quadY + halfHeight
, halfWidth
, halfHeight
, itemID
, acc
, bottomLeft
)
| BOTTOM_RIGHT =>
helpGetCollisionsBelow
( itemX
, itemY
, itemWidth
, itemHeight
, quadX + halfWidth
, quadY + halfHeight
, halfWidth
, halfHeight
, itemID
, acc
, bottomRight
)
| PARENT_QUADRANT =>
(* In this function, PARENT_QUADRANT means
* that the item is not in any of the main quadrants
* but may possibly in the parent quadrant OR
* it may be in any of the child quadrants.
* So descend down on all the children, accumulating acc.
* *)
let
val acc = getCollisionsBelowAll
( itemX
, itemY
, itemWidth
, itemHeight
, halfWidth
, halfHeight
, itemID
, acc
, topLeft
)
val acc = getCollisionsBelowAll val halfW = quadWidth div 2
( itemX val halfH = quadHeight div 2
, itemY
, itemWidth
, itemHeight
, halfWidth
, halfHeight
, itemID
, acc
, topRight
)
val acc = getCollisionsBelowAll val midX = halfW + quadX
( itemX val midY = halfH + quadY
, itemY
, itemWidth val iX = itemX
, itemHeight val iY = itemY
, halfWidth val iW = itemWidth
, halfHeight val iH = itemHeight
, itemID
, acc val qX = quadX
, bottomLeft val qY = quadY
) val qW = quadWidth
val qH = quadHeight
val vtl = visitTopLeft (iX, iY, iW, iH, qX, qY, qW, qH)
val vtr = visitTopRight (iX, iY, iW, iH, qX, qY, qW, qH)
val vbl = visitBottomLeft (iX, iY, iW, iH, qX, qY, qW, qH)
val vbr = visitBottomRight (iX, iY, iW, iH, qX, qY, qW, qH)
val acc =
if vtl then
helpGetCollisionsBelow
(iX, iY, iW, iH, qX, qY, halfW, halfH, itemID, acc, topLeft)
else acc
val acc =
if vtr then
helpGetCollisionsBelow
(iX, iY, iW, iH, midX, qY, halfW, halfH, itemID, acc, topRight)
else acc
val acc =
if vbl then
helpGetCollisionsBelow
(iX, iY, iW, iH, qX, midY, halfW, halfH, itemID, acc, bottomLeft)
else acc
val acc =
if vbl then
helpGetCollisionsBelow
(iX, iY, iW, iH, midX, midY, halfW, halfH, itemID, acc, bottomRight)
else acc
in in
getCollisionsBelowAll acc
( itemX
, itemY
, itemWidth
, itemHeight
, halfWidth
, halfHeight
, itemID
, acc
, bottomRight
)
end)
end end
| LEAF elements => | LEAF elements =>
getCollisionsBelowVec getCollisionsBelowVec
@@ -1155,8 +977,16 @@ struct
let let
val item = Vector.sub (elements, pos) val item = Vector.sub (elements, pos)
in in
if
isColliding (iX, iY, iW, iH, itemID, item) isColliding (iX, iY, iW, iH, itemID, item)
orelse hasCollisionAtVec (iX, iY, iW, iH, itemID, pos + 1, elements) then
let val _ = print ("quad-tree.sml: has collision: \n" ^ itemToString
item ^ "\n")
in
true
end
else
hasCollisionAtVec (iX, iY, iW, iH, itemID, pos + 1, elements)
end end
fun hasCollisionAt fun hasCollisionAt
@@ -1176,95 +1006,54 @@ struct
hasCollisionAtVec hasCollisionAtVec
(itemX, itemY, itemWidth, itemHeight, itemID, 0, elements) (itemX, itemY, itemWidth, itemHeight, itemID, 0, elements)
orelse orelse
(case
whichQuadrant
( itemX
, itemY
, itemWidth
, itemHeight
, quadX
, quadY
, quadWidth
, quadHeight
)
of
TOP_LEFT =>
let let
val halfWidth = quadWidth div 2 val halfW = quadWidth div 2
val halfHeight = quadHeight div 2 val halfH = quadHeight div 2
in
val midX = halfW + quadX
val midY = halfH + quadY
val iX = itemX
val iY = itemY
val iW = itemWidth
val iH = itemHeight
val qX = quadX
val qY = quadY
val qW = quadWidth
val qH = quadHeight
val vtl = visitTopLeft (iX, iY, iW, iH, qX, qY, qW, qH)
val vtr = visitTopRight (iX, iY, iW, iH, qX, qY, qW, qH)
val vbl = visitBottomLeft (iX, iY, iW, iH, qX, qY, qW, qH)
val vbr = visitBottomRight (iX, iY, iW, iH, qX, qY, qW, qH)
val tl =
if vtl then
hasCollisionAt hasCollisionAt
( itemX (iX, iY, iW, iH, qX, qY, halfW, halfH, itemID, topLeft)
, itemY else false
, itemWidth
, itemHeight val tr =
, quadX if vtr then
, quadY
, halfWidth
, halfHeight
, itemID
, topLeft
)
end
| TOP_RIGHT =>
let
val halfWidth = quadWidth div 2
val halfHeight = quadHeight div 2
val middleX = quadX + halfWidth
in
hasCollisionAt hasCollisionAt
( itemX (iX, iY, iW, iH, midX, qY, halfW, halfH, itemID, topRight)
, itemY else false
, itemWidth
, itemHeight val bl =
, middleX if vbl then
, quadY
, halfWidth
, halfHeight
, itemID
, topRight
)
end
| BOTTOM_LEFT =>
let
val halfWidth = quadWidth div 2
val halfHeight = quadHeight div 2
val middleY = quadY + halfHeight
in
hasCollisionAt hasCollisionAt
( itemX (iX, iY, iW, iH, qX, midY, halfW, halfH, itemID, bottomLeft)
, itemY else false
, itemWidth
, itemHeight val br =
, quadX if vbl then
, middleY
, halfWidth
, halfHeight
, itemID
, bottomLeft
)
end
| BOTTOM_RIGHT =>
let
val halfWidth = quadWidth div 2
val halfHeight = quadHeight div 2
val middleX = quadX + halfWidth
val middleY = quadY + halfHeight
in
hasCollisionAt hasCollisionAt
( itemX (iX, iY, iW, iH, midX, midY, halfW, halfH, itemID, bottomRight)
, itemY else false
, itemWidth in
, itemHeight tl orelse tr orelse bl orelse br
, middleX
, middleY
, halfWidth
, halfHeight
, itemID
, bottomRight
)
end end
| PARENT_QUADRANT => false)
| LEAF elements => | LEAF elements =>
hasCollisionAtVec hasCollisionAtVec
(itemX, itemY, itemWidth, itemHeight, itemID, 0, elements) (itemX, itemY, itemWidth, itemHeight, itemID, 0, elements)
@@ -1285,86 +1074,52 @@ struct
NODE {topLeft, topRight, bottomLeft, bottomRight, elements} => NODE {topLeft, topRight, bottomLeft, bottomRight, elements} =>
let let
val tryID = getItemIDVec (itemX, itemY, itemW, itemH, 0, elements) val tryID = getItemIDVec (itemX, itemY, itemW, itemH, 0, elements)
in
if tryID = ~1 then val halfW = quadW div 2
(case val halfH = quadH div 2
whichQuadrant
(itemX, itemY, itemW, itemH, quadX, quadY, quadW, quadH) val midX = halfW + quadX
of val midY = halfH + quadY
TOP_LEFT =>
let val iX = itemX
val halfWidth = quadW div 2 val iY = itemY
val halfHeight = quadH div 2 val iW = itemW
in val iH = itemH
val qX = quadX
val qY = quadY
val qW = quadW
val qH = quadH
val vtl = visitTopLeft (iX, iY, iW, iH, qX, qY, qW, qH)
val vtr = visitTopRight (iX, iY, iW, iH, qX, qY, qW, qH)
val vbl = visitBottomLeft (iX, iY, iW, iH, qX, qY, qW, qH)
val vbr = visitBottomRight (iX, iY, iW, iH, qX, qY, qW, qH)
val tryID =
if vtl andalso tryID = ~1 then
getItemID getItemID
( itemX (iX, iY, iW, iH, qX, qY, halfW, halfH, topLeft)
, itemY else tryID
, itemW
, itemH val tryID =
, quadX if vtr andalso tryID = ~1 then
, quadY
, halfWidth
, halfHeight
, topLeft
)
end
| TOP_RIGHT =>
let
val halfWidth = quadW div 2
val halfHeight = quadH div 2
val middleX = quadX + halfWidth
in
getItemID getItemID
( itemX (iX, iY, iW, iH, midX, qY, halfW, halfH, topRight)
, itemY else tryID
, itemW
, itemH val tryID =
, middleX if vbl andalso tryID = ~1 then
, quadY
, halfWidth
, halfHeight
, topRight
)
end
| BOTTOM_LEFT =>
let
val halfWidth = quadW div 2
val halfHeight = quadH div 2
val middleY = quadY + halfHeight
in
getItemID getItemID
( itemX (iX, iY, iW, iH, qX, midY, halfW, halfH, bottomLeft)
, itemY else tryID
, itemW
, itemH val tryID =
, quadX if vbl andalso tryID <> ~1 then
, middleY
, halfWidth
, halfHeight
, bottomLeft
)
end
| BOTTOM_RIGHT =>
let
val halfWidth = quadW div 2
val halfHeight = quadH div 2
val middleX = quadX + halfWidth
val middleY = quadY + halfHeight
in
getItemID getItemID
( itemX (iX, iY, iW, iH, midX, midY, halfW, halfH, bottomRight)
, itemY else tryID
, itemW in
, itemH
, middleX
, middleY
, halfWidth
, halfHeight
, bottomRight
)
end
| PARENT_QUADRANT => ~1)
else
tryID tryID
end end
| LEAF elements => getItemIDVec (itemX, itemY, itemW, itemH, 0, elements) | LEAF elements => getItemIDVec (itemX, itemY, itemW, itemH, 0, elements)