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;
}
corefine_and_compute_union
,corefine_and_compute_intersection
. Je n'ai pas de compréhension claire dans les documents. Pouvez-vous expliquer un peu?corefine_and_compute_union
calcule les segments du maillage qui se chevauchent et doivent être supprimés et remplacés par un remplissage polygonal.corefine_and_compute_intersection
est 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.À 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.
la source