/*
***************************************************************************************
* Copyright (C) 2006 EsperTech, Inc. All rights reserved. *
* http://www.espertech.com/esper *
* http://www.espertech.com *
* ---------------------------------------------------------------------------------- *
* The software in this package is published under the terms of the GPL license *
* a copy of which has been included with this distribution in the license.txt file. *
***************************************************************************************
*/
package com.espertech.esper.spatial.quadtree.prqdfilterindex;
import com.espertech.esper.spatial.quadtree.core.*;
import com.espertech.esper.spatial.quadtree.pointregion.PointRegionQuadTree;
import com.espertech.esper.spatial.quadtree.pointregion.PointRegionQuadTreeNode;
import com.espertech.esper.spatial.quadtree.pointregion.PointRegionQuadTreeNodeBranch;
import com.espertech.esper.spatial.quadtree.pointregion.PointRegionQuadTreeNodeLeaf;
import java.util.Collection;
import java.util.LinkedList;
import static com.espertech.esper.spatial.quadtree.prqdfilterindex.PointRegionQuadTreeFilterIndexCheckBB.checkBB;
public class PointRegionQuadTreeFilterIndexSet {
public static <L> void set(double x, double y, L value, PointRegionQuadTree<Object> tree) {
PointRegionQuadTreeNode<Object> root = tree.getRoot();
checkBB(root.getBb(), x, y);
PointRegionQuadTreeNode<Object> replacement = setOnNode(x, y, value, root, tree);
tree.setRoot(replacement);
}
private static <L> PointRegionQuadTreeNode<Object> setOnNode(double x, double y, L value, PointRegionQuadTreeNode<Object> node, PointRegionQuadTree<Object> tree) {
if (node instanceof PointRegionQuadTreeNodeLeaf) {
PointRegionQuadTreeNodeLeaf<Object> leaf = (PointRegionQuadTreeNodeLeaf<Object>) node;
int count = setOnLeaf(leaf, x, y, value);
leaf.incCount(count);
if (leaf.getCount() <= tree.getLeafCapacity() || node.getLevel() >= tree.getMaxTreeHeight()) {
return leaf;
}
node = subdivide(leaf, tree);
}
PointRegionQuadTreeNodeBranch<Object> branch = (PointRegionQuadTreeNodeBranch) node;
addToBranch(branch, x, y, value, tree);
return node;
}
private static void addToBranch(PointRegionQuadTreeNodeBranch<Object> branch, double x, double y, Object value, PointRegionQuadTree<Object> tree) {
QuadrantEnum quadrant = branch.getBb().getQuadrant(x, y);
if (quadrant == QuadrantEnum.NW) {
branch.setNw(setOnNode(x, y, value, branch.getNw(), tree));
} else if (quadrant == QuadrantEnum.NE) {
branch.setNe(setOnNode(x, y, value, branch.getNe(), tree));
} else if (quadrant == QuadrantEnum.SW) {
branch.setSw(setOnNode(x, y, value, branch.getSw(), tree));
} else {
branch.setSe(setOnNode(x, y, value, branch.getSe(), tree));
}
}
private static <L> PointRegionQuadTreeNode<Object> subdivide(PointRegionQuadTreeNodeLeaf<Object> leaf, PointRegionQuadTree<Object> tree) {
double w = (leaf.getBb().getMaxX() - leaf.getBb().getMinX()) / 2d;
double h = (leaf.getBb().getMaxY() - leaf.getBb().getMinY()) / 2d;
double minx = leaf.getBb().getMinX();
double miny = leaf.getBb().getMinY();
BoundingBox bbNW = new BoundingBox(minx, miny, minx + w, miny + h);
BoundingBox bbNE = new BoundingBox(minx + w, miny, leaf.getBb().getMaxX(), miny + h);
BoundingBox bbSW = new BoundingBox(minx, miny + h, minx + w, leaf.getBb().getMaxY());
BoundingBox bbSE = new BoundingBox(minx + w, miny + h, leaf.getBb().getMaxX(), leaf.getBb().getMaxY());
PointRegionQuadTreeNode<Object> nw = new PointRegionQuadTreeNodeLeaf<>(bbNW, leaf.getLevel() + 1, null, 0);
PointRegionQuadTreeNode<Object> ne = new PointRegionQuadTreeNodeLeaf<>(bbNE, leaf.getLevel() + 1, null, 0);
PointRegionQuadTreeNode<Object> sw = new PointRegionQuadTreeNodeLeaf<>(bbSW, leaf.getLevel() + 1, null, 0);
PointRegionQuadTreeNode<Object> se = new PointRegionQuadTreeNodeLeaf<>(bbSE, leaf.getLevel() + 1, null, 0);
PointRegionQuadTreeNodeBranch<Object> branch = new PointRegionQuadTreeNodeBranch<>(leaf.getBb(), leaf.getLevel(), nw, ne, sw, se);
Object points = leaf.getPoints();
if (points instanceof XYPointWValue) {
XYPointWValue point = (XYPointWValue<L>) points;
subdividePoint(point, branch, tree);
} else {
Collection<XYPointWValue<L>> collection = (Collection<XYPointWValue<L>>) points;
for (XYPointWValue<L> point : collection) {
subdividePoint(point, branch, tree);
}
}
return branch;
}
private static <L> void subdividePoint(XYPointWValue<L> point, PointRegionQuadTreeNodeBranch<Object> branch, PointRegionQuadTree<Object> tree) {
double x = point.getX();
double y = point.getY();
QuadrantEnum quadrant = branch.getBb().getQuadrant(x, y);
if (quadrant == QuadrantEnum.NW) {
branch.setNw(setOnNode(x, y, point, branch.getNw(), tree));
} else if (quadrant == QuadrantEnum.NE) {
branch.setNe(setOnNode(x, y, point, branch.getNe(), tree));
} else if (quadrant == QuadrantEnum.SW) {
branch.setSw(setOnNode(x, y, point, branch.getSw(), tree));
} else {
branch.setSe(setOnNode(x, y, point, branch.getSe(), tree));
}
}
private static <L> int setOnLeaf(PointRegionQuadTreeNodeLeaf<Object> leaf, double x, double y, L value) {
Object currentValue = leaf.getPoints();
if (value instanceof XYPointWValue) {
XYPointWValue<L> point = (XYPointWValue<L>) value;
if (point.getX() != x && point.getY() != y) {
throw new IllegalStateException();
}
if (currentValue == null) {
leaf.setPoints(point);
return 1;
}
if (currentValue instanceof XYPointWValue) {
XYPointWValue<L> other = (XYPointWValue<L>) currentValue;
if (other.getX() == x && other.getY() == y) {
other.setValue(value);
return 0; // replaced
}
Collection<XYPointWValue<L>> collection = new LinkedList<>();
collection.add(other);
collection.add(point);
leaf.setPoints(collection);
return 1;
}
Collection<XYPointWValue<L>> collection = (Collection<XYPointWValue<L>>) currentValue;
for (XYPointWValue<L> other : collection) {
if (other.getX() == x && other.getY() == y) {
other.setValue(value);
return 0;
}
}
collection.add(point);
return 1;
}
if (currentValue == null) {
XYPointWValue<L> point = new XYPointWValue<>(x, y, value);
leaf.setPoints(point);
return 1;
}
if (currentValue instanceof XYPointWValue) {
XYPointWValue<L> other = (XYPointWValue<L>) currentValue;
if (other.getX() == x && other.getY() == y) {
other.setValue(value);
return 0;
}
Collection<XYPointWValue<L>> collection = new LinkedList<>();
collection.add(other);
collection.add(new XYPointWValue<>(x, y, value));
leaf.setPoints(collection);
return 1;
}
Collection<XYPointWValue<L>> collection = (Collection<XYPointWValue<L>>) currentValue;
for (XYPointWValue<L> other : collection) {
if (other.getX() == x && other.getY() == y) {
other.setValue(value);
return 0;
}
}
collection.add(new XYPointWValue<>(x, y, value));
return 1;
}
}