Skip to content

Commit 13da464

Browse files
[builder] save/load, export/import
1 parent f4c7945 commit 13da464

File tree

3 files changed

+205
-8
lines changed

3 files changed

+205
-8
lines changed

src/Aardvark.Geometry.Quadtree/Builder.fs

Lines changed: 89 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
open Aardvark.Base
44
open System
55
open System.Collections.Generic
6+
open Serialization
7+
8+
#nowarn "1337"
69

710
module Builder =
811

@@ -77,7 +80,7 @@ module Builder =
7780
if debugOutput then
7881
printfn "[DEBUG] CREATED QNode with split limit = %d" qnode.SplitLimitExponent
7982

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

@@ -108,6 +111,8 @@ module Builder =
108111
)
109112

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

@@ -118,7 +123,6 @@ module Builder =
118123
let sampleExponent = (patches |> Array.distinctBy (fun x -> x.SampleExponent) |> Array.exactlyOne).SampleExponent
119124
build' sampleExponent rootCell patches
120125

121-
122126
/// Creates a quadtree from many small patches.
123127
type Builder () =
124128

@@ -127,6 +131,12 @@ type Builder () =
127131
let mutable isEmpty = true
128132
let mutable layerCount = 0
129133

134+
static let ensureDir path =
135+
let path = System.IO.Path.GetFullPath(path)
136+
let dir = System.IO.DirectoryInfo(path)
137+
if not dir.Exists then dir.Create()
138+
path
139+
130140
/// Add patch.
131141
member this.Add (patch : LayerSet) : unit = lock l (fun () ->
132142

@@ -150,6 +160,12 @@ type Builder () =
150160
list.Add(patch)
151161
)
152162

163+
/// Add patch.
164+
member this.Add (patch : LayerSet option) : unit =
165+
match patch with
166+
| None -> ()
167+
| Some patch -> this.Add(patch)
168+
153169
/// Add patch.
154170
member this.Add (patch : ILayer) : unit =
155171
this.Add(LayerSet([| patch |]))
@@ -158,6 +174,18 @@ type Builder () =
158174
member this.Add (patch : QNode) : unit =
159175
this.Add(patch.LayerSet)
160176

177+
/// Add all leaf nodes of given quadtree as patches.
178+
member this.Add (root : QNodeRef) : unit =
179+
root |> Quadtree.EnumerateLeafNodesInMemory |> this.AddRange
180+
181+
/// Add multiple patches.
182+
member this.AddRange (patches : seq<QNode>) : unit =
183+
for patch in patches do this.Add(patch)
184+
185+
/// Add multiple patches.
186+
member this.AddRange (patches : seq<LayerSet>) : unit =
187+
for patch in patches do this.Add(patch)
188+
161189
/// Build a quadtree from all the patches that have been added to this builder.
162190
member this.Build () : QNodeRef option =
163191

@@ -173,7 +201,11 @@ type Builder () =
173201
| Some state -> Quadtree.Merge Dominance.SecondDominates state item |> Some
174202
)
175203
None // initial state
176-
204+
205+
/// Enumerate all patches.
206+
member this.GetPatches () : seq<LayerSet> =
207+
patches |> Seq.map (fun kv -> kv.Value) |> Seq.collect id
208+
177209
member this.Print () : unit =
178210

179211
printfn "Builder("
@@ -186,4 +218,57 @@ type Builder () =
186218
printfn " global root cell = %A" (Cell2d bbGlobal)
187219

188220
printfn " )"
189-
()
221+
()
222+
223+
/// Save builder. Returns id of saved builder.
224+
member this.Save (options : SerializationOptions) : Guid =
225+
Defs.init ()
226+
let patches = this.GetPatches() |> Array.ofSeq
227+
Serialization.SavePatches options patches
228+
229+
/// Load builder with given id.
230+
static member Load (options : SerializationOptions) (id : Guid) : Builder option =
231+
Defs.init ()
232+
match Serialization.LoadPatches options id with
233+
| None -> None
234+
| Some patches ->
235+
let builder = Builder()
236+
builder.AddRange(patches)
237+
Some builder
238+
239+
/// Export builder to directory.
240+
member this.Export (dir : string) : Guid =
241+
242+
let storeDir = ensureDir dir
243+
244+
let now = DateTimeOffset.Now
245+
let fileNameKey = sprintf("builder.%04d%02d%02d%02d%02d%02d.%d.key.txt") now.Year now.Month now.Day now.Hour now.Minute now.Second now.Ticks
246+
247+
use store = new Uncodium.SimpleStore.SimpleDiskStore(System.IO.Path.Combine(storeDir, "store.dur"))
248+
let options = SerializationOptions.SimpleStore(store)
249+
let key = this.Save(options)
250+
251+
System.IO.File.WriteAllText(System.IO.Path.Combine(storeDir, fileNameKey), key.ToString())
252+
253+
key
254+
255+
/// Imports builder with given id from directory.
256+
static member Import (dir : string, id : Guid) : Builder option =
257+
258+
let storeFileName =
259+
if System.IO.File.Exists(dir) then
260+
dir
261+
else
262+
if System.IO.Directory.Exists(dir) then
263+
System.IO.Path.Combine(dir, "store.dur")
264+
else
265+
sprintf "Unknown path %s. Error 094f64b9-ba1e-4d9d-a5e1-bc471665f332." dir |> failwith
266+
267+
use store = new Uncodium.SimpleStore.SimpleDiskStore(storeFileName)
268+
let options = SerializationOptions.SimpleStore(store)
269+
match Serialization.LoadPatches options id with
270+
| None -> None
271+
| Some patches ->
272+
let builder = Builder()
273+
builder.AddRange(patches)
274+
Some builder

src/Aardvark.Geometry.Quadtree/Defs.fs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,9 @@ module Defs =
111111
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
112112
let VolumesBilinear4dLayer = def "fd547ab1-88e9-4fc2-9c7d-a67545bfd3d1" "Quadtree.VolumesBilinear4d.Layer" "Quadtree. VolumesBilinearParams4d layer. DurableMapAligned16." Durable.Primitives.DurableMapAligned16
113113

114-
let Mask1b = def "6f33738c-eddc-411e-932f-326249d95f46" "Aardvark.Geometry.Quadtree.ByteMask" "UInt8[]." Durable.Primitives.UInt8Array
114+
let Mask1b = def "6f33738c-eddc-411e-932f-326249d95f46" "Quadtree.ByteMask" "UInt8[]." Durable.Primitives.UInt8Array
115+
116+
let PatchIds = def "3505d69b-79bf-449f-8740-13a0eda219b1" "Quadtree.PatchIds" "Guid[]." Durable.Primitives.GuidArray
115117

116118
let private def2layer = Map.ofList [
117119
(Heights1f , Heights1fLayer )

src/Aardvark.Geometry.Quadtree/Serialization.fs

Lines changed: 113 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -262,7 +262,7 @@ module Serialization =
262262
(*
263263
QNode
264264
265-
durable definition c74fad23-1211-4073-94e5-54b778e0d295
265+
durable definition c74fad23-1211-4073-94e5-54b778e0d295 (Quadtree.NodeLeaf)
266266
*)
267267

268268
let private encodeQNode (options : SerializationOptions) (n : QNode) : byte[] =
@@ -381,7 +381,63 @@ module Serialization =
381381
InMemoryInner { Id = id; ExactBoundingBox = ebb; Cell = cell; SplitLimitExponent = sle; HasMask = hasMask; SubNodes = ns }
382382
| None ->
383383
InMemoryNode(QNode(id, ebb, cell, sle, layerSet))
384-
384+
385+
386+
(*
387+
LayerSet
388+
389+
durable definition c39a978b-00f5-485f-b0b3-d2cf9599016b (Quadtree.Layers)
390+
*)
391+
392+
let private encodeLayerSet (options : SerializationOptions) (x : LayerSet) : byte[] =
393+
394+
let map = List<KeyValuePair<Durable.Def, obj>>()
395+
396+
// layers
397+
for layer in x.Layers do
398+
let layerDef = Defs.GetLayerFromDef layer.Def
399+
let dm = layer.Materialize().ToDurableMap ()
400+
map.Add(kvp layerDef dm)
401+
402+
DurableCodec.Serialize(Defs.Layers, map)
403+
404+
let private decodeLayerSet (options: SerializationOptions) (def : Durable.Def) (o : obj) =
405+
406+
let map = o :?> ImmutableDictionary<Durable.Def, obj>
407+
408+
let layers : ILayer[] =
409+
map
410+
|> Seq.choose (fun kv ->
411+
match Defs.TryGetDefFromLayer kv.Key with
412+
| Some def ->
413+
let m = kv.Value :?> ImmutableDictionary<Durable.Def, obj>
414+
Layer.FromDurableMap def m |> Some
415+
| None -> None
416+
)
417+
|> Seq.toArray
418+
419+
let layerSet = LayerSet(layers)
420+
421+
invariant (layers.Length > 0) "71249698-2b8f-4423-80d6-43122ac27f9c"
422+
423+
layerSet
424+
425+
426+
(*
427+
Patch IDs
428+
429+
durable definition 3505d69b-79bf-449f-8740-13a0eda219b1 (Quadtree.PatchIds)
430+
*)
431+
432+
let private encodePatchIds (options : SerializationOptions) (ids : seq<Guid>) : byte[] =
433+
DurableCodec.Serialize(Defs.PatchIds, ids |> Array.ofSeq)
434+
435+
let private decodePatchIds (options: SerializationOptions) (def : Durable.Def) (o : obj) : Guid[] =
436+
437+
invariant (def = Defs.PatchIds) "c68e7236-21b4-4919-ba14-afa75e69d0cc"
438+
439+
let ids = o :?> Guid[]
440+
ids
385441

386442
(*
387443
save/encode
@@ -407,9 +463,25 @@ module Serialization =
407463
| InMemoryMerge n -> saveBuffer n.Id (fun () -> encodeQMergeNode options n) [| n.First; n.Second |]
408464
| LinkedNode n -> saveBuffer n.Id (fun () -> encodeQLinkedNode options n) [| n.Target |]
409465

466+
let SaveLayerSet (options: SerializationOptions) (layerSet : LayerSet) : Guid =
467+
468+
let id = Guid.NewGuid()
469+
let buffer = encodeLayerSet options layerSet
470+
options.Save id buffer
471+
id
472+
473+
let SavePatches (options: SerializationOptions) (patches : seq<LayerSet>) : Guid =
474+
475+
let buffer = patches |> Seq.map(SaveLayerSet options) |> encodePatchIds options
476+
477+
let id = Guid.NewGuid()
478+
options.Save id buffer
479+
480+
id
481+
410482

411483
(*
412-
load
484+
load/decode
413485
*)
414486

415487
let private decoders : Map<Guid, Decoder> = Map.ofList <| [
@@ -433,6 +505,44 @@ module Serialization =
433505
let struct (def, o) = DurableCodec.Deserialize(buffer)
434506
decode options def o
435507

508+
let LoadLayerSet (options: SerializationOptions) (id : Guid) : LayerSet option =
509+
510+
match options.TryLoad id with
511+
| None -> None
512+
| Some buffer ->
513+
let struct (def, o) = DurableCodec.Deserialize(buffer)
514+
let map = o :?> ImmutableDictionary<Durable.Def, obj>
515+
let layers = map |> Seq.map (fun kv -> Layer.FromDurableMap kv.Key map)
516+
for kv in map do
517+
let bar = Layer.FromDurableMap kv.Key map
518+
()
519+
520+
None
521+
522+
let LoadPatches (options: SerializationOptions) (id : Guid) : LayerSet[] option =
523+
524+
match options.TryLoad id with
525+
| None -> None
526+
| Some buffer ->
527+
let struct (def, o) = DurableCodec.Deserialize(buffer)
528+
let patchIds = decodePatchIds options def o
529+
530+
let layerSets =
531+
patchIds |> Array.map(fun patchId ->
532+
match options.TryLoad patchId with
533+
534+
| None ->
535+
sprintf "Patch (id=%A) not found. Error 033031e0-03a5-4b3f-bf3c-88b7f4215373." patchId
536+
|> failwith
537+
538+
| Some buffer ->
539+
let struct (def, o) = DurableCodec.Deserialize(buffer)
540+
let layerSet = decodeLayerSet options def o
541+
layerSet
542+
)
543+
544+
Some layerSets
545+
436546
/// Enumerates node ids of given quadtree.
437547
let rec EnumerateKeys (outOfCore : bool) (qtree : QNodeRef) : Guid seq = seq {
438548
let recurse = EnumerateKeys outOfCore

0 commit comments

Comments
 (0)