#include <iostream.h>
#include <math.h>
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glut.h>

//-------------------------------------------------------------------------------
//Polar to Rectangular Coodinate Conversion Functions (and Inverses)

double PtoRx(double r,double t)
  { return r*cos(t); }

double PtoRy(double r,double t)
  { return r*sin(t); }

double RtoPr(double x,double y)
  { return sqrt(x*x+y*y); }

double RtoPt(double x,double y)
  { return atan(y/x); }

//------------------------------------------------------------------------------
// OpenGL Calls

const XWINDOW=500;
const YWINDOW=500;

const C_XMin=0;
const C_XMax=100;
const C_YMin=0;
const C_YMax=100;

const TargetX=100;
const TargetY=0;

const GravX=50;
const GravY=50;
const GravM=10000000;

const ProjM=1;

const double K=0.000667;

double r=100,t=30*M_PI/180;

static void Init()
  { glClearColor(0.0,0.0,0.0,1.0);
    glShadeModel(GL_FLAT);
  }

static void Reshape(int w,int h)
  { glViewport(0,0,(GLint)w,(GLint)h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(C_XMin,C_XMax,C_YMin,C_YMax,-1.0,1.0);
    glMatrixMode(GL_MODELVIEW);
  }

int InBounds(double x,double y)
  { return ((x>=C_XMin)&&(x<=C_XMax)); }

int AlignedHoriz(double x,double y)
  { return (y==TargetY); }

int AlignedVert(double x,double y)
  { return (x==TargetX); }

double DistanceBetween(double x,double y,double a,double b)
  { return sqrt((a-x)*(a-x)+(b-y)*(b-y)); }

double DistanceFromTarget(double x,double y)
  { return sqrt((TargetX-x)*(TargetX-x)+(TargetY-y)*(TargetY-y)); }

double Force(double x,double y)
  { double d=DistanceBetween(x,y,GravX,GravY);
    return ProjM*GravM/(d*d)*K;
  }

double AddedGravX(double a,double b)
  { double v=cos(atan((GravY-b)*(GravY-b)/(GravX-a)*(GravX-a)))*Force(a,b);
    if (a>=GravX) v=v*-1;
    return v;
  }

double AddedGravY(double a,double b)
  { double v=sin(atan((GravY-b)*(GravY-b)/(GravX-a)*(GravX-a)))*Force(a,b);
    if (b>=GravY) v=v*-1;
    return v;
  }

void Display()
  { glFlush();
    glClear(GL_COLOR_BUFFER_BIT);

    double x=0,y=0,q=0;
    glBegin(GL_LINE_STRIP);
      glVertex3f(x,y,0);
      while(InBounds(x,y))
        { x=q*PtoRx(r,t); //+AddedGravX(q*PtoRx(r,t),16*q*q+PtoRy(r,t)*q);
          y=-16*q*q+PtoRy(r,t)*q;//*q+AddedGravY(q*PtoRx(r,t),16*q*q+PtoRy(r,t)*q);   
          glVertex3f(x,y,0);
          q+=0.01;
        }
    glEnd();
  }

void KeyboardInput(unsigned char key,int x,int y)
  { switch (key)
      { case 27: //ESC Quits
          exit(0);
          break;
      }
  }

void MouseInput(int button,int state,int x,int y)
  { switch (button)  
      { case (GLUT_LEFT_BUTTON):    
          { if (state==GLUT_DOWN)
              { r=RtoPr(C_XMin+x*(C_XMax-C_XMin)/XWINDOW,C_YMin+(YWINDOW-y)*(C_YMax-C_YMin)/YWINDOW); 
                t=RtoPt(C_XMin+x*(C_XMax-C_XMin)/XWINDOW,C_YMin+(YWINDOW-y)*(C_YMax-C_YMin)/YWINDOW);
                Display();               
              }
          }    
          break;
        case (GLUT_RIGHT_BUTTON):
          { if (state==GLUT_DOWN)
              { cout<<AddedGravX(C_XMin+x*(C_XMax-C_XMin)/XWINDOW,
                            C_YMin+(YWINDOW-y)*(C_YMax-C_YMin)/YWINDOW)<<","
                    <<AddedGravY(C_XMin+x*(C_XMax-C_XMin)/XWINDOW,
                            C_YMin+(YWINDOW-y)*(C_YMax-C_YMin)/YWINDOW)<<"\n";
              }
          }
          break;
      }
  }

int main(int argc,char **argv)
  { glutInit(&argc,argv);
    glutInitDisplayMode(GLUT_RGBA);
    glutInitWindowSize(XWINDOW,YWINDOW);
    glutInitWindowPosition(0,0);
    glutCreateWindow(argv[0]);
    Init();
    glutReshapeFunc(Reshape);
    glutDisplayFunc(Display);
    glutKeyboardFunc(KeyboardInput);
    glutMouseFunc(MouseInput); 
    glutMainLoop();
    return 0; 
  }

