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