source: ntrip/branches/BNC_2.12/qwtpolar/qwt_polar_curve.cpp @ 7991

Last change on this file since 7991 was 7991, checked in by stuerze, 22 months ago

minor adaptations to allow the successful comilation of BNC on a Rasperry Pi

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