Skip to content
qwt_compass_rose.cpp 6.47 KiB
Newer Older
pixhawk's avatar
pixhawk committed
/* -*- 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
#include "qwt_point_polar.h"
#include "qwt_painter.h"
#include <qpainter.h>
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
static QPointF qwtIntersection( 
    QPointF p11, QPointF p12, QPointF p21, QPointF p22 )
pixhawk's avatar
pixhawk committed
{
Bryant's avatar
Bryant committed
    const QLineF line1( p11, p12 );
    const QLineF line2( p21, p22 );
pixhawk's avatar
pixhawk committed

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

Bryant's avatar
Bryant committed
    return pos;
}
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
class QwtSimpleCompassRose::PrivateData
{
public:
    PrivateData():
        width( 0.2 ),
        numThorns( 8 ),
        numThornLevels( -1 ),
        shrinkFactor( 0.9 )
    {
    }
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
    double width;
    int numThorns;
    int numThornLevels;
    double shrinkFactor;
};
pixhawk's avatar
pixhawk committed

/*!
   Constructor

   \param numThorns Number of thorns
   \param numThornLevels Number of thorn levels
*/
Bryant's avatar
Bryant committed
QwtSimpleCompassRose::QwtSimpleCompassRose(
    int numThorns, int numThornLevels )
pixhawk's avatar
pixhawk committed
{
Bryant's avatar
Bryant committed
    d_data = new PrivateData();
    d_data->numThorns = numThorns;
    d_data->numThornLevels = numThornLevels;

    const QColor dark( 128, 128, 255 );
    const QColor light( 192, 255, 255 );
pixhawk's avatar
pixhawk committed
    QPalette palette;
Bryant's avatar
Bryant committed
    palette.setColor( QPalette::Dark, dark );
    palette.setColor( QPalette::Light, light );
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
    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
}

/*!
   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
void QwtSimpleCompassRose::draw( QPainter *painter, const QPointF &center,
    double radius, double north, QPalette::ColorGroup cg ) const
pixhawk's avatar
pixhawk committed
{
    QPalette pal = palette();
Bryant's avatar
Bryant committed
    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
}

/*!
   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(
    QPainter *painter,
pixhawk's avatar
pixhawk committed
    const QPalette &palette,
Bryant's avatar
Bryant committed
    const QPointF &center, double radius, double north, double width,
    int numThorns, int numThornLevels, double shrinkFactor )
pixhawk's avatar
pixhawk committed
{
    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
    painter->setPen( Qt::NoPen );
pixhawk's avatar
pixhawk committed

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

        double r = radius;
Bryant's avatar
Bryant committed
        for ( int k = 0; k < 3; k++ )
        {
pixhawk's avatar
pixhawk committed
            if ( j + k < numThornLevels )
                r *= shrinkFactor;
        }

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

Bryant's avatar
Bryant committed
        const double origin = qwtRadians( north );
        for ( double angle = origin;
Bryant's avatar
Bryant committed
            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
        }
    }
    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
void QwtSimpleCompassRose::setWidth( double width )
pixhawk's avatar
pixhawk committed
{
Bryant's avatar
Bryant committed
    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

Bryant's avatar
Bryant committed
/*! 
  \return Width of the rose
  \sa setWidth()
 */
double QwtSimpleCompassRose::width() const
{
    return d_data->width;
pixhawk's avatar
pixhawk committed
}

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

  \param numThorns Number of thorns
  \sa numThorns(), setNumThornLevels()
*/
Bryant's avatar
Bryant committed
void QwtSimpleCompassRose::setNumThorns( int numThorns )
pixhawk's avatar
pixhawk committed
{
    if ( numThorns < 4 )
        numThorns = 4;

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

Bryant's avatar
Bryant committed
    d_data->numThorns = numThorns;
pixhawk's avatar
pixhawk committed
}

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

/*!
  Set the of thorns levels

  \param numThornLevels Number of thorns levels
  \sa setNumThorns(), numThornLevels()
*/
Bryant's avatar
Bryant committed
void QwtSimpleCompassRose::setNumThornLevels( int numThornLevels )
pixhawk's avatar
pixhawk committed
{
Bryant's avatar
Bryant committed
    d_data->numThornLevels = numThornLevels;
pixhawk's avatar
pixhawk committed
}

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