Als ich mit CGAL anfing, stieß ich fast sofort auf dieses Problem. Nachdem ich die Dokumentation zum Polygonnetz sorgfältig gelesen hatte, konnte ich eine Lösung finden . Im Wesentlichen können Sie durch eine modifizierte Version von Corefinement zwei separate Geometrien unabhängig von ihrer Polyanzahl oder -form nahtlos miteinander verbinden (je größer der Unterschied der Polygone ist, desto weniger effektiv wird sie).
Stellen Sie zunächst sicher, dass sich die Geometrie nicht selbst schneidet. Stellen Sie zweitens sicher, dass CGAL::Polygon_mesh_processing::clip()
die beiden Geometrien aktiv sind (ich schlage vor, sie zu verwenden close_volumes=false
). Berechnen Sie als Nächstes die Vereinigung der beiden neuen Netze:
#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;
}
Anstatt ein Netz mit einem Punkt aus einem Kernel mit genauen Konstruktionen zu verwenden, sind die genauen Punkte eine Eigenschaft der Netzscheitelpunkte, die wir in späteren Operationen wiederverwenden können. Mit dieser Eigenschaft können wir ein Netz mit Punkten mit Gleitkommakoordinaten bearbeiten, aber von der Robustheit profitieren, die die genauen Konstruktionen bieten:
#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
. Ich habe kein klares Verständnis in den Dokumenten. Kannst du ein bisschen erklären?corefine_and_compute_union
Berechnet im Wesentlichen Segmente des Netzes, die sich überlappen und entfernt und durch eine Polygonfüllung ersetzt werden müssen.corefine_and_compute_intersection
ist in der Nähe der gleichen Sache, verwendet jedoch vorhandenes Netz, um den Schnitt zu füllen, anstatt eine glatte Netzfüllung zu erzeugen. Die erste Funktion erfordert normalerweise eine genaue Eingabe, um zu funktionieren, aber die zweite erlaubt es, sich selbst als Parameter zu übergeben.Wie sieht das Netz ursprünglich aus? Wäre es möglich, die verschiedenen Komponenten zusammenzuführen, anstatt die kleinsten Teile zu entfernen? Weitere Informationen finden Sie unter Kombinatorische CGAL-Reparatur .
Das Anschließen verschiedener Komponenten ist ein ziemlich schwieriges Problem. Ich glaube, die regulären Algorithmen zum Füllen von Löchern funktionieren nur bei Löchern, die begrenzt sind, dh es gibt eine offene Kante, die um das Loch herum verläuft und am Anfang endet.
Meine Empfehlung wäre, das Netz zu analysieren, um die offenen Kantenlisten zu finden, die verbunden werden müssen, dh die roten, grünen, blauen und violetten Linien. Finden Sie einen Weg, diese miteinander zu koppeln, dh reg-grün und blau-lila. Im Beispiel sollte es ausreichen, nur den Durchschnitt der Kanten für die Paarung zu verwenden.
Dann würden Sie eine Methode benötigen, um die Lücke zwischen den Kanten zu triangulieren. Wie Sie bereits erwähnt haben, sollte es ausreichen, ein Dreieck (oder zwei) zum Verbinden der Teile zu erstellen und den Rest mit CGAL :: Polygon_mesh_processing :: triangulate_refine_and_fair_hole zu füllen.
Zu diesem Zweck können Sie versuchen, die beiden Kanten jeder Liste zu finden, die nahe beieinander liegen. Dh die Summe der Punktabstände ist so klein wie möglich. Wählen Sie also eine Kante aus einer Liste aus und suchen Sie die nächstgelegene Kante in der anderen. Wenn Sie zwei Kanten haben, fügen Sie ein Paar Dreiecke hinzu und füllen Sie den Rest mit CGAL. Die verschiedenen Teile sollten die gleiche Oberflächenorientierung haben, damit dies funktioniert, aber das ist wahrscheinlich der Fall.
Ein anderer Ansatz wäre, nur die Eckpunkte zu verwenden, um ein Netz aus einer Punktwolke zu erstellen. Es ist jedoch nicht garantiert, dass dies mit Ihrem aktuellen Netz übereinstimmt. Die einfachste Lösung besteht wahrscheinlich darin, zu versuchen, das Problem insgesamt zu vermeiden, dh sicherzustellen, dass die Quelle der Netze gut definierte verbundene Netze erzeugt.
quelle