Subject: CGAL users discussion list
List archive
[cgal-discuss] Assertion failure doing collect_garbage() after removing isolated vertices from a surface mesh
Chronological Thread
- From: Yaoyu Hu <>
- To:
- Subject: [cgal-discuss] Assertion failure doing collect_garbage() after removing isolated vertices from a surface mesh
- Date: Thu, 2 Dec 2021 00:07:17 -0500
- Authentication-results: mail2-smtp-roc.national.inria.fr; spf=None ; spf=Pass ; spf=None
- Ironport-data: A9a23:8ZAMQahOrXtf0uWNZfmhCDoNX161CBEKZh0ujC45NGQNrF6WrkVWyGsbUW/XOvneNmf3eo0nbY/k9RgP7JODnYVkTVBo/lhgHilAwSbnLYTAfx2oZ0t+DeWaERk5t51GAjX4wXFdokb0/n9BCZC86ykjvU20buCkUredYHgrHVYMpBoJ0HqPpcZp2uaEvvDiW2thifuqyyHuEAfNNwxcagr42IrfwP9bh8kejRtD1rAIiV+ni3eF/5UdJMp3yahctBIUSKEMdgKxb76rIL1UYgrkExkR5tONyt4Xc2UPS7/WeBCB0z9YAvf/xBdFoSM23+AwM/90hUV/0W3Y2YAsjo8U6NrpFlpB0q7kwIzxVzFYDjB3Orxboe6Xf1CwtMWSywvNdH6EL/BGUx5tZ9RBoI6bBkkXraBCQNwXVTiIiOuyhb66UeJxnd8LN9juJIpZu3d6zDifA+xOfHxpa7GSsIUegyNp05gIReKEMpJfM2s+NQCbNkUJZ0NIXbsguMytolX/VxxRjm6PgZQ2xnyKlFkvlOf5WDbOUtmDRMEQhknB42yfoDm/DRYdO9iSjzGC9xqRaib0tXuTcOov+HeQr5aGQWF/x1D/zDUTXFq/5OG20wuwAo0CbUMT/SUqoO4580nDohzVN/GniCbsg/Lec4M4/y4GBMWlxa/d4gLfDW8BJtKEQMJzr9c4HFTGyXfQ9+4ExlVTXHm9RneU97PSpjS3UcTQBQfuegdcJTY4DxLfTE3fQ/4BohuP0EJ4szEtJQzN/g==
- Ironport-hdrordr: A9a23:zXd3Iq7cgH3wVv25RAPXwMXXdLJyesId70hD6qkRc20zTiX8raqTdZsgpHzJYVoqOE3I+urgBEDjewK/yXcd2+B4VotKNzOW3VdAQrsSibcKAAeNJ8Q9zINgPGtbHJSWweefMWRH
- Ironport-phdr: A9a23:G6ulDhI8aN8hVnhLvNmcuAJhWUAX0o4c3iYr45Yqw4hDbr6kt8y7ehCFvLMz0BSWDM3y0LFts6LuqafuWGgNs96qkUspV9hybSIDktgchAc6AcSIWgXRJf/uaDEmTowZDAc2t360PlJIF8ngelbcvmO97SIIGhX4KAF5Ovn5FpTdgsipyuy+4ZzebgpHiDe/Zb55MQm7oxjWusQKm4VpN7w/ygHOontGeuRWwX1nKFeOlBvi5cm+4YBu/T1It/0u68BPX6P6f78lTbNDFzQpL3o15MzwuhbdSwaE+2YRXX8XkhpMBAjF8Q36U5LsuSb0quZxxC+XNtDxQr4pRDSi9L9rRwH0hycbOTA592TXhdZxjKJdvRmtoxNyzorRbIyTM/Vwf6bdcskbRWpFR8pdTjZPAoO9b4sUD+oBPOBYr4bkq1UQohayGAmhCPryxjJJm3T62aM33/g9HQ3D2gErAtAAv2nOrNjtO6gcUe67wqrVwzvdc/xbwi3y5JTSfx07vf2AQbB9fMzMwkcvDQPFiVCQpJTnMDyP0eQMs3Wb5PdiW+KylmUqrAFxoiWvx8g2jYnIhp8Vxk3A+Ch6wYs4PtK4SEthbt6lFJtcrT2VN4xzQs47RWxjpSk1xKEct5GhYCgK1IooxwTZa/GfcIWE/xztWeSRLDp2mH9oZrOyiwiy/EW91+HxSse63VRFoydEj9TCuG0A2wDX58WGSvVz8Umv1DSO2g3O9+xJJUY5nrfVJZ4mx74/jJsTsULbEy/5mUX2kK+Wdlg/9eSy9+vnZbDmqoeTN49zjQH+PaAuldKlDeskNQgOWm6W8vm/2r375UD1XqlGg/ksnqTasJ3WP9oXqrO5DgNPz4ou6RayAjG729oCh3YHNkhKeBefgojpJV7OJPf4AO+6g1u2kTdrw+nKPqXuApnQN3TDnqrtcLR95kJGxwozytdf551QCr4fOv78RkjxtNnAAh84NQy73frnBc1j2o8CXW+DGKyUPaPIvVOW++4iI/OAaJIXtTv9M/Ql4uThjX49mV8TZ6mp2p4XZWi4HvR7I0SWe33sg9ccEWsXugczT+3nhUaNUT5WfXmyXqY86isnB4KhCIfPXpqtj6CZ3CenAp1WYXhLBUyDEXjyc4WIQuoDaCOJIsB9jzwETqOhRpQ61RCusQ/606BoIvDV+i0er5Lj1cJ66/fdlREopnRICJGW3GiJCm11hWgVXCQe3aZloEU7xE3Q/7J/hqlpHNtC+rtpT09uNYPNxutrFomjClzpcdKASVLgSdKjV2JiBuktysMDNh8uU+6piQrOinH2Utf9dpSODZ0wt7rThj3/fpkgjXnB06Ylgh8tRc4dbQVOaYZw8gHSA8jClEDLzs5CkIwT2SfM8CGIym/c5Cll
Hi,
I am trying to fix and clear some issues from a surface mesh. I do the following three steps in sequence:
(1) Duplicate non-manifold vertices.
(2) Remove self-intersections. And,
(3) Remove isolated vertices.
(4) Remove small connected components.
I always get an assertion error in (4). In my code, (1), (3), and (4) are directly calling CGAL functions to do the job. For (2) I have a simple procedure where I first identify all the self-intersection pairs and then remove all the faces that have self-intersection. I have set up a sample code and a sample mesh. The code is also available as a GitHub Gist
The sample mesh is saved in my personal Google Drive.
I am using CGAL 5.3 on Ubuntu 20.04.
=== Code begins. ===
#include <fstream>
#include <iostream>
#include <sstream>
#include <vector>
#include <CGAL/Simple_cartesian.h>
#include <CGAL/Surface_mesh.h>
#include <CGAL/Surface_mesh/IO/PLY.h>
#include <CGAL/Polygon_mesh_processing/connected_components.h>
#include <CGAL/Polygon_mesh_processing/repair.h>
#include <CGAL/Polygon_mesh_processing/self_intersections.h>
namespace PMP = CGAL::Polygon_mesh_processing;
typedef CGAL::Simple_cartesian<float> Kernel_t;
typedef Kernel_t::Point_3 Point_t;
typedef CGAL::Surface_mesh<Point_t> Mesh_t;
typedef Kernel_t::Compare_dihedral_angle_3 Compare_dihedral_angle_3;
template < typename MeshT >
void read_mesh(const std::string& fn, MeshT& mesh) {
std::ifstream ifs(fn, std::ios::binary);
if ( !ifs ) {
std::stringstream ss;
ss << "Cannot open " << fn;
throw std::runtime_error(ss.str());
}
std::string comments;
CGAL::IO::read_PLY(ifs, mesh, comments);
}
template < typename MeshT >
void duplicate_non_manifold_vertices(MeshT& mesh) {
PMP::duplicate_non_manifold_vertices(mesh);
}
template < typename MeshT >
int remove_self_intersections( MeshT& mesh ) {
typedef typename boost::graph_traits<MeshT>::face_descriptor Face_t;
std::vector< std::pair< Face_t, Face_t > > intersections;
PMP::self_intersections<CGAL::Parallel_if_available_tag>(
faces(mesh),
mesh,
std::back_inserter(intersections)
);
const int n_intersections = intersections.size();
if ( n_intersections > 0 ) {
for ( const auto& inter_pair : intersections ) {
mesh.remove_face( inter_pair.first );
mesh.remove_face( inter_pair.second );
}
mesh.collect_garbage();
}
return n_intersections;
}
template < typename MeshT >
int remove_isolated_vertices( MeshT& mesh ) {
const int N = PMP::remove_isolated_vertices(mesh);
return N;
}
// For computing the connected components.
template < typename MeshT >
struct ConnectionConstraint : public boost::put_get_helper< bool, ConnectionConstraint<MeshT> > {
typedef typename boost::graph_traits<MeshT>::edge_descriptor EdgeT;
typedef boost::readable_property_map_tag category;
typedef bool value_type;
typedef bool reference;
typedef EdgeT key_type;
ConnectionConstraint()
: m_mesh(nullptr) {}
ConnectionConstraint( MeshT& mesh, double bound )
: m_mesh(&mesh), m_bound(bound) {}
bool operator[] ( EdgeT edge ) const {
const MeshT& mesh = *m_mesh;
return m_compare(
mesh.point( source( edge, mesh ) ),
mesh.point( target( edge, mesh ) ),
mesh.point( target( next( halfedge( edge, mesh ), mesh ), mesh ) ),
mesh.point( target( next( opposite( halfedge( edge, mesh ), mesh), mesh ) ,mesh ) ),
m_bound ) == CGAL::SMALLER;
}
const MeshT* m_mesh;
Compare_dihedral_angle_3 m_compare;
double m_bound;
};
template < typename MeshT >
void remove_small_connected_components(
MeshT& mesh,
int limit_num=10,
double limit_di_angle_rad=2.36 /* 3/4 pi */ ) {
const double bound = std::cos( limit_di_angle_rad );
PMP::keep_large_connected_components(
mesh,
limit_num,
PMP::parameters::edge_is_constrained_map(
ConnectionConstraint<MeshT>(mesh, bound) )
);
}
int main(int argc, char** argv) {
const std::string in_mesh_fn =
"please download from https://drive.google.com/drive/folders/1AmQONiss-q26cgs4wNBp3fMSlVmo09Ej?usp=sharing";
// Read the mesh.
Mesh_t mesh;
read_mesh( in_mesh_fn, mesh );
// Duplicate non-manifold_vertices.
duplicate_non_manifold_vertices(mesh);
// Remove self-intersection faces.
remove_self_intersections(mesh);
// Remove isolated vertices.
remove_isolated_vertices(mesh);
// Remove small connected components.
remove_small_connected_components(mesh);
return 0;
}
#include <iostream>
#include <sstream>
#include <vector>
#include <CGAL/Simple_cartesian.h>
#include <CGAL/Surface_mesh.h>
#include <CGAL/Surface_mesh/IO/PLY.h>
#include <CGAL/Polygon_mesh_processing/connected_components.h>
#include <CGAL/Polygon_mesh_processing/repair.h>
#include <CGAL/Polygon_mesh_processing/self_intersections.h>
namespace PMP = CGAL::Polygon_mesh_processing;
typedef CGAL::Simple_cartesian<float> Kernel_t;
typedef Kernel_t::Point_3 Point_t;
typedef CGAL::Surface_mesh<Point_t> Mesh_t;
typedef Kernel_t::Compare_dihedral_angle_3 Compare_dihedral_angle_3;
template < typename MeshT >
void read_mesh(const std::string& fn, MeshT& mesh) {
std::ifstream ifs(fn, std::ios::binary);
if ( !ifs ) {
std::stringstream ss;
ss << "Cannot open " << fn;
throw std::runtime_error(ss.str());
}
std::string comments;
CGAL::IO::read_PLY(ifs, mesh, comments);
}
template < typename MeshT >
void duplicate_non_manifold_vertices(MeshT& mesh) {
PMP::duplicate_non_manifold_vertices(mesh);
}
template < typename MeshT >
int remove_self_intersections( MeshT& mesh ) {
typedef typename boost::graph_traits<MeshT>::face_descriptor Face_t;
std::vector< std::pair< Face_t, Face_t > > intersections;
PMP::self_intersections<CGAL::Parallel_if_available_tag>(
faces(mesh),
mesh,
std::back_inserter(intersections)
);
const int n_intersections = intersections.size();
if ( n_intersections > 0 ) {
for ( const auto& inter_pair : intersections ) {
mesh.remove_face( inter_pair.first );
mesh.remove_face( inter_pair.second );
}
mesh.collect_garbage();
}
return n_intersections;
}
template < typename MeshT >
int remove_isolated_vertices( MeshT& mesh ) {
const int N = PMP::remove_isolated_vertices(mesh);
return N;
}
// For computing the connected components.
template < typename MeshT >
struct ConnectionConstraint : public boost::put_get_helper< bool, ConnectionConstraint<MeshT> > {
typedef typename boost::graph_traits<MeshT>::edge_descriptor EdgeT;
typedef boost::readable_property_map_tag category;
typedef bool value_type;
typedef bool reference;
typedef EdgeT key_type;
ConnectionConstraint()
: m_mesh(nullptr) {}
ConnectionConstraint( MeshT& mesh, double bound )
: m_mesh(&mesh), m_bound(bound) {}
bool operator[] ( EdgeT edge ) const {
const MeshT& mesh = *m_mesh;
return m_compare(
mesh.point( source( edge, mesh ) ),
mesh.point( target( edge, mesh ) ),
mesh.point( target( next( halfedge( edge, mesh ), mesh ), mesh ) ),
mesh.point( target( next( opposite( halfedge( edge, mesh ), mesh), mesh ) ,mesh ) ),
m_bound ) == CGAL::SMALLER;
}
const MeshT* m_mesh;
Compare_dihedral_angle_3 m_compare;
double m_bound;
};
template < typename MeshT >
void remove_small_connected_components(
MeshT& mesh,
int limit_num=10,
double limit_di_angle_rad=2.36 /* 3/4 pi */ ) {
const double bound = std::cos( limit_di_angle_rad );
PMP::keep_large_connected_components(
mesh,
limit_num,
PMP::parameters::edge_is_constrained_map(
ConnectionConstraint<MeshT>(mesh, bound) )
);
}
int main(int argc, char** argv) {
const std::string in_mesh_fn =
"please download from https://drive.google.com/drive/folders/1AmQONiss-q26cgs4wNBp3fMSlVmo09Ej?usp=sharing";
// Read the mesh.
Mesh_t mesh;
read_mesh( in_mesh_fn, mesh );
// Duplicate non-manifold_vertices.
duplicate_non_manifold_vertices(mesh);
// Remove self-intersection faces.
remove_self_intersections(mesh);
// Remove isolated vertices.
remove_isolated_vertices(mesh);
// Remove small connected components.
remove_small_connected_components(mesh);
return 0;
}
=== Code ends. ===
Step (2) is the remove_self_intersections() function. The assertion error shows in my terminal is
=== Terminal output begins. ===
terminate called after throwing an instance of 'CGAL::Assertion_exception'
what(): CGAL ERROR: assertion violation!
Expr: _idx < data_.size()
File: /usr/local/include/CGAL/Surface_mesh/Properties.h
Line: 193
what(): CGAL ERROR: assertion violation!
Expr: _idx < data_.size()
File: /usr/local/include/CGAL/Surface_mesh/Properties.h
Line: 193
=== Terminal output ends. ===
I have also saved the backtrace from GDB in the Google Drive folder (a txt and a screenshot). please download from https://drive.google.com/drive/folders/1AmQONiss-q26cgs4wNBp3fMSlVmo09Ej?usp=sharing
From the backtrace, it looks like when iterating through the faces of the mesh for computing the connected components, a face descriptor is out of the valid range.
Another thing that I found during the debugging is that, if you check the output of mesh.has_garbage() after calling PMP::remove_isolated_vertices() in my remove_isolated_vertices() function, mesh.has_garbage() is true. I suppose PMP::remove_isolated_vertices() should not leave the mesh in a state where it has uncollected garbage.
Any help is appreciated!
Thank you!
Yaoyu
- [cgal-discuss] Assertion failure doing collect_garbage() after removing isolated vertices from a surface mesh, Yaoyu Hu, 12/02/2021
Archive powered by MHonArc 2.6.19+.