那是在很久很久以前,我在QQ群里面看到过别人用四叉树渲染无限地图, 当时一直想用C写以个。
奈何当时过于无知, 一直没学会。
最近一同事需要实现给定一个地标范围搜索下面所有的酒店, 四叉树是最为理想的结构。
凭借我当前肤浅的认为, 四叉树有3个功能:
1. 根据box 搜索在box范围内的所有点
2. 根据box 搜索所有包含或者与之相交的box
3. 根据点搜索这个点在那些box中
零零散散的画了一个下午的时间,终于解掉N久以前的心结。
渲染一个英雄周边范围的地图demo.{仅仅只是生成周边范围的Box}
搜索地标范围所有酒店应该算是第一种应用常景。我之前的心结应该算是第二种应用常景。
声明Box, Node对象
enum BoxRelation {
CROSS, CONTAIN, CONTAINED, NO_RELATION, UN_KNOW
}
public static class Node<T> {
private T s;
private int depth;
private Box box;
private Node<T> NW, NE, SE, SW;
private Node(Box box, int depth) {
this.box = box;
this.depth = depth;
}
@Override
public String toString() {
return "Node{" + "depth=" + depth + ", box=" + box + '}';
}
}
public static class Box {
private double xLow, yHigh, xHigh, yLow;
public Box(double xLow, double yHigh, double xHigh, double yLow) {
this.xLow = xLow;
this.xHigh = xHigh;
this.yLow = yLow;
this.yHigh = yHigh;
}
public boolean contain(double x, double y) {
return (x > xLow && x < xHigh && y > yLow && y < yHigh);
}
public static BoxRelation contain(Box box1, Box box2) {
BoxRelation result = containInner(box1, box2);
if (result != null) {
return result;
}
if (BoxRelation.CONTAIN == containInner(box2, box1)) {
return BoxRelation.CONTAINED;
}
return BoxRelation.NO_RELATION;
}
private static BoxRelation containInner(Box box1, Box box2) {
boolean hadIn = false;
boolean allIn = true;
boolean contain;
contain = box1.contain(box2.xLow, box2.yHigh);
hadIn |= contain;
allIn &= contain;
contain = box1.contain(box2.xHigh, box2.yHigh);
hadIn |= contain;
allIn &= contain;
contain = box1.contain(box2.xLow, box2.yLow);
hadIn |= contain;
allIn &= contain;
contain = box1.contain(box2.xHigh, box2.yLow);
hadIn |= contain;
allIn &= contain;
if (allIn) {
return BoxRelation.CONTAIN;
}
if (hadIn) {
return BoxRelation.CROSS;
}
return null;
}
@Override
public String toString() {
return "Box{" + "xLow=" + xLow + ", yHigh=" + yHigh + ", xHigh=" + xHigh + ", yLow=" + yLow + '}';
}
}
构建QuadTreeBox
public class QuadTreeBox<T> {
private T s;
private int depth;
private Node<T> root;
public QuadTreeBox(int depth, Box box, T s) {
this.depth = depth;
this.s = s;
root = new Node<T>(box, depth);
initQuadTree(root);
}
//初始化数
private void initQuadTree(Node<T> node) {
Box box = node.box;
int depth = node.depth;
if (node.depth > 0) {
node.NW = new Node<T>(new Box(box.xLow, box.yHigh, box.xLow + (box.xHigh - box.xLow) / 2, box.yHigh
- (box.yHigh - box.yLow) / 2), depth - 1);
initQuadTree(node.NW);
node.NE = new Node<T>(new Box(box.xLow + (box.xHigh - box.xLow) / 2, box.yHigh, box.xHigh, box.yHigh
- (box.yHigh - box.yLow) / 2), depth - 1);
initQuadTree(node.NE);
node.SE = new Node<T>(new Box(box.xLow + (box.xHigh - box.xLow) / 2,
box.yHigh - (box.yHigh - box.yLow) / 2, box.xHigh, box.yLow), depth - 1);
initQuadTree(node.SE);
node.SW = new Node<T>(new Box(box.xLow, box.yHigh - (box.yHigh - box.yLow) / 2, box.xLow
+ (box.xHigh - box.xLow) / 2, box.yLow), depth - 1);
initQuadTree(node.SW);
}
}
private void queryB(Node<T> node, Box box, List<Node<T>> result) {
if(node == null){
return;
}
switch (Box.contain(node.box, box)) {
case CONTAIN:
if(node.depth != 0){
queryA(node, box, result);
break;
}
result.add(node);
case CROSS:
if(node.depth != 0){
queryA(node, box, result);
break;
}
result.add(node);
break;
case CONTAINED:
if(node.depth != 0){
queryA(node, box, result);
break;
}
result.add(node);
break;
default:
break;
}
}
private void queryA(Node<T> node, Box box, List<Node<T>> result) {
if (node == null) {
return;
}
queryB(node.NW, box, result);
queryB(node.NE, box, result);
queryB(node.SE, box, result);
queryB(node.SW, box, result);
}
//查需与Box范围内应该渲染的Box
public List<Node<T>> query(Box box) {
List<Node<T>> result = Lists.newArrayList();
queryA(root, box, result);
return result;
}
}
测试代码
<pre name="code" class="java"> private void display(Node<T> node, String label) {
if (node == null) {
return;
}
System.out.println(node.depth + "\t" + label + "\t" + node.box.toString());
display(node.NW, "NW");
display(node.NE, "NE");
display(node.SE, "SE");
display(node.SW, "SW");
}
public void display() {
display(root, "root");
}
public static void main(String[] args) {
QuadTreeBox<String> treeBox = new QuadTreeBox<String>(5, new Box(-10, 10, 10, -10), "root");
treeBox.display();
System.out.println("----------------------------");
for (Node<String> node : treeBox.query(new Box(-1, 1, 1, 1))) {
System.out.println(node.depth + "\t" + node.box.toString());
}
}
测试结果:
----------------------------
0 Box{xLow=-1.25, yHigh=1.25, xHigh=-0.625, yLow=0.625}
0 Box{xLow=0.625, yHigh=1.25, xHigh=1.25, yLow=0.625}