KD Chart 2 [rev.2.4]
|
00001 /**************************************************************************** 00002 ** Copyright (C) 2001-2012 Klaralvdalens Datakonsult AB. All rights reserved. 00003 ** 00004 ** This file is part of the KD Chart library. 00005 ** 00006 ** Licensees holding valid commercial KD Chart licenses may use this file in 00007 ** accordance with the KD Chart Commercial License Agreement provided with 00008 ** the Software. 00009 ** 00010 ** 00011 ** This file may be distributed and/or modified under the terms of the 00012 ** GNU General Public License version 2 and version 3 as published by the 00013 ** Free Software Foundation and appearing in the file LICENSE.GPL.txt included. 00014 ** 00015 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE 00016 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 00017 ** 00018 ** Contact info@kdab.com if any conditions of this licensing are not 00019 ** clear to you. 00020 ** 00021 **********************************************************************/ 00022 00023 #include "KDChartPlotter_p.h" 00024 #include "KDChartPlotter.h" 00025 00026 #include "KDChartValueTrackerAttributes.h" 00027 00028 using namespace KDChart; 00029 00030 Plotter::Private::Private( const Private& rhs ) 00031 : AbstractCartesianDiagram::Private( rhs ) 00032 { 00033 } 00034 00035 void Plotter::Private::setCompressorResolution( 00036 const QSizeF& size, 00037 const AbstractCoordinatePlane* plane ) 00038 { 00039 compressor.setResolution( static_cast<int>( size.width() * plane->zoomFactorX() ), 00040 static_cast<int>( size.height() * plane->zoomFactorY() ) ); 00041 } 00042 00043 00044 void Plotter::Private::paintPolyline( 00045 PaintContext* ctx, 00046 const QBrush& brush, const QPen& pen, 00047 const QPolygonF& points ) const 00048 { 00049 ctx->painter()->setBrush( brush ); 00050 ctx->painter()->setPen( PrintingParameters::scalePen( 00051 QPen( pen.color(), 00052 pen.width(), 00053 pen.style(), 00054 Qt::FlatCap, 00055 Qt::MiterJoin ) ) ); 00056 #if QT_VERSION > 0x040299 00057 ctx->painter()->drawPolyline( points ); 00058 #else 00059 // FIXME (Mirko) verify, this sounds reverse-logical 00060 // For Qt versions older than 4.3 drawPolyline is VERY slow 00061 // so we use traditional line segments drawing instead then. 00062 for (int i = 0; i < points.size()-1; ++i) 00063 ctx->painter()->drawLine( points.at(i), points.at(i+1) ); 00064 #endif 00065 } 00066 00072 const QPointF Plotter::PlotterType::project( 00073 QPointF point, QPointF maxLimits, 00074 double z, const QModelIndex& index ) const 00075 { 00076 Q_UNUSED( maxLimits ); 00077 ThreeDLineAttributes td = diagram()->threeDLineAttributes( index ); 00078 00079 //Pending Michel FIXME - the rotation does not work as expected atm 00080 double xrad = DEGTORAD( td.lineXRotation() ); 00081 double yrad = DEGTORAD( td.lineYRotation() ); 00082 QPointF ret = QPointF(point.x()*cos( yrad ) + z * sin( yrad ) , point.y()*cos( xrad ) - z * sin( xrad ) ); 00083 return ret; 00084 } 00085 00086 void Plotter::PlotterType::paintThreeDLines( 00087 PaintContext* ctx, const QModelIndex& index, 00088 const QPointF& from, const QPointF& to, const double depth ) 00089 { 00090 // retrieve the boundaries 00091 const QPair< QPointF, QPointF > boundaries = diagram()->dataBoundaries(); 00092 const QPointF& maxLimits = boundaries.second; 00093 const QPointF topLeft = project( from, maxLimits, depth, index ); 00094 const QPointF topRight = project ( to, maxLimits, depth, index ); 00095 00096 const QPolygonF segment = QPolygonF() << from << topLeft << topRight << to; 00097 const QBrush indexBrush ( diagram()->brush( index ) ); 00098 const PainterSaver painterSaver( ctx->painter() ); 00099 00100 if( diagram()->antiAliasing() ) 00101 ctx->painter()->setRenderHint( QPainter::Antialiasing ); 00102 00103 ctx->painter()->setBrush( indexBrush ); 00104 ctx->painter()->setPen( PrintingParameters::scalePen( diagram()->pen( index ) ) ); 00105 00106 reverseMapper().addPolygon( index.row(), index.column(), segment ); 00107 ctx->painter()->drawPolygon( segment ); 00108 } 00109 00110 // this method is factored out from LineDiagram::paint, and contains 00111 // the common parts of the method that previously implemented all 00112 // chart types in one 00113 void Plotter::PlotterType::paintElements( 00114 PaintContext* ctx, 00115 DataValueTextInfoList& list, 00116 LineAttributesInfoList& lineList, 00117 LineAttributes::MissingValuesPolicy policy ) 00118 { 00119 Q_UNUSED( policy ); 00120 // paint all lines and their attributes 00121 PainterSaver painterSaver( ctx->painter() ); 00122 if ( diagram()->antiAliasing() ) 00123 ctx->painter()->setRenderHint ( QPainter::Antialiasing ); 00124 LineAttributesInfoListIterator itline ( lineList ); 00125 00126 QBrush curBrush; 00127 QPen curPen; 00128 QPolygonF points; 00129 while ( itline.hasNext() ) { 00130 const LineAttributesInfo& lineInfo = itline.next(); 00131 const QModelIndex& index = lineInfo.index; 00132 const ThreeDLineAttributes td = diagram()->threeDLineAttributes( index ); 00133 const ValueTrackerAttributes vt = diagram()->valueTrackerAttributes( index ); 00134 00135 if( td.isEnabled() ){ 00136 paintThreeDLines( ctx, index, lineInfo.value, lineInfo.nextValue, td.depth() ); 00137 } else { 00138 const QBrush br( diagram()->brush( index ) ); 00139 const QPen pn( diagram()->pen( index ) ); 00140 if( points.count() && points.last() == lineInfo.value && curBrush == br && curPen == pn ) { 00141 // line goes from last value in points to lineInfo.nextValue 00142 reverseMapper().addLine( lineInfo.index.row(), lineInfo.index.column(), points.last(), lineInfo.nextValue ); 00143 points << lineInfo.nextValue; 00144 } else { 00145 if( points.count() ) 00146 paintPolyline( ctx, curBrush, curPen, points ); 00147 curBrush = br; 00148 curPen = pn; 00149 points.clear(); 00150 // line goes from lineInfo.value to lineInfo,nextValue 00151 reverseMapper().addLine( lineInfo.index.row(), lineInfo.index.column(), lineInfo.value, lineInfo.nextValue ); 00152 points << lineInfo.value << lineInfo.nextValue; 00153 } 00154 } 00155 00156 if( vt.isEnabled() ) 00157 paintValueTracker( ctx, vt, lineInfo.value ); 00158 } 00159 if( points.count() ) 00160 paintPolyline( ctx, curBrush, curPen, points ); 00161 // paint all data value texts and the point markers 00162 paintDataValueTextsAndMarkers( diagram(), ctx, list, true ); 00163 } 00164 00165 AttributesModel* Plotter::PlotterType::attributesModel() const 00166 { 00167 return m_private->attributesModel; 00168 } 00169 00170 #if 0 00171 QModelIndex LineDiagram::LineDiagramType::attributesModelRootIndex() const 00172 { 00173 return m_private->diagram->attributesModelRootIndex(); 00174 } 00175 00176 int LineDiagram::LineDiagramType::datasetDimension() const 00177 { 00178 return m_private->datasetDimension; 00179 } 00180 #endif 00181 00182 ReverseMapper& Plotter::PlotterType::reverseMapper() 00183 { 00184 return m_private->reverseMapper; 00185 } 00186 00187 #if 0 00188 LineAttributes::MissingValuesPolicy LineDiagram::LineDiagramType::getCellValues( 00189 int row, int column, 00190 bool shiftCountedXValuesByHalfSection, 00191 double& valueX, double& valueY ) const 00192 { 00193 return m_private->diagram->getCellValues( row, column, shiftCountedXValuesByHalfSection, 00194 valueX, valueY ); 00195 } 00196 00197 double LineDiagram::LineDiagramType::valueForCellTesting( 00198 int row, int column, 00199 bool& bOK, 00200 bool showHiddenCellsAsInvalid) const 00201 { 00202 return m_private->diagram->valueForCellTesting( row, column, bOK, showHiddenCellsAsInvalid ); 00203 } 00204 #endif 00205 00206 Plotter* Plotter::PlotterType::diagram() const 00207 { 00208 return m_private->diagram; 00209 } 00210 00211 void Plotter::PlotterType::paintAreas( 00212 PaintContext* ctx, 00213 const QModelIndex& index, const QList< QPolygonF >& areas, 00214 const uint transparency ) 00215 { 00216 QColor trans = diagram()->brush( index ).color(); 00217 trans.setAlpha( transparency ); 00218 QPen indexPen = diagram()->pen(index); 00219 indexPen.setColor( trans ); 00220 const PainterSaver painterSaver( ctx->painter() ); 00221 00222 if( diagram()->antiAliasing() ) 00223 ctx->painter()->setRenderHint( QPainter::Antialiasing ); 00224 00225 ctx->painter()->setPen( PrintingParameters::scalePen( indexPen ) ); 00226 ctx->painter()->setBrush( trans ); 00227 00228 QPainterPath path; 00229 for( int i = 0; i < areas.count(); ++i ) 00230 { 00231 const QPolygonF& p = areas[ i ]; 00232 path.addPolygon( p ); 00233 reverseMapper().addPolygon( index.row(), index.column(), p ); 00234 path.closeSubpath(); 00235 } 00236 ctx->painter()->drawPath( path ); 00237 } 00238 00239 #if 0 00240 double LineDiagram::LineDiagramType::valueForCell( int row, int column ) 00241 { 00242 return diagram()->valueForCell( row, column ); 00243 } 00244 #endif 00245 00246 void Plotter::PlotterType::appendDataValueTextInfoToList( 00247 AbstractDiagram * diagram, 00248 DataValueTextInfoList & list, 00249 const QModelIndex & index, 00250 const PositionPoints& points, 00251 const Position& autoPositionPositive, 00252 const Position& autoPositionNegative, 00253 const qreal value ) 00254 { 00255 Q_UNUSED( autoPositionNegative ); 00256 m_private->appendDataValueTextInfoToList( 00257 diagram, list, index, 0, 00258 points, autoPositionPositive, autoPositionPositive, value ); 00259 } 00260 00261 void Plotter::PlotterType::paintValueTracker( PaintContext* ctx, const ValueTrackerAttributes& vt, const QPointF& at ) 00262 { 00263 CartesianCoordinatePlane* plane = qobject_cast<CartesianCoordinatePlane*>( ctx->coordinatePlane() ); 00264 if( !plane ) 00265 return; 00266 00267 DataDimensionsList gridDimensions = ctx->coordinatePlane()->gridDimensionsList(); 00268 const QPointF bottomLeft( ctx->coordinatePlane()->translate( 00269 QPointF( plane->isHorizontalRangeReversed() ? 00270 gridDimensions.at( 0 ).end : 00271 gridDimensions.at( 0 ).start, 00272 plane->isVerticalRangeReversed() ? 00273 gridDimensions.at( 1 ).end : 00274 gridDimensions.at( 1 ).start ) ) ); 00275 const QPointF markerPoint = at; 00276 const QPointF ordinatePoint( bottomLeft.x(), at.y() ); 00277 const QPointF abscissaPoint( at.x(), bottomLeft.y() ); 00278 00279 const QSizeF markerSize = vt.markerSize(); 00280 const QRectF ellipseMarker = QRectF( at.x() - markerSize.width() / 2, 00281 at.y() - markerSize.height() / 2, 00282 markerSize.width(), markerSize.height() ); 00283 00284 const QPointF ordinateMarker[3] = { 00285 QPointF( ordinatePoint.x(), at.y() + markerSize.height() / 2 ), 00286 QPointF( ordinatePoint.x() + markerSize.width() / 2, at.y() ), 00287 QPointF( ordinatePoint.x(), at.y() - markerSize.height() / 2 ) 00288 }; 00289 00290 const QPointF abscissaMarker[3] = { 00291 QPointF( at.x() + markerSize.width() / 2, abscissaPoint.y() ), 00292 QPointF( at.x(), abscissaPoint.y() - markerSize.height() / 2 ), 00293 QPointF( at.x() - markerSize.width() / 2, abscissaPoint.y() ) 00294 }; 00295 00296 QPointF topLeft = ordinatePoint; 00297 QPointF bottomRightOffset = abscissaPoint - topLeft; 00298 QSizeF size( bottomRightOffset.x(), bottomRightOffset.y() ); 00299 QRectF area( topLeft, size ); 00300 00301 PainterSaver painterSaver( ctx->painter() ); 00302 ctx->painter()->setPen( PrintingParameters::scalePen( vt.pen() ) ); 00303 ctx->painter()->setBrush( QBrush() ); 00304 00305 ctx->painter()->drawLine( markerPoint, ordinatePoint ); 00306 ctx->painter()->drawLine( markerPoint, abscissaPoint ); 00307 00308 ctx->painter()->fillRect( area, vt.areaBrush() ); 00309 00310 ctx->painter()->drawEllipse( ellipseMarker ); 00311 00312 ctx->painter()->setBrush( vt.pen().color() ); 00313 ctx->painter()->drawPolygon( ordinateMarker, 3 ); 00314 ctx->painter()->drawPolygon( abscissaMarker, 3 ); 00315 } 00316 00317 CartesianDiagramDataCompressor& Plotter::PlotterType::compressor() const 00318 { 00319 return m_private->compressor; 00320 }