diff --git a/apps/i18n.cpp b/apps/i18n.cpp index 3d52f8be8..8ad332126 100644 --- a/apps/i18n.cpp +++ b/apps/i18n.cpp @@ -307,7 +307,7 @@ constexpr static char leftIntegralFirstLegend[] = {'P', '(', 'X', Ion::Charset:: constexpr static char finiteIntegralLegend[] = {Ion::Charset::LessEqual, 'X', Ion::Charset::LessEqual, 0}; -const char * universalMessages[238] { +const char * universalMessages[239] { "", "alpha", "ALPHA", @@ -334,6 +334,7 @@ const char * universalMessages[238] { leftIntegralFirstLegend, ")=", finiteIntegralLegend, + "P(X=", " D: y=ax+b ", diff --git a/apps/i18n.h b/apps/i18n.h index 9d50ca64a..c5011f92e 100644 --- a/apps/i18n.h +++ b/apps/i18n.h @@ -288,6 +288,7 @@ namespace I18n { LeftIntegralFirstLegend, LeftIntegralSecondLegend, FiniteIntegralLegend, + DiscreteLegend, RegressionFormula, diff --git a/apps/probability/Makefile b/apps/probability/Makefile index b8b370c2f..73e90cc91 100644 --- a/apps/probability/Makefile +++ b/apps/probability/Makefile @@ -1,6 +1,7 @@ app_objs += $(addprefix apps/probability/,\ app.o\ calculation/calculation.o\ + calculation/discrete_calculation.o\ calculation/left_integral_calculation.o\ calculation/right_integral_calculation.o\ calculation/finite_integral_calculation.o\ @@ -27,11 +28,13 @@ app_images += $(addprefix apps/probability/images/,\ calcul1_icon.png\ calcul2_icon.png\ calcul3_icon.png\ + calcul4_icon.png\ exponential_icon.png\ focused_binomial_icon.png\ focused_calcul1_icon.png\ focused_calcul2_icon.png\ focused_calcul3_icon.png\ + focused_calcul4_icon.png\ focused_exponential_icon.png\ focused_normal_icon.png\ focused_poisson_icon.png\ diff --git a/apps/probability/calculation/calculation.cpp b/apps/probability/calculation/calculation.cpp index 078b7d217..0c7fe0c26 100644 --- a/apps/probability/calculation/calculation.cpp +++ b/apps/probability/calculation/calculation.cpp @@ -14,6 +14,10 @@ void Calculation::setLaw(Law * law) { compute(0); } +int Calculation::numberOfEditableParameters() { + return numberOfParameters(); +} + float Calculation::lowerBound() { return -INFINITY; } diff --git a/apps/probability/calculation/calculation.h b/apps/probability/calculation/calculation.h index 32c0b24fa..55e0aaf7d 100644 --- a/apps/probability/calculation/calculation.h +++ b/apps/probability/calculation/calculation.h @@ -10,13 +10,15 @@ public: enum class Type : uint8_t{ LeftIntegral, FiniteIntegral, - RightIntegral + RightIntegral, + Discrete, }; Calculation(); virtual ~Calculation() = default; virtual Type type() = 0; void setLaw(Law * law); virtual int numberOfParameters() = 0; + virtual int numberOfEditableParameters(); virtual I18n::Message legendForParameterAtIndex(int index) = 0; virtual void setParameterAtIndex(float f, int index) = 0; virtual float parameterAtIndex(int index) = 0; diff --git a/apps/probability/calculation/discrete_calculation.cpp b/apps/probability/calculation/discrete_calculation.cpp new file mode 100644 index 000000000..4c5f1db4a --- /dev/null +++ b/apps/probability/calculation/discrete_calculation.cpp @@ -0,0 +1,69 @@ +#include "discrete_calculation.h" +#include +#include +#include + +namespace Probability { + +DiscreteCalculation::DiscreteCalculation() : + Calculation(), + m_abscissa(0.0f), + m_result(0.0f) +{ + compute(0); +} + +Calculation::Type DiscreteCalculation::type() { + return Type::Discrete; +} + +int DiscreteCalculation::numberOfParameters() { + return 2; +} + +int DiscreteCalculation::numberOfEditableParameters() { + return 1; +} + +I18n::Message DiscreteCalculation::legendForParameterAtIndex(int index) { + assert(index >= 0 && index < 2); + if (index == 0) { + return I18n::Message::DiscreteLegend; + } + return I18n::Message::LeftIntegralSecondLegend; +} + +void DiscreteCalculation::setParameterAtIndex(float f, int index) { + assert(index == 0); + float rf = roundf(f); + m_abscissa = rf; + compute(index); +} + + +float DiscreteCalculation::parameterAtIndex(int index) { + assert(index >= 0 && index < 2); + if (index == 0) { + return m_abscissa; + } + return m_result; +} + +float DiscreteCalculation::lowerBound() { + return m_abscissa; +} + +float DiscreteCalculation::upperBound() { + return m_abscissa; +} + +void DiscreteCalculation::compute(int indexKnownElement) { + if (m_law == nullptr) { + return; + } + m_result = m_law->evaluateAtAbscissa(m_abscissa); + /* Results in probability application are rounder to 3 decimals */ + m_result = roundf(m_result/k_precision)*k_precision; +} + +} diff --git a/apps/probability/calculation/discrete_calculation.h b/apps/probability/calculation/discrete_calculation.h new file mode 100644 index 000000000..2aecf649b --- /dev/null +++ b/apps/probability/calculation/discrete_calculation.h @@ -0,0 +1,27 @@ +#ifndef PROBABILITE_DISCRETE_CALCULATION_H +#define PROBABILITE_DISCRETE_CALCULATION_H + +#include "calculation.h" + +namespace Probability { + +class DiscreteCalculation : public Calculation { +public: + DiscreteCalculation(); + Type type() override; + int numberOfParameters() override; + int numberOfEditableParameters() override; + I18n::Message legendForParameterAtIndex(int index) override; + void setParameterAtIndex(float f, int index) override; + float parameterAtIndex(int index) override; + float lowerBound() override; + float upperBound() override; +private: + void compute(int indexKnownElement) override; + float m_abscissa; + float m_result; +}; + +} + +#endif diff --git a/apps/probability/calculation/finite_integral_calculation.cpp b/apps/probability/calculation/finite_integral_calculation.cpp index 1f7e3779e..faffc59a4 100644 --- a/apps/probability/calculation/finite_integral_calculation.cpp +++ b/apps/probability/calculation/finite_integral_calculation.cpp @@ -22,6 +22,10 @@ int FiniteIntegralCalculation::numberOfParameters() { return 3; } +int FiniteIntegralCalculation::numberOfEditableParameters() { + return 2; +} + I18n::Message FiniteIntegralCalculation::legendForParameterAtIndex(int index) { assert(index >= 0 && index < 3); if (index == 0) { diff --git a/apps/probability/calculation/finite_integral_calculation.h b/apps/probability/calculation/finite_integral_calculation.h index 6e5b84200..2357cba95 100644 --- a/apps/probability/calculation/finite_integral_calculation.h +++ b/apps/probability/calculation/finite_integral_calculation.h @@ -10,6 +10,7 @@ public: FiniteIntegralCalculation(); Type type() override; int numberOfParameters() override; + int numberOfEditableParameters() override; I18n::Message legendForParameterAtIndex(int index) override; void setParameterAtIndex(float f, int index) override; float parameterAtIndex(int index) override; diff --git a/apps/probability/calculation_controller.cpp b/apps/probability/calculation_controller.cpp index 3dbf356dc..f1f1b5ecb 100644 --- a/apps/probability/calculation_controller.cpp +++ b/apps/probability/calculation_controller.cpp @@ -2,6 +2,7 @@ #include "../constant.h" #include "../apps_container.h" #include "app.h" +#include "calculation/discrete_calculation.h" #include "calculation/left_integral_calculation.h" #include "calculation/right_integral_calculation.h" #include "calculation/finite_integral_calculation.h" @@ -15,7 +16,7 @@ namespace Probability { CalculationController::ContentView::ContentView(Responder * parentResponder, CalculationController * calculationController, Calculation * calculation, Law * law) : m_titleView(KDText::FontSize::Small, I18n::Message::ComputeProbability, 0.5f, 0.5f, Palette::GreyDark, Palette::WallScreen), m_lawCurveView(law, calculation), - m_imageTableView(parentResponder, calculation, calculationController), + m_imageTableView(parentResponder, law, calculation, calculationController), m_draftTextBuffer{}, m_calculation(calculation) { @@ -102,6 +103,9 @@ void CalculationController::ContentView::layoutSubviews() { void CalculationController::ContentView::drawRect(KDContext * ctx, KDRect rect) const { KDCoordinate titleHeight = KDText::stringSize("", KDText::FontSize::Small).height()+k_titleHeightMargin; ctx->fillRect(KDRect(0,titleHeight, bounds().width(), ImageTableView::k_oneCellWidth), KDColorWhite); + if (m_calculation->numberOfEditableParameters() == 0) { + return; + } KDSize charSize = KDText::stringSize(" "); KDCoordinate xCoordinate = ImageTableView::k_oneCellWidth + k_textWidthMargin; KDCoordinate numberOfCharacters = strlen(I18n::translate(m_calculation->legendForParameterAtIndex(0))); @@ -109,6 +113,9 @@ void CalculationController::ContentView::drawRect(KDContext * ctx, KDRect rect) ctx->drawRect(KDRect(xCoordinate-ImageTableView::k_outline, titleHeight+ImageTableView::k_margin, k_textFieldWidth+ImageTableView::k_outline, ImageCell::k_height+ImageTableView::k_outline), Palette::GreyMiddle); + if (m_calculation->numberOfEditableParameters() < 2) { + return; + } xCoordinate += k_textFieldWidth + k_textWidthMargin; numberOfCharacters = strlen(I18n::translate(m_calculation->legendForParameterAtIndex(1))); xCoordinate += numberOfCharacters*charSize.width() + k_textWidthMargin; @@ -167,6 +174,9 @@ void CalculationController::setCalculationAccordingToIndex(int index, bool force case 2: new(m_calculation) RightIntegralCalculation(); break; + case 3: + new(m_calculation) DiscreteCalculation(); + break; default: return; } @@ -174,7 +184,7 @@ void CalculationController::setCalculationAccordingToIndex(int index, bool force } bool CalculationController::handleEvent(Ion::Events::Event event) { - if ((event == Ion::Events::Left && m_highlightedSubviewIndex > 0) || (event == Ion::Events::Right && m_highlightedSubviewIndex < ContentView::k_maxNumberOfEditableFields - 1)) { + if ((event == Ion::Events::Left && m_highlightedSubviewIndex > 0) || (event == Ion::Events::Right && m_highlightedSubviewIndex < m_calculation->numberOfEditableParameters())) { if (m_highlightedSubviewIndex == 0) { m_contentView.imageTableView()->select(false); m_contentView.imageTableView()->setHighlight(false); @@ -202,7 +212,7 @@ bool CalculationController::handleEvent(Ion::Events::Event event) { } bool CalculationController::textFieldShouldFinishEditing(TextField * textField, Ion::Events::Event event) { - return (event == Ion::Events::Right && m_highlightedSubviewIndex < ContentView::k_maxNumberOfEditableFields - 1) || event == Ion::Events::Left || TextFieldDelegate::textFieldShouldFinishEditing(textField, event); + return (event == Ion::Events::Right && m_highlightedSubviewIndex < m_calculation->numberOfEditableParameters()) || event == Ion::Events::Left || TextFieldDelegate::textFieldShouldFinishEditing(textField, event); } bool CalculationController::textFieldDidFinishEditing(TextField * textField, const char * text, Ion::Events::Event event) { diff --git a/apps/probability/calculation_controller.h b/apps/probability/calculation_controller.h index 7cb69cf73..12a3c7d21 100644 --- a/apps/probability/calculation_controller.h +++ b/apps/probability/calculation_controller.h @@ -38,8 +38,8 @@ private: ImageTableView * imageTableView(); EditableTextCell * calculationCellAtIndex(int index); void willDisplayEditableCellAtIndex(int index); - constexpr static int k_maxNumberOfEditableFields = 3; private: + constexpr static int k_maxNumberOfEditableFields = 3; constexpr static KDCoordinate k_textFieldWidth = 50; constexpr static KDCoordinate k_textWidthMargin = 5; constexpr static KDCoordinate k_titleHeightMargin = 5; diff --git a/apps/probability/image_table_view.cpp b/apps/probability/image_table_view.cpp index e01797f80..b612adafb 100644 --- a/apps/probability/image_table_view.cpp +++ b/apps/probability/image_table_view.cpp @@ -4,9 +4,11 @@ #include "images/calcul1_icon.h" #include "images/calcul2_icon.h" #include "images/calcul3_icon.h" +#include "images/calcul4_icon.h" #include "images/focused_calcul1_icon.h" #include "images/focused_calcul2_icon.h" #include "images/focused_calcul3_icon.h" +#include "images/focused_calcul4_icon.h" namespace Probability { @@ -42,11 +44,12 @@ void ImageCell::setImage(const Image * image, const Image * focusedImage) { m_focusedIcon = focusedImage; } -ImageTableView::ImageTableView(Responder * parentResponder, Calculation * calculation, CalculationController * calculationController) : +ImageTableView::ImageTableView(Responder * parentResponder, Law * law, Calculation * calculation, CalculationController * calculationController) : View(), Responder(parentResponder), m_selectableTableView(this, this, 0, 0, 0, 0, 0, 0, this, nullptr, false, false), m_isSelected(false), + m_law(law), m_calculation(calculation), m_calculationController(calculationController) { @@ -58,7 +61,7 @@ void ImageTableView::drawRect(KDContext * ctx, KDRect rect) const { } KDSize ImageTableView::minimalSizeForOptimalDisplay() const { - return KDSize(2*k_totalMargin+ImageCell::k_width, k_totalMargin+3*ImageCell::k_height); + return KDSize(2*k_totalMargin+ImageCell::k_width, k_totalMargin+k_numberOfImages*ImageCell::k_height); } void ImageTableView::didBecomeFirstResponder() { @@ -110,6 +113,9 @@ void ImageTableView::setHighlight(bool highlight) { int ImageTableView::numberOfRows() { if (m_isSelected) { + if (m_law->isContinuous()) { + return k_numberOfImages-1; + } return k_numberOfImages; } return 1; @@ -127,8 +133,8 @@ int ImageTableView::reusableCellCount() { void ImageTableView::willDisplayCellForIndex(HighlightCell * cell, int index) { ImageCell * myCell = (ImageCell *)cell; - const Image * images[3] = {ImageStore::Calcul1Icon, ImageStore::Calcul2Icon, ImageStore::Calcul3Icon}; - const Image * focusedImages[3] = {ImageStore::FocusedCalcul1Icon, ImageStore::FocusedCalcul2Icon, ImageStore::FocusedCalcul3Icon}; + const Image * images[k_numberOfImages] = {ImageStore::Calcul1Icon, ImageStore::Calcul2Icon, ImageStore::Calcul3Icon, ImageStore::Calcul4Icon}; + const Image * focusedImages[k_numberOfImages] = {ImageStore::FocusedCalcul1Icon, ImageStore::FocusedCalcul2Icon, ImageStore::FocusedCalcul3Icon, ImageStore::FocusedCalcul4Icon}; if (!m_isSelected) { myCell->setImage(images[(int)m_calculation->type()], focusedImages[(int)m_calculation->type()]); } else { diff --git a/apps/probability/image_table_view.h b/apps/probability/image_table_view.h index 7cc16e103..2266eb004 100644 --- a/apps/probability/image_table_view.h +++ b/apps/probability/image_table_view.h @@ -26,7 +26,7 @@ private: class ImageTableView : public View, public Responder, public SimpleListViewDataSource, public SelectableTableViewDataSource { public: - ImageTableView(Responder * parentResponder, Calculation * calculation, CalculationController * calculationController); + ImageTableView(Responder * parentResponder, Law * law, Calculation * calculation, CalculationController * calculationController); void drawRect(KDContext * ctx, KDRect rect) const override; KDSize minimalSizeForOptimalDisplay() const override; bool handleEvent(Ion::Events::Event event) override; @@ -49,11 +49,12 @@ private: View * subviewAtIndex(int index) override; void layoutSubviews() override; void setCalculationAccordingToIndex(int index); - constexpr static int k_numberOfImages = 3; + constexpr static int k_numberOfImages = 4; ImageCell m_imageCells[k_numberOfImages]; SelectableTableView m_selectableTableView; bool m_isSelected; int m_selectedIcon; + Law * m_law; Calculation * m_calculation; CalculationController * m_calculationController; }; diff --git a/apps/probability/images/calcul4_icon.png b/apps/probability/images/calcul4_icon.png new file mode 100644 index 000000000..8040f094f Binary files /dev/null and b/apps/probability/images/calcul4_icon.png differ diff --git a/apps/probability/images/focused_calcul4_icon.png b/apps/probability/images/focused_calcul4_icon.png new file mode 100644 index 000000000..a5e40e24e Binary files /dev/null and b/apps/probability/images/focused_calcul4_icon.png differ