From b7a609b44744ffdf53a13272c6a14f2dc7195501 Mon Sep 17 00:00:00 2001 From: Humza Shahid Date: Mon, 27 Jan 2025 04:52:49 +0000 Subject: [PATCH] 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) --- fcore/enemy-behaviour.sml | 6 +- fcore/physics.sml | 102 +++-- fcore/quad-tree.sml | 863 ++++++++++++++------------------------ 3 files changed, 372 insertions(+), 599 deletions(-) diff --git a/fcore/enemy-behaviour.sml b/fcore/enemy-behaviour.sml index e1c2111..2e07149 100644 --- a/fcore/enemy-behaviour.sml +++ b/fcore/enemy-behaviour.sml @@ -526,14 +526,14 @@ struct #platID enemy else eID in - if eID = #nextPlatID enemy then - getLandingPatches (eID, platforms, enemy, acc) - else if eID = ~1 orelse pID = ~1 then + if eID = ~1 orelse pID = ~1 then (* without checking that neither of these are ~1 * (which means there is no platform below the enemy/player) * there is a subscript error because the PathFinding.start * function expects neither of these values to be ~1. *) getPatrollPatches (enemy, wallTree, platformTree, acc) + else if eID = #nextPlatID enemy then + getLandingPatches (eID, platforms, enemy, acc) else if eID = pID then getPatrollPatches (enemy, wallTree, platformTree, acc) else diff --git a/fcore/physics.sml b/fcore/physics.sml index b1c92ff..5ebf86d 100644 --- a/fcore/physics.sml +++ b/fcore/physics.sml @@ -100,45 +100,68 @@ struct QuadTree.getItemID (x, y, width, height, 0, 0, ww, wh, tree) end - fun getWallPatches (walls: wall vector, lst, acc) = + fun getWallPatches (x, y, walls, wallTree, acc) = 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 + if leftWallID <> ~1 then + let + val {x = wallX, width = wallWidth, ...} = + Vector.sub (walls, leftWallID - 1) + + val newX = wallX + wallWidth + in + Fn.W_X newX :: acc + end + else + acc + end + + (* check collision with wall to the right *) + val acc = + let + val rightWallID = QuadTree.getItemID + (x + size - 1, y, 1, 1, 0, 0, ww, wh, wallTree) + in + if rightWallID <> ~1 then + let + val {x = wallX, ...} = Vector.sub (walls, rightWallID - 1) + + val newX = wallX - size + in + Fn.W_X newX :: acc + end + else + acc + end + + (* check collision with wall below *) + val downWallID = QuadTree.getItemID + (x + moveBy + 1, y + size, 1, 1, 0, 0, ww, wh, wallTree) in - case lst of - (QUERY_ON_LEFT_SIDE, wallID) :: tl => - let - val {x = wallX, width = wallWidth, ...} = - Vector.sub (walls, wallID - 1) + if downWallID <> ~1 then + let + val {y = wallY, ...} = Vector.sub (walls, downWallID - 1) - val newX = wallX + wallWidth - val acc = Fn.W_X newX :: acc - in - getWallPatches (walls, tl, acc) - end - | (QUERY_ON_RIGHT_SIDE, wallID) :: tl => - let - val {x = wallX, width = wallWidth, ...} = - Vector.sub (walls, wallID - 1) - - val newX = wallX - Fn.entitySize - val acc = Fn.W_X newX :: acc - in - getWallPatches (walls, tl, acc) - end - | (QUERY_ON_BOTTOM_SIDE, wallID) :: tl => - let - val {y = wallY, ...} = Vector.sub (walls, wallID - 1) - - val newY = wallY - Fn.entitySize - val acc = Fn.W_Y_AXIS ON_GROUND :: Fn.W_Y newY :: acc - in - getWallPatches (walls, tl, acc) - end - | (QUERY_ON_TOP_SIDE, wallID) :: tl => getWallPatches (walls, tl, acc) - | [] => acc + val newY = wallY - size + in + Fn.W_Y_AXIS ON_GROUND :: Fn.W_Y newY :: acc + end + else + acc end - fun getEnvironmentPatches (input, walls, wallTree, platforms, platformTree) = + fun getEnvironmentPatches + (input, walls: wall vector, wallTree, platforms, platformTree) = let (* react to platform and wall collisions *) val x = Fn.getX input @@ -199,16 +222,11 @@ struct else Fn.W_Y_AXIS FALLING :: acc | _ => acc - val wallCollisions = QuadTree.getCollisionSides - (x, y, size, size, 0, 0, ww, wh, 0, wallTree) - val acc = getWallPatches (walls, wallCollisions, acc) + val acc = getWallPatches (x, y, walls, wallTree, acc) val standPlatID = standingOnAreaID (x, y, platformTree) in - if standPlatID <> ~1 then - Fn.W_PLAT_ID standPlatID :: acc - else - acc + if standPlatID <> ~1 then Fn.W_PLAT_ID standPlatID :: acc else acc end end @@ -261,5 +279,5 @@ structure EnemyPhysics = val W_X = EnemyPatch.W_X val W_Y = EnemyPatch.W_Y val W_Y_AXIS = EnemyPatch.W_Y_AXIS - val W_PLAT_ID = EnemyPatch.W_PLAT_ID + val W_PLAT_ID = EnemyPatch.W_PLAT_ID end) diff --git a/fcore/quad-tree.sml b/fcore/quad-tree.sml index 820d05b..eb8bbd0 100644 --- a/fcore/quad-tree.sml +++ b/fcore/quad-tree.sml @@ -4,10 +4,6 @@ sig val empty: t - val whichQuadrant: int * int * int * int * - int * int * int * int - -> QuadTreeType.quadrant - datatype collision_side = QUERY_ON_LEFT_SIDE | QUERY_ON_TOP_SIDE @@ -50,6 +46,43 @@ struct 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 = { itemID = id , startX = startX @@ -58,6 +91,21 @@ struct , 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 val empty = LEAF (Vector.fromList []) @@ -433,6 +481,19 @@ struct LEAF elements 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) = let val itemEndX = iX + iW @@ -441,8 +502,9 @@ struct val endX = startX + width val endY = startY + height in - iX < endX andalso itemEndX > startX andalso iY < endY - andalso itemEndY > startY andalso itemID <> checkID + isBetween (iX, startX, itemEndX, endX) andalso + isBetween (iY, startY, itemEndY, endY) andalso + itemID <> checkID end fun getCollisionsVec (iX, iY, iW, iH, itemID, pos, elements, acc) = @@ -500,133 +562,53 @@ struct (* get colliding elements in this node first *) val acc = getCollisionsVec (itemX, itemY, itemWidth, itemHeight, itemID, 0, elements, acc) - val halfWidth = quadWidth div 2 - val halfHeight = quadHeight div 2 + + val halfW = quadWidth div 2 + val halfH = quadHeight div 2 + + 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 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 - (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 - ( itemX - , itemY - , itemWidth - , itemHeight - , halfWidth - , halfHeight - , itemID - , acc - , topRight - ) - - val acc = getCollisionsAll - ( itemX - , itemY - , itemWidth - , itemHeight - , halfWidth - , halfHeight - , itemID - , acc - , bottomLeft - ) - in - getCollisionsAll - ( itemX - , itemY - , itemWidth - , itemHeight - , halfWidth - , halfHeight - , itemID - , acc - , bottomRight - ) - end) + acc end | LEAF elements => getCollisionsVec @@ -769,133 +751,53 @@ struct (* get colliding elements in this node first *) val acc = getCollisionSideVec (itemX, itemY, itemWidth, itemHeight, itemID, 0, elements, acc) - val halfWidth = quadWidth div 2 - val halfHeight = quadHeight div 2 + + val halfW = quadWidth div 2 + val halfH = quadHeight div 2 + + 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 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 - (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 - ( itemX - , itemY - , itemWidth - , itemHeight - , halfWidth - , halfHeight - , itemID - , acc - , topRight - ) - - val acc = getCollisionSidesAll - ( itemX - , itemY - , itemWidth - , itemHeight - , halfWidth - , halfHeight - , itemID - , acc - , bottomLeft - ) - in - getCollisionSidesAll - ( itemX - , itemY - , itemWidth - , itemHeight - , halfWidth - , halfHeight - , itemID - , acc - , bottomRight - ) - end) + acc end | LEAF elements => getCollisionSideVec @@ -990,133 +892,53 @@ struct (* get colliding elements in this node first *) val acc = getCollisionsBelowVec (itemX, itemY, itemWidth, itemHeight, itemID, 0, elements, acc) - val halfWidth = quadWidth div 2 - val halfHeight = quadHeight div 2 + + val halfW = quadWidth div 2 + val halfH = quadHeight div 2 + + 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 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 - (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 - ( itemX - , itemY - , itemWidth - , itemHeight - , halfWidth - , halfHeight - , itemID - , acc - , topRight - ) - - val acc = getCollisionsBelowAll - ( itemX - , itemY - , itemWidth - , itemHeight - , halfWidth - , halfHeight - , itemID - , acc - , bottomLeft - ) - in - getCollisionsBelowAll - ( itemX - , itemY - , itemWidth - , itemHeight - , halfWidth - , halfHeight - , itemID - , acc - , bottomRight - ) - end) + acc end | LEAF elements => getCollisionsBelowVec @@ -1155,8 +977,16 @@ struct let val item = Vector.sub (elements, pos) in + if 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 fun hasCollisionAt @@ -1176,95 +1006,54 @@ struct hasCollisionAtVec (itemX, itemY, itemWidth, itemHeight, itemID, 0, elements) orelse - (case - whichQuadrant - ( itemX - , itemY - , itemWidth - , itemHeight - , quadX - , quadY - , quadWidth - , quadHeight - ) - of - TOP_LEFT => - let - val halfWidth = quadWidth div 2 - val halfHeight = quadHeight div 2 - in - hasCollisionAt - ( itemX - , itemY - , itemWidth - , itemHeight - , quadX - , 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 - ( itemX - , itemY - , itemWidth - , itemHeight - , middleX - , 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 - ( itemX - , itemY - , itemWidth - , itemHeight - , quadX - , 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 - ( itemX - , itemY - , itemWidth - , itemHeight - , middleX - , middleY - , halfWidth - , halfHeight - , itemID - , bottomRight - ) - end - | PARENT_QUADRANT => false) + let + val halfW = quadWidth div 2 + val halfH = quadHeight div 2 + + 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 + (iX, iY, iW, iH, qX, qY, halfW, halfH, itemID, topLeft) + else false + + val tr = + if vtr then + hasCollisionAt + (iX, iY, iW, iH, midX, qY, halfW, halfH, itemID, topRight) + else false + + val bl = + if vbl then + hasCollisionAt + (iX, iY, iW, iH, qX, midY, halfW, halfH, itemID, bottomLeft) + else false + + val br = + if vbl then + hasCollisionAt + (iX, iY, iW, iH, midX, midY, halfW, halfH, itemID, bottomRight) + else false + in + tl orelse tr orelse bl orelse br + end | LEAF elements => hasCollisionAtVec (itemX, itemY, itemWidth, itemHeight, itemID, 0, elements) @@ -1285,87 +1074,53 @@ struct NODE {topLeft, topRight, bottomLeft, bottomRight, elements} => let val tryID = getItemIDVec (itemX, itemY, itemW, itemH, 0, elements) + + val halfW = quadW div 2 + val halfH = quadH div 2 + + val midX = halfW + quadX + val midY = halfH + quadY + + val iX = itemX + val iY = itemY + val iW = itemW + 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 + (iX, iY, iW, iH, qX, qY, halfW, halfH, topLeft) + else tryID + + val tryID = + if vtr andalso tryID = ~1 then + getItemID + (iX, iY, iW, iH, midX, qY, halfW, halfH, topRight) + else tryID + + val tryID = + if vbl andalso tryID = ~1 then + getItemID + (iX, iY, iW, iH, qX, midY, halfW, halfH, bottomLeft) + else tryID + + val tryID = + if vbl andalso tryID <> ~1 then + getItemID + (iX, iY, iW, iH, midX, midY, halfW, halfH, bottomRight) + else tryID in - if tryID = ~1 then - (case - whichQuadrant - (itemX, itemY, itemW, itemH, quadX, quadY, quadW, quadH) - of - TOP_LEFT => - let - val halfWidth = quadW div 2 - val halfHeight = quadH div 2 - in - getItemID - ( itemX - , itemY - , itemW - , itemH - , quadX - , quadY - , halfWidth - , halfHeight - , topLeft - ) - end - | TOP_RIGHT => - let - val halfWidth = quadW div 2 - val halfHeight = quadH div 2 - val middleX = quadX + halfWidth - in - getItemID - ( itemX - , itemY - , itemW - , itemH - , middleX - , quadY - , halfWidth - , halfHeight - , topRight - ) - end - | BOTTOM_LEFT => - let - val halfWidth = quadW div 2 - val halfHeight = quadH div 2 - val middleY = quadY + halfHeight - in - getItemID - ( itemX - , itemY - , itemW - , itemH - , quadX - , 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 - ( itemX - , itemY - , itemW - , itemH - , middleX - , middleY - , halfWidth - , halfHeight - , bottomRight - ) - end - | PARENT_QUADRANT => ~1) - else - tryID + tryID end | LEAF elements => getItemIDVec (itemX, itemY, itemW, itemH, 0, elements) end