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