TGX 1.0.8
A tiny 2D/3D graphics library optimized for 32 bits microcontrollers.
Loading...
Searching...
No Matches
Box2.h
Go to the documentation of this file.
1
5//
6// Copyright 2020 Arvind Singh
7//
8// This library is free software; you can redistribute it and/or
9// modify it under the terms of the GNU Lesser General Public
10// License as published by the Free Software Foundation; either
11//version 2.1 of the License, or (at your option) any later version.
12//
13// This library is distributed in the hope that it will be useful,
14// but WITHOUT ANY WARRANTY; without even the implied warranty of
15// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the GNU
16// Lesser General Public License for more details.
17//
18// You should have received a copy of the GNU Lesser General Public
19// License along with this library; If not, see <http://www.gnu.org/licenses/>.
20
21#ifndef _TGX_BOX2_H_
22#define _TGX_BOX2_H_
23
24// only C++, no plain C
25#ifdef __cplusplus
26
27
28#include "Misc.h"
29#include "Vec2.h"
30
31#include <type_traits>
32#include <stdint.h>
33
34namespace tgx
35{
36
37
38 // Forward declaration
39
40 template<typename T> struct Box2;
41
42
43 // Specializations
44
45 typedef Box2<int> iBox2;
46
48
50
51
52
73 enum Anchor
74 {
75 CENTER = 0,
76 LEFT = 1,
77 RIGHT = 2,
78 TOP = 4,
79 BOTTOM = 8,
80 BASELINE = 16,
90 };
91
92
94 inline constexpr Anchor operator|(Anchor a1, Anchor a2) { return ((Anchor)((int)a1 | (int)a2)); }
95
97 inline Anchor& operator|=(Anchor& a1, Anchor a2) { a1 = a1 | a2; return a1; }
98
100 inline constexpr Anchor operator&(Anchor a1, Anchor a2) { return ((Anchor)((int)a1 & (int)a2)); }
101
103 inline Anchor& operator&=(Anchor& a1, Anchor a2) { a1 = a1 & a2; return a1; }
104
105
106
109 {
110 SPLIT_LEFT = Anchor::LEFT,
111 SPLIT_RIGHT = Anchor::RIGHT,
112 SPLIT_TOP = Anchor::TOP,
113 SPLIT_BOTTOM = Anchor::BOTTOM,
114 SPLIT_TOPLEFT = Anchor::TOPLEFT,
115 SPLIT_TOPRIGHT = Anchor::TOPRIGHT,
116 SPLIT_BOTTOMLEFT = Anchor::BOTTOMLEFT,
117 SPLIT_BOTTOMRIGHT = Anchor::BOTTOMRIGHT
118 };
119
120
122 inline constexpr BoxSplit operator|(BoxSplit a1, BoxSplit a2) { return ((BoxSplit)((int)a1 | (int)a2)); }
123
125 inline BoxSplit& operator|=(BoxSplit& a1, BoxSplit a2) { a1 = a1 | a2; return a1; }
126
128 inline constexpr BoxSplit operator&(BoxSplit a1, BoxSplit a2) { return ((BoxSplit)((int)a1 & (int)a2)); }
129
131 inline BoxSplit& operator&=(BoxSplit& a1, BoxSplit a2) { a1 = a1 & a2; return a1; }
132
133
134
135
150 template<typename T> struct Box2
151 {
152
153 // mtools extension (if available).
154 #if (MTOOLS_TGX_EXTENSIONS)
155 #include <mtools/extensions/tgx/tgx_ext_Box2.inl>
156 #endif
157
158
159 // box dimension: [minX, maxX] x [minY, maxY]
160
165
166
170 constexpr Box2()
171 {
172 }
173
174
178 constexpr Box2(const T minx, const T maxx, const T miny, const T maxy) : minX(minx), maxX(maxx), minY(miny), maxY(maxy)
179 {
180 }
181
182
186 constexpr Box2(const Vec2<T>& P) : minX(P.x), maxX(P.x), minY(P.y), maxY(P.y)
187 {
188 }
189
190
194 Box2(const Box2<T>& B) = default;
195
196
200 Box2<T>& operator=(const Box2<T>& B) = default;
201
202
206 template<typename U>
207 explicit operator Box2<U>() const { return Box2<U>((U)minX, (U)maxX, (U)minY, (U)maxY); }
208
209
213 operator Box2<typename DefaultFPType<T>::fptype>() const { return Box2<typename DefaultFPType<T>::fptype>((typename DefaultFPType<T>::fptype)minX, (typename DefaultFPType<T>::fptype)maxX, (typename DefaultFPType<T>::fptype)minY, (typename DefaultFPType<T>::fptype)maxY); }
214
215
219 constexpr inline bool isEmpty() const { return ((maxX < minX) || (maxY < minY)); }
220
221
225 void empty()
226 {
227 minX = (T)1;
228 maxX = (T)0;
229 minY = (T)1;
230 maxY = (T)0;
231 }
232
233
242 inline T lx() const
243 {
244 if (std::is_integral<T>::value) // compiler optimize this away.
245 {
246 return (maxX - minX + 1); // for integer, return the number of points
247 }
248 else
249 {
250 return (maxX - minX); // for floating point type, return maxX - minX.
251 }
252 }
253
254
263 inline T ly() const
264 {
265 if (std::is_integral<T>::value) // compiler optimize this away.
266 {
267 return (maxY - minY + 1); // for integer, return the number of points
268 }
269 else
270 {
271 return (maxY - minY); // for floating point type, return maxX - minX.
272 }
273 }
274
275
283 inline bool equals(const Box2<T>& B) const
284 {
285 if (isEmpty()) { return B.isEmpty(); }
286 return ((minX == B.minX) && (maxX == B.maxX) && (minY == B.minY) && (maxY == B.maxY));
287 }
288
289
297 inline bool operator==(const Box2<T>& B) const
298 {
299 return equals(B);
300 }
301
302
306 inline bool contains(const Vec2<T>& v) const
307 {
308 return(((minX <= v.x) && (v.x <= maxX)) && ((minY <= v.y) && (v.y <= maxY)));
309 }
310
311
319 inline bool contains(const Box2<T>& B) const
320 {
321 if (isEmpty()) return false;
322 if (B.isEmpty()) return true;
323 return ((minX <= B.minX) && (maxX >= B.maxX) && (minY <= B.minY) && (maxY >= B.maxY));
324 }
325
326
336 inline bool operator>=(const Box2<T>& B) const
337 {
338 return contains(B);
339 }
340
341
351 inline bool operator<=(const Box2<T>& B) const
352 {
353 return B.contains(*this);
354 }
355
356
364 inline bool operator>(const Box2<T>& B) const
365 {
366 return ((contains(B)) && (!equals(B)));
367 }
368
369
377 inline bool operator<(const Box2<T>& B) const
378 {
379 return ((B.contains(*this)) && (!B.equals(*this)));
380 }
381
382
386 inline Box2<T> operator&(const Box2<T>& B) const
387 {
388 Box2<T> R;
389 if (isEmpty())
390 {
391 R = *this;
392 }
393 else if (B.isEmpty())
394 {
395 R = B;
396 }
397 else
398 {
399 R.minX = max(minX, B.minX);
400 R.maxX = min(maxX, B.maxX);
401 R.minY = max(minY, B.minY);
402 R.maxY = min(maxY, B.maxY);
403 }
404 return R;
405 }
406
407
411 inline void operator&=(const Box2<T>& B)
412 {
413 (*this) = ((*this) & B);
414 }
415
416
420 inline Box2<T> operator|(const Box2<T>& B) const
421 {
422 Box2<T> R;
423 if (isEmpty())
424 {
425 R = B;
426 }
427 else if (B.isEmpty())
428 {
429 R = (*this);
430 }
431 else
432 {
433 R.minX = min(minX, B.minX);
434 R.maxX = max(maxX, B.maxX);
435 R.minY = min(minY, B.minY);
436 R.maxY = max(maxY, B.maxY);
437 }
438 return R;
439 }
440
441
445 inline void operator|=(const Box2<T>& B)
446 {
447 *this = (*this) | B;
448 }
449
450
454 inline Box2<T> operator|(const Vec2<T>& v) const
455 {
456 Box2<T> R;
457 if (isEmpty())
458 {
459 R.minX = R.maxX = v.x;
460 R.minY = R.maxY = v.y;
461 }
462 else
463 {
464 R.minX = min(minX, v.x);
465 R.maxX = max(maxX, v.x);
466 R.minY = min(minY, v.y);
467 R.maxY = max(maxY, v.y);
468 }
469 return R;
470 }
471
472
476 inline void operator|=(const Vec2<T>& v)
477 {
478 (*this) = (*this) | v;
479 }
480
481
485 inline void operator+=(const Vec2<T> & V)
486 {
487 minX += V.x;
488 maxX += V.x;
489 minY += V.y;
490 maxY += V.y;
491 }
492
493
497 inline Box2<T> operator+(const Vec2<T> & V) const
498 {
499 return Box2<T>(minX + V.x, maxX + V.x, minY + V.y, maxY + V.y);
500 }
501
502
506 inline void operator-=(const Vec2<T> & V)
507 {
508 minX -= V.x;
509 maxX -= V.x;
510 minY -= V.y;
511 maxY -= V.y;
512 }
513
514
518 inline Box2<T> operator-(const Vec2<T> & V) const
519 {
520 return Box2<T>(minX - V.x, maxX - V.x, minY - V.y, maxY - V.y);
521 }
522
523
534 inline void split_fixed(BoxSplit part)
535 {
536 *this = getSplit_fixed(part);
537 }
538
539
551 {
552 const T midX = minX + (maxX - minX)/2;
553 const T midY = minY + (maxY - minY)/2;
554 const T nextX = midX + (std::is_integral<T>::value ? (T)1 : (T)0);
555 const T nextY = midY + (std::is_integral<T>::value ? (T)1 : (T)0);
556 switch (part)
557 {
558 case SPLIT_TOP: { return Box2<T>(minX, maxX, minY, midY); }
559 case SPLIT_BOTTOM: { return Box2<T>(minX, maxX, nextY, maxY); }
560 case SPLIT_LEFT: { return Box2<T>(minX, midX, minY, maxY); }
561 case SPLIT_RIGHT: { return Box2<T>(nextX, maxX, minY, maxY); }
562 case SPLIT_TOPLEFT: { return Box2<T>(minX, midX, minY, midY); }
563 case SPLIT_TOPRIGHT: { return Box2<T>(nextX, maxX, minY, midY); }
564 case SPLIT_BOTTOMLEFT: { return Box2<T>(minX, midX, nextY, maxY); }
565 case SPLIT_BOTTOMRIGHT: { return Box2<T>(nextX, maxX, nextY, maxY); }
566 }
567 return *this;
568 }
569
570
576 Vec2<T> getAnchor(Anchor anchor_pos) const
577 {
578 anchor_pos &= (CENTER | LEFT | RIGHT | TOP | BOTTOM); // remove baseline flag
579 switch (anchor_pos)
580 {
581 case TOPLEFT: return Vec2<T>(minX, minY);
582 case TOPRIGHT: return Vec2<T>(maxX, minY);
583 case BOTTOMLEFT: return Vec2<T>(minX, maxY);
584 case BOTTOMRIGHT: return Vec2<T>(maxX, maxY);
585 case CENTER: return Vec2<T>((minX + maxX) / 2, (minY + maxY) / 2);
586 case CENTERLEFT: return Vec2<T>(minX, (minY + maxY) / 2);
587 case CENTERRIGHT: return Vec2<T>(maxX, (minY + maxY) / 2);
588 case CENTERTOP: return Vec2<T>((minX + maxX) / 2, minY);
589 case CENTERBOTTOM: return Vec2<T>((minX + maxX) / 2, maxY);
590 default: break;
591 }
592 return Vec2<T>((minX + maxX) / 2, (minY + maxY) / 2); // unknown pos returns center.
593 }
594
595
600 {
601 return Vec2<T>((minX + maxX) / 2, (minY + maxY) / 2);
602 }
603
604
613 template<typename Tfloat = typename DefaultFPType<T>::fptype> inline Tfloat ratio() const
614 {
615 if (isEmpty()) return (Tfloat)(-1);
616 return ((Tfloat)(lx())) / ((Tfloat)(ly()));
617 }
618
619
625 void zoomOut()
626 {
627 const T u = lx() / 10;
628 minX -= u;
629 maxX += u;
630 const T v = ly() / 10;
631 minY -= v;
632 maxY += v;
633 }
634
635
641 void zoomIn()
642 {
643 const T u = lx() / 8;
644 minX += u;
645 maxX -= u;
646 const T v = ly() / 8;
647 minY += v;
648 maxY -= v;
649 }
650
651
657 void left()
658 {
659 const T u = lx() / 10;
660 minX -= u;
661 maxX -= u;
662 }
663
664
670 void right()
671 {
672 const T u = lx() / 10;
673 minX += u;
674 maxX += u;
675 }
676
677
683 void up()
684 {
685 const T v = ly() / 10;
686 minY -= v;
687 maxY -= v;
688 }
689
690
696 void down()
697 {
698 const T v = ly() / 10;
699 minY += v;
700 maxY += v;
701 }
702
703
713
714
724
725
726 };
727
728
729
730
731
732 template<typename T> Box2<T> Box2<T>::getEnclosedWithSameRatioAs_fixed(const Box2<T> & B) const
733 {
734 Box2<T> C;
735 C.empty();
736 if (isEmpty() || B.isEmpty()) return C;
737
738 typedef typename DefaultFPType<T>::fptype Tfloat;
739 const Tfloat target_ratio = B.template ratio<Tfloat>();
740 if (target_ratio <= (Tfloat)0) return C;
741
742 Tfloat llx = (Tfloat)lx();
743 Tfloat lly = (Tfloat)ly();
744 if (ratio<Tfloat>() < target_ratio)
745 {
746 lly = llx / target_ratio;
747 }
748 else
749 {
750 llx = lly * target_ratio;
751 }
752
753 if (std::is_integral<T>::value)
754 {
755 T ilx = (T)floor(llx);
756 T ily = (T)floor(lly);
757 if (ilx < (T)1) ilx = (T)1;
758 if (ily < (T)1) ily = (T)1;
759 if (ilx > lx()) ilx = lx();
760 if (ily > ly()) ily = ly();
761 C.minX = minX + (lx() - ilx) / 2;
762 C.minY = minY + (ly() - ily) / 2;
763 C.maxX = C.minX + ilx - 1;
764 C.maxY = C.minY + ily - 1;
765 }
766 else
767 {
768 const Tfloat cx = ((Tfloat)minX + (Tfloat)maxX) / (Tfloat)2;
769 const Tfloat cy = ((Tfloat)minY + (Tfloat)maxY) / (Tfloat)2;
770 C.minX = (T)(cx - llx / (Tfloat)2);
771 C.maxX = (T)(cx + llx / (Tfloat)2);
772 C.minY = (T)(cy - lly / (Tfloat)2);
773 C.maxY = (T)(cy + lly / (Tfloat)2);
774 }
775 return C;
776 }
777
778
779 template<typename T> Box2<T> Box2<T>::getEnclosingWithSameRatioAs_fixed(const Box2<T> & B) const
780 {
781 Box2<T> C;
782 C.empty();
783 if (isEmpty() || B.isEmpty()) return C;
784
785 typedef typename DefaultFPType<T>::fptype Tfloat;
786 const Tfloat target_ratio = B.template ratio<Tfloat>();
787 if (target_ratio <= (Tfloat)0) return C;
788
789 Tfloat llx = (Tfloat)lx();
790 Tfloat lly = (Tfloat)ly();
791 if (ratio<Tfloat>() > target_ratio)
792 {
793 lly = llx / target_ratio;
794 }
795 else
796 {
797 llx = lly * target_ratio;
798 }
799
800 if (std::is_integral<T>::value)
801 {
802 T ilx = (T)ceil(llx);
803 T ily = (T)ceil(lly);
804 if (ilx < lx()) ilx = lx();
805 if (ily < ly()) ily = ly();
806 C.minX = minX - (ilx - lx()) / 2;
807 C.minY = minY - (ily - ly()) / 2;
808 C.maxX = C.minX + ilx - 1;
809 C.maxY = C.minY + ily - 1;
810 }
811 else
812 {
813 const Tfloat cx = ((Tfloat)minX + (Tfloat)maxX) / (Tfloat)2;
814 const Tfloat cy = ((Tfloat)minY + (Tfloat)maxY) / (Tfloat)2;
815 C.minX = (T)(cx - llx / (Tfloat)2);
816 C.maxX = (T)(cx + llx / (Tfloat)2);
817 C.minY = (T)(cy - lly / (Tfloat)2);
818 C.maxY = (T)(cy + lly / (Tfloat)2);
819 }
820 return C;
821 }
822
823
824}
825
826
827#endif
828
829#endif
830
Anchor & operator|=(Anchor &a1, Anchor a2)
Enable bitwise |= operator for enum Anchor.
Definition: Box2.h:97
constexpr Anchor operator|(Anchor a1, Anchor a2)
Enable bitwise | operator for enum Anchor.
Definition: Box2.h:94
constexpr Anchor operator&(Anchor a1, Anchor a2)
Enable bitwise & operator for enum Anchor.
Definition: Box2.h:100
BoxSplit
Splitting of a box in half and quarters.
Definition: Box2.h:109
@ SPLIT_RIGHT
right half
Definition: Box2.h:111
@ SPLIT_BOTTOMRIGHT
bottom right quarter
Definition: Box2.h:117
@ SPLIT_BOTTOM
bottom half
Definition: Box2.h:113
@ SPLIT_TOPRIGHT
top right quarter
Definition: Box2.h:115
@ SPLIT_BOTTOMLEFT
bottom left quarter
Definition: Box2.h:116
@ SPLIT_LEFT
left half
Definition: Box2.h:110
@ SPLIT_TOPLEFT
top left quarter
Definition: Box2.h:114
@ SPLIT_TOP
top half
Definition: Box2.h:112
Anchor & operator&=(Anchor &a1, Anchor a2)
Enable bitwise &= operator for enum Anchor.
Definition: Box2.h:103
Anchor
Define the placement of an anchor point inside a box.
Definition: Box2.h:74
@ BASELINE
Baseline height (vertical alignment). only makes sense with a font (when drawing text),...
Definition: Box2.h:80
@ BOTTOMRIGHT
Bottom-right corner.
Definition: Box2.h:84
@ CENTERRIGHT
center point on the right side
Definition: Box2.h:86
@ TOPLEFT
Top-left corner.
Definition: Box2.h:81
@ TOPRIGHT
Top-right corner.
Definition: Box2.h:82
@ CENTERLEFT
center point on the left side
Definition: Box2.h:85
@ BOTTOM
Bottom side (vertical alignment)
Definition: Box2.h:79
@ CENTER
Center (vertical/horizontal alignment). This is the default placement if not specified.
Definition: Box2.h:75
@ RIGHT
Right side (horizontal alignment)
Definition: Box2.h:77
@ CENTERBOTTOM
center point on the bottom side
Definition: Box2.h:88
@ BOTTOMLEFT
bottom-left corner
Definition: Box2.h:83
@ CENTERTOP
center point on the top side
Definition: Box2.h:87
@ DEFAULT_TEXT_ANCHOR
Default location for text anchoring.
Definition: Box2.h:89
@ TOP
Top side (vertical alignment)
Definition: Box2.h:78
@ LEFT
Left side (horizontal alignment)
Definition: Box2.h:76
Utility/miscellaneous functions used throughout the library.
TGX_INLINE T min(const T &a, const T &b)
Don't know why but faster than fminf() for floats.
Definition: Misc.h:132
TGX_INLINE T max(const T &a, const T &b)
Don't know why but much faster than fmaxf() for floats.
Definition: Misc.h:136
2D vector.
Generic 2D Box [specializations iBox2 , fBox2, dBox2].
Definition: Box2.h:151
bool equals(const Box2< T > &B) const
Return true if the boxes are equal.
Definition: Box2.h:283
Box2(const Box2< T > &B)=default
default copy constructor.
Box2< T > operator&(const Box2< T > &B) const
Return the intersection of this box and B.
Definition: Box2.h:386
T maxY
max vertical (Y) value (inclusive)
Definition: Box2.h:164
constexpr Box2()
default constructor: the box content is undefined.
Definition: Box2.h:170
bool operator==(const Box2< T > &B) const
Return true if the boxes are equal.
Definition: Box2.h:297
constexpr Box2(const T minx, const T maxx, const T miny, const T maxy)
Constructor with explicit dimensions.
Definition: Box2.h:178
Box2< T > operator+(const Vec2< T > &V) const
Return this box translated by vector v.
Definition: Box2.h:497
void split_fixed(BoxSplit part)
Split the box in half or quarter.
Definition: Box2.h:534
void operator-=(const Vec2< T > &V)
Translate the box by a given vector (substracted)
Definition: Box2.h:506
void left()
Move the box to the left by 1/10th of its width.
Definition: Box2.h:657
void down()
Move the box down by 1/10th of its height.
Definition: Box2.h:696
Vec2< T > getAnchor(Anchor anchor_pos) const
Return the position of an anchor point inside this box.
Definition: Box2.h:576
void up()
Move the box up by 1/10th of its height.
Definition: Box2.h:683
Box2< T > operator-(const Vec2< T > &V) const
Return this box translated by v (substracted).
Definition: Box2.h:518
bool operator>(const Box2< T > &B) const
Return true if B is strictly included in this box (i.e.
Definition: Box2.h:364
T ly() const
Return the box height.
Definition: Box2.h:263
Tfloat ratio() const
Return the aspect ratio of the box lx()/ly().
Definition: Box2.h:613
bool operator<(const Box2< T > &B) const
Return true if this box is strictly included inside B (i.e.
Definition: Box2.h:377
bool operator>=(const Box2< T > &B) const
Return true if B is included in this box.
Definition: Box2.h:336
bool operator<=(const Box2< T > &B) const
Return true if this box is included in B.
Definition: Box2.h:351
void zoomOut()
Zoom outside the box (ie increase its size by 1/10th).
Definition: Box2.h:625
T maxX
max horizontal (X) value (inclusive)
Definition: Box2.h:162
Box2< T > getEnclosedWithSameRatioAs_fixed(const Box2< T > &B) const
Return the largest box with the same ratio() as box B that is centered and enclosed inside this box.
Definition: Box2.h:732
void empty()
Make the box empty.
Definition: Box2.h:225
constexpr bool isEmpty() const
Return true if the box is empty.
Definition: Box2.h:219
T lx() const
Return the box width.
Definition: Box2.h:242
T minX
min horizontal (X) value (inclusive)
Definition: Box2.h:161
Vec2< T > center() const
Return the position of the box center as a 2 dimensional vector.
Definition: Box2.h:599
bool contains(const Vec2< T > &v) const
Return true if the box contains the point v.
Definition: Box2.h:306
Box2< T > operator|(const Vec2< T > &v) const
Return the smallest box containing this box and point v.
Definition: Box2.h:454
Box2< T > operator|(const Box2< T > &B) const
Return the smallest box containing both this box and B.
Definition: Box2.h:420
void operator|=(const Vec2< T > &v)
Enlarge this box in order to contain point v.
Definition: Box2.h:476
Box2< T > getEnclosingWithSameRatioAs_fixed(const Box2< T > &B) const
Return the smallest box with the same ratio() as box B that contains this box in its center.
Definition: Box2.h:779
bool contains(const Box2< T > &B) const
Return true if B is included in this box.
Definition: Box2.h:319
void right()
Move the box to the right by 1/10th of its width.
Definition: Box2.h:670
Box2< T > getSplit_fixed(BoxSplit part) const
Return the box splitted in half or quater.
Definition: Box2.h:550
void operator+=(const Vec2< T > &V)
Translate this box by a given vector.
Definition: Box2.h:485
Box2< T > & operator=(const Box2< T > &B)=default
default assignment operator.
void zoomIn()
Zoom inside the box (ie decrease its size by 1/8th).
Definition: Box2.h:641
void operator|=(const Box2< T > &B)
Enlarge this box in order to contain B.
Definition: Box2.h:445
T minY
min vertical (Y) value (inclusive)
Definition: Box2.h:163
constexpr Box2(const Vec2< T > &P)
Construct a box representing a single point.
Definition: Box2.h:186
void operator&=(const Box2< T > &B)
Intersect this box with box B.
Definition: Box2.h:411
Generic 2D vector [specializations iVec2, fVec2, dVec2].
Definition: Vec2.h:64
T x
'x' coordinate (first dimension)
Definition: Vec2.h:72
T y
'y' coordinate (second dimension)
Definition: Vec2.h:73