From c015a687bc1271e30de37aef914095949a3a62b6 Mon Sep 17 00:00:00 2001
From: TheNumbat <mjslater@andrew.cmu.edu>
Date: Sun, 17 Oct 2021 03:38:10 -0400
Subject: [PATCH] add vert/edge/face accessibility check

---
 src/geometry/halfedge.cpp | 59 +++++++++++++++++++++++++++------------
 1 file changed, 41 insertions(+), 18 deletions(-)

diff --git a/src/geometry/halfedge.cpp b/src/geometry/halfedge.cpp
index 401b254..79e890f 100644
--- a/src/geometry/halfedge.cpp
+++ b/src/geometry/halfedge.cpp
@@ -375,6 +375,9 @@ std::optional<std::pair<Halfedge_Mesh::ElementRef, std::string>> Halfedge_Mesh::
         if(!finite) return {{v, "A vertex position was set to a non-finite value."}};
     }
 
+    std::unordered_map<VertexRef, std::set<HalfedgeRef>> v_accessible;
+    std::unordered_map<EdgeRef, std::set<HalfedgeRef>> e_accessible;
+    std::unordered_map<FaceRef, std::set<HalfedgeRef>> f_accessible;
     std::set<HalfedgeRef> permutation;
 
     // Check valid halfedge permutation
@@ -406,24 +409,6 @@ std::optional<std::pair<Halfedge_Mesh::ElementRef, std::string>> Halfedge_Mesh::
         }
     }
 
-    for(HalfedgeRef h = halfedges_begin(); h != halfedges_end(); h++) {
-
-        if(herased.find(h) != herased.end()) continue;
-
-        // Check whether each halfedge was pointed to by a halfedge
-        if(permutation.find(h) == permutation.end()) {
-            return {{h, "A halfedge is the next of zero halfedges!"}};
-        }
-
-        // Check twin relationships
-        if(h->twin() == h) {
-            return {{h, "A halfedge's twin is itself!"}};
-        }
-        if(h->twin()->twin() != h) {
-            return {{h, "A halfedge's twin's twin is not itself!"}};
-        }
-    }
-
     // Check whether each halfedge incident on a vertex points to that vertex
     for(VertexRef v = vertices_begin(); v != vertices_end(); v++) {
 
@@ -434,12 +419,15 @@ std::optional<std::pair<Halfedge_Mesh::ElementRef, std::string>> Halfedge_Mesh::
             return {{v, "A vertex's halfedge is erased!"}};
         }
 
+        std::set<HalfedgeRef> accessible;
         do {
+            accessible.insert(h);
             if(h->vertex() != v) {
                 return {{h, "A vertex's halfedge does not point to that vertex!"}};
             }
             h = h->twin()->next();
         } while(h != v->halfedge());
+        v_accessible[v] = std::move(accessible);
     }
 
     // Check whether each halfedge incident on an edge points to that edge
@@ -452,12 +440,15 @@ std::optional<std::pair<Halfedge_Mesh::ElementRef, std::string>> Halfedge_Mesh::
             return {{e, "An edge's halfedge is erased!"}};
         }
 
+        std::set<HalfedgeRef> accessible;
         do {
+            accessible.insert(h);
             if(h->edge() != e) {
                 return {{h, "An edge's halfedge does not point to that edge!"}};
             }
             h = h->twin();
         } while(h != e->halfedge());
+        e_accessible[e] = std::move(accessible);
     }
 
     // Check whether each halfedge incident on a face points to that face
@@ -470,12 +461,44 @@ std::optional<std::pair<Halfedge_Mesh::ElementRef, std::string>> Halfedge_Mesh::
             return {{f, "A face's halfedge is erased!"}};
         }
 
+        std::set<HalfedgeRef> accessible;
         do {
+            accessible.insert(h);
             if(h->face() != f) {
                 return {{h, "A face's halfedge does not point to that face!"}};
             }
             h = h->next();
         } while(h != f->halfedge());
+        f_accessible[f] = std::move(accessible);
+    }
+
+    for(HalfedgeRef h = halfedges_begin(); h != halfedges_end(); h++) {
+
+        if(herased.find(h) != herased.end()) continue;
+
+        // Check whether each halfedge was pointed to by a halfedge
+        if(permutation.find(h) == permutation.end()) {
+            return {{h, "A halfedge is the next of zero halfedges!"}};
+        }
+
+        // Check twin relationships
+        if(h->twin() == h) {
+            return {{h, "A halfedge's twin is itself!"}};
+        }
+        if(h->twin()->twin() != h) {
+            return {{h, "A halfedge's twin's twin is not itself!"}};
+        }
+
+        // Check that the halfedge can be found via its vertex, edge, and face
+        if(v_accessible[h->vertex()].count(h) == 0) {
+            return {{h, "A halfedge is not accessible from its vertex!"}};
+        }
+        if(e_accessible[h->edge()].count(h) == 0) {
+            return {{h, "A halfedge is not accessible from its edge!"}};
+        }
+        if(f_accessible[h->face()].count(h) == 0) {
+            return {{h, "A halfedge is not accessible from its face!"}};
+        }
     }
 
     do_erase();
-- 
GitLab