source: ntrip/trunk/BNC/qwt/qwt_plot_shapeitem.cpp@ 8963

Last change on this file since 8963 was 8127, checked in by stoecker, 7 years ago

update qwt and qwtpolar, many QT5 fixes (unfinished)

File size: 11.1 KB
Line 
1/* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
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_plot_shapeitem.h"
11#include "qwt_scale_map.h"
12#include "qwt_painter.h"
13#include "qwt_curve_fitter.h"
14#include "qwt_clipper.h"
15
16static QPainterPath qwtTransformPath( const QwtScaleMap &xMap,
17 const QwtScaleMap &yMap, const QPainterPath &path, bool doAlign )
18{
19 QPainterPath shape;
20 shape.setFillRule( path.fillRule() );
21
22 for ( int i = 0; i < path.elementCount(); i++ )
23 {
24 const QPainterPath::Element &element = path.elementAt( i );
25
26 double x = xMap.transform( element.x );
27 double y = yMap.transform( element.y );
28
29 switch( element.type )
30 {
31 case QPainterPath::MoveToElement:
32 {
33 if ( doAlign )
34 {
35 x = qRound( x );
36 y = qRound( y );
37 }
38
39 shape.moveTo( x, y );
40 break;
41 }
42 case QPainterPath::LineToElement:
43 {
44 if ( doAlign )
45 {
46 x = qRound( x );
47 y = qRound( y );
48 }
49
50 shape.lineTo( x, y );
51 break;
52 }
53 case QPainterPath::CurveToElement:
54 {
55 const QPainterPath::Element& element1 = path.elementAt( ++i );
56 const double x1 = xMap.transform( element1.x );
57 const double y1 = yMap.transform( element1.y );
58
59 const QPainterPath::Element& element2 = path.elementAt( ++i );
60 const double x2 = xMap.transform( element2.x );
61 const double y2 = yMap.transform( element2.y );
62
63 shape.cubicTo( x, y, x1, y1, x2, y2 );
64 break;
65 }
66 case QPainterPath::CurveToDataElement:
67 {
68 break;
69 }
70 }
71 }
72
73 return shape;
74}
75
76
77class QwtPlotShapeItem::PrivateData
78{
79public:
80 PrivateData():
81 legendMode( QwtPlotShapeItem::LegendColor ),
82 renderTolerance( 0.0 )
83 {
84 }
85
86 QwtPlotShapeItem::PaintAttributes paintAttributes;
87 QwtPlotShapeItem::LegendMode legendMode;
88
89 double renderTolerance;
90 QRectF boundingRect;
91
92 QPen pen;
93 QBrush brush;
94 QPainterPath shape;
95};
96
97/*!
98 \brief Constructor
99
100 Sets the following item attributes:
101 - QwtPlotItem::AutoScale: true
102 - QwtPlotItem::Legend: false
103
104 \param title Title
105*/
106QwtPlotShapeItem::QwtPlotShapeItem( const QString& title ):
107 QwtPlotItem( QwtText( title ) )
108{
109 init();
110}
111
112/*!
113 \brief Constructor
114
115 Sets the following item attributes:
116 - QwtPlotItem::AutoScale: true
117 - QwtPlotItem::Legend: false
118
119 \param title Title
120*/
121QwtPlotShapeItem::QwtPlotShapeItem( const QwtText& title ):
122 QwtPlotItem( title )
123{
124 init();
125}
126
127//! Destructor
128QwtPlotShapeItem::~QwtPlotShapeItem()
129{
130 delete d_data;
131}
132
133void QwtPlotShapeItem::init()
134{
135 d_data = new PrivateData();
136 d_data->boundingRect = QwtPlotItem::boundingRect();
137
138 setItemAttribute( QwtPlotItem::AutoScale, true );
139 setItemAttribute( QwtPlotItem::Legend, false );
140
141 setZ( 8.0 );
142}
143
144//! \return QwtPlotItem::Rtti_PlotShape
145int QwtPlotShapeItem::rtti() const
146{
147 return QwtPlotItem::Rtti_PlotShape;
148}
149
150/*!
151 Specify an attribute how to draw the shape
152
153 \param attribute Paint attribute
154 \param on On/Off
155 \sa testPaintAttribute()
156*/
157void QwtPlotShapeItem::setPaintAttribute( PaintAttribute attribute, bool on )
158{
159 if ( on )
160 d_data->paintAttributes |= attribute;
161 else
162 d_data->paintAttributes &= ~attribute;
163}
164
165/*!
166 \return True, when attribute is enabled
167 \sa setPaintAttribute()
168*/
169bool QwtPlotShapeItem::testPaintAttribute( PaintAttribute attribute ) const
170{
171 return ( d_data->paintAttributes & attribute );
172}
173
174/*!
175 Set the mode how to represent the item on the legend
176
177 \param mode Mode
178 \sa legendMode()
179 */
180void QwtPlotShapeItem::setLegendMode( LegendMode mode )
181{
182 if ( mode != d_data->legendMode )
183 {
184 d_data->legendMode = mode;
185 legendChanged();
186 }
187}
188
189/*!
190 \return Mode how to represent the item on the legend
191 \sa legendMode()
192 */
193QwtPlotShapeItem::LegendMode QwtPlotShapeItem::legendMode() const
194{
195 return d_data->legendMode;
196}
197
198//! Bounding rectangle of the shape
199QRectF QwtPlotShapeItem::boundingRect() const
200{
201 return d_data->boundingRect;
202}
203
204/*!
205 \brief Set a path built from a rectangle
206
207 \param rect Rectangle
208 \sa setShape(), setPolygon(), shape()
209 */
210void QwtPlotShapeItem::setRect( const QRectF &rect )
211{
212 QPainterPath path;
213 path.addRect( rect );
214
215 setShape( path );
216}
217
218/*!
219 \brief Set a path built from a polygon
220
221 \param polygon Polygon
222 \sa setShape(), setRect(), shape()
223 */
224void QwtPlotShapeItem::setPolygon( const QPolygonF &polygon )
225{
226 QPainterPath shape;
227 shape.addPolygon( polygon );
228
229 setShape( shape );
230}
231
232/*!
233 \brief Set the shape to be displayed
234
235 \param shape Shape
236 \sa setShape(), shape()
237 */
238void QwtPlotShapeItem::setShape( const QPainterPath &shape )
239{
240 if ( shape != d_data->shape )
241 {
242 d_data->shape = shape;
243 if ( shape.isEmpty() )
244 {
245 d_data->boundingRect = QwtPlotItem::boundingRect();
246 }
247 else
248 {
249 d_data->boundingRect = shape.boundingRect();
250 }
251
252 itemChanged();
253 }
254}
255
256/*!
257 \return Shape to be displayed
258 \sa setShape()
259 */
260QPainterPath QwtPlotShapeItem::shape() const
261{
262 return d_data->shape;
263}
264
265/*!
266 Build and assign a pen
267
268 In Qt5 the default pen width is 1.0 ( 0.0 in Qt4 ) what makes it
269 non cosmetic ( see QPen::isCosmetic() ). This method has been introduced
270 to hide this incompatibility.
271
272 \param color Pen color
273 \param width Pen width
274 \param style Pen style
275
276 \sa pen(), brush()
277 */
278void QwtPlotShapeItem::setPen( const QColor &color, qreal width, Qt::PenStyle style )
279{
280 setPen( QPen( color, width, style ) );
281}
282
283/*!
284 \brief Assign a pen
285
286 The pen is used to draw the outline of the shape
287
288 \param pen Pen
289 \sa pen(), brush()
290*/
291void QwtPlotShapeItem::setPen( const QPen &pen )
292{
293 if ( pen != d_data->pen )
294 {
295 d_data->pen = pen;
296 itemChanged();
297 }
298}
299
300/*!
301 \return Pen used to draw the outline of the shape
302 \sa setPen(), brush()
303*/
304QPen QwtPlotShapeItem::pen() const
305{
306 return d_data->pen;
307}
308
309/*!
310 Assign a brush.
311
312 The brush is used to fill the path
313
314 \param brush Brush
315 \sa brush(), pen()
316*/
317void QwtPlotShapeItem::setBrush( const QBrush &brush )
318{
319 if ( brush != d_data->brush )
320 {
321 d_data->brush = brush;
322 itemChanged();
323 }
324}
325
326/*!
327 \return Brush used to fill the shape
328 \sa setBrush(), pen()
329*/
330QBrush QwtPlotShapeItem::brush() const
331{
332 return d_data->brush;
333}
334
335/*!
336 \brief Set the tolerance for the weeding optimization
337
338 After translating the shape into target device coordinate
339 ( usually widget geometries ) the painter path can be simplified
340 by a point weeding algorithm ( Douglas-Peucker ).
341
342 For shapes built from curves and ellipses weeding might
343 have the opposite effect because they have to be expanded
344 to polygons.
345
346 \param tolerance Accepted error when reducing the number of points
347 A value <= 0.0 disables weeding.
348
349 \sa renderTolerance(), QwtWeedingCurveFitter
350 */
351void QwtPlotShapeItem::setRenderTolerance( double tolerance )
352{
353 tolerance = qMax( tolerance, 0.0 );
354
355 if ( tolerance != d_data->renderTolerance )
356 {
357 d_data->renderTolerance = tolerance;
358 itemChanged();
359 }
360}
361
362/*!
363 \return Tolerance for the weeding optimization
364 \sa setRenderTolerance()
365 */
366double QwtPlotShapeItem::renderTolerance() const
367{
368 return d_data->renderTolerance;
369}
370
371/*!
372 Draw the shape item
373
374 \param painter Painter
375 \param xMap X-Scale Map
376 \param yMap Y-Scale Map
377 \param canvasRect Contents rect of the plot canvas
378*/
379void QwtPlotShapeItem::draw( QPainter *painter,
380 const QwtScaleMap &xMap, const QwtScaleMap &yMap,
381 const QRectF &canvasRect ) const
382{
383 if ( d_data->shape.isEmpty() )
384 return;
385
386 if ( d_data->pen.style() == Qt::NoPen
387 && d_data->brush.style() == Qt::NoBrush )
388 {
389 return;
390 }
391
392 const QRectF cr = QwtScaleMap::invTransform(
393 xMap, yMap, canvasRect.toRect() );
394
395 const QRectF &br = d_data->boundingRect;
396
397 if ( ( br.left() > cr.right() ) || ( br.right() < cr.left() )
398 || ( br.top() > cr.bottom() ) || ( br.bottom() < cr.top() ) )
399 {
400 // outside the visisble area
401 return;
402 }
403
404 const bool doAlign = QwtPainter::roundingAlignment( painter );
405
406 QPainterPath path = qwtTransformPath( xMap, yMap,
407 d_data->shape, doAlign );
408
409 if ( testPaintAttribute( QwtPlotShapeItem::ClipPolygons ) )
410 {
411 qreal pw = qMax( qreal( 1.0 ), painter->pen().widthF());
412 QRectF clipRect = canvasRect.adjusted( -pw, -pw, pw, pw );
413
414 QPainterPath clippedPath;
415 clippedPath.setFillRule( path.fillRule() );
416
417 const QList<QPolygonF> polygons = path.toSubpathPolygons();
418 for ( int i = 0; i < polygons.size(); i++ )
419 {
420 const QPolygonF p = QwtClipper::clipPolygonF(
421 clipRect, polygons[i], true );
422
423 clippedPath.addPolygon( p );
424
425 }
426
427 path = clippedPath;
428 }
429
430 if ( d_data->renderTolerance > 0.0 )
431 {
432 QwtWeedingCurveFitter fitter( d_data->renderTolerance );
433
434 QPainterPath fittedPath;
435 fittedPath.setFillRule( path.fillRule() );
436
437 const QList<QPolygonF> polygons = path.toSubpathPolygons();
438 for ( int i = 0; i < polygons.size(); i++ )
439 fittedPath.addPolygon( fitter.fitCurve( polygons[ i ] ) );
440
441 path = fittedPath;
442 }
443
444 painter->setPen( d_data->pen );
445 painter->setBrush( d_data->brush );
446
447 painter->drawPath( path );
448}
449
450/*!
451 \return A rectangle filled with the color of the brush ( or the pen )
452
453 \param index Index of the legend entry
454 ( usually there is only one )
455 \param size Icon size
456
457 \sa setLegendIconSize(), legendData()
458*/
459QwtGraphic QwtPlotShapeItem::legendIcon( int index,
460 const QSizeF &size ) const
461{
462 Q_UNUSED( index );
463
464 QwtGraphic icon;
465 icon.setDefaultSize( size );
466
467 if ( size.isEmpty() )
468 return icon;
469
470 if ( d_data->legendMode == QwtPlotShapeItem::LegendShape )
471 {
472 const QRectF &br = d_data->boundingRect;
473
474 QPainter painter( &icon );
475 painter.setRenderHint( QPainter::Antialiasing,
476 testRenderHint( QwtPlotItem::RenderAntialiased ) );
477
478 painter.translate( -br.topLeft() );
479
480 painter.setPen( d_data->pen );
481 painter.setBrush( d_data->brush );
482 painter.drawPath( d_data->shape );
483 }
484 else
485 {
486 QColor iconColor;
487 if ( d_data->brush.style() != Qt::NoBrush )
488 iconColor = d_data->brush.color();
489 else
490 iconColor = d_data->pen.color();
491
492 icon = defaultIcon( iconColor, size );
493 }
494
495 return icon;
496}
497
Note: See TracBrowser for help on using the repository browser.