Skip to Content.
Sympa Menu

cgal-discuss - Re: [cgal-discuss] my experience with CGAL

Subject: CGAL users discussion list

List archive

Re: [cgal-discuss] my experience with CGAL


Chronological Thread 
  • From: Joshua A Levine <>
  • To:
  • Subject: Re: [cgal-discuss] my experience with CGAL
  • Date: Tue, 02 Sep 2008 17:58:39 -0400

Jernej,

I may have solved your first problem a while back. I wanted to output the mesh into a Geomview OFF format and wrote a quick block of code to do this which I added at the end of the mesh_a_3d_gray_image.cpp file. My guess is you're trying to get an OBJ format? If so, they are very similar and you should be able to modify the last part of my code to get it in the format you would like. Keep in mind OFF indices start counting with 0, not 1.


To answer a couple of your questions:

--Accessing CGAL's internal index for each vertex can be tricky. It can be a little less hassle to just create your own (either attached to a vertex class, or as I've done below use an external structure for it). There are definitely more elegant ways to do this than the n^2-time search I used below.

--To access the (x,y,z) coordinates for a Point_3 object, you simply call .x(), .y(), and .z(). So from a vertex, you first get the Point_3 (i.e. v->point()) and then call these member functions.

--As far as I know, c2t3.facets_begin() gives you an iterator to the surface triangles only, not the entire set of facets in the tetrahedralization.

--A "facet" in cgal is really a pair of Cell_handle/index to one of the cells containing the facet. f->second gives you an integer between 0-3 which indexes into the cell (it refers to the unique vertex opposite the facet). Thus (f->second)+1, +2, & +3 (modulo 4) are the actual vertices of the facet.

So f->second is NOT the dimensionality of the facet as you were guessing in your code. FYI: the CGAL documentation states this convention in a number of places.


As for your second problem, I think one of the CGAL folks can better answer your questions about proper usage of the mesher.

Hope this helps,
Josh




Here's the code snippet I used:

C2t3::Facet_iterator iter = c2t3.facets_begin();

std::vector<GT::Point_3> pts_vec;
std::vector<int> facets;
unsigned int i,j;

while (iter != c2t3.facets_end()) {
C2t3::Facet f = *iter;
C2t3::Cell_handle cell = f.first;
int index = f.second;


for(i=1; i<=3; i++) {
GT::Point_3 p = cell->vertex((index+i)%4)->point();

int index = -1;
for(j=0; j<pts_vec.size(); j++) {
if (p == pts_vec[j]) {
index = j;
}
}

if (index == -1) {
index = pts_vec.size();
pts_vec.push_back(p);
}

facets.push_back(index);
}

iter++;
}



std::ofstream fout("output.off");

fout << "OFF" << std::endl;
fout << pts_vec.size() << " " << facets.size()/3 << " 0 " << std::endl;

//a list of x y z for each vertex
for(i=0; i<pts_vec.size(); i++) {
fout << pts_vec[i] << std::endl;
}

//a triangle (3) followed by three indices to the verts in the tri
for(i=0; i<facets.size(); i+=3) {
fout << "3 ";
fout << facets[i] << " ";
fout << facets[i+1] << " ";
fout << facets[i+2] << std::endl;
}






Jernej Barbic wrote:
Dear CGAL,

I am posting these two message by invitation of Dr. Pierre Alliez. I
attended the CGAL course at SIGGRAPH in LA, and then tried using CGAL
to do surface mesh generation. I then had an email discussion with
Pierre, relating my experience with CGAL. Also, please note that (due
to other work) it might be difficult for me to keep up with the
follow-ups; however, I wanted to share my experience, so I wrote the
emails below. Best of luck to CGAL!

Regards,
Jernej Barbic
Post-doc associate, Computer Science and Artificial Intelligence Lab,
Massachusetts Institute of Technology
http://people.csail.mit.edu/barbic/

The first email message:
===================

Dear Pierre,

I am a computer graphics post-doc at MIT, and I saw your presentation
in this year's SIGGRAPH class on CGAL in Los Angeles.

I was impressed with the presentation and the capabilities of CGAL, so
I tried using it as a tool in my project. Specifically, I wanted to
use it to generate good quality triangulations of isosurfaces, as in
the "skull" example:
http://www.cgal.org/Manual/3.3/doc_html/cgal_manual/Surface_mesher/Chapter_main.html

I managed to compile and run the "skull" example (under Mac OS X).
However, I then ran into a problem which will most likely seem quite
trivial to you: I was unable to adapt the example so that I could
actually capture the output. That is, CGAL will generate an output
mesh; I then wanted to convert this mesh to my own in-memory
representation. This representation would be very simple: a list of
vertices, each given as three double precision values, followed by a
list of faces (triangles), each a set of three integer indices into
the preceding table of vertices. I was ultimately unable to figure out
how to do this.

I listened to your presentation at SIGGRAPH, and then read the CGAL
manual several times. I spent two days looking through many CGAL
header files (about 8-10 hours of work total), following seemingly
endless templated (and cryptic at times) arguments, in an attempt to
find clues as per how to access vertices of triangulations, and how to
obtain the integer indices of the vertices of every face. For example,
I "chased" the definition of "Vertex", over many header files,
following (many) typedefs and templates, and did not succeed in
finding a final answer.

I program in C++ all the time, and am quite proficient with templates
and STL. I could not find a final answer - and got a bit frustrated
given how simple and trivial the task. If I was on the CGAL team, I am
pretty sure I could just ask somebody and get the answer very quickly,
but with the information available to me, things were difficult.

Here is what I did figure out. One can print out the vertices like this:

for ( C2t3::Vertex_iterator v = c2t3.vertices_begin(); v !=
c2t3.vertices_end(); ++v)
{
std::cout << "v " << v->point() << std::endl;
}

(but printing is not what I really wanted; it would be better if I
could store v->point() into a C array such as "double [3]")

And one can traverse the faces (but unsure if these are tet mesh
cells, or surface mesh triangles, or surface mesh
triangles+edges+vertices) like this:

int count = 0;
for(C2t3::Facet_iterator f = c2t3.facets_begin(); f != c2t3.facets_end(); f++)
{
//printf("%d\n", f->second); // this I am guessing is the
dimensionality of the facet
if (f->second == 3)
{
std::cout << f->first->vertex(0)->point() << " ";
std::cout << f->first->vertex(1)->point() << " ";
std::cout << f->first->vertex(2)->point();
std::cout << std::endl;
count++;
}
}

However, here I don't know what to do with f->first->vertex to pull
out the global integer index of that vertex. As you can see, I figured
out how to convert the vertex to its 3D location (3 coordinates); but
getting the global integer index would be much better. Also, I am not
sure if this method will give me the triangle faces of the surface
mesh, or will it give me the entire tet mesh. And if I run it on the
(unmodified, as shipped with CGAL) skull example, I get many 4-tuples
(I assume tets from the output tetrahedralization) that look ok, but
at the end there are several that have three zero entries and one
entry equalling 1. So if those are tets, unsure what they mean.

I think CGAL is great: it really implements many useful algorithms and
the ability to have exact arithmetic is very good. Based on my
experience, may I add a suggestion: right now, the manual talks a lot
about templates and about computational geometry algorithms, which is
all good. Templates certainly make CGAL more powerful. However, at
times the manual reads like the art of templatization was the main
point of CGAL; there is a lot of template lingo. This will be good for
somebody who is much into templates, but might be difficult to read
for other people. I would add even more concrete examples: whenever
you present some generic datastructure or algorithm (such as the
kernel, for example), consider giving concrete examples of templated
arguments that one can pass to those datastructures or algorithms. And
as per triangulations, it would be good to have a manual page listing
the methods available to vertex iterators, face iterators, cell
iterators; the difference between face, facet, cell; and more
documentation on input and output.

Thank you for creating CGAL, and for your help,
Jernej Barbic

The second email message:
======================

dear Jernej,

thanks for your positive feedback, that's very useful and encouraging.

as I am still on holidays, the short answer can be found in file
Complex_2_in_triangulation_3_file_writer.h

I invite you to post your detailed email to the CGAL discuss list, so that
all developers see the trend (more and more people start using that surface
mesh generator, that's good to know).

thanks again for your time,

Pierre

Hi Pierre,

Thank you very much for the pointer to
Complex_2_in_triangulation_3_file_writer.h. I was able to
"reverse-engineer" that file and now the mesher works fine for me. I
already meshed several isosurfaces. The mesher is very good. I am not
aware of any other mesher that can achieve similar results.

One minor issue that I noticed is that there is sometimes a spot on
the output mesh where for some reason the vertex density is
unnecessarily high. If there is such a spot, there is always exactly
one. It's not a big deal, but it does require either removing it
manually, or running several runs, guessing parameters until it
disappears. The location of this spot might be related to the location
of the center of the bounding sphere (user-supplied parameter), and to
how deep that center is inside the volume enclosed by the isosurface.
But not 100% sure.

Also, documentation says that the sphere center must be inside the
volume enclosed by the isosurface - but I noticed that the mesher
produces a plausible result even if it is not. And, I am not
completely sure if the bounding sphere has to cover the entire volume
where the grayscale image is defined, or only the output isosurface.
Also, I don't exactly understand the difference between the "distance
bound" and "radius bound" (inputs to the mesher); I read it several
times in the manual and from that text I don't see the difference (and
I know they must be different, or else you would not have two separate
parameters).

FYI: I am combining your surface mesher with "tetgen" to generate
volumetric tet meshes (I do so since I am assuming that your mesher
doesn't generate a (quality) tet mesh, only a quality surface mesh). I
am getting very good quality meshes using this process.

Again, my suggestion to CGAL would be to boost the documentation. Much
of the documentation talks about "concepts" and how these concepts are
implemented in "models". This is interesting on its own, however, it
might be hard for a CGAL novice to parse this. For example, I'd try to
lookup "Vertex", expecting to see a concrete class, and a list of
methods that can be used with this class. Instead, there would be lots
of typedefs and talk about how this is a model of some concept and how
it has to implement certain things. And then I'd wonder why those
typedefs are the way they are, and what alternative choices would be
and where I would look up those. And whether the class that I am
looking at (Vertex) is an actual class that I can use, or is it just
an abstract concept for me to implement (or partially implement), etc.
All this is just my 5 cents of course, take my criticism lightly. I
realize templatization has big benefits.

As per posting to the CGAL discussion list, please go ahead and post
my previous email, in my name (it is easier for me if you post it,
than if I post it). You can also post this email if you wish.

Thank you for your help.
Jernej Barbic



Archive powered by MHonArc 2.6.16.

Top of Page