bool Network::deleteVertex(vertex_id vid) { if (!containsVertex(vid)) return false; std::set<vertex_id> in = getInNeighbors(vid); std::set<vertex_id> out = getOutNeighbors(vid); // removing adjacent edges for (std::set<vertex_id>::iterator it=in.begin(); it!=in.end(); it++) deleteEdge(*it,vid); for (std::set<vertex_id>::iterator it=out.begin(); it!=out.end(); it++) deleteEdge(vid,*it); // removing the vertex vertexes.erase(vid); if (isNamed()) { // some more structures to empty const std::string& vertex_name=vertex_id_to_name[vid]; vertex_id_to_name.erase(vid); vertex_name_to_id.erase(vertex_name); } // remove attribute values for (std::map<std::string,std::map<vertex_id,std::string> >::iterator it=vertex_string_attribute.begin(); it!=vertex_string_attribute.end(); it++) vertex_string_attribute[it->first].erase(vid); for (std::map<std::string,std::map<vertex_id,double> >::iterator it=vertex_numeric_attribute.begin(); it!=vertex_numeric_attribute.end(); it++) vertex_numeric_attribute[it->first].erase(vid); return true; }
void HMesh::deleteFace(Face* f, bool del) { if(f->startEdge_->pair == NULL || f->startEdge_->pair->face == NULL) { deleteEdge(f->startEdge_); } if(f->startEdge_->next->pair == NULL || f->startEdge_->next->pair->face == NULL) { deleteEdge(f->startEdge_->next); } if(f->startEdge_->next->next->pair == NULL || f->startEdge_->next->next->pair->face == NULL) { deleteEdge(f->startEdge_->next->next); } if(del) { auto it = find(faces_.begin(), faces_.end(), f); if(it != faces_.end()) { faces_.erase(it); } } }
int GraphState::normalizeSelf () { vector<pair<int, int> > removededges; selfdone = true; // temporarily change the situation to the original graph while ( deletededges.size () != 1 ) { removededges.push_back ( make_pair ( deletededges.back ().fromnode, deletededges.back ().posfromnode ) ); reinsertEdge (); } for ( int i = closetuples->size () - 1; i >= 0; i-- ) deleteEdge ( nodes[(*closetuples)[i].from-1].edges.back () ); int b = normalizetree (); // then change the situation back for ( int i = closetuples->size () - 1; i >= 0; i-- ) reinsertEdge (); while ( !removededges.empty () ) { deleteEdge ( nodes[removededges.back ().first].edges[removededges.back().second] ); removededges.pop_back (); } return b; }
void GMap1::deleteCycle(Dart d) { Dart e = phi1(d); while (e != d) { Dart f = phi1(e); deleteEdge(e); e = f; } deleteEdge(d); }
//void ConnectivityGraph::deleteEdge( VariableID vid, FactorID fid ) { void ConnectivityGraph::deleteEdge( VertexID vxid1, VertexID vxid2 ) { assert( vxid1 != vxid2 ); // std::cout << "deleting / decrementing edge (" << vid << ", " << fid << " / " << fxid << ")" << std::endl; ////#ifdef DEBUG //// assert( existingEdges[e->vxid][e->fxid][fid] ); //// assert( existingEdges[e->fxid][e->vxid][fid] ); //// existingEdges[e->vxid][e->fxid].reset( fid ); //// existingEdges[e->fxid][e->vxid].reset( fid ); ////#endif // DEBUG // // // if ( --e->count > 0 ) return; Vertex & u( vertices[vxid1] ); Vertex & v( vertices[vxid2] ); // find (and remove) the edge from the adjacency lists // EdgeIP ee = getFromAdjLists( u, v, e->level, e->isTree ); EdgeIP ee = getFromAdjLists( u, v ); if ( ee == NULL ) { std::cout << "Can't delete edge " << Edge( /*vid, fid,*/ vxid1, vxid2, -1 ) << " (not found) -- " << vxid1 << " / " << vxid2 << std::endl; assert( ee != NULL ); return; } assert( ee->isequal( vxid1, vxid2 ) /*&& *e == *ee*/ ); deleteEdge( ee ); }
// returns true if lower found, otherwise false int GraphState::enumerateSpanning () { if ( edgessize == (int) nodes.size () - 1 ) { // we have a tree if ( closecount == (int) closetuples->size () ) // in this case we have already considered this tree as a separate tree return 0; return normalizetree (); } else { unsigned int bit = 1 << ( deletededges.size () - 1 ); determineCycles ( bit ); for ( int i = 0; i < (int) nodes.size (); i++ ) { vector<GSEdge>& edges = nodes[i].edges; for ( int j = 0; j < (int) edges.size (); j++ ) { if ( ( edges[j].cyclemark & bit ) && edges[j].tonode > i && ( i < deletededges.back ().fromnode || ( i == deletededges.back ().fromnode && edges[j].tonode < deletededges.back ().tonode ) ) ) { deleteEdge ( edges[j] ); int b = enumerateSpanning (); reinsertEdge (); if ( b ) return b; } } } } return 0; }
int main(void) { int node_num, edge_num; double ans; struct Graph graph; while (scanf("%d %d", &node_num, &edge_num) != EOF) { initGraph(&graph, node_num); input(&graph, edge_num); printf("Boruvka:\n"); ans = boruvka(&graph); printf("the MST weigths %2.1f\n", ans); clearChoosedEdge(&graph); printf("kruskal:\n"); ans = kruskal(&graph); printf("the MST weights %.2lf\n", ans); clearChoosedEdge(&graph); printf("prim:\n"); ans = prim(&graph); printf("the MST weights %.2lf\n", ans); deleteEdge(&graph); } return 0; }
void NIXMLEdgesHandler::myStartElement(int element, const SUMOSAXAttributes& attrs) { switch (element) { case SUMO_TAG_EDGE: addEdge(attrs); break; case SUMO_TAG_LANE: addLane(attrs); break; case SUMO_TAG_NEIGH: myCurrentEdge->getLaneStruct((int)myCurrentEdge->getNumLanes() - 1).oppositeID = attrs.getString(SUMO_ATTR_LANE); break; case SUMO_TAG_SPLIT: addSplit(attrs); break; case SUMO_TAG_DELETE: deleteEdge(attrs); break; case SUMO_TAG_ROUNDABOUT: addRoundabout(attrs); break; default: break; } }
void GNENet::deleteLane(GNELane* lane, GNEUndoList* undoList) { GNEEdge* edge = &lane->getParentEdge(); if (edge->getNBEdge()->getNumLanes() == 1) { // remove the whole edge instead deleteEdge(edge, undoList); } else { undoList->p_begin("delete lane"); const NBEdge::Lane& laneAttrs = edge->getNBEdge()->getLaneStruct(lane->getIndex()); const bool sidewalk = laneAttrs.permissions == SVC_PEDESTRIAN; undoList->add(new GNEChange_Lane(edge, lane, laneAttrs, false), true); if (gSelected.isSelected(GLO_LANE, lane->getGlID())) { std::set<GUIGlID> deselected; deselected.insert(lane->getGlID()); undoList->add(new GNEChange_Selection(std::set<GUIGlID>(), deselected, true), true); } if (sidewalk) { edge->getSource()->removeFromCrossings(edge, undoList); edge->getDest()->removeFromCrossings(edge, undoList); edge->getSource()->setLogicValid(false, undoList); edge->getDest()->setLogicValid(false, undoList); } requireRecompute(); undoList->p_end(); } }
PolygonMesh<PointType>::~PolygonMesh(void) { /* Delete all faces and their associated half-edges: */ Face* fPtr=faces; while(fPtr!=0) { /* Delete all the face's half-edges: */ Edge* ePtr=fPtr->edge; do { Edge* next=ePtr->getFaceSucc(); deleteEdge(ePtr); ePtr=next; } while(ePtr!=fPtr->edge); /* Delete the face: */ Face* next=fPtr->succ; fPtr->~Face(); faceAllocator.free(fPtr); fPtr=next; } /* Delete all vertices: */ Vertex* vPtr=vertices; while(vPtr!=0) { Vertex* next=vPtr->succ; vPtr->~Vertex(); vertexAllocator.free(vPtr); vPtr=next; } }
int main(void) { int node_num, edge_num, source; struct Graph graph; time = 0; source = 1; while (scanf("%d %d", &node_num, &edge_num) != EOF) { initGraph(&graph, node_num); input(&graph, edge_num); printf("source node of dfs and bfs is %d:\n", source); printf("depth first search:\n"); for (source = 1; source <= graph.node_num; source++) dfs(&graph, source, visitNode); clearVisit(&graph); printf("breadth first search:\n"); for (source = 1; source <= graph.node_num; source++) bfs(&graph, source); clearVisit(&graph); printf("traverse by topological order:\n"); topos(&graph); deleteEdge(&graph); } return 0; }
void deleteEdge(Edge *thisEdge) { if (!(thisEdge == NULL)) { deleteEdge(thisEdge->edge); free(thisEdge); } }
void GNENet::reverseEdge(GNEEdge* edge, GNEUndoList* undoList) { undoList->p_begin("reverse edge"); deleteEdge(edge, undoList); // still exists. we delete it so we can reuse the name in case of resplit GNEEdge* reversed = createEdge(edge->getDest(), edge->getSource(), edge, undoList, edge->getID(), false, true); assert(reversed != 0); reversed->setAttribute(SUMO_ATTR_SHAPE, toString(edge->getNBEdge()->getInnerGeometry().reverse()), undoList); undoList->p_end(); }
void deleteVidEdges(Graph* graph, int vId) { Node* head = graph->array[vId].head; while(head != NULL) { Node* deleteNode = head; head = head->next; deleteEdge(graph, vId, deleteNode->d); } }
void ConnectivityGraph::disconnectVars( const VariablePtrVec & vars, const Factor * f ) { for ( auto vit = vars.rbegin(), vend = vars.rend(); vit != vend; ++vit ) { const Variable & v = **vit; if ( !v.isAssigned() ) { deleteEdge( vidToVertexID( v.getID() ), fidToVertexID( f->getID() ) ); } } }
void GNENet::replaceJunctionByGeometry(GNEJunction* junction, GNEUndoList* undoList) { undoList->p_begin("Replace junction by geometry"); assert(junction->getNBNode()->checkIsRemovable()); std::vector<std::pair<NBEdge*, NBEdge*> > toJoin = junction->getNBNode()->getEdgesToJoin(); for (std::vector<std::pair<NBEdge*, NBEdge*> >::iterator j = toJoin.begin(); j != toJoin.end(); j++) { GNEEdge* begin = myEdges[(*j).first->getID()]; GNEEdge* continuation = myEdges[(*j).second->getID()]; deleteEdge(begin, undoList); deleteEdge(continuation, undoList); GNEEdge* newEdge = createEdge(begin->getSource(), continuation->getDest(), begin, undoList, begin->getMicrosimID(), false, true); PositionVector newShape = begin->getNBEdge()->getInnerGeometry(); newShape.push_back(junction->getNBNode()->getPosition()); newShape.append(continuation->getNBEdge()->getInnerGeometry()); newEdge->setAttribute(SUMO_ATTR_SHAPE, toString(newShape), undoList); // @todo what about trafficlights at the end of oontinuation? } deleteJunction(junction, undoList); undoList->p_end(); }
static void deleteNodeEdges(gctx_t *gctx, Agraph_t *g, Agnode_t *n) { Agedge_t *e, *e1; e = agfstedge(g, n); while (e) { e1 = agnxtedge(g, e, n); deleteEdge(gctx, g, e); e = e1; } }
main() { int choice,u,origin,destin; while(1) { printf("1.Insert a Vertex\n"); printf("2.Insert an Edge\n"); printf("3.Delete a Vertex\n"); printf("4.Delete an Edge\n"); printf("5.Display\n"); printf("6.Exit\n"); printf("Enter your choice : "); scanf("%d",&choice); system("cls"); switch(choice) { case 1: printf("Enter a vertex to be inserted : "); scanf("%d",&u); insertVertex(u); break; case 2: printf("Enter an Edge to be inserted : "); scanf("%d %d",&origin,&destin); insertEdge(origin,destin); break; case 3: printf("Enter a vertex to be deleted : "); scanf("%d",&u); /*This function deletes all edges coming to this vertex*/ deleteIncomingEdges(u); /*This function deletes the vertex from the vertex list*/ deleteVertex(u); break; case 4: printf("Enter an edge to be deleted : "); scanf("%d %d",&origin,&destin); deleteEdge(origin,destin); break; case 5: display(); break; case 6: exit(1); default: printf("Wrong choice\n"); break; }/*End of switch*/ }/*End of while*/ }/*End of main()*/
GNEJunction* GNENet::splitEdge(GNEEdge* edge, const Position& pos, GNEUndoList* undoList, GNEJunction* newJunction) { undoList->p_begin("split edge"); deleteEdge(edge, undoList); // still exists. we delete it so we can reuse the name in case of resplit // compute geometry const PositionVector& oldGeom = edge->getNBEdge()->getGeometry(); const SUMOReal linePos = oldGeom.nearest_offset_to_point2D(pos, false); std::pair<PositionVector, PositionVector> newGeoms = oldGeom.splitAt(linePos); // figure out the new name int posBase = 0; std::string baseName = edge->getMicrosimID(); if (edge->wasSplit()) { size_t sep_index = baseName.rfind('.'); if (sep_index != std::string::npos) { // edge may have been renamed in between std::string posString = baseName.substr(sep_index + 1); try { posBase = TplConvert::_2int(posString.c_str()); baseName = baseName.substr(0, sep_index); // includes the . } catch (NumberFormatException) { } } } baseName += '.'; // create edges if (newJunction == 0) { newJunction = createJunction(pos, undoList); } GNEEdge* firstPart = createEdge(edge->getSource(), newJunction, edge, undoList, baseName + toString(posBase), true); GNEEdge* secondPart = createEdge(newJunction, edge->getDest(), edge, undoList, baseName + toString(posBase + (int)linePos), true); // fix geometry firstPart->setAttribute(GNE_ATTR_SHAPE_START, toString(newGeoms.first[0]), undoList); firstPart->setAttribute(GNE_ATTR_SHAPE_END, toString(newGeoms.first[-1]), undoList); newGeoms.first.pop_back(); newGeoms.first.erase(newGeoms.first.begin()); firstPart->setAttribute(SUMO_ATTR_SHAPE, toString(newGeoms.first), undoList); secondPart->setAttribute(GNE_ATTR_SHAPE_START, toString(newGeoms.second[0]), undoList); secondPart->setAttribute(GNE_ATTR_SHAPE_END, toString(newGeoms.second[-1]), undoList); newGeoms.second.pop_back(); newGeoms.second.erase(newGeoms.second.begin()); secondPart->setAttribute(SUMO_ATTR_SHAPE, toString(newGeoms.second), undoList); // fix connections std::vector<NBEdge::Connection>& connections = edge->getNBEdge()->getConnections(); for (std::vector<NBEdge::Connection>::iterator con_it = connections.begin(); con_it != connections.end(); con_it++) { undoList->add(new GNEChange_Connection( secondPart, con_it->fromLane, con_it->toEdge->getID(), con_it->toLane, false, true), true); } undoList->p_end(); return newJunction; }
bool Graph::deleteNode(int index){ Node *node = nodeList[index]; map<Node*, float>::iterator it; for(it = node->neighbors.begin();it!=node->neighbors.end();it++){ // delete the edge, which direct to this node if(!deleteEdge(it->first, node)){ return false; } } nodeList.erase(nodeList.begin() + index); delete node; return true; }
void GNENet::remapEdge(GNEEdge* oldEdge, GNEJunction* from, GNEJunction* to, GNEUndoList* undoList, bool keepEndpoints) { deleteEdge(oldEdge, undoList); // delete first so we can reuse the name, reference stays valid if (from != to) { GNEEdge* newEdge = createEdge(from, to, oldEdge, undoList, oldEdge->getMicrosimID(), false, true); newEdge->setAttribute(SUMO_ATTR_SHAPE, oldEdge->getAttribute(SUMO_ATTR_SHAPE), undoList); if (keepEndpoints) { newEdge->setAttribute(GNE_ATTR_SHAPE_START, oldEdge->getAttribute(GNE_ATTR_SHAPE_START), undoList); newEdge->setAttribute(GNE_ATTR_SHAPE_END, oldEdge->getAttribute(GNE_ATTR_SHAPE_END), undoList); } } // @todo remap connectivity as well }
//do cleanup correctly in case code integrated later so no memory leaks. void deleteGraph(Node *nodes) { for (int x = 0; x < nx; x++) { for (int y = 0; y < ny; y++) { for (int z = 0; z < nz; z++) { int index = calcIndexN(x,y,z); Edge *tempEdge = nodes[index].edge; deleteEdge(tempEdge); } } } free(nodes); }
Vertex* Voronoi::InsertPoint(const Vec2& p) { QuadEdge* e = LocateTriangleEdge(p); if (e == nullptr || p == e->Org()->p || p == e->Dest()->p) return nullptr; else if (VoronoiMath::Collinear(e, p)) { e = e->Oprev(); QuadEdge* et = e->Onext(); QuadEdge::Disconnect(et); deleteEdge(et->RootEdge()); } Vertex* v = createVertex(p); v->e = e; QuadEdge* e_begin = createEdge(); e_begin->SetEndPoints(e->Org(), v); QuadEdge* et = e_begin; QuadEdge::Splice(e_begin, e); do { QuadEdge* et2 = createEdge(); QuadEdge::Connect(et2, e, et->Sym()); et = et2; e = et->Oprev(); } while (e->Lnext() != e_begin); do { et = e->Oprev(); if (VoronoiMath::OnRight(e, et->Dest()->p) && VoronoiMath::InCircle(e->Org()->p, et->Dest()->p, e->Dest()->p, p)) { QuadEdge::Flip(e); e = e->Oprev(); } else if (e->Onext() == e_begin) break; else e = e->Onext()->Lprev(); } while (true); return v; }
void NIXMLEdgesHandler::myStartElement(int element, const SUMOSAXAttributes& attrs) { switch (element) { case SUMO_TAG_EDGE: addEdge(attrs); break; case SUMO_TAG_LANE: addLane(attrs); break; case SUMO_TAG_SPLIT: addSplit(attrs); break; case SUMO_TAG_DELETE: deleteEdge(attrs); break; default: break; } }
void GNENet::deleteJunction(GNEJunction* junction, GNEUndoList* undoList) { // we have to delete all incident edges because they cannot exist without that junction // all deletions must be undone/redone together so we start a new command group // @todo if any of those edges are dead-ends should we remove their orphan junctions as well? undoList->p_begin("delete junction"); // deleting edges changes in the underlying EdgeVector so we have to make a copy const EdgeVector incident = junction->getNBNode()->getEdges(); for (EdgeVector::const_iterator it = incident.begin(); it != incident.end(); it++) { deleteEdge(myEdges[(*it)->getID()], undoList); } // remove any traffic lights from the traffic light container (avoids lots of warnings) junction->setAttribute(SUMO_ATTR_TYPE, toString(NODETYPE_PRIORITY), undoList); undoList->add(new GNEChange_Junction(this, junction, false), true); if (gSelected.isSelected(GLO_JUNCTION, junction->getGlID())) { std::set<GUIGlID> deselected; deselected.insert(junction->getGlID()); undoList->add(new GNEChange_Selection(std::set<GUIGlID>(), deselected, true), true); } undoList->p_end(); }
void ConnectivityGraph::onVariableAssigned( const Variable * v ) { // for each factor f that v is in and is not assigned // deleteEdge( v, f ) // std::cout << "var " << v->getID() << " assigned (CG)" << std::endl; #ifdef DEBUG assert( !assignedVars[v->getID()] ); assignedVars.set( v->getID() ); #endif // DEBUG // note: we do assign/unassign in reverse order of each other, so we don't // get an inefficient chaining of edge replacements when all we really want // is a disconnect for ( auto fit = v->getFactors().begin(), fend = v->getFactors().end(); fit != fend; ++fit ) { const Factor * f = *fit; if ( f->isAssigned() ) continue; if ( !f->containsVar( v->getID() ) ) continue; // std::cout << "delete edge v " << v->getID() << " to f " << f->getID() << std::endl; deleteEdge( vidToVertexID( v->getID() ), fidToVertexID( f->getID() ) ); } }
void GNENet::deleteGeometryOrEdge(GNEEdge* edge, const Position& pos, GNEUndoList* undoList) { if (!edge->deleteGeometry(pos, undoList)) { deleteEdge(edge, undoList); } }
bool Network::deleteEdge(const std::string& vertex_name1, const std::string& vertex_name2) { if (!isNamed()) throw OperationNotSupportedException("Cannot reference a named vertex in an unnamed network"); if (!containsEdge(vertex_name1,vertex_name2)) return false; return deleteEdge(vertex_name_to_id.at(vertex_name1), vertex_name_to_id.at(vertex_name2)); }
void HMesh::collapseEdge(Edge* edgy) { Vertex* v1 = edgy->start; Vertex* v2 = edgy->end; if(v1 == v2) return; *v1 = (*v1 + *v2) * 0.5; edgy->start = v1; if (edgy->face) { if(edgy->next->next->pair != NULL) { edgy->next->next->pair->pair = edgy->next->pair; if(edgy->next->pair != NULL) { edgy->next->pair->pair = edgy->next->next->pair; Edge* e1 = edgy->next->next; Edge* e2 = edgy->next; //delete old edges deleteEdge(e1, false); deleteEdge(e2, false); } } } if(edgy->pair != NULL) { if (edgy->pair->face) { if(edgy->pair->next->next->pair != NULL) { edgy->pair->next->next->pair->pair = edgy->pair->next->pair; if(edgy->pair->next->pair != NULL) { edgy->pair->next->pair->pair = edgy->pair->next->next->pair; //delete old edges Edge* e1 = edgy->pair->next->next; Edge* e2 = edgy->pair->next; deleteEdge(e1, false); deleteEdge(e2, false); } } } // Now really delete faces if(edgy->pair->face) { deleteFace(edgy->pair->face); edgy->pair = 0; } } if(edgy->face) { deleteFace(edgy->face); edgy->face = 0; } deleteEdge(edgy); auto it =v2->out_edges.begin(); while(it !=v2->out_edges.end()) { (*it)->start = v1; v1->out_edges.push_back(*it); it++; } auto it2 = v2->in_edges.begin(); while(it2 != v2->in_edges.end()) { (*it2)->end = v1; v1->in_edges.push_back(*it2); it2++; } //v2->out_edges.clear(); //v2->in_edges.clear(); }
VertexIter HalfedgeMesh::collapseEdge( EdgeIter e ) { // TODO This method should collapse the given edge and return an iterator to the new vertex created by the collapse. //1. collect elements EdgeIter e4 = e; //Halfedges HalfedgeIter h1 = e4->halfedge(); HalfedgeIter h5 = h1->twin(); //Faces FaceIter f0 = h1->face(); FaceIter f1 = h5->face(); //Early Exit #1: Ignore requests to collapse boundary edges if(f0->isBoundary() || f1->isBoundary()) return verticesEnd(); //Halfedges, cont' HalfedgeIter h2 = h1->next(); HalfedgeIter h0 = h2->next(); HalfedgeIter h3 = h5->next(); HalfedgeIter h4 = h3->next(); HalfedgeIter h7 = h0->twin(); HalfedgeIter h12 = h3->twin(); HalfedgeIter h20 = h2->twin(); HalfedgeIter h15 = h4->twin(); //Edges EdgeIter e0 = h0->edge(); EdgeIter e1 = h3->edge(); EdgeIter e2 = h4->edge(); EdgeIter e3 = h2->edge(); //EdgeIter e4 //Faces //Vertices VertexIter v0 = h0->vertex(); VertexIter v1 = h3->vertex(); VertexIter v2 = h4->vertex(); VertexIter v3 = h2->vertex(); //Early Exit #2: The number of the joint neighbor vertices of the two merging vertices //must be EXACTLY TWO std::vector<VertexIter> v1_neighbors; std::vector<VertexIter> v3_neighbors; HalfedgeIter h = h3; do { h = h->twin(); if(h->vertex() != v1) v1_neighbors.push_back(h->vertex()); h = h->next(); } while(h != h3); h = h2; do { h = h->twin(); if(h->vertex() != v3) v3_neighbors.push_back(h->vertex()); h = h->next(); } while(h != h2); std::sort(v1_neighbors.begin(), v1_neighbors.end()); std::sort(v3_neighbors.begin(), v3_neighbors.end()); std::vector<VertexIter> joint_neighbors; std::set_intersection(v1_neighbors.begin(), v1_neighbors.end(), v3_neighbors.begin(), v3_neighbors.end(), std::back_inserter(joint_neighbors)); if(joint_neighbors.size() != 2) return verticesEnd(); //Early Exit #3: mesh must have more than 4 vertices if neither v1 nor v3 is boundary vertex, //and more than 3 vertices if either v1 or v3 is boundary vertex if(!v1->isBoundary() && !v3->isBoundary() && nVertices() <= 4) return verticesEnd(); if((v1->isBoundary() || v3->isBoundary()) && nVertices() <= 3) return verticesEnd(); //Early Exit #4: v1, v3 cannot be both boundary vertex if(v1->isBoundary() && v3->isBoundary()) return verticesEnd(); //Early Exit #5: boundary vertex needs at least one triangle //By convention, Vertex::degree() returns the face degree if(v0->isBoundary() && v0->degree() <= 1) return verticesEnd(); if(v1->isBoundary() && v1->degree() <= 1) return verticesEnd(); if(v2->isBoundary() && v2->degree() <= 1) return verticesEnd(); if(v3->isBoundary() && v3->degree() <= 1) return verticesEnd(); //Early Exit #6: degenerated case: v0/v1/v2/v3 are duplicated if(v0 == v1 || v0 == v2 || v0 == v3 || v1 == v2 || v1 == v3 || v2 == v3) return verticesEnd(); VertexIter output = verticesEnd(); if(v3->isBoundary()) { std::vector<HalfedgeIter> v1_out; HalfedgeIter h = v1->halfedge(); do { v1_out.push_back(h); h = h->next()->next()->twin(); } while(h != v1->halfedge()); //2. reassign elements //Halfedges h7->twin() = h20; h7->edge() = e3; h20->twin() = h7; h12->twin() = h15; h12->edge() = e2; h15->twin() = h12; for(auto h = v1_out.begin(); h!= v1_out.end(); ++h) (*h)->vertex() = v3; //Vertices v0->halfedge() = h20; v3->halfedge() = h15; v3->position = 0.5f * (v1->position + v3->position); v2->halfedge() = h12; //Edges e3->halfedge() = h20; e2->halfedge() = h15; //Faces //3. delete elements //Halfedges deleteHalfedge(h0); deleteHalfedge(h1); deleteHalfedge(h2); deleteHalfedge(h3); deleteHalfedge(h4); deleteHalfedge(h5); //Vertices deleteVertex(v1); //Edges deleteEdge(e0); deleteEdge(e1); deleteEdge(e4); //Faces deleteFace(f0); deleteFace(f1); output = v3; } else { std::vector<HalfedgeIter> v3_out; HalfedgeIter h = v3->halfedge(); do { v3_out.push_back(h); h = h->next()->next()->twin(); } while(h != v3->halfedge()); //2. reassign elements //Halfedges h7->twin() = h20; h20->twin() = h7; h20->edge() = e0; h12->twin() = h15; h15->twin() = h12; h15->edge() = e1; for(auto h = v3_out.begin(); h!= v3_out.end(); ++h) (*h)->vertex() = v1; //Vertices v0->halfedge() = h20; v1->halfedge() = h15; v1->position = 0.5f * (v1->position + v3->position); v2->halfedge() = h12; //Edges e0->halfedge() = h20; e1->halfedge() = h15; //Faces //3. delete elements //Halfedges deleteHalfedge(h0); deleteHalfedge(h1); deleteHalfedge(h2); deleteHalfedge(h3); deleteHalfedge(h4); deleteHalfedge(h5); //Vertices deleteVertex(v3); //Edges deleteEdge(e2); deleteEdge(e3); deleteEdge(e4); //Faces deleteFace(f0); deleteFace(f1); output = v1; } return output; }