/*!
  Draw dots

  \param painter Painter
  \param xMap x map
  \param yMap y map
  \param canvasRect Contents rectangle of the canvas
  \param from index of the first point to be painted
  \param to index of the last point to be painted

  \sa draw(), drawCurve(), drawSticks(), drawLines(), drawSteps()
*/
void QwtPlotCurve::drawDots( QPainter *painter,
    const QwtScaleMap &xMap, const QwtScaleMap &yMap,
    const QRectF &canvasRect, int from, int to ) const
{
    const QColor color = painter->pen().color();

    if ( painter->pen().style() == Qt::NoPen || color.alpha() == 0 )
    {
        return;
    }

    const bool doFill = ( d_data->brush.style() != Qt::NoBrush )
            && ( d_data->brush.color().alpha() > 0 );
    const bool doAlign = QwtPainter::roundingAlignment( painter );

    QwtPointMapper mapper;
    mapper.setBoundingRect( canvasRect );
    mapper.setFlag( QwtPointMapper::RoundPoints, doAlign );

    if ( d_data->paintAttributes & FilterPoints )
    {
        if ( ( color.alpha() == 255 )
            && !( painter->renderHints() & QPainter::Antialiasing ) )
        {
            mapper.setFlag( QwtPointMapper::WeedOutPoints, true );
        }
    }

    if ( doFill )
    {
        mapper.setFlag( QwtPointMapper::WeedOutPoints, false );

        QPolygonF points = mapper.toPointsF( 
            xMap, yMap, data(), from, to );

        QwtPainter::drawPoints( painter, points );
        fillCurve( painter, xMap, yMap, canvasRect, points );
    }
    else if ( d_data->paintAttributes & ImageBuffer )
    {
        const QImage image = mapper.toImage( xMap, yMap,
            data(), from, to, d_data->pen, 
            painter->testRenderHint( QPainter::Antialiasing ),
            renderThreadCount() );

        painter->drawImage( canvasRect.toAlignedRect(), image );
    }
    else if ( d_data->paintAttributes & MinimizeMemory )
    {
        const QwtSeriesData<QPointF> *series = data();

        for ( int i = from; i <= to; i++ )
        {
            const QPointF sample = series->sample( i );

            double xi = xMap.transform( sample.x() );
            double yi = yMap.transform( sample.y() );

            if ( doAlign )
            {
                xi = qRound( xi );
                yi = qRound( yi );
            }

            QwtPainter::drawPoint( painter, QPointF( xi, yi ) );
        }
    }
    else
    {
        if ( doAlign )
        {
            const QPolygon points = mapper.toPoints(
                xMap, yMap, data(), from, to ); 

            QwtPainter::drawPoints( painter, points );
        }
        else
        {
            const QPolygonF points = mapper.toPointsF( 
                xMap, yMap, data(), from, to );

            QwtPainter::drawPoints( painter, points );
        }
    }
}
QImage QwtPlotRasterItem::compose( 
    const QwtScaleMap &xMap, const QwtScaleMap &yMap,
    const QRectF &imageArea, const QRectF &paintRect, 
    const QSize &imageSize, bool doCache) const
{
    QImage image;
    if ( imageArea.isEmpty() || paintRect.isEmpty() || imageSize.isEmpty() )
        return image;

    if ( doCache )
    {
        if ( !d_data->cache.image.isNull()
            && d_data->cache.area == imageArea
            && d_data->cache.size == paintRect.size() )
        {
            image = d_data->cache.image;
        }
    }

    if ( image.isNull() )
    {
        double dx = 0.0;
        if ( paintRect.toRect().width() > imageSize.width() )
            dx = imageArea.width() / imageSize.width();

        const QwtScaleMap xxMap = 
            imageMap(Qt::Horizontal, xMap, imageArea, imageSize, dx);
        
        double dy = 0.0;
        if ( paintRect.toRect().height() > imageSize.height() )
            dy = imageArea.height() / imageSize.height();

        const QwtScaleMap yyMap = 
            imageMap(Qt::Vertical, yMap, imageArea, imageSize, dy);

        image = renderImage( xxMap, yyMap, imageArea, imageSize );

        if ( doCache )
        {
            d_data->cache.area = imageArea;
            d_data->cache.size = paintRect.size();
            d_data->cache.image = image;
        }
    }

    if ( d_data->alpha >= 0 && d_data->alpha < 255 )
    {
        QImage alphaImage( image.size(), QImage::Format_ARGB32 );

#if QT_VERSION >= 0x040400 && !defined(QT_NO_QFUTURE)
        uint numThreads = renderThreadCount();

        if ( numThreads <= 0 )
            numThreads = QThread::idealThreadCount();

        if ( numThreads <= 0 )
            numThreads = 1;

        const int numRows = image.height() / numThreads;

        QList< QFuture<void> > futures;
        for ( uint i = 0; i < numThreads; i++ )
        {
            QRect tile( 0, i * numRows, image.width(), numRows );
            if ( i == numThreads - 1 )
            {
                tile.setHeight( image.height() - i * numRows );
                qwtToRgba( &image, &alphaImage, tile, d_data->alpha );
            }
            else
            {
                futures += QtConcurrent::run(
                    &qwtToRgba, &image, &alphaImage, tile, d_data->alpha );
            }
        }
        for ( int i = 0; i < futures.size(); i++ )
            futures[i].waitForFinished();
#else
        const QRect tile( 0, 0, image.width(), image.height() );
        qwtToRgba( &image, &alphaImage, tile, d_data->alpha );
#endif
        image = alphaImage;
    }

    return image;
}
/*!
   \brief Render an image from data and color map.

   For each pixel of area the value is mapped into a color.

  \param xMap X-Scale Map
  \param yMap Y-Scale Map
  \param area Requested area for the image in scale coordinates
  \param imageSize Size of the requested image

   \return A QImage::Format_Indexed8 or QImage::Format_ARGB32 depending
           on the color map.

   \sa QwtRasterData::value(), QwtColorMap::rgb(),
       QwtColorMap::colorIndex()
*/
QImage QwtPlotSpectrogram::renderImage(
    const QwtScaleMap &xMap, const QwtScaleMap &yMap,
    const QRectF &area, const QSize &imageSize ) const
{
    if ( imageSize.isEmpty() || d_data->data == NULL 
        || d_data->colorMap == NULL )
    {
        return QImage();
    }

    const QwtInterval intensityRange = d_data->data->interval( Qt::ZAxis );
    if ( !intensityRange.isValid() )
        return QImage();

    QImage::Format format = ( d_data->colorMap->format() == QwtColorMap::RGB )
        ? QImage::Format_ARGB32 : QImage::Format_Indexed8;

    QImage image( imageSize, format );

    if ( d_data->colorMap->format() == QwtColorMap::Indexed )
        image.setColorTable( d_data->colorMap->colorTable( intensityRange ) );

    d_data->data->initRaster( area, image.size() );

#if QT_VERSION >= 0x040400 && !defined(QT_NO_QFUTURE)
    uint numThreads = renderThreadCount();

    if ( numThreads <= 0 )
        numThreads = QThread::idealThreadCount();

    if ( numThreads <= 0 )
        numThreads = 1;

    const int numRows = imageSize.height() / numThreads;

    QList< QFuture<void> > futures;
    for ( uint i = 0; i < numThreads; i++ )
    {
        QRect tile( 0, i * numRows, image.width(), numRows );
        if ( i == numThreads - 1 )
        {
            tile.setHeight( image.height() - i * numRows );
            renderTile( xMap, yMap, tile, &image );
        }
        else
        {
            futures += QtConcurrent::run(
                this, &QwtPlotSpectrogram::renderTile,
                xMap, yMap, tile, &image );
        }
    }
    for ( int i = 0; i < futures.size(); i++ )
        futures[i].waitForFinished();

#else // QT_VERSION < 0x040400
    const QRect tile( 0, 0, image.width(), image.height() );
    renderTile( xMap, yMap, tile, &image );
#endif

    d_data->data->discardRaster();

    return image;
}
/*!
   \brief Render an image from the data and color map.

   The area is translated into a rect of the paint device.
   For each pixel of this rect the intensity is mapped
   into a color.

  \param azimuthMap Maps azimuth values to values related to 0.0, M_2PI
  \param radialMap Maps radius values into painter coordinates.
  \param pole Position of the pole in painter coordinates
  \param rect Target rectangle of the image in painter coordinates

   \return A QImage::Format_Indexed8 or QImage::Format_ARGB32 depending
           on the color map.

   \sa QwtRasterData::intensity(), QwtColorMap::rgb(),
       QwtColorMap::colorIndex()
*/
QImage QwtPolarSpectrogram::renderImage(
    const QwtScaleMap &azimuthMap, const QwtScaleMap &radialMap,
    const QPointF &pole, const QRect &rect ) const
{
    if ( d_data->data == NULL || d_data->colorMap == NULL )
        return QImage();

    QImage image( rect.size(), d_data->colorMap->format() == QwtColorMap::RGB
                  ? QImage::Format_ARGB32 : QImage::Format_Indexed8 );

    const QwtInterval intensityRange = d_data->data->interval( Qt::ZAxis );
    if ( !intensityRange.isValid() )
        return image;

    if ( d_data->colorMap->format() == QwtColorMap::Indexed )
        image.setColorTable( d_data->colorMap->colorTable( intensityRange ) );

    /*
     For the moment we only announce the composition of the image by
     calling initRaster(), but we don't pass any useful parameters.
     ( How to map rect into something, that is useful to initialize a matrix
       of values in polar coordinates ? )
     */
    d_data->data->initRaster( QRectF(), QSize() );


#if QT_VERSION >= 0x040400 && !defined(QT_NO_QFUTURE)
    uint numThreads = renderThreadCount();

    if ( numThreads <= 0 )
        numThreads = QThread::idealThreadCount();

    if ( numThreads <= 0 )
        numThreads = 1;

    const int numRows = rect.height() / numThreads;


    QVector<TileInfo> tileInfos;
    for ( uint i = 0; i < numThreads; i++ )
    {
        QRect tile( rect.x(), rect.y() + i * numRows, rect.width(), numRows );
        if ( i == numThreads - 1 )
            tile.setHeight( rect.height() - i * numRows );

        TileInfo tileInfo;
        tileInfo.imagePos = rect.topLeft();
        tileInfo.rect = tile;
        tileInfo.image = &image;

        tileInfos += tileInfo;
    }

    QVector< QFuture<void> > futures;
    for ( int i = 0; i < tileInfos.size(); i++ )
    {
        if ( i == tileInfos.size() - 1 )
        {
            renderTile( azimuthMap, radialMap, pole, &tileInfos[i] );
        }
        else
        {
            futures += QtConcurrent::run( this, &QwtPolarSpectrogram::renderTile,
                azimuthMap, radialMap, pole, &tileInfos[i] );
        }
    }
    for ( int i = 0; i < futures.size(); i++ )
        futures[i].waitForFinished();

#else // QT_VERSION < 0x040400
    renderTile( azimuthMap, radialMap, pole, rect.topLeft(), rect, &image );
#endif

    d_data->data->discardRaster();

    return image;
}