3 * @purpose Implementations for N-Body simulator
8 #include <assert.h> // To make sure I don't do anything stupid.
9 #include <math.h> //For maths and stuff
10 #include <stdio.h> //For writing data to files
11 #include "nbody.h" //Declarations of functions and structures in this file
13 // --- Body functions --- //
17 * @purpose Initialise a Body object with mass, position and velocity
18 * @param body - Target Body
19 * @param m - The mass of the Body
20 * @param x[...] - The position vector of the body
21 * @param v[...] - The velocity vector of the body
23 void Body_Init(Body * body, float m, float x[DIMENSIONS], float v[DIMENSIONS])
27 for (unsigned i = 0; i < DIMENSIONS; ++i)
37 * @function Body_Destroy
38 * @purpose Destroy a Body
39 * @param body - Target Body
41 void Body_Destroy(Body * body)
49 * @purpose Perform a single step, updating target Body
50 * @param body - Target Body
51 * @param system - System that the Body is part of (used for universal constants, etc)
53 void Body_Step(Body * body, System * system)
55 assert(body != NULL && system != NULL && body->exists);
57 //fprintf(stderr, "DEBUG - Body %p\t%d\n", (void*)(body), body->exists);
58 for (unsigned i = 0; i < DIMENSIONS; ++i)
60 body->x[i] += body->v[i] * system->dt; //Update the position vector
61 body->v[i] += (body->F[i] / body->m) * system->dt; //Update the velocity vector
62 body->F[i] = 0.00; //Reset the net force vector
65 //Do collision checking
70 * @function Body_Force
71 * @purpose Update the net force on Body A due to Body B
72 * @param A - Body to update; subject of force from B
73 * @param B - Body causing force on A; NOT CHANGED BY THIS FUNCTION
74 * @param system - System which Body A is a part of (used for universal constants, etc)
76 void Body_Force(Body * A, Body * B, System * system)
79 assert(A != NULL && B != NULL && system != NULL && A->exists && B->exists);
84 for (unsigned i = 0; i < DIMENSIONS; ++i)
85 r2 += powf((B->x[i] - A->x[i]), 2);
87 float k = system->G * (A->m * B->m) / powf(r2, 1.50);
88 for (unsigned i = 0; i < DIMENSIONS; ++i)
89 A->F[i] += k * (B->x[i] - A->x[i]);
94 * @function Body_Radius
95 * @purpose Calculate the radius of a body
96 * @param body - Target Body
97 * @returns The radius of body
99 float Body_Radius(Body * body)
101 assert(body != NULL && body->exists);
107 * @function Body_WriteData
108 * @purpose Write data about the Body to a file
109 * @param body - The target Body
110 * @param system - System to which the Body belongs
111 * @param file - File to write data to
113 void Body_WriteData(Body * body, System * system, FILE * file)
115 assert(body != NULL && system != NULL && file != NULL && body->exists);
116 fprintf(file,"%d\t%p\t%f", system->step, (void*)(body), body->m);
117 for (unsigned i = 0; i < DIMENSIONS; ++i)
118 fprintf(file,"\t%f", body->x[i]);
119 for (unsigned i = 0; i < DIMENSIONS; ++i)
120 fprintf(file,"\t%f", body->v[i]);
121 for (unsigned i = 0; i < DIMENSIONS; ++i)
122 fprintf(file,"\t%f", body->F[i]);
128 // --- System functions --- //
131 * @function System_Init
132 * @purpose Initialise a System object
133 * @param system - Target System
134 * @param x - The origin of the System (currently used for offset of graphics)
135 * @param dt - Time step
136 * @param G - Universal Gravitational Constant
137 * @param nMax - Number of Body objects this System will contain (DEFAULT = 10)
139 void System_Init(System * system, float x[DIMENSIONS], float dt, float G, unsigned nMax)
141 assert(system != NULL);
142 for (unsigned i = 0; i < DIMENSIONS; ++i)
151 system->bodies = (Body*)(calloc(sizeof(Body), nMax)); //Allocate space for nMax bodies
152 for (unsigned a = 0; a < nMax; ++a)
153 (system->bodies+a)->exists = false;
157 * @function System_Destroy
158 * @purpose Destroy all Bodies in a system
159 * @param system - Target system
162 void System_Destroy(System * system)
164 assert(system != NULL);
165 if (system->bodies != NULL)
166 free(system->bodies);
171 * @function System_Step
172 * @purpose Compute single step for all Bodies in System
173 * @param system - Target system
175 void System_Step(System * system)
177 assert(system != NULL);
180 for (unsigned a = 0; a < system->nMax; ++a)
182 if (system->bodies[a].exists)
184 for (unsigned b = 0; b < system->nMax; ++b)
186 //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);
187 if (system->bodies[b].exists)
189 //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);
190 Body_Force(&(system->bodies[a]), &(system->bodies[b]), system); //Update force on bodies[a] due to bodies[b]
191 //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);
198 for (unsigned a = 0; a < system->nMax; ++a)
200 if ((system->bodies+a)->exists)
201 Body_Step(system->bodies+a, system);
206 * @function System_AddBody
207 * @purpose Add a Body to a System. Resizes the System's bodies array if necessary.
208 * @param system - Target System
209 * @param m - Mass of the new Body
210 * @param x[...] - position vector for the new Body
211 * @param v[...] - velocity vector for the new Body
212 * @returns Pointer to new Body
215 Body * System_AddBody(System * system, float m, float x[DIMENSIONS], float v[DIMENSIONS])
217 assert(system != NULL);
220 for (a = 0; a < system->nMax; ++a)
222 if (!(system->bodies+a)->exists)
226 if (a >= system->nMax)
228 system->nMax = (system->nMax+1) * 2;
229 system->bodies = (Body*)(realloc(system->bodies, sizeof(Body) * system->nMax));
230 for (unsigned b = a; b < system->nMax; ++b)
231 (system->bodies+b)->exists = false;
234 Body_Init(system->bodies+a, m, x, v);
237 return (system->bodies+a);
242 * @function System_WriteData
243 * @purpose Write all information about System to a file
244 * @param system - Target System
245 * @param file - Target FILE (must be opened for writing)
247 void System_WriteData(System * system, FILE * file)
249 assert(system != NULL && file != NULL);
250 for (unsigned a = 0; a < system->nMax; ++a)
252 if ((system->bodies+a)->exists)
253 Body_WriteData(system->bodies+a, system, file);
259 // --- Graphical functions --- //
264 * @function Body_Draw
265 * @purpose Draw an individual Body
266 * @param body - Target Body
267 * @param system - System to which the Body belongs
270 void Body_Draw(Body * body, System * system)
272 assert(body != NULL && system != NULL && body->exists);
273 int pixel_pos[DIMENSIONS];
274 for (unsigned i = 0; i < DIMENSIONS; ++i)
275 pixel_pos[i] = (int)(system->x[i] - body->x[i]);
277 float rgb[3] = {0.0f, 0.0f, 0.0f};
278 if (body->m >= 100.0)
280 rgb[0] = 0.0f; rgb[1] = 0.0f; rgb[2] = 1.0f;
284 rgb[0] = 0.5f; rgb[1] = 0.5f; rgb[2] = 1.0f;
286 else if (body->m >= 1.0)
288 rgb[0] = 0.8f; rgb[1] = 0.2f; rgb[2] = 0.1f;
290 else if (body->m >= 0.1)
292 rgb[0] = 0.0f; rgb[1] = 0.5f; rgb[2] = 0.0f;
294 else if (body->m >= 0.01)
296 rgb[0] = 0.5f; rgb[1] = 0.5f; rgb[2] = 0.5f;
300 Graphics_Circle(pixel_pos,Body_Radius(body), rgb[0], rgb[1], rgb[2]);
302 //fprintf(stdout, "DEBUG - Body_Draw - Called\n");
306 * @function System_Draw
307 * @purpose Draw a System of Bodies
308 * @param system - Target System to draw
310 void System_Draw(System * system)
312 assert(system != NULL);
313 for (unsigned a = 0; a < system->nMax; ++a)
315 if ((system->bodies+a)->exists)
316 Body_Draw(system->bodies+a, system);
321 * @function Process_Events
322 * @purpose Handle any SDL events recieved.
324 void Process_Events()
327 while (SDL_PollEvent(&event))