#include #include #include #include "cctk.h" #include "defs.hh" #include "vect.hh" #include "bbox.hh" using namespace std; // Constructors template bbox::bbox (): _lower(T(1)), _upper(T(0)), _stride(T(1)) { } template bbox::bbox (const bbox& b) : _lower(b._lower), _upper(b._upper), _stride(b._stride) { } template bbox& bbox::operator= (const bbox& b) { _lower=b._lower; _upper=b._upper; _stride=b._stride; return *this; } template bbox::bbox (const vect& lower_, const vect& upper_, const vect& stride_) : _lower(lower_), _upper(upper_), _stride(stride_) { assert (all(_stride>T(0))); assert (all((_upper-_lower)%_stride == T(0))); if (numeric_limits::is_integer && numeric_limits::is_signed) { // prevent accidental wrap-around assert (all(_lower < numeric_limits::max() / 2)); assert (all(_lower > numeric_limits::min() / 2)); assert (all(_upper < numeric_limits::max() / 2)); assert (all(_upper > numeric_limits::min() / 2)); } } // Accessors template T bbox::size () const { if (empty()) return 0; // return prod((shape()+stride()-1)/stride()); const vect sh((shape()+stride()-T(1))/stride()); T sz = 1, max = numeric_limits::max(); for (int d=0; d bool bbox::contains (const vect& x) const { return all(x>=lower() && x<=upper()); } // Operators template bool bbox::operator== (const bbox& b) const { if (empty() && b.empty()) return true; assert (all(stride()==b.stride())); return all(lower()==b.lower() && upper()==b.upper()); } template bool bbox::operator!= (const bbox& b) const { return ! (*this == b); } template bool bbox::operator< (const bbox& b) const { // An arbitraty order: empty boxes come first, then sorted by lower // bound, then by upper bound, then by coarseness if (b.empty()) return false; if (empty()) return true; for (int d=D-1; d>=0; --d) { if (lower()[d] < b.lower()[d]) return true; if (lower()[d] > b.lower()[d]) return false; } for (int d=D-1; d>=0; --d) { if (upper()[d] < b.upper()[d]) return true; if (upper()[d] > b.upper()[d]) return false; } for (int d=D-1; d>=0; --d) { if (stride()[d] > b.stride()[d]) return true; if (stride()[d] < b.stride()[d]) return false; } return false; } template bool bbox::operator> (const bbox& b) const { return b < *this; } template bool bbox::operator<= (const bbox& b) const { return ! (b > *this); } template bool bbox::operator>= (const bbox& b) const { return b <= *this; } // Intersection template bbox bbox::operator& (const bbox& b) const { assert (all(stride()==b.stride())); vect lo = max(lower(),b.lower()); vect up = min(upper(),b.upper()); return bbox(lo,up,stride()); } // Containment template bool bbox::is_contained_in (const bbox& b) const { if (empty()) return true; // no alignment check return all(lower()>=b.lower() && upper()<=b.upper()); } // Alignment check template bool bbox::is_aligned_with (const bbox& b) const { return all(stride()==b.stride() && (lower()-b.lower()) % stride() == T(0)); } // Expand the bbox a little by multiples of the stride template bbox bbox::expand (const vect& lo, const vect& hi) const { // Allow expansion only into directions where the extent is not negative assert (all(lower()<=upper() || (lo==T(0) && hi==T(0)))); const vect str = stride(); const vect lb = lower() - lo * str; const vect ub = upper() + hi * str; return bbox(lb,ub,str); } // Find the smallest b-compatible box around *this template bbox bbox::expanded_for (const bbox& b) const { if (empty()) return bbox(b.lower(), b.lower()-b.stride(), b.stride()); const vect str = b.stride(); const vect loff = ((lower() - b.lower()) % str + str) % str; const vect uoff = ((upper() - b.lower()) % str + str) % str; const vect lo = lower() - loff; // go outwards const vect up = upper() + (str - uoff) % str; return bbox(lo,up,str); } // Find the largest b-compatible box inside *this template bbox bbox::contracted_for (const bbox& b) const { if (empty()) return bbox(b.lower(), b.lower()-b.stride(), b.stride()); const vect str = b.stride(); const vect loff = ((lower() - b.lower()) % str + str) % str; const vect uoff = ((upper() - b.lower()) % str + str) % str; const vect lo = lower() + (str - loff) % str; // go inwards const vect up = upper() - uoff; return bbox(lo,up,str); } // Smallest bbox containing both boxes template bbox bbox::expanded_containing (const bbox& b) const { if (empty()) return b; if (b.empty()) return *this; assert (is_aligned_with(b)); const vect lo = min(lower(), b.lower()); const vect up = max(upper(), b.upper()); const vect str = min(stride(), b.stride()); return bbox(lo,up,str); } // Iterators template bbox::iterator::iterator (const bbox& box_, const vect& pos_) : box(box_), pos(pos_) { if (box.empty()) pos=box.upper(); } template bool bbox::iterator::operator!= (const iterator& i) const { return any(pos!=i.pos); } template typename bbox::iterator& bbox::iterator::operator++ () { for (int d=0; d typename bbox::iterator bbox::begin () const { return iterator(*this, lower()); } template typename bbox::iterator bbox::end () const { return iterator(*this, lower()); } // Input template void bbox::input (istream& is) { try { skipws (is); consume (is, '('); is >> _lower; skipws (is); consume (is, ':'); is >> _upper; skipws (is); consume (is, ':'); is >> _stride; skipws (is); consume (is, ')'); } catch (input_error &err) { cout << "Input error while reading a bbox" << endl; throw err; } if (any(_stride<=T(0))) { cout << "While reading the bbox " << *this << ":" << endl << " The stride is not positive." << endl; throw input_error(); } if (any((_upper-_lower)%_stride != T(0))) { cout << "While reading the bbox " << *this << ":" << endl << " The stride does not evenly divide the extent." << endl; throw input_error(); } assert (all(_stride>T(0))); assert (all((_upper-_lower)%_stride == T(0))); } // Output template void bbox::output (ostream& os) const { os << "(" << lower() << ":" << upper() << ":" << stride() << ")"; } // Note: We need all dimensions all the time. template class bbox; template class bbox; template class bbox; template class bbox; template class bbox;