/*!
   \return the value at a raster position

   \param x X value in plot coordinates
   \param y Y value in plot coordinates

   \sa ResampleMode
*/
double QwtMatrixRasterData::value( double x, double y ) const
{
    const QwtInterval xInterval = interval( Qt::XAxis );
    const QwtInterval yInterval = interval( Qt::YAxis );

    if ( !( xInterval.contains(x) && yInterval.contains(y) ) )
        return qQNaN();

    double value;

    switch( d_data->resampleMode )
    {
        case BilinearInterpolation:
        {
            int col1 = qRound( (x - xInterval.minValue() ) / d_data->dx ) - 1;
            int row1 = qRound( (y - yInterval.minValue() ) / d_data->dy ) - 1;
            int col2 = col1 + 1;
            int row2 = row1 + 1;

            if ( col1 < 0 )
                col1 = col2;
            else if ( col2 >= static_cast<int>( d_data->numColumns ) )
                col2 = col1;

            if ( row1 < 0 )
                row1 = row2;
            else if ( row2 >= static_cast<int>( d_data->numRows ) )
                row2 = row1;

            const double v11 = d_data->value( row1, col1 );
            const double v21 = d_data->value( row1, col2 );
            const double v12 = d_data->value( row2, col1 );
            const double v22 = d_data->value( row2, col2 );

            const double x2 = xInterval.minValue() + 
                ( col2 + 0.5 ) * d_data->dx;
            const double y2 = yInterval.minValue() + 
                ( row2 + 0.5 ) * d_data->dy;
                
            const double rx = ( x2 - x ) / d_data->dx;
            const double ry = ( y2 - y ) / d_data->dy;

            const double vr1 = rx * v11 + ( 1.0 - rx ) * v21;
            const double vr2 = rx * v12 + ( 1.0 - rx ) * v22;

            value = ry * vr1 + ( 1.0 - ry ) * vr2;

            break;
        }
        case NearestNeighbour:
        default:
        {
            int row = int( (y - yInterval.minValue() ) / d_data->dy );
            int col = int( (x - xInterval.minValue() ) / d_data->dx );

            // In case of intervals, where the maximum is included
            // we get out of bound for row/col, when the value for the
            // maximum is requested. Instead we return the value
            // from the last row/col

            if ( row >= d_data->numRows )
                row = d_data->numRows - 1;

            if ( col >= d_data->numColumns )
                col = d_data->numColumns - 1;

            value = d_data->value( row, col );
        }
    }

    return value;
}
Example #2
0
/*!
   Calculate contour lines

   \param rect Bounding rectangle for the contour lines
   \param raster Number of data pixels of the raster data
   \param levels List of limits, where to insert contour lines
   \param flags Flags to customize the contouring algorithm

   \return Calculated contour lines

   An adaption of CONREC, a simple contouring algorithm.
   http://local.wasp.uwa.edu.au/~pbourke/papers/conrec/
*/
QwtRasterData::ContourLines QwtRasterData::contourLines(
    const QRectF &rect, const QSize &raster,
    const QList<double> &levels, ConrecFlags flags ) const
{
    ContourLines contourLines;

    if ( levels.size() == 0 || !rect.isValid() || !raster.isValid() )
        return contourLines;

    const double dx = rect.width() / raster.width();
    const double dy = rect.height() / raster.height();

    const bool ignoreOnPlane =
        flags & QwtRasterData::IgnoreAllVerticesOnLevel;

    const QwtInterval range = interval( Qt::ZAxis );
    bool ignoreOutOfRange = false;
    if ( range.isValid() )
        ignoreOutOfRange = flags & IgnoreOutOfRange;

    QwtRasterData *that = const_cast<QwtRasterData *>( this );
    that->initRaster( rect, raster );

    for ( int y = 0; y < raster.height() - 1; y++ )
    {
        enum Position
        {
            Center,

            TopLeft,
            TopRight,
            BottomRight,
            BottomLeft,

            NumPositions
        };

        QwtPoint3D xy[NumPositions];

        for ( int x = 0; x < raster.width() - 1; x++ )
        {
            const QPointF pos( rect.x() + x * dx, rect.y() + y * dy );

            if ( x == 0 )
            {
                xy[TopRight].setX( pos.x() );
                xy[TopRight].setY( pos.y() );
                xy[TopRight].setZ(
                    value( xy[TopRight].x(), xy[TopRight].y() )
                );

                xy[BottomRight].setX( pos.x() );
                xy[BottomRight].setY( pos.y() + dy );
                xy[BottomRight].setZ(
                    value( xy[BottomRight].x(), xy[BottomRight].y() )
                );
            }

            xy[TopLeft] = xy[TopRight];
            xy[BottomLeft] = xy[BottomRight];

            xy[TopRight].setX( pos.x() + dx );
            xy[TopRight].setY( pos.y() );
            xy[BottomRight].setX( pos.x() + dx );
            xy[BottomRight].setY( pos.y() + dy );

            xy[TopRight].setZ(
                value( xy[TopRight].x(), xy[TopRight].y() )
            );
            xy[BottomRight].setZ(
                value( xy[BottomRight].x(), xy[BottomRight].y() )
            );

            double zMin = xy[TopLeft].z();
            double zMax = zMin;
            double zSum = zMin;

            for ( int i = TopRight; i <= BottomLeft; i++ )
            {
                const double z = xy[i].z();

                zSum += z;
                if ( z < zMin )
                    zMin = z;
                if ( z > zMax )
                    zMax = z;
            }

            if ( ignoreOutOfRange )
            {
                if ( !range.contains( zMin ) || !range.contains( zMax ) )
                    continue;
            }

            if ( zMax < levels[0] ||
                zMin > levels[levels.size() - 1] )
            {
                continue;
            }

            xy[Center].setX( pos.x() + 0.5 * dx );
            xy[Center].setY( pos.y() + 0.5 * dy );
            xy[Center].setZ( 0.25 * zSum );

            const int numLevels = levels.size();
            for ( int l = 0; l < numLevels; l++ )
            {
                const double level = levels[l];
                if ( level < zMin || level > zMax )
                    continue;
                QPolygonF &lines = contourLines[level];
                const ContourPlane plane( level );

                QPointF line[2];
                QwtPoint3D vertex[3];

                for ( int m = TopLeft; m < NumPositions; m++ )
                {
                    vertex[0] = xy[m];
                    vertex[1] = xy[0];
                    vertex[2] = xy[m != BottomLeft ? m + 1 : TopLeft];

                    const bool intersects =
                        plane.intersect( vertex, line, ignoreOnPlane );
                    if ( intersects )
                    {
                        lines += line[0];
                        lines += line[1];
                    }
                }
            }
        }
    }

    that->discardRaster();

    return contourLines;
}