47 public sequence_type < NUMBER, 4 >
60 using UNIT_TYPE = NUMBER;
61 using POINT_TYPE = point_type < NUMBER >;
62 using SIZE_TYPE = size_type < NUMBER >;
69 template < prototype_number LEFT, prototype_number TOP, prototype_number RIGHT, prototype_number BOTTOM >
70 rectangle_type(LEFT left, TOP top, RIGHT right, BOTTOM bottom) :
71 sequence_type < NUMBER, 4 >((NUMBER) left, (NUMBER) top, (NUMBER) right, (NUMBER) bottom)
75 template < prototype_number A, prototype_number B >
76 rectangle_type(
api_change_t, A a, B b) : rectangle_type(0, 0, a, b) {}
78 template < prototype_number N >
79 rectangle_type(
api_change_t, N n) : rectangle_type(n, n) {}
88 template < prototype_po
int POINT, prototype_size SIZE >
89 rectangle_type(
const POINT & point,
const SIZE & size) :
90 rectangle_type((UNIT_TYPE)point.x, (UNIT_TYPE)point.y, (UNIT_TYPE)(point.x + size.cx), (UNIT_TYPE)(point.y + size.cy))
93 template < prototype_size SIZE >
94 rectangle_type(
const SIZE & size) : rectangle_type(0, 0, size.cx, size.cy) {}
95 template < prototype_po
int POINT1, prototype_po
int POINT2 >
96 rectangle_type(
const POINT1 & point1,
const POINT2 & point2) { top_left() = point1; bottom_right() = point2; }
97 template < prototype_rectangle RECTANGLE >
98 rectangle_type(
const RECTANGLE & t) :
99 sequence_type < NUMBER, 4 >(t)
108 template < struct_rectangle RECTANGLE >
109 rectangle_type(
const RECTANGLE & r) :
110 sequence_type < NUMBER, 4 >(r.left, r.top, r.right, r.bottom)
113 template < rectangle_source RECTANGLE_SOURCE >
114 rectangle_type(RECTANGLE_SOURCE * prectanglesource) :
115 rectangle_type(prectanglesource->rectangle_source_get())
138 template < prototype_origin_size ORIGIN_SIZE >
139 rectangle_type(
const ORIGIN_SIZE & originsize)
142 this->left = (UNIT_TYPE) originsize.origin.x;
143 this->top = (UNIT_TYPE) originsize.origin.y;
144 this->right = (UNIT_TYPE) (originsize.origin.x + originsize.size.width);
145 this->bottom = (UNIT_TYPE) (originsize.origin.y + originsize.size.height);
151 template < prototype_number NUMBER2 >
155 this->left = (UNIT_TYPE) originsize.origin.x;
156 this->top = (UNIT_TYPE) originsize.origin.y;
157 this->right = (UNIT_TYPE) (originsize.origin.x + originsize.size.cx);
158 this->bottom = (UNIT_TYPE) (originsize.origin.y + originsize.size.cy);
180 auto & origin() {
return top_left(); }
181 const auto & origin()
const {
return top_left(); }
182 const auto & bottom_right()
const {
return ((rectangle_type *)
this)->bottom_right(); }
183 const auto & top_left()
const {
return ((rectangle_type *)
this)->top_left(); }
184 UNIT_TYPE center_x()
const {
return (this->left + this->right) / (UNIT_TYPE)2; }
185 UNIT_TYPE center_y()
const {
return (this->top + this->bottom) / (UNIT_TYPE)2; }
186 POINT_TYPE center()
const {
return POINT_TYPE(center_x(), center_y()); }
189 inline bool is_set()
const {
return !is_empty(); }
190 inline bool is_empty()
const { return ::is_empty(*
this); }
191 inline bool is_null()
const { return ::is_null(*
this); }
192 inline bool is_null_or_positive ()
const {
return this->width() >= 0 && this->height() >= 0;}
193 inline bool is_ok()
const {
return is_null_or_positive(); }
194 inline bool has_area()
const {
return !is_empty(); }
195 template < prototype_po
int POINT >
196 inline bool contains(
const POINT & point)
const { return ::contains(*
this, point.x, point.y); }
197 inline bool contains_x(UNIT_TYPE x)
const { return ::contains_x(*
this, x); }
198 inline bool contains_y(UNIT_TYPE y)
const { return ::contains_y(*
this, y); }
201 template <
typename SIZE >
202 rectangle_type & ensure_at_least(
const SIZE & size)
205 this->right = (UNIT_TYPE)::maximum(this->right, this->left + size.cx);
206 this->bottom = (UNIT_TYPE)::maximum(this->bottom, this->top + size.cy);
213 template < prototype_po
int POINT >
214 inline ::f64_point to_point_rate(
const POINT & point)
const
217 return { ((::f64)point.x - (::f64)this->left) / (::f64)width(),
218 ((::f64)point.y - (::f64)this->top) / (::f64)height() };
223 inline UNIT_TYPE x_rate(::f64 xRate)
const
226 return (UNIT_TYPE)(xRate * (::f64)width() + (::f64)this->left);
231 inline UNIT_TYPE y_rate(::f64 yRate)
const
234 return (UNIT_TYPE)(yRate * (::f64)height() + (::f64)this->top);
240 inline POINT_TYPE from_point_rate(const ::f64_point & point)
const
243 return POINT_TYPE(x_rate(point.x), y_rate(point.y));
248 inline POINT_TYPE top_right()
const {
return POINT_TYPE(this->right, this->top); }
249 inline POINT_TYPE bottom_left()
const {
return POINT_TYPE(this->left, this->bottom); }
254 UNIT_TYPE minimum_dimension()
const { return ::minimum(width(), height()); }
255 UNIT_TYPE maximum_dimension()
const { return ::maximum(width(), height()); }
257 UNIT_TYPE max_border()
const { return ::maximum(::maximum(this->top, this->left), ::maximum(this->bottom, this->right)); }
259 UNIT_TYPE minimum_natural_dimension()
const { return ::minimum(::maximum((UNIT_TYPE)0, width()), ::maximum((UNIT_TYPE)0, height())); }
260 UNIT_TYPE maximum_natural_dimension()
const { return ::maximum(::maximum((UNIT_TYPE)0, width()), ::maximum((UNIT_TYPE)0, height())); }
262 UNIT_TYPE minimum_absolute_dimension()
const { return ::minimum(abs(width()), abs(height())); }
263 UNIT_TYPE maximum_absolute_dimension()
const { return ::minimum(abs(width()), abs(height())); }
268 UNIT_TYPE get_dimension(enum_orientation eorientation, ::collection::index i)
271 return eorientation == e_orientation_horizontal ? (i == 0 ? this->left : this->right)
272 : (i == 0 ? this->top : this->bottom);
276 UNIT_TYPE get_normal_dimension(enum_orientation eorientation, ::collection::index i)
279 return eorientation == e_orientation_vertical ? (i == 0 ? this->left : this->right)
280 : (i == 0 ? this->top : this->bottom);
284 UNIT_TYPE get_first_dimension(enum_orientation eorientation)
287 return eorientation == e_orientation_horizontal ? (this->left) : (this->top);
291 UNIT_TYPE get_first_normal_dimension(enum_orientation eorientation)
294 return eorientation == e_orientation_vertical ? (this->right) : (this->bottom);
298 UNIT_TYPE get_second_dimension(enum_orientation eorientation)
301 return eorientation == e_orientation_horizontal ? (this->right) : (this->bottom);
305 UNIT_TYPE get_second_normal_dimension(enum_orientation eorientation)
308 return eorientation == e_orientation_vertical ? (this->right) : (this->bottom);
312 UNIT_TYPE get_total_dimension(enum_orientation eorientation)
315 return eorientation == e_orientation_horizontal ? this->left + this->right : this->top + this->bottom;
319 UNIT_TYPE get_normal_total_dimension(enum_orientation eorientation)
322 return eorientation == e_orientation_vertical ? this->left + this->right : this->top + this->bottom;
327 UNIT_TYPE width()
const {
return this->right - this->left; }
328 UNIT_TYPE height()
const {
return this->bottom - this->top; }
329 SIZE_TYPE size()
const {
return SIZE_TYPE(width(), height()); }
330 SIZE_TYPE radius()
const {
return this->size() / ((UNIT_TYPE) 2); }
332 void set_width(UNIT_TYPE cx) { this->right = this->left + cx; }
333 void set_height(UNIT_TYPE cy) { this->bottom = this->top + cy; }
334 void set_size(UNIT_TYPE cx, UNIT_TYPE cy) { set_width(cx); set_height(cy); }
335 void set_size(
const SIZE_TYPE & size) { set_size(size.cx, size.cy); }
336 void set_top_left(UNIT_TYPE leftNew, UNIT_TYPE topNew)
338 auto offsetX = leftNew - this->left;
339 auto offsetY = topNew - this->top;
340 this->left = leftNew;
341 this->right += offsetX;
343 this->bottom += offsetY;
345 void set_top_left(
const POINT_TYPE & point) {this->set_top_left(point.x, point.y);}
346 rectangle_type & set_center_and_half_size(
const POINT_TYPE & center,
const SIZE_TYPE & halfsize)
349 *
this = with_center_and_half_size(center, halfsize);
357 rectangle_type & set_square_with_center(
const POINT_TYPE & center,
const UNIT_TYPE & apothem)
360 *
this = square_with_center_and_apothem(center, apothem);
368 static rectangle_type with_center_and_half_size(
const POINT_TYPE & center,
const SIZE_TYPE & halfsize)
372 center.x - halfsize.cx,
373 center.y - halfsize.cy,
374 center.x+ halfsize.cx,
375 center.y+ halfsize.cx
380 static rectangle_type square_with_center_and_apothem(
const POINT_TYPE & center,
const UNIT_TYPE & apothem)
383 return with_center_and_half_size(center, {apothem, apothem});
388 rectangle_type & move_top_to(UNIT_TYPE top) { this->bottom = height() + top; this->top = top;
return *
this; }
389 rectangle_type & move_left_to(UNIT_TYPE left) { this->right = width() + left; this->left = left;
return *
this; }
391 rectangle_type & move_right_to(UNIT_TYPE right) { this->left = right - width(); this->right = right;
return *
this; }
392 rectangle_type & move_bottom_to(UNIT_TYPE bottom) { this->top = bottom - height(); this->bottom = bottom;
return *
this; }
394 rectangle_type & move_to(UNIT_TYPE left, UNIT_TYPE top) { move_left_to(left);
return move_top_to(top);
return *
this; }
395 rectangle_type & move_to(
const POINT_TYPE & point) {
return move_to(point.x, point.y); }
397 POINT_TYPE & top_left() {
return *((POINT_TYPE *)
this); }
398 POINT_TYPE & bottom_right() {
return *((POINT_TYPE *)
this + 1); }
399 void swap_left_right() { ::swap_left_right(*
this); }
404 explicit operator bool()
const {
return is_set(); }
405 bool operator !()
const {
return is_empty(); }
407 rectangle_type & set(UNIT_TYPE i) { return ::assign(*
this, i, i, i, i); }
408 rectangle_type & set(UNIT_TYPE x, UNIT_TYPE y) { return ::assign(*
this, x, y, x, y); }
409 rectangle_type & set(UNIT_TYPE l, UNIT_TYPE t, UNIT_TYPE r, UNIT_TYPE b) { return ::assign(*
this, l, t, r, b); }
410 template < prototype_size SIZE >
411 rectangle_type & set(
const SIZE & s) { return ::assign(*
this, POINT_TYPE(), s); }
412 template < prototype_po
int POINT1, prototype_po
int POINT2 >
413 rectangle_type & set(
const POINT1 & p1,
const POINT2 & p2) { return ::assign(*
this, p1.x, p1.y, p2.x, p2.y); }
414 template < prototype_po
int POINT, prototype_size SIZE >
415 rectangle_type & set(
const POINT & p,
const SIZE & s) { return ::assign(*
this, p, s); }
416 template < prototype_rectangle RECTANGLE >
417 rectangle_type & set(
const RECTANGLE & rectangle)
419 return set(rectangle.left, rectangle.top, rectangle.right, rectangle.bottom);
422 rectangle_type & set_dimension(UNIT_TYPE l, UNIT_TYPE t, UNIT_TYPE w, UNIT_TYPE h)
424 this->left = (UNIT_TYPE) l;
425 this->top = (UNIT_TYPE) t;
426 this->right = (UNIT_TYPE) (l + w);
427 this->bottom = (UNIT_TYPE) (t + h);
431 rectangle_type & clear() { return ::clear(*
this); }
433 bool is_equal(
const rectangle_type & rectangle)
const
435 return this->left == rectangle.left
436 && this->top == rectangle.top
437 && this->right == rectangle.right
438 && this->bottom == rectangle.bottom;
442 template < prototype_number NUMBERX, prototype_number NUMBERY >
443 rectangle_type & inflate(NUMBERX x, NUMBERY y) { this->left = (UNIT_TYPE) (this->left - x); this->right = (UNIT_TYPE) (this->right + x); this->top = (UNIT_TYPE)(this->top - y); this->bottom = (UNIT_TYPE)(this->bottom + y);
return *
this; }
444 template < prototype_size SIZE >
445 rectangle_type & inflate(
const SIZE & size) {
return inflate(size.cx, size.cy); }
446 template < prototype_number NUMBERX, prototype_number NUMBERY >
447 rectangle_type & deflate(NUMBERX x, NUMBERY y) {
return inflate(-x, -y); }
448 template < prototype_size SIZE >
449 rectangle_type & deflate(
const SIZE & size) {
return deflate(size.cx, size.cy); }
451 template < prototype_number NUMBERX, prototype_number NUMBERY >
452 rectangle_type & offset(NUMBERX x, NUMBERY y) {
return offset_x(x).offset_y(y); }
454 template < prototype_number NUMBERX >
455 rectangle_type & offset_x(NUMBERX x) { this->left = (UNIT_TYPE) (this->left + x); this->right = (UNIT_TYPE) (this->right + x);
return *
this; }
456 template < prototype_number NUMBERY >
457 rectangle_type & offset_y(NUMBERY y) { this->top = (UNIT_TYPE) (this->top + y); this->bottom = (UNIT_TYPE) (this->bottom + y);
return *
this; }
458 template < prototype_number NUMBERN >
459 rectangle_type & inflate(NUMBERN n) {
return inflate(n, n); }
460 template < prototype_number NUMBERN >
461 rectangle_type & deflate(NUMBERN n) {
return deflate(n, n); }
463 template < prototype_number NUMBERN >
464 rectangle_type & offset(
const sequence_type < NUMBERN, 2 > & s) {
return offset_x(s.x).offset_y(s.y); }
472 bool x_intersects(
const rectangle_type & rectangle)
const { return ::x_intersects(*
this, rectangle); }
473 bool y_intersects(
const rectangle_type & rectangle)
const { return ::y_intersects(*
this, rectangle); }
474 bool intersects(
const rectangle_type & rectangle)
const { return ::intersects(*
this, rectangle); }
476 bool intersect_x(
const rectangle_type & rect1,
const rectangle_type & rect2) { return ::x_intersect(*
this, rect1, rect2); }
477 bool intersect_y(
const rectangle_type & rect1,
const rectangle_type & rect2) { return ::y_intersect(*
this, rect1, rect2); }
478 bool intersect(
const rectangle_type & rect1,
const rectangle_type & rect2) { return ::intersect(*
this, rect1, rect2); }
480 rectangle_type & intersect(
const rectangle_type & rectangle) { ::intersect(*
this, *
this, rectangle);
return *
this; }
482 rectangle_type & constrain_to(
const rectangle_type & rectangle) {
return intersect(rectangle); }
485 inline rectangle_type & constrain(rectangle_type & rectangle)
const
488 if (rectangle.left < this->left)
489 rectangle.left = this->left;
491 if (rectangle.right < this->right)
492 rectangle.right = this->right;
494 if (rectangle.top < this->top)
495 rectangle.top = this->top;
497 if (rectangle.bottom < this->bottom)
498 rectangle.bottom = this->bottom;
505 rectangle_type intersection(
const rectangle_type & rect1)
const
508 rectangle_type rectangle;
510 ::intersect(rectangle, *
this, rect1);
517 rectangle_type outside_of(
const rectangle_type& rect1)
const
520 rectangle_type rectangle;
522 rectangle.top = maximum((NUMBER)0, rect1.top - this->top);
523 rectangle.bottom = maximum((NUMBER)0, this->bottom - rect1.bottom);
524 rectangle.left = maximum((NUMBER)0, rect1.left - this->left);
525 rectangle.bottom = maximum((NUMBER)0, this->right - rect1.right);
532 bool null_intersect(
const rectangle_type & rect1,
const rectangle_type & rect2) { return ::null_intersect(*
this, rect1, rect2); }
533 bool top_left_null_intersect(
const rectangle_type & rect1,
const rectangle_type & rect2) { return ::top_left_null_intersect(*
this, rect1, rect2); }
535 rectangle_type & unite(
const rectangle_type & rectangle1,
const rectangle_type & rectangle2)
538 if (rectangle1.is_empty())
541 if (rectangle2.is_empty())
550 this->operator=(rectangle2);
555 else if (rectangle2.is_empty())
558 this->operator= (rectangle1);
564 this->operator = (rectangle1);
566 rectangle2.expand_bounding_box(this->top_left(), this->bottom_right());
575 rectangle_type & unite(
const rectangle_type & rectangle)
578 if (this->is_empty())
581 if (rectangle.is_empty())
590 this->operator=(rectangle);
595 else if (rectangle.is_set())
598 rectangle.expand_bounding_box(this->top_left(), this->bottom_right());
606 rectangle_type get_union(
const rectangle_type & rect1)
const { rectangle_type rectangle(*
this); rectangle.unite(rect1);
return *
this; }
608 rectangle_type left_difference(
const rectangle_type& rectangle)
const {
return { this->left, ::maximum(this->top, rectangle.top), rectangle.left, ::minimum(this->bottom, rectangle.bottom) }; }
609 rectangle_type top_difference(
const rectangle_type& rectangle)
const {
return { ::maximum(this->left, rectangle.left), this->top, ::minimum(this->right, rectangle.right), rectangle.top }; }
610 rectangle_type right_difference(
const rectangle_type& rectangle)
const {
return { this->right, ::maximum(this->top, rectangle.top), rectangle.right, ::minimum(this->bottom, rectangle.bottom) }; }
611 rectangle_type bottom_difference(
const rectangle_type& rectangle)
const {
return { ::maximum(this->left, rectangle.left), this->bottom, ::minimum(this->right, rectangle.right), rectangle.bottom }; }
613 rectangle_type left_plus_difference(
const rectangle_type& rectangle)
const {
return { this->left, ::minimum(this->top, rectangle.top), rectangle.left,::maximum(this->bottom, rectangle.bottom) }; }
614 rectangle_type top_plus_difference(
const rectangle_type& rectangle)
const {
return { ::minimum(this->left, rectangle.left), this->top, ::maximum(this->right, rectangle.right), rectangle.top }; }
615 rectangle_type right_plus_difference(
const rectangle_type& rectangle)
const {
return { this->right, ::minimum(this->top, rectangle.top), rectangle.right, ::maximum(this->bottom, rectangle.bottom) }; }
616 rectangle_type bottom_plus_difference(
const rectangle_type& rectangle)
const {
return { ::minimum(this->left, rectangle.left), this->bottom, ::maximum(this->right, rectangle.right), rectangle.bottom }; }
618 rectangle_type & operator =(
const rectangle_type & rectangle) =
default;
653 bool operator==(
const rectangle_type & rectangle)
const
656 return ::is_equal(*
this, rectangle);
660 template < prototype_
integral INTEGRAL >
661 constexpr bool operator <(INTEGRAL i)
const
664 return i == 0 ? !this->is_null_or_positive() : this->area() < i;
669 template < prototype_sequence2 SEQUENCE >
670 rectangle_type & operator +=(
const SEQUENCE & s) { return ::offset(*
this, s.x, s.y); }
675 rectangle_type & operator +=(
const rectangle_type & rectangle) { return ::inflate(*
this, rectangle); }
676 rectangle_type & operator*=(
const rectangle_type & rectangle) { return ::multiply_inline(*
this, rectangle); }
678 template < prototype_number NUMBER2 >
679 rectangle_type & operator*=(NUMBER2 n)
682 this->left = (UNIT_TYPE) (this->left * n);
683 this->top = (UNIT_TYPE)(this->top * n);
684 this->right = (UNIT_TYPE)(this->right * n);
685 this->bottom = (UNIT_TYPE)(this->bottom * n);
703 template < prototype_number NUMBERN >
704 rectangle_type & operator-=(
const sequence_type< NUMBERN, 2> & s) { return ::subtract(*
this, s.x, s.y); }
708 rectangle_type & operator-=(
const rectangle_type & rectangle) { return ::subtract(*
this, rectangle); }
710 rectangle_type & operator&=(
const rectangle_type & rectangle) { ::intersect(*
this, *
this, rectangle);
return*
this; }
711 rectangle_type & operator|=(
const rectangle_type & rectangle) {
return unite(rectangle); }
713 template < prototype_sequence2 SEQUENCE >
714 rectangle_type operator +(
const SEQUENCE & s)
const
716 rectangle_type rectangle(*
this); rectangle.offset(s.x, s.y);
return rectangle;
731 template < prototype_sequence2 SEQUENCE >
732 rectangle_type operator-(
const SEQUENCE & s)
const
735 rectangle_type rectangle(*
this); rectangle.offset(-s.cx, -s.cy);
return rectangle;
739 rectangle_type operator +(
const rectangle_type & rectangleAdd)
const
741 rectangle_type rectangle(*
this); rectangle.inflate(rectangleAdd);
return rectangle;
743 rectangle_type operator-(
const rectangle_type & rectangleSub)
const
746 rectangle_type rectangle(*
this); rectangle.deflate(rectangleSub);
return rectangle;
748 rectangle_type operator&(
const rectangle_type & rect2)
const
750 rectangle_type rectangle; ::intersect(rectangle, *
this, rect2);
753 rectangle_type operator|(
const rectangle_type & rectangleOr)
const
755 rectangle_type rectangle;
756 rectangle.unite(*
this, rectangleOr);
761 rectangle_type & subtract(
const rectangle_type & rectangleSrc1,
const rectangle_type & rectangleSrc2)
764 return ::subtract(*
this, rectangleSrc1, rectangleSrc2);
770 template < prototype_rectangle RECTANGLE >
771 void inflate(
const RECTANGLE & rectangle)
774 this->left = (UNIT_TYPE)(this->left - rectangle.left);
775 this->top = (UNIT_TYPE)(this->top - rectangle.top);
776 this->right = (UNIT_TYPE)(this->right + rectangle.right);
777 this->bottom = (UNIT_TYPE)(this->bottom + rectangle.bottom);
781 void inflate(UNIT_TYPE l, UNIT_TYPE t, UNIT_TYPE r, UNIT_TYPE b) {
782 this->left = (UNIT_TYPE)(this->left - l);
783 this->top = (UNIT_TYPE)(this->top - t);
784 this->right = (UNIT_TYPE)(this->right + r);
785 this->bottom = (UNIT_TYPE)(this->bottom + b);
789 template < prototype_rectangle RECTANGLE >
790 void deflate(
const RECTANGLE & rectangle)
793 this->left = (UNIT_TYPE)(this->left + rectangle.left);
794 this->top = (UNIT_TYPE)(this->top + rectangle.top);
795 this->right = (UNIT_TYPE)(this->right - rectangle.right);
796 this->bottom = (UNIT_TYPE)(this->bottom - rectangle.bottom);
800 void deflate(UNIT_TYPE l, UNIT_TYPE t, UNIT_TYPE r, UNIT_TYPE b)
802 this->left = (UNIT_TYPE)(this->left + l);
803 this->top = (UNIT_TYPE)(this->top + t);
804 this->right = (UNIT_TYPE)(this->right - r);
805 this->bottom = (UNIT_TYPE)(this->bottom - b);
810 UNIT_TYPE area()
const
813 return size().area();
825 POINT_TYPE point = center();
827 UNIT_TYPE w = (UNIT_TYPE)(d * width());
829 UNIT_TYPE h = (UNIT_TYPE)(d * height());
831 this->left = point.x - w / 2;
833 this->right = this->left + w;
835 this->top = point.y - h / 2;
837 this->bottom = this->top + h;
842 rectangle_type operator * (::f64 d)
const
845 return rectangle_type(
846 (UNIT_TYPE)(this->left * d),
847 (UNIT_TYPE)(this->top * d),
848 (UNIT_TYPE)(this->right * d),
849 (UNIT_TYPE)(this->bottom * d));
854 void DeflateBottomRightSizeByRate(::f64 dRate)
857 ::f64 Δy = height();
858 ::f64 dxNew = Δx / dRate;
859 ::f64 dyNew = Δy / dRate;
862 this->right -= (long)Δx;
863 this->bottom -= (long)Δy;
866 void SetBottomRightSize(UNIT_TYPE iWidth, UNIT_TYPE iHeight)
868 this->right = this->left + iWidth;
869 this->bottom = this->top + iHeight;
873 void SetBottomRightSize(
const SIZE_TYPE & size)
875 SetBottomRightSize(size.cx, size.cy);
878 void ExtendOnCenter(
const rectangle_type & rectangle)
881 UNIT_TYPE cx = width();
882 UNIT_TYPE cy = height();
884 ::f64 Δx = ::width(rectangle);
885 ::f64 Δy = ::height(rectangle);
886 ::f64 dr = ::maximum(Δx / cx, Δy / cy);
888 UNIT_TYPE cw = (UNIT_TYPE)(cx * dr);
889 UNIT_TYPE ch = (UNIT_TYPE)(cy * dr);
891 this->left = (UNIT_TYPE)((Δx - cw) / 2.0);
892 this->top = (UNIT_TYPE)((Δy - ch) / 2.0);
893 this->right = this->left + cw;
894 this->bottom = this->top + ch;
898 void FitOnCenterOf(
const rectangle_type & rectangle,
const SIZE_TYPE & size)
901 UNIT_TYPE cx = size.cx;
902 UNIT_TYPE cy = size.cy;
904 ::f64 Δx = ::width(rectangle);
905 ::f64 Δy = ::height(rectangle);
906 ::f64 dr = ::minimum(cx == 0 ? 1 : Δx / cx, cy == 0 ? 1 : Δy / cy);
908 UNIT_TYPE cw = cx == 0 ? (UNIT_TYPE)Δx : ((UNIT_TYPE)(cx * dr));
909 UNIT_TYPE ch = cy == 0 ? (UNIT_TYPE)Δy : ((UNIT_TYPE)(cy * dr));
911 this->left = (UNIT_TYPE)((rectangle.left) + (Δx - cw) / 2.0);
912 this->top = (UNIT_TYPE)((rectangle.top) + (Δy - ch) / 2.0);
913 this->right = this->left + cw;
914 this->bottom = this->top + ch;
918 void FitOnCenterOf(
const rectangle_type & rectangle)
921 FitOnCenterOf(rectangle, size());
926 void CenterOf(
const rectangle_type & rectangle,
const SIZE_TYPE & size)
928 UNIT_TYPE cx = size.cx;
929 UNIT_TYPE cy = size.cy;
931 UNIT_TYPE Δx = ::width(rectangle);
932 UNIT_TYPE Δy = ::height(rectangle);
934 this->left = rectangle.left + (Δx - cx) / 2;
935 this->top = rectangle.top + (Δy - cy) / 2;
936 this->right = this->left + cx;
937 this->bottom = this->top + cy;
941 void CenterOf(
const rectangle_type & rectangle)
944 CenterOf(rectangle, size());
949 void ScaleRect(::f64 Δx, ::f64 Δy, UNIT_TYPE ix, UNIT_TYPE iy)
952 this->left = (UNIT_TYPE)(((this->left - ix) * Δx) + ix);
953 this->top = (UNIT_TYPE)(((this->top - iy) * Δy) + iy);
954 this->right = (UNIT_TYPE)(((this->right - ix) * Δx) + ix);
955 this->bottom = (UNIT_TYPE)(((this->bottom - iy) * Δy) + iy);
960 void ScaleHeightAspect(UNIT_TYPE iNewHeight, UNIT_TYPE iCenterX, UNIT_TYPE iCenterY)
962 UNIT_TYPE iHeight = height();
965 ::f64 d = (::f64)iNewHeight / iHeight;
966 ScaleRect(d, d, iCenterX, iCenterY);
972 void Align(::e_align ealign,
const rectangle_type & rectangle)
977 if ((ealign & e_align_horizontal) == e_align_horizontal_center)
980 point.x = rectangle.left + (rectangle.right - rectangle.left) / 2 - width() / 2 - this->left;
983 else if ((ealign & e_align_horizontal) == e_align_left)
986 point.x = rectangle.left - this->left;
989 else if ((ealign & e_align_horizontal) == e_align_right)
992 point.x = rectangle.right - this->right;
996 if ((ealign & e_align_vertical) == e_align_vertical_center)
999 point.y = rectangle.top + (rectangle.bottom - rectangle.top) / 2 - height() / 2 - this->top;
1002 else if ((ealign & e_align_vertical) == e_align_top)
1005 point.y = rectangle.top - this->top;
1008 else if ((ealign & e_align_vertical) == e_align_bottom)
1011 point.y = rectangle.bottom - this->bottom;
1020 void _001Align(::f64 x, ::f64 y,
const rectangle_type & rectangle)
1023 _001AlignX(x, rectangle);
1025 _001AlignY(y, rectangle);
1030 void _001AlignX(::f64 dRate,
const rectangle_type & rectangle)
1033 if (fabs(dRate) < 1000.0)
1036 align_x(dRate, rectangle);
1039 else if (dRate >= 1000.0)
1044 ::f64 x = rectangle.right + width() * dRate;
1046 move_left_to((UNIT_TYPE)x);
1049 else if (dRate <= -1000.0)
1054 ::f64 x = rectangle.left + width() * dRate;
1056 move_left_to((UNIT_TYPE)(x - width()));
1063 void _001AlignY(::f64 dRate,
const rectangle_type & rectangle)
1066 if (fabs(dRate) < 1000.0)
1069 align_y(dRate, rectangle);
1072 else if (dRate >= 1000.0)
1077 ::f64 y = rectangle.bottom + height() * dRate;
1079 move_top_to((UNIT_TYPE)y);
1083 else if (dRate <= -1000.0)
1088 ::f64 y = rectangle.top + height() * dRate;
1090 move_top_to((UNIT_TYPE)(y - height()));
1098 ::f64_size aspect_size(
const rectangle_type & rectangle)
const
1101 ::f64_size size = { (::f64) width(), (::f64) height()};
1103 ::f64 dW = (::f64)rectangle.width() / size.cx;
1105 ::f64 dH = (::f64)rectangle.height() / size.cy;
1107 ::f64 d = minimum(dW, dH);
1109 return { size.cx * d, size.cy * d };
1114 void aspect_fit(
const rectangle_type & rectangle)
1117 auto size = aspect_size(rectangle);
1124 void aspect_align_fit(::f64 x, ::f64 y,
const rectangle_type & rectangle)
1127 aspect_fit(rectangle);
1129 align_x(x, rectangle);
1131 align_y(y, rectangle);
1135 void align_rate(::f64 x, ::f64 y,
const rectangle_type & rectangle)
1138 align_x(x, rectangle);
1140 align_y(y, rectangle);
1144 void align_x(::f64 dRate,
const rectangle_type & rectangle)
1149 x = (UNIT_TYPE)(rectangle.left + (rectangle.right - rectangle.left - width()) * ((dRate + 1.0) / 2.0));
1156 void align_y(::f64 dRate,
const rectangle_type & rectangle)
1161 y = (UNIT_TYPE)(rectangle.top + (rectangle.bottom - rectangle.top - height()) * ((dRate + 1.0) / 2.0));
1168 void _005Constrain(
const rectangle_type & rectangle,
const SIZE_TYPE & sizeMin)
1170 if (this->left < rectangle.left)
1171 this->left = rectangle.left;
1172 if (this->right > rectangle.right)
1173 this->right = rectangle.right;
1174 if (this->top < rectangle.top)
1175 this->top = rectangle.top;
1176 if (this->bottom > rectangle.bottom)
1177 this->bottom = rectangle.bottom;
1179 if (width() < sizeMin.cx)
1180 this->right = this->left + sizeMin.cx;
1181 if (height() < sizeMin.cy)
1182 this->bottom = this->top + sizeMin.cy;
1186 void _007Constrain(
const rectangle_type & rectangle)
1189 const SIZE_TYPE & size = this->size();
1191 if (size.cx > ::width(rectangle))
1194 intersect_x(*
this, rectangle);
1197 else if (intersect_x(*
this, rectangle))
1200 if (this->left == rectangle.left)
1203 this->right = this->left + size.cx;
1209 this->left = this->right - size.cx;
1215 if (size.cy > ::height(rectangle))
1218 intersect_y(*
this, rectangle);
1221 else if (intersect_y(*
this, rectangle))
1224 if (this->top == rectangle.top)
1227 this->bottom = this->top + size.cy;
1233 this->top = this->bottom - size.cy;
1242 void _001Constrain(
const rectangle_type & rectangle)
1245 _001ConstrainX(rectangle);
1247 _001ConstrainY(rectangle);
1252 void _001ConstrainX(
const rectangle_type & rectangle)
1255 if (this->right > rectangle.right)
1258 offset_x(rectangle.right - this->right);
1262 if (this->left < rectangle.left)
1265 offset_x(rectangle.left - this->left);
1272 void _001ConstrainY(
const rectangle_type & rectangle)
1275 if (this->bottom > rectangle.bottom)
1278 offset_y(rectangle.bottom - this->bottom);
1282 if (this->top < rectangle.top)
1285 offset_y(rectangle.top - this->top);
1292 template < prototype_rectangle RECTANGLE >
1293 void _001Constrain(
const rectangle_type & rectangle, RECTANGLE& rectangleBounding)
1296 _001ConstrainX(rectangle, rectangleBounding);
1298 _001ConstrainY(rectangle, rectangleBounding);
1303 template < prototype_rectangle RECTANGLE >
1304 void _001ConstrainX(
const rectangle_type & rectangle, RECTANGLE & rectangleBounding)
1307 if (rectangleBounding.right > rectangle.right)
1310 auto xOffset = rectangle.right - rectangleBounding.right;
1312 ::x_offset(rectangleBounding, xOffset);
1318 if (rectangleBounding.left < rectangle.left)
1321 auto xOffset = rectangle.left - rectangleBounding.left;
1323 ::x_offset(rectangleBounding, xOffset);
1332 template < prototype_rectangle RECTANGLE >
1333 void _001ConstrainY(
const rectangle_type & rectangle, RECTANGLE & rectangleBounding)
1336 if (rectangleBounding.bottom > rectangle.bottom)
1339 auto yOffset = rectangle.bottom - rectangleBounding.bottom;
1341 ::y_offset(rectangleBounding, yOffset);
1347 if (rectangleBounding.top < rectangle.top)
1350 auto yOffset = rectangle.top - rectangleBounding.top;
1352 ::y_offset(rectangleBounding, yOffset);
1360 template < prototype_rectangle RECTANGLE >
1361 bool contains(
const RECTANGLE & rectangle)
const
1363 return rectangle.left >= this->left
1364 && rectangle.right <= this->right
1365 && rectangle.top >= this->top
1366 && rectangle.bottom <= this->bottom;
1370 void SubtractRectMajor(
const rectangle_type & rectangleMajor,
const rectangle_type & rectangleMinor)
1373 rectangle_type rectangleIntersect;
1374 rectangle_type rectangleRet(*
this);
1375 if (!rectangleIntersect.intersect(rectangleMajor, rectangleMinor))
1378 rectangleRet = rectangleMajor;
1383 if (rectangleIntersect == rectangleMajor)
1386 rectangleRet.set(0, 0, 0, 0);
1391 if (rectangleIntersect.left == rectangleMajor.left
1392 && rectangleIntersect.right == rectangleMajor.right)
1395 if (rectangleIntersect.top == rectangleMajor.top)
1398 ::assign(rectangleRet,
1399 rectangleMajor.left,
1400 rectangleIntersect.top,
1401 rectangleMajor.right,
1402 rectangleMajor.bottom);
1405 else if (rectangleIntersect.bottom == rectangleMajor.bottom)
1408 ::assign(rectangleRet,
1409 rectangleMajor.left,
1411 rectangleMajor.right,
1412 rectangleIntersect.bottom);
1418 rectangleRet = rectangleMajor;
1423 else if (rectangleIntersect.top == rectangleMajor.top
1424 && rectangleIntersect.bottom == rectangleMajor.bottom)
1427 if (rectangleIntersect.left == rectangleMajor.left)
1431 rectangleIntersect.left,
1433 rectangleMajor.right,
1434 rectangleMajor.bottom);
1437 else if (rectangleIntersect.right == rectangleMajor.right)
1441 rectangleMajor.left,
1443 rectangleIntersect.right,
1444 rectangleMajor.bottom);
1450 rectangleRet = rectangleMajor;
1458 rectangleRet = rectangleMajor;
1466 *
this = rectangleRet;
1484 UNIT_TYPE minimum_signed_absolute_dimension(
bool bNegativePreference =
true)
const
1491 if (abs(w) < abs(h))
1497 else if (abs(h) < abs(w))
1503 else if (bNegativePreference)
1506 return ::minimum(w, h);
1512 return ::maximum(w, h);
1520 UNIT_TYPE maximum_signed_absolute_dimension(
bool bPositivePreference =
true)
const
1527 if (abs(w) > abs(h))
1533 else if (abs(h) > abs(w))
1539 else if (bPositivePreference)
1542 return ::maximum(w, h);
1548 return ::minimum(w, h);
1556 inline void assign(
const rectangle_type & rectangle, enum_orientation eorientation)
1559 if (eorientation == e_orientation_horizontal)
1562 this->left = rectangle.left;
1563 this->right = rectangle.right;
1566 else if (eorientation == e_orientation_vertical)
1569 this->top = rectangle.top;
1570 this->bottom = rectangle.bottom;
1577 inline void assign_normal(
const rectangle_type & rectangle, enum_orientation eorientation)
1580 if (eorientation == e_orientation_horizontal)
1583 this->top = rectangle.top;
1584 this->bottom = rectangle.bottom;
1587 else if (eorientation == e_orientation_vertical)
1590 this->left = rectangle.left;
1591 this->right = rectangle.right;
1597 inline bool operator==(nullptr_t)
const { return ::is_null(*
this); }
1600 template < prototype_size SIZE >
1601 inline bool operator == (
const SIZE & size)
const {
return this->width() == size.cx && this->height() == size.cy; }
1603 template < prototype_size SIZE >
1604 inline bool operator != (
const SIZE & size)
const {
return !operator ==(size); }
1606 template < prototype_size SIZE >
1607 inline bool operator > (
const SIZE & size)
const {
return this->size() > size; }
1609 template < prototype_size SIZE >
1610 inline bool operator >= (
const SIZE & size)
const {
return this->size() >= size; }
1612 template < prototype_size SIZE >
1613 inline bool operator < (
const SIZE & size)
const {
return this->size() < size; }
1615 template < prototype_size SIZE >
1616 inline bool operator <= (
const SIZE & size)
const {
return this->size() <= size; }
1618 template < prototype_size SIZE >
1619 inline bool any_gt(
const SIZE & size)
const {
return this->size().any_gt(size); }
1621 template < prototype_size SIZE >
1622 inline bool any_ge(
const SIZE & size)
const {
return this->size().any_ge(size); }
1624 template < prototype_size SIZE >
1625 inline bool any_lt(
const SIZE & size)
const {
return this->size().any_lt(size); }
1627 template < prototype_size SIZE >
1628 inline bool any_le(
const SIZE & size)
const {
return this->size().any_le(size); }
1631 void maximum_minimum()
1634 ::maximum(this->left);
1635 ::maximum(this->top);
1636 ::minimum(this->right);
1637 ::minimum(this->bottom);
1642 void expand_bounding_box(POINT_TYPE & top_left, POINT_TYPE & bottom_right)
const
1645 expand_minimum_maximum(top_left.x, bottom_right.x, this->left);
1646 expand_minimum_maximum(top_left.y, bottom_right.y, this->top);
1647 expand_minimum_maximum(top_left.x, bottom_right.x, this->right);
1648 expand_minimum_maximum(top_left.y, bottom_right.y, this->bottom);
1652 template < prototype_array ARRAY >
1653 ARRAY & add_clockwise_edges(ARRAY &a)
const
1655 a.add(this->top_left());
1656 a.add(this->top_right());
1657 a.add(this->bottom_right());
1658 a.add(this->bottom_left());
1661 template < prototype_array ARRAY >
1662 ARRAY& set_clockwise_edges(ARRAY& a, ::collection::index iOffset = 0)
const
1664 a[iOffset + 0] = this->top_left();
1665 a[iOffset + 1] = this->top_right();
1666 a[iOffset + 2] = this->bottom_right();
1667 a[iOffset + 3] = this->bottom_left();
1671 void rotateOn90InsideDimension(NUMBER dimHeight)
1673 auto localCopy = *
this;
1674 set_width(localCopy.height());
1675 set_height(localCopy.width());
1676 auto newLeft = dimHeight - localCopy.top - localCopy.height();
1677 auto newTop = localCopy.left;
1678 set_top_left(newLeft, newTop);
1681 void rotateOn180InsideDimension(NUMBER dimWidth, NUMBER dimHeight)
1683 NUMBER newLeft = dimWidth - this->left - this->width();
1684 NUMBER newTop = dimHeight - this->top - this->height();
1685 set_top_left(newLeft, newTop);
1688 void rotateOn270InsideDimension(NUMBER dimWidth)
1690 auto localCopy = *
this;
1691 set_width(localCopy.height());
1692 set_height(localCopy.width());
1693 auto newLeft = localCopy.top;
1694 auto newTop = dimWidth - localCopy.left - localCopy.width();
1695 set_top_left(newLeft, newTop);