Sunday, May 27, 2012

Example code for building CGAL::Polyhedron_3

I've found myself redoing this code relatively frequently, so I thought I would post it.  Nothing special, just a snippet that loads the file input.obj, builds a CGAL::Polyhedron_3 from it, and writes it out as The code also includes a rudimentary Wavefront OBJ loader.



typedef CGAL::Simple_cartesian<double>     Kernel;
typedef CGAL::Polyhedron_3<Kernel>         Polyhedron;
typedef Polyhedron::HalfedgeDS             HalfedgeDS;

// A modifier creating a triangle with the incremental builder.
template<class HDS>
class polyhedron_builder : public CGAL::Modifier_base<HDS> {
 std::vector<double> &coords;
 std::vector<int>    &tris;
    polyhedron_builder( std::vector<double> &_coords, std::vector<int> &_tris ) : coords(_coords), tris(_tris) {}
    void operator()( HDS& hds) {
  typedef typename HDS::Vertex   Vertex;
        typedef typename Vertex::Point Point;

  // create a cgal incremental builder
        CGAL::Polyhedron_incremental_builder_3<HDS> B( hds, true);
        B.begin_surface( coords.size()/3, tris.size()/3 );
  // add the polyhedron vertices
  for( int i=0; i<(int)coords.size(); i+=3 ){
   B.add_vertex( Point( coords[i+0], coords[i+1], coords[i+2] ) );
  // add the polyhedron triangles
  for( int i=0; i<(int)tris.size(); i+=3 ){
   B.add_vertex_to_facet( tris[i+0] );
   B.add_vertex_to_facet( tris[i+1] );
   B.add_vertex_to_facet( tris[i+2] );
  // finish up the surface

// reads the first integer from a string in the form
// "334/455/234" by stripping forward slashes and
// scanning the result
int get_first_integer( const char *v ){
 int ival;
 std::string s( v );
 std::replace( s.begin(), s.end(), '/', ' ' );
 sscanf( s.c_str(), "%d", &ival );
 return ival;

// barebones .OFF file reader, throws away texture coordinates, normals, etc.
// stores results in input coords array, packed [x0,y0,z0,x1,y1,z1,...] and
// tris array packed [T0a,T0b,T0c,T1a,T1b,T1c,...]
void load_obj( const char *filename, std::vector<double> &coords, std::vector<int> &tris ){
 double x, y, z;
 char line[1024], v0[1024], v1[1024], v2[1024];
 // open the file, return if open fails
 FILE *fp = fopen(filename, "r" );
 if( !fp ) return;
 // read lines from the file, if the first character of the
 // line is 'v', we are reading a vertex, otherwise, if the
 // first character is a 'f' we are reading a facet
 while( fgets( line, 1024, fp ) ){
  if( line[0] == 'v' ){
   sscanf( line, "%*s%lf%lf%lf", &x, &y, &z );
   coords.push_back( x );
   coords.push_back( y );
   coords.push_back( z );
  } else if( line[0] == 'f' ){
   sscanf( line, "%*s%s%s%s", v0, v1, v2 );
   tris.push_back( get_first_integer( v0 )-1 );
   tris.push_back( get_first_integer( v1 )-1 );
   tris.push_back( get_first_integer( v2 )-1 );

int main() {
 // two vectors to hold point coordinates and
 // triangle vertex indices
 std::vector<double> coords;
 std::vector<int>    tris;
 // load the input file
 load_obj( "input.obj", coords, tris );
 if( coords.size() == 0 )
  return 1;
 // build a polyhedron from the loaded arrays
 Polyhedron P;
 polyhedron_builder<HalfedgeDS> builder( coords, tris );
 P.delegate( builder );
 // write the polyhedron out as a .OFF file
 std::ofstream os("");
 os << P;
    return 0;


Daiki Yamanaka said...

good example code

okju ki said...

I got a assertion error on

CGAL_assertion( check_protocoll == 0);

on Polyhedron_incremental_builder_3.h

Did you know why this error occur??

* I made a code like yours.

James Gregson said...

I'm not sure, the code above compiled and ran fine for me.

Perhaps your polyhedron is not manifold (two triangles adjacent to each mesh edge)?

Unknown said...

Typo: barebones .OFF file reader should be barebones .OBJ file reader

dim said...

Nice source code!
It is so much more helpful for real life scenarios than CGAL's own samples.
Thanks for taking the time to share your code snippets!

Frogee said...

Thank you for posting this; it was very helpful.

Hernan Villanueva said...

Do the coordinates and triangles need to represent a closed surface?