/**************************************************************************** ** Copyright (C) 2001-2011 Klaralvdalens Datakonsult AB. All rights reserved. ** ** This file is part of the KD Chart library. ** ** Licensees holding valid commercial KD Chart licenses may use this file in ** accordance with the KD Chart Commercial License Agreement provided with ** the Software. ** ** ** This file may be distributed and/or modified under the terms of the ** GNU General Public License version 2 and version 3 as published by the ** Free Software Foundation and appearing in the file LICENSE.GPL.txt included. ** ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. ** ** Contact info@kdab.com if any conditions of this licensing are not ** clear to you. ** **********************************************************************/ #ifndef CARTESIANCOORDINATETRANSFORMATION_H #define CARTESIANCOORDINATETRANSFORMATION_H #include #include #include #include "KDChartZoomParameters.h" #include #include namespace KDChart { // FIXME: if this struct is used more often, we need to make it a class // with proper accessor methods: /** * \internal */ struct CoordinateTransformation { QRectF diagramRect; // represents the distance of the diagram coordinate origin to the // origin of the coordinate plane space: QPointF originTranslation; // make a vector base for R2: double unitVectorX; double unitVectorY; // implement isometric scaling: double isoScaleX; double isoScaleY; CartesianCoordinatePlane::AxesCalcMode axesCalcModeY; CartesianCoordinatePlane::AxesCalcMode axesCalcModeX; ZoomParameters zoom; typedef QPair< qreal, qreal > qrealPair; inline qreal makeLogarithmic( qrealPair reference, qreal value ) const { qreal result = value; qreal relation; if( reference.second == -1.0 ) relation = 1.0; else if( reference.second == 1.0 ) relation = 1.0; else if( reference.second > 0.0 ) relation = reference.second / log10( reference.second ); else if( result < 0.0 ) relation = reference.second / log10( -reference.second ); else relation = 10.0; if( value == 0.0 ) result = 0.0;//std::numeric_limits< qreal >::quiet_NaN(); else if( value > 0.0 ) result = log10( result ) * relation; else if( value < 0.0 ) result = -log10( -result ) * relation; if( value == 0.0 ) return result; result -= log10( qAbs( reference.first ) ) * relation; result *= ( reference.second - reference.first ) / relation / (log10(qAbs(reference.second))-log10(qAbs(reference.first))); result += reference.first; if( reference.first < 0.0 ) { result += reference.first; result -= reference.second; result = reference.first - result + reference.second; } return result; } inline QPointF translate( const QPointF& diagramPoint ) const { // ### de-inline me QPointF result = originTranslation; QPointF tempPoint = diagramPoint; const QRectF& diagRect = diagramRect; if( axesCalcModeY == CartesianCoordinatePlane::Logarithmic ) { tempPoint.setY( makeLogarithmic( qrealPair( diagRect.bottom(), diagRect.y() ), tempPoint.y() ) ); } if( axesCalcModeX == CartesianCoordinatePlane::Logarithmic ) { tempPoint.setX( makeLogarithmic( qrealPair( diagRect.x(), diagRect.right() ), tempPoint.x() ) ); } tempPoint.rx() += diagRect.width() / (2.0 * zoom.xFactor); tempPoint.ry() += diagRect.height() / (2.0 * zoom.yFactor); tempPoint.rx() -= diagRect.width() * zoom.xCenter; tempPoint.ry() -= diagRect.height() * zoom.yCenter; // translate: xNew = (xOld - diaX) * zoomX + diaX tempPoint.setX( ( tempPoint.x() - diagRect.x() ) * zoom.xFactor + diagRect.x() ); tempPoint.setY( ( tempPoint.y() - diagRect.y() ) * zoom.yFactor + diagRect.y() ); result.rx() += isoScaleX * unitVectorX * tempPoint.x(); result.ry() += isoScaleY * unitVectorY * tempPoint.y(); return result; } // convert screen points to value space points inline const QPointF translateBack( const QPointF& screenPoint ) const { qreal x, y; x = screenPoint.x() - originTranslation.x(); y = screenPoint.y() - originTranslation.y(); x /= isoScaleX * unitVectorX; y /= isoScaleY * unitVectorY; // translate back: xOld = DiaX + (xNew - DiaX) / zoomX x = diagramRect.x() + (x - diagramRect.x()) / zoom.xFactor; y = diagramRect.y() + (y - diagramRect.y()) / zoom.yFactor; x += diagramRect.width() * zoom.xCenter; y += diagramRect.height() * zoom.yCenter; x -= diagramRect.width() / (2.0 * zoom.xFactor); y -= diagramRect.height() / (2.0 * zoom.yFactor); /* if ( axesCalcModeY == CartesianCoordinatePlane::Logarithmic ){ tempPoint.setY( makeLogarithmic( diagramRect.y(), tempPoint.y() ) ); //qDebug() << "Y: " << tempPoint.y(); } if ( axesCalcModeX == CartesianCoordinatePlane::Logarithmic ){ //qDebug() << "X diagramRect.x(): " << diagramRect.x(); //qDebug() << "X tempPoint old: " << tempPoint; tempPoint.setX( makeLogarithmic( diagramRect.width(), tempPoint.x() ) ); //qDebug() << "X tempPoint new: " << tempPoint; } // qDebug() << "CoordinateTransformation::translate() using diagramRect: " // << diagramRect.x() << diagramRect.y() << diagramRect.width() << diagramRect.height(); */ return QPointF(x, y); } }; typedef QList CoordinateTransformationList; } #endif