AABB Tree

官方文档链接:CGAL 5.5 - 3D Fast Intersection and Distance Computation (AABB Tree): User Manual

1 介绍

AABB树提供了一个静态的数据结构和算法,能够对有限3D几何对象集合进行高效的相交和距离查询。

  • 相交查询可以是任何类型,前提是在traits类中实现了相应的交集谓词和构造函数。
  • 距离查询仅限于点的查询。

AABB树的数据结构将几何数据的迭代器范围作为输入,然后将其转换为primitives(图元)。在这些primitives中,构造了一个轴对齐边界框(axis-aligned bounding boxes)(AABB)的层次结构,用于加速相交和距离查询。每个图元都能访问一个输入几何对象(datum)和该对象的参考id。例如,一个图元将3D triangle作为datum,多面体表面的face handle作为id。而通过AABB tree进行相交和距离查询时,返回值中就包含了相交对象/最近点和相交图元id/最近图元id。

左图为表面三角网格模型,右图为其构建的AABB树。

2 接口

相交

  • AABB_tree::do_intersect()
  • AABB_tree::number_of_intersected_primitives()
  • AABB_tree::all_intersected_primitives()
  • AABB_tree::any_intersected_primitive()
  • AABB_tree::first_intersected_primitive()

以上函数不会构造相交对象,仅做测试。

  • AABB_tree::all_intersections()
  • AABB_tree::any_intersection()
  • AABB_tree::first_intersection()

以上函数会构造相交的对象。

距离

  • AABB_tree::closest_point()
  • AABB_tree::closest_point_and_primitive()
  • AABB_tree::accelerate_distance_queries()

注意,在AABB Tree中应避免出现退化的图元,防止算法出错。

3 几个栗子

下面例子中,三维三角形集合以list的形式存储。AABB图元将三角形(triangle)作为datum(数据),list里的迭代器作为id。程序中实现了射线与三角形集合的相交查询,点与三角形集合的最近点查询和距离计算。

// Author(s) : Camille Wormser, Pierre Alliez
#include <iostream>
#include <list>
#include <CGAL/Simple_cartesian.h>
#include <CGAL/AABB_tree.h>
#include <CGAL/AABB_traits.h>
#include <CGAL/AABB_triangle_primitive.h>
typedef CGAL::Simple_cartesian<double> K;//内核定义
typedef K::FT FT;
typedef K::Ray_3 Ray;
typedef K::Line_3 Line;
typedef K::Point_3 Point;
typedef K::Triangle_3 Triangle;
typedef std::list<Triangle>::iterator Iterator; //三角形list迭代器
typedef CGAL::AABB_triangle_primitive<K, Iterator> Primitive;
typedef CGAL::AABB_traits<K, Primitive> AABB_triangle_traits;
typedef CGAL::AABB_tree<AABB_triangle_traits> Tree;
int main()
{Point a(1.0, 0.0, 0.0);Point b(0.0, 1.0, 0.0);Point c(0.0, 0.0, 1.0);Point d(0.0, 0.0, 0.0);std::list<Triangle> triangles;triangles.push_back(Triangle(a,b,c));triangles.push_back(Triangle(a,b,d));triangles.push_back(Triangle(a,d,c));// constructs AABB treeTree tree(triangles.begin(),triangles.end());// counts #intersectionsRay ray_query(a,b);std::cout << tree.number_of_intersected_primitives(ray_query)<< " intersections(s) with ray query" << std::endl;// compute closest point and squared distancePoint point_query(2.0, 2.0, 2.0);Point closest_point = tree.closest_point(point_query);std::cerr << "closest point is: " << closest_point << std::endl;FT sqd = tree.squared_distance(point_query);std::cout << "squared distance: " << sqd << std::endl;return EXIT_SUCCESS;
}

在下面这个例子中,将创建一个多面体三角面片的AABB树。其中,AABB图元将三角形面片句柄包装为id,对应的面片作为几何对象(datum)。

// Author(s) : Camille Wormser, Pierre Alliez
#include <iostream>
#include <list>
#include <CGAL/Simple_cartesian.h>
#include <CGAL/AABB_tree.h>
#include <CGAL/AABB_traits.h>
#include <CGAL/Polyhedron_3.h>
#include <CGAL/AABB_face_graph_triangle_primitive.h>
typedef CGAL::Simple_cartesian<double> K;
typedef K::Point_3 Point;
typedef K::Plane_3 Plane;
typedef K::Vector_3 Vector;
typedef K::Segment_3 Segment;
typedef K::Ray_3 Ray;
typedef CGAL::Polyhedron_3<K> Polyhedron;
typedef CGAL::AABB_face_graph_triangle_primitive<Polyhedron> Primitive;
typedef CGAL::AABB_traits<K, Primitive> Traits;
typedef CGAL::AABB_tree<Traits> Tree;
typedef boost::optional< Tree::Intersection_and_primitive_id<Segment>::Type > Segment_intersection;
typedef boost::optional< Tree::Intersection_and_primitive_id<Plane>::Type > Plane_intersection;
typedef Tree::Primitive_id Primitive_id;
int main()
{Point p(1.0, 0.0, 0.0);Point q(0.0, 1.0, 0.0);Point r(0.0, 0.0, 1.0);Point s(0.0, 0.0, 0.0);Polyhedron polyhedron;polyhedron.make_tetrahedron(p, q, r, s);// constructs AABB treeTree tree(faces(polyhedron).first, faces(polyhedron).second, polyhedron);// constructs segment queryPoint a(-0.2, 0.2, -0.2);Point b(1.3, 0.2, 1.3);Segment segment_query(a,b);// tests intersections with segment queryif(tree.do_intersect(segment_query))std::cout << "intersection(s)" << std::endl;elsestd::cout << "no intersection" << std::endl;// computes #intersections with segment querystd::cout << tree.number_of_intersected_primitives(segment_query)<< " intersection(s)" << std::endl;// computes first encountered intersection with segment query// (generally a point)Segment_intersection intersection =tree.any_intersection(segment_query);if(intersection){// gets intersection objectconst Point* p = boost::get<Point>(&(intersection->first));if(p)std::cout << "intersection object is a point " << *p << std::endl;}// computes all intersections with segment query (as pairs object - primitive_id)std::list<Segment_intersection> intersections;tree.all_intersections(segment_query, std::back_inserter(intersections));// computes all intersected primitives with segment query as primitive idsstd::list<Primitive_id> primitives;tree.all_intersected_primitives(segment_query, std::back_inserter(primitives));// constructs plane queryVector vec(0.0,0.0,1.0);Plane plane_query(a,vec);// computes first encountered intersection with plane query// (generally a segment)Plane_intersection plane_intersection = tree.any_intersection(plane_query);if(plane_intersection){if(boost::get<Segment>(&(plane_intersection->first)))std::cout << "intersection object is a segment" << std::endl;}return EXIT_SUCCESS;
}

下面例子先读取一个闭合的多面体表面,然后以每个face的重心为起始点和垂直于face向模型内部的方向作射线,进行一个ray shooting query。

#include <CGAL/Simple_cartesian.h>
#include <CGAL/Surface_mesh.h>
#include <CGAL/AABB_tree.h>
#include <CGAL/AABB_traits.h>
#include <CGAL/AABB_face_graph_triangle_primitive.h>
#include <CGAL/Polygon_mesh_processing/compute_normal.h>
#include <CGAL/Polygon_mesh_processing/orientation.h>
#include <iostream>
#include <fstream>
typedef CGAL::Simple_cartesian<double> K;
typedef K::FT FT;
typedef K::Point_3 Point;
typedef K::Vector_3 Vector;
typedef K::Ray_3 Ray;
typedef CGAL::Surface_mesh<Point> Mesh;
typedef boost::graph_traits<Mesh>::face_descriptor face_descriptor;
typedef boost::graph_traits<Mesh>::halfedge_descriptor halfedge_descriptor;
typedef CGAL::AABB_face_graph_triangle_primitive<Mesh> Primitive;
typedef CGAL::AABB_traits<K, Primitive> Traits;
typedef CGAL::AABB_tree<Traits> Tree;
typedef boost::optional<Tree::Intersection_and_primitive_id<Ray>::Type> Ray_intersection;
struct Skip
{face_descriptor fd;Skip(const face_descriptor fd): fd(fd){}bool operator()(const face_descriptor& t) const{ if(t == fd){std::cerr << "ignore " << t  <<std::endl;};return(t == fd);}
};
int main(int argc, char* argv[])
{const std::string filename = (argc > 1) ? argv[1] : CGAL::data_file_path("meshes/tetrahedron.off");Mesh mesh;if(!CGAL::IO::read_polygon_mesh(filename, mesh)){std::cerr << "Invalid input." << std::endl;return 1;}Tree tree(faces(mesh).first, faces(mesh).second, mesh);double d = CGAL::Polygon_mesh_processing::is_outward_oriented(mesh)?-1:1;for(face_descriptor fd : faces(mesh)){halfedge_descriptor hd = halfedge(fd,mesh);Point p = CGAL::centroid(mesh.point(source(hd,mesh)),mesh.point(target(hd,mesh)),mesh.point(target(next(hd,mesh),mesh)));Vector v = CGAL::Polygon_mesh_processing::compute_face_normal(fd,mesh);Ray ray(p,d * v);Skip skip(fd);Ray_intersection intersection = tree.first_intersection(ray, skip);if(intersection){if(boost::get<Point>(&(intersection->first))){const Point* p =  boost::get<Point>(&(intersection->first) );std::cout <<  *p << std::endl;}}}std::cerr << "done" << std::endl;return 0;
}

因为重心计算属于浮点运算,因此射线第一个击中的面可能是起点质心所在的面。为了避免此状况,这里需要给first_intersection()传入一个skip functor将此面忽略。

上个例子是计算的射线与mesh的相交,下面这个例子展示如何查询一个点到mesh的squared distance和closest point及其所在的triangle。


// Author(s) : Pierre Alliez
#include <iostream>
#include <CGAL/Simple_cartesian.h>
#include <CGAL/AABB_tree.h>
#include <CGAL/AABB_traits.h>
#include <CGAL/Polyhedron_3.h>
#include <CGAL/AABB_face_graph_triangle_primitive.h>
typedef CGAL::Simple_cartesian<double> K;
typedef K::FT FT;
typedef K::Point_3 Point;
typedef K::Segment_3 Segment;
typedef CGAL::Polyhedron_3<K> Polyhedron;
typedef CGAL::AABB_face_graph_triangle_primitive<Polyhedron> Primitive;
typedef CGAL::AABB_traits<K, Primitive> Traits;
typedef CGAL::AABB_tree<Traits> Tree;
typedef Tree::Point_and_primitive_id Point_and_primitive_id;
int main()
{Point p(1.0, 0.0, 0.0);Point q(0.0, 1.0, 0.0);Point r(0.0, 0.0, 1.0);Point s(0.0, 0.0, 0.0);Polyhedron polyhedron;polyhedron.make_tetrahedron(p, q, r, s);// constructs AABB tree and computes internal KD-tree// data structure to accelerate distance queriesTree tree(faces(polyhedron).first, faces(polyhedron).second, polyhedron);// query pointPoint query(0.0, 0.0, 3.0);// computes squared distance from queryFT sqd = tree.squared_distance(query);std::cout << "squared distance: " << sqd << std::endl;// computes closest pointPoint closest = tree.closest_point(query);std::cout << "closest point: " << closest << std::endl;// computes closest point and primitive idPoint_and_primitive_id pp = tree.closest_point_and_primitive(query);Point closest_point = pp.first;Polyhedron::Face_handle f = pp.second; // closest primitive idstd::cout << "closest point: " << closest_point << std::endl;std::cout << "closest triangle: ( "<< f->halfedge()->vertex()->point() << " , "<< f->halfedge()->next()->vertex()->point() << " , "<< f->halfedge()->next()->next()->vertex()->point()<< " )" << std::endl;return EXIT_SUCCESS;
}

最后一个例子,是对于AABB树中图元的增量插入。虽然AABB树是一个静态的数据结构,但是它允许插入primitives(图元)。

#include <iostream>
#include <CGAL/Simple_cartesian.h>
#include <CGAL/AABB_tree.h>
#include <CGAL/AABB_traits.h>
#include <CGAL/Polyhedron_3.h>
#include <CGAL/AABB_face_graph_triangle_primitive.h>
typedef CGAL::Simple_cartesian<double> K;
typedef K::FT FT;
typedef K::Point_3 Point;
typedef K::Segment_3 Segment;
typedef CGAL::Polyhedron_3<K> Polyhedron;
typedef CGAL::AABB_face_graph_triangle_primitive<Polyhedron, CGAL::Default, CGAL::Tag_false> Primitive;
typedef CGAL::AABB_traits<K, Primitive> Traits;
typedef CGAL::AABB_tree<Traits> Tree;
typedef Tree::Point_and_primitive_id Point_and_primitive_id;
int main()
{Point p(1.0, 0.0, 0.0);Point q(0.0, 1.0, 0.0);Point r(0.0, 0.0, 1.0);Point s(0.0, 0.0, 0.0);Polyhedron polyhedron1;polyhedron1.make_tetrahedron(p, q, r, s);Point p2(11.0, 0.0, 0.0);Point q2(10.0, 1.0, 0.0);Point r2(10.0, 0.0, 1.0);Point s2(10.0, 0.0, 0.0);Polyhedron polyhedron2;polyhedron2.make_tetrahedron(p2, q2, r2, s2);// constructs AABB tree and computes internal KD-tree// data structure to accelerate distance queriesTree tree(faces(polyhedron1).first, faces(polyhedron1).second, polyhedron1);tree.insert(faces(polyhedron2).first, faces(polyhedron2).second, polyhedron2);// query pointPoint query(0.0, 0.0, 3.0);// computes squared distance from queryFT sqd = tree.squared_distance(query);std::cout << "squared distance: " << sqd << std::endl;return EXIT_SUCCESS;
}

上面这个例子中,首先使用polyhedron1构建tree,然后使用insert()函数将polyhedron2的faces作为primitives插入到tree中。

【CGAL_空间搜索与排序】3D快速求交和距离计算相关推荐

  1. #研发解决方案介绍#基于ES的搜索+筛选+排序解决方案

    郑昀 基于胡耀华和王超的设计文档 最后更新于2014/12/3 关键词:ElasticSearch.Lucene.solr.搜索.facet.高可用.可伸缩.mongodb.SearchHub.商品中 ...

  2. Solr空间搜索原理分析与实践

    前言 在美团CRM系统中,搜索商家的效率与公司的销售额息息相关,为了让BD们更便捷又直观地去搜索商家,美团CRM技术团队基于Solr提供了空间搜索功能,其中移动端周边商家搜索和PC端的地图模式搜索功能 ...

  3. 端智能在大众点评搜索重排序的应用实践

    端智能,是指在移动端设备运行人工智能(AI)应用的技术.本文主要讲述大众点评搜索场景下,在端侧部署大规模深度学习模型进行搜索重排序任务的实践方案,包括端上特征工程.模型迭代思路,以及具体部署优化的过程 ...

  4. LeetCode 79单词搜索80删除排序数组中的重复项Ⅱ81.搜索旋转排序数组Ⅱ

    新人公众号(求支持):bigsai 专注于Java.数据结构与算法,一起进大厂不迷路! 算法文章题解全部收录在github仓库bigsai-algorithm,求star! 关注回复进群即可加入力扣打 ...

  5. 美团-深度学习在搜索广告排序的应用实践

    一.前言 在计算广告场景中,需要平衡和优化三个参与方--用户.广告主.平台的关键指标,而预估点击率CTR(Click-through Rate)和转化率CVR(Conversion Rate)是其中非 ...

  6. 【AI in 美团】深度学习在美团搜索广告排序的应用实践

    转自:https://mp.weixin.qq.com/s/9Fcj5lO-JPfFVnRSSM_56w [AI in 美团]深度学习在美团搜索广告排序的应用实践 AI(人工智能)技术已经广泛应用于美 ...

  7. 蓝桥杯 笔记整理【JavaB组省赛真题、约数、全排列模板、排列组合、等差等比求和公式、eclipse快捷键、集合、快速求a^n、进制转换(Integer、BigInteger)、动态数组Vector】

    蓝桥杯 Java B组 省赛决赛 真题详解及小结汇总[2013年(第4届)~2020年(第11届)] 第11届 蓝桥杯-第1.2次模拟(软件类)真题-(2020年3月.4月)-官方讲解视频 说明:大部 ...

  8. Lucene系列:(9)搜索结果排序

    1.什么是搜索结果排序 搜索结果是按某个或某些字段高低排序来显示的结果 2.影响网站排名的多种因素 head/meta/ 网页的标签整洁 网页执行速度 采用div+css ...... 3.Lucen ...

  9. 【Solr空间搜索SpatialSearch】

    喂,这几个单词什么意思,你晓得伐 名词 含义 longitude 经度 latitude 纬度 LatLon 纬度经度的缩写 Grid 网格 空间搜索 空间搜索,又名Spatial Search(Sp ...

  10. [ElasticSearch] 空间搜索 (一)

    根据索引文档的地理坐标来进行搜索,Elasticsearch 也能够处理这样的搜索.--空间搜索 一.为空间搜索准备映射 PUT my_space_test {"mappings" ...

最新文章

  1. RDKit:运用RDKit计算USRCAT
  2. python使用imbalanced-learn的RandomUnderSampler方法进行下采样处理数据不平衡问题
  3. 科研人员请注意!腾讯要为你们专项开放数据、计算资源、实验环境
  4. java web 来源页_JavaWeb 分页实现
  5. mysql事务隔离级别与设置
  6. lombok @data 忽略属性_使用lombok编写优雅的Bean对象
  7. keras添加正则化全连接_TensorFlow keras卷积神经网络 添加L2正则化
  8. 1023. 组个最小数 (20)
  9. android用上传图片到服务器上,Android使用post方式上传图片到服务器的方法
  10. Python学习笔记之头部文件
  11. linux物理硬盘和sd的对应关系_Linux物理存储结构以及磁盘划分
  12. 谢希仁计算机网络第七版 以太网单播和多播MAC地址范围[纠错]
  13. C语言多线程基础-02-临界区,互斥量
  14. 使用 LaTeX 语言对 MATLAB 中的图片进行标注
  15. Spring Boot拦截器配置拦截登陆
  16. 如何把html网页共享文件夹,如何将文件夹共享 设置共享文件夹教程【详细介绍】...
  17. oracle新增字段 加注释,Oracle数据库表的字段添加注释和向现有表添加字段 | 学步园...
  18. 微信企业号(公众号)开发流程汇总
  19. Java Security:Java加密框架(JCA)简要说明
  20. linux mint 安装ubuntu软件中心,Ubuntu和Linux Mint:安装Pinta 1.6工具

热门文章

  1. 计算机组成原理——补码一位乘(Booth算法)+举例+小白理解
  2. AspNetPager分页
  3. 阿里编码规范认证考试题库(免费版)
  4. 【html教程】非常全的主页设置代码,HTML代码教程
  5. Linux|超好用!绘制流程图神器——PlantUML
  6. qq连连看java版_Java实战_仿QQ连连看
  7. 第一次C程序设计作业
  8. [AHOI2007]密码箱
  9. python 开发金山打字通辅助脚本
  10. 富其云ERP学习笔记