diff base/RangeMapper.cpp @ 885:12a6140b3ae0

Add unclamped range mapper methods
author Chris Cannam
date Thu, 06 Feb 2014 15:31:16 +0000
parents b4787b595db3
children cc27f35aa75c
line wrap: on
line diff
--- a/base/RangeMapper.cpp	Thu Feb 06 10:14:59 2014 +0000
+++ b/base/RangeMapper.cpp	Thu Feb 06 15:31:16 2014 +0000
@@ -38,11 +38,18 @@
 int
 LinearRangeMapper::getPositionForValue(float value) const
 {
+    int position = getPositionForValueUnclamped(value);
+    if (position < m_minpos) position = m_minpos;
+    if (position > m_maxpos) position = m_maxpos;
+    return position;
+}
+
+int
+LinearRangeMapper::getPositionForValueUnclamped(float value) const
+{
     int position = m_minpos +
         lrintf(((value - m_minval) / (m_maxval - m_minval))
                * (m_maxpos - m_minpos));
-    if (position < m_minpos) position = m_minpos;
-    if (position > m_maxpos) position = m_maxpos;
     if (m_inverted) return m_maxpos - (position - m_minpos);
     else return position;
 }
@@ -50,9 +57,16 @@
 float
 LinearRangeMapper::getValueForPosition(int position) const
 {
-    if (m_inverted) position = m_maxpos - (position - m_minpos);
     if (position < m_minpos) position = m_minpos;
     if (position > m_maxpos) position = m_maxpos;
+    float value = getValueForPositionUnclamped(position);
+    return value;
+}
+
+float
+LinearRangeMapper::getValueForPositionUnclamped(int position) const
+{
+    if (m_inverted) position = m_maxpos - (position - m_minpos);
     float value = m_minval +
         ((float(position - m_minpos) / float(m_maxpos - m_minpos))
          * (m_maxval - m_minval));
@@ -104,11 +118,18 @@
 int
 LogRangeMapper::getPositionForValue(float value) const
 {
-    int position = lrintf((log10(value) - m_minlog) * m_ratio) + m_minpos;
+    int position = getPositionForValueUnclamped(value);
     if (position < m_minpos) position = m_minpos;
     if (position > m_maxpos) position = m_maxpos;
-//    cerr << "LogRangeMapper::getPositionForValue: " << value << " -> "
-//              << position << " (minpos " << m_minpos << ", maxpos " << m_maxpos << ", ratio " << m_ratio << ", minlog " << m_minlog << ")" << endl;
+    return position;
+}
+
+int
+LogRangeMapper::getPositionForValueUnclamped(float value) const
+{
+    static float thresh = powf(10, -10);
+    if (value < thresh) value = thresh;
+    int position = lrintf((log10(value) - m_minlog) * m_ratio) + m_minpos;
     if (m_inverted) return m_maxpos - (position - m_minpos);
     else return position;
 }
@@ -116,12 +137,17 @@
 float
 LogRangeMapper::getValueForPosition(int position) const
 {
-    if (m_inverted) position = m_maxpos - (position - m_minpos);
     if (position < m_minpos) position = m_minpos;
     if (position > m_maxpos) position = m_maxpos;
+    float value = getValueForPositionUnclamped(position);
+    return value;
+}
+
+float
+LogRangeMapper::getValueForPositionUnclamped(int position) const
+{
+    if (m_inverted) position = m_maxpos - (position - m_minpos);
     float value = powf(10, (position - m_minpos) / m_ratio + m_minlog);
-//    cerr << "LogRangeMapper::getValueForPosition: " << position << " -> "
-//              << value << " (minpos " << m_minpos << ", maxpos " << m_maxpos << ", ratio " << m_ratio << ", minlog " << m_minlog << ")" << endl;
     return value;
 }
 
@@ -139,31 +165,63 @@
 int
 InterpolatingRangeMapper::getPositionForValue(float value) const
 {
-    CoordMap::const_iterator i = m_mappings.lower_bound(value);
-    CoordMap::const_iterator j = i;
-    --j;
+    int pos = getPositionForValueUnclamped(value);
+    CoordMap::const_iterator i = m_mappings.begin();
+    if (pos < i->second) pos = i->second;
+    i = m_mappings.end(); --i;
+    if (pos > i->second) pos = i->second;
+    return pos;
+}
 
-    if (i == m_mappings.end()) return j->second;
-    if (i == m_mappings.begin()) return i->second;
-    if (i->first == value) return i->second;
-
-    return lrintf(((value - j->first) / (i->first - j->first)) *
-                  float(i->second - j->second) + j->second);
+int
+InterpolatingRangeMapper::getPositionForValueUnclamped(float value) const
+{
+    float p = interpolate(&m_mappings, value);
+    return lrintf(p);
 }
 
 float
 InterpolatingRangeMapper::getValueForPosition(int position) const
 {
-    std::map<int, float>::const_iterator i = m_reverse.lower_bound(position);
-    std::map<int, float>::const_iterator j = i;
+    float val = getValueForPositionUnclamped(position);
+    CoordMap::const_iterator i = m_mappings.begin();
+    if (val < i->first) val = i->first;
+    i = m_mappings.end(); --i;
+    if (val > i->first) val = i->first;
+    return val;
+}
+
+float
+InterpolatingRangeMapper::getValueForPositionUnclamped(int position) const
+{
+    return interpolate(&m_reverse, position);
+}
+
+template <typename T>
+float
+InterpolatingRangeMapper::interpolate(T *mapping, float value) const
+{
+    // lower_bound: first element which does not compare less than value
+    typename T::const_iterator i = mapping->lower_bound(value);
+
+    if (i == mapping->begin()) {
+        // value is less than or equal to first element, so use the
+        // gradient from first to second and extend it
+        ++i;
+    }
+
+    if (i == mapping->end()) {
+        // value is off the end, so use the gradient from penultimate
+        // to ultimate and extend it
+        --i;
+    }
+
+    typename T::const_iterator j = i;
     --j;
 
-    if (i == m_reverse.end()) return j->second;
-    if (i == m_reverse.begin()) return i->second;
-    if (i->first == position) return i->second;
+    float gradient = float(i->second - j->second) / float(i->first - j->first);
 
-    return ((float(position) - j->first) / (i->first - j->first)) *
-        (i->second - j->second) + j->second;
+    return j->second + (value - j->first) * gradient;
 }
 
 AutoRangeMapper::AutoRangeMapper(CoordMap pointMappings,
@@ -220,8 +278,8 @@
         int diff = candidate - i->second;
         if (diff < 0) diff = -diff;
         if (diff > 1) {
-            cerr << "AutoRangeMapper::chooseMappingTypeFor: diff = " << diff
-                 << ", straight-line mapping inadequate" << endl;
+//            cerr << "AutoRangeMapper::chooseMappingTypeFor: diff = " << diff
+//                 << ", straight-line mapping inadequate" << endl;
             inadequate = true;
             break;
         }
@@ -243,8 +301,8 @@
         int diff = candidate - i->second;
         if (diff < 0) diff = -diff;
         if (diff > 1) {
-            cerr << "AutoRangeMapper::chooseMappingTypeFor: diff = " << diff
-                 << ", log mapping inadequate" << endl;
+//            cerr << "AutoRangeMapper::chooseMappingTypeFor: diff = " << diff
+//                 << ", log mapping inadequate" << endl;
             inadequate = true;
             break;
         }
@@ -268,3 +326,15 @@
 {
     return m_mapper->getValueForPosition(position);
 }
+
+int
+AutoRangeMapper::getPositionForValueUnclamped(float value) const
+{
+    return m_mapper->getPositionForValueUnclamped(value);
+}
+
+float
+AutoRangeMapper::getValueForPositionUnclamped(int position) const
+{
+    return m_mapper->getValueForPositionUnclamped(position);
+}