00001
00002
00003
00004
00005
00006
00007
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;
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;
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;
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;
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
01315
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
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
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
01358
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
01370
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
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 );
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 }