qwt_point_mapper.cpp
Go to the documentation of this file.
00001 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
00002  * Qwt Widget Library
00003  * Copyright (C) 1997   Josef Wilgen
00004  * Copyright (C) 2002   Uwe Rathmann
00005  *
00006  * This library is free software; you can redistribute it and/or
00007  * modify it under the terms of the Qwt License, Version 1.0
00008  *****************************************************************************/
00009 
00010 #include "qwt_point_mapper.h"
00011 #include "qwt_scale_map.h"
00012 #include "qwt_pixel_matrix.h"
00013 #include <qpolygon.h>
00014 #include <qimage.h>
00015 #include <qpen.h>
00016 #include <qpainter.h>
00017 
00018 #include <qthread.h>
00019 #include <qfuture.h>
00020 #include <qtconcurrentrun.h>
00021 
00022 #if !defined(QT_NO_QFUTURE)
00023 #define QWT_USE_THREADS 0
00024 #endif
00025 
00026 static QRectF qwtInvalidRect( 0.0, 0.0, -1.0, -1.0 );
00027 
00028 static inline int qwtRoundValue( double value )
00029 {
00030     return qRound( value );
00031 }
00032 
00033 static inline double qwtRoundValueF( double value )
00034 {
00035 #if 1
00036     // MS Windows and at least IRIX does not have C99's nearbyint() function
00037     return ( value >= 0.0 ) ? ::floor( value + 0.5 ) : ::ceil( value - 0.5 );
00038 #else
00039     return nearbyint( value );
00040 #endif
00041 }
00042 
00043 static Qt::Orientation qwtProbeOrientation(
00044     const QwtSeriesData<QPointF> *series, int from, int to )
00045 {
00046     if ( to - from < 20 )
00047     {
00048         // not enough points to "have an orientation"
00049         return Qt::Horizontal;
00050     }
00051 
00052     const double x0 = series->sample( from ).x();
00053     const double xn = series->sample( to ).x();
00054 
00055     if ( x0 == xn )
00056         return Qt::Vertical;
00057 
00058     const int step = ( to - from ) / 10;
00059     const bool isIncreasing = xn > x0;
00060 
00061     double x1 = x0;
00062     for ( int i = from + step; i < to; i += step )
00063     {
00064         const double x2 = series->sample( i ).x();
00065         if ( x2 != x1 )
00066         {
00067             if ( ( x2 > x1 ) != isIncreasing )
00068                 return Qt::Vertical;
00069         }
00070 
00071         x1 = x2;
00072     }
00073 
00074     return Qt::Horizontal;
00075 }
00076 
00077 template <class Polygon, class Point>
00078 class QwtPolygonQuadrupelX
00079 {
00080 public:
00081     inline void start( int x, int y )
00082     {
00083         x0 = x;
00084         y1 = yMin = yMax = y2 = y;
00085     }
00086 
00087     inline bool append( int x, int y )
00088     {
00089         if ( x0 != x )
00090             return false;
00091 
00092         if ( y < yMin )
00093             yMin = y;
00094         else if ( y > yMax )
00095             yMax = y;
00096 
00097         y2 = y;
00098 
00099         return true;
00100     }
00101 
00102     inline void flush( Polygon &polyline )
00103     {
00104         appendTo( y1, polyline );
00105 
00106         if ( y2 > y1 )
00107             qSwap( yMin, yMax );
00108 
00109         if ( yMax != y1 )
00110             appendTo( yMax, polyline );
00111 
00112         if ( yMin != yMax )
00113             appendTo( yMin, polyline );
00114 
00115         if ( y2 != yMin )
00116             appendTo( y2, polyline );
00117     }
00118 
00119 private:
00120     inline void appendTo( int y, Polygon &polyline )
00121     {
00122         polyline += Point( x0, y );
00123     }
00124 
00125 private:
00126     int x0, y1, yMin, yMax, y2;
00127 };
00128 
00129 template <class Polygon, class Point>
00130 class QwtPolygonQuadrupelY
00131 {
00132 public:
00133     inline void start( int x, int y )
00134     {
00135         y0 = y;
00136         x1 = xMin = xMax = x2 = x;
00137     }
00138 
00139     inline bool append( int x, int y )
00140     {
00141         if ( y0 != y )
00142             return false;
00143 
00144         if ( x < xMin )
00145             xMin = x;
00146         else if ( x > xMax )
00147             xMax = x;
00148 
00149         x2 = x;
00150 
00151         return true;
00152     }
00153 
00154     inline void flush( Polygon &polyline )
00155     {
00156         appendTo( x1, polyline );
00157 
00158         if ( x2 > x1 )
00159             qSwap( xMin, xMax );
00160 
00161         if ( xMax != x1 )
00162             appendTo( xMax, polyline );
00163 
00164         if ( xMin != xMax )
00165             appendTo( xMin, polyline );
00166 
00167         if ( x2 != xMin )
00168             appendTo( x2, polyline );
00169     }
00170 
00171 private:
00172     inline void appendTo( int x, Polygon &polyline )
00173     {
00174         polyline += Point( x, y0 );
00175     }
00176 
00177     int y0, x1, xMin, xMax, x2;
00178 };
00179 
00180 template <class Polygon, class Point, class PolygonQuadrupel>
00181 static Polygon qwtMapPointsQuad( const QwtScaleMap &xMap, const QwtScaleMap &yMap,
00182     const QwtSeriesData<QPointF> *series, int from, int to )
00183 {
00184     const QPointF sample0 = series->sample( from );
00185 
00186     PolygonQuadrupel q;
00187     q.start( qwtRoundValue( xMap.transform( sample0.x() ) ),
00188         qwtRoundValue( yMap.transform( sample0.y() ) ) );
00189 
00190     Polygon polyline;
00191     for ( int i = from; i <= to; i++ )
00192     {
00193         const QPointF sample = series->sample( i );
00194 
00195         const int x = qwtRoundValue( xMap.transform( sample.x() ) );
00196         const int y = qwtRoundValue( yMap.transform( sample.y() ) );
00197 
00198         if ( !q.append( x, y ) )
00199         {
00200             q.flush( polyline );
00201             q.start( x, y );
00202         }
00203     }
00204     q.flush( polyline );
00205 
00206     return polyline;
00207 }
00208 
00209 template <class Polygon, class Point, class PolygonQuadrupel>
00210 static Polygon qwtMapPointsQuad( const Polygon &polyline )
00211 {
00212     const int numPoints = polyline.size();
00213 
00214     if ( numPoints < 3 )
00215         return polyline;
00216 
00217     const Point *points = polyline.constData();
00218 
00219     Polygon polylineXY;
00220 
00221     PolygonQuadrupel q;
00222     q.start( points[0].x(), points[0].y() );
00223 
00224     for ( int i = 0; i < numPoints; i++ )
00225     {
00226         const int x = points[i].x();
00227         const int y = points[i].y();
00228 
00229         if ( !q.append( x, y ) )
00230         {
00231             q.flush( polylineXY );
00232             q.start( x, y );
00233         }
00234     }
00235     q.flush( polylineXY );
00236 
00237     return polylineXY;
00238 }
00239 
00240 
00241 template <class Polygon, class Point>
00242 static Polygon qwtMapPointsQuad( const QwtScaleMap &xMap, const QwtScaleMap &yMap,
00243     const QwtSeriesData<QPointF> *series, int from, int to ) 
00244 {
00245     Polygon polyline;
00246     if ( from > to )
00247         return polyline;
00248 
00249     /* 
00250         probing some values, to decide if it is better 
00251         to start with x or y coordinates
00252      */
00253     const Qt::Orientation orientation = qwtProbeOrientation( series, from, to );
00254 
00255     if ( orientation == Qt::Horizontal )
00256     {
00257         polyline = qwtMapPointsQuad< Polygon, Point,
00258             QwtPolygonQuadrupelY<Polygon, Point> >( xMap, yMap, series, from, to );
00259 
00260         polyline = qwtMapPointsQuad< Polygon, Point,
00261             QwtPolygonQuadrupelX<Polygon, Point> >( polyline );
00262     }
00263     else
00264     {
00265         polyline = qwtMapPointsQuad< Polygon, Point, 
00266             QwtPolygonQuadrupelX<Polygon, Point> >( xMap, yMap, series, from, to );
00267 
00268         polyline = qwtMapPointsQuad< Polygon, Point, 
00269             QwtPolygonQuadrupelY<Polygon, Point> >( polyline );
00270     }
00271 
00272     return polyline;
00273 }
00274 
00275 // Helper class to work around the 5 parameters
00276 // limitation of QtConcurrent::run()
00277 class QwtDotsCommand
00278 {
00279 public:
00280     const QwtSeriesData<QPointF> *series;
00281     int from;
00282     int to;
00283     QRgb rgb;
00284 };
00285 
00286 static void qwtRenderDots(
00287     const QwtScaleMap &xMap, const QwtScaleMap &yMap,
00288     const QwtDotsCommand command, const QPoint &pos, QImage *image ) 
00289 {
00290     const QRgb rgb = command.rgb;
00291     QRgb *bits = reinterpret_cast<QRgb *>( image->bits() );
00292 
00293     const int w = image->width();
00294     const int h = image->height();
00295 
00296     const int x0 = pos.x();
00297     const int y0 = pos.y();
00298 
00299     for ( int i = command.from; i <= command.to; i++ )
00300     {
00301         const QPointF sample = command.series->sample( i );
00302 
00303         const int x = static_cast<int>( xMap.transform( sample.x() ) + 0.5 ) - x0;
00304         const int y = static_cast<int>( yMap.transform( sample.y() ) + 0.5 ) - y0;
00305 
00306         if ( x >= 0 && x < w && y >= 0 && y < h )
00307             bits[ y * w + x ] = rgb;
00308     }
00309 }
00310 
00311 // some functors, so that the compile can inline
00312 struct QwtRoundI
00313 {
00314     inline int operator()( double value ) const
00315     {
00316         return qwtRoundValue( value );
00317     }
00318 };
00319 
00320 struct QwtRoundF
00321 {
00322     inline double operator()( double value ) const
00323     {
00324         return qwtRoundValueF( value );
00325     }
00326 };
00327 
00328 struct QwtNoRoundF
00329 {   
00330     inline double operator()( double value ) const
00331     {
00332         return value;
00333     }
00334 };
00335 
00336 // mapping points without any filtering - beside checking
00337 // the bounding rectangle
00338 
00339 template<class Polygon, class Point, class Round>
00340 static inline Polygon qwtToPoints( 
00341     const QRectF &boundingRect,
00342     const QwtScaleMap &xMap, const QwtScaleMap &yMap,
00343     const QwtSeriesData<QPointF> *series, 
00344     int from, int to, Round round )
00345 {
00346     Polygon polyline( to - from + 1 );
00347     Point *points = polyline.data();
00348 
00349     int numPoints = 0;
00350 
00351     if ( boundingRect.isValid() )
00352     {
00353         // iterating over all values
00354         // filtering out all points outside of
00355         // the bounding rectangle
00356 
00357         for ( int i = from; i <= to; i++ )
00358         {
00359             const QPointF sample = series->sample( i );
00360 
00361             const double x = xMap.transform( sample.x() );
00362             const double y = yMap.transform( sample.y() );
00363 
00364             if ( boundingRect.contains( x, y ) )
00365             {
00366                 points[ numPoints ].rx() = round( x );
00367                 points[ numPoints ].ry() = round( y );
00368 
00369                 numPoints++;
00370             }
00371         }
00372 
00373         polyline.resize( numPoints );
00374     }
00375     else
00376     {
00377         // simply iterating over all values
00378         // without any filtering
00379 
00380         for ( int i = from; i <= to; i++ )
00381         {
00382             const QPointF sample = series->sample( i );
00383 
00384             const double x = xMap.transform( sample.x() );
00385             const double y = yMap.transform( sample.y() );
00386 
00387             points[ numPoints ].rx() = round( x );
00388             points[ numPoints ].ry() = round( y );
00389 
00390             numPoints++;
00391         }
00392     }
00393 
00394     return polyline;
00395 }
00396 
00397 static inline QPolygon qwtToPointsI(
00398     const QRectF &boundingRect,
00399     const QwtScaleMap &xMap, const QwtScaleMap &yMap,
00400     const QwtSeriesData<QPointF> *series,
00401     int from, int to )
00402 {
00403     return qwtToPoints<QPolygon, QPoint>( 
00404         boundingRect, xMap, yMap, series, from, to, QwtRoundI() );
00405 }
00406 
00407 template<class Round>
00408 static inline QPolygonF qwtToPointsF(
00409     const QRectF &boundingRect,
00410     const QwtScaleMap &xMap, const QwtScaleMap &yMap,
00411     const QwtSeriesData<QPointF> *series,
00412     int from, int to, Round round )
00413 {
00414     return qwtToPoints<QPolygonF, QPointF>( 
00415         boundingRect, xMap, yMap, series, from, to, round );
00416 }
00417 
00418 // Mapping points with filtering out consecutive
00419 // points mapped to the same position
00420 
00421 template<class Polygon, class Point, class Round>
00422 static inline Polygon qwtToPolylineFiltered( 
00423     const QwtScaleMap &xMap, const QwtScaleMap &yMap,
00424     const QwtSeriesData<QPointF> *series, 
00425     int from, int to, Round round )
00426 {
00427     // in curves with many points consecutive points
00428     // are often mapped to the same position. As this might
00429     // result in empty lines ( or symbols hidden by others )
00430     // we try to filter them out
00431 
00432     Polygon polyline( to - from + 1 );
00433     Point *points = polyline.data();
00434 
00435     const QPointF sample0 = series->sample( from );
00436 
00437     points[0].rx() = round( xMap.transform( sample0.x() ) );
00438     points[0].ry() = round( yMap.transform( sample0.y() ) );
00439 
00440     int pos = 0;
00441     for ( int i = from + 1; i <= to; i++ )
00442     {
00443         const QPointF sample = series->sample( i );
00444 
00445         const Point p( round( xMap.transform( sample.x() ) ),
00446             round( yMap.transform( sample.y() ) ) );
00447 
00448         if ( points[pos] != p )
00449             points[++pos] = p;
00450     }
00451 
00452     polyline.resize( pos + 1 );
00453     return polyline;
00454 }
00455 
00456 static inline QPolygon qwtToPolylineFilteredI(
00457     const QwtScaleMap &xMap, const QwtScaleMap &yMap,
00458     const QwtSeriesData<QPointF> *series,
00459     int from, int to )
00460 {
00461     return qwtToPolylineFiltered<QPolygon, QPoint>(
00462         xMap, yMap, series, from, to, QwtRoundI() );
00463 }
00464 
00465 template<class Round>
00466 static inline QPolygonF qwtToPolylineFilteredF(
00467     const QwtScaleMap &xMap, const QwtScaleMap &yMap,
00468     const QwtSeriesData<QPointF> *series,
00469     int from, int to, Round round )
00470 {
00471     return qwtToPolylineFiltered<QPolygonF, QPointF>(
00472         xMap, yMap, series, from, to, round );
00473 } 
00474 
00475 template<class Polygon, class Point>
00476 static inline Polygon qwtToPointsFiltered(
00477     const QRectF &boundingRect,
00478     const QwtScaleMap &xMap, const QwtScaleMap &yMap,
00479     const QwtSeriesData<QPointF> *series, int from, int to )
00480 {
00481     // F.e. in scatter plots ( no connecting lines ) we
00482     // can sort out all duplicates ( not only consecutive points )
00483 
00484     Polygon polygon( to - from + 1 );
00485     Point *points = polygon.data();
00486 
00487     QwtPixelMatrix pixelMatrix( boundingRect.toAlignedRect() );
00488 
00489     int numPoints = 0;
00490     for ( int i = from; i <= to; i++ )
00491     {
00492         const QPointF sample = series->sample( i );
00493 
00494         const int x = qwtRoundValue( xMap.transform( sample.x() ) );
00495         const int y = qwtRoundValue( yMap.transform( sample.y() ) );
00496 
00497         if ( pixelMatrix.testAndSetPixel( x, y, true ) == false )
00498         {
00499             points[ numPoints ].rx() = x;
00500             points[ numPoints ].ry() = y;
00501 
00502             numPoints++;
00503         }
00504     }
00505 
00506     polygon.resize( numPoints );
00507     return polygon;
00508 }
00509 
00510 static inline QPolygon qwtToPointsFilteredI(
00511     const QRectF &boundingRect,
00512     const QwtScaleMap &xMap, const QwtScaleMap &yMap,
00513     const QwtSeriesData<QPointF> *series, int from, int to )
00514 {
00515     return qwtToPointsFiltered<QPolygon, QPoint>(
00516         boundingRect, xMap, yMap, series, from, to );
00517 } 
00518 
00519 static inline QPolygonF qwtToPointsFilteredF(
00520     const QRectF &boundingRect,
00521     const QwtScaleMap &xMap, const QwtScaleMap &yMap,
00522     const QwtSeriesData<QPointF> *series, int from, int to )
00523 {
00524     return qwtToPointsFiltered<QPolygonF, QPointF>(
00525         boundingRect, xMap, yMap, series, from, to );
00526 }
00527 
00528 class QwtPointMapper::PrivateData
00529 {
00530 public:
00531     PrivateData():
00532         boundingRect( qwtInvalidRect )
00533     {
00534     }
00535 
00536     QRectF boundingRect;
00537     QwtPointMapper::TransformationFlags flags;
00538 };
00539 
00541 QwtPointMapper::QwtPointMapper()
00542 {
00543     d_data = new PrivateData();
00544 }
00545 
00547 QwtPointMapper::~QwtPointMapper()
00548 {
00549     delete d_data;
00550 }
00551 
00558 void QwtPointMapper::setFlags( TransformationFlags flags )
00559 {
00560     d_data->flags = flags;
00561 }
00562 
00567 QwtPointMapper::TransformationFlags QwtPointMapper::flags() const
00568 {
00569     return d_data->flags;
00570 }
00571 
00580 void QwtPointMapper::setFlag( TransformationFlag flag, bool on )
00581 {
00582     if ( on )
00583         d_data->flags |= flag;
00584     else
00585         d_data->flags &= ~flag;
00586 }
00587 
00593 bool QwtPointMapper::testFlag( TransformationFlag flag ) const
00594 {
00595     return d_data->flags & flag;
00596 }
00597 
00606 void QwtPointMapper::setBoundingRect( const QRectF &rect )
00607 {
00608     d_data->boundingRect = rect;
00609 }
00610 
00615 QRectF QwtPointMapper::boundingRect() const
00616 {
00617     return d_data->boundingRect;
00618 }
00619 
00641 QPolygonF QwtPointMapper::toPolygonF(
00642     const QwtScaleMap &xMap, const QwtScaleMap &yMap,
00643     const QwtSeriesData<QPointF> *series, int from, int to ) const
00644 {
00645     QPolygonF polyline;
00646 
00647     if ( d_data->flags & RoundPoints )
00648     {
00649         if ( d_data->flags & WeedOutIntermediatePoints )
00650         {
00651             polyline = qwtMapPointsQuad<QPolygonF, QPointF>( 
00652                 xMap, yMap, series, from, to );
00653         }
00654         else if ( d_data->flags & WeedOutPoints )
00655         {
00656             polyline = qwtToPolylineFilteredF( 
00657                 xMap, yMap, series, from, to, QwtRoundF() );
00658         }
00659         else
00660         {
00661             polyline = qwtToPointsF( qwtInvalidRect, 
00662                 xMap, yMap, series, from, to, QwtRoundF() );
00663         }
00664     }
00665     else
00666     {
00667         if ( d_data->flags & WeedOutPoints )
00668         {
00669             polyline = qwtToPolylineFilteredF( 
00670                 xMap, yMap, series, from, to, QwtNoRoundF() );
00671         }
00672         else
00673         {
00674             polyline = qwtToPointsF( qwtInvalidRect, 
00675                 xMap, yMap, series, from, to, QwtNoRoundF() );
00676         }
00677     }
00678 
00679     return polyline;
00680 }
00681 
00696 QPolygon QwtPointMapper::toPolygon(
00697     const QwtScaleMap &xMap, const QwtScaleMap &yMap,
00698     const QwtSeriesData<QPointF> *series, int from, int to ) const
00699 {
00700     QPolygon polyline;
00701 
00702     if ( d_data->flags & WeedOutIntermediatePoints )
00703     {
00704         // TODO WeedOutIntermediatePointsY ...
00705         polyline = qwtMapPointsQuad<QPolygon, QPoint>( 
00706             xMap, yMap, series, from, to );
00707     }
00708     else if ( d_data->flags & WeedOutPoints )
00709     {
00710         polyline = qwtToPolylineFilteredI( 
00711             xMap, yMap, series, from, to );
00712     }
00713     else
00714     {
00715         polyline = qwtToPointsI( 
00716             qwtInvalidRect, xMap, yMap, series, from, to );
00717     }
00718 
00719     return polyline;
00720 }
00721 
00753 QPolygonF QwtPointMapper::toPointsF(
00754     const QwtScaleMap &xMap, const QwtScaleMap &yMap,
00755     const QwtSeriesData<QPointF> *series, int from, int to ) const
00756 {
00757     QPolygonF points;
00758 
00759     if ( d_data->flags & WeedOutPoints )
00760     {
00761         if ( d_data->flags & RoundPoints )
00762         {
00763             if ( d_data->boundingRect.isValid() )
00764             {   
00765                 points = qwtToPointsFilteredF( d_data->boundingRect,
00766                     xMap, yMap, series, from, to );
00767             }
00768             else
00769             {   
00770                 // without a bounding rectangle all we can
00771                 // do is to filter out duplicates of
00772                 // consecutive points
00773 
00774                 points = qwtToPolylineFilteredF( 
00775                     xMap, yMap, series, from, to, QwtRoundF() );
00776             }
00777         }
00778         else
00779         {
00780             // when rounding is not allowed we can't use
00781             // qwtToPointsFilteredF
00782 
00783             points = qwtToPolylineFilteredF( 
00784                 xMap, yMap, series, from, to, QwtNoRoundF() );
00785         }
00786     }
00787     else
00788     {
00789         if ( d_data->flags & RoundPoints )
00790         {
00791             points = qwtToPointsF( d_data->boundingRect,
00792                 xMap, yMap, series, from, to, QwtRoundF() );
00793         }
00794         else
00795         {
00796             points = qwtToPointsF( d_data->boundingRect,
00797                 xMap, yMap, series, from, to, QwtNoRoundF() );
00798         }
00799     }
00800 
00801     return points;
00802 }
00803 
00827 QPolygon QwtPointMapper::toPoints(
00828     const QwtScaleMap &xMap, const QwtScaleMap &yMap,
00829     const QwtSeriesData<QPointF> *series, int from, int to ) const
00830 {
00831     QPolygon points;
00832 
00833     if ( d_data->flags & WeedOutPoints )
00834     {
00835         if ( d_data->boundingRect.isValid() )
00836         {
00837             points = qwtToPointsFilteredI( d_data->boundingRect,
00838                 xMap, yMap, series, from, to );
00839         }
00840         else
00841         {
00842             // when we don't have the bounding rectangle all
00843             // we can do is to filter out consecutive duplicates
00844 
00845             points = qwtToPolylineFilteredI( 
00846                 xMap, yMap, series, from, to );
00847         }
00848     }
00849     else
00850     {
00851         points = qwtToPointsI( 
00852             d_data->boundingRect, xMap, yMap, series, from, to );
00853     }
00854 
00855     return points;
00856 }
00857 
00858 
00877 QImage QwtPointMapper::toImage(
00878     const QwtScaleMap &xMap, const QwtScaleMap &yMap,
00879     const QwtSeriesData<QPointF> *series, int from, int to, 
00880     const QPen &pen, bool antialiased, uint numThreads ) const
00881 {
00882     Q_UNUSED( antialiased )
00883 
00884 #if QWT_USE_THREADS
00885     if ( numThreads == 0 )
00886         numThreads = QThread::idealThreadCount();
00887 
00888     if ( numThreads <= 0 )
00889         numThreads = 1;
00890 #else
00891     Q_UNUSED( numThreads )
00892 #endif
00893 
00894     // a very special optimization for scatter plots
00895     // where every sample is mapped to one pixel only.
00896 
00897     const QRect rect = d_data->boundingRect.toAlignedRect();
00898 
00899     QImage image( rect.size(), QImage::Format_ARGB32 );
00900     image.fill( Qt::transparent );
00901 
00902     if ( pen.width() <= 1 && pen.color().alpha() == 255 )
00903     {
00904         QwtDotsCommand command;
00905         command.series = series;
00906         command.rgb = pen.color().rgba();
00907 
00908 #if QWT_USE_THREADS
00909         const int numPoints = ( to - from + 1 ) / numThreads;
00910 
00911         QList< QFuture<void> > futures;
00912         for ( uint i = 0; i < numThreads; i++ )
00913         {
00914             const QPoint pos = rect.topLeft();
00915 
00916             const int index0 = from + i * numPoints;
00917             if ( i == numThreads - 1 )
00918             {
00919                 command.from = index0;
00920                 command.to = to;
00921 
00922                 qwtRenderDots( xMap, yMap, command, pos, &image );
00923             }
00924             else
00925             {
00926                 command.from = index0;
00927                 command.to = index0 + numPoints - 1;
00928 
00929                 futures += QtConcurrent::run( &qwtRenderDots, 
00930                     xMap, yMap, command, pos, &image );
00931             }
00932         }
00933         for ( int i = 0; i < futures.size(); i++ )
00934             futures[i].waitForFinished();
00935 #else
00936         command.from = from;
00937         command.to = to;
00938 
00939         qwtRenderDots( xMap, yMap, command, rect.topLeft(), &image );
00940 #endif
00941     }
00942     else
00943     {
00944         // fallback implementation: to be replaced later by
00945         // setting the pixels of the image like above, TODO ...
00946 
00947         QPainter painter( &image );
00948         painter.setPen( pen );
00949         painter.setRenderHint( QPainter::Antialiasing, antialiased );
00950 
00951         const int chunkSize = 1000;
00952         for ( int i = from; i <= to; i += chunkSize )
00953         {
00954             const int indexTo = qMin( i + chunkSize - 1, to );
00955             const QPolygon points = toPoints(
00956                 xMap, yMap, series, i, indexTo );
00957 
00958             painter.drawPoints( points );
00959         }
00960     }
00961 
00962     return image;
00963 }


plotjuggler
Author(s): Davide Faconti
autogenerated on Fri Sep 1 2017 02:41:56