# qwt_raster_data.cpp

    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_raster_data.h"
    00011
    00012 class QwtRasterData::Contour3DPoint
    00013 {
    00014 public:
    00015     inline void setPos(double x, double y)
    00016     {
    00017         d_x = x;
    00018         d_y = y;
    00019     }
    00020
    00021     inline QwtDoublePoint pos() const
    00022     {
    00023         return QwtDoublePoint(d_x, d_y);
    00024     }
    00025
    00026     inline void setX(double x) { d_x = x; }
    00027     inline void setY(double y) { d_y = y; }
    00028     inline void setZ(double z) { d_z = z; }
    00029
    00030     inline double x() const { return d_x; }
    00031     inline double y() const { return d_y; }
    00032     inline double z() const { return d_z; }
    00033
    00034 private:
    00035     double d_x;
    00036     double d_y;
    00037     double d_z;
    00038 };
    00039
    00040 class QwtRasterData::ContourPlane
    00041 {
    00042 public:
    00043     inline ContourPlane(double z):
    00044         d_z(z)
    00045     {
    00046     }
    00047
    00048     inline bool intersect(const Contour3DPoint vertex[3],
    00049         QwtDoublePoint line[2], bool ignoreOnPlane) const;
    00050
    00051     inline double z() const { return d_z; }
    00052
    00053 private:
    00054     inline int compare(double z) const;
    00055     inline QwtDoublePoint intersection(
    00056         const Contour3DPoint& p1, const Contour3DPoint &p2) const;
    00057
    00058     double d_z;
    00059 };
    00060
    00061 inline bool QwtRasterData::ContourPlane::intersect(
    00062     const Contour3DPoint vertex[3], QwtDoublePoint line[2],
    00063     bool ignoreOnPlane) const
    00064 {
    00065     bool found = true;
    00066
    00067     // Are the vertices below (-1), on (0) or above (1) the plan ?
    00068     const int eq1 = compare(vertex[0].z());
    00069     const int eq2 = compare(vertex[1].z());
    00070     const int eq3 = compare(vertex[2].z());
    00071
    00072     /*
    00073         (a) All the vertices lie below the contour level.
    00074         (b) Two vertices lie below and one on the contour level.
    00075         (c) Two vertices lie below and one above the contour level.
    00076         (d) One vertex lies below and two on the contour level.
    00077         (e) One vertex lies below, one on and one above the contour level.
    00078         (f) One vertex lies below and two above the contour level.
    00079         (g) Three vertices lie on the contour level.
    00080         (h) Two vertices lie on and one above the contour level.
    00081         (i) One vertex lies on and two above the contour level.
    00082         (j) All the vertices lie above the contour level.
    00083      */
    00084
    00085     static const int tab[3][3][3] =
    00086     {
    00087         // jump table to avoid nested case statements
    00088         { { 0, 0, 8 }, { 0, 2, 5 }, { 7, 6, 9 } },
    00089         { { 0, 3, 4 }, { 1, 10, 1 }, { 4, 3, 0 } },
    00090         { { 9, 6, 7 }, { 5, 2, 0 }, { 8, 0, 0 } }
    00091     };
    00092
    00093     const int edgeType = tab[eq1+1][eq2+1][eq3+1];
    00094     switch (edgeType)
    00095     {
    00096         case 1:
    00097             // d(0,0,-1), h(0,0,1)
    00098             line[0] = vertex[0].pos();
    00099             line[1] = vertex[1].pos();
    00100             break;
    00101         case 2:
    00102             // d(-1,0,0), h(1,0,0)
    00103             line[0] = vertex[1].pos();
    00104             line[1] = vertex[2].pos();
    00105             break;
    00106         case 3:
    00107             // d(0,-1,0), h(0,1,0)
    00108             line[0] = vertex[2].pos();
    00109             line[1] = vertex[0].pos();
    00110             break;
    00111         case 4:
    00112             // e(0,-1,1), e(0,1,-1)
    00113             line[0] = vertex[0].pos();
    00114             line[1] = intersection(vertex[1], vertex[2]);
    00115             break;
    00116         case 5:
    00117             // e(-1,0,1), e(1,0,-1)
    00118             line[0] = vertex[1].pos();
    00119             line[1] = intersection(vertex[2], vertex[0]);
    00120             break;
    00121         case 6:
    00122             // e(-1,1,0), e(1,0,-1)
    00123             line[0] = vertex[1].pos();
    00124             line[1] = intersection(vertex[0], vertex[1]);
    00125             break;
    00126         case 7:
    00127             // c(-1,1,-1), f(1,1,-1)
    00128             line[0] = intersection(vertex[0], vertex[1]);
    00129             line[1] = intersection(vertex[1], vertex[2]);
    00130             break;
    00131         case 8:
    00132             // c(-1,-1,1), f(1,1,-1)
    00133             line[0] = intersection(vertex[1], vertex[2]);
    00134             line[1] = intersection(vertex[2], vertex[0]);
    00135             break;
    00136         case 9:
    00137             // f(-1,1,1), c(1,-1,-1)
    00138             line[0] = intersection(vertex[2], vertex[0]);
    00139             line[1] = intersection(vertex[0], vertex[1]);
    00140             break;
    00141         case 10:
    00142             // g(0,0,0)
    00143             // The CONREC algorithm has no satisfying solution for
    00144             // what to do, when all vertices are on the plane.
    00145
    00146             if ( ignoreOnPlane )
    00147                 found = false;
    00148             else
    00149             {
    00150                 line[0] = vertex[2].pos();
    00151                 line[1] = vertex[0].pos();
    00152             }
    00153             break;
    00154         default:
    00155             found = false;
    00156     }
    00157
    00158     return found;
    00159 }
    00160
    00161 inline int QwtRasterData::ContourPlane::compare(double z) const
    00162 {
    00163     if (z > d_z)
    00164         return 1;
    00165
    00166     if (z < d_z)
    00167         return -1;
    00168
    00169     return 0;
    00170 }
    00171
    00172 inline QwtDoublePoint QwtRasterData::ContourPlane::intersection(
    00173     const Contour3DPoint& p1, const Contour3DPoint &p2) const
    00174 {
    00175     const double h1 = p1.z() - d_z;
    00176     const double h2 = p2.z() - d_z;
    00177
    00178     const double x = (h2 * p1.x() - h1 * p2.x()) / (h2 - h1);
    00179     const double y = (h2 * p1.y() - h1 * p2.y()) / (h2 - h1);
    00180
    00181     return QwtDoublePoint(x, y);
    00182 }
    00183
    00184 QwtRasterData::QwtRasterData()
    00185 {
    00186 }
    00187
    00188 QwtRasterData::QwtRasterData(const QwtDoubleRect &boundingRect):
    00189     d_boundingRect(boundingRect)
    00190 {
    00191 }
    00192
    00193 QwtRasterData::~QwtRasterData()
    00194 {
    00195 }
    00196
    00197 void QwtRasterData::setBoundingRect(const QwtDoubleRect &boundingRect)
    00198 {
    00199     d_boundingRect = boundingRect;
    00200 }
    00201
    00202 QwtDoubleRect QwtRasterData::boundingRect() const
    00203 {
    00204     return d_boundingRect;
    00205 }
    00206
    00222 void QwtRasterData::initRaster(const QwtDoubleRect &, const QSize&)
    00223 {
    00224 }
    00225
    00236 void QwtRasterData::discardRaster()
    00237 {
    00238 }
    00239
    00258 QSize QwtRasterData::rasterHint(const QwtDoubleRect &) const
    00259 {
    00260     return QSize(); // use screen resolution
    00261 }
    00262
    00269 #if QT_VERSION >= 0x040000
    00270 QwtRasterData::ContourLines QwtRasterData::contourLines(
    00271     const QwtDoubleRect &rect, const QSize &raster,
    00272     const QList<double> &levels, int flags) const
    00273 #else
    00274 QwtRasterData::ContourLines QwtRasterData::contourLines(
    00275     const QwtDoubleRect &rect, const QSize &raster,
    00276     const QValueList<double> &levels, int flags) const
    00277 #endif
    00278 {
    00279     ContourLines contourLines;
    00280
    00281     if ( levels.size() == 0 || !rect.isValid() || !raster.isValid() )
    00282         return contourLines;
    00283
    00284     const double dx = rect.width() / raster.width();
    00285     const double dy = rect.height() / raster.height();
    00286
    00287     const bool ignoreOnPlane =
    00288         flags & QwtRasterData::IgnoreAllVerticesOnLevel;
    00289
    00290     const QwtDoubleInterval range = this->range();
    00291     bool ignoreOutOfRange = false;
    00292     if ( range.isValid() )
    00293         ignoreOutOfRange = flags & IgnoreOutOfRange;
    00294
    00295     ((QwtRasterData*)this)->initRaster(rect, raster);
    00296
    00297     for ( int y = 0; y < raster.height() - 1; y++ )
    00298     {
    00299         enum Position
    00300         {
    00301             Center,
    00302
    00303             TopLeft,
    00304             TopRight,
    00305             BottomRight,
    00306             BottomLeft,
    00307
    00308             NumPositions
    00309         };
    00310
    00311         Contour3DPoint xy[NumPositions];
    00312
    00313         for ( int x = 0; x < raster.width() - 1; x++ )
    00314         {
    00315             const QwtDoublePoint pos(rect.x() + x * dx, rect.y() + y * dy);
    00316
    00317             if ( x == 0 )
    00318             {
    00319                 xy[TopRight].setPos(pos.x(), pos.y());
    00320                 xy[TopRight].setZ(
    00321                     value( xy[TopRight].x(), xy[TopRight].y())
    00322                 );
    00323
    00324                 xy[BottomRight].setPos(pos.x(), pos.y() + dy);
    00325                 xy[BottomRight].setZ(
    00326                     value(xy[BottomRight].x(), xy[BottomRight].y())
    00327                 );
    00328             }
    00329
    00330             xy[TopLeft] = xy[TopRight];
    00331             xy[BottomLeft] = xy[BottomRight];
    00332
    00333             xy[TopRight].setPos(pos.x() + dx, pos.y());
    00334             xy[BottomRight].setPos(pos.x() + dx, pos.y() + dy);
    00335
    00336             xy[TopRight].setZ(
    00337                 value(xy[TopRight].x(), xy[TopRight].y())
    00338             );
    00339             xy[BottomRight].setZ(
    00340                 value(xy[BottomRight].x(), xy[BottomRight].y())
    00341             );
    00342
    00343             double zMin = xy[TopLeft].z();
    00344             double zMax = zMin;
    00345             double zSum = zMin;
    00346
    00347             for ( int i = TopRight; i <= BottomLeft; i++ )
    00348             {
    00349                 const double z = xy[i].z();
    00350
    00351                 zSum += z;
    00352                 if ( z < zMin )
    00353                     zMin = z;
    00354                 if ( z > zMax )
    00355                     zMax = z;
    00356             }
    00357
    00358             if ( ignoreOutOfRange )
    00359             {
    00360                 if ( !range.contains(zMin) || !range.contains(zMax) )
    00361                     continue;
    00362             }
    00363
    00364             if ( zMax < levels[0] ||
    00365                 zMin > levels[levels.size() - 1] )
    00366             {
    00367                 continue;
    00368             }
    00369
    00370             xy[Center].setPos(pos.x() + 0.5 * dx, pos.y() + 0.5 * dy);
    00371             xy[Center].setZ(0.25 * zSum);
    00372             const int numLevels = (int)levels.size();
    00373             for (int l = 0; l < numLevels; l++)
    00374             {
    00375                 const double level = levels[l];
    00376                 if ( level < zMin || level > zMax )
    00377                     continue;
    00378 #if QT_VERSION >= 0x040000
    00379                 QPolygonF &lines = contourLines[level];
    00380 #else
    00381                 QwtArray<QwtDoublePoint> &lines = contourLines[level];
    00382 #endif
    00383                 const ContourPlane plane(level);
    00384
    00385                 QwtDoublePoint line[2];
    00386                 Contour3DPoint vertex[3];
    00387
    00388                 for (int m = TopLeft; m < NumPositions; m++)
    00389                 {
    00390                     vertex[0] = xy[m];
    00391                     vertex[1] = xy[0];
    00392                     vertex[2] = xy[m != BottomLeft ? m + 1 : TopLeft];
    00393
    00394                     const bool intersects =
    00395                         plane.intersect(vertex, line, ignoreOnPlane);
    00396                     if ( intersects )
    00397                     {
    00398 #if QT_VERSION >= 0x040000
    00399                         lines += line[0];
    00400                         lines += line[1];
    00401 #else
    00402                         const int index = lines.size();
    00403                         lines.resize(lines.size() + 2, QGArray::SpeedOptim);
    00404
    00405                         lines[index] = line[0];
    00406                         lines[index+1] = line[1];
    00407 #endif
    00408                     }
    00409                 }
    00410             }
    00411         }
    00412     }
    00413
    00414     ((QwtRasterData*)this)->discardRaster();
    00415
    00416     return contourLines;
    00417 }