fully restructure quad tree from one that holds overlapping items in parent nodes, into one that holds overlapping items in each quadrant instead

This commit is contained in:
2025-01-27 06:04:52 +00:00
parent b7a609b447
commit 42b42220d0
3 changed files with 286 additions and 369 deletions

View File

@@ -71,12 +71,9 @@ struct
, tree: QuadTreeType.t , tree: QuadTreeType.t
) = ) =
case tree of case tree of
NODE {topLeft, topRight, bottomLeft, bottomRight, elements} => NODE {topLeft, topRight, bottomLeft, bottomRight} =>
let let
(* fold over intersecting elements in this vector first *) (* fold over intersecting elements in this vector first *)
val state = foldVec
(itemX, itemY, itemW, itemH, 0, elements, state, env)
val halfW = quadW div 2 val halfW = quadW div 2
val halfH = quadH div 2 val halfH = quadH div 2

View File

@@ -3,13 +3,7 @@ sig
type item = {itemID: int, startX: int, startY: int, width: int, height: int} type item = {itemID: int, startX: int, startY: int, width: int, height: int}
datatype t = datatype t =
NODE of NODE of {topLeft: t, topRight: t, bottomLeft: t, bottomRight: t}
{ topLeft: t
, topRight: t
, bottomLeft: t
, bottomRight: t
, elements: item vector
}
| LEAF of item vector | LEAF of item vector
datatype quadrant = datatype quadrant =
@@ -25,13 +19,7 @@ struct
type item = {itemID: int, startX: int, startY: int, width: int, height: int} type item = {itemID: int, startX: int, startY: int, width: int, height: int}
datatype t = datatype t =
NODE of NODE of {topLeft: t, topRight: t, bottomLeft: t, bottomRight: t}
{ topLeft: t
, topRight: t
, bottomLeft: t
, bottomRight: t
, elements: item vector
}
| LEAF of item vector | LEAF of item vector
datatype quadrant = datatype quadrant =

View File

@@ -92,19 +92,19 @@ struct
} }
fun itemToString {itemID, startX, startY, width, height} = fun itemToString {itemID, startX, startY, width, height} =
String.concat [ String.concat
"{itemID = ", [ "{itemID = "
Int.toString itemID, , Int.toString itemID
", startX = ", , ", startX = "
Int.toString startX, , Int.toString startX
", startY = ", , ", startY = "
Int.toString startY, , Int.toString startY
", width = ", , ", width = "
Int.toString width, , Int.toString width
", height = ", , ", height = "
Int.toString height, , Int.toString height
"}" , "}"
] ]
type t = QuadTreeType.t type t = QuadTreeType.t
@@ -186,44 +186,40 @@ struct
else PARENT_QUADRANT else PARENT_QUADRANT
end end
fun splitLeaf (qX, qY, qW, qH, tl, tr, bl, br, pe, elements, pos) = fun splitLeaf (qX, qY, qW, qH, tl, tr, bl, br, elements, pos) =
if pos < 0 then if pos < 0 then
let let
val tl = Vector.fromList tl val tl = Vector.fromList tl
val tr = Vector.fromList tr val tr = Vector.fromList tr
val bl = Vector.fromList bl val bl = Vector.fromList bl
val br = Vector.fromList br val br = Vector.fromList br
val pe = Vector.fromList pe
in in
NODE NODE
{ topLeft = LEAF tl { topLeft = LEAF tl
, topRight = LEAF tr , topRight = LEAF tr
, bottomLeft = LEAF bl , bottomLeft = LEAF bl
, bottomRight = LEAF br , bottomRight = LEAF br
, elements = pe
} }
end end
else else
let let
val item = Vector.sub (elements, pos) val item = Vector.sub (elements, pos)
val {startX = iX, startY = iY, width = iW, height = iH, ...} = item val {startX = iX, startY = iY, width = iW, height = iH, ...} = item
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 item :: tl else tl
val tr = if vtr then item :: tr else tr
val bl = if vbl then item :: bl else bl
val br = if vbr then item :: br else br
in in
case whichQuadrant (iX, iY, iW, iH, qX, qY, qW, qH) of splitLeaf (qX, qY, qW, qH, tl, tr, bl, br, elements, pos - 1)
TOP_LEFT =>
splitLeaf
(qX, qY, qW, qH, item :: tl, tr, bl, br, pe, elements, pos - 1)
| TOP_RIGHT =>
splitLeaf
(qX, qY, qW, qH, tl, item :: tr, bl, br, pe, elements, pos - 1)
| BOTTOM_LEFT =>
splitLeaf
(qX, qY, qW, qH, tl, tr, item :: bl, br, pe, elements, pos - 1)
| BOTTOM_RIGHT =>
splitLeaf
(qX, qY, qW, qH, tl, tr, bl, item :: br, pe, elements, pos - 1)
| PARENT_QUADRANT =>
splitLeaf
(qX, qY, qW, qH, tl, tr, bl, br, item :: pe, elements, pos - 1)
end end
fun insert fun insert
@@ -239,238 +235,110 @@ struct
, tree: t , tree: t
) = ) =
case tree of case tree of
NODE {topLeft, topRight, bottomLeft, bottomRight, elements} => NODE {topLeft, topRight, bottomLeft, bottomRight} =>
(* check which quadrant item is in, if any. let
* If in any child quadrants, recurse insertion into there. val halfW = quadWidth div 2
* Else, add to elements vector in current node. *) val halfH = quadHeight div 2
(case
whichQuadrant
( itemX
, itemY
, itemWidth
, itemHeight
, quadX
, quadY
, quadWidth
, quadHeight
)
of
TOP_LEFT =>
let
(* I know I am repeating myself by recalculating
* halfWidth/halfHeight in case branches but I prefer this
* over increating the indentation level further
* *)
val halfWidth = quadWidth div 2
val halfHeight = quadHeight div 2
val newTopLeft = insert val midX = halfW + quadX
( itemX val midY = halfH + quadY
, itemY
, itemWidth
, itemHeight
, quadX
, quadY
, halfWidth
, halfHeight
, itemID
, topLeft
)
in
NODE
{ topLeft = newTopLeft
, topRight = topRight
, bottomLeft = bottomLeft
, bottomRight = bottomRight
, elements = elements
}
end
| TOP_RIGHT =>
let
val halfWidth = quadWidth div 2
val halfHeight = quadHeight div 2
val middleX = quadX + halfWidth
val newTopRight = insert val iX = itemX
( itemX val iY = itemY
, itemY val iW = itemWidth
, itemWidth val iH = itemHeight
, itemHeight
, middleX
, quadY
, halfWidth
, halfHeight
, itemID
, topRight
)
in
NODE
{ topLeft = topLeft
, topRight = newTopRight
, bottomLeft = bottomLeft
, bottomRight = bottomRight
, elements = elements
}
end
| BOTTOM_LEFT =>
let
val halfWidth = quadWidth div 2
val halfHeight = quadHeight div 2
val middleY = quadY + halfHeight
val newBottomLeft = insert val qX = quadX
( itemX val qY = quadY
, itemY val qW = quadWidth
, itemWidth val qH = quadHeight
, itemHeight
, quadX
, middleY
, halfWidth
, halfHeight
, itemID
, bottomLeft
)
in
NODE
{ topLeft = topLeft
, topRight = topRight
, bottomLeft = newBottomLeft
, bottomRight = bottomRight
, elements = elements
}
end
| BOTTOM_RIGHT =>
let
val halfWidth = quadWidth div 2
val halfHeight = quadHeight div 2
val middleX = quadX + halfWidth
val middleY = quadY + halfHeight
val newBottomRight = insert val vtl = visitTopLeft (iX, iY, iW, iH, qX, qY, qW, qH)
( itemX val vtr = visitTopRight (iX, iY, iW, iH, qX, qY, qW, qH)
, itemY val vbl = visitBottomLeft (iX, iY, iW, iH, qX, qY, qW, qH)
, itemWidth val vbr = visitBottomRight (iX, iY, iW, iH, qX, qY, qW, qH)
, itemHeight
, middleX val tl =
, middleY if vtl then
, halfWidth insert (iX, iY, iW, iH, qX, qY, halfW, halfH, itemID, topLeft)
, halfHeight else
, itemID topLeft
, bottomRight
) val tr =
in if vtr then
NODE insert (iX, iY, iW, iH, midX, qY, halfW, halfH, itemID, topRight)
{ topLeft = topLeft else
, topRight = topRight topRight
, bottomLeft = bottomLeft
, bottomRight = newBottomRight val bl =
, elements = elements if vbl then
} insert
end (iX, iY, iW, iH, qX, midY, halfW, halfH, itemID, bottomLeft)
| PARENT_QUADRANT => else
(* Does not fit in any of the child quadrants bottomLeft
* so we must add to the current parent quadrant. *)
let val br =
val item = mkItem (itemID, itemX, itemY, itemWidth, itemHeight) if vbr then
val elements = Vector.concat [elements, Vector.fromList [item]] insert
in (iX, iY, iW, iH, midX, midY, halfW, halfH, itemID, bottomRight)
NODE else
{ topLeft = topLeft bottomRight
, topRight = topRight in
, bottomLeft = bottomLeft NODE {topLeft = tl, topRight = tr, bottomLeft = bl, bottomRight = br}
, bottomRight = bottomRight end
, elements = elements
}
end)
| LEAF elements => | LEAF elements =>
if Vector.length elements + 1 > maxSize then if Vector.length elements + 1 > maxSize then
(* have to calculate quadrants and split *) (* have to calculate quadrants and split *)
let let
val pos = Vector.length elements - 1 val pos = Vector.length elements - 1
val item = mkItem (itemID, itemX, itemY, itemWidth, itemHeight) val item = mkItem (itemID, itemX, itemY, itemWidth, itemHeight)
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 pos = Vector.length elements - 1
val item = mkItem (itemID, itemX, itemY, itemWidth, itemHeight)
val tl = if vtl then [item] else []
val tr = if vtr then [item] else []
val bl = if vbl then [item] else []
val br = if vbr then [item] else []
val pe = []
in in
(case splitLeaf
whichQuadrant ( quadX
( itemX , quadY
, itemY , quadWidth
, itemWidth , quadHeight
, itemHeight , tl
, quadX , tr
, quadY , bl
, quadWidth , br
, quadHeight , elements
) , pos
of )
TOP_LEFT =>
splitLeaf
( quadX
, quadY
, quadWidth
, quadHeight
, [item]
, []
, []
, []
, []
, elements
, pos
)
| TOP_RIGHT =>
splitLeaf
( quadX
, quadY
, quadWidth
, quadHeight
, []
, [item]
, []
, []
, []
, elements
, pos
)
| BOTTOM_LEFT =>
splitLeaf
( quadX
, quadY
, quadWidth
, quadHeight
, []
, []
, [item]
, []
, []
, elements
, pos
)
| BOTTOM_RIGHT =>
splitLeaf
( quadX
, quadY
, quadWidth
, quadHeight
, []
, []
, []
, [item]
, []
, elements
, pos
)
| PARENT_QUADRANT =>
splitLeaf
( quadX
, quadY
, quadWidth
, quadHeight
, []
, []
, []
, []
, [item]
, elements
, pos
))
end end
else else
(* can insert itemID in elements vector *) (* can insert itemID in elements vector *)
@@ -502,9 +370,8 @@ struct
val endX = startX + width val endX = startX + width
val endY = startY + height val endY = startY + height
in in
isBetween (iX, startX, itemEndX, endX) andalso isBetween (iX, startX, itemEndX, endX)
isBetween (iY, startY, itemEndY, endY) andalso andalso isBetween (iY, startY, itemEndY, endY) andalso itemID <> checkID
itemID <> checkID
end end
fun getCollisionsVec (iX, iY, iW, iH, itemID, pos, elements, acc) = fun getCollisionsVec (iX, iY, iW, iH, itemID, pos, elements, acc) =
@@ -522,9 +389,8 @@ struct
fun getCollisionsAll (iX, iY, iW, iH, qW, qH, itemID, acc, tree) = fun getCollisionsAll (iX, iY, iW, iH, qW, qH, itemID, acc, tree) =
case tree of case tree of
NODE {topLeft, topRight, bottomLeft, bottomRight, elements} => NODE {topLeft, topRight, bottomLeft, bottomRight} =>
let let
val acc = getCollisionsVec (iX, iY, iW, iH, itemID, 0, elements, acc)
val halfWidth = qW div 2 val halfWidth = qW div 2
val halfHeight = qH div 2 val halfHeight = qH div 2
@@ -557,12 +423,8 @@ struct
, tree: t , tree: t
) = ) =
case tree of case tree of
NODE {topLeft, topRight, bottomLeft, bottomRight, elements} => NODE {topLeft, topRight, bottomLeft, bottomRight} =>
let let
(* get colliding elements in this node first *)
val acc = getCollisionsVec
(itemX, itemY, itemWidth, itemHeight, itemID, 0, elements, acc)
val halfW = quadWidth div 2 val halfW = quadWidth div 2
val halfH = quadHeight div 2 val halfH = quadHeight div 2
@@ -584,29 +446,55 @@ struct
val vbl = visitBottomLeft (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 vbr = visitBottomRight (iX, iY, iW, iH, qX, qY, qW, qH)
val acc = val acc =
if vtl then if vtl then
helpGetCollisions helpGetCollisions
(iX, iY, iW, iH, qX, qY, halfW, halfH, itemID, acc, topLeft) (iX, iY, iW, iH, qX, qY, halfW, halfH, itemID, acc, topLeft)
else acc else
acc
val acc = val acc =
if vtr then if vtr then
helpGetCollisions helpGetCollisions
(iX, iY, iW, iH, midX, qY, halfW, halfH, itemID, acc, topRight) (iX, iY, iW, iH, midX, qY, halfW, halfH, itemID, acc, topRight)
else acc else
acc
val acc = val acc =
if vbl then if vbl then
helpGetCollisions helpGetCollisions
(iX, iY, iW, iH, qX, midY, halfW, halfH, itemID, acc, bottomLeft) ( iX
else acc , iY
, iW
, iH
, qX
, midY
, halfW
, halfH
, itemID
, acc
, bottomLeft
)
else
acc
val acc = val acc =
if vbl then if vbl then
helpGetCollisions helpGetCollisions
(iX, iY, iW, iH, midX, midY, halfW, halfH, itemID, acc, bottomRight) ( iX
else acc , iY
, iW
, iH
, midX
, midY
, halfW
, halfH
, itemID
, acc
, bottomRight
)
else
acc
in in
acc acc
end end
@@ -710,10 +598,8 @@ struct
fun getCollisionSidesAll (iX, iY, iW, iH, qW, qH, itemID, acc, tree) = fun getCollisionSidesAll (iX, iY, iW, iH, qW, qH, itemID, acc, tree) =
case tree of case tree of
NODE {topLeft, topRight, bottomLeft, bottomRight, elements} => NODE {topLeft, topRight, bottomLeft, bottomRight} =>
let let
val acc = getCollisionSideVec
(iX, iY, iW, iH, itemID, 0, elements, acc)
val halfWidth = qW div 2 val halfWidth = qW div 2
val halfHeight = qH div 2 val halfHeight = qH div 2
@@ -746,12 +632,8 @@ struct
, tree: t , tree: t
) = ) =
case tree of case tree of
NODE {topLeft, topRight, bottomLeft, bottomRight, elements} => NODE {topLeft, topRight, bottomLeft, bottomRight} =>
let let
(* get colliding elements in this node first *)
val acc = getCollisionSideVec
(itemX, itemY, itemWidth, itemHeight, itemID, 0, elements, acc)
val halfW = quadWidth div 2 val halfW = quadWidth div 2
val halfH = quadHeight div 2 val halfH = quadHeight div 2
@@ -773,29 +655,55 @@ struct
val vbl = visitBottomLeft (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 vbr = visitBottomRight (iX, iY, iW, iH, qX, qY, qW, qH)
val acc = val acc =
if vtl then if vtl then
helpGetCollisionSides helpGetCollisionSides
(iX, iY, iW, iH, qX, qY, halfW, halfH, itemID, acc, topLeft) (iX, iY, iW, iH, qX, qY, halfW, halfH, itemID, acc, topLeft)
else acc else
acc
val acc = val acc =
if vtr then if vtr then
helpGetCollisionSides helpGetCollisionSides
(iX, iY, iW, iH, midX, qY, halfW, halfH, itemID, acc, topRight) (iX, iY, iW, iH, midX, qY, halfW, halfH, itemID, acc, topRight)
else acc else
acc
val acc = val acc =
if vbl then if vbl then
helpGetCollisionSides helpGetCollisionSides
(iX, iY, iW, iH, qX, midY, halfW, halfH, itemID, acc, bottomLeft) ( iX
else acc , iY
, iW
, iH
, qX
, midY
, halfW
, halfH
, itemID
, acc
, bottomLeft
)
else
acc
val acc = val acc =
if vbl then if vbl then
helpGetCollisionSides helpGetCollisionSides
(iX, iY, iW, iH, midX, midY, halfW, halfH, itemID, acc, bottomRight) ( iX
else acc , iY
, iW
, iH
, midX
, midY
, halfW
, halfH
, itemID
, acc
, bottomRight
)
else
acc
in in
acc acc
end end
@@ -851,10 +759,8 @@ struct
fun getCollisionsBelowAll (iX, iY, iW, iH, qW, qH, itemID, acc, tree) = fun getCollisionsBelowAll (iX, iY, iW, iH, qW, qH, itemID, acc, tree) =
case tree of case tree of
NODE {topLeft, topRight, bottomLeft, bottomRight, elements} => NODE {topLeft, topRight, bottomLeft, bottomRight} =>
let let
val acc = getCollisionsBelowVec
(iX, iY, iW, iH, itemID, 0, elements, acc)
val halfWidth = qW div 2 val halfWidth = qW div 2
val halfHeight = qH div 2 val halfHeight = qH div 2
@@ -887,12 +793,8 @@ struct
, tree: t , tree: t
) = ) =
case tree of case tree of
NODE {topLeft, topRight, bottomLeft, bottomRight, elements} => NODE {topLeft, topRight, bottomLeft, bottomRight} =>
let let
(* get colliding elements in this node first *)
val acc = getCollisionsBelowVec
(itemX, itemY, itemWidth, itemHeight, itemID, 0, elements, acc)
val halfW = quadWidth div 2 val halfW = quadWidth div 2
val halfH = quadHeight div 2 val halfH = quadHeight div 2
@@ -914,29 +816,55 @@ struct
val vbl = visitBottomLeft (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 vbr = visitBottomRight (iX, iY, iW, iH, qX, qY, qW, qH)
val acc = val acc =
if vtl then if vtl then
helpGetCollisionsBelow helpGetCollisionsBelow
(iX, iY, iW, iH, qX, qY, halfW, halfH, itemID, acc, topLeft) (iX, iY, iW, iH, qX, qY, halfW, halfH, itemID, acc, topLeft)
else acc else
acc
val acc = val acc =
if vtr then if vtr then
helpGetCollisionsBelow helpGetCollisionsBelow
(iX, iY, iW, iH, midX, qY, halfW, halfH, itemID, acc, topRight) (iX, iY, iW, iH, midX, qY, halfW, halfH, itemID, acc, topRight)
else acc else
acc
val acc = val acc =
if vbl then if vbl then
helpGetCollisionsBelow helpGetCollisionsBelow
(iX, iY, iW, iH, qX, midY, halfW, halfH, itemID, acc, bottomLeft) ( iX
else acc , iY
, iW
, iH
, qX
, midY
, halfW
, halfH
, itemID
, acc
, bottomLeft
)
else
acc
val acc = val acc =
if vbl then if vbl then
helpGetCollisionsBelow helpGetCollisionsBelow
(iX, iY, iW, iH, midX, midY, halfW, halfH, itemID, acc, bottomRight) ( iX
else acc , iY
, iW
, iH
, midX
, midY
, halfW
, halfH
, itemID
, acc
, bottomRight
)
else
acc
in in
acc acc
end end
@@ -977,16 +905,15 @@ struct
let let
val item = Vector.sub (elements, pos) val item = Vector.sub (elements, pos)
in in
if if isColliding (iX, iY, iW, iH, itemID, item) then
isColliding (iX, iY, iW, iH, itemID, item) let
then val _ = print
let val _ = print ("quad-tree.sml: has collision: \n" ^ itemToString ("quad-tree.sml: has collision: \n" ^ itemToString item ^ "\n")
item ^ "\n")
in in
true true
end end
else else
hasCollisionAtVec (iX, iY, iW, iH, itemID, pos + 1, elements) hasCollisionAtVec (iX, iY, iW, iH, itemID, pos + 1, elements)
end end
fun hasCollisionAt fun hasCollisionAt
@@ -1002,10 +929,7 @@ struct
, tree , tree
) = ) =
case tree of case tree of
NODE {topLeft, topRight, bottomLeft, bottomRight, elements} => NODE {topLeft, topRight, bottomLeft, bottomRight} =>
hasCollisionAtVec
(itemX, itemY, itemWidth, itemHeight, itemID, 0, elements)
orelse
let let
val halfW = quadWidth div 2 val halfW = quadWidth div 2
val halfH = quadHeight div 2 val halfH = quadHeight div 2
@@ -1028,29 +952,33 @@ struct
val vbl = visitBottomLeft (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 vbr = visitBottomRight (iX, iY, iW, iH, qX, qY, qW, qH)
val tl = val tl =
if vtl then if vtl then
hasCollisionAt hasCollisionAt
(iX, iY, iW, iH, qX, qY, halfW, halfH, itemID, topLeft) (iX, iY, iW, iH, qX, qY, halfW, halfH, itemID, topLeft)
else false else
false
val tr = val tr =
if vtr then if vtr then
hasCollisionAt hasCollisionAt
(iX, iY, iW, iH, midX, qY, halfW, halfH, itemID, topRight) (iX, iY, iW, iH, midX, qY, halfW, halfH, itemID, topRight)
else false else
false
val bl = val bl =
if vbl then if vbl then
hasCollisionAt hasCollisionAt
(iX, iY, iW, iH, qX, midY, halfW, halfH, itemID, bottomLeft) (iX, iY, iW, iH, qX, midY, halfW, halfH, itemID, bottomLeft)
else false else
false
val br = val br =
if vbl then if vbl then
hasCollisionAt hasCollisionAt
(iX, iY, iW, iH, midX, midY, halfW, halfH, itemID, bottomRight) (iX, iY, iW, iH, midX, midY, halfW, halfH, itemID, bottomRight)
else false else
false
in in
tl orelse tr orelse bl orelse br tl orelse tr orelse bl orelse br
end end
@@ -1071,10 +999,8 @@ struct
fun getItemID (itemX, itemY, itemW, itemH, quadX, quadY, quadW, quadH, tree) = fun getItemID (itemX, itemY, itemW, itemH, quadX, quadY, quadW, quadH, tree) =
case tree of case tree of
NODE {topLeft, topRight, bottomLeft, bottomRight, elements} => NODE {topLeft, topRight, bottomLeft, bottomRight} =>
let let
val tryID = getItemIDVec (itemX, itemY, itemW, itemH, 0, elements)
val halfW = quadW div 2 val halfW = quadW div 2
val halfH = quadH div 2 val halfH = quadH div 2
@@ -1096,31 +1022,37 @@ struct
val vbl = visitBottomLeft (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 vbr = visitBottomRight (iX, iY, iW, iH, qX, qY, qW, qH)
val tryID = val try1 =
if vtl andalso tryID = ~1 then if vtl then
getItemID getItemID (iX, iY, iW, iH, qX, qY, halfW, halfH, topLeft)
(iX, iY, iW, iH, qX, qY, halfW, halfH, topLeft) else
else tryID ~1
val tryID = val try2 =
if vtr andalso tryID = ~1 then if vtr then
getItemID getItemID (iX, iY, iW, iH, midX, qY, halfW, halfH, topRight)
(iX, iY, iW, iH, midX, qY, halfW, halfH, topRight) else
else tryID ~1
val tryID = val try3 =
if vbl andalso tryID = ~1 then if vbl then
getItemID getItemID (iX, iY, iW, iH, qX, midY, halfW, halfH, bottomLeft)
(iX, iY, iW, iH, qX, midY, halfW, halfH, bottomLeft) else
else tryID ~1
val tryID = val try4 =
if vbl andalso tryID <> ~1 then if vbl then
getItemID getItemID (iX, iY, iW, iH, midX, midY, halfW, halfH, bottomRight)
(iX, iY, iW, iH, midX, midY, halfW, halfH, bottomRight) else
else tryID ~1
(* get max: we assume query was narrow enough
* that only one ID is valid *)
val a = Int.max (try1, try2)
val a = Int.max (a, try3)
val a = Int.max (a, try4)
in in
tryID a
end end
| LEAF elements => getItemIDVec (itemX, itemY, itemW, itemH, 0, elements) | LEAF elements => getItemIDVec (itemX, itemY, itemW, itemH, 0, elements)
end end