Quantum GIS API Documentation  1.7.4
src/core/qgsdiagram.cpp
Go to the documentation of this file.
00001 #include "qgsdiagram.h"
00002 #include "qgsdiagramrendererv2.h"
00003 #include "qgsrendercontext.h"
00004 
00005 #include <QPainter>
00006 
00007 void QgsDiagram::setPenWidth( QPen& pen, const QgsDiagramSettings& s, const QgsRenderContext& c )
00008 {
00009   if ( s.sizeType == QgsDiagramSettings::MM )
00010   {
00011     pen.setWidthF( s.penWidth * c.scaleFactor() );
00012   }
00013   else
00014   {
00015     pen.setWidthF( s.penWidth / c.mapToPixel().mapUnitsPerPixel() );
00016   }
00017 }
00018 
00019 QSizeF QgsDiagram::sizePainterUnits( const QSizeF& size, const QgsDiagramSettings& s, const QgsRenderContext& c )
00020 {
00021   if ( s.sizeType == QgsDiagramSettings::MM )
00022   {
00023     return QSizeF( s.size.width() * c.scaleFactor(), s.size.height() * c.scaleFactor() );
00024   }
00025   else
00026   {
00027     return QSizeF( s.size.width() / c.mapToPixel().mapUnitsPerPixel(), s.size.height() / c.mapToPixel().mapUnitsPerPixel() );
00028   }
00029 }
00030 
00031 QFont QgsDiagram::scaledFont( const QgsDiagramSettings& s, const QgsRenderContext& c )
00032 {
00033   QFont f = s.font;
00034   if ( s.sizeType == QgsDiagramSettings::MM )
00035   {
00036     f.setPixelSize( s.font.pointSizeF() * 0.376 * c.scaleFactor() );
00037   }
00038   else
00039   {
00040     f.setPixelSize( s.font.pointSizeF() / c.mapToPixel().mapUnitsPerPixel() );
00041   }
00042 
00043   return f;
00044 }
00045 
00046 QgsTextDiagram::QgsTextDiagram(): mOrientation( Vertical ), mShape( Circle )
00047 {
00048   mPen.setWidthF( 2.0 );
00049   mPen.setColor( QColor( 0, 0, 0 ) );
00050   mPen.setCapStyle( Qt::FlatCap );
00051   mBrush.setStyle( Qt::SolidPattern );
00052 }
00053 
00054 QgsTextDiagram::~QgsTextDiagram()
00055 {
00056 }
00057 
00058 void QgsTextDiagram::renderDiagram( const QgsAttributeMap& att, QgsRenderContext& c, const QgsDiagramSettings& s, const QPointF& position )
00059 {
00060   QPainter* p = c.painter();
00061   if ( !p )
00062   {
00063     return;
00064   }
00065 
00066   double scaleDenominator = c.rendererScale();
00067   if (( s.minScaleDenominator != -1 && scaleDenominator < s.minScaleDenominator )
00068       || ( s.maxScaleDenominator != -1 && scaleDenominator > s.maxScaleDenominator ) )
00069   {
00070     return;
00071   }
00072 
00073   //convert from mm / map units to painter units
00074   QSizeF spu = sizePainterUnits( s.size, s, c );
00075   double w = spu.width();
00076   double h = spu.height();
00077 
00078   double baseX = position.x();
00079   double baseY = position.y() - h;
00080 
00081   QList<QPointF> textPositions; //midpoints for text placement
00082   int nCategories = s.categoryIndices.size();
00083   for ( int i = 0; i < nCategories; ++i )
00084   {
00085     if ( mOrientation == Horizontal )
00086     {
00087       textPositions.push_back( QPointF( baseX + ( w / nCategories ) * i + w / nCategories / 2.0 , baseY + h / 2.0 ) );
00088     }
00089     else //vertical
00090     {
00091       textPositions.push_back( QPointF( baseX + w / 2.0, baseY + h / nCategories * i + w / nCategories / 2.0 ) );
00092     }
00093   }
00094 
00095   mPen.setColor( s.penColor );
00096   setPenWidth( mPen, s, c );
00097   p->setPen( mPen );
00098   mBrush.setColor( s.backgroundColor );
00099   p->setBrush( mBrush );
00100 
00101   //draw shapes and separator lines first
00102   if ( mShape == Circle )
00103   {
00104     p->drawEllipse( baseX, baseY, w, h );
00105 
00106     //draw separator lines
00107     QList<QPointF> intersect; //intersections between shape and separation lines
00108     QPointF center( baseX + w / 2.0, baseY + h / 2.0 );
00109     double r1 = w / 2.0; double r2 = h / 2.0;
00110 
00111     for ( int i = 1; i < nCategories; ++i )
00112     {
00113       if ( mOrientation == Horizontal )
00114       {
00115         lineEllipseIntersection( QPointF( baseX + w / nCategories * i, baseY ), QPointF( baseX + w / nCategories * i, baseY + h ), center, r1, r2, intersect );
00116       }
00117       else //vertical
00118       {
00119         lineEllipseIntersection( QPointF( baseX, baseY + h / nCategories * i ), QPointF( baseX + w, baseY + h / nCategories * i ), center, r1, r2, intersect );
00120       }
00121       if ( intersect.size() > 1 )
00122       {
00123         p->drawLine( intersect.at( 0 ), intersect.at( 1 ) );
00124       }
00125     }
00126   }
00127   else if ( mShape == Rectangle )
00128   {
00129     p->drawRect( QRectF( baseX, baseY, w, h ) );
00130     for ( int i = 1; i < nCategories; ++i )
00131     {
00132       if ( mOrientation == Horizontal )
00133       {
00134         p->drawLine( QPointF( baseX + w / nCategories * i , baseY ), QPointF( baseX + w / nCategories * i, baseY + h ) );
00135       }
00136       else
00137       {
00138         p->drawLine( QPointF( baseX, baseY + h / nCategories * i ) , QPointF( baseX + w,  baseY + h / nCategories * i ) );
00139       }
00140     }
00141   }
00142   else //triangle
00143   {
00144     QPolygonF triangle;
00145     triangle << QPointF( baseX, baseY + h ) << QPointF( baseX + w, baseY + h ) << QPointF( baseX + w / 2.0, baseY );
00146     p->drawPolygon( triangle );
00147 
00148     QLineF triangleEdgeLeft( baseX + w / 2.0, baseY, baseX, baseY + h );
00149     QLineF triangleEdgeRight( baseX + w, baseY + h, baseX + w / 2.0, baseY );
00150     QPointF intersectionPoint1, intersectionPoint2;
00151 
00152     for ( int i = 1; i < nCategories; ++i )
00153     {
00154       if ( mOrientation == Horizontal )
00155       {
00156         QLineF verticalLine( baseX + w / nCategories * i, baseY + h, baseX + w / nCategories * i, baseY );
00157         if ( baseX + w / nCategories * i < baseX + w / 2.0 )
00158         {
00159           verticalLine.intersect( triangleEdgeLeft, &intersectionPoint1 );
00160         }
00161         else
00162         {
00163           verticalLine.intersect( triangleEdgeRight, &intersectionPoint1 );
00164         }
00165         p->drawLine( QPointF( baseX + w / nCategories * i, baseY + h ), intersectionPoint1 );
00166       }
00167       else //vertical
00168       {
00169         QLineF horizontalLine( baseX, baseY + h / nCategories * i, baseX + w, baseY + h / nCategories * i );
00170         horizontalLine.intersect( triangleEdgeLeft, &intersectionPoint1 );
00171         horizontalLine.intersect( triangleEdgeRight, &intersectionPoint2 );
00172         p->drawLine( intersectionPoint1, intersectionPoint2 );
00173       }
00174     }
00175   }
00176 
00177   //draw text
00178   QFont sFont = scaledFont( s, c );
00179   QFontMetricsF fontMetrics( sFont );
00180   p->setFont( sFont );
00181 
00182   for ( int i = 0; i < textPositions.size(); ++i )
00183   {
00184     QString val = att[ s.categoryIndices.at( i )].toString();
00185     //find out dimensions
00186     double textHeight = fontMetrics.height();
00187     double textWidth = fontMetrics.width( val );
00188     mPen.setColor( s.categoryColors.at( i ) );
00189     p->setPen( mPen );
00190     QPointF position = textPositions.at( i );
00191     p->drawText( QPointF( position.x() - textWidth / 2.0, position.y() + textHeight / 2.0 ), val );
00192   }
00193 }
00194 
00195 void QgsTextDiagram::lineEllipseIntersection( const QPointF& lineStart, const QPointF& lineEnd, const QPointF& ellipseMid, double r1, double r2, QList<QPointF>& result ) const
00196 {
00197   result.clear();
00198 
00199   double rrx = r1 * r1;
00200   double rry = r2 * r2;
00201   double x21 = lineEnd.x() - lineStart.x();
00202   double y21 = lineEnd.y() - lineStart.y();
00203   double x10 = lineStart.x() - ellipseMid.x();
00204   double y10 = lineStart.y() - ellipseMid.y();
00205   double a = x21 * x21 / rrx + y21 * y21 / rry;
00206   double b = x21 * x10 / rrx + y21 * y10 / rry;
00207   double c = x10 * x10 / rrx + y10 * y10 / rry;
00208   double d = b * b - a * ( c - 1 );
00209   if ( d > 0 )
00210   {
00211     double e = sqrt( d );
00212     double u1 = ( -b - e ) / a;
00213     double u2 = ( -b + e ) / a;
00214     //work with a tolerance of 0.00001 because of limited numerical precision
00215     if ( -0.00001 <= u1 && u1 < 1.00001 )
00216     {
00217       result.push_back( QPointF( lineStart.x() + x21 * u1, lineStart.y() + y21 * u1 ) );
00218     }
00219     if ( -0.00001 <= u2 && u2 <= 1.00001 )
00220     {
00221       result.push_back( QPointF( lineStart.x() + x21 * u2, lineStart.y() + y21 * u2 ) );
00222     }
00223   }
00224 }
00225 
00226 QgsPieDiagram::QgsPieDiagram()
00227 {
00228   mCategoryBrush.setStyle( Qt::SolidPattern );
00229   mPen.setStyle( Qt::SolidLine );
00230 }
00231 
00232 QgsPieDiagram::~QgsPieDiagram()
00233 {
00234 }
00235 
00236 void QgsPieDiagram::renderDiagram( const QgsAttributeMap& att, QgsRenderContext& c, const QgsDiagramSettings& s, const QPointF& position )
00237 {
00238   QPainter* p = c.painter();
00239   if ( !p )
00240   {
00241     return;
00242   }
00243 
00244   //get sum of values
00245   QList<double> values;
00246   double currentVal = 0;
00247   double valSum = 0;
00248 
00249   QList<int>::const_iterator catIt = s.categoryIndices.constBegin();
00250   for ( ; catIt != s.categoryIndices.constEnd(); ++catIt )
00251   {
00252     currentVal = att[*catIt].toDouble();
00253     values.push_back( currentVal );
00254     valSum += currentVal;
00255   }
00256 
00257   //draw the slices
00258   double totalAngle = 0;
00259   double currentAngle;
00260 
00261   //convert from mm / map units to painter units
00262   QSizeF spu = sizePainterUnits( s.size, s, c );
00263   double w = spu.width();
00264   double h = spu.height();
00265 
00266   double baseX = position.x();
00267   double baseY = position.y() - h;
00268 
00269   mPen.setColor( s.penColor );
00270   setPenWidth( mPen, s, c );
00271   p->setPen( mPen );
00272 
00273   QList<double>::const_iterator valIt = values.constBegin();
00274   QList< QColor >::const_iterator colIt = s.categoryColors.constBegin();
00275   for ( ; valIt != values.constEnd(); ++valIt, ++colIt )
00276   {
00277     currentAngle =  *valIt / valSum * 360 * 16;
00278     mCategoryBrush.setColor( *colIt );
00279     p->setBrush( mCategoryBrush );
00280     p->drawPie( baseX, baseY, w, h, totalAngle, currentAngle );
00281     totalAngle += currentAngle;
00282   }
00283 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines