Qwt User's Guide 6.3.0
Loading...
Searching...
No Matches
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
17static 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
31static 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
46class QwtMatrixRasterData::PrivateData
47{
48 public:
49 PrivateData()
50 : resampleMode( QwtMatrixRasterData::NearestNeighbour )
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
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
181void 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
229QRectF 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
256double 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
400void 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.
double minValue() const
double width() const
Return the width of an interval.
bool isValid() const
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