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 }

Generated on Mon Feb 26 21:22:38 2007 for Qwt User's Guide by  doxygen 1.4.6