acme
Foundational cross-platform layer of the ca2 framework
Loading...
Searching...
No Matches
rectangle.h
1#pragma once
2
3
4#include "acme/prototype/geometry2d/_function.h"
5#include "acme/prototype/geometry2d/point.h"
6#include "acme/prototype/geometry2d/size.h"
7#include "acme/prototype/mathematics/numeric_info.h"
8
9template < typename RECTANGLE_SOURCE >
10concept rectangle_source = requires(RECTANGLE_SOURCE rectanglesource)
11{
12
13 {rectanglesource.rectangle_source_get()} -> prototype_rectangle;
14
15};
16
17
18struct api_change_t{};
19
20#define API_CHANGED_ARGUMENT api_change_t{}
21
22template < prototype_number NUMBER >
23class origin_size
24{
25public:
26
27 point_type<NUMBER> origin;
29
30 origin_size(){}
31 origin_size(NUMBER x, NUMBER y, NUMBER w, NUMBER h): origin(x, y),size(w, h){}
32 origin_size(const point_type<NUMBER> & point, const size_type<NUMBER> & size):origin(point),size(size){}
33 origin_size(const origin_size & originsize):origin(originsize.origin),size(originsize.size){}
34
35
36 auto top_left() const {return origin;}
37 auto width() const {return size.cx;}
38 auto height() const {return size.cy;}
39
40};
41
42using i32_origin_size = origin_size<::i32>;
43
44
45template < prototype_number NUMBER >
46class rectangle_type :
47 public sequence_type < NUMBER, 4 >
48
49{
50public:
51
52
53 //NUMBER left;
54 //NUMBER top;
55 //NUMBER right;
56 //NUMBER bottom;
57
58
59 //using RECTANGLE_BASE_TYPE = BASE_TYPE;
60 using UNIT_TYPE = NUMBER;
61 using POINT_TYPE = point_type < NUMBER >;
62 using SIZE_TYPE = size_type < NUMBER >;
63 //using POINT_ARRAY_TYPE = point_array_base < POINT_TYPE >;
64
65 rectangle_type() { }
66 rectangle_type(no_initialize_t) { }
67 //rectangle_type(nullptr_t) : rectangle_type(0, 0, 0, 0) {}
68
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)
72 {
73 }
74
75 template < prototype_number A, prototype_number B >
76 rectangle_type(api_change_t, A a, B b) : rectangle_type(0, 0, a, b) {}
77
78 template < prototype_number N >
79 rectangle_type(api_change_t, N n) : rectangle_type(n, n) {}
80
81
82//#ifdef APPLE
83// rectangle_type(const CGRect & t) : { ::copy(*this, &t); }
84// rectangle_type(const Gdiplus::RectF & t) : { ::copy(this, &t); }
85// rectangle_type(const CGRect * p) : { ::copy(this, p); }
86// rectangle_type(const Gdiplus::RectF * p) : { ::copy(this, p); }
87//#endif
88 template < prototype_point 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))
91 {
92 }
93 template < prototype_size SIZE >
94 rectangle_type(const SIZE & size) : rectangle_type(0, 0, size.cx, size.cy) {}
95 template < prototype_point POINT1, prototype_point 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)
100 {
101
102// this->left = (UNIT_TYPE) t.left;
103// this->top = (UNIT_TYPE) t.top;
104// this->right = (UNIT_TYPE) t.right;
105// this->bottom = (UNIT_TYPE) t.bottom;
106
107 }
108 template < struct_rectangle RECTANGLE >
109 rectangle_type(const RECTANGLE & r) :
110 sequence_type < NUMBER, 4 >(r.left, r.top, r.right, r.bottom)
111 {
112 }
113 template < rectangle_source RECTANGLE_SOURCE >
114 rectangle_type(RECTANGLE_SOURCE * prectanglesource) :
115 rectangle_type(prectanglesource->rectangle_source_get())
116 {
117
118 }
119 // template < prototype_rectangle RECTANGLE >
120 // rectangle_type & operator =(const RECTANGLE & rectangle)
121 // {
122
123 // if((void *) this != (void *) &rectangle)
124 // {
125
126 // this->left = (UNIT_TYPE) rectangle.left;
127 // this->top = (UNIT_TYPE) rectangle.top;
128 // this->right = (UNIT_TYPE) rectangle.right;
129 // this->bottom = (UNIT_TYPE) rectangle.bottom;
130
131 // }
132
133 // return *this;
134
135 // }
136
137
138 template < prototype_origin_size ORIGIN_SIZE >
139 rectangle_type(const ORIGIN_SIZE & originsize)
140 {
141
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);
146
147 //return *this;
148
149 }
150
151 template < prototype_number NUMBER2 >
152 rectangle_type(const origin_size<NUMBER2> & originsize)
153 {
154
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);
159
160 //return *this;
161
162 }
163
164// constexpr const UNIT_TYPE & x() const {return this->x;}
165// UNIT_TYPE & x() {return this->x;}
166// constexpr const UNIT_TYPE & y() const {return this->y;}
167// UNIT_TYPE & y() {return this->y;}
168
169
170 /*constexpr const UNIT_TYPE & left const {return this->x;}
171 UNIT_TYPE & left {return this->x;}
172 constexpr const UNIT_TYPE & top const {return this->y;}
173 UNIT_TYPE & top {return this->y;}*/
174
175 //constexpr const UNIT_TYPE & right const {return this->z;}
176 //UNIT_TYPE & right {return this->z;}
177 //constexpr const UNIT_TYPE & bottom const {return this->w;}
178 //UNIT_TYPE & bottom {return this->w;}
179
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()); }
187
188
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_point 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); }
199
200
201 template < typename SIZE >
202 rectangle_type & ensure_at_least(const SIZE & size)
203 {
204
205 this->right = (UNIT_TYPE)::maximum(this->right, this->left + size.cx);
206 this->bottom = (UNIT_TYPE)::maximum(this->bottom, this->top + size.cy);
207
208 return *this;
209
210 }
211
212
213 template < prototype_point POINT >
214 inline ::f64_point to_point_rate(const POINT & point) const
215 {
216
217 return { ((::f64)point.x - (::f64)this->left) / (::f64)width(),
218 ((::f64)point.y - (::f64)this->top) / (::f64)height() };
219
220 }
221
222
223 inline UNIT_TYPE x_rate(::f64 xRate) const
224 {
225
226 return (UNIT_TYPE)(xRate * (::f64)width() + (::f64)this->left);
227
228 }
229
230
231 inline UNIT_TYPE y_rate(::f64 yRate) const
232 {
233
234 return (UNIT_TYPE)(yRate * (::f64)height() + (::f64)this->top);
235
236
237 }
238
239
240 inline POINT_TYPE from_point_rate(const ::f64_point & point) const
241 {
242
243 return POINT_TYPE(x_rate(point.x), y_rate(point.y));
244
245 }
246
247 //void align_outsize_rate(::f64 x, ::f64 y, const rectangle_type& rectangle_type);
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); }
250
251 // void assign(const rectangle_type& rectangle_type, enum_orientation eorientation) ;
252 //void assign_normal(const rectangle_type& rectangle_type, enum_orientation eorientation) ;
253
254 UNIT_TYPE minimum_dimension() const { return ::minimum(width(), height()); }
255 UNIT_TYPE maximum_dimension() const { return ::maximum(width(), height()); }
256
257 UNIT_TYPE max_border() const { return ::maximum(::maximum(this->top, this->left), ::maximum(this->bottom, this->right)); }
258
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())); }
261
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())); }
264
265 //UNIT_TYPE minimum_signed_absolute_dimension(bool bNegativePreference = true) const ;
266 //UNIT_TYPE maximum_signed_absolute_dimension(bool bPositivePreference = true) const ;
267
268 UNIT_TYPE get_dimension(enum_orientation eorientation, ::collection::index i)
269 {
270
271 return eorientation == e_orientation_horizontal ? (i == 0 ? this->left : this->right)
272 : (i == 0 ? this->top : this->bottom);
273
274 }
275
276 UNIT_TYPE get_normal_dimension(enum_orientation eorientation, ::collection::index i)
277 {
278
279 return eorientation == e_orientation_vertical ? (i == 0 ? this->left : this->right)
280 : (i == 0 ? this->top : this->bottom);
281
282 }
283
284 UNIT_TYPE get_first_dimension(enum_orientation eorientation)
285 {
286
287 return eorientation == e_orientation_horizontal ? (this->left) : (this->top);
288
289 }
290
291 UNIT_TYPE get_first_normal_dimension(enum_orientation eorientation)
292 {
293
294 return eorientation == e_orientation_vertical ? (this->right) : (this->bottom);
295
296 }
297
298 UNIT_TYPE get_second_dimension(enum_orientation eorientation)
299 {
300
301 return eorientation == e_orientation_horizontal ? (this->right) : (this->bottom);
302
303 }
304
305 UNIT_TYPE get_second_normal_dimension(enum_orientation eorientation)
306 {
307
308 return eorientation == e_orientation_vertical ? (this->right) : (this->bottom);
309
310 }
311
312 UNIT_TYPE get_total_dimension(enum_orientation eorientation)
313 {
314
315 return eorientation == e_orientation_horizontal ? this->left + this->right : this->top + this->bottom;
316
317 }
318
319 UNIT_TYPE get_normal_total_dimension(enum_orientation eorientation)
320 {
321
322 return eorientation == e_orientation_vertical ? this->left + this->right : this->top + this->bottom;
323
324 }
325
326
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); }
331
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)
337 {
338 auto offsetX = leftNew - this->left;
339 auto offsetY = topNew - this->top;
340 this->left = leftNew;
341 this->right += offsetX;
342 this->top = topNew;
343 this->bottom += offsetY;
344 }
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)
347 {
348
349 *this = with_center_and_half_size(center, halfsize);
350
351 return *this;
352
353
354
355 }
356
357 rectangle_type & set_square_with_center(const POINT_TYPE & center, const UNIT_TYPE & apothem)
358 {
359
360 *this = square_with_center_and_apothem(center, apothem);
361
362 return *this;
363
364 }
365
366
367
368 static rectangle_type with_center_and_half_size(const POINT_TYPE & center, const SIZE_TYPE & halfsize)
369 {
370
371 return {
372 center.x - halfsize.cx,
373 center.y - halfsize.cy,
374 center.x+ halfsize.cx,
375 center.y+ halfsize.cx
376 };
377
378 }
379
380 static rectangle_type square_with_center_and_apothem(const POINT_TYPE & center, const UNIT_TYPE & apothem)
381 {
382
383 return with_center_and_half_size(center, {apothem, apothem});
384
385 }
386
387
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; }
390
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; }
393
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); }
396
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); }
400
401 //operator rectangle_type * () { return this; }
402 //operator const rectangle_type * () const { return (const rectangle_type *)this; }
403
404 explicit operator bool() const { return is_set(); }
405 bool operator !() const { return is_empty(); }
406
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_point POINT1, prototype_point 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_point 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)
418 {
419 return set(rectangle.left, rectangle.top, rectangle.right, rectangle.bottom);
420 }
421
422 rectangle_type & set_dimension(UNIT_TYPE l, UNIT_TYPE t, UNIT_TYPE w, UNIT_TYPE h)
423 {
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);
428 return *this;
429 }
430
431 rectangle_type & clear() { return ::clear(*this); }
432
433 bool is_equal(const rectangle_type & rectangle) const
434 {
435 return this->left == rectangle.left
436 && this->top == rectangle.top
437 && this->right == rectangle.right
438 && this->bottom == rectangle.bottom;
439
440 }
441
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); }
450
451 template < prototype_number NUMBERX, prototype_number NUMBERY >
452 rectangle_type & offset(NUMBERX x, NUMBERY y) { return offset_x(x).offset_y(y); }
453
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); }
462
463 template < prototype_number NUMBERN >
464 rectangle_type & offset(const sequence_type < NUMBERN, 2 > & s) { return offset_x(s.x).offset_y(s.y); }
465
466
467 // template < prototype_size SIZE >
468 // rectangle_type & offset(const SIZE & size) { return offset_x(size.cx).offset_y(size.cy);
469 // }
470
471
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); }
475
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); }
479
480 rectangle_type & intersect(const rectangle_type & rectangle) { ::intersect(*this, *this, rectangle); return *this; }
481
482 rectangle_type & constrain_to(const rectangle_type & rectangle) { return intersect(rectangle); }
483
484
485 inline rectangle_type & constrain(rectangle_type & rectangle) const
486 {
487
488 if (rectangle.left < this->left)
489 rectangle.left = this->left;
490
491 if (rectangle.right < this->right)
492 rectangle.right = this->right;
493
494 if (rectangle.top < this->top)
495 rectangle.top = this->top;
496
497 if (rectangle.bottom < this->bottom)
498 rectangle.bottom = this->bottom;
499
500 return rectangle;
501
502 }
503
504
505 rectangle_type intersection(const rectangle_type & rect1) const
506 {
507
508 rectangle_type rectangle;
509
510 ::intersect(rectangle, *this, rect1);
511
512 return rectangle;
513
514 }
515
516
517 rectangle_type outside_of(const rectangle_type& rect1) const
518 {
519
520 rectangle_type rectangle;
521
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);
526
527 return rectangle;
528
529 }
530
531
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); }
534
535 rectangle_type & unite(const rectangle_type & rectangle1, const rectangle_type & rectangle2)
536 {
537
538 if (rectangle1.is_empty())
539 {
540
541 if (rectangle2.is_empty())
542 {
543
544 this->Null();
545
546 }
547 else
548 {
549
550 this->operator=(rectangle2);
551
552 }
553
554 }
555 else if (rectangle2.is_empty())
556 {
557
558 this->operator= (rectangle1);
559
560 }
561 else
562 {
563
564 this->operator = (rectangle1);
565
566 rectangle2.expand_bounding_box(this->top_left(), this->bottom_right());
567
568 }
569
570 return *this;
571
572 }
573
574
575 rectangle_type & unite(const rectangle_type & rectangle)
576 {
577
578 if (this->is_empty())
579 {
580
581 if (rectangle.is_empty())
582 {
583
584 this->Null();
585
586 }
587 else
588 {
589
590 this->operator=(rectangle);
591
592 }
593
594 }
595 else if (rectangle.is_set())
596 {
597
598 rectangle.expand_bounding_box(this->top_left(), this->bottom_right());
599
600 }
601
602 return *this;
603
604 }
605
606 rectangle_type get_union(const rectangle_type & rect1) const { rectangle_type rectangle(*this); rectangle.unite(rect1); return *this; }
607
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 }; }
612
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 }; }
617
618 rectangle_type & operator =(const rectangle_type & rectangle) = default;
619
620 // template < prototype_rectangle RECTANGLE >
621 // rectangle_type & operator =(const RECTANGLE & rectangle)
622 // {
623
624 // if((void *) this != (void *) &rectangle)
625 // {
626
627 // this->left = (UNIT_TYPE) rectangle.left;
628 // this->top = (UNIT_TYPE) rectangle.top;
629 // this->right = (UNIT_TYPE) rectangle.right;
630 // this->bottom = (UNIT_TYPE) rectangle.bottom;
631
632 // }
633
634 // return *this;
635
636 // }
637
638
639 // template < prototype_origin_size ORIGIN_SIZE >
640 // rectangle_type & operator =(const ORIGIN_SIZE & originsize)
641 // {
642
643 // this->left = (UNIT_TYPE) originsize.origin.x;
644 // this->top = (UNIT_TYPE) originsize.origin.y;
645 // this->right = (UNIT_TYPE) originsize.origin.x + originsize.size.width;
646 // this->bottom = (UNIT_TYPE) originsize.origin.y + originsize.size.height;
647
648 // return *this;
649
650 // }
651
652
653 bool operator==(const rectangle_type & rectangle) const
654 {
655
656 return ::is_equal(*this, rectangle);
657
658 }
659
660 template < prototype_integral INTEGRAL >
661 constexpr bool operator <(INTEGRAL i) const
662 {
663
664 return i == 0 ? !this->is_null_or_positive() : this->area() < i;
665
666 }
667// bool operator!=(const rectangle_type & rectangle) const { return !operator ==(rectangle); }
668
669 template < prototype_sequence2 SEQUENCE >
670 rectangle_type & operator +=(const SEQUENCE & s) { return ::offset(*this, s.x, s.y); }
671
672 //template < prototype_size SIZE >
673 //rectangle_type & operator +=(const SIZE & size) { return ::offset(*this, size.cx, size.cy); }
674
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); }
677
678 template < prototype_number NUMBER2 >
679 rectangle_type & operator*=(NUMBER2 n)
680 {
681
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);
686
687 return *this;
688
689 }
690
691
692// inline rectangle_type & operator +=(const SHIFT_I32 & shift) { this->left = (UNIT_TYPE)(this->left + shift.Δx); this->top = (UNIT_TYPE)(this->top + shift.Δy); this->right = (UNIT_TYPE)(this->right + shift.Δx); this->bottom = (UNIT_TYPE)(this->bottom + shift.Δy); return *this; }
693// inline rectangle_type & operator-=(const SHIFT_I32 & shift) { this->left = (UNIT_TYPE)(this->left - shift.Δx); this->top = (UNIT_TYPE)(this->top - shift.Δy); this->right = (UNIT_TYPE)(this->right + shift.Δx); this->bottom = (UNIT_TYPE)(this->bottom + shift.Δy); return *this; }
694//
695//
696// inline rectangle_type & operator()(const SHIFT_I32 & shift) { return operator +=(shift); }
697//
698//
699// inline rectangle_type operator +(const SHIFT_I32 & shift) { return { (UNIT_TYPE)(this->left + shift.Δx), (UNIT_TYPE)(this->top + shift.Δy), (UNIT_TYPE)(this->right + shift.Δx), (UNIT_TYPE)(this->bottom + shift.Δy) }; }
700// inline rectangle_type operator-(const SHIFT_I32 & shift) { return { (UNIT_TYPE)(this->left - shift.Δx), (UNIT_TYPE)(this->top - shift.Δy), (UNIT_TYPE)(this->right - shift.Δx), (UNIT_TYPE)(this->bottom - shift.Δy) }; }
701
702
703 template < prototype_number NUMBERN >
704 rectangle_type & operator-=(const sequence_type< NUMBERN, 2> & s) { return ::subtract(*this, s.x, s.y); }
705
706 // template < prototype_size SIZE >
707 // rectangle_type & operator-=(const SIZE & size) { return ::subtract(*this, -size.cx, -size.cy); }
708 rectangle_type & operator-=(const rectangle_type & rectangle) { return ::subtract(*this, rectangle); }
709
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); }
712
713 template < prototype_sequence2 SEQUENCE >
714 rectangle_type operator +(const SEQUENCE & s) const
715 {
716 rectangle_type rectangle(*this); rectangle.offset(s.x, s.y); return rectangle;
717 }
718 // rectangle_type operator-(const POINT_TYPE & point) const
719 // {
720 // rectangle_type rectangle(*this); rectangle.offset(-point.x, -point.y); return rectangle;
721 // }
722
723 // template < prototype_size SIZE >
724 // rectangle_type operator +(const SIZE & size) const
725 // {
726 //
727 // rectangle_type rectangle(*this); rectangle.offset(size.cx, size.cy); return rectangle;
728 //
729 // }
730
731 template < prototype_sequence2 SEQUENCE >
732 rectangle_type operator-(const SEQUENCE & s) const
733 {
734
735 rectangle_type rectangle(*this); rectangle.offset(-s.cx, -s.cy); return rectangle;
736
737 }
738
739 rectangle_type operator +(const rectangle_type & rectangleAdd) const
740 {
741 rectangle_type rectangle(*this); rectangle.inflate(rectangleAdd); return rectangle;
742 }
743 rectangle_type operator-(const rectangle_type & rectangleSub) const
744
745 {
746 rectangle_type rectangle(*this); rectangle.deflate(rectangleSub); return rectangle;
747 }
748 rectangle_type operator&(const rectangle_type & rect2) const
749 {
750 rectangle_type rectangle; ::intersect(rectangle, *this, rect2);
751 return rectangle;
752 }
753 rectangle_type operator|(const rectangle_type & rectangleOr) const
754 {
755 rectangle_type rectangle;
756 rectangle.unite(*this, rectangleOr);
757 return rectangle;
758 }
759
760
761 rectangle_type & subtract(const rectangle_type & rectangleSrc1, const rectangle_type & rectangleSrc2)
762 {
763
764 return ::subtract(*this, rectangleSrc1, rectangleSrc2);
765
766 }
767
768 void normalize() ;
769
770 template < prototype_rectangle RECTANGLE >
771 void inflate(const RECTANGLE & rectangle)
772 {
773
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);
778
779 }
780
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);
786 }
787
788
789 template < prototype_rectangle RECTANGLE >
790 void deflate(const RECTANGLE & rectangle)
791 {
792
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);
797
798 }
799
800 void deflate(UNIT_TYPE l, UNIT_TYPE t, UNIT_TYPE r, UNIT_TYPE b)
801 {
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);
806 }
807
808
809
810 UNIT_TYPE area() const
811 {
812
813 return size().area();
814
815 }
816
817
818 //void get_bounding_box(const POINT_BASE_TYPE * ppoint, ::collection::count count);
819 //void get_bounding_box(const POINT_ARRAY_TYPE & pointa) { pointa.get_bounding_box(*this); }
820
821
822 void rate(::f64 d)
823 {
824
825 POINT_TYPE point = center();
826
827 UNIT_TYPE w = (UNIT_TYPE)(d * width());
828
829 UNIT_TYPE h = (UNIT_TYPE)(d * height());
830
831 this->left = point.x - w / 2;
832
833 this->right = this->left + w;
834
835 this->top = point.y - h / 2;
836
837 this->bottom = this->top + h;
838
839 }
840
841
842 rectangle_type operator * (::f64 d) const
843 {
844
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));
850
851 }
852
853
854 void DeflateBottomRightSizeByRate(::f64 dRate)
855 {
856 ::f64 Δx = width();
857 ::f64 Δy = height();
858 ::f64 dxNew = Δx / dRate;
859 ::f64 dyNew = Δy / dRate;
860 Δx = Δx - dxNew;
861 Δy = Δy - dyNew;
862 this->right -= (long)Δx;
863 this->bottom -= (long)Δy;
864 }
865
866 void SetBottomRightSize(UNIT_TYPE iWidth, UNIT_TYPE iHeight)
867 {
868 this->right = this->left + iWidth;
869 this->bottom = this->top + iHeight;
870 }
871
872
873 void SetBottomRightSize(const SIZE_TYPE & size)
874 {
875 SetBottomRightSize(size.cx, size.cy);
876 }
877
878 void ExtendOnCenter(const rectangle_type & rectangle)
879 {
880
881 UNIT_TYPE cx = width();
882 UNIT_TYPE cy = height();
883
884 ::f64 Δx = ::width(rectangle);
885 ::f64 Δy = ::height(rectangle);
886 ::f64 dr = ::maximum(Δx / cx, Δy / cy);
887
888 UNIT_TYPE cw = (UNIT_TYPE)(cx * dr);
889 UNIT_TYPE ch = (UNIT_TYPE)(cy * dr);
890
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;
895
896 }
897
898 void FitOnCenterOf(const rectangle_type & rectangle, const SIZE_TYPE & size)
899 {
900
901 UNIT_TYPE cx = size.cx;
902 UNIT_TYPE cy = size.cy;
903
904 ::f64 Δx = ::width(rectangle);
905 ::f64 Δy = ::height(rectangle);
906 ::f64 dr = ::minimum(cx == 0 ? 1 : Δx / cx, cy == 0 ? 1 : Δy / cy);
907
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));
910
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;
915
916 }
917
918 void FitOnCenterOf(const rectangle_type & rectangle)
919 {
920
921 FitOnCenterOf(rectangle, size());
922
923 }
924
925
926 void CenterOf(const rectangle_type & rectangle, const SIZE_TYPE & size)
927 {
928 UNIT_TYPE cx = size.cx;
929 UNIT_TYPE cy = size.cy;
930
931 UNIT_TYPE Δx = ::width(rectangle);
932 UNIT_TYPE Δy = ::height(rectangle);
933
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;
938
939 }
940
941 void CenterOf(const rectangle_type & rectangle)
942 {
943
944 CenterOf(rectangle, size());
945
946 }
947
948
949 void ScaleRect(::f64 Δx, ::f64 Δy, UNIT_TYPE ix, UNIT_TYPE iy)
950 {
951
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);
956
957 }
958
959
960 void ScaleHeightAspect(UNIT_TYPE iNewHeight, UNIT_TYPE iCenterX, UNIT_TYPE iCenterY)
961 {
962 UNIT_TYPE iHeight = height();
963 if (iHeight != 0)
964 {
965 ::f64 d = (::f64)iNewHeight / iHeight;
966 ScaleRect(d, d, iCenterX, iCenterY);
967 }
968
969 }
970
971
972 void Align(::e_align ealign, const rectangle_type & rectangle)
973 {
974
975 POINT_TYPE point;
976
977 if ((ealign & e_align_horizontal) == e_align_horizontal_center)
978 {
979
980 point.x = rectangle.left + (rectangle.right - rectangle.left) / 2 - width() / 2 - this->left;
981
982 }
983 else if ((ealign & e_align_horizontal) == e_align_left)
984 {
985
986 point.x = rectangle.left - this->left;
987
988 }
989 else if ((ealign & e_align_horizontal) == e_align_right)
990 {
991
992 point.x = rectangle.right - this->right;
993
994 }
995
996 if ((ealign & e_align_vertical) == e_align_vertical_center)
997 {
998
999 point.y = rectangle.top + (rectangle.bottom - rectangle.top) / 2 - height() / 2 - this->top;
1000
1001 }
1002 else if ((ealign & e_align_vertical) == e_align_top)
1003 {
1004
1005 point.y = rectangle.top - this->top;
1006
1007 }
1008 else if ((ealign & e_align_vertical) == e_align_bottom)
1009 {
1010
1011 point.y = rectangle.bottom - this->bottom;
1012
1013 }
1014
1015 offset(point);
1016
1017 }
1018
1019
1020 void _001Align(::f64 x, ::f64 y, const rectangle_type & rectangle)
1021 {
1022
1023 _001AlignX(x, rectangle);
1024
1025 _001AlignY(y, rectangle);
1026
1027 }
1028
1029
1030 void _001AlignX(::f64 dRate, const rectangle_type & rectangle)
1031 {
1032
1033 if (fabs(dRate) < 1000.0)
1034 {
1035
1036 align_x(dRate, rectangle);
1037
1038 }
1039 else if (dRate >= 1000.0)
1040 {
1041
1042 dRate -= 1000.0;
1043
1044 ::f64 x = rectangle.right + width() * dRate;
1045
1046 move_left_to((UNIT_TYPE)x);
1047
1048 }
1049 else if (dRate <= -1000.0)
1050 {
1051
1052 dRate += 1000.0;
1053
1054 ::f64 x = rectangle.left + width() * dRate;
1055
1056 move_left_to((UNIT_TYPE)(x - width()));
1057
1058 }
1059
1060 }
1061
1062
1063 void _001AlignY(::f64 dRate, const rectangle_type & rectangle)
1064 {
1065
1066 if (fabs(dRate) < 1000.0)
1067 {
1068
1069 align_y(dRate, rectangle);
1070
1071 }
1072 else if (dRate >= 1000.0)
1073 {
1074
1075 dRate -= 1000.0;
1076
1077 ::f64 y = rectangle.bottom + height() * dRate;
1078
1079 move_top_to((UNIT_TYPE)y);
1080
1081
1082 }
1083 else if (dRate <= -1000.0)
1084 {
1085
1086 dRate += 1000.0;
1087
1088 ::f64 y = rectangle.top + height() * dRate;
1089
1090 move_top_to((UNIT_TYPE)(y - height()));
1091
1092 }
1093
1094
1095 }
1096
1097
1098 ::f64_size aspect_size(const rectangle_type & rectangle) const
1099 {
1100
1101 ::f64_size size = { (::f64) width(), (::f64) height()};
1102
1103 ::f64 dW = (::f64)rectangle.width() / size.cx;
1104
1105 ::f64 dH = (::f64)rectangle.height() / size.cy;
1106
1107 ::f64 d = minimum(dW, dH);
1108
1109 return { size.cx * d, size.cy * d };
1110
1111 }
1112
1113
1114 void aspect_fit(const rectangle_type & rectangle)
1115 {
1116
1117 auto size = aspect_size(rectangle);
1118
1119 set_size(size);
1120
1121 }
1122
1123
1124 void aspect_align_fit(::f64 x, ::f64 y, const rectangle_type & rectangle)
1125 {
1126
1127 aspect_fit(rectangle);
1128
1129 align_x(x, rectangle);
1130
1131 align_y(y, rectangle);
1132
1133 }
1134
1135 void align_rate(::f64 x, ::f64 y, const rectangle_type & rectangle)
1136 {
1137
1138 align_x(x, rectangle);
1139
1140 align_y(y, rectangle);
1141
1142 }
1143
1144 void align_x(::f64 dRate, const rectangle_type & rectangle)
1145 {
1146
1147 UNIT_TYPE x;
1148
1149 x = (UNIT_TYPE)(rectangle.left + (rectangle.right - rectangle.left - width()) * ((dRate + 1.0) / 2.0));
1150
1151 move_left_to(x);
1152
1153 }
1154
1155
1156 void align_y(::f64 dRate, const rectangle_type & rectangle)
1157 {
1158
1159 UNIT_TYPE y;
1160
1161 y = (UNIT_TYPE)(rectangle.top + (rectangle.bottom - rectangle.top - height()) * ((dRate + 1.0) / 2.0));
1162
1163 move_top_to(y);
1164
1165 }
1166
1167
1168 void _005Constrain(const rectangle_type & rectangle, const SIZE_TYPE & sizeMin)
1169 {
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;
1178
1179 if (width() < sizeMin.cx)
1180 this->right = this->left + sizeMin.cx;
1181 if (height() < sizeMin.cy)
1182 this->bottom = this->top + sizeMin.cy;
1183
1184 }
1185
1186 void _007Constrain(const rectangle_type & rectangle)
1187 {
1188
1189 const SIZE_TYPE & size = this->size();
1190
1191 if (size.cx > ::width(rectangle))
1192 {
1193
1194 intersect_x(*this, rectangle);
1195
1196 }
1197 else if (intersect_x(*this, rectangle))
1198 {
1199
1200 if (this->left == rectangle.left)
1201 {
1202
1203 this->right = this->left + size.cx;
1204
1205 }
1206 else
1207 {
1208
1209 this->left = this->right - size.cx;
1210
1211 }
1212
1213 }
1214
1215 if (size.cy > ::height(rectangle))
1216 {
1217
1218 intersect_y(*this, rectangle);
1219
1220 }
1221 else if (intersect_y(*this, rectangle))
1222 {
1223
1224 if (this->top == rectangle.top)
1225 {
1226
1227 this->bottom = this->top + size.cy;
1228
1229 }
1230 else
1231 {
1232
1233 this->top = this->bottom - size.cy;
1234
1235 }
1236
1237 }
1238
1239 }
1240
1241
1242 void _001Constrain(const rectangle_type & rectangle)
1243 {
1244
1245 _001ConstrainX(rectangle);
1246
1247 _001ConstrainY(rectangle);
1248
1249 }
1250
1251
1252 void _001ConstrainX(const rectangle_type & rectangle)
1253 {
1254
1255 if (this->right > rectangle.right)
1256 {
1257
1258 offset_x(rectangle.right - this->right);
1259
1260 }
1261
1262 if (this->left < rectangle.left)
1263 {
1264
1265 offset_x(rectangle.left - this->left);
1266
1267 }
1268
1269 }
1270
1271
1272 void _001ConstrainY(const rectangle_type & rectangle)
1273 {
1274
1275 if (this->bottom > rectangle.bottom)
1276 {
1277
1278 offset_y(rectangle.bottom - this->bottom);
1279
1280 }
1281
1282 if (this->top < rectangle.top)
1283 {
1284
1285 offset_y(rectangle.top - this->top);
1286
1287 }
1288
1289 }
1290
1291
1292 template < prototype_rectangle RECTANGLE >
1293 void _001Constrain(const rectangle_type & rectangle, RECTANGLE& rectangleBounding)
1294 {
1295
1296 _001ConstrainX(rectangle, rectangleBounding);
1297
1298 _001ConstrainY(rectangle, rectangleBounding);
1299
1300 }
1301
1302
1303 template < prototype_rectangle RECTANGLE >
1304 void _001ConstrainX(const rectangle_type & rectangle, RECTANGLE & rectangleBounding)
1305 {
1306
1307 if (rectangleBounding.right > rectangle.right)
1308 {
1309
1310 auto xOffset = rectangle.right - rectangleBounding.right;
1311
1312 ::x_offset(rectangleBounding, xOffset);
1313
1314 offset_x(xOffset);
1315
1316 }
1317
1318 if (rectangleBounding.left < rectangle.left)
1319 {
1320
1321 auto xOffset = rectangle.left - rectangleBounding.left;
1322
1323 ::x_offset(rectangleBounding, xOffset);
1324
1325 offset_x(xOffset);
1326
1327 }
1328
1329 }
1330
1331
1332 template < prototype_rectangle RECTANGLE >
1333 void _001ConstrainY(const rectangle_type & rectangle, RECTANGLE & rectangleBounding)
1334 {
1335
1336 if (rectangleBounding.bottom > rectangle.bottom)
1337 {
1338
1339 auto yOffset = rectangle.bottom - rectangleBounding.bottom;
1340
1341 ::y_offset(rectangleBounding, yOffset);
1342
1343 offset_y(yOffset);
1344
1345 }
1346
1347 if (rectangleBounding.top < rectangle.top)
1348 {
1349
1350 auto yOffset = rectangle.top - rectangleBounding.top;
1351
1352 ::y_offset(rectangleBounding, yOffset);
1353
1354 offset_y(yOffset);
1355
1356 }
1357
1358 }
1359
1360 template < prototype_rectangle RECTANGLE >
1361 bool contains(const RECTANGLE & rectangle) const
1362 {
1363 return rectangle.left >= this->left
1364 && rectangle.right <= this->right
1365 && rectangle.top >= this->top
1366 && rectangle.bottom <= this->bottom;
1367 }
1368
1369 // Subtract minor from major and return the greatest box around.
1370 void SubtractRectMajor(const rectangle_type & rectangleMajor, const rectangle_type & rectangleMinor)
1371
1372 {
1373 rectangle_type rectangleIntersect;
1374 rectangle_type rectangleRet(*this);
1375 if (!rectangleIntersect.intersect(rectangleMajor, rectangleMinor))
1376 {
1377
1378 rectangleRet = rectangleMajor;
1379
1380 }
1381 else
1382 {
1383 if (rectangleIntersect == rectangleMajor)
1384
1385 {
1386 rectangleRet.set(0, 0, 0, 0);
1387 }
1388 else
1389 {
1390
1391 if (rectangleIntersect.left == rectangleMajor.left
1392 && rectangleIntersect.right == rectangleMajor.right)
1393 {
1394
1395 if (rectangleIntersect.top == rectangleMajor.top)
1396 {
1397
1398 ::assign(rectangleRet,
1399 rectangleMajor.left,
1400 rectangleIntersect.top,
1401 rectangleMajor.right,
1402 rectangleMajor.bottom);
1403
1404 }
1405 else if (rectangleIntersect.bottom == rectangleMajor.bottom)
1406 {
1407
1408 ::assign(rectangleRet,
1409 rectangleMajor.left,
1410 rectangleMajor.top,
1411 rectangleMajor.right,
1412 rectangleIntersect.bottom);
1413
1414 }
1415 else
1416 {
1417
1418 rectangleRet = rectangleMajor;
1419
1420 }
1421
1422 }
1423 else if (rectangleIntersect.top == rectangleMajor.top
1424 && rectangleIntersect.bottom == rectangleMajor.bottom)
1425 {
1426
1427 if (rectangleIntersect.left == rectangleMajor.left)
1428 {
1429
1430 rectangleRet.set(
1431 rectangleIntersect.left,
1432 rectangleMajor.top,
1433 rectangleMajor.right,
1434 rectangleMajor.bottom);
1435
1436 }
1437 else if (rectangleIntersect.right == rectangleMajor.right)
1438 {
1439
1440 rectangleRet.set(
1441 rectangleMajor.left,
1442 rectangleMajor.top,
1443 rectangleIntersect.right,
1444 rectangleMajor.bottom);
1445
1446 }
1447 else
1448 {
1449
1450 rectangleRet = rectangleMajor;
1451
1452 }
1453
1454 }
1455 else
1456 {
1457
1458 rectangleRet = rectangleMajor;
1459
1460 }
1461
1462 }
1463
1464 }
1465
1466 *this = rectangleRet;
1467
1468 return;
1469
1470 }
1471
1472
1473
1474 //void SubtractRectMinor(const rectangle_type & rectangleMajor, const rectangle_type & rectangleMinor)
1475 //{
1476
1477 // //__UNREFERENCED_PARAMETER(rectangleMajor);
1478
1479 // //__UNREFERENCED_PARAMETER(rectangleMinor);
1480
1481 //}
1482
1483
1484 UNIT_TYPE minimum_signed_absolute_dimension(bool bNegativePreference = true) const
1485 {
1486
1487 auto w = width();
1488
1489 auto h = height();
1490
1491 if (abs(w) < abs(h))
1492 {
1493
1494 return w;
1495
1496 }
1497 else if (abs(h) < abs(w))
1498 {
1499
1500 return h;
1501
1502 }
1503 else if (bNegativePreference) // absolutely equal, prefer negative ...
1504 {
1505
1506 return ::minimum(w, h);
1507
1508 }
1509 else // ... otherwise prefer positive
1510 {
1511
1512 return ::maximum(w, h);
1513
1514 }
1515
1516
1517 }
1518
1519
1520 UNIT_TYPE maximum_signed_absolute_dimension(bool bPositivePreference = true) const
1521 {
1522
1523 auto w = width();
1524
1525 auto h = height();
1526
1527 if (abs(w) > abs(h))
1528 {
1529
1530 return w;
1531
1532 }
1533 else if (abs(h) > abs(w))
1534 {
1535
1536 return h;
1537
1538 }
1539 else if (bPositivePreference) // absolutely equal, prefer positive ...
1540 {
1541
1542 return ::maximum(w, h);
1543
1544 }
1545 else // ... otherwise prefer negative
1546 {
1547
1548 return ::minimum(w, h);
1549
1550 }
1551
1552
1553 }
1554
1555
1556 inline void assign(const rectangle_type & rectangle, enum_orientation eorientation)
1557 {
1558
1559 if (eorientation == e_orientation_horizontal)
1560 {
1561
1562 this->left = rectangle.left;
1563 this->right = rectangle.right;
1564
1565 }
1566 else if (eorientation == e_orientation_vertical)
1567 {
1568
1569 this->top = rectangle.top;
1570 this->bottom = rectangle.bottom;
1571
1572 }
1573
1574 }
1575
1576
1577 inline void assign_normal(const rectangle_type & rectangle, enum_orientation eorientation)
1578 {
1579
1580 if (eorientation == e_orientation_horizontal)
1581 {
1582
1583 this->top = rectangle.top;
1584 this->bottom = rectangle.bottom;
1585
1586 }
1587 else if (eorientation == e_orientation_vertical)
1588 {
1589
1590 this->left = rectangle.left;
1591 this->right = rectangle.right;
1592
1593 }
1594
1595 }
1596
1597 inline bool operator==(nullptr_t) const { return ::is_null(*this); }
1598// inline bool operator!=(nullptr_t) const { return !operator==(nullptr); }
1599
1600 template < prototype_size SIZE >
1601 inline bool operator == (const SIZE & size) const { return this->width() == size.cx && this->height() == size.cy; }
1602
1603 template < prototype_size SIZE >
1604 inline bool operator != (const SIZE & size) const { return !operator ==(size); }
1605
1606 template < prototype_size SIZE >
1607 inline bool operator > (const SIZE & size) const { return this->size() > size; }
1608
1609 template < prototype_size SIZE >
1610 inline bool operator >= (const SIZE & size) const { return this->size() >= size; }
1611
1612 template < prototype_size SIZE >
1613 inline bool operator < (const SIZE & size) const { return this->size() < size; }
1614
1615 template < prototype_size SIZE >
1616 inline bool operator <= (const SIZE & size) const { return this->size() <= size; }
1617
1618 template < prototype_size SIZE >
1619 inline bool any_gt(const SIZE & size) const { return this->size().any_gt(size); }
1620
1621 template < prototype_size SIZE >
1622 inline bool any_ge(const SIZE & size) const { return this->size().any_ge(size); }
1623
1624 template < prototype_size SIZE >
1625 inline bool any_lt(const SIZE & size) const { return this->size().any_lt(size); }
1626
1627 template < prototype_size SIZE >
1628 inline bool any_le(const SIZE & size) const { return this->size().any_le(size); }
1629
1630
1631 void maximum_minimum()
1632 {
1633
1634 ::maximum(this->left);
1635 ::maximum(this->top);
1636 ::minimum(this->right);
1637 ::minimum(this->bottom);
1638
1639 }
1640
1641
1642 void expand_bounding_box(POINT_TYPE & top_left, POINT_TYPE & bottom_right) const
1643 {
1644
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);
1649
1650 }
1651
1652 template < prototype_array ARRAY >
1653 ARRAY & add_clockwise_edges(ARRAY &a) const
1654 {
1655 a.add(this->top_left());
1656 a.add(this->top_right());
1657 a.add(this->bottom_right());
1658 a.add(this->bottom_left());
1659 return a;
1660 }
1661 template < prototype_array ARRAY >
1662 ARRAY& set_clockwise_edges(ARRAY& a, ::collection::index iOffset = 0) const
1663 {
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();
1668 return a;
1669 }
1670
1671 void rotateOn90InsideDimension(NUMBER dimHeight)
1672 {
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);
1679 }
1680
1681 void rotateOn180InsideDimension(NUMBER dimWidth, NUMBER dimHeight)
1682 {
1683 NUMBER newLeft = dimWidth - this->left - this->width();
1684 NUMBER newTop = dimHeight - this->top - this->height();
1685 set_top_left(newLeft, newTop);
1686 }
1687
1688 void rotateOn270InsideDimension(NUMBER dimWidth)
1689 {
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);
1696 }
1697
1698};
1699
1700
1701
1702
1703
1704
1705
1706
1707//using rectangle = ::f64_rectangle;
1708
1709
1710
1711// Split to _defer_shape.h by camilo on 2022-06-28 21:20 <3ThomasBorregaardSorensen!! (Mummi and bilbo in ca2HQ)
1712
1713
1714
1715template < prototype_number NUMBER >
1716inline void rectangle_type < NUMBER >::normalize()
1717{
1718
1719 __sort(this->left, this->right);
1720
1721 __sort(this->top, this->bottom);
1722
1723}
1724
1725
1726
1727
1728
1729//template < prototype_number NUMBER >
1730//void rectangle_type < NUMBER > ::get_bounding_box(const POINT_BASE_TYPE * ppoint, ::collection::count count)
1731//{
1732//
1733// ::get_bounding_box(*this, ppoint, count);
1734//
1735//}
1736
1737
1738template < prototype_number X, prototype_number Y, prototype_number W, prototype_number H >
1739inline i32_rectangle i32_rectangle_dimension(X x, Y y, W w, H h)
1740{
1741
1742 return i32_rectangle(x, y, x + w, y + h);
1743
1744}
1745
1746
1747template < prototype_number X, prototype_number Y, prototype_number W, prototype_number H >
1748inline i64_rectangle i64_rectangle_dimension(X x, Y y, W w, H h)
1749{
1750
1751 return i64_rectangle(x, y, x + w, y + h);
1752
1753}
1754
1755
1756template < prototype_number X, prototype_number Y, prototype_number W, prototype_number H >
1757inline ::f32_rectangle f32_rectangle_dimension(X x, Y y, W w, H h)
1758{
1759
1760 return ::f32_rectangle(x, y, x + w, y + h);
1761
1762}
1763
1764
1765template < prototype_number X, prototype_number Y, prototype_number W, prototype_number H >
1766inline ::f64_rectangle f64_rectangle_dimension(X x, Y y, W w, H h)
1767{
1768
1769 return ::f64_rectangle(x, y, x + w, y + h);
1770
1771}
1772
1773//
1774//CLASS_DECL_ACME i32_rectangle & muldiv(i32_rectangle & rectangle, ::i32 numerator, ::i32 denominator);
1775//CLASS_DECL_ACME i64_rectangle & muldiv(i64_rectangle & rectangle, ::i64 numerator, ::i64 denominator);
1776//
1777//
1778//
1779//CLASS_DECL_ACME i32_rectangle & muldiv(i32_rectangle & rectangle, ::i32 numerator, ::i32 denominator);
1780//CLASS_DECL_ACME i64_rectangle & muldiv(i64_rectangle & rectangle, ::i64 numerator, ::i64 denominator);
1781//
1782//template < prototype_integral NUMERATOR, prototype_integral DENOMINATOR >
1783//rectangle_type muldiv(NUMERATOR numerator, DENOMINATOR denominator) const
1784//{
1785// return rectangle_type(
1786// ::muldiv(this->left, numerator, denominator),
1787// ::muldiv(this->top, numerator, denominator),
1788// ::muldiv(this->right, numerator, denominator),
1789// ::muldiv(this->bottom, numerator, denominator)
1790// );
1791//}
1792//
1793
1794
1795
1796
1797
1798template <prototype_number NUMBER>
1799struct std::formatter<rectangle_type<NUMBER>>
1800{
1801 bool m_bIncludeParenthesis = false; // p
1802 bool m_bIncludeDimensions = false; // d instead of l: t: r: b: --> l: t: w: h:
1803
1804
1805 constexpr bool check_option(auto &it, const auto & end)
1806 {
1807
1808 if (it != end)
1809 {
1810
1811 if (*it == 'p')
1812 {
1813 m_bIncludeParenthesis = true;
1814 it++;
1815 return true;
1816 }
1817 else if (*it == 'd')
1818 {
1819 m_bIncludeDimensions = true;
1820 it++;
1821 return true;
1822 }
1823 else if (*it != '}')
1824 {
1825
1826 throw std::format_error("Invalid format specifier for Rectangle.");
1827
1828 }
1829
1830 }
1831
1832 return false;
1833
1834 }
1835
1836
1837
1838 // Parses the format specifier
1839 constexpr auto parse(std::format_parse_context& ctx) {
1840 auto it = ctx.begin(), end = ctx.end();
1841 while (check_option(it, end));
1842 return it;
1843 }
1844
1845 // Formats the Point based on the flag set in parse()
1846 auto format(const rectangle_type<NUMBER> & rectangle, std::format_context& ctx) const {
1847 if (m_bIncludeDimensions)
1848 {
1849 if (m_bIncludeParenthesis) {
1850 return std::format_to(ctx.out(), "(x:{}, y:{}, w:{}, h:{})", rectangle.left, rectangle.top, rectangle.width(), rectangle.height());
1851 } else {
1852 return std::format_to(ctx.out(), "x:{}, y:{}, w:{}, h:{}", rectangle.left, rectangle.top, rectangle.width(), rectangle.height());
1853 }
1854 }
1855 else
1856 {
1857 if (m_bIncludeParenthesis) {
1858 return std::format_to(ctx.out(), "(l:{}, t:{}, r:{}, b:{})", rectangle.left, rectangle.top, rectangle.right, rectangle.bottom);
1859 } else {
1860 return std::format_to(ctx.out(), "(l:{}, t:{}, r:{}, b:{})", rectangle.left, rectangle.top, rectangle.right, rectangle.bottom);
1861 }
1862 }
1863 }
1864};
1865
1866
1867
Definition rectangle.h:24
Definition point.h:12
Definition rectangle.h:49
Definition size.h:11
Definition _aaa_other_initial_concepts.h:77
Definition rectangle.h:10
Definition rectangle.h:18
Definition _tags.h:5