diff options
-rw-r--r-- | dat.h | 32 | ||||
-rw-r--r-- | fns.h | 15 | ||||
-rw-r--r-- | main.c | 244 | ||||
-rw-r--r-- | matrix.c | 74 | ||||
-rw-r--r-- | mkfile | 13 | ||||
-rw-r--r-- | util.c | 16 | ||||
-rw-r--r-- | vector.c | 48 |
7 files changed, 442 insertions, 0 deletions
@@ -0,0 +1,32 @@ +#define DEG 0.01745329251994330 +#define Eg 9.81 +#define PIX2M 0.001 +#define M2PIX (1.0/PIX2M) + +enum { + STACK = 8192, + SEC = 1000, + FPS = 60, +}; + +enum { + Stheta = 0, + Spos, + Svel, + Sdeltax, + Seta, + SLEN, +}; + +typedef struct Vector Vector; +typedef double Matrix[3][3]; +typedef struct Projectile Projectile; + +struct Vector { + double x, y, w; +}; + +struct Projectile { + Vector p, v; + double mass; +}; @@ -0,0 +1,15 @@ +void addm(Matrix, Matrix); +void subm(Matrix, Matrix); +void mulm(Matrix, Matrix); +void transm(Matrix); +double detm(Matrix); +Vector mulvecm(Vector, Matrix); +Vector Vec(double, double, double); +Vector addvec(Vector, Vector); +Vector subvec(Vector, Vector); +Vector mulvec(Vector, double); +double dotvec(Vector, Vector); +Vector normvec(Vector); +double round(double); +double hypot3(double, double, double); +void *emalloc(ulong); @@ -0,0 +1,244 @@ +#include <u.h> +#include <libc.h> +#include <thread.h> +#include <draw.h> +#include <mouse.h> +#include <keyboard.h> +#include "dat.h" +#include "fns.h" + +Mousectl *mc; +Keyboardctl *kc; +Channel *scrsync; +Point orig; +Vector basis; +Projectile ball; +double t0, Δt; +double v0; +Vector target; + +char stats[SLEN][64]; +Image *statc; + +void * +emalloc(ulong n) +{ + void *p; + + p = malloc(n); + if(p == nil) + sysfatal("malloc: %r"); + memset(p, 0, n); + setmalloctag(p, getcallerpc(&n)); + return p; +} + +Point +toscreen(Vector p) +{ + return addpt(orig, Pt(p.x*basis.x, p.y*basis.y)); +} + +Vector +fromscreen(Point p) +{ + return Vec((p.x-screen->r.min.x)*M2PIX, (screen->r.max.y-p.y)*M2PIX, 1); +} + +void +drawstats(void) +{ + int i; + + snprint(stats[Svel], sizeof(stats[Svel]), "v: %gm/s", hypot(ball.v.x, ball.v.y)); + snprint(stats[Sdeltax], sizeof(stats[Sdeltax]), "Δx: %gm", target.x-ball.p.x); + for(i = 0; i < nelem(stats); i++) + stringn(screen, addpt(screen->r.min, Pt(10, font->height*i+1)), statc, ZP, font, stats[i], sizeof(stats[i])); +} + +void +redraw(void) +{ + lockdisplay(display); + draw(screen, screen->r, display->black, nil, ZP); + fillellipse(screen, toscreen(ball.p), 2, 2, display->white, ZP); + line(screen, toscreen(Vec(ball.p.x, 0, 1)), toscreen(target), 0, 0, 1, statc, ZP); + drawstats(); + flushimage(display, 1); + unlockdisplay(display); +} + +void +mmb(void) +{ + enum { + SETV0, + }; + static char *items[] = { + [SETV0] "set v0", + nil + }; + static Menu menu = { .item = items }; + char buf[32]; + + snprint(buf, sizeof(buf), "%g", v0); + switch(menuhit(2, mc, &menu, nil)){ + case SETV0: + enter("v0(m/s):", buf, sizeof(buf), mc, kc, nil); + v0 = strtod(buf, 0); + break; + } +} + +void +rmb(void) +{ + enum { + RST, + QUIT, + }; + static char *items[] = { + [RST] "reset", + [QUIT] "quit", + nil, + }; + static Menu menu = { .item = items }; + + switch(menuhit(3, mc, &menu, nil)){ + case RST: + ball.p = Vec((2+1)*M2PIX, (2+1)*M2PIX, 1); + ball.v = Vec(0, 0, 1); + break; + case QUIT: + threadexitsall(nil); + } +} + +void +mouse(void) +{ + Vector p; + double θ, dist, eta; + + if(ball.p.y <= (2+1)*M2PIX){ + p = subvec(fromscreen(mc->xy), ball.p); + θ = atan2(p.y, p.x); + snprint(stats[Stheta], sizeof(stats[Stheta]), "θ: %g°", θ*180/PI); + dist = v0*v0*sin(2*θ)/Eg; + target = Vec(ball.p.x+dist, 0, 1); + eta = 2*v0*sin(θ)/Eg; + snprint(stats[Seta], sizeof(stats[Seta]), "eta: %gs", eta); + if((mc->buttons & 1) != 0) + ball.v = Vec(v0*cos(θ), v0*sin(θ), 1); + } + if((mc->buttons & 2) != 0) + mmb(); + if((mc->buttons & 4) != 0) + rmb(); +} + +void +key(Rune r) +{ + switch(r){ + case Kdel: + case 'q': + threadexitsall(nil); + } +} + +void +resized(void) +{ + lockdisplay(display); + if(getwindow(display, Refnone) < 0) + fprint(2, "can't reattach to window\n"); + orig = Pt(screen->r.min.x, screen->r.max.y); + unlockdisplay(display); + redraw(); +} + +void +scrsyncproc(void *) +{ + for(;;){ + send(scrsync, nil); + sleep(SEC/FPS); + } +} + +#pragma varargck type "V" Vector; +int +Vfmt(Fmt *f) +{ + Vector v; + + v = va_arg(f->args, Vector); + return fmtprint(f, "(%g %g)", v.x, v.y); +} + +void +usage(void) +{ + fprint(2, "usage: %s\n", argv0); + exits("usage"); +} + +void +threadmain(int argc, char *argv[]) +{ + Rune r; + + fmtinstall('V', Vfmt); + ARGBEGIN{ + default: usage(); + }ARGEND; + + if(initdraw(nil, nil, "ballistics") < 0) + sysfatal("initdraw: %r"); + mc = initmouse(nil, screen); + if(mc == nil) + sysfatal("initmouse: %r"); + kc = initkeyboard(nil); + if(kc == nil) + sysfatal("initkeyboard: %r"); + statc = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, DYellow); + if(statc == nil) + sysfatal("allocimage: %r"); + orig = Pt(screen->r.min.x, screen->r.max.y); + basis = Vec(PIX2M, -PIX2M, 1); + ball.p = Vec((2+1)*M2PIX, (2+1)*M2PIX, 1); + ball.v = Vec(0, 0, 1); + ball.mass = 106000; + v0 = 1640; /* Paris Gun's specs */ + scrsync = chancreate(1, 0); + display->locking = 1; + unlockdisplay(display); + proccreate(scrsyncproc, 0, STACK); + t0 = nsec(); + + for(;;){ + Alt a[] = { + {mc->c, &mc->Mouse, CHANRCV}, + {mc->resizec, nil, CHANRCV}, + {kc->c, &r, CHANRCV}, + {scrsync, nil, CHANRCV}, + {nil, nil, CHANEND} + }; + switch(alt(a)){ + case 0: mouse(); break; + case 1: resized(); break; + case 2: key(r); break; + case 3: redraw(); break; + } + Δt = (nsec()-t0)/1e9; + ball.v = addvec(ball.v, mulvec(Vec(0, -Eg, 1), Δt)); + ball.p = addvec(ball.p, mulvec(ball.v, Δt)); + snprint(stats[Spos], sizeof(stats[Spos]), "p: %V", ball.p); + if(ball.p.y <= (2+1)*M2PIX){ + ball.p.y = (2+1)*M2PIX; + ball.v = Vec(0, 0, 1); + } + t0 += Δt*1e9; + } +} diff --git a/matrix.c b/matrix.c new file mode 100644 index 0000000..12956a7 --- /dev/null +++ b/matrix.c @@ -0,0 +1,74 @@ +#include <u.h> +#include <libc.h> +#include "dat.h" +#include "fns.h" + +void +addm(Matrix a, Matrix b) +{ + int i, j; + + for(i = 0; i < 3; i++) + for(j = 0; j < 3; j++) + a[i][j] += b[i][j]; +} + +void +subm(Matrix a, Matrix b) +{ + int i, j; + + for(i = 0; i < 3; i++) + for(j = 0; j < 3; j++) + a[i][j] -= b[i][j]; +} + +void +mulm(Matrix a, Matrix b) +{ + int i, j, k; + Matrix r; + + for(i = 0; i < 3; i++) + for(j = 0; j < 3; j++){ + r[i][j] = 0; + for(k = 0; k < 3; k++) + r[i][j] += a[i][k]*b[k][j]; + } + for(i = 0; i < 3; i++) + for(j = 0; j < 3; j++) + a[i][j] = r[i][j]; +} + +void +transm(Matrix m) +{ + int i, j; + double tmp; + + for(i = 0; i < 3; i++) + for(j = i; j < 3; j++){ + tmp = m[i][j]; + m[i][j] = m[j][i]; + m[j][i] = tmp; + } +} + +double +detm(Matrix m) +{ + return m[0][0]*(m[1][1]*m[2][2] - m[1][2]*m[2][1]) + + m[0][1]*(m[1][2]*m[2][0] - m[1][0]*m[2][2]) + + m[0][2]*(m[1][0]*m[2][1] - m[1][1]*m[2][0]); +} + +Vector +mulvecm(Vector v, Matrix m) +{ + Vector r; + + r.x = v.x * m[0][0] + v.y * m[0][1] + v.w * m[0][2]; + r.y = v.x * m[1][0] + v.y * m[1][1] + v.w * m[1][2]; + r.w = v.x * m[2][0] + v.y * m[2][1] + v.w * m[2][2]; + return r; +} @@ -0,0 +1,13 @@ +</$objtype/mkfile + +BIN=/$objtype/bin/ +TARG=ballistics +OFILES=\ + main.$O\ + util.$O\ + vector.$O\ + matrix.$O + +HFILES=dat.h fns.h + +</sys/src/cmd/mkone @@ -0,0 +1,16 @@ +#include <u.h> +#include <libc.h> +#include "dat.h" +#include "fns.h" + +double +round(double n) +{ + return floor(n + 0.5); +} + +double +hypot3(double x, double y, double z) +{ + return hypot(x, hypot(y, z)); +} diff --git a/vector.c b/vector.c new file mode 100644 index 0000000..0657845 --- /dev/null +++ b/vector.c @@ -0,0 +1,48 @@ +#include <u.h> +#include <libc.h> +#include "dat.h" +#include "fns.h" + +Vector +Vec(double x, double y, double w) +{ + return (Vector){x, y, w}; +} + +Vector +addvec(Vector v, Vector u) +{ + return (Vector){v.x+u.x, v.y+u.y, v.w+u.w}; +} + +Vector +subvec(Vector v, Vector u) +{ + return (Vector){v.x-u.x, v.y-u.y, v.w-u.w}; +} + +Vector +mulvec(Vector v, double s) +{ + return (Vector){v.x*s, v.y*s, v.w*s}; +} + +double +dotvec(Vector v, Vector u) +{ + return v.x*u.x + v.y*u.y + v.w*u.w; +} + +Vector +normvec(Vector v) +{ + double len; + + len = hypot3(v.x, v.y, v.w); + if(len == 0) + return (Vector){0, 0, 0}; + v.x /= len; + v.y /= len; + v.w /= len; + return v; +} |