// Copyright (C) 2010, Guy Barrand. All rights reserved. // See the file tools.license for terms. #ifndef tools_axis #define tools_axis #include "mathf" namespace tools { class axis { public: axis() :m_min_value(0) ,m_max_value(0) ,m_steps(0) ,m_is_log(false) {} virtual ~axis(){} public: axis(const axis& a_from) :m_min_value(a_from.m_min_value) ,m_max_value(a_from.m_max_value) ,m_steps(a_from.m_steps) ,m_is_log(a_from.m_is_log) {} axis& operator=(const axis& a_from){ m_min_value = a_from.m_min_value; m_max_value = a_from.m_max_value; m_steps = a_from.m_steps; m_is_log = a_from.m_is_log; return *this; } public: bool is_log(bool a_v){ if(m_is_log==a_v) return false; m_is_log = a_v; return true; } bool min_value(float a_v) { if(m_min_value==a_v) return false; m_min_value = a_v; return true; } bool max_value(float a_v) { if(m_max_value==a_v) return false; m_max_value = a_v; return true; } float min_value() const {return m_min_value;} float max_value() const {return m_max_value;} bool is_log() const {return m_is_log;} void adjust_axis() { //from hippodraw. int _axis = 0; float step; float mylow, myhigh; int N_NICE = 4; static const float nice[/*N_NICE*/4] = { 1.0,2.0,2.5,5.0 }; if (m_min_value > m_max_value) { float low = m_min_value; m_min_value = m_max_value; m_max_value = low; } else if (m_min_value == m_max_value) { float value = m_min_value; m_min_value = value - 1; m_max_value = value + 1; return; } if (m_steps <= 0) { _axis = 1; m_steps = 10; } // Round the "bin width" to a nice number. // If this is being done for an axis (ie m_steps was 0 , then // we don't have to go > *m_max_value. // float w = (m_max_value - m_min_value)/((float)m_steps); float mag = ffloor(flog10(w)); int i = 0; do { step = nice[i] * fpow(10.0,mag); mylow = ffloor(m_min_value/step) * step; myhigh = _axis==1 ? fceil(m_max_value/step) * step : mylow + step * m_steps; i++; if (i>=N_NICE) { i = 0; mag++; } } while ( ( (_axis==1) && myhigh < m_max_value) || ( (_axis==0) && myhigh <= m_max_value) ); float range = myhigh - mylow; // we now have decided on a range. Try to move // m_min_value/m_max_value a little // to end up on a nice number. // // first check if either end is near 0.0 if ( !m_is_log && (m_min_value >= 0.0) && (( (_axis==1) && (range>=m_max_value) ) || ( (_axis==0) && (range>m_max_value) )) ) { m_min_value = 0.0; m_max_value = range; return; } if ( (( (_axis==1) && (m_max_value<=0.0) ) || ( (_axis==0) && (m_max_value<0.0) )) && (-range<=m_min_value)) { m_max_value = 0.0; m_min_value = -range; return; } // try to round *m_min_value. // correction if( m_is_log && (m_min_value<=0.0)) { m_min_value = 1.0; } i = N_NICE-1; mag = myhigh != 0.0 ? fceil(flog10(ffabs(myhigh))) : fceil(flog10(ffabs(mylow))); do { step = nice[i] * fpow(10.0,mag); mylow = ffloor(m_min_value/step) * step; myhigh = mylow + range; i--; if (i<0) { i = N_NICE-1; mag--; } } while (( m_is_log && (mylow <= 0.0) ) || ( (_axis==1) && (myhigh < m_max_value) ) || ( (_axis==0) && (myhigh <= m_max_value) ) ); m_min_value = mylow; m_max_value = myhigh; } protected: float m_min_value; float m_max_value; int m_steps; bool m_is_log; }; } #endif