bool Surface_mesh:: is_collapse_ok(Halfedge v0v1) { Halfedge v1v0(opposite_halfedge(v0v1)); Vertex v0(to_vertex(v1v0)); Vertex v1(to_vertex(v0v1)); Vertex vv, vl, vr; Halfedge h1, h2; // the edges v1-vl and vl-v0 must not be both boundary edges if (!is_boundary(v0v1)) { vl = to_vertex(next_halfedge(v0v1)); h1 = next_halfedge(v0v1); h2 = next_halfedge(h1); if (is_boundary(opposite_halfedge(h1)) && is_boundary(opposite_halfedge(h2))) return false; } // the edges v0-vr and vr-v1 must not be both boundary edges if (!is_boundary(v1v0)) { vr = to_vertex(next_halfedge(v1v0)); h1 = next_halfedge(v1v0); h2 = next_halfedge(h1); if (is_boundary(opposite_halfedge(h1)) && is_boundary(opposite_halfedge(h2))) return false; } // if vl and vr are equal or both invalid -> fail if (vl == vr) return false; // edge between two boundary vertices should be a boundary edge if ( is_boundary(v0) && is_boundary(v1) && !is_boundary(v0v1) && !is_boundary(v1v0)) return false; // test intersection of the one-rings of v0 and v1 Vertex_around_vertex_circulator vv_it, vv_end; vv_it = vv_end = vertices(v0); do { vv = vv_it; if (vv != v1 && vv != vl && vv != vr) if (find_halfedge(vv, v1).is_valid()) return false; } while (++vv_it != vv_end); // passed all tests return true; }
void Surface_mesh:: flip(Edge e) { // CAUTION : Flipping a halfedge may result in // a non-manifold mesh, hence check for yourself // whether this operation is allowed or not! //let's make it sure it is actually checked assert(is_flip_ok(e)); Halfedge a0 = halfedge(e, 0); Halfedge b0 = halfedge(e, 1); Halfedge a1 = next_halfedge(a0); Halfedge a2 = next_halfedge(a1); Halfedge b1 = next_halfedge(b0); Halfedge b2 = next_halfedge(b1); Vertex va0 = to_vertex(a0); Vertex va1 = to_vertex(a1); Vertex vb0 = to_vertex(b0); Vertex vb1 = to_vertex(b1); Face fa = face(a0); Face fb = face(b0); set_vertex(a0, va1); set_vertex(b0, vb1); set_next_halfedge(a0, a2); set_next_halfedge(a2, b1); set_next_halfedge(b1, a0); set_next_halfedge(b0, b2); set_next_halfedge(b2, a1); set_next_halfedge(a1, b0); set_face(a1, fb); set_face(b1, fa); set_halfedge(fa, a0); set_halfedge(fb, b0); if (halfedge(va0) == b0) set_halfedge(va0, a1); if (halfedge(vb0) == a0) set_halfedge(vb0, b1); }
void Surface_mesh:: split(Face f, Vertex v) { /* Split an arbitrary face into triangles by connecting each vertex of fh to vh. - fh will remain valid (it will become one of the triangles) - the halfedge handles of the new triangles will point to the old halfeges */ Halfedge hend = halfedge(f); Halfedge h = next_halfedge(hend); Halfedge hold = new_edge(to_vertex(hend), v); set_next_halfedge(hend, hold); set_face(hold, f); hold = opposite_halfedge(hold); while (h != hend) { Halfedge hnext = next_halfedge(h); Face fnew = new_face(); set_halfedge(fnew, h); Halfedge hnew = new_edge(to_vertex(h), v); set_next_halfedge(hnew, hold); set_next_halfedge(hold, h); set_next_halfedge(h, hnew); set_face(hnew, fnew); set_face(hold, fnew); set_face(h, fnew); hold = opposite_halfedge(hnew); h = hnext; } set_next_halfedge(hold, hend); set_next_halfedge(next_halfedge(hend), hold); set_face(hold, f); set_halfedge(v, hold); }
void Surface_mesh:: remove_loop(Halfedge h) { Halfedge h0 = h; Halfedge h1 = next_halfedge(h0); Halfedge o0 = opposite_halfedge(h0); Halfedge o1 = opposite_halfedge(h1); Vertex v0 = to_vertex(h0); Vertex v1 = to_vertex(h1); Face fh = face(h0); Face fo = face(o0); // is it a loop ? assert ((next_halfedge(h1) == h0) && (h1 != o0)); // halfedge -> halfedge set_next_halfedge(h1, next_halfedge(o0)); set_next_halfedge(prev_halfedge(o0), h1); // halfedge -> face set_face(h1, fo); // vertex -> halfedge set_halfedge(v0, h1); adjust_outgoing_halfedge(v0); set_halfedge(v1, o1); adjust_outgoing_halfedge(v1); // face -> halfedge if (fo.is_valid() && halfedge(fo) == o0) set_halfedge(fo, h1); // delete stuff if (!edeleted_) edeleted_ = edge_property<bool>("e:deleted", false); if (!fdeleted_) fdeleted_ = face_property<bool>("f:deleted", false); if (fh.is_valid()) { fdeleted_[fh] = true; ++deleted_faces_; } edeleted_[edge(h0)] = true; ++deleted_edges_; garbage_ = true; }
void Surface_mesh:: triangulate(Face f) { /* Split an arbitrary face into triangles by connecting each vertex of fh after its second to vh. - fh will remain valid (it will become one of the triangles) - the halfedge handles of the new triangles will point to the old halfedges */ Halfedge base_h = halfedge(f); Vertex start_v = from_vertex(base_h); Halfedge next_h = next_halfedge(base_h); while (to_vertex(next_halfedge(next_h)) != start_v) { Halfedge next_next_h(next_halfedge(next_h)); Face new_f = new_face(); set_halfedge(new_f, base_h); Halfedge new_h = new_edge(to_vertex(next_h), start_v); set_next_halfedge(base_h, next_h); set_next_halfedge(next_h, new_h); set_next_halfedge(new_h, base_h); set_face(base_h, new_f); set_face(next_h, new_f); set_face(new_h, new_f); base_h = opposite_halfedge(new_h); next_h = next_next_h; } set_halfedge(f, base_h); //the last face takes the handle _fh set_next_halfedge(base_h, next_h); set_next_halfedge(next_halfedge(next_h), base_h); set_face(base_h, f); }
Surface_mesh::Normal Surface_mesh:: compute_face_normal(Face f) const { Halfedge h = halfedge(f); Halfedge hend = h; Point p0 = vpoint_[to_vertex(h)]; h = next_halfedge(h); Point p1 = vpoint_[to_vertex(h)]; h = next_halfedge(h); Point p2 = vpoint_[to_vertex(h)]; if (next_halfedge(h) == hend) // face is a triangle { p2-=p1; p0-=p1; return p2.cross(p0).normalized(); } else // face is a general polygon { Normal n(0,0,0); hend = h; do { n += (p2-p1).cross(p0-p1); h = next_halfedge(h); p0 = p1; p1 = p2; p2 = vpoint_[to_vertex(h)]; } while (h != hend); return n.normalized(); } }
bool Surface_mesh:: is_flip_ok(Edge e) const { // boundary edges cannot be flipped if (is_boundary(e)) return false; // check if the flipped edge is already present in the mesh Halfedge h0 = halfedge(e, 0); Halfedge h1 = halfedge(e, 1); Vertex v0 = to_vertex(next_halfedge(h0)); Vertex v1 = to_vertex(next_halfedge(h1)); if (v0 == v1) // this is generally a bad sign !!! return false; if (find_halfedge(v0, v1).is_valid()) return false; return true; }
Surface_mesh::Normal Surface_mesh:: compute_vertex_normal(Vertex v) const { Point nn(0,0,0); Halfedge h = halfedge(v); if (h.is_valid()) { const Halfedge hend = h; const Point p0 = vpoint_[v]; Point n, p1, p2; Scalar cosine, angle; do { if (!is_boundary(h)) { p1 = vpoint_[to_vertex(h)]; p1 -= p0; p1.normalize(); p2 = vpoint_[from_vertex(prev_halfedge(h))]; p2 -= p0; p2.normalize(); cosine = p1.dot(p2) / sqrt(p1.dot(p1)*p2.dot(p2)); if (cosine < -1.0) cosine = -1.0; else if (cosine > 1.0) cosine = 1.0; angle = acos(cosine); n = p1.cross(p2).normalized(); n *= angle; nn += n; } h = cw_rotated_halfedge(h); } while (h != hend); nn.normalize(); } return nn; }
Surface_mesh::Halfedge Surface_mesh:: find_halfedge(Vertex start, Vertex end) const { assert(is_valid(start) && is_valid(end)); Halfedge h = halfedge(start); const Halfedge hh = h; if (h.is_valid()) { do { if (to_vertex(h) == end) return h; h = cw_rotated_halfedge(h); } while (h != hh); } return Halfedge(); }
void Surface_mesh:: split(Edge e, Vertex v) { Halfedge h0 = halfedge(e, 0); Halfedge o0 = halfedge(e, 1); Vertex v2 = to_vertex(o0); Halfedge e1 = new_edge(v, v2); Halfedge t1 = opposite_halfedge(e1); Face f0 = face(h0); Face f3 = face(o0); set_halfedge(v, h0); set_vertex(o0, v); if (!is_boundary(h0)) { Halfedge h1 = next_halfedge(h0); Halfedge h2 = next_halfedge(h1); Vertex v1 = to_vertex(h1); Halfedge e0 = new_edge(v, v1); Halfedge t0 = opposite_halfedge(e0); Face f1 = new_face(); set_halfedge(f0, h0); set_halfedge(f1, h2); set_face(h1, f0); set_face(t0, f0); set_face(h0, f0); set_face(h2, f1); set_face(t1, f1); set_face(e0, f1); set_next_halfedge(h0, h1); set_next_halfedge(h1, t0); set_next_halfedge(t0, h0); set_next_halfedge(e0, h2); set_next_halfedge(h2, t1); set_next_halfedge(t1, e0); } else { set_next_halfedge(prev_halfedge(h0), t1); set_next_halfedge(t1, h0); // halfedge handle of _vh already is h0 } if (!is_boundary(o0)) { Halfedge o1 = next_halfedge(o0); Halfedge o2 = next_halfedge(o1); Vertex v3 = to_vertex(o1); Halfedge e2 = new_edge(v, v3); Halfedge t2 = opposite_halfedge(e2); Face f2 = new_face(); set_halfedge(f2, o1); set_halfedge(f3, o0); set_face(o1, f2); set_face(t2, f2); set_face(e1, f2); set_face(o2, f3); set_face(o0, f3); set_face(e2, f3); set_next_halfedge(e1, o1); set_next_halfedge(o1, t2); set_next_halfedge(t2, e1); set_next_halfedge(o0, e2); set_next_halfedge(e2, o2); set_next_halfedge(o2, o0); } else { set_next_halfedge(e1, next_halfedge(o0)); set_next_halfedge(o0, e1); set_halfedge(v, e1); } if (halfedge(v2) == h0) set_halfedge(v2, t1); }
void Surface_mesh:: garbage_collection() { if (!garbage_) return; int i, i0, i1, nV(vertices_size()), nE(edges_size()), nH(halfedges_size()), nF(faces_size()); Vertex v; Halfedge h; Face f; if (!vdeleted_) vdeleted_ = vertex_property<bool>("v:deleted", false); if (!edeleted_) edeleted_ = edge_property<bool>("e:deleted", false); if (!fdeleted_) fdeleted_ = face_property<bool>("f:deleted", false); // setup handle mapping Vertex_property<Vertex> vmap = add_vertex_property<Vertex>("v:garbage-collection"); Halfedge_property<Halfedge> hmap = add_halfedge_property<Halfedge>("h:garbage-collection"); Face_property<Face> fmap = add_face_property<Face>("f:garbage-collection"); for (i=0; i<nV; ++i) vmap[Vertex(i)] = Vertex(i); for (i=0; i<nH; ++i) hmap[Halfedge(i)] = Halfedge(i); for (i=0; i<nF; ++i) fmap[Face(i)] = Face(i); // remove deleted vertices if (nV > 0) { i0=0; i1=nV-1; while (1) { // find first deleted and last un-deleted while (!vdeleted_[Vertex(i0)] && i0 < i1) ++i0; while ( vdeleted_[Vertex(i1)] && i0 < i1) --i1; if (i0 >= i1) break; // swap vprops_.swap(i0, i1); //add for(unsigned int j = 0;j<map_2skel.size();j++) { if(map_2skel[j] == i0) map_2skel[j] = i1; else if(map_2skel[j] == i1) map_2skel[j] = i0; } //end }; // remember new size nV = vdeleted_[Vertex(i0)] ? i0 : i0+1; } // remove deleted edges if (nE > 0) { i0=0; i1=nE-1; while (1) { // find first deleted and last un-deleted while (!edeleted_[Edge(i0)] && i0 < i1) ++i0; while ( edeleted_[Edge(i1)] && i0 < i1) --i1; if (i0 >= i1) break; // swap eprops_.swap(i0, i1); hprops_.swap(2*i0, 2*i1); hprops_.swap(2*i0+1, 2*i1+1); }; // remember new size nE = edeleted_[Edge(i0)] ? i0 : i0+1; nH = 2*nE; } // remove deleted faces if (nF > 0) { i0=0; i1=nF-1; while (1) { // find 1st deleted and last un-deleted while (!fdeleted_[Face(i0)] && i0 < i1) ++i0; while ( fdeleted_[Face(i1)] && i0 < i1) --i1; if (i0 >= i1) break; // swap fprops_.swap(i0, i1); }; // remember new size nF = fdeleted_[Face(i0)] ? i0 : i0+1; } // update vertex connectivity for (i=0; i<nV; ++i) { v = Vertex(i); if (!is_isolated(v)) set_halfedge(v, hmap[halfedge(v)]); } // update halfedge connectivity for (i=0; i<nH; ++i) { h = Halfedge(i); set_vertex(h, vmap[to_vertex(h)]); set_next_halfedge(h, hmap[next_halfedge(h)]); if (!is_boundary(h)) set_face(h, fmap[face(h)]); } // update handles of faces for (i=0; i<nF; ++i) { f = Face(i); set_halfedge(f, hmap[halfedge(f)]); } // remove handle maps remove_vertex_property(vmap); remove_halfedge_property(hmap); remove_face_property(fmap); // finally resize arrays vprops_.resize(nV); vprops_.free_memory(); hprops_.resize(nH); hprops_.free_memory(); eprops_.resize(nE); eprops_.free_memory(); fprops_.resize(nF); fprops_.free_memory(); deleted_vertices_ = deleted_edges_ = deleted_faces_ = 0; garbage_ = false; }
void Surface_mesh:: remove_edge(Halfedge h) { Halfedge hn = next_halfedge(h); Halfedge hp = prev_halfedge(h); Halfedge o = opposite_halfedge(h); Halfedge on = next_halfedge(o); Halfedge op = prev_halfedge(o); Face fh = face(h); Face fo = face(o); Vertex vh = to_vertex(h); Vertex vo = to_vertex(o); // halfedge -> vertex Halfedge_around_vertex_circulator vh_it, vh_end; vh_it = vh_end = halfedges(vo); do { set_vertex(opposite_halfedge(vh_it), vh); } while (++vh_it != vh_end); // halfedge -> halfedge set_next_halfedge(hp, hn); set_next_halfedge(op, on); // face -> halfedge if (fh.is_valid()) set_halfedge(fh, hn); if (fo.is_valid()) set_halfedge(fo, on); // vertex -> halfedge if (halfedge(vh) == o) set_halfedge(vh, hn); adjust_outgoing_halfedge(vh); set_halfedge(vo, Halfedge()); // delete stuff if (!vdeleted_) vdeleted_ = vertex_property<bool>("v:deleted", false); if (!edeleted_) edeleted_ = edge_property<bool>("e:deleted", false); vdeleted_[vo] = true; ++deleted_vertices_; edeleted_[edge(h)] = true; ++deleted_edges_; garbage_ = true; //add for(unsigned int j = 0;j < map_2skel.size();j++) { if(map_2skel[j] == vo.idx()) { //unsigned int tem = map_2skel[j]; map_2skel[j] = vh.idx(); //qDebug("vertex:[%d],change %d to %d",j,tem,vh.idx()); } } //end }
void draw_it(const std::vector<std::vector<sf::Vertex>> & sims, float time, float height, std::string title) { //http://www.sfml-dev.org/tutorials/2.1/start-vc.php //nb -s for static libs const float edge = 30.0f; const float lineWidth = 5.0f; const float width = 500.0f; const float x_scale = width/time; const auto bagColour = sf::Color(180, 120, 60); sf::RenderWindow window(sf::VideoMode(static_cast<int>(width + 2*edge), static_cast<int>(height + 2*edge)), title); window.clear(sf::Color::Black); sf::RectangleShape left(sf::Vector2f(lineWidth, static_cast<float>(height))); left.setFillColor(bagColour); left.setPosition(edge, edge); window.draw(left); sf::RectangleShape right(sf::Vector2f(lineWidth, static_cast<float>(height))); right.setFillColor(bagColour); right.setPosition(edge + width, edge); window.draw(right); sf::RectangleShape base(sf::Vector2f(static_cast<float>(width) + lineWidth, lineWidth)); base.setFillColor(bagColour); base.setPosition(edge, edge + height); window.draw(base); assert(sims.begin()->size()); //TODO - and they are all the same size_t penultimate = sims.begin()->size() - 1; size_t last = 1; while (window.isOpen()) { // check all the window's events that were triggered since the last iteration of the loop sf::Event event; while (window.pollEvent(event)) { // "close requested" event: we close the window if (event.type == sf::Event::Closed) window.close(); break; } window.clear(); window.draw(left); window.draw(right); window.draw(base); last = std::min(++last, sims.begin()->size() - 1); for(const auto & points: sims) { bool out = false; for(size_t i=0; i < last; ++i) { out |= (points[i].position.y > height);//what about the edge? sf::Color colour = out ? sf::Color::Green: sf::Color::White; auto scaled_start = to_vertex(points[i], colour, edge + lineWidth, x_scale, height); auto scaled_point = to_vertex(points[i+1], colour, edge + lineWidth, x_scale, height); sf::Vertex line[] = {scaled_start, scaled_point}; window.draw(line, 2, sf::Lines); } } window.display(); std::this_thread::sleep_for(std::chrono::milliseconds(50));//set render rate... or whatever it's called } }