LUCENE-4742: Rename spatial Node back to Cell

git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1462090 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
David Wayne Smiley 2013-03-28 13:44:09 +00:00
parent 6448dce4ea
commit 56a18440e2
12 changed files with 146 additions and 146 deletions

View File

@ -21,7 +21,7 @@ import com.spatial4j.core.shape.Shape;
import org.apache.lucene.index.AtomicReaderContext;
import org.apache.lucene.index.TermsEnum;
import org.apache.lucene.search.DocIdSet;
import org.apache.lucene.spatial.prefix.tree.Node;
import org.apache.lucene.spatial.prefix.tree.Cell;
import org.apache.lucene.spatial.prefix.tree.SpatialPrefixTree;
import org.apache.lucene.util.Bits;
import org.apache.lucene.util.BytesRef;
@ -84,13 +84,13 @@ public abstract class AbstractVisitingPrefixTreeFilter extends AbstractPrefixTre
* that there are indexed terms; if not it quickly returns null. Then it calls
* {@link #start()} so a subclass can set up a return value, like an
* {@link org.apache.lucene.util.OpenBitSet}. Then it starts the traversal
* process, calling {@link #findSubCellsToVisit(org.apache.lucene.spatial.prefix.tree.Node)}
* process, calling {@link #findSubCellsToVisit(org.apache.lucene.spatial.prefix.tree.Cell)}
* which by default finds the top cells that intersect {@code queryShape}. If
* there isn't an indexed cell for a corresponding cell returned for this
* method then it's short-circuited until it finds one, at which point
* {@link #visit(org.apache.lucene.spatial.prefix.tree.Node)} is called. At
* {@link #visit(org.apache.lucene.spatial.prefix.tree.Cell)} is called. At
* some depths, of the tree, the algorithm switches to a scanning mode that
* finds calls {@link #visitScanned(org.apache.lucene.spatial.prefix.tree.Node)}
* finds calls {@link #visitScanned(org.apache.lucene.spatial.prefix.tree.Cell)}
* for each leaf cell found.
*
* @lucene.internal
@ -113,7 +113,7 @@ public abstract class AbstractVisitingPrefixTreeFilter extends AbstractPrefixTre
private VNode curVNode;//current pointer, derived from query shape
private BytesRef curVNodeTerm = new BytesRef();//curVNode.cell's term.
private Node scanCell;
private Cell scanCell;
private BytesRef thisTerm;//the result of termsEnum.term()
@ -132,7 +132,7 @@ public abstract class AbstractVisitingPrefixTreeFilter extends AbstractPrefixTre
return null; // all done
curVNode = new VNode(null);
curVNode.reset(grid.getWorldNode());
curVNode.reset(grid.getWorldCell());
start();
@ -198,11 +198,11 @@ public abstract class AbstractVisitingPrefixTreeFilter extends AbstractPrefixTre
return finish();
}
/** Called initially, and whenever {@link #visit(org.apache.lucene.spatial.prefix.tree.Node)}
/** Called initially, and whenever {@link #visit(org.apache.lucene.spatial.prefix.tree.Cell)}
* returns true. */
private void addIntersectingChildren() throws IOException {
assert thisTerm != null;
Node cell = curVNode.cell;
Cell cell = curVNode.cell;
if (cell.getLevel() >= detailLevel)
throw new IllegalStateException("Spatial logic error");
@ -211,7 +211,7 @@ public abstract class AbstractVisitingPrefixTreeFilter extends AbstractPrefixTre
//If the next indexed term just adds a leaf marker ('+') to cell,
// then add all of those docs
assert StringHelper.startsWith(thisTerm, curVNodeTerm);
scanCell = grid.getNode(thisTerm.bytes, thisTerm.offset, thisTerm.length, scanCell);
scanCell = grid.getCell(thisTerm.bytes, thisTerm.offset, thisTerm.length, scanCell);
if (scanCell.getLevel() == cell.getLevel() && scanCell.isLeaf()) {
visitLeaf(scanCell);
//advance
@ -230,7 +230,7 @@ public abstract class AbstractVisitingPrefixTreeFilter extends AbstractPrefixTre
if (!scan) {
//Divide & conquer (ultimately termsEnum.seek())
Iterator<Node> subCellsIter = findSubCellsToVisit(cell);
Iterator<Cell> subCellsIter = findSubCellsToVisit(cell);
if (!subCellsIter.hasNext())//not expected
return;
curVNode.children = new VNodeCellIterator(subCellsIter, new VNode(curVNode));
@ -248,7 +248,7 @@ public abstract class AbstractVisitingPrefixTreeFilter extends AbstractPrefixTre
* guaranteed to have an intersection and thus this must return some number
* of nodes.
*/
protected Iterator<Node> findSubCellsToVisit(Node cell) {
protected Iterator<Cell> findSubCellsToVisit(Cell cell) {
return cell.getSubCells(queryShape).iterator();
}
@ -256,13 +256,13 @@ public abstract class AbstractVisitingPrefixTreeFilter extends AbstractPrefixTre
* Scans ({@code termsEnum.next()}) terms until a term is found that does
* not start with curVNode's cell. If it finds a leaf cell or a cell at
* level {@code scanDetailLevel} then it calls {@link
* #visitScanned(org.apache.lucene.spatial.prefix.tree.Node)}.
* #visitScanned(org.apache.lucene.spatial.prefix.tree.Cell)}.
*/
protected void scan(int scanDetailLevel) throws IOException {
for (;
thisTerm != null && StringHelper.startsWith(thisTerm, curVNodeTerm);
thisTerm = termsEnum.next()) {
scanCell = grid.getNode(thisTerm.bytes, thisTerm.offset, thisTerm.length, scanCell);
scanCell = grid.getCell(thisTerm.bytes, thisTerm.offset, thisTerm.length, scanCell);
int termLevel = scanCell.getLevel();
if (termLevel > scanDetailLevel)
@ -276,10 +276,10 @@ public abstract class AbstractVisitingPrefixTreeFilter extends AbstractPrefixTre
/** Used for {@link VNode#children}. */
private class VNodeCellIterator implements Iterator<VNode> {
final Iterator<Node> cellIter;
final Iterator<Cell> cellIter;
private final VNode vNode;
VNodeCellIterator(Iterator<Node> cellIter, VNode vNode) {
VNodeCellIterator(Iterator<Cell> cellIter, VNode vNode) {
this.cellIter = cellIter;
this.vNode = vNode;
}
@ -309,26 +309,26 @@ public abstract class AbstractVisitingPrefixTreeFilter extends AbstractPrefixTre
/**
* Visit an indexed cell returned from
* {@link #findSubCellsToVisit(org.apache.lucene.spatial.prefix.tree.Node)}.
* {@link #findSubCellsToVisit(org.apache.lucene.spatial.prefix.tree.Cell)}.
*
* @param cell An intersecting cell.
* @return true to descend to more levels. It is an error to return true
* if cell.level == detailLevel
*/
protected abstract boolean visit(Node cell) throws IOException;
protected abstract boolean visit(Cell cell) throws IOException;
/**
* Called after visit() returns true and an indexed leaf cell is found. An
* indexed leaf cell means associated documents generally won't be found at
* further detail levels.
*/
protected abstract void visitLeaf(Node cell) throws IOException;
protected abstract void visitLeaf(Cell cell) throws IOException;
/**
* The cell is either indexed as a leaf or is the last level of detail. It
* might not even intersect the query shape, so be sure to check for that.
*/
protected abstract void visitScanned(Node cell) throws IOException;
protected abstract void visitScanned(Cell cell) throws IOException;
protected void preSiblings(VNode vNode) throws IOException {
@ -339,7 +339,7 @@ public abstract class AbstractVisitingPrefixTreeFilter extends AbstractPrefixTre
}//class VisitorTemplate
/**
* A Visitor Node/Cell found via the query shape for {@link VisitorTemplate}.
* A Visitor Cell/Cell found via the query shape for {@link VisitorTemplate}.
* Sometimes these are reset(cell). It's like a LinkedList node but forms a
* tree.
*
@ -353,7 +353,7 @@ public abstract class AbstractVisitingPrefixTreeFilter extends AbstractPrefixTre
final VNode parent;//only null at the root
Iterator<VNode> children;//null, then sometimes set, then null
Node cell;//not null (except initially before reset())
Cell cell;//not null (except initially before reset())
/**
* call reset(cell) after to set the cell.
@ -362,7 +362,7 @@ public abstract class AbstractVisitingPrefixTreeFilter extends AbstractPrefixTre
this.parent = parent;
}
void reset(Node cell) {
void reset(Cell cell) {
assert cell != null;
this.cell = cell;
assert children == null;

View File

@ -21,7 +21,7 @@ import com.spatial4j.core.shape.Shape;
import com.spatial4j.core.shape.SpatialRelation;
import org.apache.lucene.index.AtomicReaderContext;
import org.apache.lucene.search.DocIdSet;
import org.apache.lucene.spatial.prefix.tree.Node;
import org.apache.lucene.spatial.prefix.tree.Cell;
import org.apache.lucene.spatial.prefix.tree.SpatialPrefixTree;
import org.apache.lucene.util.Bits;
import org.apache.lucene.util.FixedBitSet;
@ -66,7 +66,7 @@ public class IntersectsPrefixTreeFilter extends AbstractVisitingPrefixTreeFilter
}
@Override
protected boolean visit(Node cell) throws IOException {
protected boolean visit(Cell cell) throws IOException {
if (cell.getShapeRel() == SpatialRelation.WITHIN || cell.getLevel() == detailLevel) {
collectDocs(results);
return false;
@ -75,12 +75,12 @@ public class IntersectsPrefixTreeFilter extends AbstractVisitingPrefixTreeFilter
}
@Override
protected void visitLeaf(Node cell) throws IOException {
protected void visitLeaf(Cell cell) throws IOException {
collectDocs(results);
}
@Override
protected void visitScanned(Node cell) throws IOException {
protected void visitScanned(Cell cell) throws IOException {
Shape cShape;
//if this cell represents a point, use the cell center vs the box
// TODO this behavior is debatable; might want to be configurable

View File

@ -1,3 +1,5 @@
package org.apache.lucene.spatial.prefix;
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
@ -15,10 +17,8 @@
* limitations under the License.
*/
package org.apache.lucene.spatial.prefix;
import com.spatial4j.core.shape.Point;
import org.apache.lucene.spatial.prefix.tree.Node;
import org.apache.lucene.spatial.prefix.tree.Cell;
import org.apache.lucene.spatial.prefix.tree.SpatialPrefixTree;
import org.apache.lucene.spatial.util.ShapeFieldCacheProvider;
import org.apache.lucene.util.BytesRef;
@ -40,11 +40,11 @@ public class PointPrefixTreeFieldCacheProvider extends ShapeFieldCacheProvider<P
this.grid = grid;
}
private Node scanCell = null;//re-used in readShape to save GC
private Cell scanCell = null;//re-used in readShape to save GC
@Override
protected Point readShape(BytesRef term) {
scanCell = grid.getNode(term.bytes, term.offset, term.length, scanCell);
scanCell = grid.getCell(term.bytes, term.offset, term.length, scanCell);
if (scanCell.getLevel() == grid.getMaxLevels() && !scanCell.isLeaf())
return scanCell.getCenter();
return null;

View File

@ -26,7 +26,7 @@ import org.apache.lucene.document.FieldType;
import org.apache.lucene.index.FieldInfo;
import org.apache.lucene.queries.function.ValueSource;
import org.apache.lucene.spatial.SpatialStrategy;
import org.apache.lucene.spatial.prefix.tree.Node;
import org.apache.lucene.spatial.prefix.tree.Cell;
import org.apache.lucene.spatial.prefix.tree.SpatialPrefixTree;
import org.apache.lucene.spatial.query.SpatialArgs;
import org.apache.lucene.spatial.util.ShapeFieldCacheDistanceValueSource;
@ -125,7 +125,7 @@ public abstract class PrefixTreeStrategy extends SpatialStrategy {
public Field[] createIndexableFields(Shape shape, double distErr) {
int detailLevel = grid.getLevelForDistance(distErr);
List<Node> cells = grid.getNodes(shape, detailLevel, true, simplifyIndexedCells);//intermediates cells
List<Cell> cells = grid.getCells(shape, detailLevel, true, simplifyIndexedCells);//intermediates cells
//TODO is CellTokenStream supposed to be re-used somehow? see Uwe's comments:
// http://code.google.com/p/lucene-spatial-playground/issues/detail?id=4
@ -151,9 +151,9 @@ public abstract class PrefixTreeStrategy extends SpatialStrategy {
private final CharTermAttribute termAtt = addAttribute(CharTermAttribute.class);
private Iterator<Node> iter = null;
private Iterator<Cell> iter = null;
public CellTokenStream(Iterator<Node> tokens) {
public CellTokenStream(Iterator<Cell> tokens) {
this.iter = tokens;
}
@ -164,12 +164,12 @@ public abstract class PrefixTreeStrategy extends SpatialStrategy {
clearAttributes();
if (nextTokenStringNeedingLeaf != null) {
termAtt.append(nextTokenStringNeedingLeaf);
termAtt.append((char) Node.LEAF_BYTE);
termAtt.append((char) Cell.LEAF_BYTE);
nextTokenStringNeedingLeaf = null;
return true;
}
if (iter.hasNext()) {
Node cell = iter.next();
Cell cell = iter.next();
CharSequence token = cell.getTokenString();
termAtt.append(token);
if (cell.isLeaf())

View File

@ -20,7 +20,7 @@ package org.apache.lucene.spatial.prefix;
import com.spatial4j.core.shape.Shape;
import org.apache.lucene.queries.TermsFilter;
import org.apache.lucene.search.Filter;
import org.apache.lucene.spatial.prefix.tree.Node;
import org.apache.lucene.spatial.prefix.tree.Cell;
import org.apache.lucene.spatial.prefix.tree.SpatialPrefixTree;
import org.apache.lucene.spatial.query.SpatialArgs;
import org.apache.lucene.spatial.query.SpatialOperation;
@ -31,7 +31,7 @@ import java.util.List;
/**
* A basic implementation of {@link PrefixTreeStrategy} using a large {@link
* TermsFilter} of all the nodes from {@link SpatialPrefixTree#getNodes(com.spatial4j.core.shape.Shape,
* TermsFilter} of all the cells from {@link SpatialPrefixTree#getCells(com.spatial4j.core.shape.Shape,
* int, boolean, boolean)}. It only supports the search of indexed Point shapes.
* <p/>
* The precision of query shapes (distErrPct) is an important factor in using
@ -55,12 +55,12 @@ public class TermQueryPrefixTreeStrategy extends PrefixTreeStrategy {
Shape shape = args.getShape();
int detailLevel = grid.getLevelForDistance(args.resolveDistErr(ctx, distErrPct));
List<Node> cells = grid.getNodes(shape, detailLevel,
List<Cell> cells = grid.getCells(shape, detailLevel,
false,//no parents
true);//simplify
BytesRef[] terms = new BytesRef[cells.size()];
int i = 0;
for (Node cell : cells) {
for (Cell cell : cells) {
terms[i++] = new BytesRef(cell.getTokenString());
}
return new TermsFilter(getFieldName(), terms);

View File

@ -26,7 +26,7 @@ import com.spatial4j.core.shape.Shape;
import com.spatial4j.core.shape.SpatialRelation;
import org.apache.lucene.index.AtomicReaderContext;
import org.apache.lucene.search.DocIdSet;
import org.apache.lucene.spatial.prefix.tree.Node;
import org.apache.lucene.spatial.prefix.tree.Cell;
import org.apache.lucene.spatial.prefix.tree.SpatialPrefixTree;
import org.apache.lucene.util.Bits;
import org.apache.lucene.util.FixedBitSet;
@ -135,13 +135,13 @@ public class WithinPrefixTreeFilter extends AbstractVisitingPrefixTreeFilter {
}
@Override
protected Iterator<Node> findSubCellsToVisit(Node cell) {
protected Iterator<Cell> findSubCellsToVisit(Cell cell) {
//use buffered query shape instead of orig. Works with null too.
return cell.getSubCells(bufferedQueryShape).iterator();
}
@Override
protected boolean visit(Node cell) throws IOException {
protected boolean visit(Cell cell) throws IOException {
//cell.relate is based on the bufferedQueryShape; we need to examine what
// the relation is against the queryShape
visitRelation = cell.getShape().relate(queryShape);
@ -159,7 +159,7 @@ public class WithinPrefixTreeFilter extends AbstractVisitingPrefixTreeFilter {
}
@Override
protected void visitLeaf(Node cell) throws IOException {
protected void visitLeaf(Cell cell) throws IOException {
SpatialRelation relation = visitRelation;
assert visitRelation == cell.getShape().relate(queryShape);
if (relation.intersects()) {
@ -170,7 +170,7 @@ public class WithinPrefixTreeFilter extends AbstractVisitingPrefixTreeFilter {
}
@Override
protected void visitScanned(Node cell) throws IOException {
protected void visitScanned(Cell cell) throws IOException {
if (queryShape.relate(cell.getShape()).intersects()) {
collectDocs(inside);
} else {

View File

@ -32,7 +32,7 @@ import java.util.List;
*
* @lucene.experimental
*/
public abstract class Node implements Comparable<Node> {
public abstract class Cell implements Comparable<Cell> {
public static final byte LEAF_BYTE = '+';//NOTE: must sort before letters & numbers
/*
@ -58,7 +58,7 @@ public abstract class Node implements Comparable<Node> {
*/
protected boolean leaf;
protected Node(String token) {
protected Cell(String token) {
this.token = token;
if (token.length() > 0 && token.charAt(token.length() - 1) == (char) LEAF_BYTE) {
this.token = token.substring(0, token.length() - 1);
@ -69,7 +69,7 @@ public abstract class Node implements Comparable<Node> {
getShape();//ensure any lazy instantiation completes to make this threadsafe
}
protected Node(byte[] bytes, int off, int len) {
protected Cell(byte[] bytes, int off, int len) {
this.bytes = bytes;
this.b_off = off;
this.b_len = len;
@ -149,8 +149,8 @@ public abstract class Node implements Comparable<Node> {
* Like {@link #getSubCells()} but with the results filtered by a shape. If
* that shape is a {@link com.spatial4j.core.shape.Point} then it must call
* {@link #getSubCell(com.spatial4j.core.shape.Point)}. The returned cells
* should have {@link Node#getShapeRel()} set to their relation with {@code
* shapeFilter}. In addition, {@link org.apache.lucene.spatial.prefix.tree.Node#isLeaf()}
* should have {@link Cell#getShapeRel()} set to their relation with {@code
* shapeFilter}. In addition, {@link Cell#isLeaf()}
* must be true when that relation is WITHIN.
* <p/>
* Precondition: Never called when getLevel() == maxLevel.
@ -158,22 +158,22 @@ public abstract class Node implements Comparable<Node> {
* @param shapeFilter an optional filter for the returned cells.
* @return A set of cells (no dups), sorted. Not Modifiable.
*/
public Collection<Node> getSubCells(Shape shapeFilter) {
public Collection<Cell> getSubCells(Shape shapeFilter) {
//Note: Higher-performing subclasses might override to consider the shape filter to generate fewer cells.
if (shapeFilter instanceof Point) {
Node subCell = getSubCell((Point) shapeFilter);
Cell subCell = getSubCell((Point) shapeFilter);
subCell.shapeRel = SpatialRelation.CONTAINS;
return Collections.singletonList(subCell);
}
Collection<Node> cells = getSubCells();
Collection<Cell> cells = getSubCells();
if (shapeFilter == null) {
return cells;
}
//TODO change API to return a filtering iterator
List<Node> copy = new ArrayList<Node>(cells.size());
for (Node cell : cells) {
List<Cell> copy = new ArrayList<Cell>(cells.size());
for (Cell cell : cells) {
SpatialRelation rel = cell.getShape().relate(shapeFilter);
if (rel == SpatialRelation.DISJOINT)
continue;
@ -192,7 +192,7 @@ public abstract class Node implements Comparable<Node> {
* <p/>
* Precondition: this.getShape().relate(p) != DISJOINT.
*/
public abstract Node getSubCell(Point p);
public abstract Cell getSubCell(Point p);
//TODO Cell getSubCell(byte b)
@ -202,7 +202,7 @@ public abstract class Node implements Comparable<Node> {
*
* @return A set of cells (no dups), sorted, modifiable, not empty, not null.
*/
protected abstract Collection<Node> getSubCells();
protected abstract Collection<Cell> getSubCells();
/**
* {@link #getSubCells()}.size() -- usually a constant. Should be >=2
@ -216,13 +216,13 @@ public abstract class Node implements Comparable<Node> {
}
@Override
public int compareTo(Node o) {
public int compareTo(Cell o) {
return getTokenString().compareTo(o.getTokenString());
}
@Override
public boolean equals(Object obj) {
return !(obj == null || !(obj instanceof Node)) && getTokenString().equals(((Node) obj).getTokenString());
return !(obj == null || !(obj instanceof Cell)) && getTokenString().equals(((Cell) obj).getTokenString());
}
@Override

View File

@ -79,21 +79,21 @@ public class GeohashPrefixTree extends SpatialPrefixTree {
}
@Override
public Node getNode(Point p, int level) {
public Cell getCell(Point p, int level) {
return new GhCell(GeohashUtils.encodeLatLon(p.getY(), p.getX(), level));//args are lat,lon (y,x)
}
@Override
public Node getNode(String token) {
public Cell getCell(String token) {
return new GhCell(token);
}
@Override
public Node getNode(byte[] bytes, int offset, int len) {
public Cell getCell(byte[] bytes, int offset, int len) {
return new GhCell(bytes, offset, len);
}
class GhCell extends Node {
class GhCell extends Cell {
GhCell(String token) {
super(token);
}
@ -109,9 +109,9 @@ public class GeohashPrefixTree extends SpatialPrefixTree {
}
@Override
public Collection<Node> getSubCells() {
public Collection<Cell> getSubCells() {
String[] hashes = GeohashUtils.getSubGeohashes(getGeohash());//sorted
List<Node> cells = new ArrayList<Node>(hashes.length);
List<Cell> cells = new ArrayList<Cell>(hashes.length);
for (String hash : hashes) {
cells.add(new GhCell(hash));
}
@ -124,8 +124,8 @@ public class GeohashPrefixTree extends SpatialPrefixTree {
}
@Override
public Node getSubCell(Point p) {
return GeohashPrefixTree.this.getNode(p,getLevel()+1);//not performant!
public Cell getSubCell(Point p) {
return GeohashPrefixTree.this.getCell(p, getLevel() + 1);//not performant!
}
private Shape shape;//cache

View File

@ -33,7 +33,7 @@ import java.util.Locale;
/**
* A {@link SpatialPrefixTree} which uses a
* <a href="http://en.wikipedia.org/wiki/Quadtree">quad tree</a> in which an
* indexed term will be generated for each node, 'A', 'B', 'C', 'D'.
* indexed term will be generated for each cell, 'A', 'B', 'C', 'D'.
*
* @lucene.experimental
*/
@ -140,19 +140,19 @@ public class QuadPrefixTree extends SpatialPrefixTree {
}
@Override
public Node getNode(Point p, int level) {
List<Node> cells = new ArrayList<Node>(1);
public Cell getCell(Point p, int level) {
List<Cell> cells = new ArrayList<Cell>(1);
build(xmid, ymid, 0, cells, new StringBuilder(), ctx.makePoint(p.getX(),p.getY()), level);
return cells.get(0);//note cells could be longer if p on edge
}
@Override
public Node getNode(String token) {
public Cell getCell(String token) {
return new QuadCell(token);
}
@Override
public Node getNode(byte[] bytes, int offset, int len) {
public Cell getCell(byte[] bytes, int offset, int len) {
return new QuadCell(bytes, offset, len);
}
@ -160,7 +160,7 @@ public class QuadPrefixTree extends SpatialPrefixTree {
double x,
double y,
int level,
List<Node> matches,
List<Cell> matches,
StringBuilder str,
Shape shape,
int maxLevel) {
@ -186,7 +186,7 @@ public class QuadPrefixTree extends SpatialPrefixTree {
double cx,
double cy,
int level,
List<Node> matches,
List<Cell> matches,
StringBuilder str,
Shape shape,
int maxLevel) {
@ -217,7 +217,7 @@ public class QuadPrefixTree extends SpatialPrefixTree {
str.setLength(strlen);
}
class QuadCell extends Node {
class QuadCell extends Cell {
public QuadCell(String token) {
super(token);
@ -239,8 +239,8 @@ public class QuadPrefixTree extends SpatialPrefixTree {
}
@Override
public Collection<Node> getSubCells() {
List<Node> cells = new ArrayList<Node>(4);
public Collection<Cell> getSubCells() {
List<Cell> cells = new ArrayList<Cell>(4);
cells.add(new QuadCell(getTokenString()+"A"));
cells.add(new QuadCell(getTokenString()+"B"));
cells.add(new QuadCell(getTokenString()+"C"));
@ -254,8 +254,8 @@ public class QuadPrefixTree extends SpatialPrefixTree {
}
@Override
public Node getSubCell(Point p) {
return QuadPrefixTree.this.getNode(p,getLevel()+1);//not performant!
public Cell getSubCell(Point p) {
return QuadPrefixTree.this.getCell(p, getLevel() + 1);//not performant!
}
private Shape shape;//cache

View File

@ -79,8 +79,8 @@ public abstract class SpatialPrefixTree {
public abstract int getLevelForDistance(double dist);
/**
* Given a node having the specified level, returns the distance from opposite
* corners. Since this might very depending on where the node is, this method
* Given a cell having the specified level, returns the distance from opposite
* corners. Since this might very depending on where the cell is, this method
* may over-estimate.
*
* @param level [1 to maxLevels]
@ -90,8 +90,8 @@ public abstract class SpatialPrefixTree {
if (level < 1 || level > getMaxLevels())
throw new IllegalArgumentException("Level must be in 1 to maxLevels range");
//TODO cache for each level
Node node = getNode(ctx.getWorldBounds().getCenter(), level);
Rectangle bbox = node.getShape().getBoundingBox();
Cell cell = getCell(ctx.getWorldBounds().getCenter(), level);
Rectangle bbox = cell.getShape().getBoundingBox();
double width = bbox.getWidth();
double height = bbox.getHeight();
//Use standard cartesian hypotenuse. For geospatial, this answer is larger
@ -99,32 +99,32 @@ public abstract class SpatialPrefixTree {
return Math.sqrt(width * width + height * height);
}
private transient Node worldNode;//cached
private transient Cell worldCell;//cached
/**
* Returns the level 0 cell which encompasses all spatial data. Equivalent to {@link #getNode(String)} with "".
* Returns the level 0 cell which encompasses all spatial data. Equivalent to {@link #getCell(String)} with "".
* This cell is threadsafe, just like a spatial prefix grid is, although cells aren't
* generally threadsafe.
* TODO rename to getTopCell or is this fine?
*/
public Node getWorldNode() {
if (worldNode == null) {
worldNode = getNode("");
public Cell getWorldCell() {
if (worldCell == null) {
worldCell = getCell("");
}
return worldNode;
return worldCell;
}
/**
* The cell for the specified token. The empty string should be equal to {@link #getWorldNode()}.
* The cell for the specified token. The empty string should be equal to {@link #getWorldCell()}.
* Precondition: Never called when token length > maxLevel.
*/
public abstract Node getNode(String token);
public abstract Cell getCell(String token);
public abstract Node getNode(byte[] bytes, int offset, int len);
public abstract Cell getCell(byte[] bytes, int offset, int len);
public final Node getNode(byte[] bytes, int offset, int len, Node target) {
public final Cell getCell(byte[] bytes, int offset, int len, Cell target) {
if (target == null) {
return getNode(bytes, offset, len);
return getCell(bytes, offset, len);
}
target.reset(bytes, offset, len);
@ -134,8 +134,8 @@ public abstract class SpatialPrefixTree {
/**
* Returns the cell containing point {@code p} at the specified {@code level}.
*/
protected Node getNode(Point p, int level) {
return getNodes(p, level, false).get(0);
protected Cell getCell(Point p, int level) {
return getCells(p, level, false).get(0);
}
/**
@ -144,7 +144,7 @@ public abstract class SpatialPrefixTree {
* leaf and none of its children are added.
* <p/>
* This implementation checks if shape is a Point and if so returns {@link
* #getNodes(com.spatial4j.core.shape.Point, int, boolean)}.
* #getCells(com.spatial4j.core.shape.Point, int, boolean)}.
*
* @param shape the shape; non-null
* @param detailLevel the maximum detail level to get cells for
@ -155,45 +155,45 @@ public abstract class SpatialPrefixTree {
* ~20-25% fewer cells.
* @return a set of cells (no dups), sorted, immutable, non-null
*/
public List<Node> getNodes(Shape shape, int detailLevel, boolean inclParents,
public List<Cell> getCells(Shape shape, int detailLevel, boolean inclParents,
boolean simplify) {
//TODO consider an on-demand iterator -- it won't build up all cells in memory.
if (detailLevel > maxLevels) {
throw new IllegalArgumentException("detailLevel > maxLevels");
}
if (shape instanceof Point) {
return getNodes((Point) shape, detailLevel, inclParents);
return getCells((Point) shape, detailLevel, inclParents);
}
List<Node> cells = new ArrayList<Node>(inclParents ? 4096 : 2048);
recursiveGetNodes(getWorldNode(), shape, detailLevel, inclParents, simplify, cells);
List<Cell> cells = new ArrayList<Cell>(inclParents ? 4096 : 2048);
recursiveGetCells(getWorldCell(), shape, detailLevel, inclParents, simplify, cells);
return cells;
}
/**
* Returns true if node was added as a leaf. If it wasn't it recursively
* Returns true if cell was added as a leaf. If it wasn't it recursively
* descends.
*/
private boolean recursiveGetNodes(Node node, Shape shape, int detailLevel,
private boolean recursiveGetCells(Cell cell, Shape shape, int detailLevel,
boolean inclParents, boolean simplify,
List<Node> result) {
if (node.getLevel() == detailLevel) {
node.setLeaf();//FYI might already be a leaf
List<Cell> result) {
if (cell.getLevel() == detailLevel) {
cell.setLeaf();//FYI might already be a leaf
}
if (node.isLeaf()) {
result.add(node);
if (cell.isLeaf()) {
result.add(cell);
return true;
}
if (inclParents && node.getLevel() != 0)
result.add(node);
if (inclParents && cell.getLevel() != 0)
result.add(cell);
Collection<Node> subCells = node.getSubCells(shape);
Collection<Cell> subCells = cell.getSubCells(shape);
int leaves = 0;
for (Node subCell : subCells) {
if (recursiveGetNodes(subCell, shape, detailLevel, inclParents, simplify, result))
for (Cell subCell : subCells) {
if (recursiveGetCells(subCell, shape, detailLevel, inclParents, simplify, result))
leaves++;
}
//can we simplify?
if (simplify && leaves == node.getSubCellsSize() && node.getLevel() != 0) {
if (simplify && leaves == cell.getSubCellsSize() && cell.getLevel() != 0) {
//Optimization: substitute the parent as a leaf instead of adding all
// children as leaves
@ -201,10 +201,10 @@ public abstract class SpatialPrefixTree {
do {
result.remove(result.size() - 1);//remove last
} while (--leaves > 0);
//add node as the leaf
node.setLeaf();
//add cell as the leaf
cell.setLeaf();
if (!inclParents) // otherwise it was already added up above
result.add(node);
result.add(cell);
return true;
}
return false;
@ -212,23 +212,23 @@ public abstract class SpatialPrefixTree {
/**
* A Point-optimized implementation of
* {@link #getNodes(com.spatial4j.core.shape.Shape, int, boolean, boolean)}. That
* {@link #getCells(com.spatial4j.core.shape.Shape, int, boolean, boolean)}. That
* method in facts calls this for points.
* <p/>
* This implementation depends on {@link #getNode(String)} being fast, as its
* This implementation depends on {@link #getCell(String)} being fast, as its
* called repeatedly when incPlarents is true.
*/
public List<Node> getNodes(Point p, int detailLevel, boolean inclParents) {
Node cell = getNode(p, detailLevel);
public List<Cell> getCells(Point p, int detailLevel, boolean inclParents) {
Cell cell = getCell(p, detailLevel);
if (!inclParents) {
return Collections.singletonList(cell);
}
String endToken = cell.getTokenString();
assert endToken.length() == detailLevel;
List<Node> cells = new ArrayList<Node>(detailLevel);
List<Cell> cells = new ArrayList<Cell>(detailLevel);
for (int i = 1; i < detailLevel; i++) {
cells.add(getNode(endToken.substring(0, i)));
cells.add(getCell(endToken.substring(0, i)));
}
cells.add(cell);
return cells;
@ -237,12 +237,12 @@ public abstract class SpatialPrefixTree {
/**
* Will add the trailing leaf byte for leaves. This isn't particularly efficient.
*/
public static List<String> nodesToTokenStrings(Collection<Node> nodes) {
List<String> tokens = new ArrayList<String>((nodes.size()));
for (Node node : nodes) {
final String token = node.getTokenString();
if (node.isLeaf()) {
tokens.add(token + (char) Node.LEAF_BYTE);
public static List<String> cellsToTokenStrings(Collection<Cell> cells) {
List<String> tokens = new ArrayList<String>((cells.size()));
for (Cell cell : cells) {
final String token = cell.getTokenString();
if (cell.isLeaf()) {
tokens.add(token + (char) Cell.LEAF_BYTE);
} else {
tokens.add(token);
}

View File

@ -26,7 +26,7 @@ import com.spatial4j.core.shape.SpatialRelation;
import com.spatial4j.core.shape.impl.RectangleImpl;
import org.apache.lucene.search.Query;
import org.apache.lucene.spatial.StrategyTestCase;
import org.apache.lucene.spatial.prefix.tree.Node;
import org.apache.lucene.spatial.prefix.tree.Cell;
import org.apache.lucene.spatial.prefix.tree.QuadPrefixTree;
import org.apache.lucene.spatial.prefix.tree.SpatialPrefixTree;
import org.apache.lucene.spatial.query.SpatialArgs;
@ -164,12 +164,12 @@ public class SpatialOpRecursivePrefixTreeTest extends StrategyTestCase {
double distErrPct = ((PrefixTreeStrategy) strategy).getDistErrPct();
double distErr = SpatialArgs.calcDistanceFromErrPct(snapMe, distErrPct, ctx);
int detailLevel = grid.getLevelForDistance(distErr);
List<Node> cells = grid.getNodes(snapMe, detailLevel, false, true);
List<Cell> cells = grid.getCells(snapMe, detailLevel, false, true);
//calc bounding box of cells.
double minX = Double.POSITIVE_INFINITY, maxX = Double.NEGATIVE_INFINITY;
double minY = Double.POSITIVE_INFINITY, maxY = Double.NEGATIVE_INFINITY;
for (Node cell : cells) {
for (Cell cell : cells) {
assert cell.getLevel() <= detailLevel;
Rectangle cellR = cell.getShape().getBoundingBox();

View File

@ -1,3 +1,5 @@
package org.apache.lucene.spatial.prefix.tree;
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
@ -15,8 +17,6 @@
* limitations under the License.
*/
package org.apache.lucene.spatial.prefix.tree;
import com.spatial4j.core.context.SpatialContext;
import com.spatial4j.core.shape.Point;
import com.spatial4j.core.shape.Rectangle;
@ -49,20 +49,20 @@ public class SpatialPrefixTreeTest extends SpatialTestCase {
}
@Test
public void testNodeTraverse() {
public void testCellTraverse() {
trie = new GeohashPrefixTree(ctx,4);
Node prevN = null;
Node n = trie.getWorldNode();
assertEquals(0,n.getLevel());
assertEquals(ctx.getWorldBounds(),n.getShape());
while(n.getLevel() < trie.getMaxLevels()) {
prevN = n;
n = n.getSubCells().iterator().next();//TODO random which one?
Cell prevC = null;
Cell c = trie.getWorldCell();
assertEquals(0, c.getLevel());
assertEquals(ctx.getWorldBounds(), c.getShape());
while(c.getLevel() < trie.getMaxLevels()) {
prevC = c;
c = c.getSubCells().iterator().next();//TODO random which one?
assertEquals(prevN.getLevel()+1,n.getLevel());
Rectangle prevNShape = (Rectangle) prevN.getShape();
Shape s = n.getShape();
assertEquals(prevC.getLevel()+1,c.getLevel());
Rectangle prevNShape = (Rectangle) prevC.getShape();
Shape s = c.getShape();
Rectangle sbox = s.getBoundingBox();
assertTrue(prevNShape.getWidth() > sbox.getWidth());
assertTrue(prevNShape.getHeight() > sbox.getHeight());