aboutsummaryrefslogtreecommitdiff
path: root/src/jtutil/linear_map.hh
blob: 59cdbdf9e1b821a8d0ff81baa52b9451fb41be44 (plain)
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
133
134
135
136
137
// linear_map.hh -- linear mapping from integers <--> floating point values
// $Id$
//
// jtutil::linear_map - linear mapping from integers <--> floating point values
//

//
// prerequisites
//    <assert.h>
//    "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 <typename 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 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<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,		// 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<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 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::