@@ -31,7 +33,7 @@ Also note that we provide code to gather the halfedges contained in the beveled
...
@@ -31,7 +33,7 @@ Also note that we provide code to gather the halfedges contained in the beveled
The reason for storing `new_halfedges` and `start_positions` in an array is that it makes it easy to access positions "to the left" and "to the right" of a given vertex. For instance, suppose we want to figure out the offset from the corner of a polygon. We might want to compute some geometric quantity involving the three vertex positions `start_positions[i-1]`, `start_positions[i]`, and `start_positions[i+1]` (as well as `inset`), then set the new vertex position `new_halfedges[i]->vertex()->pos` to this new value:
The reason for storing `new_halfedges` and `start_positions` in an array is that it makes it easy to access positions "to the left" and "to the right" of a given vertex. For instance, suppose we want to figure out the offset from the corner of a polygon. We might want to compute some geometric quantity involving the three vertex positions `start_positions[i-1]`, `start_positions[i]`, and `start_positions[i+1]` (as well as `inset`), then set the new vertex position `new_halfedges[i]->vertex()->pos` to this new value:
![BevelIndexing](bevel_indexing.png)
<center><imgsrc="bevel_diagram.png"></center>
A useful trick here is _modular arithmetic_: since we really have a "loop" of vertices, we want to make sure that indexing the next element (+1) and the previous element (-1) properly "wraps around." This can be achieved via code like
A useful trick here is _modular arithmetic_: since we really have a "loop" of vertices, we want to make sure that indexing the next element (+1) and the previous element (-1) properly "wraps around." This can be achieved via code like
@@ -12,15 +15,15 @@ Here we provide a step-by-step guide to implementing a simplified version of the
...
@@ -12,15 +15,15 @@ Here we provide a step-by-step guide to implementing a simplified version of the
We now consider the case of a triangle-triangle edge flip.
We now consider the case of a triangle-triangle edge flip.
#### PHASE 0: Draw a Diagram
### PHASE 0: Draw a Diagram
Suppose we have a pair of triangles (a,b,c) and (c,b,d). After flipping the edge (b,c), we should now have triangles (a,d,c) and (a,b,d). A good first step for implementing any local mesh operation is to draw a diagram that clearly labels all elements affected by the operation:
Suppose we have a pair of triangles (a,b,c) and (c,b,d). After flipping the edge (b,c), we should now have triangles (a,d,c) and (a,b,d). A good first step for implementing any local mesh operation is to draw a diagram that clearly labels all elements affected by the operation:
![](edge_flip_before_after.png)
<center><imgsrc="edge_flip_diagram.png"></center>
Here we have drawn a diagram of the region around the edge both before and after the edge operation (in this case, "flip"), labeling each type of element (halfedge, vertex, edge, and face) from zero to the number of elements. It is important to include every element affected by the operation, thinking very carefully about which elements will be affected. If elements are omitted during this phase, everything will break---even if the code written in the two phases is correct! In this example, for instance, we need to remember to include the halfedges "outside" the neighborhood, since their "twin" pointers will be affected.
Here we have drawn a diagram of the region around the edge both before and after the edge operation (in this case, "flip"), labeling each type of element (halfedge, vertex, edge, and face) from zero to the number of elements. It is important to include every element affected by the operation, thinking very carefully about which elements will be affected. If elements are omitted during this phase, everything will break---even if the code written in the two phases is correct! In this example, for instance, we need to remember to include the halfedges "outside" the neighborhood, since their "twin" pointers will be affected.
#### PHASE I: Collect elements
### PHASE I: Collect elements
Once you've drawn your diagram, simply collect all the elements from the "before" picture. Give them the same names as in your diagram, so that you can debug your code by comparing with the picture.
Once you've drawn your diagram, simply collect all the elements from the "before" picture. Give them the same names as in your diagram, so that you can debug your code by comparing with the picture.
...
@@ -50,7 +53,7 @@ Once you've drawn your diagram, simply collect all the elements from the "before
...
@@ -50,7 +53,7 @@ Once you've drawn your diagram, simply collect all the elements from the "before
FaceRef f0 = h0->face();
FaceRef f0 = h0->face();
// ...you fill in the rest!...
// ...you fill in the rest!...
#### PHASE II: Allocate new elements
### PHASE II: Allocate new elements
If your edge operation requires new elements, now is the time to allocate them. For the edge flip, we don't need any new elements; but suppose that for some reason we needed a new vertex v4\. At this point we would allocate the new vertex via
If your edge operation requires new elements, now is the time to allocate them. For the edge flip, we don't need any new elements; but suppose that for some reason we needed a new vertex v4\. At this point we would allocate the new vertex via
...
@@ -58,7 +61,7 @@ If your edge operation requires new elements, now is the time to allocate them.
...
@@ -58,7 +61,7 @@ If your edge operation requires new elements, now is the time to allocate them.
(The name used for this new vertex should correspond to the label you give it in your "after" picture.) Likewise, new edges, halfedges, and faces can be allocated via the methods `mesh.new_edge()`, `mesh.new_halfedge()`, and `mesh.new_face()`.
(The name used for this new vertex should correspond to the label you give it in your "after" picture.) Likewise, new edges, halfedges, and faces can be allocated via the methods `mesh.new_edge()`, `mesh.new_halfedge()`, and `mesh.new_face()`.
#### PHASE III: Reassign Elements
### PHASE III: Reassign Elements
Next, update the pointers for all the mesh elements that are affected by the edge operation. Be exhaustive! In other words, go ahead and specify every pointer for every element, even if it did not change. Once things are working correctly, you can always optimize by removing unnecessary assignments. But get it working correctly first! Correctness is more important than efficiency.
Next, update the pointers for all the mesh elements that are affected by the edge operation. Be exhaustive! In other words, go ahead and specify every pointer for every element, even if it did not change. Once things are working correctly, you can always optimize by removing unnecessary assignments. But get it working correctly first! Correctness is more important than efficiency.
...
@@ -94,7 +97,7 @@ Next, update the pointers for all the mesh elements that are affected by the edg
...
@@ -94,7 +97,7 @@ Next, update the pointers for all the mesh elements that are affected by the edg
// FACES
// FACES
f0->halfedge() = h0; //...you fill in the rest!...
f0->halfedge() = h0; //...you fill in the rest!...
#### PHASE IV: Delete unused elements
### PHASE IV: Delete unused elements
If your edge operation eliminates elements, now is the best time to deallocate them: at this point, you can be sure that they are no longer needed. For instance, since we do not need the vertex allocated in PHASE II, we could write
If your edge operation eliminates elements, now is the best time to deallocate them: at this point, you can be sure that they are no longer needed. For instance, since we do not need the vertex allocated in PHASE II, we could write
...
@@ -102,7 +105,7 @@ If your edge operation eliminates elements, now is the best time to deallocate t
...
@@ -102,7 +105,7 @@ If your edge operation eliminates elements, now is the best time to deallocate t
You should be careful that this mesh element is not referenced by any other element in the mesh. But if your "before" and "after" diagrams are correct, that should not be an issue!
You should be careful that this mesh element is not referenced by any other element in the mesh. But if your "before" and "after" diagrams are correct, that should not be an issue!
#### Design considerations
### Design considerations
The basic algorithm outlined above will handle most edge flips, but you should also think carefully about possible corner-cases. You should also think about other design issues, like "how much should this operation cost?" For instance, for this simple triangle-triangle edge flip it might be reasonable to:
The basic algorithm outlined above will handle most edge flips, but you should also think carefully about possible corner-cases. You should also think about other design issues, like "how much should this operation cost?" For instance, for this simple triangle-triangle edge flip it might be reasonable to: