mirror of
https://github.com/UpsilonNumworks/Upsilon.git
synced 2026-03-18 21:30:38 +01:00
[apps/graph] Evaluation methods renaming
This commit is contained in:
@@ -24,7 +24,7 @@ bool GraphControllerHelper::privateMoveCursorHorizontally(Shared::CurveViewCurso
|
||||
t += dir; //TODO LEA delt
|
||||
}
|
||||
|
||||
Coordinate2D<double> xy = function->xyEvaluationAtParameter(t, App::app()->localContext());
|
||||
Coordinate2D<double> xy = function->evaluateXYAtParameter(t, App::app()->localContext());
|
||||
cursor->moveTo(t, xy.x(), xy.y());
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -30,40 +30,39 @@ void GraphView::drawRect(KDContext * ctx, KDRect rect) const {
|
||||
ExpiringPointer<CartesianFunction> f = m_functionStore->modelForRecord(record);;
|
||||
|
||||
switch (f->plotType()) {
|
||||
|
||||
case Shared::CartesianFunction::PlotType::Cartesian:
|
||||
drawCartesianCurve(ctx, rect, [](float t, void * model, void * context) {
|
||||
CartesianFunction * f = (CartesianFunction *)model;
|
||||
Poincare::Context * c = (Poincare::Context *)context;
|
||||
return f->evaluateAtParameter(t, c).y();
|
||||
return f->evaluateXYAtParameter(t, c);
|
||||
}, f.operator->(), context(), f->color(), record == m_selectedRecord, m_highlightedStart, m_highlightedEnd);
|
||||
/* Draw tangent */
|
||||
if (m_tangent && record == m_selectedRecord) {
|
||||
float tangentParameter[2];
|
||||
tangentParameter[0] = f->approximateDerivative(m_curveViewCursor->x(), context());
|
||||
tangentParameter[1] = -tangentParameter[0]*m_curveViewCursor->x()+f->evaluateAtParameter(m_curveViewCursor->x(), context()).y();
|
||||
tangentParameter[1] = -tangentParameter[0]*m_curveViewCursor->x()+f->evaluateXYAtParameter(m_curveViewCursor->x(), context()).x2();
|
||||
drawCartesianCurve(ctx, rect, [](float t, void * model, void * context) {
|
||||
float * tangent = (float *)model;
|
||||
return tangent[0]*t+tangent[1];
|
||||
return Poincare::Coordinate2D<float>(t, tangent[0]*t+tangent[1]);
|
||||
}, tangentParameter, nullptr, Palette::GreyVeryDark);
|
||||
}
|
||||
break;
|
||||
|
||||
case Shared::CartesianFunction::PlotType::Polar:
|
||||
drawCurve(ctx, rect, 0.0f, 396.0f, 36.0f, [](float t, void * model, void * context) { //TODO LEA RUBEN use the models's tMin, tMax
|
||||
CartesianFunction * f = (CartesianFunction *)model;
|
||||
Poincare::Context * c = (Poincare::Context *)context;
|
||||
return f->evaluateAtParameter(t, c).y() * std::cos(t);
|
||||
}, [](float t, void * model, void * context) {
|
||||
CartesianFunction * f = (CartesianFunction *)model;
|
||||
Poincare::Context * c = (Poincare::Context *)context;
|
||||
return f->evaluateAtParameter(t, c).y() * std::sin(t);
|
||||
return f->evaluateXYAtParameter(t, c);
|
||||
}, f.operator->(), context(), false, f->color());
|
||||
break;
|
||||
|
||||
case Shared::CartesianFunction::PlotType::Parametric:
|
||||
drawCurve(ctx, rect, 0.0f, 396.0f, 36.0f, [](float t, void * model, void * context) { //TODO LEA RUBEN use the models's tMin, tMax
|
||||
CartesianFunction * f = (CartesianFunction *)model;
|
||||
Poincare::Context * c = (Poincare::Context *)context;
|
||||
if (f->isCircularlyDefined(c)) {
|
||||
return NAN;
|
||||
return Poincare::Coordinate2D<float>(NAN, NAN);
|
||||
}
|
||||
constexpr int bufferSize = CodePoint::MaxCodePointCharLength + 1;
|
||||
char unknownX[bufferSize];
|
||||
@@ -71,36 +70,15 @@ void GraphView::drawRect(KDContext * ctx, KDRect rect) const {
|
||||
Poincare::VariableContext variableContext(unknownX, c);
|
||||
variableContext.setApproximationForVariable(t);
|
||||
Poincare::Expression e = f->expressionReduced(c);
|
||||
assert(
|
||||
e.type() == Poincare::ExpressionNode::Type::Matrix &&
|
||||
static_cast<Poincare::Matrix&>(e).numberOfRows() == 2 &&
|
||||
static_cast<Poincare::Matrix&>(e).numberOfColumns() == 1
|
||||
);
|
||||
assert(e.type() == Poincare::ExpressionNode::Type::Matrix
|
||||
&& static_cast<Poincare::Matrix&>(e).numberOfRows() == 2
|
||||
&& static_cast<Poincare::Matrix&>(e).numberOfColumns() == 1);
|
||||
Poincare::Preferences * preferences = Poincare::Preferences::sharedPreferences();
|
||||
Poincare::Preferences::ComplexFormat complexFormat = Poincare::Expression::UpdatedComplexFormatWithExpressionInput(preferences->complexFormat(), e, c);
|
||||
return e.childAtIndex(0).approximateToScalar<float>(&variableContext, complexFormat, preferences->angleUnit());
|
||||
}, [](float t, void * model, void * context) {
|
||||
CartesianFunction * f = (CartesianFunction *)model;
|
||||
Poincare::Context * c = (Poincare::Context *)context;
|
||||
if (f->isCircularlyDefined(c)) {
|
||||
return NAN;
|
||||
}
|
||||
constexpr int bufferSize = CodePoint::MaxCodePointCharLength + 1;
|
||||
char unknownX[bufferSize];
|
||||
Poincare::SerializationHelper::CodePoint(unknownX, bufferSize, UCodePointUnknownX);
|
||||
Poincare::VariableContext variableContext(unknownX, c);
|
||||
variableContext.setApproximationForVariable(t);
|
||||
Poincare::Expression e = f->expressionReduced(c);
|
||||
assert(
|
||||
e.type() == Poincare::ExpressionNode::Type::Matrix &&
|
||||
static_cast<Poincare::Matrix&>(e).numberOfRows() == 2 &&
|
||||
static_cast<Poincare::Matrix&>(e).numberOfColumns() == 1
|
||||
);
|
||||
Poincare::Preferences * preferences = Poincare::Preferences::sharedPreferences();
|
||||
Poincare::Preferences::ComplexFormat complexFormat = Poincare::Expression::UpdatedComplexFormatWithExpressionInput(preferences->complexFormat(), e, c);
|
||||
return e.childAtIndex(1).approximateToScalar<float>(&variableContext, complexFormat, preferences->angleUnit());
|
||||
return Poincare::Coordinate2D<float>(e.childAtIndex(0).approximateToScalar<float>(&variableContext, complexFormat, preferences->angleUnit()), e.childAtIndex(1).approximateToScalar<float>(&variableContext, complexFormat, preferences->angleUnit()));
|
||||
}, f.operator->(), context(), false, f->color());
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ bool TangentGraphController::textFieldDidFinishEditing(TextField * textField, co
|
||||
}
|
||||
ExpiringPointer<CartesianFunction> function = App::app()->functionStore()->modelForRecord(m_record);
|
||||
assert(function->plotType() == Shared::CartesianFunction::PlotType::Cartesian);
|
||||
double y = function->evaluateAtParameter(floatBody, myApp->localContext()).y();
|
||||
double y = function->evaluate2DAtParameter(floatBody, myApp->localContext()).x2();
|
||||
m_cursor->moveTo(floatBody, floatBody, y);
|
||||
interactiveCurveViewRange()->panToMakePointVisible(m_cursor->x(), m_cursor->y(), cursorTopMarginRatio(), k_cursorRightMarginRatio, cursorBottomMarginRatio(), k_cursorLeftMarginRatio);
|
||||
reloadBannerView();
|
||||
@@ -82,7 +82,7 @@ void TangentGraphController::reloadBannerView() {
|
||||
legendLength = strlcpy(buffer, legend, bufferSize);
|
||||
Shared::TextFieldDelegateApp * myApp = textFieldDelegateApp();
|
||||
assert(function->plotType() == Shared::CartesianFunction::PlotType::Cartesian);
|
||||
y = -y*m_cursor->x()+function->evaluateAtParameter(m_cursor->x(), myApp->localContext()).y();
|
||||
y = -y*m_cursor->x()+function->evaluate2DAtParameter(m_cursor->x(), myApp->localContext()).x2();
|
||||
PoincareHelpers::ConvertFloatToText<double>(y, buffer + legendLength, PrintFloat::bufferSizeForFloatsWithPrecision(precision), precision);
|
||||
m_bannerView->bView()->setText(buffer);
|
||||
m_bannerView->reload();
|
||||
|
||||
@@ -152,7 +152,7 @@ double ValuesController::evaluationOfAbscissaAtColumn(double abscissa, int colum
|
||||
return function->approximateDerivative(abscissa, context);
|
||||
}
|
||||
//TODO LEA RUBEN
|
||||
return function->evaluateAtParameter(abscissa, context).x();
|
||||
return function->evaluate2DAtParameter(abscissa, context).x1();
|
||||
}
|
||||
|
||||
void ValuesController::updateNumberOfColumns() {
|
||||
|
||||
@@ -126,8 +126,8 @@ double Distribution::cumulativeDistributiveInverseForProbabilityUsingIncreasingF
|
||||
this,
|
||||
probability,
|
||||
nullptr);
|
||||
assert(std::isnan(result.y()) || std::fabs(result.y()) < FLT_EPSILON);
|
||||
return result.x();
|
||||
assert(std::isnan(result.x2()) || std::fabs(result.x2()) < FLT_EPSILON);
|
||||
return result.x1();
|
||||
}
|
||||
|
||||
float Distribution::yMin() const {
|
||||
|
||||
@@ -25,7 +25,7 @@ void DistributionCurveView::drawRect(KDContext * ctx, KDRect rect) const {
|
||||
return;
|
||||
}
|
||||
if (m_distribution->isContinuous()) {
|
||||
drawCartesianCurve(ctx, rect, EvaluateAtAbscissa, m_distribution, nullptr, Palette::YellowDark, true, lowerBound, upperBound);
|
||||
drawCartesianCurve(ctx, rect, EvaluateXYAtAbscissa, m_distribution, nullptr, Palette::YellowDark, true, lowerBound, upperBound);
|
||||
} else {
|
||||
drawHistogram(ctx, rect, EvaluateAtAbscissa, m_distribution, nullptr, 0, 1, false, Palette::GreyMiddle, Palette::YellowDark, lowerBound, upperBound+0.5f);
|
||||
}
|
||||
@@ -43,6 +43,10 @@ float DistributionCurveView::EvaluateAtAbscissa(float abscissa, void * model, vo
|
||||
return distribution->evaluateAtAbscissa(abscissa);
|
||||
}
|
||||
|
||||
Poincare::Coordinate2D<float> DistributionCurveView::EvaluateXYAtAbscissa(float abscissa, void * model, void * context) {
|
||||
return Poincare::Coordinate2D<float>(abscissa, EvaluateAtAbscissa(abscissa, model, context));
|
||||
}
|
||||
|
||||
void DistributionCurveView::drawStandardNormal(KDContext * ctx, KDRect rect, float colorLowerBound, float colorUpperBound) const {
|
||||
// Save the previous curve view range
|
||||
DistributionCurveView * constCastedThis = const_cast<DistributionCurveView *>(this);
|
||||
@@ -51,7 +55,7 @@ void DistributionCurveView::drawStandardNormal(KDContext * ctx, KDRect rect, flo
|
||||
// Draw a centered reduced normal curve
|
||||
NormalDistribution n;
|
||||
constCastedThis->setCurveViewRange(&n);
|
||||
drawCartesianCurve(ctx, rect, EvaluateAtAbscissa, &n, nullptr, Palette::YellowDark, true, colorLowerBound, colorUpperBound);
|
||||
drawCartesianCurve(ctx, rect, EvaluateXYAtAbscissa, &n, nullptr, Palette::YellowDark, true, colorLowerBound, colorUpperBound);
|
||||
|
||||
// Put back the previous curve view range
|
||||
constCastedThis->setCurveViewRange(previousRange);
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "calculation/calculation.h"
|
||||
#include <escher.h>
|
||||
#include <poincare/print_float.h>
|
||||
#include <poincare/coordinate_2D.h>
|
||||
|
||||
namespace Probability {
|
||||
|
||||
@@ -28,6 +29,7 @@ protected:
|
||||
char * label(Axis axis, int index) const override;
|
||||
private:
|
||||
static float EvaluateAtAbscissa(float abscissa, void * model, void * context);
|
||||
static Poincare::Coordinate2D<float> EvaluateXYAtAbscissa(float abscissa, void * model, void * context);
|
||||
static constexpr KDColor k_backgroundColor = Palette::WallScreen;
|
||||
void drawStandardNormal(KDContext * ctx, KDRect rect, float colorLowerBound, float colorUpperBound) const;
|
||||
char m_labels[k_maxNumberOfXLabels][k_labelBufferMaxSize];
|
||||
|
||||
@@ -29,7 +29,7 @@ void GraphView::drawRect(KDContext * ctx, KDRect rect) const {
|
||||
drawCartesianCurve(ctx, rect, [](float abscissa, void * model, void * context) {
|
||||
Model * regressionModel = static_cast<Model *>(model);
|
||||
double * regressionCoefficients = static_cast<double *>(context);
|
||||
return (float)regressionModel->evaluate(regressionCoefficients, abscissa);
|
||||
return Poincare::Coordinate2D<float>(abscissa, (float)regressionModel->evaluate(regressionCoefficients, abscissa));
|
||||
},
|
||||
seriesModel, m_store->coefficientsForSeries(series, globContext), color);
|
||||
for (int index = 0; index < m_store->numberOfPairsOfSeries(series); index++) {
|
||||
|
||||
@@ -27,7 +27,7 @@ double Model::levelSet(double * modelCoefficients, double xMin, double step, dou
|
||||
Expression yExpression = Number::DecimalNumber(y);
|
||||
PoincareHelpers::Simplify(&yExpression, context);
|
||||
Expression modelExpression = simplifiedExpression(modelCoefficients, context);
|
||||
double result = PoincareHelpers::NextIntersection(modelExpression, "x", xMin, step, xMax, context, yExpression).x();
|
||||
double result = PoincareHelpers::NextIntersection(modelExpression, "x", xMin, step, xMax, context, yExpression).x1();
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -67,7 +67,7 @@ bool GraphController::textFieldDidFinishEditing(TextField * textField, const cha
|
||||
return false;
|
||||
}
|
||||
floatBody = std::fmax(0, std::round(floatBody));
|
||||
double y = xyValues(selectedCurveIndex(), floatBody, myApp->localContext()).y();
|
||||
double y = xyValues(selectedCurveIndex(), floatBody, myApp->localContext()).x2();
|
||||
m_cursor->moveTo(floatBody, floatBody, y);
|
||||
interactiveCurveViewRange()->panToMakePointVisible(m_cursor->x(), m_cursor->y(), cursorTopMarginRatio(), k_cursorRightMarginRatio, cursorBottomMarginRatio(), k_cursorLeftMarginRatio);
|
||||
reloadBannerView();
|
||||
@@ -94,7 +94,7 @@ bool GraphController::moveCursorHorizontally(int direction) {
|
||||
return false;
|
||||
}
|
||||
Sequence * s = functionStore()->modelForRecord(functionStore()->activeRecordAtIndex(indexFunctionSelectedByCursor()));
|
||||
double y = s->evaluateAtParameter(x, textFieldDelegateApp()->localContext()).y();
|
||||
double y = s->evaluateXYAtParameter(x, textFieldDelegateApp()->localContext()).x2();
|
||||
m_cursor->moveTo(x, x, y);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ void GraphView::drawRect(KDContext * ctx, KDRect rect) const {
|
||||
rectXMin = rectXMin < 0 ? 0 : rectXMin;
|
||||
float rectXMax = pixelToFloat(Axis::Horizontal, rect.right() + k_externRectMargin);
|
||||
for (int x = rectXMin; x < rectXMax; x += step) {
|
||||
float y = s->evaluateAtParameter((float)x, context()).y();
|
||||
float y = s->evaluateXYAtParameter((float)x, context()).x2();
|
||||
if (std::isnan(y)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -57,10 +57,10 @@ public:
|
||||
bool isDefined() override;
|
||||
bool isEmpty() override;
|
||||
// Approximation
|
||||
Poincare::Coordinate2D<float> evaluateAtParameter(float x, Poincare::Context * context) const override {
|
||||
Poincare::Coordinate2D<float> evaluateXYAtParameter(float x, Poincare::Context * context) const override {
|
||||
return Poincare::Coordinate2D<float>(x, templatedApproximateAtAbscissa(x, static_cast<SequenceContext *>(context)));
|
||||
}
|
||||
Poincare::Coordinate2D<double> evaluateAtParameter(double x, Poincare::Context * context) const override {
|
||||
Poincare::Coordinate2D<double> evaluateXYAtParameter(double x, Poincare::Context * context) const override {
|
||||
return Poincare::Coordinate2D<double>(x,templatedApproximateAtAbscissa(x, static_cast<SequenceContext *>(context)));
|
||||
}
|
||||
template<typename T> T approximateToNextRank(int n, SequenceContext * sqctx) const;
|
||||
|
||||
@@ -112,8 +112,8 @@ void CartesianFunction::setPlotType(PlotType plotType) {
|
||||
return recordData()->setPlotType(plotType);
|
||||
}
|
||||
|
||||
Coordinate2D<double> CartesianFunction::xyEvaluationAtParameter(double t, Poincare::Context * context) const {
|
||||
Coordinate2D<double> x1x2 = evaluateAtParameter(t, context);
|
||||
Coordinate2D<double> CartesianFunction::evaluateXYAtParameter(double t, Poincare::Context * context) const {
|
||||
Coordinate2D<double> x1x2 = evaluate2DAtParameter(t, context);
|
||||
PlotType type = plotType();
|
||||
if (type == PlotType::Cartesian || type == PlotType::Parametric) {
|
||||
return x1x2;
|
||||
|
||||
@@ -26,11 +26,11 @@ public:
|
||||
void setPlotType(PlotType plotType);
|
||||
|
||||
// Evaluation
|
||||
Poincare::Coordinate2D<double> xyEvaluationAtParameter(double t, Poincare::Context * context) const;
|
||||
Poincare::Coordinate2D<float> evaluateAtParameter(float t, Poincare::Context * context) const override {
|
||||
Poincare::Coordinate2D<double> evaluateXYAtParameter(double t, Poincare::Context * context) const;
|
||||
Poincare::Coordinate2D<float> evaluate2DAtParameter(float t, Poincare::Context * context) const override {
|
||||
return templatedApproximateAtParameter(t, context);
|
||||
}
|
||||
Poincare::Coordinate2D<double> evaluateAtParameter(double t, Poincare::Context * context) const override {
|
||||
Poincare::Coordinate2D<double> evaluate2DAtParameter(double t, Poincare::Context * context) const override {
|
||||
return templatedApproximateAtParameter(t, context);
|
||||
}
|
||||
// Derivative
|
||||
|
||||
@@ -502,7 +502,7 @@ const uint8_t stampMask[stampSize+1][stampSize+1] = {
|
||||
|
||||
constexpr static int k_maxNumberOfIterations = 10;
|
||||
|
||||
void CurveView::drawCurve(KDContext * ctx, KDRect rect, float tStart, float tEnd, float tStep, EvaluateModelWithParameter xEvaluation, EvaluateModelWithParameter yEvaluation, void * model, void * context, bool drawStraightLinesEarly, KDColor color, bool colorUnderCurve, float colorLowerBound, float colorUpperBound) const {
|
||||
void CurveView::drawCurve(KDContext * ctx, KDRect rect, float tStart, float tEnd, float tStep, EvaluateXYForParameter xyEvaluation, void * model, void * context, bool drawStraightLinesEarly, KDColor color, bool colorUnderCurve, float colorLowerBound, float colorUpperBound) const {
|
||||
float previousX = NAN;
|
||||
float x = NAN;
|
||||
float previousY = NAN;
|
||||
@@ -514,29 +514,28 @@ void CurveView::drawCurve(KDContext * ctx, KDRect rect, float tStart, float tEnd
|
||||
return;
|
||||
}
|
||||
previousX = x;
|
||||
x = xEvaluation(t, model, context);
|
||||
previousY = y;
|
||||
y = yEvaluation(t, model, context);
|
||||
Coordinate2D<float> xy = xyEvaluation(t, model, context);
|
||||
x = xy.x1();
|
||||
y = xy.x2();
|
||||
if (std::isnan(x) || std::isinf(x) || std::isnan(y) || std::isinf(y)) {
|
||||
continue;
|
||||
}
|
||||
if (colorUnderCurve && colorLowerBound < x && x < colorUpperBound) {
|
||||
drawSegment(ctx, rect, Axis::Vertical, x, minFloat(0.0f, y), maxFloat(0.0f, y), color, 1);
|
||||
}
|
||||
jointDots(ctx, rect, xEvaluation, yEvaluation, model, context, drawStraightLinesEarly, t - tStep, previousX, previousY, t, x, y, color, k_maxNumberOfIterations);
|
||||
jointDots(ctx, rect, xyEvaluation, model, context, drawStraightLinesEarly, t - tStep, previousX, previousY, t, x, y, color, k_maxNumberOfIterations);
|
||||
}
|
||||
}
|
||||
|
||||
void CurveView::drawCartesianCurve(KDContext * ctx, KDRect rect, EvaluateModelWithParameter yEvaluation, void * model, void * context, KDColor color, bool colorUnderCurve, float colorLowerBound, float colorUpperBound) const {
|
||||
void CurveView::drawCartesianCurve(KDContext * ctx, KDRect rect, EvaluateXYForParameter xyEvaluation, void * model, void * context, KDColor color, bool colorUnderCurve, float colorLowerBound, float colorUpperBound) const {
|
||||
float tStart = pixelToFloat(Axis::Horizontal, rect.left() - k_externRectMargin);
|
||||
float tEnd = pixelToFloat(Axis::Horizontal, rect.right() + k_externRectMargin);
|
||||
float tStep = pixelWidth();
|
||||
drawCurve(ctx, rect, tStart, tEnd, tStep, [](float t, void * model, void * context) {
|
||||
return t;
|
||||
}, yEvaluation, model, context, true, color, colorUnderCurve, colorLowerBound, colorUpperBound);
|
||||
drawCurve(ctx, rect, tStart, tEnd, tStep, xyEvaluation, model, context, true, color, colorUnderCurve, colorLowerBound, colorUpperBound);
|
||||
}
|
||||
|
||||
void CurveView::drawHistogram(KDContext * ctx, KDRect rect, EvaluateModelWithParameter evaluation, void * model, void * context, float firstBarAbscissa, float barWidth,
|
||||
void CurveView::drawHistogram(KDContext * ctx, KDRect rect, EvaluateYForX yEvaluation, 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);
|
||||
@@ -554,7 +553,7 @@ void CurveView::drawHistogram(KDContext * ctx, KDRect rect, EvaluateModelWithPar
|
||||
return;
|
||||
}
|
||||
float centerX = fillBar ? x+barWidth/2.0f : x;
|
||||
float y = evaluation(centerX, model, context);
|
||||
float y = yEvaluation(centerX, model, context);
|
||||
if (std::isnan(y)) {
|
||||
continue;
|
||||
}
|
||||
@@ -574,7 +573,7 @@ void CurveView::drawHistogram(KDContext * ctx, KDRect rect, EvaluateModelWithPar
|
||||
}
|
||||
}
|
||||
|
||||
void CurveView::jointDots(KDContext * ctx, KDRect rect, EvaluateModelWithParameter xEvaluation, EvaluateModelWithParameter yEvaluation, void * model, void * context, bool drawStraightLinesEarly, float t, float x, float y, float s, float u, float v, KDColor color, int maxNumberOfRecursion) const {
|
||||
void CurveView::jointDots(KDContext * ctx, KDRect rect, EvaluateXYForParameter xyEvaluation , void * model, void * context, bool drawStraightLinesEarly, float t, float x, float y, float s, float u, float v, KDColor color, int maxNumberOfRecursion) const {
|
||||
float pxf = floatToPixel(Axis::Horizontal, x);
|
||||
float pyf = floatToPixel(Axis::Vertical, y);
|
||||
float puf = floatToPixel(Axis::Horizontal, u);
|
||||
@@ -588,8 +587,9 @@ void CurveView::jointDots(KDContext * ctx, KDRect rect, EvaluateModelWithParamet
|
||||
}
|
||||
// Middle point
|
||||
float ct = (t + s)/2.0f;
|
||||
float cx = xEvaluation(ct, model, context);
|
||||
float cy = yEvaluation(ct, model, context);
|
||||
Coordinate2D<float> cxy = xyEvaluation(ct, model, context);
|
||||
float cx = cxy.x1();
|
||||
float cy = cxy.x2();
|
||||
if ((drawStraightLinesEarly || maxNumberOfRecursion == 0) && ((x <= cx && cx <= u) || (u <= cx && cx <= x)) && ((y <= cy && cy <= v) || (v <= cy && cy <= y))) {
|
||||
/* As the middle dot is between the two dots, we assume that we
|
||||
* can draw a 'straight' line between the two */
|
||||
@@ -597,8 +597,8 @@ void CurveView::jointDots(KDContext * ctx, KDRect rect, EvaluateModelWithParamet
|
||||
return;
|
||||
}
|
||||
if (maxNumberOfRecursion > 0) {
|
||||
jointDots(ctx, rect, xEvaluation, yEvaluation, model, context, drawStraightLinesEarly, t, x, y, ct, cx, cy, color, maxNumberOfRecursion-1);
|
||||
jointDots(ctx, rect, xEvaluation, yEvaluation, model, context, drawStraightLinesEarly, ct, cx, cy, s, u, v, color, maxNumberOfRecursion-1);
|
||||
jointDots(ctx, rect, xyEvaluation, model, context, drawStraightLinesEarly, t, x, y, ct, cx, cy, color, maxNumberOfRecursion-1);
|
||||
jointDots(ctx, rect, xyEvaluation, model, context, drawStraightLinesEarly, ct, cx, cy, s, u, v, color, maxNumberOfRecursion-1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "curve_view_range.h"
|
||||
#include "curve_view_cursor.h"
|
||||
#include <poincare/preferences.h>
|
||||
#include <poincare/coordinate_2D.h>
|
||||
#include <cmath>
|
||||
|
||||
namespace Shared {
|
||||
@@ -14,8 +15,8 @@ public:
|
||||
/* We want a 3 characters margin before the first label tick, so that most
|
||||
* labels appear completely. This gives 3*charWidth/320 = 3*7/320= 0.066 */
|
||||
static constexpr float k_labelsHorizontalMarginRatio = 0.066f;
|
||||
//TODO LEA RUBEN EvaluateModelWithParameter that returns Coordinate2D<float>
|
||||
typedef float (*EvaluateModelWithParameter)(float t, void * model, void * context);
|
||||
typedef Poincare::Coordinate2D<float> (*EvaluateXYForParameter)(float t, void * model, void * context);
|
||||
typedef float (*EvaluateYForX)(float x, void * model, void * context);
|
||||
enum class Axis {
|
||||
Horizontal = 0,
|
||||
Vertical = 1
|
||||
@@ -63,9 +64,9 @@ protected:
|
||||
void drawGrid(KDContext * ctx, KDRect rect) const;
|
||||
void drawAxes(KDContext * ctx, KDRect rect) const;
|
||||
void drawAxis(KDContext * ctx, KDRect rect, Axis axis) const;
|
||||
void drawCurve(KDContext * ctx, KDRect rect, float tStart, float tEnd, float tStep, EvaluateModelWithParameter xEvaluation, EvaluateModelWithParameter yEvaluation, void * model, void * context, bool drawStraightLinesEarly, KDColor color, bool colorUnderCurve = false, float colorLowerBound = 0.0f, float colorUpperBound = 0.0f) const;
|
||||
void drawCartesianCurve(KDContext * ctx, KDRect rect, EvaluateModelWithParameter yEvaluation, void * model, void * context, KDColor color, bool colorUnderCurve = false, float colorLowerBound = 0.0f, float colorUpperBound = 0.0f) const;
|
||||
void drawHistogram(KDContext * ctx, KDRect rect, EvaluateModelWithParameter evaluation, void * model, void * context, float firstBarAbscissa, float barWidth,
|
||||
void drawCurve(KDContext * ctx, KDRect rect, float tStart, float tEnd, float tStep, EvaluateXYForParameter xyEvaluation, void * model, void * context, bool drawStraightLinesEarly, KDColor color, bool colorUnderCurve = false, float colorLowerBound = 0.0f, float colorUpperBound = 0.0f) const;
|
||||
void drawCartesianCurve(KDContext * ctx, KDRect rect, EvaluateXYForParameter xyEvaluation, void * model, void * context, KDColor color, bool colorUnderCurve = false, float colorLowerBound = 0.0f, float colorUpperBound = 0.0f) const;
|
||||
void drawHistogram(KDContext * ctx, KDRect rect, EvaluateYForX yEvaluation, 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 simpleDrawBothAxesLabels(KDContext * ctx, KDRect rect) const;
|
||||
@@ -84,7 +85,7 @@ private:
|
||||
int numberOfLabels(Axis axis) const;
|
||||
/* Recursively join two dots (dichotomy). The method stops when the
|
||||
* maxNumberOfRecursion in reached. */
|
||||
void jointDots(KDContext * ctx, KDRect rect, EvaluateModelWithParameter xEvaluation, EvaluateModelWithParameter yEvaluation, void * model, void * context, bool drawStraightLinesEarly, float t, float x, float y, float s, float u, float v, KDColor color, int maxNumberOfRecursion) const;
|
||||
void jointDots(KDContext * ctx, KDRect rect, EvaluateXYForParameter xyEvaluation, void * model, void * context, bool drawStraightLinesEarly, float t, float x, float y, float s, 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
|
||||
|
||||
@@ -41,8 +41,8 @@ public:
|
||||
int nameWithArgument(char * buffer, size_t bufferSize);
|
||||
|
||||
// Evaluation
|
||||
virtual Poincare::Coordinate2D<float> evaluateAtParameter(float t, Poincare::Context * context) const = 0;
|
||||
virtual Poincare::Coordinate2D<double> evaluateAtParameter(double t, Poincare::Context * context) const = 0;
|
||||
virtual Poincare::Coordinate2D<float> evaluate2DAtParameter(float t, Poincare::Context * context) const = 0;
|
||||
virtual Poincare::Coordinate2D<double> evaluate2DAtParameter(double t, Poincare::Context * context) const = 0;
|
||||
protected:
|
||||
/* FunctionRecordDataBuffer is the layout of the data buffer of Record
|
||||
* representing a Function. We want to avoid padding which would:
|
||||
|
||||
@@ -24,7 +24,7 @@ bool FunctionGoToParameterController::setParameterAtIndex(int parameterIndex, do
|
||||
assert(parameterIndex == 0);
|
||||
FunctionApp * myApp = FunctionApp::app();
|
||||
ExpiringPointer<Function> function = myApp->functionStore()->modelForRecord(m_record);
|
||||
Poincare::Coordinate2D<double> xy = function->evaluateAtParameter(f, myApp->localContext());
|
||||
Poincare::Coordinate2D<double> xy = function->evaluate2DAtParameter(f, myApp->localContext());
|
||||
m_cursor->moveTo(f, xy.x(), xy.y());
|
||||
m_graphRange->centerAxisAround(CurveViewRange::Axis::X, m_cursor->x());
|
||||
m_graphRange->centerAxisAround(CurveViewRange::Axis::Y, m_cursor->y());
|
||||
|
||||
@@ -107,7 +107,7 @@ InteractiveCurveViewRangeDelegate::Range FunctionGraphController::computeYRange(
|
||||
const int balancedBound = std::floor((tMax-tMin)/2/step);
|
||||
for (int j = -balancedBound; j <= balancedBound ; j++) {
|
||||
float t = (tMin+tMax)/2 + step * j;
|
||||
Coordinate2D<float> xy = f->evaluateAtParameter(t, context);
|
||||
Coordinate2D<float> xy = f->evaluate2DAtParameter(t, context);
|
||||
float x = xy.x();
|
||||
if (!std::isnan(x) && !std::isinf(x) && x >= xMin && x <= xMax) {
|
||||
float y = xy.y();
|
||||
@@ -139,7 +139,7 @@ void FunctionGraphController::initCursorParameters() {
|
||||
Coordinate2D<double> xy;
|
||||
do {
|
||||
ExpiringPointer<Function> firstFunction = functionStore()->modelForRecord(functionStore()->activeRecordAtIndex(functionIndex++));
|
||||
xy = firstFunction->evaluateAtParameter(t, context);
|
||||
xy = firstFunction->evaluate2DAtParameter(t, context);
|
||||
} while ((std::isnan(xy.y()) || std::isinf(xy.y())) && functionIndex < functionStore()->numberOfActiveFunctions());
|
||||
m_cursor->moveTo(t, xy.x(), xy.y());
|
||||
functionIndex = (std::isnan(xy.y()) || std::isinf(xy.y())) ? 0 : functionIndex - 1;
|
||||
@@ -181,7 +181,7 @@ bool FunctionGraphController::closestCurveIndexIsSuitable(int newIndex, int curr
|
||||
}
|
||||
|
||||
Coordinate2D<double> FunctionGraphController::xyValues(int curveIndex, double t, Poincare::Context * context) const {
|
||||
return functionStore()->modelForRecord(functionStore()->activeRecordAtIndex(curveIndex))->evaluateAtParameter(t, context);
|
||||
return functionStore()->modelForRecord(functionStore()->activeRecordAtIndex(curveIndex))->evaluate2DAtParameter(t, context);
|
||||
}
|
||||
|
||||
int FunctionGraphController::numberOfCurves() const {
|
||||
|
||||
@@ -66,7 +66,7 @@ bool SumGraphController::moveCursorHorizontallyToPosition(double x) {
|
||||
assert(!m_record.isNull());
|
||||
ExpiringPointer<Function> function = myApp->functionStore()->modelForRecord(m_record);
|
||||
|
||||
Coordinate2D<double> xy = function->evaluateAtParameter(x, myApp->localContext()); //TODO LEA assertion that x = t?
|
||||
Coordinate2D<double> xy = function->evaluate2DAtParameter(x, myApp->localContext()); //TODO LEA assertion that x = t?
|
||||
double y = xy.y();
|
||||
m_cursor->moveTo(x, x, y);
|
||||
if (m_step == Step::SecondParameter) {
|
||||
|
||||
@@ -329,7 +329,7 @@ double ValuesController::evaluationOfAbscissaAtColumn(double abscissa, int colum
|
||||
ExpiringPointer<Function> function = functionStore()->modelForRecord(recordAtColumn(columnIndex));
|
||||
//TODO LEA RUBEN Careful with merge
|
||||
//TODO LEA RUBEN change with evaluationOfParameterAtColumn?
|
||||
Poincare::Coordinate2D<double> xy = function->evaluateAtParameter(abscissa, textFieldDelegateApp()->localContext());
|
||||
Poincare::Coordinate2D<double> xy = function->evaluate2DAtParameter(abscissa, textFieldDelegateApp()->localContext());
|
||||
return xy.y();
|
||||
}
|
||||
|
||||
|
||||
@@ -889,7 +889,7 @@ Coordinate2D<double> Expression::nextMaximum(const char * symbol, double start,
|
||||
const char * symbol = reinterpret_cast<const char *>(context2);
|
||||
return -expression0->approximateWithValueForSymbol(symbol, x, context, complexFormat, angleUnit);
|
||||
}, context, complexFormat, angleUnit);
|
||||
return Coordinate2D<double>(minimumOfOpposite.x(), -minimumOfOpposite.y());
|
||||
return Coordinate2D<double>(minimumOfOpposite.x1(), -minimumOfOpposite.x2());
|
||||
}
|
||||
|
||||
double Expression::nextRoot(const char * symbol, double start, double step, double max, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const {
|
||||
@@ -910,8 +910,8 @@ Coordinate2D<double> Expression::nextIntersection(const char * symbol, double st
|
||||
return expression0->approximateWithValueForSymbol(symbol, x, context, complexFormat, angleUnit)-expression1->approximateWithValueForSymbol(symbol, x, context, complexFormat, angleUnit);
|
||||
}, context, complexFormat, angleUnit, expression);
|
||||
Coordinate2D<double> result(resultAbscissa, approximateWithValueForSymbol(symbol, resultAbscissa, context, complexFormat, angleUnit));
|
||||
if (std::fabs(result.y()) < step*k_solverPrecision) {
|
||||
result.setY(0.0);
|
||||
if (std::fabs(result.x2()) < step*k_solverPrecision) {
|
||||
result.setX2(0.0);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -929,26 +929,26 @@ Coordinate2D<double> Expression::nextMinimumOfExpression(const char * symbol, do
|
||||
result = brentMinimum(symbol, bracket[0], bracket[2], evaluate, context, complexFormat, angleUnit, expression);
|
||||
x = bracket[1];
|
||||
// Because of float approximation, exact zero is never reached
|
||||
if (std::fabs(result.x()) < std::fabs(step)*k_solverPrecision) {
|
||||
result.setX(0);
|
||||
result.setY(evaluate(0, context, complexFormat, angleUnit, this, symbol, &expression));
|
||||
if (std::fabs(result.x1()) < std::fabs(step)*k_solverPrecision) {
|
||||
result.setX1(0);
|
||||
result.setX2(evaluate(0, context, complexFormat, angleUnit, this, symbol, &expression));
|
||||
}
|
||||
/* Ignore extremum whose value is undefined or too big because they are
|
||||
* really unlikely to be local extremum. */
|
||||
if (std::isnan(result.y()) || std::fabs(result.y()) > k_maxFloat) {
|
||||
result.setX(NAN);
|
||||
if (std::isnan(result.x2()) || std::fabs(result.x2()) > k_maxFloat) {
|
||||
result.setX1(NAN);
|
||||
}
|
||||
// Idem, exact 0 never reached
|
||||
if (std::fabs(result.y()) < std::fabs(step)*k_solverPrecision) {
|
||||
result.setY(0);
|
||||
if (std::fabs(result.x2()) < std::fabs(step)*k_solverPrecision) {
|
||||
result.setX2(0);
|
||||
}
|
||||
endCondition = std::isnan(result.x()) && (step > 0.0 ? x <= max : x >= max);
|
||||
endCondition = std::isnan(result.x1()) && (step > 0.0 ? x <= max : x >= max);
|
||||
if (lookForRootMinimum) {
|
||||
endCondition |= std::fabs(result.y()) > 0 && (step > 0.0 ? x <= max : x >= max);
|
||||
endCondition |= std::fabs(result.x2()) > 0 && (step > 0.0 ? x <= max : x >= max);
|
||||
}
|
||||
} while (endCondition);
|
||||
if (lookForRootMinimum && std::fabs(result.y()) > 0) {
|
||||
result.setX(NAN);
|
||||
if (lookForRootMinimum && std::fabs(result.x2()) > 0) {
|
||||
result.setX1(NAN);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -961,18 +961,18 @@ void Expression::bracketMinimum(const char * symbol, double start, double step,
|
||||
};
|
||||
double x = start+2.0*step;
|
||||
while (step > 0.0 ? x <= max : x >= max) {
|
||||
p[2].setX(x);
|
||||
p[2].setY(evaluate(x, context, complexFormat, angleUnit, this, symbol, &expression));
|
||||
if ((p[0].y() > p[1].y() || std::isnan(p[0].y()))
|
||||
&& (p[2].y() > p[1].y() || std::isnan(p[2].y()))
|
||||
&& (!std::isnan(p[0].y()) || !std::isnan(p[2].y())))
|
||||
p[2].setX1(x);
|
||||
p[2].setX2(evaluate(x, context, complexFormat, angleUnit, this, symbol, &expression));
|
||||
if ((p[0].x2() > p[1].x2() || std::isnan(p[0].x2()))
|
||||
&& (p[2].x2() > p[1].x2() || std::isnan(p[2].x2()))
|
||||
&& (!std::isnan(p[0].x2()) || !std::isnan(p[2].x2())))
|
||||
{
|
||||
result[0] = p[0].x();
|
||||
result[1] = p[1].x();
|
||||
result[2] = p[2].x();
|
||||
result[0] = p[0].x1();
|
||||
result[1] = p[1].x1();
|
||||
result[2] = p[2].x1();
|
||||
return;
|
||||
}
|
||||
if (p[0].y() > p[1].y() && p[1].y() == p[2].y()) {
|
||||
if (p[0].x2() > p[1].x2() && p[1].x2() == p[2].x2()) {
|
||||
} else {
|
||||
p[0] = p[1];
|
||||
p[1] = p[2];
|
||||
@@ -1028,8 +1028,8 @@ double Expression::nextIntersectionWithExpression(const char * symbol, double st
|
||||
return (expression1->isUninitialized() ? 0.0 : expression1->approximateWithValueForSymbol(symbol, x, context, complexFormat, angleUnit)) - expression0->approximateWithValueForSymbol(symbol, x, context, complexFormat, angleUnit);
|
||||
}, context, complexFormat, angleUnit, expression, true)};
|
||||
for (int i = 0; i < 2; i++) {
|
||||
if (!std::isnan(resultExtremum[i].x()) && (std::isnan(result) || std::fabs(result - start) > std::fabs(resultExtremum[i].x() - start))) {
|
||||
result = resultExtremum[i].x();
|
||||
if (!std::isnan(resultExtremum[i].x1()) && (std::isnan(result) || std::fabs(result - start) > std::fabs(resultExtremum[i].x1() - start))) {
|
||||
result = resultExtremum[i].x1();
|
||||
}
|
||||
}
|
||||
if (std::fabs(result) < std::fabs(step)*k_solverPrecision) {
|
||||
|
||||
Reference in New Issue
Block a user