public boolean isEmpty() { return !head.isPresent(); }
private static <T, S extends Geometry> int calculateDepth(Optional<? extends Node<T, S>> root) { if (!root.isPresent()) return 0; else return calculateDepth(root.get(), 0); }
public BufferedImage createImage() { final BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); final Graphics2D g = (Graphics2D) image.getGraphics(); g.setBackground(Color.white); g.clearRect(0, 0, width, height); g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.75f)); if (tree.root().isPresent()) { final List<RectangleDepth> nodeDepths = getNodeDepthsSortedByDepth(tree.root().get()); drawNode(g, nodeDepths); } return image; }
private static <R, S extends Geometry> int calculateMaxDepth( Optional<? extends Node<R, S>> root) { if (!root.isPresent()) return 0; else return calculateDepth(root.get(), 0); }
/** * Returns a human readable form of the RTree. Here's an example: * * <pre> * mbr=Rectangle [x1=10.0, y1=4.0, x2=62.0, y2=85.0] * mbr=Rectangle [x1=28.0, y1=4.0, x2=34.0, y2=85.0] * entry=Entry [value=2, geometry=Point [x=29.0, y=4.0]] * entry=Entry [value=1, geometry=Point [x=28.0, y=19.0]] * entry=Entry [value=4, geometry=Point [x=34.0, y=85.0]] * mbr=Rectangle [x1=10.0, y1=45.0, x2=62.0, y2=63.0] * entry=Entry [value=5, geometry=Point [x=62.0, y=45.0]] * entry=Entry [value=3, geometry=Point [x=10.0, y=63.0]] * </pre> * * @return a string representation of the RTree */ public String asString() { if (!root.isPresent()) return ""; else return asString(root.get(), ""); }
@Override public boolean equals(Object obj) { @SuppressWarnings("rawtypes") Optional<EntryDefault> other = ObjectsHelper.asClass(obj, EntryDefault.class); if (other.isPresent()) { return Objects.equal(value, other.get().value) && Objects.equal(geometry, other.get().geometry); } else return false; }
/** * If the RTree has no entries returns {@link Optional#absent} otherwise returns * the minimum bounding rectangle of all entries in the RTree. * * @return minimum bounding rectangle of all entries in RTree */ public Optional<Rectangle> mbr() { if (!root.isPresent()) return absent(); else return of(root.get().geometry().mbr()); }
/** * Returns an immutable copy of the RTree with the addition of given entry. * * @param entry * item to add to the R-tree. * @return a new immutable R-tree including the new entry */ @SuppressWarnings("unchecked") public RTree<T, S> add(Entry<? extends T, ? extends S> entry) { if (root.isPresent()) { List<Node<T, S>> nodes = root.get().add(entry); Node<T, S> node; if (nodes.size() == 1) node = nodes.get(0); else { node = context.factory().createNonLeaf(nodes, context); } return new RTree<T, S>(node, size + 1, context); } else { Leaf<T, S> node = context.factory().createLeaf(Lists.newArrayList((Entry<T, S>) entry), context); return new RTree<T, S>(node, size + 1, context); } }
/** * Deletes one or all matching entries depending on the value of * <code>all</code>. If multiple copies of the entry are in the R-tree only one * will be deleted if all is false otherwise all matching entries will be * deleted. The entry must match on both value and geometry to be deleted. * * @param entry * the {@link Entry} to be deleted * @param all * if true deletes all matches otherwise deletes first found * @return a new immutable R-tree without one instance of the specified entry */ public RTree<T, S> delete(Entry<? extends T, ? extends S> entry, boolean all) { if (root.isPresent()) { NodeAndEntries<T, S> nodeAndEntries = root.get().delete(entry, all); if (nodeAndEntries.node().isPresent() && nodeAndEntries.node().get() == root.get()) return this; else return new RTree<T, S>(nodeAndEntries.node(), size - nodeAndEntries.countDeleted() - nodeAndEntries.entriesToAdd().size(), context).add(nodeAndEntries.entriesToAdd()); } else return this; }
@Override public boolean equals(Object obj) { Optional<CircleDouble> other = ObjectsHelper.asClass(obj, CircleDouble.class); if (other.isPresent()) { return Objects.equal(x, other.get().x) && Objects.equal(y, other.get().y) && Objects.equal(radius, other.get().radius); } else return false; }
@Override public boolean equals(Object obj) { Optional<CircleFloat> other = ObjectsHelper.asClass(obj, CircleFloat.class); if (other.isPresent()) { return Objects.equal(x, other.get().x) && Objects.equal(y, other.get().y) && Objects.equal(radius, other.get().radius); } else return false; }
/** * <p> * Returns an Observable sequence of {@link Entry} that satisfy the given * condition. Note that this method is well-behaved only if: * * * <p> * {@code condition(g)} is true for {@link Geometry} g implies * {@code condition(r)} is true for the minimum bounding rectangles of the * ancestor nodes. * * <p> * {@code distance(g) < D} is an example of such a condition. * * * @param condition * return Entries whose geometry satisfies the given condition * @return sequence of matching entries */ @VisibleForTesting Observable<Entry<T, S>> search(Func1<? super Geometry, Boolean> condition) { if (root.isPresent()) return Observable.unsafeCreate(new OnSubscribeSearch<T, S>(root.get(), condition)); else return Observable.empty(); }
@Override public Optional<Rectangle> call(Optional<Rectangle> r, Entry<T, S> entry) { if (r.isPresent()) return of(r.get().add(entry.geometry().mbr())); else return of(entry.geometry().mbr()); } }).toBlocking().single().or(rectangle(0, 0, 0, 0));
@Override public boolean equals(Object obj) { Optional<RectangleDouble> other = ObjectsHelper.asClass(obj, RectangleDouble.class); if (other.isPresent()) { return Objects.equal(x1, other.get().x1) && Objects.equal(x2, other.get().x2) && Objects.equal(y1, other.get().y1) && Objects.equal(y2, other.get().y2); } else return false; }
@Override public boolean equals(Object obj) { Optional<LineDouble> other = ObjectsHelper.asClass(obj, LineDouble.class); if (other.isPresent()) { return Objects.equal(x1, other.get().x1) && Objects.equal(x2, other.get().x2) && Objects.equal(y1, other.get().y1) && Objects.equal(y2, other.get().y2); } else return false; }
@Override public boolean equals(Object obj) { Optional<RectangleFloat> other = ObjectsHelper.asClass(obj, RectangleFloat.class); if (other.isPresent()) { return Objects.equal(x1, other.get().x1) && Objects.equal(x2, other.get().x2) && Objects.equal(y1, other.get().y1) && Objects.equal(y2, other.get().y2); } else return false; }
@Override public boolean equals(Object obj) { Optional<LineFloat> other = ObjectsHelper.asClass(obj, LineFloat.class); if (other.isPresent()) { return Objects.equal(x1, other.get().x1) && Objects.equal(x2, other.get().x2) && Objects.equal(y1, other.get().y1) && Objects.equal(y2, other.get().y2); } else return false; }
@VisibleForTesting static <T extends HasGeometry> T getBestCandidateForGroup(List<T> list, List<T> group, Rectangle groupMbr) { // TODO reduce allocations by not using Optional Optional<T> minEntry = absent(); Optional<Double> minArea = absent(); for (final T entry : list) { final double area = groupMbr.add(entry.geometry().mbr()).area(); if (!minArea.isPresent() || area < minArea.get()) { minArea = of(area); minEntry = of(entry); } } return minEntry.get(); }