1 /*
2 * This program is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU General Public License
4 * as published by the Free Software Foundation; either version 2
5 * of the License, or (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software Foundation,
14 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15 *
16 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
17 * All rights reserved.
18 */
19
20 /** \file
21 * \ingroup bli
22 *
23 * A minimalist lib for functions doing stuff with rectangle structs.
24 */
25
26 #include <math.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29
30 #include <float.h>
31 #include <limits.h>
32
33 #include "BLI_rect.h"
34 #include "BLI_utildefines.h"
35
36 #include "DNA_vec_types.h"
37
38 /* avoid including BLI_math */
39 static void unit_m4(float m[4][4]);
40
41 /**
42 * Determine if a rect is empty. An empty
43 * rect is one with a zero (or negative)
44 * width or height.
45 *
46 * \return True if \a rect is empty.
47 */
BLI_rcti_is_empty(const rcti * rect)48 bool BLI_rcti_is_empty(const rcti *rect)
49 {
50 return ((rect->xmax <= rect->xmin) || (rect->ymax <= rect->ymin));
51 }
52
BLI_rctf_is_empty(const rctf * rect)53 bool BLI_rctf_is_empty(const rctf *rect)
54 {
55 return ((rect->xmax <= rect->xmin) || (rect->ymax <= rect->ymin));
56 }
57
BLI_rcti_isect_x(const rcti * rect,const int x)58 bool BLI_rcti_isect_x(const rcti *rect, const int x)
59 {
60 if (x < rect->xmin) {
61 return false;
62 }
63 if (x > rect->xmax) {
64 return false;
65 }
66 return true;
67 }
68
BLI_rcti_isect_y(const rcti * rect,const int y)69 bool BLI_rcti_isect_y(const rcti *rect, const int y)
70 {
71 if (y < rect->ymin) {
72 return false;
73 }
74 if (y > rect->ymax) {
75 return false;
76 }
77 return true;
78 }
79
BLI_rcti_isect_pt(const rcti * rect,const int x,const int y)80 bool BLI_rcti_isect_pt(const rcti *rect, const int x, const int y)
81 {
82 if (x < rect->xmin) {
83 return false;
84 }
85 if (x > rect->xmax) {
86 return false;
87 }
88 if (y < rect->ymin) {
89 return false;
90 }
91 if (y > rect->ymax) {
92 return false;
93 }
94 return true;
95 }
96
BLI_rcti_isect_pt_v(const rcti * rect,const int xy[2])97 bool BLI_rcti_isect_pt_v(const rcti *rect, const int xy[2])
98 {
99 if (xy[0] < rect->xmin) {
100 return false;
101 }
102 if (xy[0] > rect->xmax) {
103 return false;
104 }
105 if (xy[1] < rect->ymin) {
106 return false;
107 }
108 if (xy[1] > rect->ymax) {
109 return false;
110 }
111 return true;
112 }
113
BLI_rctf_isect_x(const rctf * rect,const float x)114 bool BLI_rctf_isect_x(const rctf *rect, const float x)
115 {
116 if (x < rect->xmin) {
117 return false;
118 }
119 if (x > rect->xmax) {
120 return false;
121 }
122 return true;
123 }
124
BLI_rctf_isect_y(const rctf * rect,const float y)125 bool BLI_rctf_isect_y(const rctf *rect, const float y)
126 {
127 if (y < rect->ymin) {
128 return false;
129 }
130 if (y > rect->ymax) {
131 return false;
132 }
133 return true;
134 }
135
BLI_rctf_isect_pt(const rctf * rect,const float x,const float y)136 bool BLI_rctf_isect_pt(const rctf *rect, const float x, const float y)
137 {
138 if (x < rect->xmin) {
139 return false;
140 }
141 if (x > rect->xmax) {
142 return false;
143 }
144 if (y < rect->ymin) {
145 return false;
146 }
147 if (y > rect->ymax) {
148 return false;
149 }
150 return true;
151 }
152
BLI_rctf_isect_pt_v(const rctf * rect,const float xy[2])153 bool BLI_rctf_isect_pt_v(const rctf *rect, const float xy[2])
154 {
155 if (xy[0] < rect->xmin) {
156 return false;
157 }
158 if (xy[0] > rect->xmax) {
159 return false;
160 }
161 if (xy[1] < rect->ymin) {
162 return false;
163 }
164 if (xy[1] > rect->ymax) {
165 return false;
166 }
167 return true;
168 }
169
170 /**
171 * \returns shortest distance from \a rect to x/y (0 if inside)
172 */
173
BLI_rcti_length_x(const rcti * rect,const int x)174 int BLI_rcti_length_x(const rcti *rect, const int x)
175 {
176 if (x < rect->xmin) {
177 return rect->xmin - x;
178 }
179 if (x > rect->xmax) {
180 return x - rect->xmax;
181 }
182 return 0;
183 }
184
BLI_rcti_length_y(const rcti * rect,const int y)185 int BLI_rcti_length_y(const rcti *rect, const int y)
186 {
187 if (y < rect->ymin) {
188 return rect->ymin - y;
189 }
190 if (y > rect->ymax) {
191 return y - rect->ymax;
192 }
193 return 0;
194 }
195
BLI_rctf_length_x(const rctf * rect,const float x)196 float BLI_rctf_length_x(const rctf *rect, const float x)
197 {
198 if (x < rect->xmin) {
199 return rect->xmin - x;
200 }
201 if (x > rect->xmax) {
202 return x - rect->xmax;
203 }
204 return 0.0f;
205 }
206
BLI_rctf_length_y(const rctf * rect,const float y)207 float BLI_rctf_length_y(const rctf *rect, const float y)
208 {
209 if (y < rect->ymin) {
210 return rect->ymin - y;
211 }
212 if (y > rect->ymax) {
213 return y - rect->ymax;
214 }
215 return 0.0f;
216 }
217
218 /**
219 * is \a rct_b inside \a rct_a
220 */
BLI_rctf_inside_rctf(const rctf * rct_a,const rctf * rct_b)221 bool BLI_rctf_inside_rctf(const rctf *rct_a, const rctf *rct_b)
222 {
223 return ((rct_a->xmin <= rct_b->xmin) && (rct_a->xmax >= rct_b->xmax) &&
224 (rct_a->ymin <= rct_b->ymin) && (rct_a->ymax >= rct_b->ymax));
225 }
BLI_rcti_inside_rcti(const rcti * rct_a,const rcti * rct_b)226 bool BLI_rcti_inside_rcti(const rcti *rct_a, const rcti *rct_b)
227 {
228 return ((rct_a->xmin <= rct_b->xmin) && (rct_a->xmax >= rct_b->xmax) &&
229 (rct_a->ymin <= rct_b->ymin) && (rct_a->ymax >= rct_b->ymax));
230 }
231
232 /* based closely on 'isect_seg_seg_v2_int',
233 * but in modified so corner cases are treated as intersections */
isect_segments_i(const int v1[2],const int v2[2],const int v3[2],const int v4[2])234 static int isect_segments_i(const int v1[2], const int v2[2], const int v3[2], const int v4[2])
235 {
236 const double div = (double)((v2[0] - v1[0]) * (v4[1] - v3[1]) -
237 (v2[1] - v1[1]) * (v4[0] - v3[0]));
238 if (div == 0.0) {
239 return 1; /* co-linear */
240 }
241
242 const double lambda = (double)((v1[1] - v3[1]) * (v4[0] - v3[0]) -
243 (v1[0] - v3[0]) * (v4[1] - v3[1])) /
244 div;
245 const double mu = (double)((v1[1] - v3[1]) * (v2[0] - v1[0]) -
246 (v1[0] - v3[0]) * (v2[1] - v1[1])) /
247 div;
248 return (lambda >= 0.0 && lambda <= 1.0 && mu >= 0.0 && mu <= 1.0);
249 }
isect_segments_fl(const float v1[2],const float v2[2],const float v3[2],const float v4[2])250 static int isect_segments_fl(const float v1[2],
251 const float v2[2],
252 const float v3[2],
253 const float v4[2])
254 {
255 const double div = (double)((v2[0] - v1[0]) * (v4[1] - v3[1]) -
256 (v2[1] - v1[1]) * (v4[0] - v3[0]));
257 if (div == 0.0) {
258 return 1; /* co-linear */
259 }
260
261 const double lambda = (double)((v1[1] - v3[1]) * (v4[0] - v3[0]) -
262 (v1[0] - v3[0]) * (v4[1] - v3[1])) /
263 div;
264 const double mu = (double)((v1[1] - v3[1]) * (v2[0] - v1[0]) -
265 (v1[0] - v3[0]) * (v2[1] - v1[1])) /
266 div;
267 return (lambda >= 0.0 && lambda <= 1.0 && mu >= 0.0 && mu <= 1.0);
268 }
269
BLI_rcti_isect_segment(const rcti * rect,const int s1[2],const int s2[2])270 bool BLI_rcti_isect_segment(const rcti *rect, const int s1[2], const int s2[2])
271 {
272 /* first do outside-bounds check for both points of the segment */
273 if (s1[0] < rect->xmin && s2[0] < rect->xmin) {
274 return false;
275 }
276 if (s1[0] > rect->xmax && s2[0] > rect->xmax) {
277 return false;
278 }
279 if (s1[1] < rect->ymin && s2[1] < rect->ymin) {
280 return false;
281 }
282 if (s1[1] > rect->ymax && s2[1] > rect->ymax) {
283 return false;
284 }
285
286 /* if either points intersect then we definitely intersect */
287 if (BLI_rcti_isect_pt_v(rect, s1) || BLI_rcti_isect_pt_v(rect, s2)) {
288 return true;
289 }
290
291 /* both points are outside but may intersect the rect */
292 int tvec1[2];
293 int tvec2[2];
294 /* diagonal: [/] */
295 tvec1[0] = rect->xmin;
296 tvec1[1] = rect->ymin;
297 tvec2[0] = rect->xmin;
298 tvec2[1] = rect->ymax;
299 if (isect_segments_i(s1, s2, tvec1, tvec2)) {
300 return true;
301 }
302
303 /* diagonal: [\] */
304 tvec1[0] = rect->xmin;
305 tvec1[1] = rect->ymax;
306 tvec2[0] = rect->xmax;
307 tvec2[1] = rect->ymin;
308 if (isect_segments_i(s1, s2, tvec1, tvec2)) {
309 return true;
310 }
311
312 /* no intersection */
313 return false;
314 }
315
BLI_rctf_isect_segment(const rctf * rect,const float s1[2],const float s2[2])316 bool BLI_rctf_isect_segment(const rctf *rect, const float s1[2], const float s2[2])
317 {
318 /* first do outside-bounds check for both points of the segment */
319 if (s1[0] < rect->xmin && s2[0] < rect->xmin) {
320 return false;
321 }
322 if (s1[0] > rect->xmax && s2[0] > rect->xmax) {
323 return false;
324 }
325 if (s1[1] < rect->ymin && s2[1] < rect->ymin) {
326 return false;
327 }
328 if (s1[1] > rect->ymax && s2[1] > rect->ymax) {
329 return false;
330 }
331
332 /* if either points intersect then we definitely intersect */
333 if (BLI_rctf_isect_pt_v(rect, s1) || BLI_rctf_isect_pt_v(rect, s2)) {
334 return true;
335 }
336
337 /* both points are outside but may intersect the rect */
338 float tvec1[2];
339 float tvec2[2];
340 /* diagonal: [/] */
341 tvec1[0] = rect->xmin;
342 tvec1[1] = rect->ymin;
343 tvec2[0] = rect->xmin;
344 tvec2[1] = rect->ymax;
345 if (isect_segments_fl(s1, s2, tvec1, tvec2)) {
346 return true;
347 }
348
349 /* diagonal: [\] */
350 tvec1[0] = rect->xmin;
351 tvec1[1] = rect->ymax;
352 tvec2[0] = rect->xmax;
353 tvec2[1] = rect->ymin;
354 if (isect_segments_fl(s1, s2, tvec1, tvec2)) {
355 return true;
356 }
357
358 /* no intersection */
359 return false;
360 }
361
BLI_rcti_isect_circle(const rcti * rect,const float xy[2],const float radius)362 bool BLI_rcti_isect_circle(const rcti *rect, const float xy[2], const float radius)
363 {
364 float dx, dy;
365
366 if (xy[0] >= rect->xmin && xy[0] <= rect->xmax) {
367 dx = 0;
368 }
369 else {
370 dx = (xy[0] < rect->xmin) ? (rect->xmin - xy[0]) : (xy[0] - rect->xmax);
371 }
372
373 if (xy[1] >= rect->ymin && xy[1] <= rect->ymax) {
374 dy = 0;
375 }
376 else {
377 dy = (xy[1] < rect->ymin) ? (rect->ymin - xy[1]) : (xy[1] - rect->ymax);
378 }
379
380 return dx * dx + dy * dy <= radius * radius;
381 }
382
BLI_rctf_isect_circle(const rctf * rect,const float xy[2],const float radius)383 bool BLI_rctf_isect_circle(const rctf *rect, const float xy[2], const float radius)
384 {
385 float dx, dy;
386
387 if (xy[0] >= rect->xmin && xy[0] <= rect->xmax) {
388 dx = 0;
389 }
390 else {
391 dx = (xy[0] < rect->xmin) ? (rect->xmin - xy[0]) : (xy[0] - rect->xmax);
392 }
393
394 if (xy[1] >= rect->ymin && xy[1] <= rect->ymax) {
395 dy = 0;
396 }
397 else {
398 dy = (xy[1] < rect->ymin) ? (rect->ymin - xy[1]) : (xy[1] - rect->ymax);
399 }
400
401 return dx * dx + dy * dy <= radius * radius;
402 }
403
BLI_rctf_union(rctf * rct1,const rctf * rct2)404 void BLI_rctf_union(rctf *rct1, const rctf *rct2)
405 {
406 if (rct1->xmin > rct2->xmin) {
407 rct1->xmin = rct2->xmin;
408 }
409 if (rct1->xmax < rct2->xmax) {
410 rct1->xmax = rct2->xmax;
411 }
412 if (rct1->ymin > rct2->ymin) {
413 rct1->ymin = rct2->ymin;
414 }
415 if (rct1->ymax < rct2->ymax) {
416 rct1->ymax = rct2->ymax;
417 }
418 }
419
BLI_rcti_union(rcti * rct1,const rcti * rct2)420 void BLI_rcti_union(rcti *rct1, const rcti *rct2)
421 {
422 if (rct1->xmin > rct2->xmin) {
423 rct1->xmin = rct2->xmin;
424 }
425 if (rct1->xmax < rct2->xmax) {
426 rct1->xmax = rct2->xmax;
427 }
428 if (rct1->ymin > rct2->ymin) {
429 rct1->ymin = rct2->ymin;
430 }
431 if (rct1->ymax < rct2->ymax) {
432 rct1->ymax = rct2->ymax;
433 }
434 }
435
BLI_rctf_init(rctf * rect,float xmin,float xmax,float ymin,float ymax)436 void BLI_rctf_init(rctf *rect, float xmin, float xmax, float ymin, float ymax)
437 {
438 rect->xmin = xmin;
439 rect->xmax = xmax;
440 rect->ymin = ymin;
441 rect->ymax = ymax;
442
443 BLI_rctf_sanitize(rect);
444 }
445
BLI_rcti_init(rcti * rect,int xmin,int xmax,int ymin,int ymax)446 void BLI_rcti_init(rcti *rect, int xmin, int xmax, int ymin, int ymax)
447 {
448 rect->xmin = xmin;
449 rect->xmax = xmax;
450 rect->ymin = ymin;
451 rect->ymax = ymax;
452
453 BLI_rcti_sanitize(rect);
454 }
455
456 /**
457 * Check if X-min and Y-min are less than or equal to X-max and Y-max, respectively.
458 * If this returns false, #BLI_rctf_sanitize() can be called to address this.
459 *
460 * This is not a hard constraint or invariant for rectangles, in some cases it may be useful to
461 * have max < min. Usually this is what you'd want though.
462 */
BLI_rctf_is_valid(const rctf * rect)463 bool BLI_rctf_is_valid(const rctf *rect)
464 {
465 return (rect->xmin <= rect->xmax) && (rect->ymin <= rect->ymax);
466 }
467
BLI_rcti_is_valid(const rcti * rect)468 bool BLI_rcti_is_valid(const rcti *rect)
469 {
470 return (rect->xmin <= rect->xmax) && (rect->ymin <= rect->ymax);
471 }
472
473 /**
474 * Ensure X-min and Y-min are less than or equal to X-max and Y-max, respectively.
475 */
BLI_rctf_sanitize(rctf * rect)476 void BLI_rctf_sanitize(rctf *rect)
477 {
478 if (rect->xmin > rect->xmax) {
479 SWAP(float, rect->xmin, rect->xmax);
480 }
481 if (rect->ymin > rect->ymax) {
482 SWAP(float, rect->ymin, rect->ymax);
483 }
484
485 BLI_assert(BLI_rctf_is_valid(rect));
486 }
487
BLI_rcti_sanitize(rcti * rect)488 void BLI_rcti_sanitize(rcti *rect)
489 {
490 if (rect->xmin > rect->xmax) {
491 SWAP(int, rect->xmin, rect->xmax);
492 }
493 if (rect->ymin > rect->ymax) {
494 SWAP(int, rect->ymin, rect->ymax);
495 }
496
497 BLI_assert(BLI_rcti_is_valid(rect));
498 }
499
BLI_rctf_init_pt_radius(rctf * rect,const float xy[2],float size)500 void BLI_rctf_init_pt_radius(rctf *rect, const float xy[2], float size)
501 {
502 rect->xmin = xy[0] - size;
503 rect->xmax = xy[0] + size;
504 rect->ymin = xy[1] - size;
505 rect->ymax = xy[1] + size;
506 }
507
BLI_rcti_init_pt_radius(rcti * rect,const int xy[2],int size)508 void BLI_rcti_init_pt_radius(rcti *rect, const int xy[2], int size)
509 {
510 rect->xmin = xy[0] - size;
511 rect->xmax = xy[0] + size;
512 rect->ymin = xy[1] - size;
513 rect->ymax = xy[1] + size;
514 }
515
BLI_rcti_init_minmax(rcti * rect)516 void BLI_rcti_init_minmax(rcti *rect)
517 {
518 rect->xmin = rect->ymin = INT_MAX;
519 rect->xmax = rect->ymax = INT_MIN;
520 }
521
BLI_rctf_init_minmax(rctf * rect)522 void BLI_rctf_init_minmax(rctf *rect)
523 {
524 rect->xmin = rect->ymin = FLT_MAX;
525 rect->xmax = rect->ymax = -FLT_MAX;
526 }
527
BLI_rcti_do_minmax_v(rcti * rect,const int xy[2])528 void BLI_rcti_do_minmax_v(rcti *rect, const int xy[2])
529 {
530 if (xy[0] < rect->xmin) {
531 rect->xmin = xy[0];
532 }
533 if (xy[0] > rect->xmax) {
534 rect->xmax = xy[0];
535 }
536 if (xy[1] < rect->ymin) {
537 rect->ymin = xy[1];
538 }
539 if (xy[1] > rect->ymax) {
540 rect->ymax = xy[1];
541 }
542 }
543
BLI_rctf_do_minmax_v(rctf * rect,const float xy[2])544 void BLI_rctf_do_minmax_v(rctf *rect, const float xy[2])
545 {
546 if (xy[0] < rect->xmin) {
547 rect->xmin = xy[0];
548 }
549 if (xy[0] > rect->xmax) {
550 rect->xmax = xy[0];
551 }
552 if (xy[1] < rect->ymin) {
553 rect->ymin = xy[1];
554 }
555 if (xy[1] > rect->ymax) {
556 rect->ymax = xy[1];
557 }
558 }
559
560 /* given 2 rectangles - transform a point from one to another */
BLI_rctf_transform_pt_v(const rctf * dst,const rctf * src,float xy_dst[2],const float xy_src[2])561 void BLI_rctf_transform_pt_v(const rctf *dst,
562 const rctf *src,
563 float xy_dst[2],
564 const float xy_src[2])
565 {
566 xy_dst[0] = ((xy_src[0] - src->xmin) / (src->xmax - src->xmin));
567 xy_dst[0] = dst->xmin + ((dst->xmax - dst->xmin) * xy_dst[0]);
568
569 xy_dst[1] = ((xy_src[1] - src->ymin) / (src->ymax - src->ymin));
570 xy_dst[1] = dst->ymin + ((dst->ymax - dst->ymin) * xy_dst[1]);
571 }
572
573 /**
574 * Calculate a 4x4 matrix representing the transformation between two rectangles.
575 *
576 * \note Multiplying a vector by this matrix does *not*
577 * give the same value as #BLI_rctf_transform_pt_v.
578 */
BLI_rctf_transform_calc_m4_pivot_min_ex(const rctf * dst,const rctf * src,float matrix[4][4],uint x,uint y)579 void BLI_rctf_transform_calc_m4_pivot_min_ex(
580 const rctf *dst, const rctf *src, float matrix[4][4], uint x, uint y)
581 {
582 BLI_assert(x < 3 && y < 3);
583
584 unit_m4(matrix);
585
586 matrix[x][x] = BLI_rctf_size_x(src) / BLI_rctf_size_x(dst);
587 matrix[y][y] = BLI_rctf_size_y(src) / BLI_rctf_size_y(dst);
588 matrix[3][x] = (src->xmin - dst->xmin) * matrix[x][x];
589 matrix[3][y] = (src->ymin - dst->ymin) * matrix[y][y];
590 }
591
BLI_rctf_transform_calc_m4_pivot_min(const rctf * dst,const rctf * src,float matrix[4][4])592 void BLI_rctf_transform_calc_m4_pivot_min(const rctf *dst, const rctf *src, float matrix[4][4])
593 {
594 BLI_rctf_transform_calc_m4_pivot_min_ex(dst, src, matrix, 0, 1);
595 }
596
BLI_rcti_translate(rcti * rect,int x,int y)597 void BLI_rcti_translate(rcti *rect, int x, int y)
598 {
599 rect->xmin += x;
600 rect->ymin += y;
601 rect->xmax += x;
602 rect->ymax += y;
603 }
BLI_rctf_translate(rctf * rect,float x,float y)604 void BLI_rctf_translate(rctf *rect, float x, float y)
605 {
606 rect->xmin += x;
607 rect->ymin += y;
608 rect->xmax += x;
609 rect->ymax += y;
610 }
611
BLI_rcti_recenter(rcti * rect,int x,int y)612 void BLI_rcti_recenter(rcti *rect, int x, int y)
613 {
614 const int dx = x - BLI_rcti_cent_x(rect);
615 const int dy = y - BLI_rcti_cent_y(rect);
616 BLI_rcti_translate(rect, dx, dy);
617 }
BLI_rctf_recenter(rctf * rect,float x,float y)618 void BLI_rctf_recenter(rctf *rect, float x, float y)
619 {
620 const float dx = x - BLI_rctf_cent_x(rect);
621 const float dy = y - BLI_rctf_cent_y(rect);
622 BLI_rctf_translate(rect, dx, dy);
623 }
624
625 /* change width & height around the central location */
BLI_rcti_resize_x(rcti * rect,int x)626 void BLI_rcti_resize_x(rcti *rect, int x)
627 {
628 rect->xmin = BLI_rcti_cent_x(rect) - (x / 2);
629 rect->xmax = rect->xmin + x;
630 }
631
BLI_rcti_resize_y(rcti * rect,int y)632 void BLI_rcti_resize_y(rcti *rect, int y)
633 {
634 rect->ymin = BLI_rcti_cent_y(rect) - (y / 2);
635 rect->ymax = rect->ymin + y;
636 }
637
BLI_rcti_resize(rcti * rect,int x,int y)638 void BLI_rcti_resize(rcti *rect, int x, int y)
639 {
640 rect->xmin = BLI_rcti_cent_x(rect) - (x / 2);
641 rect->ymin = BLI_rcti_cent_y(rect) - (y / 2);
642 rect->xmax = rect->xmin + x;
643 rect->ymax = rect->ymin + y;
644 }
645
BLI_rcti_pad(rcti * rect,int pad_x,int pad_y)646 void BLI_rcti_pad(rcti *rect, int pad_x, int pad_y)
647 {
648 rect->xmin -= pad_x;
649 rect->ymin -= pad_y;
650 rect->xmax += pad_x;
651 rect->ymax += pad_y;
652 }
653
BLI_rctf_pad(rctf * rect,float pad_x,float pad_y)654 void BLI_rctf_pad(rctf *rect, float pad_x, float pad_y)
655 {
656 rect->xmin -= pad_x;
657 rect->ymin -= pad_y;
658 rect->xmax += pad_x;
659 rect->ymax += pad_y;
660 }
661
BLI_rctf_resize_x(rctf * rect,float x)662 void BLI_rctf_resize_x(rctf *rect, float x)
663 {
664 rect->xmin = BLI_rctf_cent_x(rect) - (x * 0.5f);
665 rect->xmax = rect->xmin + x;
666 }
667
BLI_rctf_resize_y(rctf * rect,float y)668 void BLI_rctf_resize_y(rctf *rect, float y)
669 {
670 rect->ymin = BLI_rctf_cent_y(rect) - (y * 0.5f);
671 rect->ymax = rect->ymin + y;
672 }
673
BLI_rctf_resize(rctf * rect,float x,float y)674 void BLI_rctf_resize(rctf *rect, float x, float y)
675 {
676 rect->xmin = BLI_rctf_cent_x(rect) - (x * 0.5f);
677 rect->ymin = BLI_rctf_cent_y(rect) - (y * 0.5f);
678 rect->xmax = rect->xmin + x;
679 rect->ymax = rect->ymin + y;
680 }
681
BLI_rcti_scale(rcti * rect,const float scale)682 void BLI_rcti_scale(rcti *rect, const float scale)
683 {
684 const int cent_x = BLI_rcti_cent_x(rect);
685 const int cent_y = BLI_rcti_cent_y(rect);
686 const int size_x_half = BLI_rcti_size_x(rect) * (scale * 0.5f);
687 const int size_y_half = BLI_rcti_size_y(rect) * (scale * 0.5f);
688 rect->xmin = cent_x - size_x_half;
689 rect->ymin = cent_y - size_y_half;
690 rect->xmax = cent_x + size_x_half;
691 rect->ymax = cent_y + size_y_half;
692 }
693
BLI_rctf_scale(rctf * rect,const float scale)694 void BLI_rctf_scale(rctf *rect, const float scale)
695 {
696 const float cent_x = BLI_rctf_cent_x(rect);
697 const float cent_y = BLI_rctf_cent_y(rect);
698 const float size_x_half = BLI_rctf_size_x(rect) * (scale * 0.5f);
699 const float size_y_half = BLI_rctf_size_y(rect) * (scale * 0.5f);
700 rect->xmin = cent_x - size_x_half;
701 rect->ymin = cent_y - size_y_half;
702 rect->xmax = cent_x + size_x_half;
703 rect->ymax = cent_y + size_y_half;
704 }
705
BLI_rctf_pad_y(rctf * rect,const float boundary_size,const float pad_min,const float pad_max)706 void BLI_rctf_pad_y(rctf *rect,
707 const float boundary_size,
708 const float pad_min,
709 const float pad_max)
710 {
711 BLI_assert(pad_max >= 0.0f);
712 BLI_assert(pad_min >= 0.0f);
713 BLI_assert(boundary_size > 0.0f);
714
715 float total_pad = pad_max + pad_min;
716 if (total_pad == 0.0f) {
717 return;
718 }
719
720 float total_extend = BLI_rctf_size_y(rect) * total_pad / (boundary_size - total_pad);
721 rect->ymax += total_extend * (pad_max / total_pad);
722 rect->ymin -= total_extend * (pad_min / total_pad);
723 }
724
BLI_rctf_interp(rctf * rect,const rctf * rect_a,const rctf * rect_b,const float fac)725 void BLI_rctf_interp(rctf *rect, const rctf *rect_a, const rctf *rect_b, const float fac)
726 {
727 const float ifac = 1.0f - fac;
728 rect->xmin = (rect_a->xmin * ifac) + (rect_b->xmin * fac);
729 rect->xmax = (rect_a->xmax * ifac) + (rect_b->xmax * fac);
730 rect->ymin = (rect_a->ymin * ifac) + (rect_b->ymin * fac);
731 rect->ymax = (rect_a->ymax * ifac) + (rect_b->ymax * fac);
732 }
733
734 /* BLI_rcti_interp() not needed yet */
735
BLI_rctf_clamp_pt_v(const rctf * rect,float xy[2])736 bool BLI_rctf_clamp_pt_v(const rctf *rect, float xy[2])
737 {
738 bool changed = false;
739 if (xy[0] < rect->xmin) {
740 xy[0] = rect->xmin;
741 changed = true;
742 }
743 if (xy[0] > rect->xmax) {
744 xy[0] = rect->xmax;
745 changed = true;
746 }
747 if (xy[1] < rect->ymin) {
748 xy[1] = rect->ymin;
749 changed = true;
750 }
751 if (xy[1] > rect->ymax) {
752 xy[1] = rect->ymax;
753 changed = true;
754 }
755 return changed;
756 }
757
BLI_rcti_clamp_pt_v(const rcti * rect,int xy[2])758 bool BLI_rcti_clamp_pt_v(const rcti *rect, int xy[2])
759 {
760 bool changed = false;
761 if (xy[0] < rect->xmin) {
762 xy[0] = rect->xmin;
763 changed = true;
764 }
765 if (xy[0] > rect->xmax) {
766 xy[0] = rect->xmax;
767 changed = true;
768 }
769 if (xy[1] < rect->ymin) {
770 xy[1] = rect->ymin;
771 changed = true;
772 }
773 if (xy[1] > rect->ymax) {
774 xy[1] = rect->ymax;
775 changed = true;
776 }
777 return changed;
778 }
779
780 /**
781 * Clamp \a rect within \a rect_bounds, setting \a r_xy to the offset.
782 *
783 * Keeps the top left corner within the bounds, which for user interface
784 * elements is typically where the most important information is.
785 *
786 * \return true if a change is made.
787 */
BLI_rctf_clamp(rctf * rect,const rctf * rect_bounds,float r_xy[2])788 bool BLI_rctf_clamp(rctf *rect, const rctf *rect_bounds, float r_xy[2])
789 {
790 bool changed = false;
791
792 r_xy[0] = 0.0f;
793 r_xy[1] = 0.0f;
794
795 if (rect->xmax > rect_bounds->xmax) {
796 float ofs = rect_bounds->xmax - rect->xmax;
797 rect->xmin += ofs;
798 rect->xmax += ofs;
799 r_xy[0] += ofs;
800 changed = true;
801 }
802
803 if (rect->xmin < rect_bounds->xmin) {
804 float ofs = rect_bounds->xmin - rect->xmin;
805 rect->xmin += ofs;
806 rect->xmax += ofs;
807 r_xy[0] += ofs;
808 changed = true;
809 }
810
811 if (rect->ymin < rect_bounds->ymin) {
812 float ofs = rect_bounds->ymin - rect->ymin;
813 rect->ymin += ofs;
814 rect->ymax += ofs;
815 r_xy[1] += ofs;
816 changed = true;
817 }
818
819 if (rect->ymax > rect_bounds->ymax) {
820 float ofs = rect_bounds->ymax - rect->ymax;
821 rect->ymin += ofs;
822 rect->ymax += ofs;
823 r_xy[1] += ofs;
824 changed = true;
825 }
826
827 return changed;
828 }
829
BLI_rcti_clamp(rcti * rect,const rcti * rect_bounds,int r_xy[2])830 bool BLI_rcti_clamp(rcti *rect, const rcti *rect_bounds, int r_xy[2])
831 {
832 bool changed = false;
833
834 r_xy[0] = 0;
835 r_xy[1] = 0;
836
837 if (rect->xmax > rect_bounds->xmax) {
838 int ofs = rect_bounds->xmax - rect->xmax;
839 rect->xmin += ofs;
840 rect->xmax += ofs;
841 r_xy[0] += ofs;
842 changed = true;
843 }
844
845 if (rect->xmin < rect_bounds->xmin) {
846 int ofs = rect_bounds->xmin - rect->xmin;
847 rect->xmin += ofs;
848 rect->xmax += ofs;
849 r_xy[0] += ofs;
850 changed = true;
851 }
852
853 if (rect->ymin < rect_bounds->ymin) {
854 int ofs = rect_bounds->ymin - rect->ymin;
855 rect->ymin += ofs;
856 rect->ymax += ofs;
857 r_xy[1] += ofs;
858 changed = true;
859 }
860
861 if (rect->ymax > rect_bounds->ymax) {
862 int ofs = rect_bounds->ymax - rect->ymax;
863 rect->ymin += ofs;
864 rect->ymax += ofs;
865 r_xy[1] += ofs;
866 changed = true;
867 }
868
869 return changed;
870 }
871
BLI_rctf_compare(const rctf * rect_a,const rctf * rect_b,const float limit)872 bool BLI_rctf_compare(const rctf *rect_a, const rctf *rect_b, const float limit)
873 {
874 if (fabsf(rect_a->xmin - rect_b->xmin) < limit) {
875 if (fabsf(rect_a->xmax - rect_b->xmax) < limit) {
876 if (fabsf(rect_a->ymin - rect_b->ymin) < limit) {
877 if (fabsf(rect_a->ymax - rect_b->ymax) < limit) {
878 return true;
879 }
880 }
881 }
882 }
883
884 return false;
885 }
886
BLI_rcti_compare(const rcti * rect_a,const rcti * rect_b)887 bool BLI_rcti_compare(const rcti *rect_a, const rcti *rect_b)
888 {
889 if (rect_a->xmin == rect_b->xmin) {
890 if (rect_a->xmax == rect_b->xmax) {
891 if (rect_a->ymin == rect_b->ymin) {
892 if (rect_a->ymax == rect_b->ymax) {
893 return true;
894 }
895 }
896 }
897 }
898
899 return false;
900 }
901
BLI_rctf_isect(const rctf * src1,const rctf * src2,rctf * dest)902 bool BLI_rctf_isect(const rctf *src1, const rctf *src2, rctf *dest)
903 {
904 float xmin, xmax;
905 float ymin, ymax;
906
907 xmin = (src1->xmin) > (src2->xmin) ? (src1->xmin) : (src2->xmin);
908 xmax = (src1->xmax) < (src2->xmax) ? (src1->xmax) : (src2->xmax);
909 ymin = (src1->ymin) > (src2->ymin) ? (src1->ymin) : (src2->ymin);
910 ymax = (src1->ymax) < (src2->ymax) ? (src1->ymax) : (src2->ymax);
911
912 if (xmax >= xmin && ymax >= ymin) {
913 if (dest) {
914 dest->xmin = xmin;
915 dest->xmax = xmax;
916 dest->ymin = ymin;
917 dest->ymax = ymax;
918 }
919 return true;
920 }
921
922 if (dest) {
923 dest->xmin = 0;
924 dest->xmax = 0;
925 dest->ymin = 0;
926 dest->ymax = 0;
927 }
928 return false;
929 }
930
BLI_rcti_isect(const rcti * src1,const rcti * src2,rcti * dest)931 bool BLI_rcti_isect(const rcti *src1, const rcti *src2, rcti *dest)
932 {
933 int xmin, xmax;
934 int ymin, ymax;
935
936 xmin = (src1->xmin) > (src2->xmin) ? (src1->xmin) : (src2->xmin);
937 xmax = (src1->xmax) < (src2->xmax) ? (src1->xmax) : (src2->xmax);
938 ymin = (src1->ymin) > (src2->ymin) ? (src1->ymin) : (src2->ymin);
939 ymax = (src1->ymax) < (src2->ymax) ? (src1->ymax) : (src2->ymax);
940
941 if (xmax >= xmin && ymax >= ymin) {
942 if (dest) {
943 dest->xmin = xmin;
944 dest->xmax = xmax;
945 dest->ymin = ymin;
946 dest->ymax = ymax;
947 }
948 return true;
949 }
950
951 if (dest) {
952 dest->xmin = 0;
953 dest->xmax = 0;
954 dest->ymin = 0;
955 dest->ymax = 0;
956 }
957 return false;
958 }
959
BLI_rctf_isect_rect_x(const rctf * src1,const rctf * src2,float range_x[2])960 bool BLI_rctf_isect_rect_x(const rctf *src1, const rctf *src2, float range_x[2])
961 {
962 const float xmin = (src1->xmin) > (src2->xmin) ? (src1->xmin) : (src2->xmin);
963 const float xmax = (src1->xmax) < (src2->xmax) ? (src1->xmax) : (src2->xmax);
964
965 if (xmax >= xmin) {
966 if (range_x) {
967 range_x[0] = xmin;
968 range_x[1] = xmax;
969 }
970 return true;
971 }
972
973 if (range_x) {
974 range_x[0] = 0;
975 range_x[1] = 0;
976 }
977 return false;
978 }
979
BLI_rctf_isect_rect_y(const rctf * src1,const rctf * src2,float range_y[2])980 bool BLI_rctf_isect_rect_y(const rctf *src1, const rctf *src2, float range_y[2])
981 {
982 const float ymin = (src1->ymin) > (src2->ymin) ? (src1->ymin) : (src2->ymin);
983 const float ymax = (src1->ymax) < (src2->ymax) ? (src1->ymax) : (src2->ymax);
984
985 if (ymax >= ymin) {
986 if (range_y) {
987 range_y[0] = ymin;
988 range_y[1] = ymax;
989 }
990 return true;
991 }
992
993 if (range_y) {
994 range_y[0] = 0;
995 range_y[1] = 0;
996 }
997 return false;
998 }
999
BLI_rcti_isect_rect_x(const rcti * src1,const rcti * src2,int range_x[2])1000 bool BLI_rcti_isect_rect_x(const rcti *src1, const rcti *src2, int range_x[2])
1001 {
1002 const int xmin = (src1->xmin) > (src2->xmin) ? (src1->xmin) : (src2->xmin);
1003 const int xmax = (src1->xmax) < (src2->xmax) ? (src1->xmax) : (src2->xmax);
1004
1005 if (xmax >= xmin) {
1006 if (range_x) {
1007 range_x[0] = xmin;
1008 range_x[1] = xmax;
1009 }
1010 return true;
1011 }
1012
1013 if (range_x) {
1014 range_x[0] = 0;
1015 range_x[1] = 0;
1016 }
1017 return false;
1018 }
1019
BLI_rcti_isect_rect_y(const rcti * src1,const rcti * src2,int range_y[2])1020 bool BLI_rcti_isect_rect_y(const rcti *src1, const rcti *src2, int range_y[2])
1021 {
1022 const int ymin = (src1->ymin) > (src2->ymin) ? (src1->ymin) : (src2->ymin);
1023 const int ymax = (src1->ymax) < (src2->ymax) ? (src1->ymax) : (src2->ymax);
1024
1025 if (ymax >= ymin) {
1026 if (range_y) {
1027 range_y[0] = ymin;
1028 range_y[1] = ymax;
1029 }
1030 return true;
1031 }
1032
1033 if (range_y) {
1034 range_y[0] = 0;
1035 range_y[1] = 0;
1036 }
1037 return false;
1038 }
1039
BLI_rcti_rctf_copy(rcti * dst,const rctf * src)1040 void BLI_rcti_rctf_copy(rcti *dst, const rctf *src)
1041 {
1042 dst->xmin = floorf(src->xmin + 0.5f);
1043 dst->xmax = dst->xmin + floorf(BLI_rctf_size_x(src) + 0.5f);
1044 dst->ymin = floorf(src->ymin + 0.5f);
1045 dst->ymax = dst->ymin + floorf(BLI_rctf_size_y(src) + 0.5f);
1046 }
1047
BLI_rcti_rctf_copy_floor(rcti * dst,const rctf * src)1048 void BLI_rcti_rctf_copy_floor(rcti *dst, const rctf *src)
1049 {
1050 dst->xmin = floorf(src->xmin);
1051 dst->xmax = floorf(src->xmax);
1052 dst->ymin = floorf(src->ymin);
1053 dst->ymax = floorf(src->ymax);
1054 }
1055
BLI_rcti_rctf_copy_round(rcti * dst,const rctf * src)1056 void BLI_rcti_rctf_copy_round(rcti *dst, const rctf *src)
1057 {
1058 dst->xmin = floorf(src->xmin + 0.5f);
1059 dst->xmax = floorf(src->xmax + 0.5f);
1060 dst->ymin = floorf(src->ymin + 0.5f);
1061 dst->ymax = floorf(src->ymax + 0.5f);
1062 }
1063
BLI_rctf_rcti_copy(rctf * dst,const rcti * src)1064 void BLI_rctf_rcti_copy(rctf *dst, const rcti *src)
1065 {
1066 dst->xmin = src->xmin;
1067 dst->xmax = src->xmax;
1068 dst->ymin = src->ymin;
1069 dst->ymax = src->ymax;
1070 }
1071
print_rctf(const char * str,const rctf * rect)1072 void print_rctf(const char *str, const rctf *rect)
1073 {
1074 printf("%s: xmin %.8f, xmax %.8f, ymin %.8f, ymax %.8f (%.12fx%.12f)\n",
1075 str,
1076 rect->xmin,
1077 rect->xmax,
1078 rect->ymin,
1079 rect->ymax,
1080 BLI_rctf_size_x(rect),
1081 BLI_rctf_size_y(rect));
1082 }
1083
print_rcti(const char * str,const rcti * rect)1084 void print_rcti(const char *str, const rcti *rect)
1085 {
1086 printf("%s: xmin %d, xmax %d, ymin %d, ymax %d (%dx%d)\n",
1087 str,
1088 rect->xmin,
1089 rect->xmax,
1090 rect->ymin,
1091 rect->ymax,
1092 BLI_rcti_size_x(rect),
1093 BLI_rcti_size_y(rect));
1094 }
1095
1096 /* -------------------------------------------------------------------- */
1097 /* Comprehensive math (float only) */
1098
1099 /** \name Rect math functions
1100 * \{ */
1101
1102 #define ROTATE_SINCOS(r_vec, mat2, vec) \
1103 { \
1104 (r_vec)[0] = (mat2)[1] * (vec)[0] + (+(mat2)[0]) * (vec)[1]; \
1105 (r_vec)[1] = (mat2)[0] * (vec)[0] + (-(mat2)[1]) * (vec)[1]; \
1106 } \
1107 ((void)0)
1108
1109 /**
1110 * Expand the rectangle to fit a rotated \a src.
1111 */
BLI_rctf_rotate_expand(rctf * dst,const rctf * src,const float angle)1112 void BLI_rctf_rotate_expand(rctf *dst, const rctf *src, const float angle)
1113 {
1114 const float mat2[2] = {sinf(angle), cosf(angle)};
1115 const float cent[2] = {BLI_rctf_cent_x(src), BLI_rctf_cent_y(src)};
1116 float corner[2], corner_rot[2], corder_max[2];
1117
1118 /* x is same for both corners */
1119 corner[0] = src->xmax - cent[0];
1120 corner[1] = src->ymax - cent[1];
1121 ROTATE_SINCOS(corner_rot, mat2, corner);
1122 corder_max[0] = fabsf(corner_rot[0]);
1123 corder_max[1] = fabsf(corner_rot[1]);
1124
1125 corner[1] *= -1;
1126 ROTATE_SINCOS(corner_rot, mat2, corner);
1127 corder_max[0] = MAX2(corder_max[0], fabsf(corner_rot[0]));
1128 corder_max[1] = MAX2(corder_max[1], fabsf(corner_rot[1]));
1129
1130 dst->xmin = cent[0] - corder_max[0];
1131 dst->xmax = cent[0] + corder_max[0];
1132 dst->ymin = cent[1] - corder_max[1];
1133 dst->ymax = cent[1] + corder_max[1];
1134 }
1135
1136 #undef ROTATE_SINCOS
1137
1138 /** \} */
1139
unit_m4(float m[4][4])1140 static void unit_m4(float m[4][4])
1141 {
1142 m[0][0] = m[1][1] = m[2][2] = m[3][3] = 1.0f;
1143 m[0][1] = m[0][2] = m[0][3] = 0.0f;
1144 m[1][0] = m[1][2] = m[1][3] = 0.0f;
1145 m[2][0] = m[2][1] = m[2][3] = 0.0f;
1146 m[3][0] = m[3][1] = m[3][2] = 0.0f;
1147 }
1148