qwt_compass_rose.cpp 6.47 KB
Newer Older
pixhawk's avatar
pixhawk committed
1 2 3 4 5 6 7 8 9 10
/* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
 * Qwt Widget Library
 * Copyright (C) 1997   Josef Wilgen
 * Copyright (C) 2002   Uwe Rathmann
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the Qwt License, Version 1.0
 *****************************************************************************/

#include "qwt_compass_rose.h"
Bryant's avatar
Bryant committed
11 12 13
#include "qwt_point_polar.h"
#include "qwt_painter.h"
#include <qpainter.h>
pixhawk's avatar
pixhawk committed
14

Bryant's avatar
Bryant committed
15 16
static QPointF qwtIntersection( 
    QPointF p11, QPointF p12, QPointF p21, QPointF p22 )
pixhawk's avatar
pixhawk committed
17
{
Bryant's avatar
Bryant committed
18 19
    const QLineF line1( p11, p12 );
    const QLineF line2( p21, p22 );
pixhawk's avatar
pixhawk committed
20

Bryant's avatar
Bryant committed
21 22 23
    QPointF pos;
    if ( line1.intersect( line2, &pos ) == QLineF::NoIntersection )
        return QPointF();
pixhawk's avatar
pixhawk committed
24

Bryant's avatar
Bryant committed
25 26
    return pos;
}
pixhawk's avatar
pixhawk committed
27

Bryant's avatar
Bryant committed
28 29 30 31 32 33 34 35 36 37
class QwtSimpleCompassRose::PrivateData
{
public:
    PrivateData():
        width( 0.2 ),
        numThorns( 8 ),
        numThornLevels( -1 ),
        shrinkFactor( 0.9 )
    {
    }
pixhawk's avatar
pixhawk committed
38

Bryant's avatar
Bryant committed
39 40 41 42 43
    double width;
    int numThorns;
    int numThornLevels;
    double shrinkFactor;
};
pixhawk's avatar
pixhawk committed
44 45 46 47 48 49 50

/*!
   Constructor

   \param numThorns Number of thorns
   \param numThornLevels Number of thorn levels
*/
Bryant's avatar
Bryant committed
51 52
QwtSimpleCompassRose::QwtSimpleCompassRose(
    int numThorns, int numThornLevels )
pixhawk's avatar
pixhawk committed
53
{
Bryant's avatar
Bryant committed
54 55 56 57 58 59
    d_data = new PrivateData();
    d_data->numThorns = numThorns;
    d_data->numThornLevels = numThornLevels;

    const QColor dark( 128, 128, 255 );
    const QColor light( 192, 255, 255 );
60

pixhawk's avatar
pixhawk committed
61
    QPalette palette;
Bryant's avatar
Bryant committed
62 63
    palette.setColor( QPalette::Dark, dark );
    palette.setColor( QPalette::Light, light );
pixhawk's avatar
pixhawk committed
64

Bryant's avatar
Bryant committed
65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92
    setPalette( palette );
}

//! Destructor
QwtSimpleCompassRose::~QwtSimpleCompassRose()
{
    delete d_data;
}

/*!
  Set the Factor how to shrink the thorns with each level
  The default value is 0.9.

  \param factor Shrink factor
  \sa shrinkFactor()
*/
void QwtSimpleCompassRose::setShrinkFactor( double factor )
{
    d_data->shrinkFactor = factor;
}

/*!
  \return Factor how to shrink the thorns with each level
  \sa setShrinkFactor()
*/
double QwtSimpleCompassRose::shrinkFactor() const
{
    return d_data->shrinkFactor;
pixhawk's avatar
pixhawk committed
93 94 95 96 97 98 99 100 101 102 103
}

/*!
   Draw the rose

   \param painter Painter
   \param center Center point
   \param radius Radius of the rose
   \param north Position
   \param cg Color group
*/
Bryant's avatar
Bryant committed
104 105
void QwtSimpleCompassRose::draw( QPainter *painter, const QPointF &center,
    double radius, double north, QPalette::ColorGroup cg ) const
pixhawk's avatar
pixhawk committed
106 107
{
    QPalette pal = palette();
Bryant's avatar
Bryant committed
108 109 110 111
    pal.setCurrentColorGroup( cg );

    drawRose( painter, pal, center, radius, north, d_data->width,
        d_data->numThorns, d_data->numThornLevels, d_data->shrinkFactor );
pixhawk's avatar
pixhawk committed
112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127
}

/*!
   Draw the rose

   \param painter Painter
   \param palette Palette
   \param center Center of the rose
   \param radius Radius of the rose
   \param north Position pointing to north
   \param width Width of the rose
   \param numThorns Number of thorns
   \param numThornLevels Number of thorn levels
   \param shrinkFactor Factor to shrink the thorns with each level
*/
void QwtSimpleCompassRose::drawRose(
128
    QPainter *painter,
pixhawk's avatar
pixhawk committed
129
    const QPalette &palette,
Bryant's avatar
Bryant committed
130 131
    const QPointF &center, double radius, double north, double width,
    int numThorns, int numThornLevels, double shrinkFactor )
pixhawk's avatar
pixhawk committed
132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149
{
    if ( numThorns < 4 )
        numThorns = 4;

    if ( numThorns % 4 )
        numThorns += 4 - numThorns % 4;

    if ( numThornLevels <= 0 )
        numThornLevels = numThorns / 4;

    if ( shrinkFactor >= 1.0 )
        shrinkFactor = 1.0;

    if ( shrinkFactor <= 0.5 )
        shrinkFactor = 0.5;

    painter->save();

Bryant's avatar
Bryant committed
150
    painter->setPen( Qt::NoPen );
pixhawk's avatar
pixhawk committed
151

Bryant's avatar
Bryant committed
152 153 154
    for ( int j = 1; j <= numThornLevels; j++ )
    {
        double step =  qPow( 2.0, j ) * M_PI / numThorns;
pixhawk's avatar
pixhawk committed
155 156 157 158
        if ( step > M_PI_2 )
            break;

        double r = radius;
Bryant's avatar
Bryant committed
159 160
        for ( int k = 0; k < 3; k++ )
        {
pixhawk's avatar
pixhawk committed
161 162 163 164 165 166 167 168
            if ( j + k < numThornLevels )
                r *= shrinkFactor;
        }

        double leafWidth = r * width;
        if ( 2.0 * M_PI / step > 32 )
            leafWidth = 16;

Bryant's avatar
Bryant committed
169
        const double origin = qwtRadians( north );
170
        for ( double angle = origin;
Bryant's avatar
Bryant committed
171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193
            angle < 2.0 * M_PI + origin; angle += step )
        {
            const QPointF p = qwtPolar2Pos( center, r, angle );
            const QPointF p1 = qwtPolar2Pos( center, leafWidth, angle + M_PI_2 );
            const QPointF p2 = qwtPolar2Pos( center, leafWidth, angle - M_PI_2 );
            const QPointF p3 = qwtPolar2Pos( center, r, angle + step / 2.0 );
            const QPointF p4 = qwtPolar2Pos( center, r, angle - step / 2.0 );

            QPainterPath darkPath;
            darkPath.moveTo( center );
            darkPath.lineTo( p );
            darkPath.lineTo( qwtIntersection( center, p3, p1, p ) );

            painter->setBrush( palette.brush( QPalette::Dark ) );
            painter->drawPath( darkPath );

            QPainterPath lightPath;
            lightPath.moveTo( center );
            lightPath.lineTo( p );
            lightPath.lineTo( qwtIntersection( center, p4, p2, p ) );

            painter->setBrush( palette.brush( QPalette::Light ) );
            painter->drawPath( lightPath );
pixhawk's avatar
pixhawk committed
194 195 196 197 198 199 200 201 202 203 204
        }
    }
    painter->restore();
}

/*!
   Set the width of the rose heads. Lower value make thinner heads.
   The range is limited from 0.03 to 0.4.

   \param width Width
*/
Bryant's avatar
Bryant committed
205
void QwtSimpleCompassRose::setWidth( double width )
pixhawk's avatar
pixhawk committed
206
{
Bryant's avatar
Bryant committed
207 208 209 210 211 212 213
    d_data->width = width;
    if ( d_data->width < 0.03 )
        d_data->width = 0.03;

    if ( d_data->width > 0.4 )
        d_data->width = 0.4;
}
pixhawk's avatar
pixhawk committed
214

Bryant's avatar
Bryant committed
215 216 217 218 219 220 221
/*! 
  \return Width of the rose
  \sa setWidth()
 */
double QwtSimpleCompassRose::width() const
{
    return d_data->width;
pixhawk's avatar
pixhawk committed
222 223 224 225
}

/*!
  Set the number of thorns on one level
226
  The number is aligned to a multiple of 4, with a minimum of 4
pixhawk's avatar
pixhawk committed
227 228 229 230

  \param numThorns Number of thorns
  \sa numThorns(), setNumThornLevels()
*/
Bryant's avatar
Bryant committed
231
void QwtSimpleCompassRose::setNumThorns( int numThorns )
pixhawk's avatar
pixhawk committed
232 233 234 235 236 237 238
{
    if ( numThorns < 4 )
        numThorns = 4;

    if ( numThorns % 4 )
        numThorns += 4 - numThorns % 4;

Bryant's avatar
Bryant committed
239
    d_data->numThorns = numThorns;
pixhawk's avatar
pixhawk committed
240 241 242 243 244 245 246 247
}

/*!
   \return Number of thorns
   \sa setNumThorns(), setNumThornLevels()
*/
int QwtSimpleCompassRose::numThorns() const
{
Bryant's avatar
Bryant committed
248
    return d_data->numThorns;
pixhawk's avatar
pixhawk committed
249 250 251 252 253 254 255 256
}

/*!
  Set the of thorns levels

  \param numThornLevels Number of thorns levels
  \sa setNumThorns(), numThornLevels()
*/
Bryant's avatar
Bryant committed
257
void QwtSimpleCompassRose::setNumThornLevels( int numThornLevels )
pixhawk's avatar
pixhawk committed
258
{
Bryant's avatar
Bryant committed
259
    d_data->numThornLevels = numThornLevels;
pixhawk's avatar
pixhawk committed
260 261 262 263 264 265 266 267
}

/*!
   \return Number of thorn levels
   \sa setNumThorns(), setNumThornLevels()
*/
int QwtSimpleCompassRose::numThornLevels() const
{
Bryant's avatar
Bryant committed
268
    return d_data->numThornLevels;
pixhawk's avatar
pixhawk committed
269
}