Path: blob/master/thirdparty/embree/common/math/lbbox.h
9912 views
// Copyright 2009-2021 Intel Corporation1// SPDX-License-Identifier: Apache-2.023#pragma once45#include "bbox.h"6#include "range.h"78namespace embree9{10template<typename T>11__forceinline std::pair<T,T> globalLinear(const std::pair<T,T>& v, const BBox1f& dt)12{13const float rcp_dt_size = float(1.0f)/dt.size();14const T g0 = lerp(v.first,v.second,-dt.lower*rcp_dt_size);15const T g1 = lerp(v.first,v.second,(1.0f-dt.lower)*rcp_dt_size);16return std::make_pair(g0,g1);17}1819template<typename T>20struct LBBox21{22public:23__forceinline LBBox () {}2425template<typename T1>26__forceinline LBBox ( const LBBox<T1>& other )27: bounds0(other.bounds0), bounds1(other.bounds1) {}2829__forceinline LBBox& operator= ( const LBBox& other ) {30bounds0 = other.bounds0; bounds1 = other.bounds1; return *this;31}3233__forceinline LBBox (EmptyTy)34: bounds0(EmptyTy()), bounds1(EmptyTy()) {}3536__forceinline explicit LBBox ( const BBox<T>& bounds)37: bounds0(bounds), bounds1(bounds) { }3839__forceinline LBBox ( const BBox<T>& bounds0, const BBox<T>& bounds1)40: bounds0(bounds0), bounds1(bounds1) { }4142LBBox ( const avector<BBox<T>>& bounds )43{44assert(bounds.size());45BBox<T> b0 = bounds.front();46BBox<T> b1 = bounds.back();47for (size_t i=1; i<bounds.size()-1; i++) {48const float f = float(i)/float(bounds.size()-1);49const BBox<T> bt = lerp(b0,b1,f);50const T dlower = min(bounds[i].lower-bt.lower,T(zero));51const T dupper = max(bounds[i].upper-bt.upper,T(zero));52b0.lower += dlower; b1.lower += dlower;53b0.upper += dupper; b1.upper += dupper;54}55bounds0 = b0;56bounds1 = b1;57}5859/*! calculates the linear bounds of a primitive for the specified time range */60template<typename BoundsFunc>61__forceinline LBBox(const BoundsFunc& bounds, const BBox1f& time_range, float numTimeSegments)62{63const float lower = time_range.lower*numTimeSegments;64const float upper = time_range.upper*numTimeSegments;65const float ilowerf = floor(lower);66const float iupperf = ceil(upper);67const int ilower = (int)ilowerf;68const int iupper = (int)iupperf;6970const BBox<T> blower0 = bounds(ilower);71const BBox<T> bupper1 = bounds(iupper);7273if (iupper-ilower == 1) {74bounds0 = lerp(blower0, bupper1, lower-ilowerf);75bounds1 = lerp(bupper1, blower0, iupperf-upper);76return;77}7879const BBox<T> blower1 = bounds(ilower+1);80const BBox<T> bupper0 = bounds(iupper-1);81BBox<T> b0 = lerp(blower0, blower1, lower-ilowerf);82BBox<T> b1 = lerp(bupper1, bupper0, iupperf-upper);8384for (int i = ilower+1; i < iupper; i++)85{86const float f = (float(i)/numTimeSegments - time_range.lower) / time_range.size();87const BBox<T> bt = lerp(b0, b1, f);88const BBox<T> bi = bounds(i);89const T dlower = min(bi.lower-bt.lower, T(zero));90const T dupper = max(bi.upper-bt.upper, T(zero));91b0.lower += dlower; b1.lower += dlower;92b0.upper += dupper; b1.upper += dupper;93}9495bounds0 = b0;96bounds1 = b1;97}9899/*! calculates the linear bounds of a primitive for the specified time range */100template<typename BoundsFunc>101__forceinline LBBox(const BoundsFunc& bounds, const BBox1f& time_range_in, const BBox1f& geom_time_range, float geom_time_segments)102{103/* normalize global time_range_in to local geom_time_range */104const BBox1f time_range((time_range_in.lower-geom_time_range.lower)/geom_time_range.size(),105(time_range_in.upper-geom_time_range.lower)/geom_time_range.size());106107const float lower = time_range.lower*geom_time_segments;108const float upper = time_range.upper*geom_time_segments;109const float ilowerf = floor(lower);110const float iupperf = ceil(upper);111const float ilowerfc = max(0.0f,ilowerf);112const float iupperfc = min(iupperf,geom_time_segments);113const int ilowerc = (int)ilowerfc;114const int iupperc = (int)iupperfc;115assert(iupperc-ilowerc > 0);116117/* this larger iteration range guarantees that we process borders of geom_time_range is (partially) inside time_range_in */118const int ilower_iter = max(-1,(int)ilowerf);119const int iupper_iter = min((int)iupperf,(int)geom_time_segments+1);120121const BBox<T> blower0 = bounds(ilowerc);122const BBox<T> bupper1 = bounds(iupperc);123if (iupper_iter-ilower_iter == 1) {124bounds0 = lerp(blower0, bupper1, max(0.0f,lower-ilowerfc));125bounds1 = lerp(bupper1, blower0, max(0.0f,iupperfc-upper));126return;127}128129const BBox<T> blower1 = bounds(ilowerc+1);130const BBox<T> bupper0 = bounds(iupperc-1);131BBox<T> b0 = lerp(blower0, blower1, max(0.0f,lower-ilowerfc));132BBox<T> b1 = lerp(bupper1, bupper0, max(0.0f,iupperfc-upper));133134for (int i = ilower_iter+1; i < iupper_iter; i++)135{136const float f = (float(i)/geom_time_segments - time_range.lower) / time_range.size();137const BBox<T> bt = lerp(b0, b1, f);138const BBox<T> bi = bounds(i);139const T dlower = min(bi.lower-bt.lower, T(zero));140const T dupper = max(bi.upper-bt.upper, T(zero));141b0.lower += dlower; b1.lower += dlower;142b0.upper += dupper; b1.upper += dupper;143}144145bounds0 = b0;146bounds1 = b1;147}148149/*! calculates the linear bounds of a primitive for the specified time range */150template<typename BoundsFunc>151__forceinline LBBox(const BoundsFunc& bounds, const range<int>& time_range, int numTimeSegments)152{153const int ilower = time_range.begin();154const int iupper = time_range.end();155156BBox<T> b0 = bounds(ilower);157BBox<T> b1 = bounds(iupper);158159if (iupper-ilower == 1)160{161bounds0 = b0;162bounds1 = b1;163return;164}165166for (int i = ilower+1; i<iupper; i++)167{168const float f = float(i - time_range.begin()) / float(time_range.size());169const BBox<T> bt = lerp(b0, b1, f);170const BBox<T> bi = bounds(i);171const T dlower = min(bi.lower-bt.lower, T(zero));172const T dupper = max(bi.upper-bt.upper, T(zero));173b0.lower += dlower; b1.lower += dlower;174b0.upper += dupper; b1.upper += dupper;175}176177bounds0 = b0;178bounds1 = b1;179}180181/*! calculates the linear bounds for target_time_range of primitive with it's time_range_in and bounds */182__forceinline LBBox(const BBox1f& time_range_in, const LBBox<T> lbounds, const BBox1f& target_time_range)183{184const BBox3f bounds0 = lbounds.bounds0;185const BBox3f bounds1 = lbounds.bounds1;186187/* normalize global target_time_range to local time_range_in */188const BBox1f time_range((target_time_range.lower-time_range_in.lower)/time_range_in.size(),189(target_time_range.upper-time_range_in.lower)/time_range_in.size());190191const BBox1f clipped_time_range(max(0.0f,time_range.lower), min(1.0f,time_range.upper));192193/* compute bounds at begin and end of clipped time range */194BBox<T> b0 = lerp(bounds0,bounds1,clipped_time_range.lower);195BBox<T> b1 = lerp(bounds0,bounds1,clipped_time_range.upper);196197/* make sure that b0 is properly bounded at time_range_in.lower */198{199const BBox<T> bt = lerp(b0, b1, (0.0f - time_range.lower) / time_range.size());200const T dlower = min(bounds0.lower-bt.lower, T(zero));201const T dupper = max(bounds0.upper-bt.upper, T(zero));202b0.lower += dlower; b1.lower += dlower;203b0.upper += dupper; b1.upper += dupper;204}205206/* make sure that b1 is properly bounded at time_range_in.upper */207{208const BBox<T> bt = lerp(b0, b1, (1.0f - time_range.lower) / time_range.size());209const T dlower = min(bounds1.lower-bt.lower, T(zero));210const T dupper = max(bounds1.upper-bt.upper, T(zero));211b0.lower += dlower; b1.lower += dlower;212b0.upper += dupper; b1.upper += dupper;213}214215this->bounds0 = b0;216this->bounds1 = b1;217}218219/*! calculates the linear bounds for target_time_range of primitive with it's time_range_in and bounds */220__forceinline LBBox(const BBox1f& time_range_in, const BBox<T>& bounds0, const BBox<T>& bounds1, const BBox1f& target_time_range)221: LBBox(time_range_in,LBBox(bounds0,bounds1),target_time_range) {}222223public:224225__forceinline bool empty() const {226return bounds().empty();227}228229__forceinline BBox<T> bounds () const {230return merge(bounds0,bounds1);231}232233__forceinline BBox<T> interpolate( const float t ) const {234return lerp(bounds0,bounds1,t);235}236237__forceinline LBBox<T> interpolate( const BBox1f& dt ) const {238return LBBox<T>(interpolate(dt.lower),interpolate(dt.upper));239}240241__forceinline void extend( const LBBox& other ) {242bounds0.extend(other.bounds0);243bounds1.extend(other.bounds1);244}245246__forceinline float expectedHalfArea() const;247248__forceinline float expectedHalfArea(const BBox1f& dt) const {249return interpolate(dt).expectedHalfArea();250}251252__forceinline float expectedApproxHalfArea() const {253return 0.5f*(halfArea(bounds0) + halfArea(bounds1));254}255256/* calculates bounds for [0,1] time range from bounds in dt time range */257__forceinline LBBox global(const BBox1f& dt) const258{259const float rcp_dt_size = 1.0f/dt.size();260const BBox<T> b0 = interpolate(-dt.lower*rcp_dt_size);261const BBox<T> b1 = interpolate((1.0f-dt.lower)*rcp_dt_size);262return LBBox(b0,b1);263}264265/*! Comparison Operators */266//template<typename TT> friend __forceinline bool operator==( const LBBox<TT>& a, const LBBox<TT>& b ) { return a.bounds0 == b.bounds0 && a.bounds1 == b.bounds1; }267//template<typename TT> friend __forceinline bool operator!=( const LBBox<TT>& a, const LBBox<TT>& b ) { return a.bounds0 != b.bounds0 || a.bounds1 != b.bounds1; }268friend __forceinline bool operator==( const LBBox& a, const LBBox& b ) { return a.bounds0 == b.bounds0 && a.bounds1 == b.bounds1; }269friend __forceinline bool operator!=( const LBBox& a, const LBBox& b ) { return a.bounds0 != b.bounds0 || a.bounds1 != b.bounds1; }270271/*! output operator */272friend __forceinline embree_ostream operator<<(embree_ostream cout, const LBBox& box) {273return cout << "LBBox { " << box.bounds0 << "; " << box.bounds1 << " }";274}275276public:277BBox<T> bounds0, bounds1;278};279280/*! tests if box is finite */281template<typename T>282__forceinline bool isvalid( const LBBox<T>& v ) {283return isvalid(v.bounds0) && isvalid(v.bounds1);284}285286template<typename T>287__forceinline bool isvalid_non_empty( const LBBox<T>& v ) {288return isvalid_non_empty(v.bounds0) && isvalid_non_empty(v.bounds1);289}290291template<typename T>292__forceinline T expectedArea(const T& a0, const T& a1, const T& b0, const T& b1)293{294const T da = a1-a0;295const T db = b1-b0;296return a0*b0+(a0*db+da*b0)*T(0.5f) + da*db*T(1.0f/3.0f);297}298299template<> __forceinline float LBBox<Vec3fa>::expectedHalfArea() const300{301const Vec3fa d0 = bounds0.size();302const Vec3fa d1 = bounds1.size();303return reduce_add(expectedArea(Vec3fa(d0.x,d0.y,d0.z),304Vec3fa(d1.x,d1.y,d1.z),305Vec3fa(d0.y,d0.z,d0.x),306Vec3fa(d1.y,d1.z,d1.x)));307}308309template<typename T>310__forceinline float expectedApproxHalfArea(const LBBox<T>& box) {311return box.expectedApproxHalfArea();312}313314template<typename T>315__forceinline LBBox<T> merge(const LBBox<T>& a, const LBBox<T>& b) {316return LBBox<T>(merge(a.bounds0, b.bounds0), merge(a.bounds1, b.bounds1));317}318319/*! subset relation */320template<typename T> __inline bool subset( const LBBox<T>& a, const LBBox<T>& b ) {321return subset(a.bounds0,b.bounds0) && subset(a.bounds1,b.bounds1);322}323324/*! default template instantiations */325typedef LBBox<float> LBBox1f;326typedef LBBox<Vec2f> LBBox2f;327typedef LBBox<Vec3f> LBBox3f;328typedef LBBox<Vec3fa> LBBox3fa;329typedef LBBox<Vec3fx> LBBox3fx;330}331332333