Commit ba9f8584 authored by Caleb C. Sander's avatar Caleb C. Sander
Browse files

Rename types to _t

parent 1c7777b4
No related merge requests found
Showing with 250 additions and 237 deletions
+250 -237
......@@ -2,7 +2,6 @@
#define __BODY_H__
#include <stdbool.h>
#include "color.h"
#include "list.h"
#include "vector.h"
......@@ -13,13 +12,13 @@
* Bodies can accumulate forces and impulses during each tick.
* Angular physics (i.e. torques) are not currently implemented.
*/
typedef struct body Body;
typedef struct body body_t;
/**
* Initializes a body without any info.
* Acts like body_init_with_info() where info and info_freer are NULL.
*/
Body *body_init(List *shape, double mass, RGBColor color);
body_t *body_init(list_t *shape, double mass, rgb_color_t color);
/**
* Allocates memory for a body with the given parameters.
......@@ -27,15 +26,19 @@ Body *body_init(List *shape, double mass, RGBColor color);
* Asserts that the mass is positive and that the required memory is allocated.
*
* @param shape a list of vectors describing the initial shape of the body
* @param mass the mass of the body (if INFINITY, prevents the body from moving)
* @param mass the mass of the body (if INFINITY, stops the body from moving)
* @param color the color of the body, used to draw it on the screen
* @param info additional information to associate with the body,
* e.g. its type if the scene has multiple types of bodies
* @param info_freer if non-NULL, a function call on the info to free it
* @return a pointer to the newly allocated body
*/
Body *body_init_with_info(
List *shape, double mass, RGBColor color, void *info, FreeFunc info_freer
body_t *body_init_with_info(
list_t *shape,
double mass,
rgb_color_t color,
void *info,
free_func_t info_freer
);
/**
......@@ -43,7 +46,7 @@ Body *body_init_with_info(
*
* @param body a pointer to a body returned from body_init()
*/
void body_free(Body *body);
void body_free(body_t *body);
/**
* Gets the current shape of a body.
......@@ -52,7 +55,7 @@ void body_free(Body *body);
* @param body a pointer to a body returned from body_init()
* @return the polygon describing the body's current position
*/
List *body_get_shape(Body *body);
list_t *body_get_shape(body_t *body);
/**
* Gets the current center of mass of a body.
......@@ -63,7 +66,7 @@ List *body_get_shape(Body *body);
* @param body a pointer to a body returned from body_init()
* @return the body's center of mass
*/
Vector body_get_centroid(Body *body);
vector_t body_get_centroid(body_t *body);
/**
* Gets the current velocity of a body.
......@@ -71,7 +74,7 @@ Vector body_get_centroid(Body *body);
* @param body a pointer to a body returned from body_init()
* @return the body's velocity vector
*/
Vector body_get_velocity(Body *body);
vector_t body_get_velocity(body_t *body);
/**
* Gets the mass of a body.
......@@ -79,7 +82,7 @@ Vector body_get_velocity(Body *body);
* @param body a pointer to a body returned from body_init()
* @return the mass passed to body_init(), which must be greater than 0
*/
double body_get_mass(Body *body);
double body_get_mass(body_t *body);
/**
* Gets the display color of a body.
......@@ -87,7 +90,7 @@ double body_get_mass(Body *body);
* @param body a pointer to a body returned from body_init()
* @return the color passed to body_init(), as an (R, G, B) tuple
*/
RGBColor body_get_color(Body *body);
rgb_color_t body_get_color(body_t *body);
/**
* Gets the information associated with a body.
......@@ -95,7 +98,7 @@ RGBColor body_get_color(Body *body);
* @param body a pointer to a body returned from body_init()
* @return the info passed to body_init()
*/
void *body_get_info(Body *body);
void *body_get_info(body_t *body);
/**
* Translates a body to a new position.
......@@ -104,7 +107,7 @@ void *body_get_info(Body *body);
* @param body a pointer to a body returned from body_init()
* @param x the body's new centroid
*/
void body_set_centroid(Body *body, Vector x);
void body_set_centroid(body_t *body, vector_t x);
/**
* Changes a body's velocity (the time-derivative of its position).
......@@ -112,7 +115,7 @@ void body_set_centroid(Body *body, Vector x);
* @param body a pointer to a body returned from body_init()
* @param v the body's new velocity
*/
void body_set_velocity(Body *body, Vector v);
void body_set_velocity(body_t *body, vector_t v);
/**
* Changes a body's orientation in the plane.
......@@ -122,7 +125,7 @@ void body_set_velocity(Body *body, Vector v);
* @param body a pointer to a body returned from body_init()
* @param angle the body's new angle in radians. Positive is counterclockwise.
*/
void body_set_rotation(Body *body, double angle);
void body_set_rotation(body_t *body, double angle);
/**
* Applies a force to a body over the current tick.
......@@ -132,7 +135,7 @@ void body_set_rotation(Body *body, double angle);
* @param body a pointer to a body returned from body_init()
* @param force the force vector to apply
*/
void body_add_force(Body *body, Vector force);
void body_add_force(body_t *body, vector_t force);
/**
* Applies an impulse to a body.
......@@ -144,7 +147,7 @@ void body_add_force(Body *body, Vector force);
* @param body a pointer to a body returned from body_init()
* @param impulse the impulse vector to apply
*/
void body_add_impulse(Body *body, Vector impulse);
void body_add_impulse(body_t *body, vector_t impulse);
/**
* Updates the body after a given time interval has elapsed.
......@@ -157,7 +160,7 @@ void body_add_impulse(Body *body, Vector impulse);
* @param body the body to tick
* @param dt the number of seconds elapsed since the last tick
*/
void body_tick(Body *body, double dt);
void body_tick(body_t *body, double dt);
/**
* Marks a body for removal--future calls to body_is_removed() will return true.
......@@ -166,7 +169,7 @@ void body_tick(Body *body, double dt);
*
* @param body the body to mark for removal
*/
void body_remove(Body *body);
void body_remove(body_t *body);
/**
* Returns whether a body has been marked for removal.
......@@ -176,6 +179,6 @@ void body_remove(Body *body);
* @param body the body to check
* @return whether body_remove() has been called on the body
*/
bool body_is_removed(Body *body);
bool body_is_removed(body_t *body);
#endif // #ifndef __BODY_H__
......@@ -3,7 +3,6 @@
#include <stdbool.h>
#include "list.h"
#include "vector.h"
/**
* Determines whether two convex polygons intersect.
......@@ -15,6 +14,6 @@
* @param shape2 the second shape
* @return whether the shapes are colliding
*/
bool find_collision(List *shape1, List *shape2);
bool find_collision(list_t *shape1, list_t *shape2);
#endif // #ifndef __COLLISION_H__
......@@ -4,7 +4,9 @@
#include "scene.h"
/**
* Adds a Newtonian gravitational force between two bodies in a scene.
* Adds a force creator to a scene that applies gravity between two bodies.
* The force creator will be called each tick
* to compute the Newtonian gravitational force between the bodies.
* See https://en.wikipedia.org/wiki/Newton%27s_law_of_universal_gravitation#Vector_form.
* The force should not be applied when the bodies are very close,
* because its magnitude blows up as the distance between the bodies goes to 0.
......@@ -14,10 +16,12 @@
* @param body1 the first body
* @param body2 the second body
*/
void create_newtonian_gravity(Scene *scene, double G, Body *body1, Body *body2);
void create_newtonian_gravity(scene_t *scene, double G, body_t *body1, body_t *body2);
/**
* Adds a Hooke's-Law spring force between two bodies in a scene.
* Adds a force creator to a scene that acts like a spring between two bodies.
* The force creator will be called each tick
* to compute the Hooke's-Law spring force between the bodies.
* See https://en.wikipedia.org/wiki/Hooke%27s_law.
*
* @param scene the scene containing the bodies
......@@ -25,10 +29,12 @@ void create_newtonian_gravity(Scene *scene, double G, Body *body1, Body *body2);
* @param body1 the first body
* @param body2 the second body
*/
void create_spring(Scene *scene, double k, Body *body1, Body *body2);
void create_spring(scene_t *scene, double k, body_t *body1, body_t *body2);
/**
* Adds a drag force on a body proportional to its velocity.
* Adds a force creator to a scene that applies a drag force on a body.
* The force creator will be called each tick
* to compute the drag force on the body proportional to its velocity.
* The force points opposite the body's velocity.
*
* @param scene the scene containing the bodies
......@@ -36,16 +42,16 @@ void create_spring(Scene *scene, double k, Body *body1, Body *body2);
* (higher gamma means more drag)
* @param body the body to slow down
*/
void create_drag(Scene *scene, double gamma, Body *body);
void create_drag(scene_t *scene, double gamma, body_t *body);
/**
* Adds a ForceCreator to a scene that destroys two bodies when they collide.
* Adds a force creator to a scene that destroys two bodies when they collide.
* The bodies should be destroyed by calling body_remove().
*
* @param scene the scene containing the bodies
* @param body1 the first body
* @param body2 the second body
*/
void create_destructive_collision(Scene *scene, Body *body1, Body *body2);
void create_destructive_collision(scene_t *scene, body_t *body1, body_t *body2);
#endif // #ifndef __FORCES_H__
#ifndef __SCENE_H__
#define __SCENE_H__
#include <stdbool.h>
#include "body.h"
#include "list.h"
......@@ -10,14 +9,14 @@
* The scene automatically resizes to store
* arbitrarily many bodies and force creators.
*/
typedef struct scene Scene;
typedef struct scene scene_t;
/**
* A function which adds some forces or impulses to bodies,
* e.g. from collisions, gravity, or spring forces.
* Takes in an auxiliary value that can store parameters or state.
*/
typedef void (*ForceCreator)(void *aux);
typedef void (*force_creator_t)(void *aux);
/**
* Allocates memory for an empty scene.
......@@ -26,7 +25,7 @@ typedef void (*ForceCreator)(void *aux);
*
* @return the new scene
*/
Scene *scene_init(void);
scene_t *scene_init(void);
/**
* Releases memory allocated for a given scene
......@@ -34,7 +33,7 @@ Scene *scene_init(void);
*
* @param scene a pointer to a scene returned from scene_init()
*/
void scene_free(Scene *scene);
void scene_free(scene_t *scene);
/**
* Gets the number of bodies in a given scene.
......@@ -42,7 +41,7 @@ void scene_free(Scene *scene);
* @param scene a pointer to a scene returned from scene_init()
* @return the number of bodies added with scene_add_body()
*/
size_t scene_bodies(Scene *scene);
size_t scene_bodies(scene_t *scene);
/**
* Gets the body at a given index in a scene.
......@@ -52,7 +51,7 @@ size_t scene_bodies(Scene *scene);
* @param index the index of the body in the scene (starting at 0)
* @return a pointer to the body at the given index
*/
Body *scene_get_body(Scene *scene, size_t index);
body_t *scene_get_body(scene_t *scene, size_t index);
/**
* Adds a body to a scene.
......@@ -60,7 +59,7 @@ Body *scene_get_body(Scene *scene, size_t index);
* @param scene a pointer to a scene returned from scene_init()
* @param body a pointer to the body to add to the scene
*/
void scene_add_body(Scene *scene, Body *body);
void scene_add_body(scene_t *scene, body_t *body);
/**
* @deprecated Use body_remove() instead
......@@ -71,14 +70,17 @@ void scene_add_body(Scene *scene, Body *body);
* @param scene a pointer to a scene returned from scene_init()
* @param index the index of the body in the scene (starting at 0)
*/
void scene_remove_body(Scene *scene, size_t index);
void scene_remove_body(scene_t *scene, size_t index);
/**
* @deprecated Use scene_add_bodies_force_creator() instead
* so the scene knows which bodies the force creator depends on
*/
void scene_add_force_creator(
Scene *scene, ForceCreator forcer, void *aux, FreeFunc freer
scene_t *scene,
force_creator_t forcer,
void *aux,
free_func_t freer
);
/**
......@@ -97,7 +99,11 @@ void scene_add_force_creator(
* @param freer if non-NULL, a function to call in order to free aux
*/
void scene_add_bodies_force_creator(
Scene *scene, ForceCreator forcer, void *aux, List *bodies, FreeFunc freer
scene_t *scene,
force_creator_t forcer,
void *aux,
list_t *bodies,
free_func_t freer
);
/**
......@@ -110,6 +116,6 @@ void scene_add_bodies_force_creator(
* @param scene a pointer to a scene returned from scene_init()
* @param dt the time elapsed since the last tick, in seconds
*/
void scene_tick(Scene *scene, double dt);
void scene_tick(scene_t *scene, double dt);
#endif // #ifndef __SCENE_H__
......@@ -5,23 +5,23 @@
#include <stdlib.h>
void test_body_init() {
Vector v[] = {{1, 1}, {2, 1}, {2, 2}, {1, 2}};
vector_t v[] = {{1, 1}, {2, 1}, {2, 2}, {1, 2}};
const size_t VERTICES = sizeof(v) / sizeof(*v);
List *shape = list_init(0, free);
list_t *shape = list_init(0, free);
for (size_t i = 0; i < VERTICES; i++) {
Vector *list_v = malloc(sizeof(*list_v));
vector_t *list_v = malloc(sizeof(*list_v));
*list_v = v[i];
list_add(shape, list_v);
}
RGBColor color = {0, 0.5, 1};
Body *body = body_init(shape, 3, color);
List *shape2 = body_get_shape(body);
rgb_color_t color = {0, 0.5, 1};
body_t *body = body_init(shape, 3, color);
list_t *shape2 = body_get_shape(body);
assert(list_size(shape2) == VERTICES);
for (size_t i = 0; i < VERTICES; i++) {
assert(vec_isclose(*(Vector *) list_get(shape2, i), v[i]));
assert(vec_isclose(*(vector_t *) list_get(shape2, i), v[i]));
}
list_free(shape2);
assert(vec_isclose(body_get_centroid(body), (Vector) {1.5, 1.5}));
assert(vec_isclose(body_get_centroid(body), (vector_t) {1.5, 1.5}));
assert(vec_equal(body_get_velocity(body), VEC_ZERO));
assert(body_get_color(body).r == color.r);
assert(body_get_color(body).g == color.g);
......@@ -31,65 +31,65 @@ void test_body_init() {
}
void test_body_setters() {
List *shape = list_init(3, free);
Vector *v = malloc(sizeof(*v));
*v = (Vector) {+1, 0};
list_t *shape = list_init(3, free);
vector_t *v = malloc(sizeof(*v));
*v = (vector_t) {+1, 0};
list_add(shape, v);
v = malloc(sizeof(*v));
*v = (Vector) {0, +1};
*v = (vector_t) {0, +1};
list_add(shape, v);
v = malloc(sizeof(*v));
*v = (Vector) {-1, 0};
*v = (vector_t) {-1, 0};
list_add(shape, v);
Body *body = body_init(shape, 1, (RGBColor) {0, 0, 0});
body_set_velocity(body, (Vector) {+5, -5});
assert(vec_equal(body_get_velocity(body), (Vector) {+5, -5}));
assert(vec_isclose(body_get_centroid(body), (Vector) {0, 1.0 / 3.0}));
body_set_centroid(body, (Vector) {1, 2});
assert(vec_isclose(body_get_centroid(body), (Vector) {1, 2}));
body_t *body = body_init(shape, 1, (rgb_color_t) {0, 0, 0});
body_set_velocity(body, (vector_t) {+5, -5});
assert(vec_equal(body_get_velocity(body), (vector_t) {+5, -5}));
assert(vec_isclose(body_get_centroid(body), (vector_t) {0, 1.0 / 3.0}));
body_set_centroid(body, (vector_t) {1, 2});
assert(vec_isclose(body_get_centroid(body), (vector_t) {1, 2}));
shape = body_get_shape(body);
assert(list_size(shape) == 3);
assert(vec_isclose(*(Vector *) list_get(shape, 0), (Vector) {2, 5.0 / 3.0}));
assert(vec_isclose(*(Vector *) list_get(shape, 1), (Vector) {1, 8.0 / 3.0}));
assert(vec_isclose(*(Vector *) list_get(shape, 2), (Vector) {0, 5.0 / 3.0}));
assert(vec_isclose(*(vector_t *) list_get(shape, 0), (vector_t) {2, 5.0 / 3.0}));
assert(vec_isclose(*(vector_t *) list_get(shape, 1), (vector_t) {1, 8.0 / 3.0}));
assert(vec_isclose(*(vector_t *) list_get(shape, 2), (vector_t) {0, 5.0 / 3.0}));
list_free(shape);
body_set_rotation(body, M_PI / 2);
assert(vec_isclose(body_get_centroid(body), (Vector) {1, 2}));
assert(vec_isclose(body_get_centroid(body), (vector_t) {1, 2}));
shape = body_get_shape(body);
assert(list_size(shape) == 3);
assert(vec_isclose(*(Vector *) list_get(shape, 0), (Vector) {4.0 / 3.0, 3}));
assert(vec_isclose(*(Vector *) list_get(shape, 1), (Vector) {1.0 / 3.0, 2}));
assert(vec_isclose(*(Vector *) list_get(shape, 2), (Vector) {4.0 / 3.0, 1}));
assert(vec_isclose(*(vector_t *) list_get(shape, 0), (vector_t) {4.0 / 3.0, 3}));
assert(vec_isclose(*(vector_t *) list_get(shape, 1), (vector_t) {1.0 / 3.0, 2}));
assert(vec_isclose(*(vector_t *) list_get(shape, 2), (vector_t) {4.0 / 3.0, 1}));
list_free(shape);
body_set_centroid(body, (Vector) {3, 4});
assert(vec_isclose(body_get_centroid(body), (Vector) {3, 4}));
body_set_centroid(body, (vector_t) {3, 4});
assert(vec_isclose(body_get_centroid(body), (vector_t) {3, 4}));
shape = body_get_shape(body);
assert(list_size(shape) == 3);
assert(vec_isclose(*(Vector *) list_get(shape, 0), (Vector) {10.0 / 3.0, 5}));
assert(vec_isclose(*(Vector *) list_get(shape, 1), (Vector) {7.0 / 3.0, 4}));
assert(vec_isclose(*(Vector *) list_get(shape, 2), (Vector) {10.0 / 3.0, 3}));
assert(vec_isclose(*(vector_t *) list_get(shape, 0), (vector_t) {10.0 / 3.0, 5}));
assert(vec_isclose(*(vector_t *) list_get(shape, 1), (vector_t) {7.0 / 3.0, 4}));
assert(vec_isclose(*(vector_t *) list_get(shape, 2), (vector_t) {10.0 / 3.0, 3}));
list_free(shape);
body_free(body);
}
void test_body_tick() {
const Vector A = {1, 2};
const vector_t A = {1, 2};
const double DT = 1e-6;
const int STEPS = 1000000;
List *shape = list_init(4, free);
Vector *v = malloc(sizeof(*v));
list_t *shape = list_init(4, free);
vector_t *v = malloc(sizeof(*v));
v->x = v->y = -1;
list_add(shape, v);
v = malloc(sizeof(*v));
*v = (Vector) {+1, -1};
*v = (vector_t) {+1, -1};
list_add(shape, v);
v = malloc(sizeof(*v));
v->x = v->y = +1;
list_add(shape, v);
v = malloc(sizeof(*v));
*v = (Vector) {-1, +1};
*v = (vector_t) {-1, +1};
list_add(shape, v);
Body *body = body_init(shape, 1, (RGBColor) {0, 0, 0});
body_t *body = body_init(shape, 1, (rgb_color_t) {0, 0, 0});
// Apply constant acceleration and ensure position is (a / 2) * t ** 2
for (int i = 0; i < STEPS; i++) {
......@@ -99,66 +99,66 @@ void test_body_tick() {
body_tick(body, DT);
}
double t = STEPS * DT;
Vector new_x = vec_multiply(t * t / 2, A);
vector_t new_x = vec_multiply(t * t / 2, A);
shape = body_get_shape(body);
assert(vec_isclose(*(Vector *) list_get(shape, 0), vec_add((Vector) {-1, -1}, new_x)));
assert(vec_isclose(*(Vector *) list_get(shape, 1), vec_add((Vector) {+1, -1}, new_x)));
assert(vec_isclose(*(Vector *) list_get(shape, 2), vec_add((Vector) {+1, +1}, new_x)));
assert(vec_isclose(*(Vector *) list_get(shape, 3), vec_add((Vector) {-1, +1}, new_x)));
assert(vec_isclose(*(vector_t *) list_get(shape, 0), vec_add((vector_t) {-1, -1}, new_x)));
assert(vec_isclose(*(vector_t *) list_get(shape, 1), vec_add((vector_t) {+1, -1}, new_x)));
assert(vec_isclose(*(vector_t *) list_get(shape, 2), vec_add((vector_t) {+1, +1}, new_x)));
assert(vec_isclose(*(vector_t *) list_get(shape, 3), vec_add((vector_t) {-1, +1}, new_x)));
list_free(shape);
body_free(body);
}
void test_infinite_mass() {
List *shape = list_init(10, free);
Vector *v = malloc(sizeof(*v));
list_t *shape = list_init(10, free);
vector_t *v = malloc(sizeof(*v));
*v = VEC_ZERO;
list_add(shape, v);
v = malloc(sizeof(*v));
*v = (Vector) {+1, 0};
*v = (vector_t) {+1, 0};
list_add(shape, v);
v = malloc(sizeof(*v));
*v = (Vector) {+1, +1};
*v = (vector_t) {+1, +1};
list_add(shape, v);
v = malloc(sizeof(*v));
*v = (Vector) {0, +1};
*v = (vector_t) {0, +1};
list_add(shape, v);
Body *body = body_init(shape, INFINITY, (RGBColor) {0, 0, 0});
body_set_velocity(body, (Vector) {2, 3});
body_t *body = body_init(shape, INFINITY, (rgb_color_t) {0, 0, 0});
body_set_velocity(body, (vector_t) {2, 3});
assert(body_get_mass(body) == INFINITY);
body_add_force(body, (Vector) {1, 1});
body_add_force(body, (vector_t) {1, 1});
body_tick(body, 1.0);
assert(vec_equal(body_get_velocity(body), (Vector) {2, 3}));
assert(vec_isclose(body_get_centroid(body), (Vector) {2.5, 3.5}));
assert(vec_equal(body_get_velocity(body), (vector_t) {2, 3}));
assert(vec_isclose(body_get_centroid(body), (vector_t) {2.5, 3.5}));
body_free(body);
}
void test_forces() {
const double MASS = 10;
const double DT = 0.1;
List *shape = list_init(3, free);
Vector *v = malloc(sizeof(*v));
*v = (Vector) {+1, 0};
list_t *shape = list_init(3, free);
vector_t *v = malloc(sizeof(*v));
*v = (vector_t) {+1, 0};
list_add(shape, v);
v = malloc(sizeof(*v));
*v = (Vector) {0, +1};
*v = (vector_t) {0, +1};
list_add(shape, v);
v = malloc(sizeof(*v));
*v = (Vector) {-1, 0};
*v = (vector_t) {-1, 0};
list_add(shape, v);
Body *body = body_init(shape, MASS, (RGBColor) {0, 0, 0});
body_t *body = body_init(shape, MASS, (rgb_color_t) {0, 0, 0});
body_set_centroid(body, VEC_ZERO);
Vector old_velocity = {1, -2};
vector_t old_velocity = {1, -2};
body_set_velocity(body, old_velocity);
body_add_force(body, (Vector) {MASS * 3, MASS * 4});
body_add_impulse(body, (Vector) {MASS * 10, MASS * 5});
body_add_force(body, (Vector) {MASS * 3, MASS * 4});
body_add_force(body, (vector_t) {MASS * 3, MASS * 4});
body_add_impulse(body, (vector_t) {MASS * 10, MASS * 5});
body_add_force(body, (vector_t) {MASS * 3, MASS * 4});
body_tick(body, DT);
Vector new_velocity =
vec_add(old_velocity, (Vector) {10 + 6 * DT, 5 + 8 * DT});
vector_t new_velocity =
vec_add(old_velocity, (vector_t) {10 + 6 * DT, 5 + 8 * DT});
assert(vec_isclose(body_get_velocity(body), new_velocity));
Vector new_centroid =
vec_multiply(DT / 2.0, vec_add(old_velocity, new_velocity));
vector_t new_centroid =
vec_multiply(DT / 2, vec_add(old_velocity, new_velocity));
assert(vec_isclose(body_get_centroid(body), new_centroid));
body_tick(body, DT);
assert(vec_isclose(
......@@ -169,17 +169,17 @@ void test_forces() {
}
void test_body_remove() {
List *shape = list_init(3, free);
Vector *v = malloc(sizeof(*v));
*v = (Vector) {+1, 0};
list_t *shape = list_init(3, free);
vector_t *v = malloc(sizeof(*v));
*v = (vector_t) {+1, 0};
list_add(shape, v);
v = malloc(sizeof(*v));
*v = (Vector) {0, +1};
*v = (vector_t) {0, +1};
list_add(shape, v);
v = malloc(sizeof(*v));
*v = (Vector) {-1, 0};
*v = (vector_t) {-1, 0};
list_add(shape, v);
Body *body = body_init(shape, 1, (RGBColor) {0, 0, 0});
body_t *body = body_init(shape, 1, (rgb_color_t) {0, 0, 0});
assert(!body_is_removed(body));
body_remove(body);
assert(body_is_removed(body));
......@@ -189,36 +189,36 @@ void test_body_remove() {
}
void test_body_info() {
List *shape = list_init(3, free);
Vector *v = malloc(sizeof(*v));
*v = (Vector) {+1, 0};
list_t *shape = list_init(3, free);
vector_t *v = malloc(sizeof(*v));
*v = (vector_t) {+1, 0};
list_add(shape, v);
v = malloc(sizeof(*v));
*v = (Vector) {0, +1};
*v = (vector_t) {0, +1};
list_add(shape, v);
v = malloc(sizeof(*v));
*v = (Vector) {-1, 0};
*v = (vector_t) {-1, 0};
list_add(shape, v);
int *info = malloc(sizeof(*info));
*info = 123;
Body *body = body_init_with_info(shape, 1, (RGBColor) {0, 0, 0}, info, NULL);
body_t *body = body_init_with_info(shape, 1, (rgb_color_t) {0, 0, 0}, info, NULL);
assert(*(int *) body_get_info(body) == 123);
body_free(body);
free(info);
}
void test_body_info_freer() {
List *shape = list_init(3, free);
Vector *v = malloc(sizeof(*v));
*v = (Vector) {+1, 0};
list_t *shape = list_init(3, free);
vector_t *v = malloc(sizeof(*v));
*v = (vector_t) {+1, 0};
list_add(shape, v);
v = malloc(sizeof(*v));
*v = (Vector) {0, +1};
*v = (vector_t) {0, +1};
list_add(shape, v);
v = malloc(sizeof(*v));
*v = (Vector) {-1, 0};
*v = (vector_t) {-1, 0};
list_add(shape, v);
List *info = list_init(3, free);
list_t *info = list_init(3, free);
int *info_elem = malloc(sizeof(*info_elem));
*info_elem = 10;
list_add(info, info_elem);
......@@ -228,8 +228,12 @@ void test_body_info_freer() {
info_elem = malloc(sizeof(*info_elem));
*info_elem = 30;
list_add(info, info_elem);
Body *body = body_init_with_info(
shape, 1, (RGBColor) {0, 0, 0}, info, (FreeFunc) list_free
body_t *body = body_init_with_info(
shape,
1,
(rgb_color_t) {0, 0, 0},
info,
(free_func_t) list_free
);
assert(*(int *) list_get(body_get_info(body), 0) == 10);
assert(*(int *) list_get(body_get_info(body), 1) == 20);
......@@ -256,5 +260,4 @@ int main(int argc, char *argv[]) {
DO_TEST(test_body_info_freer)
puts("body_test PASS");
return 0;
}
......@@ -4,19 +4,19 @@
#include <math.h>
#include <stdlib.h>
List *make_shape() {
List *shape = list_init(4, free);
Vector *v = malloc(sizeof(*v));
*v = (Vector) {-1, -1};
list_t *make_shape() {
list_t *shape = list_init(4, free);
vector_t *v = malloc(sizeof(*v));
*v = (vector_t) {-1, -1};
list_add(shape, v);
v = malloc(sizeof(*v));
*v = (Vector) {+1, -1};
*v = (vector_t) {+1, -1};
list_add(shape, v);
v = malloc(sizeof(*v));
*v = (Vector) {+1, +1};
*v = (vector_t) {+1, +1};
list_add(shape, v);
v = malloc(sizeof(*v));
*v = (Vector) {-1, +1};
*v = (vector_t) {-1, +1};
list_add(shape, v);
return shape;
}
......@@ -28,29 +28,30 @@ void test_spring_sinusoid() {
const double A = 3;
const double DT = 1e-6;
const int STEPS = 1000000;
Scene *scene = scene_init();
Body *mass = body_init(make_shape(), M, (RGBColor) {0, 0, 0});
body_set_centroid(mass, (Vector) {A, 0});
scene_t *scene = scene_init();
body_t *mass = body_init(make_shape(), M, (rgb_color_t) {0, 0, 0});
body_set_centroid(mass, (vector_t) {A, 0});
scene_add_body(scene, mass);
Body *anchor = body_init(make_shape(), INFINITY, (RGBColor) {0, 0, 0});
body_t *anchor = body_init(make_shape(), INFINITY, (rgb_color_t) {0, 0, 0});
scene_add_body(scene, anchor);
create_spring(scene, K, mass, anchor);
for (int i = 0; i < STEPS; i++) {
assert(vec_isclose(
body_get_centroid(mass),
(Vector) {A * cos(sqrt(K / M) * i * DT), 0}
(vector_t) {A * cos(sqrt(K / M) * i * DT), 0}
));
assert(vec_equal(body_get_centroid(anchor), VEC_ZERO));
scene_tick(scene, DT);
}
scene_free(scene);
}
double gravity_potential(double G, Body *body1, Body *body2) {
Vector r = vec_subtract(body_get_centroid(body2), body_get_centroid(body1));
double gravity_potential(double G, body_t *body1, body_t *body2) {
vector_t r = vec_subtract(body_get_centroid(body2), body_get_centroid(body1));
return -G * body_get_mass(body1) * body_get_mass(body2) / sqrt(vec_dot(r, r));
}
double kinetic_energy(Body *body) {
Vector v = body_get_velocity(body);
double kinetic_energy(body_t *body) {
vector_t v = body_get_velocity(body);
return body_get_mass(body) * vec_dot(v, v) / 2;
}
......@@ -60,11 +61,11 @@ void test_energy_conservation() {
const double G = 1e3;
const double DT = 1e-6;
const int STEPS = 1000000;
Scene *scene = scene_init();
Body *mass1 = body_init(make_shape(), M1, (RGBColor) {0, 0, 0});
scene_t *scene = scene_init();
body_t *mass1 = body_init(make_shape(), M1, (rgb_color_t) {0, 0, 0});
scene_add_body(scene, mass1);
Body *mass2 = body_init(make_shape(), M2, (RGBColor) {0, 0, 0});
body_set_centroid(mass2, (Vector) {10, 20});
body_t *mass2 = body_init(make_shape(), M2, (rgb_color_t) {0, 0, 0});
body_set_centroid(mass2, (vector_t) {10, 20});
scene_add_body(scene, mass2);
create_newtonian_gravity(scene, G, mass1, mass2);
double initial_energy = gravity_potential(G, mass1, mass2);
......@@ -72,24 +73,24 @@ void test_energy_conservation() {
assert(body_get_centroid(mass1).x < body_get_centroid(mass2).x);
double energy = gravity_potential(G, mass1, mass2) +
kinetic_energy(mass1) + kinetic_energy(mass2);
assert(within(1e-5, energy / initial_energy, 1));
assert(within(1e-4, energy / initial_energy, 1));
scene_tick(scene, DT);
}
scene_free(scene);
}
Body *make_triangle_body() {
List *shape = list_init(3, free);
Vector *v = malloc(sizeof(*v));
*v = (Vector) {1, 0};
body_t *make_triangle_body() {
list_t *shape = list_init(3, free);
vector_t *v = malloc(sizeof(*v));
*v = (vector_t) {1, 0};
list_add(shape, v);
v = malloc(sizeof(*v));
*v = (Vector) {-0.5, +sqrt(3) / 2};
*v = (vector_t) {-0.5, +sqrt(3) / 2};
list_add(shape, v);
v = malloc(sizeof(*v));
*v = (Vector) {-0.5, -sqrt(3) / 2};
*v = (vector_t) {-0.5, -sqrt(3) / 2};
list_add(shape, v);
return body_init(shape, 1, (RGBColor) {0, 0, 0});
return body_init(shape, 1, (rgb_color_t) {0, 0, 0});
}
// Tests that destructive collisions remove bodies from the scene
......@@ -99,19 +100,19 @@ void test_collisions() {
const double SEPARATION_AT_COLLISION = 1.5;
const int TICKS_TO_COLLISION = 10;
Scene *scene = scene_init();
Body *body1 = make_triangle_body();
Vector initial_separation =
scene_t *scene = scene_init();
body_t *body1 = make_triangle_body();
vector_t initial_separation =
{SEPARATION_AT_COLLISION + V * DT * (TICKS_TO_COLLISION - 0.5), 0};
body_set_centroid(body1, vec_negate(initial_separation));
body_set_velocity(body1, (Vector) {+V, 0});
body_set_velocity(body1, (vector_t) {+V, 0});
scene_add_body(scene, body1);
Body *body2 = make_triangle_body();
body_t *body2 = make_triangle_body();
scene_add_body(scene, body2);
Body *body3 = make_triangle_body();
body_set_velocity(body3, (Vector) {-V, 0});
body_t *body3 = make_triangle_body();
body_set_velocity(body3, (vector_t) {-V, 0});
body_set_centroid(body3, initial_separation);
scene_add_body(scene, body3);
......@@ -134,10 +135,10 @@ void test_collisions() {
// Tests that force creators properly register their list of affected bodies.
// If they don't, asan will report a heap-use-after-free failure.
void test_forces_removed() {
Scene *scene = scene_init();
scene_t *scene = scene_init();
for (int i = 0; i < 10; i++) {
Body *body = body_init(make_shape(), 1, (RGBColor) {0, 0, 0});
body_set_centroid(body, (Vector) {i, i});
body_t *body = body_init(make_shape(), 1, (rgb_color_t) {0, 0, 0});
body_set_centroid(body, (vector_t) {i, i});
scene_add_body(scene, body);
for (int j = 0; j < i; j++) {
create_newtonian_gravity(scene, 1, body, scene_get_body(scene, j));
......@@ -167,5 +168,4 @@ int main(int argc, char *argv[]) {
DO_TEST(test_forces_removed)
puts("forces_test PASS");
return 0;
}
......@@ -5,14 +5,14 @@
#include <stdlib.h>
void scene_get_first(void *scene) {
scene_get_body((Scene *) scene, 0);
scene_get_body(scene, 0);
}
void scene_remove_first(void *scene) {
scene_remove_body((Scene *) scene, 0);
scene_remove_body(scene, 0);
}
void test_empty_scene() {
Scene *scene = scene_init();
scene_t *scene = scene_init();
assert(scene_bodies(scene) == 0);
for (int i = 0; i < 10; i++) scene_tick(scene, 1);
assert(test_assert_fail(scene_get_first, scene));
......@@ -20,37 +20,37 @@ void test_empty_scene() {
scene_free(scene);
}
List *make_shape() {
List *shape = list_init(4, free);
Vector *v = malloc(sizeof(*v));
*v = (Vector) {-1, -1};
list_t *make_shape() {
list_t *shape = list_init(4, free);
vector_t *v = malloc(sizeof(*v));
*v = (vector_t) {-1, -1};
list_add(shape, v);
v = malloc(sizeof(*v));
*v = (Vector) {+1, -1};
*v = (vector_t) {+1, -1};
list_add(shape, v);
v = malloc(sizeof(*v));
*v = (Vector) {+1, +1};
*v = (vector_t) {+1, +1};
list_add(shape, v);
v = malloc(sizeof(*v));
*v = (Vector) {-1, +1};
*v = (vector_t) {-1, +1};
list_add(shape, v);
return shape;
}
void test_scene() {
// Build a scene with 3 bodies
Scene *scene = scene_init();
scene_t *scene = scene_init();
assert(scene_bodies(scene) == 0);
Body *body1 = body_init(make_shape(), 1, (RGBColor) {1, 1, 1});
body_t *body1 = body_init(make_shape(), 1, (rgb_color_t) {1, 1, 1});
scene_add_body(scene, body1);
assert(scene_bodies(scene) == 1);
assert(scene_get_body(scene, 0) == body1);
Body *body2 = body_init(make_shape(), 2, (RGBColor) {1, 1, 1});
body_t *body2 = body_init(make_shape(), 2, (rgb_color_t) {1, 1, 1});
scene_add_body(scene, body2);
assert(scene_bodies(scene) == 2);
assert(scene_get_body(scene, 0) == body1);
assert(scene_get_body(scene, 1) == body2);
Body *body3 = body_init(make_shape(), 3, (RGBColor) {1, 1, 1});
body_t *body3 = body_init(make_shape(), 3, (rgb_color_t) {1, 1, 1});
scene_add_body(scene, body3);
assert(scene_bodies(scene) == 3);
assert(scene_get_body(scene, 0) == body1);
......@@ -58,20 +58,20 @@ void test_scene() {
assert(scene_get_body(scene, 2) == body3);
// Set the bodies' positions with no velocity and ensure they match
body_set_centroid(body1, (Vector) {1, 1});
body_set_centroid(body2, (Vector) {2, 2});
body_set_centroid(body3, (Vector) {3, 3});
body_set_centroid(body1, (vector_t) {1, 1});
body_set_centroid(body2, (vector_t) {2, 2});
body_set_centroid(body3, (vector_t) {3, 3});
scene_tick(scene, 1);
assert(vec_isclose(body_get_centroid(body1), (Vector) {1, 1}));
assert(vec_isclose(body_get_centroid(body2), (Vector) {2, 2}));
assert(vec_isclose(body_get_centroid(body3), (Vector) {3, 3}));
body_set_velocity(body1, (Vector) {+1, 0});
body_set_velocity(body2, (Vector) {-1, 0});
body_set_velocity(body3, (Vector) {0, +1});
assert(vec_isclose(body_get_centroid(body1), (vector_t) {1, 1}));
assert(vec_isclose(body_get_centroid(body2), (vector_t) {2, 2}));
assert(vec_isclose(body_get_centroid(body3), (vector_t) {3, 3}));
body_set_velocity(body1, (vector_t) {+1, 0});
body_set_velocity(body2, (vector_t) {-1, 0});
body_set_velocity(body3, (vector_t) {0, +1});
scene_tick(scene, 1);
assert(vec_isclose(body_get_centroid(body1), (Vector) {2, 1}));
assert(vec_isclose(body_get_centroid(body2), (Vector) {1, 2}));
assert(vec_isclose(body_get_centroid(body3), (Vector) {3, 4}));
assert(vec_isclose(body_get_centroid(body1), (vector_t) {2, 1}));
assert(vec_isclose(body_get_centroid(body2), (vector_t) {1, 2}));
assert(vec_isclose(body_get_centroid(body3), (vector_t) {3, 4}));
// Try removing the second body
scene_remove_body(scene, 1);
......@@ -83,19 +83,19 @@ void test_scene() {
// Tick the remaining bodies
scene_tick(scene, 1);
assert(vec_isclose(body_get_centroid(body1), (Vector) {3, 1}));
assert(vec_isclose(body_get_centroid(body3), (Vector) {3, 5}));
assert(vec_isclose(body_get_centroid(body1), (vector_t) {3, 1}));
assert(vec_isclose(body_get_centroid(body3), (vector_t) {3, 5}));
scene_free(scene);
}
// A force creator that moves a body in uniform circular motion about the origin
void centripetal_force(void *aux) {
Body *body = (Body *) aux;
Vector v = body_get_velocity(body);
Vector r = body_get_centroid(body);
body_t *body = aux;
vector_t v = body_get_velocity(body);
vector_t r = body_get_centroid(body);
assert(isclose(vec_dot(v, r), 0));
Vector force =
vector_t force =
vec_multiply(-body_get_mass(body) * vec_dot(v, v) / vec_dot(r, r), r);
body_add_force(body, force);
}
......@@ -105,14 +105,15 @@ void test_force_creator() {
const double R = 2;
const double DT = 1e-6;
const int STEPS = 1000000;
Scene *scene = scene_init();
Body *body = body_init(make_shape(), 123, (RGBColor) {0, 0, 0});
body_set_centroid(body, (Vector) {R, 0});
body_set_velocity(body, (Vector) {0, OMEGA * R});
scene_t *scene = scene_init();
body_t *body = body_init(make_shape(), 123, (rgb_color_t) {0, 0, 0});
vector_t radius = {R, 0};
body_set_centroid(body, radius);
body_set_velocity(body, (vector_t) {0, OMEGA * R});
scene_add_body(scene, body);
scene_add_force_creator(scene, centripetal_force, body, NULL);
for (int i = 0; i < STEPS; i++) {
Vector expected_x = vec_rotate((Vector) {R, 0}, OMEGA * i * DT);
vector_t expected_x = vec_rotate(radius, OMEGA * i * DT);
assert(vec_within(1e-4, body_get_centroid(body), expected_x));
scene_tick(scene, DT);
}
......@@ -120,29 +121,29 @@ void test_force_creator() {
}
typedef struct {
Scene *scene;
scene_t *scene;
double coefficient;
} ForceAux;
} force_aux_t;
// A force creator that applies constant downwards gravity to all bodies in a scene
void constant_gravity(void *aux) {
ForceAux *gravity_aux = (ForceAux *) aux;
force_aux_t *gravity_aux = aux;
size_t body_count = scene_bodies(gravity_aux->scene);
for (size_t i = 0; i < body_count; i++) {
Body *body = scene_get_body(gravity_aux->scene, i);
Vector force = {0, -gravity_aux->coefficient * body_get_mass(body)};
body_t *body = scene_get_body(gravity_aux->scene, i);
vector_t force = {0, -gravity_aux->coefficient * body_get_mass(body)};
body_add_force(body, force);
}
}
// A force creator that applies drag proportional to v ** 2 to all bodies in a scene
void air_drag(void *aux) {
ForceAux *drag_aux = (ForceAux *) aux;
force_aux_t *drag_aux = aux;
size_t body_count = scene_bodies(drag_aux->scene);
for (size_t i = 0; i < body_count; i++) {
Body *body = scene_get_body(drag_aux->scene, i);
Vector v = body_get_velocity(body);
Vector force =
body_t *body = scene_get_body(drag_aux->scene, i);
vector_t v = body_get_velocity(body);
vector_t force =
vec_multiply(-drag_aux->coefficient * sqrt(vec_dot(v, v)), v);
body_add_force(body, force);
}
......@@ -153,27 +154,27 @@ void test_force_creator_aux() {
const double GRAVITY = 9.8, DRAG = 3;
const double DT = 1e-3;
const int STEPS = 100000;
Scene *scene = scene_init();
Body *light = body_init(make_shape(), LIGHT_MASS, (RGBColor) {0, 0, 0});
scene_t *scene = scene_init();
body_t *light = body_init(make_shape(), LIGHT_MASS, (rgb_color_t) {0, 0, 0});
scene_add_body(scene, light);
Body *heavy = body_init(make_shape(), HEAVY_MASS, (RGBColor) {0, 0, 0});
body_t *heavy = body_init(make_shape(), HEAVY_MASS, (rgb_color_t) {0, 0, 0});
scene_add_body(scene, heavy);
ForceAux *gravity_aux = malloc(sizeof(*gravity_aux));
force_aux_t *gravity_aux = malloc(sizeof(*gravity_aux));
gravity_aux->scene = scene;
gravity_aux->coefficient = GRAVITY;
scene_add_force_creator(scene, constant_gravity, gravity_aux, free);
ForceAux *drag_aux = malloc(sizeof(*drag_aux));
force_aux_t *drag_aux = malloc(sizeof(*drag_aux));
drag_aux->scene = scene;
drag_aux->coefficient = DRAG;
scene_add_force_creator(scene, air_drag, drag_aux, free);
for (int i = 0; i < STEPS; i++) scene_tick(scene, DT);
assert(vec_isclose(
body_get_velocity(light),
(Vector) {0, -sqrt(GRAVITY * LIGHT_MASS / DRAG)
(vector_t) {0, -sqrt(GRAVITY * LIGHT_MASS / DRAG)
}));
assert(vec_isclose(
body_get_velocity(heavy),
(Vector) {0, -sqrt(GRAVITY * HEAVY_MASS / DRAG)
(vector_t) {0, -sqrt(GRAVITY * HEAVY_MASS / DRAG)
}));
scene_free(scene);
}
......@@ -187,7 +188,7 @@ void test_force_creator_aux() {
so it should only be called during the first two ticks.
*/
void remove_body(void *aux) {
Scene *scene = (Scene *) aux;
scene_t *scene = aux;
size_t body_count = scene_bodies(scene);
if (body_count > 0) {
body_remove(scene_get_body(scene, body_count - 1));
......@@ -195,10 +196,10 @@ void remove_body(void *aux) {
}
typedef struct {
int count;
Scene *scene;
} CountAux;
scene_t *scene;
} count_aux_t;
void count_calls(void *aux) {
CountAux *count_aux = (CountAux *) aux;
count_aux_t *count_aux = aux;
// Every time count_calls() is called, the body count should decrease by 1
assert(scene_bodies(count_aux->scene) == 3 - count_aux->count);
// Record that count_calls() was called an additional time
......@@ -206,23 +207,19 @@ void count_calls(void *aux) {
}
void test_reaping() {
Scene *scene = scene_init();
scene_t *scene = scene_init();
for (int i = 0; i < 3; i++) {
scene_add_body(scene, body_init(make_shape(), 1, (RGBColor) {0, 0, 0}));
scene_add_body(scene, body_init(make_shape(), 1, (rgb_color_t) {0, 0, 0}));
}
scene_add_bodies_force_creator(
scene, remove_body, scene, list_init(0, NULL), NULL
);
scene_add_bodies_force_creator(scene, remove_body, scene, list_init(0, NULL), NULL);
CountAux *count_aux = malloc(sizeof(*count_aux));
count_aux_t *count_aux = malloc(sizeof(*count_aux));
count_aux->count = 0;
count_aux->scene = scene;
List *required_bodies = list_init(2, NULL);
list_t *required_bodies = list_init(2, NULL);
list_add(required_bodies, scene_get_body(scene, 0));
list_add(required_bodies, scene_get_body(scene, 1));
scene_add_bodies_force_creator(
scene, count_calls, count_aux, required_bodies, NULL
);
scene_add_bodies_force_creator(scene, count_calls, count_aux, required_bodies, NULL);
while (scene_bodies(scene) > 0) {
scene_tick(scene, 1);
......@@ -249,5 +246,4 @@ int main(int argc, char *argv[]) {
DO_TEST(test_reaping)
puts("scene_test PASS");
return 0;
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment