Skip to content

Commit

Permalink
sync
Browse files Browse the repository at this point in the history
  • Loading branch information
stefanmaierhofer committed Feb 7, 2024
1 parent 4bb2b43 commit bae6779
Show file tree
Hide file tree
Showing 5 changed files with 205 additions and 23 deletions.
111 changes: 108 additions & 3 deletions src/Aardvark.Geometry.Quadtree/Builder.fs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ module Builder =

let private debugOutput =
#if DEBUG
true
false
#else
false
#endif
Expand Down Expand Up @@ -86,7 +86,7 @@ module Builder =

else

let bbQuadrants = rootCell.Children |> Array.map (fun subCell -> subCell.GetBoundsForExponent(sampleExponent))
//let bbQuadrants = rootCell.Children |> Array.map (fun subCell -> subCell.GetBoundsForExponent(sampleExponent))

let patchesPerQuadrant =
rootCell.Children
Expand Down Expand Up @@ -116,6 +116,106 @@ module Builder =
let result = { Id = Guid.NewGuid(); ExactBoundingBox = ebb; Cell = rootCell; SplitLimitExponent = BuildConfig.Default.SplitLimitPowerOfTwo; HasMask = hasMask; SubNodes = subNodes }
result |> InMemoryInner

let rec private build'' (minSampleExponent : int) (rootCell : Cell2d) (patches : LayerSet[]) =

if debugOutput then
printfn "[DEBUG] build' rootCell = %A, %d patches" rootCell patches.Length

for p in patches do
invariantm (p.SampleExponent >= minSampleExponent)
(fun () -> sprintf "Patch sample exponent %d is smaller than specified minimum sample exponent %d." p.SampleExponent minSampleExponent)
"28d1fdd1-2da6-4329-a065-c134c1351ffc"

match patches.Length with

| 0 -> NoNode

| 1 ->

let theSinglePatch = patches[0]

if debugOutput then
printfn "[DEBUG] SINGLE patch (%A)" theSinglePatch.SampleWindow

Quadtree.Build BuildConfig.Default theSinglePatch.Layers

| n -> // n patches

let ebb = patches |> Seq.map (fun patch -> patch.BoundingBox) |> Box2d

let rootBounds = getBoundsForExponent minSampleExponent rootCell
if rootBounds.Size.X <= 256 && rootBounds.Size.Y <= 256 then

let bbWindow = patches |> Seq.map (fun patch -> patch.SampleWindow) |> Box2l

if debugOutput then
printfn "[DEBUG] MERGE %d patches; %A" n (bbWindow - rootBounds.Min)

//if debugOutput then
// for patch in patches do
// printfn "[DEBUG] %A (exact %A)" (patch.SampleWindow - rootBounds.Min) (bbWindow - rootBounds.Min)

// adjust root cell for split limit
let requiredRootCellSplitLimit = minSampleExponent + BuildConfig.Default.SplitLimitPowerOfTwo

let mutable rootCell = rootCell

if requiredRootCellSplitLimit <> rootCell.Exponent then

invariantm (rootCell.Exponent < requiredRootCellSplitLimit)
(fun () -> sprintf "Expected root cell exponent %d to be smaller than requiredRootCellSplitLimit %d." rootCell.Exponent requiredRootCellSplitLimit)
"4911adf3-7b87-4234-9bcc-bc3076df846e"

if debugOutput then
printfn "[DEBUG] must adjust root cell %A exponent to %d" rootCell requiredRootCellSplitLimit

while rootCell.Exponent < requiredRootCellSplitLimit do rootCell <- rootCell.Parent

if debugOutput then
printfn "[DEBUG] adjusted root cell is %A" rootCell

let merged = LayerSet.Merge patches
let qnode = QNode(Guid.NewGuid(), ebb, rootCell, BuildConfig.Default.SplitLimitPowerOfTwo, merged)

if debugOutput then
printfn "[DEBUG] CREATED QNode with split limit = %d" qnode.SplitLimitExponent

//let xs = qnode |> InMemoryNode |> Query.All Query.Config.Default |> Seq.map (fun x -> x.GetSamples<V4f>(Defs.HeightsBilinear4f)) |> Array.ofSeq |> Array.collect id
//for x in xs do printfn "%A" x
qnode |> InMemoryNode

else

//let bbQuadrants = rootCell.Children |> Array.map (fun subCell -> subCell.GetBoundsForExponent(sampleExponent))

let patchesPerQuadrant =
rootCell.Children
|> Array.map (fun subCell ->
let bbQuadrant = subCell.GetBoundsForExponent(minSampleExponent)
let subPatches = patches |> Array.choose (fun b -> b.WithWindow bbQuadrant)
(subCell, subPatches)
)


if debugOutput then
printfn "[DEBUG] SPLIT %d patches" n

//for i in 0..3 do
// let (subCell, subPatches) = patchesPerQuadrant[i]
// printfn "%A%A[%d] size = %A, %d patches" rootCell ebb i bbWindow.Size subPatches.Length

let subNodes = patchesPerQuadrant |> Array.map (fun (subCell, subPatches) ->
match subPatches.Length with
| 0 -> NoNode
| _ -> build'' minSampleExponent subCell subPatches
)

let hasMask = subNodes |> Array.exists (fun n -> n.HasMask)
if debugOutput && hasMask then
printfn "[DEBUG] has mask %A" rootCell
let result = { Id = Guid.NewGuid(); ExactBoundingBox = ebb; Cell = rootCell; SplitLimitExponent = BuildConfig.Default.SplitLimitPowerOfTwo; HasMask = hasMask; SubNodes = subNodes }
result |> InMemoryInner

/// Creates a quadtree from many small patches.
let Build (patches : LayerSet seq) : QNodeRef =
let patches = patches |> Array.ofSeq
Expand Down Expand Up @@ -188,6 +288,8 @@ type Builder () =

/// Build a quadtree from all the patches that have been added to this builder.
member this.Build () : QNodeRef option =

let mutable mergesCount = 0

patches
// (1) sort per-resolution patch lists from coarse to fine resolution ...
Expand All @@ -198,7 +300,10 @@ type Builder () =
|> Seq.fold (fun state item ->
match state with
| None -> Some item
| Some state -> Quadtree.Merge Dominance.SecondDominates state item |> Some
| Some state ->
mergesCount <- mergesCount + 1
printfn "[Builder.Build()] mergesCount -> %d" mergesCount
Quadtree.Merge Dominance.SecondDominates state item |> Some
)
None // initial state

Expand Down
23 changes: 18 additions & 5 deletions src/Aardvark.Geometry.Quadtree/Layer.fs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ open Aardvark.Data
open System
open System.Collections.Immutable
open System.Collections.Generic
open System.Diagnostics

#nowarn "44"

Expand Down Expand Up @@ -134,20 +135,29 @@ type Layer<'a when 'a : equality>(def : Durable.Def, data : 'a[], mapping : Data
| Fail ->
if inside () then
let i = mapping.GetBufferIndex s
data.[i]
match mask with
| None -> data[i]
| Some mask -> if mask[i] = 1uy then data[i] else failwith "Error 79671ba5-c509-4edd-ac4b-0f8d7b5e7222."

else
failwith <| sprintf "Position %A outside of available data [%A-%A]." s this.SampleMin this.SampleMaxIncl

| ClampToBorder value ->
if inside () then
let i = mapping.GetBufferIndex s
data.[i]
match mask with
| None -> data[i]
| Some mask -> if mask[i] = 1uy then data[i] else failwith "Error 6befcffd-3f31-465b-b37a-43137339b6f8."
else
value

| ClampToEdge ->
let x = if s.X < min.X then min.X elif s.X > maxIncl.X then maxIncl.X else s.X
let y = if s.Y < min.Y then min.Y elif s.Y > maxIncl.Y then maxIncl.Y else s.Y
let i = mapping.GetBufferIndex(x, y)
data.[i]
match mask with
| None -> data[i]
| Some mask -> if mask[i] = 1uy then data[i] else failwith "Error 472e5d8b-aa34-4ad9-a973-75d652a57f18."

member this.GetSample (mode : BorderMode<'a>, globalPos : V2d) : 'a =
let s = mapping.GetSampleCell globalPos
Expand Down Expand Up @@ -300,8 +310,6 @@ module Layer =
let i = finalMapping.GetBufferIndex c
let v = layer.GetSample(Fail, c)

//finalData.[i] <- v

match finalMask[i] with
| 255uy ->
finalData[i] <- v
Expand Down Expand Up @@ -342,6 +350,11 @@ module Layer =
printfn "[DEBUG][Layer.mergeTyped] debugCountOccupied.Count = %d / %d ... %5.2f" coundOccupiedSamples finalMask.Length (float coundOccupiedSamples / float finalMask.Length)

// rewrite mask (1 ... occupied, 0 ... undefined)

let countOccupied = finalMask |> Array.filter (fun x -> x <> 255uy) |> Array.length
let countUndefined = finalMask |> Array.filter (fun x -> x = 255uy) |> Array.length
printfn "[OCCUPANCY][e = %d][%A][%A] countOccupied = %d, countUndefined = %d" e finalWindow finalWindow.Size countOccupied countUndefined

for i = 0 to finalMask.Length-1 do
finalMask[i] <- if finalMask[i] = 255uy then 0uy else 1uy

Expand Down
3 changes: 3 additions & 0 deletions src/Aardvark.Geometry.Quadtree/Node.fs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ and QNode(uid : Guid, exactBoundingBox : Box2d, cell : Cell2d, splitLimitExp : i
new (exactBoundingBox : Box2d, cell : Cell2d, splitLimitExp : int, layers : LayerSet) =
QNode(Guid.NewGuid(), exactBoundingBox, cell, splitLimitExp, layers)

new (splitLimitExp : int, layers : LayerSet) =
QNode(Guid.NewGuid(), layers.BoundingBox, layers.BoundingBox |> Cell2d, splitLimitExp, layers)

member _.Id with get() = uid

member _.Cell with get() = cell
Expand Down
34 changes: 21 additions & 13 deletions src/Aardvark.Geometry.Quadtree/Query.fs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ open Aardvark.Base
open Aardvark.Data
open System
open System.Collections.Generic
open System.Threading
open System.Diagnostics

module Query =
Expand Down Expand Up @@ -77,7 +76,7 @@ module Query =
let mergeDominatingT1 = Stopwatch()

/// xs dominate always
let private mergeDominating (config : Config) (xs : Result list) (ys : Result list) (isSampleInside : Cell2d -> bool) : Result seq =
let private mergeDominatingPerSample (config : Config) (xs : Result list) (ys : Result list) (isSampleInside : Cell2d -> bool) : Result seq =

if config.Verbose then
printfn "[mergeDominating] xs:"
Expand All @@ -93,7 +92,7 @@ module Query =
let yebb = y.Node.ExactBoundingBox
xs |> Array.filter(fun x -> x.Node.ExactBoundingBox.Intersects(yebb))

seq {
let resultSeq = seq {

mergeDominatingT0.Start();

Expand All @@ -115,11 +114,17 @@ module Query =
let mutable result = List<Cell2d>(8192)

// all dominating sample cells intersecting dominated result
let zcs = zs |> Array.collect(fun z -> z.GetSampleCells() |> Array.filter(fun zc -> zc.BoundingBox.Intersects(yebb))) |> Array.map(fun c -> c.BoundingBox)
let zcs0 = zs |> Array.collect(fun z -> z.GetSampleCells())
let zcs1 = zcs0 |> Seq.filter(fun zc -> zc.BoundingBox.Intersects(yebb)) |> Seq.toList
let zcs = zcs1 |> Seq.map(fun c -> c.BoundingBox) |> Seq.toList |> List.toArray

// all sample cells of dominated result
let ycs = y.GetSampleCells ()

let mutable i = 0
for yc in ycs do
i <- i + 1
//printfn "[resolve dominate results] %d/%d" i ycs.Length
let inline isDominatedCellYcFullyCovered (bb : Box2d) =
zcs |> Array.exists(fun zc -> zc.Contains(bb))
let inline isDominatedCellYcInterferedWith (bb : Box2d) =
Expand Down Expand Up @@ -170,15 +175,18 @@ module Query =
mergeDominatingT0.Stop()
}

let private merge (config : Config) (dom : Dominance) (xs : Result list) (ys : Result list) (isSampleInside : Cell2d -> bool) : Result list =
let result = resultSeq |> Seq.toArray
result

let private mergePerSample (config : Config) (dom : Dominance) (xs : Result list) (ys : Result list) (isSampleInside : Cell2d -> bool) : Result list =
match xs |> Seq.isEmpty, ys |> Seq.isEmpty with
// both sequences contain values
| false, false ->
match dom with
| FirstDominates
| MoreDetailedOrFirst -> mergeDominating config xs ys isSampleInside |> Seq.toList
| MoreDetailedOrFirst -> mergeDominatingPerSample config xs ys isSampleInside |> Seq.toList
| SecondDominates
| MoreDetailedOrSecond -> mergeDominating config ys xs isSampleInside |> Seq.toList
| MoreDetailedOrSecond -> mergeDominatingPerSample config ys xs isSampleInside |> Seq.toList
// xs contains values, ys is empty -> no need to merge, just return xs
| false, true -> xs
// xs is empty -> no need to merge, just return ys
Expand All @@ -204,8 +212,8 @@ module Query =
let xs = generic a |> Seq.toList
let ys = generic b |> Seq.toList
//printf "merge first (%d) + second (%d) %A ... " xs.Length ys.Length a.Cell
let r = merge config dom xs ys isSampleInside
let foo = r |> List.collect (fun x -> x.GetSampleCells() |> Array.toList)
let r = mergePerSample config dom xs ys isSampleInside
//let foo = r |> List.collect (fun x -> x.GetSampleCells() |> Array.toList)
//printfn "done %d" (r |> List.sumBy (fun x -> x.GetSampleCells().Length))
r

Expand Down Expand Up @@ -394,8 +402,8 @@ module Query =
let result = { Node = n; Selection = FullySelected }
if config.Verbose then
printfn "[Generic ] fully inside (%A)" root.Cell
printfn "[Generic ] YIELD %A" result
for c in result.GetSampleCells() do printfn "[Generic ] Y %A" c
printfn "[Generic ] YIELD %A" result.Node.Cell
//for c in result.GetSampleCells() do printfn "[Generic ] Ya %A" c
yield result
else
// partially inside
Expand All @@ -405,8 +413,8 @@ module Query =
if xs.Length > 0 then
let result = { Node = n; Selection = CellsSelected xs }
if config.Verbose then
printfn "[Generic ] YIELD %A" result
for c in result.GetSampleCells() do printfn "[Generic ] Y %A" c
printfn "[Generic ] YIELD %A" result.Node.Cell
//for c in result.GetSampleCells() do printfn "[Generic ] Yb %A" c
yield result

}
Expand Down
57 changes: 55 additions & 2 deletions src/Scratch/Program.fs
Original file line number Diff line number Diff line change
Expand Up @@ -1276,7 +1276,7 @@ let builderTest_20240112 () =

let buildSerializationTest_20240202 () =

let path = Path.GetFullPath("c:/tmp/20240202_quadtreetest")
let path = Path.GetFullPath(@"c:\tmp\20240202_quadtreetest")

printfn "path = %s" path

Expand Down Expand Up @@ -1307,10 +1307,63 @@ let buildSerializationTest_20240202 () =

()

let cp_20240202_quadtreetest () =

let path = Path.GetFullPath(@"W:\Datasets\Vgm\Quadtree\20240202_quadtreetest")

printfn "path = %s" path

let options = SerializationOptions.NewInMemoryStore(verbose = false)

let idFile = Guid(File.ReadAllText(@"W:\Datasets\Vgm\Quadtree\20240202_quadtreetest\builder.20240202122614.638424735748032405.key.txt"))
let builderReloadedFile = Builder.Import(path, idFile)
match builderReloadedFile with
| None -> printfn "reloaded from file = None"
| Some x ->
printfn "reloaded from file, %d patches" (x.GetPatches() |> Seq.length)

let samplesCount =
x.GetPatches()
|> Seq.filter(fun patch -> patch.SampleExponent = -3)
|> Seq.sumBy(fun patch -> patch.SampleWindow.Area)
printfn("total samples count with e = -3: %d") samplesCount

match x.Build () with
| None -> failwith ""
| Some qtree ->
let makeReturnValOfQueryResults (resultChunk : seq<Query.Result>) (def : Aardvark.Data.Durable.Def) =

let samples =
resultChunk
|> Seq.collect (fun chunk -> chunk.GetSamples<V4f> def)
//|> Seq.map (fun (cell,bilParamV) -> let bilParam = BilinearSurfaceParams.FromV4f bilParamV
// (bilParam, cell))
|> Seq.toList

//posAndParams |> Seq.filter (fun pos -> (fst pos).b0.IsNaN() |> not)
// |> Seq.map (fun pos -> { originalCell = snd pos; surface = fst pos} )

//let mutable i = 0
//for s in samples do
// i <- i + 1
// printfn "%A" s

samples

let config = Query.Config.Default //{ Query.Config.Default with Verbose = true }
let resultCells = qtree |> Query.All config |> Seq.toArray
let samples = makeReturnValOfQueryResults resultCells Defs.HeightsBilinear4f

()

()

[<EntryPoint>]
let main argv =

buildSerializationTest_20240202 ()
cp_20240202_quadtreetest ()

//buildSerializationTest_20240202 ()

//builderTest_20240112 ()

Expand Down

0 comments on commit bae6779

Please sign in to comment.