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 /**@}*/