shithub: ballistics

Download patch

ref: 44d868b0684ef88d830f2e99624b826fc4c3507e
parent: d6be49085c76bbea87b7d7c61455b93883669bf1
author: rodri <rgl@antares-labs.eu>
date: Tue Jan 16 18:02:46 EST 2024

add air drag.

--- a/dat.h
+++ b/dat.h
@@ -1,4 +1,6 @@
-#define Eg	9.81
+#define Eg	9.81	/* earth's gravity (m·s⁻²) */
+#define Cd	0.45	/* drag coefficient for a sphere */
+#define ρ	1.293	/* air density (kg·m⁻³) */
 #define PIX2M	0.001
 #define M2PIX	(1.0/PIX2M)
 
@@ -6,6 +8,7 @@
 	Stheta = 0,
 	Spos,
 	Svel,
+	Sdrag,
 	Sdeltax,
 	Seta,
 	SLEN,
@@ -17,4 +20,5 @@
 {
 	Point2 p, v;
 	double mass;
+	double r;
 };
--- a/main.c
+++ b/main.c
@@ -15,6 +15,7 @@
 Projectile ball;
 double t0, Δt;
 double v0;
+double A;	/* area of the projectile that meets the air */
 Point2 target;
 
 char stats[SLEN][64];
@@ -47,11 +48,27 @@
 }
 
 void
+∫(double Δt)
+{
+	Point2 Fd;	/* drag force */
+
+	Fd = mulpt2(mulpt2(ball.v, -vec2len(ball.v)), 0.5 * Cd*ρ*A);	/* ½CdρAv² */
+	ball.v = addpt2(ball.v, mulpt2(addpt2(Vec2(0,-Eg), divpt2(Fd, ball.mass)), Δt));
+	ball.p = addpt2(ball.p, mulpt2(ball.v, Δt));
+	snprint(stats[Spos], sizeof(stats[Spos]), "p: %v", ball.p);
+	snprint(stats[Sdrag], sizeof(stats[Sdrag]), "Fd: %v", Fd);
+	if(ball.p.y <= (2+1)*M2PIX){
+		ball.p.y = (2+1)*M2PIX;
+		ball.v = Vec2(0,0);
+	}
+}
+
+void
 drawstats(void)
 {
 	int i;
 
-	snprint(stats[Svel], sizeof(stats[Svel]), "v: %gm/s", vec2len(ball.v));
+	snprint(stats[Svel], sizeof(stats[Svel]), "|v|: %gm/s", vec2len(ball.v));
 	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]));
@@ -86,7 +103,8 @@
 	switch(menuhit(2, mc, &menu, nil)){
 	case SETV0:
 		enter("v0(m/s):", buf, sizeof(buf), mc, kc, nil);
-		v0 = strtod(buf, 0);
+		if(buf[0] != 0)
+			v0 = strtod(buf, nil);
 		break;
 	}
 }
@@ -124,7 +142,7 @@
 	if(ball.p.y <= (2+1)*M2PIX){
 		p = subpt2(fromscreen(mc->xy), ball.p);
 		θ = atan2(p.y, p.x);
-		snprint(stats[Stheta], sizeof(stats[Stheta]), "θ: %g°", θ*180/PI);
+		snprint(stats[Stheta], sizeof(stats[Stheta]), "θ: %g°", θ/DEG);
 		dist = v0*v0*sin(2*θ)/Eg;
 		target = Pt2(ball.p.x+dist, 0, 1);
 		eta = 2*v0*sin(θ)/Eg;
@@ -204,6 +222,8 @@
 	ball.p = Pt2((2+1)*M2PIX,(2+1)*M2PIX,1);
 	ball.v = Vec2(0, 0);
 	ball.mass = 106000;
+	ball.r = 0.1;		/* 10cm */
+	A = 2*PI*ball.r*ball.r;	/* ½(4πr²) */
 	v0 = 1640; /* Paris Gun's specs */
 
 	scrsync = chancreate(1, 0);
@@ -227,14 +247,8 @@
 		case 2: key(r); break;
 		case 3: redraw(); break;
 		}
-		Δt = (nsec()-t0)/1e9;
-		ball.v = addpt2(ball.v, mulpt2(Vec2(0,-Eg), Δt));
-		ball.p = addpt2(ball.p, mulpt2(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 = Vec2(0,0);
-		}
-		t0 += Δt*1e9;
+		Δt = (nsec()-t0);
+		∫(Δt/1e9);
+		t0 += Δt;
 	}
 }