source: ntrip/trunk/BNC/qwtpolar/qwt_polar_curve.cpp@ 9448

Last change on this file since 9448 was 8127, checked in by stoecker, 8 years ago

update qwt and qwtpolar, many QT5 fixes (unfinished)

File size: 14.4 KB
RevLine 
[4272]1/* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
2 * QwtPolar Widget Library
3 * Copyright (C) 2008 Uwe Rathmann
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the Qwt License, Version 1.0
7 *****************************************************************************/
8
9#include "qwt_polar_curve.h"
10#include "qwt_polar.h"
11#include <qwt_painter.h>
12#include <qwt_scale_map.h>
13#include <qwt_math.h>
14#include <qwt_symbol.h>
15#include <qwt_legend.h>
16#include <qwt_curve_fitter.h>
17#include <qwt_clipper.h>
18#include <qpainter.h>
19
20static inline bool qwtInsidePole( const QwtScaleMap &map, double radius )
21{
22 return map.isInverting() ? ( radius > map.s1() ) : ( radius < map.s1() );
23}
24
25static int qwtVerifyRange( int size, int &i1, int &i2 )
26{
27 if ( size < 1 )
28 return 0;
29
30 i1 = qBound( 0, i1, size - 1 );
31 i2 = qBound( 0, i2, size - 1 );
32
33 if ( i1 > i2 )
34 qSwap( i1, i2 );
35
36 return ( i2 - i1 + 1 );
37}
38
39class QwtPolarCurve::PrivateData
40{
41public:
42 PrivateData():
43 style( QwtPolarCurve::Lines ),
44 curveFitter( NULL ),
45 legendAttributes( 0 )
46 {
47 symbol = new QwtSymbol();
48 pen = QPen( Qt::black );
49 }
50
51 ~PrivateData()
52 {
53 delete symbol;
54 delete curveFitter;
55 }
56
57 QwtPolarCurve::CurveStyle style;
58 const QwtSymbol *symbol;
59 QPen pen;
60 QwtCurveFitter *curveFitter;
61
62 QwtPolarCurve::LegendAttributes legendAttributes;
63};
64
65//! Constructor
66QwtPolarCurve::QwtPolarCurve():
67 QwtPolarItem( QwtText() )
68{
69 init();
70}
71
72/*!
73 Constructor
74 \param title title of the curve
75*/
76QwtPolarCurve::QwtPolarCurve( const QwtText &title ):
77 QwtPolarItem( title )
78{
79 init();
80}
81
82/*!
83 Constructor
84 \param title title of the curve
85*/
86QwtPolarCurve::QwtPolarCurve( const QString &title ):
87 QwtPolarItem( QwtText( title ) )
88{
89 init();
90}
91
92//! Destructor
93QwtPolarCurve::~QwtPolarCurve()
94{
95 delete d_series;
96 delete d_data;
97}
98
99//! Initialize data members
100void QwtPolarCurve::init()
101{
102 d_data = new PrivateData;
103 d_series = NULL;
104
105 setItemAttribute( QwtPolarItem::AutoScale );
106 setItemAttribute( QwtPolarItem::Legend );
107 setZ( 20.0 );
108
109 setRenderHint( RenderAntialiased, true );
110}
111
112//! \return QwtPolarCurve::Rtti_PolarCurve
113int QwtPolarCurve::rtti() const
114{
115 return QwtPolarItem::Rtti_PolarCurve;
116}
117
118/*!
119 Specify an attribute how to draw the legend identifier
120
121 \param attribute Attribute
122 \param on On/Off
123 /sa LegendAttribute, testLegendAttribute()
124*/
125void QwtPolarCurve::setLegendAttribute( LegendAttribute attribute, bool on )
126{
127 if ( on )
128 d_data->legendAttributes |= attribute;
129 else
130 d_data->legendAttributes &= ~attribute;
131}
132
133/*!
134 \brief Test if a lefend attribute is enables
135
136 \param attribute Legend attribute
137
138 \return True if attribute is enabled
139 \sa LegendAttribute, setLegendAttribute()
140*/
141bool QwtPolarCurve::testLegendAttribute( LegendAttribute attribute ) const
142{
143 return ( d_data->legendAttributes & attribute );
144}
145
146/*!
147 Set the curve's drawing style
148
149 \param style Curve style
150 \sa CurveStyle, style()
151*/
152void QwtPolarCurve::setStyle( CurveStyle style )
153{
154 if ( style != d_data->style )
155 {
156 d_data->style = style;
157 itemChanged();
158 }
159}
160
161/*!
162 \return Current style
163 \sa CurveStyle, setStyle()
164*/
165QwtPolarCurve::CurveStyle QwtPolarCurve::style() const
166{
167 return d_data->style;
168}
169
170/*!
171 \brief Assign a symbol
172 \param symbol Symbol
173 \sa symbol()
174*/
[8127]175void QwtPolarCurve::setSymbol( QwtSymbol *symbol )
[4272]176{
177 if ( symbol != d_data->symbol )
178 {
179 delete d_data->symbol;
180 d_data->symbol = symbol;
181 itemChanged();
182 }
183}
184
185/*!
186 \return The current symbol
187 \sa setSymbol()
188*/
189const QwtSymbol *QwtPolarCurve::symbol() const
190{
191 return d_data->symbol;
192}
193
194/*!
195 \brief Assign a pen
196 \param pen New pen
197 \sa pen()
198*/
199void QwtPolarCurve::setPen( const QPen &pen )
200{
201 if ( pen != d_data->pen )
202 {
203 d_data->pen = pen;
204 itemChanged();
205 }
206}
207
208/*!
209 \return Pen used to draw the lines
210 \sa setPen()
211*/
212const QPen& QwtPolarCurve::pen() const
213{
214 return d_data->pen;
215}
216
217/*!
218 Initialize data with a pointer to QwtSeriesData<QwtPointPolar>.
219
220 The x-values of the data object represent the azimuth,
221 the y-value respresent the radius.
222
223 \param data Data
224*/
225void QwtPolarCurve::setData( QwtSeriesData<QwtPointPolar> *data )
226{
227 if ( d_series != data )
228 {
229 delete d_series;
230 d_series = data;
231 itemChanged();
232 }
233}
234
235/*!
236 \brief Insert a curve fitter
237
238 \param curveFitter Curve fitter
239
240 A curve fitter interpolates the curve points. F.e QwtPolarFitter
241 adds equidistant points so that the connection gets rounded instead
242 of having straight lines. If curveFitter is NULL fitting is disabled.
243
244 \sa curveFitter()
245*/
246void QwtPolarCurve::setCurveFitter( QwtCurveFitter *curveFitter )
247{
248 if ( curveFitter != d_data->curveFitter )
249 {
250 delete d_data->curveFitter;
251 d_data->curveFitter = curveFitter;
252
253 itemChanged();
254 }
255}
256
257/*!
258 \return The curve fitter
259 \sa setCurveFitter()
260*/
261QwtCurveFitter *QwtPolarCurve::curveFitter() const
262{
263 return d_data->curveFitter;
264}
265
266/*!
267 Draw the curve
268
269 \param painter Painter
270 \param azimuthMap Maps azimuth values to values related to 0.0, M_2PI
271 \param radialMap Maps radius values into painter coordinates.
272 \param pole Position of the pole in painter coordinates
273 \param radius Radius of the complete plot area in painter coordinates
274 \param canvasRect Contents rect of the canvas in painter coordinates
275*/
276void QwtPolarCurve::draw( QPainter *painter,
277 const QwtScaleMap &azimuthMap, const QwtScaleMap &radialMap,
278 const QPointF &pole, double radius,
279 const QRectF &canvasRect ) const
280{
281 Q_UNUSED( radius );
282 Q_UNUSED( canvasRect );
283
284 draw( painter, azimuthMap, radialMap, pole, 0, -1 );
285}
286
287/*!
288 \brief Draw an interval of the curve
289 \param painter Painter
290 \param azimuthMap Maps azimuth values to values related to 0.0, M_2PI
291 \param radialMap Maps radius values into painter coordinates.
292 \param pole Position of the pole in painter coordinates
293 \param from index of the first point to be painted
294 \param to index of the last point to be painted. If to < 0 the
295 curve will be painted to its last point.
296
297 \sa drawCurve(), drawSymbols(),
298*/
299void QwtPolarCurve::draw( QPainter *painter,
300 const QwtScaleMap &azimuthMap, const QwtScaleMap &radialMap,
301 const QPointF &pole, int from, int to ) const
302{
303 if ( !painter || dataSize() <= 0 )
304 return;
305
306 if ( to < 0 )
307 to = dataSize() - 1;
308
309 if ( qwtVerifyRange( dataSize(), from, to ) > 0 )
310 {
311 painter->save();
312 painter->setPen( d_data->pen );
313
314 drawCurve( painter, d_data->style,
315 azimuthMap, radialMap, pole, from, to );
316
317 painter->restore();
318
319 if ( d_data->symbol->style() != QwtSymbol::NoSymbol )
320 {
321 painter->save();
322 drawSymbols( painter, *d_data->symbol,
323 azimuthMap, radialMap, pole, from, to );
324 painter->restore();
325 }
326 }
327}
328
329/*!
330 Draw the line part (without symbols) of a curve interval.
331
332 \param painter Painter
333 \param style Curve style, see QwtPolarCurve::CurveStyle
334 \param azimuthMap Maps azimuth values to values related to 0.0, M_2PI
335 \param radialMap Maps radius values into painter coordinates.
336 \param pole Position of the pole in painter coordinates
337 \param from index of the first point to be painted
338 \param to index of the last point to be painted.
339 \sa draw(), drawLines()
340*/
341void QwtPolarCurve::drawCurve( QPainter *painter, int style,
342 const QwtScaleMap &azimuthMap, const QwtScaleMap &radialMap,
343 const QPointF &pole, int from, int to ) const
344{
345 switch ( style )
346 {
347 case Lines:
348 drawLines( painter, azimuthMap, radialMap, pole, from, to );
349 break;
350 case NoCurve:
351 default:
352 break;
353 }
354}
355
356/*!
357 Draw lines
358
359 \param painter Painter
360 \param azimuthMap Maps azimuth values to values related to 0.0, M_2PI
361 \param radialMap Maps radius values into painter coordinates.
362 \param pole Position of the pole in painter coordinates
363 \param from index of the first point to be painted
364 \param to index of the last point to be painted.
365 \sa draw(), drawLines(), setCurveFitter()
366*/
367void QwtPolarCurve::drawLines( QPainter *painter,
368 const QwtScaleMap &azimuthMap, const QwtScaleMap &radialMap,
369 const QPointF &pole, int from, int to ) const
370{
371 int size = to - from + 1;
372 if ( size <= 0 )
373 return;
374
375 QPolygonF polyline;
376 if ( d_data->curveFitter )
377 {
378 QPolygonF points( size );
379 for ( int j = from; j <= to; j++ )
380 {
381 const QwtPointPolar point = sample( j );
382 points[j - from] = QPointF( point.azimuth(), point.radius() );
383 }
384
385 points = d_data->curveFitter->fitCurve( points );
386
387 polyline.resize( points.size() );
388
389 QPointF *polylineData = polyline.data();
390 QPointF *pointsData = points.data();
391
392 for ( int i = 0; i < points.size(); i++ )
393 {
394 const QwtPointPolar point( pointsData[i].x(), pointsData[i].y() );
395
396 double r = radialMap.transform( point.radius() );
397 const double a = azimuthMap.transform( point.azimuth() );
398
399 polylineData[i] = qwtPolar2Pos( pole, r, a );
400 }
401 }
402 else
403 {
404 polyline.resize( size );
405 QPointF *polylineData = polyline.data();
406
407 for ( int i = from; i <= to; i++ )
408 {
409 QwtPointPolar point = sample( i );
410 if ( !qwtInsidePole( radialMap, point.radius() ) )
411 {
412 double r = radialMap.transform( point.radius() );
413 const double a = azimuthMap.transform( point.azimuth() );
414 polylineData[i - from] = qwtPolar2Pos( pole, r, a );
415 }
416 else
417 {
418 polylineData[i - from] = pole;
419 }
420 }
421 }
422
423 QRectF clipRect;
424 if ( painter->hasClipping() )
425 clipRect = painter->clipRegion().boundingRect();
426 else
427 {
428 clipRect = painter->window();
429 if ( !clipRect.isEmpty() )
430 clipRect = painter->transform().inverted().mapRect( clipRect );
431 }
432
433 if ( !clipRect.isEmpty() )
434 {
[8127]435 double off = qCeil( qMax( qreal( 1.0 ), painter->pen().widthF() ) );
[4272]436 clipRect = clipRect.toRect().adjusted( -off, -off, off, off );
437 polyline = QwtClipper::clipPolygonF( clipRect, polyline );
438 }
439
440 QwtPainter::drawPolyline( painter, polyline );
441 painter->drawPolyline( polyline );
442}
443
444/*!
445 Draw symbols
446
447 \param painter Painter
448 \param symbol Curve symbol
449 \param azimuthMap Maps azimuth values to values related to 0.0, M_2PI
450 \param radialMap Maps radius values into painter coordinates.
451 \param pole Position of the pole in painter coordinates
452 \param from index of the first point to be painted
453 \param to index of the last point to be painted.
454
455 \sa setSymbol(), draw(), drawCurve()
456*/
457void QwtPolarCurve::drawSymbols( QPainter *painter, const QwtSymbol &symbol,
458 const QwtScaleMap &azimuthMap, const QwtScaleMap &radialMap,
459 const QPointF &pole, int from, int to ) const
460{
461 painter->setBrush( symbol.brush() );
462 painter->setPen( symbol.pen() );
463
464 const int chunkSize = 500;
465
466 for ( int i = from; i <= to; i += chunkSize )
467 {
468 const int n = qMin( chunkSize, to - i + 1 );
469
470 QPolygonF points;
471 for ( int j = 0; j < n; j++ )
472 {
473 const QwtPointPolar point = sample( i + j );
474
475 if ( !qwtInsidePole( radialMap, point.radius() ) )
476 {
477 const double r = radialMap.transform( point.radius() );
478 const double a = azimuthMap.transform( point.azimuth() );
479
480 points += qwtPolar2Pos( pole, r, a );
481 }
482 else
483 {
484 points += pole;
485 }
486 }
487
488 if ( points.size() > 0 )
489 symbol.drawSymbols( painter, points );
490 }
491}
492
493/*!
494 \return Number of points
495 \sa setData()
496*/
497size_t QwtPolarCurve::dataSize() const
498{
499 return d_series->size();
500}
501
502/*!
[8127]503 \return Icon representing the curve on the legend
[4272]504
[8127]505 \param index Index of the legend entry
506 ( ignored as there is only one )
507 \param size Icon size
[4272]508
[8127]509 \sa QwtPolarItem::setLegendIconSize(), QwtPolarItem::legendData()
510 */
511QwtGraphic QwtPolarCurve::legendIcon( int index,
512 const QSizeF &size ) const
[4272]513{
[8127]514 Q_UNUSED( index );
[4272]515
[8127]516 if ( size.isEmpty() )
517 return QwtGraphic();
[4272]518
[8127]519 QwtGraphic graphic;
520 graphic.setDefaultSize( size );
521 graphic.setRenderHint( QwtGraphic::RenderPensUnscaled, true );
[4272]522
[8127]523 QPainter painter( &graphic );
524 painter.setRenderHint( QPainter::Antialiasing,
525 testRenderHint( QwtPolarItem::RenderAntialiased ) );
[4272]526
527 if ( d_data->legendAttributes == 0 )
528 {
529 QBrush brush;
[8127]530
[4272]531 if ( style() != QwtPolarCurve::NoCurve )
[8127]532 {
[4272]533 brush = QBrush( pen().color() );
[8127]534 }
[4272]535 else if ( d_data->symbol &&
536 ( d_data->symbol->style() != QwtSymbol::NoSymbol ) )
537 {
538 brush = QBrush( d_data->symbol->pen().color() );
539 }
[8127]540
[4272]541 if ( brush.style() != Qt::NoBrush )
[8127]542 {
543 QRectF r( 0, 0, size.width(), size.height() );
544 painter.fillRect( r, brush );
545 }
[4272]546 }
[8127]547
[4272]548 if ( d_data->legendAttributes & QwtPolarCurve::LegendShowLine )
549 {
550 if ( pen() != Qt::NoPen )
551 {
[8127]552 QPen pn = pen();
553 pn.setCapStyle( Qt::FlatCap );
554
555 painter.setPen( pn );
556
557 const double y = 0.5 * size.height();
558 QwtPainter::drawLine( &painter, 0.0, y, size.width(), y );
[4272]559 }
560 }
[8127]561
[4272]562 if ( d_data->legendAttributes & QwtPolarCurve::LegendShowSymbol )
563 {
[8127]564 if ( d_data->symbol )
[4272]565 {
[8127]566 QRectF r( 0, 0, size.width(), size.height() );
567 d_data->symbol->drawSymbol( &painter, r );
[4272]568 }
569 }
[8127]570
571 return graphic;
[4272]572}
573
574/*!
575 Interval, that is necessary to display the item
576 This interval can be useful for operations like clipping or autoscaling
577
578 \param scaleId Scale index
579 \return bounding interval
580
581 \sa QwtData::boundingRect()
582*/
583QwtInterval QwtPolarCurve::boundingInterval( int scaleId ) const
584{
585 const QRectF boundingRect = d_series->boundingRect();
586
587 if ( scaleId == QwtPolar::ScaleAzimuth )
588 return QwtInterval( boundingRect.left(), boundingRect.right() );
589
590 if ( scaleId == QwtPolar::ScaleRadius )
591 return QwtInterval( boundingRect.top(), boundingRect.bottom() );
592
593 return QwtInterval();
594}
[8127]595
596
Note: See TracBrowser for help on using the repository browser.