// ------------------------------------------------------------------------ // This program is complementary material for the book: // // Frank Nielsen // // Visual Computing: Geometry, Graphics, and Vision // // ISBN: 1-58450-427-7 // // Charles River Media, Inc. // // // All programs are available at http://www.charlesriver.com/visualcomputing/ // // You may use this program for ACADEMIC and PERSONAL purposes ONLY. // // // The use of this program in a commercial product requires EXPLICITLY // written permission from the author. The author is NOT responsible or // liable for damage or loss that may be caused by the use of this program. // // Copyright (c) 2005. Frank Nielsen. All rights reserved. // ------------------------------------------------------------------------ // ------------------------------------------------------------------------ // File: ShamosHoey.cpp // // Description: Detect whether a set of line segments intersect or not // Implement in a STL fashion a simple but optimal algorithm // to detect whether there exists an intersection point among a set of n segments in O(n log n) time // // Michael I. Shamos and Dan Hoey. // "Geometric intersection problems" (FOCS 1976) // In 17th Annual Symposium on Foundations of Computer Science // pages 208-215, Houston, Texas, 25-27 October 1976. IEEE. // ------------------------------------------------------------------------ #include "stdafx.h" #include #include #include #include #include #define W 900 #define H 900 using namespace std; enum type {LEFT, RIGHT}; class point { public: double x,y; int n; type endpoint; // Lexicographic order on the x-coordinate bool operator < ( const point & rhs) {return (x (const point & rhs) {return (x>rhs.x);} }; class segment { public: point A,B; }; class Yline { public: static double x; double a,b; // equation of nonvertical line y=ax+b int n; void setX(double xx) {x=xx;} bool operator < ( const Yline & rhs) { // cout <<"\t\tGeneric dictionary (inferior): "< ( const Yline & rhs) { // cout <<"\t\tGeneric dictionary (inferior): "<rhs.a*x+rhs.b); } bool operator == ( const Yline & rhs) { // cout <<"\t\tGeneric dictionary (inferior): "< (r.x-p.x)*(q.y-p.y)+ERR) return CCW; if ((q.x-p.x)*(r.y-p.y) < (r.x-p.x)*(q.y-p.y)-ERR) return CW; return ON; } bool SegmentIntersect(segment s1, segment s2) { if (Orient2D(s1.A,s1.B,s2.A)==Orient2D(s1.A,s1.B,s2.B)) return false; if (Orient2D(s2.A,s2.B,s1.A)==Orient2D(s2.A,s2.B,s1.B)) return false; intersection=true; return true; } // Return a random number in [0,1] inline double randd() { return (double)rand()/(double)RAND_MAX; } // Line equation + segment number void SegmentToYevent(segment S, int nn, Yline& eventp) { eventp.n=nn; eventp.a=(S.B.y-S.A.y)/(S.B.x-S.A.x); //slope eventp.b=S.A.y-eventp.a*S.A.x; // y=ax+b } int Intersect() { cout << "Some pair of segments intersect"< T; vector::iterator event; vector Yorder; vector::iterator pos, below, above; Yline yevent; segment *seg; double ycoord; int inter1,inter2; static nbstep=0; void disp() { int i; char buffer[256]; vector::iterator yo; glClearColor(1,1,1,0); glClear(GL_COLOR_BUFFER_BIT); glColor3f(0,0,1); glPointSize(2); // Draw the line segments glBegin(GL_LINES); for(i=0;i-1) { glBegin(GL_LINES); glVertex2f(seg[iabove].A.x,seg[iabove].A.y); glVertex2f(seg[iabove].B.x,seg[iabove].B.y); glEnd(); } if (ibelow>-1) { glBegin(GL_LINES); glVertex2f(seg[ibelow].A.x,seg[ibelow].A.y); glVertex2f(seg[ibelow].B.x,seg[ibelow].B.y); glEnd(); } glLineWidth(1); if (ime>-1) { glColor3f(0,1,0); glBegin(GL_LINES); glVertex2f(seg[ime].A.x,seg[ime].A.y); glVertex2f(seg[ime].B.x,seg[ime].B.y); glEnd(); } if (intersection) { glColor3f(1,0,0); glRasterPos2f(0.1,0.9); sprintf(buffer,"Detected a pair of intersecting line segments! Press 'r' for another set"); for(int ii=0;buffer[ii]!=0;ii++) glutBitmapCharacter(GLUT_BITMAP_TIMES_ROMAN_24, buffer[ii]); glColor3f(1,0,0); glLineWidth(5); glBegin(GL_LINES); glVertex2f(seg[inter1].A.x,seg[inter1].A.y); glVertex2f(seg[inter1].B.x,seg[inter1].B.y); glVertex2f(seg[inter2].A.x,seg[inter2].A.y); glVertex2f(seg[inter2].B.x,seg[inter2].B.y); glEnd(); glLineWidth(1); } if (nbstep>=2*n) { glColor3f(1,0,0); glRasterPos2f(0.01,0.9); sprintf(buffer,"I have not detected any pair of intersecting segments ! Press 'r' for another set"); for(int ii=0;buffer[ii]!=0;ii++) glutBitmapCharacter(GLUT_BITMAP_TIMES_ROMAN_24, buffer[ii]); } } glFlush(); glutSwapBuffers(); } void HandleEvent(); void InitializeSegments(); void key(unsigned char key , int x , int y) { if (key=='r') { intersection=false; nbstep=0; InitializeSegments(); disp(); } else{ if (!intersection){ nbstep++; if (nbstep<2*n) { event++; cout << "Number of segments crossing the Y sweep line:" << (unsigned int)Yorder.size() << endl; HandleEvent(); } } // Refresh the animation disp(); } } void SeekBelowAbove() { iabove=ibelow=-1; for(int i=0;iYorder[ibelow]) ibelow=i; } if (Yorder[i]>yevent) { if (iabove==-1) iabove=i; else if (Yorder[i]0) { below=Yorder.begin(); while( (below!=Yorder.end()) && ((*below)length*length) goto redraw; if (P1.xP2.x) {P1.endpoint=RIGHT; P2.endpoint=LEFT; seg[i].A=P2; seg[i].B=P1;} T.push_back(P1); T.push_back(P2); } cout<<"Sort the x-coordinates of segment endpoints."<