Line 320... |
Line 320... |
320 |
\begin{verbatim}
|
320 |
\begin{verbatim}
|
321 |
VertexID vid;
|
321 |
VertexID vid;
|
322 |
// ... obtain a vertex ID
|
322 |
// ... obtain a vertex ID
|
323 |
vec3d p = m.pos(vid);
|
323 |
vec3d p = m.pos(vid);
|
324 |
\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.
|
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
|
- |
|
326 |
\begin{verbatim}
|
- |
|
327 |
m.pos(vid) = p;
|
326 |
|
328 |
\end{verbatim}
|
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,
|
329 |
\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,
|
328 |
\begin{verbatim}
|
330 |
\begin{verbatim}
|
329 |
VertexID Manifold::split_edge(HalfEdgeID h);
|
331 |
VertexID Manifold::split_edge(HalfEdgeID h);
|
330 |
\end{verbatim}
|
332 |
\end{verbatim}
|
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
|
333 |
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
|
332 |
\begin{verbatim}
|
334 |
\begin{verbatim}
|
333 |
bool boundary(const Manifold& m, HalfEdgeID h);
|
335 |
bool boundary(const Manifold& m, HalfEdgeID h);
|
334 |
\end{verbatim}
|
336 |
\end{verbatim}
|
335 |
returns true if the halfedge identified by \texttt{h} is a boundary edge in \texttt{m}.
|
337 |
returns true if the halfedge identified by \texttt{h} is a boundary edge in \texttt{m}.
|
336 |
|
338 |
|
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}
|
339 |
A very frequent operation is that we need to iterate over all the vertices in a mesh. This is done as follows:
|
338 |
\begin{verbatim}
|
340 |
\begin{verbatim}
|
339 |
for(VertexIDIterator v = m.vertices_begin();
|
341 |
for(VertexID v : m.vertices())
|
340 |
v != m.vertices_end(); ++v)
|
- |
|
341 |
{
|
342 |
{
|
342 |
Vec3d p = mani.pos(*v);
|
343 |
Vec3d p = m.pos(v);
|
343 |
// Do something
|
344 |
// Do something with the position
|
344 |
}
|
345 |
}
|
345 |
\end{verbatim}
|
346 |
\end{verbatim}
|
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 |
Since we also have ID types for faces and half edges, similar code could have been used to iterate over these entities. As a note: there are also specific iterator classes (e.g. \texttt{VertexIDIterator}) which can be used to iterate with old fashioned for loops. However, the syntax is far more cumbersome, so we suggest you stick with the range based for loops as shown above.
|
347 |
|
- |
|
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 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}
|
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 |
\begin{verbatim}
|
351 |
\begin{verbatim}
|
351 |
Vec3d p(0);
|
352 |
Vec3d p(0);
|
352 |
FaceIDIterator f = m.faces_begin();
|
353 |
FaceID f = *m.faces_begin();
|
353 |
Walker w = m.walker(*f);
|
- |
|
354 |
for(; !w.full_circle(); w = w.next()){
|
354 |
for(Walker w = m.walker(f); !w.full_circle(); w = w.next())
|
355 |
p += m.pos(w.vertex());
|
355 |
p += m.pos(w.vertex());
|
356 |
p /= w.no_steps();
|
356 |
p /= w.no_steps();
|
357 |
\end{verbatim}
|
357 |
\end{verbatim}
|
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}:
|
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 |
\begin{verbatim}
|
359 |
\begin{verbatim}
|
360 |
Walker w;
|
360 |
Walker w;
|
361 |
w = w.next();
|
361 |
w = w.next();
|
362 |
w = w.prev();
|
362 |
w = w.prev();
|
363 |
w = w.opp();
|
363 |
w = w.opp();
|
Line 366... |
Line 366... |
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.
|
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 |
|
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
|
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 |
\begin{verbatim}
|
369 |
\begin{verbatim}
|
370 |
Vec3d p(0);
|
370 |
Vec3d p(0);
|
371 |
VertexIDIterator v = m.vertices_begin();
|
371 |
VertexID v = *m.vertices_begin();
|
372 |
Walker w = m.walker(*v);
|
372 |
for(Walker w = m.walker(v);!w.full_circle();
|
373 |
for(; !w.full_circle(); w = w.circulate_vertex_ccw()){
|
373 |
w = w.circulate_vertex_ccw()){
|
374 |
p += m.pos(w.vertex());
|
374 |
p += m.pos(w.vertex());
|
375 |
p /= w.no_steps();
|
375 |
p /= w.no_steps();
|
376 |
\end{verbatim}
|
376 |
\end{verbatim}
|
377 |
|
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()}.
|
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 |
|
379 |
|
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}.
|
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 |
\begin{verbatim}
|
- |
|
382 |
Vec3d p(0);
|
- |
|
383 |
int n = circulate_vertex_ccw(m, v,
|
- |
|
384 |
[&](VertexID v){ p += m.pos(v); });
|
- |
|
385 |
return p / n;
|
- |
|
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.
|
381 |
|
388 |
|
382 |
To summarize there are three datatypes that we use to refer to mesh entitites.
|
389 |
To summarize there are three datatypes that we use to refer to mesh entitites.
|
383 |
\begin{itemize}
|
390 |
\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.
|
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.
|
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.
|
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.
|