Ultralight  1.0.0
A fast, lightweight, HTML UI engine for native apps.
Geometry.h
Go to the documentation of this file.
1 #pragma once
15 #include <Ultralight/Defines.h>
16 #include <memory.h>
17 #include <cmath>
18 #include <algorithm>
19 
20 namespace ultralight {
21 
25 struct UExport vec2 {
26  union {
27  float value[2];
28  struct { float x, y; };
29  };
30 
31  inline vec2() {}
32 
33  inline vec2(float x, float y) : x(x), y(y) {}
34 
35  inline vec2(float x) : x(x), y(x) {}
36 
37  inline vec2 yx() const { return { y, x }; }
38 
39  inline vec2 xx() const { return { x, x }; }
40 
41  inline vec2 yy() const { return { y, y }; }
42 
43  inline friend vec2 operator+(vec2 lhs, const vec2& rhs) { lhs += rhs; return lhs; }
44 
45  inline friend vec2 operator-(vec2 lhs, const vec2& rhs) { lhs -= rhs; return lhs; }
46 
47  inline friend vec2 operator*(vec2 lhs, const vec2& rhs) { lhs *= rhs; return lhs; }
48 
49  inline friend vec2 operator/(vec2 lhs, const vec2& rhs) { lhs /= rhs; return lhs; }
50 
51  inline friend vec2 operator+(vec2 lhs, float rhs) { lhs += rhs; return lhs; }
52 
53  inline friend vec2 operator-(vec2 lhs, float rhs) { lhs -= rhs; return lhs; }
54 
55  inline friend vec2 operator*(vec2 lhs, float rhs) { lhs *= rhs; return lhs; }
56 
57  inline friend vec2 operator/(vec2 lhs, float rhs) { lhs /= rhs; return lhs; }
58 
59  inline vec2& operator+=(const vec2& rhs) {
60  value[0] += rhs.value[0];
61  value[1] += rhs.value[1];
62  return *this;
63  }
64 
65  inline vec2& operator-=(const vec2& rhs) {
66  value[0] -= rhs.value[0];
67  value[1] -= rhs.value[1];
68  return *this;
69  }
70 
71  inline vec2& operator*=(const vec2& rhs) {
72  value[0] *= rhs.value[0];
73  value[1] *= rhs.value[1];
74  return *this;
75  }
76 
77  inline vec2& operator/=(const vec2& rhs) {
78  value[0] /= rhs.value[0];
79  value[1] /= rhs.value[1];
80  return *this;
81  }
82 
83  inline vec2& operator+=(float rhs) {
84  value[0] += rhs;
85  value[1] += rhs;
86  return *this;
87  }
88 
89  inline vec2& operator-=(float rhs) {
90  value[0] -= rhs;
91  value[1] -= rhs;
92  return *this;
93  }
94 
95  inline vec2& operator*=(float rhs) {
96  value[0] *= rhs;
97  value[1] *= rhs;
98  return *this;
99  }
100 
101  inline vec2& operator/=(float rhs) {
102  value[0] /= rhs;
103  value[1] /= rhs;
104  return *this;
105  }
106 
107  inline friend bool operator==(const vec2& a, const vec2& b) {
108  return !memcmp(&a, &b, sizeof(a));
109  }
110 
111  inline friend bool operator!=(const vec2& a, const vec2& b) {
112  return !(a == b);
113  }
114 
115  inline friend vec2 min_(const vec2& a, const vec2& b) {
116  return{ (b.x < a.x) ? b.x : a.x,
117  (b.y < a.y) ? b.y : a.y };
118  }
119 
120  inline friend vec2 max_(const vec2& a, const vec2& b) {
121  return{ (a.x < b.x) ? b.x : a.x,
122  (a.y < b.y) ? b.y : a.y };
123  }
124 
125  inline friend vec2 clamp(const vec2& x, const vec2& minVal, const vec2& maxVal) {
126  return min_(max_(x, minVal), maxVal);
127  }
128 
129  inline friend vec2 mix(const vec2& a, const vec2& b, float t) {
130  return a * (1.0f - t) + b * t;
131  }
132 
133  inline friend float length(const vec2& a) {
134  return sqrtf(a.x * a.x + a.y * a.y);
135  }
136 
137  // squared length
138  inline friend float length2(const vec2& a) {
139  return dot(a, a);
140  }
141 
142  inline friend float distance(const vec2& a, const vec2& b) {
143  return length(a - b);
144  }
145 
146  // squared distance
147  inline friend float distance2(const vec2& a, const vec2& b) {
148  return length2(a - b);
149  }
150 
151  inline friend vec2 normalize(const vec2& a) {
152  return a / length(a);
153  }
154 
155  inline friend float dot(const vec2& a, const vec2& b) {
156  return a.x * b.x + a.y * b.y;
157  }
158 };
159 
163 struct UExport vec3 {
164  union {
165  float value[3];
166  struct { float x, y, z; };
167  };
168 
169  inline vec3() {}
170 
171  inline vec3(float x, float y, float z) : x(x), y(y), z(z) {}
172 
173  inline vec3(float x) : x(x), y(x), z(x) {}
174 
175  inline friend vec3 operator+(vec3 lhs, const vec3& rhs) { lhs += rhs; return lhs; }
176 
177  inline friend vec3 operator-(vec3 lhs, const vec3& rhs) { lhs -= rhs; return lhs; }
178 
179  inline friend vec3 operator*(vec3 lhs, const vec3& rhs) { lhs *= rhs; return lhs; }
180 
181  inline friend vec3 operator/(vec3 lhs, const vec3& rhs) { lhs /= rhs; return lhs; }
182 
183  inline friend vec3 operator+(vec3 lhs, float rhs) { lhs += rhs; return lhs; }
184 
185  inline friend vec3 operator-(vec3 lhs, float rhs) { lhs -= rhs; return lhs; }
186 
187  inline friend vec3 operator*(vec3 lhs, float rhs) { lhs *= rhs; return lhs; }
188 
189  inline friend vec3 operator/(vec3 lhs, float rhs) { lhs /= rhs; return lhs; }
190 
191  inline vec3& operator+=(const vec3& rhs) {
192  value[0] += rhs.value[0];
193  value[1] += rhs.value[1];
194  value[2] += rhs.value[2];
195  return *this;
196  }
197 
198  inline vec3& operator-=(const vec3& rhs) {
199  value[0] -= rhs.value[0];
200  value[1] -= rhs.value[1];
201  value[2] -= rhs.value[2];
202  return *this;
203  }
204 
205  inline vec3& operator*=(const vec3& rhs) {
206  value[0] *= rhs.value[0];
207  value[1] *= rhs.value[1];
208  value[2] *= rhs.value[2];
209  return *this;
210  }
211 
212  inline vec3& operator/=(const vec3& rhs) {
213  value[0] /= rhs.value[0];
214  value[1] /= rhs.value[1];
215  value[2] /= rhs.value[2];
216  return *this;
217  }
218 
219  inline vec3& operator+=(float rhs) {
220  value[0] += rhs;
221  value[1] += rhs;
222  value[2] += rhs;
223  return *this;
224  }
225 
226  inline vec3& operator-=(float rhs) {
227  value[0] -= rhs;
228  value[1] -= rhs;
229  value[2] -= rhs;
230  return *this;
231  }
232 
233  inline vec3& operator*=(float rhs) {
234  value[0] *= rhs;
235  value[1] *= rhs;
236  value[2] *= rhs;
237  return *this;
238  }
239 
240  inline vec3& operator/=(float rhs) {
241  value[0] /= rhs;
242  value[1] /= rhs;
243  value[2] /= rhs;
244  return *this;
245  }
246 
247  inline friend bool operator==(const vec3& a, const vec3& b) {
248  return !memcmp(&a, &b, sizeof(a));
249  }
250 
251  inline friend bool operator!=(const vec3& a, const vec3& b) {
252  return !(a == b);
253  }
254 
255  inline friend vec3 min_(const vec3& a, const vec3& b) {
256  return{ (b.x < a.x) ? b.x : a.x,
257  (b.y < a.y) ? b.y : a.y,
258  (b.z < a.z) ? b.z : a.z };
259  }
260 
261  inline friend vec3 max_(const vec3& a, const vec3& b) {
262  return{ (a.x < b.x) ? b.x : a.x,
263  (a.y < b.y) ? b.y : a.y,
264  (a.z < b.z) ? b.z : a.z };
265  }
266  inline friend vec3 clamp(const vec3& x, const vec3& minVal, const vec3& maxVal) {
267  return min_(max_(x, minVal), maxVal);
268  }
269 
270  inline friend vec3 mix(const vec3& a, const vec3& b, float t) {
271  return a * (1.0f - t) + b * t;
272  }
273 
274  inline friend float length(const vec3& a) {
275  return sqrtf(a.x * a.x + a.y * a.y + a.z * a.z);
276  }
277 
278  inline friend float distance(const vec3& a, const vec3& b) {
279  return length(a - b);
280  }
281 
282  inline friend vec3 normalize(const vec3& a) {
283  return a / length(a);
284  }
285 
286  inline friend float dot(const vec3& a, const vec3& b) {
287  return a.x * b.x + a.y * b.y + a.z * b.z;
288  }
289 };
290 
294 struct UExport vec4 {
295  union {
296  float value[4];
297  struct { float x, y, z, w; };
298  };
299 
300  inline vec4() {}
301 
302  inline vec4(float x, float y, float z, float w) : x(x), y(y), z(z), w(w) {}
303 
304  inline vec4(float x) : x(x), y(x), z(x), w(x) {}
305 
306  inline vec4(const float x[4]) { memcpy(value, x, sizeof(value)); }
307 
308  inline friend bool operator==(const vec4& a, const vec4& b) {
309  return !memcmp(&a, &b, sizeof(a));
310  }
311 
312  inline friend bool operator!=(const vec4& a, const vec4& b) {
313  return !(a == b);
314  }
315 
316  inline friend vec4 operator+(vec4 lhs, const vec4& rhs) { lhs += rhs; return lhs; }
317 
318  inline friend vec4 operator-(vec4 lhs, const vec4& rhs) { lhs -= rhs; return lhs; }
319 
320  inline friend vec4 operator*(vec4 lhs, const vec4& rhs) { lhs *= rhs; return lhs; }
321 
322  inline friend vec4 operator/(vec4 lhs, const vec4& rhs) { lhs /= rhs; return lhs; }
323 
324  inline friend vec4 operator+(vec4 lhs, float rhs) { lhs += rhs; return lhs; }
325 
326  inline friend vec4 operator-(vec4 lhs, float rhs) { lhs -= rhs; return lhs; }
327 
328  inline friend vec4 operator*(vec4 lhs, float rhs) { lhs *= rhs; return lhs; }
329 
330  inline friend vec4 operator/(vec4 lhs, float rhs) { lhs /= rhs; return lhs; }
331 
332  inline vec4& operator+=(const vec4& rhs) {
333  value[0] += rhs.value[0];
334  value[1] += rhs.value[1];
335  value[2] += rhs.value[2];
336  value[3] += rhs.value[3];
337  return *this;
338  }
339 
340  inline vec4& operator-=(const vec4& rhs) {
341  value[0] -= rhs.value[0];
342  value[1] -= rhs.value[1];
343  value[2] -= rhs.value[2];
344  value[3] -= rhs.value[3];
345  return *this;
346  }
347 
348  inline vec4& operator*=(const vec4& rhs) {
349  value[0] *= rhs.value[0];
350  value[1] *= rhs.value[1];
351  value[2] *= rhs.value[2];
352  value[3] *= rhs.value[3];
353  return *this;
354  }
355 
356  inline vec4& operator/=(const vec4& rhs) {
357  value[0] /= rhs.value[0];
358  value[1] /= rhs.value[1];
359  value[2] /= rhs.value[2];
360  value[3] /= rhs.value[3];
361  return *this;
362  }
363 
364  inline vec4& operator+=(float rhs) {
365  value[0] += rhs;
366  value[1] += rhs;
367  value[2] += rhs;
368  value[3] += rhs;
369  return *this;
370  }
371 
372  inline vec4& operator-=(float rhs) {
373  value[0] -= rhs;
374  value[1] -= rhs;
375  value[2] -= rhs;
376  value[3] -= rhs;
377  return *this;
378  }
379 
380  inline vec4& operator*=(float rhs) {
381  value[0] *= rhs;
382  value[1] *= rhs;
383  value[2] *= rhs;
384  value[3] *= rhs;
385  return *this;
386  }
387 
388  inline vec4& operator/=(float rhs) {
389  value[0] /= rhs;
390  value[1] /= rhs;
391  value[2] /= rhs;
392  value[3] /= rhs;
393  return *this;
394  }
395 
396  inline friend vec4 min_(const vec4& a, const vec4& b) {
397  return{ (b.x < a.x) ? b.x : a.x,
398  (b.y < a.y) ? b.y : a.y,
399  (b.z < a.z) ? b.z : a.z,
400  (b.w < a.w) ? b.w : a.w };
401  }
402 
403  inline friend vec4 max_(const vec4& a, const vec4& b) {
404  return{ (a.x < b.x) ? b.x : a.x,
405  (a.y < b.y) ? b.y : a.y,
406  (a.z < b.z) ? b.z : a.z,
407  (a.w < b.w) ? b.w : a.w };
408  }
409 };
410 
414 typedef vec2 Point;
415 
419 struct UExport Rect {
420  union {
421  float value[4];
422  struct { float left, top, right, bottom; };
423  };
424 
425  static inline Rect MakeEmpty() {
426  Rect result;
427  result.SetEmpty();
428  return result;
429  }
430 
431  inline float width() const { return right - left; }
432  inline float height() const { return bottom - top; }
433  inline float x() const { return left; }
434  inline float y() const { return top; }
435  inline float center_x() const { return (left + right) * 0.5f; }
436  inline float center_y() const { return (top + bottom) * 0.5f; }
437 
438  inline Point origin() const { return { left, top }; }
439 
440  inline void SetEmpty() {
441  memset(this, 0, sizeof(*this));
442  }
443 
444  inline bool IsEmpty() const {
445  return *this == MakeEmpty();
446  }
447 
448  inline bool IsValid() const {
449  return width() > 0 && height() > 0;
450  }
451 
452  inline void Inset(float dx, float dy) {
453  value[0] += dx;
454  value[1] += dy;
455  value[2] -= dx;
456  value[3] -= dy;
457  }
458 
459  inline void Outset(float dx, float dy) {
460  Inset(-dx, -dy);
461  }
462 
463  inline void Move(float dx, float dy) {
464  value[0] += dx;
465  value[1] += dy;
466  value[2] += dx;
467  value[3] += dy;
468  }
469 
470  inline float area() const {
471  return width() * height();
472  }
473 
474  inline void Join(const Rect& rhs) {
475  // if we are empty, just assign
476  if (IsEmpty()) {
477  *this = rhs;
478  }
479  else {
480  if (rhs.value[0] < value[0]) value[0] = rhs.value[0];
481  if (rhs.value[1] < value[1]) value[1] = rhs.value[1];
482  if (rhs.value[2] > value[2]) value[2] = rhs.value[2];
483  if (rhs.value[3] > value[3]) value[3] = rhs.value[3];
484  }
485  }
486 
487  inline void Join(const Point& p) {
488  // if we are empty, just assign
489  if (IsEmpty()) {
490  *this = { p.x, p.y, p.x, p.y };
491  }
492  else {
493  if (p.x < value[0]) value[0] = p.x;
494  if (p.y < value[1]) value[1] = p.y;
495  if (p.x > value[2]) value[2] = p.x;
496  if (p.y > value[3]) value[3] = p.y;
497  }
498  }
499 
500  inline bool Contains(const Point& p) const {
501  return p.x >= left && p.x <= right &&
502  p.y >= top && p.y <= bottom;
503  }
504 
505  inline bool Contains(const Rect& r) const {
506  return left <= r.left && top <= r.top &&
507  right >= r.right && bottom >= r.bottom;
508  }
509 
510  inline bool Intersects(const Rect& rhs) const {
511  return !(rhs.left > right ||
512  rhs.right < left ||
513  rhs.top > bottom ||
514  rhs.bottom < top);
515  }
516 
517  inline Rect Intersect(const Rect& other) const {
518  return{ (left < other.left) ? other.left : left,
519  (top < other.top) ? other.top : top,
520  (other.right < right) ? other.right : right,
521  (other.bottom < bottom) ? other.bottom : bottom };
522  }
523 
524  friend inline bool operator==(const Rect& a, const Rect& b) {
525  return !memcmp(&a, &b, sizeof(a));
526  }
527 
528  friend inline bool operator!=(const Rect& a, const Rect& b) {
529  return !(a == b);
530  }
531 };
532 
536 struct UExport IntRect {
537  union {
538  int value[4];
539  struct { int left, top, right, bottom; };
540  };
541 
542  static inline IntRect MakeEmpty() {
543  IntRect result;
544  result.SetEmpty();
545  return result;
546  }
547 
548  inline int width() const { return right - left; }
549  inline int height() const { return bottom - top; }
550  inline int x() const { return left; }
551  inline int y() const { return top; }
552  inline int center_x() const { return (int)std::round((left + right) * 0.5f); }
553  inline int center_y() const { return (int)std::round((top + bottom) * 0.5f); }
554 
555  inline Point origin() const { return{ (float)left, (float)top }; }
556 
557  inline void SetEmpty() {
558  memset(this, 0, sizeof(*this));
559  }
560 
561  inline bool IsEmpty() const {
562  return *this == MakeEmpty();
563  }
564 
565  inline bool IsValid() const {
566  return width() > 0 && height() > 0;
567  }
568 
569  inline void Inset(int dx, int dy) {
570  value[0] += dx;
571  value[1] += dy;
572  value[2] -= dx;
573  value[3] -= dy;
574  }
575 
576  inline void Outset(int dx, int dy) {
577  Inset(-dx, -dy);
578  }
579 
580  inline void Move(int dx, int dy) {
581  value[0] += dx;
582  value[1] += dy;
583  value[2] += dx;
584  value[3] += dy;
585  }
586 
587  inline int area() const {
588  return width() * height();
589  }
590 
591  inline void Join(const IntRect& rhs) {
592  // if we are empty, just assign
593  if (IsEmpty()) {
594  *this = rhs;
595  }
596  else {
597  if (rhs.value[0] < value[0]) value[0] = rhs.value[0];
598  if (rhs.value[1] < value[1]) value[1] = rhs.value[1];
599  if (rhs.value[2] > value[2]) value[2] = rhs.value[2];
600  if (rhs.value[3] > value[3]) value[3] = rhs.value[3];
601  }
602  }
603 
604  inline void Join(const Point& p) {
605  // if we are empty, just assign
606  if (IsEmpty()) {
607  *this = { (int)std::floor(p.x), (int)std::floor(p.y), (int)std::ceil(p.x), (int)std::ceil(p.y) };
608  }
609  else {
610  if ((int)std::floor(p.x) < value[0]) value[0] = (int)std::floor(p.x);
611  if ((int)std::floor(p.y) < value[1]) value[1] = (int)std::floor(p.y);
612  if ((int)std::ceil(p.x) > value[2]) value[2] = (int)std::ceil(p.x);
613  if ((int)std::ceil(p.y) > value[3]) value[3] = (int)std::ceil(p.y);
614  }
615  }
616 
617  inline bool Contains(const Point& p) const {
618  return p.x >= left && p.x <= right &&
619  p.y >= top && p.y <= bottom;
620  }
621 
622  inline bool Contains(const IntRect& r) const {
623  return left <= r.left && top <= r.top &&
624  right >= r.right && bottom >= r.bottom;
625  }
626 
627  inline bool Intersects(const IntRect& rhs) const {
628  // Since this is mostly used for pixel operations, we only count
629  // intersections that have width and height >= 1.
630  return !(rhs.left > right - 1 ||
631  rhs.right < left ||
632  rhs.top > bottom - 1 ||
633  rhs.bottom < top);
634  }
635 
636  inline IntRect Intersect(const IntRect& other) const {
637  return{ (left < other.left) ? other.left : left,
638  (top < other.top) ? other.top : top,
639  (other.right < right) ? other.right : right,
640  (other.bottom < bottom) ? other.bottom : bottom };
641  }
642 
643  friend inline bool operator==(const IntRect& a, const IntRect& b) {
644  return !memcmp(&a, &b, sizeof(a));
645  }
646 
647  friend inline bool operator!=(const IntRect& a, const IntRect& b) {
648  return !(a == b);
649  }
650 };
651 
655 struct UExport RoundedRect {
656  Rect rect;
657  float radii_x[4];
658  float radii_y[4];
659 
660  void SetEmpty();
661 
662  bool IsRounded() const;
663 
664  // Negative is inside, positive is outside.
665  float GetSignedDistance(const Point& p) const;
666 
667  // Returns whether or not intersection is found. Can fail if the resulting
668  // geometry is not a rounded rectangle.
669  bool Intersect(const RoundedRect& other, RoundedRect& result) const;
670 
671  void SnapToPixels();
672 
673  Rect CalculateInterior() const;
674 };
675 
676 } // namespace ultralight
Rounded Rectangle Helper.
Definition: Geometry.h:655
This is a set of common JavaScriptCore Helper functions to simplify sample code.
Definition: App.h:19
vec2 Point
Point is typedef'd to a 2D vector.
Definition: Geometry.h:414
Float Rectangle Helper.
Definition: Geometry.h:419
3D Vector Helper
Definition: Geometry.h:163
Integer Rectangle Helper.
Definition: Geometry.h:536
2D Vector Helper
Definition: Geometry.h:25
4D Vector Helper
Definition: Geometry.h:294