Line 10... |
Line 10... |
10 |
\usepackage[pdftex,
|
10 |
\usepackage[pdftex,
|
11 |
pagebackref=true,
|
11 |
pagebackref=true,
|
12 |
colorlinks=true,
|
12 |
colorlinks=true,
|
13 |
linkcolor=blue
|
13 |
linkcolor=blue
|
14 |
]{hyperref}
|
14 |
]{hyperref}
|
- |
|
15 |
|
15 |
\makeindex
|
16 |
\makeindex
|
16 |
\lstset{tabsize=1,language=C++,basicstyle=\small}
|
17 |
\lstset{tabsize=1,language=C++,basicstyle=\small}
|
17 |
\author{J. Andreas B{\ae}rentzen}
|
18 |
\author{J. Andreas B{\ae}rentzen}
|
18 |
\title{Introduction to GEL\\\vspace{0.25cm} \normalsize
|
19 |
\title{Introduction to GEL\\\vspace{0.25cm} \normalsize
|
19 |
\textit{An informal introduction to the GEL library with many examples of usage}.}
|
20 |
\textit{An informal introduction to the GEL library with many examples of usage}.}
|
20 |
\setcounter{tocdepth}{2}
|
21 |
\setcounter{tocdepth}{2}
|
21 |
\begin{document}
|
22 |
\begin{document}
|
22 |
\maketitle
|
23 |
\maketitle
|
23 |
\tableofcontents
|
24 |
\tableofcontents
|
24 |
\newpage\section{Introduction}
|
25 |
\newpage\section{Introduction}
|
- |
|
26 |
\sloppy
|
25 |
|
27 |
|
26 |
GEL is an abbreviation of GEometry and Linear algebra. GEL is a C++ library with tools for manipulating digital representations of geometry such as polygonal meshes, triangle meshes, point clouds, and voxel grids. Since linear algebra tools are invariably needed for this, GEL also contains tools for linear algebra. Finally, GEL contains tools for drawing geometry using OpenGL and various utilities.
|
28 |
GEL is an abbreviation of GEometry and Linear algebra. GEL is a C++ library with tools for manipulating digital representations of geometry such as polygonal meshes, triangle meshes, point clouds, and voxel grids. Since linear algebra tools are invariably needed for this, GEL also contains tools for linear algebra. Finally, GEL contains tools for drawing geometry using OpenGL and various utilities.
|
27 |
|
29 |
|
28 |
\subsection{GEL Homepage}
|
- |
|
29 |
The online home of GEL is here:
|
- |
|
30 |
\href{http://www.imm.dtu.dk/GEL/}{http://www.imm.dtu.dk/GEL/}
|
30 |
This document pertains to the version of GEL which is distributed on CampusNet for 02585. This version of GEL comes with project files for Visual Studio 9 and XCode and examples relevant for the course are included in the distribution.
|
31 |
|
31 |
|
32 |
\subsection{Purpose of this document}
|
- |
|
33 |
GEL is not sufficiently documented, but a fair amount of Doxygen documentation is provided for those parts of GEL which are used a lot. The goal of this document is to provide more detail and to help people getting started. In particular, this document focuses on functionality in the CGLA and HMesh namespaces, but we shall also take a look at some other parts of GEL. Unfortunately, it is rather difficult to be complete: There is functionality in GEL not covered here. Consequently, if you are looking for something particular, we \textbf{entreat }you to look at the Doxygen web (start at the GEL homepage). Most functions and classes are in fact described in the auto-generated documentation.
|
32 |
GEL is not documented as well as we would like, but a fair amount of Doxygen documentation is provided for those parts of GEL which are used a lot. You will find the reference manual at \href{http://www2.imm.dtu.dk/courses/02585/GELref/index.html}{http://www2.imm.dtu.dk/courses/02585/GELref/index.html}
|
34 |
|
33 |
|
35 |
\subsection{Overview of GEL}
|
- |
|
36 |
|
- |
|
37 |
GEL contains many tools for geometry processing and a number of data structures. Perhaps the most important is the Manifold class which resides in the HMesh namespace. A Manifold is a halfedge based representation of a polygonal mesh. There is also a simpler triangle mesh data structure, TriMesh, based on an indexed face set. There are several voxel grid data structures, a fairly efficient k-D tree for storing points, bounding box hierarchies etc.
|
- |
|
38 |
|
- |
|
39 |
A number of algorithms exist for manipulating these representations of geometric data. For instance, Manifold has a function for mesh simplification, several functions for smoothing (including anisotropic), mesh optimization, and mesh clean up.
|
- |
|
40 |
Another strong point of GEL is the fact that it contains good support for converting between representations; especially between meshes and voxel grids. There are several tools for polygonizing isosurfaces and also converting meshes to distance fields. The tools pertaining to the Manifold data structure are in the HMesh namespace. The other geometry related tools are in the Geometry namespace.
|
34 |
Please use it. Autogenerated documentation is not eminently readable, but it is much better than no documentation and it should be relatively complete for the parts of GEL needed in the course.
|
41 |
|
- |
|
42 |
There are two packages for linear algebra: CGLA is strictly for small vectors and matrices (dimensions 2,3, and 4). LinAlg is a Lapack wrapper for slightly larger problems. At this point, it is fairly simple but includes a number of functions for solving linear systems, factoring matrices and finding eigensolutions for symmetric matrices.
|
- |
|
43 |
|
- |
|
44 |
GLGraphics contains facilities for drawing entities from other parts of GEL via OpenGL. Especially TriMesh and Manifold have good support. For instance, there is a nice wireframe drawing class. There are also two virtual trackballs for interactive programs and some tools for viewing in interactive programs and SOIL a small open source library for image loading by Jonathan Dummer.
|
- |
|
45 |
|
- |
|
46 |
Finally there are some utilities in Util: Getting command line arguments, hash table classes, a 2D grid class, a resource manager, an XML parser by Jeppe Frisvad and other tools.
|
- |
|
47 |
|
35 |
|
48 |
Apart from the namespaces (sublibraries) we have a number of demo applications. Some of these might be useful in themselves. One example is a tool for converting a mesh to a signed distance field and an OBJ viewer which is also able to load X3D and PLY meshes. We are working on the MeshEdit application which is already a highly useful swiss knife for geometry processing.
|
36 |
The goal of \textit{this} document is to provide more detail and to help people getting started. In particular, this document focuses on functionality in the CGLA and HMesh namespaces, but we shall also take a look at some other parts of GEL. Unfortunately, it is rather difficult to be complete: There is functionality in GEL not covered here. Consequently, if you are looking for something particular, we \textbf{entreat } you to look at the reference linked to above
|
- |
|
37 |
\subsection{Overview of GEL}
|
49 |
|
38 |
|
50 |
\section{Compilation and Installation}
|
39 |
GEL contains many tools for geometry processing and a number of data structures. Perhaps the most important is the \texttt{Manifold} class which resides in the \texttt{HMesh} namespace. A \texttt{Manifold} is a halfedge based representation of a polygonal mesh. There is also a simpler triangle mesh data structure, \texttt{TriMesh}, based on an indexed face set. There are several voxel grid data structures, a fairly efficient k-D tree for storing points, bounding box hierarchies etc.
|
51 |
|
40 |
|
52 |
Life would be easier if one's library did not rely on dependencies. We try hard to have only a minimal set, but the following libraries \textit{are} required in order to build GEL.
|
41 |
A number of algorithms exist for manipulating these representations of geometric data. For instance, \texttt{Manifold} has a function for mesh simplification, several functions for smoothing (including anisotropic), mesh optimization, and mesh clean up.
|
53 |
\begin{itemize}
|
- |
|
54 |
\item OpenGL
|
- |
|
55 |
\item GLUT
|
- |
|
56 |
\item GLEW
|
- |
|
57 |
\item Lapack (and its depencies)
|
- |
|
58 |
\item GLConsole (only for MeshEdit).
|
- |
|
59 |
\end{itemize}
|
- |
|
60 |
OpenGL is typically installed on any platform. GLUT is typically available for any platform. A replacement such as FreeGLUT should be an option. Lapack is typically also available everywhere. The only problem is GLConsole. As of writing only MeshEdit depends on GLConsole which can be obtained from SourceForge:
|
42 |
Another strong point of GEL is the fact that it contains good support for converting between representations; especially between meshes and voxel grids. There are several tools for polygonizing isosurfaces and also converting meshes to distance fields. The tools pertaining to the Manifold data structure are in the \texttt{HMesh} namespace. The other geometry related tools are in the \texttt{Geometry} namespace.
|
61 |
|
43 |
|
62 |
\href{http://sourceforge.net/projects/glconsole/}{http://sourceforge.net/projects/glconsole/}
|
44 |
There are two packages for linear algebra: \texttt{CGLA} is strictly for small vectors and matrices (dimensions 2,3, and 4). \texttt{LinAlg} is a Lapack wrapper for slightly larger problems. At this point, it is fairly simple but includes a number of functions for solving linear systems, factoring matrices and finding eigensolutions for symmetric matrices.
|
63 |
|
45 |
|
64 |
GLConsole is extremely convenient but a well kept, little documented secret. Please do not try to install it unless you need MeshEdit. We will update this text if we either include it in GEL (assuming the authors allow it) or change to some other library.
|
46 |
\texttt{GLGraphics} contains facilities for drawing entities from other parts of GEL via OpenGL. Especially \texttt{TriMesh} and Manifold have good support. For instance, there is a nice wireframe drawing class. There are also two virtual trackballs for interactive programs and some tools for viewing in interactive programs and SOIL a small open source library for image loading by Jonathan Dummer.
|
65 |
|
47 |
|
66 |
GEL is compiled using CMake. Currently CMake is the official way of producing Visual Studio Solution files. A separate Mac OSX XCode project file is also maintained but may be removed if CMake makes it redundant. A set of Makefiles for various unices are also found in the package but no longer maintained.
|
48 |
Finally there are some utilities in \texttt{Util}: Getting command line arguments, hash table classes, a 2D grid class, a resource manager, an XML parser by Jeppe Frisvad and other tools.
|
67 |
|
- |
|
68 |
To install GEL, put the libraries and header files in the logical place. CMake should instruct your build environment on how to do this. Then you can use GEL simply by including the header files and linking against the GEL libraries. On windows using Visual Studio it is important that you define SECURE\_SCL to be 0. This is because Visual Studio is a bit pedantic about not allowing access to the raw memory of STL containers.
|
- |
|
69 |
|
49 |
|
70 |
\section{CGLA}
|
50 |
\section{CGLA}
|
71 |
|
51 |
|
72 |
CGLA is a set of numerical C++ vector and matrix classes and class
|
52 |
\texttt{CGLA} is a set of numerical C++ vector and matrix classes and class
|
73 |
templates designed with computer graphics in mind. CGLA stands for
|
53 |
templates designed with computer graphics in mind. \texttt{CGLA} stands for
|
74 |
``Computer Graphics Linear Algebra''. Let us get right down to the obvious question: Why create another
|
54 |
``Computer Graphics Linear Algebra''. Let us get right down to the obvious question: Why create another
|
75 |
linear algebra package?
|
55 |
linear algebra package?
|
76 |
Well, CGLA evolved from a few matrix and vector classes because I
|
56 |
Well, \texttt{CGLA} evolved from a few matrix and vector classes because I
|
77 |
didn't have anything better. Also, I created CGLA to experiment with
|
57 |
didn't have anything better. Also, I created \texttt{CGLA} to experiment with
|
78 |
some template programming techniques. This led to the most important
|
58 |
some template programming techniques. This led to the most important
|
79 |
feature of CGLA, namely the fact that all vector types are derived
|
59 |
feature of \texttt{CGLA}, namely the fact that all vector types are derived
|
80 |
from the same template.
|
60 |
from the same template.
|
81 |
|
61 |
|
82 |
This makes it easy to ensure identical semantics: Since all vectors
|
62 |
This makes it easy to ensure identical semantics: Since all vectors
|
83 |
have inherited, say, the * operator from a common ancestor, it works
|
63 |
have inherited, say, the * operator from a common ancestor, it works
|
84 |
the same for all of them.
|
64 |
the same for all of them.
|
85 |
|
65 |
|
86 |
It is important to note that CGLA was designed for Computer Graphics
|
66 |
It is important to note that \texttt{CGLA} was designed for Computer Graphics
|
87 |
(not numerical computations) and this had a number of
|
67 |
(not numerical computations) and this had a number of
|
88 |
implications. Since, in computer graphics we mainly need small vectors
|
68 |
implications. Since, in computer graphics we mainly need small vectors
|
89 |
of dimension 2,3, or 4 CGLA was designed for vectors of low
|
69 |
of dimension 2,3, or 4 \texttt{CGLA} was designed for vectors of low
|
90 |
dimensionality. Moreover, the amount of memory allocated for a vector
|
70 |
dimensionality. Moreover, the amount of memory allocated for a vector
|
91 |
is decided by its type at compile time. CGLA does not use dynamic
|
71 |
is decided by its type at compile time. \texttt{CGLA} does not use dynamic
|
92 |
memory. CGLA also does not use virtual functions, and most functions
|
72 |
memory. \texttt{CGLA} also does not use virtual functions, and most functions
|
93 |
are inline. These features all help making CGLA relatively fast.
|
73 |
are inline. These features all help making \texttt{CGLA} relatively fast.
|
94 |
|
74 |
|
95 |
Of course, other libraries of vector templates for computer graphics
|
75 |
Of course, other libraries of vector templates for computer graphics
|
96 |
exist, but to my knowledge none where the fundamental templates are
|
76 |
exist, but to my knowledge none where the fundamental templates are
|
97 |
parametrized w.r.t. dimension as well as type. In other words, we have
|
77 |
parametrized w.r.t. dimension as well as type. In other words, we have
|
98 |
a template (\texttt{ArithVec})that gets both type
|
78 |
a template (\texttt{ArithVec}) that gets both type
|
99 |
(e.g. \texttt{float}) and dimension
|
79 |
(e.g. \texttt{float}) and dimension
|
100 |
(e.g. 3) as arguments. the intended use of this template is as
|
80 |
(e.g. 3) as arguments. the intended use of this template is as
|
101 |
ancestor of concrete types such as \texttt{Vec3f} - a 3D floating
|
81 |
ancestor of concrete types such as \texttt{Vec3f} - a 3D floating
|
102 |
point type.
|
82 |
point type.
|
103 |
|
83 |
|
104 |
The use of just one template as basis is very important, I believe,
|
84 |
The use of just one template as basis is very important, I believe,
|
105 |
since it makes it extremely simple to add new types of
|
85 |
since it makes it extremely simple to add new types of
|
106 |
vectors. Another very generic template is \texttt{ArithMat} which is a
|
86 |
vectors. Another very generic template is \texttt{ArithMat} which is a
|
107 |
template for matrix classes. (and not necessarily NxN matrices).
|
87 |
template for matrix classes. (and not necessarily NxN matrices).
|
108 |
|
88 |
|
109 |
From a users perspective CGLA contains a number of vector and matrix
|
89 |
From a users perspective \texttt{CGLA} contains a number of vector and matrix
|
110 |
classes, a quaternion and some utility classes. In summary, the most
|
90 |
classes, a quaternion and some utility classes. In summary, the most
|
111 |
important features are
|
91 |
important features are
|
112 |
\begin{itemize}
|
92 |
\begin{itemize}
|
113 |
\item A number of 2, 3 and 4 d vector classes.
|
93 |
\item A number of 2, 3 and 4 d vector classes.
|
114 |
\item A number of Matrix classes.
|
94 |
\item A number of Matrix classes.
|
Line 118... |
Line 98... |
118 |
\end{itemize}
|
98 |
\end{itemize}
|
119 |
|
99 |
|
120 |
|
100 |
|
121 |
\subsection{Naming conventions}
|
101 |
\subsection{Naming conventions}
|
122 |
|
102 |
|
123 |
Vectors in CGLA are named \texttt{VecDT} where \texttt{D} stands for
|
103 |
Vectors in \texttt{CGLA} are named \texttt{VecDT} where \texttt{D} stands for
|
124 |
dimension at \texttt{T}
|
104 |
dimension at \texttt{T}
|
125 |
for type. For instance a 3D floating point vector is named
|
105 |
for type. For instance a 3D floating point vector is named
|
126 |
\texttt{Vec3f}. Other types are d (double), s (short), i (int), uc
|
106 |
\texttt{Vec3f}. Other types are d (double), s (short), i (int), uc
|
127 |
(unsigned char), and usi (unsigned shourt int).
|
107 |
(unsigned char), and usi (unsigned shourt int).
|
128 |
|
108 |
|
129 |
Matrices are similiarly named \texttt{MatDxDT}. For instance a 4D
|
109 |
Matrices are similiarly named \texttt{MatDxDT}. For instance a 4D
|
130 |
\texttt{double} matrix is called \texttt{Mat4x4d}.
|
110 |
\texttt{double} matrix is called \texttt{Mat4x4d}.
|
131 |
|
111 |
|
132 |
\subsection{How to use CGLA}
|
112 |
\subsection{How to use CGLA}
|
133 |
|
113 |
|
134 |
If you need a given CGLA class you can find the header file that
|
114 |
If you need a given \texttt{CGLA} class you can find the header file that
|
135 |
contains it in this document. Simply include the header file and use
|
115 |
contains it in this document. Simply include the header file and use
|
136 |
the class. Remember also that all CGLA functions and classes live in
|
116 |
the class. Remember also that all \texttt{CGLA} functions and classes live in
|
137 |
the CGLA namespace! Lastly, look at the example programs that came
|
117 |
the \texttt{CGLA} namespace! Lastly, look at the example programs that came
|
138 |
with the code.
|
118 |
with the code.
|
139 |
|
119 |
|
140 |
An important point is that you should never use the Arith... classes
|
120 |
An important point is that you should never use the Arith... classes
|
141 |
directly. Classes whose names begin with Arith are templates used for
|
121 |
directly. Classes whose names begin with Arith are templates used for
|
142 |
deriving concrete types. It is simpler, cleaner, and the intended
|
122 |
deriving concrete types. It is simpler, cleaner, and the intended
|
143 |
thing to do to only use the derived types.
|
123 |
thing to do to only use the derived types.
|
144 |
|
124 |
|
145 |
In some cases, you may find that you need a vector or matrix class
|
125 |
In some cases, you may find that you need a vector or matrix class
|
146 |
that I haven't defined. If so, it is fortunate that CGLA is easy to
|
126 |
that I haven't defined. If so, it is fortunate that \texttt{CGLA} is easy to
|
147 |
extend. Just look at, say, \texttt{Vec4f} if you need a \texttt{Vec5d}
|
127 |
extend. Just look at, say, \texttt{Vec4f} if you need a \texttt{Vec5d}
|
148 |
class.
|
128 |
class.
|
149 |
|
129 |
|
150 |
For some more specific help look at the next section where some of the
|
130 |
For some more specific help look at the next section where some of the
|
151 |
commonly used operations are shown.
|
131 |
commonly used operations are shown.
|
Line 185... |
Line 165... |
185 |
created differently, using
|
165 |
created differently, using
|
186 |
\begin{verbatim}
|
166 |
\begin{verbatim}
|
187 |
Vec3f p0(10);
|
167 |
Vec3f p0(10);
|
188 |
\end{verbatim}
|
168 |
\end{verbatim}
|
189 |
|
169 |
|
- |
|
170 |
We often need arithmetic operators which work on vectors and matrices. This is supported by CGLA through overloaded versions of the standard arithmetic operators. Using \texttt{Vec3f} and \texttt{+} as examples, we have the following syntax:
|
- |
|
171 |
\begin{verbatim}
|
- |
|
172 |
Vec3f p0(0,1,2);
|
- |
|
173 |
Vec3f p1(0,1,0);
|
- |
|
174 |
|
- |
|
175 |
Vec3f p2 = p0 + p1;
|
- |
|
176 |
p2 += p1; // Same as p2 = p2 + p1
|
- |
|
177 |
\end{verbatim}
|
- |
|
178 |
Thus both the normal form of \texttt{+} and the assignment form are supported for \texttt{Vec3f}. The same is true of the other arithmetic operators \texttt{-*/} and the operators are supported for most CGLA entities including all matrix and vector types.
|
- |
|
179 |
|
- |
|
180 |
Multiplication is also supported for matrix vector products:
|
- |
|
181 |
\begin{verbatim}
|
- |
|
182 |
Vec4d p0(1,1,0,1);
|
- |
|
183 |
|
- |
|
184 |
Mat4x4d m = rotation_Mat4x4d(ZAXIS, 3.14);
|
- |
|
185 |
|
- |
|
186 |
Vec4d p1 = m * p0;
|
- |
|
187 |
\end{verbatim}
|
- |
|
188 |
|
- |
|
189 |
but all vectors are column vectors, so only right multiplication is supported. We cannot multiply a vector on the left side of a matrix. However, there is, of course, a \texttt{dot} function which computes the dot product of two vectors.
|
- |
|
190 |
|
190 |
A very common operation is to compute the normal of a triangle from
|
191 |
A very common operation is to compute the normal of a triangle from
|
191 |
the position of its vertices. Assuming the three vectors represent the
|
192 |
the position of its vertices. Assuming the three vectors represent the
|
192 |
vertices of a triangle, we can compute the normal by finding the
|
193 |
vertices of a triangle, we can compute the normal by finding the
|
193 |
vector from the first vertex to the two other vertices, taking the
|
194 |
vector from the first vertex to the two other vertices, taking the
|
194 |
cross product and normalizing the result. This is a one-liner:
|
195 |
cross product and normalizing the result. This is a one-liner:
|
Line 200... |
Line 201... |
200 |
Quite a lot goes on in the snippet above. Observe that the - operator
|
201 |
Quite a lot goes on in the snippet above. Observe that the - operator
|
201 |
also works for vectors. In fact almost all the arithmetic operators
|
202 |
also works for vectors. In fact almost all the arithmetic operators
|
202 |
work for vectors. You can also use assignment operators (i.e
|
203 |
work for vectors. You can also use assignment operators (i.e
|
203 |
\texttt{+=}) which is often faster. Then there is the function
|
204 |
\texttt{+=}) which is often faster. Then there is the function
|
204 |
\texttt{cross} which simply computes the cross product of its
|
205 |
\texttt{cross} which simply computes the cross product of its
|
205 |
arguments. Another frequently used function is \texttt{dot} which
|
- |
|
206 |
takes the dot product. Finally the vector is normalized using the
|
206 |
arguments. Finally the vector is normalized using the
|
207 |
function normalize.
|
207 |
function normalize.
|
208 |
|
208 |
|
209 |
Of course, we can print all or at least most CGLA entities. For
|
209 |
Of course, we can print all or at least most CGLA entities. For
|
210 |
example
|
210 |
example
|
211 |
|
211 |
|
Line 293... |
Line 293... |
293 |
glVertex3fv(p.get());
|
293 |
glVertex3fv(p.get());
|
294 |
\end{verbatim}
|
294 |
\end{verbatim}
|
295 |
|
295 |
|
296 |
\section{HMesh}
|
296 |
\section{HMesh}
|
297 |
|
297 |
|
298 |
HMesh's \texttt{Manifold} class is a halfedge based mesh data structure. This type of data structure restricts you to manifolds, but allows for general N-gons for arbitrary N and makes manipulation somewhat simpler than other types of data structures for meshes. Note that this particular implementation does not allow more than one loop per face.
|
298 |
HMesh's \texttt{Manifold} class is a halfedge based mesh data structure. To use the basic functionality you need to include the Manifold.h header and use the appropriate name space:
|
299 |
|
- |
|
300 |
The central element of the data structure is the halfedge. It is not the goal here to discuss the halfedge data structure, but it is probably helpful that you see the syntax for e.g. going from a halfedge to the next. It may also be useful to understand the basics of the data structure. The goal is to explain the basics and show how to navigate around the mesh.
|
- |
|
301 |
|
- |
|
302 |
First of all, we only access elements via iterators. An iterator can be thought of as a pointer, but it is in fact an iterator to an STL list. Given a
|
- |
|
303 |
\begin{verbatim}
|
- |
|
304 |
Manifold m;
|
- |
|
305 |
\end{verbatim}
|
- |
|
306 |
we can loop over all its faces using
|
- |
|
307 |
\begin{verbatim}
|
299 |
\begin{verbatim}
|
308 |
for(FaceIter f = m.faces_begin(); f != m.faces_end(); ++f)
|
300 |
#include <Manifold.h>
|
309 |
f->touched = -1;
|
301 |
using namespace HMesh;
|
310 |
\end{verbatim}
|
302 |
\end{verbatim}
|
- |
|
303 |
This type of data structure restricts you to manifolds, but allows for general N-gons for arbitrary N and makes manipulation somewhat simpler than other types of data structures for meshes. Note that this particular implementation does not allow more than one loop per face.
|
311 |
|
304 |
|
312 |
The loop above visited each face f of m and assigned -1 to a variable called touched. The touched variables are simply integers, and a touched variable is associated with each face.
|
305 |
Since the halfedge representation can only represent polygonized manifolds, the name of the data structure is
|
313 |
|
- |
|
314 |
Note that we only refer to faces via their iterators. The same is true of vertices and halfedges. Vertices and halfedges also have touched variables, so the above code could be repeated exactly for vertices and halfedges. Here goes:
|
- |
|
315 |
\begin{verbatim}
|
306 |
\begin{verbatim}
|
316 |
for(VertexIter v = m.vertices_begin();
|
- |
|
317 |
v != m.vertices_end(); ++v)
|
- |
|
318 |
v->touched = -1;
|
- |
|
319 |
|
- |
|
320 |
for(HalfEdgeIter h = m.halfedges_begin();
|
- |
|
321 |
h != m.halfedges_end(); ++h)
|
- |
|
322 |
h->touched = -1;
|
307 |
Manifold m;
|
323 |
\end{verbatim}
|
308 |
\end{verbatim}
|
- |
|
309 |
The central element of the data structure is the \textit{halfedge}. A halfedge is a representation of an edge, but it is imbued with a direction: it represents the edge in the counterclockwise loop around one of the two faces that share the edge. Thus, we always have two halfedges for a given edge, and a halfedge contains an integer index that points to its opposite halfedge. Similarly, indices point to the next and the previous halfedge in a counterclockwise loop as well as the incident face and the incident vertex in the direction of the halfedge.
|
324 |
|
310 |
|
325 |
What would be the use of setting the touched values to -1? Well, if we want to keep track of whether we have visited a given halfedge, we can initially set the touched values of all halfedges to -1 and then as we visit a halfedge set its value to something different. The same idea can be applied to faces and vertices.
|
311 |
A vertex has an integer index referencing one of the halfedges which emanate from the vertex, and a face has the index of one of the halfedges in the loop around the face. The entities and the integer indices used to refer from one entity to another are illustrated in Figure~\ref{fig:halfedge}. Note also that the pointers from an entity to another, e.g. from a halfedge to its next edge is the mechanism that allows us to traverse the mesh.
|
- |
|
312 |
\begin{figure}[h!]
|
- |
|
313 |
\centering
|
- |
|
314 |
\includegraphics[width=0.5\textwidth]{halfedge-entities.pdf}
|
326 |
|
315 |
\caption{A halfedge and related entities. The halfedge has pointers to the \texttt{next} and previous (\texttt{prev}) halfedges in the counterclockwise loop around its face. It also has a pointer to the opposite (\texttt{opp}) halfedge, which corresponds to the same geometric edge but is part of the loop around the adjacent face. Finally, the halfedge has a pointer to the next \texttt{vertex} in the direction of the halfedge and to its \texttt{face}. A face has a pointer to exactly one halfedge (\texttt{last}) and a vertex has a pointer to one outgoing halfedge (\texttt{h}). The word ``pointer'' is a bit of a misnomer. In GEL we use integer indices instead of memory pointers. }
|
327 |
Another common use of the touched values is as indices into an array. In this way, you can store auxiliary data with the mesh. In fact, there is a function\\ \texttt{enumerate\_vertices()} which enumerates all vertices (so each has a unique positive (or zero) integer. Similar functions exist for faces and halfedges.
|
316 |
\label{fig:halfedge}
|
- |
|
317 |
\end{figure}
|
328 |
|
318 |
|
329 |
So far, we have only discussed touched, but halfedges, faces, and vertices contain other data members. Most of these are iterators pointing to other edges, faces, or vertices. In the following, we briefly mention each member of the datastructures and show how to get to it. To get the opposite halfedge, use
|
319 |
The integer indices are not only used to store references from one entity to another. In GEL, we do not directly access entities but use integer IDs to refer to them. For instance to get the position of a vertex, which is stored as a \texttt{Vec3d}, we need
|
330 |
\begin{verbatim}
|
320 |
\begin{verbatim}
|
- |
|
321 |
VertexID vid;
|
331 |
HalfEdgeIter h2 = h1->opp;
|
322 |
// ... obtain a vertex ID
|
- |
|
323 |
vec3d p = m.pos(vid);
|
332 |
\end{verbatim}
|
324 |
\end{verbatim}
|
- |
|
325 |
Note that m.pos(vid) returns a reference to the vertex identified by vid, so we can also assign the vertex position simply using m.pos(vid) = p.
|
333 |
|
326 |
|
334 |
To get the next halfedge (in counterclockwise cycle around the vertex),
|
327 |
\texttt{VertexID}, \texttt{FaceID}, and \texttt{HalfEdgeID} are simply indices which we use to refer to entities in the mesh. These types are used to communicate with the \texttt{Manifold} class. For instance to get the position of a vertex, but many other functions -- both inside and outside the \texttt{Manifold} class take one of the ID types as argument. For instance,
|
335 |
\begin{verbatim}
|
328 |
\begin{verbatim}
|
336 |
HalfEdgeIter h2 = h1->next;
|
329 |
VertexID Manifold::split_edge(HalfEdgeID h);
|
337 |
\end{verbatim}
|
330 |
\end{verbatim}
|
338 |
the previous halfedge,
|
- |
|
- |
|
331 |
splits an edge and returns a \texttt{VertexID} for the introduced vertex. For functions outside the class, we need to also give the \texttt{Manifold} as an argument since an ID does not tell the function which mesh we are referring to. For example
|
339 |
\begin{verbatim}
|
332 |
\begin{verbatim}
|
340 |
HalfEdgeIter h2 = h1->prev;
|
333 |
bool boundary(const Manifold& m, HalfEdgeID h);
|
341 |
\end{verbatim}
|
334 |
\end{verbatim}
|
342 |
the vertex they point at,
|
335 |
returns true if the halfedge identified by \texttt{h} is a boundary edge in \texttt{m}.
|
343 |
\begin{verbatim}
|
- |
|
344 |
VertexIter v = h->vert
|
- |
|
345 |
\end{verbatim}
|
336 |
|
346 |
and the face whose counter clockwise halfedge loop they are one segment of.
|
337 |
We might somewhere have stored the \texttt{VertexID}, but frequently we simply iterate through our vertices. In other words, we loop over all vertices. Such a loop requires another type, namely the \texttt{VertexIDIterator}
|
347 |
\begin{verbatim}
|
338 |
\begin{verbatim}
|
- |
|
339 |
for(VertexIDIterator v = m.vertices_begin();
|
- |
|
340 |
v != m.vertices_end(); ++v)
|
- |
|
341 |
{
|
348 |
FaceIter f = h->face;
|
342 |
Vec3d p = mani.pos(*v);
|
- |
|
343 |
// Do something
|
- |
|
344 |
}
|
349 |
\end{verbatim}
|
345 |
\end{verbatim}
|
350 |
A vertex knows its position which is a Vec3f. To get the position, use
|
346 |
An ID iterator is only useful for iterating over elements in the mesh. However, from the iterator we can obtain the ID by using the dereference operator \texttt{*} as shown above. We also have \texttt{HalfEdgeID}, \texttt{HalfEdgeIDIterator}, \texttt{FaceID}, and \texttt{FaceIDIterator}. Thus, similar code could have been used to iterate over halfedges or faces. Clearly, iterating over elements is just the beginning. The iterators expose how the mesh entities are stored in the \texttt{Manifold} but not how they relate geometrically to one another.
|
- |
|
347 |
|
- |
|
348 |
\subsection{Walker}
|
- |
|
349 |
To traverse the mesh in a geometric fashion, we use the \texttt{Walker}. A \texttt{Walker} simply encapsulates an ID for a given \texttt{HalfEdge} and a pointer to the data structure which stores the mesh. Thus, to compute the centroid for a given face, we can use a \texttt{Walker}
|
351 |
\begin{verbatim}
|
350 |
\begin{verbatim}
|
352 |
Vec3f pos = v->pos;
|
351 |
Vec3d p(0);
|
- |
|
352 |
FaceIDIterator f = m.faces_begin();
|
- |
|
353 |
Walker w = m.walker(*f);
|
- |
|
354 |
for(; !w.full_circle(); w = w.next()){
|
- |
|
355 |
p += m.pos(w.vertex());
|
- |
|
356 |
p /= w.no_steps();
|
353 |
\end{verbatim}
|
357 |
\end{verbatim}
|
354 |
A vertex also knows one outgoing halfedge:
|
358 |
The code above computes the centroid for the first face in the mesh. The benefit of the walker is that it allows us to move from a halfedge to all connected halfedges. The simple traversal functions are \texttt{next}, \texttt{prev}, and \texttt{opp}:
|
355 |
\begin{verbatim}
|
359 |
\begin{verbatim}
|
356 |
HalfEdgeIter h = v->he;
|
360 |
Walker w;
|
- |
|
361 |
w = w.next();
|
- |
|
362 |
w = w.prev();
|
- |
|
363 |
w = w.opp();
|
357 |
\end{verbatim}
|
364 |
\end{verbatim}
|
358 |
A face knows one halfedge in its counterclockwise cycle
|
365 |
\texttt{prev} does the same as \texttt{circulate\_face\_cw} and \texttt{next} does the same as \\\texttt{circulate\_face\_ccw}. The longer names are indicative of the geometric operation while \texttt{prev} and \texttt{next} highlight the connection with the data structure. It is important to note that all of the functions which operate on \texttt{Walker} instances return a new \texttt{Walker} and do not alter the state of the current walker. Thus to walk around a face, we use \texttt{w = w.next()} as opposed to just \texttt{w.next()} in the for loop above.
|
- |
|
366 |
That might seem inconvenient but it is more flexible since we can obtain, say, a nearby vertex just by concatenating some traversal functions. For instance \texttt{w.next().opp().next().vertex()} returns an ID to a vertex nearby -- without changing \texttt{w}. The sequence \texttt{w.next().opp().next()} creates three anonymous walkers. If, on the other hand, the functions used for walking updated the state of \texttt{w}, we would have needed to first make a named copy of \texttt{w} before updating its state, so that we could get back to the original state.
|
- |
|
367 |
|
- |
|
368 |
\texttt{Walker} can be used to circulate around both faces and vertices. Below, we use vertex circulation to compute the average of the neighbors of a vertex
|
359 |
\begin{verbatim}
|
369 |
\begin{verbatim}
|
- |
|
370 |
Vec3d p(0);
|
- |
|
371 |
VertexIDIterator v = m.vertices_begin();
|
360 |
HalfEdgeIter h = face->last;
|
372 |
Walker w = m.walker(*v);
|
- |
|
373 |
for(; !w.full_circle(); w = w.circulate_vertex_ccw()){
|
- |
|
374 |
p += m.pos(w.vertex());
|
- |
|
375 |
p /= w.no_steps();
|
361 |
\end{verbatim}
|
376 |
\end{verbatim}
|
362 |
|
377 |
|
- |
|
378 |
The \texttt{full\_circle()} function tests whether the walker has returned to the original halfedge whence it was created. We can also call \texttt{no\_steps() } which returns the number of steps taken. In this regard, vertex circulation is considered atomic - even though \texttt{w.circulate\_vertex\_ccw()} is the same as \texttt{w.prev().opp()}.
|
363 |
|
379 |
|
364 |
To move around a face, we can repeatedly ask for the next halfedge. Likewise, to move around a vertex, we can repeatedly ask for \texttt{h->opp->next} but it is not elegant, and in both cases we need a stop condition. Circulators encapsulate the task of visiting all edges delimiting a face or radiating from a vertex in a nice(r) way.
|
380 |
From a walker we can easily obtain any of the mesh entities that the halfedge it refers to are incident upon. For instance \texttt{vertex()} returns the \texttt{VertexID} of the vertex which the halfedge points to, \texttt{face()} gives us the \texttt{FaceID} of the incident face and \texttt{halfedge()} simply returns the \texttt{HalfEdgeID}.
|
365 |
|
381 |
|
- |
|
382 |
To summarize there are three datatypes that we use to refer to mesh entitites.
|
- |
|
383 |
\begin{itemize}
|
- |
|
384 |
\item IDs \texttt{VertexID}, \texttt{HalfEdgeID}, and \texttt{FaceID} are simply indices. These types are what we use when calling functions that take arguments which refer to mesh entities.
|
366 |
Given
|
385 |
\item ID iterators \texttt{VertexIDIterator}, \texttt{HalfEdgeIDIterator}, and\\ \texttt{FaceIDIterator} as their names imply can be used to iterate over the entities of a mesh. As such they reflect how the mesh is stored in memory. Dereferencing an ID iterator will give an ID.
|
- |
|
386 |
\item \texttt{Walker} is used to walk from halfedge to halfedge on the mesh. It utilizes the references stored in halfedges to other halfedges in order to facilitate this traversal. Again, we can obtain an ID from a walker.
|
367 |
\begin{verbatim}
|
387 |
\end{itemize}
|
368 |
VertexIter v
|
388 |
It might seem tiresome that you have to deal with three different methods for referring to mesh entities, but they do very different jobs. The IDs are simply indices (wrapped in a class) referring to mesh elements. The iterators combine this indices with a reference to the actual data structures. The walker contains functions that allow us to move from halfedge to halfedge and additionally keeps track of the starting point and number of steps taken.
|
- |
|
389 |
|
- |
|
390 |
We could have combined two or all three of these concepts, but would have led to rather bloated datatypes.
|
- |
|
391 |
|
369 |
\end{verbatim}
|
392 |
\subsection{Attributes}
|
370 |
we can go:
|
393 |
Given a \texttt{VertexID}, \texttt{v}, and a \texttt{Manifold}, \texttt{m}, we can obtain the geometric position of the vertex with the method call \texttt{m.pos(v)}. If is fairly important to note that a reference to the position is returned. Thus, we can assign the position of a vertex:
|
371 |
\begin{verbatim}
|
394 |
\begin{verbatim}
|
372 |
VertexCirculator vc(v);
|
- |
|
373 |
Vec3f p(0.0);
|
395 |
Vec3d p;
|
374 |
for( ; !vc.end(); ++vc)
|
396 |
VertexID v;
|
375 |
p += vc.get_vertex()->pos;
|
397 |
// ...
|
376 |
p/= vc.no_steps();
|
398 |
m.pos(v) = p;
|
377 |
\end{verbatim}
|
399 |
\end{verbatim}
|
378 |
|
400 |
|
379 |
So what does the code above do? It visits each neighboring vertex to a given vertex and computes the average position which is useful in a number of situations.
|
401 |
Geometric position is in fact the only attribute that is stored for a vertex. That might seem strange since we would very often like to associate any number of attributes with mesh entities. For instance, we might need to associate normals, colors, curvature tensors, counters, etc. with vertices, faces, or even edges.
|
380 |
|
402 |
|
381 |
We can do the same thing with a FaceCirculator
|
403 |
Unfortunately, what precise attributes we need depends greatly on the precise application. To resolve this issue, we have introduces three attribute vector class templates which allow the user to create his own attribute vectors:
|
382 |
\begin{verbatim}
|
404 |
\begin{verbatim}
|
- |
|
405 |
VertexAttributeVector<T> vertex_attrib_vector;
|
383 |
FaceCirculator fc(f);
|
406 |
FaceAttributeVector<T> face_ttrib_vector;
|
- |
|
407 |
HalfEdgeAttributeVector<T> halfedge_attrib_vector;
|
384 |
Vec3f p(0.0);
|
408 |
\end{verbatim}
|
- |
|
409 |
where \texttt{T} is a typename. Attribute vectors are indexed with indices. Thus, a
|
385 |
for( ; !fc.end(); ++fc)
|
410 |
\texttt{VertexAttributeVector} is indexed with a \texttt{VertexID} and likewise for the other types. To give a simple example of how this is used consider smoothing a mesh. The simplest way of smoothing is to replace the vertex with the average of its neighbors. However, if we copy the average value back before the average value for some neighbor has been computed, then we clearly use one average to compute another average and thereby introduce an unfortunate dependence on the ordering of the vertices. Consequently, we need to first compute all of the averages and then update the original vertices. The code looks as follows:
|
- |
|
411 |
\begin{verbatim}
|
- |
|
412 |
void smooth(Manifold& m, float t)
|
- |
|
413 |
{
|
- |
|
414 |
VertexAttributeVector<Vec3f> pos(m.total_vertices());
|
- |
|
415 |
for(VertexIDIterator v = m.vertices_begin();
|
386 |
p += fc.get_vertex()->pos;
|
416 |
v != m.vertices_end(); ++v)
|
- |
|
417 |
{
|
- |
|
418 |
if(!boundary(m, *v))
|
- |
|
419 |
{
|
387 |
p/= fc.no_steps();
|
420 |
Vec3f avg_pos(0);
|
- |
|
421 |
Walker w = m.walker(v)
|
- |
|
422 |
for(; !w.full_circle(); w = w.circulate_vertex_cw())
|
- |
|
423 |
avg_pos += m.pos(w.vertex());
|
- |
|
424 |
pos[*v] = avg_pos / w.no_steps();
|
- |
|
425 |
}
|
- |
|
426 |
}
|
- |
|
427 |
for(VertexIDIterator v = m.vertices_begin();
|
- |
|
428 |
v != m.vertices_end(); ++v){
|
- |
|
429 |
if(!boundary(m, *v))
|
- |
|
430 |
m.pos(*v) = pos[*v];
|
- |
|
431 |
}
|
- |
|
432 |
}
|
388 |
\end{verbatim}
|
433 |
\end{verbatim}
|
389 |
|
434 |
|
390 |
Internally, both the vertex and face circulators simply keep track of a single halfedge. So \texttt{get\_vertex()} returns the vertex pointed to by that halfedge. There are similar functions for getting the halfedge itself, the face it points to or its opposite halfedge.
|
435 |
In the smoothing example the \texttt{VertexAttributeVector} containing the new positions is initialized to a size equal to the actual number of vertices. That is not strictly necessary since the attribute vectors automatically resize if the index stored in the ID is out of bounds. Thus, we never explicitly need to increase the size of an attribute vector. What if there are suddenly fewer vertices? In that case, we can clean up the attribute vector. However, we also need to clean up the manifold. The procedure looks as follows:
|
391 |
|
- |
|
392 |
Use circulators whenever you need to go around a face or vertex, but not when you need more complex navigation which is not easily expressed as circulation. In that case it is probably easier to just use the next, prev, and opp to move around. To work with the functions and classes just described, you will need the following header files:
|
- |
|
393 |
\begin{verbatim}
|
436 |
\begin{verbatim}
|
- |
|
437 |
VertexAttributeVector<T> vertex_attrib_vector;
|
394 |
#include <HMesh/Manifold.h>
|
438 |
Manifold m;
|
- |
|
439 |
// ....
|
- |
|
440 |
|
- |
|
441 |
IDRemap remap;
|
395 |
#include <HMesh/FaceCirculator.h>
|
442 |
m.cleanup(remap);
|
396 |
#include <HMesh/VertexCirculator.h>
|
443 |
vertex_attrib_vector.cleanup(remap);
|
397 |
\end{verbatim}
|
444 |
\end{verbatim}
|
- |
|
445 |
Calling \texttt{cleanup} on the \texttt{Manifold} removes unused mesh entities, resizes, and resize the vectors containing these entities. When we subsequently call cleanup on the attribute vector, the same reorganization is carried out on the attribute vector keeping it in sync. Strictly speaking cleanup is rarely needed, but it removes unused memory which can be a performance advantage.
|
- |
|
446 |
|
398 |
\subsection{Extended Example: Edge Flipping}
|
447 |
\subsection{Extended Example: Edge Flipping}
|
399 |
The following example demonstrates how to create a Manifold and add polygons (in this case triangles) and finally how to flip edges of a manifold. First, let us define some vertices
|
448 |
The following example demonstrates how to create a \texttt{Manifold} and add polygons (in this case triangles) and finally how to flip edges of a manifold. First, let us define some vertices
|
400 |
\begin{verbatim}
|
449 |
\begin{verbatim}
|
401 |
vector<Vec3f> vertices(3);
|
450 |
vector<Vec3f> vertices(3);
|
402 |
vertices[0] = p1;
|
451 |
vertices[0] = p1;
|
403 |
vertices[1] = p2;
|
452 |
vertices[1] = p2;
|
404 |
vertices[2] = p3;
|
453 |
vertices[2] = p3;
|
405 |
\end{verbatim}
|
454 |
\end{verbatim}
|
406 |
and then a vector of faces. The faces vector contains the number of vertices of each face in the mesh we want tor produce. Initially, we want to make a mesh with just one single triangle, so we produce a vector of one element and set that element to 3.
|
455 |
and then a vector of faces. The faces vector contains the number of vertices of each face in the mesh we want tor produce. Initially, we want to make a mesh with just one single triangle, so we produce a vector of one element and set that element to 3.
|
407 |
\begin{verbatim}
|
456 |
\begin{verbatim}
|
408 |
vector<int> faces(1);
|
457 |
vector<int> faces(1);
|
409 |
faces[0] = 3;
|
458 |
faces[0] = 3;
|
410 |
\end{verbatim}
|
459 |
\end{verbatim}
|
411 |
|
- |
|
412 |
Next, we need the index vector. This vector is a long list of indices to vertices. For each face, we store the indices to its vertices in this vector. Since we just have a triangle, we store three vertices in the vector.
|
460 |
Next, we need the index vector. This vector is a long list of indices to vertices. For each face, we store the indices to its vertices in this vector. Since we just have a triangle, we store three vertices in the vector.
|
413 |
\begin{verbatim}
|
461 |
\begin{verbatim}
|
414 |
vector<int> indices(3);
|
462 |
vector<int> indices(3);
|
415 |
indices[0]=0;
|
463 |
indices[0]=0;
|
416 |
indices[1]=1;
|
464 |
indices[1]=1;
|
417 |
indices[2]=2;
|
465 |
indices[2]=2;
|
418 |
\end{verbatim}
|
466 |
\end{verbatim}
|
419 |
So, if we had had two triangles, we would have stored six indices. Finally, we call \texttt{build\_manifold} with the indexed face set data, we have compiled.
|
467 |
So, if we had had two triangles, we would have stored six indices. Finally, we call \texttt{build} with the indexed face set data, we have compiled.
|
420 |
\begin{verbatim}
|
468 |
\begin{verbatim}
|
421 |
build_manifold(mani, // The triangle mesh.
|
- |
|
422 |
3, // Number of vertices.
|
- |
|
423 |
&vertices[0], // Pointer to vertices.
|
469 |
m.build(3, reinterpret_cast<float*>(&vertices[0]),1,
|
424 |
1, // Number of faces.
|
- |
|
425 |
&faces[0], // Pointer to faces.
|
470 |
&faces[0], &indices[0]);
|
426 |
&indices[0]); // Pointer to indices.
|
- |
|
427 |
\end{verbatim}
|
- |
|
428 |
The result of the above is a mesh with a single triangle. Note that \texttt{build\_manifold} is in
|
- |
|
429 |
\begin{verbatim}
|
- |
|
430 |
#include <HMesh/build_manifold.h>
|
- |
|
431 |
\end{verbatim}
|
471 |
\end{verbatim}
|
- |
|
472 |
The result of the above is a mesh with a single triangle.
|
432 |
Next, we try to split an edge. We grab the first halfedge and split it: Now we have two triangles. Splitting the halfedge changes the containing triangle to a quadrilateral, and we call triangulate to divide it into two triangls again.
|
473 |
Next, we try to split an edge. We grab the first halfedge and split it: Now we have two triangles. Splitting the halfedge changes the containing triangle to a quadrilateral, and we call triangulate to divide it into two triangls again.
|
433 |
\begin{verbatim}
|
474 |
\begin{verbatim}
|
434 |
HalfEdgeIter h = m.halfedges_begin();
|
475 |
HalfEdgeIDIterator h = m.halfedges_begin();
|
435 |
m.split_edge(h);
|
476 |
m.split_edge(*h);
|
436 |
m.triangulate(h->face);
|
477 |
triangulate_face_by_edge_split(m, m.walker(*h).face());
|
437 |
\end{verbatim}
|
478 |
\end{verbatim}
|
438 |
Now, we obtain an iterator to the first of our (two) triangles.
|
479 |
Now, we obtain an iterator to the first of our (two) triangles.
|
439 |
\begin{verbatim}
|
480 |
\begin{verbatim}
|
440 |
FaceIter f1 =m.faces_begin();
|
481 |
FaceIDIterator f1 =m.faces_begin();
|
441 |
\end{verbatim}
|
482 |
\end{verbatim}
|
442 |
We create a vertex, \texttt{v}, at centre of \texttt{f1} and insert it in that face:
|
483 |
We create a vertex, \texttt{v}, at centre of \texttt{f1} and insert it in that face:
|
443 |
\begin{verbatim}
|
484 |
\begin{verbatim}
|
444 |
VertexIter v=m.create_vertex(centre(f1));
|
- |
|
445 |
m.face_insert_point(f1,v);
|
485 |
m.split_face_by_vertex(*f1);
|
446 |
\end{verbatim}
|
486 |
\end{verbatim}
|
447 |
The code below, marks one of a pair of halfedges (with the value 1).
|
487 |
The code below, marks one of a pair of halfedges (with the value 1).
|
448 |
\begin{verbatim}
|
488 |
\begin{verbatim}
|
- |
|
489 |
HalfEdgeAttributeVector<int> touched;
|
- |
|
490 |
|
- |
|
491 |
// ....
|
- |
|
492 |
|
449 |
for(HalfEdgeIter h = m.halfedges_begin(); h!=m.halfedges_end(); ++h)
|
493 |
for(HalfEdgeIDIterator h = m.halfedges_begin();
|
450 |
h->touched =0;
|
494 |
h!=m.halfedges_end(); ++h)
|
- |
|
495 |
{
|
451 |
for(HalfEdgeIter h = m.halfedges_begin(); h!=m.halfedges_end(); ++h)
|
496 |
if(m.walker(*h).opp().halfedge() < *h)
|
452 |
if(h->opp->touched == 0)
|
497 |
touched[*h] =0;
|
- |
|
498 |
else
|
453 |
h->touched = 1;
|
499 |
touched[*h] =1;
|
- |
|
500 |
}
|
454 |
\end{verbatim}
|
501 |
\end{verbatim}
|
455 |
Next, we set the \texttt{flipper} variable to point to the first of these halfedges:
|
502 |
Next, we set the \texttt{flipper} variable to point to the first of these halfedges:
|
456 |
\begin{verbatim}
|
503 |
\begin{verbatim}
|
457 |
flipper = m.halfedges_begin();
|
504 |
flipper = m.halfedges_begin();
|
458 |
\end{verbatim}
|
505 |
\end{verbatim}
|
459 |
The long piece of code below examines a halfedge pointed to by \texttt{flipper}, and if it is not a boundary halfedge it tries to flip it. Then it increments the \texttt{flipper} variable until it lands on a halfedge marked with 1. If \texttt{flipper} reaches the end of the list of halfedges, we start over.
|
506 |
The long piece of code below examines a halfedge pointed to by \texttt{flipper}, and if it is not a boundary halfedge it tries to flip it. Then it increments the \texttt{flipper} variable until it lands on a halfedge marked with 1. If \texttt{flipper} reaches the end of the list of halfedges, we start over.
|
460 |
\begin{verbatim}
|
507 |
\begin{verbatim}
|
461 |
if(is_boundary(flipper))
|
508 |
if(!boundary(m, *flipper))
|
462 |
cout << "boundary edge: could not flip" << endl;
|
- |
|
463 |
else
|
- |
|
464 |
if(!m.flip(flipper))
|
509 |
if(precond_flip_edge(m,*flipper))
|
465 |
cout << "could not flip" << endl;
|
510 |
m.flip_edge(*flipper);
|
466 |
do
|
511 |
do
|
467 |
{
|
512 |
{
|
468 |
++flipper;
|
513 |
++flipper;
|
469 |
if(flipper==m.halfedges_end())
|
514 |
if(flipper==m.halfedges_end())
|
- |
|
515 |
{
|
470 |
flipper = m.halfedges_begin();
|
516 |
flipper = m.halfedges_begin();
|
- |
|
517 |
break;
|
- |
|
518 |
}
|
471 |
}
|
519 |
}
|
472 |
while(flipper->touched == 0);
|
520 |
while(touched[*flipper] == 0);
|
473 |
\end{verbatim}
|
521 |
\end{verbatim}
|
474 |
\subsection{Extended Example: Implicit Surface Polygonization}
|
- |
|
475 |
This example demonstrates how we can produce an HMesh Manifold from an implicitly defined object. Say, we have some function, \texttt{f}, which represents an object by what we sometimes call a characteristic function (\texttt{f<0} inside the object, \texttt{f>0} outside, \texttt{f=0} on the surface). We wish to extract the 0 set as a Manifold.
|
522 |
This example may not serve much of a purpose but illustrates how we can iterate over all edges and flip them. From this example, we are fairly close to Delaunay triangulation.
|
476 |
|
523 |
|
477 |
First, we create a 3D grid of floating point values as shown below.
|
- |
|
478 |
\begin{verbatim}
|
- |
|
479 |
RGrid<float> grid(Vec3i(N,N,N)); // Voxel grid on which to sample
|
- |
|
480 |
\end{verbatim}
|
- |
|
481 |
We sample \texttt{f} on that grid
|
- |
|
482 |
\begin{verbatim}
|
- |
|
483 |
for(int i=0;i<N;++i)
|
- |
|
484 |
for(int j=0;j<N;++j)
|
- |
|
485 |
for(int k=0;k<N;++k)
|
- |
|
486 |
grid[Vec3i(i,j,k)] = f(i,j,k);
|
- |
|
487 |
\end{verbatim}
|
- |
|
488 |
Next, we call a function which polygonizes the 0 set. The first two arguments are the grid and the manifold, the third argument is set to 0, since we want the zero level set, and the final argument tells the polygonizer to push the vertices onto the zero set (as opposed to leaving them in their initial position which is close to but not actually on the zero set).
|
524 |
\subsection{HMesh tools}
|
489 |
\begin{verbatim}
|
- |
|
490 |
cuberille_polygonize(grid, mani, 0.0, true);
|
- |
|
491 |
\end{verbatim}
|
- |
|
492 |
In post-processing, we triangulate \texttt{mani} and remove ugly triangles. Caps are triangles with one big angle (close to 180 degrees). Needles are triangles with one very short edge.
|
- |
|
493 |
\begin{verbatim}
|
- |
|
494 |
triangulate(mani);
|
- |
|
495 |
remove_caps_from_trimesh(mani, M_PI * 0.85);
|
- |
|
496 |
remove_needles_from_trimesh(mani, 1e-2);
|
- |
|
497 |
\end{verbatim}
|
- |
|
498 |
Note that you need the following header files:
|
- |
|
499 |
\begin{verbatim}
|
- |
|
500 |
#include <Geometry/RGrid.h>
|
- |
|
501 |
#include <HMesh/volume_polygonize.h>
|
- |
|
502 |
\end{verbatim}
|
- |
|
503 |
to use the grid and the polygonizer, respectively.
|
- |
|
504 |
|
525 |
|
- |
|
526 |
The HMesh directory contains not only the basic data structure and functionality for traversing a mesh. There are also tools for mesh optimization through energy minimization, several algorithms for mesh smoothing, a number of tools for cleaning meshes as well as tools for simplifying meshes.
|
505 |
|
527 |
|
506 |
\section{GLGraphics}
|
528 |
\section{GLGraphics}
|
507 |
|
529 |
|
508 |
GLGraphics contains a set of tools needed for visualization of geometrical objects. In particular, this namespace contains mesh rendering facilities, and in the following, a very simple example is given. This section is basically a walk through of the simplest GEL program that draws a mesh. Apart from GEL, we also use OpenGL and that requires a toolkit for connecting with the window system. With GEL programs, one generally uses GLUT, and this example is not an exception.
|
530 |
\texttt{GLGraphics} contains a set of tools needed for visualization of geometrical objects. In particular, this namespace contains mesh rendering facilities, and in the following, a very simple example is given. This section is basically a walk through of the simplest GEL program that draws a mesh. Apart from GEL, we also use OpenGL and that requires a toolkit for connecting with the window system. With GEL programs, one generally uses GLUT, and this example is not an exception.
|
509 |
|
531 |
|
510 |
For starters, we need to include some files mostly from GLGraphics but also the header file for the mesh load function of HMesh and the GLEW header. Why incude glew.h rather than just gl.h? Well, HMesh/draw.h contains some draw functions which rely on shaders, and since gl.h is normally not up to date, it makes sense to use glew.h instead of gl.h even though it inflicts a dependency. We include GLGraphics/gel\_glut.h rather than the normal glut.h. That is because the GEL version works the same on Windows, OSX, Linux and probably other platforms.
|
532 |
For starters, we need to include some files mostly from \texttt{GLGraphics} but also the header file for the mesh load function of \texttt{HMesh} and the \texttt{GLEW} header. Why incude \texttt{glew.h} rather than just \texttt{gl.h}? Well, \texttt{HMesh/draw.h} contains some draw functions which rely on shaders, and since \texttt{gl.h} is normally not up to date, it makes sense to use \texttt{glew.h} instead of \texttt{gl.h} even though it inflicts a dependency. We include \texttt{GLGraphics/gel\_glut.h} rather than the normal \texttt{glut.h}. That is because the GEL version works the same on Windows, OSX, Linux and probably other platforms.
|
511 |
|
533 |
|
512 |
We also open the namespaces we will need and declare two globals: The view controller \texttt{view\_ctrl} and the mesh \texttt{mani}. The view controller class is rather complex. It more or less insulates you from having to deal directly with the projections and transformations of OpenGL: It sets up a perspective projection and also the modelview transformation needed to view the object. From a user interface perspective, it defines a virtual trackball which allows you to rotate the object.
|
534 |
We also open the namespaces we will need and declare two globals: The view controller \texttt{view\_ctrl} and the mesh \texttt{mani}. The view controller class is rather complex. It more or less insulates you from having to deal directly with the projections and transformations of OpenGL: It sets up a perspective projection and also the modelview transformation needed to view the object. From a user interface perspective, it defines a virtual trackball which allows you to rotate the object.
|
513 |
\begin{verbatim}
|
535 |
\begin{verbatim}
|
514 |
#include <GL/glew.h>
|
536 |
#include <GL/glew.h>
|
515 |
#include <GLGraphics/gel_glut.h>
|
537 |
#include <GLGraphics/gel_glut.h>
|
Line 601... |
Line 623... |
601 |
|
623 |
|
602 |
These functions attempt to obviate the need for an answer to the first two questions by providing an API for loading and compiling shaders and checking for errors. However, I don't include functions for creating the program, attaching shaders and linking. Why not? Because the need for flexibility means that the API would be just as complex as just using the OpenGL functions directly! However, loading shaders and checking for errors in compiled shaders is different. It makes sense to wrap that. It also makes sense to wrap the error checking for programs that are linked, so there is a function for that too.
|
624 |
These functions attempt to obviate the need for an answer to the first two questions by providing an API for loading and compiling shaders and checking for errors. However, I don't include functions for creating the program, attaching shaders and linking. Why not? Because the need for flexibility means that the API would be just as complex as just using the OpenGL functions directly! However, loading shaders and checking for errors in compiled shaders is different. It makes sense to wrap that. It also makes sense to wrap the error checking for programs that are linked, so there is a function for that too.
|
603 |
|
625 |
|
604 |
Since shader loading and error check sandwhich the two calls needed for compilation, the most important function in this API, \texttt{create\_glsl\_shader}, loads a shader, compiles it, checks for errors and returns the shader handle. There is also a version which creates a shader from a string.
|
626 |
Since shader loading and error check sandwhich the two calls needed for compilation, the most important function in this API, \texttt{create\_glsl\_shader}, loads a shader, compiles it, checks for errors and returns the shader handle. There is also a version which creates a shader from a string.
|
605 |
|
627 |
|
606 |
There is some code below to illustrate usage.
|
628 |
There is some code below to illustrate usage.
|
607 |
\begin{verbatim}
|
629 |
\begin{verbatim}
|
608 |
GLuint vs = create_glsl_shader(GL_VERTEX_SHADER,
|
630 |
GLuint vs = create_glsl_shader(GL_VERTEX_SHADER,
|
609 |
shader_path, "tri.vert");
|
631 |
shader_path, "tri.vert");
|
610 |
GLuint gs = create_glsl_shader(GL_GEOMETRY_SHADER_EXT,
|
632 |
GLuint gs = create_glsl_shader(GL_GEOMETRY_SHADER_EXT,
|
611 |
shader_path, "tri.geom");
|
633 |
shader_path, "tri.geom");
|
Line 705... |
Line 727... |
705 |
\item There is more - for instance a resource manager template, some string utility templates and a hash table implementation.
|
727 |
\item There is more - for instance a resource manager template, some string utility templates and a hash table implementation.
|
706 |
\end{trivlist}
|
728 |
\end{trivlist}
|
707 |
Arguably, it would be more pretty if these pieces had been more thematically linked, but many are used a lot, and it seemed reasonable to have somewhere to stick various functions and classes that did not naturally belong elsewhere.
|
729 |
Arguably, it would be more pretty if these pieces had been more thematically linked, but many are used a lot, and it seemed reasonable to have somewhere to stick various functions and classes that did not naturally belong elsewhere.
|
708 |
|
730 |
|
709 |
|
731 |
|
710 |
\section{Authors and License}
|
732 |
\section{Authors}
|
- |
|
733 |
\begin{trivlist}
|
- |
|
734 |
\item Andreas B{\ae}rentzen created the library and has written most of the code not contributed by the people below.
|
- |
|
735 |
\item Jeppe Revall Frisvad has contributed greatly to the CGLA part of GEL and elsewhere.
|
- |
|
736 |
\item Christian Thode Larsen rewrote the classes in HMesh. They are much nicer for it.
|
711 |
Many other people contribute, but the core of GEL was written (mostly) by Andreas B{\ae}entzen (jab{@}imm.dtu.dk), and any bug fixes, contributions, or questions should be addressed to me, unless you know precisely who could take care of the problem.
|
737 |
\item Anders Wang Kristensen has been a great help in the process of reworking HMesh and also contributed some code for an OpenGL console.
|
- |
|
738 |
\item Henrik Aan{\ae}s provided the original LinAlg package, which is a set of simple but very useful Lapack bindings.
|
- |
|
739 |
\item Rasmus Paulsen, Bjarke Jakobsen, Marek Misztal helped with structure and compilation on various platforms with testing and ideas.
|
- |
|
740 |
\end{trivlist}
|
712 |
|
741 |
|
713 |
I was considering putting GEL under the LGPL. But it is a long complex
|
- |
|
714 |
text. The longer any kind of document, the more chances for loopholes
|
- |
|
715 |
in my opinion. Instead, I list a few rules below. The most
|
742 |
\section{License}
|
716 |
important one is that if you want to use GEL for some purpose, and it
|
- |
|
717 |
is not crystal clear whether it is against the rules, contact me. As
|
- |
|
718 |
for the rules:
|
743 |
\begin{trivlist}
|
719 |
|
744 |
\item
|
720 |
You are allowed to use GEL for academic or commercial purposes. In
|
- |
|
721 |
particular, you are welcome to give GEL to students as a basis for
|
745 |
You are allowed to use GEL for academic or commercial purposes. In particular, you are welcome to give GEL to students as a basis for academic work or to use it in your own applications.
|
722 |
academic work or to use it for your own applications.
|
- |
|
723 |
|
746 |
\item
|
724 |
The biggest limitation that I want to impose is that you cannot repackage
|
- |
|
725 |
GEL in any way. You are not allowed to distribute another library which
|
747 |
Regarding the use of GEL in other libraries. GEL does exist in slightly different versions, since we have created pared down packages for various courses. We would like to retain the prerogative of repackaging. If you would like to use GEL in its entirety in another library that is fine, but we do not allow you not to take bits and pieces and put them into a different library.
|
726 |
contains GEL or parts of GEL unless you make it clear that this other
|
- |
|
727 |
library contains GEL. You are also not allowed to redistribute GEL in a
|
- |
|
- |
|
748 |
\item
|
728 |
changed form. If you want changes to be made, contact me.
|
749 |
If you use GEL, we would be grateful for due credit.
|
729 |
|
750 |
\item
|
730 |
Of course, neither I nor my employer will give you any money or be
|
- |
|
731 |
held responsible in any way, under any circumstances what so ever - no
|
751 |
Finally, we follow the MIT license as regards warranty:
|
732 |
matter what sort of damage GEL might inflict upon you. Not that I can
|
- |
|
733 |
foresee GEL causing you any damage :-)
|
- |
|
734 |
|
752 |
\item
|
735 |
If anything is unclear, please contact me. In fact, if you want to use
|
- |
|
736 |
GEL for a bigger project, I'd appreciate an email to jab@imm.dtu.dk
|
753 |
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
737 |
|
754 |
\item
|
738 |
In a project such as this, it is almost impossible to completely avoid
|
755 |
If anything is unclear, please send an email to jab@imm.dtu.dk.
|
739 |
building upon fragments of other peoples source code. GEL includes an
|
- |
|
740 |
obj loader based on work by Nate Robins. Some pieces of source code
|
- |
|
741 |
from Graphics Gems have also been used. Moreover, I have included
|
756 |
\end{trivlist}
|
742 |
rply by Diego Nehab, Princeton University, and the Simple OpenGL Image Loader by
|
- |
|
743 |
Jonathan Dummer. All of this amounts to only a fraction of the GEL source code and it should not be in violation of any license. In particular, SOIL and RPLY are under the MIT license and it is acceptable to include these packages as long as the copyright notice is retained (which it is.)
|
757 |
\section{Open Source Code used in GEL}
|
744 |
|
758 |
|
- |
|
759 |
Source code from other projects have been incorporated in GEL.
|
- |
|
760 |
\begin{trivlist}
|
- |
|
761 |
\item From Graphics Gems, two functions for inverting matrices and Jules Bloomenthal's polygonizer which I reworked from C to C++. This is allowed according to the license.
|
- |
|
762 |
\item rply by Diego Nehab, Princeton University, and the Simple OpenGL Image Loader by Jonathan Dummer. These are MIT licensed and our use is congruent with that license.
|
- |
|
763 |
\item The OpenGL Extension Wrangler Library is also included and appears to have a license identical to the MIT license. As mentioned, our use is congruent with that license.
|
- |
|
764 |
\end{trivlist}
|
- |
|
765 |
The incorporated code amounts to only a small fraction of the GEL source code.
|
745 |
\end{document}
|
766 |
\end{document}
|