1 package com.github.davidmoten.rtree.fbs;
2
3 import static com.github.davidmoten.rtree.fbs.FlatBuffersHelper.createBox;
4 import static com.github.davidmoten.rtree.fbs.FlatBuffersHelper.parseObject;
5 import static com.github.davidmoten.rtree.fbs.FlatBuffersHelper.toGeometry;
6
7 import java.util.ArrayList;
8 import java.util.List;
9
10 import com.github.davidmoten.guavamini.Preconditions;
11 import com.github.davidmoten.rtree.Context;
12 import com.github.davidmoten.rtree.Entries;
13 import com.github.davidmoten.rtree.Entry;
14 import com.github.davidmoten.rtree.Node;
15 import com.github.davidmoten.rtree.NonLeaf;
16 import com.github.davidmoten.rtree.fbs.generated.BoundsType_;
17 import com.github.davidmoten.rtree.fbs.generated.Bounds_;
18 import com.github.davidmoten.rtree.fbs.generated.BoxDouble_;
19 import com.github.davidmoten.rtree.fbs.generated.BoxFloat_;
20 import com.github.davidmoten.rtree.fbs.generated.Entry_;
21 import com.github.davidmoten.rtree.fbs.generated.Geometry_;
22 import com.github.davidmoten.rtree.fbs.generated.Node_;
23 import com.github.davidmoten.rtree.geometry.Geometries;
24 import com.github.davidmoten.rtree.geometry.Geometry;
25 import com.github.davidmoten.rtree.geometry.Rectangle;
26 import com.github.davidmoten.rtree.internal.NodeAndEntries;
27 import com.github.davidmoten.rtree.internal.NonLeafHelper;
28
29 import rx.Subscriber;
30 import rx.functions.Func1;
31
32 final class NonLeafFlatBuffers<T, S extends Geometry> implements NonLeaf<T, S> {
33
34 private final Node_ node;
35 private final Context<T, S> context;
36 private final Func1<byte[], ? extends T> deserializer;
37
38 NonLeafFlatBuffers(Node_ node, Context<T, S> context, Func1<byte[], ? extends T> deserializer) {
39 Preconditions.checkNotNull(node);
40
41
42 this.node = node;
43 this.context = context;
44 this.deserializer = deserializer;
45 }
46
47 @Override
48 public List<Node<T, S>> add(Entry<? extends T, ? extends S> entry) {
49 return NonLeafHelper.add(entry, this);
50 }
51
52 @Override
53 public NodeAndEntries<T, S> delete(Entry<? extends T, ? extends S> entry, boolean all) {
54 return NonLeafHelper.delete(entry, all, this);
55 }
56
57 @Override
58 public void searchWithoutBackpressure(Func1<? super Geometry, Boolean> criterion,
59 Subscriber<? super Entry<T, S>> subscriber) {
60
61
62
63 searchWithoutBackpressure(node, criterion, subscriber, deserializer, new Entry_(),
64 new Geometry_(), new Bounds_());
65 }
66
67 @SuppressWarnings("unchecked")
68 private static <T, S extends Geometry> void searchWithoutBackpressure(Node_ node,
69 Func1<? super Geometry, Boolean> criterion, Subscriber<? super Entry<T, S>> subscriber,
70 Func1<byte[], ? extends T> deserializer, Entry_ entry, Geometry_ geometry,
71 Bounds_ bounds) {
72 {
73
74 node.mbb(bounds);
75 final Rectangle rect;
76 if (bounds.type() == BoundsType_.BoundsDouble) {
77 BoxDouble_ b = bounds.boxDouble();
78 rect = Geometries.rectangle(b.minX(), b.minY(), b.maxX(), b.maxY());
79 } else {
80 BoxFloat_ b = bounds.boxFloat();
81 rect = Geometries.rectangle(b.minX(), b.minY(), b.maxX(), b.maxY());
82 }
83 if (!criterion.call(rect)) {
84 return;
85 }
86 }
87 int numChildren = node.childrenLength();
88
89 Node_ child = new Node_();
90 if (numChildren > 0) {
91 for (int i = 0; i < numChildren; i++) {
92 if (subscriber.isUnsubscribed())
93 return;
94 node.children(child, i);
95 searchWithoutBackpressure(child, criterion, subscriber, deserializer, entry,
96 geometry, bounds);
97 }
98 } else {
99 int numEntries = node.entriesLength();
100
101
102 for (int i = 0; i < numEntries; i++) {
103 if (subscriber.isUnsubscribed())
104 return;
105
106 node.entries(entry, i);
107
108 entry.geometry(geometry);
109 final Geometry g = toGeometry(geometry);
110 if (criterion.call(g)) {
111 T t = parseObject(deserializer, entry);
112 Entry<T, S> ent = Entries.entry(t, (S) g);
113 subscriber.onNext(ent);
114 }
115 }
116 }
117
118 }
119
120 private List<Node<T, S>> createChildren() {
121
122
123 int numChildren = node.childrenLength();
124 List<Node<T, S>> children = new ArrayList<Node<T, S>>(numChildren);
125 for (int i = 0; i < numChildren; i++) {
126 Node_ child = node.children(i);
127 if (child.childrenLength() > 0) {
128 children.add(new NonLeafFlatBuffers<T, S>(child, context, deserializer));
129 } else {
130 children.add(new LeafFlatBuffers<T, S>(child, context, deserializer));
131 }
132 }
133 return children;
134 }
135
136 @Override
137 public int count() {
138 return node.childrenLength();
139 }
140
141 @Override
142 public Context<T, S> context() {
143 return context;
144 }
145
146 @Override
147 public Geometry geometry() {
148 return FlatBuffersHelper.createBox(node.mbb());
149 }
150
151 @Override
152 public Node<T, S> child(int i) {
153 Node_ child = node.children(i);
154 if (child.childrenLength() > 0)
155 return new NonLeafFlatBuffers<T, S>(child, context, deserializer);
156 else
157 return new LeafFlatBuffers<T, S>(child, context, deserializer);
158 }
159
160 @Override
161 public List<Node<T, S>> children() {
162 return createChildren();
163 }
164
165 @Override
166 public String toString() {
167 return "Node [" + (node.childrenLength() > 0 ? "NonLeaf" : "Leaf") + ","
168 + createBox(node.mbb()).toString() + "]";
169 }
170
171 }