Merge changes Iaf806c1f,I2c54cb11,Iabf36299,I2e2cf0c7,I21a08f18, ...

* changes:
  [apps] Add a margin around the window when drawing curves
  [apps] Use curve view window in the abstract class curve view
  [apps/statistics] Make data model inherit from curve view window
  [apps/probability] Make the model law inherit from curve view window
  [apps/graph/graph] Make the model graph window inherit from curve view window
  [apps] Create an abstract model curve view window
  [apps/graph/graph] When redrawing the curve, slightly exceed the rect to ensure the continuity of the curve
  [apps/graph/graph] Add a banner view in the graph view
  [apps/graph/graph] Create a class banner view
  [apps/probability] Add a pointer to the data model in the histogram controller
  [apps/probability] Improve data controller to delete pairs of data
  [escher] Add a method in even odd editable text cell to access editable text cell
  [apps/probability] Add method in data model (to delete pairs)
  [escher] Correct syntax error
This commit is contained in:
Émilie Feral
2016-12-27 14:14:59 +01:00
committed by Gerrit
33 changed files with 398 additions and 182 deletions

View File

@@ -9,6 +9,7 @@ app_objs += $(addprefix apps/,\
apps_container.o\
constant.o\
curve_view.o\
curve_view_window.o\
editable_cell_table_view_controller.o\
expression_text_field_delegate.o\
float_parameter_controller.o\

View File

@@ -7,15 +7,38 @@
constexpr KDColor CurveView::k_axisColor;
CurveView::CurveView() :
View()
CurveView::CurveView(CurveViewWindow * curveViewWindow) :
View(),
m_curveViewWindow(curveViewWindow)
{
}
void CurveView::setCurveViewWindow(CurveViewWindow * curveViewWindow) {
m_curveViewWindow = curveViewWindow;
}
void CurveView::reload() {
markRectAsDirty(bounds());
}
float CurveView::min(Axis axis) const {
assert(axis == Axis::Horizontal || axis == Axis::Vertical);
float range = axis == Axis::Horizontal ? m_curveViewWindow->xMax() - m_curveViewWindow->xMin() : m_curveViewWindow->yMax() - m_curveViewWindow->yMin();
float absoluteMin = (axis == Axis::Horizontal ? m_curveViewWindow->xMin(): m_curveViewWindow->yMin());
return absoluteMin - k_marginFactor*range;
}
float CurveView::max(Axis axis) const {
assert(axis == Axis::Horizontal || axis == Axis::Vertical);
float range = axis == Axis::Horizontal ? m_curveViewWindow->xMax() - m_curveViewWindow->xMin() : m_curveViewWindow->yMax() - m_curveViewWindow->yMin();
float absoluteMax = (axis == Axis::Horizontal ? m_curveViewWindow->xMax() : m_curveViewWindow->yMax());
return absoluteMax + k_marginFactor*range;
}
float CurveView::gridUnit(Axis axis) const {
return (axis == Axis::Horizontal ? m_curveViewWindow->xGridUnit() : m_curveViewWindow->yGridUnit());
}
KDCoordinate CurveView::pixelLength(Axis axis) const {
assert(axis == Axis::Horizontal || axis == Axis::Vertical);
return (axis == Axis::Horizontal ? m_frame.width() : m_frame.height());
@@ -131,13 +154,14 @@ const uint8_t stampMask[stampSize+1][stampSize+1] = {
constexpr static int k_maxNumberOfIterations = 10;
constexpr static int k_resolution = 320.0f;
constexpr static int k_externRectMargin = 1;
void CurveView::drawCurve(void * curve, KDColor color, KDContext * ctx, KDRect rect, bool colorUnderCurve, float colorLowerBound, float colorUpperBound, bool continuously) const {
float xMin = min(Axis::Horizontal);
float xMax = max(Axis::Horizontal);
float xStep = (xMax-xMin)/k_resolution;
float rectMin = pixelToFloat(Axis::Horizontal, rect.left());
float rectMax = pixelToFloat(Axis::Horizontal, rect.right());
float rectMin = pixelToFloat(Axis::Horizontal, rect.left() - k_externRectMargin);
float rectMax = pixelToFloat(Axis::Horizontal, rect.right() + k_externRectMargin);
for (float x = rectMin; x < rectMax; x += xStep) {
float y = evaluateCurveAtAbscissa(curve, x);
float pxf = floatToPixel(Axis::Horizontal, x);

View File

@@ -3,6 +3,7 @@
#include <escher.h>
#include <poincare.h>
#include "curve_view_window.h"
class CurveView : public View {
public:
@@ -10,16 +11,19 @@ public:
Horizontal = 0,
Vertical = 1
};
CurveView();
CurveView(CurveViewWindow * curveViewWindow = nullptr);
void reload();
protected:
constexpr static KDColor k_axisColor = KDColor::RGB24(0x000000);
constexpr static KDCoordinate k_labelMargin = 4;
constexpr static int k_maxNumberOfXLabels = 18;
constexpr static int k_maxNumberOfYLabels = 13;
virtual float min(Axis axis) const = 0;
virtual float max(Axis axis) const = 0;
virtual float gridUnit(Axis axis) const = 0;
void setCurveViewWindow(CurveViewWindow * curveViewWindow);
/* The window bounds are deduced from the model bounds but also take into
account a margin (computed with k_marginFactor) */
float min(Axis axis) const;
float max(Axis axis) const;
float gridUnit(Axis axis) const;
virtual char * label(Axis axis, int index) const = 0;
KDCoordinate pixelLength(Axis axis) const;
float pixelToFloat(Axis axis, KDCoordinate p) const;
@@ -32,6 +36,7 @@ protected:
void computeLabels(Axis axis);
void drawLabels(Axis axis, bool shiftOrigin, KDContext * ctx, KDRect rect) const;
private:
constexpr static float k_marginFactor = 0.2f;
int numberOfLabels(Axis axis) const;
virtual float evaluateCurveAtAbscissa(void * curve, float t) const = 0;
/* Recursively join two dots (dichotomy). The method stops when the
@@ -43,6 +48,7 @@ private:
* function shifts the stamp (by blending adjacent pixel colors) to draw with
* anti alising. */
void stampAtLocation(float pxf, float pyf, KDColor color, KDContext * ctx, KDRect rect) const;
CurveViewWindow * m_curveViewWindow;
};
#endif

View File

@@ -0,0 +1,29 @@
#include "curve_view_window.h"
#include <math.h>
#include <float.h>
float CurveViewWindow::yGridUnit() {
return 0.0f;
}
float CurveViewWindow::computeGridUnit(Axis axis) {
int a = 0;
int b = 0;
float d = xMax() - xMin();
float maxNumberOfUnits = k_maxNumberOfXGridUnits;
float minNumberOfUnits = k_minNumberOfXGridUnits;
if (axis == Axis::Y) {
d = yMax() - yMin();
maxNumberOfUnits = k_maxNumberOfYGridUnits;
minNumberOfUnits = k_minNumberOfYGridUnits;
}
float units[3] = {k_oneUnit, k_twoUnit, k_fiveUnit};
for (int k = 0; k < 3; k++) {
float unit = units[k];
if (floorf(log10f(d/(unit*maxNumberOfUnits))) != floorf(log10f(d/(unit*minNumberOfUnits)))) {
b = floorf(log10f(d/(unit*minNumberOfUnits)));
a = unit;
}
}
return a*powf(10,b);
}

27
apps/curve_view_window.h Normal file
View File

@@ -0,0 +1,27 @@
#ifndef APPS_CURVE_VIEW_WINDOW_H
#define APPS_CURVE_VIEW_WINDOW_H
class CurveViewWindow {
public:
enum class Axis {
X,
Y
};
virtual float xMin() = 0;
virtual float xMax() = 0;
virtual float yMin() = 0;
virtual float yMax() = 0;
virtual float xGridUnit() = 0;
virtual float yGridUnit();
protected:
constexpr static float k_minNumberOfXGridUnits = 7.0f;
constexpr static float k_maxNumberOfXGridUnits = 18.0f;
constexpr static float k_minNumberOfYGridUnits = 5.0f;
constexpr static float k_maxNumberOfYGridUnits = 13.0f;
constexpr static float k_oneUnit = 1.0f;
constexpr static float k_twoUnit = 2.0f;
constexpr static float k_fiveUnit = 5.0f;
float computeGridUnit(Axis axis);
};
#endif

View File

@@ -3,6 +3,7 @@ app_objs += $(addprefix apps/graph/,\
function.o\
function_store.o\
function_title_cell.o\
graph/banner_view.o\
graph/graph_window.o\
graph/window_parameter_controller.o\
graph/cursor_view.o\

View File

@@ -0,0 +1,82 @@
#include "banner_view.h"
#include <assert.h>
#include "../../constant.h"
namespace Graph {
BannerView::BannerView() :
m_abscissa(0.0f),
m_function(nullptr),
m_abscissaView(0.0f, 0.5f),
m_functionView(0.5f, 0.5f),
m_derivativeView(1.0f, 0.5f),
m_displayDerivative(false),
m_context(nullptr)
{
}
void BannerView::drawRect(KDContext * ctx, KDRect rect) const {
ctx->fillRect(bounds(), KDColorWhite);
}
void BannerView::setContext(Context * context) {
m_context = context;
}
void BannerView::setAbscissa(float x) {
markRectAsDirty(bounds());
m_abscissa = x;
char buffer[4+Constant::FloatBufferSizeInScientificMode] = {'x', ' ', '=', ' ',0};
Float(x).convertFloatToText(buffer+4, Constant::FloatBufferSizeInScientificMode, Constant::NumberOfDigitsInMantissaInScientificMode);
m_abscissaView.setText(buffer);
}
void BannerView::setFunction(Function * f) {
markRectAsDirty(bounds());
m_function = f;
float y = f->evaluateAtAbscissa(m_abscissa, m_context);
char buffer[8+Constant::FloatBufferSizeInScientificMode] = {0, 0, '(', 'x', ')', ' ', '=', ' ',0};
buffer[1] = f->name()[0];
Float(y).convertFloatToText(buffer+8, Constant::FloatBufferSizeInScientificMode, Constant::NumberOfDigitsInMantissaInScientificMode);
m_functionView.setText(buffer+1);
y = f->approximateDerivative(m_abscissa, m_context);
buffer[0] = f->name()[0];
buffer[1] = '\'';
Float(y).convertFloatToText(buffer+8, Constant::FloatBufferSizeInScientificMode, Constant::NumberOfDigitsInMantissaForDerivativeNumberInScientificMode);
m_derivativeView.setText(buffer);
}
void BannerView::setDisplayDerivative(bool displayDerivative) {
m_displayDerivative = displayDerivative;
}
bool BannerView::displayDerivative() {
return m_displayDerivative;
}
int BannerView::numberOfSubviews() const {
if (m_displayDerivative) {
return 3;
}
return 2;
}
View * BannerView::subviewAtIndex(int index) {
assert(index >= 0);
if (index == 0) {
return &m_abscissaView;
}
if (index == 1) {
return &m_functionView;
}
return &m_derivativeView;
}
void BannerView::layoutSubviews() {
m_abscissaView.setFrame(bounds());
m_functionView.setFrame(bounds());
m_derivativeView.setFrame(bounds());
}
}

View File

@@ -0,0 +1,33 @@
#ifndef GRAPH_BANNER_VIEW_H
#define GRAPH_BANNER_VIEW_H
#include <escher.h>
#include "../function.h"
namespace Graph {
class BannerView : public View {
public:
BannerView();
void drawRect(KDContext * ctx, KDRect rect) const override;
void setContext(Context * context);
void setAbscissa(float x);
void setFunction(Function * f);
void setDisplayDerivative(bool displayDerivative);
bool displayDerivative();
private:
int numberOfSubviews() const override;
View * subviewAtIndex(int index) override;
void layoutSubviews() override;
float m_abscissa;
Function * m_function;
BufferTextView m_abscissaView;
BufferTextView m_functionView;
BufferTextView m_derivativeView;
bool m_displayDerivative;
Context * m_context;
};
}
#endif

View File

@@ -6,7 +6,6 @@ namespace Graph {
CurveParameterController::CurveParameterController(GraphView * graphView) :
ViewController(nullptr),
m_graphView(graphView),
m_displayDerivative(false),
m_function(nullptr),
m_calculationCell(ChevronMenuListCell((char*)"Calculer")),
m_goToCell(ChevronMenuListCell((char*)"Aller a")),
@@ -33,7 +32,7 @@ void CurveParameterController::didBecomeFirstResponder() {
void CurveParameterController::willDisplayCellForIndex(TableViewCell * cell, int index) {
if (cell == &m_derivativeCell) {
SwitchView * switchView = (SwitchView *)m_derivativeCell.accessoryView();
switchView->setState(m_displayDerivative);
switchView->setState(m_graphView->bannerView()->displayDerivative());
}
}
@@ -50,7 +49,7 @@ bool CurveParameterController::handleEvent(Ion::Events::Event event) {
return true;
}
case 2:
m_displayDerivative = !m_displayDerivative;
m_graphView->bannerView()->setDisplayDerivative(!m_graphView->bannerView()->displayDerivative());
m_selectableTableView.reloadData();
return true;
default:
@@ -79,10 +78,6 @@ KDCoordinate CurveParameterController::cellHeight() {
return 35;
}
bool CurveParameterController::displayDerivative() const {
return m_displayDerivative;
}
void CurveParameterController::setFunction(Function * function) {
m_function = function;
}

View File

@@ -20,11 +20,9 @@ public:
TableViewCell * reusableCell(int index) override;
int reusableCellCount() override;
void willDisplayCellForIndex(TableViewCell * cell, int index) override;
bool displayDerivative() const;
void setFunction(Function * function);
private:
GraphView * m_graphView;
bool m_displayDerivative;
Function * m_function;
constexpr static int k_totalNumberOfCells = 3;
ChevronMenuListCell m_calculationCell;

View File

@@ -8,7 +8,7 @@ namespace Graph {
constexpr KDColor GraphView::k_gridColor;
GraphView::GraphView(FunctionStore * functionStore, GraphWindow * graphWindow) :
CurveView(),
CurveView(graphWindow),
m_cursorView(CursorView()),
m_xCursorPosition(-1.0f),
m_yCursorPosition(-1.0f),
@@ -19,17 +19,25 @@ GraphView::GraphView(FunctionStore * functionStore, GraphWindow * graphWindow) :
{
}
BannerView * GraphView::bannerView() {
return &m_bannerView;
}
int GraphView::numberOfSubviews() const {
return 1;
return 2;
};
View * GraphView::subviewAtIndex(int index) {
assert(index == 0);
return &m_cursorView;
assert(index >= 0 && index < 2);
if (index == 0) {
return &m_cursorView;
}
return &m_bannerView;
}
void GraphView::setContext(Context * context) {
m_context = context;
m_bannerView.setContext(context);
}
Context * GraphView::context() const {
@@ -52,10 +60,6 @@ void GraphView::reloadCursor() {
layoutSubviews();
}
float GraphView::gridUnit(Axis axis) const {
return (axis == Axis::Horizontal ? m_graphWindow->xGridUnit() : m_graphWindow->yGridUnit());
}
char * GraphView::label(Axis axis, int index) const {
return (axis == Axis::Horizontal ? (char *)m_xLabels[index] : (char *)m_yLabels[index]);
}
@@ -74,6 +78,7 @@ void GraphView::goToAbscissaOnFunction(float abscissa, Function * function) {
float ordinate = function->evaluateAtAbscissa(abscissa, m_context);
m_graphWindow->centerAxisAround(GraphWindow::Axis::Y, ordinate);
m_yCursorPosition = floatToPixel(Axis::Vertical, ordinate);
updateBannerView(function);
reload();
}
@@ -89,6 +94,7 @@ void GraphView::initCursorPosition() {
float fCenter = firstFunction->evaluateAtAbscissa(center, m_context);
m_xCursorPosition = (bounds().width()-1.0f)/2.0f;
m_yCursorPosition = floatToPixel(Axis::Vertical, fCenter);
updateBannerView(firstFunction);
}
void GraphView::moveCursorHorizontally(KDCoordinate xOffset) {
@@ -102,6 +108,7 @@ void GraphView::moveCursorHorizontally(KDCoordinate xOffset) {
bool windowHasMoved = m_graphWindow->panToMakePointVisible(x, y, xMargin, yMargin);
m_xCursorPosition = floatToPixel(Axis::Horizontal, x);
m_yCursorPosition = floatToPixel(Axis::Vertical, y);
updateBannerView(f);
if (windowHasMoved) {
reload();
} else {
@@ -134,6 +141,7 @@ Function * GraphView::moveCursorVertically(int direction) {
markRectAsDirty(KDRect(KDPoint(roundf(m_xCursorPosition) - k_cursorSize/2, roundf(m_yCursorPosition)- k_cursorSize/2), k_cursorSize, k_cursorSize));
m_xCursorPosition = floatToPixel(Axis::Horizontal, x);
m_yCursorPosition = floatToPixel(Axis::Vertical, nextY);
updateBannerView(nextFunction);
if (windowHasMoved) {
reload();
} else {
@@ -144,10 +152,13 @@ Function * GraphView::moveCursorVertically(int direction) {
void GraphView::layoutSubviews() {
KDRect cursorFrame(roundf(m_xCursorPosition) - k_cursorSize/2, roundf(m_yCursorPosition) - k_cursorSize/2, k_cursorSize, k_cursorSize);
KDRect bannerFrame(KDRect(0, bounds().height()- k_bannerHeight, bounds().width(), k_bannerHeight));
if (!m_visibleCursor) {
cursorFrame = KDRectZero;
bannerFrame = KDRectZero;
}
m_cursorView.setFrame(cursorFrame);
m_bannerView.setFrame(bannerFrame);
}
void GraphView::drawRect(KDContext * ctx, KDRect rect) const {
@@ -184,19 +195,14 @@ void GraphView::drawGrid(KDContext * ctx, KDRect rect) const {
drawGridLines(ctx, rect, Axis::Vertical, m_graphWindow->yGridUnit(), k_gridColor);
}
float GraphView::min(Axis axis) const {
assert(axis == Axis::Horizontal || axis == Axis::Vertical);
return (axis == Axis::Horizontal ? m_graphWindow->xMin() : m_graphWindow->yMin());
}
float GraphView::max(Axis axis) const {
assert(axis == Axis::Horizontal || axis == Axis::Vertical);
return (axis == Axis::Horizontal ? m_graphWindow->xMax() : m_graphWindow->yMax());
}
float GraphView::evaluateCurveAtAbscissa(void * curve, float abscissa) const {
Function * f = (Function *)curve;
return f->evaluateAtAbscissa(abscissa, m_context);
}
void GraphView::updateBannerView(Function * function) {
m_bannerView.setAbscissa(xCursorPosition());
m_bannerView.setFunction(function);
}
}

View File

@@ -2,6 +2,7 @@
#define GRAPH_GRAPH_VIEW_H
#include <escher.h>
#include "banner_view.h"
#include "cursor_view.h"
#include "graph_window.h"
#include "../../curve_view.h"
@@ -14,6 +15,7 @@ namespace Graph {
class GraphView : public CurveView {
public:
GraphView(FunctionStore * functionStore, GraphWindow * graphWindow);
BannerView * bannerView();
void drawRect(KDContext * ctx, KDRect rect) const override;
float xPixelCursorPosition();
@@ -32,18 +34,19 @@ private:
constexpr static KDColor k_gridColor = KDColor::RGB24(0xEEEEEE);
constexpr static KDCoordinate k_cursorSize = 9;
constexpr static float k_cursorMarginToBorder = 6.0f;
constexpr static KDCoordinate k_bannerHeight = 30;
int numberOfSubviews() const override;
View * subviewAtIndex(int index) override;
void layoutSubviews() override;
float min(Axis axis) const override;
float max(Axis axis) const override;
float gridUnit(Axis axis) const override;
char * label(Axis axis, int index) const override;
float evaluateCurveAtAbscissa(void * expression, float abscissa) const override;
void drawGrid(KDContext * ctx, KDRect rect) const;
void drawGridLines(KDContext * ctx, KDRect rect, Axis axis, float step, KDColor color) const;
void updateBannerView(Function * function);
BannerView m_bannerView;
CursorView m_cursorView;
float m_xCursorPosition;

View File

@@ -51,23 +51,23 @@ float GraphWindow::yGridUnit() {
void GraphWindow::setXMin(float xMin) {
m_xMin = xMin;
computeYaxes();
computeGridUnit(Axis::X);
m_xGridUnit = computeGridUnit(Axis::X);
}
void GraphWindow::setXMax(float xMax) {
m_xMax = xMax;
computeYaxes();
computeGridUnit(Axis::X);
m_xGridUnit = computeGridUnit(Axis::X);
}
void GraphWindow::setYMin(float yMin) {
m_yMin = yMin;
computeGridUnit(Axis::Y);
m_yGridUnit = computeGridUnit(Axis::Y);
}
void GraphWindow::setYMax(float yMax) {
m_yMax = yMax;
computeGridUnit(Axis::Y);
m_yGridUnit = computeGridUnit(Axis::Y);
}
void GraphWindow::setYAuto(bool yAuto) {
@@ -104,7 +104,7 @@ bool GraphWindow::computeYaxes() {
m_yMax = max + 1;
}
}
computeGridUnit(Axis::Y);
m_yGridUnit = computeGridUnit(Axis::Y);
return true;
}
@@ -123,11 +123,11 @@ void GraphWindow::zoom(float ratio) {
float yMax = m_yMax;
m_xMin = (xMax+xMin)/2.0f - ratio*fabsf(xMax-xMin);
m_xMax = (xMax+xMin)/2.0f + ratio*fabsf(xMax-xMin);
computeGridUnit(Axis::X);
m_xGridUnit = computeGridUnit(Axis::X);
m_yAuto = false;
m_yMin = (yMax+yMin)/2.0f - ratio*fabsf(yMax-yMin);
m_yMax = (yMax+yMin)/2.0f + ratio*fabsf(yMax-yMin);
computeGridUnit(Axis::Y);
m_yGridUnit = computeGridUnit(Axis::Y);
}
void GraphWindow::centerAxisAround(Axis axis, float position) {
@@ -136,13 +136,13 @@ void GraphWindow::centerAxisAround(Axis axis, float position) {
m_xMin = position - range/2.0f;
m_xMax = position + range/2.0f;
computeYaxes();
computeGridUnit(Axis::X);
m_xGridUnit = computeGridUnit(Axis::X);
} else {
m_yAuto = false;
float range = m_yMax - m_yMin;
m_yMin = position - range/2.0f;
m_yMax = position + range/2.0f;
computeGridUnit(Axis::Y);
m_yGridUnit = computeGridUnit(Axis::Y);
}
}
@@ -151,23 +151,23 @@ void GraphWindow::translateWindow(Direction direction) {
if (direction == Direction::Up) {
m_yMin = m_yMin + m_yGridUnit;
m_yMax = m_yMax + m_yGridUnit;
computeGridUnit(Axis::Y);
m_yGridUnit = computeGridUnit(Axis::Y);
}
if (direction == Direction::Down) {
m_yMin = m_yMin - m_yGridUnit;
m_yMax = m_yMax - m_yGridUnit;
computeGridUnit(Axis::Y);
m_yGridUnit = computeGridUnit(Axis::Y);
}
if (direction == Direction::Left) {
m_xMin = m_xMin - m_xGridUnit;
m_xMax = m_xMax - m_xGridUnit;
computeGridUnit(Axis::X);
m_xGridUnit = computeGridUnit(Axis::X);
computeYaxes();
}
if (direction == Direction::Right) {
m_xMin = m_xMin + m_xGridUnit;
m_xMax = m_xMax + m_xGridUnit;
computeGridUnit(Axis::X);
m_xGridUnit = computeGridUnit(Axis::X);
computeYaxes();
}
}
@@ -175,11 +175,11 @@ void GraphWindow::translateWindow(Direction direction) {
void GraphWindow::setTrigonometric() {
m_xMin = -10.5f;
m_xMax = 10.5f;
computeGridUnit(Axis::X);
m_xGridUnit = computeGridUnit(Axis::X);
m_yAuto = false;
m_yMin = -1.6f;
m_yMax = 1.6f;
computeGridUnit(Axis::Y);
m_yGridUnit = computeGridUnit(Axis::Y);
}
void GraphWindow::roundAbscissa() {
@@ -187,7 +187,7 @@ void GraphWindow::roundAbscissa() {
float xMax = m_xMax;
m_xMin = roundf((xMin+xMax)/2) - 160.0f;
m_xMax = roundf((xMin+xMax)/2) + 159.0f;
computeGridUnit(Axis::X);
m_xGridUnit = computeGridUnit(Axis::X);
computeYaxes();
}
@@ -198,17 +198,17 @@ void GraphWindow::normalize() {
float yMax = m_yMax;
m_xMin = (xMin+xMax)/2 - 5.3f;
m_xMax = (xMin+xMax)/2 + 5.3f;
computeGridUnit(Axis::X);
m_xGridUnit = computeGridUnit(Axis::X);
m_yAuto = false;
m_yMin = (yMin+yMax)/2 - 3.1f;
m_yMax = (yMin+yMax)/2 + 3.1f;
computeGridUnit(Axis::Y);
m_yGridUnit = computeGridUnit(Axis::Y);
}
void GraphWindow::setDefault() {
m_xMin = -10.0f;
m_xMax = 10.0f;
computeGridUnit(Axis::X);
m_xGridUnit = computeGridUnit(Axis::X);
setYAuto(true);
}
@@ -219,56 +219,30 @@ bool GraphWindow::panToMakePointVisible(float x, float y, float xMargin, float y
if (x < m_xMin + xMargin) {
m_xMin = x - xMargin;
m_xMax = m_xMin + xRange;
computeGridUnit(Axis::X);
m_xGridUnit = computeGridUnit(Axis::X);
computeYaxes();
windowMoved = true;
}
if (x > m_xMax - xMargin) {
m_xMax = x + xMargin;
m_xMin = m_xMax - xRange;
computeGridUnit(Axis::X);
m_xGridUnit = computeGridUnit(Axis::X);
computeYaxes();
windowMoved = true;
}
if (y < m_yMin + yMargin) {
m_yMin = y - yMargin;
m_yMax = m_yMin + yRange;
computeGridUnit(Axis::Y);
m_yGridUnit = computeGridUnit(Axis::Y);
windowMoved = true;
}
if (y > m_yMax - yMargin) {
m_yMax = y + yMargin;
m_yMin = m_yMax - yRange;
computeGridUnit(Axis::Y);
m_yGridUnit = computeGridUnit(Axis::Y);
windowMoved = true;
}
return windowMoved;
}
void GraphWindow::computeGridUnit(Axis axis) {
int a = 0;
int b = 0;
float d = m_xMax - m_xMin;
float maxNumberOfUnits = k_maxNumberOfXGridUnits;
float minNumberOfUnits = k_minNumberOfXGridUnits;
if (axis == Axis::Y) {
d = m_yMax - m_yMin;
maxNumberOfUnits = k_maxNumberOfYGridUnits;
minNumberOfUnits = k_minNumberOfYGridUnits;
}
float units[3] = {k_oneUnit, k_twoUnit, k_fiveUnit};
for (int k = 0; k < 3; k++) {
float unit = units[k];
if (floorf(log10f(d/(unit*maxNumberOfUnits))) != floorf(log10f(d/(unit*minNumberOfUnits)))) {
b = floorf(log10f(d/(unit*minNumberOfUnits)));
a = unit;
}
}
if (axis == Axis::X) {
m_xGridUnit = a*powf(10,b);
} else {
m_yGridUnit = a*powf(10,b);
}
}
}

View File

@@ -2,15 +2,12 @@
#define GRAPH_GRAPH_AXIS_INTERVAL_H
#include "../function_store.h"
#include "../../curve_view_window.h"
namespace Graph {
class GraphWindow {
class GraphWindow : public CurveViewWindow {
public:
enum class Axis {
X,
Y
};
enum class Direction {
Up,
Left,
@@ -18,13 +15,13 @@ public:
Right
};
GraphWindow(FunctionStore * functionStore);
float xMin();
float xMax();
float yMin();
float yMax();
float xMin() override;
float xMax() override;
float yMin() override;
float yMax() override;
bool yAuto();
float xGridUnit();
float yGridUnit();
float xGridUnit() override;
float yGridUnit() override;
void setXMin(float f);
void setXMax(float f);
void setYMin(float f);
@@ -44,14 +41,6 @@ public:
void setDefault();
bool panToMakePointVisible(float x, float y, float xMargin, float yMargin);
private:
constexpr static float k_minNumberOfXGridUnits = 7.0f;
constexpr static float k_maxNumberOfXGridUnits = 18.0f;
constexpr static float k_minNumberOfYGridUnits = 5.0f;
constexpr static float k_maxNumberOfYGridUnits = 13.0f;
constexpr static float k_oneUnit = 1.0f;
constexpr static float k_twoUnit = 2.0f;
constexpr static float k_fiveUnit = 5.0f;
void computeGridUnit(Axis axis);
float m_xMin;
float m_xMax;
float m_yMin;

View File

@@ -48,17 +48,12 @@ float BinomialLaw::xMax() {
}
float BinomialLaw::yMin() {
int maxAbscissa = m_parameter2 < 1.0f ? (m_parameter1+1)*m_parameter2 : m_parameter1;
float result = k_minMarginFactor*evaluateAtAbscissa(maxAbscissa);
if (result >= 0.0f || isnan(result)) {
result = k_minMarginFactor;
}
return result;
return 0.0f;
}
float BinomialLaw::yMax() {
int maxAbscissa = m_parameter2 < 1.0f ? (m_parameter1+1)*m_parameter2 : m_parameter1;
float result = k_maxMarginFactor*evaluateAtAbscissa(maxAbscissa);
float result = evaluateAtAbscissa(maxAbscissa);
if (result <= 0.0f || result == yMin() || isnan(result)) {
result = yMin() + 1.0f;
}

View File

@@ -42,11 +42,11 @@ float ExponentialLaw::xMax() {
}
float ExponentialLaw::yMin() {
return k_minMarginFactor*m_parameter1;
return 0.0f;
}
float ExponentialLaw::yMax() {
return k_maxMarginFactor*m_parameter1;
return m_parameter1;
}
float ExponentialLaw::evaluateAtAbscissa(float x) const {

View File

@@ -4,19 +4,8 @@
namespace Probability {
float Law::gridUnit() {
int a = 0;
int b = 0;
float d = xMax() - xMin();
float units[3] = {k_oneUnit, k_twoUnit, k_fiveUnit};
for (int k = 0; k < 3; k++) {
float unit = units[k];
if (floorf(log10f(d/(unit*k_maxNumberOfXGridUnits))) != floorf(log10f(d/(unit*k_minNumberOfXGridUnits)))) {
b = floorf(log10f(d/(unit*k_minNumberOfXGridUnits)));
a = unit;
}
}
return a*powf(10,b);
float Law::xGridUnit() {
return computeGridUnit(Axis::X);
}
float Law::cumulativeDistributiveFunctionAtAbscissa(float x) const {

View File

@@ -2,10 +2,11 @@
#define PROBABILITE_LAW_H
#include <poincare.h>
#include "../../curve_view_window.h"
namespace Probability {
class Law {
class Law : public CurveViewWindow {
public:
enum class Type : uint8_t{
Binomial,
@@ -18,11 +19,7 @@ public:
virtual const char * title() = 0;
virtual Type type() const = 0;
virtual bool isContinuous() const = 0;
virtual float xMin() = 0;
virtual float yMin() = 0;
virtual float xMax() = 0;
virtual float yMax() = 0;
float gridUnit();
float xGridUnit() override;
virtual int numberOfParameter() = 0;
virtual float parameterValueAtIndex(int index) = 0;
virtual const char * parameterNameAtIndex(int index) = 0;
@@ -36,13 +33,6 @@ public:
virtual float cumulativeDistributiveInverseForProbability(float * probability);
virtual float rightIntegralInverseForProbability(float * probability);
protected:
constexpr static float k_minNumberOfXGridUnits = 7.0f;
constexpr static float k_maxNumberOfXGridUnits = 18.0f;
constexpr static float k_oneUnit = 1.0f;
constexpr static float k_twoUnit = 2.0f;
constexpr static float k_fiveUnit = 5.0f;
constexpr static float k_minMarginFactor = -0.2f;
constexpr static float k_maxMarginFactor = 1.2f;
constexpr static int k_maxNumberOfOperations = 1000000;
};

View File

@@ -55,17 +55,12 @@ float NormalLaw::xMax() {
}
float NormalLaw::yMin() {
float maxAbscissa = m_parameter1;
float result = k_minMarginFactor*evaluateAtAbscissa(maxAbscissa);
if (result >= 0.0f) {
result = k_minMarginFactor;
}
return result;
return 0.0f;
}
float NormalLaw::yMax() {
float maxAbscissa = m_parameter1;
float result = k_maxMarginFactor*evaluateAtAbscissa(maxAbscissa);
float result = evaluateAtAbscissa(maxAbscissa);
if (result <= 0.0f || result == yMin()) {
result = yMin() + 1.0f;
}

View File

@@ -32,7 +32,7 @@ const char * PoissonLaw::parameterDefinitionAtIndex(int index) {
}
float PoissonLaw::xMin() {
return -1.0f;
return 0.0f;
}
float PoissonLaw::xMax() {
@@ -41,13 +41,12 @@ float PoissonLaw::xMax() {
}
float PoissonLaw::yMin() {
int maxAbscissa = (int)m_parameter1;
return k_minMarginFactor*evaluateAtAbscissa(maxAbscissa);
return 0.0f;
}
float PoissonLaw::yMax() {
int maxAbscissa = (int)m_parameter1;
return k_maxMarginFactor*evaluateAtAbscissa(maxAbscissa);
return evaluateAtAbscissa(maxAbscissa);
}
float PoissonLaw::evaluateAtAbscissa(float x) const {

View File

@@ -48,11 +48,11 @@ float UniformLaw::xMax() {
}
float UniformLaw::yMin() {
return k_minMarginFactor*(1.0f/(m_parameter2-m_parameter1));
return 0.0f;
}
float UniformLaw::yMax() {
return k_maxMarginFactor*(1.0f/(m_parameter2-m_parameter1));
return (1.0f/(m_parameter2-m_parameter1));
}
float UniformLaw::evaluateAtAbscissa(float t) const {

View File

@@ -12,6 +12,7 @@ LawCurveView::LawCurveView() :
}
void LawCurveView::setLaw(Law * law) {
setCurveViewWindow(law);
m_law = law;
}
@@ -45,21 +46,6 @@ void LawCurveView::drawRect(KDContext * ctx, KDRect rect) const {
}
}
float LawCurveView::min(Axis axis) const {
assert(axis == Axis::Horizontal || axis == Axis::Vertical);
return (axis == Axis::Horizontal ? m_law->xMin() : m_law->yMin());
}
float LawCurveView::max(Axis axis) const {
assert(axis == Axis::Horizontal || axis == Axis::Vertical);
return (axis == Axis::Horizontal ? m_law->xMax() : m_law->yMax());
}
float LawCurveView::gridUnit(Axis axis) const {
assert(axis == Axis::Horizontal);
return m_law->gridUnit();
}
char * LawCurveView::label(Axis axis, int index) const {
assert(axis == Axis::Horizontal);
return (char *)m_labels[index];

View File

@@ -18,9 +18,6 @@ public:
void reload();
void drawRect(KDContext * ctx, KDRect rect) const override;
protected:
float min(Axis axis) const override;
float max(Axis axis) const override;
float gridUnit(Axis axis) const override;
char * label(Axis axis, int index) const override;
private:
char m_labels[k_maxNumberOfXLabels][Constant::FloatBufferSizeInScientificMode];

View File

@@ -12,7 +12,7 @@ App::App(Container * container) :
m_boxController(BoxController(&m_boxAlternateEmptyViewController)),
m_boxAlternateEmptyViewController(AlternateEmptyViewController(nullptr, &m_boxController, &m_boxController)),
m_boxStackViewController(StackViewController(&m_tabViewController, &m_boxAlternateEmptyViewController)),
m_histogramController(HistogramController(&m_histogramHeader, &m_histogramHeader)),
m_histogramController(HistogramController(&m_histogramHeader, &m_histogramHeader, &m_data)),
m_histogramHeader(HeaderViewController(&m_histogramAlternateEmptyViewController, &m_histogramController, &m_histogramController)),
m_histogramAlternateEmptyViewController(AlternateEmptyViewController(nullptr, &m_histogramHeader, &m_histogramController)),
m_histogramStackViewController(StackViewController(&m_tabViewController, &m_histogramAlternateEmptyViewController)),

View File

@@ -1,4 +1,5 @@
#include "data.h"
#include <float.h>
namespace Statistics {
@@ -22,7 +23,7 @@ int Data::sizeAtIndex(int index) {
void Data::setValueAtIndex(float value, int index) {
m_values[index] = value;
if (index >= m_numberOfPairs) {
m_sizes[index] = 0;
m_sizes[index] = 1;
m_numberOfPairs++;
}
}
@@ -35,4 +36,66 @@ void Data::setSizeAtIndex(int size, int index) {
}
}
void Data::deletePairAtIndex(int index) {
m_numberOfPairs--;
for (int k = index; k < m_numberOfPairs; k++) {
m_values[k] = m_values[k+1];
m_sizes[k] = m_sizes[k+1];
}
m_values[m_numberOfPairs] = 0.0f;
m_sizes[m_numberOfPairs] = 1;
}
int Data::sizeOfValuesBetweenBounds(float lowerBound, float upperBound) const {
int result = 0;
for (int k = 0; k < m_numberOfPairs; k++) {
if (m_values[k] < upperBound && lowerBound <= m_values[k]) {
result += m_sizes[k];
}
}
return result;
}
float Data::xMin() {
float valueMin = FLT_MAX;
for (int k = 0; k < m_numberOfPairs; k++) {
if (m_values[k] < valueMin) {
valueMin = m_values[k];
}
}
return valueMin;
}
float Data::xMax() {
float valueMax = -FLT_MAX;
for (int k = 0; k < m_numberOfPairs; k++) {
if (m_values[k] > valueMax) {
valueMax = m_values[k];
}
}
float valueMin = xMin();
if (valueMax - valueMin > k_maxRangeValue) {
valueMax = valueMin + 10.0f;
}
return valueMax;
}
float Data::yMin() {
return 0.0f;
}
float Data::yMax() {
float sizeMax = -FLT_MAX;
for (int k = 0; k < m_numberOfPairs; k++) {
if (m_sizes[k] > sizeMax) {
sizeMax = m_sizes[k];
}
}
return sizeMax;
}
float Data::xGridUnit() {
return computeGridUnit(Axis::X);
}
}

View File

@@ -1,9 +1,11 @@
#ifndef STATISTICS_DATA_H
#define STATISTICS_DATA_H
#include "../curve_view_window.h"
namespace Statistics {
class Data {
class Data : public CurveViewWindow {
public:
Data();
// Delete the implicit copy constructor: the object is heavy
@@ -13,9 +15,18 @@ public:
int sizeAtIndex(int index);
void setValueAtIndex(float value, int index);
void setSizeAtIndex(int size, int index);
void deletePairAtIndex(int index);
int sizeOfValuesBetweenBounds(float lowerBound, float upperBound) const;
float xMin() override;
// if the range of value is to wide, value max returns valueMin + 10
float xMax() override;
float yMin() override;
float yMax() override;
float xGridUnit() override;
// TODO: decide the max number of elements after optimization
constexpr static int k_maxNumberOfPairs = 500;
private:
constexpr static int k_maxRangeValue = 320;
int m_sizes[k_maxNumberOfPairs];
float m_values[k_maxNumberOfPairs];
int m_numberOfPairs;

View File

@@ -79,6 +79,18 @@ bool DataController::handleEvent(Ion::Events::Event event) {
app()->setFirstResponder(tabController());
return true;
}
if (event == Ion::Events::Clear) {
if (m_selectableTableView.selectedColumn() == 0) {
m_data->deletePairAtIndex(m_selectableTableView.selectedRow()-1);
m_selectableTableView.reloadData();
} else {
m_data->setSizeAtIndex(1, m_selectableTableView.selectedRow()-1);
EvenOddEditableTextCell * myCell = (EvenOddEditableTextCell *)m_selectableTableView.cellAtLocation(m_selectableTableView.selectedColumn(), m_selectableTableView.selectedRow());
willDisplayCellAtLocation(myCell, m_selectableTableView.selectedColumn(), m_selectableTableView.selectedRow());
myCell->editableTextCell()->textField()->handleEvent(Ion::Events::OK);
}
return true;
}
return false;
}

View File

@@ -2,12 +2,13 @@
namespace Statistics {
HistogramController::HistogramController(Responder * parentResponder, HeaderViewController * headerViewController) :
HistogramController::HistogramController(Responder * parentResponder, HeaderViewController * headerViewController, Data * data) :
ViewController(parentResponder),
HeaderViewDelegate(headerViewController),
m_view(SolidColorView(KDColorGreen)),
m_settingButton(Button(this, "Reglages de l'histogramme",Invocation([](void * context, void * sender) {}, this))),
m_selectedBin(0)
m_selectedBin(0),
m_data(data)
{
}
@@ -49,11 +50,14 @@ Button * HistogramController::buttonAtIndex(int index) {
}
bool HistogramController::isEmpty() {
if (m_data->numberOfPairs() == 0) {
return true;
}
return false;
}
const char * HistogramController::emptyMessage() {
return "Aucune donnée à tracer";
return "Aucune donnee à tracer";
}
Responder * HistogramController::defaultController() {

View File

@@ -2,13 +2,14 @@
#define STATISTICS_HISTOGRAM_CONTROLLER_H
#include <escher.h>
#include "data.h"
namespace Statistics {
class HistogramController : public ViewController, public HeaderViewDelegate, public AlternateEmptyViewDelegate {
public:
HistogramController(Responder * parentResponder, HeaderViewController * headerViewController);
HistogramController(Responder * parentResponder, HeaderViewController * headerViewController, Data * m_data);
const char * title() const override;
View * view() override;
bool handleEvent(Ion::Events::Event event) override;
@@ -24,6 +25,7 @@ private:
SolidColorView m_view;
Button m_settingButton;
int m_selectedBin;
Data * m_data;
};
}

View File

@@ -10,7 +10,7 @@ class EditableTextCell : public TableViewCell, public Responder {
public:
EditableTextCell(Responder * parentResponder, TextFieldDelegate * delegate, char * draftTextBuffer,
float horizontalAlignment = 0.0f, float verticalAlignment = 0.5f, KDColor textColor = KDColorBlack, KDColor = KDColorWhite);
TextField * textfield();
TextField * textField();
void reloadCell() override;
const char * text() const;
void setText(const char * textContent);

View File

@@ -8,6 +8,7 @@
class EvenOddEditableTextCell : public EvenOddCell, public Responder {
public:
EvenOddEditableTextCell(Responder * parentResponder, TextFieldDelegate * delegate, char * draftTextBuffer);
EditableTextCell * editableTextCell();
void reloadCell() override;
const char * text() const;
void setText(const char * textContent);

View File

@@ -11,7 +11,7 @@ EditableTextCell::EditableTextCell(Responder * parentResponder, TextFieldDelegat
{
}
TextField * EditableTextCell::textfield() {
TextField * EditableTextCell::textField() {
return &m_textField;
}

View File

@@ -9,9 +9,13 @@ EvenOddEditableTextCell::EvenOddEditableTextCell(Responder * parentResponder, Te
{
}
EditableTextCell * EvenOddEditableTextCell::editableTextCell() {
return &m_editableCell;
}
void EvenOddEditableTextCell::reloadCell() {
EvenOddCell::reloadCell();
m_editableCell.textfield()->setBackgroundColor(backgroundColor());
m_editableCell.textField()->setBackgroundColor(backgroundColor());
}
const char * EvenOddEditableTextCell::text() const {