计算射线和网格之间的交点

To calculate intersections between a ray and a mesh

问题描述

我想使用函数 CGAL::advancing_front_surface_reconstruction() 计算射线和从点云构建的表面网格之间的所有交点。时间成本对我来说非常重要。所以我想使用名为 Fast Intersection and Distance Computation 的包。但是当我通过函数 tree() 从表面网格构建 AABBtree 时,出现了一个错误。 IDE 的错误列表显示:'<function-style-cast>' can not transform to CGAL::AABB_face_graph_triangle_primitive<meshCGAL, CGAL::Default, CGAL::Tag_true, CGAL::tag_false> from "initializer list"
当我使用 CGAL::advancing_front_surface_reconstruction() 从点云重建网格时,我使用名为 CGAL::Exact_predicates_inexact_constructions_kernel 的内核,但是 Simple_cartesian< 快速交点和距离计算需要double>内核。这是主要原因吗?如何同时使用这两个程序包?

代码

代码如下:

#include<iostream>
#include<vector>
#include<string>
#include<array>
#include<fstream>
#include<algorithm>

#include <CGAL/Simple_cartesian.h>
#include<CGAL/AABB_tree.h>
#include<CGAL/AABB_traits.h>
#include<CGAL/AABB_segment_primitive.h>
#include<CGAL/Surface_mesh.h>
#include <CGAL/AABB_face_graph_triangle_primitive.h>

#include<CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include<CGAL/Advancing_front_surface_reconstruction.h>
#include<CGAL/Surface_mesh.h>
#include <CGAL/boost/graph/IO/polygon_mesh_io.h>
#include<CGAL/Polygon_mesh_processing/corefinement.h>
#include<CGAL/polygon_mesh_processing/remesh.h>


using std::cout;
using std::cin;
using std::endl;
using std::string;

namespace PMP = CGAL::Polygon_mesh_processing;

typedef std::array<std::size_t, 3> Facet;
typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel;
typedef Kernel::Point_3 Point_3;
typedef CGAL::Surface_mesh <Point_3> Mesh;

typedef CGAL::Simple_cartesian<double> K;
typedef K::FT FT;
typedef K::Point_3 pointCGAL;
typedef K::Vector_3 vectorCGAL;
typedef K::Ray_3 rayCGAL;
typedef CGAL::Surface_mesh<pointCGAL> meshCGAL;
typedef boost::graph_traits<meshCGAL>::face_descriptor face_descriptor;
typedef boost::graph_traits<meshCGAL>::halfedge_descriptor halfedge_descriptor;

typedef CGAL::AABB_face_graph_triangle_primitive<meshCGAL> Primitive;
typedef CGAL::AABB_traits<K, Primitive> Traits;
typedef CGAL::AABB_tree<Traits> Tree;
typedef boost::optional<Tree::Intersection_and_primitive_id<rayCGAL>::Type> Ray_intersection;


struct Construct {
    Mesh& mesh;
    template <typename PointIterator>
    Construct(Mesh& mesh, PointIterator b, PointIterator e) :mesh(mesh) {
        for (; b != e; ++b) {
            boost::graph_traits<Mesh>::vertex_descriptor v;
            v = add_vertex(mesh);
            mesh.point(v) = *b;
        }
    }

    Construct& operator=(const Facet f) {
        typedef boost::graph_traits<Mesh>::vertex_descriptor vertex_descriptor;
        typedef boost::graph_traits<Mesh>::vertices_size_type size_type;
        mesh.add_face(vertex_descriptor(static_cast<size_type>(f[0])),
            vertex_descriptor(static_cast<size_type>(f[1])),
            vertex_descriptor(static_cast<size_type>(f[2])));
        return *this;
    }

    Construct& operator*() { return *this; }
    Construct& operator++() { return *this; }
    Construct& operator++(int) { return *this; }
};


int main() {

    //load sv
    Mesh sv;
    std::cout << "load sv49..." << std::endl;
    std::ifstream fin("./svPoints/sv49.txt");
    std::vector<Point_3> points;
    std::vector<Facet> facets;
    std::copy(std::istream_iterator<Point_3>(fin),
        std::istream_iterator<Point_3>(),
        std::back_inserter(points));
    fin.close();

    //convert sv to Surface_mesh, repair
    Construct construct(sv, points.begin(), points.end());
    CGAL::advancing_front_surface_reconstruction(points.begin(), points.end(), construct);//convert sv to surface_mesh
    CGAL::Polygon_mesh_processing::remove_isolated_vertices(sv);//filter out isolated vertices
    if (!CGAL::Polygon_mesh_processing::is_outward_oriented(sv))
        CGAL::Polygon_mesh_processing::reverse_face_orientations(sv);//make sure that the meshes are outer oriented
    CGAL::IO::write_polygon_mesh("sv49.off",sv);

    //build AABBtree of sv
    Tree tree(faces(sv).first, faces(sv).second, sv);
    vectorCGAL orientation(0, 0, 1);
    pointCGAL start = pointCGAL(0, 0, 0);
    rayCGAL ray_query(start, orientation);
    std::vector<Ray_intersection> intersections;
    tree.all_intersections(ray_query, std::back_inserter(intersections));
    if (!intersections.empty()) {
        for (auto intersect : intersections) {
            auto a = intersect->first;
            if (pointCGAL* p = boost::get<pointCGAL>(&a)) {
                cout << *p << endl;
            }
        }
    }
    return 0;
}

运行时环境

IDE: Visual Studio 2017
CGAL 版本:5.3
解决方案配置:Debug x64

文件

程序中使用的文件sv49.txt可以从GitHub下载,这里是link.


附加问题
当我使用内核 CGAL::Exact_predicates_inexact_constructions_kernel 而不是内核 Simple_cartesian 时,程序编译没有错误。但是当我在程序中测试从点(-100.0,-50.0,-100.0)开始在向量(0.0,0.0,1.0)方向上的光线与名为 sv 的网格之间的所有交点时,我得到了 46 个交点。结果很荒谬。然后我尝试内核CGAL::Exact_predicates_exact_constructions_kernel,结果也不准确。结果显示所有交集如下:

-100 -50 -10
-100 -50 -10
-100 -50 -10
-100 -50 -9
-100 -50 -8
-100 -50 -8
-100 -50 -9
-100 -50 -3
-100 -50 -1
-100 -50 -7
-100 -50 -7
-100 -50 -6
-100 -50 -5
-100 -50 -6
-100 -50 -5
-100 -50 -4
-100 -50 -4
-100 -50 -3
-100 -50 -2
-100 -50 -2
-100 -50 0
-100 -50 -0
-100 -50 -1
-100 -50 -0
-100 -50 -0

真正的交叉点应该是 (-100, -50, -0) 和 (-100, -50, -10)。重复的交集是合理的,其他的都是不可能的交集

在网格 sv 中绘制点 (-100,-50,-0) 后,我明白了为什么会出现看起来很荒谬的结果的原因。从技术上讲,这不是数学上的错误答案,只是不是我所期望的。从这一点开始并沿 (0, 0, 1) 方向的射线是与网格一侧的许多面相交的射线。在这种情况下,CGAL 库可以很好地计算交点,但我需要过滤掉交点。