Subversion Repositories gelsvn

Rev

Rev 635 | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 635 Rev 636
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. Below an example with 4D double precision vector and matrix:
180
Multiplication is also supported for matrix vector products:
181
\begin{verbatim}
181
\begin{verbatim}
182
  Vec4d x(1,1,0,1);
182
  Vec4d p0(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 y = m * x;
186
  Vec4d p1 = m * p0;
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 348... Line 348...
348
\subsection{Walker}
348
\subsection{Walker}
349
To loop over all vertices is one way of traversing the mesh. It ensures that we visit all vertices, but it does not relate to the connectivity of the mesh. 
349
To loop over all vertices is one way of traversing the mesh. It ensures that we visit all vertices, but it does not relate to the connectivity of the mesh. 
350
To traverse the mesh in a way that respects connectivity, we use the \texttt{Walker} class. A \texttt{Walker} always points to a specific halfedge, but unlike a \texttt{HalfEdgeID}, it can be used to move from edge to edge. For instance, to compute the centroid for a given face, we can use the following code:
350
To traverse the mesh in a way that respects connectivity, we use the \texttt{Walker} class. A \texttt{Walker} always points to a specific halfedge, but unlike a \texttt{HalfEdgeID}, it can be used to move from edge to edge. For instance, to compute the centroid for a given face, we can use the following code:
351
\begin{verbatim}
351
\begin{verbatim}
352
Vec3d p(0);
352
Vec3d p(0);
353
FaceID f = *m.faces_begin();
353
FaceID f = m.faces();
-
 
354
Walker w = m.walker(f);
354
for(Walker w = m.walker(f); !w.full_circle(); w = w.next())
355
for(; !w.full_circle(); w = w.next())
355
  p += m.pos(w.vertex()); 
356
  p += m.pos(w.vertex()); 
356
p /= w.no_steps();
357
p /= w.no_steps();
357
\end{verbatim}
358
\end{verbatim}
358
The code above computes the centroid for the first face in the mesh. It does so by jumping from edge to edge until it has come full circle. For each jump, we add the vertex pointed to by the halfedge to \texttt{p}. The benefit of the \texttt{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}:
359
The code above computes the centroid for the first face in the mesh. It does so by jumping from edge to edge until it has come full circle. For each jump, we add the vertex pointed to by the halfedge to \texttt{p}. The benefit of the \texttt{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}:
359
\begin{verbatim}
360
\begin{verbatim}
Line 366... Line 367...
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
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
 
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
369
\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
369
\begin{verbatim}
370
\begin{verbatim}
370
Vec3d p(0);
371
Vec3d p(0);
371
VertexID v = *m.vertices_begin();
372
VertexID v = m.vertices();
372
for(Walker w = m.walker(v);!w.full_circle(); 
373
Walker w = m.walker(v)
373
     w = w.circulate_vertex_ccw()){
374
for(;!w.full_circle(); w = w.circulate_vertex_ccw()){
374
  p += m.pos(w.vertex()); 
375
  p += m.pos(w.vertex()); 
375
p /= w.no_steps();
376
p /= w.no_steps();
376
\end{verbatim}
377
\end{verbatim}
377
 
378
 
378
Again, 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, a step of vertex circulation is considered atomic - even though \texttt{w.circulate\_vertex\_ccw()} is the same as  \texttt{w.prev().opp()}.
379
Again, 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, a step of vertex circulation is considered atomic - even though \texttt{w.circulate\_vertex\_ccw()} is the same as  \texttt{w.prev().opp()}.
379
 
380
 
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}. There is one more option for circulation. The following code does precisely the same as the code above, i.e. it computes the average of the neighboring vertices.
381
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}. There is one more option for circulation. The following code does precisely the same as the code above, i.e. it computes the average of the neighboring vertices.
381
\begin{verbatim}
382
\begin{verbatim}
382
        Vec3d p(0);
383
Vec3d p(0);
383
        int n = circulate_vertex_ccw(m, v, 
384
int n = circulate_vertex_ccw(m, v, 
384
                   [&](VertexID v){ p += m.pos(v); });
385
          [&](VertexID v){ p += m.pos(v); });
385
        return p / n;
386
return p / n;
386
\end{verbatim}
387
\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.
388
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
 
389
 
389
To sum up, there are two datatypes that we use to refer to mesh entitites.
390
To summarize there are three datatypes that we use to refer to mesh entitites.
390
\begin{itemize}
391
\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. 
392
\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. 
-
 
393
\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. 
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
\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.
393
\end{itemize}
395
\end{itemize}
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
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.
-
 
397
 
-
 
398
We could have combined two or all three of these concepts, but would have led to rather bloated datatypes.
395
 
399
 
396
\subsection{Attributes}
400
\subsection{Attributes}
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
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:
398
\begin{verbatim}
402
\begin{verbatim}
399
Vec3d p;
403
Vec3d p;
Line 404... Line 408...
404
 
408
 
405
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.
409
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.
406
 
410
 
407
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:
411
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:
408
\begin{verbatim}
412
\begin{verbatim}
409
VertexAttributeVector<T> vertex_attrib_vector; 
413
VertexAttributeVector<T>   vertex_attrib_vector; 
410
FaceAttributeVector<T> face_ttrib_vector;
414
FaceAttributeVector<T>     face_ttrib_vector;
411
HalfEdgeAttributeVector<T> halfedge_attrib_vector;
415
HalfEdgeAttributeVector<T> halfedge_attrib_vector;
412
\end{verbatim}
416
\end{verbatim}
413
where \texttt{T} is a typename. Attribute vectors are indexed with indices. Thus, a
417
where \texttt{T} is a typename. Attribute vectors are indexed with indices. Thus, a
414
\texttt{VertexAttributeVector} is indexed with a \texttt{VertexID} and likewise for the other types. 
418
\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:
415
\begin{verbatim}
419
\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}
-
 
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:
420
void smooth(Manifold& m, float t)
422
\begin{verbatim}    
-
 
423
void laplacian_smooth_example(Manifold& m)
-
 
424
{
421
{
425
    VertexAttributeVector<Vec3d> new_pos = 
422
  VertexAttributeVector<Vec3f> pos(m.total_vertices());
426
        m.positions_attribute_vector();
-
 
427
    for(VertexID v : m.vertices())
423
  for(VertexID v : m.vertices())
-
 
424
  { 
428
        if(!boundary(m, v))
425
    if(!boundary(m, v))
429
        {
426
    {
430
            Vec3d L(0);
427
      Vec3f avg_pos(0);
-
 
428
      Walker w = m.walker(v)
431
            int n = circulate_vertex_ccw(m,v,
429
      for(; !w.full_circle(); w = w.circulate_vertex_cw())
432
                [&](VertexID v){
430
        avg_pos += m.pos(w.vertex());
433
                    L += m.pos(v);
431
      pos[v] =  avg_pos / w.no_steps();
434
            });
432
    }
-
 
433
  }
-
 
434
  
435
            new_pos[v] = L/n;
435
  for(VertexID v : m.vertices())
436
        }
436
  {
-
 
437
    if(!boundary(m, v))
437
   m.positions_attribute_vector() = new_pos;
438
      m.pos(v) = pos[v];
-
 
439
  }
438
}
440
}
439
\end{verbatim}
441
\end{verbatim}
-
 
442
 
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
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:
441
\begin{verbatim}
444
\begin{verbatim}
442
VertexAttributeVector<T> vertex_attrib_vector; 
445
VertexAttributeVector<T> vertex_attrib_vector; 
443
Manifold m;
446
Manifold m;
444
// ....
447
// ....
445
 
448
 
Line 448... Line 451...
448
vertex_attrib_vector.cleanup(remap);
451
vertex_attrib_vector.cleanup(remap);
449
\end{verbatim}
452
\end{verbatim}
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
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.
451
 
454
 
452
\subsection{Extended Example: Edge Flipping}
455
\subsection{Extended Example: Edge Flipping}
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
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
454
\begin{verbatim}
457
\begin{verbatim}
455
  vector<Vec3f> vertices(3);
458
  vector<Vec3f> vertices(3);
456
  vertices[0] = p1;
459
  vertices[0] = p1;
457
  vertices[1] = p2;
460
  vertices[1] = p2;
458
  vertices[2] = p3;
461
  vertices[2] = p3;
Line 475... Line 478...
475
   &faces[0], &indices[0]);
478
   &faces[0], &indices[0]);
476
\end{verbatim}
479
\end{verbatim}
477
The result of the above is a mesh with a single triangle.
480
The result of the above is a mesh with a single triangle.
478
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.
481
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.
479
\begin{verbatim}
482
\begin{verbatim}
480
HalfEdgeIDIterator h = m.halfedges_begin();
483
HalfEdgeID h = m.halfedge();
481
m.split_edge(*h); 
484
m.split_edge(h); 
482
triangulate_face_by_edge_split(m, m.walker(*h).face());
485
triangulate_face_by_edge_split(m, m.walker(h).face());
483
\end{verbatim}
486
\end{verbatim}
484
Now, we obtain an iterator to the first of our (two) triangles.
487
Now, we obtain an iterator to the first of our (two) triangles.
485
\begin{verbatim}
488
\begin{verbatim}
486
FaceIDIterator f1 =m.faces_begin();
489
FaceID f1 = m.faces();
487
\end{verbatim}
490
\end{verbatim}
488
We create a vertex, \texttt{v}, at centre of \texttt{f1} and insert it in that face:
491
We create a vertex, \texttt{v}, at centre of \texttt{f1} and insert it in that face:
489
\begin{verbatim}
492
\begin{verbatim}
490
m.split_face_by_vertex(*f1);
493
m.split_face_by_vertex(f1);
491
\end{verbatim}
494
\end{verbatim}
492
The code below, marks one of a pair of halfedges (with the value 1).
495
The code below, marks one of a pair of halfedges (with the value 1).
493
\begin{verbatim}
496
\begin{verbatim}
494
HalfEdgeAttributeVector<int> touched;
497
HalfEdgeAttributeVector<int> touched;
495
 
498
 
496
// ....
499
// ....
497
 
500
 
498
for(HalfEdgeIDIterator h = m.halfedges_begin(); 
501
for(HalfEdgeID h : m.halfedges())
499
   h!=m.halfedges_end(); ++h)
-
 
500
    {
502
{
501
        if(m.walker(*h).opp().halfedge() < *h)
503
  if(m.walker(h).opp().halfedge() < h)
502
            touched[*h] =0;
504
    touched[h] =0;
503
        else
505
  else
504
            touched[*h] =1;
506
    touched[h] =1;
505
    }
507
}
506
\end{verbatim}
508
\end{verbatim}
507
Next, we set the \texttt{flipper} variable to point to the first of these halfedges:
509
Next, we set the \texttt{flipper} variable to point to the first of these halfedges:
508
\begin{verbatim}
510
\begin{verbatim}
509
flipper = m.halfedges_begin();
511
flipper = m.halfedges_begin();
510
\end{verbatim}
512
\end{verbatim}