public MeshResult FlipEdge(int eab, out EdgeFlipInfo flip) { flip = new EdgeFlipInfo(); if (!IsEdge(eab)) { return(MeshResult.Failed_NotAnEdge); } if (edge_is_boundary(eab)) { return(MeshResult.Failed_IsBoundaryEdge); } // find oriented edge [a,b], tris t0,t1, and other verts c in t0, d in t1 int eab_i = 4 * eab; int a = edges[eab_i], b = edges[eab_i + 1]; int t0 = edges[eab_i + 2], t1 = edges[eab_i + 3]; int[] T0tv = GetTriangle(t0).array; int[] T1tv = GetTriangle(t1).array; int c = IndexUtil.orient_tri_edge_and_find_other_vtx(ref a, ref b, T0tv); int d = IndexUtil.find_tri_other_vtx(a, b, T1tv); if (c == InvalidID || d == InvalidID) { return(MeshResult.Failed_BrokenTopology); } int flipped = find_edge(c, d); if (flipped != InvalidID) { return(MeshResult.Failed_FlippedEdgeExists); } // find edges bc, ca, ad, db int ebc = find_tri_neighbour_edge(t0, b, c); int eca = find_tri_neighbour_edge(t0, c, a); int ead = find_tri_neighbour_edge(t1, a, d); int edb = find_tri_neighbour_edge(t1, d, b); // update triangles set_triangle(t0, c, d, b); set_triangle(t1, d, c, a); // update edge AB, which becomes flipped edge CD set_edge_vertices(eab, c, d); set_edge_triangles(eab, t0, t1); int ecd = eab; // update the two other edges whose triangle nbrs have changed if (replace_edge_triangle(eca, t0, t1) == -1) { throw new ArgumentException("DMesh3.FlipEdge: first replace_edge_triangle failed"); } if (replace_edge_triangle(edb, t1, t0) == -1) { throw new ArgumentException("DMesh3.FlipEdge: second replace_edge_triangle failed"); } // update triangle nbr lists (these are edges) set_triangle_edges(t0, ecd, edb, ebc); set_triangle_edges(t1, ecd, eca, ead); // remove old eab from verts a and b, and decrement ref counts if (vertex_edges[a].Remove(eab) == false) { throw new ArgumentException("DMesh3.FlipEdge: first vertex_edges remove failed"); } if (vertex_edges[b].Remove(eab) == false) { throw new ArgumentException("DMesh3.FlipEdge: second vertex_edges remove failed"); } vertices_refcount.decrement(a); vertices_refcount.decrement(b); if (IsVertex(a) == false || IsVertex(b) == false) { throw new ArgumentException("DMesh3.FlipEdge: either a or b is not a vertex?"); } // add new edge ecd to verts c and d, and increment ref counts vertex_edges[c].Add(ecd); vertex_edges[d].Add(ecd); vertices_refcount.increment(c); vertices_refcount.increment(d); // success! collect up results flip.eID = eab; flip.v0 = a; flip.v1 = b; flip.ov0 = c; flip.ov1 = d; flip.t0 = t0; flip.t1 = t1; updateTimeStamp(true); return(MeshResult.Ok); }
public MeshResult SplitEdge(int eab, out EdgeSplitInfo split) { split = new EdgeSplitInfo(); if (!IsEdge(eab)) { return(MeshResult.Failed_NotAnEdge); } // look up primary edge & triangle int eab_i = 4 * eab; int a = edges[eab_i], b = edges[eab_i + 1]; int t0 = edges[eab_i + 2]; if (t0 == InvalidID) { return(MeshResult.Failed_BrokenTopology); } Index3i T0tv = GetTriangle(t0); int[] T0tv_array = T0tv.array; int c = IndexUtil.orient_tri_edge_and_find_other_vtx(ref a, ref b, T0tv_array); // create new vertex Vector3d vNew = 0.5 * (GetVertex(a) + GetVertex(b)); int f = AppendVertex(vNew); // quite a bit of code is duplicated between boundary and non-boundary case, but it // is too hard to follow later if we factor it out... if (edge_is_boundary(eab)) { // look up edge bc, which needs to be modified Index3i T0te = GetTriEdges(t0); int ebc = T0te[IndexUtil.find_edge_index_in_tri(b, c, T0tv_array)]; // rewrite existing triangle replace_tri_vertex(t0, b, f); // add new second triangle int t2 = add_triangle_only(f, b, c, InvalidID, InvalidID, InvalidID); if (triangle_groups != null) { triangle_groups.insert(triangle_groups[t0], t2); } // rewrite edge bc, create edge af replace_edge_triangle(ebc, t0, t2); int eaf = eab; replace_edge_vertex(eaf, b, f); vertex_edges[b].Remove(eab); vertex_edges[f].Add(eaf); // create new edges fb and fc int efb = add_edge(f, b, t2); int efc = add_edge(f, c, t0, t2); // update triangle edge-nbrs replace_triangle_edge(t0, ebc, efc); set_triangle_edges(t2, efb, ebc, efc); // update vertex refcounts vertices_refcount.increment(c); vertices_refcount.increment(f, 2); split.bIsBoundary = true; split.vNew = f; split.eNew = efb; updateTimeStamp(true); return(MeshResult.Ok); } else // interior triangle branch // look up other triangle { int t1 = edges[eab_i + 3]; Index3i T1tv = GetTriangle(t1); int[] T1tv_array = T1tv.array; int d = IndexUtil.find_tri_other_vtx(a, b, T1tv_array); // look up edges that we are going to need to update // [TODO OPT] could use ordering to reduce # of compares here Index3i T0te = GetTriEdges(t0); int ebc = T0te[IndexUtil.find_edge_index_in_tri(b, c, T0tv_array)]; Index3i T1te = GetTriEdges(t1); int edb = T1te[IndexUtil.find_edge_index_in_tri(d, b, T1tv_array)]; // rewrite existing triangles replace_tri_vertex(t0, b, f); replace_tri_vertex(t1, b, f); // add two new triangles to close holes we just created int t2 = add_triangle_only(f, b, c, InvalidID, InvalidID, InvalidID); int t3 = add_triangle_only(f, d, b, InvalidID, InvalidID, InvalidID); if (triangle_groups != null) { triangle_groups.insert(triangle_groups[t0], t2); triangle_groups.insert(triangle_groups[t1], t3); } // update the edges we found above, to point to new triangles replace_edge_triangle(ebc, t0, t2); replace_edge_triangle(edb, t1, t3); // edge eab became eaf int eaf = eab; //Edge * eAF = eAB; replace_edge_vertex(eaf, b, f); // update a/b/f vertex-edges vertex_edges[b].Remove(eab); vertex_edges[f].Add(eaf); // create new edges connected to f (also updates vertex-edges) int efb = add_edge(f, b, t2, t3); int efc = add_edge(f, c, t0, t2); int edf = add_edge(d, f, t1, t3); // update triangle edge-nbrs replace_triangle_edge(t0, ebc, efc); replace_triangle_edge(t1, edb, edf); set_triangle_edges(t2, efb, ebc, efc); set_triangle_edges(t3, edf, edb, efb); // update vertex refcounts vertices_refcount.increment(c); vertices_refcount.increment(d); vertices_refcount.increment(f, 4); split.bIsBoundary = false; split.vNew = f; split.eNew = efb; updateTimeStamp(true); return(MeshResult.Ok); } }