2024-12-09 00:23:00 +00:00
|
|
|
signature QUAD_TREE =
|
|
|
|
|
sig
|
|
|
|
|
type t
|
|
|
|
|
|
2024-12-15 09:10:19 +00:00
|
|
|
val empty: t
|
|
|
|
|
|
2024-12-09 07:05:21 +00:00
|
|
|
datatype collision_side =
|
|
|
|
|
QUERY_ON_LEFT_SIDE
|
|
|
|
|
| QUERY_ON_TOP_SIDE
|
|
|
|
|
| QUERY_ON_RIGHT_SIDE
|
|
|
|
|
| QUERY_ON_BOTTOM_SIDE
|
|
|
|
|
|
2024-12-17 22:04:46 +00:00
|
|
|
val insert: int * int * int * int *
|
|
|
|
|
int * int * int * int *
|
|
|
|
|
int * t -> t
|
2024-12-09 00:23:00 +00:00
|
|
|
|
2024-12-13 22:48:34 +00:00
|
|
|
val fromItem: int * int * int * int * int -> t
|
2024-12-10 08:42:36 +00:00
|
|
|
|
2024-12-17 22:04:46 +00:00
|
|
|
val getCollisions: int * int * int * int *
|
|
|
|
|
int * int * int * int *
|
|
|
|
|
int * t -> int list
|
2024-12-13 22:48:34 +00:00
|
|
|
|
2025-01-11 13:45:29 +00:00
|
|
|
val helpGetCollisions: int * int * int * int *
|
|
|
|
|
int * int * int * int *
|
|
|
|
|
int * int list * t
|
|
|
|
|
-> int list
|
|
|
|
|
|
2024-12-13 22:48:34 +00:00
|
|
|
val getCollisionSides: int * int * int * int * int * int * int * int * int * t
|
|
|
|
|
-> (collision_side * int) list
|
2024-12-17 22:04:46 +00:00
|
|
|
|
|
|
|
|
val getCollisionsBelow: int * int * int * int * int * int * int * int * int * t
|
|
|
|
|
-> int list
|
2025-01-11 21:35:55 +00:00
|
|
|
|
|
|
|
|
val hasCollisionAt: int * int * int * int *
|
|
|
|
|
int * int * int * int *
|
|
|
|
|
int * t -> bool
|
2025-01-17 21:48:18 +00:00
|
|
|
|
|
|
|
|
val getItemID: int * int * int * int *
|
|
|
|
|
int * int * int * int *
|
|
|
|
|
t -> int
|
2024-12-09 00:23:00 +00:00
|
|
|
end
|
|
|
|
|
|
2024-12-13 22:48:34 +00:00
|
|
|
structure QuadTree: QUAD_TREE =
|
2024-12-07 11:12:19 +00:00
|
|
|
struct
|
2025-01-18 22:54:34 +00:00
|
|
|
open QuadTreeType
|
|
|
|
|
|
|
|
|
|
type item = QuadTreeType.item
|
2024-12-07 11:12:19 +00:00
|
|
|
|
2025-01-27 04:52:49 +00:00
|
|
|
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
|
|
|
|
|
|
2024-12-07 11:12:19 +00:00
|
|
|
fun mkItem (id, startX, startY, width, height) : item =
|
|
|
|
|
{ itemID = id
|
|
|
|
|
, startX = startX
|
|
|
|
|
, startY = startY
|
|
|
|
|
, width = width
|
|
|
|
|
, height = height
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-27 04:52:49 +00:00
|
|
|
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,
|
|
|
|
|
"}"
|
|
|
|
|
]
|
|
|
|
|
|
2025-01-18 22:54:34 +00:00
|
|
|
type t = QuadTreeType.t
|
2024-12-07 11:12:19 +00:00
|
|
|
|
2024-12-15 09:10:19 +00:00
|
|
|
val empty = LEAF (Vector.fromList [])
|
|
|
|
|
|
2024-12-13 22:48:34 +00:00
|
|
|
fun fromItem (itemID, startX, startY, width, height) =
|
|
|
|
|
let
|
|
|
|
|
val item = mkItem (itemID, startX, startY, width, height)
|
|
|
|
|
val elements = Vector.fromList [item]
|
|
|
|
|
in
|
|
|
|
|
LEAF elements
|
|
|
|
|
end
|
|
|
|
|
|
2024-12-07 11:12:19 +00:00
|
|
|
(* max size of vector before we split it further *)
|
2024-12-08 23:38:50 +00:00
|
|
|
val maxSize = 3
|
2024-12-07 11:12:19 +00:00
|
|
|
|
|
|
|
|
fun isItemInQuad (iX, iY, iWidth, iHeight, qX, qY, qWidth, qHeight) =
|
|
|
|
|
iX >= qX andalso iY >= qY andalso iWidth <= qWidth
|
|
|
|
|
andalso iHeight <= qHeight
|
|
|
|
|
|
|
|
|
|
fun whichQuadrant
|
|
|
|
|
(itemX, itemY, itemWidth, itemHeight, quadX, quadY, quadWidth, quadHeight) =
|
|
|
|
|
let
|
|
|
|
|
(* calculate quadrants *)
|
|
|
|
|
val halfWidth = quadWidth div 2
|
|
|
|
|
val halfHeight = quadHeight div 2
|
|
|
|
|
|
|
|
|
|
val middleX = quadX + halfWidth
|
|
|
|
|
val middleY = quadY + halfHeight
|
|
|
|
|
|
|
|
|
|
val isInTopLeft = isItemInQuad
|
2024-12-13 22:48:34 +00:00
|
|
|
( itemX
|
|
|
|
|
, itemY
|
|
|
|
|
, itemWidth
|
|
|
|
|
, itemHeight
|
|
|
|
|
, quadX
|
|
|
|
|
, quadY
|
|
|
|
|
, halfWidth
|
|
|
|
|
, halfHeight
|
2024-12-07 11:12:19 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
val isInTopRight = isItemInQuad
|
2024-12-13 22:48:34 +00:00
|
|
|
( itemX
|
|
|
|
|
, itemY
|
|
|
|
|
, itemWidth
|
|
|
|
|
, itemHeight
|
|
|
|
|
, middleX
|
|
|
|
|
, quadY
|
|
|
|
|
, halfWidth
|
|
|
|
|
, halfHeight
|
2024-12-07 11:12:19 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
val isInBottomLeft = isItemInQuad
|
2024-12-13 22:48:34 +00:00
|
|
|
( itemX
|
|
|
|
|
, itemY
|
|
|
|
|
, itemWidth
|
|
|
|
|
, itemHeight
|
|
|
|
|
, quadX
|
|
|
|
|
, middleY
|
|
|
|
|
, halfWidth
|
|
|
|
|
, halfHeight
|
2024-12-07 11:12:19 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
val isInBottomRight = isItemInQuad
|
2024-12-13 22:48:34 +00:00
|
|
|
( itemX
|
|
|
|
|
, itemY
|
|
|
|
|
, itemWidth
|
|
|
|
|
, itemHeight
|
|
|
|
|
, middleX
|
|
|
|
|
, middleY
|
|
|
|
|
, halfWidth
|
|
|
|
|
, halfHeight
|
2024-12-07 11:12:19 +00:00
|
|
|
)
|
|
|
|
|
in
|
|
|
|
|
if isInTopLeft then TOP_LEFT
|
|
|
|
|
else if isInTopRight then TOP_RIGHT
|
|
|
|
|
else if isInBottomLeft then BOTTOM_LEFT
|
|
|
|
|
else if isInBottomRight then BOTTOM_RIGHT
|
|
|
|
|
else PARENT_QUADRANT
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
fun splitLeaf (qX, qY, qW, qH, tl, tr, bl, br, pe, elements, pos) =
|
|
|
|
|
if pos < 0 then
|
|
|
|
|
let
|
|
|
|
|
val tl = Vector.fromList tl
|
|
|
|
|
val tr = Vector.fromList tr
|
|
|
|
|
val bl = Vector.fromList bl
|
|
|
|
|
val br = Vector.fromList br
|
|
|
|
|
val pe = Vector.fromList pe
|
|
|
|
|
in
|
|
|
|
|
NODE
|
|
|
|
|
{ topLeft = LEAF tl
|
|
|
|
|
, topRight = LEAF tr
|
|
|
|
|
, bottomLeft = LEAF bl
|
|
|
|
|
, bottomRight = LEAF br
|
|
|
|
|
, elements = pe
|
|
|
|
|
}
|
|
|
|
|
end
|
|
|
|
|
else
|
|
|
|
|
let
|
|
|
|
|
val item = Vector.sub (elements, pos)
|
|
|
|
|
val {startX = iX, startY = iY, width = iW, height = iH, ...} = item
|
|
|
|
|
in
|
|
|
|
|
case whichQuadrant (iX, iY, iW, iH, qX, qY, qW, qH) of
|
|
|
|
|
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
|
|
|
|
|
|
|
|
|
|
fun insert
|
2025-01-11 21:35:55 +00:00
|
|
|
( itemX
|
|
|
|
|
, itemY
|
|
|
|
|
, itemWidth
|
|
|
|
|
, itemHeight
|
|
|
|
|
, quadX
|
|
|
|
|
, quadY
|
|
|
|
|
, quadWidth
|
|
|
|
|
, quadHeight
|
|
|
|
|
, itemID
|
|
|
|
|
, tree: t
|
2024-12-07 11:12:19 +00:00
|
|
|
) =
|
|
|
|
|
case tree of
|
|
|
|
|
NODE {topLeft, topRight, bottomLeft, bottomRight, elements} =>
|
|
|
|
|
(* check which quadrant item is in, if any.
|
|
|
|
|
* If in any child quadrants, recurse insertion into there.
|
|
|
|
|
* Else, add to elements vector in current node. *)
|
|
|
|
|
(case
|
|
|
|
|
whichQuadrant
|
2024-12-13 22:48:34 +00:00
|
|
|
( itemX
|
|
|
|
|
, itemY
|
|
|
|
|
, itemWidth
|
|
|
|
|
, itemHeight
|
|
|
|
|
, quadX
|
|
|
|
|
, quadY
|
|
|
|
|
, quadWidth
|
|
|
|
|
, quadHeight
|
2024-12-07 11:12:19 +00:00
|
|
|
)
|
|
|
|
|
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
|
2024-12-13 22:48:34 +00:00
|
|
|
( itemX
|
|
|
|
|
, itemY
|
|
|
|
|
, itemWidth
|
|
|
|
|
, itemHeight
|
|
|
|
|
, quadX
|
|
|
|
|
, quadY
|
|
|
|
|
, halfWidth
|
|
|
|
|
, halfHeight
|
|
|
|
|
, itemID
|
|
|
|
|
, topLeft
|
2024-12-07 11:12:19 +00:00
|
|
|
)
|
|
|
|
|
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
|
2024-12-13 22:48:34 +00:00
|
|
|
( itemX
|
|
|
|
|
, itemY
|
|
|
|
|
, itemWidth
|
|
|
|
|
, itemHeight
|
|
|
|
|
, middleX
|
|
|
|
|
, quadY
|
|
|
|
|
, halfWidth
|
|
|
|
|
, halfHeight
|
|
|
|
|
, itemID
|
|
|
|
|
, topRight
|
2024-12-07 11:12:19 +00:00
|
|
|
)
|
|
|
|
|
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
|
2024-12-13 22:48:34 +00:00
|
|
|
( itemX
|
|
|
|
|
, itemY
|
|
|
|
|
, itemWidth
|
|
|
|
|
, itemHeight
|
|
|
|
|
, quadX
|
|
|
|
|
, middleY
|
|
|
|
|
, halfWidth
|
|
|
|
|
, halfHeight
|
|
|
|
|
, itemID
|
|
|
|
|
, bottomLeft
|
2024-12-07 11:12:19 +00:00
|
|
|
)
|
|
|
|
|
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
|
2024-12-13 22:48:34 +00:00
|
|
|
( itemX
|
|
|
|
|
, itemY
|
|
|
|
|
, itemWidth
|
|
|
|
|
, itemHeight
|
|
|
|
|
, middleX
|
|
|
|
|
, middleY
|
|
|
|
|
, halfWidth
|
|
|
|
|
, halfHeight
|
|
|
|
|
, itemID
|
|
|
|
|
, bottomRight
|
2024-12-07 11:12:19 +00:00
|
|
|
)
|
|
|
|
|
in
|
|
|
|
|
NODE
|
|
|
|
|
{ topLeft = topLeft
|
|
|
|
|
, topRight = topRight
|
|
|
|
|
, bottomLeft = bottomLeft
|
|
|
|
|
, bottomRight = newBottomRight
|
|
|
|
|
, elements = elements
|
|
|
|
|
}
|
|
|
|
|
end
|
|
|
|
|
| PARENT_QUADRANT =>
|
|
|
|
|
(* Does not fit in any of the child quadrants
|
|
|
|
|
* so we must add to the current parent quadrant. *)
|
|
|
|
|
let
|
|
|
|
|
val item = mkItem (itemID, itemX, itemY, itemWidth, itemHeight)
|
|
|
|
|
val elements = Vector.concat [elements, Vector.fromList [item]]
|
|
|
|
|
in
|
|
|
|
|
NODE
|
|
|
|
|
{ topLeft = topLeft
|
|
|
|
|
, topRight = topRight
|
|
|
|
|
, bottomLeft = bottomLeft
|
|
|
|
|
, bottomRight = bottomRight
|
|
|
|
|
, elements = elements
|
|
|
|
|
}
|
|
|
|
|
end)
|
|
|
|
|
| LEAF elements =>
|
|
|
|
|
if Vector.length elements + 1 > maxSize then
|
|
|
|
|
(* have to calculate quadrants and split *)
|
|
|
|
|
let
|
|
|
|
|
val pos = Vector.length elements - 1
|
|
|
|
|
val item = mkItem (itemID, itemX, itemY, itemWidth, itemHeight)
|
|
|
|
|
in
|
|
|
|
|
(case
|
|
|
|
|
whichQuadrant
|
2024-12-13 22:48:34 +00:00
|
|
|
( itemX
|
|
|
|
|
, itemY
|
|
|
|
|
, itemWidth
|
|
|
|
|
, itemHeight
|
|
|
|
|
, quadX
|
|
|
|
|
, quadY
|
|
|
|
|
, quadWidth
|
|
|
|
|
, quadHeight
|
2024-12-07 11:12:19 +00:00
|
|
|
)
|
|
|
|
|
of
|
|
|
|
|
TOP_LEFT =>
|
|
|
|
|
splitLeaf
|
2024-12-13 22:48:34 +00:00
|
|
|
( quadX
|
|
|
|
|
, quadY
|
|
|
|
|
, quadWidth
|
|
|
|
|
, quadHeight
|
|
|
|
|
, [item]
|
|
|
|
|
, []
|
|
|
|
|
, []
|
|
|
|
|
, []
|
|
|
|
|
, []
|
|
|
|
|
, elements
|
|
|
|
|
, pos
|
2024-12-07 11:12:19 +00:00
|
|
|
)
|
|
|
|
|
| TOP_RIGHT =>
|
|
|
|
|
splitLeaf
|
2024-12-13 22:48:34 +00:00
|
|
|
( quadX
|
|
|
|
|
, quadY
|
|
|
|
|
, quadWidth
|
|
|
|
|
, quadHeight
|
|
|
|
|
, []
|
|
|
|
|
, [item]
|
|
|
|
|
, []
|
|
|
|
|
, []
|
|
|
|
|
, []
|
|
|
|
|
, elements
|
|
|
|
|
, pos
|
2024-12-07 11:12:19 +00:00
|
|
|
)
|
|
|
|
|
| BOTTOM_LEFT =>
|
|
|
|
|
splitLeaf
|
2024-12-13 22:48:34 +00:00
|
|
|
( quadX
|
|
|
|
|
, quadY
|
|
|
|
|
, quadWidth
|
|
|
|
|
, quadHeight
|
|
|
|
|
, []
|
|
|
|
|
, []
|
|
|
|
|
, [item]
|
|
|
|
|
, []
|
|
|
|
|
, []
|
|
|
|
|
, elements
|
|
|
|
|
, pos
|
2024-12-07 11:12:19 +00:00
|
|
|
)
|
|
|
|
|
| BOTTOM_RIGHT =>
|
|
|
|
|
splitLeaf
|
2024-12-13 22:48:34 +00:00
|
|
|
( quadX
|
|
|
|
|
, quadY
|
|
|
|
|
, quadWidth
|
|
|
|
|
, quadHeight
|
|
|
|
|
, []
|
|
|
|
|
, []
|
|
|
|
|
, []
|
|
|
|
|
, [item]
|
|
|
|
|
, []
|
|
|
|
|
, elements
|
|
|
|
|
, pos
|
2024-12-07 11:12:19 +00:00
|
|
|
)
|
|
|
|
|
| PARENT_QUADRANT =>
|
|
|
|
|
splitLeaf
|
2024-12-13 22:48:34 +00:00
|
|
|
( quadX
|
|
|
|
|
, quadY
|
|
|
|
|
, quadWidth
|
|
|
|
|
, quadHeight
|
|
|
|
|
, []
|
|
|
|
|
, []
|
|
|
|
|
, []
|
|
|
|
|
, []
|
|
|
|
|
, [item]
|
|
|
|
|
, elements
|
|
|
|
|
, pos
|
2024-12-07 11:12:19 +00:00
|
|
|
))
|
|
|
|
|
end
|
|
|
|
|
else
|
|
|
|
|
(* can insert itemID in elements vector *)
|
|
|
|
|
let
|
|
|
|
|
val item = mkItem (itemID, itemX, itemY, itemWidth, itemHeight)
|
|
|
|
|
val elements = Vector.concat [elements, Vector.fromList [item]]
|
|
|
|
|
in
|
|
|
|
|
LEAF elements
|
|
|
|
|
end
|
2024-12-08 23:38:50 +00:00
|
|
|
|
2025-01-27 04:52:49 +00:00
|
|
|
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)
|
|
|
|
|
|
2024-12-08 23:38:50 +00:00
|
|
|
fun isColliding (iX, iY, iW, iH, itemID, checkWith: item) =
|
|
|
|
|
let
|
|
|
|
|
val itemEndX = iX + iW
|
|
|
|
|
val itemEndY = iY + iH
|
|
|
|
|
val {itemID = checkID, startX, startY, width, height, ...} = checkWith
|
|
|
|
|
val endX = startX + width
|
|
|
|
|
val endY = startY + height
|
|
|
|
|
in
|
2025-01-27 04:52:49 +00:00
|
|
|
isBetween (iX, startX, itemEndX, endX) andalso
|
|
|
|
|
isBetween (iY, startY, itemEndY, endY) andalso
|
|
|
|
|
itemID <> checkID
|
2024-12-08 23:38:50 +00:00
|
|
|
end
|
|
|
|
|
|
2024-12-10 08:42:36 +00:00
|
|
|
fun getCollisionsVec (iX, iY, iW, iH, itemID, pos, elements, acc) =
|
|
|
|
|
if pos = Vector.length elements then
|
|
|
|
|
acc
|
|
|
|
|
else
|
|
|
|
|
let
|
|
|
|
|
val item = Vector.sub (elements, pos)
|
2024-12-13 22:48:34 +00:00
|
|
|
val acc =
|
|
|
|
|
if isColliding (iX, iY, iW, iH, itemID, item) then #itemID item :: acc
|
2024-12-10 08:42:36 +00:00
|
|
|
else acc
|
|
|
|
|
in
|
|
|
|
|
getCollisionsVec (iX, iY, iW, iH, itemID, pos + 1, elements, acc)
|
|
|
|
|
end
|
|
|
|
|
|
2024-12-13 22:48:34 +00:00
|
|
|
fun getCollisionsAll (iX, iY, iW, iH, qW, qH, itemID, acc, tree) =
|
|
|
|
|
case tree of
|
2024-12-10 08:42:36 +00:00
|
|
|
NODE {topLeft, topRight, bottomLeft, bottomRight, elements} =>
|
|
|
|
|
let
|
2024-12-13 22:48:34 +00:00
|
|
|
val acc = getCollisionsVec (iX, iY, iW, iH, itemID, 0, elements, acc)
|
2024-12-10 08:42:36 +00:00
|
|
|
val halfWidth = qW div 2
|
|
|
|
|
val halfHeight = qH div 2
|
|
|
|
|
|
2024-12-13 22:48:34 +00:00
|
|
|
val acc = getCollisionsAll
|
|
|
|
|
(iX, iY, iW, iH, halfWidth, halfHeight, itemID, acc, topLeft)
|
|
|
|
|
|
|
|
|
|
val acc = getCollisionsAll
|
|
|
|
|
(iX, iY, iW, iH, halfWidth, halfHeight, itemID, acc, topRight)
|
|
|
|
|
|
|
|
|
|
val acc = getCollisionsAll
|
|
|
|
|
(iX, iY, iW, iH, halfWidth, halfHeight, itemID, acc, bottomLeft)
|
2024-12-10 08:42:36 +00:00
|
|
|
in
|
|
|
|
|
getCollisionsAll
|
2024-12-13 22:48:34 +00:00
|
|
|
(iX, iY, iW, iH, halfWidth, halfWidth, itemID, acc, bottomRight)
|
2024-12-10 08:42:36 +00:00
|
|
|
end
|
|
|
|
|
| LEAF elements =>
|
|
|
|
|
getCollisionsVec (iX, iY, iW, iH, itemID, 0, elements, acc)
|
|
|
|
|
|
2024-12-13 22:48:34 +00:00
|
|
|
fun helpGetCollisions
|
|
|
|
|
( itemX
|
|
|
|
|
, itemY
|
|
|
|
|
, itemWidth
|
|
|
|
|
, itemHeight
|
|
|
|
|
, quadX
|
|
|
|
|
, quadY
|
|
|
|
|
, quadWidth
|
|
|
|
|
, quadHeight
|
|
|
|
|
, itemID
|
|
|
|
|
, acc
|
|
|
|
|
, tree: t
|
2024-12-10 08:42:36 +00:00
|
|
|
) =
|
|
|
|
|
case tree of
|
|
|
|
|
NODE {topLeft, topRight, bottomLeft, bottomRight, elements} =>
|
|
|
|
|
let
|
|
|
|
|
(* get colliding elements in this node first *)
|
2024-12-13 22:48:34 +00:00
|
|
|
val acc = getCollisionsVec
|
|
|
|
|
(itemX, itemY, itemWidth, itemHeight, itemID, 0, elements, acc)
|
|
|
|
|
|
2025-01-27 04:52:49 +00:00
|
|
|
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
|
|
|
|
|
acc
|
2024-12-10 08:42:36 +00:00
|
|
|
end
|
|
|
|
|
| LEAF elements =>
|
2024-12-13 22:48:34 +00:00
|
|
|
getCollisionsVec
|
|
|
|
|
(itemX, itemY, itemWidth, itemHeight, itemID, 0, elements, acc)
|
|
|
|
|
|
|
|
|
|
fun getCollisions
|
2025-01-11 21:35:55 +00:00
|
|
|
( itemX
|
|
|
|
|
, itemY
|
|
|
|
|
, itemWidth
|
|
|
|
|
, itemHeight
|
|
|
|
|
, quadX
|
|
|
|
|
, quadY
|
|
|
|
|
, quadWidth
|
|
|
|
|
, quadHeight
|
|
|
|
|
, itemID
|
|
|
|
|
, tree
|
2024-12-10 08:42:36 +00:00
|
|
|
) =
|
2024-12-13 22:48:34 +00:00
|
|
|
helpGetCollisions
|
2025-01-11 21:35:55 +00:00
|
|
|
( itemX
|
|
|
|
|
, itemY
|
|
|
|
|
, itemWidth
|
|
|
|
|
, itemHeight
|
|
|
|
|
, quadX
|
|
|
|
|
, quadY
|
|
|
|
|
, quadWidth
|
|
|
|
|
, quadHeight
|
|
|
|
|
, itemID
|
|
|
|
|
, []
|
|
|
|
|
, tree
|
2024-12-10 08:42:36 +00:00
|
|
|
)
|
|
|
|
|
|
2024-12-09 07:05:21 +00:00
|
|
|
(* no variant to represent 'no collision' case
|
|
|
|
|
* because caller should only try getting collision side
|
|
|
|
|
* after checking that there is any collision. *)
|
|
|
|
|
datatype collision_side =
|
|
|
|
|
QUERY_ON_LEFT_SIDE
|
|
|
|
|
| QUERY_ON_TOP_SIDE
|
|
|
|
|
| QUERY_ON_RIGHT_SIDE
|
|
|
|
|
| QUERY_ON_BOTTOM_SIDE
|
|
|
|
|
|
|
|
|
|
(* getCollisionSide function ported from this answer:
|
|
|
|
|
* https://stackoverflow.com/a/56607347
|
|
|
|
|
* *)
|
|
|
|
|
fun getCollisionSide (iX, iY, iW, iH, checkWith: item) =
|
|
|
|
|
let
|
|
|
|
|
val iFinishX = iX + iW
|
|
|
|
|
val iFinishY = iY + iH
|
|
|
|
|
val iHalfW = iW div 2
|
|
|
|
|
val iHalfH = iH div 2
|
|
|
|
|
val iCentreX = iX + iHalfW
|
|
|
|
|
val iCentreY = iY + iHalfH
|
|
|
|
|
|
2024-12-10 08:42:36 +00:00
|
|
|
val {startX = cX, startY = cY, width = cW, height = cH, ...} = checkWith
|
2024-12-09 07:05:21 +00:00
|
|
|
|
|
|
|
|
val cFinishX = cX + cW
|
|
|
|
|
val cFinishY = cY + cH
|
|
|
|
|
val cHalfW = cW div 2
|
|
|
|
|
val cHalfH = cH div 2
|
|
|
|
|
val cCentreX = cX + cHalfW
|
|
|
|
|
val cCentreY = cY + cHalfH
|
|
|
|
|
|
|
|
|
|
val diffX = iCentreX - cCentreX
|
|
|
|
|
val diffY = iCentreY - cCentreY
|
|
|
|
|
|
|
|
|
|
val minXDist = iHalfW + cHalfW
|
|
|
|
|
val minYDist = iHalfH + cHalfH
|
|
|
|
|
|
2024-12-13 22:48:34 +00:00
|
|
|
val depthX = if diffX > 0 then minXDist - diffX else (~minXDist) - diffX
|
2024-12-09 07:05:21 +00:00
|
|
|
|
2024-12-13 22:48:34 +00:00
|
|
|
val depthY = if diffY > 0 then minYDist - diffY else (~minYDist) - diffY
|
2024-12-09 07:05:21 +00:00
|
|
|
in
|
|
|
|
|
if abs depthX < abs depthY then
|
2024-12-13 22:48:34 +00:00
|
|
|
if depthX > 0 then QUERY_ON_LEFT_SIDE else QUERY_ON_RIGHT_SIDE
|
|
|
|
|
else if depthY > 0 then
|
|
|
|
|
QUERY_ON_TOP_SIDE
|
2024-12-09 07:05:21 +00:00
|
|
|
else
|
2024-12-13 22:48:34 +00:00
|
|
|
QUERY_ON_BOTTOM_SIDE
|
2024-12-09 07:05:21 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
|
|
(* like getCollisionsVec, but instead of consing just the itemID,
|
|
|
|
|
* it also conses the "collision-side" information.
|
|
|
|
|
* *)
|
|
|
|
|
fun getCollisionSideVec (iX, iY, iW, iH, itemID, pos, elements, acc) =
|
|
|
|
|
if pos = Vector.length elements then
|
|
|
|
|
acc
|
|
|
|
|
else
|
|
|
|
|
let
|
|
|
|
|
val item = Vector.sub (elements, pos)
|
2024-12-13 22:48:34 +00:00
|
|
|
val acc =
|
|
|
|
|
if isColliding (iX, iY, iW, iH, itemID, item) then
|
|
|
|
|
let val side = getCollisionSide (iX, iY, iW, iH, item)
|
|
|
|
|
in (side, #itemID item) :: acc
|
2024-12-09 07:05:21 +00:00
|
|
|
end
|
2024-12-13 22:48:34 +00:00
|
|
|
else
|
|
|
|
|
acc
|
2024-12-09 07:05:21 +00:00
|
|
|
in
|
2024-12-10 08:42:36 +00:00
|
|
|
getCollisionSideVec (iX, iY, iW, iH, itemID, pos + 1, elements, acc)
|
2024-12-09 07:05:21 +00:00
|
|
|
end
|
|
|
|
|
|
2024-12-13 22:48:34 +00:00
|
|
|
fun getCollisionSidesAll (iX, iY, iW, iH, qW, qH, itemID, acc, tree) =
|
|
|
|
|
case tree of
|
2024-12-08 23:38:50 +00:00
|
|
|
NODE {topLeft, topRight, bottomLeft, bottomRight, elements} =>
|
|
|
|
|
let
|
2024-12-13 22:48:34 +00:00
|
|
|
val acc = getCollisionSideVec
|
|
|
|
|
(iX, iY, iW, iH, itemID, 0, elements, acc)
|
2024-12-08 23:38:50 +00:00
|
|
|
val halfWidth = qW div 2
|
|
|
|
|
val halfHeight = qH div 2
|
|
|
|
|
|
2024-12-13 22:48:34 +00:00
|
|
|
val acc = getCollisionSidesAll
|
|
|
|
|
(iX, iY, iW, iH, halfWidth, halfHeight, itemID, acc, topLeft)
|
|
|
|
|
|
|
|
|
|
val acc = getCollisionSidesAll
|
|
|
|
|
(iX, iY, iW, iH, halfWidth, halfHeight, itemID, acc, topRight)
|
|
|
|
|
|
|
|
|
|
val acc = getCollisionSidesAll
|
|
|
|
|
(iX, iY, iW, iH, halfWidth, halfHeight, itemID, acc, bottomLeft)
|
2024-12-08 23:38:50 +00:00
|
|
|
in
|
2024-12-10 08:42:36 +00:00
|
|
|
getCollisionSidesAll
|
2024-12-13 22:48:34 +00:00
|
|
|
(iX, iY, iW, iH, halfWidth, halfWidth, itemID, acc, bottomRight)
|
2024-12-08 23:38:50 +00:00
|
|
|
end
|
|
|
|
|
| LEAF elements =>
|
2024-12-10 08:42:36 +00:00
|
|
|
getCollisionSideVec (iX, iY, iW, iH, itemID, 0, elements, acc)
|
2024-12-08 23:38:50 +00:00
|
|
|
|
2024-12-10 08:42:36 +00:00
|
|
|
fun helpGetCollisionSides
|
2024-12-13 22:48:34 +00:00
|
|
|
( itemX
|
|
|
|
|
, itemY
|
|
|
|
|
, itemWidth
|
|
|
|
|
, itemHeight
|
|
|
|
|
, quadX
|
|
|
|
|
, quadY
|
|
|
|
|
, quadWidth
|
|
|
|
|
, quadHeight
|
|
|
|
|
, itemID
|
|
|
|
|
, acc
|
|
|
|
|
, tree: t
|
2024-12-08 23:38:50 +00:00
|
|
|
) =
|
|
|
|
|
case tree of
|
|
|
|
|
NODE {topLeft, topRight, bottomLeft, bottomRight, elements} =>
|
|
|
|
|
let
|
|
|
|
|
(* get colliding elements in this node first *)
|
2024-12-13 22:48:34 +00:00
|
|
|
val acc = getCollisionSideVec
|
|
|
|
|
(itemX, itemY, itemWidth, itemHeight, itemID, 0, elements, acc)
|
|
|
|
|
|
2025-01-27 04:52:49 +00:00
|
|
|
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
|
|
|
|
|
acc
|
2024-12-08 23:38:50 +00:00
|
|
|
end
|
|
|
|
|
| LEAF elements =>
|
2024-12-10 08:42:36 +00:00
|
|
|
getCollisionSideVec
|
2024-12-13 22:48:34 +00:00
|
|
|
(itemX, itemY, itemWidth, itemHeight, itemID, 0, elements, acc)
|
2024-12-08 23:38:50 +00:00
|
|
|
|
2024-12-10 08:42:36 +00:00
|
|
|
fun getCollisionSides
|
2025-01-11 21:35:55 +00:00
|
|
|
( itemX
|
|
|
|
|
, itemY
|
|
|
|
|
, itemWidth
|
|
|
|
|
, itemHeight
|
|
|
|
|
, quadX
|
|
|
|
|
, quadY
|
|
|
|
|
, quadWidth
|
|
|
|
|
, quadHeight
|
|
|
|
|
, itemID
|
|
|
|
|
, tree
|
2024-12-09 00:23:00 +00:00
|
|
|
) =
|
2024-12-10 08:42:36 +00:00
|
|
|
helpGetCollisionSides
|
2025-01-11 21:35:55 +00:00
|
|
|
( itemX
|
|
|
|
|
, itemY
|
|
|
|
|
, itemWidth
|
|
|
|
|
, itemHeight
|
|
|
|
|
, quadX
|
|
|
|
|
, quadY
|
|
|
|
|
, quadWidth
|
|
|
|
|
, quadHeight
|
|
|
|
|
, itemID
|
|
|
|
|
, []
|
|
|
|
|
, tree
|
2024-12-17 22:04:46 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
fun getCollisionsBelowVec (iX, iY, iW, iH, itemID, pos, elements, acc) =
|
|
|
|
|
if pos = Vector.length elements then
|
|
|
|
|
acc
|
|
|
|
|
else
|
|
|
|
|
let
|
|
|
|
|
val item = Vector.sub (elements, pos)
|
|
|
|
|
val {itemID = curID, ...} = item
|
|
|
|
|
in
|
|
|
|
|
if isColliding (iX, iY, iW, iH, itemID, item) then
|
|
|
|
|
case getCollisionSide (iX, iY, iW, iH, item) of
|
|
|
|
|
QUERY_ON_BOTTOM_SIDE =>
|
|
|
|
|
getCollisionsBelowVec
|
2025-01-11 21:35:55 +00:00
|
|
|
(iX, iY, iW, iH, itemID, pos + 1, elements, curID :: acc)
|
2024-12-17 22:04:46 +00:00
|
|
|
| _ =>
|
|
|
|
|
getCollisionsBelowVec
|
2025-01-11 21:35:55 +00:00
|
|
|
(iX, iY, iW, iH, itemID, pos + 1, elements, acc)
|
2024-12-17 22:04:46 +00:00
|
|
|
else
|
2025-01-11 21:35:55 +00:00
|
|
|
getCollisionsBelowVec (iX, iY, iW, iH, itemID, pos + 1, elements, acc)
|
2024-12-17 22:04:46 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
|
|
fun getCollisionsBelowAll (iX, iY, iW, iH, qW, qH, itemID, acc, tree) =
|
|
|
|
|
case tree of
|
|
|
|
|
NODE {topLeft, topRight, bottomLeft, bottomRight, elements} =>
|
|
|
|
|
let
|
|
|
|
|
val acc = getCollisionsBelowVec
|
|
|
|
|
(iX, iY, iW, iH, itemID, 0, elements, acc)
|
|
|
|
|
val halfWidth = qW div 2
|
|
|
|
|
val halfHeight = qH div 2
|
|
|
|
|
|
|
|
|
|
val acc = getCollisionsBelowAll
|
|
|
|
|
(iX, iY, iW, iH, halfWidth, halfHeight, itemID, acc, topLeft)
|
|
|
|
|
|
|
|
|
|
val acc = getCollisionsBelowAll
|
|
|
|
|
(iX, iY, iW, iH, halfWidth, halfHeight, itemID, acc, topRight)
|
|
|
|
|
|
|
|
|
|
val acc = getCollisionsBelowAll
|
|
|
|
|
(iX, iY, iW, iH, halfWidth, halfHeight, itemID, acc, bottomLeft)
|
|
|
|
|
in
|
|
|
|
|
getCollisionsBelowAll
|
|
|
|
|
(iX, iY, iW, iH, halfWidth, halfWidth, itemID, acc, bottomRight)
|
|
|
|
|
end
|
|
|
|
|
| LEAF elements =>
|
|
|
|
|
getCollisionsBelowVec (iX, iY, iW, iH, itemID, 0, elements, acc)
|
|
|
|
|
|
|
|
|
|
fun helpGetCollisionsBelow
|
2025-01-11 21:35:55 +00:00
|
|
|
( itemX
|
|
|
|
|
, itemY
|
|
|
|
|
, itemWidth
|
|
|
|
|
, itemHeight
|
|
|
|
|
, quadX
|
|
|
|
|
, quadY
|
|
|
|
|
, quadWidth
|
|
|
|
|
, quadHeight
|
|
|
|
|
, itemID
|
|
|
|
|
, acc
|
|
|
|
|
, tree: t
|
2024-12-17 22:04:46 +00:00
|
|
|
) =
|
|
|
|
|
case tree of
|
|
|
|
|
NODE {topLeft, topRight, bottomLeft, bottomRight, elements} =>
|
|
|
|
|
let
|
|
|
|
|
(* get colliding elements in this node first *)
|
|
|
|
|
val acc = getCollisionsBelowVec
|
|
|
|
|
(itemX, itemY, itemWidth, itemHeight, itemID, 0, elements, acc)
|
|
|
|
|
|
2025-01-27 04:52:49 +00:00
|
|
|
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
|
|
|
|
|
acc
|
2024-12-17 22:04:46 +00:00
|
|
|
end
|
|
|
|
|
| LEAF elements =>
|
|
|
|
|
getCollisionsBelowVec
|
|
|
|
|
(itemX, itemY, itemWidth, itemHeight, itemID, 0, elements, acc)
|
|
|
|
|
|
|
|
|
|
fun getCollisionsBelow
|
2025-01-11 21:35:55 +00:00
|
|
|
( itemX
|
|
|
|
|
, itemY
|
|
|
|
|
, itemWidth
|
|
|
|
|
, itemHeight
|
|
|
|
|
, quadX
|
|
|
|
|
, quadY
|
|
|
|
|
, quadWidth
|
|
|
|
|
, quadHeight
|
|
|
|
|
, itemID
|
|
|
|
|
, tree
|
2024-12-17 22:04:46 +00:00
|
|
|
) =
|
|
|
|
|
helpGetCollisionsBelow
|
2025-01-11 21:35:55 +00:00
|
|
|
( itemX
|
|
|
|
|
, itemY
|
|
|
|
|
, itemWidth
|
|
|
|
|
, itemHeight
|
|
|
|
|
, quadX
|
|
|
|
|
, quadY
|
|
|
|
|
, quadWidth
|
|
|
|
|
, quadHeight
|
|
|
|
|
, itemID
|
|
|
|
|
, []
|
|
|
|
|
, tree
|
2024-12-09 00:23:00 +00:00
|
|
|
)
|
2025-01-11 21:35:55 +00:00
|
|
|
|
|
|
|
|
fun hasCollisionAtVec (iX, iY, iW, iH, itemID, pos, elements) =
|
|
|
|
|
if pos = Vector.length elements then
|
|
|
|
|
false
|
|
|
|
|
else
|
|
|
|
|
let
|
|
|
|
|
val item = Vector.sub (elements, pos)
|
|
|
|
|
in
|
2025-01-27 04:52:49 +00:00
|
|
|
if
|
2025-01-11 21:35:55 +00:00
|
|
|
isColliding (iX, iY, iW, iH, itemID, item)
|
2025-01-27 04:52:49 +00:00
|
|
|
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)
|
2025-01-11 21:35:55 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
|
|
fun hasCollisionAt
|
|
|
|
|
( itemX
|
|
|
|
|
, itemY
|
|
|
|
|
, itemWidth
|
|
|
|
|
, itemHeight
|
|
|
|
|
, quadX
|
|
|
|
|
, quadY
|
|
|
|
|
, quadWidth
|
|
|
|
|
, quadHeight
|
|
|
|
|
, itemID
|
|
|
|
|
, tree
|
|
|
|
|
) =
|
|
|
|
|
case tree of
|
|
|
|
|
NODE {topLeft, topRight, bottomLeft, bottomRight, elements} =>
|
|
|
|
|
hasCollisionAtVec
|
|
|
|
|
(itemX, itemY, itemWidth, itemHeight, itemID, 0, elements)
|
|
|
|
|
orelse
|
2025-01-27 04:52:49 +00:00
|
|
|
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
|
2025-01-11 21:35:55 +00:00
|
|
|
| LEAF elements =>
|
|
|
|
|
hasCollisionAtVec
|
|
|
|
|
(itemX, itemY, itemWidth, itemHeight, itemID, 0, elements)
|
2025-01-17 21:48:18 +00:00
|
|
|
|
|
|
|
|
fun getItemIDVec (iX, iY, iW, iH, pos, elements) =
|
|
|
|
|
if pos = Vector.length elements then
|
|
|
|
|
~1
|
|
|
|
|
else
|
|
|
|
|
let
|
|
|
|
|
val item = Vector.sub (elements, pos)
|
|
|
|
|
in
|
|
|
|
|
if isColliding (iX, iY, iW, iH, ~1, item) then #itemID item
|
|
|
|
|
else getItemIDVec (iX, iY, iW, iH, pos + 1, elements)
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
fun getItemID (itemX, itemY, itemW, itemH, quadX, quadY, quadW, quadH, tree) =
|
|
|
|
|
case tree of
|
|
|
|
|
NODE {topLeft, topRight, bottomLeft, bottomRight, elements} =>
|
|
|
|
|
let
|
|
|
|
|
val tryID = getItemIDVec (itemX, itemY, itemW, itemH, 0, elements)
|
2025-01-27 04:52:49 +00:00
|
|
|
|
|
|
|
|
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
|
2025-01-17 21:48:18 +00:00
|
|
|
in
|
2025-01-27 04:52:49 +00:00
|
|
|
tryID
|
2025-01-17 21:48:18 +00:00
|
|
|
end
|
|
|
|
|
| LEAF elements => getItemIDVec (itemX, itemY, itemW, itemH, 0, elements)
|
2024-12-07 11:12:19 +00:00
|
|
|
end
|