CGAL menghubungkan 2 geometri

11

Saat ini saya mencoba untuk bergabung dengan berbagai bagian Mesh, yang tidak terhubung. Dari contoh saya menemukan ini (blobby_3cc.off).

Dengan keep_large_connected_componentsdan keep_largest_connected_componentssaya menghapus semua komponen yang lebih kecil. Yang membuat 3 ini di bawah.

Saya tidak dapat menemukan cara dalam dokumentasi untuk bergabung bersama mereka dan mengisi bagian yang hilang. Salah satu solusinya adalah membuat 1 segitiga dan mengisi lubang (sejak saat itu adalah 1 objek, dengan lubang yang sangat besar). Tetapi saya tidak dapat menemukan cara untuk bergabung bersama ini.

Adakah yang punya solusi untuk ini?

Saya menggunakan CGAL untuk C ++.

masukkan deskripsi gambar di sini

Niels
sumber

Jawaban:

3

Ketika saya mulai dengan CGAL, saya segera mengalami masalah ini. Saya dapat menemukan solusi setelah membaca dokumentasi mesh poligon dengan cermat . Pada dasarnya, melalui versi modifikasi dari Corefinement , Anda dapat dengan lancar menyatukan dua geometri yang terpisah, tidak peduli jumlah atau bentuk poli mereka (namun, semakin besar perbedaan poligon, semakin kurang efektifnya).

Yang harus Anda lakukan adalah terlebih dahulu, pastikan geometri tidak berpotongan sendiri. Kedua, pastikan itu CGAL::Polygon_mesh_processing::clip()aktif pada dua geometri (saya sarankan menggunakan close_volumes=false). Selanjutnya, hitung penyatuan dua jerat baru:

#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;
}

Alih-alih menggunakan mesh dengan titik dari kernel dengan konstruksi yang tepat, titik-titik yang tepat adalah properti dari simpul mesh yang dapat kita gunakan kembali dalam operasi selanjutnya. Dengan properti itu, kita dapat memanipulasi mesh dengan poin yang memiliki koordinat floating point tetapi manfaat dari kekokohan yang diberikan oleh konstruksi yang tepat .:

#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;
}
Waltz Kematian
sumber
Dan untuk mengisi lubang, lihat Combinatorial Repairing dan hole filling
Death Waltz
Terimakasih atas balasan anda. Saya mencoba untuk memahami kode Anda, tetapi beberapa fungsi saya sepertinya tidak mengerti corefine_and_compute_union, corefine_and_compute_intersection. Saya tidak mendapatkan pemahaman yang jelas dalam dokumen. Bisakah Anda jelaskan sedikit?
Niels
Intinya, corefine_and_compute_unionhitung segmen-segmen dari mesh yang tumpang tindih, dan perlu dihilangkan dan diganti dengan isian poligon. corefine_and_compute_intersectiondekat dengan hal yang sama, tetapi menggunakan mesh yang ada untuk mengisi potongan bukannya menghasilkan fill mesh halus. Fungsi pertama biasanya membutuhkan input yang tepat untuk bekerja, tetapi yang kedua memungkinkannya untuk lulus sendiri sebagai parameter.
Death Waltz
Saya harus memeriksanya akhir pekan ini dan melihat hasilnya jadi saya tahu cara kerjanya. Saya akan menerima jawaban ini sebagai jawaban yang benar sebelum hadiah habis.
Niels
Baiklah, jika tidak berhasil, beri tahu saya
Death Waltz
0

Bagaimana tampilan mesh awalnya? mungkinkah menggabungkan komponen yang berbeda daripada menghapus bagian terkecil? Lihat perbaikan kombinasi CGAL untuk info lebih lanjut.

Menghubungkan berbagai komponen adalah masalah yang agak sulit. Saya percaya algoritma mengisi lubang biasa hanya bekerja pada lubang yang dibatasi, yaitu ada tepi terbuka yang berjalan di sekitar lubang dan berakhir di awal.

Rekomendasi saya akan menganalisis mesh untuk menemukan daftar tepi terbuka yang perlu dihubungkan, yaitu garis merah, hijau, biru dan ungu. Temukan cara untuk memasangkan ini satu sama lain, yaitu reg-hijau dan biru-ungu. Dalam contoh itu harus cukup dengan hanya menggunakan rata-rata tepi untuk pemasangan.

Maka Anda akan memerlukan beberapa metode untuk melakukan triangulasi celah di antara tepinya. Seperti yang Anda sebutkan, itu seharusnya cukup untuk membuat segitiga (atau dua) untuk menghubungkan bagian-bagian, dan menggunakan sesuatu seperti CGAL :: Polygon_mesh_processing :: triangulate_refine_and_fair_hole untuk mengisi sisanya.

Untuk melakukan ini, Anda dapat mencoba menemukan dua tepi dari setiap daftar yang dekat satu sama lain. Yaitu jumlah jarak titik sekecil mungkin. Jadi pilih satu sisi dari satu daftar dan temukan sisi terdekat di sisi lainnya. Saat Anda memiliki dua sisi, tambahkan sepasang segitiga dan gunakan CGAL untuk mengisi sisanya. Bagian-bagian yang berbeda harus memiliki orientasi permukaan yang sama agar ini berfungsi, tetapi mungkin itulah masalahnya.

Pendekatan lain adalah dengan hanya menggunakan simpul untuk membuat mesh dari titik cloud , tetapi ini tidak dijamin cocok dengan mesh Anda saat ini. Solusi termudah mungkin adalah mencoba untuk menghindari masalah sama sekali, yaitu memastikan sumber jerat menghasilkan jerat terhubung yang terdefinisi dengan baik.

contoh tepi untuk terhubung

JonasH
sumber
Terima kasih atas balasan Anda, ini memang pendekatan yang telah saya kerjakan untuk sementara waktu, saya hampir selesai pemrograman, saat ini mengalami masalah dengan wajah di arah yang salah sehingga lubang pengisian gagal.
Niels