00001 
00002 
00003 
00004 
00005 
00006 
00007 
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     
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 
00074 
00075 
00076 
00077 
00078 
00079 
00080 
00081 
00082 
00083 
00084 
00085     static const int tab[3][3][3] =
00086     {
00087         
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             
00098             line[0] = vertex[0].pos();
00099             line[1] = vertex[1].pos();
00100             break;
00101         case 2:
00102             
00103             line[0] = vertex[1].pos();
00104             line[1] = vertex[2].pos();
00105             break;
00106         case 3:
00107             
00108             line[0] = vertex[2].pos();
00109             line[1] = vertex[0].pos();
00110             break;
00111         case 4:
00112             
00113             line[0] = vertex[0].pos();
00114             line[1] = intersection(vertex[1], vertex[2]);
00115             break;
00116         case 5:
00117             
00118             line[0] = vertex[1].pos();
00119             line[1] = intersection(vertex[2], vertex[0]);
00120             break;
00121         case 6:
00122             
00123             line[0] = vertex[1].pos();
00124             line[1] = intersection(vertex[0], vertex[1]);
00125             break;
00126         case 7:
00127             
00128             line[0] = intersection(vertex[0], vertex[1]);
00129             line[1] = intersection(vertex[1], vertex[2]);
00130             break;
00131         case 8:
00132             
00133             line[0] = intersection(vertex[1], vertex[2]);
00134             line[1] = intersection(vertex[2], vertex[0]);
00135             break;
00136         case 9:
00137             
00138             line[0] = intersection(vertex[2], vertex[0]);
00139             line[1] = intersection(vertex[0], vertex[1]);
00140             break;
00141         case 10:
00142             
00143             
00144             
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(); 
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 }