1 /**
2  * @file rect.c
3  * Rectangles.
4  *
5  * @authors Copyright © 2013 Daniel Swanson <danij@dengine.net>
6  *
7  * @par License
8  * GPL: http://www.gnu.org/licenses/gpl.html
9  *
10  * <small>This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by the
12  * Free Software Foundation; either version 2 of the License, or (at your
13  * option) any later version. This program is distributed in the hope that it
14  * will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
15  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
16  * Public License for more details. You should have received a copy of the GNU
17  * General Public License along with this program; if not, write to the Free
18  * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
19  * 02110-1301 USA</small>
20  */
21 
22 #include "de/rect.h"
23 #include "de/memory.h"
24 
25 struct rect_s {
26     Point2 *origin;
27     Size2 *size;
28 };
29 
30 struct rectf_s {
31     Point2f *origin;
32     Size2f *size;
33 };
34 
Rect_New(void)35 Rect *Rect_New(void)
36 {
37     Rect *r = M_Malloc(sizeof *r);
38     r->origin = Point2_New();
39     r->size = Size2_New();
40     return r;
41 }
42 
Rect_NewWithOriginSize(Point2 const * origin,Size2 const * size)43 Rect *Rect_NewWithOriginSize(Point2 const *origin, Size2 const *size)
44 {
45     Rect *r = Rect_New();
46     Rect_SetOrigin(r, origin);
47     Rect_SetSize(r, size);
48     return r;
49 }
50 
Rect_NewWithOriginSize2(int x,int y,int width,int height)51 Rect *Rect_NewWithOriginSize2(int x, int y, int width, int height)
52 {
53     Rect *r = Rect_New();
54     Rect_SetXY(r, x, y);
55     Rect_SetWidthHeight(r, width, height);
56     return r;
57 }
58 
Rect_NewFromRaw(RectRaw const * rawRect)59 Rect *Rect_NewFromRaw(RectRaw const *rawRect)
60 {
61     DENG_ASSERT(rawRect);
62     return Rect_NewWithOriginSize2(rawRect->origin.x, rawRect->origin.y,
63                                    rawRect->size.width, rawRect->size.height);
64 }
65 
Rect_Delete(Rect * r)66 void Rect_Delete(Rect *r)
67 {
68     if (!r) return;
69     Point2_Delete(r->origin);
70     Size2_Delete(r->size);
71     M_Free(r);
72 }
73 
Rect_Copy(Rect * r,Rect const * other)74 void Rect_Copy(Rect *r, Rect const *other)
75 {
76     DENG_ASSERT(r);
77     if (!other) return;
78     Point2_SetXY(r->origin, Rect_X(other), Rect_Y(other));
79     Size2_SetWidthHeight(r->size, Rect_Width(other), Rect_Height(other));
80 }
81 
Rect_CopyRaw(Rect * r,RectRaw const * rawRect)82 Rect *Rect_CopyRaw(Rect *r, RectRaw const *rawRect)
83 {
84     DENG_ASSERT(r);
85     if (rawRect)
86     {
87         Point2_SetXY(r->origin, rawRect->origin.x, rawRect->origin.y);
88         Size2_SetWidthHeight(r->size, rawRect->size.width, rawRect->size.height);
89     }
90     return r;
91 }
92 
Rect_Raw(Rect const * r,RectRaw * rawRect)93 RectRaw *Rect_Raw(Rect const *r, RectRaw *rawRect)
94 {
95     DENG_ASSERT(r);
96     if (!rawRect) return NULL;
97     Point2_Raw(r->origin, &rawRect->origin);
98     Size2_Raw(r->size, &rawRect->size);
99     return rawRect;
100 }
101 
Rect_IsNull(Rect const * r)102 dd_bool Rect_IsNull(Rect const *r)
103 {
104     DENG_ASSERT(r);
105     return Size2_IsNull(r->size);
106 }
107 
Rect_Width(Rect const * r)108 int Rect_Width(Rect const *r)
109 {
110     DENG_ASSERT(r);
111     return Size2_Width(r->size);
112 }
113 
Rect_Height(Rect const * r)114 int Rect_Height(Rect const *r)
115 {
116     DENG_ASSERT(r);
117     return Size2_Height(r->size);
118 }
119 
Rect_SetWidth(Rect * r,int width)120 void Rect_SetWidth(Rect *r, int width)
121 {
122     DENG_ASSERT(r);
123     Size2_SetWidth(r->size, width);
124 }
125 
Rect_SetHeight(Rect * r,int height)126 void Rect_SetHeight(Rect *r, int height)
127 {
128     DENG_ASSERT(r);
129     Size2_SetHeight(r->size, height);
130 }
131 
Rect_Origin(Rect const * r)132 Point2 const *Rect_Origin(Rect const *r)
133 {
134     DENG_ASSERT(r);
135     return r->origin;
136 }
137 
Rect_X(Rect const * r)138 int Rect_X(Rect const *r)
139 {
140     DENG_ASSERT(r);
141     return Point2_X(r->origin);
142 }
143 
Rect_Y(Rect const * r)144 int Rect_Y(Rect const *r)
145 {
146     DENG_ASSERT(r);
147     return Point2_Y(r->origin);
148 }
149 
Rect_SetOrigin(Rect * r,Point2 const * origin)150 void Rect_SetOrigin(Rect *r, Point2 const *origin)
151 {
152     DENG_ASSERT(r);
153     Point2_SetXY(r->origin, Point2_X(origin), Point2_Y(origin));
154 }
155 
Rect_SetX(Rect * r,int x)156 void Rect_SetX(Rect *r, int x)
157 {
158     DENG_ASSERT(r);
159     Point2_SetX(r->origin, x);
160 }
161 
Rect_SetY(Rect * r,int y)162 void Rect_SetY(Rect *r, int y)
163 {
164     DENG_ASSERT(r);
165     Point2_SetY(r->origin, y);
166 }
167 
Rect_SetXY(Rect * r,int x,int y)168 void Rect_SetXY(Rect *r, int x, int y)
169 {
170     DENG_ASSERT(r);
171     Point2_SetXY(r->origin, x, y);
172 }
173 
Rect_TranslateX(Rect * r,int x)174 void Rect_TranslateX(Rect *r, int x)
175 {
176     DENG_ASSERT(r);
177     Point2_TranslateX(r->origin, x);
178 }
179 
Rect_TranslateY(Rect * r,int y)180 void Rect_TranslateY(Rect *r, int y)
181 {
182     DENG_ASSERT(r);
183     Point2_TranslateY(r->origin, y);
184 }
185 
Rect_TranslateXY(Rect * r,int x,int y)186 void Rect_TranslateXY(Rect *r, int x, int y)
187 {
188     DENG_ASSERT(r);
189     Point2_TranslateXY(r->origin, x, y);
190 }
191 
Rect_Translate(Rect * r,Point2Raw const * delta)192 void Rect_Translate(Rect *r, Point2Raw const *delta)
193 {
194     DENG_ASSERT(r);
195     Point2_Translate(r->origin, delta);
196 }
197 
Rect_Size(Rect const * r)198 Size2 const *Rect_Size(Rect const *r)
199 {
200     DENG_ASSERT(r);
201     return r->size;
202 }
203 
Rect_SetSize(Rect * r,Size2 const * size)204 void Rect_SetSize(Rect *r, Size2 const *size)
205 {
206     DENG_ASSERT(r);
207     Size2_SetWidthHeight(r->size, Size2_Width(size), Size2_Height(size));
208 }
209 
Rect_SetWidthHeight(Rect * r,int width,int height)210 void Rect_SetWidthHeight(Rect *r, int width, int height)
211 {
212     DENG_ASSERT(r);
213     Size2_SetWidthHeight(r->size, width, height);
214 }
215 
Rect_TopLeft(Rect const * r,Point2Raw * point)216 Point2Raw *Rect_TopLeft(Rect const *r, Point2Raw *point)
217 {
218     DENG_ASSERT(r);
219     if (!point) return NULL;
220     point->x = Point2_X(r->origin);
221     point->y = Point2_Y(r->origin);
222     return point;
223 }
224 
Rect_TopRight(Rect const * r,Point2Raw * point)225 Point2Raw *Rect_TopRight(Rect const *r, Point2Raw *point)
226 {
227     DENG_ASSERT(r);
228     if (!point) return NULL;
229     point->x = Point2_X(r->origin) + Size2_Width(r->size);
230     point->y = Point2_Y(r->origin);
231     return point;
232 }
233 
Rect_BottomLeft(Rect const * r,Point2Raw * point)234 Point2Raw *Rect_BottomLeft(Rect const *r, Point2Raw *point)
235 {
236     DENG_ASSERT(r);
237     if (!point) return NULL;
238     point->x = Point2_X(r->origin);
239     point->y = Point2_Y(r->origin) + Size2_Height(r->size);
240     return point;
241 }
242 
Rect_BottomRight(Rect const * r,Point2Raw * point)243 Point2Raw *Rect_BottomRight(Rect const *r, Point2Raw *point)
244 {
245     DENG_ASSERT(r);
246     if (!point) return NULL;
247     point->x = Point2_X(r->origin) + Size2_Width(r->size);
248     point->y = Point2_Y(r->origin) + Size2_Height(r->size);
249     return point;
250 }
251 
Rect_Normalize(Rect * r)252 Rect *Rect_Normalize(Rect *r)
253 {
254     DENG_ASSERT(r);
255     if (Size2_Width(r->size) < 0)
256         Point2_TranslateX(r->origin, -Size2_Width(r->size));
257     if (Size2_Height(r->size) < 0)
258         Point2_TranslateY(r->origin, -Size2_Height(r->size));
259     return r;
260 }
261 
Rect_Normalized(Rect const * rect,RectRaw * normalized)262 RectRaw *Rect_Normalized(Rect const *rect, RectRaw *normalized)
263 {
264     if (!normalized) return NULL;
265 
266     if (!rect)
267     {
268         memset(normalized, 0, sizeof(*normalized));
269         return normalized;
270     }
271 
272     Rect_Raw(rect, normalized);
273     if (normalized->size.width < 0)
274         normalized->origin.x -= normalized->size.width;
275     if (normalized->size.height < 0)
276         normalized->origin.y -= normalized->size.height;
277 
278     return normalized;
279 }
280 
281 /// @pre  This and @a other have been normalized.
Rect_UniteRaw2(Rect * r,RectRaw const * other)282 static Rect *Rect_UniteRaw2(Rect *r, RectRaw const *other)
283 {
284     Point2Raw oldOrigin;
285     DENG_ASSERT(r && other);
286 
287     Point2_Raw(r->origin, &oldOrigin);
288 
289     Rect_SetXY(r, MIN_OF(Point2_X(r->origin), other->origin.x),
290                   MIN_OF(Point2_Y(r->origin), other->origin.y));
291 
292     Rect_SetWidthHeight(r, MAX_OF(oldOrigin.x + Size2_Width(r->size),
293                                   other->origin.x + other->size.width)  - Point2_X(r->origin),
294                            MAX_OF(oldOrigin.y + Size2_Height(r->size),
295                                   other->origin.y + other->size.height) - Point2_Y(r->origin));
296 
297     return r;
298 }
299 
Rect_UniteRaw(Rect * r,RectRaw const * other)300 Rect *Rect_UniteRaw(Rect *r, RectRaw const *other)
301 {
302     RectRaw otherNormalized;
303 
304     if (!other) return r;
305 
306     memcpy(&otherNormalized, other, sizeof(otherNormalized));
307     if (otherNormalized.size.width < 0)
308         otherNormalized.origin.x -= otherNormalized.size.width;
309     if (otherNormalized.size.height < 0)
310         otherNormalized.origin.y -= otherNormalized.size.height;
311 
312     return Rect_UniteRaw2(Rect_Normalize(r), &otherNormalized);
313 }
314 
Rect_Unite(Rect * r,Rect const * other)315 Rect *Rect_Unite(Rect *r, Rect const *other)
316 {
317     RectRaw rawOther;
318     return Rect_UniteRaw2(Rect_Normalize(r), Rect_Normalized(other, &rawOther));
319 }
320 
Rect_United(Rect const * rect,Rect const * other,RectRaw * united)321 RectRaw *Rect_United(Rect const *rect, Rect const *other, RectRaw *united)
322 {
323     RectRaw normA, normB;
324 
325     if (!united) return NULL;
326 
327     if (!other)
328     {
329         united->origin.x = Point2_X(rect->origin);
330         united->origin.y = Point2_Y(rect->origin);
331         united->size.width  = Size2_Width(rect->size);
332         united->size.height = Size2_Height(rect->size);
333         return united;
334     }
335 
336     Rect_Normalized(rect, &normA);
337     Rect_Normalized(other, &normB);
338 
339     united->origin.x = MIN_OF(normA.origin.x, normB.origin.x);
340     united->origin.y = MIN_OF(normA.origin.y, normB.origin.y);
341 
342     united->size.width  = MAX_OF(normA.origin.x + normA.size.width,
343                                  normB.origin.x + normB.size.width)  - united->origin.x;
344     united->size.height = MAX_OF(normA.origin.y + normA.size.height,
345                                  normB.origin.y + normB.size.height) - united->origin.y;
346 
347     return united;
348 }
349 
Rect_Equality(Rect const * r,Rect const * other)350 dd_bool Rect_Equality(Rect const *r, Rect const *other)
351 {
352     DENG_ASSERT(r);
353     if (!other) return false;
354     return r == other || (Point2_Equality(r->origin, Rect_Origin(other)) &&
355                           Size2_Equality(r->size, Rect_Size(other)));
356 }
357 
Rectf_New(void)358 Rectf *Rectf_New(void)
359 {
360     Rectf *r = M_Calloc(sizeof *r);
361     r->origin = Point2f_New();
362     r->size = Size2f_New();
363     return r;
364 }
365 
Rectf_NewWithOriginSize(Point2f const * origin,Size2f const * size)366 Rectf *Rectf_NewWithOriginSize(Point2f const *origin, Size2f const *size)
367 {
368     Rectf *r = Rectf_New();
369     Rectf_SetOrigin(r, origin);
370     Rectf_SetSize(r, size);
371     return r;
372 }
373 
Rectf_NewWithOriginSize2(double x,double y,double width,double height)374 Rectf *Rectf_NewWithOriginSize2(double x, double y, double width, double height)
375 {
376     Rectf *r = Rectf_New();
377     Rectf_SetXY(r, x, y);
378     Rectf_SetWidthHeight(r, width, height);
379     return r;
380 }
381 
Rectf_NewFromRaw(RectRawf const * rawRect)382 Rectf *Rectf_NewFromRaw(RectRawf const *rawRect)
383 {
384     DENG_ASSERT(rawRect);
385     return Rectf_NewWithOriginSize2(rawRect->origin.x, rawRect->origin.y,
386                                     rawRect->size.width, rawRect->size.height);
387 }
388 
Rectf_Delete(Rectf * r)389 void Rectf_Delete(Rectf *r)
390 {
391     DENG_ASSERT(r);
392     Point2f_Delete(r->origin);
393     Size2f_Delete(r->size);
394     M_Free(r);
395 }
396 
Rectf_Copy(Rectf * r,Rectf const * other)397 void Rectf_Copy(Rectf *r, Rectf const *other)
398 {
399     DENG_ASSERT(r);
400     if (!other) return;
401     Point2f_SetXY(r->origin, Rectf_X(other), Rectf_Y(other));
402     Size2f_SetWidthHeight(r->size, Rectf_Width(other), Rectf_Height(other));
403 }
404 
Rectf_CopyRaw(Rectf * r,RectRawf const * rawRect)405 Rectf *Rectf_CopyRaw(Rectf *r, RectRawf const *rawRect)
406 {
407     DENG_ASSERT(r);
408     if (rawRect)
409     {
410         Point2f_SetXY(r->origin, rawRect->origin.x, rawRect->origin.y);
411         Size2f_SetWidthHeight(r->size, rawRect->size.width, rawRect->size.height);
412     }
413     return r;
414 }
415 
Rectf_Raw(Rectf const * r,RectRawf * rawRect)416 RectRawf *Rectf_Raw(Rectf const *r, RectRawf *rawRect)
417 {
418     DENG_ASSERT(r);
419     if (!rawRect) return NULL;
420     Point2f_Raw(r->origin, &rawRect->origin);
421     Size2f_Raw(r->size, &rawRect->size);
422     return rawRect;
423 }
424 
Rectf_IsNull(Rectf const * r)425 dd_bool Rectf_IsNull(Rectf const *r)
426 {
427     DENG_ASSERT(r);
428     return Size2f_IsNull(r->size);
429 }
430 
Rectf_Width(Rectf const * r)431 double Rectf_Width(Rectf const *r)
432 {
433     DENG_ASSERT(r);
434     return Size2f_Width(r->size);
435 }
436 
Rectf_Height(Rectf const * r)437 double Rectf_Height(Rectf const *r)
438 {
439     DENG_ASSERT(r);
440     return Size2f_Height(r->size);
441 }
442 
Rectf_Origin(Rectf const * r)443 Point2f const *Rectf_Origin(Rectf const *r)
444 {
445     DENG_ASSERT(r);
446     return r->origin;
447 }
448 
Rectf_X(Rectf const * r)449 double Rectf_X(Rectf const *r)
450 {
451     DENG_ASSERT(r);
452     return Point2f_X(r->origin);
453 }
454 
Rectf_Y(Rectf const * r)455 double Rectf_Y(Rectf const *r)
456 {
457     DENG_ASSERT(r);
458     return Point2f_Y(r->origin);
459 }
460 
Rectf_SetOrigin(Rectf * r,Point2f const * origin)461 void Rectf_SetOrigin(Rectf *r, Point2f const *origin)
462 {
463     DENG_ASSERT(r);
464     Point2f_SetXY(r->origin, Point2f_X(origin), Point2f_Y(origin));
465 }
466 
Rectf_SetX(Rectf * r,double x)467 void Rectf_SetX(Rectf *r, double x)
468 {
469     DENG_ASSERT(r);
470     Point2f_SetX(r->origin, x);
471 }
472 
Rectf_SetY(Rectf * r,double y)473 void Rectf_SetY(Rectf *r, double y)
474 {
475     DENG_ASSERT(r);
476     Point2f_SetY(r->origin, y);
477 }
478 
Rectf_SetXY(Rectf * r,double x,double y)479 void Rectf_SetXY(Rectf *r, double x, double y)
480 {
481     DENG_ASSERT(r);
482     Point2f_SetXY(r->origin, x, y);
483 }
484 
Rectf_Translate(Rectf * r,Point2Rawf const * delta)485 void Rectf_Translate(Rectf *r, Point2Rawf const *delta)
486 {
487     DENG_ASSERT(r);
488     Point2f_Translate(r->origin, delta);
489 }
490 
Rectf_TranslateX(Rectf * r,double x)491 void Rectf_TranslateX(Rectf *r, double x)
492 {
493     DENG_ASSERT(r);
494     Point2f_TranslateX(r->origin, x);
495 }
496 
Rectf_TranslateY(Rectf * r,double y)497 void Rectf_TranslateY(Rectf *r, double y)
498 {
499     DENG_ASSERT(r);
500     Point2f_TranslateY(r->origin, y);
501 }
502 
Rectf_TranslateXY(Rectf * r,double x,double y)503 void Rectf_TranslateXY(Rectf *r, double x, double y)
504 {
505     DENG_ASSERT(r);
506     Point2f_TranslateXY(r->origin, x, y);
507 }
508 
Rectf_SetWidth(Rectf * r,double width)509 void Rectf_SetWidth(Rectf *r, double width)
510 {
511     DENG_ASSERT(r);
512     Size2f_SetWidth(r->size, width);
513 }
514 
Rectf_SetHeight(Rectf * r,double height)515 void Rectf_SetHeight(Rectf *r, double height)
516 {
517     DENG_ASSERT(r);
518     Size2f_SetHeight(r->size, height);
519 }
520 
Rectf_Size(Rectf const * r)521 Size2f const *Rectf_Size(Rectf const *r)
522 {
523     DENG_ASSERT(r);
524     return r->size;
525 }
526 
Rectf_SetSize(Rectf * r,Size2f const * size)527 void Rectf_SetSize(Rectf *r, Size2f const *size)
528 {
529     DENG_ASSERT(r);
530     Size2f_SetWidthHeight(r->size, Size2f_Width(size), Size2f_Height(size));
531 }
532 
Rectf_SetWidthHeight(Rectf * r,double width,double height)533 void Rectf_SetWidthHeight(Rectf *r, double width, double height)
534 {
535     DENG_ASSERT(r);
536     Size2f_SetWidthHeight(r->size, width, height);
537 }
538 
Rectf_TopLeft(Rectf const * r,Point2Rawf * point)539 Point2Rawf *Rectf_TopLeft(Rectf const *r, Point2Rawf *point)
540 {
541     DENG_ASSERT(r);
542     if (!point) return NULL;
543     point->x = Point2f_X(r->origin);
544     point->y = Point2f_Y(r->origin);
545     return point;
546 }
547 
Rectf_TopRight(Rectf const * r,Point2Rawf * point)548 Point2Rawf *Rectf_TopRight(Rectf const *r, Point2Rawf *point)
549 {
550     DENG_ASSERT(r);
551     if (!point) return NULL;
552     point->x = Point2f_X(r->origin) + Size2f_Width(r->size);
553     point->y = Point2f_Y(r->origin);
554     return point;
555 }
556 
Rectf_BottomLeft(Rectf const * r,Point2Rawf * point)557 Point2Rawf *Rectf_BottomLeft(Rectf const *r, Point2Rawf *point)
558 {
559     DENG_ASSERT(r);
560     if (!point) return NULL;
561     point->x = Point2f_X(r->origin);
562     point->y = Point2f_Y(r->origin) + Size2f_Height(r->size);
563     return point;
564 }
565 
Rectf_BottomRight(Rectf const * r,Point2Rawf * point)566 Point2Rawf *Rectf_BottomRight(Rectf const *r, Point2Rawf *point)
567 {
568     DENG_ASSERT(r);
569     if (!point) return NULL;
570     point->x = Point2f_X(r->origin) + Size2f_Width(r->size);
571     point->y = Point2f_Y(r->origin) + Size2f_Height(r->size);
572     return point;
573 }
574 
Rectf_Normalize(Rectf * r)575 Rectf *Rectf_Normalize(Rectf *r)
576 {
577     DENG_ASSERT(r);
578     if (Size2f_Width(r->size) < 0)
579         Point2f_TranslateX(r->origin, -Size2f_Width(r->size));
580     if (Size2f_Height(r->size) < 0)
581         Point2f_TranslateY(r->origin, -Size2f_Height(r->size));
582     return r;
583 }
584 
Rectf_Normalized(Rectf const * rect,RectRawf * normalized)585 RectRawf *Rectf_Normalized(Rectf const *rect, RectRawf *normalized)
586 {
587     if (!normalized) return NULL;
588 
589     if (!rect)
590     {
591         memset(normalized, 0, sizeof(*normalized));
592         return normalized;
593     }
594 
595     Rectf_Raw(rect, normalized);
596     if (normalized->size.width < 0)
597         normalized->origin.x -= normalized->size.width;
598     if (normalized->size.height < 0)
599         normalized->origin.y -= normalized->size.height;
600 
601     return normalized;
602 }
603 
604 /// @pre  This and @a other have been normalized.
Rectf_UniteRaw2(Rectf * r,RectRawf const * other)605 static Rectf *Rectf_UniteRaw2(Rectf *r, RectRawf const *other)
606 {
607     Point2Rawf oldOrigin;
608     DENG_ASSERT(r && other);
609 
610     Point2f_Raw(r->origin, &oldOrigin);
611 
612     Rectf_SetXY(r, MIN_OF(Point2f_X(r->origin), other->origin.x),
613                    MIN_OF(Point2f_Y(r->origin), other->origin.y));
614 
615     Rectf_SetWidthHeight(r, MAX_OF(oldOrigin.x + Size2f_Width(r->size),
616                                    other->origin.x + other->size.width)  - Point2f_X(r->origin),
617                             MAX_OF(oldOrigin.y + Size2f_Height(r->size),
618                                    other->origin.y + other->size.height) - Point2f_Y(r->origin));
619 
620     return r;
621 }
622 
Rectf_UniteRaw(Rectf * r,RectRawf const * other)623 Rectf *Rectf_UniteRaw(Rectf *r, RectRawf const *other)
624 {
625     RectRawf otherNormalized;
626 
627     if (!other) return r;
628 
629     memcpy(&otherNormalized, other, sizeof(otherNormalized));
630     if (otherNormalized.size.width < 0)
631         otherNormalized.origin.x -= otherNormalized.size.width;
632     if (otherNormalized.size.height < 0)
633         otherNormalized.origin.y -= otherNormalized.size.height;
634 
635     return Rectf_UniteRaw2(Rectf_Normalize(r), &otherNormalized);
636 }
637 
Rectf_Unite(Rectf * r,Rectf const * other)638 Rectf *Rectf_Unite(Rectf *r, Rectf const *other)
639 {
640     RectRawf rawOther;
641     return Rectf_UniteRaw2(Rectf_Normalize(r), Rectf_Normalized(other, &rawOther));
642 }
643 
Rectf_United(Rectf const * rect,Rectf const * other,RectRawf * united)644 RectRawf *Rectf_United(Rectf const *rect, Rectf const *other, RectRawf *united)
645 {
646     RectRawf normA, normB;
647 
648     if (!united) return NULL;
649 
650     if (!other)
651     {
652         united->origin.x = Point2f_X(rect->origin);
653         united->origin.y = Point2f_Y(rect->origin);
654         united->size.width  = Size2f_Width(rect->size);
655         united->size.height = Size2f_Height(rect->size);
656         return united;
657     }
658 
659     Rectf_Normalized(rect, &normA);
660     Rectf_Normalized(other, &normB);
661 
662     united->origin.x = MIN_OF(normA.origin.x, normB.origin.x);
663     united->origin.y = MIN_OF(normA.origin.y, normB.origin.y);
664 
665     united->size.width  = MAX_OF(normA.origin.x + normA.size.width,
666                                  normB.origin.x + normB.size.width)  - united->origin.x;
667     united->size.height = MAX_OF(normA.origin.y + normA.size.height,
668                                  normB.origin.y + normB.size.height) - united->origin.y;
669 
670     return united;
671 }
672 
Rectf_Equality(Rectf const * r,Rectf const * other)673 dd_bool Rectf_Equality(Rectf const *r, Rectf const *other)
674 {
675     DENG_ASSERT(r);
676     if (!other) return false;
677     return r == other || (Point2f_Equality(r->origin, Rectf_Origin(other)) &&
678                           Size2f_Equality(r->size, Rectf_Size(other)));
679 }
680