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