NCBI C++ ToolKit
gldrawscale.cpp
Go to the documentation of this file.

Go to the SVN repository for this file.

1 /* $Id: gldrawscale.cpp 47292 2022-12-21 00:32:34Z evgeniev $
2 * ===========================================================================
3 *
4 * PUBLIC DOMAIN NOTICE
5 * National Center for Biotechnology Information
6 *
7 * This software/database is a "United States Government Work" under the
8 * terms of the United States Copyright Act. It was written as part of
9 * the author's official duties as a United States Government employee and
10 * thus cannot be copyrighted. This software/database is freely available
11 * to the public for use. The National Library of Medicine and the U.S.
12 * Government have not placed any restriction on its use or reproduction.
13 *
14 * Although all reasonable efforts have been taken to ensure the accuracy
15 * and reliability of the software and data, the NLM and the U.S.
16 * Government do not and cannot warrant the performance or results that
17 * may be obtained by using this software or data. The NLM and the U.S.
18 * Government disclaim all warranties, express or implied, including
19 * warranties of performance, merchantability or fitness for any particular
20 * purpose.
21 *
22 * Please cite the author in any work or product based on this material.
23 *
24 * ===========================================================================
25 *
26 * Author: Philip Johnson
27 *
28 * File Description: 'gldrawscale' -- contains class to nicely draw a scale
29 * on screen (think sequence coordinates).
30 *
31 * ---------------------------------------------------------------------------
32 */
33 
34 #include <ncbi_pch.hpp>
36 #include <gui/opengl/glfont.hpp>
37 #include <gui/opengl/glutils.hpp>
38 #include <corelib/ncbistre.hpp>
39 #include <algorithm>
40 #include <math.h>
41 
43 
44 const char* CGlDrawScale::sm_SISymbols = "kMGTPEZY";
45 
46 //-----------------------------------------------------------------------------
47 //PRE : font to use for drawing scale; whether or not to use abbreviations
48 //when appropriate (and, if so, what sort to use)
49 //POST: viewscale initialized
51  : m_Font(font),
52  m_UseAbbrev(useAbbrev),
53  m_CoordConverter(NULL)
54 {
55  char tmp[2];
56  tmp[1] = '\0';
57 
58  m_MaxDigitWidth = 0;
59  for( char d = '0'; d <= '9'; ++d) {
60  tmp[0] = d;
62  }
63 
65  for(unsigned int i = 0; sm_SISymbols[i] != '\0'; ++i) {
66  tmp[0] = sm_SISymbols[i];
68  }
69 }
70 
71 //-----------------------------------------------------------------------------
72 //PRE : unsigned integer (x)
73 //POST: 10^n
74 unsigned int CGlDrawScale::x_Exp10(unsigned int x) const
75 {
76  unsigned int n;
77 
78  n = 1;
79  for(unsigned int i = 0; i < x; ++i) {
80  n *= 10;
81  }
82 
83  return n;
84 }
85 
86 
87 //-----------------------------------------------------------------------------
88 //PRE : an integer
89 //POST: if greater than 2 digits, integer rounded up to first number with
90 //only 2 significant digits; if exactly 2 digits, integer rounded up to
91 //first number with 1 significant digit; if between 5 and 10, rounded up to
92 //10; if less than 5, rounded up to 5
93 void CGlDrawScale::x_Normalize(int &num) const
94 {
95  int sign = 1;
96  if (num < 0) { //remove negative
97  sign = -1;
98  num *= -1;
99  }
100 
101  int digitsI = (num == 0) ? 1 : (int) floor(log10((float)num) + 1);
102  if (digitsI >= 3) {
103  num = (num / x_Exp10(digitsI-2) + 1) * x_Exp10(digitsI-2);
104  } else if (digitsI == 2) {
105  num = (num / x_Exp10(digitsI-1) + 1) * x_Exp10(digitsI-1);
106  } else if (num > 5) {
107  num = 10;
108  } else {
109  num = 5;
110  }
111 
112  num *= sign; //put back negative (if had in originally)
113 }
114 
115 //-----------------------------------------------------------------------------
116 //PRE : a number
117 //POST: a string representing that number
119 {
120  CNcbiOstrstream oss;
121 
122  switch(type) {
123  case eNoAbbrev:
124  oss << num;
125  break;
126 
127  case eCommas:
128  {
129  int count = 0;
130  while (abs(num) >= 10) {
131  oss << num % 10;
132  if (++count % 3 == 0) {
133  oss << ',';
134  }
135  num /= 10;
136  }
137  oss << num % 10;
138  string tmp = CNcbiOstrstreamToString(oss);
139  reverse(tmp.begin(), tmp.end());
140  return tmp;
141  }
142 
144  oss.precision(3);
145  oss.flags(oss.scientific);
146  oss << (float) num;
147  break;
148 
149  case eUseSISymbols:
150  {{
151  int prefixI = -1;
152  float decimal = (float)num;
153  while (abs(num) >= 1000) {
154  ++prefixI;
155  decimal = (float) num / 1000;
156  num /= 1000;
157  }
158  oss << decimal;
159  if (prefixI >= 0) {
160  oss << sm_SISymbols[prefixI] << '\0';
161  }
162  }}
163  break;
164  }
165 
166  return CNcbiOstrstreamToString(oss);
167 }
168 
169 //-----------------------------------------------------------------------------
170 //PRE : left-most user coordinate, right-most user coordinate
171 //POST: maximum size of label for this range
172 unsigned int CGlDrawScale::x_CalcMaxLabelSize(int left, int right,
173  EAbbrevType abbrev) const
174 {
175  unsigned int size = 0;
176 
177  int digitsL = (left == 0) ? 1 : (int) floor(log10((float)abs(left)) + 1);
178  int digitsR = (right == 0) ? 1 : (int) floor(log10((float)abs(right)) + 1);
179  switch (abbrev) {
180  case eNoAbbrev: //DDDDD..
181  size = (unsigned int)(max(digitsR, digitsL) * m_MaxDigitWidth);
182  break;
183  case eCommas: //D,DDD,DDD...
184  size =
185  (unsigned int)((max(digitsL, digitsR) + max(digitsL, digitsR) / 3)
186  * m_MaxDigitWidth);
187  break;
188  case eUseSISymbols: //DDD.DDDk
189  size = (unsigned int)(m_MaxDigitWidth * 6 + m_Font.TextWidth(".") +
191  break;
192  case eUseScientificNotation: //D.DDDe+DD
193  size = (unsigned int)(m_MaxDigitWidth * 6 + m_Font.TextWidth(".e+"));
194  break;
195  }
196 
197  if (left < 0 || right < 0) {
198  size += (unsigned int)(m_Font.TextWidth("-"));
199  }
200  return size;
201 }
202 
203 //-----------------------------------------------------------------------------
204 //PRE : width in pixels; left-most user coordinate, right-most user
205 //coordinate
206 //POST: scale drawn in the following box: left, -0.5, right, [font-height]
207 void CGlDrawScale::Draw(int width, int left, int right) const
208 {
209  if (width <= 0)
210  throw runtime_error("CGlDrawScale::Draw given non-positive width.");
211 
212  double xScale, yScale;
213  {
214  GLint viewport[4];
215  GLdouble mvMatrix[16], projMatrix[16];
216  GLdouble wx1,wx2,wy1,wy2,wz; //world coordinates
217 
218  glGetIntegerv(GL_VIEWPORT, viewport);
219  glGetDoublev(GL_MODELVIEW_MATRIX, mvMatrix);
220  glGetDoublev(GL_PROJECTION_MATRIX, projMatrix);
221 
222  int glL = m_CoordConverter ? m_CoordConverter->ToGl(left) : left;
223  int glR = m_CoordConverter ? m_CoordConverter->ToGl(right) : right;
224 
225  gluUnProjectX(glL,0,0, mvMatrix, projMatrix, viewport, &wx1,&wy1,&wz);
226  gluUnProjectX(glR,1,0, mvMatrix, projMatrix, viewport, &wx2,&wy2,&wz);
227  xScale = (wx2-wx1)/(glR-glL);
228  yScale = (wy2-wy1);
229  }
230 
231  EAbbrevType abbrevType;
232  if (m_UseAbbrev != eNoAbbrev && //use abbreviations
233  abs(right-left) > width) { //big interval
234  abbrevType = m_UseAbbrev;
235  } else {
236  abbrevType = eNoAbbrev;
237  }
238 
239  unsigned int maxLabelSize = x_CalcMaxLabelSize(left, right, abbrevType);
240  int labelInterval = (int) ceil(((float)(right-left) / width) *
241  (maxLabelSize*1.5));
242  x_Normalize(labelInterval);
243 
244  int minBound = min(left, right);
245  int maxBound = max(left, right);
246 
247 
248  int labelStart = left;
249  if (labelStart % labelInterval != 0) {
250  labelStart = (labelStart / labelInterval) * labelInterval;
251  if (labelStart < minBound || labelStart > maxBound) {
252  labelStart += labelInterval;
253  }
254  }
255 
256  //labels
257  for (int labelPos = labelStart;
258  labelPos >= minBound && labelPos <= maxBound;
259  labelPos += labelInterval) {
260  string label = x_GenerateLabel(labelPos, abbrevType);
261 
263  labelPos) -
264  (m_Font.TextWidth(label.c_str()) * xScale / 2),
265  3.0f * yScale, label.c_str());
266  }
267 
268  //tickmarks
269  glBegin(GL_LINES);
270  int tickInterval = max(1, abs(labelInterval) / 5);
271  if (labelInterval < 0) {
272  tickInterval *= -1;
273  }
274  int tickStart = left;
275  if (tickStart % tickInterval != 0) {
276  tickStart = (tickStart / tickInterval) * tickInterval;
277  if (tickStart < minBound || tickStart > maxBound) {
278  tickStart += tickInterval;
279  }
280  }
281 
282  for (int labelPos = tickStart;
283  labelPos >= minBound && labelPos <= maxBound;
284  labelPos += tickInterval) {
285  int glPos = (m_CoordConverter ? m_CoordConverter->ToGl(labelPos) :
286  labelPos);
287  glVertex2d(glPos, (labelPos % labelInterval == 0) ? -yScale * 4.0
288  : -yScale * 2.0);
289  glVertex2d(glPos, 0);
290  }
291  glEnd();
292 }
293 
CNcbiOstrstreamToString class helps convert CNcbiOstrstream to a string Sample usage:
Definition: ncbistre.hpp:802
#define NULL
Definition: ncbistd.hpp:225
string x_GenerateLabel(int num, EAbbrevType type) const
virtual TModelUnit TextWidth(const char *text) const =0
void Draw(int width, int left, int right) const
unsigned int x_Exp10(unsigned int x) const
Definition: gldrawscale.cpp:74
virtual void TextOut(const char *text) const =0
virtual int ToGl(int) const =0
CGlDrawScale(IGlFont &font, EAbbrevType useAbbrev)
Definition: gldrawscale.cpp:50
TModelUnit m_MaxDigitWidth
static const char * sm_SISymbols
IGlFont & m_Font
Definition: gldrawscale.hpp:96
CCoordConverter * m_CoordConverter
Definition: gldrawscale.hpp:98
unsigned int x_CalcMaxLabelSize(int left, int right, EAbbrevType abbrev) const
void x_Normalize(int &num) const
Definition: gldrawscale.cpp:93
int gluUnProjectX(GLdouble winx, GLdouble winy, GLdouble winz, const GLdouble modelMatrix[16], const GLdouble projMatrix[16], const GLint viewport[4], GLdouble *objx, GLdouble *objy, GLdouble *objz)
Definition: glutils.hpp:237
TModelUnit m_MaxSIPrefixWidth
EAbbrevType m_UseAbbrev
Definition: gldrawscale.hpp:97
@ eUseScientificNotation
Definition: gldrawscale.hpp:70
#define END_NCBI_SCOPE
End previously defined NCBI scope.
Definition: ncbistl.hpp:103
#define BEGIN_NCBI_SCOPE
Define ncbi namespace.
Definition: ncbistl.hpp:100
static const char label[]
unsigned int
A callback function used to compare two keys in a database.
Definition: types.hpp:1210
int i
yy_size_t n
const struct ncbi::grid::netcache::search::fields::SIZE size
#define abs(a)
Definition: ncbi_heapmgr.c:130
NCBI C++ stream class wrappers for triggering between "new" and "old" C++ stream libraries.
T max(T x_, T y_)
T log10(T x_)
T min(T x_, T y_)
static char tmp[2048]
Definition: utf8.c:42
Definition: type.c:6
Modified on Sat Dec 02 09:21:51 2023 by modify_doxy.py rev. 669887