// // s is a spoke pointing OUT from x // void Subdivision::optimize(Vec2& x, Edge *s) { Edge *start_spoke = s; Edge *spoke = s; do { Edge *e = spoke->Lnext(); Edge *t = e->Oprev(); if( isInterior(e) && shouldSwap(x, e) ) swap(e); else { spoke = spoke->Onext(); if( spoke == start_spoke ) break; } } while( true ); // // Now, update all the triangles spoke = start_spoke; do { Edge *e = spoke->Lnext(); Triangle *t = e->Lface(); if( t ) t->update(*this); spoke = spoke->Onext(); } while( spoke != start_spoke ); }
Edge * splitFace(Face *fl, Vertex *v1, Vertex *v2) { Face *fr = new Face(); //cout << " split vertices: " << v1->p << "-" << v2->p << endl; Edge *a = v1->getEdge(); Edge *b = v2->getEdge(); Edge *c = Edge::makeEdge(v1, v2, fl, fr); while (a->Left() != fl) { a = a->Onext(); } while (b->Left() != fl) { b = b->Onext(); } Edge::splice(a, c); Edge::splice(b, c->Sym()); Edge *cIter = c->Lnext(); while (cIter != c) { cIter->setLeft(fl); cIter = cIter->Lnext(); } cIter = c->Rnext(); while (cIter != c) { cIter->setRight(fr); cIter = cIter->Rnext(); } return c; }
void Edge::splice(Edge *a, Edge *b) { Edge *temp; Edge *alpha = a->Onext()->Rot(); Edge *beta = b->Onext()->Rot(); temp = a->Onext(); a->next = b->Onext(); b->next = temp; temp = alpha->Onext(); alpha->next = beta->Onext(); beta->next = temp; }
void splice(Edge *a, Edge *b) { Edge *alpha = a->Onext()->Rot(); Edge *beta = b->Onext()->Rot(); Edge *t1 = b->Onext(); Edge *t2 = a->Onext(); Edge *t3 = beta->Onext(); Edge *t4 = alpha->Onext(); a->next = t1; b->next = t2; alpha->next = t3; beta->next = t4; }
int getVertexOrder(Edge *e, vector<Point>& pts) { int count = 1; Edge *iter = e->Onext(); if (iter == NULL) { cout << "Erro: ponteiro next == NULL\n"; return -1; } pts.clear(); pts.push_back(e->Sym()->Orig()->p); while (iter != e && count < 100) { count++; iter = iter->Onext(); pts.push_back(iter->Sym()->Orig()->p); } if (count == 100) { cout << "Erro: loop infinito\n"; return -1; } return count; }
void Edge::splice(Edge *a, Edge *b) { assert(a != 0); assert(b != 0); // see Guibas and Stolfi Edge* alpha = a->Onext()->Rot(); Edge* beta = b->Onext()->Rot(); Edge* t1 = b->Onext(); Edge* t2 = a->Onext(); Edge* t3 = beta->Onext(); Edge* t4 = alpha->Onext(); a->next = t1; b->next = t2; alpha->next = t3; beta->next = t4; }
void Subdivision::InsertSite(const Point2d& x) // Inserts a new point into a subdivision representing a Delaunay // triangulation, and fixes the affected edges so that the result // is still a Delaunay triangulation. This is based on the // pseudocode from Guibas and Stolfi (1985) p.120, with slight // modifications and a bug fix. { Edge* e = Locate(x); if ((x == e->Org2d()) || (x == e->Dest2d())) // point is already in return; else if (OnEdge(x, e)) { e = e->Oprev(); DeleteEdge(e->Onext()); } // Connect the new point to the vertices of the containing // triangle (or quadrilateral, if the new point fell on an // existing edge.) Edge* base = MakeEdge(); base->EndPoints(e->Org(), new Point2d(x)); Splice(base, e); startingEdge = base; do { base = Connect(e, base->Sym()); e = base->Oprev(); } while (e->Lnext() != startingEdge); // Examine suspect edges to ensure that the Delaunay condition // is satisfied. do { Edge* t = e->Oprev(); if (RightOf(t->Dest2d(), e) && InCircle(e->Org2d(), t->Dest2d(), e->Dest2d(), x)) { Swap(e); e = e->Oprev(); } else if (e->Onext() == startingEdge) // no more suspect edges return; else // pop a suspect edge e = e->Onext()->Lprev(); } while (TRUE); }
Edge* Subdivision::Locate(const Point2d& x) // Returns an edge e, s.t. either x is on e, or e is an edge of // a triangle containing x. The search starts from startingEdge // and proceeds in the general direction of x. Based on the // pseudocode in Guibas and Stolfi (1985) p.121. { Edge* e = startingEdge; while (TRUE) { if (x == e->Org2d() || x == e->Dest2d()) return e; else if (RightOf(x, e)) e = e->Sym(); else if (!RightOf(x, e->Onext())) e = e->Onext(); else if (!RightOf(x, e->Dprev())) e = e->Dprev(); else return e; } }
Edge *Subdivision::locate(const Vec2& x, Edge *start) { Edge *e = start; double t = triArea(x, e->Dest(), e->Org()); if (t>0) { // x is to the right of edge e t = -t; e = e->Sym(); } while (true) { Edge *eo = e->Onext(); Edge *ed = e->Dprev(); double to = triArea(x, eo->Dest(), eo->Org()); double td = triArea(x, ed->Dest(), ed->Org()); if (td>0) // x is below ed if (to>0 || to==0 && t==0) {// x is interior, or origin endpoint startingEdge = e; return e; } else { // x is below ed, below eo t = to; e = eo; } else // x is on or above ed if (to>0) // x is above eo if (td==0 && t==0) { // x is destination endpoint startingEdge = e; return e; } else { // x is on or above ed and above eo t = td; e = ed; } else // x is on or below eo if (t==0 && !leftOf(eo->Dest(), e)) // x on e but subdiv. is to right e = e->Sym(); else if (rand()&1) { // x is on or above ed and t = to; // on or below eo; step randomly e = eo; } else { t = td; e = ed; } } }
void Cell::setOrbitOrg(Edge *edge, Vertex *org) { assert(edge != 0); assert(org != 0); // traverse the Onext orbit of _edge_, setting the origin of each edge to // _org_ Edge *scan = edge; do { scan->setOrg(org); scan = scan->Onext(); } while (scan != edge); }
Edge *getVerticesEdge(Vertex *v1, Vertex *v2) { if (v1 == NULL || v2 == NULL) return NULL; Edge *e = v1->getEdge(); while (e->Dest() != v2) { e = e->Onext(); if (e == v1->getEdge()) { e = NULL; break; } } return e; }
void Splice(Edge* a, Edge* b) // This operator affects the two edge rings around the origins of a and b, // and, independently, the two edge rings around the left faces of a and b. // In each case, (i) if the two rings are distinct, Splice will combine // them into one; (ii) if the two are the same ring, Splice will break it // into two separate pieces. // Thus, Splice can be used both to attach the two edges together, and // to break them apart. See Guibas and Stolfi (1985) p.96 for more details // and illustrations. { Edge* alpha = a->Onext()->Rot(); Edge* beta = b->Onext()->Rot(); Edge* t1 = b->Onext(); Edge* t2 = a->Onext(); Edge* t3 = beta->Onext(); Edge* t4 = alpha->Onext(); a->next = t1; b->next = t2; alpha->next = t3; beta->next = t4; }
Edge *Cell::getOrbitLeft(Edge *edge, Face *left) { assert(edge != 0); assert(left != 0); // traverse the Onext orbit of _edge_ looking for an edge whose left face is // _left Edge *scan = edge; do { if (scan->Left() == left) { return scan; } scan = scan->Onext(); } while (scan != edge); return 0; }
int getVertexOrder(Edge *e) { int count = 1; Edge *iter = e->Onext(); if (iter == NULL) { cout << "Erro: ponteiro next == NULL\n"; return -1; } while (iter != e && count < 100) { count++; iter = iter->Onext(); } if (count == 100) { cout << "Erro: loop infinito\n"; return -1; } return count; }
int main() { using cgl::Point2d; using cgl::Edge; using cgl::make_edge; // Point2d *a = new Point2d(0.0, 0.0); // 0 // Point2d *b = new Point2d(1.0, 0.0); // 1 // Point2d *c = new Point2d(1.0, 1.0); // 2 // Point2d *d = new Point2d(0.0, 1.0); // 3 Edge *ea = make_edge(0, 1); Edge *eb = make_edge(ea->Dest(), 2); Edge *ec = make_edge(eb->Dest(), 3); Edge *ed = make_edge(ec->Dest(), 0); Edge *ee = make_edge(eb->Dest(), ea->Org()); // Connect eb to ea->Dest() splice(ea->Sym(), eb); // Connect ec to eb->Dest() splice(eb->Sym(), ec); // Connect ed to ec->Sym() and ea splice(ec->Sym(), ed); splice(ed->Sym(), ea); // Connect ee to ec and ea -- this is equivalent to Delaunay::connect splice(ee, eb->Lnext()); splice(ee->Sym(), ea); // Traverse the convex hull if (ea->Dnext() != eb->Sym()) { std::cerr << "Error: ea->Dnext() != eb->Sym()" << std::endl; return 1; } if (eb->Dnext() != ec->Sym()) { std::cerr << "Error: eb->Dnext() != ec->Sym()" << std::endl; return 1; } if (ec->Dnext() != ed->Sym()) { std::cerr << "Error: ec->Dnext() != ed->Sym()" << std::endl; return 1; } if (ed->Dprev() != ee) { std::cerr << "Error: ed->Dprev() != ee" << std::endl; return 1; } // Cross linkage -- test algebra // Rot / invRot if (ee->Rot()->Org() != ed->invRot()->Org()) { std::cerr << "Error: ee->Rot()->Org() != ed->invRot()->Org()" << std::endl; return 1; } // Sym if (ee->Sym()->Org() != 0) { std::cerr << "Error: ee->Sym()->Org() != a" << std::endl; return 1; } // Onext if (ee->Onext() != eb->Sym()) { std::cerr << "Error: ee->Onext() != eb->Sym()" << std::endl; return 1; } // Oprev if (ee->Oprev() != ec) { std::cerr << "Error: ee->Oprev() != ec" << std::endl; return 1; } // Dnext if (ee->Dnext() != ed) { std::cerr << "Error: ee->Dnext() != ed" << std::endl; return 1; } // Dprev if (ee->Dprev() != ea->Sym()) { std::cerr << "Error: ee->Dprev() != ea->Sym()" << std::endl; return 1; } // Lnext if (ee->Lnext() != ea) { std::cerr << "Error: ee->Lnext() != ea" << std::endl; return 1; } // Lprev if (ee->Lprev() != eb) { std::cerr << "Error: ee->Lprev() != eb" << std::endl; return 1; } // Rnext if (ee->Rnext() != ec->Sym()) { std::cerr << "Error: ee->Rnext() != ec->Sym()" << std::endl; return 1; } // Rprev if (ee->Rprev() != ed->Sym()) { std::cerr << "Error: ee->Rprev() != ed->Sym()" << std::endl; return 1; } // Org / Dest if (ed->Org() != 3) { std::cerr << "Error: ed->Org() != d" << std::endl; return 1; } if (ed->Dest() != 0) { std::cerr << "Error: ed->Dest() != a" << std::endl; return 1; } if (ee->Org() != 2) { std::cerr << "Error: ee->Org() != c" << std::endl; return 1; } if (ee->Dest() != 0) { std::cerr << "Error: ee->Dest() != a" << std::endl; return 1; } // Let the system clean up the memory return 0; }
void Edge::killEdge(Edge *e) { Edge *f = e->Sym(); if (e->Onext() != e) splice(e, e->Oprev()); if (f->Onext() != f) splice(f, f->Oprev()); delete (QuadEdge *)(e - e->r); }
/*Type of Cut Strategy is defined as: * (useAltCut, useVertical) = (true, true) => Alternating Cuts * (useAltCut, useVertical) = (true, false) => Horizontal Cuts* * (useAltCut, useVertical) = (false, true) => Vertical Cuts * */ void delaunay(Vertex **ppVertices, long numVertices, Edge **ppLe, Edge **ppRe, bool useAltCuts, bool useVertical) { NOT_NULL(ppVertices); if(numVertices == 2) { Edge *pA = Edge::makeEdge(); if(*ppVertices[0] > *ppVertices[1]) { ELEM_SWAP(ppVertices[0], ppVertices[1]); } pA->setOrg(ppVertices[0]); pA->setDest(ppVertices[1]); *ppLe = pA; *ppRe = pA->Sym(); } else if(numVertices == 3) { Edge *pA = Edge::makeEdge(), *pB = Edge::makeEdge(), *pC = 0; if(*ppVertices[0] > *ppVertices[1]) { ELEM_SWAP(ppVertices[0], ppVertices[1]); } if(*ppVertices[1] > *ppVertices[2]) { ELEM_SWAP(ppVertices[1], ppVertices[2]); } Edge::splice(pA->Sym(), pB); pA->setOrg(ppVertices[0]); pA->setDest(ppVertices[1]); pB->setOrg(ppVertices[1]); pB->setDest(ppVertices[2]); REAL ccw = orient2d(ppVertices[0]->Pos(), ppVertices[1]->Pos(), ppVertices[2]->Pos()); if(ccw > 0) { pC = Edge::connect(pB, pA); *ppLe = pA; *ppRe = pB->Sym(); } else if(ccw < 0) { pC = Edge::connect(pB, pA); *ppLe = pC->Sym(); *ppRe = pC; } else { *ppLe = pA; *ppRe = pB->Sym(); } } else { long middle = std::floor(numVertices/2); Edge *pLdo = 0, *pLdi = 0, *pRdi = 0, *pRdo = 0; //These vertices are used for merging a horizontal cut Vertex *pBotMax = 0, //highest vertex of bottom half *pTopMin = 0, //lowest vertex of top half *pMin = 0, //Lexicographically max vertex *pMax = 0; //Lexicographically min vertex //Find median partition by X or Y, depending on whether we're using a vertical cut std::nth_element(ppVertices, ppVertices+middle, ppVertices+numVertices, useVertical ? Vertex::lessX : Vertex::lessY); //Recursive calls delaunay(ppVertices, middle, &pLdo, &pLdi, useAltCuts, useAltCuts ? !useVertical : useVertical); delaunay(ppVertices+middle, numVertices - middle, &pRdi, &pRdo, useAltCuts, useAltCuts ? !useVertical : useVertical); //Modify ldi be highest in bottom half and rdi to be lowest in top half if(!useVertical) { pBotMax = ppVertices[0]; pTopMin = ppVertices[middle]; pMin = (*ppVertices[0] < *ppVertices[middle]) ? ppVertices[0] : ppVertices[middle]; pMax = (*ppVertices[0] > *ppVertices[middle]) ? ppVertices[0] : ppVertices[middle];; for(long i=1; i < middle; i++) { if(*ppVertices[i] < *pMin) { pMin = ppVertices[i]; } else if(*ppVertices[i] > *pMax) { pMax = ppVertices[i]; } if(ppVertices[i]->gtY(*pBotMax)) { pBotMax = ppVertices[i]; } } for(long i=middle+1; i < numVertices; i++) { if(*ppVertices[i] < *pMin) { pMin = ppVertices[i]; } else if(*ppVertices[i] > *pMax) { pMax = ppVertices[i]; } if(ppVertices[i]->ltY(*pTopMin)) { pTopMin = ppVertices[i]; } } pLdi = pBotMax->getCWHullEdge(); pRdi = pTopMin->getCCWHullEdge(); } //Compute the lower common tangent of two sets of vertices while (1) { if(pLdi->leftOf(pRdi->Org())) { pLdi = pLdi->Lnext(); } else if(pRdi->rightOf(pLdi->Org())) { pRdi = pRdi->Rprev(); } else { break; } } // Create a first cross edge pBasel from pRdi.origin to pLdi.origin Edge *pBasel = Edge::connect(pRdi->Sym(), pLdi); if(pLdi->Org() == pLdo->Org()) { pLdo = pBasel->Sym(); } if(pRdi->Org() == pRdo->Org()) { pRdo = pBasel; } //Merging two halves while(1) { //Locate the first Left point pLcand to be encou Edge *pLcand = pBasel->Sym()->Onext(); bool leftFinished = !pLcand->valid(pBasel); if(!leftFinished) { while(incircle(pBasel->Dest()->Pos(), pBasel->Org()->Pos(), pLcand->Dest()->Pos(), pLcand->Onext()->Dest()->Pos()) > 0) { Edge *pT = pLcand->Onext(); Edge::deleteEdge(pLcand); pLcand = pT; } } //Symmetrically locate the first R point to be hit Edge *pRcand = pBasel->Oprev(); bool rightFinished = !pRcand->valid(pBasel); if(!rightFinished) { while(incircle(pBasel->Dest()->Pos(), pBasel->Org()->Pos(), pRcand->Dest()->Pos(), pRcand->Oprev()->Dest()->Pos()) > 0) { Edge *pT = pRcand->Oprev(); Edge::deleteEdge(pRcand); pRcand = pT; } } //both are invalid, pBasel is upper common tangent if(leftFinished && rightFinished) { break; } //the next cross edge is to be connected to either pLcand.dest or pRcand.dest if(leftFinished || (!rightFinished && incircle(pLcand->Dest()->Pos(), pLcand->Org()->Pos(), pRcand->Org()->Pos(), pRcand->Dest()->Pos()) > 0)) { pBasel = Edge::connect(pRcand, pBasel->Sym()); } else { pBasel = Edge::connect(pBasel->Sym(), pLcand->Sym()); } } //Modify pLdo and pRdo if we merging a horizontal cut if(!useVertical) { pLdo = pMin->getCCWHullEdge(); pRdo = pMax->getCWHullEdge(); } *ppLe = pLdo; *ppRe = pRdo; } return; }
Edge *Subdivision::spoke(Vec2& x, Edge *e) { Triangle *new_faces[4]; int facedex = 0; // // NOTE: e is the edge returned by locate(x) // if ( (x == e->Org()) || (x == e->Dest()) ) { // point is already in the mesh // #ifdef _INC_IOSTREAM std::cerr << "WARNING: Tried to reinsert point: " << x << std::endl; std::cerr << " org: " << e->Org() << std::endl; std::cerr << " dest: " << e->Dest() << std::endl; #endif return NULL; } Edge *boundary_edge = NULL; Triangle *lface = e->Lface(); lface->dontAnchor(e); new_faces[facedex++] = lface; if( onEdge(x,e) ) { if( ccwBoundary(e) ) { // // e lies on the boundary // Defer deletion until after new edges are added. boundary_edge = e; } else { Triangle *sym_lface = e->Sym()->Lface(); new_faces[facedex++] = sym_lface; sym_lface->dontAnchor(e->Sym()); e = e->Oprev(); deleteEdge(e->Onext()); } } else { // x lies within the Lface of e } Edge *base = makeEdge(e->Org(), x.clone()); splice(base, e); startingEdge = base; do { base = connect(e, base->Sym()); e = base->Oprev(); } while( e->Lnext() != startingEdge ); if( boundary_edge ) deleteEdge(boundary_edge); // Update all the faces in our new spoked polygon. // If point x on perimeter, then don't add an exterior face base = boundary_edge ? startingEdge->Rprev() : startingEdge->Sym(); do { if( facedex ) new_faces[--facedex]->reshape(base); else makeFace(base); base = base->Onext(); } while( base != startingEdge->Sym() ); return startingEdge; }