mirror of
https://github.com/UpsilonNumworks/Upsilon.git
synced 2026-01-19 00:37:25 +01:00
[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:
committed by
EmilieNumworks
parent
ea28475432
commit
ef8f5e07c2
@@ -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());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user