shithub: ballistics

Download patch

ref: 168a16b70a928ed64061bdac7fc9d52235c3f9fc
author: rodri <[email protected]>
date: Thu Feb 20 17:02:08 EST 2020

git release.

--- /dev/null
+++ b/dat.h
@@ -1,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;
+};
--- /dev/null
+++ b/fns.h
@@ -1,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);
--- /dev/null
+++ b/main.c
@@ -1,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;
+	}
+}
--- /dev/null
+++ b/matrix.c
@@ -1,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;
+}
--- /dev/null
+++ b/mkfile
@@ -1,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
--- /dev/null
+++ b/util.c
@@ -1,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));
+}
--- /dev/null
+++ b/vector.c
@@ -1,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;
+}