RulerTicks.hxx

Go to the documentation of this file.
00001 #ifndef RulerTicks_hxx
00002 #define RulerTicks_hxx
00003 
00004 #include <cmath>
00005 #include "Assert.hxx"
00006 namespace CLAM
00007 {
00008 
00009 /*
00010         Implements the logic to place graphically several markers
00011         in a ruler so that the markers are placed with a given
00012         minimal separation and corresponds to round numbers
00013         on the mapped domain interval.
00014         So, given a domain value range, a pixel size and a minimal pixel gap,
00015         it gives you the domain offset for the first tick and the intertick gap
00016         also in domain units.
00017         Chosen round numbers are series so that the last non zero
00018         decimal steps in 1, 2 or 5 jumps and include 0. For instance:
00019         - 3.1, 3.2, 3.3...
00020         - 22, 24, 26...
00021         - 0.35, 0.40, 0.45...
00022 */
00023 class RulerTicks
00024 {
00025                 mutable bool _needsUpdate;
00026 
00027                 double _min;
00028                 double _max;
00029                 double _minGap;
00030                 double _width;
00031 
00032                 mutable double _markOffset;
00033                 mutable double _markGap;
00034         public:
00035                 RulerTicks()
00036                         : _needsUpdate(true)
00037                         , _min(0)
00038                         , _max(1)
00039                         , _minGap(5)
00040                         , _width(100)
00041                         , _markOffset(666)
00042                         , _markGap(69)
00043                 {
00044                 }
00046                 void setRange(double min, double max)
00047                 {
00048                         CLAM_ASSERT(min<max, "RulerTicks: Empty or inverse order range");
00049                         _min = min;
00050                         _max = max;
00051                         _needsUpdate = true;
00052                 }
00054                 void setWidth(double width)
00055                 {
00056                         CLAM_ASSERT(width>0, "RulerTicks: Pixel width should be greater than zero");
00057                         _width = width;
00058                         _needsUpdate = true;
00059                 }
00061                 void setMinGap(double minGap)
00062                 {
00063                         _minGap = minGap;
00064                         _needsUpdate = true;
00065                 }
00066                 double markOffset() const
00067                 {
00068                         if (_needsUpdate) update();
00069                         return _markOffset;
00070                 }
00071                 double markGap() const
00072                 {
00073                         if (_needsUpdate) update();
00074                         return _markGap;
00075                 }
00076                 void update() const
00077                 {
00078                         double mappedMinGap = std::fabs(_minGap*(_max-_min)/_width);
00079                         _markGap=1;
00080                         if (mappedMinGap>=1)
00081                         {
00082                                 while (true)
00083                                 {
00084                                         if (_markGap>=mappedMinGap) break;
00085                                         if (_markGap*2>=mappedMinGap) {_markGap*=2; break;}
00086                                         if (_markGap*5>=mappedMinGap) {_markGap*=5; break;}
00087                                         _markGap*=10;
00088                                 }
00089                         }
00090                         else
00091                         {
00092                                 while (true)
00093                                 {
00094                                         if (_markGap<1e-8) {_markGap=1e-8; break;}
00095                                         if (_markGap<mappedMinGap) {break;}
00096                                         if (_markGap/2<mappedMinGap) {_markGap/=2; break;}
00097                                         if (_markGap/5<mappedMinGap) {_markGap/=5; break;}
00098                                         _markGap/=10;
00099                                 }
00100                         }
00101                         double ceil = std::ceil(_min/_markGap);
00102                         _markOffset = (std::fabs(ceil)<1e-5)? 0. : ceil*_markGap;
00103 
00104                         _needsUpdate = false;
00105                 }
00107                 double tickValue(unsigned i) const
00108                 {
00109                         if (_needsUpdate) update();
00110                         return _markOffset+_markGap*i;
00111                 }
00113                 double pixelTickPos(unsigned i) const
00114                 {
00115                         return toPixel(tickValue(i));
00116                 }
00117                 // Returns the pixel position of a given domain value
00118                 double toPixel(double value) const
00119                 {
00120                         return (value-_min)*_width/(_max-_min);
00121                 }
00122                 // Returns the number of ticks that will appear
00123                 unsigned nTicks() const
00124                 {
00125                         if (_needsUpdate) update();
00126                         return std::ceil((_max-_markOffset)/_markGap);
00127                 }
00128 };
00129 
00130 } // namespace CLAM
00131 
00132 #endif//RulerTicks_hxx
00133 
Generated by  doxygen 1.6.3