Skip to content

Commit

Permalink
masks (implementation completed, all tests green again)
Browse files Browse the repository at this point in the history
  • Loading branch information
stefanmaierhofer committed Nov 15, 2023
1 parent 9e40625 commit b43e978
Show file tree
Hide file tree
Showing 9 changed files with 215 additions and 159 deletions.
3 changes: 3 additions & 0 deletions RELEASE_NOTES.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
### 0.4.4
- Builder (creates quadtree from many small patches)

### 0.4.3
- fix queries

Expand Down
3 changes: 2 additions & 1 deletion src/Aardvark.Geometry.Quadtree/Builder.fs
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,8 @@ module Builder =
| _ -> build' sampleExponent subCell subPatches
)

let result = { Id = Guid.NewGuid(); ExactBoundingBox = ebb; Cell = rootCell; SplitLimitExponent = BuildConfig.Default.SplitLimitPowerOfTwo; SubNodes = subNodes }
let hasMask = subNodes |> Array.exists (fun n -> n.HasMask)
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.
Expand Down
2 changes: 1 addition & 1 deletion src/Aardvark.Geometry.Quadtree/Defs.fs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
open Aardvark.Data
open Aardvark.Base
open System
open System.Runtime.InteropServices
open System.Runtime.CompilerServices

#nowarn "44"
Expand Down Expand Up @@ -32,6 +31,7 @@ module Defs =
let OriginalSampleExponent = def "16c41f1d-0c31-4ef8-b22b-36276d2f2e45" "Quadtree.OriginalSampleExponent" "Quadtree. Power-of-two original sample exponent. Int32." Durable.Primitives.Int32
let Layers = def "c39a978b-00f5-485f-b0b3-d2cf9599016b" "Quadtree.Layers" "A quadtree node's layers. DurableMapAligned16." Durable.Primitives.DurableMapAligned16
let ExactBoundingBox = def "abd1f1e6-7165-44d2-8019-fde4f59c9c9f" "Quadtree.ExactBoundingBox" "Quadtree. Exact bounds of original (most detailed) data. Box2d." Durable.Aardvark.Box2d
let HasMask = def "fcfdf5b0-af9c-407b-9855-0a743edae77b" "Quadtree.HasMask" "Quadtree. 1 if subtree has any masks, otherwise 0." Durable.Primitives.Int32
let SubnodeIds = def "a2841629-e4e2-4b90-bdd1-7a1a5a41bded" "Quadtree.SubnodeIds" "Quadtree. Subnodes as array of guids. Array length is 4 for inner nodes (where Guid.Empty means no subnode) and no array for leaf nodes. Guid[]." Durable.Primitives.GuidArray

let Dominance = def "e782ace4-f2dd-4bc1-b8ad-5abad87f4ff1" "Quadtree.Dominance" "Quadtree. Dominance mode for quadtree merges. Guid." Durable.Primitives.GuidDef
Expand Down
32 changes: 12 additions & 20 deletions src/Aardvark.Geometry.Quadtree/Merge.fs
Original file line number Diff line number Diff line change
Expand Up @@ -79,22 +79,14 @@ module Merge =

let winner dom (first : QNodeRef) (second : QNodeRef) : QNodeRef option =

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
if first.HasMask || second.HasMask then
None
else
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

/// Immutable merge.
Expand Down Expand Up @@ -160,11 +152,11 @@ module Merge =
match winner dom first second with
| Some w -> w
| None -> match first, second with
| NoNode, b -> b
| a, NoNode -> a
| NoNode, b -> b
| a, NoNode -> a

| OutOfCoreNode (_,a), OutOfCoreNode (_,b) -> merge dom (a()) (b())
| OutOfCoreNode (_,a), b -> merge dom (a()) (b )
| a, OutOfCoreNode (_,b) -> merge dom (a ) (b())
| OutOfCoreNode a, OutOfCoreNode b -> merge dom (a.Load()) (b.Load())
| OutOfCoreNode a, b -> merge dom (a.Load()) (b )
| a, OutOfCoreNode b -> merge dom (a ) (b.Load())

| _ -> mergeToCommonRoot dom first second
132 changes: 78 additions & 54 deletions src/Aardvark.Geometry.Quadtree/Node.fs
Original file line number Diff line number Diff line change
Expand Up @@ -109,12 +109,16 @@ and QNode(uid : Guid, exactBoundingBox : Box2d, cell : Cell2d, splitLimitExp : i
/// Returns 2.0 ^ SampleExponent.
member this.SampleSize with get() : float = layers.SampleSize

/// True if there is a layer with a mask.
member this.HasMask with get() : bool = layers.HasMask

and
QInnerNode = {
Id : Guid
ExactBoundingBox : Box2d
Cell : Cell2d
SplitLimitExponent : int
HasMask : bool
SubNodes : QNodeRef[]
}

Expand All @@ -124,21 +128,30 @@ and
ExactBoundingBox : Box2d
Cell : Cell2d
SplitLimitExponent : int
HasMask : bool
Dominance : Dominance
First : QNodeRef
Second : QNodeRef
}
and
QLinkedNode = {
Id : Guid
HasMask : bool
Target : QNodeRef
}
and

QOutOfCoreNode = {
Id : Guid
HasMask : bool
Load : unit -> QNodeRef
}
and

QNodeRef =
| NoNode
| InMemoryNode of QNode
| OutOfCoreNode of Guid * (unit -> QNodeRef)
| OutOfCoreNode of QOutOfCoreNode
| InMemoryInner of QInnerNode
| InMemoryMerge of QMergeNode
| LinkedNode of QLinkedNode
Expand All @@ -147,80 +160,89 @@ and
/// Forces property Id. Throws exception if NoNode.
member this.Id with get() =
match this with
| NoNode -> failwith "Id does not exist for NoNode. Error c48422a9-4df6-4d15-9dad-af075a1d52ac."
| InMemoryNode n -> n.Id
| NoNode -> failwith "Id does not exist for NoNode. Error c48422a9-4df6-4d15-9dad-af075a1d52ac."
| InMemoryNode n -> n.Id
| InMemoryInner n -> n.Id
| InMemoryMerge n -> n.Id
| OutOfCoreNode (_, load) -> load().Id
| LinkedNode n -> n.Id
| OutOfCoreNode n -> n.Load().Id
| LinkedNode n -> n.Id

/// Forces property Cell. Throws exception if NoNode.
member this.Cell with get() =
match this with
| NoNode -> failwith "Cell does not exist for NoNode. Error c48422a9-4df6-4d15-9dad-af075a1d52ac."
| InMemoryNode n -> n.Cell
| NoNode -> failwith "Cell does not exist for NoNode. Error c48422a9-4df6-4d15-9dad-af075a1d52ac."
| InMemoryNode n -> n.Cell
| InMemoryInner n -> n.Cell
| InMemoryMerge n -> n.Cell
| OutOfCoreNode (_, load) -> load().Cell
| LinkedNode n -> n.Target.Cell
| OutOfCoreNode n -> n.Load().Cell
| LinkedNode n -> n.Target.Cell

/// Returns node's exact bounding box, or invalid box for NoNode.
member this.ExactBoundingBox with get() =
match this with
| NoNode -> Box2d.Invalid
| InMemoryNode n -> n.ExactBoundingBox
| NoNode -> Box2d.Invalid
| InMemoryNode n -> n.ExactBoundingBox
| InMemoryInner n -> n.ExactBoundingBox
| InMemoryMerge n -> n.ExactBoundingBox
| OutOfCoreNode (_, load) -> load().ExactBoundingBox
| LinkedNode n -> n.Target.ExactBoundingBox
| OutOfCoreNode n -> n.Load().ExactBoundingBox
| LinkedNode n -> n.Target.ExactBoundingBox

/// Forces property SplitLimitExp. Throws exception if NoNode.
member this.SplitLimitExponent with get() =
match this with
| NoNode -> failwith "SplitLimitExp does not exist for NoNode. Error 4424a37e-dcd8-4ae0-975c-7ae6d926aaa8."
| InMemoryNode n -> n.SplitLimitExponent
| NoNode -> failwith "SplitLimitExp does not exist for NoNode. Error 4424a37e-dcd8-4ae0-975c-7ae6d926aaa8."
| InMemoryNode n -> n.SplitLimitExponent
| InMemoryInner n -> n.SplitLimitExponent
| InMemoryMerge n -> n.SplitLimitExponent
| OutOfCoreNode (_, load) -> load().SplitLimitExponent
| LinkedNode n -> n.Target.SplitLimitExponent
| OutOfCoreNode n -> n.Load().SplitLimitExponent
| LinkedNode n -> n.Target.SplitLimitExponent

member this.GetFirstNonEmptySubNode() : QNodeRef option =
match this with
| NoNode -> None
| NoNode -> None
| InMemoryInner n -> n.SubNodes |> Array.tryFind (fun sn -> match sn with | NoNode -> false | _ -> true)
| InMemoryMerge n -> Some n.First
| InMemoryNode n -> None
| OutOfCoreNode (_, load) -> load().GetFirstNonEmptySubNode()
| LinkedNode n -> n.Target.GetFirstNonEmptySubNode()
| InMemoryNode _ -> None
| OutOfCoreNode n -> n.Load().GetFirstNonEmptySubNode()
| LinkedNode n -> n.Target.GetFirstNonEmptySubNode()

member this.ContainsLayer (semantic : Durable.Def) =
match this with
| NoNode -> false
| NoNode -> false
| InMemoryInner _ -> match this.GetFirstNonEmptySubNode() with
| Some n -> n.ContainsLayer(semantic)
| None -> failwith "Invariant 0a85f195-7feb-4ecb-912d-7fd4e7024951."
| InMemoryMerge _ -> false
| InMemoryNode n -> n.ContainsLayer semantic
| OutOfCoreNode (_, load) -> load().ContainsLayer semantic
| LinkedNode n -> n.Target.ContainsLayer semantic
| InMemoryNode n -> n.ContainsLayer semantic
| OutOfCoreNode n -> n.Load().ContainsLayer semantic
| LinkedNode n -> n.Target.ContainsLayer semantic

member this.LayerSet with get() : LayerSet option =
match this with
| NoNode -> None
| NoNode -> None
| InMemoryInner _ -> None
| InMemoryMerge _ -> None
| InMemoryNode n -> Some(n.LayerSet)
| OutOfCoreNode (_, load) -> load().LayerSet
| LinkedNode n -> n.Target.LayerSet
| InMemoryNode n -> Some(n.LayerSet)
| OutOfCoreNode n -> n.Load().LayerSet
| LinkedNode n -> n.Target.LayerSet

member this.IsLeafNode with get() =
match this with
| NoNode -> false
| InMemoryInner _ -> false
| InMemoryMerge _ -> false
| InMemoryNode _ -> true
| InMemoryNode _ -> true
| OutOfCoreNode _ -> true
| LinkedNode n -> n.Target.IsLeafNode
| LinkedNode n -> n.Target.IsLeafNode

member this.HasMask with get() =
match this with
| NoNode -> false
| InMemoryInner n -> n.HasMask
| InMemoryMerge n -> n.HasMask
| InMemoryNode n -> n.HasMask
| OutOfCoreNode n -> n.HasMask
| LinkedNode n -> n.Target.HasMask

/// Replace all occurences of 'oldSemantic' with 'newSemantic'.
/// Returns (true, <newUpdatedOctree>) if 'oldSemantic' exists and is replaced.
Expand Down Expand Up @@ -258,7 +280,7 @@ and
| Some qnode -> (true, InMemoryNode qnode)
| None -> unchanged

| OutOfCoreNode (_, load) -> load() |> qnode
| OutOfCoreNode n -> n.Load() |> qnode

| LinkedNode n -> n.Target.UpdateLayerSemantic (oldSemantic, newSemantic)

Expand All @@ -267,42 +289,42 @@ and
match this with
| NoNode
| InMemoryInner _
| InMemoryMerge _ -> sprintf "Layer not found. %A. Error 2c634f5f-d359-4523-b87a-a96d2522c018." def |> failwith
| InMemoryNode n -> n.LayerSet.GetLayer def
| OutOfCoreNode (_, load) -> load().LayerSet.Value.GetLayer def
| LinkedNode n -> n.Target.GetLayer def
| InMemoryMerge _ -> sprintf "Layer not found. %A. Error 2c634f5f-d359-4523-b87a-a96d2522c018." def |> failwith
| InMemoryNode n -> n.LayerSet.GetLayer def
| OutOfCoreNode n -> n.Load().LayerSet.Value.GetLayer def
| LinkedNode n -> n.Target.GetLayer def

/// Throws if no such layer.
member this.GetLayer<'a when 'a : equality> def =
match this with
| NoNode
| InMemoryInner _
| InMemoryMerge _ -> sprintf "Layer not found. %A. Error f33f39a9-2394-473f-8dae-76bd8baaaafb." def |> failwith
| InMemoryNode n -> n.LayerSet.GetLayer<'a> def
| OutOfCoreNode (_, load) -> load().LayerSet.Value.GetLayer<'a> def
| LinkedNode n -> n.Target.GetLayer<'a> def
| InMemoryMerge _ -> sprintf "Layer not found. %A. Error f33f39a9-2394-473f-8dae-76bd8baaaafb." def |> failwith
| InMemoryNode n -> n.LayerSet.GetLayer<'a> def
| OutOfCoreNode n -> n.Load().LayerSet.Value.GetLayer<'a> def
| LinkedNode n -> n.Target.GetLayer<'a> def

member this.TryGetLayer def =
match this with
| NoNode
| InMemoryInner _
| InMemoryMerge _ -> None
| InMemoryNode n -> n.LayerSet.TryGetLayer def
| OutOfCoreNode (_, load) -> match load().LayerSet with
| Some ls -> ls.TryGetLayer def
| None -> None
| LinkedNode n -> n.Target.TryGetLayer def
| InMemoryMerge _ -> None
| InMemoryNode n -> n.LayerSet.TryGetLayer def
| OutOfCoreNode n -> match n.Load().LayerSet with
| Some ls -> ls.TryGetLayer def
| None -> None
| LinkedNode n -> n.Target.TryGetLayer def

member this.TryGetLayer<'a when 'a : equality> def =
match this with
| NoNode
| InMemoryInner _
| InMemoryMerge _ -> None
| InMemoryNode n -> n.LayerSet.TryGetLayer<'a> def
| OutOfCoreNode (_, load) -> match load().LayerSet with
| Some ls -> ls.TryGetLayer<'a> def
| None -> None
| LinkedNode n -> n.Target.TryGetLayer<'a> def
| InMemoryMerge _ -> None
| InMemoryNode n -> n.LayerSet.TryGetLayer<'a> def
| OutOfCoreNode n -> match n.Load().LayerSet with
| Some ls -> ls.TryGetLayer<'a> def
| None -> None
| LinkedNode n -> n.Target.TryGetLayer<'a> def

module QNode =

Expand All @@ -320,7 +342,7 @@ module QInnerNode =
| Some qi ->
let ns = Array.create 4 NoNode
ns.[qi] <- n
{ Id = Guid.NewGuid(); ExactBoundingBox = n.ExactBoundingBox; Cell = rc; SplitLimitExponent = n.SplitLimitExponent; SubNodes = ns }
{ Id = Guid.NewGuid(); ExactBoundingBox = n.ExactBoundingBox; Cell = rc; SplitLimitExponent = n.SplitLimitExponent; HasMask = n.HasMask; SubNodes = ns }

let ofSubNodes (ns : QNodeRef[]) : QInnerNode =
invariant (ns.Length = 4) "acf0afb0-5d73-4827-acca-e1707ec6db5a"
Expand All @@ -336,7 +358,8 @@ module QInnerNode =

let ebb = ns' |> Seq.map(fun n -> n.ExactBoundingBox) |> Box2d

{ Id = Guid.NewGuid(); ExactBoundingBox = ebb; Cell = rc; SplitLimitExponent = ns'.[0].SplitLimitExponent; SubNodes = ns }
let hasMask = ns |> Array.exists (fun n -> n.HasMask)
{ Id = Guid.NewGuid(); ExactBoundingBox = ebb; Cell = rc; SplitLimitExponent = ns'.[0].SplitLimitExponent; HasMask = hasMask; SubNodes = ns }


module QMergeNode =
Expand All @@ -356,6 +379,7 @@ module QMergeNode =
{
Id = Guid.NewGuid()
ExactBoundingBox = ebb; Cell = cell; SplitLimitExponent = first.SplitLimitExponent
HasMask = first.HasMask || second.HasMask
Dominance = dom; First = first; Second = second
}

Expand Down
Loading

0 comments on commit b43e978

Please sign in to comment.