[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)

This commit is contained in:
Émilie Feral
2018-01-08 11:43:55 +01:00
committed by EmilieNumworks
parent ea28475432
commit ef8f5e07c2
12 changed files with 45 additions and 67 deletions

View File

@@ -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());
}
}

View File

@@ -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;
};

View File

@@ -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);
}
}

View File

@@ -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;
};

View File

@@ -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;
}
}

View File

@@ -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;
};
}

View File

@@ -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);

View File

@@ -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;

View File

@@ -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);
}
}

View File

@@ -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

View File

@@ -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);
}
}

View File

@@ -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;
};
}