Subversion Repositories gelsvn

Rev

Rev 633 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 633 Rev 635
Line 175... Line 175...
175
  Vec3f p2 = p0 + p1;
175
  Vec3f p2 = p0 + p1;
176
  p2 += p1; // Same as p2 = p2 + p1
176
  p2 += p1; // Same as p2 = p2 + p1
177
\end{verbatim}
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.
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
 
179
 
180
Multiplication is also supported for matrix vector products:
180
Multiplication is also supported for matrix vector products. Below an example with 4D double precision vector and matrix:
181
\begin{verbatim}
181
\begin{verbatim}
182
  Vec4d p0(1,1,0,1);
182
  Vec4d x(1,1,0,1);
183
  
183
  
184
  Mat4x4d m = rotation_Mat4x4d(ZAXIS, 3.14);
184
  Mat4x4d m = rotation_Mat4x4d(ZAXIS, 3.14);
185
 
185
 
186
  Vec4d p1 = m * p0;
186
  Vec4d y = m * x;
187
\end{verbatim}
187
\end{verbatim}
188
 
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. 
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
 
191
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
Line 384... Line 384...
384
                   [&](VertexID v){ p += m.pos(v); });
384
                   [&](VertexID v){ p += m.pos(v); });
385
        return p / n;
385
        return p / n;
386
\end{verbatim}
386
\end{verbatim}
387
Here the function \texttt{circulate\_vertex\_ccw} takes three arguments. The \texttt{Manifold}, \texttt{m}, and the vertex, \texttt{v}, around which we circulate, and, finally, a function that accepts a \texttt{VertexID}. This function gets called for every vertex adjacent to \texttt{v}. In this example, the function is given as a so called \textit{lambda} function. This allows us to write things compactly and to have the body of the function where it is needed. We could also have passed a function which accepts a \texttt{FaceID} or a \texttt{HalfEdgeID} or a \texttt{Walker}. Thus, we can visit incident faces and edges during circulation if that is what we need, and if we need go get some entity other than adjacent vertices, edges, or faces, we can use the \texttt{Walker} option which is the most generic.
387
Here the function \texttt{circulate\_vertex\_ccw} takes three arguments. The \texttt{Manifold}, \texttt{m}, and the vertex, \texttt{v}, around which we circulate, and, finally, a function that accepts a \texttt{VertexID}. This function gets called for every vertex adjacent to \texttt{v}. In this example, the function is given as a so called \textit{lambda} function. This allows us to write things compactly and to have the body of the function where it is needed. We could also have passed a function which accepts a \texttt{FaceID} or a \texttt{HalfEdgeID} or a \texttt{Walker}. Thus, we can visit incident faces and edges during circulation if that is what we need, and if we need go get some entity other than adjacent vertices, edges, or faces, we can use the \texttt{Walker} option which is the most generic.
388
 
388
 
389
To summarize there are three datatypes that we use to refer to mesh entitites.
389
To sum up, there are two datatypes that we use to refer to mesh entitites.
390
\begin{itemize}
390
\begin{itemize}
391
\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. 
391
\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. 
392
\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. 
-
 
393
\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.
392
\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.
394
\end{itemize}
393
\end{itemize}
395
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.
394
It might seem tiresome that you have to deal with two 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 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. In fact there are also three iterator classes, but we do not mention them, because the user does not need them; they are only a tool which allows for loops that visit all faces, edges, or vertices.
396
 
-
 
397
We could have combined two or all three of these concepts, but would have led to rather bloated datatypes.
-
 
398
 
395
 
399
\subsection{Attributes}
396
\subsection{Attributes}
400
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:
397
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:
401
\begin{verbatim}
398
\begin{verbatim}
402
Vec3d p;
399
Vec3d p;
Line 412... Line 409...
412
VertexAttributeVector<T> vertex_attrib_vector; 
409
VertexAttributeVector<T> vertex_attrib_vector; 
413
FaceAttributeVector<T> face_ttrib_vector;
410
FaceAttributeVector<T> face_ttrib_vector;
414
HalfEdgeAttributeVector<T> halfedge_attrib_vector;
411
HalfEdgeAttributeVector<T> halfedge_attrib_vector;
415
\end{verbatim}
412
\end{verbatim}
416
where \texttt{T} is a typename. Attribute vectors are indexed with indices. Thus, a
413
where \texttt{T} is a typename. Attribute vectors are indexed with indices. Thus, a
417
\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:
414
\texttt{VertexAttributeVector} is indexed with a \texttt{VertexID} and likewise for the other types. 
418
\begin{verbatim}
415
\begin{verbatim}
-
 
416
VertexAttributeVector<Vec3d> my_attrib;
-
 
417
VertexID v; 
-
 
418
// assign some vertex ID to v
-
 
419
my_attrib[v] = Vec3d(1,2,3);
-
 
420
\end{verbatim}
419
void smooth(Manifold& m, float t)
421
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. What we do is to copy \textit{all} vertex positions to a new attribute vector. Then we compute a new position for each vertex storing it in the new attribute vector. Finally, we copy the positions back. Some complexity is due to the treatment of boundaries. Boundary vertices are not smoothed in this example. However, since we have copied the old vertex positions to the new attribute vector this means that boundary vertices are simply left where they are. The code looks as follows:
-
 
422
\begin{verbatim}    
-
 
423
void laplacian_smooth_example(Manifold& m)
420
    {
424
{
421
        VertexAttributeVector<Vec3f> pos(m.total_vertices());
425
    VertexAttributeVector<Vec3d> new_pos = 
-
 
426
        m.positions_attribute_vector();
422
        for(VertexIDIterator v = m.vertices_begin(); 
427
    for(VertexID v : m.vertices())
423
              v != m.vertices_end(); ++v)
428
        if(!boundary(m, v))
424
        {
429
        {
425
            if(!boundary(m, *v))
-
 
426
            {
-
 
427
          Vec3f avg_pos(0);
430
            Vec3d L(0);
428
          Walker w = m.walker(v)
-
 
429
            for(; !w.full_circle(); w = w.circulate_vertex_cw())
431
            int n = circulate_vertex_ccw(m,v,
430
                avg_pos += m.pos(w.vertex());
432
                [&](VertexID v){
431
                pos[*v] =  avg_pos / w.no_steps();
433
                    L += m.pos(v);
432
             }
434
            });
433
        }
-
 
434
        for(VertexIDIterator v = m.vertices_begin(); 
-
 
435
              v != m.vertices_end(); ++v){
-
 
436
            if(!boundary(m, *v))
-
 
437
                m.pos(*v) = pos[*v];
435
            new_pos[v] = L/n;
438
        }
436
        }
-
 
437
   m.positions_attribute_vector() = new_pos;
439
    }
438
}
440
\end{verbatim}
439
\end{verbatim}
441
 
-
 
442
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:
440
What if we were to write to a position in the attribute vector which did not contain a value? For instance, what happens if we add vertices to the mesh, somehow, and then assign attribute values to the added vertices. One would hope that the attribute vector is resized automatically, and that is the case, fortunately. 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:
443
\begin{verbatim}
441
\begin{verbatim}
444
VertexAttributeVector<T> vertex_attrib_vector; 
442
VertexAttributeVector<T> vertex_attrib_vector; 
445
Manifold m;
443
Manifold m;
446
// ....
444
// ....
447
 
445
 
Line 450... Line 448...
450
vertex_attrib_vector.cleanup(remap);
448
vertex_attrib_vector.cleanup(remap);
451
\end{verbatim}
449
\end{verbatim}
452
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.
450
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.
453
 
451
 
454
\subsection{Extended Example: Edge Flipping}
452
\subsection{Extended Example: Edge Flipping}
455
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
453
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. This is just a vector of 3D points:
456
\begin{verbatim}
454
\begin{verbatim}
457
  vector<Vec3f> vertices(3);
455
  vector<Vec3f> vertices(3);
458
  vertices[0] = p1;
456
  vertices[0] = p1;
459
  vertices[1] = p2;
457
  vertices[1] = p2;
460
  vertices[2] = p3;
458
  vertices[2] = p3;