/* This file contains the definition of class CartesianSystem

---------------------------------------------------------------*/

#include <iostream.h>                       // interactive I/O
#include <stdlib.h>                         // exit()
#include <stdio.h>                          // sprintf()

#include "CartSys.h"

/* EnterGraphicsMode initializes the display for graphics

---------------------------------------------------------------*/

void EnterGraphicsMode(char GraphicsPath[])
{
   int
      GraphDriver = DETECT;
   int
      GraphMode;

   initgraph(&GraphDriver, &GraphMode, GraphicsPath);

   int
      GraphError = graphresult();

   if (GraphError != grOk)
   {
      cerr << "\nStartGraphics Error: "
         << grapherrormsg(GraphError) << "\n\n";
      exit (-1);
   }
}

/* --- DisplayMsg puts a message in the bottom margin.

   Receive: Msg, a character string to be displayed.
   Output:  Msg, within the cartesian system margin.
-------------------------------------------------------------------*/

void CartesianSystem::DisplayMsg(char* Msg)
{
   settextjustify(CENTER_TEXT,BOTTOM_TEXT);
   settextstyle(DEFAULT_FONT, HORIZ_DIR, 1);
   outtextxy(getmaxx()/2, getmaxy(), Msg);
}

/* --- DrawAxes displays labeled x and y axes ----------

   Output: Labeled x and y axes, appropriately scaled.
-------------------------------------------------------*/

void CartesianSystem::DrawAxes(void)
{
   line(0, xAxisRow, LastCol, xAxisRow);                // x-axis
   line(yAxisCol, 0, yAxisCol, LastRow-BottomMargin);   // y-axis

   char Buffer[12];                                      // label axes
   const int Offset = 5;
   int PixelX, PixelY;

   settextstyle(SMALL_FONT, HORIZ_DIR, 3);
   settextjustify(RIGHT_TEXT, CENTER_TEXT);
   for (double y = yMax; y >= yMin; y -= yAxisIncrement)
   {
      if ((y > yAxisIncrement/2.0) || (y < (-yAxisIncrement)/2.0))
      {
         PixelY = yToRow(y);
         line(yAxisCol-Offset, PixelY, yAxisCol+Offset, PixelY);
         sprintf(Buffer, "%.3f", y);
         outtextxy(yAxisCol-Offset, PixelY, Buffer);
      }
   }

   settextjustify(CENTER_TEXT, TOP_TEXT);
   for (double x = xMin; x <= xMax; x += xAxisIncrement)
   {
      if ((x > xAxisIncrement/2.0) || (x < (-xAxisIncrement)/2.0))
      {
         PixelX = xToCol(x);
         line(PixelX, xAxisRow-Offset, PixelX, xAxisRow+Offset);
         sprintf(Buffer, "%.3f", x);
         outtextxy(PixelX, xAxisRow+Offset, Buffer);
      }
   }
}

/* --- Class Constructor-----------------------------------------

   Pre:     A CartesianSystem object has been declared.
   Receive: The extrema for the x, y, and z axes.
   Post:    The screen has been initialized to display
              a cartesian system with the given extrema.
----------------------------------------------------------------*/

CartesianSystem::CartesianSystem(double xLo, double xHi,
                                 double yLo, double yHi,
                                 double zLo, double zHi)
{
   EnterGraphicsMode("C:\\TC\\BGI");             // set display for gfx

   xMin = xLo; xMax = xHi;                       // initialize members
   yMin = yLo; yMax = yHi;
   zMin = zLo; zMax = zHi;

   LastRow = getmaxy();
   LastCol = getmaxx();
   BottomMargin = 15;

   xDelta = (xMax - xMin) / (LastCol+1-BottomMargin);
   yDelta = (yMax - yMin) / (LastRow+1-BottomMargin);
   zDelta = (zMax - zMin) / NumColors;

   xAxisIncrement = (xMax - xMin) / 12.0;
   yAxisIncrement = (yMax - yMin) / 10.0;
   xAxisRow = yToRow(0.0);
   yAxisCol = xToCol(0.0);

   ColorArray[0] = BROWN;
   ColorArray[1] = DARKGRAY;
   ColorArray[2] = BLUE;
   ColorArray[3] = CYAN;
   ColorArray[4] = LIGHTRED;
   ColorArray[5] = YELLOW;
   ColorArray[6] = WHITE;
}

/* --- Graph displays the graph of a function F(x) -------------

   Receive: F, a (pointer to a) function F(x).
   Output:  The CartesianSystem graph of F.
---------------------------------------------------------------*/

void CartesianSystem::Graph(FunctionOfX F, int Color)
{
   double
      x = xMin,
      y;
   int
      PixelX,
      PixelY;

   DrawAxes();                                   // draw axes

   for (PixelX = 0; PixelX <= LastCol; PixelX++)
   {
      y = (*F)(x);
      if ((y >= yMin) && (y <= yMax))
      {
         PixelY = yToRow(y);
         putpixel(PixelX, PixelY, Color);
      }
      x += xDelta;
   }
   DisplayMsg("Press <Enter> to continue...");
   AwaitUser();
}

/* --- DensityPlot displays a function F(x, y)'s density plot. ---

   Receive: F, a (pointer to a) function F(x, y).
   Output:  The CartesianSystem density plot of F,
                   looking down the z-axis.
-----------------------------------------------------------------*/

void CartesianSystem::DensityPlot(FunctionOfXandY F)
{
   int
      PixelX,
      PixelY,
      zColor;
   double
      x,
      y = yMin,
      z;
   DisplayMsg("When drawing is complete, press <Enter> to continue.");

   for (PixelY = 0; PixelY < LastRow-BottomMargin; PixelY++)
   {
      x = xMin;
      for (PixelX = 0; PixelX < LastCol; PixelX++)
      {
         z = (*F)(x, y);
         if (z >= zMax)
            zColor = NumColors-1; // maximum color index
         else if (z <= zMin)
            zColor = 0;           // minimum color index
         else
            zColor = round( (z-zMin)/zDelta );
         putpixel(PixelX, PixelY, ColorArray[zColor]);

         x += xDelta;
      }
      y += yDelta;
   }
   DrawAxes();                                   // draw axes
   AwaitUser();
}

