CGAL 2 geometriyi birleştirme


11

Şu anda Mesh'in bağlı olmayan farklı kısımlarına katılmaya çalışıyorum. Örnekte bunu buldum (blobby_3cc.off).

İle keep_large_connected_componentsve keep_largest_connected_componentstüm küçük bileşenleri kaldırırım. Hangi bu 3 aşağıda tutar.

Belgelerde bir araya gelip eksik parçaları doldurmanın bir yolunu bulamıyorum. Bir çözüm 1 üçgen oluşturmak ve delikleri doldurmaktır (o zamandan beri muazzam deliklerle 1 nesne). Ama bunlara birlikte katılmanın bir yolunu bulamıyorum.

Bunun için bir çözümü olan var mı?

C ++ için CGAL kullanıyorum.

resim açıklamasını buraya girin

Yanıtlar:


3

CGAL ile başladığımda hemen bu problemle karşılaştım. Çokgen örgü belgelerini dikkatlice okuduktan sonra bir çözüm bulabildim . Temel olarak, Corefinement'in değiştirilmiş bir versiyonu sayesinde , poli sayısı veya şekli ne olursa olsun, iki ayrı geometriyi düzgün bir şekilde birleştirebilirsiniz (ancak, çokgenlerin farkı ne kadar büyük olursa, o kadar az etkili olacaktır).

Yapmanız gereken ilk şey, geometrinin kendi kendine kesişmediğinden emin olmaktır. İkinci olarak, CGAL::Polygon_mesh_processing::clip()iki geometride aktif olduğundan emin olun (kullanmanızı öneririm close_volumes=false). Ardından, iki yeni kafesin birleşimini hesaplayın:

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

Tam konstrüksiyonları olan bir çekirdekten gelen bir noktaya sahip bir kafes kullanmak yerine, kesin noktalar daha sonraki işlemlerde tekrar kullanabileceğimiz kafes köşelerinin bir özelliğidir. Bu özellik ile, kayan nokta koordinatlarına sahip noktaları olan bir ağı manipüle edebiliriz, ancak tam konstrüksiyonlar tarafından sağlanan sağlamlıktan yararlanabiliriz .:

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

Ve herhangi bir deliği doldurmak için bkz. Kombinatoryal Onarım ve delik doldurma
Death Waltz

Cevabın için teşekkürler. Ben kodunuzu anlamaya çalışmak, ancak bazı işlevler anlıyorum görünmüyor corefine_and_compute_union, corefine_and_compute_intersection. Belgelerde net bir anlayış elde edemiyorum. Biraz açıklayabilir misin?
Niels

Esasen, corefine_and_compute_unionörgünün üst üste binen ve çıkarılması ve bir çokgen dolgu ile değiştirilmesi gereken bölümleri hesaplar. corefine_and_compute_intersectionaynı şeye yakındır, ancak düzgün bir kafes dolgusu oluşturmak yerine kesimi doldurmak için mevcut ağı kullanır. İlk işlev genellikle çalışmak için kesin bir girdi gerektirir, ancak ikincisi parametrenin kendisini geçirmesine izin verir.
Ölüm Waltz

Bu hafta sonu kontrol etmek ve sonucu görmek zorunda böylece nasıl çalıştığını biliyorum. Ödül bitmeden bu cevabı doğru cevap olarak kabul edeceğim.
Niels

Tamam, eğer işe yaramazsa, bana bildirin
Death Waltz

0

Örgü orijinal olarak nasıl görünüyor? en küçük parçaları çıkarmak yerine farklı bileşenleri birleştirmek mümkün müdür? Daha fazla bilgi için CGAL kombinatorik onarımına bakınız .

Farklı bileşenlerin bağlanması oldukça zor bir sorundur. Düzenli delik doldurma algoritmalarının sadece sınırlı delikler üzerinde çalıştığına inanıyorum, yani delik etrafında dolaşan ve başlangıçta biten açık bir kenar var.

Benim tavsiyem, bağlanması gereken açık kenar listelerini, yani kırmızı, yeşil, mavi ve mor çizgileri bulmak için örgüyü analiz etmektir. Bunları birbirleriyle eşleştirmenin bir yolunu bulun, örneğin reg-yeşil ve mavi-mor. Örnekte, eşleştirme için sadece kenarların ortalamasını kullanmak yeterli olmalıdır.

Sonra kenarlar arasındaki boşluğu üçgenlemek için bir yönteme ihtiyacınız olacaktır. Bahsettiğiniz gibi, parçaları bağlamak için bir üçgen (veya iki) oluşturmak ve gerisini doldurmak için CGAL :: Polygon_mesh_processing :: triangulate_refine_and_fair_hole gibi bir şey kullanmak yeterli olmalıdır.

Bunu yapmak için her listenin birbirine yakın iki kenarını bulmayı deneyebilirsiniz. Yani nokta mesafelerinin toplamı mümkün olduğunca küçük. Bu yüzden bir listeden bir kenar seçin ve diğerinde en yakın kenarı bulun. İki kenarınız olduğunda, bir çift üçgen ekleyin ve gerisini doldurmak için CGAL kullanın. Farklı parçalar bunun çalışması için aynı yüzey yönüne sahip olmalıdır, ancak muhtemelen durum böyledir.

Başka bir yaklaşım , bir nokta bulutundan bir kafes oluşturmak için sadece köşeleri kullanmak olacaktır , ancak bunun mevcut kafesinizle eşleşmesi garanti edilmez. En kolay çözüm muhtemelen problemi tamamen önlemeye çalışmaktır, yani ağların kaynağının iyi tanımlanmış bağlı ağlar üretmesini sağlamaktır.

bağlanacak kenar örneği


Cevabınız için teşekkür ederim, bu gerçekten bir süredir üzerinde çalıştığım yaklaşım, neredeyse programlamayı bitirdim, şu anda yüzleri yanlış yönde olan sorunları yaşıyorum, böylece doldurma delikleri başarısız oluyor.
Niels
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.