1 /* graphene-rect.c: Rectangular type
2 *
3 * SPDX-License-Identifier: MIT
4 *
5 * Copyright 2014 Emmanuele Bassi
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a copy
8 * of this software and associated documentation files (the "Software"), to deal
9 * in the Software without restriction, including without limitation the rights
10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 * copies of the Software, and to permit persons to whom the Software is
12 * furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 * THE SOFTWARE.
24 */
25
26 /**
27 * SECTION:graphene-rect
28 * @title: Rectangle
29 * @short_description: Rectangular shape type
30 *
31 * #graphene_rect_t is a type representing a rectangle through an origin
32 * #graphene_point_t point and a #graphene_size_t size.
33 *
34 * ![](rectangle.png)
35 *
36 * Operations on a #graphene_rect_t will normalize the rectangle, to
37 * ensure that the origin is always the top-left corner of the rectangle
38 * and that the size is always positive.
39 */
40
41 #include "graphene-private.h"
42
43 #include "graphene-rect.h"
44
45 #include <math.h>
46
47 /*< private >
48 * graphene_rect_normalize_in_place:
49 * @r: (inout): a #graphene_rect_t
50 *
51 * Normalizes the passed #graphene_rect_t.
52 */
53 static inline void
graphene_rect_normalize_in_place(graphene_rect_t * r)54 graphene_rect_normalize_in_place (graphene_rect_t *r)
55 {
56 if (r->size.width < 0.f)
57 {
58 float size = fabsf (r->size.width);
59
60 r->origin.x -= size;
61 r->size.width = size;
62 }
63
64 if (r->size.height < 0.f)
65 {
66 float size = fabsf (r->size.height);
67
68 r->origin.y -= size;
69 r->size.height = size;
70 }
71 }
72
73 /**
74 * graphene_rect_alloc:
75 *
76 * Allocates a new #graphene_rect_t.
77 *
78 * The contents of the returned rectangle are undefined.
79 *
80 * Returns: (transfer full): the newly allocated rectangle
81 *
82 * Since: 1.0
83 */
84 graphene_rect_t *
graphene_rect_alloc(void)85 graphene_rect_alloc (void)
86 {
87 return calloc (1, sizeof (graphene_rect_t));
88 }
89
90 /**
91 * graphene_rect_free:
92 * @r: a #graphene_rect_t
93 *
94 * Frees the resources allocated by graphene_rect_alloc().
95 *
96 * Since: 1.0
97 */
98 void
graphene_rect_free(graphene_rect_t * r)99 graphene_rect_free (graphene_rect_t *r)
100 {
101 free (r);
102 }
103
104 /**
105 * graphene_rect_init:
106 * @r: a #graphene_rect_t
107 * @x: the X coordinate of the @graphene_rect_t.origin
108 * @y: the Y coordinate of the @graphene_rect_t.origin
109 * @width: the width of the @graphene_rect_t.size
110 * @height: the height of the @graphene_rect_t.size
111 *
112 * Initializes the given #graphene_rect_t with the given values.
113 *
114 * This function will implicitly normalize the #graphene_rect_t
115 * before returning.
116 *
117 * Returns: (transfer none): the initialized rectangle
118 *
119 * Since: 1.0
120 */
121 graphene_rect_t *
graphene_rect_init(graphene_rect_t * r,float x,float y,float width,float height)122 graphene_rect_init (graphene_rect_t *r,
123 float x,
124 float y,
125 float width,
126 float height)
127 {
128 graphene_point_init (&r->origin, x, y);
129 graphene_size_init (&r->size, width, height);
130
131 graphene_rect_normalize_in_place (r);
132
133 return r;
134 }
135
136 /**
137 * graphene_rect_init_from_rect:
138 * @r: a #graphene_rect_t
139 * @src: a #graphene_rect_t
140 *
141 * Initializes @r using the given @src rectangle.
142 *
143 * This function will implicitly normalize the #graphene_rect_t
144 * before returning.
145 *
146 * Returns: (transfer none): the initialized rectangle
147 *
148 * Since: 1.0
149 */
150 graphene_rect_t *
graphene_rect_init_from_rect(graphene_rect_t * r,const graphene_rect_t * src)151 graphene_rect_init_from_rect (graphene_rect_t *r,
152 const graphene_rect_t *src)
153 {
154 *r = *src;
155
156 graphene_rect_normalize_in_place (r);
157
158 return r;
159 }
160
161 static bool
rect_equal(const void * p1,const void * p2)162 rect_equal (const void *p1,
163 const void *p2)
164 {
165 const graphene_rect_t *a = p1;
166 const graphene_rect_t *b = p2;
167
168 graphene_rect_t r_a, r_b;
169
170 graphene_rect_normalize_r (a, &r_a);
171 graphene_rect_normalize_r (b, &r_b);
172
173 return graphene_point_equal (&r_a.origin, &r_b.origin) &&
174 graphene_size_equal (&r_a.size, &r_b.size);
175 }
176
177 /**
178 * graphene_rect_equal:
179 * @a: a #graphene_rect_t
180 * @b: a #graphene_rect_t
181 *
182 * Checks whether the two given rectangle are equal.
183 *
184 * Returns: `true` if the rectangles are equal
185 *
186 * Since: 1.0
187 */
188 bool
graphene_rect_equal(const graphene_rect_t * a,const graphene_rect_t * b)189 graphene_rect_equal (const graphene_rect_t *a,
190 const graphene_rect_t *b)
191 {
192 return graphene_pointer_equal (a, b, rect_equal);
193 }
194
195 /**
196 * graphene_rect_normalize:
197 * @r: a #graphene_rect_t
198 *
199 * Normalizes the passed rectangle.
200 *
201 * This function ensures that the size of the rectangle is made of
202 * positive values, and that the origin is the top-left corner of
203 * the rectangle.
204 *
205 * Returns: (transfer none): the normalized rectangle
206 *
207 * Since: 1.0
208 */
209 graphene_rect_t *
graphene_rect_normalize(graphene_rect_t * r)210 graphene_rect_normalize (graphene_rect_t *r)
211 {
212 graphene_rect_normalize_in_place (r);
213
214 return r;
215 }
216
217 /**
218 * graphene_rect_normalize_r:
219 * @r: a #graphene_rect_t
220 * @res: (out caller-allocates): the return location for the
221 * normalized rectangle
222 *
223 * Normalizes the passed rectangle.
224 *
225 * This function ensures that the size of the rectangle is made of
226 * positive values, and that the origin is in the top-left corner
227 * of the rectangle.
228 *
229 * Since: 1.4
230 */
231 void
graphene_rect_normalize_r(const graphene_rect_t * r,graphene_rect_t * res)232 graphene_rect_normalize_r (const graphene_rect_t *r,
233 graphene_rect_t *res)
234 {
235 if (res != r)
236 *res = *r;
237
238 graphene_rect_normalize_in_place (res);
239 }
240
241 /**
242 * graphene_rect_get_center:
243 * @r: a #graphene_rect_t
244 * @p: (out caller-allocates): return location for a #graphene_point_t
245 *
246 * Retrieves the coordinates of the center of the given rectangle.
247 *
248 * Since: 1.0
249 */
250 void
graphene_rect_get_center(const graphene_rect_t * r,graphene_point_t * p)251 graphene_rect_get_center (const graphene_rect_t *r,
252 graphene_point_t *p)
253 {
254 graphene_rect_t rr;
255
256 rr = *r;
257 graphene_rect_normalize_in_place (&rr);
258
259 graphene_point_init (p,
260 rr.origin.x + (rr.size.width / 2.f),
261 rr.origin.y + (rr.size.height / 2.f));
262 }
263
264 /**
265 * graphene_rect_get_top_left:
266 * @r: a #graphene_rect_t
267 * @p: (out caller-allocates): return location for a #graphene_point_t
268 *
269 * Retrieves the coordinates of the top-left corner of the given rectangle.
270 *
271 * Since: 1.0
272 */
273 void
graphene_rect_get_top_left(const graphene_rect_t * r,graphene_point_t * p)274 graphene_rect_get_top_left (const graphene_rect_t *r,
275 graphene_point_t *p)
276 {
277 graphene_rect_t rr;
278
279 rr = *r;
280 graphene_rect_normalize_in_place (&rr);
281
282 graphene_point_init_from_point (p, &rr.origin);
283 }
284
285 /**
286 * graphene_rect_get_top_right:
287 * @r: a #graphene_rect_t
288 * @p: (out caller-allocates): return location for a #graphene_point_t
289 *
290 * Retrieves the coordinates of the top-right corner of the given rectangle.
291 *
292 * Since: 1.0
293 */
294 void
graphene_rect_get_top_right(const graphene_rect_t * r,graphene_point_t * p)295 graphene_rect_get_top_right (const graphene_rect_t *r,
296 graphene_point_t *p)
297 {
298 graphene_rect_t rr;
299
300 rr = *r;
301 graphene_rect_normalize_in_place (&rr);
302
303 graphene_point_init (p, rr.origin.x + rr.size.width, rr.origin.y);
304 }
305
306 /**
307 * graphene_rect_get_bottom_left:
308 * @r: a #graphene_rect_t
309 * @p: (out caller-allocates): return location for a #graphene_point_t
310 *
311 * Retrieves the coordinates of the bottom-left corner of the given rectangle.
312 *
313 * Since: 1.0
314 */
315 void
graphene_rect_get_bottom_left(const graphene_rect_t * r,graphene_point_t * p)316 graphene_rect_get_bottom_left (const graphene_rect_t *r,
317 graphene_point_t *p)
318 {
319 graphene_rect_t rr;
320
321 rr = *r;
322 graphene_rect_normalize_in_place (&rr);
323
324 graphene_point_init (p, rr.origin.x, rr.origin.y + rr.size.height);
325 }
326
327 /**
328 * graphene_rect_get_bottom_right:
329 * @r: a #graphene_rect_t
330 * @p: (out caller-allocates): return location for a #graphene_point_t
331 *
332 * Retrieves the coordinates of the bottom-right corner of the given rectangle.
333 *
334 * Since: 1.0
335 */
336 void
graphene_rect_get_bottom_right(const graphene_rect_t * r,graphene_point_t * p)337 graphene_rect_get_bottom_right (const graphene_rect_t *r,
338 graphene_point_t *p)
339 {
340 graphene_rect_t rr;
341
342 rr = *r;
343 graphene_rect_normalize_in_place (&rr);
344
345 graphene_point_init (p,
346 rr.origin.x + rr.size.width,
347 rr.origin.y + rr.size.height);
348 }
349
350 /**
351 * graphene_rect_get_vertices:
352 * @r: a #graphene_rect_t
353 * @vertices: (out) (array fixed-size=4): return location for an array
354 * of 4 #graphene_vec2_t
355 *
356 * Computes the four vertices of a #graphene_rect_t.
357 *
358 * Since: 1.4
359 */
360 void
graphene_rect_get_vertices(const graphene_rect_t * r,graphene_vec2_t vertices[])361 graphene_rect_get_vertices (const graphene_rect_t *r,
362 graphene_vec2_t vertices[])
363 {
364 graphene_rect_t rr;
365
366 graphene_rect_normalize_r (r, &rr);
367
368 graphene_vec2_init (&vertices[0], rr.origin.x, rr.origin.y);
369 graphene_vec2_init (&vertices[1], rr.origin.x + rr.size.width, rr.origin.y);
370 graphene_vec2_init (&vertices[2], rr.origin.x + rr.size.width, rr.origin.y + rr.size.height);
371 graphene_vec2_init (&vertices[3], rr.origin.x, rr.origin.y + rr.size.height);
372 }
373
374 #define GRAPHENE_RECT_GET(arg, part, field) \
375 float \
376 graphene_rect_get_ ## field (const graphene_rect_t * arg) \
377 { \
378 graphene_rect_t rr; \
379 \
380 rr = *arg; \
381 graphene_rect_normalize_in_place (&rr); \
382 \
383 return rr.part.field; \
384 }
385
386 /**
387 * graphene_rect_get_x:
388 * @r: a #graphene_rect_t
389 *
390 * Retrieves the normalized X coordinate of the origin of the given
391 * rectangle.
392 *
393 * Returns: the normalized X coordinate of the rectangle
394 *
395 * Since: 1.0
396 */
GRAPHENE_RECT_GET(r,origin,x)397 GRAPHENE_RECT_GET (r, origin, x)
398
399 /**
400 * graphene_rect_get_y:
401 * @r: a #graphene_rect_t
402 *
403 * Retrieves the normalized Y coordinate of the origin of the given
404 * rectangle.
405 *
406 * Returns: the normalized Y coordinate of the rectangle
407 *
408 * Since: 1.0
409 */
410 GRAPHENE_RECT_GET (r, origin, y)
411
412 /**
413 * graphene_rect_get_width:
414 * @r: a #graphene_rect_t
415 *
416 * Retrieves the normalized width of the given rectangle.
417 *
418 * Returns: the normalized width of the rectangle
419 *
420 * Since: 1.0
421 */
422 GRAPHENE_RECT_GET (r, size, width)
423
424 /**
425 * graphene_rect_get_height:
426 * @r: a #graphene_rect_t
427 *
428 * Retrieves the normalized height of the given rectangle.
429 *
430 * Returns: the normalized height of the rectangle
431 *
432 * Since: 1.0
433 */
434 GRAPHENE_RECT_GET (r, size, height)
435
436 #undef GRAPHENE_RECT_GET
437
438 /**
439 * graphene_rect_get_area:
440 * @r: a #graphene_rect_t
441 *
442 * Compute the area of given normalized rectangle.
443 *
444 * Returns: the area of the normalized rectangle
445 *
446 * Since: 1.10
447 */
448 float
449 graphene_rect_get_area (const graphene_rect_t *r)
450 {
451 graphene_rect_t rr;
452
453 graphene_rect_normalize_r (r, &rr);
454
455 return rr.size.width * rr.size.height;
456 }
457
458 /**
459 * graphene_rect_union:
460 * @a: a #graphene_rect_t
461 * @b: a #graphene_rect_t
462 * @res: (out caller-allocates): return location for a #graphene_rect_t
463 *
464 * Computes the union of the two given rectangles.
465 *
466 * ![](rectangle-union.png)
467 *
468 * The union in the image above is the blue outline.
469 *
470 * Since: 1.0
471 */
472 void
graphene_rect_union(const graphene_rect_t * a,const graphene_rect_t * b,graphene_rect_t * res)473 graphene_rect_union (const graphene_rect_t *a,
474 const graphene_rect_t *b,
475 graphene_rect_t *res)
476 {
477 graphene_rect_t ra, rb;
478
479 ra = *a;
480 rb = *b;
481
482 graphene_rect_normalize_in_place (&ra);
483 graphene_rect_normalize_in_place (&rb);
484
485 res->origin.x = MIN (ra.origin.x, rb.origin.x);
486 res->origin.y = MIN (ra.origin.y, rb.origin.y);
487
488 res->size.width = MAX (ra.origin.x + ra.size.width, rb.origin.x + rb.size.width) - res->origin.x;
489 res->size.height = MAX (ra.origin.y + ra.size.height, rb.origin.y + rb.size.height) - res->origin.y;
490 }
491
492 /**
493 * graphene_rect_intersection:
494 * @a: a #graphene_rect_t
495 * @b: a #graphene_rect_t
496 * @res: (out caller-allocates) (optional): return location for
497 * a #graphene_rect_t
498 *
499 * Computes the intersection of the two given rectangles.
500 *
501 * ![](rectangle-intersection.png)
502 *
503 * The intersection in the image above is the blue outline.
504 *
505 * If the two rectangles do not intersect, @res will contain
506 * a degenerate rectangle with origin in (0, 0) and a size of 0.
507 *
508 * Returns: `true` if the two rectangles intersect
509 *
510 * Since: 1.0
511 */
512 bool
graphene_rect_intersection(const graphene_rect_t * a,const graphene_rect_t * b,graphene_rect_t * res)513 graphene_rect_intersection (const graphene_rect_t *a,
514 const graphene_rect_t *b,
515 graphene_rect_t *res)
516 {
517 graphene_rect_t ra, rb;
518 float x_1, y_1, x_2, y_2;
519
520 ra = *a;
521 rb = *b;
522
523 graphene_rect_normalize_in_place (&ra);
524 graphene_rect_normalize_in_place (&rb);
525
526 x_1 = MAX (ra.origin.x, rb.origin.x);
527 y_1 = MAX (ra.origin.y, rb.origin.y);
528 x_2 = MIN (ra.origin.x + ra.size.width, rb.origin.x + rb.size.width);
529 y_2 = MIN (ra.origin.y + ra.size.height, rb.origin.y + rb.size.height);
530
531 if (x_1 >= x_2 || y_1 >= y_2)
532 {
533 if (res != NULL)
534 graphene_rect_init (res, 0.0f, 0.0f, 0.0f, 0.0f);
535
536 return false;
537 }
538
539 if (res != NULL)
540 graphene_rect_init (res, x_1, y_1, x_2 - x_1, y_2 - y_1);
541
542 return true;
543 }
544
545 /**
546 * graphene_rect_contains_point:
547 * @r: a #graphene_rect_t
548 * @p: a #graphene_point_t
549 *
550 * Checks whether a #graphene_rect_t contains the given coordinates.
551 *
552 * Returns: `true` if the rectangle contains the point
553 *
554 * Since: 1.0
555 */
556 bool
graphene_rect_contains_point(const graphene_rect_t * r,const graphene_point_t * p)557 graphene_rect_contains_point (const graphene_rect_t *r,
558 const graphene_point_t *p)
559 {
560 graphene_rect_t rr;
561
562 rr = *r;
563 graphene_rect_normalize_in_place (&rr);
564
565 return p->x >= rr.origin.x &&
566 p->y >= rr.origin.y &&
567 p->x <= (rr.origin.x + rr.size.width) &&
568 p->y <= (rr.origin.y + rr.size.height);
569 }
570
571 /**
572 * graphene_rect_contains_rect:
573 * @a: a #graphene_rect_t
574 * @b: a #graphene_rect_t
575 *
576 * Checks whether a #graphene_rect_t fully contains the given
577 * rectangle.
578 *
579 * Returns: `true` if the rectangle @a fully contains @b
580 *
581 * Since: 1.0
582 */
583 bool
graphene_rect_contains_rect(const graphene_rect_t * a,const graphene_rect_t * b)584 graphene_rect_contains_rect (const graphene_rect_t *a,
585 const graphene_rect_t *b)
586 {
587 graphene_rect_t res;
588
589 graphene_rect_union (a, b, &res);
590
591 return graphene_rect_equal (a, &res);
592 }
593
594 /**
595 * graphene_rect_offset:
596 * @r: a #graphene_rect_t
597 * @d_x: the horizontal offset
598 * @d_y: the vertical offset
599 *
600 * Offsets the origin by @d_x and @d_y.
601 *
602 * The size of the rectangle is unchanged.
603 *
604 * Returns: (transfer none): the offset rectangle
605 *
606 * Since: 1.0
607 */
608 graphene_rect_t *
graphene_rect_offset(graphene_rect_t * r,float d_x,float d_y)609 graphene_rect_offset (graphene_rect_t *r,
610 float d_x,
611 float d_y)
612 {
613 graphene_rect_offset_r (r, d_x, d_y, r);
614
615 return r;
616 }
617
618 /**
619 * graphene_rect_offset_r:
620 * @r: a #graphene_rect_t
621 * @d_x: the horizontal offset
622 * @d_y: the vertical offset
623 * @res: (out caller-allocates): return location for the offset
624 * rectangle
625 *
626 * Offsets the origin of the given rectangle by @d_x and @d_y.
627 *
628 * The size of the rectangle is left unchanged.
629 *
630 * Since: 1.4
631 */
632 void
graphene_rect_offset_r(const graphene_rect_t * r,float d_x,float d_y,graphene_rect_t * res)633 graphene_rect_offset_r (const graphene_rect_t *r,
634 float d_x,
635 float d_y,
636 graphene_rect_t *res)
637 {
638 graphene_rect_normalize_r (r, res);
639
640 res->origin.x += d_x;
641 res->origin.y += d_y;
642 }
643
644 /**
645 * graphene_rect_inset:
646 * @r: a #graphene_rect_t
647 * @d_x: the horizontal inset
648 * @d_y: the vertical inset
649 *
650 * Changes the given rectangle to be smaller, or larger depending on the
651 * given inset parameters.
652 *
653 * To create an inset rectangle, use positive @d_x or @d_y values; to
654 * create a larger, encompassing rectangle, use negative @d_x or @d_y
655 * values.
656 *
657 * The origin of the rectangle is offset by @d_x and @d_y, while the size
658 * is adjusted by `(2 * @d_x, 2 * @d_y)`. If @d_x and @d_y are positive
659 * values, the size of the rectangle is decreased; if @d_x and @d_y are
660 * negative values, the size of the rectangle is increased.
661 *
662 * If the size of the resulting inset rectangle has a negative width or
663 * height then the size will be set to zero.
664 *
665 * Returns: (transfer none): the inset rectangle
666 *
667 * Since: 1.0
668 */
669 graphene_rect_t *
graphene_rect_inset(graphene_rect_t * r,float d_x,float d_y)670 graphene_rect_inset (graphene_rect_t *r,
671 float d_x,
672 float d_y)
673 {
674 graphene_rect_inset_r (r, d_x, d_y, r);
675
676 return r;
677 }
678
679 /**
680 * graphene_rect_inset_r:
681 * @r: a #graphene_rect_t
682 * @d_x: the horizontal inset
683 * @d_y: the vertical inset
684 * @res: (out caller-allocates): return location for the inset rectangle
685 *
686 * Changes the given rectangle to be smaller, or larger depending on the
687 * given inset parameters.
688 *
689 * To create an inset rectangle, use positive @d_x or @d_y values; to
690 * create a larger, encompassing rectangle, use negative @d_x or @d_y
691 * values.
692 *
693 * The origin of the rectangle is offset by @d_x and @d_y, while the size
694 * is adjusted by `(2 * @d_x, 2 * @d_y)`. If @d_x and @d_y are positive
695 * values, the size of the rectangle is decreased; if @d_x and @d_y are
696 * negative values, the size of the rectangle is increased.
697 *
698 * If the size of the resulting inset rectangle has a negative width or
699 * height then the size will be set to zero.
700 *
701 * Since: 1.4
702 */
703 void
graphene_rect_inset_r(const graphene_rect_t * r,float d_x,float d_y,graphene_rect_t * res)704 graphene_rect_inset_r (const graphene_rect_t *r,
705 float d_x,
706 float d_y,
707 graphene_rect_t *res)
708 {
709 graphene_rect_normalize_r (r, res);
710
711 res->origin.x += d_x;
712 res->origin.y += d_y;
713
714 if (d_x >= 0.f)
715 res->size.width -= (d_x * 2.f);
716 else
717 res->size.width += (d_x * -2.f);
718
719 if (d_y >= 0.f)
720 res->size.height -= (d_y * 2.f);
721 else
722 res->size.height += (d_y * -2.f);
723
724 if (res->size.width < 0.f)
725 res->size.width = 0.f;
726
727 if (res->size.height < 0.f)
728 res->size.height = 0.f;
729 }
730
731 /**
732 * graphene_rect_round_to_pixel:
733 * @r: a #graphene_rect_t
734 *
735 * Rounds the origin and the size of the given rectangle to
736 * their nearest integer values; the rounding is guaranteed
737 * to be large enough to contain the original rectangle.
738 *
739 * Returns: (transfer none): the pixel-aligned rectangle.
740 *
741 * Since: 1.0
742 *
743 * Deprecated: 1.4: Use graphene_rect_round() instead
744 */
745 graphene_rect_t *
graphene_rect_round_to_pixel(graphene_rect_t * r)746 graphene_rect_round_to_pixel (graphene_rect_t *r)
747 {
748 graphene_rect_round (r, r);
749
750 return r;
751 }
752
753 /**
754 * graphene_rect_round:
755 * @r: a #graphene_rect_t
756 * @res: (out caller-allocates): return location for the
757 * rounded rectangle
758 *
759 * Rounds the origin and size of the given rectangle to
760 * their nearest integer values; the rounding is guaranteed
761 * to be large enough to have an area bigger or equal to the
762 * original rectangle, but might not fully contain its extents.
763 * Use graphene_rect_round_extents() in case you need to round
764 * to a rectangle that covers fully the original one.
765 *
766 * This function is the equivalent of calling `floor` on
767 * the coordinates of the origin, and `ceil` on the size.
768 *
769 * Since: 1.4
770 *
771 * Deprecated: 1.10: Use graphene_rect_round_extents() instead
772 */
773 void
graphene_rect_round(const graphene_rect_t * r,graphene_rect_t * res)774 graphene_rect_round (const graphene_rect_t *r,
775 graphene_rect_t *res)
776 {
777 graphene_rect_normalize_r (r, res);
778
779 res->origin.x = floorf (res->origin.x);
780 res->origin.y = floorf (res->origin.y);
781
782 res->size.width = ceilf (res->size.width);
783 res->size.height = ceilf (res->size.height);
784 }
785
786 /**
787 * graphene_rect_round_extents:
788 * @r: a #graphene_rect_t
789 * @res: (out caller-allocates): return location for the
790 * rectangle with rounded extents
791 *
792 * Rounds the origin of the given rectangle to its nearest
793 * integer value and and recompute the size so that the
794 * rectangle is large enough to contain all the conrners
795 * of the original rectangle.
796 *
797 * This function is the equivalent of calling `floor` on
798 * the coordinates of the origin, and recomputing the size
799 * calling `ceil` on the bottom-right coordinates.
800 *
801 * If you want to be sure that the rounded rectangle
802 * completely covers the area that was covered by the
803 * original rectangle — i.e. you want to cover the area
804 * including all its corners — this function will make sure
805 * that the size is recomputed taking into account the ceiling
806 * of the coordinates of the bottom-right corner.
807 * If the difference between the original coordinates and the
808 * coordinates of the rounded rectangle is greater than the
809 * difference between the original size and and the rounded
810 * size, then the move of the origin would not be compensated
811 * by a move in the anti-origin, leaving the corners of the
812 * original rectangle outside the rounded one.
813 *
814 * Since: 1.10
815 */
816 void
graphene_rect_round_extents(const graphene_rect_t * r,graphene_rect_t * res)817 graphene_rect_round_extents (const graphene_rect_t *r,
818 graphene_rect_t *res)
819 {
820 float x2, y2;
821
822 graphene_rect_normalize_r (r, res);
823
824 x2 = res->origin.x + res->size.width;
825 y2 = res->origin.y + res->size.height;
826
827 res->origin.x = floorf (res->origin.x);
828 res->origin.y = floorf (res->origin.y);
829
830 res->size.width = ceilf (x2) - res->origin.x;
831 res->size.height = ceilf (y2) - res->origin.y;
832 }
833
834 /**
835 * graphene_rect_expand:
836 * @r: a #graphene_rect_t
837 * @p: a #graphene_point_t
838 * @res: (out caller-allocates): return location for the expanded rectangle
839 *
840 * Expands a #graphene_rect_t to contain the given #graphene_point_t.
841 *
842 * Since: 1.4
843 */
844 void
graphene_rect_expand(const graphene_rect_t * r,const graphene_point_t * p,graphene_rect_t * res)845 graphene_rect_expand (const graphene_rect_t *r,
846 const graphene_point_t *p,
847 graphene_rect_t *res)
848 {
849 graphene_rect_t tmp;
850
851 graphene_rect_init (&tmp, p->x, p->y, 0.f, 0.f);
852 graphene_rect_union (r, &tmp, res);
853
854 graphene_rect_normalize_in_place (res);
855 }
856
857 /**
858 * graphene_rect_interpolate:
859 * @a: a #graphene_rect_t
860 * @b: a #graphene_rect_t
861 * @factor: the linear interpolation factor
862 * @res: (out caller-allocates): return location for the
863 * interpolated rectangle
864 *
865 * Linearly interpolates the origin and size of the two given
866 * rectangles.
867 *
868 * Since: 1.0
869 */
870 void
graphene_rect_interpolate(const graphene_rect_t * a,const graphene_rect_t * b,double factor,graphene_rect_t * res)871 graphene_rect_interpolate (const graphene_rect_t *a,
872 const graphene_rect_t *b,
873 double factor,
874 graphene_rect_t *res)
875 {
876 graphene_rect_t ra, rb;
877
878 ra = *a;
879 graphene_rect_normalize_in_place (&ra);
880
881 rb = *b;
882 graphene_rect_normalize_in_place (&rb);
883
884 res->origin.x = graphene_lerp (ra.origin.x, rb.origin.x, factor);
885 res->origin.y = graphene_lerp (ra.origin.y, rb.origin.y, factor);
886 res->size.width = graphene_lerp (ra.size.width, rb.size.width, factor);
887 res->size.height = graphene_lerp (ra.size.height, rb.size.height, factor);
888 }
889
890 static const graphene_rect_t _graphene_rect_zero;
891
892 /**
893 * graphene_rect_zero:
894 *
895 * Returns a degenerate rectangle with origin fixed at (0, 0) and
896 * a size of 0, 0.
897 *
898 * Returns: (transfer none): a fixed rectangle
899 *
900 * Since: 1.4
901 */
902 const graphene_rect_t *
graphene_rect_zero(void)903 graphene_rect_zero (void)
904 {
905 return &_graphene_rect_zero;
906 }
907
908 /**
909 * graphene_rect_scale:
910 * @r: a #graphene_rect_t
911 * @s_h: horizontal scale factor
912 * @s_v: vertical scale factor
913 * @res: (out caller-allocates): return location for the
914 * scaled rectangle
915 *
916 * Scales the size and origin of a rectangle horizontaly by @s_h,
917 * and vertically by @s_v. The result @res is normalized.
918 *
919 * Since: 1.10
920 */
921 void
graphene_rect_scale(const graphene_rect_t * r,float s_h,float s_v,graphene_rect_t * res)922 graphene_rect_scale (const graphene_rect_t *r,
923 float s_h,
924 float s_v,
925 graphene_rect_t *res)
926 {
927 graphene_rect_normalize_r (r, res);
928
929 res->origin.x *= s_h;
930 res->origin.y *= s_v;
931 res->size.width *= s_h;
932 res->size.height *= s_v;
933
934 graphene_rect_normalize_r (res, res);
935 }
936