// Author      : Josh Grant
// Course      : CIS5900, Computer Graphics, Fall 2000
// Assignment  : hw05
// Date        : October 10th, 2000
// Description : This program randomly samples points on a circle and outputs
//               the scene as a PPM file.  The class Image is called to set
//               up sort of a drawing board to place some Dot objects.  The
//               below arguments can be optionally changed when exectued at the
//               command line...
//                  xcenter   - x coordinate of center of circle
//                  ycenter   - y coordinate of center of circle
//                  radius    - radius of the circle
//                  fradius   - radius of each dot to be drawn
//                  samples   - number of samples to attempt.
//                  yDim      - y number of Pixels in image
//                  xDim      - x number of Pixels in image
//                  xMin      - minimum x coordinate of image
//                  xMax      - maximum x coordinate of image
//                  yMin      - minimum y coordinate of image
//                  yMax      - maximum y coordinate of image
//               A -help option is also available to print the usage of the
//               program. 

#include <iostream.h>
#include <stdlib.h>
#include <unistd.h>
#include <image.h>
#include <dot.h>

int pointOnCircle(double &x, double &y);
int checkArgs(int myargc, char **myargv);
void printUsage(char *progname);

// I know globals are bad, but this was a quick way to clean up the mess
// caused by parsing through the command line.  Now the function is at the
// bottom of the page instead of right up top.
double xcenter = 0.0, ycenter = 0.0, radius = 20.0;
double fradius = 10.0;
int    samples = 5, yDim = 200, xDim = 200, filter  = 1;
double xMin = -1.0, xMax = 1.0, yMin = -1.0, yMax = 1.0;

int main(int argc, char **argv) {
  int i;
  double x = 0.0, y = 0.0;
  Image *image;
  Dot dot;

  // if one of the command line arguments was not recognized, then we print
  // the usage and quit.
  if (!checkArgs(argc, argv))
    printUsage(argv[0]);

  // create a new Image which our Dot object will write to.
  image = new Image(xDim, yDim, xMax, xMin, yMax, yMin);

  // initializing the Dot object
  dot.setParams(0.0, 0.0, 0.0, 1.0, 0.0, 0.0, fradius, TENT);
  srand48(getpid());
  for (i = 0; i < samples; i++) {
    if (pointOnCircle(x, y)) {
      dot.x = xcenter + x*(radius*(xMax-xMin) / xDim);
      dot.y = ycenter + y*(radius*(yMax-yMin) / yDim);
      dot.drawDot(image);
    }
  }
  image->writePPM(cout);

  return 0;
}

// Function first looks for a point within the unit circle by randomly
// picking a value for x, y and then scaling it between -1 and 1.  If one
// is found then it is normalized.
int pointOnCircle(double &x, double &y) {
  float length;
  int maxAttempts = 10;

  do {
    x = 2.0 * (drand48() - 0.5);
    y = 2.0 * (drand48() - 0.5);
    length = sqrt(x*x + y*y);
  } while ( ((length > 1.0) || (length == 0.0)) && (--maxAttempts) );

  if ( (length <= 1.0) && (length > 0.0) ) {     // Normalize.
    x /= length;
    y /= length;
  } else {                                       // throw exception
    return 0;
  }
  return 1;
}


// checkArgs() checks the command line arguments and assigns all variables
// not listed on command to zero.
int checkArgs(int myargc, char **myargv) {
  for (int i = 1; i < myargc; i += 2) {
    if (!strcmp(myargv[i], "xcenter"))
      xcenter = atof(myargv[i + 1]);
    else if (!strcmp(myargv[i], "ycenter"))
      ycenter = atof(myargv[i + 1]);
    else if (!strcmp(myargv[i], "radius"))
      radius = atof(myargv[i + 1]);
    else if (!strcmp(myargv[i], "samples"))
      samples = atoi(myargv[i + 1]);
    else if (!strcmp(myargv[i], "filter"))
      filter = atoi(myargv[i + 1]);
    else if (!strcmp(myargv[i], "fradius"))
      fradius = atof(myargv[i + 1]);
    else if (!strcmp(myargv[i], "xDim"))
      xDim = atoi(myargv[i + 1]);
    else if (!strcmp(myargv[i], "yDim"))
      yDim = atoi(myargv[i + 1]);
    else if (!strcmp(myargv[i], "xMin"))
      xMin = atof(myargv[i + 1]);
    else if (!strcmp(myargv[i], "xMax"))
      xMax = atof(myargv[i + 1]);
    else if (!strcmp(myargv[i], "yMin"))
      yMin = atof(myargv[i + 1]);
    else if (!strcmp(myargv[i], "yMax"))
      yMax = atof(myargv[i + 1]);
    else if (!strcmp(myargv[i], "-help"))
      return 0;
  }
  return 1;
}

void printUsage(char *progname) {
  cout << "Usage - " << endl;
  cout << "  " << progname << " [xcenter <num>] [ycenter <num>] " << endl;
  cout << "  [radius <num>] [samples <num>] [filter <num>] " << endl;
  cout << "  [fradius <num>] [xDim <num>] [yDim <num>]" << endl;
  cout << "  [xMin <num>] [xMax <num>] [yMin <num>] [yMax <num>]" << endl;
  cout << "  " << progname << " -help" << endl;
  exit(1);
}