【问题标题】:CGAL connecting 2 geometriesCGAL 连接 2 个几何图形
【发布时间】:2020-03-05 21:48:52
【问题描述】:

目前我尝试加入未连接的网格的不同部分。从示例中我发现了这个( blobby_3cc.off )。

使用keep_large_connected_componentskeep_largest_connected_components,我删除了所有较小的组件。这将这 3 个保留在下面。

我在文档中找不到将它们连接在一起并填补缺失部分的方法。一种解决方案是创建 1 个三角形并填充孔(因为它是 1 个对象,带有巨大的孔)。但我找不到将它们连接在一起的方法。

谁有解决办法?

我在 C++ 中使用 CGAL。

【问题讨论】:

    标签: 3d geometry cgal


    【解决方案1】:

    当我开始使用 CGAL 时,我几乎立即遇到了这个问题。在仔细阅读polygon mesh documentation 后,我能够找到解决方案。本质上,通过Corefinement 的修改版本,您可以平滑地将两个单独的几何体网格在一起,无论它们的多边形数量或形状如何(但是,多边形的差异越大,效果就越差)。

    您首先要做的是确保几何图形不会自相交。其次,确保CGAL::Polygon_mesh_processing::clip() 在两个几何图形上处于活动状态(我建议使用close_volumes=false)。接下来,计算两个新网格的并集:

    #include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
    #include <CGAL/Surface_mesh.h>
    #include <CGAL/Polygon_mesh_processing/corefinement.h>
    #include <fstream>
    typedef CGAL::Exact_predicates_inexact_constructions_kernel K;
    typedef CGAL::Surface_mesh<K::Point_3>             Mesh;
    namespace PMP = CGAL::Polygon_mesh_processing;
    int main(int argc, char* argv[])
    {
      const char* filename1 = (argc > 1) ? argv[1] : "data/blobby.off";
      const char* filename2 = (argc > 2) ? argv[2] : "data/eight.off";
      std::ifstream input(filename1);
      Mesh mesh1, mesh2;
      if (!input || !(input >> mesh1))
      {
        std::cerr << "First mesh is not a valid off file." << std::endl;
        return 1;
      }
      input.close();
      input.open(filename2);
      if (!input || !(input >> mesh2))
      {
        std::cerr << "Second mesh is not a valid off file." << std::endl;
        return 1;
      }
      Mesh out;
      bool valid_union = PMP::corefine_and_compute_union(mesh1,mesh2, out);
      if (valid_union)
      {
        std::cout << "Union was successfully computed\n";
        std::ofstream output("union.off");
        output << out;
        return 0;
      }
      std::cout << "Union could not be computed\n";
      return 1;
    }
    

    与使用具有精确构造的内核中的点的网格不同,精确点是网格顶点的属性,我们可以在以后的操作中重用它。使用该属性,我们可以操作具有浮点坐标的点的网格,但受益于精确构造提供的鲁棒性。:

    #include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
    #include <CGAL/Exact_predicates_exact_constructions_kernel.h>
    #include <CGAL/Surface_mesh.h>
    #include <CGAL/Polygon_mesh_processing/corefinement.h>
    #include <fstream>
    typedef CGAL::Exact_predicates_inexact_constructions_kernel K;
    typedef CGAL::Exact_predicates_exact_constructions_kernel EK;
    typedef CGAL::Surface_mesh<K::Point_3> Mesh;
    typedef boost::graph_traits<Mesh>::vertex_descriptor vertex_descriptor;
    typedef Mesh::Property_map<vertex_descriptor,EK::Point_3> Exact_point_map;
    typedef Mesh::Property_map<vertex_descriptor,bool> Exact_point_computed;
    namespace PMP = CGAL::Polygon_mesh_processing;
    namespace params = PMP::parameters;
    struct Coref_point_map
    {
      // typedef for the property map
      typedef boost::property_traits<Exact_point_map>::value_type value_type;
      typedef boost::property_traits<Exact_point_map>::reference reference;
      typedef boost::property_traits<Exact_point_map>::category category;
      typedef boost::property_traits<Exact_point_map>::key_type key_type;
      // exterior references
      Exact_point_computed* exact_point_computed_ptr;
      Exact_point_map* exact_point_ptr;
      Mesh* mesh_ptr;
      Exact_point_computed& exact_point_computed() const
      {
        CGAL_assertion(exact_point_computed_ptr!=NULL);
        return *exact_point_computed_ptr;
      }
      Exact_point_map& exact_point() const
      {
        CGAL_assertion(exact_point_ptr!=NULL);
        return *exact_point_ptr;
      }
      Mesh& mesh() const
      {
        CGAL_assertion(mesh_ptr!=NULL);
        return *mesh_ptr;
      }
      // Converters
      CGAL::Cartesian_converter<K, EK> to_exact;
      CGAL::Cartesian_converter<EK, K> to_input;
      Coref_point_map()
        : exact_point_computed_ptr(NULL)
        , exact_point_ptr(NULL)
        , mesh_ptr(NULL)
      {}
      Coref_point_map(Exact_point_map& ep,
                      Exact_point_computed& epc,
                      Mesh& m)
        : exact_point_computed_ptr(&epc)
        , exact_point_ptr(&ep)
        , mesh_ptr(&m)
      {}
      friend
      reference get(const Coref_point_map& map, key_type k)
      {
        // create exact point if it does not exist
        if (!map.exact_point_computed()[k]){
          map.exact_point()[k]=map.to_exact(map.mesh().point(k));
          map.exact_point_computed()[k]=true;
        }
        return map.exact_point()[k];
      }
      friend
      void put(const Coref_point_map& map, key_type k, const EK::Point_3& p)
      {
        map.exact_point_computed()[k]=true;
        map.exact_point()[k]=p;
        // create the input point from the exact one
        map.mesh().point(k)=map.to_input(p);
      }
    };
    int main(int argc, char* argv[])
    {
      const char* filename1 = (argc > 1) ? argv[1] : "data/blobby.off";
      const char* filename2 = (argc > 2) ? argv[2] : "data/eight.off";
      std::ifstream input(filename1);
      Mesh mesh1, mesh2;
      if (!input || !(input >> mesh1))
      {
        std::cerr << "First mesh is not a valid off file." << std::endl;
        return 1;
      }
      input.close();
      input.open(filename2);
      if (!input || !(input >> mesh2))
      {
        std::cerr << "Second mesh is not a valid off file." << std::endl;
        return 1;
      }
      Exact_point_map mesh1_exact_points =
        mesh1.add_property_map<vertex_descriptor,EK::Point_3>("e:exact_point").first;
      Exact_point_computed mesh1_exact_points_computed =
        mesh1.add_property_map<vertex_descriptor,bool>("e:exact_points_computed").first;
      Exact_point_map mesh2_exact_points =
        mesh2.add_property_map<vertex_descriptor,EK::Point_3>("e:exact_point").first;
      Exact_point_computed mesh2_exact_points_computed =
        mesh2.add_property_map<vertex_descriptor,bool>("e:exact_points_computed").first;
      Coref_point_map mesh1_pm(mesh1_exact_points, mesh1_exact_points_computed, mesh1);
      Coref_point_map mesh2_pm(mesh2_exact_points, mesh2_exact_points_computed, mesh2);
      if ( PMP::corefine_and_compute_intersection(mesh1,
                                                  mesh2,
                                                  mesh1,
                                                  params::vertex_point_map(mesh1_pm),
                                                  params::vertex_point_map(mesh2_pm),
                                                  params::vertex_point_map(mesh1_pm) ) )
      {
        if ( PMP::corefine_and_compute_union(mesh1,
                                             mesh2,
                                             mesh2,
                                             params::vertex_point_map(mesh1_pm),
                                             params::vertex_point_map(mesh2_pm),
                                             params::vertex_point_map(mesh2_pm) ) )
        {
          std::cout << "Intersection and union were successfully computed\n";
          std::ofstream output("inter_union.off");
          output << mesh2;
          return 0;
        }
        std::cout << "Union could not be computed\n";
        return 1;
      }
      std::cout << "Intersection could not be computed\n";
      return 1;
    }
    

    【讨论】:

    • 要填补任何漏洞,请参阅Combinatorial Repairinghole filling
    • 感谢您的回复。我试图理解你的代码,但有些功能我似乎不理解corefine_and_compute_unioncorefine_and_compute_intersection。我在文档中没有得到任何明确的理解。你能解释一下吗?
    • 基本上,corefine_and_compute_union 计算重叠的网格段,需要移除并替换为多边形填充。 corefine_and_compute_intersection 接近于相同的东西,但使用现有的网格来填充切口,而不是生成平滑的网格填充。第一个函数通常需要精确的输入才能工作,但第二个函数允许它作为参数传递自己。
    • 我确实必须在这个周末检查它并查看结果,以便我知道它是如何工作的。在赏金用完之前,我会接受这个答案作为正确答案。
    【解决方案2】:

    网格最初看起来如何?合并不同的组件而不是删除最小的部分是否可行?请参阅CGAL combinatorical repairing 了解更多信息。

    连接不同的组件是一个相当困难的问题。我相信常规的孔填充算法仅适用于有界的孔,即有一个开放的边缘环绕孔并在开始时结束。

    我的建议是分析网格以找到需要连接的开放边列表,即红色、绿色、蓝色和紫色线。找到一种方法将它们相互配对,即 reg-green 和 blue-purple。在示例中,仅使用边缘的平均值进行配对就足够了。

    然后你需要一些方法来三角测量边缘之间的间隙。正如您所提到的,创建一个(或两个)三角形来连接部件就足够了,并使用 CGAL::Polygon_mesh_processing::triangulate_refine_and_fair_hole 之类的东西来填充其余部分。

    为此,您可以尝试找到每个列表中彼此靠近的两条边。 IE。点距离之和尽可能小。因此,从一个列表中选择一个边缘并在另一个列表中找到最近的边缘。当你有两条边时,添加一对三角形并使用 CGAL 填充其余部分。不同的部分应该具有相同的表面方向才能工作,但可能就是这种情况。

    另一种方法是只使用create a mesh from a point cloud 的顶点,但这不能保证与您当前的网格相匹配。最简单的解决方案可能是尝试完全避免该问题,即确保网格源产生定义明确的连接网格。

    【讨论】:

    • 感谢您的回复,这确实是我一直在研究的方法,我几乎完成了编程,目前遇到错误方向的问题,因此填充孔失败。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-01-18
    • 1970-01-01
    • 2017-10-14
    • 1970-01-01
    • 2018-08-01
    相关资源
    最近更新 更多