10#include "qwt_point_mapper.h" 
   11#include "qwt_scale_map.h" 
   12#include "qwt_pixel_matrix.h" 
   13#include "qwt_series_data.h" 
   23#include <qtconcurrentrun.h> 
   25#if !defined( QT_NO_QFUTURE ) 
   26#define QWT_USE_THREADS 1 
   29static QRectF qwtInvalidRect( 0.0, 0.0, -1.0, -1.0 );
 
   31static inline int qwtRoundValue( 
double value )
 
   33    return qRound( value );
 
   36static inline double qwtRoundValueF( 
double value )
 
   40    return ( value >= 0.0 ) ? std::floor( value + 0.5 ) : std::ceil( value - 0.5 );
 
   42    return nearbyint( value );
 
   46static Qt::Orientation qwtProbeOrientation(
 
   52        return Qt::Horizontal;
 
   55    const double x0 = series->
sample( from ).x();
 
   56    const double xn = series->
sample( to ).x();
 
   61    const int step = ( to - from ) / 10;
 
   62    const bool isIncreasing = xn > x0;
 
   65    for ( 
int i = from + step; i < to; i += step )
 
   67        const double x2 = series->
sample( i ).x();
 
   70            if ( ( x2 > x1 ) != isIncreasing )
 
   77    return Qt::Horizontal;
 
   82    template< 
class Polygon, 
class Po
int >
 
   83    class QwtPolygonQuadrupelX
 
   86        inline void start( 
int x, 
int y )
 
   89            m_y1 = m_yMin = m_yMax = m_y2 = y;
 
   92        inline bool append( 
int x, 
int y )
 
   99            else if ( y > m_yMax )
 
  107        inline void flush( Polygon& polyline )
 
  109            appendTo( m_y1, polyline );
 
  112                qSwap( m_yMin, m_yMax );
 
  114            if ( m_yMax != m_y1 )
 
  115                appendTo( m_yMax, polyline );
 
  117            if ( m_yMin != m_yMax )
 
  118                appendTo( m_yMin, polyline );
 
  120            if ( m_y2 != m_yMin )
 
  121                appendTo( m_y2, polyline );
 
  125        inline void appendTo( 
int y, Polygon& polyline )
 
  127            polyline += Point( m_x0, y );
 
  131        int m_x0, m_y1, m_yMin, m_yMax, m_y2;
 
  134    template< 
class Polygon, 
class Po
int >
 
  135    class QwtPolygonQuadrupelY
 
  138        inline void start( 
int x, 
int y )
 
  141            m_x1 = m_xMin = m_xMax = m_x2 = x;
 
  144        inline bool append( 
int x, 
int y )
 
  151            else if ( x > m_xMax )
 
  159        inline void flush( Polygon& polyline )
 
  161            appendTo( m_x1, polyline );
 
  164                qSwap( m_xMin, m_xMax );
 
  166            if ( m_xMax != m_x1 )
 
  167                appendTo( m_xMax, polyline );
 
  169            if ( m_xMin != m_xMax )
 
  170                appendTo( m_xMin, polyline );
 
  172            if ( m_x2 != m_xMin )
 
  173                appendTo( m_x2, polyline );
 
  177        inline void appendTo( 
int x, Polygon& polyline )
 
  179            polyline += Point( x, m_y0 );
 
  182        int m_y0, m_x1, m_xMin, m_xMax, m_x2;
 
  186template< 
class Polygon, 
class Po
int, 
class PolygonQuadrupel >
 
  190    const QPointF sample0 = series->
sample( from );
 
  193    q.start( qwtRoundValue( xMap.
transform( sample0.x() ) ),
 
  194        qwtRoundValue( yMap.
transform( sample0.y() ) ) );
 
  197    for ( 
int i = from; i <= to; i++ )
 
  199        const QPointF sample = series->
sample( i );
 
  201        const int x = qwtRoundValue( xMap.
transform( sample.x() ) );
 
  202        const int y = qwtRoundValue( yMap.
transform( sample.y() ) );
 
  204        if ( !q.append( x, y ) )
 
  215template< 
class Polygon, 
class Po
int, 
class PolygonQuadrupel >
 
  216static Polygon qwtMapPointsQuad( 
const Polygon& polyline )
 
  218    const int numPoints = polyline.size();
 
  223    const Point* points = polyline.constData();
 
  228    q.start( points[0].x(), points[0].y() );
 
  230    for ( 
int i = 0; i < numPoints; i++ )
 
  232        const int x = points[i].x();
 
  233        const int y = points[i].y();
 
  235        if ( !q.append( x, y ) )
 
  237            q.flush( polylineXY );
 
  241    q.flush( polylineXY );
 
  247template< 
class Polygon, 
class Po
int >
 
  259    const Qt::Orientation orientation = qwtProbeOrientation( series, from, to );
 
  261    if ( orientation == Qt::Horizontal )
 
  263        polyline = qwtMapPointsQuad< Polygon, Point,
 
  264            QwtPolygonQuadrupelY< Polygon, Point > >( xMap, yMap, series, from, to );
 
  266        polyline = qwtMapPointsQuad< Polygon, Point,
 
  267            QwtPolygonQuadrupelX< Polygon, Point > >( polyline );
 
  271        polyline = qwtMapPointsQuad< Polygon, Point,
 
  272            QwtPolygonQuadrupelX< Polygon, Point > >( xMap, yMap, series, from, to );
 
  274        polyline = qwtMapPointsQuad< Polygon, Point,
 
  275            QwtPolygonQuadrupelY< Polygon, Point > >( polyline );
 
  292static void qwtRenderDots(
 
  294    const QwtDotsCommand& command, 
const QPoint& pos, QImage* image )
 
  296    const QRgb rgb = command.rgb;
 
  297    QRgb* bits = 
reinterpret_cast< QRgb* 
>( image->bits() );
 
  299    const int w = image->width();
 
  300    const int h = image->height();
 
  302    const int x0 = pos.x();
 
  303    const int y0 = pos.y();
 
  305    for ( 
int i = command.from; i <= command.to; i++ )
 
  307        const QPointF sample = command.series->
sample( i );
 
  309        const int x = 
static_cast< int >( xMap.
transform( sample.x() ) + 0.5 ) - x0;
 
  310        const int y = 
static_cast< int >( yMap.
transform( sample.y() ) + 0.5 ) - y0;
 
  312        if ( x >= 0 && x < w && y >= 0 && y < h )
 
  313            bits[ y * w + x ] = rgb;
 
  320    inline int operator()( 
double value )
 const 
  322        return qwtRoundValue( value );
 
  328    inline double operator()( 
double value )
 const 
  330        return qwtRoundValueF( value );
 
  336    inline double operator()( 
double value )
 const 
  345template< 
class Polygon, 
class Po
int, 
class Round >
 
  346static inline Polygon qwtToPoints(
 
  347    const QRectF& boundingRect,
 
  350    int from, 
int to, Round round )
 
  352    Polygon polyline( to - from + 1 );
 
  353    Point* points = polyline.data();
 
  357    if ( boundingRect.isValid() )
 
  363        for ( 
int i = from; i <= to; i++ )
 
  365            const QPointF sample = series->
sample( i );
 
  367            const double x = xMap.
transform( sample.x() );
 
  368            const double y = yMap.
transform( sample.y() );
 
  370            if ( boundingRect.contains( x, y ) )
 
  372                points[ numPoints ].rx() = round( x );
 
  373                points[ numPoints ].ry() = round( y );
 
  379        polyline.resize( numPoints );
 
  386        for ( 
int i = from; i <= to; i++ )
 
  388            const QPointF sample = series->
sample( i );
 
  390            const double x = xMap.
transform( sample.x() );
 
  391            const double y = yMap.
transform( sample.y() );
 
  393            points[ numPoints ].rx() = round( x );
 
  394            points[ numPoints ].ry() = round( y );
 
  403static inline QPolygon qwtToPointsI(
 
  404    const QRectF& boundingRect,
 
  409    return qwtToPoints< QPolygon, QPoint >(
 
  410        boundingRect, xMap, yMap, series, from, to, QwtRoundI() );
 
  413template< 
class Round >
 
  414static inline QPolygonF qwtToPointsF(
 
  415    const QRectF& boundingRect,
 
  418    int from, 
int to, Round round )
 
  420    return qwtToPoints< QPolygonF, QPointF >(
 
  421        boundingRect, xMap, yMap, series, from, to, round );
 
  427template< 
class Polygon, 
class Po
int, 
class Round >
 
  428static inline Polygon qwtToPolylineFiltered(
 
  431    int from, 
int to, Round round )
 
  438    Polygon polyline( to - from + 1 );
 
  439    Point* points = polyline.data();
 
  441    const QPointF sample0 = series->
sample( from );
 
  443    points[0].rx() = round( xMap.
transform( sample0.x() ) );
 
  444    points[0].ry() = round( yMap.
transform( sample0.y() ) );
 
  447    for ( 
int i = from + 1; i <= to; i++ )
 
  449        const QPointF sample = series->
sample( i );
 
  451        const Point p( round( xMap.
transform( sample.x() ) ),
 
  454        if ( points[pos] != p )
 
  458    polyline.resize( pos + 1 );
 
  462static inline QPolygon qwtToPolylineFilteredI(
 
  467    return qwtToPolylineFiltered< QPolygon, QPoint >(
 
  468        xMap, yMap, series, from, to, QwtRoundI() );
 
  471template< 
class Round >
 
  472static inline QPolygonF qwtToPolylineFilteredF(
 
  475    int from, 
int to, Round round )
 
  477    return qwtToPolylineFiltered< QPolygonF, QPointF >(
 
  478        xMap, yMap, series, from, to, round );
 
  481template< 
class Polygon, 
class Po
int >
 
  482static inline Polygon qwtToPointsFiltered(
 
  483    const QRectF& boundingRect,
 
  490    Polygon polygon( to - from + 1 );
 
  491    Point* points = polygon.data();
 
  496    for ( 
int i = from; i <= to; i++ )
 
  498        const QPointF sample = series->
sample( i );
 
  500        const int x = qwtRoundValue( xMap.
transform( sample.x() ) );
 
  501        const int y = qwtRoundValue( yMap.
transform( sample.y() ) );
 
  503        if ( pixelMatrix.testAndSetPixel( x, y, 
true ) == 
false )
 
  505            points[ numPoints ].rx() = x;
 
  506            points[ numPoints ].ry() = y;
 
  512    polygon.resize( numPoints );
 
  516static inline QPolygon qwtToPointsFilteredI(
 
  517    const QRectF& boundingRect,
 
  521    return qwtToPointsFiltered< QPolygon, QPoint >(
 
  522        boundingRect, xMap, yMap, series, from, to );
 
  525static inline QPolygonF qwtToPointsFilteredF(
 
  526    const QRectF& boundingRect,
 
  530    return qwtToPointsFiltered< QPolygonF, QPointF >(
 
  531        boundingRect, xMap, yMap, series, from, to );
 
  534class QwtPointMapper::PrivateData
 
  538        : boundingRect( qwtInvalidRect )
 
  549    m_data = 
new PrivateData();
 
 
  566    m_data->flags = 
flags;
 
 
  575    return m_data->flags;
 
 
  589        m_data->flags |= flag;
 
  591        m_data->flags &= ~flag;
 
 
  601    return m_data->flags & flag;
 
 
  614    m_data->boundingRect = rect;
 
 
  623    return m_data->boundingRect;
 
 
  657            polyline = qwtMapPointsQuad< QPolygonF, QPointF >(
 
  658                xMap, yMap, series, from, to );
 
  662            polyline = qwtToPolylineFilteredF(
 
  663                xMap, yMap, series, from, to, QwtRoundF() );
 
  667            polyline = qwtToPointsF( qwtInvalidRect,
 
  668                xMap, yMap, series, from, to, QwtRoundF() );
 
  675            polyline = qwtToPolylineFilteredF(
 
  676                xMap, yMap, series, from, to, QwtNoRoundF() );
 
  680            polyline = qwtToPointsF( qwtInvalidRect,
 
  681                xMap, yMap, series, from, to, QwtNoRoundF() );
 
 
  711        polyline = qwtMapPointsQuad< QPolygon, QPoint >(
 
  712            xMap, yMap, series, from, to );
 
  716        polyline = qwtToPolylineFilteredI(
 
  717            xMap, yMap, series, from, to );
 
  721        polyline = qwtToPointsI(
 
  722            qwtInvalidRect, xMap, yMap, series, from, to );
 
 
  769            if ( m_data->boundingRect.isValid() )
 
  771                points = qwtToPointsFilteredF( m_data->boundingRect,
 
  772                    xMap, yMap, series, from, to );
 
  780                points = qwtToPolylineFilteredF(
 
  781                    xMap, yMap, series, from, to, QwtRoundF() );
 
  789            points = qwtToPolylineFilteredF(
 
  790                xMap, yMap, series, from, to, QwtNoRoundF() );
 
  797            points = qwtToPointsF( m_data->boundingRect,
 
  798                xMap, yMap, series, from, to, QwtRoundF() );
 
  802            points = qwtToPointsF( m_data->boundingRect,
 
  803                xMap, yMap, series, from, to, QwtNoRoundF() );
 
 
  841        if ( m_data->boundingRect.isValid() )
 
  843            points = qwtToPointsFilteredI( m_data->boundingRect,
 
  844                xMap, yMap, series, from, to );
 
  851            points = qwtToPolylineFilteredI(
 
  852                xMap, yMap, series, from, to );
 
  857        points = qwtToPointsI(
 
  858            m_data->boundingRect, xMap, yMap, series, from, to );
 
 
  886    const QPen& pen, 
bool antialiased, uint numThreads )
 const 
  888    Q_UNUSED( antialiased )
 
  891    if ( numThreads == 0 )
 
  892        numThreads = QThread::idealThreadCount();
 
  894    if ( numThreads <= 0 )
 
  897    Q_UNUSED( numThreads )
 
  903    const QRect rect = m_data->boundingRect.toAlignedRect();
 
  905    QImage image( rect.size(), QImage::Format_ARGB32 );
 
  906    image.fill( Qt::transparent );
 
  908    if ( pen.width() <= 1 && pen.color().alpha() == 255 )
 
  910        QwtDotsCommand command;
 
  911        command.series = series;
 
  912        command.rgb = pen.color().rgba();
 
  915        const int numPoints = ( to - from + 1 ) / numThreads;
 
  918        for ( uint i = 0; i < numThreads; i++ )
 
  920            const QPoint pos = rect.topLeft();
 
  922            const int index0 = from + i * numPoints;
 
  923            if ( i == numThreads - 1 )
 
  925                command.from = index0;
 
  928                qwtRenderDots( xMap, yMap, command, pos, &image );
 
  932                command.from = index0;
 
  933                command.to = index0 + numPoints - 1;
 
  935                futures += QtConcurrent::run( &qwtRenderDots,
 
  936                    xMap, yMap, command, pos, &image );
 
  939        for ( 
int i = 0; i < futures.size(); i++ )
 
  940            futures[i].waitForFinished();
 
  945        qwtRenderDots( xMap, yMap, command, rect.topLeft(), &image );
 
  953        QPainter painter( &image );
 
  954        painter.setPen( pen );
 
  955        painter.setRenderHint( QPainter::Antialiasing, antialiased );
 
  957        const int chunkSize = 1000;
 
  958        for ( 
int i = from; i <= to; i += chunkSize )
 
  960            const int indexTo = qMin( i + chunkSize - 1, to );
 
  962                xMap, yMap, series, i, indexTo );
 
  964            painter.drawPoints( points );
 
 
A bit field corresponding to the pixels of a rectangle.
void setBoundingRect(const QRectF &)
QRectF boundingRect() const
QPolygonF toPolygonF(const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QwtSeriesData< QPointF > *series, int from, int to) const
Translate a series of points into a QPolygonF.
TransformationFlags flags() const
QImage toImage(const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QwtSeriesData< QPointF > *series, int from, int to, const QPen &, bool antialiased, uint numThreads) const
Translate a series into a QImage.
bool testFlag(TransformationFlag) const
QPolygonF toPointsF(const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QwtSeriesData< QPointF > *series, int from, int to) const
Translate a series into a QPolygonF.
void setFlag(TransformationFlag, bool on=true)
QwtPointMapper()
Constructor.
~QwtPointMapper()
Destructor.
TransformationFlag
Flags affecting the transformation process.
@ RoundPoints
Round points to integer values.
@ WeedOutIntermediatePoints
QPolygon toPolygon(const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QwtSeriesData< QPointF > *series, int from, int to) const
Translate a series of points into a QPolygon.
void setFlags(TransformationFlags)
QFlags< TransformationFlag > TransformationFlags
QPolygon toPoints(const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QwtSeriesData< QPointF > *series, int from, int to) const
Translate a series of points into a QPolygon.
double transform(double s) const
virtual T sample(size_t i) const =0