Mercurial > hg > svcore
comparison base/RangeMapper.cpp @ 891:8962f80f5d8e tony_integration
Merge from default branch
author | Chris Cannam |
---|---|
date | Tue, 11 Mar 2014 17:32:31 +0000 |
parents | 12a6140b3ae0 |
children | cc27f35aa75c |
comparison
equal
deleted
inserted
replaced
890:4cbf8c6a462d | 891:8962f80f5d8e |
---|---|
36 } | 36 } |
37 | 37 |
38 int | 38 int |
39 LinearRangeMapper::getPositionForValue(float value) const | 39 LinearRangeMapper::getPositionForValue(float value) const |
40 { | 40 { |
41 int position = getPositionForValueUnclamped(value); | |
42 if (position < m_minpos) position = m_minpos; | |
43 if (position > m_maxpos) position = m_maxpos; | |
44 return position; | |
45 } | |
46 | |
47 int | |
48 LinearRangeMapper::getPositionForValueUnclamped(float value) const | |
49 { | |
41 int position = m_minpos + | 50 int position = m_minpos + |
42 lrintf(((value - m_minval) / (m_maxval - m_minval)) | 51 lrintf(((value - m_minval) / (m_maxval - m_minval)) |
43 * (m_maxpos - m_minpos)); | 52 * (m_maxpos - m_minpos)); |
53 if (m_inverted) return m_maxpos - (position - m_minpos); | |
54 else return position; | |
55 } | |
56 | |
57 float | |
58 LinearRangeMapper::getValueForPosition(int position) const | |
59 { | |
44 if (position < m_minpos) position = m_minpos; | 60 if (position < m_minpos) position = m_minpos; |
45 if (position > m_maxpos) position = m_maxpos; | 61 if (position > m_maxpos) position = m_maxpos; |
46 // SVDEBUG << "LinearRangeMapper::getPositionForValue: " << value << " -> " | 62 float value = getValueForPositionUnclamped(position); |
47 // << position << " (minpos " << m_minpos << ", maxpos " << m_maxpos << ", minval " << m_minval << ", maxval " << m_maxval << ")" << endl; | 63 return value; |
48 if (m_inverted) return m_maxpos - position; | 64 } |
49 else return position; | 65 |
50 } | 66 float |
51 | 67 LinearRangeMapper::getValueForPositionUnclamped(int position) const |
52 float | 68 { |
53 LinearRangeMapper::getValueForPosition(int position) const | 69 if (m_inverted) position = m_maxpos - (position - m_minpos); |
54 { | |
55 if (m_inverted) position = m_maxpos - position; | |
56 float value = m_minval + | 70 float value = m_minval + |
57 ((float(position - m_minpos) / float(m_maxpos - m_minpos)) | 71 ((float(position - m_minpos) / float(m_maxpos - m_minpos)) |
58 * (m_maxval - m_minval)); | 72 * (m_maxval - m_minval)); |
59 if (value < m_minval) value = m_minval; | |
60 if (value > m_maxval) value = m_maxval; | |
61 // SVDEBUG << "LinearRangeMapper::getValueForPosition: " << position << " -> " | |
62 // << value << " (minpos " << m_minpos << ", maxpos " << m_maxpos << ", minval " << m_minval << ", maxval " << m_maxval << ")" << endl; | |
63 return value; | 73 return value; |
64 } | 74 } |
65 | 75 |
66 LogRangeMapper::LogRangeMapper(int minpos, int maxpos, | 76 LogRangeMapper::LogRangeMapper(int minpos, int maxpos, |
67 float minval, float maxval, | 77 float minval, float maxval, |
71 m_unit(unit), | 81 m_unit(unit), |
72 m_inverted(inverted) | 82 m_inverted(inverted) |
73 { | 83 { |
74 convertMinMax(minpos, maxpos, minval, maxval, m_minlog, m_ratio); | 84 convertMinMax(minpos, maxpos, minval, maxval, m_minlog, m_ratio); |
75 | 85 |
76 cerr << "LogRangeMapper: minpos " << minpos << ", maxpos " | 86 // cerr << "LogRangeMapper: minpos " << minpos << ", maxpos " |
77 << maxpos << ", minval " << minval << ", maxval " | 87 // << maxpos << ", minval " << minval << ", maxval " |
78 << maxval << ", minlog " << m_minlog << ", ratio " << m_ratio | 88 // << maxval << ", minlog " << m_minlog << ", ratio " << m_ratio |
79 << ", unit " << unit << endl; | 89 // << ", unit " << unit << endl; |
80 | 90 |
81 assert(m_maxpos != m_minpos); | 91 assert(m_maxpos != m_minpos); |
82 | 92 |
83 m_maxlog = (m_maxpos - m_minpos) / m_ratio + m_minlog; | 93 m_maxlog = (m_maxpos - m_minpos) / m_ratio + m_minlog; |
94 | |
95 // cerr << "LogRangeMapper: maxlog = " << m_maxlog << endl; | |
84 } | 96 } |
85 | 97 |
86 void | 98 void |
87 LogRangeMapper::convertMinMax(int minpos, int maxpos, | 99 LogRangeMapper::convertMinMax(int minpos, int maxpos, |
88 float minval, float maxval, | 100 float minval, float maxval, |
104 } | 116 } |
105 | 117 |
106 int | 118 int |
107 LogRangeMapper::getPositionForValue(float value) const | 119 LogRangeMapper::getPositionForValue(float value) const |
108 { | 120 { |
109 int position = (log10(value) - m_minlog) * m_ratio + m_minpos; | 121 int position = getPositionForValueUnclamped(value); |
110 if (position < m_minpos) position = m_minpos; | 122 if (position < m_minpos) position = m_minpos; |
111 if (position > m_maxpos) position = m_maxpos; | 123 if (position > m_maxpos) position = m_maxpos; |
112 // SVDEBUG << "LogRangeMapper::getPositionForValue: " << value << " -> " | 124 return position; |
113 // << position << " (minpos " << m_minpos << ", maxpos " << m_maxpos << ", ratio " << m_ratio << ", minlog " << m_minlog << ")" << endl; | 125 } |
114 if (m_inverted) return m_maxpos - position; | 126 |
127 int | |
128 LogRangeMapper::getPositionForValueUnclamped(float value) const | |
129 { | |
130 static float thresh = powf(10, -10); | |
131 if (value < thresh) value = thresh; | |
132 int position = lrintf((log10(value) - m_minlog) * m_ratio) + m_minpos; | |
133 if (m_inverted) return m_maxpos - (position - m_minpos); | |
115 else return position; | 134 else return position; |
116 } | 135 } |
117 | 136 |
118 float | 137 float |
119 LogRangeMapper::getValueForPosition(int position) const | 138 LogRangeMapper::getValueForPosition(int position) const |
120 { | 139 { |
121 if (m_inverted) position = m_maxpos - position; | 140 if (position < m_minpos) position = m_minpos; |
141 if (position > m_maxpos) position = m_maxpos; | |
142 float value = getValueForPositionUnclamped(position); | |
143 return value; | |
144 } | |
145 | |
146 float | |
147 LogRangeMapper::getValueForPositionUnclamped(int position) const | |
148 { | |
149 if (m_inverted) position = m_maxpos - (position - m_minpos); | |
122 float value = powf(10, (position - m_minpos) / m_ratio + m_minlog); | 150 float value = powf(10, (position - m_minpos) / m_ratio + m_minlog); |
123 // SVDEBUG << "LogRangeMapper::getValueForPosition: " << position << " -> " | |
124 // << value << " (minpos " << m_minpos << ", maxpos " << m_maxpos << ", ratio " << m_ratio << ", minlog " << m_minlog << ")" << endl; | |
125 return value; | 151 return value; |
126 } | 152 } |
127 | 153 |
154 InterpolatingRangeMapper::InterpolatingRangeMapper(CoordMap pointMappings, | |
155 QString unit) : | |
156 m_mappings(pointMappings), | |
157 m_unit(unit) | |
158 { | |
159 for (CoordMap::const_iterator i = m_mappings.begin(); | |
160 i != m_mappings.end(); ++i) { | |
161 m_reverse[i->second] = i->first; | |
162 } | |
163 } | |
164 | |
165 int | |
166 InterpolatingRangeMapper::getPositionForValue(float value) const | |
167 { | |
168 int pos = getPositionForValueUnclamped(value); | |
169 CoordMap::const_iterator i = m_mappings.begin(); | |
170 if (pos < i->second) pos = i->second; | |
171 i = m_mappings.end(); --i; | |
172 if (pos > i->second) pos = i->second; | |
173 return pos; | |
174 } | |
175 | |
176 int | |
177 InterpolatingRangeMapper::getPositionForValueUnclamped(float value) const | |
178 { | |
179 float p = interpolate(&m_mappings, value); | |
180 return lrintf(p); | |
181 } | |
182 | |
183 float | |
184 InterpolatingRangeMapper::getValueForPosition(int position) const | |
185 { | |
186 float val = getValueForPositionUnclamped(position); | |
187 CoordMap::const_iterator i = m_mappings.begin(); | |
188 if (val < i->first) val = i->first; | |
189 i = m_mappings.end(); --i; | |
190 if (val > i->first) val = i->first; | |
191 return val; | |
192 } | |
193 | |
194 float | |
195 InterpolatingRangeMapper::getValueForPositionUnclamped(int position) const | |
196 { | |
197 return interpolate(&m_reverse, position); | |
198 } | |
199 | |
200 template <typename T> | |
201 float | |
202 InterpolatingRangeMapper::interpolate(T *mapping, float value) const | |
203 { | |
204 // lower_bound: first element which does not compare less than value | |
205 typename T::const_iterator i = mapping->lower_bound(value); | |
206 | |
207 if (i == mapping->begin()) { | |
208 // value is less than or equal to first element, so use the | |
209 // gradient from first to second and extend it | |
210 ++i; | |
211 } | |
212 | |
213 if (i == mapping->end()) { | |
214 // value is off the end, so use the gradient from penultimate | |
215 // to ultimate and extend it | |
216 --i; | |
217 } | |
218 | |
219 typename T::const_iterator j = i; | |
220 --j; | |
221 | |
222 float gradient = float(i->second - j->second) / float(i->first - j->first); | |
223 | |
224 return j->second + (value - j->first) * gradient; | |
225 } | |
226 | |
227 AutoRangeMapper::AutoRangeMapper(CoordMap pointMappings, | |
228 QString unit) : | |
229 m_mappings(pointMappings), | |
230 m_unit(unit) | |
231 { | |
232 m_type = chooseMappingTypeFor(m_mappings); | |
233 | |
234 CoordMap::const_iterator first = m_mappings.begin(); | |
235 CoordMap::const_iterator last = m_mappings.end(); | |
236 --last; | |
237 | |
238 switch (m_type) { | |
239 case StraightLine: | |
240 m_mapper = new LinearRangeMapper(first->second, last->second, | |
241 first->first, last->first, | |
242 unit, false); | |
243 break; | |
244 case Logarithmic: | |
245 m_mapper = new LogRangeMapper(first->second, last->second, | |
246 first->first, last->first, | |
247 unit, false); | |
248 break; | |
249 case Interpolating: | |
250 m_mapper = new InterpolatingRangeMapper(m_mappings, unit); | |
251 break; | |
252 } | |
253 } | |
254 | |
255 AutoRangeMapper::~AutoRangeMapper() | |
256 { | |
257 delete m_mapper; | |
258 } | |
259 | |
260 AutoRangeMapper::MappingType | |
261 AutoRangeMapper::chooseMappingTypeFor(const CoordMap &mappings) | |
262 { | |
263 // how do we work out whether a linear/log mapping is "close enough"? | |
264 | |
265 CoordMap::const_iterator first = mappings.begin(); | |
266 CoordMap::const_iterator last = mappings.end(); | |
267 --last; | |
268 | |
269 LinearRangeMapper linm(first->second, last->second, | |
270 first->first, last->first, | |
271 "", false); | |
272 | |
273 bool inadequate = false; | |
274 | |
275 for (CoordMap::const_iterator i = mappings.begin(); | |
276 i != mappings.end(); ++i) { | |
277 int candidate = linm.getPositionForValue(i->first); | |
278 int diff = candidate - i->second; | |
279 if (diff < 0) diff = -diff; | |
280 if (diff > 1) { | |
281 // cerr << "AutoRangeMapper::chooseMappingTypeFor: diff = " << diff | |
282 // << ", straight-line mapping inadequate" << endl; | |
283 inadequate = true; | |
284 break; | |
285 } | |
286 } | |
287 | |
288 if (!inadequate) { | |
289 return StraightLine; | |
290 } | |
291 | |
292 LogRangeMapper logm(first->second, last->second, | |
293 first->first, last->first, | |
294 "", false); | |
295 | |
296 inadequate = false; | |
297 | |
298 for (CoordMap::const_iterator i = mappings.begin(); | |
299 i != mappings.end(); ++i) { | |
300 int candidate = logm.getPositionForValue(i->first); | |
301 int diff = candidate - i->second; | |
302 if (diff < 0) diff = -diff; | |
303 if (diff > 1) { | |
304 // cerr << "AutoRangeMapper::chooseMappingTypeFor: diff = " << diff | |
305 // << ", log mapping inadequate" << endl; | |
306 inadequate = true; | |
307 break; | |
308 } | |
309 } | |
310 | |
311 if (!inadequate) { | |
312 return Logarithmic; | |
313 } | |
314 | |
315 return Interpolating; | |
316 } | |
317 | |
318 int | |
319 AutoRangeMapper::getPositionForValue(float value) const | |
320 { | |
321 return m_mapper->getPositionForValue(value); | |
322 } | |
323 | |
324 float | |
325 AutoRangeMapper::getValueForPosition(int position) const | |
326 { | |
327 return m_mapper->getValueForPosition(position); | |
328 } | |
329 | |
330 int | |
331 AutoRangeMapper::getPositionForValueUnclamped(float value) const | |
332 { | |
333 return m_mapper->getPositionForValueUnclamped(value); | |
334 } | |
335 | |
336 float | |
337 AutoRangeMapper::getValueForPositionUnclamped(int position) const | |
338 { | |
339 return m_mapper->getValueForPositionUnclamped(position); | |
340 } |