VCV Rack API v2
Loading...
Searching...
No Matches
math.hpp
Go to the documentation of this file.
1#pragma once
2#include <complex>
3#include <algorithm> // for std::min, max
4
5#include <common.hpp>
6
7
8namespace rack {
10namespace math {
11
12
14// basic integer functions
16
18template <typename T>
19bool isEven(T x) {
20 return x % 2 == 0;
21}
22
24template <typename T>
25bool isOdd(T x) {
26 return x % 2 != 0;
27}
28
32inline int clamp(int x, int a, int b) {
33 return std::max(std::min(x, b), a);
34}
35
39inline int clampSafe(int x, int a, int b) {
40 return (a <= b) ? clamp(x, a, b) : clamp(x, b, a);
41}
42
47inline int eucMod(int a, int b) {
48 int mod = a % b;
49 if (mod < 0) {
50 mod += b;
51 }
52 return mod;
53}
54
58inline int eucDiv(int a, int b) {
59 int div = a / b;
60 int mod = a % b;
61 if (mod < 0) {
62 div -= 1;
63 }
64 return div;
65}
66
67inline void eucDivMod(int a, int b, int* div, int* mod) {
68 *div = a / b;
69 *mod = a % b;
70 if (*mod < 0) {
71 *div -= 1;
72 *mod += b;
73 }
74}
75
77inline int log2(int n) {
78 int i = 0;
79 while (n >>= 1) {
80 i++;
81 }
82 return i;
83}
84
86template <typename T>
87bool isPow2(T n) {
88 return n > 0 && (n & (n - 1)) == 0;
89}
90
94template <typename T>
95T sgn(T x) {
96 return x > 0 ? 1 : (x < 0 ? -1 : 0);
97}
98
100// basic float functions
102
106inline float clamp(float x, float a = 0.f, float b = 1.f) {
107 return std::fmax(std::fmin(x, b), a);
108}
109
113inline float clampSafe(float x, float a = 0.f, float b = 1.f) {
114 return (a <= b) ? clamp(x, a, b) : clamp(x, b, a);
115}
116
118#if defined __clang__
119// Clang doesn't support disabling individual optimizations, just everything.
120__attribute__((optnone))
121#else
122__attribute__((optimize("signed-zeros")))
123#endif
124inline float normalizeZero(float x) {
125 return x + 0.f;
126}
127
131inline float eucMod(float a, float b) {
132 float mod = std::fmod(a, b);
133 if (mod < 0.f) {
134 mod += b;
135 }
136 return mod;
137}
138
140inline bool isNear(float a, float b, float epsilon = 1e-6f) {
141 return std::fabs(a - b) <= epsilon;
142}
143
145inline float chop(float x, float epsilon = 1e-6f) {
146 return std::fabs(x) <= epsilon ? 0.f : x;
147}
148
151inline float rescale(float x, float xMin, float xMax, float yMin, float yMax) {
152 return yMin + (x - xMin) / (xMax - xMin) * (yMax - yMin);
153}
154
157inline float crossfade(float a, float b, float p) {
158 return a + (b - a) * p;
159}
160
164inline float interpolateLinear(const float* p, float x) {
165 int xi = x;
166 float xf = x - xi;
167 return crossfade(p[xi], p[xi + 1], xf);
168}
169
176inline void complexMult(float ar, float ai, float br, float bi, float* cr, float* ci) {
177 *cr = ar * br - ai * bi;
178 *ci = ar * bi + ai * br;
179}
180
182// 2D vector and rectangle
184
185struct Rect;
186
189struct Vec {
190 float x = 0.f;
191 float y = 0.f;
192
193 Vec() {}
194 Vec(float xy) : x(xy), y(xy) {}
195 Vec(float x, float y) : x(x), y(y) {}
196
197 float& operator[](int i) {
198 return (i == 0) ? x : y;
199 }
200 const float& operator[](int i) const {
201 return (i == 0) ? x : y;
202 }
206 Vec neg() const {
207 return Vec(-x, -y);
208 }
209 Vec plus(Vec b) const {
210 return Vec(x + b.x, y + b.y);
211 }
212 Vec minus(Vec b) const {
213 return Vec(x - b.x, y - b.y);
214 }
215 Vec mult(float s) const {
216 return Vec(x * s, y * s);
217 }
218 Vec mult(Vec b) const {
219 return Vec(x * b.x, y * b.y);
220 }
221 Vec div(float s) const {
222 return Vec(x / s, y / s);
223 }
224 Vec div(Vec b) const {
225 return Vec(x / b.x, y / b.y);
226 }
227 float dot(Vec b) const {
228 return x * b.x + y * b.y;
229 }
230 float arg() const {
231 return std::atan2(y, x);
232 }
233 float norm() const {
234 return std::hypot(x, y);
235 }
236 Vec normalize() const {
237 return div(norm());
238 }
239 float square() const {
240 return x * x + y * y;
241 }
242 float area() const {
243 return x * y;
244 }
246 Vec rotate(float angle) {
247 float sin = std::sin(angle);
248 float cos = std::cos(angle);
249 return Vec(x * cos - y * sin, x * sin + y * cos);
250 }
254 Vec flip() const {
255 return Vec(y, x);
256 }
257 Vec min(Vec b) const {
258 return Vec(std::fmin(x, b.x), std::fmin(y, b.y));
259 }
260 Vec max(Vec b) const {
261 return Vec(std::fmax(x, b.x), std::fmax(y, b.y));
262 }
263 Vec abs() const {
264 return Vec(std::fabs(x), std::fabs(y));
265 }
266 Vec round() const {
267 return Vec(std::round(x), std::round(y));
268 }
269 Vec floor() const {
270 return Vec(std::floor(x), std::floor(y));
271 }
272 Vec ceil() const {
273 return Vec(std::ceil(x), std::ceil(y));
274 }
275 bool equals(Vec b) const {
276 return x == b.x && y == b.y;
277 }
278 bool isZero() const {
279 return x == 0.f && y == 0.f;
280 }
281 bool isFinite() const {
282 return std::isfinite(x) && std::isfinite(y);
283 }
284 Vec clamp(Rect bound) const;
285 Vec clampSafe(Rect bound) const;
286 Vec crossfade(Vec b, float p) {
287 return this->plus(b.minus(*this).mult(p));
288 }
289
290 // Method aliases
291 bool isEqual(Vec b) const {
292 return equals(b);
293 }
294};
295
296
301struct Rect {
304
305 Rect() {}
307 Rect(float posX, float posY, float sizeX, float sizeY) : pos(Vec(posX, posY)), size(Vec(sizeX, sizeY)) {}
310 static Rect fromMinMax(Vec a, Vec b) {
311 return Rect(a, b.minus(a));
312 }
315 static Rect fromCorners(Vec a, Vec b) {
316 return fromMinMax(a.min(b), a.max(b));
317 }
319 static Rect inf() {
320 return Rect(Vec(-INFINITY, -INFINITY), Vec(INFINITY, INFINITY));
321 }
322
326 bool contains(Vec v) const {
327 return (pos.x <= v.x) && (size.x == INFINITY || v.x < pos.x + size.x)
328 && (pos.y <= v.y) && (size.y == INFINITY || v.y < pos.y + size.y);
329 }
333 bool contains(Rect r) const {
334 return (pos.x <= r.pos.x) && (r.pos.x - size.x <= pos.x - r.size.x)
335 && (pos.y <= r.pos.y) && (r.pos.y - size.y <= pos.y - r.size.y);
336 }
340 bool intersects(Rect r) const {
341 return (r.size.x == INFINITY || pos.x < r.pos.x + r.size.x) && (size.x == INFINITY || r.pos.x < pos.x + size.x)
342 && (r.size.y == INFINITY || pos.y < r.pos.y + r.size.y) && (size.y == INFINITY || r.pos.y < pos.y + size.y);
343 }
344 bool equals(Rect r) const {
345 return pos.equals(r.pos) && size.equals(r.size);
346 }
347 float getLeft() const {
348 return pos.x;
349 }
350 float getRight() const {
351 return (size.x == INFINITY) ? INFINITY : (pos.x + size.x);
352 }
353 float getTop() const {
354 return pos.y;
355 }
356 float getBottom() const {
357 return (size.y == INFINITY) ? INFINITY : (pos.y + size.y);
358 }
359 float getWidth() const {
360 return size.x;
361 }
362 float getHeight() const {
363 return size.y;
364 }
368 Vec getCenter() const {
369 return pos.plus(size.mult(0.5f));
370 }
371 Vec getTopLeft() const {
372 return pos;
373 }
374 Vec getTopRight() const {
375 return Vec(getRight(), getTop());
376 }
378 return Vec(getLeft(), getBottom());
379 }
381 return Vec(getRight(), getBottom());
382 }
384 Rect clamp(Rect bound) const {
385 Rect r;
386 r.pos.x = math::clampSafe(pos.x, bound.pos.x, bound.pos.x + bound.size.x);
387 r.pos.y = math::clampSafe(pos.y, bound.pos.y, bound.pos.y + bound.size.y);
388 r.size.x = math::clamp(pos.x + size.x, bound.pos.x, bound.pos.x + bound.size.x) - r.pos.x;
389 r.size.y = math::clamp(pos.y + size.y, bound.pos.y, bound.pos.y + bound.size.y) - r.pos.y;
390 return r;
391 }
393 Rect nudge(Rect bound) const {
394 Rect r;
395 r.size = size;
396 r.pos.x = math::clampSafe(pos.x, bound.pos.x, bound.pos.x + bound.size.x - size.x);
397 r.pos.y = math::clampSafe(pos.y, bound.pos.y, bound.pos.y + bound.size.y - size.y);
398 return r;
399 }
401 Rect expand(Rect b) const {
402 Rect r;
403 r.pos.x = std::fmin(pos.x, b.pos.x);
404 r.pos.y = std::fmin(pos.y, b.pos.y);
405 r.size.x = std::fmax(pos.x + size.x, b.pos.x + b.size.x) - r.pos.x;
406 r.size.y = std::fmax(pos.y + size.y, b.pos.y + b.size.y) - r.pos.y;
407 return r;
408 }
410 Rect intersect(Rect b) const {
411 Rect r;
412 r.pos.x = std::fmax(pos.x, b.pos.x);
413 r.pos.y = std::fmax(pos.y, b.pos.y);
414 r.size.x = std::fmin(pos.x + size.x, b.pos.x + b.size.x) - r.pos.x;
415 r.size.y = std::fmin(pos.y + size.y, b.pos.y + b.size.y) - r.pos.y;
416 return r;
417 }
419 Rect zeroPos() const {
420 return Rect(Vec(), size);
421 }
423 Rect grow(Vec delta) const {
424 Rect r;
425 r.pos = pos.minus(delta);
426 r.size = size.plus(delta.mult(2.f));
427 return r;
428 }
430 Rect shrink(Vec delta) const {
431 Rect r;
432 r.pos = pos.plus(delta);
433 r.size = size.minus(delta.mult(2.f));
434 return r;
435 }
438 return pos.plus(size.mult(p));
439 }
440
441 // Method aliases
442 bool isContaining(Vec v) const {
443 return contains(v);
444 }
445 bool isIntersecting(Rect r) const {
446 return intersects(r);
447 }
448 bool isEqual(Rect r) const {
449 return equals(r);
450 }
451};
452
453
454inline Vec Vec::clamp(Rect bound) const {
455 return Vec(
456 math::clamp(x, bound.pos.x, bound.pos.x + bound.size.x),
457 math::clamp(y, bound.pos.y, bound.pos.y + bound.size.y)
458 );
459}
460
461inline Vec Vec::clampSafe(Rect bound) const {
462 return Vec(
463 math::clampSafe(x, bound.pos.x, bound.pos.x + bound.size.x),
464 math::clampSafe(y, bound.pos.y, bound.pos.y + bound.size.y)
465 );
466}
467
468
469// Operator overloads for Vec
470inline Vec operator+(const Vec& a) {
471 return a;
472}
473inline Vec operator-(const Vec& a) {
474 return a.neg();
475}
476inline Vec operator+(const Vec& a, const Vec& b) {
477 return a.plus(b);
478}
479inline Vec operator-(const Vec& a, const Vec& b) {
480 return a.minus(b);
481}
482inline Vec operator*(const Vec& a, const Vec& b) {
483 return a.mult(b);
484}
485inline Vec operator*(const Vec& a, const float& b) {
486 return a.mult(b);
487}
488inline Vec operator*(const float& a, const Vec& b) {
489 return b.mult(a);
490}
491inline Vec operator/(const Vec& a, const Vec& b) {
492 return a.div(b);
493}
494inline Vec operator/(const Vec& a, const float& b) {
495 return a.div(b);
496}
497inline Vec operator+=(Vec& a, const Vec& b) {
498 return a = a.plus(b);
499}
500inline Vec operator-=(Vec& a, const Vec& b) {
501 return a = a.minus(b);
502}
503inline Vec operator*=(Vec& a, const Vec& b) {
504 return a = a.mult(b);
505}
506inline Vec operator*=(Vec& a, const float& b) {
507 return a = a.mult(b);
508}
509inline Vec operator/=(Vec& a, const Vec& b) {
510 return a = a.div(b);
511}
512inline Vec operator/=(Vec& a, const float& b) {
513 return a = a.div(b);
514}
515inline bool operator==(const Vec& a, const Vec& b) {
516 return a.equals(b);
517}
518inline bool operator!=(const Vec& a, const Vec& b) {
519 return !a.equals(b);
520}
521
522
523// Operator overloads for Rect
524inline bool operator==(const Rect& a, const Rect& b) {
525 return a.equals(b);
526}
527inline bool operator!=(const Rect& a, const Rect& b) {
528 return !a.equals(b);
529}
530
531
541#define VEC_ARGS(v) (v).x, (v).y
542#define RECT_ARGS(r) (r).pos.x, (r).pos.y, (r).size.x, (r).size.y
543
544
545} // namespace math
546} // namespace rack
Vec operator/=(Vec &a, const Vec &b)
Definition math.hpp:509
void eucDivMod(int a, int b, int *div, int *mod)
Definition math.hpp:67
int eucDiv(int a, int b)
Euclidean division.
Definition math.hpp:58
bool isEven(T x)
Returns true if x is odd.
Definition math.hpp:19
float chop(float x, float epsilon=1e-6f)
If the magnitude of x if less than epsilon, return 0.
Definition math.hpp:145
Vec operator+(const Vec &a)
Definition math.hpp:470
bool operator==(const Vec &a, const Vec &b)
Definition math.hpp:515
int eucMod(int a, int b)
Euclidean modulus.
Definition math.hpp:47
int clamp(int x, int a, int b)
Limits x between a and b.
Definition math.hpp:32
bool isOdd(T x)
Returns true if x is odd.
Definition math.hpp:25
bool operator!=(const Vec &a, const Vec &b)
Definition math.hpp:518
float rescale(float x, float xMin, float xMax, float yMin, float yMax)
Rescales x from the range [xMin, xMax] to [yMin, yMax].
Definition math.hpp:151
Vec operator-(const Vec &a)
Definition math.hpp:473
float crossfade(float a, float b, float p)
Linearly interpolates between a and b, from p = 0 to p = 1.
Definition math.hpp:157
bool isPow2(T n)
Returns whether n is a power of 2.
Definition math.hpp:87
int log2(int n)
Returns floor(log_2(n)), or 0 if n == 1.
Definition math.hpp:77
bool isNear(float a, float b, float epsilon=1e-6f)
Returns whether a is within epsilon distance from b.
Definition math.hpp:140
Vec operator+=(Vec &a, const Vec &b)
Definition math.hpp:497
Vec operator*(const Vec &a, const Vec &b)
Definition math.hpp:482
Vec operator-=(Vec &a, const Vec &b)
Definition math.hpp:500
__attribute__((optimize("signed-zeros"))) inline float normalizeZero(float x)
Converts -0.f to 0.f.
Definition math.hpp:122
int clampSafe(int x, int a, int b)
Limits x between a and b.
Definition math.hpp:39
float interpolateLinear(const float *p, float x)
Linearly interpolates an array p with index x.
Definition math.hpp:164
T sgn(T x)
Returns 1 for positive numbers, -1 for negative numbers, and 0 for zero.
Definition math.hpp:95
Vec operator/(const Vec &a, const Vec &b)
Definition math.hpp:491
Vec operator*=(Vec &a, const Vec &b)
Definition math.hpp:503
void complexMult(float ar, float ai, float br, float bi, float *cr, float *ci)
Complex multiplication c = a * b.
Definition math.hpp:176
Root namespace for the Rack API.
Definition AudioDisplay.hpp:9
2-dimensional rectangle for graphics.
Definition math.hpp:301
Rect(float posX, float posY, float sizeX, float sizeY)
Definition math.hpp:307
Rect nudge(Rect bound) const
Nudges the position to fix inside a bounding box.
Definition math.hpp:393
Vec size
Definition math.hpp:303
Vec pos
Definition math.hpp:302
bool isContaining(Vec v) const
Definition math.hpp:442
Rect(Vec pos, Vec size)
Definition math.hpp:306
Rect expand(Rect b) const
Returns the bounding box of the union of this and b.
Definition math.hpp:401
Vec getCenter() const
Returns the center point of the rectangle.
Definition math.hpp:368
Rect shrink(Vec delta) const
Contracts each corner.
Definition math.hpp:430
Rect clamp(Rect bound) const
Clamps the edges of the rectangle to fit within a bound.
Definition math.hpp:384
Rect grow(Vec delta) const
Expands each corner.
Definition math.hpp:423
bool equals(Rect r) const
Definition math.hpp:344
static Rect fromCorners(Vec a, Vec b)
Constructs a Rect from any two opposite corners.
Definition math.hpp:315
bool contains(Vec v) const
Returns whether this Rect contains a point, inclusive on the left/top, exclusive on the right/bottom.
Definition math.hpp:326
Vec getBottomRight() const
Definition math.hpp:380
float getTop() const
Definition math.hpp:353
float getHeight() const
Definition math.hpp:362
bool isIntersecting(Rect r) const
Definition math.hpp:445
Vec getTopRight() const
Definition math.hpp:374
static Rect fromMinMax(Vec a, Vec b)
Constructs a Rect from a top-left and bottom-right vector.
Definition math.hpp:310
float getRight() const
Definition math.hpp:350
Vec getTopLeft() const
Definition math.hpp:371
Vec interpolate(Vec p)
Returns pos + size * p
Definition math.hpp:437
float getLeft() const
Definition math.hpp:347
bool intersects(Rect r) const
Returns whether this Rect overlaps with another Rect.
Definition math.hpp:340
static Rect inf()
Returns the infinite Rect.
Definition math.hpp:319
bool isEqual(Rect r) const
Definition math.hpp:448
Rect zeroPos() const
Returns a Rect with its position set to zero.
Definition math.hpp:419
bool contains(Rect r) const
Returns whether this Rect contains (is a superset of) a Rect.
Definition math.hpp:333
Rect intersect(Rect b) const
Returns the intersection of this and b.
Definition math.hpp:410
float getBottom() const
Definition math.hpp:356
float getWidth() const
Definition math.hpp:359
Vec getBottomLeft() const
Definition math.hpp:377
Rect()
Definition math.hpp:305
2-dimensional vector of floats, representing a point on the plane for graphics.
Definition math.hpp:189
Vec minus(Vec b) const
Definition math.hpp:212
float square() const
Definition math.hpp:239
Vec normalize() const
Definition math.hpp:236
Vec clampSafe(Rect bound) const
Definition math.hpp:461
Vec plus(Vec b) const
Definition math.hpp:209
bool isFinite() const
Definition math.hpp:281
Vec clamp(Rect bound) const
Definition math.hpp:454
bool isZero() const
Definition math.hpp:278
Vec(float xy)
Definition math.hpp:194
Vec div(Vec b) const
Definition math.hpp:224
bool isEqual(Vec b) const
Definition math.hpp:291
float norm() const
Definition math.hpp:233
float arg() const
Definition math.hpp:230
Vec()
Definition math.hpp:193
Vec round() const
Definition math.hpp:266
Vec crossfade(Vec b, float p)
Definition math.hpp:286
Vec flip() const
Swaps the coordinates.
Definition math.hpp:254
Vec min(Vec b) const
Definition math.hpp:257
Vec mult(float s) const
Definition math.hpp:215
float x
Definition math.hpp:190
Vec abs() const
Definition math.hpp:263
Vec mult(Vec b) const
Definition math.hpp:218
float y
Definition math.hpp:191
Vec neg() const
Negates the vector.
Definition math.hpp:206
Vec max(Vec b) const
Definition math.hpp:260
Vec rotate(float angle)
Rotates counterclockwise in radians.
Definition math.hpp:246
const float & operator[](int i) const
Definition math.hpp:200
float area() const
Definition math.hpp:242
Vec floor() const
Definition math.hpp:269
float & operator[](int i)
Definition math.hpp:197
bool equals(Vec b) const
Definition math.hpp:275
float dot(Vec b) const
Definition math.hpp:227
Vec(float x, float y)
Definition math.hpp:195
Vec div(float s) const
Definition math.hpp:221
Vec ceil() const
Definition math.hpp:272