Box2D 3.2.0
A 2D physics engine for games
Loading...
Searching...
No Matches
math_functions.h
1// SPDX-FileCopyrightText: 2023 Erin Catto
2// SPDX-License-Identifier: MIT
3
4#pragma once
5
6#include "base.h"
7#include "math_types.h"
8
9#include <float.h>
10#include <math.h>
11#include <stdbool.h>
12
17
19B2_API bool b2IsValidFloat( float a );
20
22B2_API bool b2IsValidVec2( b2Vec2 v );
23
25B2_API bool b2IsValidRot( b2Rot q );
26
29
32B2_API bool b2IsValidAABB( b2AABB aabb );
33
35B2_API bool b2IsValidPlane( b2Plane a );
36
38B2_API bool b2IsValidPos( b2Pos p );
39
42
44B2_INLINE int b2MinInt( int a, int b )
45{
46 return a < b ? a : b;
47}
48
50B2_INLINE int b2MaxInt( int a, int b )
51{
52 return a > b ? a : b;
53}
54
56B2_INLINE int b2AbsInt( int a )
57{
58 return a < 0 ? -a : a;
59}
60
62B2_INLINE int b2ClampInt( int a, int lower, int upper )
63{
64 return a < lower ? lower : ( a > upper ? upper : a );
65}
66
68B2_INLINE int b2CeilingInt( int numerator, int denominator )
69{
70 B2_VALIDATE( denominator > 0 && numerator >= 0 );
71 return ( numerator + denominator - 1 ) / denominator;
72}
73
75B2_INLINE float b2MinFloat( float a, float b )
76{
77 return a < b ? a : b;
78}
79
81B2_INLINE float b2MaxFloat( float a, float b )
82{
83 return a > b ? a : b;
84}
85
87B2_INLINE float b2AbsFloat( float a )
88{
89 return a < 0 ? -a : a;
90}
91
93B2_INLINE float b2ClampFloat( float a, float lower, float upper )
94{
95 return a < lower ? lower : ( a > upper ? upper : a );
96}
97
101B2_API float b2Atan2( float y, float x );
102
104B2_API b2CosSin b2ComputeCosSin( float radians );
105
107B2_INLINE float b2Dot( b2Vec2 a, b2Vec2 b )
108{
109 return a.x * b.x + a.y * b.y;
110}
111
113B2_INLINE float b2Cross( b2Vec2 a, b2Vec2 b )
114{
115 return a.x * b.y - a.y * b.x;
116}
117
119B2_INLINE b2Vec2 b2CrossVS( b2Vec2 v, float s )
120{
121 return B2_LITERAL( b2Vec2 ){ s * v.y, -s * v.x };
122}
123
125B2_INLINE b2Vec2 b2CrossSV( float s, b2Vec2 v )
126{
127 return B2_LITERAL( b2Vec2 ){ -s * v.y, s * v.x };
128}
129
131B2_INLINE b2Vec2 b2LeftPerp( b2Vec2 v )
132{
133 return B2_LITERAL( b2Vec2 ){ -v.y, v.x };
134}
135
137B2_INLINE b2Vec2 b2RightPerp( b2Vec2 v )
138{
139 return B2_LITERAL( b2Vec2 ){ v.y, -v.x };
140}
141
143B2_INLINE b2Vec2 b2Add( b2Vec2 a, b2Vec2 b )
144{
145 return B2_LITERAL( b2Vec2 ){ a.x + b.x, a.y + b.y };
146}
147
149B2_INLINE b2Vec2 b2Sub( b2Vec2 a, b2Vec2 b )
150{
151 return B2_LITERAL( b2Vec2 ){ a.x - b.x, a.y - b.y };
152}
153
155B2_INLINE b2Vec2 b2Neg( b2Vec2 a )
156{
157 return B2_LITERAL( b2Vec2 ){ -a.x, -a.y };
158}
159
162B2_INLINE b2Vec2 b2Lerp( b2Vec2 a, b2Vec2 b, float t )
163{
164 return B2_LITERAL( b2Vec2 ){ ( 1.0f - t ) * a.x + t * b.x, ( 1.0f - t ) * a.y + t * b.y };
165}
166
168B2_INLINE b2Vec2 b2Mul( b2Vec2 a, b2Vec2 b )
169{
170 return B2_LITERAL( b2Vec2 ){ a.x * b.x, a.y * b.y };
171}
172
174B2_INLINE b2Vec2 b2MulSV( float s, b2Vec2 v )
175{
176 return B2_LITERAL( b2Vec2 ){ s * v.x, s * v.y };
177}
178
180B2_INLINE b2Vec2 b2MulAdd( b2Vec2 a, float s, b2Vec2 b )
181{
182 return B2_LITERAL( b2Vec2 ){ a.x + s * b.x, a.y + s * b.y };
183}
184
186B2_INLINE b2Vec2 b2MulSub( b2Vec2 a, float s, b2Vec2 b )
187{
188 return B2_LITERAL( b2Vec2 ){ a.x - s * b.x, a.y - s * b.y };
189}
190
192B2_INLINE b2Vec2 b2Abs( b2Vec2 a )
193{
194 b2Vec2 b;
195 b.x = b2AbsFloat( a.x );
196 b.y = b2AbsFloat( a.y );
197 return b;
198}
199
201B2_INLINE b2Vec2 b2Min( b2Vec2 a, b2Vec2 b )
202{
203 b2Vec2 c;
204 c.x = b2MinFloat( a.x, b.x );
205 c.y = b2MinFloat( a.y, b.y );
206 return c;
207}
208
210B2_INLINE b2Vec2 b2Max( b2Vec2 a, b2Vec2 b )
211{
212 b2Vec2 c;
213 c.x = b2MaxFloat( a.x, b.x );
214 c.y = b2MaxFloat( a.y, b.y );
215 return c;
216}
217
219B2_INLINE b2Vec2 b2Clamp( b2Vec2 v, b2Vec2 a, b2Vec2 b )
220{
221 b2Vec2 c;
222 c.x = b2ClampFloat( v.x, a.x, b.x );
223 c.y = b2ClampFloat( v.y, a.y, b.y );
224 return c;
225}
226
228B2_INLINE float b2Length( b2Vec2 v )
229{
230 return sqrtf( v.x * v.x + v.y * v.y );
231}
232
234B2_INLINE float b2Distance( b2Vec2 a, b2Vec2 b )
235{
236 float dx = b.x - a.x;
237 float dy = b.y - a.y;
238 return sqrtf( dx * dx + dy * dy );
239}
240
242B2_FORCE_INLINE b2Vec2 b2Normalize( b2Vec2 a )
243{
244 float lengthSquared = a.x * a.x + a.y * a.y;
245 if ( lengthSquared > 1000.0f * FLT_MIN )
246 {
247 float s = 1.0f / sqrtf( lengthSquared );
248 b2Vec2 u = { s * a.x, s * a.y };
249 return u;
250 }
251 return B2_LITERAL( b2Vec2 ){ 0.0f, 0.0f };
252}
253
255B2_INLINE bool b2IsNormalized( b2Vec2 a )
256{
257 float aa = b2Dot( a, a );
258 return b2AbsFloat( 1.0f - aa ) < 100.0f * FLT_EPSILON;
259}
260
263B2_INLINE b2Vec2 b2GetLengthAndNormalize( float* length, b2Vec2 a )
264{
265 float lengthSquared = a.x * a.x + a.y * a.y;
266 if ( lengthSquared > 1000.0f * FLT_MIN )
267 {
268 *length = sqrtf( lengthSquared );
269 float s = 1.0f / *length;
270 b2Vec2 u = { s * a.x, s * a.y };
271 return u;
272 }
273
274 *length = 0.0f;
275 return B2_LITERAL( b2Vec2 ){ 0.0f, 0.0f };
276}
277
279B2_INLINE b2Rot b2NormalizeRot( b2Rot q )
280{
281 float mag = sqrtf( q.s * q.s + q.c * q.c );
282 float invMag = mag > 0.0f ? 1.0f / mag : 0.0f;
283 b2Rot qn = { q.c * invMag, q.s * invMag };
284 return qn;
285}
286
290B2_INLINE b2Rot b2IntegrateRotation( b2Rot q1, float deltaAngle )
291{
292 // dc/dt = -omega * sin(t)
293 // ds/dt = omega * cos(t)
294 // c2 = c1 - omega * h * s1
295 // s2 = s1 + omega * h * c1
296 b2Rot q2 = { q1.c - deltaAngle * q1.s, q1.s + deltaAngle * q1.c };
297 float mag = sqrtf( q2.s * q2.s + q2.c * q2.c );
298 float invMag = mag > 0.0f ? 1.0f / mag : 0.0f;
299 b2Rot qn = { q2.c * invMag, q2.s * invMag };
300 return qn;
301}
302
304B2_INLINE float b2LengthSquared( b2Vec2 v )
305{
306 return v.x * v.x + v.y * v.y;
307}
308
310B2_INLINE float b2DistanceSquared( b2Vec2 a, b2Vec2 b )
311{
312 b2Vec2 c = { b.x - a.x, b.y - a.y };
313 return c.x * c.x + c.y * c.y;
314}
315
317B2_INLINE b2Rot b2MakeRot( float radians )
318{
319 b2CosSin cs = b2ComputeCosSin( radians );
320 return B2_LITERAL( b2Rot ){ cs.cosine, cs.sine };
321}
322
324B2_INLINE b2Rot b2MakeRotFromUnitVector( b2Vec2 unitVector )
325{
326 B2_ASSERT( b2IsNormalized( unitVector ) );
327 return B2_LITERAL( b2Rot ){ unitVector.x, unitVector.y };
328}
329
332
334B2_INLINE bool b2IsNormalizedRot( b2Rot q )
335{
336 // larger tolerance due to failure on mingw 32-bit
337 float qq = q.s * q.s + q.c * q.c;
338 return 1.0f - 0.0006f < qq && qq < 1.0f + 0.0006f;
339}
340
342B2_INLINE b2Rot b2InvertRot( b2Rot a )
343{
344 return B2_LITERAL( b2Rot ){ a.c, -a.s };
345}
346
350B2_INLINE b2Rot b2NLerp( b2Rot q1, b2Rot q2, float t )
351{
352 float omt = 1.0f - t;
353 b2Rot q = {
354 omt * q1.c + t * q2.c,
355 omt * q1.s + t * q2.s,
356 };
357
358 float mag = sqrtf( q.s * q.s + q.c * q.c );
359 float invMag = mag > 0.0f ? 1.0f / mag : 0.0f;
360 b2Rot qn = { q.c * invMag, q.s * invMag };
361 return qn;
362}
363
368B2_INLINE float b2ComputeAngularVelocity( b2Rot q1, b2Rot q2, float inv_h )
369{
370 // ds/dt = omega * cos(t)
371 // dc/dt = -omega * sin(t)
372 // s2 = s1 + omega * h * c1
373 // c2 = c1 - omega * h * s1
374
375 // omega * h * s1 = c1 - c2
376 // omega * h * c1 = s2 - s1
377 // omega * h = (c1 - c2) * s1 + (s2 - s1) * c1;
378 // omega * h = s1 * c1 - c2 * s1 + s2 * c1 - s1 * c1
379 // omega * h = s2 * c1 - c2 * s1 = sin(a2 - a1) ~= a2 - a1 for small delta
380 float omega = inv_h * ( q2.s * q1.c - q2.c * q1.s );
381 return omega;
382}
383
385B2_INLINE float b2Rot_GetAngle( b2Rot q )
386{
387 return b2Atan2( q.s, q.c );
388}
389
391B2_INLINE b2Vec2 b2Rot_GetXAxis( b2Rot q )
392{
393 b2Vec2 v = { q.c, q.s };
394 return v;
395}
396
398B2_INLINE b2Vec2 b2Rot_GetYAxis( b2Rot q )
399{
400 b2Vec2 v = { -q.s, q.c };
401 return v;
402}
403
405B2_INLINE b2Rot b2MulRot( b2Rot q, b2Rot r )
406{
407 // [qc -qs] * [rc -rs] = [qc*rc-qs*rs -qc*rs-qs*rc]
408 // [qs qc] [rs rc] [qs*rc+qc*rs -qs*rs+qc*rc]
409 // s(q + r) = qs * rc + qc * rs
410 // c(q + r) = qc * rc - qs * rs
411 b2Rot qr;
412 qr.s = q.s * r.c + q.c * r.s;
413 qr.c = q.c * r.c - q.s * r.s;
414 return qr;
415}
416
419B2_INLINE b2Rot b2InvMulRot( b2Rot a, b2Rot b )
420{
421 // [ ac as] * [bc -bs] = [ac*bc+as*bs -ac*bs+as*bc]
422 // [-as ac] [bs bc] [-as*bc+ac*bs as*bs+ac*bc]
423 // s(b - a) = ac * bs - as * bc
424 // c(b - a) = ac * bc + as * bs
425 b2Rot r;
426 r.s = a.c * b.s - a.s * b.c;
427 r.c = a.c * b.c + a.s * b.s;
428 return r;
429}
430
432B2_INLINE float b2RelativeAngle( b2Rot a, b2Rot b )
433{
434 // sin(b - a) = bs * ac - bc * as
435 // cos(b - a) = bc * ac + bs * as
436 float s = a.c * b.s - a.s * b.c;
437 float c = a.c * b.c + a.s * b.s;
438 return b2Atan2( s, c );
439}
440
442B2_INLINE float b2UnwindAngle( float radians )
443{
444 // This function can be implemented using remainderf.
445 // However that is a libc dependency not present in WASM.
446 // This function doesn't work well with huge angles. So unwind your angles regularly.
447 B2_VALIDATE( b2AbsFloat( radians ) < 1.0e4f );
448 float x = b2ClampFloat( radians, -1.0e6f, 1.0e6f );
449
450 // Work in doubles. Adding and removing this constant rounds to the nearest integer.
451 // https://stackoverflow.com/questions/17035464/a-fast-method-to-round-a-double-to-a-32-bit-int-explained
452 double twoPi = 2.0f * B2_PI;
453 double roundToNearest = 6755399441055744.0;
454 double a = x;
455 double k = ( a / twoPi + roundToNearest ) - roundToNearest;
456 return (float)( a - k * twoPi );
457}
458
460B2_INLINE b2Vec2 b2RotateVector( b2Rot q, b2Vec2 v )
461{
462 return B2_LITERAL( b2Vec2 ){ q.c * v.x - q.s * v.y, q.s * v.x + q.c * v.y };
463}
464
466B2_INLINE b2Vec2 b2InvRotateVector( b2Rot q, b2Vec2 v )
467{
468 return B2_LITERAL( b2Vec2 ){ q.c * v.x + q.s * v.y, -q.s * v.x + q.c * v.y };
469}
470
472B2_INLINE b2Vec2 b2TransformPoint( b2Transform t, const b2Vec2 p )
473{
474 float x = ( t.q.c * p.x - t.q.s * p.y ) + t.p.x;
475 float y = ( t.q.s * p.x + t.q.c * p.y ) + t.p.y;
476
477 return B2_LITERAL( b2Vec2 ){ x, y };
478}
479
481B2_INLINE b2Vec2 b2InvTransformPoint( b2Transform t, const b2Vec2 p )
482{
483 float vx = p.x - t.p.x;
484 float vy = p.y - t.p.y;
485 return B2_LITERAL( b2Vec2 ){ t.q.c * vx + t.q.s * vy, -t.q.s * vx + t.q.c * vy };
486}
487
492B2_INLINE b2Transform b2MulTransforms( b2Transform A, b2Transform B )
493{
494 b2Transform C;
495 C.q = b2MulRot( A.q, B.q );
496 C.p = b2Add( b2RotateVector( A.q, B.p ), A.p );
497 return C;
498}
499
503B2_INLINE b2Transform b2InvMulTransforms( b2Transform A, b2Transform B )
504{
505 b2Transform C;
506 C.q = b2InvMulRot( A.q, B.q );
507 C.p = b2InvRotateVector( A.q, b2Sub( B.p, A.p ) );
508 return C;
509}
510
512B2_INLINE b2Pos b2ToPos( b2Vec2 v )
513{
514 return B2_LITERAL( b2Pos ){ v.x, v.y };
515}
516
518B2_INLINE b2Vec2 b2ToVec2( b2Pos p )
519{
520 return B2_LITERAL( b2Vec2 ){ (float)p.x, (float)p.y };
521}
522
527B2_INLINE float b2RoundDownFloat( double x )
528{
529#if defined( BOX2D_DOUBLE_PRECISION )
530 float f = (float)x;
531 return (double)f > x ? nextafterf( f, -FLT_MAX ) : f;
532#else
533 return (float)x;
534#endif
535}
536
538B2_INLINE float b2RoundUpFloat( double x )
539{
540#if defined( BOX2D_DOUBLE_PRECISION )
541 float f = (float)x;
542 return (double)f < x ? nextafterf( f, FLT_MAX ) : f;
543#else
544 return (float)x;
545#endif
546}
547
549B2_INLINE b2Vec2 b2SubPos( b2Pos a, b2Pos b )
550{
551 return B2_LITERAL( b2Vec2 ){ (float)( a.x - b.x ), (float)( a.y - b.y ) };
552}
553
555B2_INLINE b2Pos b2OffsetPos( b2Pos p, b2Vec2 d )
556{
557 return B2_LITERAL( b2Pos ){ p.x + d.x, p.y + d.y };
558}
559
561B2_INLINE b2Pos b2LerpPos( b2Pos a, b2Pos b, float t )
562{
563 return B2_LITERAL( b2Pos ){ ( 1.0f - t ) * a.x + t * b.x, ( 1.0f - t ) * a.y + t * b.y };
564}
565
567B2_INLINE b2Pos b2TransformWorldPoint( b2WorldTransform t, b2Vec2 p )
568{
569 float rx = t.q.c * p.x - t.q.s * p.y;
570 float ry = t.q.s * p.x + t.q.c * p.y;
571 return B2_LITERAL( b2Pos ){ t.p.x + rx, t.p.y + ry };
572}
573
575B2_INLINE b2Vec2 b2InvTransformWorldPoint( b2WorldTransform t, b2Pos p )
576{
577 float vx = (float)( p.x - t.p.x );
578 float vy = (float)( p.y - t.p.y );
579 return B2_LITERAL( b2Vec2 ){ t.q.c * vx + t.q.s * vy, -t.q.s * vx + t.q.c * vy };
580}
581
583B2_INLINE b2Transform b2InvMulWorldTransforms( b2WorldTransform A, b2WorldTransform B )
584{
585 b2Transform C;
586 C.q = b2InvMulRot( A.q, B.q );
587 b2Vec2 d = { (float)( B.p.x - A.p.x ), (float)( B.p.y - A.p.y ) };
588 C.p = b2InvRotateVector( A.q, d );
589 return C;
590}
591
593B2_INLINE b2WorldTransform b2MulWorldTransforms( b2WorldTransform A, b2Transform B )
594{
596 C.q = b2MulRot( A.q, B.q );
597 C.p = b2OffsetPos( A.p, b2RotateVector( A.q, B.p ) );
598 return C;
599}
600
602B2_INLINE b2Transform b2ToRelativeTransform( b2WorldTransform t, b2Pos base )
603{
604 b2Transform r;
605 r.q = t.q;
606 r.p = B2_LITERAL( b2Vec2 ){ (float)( t.p.x - base.x ), (float)( t.p.y - base.y ) };
607 return r;
608}
609
611B2_INLINE b2WorldTransform b2MakeWorldTransform( b2Transform t )
612{
614 w.p = b2ToPos( t.p );
615 w.q = t.q;
616 return w;
617}
618
620B2_INLINE b2Vec2 b2MulMV( b2Mat22 A, b2Vec2 v )
621{
622 b2Vec2 u = {
623 A.cx.x * v.x + A.cy.x * v.y,
624 A.cx.y * v.x + A.cy.y * v.y,
625 };
626 return u;
627}
628
630B2_INLINE b2Mat22 b2GetInverse22( b2Mat22 A )
631{
632 float a = A.cx.x, b = A.cy.x, c = A.cx.y, d = A.cy.y;
633 float det = a * d - b * c;
634 if ( det != 0.0f )
635 {
636 det = 1.0f / det;
637 }
638
639 b2Mat22 B = {
640 { det * d, -det * c },
641 { -det * b, det * a },
642 };
643 return B;
644}
645
648B2_INLINE b2Vec2 b2Solve22( b2Mat22 A, b2Vec2 b )
649{
650 float a11 = A.cx.x, a12 = A.cy.x, a21 = A.cx.y, a22 = A.cy.y;
651 float det = a11 * a22 - a12 * a21;
652 if ( det != 0.0f )
653 {
654 det = 1.0f / det;
655 }
656 b2Vec2 x = { det * ( a22 * b.x - a12 * b.y ), det * ( a11 * b.y - a21 * b.x ) };
657 return x;
658}
659
661B2_INLINE bool b2AABB_Contains( b2AABB a, b2AABB b )
662{
663 bool s = true;
664 s = s && a.lowerBound.x <= b.lowerBound.x;
665 s = s && a.lowerBound.y <= b.lowerBound.y;
666 s = s && b.upperBound.x <= a.upperBound.x;
667 s = s && b.upperBound.y <= a.upperBound.y;
668 return s;
669}
670
672B2_INLINE b2Vec2 b2AABB_Center( b2AABB a )
673{
674 b2Vec2 b = { 0.5f * ( a.lowerBound.x + a.upperBound.x ),
675 0.5f * ( a.lowerBound.y + a.upperBound.y ) };
676 return b;
677}
678
680B2_INLINE b2Vec2 b2AABB_Extents( b2AABB a )
681{
682 b2Vec2 b = { 0.5f * ( a.upperBound.x - a.lowerBound.x ),
683 0.5f * ( a.upperBound.y - a.lowerBound.y ) };
684 return b;
685}
686
688B2_INLINE b2AABB b2AABB_Union( b2AABB a, b2AABB b )
689{
690 b2AABB c;
691 c.lowerBound.x = b2MinFloat( a.lowerBound.x, b.lowerBound.x );
692 c.lowerBound.y = b2MinFloat( a.lowerBound.y, b.lowerBound.y );
693 c.upperBound.x = b2MaxFloat( a.upperBound.x, b.upperBound.x );
694 c.upperBound.y = b2MaxFloat( a.upperBound.y, b.upperBound.y );
695 return c;
696}
697
699B2_INLINE bool b2AABB_Overlaps( b2AABB a, b2AABB b )
700{
701 return !( b.lowerBound.x > a.upperBound.x || b.lowerBound.y > a.upperBound.y ||
702 a.lowerBound.x > b.upperBound.x || a.lowerBound.y > b.upperBound.y );
703}
704
706B2_INLINE b2AABB b2MakeAABB( const b2Vec2* points, int count, float radius )
707{
708 B2_ASSERT( count > 0 );
709 b2AABB a = { points[0], points[0] };
710 for ( int i = 1; i < count; ++i )
711 {
712 a.lowerBound = b2Min( a.lowerBound, points[i] );
713 a.upperBound = b2Max( a.upperBound, points[i] );
714 }
715
716 b2Vec2 r = { radius, radius };
717 a.lowerBound = b2Sub( a.lowerBound, r );
718 a.upperBound = b2Add( a.upperBound, r );
719
720 return a;
721}
722
724B2_INLINE float b2PlaneSeparation( b2Plane plane, b2Vec2 point )
725{
726 return b2Dot( plane.normal, point ) - plane.offset;
727}
728
734B2_INLINE float b2SpringDamper( float hertz, float dampingRatio, float position, float velocity,
735 float timeStep )
736{
737 float omega = 2.0f * B2_PI * hertz;
738 float omegaH = omega * timeStep;
739 return ( velocity - omega * omegaH * position ) /
740 ( 1.0f + 2.0f * dampingRatio * omegaH + omegaH * omegaH );
741}
742
755B2_API void b2SetLengthUnitsPerMeter( float lengthUnits );
756
758B2_API float b2GetLengthUnitsPerMeter( void );
759
760#ifdef __cplusplus
762extern "C" BOX2D_EXPORT float b2_lengthUnitsPerMeter;
763#else
765BOX2D_EXPORT extern float b2_lengthUnitsPerMeter;
766#endif
767
769
770#ifdef __cplusplus
771
773inline void operator+=( b2Vec2& a, b2Vec2 b )
774{
775 a.x += b.x;
776 a.y += b.y;
777}
778
780inline void operator-=( b2Vec2& a, b2Vec2 b )
781{
782 a.x -= b.x;
783 a.y -= b.y;
784}
785
787inline void operator*=( b2Vec2& a, float b )
788{
789 a.x *= b;
790 a.y *= b;
791}
792
794inline b2Vec2 operator-( b2Vec2 a )
795{
796 return { -a.x, -a.y };
797}
798
800inline b2Vec2 operator+( b2Vec2 a, b2Vec2 b )
801{
802 return { a.x + b.x, a.y + b.y };
803}
804
806inline b2Vec2 operator-( b2Vec2 a, b2Vec2 b )
807{
808 return { a.x - b.x, a.y - b.y };
809}
810
812inline b2Vec2 operator*( float a, b2Vec2 b )
813{
814 return { a * b.x, a * b.y };
815}
816
818inline b2Vec2 operator*( b2Vec2 a, float b )
819{
820 return { a.x * b, a.y * b };
821}
822
824inline bool operator==( b2Vec2 a, b2Vec2 b )
825{
826 return a.x == b.x && a.y == b.y;
827}
828
830inline bool operator!=( b2Vec2 a, b2Vec2 b )
831{
832 return a.x != b.x || a.y != b.y;
833}
834
835#if defined( BOX2D_DOUBLE_PRECISION )
836
838inline b2Pos operator+( b2Pos a, b2Vec2 b )
839{
840 return { a.x + b.x, a.y + b.y };
841}
842
844inline b2Pos operator-( b2Pos a, b2Vec2 b )
845{
846 return { a.x - b.x, a.y - b.y };
847}
848
850inline b2Vec2 operator-( b2Pos a, b2Pos b )
851{
852 return { (float)( a.x - b.x ), (float)( a.y - b.y ) };
853}
854
855#endif
856
857#endif
858
float c
cosine and sine
Definition math_types.h:31
float x
coordinates
Definition math_types.h:16
b2Vec2 cx
columns
Definition math_types.h:72
float cosine
cosine and sine
Definition math_types.h:23
BOX2D_EXPORT float b2_lengthUnitsPerMeter
This value is exported for efficiency. Don't modify directly.
float b2GetLengthUnitsPerMeter(void)
Get the current length units per meter.
bool b2IsValidPlane(b2Plane a)
Is this a valid plane? Normal is a unit vector. Not NaN or infinity.
bool b2IsValidPos(b2Pos p)
Is this a valid world position? Not NaN or infinity.
float b2Atan2(float y, float x)
Compute an approximate arctangent in the range [-pi, pi] This is hand coded for cross-platform determ...
void b2SetLengthUnitsPerMeter(float lengthUnits)
Box2D bases all length units on meters, but you may need different units for your game.
bool b2IsValidVec2(b2Vec2 v)
Is this a valid vector? Not NaN or infinity.
bool b2IsValidFloat(float a)
Is this a valid number? Not NaN or infinity.
b2Vec2 b2Pos
Alias in single precision.
Definition math_types.h:61
bool b2IsValidRot(b2Rot q)
Is this a valid rotation? Not NaN or infinity. Is normalized.
b2Transform b2WorldTransform
Alias in single precision.
Definition math_types.h:64
b2CosSin b2ComputeCosSin(float radians)
Compute the cosine and sine of an angle in radians. Implemented for cross-platform determinism.
bool b2IsValidWorldTransform(b2WorldTransform t)
Is this a valid world transform? Not NaN or infinity. Rotation is normalized.
bool b2IsValidAABB(b2AABB aabb)
Is this a valid bounding box?
#define B2_PI
https://en.wikipedia.org/wiki/Pi
Definition math_types.h:90
bool b2IsValidTransform(b2Transform t)
Is this a valid transform? Not NaN or infinity. Rotation is normalized.
b2Rot b2ComputeRotationBetweenUnitVectors(b2Vec2 v1, b2Vec2 v2)
Compute the rotation between two unit vectors.
Axis-aligned bounding box.
Definition math_types.h:77
Cosine and sine pair This uses a custom implementation designed for cross-platform determinism.
Definition math_types.h:21
A 2-by-2 Matrix.
Definition math_types.h:70
separation = dot(normal, point) - offset
Definition math_types.h:84
2D rotation This is similar to using a complex number for rotation
Definition math_types.h:29
A 2D rigid transform.
Definition math_types.h:36
2D vector This can be used to represent a point or free vector
Definition math_types.h:14