Skip to content

Commit ddb95f0

Browse files
committed
contourc: Fix work with with vector_2d iterators by introducing vector_2d_view util class
This class could iterates over non-contiguous vector_2d unlike old `vec[0].data()` pointers.
1 parent d83e3f1 commit ddb95f0

File tree

2 files changed

+91
-7
lines changed

2 files changed

+91
-7
lines changed

source/matplot/util/common.h

Lines changed: 81 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,16 @@
66
#define MATPLOTPLUSPLUS_COMMON_H
77

88
#include <algorithm>
9+
#include <cctype>
910
#include <complex>
1011
#include <functional>
1112
#include <map>
1213
#include <matplot/util/concepts.h>
14+
#include <numeric>
1315
#include <sstream>
1416
#include <string>
1517
#include <string_view>
1618
#include <vector>
17-
#include <cctype>
1819

1920
namespace matplot {
2021
bool iequals(std::string_view str1, std::string_view str2);
@@ -504,6 +505,85 @@ namespace matplot {
504505

505506
double distance(double x1, double y1, double x2, double y2);
506507

508+
/// \brief Simple read-only 2d view for vector_2d.
509+
/// It could iterates over all vector's elements and get value using
510+
/// only one index (offset).
511+
class vector_2d_view {
512+
using vector_2d = matplot::vector_2d;
513+
const vector_2d &_vec;
514+
const std::size_t _sz;
515+
516+
/// \brief Helper method for determining the whole array size.
517+
/// Required for caching inner vector's size.
518+
std::size_t calculate_size(const vector_2d &vec) {
519+
return std::accumulate(
520+
vec.begin(), vec.end(), (std::size_t)(0),
521+
[](auto cnt, const auto &vec) { return cnt + vec.size(); });
522+
}
523+
524+
public:
525+
static const double &get_element_from_offset(const vector_2d &vec,
526+
std::size_t offset) {
527+
std::size_t row_size = vec[0].size();
528+
std::size_t cur_row = offset / row_size;
529+
std::size_t cur_column = offset % row_size;
530+
return vec[cur_row][cur_column];
531+
}
532+
533+
static vector_2d_view from_vector_2d(const vector_2d &vec) {
534+
return vector_2d_view(vec);
535+
}
536+
std::size_t size() const { return _sz; }
537+
vector_2d_view(const vector_2d &vec)
538+
: _vec(vec), _sz(calculate_size(vec)) {}
539+
540+
double operator()(std::size_t i, std::size_t j) {
541+
return _vec.at(i).at(j);
542+
}
543+
friend class iterator;
544+
545+
class iterator {
546+
vector_2d_view *const _vec;
547+
std::size_t _row_offset;
548+
std::size_t _col_offset;
549+
550+
static bool is_empty_iterator(const iterator &it) {
551+
return it._vec == nullptr;
552+
}
553+
static bool is_end_iterator(const iterator &it) {
554+
return is_empty_iterator(it) ||
555+
it._row_offset * it._col_offset >= it._vec->size();
556+
}
557+
558+
public:
559+
iterator(vector_2d_view *const vec)
560+
: _vec(vec), _row_offset(0), _col_offset(0) {}
561+
562+
bool operator==(const iterator &it) const {
563+
return is_end_iterator(it)
564+
? is_end_iterator(*this)
565+
: it._vec == _vec && it._row_offset == _row_offset &&
566+
it._col_offset == _col_offset;
567+
}
568+
569+
auto operator*() const { return (*_vec)(_row_offset, _col_offset); }
570+
571+
iterator &operator++() {
572+
_col_offset++;
573+
if (_col_offset >= _vec->_vec.at(_row_offset).size()) {
574+
_col_offset = 0;
575+
_row_offset++;
576+
}
577+
return *this;
578+
}
579+
580+
// iterator traits
581+
using value_type = double;
582+
};
583+
iterator begin() { return iterator{this}; }
584+
iterator end() { return iterator{nullptr}; }
585+
};
586+
507587
} // namespace matplot
508588

509589
#endif // MATPLOTPLUSPLUS_COMMON_H

source/matplot/util/contourc.cpp

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1188,13 +1188,16 @@ namespace matplot {
11881188

11891189
XY QuadContourGenerator::get_point_xy(long point) const {
11901190
assert(point >= 0 && point < _n && "Point index out of bounds.");
1191-
return XY(_x[0].data()[static_cast<size_t>(point)],
1192-
_y[0].data()[static_cast<size_t>(point)]);
1191+
return XY(vector_2d_view::get_element_from_offset(
1192+
_x, static_cast<size_t>(point)),
1193+
vector_2d_view::get_element_from_offset(
1194+
_y, static_cast<size_t>(point)));
11931195
}
11941196

11951197
const double &QuadContourGenerator::get_point_z(long point) const {
11961198
assert(point >= 0 && point < _n && "Point index out of bounds.");
1197-
return _z[0].data()[static_cast<size_t>(point)];
1199+
return vector_2d_view::get_element_from_offset(
1200+
_z, static_cast<size_t>(point));
11981201
}
11991202

12001203
Edge
@@ -1305,9 +1308,10 @@ namespace matplot {
13051308
(_corner_mask
13061309
? MASK_EXISTS | MASK_BOUNDARY_S | MASK_BOUNDARY_W
13071310
: MASK_EXISTS_QUAD | MASK_BOUNDARY_S | MASK_BOUNDARY_W);
1308-
1311+
auto z_view = vector_2d_view::from_vector_2d(_z);
13091312
if (two_levels) {
1310-
const double *z_ptr = _z[0].data();
1313+
1314+
auto z_ptr = z_view.begin();
13111315
for (long quad = 0; quad < _n; ++quad, ++z_ptr) {
13121316
_cache[quad] &= keep_mask;
13131317
if (*z_ptr > upper_level)
@@ -1316,7 +1320,7 @@ namespace matplot {
13161320
_cache[quad] |= MASK_Z_LEVEL_1;
13171321
}
13181322
} else {
1319-
const double *z_ptr = _z[0].data();
1323+
auto z_ptr = z_view.begin();
13201324
for (long quad = 0; quad < _n; ++quad, ++z_ptr) {
13211325
_cache[quad] &= keep_mask;
13221326
if (*z_ptr > lower_level)

0 commit comments

Comments
 (0)