From ef8f5e07c2d870a86fb7cf0652b6b2efc4276d80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Mon, 8 Jan 2018 11:43:55 +0100 Subject: [PATCH] [apps] In CurveView, replace the virtual method evaluateModelWithParameter by a function given as parameter (to be able to call Curve view methods with different implementation of evaluateModelWithParameter) --- apps/graph/graph/graph_view.cpp | 11 +++++------ apps/graph/graph/graph_view.h | 1 - apps/probability/law_curve_view.cpp | 9 +++++---- apps/probability/law_curve_view.h | 2 +- apps/regression/graph_view.cpp | 17 +++++++---------- apps/regression/graph_view.h | 6 ------ apps/sequence/graph/graph_view.cpp | 7 +------ apps/sequence/graph/graph_view.h | 1 - apps/shared/curve_view.cpp | 26 +++++++++++--------------- apps/shared/curve_view.h | 9 ++++----- apps/statistics/histogram_view.cpp | 18 ++++++++++-------- apps/statistics/histogram_view.h | 5 +---- 12 files changed, 45 insertions(+), 67 deletions(-) diff --git a/apps/graph/graph/graph_view.cpp b/apps/graph/graph/graph_view.cpp index ec35f887f..9ee339f00 100644 --- a/apps/graph/graph/graph_view.cpp +++ b/apps/graph/graph/graph_view.cpp @@ -15,13 +15,12 @@ void GraphView::drawRect(KDContext * ctx, KDRect rect) const { FunctionGraphView::drawRect(ctx, rect); for (int i = 0; i < m_functionStore->numberOfActiveFunctions(); i++) { CartesianFunction * f = m_functionStore->activeFunctionAtIndex(i); - drawCurve(ctx, rect, f, f->color()); + drawCurve(ctx, rect, [](float t, void * model, void * context) { + CartesianFunction * f = (CartesianFunction *)model; + Poincare::Context * c = (Poincare::Context *)context; + return f->evaluateAtAbscissa(t, c); + }, f, context(), f->color()); } } -float GraphView::evaluateModelWithParameter(Model * curve, float abscissa) const { - CartesianFunction * f = (CartesianFunction *)curve; - return f->evaluateAtAbscissa(abscissa, context()); -} - } diff --git a/apps/graph/graph/graph_view.h b/apps/graph/graph/graph_view.h index cd5f30c68..1692f681f 100644 --- a/apps/graph/graph/graph_view.h +++ b/apps/graph/graph/graph_view.h @@ -12,7 +12,6 @@ public: Shared::CurveViewCursor * cursor, Shared::BannerView * bannerView, View * cursorView); void drawRect(KDContext * ctx, KDRect rect) const override; private: - float evaluateModelWithParameter(Model * expression, float abscissa) const override; CartesianFunctionStore * m_functionStore; }; diff --git a/apps/probability/law_curve_view.cpp b/apps/probability/law_curve_view.cpp index 07dd3b6b9..4fbbd167d 100644 --- a/apps/probability/law_curve_view.cpp +++ b/apps/probability/law_curve_view.cpp @@ -27,9 +27,9 @@ void LawCurveView::drawRect(KDContext * ctx, KDRect rect) const { drawAxes(ctx, rect, Axis::Horizontal); drawLabels(ctx, rect, Axis::Horizontal, false); if (m_law->isContinuous()) { - drawCurve(ctx, rect, m_law, Palette::YellowDark, true, lowerBound, upperBound, true); + drawCurve(ctx, rect, EvaluateAtAbscissa, m_law, nullptr, Palette::YellowDark, true, lowerBound, upperBound, true); } else { - drawHistogram(ctx, rect, m_law, 0, 1, false, Palette::GreyMiddle, Palette::YellowDark, lowerBound, upperBound+0.5f); + drawHistogram(ctx, rect, EvaluateAtAbscissa, m_law, nullptr, 0, 1, false, Palette::GreyMiddle, Palette::YellowDark, lowerBound, upperBound+0.5f); } } @@ -40,8 +40,9 @@ char * LawCurveView::label(Axis axis, int index) const { return (char *)m_labels[index]; } -float LawCurveView::evaluateModelWithParameter(void * law, float abscissa) const { - return m_law->evaluateAtAbscissa(abscissa); +float LawCurveView::EvaluateAtAbscissa(float abscissa, void * model, void * context) { + Law * law = (Law *)model; + return law->evaluateAtAbscissa(abscissa); } } diff --git a/apps/probability/law_curve_view.h b/apps/probability/law_curve_view.h index d1d8b3410..f6b820d60 100644 --- a/apps/probability/law_curve_view.h +++ b/apps/probability/law_curve_view.h @@ -19,7 +19,7 @@ protected: char * label(Axis axis, int index) const override; private: char m_labels[k_maxNumberOfXLabels][Poincare::PrintFloat::bufferSizeForFloatsWithPrecision(Constant::ShortNumberOfSignificantDigits)]; - float evaluateModelWithParameter(Model * law, float abscissa) const override; + static float EvaluateAtAbscissa(float abscissa, void * model, void * context); Law * m_law; Calculation * m_calculation; }; diff --git a/apps/regression/graph_view.cpp b/apps/regression/graph_view.cpp index 09bbefc59..af696bbee 100644 --- a/apps/regression/graph_view.cpp +++ b/apps/regression/graph_view.cpp @@ -9,9 +9,7 @@ GraphView::GraphView(Store * store, CurveViewCursor * cursor, BannerView * banne CurveView(store, cursor, bannerView, cursorView), m_store(store), m_xLabels{}, - m_yLabels{}, - m_slope(NAN), - m_yIntercept(NAN) + m_yLabels{} { } @@ -22,9 +20,12 @@ void GraphView::drawRect(KDContext * ctx, KDRect rect) const { drawAxes(ctx, rect, Axis::Vertical); drawLabels(ctx, rect, Axis::Horizontal, true); drawLabels(ctx, rect, Axis::Vertical, true); - m_slope = m_store->slope(); - m_yIntercept = m_store->yIntercept(); - drawCurve(ctx, rect, nullptr, Palette::YellowDark); + float regressionParameters[2] = {(float)m_store->slope(), (float)m_store->yIntercept()}; + drawCurve(ctx, rect, [](float abscissa, void * model, void * context) { + float * params = (float *)model; + return params[0]*abscissa+params[1]; + }, + regressionParameters, nullptr, Palette::YellowDark); for (int index = 0; index < m_store->numberOfPairs(); index++) { drawDot(ctx, rect, m_store->get(0,index), m_store->get(1,index), Palette::Red); } @@ -39,8 +40,4 @@ char * GraphView::label(Axis axis, int index) const { return (char *)m_xLabels[index]; } -float GraphView::evaluateModelWithParameter(Model * curve, float t) const { - return m_slope*t+m_yIntercept; -} - } diff --git a/apps/regression/graph_view.h b/apps/regression/graph_view.h index 39a55094d..de60b5e91 100644 --- a/apps/regression/graph_view.h +++ b/apps/regression/graph_view.h @@ -14,15 +14,9 @@ public: void drawRect(KDContext * ctx, KDRect rect) const override; private: char * label(Axis axis, int index) const override; - float evaluateModelWithParameter(Model * curve, float t) const override; Store * m_store; char m_xLabels[k_maxNumberOfXLabels][Poincare::PrintFloat::bufferSizeForFloatsWithPrecision(Constant::ShortNumberOfSignificantDigits)]; char m_yLabels[k_maxNumberOfYLabels][Poincare::PrintFloat::bufferSizeForFloatsWithPrecision(Constant::ShortNumberOfSignificantDigits)]; - /* We memoize the a and b of the regression y = ax+b to avoid recomputing them - * for each stamp of the curve (since the computation is done with double - * precision) */ - mutable float m_slope; - mutable float m_yIntercept; }; } diff --git a/apps/sequence/graph/graph_view.cpp b/apps/sequence/graph/graph_view.cpp index d146d4bb6..18ada18e1 100644 --- a/apps/sequence/graph/graph_view.cpp +++ b/apps/sequence/graph/graph_view.cpp @@ -29,7 +29,7 @@ void GraphView::drawRect(KDContext * ctx, KDRect rect) const { float windowRange = pixelToFloat(Axis::Horizontal, bounds().width()) - pixelToFloat(Axis::Horizontal, 0); int step = std::ceil(windowRange/resolution()); for (int x = rectXMin; x < rectXMax; x += step) { - float y = evaluateModelWithParameter(s, x); + float y = s->evaluateAtAbscissa((float)x, context()); if (std::isnan(y)) { continue; } @@ -92,11 +92,6 @@ float GraphView::samplingRatio() const { return 5.0f; } -float GraphView::evaluateModelWithParameter(Model * curve, float abscissa) const { - Sequence * s = (Sequence *)curve; - return s->evaluateAtAbscissa(abscissa, context()); -} - KDSize GraphView::cursorSize() { if (m_verticalCursor) { return KDSize(1, 0); diff --git a/apps/sequence/graph/graph_view.h b/apps/sequence/graph/graph_view.h index 0c8486faa..b5723689d 100644 --- a/apps/sequence/graph/graph_view.h +++ b/apps/sequence/graph/graph_view.h @@ -18,7 +18,6 @@ public: void setHighlightColor(bool highlightColor); private: float samplingRatio() const override; - float evaluateModelWithParameter(Model * expression, float abscissa) const override; KDSize cursorSize() override; SequenceStore * m_sequenceStore; bool m_verticalCursor; diff --git a/apps/shared/curve_view.cpp b/apps/shared/curve_view.cpp index 7c37afd35..e87df7956 100644 --- a/apps/shared/curve_view.cpp +++ b/apps/shared/curve_view.cpp @@ -301,7 +301,7 @@ const uint8_t stampMask[stampSize+1][stampSize+1] = { constexpr static int k_maxNumberOfIterations = 10; -void CurveView::drawCurve(KDContext * ctx, KDRect rect, Model * curve, KDColor color, bool colorUnderCurve, float colorLowerBound, float colorUpperBound, bool continuously) const { +void CurveView::drawCurve(KDContext * ctx, KDRect rect, EvaluateModelWithParameter evaluation, void * model, void * context, KDColor color, bool colorUnderCurve, float colorLowerBound, float colorUpperBound, bool continuously) const { float xMin = min(Axis::Horizontal); float xMax = max(Axis::Horizontal); float xStep = (xMax-xMin)/resolution(); @@ -313,7 +313,7 @@ void CurveView::drawCurve(KDContext * ctx, KDRect rect, Model * curve, KDColor c if (x == x-xStep || x == x+xStep) { return; } - float y = evaluateModelWithParameter(curve, x); + float y = evaluation(x, model, context); if (std::isnan(y)|| std::isinf(y)) { continue; } @@ -327,20 +327,20 @@ void CurveView::drawCurve(KDContext * ctx, KDRect rect, Model * curve, KDColor c ctx->fillRect(colorRect, color); } stampAtLocation(ctx, rect, pxf, pyf, color); - if (x <= rectMin || std::isnan(evaluateModelWithParameter(curve, x-xStep))) { + if (x <= rectMin || std::isnan(evaluation(x-xStep, model, context))) { continue; } if (continuously) { float puf = floatToPixel(Axis::Horizontal, x - xStep); - float pvf = floatToPixel(Axis::Vertical, evaluateModelWithParameter(curve, x-xStep)); + float pvf = floatToPixel(Axis::Vertical, evaluation(x-xStep, model, context)); straightJoinDots(ctx, rect, puf, pvf, pxf, pyf, color); } else { - jointDots(ctx, rect, curve, x - xStep, evaluateModelWithParameter(curve, x-xStep), x, y, color, k_maxNumberOfIterations); + jointDots(ctx, rect, evaluation, model, context, x - xStep, evaluation(x-xStep, model, context), x, y, color, k_maxNumberOfIterations); } } } -void CurveView::drawHistogram(KDContext * ctx, KDRect rect, Model * model, float firstBarAbscissa, float barWidth, +void CurveView::drawHistogram(KDContext * ctx, KDRect rect, EvaluateModelWithParameter evaluation, void * model, void * context, float firstBarAbscissa, float barWidth, bool fillBar, KDColor defaultColor, KDColor highlightColor, float highlightLowerBound, float highlightUpperBound) const { float rectMin = pixelToFloat(Axis::Horizontal, rect.left()); float rectMinBinNumber = std::floor((rectMin - firstBarAbscissa)/barWidth); @@ -357,7 +357,7 @@ void CurveView::drawHistogram(KDContext * ctx, KDRect rect, Model * model, float return; } float centerX = fillBar ? x+barWidth/2.0f : x; - float y = evaluateModelWithParameter(model, centerX); + float y = evaluation(centerX, model, context); if (std::isnan(y)) { continue; } @@ -385,15 +385,11 @@ int CurveView::numberOfLabels(Axis axis) const { return std::ceil((max(axis) - min(axis))/(2*gridUnit(axis))); } -float CurveView::evaluateModelWithParameter(Model * curve, float t) const { - return 0.0f; -} - KDSize CurveView::cursorSize() { return KDSize(k_cursorSize, k_cursorSize); } -void CurveView::jointDots(KDContext * ctx, KDRect rect, Model * curve, float x, float y, float u, float v, KDColor color, int maxNumberOfRecursion) const { +void CurveView::jointDots(KDContext * ctx, KDRect rect, EvaluateModelWithParameter evaluation, void * model, void * context, float x, float y, float u, float v, KDColor color, int maxNumberOfRecursion) const { float pyf = floatToPixel(Axis::Vertical, y); float pvf = floatToPixel(Axis::Vertical, v); if (std::isnan(pyf) || std::isnan(pvf)) { @@ -416,7 +412,7 @@ void CurveView::jointDots(KDContext * ctx, KDRect rect, Model * curve, float x, } // C is the dot whose abscissa is between x and u float cx = (x + u)/2.0f; - float cy = evaluateModelWithParameter(curve, cx); + float cy = evaluation(cx, model, context); if ((y <= cy && cy <= v) || (v <= cy && cy <= y)) { /* As the middle dot is vertically between the two dots, we assume that we * can draw a 'straight' line between the two */ @@ -432,8 +428,8 @@ void CurveView::jointDots(KDContext * ctx, KDRect rect, Model * curve, float x, float pcyf = floatToPixel(Axis::Vertical, cy); if (maxNumberOfRecursion > 0) { stampAtLocation(ctx, rect, pcxf, pcyf, color); - jointDots(ctx, rect, curve, x, y, cx, cy, color, maxNumberOfRecursion-1); - jointDots(ctx, rect, curve, cx, cy, u, v, color, maxNumberOfRecursion-1); + jointDots(ctx, rect, evaluation, model, context, x, y, cx, cy, color, maxNumberOfRecursion-1); + jointDots(ctx, rect, evaluation, model, context, cx, cy, u, v, color, maxNumberOfRecursion-1); } } diff --git a/apps/shared/curve_view.h b/apps/shared/curve_view.h index 3609392eb..610ddaed0 100644 --- a/apps/shared/curve_view.h +++ b/apps/shared/curve_view.h @@ -12,7 +12,7 @@ namespace Shared { class CurveView : public View { public: - typedef void Model; + typedef float (*EvaluateModelWithParameter)(float t, void * model, void * context); enum class Axis { Horizontal = 0, Vertical = 1 @@ -49,8 +49,8 @@ protected: void drawGridLines(KDContext * ctx, KDRect rect, Axis axis, float step, KDColor color) const; void drawGrid(KDContext * ctx, KDRect rect) const; void drawAxes(KDContext * ctx, KDRect rect, Axis axis) const; - void drawCurve(KDContext * ctx, KDRect rect, Model * curve, KDColor color, bool colorUnderCurve = false, float colorLowerBound = 0.0f, float colorUpperBound = 0.0f, bool continuously = false) const; - void drawHistogram(KDContext * ctx, KDRect rect, Model * model, float firstBarAbscissa, float barWidth, + void drawCurve(KDContext * ctx, KDRect rect, EvaluateModelWithParameter evaluation, void * model, void * context, KDColor color, bool colorUnderCurve = false, float colorLowerBound = 0.0f, float colorUpperBound = 0.0f, bool continuously = false) const; + void drawHistogram(KDContext * ctx, KDRect rect, EvaluateModelWithParameter evaluation, void * model, void * context, float firstBarAbscissa, float barWidth, bool fillBar, KDColor defaultColor, KDColor highlightColor, float highlightLowerBound = INFINITY, float highlightUpperBound = -INFINITY) const; void computeLabels(Axis axis); void drawLabels(KDContext * ctx, KDRect rect, Axis axis, bool shiftOrigin) const; @@ -65,10 +65,9 @@ private: KDCoordinate pixelLength(Axis axis) const; virtual char * label(Axis axis, int index) const = 0; int numberOfLabels(Axis axis) const; - virtual float evaluateModelWithParameter(Model * curve, float t) const; /* Recursively join two dots (dichotomy). The method stops when the * maxNumberOfRecursion in reached. */ - void jointDots(KDContext * ctx, KDRect rect, Model * curve, float x, float y, float u, float v, KDColor color, int maxNumberOfRecursion) const; + void jointDots(KDContext * ctx, KDRect rect, EvaluateModelWithParameter evaluation, void * model, void * context, float x, float y, float u, float v, KDColor color, int maxNumberOfRecursion) const; /* Join two dots with a straight line. */ void straightJoinDots(KDContext * ctx, KDRect rect, float pxf, float pyf, float puf, float pvf, KDColor color) const; /* Stamp centered around (pxf, pyf). If pxf and pyf are not round number, the diff --git a/apps/statistics/histogram_view.cpp b/apps/statistics/histogram_view.cpp index 2782e5518..a1af3b496 100644 --- a/apps/statistics/histogram_view.cpp +++ b/apps/statistics/histogram_view.cpp @@ -11,8 +11,7 @@ HistogramView::HistogramView(Store * store, BannerView * bannerView) : m_store(store), m_labels{}, m_highlightedBarStart(NAN), - m_highlightedBarEnd(NAN), - m_totalSize(NAN) + m_highlightedBarEnd(NAN) { } @@ -28,15 +27,16 @@ void HistogramView::reload() { } void HistogramView::drawRect(KDContext * ctx, KDRect rect) const { - m_totalSize = m_store->sumOfColumn(1); ctx->fillRect(rect, KDColorWhite); drawAxes(ctx, rect, Axis::Horizontal); drawLabels(ctx, rect, Axis::Horizontal, false); + /* We memoize the total size to avoid recomputing it in double precision at + * every call to EvaluateHistogramAtAbscissa() */ + float totalSize = m_store->sumOfColumn(1); if (isMainViewSelected()) { - drawHistogram(ctx, rect, nullptr, m_store->firstDrawnBarAbscissa(), m_store->barWidth(), true, Palette::Select, Palette::YellowDark, - m_highlightedBarStart, m_highlightedBarEnd); + drawHistogram(ctx, rect, EvaluateHistogramAtAbscissa, m_store, &totalSize, m_store->firstDrawnBarAbscissa(), m_store->barWidth(), true, Palette::Select, Palette::YellowDark, m_highlightedBarStart, m_highlightedBarEnd); } else { - drawHistogram(ctx, rect, nullptr, m_store->firstDrawnBarAbscissa(), m_store->barWidth(), true, Palette::GreyMiddle, Palette::YellowDark); + drawHistogram(ctx, rect, EvaluateHistogramAtAbscissa, m_store, &totalSize, m_store->firstDrawnBarAbscissa(), m_store->barWidth(), true, Palette::GreyMiddle, Palette::YellowDark); } } @@ -56,8 +56,10 @@ char * HistogramView::label(Axis axis, int index) const { return (char *)m_labels[index]; } -float HistogramView::evaluateModelWithParameter(Model * curve, float t) const { - return m_store->heightOfBarAtValue(t)/m_totalSize; +float HistogramView::EvaluateHistogramAtAbscissa(float abscissa, void * model, void * context) { + Store * store = (Store *)model; + float * totalSize = (float *)context; + return store->heightOfBarAtValue(abscissa)/(*totalSize); } } diff --git a/apps/statistics/histogram_view.h b/apps/statistics/histogram_view.h index d0ae6b6d6..fc97095e3 100644 --- a/apps/statistics/histogram_view.h +++ b/apps/statistics/histogram_view.h @@ -16,14 +16,11 @@ public: void setHighlight(float start, float end); private: char * label(Axis axis, int index) const override; - float evaluateModelWithParameter(Model * curve, float t) const override; Store * m_store; char m_labels[k_maxNumberOfXLabels][Poincare::PrintFloat::bufferSizeForFloatsWithPrecision(Constant::ShortNumberOfSignificantDigits)]; + static float EvaluateHistogramAtAbscissa(float abscissa, void * model, void * context); float m_highlightedBarStart; float m_highlightedBarEnd; - /* We memoize the total size to avoid recomputing it in double precision at - * every call to evaluateModelWithParameter() */ - mutable float m_totalSize; }; }