Chris Pollett > Old Classes
> |
HW1 Solutions Pagebitfill.cpp/****************************************************** * Project: CS116A Homework #2 * File: bitfill.cpp * Purpose: Code to print out a letters vaa and ji * three times each as specified in HW2 * description * * Start date: Oct 18, 2004 * Programmer: Chris Pollett * * Remarks: * *******************************************************/ #ifdef WIN32 #include<windows.h> //for windows #include <GL/glut.h> #include <GL/glu.h> #endif #ifdef __APPLE__ //for MAC /* I created my project under xcode. I chose new C++ tool as the kind of project. Then under External frameworks and libraries I added the two frameworks: OpenGL.framework and GLUT.framework. (Frameworks are in /Library/Frameworks) */ #include <OpenGL/gl.h> #include <OpenGL/glu.h> #include <GLUT/glut.h> #endif #ifdef linux // for linux /*My compile line was: g++ -I /usr/X11R6/include -L /usr/X11R6/lib -lglut -lGL \ -lGLU -lX11 -lXmu -lXi -lm name.cpp -o name */ #include <GL/glut.h> #include <GL/glu.h> #endif //C headers #include <cmath> //C++ headers #include <iostream> #include <string> using namespace std; /* Globals */ GLsizei winWidth = 400, winHeight = 400; // used for size of window /*-----------------------------------------------*/ void drawVaa(void) /* PURPOSE: Draws the Vaa bitmap three times with only one call to glRasterPos2i RECEIVES: nothing RETURNS: nothing REMARKS: */ { GLubyte vaaShape[52] = // vaa symbol byte array { 0x00, 0x00, 0x00, 0xC0, 0x03, 0x80, 0x0E, 0x00, 0x38, 0x00, 0x71, 0xC0, 0x1D, 0x40, 0x07, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x80, 0x00, 0x00 }; glColor3f(0.0, 0.0, 0.0); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); glRasterPos2i(50, 300); //Draw bitmap three time, two pixel gap comes from xoffset of 15 glBitmap(13, 13, 0.0, 0.0, 15.0, 0.0, vaaShape); glBitmap(13, 13, 0.0, 0.0, 15.0, 0.0, vaaShape); glBitmap(13, 13, 0.0, 0.0, 15.0, 0.0, vaaShape); } /*-----------------------------------------------*/ void drawJi(void) /* PURPOSE: Draws the Ji symbol three times as specified in homework description RECEIVES: nothing RETURNS: nothing REMARKS: */ { GLuint jiListID = glGenLists(1); // id of ji display list // Set up how we draw the points. GLfloat widths[2]; // Store supported point size range // Get supported line size range and step size glGetFloatv(GL_LINE_WIDTH_RANGE,widths); // Specify the point size -- try to make at least 10 GLfloat drawWidth = 10; if(drawWidth > widths[1]) drawWidth = widths[1]; //Create display list glNewList(jiListID, GL_COMPILE); glLineWidth(drawWidth); glRecti(50, 100, 60, 150); glBegin(GL_QUADS); glVertex2i(50, 150); glVertex2i(50, 160); glVertex2i(150, 160); glVertex2i(150, 150); glEnd(); glLineStipple(1, 0xF0F0); glEnable(GL_LINE_STIPPLE); glBegin(GL_LINE_STRIP); glVertex2i(150, 155); glVertex2i(200, 155); glVertex2i(100, 250); glEnd(); glDisable(GL_LINE_STIPPLE); glEndList(); //Now draw three times glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_BLEND); glColor4f(1.0, 0.0, 0.0, .5); glCallList(jiListID); glTranslated(50, 0, 0); //used Translate before in my solutions to Hw1 glColor4f(0.0, 1.0, 0.0, .5); glCallList(jiListID); glTranslated(50, 0, 0); glColor4f(0.0, 0.0, 1.0, .5); glCallList(jiListID); glTranslated(-100, 0, 0); //undo translations glDisable(GL_BLEND); } /*-----------------------------------------------*/ void drawVaaJi(void) /* PURPOSE: GLUT display callback function for this program. Serves as the main driver for the program. Draws the Vaa bitmap three times using drawVaa then draws the Ji display list three times using drawJi RECEIVES: nothing RETURNS: nothing REMARKS: */ { glClear(GL_COLOR_BUFFER_BIT); glColor3f(0.0, 0.0, 0.0); drawVaa(); drawJi(); glFlush(); } /*-----------------------------------------------*/ void winReshapeFn(int newWidth, int newHeight) /* PURPOSE: Resizes/redisplays the contents of the current window RECEIVES: newWidth, newHeight -- the new dimensions RETURNS: nothing REMARKS: Notice resize viewport */ { winWidth = newWidth; winHeight = newHeight; glViewport(0, 0, newWidth, newHeight); glClearColor(1.0, 1.0, 1.0, 0.0); glClear(GL_COLOR_BUFFER_BIT); glLoadIdentity(); gluOrtho2D(0.0, winWidth, 0.0, winHeight); drawVaaJi(); } /*-----------------------------------------------*/ void init(void) /* PURPOSE: Used to initializes our OpenGL window and set up pt pointers for keyboard handler RECEIVES: Nothing RETURNS: Nothing REMARKS: Nothing */ { glClearColor(1.0, 1.0, 1.0, 0.0); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluOrtho2D(0.0, winWidth, 0.0, winHeight); /* note don't set default viewport size as will by default be whole window*/ } int main(int argc, char** argv) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB); glutInitWindowPosition(50, 100); glutInitWindowSize(winWidth, winHeight); glutCreateWindow("Odd Even Rule Tester"); init(); //Set up drawing callbacks glutDisplayFunc(drawVaaJi); glutReshapeFunc(winReshapeFn); //Start main loop glutMainLoop(); return 0; } intext.cpp/****************************************************** * Project: CS116A Homework #2 * File: intext.cpp * Purpose: Code to print out a letter ngii and two points * Points colored according to if both interior/exterior to ngii * Start date: Oct 18, 2004 * Programmer: Chris Pollett * * Remarks: Letter writing is implemented using a Command Pattern. This would make it * easy to add new letters. * In real world word have separate .h and .cpp files * * Added keyboard control (arrow keys) to move points around * esc switches which point to move * space- turns on and off drawing a colored line between two points * *******************************************************/ #ifdef WIN32 #include<windows.h> //for windows #include <GL/glut.h> #include <GL/glu.h> #endif #ifdef __APPLE__ //for MAC /* I created my project under xcode. I chose new C++ tool as the kind of project. Then under External frameworks and libraries I added the two frameworks: OpenGL.framework and GLUT.framework. (Frameworks are in /Library/Frameworks) */ #include <OpenGL/gl.h> #include <OpenGL/glu.h> #include <GLUT/glut.h> #endif #ifdef linux // for linux /*My compile line was: g++ -I /usr/X11R6/include -L /usr/X11R6/lib -lglut -lGL \ -lGLU -lX11 -lXmu -lXi -lm name.cpp -o name */ #include <GL/glut.h> #include <GL/glu.h> #endif //C headers #include <cmath> //C++ headers #include <fstream> #include <iostream> #include <sstream> #include <string> #include <vector> #include <queue> using namespace std; /* CONSTANTS */ const GLfloat PI = 3.14159265358979323846; /* CLASS DEFINITIONS */ /*-----------------------------------------------*/ class ScreenPt /* PURPOSE: Encapsulates the notions of a point (x,y) on the screen Has simple accessors and increment/decrement mutators which are useful for Bresenham-like algorithms */ { private: GLint x, y; public: ScreenPt(GLint newX=0, GLint newY=0) { x = newX; y = newY; } void setCoords(GLint x0, GLint y0) { x = x0; y = y0; } GLint getx() const { return x; } GLint gety() const { return y; } void incx() { x++; } void decx() { x--; } void incy() { y++; } void decy() { y--; } bool operator<(const ScreenPt b) const //used by priority_queue in drawing even odd edge; { return x*x + y*y > b.getx()*b.getx() + b.gety()*b.gety(); } }; /*-----------------------------------------------*/ class Letter /* PURPOSE: Holds an ascii character together with a string saying how it is drawn. Format of this draw string is as follows: "cmd1 par1 par2 par3 ... cmd2 par1 par2" where everything operation in the string is sepearted by a single space cmdX indicates a command and can be either c (draw arc) or l (draw line) parX indicates a parameter to the command. Ex c .3 .3 .2 0 6.28 l 3 .5 .5 .5 .1 .6 .1 First, draws a complete circle (0 to 6.28 is one revolution) of radius .2 centered at (.3, .3). Then draws a polyline consisting of 3 points (.5,.5), (.5, .1), and (.6, .1). Letter are assumed to fit in a 1.0 x 1.0 pixel box which is scaled by desired size dby the scale parameter of the draw function. */ { private: char _letter; GLfloat _width; string _representation; void getArcVertices(vector<ScreenPt>& pts, vector<bool>& drawableEdges, GLint xc, GLint yc, GLint radiusX, GLint radiusY, GLfloat startTheta, GLfloat endTheta); public: Letter(char l, GLfloat w, string rep); void getVertices(vector<ScreenPt>& pts, vector<bool>& drawableEdges, GLfloat x, GLfloat y, GLfloat scaleX, GLfloat scaleY); void getIntersectEdges(priority_queue<ScreenPt>& pts, ScreenPt p1, ScreenPt p2, GLfloat x, GLfloat y, GLfloat scaleX, GLfloat scaleY); void draw(GLfloat x, GLfloat y, GLfloat scaleX, GLfloat scaleY); GLfloat width() {return _width;} bool canDraw(char l){return (_letter == l); } }; /*-----------------------------------------------*/ class LetterProcessor /* PURPOSE: Is a container for Letters (supporting add) and allows one to print strings of these letters to the screen. */ { private: vector<Letter> _letters; public: void add(Letter l){ _letters.push_back(l);} void draw(GLfloat x, GLfloat y, GLfloat scaleX, GLfloat scaleY, string output); void drawIntersectEdges(ScreenPt p1, ScreenPt p2, GLfloat x, GLfloat y, GLfloat scaleX, GLfloat scaleY, string testString, bool lineModeFlag); }; /* GLOBALS */ GLsizei winWidth = 600, winHeight = 600; // used for size of window GLfloat drawSize = 1; //thickness to draw points ScreenPt pt1, pt2, *pactivePt, *ppassivePt; //pointers used by keyboard handlers bool lineModeFlag = false; //use to tell if draw a line between two test points /* FUNCTIONS */ // Auxiliary functions void setPixel(GLint x, GLint y); inline GLint crossProduct(GLint x0, GLint y0, GLint x1, GLint y1); int intersect(ScreenPt edge1p1, ScreenPt edge1p2, ScreenPt edge2p1, ScreenPt edge2p2, GLint& crossX, GLint& crossY ); bool containedBox(GLint x, GLint y, ScreenPt corner1, ScreenPt corner2); void orderPtX(ScreenPt& p1, ScreenPt& p2); void orderPtY(ScreenPt& p1, ScreenPt& p2); inline GLint sgn(GLint x); void lineBres(int x0, int y0, int xEnd, int yEnd); // Polyline functions void polyLineBres(vector<ScreenPt>& pts, vector<bool>& drawableEdges); /* IMPLEMENTATIONS */ /*-----------------------------------------------*/ Letter::Letter(char l, GLfloat w, string rep) /* PURPOSE: constructor RECEIVES: l - the letter to be associated with the draw string w - how wide the letter is. A value from 0.0 to 1.0 rep - string used to say how to draw letter (format described in class def) RETURNS: An instance of letter REMARKS: */ { _letter = l; _width = w; _representation = rep; } /*-----------------------------------------------*/ void Letter::getVertices(vector<ScreenPt>& pts, vector<bool>& drawableEdges, GLfloat x, GLfloat y, GLfloat scaleX, GLfloat scaleY) /* PURPOSE: returns all the coordinates positions for drawing the edges of the stored letter at the given height. drawableEdges used to control endpoints for the various polylines RECEIVES: pts - vector to store points into drawableEdges - vector to store endpoints of polylines x, y -coordinates to draw letter at scaleX, scaleY -width and height of letter. RETURNS: REMARKS: */ { istringstream tokens(_representation); int i, len; int tmpX, tmpY, radiusX, radiusY, xc, yc; GLfloat tmpF, startTheta, endTheta; char token; while(!tokens.eof()) { tokens >> token; switch(token) { case 'l': tokens >> len; for(i = 0; i < len; i++) { tokens >> tmpF; tmpX = (int)(x + scaleX*tmpF); tokens >> tmpF; tmpY = (int)(y + scaleY*tmpF); pts.push_back(ScreenPt(tmpX,tmpY)); } drawableEdges.push_back(false); for(i = 1; i < len; i++) drawableEdges.push_back(true); break; case 'c': tokens >> tmpF; xc = (int)(x + scaleX*tmpF); tokens >> tmpF; yc = (int)(y + scaleY*tmpF); tokens >> tmpF; radiusX = (int)(scaleX*tmpF); radiusY = (int)(scaleY*tmpF); tokens >> startTheta; tokens >> endTheta; getArcVertices(pts, drawableEdges, xc, yc, radiusX, radiusY, startTheta, endTheta); break; } } } /*-----------------------------------------------*/ void Letter::getArcVertices(vector<ScreenPt>& pts, vector<bool>& drawableEdges, GLint xc, GLint yc, GLint radiusX, GLint radiusY, GLfloat startTheta, GLfloat endTheta) /* PURPOSE: get vertices of polyline used to draw an ellipse arc RECEIVES: pts - vector to store points of arc drawableEdges - used to say if an adge should be drawn. (one first value false) xc, yc -center of arc radiusX, radiusY - ellipse diameters startTheta, endTheta - angle endpoints of arc RETURNS: as a side effect two vectors pts ad drawableEdges are modified REMARKS: SLERP -like use of n angle formulas */ { GLint rsTheta = (int)(startTheta/(2*PI)); GLint reTheta = (int)(endTheta/(2*PI)); startTheta -= rsTheta*(2*PI); endTheta -= reTheta*(2*PI); startTheta = (startTheta > 0) ? startTheta : 2*PI - startTheta; endTheta = (endTheta > 0) ? endTheta : 2*PI - endTheta; endTheta = (endTheta > startTheta) ? endTheta : endTheta + (2*PI); GLfloat theta=endTheta - startTheta; GLint slices = (radiusX < radiusY) ? radiusX : radiusY; if(slices <= 0) slices = 1; //Calculate start-up sines and cosines GLfloat sinsTheta = sin(startTheta), cossTheta = cos(startTheta); GLfloat sincTheta = sin(theta/slices), coscTheta = cos(theta/slices), origCosc = coscTheta; GLfloat oldSinc = 0, oldCosc = 1, tmpSinc, tmpCosc; GLfloat sinSum, cosSum; //Use nth angle and sum angle formulas to calculate rest of sines and cosine and vertices pts.push_back( ScreenPt((long)(xc + radiusX*sinsTheta), (long)(yc + radiusY*cossTheta))); drawableEdges.push_back(false); sinSum = sinsTheta * coscTheta + cossTheta*sincTheta; cosSum = cossTheta * coscTheta - sinsTheta*sincTheta; pts.push_back( ScreenPt((long)(xc + radiusX*sinSum), (long)(yc + radiusY*cosSum))); drawableEdges.push_back(true); for(int i = 1; i < slices; i++) { tmpSinc = 2*sincTheta*origCosc - oldSinc; tmpCosc = 2*coscTheta*origCosc - oldCosc; oldSinc = sincTheta; oldCosc = coscTheta; sincTheta = tmpSinc; coscTheta = tmpCosc; sinSum = sinsTheta * coscTheta + cossTheta*sincTheta; cosSum = cossTheta * coscTheta - sinsTheta*sincTheta; pts.push_back( ScreenPt((long)(xc + radiusX*sinSum), (long)(yc + radiusY*cosSum))); drawableEdges.push_back(true); } } /*-----------------------------------------------*/ void Letter::getIntersectEdges(priority_queue<ScreenPt>& pts, ScreenPt p1, ScreenPt p2, GLfloat x, GLfloat y, GLfloat scaleX, GLfloat scaleY) /* PURPOSE: determines which edges of letter drawn at x and y with given scales would intersect the line segment with the endpoints p1 and p2 Stores the intersection points in a priority queue according to distance from p1. RECEIVES: pts - priority queue to store into p1 and p2 - endpoints of line segment x and y - point letter is supposed to be at scaleX and scaleY - how bug letter is RETURNS: nothing REMARKS: */ { vector<ScreenPt> letterPts; vector<bool> drawableEdges; getVertices(letterPts, drawableEdges, x, y, scaleX, scaleY); GLint crossX, crossY, lx, ly; int cross; for(unsigned int i = 0; i < letterPts.size() - 1; i++) { lx = letterPts[i].getx(); ly = letterPts[i].gety(); cross = intersect(p1, p2, letterPts[i], letterPts[i+1], crossX, crossY ); if((drawableEdges[i+1] && cross > 0) || (cross == 0 && crossX == lx && crossY == ly)) /* second clause is a weak attemp to avoid counting twice if intersect at a corner */ { pts.push(ScreenPt(crossX - p1.getx(), crossY - p1.gety())); } } } /*-----------------------------------------------*/ void Letter::draw(GLfloat x, GLfloat y, GLfloat scaleX, GLfloat scaleY) /* PURPOSE: Used to draw the Letter according to the instructions in _represntation RECEIVES: x and y - coordinates to draw at. scaleX - how many pixels wide to draw the letter scaleY - how many pixels tall to draw the letter RETURNS: nothing REMARKS: The use of a global function pointer was to aid in testing my code... I first used the built-in OpenGL and GLU line-drawing and arc drawing functions to test to make sure letters were drawing correctly. Once I had this working I wrote my own poly-line and arc drawing functions. Then I switched which was used in draw by changing what the global function pointer pointed to. */ { vector<ScreenPt> pts; vector<bool> drawableEdges; getVertices(pts, drawableEdges, x, y, scaleX, scaleY); polyLineBres(pts, drawableEdges); } /*-----------------------------------------------*/ void LetterProcessor::draw(GLfloat x, GLfloat y, GLfloat scaleX, GLfloat scaleY, string output) /* PURPOSE: Draws a string at the specified location and size on the screen RECEIVES: x and y - screen location to draw scaleX - how wide to scale each letter scaleY - how many pixels tall output - string to output RETURNS: nothing REMARKS: */ { GLfloat curX = x; GLfloat curY = y; bool drawSucceed; int len = output.size(); //avoid dereferencing more than once int numLetters = _letters.size(); for(int i = 0; i < len ; i++) { drawSucceed = false; for(int j = 0; j < numLetters; j++) { if(_letters[j].canDraw(output[i])) /*linear search.. So fast! Not!! Actually given the small number of letters in most alphabets could be. */ { drawSucceed = true; _letters[j].draw(curX, curY, scaleX, scaleY); curX += scaleX*_letters[j].width(); } } if(!drawSucceed) throw string("Letter: ") + output[i] + " is not drawable."; } } /*-----------------------------------------------*/ void LetterProcessor::drawIntersectEdges(ScreenPt p1, ScreenPt p2, GLfloat x, GLfloat y, GLfloat scaleX, GLfloat scaleY, string testString, bool lineModeFlag) /* PURPOSE: draws a line from p1 to p2 colored according to how the line intersects with the letters in test string drawn at the given location and scale RECEIVES: p1 and p1 - endpoints of line segment x and y - coordinate where testString is supposed to be drawn (note doesn't draw testString) scaleX scaleY - scale factors in pixels to multiple letters height and width by testString - string to check intersection with lineModeFlag - says whether to draw line or only its endpoints. RETURNS: nothing REMARKS: */ { GLfloat curX = x; GLfloat curY = y; priority_queue<ScreenPt> intersectPts; int len = testString.size(); //avoid dereferencing more than once int numLetters = _letters.size(); bool drawSucceed; for(int i = 0; i < len ; i++) { drawSucceed = false; for(int j = 0; j < numLetters; j++) { if(_letters[j].canDraw(testString[i])) /*linear search.. So fast! Not!! Actually given the small number of letters in most alphabets could be. */ { drawSucceed = true; _letters[j].getIntersectEdges(intersectPts, p1, p2, curX, curY, scaleX, scaleY); curX += scaleX*_letters[j].width(); } } if(!drawSucceed) throw string("Letter: ") + testString[i] + " is not drawable."; } GLint lineX = p1.getx(), lineY = p1.gety(), tmpX, tmpY; bool isRed = true; ScreenPt tmpPt; glColor3f(1.0, 0.0, 0.0); glPointSize(drawSize); glBegin(GL_POINTS); glVertex2i(lineX, lineY); glEnd(); glPointSize(1); if(intersectPts.empty() && lineModeFlag) { lineBres(lineX, lineY, p2.getx(), p2.gety()); } while(intersectPts.size() > 0) { tmpPt=intersectPts.top(); tmpPt.setCoords(tmpPt.getx()+p1.getx(), tmpPt.gety()+p1.gety()); intersectPts.pop(); if(lineModeFlag) { tmpX = tmpPt.getx(); tmpY = tmpPt.gety(); lineBres(lineX, lineY, tmpX, tmpY); glFlush(); lineX = tmpX; lineY = tmpY; } isRed = (isRed) ? false : true; if(isRed) { glColor3f(1.0, 0.0, 0.0); } else { glColor3f(0.0, 0.0, 1.0); } } if( lineModeFlag) { lineBres(lineX, lineY, p2.getx(), p2.gety()); } glPointSize(drawSize); glBegin(GL_POINTS); glVertex2i(p2.getx(), p2.gety()); glEnd(); } /*-----------------------------------------------*/ void setPixel(GLint x, GLint y) /* PURPOSE: Draw a pixel at desired location on screen RECEIVES: x,y - coordinates of pixel to draw RETURNS: nothing REMARKS: side-effect is pixel drawn */ { glBegin(GL_POINTS); glVertex2i(x, y); glEnd(); } /*-----------------------------------------------*/ inline GLint crossProduct(ScreenPt p0, ScreenPt p1) /* PURPOSE: Takes the 2D cross-product of supplied points. RECEIVES: p0, p1 - points to take cross product of RETURNS: p0 X p1 REMARKS: inlined for speed */ { return p0.getx()*p1.gety() - p1.getx()*p0.gety(); } /*-----------------------------------------------*/ bool containedBox(GLint x, GLint y, ScreenPt corner1, ScreenPt corner2) /* PURPOSE: checks if (x,y) is in the rectangle with the given corners RECEIVES: x, y- coordinates of point to check, corner1, corner2 - points for rectangle RETURNS: true - if is inside REMARKS: */ { GLint x1 = corner1.getx(), y1 = corner1.gety(); GLint x2 = corner2.getx(), y2 = corner2.gety(); if(((x1 <= x && x2 >= x) || (x1 >= x && x2 <= x) ) && ((y1 <= y && y2 >= y) || (y1 >= y && y2 <= y))) return true; return false; } /*-----------------------------------------------*/ void orderPtX(ScreenPt& p1, ScreenPt& p2) /* PURPOSE: arranges two points according to which has smaller x value RECEIVES: p1 and p2 - points to arrange RETURNS: nothing REMARKS: */ { if(p1.getx() > p2.getx()) { ScreenPt tmp; tmp = p1; p1 = p2; p2 = tmp; } } /*-----------------------------------------------*/ void orderPtY(ScreenPt& p1, ScreenPt& p2) /* PURPOSE: arranges two points according to which has smaller y value RECEIVES: p1 and p2 - points to arrange RETURNS: nothing REMARKS: */{ if(p1.gety() > p2.gety()) { ScreenPt tmp; tmp = p1; p1 = p2; p2 = tmp; } } /*-----------------------------------------------*/ inline GLint sgn(GLint x) /* PURPOSE: computes the sign of x RECEIVES: number to compute sign of RETURNS: sign of the number (i.e., +1 or -1) REMARKS: */ { return (x > 0)? 1 : -1; } /*-----------------------------------------------*/ int intersect(ScreenPt edge1p1, ScreenPt edge1p2, ScreenPt edge2p1, ScreenPt edge2p2, GLint& crossX, GLint& crossY ) /* PURPOSE: checks if two edges intersect RECEIVES: endpts of the two edges and two GLint's to store intersection point in RETURNS: 1 if intersect 0 if intersect at an endpt -1 if don't intersect REMARKS: side effect is crossX and crossY set to intersection point */ { //1st try to rule out collisions by sorting on x and y coordinates orderPtY(edge1p1, edge1p2); orderPtY(edge2p1, edge2p2); if(edge1p2.gety() < edge2p1.gety() || edge2p2.gety() < edge1p1.gety()) return -1; orderPtX(edge1p1, edge1p2); orderPtX(edge2p1, edge2p2); if(edge1p2.getx() < edge2p1.getx() || edge2p2.getx() < edge1p1.getx()) return -1; if(edge1p2.getx() == edge2p1.getx() && edge1p2.gety() == edge2p1.gety()) //intersect at an end pt { crossX = edge1p2.getx(); crossY = edge1p2.gety(); return 0; } /*if crosses line crossed edge then turn direction when go from one from one endpt to line to other endpt. we check this cross products */ GLint e1p1x = edge1p1.getx(), e1p2x = edge1p2.getx(); GLint e1p1y = edge1p1.gety(), e1p2y = edge1p2.gety(); GLint e2p1x = edge2p1.getx(), e2p2x = edge2p2.getx(); GLint e2p1y = edge2p1.gety(), e2p2y = edge2p2.gety(); ScreenPt leftE = ScreenPt(e2p1x - e1p1x, e2p1y - e1p1y); ScreenPt rightE = ScreenPt(e2p2x - e1p1x, e2p2y - e1p1y); ScreenPt edge = ScreenPt(e1p2x - e1p1x, e1p2y - e1p1y); ScreenPt edge2 = ScreenPt(e2p2x - e2p1x, e2p2y - e2p1y); if(sgn(crossProduct(leftE, edge))*sgn(crossProduct(edge, rightE)) < 0) return -1; GLfloat m = (GLfloat)(edge.gety())/edge.getx(); GLfloat m2 = (GLfloat)(edge2.gety())/edge2.getx(); /* Now find intersection. Check a bunch of special cases (probably could simplify a lot) */ if(m == m2) // both edges have same slope { crossX = e1p2x; crossY = e1p2y; } else if(edge.getx() == 0) // parallel infinite slope lines { crossX = e1p1x; if(edge2.getx() > 0) { crossY = (GLint)(m2*(GLfloat)(crossX - e2p1x) + e2p1y); return 1; } else { if(containedBox(crossX, e2p1y, edge2p1, edge2p2)) { crossY = e2p1y; return 1; } if(containedBox(crossX, e2p2y, edge2p1, edge2p2)) { crossY = e2p2y; return 1; } return -1; } } else if(edge2.getx() == 0) { crossX = e2p1x; if(edge.getx() > 0) { crossY = (GLint)(m*(GLfloat)(crossX - e1p1x) +e1p1y); return 1; } else { if(containedBox(crossX, e1p1y, edge1p1, edge1p2)) { crossY = e1p1y; return 1; } if(containedBox(crossX, e1p2y, edge1p1, edge1p2)) { crossY = e1p2y; return 1; } return -1; } } else { crossX = (GLint)((e2p1y - e1p1y + m*(GLfloat)e1p1x - m2*(GLfloat)e2p1x)/(m-m2)); crossY = (GLint)(m*(GLfloat)(crossX - e1p1x) + e1p1y); } return 1; } /*-----------------------------------------------*/ void lineBres(int x0, int y0, int xEnd, int yEnd) /* PURPOSE: Draws a line segment from (x0, y0) to (xEnd, yEnd) using my implementation Bresenham's algorithm RECEIVES: x0, y0 - start point of line segment xEnd, yEnd - end point of line segment RETURNS: nothing REMARKS: Side-effect is the line segment drawn Note basically hacked the books code to handle negative slopes and slopes with large magnitude. Right now it makes too many flag type checks. Could easily be optimized. */ { int dx = abs(xEnd - x0), dy = abs(yEnd - y0); int p; int twoD, twoDMinusD; int x,y, *a, *b, *a0, *aEnd; int slopeSign = ((xEnd - x0)*(yEnd - y0) > 0) ? 1 : -1; if(dx > dy)//added by me to books algorithm { a = &x; b = &y; a0 = &x0; aEnd = &xEnd; p = 2*dy -dx; twoD = 2*dy; twoDMinusD = 2*(dy-dx); } else { a = &y; b = &x; a0 = &y0; aEnd = &yEnd; p = 2*dx - dy; twoD = 2*dx; twoDMinusD = 2*(dx-dy); } if(*a0 > *aEnd) { x = xEnd; y = yEnd; *aEnd = *a0; } else { x = x0; y = y0; } setPixel(x, y); while(*a < *aEnd) { (*a)++; if(p < 0) { p += twoD; } else { (*b) += slopeSign; p += twoDMinusD; } setPixel(x, y); } } /*-----------------------------------------------*/ void polyLineBres(vector<ScreenPt>& pts, vector<bool>& drawableEdges) /* PURPOSE: Draws a polyline using my implmentation of Bresenham's algorithm RECEIVES: pts - vector of points to draw RETURNS: nothing REMARKS: Has side-effect of drawing the poly-line to the screen Assumes that both vectors are of the same length */ { int len = pts.size(); for(int i = 0; i < len - 1; i++) { if(drawableEdges[i+1]) lineBres(pts[i].getx(), pts[i].gety(), pts[i+1].getx(), pts[i+1].gety()); } } /* GLUT AND DRIVER CODE */ /*-----------------------------------------------*/ void drawNameVowels(void) /* PURPOSE: GLUT display callback function for this program. Serves as the main driver for the program. Initializes a LetterProcessor font and adds the neccessary letters (In this case only ngii) to it Finally, draws the desired strings (This case scaled to whole screen). RECEIVES: nothing RETURNS: nothing REMARKS: Side-effect is to draw ngii to the screen as well as two points that are testing if are interior or exterior to the ngii */ { LetterProcessor font; string ngii = "c .16 .7 .125 0 6.28 c .16 .7 .025 0 6.28"; ngii += " c .34 .525 .125 0 6.28 c .34 .525 .025 0 6.28"; ngii += " c .7 .6 .2 4.71 7.85 c .7 .6 .1 4.71 7.85"; ngii += " l 4 .5 .6 .5 .1 .6 .1 .6 .6 l 4 .8 .6 .8 .5 .9 .5 .9 .6"; ngii += " c .7 .9 .05 0 6.28"; font.add(Letter('n', 1, ngii)); // Set up how we draw the points. GLfloat sizes[2]; // Store supported point size range GLfloat step; // Store supported point size increments // Get supported point size range and step size glGetFloatv(GL_POINT_SIZE_RANGE,sizes); glGetFloatv(GL_POINT_SIZE_GRANULARITY,&step); // Specify the point size drawSize = (winWidth < winHeight) ? winWidth/50 : winHeight/50; if(drawSize > sizes[1]) drawSize = sizes[1]; glPointSize(drawSize); glClear(GL_COLOR_BUFFER_BIT); glColor3f(1.0, 0.0, 0.0); //here's where we draw the strings to the screen try { font.draw(0, 0, winWidth, winHeight, string("n")); font.drawIntersectEdges(pt1, pt2, 0, 0, winWidth, winHeight, string("n"), lineModeFlag); } catch(string error) { cerr << error << endl; } glFlush(); } /*-----------------------------------------------*/ void winReshapeFn(int newWidth, int newHeight) /* PURPOSE: Resizes/redisplays the contents of the current window RECEIVES: newWidth, newHeight -- the new dimensions RETURNS: nothing REMARKS: Notice resize viewport */ { winWidth = newWidth; winHeight = newHeight; glViewport(0, 0, newWidth, newHeight); glClearColor(1.0, 1.0, 1.0, 0.0); glClear(GL_COLOR_BUFFER_BIT); glLoadIdentity(); gluOrtho2D(0.0, winWidth, 0.0, winHeight); drawNameVowels(); } /*-----------------------------------------------*/ void keyHandleFn(int key, int x, int y) /* PURPOSE: Handles keyboard events. The keyboard was very useful in testing this project RECEIVES: key - the special key (non a-z letter) pressed x - screen X position y - screen Y position RETURNS: nothing REMARKS: */ { ScreenPt *tmp; switch(key) { case 27: //escape key tmp = pactivePt; pactivePt = ppassivePt; ppassivePt = tmp; break; case ' ': lineModeFlag = (lineModeFlag)? false : true; break; case GLUT_KEY_LEFT: pactivePt->decx(); break; case GLUT_KEY_RIGHT: pactivePt->incx(); break; case GLUT_KEY_UP: pactivePt->incy(); break; case GLUT_KEY_DOWN: pactivePt->decy(); break; } glutPostRedisplay(); } /*-----------------------------------------------*/ void keyHandleFn1(unsigned char key, int x, int y) /* PURPOSE: Handles keyboard events like space and esc. The keyboard was very useful in testing this project RECEIVES: key - the special key (non a-z letter) pressed x - screen X position y - screen Y position RETURNS: nothing REMARKS: */ { ScreenPt *tmp; switch(key) { case 27: //escape key tmp = pactivePt; pactivePt = ppassivePt; ppassivePt = tmp; break; case ' ': lineModeFlag = (lineModeFlag)? false : true; break; } glutPostRedisplay(); } /*-----------------------------------------------*/ void readParameters() /* PURPOSE: Reads Parameter file with initial window size and two points position RECEIVES: nothing RETURNS: nothing REMARKS: */ { ifstream fin; int tmpX1, tmpY1, tmpX2, tmpY2; try { fin.open("parameters.txt"); if(fin.fail()) throw string("Failed to open parameters.txt"); if(!(fin >> winWidth >> winHeight >> tmpX1 >> tmpY1 >> tmpX2>> tmpY2)) { fin.close(); throw string("parameters.txt format incorrect"); } fin.close(); } catch(string error) { cerr << error << endl; cerr << "Using default values" << endl; tmpX1 = 0; tmpY1 = 0; tmpX2 = winWidth; tmpY2 = winHeight; } pt1.setCoords(tmpX1, tmpY1); pt2.setCoords(tmpX2, tmpY2); } /*-----------------------------------------------*/ void init(void) /* PURPOSE: Used to initializes our OpenGL window and set up pt pointers for keyboard handler RECEIVES: Nothing RETURNS: Nothing REMARKS: Nothing */ { glClearColor(1.0, 1.0, 1.0, 0.0); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluOrtho2D(0.0, winWidth, 0.0, winHeight); /* note don't set default viewport size as will by default be whole window*/ pactivePt = &pt1; ppassivePt = &pt2; } int main(int argc, char** argv) { readParameters(); glutInit(&argc, argv); glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB); glutInitWindowPosition(50, 100); glutInitWindowSize(winWidth, winHeight); glutCreateWindow("Odd Even Rule Tester"); init(); //Set up drawing callbacks glutDisplayFunc(drawNameVowels); glutReshapeFunc(winReshapeFn); //Set up keyboard handlers glutSpecialFunc(keyHandleFn); // for arrow keys glutKeyboardFunc(keyHandleFn1); // for space esc //Start main loop glutMainLoop(); return 0; } |