svcore  1.9
RangeMapper.cpp
Go to the documentation of this file.
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
2 
3 /*
4  Sonic Visualiser
5  An audio file viewer and annotation editor.
6  Centre for Digital Music, Queen Mary, University of London.
7  This file copyright 2006 QMUL.
8 
9  This program is free software; you can redistribute it and/or
10  modify it under the terms of the GNU General Public License as
11  published by the Free Software Foundation; either version 2 of the
12  License, or (at your option) any later version. See the file
13  COPYING included with this distribution for more information.
14 */
15 
16 #include "RangeMapper.h"
17 #include "system/System.h"
18 
19 #include <cassert>
20 #include <cmath>
21 
22 #include <iostream>
23 
24 LinearRangeMapper::LinearRangeMapper(int minpos, int maxpos,
25  float minval, float maxval,
26  QString unit, bool inverted) :
27  m_minpos(minpos),
28  m_maxpos(maxpos),
29  m_minval(minval),
30  m_maxval(maxval),
31  m_unit(unit),
32  m_inverted(inverted)
33 {
34  assert(m_maxval != m_minval);
35  assert(m_maxpos != m_minpos);
36 }
37 
38 int
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
49 {
50  int position = m_minpos +
51  lrintf(((value - m_minval) / (m_maxval - m_minval))
52  * (m_maxpos - m_minpos));
53  if (m_inverted) return m_maxpos - (position - m_minpos);
54  else return position;
55 }
56 
57 float
59 {
60  if (position < m_minpos) position = m_minpos;
61  if (position > m_maxpos) position = m_maxpos;
62  float value = getValueForPositionUnclamped(position);
63  return value;
64 }
65 
66 float
68 {
69  if (m_inverted) position = m_maxpos - (position - m_minpos);
70  float value = m_minval +
71  ((float(position - m_minpos) / float(m_maxpos - m_minpos))
72  * (m_maxval - m_minval));
73  return value;
74 }
75 
76 LogRangeMapper::LogRangeMapper(int minpos, int maxpos,
77  float minval, float maxval,
78  QString unit, bool inverted) :
79  m_minpos(minpos),
80  m_maxpos(maxpos),
81  m_unit(unit),
82  m_inverted(inverted)
83 {
84  convertMinMax(minpos, maxpos, minval, maxval, m_minlog, m_ratio);
85 
86 // cerr << "LogRangeMapper: minpos " << minpos << ", maxpos "
87 // << maxpos << ", minval " << minval << ", maxval "
88 // << maxval << ", minlog " << m_minlog << ", ratio " << m_ratio
89 // << ", unit " << unit << endl;
90 
91  assert(m_maxpos != m_minpos);
92 
94 
95 // cerr << "LogRangeMapper: maxlog = " << m_maxlog << endl;
96 }
97 
98 void
99 LogRangeMapper::convertMinMax(int minpos, int maxpos,
100  float minval, float maxval,
101  float &minlog, float &ratio)
102 {
103  static float thresh = powf(10, -10);
104  if (minval < thresh) minval = thresh;
105  minlog = log10f(minval);
106  ratio = (maxpos - minpos) / (log10f(maxval) - minlog);
107 }
108 
109 void
110 LogRangeMapper::convertRatioMinLog(float ratio, float minlog,
111  int minpos, int maxpos,
112  float &minval, float &maxval)
113 {
114  minval = powf(10, minlog);
115  maxval = powf(10, (maxpos - minpos) / ratio + minlog);
116 }
117 
118 int
120 {
121  int position = getPositionForValueUnclamped(value);
122  if (position < m_minpos) position = m_minpos;
123  if (position > m_maxpos) position = m_maxpos;
124  return position;
125 }
126 
127 int
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);
134  else return position;
135 }
136 
137 float
139 {
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
148 {
149  if (m_inverted) position = m_maxpos - (position - m_minpos);
150  float value = powf(10, (position - m_minpos) / m_ratio + m_minlog);
151  return value;
152 }
153 
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
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
178 {
179  float p = interpolate(&m_mappings, value);
180  return lrintf(p);
181 }
182 
183 float
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
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 
228  QString unit) :
229  m_mappings(pointMappings),
230  m_unit(unit)
231 {
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:
251  break;
252  }
253 }
254 
256 {
257  delete m_mapper;
258 }
259 
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
320 {
321  return m_mapper->getPositionForValue(value);
322 }
323 
324 float
326 {
327  return m_mapper->getValueForPosition(position);
328 }
329 
330 int
332 {
333  return m_mapper->getPositionForValueUnclamped(value);
334 }
335 
336 float
338 {
339  return m_mapper->getValueForPositionUnclamped(position);
340 }
LinearRangeMapper(int minpos, int maxpos, float minval, float maxval, QString unit="", bool inverted=false)
Map values in range minval->maxval linearly into integer range minpos->maxpos.
Definition: RangeMapper.cpp:24
virtual float getValueForPosition(int position) const
Return the value mapped from the given position, clamping to the minimum and maximum extents of the m...
static void convertRatioMinLog(float ratio, float minlog, int minpos, int maxpos, float &minval, float &maxval)
MappingType m_type
Definition: RangeMapper.h:247
virtual float getValueForPositionUnclamped(int position) const
Return the value mapped from the given positionq, without clamping.
float interpolate(T *mapping, float v) const
std::map< float, int > CoordMap
Definition: RangeMapper.h:191
virtual int getPositionForValueUnclamped(float value) const
Return the position that maps to the given value, rounding to the nearest position,...
std::map< int, float > m_reverse
Definition: RangeMapper.h:175
virtual float getValueForPosition(int position) const
Return the value mapped from the given position, clamping to the minimum and maximum extents of the m...
MappingType chooseMappingTypeFor(const CoordMap &)
RangeMapper * m_mapper
Definition: RangeMapper.h:250
static void convertMinMax(int minpos, int maxpos, float minval, float maxval, float &ratio, float &minlog)
Definition: RangeMapper.cpp:99
virtual float getValueForPositionUnclamped(int position) const =0
Return the value mapped from the given positionq, without clamping.
virtual int getPositionForValue(float value) const
Return the position that maps to the given value, rounding to the nearest position and clamping to th...
InterpolatingRangeMapper(CoordMap pointMappings, QString unit)
Given a series of (value, position) coordinate mappings, construct a range mapper that maps arbitrary...
virtual float getValueForPosition(int position) const
Return the value mapped from the given position, clamping to the minimum and maximum extents of the m...
Definition: RangeMapper.cpp:58
LogRangeMapper(int minpos, int maxpos, float minval, float maxval, QString m_unit="", bool inverted=false)
Map values in range minval->maxval into integer range minpos->maxpos such that logs of the values are...
Definition: RangeMapper.cpp:76
virtual int getPositionForValue(float value) const
Return the position that maps to the given value, rounding to the nearest position and clamping to th...
virtual int getPositionForValueUnclamped(float value) const =0
Return the position that maps to the given value, rounding to the nearest position,...
virtual float getValueForPositionUnclamped(int position) const
Return the value mapped from the given positionq, without clamping.
virtual int getPositionForValueUnclamped(float value) const
Return the position that maps to the given value, rounding to the nearest position,...
virtual int getPositionForValueUnclamped(float value) const
Return the position that maps to the given value, rounding to the nearest position,...
Definition: RangeMapper.cpp:48
std::map< float, int > CoordMap
Definition: RangeMapper.h:142
virtual float getValueForPositionUnclamped(int position) const
Return the value mapped from the given positionq, without clamping.
virtual int getPositionForValue(float value) const
Return the position that maps to the given value, rounding to the nearest position and clamping to th...
virtual int getPositionForValue(float value) const
Return the position that maps to the given value, rounding to the nearest position and clamping to th...
Definition: RangeMapper.cpp:39
virtual int getPositionForValueUnclamped(float value) const
Return the position that maps to the given value, rounding to the nearest position,...
virtual int getPositionForValue(float value) const =0
Return the position that maps to the given value, rounding to the nearest position and clamping to th...
virtual float getValueForPosition(int position) const =0
Return the value mapped from the given position, clamping to the minimum and maximum extents of the m...
virtual float getValueForPositionUnclamped(int position) const
Return the value mapped from the given positionq, without clamping.
Definition: RangeMapper.cpp:67
AutoRangeMapper(CoordMap pointMappings, QString unit)
Given a series of (value, position) coordinate mappings, construct a range mapper that maps arbitrary...
CoordMap m_mappings
Definition: RangeMapper.h:248
virtual float getValueForPosition(int position) const
Return the value mapped from the given position, clamping to the minimum and maximum extents of the m...