Qwt User's Guide 6.3.0
Loading...
Searching...
No Matches
qwt_symbol.cpp
1/******************************************************************************
2 * Qwt Widget Library
3 * Copyright (C) 1997 Josef Wilgen
4 * Copyright (C) 2002 Uwe Rathmann
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the Qwt License, Version 1.0
8 *****************************************************************************/
9
10#include "qwt_symbol.h"
11#include "qwt_painter.h"
12#include "qwt_graphic.h"
13#include "qwt_math.h"
14
15#include <qpainter.h>
16#include <qpainterpath.h>
17#include <qpixmap.h>
18#include <qpaintengine.h>
19#ifndef QWT_NO_SVG
20#include <qsvgrenderer.h>
21#endif
22
23namespace QwtTriangle
24{
25 enum Type
26 {
27 Left,
28 Right,
29 Up,
30 Down
31 };
32}
33
34static QwtGraphic qwtPathGraphic( const QPainterPath& path,
35 const QPen& pen, const QBrush& brush )
36{
37 QwtGraphic graphic;
39
40 QPainter painter( &graphic );
41 painter.setPen( pen );
42 painter.setBrush( brush );
43 painter.drawPath( path );
44 painter.end();
45
46 return graphic;
47}
48
49static inline QRectF qwtScaledBoundingRect(
50 const QwtGraphic& graphic, const QSizeF size )
51{
52 QSizeF scaledSize = size;
53 if ( scaledSize.isEmpty() )
54 scaledSize = graphic.defaultSize();
55
56 const QSizeF sz = graphic.controlPointRect().size();
57
58 double sx = 1.0;
59 if ( sz.width() > 0.0 )
60 sx = scaledSize.width() / sz.width();
61
62 double sy = 1.0;
63 if ( sz.height() > 0.0 )
64 sy = scaledSize.height() / sz.height();
65
66 return graphic.scaledBoundingRect( sx, sy );
67}
68
69static inline void qwtDrawPixmapSymbols( QPainter* painter,
70 const QPointF* points, int numPoints, const QwtSymbol& symbol )
71{
72 QSize size = symbol.size();
73 if ( size.isEmpty() )
74 size = symbol.pixmap().size();
75
76 const QTransform transform = painter->transform();
77 if ( transform.isScaling() )
78 {
79 const QRect r( 0, 0, size.width(), size.height() );
80 size = transform.mapRect( r ).size();
81 }
82
83 QPixmap pm = symbol.pixmap();
84 if ( pm.size() != size )
85 pm = pm.scaled( size );
86
87 QPointF pinPoint( 0.5 * size.width(), 0.5 * size.height() );
88 if ( symbol.isPinPointEnabled() )
89 pinPoint = symbol.pinPoint();
90
91 painter->resetTransform();
92
93 for ( int i = 0; i < numPoints; i++ )
94 {
95 const QPointF pos = transform.map( points[i] ) - pinPoint;
96
98 QRect( pos.toPoint(), pm.size() ), pm );
99 }
100}
101
102#ifndef QWT_NO_SVG
103
104static inline void qwtDrawSvgSymbols( QPainter* painter,
105 const QPointF* points, int numPoints,
106 QSvgRenderer* renderer, const QwtSymbol& symbol )
107{
108 if ( renderer == NULL || !renderer->isValid() )
109 return;
110
111 const QRectF viewBox = renderer->viewBoxF();
112 if ( viewBox.isEmpty() )
113 return;
114
115 QSizeF sz = symbol.size();
116 if ( !sz.isValid() )
117 sz = viewBox.size();
118
119 const double sx = sz.width() / viewBox.width();
120 const double sy = sz.height() / viewBox.height();
121
122 QPointF pinPoint = viewBox.center();
123 if ( symbol.isPinPointEnabled() )
124 pinPoint = symbol.pinPoint();
125
126 const double dx = sx * ( pinPoint.x() - viewBox.left() );
127 const double dy = sy * ( pinPoint.y() - viewBox.top() );
128
129 for ( int i = 0; i < numPoints; i++ )
130 {
131 const double x = points[i].x() - dx;
132 const double y = points[i].y() - dy;
133
134 renderer->render( painter,
135 QRectF( x, y, sz.width(), sz.height() ) );
136 }
137}
138
139#endif
140
141static inline void qwtDrawGraphicSymbols( QPainter* painter,
142 const QPointF* points, int numPoints, const QwtGraphic& graphic,
143 const QwtSymbol& symbol )
144{
145 const QRectF pointRect = graphic.controlPointRect();
146 if ( pointRect.isEmpty() )
147 return;
148
149 double sx = 1.0;
150 double sy = 1.0;
151
152 const QSize sz = symbol.size();
153 if ( sz.isValid() )
154 {
155 sx = sz.width() / pointRect.width();
156 sy = sz.height() / pointRect.height();
157 }
158
159 QPointF pinPoint = pointRect.center();
160 if ( symbol.isPinPointEnabled() )
161 pinPoint = symbol.pinPoint();
162
163 const QTransform transform = painter->transform();
164
165 for ( int i = 0; i < numPoints; i++ )
166 {
167 QTransform tr = transform;
168 tr.translate( points[i].x(), points[i].y() );
169 tr.scale( sx, sy );
170 tr.translate( -pinPoint.x(), -pinPoint.y() );
171
172 painter->setTransform( tr );
173
174 graphic.render( painter );
175 }
176
177 painter->setTransform( transform );
178}
179
180static inline void qwtDrawEllipseSymbols( QPainter* painter,
181 const QPointF* points, int numPoints, const QwtSymbol& symbol )
182{
183 painter->setBrush( symbol.brush() );
184 painter->setPen( symbol.pen() );
185
186 const QSize size = symbol.size();
187
188 if ( QwtPainter::roundingAlignment( painter ) )
189 {
190 const int sw = size.width();
191 const int sh = size.height();
192 const int sw2 = size.width() / 2;
193 const int sh2 = size.height() / 2;
194
195 for ( int i = 0; i < numPoints; i++ )
196 {
197 const int x = qRound( points[i].x() );
198 const int y = qRound( points[i].y() );
199
200 const QRectF r( x - sw2, y - sh2, sw, sh );
201 QwtPainter::drawEllipse( painter, r );
202 }
203 }
204 else
205 {
206 const double sw = size.width();
207 const double sh = size.height();
208 const double sw2 = 0.5 * size.width();
209 const double sh2 = 0.5 * size.height();
210
211 for ( int i = 0; i < numPoints; i++ )
212 {
213 const double x = points[i].x();
214 const double y = points[i].y();
215
216 const QRectF r( x - sw2, y - sh2, sw, sh );
217 QwtPainter::drawEllipse( painter, r );
218 }
219 }
220}
221
222static inline void qwtDrawRectSymbols( QPainter* painter,
223 const QPointF* points, int numPoints, const QwtSymbol& symbol )
224{
225 const QSize size = symbol.size();
226
227 QPen pen = symbol.pen();
228 pen.setJoinStyle( Qt::MiterJoin );
229 painter->setPen( pen );
230 painter->setBrush( symbol.brush() );
231 painter->setRenderHint( QPainter::Antialiasing, false );
232
233 if ( QwtPainter::roundingAlignment( painter ) )
234 {
235 const int sw = size.width();
236 const int sh = size.height();
237 const int sw2 = size.width() / 2;
238 const int sh2 = size.height() / 2;
239
240 for ( int i = 0; i < numPoints; i++ )
241 {
242 const int x = qRound( points[i].x() );
243 const int y = qRound( points[i].y() );
244
245 const QRect r( x - sw2, y - sh2, sw, sh );
246 QwtPainter::drawRect( painter, r );
247 }
248 }
249 else
250 {
251 const double sw = size.width();
252 const double sh = size.height();
253 const double sw2 = 0.5 * size.width();
254 const double sh2 = 0.5 * size.height();
255
256 for ( int i = 0; i < numPoints; i++ )
257 {
258 const double x = points[i].x();
259 const double y = points[i].y();
260
261 const QRectF r( x - sw2, y - sh2, sw, sh );
262 QwtPainter::drawRect( painter, r );
263 }
264 }
265}
266
267static inline void qwtDrawDiamondSymbols( QPainter* painter,
268 const QPointF* points, int numPoints, const QwtSymbol& symbol )
269{
270 const QSize size = symbol.size();
271
272 QPen pen = symbol.pen();
273 pen.setJoinStyle( Qt::MiterJoin );
274 painter->setPen( pen );
275 painter->setBrush( symbol.brush() );
276
277 if ( QwtPainter::roundingAlignment( painter ) )
278 {
279 for ( int i = 0; i < numPoints; i++ )
280 {
281 const int x = qRound( points[i].x() );
282 const int y = qRound( points[i].y() );
283
284 const int x1 = x - size.width() / 2;
285 const int y1 = y - size.height() / 2;
286 const int x2 = x1 + size.width();
287 const int y2 = y1 + size.height();
288
289 QPolygonF polygon;
290 polygon += QPointF( x, y1 );
291 polygon += QPointF( x1, y );
292 polygon += QPointF( x, y2 );
293 polygon += QPointF( x2, y );
294
295 QwtPainter::drawPolygon( painter, polygon );
296 }
297 }
298 else
299 {
300 for ( int i = 0; i < numPoints; i++ )
301 {
302 const QPointF& pos = points[i];
303
304 const double x1 = pos.x() - 0.5 * size.width();
305 const double y1 = pos.y() - 0.5 * size.height();
306 const double x2 = x1 + size.width();
307 const double y2 = y1 + size.height();
308
309 QPolygonF polygon;
310 polygon += QPointF( pos.x(), y1 );
311 polygon += QPointF( x2, pos.y() );
312 polygon += QPointF( pos.x(), y2 );
313 polygon += QPointF( x1, pos.y() );
314
315 QwtPainter::drawPolygon( painter, polygon );
316 }
317 }
318}
319
320static inline void qwtDrawTriangleSymbols(
321 QPainter* painter, QwtTriangle::Type type,
322 const QPointF* points, int numPoints,
323 const QwtSymbol& symbol )
324{
325 const QSize size = symbol.size();
326
327 QPen pen = symbol.pen();
328 pen.setJoinStyle( Qt::MiterJoin );
329 painter->setPen( pen );
330
331 painter->setBrush( symbol.brush() );
332
333 const bool doAlign = QwtPainter::roundingAlignment( painter );
334
335 double sw2 = 0.5 * size.width();
336 double sh2 = 0.5 * size.height();
337
338 if ( doAlign )
339 {
340 sw2 = std::floor( sw2 );
341 sh2 = std::floor( sh2 );
342 }
343
344 QPolygonF triangle( 3 );
345 QPointF* trianglePoints = triangle.data();
346
347 for ( int i = 0; i < numPoints; i++ )
348 {
349 const QPointF& pos = points[i];
350
351 double x = pos.x();
352 double y = pos.y();
353
354 if ( doAlign )
355 {
356 x = qRound( x );
357 y = qRound( y );
358 }
359
360 const double x1 = x - sw2;
361 const double x2 = x1 + size.width();
362 const double y1 = y - sh2;
363 const double y2 = y1 + size.height();
364
365 switch ( type )
366 {
367 case QwtTriangle::Left:
368 {
369 trianglePoints[0].rx() = x2;
370 trianglePoints[0].ry() = y1;
371
372 trianglePoints[1].rx() = x1;
373 trianglePoints[1].ry() = y;
374
375 trianglePoints[2].rx() = x2;
376 trianglePoints[2].ry() = y2;
377
378 break;
379 }
380 case QwtTriangle::Right:
381 {
382 trianglePoints[0].rx() = x1;
383 trianglePoints[0].ry() = y1;
384
385 trianglePoints[1].rx() = x2;
386 trianglePoints[1].ry() = y;
387
388 trianglePoints[2].rx() = x1;
389 trianglePoints[2].ry() = y2;
390
391 break;
392 }
393 case QwtTriangle::Up:
394 {
395 trianglePoints[0].rx() = x1;
396 trianglePoints[0].ry() = y2;
397
398 trianglePoints[1].rx() = x;
399 trianglePoints[1].ry() = y1;
400
401 trianglePoints[2].rx() = x2;
402 trianglePoints[2].ry() = y2;
403
404 break;
405 }
406 case QwtTriangle::Down:
407 {
408 trianglePoints[0].rx() = x1;
409 trianglePoints[0].ry() = y1;
410
411 trianglePoints[1].rx() = x;
412 trianglePoints[1].ry() = y2;
413
414 trianglePoints[2].rx() = x2;
415 trianglePoints[2].ry() = y1;
416
417 break;
418 }
419 }
420 QwtPainter::drawPolygon( painter, triangle );
421 }
422}
423
424static inline void qwtDrawLineSymbols(
425 QPainter* painter, int orientations,
426 const QPointF* points, int numPoints, const QwtSymbol& symbol )
427{
428 const QSize size = symbol.size();
429
430 int off = 0;
431
432 QPen pen = symbol.pen();
433 if ( pen.width() > 1 )
434 {
435 pen.setCapStyle( Qt::FlatCap );
436 off = 1;
437 }
438
439 painter->setPen( pen );
440 painter->setRenderHint( QPainter::Antialiasing, false );
441
442 if ( QwtPainter::roundingAlignment( painter ) )
443 {
444 const int sw = qwtFloor( size.width() );
445 const int sh = qwtFloor( size.height() );
446 const int sw2 = size.width() / 2;
447 const int sh2 = size.height() / 2;
448
449 for ( int i = 0; i < numPoints; i++ )
450 {
451 if ( orientations & Qt::Horizontal )
452 {
453 const int x = qRound( points[i].x() ) - sw2;
454 const int y = qRound( points[i].y() );
455
456 QwtPainter::drawLine( painter, x, y, x + sw + off, y );
457 }
458 if ( orientations & Qt::Vertical )
459 {
460 const int x = qRound( points[i].x() );
461 const int y = qRound( points[i].y() ) - sh2;
462
463 QwtPainter::drawLine( painter, x, y, x, y + sh + off );
464 }
465 }
466 }
467 else
468 {
469 const double sw = size.width();
470 const double sh = size.height();
471 const double sw2 = 0.5 * size.width();
472 const double sh2 = 0.5 * size.height();
473
474 for ( int i = 0; i < numPoints; i++ )
475 {
476 if ( orientations & Qt::Horizontal )
477 {
478 const double x = points[i].x() - sw2;
479 const double y = points[i].y();
480
481 QwtPainter::drawLine( painter, x, y, x + sw, y );
482 }
483 if ( orientations & Qt::Vertical )
484 {
485 const double y = points[i].y() - sh2;
486 const double x = points[i].x();
487
488 QwtPainter::drawLine( painter, x, y, x, y + sh );
489 }
490 }
491 }
492}
493
494static inline void qwtDrawXCrossSymbols( QPainter* painter,
495 const QPointF* points, int numPoints, const QwtSymbol& symbol )
496{
497 const QSize size = symbol.size();
498 int off = 0;
499
500 QPen pen = symbol.pen();
501 if ( pen.width() > 1 )
502 {
503 pen.setCapStyle( Qt::FlatCap );
504 off = 1;
505 }
506 painter->setPen( pen );
507
508
509 if ( QwtPainter::roundingAlignment( painter ) )
510 {
511 const int sw = size.width();
512 const int sh = size.height();
513 const int sw2 = size.width() / 2;
514 const int sh2 = size.height() / 2;
515
516 for ( int i = 0; i < numPoints; i++ )
517 {
518 const QPointF& pos = points[i];
519
520 const int x = qRound( pos.x() );
521 const int y = qRound( pos.y() );
522
523 const int x1 = x - sw2;
524 const int x2 = x1 + sw + off;
525 const int y1 = y - sh2;
526 const int y2 = y1 + sh + off;
527
528 QwtPainter::drawLine( painter, x1, y1, x2, y2 );
529 QwtPainter::drawLine( painter, x2, y1, x1, y2 );
530 }
531 }
532 else
533 {
534 const double sw = size.width();
535 const double sh = size.height();
536 const double sw2 = 0.5 * size.width();
537 const double sh2 = 0.5 * size.height();
538
539 for ( int i = 0; i < numPoints; i++ )
540 {
541 const QPointF& pos = points[i];
542
543 const double x1 = pos.x() - sw2;
544 const double x2 = x1 + sw;
545 const double y1 = pos.y() - sh2;
546 const double y2 = y1 + sh;
547
548 QwtPainter::drawLine( painter, x1, y1, x2, y2 );
549 QwtPainter::drawLine( painter, x1, y2, x2, y1 );
550 }
551 }
552}
553
554static inline void qwtDrawStar1Symbols( QPainter* painter,
555 const QPointF* points, int numPoints, const QwtSymbol& symbol )
556{
557 const QSize size = symbol.size();
558 painter->setPen( symbol.pen() );
559
560 if ( QwtPainter::roundingAlignment( painter ) )
561 {
562 QRect r( 0, 0, size.width(), size.height() );
563
564 for ( int i = 0; i < numPoints; i++ )
565 {
566 r.moveCenter( points[i].toPoint() );
567
568 const double sqrt1_2 = 0.70710678118654752440; /* 1/sqrt(2) */
569
570 const double d1 = r.width() / 2.0 * ( 1.0 - sqrt1_2 );
571
572 QwtPainter::drawLine( painter,
573 qRound( r.left() + d1 ), qRound( r.top() + d1 ),
574 qRound( r.right() - d1 ), qRound( r.bottom() - d1 ) );
575 QwtPainter::drawLine( painter,
576 qRound( r.left() + d1 ), qRound( r.bottom() - d1 ),
577 qRound( r.right() - d1), qRound( r.top() + d1 ) );
578
579 const QPoint c = r.center();
580
581 QwtPainter::drawLine( painter,
582 c.x(), r.top(), c.x(), r.bottom() );
583 QwtPainter::drawLine( painter,
584 r.left(), c.y(), r.right(), c.y() );
585 }
586 }
587 else
588 {
589 QRectF r( 0, 0, size.width(), size.height() );
590
591 for ( int i = 0; i < numPoints; i++ )
592 {
593 r.moveCenter( points[i] );
594
595 const double sqrt1_2 = 0.70710678118654752440; /* 1/sqrt(2) */
596
597 const QPointF c = r.center();
598 const double d1 = r.width() / 2.0 * ( 1.0 - sqrt1_2 );
599
600 QwtPainter::drawLine( painter,
601 r.left() + d1, r.top() + d1,
602 r.right() - d1, r.bottom() - d1 );
603 QwtPainter::drawLine( painter,
604 r.left() + d1, r.bottom() - d1,
605 r.right() - d1, r.top() + d1 );
606 QwtPainter::drawLine( painter,
607 c.x(), r.top(),
608 c.x(), r.bottom() );
609 QwtPainter::drawLine( painter,
610 r.left(), c.y(),
611 r.right(), c.y() );
612 }
613 }
614}
615
616static inline void qwtDrawStar2Symbols( QPainter* painter,
617 const QPointF* points, int numPoints, const QwtSymbol& symbol )
618{
619 QPen pen = symbol.pen();
620 if ( pen.width() > 1 )
621 pen.setCapStyle( Qt::FlatCap );
622 pen.setJoinStyle( Qt::MiterJoin );
623 painter->setPen( pen );
624
625 painter->setBrush( symbol.brush() );
626
627 const double cos30 = 0.866025; // cos(30°)
628
629 const double dy = 0.25 * symbol.size().height();
630 const double dx = 0.5 * symbol.size().width() * cos30 / 3.0;
631
632 QPolygonF star( 12 );
633 QPointF* starPoints = star.data();
634
635 const bool doAlign = QwtPainter::roundingAlignment( painter );
636
637 for ( int i = 0; i < numPoints; i++ )
638 {
639 double x = points[i].x();
640 double y = points[i].y();
641 if ( doAlign )
642 {
643 x = qRound( x );
644 y = qRound( y );
645 }
646
647 double x1 = x - 3 * dx;
648 double y1 = y - 2 * dy;
649 if ( doAlign )
650 {
651 x1 = qRound( x - 3 * dx );
652 y1 = qRound( y - 2 * dy );
653 }
654
655 const double x2 = x1 + 1 * dx;
656 const double x3 = x1 + 2 * dx;
657 const double x4 = x1 + 3 * dx;
658 const double x5 = x1 + 4 * dx;
659 const double x6 = x1 + 5 * dx;
660 const double x7 = x1 + 6 * dx;
661
662 const double y2 = y1 + 1 * dy;
663 const double y3 = y1 + 2 * dy;
664 const double y4 = y1 + 3 * dy;
665 const double y5 = y1 + 4 * dy;
666
667 starPoints[0].rx() = x4;
668 starPoints[0].ry() = y1;
669
670 starPoints[1].rx() = x5;
671 starPoints[1].ry() = y2;
672
673 starPoints[2].rx() = x7;
674 starPoints[2].ry() = y2;
675
676 starPoints[3].rx() = x6;
677 starPoints[3].ry() = y3;
678
679 starPoints[4].rx() = x7;
680 starPoints[4].ry() = y4;
681
682 starPoints[5].rx() = x5;
683 starPoints[5].ry() = y4;
684
685 starPoints[6].rx() = x4;
686 starPoints[6].ry() = y5;
687
688 starPoints[7].rx() = x3;
689 starPoints[7].ry() = y4;
690
691 starPoints[8].rx() = x1;
692 starPoints[8].ry() = y4;
693
694 starPoints[9].rx() = x2;
695 starPoints[9].ry() = y3;
696
697 starPoints[10].rx() = x1;
698 starPoints[10].ry() = y2;
699
700 starPoints[11].rx() = x3;
701 starPoints[11].ry() = y2;
702
703 QwtPainter::drawPolygon( painter, star );
704 }
705}
706
707static inline void qwtDrawHexagonSymbols( QPainter* painter,
708 const QPointF* points, int numPoints, const QwtSymbol& symbol )
709{
710 painter->setBrush( symbol.brush() );
711 painter->setPen( symbol.pen() );
712
713 const double cos30 = 0.866025; // cos(30°)
714 const double dx = 0.5 * ( symbol.size().width() - cos30 );
715
716 const double dy = 0.25 * symbol.size().height();
717
718 QPolygonF hexaPolygon( 6 );
719 QPointF* hexaPoints = hexaPolygon.data();
720
721 const bool doAlign = QwtPainter::roundingAlignment( painter );
722
723 for ( int i = 0; i < numPoints; i++ )
724 {
725 double x = points[i].x();
726 double y = points[i].y();
727 if ( doAlign )
728 {
729 x = qRound( x );
730 y = qRound( y );
731 }
732
733 double x1 = x - dx;
734 double y1 = y - 2 * dy;
735 if ( doAlign )
736 {
737 x1 = std::ceil( x1 );
738 y1 = std::ceil( y1 );
739 }
740
741 const double x2 = x1 + 1 * dx;
742 const double x3 = x1 + 2 * dx;
743
744 const double y2 = y1 + 1 * dy;
745 const double y3 = y1 + 3 * dy;
746 const double y4 = y1 + 4 * dy;
747
748 hexaPoints[0].rx() = x2;
749 hexaPoints[0].ry() = y1;
750
751 hexaPoints[1].rx() = x3;
752 hexaPoints[1].ry() = y2;
753
754 hexaPoints[2].rx() = x3;
755 hexaPoints[2].ry() = y3;
756
757 hexaPoints[3].rx() = x2;
758 hexaPoints[3].ry() = y4;
759
760 hexaPoints[4].rx() = x1;
761 hexaPoints[4].ry() = y3;
762
763 hexaPoints[5].rx() = x1;
764 hexaPoints[5].ry() = y2;
765
766 QwtPainter::drawPolygon( painter, hexaPolygon );
767 }
768}
769
770class QwtSymbol::PrivateData
771{
772 public:
773 PrivateData( QwtSymbol::Style st, const QBrush& br,
774 const QPen& pn, const QSize& sz )
775 : style( st )
776 , size( sz )
777 , brush( br )
778 , pen( pn )
779 , isPinPointEnabled( false )
780 {
781 cache.policy = QwtSymbol::AutoCache;
782#ifndef QWT_NO_SVG
783 svg.renderer = NULL;
784#endif
785 }
786
787 ~PrivateData()
788 {
789#ifndef QWT_NO_SVG
790 delete svg.renderer;
791#endif
792 }
793
794 Style style;
795 QSize size;
796 QBrush brush;
797 QPen pen;
798
799 bool isPinPointEnabled;
800 QPointF pinPoint;
801
802 struct Path
803 {
804 QPainterPath path;
805 QwtGraphic graphic;
806
807 } path;
808
809 struct Pixmap
810 {
811 QPixmap pixmap;
812
813 } pixmap;
814
815 struct Graphic
816 {
817 QwtGraphic graphic;
818
819 } graphic;
820
821#ifndef QWT_NO_SVG
822 struct SVG
823 {
824 QSvgRenderer* renderer;
825 } svg;
826#endif
827
828 struct PaintCache
829 {
831 QPixmap pixmap;
832
833 } cache;
834};
835
844{
845 m_data = new PrivateData( style, QBrush( Qt::gray ),
846 QPen( Qt::black, 0 ), QSize() );
847}
848
858QwtSymbol::QwtSymbol( QwtSymbol::Style style, const QBrush& brush,
859 const QPen& pen, const QSize& size )
860{
861 m_data = new PrivateData( style, brush, pen, size );
862}
863
878QwtSymbol::QwtSymbol( const QPainterPath& path,
879 const QBrush& brush, const QPen& pen )
880{
881 m_data = new PrivateData( QwtSymbol::Path, brush, pen, QSize() );
882 setPath( path );
883}
884
887{
888 delete m_data;
889}
890
901{
902 if ( m_data->cache.policy != policy )
903 {
904 m_data->cache.policy = policy;
906 }
907}
908
914{
915 return m_data->cache.policy;
916}
917
966void QwtSymbol::setPath( const QPainterPath& path )
967{
968 m_data->style = QwtSymbol::Path;
969 m_data->path.path = path;
970 m_data->path.graphic.reset();
971}
972
977const QPainterPath& QwtSymbol::path() const
978{
979 return m_data->path.path;
980}
981
992void QwtSymbol::setPixmap( const QPixmap& pixmap )
993{
994 m_data->style = QwtSymbol::Pixmap;
995 m_data->pixmap.pixmap = pixmap;
996}
997
1002const QPixmap& QwtSymbol::pixmap() const
1003{
1004 return m_data->pixmap.pixmap;
1005}
1006
1017void QwtSymbol::setGraphic( const QwtGraphic& graphic )
1018{
1019 m_data->style = QwtSymbol::Graphic;
1020 m_data->graphic.graphic = graphic;
1021}
1022
1028{
1029 return m_data->graphic.graphic;
1030}
1031
1032#ifndef QWT_NO_SVG
1033
1044void QwtSymbol::setSvgDocument( const QByteArray& svgDocument )
1045{
1046 m_data->style = QwtSymbol::SvgDocument;
1047 if ( m_data->svg.renderer == NULL )
1048 m_data->svg.renderer = new QSvgRenderer();
1049
1050 m_data->svg.renderer->load( svgDocument );
1051}
1052
1053#endif
1054
1067void QwtSymbol::setSize( int width, int height )
1068{
1069 if ( ( width >= 0 ) && ( height < 0 ) )
1070 height = width;
1071
1072 setSize( QSize( width, height ) );
1073}
1074
1081void QwtSymbol::setSize( const QSize& size )
1082{
1083 if ( size.isValid() && size != m_data->size )
1084 {
1085 m_data->size = size;
1087 }
1088}
1089
1094const QSize& QwtSymbol::size() const
1095{
1096 return m_data->size;
1097}
1098
1107void QwtSymbol::setBrush( const QBrush& brush )
1108{
1109 if ( brush != m_data->brush )
1110 {
1111 m_data->brush = brush;
1113
1114 if ( m_data->style == QwtSymbol::Path )
1115 m_data->path.graphic.reset();
1116 }
1117}
1118
1123const QBrush& QwtSymbol::brush() const
1124{
1125 return m_data->brush;
1126}
1127
1141void QwtSymbol::setPen( const QColor& color,
1142 qreal width, Qt::PenStyle style )
1143{
1144 setPen( QPen( color, width, style ) );
1145}
1146
1155void QwtSymbol::setPen( const QPen& pen )
1156{
1157 if ( pen != m_data->pen )
1158 {
1159 m_data->pen = pen;
1161
1162 if ( m_data->style == QwtSymbol::Path )
1163 m_data->path.graphic.reset();
1164 }
1165}
1166
1171const QPen& QwtSymbol::pen() const
1172{
1173 return m_data->pen;
1174}
1175
1186void QwtSymbol::setColor( const QColor& color )
1187{
1188 switch ( m_data->style )
1189 {
1190 case QwtSymbol::Ellipse:
1191 case QwtSymbol::Rect:
1192 case QwtSymbol::Diamond:
1198 case QwtSymbol::Star2:
1199 case QwtSymbol::Hexagon:
1200 {
1201 if ( m_data->brush.color() != color )
1202 {
1203 m_data->brush.setColor( color );
1205 }
1206 break;
1207 }
1208 case QwtSymbol::Cross:
1209 case QwtSymbol::XCross:
1210 case QwtSymbol::HLine:
1211 case QwtSymbol::VLine:
1212 case QwtSymbol::Star1:
1213 {
1214 if ( m_data->pen.color() != color )
1215 {
1216 m_data->pen.setColor( color );
1218 }
1219 break;
1220 }
1221 default:
1222 {
1223 if ( m_data->brush.color() != color ||
1224 m_data->pen.color() != color )
1225 {
1227 }
1228
1229 m_data->brush.setColor( color );
1230 m_data->pen.setColor( color );
1231 }
1232 }
1233}
1234
1249void QwtSymbol::setPinPoint( const QPointF& pos, bool enable )
1250{
1251 if ( m_data->pinPoint != pos )
1252 {
1253 m_data->pinPoint = pos;
1254 if ( m_data->isPinPointEnabled )
1255 {
1257 }
1258 }
1259
1260 setPinPointEnabled( enable );
1261}
1262
1267QPointF QwtSymbol::pinPoint() const
1268{
1269 return m_data->pinPoint;
1270}
1271
1279{
1280 if ( m_data->isPinPointEnabled != on )
1281 {
1282 m_data->isPinPointEnabled = on;
1284 }
1285}
1286
1292{
1293 return m_data->isPinPointEnabled;
1294}
1295
1307void QwtSymbol::drawSymbols( QPainter* painter,
1308 const QPointF* points, int numPoints ) const
1309{
1310 if ( numPoints <= 0 )
1311 return;
1312
1313 bool useCache = false;
1314
1315 // Don't use the pixmap, when the paint device
1316 // could generate scalable vectors
1317
1318 if ( QwtPainter::roundingAlignment( painter ) &&
1319 !painter->transform().isScaling() )
1320 {
1321 if ( m_data->cache.policy == QwtSymbol::Cache )
1322 {
1323 useCache = true;
1324 }
1325 else if ( m_data->cache.policy == QwtSymbol::AutoCache )
1326 {
1327 switch( painter->paintEngine()->type() )
1328 {
1329 case QPaintEngine::OpenGL:
1330 case QPaintEngine::OpenGL2:
1331 {
1332 // using a FBO as cache ?
1333 useCache = false;
1334 break;
1335 }
1336 case QPaintEngine::OpenVG:
1337 case QPaintEngine::SVG:
1338 case QPaintEngine::Pdf:
1339 case QPaintEngine::Picture:
1340 {
1341 // vector graphics
1342 useCache = false;
1343 break;
1344 }
1345 case QPaintEngine::X11:
1346 {
1347 switch( m_data->style )
1348 {
1349 case QwtSymbol::XCross:
1350 case QwtSymbol::HLine:
1351 case QwtSymbol::VLine:
1352 case QwtSymbol::Cross:
1353 {
1354 // for the very simple shapes using vector graphics is
1355 // usually faster.
1356
1357 useCache = false;
1358 break;
1359 }
1360
1361 case QwtSymbol::Pixmap:
1362 {
1363 if ( m_data->size.isEmpty() ||
1364 m_data->size == m_data->pixmap.pixmap.size() )
1365 {
1366 // no need to have a pixmap cache for a pixmap
1367 // of the same size
1368
1369 useCache = false;
1370 }
1371 break;
1372 }
1373 default:
1374 break;
1375 }
1376 break;
1377 }
1378 default:
1379 {
1380 useCache = true;
1381 }
1382 }
1383 }
1384 }
1385
1386 if ( useCache )
1387 {
1388 const QRect br = boundingRect();
1389
1390 if ( m_data->cache.pixmap.isNull() )
1391 {
1392 m_data->cache.pixmap = QwtPainter::backingStore( NULL, br.size() );
1393 m_data->cache.pixmap.fill( Qt::transparent );
1394
1395 QPainter p( &m_data->cache.pixmap );
1396 p.setRenderHints( painter->renderHints() );
1397 p.translate( -br.topLeft() );
1398
1399 const QPointF pos( 0.0, 0.0 );
1400 renderSymbols( &p, &pos, 1 );
1401 }
1402
1403 const int dx = br.left();
1404 const int dy = br.top();
1405
1406 for ( int i = 0; i < numPoints; i++ )
1407 {
1408 const int left = qRound( points[i].x() ) + dx;
1409 const int top = qRound( points[i].y() ) + dy;
1410
1411 painter->drawPixmap( left, top, m_data->cache.pixmap );
1412 }
1413 }
1414 else
1415 {
1416 painter->save();
1417 renderSymbols( painter, points, numPoints );
1418 painter->restore();
1419 }
1420}
1421
1434void QwtSymbol::drawSymbol( QPainter* painter, const QRectF& rect ) const
1435{
1436 if ( m_data->style == QwtSymbol::NoSymbol )
1437 return;
1438
1439 if ( m_data->style == QwtSymbol::Graphic )
1440 {
1441 m_data->graphic.graphic.render(
1442 painter, rect, Qt::KeepAspectRatio );
1443 }
1444 else if ( m_data->style == QwtSymbol::Path )
1445 {
1446 if ( m_data->path.graphic.isNull() )
1447 {
1448 m_data->path.graphic = qwtPathGraphic(
1449 m_data->path.path, m_data->pen, m_data->brush );
1450 }
1451
1452 m_data->path.graphic.render(
1453 painter, rect, Qt::KeepAspectRatio );
1454 return;
1455 }
1456 else if ( m_data->style == QwtSymbol::SvgDocument )
1457 {
1458#ifndef QWT_NO_SVG
1459 if ( m_data->svg.renderer )
1460 {
1461 QRectF scaledRect;
1462
1463 QSizeF sz = m_data->svg.renderer->viewBoxF().size();
1464 if ( !sz.isEmpty() )
1465 {
1466 sz.scale( rect.size(), Qt::KeepAspectRatio );
1467 scaledRect.setSize( sz );
1468 scaledRect.moveCenter( rect.center() );
1469 }
1470 else
1471 {
1472 scaledRect = rect;
1473 }
1474
1475 m_data->svg.renderer->render(
1476 painter, scaledRect );
1477 }
1478#endif
1479 }
1480 else
1481 {
1482 const QRect br = boundingRect();
1483
1484 // scale the symbol size to fit into rect.
1485
1486 const double ratio = qMin( rect.width() / br.width(),
1487 rect.height() / br.height() );
1488
1489 painter->save();
1490
1491 painter->translate( rect.center() );
1492 painter->scale( ratio, ratio );
1493
1494 const bool isPinPointEnabled = m_data->isPinPointEnabled;
1495 m_data->isPinPointEnabled = false;
1496
1497 const QPointF pos;
1498 renderSymbols( painter, &pos, 1 );
1499
1500 m_data->isPinPointEnabled = isPinPointEnabled;
1501
1502 painter->restore();
1503 }
1504}
1505
1513void QwtSymbol::renderSymbols( QPainter* painter,
1514 const QPointF* points, int numPoints ) const
1515{
1516 switch ( m_data->style )
1517 {
1518 case QwtSymbol::Ellipse:
1519 {
1520 qwtDrawEllipseSymbols( painter, points, numPoints, *this );
1521 break;
1522 }
1523 case QwtSymbol::Rect:
1524 {
1525 qwtDrawRectSymbols( painter, points, numPoints, *this );
1526 break;
1527 }
1528 case QwtSymbol::Diamond:
1529 {
1530 qwtDrawDiamondSymbols( painter, points, numPoints, *this );
1531 break;
1532 }
1533 case QwtSymbol::Cross:
1534 {
1535 qwtDrawLineSymbols( painter, Qt::Horizontal | Qt::Vertical,
1536 points, numPoints, *this );
1537 break;
1538 }
1539 case QwtSymbol::XCross:
1540 {
1541 qwtDrawXCrossSymbols( painter, points, numPoints, *this );
1542 break;
1543 }
1546 {
1547 qwtDrawTriangleSymbols( painter, QwtTriangle::Up,
1548 points, numPoints, *this );
1549 break;
1550 }
1552 {
1553 qwtDrawTriangleSymbols( painter, QwtTriangle::Down,
1554 points, numPoints, *this );
1555 break;
1556 }
1558 {
1559 qwtDrawTriangleSymbols( painter, QwtTriangle::Right,
1560 points, numPoints, *this );
1561 break;
1562 }
1564 {
1565 qwtDrawTriangleSymbols( painter, QwtTriangle::Left,
1566 points, numPoints, *this );
1567 break;
1568 }
1569 case QwtSymbol::HLine:
1570 {
1571 qwtDrawLineSymbols( painter, Qt::Horizontal,
1572 points, numPoints, *this );
1573 break;
1574 }
1575 case QwtSymbol::VLine:
1576 {
1577 qwtDrawLineSymbols( painter, Qt::Vertical,
1578 points, numPoints, *this );
1579 break;
1580 }
1581 case QwtSymbol::Star1:
1582 {
1583 qwtDrawStar1Symbols( painter, points, numPoints, *this );
1584 break;
1585 }
1586 case QwtSymbol::Star2:
1587 {
1588 qwtDrawStar2Symbols( painter, points, numPoints, *this );
1589 break;
1590 }
1591 case QwtSymbol::Hexagon:
1592 {
1593 qwtDrawHexagonSymbols( painter, points, numPoints, *this );
1594 break;
1595 }
1596 case QwtSymbol::Path:
1597 {
1598 if ( m_data->path.graphic.isNull() )
1599 {
1600 m_data->path.graphic = qwtPathGraphic( m_data->path.path,
1601 m_data->pen, m_data->brush );
1602 }
1603
1604 qwtDrawGraphicSymbols( painter, points, numPoints,
1605 m_data->path.graphic, *this );
1606 break;
1607 }
1608 case QwtSymbol::Pixmap:
1609 {
1610 qwtDrawPixmapSymbols( painter, points, numPoints, *this );
1611 break;
1612 }
1613 case QwtSymbol::Graphic:
1614 {
1615 qwtDrawGraphicSymbols( painter, points, numPoints,
1616 m_data->graphic.graphic, *this );
1617 break;
1618 }
1620 {
1621#ifndef QWT_NO_SVG
1622 qwtDrawSvgSymbols( painter, points, numPoints,
1623 m_data->svg.renderer, *this );
1624#endif
1625 break;
1626 }
1627 default:;
1628 }
1629}
1630
1638{
1639 QRectF rect;
1640
1641 bool pinPointTranslation = false;
1642
1643 switch ( m_data->style )
1644 {
1645 case QwtSymbol::Ellipse:
1646 case QwtSymbol::Rect:
1647 case QwtSymbol::Hexagon:
1648 {
1649 qreal pw = 0.0;
1650 if ( m_data->pen.style() != Qt::NoPen )
1651 pw = QwtPainter::effectivePenWidth( m_data->pen );
1652
1653 rect.setSize( m_data->size + QSizeF( pw, pw ) );
1654 rect.moveCenter( QPointF( 0.0, 0.0 ) );
1655
1656 break;
1657 }
1658 case QwtSymbol::XCross:
1659 case QwtSymbol::Diamond:
1665 case QwtSymbol::Star1:
1666 case QwtSymbol::Star2:
1667 {
1668 qreal pw = 0.0;
1669 if ( m_data->pen.style() != Qt::NoPen )
1670 pw = QwtPainter::effectivePenWidth( m_data->pen );
1671
1672 rect.setSize( m_data->size + QSizeF( 2 * pw, 2 * pw ) );
1673 rect.moveCenter( QPointF( 0.0, 0.0 ) );
1674 break;
1675 }
1676 case QwtSymbol::Path:
1677 {
1678 if ( m_data->path.graphic.isNull() )
1679 {
1680 m_data->path.graphic = qwtPathGraphic(
1681 m_data->path.path, m_data->pen, m_data->brush );
1682 }
1683
1684 rect = qwtScaledBoundingRect(
1685 m_data->path.graphic, m_data->size );
1686 pinPointTranslation = true;
1687
1688 break;
1689 }
1690 case QwtSymbol::Pixmap:
1691 {
1692 if ( m_data->size.isEmpty() )
1693 rect.setSize( m_data->pixmap.pixmap.size() );
1694 else
1695 rect.setSize( m_data->size );
1696
1697 pinPointTranslation = true;
1698
1699 break;
1700 }
1701 case QwtSymbol::Graphic:
1702 {
1703 rect = qwtScaledBoundingRect(
1704 m_data->graphic.graphic, m_data->size );
1705 pinPointTranslation = true;
1706
1707 break;
1708 }
1709#ifndef QWT_NO_SVG
1711 {
1712 if ( m_data->svg.renderer )
1713 rect = m_data->svg.renderer->viewBoxF();
1714
1715 if ( m_data->size.isValid() && !rect.isEmpty() )
1716 {
1717 QSizeF sz = rect.size();
1718
1719 const double sx = m_data->size.width() / sz.width();
1720 const double sy = m_data->size.height() / sz.height();
1721
1722 QTransform transform;
1723 transform.scale( sx, sy );
1724
1725 rect = transform.mapRect( rect );
1726 }
1727 pinPointTranslation = true;
1728 break;
1729 }
1730#endif
1731 default:
1732 {
1733 rect.setSize( m_data->size );
1734 rect.moveCenter( QPointF( 0.0, 0.0 ) );
1735 }
1736 }
1737
1738 if ( pinPointTranslation )
1739 {
1740 QPointF pinPoint( 0.0, 0.0 );
1741 if ( m_data->isPinPointEnabled )
1742 pinPoint = rect.center() - m_data->pinPoint;
1743
1744 rect.moveCenter( pinPoint );
1745 }
1746
1747 QRect r;
1748 r.setLeft( qwtFloor( rect.left() ) );
1749 r.setTop( qwtFloor( rect.top() ) );
1750 r.setRight( qwtCeil( rect.right() ) );
1751 r.setBottom( qwtCeil( rect.bottom() ) );
1752
1753 if ( m_data->style != QwtSymbol::Pixmap )
1754 r.adjust( -1, -1, 1, 1 ); // for antialiasing
1755
1756 return r;
1757}
1758
1771{
1772 if ( !m_data->cache.pixmap.isNull() )
1773 m_data->cache.pixmap = QPixmap();
1774}
1775
1783{
1784 if ( m_data->style != style )
1785 {
1786 m_data->style = style;
1788 }
1789}
1790
1796{
1797 return m_data->style;
1798}
A paint device for scalable graphics.
Definition qwt_graphic.h:76
@ RenderPensUnscaled
Definition qwt_graphic.h:96
void reset()
Clear all stored commands.
void setRenderHint(RenderHint, bool on=true)
bool isNull() const
QRectF controlPointRect() const
QSizeF defaultSize() const
Default size.
QRectF scaledBoundingRect(qreal sx, qreal sy) const
Calculate the target rectangle for scaling the graphic.
void render(QPainter *) const
Replay all recorded painter commands.
static void drawEllipse(QPainter *, const QRectF &)
Wrapper for QPainter::drawEllipse()
static void drawPolygon(QPainter *, const QPolygonF &)
Wrapper for QPainter::drawPolygon()
static qreal effectivePenWidth(const QPen &)
static void drawRect(QPainter *, qreal x, qreal y, qreal w, qreal h)
Wrapper for QPainter::drawRect()
static QPixmap backingStore(QWidget *, const QSize &)
static bool roundingAlignment()
static void drawPixmap(QPainter *, const QRectF &, const QPixmap &)
Wrapper for QPainter::drawPixmap()
static void drawLine(QPainter *, qreal x1, qreal y1, qreal x2, qreal y2)
Wrapper for QPainter::drawLine()
A class for drawing symbols.
Definition qwt_symbol.h:32
const QPainterPath & path() const
virtual void setColor(const QColor &)
Set the color of the symbol.
Style style() const
const QBrush & brush() const
const QPixmap & pixmap() const
void setPen(const QColor &, qreal width=0.0, Qt::PenStyle=Qt::SolidLine)
void drawSymbol(QPainter *, const QRectF &) const
Draw the symbol into a rectangle.
void setCachePolicy(CachePolicy)
void setStyle(Style)
void setPinPointEnabled(bool)
virtual ~QwtSymbol()
Destructor.
virtual QRect boundingRect() const
void setSvgDocument(const QByteArray &)
void drawSymbols(QPainter *, const QPolygonF &) const
Draw symbols at the specified points.
Definition qwt_symbol.h:251
@ VLine
Vertical line.
Definition qwt_symbol.h:77
@ Ellipse
Ellipse or circle.
Definition qwt_symbol.h:44
@ LTriangle
Triangle pointing left.
Definition qwt_symbol.h:62
@ Star1
X combined with +.
Definition qwt_symbol.h:80
@ HLine
Horizontal line.
Definition qwt_symbol.h:74
@ Rect
Rectangle.
Definition qwt_symbol.h:47
@ Triangle
Triangle pointing upwards.
Definition qwt_symbol.h:53
@ Hexagon
Hexagon.
Definition qwt_symbol.h:86
@ Diamond
Diamond.
Definition qwt_symbol.h:50
@ XCross
Diagonal cross (X)
Definition qwt_symbol.h:71
@ Cross
Cross (+)
Definition qwt_symbol.h:68
@ UTriangle
Triangle pointing upwards.
Definition qwt_symbol.h:59
@ NoSymbol
No Style. The symbol cannot be drawn.
Definition qwt_symbol.h:41
@ DTriangle
Triangle pointing downwards.
Definition qwt_symbol.h:56
@ RTriangle
Triangle pointing right.
Definition qwt_symbol.h:65
@ Star2
Six-pointed star.
Definition qwt_symbol.h:83
void setPath(const QPainterPath &)
Set a painter path as symbol.
void setPixmap(const QPixmap &)
QwtSymbol(Style=NoSymbol)
void invalidateCache()
void setPinPoint(const QPointF &pos, bool enable=true)
Set and enable a pin point.
void setSize(const QSize &)
bool isPinPointEnabled() const
void setGraphic(const QwtGraphic &)
const QSize & size() const
virtual void renderSymbols(QPainter *, const QPointF *, int numPoints) const
@ Cache
Always use a pixmap cache.
Definition qwt_symbol.h:156
CachePolicy cachePolicy() const
const QwtGraphic & graphic() const
const QPen & pen() const
QPointF pinPoint() const
void setBrush(const QBrush &)
Assign a brush.