// linear_map.hh -- linear mapping from integers <--> floating point values // $Id$ // // jtutil::linear_map - linear mapping from integers <--> floating point values // // // prerequisites // // "stdc.h" // "util.hh" // for jtutil::how_many_in_range() and fuzzy:: // // // The template defined in this file represents a linear mapping between // a contiguous range of integers, and an arithmetic progression of // floating point values, parameterized by the floating point data type. // #ifndef NDEBUG // // Full bounds checking is done on the mapping in both directions // #endif //***************************************************************************** namespace jtutil { template class linear_map { public: // integer bounds info int min_int() const { return min_int_; } int max_int() const { return max_int_; } int N_points() const { return jtutil::how_many_in_range(min_int_,max_int_); } bool is_in_range(int i) const { return (i >= min_int()) && (i <= max_int()); } int clamp(int i) const { if (i < min_int()) then return min_int(); else if (i > max_int()) then return max_int(); else return i; } // convert int --> fp fp fp_of_int_unchecked(int i) const { return origin_ + delta_*i; } fp fp_of_int(int i) const { assert(is_in_range(i)); return fp_of_int_unchecked(i); } // converg delta_int --> delta_fp fp delta_fp_of_delta_int(int delta_i) const { return delta_ * delta_i; } // fp bounds info fp origin() const { return origin_; } fp delta_fp() const { return delta_; } fp inverse_delta_fp() const { return inverse_delta_; } fp min_fp() const { return fp_of_int_unchecked(min_int_); } fp max_fp() const { return fp_of_int_unchecked(max_int_); } bool is_in_range(fp x) const { return fuzzy::GE(x,min_fp()) && fuzzy::LE(x,max_fp()); } fp clamp(fp x) const { if (x < min_fp()) then return min_fp(); else if (x > max_fp()) then return max_fp(); else return x; } // convert linear map indices <--> C-style 0-origin indices int zero_origin_int(int i) const { return i - min_int(); } int map_int(int zero_origin_i) { return zero_origin_i + min_int(); } // convert fp --> int coordinate, but return result as fp // (which need not be fuzzily integral) fp fp_int_of_fp(fp x) const; // convert fp --> int, check being fuzzily integral enum noninteger_action // what to do if "int" // isn't fuzzily integral? { error, // jtutil::error_exit(...) warning, // print warning msg, then round to nearest round, // (silently) round to nearest floor, // (silently) round to -infinity ceiling // (silently) round to +infinity }; int int_of_fp(fp x, noninteger_action nia = error) const; // convert delta_fp --> delta_int, check being fuzzily integral int delta_int_of_delta_fp(fp delta_x, noninteger_action nia = error) const; // constructors linear_map(int min_int_in, int max_int_in, fp min_fp_in, fp delta_fp_in, fp max_fp_in); // ... construct with subrange of existing linear_map linear_map(const linear_map &lm_in, int min_int_in, int max_int_in); // no need for explicit destructor, compiler-generated no-op is ok // no need for copy constructor or assignment operator, // compiler-generated defaults are ok private: // common code (argument validation & setup) for all constructors // assumes min_int_, max_int_, delta_ already initialized, // other class members *not* initialized void constructor_common(fp min_fp_in, fp max_fp_in); // these define the actual mapping // via the fp_of_int() function (above) fp origin_, delta_; // cache of 1.0/delta_ // ==> avoids fp divide in inverse_delta_fp() // ==> also makes fp --> int conversions slightly faster fp inverse_delta_; // bounds (inclusive) const int min_int_, max_int_; }; }; // namespace jtutil::