有没有办法使这种最短路径算法更快?

时间:2018-10-18 20:02:52

标签: c++ algorithm path-finding cgal

使用 CGAL 库,我正在尝试实现Shortest Path方法。

我取得了一些成功,但是映射路径所花费的时间几乎无法接受,在Release中运行可能要花费1.5秒。

我知道输入的内容可能很大,有 50000张面孔,但这是我必须要处理的。

要详细说明我要执行的操作,可以通过在两个不同的位置单击并在其中生成路径来沿网格表面绘制样条图片:enter image description here

我的类型定义是:

typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel;
typedef CGAL::Surface_mesh<Kernel::Point_3> Triangle_mesh;
typedef CGAL::Surface_mesh_shortest_path_traits<Kernel, Triangle_mesh> Traits;
// default property maps
typedef boost::property_map<Triangle_mesh,
    boost::vertex_external_index_t>::type  Vertex_index_map;
typedef boost::property_map<Triangle_mesh,
    CGAL::halfedge_external_index_t>::type Halfedge_index_map;
typedef boost::property_map<Triangle_mesh,
    CGAL::face_external_index_t>::type     Face_index_map;
typedef CGAL::Surface_mesh_shortest_path<Traits> Surface_mesh_shortest_path;
typedef boost::graph_traits<Triangle_mesh> Graph_traits;
typedef Graph_traits::vertex_iterator vertex_iterator;
typedef Graph_traits::halfedge_iterator halfedge_iterator;
typedef Graph_traits::face_iterator face_iterator;

我的代码如下:

Traits::Barycentric_coordinates src_face_location = { { p1.barycentric[2], p1.barycentric[0], p1.barycentric[1] } };
face_iterator src_face_it = faces(map->m_cgal_mesh).first;
std::advance(src_face_it, src_faceIndex);

map->m_shortest_paths->remove_all_source_points();
map->m_shortest_paths->add_source_point(*src_face_it, src_face_location);

Traits::Barycentric_coordinates dest_face_location = { { p2.barycentric[2], p2.barycentric[0], p2.barycentric[1] } };
face_iterator dest_face_it = faces(map->m_cgal_mesh).first;
std::advance(dest_face_it, dest_faceIndex);

std::vector<Traits::Point_3> cgal_points;
auto r = map->m_shortest_paths->shortest_path_points_to_source_points(*dest_face_it, dest_face_location, std::back_inserter(cgal_points));

points.resize(cgal_points.size(), 3);

for (int i = 0; i < cgal_points.size(); ++i) {
    auto const& p = cgal_points[i];
    points.row(i) = RowVector3d(p.x(), p.y(), p.z());
}

此过程占总时间的99%:

auto r = map->m_shortest_paths->shortest_path_points_to_source_points(*dest_face_it, dest_face_location, std::back_inserter(cgal_points));

关于如何提高性能的任何想法?

2 个答案:

答案 0 :(得分:5)

CGAL文档指出,当您在2D平面上展开网格时,最短路径始终是一条直线。 最短路径算法的输入是具有重心坐标的顶点或平面。您可以将这些输入坐标映射到已映射到网格上的2D纹理。 在纹理的起点和终点之间绘制一条红线。 您将必须更深入地研究如何将顶点输入坐标转换为纹理中的绝对XY坐标。 还请记住,最短路径可能在网格的背面。根据纹理的映射方式,可能需要绘制多于1条线。

答案 1 :(得分:3)

从文档中很明显。您需要先致电build_sequence_tree我的建议是您在用户单击目标之前将这种性能提升置于某处-这可能是在首先选择源时,因此当用户开始四处单击时不会感觉到。如果您能找到一种在后台安全运行此方法的方法,那就更好了。

  

2.1.3构建内部序列树

     

最短路径查询的耗时操作包括   建立用于进行查询的内部数据结构。这个   数据结构称为序列树。它将被建造   自动完成第一个最短路径查询后   只要源点集重复用于任何后续查询   不会改变。每次更改源点集时,   序列树需要重建(如果已经构建)。请注意,它可以   也可以通过调用来手动构建   Surface_mesh_shortest_path :: build_sequence_tree()。​​

https://doc.cgal.org/latest/Surface_mesh_shortest_path/index.html

另外,看起来该算法在最坏情况的多项式时间内运行。正如其他人指出的那样,如果您知道问题在所有情况下都是凸的,则有可能进行优化。