KChart

CartesianCoordinateTransformation.h
1 /*
2  * SPDX-FileCopyrightText: 2001-2015 Klaralvdalens Datakonsult AB. All rights reserved.
3  *
4  * This file is part of the KD Chart library.
5  *
6  * SPDX-License-Identifier: GPL-2.0-or-later
7  */
8 
9 #ifndef CARTESIANCOORDINATETRANSFORMATION_H
10 #define CARTESIANCOORDINATETRANSFORMATION_H
11 
12 #include <QList>
13 #include <QRectF>
14 #include <QPointF>
15 
16 #include "KChartZoomParameters.h"
17 
18 #include <cmath>
19 #include <limits>
20 
21 namespace KChart {
22 
23  // FIXME: if this struct is used more often, we need to make it a class
24  // with proper accessor methods:
25 
26  /**
27  * \internal
28  */
30 
32  : axesCalcModeY( CartesianCoordinatePlane::Linear ),
33  axesCalcModeX( CartesianCoordinatePlane::Linear ),
34  isPositiveX( true ),
35  isPositiveY( true )
36  {}
37 
38  CartesianCoordinatePlane::AxesCalcMode axesCalcModeY;
39  CartesianCoordinatePlane::AxesCalcMode axesCalcModeX;
40 
41  ZoomParameters zoom;
42 
43  QTransform transform;
44  QTransform backTransform;
45  // a logarithmic scale cannot cross zero, so we have to know which side we are on.
46  bool isPositiveX;
47  bool isPositiveY;
48 
49  qreal logTransform( qreal value, bool isPositiveRange ) const
50  {
51  if ( isPositiveRange ) {
52  return log10( value );
53  } else {
54  return -log10( -value );
55  }
56  }
57 
58  qreal logTransformBack( qreal value, bool wasPositive ) const
59  {
60  if ( wasPositive ) {
61  return pow( 10.0, value );
62  } else {
63  return -pow( 10.0, -value );
64  }
65  }
66 
67  void updateTransform( const QRectF& constDataRect, const QRectF& screenRect )
68  {
69  QRectF dataRect = constDataRect;
70  if ( axesCalcModeX == CartesianCoordinatePlane::Logarithmic ) {
71  // the data will be scaled by logTransform() later, so scale its bounds as well
72  isPositiveX = dataRect.left() >= 0.0;
73  dataRect.setLeft( logTransform( dataRect.left(), isPositiveX ) );
74  dataRect.setRight( logTransform( dataRect.right(), isPositiveX ) );
75  }
76  if ( axesCalcModeY == CartesianCoordinatePlane::Logarithmic ) {
77  isPositiveY = dataRect.top() >= 0.0;
78  dataRect.setTop( logTransform( dataRect.top(), isPositiveY ) );
79  dataRect.setBottom( logTransform( dataRect.bottom(), isPositiveY ) );
80  }
81 
82  transform.reset();
83  // read the following transformation sequence from bottom to top(!)
84  transform.translate( screenRect.left(), screenRect.bottom() );
85  transform.scale( screenRect.width(), screenRect.height() );
86 
87  // TODO: mirror in case of "reverse" axes?
88 
89  // transform into screen space
90  transform.translate( 0.5, -0.5 );
91  transform.scale( zoom.xFactor, zoom.yFactor );
92  transform.translate( -zoom.xCenter, 1.0 - zoom.yCenter );
93  // zoom
94  transform.scale( 1.0 / dataRect.width(), 1.0 / dataRect.height() );
95  transform.translate( -dataRect.left(), -dataRect.bottom() );
96  // transform into the unit square
97 
98  backTransform = transform.inverted();
99  }
100 
101  // convert data space point to screen point
102  inline QPointF translate( const QPointF& dataPoint ) const
103  {
104  QPointF data = dataPoint;
105  if ( axesCalcModeX == CartesianCoordinatePlane::Logarithmic ) {
106  data.setX( logTransform( data.x(), isPositiveX ) );
107  }
108  if ( axesCalcModeY == CartesianCoordinatePlane::Logarithmic ) {
109  data.setY( logTransform( data.y(), isPositiveY ) );
110  }
111 
112  return transform.map( data );
113  }
114 
115  // convert screen point to data space point
116  inline const QPointF translateBack( const QPointF& screenPoint ) const
117  {
118  QPointF ret = backTransform.map( screenPoint );
119  if ( axesCalcModeX == CartesianCoordinatePlane::Logarithmic ) {
120  ret.setX( logTransformBack( ret.x(), isPositiveX ) );
121  }
122  if ( axesCalcModeY == CartesianCoordinatePlane::Logarithmic ) {
123  ret.setY( logTransformBack( ret.y(), isPositiveY ) );
124  }
125  return ret;
126  }
127  };
128 
130 
131 }
132 
133 #endif
QPoint map(const QPoint &point) const const
qreal left() const const
void setLeft(qreal x)
void setBottom(qreal y)
void setX(qreal x)
void setY(qreal y)
ZoomParameters stores the center and the factor of zooming internally.
qreal bottom() const const
void setRight(qreal x)
qreal top() const const
qreal right() const const
qreal x() const const
qreal y() const const
qreal width() const const
void setTop(qreal y)
qreal height() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Tue Nov 28 2023 03:59:59 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.