// drawings.cpp
// a file containing functions to draw stuff
// P. Conrad, CISC181, Fall 2004

#include <iostream>
using std::ios;
#include <iomanip>
using std::setiosflags;

#include <fstream>
using std::endl;
using std::ostream;
using std::ofstream;
using std::ios;
using std::cerr;

#include <cmath>
using std::sin;
using std::cos;

const double PI = 3.14159;

void drawHouse(ostream & out, double x,double  y, double height, double width)
{
  // draw a house with the lower left corner at x,y
  // with width and height as per the parameters
  // draw it by sending data points to the "ostream reference" out
  
  out << "# output from drawHouse \n";
  out << x << " " << y << "\n"
      << (x + width) << " " << y << "\n"
      << (x + width) << " " << y + (.75 * height) << "\n"
      << x << " " << y + (.75 * height) << "\n"
      << x << " " << y << "\n"
      << "\n"
      << x << " " << y + (.75 * height) << "\n"
      << x + (width/2.0) << " " << (y+height) << "\n"
      << x + width << " " << y + .75 * height << "\n"
      << "\n"
      << x + 0.4*width << " " << y << "\n"
      << x + 0.4*width << " " << y + 0.375*height << "\n"
      << x + 0.6*width << " " << y + 0.375*height << "\n"
      << x + 0.6*width << " " << y << "\n"
      << endl;
    
}


// Two utility functions to compute the x, y coordinates of
// points spaced evenly around a circle.  initAngle specifies
// the initial offset in radians (e.g. PI/2 to start at the 
// "top" of the circle)

double xCoord(double radius, double centerX,
	      int i, int numPoints, double initAngle)
{
  return (radius * cos( (i * (2.0 * PI ))/ numPoints + initAngle ) + centerX);
}

double yCoord(double radius, double centerY,
	      int i, int numPoints, double initAngle)
{
  return (radius * sin( (i * (2.0 * PI ))/ numPoints + initAngle ) + centerY);
}

// Draw a regular polygon.

void drawPolygon(ostream &outfile, double centerX, double centerY,
		 double radius, int numPoints)
{

  outfile << "# output from drawPolygon"
      	  << " centerX= " << centerX 
	  << " centerY= " << centerY 
	  << " radius= " << radius 
	  << " numPoints= " << numPoints 
	  << " \n" ;

  double x,y;

  for (int i=0; i<=numPoints; i++)
    {
      x = xCoord(radius, centerX, i, numPoints, 0.0);
      y = yCoord(radius, centerY, i, numPoints, 0.0);

      outfile << setiosflags(ios::fixed) <<  x << " " << y << "\n";
    }

  outfile << "\n";

}

// A way to draw an approximate circle: just draw a polygon with
// 100 points.

void drawApproxCircle(ostream &outfile, double centerX, double centerY,
		 double radius)
{
  outfile << "# DrawApproxCircle " 
    	  << " centerX= " << centerX 
	  << " centerY= " << centerY 
	  << " radius= " << radius 
	  << " \n" ;
  drawPolygon(outfile,centerX,centerY,radius,100);
}

// Draw a star

void drawStar(ostream &outfile, double centerX, double centerY,
		 double radius, int numPoints, int skipValue, 
	         double initAngle)
{

  outfile << "# output from drawStar "
	  << " centerX = " << centerX 
	  << " centerY = " << centerY
	  << " radius = " << radius
	  << " numPoints = " << numPoints
	  << " skipValue = " << skipValue
	  << " initAngle = " << initAngle 
	  << "\n";
  
  double x1,y1,x2,y2;

  for (int i=0; i<numPoints; i++)
    {
      x1 = xCoord(radius, centerX, i, numPoints, initAngle);
      y1 = yCoord(radius, centerY, i, numPoints, initAngle);

      x2 = xCoord(radius, centerX, i+1+skipValue, numPoints, initAngle);
      y2 = yCoord(radius, centerY, i+1+skipValue, numPoints, initAngle);

      outfile << setiosflags(ios::fixed) <<  x1 << " " << y1 << "\n";
      outfile << setiosflags(ios::fixed) <<  x2 << " " << y2 << "\n";
      outfile << "\n";
    }

  outfile << "\n";

}

void drawFivePointedStar(ostream &outfile, double x, double y,
			 double r)
{
  outfile << "# drawFivePointedStar " 
	  << " x=" << x << " y= " << y << " r= " << r << "\n";
  
  drawStar(outfile, x, y, r, 5, 1, PI/2.0);
}



void drawFivePointedOutlineStar(ostream &outfile, double centerX,
				double centerY, double radius)
{

  outfile << "# output from drawFivePointedOutlineStar\n";
  


  // 
  //    Consider the following points, numbered 0 through 4 (see diagram below)
  //    i will go through a loop (for int i=0; i<5; i++) representing these
  //    five points.
  //  
  //    On the first pass through the loop, we draw a line from point 0 to
  //    the point labelled "a" to point 1.  Similarly, on the second pass,
  //    we will draw a line from 1 to point b to point 2, etc.
  //    The point a between 0 and 1 is the intersection of the lines from
  //    point 0 to point 2, and point 1 to point 3.
  // 
  //                      0
  //                     
  //                1    a e     4
  //                    b   d
  //                      c
  // 
  //                   2     3
  //
  //   To determine the point P that lines on the intersection of the lines
  //   from point i to i+2 and i+1 to i+4, we must determine the slope of
  //   each of those lines.    Call these two slopes m1 and m2.
  //   We must then determine the y intercepts of these lines, b1 and b2.
  //   Then we can use a formula that determines the intersection of two
  //   lines, given their m and b values.
  // 

  double x0,y0,x1,y1,x2,y2,x4,y4, xP, yP;
  double m1, b1, m2, b2;

  const double initAngle = PI/2.0;
  const int numPoints = 5;

  for (int i=0; i<5; i++)
    {
      // consider two lines: one from point i to i+3, and 
      // another from point i+2 to i+4


      x0 = xCoord(radius, centerX, i, numPoints, initAngle);
      y0 = yCoord(radius, centerY, i, numPoints, initAngle);

      x1 = xCoord(radius, centerX, i+1, numPoints, initAngle);
      y1 = yCoord(radius, centerY, i+1, numPoints, initAngle);

      x2 = xCoord(radius, centerX, i+2, numPoints, initAngle);
      y2 = yCoord(radius, centerY, i+2, numPoints, initAngle);

      x4 = xCoord(radius, centerX, i+4, numPoints, initAngle);
      y4 = yCoord(radius, centerY, i+4, numPoints, initAngle);

      // @@@ FOR LAB08, NOTHING TO DO...
      // @@@ You do have to so some work for project 1 though...
      // @@@ NOW YOU HAVE TO DO SOME WORK TO FIGURE OUT 
      // what the values of xP and yP are supposed to be...

      // now draw line from x0,y0 to xP,yP
      // and another line from xP,yP to x1, y1
      // and then pick up the pen
      
 
    }

  outfile << "\n";

}


void drawRectangle(ostream &outfile, double x, double y,
		   double width, double height)
{
  
  outfile << "#drawRectangle \n " 
	  << x  << " " << y << "\n"
	  << x + width << " " << y << "\n"
	  << x + width << " " << y + height << "\n "
	  << x  << " " << y + height << "\n "
	  << x  << " " << y << "\n"
	  << "\n"; // lift the pen when done
  return; 
}

void drawFlagPole(ostream &outfile, double x, double y, 
		  double height)
{
  // reference point x,y is at the center of the base of the flag pole.
  // place a circle with diameter = twice the width of the flag pole
  // at the top.

  double width = height / 50.0;

  outfile << "# drawFlagPole "
	  << " x= " << x 
	  << " y= " << y 
	  << " width= " << width 
	  << " height= " << height 
	  << " \n" ;
    
  drawRectangle(outfile, x - width/2.0, y, width, height - width);
  drawApproxCircle(outfile, x, y + height - width, width * 1.5);
   
}

void drawStopSign(ostream &outfile, double x, double y, 
		  double height)
{
  // reference point x,y is at the center of the base of the flag pole.
  // place a circle with diameter = twice the width of the flag pole
  // at the top.

  double width = height / 50.0;
  double radius = height / 5.0;

  outfile << "# drawStopSign "
	  << " x= " << x 
	  << " y= " << y 
	  << " width= " << width 
	  << " height= " << height 
	  << " \n" ;
    
  drawRectangle(outfile, x - width/2.0, y, width, height - radius*1.8);
  drawStar(outfile, x, y + height - radius, radius, 8, 0, 2 * PI / 16.0);
   
}

void drawUSFlag(ostream &outfile, double x, double y, double height)
{

// note: length determined automatically from height using 
// standard ratio for US Flag of 10:19 
// (Source: http://flagspot.net/flags/xf-rati.html)
//          but see also: http://flagspot.net/flags/us-size.html)

// For detailed proporations, see:
//    http://www.montney.com/flag/proportions.htm
//    http://www.thepowermall.com/title4flags/amendment.htm            
//  or do a web search for "dimensions of the constituent parts of the flag"

  // @@@ SOME WORK TO DO HERE FOR PROJECT 1...

}

// @@@ ADD A FUNCTION HERE TO DRAW A FRENCH FLAG...  
// @@@ AND ADD THE FUNCTION PROTOTYPE INSIDE THE drawings.h file

void drawGermanFlag(ostream &outfile, double x, double y, double height)
// note: length determined automatically from height using 
// standard ratio for German Flag of 3:5
// (Source: http://flagspot.net/flags/xf-rati.html)
{
  double width = height * 5.0 / 3.0;
  outfile << "# drawGermanFlag \n";
  drawRectangle(outfile, x, y, width, height);
  
  // draw the two lines separating the three colors
  outfile << x   << " " << y + height/3.0  << "\n" 
	  << x + width << " " << y + height/3.0 << "\n" 
	  << "\n"
	  << x  << " " << y + 2.0 * height / 3.0 << "\n" 
	  << x + width << " " << y + 2.0 * height / 3.0 << "\n" 
	  << "\n";
  return; 
  
}

void drawTexasFlag(ostream &outfile, double x, double y, double height)
// note: length determined automatically from height using 
// standard ratio for Texas flag of 2:3
// (Source: http://www.lsjunction.com/flag.htm)
{

  double width = height * 3.0/2.0;
  outfile << "# drawTexasFlag \n";
  drawRectangle(outfile, x, y,  width, height);
  
  // draw the line top to bottom separating the blue
  // stripe at left (@@@ FILL IN CODE HERE)

 
  
  // draw the line from left to right separating 
  // upper right white part from the lower right red part
  // (@@@ FILL IN CODE HERE)
  

  
  // draw the line from left to right separating 
  // upper right white part from the lower right red part
  // (@@@ FILL IN CODE HERE)
  

  // draw the star.  Diameter is 3/4 width of the 
  // blue stripe.   (@@@ FILL IN CODE HERE)

  double diameter = 3.0/4.0 * width/3.0;



  
  return; 
}

void writeGnuplotFile(const char * const gnuplotFileName, 
		      const char * const dataFileName, 
		      const char * const pngFileName, 
		      double height, double width)
{
  ofstream gnpfile(gnuplotFileName,ios::out); 
  
  if (!gnpfile)
    {
      cerr << "Couldn't open file " << gnuplotFileName << " sorry!" << endl;
      exit(-1);
    }
  
  gnpfile << "set xrange [-1:" << width << "]\n"
	  << "set yrange [-1:" << height  << "]\n"
	  << "set output \"" << pngFileName << "\" \n"
	  << "set terminal png large color\n"
	  << "set size ratio -1\n" // negative preserves even aspect ratio
	  << "set nokey\n"
	  << "plot \"" << dataFileName << "\" with lines\n"
	  << endl;

  gnpfile.close();
  return;

}

void drawStickFigure(ostream &outfile, double x, double y, 
		 double height)
{
  // @@@ FILL IN CODE HERE

}

void drawSnowMan(ostream &outfile, double x, double y, 
		 double height)
{
  // 6 units high; diameter of bottom circle 3,
  // diameter of middle circle 2, 
  // diameter of top circle 1

  double unit = height/9.0;

  double radius1 = unit * 4/2.0;
  double radius2 = unit * 3/2.0;
  double radius3 = unit * 2/2.0;

  double centerHeight = y + radius1;

  // draw the bottom circle

  drawApproxCircle(outfile, x, centerHeight , radius1 );

  // draw the middle circle
  centerHeight += (radius1 + radius2);
  drawApproxCircle(outfile, x, centerHeight, radius2 );

  // @@@ NOW FILL IN SOME CODE TO DRAW THE TOP CIRCLE


  
}
