comparison base/RangeMapper.cpp @ 880:b4787b595db3

Implement and test the interpolating and auto range mappers
author Chris Cannam
date Fri, 31 Jan 2014 17:09:02 +0000
parents eb6b6a88faed
children 12a6140b3ae0
comparison
equal deleted inserted replaced
879:eb6b6a88faed 880:b4787b595db3
123 // cerr << "LogRangeMapper::getValueForPosition: " << position << " -> " 123 // cerr << "LogRangeMapper::getValueForPosition: " << position << " -> "
124 // << value << " (minpos " << m_minpos << ", maxpos " << m_maxpos << ", ratio " << m_ratio << ", minlog " << m_minlog << ")" << endl; 124 // << value << " (minpos " << m_minpos << ", maxpos " << m_maxpos << ", ratio " << m_ratio << ", minlog " << m_minlog << ")" << endl;
125 return value; 125 return value;
126 } 126 }
127 127
128 InterpolatingRangeMapper::InterpolatingRangeMapper(CoordMap pointMappings,
129 QString unit) :
130 m_mappings(pointMappings),
131 m_unit(unit)
132 {
133 for (CoordMap::const_iterator i = m_mappings.begin();
134 i != m_mappings.end(); ++i) {
135 m_reverse[i->second] = i->first;
136 }
137 }
138
139 int
140 InterpolatingRangeMapper::getPositionForValue(float value) const
141 {
142 CoordMap::const_iterator i = m_mappings.lower_bound(value);
143 CoordMap::const_iterator j = i;
144 --j;
145
146 if (i == m_mappings.end()) return j->second;
147 if (i == m_mappings.begin()) return i->second;
148 if (i->first == value) return i->second;
149
150 return lrintf(((value - j->first) / (i->first - j->first)) *
151 float(i->second - j->second) + j->second);
152 }
153
154 float
155 InterpolatingRangeMapper::getValueForPosition(int position) const
156 {
157 std::map<int, float>::const_iterator i = m_reverse.lower_bound(position);
158 std::map<int, float>::const_iterator j = i;
159 --j;
160
161 if (i == m_reverse.end()) return j->second;
162 if (i == m_reverse.begin()) return i->second;
163 if (i->first == position) return i->second;
164
165 return ((float(position) - j->first) / (i->first - j->first)) *
166 (i->second - j->second) + j->second;
167 }
168
169 AutoRangeMapper::AutoRangeMapper(CoordMap pointMappings,
170 QString unit) :
171 m_mappings(pointMappings),
172 m_unit(unit)
173 {
174 m_type = chooseMappingTypeFor(m_mappings);
175
176 CoordMap::const_iterator first = m_mappings.begin();
177 CoordMap::const_iterator last = m_mappings.end();
178 --last;
179
180 switch (m_type) {
181 case StraightLine:
182 m_mapper = new LinearRangeMapper(first->second, last->second,
183 first->first, last->first,
184 unit, false);
185 break;
186 case Logarithmic:
187 m_mapper = new LogRangeMapper(first->second, last->second,
188 first->first, last->first,
189 unit, false);
190 break;
191 case Interpolating:
192 m_mapper = new InterpolatingRangeMapper(m_mappings, unit);
193 break;
194 }
195 }
196
197 AutoRangeMapper::~AutoRangeMapper()
198 {
199 delete m_mapper;
200 }
201
202 AutoRangeMapper::MappingType
203 AutoRangeMapper::chooseMappingTypeFor(const CoordMap &mappings)
204 {
205 // how do we work out whether a linear/log mapping is "close enough"?
206
207 CoordMap::const_iterator first = mappings.begin();
208 CoordMap::const_iterator last = mappings.end();
209 --last;
210
211 LinearRangeMapper linm(first->second, last->second,
212 first->first, last->first,
213 "", false);
214
215 bool inadequate = false;
216
217 for (CoordMap::const_iterator i = mappings.begin();
218 i != mappings.end(); ++i) {
219 int candidate = linm.getPositionForValue(i->first);
220 int diff = candidate - i->second;
221 if (diff < 0) diff = -diff;
222 if (diff > 1) {
223 cerr << "AutoRangeMapper::chooseMappingTypeFor: diff = " << diff
224 << ", straight-line mapping inadequate" << endl;
225 inadequate = true;
226 break;
227 }
228 }
229
230 if (!inadequate) {
231 return StraightLine;
232 }
233
234 LogRangeMapper logm(first->second, last->second,
235 first->first, last->first,
236 "", false);
237
238 inadequate = false;
239
240 for (CoordMap::const_iterator i = mappings.begin();
241 i != mappings.end(); ++i) {
242 int candidate = logm.getPositionForValue(i->first);
243 int diff = candidate - i->second;
244 if (diff < 0) diff = -diff;
245 if (diff > 1) {
246 cerr << "AutoRangeMapper::chooseMappingTypeFor: diff = " << diff
247 << ", log mapping inadequate" << endl;
248 inadequate = true;
249 break;
250 }
251 }
252
253 if (!inadequate) {
254 return Logarithmic;
255 }
256
257 return Interpolating;
258 }
259
260 int
261 AutoRangeMapper::getPositionForValue(float value) const
262 {
263 return m_mapper->getPositionForValue(value);
264 }
265
266 float
267 AutoRangeMapper::getValueForPosition(int position) const
268 {
269 return m_mapper->getValueForPosition(position);
270 }