odin-blend2d

Odin bindings to Blend2D
Log | Files | Refs | README | LICENSE

math_functions.h (17868B)


      1 // SPDX-FileCopyrightText: 2023 Erin Catto
      2 // SPDX-License-Identifier: MIT
      3 
      4 #pragma once
      5 
      6 #include "base.h"
      7 
      8 #include <float.h>
      9 #include <math.h>
     10 #include <stdbool.h>
     11 
     12 /**
     13  * @defgroup math Math
     14  * @brief Vector math types and functions
     15  * @{
     16  */
     17 
     18 /// 2D vector
     19 /// This can be used to represent a point or free vector
     20 typedef struct b2Vec2
     21 {
     22 	/// coordinates
     23 	float x, y;
     24 } b2Vec2;
     25 
     26 /// Cosine and sine pair
     27 /// This uses a custom implementation designed for cross-platform determinism
     28 typedef struct b2CosSin
     29 {
     30 	/// cosine and sine
     31 	float cosine;
     32 	float sine;
     33 } b2CosSin;
     34 
     35 /// 2D rotation
     36 /// This is similar to using a complex number for rotation
     37 typedef struct b2Rot
     38 {
     39 	/// cosine and sine
     40 	float c, s;
     41 } b2Rot;
     42 
     43 /// A 2D rigid transform
     44 typedef struct b2Transform
     45 {
     46 	b2Vec2 p;
     47 	b2Rot q;
     48 } b2Transform;
     49 
     50 /// A 2-by-2 Matrix
     51 typedef struct b2Mat22
     52 {
     53 	/// columns
     54 	b2Vec2 cx, cy;
     55 } b2Mat22;
     56 
     57 /// Axis-aligned bounding box
     58 typedef struct b2AABB
     59 {
     60 	b2Vec2 lowerBound;
     61 	b2Vec2 upperBound;
     62 } b2AABB;
     63 
     64 /**@}*/
     65 
     66 /**
     67  * @addtogroup math
     68  * @{
     69  */
     70 
     71 /// https://en.wikipedia.org/wiki/Pi
     72 #define B2_PI 3.14159265359f
     73 
     74 static const b2Vec2 b2Vec2_zero = { 0.0f, 0.0f };
     75 static const b2Rot b2Rot_identity = { 1.0f, 0.0f };
     76 static const b2Transform b2Transform_identity = { { 0.0f, 0.0f }, { 1.0f, 0.0f } };
     77 static const b2Mat22 b2Mat22_zero = { { 0.0f, 0.0f }, { 0.0f, 0.0f } };
     78 
     79 /// @return the minimum of two integers
     80 B2_INLINE int b2MinInt( int a, int b )
     81 {
     82 	return a < b ? a : b;
     83 }
     84 
     85 /// @return the maximum of two integers
     86 B2_INLINE int b2MaxInt( int a, int b )
     87 {
     88 	return a > b ? a : b;
     89 }
     90 
     91 /// @return the absolute value of an integer
     92 B2_INLINE int b2AbsInt( int a )
     93 {
     94 	return a < 0 ? -a : a;
     95 }
     96 
     97 /// @return an integer clamped between a lower and upper bound
     98 B2_INLINE int b2ClampInt( int a, int lower, int upper )
     99 {
    100 	return a < lower ? lower : ( a > upper ? upper : a );
    101 }
    102 
    103 /// @return the minimum of two floats
    104 B2_INLINE float b2MinFloat( float a, float b )
    105 {
    106 	return a < b ? a : b;
    107 }
    108 
    109 /// @return the maximum of two floats
    110 B2_INLINE float b2MaxFloat( float a, float b )
    111 {
    112 	return a > b ? a : b;
    113 }
    114 
    115 /// @return the absolute value of a float
    116 B2_INLINE float b2AbsFloat( float a )
    117 {
    118 	return a < 0 ? -a : a;
    119 }
    120 
    121 /// @return a float clamped between a lower and upper bound
    122 B2_INLINE float b2ClampFloat( float a, float lower, float upper )
    123 {
    124 	return a < lower ? lower : ( a > upper ? upper : a );
    125 }
    126 
    127 /// Compute an approximate arctangent in the range [-pi, pi]
    128 /// This is hand coded for cross-platform determinism. The atan2f
    129 /// function in the standard library is not cross-platform deterministic.
    130 ///	Accurate to around 0.0023 degrees
    131 B2_API float b2Atan2( float y, float x );
    132 
    133 /// Compute the cosine and sine of an angle in radians. Implemented
    134 /// for cross-platform determinism.
    135 B2_API b2CosSin b2ComputeCosSin( float radians );
    136 
    137 /// Vector dot product
    138 B2_INLINE float b2Dot( b2Vec2 a, b2Vec2 b )
    139 {
    140 	return a.x * b.x + a.y * b.y;
    141 }
    142 
    143 /// Vector cross product. In 2D this yields a scalar.
    144 B2_INLINE float b2Cross( b2Vec2 a, b2Vec2 b )
    145 {
    146 	return a.x * b.y - a.y * b.x;
    147 }
    148 
    149 /// Perform the cross product on a vector and a scalar. In 2D this produces a vector.
    150 B2_INLINE b2Vec2 b2CrossVS( b2Vec2 v, float s )
    151 {
    152 	return B2_LITERAL( b2Vec2 ){ s * v.y, -s * v.x };
    153 }
    154 
    155 /// Perform the cross product on a scalar and a vector. In 2D this produces a vector.
    156 B2_INLINE b2Vec2 b2CrossSV( float s, b2Vec2 v )
    157 {
    158 	return B2_LITERAL( b2Vec2 ){ -s * v.y, s * v.x };
    159 }
    160 
    161 /// Get a left pointing perpendicular vector. Equivalent to b2CrossSV(1.0f, v)
    162 B2_INLINE b2Vec2 b2LeftPerp( b2Vec2 v )
    163 {
    164 	return B2_LITERAL( b2Vec2 ){ -v.y, v.x };
    165 }
    166 
    167 /// Get a right pointing perpendicular vector. Equivalent to b2CrossVS(v, 1.0f)
    168 B2_INLINE b2Vec2 b2RightPerp( b2Vec2 v )
    169 {
    170 	return B2_LITERAL( b2Vec2 ){ v.y, -v.x };
    171 }
    172 
    173 /// Vector addition
    174 B2_INLINE b2Vec2 b2Add( b2Vec2 a, b2Vec2 b )
    175 {
    176 	return B2_LITERAL( b2Vec2 ){ a.x + b.x, a.y + b.y };
    177 }
    178 
    179 /// Vector subtraction
    180 B2_INLINE b2Vec2 b2Sub( b2Vec2 a, b2Vec2 b )
    181 {
    182 	return B2_LITERAL( b2Vec2 ){ a.x - b.x, a.y - b.y };
    183 }
    184 
    185 /// Vector negation
    186 B2_INLINE b2Vec2 b2Neg( b2Vec2 a )
    187 {
    188 	return B2_LITERAL( b2Vec2 ){ -a.x, -a.y };
    189 }
    190 
    191 /// Vector linear interpolation
    192 /// https://fgiesen.wordpress.com/2012/08/15/linear-interpolation-past-present-and-future/
    193 B2_INLINE b2Vec2 b2Lerp( b2Vec2 a, b2Vec2 b, float t )
    194 {
    195 	return B2_LITERAL( b2Vec2 ){ ( 1.0f - t ) * a.x + t * b.x, ( 1.0f - t ) * a.y + t * b.y };
    196 }
    197 
    198 /// Component-wise multiplication
    199 B2_INLINE b2Vec2 b2Mul( b2Vec2 a, b2Vec2 b )
    200 {
    201 	return B2_LITERAL( b2Vec2 ){ a.x * b.x, a.y * b.y };
    202 }
    203 
    204 /// Multiply a scalar and vector
    205 B2_INLINE b2Vec2 b2MulSV( float s, b2Vec2 v )
    206 {
    207 	return B2_LITERAL( b2Vec2 ){ s * v.x, s * v.y };
    208 }
    209 
    210 /// a + s * b
    211 B2_INLINE b2Vec2 b2MulAdd( b2Vec2 a, float s, b2Vec2 b )
    212 {
    213 	return B2_LITERAL( b2Vec2 ){ a.x + s * b.x, a.y + s * b.y };
    214 }
    215 
    216 /// a - s * b
    217 B2_INLINE b2Vec2 b2MulSub( b2Vec2 a, float s, b2Vec2 b )
    218 {
    219 	return B2_LITERAL( b2Vec2 ){ a.x - s * b.x, a.y - s * b.y };
    220 }
    221 
    222 /// Component-wise absolute vector
    223 B2_INLINE b2Vec2 b2Abs( b2Vec2 a )
    224 {
    225 	b2Vec2 b;
    226 	b.x = b2AbsFloat( a.x );
    227 	b.y = b2AbsFloat( a.y );
    228 	return b;
    229 }
    230 
    231 /// Component-wise minimum vector
    232 B2_INLINE b2Vec2 b2Min( b2Vec2 a, b2Vec2 b )
    233 {
    234 	b2Vec2 c;
    235 	c.x = b2MinFloat( a.x, b.x );
    236 	c.y = b2MinFloat( a.y, b.y );
    237 	return c;
    238 }
    239 
    240 /// Component-wise maximum vector
    241 B2_INLINE b2Vec2 b2Max( b2Vec2 a, b2Vec2 b )
    242 {
    243 	b2Vec2 c;
    244 	c.x = b2MaxFloat( a.x, b.x );
    245 	c.y = b2MaxFloat( a.y, b.y );
    246 	return c;
    247 }
    248 
    249 /// Component-wise clamp vector v into the range [a, b]
    250 B2_INLINE b2Vec2 b2Clamp( b2Vec2 v, b2Vec2 a, b2Vec2 b )
    251 {
    252 	b2Vec2 c;
    253 	c.x = b2ClampFloat( v.x, a.x, b.x );
    254 	c.y = b2ClampFloat( v.y, a.y, b.y );
    255 	return c;
    256 }
    257 
    258 /// Get the length of this vector (the norm)
    259 B2_INLINE float b2Length( b2Vec2 v )
    260 {
    261 	return sqrtf( v.x * v.x + v.y * v.y );
    262 }
    263 
    264 /// Get the distance between two points
    265 B2_INLINE float b2Distance( b2Vec2 a, b2Vec2 b )
    266 {
    267 	float dx = b.x - a.x;
    268 	float dy = b.y - a.y;
    269 	return sqrtf( dx * dx + dy * dy );
    270 }
    271 
    272 /// Convert a vector into a unit vector if possible, otherwise returns the zero vector.
    273 B2_INLINE b2Vec2 b2Normalize( b2Vec2 v )
    274 {
    275 	float length = sqrtf( v.x * v.x + v.y * v.y );
    276 	if ( length < FLT_EPSILON )
    277 	{
    278 		return b2Vec2_zero;
    279 	}
    280 
    281 	float invLength = 1.0f / length;
    282 	b2Vec2 n = { invLength * v.x, invLength * v.y };
    283 	return n;
    284 }
    285 
    286 /// Convert a vector into a unit vector if possible, otherwise returns the zero vector. Also
    287 /// outputs the length.
    288 B2_INLINE b2Vec2 b2GetLengthAndNormalize( float* length, b2Vec2 v )
    289 {
    290 	*length = b2Length( v );
    291 	if ( *length < FLT_EPSILON )
    292 	{
    293 		return b2Vec2_zero;
    294 	}
    295 
    296 	float invLength = 1.0f / *length;
    297 	b2Vec2 n = { invLength * v.x, invLength * v.y };
    298 	return n;
    299 }
    300 
    301 /// Normalize rotation
    302 B2_INLINE b2Rot b2NormalizeRot( b2Rot q )
    303 {
    304 	float mag = sqrtf( q.s * q.s + q.c * q.c );
    305 	float invMag = mag > 0.0 ? 1.0f / mag : 0.0f;
    306 	b2Rot qn = { q.c * invMag, q.s * invMag };
    307 	return qn;
    308 }
    309 
    310 /// Integrate rotation from angular velocity
    311 /// @param q1 initial rotation
    312 /// @param deltaAngle the angular displacement in radians
    313 B2_INLINE b2Rot b2IntegrateRotation( b2Rot q1, float deltaAngle )
    314 {
    315 	// dc/dt = -omega * sin(t)
    316 	// ds/dt = omega * cos(t)
    317 	// c2 = c1 - omega * h * s1
    318 	// s2 = s1 + omega * h * c1
    319 	b2Rot q2 = { q1.c - deltaAngle * q1.s, q1.s + deltaAngle * q1.c };
    320 	float mag = sqrtf( q2.s * q2.s + q2.c * q2.c );
    321 	float invMag = mag > 0.0 ? 1.0f / mag : 0.0f;
    322 	b2Rot qn = { q2.c * invMag, q2.s * invMag };
    323 	return qn;
    324 }
    325 
    326 /// Get the length squared of this vector
    327 B2_INLINE float b2LengthSquared( b2Vec2 v )
    328 {
    329 	return v.x * v.x + v.y * v.y;
    330 }
    331 
    332 /// Get the distance squared between points
    333 B2_INLINE float b2DistanceSquared( b2Vec2 a, b2Vec2 b )
    334 {
    335 	b2Vec2 c = { b.x - a.x, b.y - a.y };
    336 	return c.x * c.x + c.y * c.y;
    337 }
    338 
    339 /// Make a rotation using an angle in radians
    340 B2_INLINE b2Rot b2MakeRot( float radians )
    341 {
    342 	b2CosSin cs = b2ComputeCosSin( radians );
    343 	return B2_LITERAL( b2Rot ){ cs.cosine, cs.sine };
    344 }
    345 
    346 /// Compute the rotation between two unit vectors
    347 B2_API b2Rot b2ComputeRotationBetweenUnitVectors( b2Vec2 v1, b2Vec2 v2 );
    348 
    349 /// Is this rotation normalized?
    350 B2_INLINE bool b2IsNormalized( b2Rot q )
    351 {
    352 	// larger tolerance due to failure on mingw 32-bit
    353 	float qq = q.s * q.s + q.c * q.c;
    354 	return 1.0f - 0.0006f < qq && qq < 1.0f + 0.0006f;
    355 }
    356 
    357 /// Normalized linear interpolation
    358 /// https://fgiesen.wordpress.com/2012/08/15/linear-interpolation-past-present-and-future/
    359 ///	https://web.archive.org/web/20170825184056/http://number-none.com/product/Understanding%20Slerp,%20Then%20Not%20Using%20It/
    360 B2_INLINE b2Rot b2NLerp( b2Rot q1, b2Rot q2, float t )
    361 {
    362 	float omt = 1.0f - t;
    363 	b2Rot q = {
    364 		omt * q1.c + t * q2.c,
    365 		omt * q1.s + t * q2.s,
    366 	};
    367 
    368 	return b2NormalizeRot( q );
    369 }
    370 
    371 /// Compute the angular velocity necessary to rotate between two rotations over a give time
    372 /// @param q1 initial rotation
    373 /// @param q2 final rotation
    374 /// @param inv_h inverse time step
    375 B2_INLINE float b2ComputeAngularVelocity( b2Rot q1, b2Rot q2, float inv_h )
    376 {
    377 	// ds/dt = omega * cos(t)
    378 	// dc/dt = -omega * sin(t)
    379 	// s2 = s1 + omega * h * c1
    380 	// c2 = c1 - omega * h * s1
    381 
    382 	// omega * h * s1 = c1 - c2
    383 	// omega * h * c1 = s2 - s1
    384 	// omega * h = (c1 - c2) * s1 + (s2 - s1) * c1;
    385 	// omega * h = s1 * c1 - c2 * s1 + s2 * c1 - s1 * c1
    386 	// omega * h = s2 * c1 - c2 * s1 = sin(a2 - a1) ~= a2 - a1 for small delta
    387 	float omega = inv_h * ( q2.s * q1.c - q2.c * q1.s );
    388 	return omega;
    389 }
    390 
    391 /// Get the angle in radians in the range [-pi, pi]
    392 B2_INLINE float b2Rot_GetAngle( b2Rot q )
    393 {
    394 	return b2Atan2( q.s, q.c );
    395 }
    396 
    397 /// Get the x-axis
    398 B2_INLINE b2Vec2 b2Rot_GetXAxis( b2Rot q )
    399 {
    400 	b2Vec2 v = { q.c, q.s };
    401 	return v;
    402 }
    403 
    404 /// Get the y-axis
    405 B2_INLINE b2Vec2 b2Rot_GetYAxis( b2Rot q )
    406 {
    407 	b2Vec2 v = { -q.s, q.c };
    408 	return v;
    409 }
    410 
    411 /// Multiply two rotations: q * r
    412 B2_INLINE b2Rot b2MulRot( b2Rot q, b2Rot r )
    413 {
    414 	// [qc -qs] * [rc -rs] = [qc*rc-qs*rs -qc*rs-qs*rc]
    415 	// [qs  qc]   [rs  rc]   [qs*rc+qc*rs -qs*rs+qc*rc]
    416 	// s(q + r) = qs * rc + qc * rs
    417 	// c(q + r) = qc * rc - qs * rs
    418 	b2Rot qr;
    419 	qr.s = q.s * r.c + q.c * r.s;
    420 	qr.c = q.c * r.c - q.s * r.s;
    421 	return qr;
    422 }
    423 
    424 /// Transpose multiply two rotations: qT * r
    425 B2_INLINE b2Rot b2InvMulRot( b2Rot q, b2Rot r )
    426 {
    427 	// [ qc qs] * [rc -rs] = [qc*rc+qs*rs -qc*rs+qs*rc]
    428 	// [-qs qc]   [rs  rc]   [-qs*rc+qc*rs qs*rs+qc*rc]
    429 	// s(q - r) = qc * rs - qs * rc
    430 	// c(q - r) = qc * rc + qs * rs
    431 	b2Rot qr;
    432 	qr.s = q.c * r.s - q.s * r.c;
    433 	qr.c = q.c * r.c + q.s * r.s;
    434 	return qr;
    435 }
    436 
    437 /// relative angle between b and a (rot_b * inv(rot_a))
    438 B2_INLINE float b2RelativeAngle( b2Rot b, b2Rot a )
    439 {
    440 	// sin(b - a) = bs * ac - bc * as
    441 	// cos(b - a) = bc * ac + bs * as
    442 	float s = b.s * a.c - b.c * a.s;
    443 	float c = b.c * a.c + b.s * a.s;
    444 	return b2Atan2( s, c );
    445 }
    446 
    447 /// Convert an angle in the range [-2*pi, 2*pi] into the range [-pi, pi]
    448 B2_INLINE float b2UnwindAngle( float radians )
    449 {
    450 	if ( radians < -B2_PI )
    451 	{
    452 		return radians + 2.0f * B2_PI;
    453 	}
    454 	else if ( radians > B2_PI )
    455 	{
    456 		return radians - 2.0f * B2_PI;
    457 	}
    458 
    459 	return radians;
    460 }
    461 
    462 /// Convert any into the range [-pi, pi] (slow)
    463 B2_INLINE float b2UnwindLargeAngle( float radians )
    464 {
    465 	while ( radians > B2_PI )
    466 	{
    467 		radians -= 2.0f * B2_PI;
    468 	}
    469 
    470 	while ( radians < -B2_PI )
    471 	{
    472 		radians += 2.0f * B2_PI;
    473 	}
    474 
    475 	return radians;
    476 }
    477 
    478 /// Rotate a vector
    479 B2_INLINE b2Vec2 b2RotateVector( b2Rot q, b2Vec2 v )
    480 {
    481 	return B2_LITERAL( b2Vec2 ){ q.c * v.x - q.s * v.y, q.s * v.x + q.c * v.y };
    482 }
    483 
    484 /// Inverse rotate a vector
    485 B2_INLINE b2Vec2 b2InvRotateVector( b2Rot q, b2Vec2 v )
    486 {
    487 	return B2_LITERAL( b2Vec2 ){ q.c * v.x + q.s * v.y, -q.s * v.x + q.c * v.y };
    488 }
    489 
    490 /// Transform a point (e.g. local space to world space)
    491 B2_INLINE b2Vec2 b2TransformPoint( b2Transform t, const b2Vec2 p )
    492 {
    493 	float x = ( t.q.c * p.x - t.q.s * p.y ) + t.p.x;
    494 	float y = ( t.q.s * p.x + t.q.c * p.y ) + t.p.y;
    495 
    496 	return B2_LITERAL( b2Vec2 ){ x, y };
    497 }
    498 
    499 /// Inverse transform a point (e.g. world space to local space)
    500 B2_INLINE b2Vec2 b2InvTransformPoint( b2Transform t, const b2Vec2 p )
    501 {
    502 	float vx = p.x - t.p.x;
    503 	float vy = p.y - t.p.y;
    504 	return B2_LITERAL( b2Vec2 ){ t.q.c * vx + t.q.s * vy, -t.q.s * vx + t.q.c * vy };
    505 }
    506 
    507 /// Multiply two transforms. If the result is applied to a point p local to frame B,
    508 /// the transform would first convert p to a point local to frame A, then into a point
    509 /// in the world frame.
    510 /// v2 = A.q.Rot(B.q.Rot(v1) + B.p) + A.p
    511 ///    = (A.q * B.q).Rot(v1) + A.q.Rot(B.p) + A.p
    512 B2_INLINE b2Transform b2MulTransforms( b2Transform A, b2Transform B )
    513 {
    514 	b2Transform C;
    515 	C.q = b2MulRot( A.q, B.q );
    516 	C.p = b2Add( b2RotateVector( A.q, B.p ), A.p );
    517 	return C;
    518 }
    519 
    520 /// Creates a transform that converts a local point in frame B to a local point in frame A.
    521 /// v2 = A.q' * (B.q * v1 + B.p - A.p)
    522 ///    = A.q' * B.q * v1 + A.q' * (B.p - A.p)
    523 B2_INLINE b2Transform b2InvMulTransforms( b2Transform A, b2Transform B )
    524 {
    525 	b2Transform C;
    526 	C.q = b2InvMulRot( A.q, B.q );
    527 	C.p = b2InvRotateVector( A.q, b2Sub( B.p, A.p ) );
    528 	return C;
    529 }
    530 
    531 /// Multiply a 2-by-2 matrix times a 2D vector
    532 B2_INLINE b2Vec2 b2MulMV( b2Mat22 A, b2Vec2 v )
    533 {
    534 	b2Vec2 u = {
    535 		A.cx.x * v.x + A.cy.x * v.y,
    536 		A.cx.y * v.x + A.cy.y * v.y,
    537 	};
    538 	return u;
    539 }
    540 
    541 /// Get the inverse of a 2-by-2 matrix
    542 B2_INLINE b2Mat22 b2GetInverse22( b2Mat22 A )
    543 {
    544 	float a = A.cx.x, b = A.cy.x, c = A.cx.y, d = A.cy.y;
    545 	float det = a * d - b * c;
    546 	if ( det != 0.0f )
    547 	{
    548 		det = 1.0f / det;
    549 	}
    550 
    551 	b2Mat22 B = {
    552 		{ det * d, -det * c },
    553 		{ -det * b, det * a },
    554 	};
    555 	return B;
    556 }
    557 
    558 /// Solve A * x = b, where b is a column vector. This is more efficient
    559 /// than computing the inverse in one-shot cases.
    560 B2_INLINE b2Vec2 b2Solve22( b2Mat22 A, b2Vec2 b )
    561 {
    562 	float a11 = A.cx.x, a12 = A.cy.x, a21 = A.cx.y, a22 = A.cy.y;
    563 	float det = a11 * a22 - a12 * a21;
    564 	if ( det != 0.0f )
    565 	{
    566 		det = 1.0f / det;
    567 	}
    568 	b2Vec2 x = { det * ( a22 * b.x - a12 * b.y ), det * ( a11 * b.y - a21 * b.x ) };
    569 	return x;
    570 }
    571 
    572 /// Does a fully contain b
    573 B2_INLINE bool b2AABB_Contains( b2AABB a, b2AABB b )
    574 {
    575 	bool s = true;
    576 	s = s && a.lowerBound.x <= b.lowerBound.x;
    577 	s = s && a.lowerBound.y <= b.lowerBound.y;
    578 	s = s && b.upperBound.x <= a.upperBound.x;
    579 	s = s && b.upperBound.y <= a.upperBound.y;
    580 	return s;
    581 }
    582 
    583 /// Get the center of the AABB.
    584 B2_INLINE b2Vec2 b2AABB_Center( b2AABB a )
    585 {
    586 	b2Vec2 b = { 0.5f * ( a.lowerBound.x + a.upperBound.x ), 0.5f * ( a.lowerBound.y + a.upperBound.y ) };
    587 	return b;
    588 }
    589 
    590 /// Get the extents of the AABB (half-widths).
    591 B2_INLINE b2Vec2 b2AABB_Extents( b2AABB a )
    592 {
    593 	b2Vec2 b = { 0.5f * ( a.upperBound.x - a.lowerBound.x ), 0.5f * ( a.upperBound.y - a.lowerBound.y ) };
    594 	return b;
    595 }
    596 
    597 /// Union of two AABBs
    598 B2_INLINE b2AABB b2AABB_Union( b2AABB a, b2AABB b )
    599 {
    600 	b2AABB c;
    601 	c.lowerBound.x = b2MinFloat( a.lowerBound.x, b.lowerBound.x );
    602 	c.lowerBound.y = b2MinFloat( a.lowerBound.y, b.lowerBound.y );
    603 	c.upperBound.x = b2MaxFloat( a.upperBound.x, b.upperBound.x );
    604 	c.upperBound.y = b2MaxFloat( a.upperBound.y, b.upperBound.y );
    605 	return c;
    606 }
    607 
    608 /// Is this a valid number? Not NaN or infinity.
    609 B2_API bool b2IsValidFloat( float a );
    610 
    611 /// Is this a valid vector? Not NaN or infinity.
    612 B2_API bool b2IsValidVec2( b2Vec2 v );
    613 
    614 /// Is this a valid rotation? Not NaN or infinity. Is normalized.
    615 B2_API bool b2IsValidRotation( b2Rot q );
    616 
    617 /// Is this a valid bounding box? Not Nan or infinity. Upper bound greater than or equal to lower bound.
    618 B2_API bool b2IsValidAABB( b2AABB aabb );
    619 
    620 /// Box2D bases all length units on meters, but you may need different units for your game.
    621 /// You can set this value to use different units. This should be done at application startup
    622 /// and only modified once. Default value is 1.
    623 /// For example, if your game uses pixels for units you can use pixels for all length values
    624 /// sent to Box2D. There should be no extra cost. However, Box2D has some internal tolerances
    625 /// and thresholds that have been tuned for meters. By calling this function, Box2D is able
    626 /// to adjust those tolerances and thresholds to improve accuracy.
    627 /// A good rule of thumb is to pass the height of your player character to this function. So
    628 /// if your player character is 32 pixels high, then pass 32 to this function. Then you may
    629 /// confidently use pixels for all the length values sent to Box2D. All length values returned
    630 /// from Box2D will also be pixels because Box2D does not do any scaling internally.
    631 /// However, you are now on the hook for coming up with good values for gravity, density, and
    632 /// forces.
    633 /// @warning This must be modified before any calls to Box2D
    634 B2_API void b2SetLengthUnitsPerMeter( float lengthUnits );
    635 
    636 /// Get the current length units per meter.
    637 B2_API float b2GetLengthUnitsPerMeter( void );
    638 
    639 /**@}*/
    640 
    641 /**
    642  * @defgroup math_cpp C++ Math
    643  * @brief Math operator overloads for C++
    644  *
    645  * See math_functions.h for details.
    646  * @{
    647  */
    648 
    649 #ifdef __cplusplus
    650 
    651 /// Unary add one vector to another
    652 inline void operator+=( b2Vec2& a, b2Vec2 b )
    653 {
    654 	a.x += b.x;
    655 	a.y += b.y;
    656 }
    657 
    658 /// Unary subtract one vector from another
    659 inline void operator-=( b2Vec2& a, b2Vec2 b )
    660 {
    661 	a.x -= b.x;
    662 	a.y -= b.y;
    663 }
    664 
    665 /// Unary multiply a vector by a scalar
    666 inline void operator*=( b2Vec2& a, float b )
    667 {
    668 	a.x *= b;
    669 	a.y *= b;
    670 }
    671 
    672 /// Unary negate a vector
    673 inline b2Vec2 operator-( b2Vec2 a )
    674 {
    675 	return { -a.x, -a.y };
    676 }
    677 
    678 /// Binary vector addition
    679 inline b2Vec2 operator+( b2Vec2 a, b2Vec2 b )
    680 {
    681 	return { a.x + b.x, a.y + b.y };
    682 }
    683 
    684 /// Binary vector subtraction
    685 inline b2Vec2 operator-( b2Vec2 a, b2Vec2 b )
    686 {
    687 	return { a.x - b.x, a.y - b.y };
    688 }
    689 
    690 /// Binary scalar and vector multiplication
    691 inline b2Vec2 operator*( float a, b2Vec2 b )
    692 {
    693 	return { a * b.x, a * b.y };
    694 }
    695 
    696 /// Binary scalar and vector multiplication
    697 inline b2Vec2 operator*( b2Vec2 a, float b )
    698 {
    699 	return { a.x * b, a.y * b };
    700 }
    701 
    702 /// Binary vector equality
    703 inline bool operator==( b2Vec2 a, b2Vec2 b )
    704 {
    705 	return a.x == b.x && a.y == b.y;
    706 }
    707 
    708 /// Binary vector inequality
    709 inline bool operator!=( b2Vec2 a, b2Vec2 b )
    710 {
    711 	return a.x != b.x || a.y != b.y;
    712 }
    713 
    714 #endif
    715 
    716 /**@}*/