diff --git a/apps/calculation/additional_outputs/trigonometry_graph_cell.cpp b/apps/calculation/additional_outputs/trigonometry_graph_cell.cpp index 636ce588a..fe5487e0a 100644 --- a/apps/calculation/additional_outputs/trigonometry_graph_cell.cpp +++ b/apps/calculation/additional_outputs/trigonometry_graph_cell.cpp @@ -8,7 +8,8 @@ namespace Calculation { TrigonometryGraphView::TrigonometryGraphView(TrigonometryModel * model) : CurveView(model), - m_model(model) + m_model(model), + m_shouldDisplayTan(false) { } @@ -22,17 +23,33 @@ void TrigonometryGraphView::drawRect(KDContext * ctx, KDRect rect) const { drawCurve(ctx, rect, 0.0f, 2.0f*M_PI, M_PI/180.0f, [](float t, void * model, void * context) { return Poincare::Coordinate2D(std::cos(t), std::sin(t)); }, nullptr, nullptr, true, Palette::SecondaryText, false); - // Draw dashed segment to indicate sine and cosine - drawHorizontalOrVerticalSegment(ctx, rect, Axis::Vertical, c, 0.0f, s, Palette::CalculationTrigoAndComplexForeground, 1, 3); - drawHorizontalOrVerticalSegment(ctx, rect, Axis::Horizontal, s, 0.0f, c, Palette::CalculationTrigoAndComplexForeground, 1, 3); + + if (!m_shouldDisplayTan) { + // Draw dashed segment to indicate sine and cosine + drawHorizontalOrVerticalSegment(ctx, rect, Axis::Vertical, c, 0.0f, s, Palette::CalculationTrigoAndComplexForeground, 1, 3); + drawHorizontalOrVerticalSegment(ctx, rect, Axis::Horizontal, s, 0.0f, c, Palette::CalculationTrigoAndComplexForeground, 1, 3); + } + + if (m_shouldDisplayTan) { + float t = std::tan(m_model->angle()); + drawHorizontalOrVerticalSegment(ctx, rect, Axis::Vertical, 1.0f, m_model->yMin(), m_model->yMax(), Palette::SecondaryText, 2); + drawSegment(ctx, rect, 0.0f, 0.0f, 1.0f, t, Palette::SecondaryText, false); + drawDot(ctx, rect, 1.0f, t, Palette::CalculationTrigoAndComplexForeground, Size::Large); + drawLabel(ctx, rect, 0.0f, t, "tan(θ)", Palette::CalculationTrigoAndComplexForeground, CurveView::RelativePosition::Before, CurveView::RelativePosition::None); + drawHorizontalOrVerticalSegment(ctx, rect, Axis::Horizontal, t, 0.0f, 1.0f, Palette::CalculationTrigoAndComplexForeground, 1, 3); + } + // Draw angle position on the circle - drawDot(ctx, rect, c, s, Palette::CalculationTrigoAndComplexForeground, Size::Large); + drawDot(ctx, rect, c, s, m_shouldDisplayTan ? Palette::SecondaryText : Palette::CalculationTrigoAndComplexForeground, m_shouldDisplayTan ? Size::Tiny : Size::Large); // Draw graduations drawLabelsAndGraduations(ctx, rect, Axis::Vertical, false, true); drawLabelsAndGraduations(ctx, rect, Axis::Horizontal, false, true); - // Draw labels - drawLabel(ctx, rect, 0.0f, s, "sin(θ)", Palette::CalculationTrigoAndComplexForeground, c >= 0.0f ? CurveView::RelativePosition::Before : CurveView::RelativePosition::After, CurveView::RelativePosition::None); - drawLabel(ctx, rect, c, 0.0f, "cos(θ)", Palette::CalculationTrigoAndComplexForeground, CurveView::RelativePosition::None, s >= 0.0f ? CurveView::RelativePosition::Before : CurveView::RelativePosition::After); + + if (!m_shouldDisplayTan) { + // Draw labels + drawLabel(ctx, rect, 0.0f, s, "sin(θ)", Palette::CalculationTrigoAndComplexForeground, c >= 0.0f ? CurveView::RelativePosition::Before : CurveView::RelativePosition::After, CurveView::RelativePosition::None); + drawLabel(ctx, rect, c, 0.0f, "cos(θ)", Palette::CalculationTrigoAndComplexForeground, CurveView::RelativePosition::None, s >= 0.0f ? CurveView::RelativePosition::Before : CurveView::RelativePosition::After); + } } } diff --git a/apps/calculation/additional_outputs/trigonometry_graph_cell.h b/apps/calculation/additional_outputs/trigonometry_graph_cell.h index aea81926a..92fccd8ae 100644 --- a/apps/calculation/additional_outputs/trigonometry_graph_cell.h +++ b/apps/calculation/additional_outputs/trigonometry_graph_cell.h @@ -11,13 +11,16 @@ class TrigonometryGraphView : public Shared::CurveView { public: TrigonometryGraphView(TrigonometryModel * model); void drawRect(KDContext * ctx, KDRect rect) const override; + void setShouldDisplayTan(bool shouldDisplayTan) { m_shouldDisplayTan = shouldDisplayTan; }; private: TrigonometryModel * m_model; + bool m_shouldDisplayTan; }; class TrigonometryGraphCell : public IllustrationCell { public: TrigonometryGraphCell(TrigonometryModel * model) : m_view(model) {} + void setShouldDisplayTan(bool shouldDisplayTan) { m_view.setShouldDisplayTan(shouldDisplayTan); }; private: View * view() override { return &m_view; } TrigonometryGraphView m_view; diff --git a/apps/calculation/additional_outputs/trigonometry_list_controller.cpp b/apps/calculation/additional_outputs/trigonometry_list_controller.cpp index 354cbc739..bdb612006 100644 --- a/apps/calculation/additional_outputs/trigonometry_list_controller.cpp +++ b/apps/calculation/additional_outputs/trigonometry_list_controller.cpp @@ -18,7 +18,10 @@ Poincare::Constant toConstant(Expression e) { } void TrigonometryListController::setExpression(Expression e) { - assert(e.type() == ExpressionNode::Type::Cosine || e.type() == ExpressionNode::Type::Sine); + assert(e.type() == ExpressionNode::Type::Cosine || e.type() == ExpressionNode::Type::Sine || e.type() == ExpressionNode::Type::Tangent); + bool shouldDisplayTan = e.type() == ExpressionNode::Type::Tangent; + m_graphCell.setShouldDisplayTan(shouldDisplayTan); + m_model.setShouldDisplayTan(shouldDisplayTan); Poincare::Context * context = App::app()->localContext(); Poincare::Preferences * preferences = Poincare::Preferences::sharedPreferences(); @@ -58,6 +61,7 @@ void TrigonometryListController::setExpression(Expression e) { IllustratedListController::setExpression(angleExpression); // Fill calculation store + m_calculationStore.push("tan(θ)", context, CalculationHeight); m_calculationStore.push("sin(θ)", context, CalculationHeight); m_calculationStore.push("cos(θ)", context, CalculationHeight); m_calculationStore.push("θ", context, CalculationHeight); diff --git a/apps/calculation/additional_outputs/trigonometry_model.cpp b/apps/calculation/additional_outputs/trigonometry_model.cpp index ef7c708c3..8b61bac8d 100644 --- a/apps/calculation/additional_outputs/trigonometry_model.cpp +++ b/apps/calculation/additional_outputs/trigonometry_model.cpp @@ -8,4 +8,22 @@ TrigonometryModel::TrigonometryModel() : { } +float TrigonometryModel::yMin() const { + if (m_shouldDisplayTan) { + return -1.1f; + } + return yCenter() - yHalfRange(); +} + +float TrigonometryModel::yMax() const { + if (m_shouldDisplayTan) { + float t = std::tan(angle()); + if (t <= 1.2f) { + return 1.2f; + } + return 1.2f * std::tan(angle()); + } + return yCenter() + yHalfRange(); +} + } diff --git a/apps/calculation/additional_outputs/trigonometry_model.h b/apps/calculation/additional_outputs/trigonometry_model.h index c299565a8..f53ebbd3c 100644 --- a/apps/calculation/additional_outputs/trigonometry_model.h +++ b/apps/calculation/additional_outputs/trigonometry_model.h @@ -14,11 +14,12 @@ public: // CurveViewRange float xMin() const override { return -k_xHalfRange; } float xMax() const override { return k_xHalfRange; } - float yMin() const override { return yCenter() - yHalfRange(); } - float yMax() const override { return yCenter() + yHalfRange(); } + float yMin() const override; + float yMax() const override; void setAngle(float f) { m_angle = f; } float angle() const { return m_angle*(float)M_PI/(float)Poincare::Trigonometry::PiInAngleUnit(Poincare::Preferences::sharedPreferences()->angleUnit()); } + void setShouldDisplayTan(bool shouldDisplayTan) { m_shouldDisplayTan = shouldDisplayTan; } private: constexpr static float k_xHalfRange = 2.1f; // We center the yRange around the semi-circle where the angle is @@ -33,6 +34,7 @@ private: float yHalfRange() const { return IllustratedListController::k_illustrationHeight*k_xHalfRange/(Ion::Display::Width - Metric::PopUpRightMargin - Metric::PopUpLeftMargin); } float m_angle; + bool m_shouldDisplayTan; }; } diff --git a/apps/calculation/calculation.cpp b/apps/calculation/calculation.cpp index b67efc2b8..694bf5cb4 100644 --- a/apps/calculation/calculation.cpp +++ b/apps/calculation/calculation.cpp @@ -251,8 +251,11 @@ Calculation::AdditionalInformationType Calculation::additionalInformationType(Co * - > input: 2cos(2) - cos(2) * > output: cos(2) */ - if (input().isDefinedCosineOrSine(context, complexFormat, preferences->angleUnit()) || o.isDefinedCosineOrSine(context, complexFormat, preferences->angleUnit())) { - return AdditionalInformationType::Trigonometry; + if (i.isDefinedCosineOrSineOrTangent(context, complexFormat, preferences->angleUnit())) { + return AdditionalInformationType::TrigonometryInput; + } + if (o.isDefinedCosineOrSineOrTangent(context, complexFormat, preferences->angleUnit())) { + return AdditionalInformationType::TrigonometryOutput; } if (o.hasUnit()) { Expression unit; diff --git a/apps/calculation/calculation.h b/apps/calculation/calculation.h index 4c40bcbb1..013708739 100644 --- a/apps/calculation/calculation.h +++ b/apps/calculation/calculation.h @@ -40,7 +40,8 @@ public: Integer, Rational, SecondDegree, - Trigonometry, + TrigonometryInput, + TrigonometryOutput, Unit, Matrix, Complex diff --git a/apps/calculation/history_controller.cpp b/apps/calculation/history_controller.cpp index 9a8687309..24736d8a9 100644 --- a/apps/calculation/history_controller.cpp +++ b/apps/calculation/history_controller.cpp @@ -103,12 +103,12 @@ bool HistoryController::handleEvent(Ion::Events::Event event) { vc = &m_complexController; } else if (additionalInfoType == Calculation::AdditionalInformationType::SecondDegree) { vc = &m_secondDegreeController; - } else if (additionalInfoType == Calculation::AdditionalInformationType::Trigonometry) { + } else if (additionalInfoType == Calculation::AdditionalInformationType::TrigonometryInput) { vc = &m_trigonometryController; - // Find which of the input or output is the cosine/sine - ExpressionNode::Type t = e.type(); - e = t == ExpressionNode::Type::Cosine || t == ExpressionNode::Type::Sine ? e : calculationAtIndex(focusRow)->input(); - } else if (additionalInfoType == Calculation::AdditionalInformationType::Integer) { + e = calculationAtIndex(focusRow)->input(); + } else if (additionalInfoType == Calculation::AdditionalInformationType::TrigonometryOutput) { + vc = &m_trigonometryController; + } else if (additionalInfoType == Calculation::AdditionalInformationType::Integer) { vc = &m_integerController; } else if (additionalInfoType == Calculation::AdditionalInformationType::Rational) { vc = &m_rationalController; diff --git a/poincare/include/poincare/expression.h b/poincare/include/poincare/expression.h index e1d66d222..aaa688f58 100644 --- a/poincare/include/poincare/expression.h +++ b/poincare/include/poincare/expression.h @@ -183,7 +183,7 @@ public: bool isRationalOne() const; bool isRandom() const { return node()->isRandom(); } bool isParameteredExpression() const { return node()->isParameteredExpression(); } - bool isDefinedCosineOrSine(Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const; + bool isDefinedCosineOrSineOrTangent(Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const; bool isBasedIntegerCappedBy(const char * integerString) const; bool isDivisionOfIntegers() const; bool hasDefinedComplexApproximation(Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const; diff --git a/poincare/src/expression.cpp b/poincare/src/expression.cpp index a20978576..0de33042d 100644 --- a/poincare/src/expression.cpp +++ b/poincare/src/expression.cpp @@ -292,9 +292,9 @@ bool Expression::getLinearCoefficients(char * variables, int maxVariableSize, Ex return !isMultivariablePolynomial; } -bool Expression::isDefinedCosineOrSine(Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const { +bool Expression::isDefinedCosineOrSineOrTangent(Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const { ExpressionNode::Type t = type(); - if (t == ExpressionNode::Type::Cosine || t == ExpressionNode::Type::Sine) { + if (t == ExpressionNode::Type::Cosine || t == ExpressionNode::Type::Sine || t == ExpressionNode::Type::Tangent) { float r = childAtIndex(0).approximateToScalar(context, complexFormat, angleUnit); if (!std::isnan(r)) { return true;