/*File: ship2.cxx
Written by: Emily Cai (emilyrune@hotmail.com)
October 20th, 2011
The purpose of this program is to graw a gravitational field of 3 stars.*/
//------------------------------------------------------------------------
//Directives:
#include <cassert>
#include <iostream>
#include <cmath>
#include <cstdlib>
#include <graphics.h>
using namespace std;
//------------------------------------------------------------------------
//------------------------------------------------------------------------
//Named Constants:
const double G = 6.67e-11;
const int FRAMES_PER_SEC = 30;
const int S = 500;
const double SIMTIME = 50000;
const double WMAX = 2.5e11;
//------------------------------------------------------------------------
//------------------------------------------------------------------------
//Prototypes:
// The parameters x and y give the location of a spaceship in a
// two-dimensional star field. The parameters sx and sy give the
// location of a star of mass m in this field. The return value
// is the acceleration along the x-axis that the ship feels from
// the star. All distances are in meters and the mass
// is in kilograms. The answer is in m/sec^2.
double accx(double x, double y, double sx, double sy, double m);
//------------------------------------------------------------------------
// The parameters x and y give the location of a spaceship in a
// two-dimensional star field. The parameters sx and sy give the
// location of a star of mass m in this field. The return value
// is the acceleration along the y-axis that the ship feels from
// the star. All distances are in meters and the mass
// is in kilograms. The answer is in m/sec^2.
double accy(double x, double y, double sx, double sy, double m);
//------------------------------------------------------------------------
//This draws a vector field.
void draw_grid(double x1, double y1, double m1, double x2,
double y2, double m2, double x3, double y3, double m3);
//------------------------------------------------------------------------
//This draws a ship!
void draw_ship (double x, double y);
//------------------------------------------------------------------------
//This retrieves the clicking of the left mouse to move the ship to where
//it was and reset the velocity of it to 0.
void left_mouseclick (double &x, double &y, double &vx, double &vy);
//------------------------------------------------------------------------
//This converts world coordinates to pixel coordinates.
int pixel(double wx, double w0, double w1, int p0, int p1);
//------------------------------------------------------------------------
//This gets the mouse click of the right mouse button to move the 3 planets
//and their gravitational field around them.
void right_mouseclick (int &count, double &x1, double &y1,double &x2, double &y2,
double &x3, double &y3);
//------------------------------------------------------------------------
//Opposite of the pixel function, changes pixel coords into world coords.
double world(int p, double v0, double v1, int p0, int p1);
//------------------------------------------------------------------------
//------------------------------------------------------------------------
int main()
{
double x1 = 3.0e10;
double y1 = -7.5e10;
double x2 = -4.5e10;
double y2 = 3.0e10;
double x3 = 4.5e10;
double y3 = 9.0e10;
double m1 = 2.5e30;
double m2 = 9.5e30;
double m3 = 1.5e31;
double x = -6.0e10;
double y = -1.3e11;
double vx = 0.0;
double vy = 0.0;
int count = 0;
initwindow (S, S, "Field of Dreams", 0, 0, true);
while (true)
{
clearviewport ();
draw_ship(x, y);
draw_grid(x1, y1, m1, x2, y2, m2, x3, y3, m3);
setfillstyle (SOLID_FILL, YELLOW);
fillellipse (pixel (x1, -WMAX, WMAX, 0, S),
pixel (y1, WMAX, -WMAX, 0, S), 5, 5);
setfillstyle (SOLID_FILL, BLUE);
fillellipse (pixel (x2, -WMAX, WMAX, 0, S),
pixel (y2, WMAX, -WMAX, 0, S), 7, 7);
setfillstyle (SOLID_FILL, RED);
fillellipse (pixel (x3, -WMAX, WMAX, 0, S),
pixel (y3, WMAX, -WMAX, 0, S), 9, 9);
swapbuffers ();
vx += (accx(x, y, x1, y1, m1) + accx (x, y, x2, y2, m2) +
accx(x, y, x3, y3, m3))*SIMTIME;
vy += (accy (x, y, x1, y1, m1) + accy (x, y, x2, y2, m2) +
accy (x, y, x3, y3, m3))*SIMTIME;
x += vx*SIMTIME;
y += vy*SIMTIME;
delay (1000/FRAMES_PER_SEC);
left_mouseclick(x, y, vx, vy);
right_mouseclick (count, x1, y1 ,x2 ,y2 ,x3 , y3);
}
return EXIT_SUCCESS;
}
//------------------------------------------------------------------------
//------------------------------------------------------------------------
double accx(double x, double y, double sx, double sy, double m)
{
double dx = (sx - x);
double dy = (sy - y);
double denominator = pow(dx*dx + dy*dy, 1.5);
return G*m*dx/denominator;
}
//-----------------------------------------------------------------------
//-----------------------------------------------------------------------
double accy(double x, double y, double sx, double sy, double m)
{
double dx = (sx - x);
double dy = (sy - y);
double denominator = pow(dx*dx + dy*dy, 1.5);
return G*m*dy/denominator;
}
//----------------------------------------------------------------------
//----------------------------------------------------------------------
//The void draw_grid draws the white dots on the grid screen as well
//as the lines which show the gravitational pull of the planets through
//the m's. The x's and y's are for the location of the stars.
void draw_grid(double x1, double y1, double m1, double x2,
double y2, double m2, double x3, double y3, double m3)
{
double xvector;
double yvector;
double y;
double x;
double distance;
for (x =-WMAX; x<=WMAX; x +=WMAX/6)
{
for (y =-WMAX; y<=WMAX; y +=WMAX/6)
{
/*This part of the for loop shows what is needed to draw
the vectors in every point.*/
xvector = (accx(x, y, x1, y1, m1)+ accx (x, y, x2, y2, m2)
+ accx (x, y, x3, y3, m3));
yvector = (accy(x, y, x1, y1, m1)+ accy (x, y, x2, y2, m2)
+ accy(x, y, x3, y3, m3));
xvector *= 5.0e10;
yvector *= 5.0e10;
distance = sqrt(xvector*xvector+yvector*yvector);
if (distance <= WMAX/7.07107)
{
/*This part draws the lines that are connected to
the grid.*/
line (pixel (x, -WMAX, WMAX, 0, S),
pixel (y, WMAX, -WMAX, 0, S),
pixel (x+xvector, -WMAX, WMAX, 0, S),
pixel (y+yvector, WMAX, -WMAX, 0, S));
setfillstyle (SOLID_FILL, WHITE);
fillellipse ( pixel (x+xvector, -WMAX, WMAX, 0, S),
pixel (y+yvector, WMAX, -WMAX, 0, S),
2, 2);
}
}
}
}
//----------------------------------------------------------------------
//----------------------------------------------------------------------
void draw_ship (double x, double y)
{
setfillstyle(SOLID_FILL, GREEN);
fillellipse(pixel (x, -WMAX, WMAX, 0, S),
pixel (y, WMAX, -WMAX, 0, S), 4, 4);
}
//----------------------------------------------------------------------
//----------------------------------------------------------------------
int pixel( double wx, double w0, double w1, int p0, int p1)
{
// Sizes of the parts of the two coordinate systems
// that we are using:
double world_width = w1 - w0;
double pixel_width = p1 - p0;
// How far across the world coordinate system is wx?
double fraction = (wx - w0)/world_width;
// Convert that fraction to the corresponding spot in
// the pixel coordinate system:
return int(p0 + fraction*pixel_width);
//From professeur Michael Main's android.cxx
}
//----------------------------------------------------------------------
//----------------------------------------------------------------------
void left_mouseclick (double &x, double &y, double &vx, double &vy)
{
int pixel_x, pixel_y;
if (ismouseclick (WM_LBUTTONDOWN))
{
getmouseclick (WM_LBUTTONDOWN, pixel_x, pixel_y);
vx = 0.0;
vy = 0.0;
x = world(pixel_x, -WMAX, WMAX, 0, S);
y = world(pixel_y, WMAX, -WMAX, 0, S);
}
}
//----------------------------------------------------------------------
void right_mouseclick (int &count, double &x1, double &y1,double &x2, double &y2,
double &x3, double &y3)
{
int x, y;
if(ismouseclick(WM_RBUTTONDOWN))
{
count++;
switch(count%3)
{
case 1:
getmouseclick(WM_RBUTTONDOWN, x, y);
x1 = world(x, -WMAX, WMAX, 0, S);
y1 = world(y, WMAX, -WMAX, 0, S);
break;
case 2:
getmouseclick(WM_RBUTTONDOWN, x, y);
x2 = world(x, -WMAX, WMAX, 0, S);
y2 = world(y, WMAX, -WMAX, 0, S);
break;
case 0:
getmouseclick(WM_RBUTTONDOWN, x, y);
x3 = world(x, -WMAX, WMAX, 0, S);
y3 = world(y, WMAX, -WMAX, 0, S);
break;
}
}
}
//----------------------------------------------------------------------
double world(int p, double v0, double v1, int p0, int p1)
{
double fraction = double(p - p0)/double(p1 - p0);
double distance_from_v0 = fraction*(v1 - v0);
return v0 + distance_from_v0;
}
//----------------------------------------------------------------------