From 9b2e39f2cf38ac9a44ad257c3ebc7c9969fb6d5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Fri, 9 Dec 2016 14:25:19 +0100 Subject: [PATCH] [apps/graph/graph] Add methods to the graph window model Change-Id: I3361b76c87a79d0f997e51ad62c7687b2ac313e5 --- apps/curve_view.h | 6 +- .../graph/graph/goto_parameter_controller.cpp | 2 +- apps/graph/graph/graph_controller.cpp | 26 +--- apps/graph/graph/graph_view.cpp | 65 +++----- apps/graph/graph/graph_view.h | 6 +- apps/graph/graph/graph_window.cpp | 139 +++++++++++++++++- apps/graph/graph/graph_window.h | 18 +++ .../initialisation_parameter_controller.cpp | 24 +-- .../graph/graph/zoom_parameter_controller.cpp | 27 +--- 9 files changed, 195 insertions(+), 118 deletions(-) diff --git a/apps/curve_view.h b/apps/curve_view.h index da275248a..00968c7ec 100644 --- a/apps/curve_view.h +++ b/apps/curve_view.h @@ -6,13 +6,13 @@ class CurveView : public View { public: - CurveView(); - void reload(); -protected: enum class Axis { Horizontal = 0, Vertical = 1 }; + CurveView(); + void reload(); +protected: constexpr static KDColor k_axisColor = KDColor::RGB24(0x000000); constexpr static KDCoordinate k_labelMargin = 4; constexpr static int k_maxNumberOfXLabels = 18; diff --git a/apps/graph/graph/goto_parameter_controller.cpp b/apps/graph/graph/goto_parameter_controller.cpp index edf281143..e5a6ed10d 100644 --- a/apps/graph/graph/goto_parameter_controller.cpp +++ b/apps/graph/graph/goto_parameter_controller.cpp @@ -27,7 +27,7 @@ float GoToParameterController::parameterAtIndex(int index) { void GoToParameterController::setParameterAtIndex(int parameterIndex, float f) { assert(parameterIndex == 0); - m_graphView->setXCursorPosition(f, m_function); + m_graphView->goToAbscissaOnFunction(f, m_function); } int GoToParameterController::numberOfRows() { diff --git a/apps/graph/graph/graph_controller.cpp b/apps/graph/graph/graph_controller.cpp index 7ab6f98e6..7b1113fe5 100644 --- a/apps/graph/graph/graph_controller.cpp +++ b/apps/graph/graph/graph_controller.cpp @@ -114,7 +114,7 @@ void GraphController::didBecomeFirstResponder() { headerViewController()->setSelectedButton(-1); m_headerSelected = false; - m_view.setVisibleCursor(true); + m_view.setCursorVisible(true); // Layout view whe the graph view that might have been modified by the zoom page headerViewController()->layoutView(); // Reload graph view @@ -127,7 +127,7 @@ bool GraphController::handleEvent(Ion::Events::Event event) { headerViewController()->setSelectedButton(-1); m_headerSelected = false; app()->setFirstResponder(this); - m_view.setVisibleCursor(true); + m_view.setCursorVisible(true); return true; } if (event == Ion::Events::Up) { @@ -137,29 +137,13 @@ bool GraphController::handleEvent(Ion::Events::Event event) { return headerViewController()->handleEvent(event); } else { if (event == Ion::Events::Plus) { - float xMin = m_graphWindow.xMin(); - float xMax = m_graphWindow.xMax(); - float yMin = m_graphWindow.yMin(); - float yMax = m_graphWindow.yMax(); - m_graphWindow.setXMin((xMax+xMin)/2.0f - fabsf(xMax-xMin)/3.0f); - m_graphWindow.setXMax((xMax+xMin)/2.0f + fabsf(xMax-xMin)/3.0f); - m_graphWindow.setYAuto(false); - m_graphWindow.setYMin((yMax+yMin)/2.0f - fabsf(yMax-yMin)/3.0f); - m_graphWindow.setYMax((yMax+yMin)/2.0f + fabsf(yMax-yMin)/3.0f); + m_graphWindow.zoom(1.0f/3.0f); m_view.initCursorPosition(); m_view.reload(); return true; } if (event == Ion::Events::Minus) { - float xMin = m_graphWindow.xMin(); - float xMax = m_graphWindow.xMax(); - float yMin = m_graphWindow.yMin(); - float yMax = m_graphWindow.yMax(); - m_graphWindow.setXMin((xMax+xMin)/2.0f - 3.0f*fabsf(xMax-xMin)/4.0f); - m_graphWindow.setXMax((xMax+xMin)/2.0f + 3.0f*fabsf(xMax-xMin)/4.0f); - m_graphWindow.setYAuto(false); - m_graphWindow.setYMin((yMax+yMin)/2.0f - 3.0f*fabsf(yMax-yMin)/4.0f); - m_graphWindow.setYMax((yMax+yMin)/2.0f + 3.0f*fabsf(yMax-yMin)/4.0f); + m_graphWindow.zoom(3.0f/4.0f); m_view.initCursorPosition(); m_view.reload(); return true; @@ -176,7 +160,7 @@ bool GraphController::handleEvent(Ion::Events::Event event) { Function * f = m_view.moveCursorUp(); if (f == nullptr) { m_view.initCursorPosition(); - m_view.setVisibleCursor(false); + m_view.setCursorVisible(false); headerViewController()->setSelectedButton(0); m_headerSelected = true; } diff --git a/apps/graph/graph/graph_view.cpp b/apps/graph/graph/graph_view.cpp index 82eeae890..1a51969ce 100644 --- a/apps/graph/graph/graph_view.cpp +++ b/apps/graph/graph/graph_view.cpp @@ -63,21 +63,16 @@ float GraphView::xCursorPosition() { return min(Axis::Horizontal) + m_xCursorPosition*(max(Axis::Horizontal)-min(Axis::Horizontal))/pixelLength(Axis::Horizontal); } -void GraphView::setXCursorPosition(float xPosition, Function * function) { - float xRange = max(Axis::Horizontal) - min(Axis::Horizontal); - float yRange = max(Axis::Horizontal) - min(Axis::Horizontal); - m_graphWindow->setXMin(xPosition - xRange/2.0f); - m_graphWindow->setXMax(xPosition + xRange/2.0f); - m_xCursorPosition = floatToPixel(Axis::Horizontal, xPosition); - float yPosition = function->evaluateAtAbscissa(xPosition, m_evaluateContext); - m_graphWindow->setYAuto(false); - m_graphWindow->setYMin(yPosition - yRange/2.0f); - m_graphWindow->setYMax(yPosition + yRange/2.0f); - m_yCursorPosition = floatToPixel(Axis::Vertical, yPosition); +void GraphView::goToAbscissaOnFunction(float abscissa, Function * function) { + m_graphWindow->centerAxisAround(GraphWindow::Axis::X, abscissa); + m_xCursorPosition = floatToPixel(Axis::Horizontal, abscissa); + float ordinate = function->evaluateAtAbscissa(abscissa, m_evaluateContext); + m_graphWindow->centerAxisAround(GraphWindow::Axis::Y, ordinate); + m_yCursorPosition = floatToPixel(Axis::Vertical, ordinate); reload(); } -void GraphView::setVisibleCursor(bool visibleCursor) { +void GraphView::setCursorVisible(bool visibleCursor) { m_visibleCursor = visibleCursor; layoutSubviews(); } @@ -92,35 +87,15 @@ void GraphView::initCursorPosition() { } void GraphView::moveCursorHorizontally(KDCoordinate xOffset) { - bool outsideWindow = m_xCursorPosition < 0 || m_xCursorPosition > bounds().width() || m_yCursorPosition < 0 || m_yCursorPosition > bounds().height(); m_xCursorPosition = m_xCursorPosition + xOffset; - if (!outsideWindow && m_xCursorPosition < k_cursorMarginToBorder) { - float xRange = max(Axis::Horizontal) - min(Axis::Horizontal); - m_graphWindow->setXMin(pixelToFloat(Axis::Horizontal, floorf(m_xCursorPosition)-k_cursorMarginToBorder)); - m_graphWindow->setXMax(min(Axis::Horizontal) + xRange); - m_xCursorPosition = m_xCursorPosition - floorf(m_xCursorPosition) + k_cursorMarginToBorder; - } - if (!outsideWindow && m_xCursorPosition > bounds().width() - k_cursorMarginToBorder) { - float xRange = max(Axis::Horizontal) - min(Axis::Horizontal); - m_graphWindow->setXMax(pixelToFloat(Axis::Horizontal, ceilf(m_xCursorPosition)+k_cursorMarginToBorder)); - m_graphWindow->setXMin(max(Axis::Horizontal) - xRange); - m_xCursorPosition = bounds().width() - k_cursorMarginToBorder - ceilf(m_xCursorPosition) + m_xCursorPosition; - } + float x = pixelToFloat(Axis::Horizontal, m_xCursorPosition); Function * f = m_functionStore->activeFunctionAtIndex(m_indexFunctionSelectedByCursor); - float ordinate = f->evaluateAtAbscissa(pixelToFloat(Axis::Horizontal, m_xCursorPosition), m_evaluateContext); - m_yCursorPosition = floatToPixel(Axis::Vertical, ordinate); - if (!outsideWindow && m_yCursorPosition < k_cursorMarginToBorder) { - float yRange = max(Axis::Vertical) - min(Axis::Vertical); - m_graphWindow->setYMax(pixelToFloat(Axis::Vertical, floorf(m_yCursorPosition)-k_cursorMarginToBorder)); - m_graphWindow->setYMin(max(Axis::Vertical) - yRange); - m_yCursorPosition = m_yCursorPosition - floorf(m_yCursorPosition) + k_cursorMarginToBorder; - } - if (!outsideWindow && m_yCursorPosition > bounds().height() - k_cursorMarginToBorder) { - float yRange = max(Axis::Vertical) - min(Axis::Vertical); - m_graphWindow->setYMin(pixelToFloat(Axis::Vertical, ceilf(m_yCursorPosition)+k_cursorMarginToBorder)); - m_graphWindow->setYMax(min(Axis::Vertical) + yRange); - m_yCursorPosition = bounds().height() - k_cursorMarginToBorder - ceilf(m_yCursorPosition) + m_yCursorPosition; - } + float y = f->evaluateAtAbscissa(x, m_evaluateContext); + float xMargin = pixelToFloat(Axis::Horizontal, k_cursorMarginToBorder) - pixelToFloat(Axis::Horizontal, 0); + float yMargin = pixelToFloat(Axis::Vertical, 0) - pixelToFloat(Axis::Vertical, k_cursorMarginToBorder); + m_graphWindow->panToMakePointVisible(x, y, xMargin, yMargin); + m_xCursorPosition = floatToPixel(Axis::Horizontal, x); + m_yCursorPosition = floatToPixel(Axis::Vertical, y); reload(); } @@ -142,8 +117,12 @@ Function * GraphView::moveCursorUp() { if (nextFunction == actualFunction) { return nullptr; } + float xMargin = pixelToFloat(Axis::Horizontal, k_cursorMarginToBorder) - pixelToFloat(Axis::Horizontal, 0); + float yMargin = pixelToFloat(Axis::Vertical, 0) - pixelToFloat(Axis::Vertical, k_cursorMarginToBorder); + m_graphWindow->panToMakePointVisible(x, nextY, xMargin, yMargin); + m_xCursorPosition = floatToPixel(Axis::Horizontal, x); m_yCursorPosition = floatToPixel(Axis::Vertical, nextY); - layoutSubviews(); + reload(); return nextFunction; } @@ -165,8 +144,12 @@ Function * GraphView::moveCursorDown() { if (nextFunction == actualFunction) { return nullptr; } + float xMargin = pixelToFloat(Axis::Horizontal, k_cursorMarginToBorder) - pixelToFloat(Axis::Horizontal, 0); + float yMargin = pixelToFloat(Axis::Vertical, 0) - pixelToFloat(Axis::Vertical, k_cursorMarginToBorder); + m_graphWindow->panToMakePointVisible(x, nextY, xMargin, yMargin); + m_xCursorPosition = floatToPixel(Axis::Horizontal, x); m_yCursorPosition = floatToPixel(Axis::Vertical, nextY); - layoutSubviews(); + reload(); return nextFunction; } diff --git a/apps/graph/graph/graph_view.h b/apps/graph/graph/graph_view.h index 98a45b198..952989ce1 100644 --- a/apps/graph/graph/graph_view.h +++ b/apps/graph/graph/graph_view.h @@ -18,8 +18,8 @@ public: float xPixelCursorPosition(); float xCursorPosition(); - void setXCursorPosition(float xPosition, Function * function); - void setVisibleCursor(bool visibleCursor); + void goToAbscissaOnFunction(float abscissa, Function * function); + void setCursorVisible(bool visibleCursor); void initCursorPosition(); void moveCursorHorizontally(KDCoordinate xOffset); Function * moveCursorUp(); @@ -31,7 +31,7 @@ public: private: constexpr static KDColor k_gridColor = KDColor::RGB24(0xEEEEEE); constexpr static KDCoordinate k_cursorSize = 10; - constexpr static float k_cursorMarginToBorder = 5.0f; + constexpr static float k_cursorMarginToBorder = 6.0f; int numberOfSubviews() const override; View * subviewAtIndex(int index) override; diff --git a/apps/graph/graph/graph_window.cpp b/apps/graph/graph/graph_window.cpp index ec2001ee5..25ec67551 100644 --- a/apps/graph/graph/graph_window.cpp +++ b/apps/graph/graph/graph_window.cpp @@ -104,6 +104,137 @@ void GraphWindow::computeYaxes() { computeYScale(); } +Context * GraphWindow::context() { + return m_evaluateContext; +} + +void GraphWindow::setContext(Context * context) { + m_evaluateContext = (EvaluateContext *)context; +} + +void GraphWindow::zoom(float ratio) { + float xMin = m_xMin; + float xMax = m_xMax; + float yMin = m_yMin; + float yMax = m_yMax; + m_xMin = (xMax+xMin)/2.0f - ratio*fabsf(xMax-xMin); + m_xMax = (xMax+xMin)/2.0f + ratio*fabsf(xMax-xMin); + computeXScale(); + m_yAuto = false; + m_yMin = (yMax+yMin)/2.0f - ratio*fabsf(yMax-yMin); + m_yMax = (yMax+yMin)/2.0f + ratio*fabsf(yMax-yMin); + computeYScale(); +} + +void GraphWindow::centerAxisAround(Axis axis, float position) { + if (axis == Axis::X) { + float range = m_xMax - m_xMin; + m_xMin = position - range/2.0f; + m_xMax = position + range/2.0f; + computeYaxes(); + computeXScale(); + } else { + m_yAuto = false; + float range = m_yMax - m_yMin; + m_yMin = position - range/2.0f; + m_yMax = position + range/2.0f; + computeYScale(); + } +} + +void GraphWindow::translateWindow(Direction direction) { + m_yAuto = false; + if (direction == Direction::Up) { + m_yMin = m_yMin + m_yScale; + m_yMax = m_yMax + m_yScale; + computeYScale(); + } + if (direction == Direction::Down) { + m_yMin = m_yMin - m_yScale; + m_yMax = m_yMax - m_yScale; + computeYScale(); + } + if (direction == Direction::Left) { + m_xMin = m_xMin - m_xScale; + m_xMax = m_xMax - m_xScale; + computeXScale(); + computeYaxes(); + } + if (direction == Direction::Right) { + m_xMin = m_xMin + m_xScale; + m_xMax = m_xMax + m_xScale; + computeXScale(); + computeYaxes(); + } +} + +void GraphWindow::setTrigonometric() { + m_xMin = -10.5f; + m_xMax = 10.5f; + computeXScale(); + m_yAuto = false; + m_yMin = -1.6f; + m_yMax = 1.6f; + computeYScale(); +} + +void GraphWindow::roundAbscissa() { + float xMin = m_xMin; + float xMax = m_xMax; + m_xMin = roundf((xMin+xMax)/2) - 160.0f; + m_xMax = roundf((xMin+xMax)/2) + 159.0f; + computeXScale(); + computeYaxes(); +} + +void GraphWindow::normalize() { + float xMin = m_xMin; + float xMax = m_xMax; + float yMin = m_yMin; + float yMax = m_yMax; + m_xMin = (xMin+xMax)/2 - 5.3f; + m_xMax = (xMin+xMax)/2 + 5.3f; + computeXScale(); + m_yAuto = false; + m_yMin = (yMin+yMax)/2 - 3.1f; + m_yMax = (yMin+yMax)/2 + 3.1f; + computeYScale(); +} + +void GraphWindow::setDefault() { + m_xMin = -10.0f; + m_xMax = 10.0f; + computeXScale(); + setYAuto(true); +} + +void GraphWindow::panToMakePointVisible(float x, float y, float xMargin, float yMargin) { + float xRange = m_xMax - m_xMin; + float yRange = m_yMax - m_yMin; + if (x < m_xMin + xMargin) { + m_xMin = x - xMargin; + m_xMax = m_xMin + xRange; + computeXScale(); + computeYaxes(); + } + if (x > m_xMax - xMargin) { + m_xMax = x + xMargin; + m_xMin = m_xMax - xRange; + computeXScale(); + computeYaxes(); + } + if (y < m_yMin + yMargin) { + m_yMin = y - yMargin; + m_yMax = m_yMin + yRange; + computeYScale(); + } + if (y > m_yMax - yMargin) { + m_yMax = y + yMargin; + m_yMin = m_yMax - yRange; + computeYScale(); + } +} + void GraphWindow::computeXScale() { int a = 0; int b = 0; @@ -142,12 +273,4 @@ void GraphWindow::computeYScale() { m_yScale = a*powf(10,b); } -Context * GraphWindow::context() { - return m_evaluateContext; -} - -void GraphWindow::setContext(Context * context) { - m_evaluateContext = (EvaluateContext *)context; -} - } diff --git a/apps/graph/graph/graph_window.h b/apps/graph/graph/graph_window.h index 7162b59a5..cb3a9a186 100644 --- a/apps/graph/graph/graph_window.h +++ b/apps/graph/graph/graph_window.h @@ -8,6 +8,16 @@ namespace Graph { class GraphWindow { public: + enum class Axis { + X, + Y + }; + enum class Direction { + Up, + Left, + Down, + Right + }; GraphWindow(FunctionStore * functionStore); float xMin(); float xMax(); @@ -26,6 +36,14 @@ public: void computeYaxes(); Context * context(); void setContext(Context * context); + void zoom(float ratio); + void centerAxisAround(Axis axis, float position); + void translateWindow(Direction direction); + void setTrigonometric(); + void roundAbscissa(); + void normalize(); + void setDefault(); + void panToMakePointVisible(float x, float y, float xMargin, float yMargin); private: void computeXScale(); void computeYScale(); diff --git a/apps/graph/graph/initialisation_parameter_controller.cpp b/apps/graph/graph/initialisation_parameter_controller.cpp index 349359681..f0966b7de 100644 --- a/apps/graph/graph/initialisation_parameter_controller.cpp +++ b/apps/graph/graph/initialisation_parameter_controller.cpp @@ -36,36 +36,20 @@ bool InitialisationParameterController::handleEvent(Ion::Events::Event event) { switch (m_selectableTableView.selectedRow()) { case 0: // TODO: if mode == degree, xmin = -600, xmax = 600 - m_graphWindow->setXMin(-10.5f); - m_graphWindow->setXMax(10.5f); - m_graphWindow->setYAuto(false); - m_graphWindow->setYMin(-1.6f); - m_graphWindow->setYMax(1.6f); + m_graphWindow->setTrigonometric(); break; case 1: { - float xMin = m_graphWindow->xMin(); - float xMax =m_graphWindow->xMax(); - m_graphWindow->setXMin(roundf((xMin+xMax)/2) - 160.0f); - m_graphWindow->setXMax(roundf((xMin+xMax)/2) + 159.0f); + m_graphWindow->roundAbscissa(); break; } case 2: { - float xMin = m_graphWindow->xMin(); - float xMax =m_graphWindow->xMax(); - float yMin = m_graphWindow->yMin(); - float yMax =m_graphWindow->yMax(); - m_graphWindow->setXMin((xMin+xMax)/2 - 5.3f); - m_graphWindow->setXMax((xMin+xMax)/2 + 5.3f); - m_graphWindow->setYMin((yMin+yMax)/2 - 3.1f); - m_graphWindow->setYMax((yMin+yMax)/2 + 3.1f); + m_graphWindow->normalize(); break; } case 3: - m_graphWindow->setXMin(-10.0f); - m_graphWindow->setXMax(10.0f); - m_graphWindow->setYAuto(true); + m_graphWindow->setDefault(); break; default: return false; diff --git a/apps/graph/graph/zoom_parameter_controller.cpp b/apps/graph/graph/zoom_parameter_controller.cpp index 4c24aa18f..77dc49a63 100644 --- a/apps/graph/graph/zoom_parameter_controller.cpp +++ b/apps/graph/graph/zoom_parameter_controller.cpp @@ -24,53 +24,38 @@ View * ZoomParameterController::view() { } bool ZoomParameterController::handleEvent(Ion::Events::Event event) { - float xMin = m_graphWindow->xMin(); - float xMax = m_graphWindow->xMax(); - float yMin = m_graphWindow->yMin(); - float yMax = m_graphWindow->yMax(); - m_graphWindow->setYAuto(false); if (event == Ion::Events::Plus) { - m_graphWindow->setXMin((xMax+xMin)/2.0f - fabsf(xMax-xMin)/3.0f); - m_graphWindow->setXMax((xMax+xMin)/2.0f + fabsf(xMax-xMin)/3.0f); - m_graphWindow->setYMin((yMax+yMin)/2.0f - fabsf(yMax-yMin)/3.0f); - m_graphWindow->setYMax((yMax+yMin)/2.0f + fabsf(yMax-yMin)/3.0f); + m_graphWindow->zoom(1.0f/3.0f); m_contentView.graphView()->initCursorPosition(); m_contentView.graphView()->reload(); return true; } if (event == Ion::Events::Minus) { - m_graphWindow->setXMin((xMax+xMin)/2.0f - 3.0f*fabsf(xMax-xMin)/4.0f); - m_graphWindow->setXMax((xMax+xMin)/2.0f + 3.0f*fabsf(xMax-xMin)/4.0f); - m_graphWindow->setYMin((yMax+yMin)/2.0f - 3.0f*fabsf(yMax-yMin)/4.0f); - m_graphWindow->setYMax((yMax+yMin)/2.0f + 3.0f*fabsf(yMax-yMin)/4.0f); + m_graphWindow->zoom(3.0f/4.0f); m_contentView.graphView()->initCursorPosition(); m_contentView.graphView()->reload(); return true; } if (event == Ion::Events::Up) { - m_graphWindow->setYMin(yMin + m_graphWindow->yScale()); - m_graphWindow->setYMax(yMax + m_graphWindow->yScale()); + m_graphWindow->translateWindow(GraphWindow::Direction::Up); m_contentView.graphView()->initCursorPosition(); m_contentView.graphView()->reload(); return true; } if (event == Ion::Events::Down) { - m_graphWindow->setYMin(yMin - m_graphWindow->yScale()); - m_graphWindow->setYMax(yMax - m_graphWindow->yScale()); + m_graphWindow->translateWindow(GraphWindow::Direction::Down); m_contentView.graphView()->initCursorPosition(); m_contentView.graphView()->reload(); return true; } if (event == Ion::Events::Left) { - m_graphWindow->setXMin(xMin - m_graphWindow->xScale()); - m_graphWindow->setXMax(xMax - m_graphWindow->xScale()); + m_graphWindow->translateWindow(GraphWindow::Direction::Left); m_contentView.graphView()->initCursorPosition(); m_contentView.graphView()->reload(); return true; } if (event == Ion::Events::Right) { - m_graphWindow->setXMin(xMin + m_graphWindow->xScale()); - m_graphWindow->setXMax(xMax + m_graphWindow->xScale()); + m_graphWindow->translateWindow(GraphWindow::Direction::Right); m_contentView.graphView()->initCursorPosition(); m_contentView.graphView()->reload(); return true;