diff options
Diffstat (limited to 'intern/cycles/util/boundbox.h')
-rw-r--r-- | intern/cycles/util/boundbox.h | 282 |
1 files changed, 282 insertions, 0 deletions
diff --git a/intern/cycles/util/boundbox.h b/intern/cycles/util/boundbox.h new file mode 100644 index 00000000000..ed81e4cf8c3 --- /dev/null +++ b/intern/cycles/util/boundbox.h @@ -0,0 +1,282 @@ +/* + * Copyright 2011-2013 Blender Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __UTIL_BOUNDBOX_H__ +#define __UTIL_BOUNDBOX_H__ + +#include <float.h> +#include <math.h> + +#include "util/math.h" +#include "util/string.h" +#include "util/transform.h" +#include "util/types.h" + +CCL_NAMESPACE_BEGIN + +/* 3D BoundBox */ + +class BoundBox { + public: + float3 min, max; + + __forceinline BoundBox() + { + } + + __forceinline BoundBox(const float3 &pt) : min(pt), max(pt) + { + } + + __forceinline BoundBox(const float3 &min_, const float3 &max_) : min(min_), max(max_) + { + } + + enum empty_t { empty = 0 }; + + __forceinline BoundBox(empty_t) + : min(make_float3(FLT_MAX, FLT_MAX, FLT_MAX)), max(make_float3(-FLT_MAX, -FLT_MAX, -FLT_MAX)) + { + } + + __forceinline void grow(const float3 &pt) + { + /* the order of arguments to min is such that if pt is nan, it will not + * influence the resulting bounding box */ + min = ccl::min(pt, min); + max = ccl::max(pt, max); + } + + __forceinline void grow(const float3 &pt, float border) + { + float3 shift = make_float3(border, border, border); + min = ccl::min(pt - shift, min); + max = ccl::max(pt + shift, max); + } + + __forceinline void grow(const BoundBox &bbox) + { + grow(bbox.min); + grow(bbox.max); + } + + __forceinline void grow_safe(const float3 &pt) + { + /* the order of arguments to min is such that if pt is nan, it will not + * influence the resulting bounding box */ + if (isfinite(pt.x) && isfinite(pt.y) && isfinite(pt.z)) { + min = ccl::min(pt, min); + max = ccl::max(pt, max); + } + } + + __forceinline void grow_safe(const float3 &pt, float border) + { + if (isfinite(pt.x) && isfinite(pt.y) && isfinite(pt.z) && isfinite(border)) { + float3 shift = make_float3(border, border, border); + min = ccl::min(pt - shift, min); + max = ccl::max(pt + shift, max); + } + } + + __forceinline void grow_safe(const BoundBox &bbox) + { + grow_safe(bbox.min); + grow_safe(bbox.max); + } + + __forceinline void intersect(const BoundBox &bbox) + { + min = ccl::max(min, bbox.min); + max = ccl::min(max, bbox.max); + } + + /* todo: avoid using this */ + __forceinline float safe_area() const + { + if (!((min.x <= max.x) && (min.y <= max.y) && (min.z <= max.z))) + return 0.0f; + + return area(); + } + + __forceinline float area() const + { + return half_area() * 2.0f; + } + + __forceinline float half_area() const + { + float3 d = max - min; + return (d.x * d.z + d.y * d.z + d.x * d.y); + } + + __forceinline float3 center() const + { + return 0.5f * (min + max); + } + + __forceinline float3 center2() const + { + return min + max; + } + + __forceinline float3 size() const + { + return max - min; + } + + __forceinline bool valid() const + { + return (min.x <= max.x) && (min.y <= max.y) && (min.z <= max.z) && + (isfinite(min.x) && isfinite(min.y) && isfinite(min.z)) && + (isfinite(max.x) && isfinite(max.y) && isfinite(max.z)); + } + + BoundBox transformed(const Transform *tfm) const + { + BoundBox result = BoundBox::empty; + + for (int i = 0; i < 8; i++) { + float3 p; + + p.x = (i & 1) ? min.x : max.x; + p.y = (i & 2) ? min.y : max.y; + p.z = (i & 4) ? min.z : max.z; + + result.grow(transform_point(tfm, p)); + } + + return result; + } + + __forceinline bool intersects(const BoundBox &other) + { + float3 center_diff = center() - other.center(), total_size = (size() + other.size()) * 0.5f; + return fabsf(center_diff.x) <= total_size.x && fabsf(center_diff.y) <= total_size.y && + fabsf(center_diff.z) <= total_size.z; + } +}; + +__forceinline BoundBox merge(const BoundBox &bbox, const float3 &pt) +{ + return BoundBox(min(bbox.min, pt), max(bbox.max, pt)); +} + +__forceinline BoundBox merge(const BoundBox &a, const BoundBox &b) +{ + return BoundBox(min(a.min, b.min), max(a.max, b.max)); +} + +__forceinline BoundBox merge(const BoundBox &a, + const BoundBox &b, + const BoundBox &c, + const BoundBox &d) +{ + return merge(merge(a, b), merge(c, d)); +} + +__forceinline BoundBox intersect(const BoundBox &a, const BoundBox &b) +{ + return BoundBox(max(a.min, b.min), min(a.max, b.max)); +} + +__forceinline BoundBox intersect(const BoundBox &a, const BoundBox &b, const BoundBox &c) +{ + return intersect(a, intersect(b, c)); +} + +/* 2D BoundBox */ + +class BoundBox2D { + public: + float left; + float right; + float bottom; + float top; + + BoundBox2D() : left(0.0f), right(1.0f), bottom(0.0f), top(1.0f) + { + } + + bool operator==(const BoundBox2D &other) const + { + return (left == other.left && right == other.right && bottom == other.bottom && + top == other.top); + } + + float width() + { + return right - left; + } + + float height() + { + return top - bottom; + } + + BoundBox2D operator*(float f) const + { + BoundBox2D result; + + result.left = left * f; + result.right = right * f; + result.bottom = bottom * f; + result.top = top * f; + + return result; + } + + BoundBox2D subset(const BoundBox2D &other) const + { + BoundBox2D subset; + + subset.left = left + other.left * (right - left); + subset.right = left + other.right * (right - left); + subset.bottom = bottom + other.bottom * (top - bottom); + subset.top = bottom + other.top * (top - bottom); + + return subset; + } + + BoundBox2D make_relative_to(const BoundBox2D &other) const + { + BoundBox2D result; + + result.left = ((left - other.left) / (other.right - other.left)); + result.right = ((right - other.left) / (other.right - other.left)); + result.bottom = ((bottom - other.bottom) / (other.top - other.bottom)); + result.top = ((top - other.bottom) / (other.top - other.bottom)); + + return result; + } + + BoundBox2D clamp(float mn = 0.0f, float mx = 1.0f) + { + BoundBox2D result; + + result.left = ccl::clamp(left, mn, mx); + result.right = ccl::clamp(right, mn, mx); + result.bottom = ccl::clamp(bottom, mn, mx); + result.top = ccl::clamp(top, mn, mx); + + return result; + } +}; + +CCL_NAMESPACE_END + +#endif /* __UTIL_BOUNDBOX_H__ */ |