CGAL, що з'єднує 2 геометрії


11

В даний час я намагаюся приєднатися до різних частин Mesh, які не пов'язані між собою. З прикладу я знайшов це (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;
}

А щоб заповнити будь-які отвори, дивіться комбінаторний ремонт та заповнення отворів
Вальс смерті

Дякую за вашу відповідь Я намагаюся зрозуміти ваш код, але деякі функції я , здається, не розуміють corefine_and_compute_union, corefine_and_compute_intersection. Я не розумію чітко розуміння в документах. Ви можете трохи пояснити?
Нільс

По суті, corefine_and_compute_unionобчислює сегменти сітки, які перекриваються, і їх потрібно видалити і замінити на заливку багатокутника. corefine_and_compute_intersectionблизький до тієї ж речі, але використовує існуючу сітку для заповнення розрізу, а не генерування гладкої сітки. Перша функція зазвичай вимагає точного введення для роботи, але друга дозволяє їй передавати себе як параметр.
Вальс смерті

Мені потрібно перевірити це в ці вихідні і побачити результат, щоб я знав, як це працює. Я прийму цю відповідь як правильну відповідь, перш ніж виграш щедрість.
Нільс

Добре, якщо це не працює, дайте мені знати
Вальс Смерти,

0

Як виглядає сітка спочатку? чи було б можливо об'єднати різні компоненти, а не видалити найдрібніші частини? Для отримання додаткової інформації див. Комбінаторний ремонт CGAL .

Підключення різних компонентів - досить складна проблема. я вважаю, що алгоритми заповнення звичайних отворів працюють лише на обмежених отворах, тобто є відкритий край, який проходить навколо отвору і закінчується на початку.

Моєю рекомендацією було б проаналізувати сітку, щоб знайти відкриті списки країв, які потрібно з'єднати, тобто червоні, зелені, сині та фіолетові лінії. Знайдіть спосіб з’єднати їх між собою, тобто reg-green та blue-purple. У прикладі повинно бути достатньо просто використати середню частину ребер для створення пари.

Тоді вам знадобиться якийсь метод для тріангуляції зазору між ребрами. Як ви вже згадували, для з’єднання деталей має бути достатньо створити трикутник (або два) і використовувати щось, наприклад CGAL :: Polygon_mesh_processing :: triangulate_refine_and_fair_hole, щоб заповнити решту.

Для цього ви можете спробувати знайти два краї кожного списку, які знаходяться близько один до одного. Тобто сума точкових відстаней є якомога меншою. Тому виберіть один край з одного списку і знайдіть найближчий край в іншому. Коли у вас два ребра, додайте пару трикутників і використовуйте CGAL для заповнення решти. Різні частини повинні мати однакову орієнтацію поверхні, щоб це працювало, але це, мабуть, так.

Іншим підходом було б просто використовувати вершини для створення сітки з точкової хмари , але це не гарантовано відповідає вашій поточній сітці. Найпростіше рішення - це, мабуть, спробувати взагалі уникнути проблеми, тобто переконатися, що джерело сіток виробляє чітко визначені з'єднані сітки.

приклад ребер для з'єднання


Дякую за Вашу відповідь, це справді підхід, над яким я працював деякий час, я майже закінчив програмування, наразі виникли проблеми з обличчями в неправильному напрямку, тому отвори для заповнення не вдається.
Нільс
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.