$(BIN) : $(OBJ)
$(CXX) -o $(BIN) $(OBJ)
-%.o : %.c %.h
+%.o : %.c
$(CXX) -c $<
clean :
#include <math.h> //For trig functions
+static int screen_width = 0;
+static int screen_height = 0;
+
/**
* @function Graphics_Init
* @purpose Initialise the SDL/OpenGL graphics system
glDisable(GL_DEPTH_TEST);
SDL_WM_SetCaption(caption, NULL);
+
+ screen_width = w; screen_height = h;
+
atexit(Graphics_Destroy);
}
//SDL_Flip(screen);
}
+/**
+ * @function Process_Events
+ * @purpose Handle any SDL events recieved.
+ */
+void Process_Events()
+{
+ static float view_v[3] = {0,0,0};
+ static float view_speed = 5.0;
+ static float view_scale = 1;
+ SDL_Event event;
+
+
+
+
+ while (SDL_PollEvent(&event))
+ {
+ switch (event.type)
+ {
+ case SDL_KEYDOWN:
+ switch (event.key.keysym.sym)
+ {
+ case SDLK_LEFT:
+ view_v[0] += view_speed;
+ break;
+ case SDLK_RIGHT:
+ view_v[0] -= view_speed;
+ break;
+ case SDLK_UP:
+ view_v[1] += view_speed;
+ break;
+ case SDLK_DOWN:
+ view_v[1] -= view_speed;
+ break;
+ case SDLK_i:
+ view_v[0] = 0; view_v[1] = 0; view_v[2] = 0;
+ view_scale = 1;
+ glLoadIdentity();
+ break;
+ default:
+ break;
+ }
+ break;
+ case SDL_KEYUP:
+ switch (event.key.keysym.sym)
+ {
+ case SDLK_LEFT:
+ case SDLK_RIGHT:
+ view_v[0] = 0;
+ break;
+ case SDLK_UP:
+ case SDLK_DOWN:
+ view_v[1] = 0;
+ default:
+ break;
+ }
+ break;
+
+ case SDL_MOUSEBUTTONDOWN:
+ {
+ int mouse[2];
+ SDL_GetMouseState(mouse, mouse+1);
+
+ switch (event.button.button)
+ {
+ case SDL_BUTTON_WHEELUP:
+
+ view_scale = 1.05;
+ glTranslatef(screen_width/2.0, screen_height/2.0,0.0);
+ glScaled(view_scale, view_scale, 1);
+ glTranslatef(-screen_width/2.0, -screen_height/2.0, 0.0);
+ break;
+ case SDL_BUTTON_WHEELDOWN:
+ view_scale = 0.95;
+ glTranslatef(screen_width/2.0, screen_height/2.0,0.0);
+ glScaled(view_scale, view_scale, 1);
+ glTranslatef(-screen_width/2.0, -screen_height/2.0, 0.0);
+ break;
+ default:
+ break;
+
+ }
+
+ break;
+ }
+ case SDL_MOUSEBUTTONUP:
+ break;
+ case SDL_QUIT:
+ exit(EXIT_SUCCESS);
+ break;
+ }
+ }
+
+
+ glTranslatef(view_v[0], view_v[1], view_v[2]);
+ //SDL_Delay(1);
+}
+
#endif //DIMENSIONS
-void Graphics_Init(const char * caption, int w, int h); //Initialise graphics
-void Graphics_Destroy(); //Destroy graphics
-void Graphics_Update(); //Update view
-void Graphics_Clear(float r, float g, float b); //Clear screen
-void Graphics_Pixel(int x[DIMENSIONS], float r, float g, float b); //Draw single pixel
-void Graphics_Line(int x1[DIMENSIONS], int x2[DIMENSIONS], float r, float g, float b); //Draw straight line
-void Graphics_Circle(int x[2], float radius, float r, float g, float b); //Draw circle
+extern void Graphics_Init(const char * caption, int w, int h); //Initialise graphics
+extern void Graphics_Destroy(); //Destroy graphics
+extern void Graphics_Update(); //Update view
+extern void Graphics_Clear(float r, float g, float b); //Clear screen
+extern void Graphics_Pixel(int x[DIMENSIONS], float r, float g, float b); //Draw single pixel
+extern void Graphics_Line(int x1[DIMENSIONS], int x2[DIMENSIONS], float r, float g, float b); //Draw straight line
+extern void Graphics_Circle(int x[2], float radius, float r, float g, float b); //Draw circle
+extern void Process_Events(); //Handle any events from the SDL system
-
-void Graphics_DrawPixel(int x[DIMENSIONS], float r, float g, float b);
+extern void Graphics_DrawPixel(int x[DIMENSIONS], float r, float g, float b);
#endif //_GRAPHICS_H
#include <stdio.h>
#include <stdbool.h>
#include <assert.h>
+#include <time.h>
#include "nbody.h"
int main(int argc, char ** argv)
{
-
+ srand(time(NULL));
System system;
- System_Init(&system, (float[3]){320,240,0}, 0.1, 10, 1);
+ System_Init(&system, (float[3]){320,240,0}, 1.0, 1.0, 0.4,1);
#ifdef _GRAPHICS_H
Graphics_Init("N-Body", 640, 480);
#endif //_GRAPHICS_H
- assert(System_AddBody(&system, 1, (float[2]){0.0f,0.0f}, (float[2]){0.0f,0.0f})->exists);
- assert(System_AddBody(&system, 0.01, (float[2]){120.0f, -120.0f}, (float[2]){-1.1f, 1.0f})->exists);
+ for (unsigned a = 0; a < 2; ++a)
+ {
+ float m = ((float)(rand() % 100))/1000.0;
+ float x[DIMENSIONS];
+ float v[DIMENSIONS];
+ for (unsigned i = 0; i < DIMENSIONS; ++i)
+ {
+ x[i] = (float)(rand() % 640 - 320);
+ v[i] = (float)(rand() % 100 - 50) / 100;
+ }
+ System_AddBody(&system, m, x, v);
+ }
+ System_AddBody(&system, 1.0, (float[2]){0,0}, (float[2]){0,0});
+
while (true)
{
System_Step(&system);
- //System_WriteData(&system, stdout);
+ System_WriteData(&system, stdout);
#ifdef _GRAPHICS_H
Graphics_Clear(1, 1, 1); //Clear screen
System_Draw(&system); //Draw system
body->x[i] = x[i];
body->v[i] = v[i];
body->F[i] = 0.00;
+
+ body->x_old[i] = x[i];
+ body->v_old[i] = v[i];
}
+
body->exists = true;
+ body->collided = false;
}
/**
* @function Body_Destroy
* @purpose Destroy a Body
* @param body - Target Body
+ * @param system - System to which the Body belongs
*/
-void Body_Destroy(Body * body)
+void Body_Destroy(Body * body, System * system)
{
assert(body != NULL);
body->exists = false;
+ system->n -= 1;
}
/**
void Body_Step(Body * body, System * system)
{
assert(body != NULL && system != NULL && body->exists);
-
- //fprintf(stderr, "DEBUG - Body %p\t%d\n", (void*)(body), body->exists);
+ body->collided = false;
for (unsigned i = 0; i < DIMENSIONS; ++i)
{
+
+ //Each Body keeps track of position and velocity on the previous step
+ //This is used for collision handling in the overall System step.
+ body->x_old[i] = body->x[i];
+ body->v_old[i] = body->v[i];
+
body->x[i] += body->v[i] * system->dt; //Update the position vector
body->v[i] += (body->F[i] / body->m) * system->dt; //Update the velocity vector
body->F[i] = 0.00; //Reset the net force vector
}
-
- //Do collision checking
}
float Body_Radius(Body * body)
{
assert(body != NULL && body->exists);
- float radius = 5.0;
- return radius;
+ return 8.0 * sqrt(body->m);
+}
+
+
+/**
+ * @function Body_CheckCollision
+ * @purpose Check for collision between bodies
+ * @param A - First body
+ * @param B - Second body
+ * @param system - System that the bodies belong to
+ * @param t - pointer to variable that will store the time of closest approach
+ * @returns true if collision occurred
+ */
+bool Body_CheckCollision(Body * A, Body * B, System * system, float * t)
+{
+ assert(A != NULL && B != NULL && system != NULL && A->exists && B->exists);
+
+ if (A == B)
+ return false;
+
+ // Determine time and position of closest approach
+ float x_rel[DIMENSIONS];
+ float v_rel[DIMENSIONS];
+ float coeff_t = 0.0;
+ float c = 0.0;
+ for (unsigned i = 0; i < DIMENSIONS; ++i)
+ {
+ x_rel[i] = B->x_old[i] - A->x_old[i];
+ v_rel[i] = B->v_old[i] - A->v_old[i];
+ c += v_rel[i] * x_rel[i];
+ coeff_t += v_rel[i] * v_rel[i];
+ }
+
+ *t = -c / coeff_t;
+ if (*t <= system->dt/100.0 || *t > system->dt)
+ return false;
+
+ float r2 = 0.0;
+ for (unsigned i = 0; i < DIMENSIONS; ++i)
+ {
+ x_rel[i] += *t * v_rel[i];
+ r2 += pow(x_rel[i], 2);
+ }
+
+ return (r2 <= pow(Body_Radius(A), 2) + pow(Body_Radius(B), 2));
+}
+
+/**
+ * @function Body_HandleCollision
+ * @purpose Handle a collision between two Bodies
+ * @param A - The first Body
+ * @param B - The second Body
+ * @param system - The System to which the bodies belong
+ * @param t - The time of closest approach
+ */
+void Body_HandleCollision(Body * A, Body * B, System * system, float t)
+{
+ fprintf(stderr, "#Collision %p %p at t %f\n", (void*)A, (void*)B, t);
+ fprintf(stderr,"# Before Collide; A velocity is %f %f, B velocity is %f %f\n", A->v[0], A->v[1], B->v[0], B->v[1]);
+ //Calculate A's new velocity and position
+ for (unsigned i = 0; i < DIMENSIONS; ++i)
+ {
+ A->v[i] = A->m * A->v_old[i] + B->m * B->v_old[i] + B->m * system->cor * (B->v_old[i] - A->v_old[i]);
+ A->v[i] = A->v[i] / (A->m + B->m);
+
+ A->x[i] = A->x_old[i] + A->v_old[i] * t; //Move to the collision point at the original velocity
+ A->x[i] += A->v[i] * (system->dt - t); //Move the rest of the step at the new velocity
+
+ }
+
+ //For cor = 0, bodies always merge; B is travelling with A
+ if (system->cor == 0.0)
+ {
+ A->m += B->m; //Increase A's mass
+ Body_Destroy(B, system); //Destroy B
+ return;
+ }
+
+ //Calculate B's new velocity and position
+ for (unsigned i = 0; i < DIMENSIONS; ++i)
+ {
+ B->v[i] = B->m * B->v_old[i] + A->m * A->v_old[i] + A->m * system->cor * (A->v_old[i] - B->v_old[i]);
+ B->v[i] = B->v[i] / (B->m + A->m);
+
+ B->x[i] = B->x_old[i] + B->v_old[i] * t; //Move to the collision point at the original velocity
+ B->x[i] += B->v[i] * (system->dt - t); //Move the rest of the step at the new velocity
+
+ }
+
+ //Determine whether Body B has escaped Body A; if it hasn't, merge the two bodies
+
+
+ fprintf(stderr, "# After Collide; A velocity is %f %f, B velocity is %f %f\n", A->v[0], A->v[1], B->v[0], B->v[1]);
+
+ float v2 = 0.0;
+ float r2 = 0.0;
+ for (unsigned i = 0; i < DIMENSIONS; ++i)
+ {
+ v2 += pow(B->v[i], 2);
+ r2 += pow(B->x[i] - A->x[i], 2);
+ }
+
+ fprintf(stderr, "# Collision; v is %f, escape is %f and %f\n", v2, 2.0 * system->G * A->m / sqrt(r2),2.0 * system->G * B->m / sqrt(r2));
+ if (v2 > 2.0*system->G * A->m / sqrt(r2) && v2 > 2.0*system->G * B->m / sqrt(r2))
+ return;
+
+ //Inelastically merge the two bodies
+ for (unsigned i = 0; i < DIMENSIONS; ++i)
+ {
+ A->x[i] = (A->m * A->x[i] + B->m * B->x[i]) / (A->m + B->m);
+ A->v[i] = (A->m * A->v[i] + B->m * B->v[i]) / (A->m + B->m);
+ }
+ A->m += B->m;
+ Body_Destroy(B, system);
+
}
/**
* @param x - The origin of the System (currently used for offset of graphics)
* @param dt - Time step
* @param G - Universal Gravitational Constant
+ * @param cor - The coefficient of restitution for collisions
* @param nMax - Number of Body objects this System will contain (DEFAULT = 10)
*/
-void System_Init(System * system, float x[DIMENSIONS], float dt, float G, unsigned nMax)
+void System_Init(System * system, float x[DIMENSIONS], float dt, float G, float cor, unsigned nMax)
{
assert(system != NULL);
for (unsigned i = 0; i < DIMENSIONS; ++i)
system->dt = dt;
system->G = G;
+ system->cor = cor;
system->nMax = nMax;
system->n = 0;
// Update forces
for (unsigned a = 0; a < system->nMax; ++a)
{
- if (system->bodies[a].exists)
+ if (!(system->bodies+a)->exists)
+ continue;
+
+ for (unsigned b = 0; b < system->nMax; ++b)
{
- for (unsigned b = 0; b < system->nMax; ++b)
- {
- //fprintf(stderr, "DEBUG1 - %p\t%p\t%d\t%d\n", (void*)(system->bodies+a), (void*)(system->bodies+b), system->bodies[a].exists, system->bodies[b].exists);
- if (system->bodies[b].exists)
- {
- //fprintf(stderr, "DEBUG2 - %p\t%p\t%d\t%d\n", (void*)(system->bodies+a), (void*)(system->bodies+b), system->bodies[a].exists, system->bodies[b].exists);
- Body_Force(&(system->bodies[a]), &(system->bodies[b]), system); //Update force on bodies[a] due to bodies[b]
- //fprintf(stderr, "DEBUG3 - %p\t%p\t%d\t%d\n", (void*)(system->bodies+a), (void*)(system->bodies+b), system->bodies[a].exists, system->bodies[b].exists);
- }
- }
+ if (!(system->bodies+b)->exists)
+ continue;
+
+ Body_Force(system->bodies+a, system->bodies+b, system); //Update force on bodies[a] due to
}
+
}
// Perform steps
{
if ((system->bodies+a)->exists)
Body_Step(system->bodies+a, system);
+
+
+
+ }
+
+ //Check for collisions
+ //Note: Only allows for one collision per step
+
+ for (unsigned a = 0; a < system->nMax; ++a)
+ {
+ if ((system->bodies+a)->exists == false || (system->bodies+a)->collided)
+ continue;
+
+ for (unsigned b = 0; b < system->nMax; ++b)
+ {
+ if ((system->bodies+b)->exists == false || (system->bodies+b)->collided)
+ continue;
+
+ float t = 0.0;
+ if (Body_CheckCollision(system->bodies+a, system->bodies+b, system, &t))
+ {
+ Body_HandleCollision(system->bodies+a, system->bodies+b, system, t);
+ (system->bodies+a)->collided = true;
+ (system->bodies+b)->collided = true;
+ break;
+ }
+
+ }
+
+ /* Reflections
+ if ((system->bodies+a)->x[0] + system->x[0] < 0 || (system->bodies+a)->x[0] + system->x[0] > 640)
+ (system->bodies+a)->v[0] = -(system->bodies+a)->v[0];
+ if ((system->bodies+a)->x[1] + system->x[1] < 0 || (system->bodies+a)->x[1] + system->x[1] > 480)
+ (system->bodies+a)->v[1] = -(system->bodies+a)->v[1];
+ */
+
}
+
+
}
/**
}
}
-/**
- * @function Process_Events
- * @purpose Handle any SDL events recieved.
- */
-void Process_Events()
-{
- SDL_Event event;
- while (SDL_PollEvent(&event))
- {
- switch(event.type)
- {
- case SDL_QUIT:
- exit(EXIT_SUCCESS);
- break;
- }
- }
- //SDL_Delay(1);
-}
-
#endif //_GRAPHICS_H
//EOF
float v[DIMENSIONS]; //Velocity vector
float F[DIMENSIONS]; //Net force due to all other bodies in the System
+ // Used for detecting and handling collisions
+ float x_old[DIMENSIONS]; //Position on previous step
+ float v_old[DIMENSIONS]; //Velocity on previous step
+
bool exists; //Used by memory management
+ bool collided; //Used to enforce "one collision per step"
+
} Body;
/**
*/
typedef struct
{
+
+ //--- Physical parameters ---
+
+ float G; //Universal Gravitational Constant; used to calculate forces between Bodies
+ float dt; //Time interval
+ float cor; //Coefficient of restitution for objects in the system
+
+ float x[DIMENSIONS]; //The origin of the system
+
+
+ //--- Memory management and simulation parameters ---
+
Body * bodies; //Array of Bodies
unsigned nMax; //Size of array; maximum number of Bodies before Array needs to be resized
unsigned n; //Number of bodies currently in the system
- float G; //Universal Gravitational Constant; used to calculate forces between Bodies
-
- float dt; //Time interval
unsigned step; //Number of steps executed by the System
- float x[DIMENSIONS]; //The origin of the system
+
} System;
* Functions for operating with Body objects
*/
extern void Body_Init(Body * body, float m, float x[DIMENSIONS], float v[DIMENSIONS]); //Initialise Body
-extern void Body_Destroy(Body * body); //Destroy Body
+extern void Body_Destroy(Body * body, System * system); //Destroy Body
extern void Body_Step(Body * body, System * system); //Step Body
extern void Body_Force(Body * A, Body * B, System * system); //Calculate Force between Bodies
+extern bool Body_CheckCollision(Body * A, Body * B, System * system, float * t); //Check for collision between Bodies
+extern void Body_HandleCollision(Body * A, Body * B, System * system, float t); //Handle collision between Bodies
/**
* Functions for operating with System object
*/
-extern void System_Init(System * system, float x[DIMENSIONS], float dt, float G, unsigned nMax); //Initialise System
+extern void System_Init(System * system, float x[DIMENSIONS], float dt, float G, float cor, unsigned nMax); //Initialise System
extern void System_Destroy(System * system); //Destroy System
extern void System_Step(System * system); //Step all Bodies in System
extern Body * System_AddBody(System * system, float m, float x[DIMENSIONS], float v[DIMENSIONS]); //Add Body to System
#ifdef _GRAPHICS_H
extern void System_Draw(System * system); //Draw a System of Bodies
extern void Body_Draw(Body * body, System * system); //Draw an individual Body
-
- extern void Process_Events(); //Handle any events from the SDL system
#endif //_GRAPHICS_H
--- /dev/null
+#!/bin/bash
+
+if [ "$(ps aux | grep $0)" != "" ]; then
+ echo "Already running!"
+ exit 1
+fi
+
+#Script to run on "superbug" to backup to BoB storage
+
+#target="smb://10.1.1.1/bob2%20usb%20storage/honours"
+target_directory="sam\honours"
+update_period=1 #Update this often in minutes
+
+smb_command="" #"cd $target_directory;"
+for backup in $(find . -mmin -$update_period -print | grep -v "\.git" | sed 's:^\./::g'); do
+ #echo "$backup"
+ if [ "$backup" != "." ]; then
+ smb_command=""
+ if [ "$(stat $backup | head --lines=2 | tail --lines=1 | awk '{print $NF}')" == "directory" ]; then
+ smb_command="mkdir $target_directory\\$(echo \"$backup\" | sed 's:/:\\:g');"
+ else
+ smb_command="put \"$backup\" $target_directory\\\"$(echo $backup | sed 's:/:\\:g')\";"
+ fi
+ echo "SMB command: $smb_command"
+ smbclient -N //10.1.1.1/"BoB2 USB storage" -c "$smb_command"
+ fi
+done
+
+exit 0