~ubuntu-branches/ubuntu/wily/openms/wily

« back to all changes in this revision

Viewing changes to source/VISUAL/AxisPainter.C

  • Committer: Package Import Robot
  • Author(s): Filippo Rusconi
  • Date: 2012-11-12 15:58:12 UTC
  • Revision ID: package-import@ubuntu.com-20121112155812-vr15wtg9b50cuesg
Tags: upstream-1.9.0
ImportĀ upstreamĀ versionĀ 1.9.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// -*- mode: C++; tab-width: 2; -*-
 
2
// vi: set ts=2:
 
3
//
 
4
// --------------------------------------------------------------------------
 
5
//                   OpenMS Mass Spectrometry Framework
 
6
// --------------------------------------------------------------------------
 
7
//  Copyright (C) 2003-2011 -- Oliver Kohlbacher, Knut Reinert
 
8
//
 
9
//  This library is free software; you can redistribute it and/or
 
10
//  modify it under the terms of the GNU Lesser General Public
 
11
//  License as published by the Free Software Foundation; either
 
12
//  version 2.1 of the License, or (at your option) any later version.
 
13
//
 
14
//  This library is distributed in the hope that it will be useful,
 
15
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
16
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
17
//  Lesser General Public License for more details.
 
18
//
 
19
//  You should have received a copy of the GNU Lesser General Public
 
20
//  License along with this library; if not, write to the Free Software
 
21
//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
22
//
 
23
// --------------------------------------------------------------------------
 
24
// $Maintainer: Timo Sachsenberg $
 
25
// $Authors: Timo Sachsenberg $
 
26
// --------------------------------------------------------------------------
 
27
 
 
28
#include <OpenMS/VISUAL/AxisPainter.h>
 
29
#include <OpenMS/MATH/MISC/MathFunctions.h>
 
30
 
 
31
using namespace std;
 
32
 
 
33
namespace OpenMS
 
34
{
 
35
  using namespace Math;
 
36
 
 
37
  void AxisPainter::paint(QPainter* painter, QPaintEvent*, const DoubleReal& min, const DoubleReal& max, const GridVector& grid,
 
38
                          const Int width, const Int height, const AxisPainter::Alignment alignment, const UInt margin,
 
39
                          bool show_legend, String legend, bool shorten_number,
 
40
                          bool is_log, bool is_inverse_orientation)
 
41
  {
 
42
    // position of the widget
 
43
    bool horizontal_alignment = (alignment == BOTTOM || alignment == TOP);
 
44
 
 
45
    // spacing between ticks and text
 
46
    const UInt tick_spacing = 4;
 
47
 
 
48
    // determine paintable area without margin
 
49
    UInt h = height;
 
50
    UInt w = width;
 
51
    w = (horizontal_alignment) ? w - margin : w;
 
52
    h = (horizontal_alignment) ? h : h - margin;
 
53
 
 
54
    // paint axis lines
 
55
    switch (alignment)
 
56
    {
 
57
    case BOTTOM:
 
58
      painter->drawLine(0, 0, w-1, 0);
 
59
      break;
 
60
    case TOP:
 
61
      painter->drawLine(0, h-1, w-1, h-1);
 
62
      break;
 
63
    case LEFT:
 
64
      painter->drawLine(w-1, 0 , w-1, h-1);
 
65
      break;
 
66
    case RIGHT:
 
67
      painter->drawLine(0, 0 , 0, h-1);
 
68
      break;
 
69
    }
 
70
 
 
71
    // shrink font size if text does not fit
 
72
    UInt font_size = painter->font().pointSize();
 
73
    UInt max_width = 0;
 
74
 
 
75
    if (grid.size() >= 1) //check big intervals only
 
76
    {
 
77
      QFontMetrics metrics(QFont(painter->font().family(), font_size));
 
78
      for (Size i = 0; i < grid[0].size(); i++)
 
79
      {
 
80
        QString tmp;
 
81
        if (shorten_number)
 
82
        {
 
83
          getShortenedNumber_(tmp, scale_(grid[0][i], is_log));
 
84
        } else
 
85
        {
 
86
          tmp = QString("%1").arg(scale_(grid[0][i], is_log));
 
87
        }
 
88
        QRect rect = metrics.boundingRect(tmp);
 
89
        max_width = std::max(max_width,(UInt)rect.width());
 
90
      }
 
91
    }
 
92
 
 
93
    //shrink font if too much text it displayed
 
94
    UInt overall_required_pixels = 0;
 
95
    if (horizontal_alignment)
 
96
    {
 
97
      Size tick_count = 0;
 
98
      for (Size i=0; i<grid.size(); i++)
 
99
      {
 
100
        tick_count += grid[i].size();
 
101
      }
 
102
      overall_required_pixels = (UInt)(max_width*tick_count);
 
103
    }
 
104
    else // Shrink font if the largest text is too big
 
105
    {
 
106
      overall_required_pixels = UInt(max_width  + 0.25*font_size + tick_spacing);
 
107
    }
 
108
 
 
109
    if (w < overall_required_pixels)
 
110
    {
 
111
      font_size = UInt(font_size * w / overall_required_pixels);
 
112
    }
 
113
 
 
114
    // Painting tick levels
 
115
    for (Size i = 0; i != grid.size(); i++)
 
116
    {
 
117
      // Just draw text on big intervalls
 
118
      if (is_log && i > 0)
 
119
      {
 
120
        break;
 
121
      }
 
122
 
 
123
      QColor text_color;
 
124
      UInt tick_size = 0;
 
125
      QFontMetrics metrics(painter->font());
 
126
 
 
127
      if (i == 0) // big intervals
 
128
      {
 
129
        painter->setFont(QFont(painter->font().family(), UInt(font_size)));
 
130
        metrics = QFontMetrics(painter->font());
 
131
        tick_size = UInt(0.33 * font_size);
 
132
        text_color = QColor(0, 0, 0);
 
133
      }
 
134
      else // small intervals
 
135
      {
 
136
        painter->setFont(QFont(painter->font().family(), UInt(0.8*font_size)));
 
137
        metrics = QFontMetrics(painter->font());
 
138
        tick_size = UInt(0.25 * font_size);
 
139
        text_color = QColor(20, 20, 20);
 
140
      }
 
141
 
 
142
      // painting all ticks of the level
 
143
      UInt i_beg = (horizontal_alignment)? 0 : h;
 
144
      UInt i_end = (horizontal_alignment)? w : 0;
 
145
      for (Size j = 0; j != grid[i].size(); j++)
 
146
      {
 
147
        UInt tick_pos;
 
148
        if (is_inverse_orientation)
 
149
        {
 
150
          tick_pos = UInt(intervalTransformation(grid[i][j], min, max, i_end, i_beg)) + ((alignment==LEFT || alignment==RIGHT)?-1:1)*margin;
 
151
        }
 
152
        else
 
153
        {
 
154
          tick_pos = UInt(intervalTransformation(grid[i][j], min, max, i_beg, i_end));
 
155
        }
 
156
 
 
157
        // paint ticks
 
158
        painter->setPen(QPen(Qt::black));
 
159
        switch (alignment)
 
160
        {
 
161
        case BOTTOM:
 
162
          painter->drawLine(tick_pos, 0, tick_pos, tick_size);
 
163
          break;
 
164
        case TOP:
 
165
          painter->drawLine(tick_pos, h, tick_pos,  h-tick_size);
 
166
          break;
 
167
        case LEFT:
 
168
          painter->drawLine(w-tick_size, tick_pos+margin, w, tick_pos+margin);
 
169
          break;
 
170
        case RIGHT:
 
171
          painter->drawLine(0, tick_pos+margin, tick_size, tick_pos+margin);
 
172
          break;
 
173
        }
 
174
 
 
175
        // values at axis lines
 
176
 
 
177
        // count number of grid lines
 
178
        Size gl_count = 0;
 
179
        for (GridVector::const_iterator it = grid.begin(); it != grid.end(); ++it)
 
180
        {
 
181
          gl_count += it->size();
 
182
        }
 
183
        //  if there are too many grid lines, hide every odd minor grid line value
 
184
        if (gl_count >= 30 && i == 1)
 
185
        {
 
186
          // needed because skips occur in small grid lines at the position of big grid lines
 
187
          DoubleReal dist_small = std::min<DoubleReal>(fabs(grid[1][1] - grid[1][0]), fabs(grid[1][2] - grid[1][1]));
 
188
          UInt n = Math::round((grid[1][j] - grid[0][0]) / dist_small);
 
189
          if (n % 2 == 1)
 
190
          {
 
191
            continue;
 
192
          }
 
193
        }
 
194
 
 
195
        QString text;
 
196
        if (shorten_number)
 
197
        {
 
198
          getShortenedNumber_(text, scale_(grid[i][j], is_log));
 
199
        } else
 
200
        {
 
201
          text = QString("%1").arg(scale_(grid[i][j], is_log));
 
202
        }
 
203
 
 
204
        painter->setPen(QPen(text_color));
 
205
 
 
206
        // get bounding rectangle for text we want to layout
 
207
        QRect textbound = metrics.boundingRect(text);
 
208
 
 
209
        // Calculate text position
 
210
        UInt x_pos = 0;
 
211
        switch (alignment)
 
212
        {
 
213
        case BOTTOM:
 
214
        case TOP:
 
215
          x_pos = tick_pos - UInt(0.5*textbound.width());
 
216
          break;
 
217
        case LEFT:
 
218
          x_pos = w - (tick_size + tick_spacing) - textbound.width();
 
219
          break;
 
220
        case RIGHT:
 
221
          x_pos = tick_size + tick_spacing;
 
222
          break;
 
223
        }
 
224
 
 
225
        UInt y_pos = 0;
 
226
        switch (alignment)
 
227
        {
 
228
        case BOTTOM:
 
229
          y_pos = tick_size + tick_spacing + UInt(0.5*textbound.height());
 
230
          break;
 
231
        case TOP:
 
232
          y_pos = h - (tick_size + tick_spacing);
 
233
          break;
 
234
        case LEFT:
 
235
        case RIGHT:
 
236
          y_pos = tick_pos + margin + UInt(0.25*textbound.height());
 
237
          break;
 
238
        }
 
239
        painter->drawText(x_pos, y_pos, text);
 
240
      }
 
241
    }
 
242
 
 
243
    // Painting legend
 
244
    if (show_legend && legend != "")
 
245
    {
 
246
      // style settings
 
247
      painter->setPen(QPen(Qt::black));
 
248
 
 
249
      switch (alignment)
 
250
      {
 
251
      case BOTTOM:
 
252
        painter->drawText(0, 0 ,  w, h, Qt::AlignBottom|Qt::AlignHCenter, legend.c_str());
 
253
        break;
 
254
      case TOP:
 
255
        painter->drawText(0, 0 ,  w, h, Qt::AlignTop|Qt::AlignHCenter, legend.c_str());
 
256
        break;
 
257
      case LEFT:
 
258
        painter->rotate(270);
 
259
        painter->drawText(-(int)h, 0 ,h ,w, Qt::AlignHCenter|Qt::AlignTop, legend.c_str());
 
260
        break;
 
261
      case RIGHT:
 
262
        painter->rotate(270);
 
263
        painter->drawText(-(int)h, 0 ,h ,w, Qt::AlignHCenter|Qt::AlignBottom, legend.c_str());
 
264
        break;
 
265
      }
 
266
    }
 
267
  }
 
268
 
 
269
  void AxisPainter::getShortenedNumber_(QString& short_num, DoubleReal number)
 
270
  {
 
271
    if (number < 1000.0)
 
272
    {
 
273
      short_num = QString("%1").arg(number);
 
274
    }
 
275
    else if (number < 1000000.0)
 
276
    {
 
277
      short_num = QString("%1k").arg(Math::roundDecimal(number/1000.0, -2));
 
278
    }
 
279
    else if (number < 1000000000.0)
 
280
    {
 
281
      short_num = QString("%1M").arg(number/1000000.0);
 
282
    }
 
283
    else
 
284
    {
 
285
      short_num = QString("%1G").arg(number/1000000000.0);
 
286
    }
 
287
  }
 
288
 
 
289
  DoubleReal AxisPainter::scale_(DoubleReal x, bool is_log)
 
290
  {
 
291
    return (is_log) ? Math::roundDecimal(pow(10,x),-8) : Math::roundDecimal(x,-8);
 
292
  }
 
293
 
 
294
}