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