// Copyright 2001 softSurfer, 2012 Dan Sunday // This code may be freely used and modified for any purpose // providing that this copyright notice is included with it. // SoftSurfer makes no warranty for this code, and cannot be held // liable for any real or imagined damage resulting from its use. // Users of this code must verify correctness for their application. // Assume that classes are already given for the objects: // Point with 2D coordinates {float x, y;} // Polygon with n vertices {int n; Point *V;} with V[n]=V[0] // Tnode is a node element structure for a BBT // BBT is a class for a Balanced Binary Tree // such as an AVL, a 2-3, or a red-black tree // with methods given by the placeholder code: typedef struct _BBTnode Tnode; struct _BBTnode { void* val; // plus node mgmt info ... }; class BBT { Tnode *root; public: BBT() {root = (Tnode*)0;} // constructor ~BBT() {freetree();} // destructor Tnode* insert( void* ){}; // insert data into the tree Tnode* find( void* ){}; // find data from the tree Tnode* next( Tnode* ){}; // get next tree node Tnode* prev( Tnode* ){}; // get previous tree node void remove( Tnode* ){}; // remove node from the tree void freetree(){}; // free all tree data structs }; // NOTE: // Code for these methods must be provided for the algorithm to work. // We have not provided it since binary tree algorithms are well-known // and code is widely available. Further, we want to reduce the clutter // accompanying the essential sweep line algorithm. //=================================================================== #define FALSE 0 #define TRUE 1 #define LEFT 0 #define RIGHT 1 extern void qsort(void*, unsigned, unsigned, int(*)(const void*,const void*)); // xyorder(): determines the xy lexicographical order of two points // returns: (+1) if p1 > p2; (-1) if p1 < p2; and 0 if equal int xyorder( Point* p1, Point* p2 ) { // test the x-coord first if (p1->x > p2->x) return 1; if (p1->x < p2->x) return (-1); // and test the y-coord second if (p1->y > p2->y) return 1; if (p1->y < p2->y) return (-1); // when you exclude all other possibilities, what remains is... return 0; // they are the same point } // isLeft(): tests if point P2 is Left|On|Right of the line P0 to P1. // returns: >0 for left, 0 for on, and <0 for right of the line. // (see Algorithm 1 on Area of Triangles) inline float isLeft( Point P0, Point P1, Point P2 ) { return (P1.x - P0.x)*(P2.y - P0.y) - (P2.x - P0.x)*(P1.y - P0.y); } //=================================================================== // EventQueue Class // Event element data struct typedef struct _event Event; struct _event { int edge; // polygon edge i is V[i] to V[i+1] int type; // event type: LEFT or RIGHT vertex Point* eV; // event vertex }; int E_compare( const void* v1, const void* v2 ) // qsort compare two events { Event** pe1 = (Event**)v1; Event** pe2 = (Event**)v2; return xyorder( (*pe1)->eV, (*pe2)->eV ); } // the EventQueue is a presorted array (no insertions needed) class EventQueue { int ne; // total number of events in array int ix; // index of next event on queue Event* Edata; // array of all events Event** Eq; // sorted list of event pointers public: EventQueue(Polygon P); // constructor ~EventQueue(void) // destructor { delete Eq; delete Edata;} Event* next(); // next event on queue }; // EventQueue Routines EventQueue::EventQueue( Polygon P ) { ix = 0; ne = 2 * P.n; // 2 vertex events for each edge Edata = (Event*)new Event[ne]; Eq = (Event**)new (Event*)[ne]; for (int i=0; i < ne; i++) // init Eq array pointers Eq[i] = &Edata[i]; // Initialize event queue with edge segment endpoints for (int i=0; i < P.n; i++) { // init data for edge i Eq[2*i]->edge = i; Eq[2*i+1]->edge = i; Eq[2*i]->eV = &(P.V[i]); Eq[2*i+1]->eV = &(P.V[i+1]); if (xyorder( &P.V[i], &P.V[i+1]) < 0) { // determine type Eq[2*i]->type = LEFT; Eq[2*i+1]->type = RIGHT; } else { Eq[2*i]->type = RIGHT; Eq[2*i+1]->type = LEFT; } } // Sort Eq[] by increasing x and y qsort( Eq, ne, sizeof(Event*), E_compare ); } Event* EventQueue::next() { if (ix >= ne) return (Event*)0; else return Eq[ix++]; } //=================================================================== // SweepLine Class // SweepLine segment data struct typedef struct _SL_segment SLseg; struct _SL_segment { int edge; // polygon edge i is V[i] to V[i+1] Point lP; // leftmost vertex point Point rP; // rightmost vertex point SLseg* above; // segment above this one SLseg* below; // segment below this one }; // the Sweep Line itself class SweepLine { int nv; // number of vertices in polygon Polygon* Pn; // initial Polygon BBT Tree; // balanced binary tree public: SweepLine(Polygon P) // constructor { nv = P.n; Pn = &P; } ~SweepLine(void) // destructor { Tree.freetree();} SLseg* add( Event* ); SLseg* find( Event* ); int intersect( SLseg*, SLseg* ); void remove( SLseg* ); }; SLseg* SweepLine::add( Event* E ) { // fill in SLseg element data SLseg* s = new SLseg; s->edge = E->edge; // if it is being added, then it must be a LEFT edge event // but need to determine which endpoint is the left one Point* v1 = &(Pn->V[s->edge]); Point* v2 = &(Pn->V[s->edge+1]); if (xyorder( v1, v2) < 0) { // determine which is leftmost s->lP = *v1; s->rP = *v2; } else { s->rP = *v1; s->lP = *v2; } s->above = (SLseg*)0; s->below = (SLseg*)0; // add a node to the balanced binary tree Tnode* nd = Tree.insert(s); Tnode* nx = Tree.next(nd); Tnode* np = Tree.prev(nd); if (nx != (Tnode*)0) { s->above = (SLseg*)nx->val; s->above->below = s; } if (np != (Tnode*)0) { s->below = (SLseg*)np->val; s->below->above = s; } return s; } SLseg* SweepLine::find( Event* E ) { // need a segment to find it in the tree SLseg* s = new SLseg; s->edge = E->edge; s->above = (SLseg*)0; s->below = (SLseg*)0; Tnode* nd = Tree.find(s); delete s; if (nd == (Tnode*)0) return (SLseg*)0; return (SLseg*)nd->val; } void SweepLine::remove( SLseg* s ) { // remove the node from the balanced binary tree Tnode* nd = Tree.find(s); if (nd == (Tnode*)0) return; // not there // get the above and below segments pointing to each other Tnode* nx = Tree.next(nd); if (nx != (Tnode*)0) { SLseg* sx = (SLseg*)(nx->val); sx->below = s->below; } Tnode* np = Tree.prev(nd); if (np != (Tnode*)0) { SLseg* sp = (SLseg*)(np->val); sp->above = s->above; } Tree.remove(nd); // now can safely remove it delete s; } // test intersect of 2 segments and return: 0=none, 1=intersect int SweepLine::intersect( SLseg* s1, SLseg* s2) { if (s1 == (SLseg*)0 || s2 == (SLseg*)0) return FALSE; // no intersect if either segment doesn't exist // check for consecutive edges in polygon int e1 = s1->edge; int e2 = s2->edge; if (((e1+1)%nv == e2) || (e1 == (e2+1)%nv)) return FALSE; // no non-simple intersect since consecutive // test for existence of an intersect point float lsign, rsign; lsign = isLeft(s1->lP, s1->rP, s2->lP); // s2 left point sign rsign = isLeft(s1->lP, s1->rP, s2->rP); // s2 right point sign if (lsign * rsign > 0) // s2 endpoints have same sign relative to s1 return FALSE; // => on same side => no intersect is possible lsign = isLeft(s2->lP, s2->rP, s1->lP); // s1 left point sign rsign = isLeft(s2->lP, s2->rP, s1->rP); // s1 right point sign if (lsign * rsign > 0) // s1 endpoints have same sign relative to s2 return FALSE; // => on same side => no intersect is possible // the segments s1 and s2 straddle each other return TRUE; // => an intersect exists } //=================================================================== // simple_Polygon(): test if a Polygon is simple or not // Input: Pn = a polygon with n vertices V[] // Return: FALSE(0) = is NOT simple // TRUE(1) = IS simple int simple_Polygon( Polygon Pn ) { EventQueue Eq(Pn); SweepLine SL(Pn); Event* e; // the current event SLseg* s; // the current SL segment // This loop processes all events in the sorted queue // Events are only left or right vertices since // No new events will be added (an intersect => Done) while (e = Eq.next()) { // while there are events if (e->type == LEFT) { // process a left vertex s = SL.add(e); // add it to the sweep line if (SL.intersect( s, s->above)) return FALSE; // Pn is NOT simple if (SL.intersect( s, s->below)) return FALSE; // Pn is NOT simple } else { // processs a right vertex s = SL.find(e); if (SL.intersect( s->above, s->below)) return FALSE; // Pn is NOT simple SL.remove(s); // remove it from the sweep line } } return TRUE; // Pn IS simple } //===================================================================