Quantum GIS API Documentation
1.7.4
|
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 }