diff --git a/src/Aardvark.Geometry.Quadtree.Tests/StructureTests.fs b/src/Aardvark.Geometry.Quadtree.Tests/StructureTests.fs
index 9f803b0..ff66bd1 100644
--- a/src/Aardvark.Geometry.Quadtree.Tests/StructureTests.fs
+++ b/src/Aardvark.Geometry.Quadtree.Tests/StructureTests.fs
@@ -31,7 +31,7 @@ module StructureTests =
Split : int
}
- let createQuadtreeTyped<'a> def spec =
+ let createQuadtreeTyped<'a when 'a : equality> def spec =
let (w, h) = spec.Size
let mapping = DataMapping(spec.Origin, V2i(w,h))
let layer = Layer<'a>(def, spec.Data, mapping)
diff --git a/src/Aardvark.Geometry.Quadtree.sln b/src/Aardvark.Geometry.Quadtree.sln
index f390d64..67b086f 100644
--- a/src/Aardvark.Geometry.Quadtree.sln
+++ b/src/Aardvark.Geometry.Quadtree.sln
@@ -14,10 +14,14 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "_", "_", "{CBD0D4B2-E888-4C
..\build.cmd = ..\build.cmd
..\build.sh = ..\build.sh
..\LICENSE = ..\LICENSE
+ ..\.github\workflows\linux.yml = ..\.github\workflows\linux.yml
+ ..\.github\workflows\mac.yml = ..\.github\workflows\mac.yml
..\paket.dependencies = ..\paket.dependencies
..\paket.lock = ..\paket.lock
+ ..\.github\workflows\publish.yml = ..\.github\workflows\publish.yml
..\README.md = ..\README.md
..\RELEASE_NOTES.md = ..\RELEASE_NOTES.md
+ ..\.github\workflows\windows.yml = ..\.github\workflows\windows.yml
EndProjectSection
EndProject
Global
@@ -43,7 +47,7 @@ Global
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
- SolutionGuid = {E996B5E6-49B2-4479-9DDE-455A40509F43}
EnterpriseLibraryConfigurationToolBinariesPathV6 = packages\EnterpriseLibrary.TransientFaultHandling.6.0.1304.0\lib\portable-net45+win+wp8;packages\EnterpriseLibrary.TransientFaultHandling.Data.6.0.1304.1\lib\NET45
+ SolutionGuid = {E996B5E6-49B2-4479-9DDE-455A40509F43}
EndGlobalSection
EndGlobal
diff --git a/src/Aardvark.Geometry.Quadtree/Aardvark.Geometry.Quadtree.fsproj b/src/Aardvark.Geometry.Quadtree/Aardvark.Geometry.Quadtree.fsproj
index c9782d0..7887276 100644
--- a/src/Aardvark.Geometry.Quadtree/Aardvark.Geometry.Quadtree.fsproj
+++ b/src/Aardvark.Geometry.Quadtree/Aardvark.Geometry.Quadtree.fsproj
@@ -23,6 +23,7 @@
+
diff --git a/src/Aardvark.Geometry.Quadtree/Builder.fs b/src/Aardvark.Geometry.Quadtree/Builder.fs
new file mode 100644
index 0000000..e074649
--- /dev/null
+++ b/src/Aardvark.Geometry.Quadtree/Builder.fs
@@ -0,0 +1,144 @@
+namespace Aardvark.Geometry.Quadtree
+
+open Aardvark.Base
+open System
+open System.Collections.Generic
+
+module Builder =
+
+ let private debugOutput = false
+
+ let rec private build' (sampleExponent : int) (rootCell : Cell2d) (patches : LayerSet[]) =
+
+ if debugOutput then
+ printfn "[DEBUG] build' rootCell = %A, %d patches" rootCell patches.Length
+
+ 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 sampleExponent 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)
+
+ let merged = LayerSet.Merge patches
+ let qnode = QNode(Guid.NewGuid(), ebb, rootCell, BuildConfig.Default.SplitLimitPowerOfTwo, merged)
+ let xs = qnode |> InMemoryNode |> Query.All Query.Config.Default |> Seq.map (fun x -> x.GetSamples(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(sampleExponent)
+ 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' sampleExponent subCell subPatches
+ )
+
+ let result = { Id = Guid.NewGuid(); ExactBoundingBox = ebb; Cell = rootCell; SplitLimitExponent = BuildConfig.Default.SplitLimitPowerOfTwo; SubNodes = subNodes }
+ result |> InMemoryInner
+
+ /// Creates a quadtree from many small patches.
+ let Build (patches : LayerSet seq) : QNodeRef =
+ let patches = patches |> Array.ofSeq
+ let rootCell = patches |> Array.map (fun patch -> patch.BoundingBox) |> Box2d |> Cell2d
+ let sampleExponent = (patches |> Array.distinctBy (fun x -> x.SampleExponent) |> Array.exactlyOne).SampleExponent
+ build' sampleExponent rootCell patches
+
+
+/// Creates a quadtree from many small patches.
+type Builder () =
+
+ let l = obj()
+ let patches = Dictionary>()
+ let mutable isEmpty = true
+ let mutable layerCount = 0
+
+ /// Add patch.
+ member this.Add (patch : LayerSet) : unit = lock l (fun () ->
+
+ if isEmpty then
+ layerCount <- patch.Layers.Length
+ isEmpty <- true
+
+ invariantm
+ (patch.Layers.Length = layerCount)
+ (fun()->sprintf "Expected %d layers, but patch has %d. layers" layerCount patch.Layers.Length)
+ "e76e1577-4963-441c-884c-dc32da0b3b15"
+
+ // get or create patch list for patch's resolution (a.k.a. sample exponent)
+ let list =
+ match patches.TryGetValue(patch.SampleExponent) with
+ | (true, xs) -> xs
+ | (false, _) -> let xs = List()
+ patches[patch.SampleExponent] <- xs
+ xs
+ // add patch to list
+ list.Add(patch)
+ )
+
+ /// Add patch.
+ member this.Add (patch : ILayer) : unit =
+ this.Add(LayerSet([| patch |]))
+
+ /// Add patch.
+ member this.Add (patch : QNode) : unit =
+ this.Add(patch.LayerSet)
+
+ /// Build a quadtree from all the patches that have been added to this builder.
+ member this.Build () : QNodeRef option =
+
+ patches
+ // (1) sort per-resolution patch lists from coarse to fine resolution ...
+ |> Seq.sortByDescending (fun kv -> kv.Key) |> Seq.map (fun kv -> kv.Value)
+ // (2) create a quadtree for each resolution ...
+ |> Seq.map Builder.Build
+ // (3) merge quadtrees with finer resolution always dominating ...
+ |> Seq.fold (fun state item ->
+ match state with
+ | None -> Some item
+ | Some state -> Quadtree.Merge Dominance.SecondDominates state item |> Some
+ )
+ None // initial state
+
+
\ No newline at end of file
diff --git a/src/Aardvark.Geometry.Quadtree/Defs.fs b/src/Aardvark.Geometry.Quadtree/Defs.fs
index 82ed9ec..ffcde3a 100644
--- a/src/Aardvark.Geometry.Quadtree/Defs.fs
+++ b/src/Aardvark.Geometry.Quadtree/Defs.fs
@@ -111,6 +111,8 @@ module Defs =
let VolumesBilinear4d = def "9aadc102-68b7-4e6f-ba22-bad1440e1bcf" "Quadtree.VolumesBilinear4d" "Quadtree. Volume value (height difference) per sample as bilinear params. volume(x,y) = A + B*x + C*y+ D*x*y, where x,y in range [-sample.Size/2, +sample.Size/2], (x=0,y=0) corresponds to center of sample (A), and A=v.X, B=v.Y, C=v.Z, D=v.W. V4d[]." Durable.Aardvark.V4dArray
let VolumesBilinear4dLayer = def "fd547ab1-88e9-4fc2-9c7d-a67545bfd3d1" "Quadtree.VolumesBilinear4d.Layer" "Quadtree. VolumesBilinearParams4d layer. DurableMapAligned16." Durable.Primitives.DurableMapAligned16
+ let Mask1b = def "6f33738c-eddc-411e-932f-326249d95f46" "Aardvark.Geometry.Quadtree.ByteMask" "UInt8[]." Durable.Primitives.UInt8Array
+
let private def2layer = Map.ofList [
(Heights1f , Heights1fLayer )
(HeightsBilinear4f , HeightsBilinear4fLayer )
diff --git a/src/Aardvark.Geometry.Quadtree/Layer.fs b/src/Aardvark.Geometry.Quadtree/Layer.fs
index 50e79a7..6a20875 100644
--- a/src/Aardvark.Geometry.Quadtree/Layer.fs
+++ b/src/Aardvark.Geometry.Quadtree/Layer.fs
@@ -14,10 +14,9 @@ type ILayer =
abstract member WithWindow : Box2l -> ILayer option
abstract member MapSingleCenteredSampleTo : Cell2d -> ILayer
abstract member WithSemantic : Durable.Def -> ILayer
- //abstract member ResampleUntyped : Cell2d -> ILayer
- //abstract member SupersampleUntyped : unit -> ILayer
abstract member Materialize : unit -> ILayer
abstract member ToDurableMap : unit -> seq>
+ abstract member Mask : byte[] option
[]
module ILayerExtensions =
@@ -45,55 +44,73 @@ module ILayerExtensions =
let w = this.SampleWindow
Box2l(w.Min * 2L, w.Max * 2L)
-type Layer<'a>(def : Durable.Def, data : 'a[], mapping : DataMapping) =
+type Layer<'a when 'a : equality>(def : Durable.Def, data : 'a[], mapping : DataMapping, mask : byte[] option) =
do
invariantm (data.Length >= mapping.WindowSize.X * mapping.WindowSize.Y)
(fun()->sprintf "Mapping window %A exceeds available data (length=%d)." mapping.Window data.Length)
"971a69a6-cd25-43b8-b85b-7dd783456552"
+ new(def : Durable.Def, data : 'a[], mapping : DataMapping) = Layer<'a>(def, data, mapping, None)
+
interface ILayer with
+ member this.Mask with get() = mask
+
member this.Def with get() = def
member this.Mapping with get() = mapping
member this.WithWindow (w : Box2l) =
mapping.WithWindow(w)
- |> Option.map (fun m -> Layer(def, data, m) :> ILayer)
+ |> Option.map (fun m -> Layer(def, data, m, mask) :> ILayer)
member this.MapSingleCenteredSampleTo (c : Cell2d) =
invariant (mapping.BufferOrigin.IsCenteredAtOrigin) "1a276e80-0404-4e69-9777-acbac1a4ed6a"
invariant (c.TouchesOrigin) "e2326309-7171-4b9b-841e-4f0a5ef028d7"
invariant (data.Length = 1) "bf2b4330-67fd-4283-880f-f9c96dafee61"
- Layer(def, data, DataMapping(c, V2i.II)) :> ILayer
+ Layer(def, data, DataMapping(c, V2i.II), mask) :> ILayer
member this.WithSemantic (newSemantic : Durable.Def) =
- Layer(newSemantic, data, mapping) :> ILayer
+ Layer(newSemantic, data, mapping, mask) :> ILayer
member this.Materialize () =
if mapping.Window.Min = V2l.OO && mapping.WindowSize = mapping.BufferSize then
this :> ILayer
else
let size = V2i(mapping.WindowSize)
- let newdata = Array.zeroCreate<'a> (int mapping.Window.Area)
+ let newArrayLength = int mapping.Window.Area
+ let newdata = Array.zeroCreate<'a> newArrayLength
let mutable i = 0
for y = 0 to size.Y - 1 do
for x = 0 to size.X - 1 do
let c = Cell2d(mapping.Window.Min.X + int64 x, mapping.Window.Min.Y + int64 y, mapping.BufferOrigin.Exponent)
let s = this.GetSample(Fail, c)
- newdata.[i] <- s
+ newdata[i] <- s
i <- i + 1
+ let newmask =
+ match mask with
+ | None -> None
+ | Some mask ->
+ let mutable i = 0
+ let newmask = Array.zeroCreate newArrayLength
+ for y = 0 to size.Y - 1 do
+ for x = 0 to size.X - 1 do
+ newmask[i] <- mask[mapping.GetBufferIndex(x, y)]
+ i <- i + 1
+ Some newmask
+
let m = DataMapping(Cell2d(mapping.Window.Min, mapping.BufferOrigin.Exponent), size)
- Layer<'a>(def, newdata, m) :> ILayer
+ Layer<'a>(def, newdata, m, newmask) :> ILayer
member this.ToDurableMap () = seq {
- kvp Defs.Layer.DefId def.Id
- kvp Defs.Layer.BufferOrigin mapping.BufferOrigin
- kvp Defs.Layer.BufferSize mapping.BufferSize
- kvp Defs.Layer.Window mapping.Window
- kvp def data
+ yield kvp Defs.Layer.DefId def.Id
+ yield kvp Defs.Layer.BufferOrigin mapping.BufferOrigin
+ yield kvp Defs.Layer.BufferSize mapping.BufferSize
+ yield kvp Defs.Layer.Window mapping.Window
+ yield kvp def data
+ match mask with | Some x ->yield kvp Defs.Mask1b x | None -> ()
}
member this.Def with get() = def
@@ -110,9 +127,6 @@ type Layer<'a>(def : Durable.Def, data : 'a[], mapping : DataMapping) =
if c.Exponent > min.Exponent then failwith "Invariant 4270bb56-29a0-4267-82d3-aacffd7c5e88."
let mutable s = c
while s.Exponent < min.Exponent do s <- s.Parent
- //let s = if c.Exponent = min.Exponent then c
- // elif c.Exponent + 1 = min.Exponent then c.Parent
- // else failwith "Invariant 4d59a076-37ee-42d4-8326-2341be922a6c."
let inline inside () = s.X >= min.X && s.Y >= min.Y && s.X <= maxIncl.X && s.Y <= maxIncl.Y
@@ -144,37 +158,8 @@ module Layer =
let private verbose = false
type private M = ImmutableDictionary
- let private foo = Map.ofList [
- (Defs.Heights1d, fun (map : M) -> map.[Defs.Heights1d])
- ]
-
- let Deserialize (buffer : byte[]) : ILayer =
- let struct (def, o) = DurableCodec.Deserialize(buffer)
- let map = o :?> ImmutableDictionary
- let mapping = DataMapping(
- map.[Defs.Layer.BufferOrigin] :?> Cell2d,
- map.[Defs.Layer.BufferSize] :?> V2i,
- map.[Defs.Layer.Window] :?> Box2l
- )
- let data = map |> foo.[def]
- match data with
- | :? (int[]) -> Layer(def, data :?> int[], mapping) :> ILayer
- | :? (int64[]) -> Layer(def, data :?> int64[], mapping) :> ILayer
- | :? (float[]) -> Layer(def, data :?> float[], mapping) :> ILayer
- | :? (float32[]) -> Layer(def, data :?> float32[], mapping) :> ILayer
- | :? (V2f[]) -> Layer(def, data :?> V2f[], mapping) :> ILayer
- | :? (V2d[]) -> Layer(def, data :?> V2d[], mapping) :> ILayer
- | :? (V3f[]) -> Layer(def, data :?> V3f[], mapping) :> ILayer
- | :? (V3d[]) -> Layer(def, data :?> V3d[], mapping) :> ILayer
- | :? (V4f[]) -> Layer(def, data :?> V4f[], mapping) :> ILayer
- | :? (V4d[]) -> Layer(def, data :?> V4d[], mapping) :> ILayer
- | :? (C3b[]) -> Layer(def, data :?> C3b[], mapping) :> ILayer
- | :? (C4b[]) -> Layer(def, data :?> C4b[], mapping) :> ILayer
- | :? (C3f[]) -> Layer(def, data :?> C3f[], mapping) :> ILayer
- | :? (C4f[]) -> Layer(def, data :?> C4f[], mapping) :> ILayer
- | _ -> failwith <| sprintf "Unknown type %A. Invariant 4e797062-04a2-445f-9725-79f66823aff8." (data.GetType())
- let defineBuilder<'a> def = (def, fun mapping (data : obj) -> Layer<'a>(def, data :?> 'a[], mapping) :> ILayer)
+ let defineBuilder<'a when 'a : equality> def = (def, fun mapping (data : obj) mask -> Layer<'a>(def, data :?> 'a[], mapping, mask) :> ILayer)
let private builders = Map.ofList [
defineBuilder Defs.Heights1f
defineBuilder Defs.Heights1d
@@ -214,10 +199,55 @@ module Layer =
map.[Defs.Layer.Window] :?> Box2l
)
+ let mask =
+ match map.TryGetValue(Defs.Mask1b) with
+ | (false, _) -> None
+ | (true, :? (byte[])) as (_, x) -> Some (x :?> byte[])
+ | _ -> failwith "Internal error 30ae3cd8-c06a-4698-9db3-a6ef69706e6a."
+
match builders |> Map.tryFind def with
- | Some builder -> builder mapping (map.[def])
+ | Some builder -> builder mapping (map.[def]) mask
| None -> sprintf "Unknown layer type %A. 8c90faa2-de10-4938-b8ee-3034bd9bdea0." def |> failwith
+ let Deserialize (buffer : byte[]) : ILayer =
+
+ let foo = Map.ofList [
+ (Defs.Heights1d, fun (map : M) -> map.[Defs.Heights1d])
+ ]
+
+ let struct (def, o) = DurableCodec.Deserialize(buffer)
+ let map = o :?> ImmutableDictionary
+ let mapping = DataMapping(
+ map.[Defs.Layer.BufferOrigin] :?> Cell2d,
+ map.[Defs.Layer.BufferSize] :?> V2i,
+ map.[Defs.Layer.Window] :?> Box2l
+ )
+
+ let mask =
+ match map.TryGetValue(Defs.Mask1b) with
+ | (false, _) -> None
+ | (true, :? (byte[])) as (_, x) -> Some (x :?> byte[])
+ | _ -> failwith "Internal error 0be664f2-2bb5-4023-8821-7bfd371d1ac6."
+
+ let data = map |> foo.[def]
+ match data with
+ | :? (int[]) -> Layer (def, data :?> int[] , mapping, mask) :> ILayer
+ | :? (int64[]) -> Layer (def, data :?> int64[] , mapping, mask) :> ILayer
+ | :? (float[]) -> Layer (def, data :?> float[] , mapping, mask) :> ILayer
+ | :? (float32[]) -> Layer(def, data :?> float32[], mapping, mask) :> ILayer
+ | :? (V2f[]) -> Layer (def, data :?> V2f[] , mapping, mask) :> ILayer
+ | :? (V2d[]) -> Layer (def, data :?> V2d[] , mapping, mask) :> ILayer
+ | :? (V3f[]) -> Layer (def, data :?> V3f[] , mapping, mask) :> ILayer
+ | :? (V3d[]) -> Layer (def, data :?> V3d[] , mapping, mask) :> ILayer
+ | :? (V4f[]) -> Layer (def, data :?> V4f[] , mapping, mask) :> ILayer
+ | :? (V4d[]) -> Layer (def, data :?> V4d[] , mapping, mask) :> ILayer
+ | :? (C3b[]) -> Layer (def, data :?> C3b[] , mapping, mask) :> ILayer
+ | :? (C4b[]) -> Layer (def, data :?> C4b[] , mapping, mask) :> ILayer
+ | :? (C3f[]) -> Layer (def, data :?> C3f[] , mapping, mask) :> ILayer
+ | :? (C4f[]) -> Layer (def, data :?> C4f[] , mapping, mask) :> ILayer
+ | _ -> failwith <| sprintf "Unknown type %A. Invariant 4e797062-04a2-445f-9725-79f66823aff8." (data.GetType())
+
+
let BoundingBox (layer : ILayer) = layer.Mapping.BoundingBox
let Window (layer : ILayer) = layer.Mapping.Window
@@ -231,7 +261,7 @@ module Layer =
invariant (layers |> Array.forall (fun l -> l.Def = def)) "49514f12-b4f9-4708-9108-94a6dcc5d217"
def
- let private mergeTyped (layers : Layer<'a>[]) : Layer<'a> =
+ let private mergeTyped<'a when 'a : equality> (undefinedValue : 'a) (layers : Layer<'a>[]) : Layer<'a> =
let def = ensureSameDef layers
if verbose then
printfn "[Layer.Merge] .... def = %s" def.Name
@@ -246,7 +276,8 @@ module Layer =
let finalOrigin = Cell2d(finalWindow.Min, e)
let finalMapping = DataMapping(finalOrigin, V2i finalWindow.Size, finalWindow)
let finalData = Array.zeroCreate<'a> (int finalWindow.Size.X * int finalWindow.Size.Y)
-
+ let finalMask = Array.create (int finalWindow.Size.X * int finalWindow.Size.Y) 255uy
+
if verbose then
for l in layers do printfn "[Layer.Merge] .... [%A-%A]" l.SampleMin l.SampleMaxIncl
printfn "[Layer.Merge] .... final mapping"
@@ -254,7 +285,11 @@ module Layer =
printfn "[Layer.Merge] .... buffer size : %A" finalWindow.Size
printfn "[Layer.Merge] .... window: %A" finalWindow
-
+ let mutable debugCountValues = 0
+ let mutable debugCountCollisions = 0
+ let debugCollisionSamples = HashSet()
+
+ let mutable layerIndex = 0uy
for layer in layers do
let w = layer.Mapping.Window
let xMaxIncl = int w.SizeX - 1
@@ -264,17 +299,62 @@ module Layer =
let c = Cell2d(w.Min.X + int64 x, w.Min.Y + int64 y, e)
let i = finalMapping.GetBufferIndex c
let v = layer.GetSample(Fail, c)
- finalData.[i] <- v
+
+ //finalData.[i] <- v
+
+ match finalMask[i] with
+ | 255uy ->
+ finalData[i] <- v
+ finalMask[i] <- layerIndex
+ debugCountValues <- debugCountValues + 1
+ | _ ->
+ if v <> finalData[i] then
+ if finalData[i] = undefinedValue then
+ if v <> undefinedValue then
+ finalData[i] <- v
+ finalMask[i] <- layerIndex
+ else
+ ()
+ else
+ if v <> undefinedValue then
+ debugCollisionSamples.Add(i) |> ignore
+ debugCountCollisions <- debugCountCollisions + 1
+
+ if verbose then
+ printfn "[DEBUG][Layer.mergeTyped] COLLISION overwriting value %A from layer %d with value %A from layer %d" finalData[i] finalMask[i] v layerIndex
+
+ else
+ ()
+
+
+
+
+ layerIndex <- layerIndex + 1uy
+
- Layer(def, finalData, finalMapping)
+ // count occupied samples
+ let coundOccupiedSamples = finalMask |> Array.sumBy (fun x -> if x = 255uy then 1 else 0)
- let private toTyped<'a> (layers : ILayer[]) : Layer<'a>[] =
+ if verbose && debugCountCollisions > 0 then
+ printfn "[DEBUG][Layer.mergeTyped] debugCountValues = %d" debugCountValues
+ printfn "[DEBUG][Layer.mergeTyped] debugCountCollisions = %d" debugCountCollisions
+ printfn "[DEBUG][Layer.mergeTyped] debugCollisionSamples.Count = %d" debugCollisionSamples.Count
+ printfn "[DEBUG][Layer.mergeTyped] debugCountOccupied.Count = %d / %d ... %5.2f" coundOccupiedSamples finalMask.Length (float coundOccupiedSamples / float finalMask.Length)
+
+ // rewrite mask (1 ... occupied, 0 ... undefined)
+ for i = 0 to finalMask.Length-1 do
+ finalMask[i] <- if finalMask[i] = 255uy then 0uy else 1uy
+
+ Layer(def, finalData, finalMapping, if coundOccupiedSamples > 0 then Some finalMask else None)
+
+ let private toTyped<'a when 'a : equality> (layers : ILayer[]) : Layer<'a>[] =
layers |> Array.map (fun x -> x :?> Layer<'a>)
- let private mergeUntyped_<'a> xs = xs |> toTyped<'a> |> mergeTyped :> ILayer
+ let private mergeUntyped_<'a when 'a : equality> (undefinedValue : 'a) xs : ILayer =
+ xs |> toTyped<'a> |> (mergeTyped undefinedValue) :> ILayer
/// Merge layers of same type (def).
- let Merge (layers : ILayer seq) : ILayer option =
+ let Merge (layers : ILayer seq) =
let ls = layers |> Array.ofSeq
match ls.Length with
| 0 ->
@@ -282,43 +362,49 @@ module Layer =
None
| 1 ->
if verbose then printfn "[Layer.Merge] 1 layer -> Some ls.[0]"
- Some ls.[0]
+ Some (ls |> Array.exactlyOne)
| n ->
let distinctDefCount = ls |> Seq.distinctBy (fun l -> l.Def) |> Seq.length
if distinctDefCount <> 1 then failwith "Can only merge layers of same type (def). Error 68bf8529-e9c5-4b7b-a100-3e4850fc9c33."
if verbose then printfn "[Layer.Merge] %d layers" n
- match ls.[0] with
- | :? Layer -> ls |> mergeUntyped_
- | :? Layer -> ls |> mergeUntyped_
- | :? Layer -> ls |> mergeUntyped_
- | :? Layer -> ls |> mergeUntyped_
- | :? Layer -> ls |> mergeUntyped_
- | :? Layer -> ls |> mergeUntyped_
- | :? Layer -> ls |> mergeUntyped_
- | :? Layer -> ls |> mergeUntyped_
- | :? Layer -> ls |> mergeUntyped_
- | :? Layer -> ls |> mergeUntyped_
- | :? Layer -> ls |> mergeUntyped_
- | :? Layer -> ls |> mergeUntyped_
- | :? Layer -> ls |> mergeUntyped_
- | :? Layer -> ls |> mergeUntyped_
- | _ -> failwith <| sprintf "Unsupported layer type %A. Invariant bfb8d2ec-666d-4878-b612-f46f59dd5e82." ls.[0]
-
- |> Some
-
+ let mergedLayers =
+ match ls.[0] with
+ | :? Layer -> ls |> mergeUntyped_ Int32.MinValue
+ | :? Layer -> ls |> mergeUntyped_ Int64.MinValue
+ | :? Layer -> ls |> mergeUntyped_ nan
+ | :? Layer -> ls |> mergeUntyped_ nanf
+ | :? Layer -> ls |> mergeUntyped_ V2f.NaN
+ | :? Layer -> ls |> mergeUntyped_ V2d.NaN
+ | :? Layer -> ls |> mergeUntyped_ V3f.NaN
+ | :? Layer -> ls |> mergeUntyped_ V3d.NaN
+ | :? Layer -> ls |> mergeUntyped_ V4f.NaN
+ | :? Layer -> ls |> mergeUntyped_ V4d.NaN
+ | :? Layer -> ls |> mergeUntyped_ (C3b(0, 0, 0))
+ | :? Layer -> ls |> mergeUntyped_ (C4b(0, 0, 0, 0))
+ | :? Layer -> ls |> mergeUntyped_ (C3f(0, 0, 0))
+ | :? Layer -> ls |> mergeUntyped_ (C4f(0, 0, 0, 0))
+ | _ -> failwith <| sprintf "Unsupported layer type %A. Invariant bfb8d2ec-666d-4878-b612-f46f59dd5e82." ls.[0]
+
+ Some mergedLayers
type LayerSet(layers : ILayer[]) =
do
invariantm (layers.Length > 0) (fun()->"No layers.") "3532f669-8321-4f47-a39d-8c9920cb5f67"
+
+ let sampleExponent = layers |> Seq.map (fun x -> x.SampleExponent) |> Seq.distinct |> Seq.tryExactlyOne
+ invariantm (sampleExponent.IsSome) (fun()->"Layers have different sample exponents.") "975ddfbd-ae0d-4b54-bad6-cd054faeadf9"
+
+ ()
- member this.Layers with get() = layers
+ member this.Layers with get() = layers
- member this.BoundingBox with get() = layers.[0].BoundingBox
- member this.Mapping with get() = layers.[0].Mapping
- member this.SampleExponent with get() = layers.[0].Mapping.BufferOrigin.Exponent
- member this.SampleWindow with get() = layers.[0].Mapping.Window
+ member this.BoundingBox with get() = layers.[0].BoundingBox
+ member this.Mapping with get() = layers.[0].Mapping
+ member this.SampleExponent with get() = layers.[0].Mapping.BufferOrigin.Exponent
+ member this.SampleWindow with get() = layers.[0].Mapping.Window
+ member this.SampleWindowAtChildLevel with get() = layers.[0].SampleWindowAtChildLevel
/// Returns 2.0 ^ SampleExponent.
member this.SampleSize with get() = 2.0 ** float(layers.[0].Mapping.BufferOrigin.Exponent)
@@ -326,7 +412,7 @@ type LayerSet(layers : ILayer[]) =
member this.TryGetLayer (semantic : Durable.Def) : ILayer option =
layers |> Array.tryFind (fun x -> x.Def.Id = semantic.Id)
- member this.TryGetLayer<'a> (semantic : Durable.Def) : Layer<'a> option =
+ member this.TryGetLayer<'a when 'a : equality> (semantic : Durable.Def) : Layer<'a> option =
this.TryGetLayer(semantic) |> Option.map (fun x -> x :?> Layer<'a>)
member this.GetLayer(semantic : Durable.Def) : ILayer =
@@ -335,7 +421,7 @@ type LayerSet(layers : ILayer[]) =
with
| _ -> sprintf "Failed to retrieve layer %A. Available layers are %A. Error 091474a1-d06b-408a-8609-85e0b272e645." semantic.Name (layers |> Array.map(fun x->x.Def.Name)) |> failwith
- member this.GetLayer<'a>(semantic : Durable.Def) : Layer<'a> =
+ member this.GetLayer<'a when 'a : equality>(semantic : Durable.Def) : Layer<'a> =
this.GetLayer(semantic) :?> Layer<'a>
member this.WithWindow (w : Box2l) : LayerSet option =
@@ -369,4 +455,29 @@ type LayerSet(layers : ILayer[]) =
let l = oldLayer.WithSemantic(newSemantic)
layers |> Seq.filter (fun x -> x.Def.Id <> oldSemantic.Id) |> Seq.append [l] |> Seq.toArray
- LayerSet(newLayers) |> Some
\ No newline at end of file
+ LayerSet(newLayers) |> Some
+
+ /// True, if at least one layer has a mask.
+ member this.HasMask with get () = this.Layers |> Array.exists (fun x -> x.Mask.IsSome)
+
+module LayerSet =
+
+ /// Merges multiple layer sets.
+ /// All layer sets must have identical layers (same number, same semantics, same order).
+ let Merge (layerSets : LayerSet seq) : LayerSet =
+
+ let layerSets = layerSets |> Array.ofSeq
+ let layersPerLayerSet = layerSets[0].Layers.Length
+
+ let indices = [0..layersPerLayerSet-1]
+
+ let layers =
+ indices
+ |> List.choose (fun i ->
+ // merge the i-th layers from all layer sets
+ layerSets |> Array.map (fun x -> x.Layers[i]) |> Layer.Merge
+ )
+ |> Array.ofList
+
+ let result = LayerSet layers
+ result
\ No newline at end of file
diff --git a/src/Aardvark.Geometry.Quadtree/Merge.fs b/src/Aardvark.Geometry.Quadtree/Merge.fs
index 757e1d6..581f1f6 100644
--- a/src/Aardvark.Geometry.Quadtree/Merge.fs
+++ b/src/Aardvark.Geometry.Quadtree/Merge.fs
@@ -78,10 +78,22 @@ with
module Merge =
let winner dom (first : QNodeRef) (second : QNodeRef) : QNodeRef option =
- match dom, first.ExactBoundingBox, second.ExactBoundingBox with
- | FirstDominates, bb1, bb2 when bb1.Contains(bb2) -> Some first
- | SecondDominates, bb1, bb2 when bb2.Contains(bb1) -> Some second
- | _ -> None
+
+ None
+
+ (*
+ removed optimization, because this no longer works when masks are involved
+
+ - adding mask info (e.g. HasMask for all nodes/subtrees) would break backwards compatibility in serialization
+ - we can add this back again if it turns out that this makes a huge difference
+ (and would then also need to add more metadata and upgrade serialization accordingly)
+ *)
+
+ //match dom, first.ExactBoundingBox, second.ExactBoundingBox with
+ // | FirstDominates, bb1, bb2 when bb1.Contains(bb2) -> Some first
+ // | SecondDominates, bb1, bb2 when bb2.Contains(bb1) -> Some second
+ // | _ -> None
+
let growParent (n : QNodeRef) : QNodeRef = QInnerNode.ofSubNode(n) |> InMemoryInner
diff --git a/src/Aardvark.Geometry.Quadtree/Node.fs b/src/Aardvark.Geometry.Quadtree/Node.fs
index 7997992..fb44b7e 100644
--- a/src/Aardvark.Geometry.Quadtree/Node.fs
+++ b/src/Aardvark.Geometry.Quadtree/Node.fs
@@ -70,13 +70,13 @@ and QNode(uid : Guid, exactBoundingBox : Box2d, cell : Cell2d, splitLimitExp : i
member this.TryGetLayer (semantic : Durable.Def) : ILayer option =
layers.TryGetLayer(semantic)
- member this.TryGetLayer<'a> (semantic : Durable.Def) : Layer<'a> option =
+ member this.TryGetLayer<'a when 'a : equality> (semantic : Durable.Def) : Layer<'a> option =
layers.TryGetLayer<'a>(semantic)
member this.GetLayer(semantic : Durable.Def) : ILayer =
layers.GetLayer(semantic)
- member this.GetLayer<'a>(semantic : Durable.Def) : Layer<'a> =
+ member this.GetLayer<'a when 'a : equality>(semantic : Durable.Def) : Layer<'a> =
layers.GetLayer<'a>(semantic)
member this.WithWindow (w : Box2l) : QNode option =
@@ -103,6 +103,9 @@ and QNode(uid : Guid, exactBoundingBox : Box2d, cell : Cell2d, splitLimitExp : i
member this.GetSample (p : V2d) : Cell2d =
layers.Mapping.GetSampleCell(p)
+ /// Resolution level.
+ member this.SampleExponent with get() = layers.SampleExponent
+
/// Returns 2.0 ^ SampleExponent.
member this.SampleSize with get() : float = layers.SampleSize
@@ -138,7 +141,7 @@ and
| OutOfCoreNode of Guid * (unit -> QNodeRef)
| InMemoryInner of QInnerNode
| InMemoryMerge of QMergeNode
- | LinkedNode of QLinkedNode
+ | LinkedNode of QLinkedNode
with
/// Forces property Id. Throws exception if NoNode.
@@ -270,7 +273,7 @@ and
| LinkedNode n -> n.Target.GetLayer def
/// Throws if no such layer.
- member this.GetLayer<'a> def =
+ member this.GetLayer<'a when 'a : equality> def =
match this with
| NoNode
| InMemoryInner _
@@ -290,7 +293,7 @@ and
| None -> None
| LinkedNode n -> n.Target.TryGetLayer def
- member this.TryGetLayer<'a> def =
+ member this.TryGetLayer<'a when 'a : equality> def =
match this with
| NoNode
| InMemoryInner _
diff --git a/src/Aardvark.Geometry.Quadtree/Prelude.fs b/src/Aardvark.Geometry.Quadtree/Prelude.fs
index 30bd544..5790672 100644
--- a/src/Aardvark.Geometry.Quadtree/Prelude.fs
+++ b/src/Aardvark.Geometry.Quadtree/Prelude.fs
@@ -34,7 +34,18 @@ module Prelude =
let inline inDifferentQuadrants (a : Cell2d) (b : Cell2d) =
if a.IsCenteredAtOrigin || b.IsCenteredAtOrigin then false
else ((a.X >= 0L) <> (b.X >= 0L)) || ((a.Y >= 0L) <> (b.Y >= 0L))
-
+
+ /// Gets cell bounds in resolution 2^e with inclusive min and exclusive max.
+ let getBoundsForExponent (e : int) (cell : Cell2d) : Box2l =
+ if cell.IsCenteredAtOrigin then
+ invariant (e < cell.Exponent) "ecfc0260-688b-43f2-9e10-a0bc66132ac1"
+ let d = cell.Exponent - e - 1
+ let x = 1L <<< d
+ Box2l(-x, -x, x, x)
+ else
+ invariant (e <= cell.Exponent) "316764bd-c4fe-4202-bba4-bf603061b629"
+ let d = cell.Exponent - e
+ Box2l(cell.X <<< d, cell.Y <<< d, (cell.X + 1L) <<< d, (cell.Y + 1L) <<< d)
module Option =
diff --git a/src/Aardvark.Geometry.Quadtree/PrettyPrint.fs b/src/Aardvark.Geometry.Quadtree/PrettyPrint.fs
index 4372d56..c9be2b6 100644
--- a/src/Aardvark.Geometry.Quadtree/PrettyPrint.fs
+++ b/src/Aardvark.Geometry.Quadtree/PrettyPrint.fs
@@ -129,7 +129,7 @@ module PrettyPrint =
| -3 -> C3b(128,255,255)
| _ -> C3b.Gray80
- let ofQNodeRef<'a> (name : string) (pos : Pos) (def : Durable.Def) (qref : QNodeRef) : Cells =
+ let ofQNodeRef<'a when 'a : equality> (name : string) (pos : Pos) (def : Durable.Def) (qref : QNodeRef) : Cells =
let f = { HAlign=Left; VAlign=Top; Bgcolor=C3b.White }
@@ -203,11 +203,11 @@ module PrettyPrint =
- let generateHtmlDebugView<'a> title def quadtrees =
+ let generateHtmlDebugView<'a when 'a : equality> title def quadtrees =
let content = quadtrees |> List.mapi (fun i x -> Cells.ofQNodeRef<'a> (sprintf "%s
" (fst x)) {X=0;Y=i*2} def (snd x))
Cells.Group({X=0;Y=0}, Format.Default, sprintf "%s
" title, content) |> Cells.toHtml
- let showHtmlDebugView<'a> title def quadtrees =
+ let showHtmlDebugView<'a when 'a : equality> title def quadtrees =
let html = generateHtmlDebugView<'a> title def quadtrees
let now = DateTime.Now
let filename = sprintf "quadtree_%04d-%02d-%02d-%02d-%02d-%02d.html" now.Year now.Month now.Day now.Hour now.Minute now.Second
diff --git a/src/Aardvark.Geometry.Quadtree/Quadtree.fs b/src/Aardvark.Geometry.Quadtree/Quadtree.fs
index fbc4d7a..bd52f03 100644
--- a/src/Aardvark.Geometry.Quadtree/Quadtree.fs
+++ b/src/Aardvark.Geometry.Quadtree/Quadtree.fs
@@ -28,6 +28,50 @@ module Quadtree =
| OutOfCoreNode (_, load) -> load()
| _ -> node
+ /// Enumerate all nodes.
+ /// Out-of-core nodes are automatically loaded and traversed.
+ /// A resulting QNode object x can be simply converted back to a QNodeRef by calling `InMemoryNode x`.
+ let EnumerateLeafNodesInMemory (root : QNodeRef) : seq = seq {
+
+ let stack = Stack()
+ stack.Push root
+
+ while stack.Count > 0 do
+
+ let node = stack.Pop() |> EnsureInMemory
+
+ match node with
+ | NoNode -> ()
+ | InMemoryNode q -> yield q
+ | OutOfCoreNode _ -> failwith "Internal error 7a6995bd-c0d3-4650-8ea5-9764ec3fe26c."
+ | InMemoryInner n -> for subNode in n.SubNodes do subNode |> stack.Push
+ | InMemoryMerge n -> n.First |> stack.Push
+ n.Second |> stack.Push
+ | LinkedNode n -> n.Target |> stack.Push
+ }
+
+ /// Enumerate all nodes of given quadtree.
+ /// If outOfCore is true, then the full tree is traversed, even nodes that are stored out-of-core.
+ let EnumerateNodes (outOfCore : bool) (root : QNodeRef) : seq = seq {
+
+ let stack = Stack()
+ stack.Push root
+
+ while stack.Count > 0 do
+
+ let node = stack.Pop()
+
+ match node with
+ | NoNode -> ()
+ | InMemoryNode n -> yield node
+ | OutOfCoreNode (_, load) -> if outOfCore then stack.Push (load()) else yield node
+ | InMemoryInner n -> for subNode in n.SubNodes do subNode |> stack.Push
+ | InMemoryMerge n -> n.First |> stack.Push
+ n.Second |> stack.Push
+ yield node
+ | LinkedNode n -> n.Target |> stack.Push
+ }
+
/// Enumerate all nodes breadth first.
/// If outOfCore is false, then out-of-core nodes are handled like leaf nodes.
let EnumerateNodesBreadthFirst (outOfCore : bool) (root : QNodeRef) : seq = seq {
@@ -86,16 +130,26 @@ module Quadtree =
count
/// Count number of nodes in quadtree.
- /// If outOfCore is false, then out-of-core nodes are handled like leafs.
+ /// If outOfCore is false, then out-of-core nodes are handled like leaf nodes.
let CountNodes outOfCore root = root |> tryCount outOfCore 1 1
/// Count number of leaf nodes in quadtree.
- /// If outOfCore is false, then out-of-core nodes are handled like leafs.
- let CountLeafs outOfCore root = root |> tryCount outOfCore 1 0
+ /// If outOfCore is false, then out-of-core nodes are handled like leaf nodes.
+ let CountLeafNodes outOfCore root = root |> tryCount outOfCore 1 0
+
+ []
+ let CountLeafs = CountLeafNodes
/// Count number of inner nodes in quadtree.
- /// If outOfCore is false, then out-of-core nodes are handled like leafs.
- let CountInner outOfCore root = root |> tryCount outOfCore 0 1
+ /// If outOfCore is false, then out-of-core nodes are handled like leaf nodes.
+ let CountInnerNodes outOfCore root = root |> tryCount outOfCore 0 1
+
+ []
+ let CountInner = CountInnerNodes
+
+ /// Count number of merge nodes in quadtree.
+ /// If outOfCore is false, then out-of-core nodes are handled like leaf nodes.
+ let CountMergeNodes outOfCore root : int = root |> EnumerateNodes outOfCore |> Seq.filter (fun n -> match n with | InMemoryMerge _ -> true | _ -> false) |> Seq.length
let PrintStructure (outOfCore : bool) (n : QNodeRef) =
@@ -153,7 +207,7 @@ module Quadtree =
for i = 0 to 3 do
match subNodes.[i] with
| InMemoryNode x -> invariant (x.Cell = children.[i]) "15f2c6c3-6f5b-4ac0-9ec0-8ab968ac9c2e"
- | InMemoryInner x -> invariant (x.Cell = children.[i]) "817d1b42-8fd9-465c-9cac-4d197a9a5bb9"
+ | InMemoryInner x -> invariant (x.Cell = children.[i]) "817d1b42-8fd9-465c-9cac-4d197a9a5bb9"
| NoNode -> ()
| _ -> failwith "Todo 6f5d63bc-ece6-49ef-b634-879f81a4fc36."
@@ -211,7 +265,7 @@ module Quadtree =
qtree.ContainsLayer(semantic)
/// Throws if no such layer.
- let GetLayer<'a> (semantic : Durable.Def) (qtree : QNodeRef) : Layer<'a> =
+ let GetLayer<'a when 'a : equality> (semantic : Durable.Def) (qtree : QNodeRef) : Layer<'a> =
qtree.GetLayer<'a>(semantic)
/// Throws if no such layer.
@@ -219,7 +273,7 @@ module Quadtree =
qtree.GetLayer(semantic)
/// Throws if no such layer.
- let TryGetLayer<'a> (semantic : Durable.Def) (qtree : QNodeRef) : Layer<'a> option =
+ let TryGetLayer<'a when 'a : equality> (semantic : Durable.Def) (qtree : QNodeRef) : Layer<'a> option =
qtree.TryGetLayer<'a>(semantic)
/// Throws if no such layer.
diff --git a/src/Aardvark.Geometry.Quadtree/Query.fs b/src/Aardvark.Geometry.Quadtree/Query.fs
index effbbaa..dc97c17 100644
--- a/src/Aardvark.Geometry.Quadtree/Query.fs
+++ b/src/Aardvark.Geometry.Quadtree/Query.fs
@@ -62,7 +62,7 @@ module Query =
| SubtractionSelected second -> this.Node.LayerSet.SampleWindow.GetAllSamplesFromFirstMinusSecond(second, this.Node.LayerSet.SampleExponent)
| FullySelected -> this.Node.GetAllSamples()
- member this.GetSamples<'a>(def : Durable.Def) : (Cell2d*'a)[] =
+ member this.GetSamples<'a when 'a : equality>(def : Durable.Def) : (Cell2d*'a)[] =
let layer = this.Node.GetLayer<'a>(def)
let cells = this.GetSampleCells ()
let result = cells |> Array.map (fun p ->
@@ -628,7 +628,7 @@ module Sample =
}
with
member this.GetSampleCells () : Cell2d[] = this.Cells
- member this.GetSamples<'a>(def : Durable.Def) : (V2d*Cell2d*'a)[] =
+ member this.GetSamples<'a when 'a : equality>(def : Durable.Def) : (V2d*Cell2d*'a)[] =
let layer = this.Node.GetLayer<'a>(def)
this.Cells |> Array.map2 (fun p c -> (p, c, layer.GetSample(Fail, c))) this.Positions
@@ -747,7 +747,7 @@ module Sample =
let result = Positions config [| position |] root |> Seq.toArray
result |> Seq.tryHead
- let PositionTyped<'a> (config : Query.Config) (position : V2d) (def : Durable.Def) (root : QNodeRef) : 'a option =
+ let PositionTyped<'a when 'a : equality> (config : Query.Config) (position : V2d) (def : Durable.Def) (root : QNodeRef) : 'a option =
match Position config position root with
| Some x ->
let xs = x.GetSamples<'a> def
diff --git a/src/Scratch/Program.fs b/src/Scratch/Program.fs
index c73070c..c9a5994 100644
--- a/src/Scratch/Program.fs
+++ b/src/Scratch/Program.fs
@@ -1010,45 +1010,111 @@ let madorjan20211103 () =
let flattenSketch () =
- let store = @"W:\Datasets\Vgm\Data\2023-09-04_bugreport"
- let key = Guid "c0d343c1-8aaf-4884-9f98-4627b4f09396"
+ let store = @"W:\Datasets\Vgm\Data\2023-09-04_quadtree"
+ //let store = @"W:\Datasets\Vgm\Data\2023-11-10_quadtree"
+
+ let key = File.ReadAllText(Path.Combine(store, "key.txt")) |> Guid
let options = Serialization.SerializationOptions.SimpleDiskStore store
+ let root : QNodeRef = Quadtree.Load options key
- let root = Quadtree.Load options key
+ let leafNodes = root |> Quadtree.EnumerateLeafNodesInMemory |> List.ofSeq
+ printfn "original quadtree has %d leaf nodes and %d merge nodes" leafNodes.Length (Quadtree.CountMergeNodes true root)
+
- //let nodeCount = root |> Quadtree.enumerateNodesBreadthFirst true |> Seq.length
- printfn "node count (all) = %d" (root |> Quadtree.CountNodes true)
- printfn "node count (inner) = %d" (root |> Quadtree.CountInner true)
- printfn "node count (leafs) = %d" (root |> Quadtree.CountLeafs true)
+ let resolutions = leafNodes |> List.groupBy (fun n -> n.SampleExponent)
- let foo (root : QNodeRef) : seq = seq {
-
- let ensureInMemory n = match n with | OutOfCoreNode (_, load) -> load() | _ -> n
- let stack = Stack()
- stack.Push root
+ let builder = Builder()
+ for n in leafNodes do builder.Add n
+
+ match builder.Build() with
+ | None -> printfn ""
+ | Some newAndBetterTree ->
+ let countLeafNodes = newAndBetterTree |> Quadtree.CountLeafNodes true
+ let countMergeNodes = newAndBetterTree |> Quadtree.CountMergeNodes true
+ //for n in Quadtree.EnumerateNodes true newAndBetterTree do printfn "%A" (n.GetType())
+ printfn "new quadtree has %d leaf nodes and %d merge nodes" countLeafNodes countMergeNodes
- while stack.Count > 0 do
- let node = stack.Pop() |> ensureInMemory
+
+
- match node with
- | NoNode -> ()
- | InMemoryNode _ -> yield node
- | OutOfCoreNode _ -> failwith "Internal error 7a6995bd-c0d3-4650-8ea5-9764ec3fe26c."
- | InMemoryInner n -> yield node
- for subNode in n.SubNodes do subNode |> stack.Push
- | InMemoryMerge n -> yield node
- n.First |> stack.Push
- n.Second |> stack.Push
- | LinkedNode n -> n.Target |> stack.Push
- }
+ ////let nodeCount = root |> Quadtree.enumerateNodesBreadthFirst true |> Seq.length
+ //printfn "node count (all) = %d" (root |> Quadtree.CountNodes true)
+ //printfn "node count (inner) = %d" (root |> Quadtree.CountInner true)
+ //printfn "node count (leafs) = %d" (root |> Quadtree.CountLeafs true)
- let fooSeq = foo root |> List.ofSeq
- let nodeCount = root |> foo |> Seq.length
- printfn "node count (foo ) = %d" nodeCount
+ //printfn ""
+ //printfn "grouping by sample size"
+ //let gs = leafNodes |> Seq.groupBy (fun n -> n.LayerSet.SampleExponent) |> List.ofSeq
+ //let histo = gs
+ // |> Seq.map (fun (key, ns) -> (key, ns |> List.ofSeq))
+ // //|> Seq.sortByDescending (fun (key, _) -> key)
+
+ //for (k, ns) in histo do
+
+ // let countPatches = ns |> List.length
+ // let countSamples = ns |> List.sumBy (fun x -> x.LayerSet.SampleWindow.Area)
+ // let ebb = ns |> Seq.map (fun n -> n.ExactBoundingBox) |> Box2d
+ // printfn " %d" k
+ // printfn " patches %8d" countPatches
+ // printfn " samples %8d" countSamples
+ // printfn " ebb %A" ebb
+ // printfn ""
+
+ // //let result = ns |> List.map (fun n -> n.LayerSet) |> Builder.Build
+
+ // for n in ns do builder.Add(n.LayerSet)
+
+ // ()
+
+ //let boxes = List()
+ //for n in ns do
+ // let foo = n |> InMemoryNode |> Query.All Query.Config.Default |> Seq.collect (fun x -> x.GetSampleCells ()) |> Seq.groupBy id |> Seq.filter (fun (_, xs) -> xs |> Seq.length <> 1) |> Array.ofSeq
+ // for (c, cs) in foo do printfn "%A -> %d" c (cs |> Seq.length)
+ // // printfn "[%d] %A" k n.LayerSet.SampleWindow
+ // boxes.Add(n.LayerSet.SampleWindow)
+ // ()
+
+ //let mergeBoxes (boxes : List) : List =
+ // let gbb = Box2l(boxes)
+ // printfn "gbb %A with size = %A" gbb gbb.Size
+
+ // let candidateSets = boxes |> Seq.groupBy (fun box -> box.Min.X) |> Seq.map (fun (k, bs) -> (k, bs |> List.ofSeq)) |> List.ofSeq
+ // printfn " candidate sets : %d" candidateSets.Length
+ // printfn " candidate sets (>1): %d" (candidateSets |> Seq.filter (fun (k, bs) -> bs.Length > 1) |> Seq.length)
+
+ // //for (minX, bs) in candidateSets do
+ // // let groupedByWidth = bs |> Seq.groupBy (fun b -> b.Size.X) |> List.ofSeq
+ // // for (w, bs) in groupedByWidth do
+ // // // same min.X, same width
+ // // printfn "minX = %d, width = %d, count = %d" minX w (bs |> Seq.length)
+ // // let bs2 = bs |> Seq.sortBy (fun b -> b.Min.Y)
+ // // for b in bs2 do
+ // // printfn " * %A %A" b b.Size
+
+
+ // let result = List()
+ // result
+
+ //let boxesMerged = mergeBoxes boxes
+
+ //printfn " merged boxes ... %d" boxesMerged.Count
+
+
+ //printfn ""
+ //let nodeCount = root |> enumerateLeafs |> Seq.length
+ //printfn "node count (foo ) = %d" nodeCount
+
+ //printfn ""
+ //let histo = root
+ // |> Quadtree.EnumerateNodesBreadthFirst true
+ // |> Seq.groupBy (fun n -> n.GetType().Name)
+ // |> Seq.map (fun (key, ns) -> (key, ns |> Seq.length))
+ // |> Map.ofSeq
+ //for kv in histo do printfn "%s -> %d" kv.Key kv.Value
//Quadtree.PrintStructure true q