// This is a code fragment demonstrating a 3-d stereographic projection // It is not compilable as is, you will have to incorporate it into // your program. /*****************************************************************************************************/ // put this in header file #define _MAX_STARNAME 15 // 15 characters for starname #define SX 640 // resulting picture is 640 pixels horizontally #define SY 480 // resulting picture is 480 pixels vertically #define SCX (SX/2) // center of the picture X #define SCY (SY/2) // center of the picture Y // in cross eyed and wide eyed methods, there are two pictures displayed // side by side. "Stereo pairs" #define SCXL (SX/4) // center of left picture X #define SCXR (SCX+SCXL) // center of right picture X #define CROSSEYE 0 // stereo pairs using cross-eyed method #define WIDEEYE 1 // stereo pairs using wide-eyed method #define ANAGLYPH 2 // red-blue anaglyph image #define NO3D 3 // no 3-d, just a flat image #define LEFT 0 #define RIGHT 1 // anaglyph colors #define REDCOLOR RGB(255,0,0) #define BLUECOLOR RGB(0,255,255) #define BLACKCOLOR RGB(0,0,0) struct TriPoint { double x; double y; double z; }; struct StarNode { char starName[_MAX_STARNAME+1]; TriPoint loc; }; // global variables StarNode starList[100]; // make this into a linked list or other // dynamically allocated data structure TriPoint eye[100][2]; // ditto. double scaleFactor; // magnification of resulting image short numStars; // number of stars in starList short viewMode; // cross-eyes, anaglyph, or whatever TriPoint from[2]; TriPoint at,up; double viewAngle,theta,kval; short scxLeftEye[2]; short scxRightEye[2]; /*****************************************************************************************************/ // insert this into the initialization section scxLeftEye[CROSSEYE] = SCXR; scxRightEye[CROSSEYE] = SCXL; scxLeftEye[WIDEEYE] = SCXL; scxRightEye[WIDEEYE] = SCXR; scaleFactor = 75.0; viewMode = CROSSEYE; from[LEFT].x = -0.5; // hovering above x-y plane, eye separation 1.0 from[LEFT].y = 0.0; from[LEFT].z = 5.0; from[RIGHT].x = 0.5; from[RIGHT].y = 0.0; from[RIGHT].z = 5.0; at.x = 0.0; at.y = 0.0; at.z = 50.0; // this seems to make a better perpective than 0.0 up.x = 0.0; up.y = 1.0; up.z = 0.0; viewAngle = 60; theta = MakeRadians(viewAngle); dval = cos(theta / 2) / sin(theta / 2); // you will have to create code to allow user to set the scaleFactor, viewMode, // from, at, up, and viewAngle variables. Remember to recalculate theta // and dval if viewAngle is changed, as is done above. // read in star data double _x,_y,_z; char _starName[_MAX_STARNAME+1]; FILE *datafile; char instring[258]; numStars = -1; datafile = fopen("STEREO.DAT", "r"); while (fgets(instring, 258, datafile)) { // insert code to load _starName, _x, _y, and _z from instring numStars++; strcpy(starList[numStars].starName,_starName); starList[numStars].loc.x = _x; starList[numStars].loc.y = _y; starList[numStars].loc.z = _z; } fclose(datafile); CalcEye(); } /*****************************************************************************************************/ // insert this into section that draws the screen short a; if ((viewMode == CROSSEYE) || (viewMode == WIDEEYE)) { // draw a vertical line separating the two stereo pairs MoveTo(SCX,0); LineTo(SCX,SY); } for (a = 0; a <= numStars; a++) { switch (viewMode) { case NO3D: PlotStar(a); break; case CROSSEYE: case WIDEEYE: PlotStarCrossWide(a); break; case ANAGLYPH: PlotStarAnaglyph(a); break; } } /*****************************************************************************************************/ void PlotStar(short starNum) { short plotX,plotY; double px,py; char buffer[80]; plotX = (starList[starNum].loc.x * scaleFactor) + SCX; plotY = SY - ((starList[starNum].loc.y * scaleFactor) + SCY); // make a 11x11 cross at the plot position MoveTo(plotX, plotY-5); LineTo(plotX, plotY+6); MoveTo(plotX-5, plotY); LineTo(plotX+6, plotY); // print the star name next to it wsprintf(buffer,"%s",starList[starNum].starName); TextOut(paintDCH, plotX+3, plotY-11, buffer, lstrlen(buffer)); } /*****************************************************************************************************/ void PlotStarCrossWide(short starNum) { short plotX,plotY; char buffer[80]; wsprintf(buffer,"%s",starList[starNum].starName); // draw left eye's image plotX = (eye[starNum][LEFT].x * scaleFactor) + scxLeftEye[viewMode]; plotY = SY - ((eye[starNum][LEFT].y * scaleFactor) + SCY) ; if (((viewMode == CROSSEYE) && (plotX > SCX)) || ((viewMode == WIDEEYE) && (plotX < SCX))) { MoveTo(plotX, plotY-5); LineTo(plotX, plotY+6); MoveTo(plotX-5, plotY); LineTo(plotX+6, plotY); TextOut(plotX+3, plotY-11, buffer, lstrlen(buffer)); } // draw right eye's image plotX = (eye[starNum][RIGHT].x * scaleFactor) + scxRightEye[viewMode]; plotY = SY - ((eye[starNum][RIGHT].y * scaleFactor) + SCY) ; if (((viewMode == CROSSEYE) && (plotX < SCX)) || ((viewMode == WIDEEYE) && (plotX > SCX))) { MoveTo(plotX, plotY-5); LineTo(plotX, plotY+6); MoveTo(plotX-5, plotY); LineTo(plotX+6, plotY); TextOut(plotX+3, plotY-11, buffer, lstrlen(buffer)); } } /*****************************************************************************************************/ void PlotStarAnaglyph(short starNum) { short plotX,plotY; char buffer[80]; wsprintf(buffer,"%s",starList[starNum].starName); plotX = (eye[starNum][LEFT].x * scaleFactor) + SCX; plotY = SY - ((eye[starNum][LEFT].y * scaleFactor) + SCY) ; // insert code to make pen draw in red MoveTo(paintDCH, plotX, plotY-5); LineTo(paintDCH, plotX, plotY+6); MoveTo(paintDCH, plotX-5, plotY); LineTo(paintDCH, plotX+6, plotY); TextOut(paintDCH, plotX+3, plotY-11, buffer, lstrlen(buffer)); plotX = (eye[starNum][RIGHT].x * scaleFactor) + SCX; plotY = SY - ((eye[starNum][RIGHT].y * scaleFactor) + SCY) ; // insert code to make pen draw in blue MoveTo(paintDCH, plotX, plotY-5); LineTo(paintDCH, plotX, plotY+6); MoveTo(paintDCH, plotX-5, plotY); LineTo(paintDCH, plotX+6, plotY); TextOut(paintDCH, plotX+3, plotY-11, buffer, lstrlen(buffer)); // insert code to make pen draw in black } /*****************************************************************************************************/ void Calc3D(short eyeID) { short a; TriPoint aPrime,a1,a2,a3,temp,eyeC; double aPrimeMag, tempMag; double offX, offY, offZ; double ex,ey; aPrime = Subtract(&at, &from[eyeID]); aPrimeMag = Mag(&aPrime); a3 = Divide(&aPrime, aPrimeMag); temp = Cross(&aPrime, &up); tempMag = Mag(&temp); a1 = Divide(&temp, tempMag); temp = Cross(&aPrime, &up); temp = Cross(&temp, &aPrime); tempMag = Mag(&temp); a2 = Divide(&temp, tempMag); offX = -a1.x * from[eyeID].x - a1.y * from[eyeID].y - a1.z * from[eyeID].z; offY = -a2.x * from[eyeID].x - a2.y * from[eyeID].y - a2.z * from[eyeID].z; offZ = -a3.x * from[eyeID].x - a3.y * from[eyeID].y - a3.z * from[eyeID].z; for (a = 0; a <= numStars; a++) { eyeC.x = (starList[a].loc.x * a1.x) + (starList[a].loc.y * a1.y) + (starList[a].loc.z * a1.z) + offX; eyeC.y = (starList[a].loc.x * a2.x) + (starList[a].loc.y * a2.y) + (starList[a].loc.z * a2.z) + offY; eyeC.z = (starList[a].loc.x * a3.x) + (starList[a].loc.y * a3.y) + (starList[a].loc.z * a3.z) + offZ; ex = eyeC.x * dval; if (eyeC.z != 0) ex = ex / eyeC.z; ey = eyeC.y * dval; if (eyeC.z != 0) ey = ey / eyeC.z; eye[a][eyeID].x = ex; eye[a][eyeID].y = ey; } } /*****************************************************************************************************/ void CalcEye() { Calc3D(LEFT); Calc3D(RIGHT); } /*****************************************************************************************************/ double Mag(TriPoint *v) { return sqrt((v->x * v->x) + (v->y * v->y) + (v->z * v->z)); } /*****************************************************************************************************/ TriPoint Subtract(TriPoint *v1, TriPoint *v2) { TriPoint c; c.x = v1->x - v2->x; c.y = v1->y - v2->y; c.z = v1->z - v2->z; return c; } /*****************************************************************************************************/ TriPoint Cross(TriPoint *v1, TriPoint *v2) { TriPoint c; c.x = v1->y * v2->z - v2->y * v1->z; c.y = v1->z * v2->x - v2->z * v1->x; c.z = v1->x * v2->y - v2->x * v1->y; return c; } /*****************************************************************************************************/ TriPoint Divide(TriPoint *v, double num) { TriPoint result; result.x = v->x; result.y = v->y; result.z = v->z; if (num != 0) { result.x = v->x / num; result.y = v->y / num; result.z = v->z / num; } return result; } /*****************************************************************************************************/ double MakeRadians(double degrees) { return degrees * 0.017453293; } /*****************************************************************************************************/