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