CGAL reliant 2 géométries


11

Actuellement, j'essaie de joindre différentes parties du maillage, qui ne sont pas connectées. Dans l'exemple, j'ai trouvé cela (blobby_3cc.off).

Avec le keep_large_connected_componentset le keep_largest_connected_componentsje supprime tous les petits composants. Ce qui garde ces 3 ci-dessous.

Je ne trouve aucun moyen dans la documentation de les réunir et de remplir les parties manquantes. Une solution est de créer 1 triangle et de remplir les trous (depuis lors c'est 1 objet, avec d'énormes trous). Mais je ne trouve pas de moyen de les réunir.

Quelqu'un a une solution à cela?

J'utilise CGAL pour C ++.

entrez la description de l'image ici

Réponses:


3

Lorsque j'ai commencé avec CGAL, j'ai presque immédiatement rencontré ce problème. J'ai pu trouver une solution après avoir lu attentivement la documentation du maillage polygonal . Essentiellement, grâce à une version modifiée de Corefinement , vous pouvez mailler en douceur deux géométries distinctes, quels que soient leur nombre de poly ou leur forme (cependant, plus la différence de polygones est grande, moins elle deviendra efficace).

Ce que vous devez faire est d'abord, assurez-vous que la géométrie ne s'auto-intersecte pas. Deuxièmement, assurez-vous qu'il CGAL::Polygon_mesh_processing::clip()est actif sur les deux géométries (je suggère d'utiliser close_volumes=false). Ensuite, calculez l'union des deux nouvelles mailles:

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

Au lieu d'utiliser un maillage avec un point d'un noyau avec des constructions exactes, les points exacts sont une propriété des sommets du maillage que nous pouvons réutiliser dans des opérations ultérieures. Avec cette propriété, nous pouvons manipuler un maillage avec des points ayant des coordonnées en virgule flottante mais bénéficier de la robustesse fournie par les constructions exactes .:

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

Et pour combler les trous, voir Réparation combinatoire et remplissage des trous
Death Waltz

Merci pour votre réponse. J'essaie de comprendre votre code, mais certaines fonctions , je ne semble pas comprendre corefine_and_compute_union, corefine_and_compute_intersection. Je n'ai pas de compréhension claire dans les documents. Pouvez-vous expliquer un peu?
Niels

Essentiellement, corefine_and_compute_unioncalcule les segments du maillage qui se chevauchent et doivent être supprimés et remplacés par un remplissage polygonal. corefine_and_compute_intersectionest proche de la même chose, mais utilise le maillage existant pour remplir la coupe au lieu de générer un remplissage de maillage lisse. La première fonction nécessite généralement une entrée exacte pour fonctionner, mais la seconde lui permet de se passer en paramètre.
Death Waltz

Je dois le vérifier ce week-end et voir le résultat, donc je sais comment cela fonctionne. J'accepterai cette réponse comme la bonne réponse avant la fin de la prime.
Niels

D'accord, si cela ne fonctionne pas, faites le moi savoir
Death Waltz

0

À quoi ressemble le maillage à l'origine? serait-il possible de fusionner les différents composants plutôt que d'enlever les plus petites pièces? Voir la réparation combinatoire CGAL pour plus d'informations.

La connexion de différents composants est un problème assez difficile. je crois que les algorithmes de remplissage de trous réguliers ne fonctionnent que sur les trous qui sont délimités, c'est-à-dire qu'il y a un bord ouvert qui fait le tour du trou et se termine au début.

Ma recommandation serait d'analyser le maillage pour trouver les arêtes-listes ouvertes à connecter, c'est-à-dire les lignes rouges, vertes, bleues et violettes. Trouvez un moyen de les associer les uns aux autres, c'est-à-dire vert reg et bleu-violet. Dans l'exemple, il devrait suffire d'utiliser simplement la moyenne des bords pour l'appariement.

Ensuite, vous auriez besoin d'une méthode pour trianguler l'écart entre les bords. Comme vous le mentionnez, il devrait être suffisant de créer un triangle (ou deux) pour connecter les pièces et d'utiliser quelque chose comme CGAL :: Polygon_mesh_processing :: triangulate_refine_and_fair_hole pour remplir le reste.

Pour ce faire, vous pouvez essayer de trouver les deux bords de chaque liste qui sont proches l'un de l'autre. C'est-à-dire que la somme des distances ponctuelles est aussi petite que possible. Choisissez donc un bord dans une liste et trouvez le bord le plus proche dans l'autre. Lorsque vous avez deux arêtes, ajoutez une paire de triangles et utilisez CGAL pour remplir le reste. Les différentes pièces doivent avoir la même orientation de surface pour que cela fonctionne, mais c'est probablement le cas.

Une autre approche consisterait à simplement utiliser les sommets pour créer un maillage à partir d'un nuage de points , mais cela n'est pas garanti pour correspondre à votre maillage actuel. La solution la plus simple est probablement d'essayer d'éviter complètement le problème, c'est-à-dire de s'assurer que la source des mailles produit des mailles connectées bien définies.

exemple de bords à connecter


Merci pour votre réponse, c'est en effet l'approche sur laquelle je travaille depuis un moment, j'ai presque fini de programmer, ayant actuellement des problèmes avec des visages dans la mauvaise direction donc les trous de remplissage échouent.
Niels
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.