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;
|