1  /* * mode: C++ ; cfilestyle: "stroustrup" * *****************************


2  * Qwt Widget Library


3  * Copyright (C) 1997 Josef Wilgen


4  * Copyright (C) 2002 Uwe Rathmann


5  *


6  * This library is free software; you can redistribute it and/or


7  * modify it under the terms of the Qwt License, Version 1.0


8  *****************************************************************************/


9 


10  #include "qwt_raster_data.h"


11  #include "qwt_point_3d.h"


12 


13  class QwtRasterData::ContourPlane


14  {


15  public:


16  inline ContourPlane( double z ):


17  d_z( z )


18  {


19  }


20 


21  inline bool intersect( const QwtPoint3D vertex[3],


22  QPointF line[2], bool ignoreOnPlane ) const;


23 


24  inline double z() const { return d_z; }


25 


26  private:


27  inline int compare( double z ) const;


28  inline QPointF intersection(


29  const QwtPoint3D& p1, const QwtPoint3D &p2 ) const;


30 


31  double d_z;


32  };


33 


34  inline bool QwtRasterData::ContourPlane::intersect(


35  const QwtPoint3D vertex[3], QPointF line[2],


36  bool ignoreOnPlane ) const


37  {


38  bool found = true;


39 


40  // Are the vertices below (1), on (0) or above (1) the plan ?


41  const int eq1 = compare( vertex[0].z() );


42  const int eq2 = compare( vertex[1].z() );


43  const int eq3 = compare( vertex[2].z() );


44 


45  /*


46  (a) All the vertices lie below the contour level.


47  (b) Two vertices lie below and one on the contour level.


48  (c) Two vertices lie below and one above the contour level.


49  (d) One vertex lies below and two on the contour level.


50  (e) One vertex lies below, one on and one above the contour level.


51  (f) One vertex lies below and two above the contour level.


52  (g) Three vertices lie on the contour level.


53  (h) Two vertices lie on and one above the contour level.


54  (i) One vertex lies on and two above the contour level.


55  (j) All the vertices lie above the contour level.


56  */


57 


58  static const int tab[3][3][3] =


59  {


60  // jump table to avoid nested case statements


61  { { 0, 0, 8 }, { 0, 2, 5 }, { 7, 6, 9 } },


62  { { 0, 3, 4 }, { 1, 10, 1 }, { 4, 3, 0 } },


63  { { 9, 6, 7 }, { 5, 2, 0 }, { 8, 0, 0 } }


64  };


65 


66  const int edgeType = tab[eq1+1][eq2+1][eq3+1];


67  switch ( edgeType )


68  {


69  case 1:


70  // d(0,0,1), h(0,0,1)


71  line[0] = vertex[0].toPoint();


72  line[1] = vertex[1].toPoint();


73  break;


74  case 2:


75  // d(1,0,0), h(1,0,0)


76  line[0] = vertex[1].toPoint();


77  line[1] = vertex[2].toPoint();


78  break;


79  case 3:


80  // d(0,1,0), h(0,1,0)


81  line[0] = vertex[2].toPoint();


82  line[1] = vertex[0].toPoint();


83  break;


84  case 4:


85  // e(0,1,1), e(0,1,1)


86  line[0] = vertex[0].toPoint();


87  line[1] = intersection( vertex[1], vertex[2] );


88  break;


89  case 5:


90  // e(1,0,1), e(1,0,1)


91  line[0] = vertex[1].toPoint();


92  line[1] = intersection( vertex[2], vertex[0] );


93  break;


94  case 6:


95  // e(1,1,0), e(1,0,1)


96  line[0] = vertex[1].toPoint();


97  line[1] = intersection( vertex[0], vertex[1] );


98  break;


99  case 7:


100  // c(1,1,1), f(1,1,1)


101  line[0] = intersection( vertex[0], vertex[1] );


102  line[1] = intersection( vertex[1], vertex[2] );


103  break;


104  case 8:


105  // c(1,1,1), f(1,1,1)


106  line[0] = intersection( vertex[1], vertex[2] );


107  line[1] = intersection( vertex[2], vertex[0] );


108  break;


109  case 9:


110  // f(1,1,1), c(1,1,1)


111  line[0] = intersection( vertex[2], vertex[0] );


112  line[1] = intersection( vertex[0], vertex[1] );


113  break;


114  case 10:


115  // g(0,0,0)


116  // The CONREC algorithm has no satisfying solution for


117  // what to do, when all vertices are on the plane.


118 


119  if ( ignoreOnPlane )


120  found = false;


121  else


122  {


123  line[0] = vertex[2].toPoint();


124  line[1] = vertex[0].toPoint();


125  }


126  break;


127  default:


128  found = false;


129  }


130 


131  return found;


132  }


133 


134  inline int QwtRasterData::ContourPlane::compare( double z ) const


135  {


136  if ( z > d_z )


137  return 1;


138 


139  if ( z < d_z )


140  return 1;


141 


142  return 0;


143  }


144 


145  inline QPointF QwtRasterData::ContourPlane::intersection(


146  const QwtPoint3D& p1, const QwtPoint3D &p2 ) const


147  {


148  const double h1 = p1.z()  d_z;


149  const double h2 = p2.z()  d_z;


150 


151  const double x = ( h2 * p1.x()  h1 * p2.x() ) / ( h2  h1 );


152  const double y = ( h2 * p1.y()  h1 * p2.y() ) / ( h2  h1 );


153 


154  return QPointF( x, y );


155  }


156 


157  //! Constructor


158  QwtRasterData::QwtRasterData()


159  {


160  }


161 


162  //! Destructor


163  QwtRasterData::~QwtRasterData()


164  {


165  }


166 


167  /*!


168  Set the bounding interval for the x, y or z coordinates.


169 


170  \param axis Axis


171  \param interval Bounding interval


172 


173  \sa interval()


174  */


175  void QwtRasterData::setInterval( Qt::Axis axis, const QwtInterval &interval )


176  {


177  d_intervals[axis] = interval;


178  }


179 


180  /*!


181  \brief Initialize a raster


182 


183  Before the composition of an image QwtPlotSpectrogram calls initRaster,


184  announcing the area and its resolution that will be requested.


185 


186  The default implementation does nothing, but for data sets that


187  are stored in files, it might be good idea to reimplement initRaster,


188  where the data is resampled and loaded into memory.


189 


190  \param area Area of the raster


191  \param raster Number of horizontal and vertical pixels


192 


193  \sa initRaster(), value()


194  */


195  void QwtRasterData::initRaster( const QRectF &area, const QSize &raster )


196  {


197  Q_UNUSED( area );


198  Q_UNUSED( raster );


199  }


200 


201  /*!


202  \brief Discard a raster


203 


204  After the composition of an image QwtPlotSpectrogram calls discardRaster().


205 


206  The default implementation does nothing, but if data has been loaded


207  in initRaster(), it could deleted now.


208 


209  \sa initRaster(), value()


210  */


211  void QwtRasterData::discardRaster()


212  {


213  }


214 


215  /*!


216  \brief Pixel hint


217 


218  pixelHint() returns the geometry of a pixel, that can be used


219  to calculate the resolution and alignment of the plot item, that is


220  representing the data.


221 


222  Width and height of the hint need to be the horizontal


223  and vertical distances between 2 neighboured points.


224  The center of the hint has to be the position of any point


225  ( it doesn't matter which one ).


226 


227  An empty hint indicates, that there are values for any detail level.


228 


229  Limiting the resolution of the image might significantly improve


230  the performance and heavily reduce the amount of memory when rendering


231  a QImage from the raster data.


232 


233  The default implementation returns an empty rectangle recommending


234  to render in target device ( f.e. screen ) resolution.


235 


236  \param area In most implementations the resolution of the data doesn't


237  depend on the requested area.


238 


239  \return Bounding rectangle of a pixel


240  */


241  QRectF QwtRasterData::pixelHint( const QRectF &area ) const


242  {


243  Q_UNUSED( area );


244  return QRectF();


245  }


246 


247  /*!


248  Calculate contour lines


249 


250  An adaption of CONREC, a simple contouring algorithm.


251  http://local.wasp.uwa.edu.au/~pbourke/papers/conrec/


252  */


253  QwtRasterData::ContourLines QwtRasterData::contourLines(


254  const QRectF &rect, const QSize &raster,


255  const QList<double> &levels, ConrecFlags flags ) const


256  {


257  ContourLines contourLines;


258 


259  if ( levels.size() == 0  !rect.isValid()  !raster.isValid() )


260  return contourLines;


261 


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


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


264 


265  const bool ignoreOnPlane =


266  flags & QwtRasterData::IgnoreAllVerticesOnLevel;


267 


268  const QwtInterval range = interval( Qt::ZAxis );


269  bool ignoreOutOfRange = false;


270  if ( range.isValid() )


271  ignoreOutOfRange = flags & IgnoreOutOfRange;


272 


273  QwtRasterData *that = const_cast<QwtRasterData *>( this );


274  that>initRaster( rect, raster );


275 


276  for ( int y = 0; y < raster.height()  1; y++ )


277  {


278  enum Position


279  {


280  Center,


281 


282  TopLeft,


283  TopRight,


284  BottomRight,


285  BottomLeft,


286 


287  NumPositions


288  };


289 


290  QwtPoint3D xy[NumPositions];


291 


292  for ( int x = 0; x < raster.width()  1; x++ )


293  {


294  const QPointF pos( rect.x() + x * dx, rect.y() + y * dy );


295 


296  if ( x == 0 )


297  {


298  xy[TopRight].setX( pos.x() );


299  xy[TopRight].setY( pos.y() );


300  xy[TopRight].setZ(


301  value( xy[TopRight].x(), xy[TopRight].y() )


302  );


303 


304  xy[BottomRight].setX( pos.x() );


305  xy[BottomRight].setY( pos.y() + dy );


306  xy[BottomRight].setZ(


307  value( xy[BottomRight].x(), xy[BottomRight].y() )


308  );


309  }


310 


311  xy[TopLeft] = xy[TopRight];


312  xy[BottomLeft] = xy[BottomRight];


313 


314  xy[TopRight].setX( pos.x() + dx );


315  xy[TopRight].setY( pos.y() );


316  xy[BottomRight].setX( pos.x() + dx );


317  xy[BottomRight].setY( pos.y() + dy );


318 


319  xy[TopRight].setZ(


320  value( xy[TopRight].x(), xy[TopRight].y() )


321  );


322  xy[BottomRight].setZ(


323  value( xy[BottomRight].x(), xy[BottomRight].y() )


324  );


325 


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


327  double zMax = zMin;


328  double zSum = zMin;


329 


330  for ( int i = TopRight; i <= BottomLeft; i++ )


331  {


332  const double z = xy[i].z();


333 


334  zSum += z;


335  if ( z < zMin )


336  zMin = z;


337  if ( z > zMax )


338  zMax = z;


339  }


340 


341  if ( ignoreOutOfRange )


342  {


343  if ( !range.contains( zMin )  !range.contains( zMax ) )


344  continue;


345  }


346 


347  if ( zMax < levels[0] 


348  zMin > levels[levels.size()  1] )


349  {


350  continue;


351  }


352 


353  xy[Center].setX( pos.x() + 0.5 * dx );


354  xy[Center].setY( pos.y() + 0.5 * dy );


355  xy[Center].setZ( 0.25 * zSum );


356 


357  const int numLevels = levels.size();


358  for ( int l = 0; l < numLevels; l++ )


359  {


360  const double level = levels[l];


361  if ( level < zMin  level > zMax )


362  continue;


363  QPolygonF &lines = contourLines[level];


364  const ContourPlane plane( level );


365 


366  QPointF line[2];


367  QwtPoint3D vertex[3];


368 


369  for ( int m = TopLeft; m < NumPositions; m++ )


370  {


371  vertex[0] = xy[m];


372  vertex[1] = xy[0];


373  vertex[2] = xy[m != BottomLeft ? m + 1 : TopLeft];


374 


375  const bool intersects =


376  plane.intersect( vertex, line, ignoreOnPlane );


377  if ( intersects )


378  {


379  lines += line[0];


380  lines += line[1];


381  }


382  }


383  }


384  }


385  }


386 


387  that>discardRaster();


388 


389  return contourLines;


390  }

