naev 0.11.5
physics.c
1/*
2 * See Licensing and Copyright notice in naev.h
3 */
5#include <stdio.h>
6#include <stdlib.h>
7
8#include "naev.h"
11#include "log.h"
12#include "nstring.h"
13#include "physics.h"
14
19const char _UNIT_TIME[] = N_("sec");
20const char _UNIT_PER_TIME[] = N_("/sec");
21const char _UNIT_DISTANCE[] = N_("km");
22const char _UNIT_SPEED[] = N_("km/s");
23const char _UNIT_ACCEL[] = N_("km/s²");
24const char _UNIT_ENERGY[] = N_("GJ");
25const char _UNIT_POWER[] = N_("GW");
26const char _UNIT_ANGLE[] = N_("°");
27const char _UNIT_ROTATION[] = N_("°/s");
28const char _UNIT_MASS[] = N_("t");
29const char _UNIT_CPU[] = N_("PFLOP");
30const char _UNIT_UNIT[] = N_("u");
31const char _UNIT_PERCENT[] = N_("%");
32
36static double angle_cleanup( double a )
37{
38 if (FABS(a) >= 2.*M_PI) {
39 a = fmod(a, 2.*M_PI);
40 }
41 if (a < 0.) {
42 a += 2.*M_PI;
43 }
44 return a;
45}
52double angle_diff( double ref, double a )
53{
54 /* Get angles. */
55 double a1 = angle_cleanup(ref);
56 double a2 = angle_cleanup(a);
57 double d = a2 - a1;
58
59 /* Filter offsets. */
60 d = (d < M_PI) ? d : d - 2.*M_PI;
61 d = (d > -M_PI) ? d : d + 2.*M_PI;
62 return d;
63}
64
79static void solid_update_euler( Solid *obj, double dt )
80{
81 double px,py, vx,vy, ax,ay, th;
82 double cdir, sdir;
83
84 /* Save previous position. */
85 obj->pre = obj->pos;
86
87 /* Make sure angle doesn't flip */
88 obj->dir += obj->dir_vel*dt;
89 if (obj->dir >= 2*M_PI)
90 obj->dir -= 2*M_PI;
91 if (obj->dir < 0.)
92 obj->dir += 2*M_PI;
93
94 /* Initial positions. */
95 px = obj->pos.x;
96 py = obj->pos.y;
97 vx = obj->vel.x;
98 vy = obj->vel.y;
99 th = obj->accel;
100
101 /* Save direction. */
102 sdir = sin(obj->dir);
103 cdir = cos(obj->dir);
104
105 /* Get acceleration. */
106 ax = th*cdir;
107 ay = th*sdir;
108
109 /* Symplectic Euler should reduce a bit the approximation error. */
110 vx += ax*dt;
111 vy += ay*dt;
112 px += vx*dt;
113 py += vy*dt;
114
115 /* Update position and velocity. */
116 vec2_cset( &obj->vel, vx, vy );
117 vec2_cset( &obj->pos, px, py );
118}
119
143#define RK4_MIN_H 0.01
144static void solid_update_rk4( Solid *obj, double dt )
145{
146 int N; /* for iteration, and pass calculation */
147 double h, px,py, vx,vy; /* pass, and position/velocity values */
148 double vmod, vang, th;
149 int vint;
150 int limit; /* limit speed? */
151
152 /* Save previous position. */
153 obj->pre = obj->pos;
154
155 /* Initial positions and velocity. */
156 px = obj->pos.x;
157 py = obj->pos.y;
158 vx = obj->vel.x;
159 vy = obj->vel.y;
160 limit = (obj->speed_max >= 0.);
161
162 /* Initial RK parameters. */
163 if (dt > RK4_MIN_H)
164 N = (int)(dt / RK4_MIN_H);
165 else
166 N = 1;
167 vmod = MOD( vx, vy );
168 vint = (int) vmod/100.;
169 if (N < vint)
170 N = vint;
171 h = dt / (double)N; /* step */
172
173 /* Movement Quantity Theorem: m*a = \sum f */
174 th = obj->accel;
175
176 for (int i=0; i < N; i++) { /* iterations */
177 double ix, iy, tx, ty;
178 /* Calculate acceleration for the frame. */
179 double ax = th*cos(obj->dir);
180 double ay = th*sin(obj->dir);
181
182 /* Limit the speed. */
183 if (limit) {
184 vmod = MOD( vx, vy );
185 if (vmod > obj->speed_max) {
186 /* We limit by applying a force against it. */
187 vang = ANGLE( vx, vy ) + M_PI;
188 vmod = 3. * (vmod - obj->speed_max);
189
190 /* Update accel. */
191 ax += vmod * cos(vang);
192 ay += vmod * sin(vang);
193 }
194 }
195
196 /* x component */
197 tx = ix = ax;
198 tx += 2.*ix + h*tx;
199 tx += 2.*ix + h*tx;
200 tx += ix + h*tx;
201 tx *= h/6.;
202
203 vx += tx;
204 px += vx * h;
205
206 /* y component */
207 ty = iy = ay;
208 ty += 2.*iy + h*ty;
209 ty += 2.*iy + h*ty;
210 ty += iy + h*ty;
211 ty *= h/6.;
212
213 vy += ty;
214 py += vy * h;
215
216 /* rotation. */
217 obj->dir += obj->dir_vel*h;
218 }
219 vec2_cset( &obj->vel, vx, vy );
220 vec2_cset( &obj->pos, px, py );
221
222 /* Validity check. */
223 if (obj->dir >= 2.*M_PI)
224 obj->dir -= 2.*M_PI;
225 else if (obj->dir < 0.)
226 obj->dir += 2.*M_PI;
227}
228
232double solid_maxspeed( const Solid *s, double speed, double accel )
233{
234 (void) s;
235 return speed + accel / 3.;
236}
237
247void solid_init( Solid* dest, double mass, double dir,
248 const vec2* pos, const vec2* vel, int update )
249{
250 memset(dest, 0, sizeof(Solid));
251
252 dest->mass = mass;
253
254 /* Set direction velocity. */
255 dest->dir_vel = 0.;
256
257 /* Set acceleration. */
258 dest->accel = 0.;
259
260 /* Set direction. */
261 dest->dir = dir;
262 if ((dest->dir > 2.*M_PI) || (dest->dir < 0.))
263 dest->dir = fmod(dest->dir, 2.*M_PI);
264
265 /* Set velocity. */
266 if (vel == NULL)
267 vectnull( &dest->vel );
268 else
269 dest->vel = *vel;
270
271 /* Set position. */
272 if (pos == NULL)
273 vectnull( &dest->pos );
274 else
275 dest->pos = *pos;
276 dest->pre = dest->pos; /* Store previous position. */
277
278 /* Misc. */
279 dest->speed_max = -1.; /* Negative is invalid. */
280
281 /* Handle update. */
282 switch (update) {
283 case SOLID_UPDATE_RK4:
284 dest->update = solid_update_rk4;
285 break;
286
287 case SOLID_UPDATE_EULER:
288 dest->update = solid_update_euler;
289 break;
290
291 default:
292 WARN(_("Solid initialization did not specify correct update function!"));
293 dest->update = solid_update_rk4;
294 break;
295 }
296}
Header file with generic functions and naev-specifics.
#define FABS(x)
Definition naev.h:37
static const double d[]
Definition rng.c:273
Represents a solid in the game.
Definition physics.h:44
double dir_vel
Definition physics.h:47
double speed_max
Definition physics.h:52
void(* update)(struct Solid_ *, double)
Definition physics.h:53
vec2 vel
Definition physics.h:48
vec2 pre
Definition physics.h:50
double dir
Definition physics.h:46
double mass
Definition physics.h:45
vec2 pos
Definition physics.h:49
double accel
Definition physics.h:51
Represents a 2d vector.
Definition vec2.h:32
double y
Definition vec2.h:34
double x
Definition vec2.h:33