code search function to query quad tree

This commit is contained in:
2025-07-07 23:08:47 +01:00
parent ab9e1e23d0
commit fb2bc76c10
2 changed files with 113 additions and 0 deletions

BIN
dotscape

Binary file not shown.

View File

@@ -244,4 +244,117 @@ struct
Vector.concat vec Vector.concat vec
end end
end end
(* building and querying quad tree, plus compression *)
datatype quad_tree =
LEAF of {x: int, y: int, ex: int, ey: int, data: int}
| NODE of {tl: quad_tree, tr: quad_tree, bl: quad_tree, br: quad_tree}
| EMPTY
fun buildTree (x, y, size, grid) =
if x >= Vector.length grid orelse y >= Vector.length grid then
EMPTY
else if quadHasSameColour (x, y, x + size, y + size, grid) then
let
val yAxis = Vector.sub (grid, x)
val data = Vector.sub (yAxis, y)
in
if data = ignoreData then
EMPTY
else
let
val ex = x + size
val ey = y + size
in
LEAF {x = x, y = y, ex = ex, ey = ey, data = data}
end
end
else
(if size mod 2 = 0 orelse size = 1 then
let
val halfSize = size div 2
val tl = buildTree (x, y, halfSize, grid)
val tr = buildTree (x + halfSize, y, halfSize, grid)
val bl = buildTree (x, y + halfSize, halfSize, grid)
val br = buildTree (x + halfSize, y + halfSize, halfSize, grid)
in
NODE {tl = tl, tr = tr, bl = bl, br = br}
end
else
(* handles odd-number divisions.
* For example, `7 div 2` is 3 because of integer division.
* We would not cover every pixel unless we handle odd numbers specially. *)
let
val halfSizeBefore = size div 2
val halfSizeAfter = (size + 1) div 2
val tl = buildTree (x, y, halfSizeAfter, grid)
val tr = buildTree (x + halfSizeBefore, y, halfSizeAfter, grid)
val bl = buildTree (x, y + halfSizeBefore, halfSizeAfter, grid)
val br =
buildTree
(x + halfSizeBefore, y + halfSizeBefore, halfSizeAfter, grid)
in
NODE {tl = tl, tr = tr, bl = bl, br = br}
end)
fun getItemWithDataAt (x, y, qx, qy, size, tree, data) =
case tree of
EMPTY => NONE
| LEAF (item as {x = ix, y = iy, ex = iex, ey = iey, data = oldData}) =>
if data = oldData then
(* data matches *)
if (x >= ix andalso x <= iex) andalso (y >= iy andalso y <= iey) then
(* search coordinates are in item *)
SOME item
else
NONE
else
NONE
| NODE {tl, tr, bl, br} =>
if size mod 2 = 0 orelse size = 1 then
let
val halfSize = size div 2
val qmx = x + halfSize
val qfx = x + size
val qmy = y + halfSize
val qfy = y + size
in
if y >= qy andalso y <= qmy then
(* top *)
if x >= qx andalso x <= qmx then
(* top left *)
getItemWithDataAt (x, y, qx, qy, halfSize, tl, data)
else
(* top right *)
getItemWithDataAt (x, y, qx + halfSize, qy, halfSize, tr, data)
else (* bottom *) if x >= qx andalso x <= qmx then
(* bottom left *)
getItemWithDataAt (x, y, qx, qy + halfSize, halfSize, bl, data)
else
(* bottom right *)
getItemWithDataAt
(x, y, qx + halfSize, qy + halfSize, halfSize, br, data)
end
else
let
val halfSizeBefore = size div 2
val halfSizeAfter = (size + 1) div 2
val qmx = x + halfSizeBefore
val qmy = y + halfSizeBefore
in
if y >= qy andalso y <= qmy then
(* top *)
if x >= qx andalso x <= qmx then
(* top left *)
getItemWithDataAt (x, y, qx, qy, halfSizeAfter, tl, data)
else
(* top right *)
getItemWithDataAt (x, y, qmx, qy, halfSizeAfter, tr, data)
else (* bottom *) if x >= qx andalso x <= qmx then
(* bottom left *)
getItemWithDataAt (x, y, qx, qmy, halfSizeAfter, bl, data)
else
(* bottom right *)
getItemWithDataAt (x, y, qmx, qmy, halfSizeAfter, br, data)
end
end end