Qwt User's Guide  6.2.0
qwt_matrix_raster_data.cpp
1 /******************************************************************************
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_matrix_raster_data.h"
11 #include "qwt_interval.h"
12 
13 #include <qvector.h>
14 #include <qnumeric.h>
15 #include <qrect.h>
16 
17 static inline double qwtHermiteInterpolate(
18  double A, double B, double C, double D, double t )
19 {
20  const double t2 = t * t;
21  const double t3 = t2 * t;
22 
23  const double a = -A / 2.0 + ( 3.0 * B ) / 2.0 - ( 3.0 * C ) / 2.0 + D / 2.0;
24  const double b = A - ( 5.0 * B ) / 2.0 + 2.0 * C - D / 2.0;
25  const double c = -A / 2.0 + C / 2.0;
26  const double d = B;
27 
28  return a * t3 + b * t2 + c * t + d;
29 }
30 
31 static inline double qwtBicubicInterpolate(
32  double v00, double v10, double v20, double v30,
33  double v01, double v11, double v21, double v31,
34  double v02, double v12, double v22, double v32,
35  double v03, double v13, double v23, double v33,
36  double dx, double dy )
37 {
38  const double v0 = qwtHermiteInterpolate( v00, v10, v20, v30, dx );
39  const double v1 = qwtHermiteInterpolate( v01, v11, v21, v31, dx );
40  const double v2 = qwtHermiteInterpolate( v02, v12, v22, v32, dx );
41  const double v3 = qwtHermiteInterpolate( v03, v13, v23, v33, dx );
42 
43  return qwtHermiteInterpolate( v0, v1, v2, v3, dy );
44 }
45 
46 class QwtMatrixRasterData::PrivateData
47 {
48  public:
49  PrivateData()
51  , numColumns(0)
52  {
53  }
54 
55  inline double value(int row, int col) const
56  {
57  return values.data()[ row * numColumns + col ];
58  }
59 
60  QwtInterval intervals[3];
62 
63  QVector< double > values;
64  int numColumns;
65  int numRows;
66 
67  double dx;
68  double dy;
69 };
70 
73 {
74  m_data = new PrivateData();
75  update();
76 }
77 
80 {
81  delete m_data;
82 }
83 
91 {
92  m_data->resampleMode = mode;
93 }
94 
100 {
101  return m_data->resampleMode;
102 }
103 
121  Qt::Axis axis, const QwtInterval& interval )
122 {
123  if ( axis >= 0 && axis <= 2 )
124  {
125  m_data->intervals[axis] = interval;
126  update();
127  }
128 }
129 
135 {
136  if ( axis >= 0 && axis <= 2 )
137  return m_data->intervals[ axis ];
138 
139  return QwtInterval();
140 }
141 
156  const QVector< double >& values, int numColumns )
157 {
158  m_data->values = values;
159  m_data->numColumns = qMax( numColumns, 0 );
160  update();
161 }
162 
168 {
169  return m_data->values;
170 }
171 
181 void QwtMatrixRasterData::setValue( int row, int col, double value )
182 {
183  if ( row >= 0 && row < m_data->numRows &&
184  col >= 0 && col < m_data->numColumns )
185  {
186  const int index = row * m_data->numColumns + col;
187  m_data->values.data()[ index ] = value;
188  }
189 }
190 
196 {
197  return m_data->numColumns;
198 }
199 
205 {
206  return m_data->numRows;
207 }
208 
229 QRectF QwtMatrixRasterData::pixelHint( const QRectF& area ) const
230 {
231  Q_UNUSED( area )
232 
233  QRectF rect;
234  if ( m_data->resampleMode == NearestNeighbour )
235  {
236  const QwtInterval intervalX = interval( Qt::XAxis );
237  const QwtInterval intervalY = interval( Qt::YAxis );
238  if ( intervalX.isValid() && intervalY.isValid() )
239  {
240  rect = QRectF( intervalX.minValue(), intervalY.minValue(),
241  m_data->dx, m_data->dy );
242  }
243  }
244 
245  return rect;
246 }
247 
256 double QwtMatrixRasterData::value( double x, double y ) const
257 {
258  const QwtInterval xInterval = interval( Qt::XAxis );
259  const QwtInterval yInterval = interval( Qt::YAxis );
260 
261  if ( !( xInterval.contains(x) && yInterval.contains(y) ) )
262  return qQNaN();
263 
264  double value;
265 
266  switch( m_data->resampleMode )
267  {
269  {
270  const double colF = ( x - xInterval.minValue() ) / m_data->dx;
271  const double rowF = ( y - yInterval.minValue() ) / m_data->dy;
272 
273  const int col = qRound( colF );
274  const int row = qRound( rowF );
275 
276  int col0 = col - 2;
277  int col1 = col - 1;
278  int col2 = col;
279  int col3 = col + 1;
280 
281  if ( col1 < 0 )
282  col1 = col2;
283 
284  if ( col0 < 0 )
285  col0 = col1;
286 
287  if ( col2 >= m_data->numColumns )
288  col2 = col1;
289 
290  if ( col3 >= m_data->numColumns )
291  col3 = col2;
292 
293  int row0 = row - 2;
294  int row1 = row - 1;
295  int row2 = row;
296  int row3 = row + 1;
297 
298  if ( row1 < 0 )
299  row1 = row2;
300 
301  if ( row0 < 0 )
302  row0 = row1;
303 
304  if ( row2 >= m_data->numRows )
305  row2 = row1;
306 
307  if ( row3 >= m_data->numRows )
308  row3 = row2;
309 
310  // First row
311  const double v00 = m_data->value( row0, col0 );
312  const double v10 = m_data->value( row0, col1 );
313  const double v20 = m_data->value( row0, col2 );
314  const double v30 = m_data->value( row0, col3 );
315 
316  // Second row
317  const double v01 = m_data->value( row1, col0 );
318  const double v11 = m_data->value( row1, col1 );
319  const double v21 = m_data->value( row1, col2 );
320  const double v31 = m_data->value( row1, col3 );
321 
322  // Third row
323  const double v02 = m_data->value( row2, col0 );
324  const double v12 = m_data->value( row2, col1 );
325  const double v22 = m_data->value( row2, col2 );
326  const double v32 = m_data->value( row2, col3 );
327 
328  // Fourth row
329  const double v03 = m_data->value( row3, col0 );
330  const double v13 = m_data->value( row3, col1 );
331  const double v23 = m_data->value( row3, col2 );
332  const double v33 = m_data->value( row3, col3 );
333 
334  value = qwtBicubicInterpolate(
335  v00, v10, v20, v30, v01, v11, v21, v31,
336  v02, v12, v22, v32, v03, v13, v23, v33,
337  colF - col + 0.5, rowF - row + 0.5 );
338 
339  break;
340  }
342  {
343  int col1 = qRound( ( x - xInterval.minValue() ) / m_data->dx ) - 1;
344  int row1 = qRound( ( y - yInterval.minValue() ) / m_data->dy ) - 1;
345  int col2 = col1 + 1;
346  int row2 = row1 + 1;
347 
348  if ( col1 < 0 )
349  col1 = col2;
350  else if ( col2 >= m_data->numColumns )
351  col2 = col1;
352 
353  if ( row1 < 0 )
354  row1 = row2;
355  else if ( row2 >= m_data->numRows )
356  row2 = row1;
357 
358  const double v11 = m_data->value( row1, col1 );
359  const double v21 = m_data->value( row1, col2 );
360  const double v12 = m_data->value( row2, col1 );
361  const double v22 = m_data->value( row2, col2 );
362 
363  const double x2 = xInterval.minValue() + ( col2 + 0.5 ) * m_data->dx;
364  const double y2 = yInterval.minValue() + ( row2 + 0.5 ) * m_data->dy;
365 
366  const double rx = ( x2 - x ) / m_data->dx;
367  const double ry = ( y2 - y ) / m_data->dy;
368 
369  const double vr1 = rx * v11 + ( 1.0 - rx ) * v21;
370  const double vr2 = rx * v12 + ( 1.0 - rx ) * v22;
371 
372  value = ry * vr1 + ( 1.0 - ry ) * vr2;
373 
374  break;
375  }
376  case NearestNeighbour:
377  default:
378  {
379  int row = int( ( y - yInterval.minValue() ) / m_data->dy );
380  int col = int( ( x - xInterval.minValue() ) / m_data->dx );
381 
382  // In case of intervals, where the maximum is included
383  // we get out of bound for row/col, when the value for the
384  // maximum is requested. Instead we return the value
385  // from the last row/col
386 
387  if ( row >= m_data->numRows )
388  row = m_data->numRows - 1;
389 
390  if ( col >= m_data->numColumns )
391  col = m_data->numColumns - 1;
392 
393  value = m_data->value( row, col );
394  }
395  }
396 
397  return value;
398 }
399 
400 void QwtMatrixRasterData::update()
401 {
402  m_data->numRows = 0;
403  m_data->dx = 0.0;
404  m_data->dy = 0.0;
405 
406  if ( m_data->numColumns > 0 )
407  {
408  m_data->numRows = m_data->values.size() / m_data->numColumns;
409 
410  const QwtInterval xInterval = interval( Qt::XAxis );
411  const QwtInterval yInterval = interval( Qt::YAxis );
412  if ( xInterval.isValid() )
413  m_data->dx = xInterval.width() / m_data->numColumns;
414  if ( yInterval.isValid() )
415  m_data->dy = yInterval.width() / m_data->numRows;
416  }
417 }
A class representing an interval.
Definition: qwt_interval.h:23
double minValue() const
Definition: qwt_interval.h:192
double width() const
Return the width of an interval.
Definition: qwt_interval.h:227
bool isValid() const
Definition: qwt_interval.h:210
bool contains(double value) const
A class representing a matrix of values as raster data.
void setResampleMode(ResampleMode mode)
Set the resampling algorithm.
virtual double value(double x, double y) const override
virtual ~QwtMatrixRasterData()
Destructor.
virtual QwtInterval interval(Qt::Axis axis) const override final
ResampleMode
Resampling algorithm The default setting is NearestNeighbour;.
void setValue(int row, int col, double value)
Change a single value in the matrix.
void setValueMatrix(const QVector< double > &values, int numColumns)
Assign a value matrix.
void setInterval(Qt::Axis, const QwtInterval &)
Assign the bounding interval for an axis.
virtual QRectF pixelHint(const QRectF &) const override
Calculate the pixel hint.
const QVector< double > valueMatrix() const
ResampleMode resampleMode() const