Numworks Epsilon  1.4.1
Graphing Calculator Operating System
graph_controller.cpp
Go to the documentation of this file.
1 #include "graph_controller.h"
2 #include "../apps_container.h"
3 #include <cmath>
4 
5 using namespace Poincare;
6 using namespace Shared;
7 
8 namespace Regression {
9 
10 GraphController::GraphController(Responder * parentResponder, ButtonRowController * header, Store * store, CurveViewCursor * cursor, uint32_t * modelVersion, uint32_t * rangeVersion, int * selectedDotIndex) :
11  InteractiveCurveViewController(parentResponder, header, store, &m_view, cursor, modelVersion, rangeVersion),
12  m_crossCursorView(),
13  m_roundCursorView(Palette::YellowDark),
14  m_bannerView(),
15  m_view(store, m_cursor, &m_bannerView, &m_crossCursorView),
16  m_store(store),
17  m_initialisationParameterController(this, m_store),
18  m_predictionParameterController(this, m_store, m_cursor, this),
19  m_selectedDotIndex(selectedDotIndex)
20 {
21  m_store->setCursor(m_cursor);
22 }
23 
25  return &m_initialisationParameterController;
26 }
27 
29  if (m_store->numberOfPairs() < 2 || std::isinf(m_store->slope()) || std::isnan(m_store->slope())) {
30  return true;
31  }
32  return false;
33 }
34 
36  if (m_store->numberOfPairs() == 0) {
37  return I18n::Message::NoDataToPlot;
38  }
39  return I18n::Message::NoEnoughDataForRegression;
40 }
41 
43  InteractiveCurveViewController::viewWillAppear();
44  m_view.setCursorView(*m_selectedDotIndex >= 0 ? static_cast<View *>(&m_crossCursorView): static_cast<View *>(&m_roundCursorView));
45 }
46 
48  *m_selectedDotIndex = -1;
49  m_view.setCursorView(&m_roundCursorView);
50 }
51 
52 CurveView * GraphController::curveView() {
53  return &m_view;
54 }
55 
56 InteractiveCurveViewRange * GraphController::interactiveCurveViewRange() {
57  return m_store;
58 }
59 
60 bool GraphController::handleEnter() {
61  stackController()->push(&m_predictionParameterController);
62  return true;
63 }
64 
65 void GraphController::reloadBannerView() {
66  m_bannerView.setMessageAtIndex(I18n::Message::RegressionFormula, 3);
67 
68  char buffer[k_maxNumberOfCharacters + PrintFloat::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits)];
69  int numberOfChar = 0;
70  const char * legend = " P(";
71  int legendLength = strlen(legend);
72  strlcpy(buffer, legend, legendLength+1);
73  numberOfChar += legendLength;
74  if (*m_selectedDotIndex == m_store->numberOfPairs()) {
75  legend = I18n::translate(I18n::Message::MeanDot);
76  legendLength = strlen(legend);
77  strlcpy(buffer+numberOfChar, legend, legendLength+1);
78  numberOfChar += legendLength;
79  } else if (*m_selectedDotIndex < 0) {
80  legend = I18n::translate(I18n::Message::Reg);
81  legendLength = strlen(legend);
82  strlcpy(buffer+numberOfChar, legend, legendLength+1);
83  numberOfChar += legendLength;
84  } else {
85  numberOfChar += PrintFloat::convertFloatToText<float>(std::round((float)*m_selectedDotIndex+1.0f), buffer+numberOfChar, PrintFloat::bufferSizeForFloatsWithPrecision(Constant::ShortNumberOfSignificantDigits), Constant::ShortNumberOfSignificantDigits, PrintFloat::Mode::Decimal);
86  }
87  legend = ") ";
88  legendLength = strlen(legend);
89  strlcpy(buffer+numberOfChar, legend, legendLength+1);
90  buffer[k_maxLegendLength] = 0;
91  m_bannerView.setLegendAtIndex(buffer, 0);
92 
93  numberOfChar = 0;
94  legend = "x=";
95  double x = m_cursor->x();
96  // Display a specific legend if the mean dot is selected
97  if (*m_selectedDotIndex == m_store->numberOfPairs()) {
98  constexpr static char legX[] = {Ion::Charset::XBar, '=', 0};
99  legend = legX;
100  x = m_store->meanOfColumn(0);
101  }
102  legendLength = strlen(legend);
103  strlcpy(buffer, legend, legendLength+1);
104  numberOfChar += legendLength;
105  numberOfChar += PrintFloat::convertFloatToText<double>(x, buffer+numberOfChar, PrintFloat::bufferSizeForFloatsWithPrecision(Constant::MediumNumberOfSignificantDigits), Constant::MediumNumberOfSignificantDigits);
106  legend = " ";
107  legendLength = strlen(legend);
108  strlcpy(buffer+numberOfChar, legend, legendLength+1);
109  buffer[k_maxLegendLength] = 0;
110  m_bannerView.setLegendAtIndex(buffer, 1);
111 
112  numberOfChar = 0;
113  legend = "y=";
114  double y = m_cursor->y();
115  if (*m_selectedDotIndex == m_store->numberOfPairs()) {
116  constexpr static char legY[] = {Ion::Charset::YBar, '=', 0};
117  legend = legY;
118  y = m_store->meanOfColumn(1);
119  }
120  legendLength = strlen(legend);
121  strlcpy(buffer, legend, legendLength+1);
122  numberOfChar += legendLength;
123  numberOfChar += PrintFloat::convertFloatToText<double>(y, buffer+numberOfChar, PrintFloat::bufferSizeForFloatsWithPrecision(Constant::MediumNumberOfSignificantDigits), Constant::MediumNumberOfSignificantDigits);
124  legend = " ";
125  legendLength = strlen(legend);
126  strlcpy(buffer+numberOfChar, legend, legendLength+1);
127  buffer[k_maxLegendLength] = 0;
128  m_bannerView.setLegendAtIndex(buffer, 2);
129 
130  numberOfChar = 0;
131  legend = " a=";
132  double slope = m_store->slope();
133  legendLength = strlen(legend);
134  strlcpy(buffer, legend, legendLength+1);
135  numberOfChar += legendLength;
136  numberOfChar += PrintFloat::convertFloatToText<double>(slope, buffer+numberOfChar, PrintFloat::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits), Constant::LargeNumberOfSignificantDigits);
137  legend = " ";
138  legendLength = strlen(legend);
139  strlcpy(buffer+numberOfChar, legend, legendLength+1);
140  buffer[k_maxLegendLength] = 0;
141  m_bannerView.setLegendAtIndex(buffer, 4);
142 
143  numberOfChar = 0;
144  legend = " b=";
145  double yIntercept = m_store->yIntercept();
146  legendLength = strlen(legend);
147  strlcpy(buffer, legend, legendLength+1);
148  numberOfChar += legendLength;
149  numberOfChar += PrintFloat::convertFloatToText<double>(yIntercept, buffer+numberOfChar, PrintFloat::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits), Constant::LargeNumberOfSignificantDigits);
150  legend = " ";
151  legendLength = strlen(legend);
152  strlcpy(buffer+numberOfChar, legend, legendLength+1);
153  buffer[k_maxLegendLength] = 0;
154  m_bannerView.setLegendAtIndex(buffer, 5);
155 
156  numberOfChar = 0;
157  legend = " r=";
158  double r = m_store->correlationCoefficient();
159  legendLength = strlen(legend);
160  strlcpy(buffer, legend, legendLength+1);
161  numberOfChar += legendLength;
162  numberOfChar += PrintFloat::convertFloatToText<double>(r, buffer+numberOfChar, PrintFloat::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits), Constant::LargeNumberOfSignificantDigits);
163  legend = " ";
164  legendLength = strlen(legend);
165  strlcpy(buffer+numberOfChar, legend, legendLength+1);
166  buffer[k_maxLegendLength+10] = 0;
167  m_bannerView.setLegendAtIndex(buffer, 6);
168 
169  numberOfChar = 0;
170  legend = " r2=";
171  double r2 = m_store->squaredCorrelationCoefficient();
172  legendLength = strlen(legend);
173  strlcpy(buffer, legend, legendLength+1);
174  numberOfChar += legendLength;
175  numberOfChar += PrintFloat::convertFloatToText<double>(r2, buffer+numberOfChar, PrintFloat::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits), Constant::LargeNumberOfSignificantDigits);
176  legend = " ";
177  legendLength = strlen(legend);
178  strlcpy(buffer+numberOfChar, legend, legendLength+1);
179  buffer[k_maxLegendLength] = 0;
180  m_bannerView.setLegendAtIndex(buffer, 7);
181 }
182 
183 void GraphController::initRangeParameters() {
184  m_store->setDefault();
185 }
186 
187 void GraphController::initCursorParameters() {
188  double x = m_store->meanOfColumn(0);
189  double y = m_store->meanOfColumn(1);
190  m_cursor->moveTo(x, y);
191  m_store->panToMakePointVisible(x, y, k_cursorTopMarginRatio, k_cursorRightMarginRatio, k_cursorBottomMarginRatio, k_cursorLeftMarginRatio);
192  *m_selectedDotIndex = m_store->numberOfPairs();
193 }
194 
195 bool GraphController::moveCursorHorizontally(int direction) {
196  if (*m_selectedDotIndex >= 0) {
197  int dotSelected = m_store->nextDot(direction, *m_selectedDotIndex);
198  if (dotSelected >= 0 && dotSelected < m_store->numberOfPairs()) {
199  *m_selectedDotIndex = dotSelected;
200  m_cursor->moveTo(m_store->get(0, *m_selectedDotIndex), m_store->get(1, *m_selectedDotIndex));
201  m_store->panToMakePointVisible(m_cursor->x(), m_cursor->y(), k_cursorTopMarginRatio, k_cursorRightMarginRatio, k_cursorBottomMarginRatio, k_cursorLeftMarginRatio);
202  return true;
203  }
204  if (dotSelected == m_store->numberOfPairs()) {
205  *m_selectedDotIndex = dotSelected;
206  m_cursor->moveTo(m_store->meanOfColumn(0), m_store->meanOfColumn(1));
207  m_store->panToMakePointVisible(m_cursor->x(), m_cursor->y(), k_cursorTopMarginRatio, k_cursorRightMarginRatio, k_cursorBottomMarginRatio, k_cursorLeftMarginRatio);
208  return true;
209  }
210  return false;
211  }
212  double x = direction > 0 ? m_cursor->x() + m_store->xGridUnit()/k_numberOfCursorStepsInGradUnit :
214  double y = m_store->yValueForXValue(x);
215  m_cursor->moveTo(x, y);
216  m_store->panToMakePointVisible(x, y, k_cursorTopMarginRatio, k_cursorRightMarginRatio, k_cursorBottomMarginRatio, k_cursorLeftMarginRatio);
217  return true;
218 }
219 
220 bool GraphController::moveCursorVertically(int direction) {
221  double yRegressionCurve = m_store->yValueForXValue(m_cursor->x());
222  if (*m_selectedDotIndex >= 0) {
223  if ((yRegressionCurve - m_cursor->y() > 0) == (direction > 0)) {
225  m_cursor->moveTo(m_cursor->x(), yRegressionCurve);
226  m_store->panToMakePointVisible(m_cursor->x(), m_cursor->y(), k_cursorTopMarginRatio, k_cursorRightMarginRatio, k_cursorBottomMarginRatio, k_cursorLeftMarginRatio);
227  return true;
228  } else {
229  return false;
230  }
231  } else {
232  int dotSelected = m_store->closestVerticalDot(direction, m_cursor->x());
233  if (dotSelected >= 0 && dotSelected <= m_store->numberOfPairs()) {
234  m_view.setCursorView(&m_crossCursorView);
235  if (dotSelected == m_store->numberOfPairs()) {
236  *m_selectedDotIndex = dotSelected;
237  m_cursor->moveTo(m_store->meanOfColumn(0), m_store->meanOfColumn(1));
238  m_store->panToMakePointVisible(m_cursor->x(), m_cursor->y(), k_cursorTopMarginRatio, k_cursorRightMarginRatio, k_cursorBottomMarginRatio, k_cursorLeftMarginRatio);
239  return true;
240  }
241  *m_selectedDotIndex = dotSelected;
242  m_cursor->moveTo(m_store->get(0, *m_selectedDotIndex), m_store->get(1, *m_selectedDotIndex));
243  m_store->panToMakePointVisible(m_cursor->x(), m_cursor->y(), k_cursorTopMarginRatio, k_cursorRightMarginRatio, k_cursorBottomMarginRatio, k_cursorLeftMarginRatio);
244  return true;
245  }
246  return false;
247  }
248 }
249 
250 uint32_t GraphController::modelVersion() {
251  return m_store->storeChecksum();
252 }
253 
254 uint32_t GraphController::rangeVersion() {
255  return m_store->rangeChecksum();
256 }
257 
258 bool GraphController::isCursorVisible() {
259  return interactiveCurveViewRange()->isCursorVisible(k_cursorTopMarginRatio, k_cursorRightMarginRatio, k_cursorBottomMarginRatio, k_cursorLeftMarginRatio);
260 }
261 
262 }
virtual StackViewController * stackController() const
void setLegendAtIndex(char *text, int index)
Definition: banner_view.cpp:7
double squaredCorrelationCoefficient()
Definition: store.cpp:210
#define isinf(x)
Definition: math.h:44
static constexpr int MediumNumberOfSignificantDigits
Definition: constant.h:7
int closestVerticalDot(int direction, float x)
Definition: store.cpp:19
void push(ViewController *vc, KDColor textColor=Palette::SubTab, KDColor backgroundColor=KDColorWhite, KDColor separatorColor=Palette::GreyBright)
double meanOfColumn(int i)
Definition: store.cpp:162
bool isEmpty() const override
size_t strlcpy(char *dst, const char *src, size_t len)
Definition: strlcpy.c:3
double correlationCoefficient()
Definition: store.cpp:201
void setMessageAtIndex(I18n::Message text, int index)
Definition: banner_view.cpp:18
static constexpr int ShortNumberOfSignificantDigits
Definition: constant.h:8
int nextDot(int direction, int dot)
Definition: store.cpp:51
enum Message uint16_t enum Language uint16_t const char * translate(Message m, Language l=(Language) 0)
Definition: i18n.cpp:5
size_t strlen(const char *s)
Definition: strlen.c:3
unsigned int uint32_t
Definition: stdint.h:6
#define round(x)
Definition: math.h:192
static constexpr int LargeNumberOfSignificantDigits
Definition: constant.h:6
double yIntercept()
Definition: store.cpp:186
double get(int i, int j)
void moveTo(double x, double y)
#define isnan(x)
Definition: math.h:43
bool isCursorVisible(float topMarginRatio, float rightMarginRatio, float bottomMarginRation, float leftMarginRation)
I18n::Message emptyMessage() override
void panToMakePointVisible(float x, float y, float topMarginRatio, float rightMarginRatio, float bottomMarginRation, float leftMarginRation)
ViewController * initialisationParameterController() override
void setDefault() override
Definition: store.cpp:111
void setCursorView(View *cursorView)
Definition: curve_view.cpp:64
double yValueForXValue(double x)
Definition: store.cpp:190
double numberOfPairs()
Definition: store.cpp:122
double slope()
Definition: store.cpp:182
Definition: palette.h:6