qwt_symbol.cpp
Go to the documentation of this file.
00001 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
00002  * Qwt Widget Library
00003  * Copyright (C) 1997   Josef Wilgen
00004  * Copyright (C) 2002   Uwe Rathmann
00005  *
00006  * This library is free software; you can redistribute it and/or
00007  * modify it under the terms of the Qwt License, Version 1.0
00008  *****************************************************************************/
00009 
00010 #include "qwt_symbol.h"
00011 #include "qwt_painter.h"
00012 #include "qwt_graphic.h"
00013 #include <qapplication.h>
00014 #include <qpainter.h>
00015 #include <qpainterpath.h>
00016 #include <qpixmap.h>
00017 #include <qpaintengine.h>
00018 #include <qmath.h>
00019 #ifndef QWT_NO_SVG
00020 #include <QtSvg/QSvgRenderer>
00021 #endif
00022 
00023 namespace QwtTriangle
00024 {
00025     enum Type
00026     {
00027         Left,
00028         Right,
00029         Up,
00030         Down
00031     };
00032 }
00033 
00034 static QwtGraphic qwtPathGraphic( const QPainterPath &path, 
00035     const QPen &pen, const QBrush& brush )
00036 {
00037     QwtGraphic graphic;
00038     graphic.setRenderHint( QwtGraphic::RenderPensUnscaled );
00039 
00040     QPainter painter( &graphic );
00041     painter.setPen( pen );
00042     painter.setBrush( brush );
00043     painter.drawPath( path );
00044     painter.end();
00045 
00046     return graphic;
00047 }
00048 
00049 static inline QRectF qwtScaledBoundingRect( 
00050     const QwtGraphic &graphic, const QSizeF size )
00051 {
00052     QSizeF scaledSize = size;
00053     if ( scaledSize.isEmpty() )
00054         scaledSize = graphic.defaultSize();
00055         
00056     const QSizeF sz = graphic.controlPointRect().size();
00057 
00058     double sx = 1.0;
00059     if ( sz.width() > 0.0 )
00060         sx = scaledSize.width() / sz.width();
00061     
00062     double sy = 1.0;
00063     if ( sz.height() > 0.0 )
00064         sy = scaledSize.height() / sz.height();
00065 
00066     return graphic.scaledBoundingRect( sx, sy );
00067 }
00068 
00069 static inline void qwtDrawPixmapSymbols( QPainter *painter,
00070     const QPointF *points, int numPoints, const QwtSymbol &symbol )
00071 {
00072     QSize size = symbol.size();
00073     if ( size.isEmpty() )
00074         size = symbol.pixmap().size();
00075 
00076     const QTransform transform = painter->transform();
00077     if ( transform.isScaling() )
00078     {
00079         const QRect r( 0, 0, size.width(), size.height() );
00080         size = transform.mapRect( r ).size();
00081     }
00082 
00083     QPixmap pm = symbol.pixmap();
00084     if ( pm.size() != size )
00085         pm = pm.scaled( size );
00086     
00087     QPointF pinPoint( 0.5 * size.width(), 0.5 * size.height() );
00088     if ( symbol.isPinPointEnabled() )
00089         pinPoint = symbol.pinPoint();
00090 
00091     painter->resetTransform();
00092 
00093     for ( int i = 0; i < numPoints; i++ )
00094     {
00095         const QPointF pos = transform.map( points[i] ) - pinPoint;
00096 
00097         QwtPainter::drawPixmap( painter, 
00098             QRect( pos.toPoint(), pm.size() ), pm );
00099     }
00100 }
00101 
00102 #ifndef QWT_NO_SVG
00103 
00104 static inline void qwtDrawSvgSymbols( QPainter *painter, 
00105     const QPointF *points, int numPoints, 
00106     QSvgRenderer *renderer, const QwtSymbol &symbol )
00107 {
00108     if ( renderer == NULL || !renderer->isValid() )
00109         return;
00110 
00111     const QRectF viewBox = renderer->viewBoxF();
00112     if ( viewBox.isEmpty() )
00113         return;
00114 
00115     QSizeF sz = symbol.size();
00116     if ( !sz.isValid() )
00117         sz = viewBox.size();
00118 
00119     const double sx = sz.width() / viewBox.width();
00120     const double sy = sz.height() / viewBox.height();
00121 
00122     QPointF pinPoint = viewBox.center();
00123     if ( symbol.isPinPointEnabled() )
00124         pinPoint = symbol.pinPoint();
00125 
00126     const double dx = sx * ( pinPoint.x() - viewBox.left() );
00127     const double dy = sy * ( pinPoint.y() - viewBox.top() );
00128 
00129     for ( int i = 0; i < numPoints; i++ )
00130     {
00131         const double x = points[i].x() - dx;
00132         const double y = points[i].y() - dy;
00133 
00134         renderer->render( painter, 
00135             QRectF( x, y, sz.width(), sz.height() ) );
00136     }
00137 }
00138 
00139 #endif
00140 
00141 static inline void qwtDrawGraphicSymbols( QPainter *painter, 
00142     const QPointF *points, int numPoints, const QwtGraphic &graphic,
00143     const QwtSymbol &symbol )
00144 {
00145     const QRectF pointRect = graphic.controlPointRect();
00146     if ( pointRect.isEmpty() )
00147         return;
00148 
00149     double sx = 1.0;
00150     double sy = 1.0;
00151 
00152     const QSize sz = symbol.size();
00153     if ( sz.isValid() )
00154     {
00155         sx = sz.width() / pointRect.width();
00156         sy = sz.height() / pointRect.height();
00157     }
00158 
00159     QPointF pinPoint = pointRect.center();
00160     if ( symbol.isPinPointEnabled() )
00161         pinPoint = symbol.pinPoint();
00162 
00163     const QTransform transform = painter->transform();
00164 
00165     for ( int i = 0; i < numPoints; i++ )
00166     {
00167         QTransform tr = transform;
00168         tr.translate( points[i].x(), points[i].y() );
00169         tr.scale( sx, sy );
00170         tr.translate( -pinPoint.x(), -pinPoint.y() );
00171 
00172         painter->setTransform( tr );
00173 
00174         graphic.render( painter );
00175     }
00176 
00177     painter->setTransform( transform );
00178 }
00179 
00180 static inline void qwtDrawEllipseSymbols( QPainter *painter,
00181     const QPointF *points, int numPoints, const QwtSymbol &symbol )
00182 {
00183     painter->setBrush( symbol.brush() );
00184     painter->setPen( symbol.pen() );
00185 
00186     const QSize size = symbol.size();
00187 
00188     if ( QwtPainter::roundingAlignment( painter ) )
00189     {
00190         const int sw = size.width();
00191         const int sh = size.height();
00192         const int sw2 = size.width() / 2;
00193         const int sh2 = size.height() / 2;
00194 
00195         for ( int i = 0; i < numPoints; i++ )
00196         {
00197             const int x = qRound( points[i].x() );
00198             const int y = qRound( points[i].y() );
00199 
00200             const QRectF r( x - sw2, y - sh2, sw, sh );
00201             QwtPainter::drawEllipse( painter, r );
00202         }
00203     }
00204     else
00205     {
00206         const double sw = size.width();
00207         const double sh = size.height();
00208         const double sw2 = 0.5 * size.width();
00209         const double sh2 = 0.5 * size.height();
00210 
00211         for ( int i = 0; i < numPoints; i++ )
00212         {
00213             const double x = points[i].x();
00214             const double y = points[i].y();
00215 
00216             const QRectF r( x - sw2, y - sh2, sw, sh );
00217             QwtPainter::drawEllipse( painter, r );
00218         }
00219     }
00220 }
00221 
00222 static inline void qwtDrawRectSymbols( QPainter *painter,
00223     const QPointF *points, int numPoints, const QwtSymbol &symbol )
00224 {
00225     const QSize size = symbol.size();
00226 
00227     QPen pen = symbol.pen();
00228     pen.setJoinStyle( Qt::MiterJoin );
00229     painter->setPen( pen );
00230     painter->setBrush( symbol.brush() );
00231     painter->setRenderHint( QPainter::Antialiasing, false );
00232 
00233     if ( QwtPainter::roundingAlignment( painter ) )
00234     {
00235         const int sw = size.width();
00236         const int sh = size.height();
00237         const int sw2 = size.width() / 2;
00238         const int sh2 = size.height() / 2;
00239 
00240         for ( int i = 0; i < numPoints; i++ )
00241         {
00242             const int x = qRound( points[i].x() );
00243             const int y = qRound( points[i].y() );
00244 
00245             const QRect r( x - sw2, y - sh2, sw, sh );
00246             QwtPainter::drawRect( painter, r );
00247         }
00248     }
00249     else
00250     {
00251         const double sw = size.width();
00252         const double sh = size.height();
00253         const double sw2 = 0.5 * size.width();
00254         const double sh2 = 0.5 * size.height();
00255 
00256         for ( int i = 0; i < numPoints; i++ )
00257         {
00258             const double x = points[i].x();
00259             const double y = points[i].y();
00260 
00261             const QRectF r( x - sw2, y - sh2, sw, sh );
00262             QwtPainter::drawRect( painter, r );
00263         }
00264     }
00265 }
00266 
00267 static inline void qwtDrawDiamondSymbols( QPainter *painter,
00268     const QPointF *points, int numPoints, const QwtSymbol &symbol )
00269 {
00270     const QSize size = symbol.size();
00271 
00272     QPen pen = symbol.pen();
00273     pen.setJoinStyle( Qt::MiterJoin );
00274     painter->setPen( pen );
00275     painter->setBrush( symbol.brush() );
00276 
00277     if ( QwtPainter::roundingAlignment( painter ) )
00278     {
00279         for ( int i = 0; i < numPoints; i++ )
00280         {
00281             const int x = qRound( points[i].x() );
00282             const int y = qRound( points[i].y() );
00283 
00284             const int x1 = x - size.width() / 2;
00285             const int y1 = y - size.height() / 2;
00286             const int x2 = x1 + size.width();
00287             const int y2 = y1 + size.height();
00288 
00289             QPolygonF polygon;
00290             polygon += QPointF( x, y1 );
00291             polygon += QPointF( x1, y );
00292             polygon += QPointF( x, y2 );
00293             polygon += QPointF( x2, y );
00294 
00295             QwtPainter::drawPolygon( painter, polygon );
00296         }
00297     }
00298     else
00299     {
00300         for ( int i = 0; i < numPoints; i++ )
00301         {
00302             const QPointF &pos = points[i];
00303 
00304             const double x1 = pos.x() - 0.5 * size.width();
00305             const double y1 = pos.y() - 0.5 * size.height();
00306             const double x2 = x1 + size.width();
00307             const double y2 = y1 + size.height();
00308 
00309             QPolygonF polygon;
00310             polygon += QPointF( pos.x(), y1 );
00311             polygon += QPointF( x2, pos.y() );
00312             polygon += QPointF( pos.x(), y2 );
00313             polygon += QPointF( x1, pos.y() );
00314 
00315             QwtPainter::drawPolygon( painter, polygon );
00316         }
00317     }
00318 }
00319 
00320 static inline void qwtDrawTriangleSymbols(
00321     QPainter *painter, QwtTriangle::Type type,
00322     const QPointF *points, int numPoints,
00323     const QwtSymbol &symbol )
00324 {
00325     const QSize size = symbol.size();
00326 
00327     QPen pen = symbol.pen();
00328     pen.setJoinStyle( Qt::MiterJoin );
00329     painter->setPen( pen );
00330 
00331     painter->setBrush( symbol.brush() );
00332 
00333     const bool doAlign = QwtPainter::roundingAlignment( painter );
00334 
00335     double sw2 = 0.5 * size.width();
00336     double sh2 = 0.5 * size.height();
00337 
00338     if ( doAlign )
00339     {
00340         sw2 = qFloor( sw2 );
00341         sh2 = qFloor( sh2 );
00342     }
00343 
00344     QPolygonF triangle( 3 );
00345     QPointF *trianglePoints = triangle.data();
00346 
00347     for ( int i = 0; i < numPoints; i++ )
00348     {
00349         const QPointF &pos = points[i];
00350 
00351         double x = pos.x();
00352         double y = pos.y();
00353 
00354         if ( doAlign )
00355         {
00356             x = qRound( x );
00357             y = qRound( y );
00358         }
00359 
00360         const double x1 = x - sw2;
00361         const double x2 = x1 + size.width();
00362         const double y1 = y - sh2;
00363         const double y2 = y1 + size.height();
00364 
00365         switch ( type )
00366         {
00367             case QwtTriangle::Left:
00368             {
00369                 trianglePoints[0].rx() = x2;
00370                 trianglePoints[0].ry() = y1;
00371 
00372                 trianglePoints[1].rx() = x1;
00373                 trianglePoints[1].ry() = y;
00374 
00375                 trianglePoints[2].rx() = x2;
00376                 trianglePoints[2].ry() = y2;
00377 
00378                 break;
00379             }
00380             case QwtTriangle::Right:
00381             {
00382                 trianglePoints[0].rx() = x1;
00383                 trianglePoints[0].ry() = y1;
00384 
00385                 trianglePoints[1].rx() = x2;
00386                 trianglePoints[1].ry() = y;
00387 
00388                 trianglePoints[2].rx() = x1;
00389                 trianglePoints[2].ry() = y2;
00390 
00391                 break;
00392             }
00393             case QwtTriangle::Up:
00394             {
00395                 trianglePoints[0].rx() = x1;
00396                 trianglePoints[0].ry() = y2;
00397 
00398                 trianglePoints[1].rx() = x;
00399                 trianglePoints[1].ry() = y1;
00400 
00401                 trianglePoints[2].rx() = x2;
00402                 trianglePoints[2].ry() = y2;
00403 
00404                 break;
00405             }
00406             case QwtTriangle::Down:
00407             {
00408                 trianglePoints[0].rx() = x1;
00409                 trianglePoints[0].ry() = y1;
00410 
00411                 trianglePoints[1].rx() = x;
00412                 trianglePoints[1].ry() = y2;
00413 
00414                 trianglePoints[2].rx() = x2;
00415                 trianglePoints[2].ry() = y1;
00416 
00417                 break;
00418             }
00419         }
00420         QwtPainter::drawPolygon( painter, triangle );
00421     }
00422 }
00423 
00424 static inline void qwtDrawLineSymbols(
00425     QPainter *painter, int orientations,
00426     const QPointF *points, int numPoints, const QwtSymbol &symbol )
00427 {
00428     const QSize size = symbol.size();
00429 
00430     int off = 0;
00431 
00432     QPen pen = symbol.pen();
00433     if ( pen.width() > 1 )
00434     {
00435         pen.setCapStyle( Qt::FlatCap );
00436         off = 1;
00437     }
00438 
00439     painter->setPen( pen );
00440     painter->setRenderHint( QPainter::Antialiasing, false );
00441 
00442     if ( QwtPainter::roundingAlignment( painter ) )
00443     {
00444         const int sw = qFloor( size.width() );
00445         const int sh = qFloor( size.height() );
00446         const int sw2 = size.width() / 2;
00447         const int sh2 = size.height() / 2;
00448 
00449         for ( int i = 0; i < numPoints; i++ )
00450         {
00451             if ( orientations & Qt::Horizontal )
00452             {
00453                 const int x = qRound( points[i].x() ) - sw2;
00454                 const int y = qRound( points[i].y() );
00455 
00456                 QwtPainter::drawLine( painter, x, y, x + sw + off, y );
00457             }
00458             if ( orientations & Qt::Vertical )
00459             {
00460                 const int x = qRound( points[i].x() );
00461                 const int y = qRound( points[i].y() ) - sh2;
00462 
00463                 QwtPainter::drawLine( painter, x, y, x, y + sh + off );
00464             }
00465         }
00466     }
00467     else
00468     {
00469         const double sw = size.width();
00470         const double sh = size.height();
00471         const double sw2 = 0.5 * size.width();
00472         const double sh2 = 0.5 * size.height();
00473 
00474         for ( int i = 0; i < numPoints; i++ )
00475         {
00476             if ( orientations & Qt::Horizontal )
00477             {
00478                 const double x = points[i].x() - sw2;
00479                 const double y = points[i].y();
00480 
00481                 QwtPainter::drawLine( painter, x, y, x + sw, y );
00482             }
00483             if ( orientations & Qt::Vertical )
00484             {
00485                 const double y = points[i].y() - sh2;
00486                 const double x = points[i].x();
00487 
00488                 QwtPainter::drawLine( painter, x, y, x, y + sh );
00489             }
00490         }
00491     }
00492 }
00493 
00494 static inline void qwtDrawXCrossSymbols( QPainter *painter,
00495     const QPointF *points, int numPoints, const QwtSymbol &symbol )
00496 {
00497     const QSize size = symbol.size();
00498     int off = 0;
00499 
00500     QPen pen = symbol.pen();
00501     if ( pen.width() > 1 )
00502     {
00503         pen.setCapStyle( Qt::FlatCap );
00504         off = 1;
00505     }
00506     painter->setPen( pen );
00507 
00508 
00509     if ( QwtPainter::roundingAlignment( painter ) )
00510     {
00511         const int sw = size.width();
00512         const int sh = size.height();
00513         const int sw2 = size.width() / 2;
00514         const int sh2 = size.height() / 2;
00515 
00516         for ( int i = 0; i < numPoints; i++ )
00517         {
00518             const QPointF &pos = points[i];
00519 
00520             const int x = qRound( pos.x() );
00521             const int y = qRound( pos.y() );
00522 
00523             const int x1 = x - sw2;
00524             const int x2 = x1 + sw + off;
00525             const int y1 = y - sh2;
00526             const int y2 = y1 + sh + off;
00527 
00528             QwtPainter::drawLine( painter, x1, y1, x2, y2 );
00529             QwtPainter::drawLine( painter, x2, y1, x1, y2 );
00530         }
00531     }
00532     else
00533     {
00534         const double sw = size.width();
00535         const double sh = size.height();
00536         const double sw2 = 0.5 * size.width();
00537         const double sh2 = 0.5 * size.height();
00538 
00539         for ( int i = 0; i < numPoints; i++ )
00540         {
00541             const QPointF &pos = points[i];
00542 
00543             const double x1 = pos.x() - sw2;
00544             const double x2 = x1 + sw;
00545             const double y1 = pos.y() - sh2;
00546             const double y2 = y1 + sh;
00547 
00548             QwtPainter::drawLine( painter, x1, y1, x2, y2 );
00549             QwtPainter::drawLine( painter, x1, y2, x2, y1 );
00550         }
00551     }
00552 }
00553 
00554 static inline void qwtDrawStar1Symbols( QPainter *painter,
00555     const QPointF *points, int numPoints, const QwtSymbol &symbol )
00556 {
00557     const QSize size = symbol.size();
00558     painter->setPen( symbol.pen() );
00559 
00560     if ( QwtPainter::roundingAlignment( painter ) )
00561     {
00562         QRect r( 0, 0, size.width(), size.height() );
00563 
00564         for ( int i = 0; i < numPoints; i++ )
00565         {
00566             r.moveCenter( points[i].toPoint() );
00567 
00568             const double sqrt1_2 = 0.70710678118654752440; /* 1/sqrt(2) */
00569 
00570             const double d1 = r.width() / 2.0 * ( 1.0 - sqrt1_2 );
00571 
00572             QwtPainter::drawLine( painter,
00573                 qRound( r.left() + d1 ), qRound( r.top() + d1 ),
00574                 qRound( r.right() - d1 ), qRound( r.bottom() - d1 ) );
00575             QwtPainter::drawLine( painter,
00576                 qRound( r.left() + d1 ), qRound( r.bottom() - d1 ),
00577                 qRound( r .right() - d1), qRound( r.top() + d1 ) );
00578 
00579             const QPoint c = r.center();
00580 
00581             QwtPainter::drawLine( painter,
00582                 c.x(), r.top(), c.x(), r.bottom() );
00583             QwtPainter::drawLine( painter,
00584                 r.left(), c.y(), r.right(), c.y() );
00585         }
00586     }
00587     else
00588     {
00589         QRectF r( 0, 0, size.width(), size.height() );
00590 
00591         for ( int i = 0; i < numPoints; i++ )
00592         {
00593             r.moveCenter( points[i] );
00594 
00595             const double sqrt1_2 = 0.70710678118654752440; /* 1/sqrt(2) */
00596 
00597             const QPointF c = r.center();
00598             const double d1  = r.width() / 2.0 * ( 1.0 - sqrt1_2 );
00599 
00600             QwtPainter::drawLine( painter,
00601                 r.left() + d1, r.top() + d1,
00602                 r.right() - d1, r.bottom() - d1 );
00603             QwtPainter::drawLine( painter,
00604                 r.left() + d1, r.bottom() - d1,
00605                 r.right() - d1, r.top() + d1 );
00606             QwtPainter::drawLine( painter,
00607                 c.x(), r.top(),
00608                 c.x(), r.bottom() );
00609             QwtPainter::drawLine( painter,
00610                 r.left(), c.y(),
00611                 r.right(), c.y() );
00612         }
00613     }
00614 }
00615 
00616 static inline void qwtDrawStar2Symbols( QPainter *painter,
00617     const QPointF *points, int numPoints, const QwtSymbol &symbol )
00618 {
00619     QPen pen = symbol.pen();
00620     if ( pen.width() > 1 )
00621         pen.setCapStyle( Qt::FlatCap );
00622     pen.setJoinStyle( Qt::MiterJoin );
00623     painter->setPen( pen );
00624 
00625     painter->setBrush( symbol.brush() );
00626 
00627     const double cos30 = 0.866025; // cos(30°)
00628 
00629     const double dy = 0.25 * symbol.size().height();
00630     const double dx = 0.5 * symbol.size().width() * cos30 / 3.0;
00631 
00632     QPolygonF star( 12 );
00633     QPointF *starPoints = star.data();
00634 
00635     const bool doAlign = QwtPainter::roundingAlignment( painter );
00636 
00637     for ( int i = 0; i < numPoints; i++ )
00638     {
00639         double x = points[i].x();
00640         double y = points[i].y();
00641         if ( doAlign )
00642         {
00643             x = qRound( x );
00644             y = qRound( y );
00645         }
00646 
00647         double x1 = x - 3 * dx;
00648         double y1 = y - 2 * dy;
00649         if ( doAlign )
00650         {
00651             x1 = qRound( x - 3 * dx );
00652             y1 = qRound( y - 2 * dy );
00653         }
00654 
00655         const double x2 = x1 + 1 * dx;
00656         const double x3 = x1 + 2 * dx;
00657         const double x4 = x1 + 3 * dx;
00658         const double x5 = x1 + 4 * dx;
00659         const double x6 = x1 + 5 * dx;
00660         const double x7 = x1 + 6 * dx;
00661 
00662         const double y2 = y1 + 1 * dy;
00663         const double y3 = y1 + 2 * dy;
00664         const double y4 = y1 + 3 * dy;
00665         const double y5 = y1 + 4 * dy;
00666 
00667         starPoints[0].rx() = x4;
00668         starPoints[0].ry() = y1;
00669 
00670         starPoints[1].rx() = x5;
00671         starPoints[1].ry() = y2;
00672 
00673         starPoints[2].rx() = x7;
00674         starPoints[2].ry() = y2;
00675 
00676         starPoints[3].rx() = x6;
00677         starPoints[3].ry() = y3;
00678 
00679         starPoints[4].rx() = x7;
00680         starPoints[4].ry() = y4;
00681 
00682         starPoints[5].rx() = x5;
00683         starPoints[5].ry() = y4;
00684 
00685         starPoints[6].rx() = x4;
00686         starPoints[6].ry() = y5;
00687 
00688         starPoints[7].rx() = x3;
00689         starPoints[7].ry() = y4;
00690 
00691         starPoints[8].rx() = x1;
00692         starPoints[8].ry() = y4;
00693 
00694         starPoints[9].rx() = x2;
00695         starPoints[9].ry() = y3;
00696 
00697         starPoints[10].rx() = x1;
00698         starPoints[10].ry() = y2;
00699 
00700         starPoints[11].rx() = x3;
00701         starPoints[11].ry() = y2;
00702 
00703         QwtPainter::drawPolygon( painter, star );
00704     }
00705 }
00706 
00707 static inline void qwtDrawHexagonSymbols( QPainter *painter,
00708     const QPointF *points, int numPoints, const QwtSymbol &symbol )
00709 {
00710     painter->setBrush( symbol.brush() );
00711     painter->setPen( symbol.pen() );
00712 
00713     const double cos30 = 0.866025; // cos(30°)
00714     const double dx = 0.5 * ( symbol.size().width() - cos30 );
00715 
00716     const double dy = 0.25 * symbol.size().height();
00717 
00718     QPolygonF hexaPolygon( 6 );
00719     QPointF *hexaPoints = hexaPolygon.data();
00720 
00721     const bool doAlign = QwtPainter::roundingAlignment( painter );
00722 
00723     for ( int i = 0; i < numPoints; i++ )
00724     {
00725         double x = points[i].x();
00726         double y = points[i].y();
00727         if ( doAlign )
00728         {
00729             x = qRound( x );
00730             y = qRound( y );
00731         }
00732 
00733         double x1 = x - dx;
00734         double y1 = y - 2 * dy;
00735         if ( doAlign )
00736         {
00737             x1 = qCeil( x1 );
00738             y1 = qCeil( y1 );
00739         }
00740 
00741         const double x2 = x1 + 1 * dx;
00742         const double x3 = x1 + 2 * dx;
00743 
00744         const double y2 = y1 + 1 * dy;
00745         const double y3 = y1 + 3 * dy;
00746         const double y4 = y1 + 4 * dy;
00747 
00748         hexaPoints[0].rx() = x2;
00749         hexaPoints[0].ry() = y1;
00750 
00751         hexaPoints[1].rx() = x3;
00752         hexaPoints[1].ry() = y2;
00753 
00754         hexaPoints[2].rx() = x3;
00755         hexaPoints[2].ry() = y3;
00756 
00757         hexaPoints[3].rx() = x2;
00758         hexaPoints[3].ry() = y4;
00759 
00760         hexaPoints[4].rx() = x1;
00761         hexaPoints[4].ry() = y3;
00762 
00763         hexaPoints[5].rx() = x1;
00764         hexaPoints[5].ry() = y2;
00765 
00766         QwtPainter::drawPolygon( painter, hexaPolygon );
00767     }
00768 }
00769 
00770 class QwtSymbol::PrivateData
00771 {
00772 public:
00773     PrivateData( QwtSymbol::Style st, const QBrush &br,
00774             const QPen &pn, const QSize &sz ):
00775         style( st ),
00776         size( sz ),
00777         brush( br ),
00778         pen( pn ),
00779         isPinPointEnabled( false )
00780     {
00781         cache.policy = QwtSymbol::AutoCache;
00782 #ifndef QWT_NO_SVG
00783         svg.renderer = NULL;
00784 #endif
00785     }
00786 
00787     ~PrivateData()
00788     {
00789 #ifndef QWT_NO_SVG
00790         delete svg.renderer;
00791 #endif
00792     }
00793 
00794     Style style;
00795     QSize size;
00796     QBrush brush;
00797     QPen pen;
00798 
00799     bool isPinPointEnabled;
00800     QPointF pinPoint;
00801 
00802     struct Path
00803     {
00804         QPainterPath path;
00805         QwtGraphic graphic;
00806 
00807     } path;
00808 
00809     struct Pixmap
00810     {
00811         QPixmap pixmap;
00812 
00813     } pixmap;
00814 
00815     struct Graphic
00816     {
00817         QwtGraphic graphic;
00818 
00819     } graphic;
00820 
00821 #ifndef QWT_NO_SVG
00822     struct SVG
00823     {
00824         QSvgRenderer *renderer;
00825     } svg;
00826 #endif
00827 
00828     struct PaintCache
00829     {
00830         QwtSymbol::CachePolicy policy;
00831         QPixmap pixmap;
00832 
00833     } cache;
00834 };
00835 
00843 QwtSymbol::QwtSymbol( Style style )
00844 {
00845     d_data = new PrivateData( style, QBrush( Qt::gray ),
00846         QPen( Qt::black, 0 ), QSize() );
00847 }
00848 
00858 QwtSymbol::QwtSymbol( QwtSymbol::Style style, const QBrush &brush,
00859     const QPen &pen, const QSize &size )
00860 {
00861     d_data = new PrivateData( style, brush, pen, size );
00862 }
00863 
00878 QwtSymbol::QwtSymbol( const QPainterPath &path, 
00879     const QBrush &brush, const QPen &pen )
00880 {
00881     d_data = new PrivateData( QwtSymbol::Path, brush, pen, QSize() );
00882     setPath( path );
00883 }
00884 
00886 QwtSymbol::~QwtSymbol()
00887 {
00888     delete d_data;
00889 }
00890 
00899 void QwtSymbol::setCachePolicy(
00900     QwtSymbol::CachePolicy policy )
00901 {
00902     if ( d_data->cache.policy != policy )
00903     {
00904         d_data->cache.policy = policy;
00905         invalidateCache();
00906     }
00907 }
00908 
00913 QwtSymbol::CachePolicy QwtSymbol::cachePolicy() const
00914 {
00915     return d_data->cache.policy;
00916 }
00917 
00965 void QwtSymbol::setPath( const QPainterPath &path )
00966 {
00967     d_data->style = QwtSymbol::Path;
00968     d_data->path.path = path;
00969     d_data->path.graphic.reset();
00970 }
00971 
00976 const QPainterPath &QwtSymbol::path() const
00977 {
00978     return d_data->path.path;
00979 }
00980 
00991 void QwtSymbol::setPixmap( const QPixmap &pixmap )
00992 {
00993     d_data->style = QwtSymbol::Pixmap;
00994     d_data->pixmap.pixmap = pixmap;
00995 }
00996 
01001 const QPixmap &QwtSymbol::pixmap() const
01002 {
01003     return d_data->pixmap.pixmap;
01004 }
01005 
01016 void QwtSymbol::setGraphic( const QwtGraphic &graphic )
01017 {
01018     d_data->style = QwtSymbol::Graphic;
01019     d_data->graphic.graphic = graphic;
01020 }
01021 
01026 const QwtGraphic &QwtSymbol::graphic() const
01027 {
01028     return d_data->graphic.graphic;
01029 }
01030 
01031 #ifndef QWT_NO_SVG
01032 
01043 void QwtSymbol::setSvgDocument( const QByteArray &svgDocument )
01044 {
01045     d_data->style = QwtSymbol::SvgDocument;
01046     if ( d_data->svg.renderer == NULL )
01047         d_data->svg.renderer = new QSvgRenderer();
01048 
01049     d_data->svg.renderer->load( svgDocument );
01050 }
01051 
01052 #endif
01053 
01066 void QwtSymbol::setSize( int width, int height )
01067 {
01068     if ( ( width >= 0 ) && ( height < 0 ) )
01069         height = width;
01070 
01071     setSize( QSize( width, height ) );
01072 }
01073 
01080 void QwtSymbol::setSize( const QSize &size )
01081 {
01082     if ( size.isValid() && size != d_data->size )
01083     {
01084         d_data->size = size;
01085         invalidateCache();
01086     }
01087 }
01088 
01093 const QSize& QwtSymbol::size() const
01094 {
01095     return d_data->size;
01096 }
01097 
01106 void QwtSymbol::setBrush( const QBrush &brush )
01107 {
01108     if ( brush != d_data->brush )
01109     {
01110         d_data->brush = brush;
01111         invalidateCache();
01112 
01113         if ( d_data->style == QwtSymbol::Path )
01114             d_data->path.graphic.reset();
01115     }
01116 }
01117 
01122 const QBrush& QwtSymbol::brush() const
01123 {
01124     return d_data->brush;
01125 }
01126 
01140 void QwtSymbol::setPen( const QColor &color,
01141     qreal width, Qt::PenStyle style )
01142 {
01143     setPen( QPen( color, width, style ) );
01144 }
01145 
01154 void QwtSymbol::setPen( const QPen &pen )
01155 {
01156     if ( pen != d_data->pen )
01157     {
01158         d_data->pen = pen;
01159         invalidateCache();
01160 
01161         if ( d_data->style == QwtSymbol::Path )
01162             d_data->path.graphic.reset();
01163     }
01164 }
01165 
01170 const QPen& QwtSymbol::pen() const
01171 {
01172     return d_data->pen;
01173 }
01174 
01185 void QwtSymbol::setColor( const QColor &color )
01186 {
01187     switch ( d_data->style )
01188     {
01189         case QwtSymbol::Ellipse:
01190         case QwtSymbol::Rect:
01191         case QwtSymbol::Diamond:
01192         case QwtSymbol::Triangle:
01193         case QwtSymbol::UTriangle:
01194         case QwtSymbol::DTriangle:
01195         case QwtSymbol::RTriangle:
01196         case QwtSymbol::LTriangle:
01197         case QwtSymbol::Star2:
01198         case QwtSymbol::Hexagon:
01199         {
01200             if ( d_data->brush.color() != color )
01201             {
01202                 d_data->brush.setColor( color );
01203                 invalidateCache();
01204             }
01205             break;
01206         }
01207         case QwtSymbol::Cross:
01208         case QwtSymbol::XCross:
01209         case QwtSymbol::HLine:
01210         case QwtSymbol::VLine:
01211         case QwtSymbol::Star1:
01212         {
01213             if ( d_data->pen.color() != color )
01214             {
01215                 d_data->pen.setColor( color );
01216                 invalidateCache();
01217             }
01218             break;
01219         }
01220         default:
01221         {
01222             if ( d_data->brush.color() != color ||
01223                 d_data->pen.color() != color )
01224             {
01225                 invalidateCache();
01226             }
01227 
01228             d_data->brush.setColor( color );
01229             d_data->pen.setColor( color );
01230         }
01231     }
01232 }
01233 
01248 void QwtSymbol::setPinPoint( const QPointF &pos, bool enable )
01249 {
01250     if ( d_data->pinPoint != pos )
01251     {
01252         d_data->pinPoint = pos;
01253         if ( d_data->isPinPointEnabled )
01254         {
01255             invalidateCache();
01256         }
01257     }
01258 
01259     setPinPointEnabled( enable );
01260 }
01261 
01266 QPointF QwtSymbol::pinPoint() const
01267 {
01268     return d_data->pinPoint;
01269 }
01270 
01277 void QwtSymbol::setPinPointEnabled( bool on )
01278 {
01279     if ( d_data->isPinPointEnabled != on )
01280     {
01281         d_data->isPinPointEnabled = on;
01282         invalidateCache();
01283     }
01284 }
01285 
01290 bool QwtSymbol::isPinPointEnabled() const
01291 {
01292     return d_data->isPinPointEnabled;
01293 }
01294 
01306 void QwtSymbol::drawSymbols( QPainter *painter,
01307     const QPointF *points, int numPoints ) const
01308 {
01309     if ( numPoints <= 0 )
01310         return;
01311 
01312     bool useCache = false;
01313 
01314     // Don't use the pixmap, when the paint device
01315     // could generate scalable vectors
01316 
01317     if ( QwtPainter::roundingAlignment( painter ) &&
01318         !painter->transform().isScaling() )
01319     {
01320         if ( d_data->cache.policy == QwtSymbol::Cache )
01321         {
01322             useCache = true;
01323         }
01324         else if ( d_data->cache.policy == QwtSymbol::AutoCache )
01325         {
01326             switch( painter->paintEngine()->type() )
01327             {
01328                 case QPaintEngine::OpenGL:
01329 #if QT_VERSION >= 0x040600
01330                 case QPaintEngine::OpenGL2:
01331 #endif
01332                 {
01333                     // using a FBO as cache ?
01334                     useCache = false;
01335                     break;
01336                 }
01337 #if QT_VERSION >= 0x040500
01338                 case QPaintEngine::OpenVG:
01339 #endif
01340                 case QPaintEngine::SVG:
01341                 case QPaintEngine::Pdf:
01342                 case QPaintEngine::Picture:
01343                 {
01344                     // vector graphics
01345                     useCache = false;
01346                     break;
01347                 }
01348                 case QPaintEngine::X11:
01349                 {
01350                     switch( d_data->style )
01351                     {
01352                         case QwtSymbol::XCross:
01353                         case QwtSymbol::HLine:
01354                         case QwtSymbol::VLine:
01355                         case QwtSymbol::Cross:
01356                         {
01357                             // for the very simple shapes using vector graphics is 
01358                             // usually faster.
01359 
01360                             useCache = false;
01361                             break;
01362                         }
01363 
01364                         case QwtSymbol::Pixmap:
01365                         {
01366                             if ( d_data->size.isEmpty() ||
01367                                 d_data->size == d_data->pixmap.pixmap.size() ) 
01368                             {
01369                                 // no need to have a pixmap cache for a pixmap
01370                                 // of the same size
01371 
01372                                 useCache = false;
01373                             }
01374                             break;
01375                         }                       
01376                         default:
01377                             break;
01378                     }
01379                     break;
01380                 }
01381                 default:
01382                 {
01383                     useCache = true;
01384                 }
01385             }
01386         }
01387     }
01388 
01389     if ( useCache )
01390     {
01391         const QRect br = boundingRect();
01392 
01393         const QRect rect( 0, 0, br.width(), br.height() );
01394 
01395         if ( d_data->cache.pixmap.isNull() )
01396         {
01397             d_data->cache.pixmap = QwtPainter::backingStore( NULL, br.size() );
01398             d_data->cache.pixmap.fill( Qt::transparent );
01399 
01400             QPainter p( &d_data->cache.pixmap );
01401             p.setRenderHints( painter->renderHints() );
01402             p.translate( -br.topLeft() );
01403 
01404             const QPointF pos( 0.0, 0.0 );
01405             renderSymbols( &p, &pos, 1 );
01406         }
01407 
01408         const int dx = br.left();
01409         const int dy = br.top();
01410 
01411         for ( int i = 0; i < numPoints; i++ )
01412         {
01413             const int left = qRound( points[i].x() ) + dx;
01414             const int top = qRound( points[i].y() ) + dy;
01415 
01416             painter->drawPixmap( left, top, d_data->cache.pixmap );
01417         }
01418     }
01419     else
01420     {
01421         painter->save();
01422         renderSymbols( painter, points, numPoints );
01423         painter->restore();
01424     }
01425 }
01426 
01439 void QwtSymbol::drawSymbol( QPainter *painter, const QRectF &rect ) const
01440 {
01441     if ( d_data->style == QwtSymbol::NoSymbol )
01442         return;
01443 
01444     if ( d_data->style == QwtSymbol::Graphic )
01445     {
01446         d_data->graphic.graphic.render( 
01447             painter, rect, Qt::KeepAspectRatio );
01448     }
01449     else if ( d_data->style == QwtSymbol::Path )
01450     {
01451         if ( d_data->path.graphic.isNull() )
01452         {
01453             d_data->path.graphic = qwtPathGraphic( 
01454                 d_data->path.path, d_data->pen, d_data->brush );
01455         }
01456 
01457         d_data->path.graphic.render( 
01458             painter, rect, Qt::KeepAspectRatio );
01459         return;
01460     }
01461     else if ( d_data->style == QwtSymbol::SvgDocument )
01462     {
01463 #ifndef QWT_NO_SVG
01464         if ( d_data->svg.renderer )
01465         {
01466             QRectF scaledRect;
01467 
01468             QSizeF sz = d_data->svg.renderer->viewBoxF().size();
01469             if ( !sz.isEmpty() )
01470             {
01471                 sz.scale( rect.size(), Qt::KeepAspectRatio );
01472                 scaledRect.setSize( sz );
01473                 scaledRect.moveCenter( rect.center() );
01474             }
01475             else
01476             {
01477                 scaledRect = rect;
01478             }
01479 
01480             d_data->svg.renderer->render( 
01481                 painter, scaledRect );
01482         }
01483 #endif
01484     }
01485     else
01486     {
01487         const QRect br = boundingRect();
01488 
01489         // scale the symbol size to fit into rect.
01490 
01491         const double ratio = qMin( rect.width() / br.width(), 
01492             rect.height() / br.height() );
01493 
01494         painter->save();
01495 
01496         painter->translate( rect.center() );
01497         painter->scale( ratio, ratio );
01498 
01499         const bool isPinPointEnabled = d_data->isPinPointEnabled;
01500         d_data->isPinPointEnabled = false;
01501 
01502         const QPointF pos;
01503         renderSymbols( painter, &pos, 1 );
01504     
01505         d_data->isPinPointEnabled = isPinPointEnabled;
01506 
01507         painter->restore();
01508     }
01509 }
01510 
01518 void QwtSymbol::renderSymbols( QPainter *painter,
01519     const QPointF *points, int numPoints ) const
01520 {
01521     switch ( d_data->style )
01522     {
01523         case QwtSymbol::Ellipse:
01524         {
01525             qwtDrawEllipseSymbols( painter, points, numPoints, *this );
01526             break;
01527         }
01528         case QwtSymbol::Rect:
01529         {
01530             qwtDrawRectSymbols( painter, points, numPoints, *this );
01531             break;
01532         }
01533         case QwtSymbol::Diamond:
01534         {
01535             qwtDrawDiamondSymbols( painter, points, numPoints, *this );
01536             break;
01537         }
01538         case QwtSymbol::Cross:
01539         {
01540             qwtDrawLineSymbols( painter, Qt::Horizontal | Qt::Vertical,
01541                 points, numPoints, *this );
01542             break;
01543         }
01544         case QwtSymbol::XCross:
01545         {
01546             qwtDrawXCrossSymbols( painter, points, numPoints, *this );
01547             break;
01548         }
01549         case QwtSymbol::Triangle:
01550         case QwtSymbol::UTriangle:
01551         {
01552             qwtDrawTriangleSymbols( painter, QwtTriangle::Up,
01553                 points, numPoints, *this );
01554             break;
01555         }
01556         case QwtSymbol::DTriangle:
01557         {
01558             qwtDrawTriangleSymbols( painter, QwtTriangle::Down,
01559                 points, numPoints, *this );
01560             break;
01561         }
01562         case QwtSymbol::RTriangle:
01563         {
01564             qwtDrawTriangleSymbols( painter, QwtTriangle::Right,
01565                 points, numPoints, *this );
01566             break;
01567         }
01568         case QwtSymbol::LTriangle:
01569         {
01570             qwtDrawTriangleSymbols( painter, QwtTriangle::Left,
01571                 points, numPoints, *this );
01572             break;
01573         }
01574         case QwtSymbol::HLine:
01575         {
01576             qwtDrawLineSymbols( painter, Qt::Horizontal,
01577                 points, numPoints, *this );
01578             break;
01579         }
01580         case QwtSymbol::VLine:
01581         {
01582             qwtDrawLineSymbols( painter, Qt::Vertical,
01583                 points, numPoints, *this );
01584             break;
01585         }
01586         case QwtSymbol::Star1:
01587         {
01588             qwtDrawStar1Symbols( painter, points, numPoints, *this );
01589             break;
01590         }
01591         case QwtSymbol::Star2:
01592         {
01593             qwtDrawStar2Symbols( painter, points, numPoints, *this );
01594             break;
01595         }
01596         case QwtSymbol::Hexagon:
01597         {
01598             qwtDrawHexagonSymbols( painter, points, numPoints, *this );
01599             break;
01600         }
01601         case QwtSymbol::Path:
01602         {
01603             if ( d_data->path.graphic.isNull() )
01604             {
01605                 d_data->path.graphic = qwtPathGraphic( d_data->path.path, 
01606                     d_data->pen, d_data->brush );
01607             }
01608 
01609             qwtDrawGraphicSymbols( painter, points, numPoints, 
01610                 d_data->path.graphic, *this );
01611             break;
01612         }
01613         case QwtSymbol::Pixmap:
01614         {
01615             qwtDrawPixmapSymbols( painter, points, numPoints, *this );
01616             break;
01617         }
01618         case QwtSymbol::Graphic:
01619         {
01620             qwtDrawGraphicSymbols( painter, points, numPoints, 
01621                 d_data->graphic.graphic, *this );
01622             break;
01623         }
01624         case QwtSymbol::SvgDocument:
01625         {
01626 #ifndef QWT_NO_SVG
01627             qwtDrawSvgSymbols( painter, points, numPoints, 
01628                 d_data->svg.renderer, *this );
01629 #endif
01630             break;
01631         }
01632         default:;
01633     }
01634 }
01635 
01642 QRect QwtSymbol::boundingRect() const
01643 {
01644     QRectF rect;
01645 
01646     bool pinPointTranslation = false;
01647 
01648     switch ( d_data->style )
01649     {
01650         case QwtSymbol::Ellipse:
01651         case QwtSymbol::Rect:
01652         case QwtSymbol::Hexagon:
01653         {
01654             qreal pw = 0.0;
01655             if ( d_data->pen.style() != Qt::NoPen )
01656                 pw = qMax( d_data->pen.widthF(), qreal( 1.0 ) );
01657 
01658             rect.setSize( d_data->size + QSizeF( pw, pw ) );
01659             rect.moveCenter( QPointF( 0.0, 0.0 ) );
01660 
01661             break;
01662         }
01663         case QwtSymbol::XCross:
01664         case QwtSymbol::Diamond:
01665         case QwtSymbol::Triangle:
01666         case QwtSymbol::UTriangle:
01667         case QwtSymbol::DTriangle:
01668         case QwtSymbol::RTriangle:
01669         case QwtSymbol::LTriangle:
01670         case QwtSymbol::Star1:
01671         case QwtSymbol::Star2:
01672         {
01673             qreal pw = 0.0;
01674             if ( d_data->pen.style() != Qt::NoPen )
01675                 pw = qMax( d_data->pen.widthF(), qreal( 1.0 ) );
01676 
01677             rect.setSize( d_data->size + QSizeF( 2 * pw, 2 * pw ) );
01678             rect.moveCenter( QPointF( 0.0, 0.0 ) );
01679             break;
01680         }
01681         case QwtSymbol::Path:
01682         {
01683             if ( d_data->path.graphic.isNull() )
01684             {
01685                 d_data->path.graphic = qwtPathGraphic(
01686                     d_data->path.path, d_data->pen, d_data->brush );
01687             }
01688 
01689             rect = qwtScaledBoundingRect( 
01690                 d_data->path.graphic, d_data->size );
01691             pinPointTranslation = true;
01692 
01693             break;
01694         }
01695         case QwtSymbol::Pixmap:
01696         {
01697             if ( d_data->size.isEmpty() )
01698                 rect.setSize( d_data->pixmap.pixmap.size() );
01699             else
01700                 rect.setSize( d_data->size );
01701             
01702             pinPointTranslation = true;
01703 
01704             break;
01705         }
01706         case QwtSymbol::Graphic:
01707         {
01708             rect = qwtScaledBoundingRect( 
01709                 d_data->graphic.graphic, d_data->size );
01710             pinPointTranslation = true;
01711 
01712             break;
01713         }
01714 #ifndef QWT_NO_SVG
01715         case QwtSymbol::SvgDocument:
01716         {
01717             if ( d_data->svg.renderer )
01718                 rect = d_data->svg.renderer->viewBoxF();
01719 
01720             if ( d_data->size.isValid() && !rect.isEmpty() )
01721             {
01722                 QSizeF sz = rect.size();
01723 
01724                 const double sx = d_data->size.width() / sz.width();
01725                 const double sy = d_data->size.height() / sz.height();
01726 
01727                 QTransform transform;
01728                 transform.scale( sx, sy );
01729 
01730                 rect = transform.mapRect( rect );
01731             }
01732             pinPointTranslation = true;
01733             break;
01734         }
01735 #endif
01736         default:
01737         {
01738             rect.setSize( d_data->size );
01739             rect.moveCenter( QPointF( 0.0, 0.0 ) );
01740         }
01741     }
01742 
01743     if ( pinPointTranslation )
01744     {
01745         QPointF pinPoint( 0.0, 0.0 );
01746         if ( d_data->isPinPointEnabled )
01747             pinPoint = rect.center() - d_data->pinPoint;
01748 
01749         rect.moveCenter( pinPoint );
01750     }
01751 
01752     QRect r;
01753     r.setLeft( qFloor( rect.left() ) );
01754     r.setTop( qFloor( rect.top() ) );
01755     r.setRight( qCeil( rect.right() ) );
01756     r.setBottom( qCeil( rect.bottom() ) );
01757 
01758     if ( d_data->style != QwtSymbol::Pixmap )
01759         r.adjust( -1, -1, 1, 1 ); // for antialiasing
01760 
01761     return r;
01762 }
01763 
01775 void QwtSymbol::invalidateCache()
01776 {
01777     if ( !d_data->cache.pixmap.isNull() )
01778         d_data->cache.pixmap = QPixmap();
01779 }
01780 
01787 void QwtSymbol::setStyle( QwtSymbol::Style style )
01788 {
01789     if ( d_data->style != style )
01790     {
01791         d_data->style = style;
01792         invalidateCache();
01793     }
01794 }
01795 
01800 QwtSymbol::Style QwtSymbol::style() const
01801 {
01802     return d_data->style;
01803 }


plotjuggler
Author(s): Davide Faconti
autogenerated on Fri Sep 1 2017 02:41:57