diff --git a/apps/graph/graph/graph_view.cpp b/apps/graph/graph/graph_view.cpp index ad19d7067..c0d36a186 100644 --- a/apps/graph/graph/graph_view.cpp +++ b/apps/graph/graph/graph_view.cpp @@ -41,9 +41,7 @@ void GraphView::drawRect(KDContext * ctx, KDRect rect) const { float tmin = f->tMin(); float tmax = f->tMax(); - float tstep = (tmax-tmin) / k_graphStepDenominator; - - float tCacheMin, tCacheStep; + float tCacheMin, tCacheStep, tStepNonCartesian; if (type == ContinuousFunction::PlotType::Cartesian) { float rectLeft = pixelToFloat(Axis::Horizontal, rect.left() - k_externRectMargin); /* Here, tCacheMin can depend on rect (and change as the user move) @@ -53,7 +51,8 @@ void GraphView::drawRect(KDContext * ctx, KDRect rect) const { tCacheStep = pixelWidth(); } else { tCacheMin = tmin; - tCacheStep = int(k_graphStepDenominator) * tstep / ContinuousFunctionCache::k_numberOfParametricCacheablePoints; + // Compute tCacheStep and tStepNonCartesian + ContinuousFunctionCache::ComputeNonCartesianSteps(&tStepNonCartesian, &tCacheStep, tmax, tmin); } ContinuousFunctionCache::PrepareForCaching(f.operator->(), cch, tCacheMin, tCacheStep); @@ -80,7 +79,7 @@ void GraphView::drawRect(KDContext * ctx, KDRect rect) const { } } else if (type == Shared::ContinuousFunction::PlotType::Polar) { // Polar - drawPolarCurve(ctx, rect, tmin, tmax, tstep, [](float t, void * model, void * context) { + drawPolarCurve(ctx, rect, tmin, tmax, tStepNonCartesian, [](float t, void * model, void * context) { ContinuousFunction * f = (ContinuousFunction *)model; Poincare::Context * c = (Poincare::Context *)context; return f->evaluateXYAtParameter(t, c); @@ -88,7 +87,7 @@ void GraphView::drawRect(KDContext * ctx, KDRect rect) const { } else { // Parametric assert(type == Shared::ContinuousFunction::PlotType::Parametric); - drawCurve(ctx, rect, tmin, tmax, tstep, [](float t, void * model, void * context) { + drawCurve(ctx, rect, tmin, tmax, tStepNonCartesian, [](float t, void * model, void * context) { ContinuousFunction * f = (ContinuousFunction *)model; Poincare::Context * c = (Poincare::Context *)context; return f->evaluateXYAtParameter(t, c); diff --git a/apps/graph/test/caching.cpp b/apps/graph/test/caching.cpp index 059c7cef3..bef20e35d 100644 --- a/apps/graph/test/caching.cpp +++ b/apps/graph/test/caching.cpp @@ -55,8 +55,11 @@ void assert_check_polar_cache_against_function(ContinuousFunction * function, Co float tMin = range->xMin(); float tMax = range->xMax(); - float tStep = ((tMax - tMin) / Graph::GraphView::k_graphStepDenominator) / ContinuousFunctionCache::k_parametricStepFactor; - ContinuousFunctionCache::PrepareForCaching(function, cache, tMin, tStep); + + float tStep, tCacheStep; + ContinuousFunctionCache::ComputeNonCartesianSteps(&tStep, &tCacheStep, tMax, tMin); + + ContinuousFunctionCache::PrepareForCaching(function, cache, tMin, tCacheStep); // Fill the cache float t; diff --git a/apps/shared/continuous_function_cache.cpp b/apps/shared/continuous_function_cache.cpp index ce43fd312..ad1e0e98c 100644 --- a/apps/shared/continuous_function_cache.cpp +++ b/apps/shared/continuous_function_cache.cpp @@ -7,7 +7,6 @@ namespace Shared { constexpr int ContinuousFunctionCache::k_sizeOfCache; constexpr float ContinuousFunctionCache::k_cacheHitTolerance; constexpr int ContinuousFunctionCache::k_numberOfAvailableCaches; -constexpr int ContinuousFunctionCache::k_numberOfParametricCacheablePoints; // public void ContinuousFunctionCache::PrepareForCaching(void * fun, ContinuousFunctionCache * cache, float tMin, float tStep) { @@ -52,6 +51,26 @@ Poincare::Coordinate2D ContinuousFunctionCache::valueForParameter(const C return valuesAtIndex(function, context, t, resIndex); } +void ContinuousFunctionCache::ComputeNonCartesianSteps(float * tStep, float * tCacheStep, float tMax, float tMin) { + // Expected step length + *tStep = (tMax - tMin) / Graph::GraphView::k_graphStepDenominator; + /* Parametric and polar functions require caching both x and y values, + * with the same k_sizeOfCache. To cover the entire range, + * number of cacheable points is half the cache size. */ + const int numberOfCacheablePoints = k_sizeOfCache / 2; + const int numberOfWholeSteps = static_cast(Graph::GraphView::k_graphStepDenominator); + static_assert(numberOfCacheablePoints % numberOfWholeSteps == 0, "numberOfCacheablePoints should be a multiple of numberOfWholeSteps for optimal caching"); + /* Define cacheStep such that every whole graph steps are equally divided + * For instance, with : + * graphStepDenominator = 10.1 + * numberOfCacheablePoints = 160 + * tMin [----------------|----------------| ... |----------------|**] tMax + * step1 step2 step10 step11 + * There are 11 steps, the first 10 are whole and have an equal size (tStep). + * There are 16 cache points in the first 10 steps, 160 total cache points. */ + *tCacheStep = *tStep * numberOfWholeSteps / numberOfCacheablePoints; +} + // private void ContinuousFunctionCache::invalidateBetween(int iInf, int iSup) { for (int i = iInf; i < iSup; i++) { diff --git a/apps/shared/continuous_function_cache.h b/apps/shared/continuous_function_cache.h index 2d035c34c..4ccf8b015 100644 --- a/apps/shared/continuous_function_cache.h +++ b/apps/shared/continuous_function_cache.h @@ -11,16 +11,8 @@ namespace Shared { class ContinuousFunction; class ContinuousFunctionCache { -private: - /* The size of the cache is chosen to optimize the display of cartesian - * functions */ - static constexpr int k_sizeOfCache = Ion::Display::Width; public: static constexpr int k_numberOfAvailableCaches = 2; - /* Parametric and polar functions require caching both x and y values, - * with the same k_sizeOfCache. To cover the entire range, - * k_numberOfParametricCacheablePoints is halved. */ - static constexpr int k_numberOfParametricCacheablePoints = k_sizeOfCache / 2; static void PrepareForCaching(void * fun, ContinuousFunctionCache * cache, float tMin, float tStep); @@ -29,7 +21,12 @@ public: float step() const { return m_tStep; } void clear(); Poincare::Coordinate2D valueForParameter(const ContinuousFunction * function, Poincare::Context * context, float t); + // Sets step parameters for non-cartesian curves + static void ComputeNonCartesianSteps(float * tStep, float * tCacheStep, float tMax, float tMin); private: + /* The size of the cache is chosen to optimize the display of cartesian + * functions */ + static constexpr int k_sizeOfCache = Ion::Display::Width; /* We need a certain amount of tolerance since we try to evaluate the * equality of floats. But the value has to be chosen carefully. Too high of * a tolerance causes false positives, which lead to errors in curves