Пример #1
0
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;
                }
    }
}
Пример #2
0
static inline void printFace(std::ostream &out, Face *f) {
    out << "Face: " << f->getID() << std::endl;
    FaceEdgeIterator eitr(f);
    Edge *e = NULL;
    int edge = 0;
    while ((e = eitr.next())) {
        out << "Edge " << edge << " with id: " << e->getID() << " from " <<
               e->Org()->pos << " to " << e->Dest()->pos << std::endl;
        ++edge;
    }
}
Пример #3
0
Edge *Cell::getOrbitOrg(Edge *edge, Vertex *org) {
    assert(edge != 0);
    assert(org != 0);

    // traverse the Lnext orbit of _edge_ looking for an edge whose origin is
    // _org_
    Edge *scan = edge;

    do {
        if (scan->Org() == org) {
            return scan;
        }

        scan = scan->Lnext();
    } while (scan != edge);

    return 0;
}
Пример #4
0
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);
}
Пример #5
0
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;
}
Пример #6
0
/*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;
}