add BLI_strcpy_rlen, replace strcat, which was used in misleading way.
[blender.git] / intern / cycles / util / util_boundbox.h
1 /*
2  * Copyright 2011, Blender Foundation.
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
19 #ifndef __UTIL_BOUNDBOX_H__
20 #define __UTIL_BOUNDBOX_H__
21
22 #include <math.h>
23 #include <float.h>
24
25 #include "util_math.h"
26 #include "util_string.h"
27 #include "util_transform.h"
28 #include "util_types.h"
29
30 using namespace std;
31
32 CCL_NAMESPACE_BEGIN
33
34 /* 3D BoundBox */
35
36 class BoundBox
37 {
38 public:
39         float3 min, max;
40
41         __forceinline BoundBox()
42         {
43         }
44
45         __forceinline BoundBox(const float3& pt)
46         : min(pt), max(pt)
47         {
48         }
49
50         __forceinline BoundBox(const float3& min_, const float3& max_)
51         : min(min_), max(max_)
52         {
53         }
54
55         enum empty_t { empty = 0};
56
57         __forceinline BoundBox(empty_t)
58         : min(make_float3(FLT_MAX, FLT_MAX, FLT_MAX)), max(make_float3(-FLT_MAX, -FLT_MAX, -FLT_MAX))
59         {
60         }
61
62         __forceinline void grow(const float3& pt)  
63         {
64                 /* the order of arguments to min is such that if pt is nan, it will not
65                  * influence the resulting bounding box */
66                 min = ccl::min(pt, min);
67                 max = ccl::max(pt, max);
68         }
69
70         __forceinline void grow(const float3& pt, float border)  
71         {
72                 float3 shift = make_float3(border, border, border);
73                 min = ccl::min(pt - shift, min);
74                 max = ccl::max(pt + shift, max);
75         }
76
77         __forceinline void grow(const BoundBox& bbox)
78         {
79                 grow(bbox.min);
80                 grow(bbox.max);
81         }
82
83         __forceinline void grow_safe(const float3& pt)  
84         {
85                 /* the order of arguments to min is such that if pt is nan, it will not
86                  * influence the resulting bounding box */
87                 if(isfinite(pt.x) && isfinite(pt.y) && isfinite(pt.z)) {
88                         min = ccl::min(pt, min);
89                         max = ccl::max(pt, max);
90                 }
91         }
92
93         __forceinline void grow_safe(const float3& pt, float border)  
94         {
95                 if(isfinite(pt.x) && isfinite(pt.y) && isfinite(pt.z) && isfinite(border)) {
96                         float3 shift = make_float3(border, border, border);
97                         min = ccl::min(pt - shift, min);
98                         max = ccl::max(pt + shift, max);
99                 }
100         }
101
102         __forceinline void grow_safe(const BoundBox& bbox)
103         {
104                 grow_safe(bbox.min);
105                 grow_safe(bbox.max);
106         }
107
108         __forceinline void intersect(const BoundBox& bbox) 
109         {
110                 min = ccl::max(min, bbox.min);
111                 max = ccl::min(max, bbox.max);
112         }
113
114         /* todo: avoid using this */
115         __forceinline float safe_area() const
116         {
117                 if(!((min.x <= max.x) && (min.y <= max.y) && (min.z <= max.z)))
118                         return 0.0f;
119
120                 return area();
121         }
122
123         __forceinline float area() const
124         {
125                 return half_area()*2.0f;
126         }
127
128         __forceinline float half_area() const
129         {
130                 float3 d = max - min;
131                 return (d.x*d.z + d.y*d.z + d.x*d.y);
132         }
133
134         __forceinline float3 center() const
135         {
136                 return 0.5f*(min + max);
137         }
138
139         __forceinline float3 center2() const
140         {
141                 return min + max;
142         }
143
144         __forceinline float3 size() const
145         {
146                 return max - min;
147         }
148
149         __forceinline bool valid() const
150         {
151                 return (min.x <= max.x) && (min.y <= max.y) && (min.z <= max.z) &&
152                        (isfinite(min.x) && isfinite(min.y) && isfinite(min.z)) &&
153                        (isfinite(max.x) && isfinite(max.y) && isfinite(max.z));
154         }
155
156         BoundBox transformed(const Transform *tfm)
157         {
158                 BoundBox result = BoundBox::empty;
159
160                 for(int i = 0; i < 8; i++) {
161                         float3 p;
162
163                         p.x = (i & 1)? min.x: max.x;
164                         p.y = (i & 2)? min.y: max.y;
165                         p.z = (i & 4)? min.z: max.z;
166
167                         result.grow(transform_point(tfm, p));
168                 }
169
170                 return result;
171         }
172 };
173
174 __forceinline BoundBox merge(const BoundBox& bbox, const float3& pt)
175 {
176         return BoundBox(min(bbox.min, pt), max(bbox.max, pt));
177 }
178
179 __forceinline BoundBox merge(const BoundBox& a, const BoundBox& b)
180 {
181         return BoundBox(min(a.min, b.min), max(a.max, b.max));
182 }
183
184 __forceinline BoundBox merge(const BoundBox& a, const BoundBox& b, const BoundBox& c, const BoundBox& d)
185 {
186         return merge(merge(a, b), merge(c, d));
187 }
188
189 __forceinline BoundBox intersect(const BoundBox& a, const BoundBox& b)
190 {
191         return BoundBox(max(a.min, b.min), min(a.max, b.max));
192 }
193
194 __forceinline BoundBox intersect(const BoundBox& a, const BoundBox& b, const BoundBox& c)
195 {
196         return intersect(a, intersect(b, c));
197 }
198
199 /* 2D BoundBox */
200
201 class BoundBox2D {
202 public:
203         float left;
204         float right;
205         float bottom;
206         float top;
207
208         BoundBox2D()
209         : left(0.0f), right(1.0f), bottom(0.0f), top(1.0f)
210         {
211         }
212
213         bool operator==(const BoundBox2D& other) const
214         {
215                 return (left == other.left && right == other.right &&
216                         bottom == other.bottom && top == other.top);
217         }
218
219         float width()
220         {
221                 return right - left;
222         }
223
224         float height()
225         {
226                 return top - bottom;
227         }
228
229         BoundBox2D operator*(float f) const
230         {
231                 BoundBox2D result;
232
233                 result.left = left*f;
234                 result.right = right*f;
235                 result.bottom = bottom*f;
236                 result.top = top*f;
237
238                 return result;
239         }
240
241         BoundBox2D subset(const BoundBox2D& other) const
242         {
243                 BoundBox2D subset;
244
245                 subset.left = left + other.left*(right - left);
246                 subset.right = left + other.right*(right - left);
247                 subset.bottom = bottom + other.bottom*(top - bottom);
248                 subset.top = bottom + other.top*(top - bottom);
249
250                 return subset;
251         }
252
253         BoundBox2D make_relative_to(const BoundBox2D& other) const
254         {
255                 BoundBox2D result;
256
257                 result.left = ((left - other.left) / (other.right - other.left));
258                 result.right = ((right - other.left) / (other.right - other.left));
259                 result.bottom = ((bottom - other.bottom) / (other.top - other.bottom));
260                 result.top = ((top - other.bottom) / (other.top - other.bottom));
261
262                 return result;
263         }
264
265         BoundBox2D clamp(float mn = 0.0f, float mx = 1.0f)
266         {
267                 BoundBox2D result;
268
269                 result.left = ccl::clamp(left, mn, mx);
270                 result.right = ccl::clamp(right, mn, mx);
271                 result.bottom = ccl::clamp(bottom, mn, mx);
272                 result.top = ccl::clamp(top, mn, mx);
273
274                 return result;
275         }
276 };
277
278 CCL_NAMESPACE_END
279
280 #endif /* __UTIL_BOUNDBOX_H__ */
281