5#ifndef QWT_GRID_DATA_HPP
6#define QWT_GRID_DATA_HPP
89 typename XContainer = std::vector< T >,
90 typename YContainer = std::vector< T >,
91 typename DataColumn = std::vector< T >,
92 typename DataContainer = std::vector< DataColumn > >
101 using size_type =
typename DataColumn::size_type;
113 BilinearInterpolation,
123 : m_mode(NearestNeighbour), m_xMin(0.0), m_xMax(0.0), m_yMin(0.0), m_yMax(0.0), m_dataMax(0.0), m_dataMin(0.0)
145 m_xMin =
xAxis.front();
146 m_xMax =
xAxis.back();
147 m_yMin =
yAxis.front();
148 m_yMax =
yAxis.back();
182 m_xMin =
xAxis.front();
183 m_xMax =
xAxis.back();
184 m_yMin =
yAxis.front();
185 m_yMax =
yAxis.back();
210 return value(xy.first, xy.second);
222 case NearestNeighbour:
224 case BilinearInterpolation:
226 case BicubicInterpolation:
229 throw std::runtime_error(
"Unknown resampling mode.");
259 return m_xAxis.size();
268 return m_yAxis.size();
287 return m_xAxis.at(ix);
297 return m_yAxis.at(iy);
307 return m_data.at(ix).at(iy);
347 if (m_xAxis.empty() || m_yAxis.empty() || m_data.empty()) {
350 if (m_xAxis.size() != m_data.size()) {
353 for (
const auto& column : m_data) {
354 if (column.size() != m_yAxis.size()) {
358 if (!std::is_sorted(m_xAxis.begin(), m_xAxis.end())) {
361 if (!std::is_sorted(m_yAxis.begin(), m_yAxis.end())) {
372 if (m_xAxis.empty() || m_yAxis.empty() || m_data.empty()) {
373 throw std::invalid_argument(
"Axes or data cannot be empty.");
375 if (m_data.size() != m_xAxis.size()) {
376 throw std::invalid_argument(
"Number of columns in data must match x-axis size.");
378 for (
const auto& column : m_data) {
379 if (column.size() != m_yAxis.size()) {
380 throw std::invalid_argument(
"Number of rows in data must match y-axis size.");
383 if (!std::is_sorted(m_xAxis.begin(), m_xAxis.end())) {
384 std::sort(m_xAxis.begin(), m_xAxis.end());
386 if (!std::is_sorted(m_yAxis.begin(), m_yAxis.end())) {
387 std::sort(m_yAxis.begin(), m_yAxis.end());
425 template<
typename Container >
428 auto it = std::lower_bound(arr.begin(), arr.end(), val);
429 if (it == arr.begin())
432 return arr.size() - 1;
433 size_type idx = std::distance(arr.begin(), it);
434 return (std::abs(arr[ idx ] - val) < std::abs(arr[ idx - 1 ] - val)) ? idx : idx - 1;
444 template<
typename Container >
447 auto it = std::lower_bound(arr.begin(), arr.end(), val);
448 if (it == arr.begin())
450 return std::distance(arr.begin(), it) - 1;
453 template<
typename V >
454 static const V& clamp(
const V&
value,
const V& lo,
const V& hi)
467 m_dataMin = std::numeric_limits< T >::max();
468 m_dataMax = std::numeric_limits< T >::lowest();
470 for (
const auto& column : m_data) {
471 for (
const auto& val : column) {
472 if (qwt_is_nan_or_inf(val))
474 m_dataMin = std::min(m_dataMin, val);
475 m_dataMax = std::max(m_dataMax, val);
480 m_dataMin = std::numeric_limits< T >::quiet_NaN();
481 m_dataMax = std::numeric_limits< T >::quiet_NaN();
497 return m_data[ xIdx ][ yIdx ];
511 size_type x1Idx = x0Idx + 1;
513 size_type y1Idx = y0Idx + 1;
515 T x0 = m_xAxis[ x0Idx ], x1 = m_xAxis[ x1Idx ];
516 T y0 = m_yAxis[ y0Idx ], y1 = m_yAxis[ y1Idx ];
518 T f00 = m_data[ x0Idx ][ y0Idx ];
519 T f10 = m_data[ x1Idx ][ y0Idx ];
520 T f01 = m_data[ x0Idx ][ y1Idx ];
521 T f11 = m_data[ x1Idx ][ y1Idx ];
523 T dx = (x - x0) / (x1 - x0);
524 T dy = (y - y0) / (y1 - y0);
526 return (1 - dx) * (1 - dy) * f00 + dx * (1 - dy) * f10 + (1 - dx) * dy * f01 + dx * dy * f11;
542 auto xIt = std::lower_bound(m_xAxis.begin(), m_xAxis.end(), x);
543 size_type x0, x1, x2, x3;
546 if (xIt == m_xAxis.begin()) {
552 }
else if (xIt == m_xAxis.end()) {
553 x0 = m_xAxis.size() - 3;
554 x1 = m_xAxis.size() - 2;
555 x2 = m_xAxis.size() - 1;
556 x3 = m_xAxis.size() - 1;
559 x0 = xIt - 2 - m_xAxis.begin();
562 x1 = xIt - 1 - m_xAxis.begin();
563 x2 = xIt - m_xAxis.begin();
564 x3 = xIt + 1 - m_xAxis.begin();
565 if (x3 >= m_xAxis.size())
566 x3 = m_xAxis.size() - 1;
567 xWeight =
static_cast< T
>(x - m_xAxis[ x1 ]) / (m_xAxis[ x2 ] - m_xAxis[ x1 ]);
571 auto yIt = std::lower_bound(m_yAxis.begin(), m_yAxis.end(), y);
572 size_type y0, y1, y2, y3;
575 if (yIt == m_yAxis.begin()) {
581 }
else if (yIt == m_yAxis.end()) {
582 y0 = m_yAxis.size() - 3;
583 y1 = m_yAxis.size() - 2;
584 y2 = m_yAxis.size() - 1;
585 y3 = m_yAxis.size() - 1;
588 y0 = yIt - 2 - m_yAxis.begin();
591 y1 = yIt - 1 - m_yAxis.begin();
592 y2 = yIt - m_yAxis.begin();
593 y3 = yIt + 1 - m_yAxis.begin();
594 if (y3 >= m_yAxis.size())
595 y3 = m_yAxis.size() - 1;
596 yWeight =
static_cast< T
>(y - m_yAxis[ y1 ]) / (m_yAxis[ y2 ] - m_yAxis[ y1 ]);
600 auto h00 = [](T t) {
return (1 + 2 * t) * (1 - t) * (1 - t); };
601 auto h10 = [](T t) {
return t * (1 - t) * (1 - t); };
602 auto h01 = [](T t) {
return t * t * (3 - 2 * t); };
603 auto h11 = [](T t) {
return t * t * (t - 1); };
607 for (
int i = 0; i < 4; ++i) {
610 v[ 0 ] = m_data[ x0 ][ y0 + i ];
611 v[ 1 ] = m_data[ x1 ][ y0 + i ];
612 v[ 2 ] = m_data[ x2 ][ y0 + i ];
613 v[ 3 ] = m_data[ x3 ][ y0 + i ];
616 values[ 0 ][ i ] = h00(xWeight) * v[ 1 ]
617 + h10(xWeight) * (m_xAxis[ x2 ] - m_xAxis[ x1 ])
618 * ((v[ 2 ] - v[ 1 ]) / (m_xAxis[ x2 ] - m_xAxis[ x1 ])
619 + (v[ 2 ] - v[ 1 ] - (v[ 1 ] - v[ 0 ]) / (m_xAxis[ x1 ] - m_xAxis[ x0 ]))
620 / (m_xAxis[ x2 ] - m_xAxis[ x0 ]) * (m_xAxis[ x2 ] - m_xAxis[ x1 ]))
621 + h01(xWeight) * v[ 2 ]
622 + h11(xWeight) * (m_xAxis[ x2 ] - m_xAxis[ x1 ])
623 * ((v[ 2 ] - v[ 1 ]) / (m_xAxis[ x2 ] - m_xAxis[ x1 ])
624 + (v[ 3 ] - v[ 2 ] - (v[ 2 ] - v[ 1 ]) / (m_xAxis[ x2 ] - m_xAxis[ x1 ]))
625 / (m_xAxis[ x3 ] - m_xAxis[ x1 ]) * (m_xAxis[ x2 ] - m_xAxis[ x1 ]));
630 v[ 0 ] = values[ 0 ][ 0 ];
631 v[ 1 ] = values[ 0 ][ 1 ];
632 v[ 2 ] = values[ 0 ][ 2 ];
633 v[ 3 ] = values[ 0 ][ 3 ];
635 return h00(yWeight) * v[ 1 ]
636 + h10(yWeight) * (m_yAxis[ y2 ] - m_yAxis[ y1 ])
637 * ((v[ 2 ] - v[ 1 ]) / (m_yAxis[ y2 ] - m_yAxis[ y1 ])
638 + (v[ 2 ] - v[ 1 ] - (v[ 1 ] - v[ 0 ]) / (m_yAxis[ y1 ] - m_yAxis[ y0 ]))
639 / (m_yAxis[ y2 ] - m_yAxis[ y0 ]) * (m_yAxis[ y2 ] - m_yAxis[ y1 ]))
640 + h01(yWeight) * v[ 2 ]
641 + h11(yWeight) * (m_yAxis[ y2 ] - m_yAxis[ y1 ])
642 * ((v[ 2 ] - v[ 1 ]) / (m_yAxis[ y2 ] - m_yAxis[ y1 ])
643 + (v[ 3 ] - v[ 2 ] - (v[ 2 ] - v[ 1 ]) / (m_yAxis[ y2 ] - m_yAxis[ y1 ]))
644 / (m_yAxis[ y3 ] - m_yAxis[ y1 ]) * (m_yAxis[ y2 ] - m_yAxis[ y1 ]));
668 T m_xMin, m_xMax, m_yMin, m_yMax, m_dataMin, m_dataMax;
A generic container class for storing 2D grid data and providing resampling methods.
Definition qwt_grid_data.hpp:94
T value(T x, T y) const
Query value at (x, y).
Definition qwt_grid_data.hpp:219
void setValue(const x_container_type &xAxis, const y_container_type &yAxis, const data_container_type &data)
Set new x-axis, y-axis, and data matrix.
Definition qwt_grid_data.hpp:175
size_type xSize() const
Size of x-axis
Definition qwt_grid_data.hpp:257
std::pair< size_type, size_type > valueSize() const
Size of the value matrix
Definition qwt_grid_data.hpp:275
T atY(size_type iy) const
Value at y-axis index
Definition qwt_grid_data.hpp:295
size_type ySize() const
Size of y-axis
Definition qwt_grid_data.hpp:266
ResampleMode resampleMode() const
Get the current resampling mode.
Definition qwt_grid_data.hpp:248
QwtGridData()
Default constructor.
Definition qwt_grid_data.hpp:122
XContainer x_container_type
Type of the x-axis container
Definition qwt_grid_data.hpp:97
void validate()
Validate the data.
Definition qwt_grid_data.hpp:370
T value_type
Type of the stored values
Definition qwt_grid_data.hpp:96
void findValueRange()
Get the minimum & maximum value in the data matrix.
Definition qwt_grid_data.hpp:465
T operator[](const std::pair< T, T > &xy) const
operator []
Definition qwt_grid_data.hpp:208
const y_container_type & yAxis() const
Get the y-axis values.
Definition qwt_grid_data.hpp:325
void setResampleMode(ResampleMode mode)
Set the resampling mode.
Definition qwt_grid_data.hpp:238
T bilinearInterpolation(T x, T y) const
Bilinear interpolation.
Definition qwt_grid_data.hpp:508
T atValue(size_type ix, size_type iy) const
Value at matrix index
Definition qwt_grid_data.hpp:305
T nearestNeighbour(T x, T y) const
Nearest neighbor interpolation.
Definition qwt_grid_data.hpp:493
YContainer y_container_type
Type of the y-axis container
Definition qwt_grid_data.hpp:98
static size_type findClosestIndex(const Container &arr, T val)
Find the closest index in a sorted array.
Definition qwt_grid_data.hpp:426
const data_container_type & data() const
Get the data matrix.
Definition qwt_grid_data.hpp:335
const x_container_type & xAxis() const
Get the x-axis values.
Definition qwt_grid_data.hpp:315
DataColumn data_column_type
Type of a single column in the data matrix
Definition qwt_grid_data.hpp:99
T operator()(T x, T y) const
Operator to query value at (x, y).
Definition qwt_grid_data.hpp:195
QwtGridData(const x_container_type &xAxis, const y_container_type &yAxis, const data_container_type &data, ResampleMode mode=NearestNeighbour)
Constructor with initial data.
Definition qwt_grid_data.hpp:137
bool valid() const
Check if the object is valid.
Definition qwt_grid_data.hpp:345
static size_type findLowerIndex(const Container &arr, T val)
Find the lower bound index in a sorted array.
Definition qwt_grid_data.hpp:445
ResampleMode
Enumeration for resampling methods.
Definition qwt_grid_data.hpp:111
T atX(size_type ix) const
Value at x-axis index
Definition qwt_grid_data.hpp:285
DataContainer data_container_type
Type of the data matrix
Definition qwt_grid_data.hpp:100
T bicubicInterpolation(T x, T y) const
Perform bicubic interpolation.
Definition qwt_grid_data.hpp:539