CGAL เชื่อมต่อ 2 รูปทรง


11

ปัจจุบันฉันพยายามเข้าร่วมส่วนต่าง ๆ ของตาข่ายซึ่งไม่ได้เชื่อมต่อ จากตัวอย่างฉันพบสิ่งนี้ (blobby_3cc.off)

ด้วยkeep_large_connected_componentsและkeep_largest_connected_componentsฉันจะลบองค์ประกอบที่มีขนาดเล็กทั้งหมด ซึ่งทำให้ทั้ง 3 ด้านล่าง

ฉันไม่สามารถหาวิธีในเอกสารประกอบเพื่อเข้าร่วมด้วยกันและเติมส่วนที่ขาดหายไป ทางออกหนึ่งคือการสร้าง 1 สามเหลี่ยมและเติมหลุม (ตั้งแต่นั้นเป็น 1 วัตถุที่มีรูมหาศาล) แต่ฉันไม่สามารถหาวิธีที่จะเข้าร่วมด้วยกันได้

ใครมีวิธีแก้ปัญหานี้?

ฉันกำลังใช้ CGAL สำหรับ C ++

ป้อนคำอธิบายรูปภาพที่นี่

คำตอบ:


3

เมื่อฉันเริ่มต้นด้วย CGAL ฉันพบปัญหานี้เกือบจะในทันที ผมสามารถที่จะหาทางแก้ปัญหาอย่างระมัดระวังหลังจากอ่านมากกว่าเอกสารตาข่ายรูปหลายเหลี่ยม โดยพื้นฐานแล้วผ่านการแก้ไข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 Repairingและการเติมหลุม
Death Waltz

ขอบคุณสำหรับการตอบกลับของคุณ. ฉันพยายามที่จะเข้าใจรหัสของคุณ แต่ฟังก์ชั่นบางอย่างที่ฉันดูเหมือนจะไม่เข้าใจ,corefine_and_compute_union corefine_and_compute_intersectionฉันไม่เข้าใจชัดเจนในเอกสาร คุณช่วยอธิบายหน่อยได้ไหม?
Niels

เป็นหลักcorefine_and_compute_unionคำนวณส่วนของตาข่ายที่ทับซ้อนกันและจำเป็นต้องลบและแทนที่ด้วยการเติมรูปหลายเหลี่ยม corefine_and_compute_intersectionใกล้เคียงกับสิ่งเดียวกัน แต่ใช้ตาข่ายที่มีอยู่เพื่อเติมรอยตัดแทนที่จะสร้างตาข่ายแบบเรียบ ฟังก์ชั่นแรกมักจะต้องการอินพุตที่แน่นอนในการทำงาน แต่ฟังก์ชันที่สองอนุญาตให้ส่งผ่านตัวเองเป็นพารามิเตอร์
Death Waltz

ฉันต้องตรวจสอบมันในสุดสัปดาห์นี้และดูผลลัพธ์เพื่อให้ฉันรู้ว่ามันทำงานอย่างไร ฉันจะยอมรับคำตอบนี้เป็นคำตอบที่ถูกต้องก่อนที่เงินรางวัลจะหมด
Niels

เอาล่ะถ้ามันไม่ทำงานให้ฉันรู้
Death Waltz

0

แต่เดิมตาข่ายมีลักษณะอย่างไร เป็นไปได้ไหมที่จะรวมส่วนประกอบต่าง ๆ แทนที่จะเอาชิ้นส่วนที่เล็กที่สุดออก ดูCGAL combinatorical ซ่อมสำหรับข้อมูลเพิ่มเติม

การเชื่อมต่อส่วนประกอบต่าง ๆ เป็นปัญหาที่ค่อนข้างยาก ฉันเชื่อว่าอัลกอริธึมการอุดรูปกตินั้นใช้ได้กับหลุมที่มีขอบเขตเท่านั้นนั่นคือมีขอบเปิดที่ไปรอบ ๆ รูและสิ้นสุดเมื่อเริ่มต้น

คำแนะนำของฉันคือการวิเคราะห์ตาข่ายเพื่อค้นหารายการขอบเปิดที่ต้องเชื่อมต่อเช่นเส้นสีแดงสีเขียวสีน้ำเงินและสีม่วง ค้นหาวิธีการจับคู่สิ่งเหล่านี้ด้วยกันเช่น reg-green และ blue-purple ในตัวอย่างมันควรจะเพียงพอที่จะใช้ค่าเฉลี่ยของขอบสำหรับการจับคู่

จากนั้นคุณจะต้องใช้วิธีในการวิเคราะห์ช่องว่างระหว่างขอบ ดังที่คุณกล่าวถึงมันควรจะเพียงพอที่จะสร้างรูปสามเหลี่ยม (หรือสอง) เพื่อเชื่อมต่อชิ้นส่วนและใช้สิ่งที่ชอบ CGAL :: Polygon_mesh_processing :: triangulate_refine_refine_and_fair_hole เพื่อเติมส่วนที่เหลือ

เมื่อต้องการทำเช่นนี้คุณสามารถลองค้นหาทั้งสองขอบของแต่ละรายการที่อยู่ใกล้กัน เช่นผลรวมของระยะทางจุดเล็กที่สุด ดังนั้นเลือกหนึ่งขอบจากรายการหนึ่งและค้นหาขอบที่ใกล้เคียงที่สุดในอีกรายการหนึ่ง เมื่อคุณมีสองขอบเพิ่มสามเหลี่ยมหนึ่งคู่และใช้ CGAL เพื่อเติมส่วนที่เหลือ ส่วนต่าง ๆ ควรมีการวางแนวพื้นผิวแบบเดียวกันเพื่อให้ใช้งานได้ แต่อาจเป็นไปได้

อีกวิธีคือการใช้จุดยอดในการสร้างตาข่ายจากจุดเมฆแต่มันไม่รับประกันว่าจะตรงกับตาข่ายปัจจุบันของคุณ วิธีแก้ปัญหาที่ง่ายที่สุดน่าจะพยายามหลีกเลี่ยงปัญหาทั้งหมดเช่นตรวจสอบให้แน่ใจว่าแหล่งที่มาของตาข่ายผลิตตาข่ายเชื่อมต่อที่กำหนดไว้อย่างดี

ตัวอย่างของขอบที่จะเชื่อมต่อ


ขอบคุณสำหรับคำตอบของคุณนี่เป็นวิธีการที่ฉันได้ดำเนินการมาระยะหนึ่งแล้วฉันเกือบจะเสร็จสิ้นการเขียนโปรแกรมขณะนี้มีปัญหากับใบหน้าในทิศทางที่ไม่ถูกต้องดังนั้นช่องเติมจะล้มเหลว
Niels
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.