CGAL che collega 2 geometrie


11

Attualmente provo a unirmi a parti diverse della rete, che non sono collegate. Dall'esempio ho trovato questo (blobby_3cc.off).

Con keep_large_connected_componentse keep_largest_connected_componentsrimuovo tutti i componenti più piccoli. Che mantiene questi 3 sotto.

Non riesco a trovare un modo nella documentazione per unirli e riempire le parti mancanti. Una soluzione è quella di creare 1 triangolo e riempire i fori (da allora è 1 oggetto, con enormi fori). Ma non riesco a trovare un modo per unirli insieme.

Qualcuno ha una soluzione per questo?

Sto usando CGAL per C ++.

inserisci qui la descrizione dell'immagine

Risposte:


3

Quando ho iniziato con CGAL, ho riscontrato quasi immediatamente questo problema. Sono stato in grado di trovare una soluzione dopo aver letto attentamente la documentazione della mesh poligonale . In sostanza, attraverso una versione modificata di Corefinement , è possibile unire in modo uniforme due geometrie separate, indipendentemente dal numero di poligoni o dalla forma (tuttavia, maggiore è la differenza di poligoni, meno efficace diventerà).

Quello che devi fare è prima di tutto, assicurati che la geometria non si intersechi da sola. In secondo luogo, assicurarsi che CGAL::Polygon_mesh_processing::clip()sia attivo sulle due geometrie (suggerisco di utilizzare close_volumes=false). Successivamente, calcola l'unione delle due nuove mesh:

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

Invece di usare una mesh con un punto di un kernel con costruzioni esatte, i punti esatti sono una proprietà dei vertici della mesh che possiamo riutilizzare in operazioni successive. Con quella proprietà, possiamo manipolare una mesh con punti con coordinate in virgola mobile ma beneficiare della robustezza fornita dalle esatte costruzioni .:

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

E per riempire eventuali buchi, vedi Riparazione combinatoria e riempimento di buchi
Valzer della morte,

Grazie per la risposta. Cerco di capire il codice, ma alcune funzioni non mi sembra di capire corefine_and_compute_union, corefine_and_compute_intersection. Non ho alcuna chiara comprensione nei documenti. Puoi spiegarci un po '?
Niels,

In sostanza, corefine_and_compute_unioncalcola i segmenti della mesh che si sovrappongono e devono essere rimossi e sostituiti con un riempimento poligonale. corefine_and_compute_intersectionè simile alla stessa cosa, ma utilizza la mesh esistente per riempire il taglio invece di generare un riempimento uniforme della mesh. La prima funzione di solito richiede un input esatto per funzionare, ma la seconda consente di passare se stessa come parametro.
Death Waltz,

Devo verificarlo questo fine settimana e vedere il risultato, quindi so come funziona. Accetterò questa risposta come la risposta corretta prima che finisca la generosità.
Niels,

Va bene, se non funziona, fammi sapere
Death Waltz,

0

Come appare originariamente la mesh? sarebbe possibile unire i diversi componenti anziché rimuovere le parti più piccole? Vedi Riparazione combinatoria CGAL per maggiori informazioni.

Il collegamento di diversi componenti è un problema piuttosto difficile. credo che i normali algoritmi di riempimento dei fori funzionino solo su fori delimitati, ovvero c'è un bordo aperto che gira intorno al foro e finisce all'inizio.

La mia raccomandazione sarebbe quella di analizzare la mesh per trovare gli elenchi di bordi aperti che devono essere collegati, cioè le linee rosse, verdi, blu e viola. Trova un modo per accoppiarli tra loro, ad esempio reg-green e blue-purple. Nell'esempio dovrebbe essere sufficiente usare solo la media dei bordi per l'accoppiamento.

Quindi avresti bisogno di un metodo per triangolare lo spazio tra i bordi. Come accennato, dovrebbe essere sufficiente creare un triangolo (o due) per collegare le parti e utilizzare qualcosa come CGAL :: Polygon_mesh_processing :: triangulate_refine_and_fair_hole per riempire il resto.

Per fare ciò, puoi provare a trovare i due bordi di ciascun elenco vicini l'uno all'altro. Cioè la somma delle distanze dei punti è il più piccola possibile. Quindi scegli un bordo da un elenco e trova il bordo più vicino nell'altro. Quando hai due bordi, aggiungi una coppia di triangoli e usa CGAL per riempire il resto. Le diverse parti dovrebbero avere lo stesso orientamento della superficie affinché funzioni, ma probabilmente è così.

Un altro approccio sarebbe quello di usare solo i vertici per creare una mesh da una nuvola di punti , ma questo non è garantito per adattarsi alla mesh corrente. La soluzione più semplice è probabilmente quella di cercare di evitare del tutto il problema, ovvero assicurare che l'origine delle mesh produca mesh ben definite.

esempio di bordi da connettere


Grazie per la tua risposta, questo è davvero l'approccio su cui ho lavorato per un po ', ho quasi finito di programmare, attualmente ho problemi con le facce nella direzione sbagliata, quindi i fori di riempimento falliscono.
Niels,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.