/* CartesianSystem.cpp defines non-trivial methods of class CartesianSystem.
 *
 *  Copyright Joel Adams, July 2001, All rights reserved.
 */
 
#include "CartesianSystem.h"      // our class
#include "127GraphicsSettings.h"  // do_console()
#include <sstream>                // ostringstream
using namespace std;

void CartesianSystem::initialize(double minX, double minY,  // lower-left corner
                                  double maxX, double maxY, // upper-right corner
                                  bool axisVisible)         // show axis?
{
  assert(minX < maxX && minY < maxY);                       // store boundary values
  xMin = minX; yMin = minY;
  xMax = maxX; yMax = maxY;
  
  myXRange = xMax - xMin;                                   // range of X values
  myYRange = yMax - yMin;                                   // range of Y values
  setSizeDependentAttributes();                              // what it says
  
  myAxisVisible = axisVisible;                               // set axis visibility
  myDecimalDigits = DEFAULT_PRECISION;                       // axis labels' precision
  drawAxis();                                                // draw it (maybe)
  
  do_console();  // Need this to make the window show up ?!?
  cout << "CartesianSystem: "
       << GetWidth() << 'x' << GetHeight() << " pixels ;"
       << " use 2-to-1 X-to-Y aspect ratios."
       << "\n<* Type Cmd-q (or Cntl-q) or Cmd-Opt-Esc (or Cntl-Alt-Del) to quit *>\n";
}

void CartesianSystem::setSizeDependentAttributes()
{
  const int FUDGE_FACTOR = 20;                           // tune this to adjust X-Y pixel skew

  myRows = GetHeight() - 2 * AXIS_MARGIN + FUDGE_FACTOR; // rows within the drawing space
  myLastRow = myRows - 1;
  
  myColumns = GetWidth() - 2 * AXIS_MARGIN;              // columns within the space
  
  myColumnsPerX = myXRange / myColumns;             // x++ moves this many columns
  myRowsPerY    = myYRange / myRows;                // y++ moves this many rows
  
  xInterval = myXRange / (myColumns / AXIS_GAP);  // distance btwn x-axis hash-marks
  yInterval = myYRange / (myRows / AXIS_GAP);     // distance btwn y-axis hash-marks
}

void CartesianSystem::drawAxis(int axisColor, int penSize)
{
  if (myAxisVisible)
  {
    SetBrush(axisColor);
    SetPen(penSize);
    
    DrawLine(xToColumn(xMin), yToRow(0),                     // x-axis
              xToColumn(xMax), yToRow(0));
    SetFont(10, 0, 0);
    for (double x = xInterval; x <= xMax; x += xInterval)    // origin-to-xMax
    {
      DrawLine(xToColumn(x), yToRow(0)+5,                    //  hash-marks
                xToColumn(x), yToRow(0)-5);
      ostringstream sout;                                    //  and labels
      sout << fixed << showpoint 
           << setprecision(myDecimalDigits) << x;
      DrawString(xToColumn(x)-15, yToRow(0)+18, sout.str().data());
    }

    for (double x = -xInterval; x >= xMin; x -= xInterval)   // origin-to-xMin
    {
      DrawLine(xToColumn(x), yToRow(0)+5,                    //  hash-marks
                xToColumn(x), yToRow(0)-5);
      ostringstream sout;                                    //  and labels
      sout << fixed << showpoint 
           << setprecision(myDecimalDigits) << x;
      DrawString(xToColumn(x)-15, yToRow(0)+18, sout.str().data());
    }
    
    
    DrawLine(xToColumn(0), yToRow(yMin),                     // y-axis
              xToColumn(0), yToRow(yMax));
    for (double y = yInterval; y <= yMax; y += yInterval)    // origin-to-yMax
    {
      DrawLine(xToColumn(0)-5, yToRow(y),                    //  hash-marks
                xToColumn(0)+5, yToRow(y));
      ostringstream sout;                                    //  and labels
      sout << fixed << showpoint 
           << setprecision(myDecimalDigits) << y;
      DrawString(xToColumn(0)+10, yToRow(y)+5, sout.str().data());
    }

    for (double y = -yInterval; y >= yMin; y -= yInterval)   // origin-to-yMin
    {
      DrawLine(xToColumn(0)-5, yToRow(y),                    //  hash-marks
                xToColumn(0)+5, yToRow(y));
      ostringstream sout;                                    //  and labels
      sout << fixed << showpoint 
           << setprecision(myDecimalDigits) << y;
      DrawString(xToColumn(0)+10, yToRow(y)+5, sout.str().data());
    }

  }
}

void CartesianSystem::clear(int bgColor, bool axisVisible)
{
  SetBrush(bgColor);
  DrawRectangle(0, 0, GetWidth()-1, GetHeight()-1);         // kludge to 'clear' screen
  myAxisVisible = axisVisible;
    drawAxis();
 }
 


void CartesianSystem::drawFunction(FunctionOfX aFunction, int aColor)
{
  SetBrush(aColor);
  double y;
  for (double x = xMin; x <= xMax; x += deltaX())
  {
     y = aFunction(x);
     if (yMin <= y && y <= yMax)
       DrawPixel(xToColumn(x), yToRow(y));
  }
}

void CartesianSystem::drawNumber(double x, double y, double number, int aColor)
{
  ostringstream sout;
  sout << number;
  SetBrush(aColor);
  DrawString(xToColumn(x), yToRow(y), sout.str().data());
}

