From 28a721e96e1f5cac4faa36f29ccd3b20798b7ec4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Wed, 28 Aug 2019 16:11:12 +0200 Subject: [PATCH] [apps] Start fixing apps as cursor has new member variable --- .../graph/calculation_graph_controller.cpp | 6 +- apps/graph/graph/graph_controller_helper.cpp | 19 +++++-- apps/graph/graph/graph_view.cpp | 12 ++-- apps/graph/graph/graph_view.h | 1 - apps/graph/graph/tangent_graph_controller.cpp | 9 ++- apps/graph/values/values_controller.cpp | 3 +- .../regression/go_to_parameter_controller.cpp | 6 +- apps/regression/graph_controller.cpp | 26 ++++++--- apps/regression/graph_controller.h | 3 +- apps/regression/store.h | 4 +- apps/sequence/graph/graph_controller.cpp | 12 ++-- apps/sequence/graph/graph_controller.h | 2 +- apps/sequence/graph/graph_view.cpp | 2 +- apps/sequence/sequence.h | 8 +-- apps/shared/cartesian_function.cpp | 35 +++++++++--- apps/shared/cartesian_function.h | 13 +++-- apps/shared/curve_view.h | 1 + apps/shared/function.h | 8 ++- .../function_go_to_parameter_controller.cpp | 6 +- apps/shared/function_graph_controller.cpp | 55 +++++++++++++------ apps/shared/function_graph_controller.h | 4 +- .../interactive_curve_view_controller.cpp | 7 ++- .../interactive_curve_view_controller.h | 3 +- apps/shared/sum_graph_controller.cpp | 6 +- apps/shared/values_controller.cpp | 5 +- poincare/include/poincare/coordinate_2D.h | 1 + 26 files changed, 172 insertions(+), 85 deletions(-) diff --git a/apps/graph/graph/calculation_graph_controller.cpp b/apps/graph/graph/calculation_graph_controller.cpp index 80622e8ab..d4a3c9811 100644 --- a/apps/graph/graph/calculation_graph_controller.cpp +++ b/apps/graph/graph/calculation_graph_controller.cpp @@ -26,7 +26,8 @@ void CalculationGraphController::viewWillAppear() { m_graphView->setBannerView(&m_defaultBannerView); } else { m_isActive = true; - m_cursor->moveTo(pointOfInterest.x(), pointOfInterest.y()); + assert(App::app()->functionStore()->modelForRecord(m_record)->plotType() == Shared::CartesianFunction::PlotType::Cartesian); + m_cursor->moveTo(pointOfInterest.x(), pointOfInterest.x(), pointOfInterest.y()); m_graphRange->panToMakePointVisible(m_cursor->x(), m_cursor->y(), cursorTopMarginRatio(), k_cursorRightMarginRatio, cursorBottomMarginRatio(), k_cursorLeftMarginRatio); m_bannerView->setNumberOfSubviews(Shared::XYBannerView::k_numberOfSubviews); reloadBannerView(); @@ -73,7 +74,8 @@ bool CalculationGraphController::moveCursorHorizontally(int direction) { if (std::isnan(newPointOfInterest.x())) { return false; } - m_cursor->moveTo(newPointOfInterest.x(), newPointOfInterest.y()); + assert(App::app()->functionStore()->modelForRecord(m_record)->plotType() == Shared::CartesianFunction::PlotType::Cartesian); + m_cursor->moveTo(newPointOfInterest.x(), newPointOfInterest.x(), newPointOfInterest.y()); return true; } diff --git a/apps/graph/graph/graph_controller_helper.cpp b/apps/graph/graph/graph_controller_helper.cpp index e0ffeb964..59364ce9e 100644 --- a/apps/graph/graph/graph_controller_helper.cpp +++ b/apps/graph/graph/graph_controller_helper.cpp @@ -11,10 +11,21 @@ namespace Graph { bool GraphControllerHelper::privateMoveCursorHorizontally(Shared::CurveViewCursor * cursor, int direction, Shared::InteractiveCurveViewRange * range, int numberOfStepsInGradUnit, Ion::Storage::Record record) { ExpiringPointer function = App::app()->functionStore()->modelForRecord(record); - double xCursorPosition = cursor->x(); - double x = xCursorPosition + (direction > 0 ? 1.0 : -1.0) * range->xGridUnit()/numberOfStepsInGradUnit; - double y = function->evaluateAtAbscissa(x, App::app()->localContext()); - cursor->moveTo(x, y); + double tCursorPosition = cursor->t(); + double t = tCursorPosition; + double dir = (direction > 0 ? 1.0 : -1.0); + CartesianFunction::PlotType type = function->plotType(); + if (type == CartesianFunction::PlotType::Cartesian) { + t+= dir * range->xGridUnit()/numberOfStepsInGradUnit; + } else if (type == CartesianFunction::PlotType::Polar) { + t += dir; //TODO LEA delt + } else { + assert(type == CartesianFunction::PlotType::Parametric); + t += dir; //TODO LEA delt + } + + Coordinate2D xy = function->xyEvaluationAtParameter(t, App::app()->localContext()); + cursor->moveTo(t, xy.x(), xy.y()); return true; } diff --git a/apps/graph/graph/graph_view.cpp b/apps/graph/graph/graph_view.cpp index c5d04aaf3..e674ce092 100644 --- a/apps/graph/graph/graph_view.cpp +++ b/apps/graph/graph/graph_view.cpp @@ -34,13 +34,13 @@ void GraphView::drawRect(KDContext * ctx, KDRect rect) const { drawCartesianCurve(ctx, rect, [](float t, void * model, void * context) { CartesianFunction * f = (CartesianFunction *)model; Poincare::Context * c = (Poincare::Context *)context; - return f->evaluateAtAbscissa(t, c); + return f->evaluateAtParameter(t, c).y(); }, 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->evaluateAtAbscissa(m_curveViewCursor->x(), context()); + tangentParameter[1] = -tangentParameter[0]*m_curveViewCursor->x()+f->evaluateAtParameter(m_curveViewCursor->x(), context()).y(); drawCartesianCurve(ctx, rect, [](float t, void * model, void * context) { float * tangent = (float *)model; return tangent[0]*t+tangent[1]; @@ -48,18 +48,18 @@ void GraphView::drawRect(KDContext * ctx, KDRect rect) const { } break; case Shared::CartesianFunction::PlotType::Polar: - drawCurve(ctx, rect, 0.0f, 396.0f, 36.0f, [](float t, void * model, void * context) { + 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->evaluateAtAbscissa(t, c) * std::cos(t); + 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->evaluateAtAbscissa(t, c) * std::sin(t); + return f->evaluateAtParameter(t, c).y() * std::sin(t); }, 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) { + 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)) { diff --git a/apps/graph/graph/graph_view.h b/apps/graph/graph/graph_view.h index 294bb2b3f..54039b31d 100644 --- a/apps/graph/graph/graph_view.h +++ b/apps/graph/graph/graph_view.h @@ -8,7 +8,6 @@ namespace Graph { class GraphView : public Shared::FunctionGraphView { public: - GraphView(CartesianFunctionStore * functionStore, Shared::InteractiveCurveViewRange * graphRange, Shared::CurveViewCursor * cursor, Shared::BannerView * bannerView, View * cursorView); void reload() override; diff --git a/apps/graph/graph/tangent_graph_controller.cpp b/apps/graph/graph/tangent_graph_controller.cpp index 51dcbf403..f3f5fa8b2 100644 --- a/apps/graph/graph/tangent_graph_controller.cpp +++ b/apps/graph/graph/tangent_graph_controller.cpp @@ -46,8 +46,9 @@ bool TangentGraphController::textFieldDidFinishEditing(TextField * textField, co return false; } ExpiringPointer function = App::app()->functionStore()->modelForRecord(m_record); - double y = function->evaluateAtAbscissa(floatBody, myApp->localContext()); - m_cursor->moveTo(floatBody, y); + assert(function->plotType() == Shared::CartesianFunction::PlotType::Cartesian); + double y = function->evaluateAtParameter(floatBody, myApp->localContext()).y(); + m_cursor->moveTo(floatBody, floatBody, y); interactiveCurveViewRange()->panToMakePointVisible(m_cursor->x(), m_cursor->y(), cursorTopMarginRatio(), k_cursorRightMarginRatio, cursorBottomMarginRatio(), k_cursorLeftMarginRatio); reloadBannerView(); curveView()->reload(); @@ -79,7 +80,9 @@ void TangentGraphController::reloadBannerView() { legend = "b="; legendLength = strlcpy(buffer, legend, bufferSize); - y = -y*m_cursor->x()+function->evaluateAtAbscissa(m_cursor->x(), context); + Shared::TextFieldDelegateApp * myApp = textFieldDelegateApp(); + assert(function->plotType() == Shared::CartesianFunction::PlotType::Cartesian); + y = -y*m_cursor->x()+function->evaluateAtParameter(m_cursor->x(), myApp->localContext()).y(); PoincareHelpers::ConvertFloatToText(y, buffer + legendLength, PrintFloat::bufferSizeForFloatsWithPrecision(precision), precision); m_bannerView->bView()->setText(buffer); m_bannerView->reload(); diff --git a/apps/graph/values/values_controller.cpp b/apps/graph/values/values_controller.cpp index e191d8441..c9dc19dc0 100644 --- a/apps/graph/values/values_controller.cpp +++ b/apps/graph/values/values_controller.cpp @@ -151,7 +151,8 @@ double ValuesController::evaluationOfAbscissaAtColumn(double abscissa, int colum if (isDerivative) { return function->approximateDerivative(abscissa, context); } - return function->evaluateAtAbscissa(abscissa, context); + //TODO LEA RUBEN + return function->evaluateAtParameter(abscissa, context).x(); } void ValuesController::updateNumberOfColumns() { diff --git a/apps/regression/go_to_parameter_controller.cpp b/apps/regression/go_to_parameter_controller.cpp index 4d6c1c602..56ddfbe4b 100644 --- a/apps/regression/go_to_parameter_controller.cpp +++ b/apps/regression/go_to_parameter_controller.cpp @@ -52,7 +52,7 @@ bool GoToParameterController::setParameterAtIndex(int parameterIndex, double f) if (std::fabs(unknown - f) < DBL_EPSILON) { // If the computed value is NaN and the current abscissa is solution m_graphController->selectRegressionCurve(); - m_cursor->moveTo(x, unknown); + m_cursor->moveTo(x, x, unknown); return true; } } @@ -62,7 +62,7 @@ bool GoToParameterController::setParameterAtIndex(int parameterIndex, double f) } m_graphController->selectRegressionCurve(); if (m_xPrediction) { - m_cursor->moveTo(f, unknown); + m_cursor->moveTo(f, f, unknown); } else { double yFromX = m_store->modelForSeries(series)->evaluate(m_store->coefficientsForSeries(series, globContext), unknown); /* We here compute y2 = a*((y1-b)/a)+b, which does not always give y1, @@ -71,7 +71,7 @@ bool GoToParameterController::setParameterAtIndex(int parameterIndex, double f) Container::activeApp()->displayWarning(I18n::Message::ForbiddenValue); return false; } - m_cursor->moveTo(unknown, yFromX); + m_cursor->moveTo(unknown, unknown, yFromX); } m_graphRange->centerAxisAround(CurveViewRange::Axis::X, m_cursor->x()); m_graphRange->centerAxisAround(CurveViewRange::Axis::Y, m_cursor->y()); diff --git a/apps/regression/graph_controller.cpp b/apps/regression/graph_controller.cpp index bc26a5d8c..33aaf18a2 100644 --- a/apps/regression/graph_controller.cpp +++ b/apps/regression/graph_controller.cpp @@ -234,12 +234,16 @@ bool GraphController::moveCursorHorizontally(int direction) { int dotSelected = m_store->nextDot(*m_selectedSeriesIndex, direction, *m_selectedDotIndex); if (dotSelected >= 0 && dotSelected < m_store->numberOfPairsOfSeries(*m_selectedSeriesIndex)) { *m_selectedDotIndex = dotSelected; - m_cursor->moveTo(m_store->get(*m_selectedSeriesIndex, 0, *m_selectedDotIndex), m_store->get(*m_selectedSeriesIndex, 1, *m_selectedDotIndex)); + double x = m_store->get(*m_selectedSeriesIndex, 0, *m_selectedDotIndex); + double y = m_store->get(*m_selectedSeriesIndex, 1, *m_selectedDotIndex); + m_cursor->moveTo(x, x, y); return true; } if (dotSelected == m_store->numberOfPairsOfSeries(*m_selectedSeriesIndex)) { *m_selectedDotIndex = dotSelected; - m_cursor->moveTo(m_store->meanOfColumn(*m_selectedSeriesIndex, 0), m_store->meanOfColumn(*m_selectedSeriesIndex, 1)); + double x = m_store->meanOfColumn(*m_selectedSeriesIndex, 0); + double y = m_store->meanOfColumn(*m_selectedSeriesIndex, 1); + m_cursor->moveTo(x, x, y); return true; } return false; @@ -247,7 +251,7 @@ bool GraphController::moveCursorHorizontally(int direction) { double x = direction > 0 ? m_cursor->x() + m_store->xGridUnit()/k_numberOfCursorStepsInGradUnit : m_cursor->x() - m_store->xGridUnit()/k_numberOfCursorStepsInGradUnit; double y = yValue(*m_selectedSeriesIndex, x, globalContext()); - m_cursor->moveTo(x, y); + m_cursor->moveTo(x, x, y); return true; } @@ -268,7 +272,7 @@ bool GraphController::handleEnter() { void GraphController::initCursorParameters() { double x = m_store->meanOfColumn(*m_selectedSeriesIndex, 0); double y = m_store->meanOfColumn(*m_selectedSeriesIndex, 1); - m_cursor->moveTo(x, y); + m_cursor->moveTo(x, x, y); if (m_store->yAuto()) { m_store->panToMakePointVisible(x, y, cursorTopMarginRatio(), k_cursorRightMarginRatio, cursorBottomMarginRatio(), k_cursorLeftMarginRatio); } @@ -324,7 +328,7 @@ bool GraphController::moveCursorVertically(int direction) { // Select the regression *m_selectedSeriesIndex = closestRegressionSeries; selectRegressionCurve(); - m_cursor->moveTo(x, yValue(*m_selectedSeriesIndex, x, context)); + m_cursor->moveTo(x, x, yValue(*m_selectedSeriesIndex, x, context)); return true; } @@ -335,10 +339,14 @@ bool GraphController::moveCursorVertically(int direction) { *m_selectedDotIndex = dotSelected; if (dotSelected == m_store->numberOfPairsOfSeries(*m_selectedSeriesIndex)) { // Select the mean dot - m_cursor->moveTo(m_store->meanOfColumn(*m_selectedSeriesIndex, 0), m_store->meanOfColumn(*m_selectedSeriesIndex, 1)); + double x = m_store->meanOfColumn(*m_selectedSeriesIndex, 0); + double y = m_store->meanOfColumn(*m_selectedSeriesIndex, 1); + m_cursor->moveTo(x, x, y); } else { // Select a data point dot - m_cursor->moveTo(m_store->get(*m_selectedSeriesIndex, 0, *m_selectedDotIndex), m_store->get(*m_selectedSeriesIndex, 1, *m_selectedDotIndex)); + double x = m_store->get(*m_selectedSeriesIndex, 0, *m_selectedDotIndex); + double y = m_store->get(*m_selectedSeriesIndex, 1, *m_selectedDotIndex); + m_cursor->moveTo(x, x, y); } return true; } @@ -359,6 +367,10 @@ bool GraphController::closestCurveIndexIsSuitable(int newIndex, int currentIndex return newIndex != currentIndex && !m_store->seriesIsEmpty(newIndex); } +Coordinate2D GraphController::xyValues(int curveIndex, double x, Poincare::Context * context) const { + return Coordinate2D(x, yValue(curveIndex, x, context)); +} + double GraphController::yValue(int curveIndex, double x, Poincare::Context * context) const { return m_store->yValueForXValue(curveIndex, x, context); } diff --git a/apps/regression/graph_controller.h b/apps/regression/graph_controller.h index 48a162873..310648af1 100644 --- a/apps/regression/graph_controller.h +++ b/apps/regression/graph_controller.h @@ -46,7 +46,8 @@ private: uint32_t rangeVersion() override; int selectedCurveIndex() const override { return *m_selectedSeriesIndex; } bool closestCurveIndexIsSuitable(int newIndex, int currentIndex) const override; - double yValue(int curveIndex, double x, Poincare::Context * context) const override; + Poincare::Coordinate2D xyValues(int curveIndex, double x, Poincare::Context * context) const override; + double yValue(int curveIndex, double x, Poincare::Context * context) const; bool suitableYValue(double y) const override; int numberOfCurves() const override; int estimatedBannerNumberOfLines() const override; diff --git a/apps/regression/store.h b/apps/regression/store.h index a5acc58b6..da5a24252 100644 --- a/apps/regression/store.h +++ b/apps/regression/store.h @@ -70,8 +70,8 @@ public: double squaredCorrelationCoefficient(int series) const; private: constexpr static float k_displayHorizontalMarginRatio = 0.05f; - float maxValueOfColumn(int series, int i) const; - float minValueOfColumn(int series, int i) const; + float maxValueOfColumn(int series, int i) const; //TODO LEA why float ? + float minValueOfColumn(int series, int i) const; //TODO LEA why float ? Model * regressionModel(int index); uint32_t m_seriesChecksum[k_numberOfSeries]; Model::Type m_regressionTypes[k_numberOfSeries]; diff --git a/apps/sequence/graph/graph_controller.cpp b/apps/sequence/graph/graph_controller.cpp index 0056975bc..6f0a52d59 100644 --- a/apps/sequence/graph/graph_controller.cpp +++ b/apps/sequence/graph/graph_controller.cpp @@ -67,8 +67,8 @@ bool GraphController::textFieldDidFinishEditing(TextField * textField, const cha return false; } floatBody = std::fmax(0, std::round(floatBody)); - double y = yValue(selectedCurveIndex(), floatBody, myApp->localContext()); - m_cursor->moveTo(floatBody, y); + double y = xyValues(selectedCurveIndex(), floatBody, myApp->localContext()).y(); + m_cursor->moveTo(floatBody, floatBody, y); interactiveCurveViewRange()->panToMakePointVisible(m_cursor->x(), m_cursor->y(), cursorTopMarginRatio(), k_cursorRightMarginRatio, cursorBottomMarginRatio(), k_cursorLeftMarginRatio); reloadBannerView(); m_view.reload(); @@ -94,13 +94,13 @@ bool GraphController::moveCursorHorizontally(int direction) { return false; } Sequence * s = functionStore()->modelForRecord(functionStore()->activeRecordAtIndex(indexFunctionSelectedByCursor())); - double y = s->evaluateAtAbscissa(x, textFieldDelegateApp()->localContext()); - m_cursor->moveTo(x, y); + double y = s->evaluateAtParameter(x, textFieldDelegateApp()->localContext()).y(); + m_cursor->moveTo(x, x, y); return true; } -double GraphController::defaultCursorAbscissa() { - return std::fmax(0.0, std::round(Shared::FunctionGraphController::defaultCursorAbscissa())); +double GraphController::defaultCursorT() { + return std::fmax(0.0, std::round(Shared::FunctionGraphController::defaultCursorT())); } } diff --git a/apps/sequence/graph/graph_controller.h b/apps/sequence/graph/graph_controller.h index 5d538ec78..b7cc19542 100644 --- a/apps/sequence/graph/graph_controller.h +++ b/apps/sequence/graph/graph_controller.h @@ -26,7 +26,7 @@ private: Shared::XYBannerView * bannerView() override { return &m_bannerView; } bool handleEnter() override; bool moveCursorHorizontally(int direction) override; - double defaultCursorAbscissa() override; + double defaultCursorT() override; CurveViewRange * interactiveCurveViewRange() override { return m_graphRange; } SequenceStore * functionStore() const override { return static_cast(Shared::FunctionGraphController::functionStore()); } GraphView * functionGraphView() override { return &m_view; } diff --git a/apps/sequence/graph/graph_view.cpp b/apps/sequence/graph/graph_view.cpp index 6e0971c2e..2668ee843 100644 --- a/apps/sequence/graph/graph_view.cpp +++ b/apps/sequence/graph/graph_view.cpp @@ -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->evaluateAtAbscissa((float)x, context()); + float y = s->evaluateAtParameter((float)x, context()).y(); if (std::isnan(y)) { continue; } diff --git a/apps/sequence/sequence.h b/apps/sequence/sequence.h index a3393fe8b..2b9f3be8f 100644 --- a/apps/sequence/sequence.h +++ b/apps/sequence/sequence.h @@ -57,11 +57,11 @@ public: bool isDefined() override; bool isEmpty() override; // Approximation - float evaluateAtAbscissa(float x, Poincare::Context * context) const override { - return templatedApproximateAtAbscissa(x, static_cast(context)); + Poincare::Coordinate2D evaluateAtParameter(float x, Poincare::Context * context) const override { + return Poincare::Coordinate2D(x, templatedApproximateAtAbscissa(x, static_cast(context))); } - double evaluateAtAbscissa(double x, Poincare::Context * context) const override { - return templatedApproximateAtAbscissa(x, static_cast(context)); + Poincare::Coordinate2D evaluateAtParameter(double x, Poincare::Context * context) const override { + return Poincare::Coordinate2D(x,templatedApproximateAtAbscissa(x, static_cast(context))); } template T approximateToNextRank(int n, SequenceContext * sqctx) const; diff --git a/apps/shared/cartesian_function.cpp b/apps/shared/cartesian_function.cpp index d012f07b8..c4383b29b 100644 --- a/apps/shared/cartesian_function.cpp +++ b/apps/shared/cartesian_function.cpp @@ -112,6 +112,16 @@ void CartesianFunction::setPlotType(PlotType plotType) { return recordData()->setPlotType(plotType); } +Coordinate2D CartesianFunction::xyEvaluationAtParameter(double t, Poincare::Context * context) const { + Coordinate2D x1x2 = evaluateAtParameter(t, context); + PlotType type = plotType(); + if (type == PlotType::Cartesian || type == PlotType::Parametric) { + return x1x2; + } + assert(type == PlotType::Polar); + return Coordinate2D(x1x2.y() * std::cos(x1x2.x()*3.14/180.0), x1x2.y() * std::sin(x1x2.x()*3.14/180.0)); //TODO LEA RUBEN +} + bool CartesianFunction::displayDerivative() const { return recordData()->displayDerivative(); } @@ -159,17 +169,28 @@ CartesianFunction::CartesianFunctionRecordDataBuffer * CartesianFunction::record } template -T CartesianFunction::templatedApproximateAtAbscissa(T x, Poincare::Context * context) const { +Coordinate2D CartesianFunction::templatedApproximateAtParameter(T t, Poincare::Context * context) const { if (isCircularlyDefined(context)) { - return NAN; + return Coordinate2D(NAN, NAN); } constexpr int bufferSize = CodePoint::MaxCodePointCharLength + 1; - char unknownX[bufferSize]; - Poincare::SerializationHelper::CodePoint(unknownX, bufferSize, UCodePointUnknownX); - return PoincareHelpers::ApproximateWithValueForSymbol(expressionReduced(context), unknownX, x, context); + char unknown[bufferSize]; + Poincare::SerializationHelper::CodePoint(unknown, bufferSize, symbol()); + PlotType type = plotType(); + if (type == PlotType::Cartesian || type == PlotType::Polar) { + return Coordinate2D(t, PoincareHelpers::ApproximateWithValueForSymbol(expressionReduced(context), unknown, t, context)); + } + assert(type == PlotType::Parametric); + Expression e = expressionReduced(context); + assert(e.type() == ExpressionNode::Type::Matrix); + assert(static_cast(e).numberOfRows() == 2); + assert(static_cast(e).numberOfColumns() == 1); + return Coordinate2D( + PoincareHelpers::ApproximateWithValueForSymbol(e.childAtIndex(0), unknown, t, context), + PoincareHelpers::ApproximateWithValueForSymbol(e.childAtIndex(1), unknown, t, context)); } -template float CartesianFunction::templatedApproximateAtAbscissa(float, Poincare::Context *) const; -template double CartesianFunction::templatedApproximateAtAbscissa(double, Poincare::Context *) const; +template Coordinate2D CartesianFunction::templatedApproximateAtParameter(float, Poincare::Context *) const; +template Coordinate2D CartesianFunction::templatedApproximateAtParameter(double, Poincare::Context *) const; } diff --git a/apps/shared/cartesian_function.h b/apps/shared/cartesian_function.h index 28a980611..d8e0428ff 100644 --- a/apps/shared/cartesian_function.h +++ b/apps/shared/cartesian_function.h @@ -26,6 +26,7 @@ public: void setPlotType(PlotType plotType); // Evaluation + Poincare::Coordinate2D xyEvaluationAtParameter(double t, Poincare::Context * context) const; Poincare::Coordinate2D evaluateAtParameter(float t, Poincare::Context * context) const override { return templatedApproximateAtParameter(t, context); } @@ -38,8 +39,8 @@ public: int derivativeNameWithArgument(char * buffer, size_t bufferSize); double approximateDerivative(double x, Poincare::Context * context) const; // tMin and tMax - double tMin() const; - double tMax() const; + double tMin() const override; + double tMax() const override; void setTMin(double tMin); void setTMax(double tMax); private: @@ -52,7 +53,9 @@ private: CartesianFunctionRecordDataBuffer(KDColor color) : FunctionRecordDataBuffer(color), m_plotType(PlotType::Cartesian), - m_displayDerivative(false) + m_displayDerivative(false), + m_tMin(0.0), + m_tMax(396.0) // TODO LEA RUBEN {} PlotType plotType() const { return m_plotType; } void setPlotType(PlotType plotType) { m_plotType = plotType; } @@ -66,7 +69,7 @@ private: PlotType m_plotType; bool m_displayDerivative; double m_tMin; - bool m_tMax; + double m_tMax; /* In the record, after the boolean flag about displayDerivative, there is * the expression of the function, directly copied from the pool. */ //char m_expression[0]; @@ -81,7 +84,7 @@ private: size_t metaDataSize() const override { return sizeof(CartesianFunctionRecordDataBuffer); } const ExpressionModel * model() const override { return &m_model; } CartesianFunctionRecordDataBuffer * recordData() const; - template T templatedApproximateAtAbscissa(T x, Poincare::Context * context) const; + template Poincare::Coordinate2D templatedApproximateAtParameter(T t, Poincare::Context * context) const; Model m_model; }; diff --git a/apps/shared/curve_view.h b/apps/shared/curve_view.h index da10a0b77..9fc1a08b9 100644 --- a/apps/shared/curve_view.h +++ b/apps/shared/curve_view.h @@ -14,6 +14,7 @@ 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 typedef float (*EvaluateModelWithParameter)(float t, void * model, void * context); enum class Axis { Horizontal = 0, diff --git a/apps/shared/function.h b/apps/shared/function.h index c83705811..6f5cd7d79 100644 --- a/apps/shared/function.h +++ b/apps/shared/function.h @@ -33,12 +33,16 @@ public: KDColor color() const; void setActive(bool active); + // Definition Interval + virtual double tMin() const { return NAN; } + virtual double tMax() const { return NAN; } + // Name int nameWithArgument(char * buffer, size_t bufferSize); // Evaluation - virtual float evaluateAtAbscissa(float x, Poincare::Context * context) const = 0; - virtual double evaluateAtAbscissa(double x, Poincare::Context * context) const = 0; + virtual Poincare::Coordinate2D evaluateAtParameter(float t, Poincare::Context * context) const = 0; + virtual Poincare::Coordinate2D evaluateAtParameter(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: diff --git a/apps/shared/function_go_to_parameter_controller.cpp b/apps/shared/function_go_to_parameter_controller.cpp index 28a503e21..5abea7151 100644 --- a/apps/shared/function_go_to_parameter_controller.cpp +++ b/apps/shared/function_go_to_parameter_controller.cpp @@ -17,15 +17,15 @@ const char * FunctionGoToParameterController::title() { double FunctionGoToParameterController::parameterAtIndex(int index) { assert(index == 0); - return m_cursor->x(); + return m_cursor->t(); } bool FunctionGoToParameterController::setParameterAtIndex(int parameterIndex, double f) { assert(parameterIndex == 0); FunctionApp * myApp = FunctionApp::app(); ExpiringPointer function = myApp->functionStore()->modelForRecord(m_record); - double y = function->evaluateAtAbscissa(f, myApp->localContext()); - m_cursor->moveTo(f, y); + Poincare::Coordinate2D xy = function->evaluateAtParameter(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()); /* The range might have evolved to center around the cursor but we don't want diff --git a/apps/shared/function_graph_controller.cpp b/apps/shared/function_graph_controller.cpp index b224e296d..eb4f9043c 100644 --- a/apps/shared/function_graph_controller.cpp +++ b/apps/shared/function_graph_controller.cpp @@ -1,5 +1,6 @@ #include "function_graph_controller.h" #include "function_app.h" +#include #include #include #include @@ -8,6 +9,9 @@ using namespace Poincare; namespace Shared { +static inline int minFloat(float x, float y) { return x < y ? x : y; } +static inline int maxFloat(float x, float y) { return x > y ? x : y; } + FunctionGraphController::FunctionGraphController(Responder * parentResponder, InputEventHandlerDelegate * inputEventHandlerDelegate, ButtonRowController * header, InteractiveCurveViewRange * interactiveRange, CurveView * curveView, CurveViewCursor * cursor, int * indexFunctionSelectedByCursor, uint32_t * modelVersion, uint32_t * rangeVersion, Preferences::AngleUnit * angleUnitVersion) : InteractiveCurveViewController(parentResponder, inputEventHandlerDelegate, header, interactiveRange, curveView, cursor, modelVersion, rangeVersion), m_initialisationParameterController(this, interactiveRange), @@ -88,17 +92,29 @@ InteractiveCurveViewRangeDelegate::Range FunctionGraphController::computeYRange( * the values of a function. Otherwise some relevant extremal values may be * missed. */ const float step = curveView()->pixelWidth() / 2; - for (int i=0; inumberOfActiveFunctions(); i++) { + for (int i = 0; i < functionStore()->numberOfActiveFunctions(); i++) { ExpiringPointer f = functionStore()->modelForRecord(functionStore()->activeRecordAtIndex(i)); /* Scan x-range from the middle to the extrema in order to get balanced * y-range for even functions (y = 1/x). */ - const int balancedBound = std::floor((xMax-xMin)/2/step); + double tMin = f->tMin(); + if (std::isnan(tMin)) { + tMin = xMin; + } + double tMax = f->tMax(); + if (std::isnan(tMax)) { + tMax = xMax; + } + const int balancedBound = std::floor((tMax-tMin)/2/step); for (int j = -balancedBound; j <= balancedBound ; j++) { - float x = (xMin+xMax)/2 + step * j; - float y = f->evaluateAtAbscissa(x, context); - if (!std::isnan(y) && !std::isinf(y)) { - min = min < y ? min : y; - max = max > y ? max : y; + float t = (tMin+tMax)/2 + step * j; + Coordinate2D xy = f->evaluateAtParameter(t, context); + float x = xy.x(); + if (!std::isnan(x) && !std::isinf(x) && x >= xMin && x <= xMax) { + float y = xy.y(); + if (!std::isnan(y) && !std::isinf(y)) { + min = minFloat(min, y); + max = maxFloat(max, y); + } } } } @@ -108,8 +124,8 @@ InteractiveCurveViewRangeDelegate::Range FunctionGraphController::computeYRange( return range; } -double FunctionGraphController::defaultCursorAbscissa() { - return (interactiveCurveViewRange()->xMin()+interactiveCurveViewRange()->xMax())/2.0f; +double FunctionGraphController::defaultCursorT() { + return 0.0; //TODO LEA (interactiveCurveViewRange()->xMin()+interactiveCurveViewRange()->xMax())/2.0f; } FunctionStore * FunctionGraphController::functionStore() const { @@ -117,23 +133,25 @@ FunctionStore * FunctionGraphController::functionStore() const { } void FunctionGraphController::initCursorParameters() { - double x = defaultCursorAbscissa(); + double t = defaultCursorT(); Poincare::Context * context = textFieldDelegateApp()->localContext(); int functionIndex = 0; - double y = 0; + Coordinate2D xy; do { ExpiringPointer firstFunction = functionStore()->modelForRecord(functionStore()->activeRecordAtIndex(functionIndex++)); - y = firstFunction->evaluateAtAbscissa(x, context); - } while ((std::isnan(y) || std::isinf(y)) && functionIndex < functionStore()->numberOfActiveFunctions()); - m_cursor->moveTo(x, y); - functionIndex = (std::isnan(y) || std::isinf(y)) ? 0 : functionIndex - 1; + xy = firstFunction->evaluateAtParameter(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; selectFunctionWithCursor(functionIndex); if (interactiveCurveViewRange()->yAuto()) { - interactiveCurveViewRange()->panToMakePointVisible(x, y, cursorTopMarginRatio(), k_cursorRightMarginRatio, cursorBottomMarginRatio(), k_cursorLeftMarginRatio); + interactiveCurveViewRange()->panToMakePointVisible(xy.x(), xy.y(), cursorTopMarginRatio(), k_cursorRightMarginRatio, cursorBottomMarginRatio(), k_cursorLeftMarginRatio); } } bool FunctionGraphController::moveCursorVertically(int direction) { + return false; //TODO LEA +#if 0 int currentActiveFunctionIndex = indexFunctionSelectedByCursor(); Poincare::Context * context = textFieldDelegateApp()->localContext(); int nextActiveFunctionIndex = InteractiveCurveViewController::closestCurveIndexVertically(direction > 0, currentActiveFunctionIndex, context); @@ -143,6 +161,7 @@ bool FunctionGraphController::moveCursorVertically(int direction) { selectFunctionWithCursor(nextActiveFunctionIndex); m_cursor->moveTo(m_cursor->x(), yValue(nextActiveFunctionIndex, m_cursor->x(), context)); return true; +#endif } CurveView * FunctionGraphController::curveView() { @@ -161,8 +180,8 @@ bool FunctionGraphController::closestCurveIndexIsSuitable(int newIndex, int curr return newIndex != currentIndex; } -double FunctionGraphController::yValue(int curveIndex, double x, Poincare::Context * context) const { - return functionStore()->modelForRecord(functionStore()->activeRecordAtIndex(curveIndex))->evaluateAtAbscissa(x, context); +Coordinate2D FunctionGraphController::xyValues(int curveIndex, double t, Poincare::Context * context) const { + return functionStore()->modelForRecord(functionStore()->activeRecordAtIndex(curveIndex))->evaluateAtParameter(t, context); } int FunctionGraphController::numberOfCurves() const { diff --git a/apps/shared/function_graph_controller.h b/apps/shared/function_graph_controller.h index 6f2eb565d..7c37742d3 100644 --- a/apps/shared/function_graph_controller.h +++ b/apps/shared/function_graph_controller.h @@ -25,13 +25,13 @@ protected: bool handleEnter() override; int indexFunctionSelectedByCursor() const { return *m_indexFunctionSelectedByCursor; } virtual void selectFunctionWithCursor(int functionIndex); - virtual double defaultCursorAbscissa(); + virtual double defaultCursorT(); virtual FunctionStore * functionStore() const; // Closest vertical curve helper bool closestCurveIndexIsSuitable(int newIndex, int currentIndex) const override; int selectedCurveIndex() const override { return *m_indexFunctionSelectedByCursor; } - double yValue(int curveIndex, double x, Poincare::Context * context) const override; + Poincare::Coordinate2D xyValues(int curveIndex, double t, Poincare::Context * context) const override; int numberOfCurves() const override; private: diff --git a/apps/shared/interactive_curve_view_controller.cpp b/apps/shared/interactive_curve_view_controller.cpp index 547dbd638..72f781fa3 100644 --- a/apps/shared/interactive_curve_view_controller.cpp +++ b/apps/shared/interactive_curve_view_controller.cpp @@ -186,8 +186,8 @@ bool InteractiveCurveViewController::textFieldDidFinishEditing(TextField * textF if (textFieldDelegateApp()->hasUndefinedValue(text, floatBody)) { return false; } - double y = yValue(selectedCurveIndex(), floatBody, textFieldDelegateApp()->localContext()); - m_cursor->moveTo(floatBody, y); + Coordinate2D xy = xyValues(selectedCurveIndex(), floatBody, textFieldDelegateApp()->localContext()); + m_cursor->moveTo(floatBody, xy.x(), xy.y()); interactiveCurveViewRange()->panToMakePointVisible(m_cursor->x(), m_cursor->y(), cursorTopMarginRatio(), k_cursorRightMarginRatio, cursorBottomMarginRatio(), k_cursorLeftMarginRatio); reloadBannerView(); curveView()->reload(); @@ -221,6 +221,8 @@ bool InteractiveCurveViewController::isCursorVisible() { } int InteractiveCurveViewController::closestCurveIndexVertically(bool goingUp, int currentCurveIndex, Poincare::Context * context) const { + return 0; //TODO LEA +#if 0 double x = m_cursor->x(); double y = m_cursor->y(); double nextY = goingUp ? DBL_MAX : -DBL_MAX; @@ -273,6 +275,7 @@ int InteractiveCurveViewController::closestCurveIndexVertically(bool goingUp, in } } return nextCurveIndex; +#endif } float InteractiveCurveViewController::cursorBottomMarginRatio() { diff --git a/apps/shared/interactive_curve_view_controller.h b/apps/shared/interactive_curve_view_controller.h index 105eb2520..eb20ad2fe 100644 --- a/apps/shared/interactive_curve_view_controller.h +++ b/apps/shared/interactive_curve_view_controller.h @@ -6,6 +6,7 @@ #include "ok_view.h" #include "range_parameter_controller.h" #include "zoom_parameter_controller.h" +#include namespace Shared { @@ -44,7 +45,7 @@ protected: int closestCurveIndexVertically(bool goingUp, int currentSelectedCurve, Poincare::Context * context) const; virtual bool closestCurveIndexIsSuitable(int newIndex, int currentIndex) const = 0; virtual int selectedCurveIndex() const = 0; - virtual double yValue(int curveIndex, double x, Poincare::Context * context) const = 0; + virtual Poincare::Coordinate2D xyValues(int curveIndex, double t, Poincare::Context * context) const = 0; virtual bool suitableYValue(double y) const { return true; } virtual int numberOfCurves() const = 0; diff --git a/apps/shared/sum_graph_controller.cpp b/apps/shared/sum_graph_controller.cpp index 01b34e940..bdffbf805 100644 --- a/apps/shared/sum_graph_controller.cpp +++ b/apps/shared/sum_graph_controller.cpp @@ -65,8 +65,10 @@ bool SumGraphController::moveCursorHorizontallyToPosition(double x) { FunctionApp * myApp = FunctionApp::app(); assert(!m_record.isNull()); ExpiringPointer function = myApp->functionStore()->modelForRecord(m_record); - double y = function->evaluateAtAbscissa(x, myApp->localContext()); - m_cursor->moveTo(x, y); + + Coordinate2D xy = function->evaluateAtParameter(x, myApp->localContext()); //TODO LEA assertion that x = t? + double y = xy.y(); + m_cursor->moveTo(x, x, y); if (m_step == Step::SecondParameter) { m_graphView->setAreaHighlight(m_startSum, m_cursor->x()); } diff --git a/apps/shared/values_controller.cpp b/apps/shared/values_controller.cpp index 45fd31151..b7b1882d4 100644 --- a/apps/shared/values_controller.cpp +++ b/apps/shared/values_controller.cpp @@ -327,7 +327,10 @@ int ValuesController::maxNumberOfElements() const { double ValuesController::evaluationOfAbscissaAtColumn(double abscissa, int columnIndex) { ExpiringPointer function = functionStore()->modelForRecord(recordAtColumn(columnIndex)); - return function->evaluateAtAbscissa(abscissa, textFieldDelegateApp()->localContext()); + //TODO LEA RUBEN Careful with merge + //TODO LEA RUBEN change with evaluationOfParameterAtColumn? + Poincare::Coordinate2D xy = function->evaluateAtParameter(abscissa, textFieldDelegateApp()->localContext()); + return xy.y(); } void ValuesController::updateNumberOfColumns() { diff --git a/poincare/include/poincare/coordinate_2D.h b/poincare/include/poincare/coordinate_2D.h index ecd8748be..0a9489f44 100644 --- a/poincare/include/poincare/coordinate_2D.h +++ b/poincare/include/poincare/coordinate_2D.h @@ -5,6 +5,7 @@ namespace Poincare { +// TODO LEA RUBEN x1 and x2 instead of x y template class Coordinate2D final { public: