qwt_scale_draw.cpp
Go to the documentation of this file.
1 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
2  * Qwt Widget Library
3  * Copyright (C) 1997 Josef Wilgen
4  * Copyright (C) 2002 Uwe Rathmann
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the Qwt License, Version 1.0
8  *****************************************************************************/
9 
10 #include "qwt_scale_draw.h"
11 #include "qwt_scale_div.h"
12 #include "qwt_scale_map.h"
13 #include "qwt_math.h"
14 #include "qwt_painter.h"
15 #include <qpen.h>
16 #include <qpainter.h>
17 #include <qmath.h>
18 
19 #if QT_VERSION < 0x040601
20 #define qFastSin(x) qSin(x)
21 #define qFastCos(x) qCos(x)
22 #endif
23 
25 {
26 public:
28  len( 0 ),
30  labelAlignment( 0 ),
31  labelRotation( 0.0 )
32  {
33  }
34 
35  QPointF pos;
36  double len;
37 
39 
40  Qt::Alignment labelAlignment;
41  double labelRotation;
42 };
43 
52 {
54  setLength( 100 );
55 }
56 
59 {
60  delete d_data;
61 }
62 
69 {
70  return d_data->alignment;
71 }
72 
82 {
83  d_data->alignment = align;
84 }
85 
96 Qt::Orientation QwtScaleDraw::orientation() const
97 {
98  switch ( d_data->alignment )
99  {
100  case TopScale:
101  case BottomScale:
102  return Qt::Horizontal;
103  case LeftScale:
104  case RightScale:
105  default:
106  return Qt::Vertical;
107  }
108 }
109 
121  const QFont &font, int &start, int &end ) const
122 {
123  start = 0;
124  end = 1.0;
125 
127  return;
128 
129  const QList<double> &ticks = scaleDiv().ticks( QwtScaleDiv::MajorTick );
130  if ( ticks.count() == 0 )
131  return;
132 
133  // Find the ticks, that are mapped to the borders.
134  // minTick is the tick, that is mapped to the top/left-most position
135  // in widget coordinates.
136 
137  double minTick = ticks[0];
138  double minPos = scaleMap().transform( minTick );
139  double maxTick = minTick;
140  double maxPos = minPos;
141 
142  for ( int i = 1; i < ticks.count(); i++ )
143  {
144  const double tickPos = scaleMap().transform( ticks[i] );
145  if ( tickPos < minPos )
146  {
147  minTick = ticks[i];
148  minPos = tickPos;
149  }
150  if ( tickPos > scaleMap().transform( maxTick ) )
151  {
152  maxTick = ticks[i];
153  maxPos = tickPos;
154  }
155  }
156 
157  double e = 0.0;
158  double s = 0.0;
159  if ( orientation() == Qt::Vertical )
160  {
161  s = -labelRect( font, minTick ).top();
162  s -= qAbs( minPos - qRound( scaleMap().p2() ) );
163 
164  e = labelRect( font, maxTick ).bottom();
165  e -= qAbs( maxPos - scaleMap().p1() );
166  }
167  else
168  {
169  s = -labelRect( font, minTick ).left();
170  s -= qAbs( minPos - scaleMap().p1() );
171 
172  e = labelRect( font, maxTick ).right();
173  e -= qAbs( maxPos - scaleMap().p2() );
174  }
175 
176  if ( s < 0.0 )
177  s = 0.0;
178  if ( e < 0.0 )
179  e = 0.0;
180 
181  start = qCeil( s );
182  end = qCeil( e );
183 }
184 
195 int QwtScaleDraw::minLabelDist( const QFont &font ) const
196 {
198  return 0;
199 
200  const QList<double> &ticks = scaleDiv().ticks( QwtScaleDiv::MajorTick );
201  if ( ticks.isEmpty() )
202  return 0;
203 
204  const QFontMetrics fm( font );
205 
206  const bool vertical = ( orientation() == Qt::Vertical );
207 
208  QRectF bRect1;
209  QRectF bRect2 = labelRect( font, ticks[0] );
210  if ( vertical )
211  {
212  bRect2.setRect( -bRect2.bottom(), 0.0, bRect2.height(), bRect2.width() );
213  }
214 
215  double maxDist = 0.0;
216 
217  for ( int i = 1; i < ticks.count(); i++ )
218  {
219  bRect1 = bRect2;
220  bRect2 = labelRect( font, ticks[i] );
221  if ( vertical )
222  {
223  bRect2.setRect( -bRect2.bottom(), 0.0,
224  bRect2.height(), bRect2.width() );
225  }
226 
227  double dist = fm.leading(); // space between the labels
228  if ( bRect1.right() > 0 )
229  dist += bRect1.right();
230  if ( bRect2.left() < 0 )
231  dist += -bRect2.left();
232 
233  if ( dist > maxDist )
234  maxDist = dist;
235  }
236 
237  double angle = qwtRadians( labelRotation() );
238  if ( vertical )
239  angle += M_PI / 2;
240 
241  const double sinA = qFastSin( angle ); // qreal -> double
242  if ( qFuzzyCompare( sinA + 1.0, 1.0 ) )
243  return qCeil( maxDist );
244 
245  const int fmHeight = fm.ascent() - 2;
246 
247  // The distance we need until there is
248  // the height of the label font. This height is needed
249  // for the neighbored label.
250 
251  double labelDist = fmHeight / qFastSin( angle ) * qFastCos( angle );
252  if ( labelDist < 0 )
253  labelDist = -labelDist;
254 
255  // For text orientations close to the scale orientation
256 
257  if ( labelDist > maxDist )
258  labelDist = maxDist;
259 
260  // For text orientations close to the opposite of the
261  // scale orientation
262 
263  if ( labelDist < fmHeight )
264  labelDist = fmHeight;
265 
266  return qCeil( labelDist );
267 }
268 
282 double QwtScaleDraw::extent( const QFont &font ) const
283 {
284  double d = 0;
285 
287  {
288  if ( orientation() == Qt::Vertical )
289  d = maxLabelWidth( font );
290  else
291  d = maxLabelHeight( font );
292 
293  if ( d > 0 )
294  d += spacing();
295  }
296 
298  {
299  d += maxTickLength();
300  }
301 
303  {
304  const double pw = qMax( 1, penWidth() ); // pen width can be zero
305  d += pw;
306  }
307 
308  d = qMax( d, minimumExtent() );
309  return d;
310 }
311 
320 int QwtScaleDraw::minLength( const QFont &font ) const
321 {
322  int startDist, endDist;
323  getBorderDistHint( font, startDist, endDist );
324 
325  const QwtScaleDiv &sd = scaleDiv();
326 
327  const uint minorCount =
328  sd.ticks( QwtScaleDiv::MinorTick ).count() +
329  sd.ticks( QwtScaleDiv::MediumTick ).count();
330  const uint majorCount =
331  sd.ticks( QwtScaleDiv::MajorTick ).count();
332 
333  int lengthForLabels = 0;
335  lengthForLabels = minLabelDist( font ) * majorCount;
336 
337  int lengthForTicks = 0;
339  {
340  const double pw = qMax( 1, penWidth() ); // penwidth can be zero
341  lengthForTicks = qCeil( ( majorCount + minorCount ) * ( pw + 1.0 ) );
342  }
343 
344  return startDist + endDist + qMax( lengthForLabels, lengthForTicks );
345 }
346 
356 QPointF QwtScaleDraw::labelPosition( double value ) const
357 {
358  const double tval = scaleMap().transform( value );
359  double dist = spacing();
361  dist += qMax( 1, penWidth() );
362 
365 
366  double px = 0;
367  double py = 0;
368 
369  switch ( alignment() )
370  {
371  case RightScale:
372  {
373  px = d_data->pos.x() + dist;
374  py = tval;
375  break;
376  }
377  case LeftScale:
378  {
379  px = d_data->pos.x() - dist;
380  py = tval;
381  break;
382  }
383  case BottomScale:
384  {
385  px = tval;
386  py = d_data->pos.y() + dist;
387  break;
388  }
389  case TopScale:
390  {
391  px = tval;
392  py = d_data->pos.y() - dist;
393  break;
394  }
395  }
396 
397  return QPointF( px, py );
398 }
399 
409 void QwtScaleDraw::drawTick( QPainter *painter, double value, double len ) const
410 {
411  if ( len <= 0 )
412  return;
413 
414  const bool roundingAlignment = QwtPainter::roundingAlignment( painter );
415 
416  QPointF pos = d_data->pos;
417 
418  double tval = scaleMap().transform( value );
419  if ( roundingAlignment )
420  tval = qRound( tval );
421 
422  const int pw = penWidth();
423  int a = 0;
424  if ( pw > 1 && roundingAlignment )
425  a = 1;
426 
427  switch ( alignment() )
428  {
429  case LeftScale:
430  {
431  double x1 = pos.x() + a;
432  double x2 = pos.x() + a - pw - len;
433  if ( roundingAlignment )
434  {
435  x1 = qRound( x1 );
436  x2 = qRound( x2 );
437  }
438 
439  QwtPainter::drawLine( painter, x1, tval, x2, tval );
440  break;
441  }
442 
443  case RightScale:
444  {
445  double x1 = pos.x();
446  double x2 = pos.x() + pw + len;
447  if ( roundingAlignment )
448  {
449  x1 = qRound( x1 );
450  x2 = qRound( x2 );
451  }
452 
453  QwtPainter::drawLine( painter, x1, tval, x2, tval );
454  break;
455  }
456 
457  case BottomScale:
458  {
459  double y1 = pos.y();
460  double y2 = pos.y() + pw + len;
461  if ( roundingAlignment )
462  {
463  y1 = qRound( y1 );
464  y2 = qRound( y2 );
465  }
466 
467  QwtPainter::drawLine( painter, tval, y1, tval, y2 );
468  break;
469  }
470 
471  case TopScale:
472  {
473  double y1 = pos.y() + a;
474  double y2 = pos.y() - pw - len + a;
475  if ( roundingAlignment )
476  {
477  y1 = qRound( y1 );
478  y2 = qRound( y2 );
479  }
480 
481  QwtPainter::drawLine( painter, tval, y1, tval, y2 );
482  break;
483  }
484  }
485 }
486 
493 void QwtScaleDraw::drawBackbone( QPainter *painter ) const
494 {
495  const bool doAlign = QwtPainter::roundingAlignment( painter );
496 
497  const QPointF &pos = d_data->pos;
498  const double len = d_data->len;
499  const int pw = qMax( penWidth(), 1 );
500 
501  // pos indicates a border not the center of the backbone line
502  // so we need to shift its position depending on the pen width
503  // and the alignment of the scale
504 
505  double off;
506  if ( doAlign )
507  {
508  if ( alignment() == LeftScale || alignment() == TopScale )
509  off = ( pw - 1 ) / 2;
510  else
511  off = pw / 2;
512  }
513  else
514  {
515  off = 0.5 * penWidth();
516  }
517 
518  switch ( alignment() )
519  {
520  case LeftScale:
521  {
522  double x = pos.x() - off;
523  if ( doAlign )
524  x = qRound( x );
525 
526  QwtPainter::drawLine( painter, x, pos.y(), x, pos.y() + len );
527  break;
528  }
529  case RightScale:
530  {
531  double x = pos.x() + off;
532  if ( doAlign )
533  x = qRound( x );
534 
535  QwtPainter::drawLine( painter, x, pos.y(), x, pos.y() + len );
536  break;
537  }
538  case TopScale:
539  {
540  double y = pos.y() - off;
541  if ( doAlign )
542  y = qRound( y );
543 
544  QwtPainter::drawLine( painter, pos.x(), y, pos.x() + len, y );
545  break;
546  }
547  case BottomScale:
548  {
549  double y = pos.y() + off;
550  if ( doAlign )
551  y = qRound( y );
552 
553  QwtPainter::drawLine( painter, pos.x(), y, pos.x() + len, y );
554  break;
555  }
556  }
557 }
558 
590 void QwtScaleDraw::move( const QPointF &pos )
591 {
592  d_data->pos = pos;
593  updateMap();
594 }
595 
600 QPointF QwtScaleDraw::pos() const
601 {
602  return d_data->pos;
603 }
604 
616 {
617 #if 0
618  if ( length >= 0 && length < 10 )
619  length = 10;
620 
621  // why should we accept negative lengths ???
622  if ( length < 0 && length > -10 )
623  length = -10;
624 #else
625  length = qMax( length, 10.0 );
626 #endif
627 
628  d_data->len = length;
629  updateMap();
630 }
631 
636 double QwtScaleDraw::length() const
637 {
638  return d_data->len;
639 }
640 
649 void QwtScaleDraw::drawLabel( QPainter *painter, double value ) const
650 {
651  QwtText lbl = tickLabel( painter->font(), value );
652  if ( lbl.isEmpty() )
653  return;
654 
655  QPointF pos = labelPosition( value );
656 
657  QSizeF labelSize = lbl.textSize( painter->font() );
658 
659  const QTransform transform = labelTransformation( pos, labelSize );
660 
661  painter->save();
662  painter->setWorldTransform( transform, true );
663 
664  lbl.draw ( painter, QRect( QPoint( 0, 0 ), labelSize.toSize() ) );
665 
666  painter->restore();
667 }
668 
681 QRect QwtScaleDraw::boundingLabelRect( const QFont &font, double value ) const
682 {
683  QwtText lbl = tickLabel( font, value );
684  if ( lbl.isEmpty() )
685  return QRect();
686 
687  const QPointF pos = labelPosition( value );
688  QSizeF labelSize = lbl.textSize( font );
689 
690  const QTransform transform = labelTransformation( pos, labelSize );
691  return transform.mapRect( QRect( QPoint( 0, 0 ), labelSize.toSize() ) );
692 }
693 
705  const QPointF &pos, const QSizeF &size ) const
706 {
707  QTransform transform;
708  transform.translate( pos.x(), pos.y() );
709  transform.rotate( labelRotation() );
710 
711  int flags = labelAlignment();
712  if ( flags == 0 )
713  {
714  switch ( alignment() )
715  {
716  case RightScale:
717  {
718  if ( flags == 0 )
719  flags = Qt::AlignRight | Qt::AlignVCenter;
720  break;
721  }
722  case LeftScale:
723  {
724  if ( flags == 0 )
725  flags = Qt::AlignLeft | Qt::AlignVCenter;
726  break;
727  }
728  case BottomScale:
729  {
730  if ( flags == 0 )
731  flags = Qt::AlignHCenter | Qt::AlignBottom;
732  break;
733  }
734  case TopScale:
735  {
736  if ( flags == 0 )
737  flags = Qt::AlignHCenter | Qt::AlignTop;
738  break;
739  }
740  }
741  }
742 
743  double x, y;
744 
745  if ( flags & Qt::AlignLeft )
746  x = -size.width();
747  else if ( flags & Qt::AlignRight )
748  x = 0.0;
749  else // Qt::AlignHCenter
750  x = -( 0.5 * size.width() );
751 
752  if ( flags & Qt::AlignTop )
753  y = -size.height();
754  else if ( flags & Qt::AlignBottom )
755  y = 0;
756  else // Qt::AlignVCenter
757  y = -( 0.5 * size.height() );
758 
759  transform.translate( x, y );
760 
761  return transform;
762 }
763 
774 QRectF QwtScaleDraw::labelRect( const QFont &font, double value ) const
775 {
776  QwtText lbl = tickLabel( font, value );
777  if ( lbl.isEmpty() )
778  return QRectF( 0.0, 0.0, 0.0, 0.0 );
779 
780  const QPointF pos = labelPosition( value );
781 
782  const QSizeF labelSize = lbl.textSize( font );
783  const QTransform transform = labelTransformation( pos, labelSize );
784 
785  QRectF br = transform.mapRect( QRectF( QPointF( 0, 0 ), labelSize ) );
786  br.translate( -pos.x(), -pos.y() );
787 
788  return br;
789 }
790 
799 QSizeF QwtScaleDraw::labelSize( const QFont &font, double value ) const
800 {
801  return labelRect( font, value ).size();
802 }
803 
817 void QwtScaleDraw::setLabelRotation( double rotation )
818 {
819  d_data->labelRotation = rotation;
820 }
821 
827 {
828  return d_data->labelRotation;
829 }
830 
857 {
859 }
860 
865 Qt::Alignment QwtScaleDraw::labelAlignment() const
866 {
867  return d_data->labelAlignment;
868 }
869 
874 int QwtScaleDraw::maxLabelWidth( const QFont &font ) const
875 {
876  double maxWidth = 0.0;
877 
878  const QList<double> &ticks = scaleDiv().ticks( QwtScaleDiv::MajorTick );
879  for ( int i = 0; i < ticks.count(); i++ )
880  {
881  const double v = ticks[i];
882  if ( scaleDiv().contains( v ) )
883  {
884  const double w = labelSize( font, ticks[i] ).width();
885  if ( w > maxWidth )
886  maxWidth = w;
887  }
888  }
889 
890  return qCeil( maxWidth );
891 }
892 
897 int QwtScaleDraw::maxLabelHeight( const QFont &font ) const
898 {
899  double maxHeight = 0.0;
900 
901  const QList<double> &ticks = scaleDiv().ticks( QwtScaleDiv::MajorTick );
902  for ( int i = 0; i < ticks.count(); i++ )
903  {
904  const double v = ticks[i];
905  if ( scaleDiv().contains( v ) )
906  {
907  const double h = labelSize( font, ticks[i] ).height();
908  if ( h > maxHeight )
909  maxHeight = h;
910  }
911  }
912 
913  return qCeil( maxHeight );
914 }
915 
917 {
918  const QPointF pos = d_data->pos;
919  double len = d_data->len;
920 
921  QwtScaleMap &sm = scaleMap();
922  if ( orientation() == Qt::Vertical )
923  sm.setPaintInterval( pos.y() + len, pos.y() );
924  else
925  sm.setPaintInterval( pos.x(), pos.x() + len );
926 }
int v
d
static void drawLine(QPainter *, double x1, double y1, double x2, double y2)
Wrapper for QPainter::drawLine()
Definition: qwt_painter.h:147
virtual void drawTick(QPainter *, double val, double len) const
void setAlignment(Alignment)
void setLength(double length)
virtual double extent(const QFont &) const
The scale is above.
XmlRpcServer s
QPointF labelPosition(double val) const
void draw(QPainter *painter, const QRectF &rect) const
Definition: qwt_text.cpp:560
A class representing a scale division.
Definition: qwt_scale_div.h:36
const QwtScaleMap & scaleMap() const
void getBorderDistHint(const QFont &, int &start, int &end) const
Determine the minimum border distance.
TFSIMD_FORCE_INLINE const tfScalar & y() const
QPointF pos() const
QwtScaleDraw()
Constructor.
int minLength(const QFont &) const
int minLabelDist(const QFont &) const
TFSIMD_FORCE_INLINE tfScalar angle(const Quaternion &q1, const Quaternion &q2)
virtual ~QwtScaleDraw()
Destructor.
#define qFastCos(x)
int maxLabelWidth(const QFont &) const
PrivateData * d_data
QTransform labelTransformation(const QPointF &, const QSizeF &) const
QSizeF textSize(const QFont &=QFont()) const
Definition: qwt_text.cpp:526
QSizeF labelSize(const QFont &, double val) const
bool contains(double value) const
Alignment alignment() const
double qwtRadians(double degrees)
Translate degrees into radians.
Definition: qwt_math.h:144
The scale is left.
const QwtScaleDiv & scaleDiv() const
bool isEmpty() const
Definition: qwt_text.h:213
void setPaintInterval(double p1, double p2)
Specify the borders of the paint device interval.
A class representing a text.
Definition: qwt_text.h:51
TFSIMD_FORCE_INLINE const tfScalar & x() const
void setLabelRotation(double rotation)
Backbone = the line where the ticks are located.
A scale map.
Definition: qwt_scale_map.h:30
Qt::Orientation orientation() const
virtual void drawBackbone(QPainter *) const
Qt::Alignment labelAlignment() const
virtual void drawLabel(QPainter *, double val) const
const QwtText & tickLabel(const QFont &, double value) const
Convert a value into its representing label and cache it.
TFSIMD_FORCE_INLINE const tfScalar & w() const
The scale is right.
double length() const
QRectF labelRect(const QFont &, double val) const
int maxLabelHeight(const QFont &) const
bool hasComponent(ScaleComponent) const
#define qFastSin(x)
A class for drawing scales.
double transform(double s) const
QRect boundingLabelRect(const QFont &, double val) const
Find the bounding rectangle for the label.
int i
QList< double > ticks(int tickType) const
int flags
double tickLength(QwtScaleDiv::TickType) const
double labelRotation() const
int a
void setLabelAlignment(Qt::Alignment)
Change the label flags.
The scale is below.
double spacing() const
Get the spacing.
static bool roundingAlignment()
Definition: qwt_painter.h:176
void move(double x, double y)


plotjuggler
Author(s): Davide Faconti
autogenerated on Sat Jul 6 2019 03:44:17