Merged changes in the trunk up to revision 45619.
[blender.git] / source / blender / blenlib / intern / rct.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
19  * All rights reserved.
20  *
21  * The Original Code is: all of this file.
22  *
23  * Contributor(s): none yet.
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  *
27  */
28
29 /** \file blender/blenlib/intern/rct.c
30  *  \ingroup bli
31  *
32  * A minimalist lib for functions doing stuff with rectangle structs.
33  */
34
35 #include <stdio.h>
36 #include <math.h>
37
38 #include "DNA_vec_types.h"
39 #include "BLI_rect.h"
40
41 int BLI_rcti_is_empty(rcti * rect)
42 {
43         return ((rect->xmax <= rect->xmin) || (rect->ymax <= rect->ymin));
44 }
45
46 int BLI_rctf_is_empty(rctf * rect)
47 {
48         return ((rect->xmax <= rect->xmin) || (rect->ymax <= rect->ymin));
49 }
50
51 int BLI_in_rcti(rcti * rect, int x, int y)
52 {
53         if (x < rect->xmin) return 0;
54         if (x > rect->xmax) return 0;
55         if (y < rect->ymin) return 0;
56         if (y > rect->ymax) return 0;
57         return 1;
58 }
59
60 int BLI_in_rctf(rctf *rect, float x, float y)
61 {
62         if (x < rect->xmin) return 0;
63         if (x > rect->xmax) return 0;
64         if (y < rect->ymin) return 0;
65         if (y > rect->ymax) return 0;
66         return 1;
67 }
68
69 /* based closely on 'isect_line_line_v2_int', but in modified so corner cases are treated as intersections */
70 static int isect_segments(const int v1[2], const int v2[2], const int v3[2], const int v4[2])
71 {
72         const double div = (double)((v2[0] - v1[0]) * (v4[1] - v3[1]) - (v2[1] - v1[1]) * (v4[0] - v3[0]));
73         if (div == 0.0f) {
74                 return 1; /* co-linear */
75         }
76         else {
77                 const double labda = (double)((v1[1] - v3[1]) * (v4[0] - v3[0]) - (v1[0] - v3[0]) * (v4[1] - v3[1])) / div;
78                 const double mu    = (double)((v1[1] - v3[1]) * (v2[0] - v1[0]) - (v1[0] - v3[0]) * (v2[1] - v1[1])) / div;
79                 return (labda >= 0.0f && labda <= 1.0f && mu >= 0.0f && mu <= 1.0f);
80         }
81 }
82
83 int BLI_segment_in_rcti(rcti *rect, int s1[2], int s2[2])
84 {
85         /* first do outside-bounds check for both points of the segment */
86         if (s1[0] < rect->xmin && s2[0] < rect->xmin) return 0;
87         if (s1[0] > rect->xmax && s2[0] > rect->xmax) return 0;
88         if (s1[1] < rect->ymin && s2[1] < rect->ymin) return 0;
89         if (s1[1] > rect->ymax && s2[1] > rect->ymax) return 0;
90
91         /* if either points intersect then we definetly intersect */
92         if (BLI_in_rcti(rect, s1[0], s1[1]) || BLI_in_rcti(rect, s2[0], s2[1])) {
93                 return 1;
94         }
95         else {
96                 /* both points are outside but may insersect the rect */
97                 int tvec1[2];
98                 int tvec2[2];
99                 /* diagonal: [/] */
100                 tvec1[0] = rect->xmin; tvec1[1] = rect->ymin;
101                 tvec2[0] = rect->xmin; tvec2[1] = rect->ymax;
102                 if (isect_segments(s1, s2, tvec1, tvec2)) {
103                         return 1;
104                 }
105
106                 /* diagonal: [\] */
107                 tvec1[0] = rect->xmin; tvec1[1] = rect->ymax;
108                 tvec2[0] = rect->xmax; tvec2[1] = rect->ymin;
109                 if (isect_segments(s1, s2, tvec1, tvec2)) {
110                         return 1;
111                 }
112
113                 /* no intersection */
114                 return 0;
115         }
116 }
117
118 void BLI_union_rctf(rctf *rct1, rctf *rct2)
119 {
120         if (rct1->xmin > rct2->xmin) rct1->xmin = rct2->xmin;
121         if (rct1->xmax < rct2->xmax) rct1->xmax = rct2->xmax;
122         if (rct1->ymin > rct2->ymin) rct1->ymin = rct2->ymin;
123         if (rct1->ymax < rct2->ymax) rct1->ymax = rct2->ymax;
124 }
125
126 void BLI_union_rcti(rcti *rct1, rcti *rct2)
127 {
128         if (rct1->xmin > rct2->xmin) rct1->xmin = rct2->xmin;
129         if (rct1->xmax < rct2->xmax) rct1->xmax = rct2->xmax;
130         if (rct1->ymin > rct2->ymin) rct1->ymin = rct2->ymin;
131         if (rct1->ymax < rct2->ymax) rct1->ymax = rct2->ymax;
132 }
133
134 void BLI_init_rctf(rctf *rect, float xmin, float xmax, float ymin, float ymax)
135 {
136         if (xmin <= xmax) {
137                 rect->xmin = xmin;
138                 rect->xmax = xmax;
139         }
140         else {
141                 rect->xmax = xmin;
142                 rect->xmin = xmax;
143         }
144         if (ymin <= ymax) {
145                 rect->ymin = ymin;
146                 rect->ymax = ymax;
147         }
148         else {
149                 rect->ymax = ymin;
150                 rect->ymin = ymax;
151         }
152 }
153
154 void BLI_init_rcti(rcti *rect, int xmin, int xmax, int ymin, int ymax)
155 {
156         if (xmin <= xmax) {
157                 rect->xmin = xmin;
158                 rect->xmax = xmax;
159         }
160         else {
161                 rect->xmax = xmin;
162                 rect->xmin = xmax;
163         }
164         if (ymin <= ymax) {
165                 rect->ymin = ymin;
166                 rect->ymax = ymax;
167         }
168         else {
169                 rect->ymax = ymin;
170                 rect->ymin = ymax;
171         }
172 }
173
174 void BLI_translate_rcti(rcti *rect, int x, int y)
175 {
176         rect->xmin += x;
177         rect->ymin += y;
178         rect->xmax += x;
179         rect->ymax += y;
180 }
181 void BLI_translate_rctf(rctf *rect, float x, float y)
182 {
183         rect->xmin += x;
184         rect->ymin += y;
185         rect->xmax += x;
186         rect->ymax += y;
187 }
188
189 /* change width & height around the central location */
190 void BLI_resize_rcti(rcti *rect, int x, int y)
191 {
192         rect->xmin = rect->xmax = (rect->xmax + rect->xmin) / 2;
193         rect->ymin = rect->ymax = (rect->ymax + rect->ymin) / 2;
194         rect->xmin -= x / 2;
195         rect->ymin -= y / 2;
196         rect->xmax = rect->xmin + x;
197         rect->ymax = rect->ymin + y;
198 }
199
200 void BLI_resize_rctf(rctf *rect, float x, float y)
201 {
202         rect->xmin = rect->xmax = (rect->xmax + rect->xmin) * 0.5f;
203         rect->ymin = rect->ymax = (rect->ymax + rect->ymin) * 0.5f;
204         rect->xmin -= x * 0.5f;
205         rect->ymin -= y * 0.5f;
206         rect->xmax = rect->xmin + x;
207         rect->ymax = rect->ymin + y;
208 }
209
210 int BLI_isect_rctf(rctf *src1, rctf *src2, rctf *dest)
211 {
212         float xmin, xmax;
213         float ymin, ymax;
214
215         xmin = (src1->xmin) > (src2->xmin) ? (src1->xmin) : (src2->xmin);
216         xmax = (src1->xmax) < (src2->xmax) ? (src1->xmax) : (src2->xmax);
217         ymin = (src1->ymin) > (src2->ymin) ? (src1->ymin) : (src2->ymin);
218         ymax = (src1->ymax) < (src2->ymax) ? (src1->ymax) : (src2->ymax);
219
220         if (xmax >= xmin && ymax >= ymin) {
221                 if (dest) {
222                         dest->xmin = xmin;
223                         dest->xmax = xmax;
224                         dest->ymin = ymin;
225                         dest->ymax = ymax;
226                 }
227                 return 1;
228         }
229         else {
230                 if (dest) {
231                         dest->xmin = 0;
232                         dest->xmax = 0;
233                         dest->ymin = 0;
234                         dest->ymax = 0;
235                 }
236                 return 0;
237         }
238 }
239
240 int BLI_isect_rcti(rcti *src1, rcti *src2, rcti *dest)
241 {
242         int xmin, xmax;
243         int ymin, ymax;
244
245         xmin = (src1->xmin) > (src2->xmin) ? (src1->xmin) : (src2->xmin);
246         xmax = (src1->xmax) < (src2->xmax) ? (src1->xmax) : (src2->xmax);
247         ymin = (src1->ymin) > (src2->ymin) ? (src1->ymin) : (src2->ymin);
248         ymax = (src1->ymax) < (src2->ymax) ? (src1->ymax) : (src2->ymax);
249
250         if (xmax >= xmin && ymax >= ymin) {
251                 if (dest) {
252                         dest->xmin = xmin;
253                         dest->xmax = xmax;
254                         dest->ymin = ymin;
255                         dest->ymax = ymax;
256                 }
257                 return 1;
258         }
259         else {
260                 if (dest) {
261                         dest->xmin = 0;
262                         dest->xmax = 0;
263                         dest->ymin = 0;
264                         dest->ymax = 0;
265                 }
266                 return 0;
267         }
268 }
269
270 void BLI_copy_rcti_rctf(rcti *tar, const rctf *src)
271 {
272         tar->xmin = floor(src->xmin + 0.5f);
273         tar->xmax = floor((src->xmax - src->xmin) + 0.5f);
274         tar->ymin = floor(src->ymin + 0.5f);
275         tar->ymax = floor((src->ymax - src->ymin) + 0.5f);
276 }
277
278 void print_rctf(const char *str, rctf *rect)
279 {
280         printf("%s: xmin %.3f, xmax %.3f, ymin %.3f, ymax %.3f (%.3fx%.3f)\n", str,
281                rect->xmin, rect->xmax, rect->ymin, rect->ymax, rect->xmax - rect->xmin, rect->ymax - rect->ymin);
282 }
283
284 void print_rcti(const char *str, rcti *rect)
285 {
286         printf("%s: xmin %d, xmax %d, ymin %d, ymax %d (%dx%d)\n", str,
287                rect->xmin, rect->xmax, rect->ymin, rect->ymax, rect->xmax - rect->xmin, rect->ymax - rect->ymin);
288 }