四叉数之box索引box

那是在很久很久以前,我在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}














  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个简单的Matlab代码,用于搜索四树quadtree的每个节点,获取区域范围与射线相交的叶子节点中存储的三角面索引,并且根据索引得到三角面的顶点坐标和法向量,最后用射线与三角面进行求交运算,最后遍历完整棵四树,得到射线与所有三角面的交点,返回交点坐标和索引信息。 ```matlab function [vertices, normals, indices] = quadtree_ray_tracing(root, ray_origin, ray_direction) % Recursive function to traverse the quadtree and find intersections % with ray % Check if current node is a leaf node if isempty(root.children) % Check if ray intersects with leaf node's bounding box intersection = ray_box_intersection(root.box, ray_origin, ray_direction); if intersection % Get triangle indices from leaf node indices = root.indices; % Get vertices and normals from indices [vertices, normals] = get_vertices_normals(indices); % Find ray-triangle intersections [intersections, ~] = TriangleRayIntersection(ray_origin, ray_direction, vertices); % Return intersection information if ~isempty(intersections) % Find closest intersection [~, index] = min(intersections); intersection_point = vertices(index, :); intersection_normal = normals(index, :); return end end else % Recursively traverse child nodes for i = 1:length(root.children) child = root.children(i); intersection = ray_box_intersection(child.box, ray_origin, ray_direction); if intersection [vertices, normals, indices] = quadtree_ray_tracing(child, ray_origin, ray_direction); if ~isempty(indices) return end end end end % No intersection found vertices = []; normals = []; indices = []; end function [vertices, normals] = get_vertices_normals(indices) % Get vertices and normals from triangle indices % Load mesh data mesh_data = load('mesh_data.mat'); vertices = mesh_data.vertices; normals = mesh_data.normals; % Get vertices and normals for each triangle vertices = vertices(indices, :); normals = normals(indices, :); end function intersection = ray_box_intersection(box, ray_origin, ray_direction) % Check if ray intersects with bounding box % Check for intersection with each face of bounding box tmin = (box([1 2 3]) - ray_origin) ./ ray_direction; tmax = (box([4 5 6]) - ray_origin) ./ ray_direction; tmin = max(min(tmin, tmax), 0); tmax = min(max(tmin, tmax), 1); intersection = all(tmax >= tmin); end function [t, u, v] = TriangleRayIntersection(Orig, Dir, Verts) % Calculate ray-triangle intersection % Triangle vertices v1 = Verts(1,:); v2 = Verts(2,:); v3 = Verts(3,:); % Edge vectors e1 = v2 - v1; e2 = v3 - v1; % Normal vector n = cross(e1, e2); % Check if ray is parallel to triangle ndotd = dot(n, Dir); if abs(ndotd) < eps t = Inf; u = 0; v = 0; return end % Calculate intersection point w = Orig - v1; ndotw = dot(n, w); t = -ndotw / ndotd; % Check if intersection is behind ray origin if t < 0 t = Inf; u = 0; v = 0; return end % Calculate barycentric coordinates q = cross(Dir, e2); u = dot(w, q) / dot(n, q); p = cross(w, e1); v = dot(Dir, p) / dot(n, p); % Check if point is inside triangle if u < 0 || v < 0 || u + v > 1 t = Inf; u = 0; v = 0; return end end ``` 请注意,上面的代码只是一个简单的示例,需要根据具体的应用场景和数据格式进行修改和调整。同时,代码中还需要加载存储三角面数据的文件,这里假设该数据以matlab格式存储,文件名为`mesh_data.mat`,包含`vertices`和`normals`两个变量,分别存储所有三角面的顶点坐标和法向量。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值