1 /* This file is part of GEGL
2  *
3  * GEGL is free software; you can redistribute it and/or
4  * modify it under the terms of the GNU Lesser General Public
5  * License as published by the Free Software Foundation; either
6  * version 3 of the License, or (at your option) any later version.
7  *
8  * GEGL is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11  * Lesser General Public License for more details.
12  *
13  * You should have received a copy of the GNU Lesser General Public
14  * License along with GEGL; if not, see <https://www.gnu.org/licenses/>.
15  *
16  * Copyright 2003-2007 Calvin Williamson, Øyvind Kolås.
17  */
18 
19 #include "config.h"
20 
21 #include <string.h>
22 #include <glib-object.h>
23 #include "gegl-buffer.h"
24 #include "gegl-buffer-private.h"
25 #include "gegl-rectangle.h"
26 
27 GeglRectangle *
gegl_rectangle_new(gint x,gint y,guint w,guint h)28 gegl_rectangle_new (gint           x,
29                     gint           y,
30                     guint          w,
31                     guint          h)
32 {
33   GeglRectangle *r = g_new (GeglRectangle, 1);
34 
35   r->x      = x;
36   r->y      = y;
37   r->width  = w;
38   r->height = h;
39 
40   return r;
41 }
42 
43 void
gegl_rectangle_set(GeglRectangle * r,gint x,gint y,guint w,guint h)44 gegl_rectangle_set (GeglRectangle *r,
45                     gint           x,
46                     gint           y,
47                     guint          w,
48                     guint          h)
49 {
50   r->x      = x;
51   r->y      = y;
52   r->width  = w;
53   r->height = h;
54 }
55 
56 gboolean
gegl_rectangle_align(GeglRectangle * dest,const GeglRectangle * rectangle,const GeglRectangle * tile,GeglRectangleAlignment alignment)57 gegl_rectangle_align (GeglRectangle          *dest,
58                       const GeglRectangle    *rectangle,
59                       const GeglRectangle    *tile,
60                       GeglRectangleAlignment  alignment)
61 {
62   gint x1, x2;
63   gint y1, y2;
64 
65   x1 = rectangle->x - tile->x;
66   x2 = x1 + rectangle->width;
67 
68   y1 = rectangle->y - tile->y;
69   y2 = y1 + rectangle->height;
70 
71   switch (alignment)
72     {
73     case GEGL_RECTANGLE_ALIGNMENT_SUBSET:
74       if (x1 > 0) x1 += tile->width  - 1;
75       if (x2 < 0) x2 -= tile->width  - 1;
76 
77       if (y1 > 0) y1 += tile->height - 1;
78       if (y2 < 0) y2 -= tile->height - 1;
79 
80       break;
81 
82     case GEGL_RECTANGLE_ALIGNMENT_SUPERSET:
83       if (x1 < 0) x1 -= tile->width  - 1;
84       if (x2 > 0) x2 += tile->width  - 1;
85 
86       if (y1 < 0) y1 -= tile->height - 1;
87       if (y2 > 0) y2 += tile->height - 1;
88 
89       break;
90 
91     case GEGL_RECTANGLE_ALIGNMENT_NEAREST:
92       if (x1 > 0) x1 += tile->width  / 2;
93       else        x1 -= tile->width  / 2 - 1;
94       if (x2 > 0) x2 += tile->width  / 2;
95       else        x2 -= tile->width  / 2 - 1;
96 
97       if (y1 > 0) y1 += tile->height / 2;
98       else        y1 -= tile->height / 2 - 1;
99       if (y2 > 0) y2 += tile->height / 2;
100       else        y2 -= tile->height / 2 - 1;
101 
102       break;
103     }
104 
105   if (tile->width)
106     {
107       x1 = x1 / tile->width  * tile->width;
108       x2 = x2 / tile->width  * tile->width;
109     }
110   if (tile->height)
111     {
112       y1 = y1 / tile->height * tile->height;
113       y2 = y2 / tile->height * tile->height;
114     }
115 
116   if (x1 < x2 && y1 < y2)
117     {
118       if (dest)
119         {
120           gegl_rectangle_set (dest,
121                               tile->x + x1,
122                               tile->y + y1,
123                               x2 - x1,
124                               y2 - y1);
125         }
126 
127       return TRUE;
128     }
129   else
130     {
131       if (dest)
132         gegl_rectangle_set (dest, 0, 0, 0, 0);
133 
134       return FALSE;
135     }
136 }
137 
138 gboolean
gegl_rectangle_align_to_buffer(GeglRectangle * dest,const GeglRectangle * rectangle,GeglBuffer * buffer,GeglRectangleAlignment alignment)139 gegl_rectangle_align_to_buffer (GeglRectangle          *dest,
140                                 const GeglRectangle    *rectangle,
141                                 GeglBuffer             *buffer,
142                                 GeglRectangleAlignment  alignment)
143 {
144   return gegl_rectangle_align (dest, rectangle,
145                                GEGL_RECTANGLE (buffer->shift_x,
146                                                buffer->shift_y,
147                                                buffer->tile_width,
148                                                buffer->tile_height),
149                                alignment);
150 }
151 
152 void
gegl_rectangle_bounding_box(GeglRectangle * dest,const GeglRectangle * src1,const GeglRectangle * src2)153 gegl_rectangle_bounding_box (GeglRectangle       *dest,
154                              const GeglRectangle *src1,
155                              const GeglRectangle *src2)
156 {
157   gboolean s1_has_area = src1->width && src1->height;
158   gboolean s2_has_area = src2->width && src2->height;
159 
160   if (!s1_has_area && !s2_has_area)
161     gegl_rectangle_set (dest, 0, 0, 0, 0);
162   else if (!s1_has_area)
163     gegl_rectangle_copy (dest, src2);
164   else if (!s2_has_area)
165     gegl_rectangle_copy (dest, src1);
166   else
167     {
168       gint x1 = MIN (src1->x, src2->x);
169       gint x2 = MAX (src1->x + src1->width, src2->x + src2->width);
170       gint y1 = MIN (src1->y, src2->y);
171       gint y2 = MAX (src1->y + src1->height, src2->y + src2->height);
172 
173       dest->x      = x1;
174       dest->y      = y1;
175       dest->width  = x2 - x1;
176       dest->height = y2 - y1;
177     }
178 }
179 
180 gboolean
gegl_rectangle_intersect(GeglRectangle * dest,const GeglRectangle * src1,const GeglRectangle * src2)181 gegl_rectangle_intersect (GeglRectangle       *dest,
182                           const GeglRectangle *src1,
183                           const GeglRectangle *src2)
184 {
185   gint x1, x2, y1, y2;
186 
187   x1 = MAX (src1->x, src2->x);
188   x2 = MIN (src1->x + src1->width, src2->x + src2->width);
189 
190   if (x2 <= x1)
191     {
192       if (dest)
193         gegl_rectangle_set (dest, 0, 0, 0, 0);
194       return FALSE;
195     }
196 
197   y1 = MAX (src1->y, src2->y);
198   y2 = MIN (src1->y + src1->height, src2->y + src2->height);
199 
200   if (y2 <= y1)
201     {
202       if (dest)
203         gegl_rectangle_set (dest, 0, 0, 0, 0);
204       return FALSE;
205     }
206 
207   if (dest)
208     gegl_rectangle_set (dest, x1, y1, x2 - x1, y2 - y1);
209   return TRUE;
210 }
211 
212 gint
gegl_rectangle_subtract(GeglRectangle dest[4],const GeglRectangle * minuend,const GeglRectangle * subtrahend)213 gegl_rectangle_subtract (GeglRectangle        dest[4],
214                          const GeglRectangle *minuend,
215                          const GeglRectangle *subtrahend)
216 {
217   gint mx1, mx2;
218   gint my1, my2;
219 
220   gint sx1, sx2;
221   gint sy1, sy2;
222 
223   gint n = 0;
224 
225   mx1 = minuend->x;
226   mx2 = minuend->x + minuend->width;
227   my1 = minuend->y;
228   my2 = minuend->y + minuend->height;
229 
230   sx1 = subtrahend->x;
231   sx2 = subtrahend->x + subtrahend->width;
232   sy1 = subtrahend->y;
233   sy2 = subtrahend->y + subtrahend->height;
234 
235   if (sx2 <= mx1 || sx1 >= mx2 || sy2 <= my1 || sy1 >= my2)
236     {
237       dest[0] = *minuend;
238 
239       return 1;
240     }
241 
242   if (sy1 > my1)
243     {
244       gegl_rectangle_set (&dest[n++], mx1, my1, mx2 - mx1, sy1 - my1);
245 
246       my1 = sy1;
247     }
248 
249   if (sy2 < my2)
250     {
251       gegl_rectangle_set (&dest[n++], mx1, sy2, mx2 - mx1, my2 - sy2);
252 
253       my2 = sy2;
254     }
255 
256   if (sx1 > mx1)
257     {
258       gegl_rectangle_set (&dest[n++], mx1, my1, sx1 - mx1, my2 - my1);
259 
260       mx1 = sx1;
261     }
262 
263   if (sx2 < mx2)
264     {
265       gegl_rectangle_set (&dest[n++], sx2, my1, mx2 - sx2, my2 - my1);
266 
267       mx2 = sx2;
268     }
269 
270   return n;
271 }
272 
273 gboolean
gegl_rectangle_subtract_bounding_box(GeglRectangle * dest,const GeglRectangle * minuend,const GeglRectangle * subtrahend)274 gegl_rectangle_subtract_bounding_box (GeglRectangle       *dest,
275                                       const GeglRectangle *minuend,
276                                       const GeglRectangle *subtrahend)
277 {
278   gint mx1, mx2;
279   gint my1, my2;
280 
281   gint sx1, sx2;
282   gint sy1, sy2;
283 
284   mx1 = minuend->x;
285   mx2 = minuend->x + minuend->width;
286   my1 = minuend->y;
287   my2 = minuend->y + minuend->height;
288 
289   sx1 = subtrahend->x;
290   sx2 = subtrahend->x + subtrahend->width;
291   sy1 = subtrahend->y;
292   sy2 = subtrahend->y + subtrahend->height;
293 
294   if (sx1 <= mx1 && sx2 >= mx2)
295     {
296       if (sy1 <= my1) my1 = MAX (my1, sy2);
297       if (sy2 >= my2) my2 = MIN (my2, sy1);
298     }
299   else if (sy1 <= my1 && sy2 >= my2)
300     {
301       if (sx1 <= mx1) mx1 = MAX (mx1, sx2);
302       if (sx2 >= mx2) mx2 = MIN (mx2, sx1);
303     }
304 
305   if (mx1 < mx2 && my1 < my2)
306     {
307       if (dest)
308         gegl_rectangle_set (dest, mx1, my1, mx2 - mx1, my2 - my1);
309       return TRUE;
310     }
311   else
312     {
313       if (dest)
314         gegl_rectangle_set (dest, 0, 0, 0, 0);
315       return FALSE;
316     }
317 }
318 
319 gint
gegl_rectangle_xor(GeglRectangle dest[4],const GeglRectangle * src1,const GeglRectangle * src2)320 gegl_rectangle_xor (GeglRectangle        dest[4],
321                     const GeglRectangle *src1,
322                     const GeglRectangle *src2)
323 {
324   GeglRectangle rect1 = *src1;
325   GeglRectangle rect2 = *src2;
326   gint          n;
327 
328   n  = gegl_rectangle_subtract (dest,     &rect1, &rect2);
329   n += gegl_rectangle_subtract (dest + n, &rect2, &rect1);
330 
331   return n;
332 }
333 
334 void
gegl_rectangle_copy(GeglRectangle * to,const GeglRectangle * from)335 gegl_rectangle_copy (GeglRectangle       *to,
336                      const GeglRectangle *from)
337 {
338   to->x      = from->x;
339   to->y      = from->y;
340   to->width  = from->width;
341   to->height = from->height;
342 }
343 
344 gboolean
gegl_rectangle_contains(const GeglRectangle * r,const GeglRectangle * s)345 gegl_rectangle_contains (const GeglRectangle *r,
346                          const GeglRectangle *s)
347 {
348   g_return_val_if_fail (r && s, FALSE);
349 
350   if (s->x >= r->x &&
351       s->y >= r->y &&
352       (s->x + s->width) <= (r->x + r->width) &&
353       (s->y + s->height) <= (r->y + r->height))
354     return TRUE;
355   else
356     return FALSE;
357 }
358 
359 gboolean
gegl_rectangle_equal(const GeglRectangle * r,const GeglRectangle * s)360 gegl_rectangle_equal (const GeglRectangle *r,
361                       const GeglRectangle *s)
362 {
363   g_return_val_if_fail (r && s, FALSE);
364 
365   if (r->x == s->x &&
366       r->y == s->y &&
367       r->width == s->width &&
368       r->height == s->height)
369     return TRUE;
370   else
371     return FALSE;
372 }
373 
374 gboolean
gegl_rectangle_equal_coords(const GeglRectangle * r,gint x,gint y,gint w,gint h)375 gegl_rectangle_equal_coords (const GeglRectangle *r,
376                              gint                 x,
377                              gint                 y,
378                              gint                 w,
379                              gint                 h)
380 {
381   g_return_val_if_fail (r, FALSE);
382 
383   if (r->x == x &&
384       r->y == y &&
385       r->width == w &&
386       r->height == h)
387     return TRUE;
388   else
389     return FALSE;
390 }
391 
392 gboolean
gegl_rectangle_is_empty(const GeglRectangle * r)393 gegl_rectangle_is_empty (const GeglRectangle *r)
394 {
395   g_return_val_if_fail (r != NULL, FALSE);
396   return r->width == 0 || r->height == 0;
397 }
398 
399 GeglRectangle *
gegl_rectangle_dup(const GeglRectangle * rectangle)400 gegl_rectangle_dup (const GeglRectangle *rectangle)
401 {
402   GeglRectangle *result = g_new (GeglRectangle, 1);
403 
404   *result = *rectangle;
405 
406   return result;
407 }
408 
409 GeglRectangle
gegl_rectangle_infinite_plane(void)410 gegl_rectangle_infinite_plane (void)
411 {
412   GeglRectangle infinite_plane_rect = {G_MININT / 2, G_MININT / 2, G_MAXINT, G_MAXINT};
413   return infinite_plane_rect;
414 }
415 
416 gboolean
gegl_rectangle_is_infinite_plane(const GeglRectangle * rectangle)417 gegl_rectangle_is_infinite_plane (const GeglRectangle *rectangle)
418 {
419   return (rectangle->x      == G_MININT / 2 &&
420           rectangle->y      == G_MININT / 2 &&
421           rectangle->width  == G_MAXINT     &&
422           rectangle->height == G_MAXINT);
423 }
424 
425 void
gegl_rectangle_dump(const GeglRectangle * rectangle)426 gegl_rectangle_dump (const GeglRectangle *rectangle)
427 {
428   g_print ("%d, %d, %d×%d\n",
429            rectangle->x,
430            rectangle->y,
431            rectangle->width,
432            rectangle->height);
433 }
434 
435 GType
gegl_rectangle_get_type(void)436 gegl_rectangle_get_type (void)
437 {
438   static GType our_type = 0;
439 
440   if (our_type == 0)
441     our_type = g_boxed_type_register_static (g_intern_static_string ("GeglRectangle"),
442                                              (GBoxedCopyFunc) gegl_rectangle_dup,
443                                              (GBoxedFreeFunc) g_free);
444   return our_type;
445 }
446 
447 gint
_gegl_float_epsilon_zero(float value)448 _gegl_float_epsilon_zero (float value)
449 {
450   return value > -GEGL_FLOAT_EPSILON && value < GEGL_FLOAT_EPSILON;
451 }
452 
453 gint
_gegl_float_epsilon_equal(float v1,float v2)454 _gegl_float_epsilon_equal (float v1, float v2)
455 {
456   register float diff = v1 - v2;
457 
458   return diff > -GEGL_FLOAT_EPSILON && diff < GEGL_FLOAT_EPSILON;
459 }
460 
461