diff --git a/apps/graph/graph/graph_controller.cpp b/apps/graph/graph/graph_controller.cpp index bffde8d6b..0e1fc3aa0 100644 --- a/apps/graph/graph/graph_controller.cpp +++ b/apps/graph/graph/graph_controller.cpp @@ -2,11 +2,10 @@ #include "../app.h" using namespace Shared; -using namespace Poincare; namespace Graph { -GraphController::GraphController(Responder * parentResponder, CartesianFunctionStore * functionStore, Shared::InteractiveCurveViewRange * curveViewRange, CurveViewCursor * cursor, int * indexFunctionSelectedByCursor, uint32_t * modelVersion, uint32_t * rangeVersion, Preferences::AngleUnit * angleUnitVersion, ButtonRowController * header) : +GraphController::GraphController(Responder * parentResponder, CartesianFunctionStore * functionStore, Shared::InteractiveCurveViewRange * curveViewRange, CurveViewCursor * cursor, int * indexFunctionSelectedByCursor, uint32_t * modelVersion, uint32_t * rangeVersion, Poincare::Preferences::AngleUnit * angleUnitVersion, ButtonRowController * header) : FunctionGraphController(parentResponder, header, curveViewRange, &m_view, cursor, indexFunctionSelectedByCursor, modelVersion, rangeVersion, angleUnitVersion), m_bannerView(), m_view(functionStore, curveViewRange, m_cursor, &m_bannerView, &m_cursorView), @@ -44,7 +43,7 @@ float GraphController::interestingXRange() { TextFieldDelegateApp * myApp = (TextFieldDelegateApp *)app(); for (int i = 0; i < functionStore()->numberOfActiveFunctions(); i++) { Function * f = functionStore()->activeFunctionAtIndex(i); - float fRange = f->expression(myApp->localContext()).characteristicXRange(*(myApp->localContext()), Preferences::sharedPreferences()->angleUnit()); + float fRange = f->expression(myApp->localContext()).characteristicXRange(*(myApp->localContext()), Poincare::Preferences::sharedPreferences()->angleUnit()); if (!std::isnan(fRange)) { characteristicRange = fRange > characteristicRange ? fRange : characteristicRange; } diff --git a/apps/graph/graph/intersection_graph_controller.cpp b/apps/graph/graph/intersection_graph_controller.cpp index 06158dff3..71b47b3d8 100644 --- a/apps/graph/graph/intersection_graph_controller.cpp +++ b/apps/graph/graph/intersection_graph_controller.cpp @@ -3,7 +3,6 @@ #include "../../shared/poincare_helpers.h" using namespace Shared; -using namespace Poincare; namespace Graph { @@ -21,7 +20,7 @@ const char * IntersectionGraphController::title() { void IntersectionGraphController::reloadBannerView() { m_bannerView->setNumberOfSubviews(2); reloadBannerViewForCursorOnFunction(m_cursor, m_function, 'x'); - size_t bufferSize = FunctionBannerDelegate::k_maxNumberOfCharacters+PrintFloat::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits); + size_t bufferSize = FunctionBannerDelegate::k_maxNumberOfCharacters+Poincare::PrintFloat::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits); char buffer[bufferSize]; const char * space = " "; int spaceLength = strlen(space); @@ -31,18 +30,18 @@ void IntersectionGraphController::reloadBannerView() { numberOfChar += strlcpy(buffer, legend, bufferSize); buffer[0] = m_function->name()[0]; buffer[5] = m_intersectedFunction->name()[0]; - numberOfChar += PoincareHelpers::ConvertFloatToText(m_cursor->y(), buffer+numberOfChar, PrintFloat::bufferSizeForFloatsWithPrecision(Constant::MediumNumberOfSignificantDigits), Constant::MediumNumberOfSignificantDigits); + numberOfChar += PoincareHelpers::ConvertFloatToText(m_cursor->y(), buffer+numberOfChar, Poincare::PrintFloat::bufferSizeForFloatsWithPrecision(Constant::MediumNumberOfSignificantDigits), Constant::MediumNumberOfSignificantDigits); strlcpy(buffer+numberOfChar, space, bufferSize - numberOfChar); buffer[FunctionBannerDelegate::k_maxDigitLegendLength+legendLength] = 0; bannerView()->setLegendAtIndex(buffer, 1); } -Expression::Coordinate2D IntersectionGraphController::computeNewPointOfInterest(double start, double step, double max, Context * context) { - Expression::Coordinate2D result = {.abscissa = NAN, .value = NAN}; +Poincare::Expression::Coordinate2D IntersectionGraphController::computeNewPointOfInterest(double start, double step, double max, Poincare::Context * context) { + Poincare::Expression::Coordinate2D result = {.abscissa = NAN, .value = NAN}; for (int i = 0; i < m_functionStore->numberOfActiveFunctions(); i++) { Function * f = m_functionStore->activeFunctionAtIndex(i); if (f != m_function) { - Expression::Coordinate2D intersection = m_function->nextIntersectionFrom(start, step, max, context, f); + Poincare::Expression::Coordinate2D intersection = m_function->nextIntersectionFrom(start, step, max, context, f); if ((std::isnan(result.abscissa) || std::fabs(intersection.abscissa-start) < std::fabs(result.abscissa-start)) && !std::isnan(intersection.abscissa)) { m_intersectedFunction = f; result = (std::isnan(result.abscissa) || std::fabs(intersection.abscissa-start) < std::fabs(result.abscissa-start)) ? intersection : result; diff --git a/poincare/Makefile b/poincare/Makefile index 4fe4a40f3..9c06e04c4 100644 --- a/poincare/Makefile +++ b/poincare/Makefile @@ -70,6 +70,7 @@ objs += $(addprefix poincare/src/,\ float.o\ floor.o\ frac_part.o\ + function.o\ global_context.o\ great_common_divisor.o\ hyperbolic_arc_cosine.o\ diff --git a/poincare/include/poincare/expression.h b/poincare/include/poincare/expression.h index 5c3961871..0c1e421fb 100644 --- a/poincare/include/poincare/expression.h +++ b/poincare/include/poincare/expression.h @@ -37,6 +37,7 @@ class Expression : public TreeHandle { friend class Factorial; friend class Floor; friend class FracPart; + friend class Function; friend class GlobalContext; friend class GreatCommonDivisor; friend class HyperbolicTrigonometricFunction; @@ -74,6 +75,7 @@ class Expression : public TreeHandle { template friend class ExceptionExpressionNode; friend class ExpressionNode; + friend class FunctionNode; friend class IntegralNode; template friend class LogarithmNode; diff --git a/poincare/include/poincare/expression_node.h b/poincare/include/poincare/expression_node.h index f91f46ebf..5d85d6821 100644 --- a/poincare/include/poincare/expression_node.h +++ b/poincare/include/poincare/expression_node.h @@ -51,6 +51,7 @@ public: Factor, Floor, FracPart, + Function, GreatCommonDivisor, HyperbolicArcCosine, HyperbolicArcSine, diff --git a/poincare/include/poincare/function.h b/poincare/include/poincare/function.h new file mode 100644 index 000000000..f84b87cb9 --- /dev/null +++ b/poincare/include/poincare/function.h @@ -0,0 +1,50 @@ +#ifndef POINCARE_FUNCTION_H +#define POINCARE_FUNCTION_H + +#include + +namespace Poincare { + +class FunctionNode : public SymbolNode { +public: + // TreeNode + size_t size() const override { return sizeof(FunctionNode); } + int numberOfChildren() const override { return 1; } //TODO allow any number of children? +#if POINCARE_TREE_LOG + virtual void logNodeName(std::ostream & stream) const override { + stream << "Function"; + } +#endif + + // Properties + Type type() const override { return Type::Function; } + int polynomialDegree(Context & context, char symbolName) const override; + int getPolynomialCoefficients(Context & context, char symbolName, Expression coefficients[]) const override; + int getVariables(Context & context, isVariableTest isVariable, char * variables) const override; + float characteristicXRange(Context & context, Preferences::AngleUnit angleUnit) const override; + +private: + // Layout + Layout createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override; + int serialize(char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override; + // Simplification + Expression shallowReduce(Context & context, Preferences::AngleUnit angleUnit) override; + // Evaluation + Evaluation approximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override; + Evaluation approximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override; +}; + +class Function : public Symbol { +public: + Function(); + Function(const FunctionNode * n) : Symbol(n) {} + explicit Function(Expression operand) : Function() { + replaceChildAtIndexInPlace(0, operand); + } + + Expression shallowReduce(Context & context, Preferences::AngleUnit angleUnit); +}; + +} + +#endif diff --git a/poincare/include/poincare_nodes.h b/poincare/include/poincare_nodes.h index 005b248f5..c52c4fa7e 100644 --- a/poincare/include/poincare_nodes.h +++ b/poincare/include/poincare_nodes.h @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include diff --git a/poincare/src/function.cpp b/poincare/src/function.cpp new file mode 100644 index 000000000..8a5e5a2d2 --- /dev/null +++ b/poincare/src/function.cpp @@ -0,0 +1,60 @@ +#include +#include +#include +#include +#include +#include + +namespace Poincare { + +int FunctionNode::polynomialDegree(Context & context, char symbolName) const { + Expression e = context.expressionForSymbol(Function(this)); + return e.polynomialDegree(context, symbolName); +} + +int FunctionNode::getPolynomialCoefficients(Context & context, char symbolName, Expression coefficients[]) const { + Expression e = context.expressionForSymbol(Function(this)); + return e.getPolynomialCoefficients(context, symbolName, coefficients); +} + +int FunctionNode::getVariables(Context & context, isVariableTest isVariable, char * variables) const { + Expression e = context.expressionForSymbol(Function(this)); + return e.getVariables(context, isVariable, variables); +} + +float FunctionNode::characteristicXRange(Context & context, Preferences::AngleUnit angleUnit) const { + Expression e = context.expressionForSymbol(Function(this)); + return e.characteristicXRange(context, angleUnit); +} + +Layout FunctionNode::createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const { + char nameString[2] = {name(), 0}; //TODO Fix this when longer name + return LayoutHelper::Prefix(Function(this), floatDisplayMode, numberOfSignificantDigits, nameString); +} + +int FunctionNode::serialize(char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const { + char nameString[2] = {name(), 0}; //TODO Fix this when longer name + return SerializationHelper::Prefix(this, buffer, bufferSize, floatDisplayMode, numberOfSignificantDigits, nameString); +} + +Expression FunctionNode::shallowReduce(Context & context, Preferences::AngleUnit angleUnit) { + return Function(this).shallowReduce(context, angleUnit); +} + +Evaluation FunctionNode::approximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const { + Expression e = context.expressionForSymbol(Function(this)); + return e.approximateToEvaluation(context, angleUnit); +} + +Evaluation FunctionNode::approximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const { + Expression e = context.expressionForSymbol(Function(this)); + return e.approximateToEvaluation(context, angleUnit); +} + +Function::Function() : Function(TreePool::sharedPool()->createTreeNode()) {} + +Expression Function::shallowReduce(Context & context, Preferences::AngleUnit angleUnit) { + return Expression::defaultShallowReduce(context, angleUnit); +} + +} diff --git a/poincare/src/tree_pool.cpp b/poincare/src/tree_pool.cpp index e1a1dd322..cceb37f72 100644 --- a/poincare/src/tree_pool.cpp +++ b/poincare/src/tree_pool.cpp @@ -231,6 +231,7 @@ template DivisionNode * Poincare::TreePool::createTreeNode(size_t template DivisionQuotientNode * Poincare::TreePool::createTreeNode(size_t size); template DivisionRemainderNode * Poincare::TreePool::createTreeNode(size_t size); template EmptyExpressionNode * Poincare::TreePool::createTreeNode(size_t size); +template FunctionNode * Poincare::TreePool::createTreeNode(size_t size); template HyperbolicArcCosineNode * Poincare::TreePool::createTreeNode(size_t size); template HyperbolicArcSineNode * Poincare::TreePool::createTreeNode(size_t size); template HyperbolicArcTangentNode * Poincare::TreePool::createTreeNode(size_t size);