From 7c612f35a8a11e7b08497731501938a3bcb7f552 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Mon, 30 Mar 2020 18:03:10 +0200 Subject: [PATCH] [python] matplotlib: change Store::Rectangle structure to (left, right, top, bottom) and avoid rounding error when converting flaot rect to pixel --- .../port/mod/matplotlib/pyplot/modpyplot.cpp | 10 +++++----- .../port/mod/matplotlib/pyplot/plot_store.cpp | 18 ++++++++---------- python/port/mod/matplotlib/pyplot/plot_store.h | 16 ++++++++-------- .../port/mod/matplotlib/pyplot/plot_view.cpp | 14 ++++++++------ 4 files changed, 29 insertions(+), 29 deletions(-) diff --git a/python/port/mod/matplotlib/pyplot/modpyplot.cpp b/python/port/mod/matplotlib/pyplot/modpyplot.cpp index eea8af5e5..0cc1005d6 100644 --- a/python/port/mod/matplotlib/pyplot/modpyplot.cpp +++ b/python/port/mod/matplotlib/pyplot/modpyplot.cpp @@ -182,8 +182,9 @@ mp_obj_t modpyplot_bar(size_t n_args, const mp_obj_t *args) { mp_float_t iW = mp_obj_get_float(wItems[wLength > 1 ? i : 0]); mp_float_t iB = mp_obj_get_float(bItems[bLength > 1 ? i : 0]); mp_float_t iX = mp_obj_get_float(xItems[i])-iW/2.0; - mp_float_t iY = iH < 0.0 ? iB : iB + iH; - sPlotStore->addRect(mp_obj_new_float(iX), mp_obj_new_float(iY), mp_obj_new_float(iW), mp_obj_new_float(std::fabs(iH)), color); + mp_float_t iYStart = iH < 0.0 ? iB : iB + iH; + mp_float_t iYEnd = iH < 0.0 ? iB + iH : iB; + sPlotStore->addRect(mp_obj_new_float(iX), mp_obj_new_float(iX+iW), mp_obj_new_float(iYStart), mp_obj_new_float(iYEnd), color); // TODO: use float_binary_op? } return mp_const_none; } @@ -262,7 +263,7 @@ mp_obj_t modpyplot_hist(size_t n_args, const mp_obj_t *args) { mp_float_t upperBound = mp_obj_get_float(edgeItems[binIndex+1]); while (mp_obj_get_float(xItems[xIndex]) < upperBound || (binIndex == nBins - 1 && mp_obj_get_float(xItems[xIndex]) == upperBound)) { // Increment the bin count - binItems[binIndex] = mp_obj_new_int(mp_obj_get_int(binItems[binIndex]) + 1); // TODO: better way? + binItems[binIndex] = mp_obj_new_int(mp_obj_get_int(binItems[binIndex]) + 1); // TODO: better way? Use int_unary_op? xIndex++; if (xIndex == xLength) { break; @@ -273,8 +274,7 @@ mp_obj_t modpyplot_hist(size_t n_args, const mp_obj_t *args) { KDColor color = Palette::nextDataColor(&paletteIndex); for (size_t i=0; iaddRect(edgeItems[i], binItems[i], mp_obj_new_float(width), binItems[i], color); + sPlotStore->addRect(edgeItems[i], edgeItems[i+1], binItems[i], mp_obj_new_float(0.0), color); } return mp_const_none; } diff --git a/python/port/mod/matplotlib/pyplot/plot_store.cpp b/python/port/mod/matplotlib/pyplot/plot_store.cpp index 10c09c745..ede1a3af4 100644 --- a/python/port/mod/matplotlib/pyplot/plot_store.cpp +++ b/python/port/mod/matplotlib/pyplot/plot_store.cpp @@ -121,16 +121,16 @@ template class PlotStore::ListIterator; PlotStore::Rect::Rect(mp_obj_t tuple) { mp_obj_t * elements; mp_obj_get_array_fixed_n(tuple, 5, &elements); - m_x = mp_obj_get_float(elements[0]); - m_y = mp_obj_get_float(elements[1]); - m_width = mp_obj_get_float(elements[2]); - m_height = mp_obj_get_float(elements[3]); + m_left = mp_obj_get_float(elements[0]); + m_right = mp_obj_get_float(elements[1]); + m_top = mp_obj_get_float(elements[2]); + m_bottom = mp_obj_get_float(elements[3]); m_color = KDColor::RGB16(mp_obj_get_int(elements[4])); } -void PlotStore::addRect(mp_obj_t x, mp_obj_t y, mp_obj_t width, mp_obj_t height, KDColor c) { +void PlotStore::addRect(mp_obj_t left, mp_obj_t right, mp_obj_t top, mp_obj_t bottom, KDColor c) { mp_obj_t color = mp_obj_new_int(c); - mp_obj_t items[5] = {x, y, width, height, color}; + mp_obj_t items[5] = {left, right, top, bottom, color}; checkFloatType(items, 4); mp_obj_t tuple = mp_obj_new_tuple(5, items); mp_obj_list_append(m_rects, tuple); @@ -204,10 +204,8 @@ void PlotStore::initRange() { updateRange(&xMin, &xMax, &yMin, &yMax, segment.xEnd(), segment.yEnd()); } for (PlotStore::Rect rectangle : rects()) { - float x = rectangle.x(); - float y = rectangle.y(); - updateRange(&xMin, &xMax, &yMin, &yMax, x, y); - updateRange(&xMin, &xMax, &yMin, &yMax, x + rectangle.width(), y - rectangle.height()); + updateRange(&xMin, &xMax, &yMin, &yMax, rectangle.left(), rectangle.top()); + updateRange(&xMin, &xMax, &yMin, &yMax, rectangle.right(), rectangle.bottom()); } checkPositiveRangeAndAddMargin(&xMin, &xMax); checkPositiveRangeAndAddMargin(&yMin, &yMax); diff --git a/python/port/mod/matplotlib/pyplot/plot_store.h b/python/port/mod/matplotlib/pyplot/plot_store.h index 17329163f..d74b60cb0 100644 --- a/python/port/mod/matplotlib/pyplot/plot_store.h +++ b/python/port/mod/matplotlib/pyplot/plot_store.h @@ -87,16 +87,16 @@ public: class Rect { public: Rect(mp_obj_t tuple); - float x() const { return m_x; } - float y() const { return m_y; } - float width() const { return m_width; } - float height() const { return m_height; } + float left() const { return m_left; } + float right() const { return m_right; } + float top() const { return m_top; } + float bottom() const { return m_bottom; } KDColor color() const { return m_color; } private: - float m_x; - float m_y; - float m_width; - float m_height; + float m_left; + float m_right; + float m_top; + float m_bottom; KDColor m_color; }; diff --git a/python/port/mod/matplotlib/pyplot/plot_view.cpp b/python/port/mod/matplotlib/pyplot/plot_view.cpp index fdb4a9afb..eef482aef 100644 --- a/python/port/mod/matplotlib/pyplot/plot_view.cpp +++ b/python/port/mod/matplotlib/pyplot/plot_view.cpp @@ -54,13 +54,15 @@ void PlotView::traceSegment(KDContext * ctx, KDRect r, PlotStore::Segment segmen static inline KDCoordinate maxKDCoordinate(KDCoordinate x, KDCoordinate y) { return x > y ? x : y; } void PlotView::traceRect(KDContext * ctx, KDRect r, PlotStore::Rect rect) const { + KDCoordinate left = std::round(floatToPixel(Axis::Horizontal, rect.left())); + KDCoordinate right = std::round(floatToPixel(Axis::Horizontal, rect.right())); + KDCoordinate top = std::round(floatToPixel(Axis::Vertical, rect.top())); + KDCoordinate bottom = std::round(floatToPixel(Axis::Vertical, rect.bottom())); KDRect pixelRect( - std::round(floatToPixel(Axis::Horizontal, rect.x())), - std::round(floatToPixel(Axis::Vertical, rect.y())), - // Use std::ceil instead of std::round to avoid empty pixel line between bars and horizontal axis line - // TODO: change stored rectangles to keep all summits? - maxKDCoordinate(std::ceil(rect.width() / pixelWidth()), 1), // Rectangle should at least be visible - std::ceil(rect.height() / pixelHeight()) + left, + top, + maxKDCoordinate(right - left, 1), // Rectangle should at least be visible + bottom - top ); ctx->fillRect(pixelRect, rect.color()); }