Mercurial > hg > svcore
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 } |