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 <qsvgrenderer.h>
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 if ( d_data->cache.pixmap.isNull() )
01394 {
01395 d_data->cache.pixmap = QwtPainter::backingStore( NULL, br.size() );
01396 d_data->cache.pixmap.fill( Qt::transparent );
01397
01398 QPainter p( &d_data->cache.pixmap );
01399 p.setRenderHints( painter->renderHints() );
01400 p.translate( -br.topLeft() );
01401
01402 const QPointF pos( 0.0, 0.0 );
01403 renderSymbols( &p, &pos, 1 );
01404 }
01405
01406 const int dx = br.left();
01407 const int dy = br.top();
01408
01409 for ( int i = 0; i < numPoints; i++ )
01410 {
01411 const int left = qRound( points[i].x() ) + dx;
01412 const int top = qRound( points[i].y() ) + dy;
01413
01414 painter->drawPixmap( left, top, d_data->cache.pixmap );
01415 }
01416 }
01417 else
01418 {
01419 painter->save();
01420 renderSymbols( painter, points, numPoints );
01421 painter->restore();
01422 }
01423 }
01424
01437 void QwtSymbol::drawSymbol( QPainter *painter, const QRectF &rect ) const
01438 {
01439 if ( d_data->style == QwtSymbol::NoSymbol )
01440 return;
01441
01442 if ( d_data->style == QwtSymbol::Graphic )
01443 {
01444 d_data->graphic.graphic.render(
01445 painter, rect, Qt::KeepAspectRatio );
01446 }
01447 else if ( d_data->style == QwtSymbol::Path )
01448 {
01449 if ( d_data->path.graphic.isNull() )
01450 {
01451 d_data->path.graphic = qwtPathGraphic(
01452 d_data->path.path, d_data->pen, d_data->brush );
01453 }
01454
01455 d_data->path.graphic.render(
01456 painter, rect, Qt::KeepAspectRatio );
01457 return;
01458 }
01459 else if ( d_data->style == QwtSymbol::SvgDocument )
01460 {
01461 #ifndef QWT_NO_SVG
01462 if ( d_data->svg.renderer )
01463 {
01464 QRectF scaledRect;
01465
01466 QSizeF sz = d_data->svg.renderer->viewBoxF().size();
01467 if ( !sz.isEmpty() )
01468 {
01469 sz.scale( rect.size(), Qt::KeepAspectRatio );
01470 scaledRect.setSize( sz );
01471 scaledRect.moveCenter( rect.center() );
01472 }
01473 else
01474 {
01475 scaledRect = rect;
01476 }
01477
01478 d_data->svg.renderer->render(
01479 painter, scaledRect );
01480 }
01481 #endif
01482 }
01483 else
01484 {
01485 const QRect br = boundingRect();
01486
01487
01488
01489 const double ratio = qMin( rect.width() / br.width(),
01490 rect.height() / br.height() );
01491
01492 painter->save();
01493
01494 painter->translate( rect.center() );
01495 painter->scale( ratio, ratio );
01496
01497 const bool isPinPointEnabled = d_data->isPinPointEnabled;
01498 d_data->isPinPointEnabled = false;
01499
01500 const QPointF pos;
01501 renderSymbols( painter, &pos, 1 );
01502
01503 d_data->isPinPointEnabled = isPinPointEnabled;
01504
01505 painter->restore();
01506 }
01507 }
01508
01516 void QwtSymbol::renderSymbols( QPainter *painter,
01517 const QPointF *points, int numPoints ) const
01518 {
01519 switch ( d_data->style )
01520 {
01521 case QwtSymbol::Ellipse:
01522 {
01523 qwtDrawEllipseSymbols( painter, points, numPoints, *this );
01524 break;
01525 }
01526 case QwtSymbol::Rect:
01527 {
01528 qwtDrawRectSymbols( painter, points, numPoints, *this );
01529 break;
01530 }
01531 case QwtSymbol::Diamond:
01532 {
01533 qwtDrawDiamondSymbols( painter, points, numPoints, *this );
01534 break;
01535 }
01536 case QwtSymbol::Cross:
01537 {
01538 qwtDrawLineSymbols( painter, Qt::Horizontal | Qt::Vertical,
01539 points, numPoints, *this );
01540 break;
01541 }
01542 case QwtSymbol::XCross:
01543 {
01544 qwtDrawXCrossSymbols( painter, points, numPoints, *this );
01545 break;
01546 }
01547 case QwtSymbol::Triangle:
01548 case QwtSymbol::UTriangle:
01549 {
01550 qwtDrawTriangleSymbols( painter, QwtTriangle::Up,
01551 points, numPoints, *this );
01552 break;
01553 }
01554 case QwtSymbol::DTriangle:
01555 {
01556 qwtDrawTriangleSymbols( painter, QwtTriangle::Down,
01557 points, numPoints, *this );
01558 break;
01559 }
01560 case QwtSymbol::RTriangle:
01561 {
01562 qwtDrawTriangleSymbols( painter, QwtTriangle::Right,
01563 points, numPoints, *this );
01564 break;
01565 }
01566 case QwtSymbol::LTriangle:
01567 {
01568 qwtDrawTriangleSymbols( painter, QwtTriangle::Left,
01569 points, numPoints, *this );
01570 break;
01571 }
01572 case QwtSymbol::HLine:
01573 {
01574 qwtDrawLineSymbols( painter, Qt::Horizontal,
01575 points, numPoints, *this );
01576 break;
01577 }
01578 case QwtSymbol::VLine:
01579 {
01580 qwtDrawLineSymbols( painter, Qt::Vertical,
01581 points, numPoints, *this );
01582 break;
01583 }
01584 case QwtSymbol::Star1:
01585 {
01586 qwtDrawStar1Symbols( painter, points, numPoints, *this );
01587 break;
01588 }
01589 case QwtSymbol::Star2:
01590 {
01591 qwtDrawStar2Symbols( painter, points, numPoints, *this );
01592 break;
01593 }
01594 case QwtSymbol::Hexagon:
01595 {
01596 qwtDrawHexagonSymbols( painter, points, numPoints, *this );
01597 break;
01598 }
01599 case QwtSymbol::Path:
01600 {
01601 if ( d_data->path.graphic.isNull() )
01602 {
01603 d_data->path.graphic = qwtPathGraphic( d_data->path.path,
01604 d_data->pen, d_data->brush );
01605 }
01606
01607 qwtDrawGraphicSymbols( painter, points, numPoints,
01608 d_data->path.graphic, *this );
01609 break;
01610 }
01611 case QwtSymbol::Pixmap:
01612 {
01613 qwtDrawPixmapSymbols( painter, points, numPoints, *this );
01614 break;
01615 }
01616 case QwtSymbol::Graphic:
01617 {
01618 qwtDrawGraphicSymbols( painter, points, numPoints,
01619 d_data->graphic.graphic, *this );
01620 break;
01621 }
01622 case QwtSymbol::SvgDocument:
01623 {
01624 #ifndef QWT_NO_SVG
01625 qwtDrawSvgSymbols( painter, points, numPoints,
01626 d_data->svg.renderer, *this );
01627 #endif
01628 break;
01629 }
01630 default:;
01631 }
01632 }
01633
01640 QRect QwtSymbol::boundingRect() const
01641 {
01642 QRectF rect;
01643
01644 bool pinPointTranslation = false;
01645
01646 switch ( d_data->style )
01647 {
01648 case QwtSymbol::Ellipse:
01649 case QwtSymbol::Rect:
01650 case QwtSymbol::Hexagon:
01651 {
01652 qreal pw = 0.0;
01653 if ( d_data->pen.style() != Qt::NoPen )
01654 pw = qMax( d_data->pen.widthF(), qreal( 1.0 ) );
01655
01656 rect.setSize( d_data->size + QSizeF( pw, pw ) );
01657 rect.moveCenter( QPointF( 0.0, 0.0 ) );
01658
01659 break;
01660 }
01661 case QwtSymbol::XCross:
01662 case QwtSymbol::Diamond:
01663 case QwtSymbol::Triangle:
01664 case QwtSymbol::UTriangle:
01665 case QwtSymbol::DTriangle:
01666 case QwtSymbol::RTriangle:
01667 case QwtSymbol::LTriangle:
01668 case QwtSymbol::Star1:
01669 case QwtSymbol::Star2:
01670 {
01671 qreal pw = 0.0;
01672 if ( d_data->pen.style() != Qt::NoPen )
01673 pw = qMax( d_data->pen.widthF(), qreal( 1.0 ) );
01674
01675 rect.setSize( d_data->size + QSizeF( 2 * pw, 2 * pw ) );
01676 rect.moveCenter( QPointF( 0.0, 0.0 ) );
01677 break;
01678 }
01679 case QwtSymbol::Path:
01680 {
01681 if ( d_data->path.graphic.isNull() )
01682 {
01683 d_data->path.graphic = qwtPathGraphic(
01684 d_data->path.path, d_data->pen, d_data->brush );
01685 }
01686
01687 rect = qwtScaledBoundingRect(
01688 d_data->path.graphic, d_data->size );
01689 pinPointTranslation = true;
01690
01691 break;
01692 }
01693 case QwtSymbol::Pixmap:
01694 {
01695 if ( d_data->size.isEmpty() )
01696 rect.setSize( d_data->pixmap.pixmap.size() );
01697 else
01698 rect.setSize( d_data->size );
01699
01700 pinPointTranslation = true;
01701
01702 break;
01703 }
01704 case QwtSymbol::Graphic:
01705 {
01706 rect = qwtScaledBoundingRect(
01707 d_data->graphic.graphic, d_data->size );
01708 pinPointTranslation = true;
01709
01710 break;
01711 }
01712 #ifndef QWT_NO_SVG
01713 case QwtSymbol::SvgDocument:
01714 {
01715 if ( d_data->svg.renderer )
01716 rect = d_data->svg.renderer->viewBoxF();
01717
01718 if ( d_data->size.isValid() && !rect.isEmpty() )
01719 {
01720 QSizeF sz = rect.size();
01721
01722 const double sx = d_data->size.width() / sz.width();
01723 const double sy = d_data->size.height() / sz.height();
01724
01725 QTransform transform;
01726 transform.scale( sx, sy );
01727
01728 rect = transform.mapRect( rect );
01729 }
01730 pinPointTranslation = true;
01731 break;
01732 }
01733 #endif
01734 default:
01735 {
01736 rect.setSize( d_data->size );
01737 rect.moveCenter( QPointF( 0.0, 0.0 ) );
01738 }
01739 }
01740
01741 if ( pinPointTranslation )
01742 {
01743 QPointF pinPoint( 0.0, 0.0 );
01744 if ( d_data->isPinPointEnabled )
01745 pinPoint = rect.center() - d_data->pinPoint;
01746
01747 rect.moveCenter( pinPoint );
01748 }
01749
01750 QRect r;
01751 r.setLeft( qFloor( rect.left() ) );
01752 r.setTop( qFloor( rect.top() ) );
01753 r.setRight( qCeil( rect.right() ) );
01754 r.setBottom( qCeil( rect.bottom() ) );
01755
01756 if ( d_data->style != QwtSymbol::Pixmap )
01757 r.adjust( -1, -1, 1, 1 );
01758
01759 return r;
01760 }
01761
01773 void QwtSymbol::invalidateCache()
01774 {
01775 if ( !d_data->cache.pixmap.isNull() )
01776 d_data->cache.pixmap = QPixmap();
01777 }
01778
01785 void QwtSymbol::setStyle( QwtSymbol::Style style )
01786 {
01787 if ( d_data->style != style )
01788 {
01789 d_data->style = style;
01790 invalidateCache();
01791 }
01792 }
01793
01798 QwtSymbol::Style QwtSymbol::style() const
01799 {
01800 return d_data->style;
01801 }