// Include Files #include #include #include #include #include "trulla.h" #include "loadws.h" #include "tr2robot.h" // External Declarations extern float feetPerGridel; extern int showGrid; extern int maxInt; extern float maxFloat; extern int outputLine; extern int sizeOfCharInPix; extern int optionsLine; extern int gridelOffset; extern int xOffsetInPix, yOffsetInPix; // offset to cell center from upper left of cell extern int currCellXInPix, currCellYInPix; extern int maxXCoord, maxYCoord; extern int cellWidthInPix, cellHgtInPix; extern int currCellX, currCellY; extern int goalCellX, goalCellY; extern int wsWidthInCells, wsHgtInCells; extern int pathsAreDisplayed; extern GRIDEL * gridPtr; extern void ReDrawGrid (); extern void DrawGrid (); extern void DisplayOptions (); extern void DrawGoalIndicator (); extern void ColorCell ( int left, int top, int right, int bottom, GRIDEL * tempGridPtr ); extern void FeetToGridels ( LOCATION * locationInFeet, LOCATION * locationInGridels ); extern void GeneratePaths (); // Globals float toleranceInFeet; LOCATION * goalLocation; struct textsettingstype far textinfo; struct palettetype far graypal; // Function Prototypes void ClearDisplay (); int GetNextCell ( int haveCurrCell ); void DrawCurrentLocation ( LOCATION * currLocInGridels ); void InitGraphics (); void GetMaxCoords (); void DefineGrayScale (); void MoveLeft (); void MoveRight (); void MoveUp (); void MoveDown (); ///////////////////////////////////////////////////////////////////// // Function: InitializeDisplay // Purpose: Initializes the graphics system, calculates the maximum // allowable coordinates for the grid display, and defines the // gray scale for use in coloring the cells of the grid. ///////////////////////////////////////////////////////////////////// void InitializeDisplay () { InitGraphics (); GetMaxCoords (); DefineGrayScale (); } ///////////////////////////////////////////////////////////////////// // Function: InitGraphics // Purpose: Automatically detects the graphics driver and initializes // the graphics system. If an error occurs during initialization, // report this and exit the program. ///////////////////////////////////////////////////////////////////// void InitGraphics () { int gmode, errorcode; int gdriver = DETECT; // initialize graphics mode initgraph(&gdriver, &gmode, "C:\\BORLANDC\\BGI"); // read result of initialization errorcode = graphresult(); if (errorcode != grOk) // an error occurred { printf("Graphics error: %s\n", grapherrormsg(errorcode)); printf("Press any key to halt:"); getch(); exit (BADEXIT); // return with error code } } ///////////////////////////////////////////////////////////////////// // Function: GetMaxCoords // Purpose: The maxXCoord and maxYCoord variables define the maximum // allowable coordinates on the screen for drawing the workspace // grid. The rectangle bounding the grid extends from (0,0) (upper // left) to (maxXCoord,maxYCoord) (lower right). Lines at the // bottom of the screen are used to display the user options and // the statistics line; this space, therefore, is removed from the // allowable grid space. In addition, the y coordinates // for these two lines are calculated. ///////////////////////////////////////////////////////////////////// void GetMaxCoords () { gettextsettings (&textinfo); // gets charsize needed for DisplayOptions() // The charsize data item of the textinfo structure is multiplied by 8 // because the bit-mapped fonts is 8x8. The value of textinfo.charsize // indicates how many times bigger than this size the character is. If, // for example, textinfo.charsize is 1, then the characters display in an // 8x8 box; if it's 2, then a 16x16 size box is used... See the Borland // help information on "textsettingstype" then "charsize". sizeOfCharInPix = 8 * textinfo.charsize; maxXCoord = getmaxx(); maxYCoord = getmaxy() - 3 * sizeOfCharInPix; // remove 3 lines from bottom optionsLine = maxYCoord + sizeOfCharInPix; outputLine = optionsLine + sizeOfCharInPix; } //////////////////////////////////////////////////////////////////// // Function: DefineGrayScale // Purpose: Define the palette colors to be a gray scale from // black (0) to white (MAXWGT). MAXWGT is currently set to 15. // This accommodates the current allowable gridel weights of 1 to 9 // and 'x' ('x', indicating an obstacle, is read from the workspace // file and is stored as 15 in the weight variables.) No provisions // have been made in the program to allow for more than 15 different // weights. // The gray scale lightens as the palette color numbers increase; // however, traversal of gridels becomes more difficult with // increasing weights. An attempt to define the gray scale from // white (0) to black (MAXWGT) resulted in an unattractive white // border at the edges of the screen. A simpler fix was to leave // the gray scale as currently defined (black to white) and do a // calculation where necessary to obtain a gray color which more // appropriately represents the gridel weight. ///////////////////////////////////////////////////////////////////// void DefineGrayScale () { getpalette (&graypal); for ( int i = 0; i < MAXWGT; i++ ) setrgbpalette ( graypal.colors[i], i*4, i*4, i*4 ); } //////////////////////////////////////////////////////////////////// // Function: ClearDisplay // Purpose: Erases paths on the grid by redrawing the grid and // erases the goal indicator in the current goal cell. This // function is used when the goal indicator is being moved // to another location. ///////////////////////////////////////////////////////////////////// void ClearDisplay () { if ( pathsAreDisplayed ) { ReDrawGrid (); pathsAreDisplayed = 0; } ColorCell ( currCellXInPix, currCellYInPix, currCellXInPix + cellWidthInPix, currCellYInPix + cellHgtInPix, gridPtr + gridelOffset ); } ///////////////////////////////////////////////////////////////////// // Function: MoveUp // Purpose: Moves the goal indicator up the grid one cell. ///////////////////////////////////////////////////////////////////// void MoveUp () { if ( currCellY > 0 ) { ClearDisplay (); gridelOffset -= wsWidthInCells; currCellY--; currCellYInPix -= cellHgtInPix; DrawGoalIndicator (); } } ///////////////////////////////////////////////////////////////////// // Function: MoveDown // Purpose: Moves the goal indicator down the grid one cell. ///////////////////////////////////////////////////////////////////// void MoveDown () { if ( currCellY + 1 < wsHgtInCells ) { ClearDisplay(); gridelOffset += wsWidthInCells; currCellY++; currCellYInPix += cellHgtInPix; DrawGoalIndicator (); } } ///////////////////////////////////////////////////////////////////// // Function: MoveLeft // Purpose: Moves the goal indicator to the left by one cell. ///////////////////////////////////////////////////////////////////// void MoveLeft () { if ( currCellX > 0 ) { ClearDisplay(); gridelOffset--; currCellX--; currCellXInPix -= cellWidthInPix; DrawGoalIndicator (); } } ///////////////////////////////////////////////////////////////////// // Function: MoveRight // Purpose: Moves the goal indicator to the right by one cell. ///////////////////////////////////////////////////////////////////// void MoveRight () { if ( currCellX + 1 < wsWidthInCells ) { ClearDisplay(); gridelOffset++; currCellX++; currCellXInPix += cellWidthInPix; DrawGoalIndicator (); } } ///////////////////////////////////////////////////////////////////// // Function: DrawCurrentLocation // Purpose: This function was intended to test the robot interface // functions. It draws an indicator "==" in the current cell // to show the path that the robot follows to move from one // subgoal to another. ///////////////////////////////////////////////////////////////////// void DrawCurrentLocation ( LOCATION * currLocInGridels ) { int tempGridelOffset; int currXLocInPix, currYLocInPix; tempGridelOffset = (int) currLocInGridels->y * wsWidthInCells + (int) currLocInGridels->x; if ( (gridPtr+tempGridelOffset)->r_weight <= 5 ) setcolor ( BLACK ); else setcolor ( WHITE ); currXLocInPix = (int) currLocInGridels->x * cellWidthInPix + xOffsetInPix; currYLocInPix = (int) currLocInGridels->y * cellHgtInPix + yOffsetInPix - 10; outtextxy ( currXLocInPix, currYLocInPix, "==" ); } ///////////////////////////////////////////////////////////////////// // Function: GetNextCell // Purpose: This function was intended to test the robot interface // functions. It allows manual input of the robot's current // location. Each time this function is called, it finds the // next subgoal and advances the current location to this subgoal // until the goal is reached. ///////////////////////////////////////////////////////////////////// int GetNextCell ( int haveCurrCell ) { LOCATION * currLocInFeet; LOCATION currLocInGridels; DISPLACEMENT * subgoalDispInFeet; int tempGridelOffset; if ( !haveCurrCell ) { printf("Enter curr cell: "); scanf("%f %f", &(currLocInFeet->x), &(currLocInFeet->y)); FeetToGridels ( currLocInFeet, &currLocInGridels ); tempGridelOffset = (int) currLocInGridels.y * wsWidthInCells + (int) currLocInGridels.x; if ( (gridPtr+tempGridelOffset)->r_weight != MAXWGT && ! ( (gridPtr+tempGridelOffset)->delx == 0 && (gridPtr+tempGridelOffset)->dely == 0 ) ) { DrawCurrentLocation ( &currLocInGridels ); haveCurrCell = 1; } printf("Enter tolerance: "); scanf("%f", &(toleranceInFeet)); } if ( NextSubgoal ( currLocInFeet, subgoalDispInFeet ) ) { AdvanceCurrLocation ( currLocInFeet, subgoalDispInFeet ); FeetToGridels ( currLocInFeet, &currLocInGridels ); DrawCurrentLocation ( &currLocInGridels ); if ( IsGoal (goalLocation, currLocInFeet, toleranceInFeet) ) { printf ("REACHED GOAL\n"); haveCurrCell = 0; } } else { haveCurrCell = 0; printf ("NO SUBGOAL\n"); } return ( haveCurrCell ); } ///////////////////////////////////////////////////////////////////// // Function: Trulla // Purpose: This is the main trulla function. It can be called // by a driver program. (See modules RUNTRULLA.CPP for an example // of how this is done.) ///////////////////////////////////////////////////////////////////// void Trulla () { int choice; int haveCurrCell = 0; showGrid = 1; pathsAreDisplayed = 0; InitializeDisplay (); LoadFile(NULL); do { choice = getch(); switch ( choice ) { case 'R' : case 'r' : printf ("Enter goal location: "); scanf ( "%f %f", &(goalLocation->x), &(goalLocation->y) ); SetGoal ( goalLocation ); break; case 'N' : case 'n' : if ( pathsAreDisplayed ) { haveCurrCell = GetNextCell ( haveCurrCell ); //haveCurrCell could get changed } break; case 'L' : case 'l' : // load a new workspace file LoadFile (NULL); break; case 72 : // up arrow MoveUp (); break; case 75 : // left arrow MoveLeft (); break; case 77 : // right arrow MoveRight (); break; case 80 : // down arrow MoveDown (); break; // generate a path if the goal has changed or if the cell is not an obstacle case 'G' : case 'g' : if ( (goalCellX != currCellX || goalCellY != currCellY) && (gridPtr+gridelOffset)->r_weight != MAXWGT ) { GeneratePaths (); pathsAreDisplayed = 1; goalLocation->x = goalCellX * feetPerGridel; goalLocation->y = goalCellY * feetPerGridel; } break; } } while ( choice != 'Q' && choice != 'q' ); closegraph(); }