1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
|
// linear_map.hh -- linear mapping from integers <--> floating point values
// $Id$
//
// linear_map - linear mapping from integers <--> floating point values
//
//
// prerequisites
// <assert.h>
// <jt/util++.hh> // for 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
//*****************************************************************************
template <class fp>
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 HOW_MANY_IN_RANGE(min_int_,max_int_); }
bool 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 offset_ + delta_*i; }
fp fp_of_int(int i) const
{
assert(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 min_fp() const { return fp_of_int_unchecked(min_int_); }
fp delta_fp() const { return delta_; }
fp inverse_delta_fp() const { return inverse_delta_; }
fp max_fp() const { return fp_of_int_unchecked(max_int_); }
bool in_range(fp x) const
{
return fuzzy<fp>::GE(x,min_fp()) && fuzzy<fp>::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, // 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<fp> &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 offset_, 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_;
};
|