diff options
| author | Sam Anthony <sam@samanthony.xyz> | 2024-10-02 12:53:54 -0400 |
|---|---|---|
| committer | Sam Anthony <sam@samanthony.xyz> | 2024-10-02 12:53:54 -0400 |
| commit | 9ade04722dd351c3f42cd98be28fc255043b3030 (patch) | |
| tree | 3aced80bf9cc9fb4160e2fab1ad7afa2d5b45df9 | |
| parent | 2c54c155c9dc92c62881998c055bce17beddbe4f (diff) | |
| download | balls-9ade04722dd351c3f42cd98be28fc255043b3030.zip | |
multiple balls
| -rw-r--r-- | Makefile | 2 | ||||
| -rw-r--r-- | balls.cpp | 87 | ||||
| -rw-r--r-- | balls.h | 12 | ||||
| -rw-r--r-- | collision.cpp (renamed from collision.c) | 9 | ||||
| -rw-r--r-- | geometry.cpp | 11 | ||||
| -rw-r--r-- | rand.cpp | 15 |
6 files changed, 127 insertions, 9 deletions
@@ -2,7 +2,7 @@ CC = g++ CFLAGS = -Wall -pedantic LDFLAGS = -ltbb -lglut -lGLU -lGL -balls: balls.o collision.o geometry.o +balls: balls.o collision.o geometry.o rand.o ${CC} -o $@ $^ ${LDFLAGS} @echo done @@ -1,4 +1,4 @@ -#include <stdlib.h> +#include <iostream> #include <GL/glut.h> #include <oneapi/tbb.h> @@ -6,6 +6,14 @@ using namespace std; +#define VMAX_INIT 0.15 + /* max initial velocity [m/s] */ +#define RMIN 0.05 +#define RMAX 0.10 + /* min/max radius [m] */ +#define DENSITY 1500.0 + /* density of ball [kg/m^3] */ + enum { WIDTH = 800, HEIGHT = 600, @@ -17,6 +25,8 @@ enum { FPS = 60, MS_PER_S = 1000, FRAME_TIME_MS = MS_PER_S / FPS, + + NBALLS_DEFAULT = 3, }; void keyboard(unsigned char key, int x, int y); @@ -24,10 +34,15 @@ void display(void); void drawBg(void); void drawCircle(double radius, Point p); void reshape(int w, int h); +vector<Ball> makeBalls(unsigned int n); +vector<Point> noOverlapCircles(unsigned int n); +double mass(double radius); +double volumeSphere(double radius); void animate(int v); const static Rectangle bounds = {{-1.5, -1.0}, {1.5, 1.0}}; -static Ball ball = {{0.25, 0.25}, {0.25, 0.25}, 0.200, 0.25}; + +static vector<Ball> balls; int main(int argc, char *argv[]) { @@ -39,6 +54,9 @@ main(int argc, char *argv[]) { glutKeyboardFunc(keyboard); glutDisplayFunc(display); glutReshapeFunc(reshape); + + balls = makeBalls(NBALLS_DEFAULT); + glutTimerFunc(FRAME_TIME_MS, animate, 0); glutMainLoop(); @@ -57,7 +75,8 @@ display(void) { glClearColor(0, 0, 0, 1); glClear(GL_COLOR_BUFFER_BIT); drawBg(); - drawCircle(ball.r, ball.p); + for (Ball b : balls) + drawCircle(b.r, b.p); glutSwapBuffers(); } @@ -105,11 +124,67 @@ reshape(int w, int h) { glMatrixMode(GL_MODELVIEW); } +vector<Ball> +makeBalls(unsigned int n) { + vector<Ball> balls(n); + vector<Point> ps = noOverlapCircles(n); + unsigned int i; + + srand(time(0)); + for (i = 0; i < n; i++) { + cout << "Creating ball " << i << "\n"; + balls[i].p = ps[i]; + + balls[i].v.x = randDouble(-VMAX_INIT, VMAX_INIT); + balls[i].v.y = randDouble(-VMAX_INIT, VMAX_INIT); + + balls[i].r = randDouble(RMIN, RMAX); + + balls[i].m = mass(balls[i].r); + } + return balls; +} + +vector<Point> +noOverlapCircles(unsigned int n) { + vector<Point> ps(n); + Rectangle r; + unsigned int i, j; + + srand(time(0)); + r = insetRect(bounds, RMAX); + for (i = 0; i < n; i++) { + cout << "Create non-overlapping circle " << i << "\n"; + ps[i] = randPtInRect(r); + for (j = 0; j < i; j++) /* TODO: parallel reduce */ + if (isCollision(ps[j], RMAX, ps[i], RMAX)) + break; + if (j < i) { /* overlapping */ + i--; + continue; + } + } + return ps; +} + +/* mass [kg] of ball as function of radius [m] */ +double +mass(double radius) { + return volumeSphere(radius) * DENSITY; +} + +/* volume [m^3] of sphere as function of radius [m] */ +double +volumeSphere(double radius) { + return 4.0 * M_PI * radius*radius*radius / 3.0; +} + void animate(int v) { - ball.p = ptAddVec(ball.p, ball.v); - - collideWall(&ball, bounds); + for (Ball& ball : balls) { + ball.p = ptAddVec(ball.p, ball.v); + collideWall(&ball, bounds); + } display(); glutTimerFunc(FRAME_TIME_MS, animate, 0); @@ -1,3 +1,5 @@ +#include <stdlib.h> + typedef struct { double x, y; } Point; @@ -13,11 +15,17 @@ typedef struct { typedef struct { Point p; /* position [m] */ Vector v; /* velocity [m/s] */ - double m; /* mass [kg] */ double r; /* radius [m] */ + double m; /* mass [kg] */ } Ball; Point ptAddVec(Point p, Vector v); +Point Pt(double x, double y); Rectangle insetRect(Rectangle r, double n); +Point randPtInRect(Rectangle r); + +int isCollision(Point p1, double r1, Point p2, double r2); +void collideWall(Ball *b, Rectangle wall); -void collideWall(Ball *b, Rectangle wall);
\ No newline at end of file +int randInt(int lo, int hi); +double randDouble(double lo, double hi); diff --git a/collision.c b/collision.cpp index 17889a4..1ffe957 100644 --- a/collision.c +++ b/collision.cpp @@ -4,6 +4,15 @@ static double clamp(double v, double lo, double hi); static double min(double a, double b); static double max(double a, double b); +int +isCollision(Point p1, double r1, Point p2, double r2) { + double dx, dy; + + dx = p1.x - p2.x; + dy = p1.y - p2.y; + return (dx*dx + dy*dy) <= (r1+r2)*(r1+r2); +} + void collideWall(Ball *b, Rectangle wall) { wall = insetRect(wall, b->r); diff --git a/geometry.cpp b/geometry.cpp index ae2c8ae..2bdad8c 100644 --- a/geometry.cpp +++ b/geometry.cpp @@ -7,6 +7,12 @@ ptAddVec(Point p, Vector v) { return p; } +Point +Pt(double x, double y) { + Point p = {x, y}; + return p; +} + Rectangle insetRect(Rectangle r, double n) { r.min.x += n; @@ -15,3 +21,8 @@ insetRect(Rectangle r, double n) { r.max.y -= n; return r; } + +Point +randPtInRect(Rectangle r) { + return Pt(randDouble(r.min.x, r.max.x), randDouble(r.min.y, r.max.y)); +} diff --git a/rand.cpp b/rand.cpp new file mode 100644 index 0000000..6ffe897 --- /dev/null +++ b/rand.cpp @@ -0,0 +1,15 @@ +#include "balls.h" + +int +randInt(int lo, int hi) { + return (rand() % (hi-lo)) + lo; +} + +double +randDouble(double lo, double hi) { + double r, diff; + + r = (double) rand() / (double) RAND_MAX; + diff = hi - lo; + return lo + r*diff; +} |