diff --git a/poincare/include/poincare/zoom.h b/poincare/include/poincare/zoom.h index 1adb1d425..5b0d445d9 100644 --- a/poincare/include/poincare/zoom.h +++ b/poincare/include/poincare/zoom.h @@ -12,8 +12,11 @@ public: typedef float (*ValueAtAbscissa)(float abscissa, Context * context, const void * auxiliary); - static void InterestingRangesForDisplay(ValueAtAbscissa evaluation, float * xMin, float * xMax, float * yMin, float * yMax, float tMin, float tMax, Context * context, const void * auxiliary); + /* Return false if the X range was given a default value because there were + * no points of interest. */ + static bool InterestingRangesForDisplay(ValueAtAbscissa evaluation, float * xMin, float * xMax, float * yMin, float * yMax, float tMin, float tMax, Context * context, const void * auxiliary); static void RefinedYRangeForDisplay(ValueAtAbscissa evaluation, float xMin, float xMax, float * yMin, float * yMax, Context * context, const void * auxiliary, bool boundByMagnitude = false); + static void RangeWithRatioForDisplay(ValueAtAbscissa evaluation, float yxRatio, float * xMin, float * xMax, float * yMin, float * yMax, Context * context, const void * auxiliary); /* If shrink is false, the range will be set to ratio by increasing the size * of the smallest axis. If it is true, the longest axis will be reduced.*/ diff --git a/poincare/src/zoom.cpp b/poincare/src/zoom.cpp index 2c93223fa..c556db422 100644 --- a/poincare/src/zoom.cpp +++ b/poincare/src/zoom.cpp @@ -17,7 +17,7 @@ constexpr float Zoom::k_defaultHalfRange, Zoom::k_maxRatioBetweenPointsOfInterest; -void Zoom::InterestingRangesForDisplay(ValueAtAbscissa evaluation, float * xMin, float * xMax, float * yMin, float * yMax, float tMin, float tMax, Context * context, const void * auxiliary) { +bool Zoom::InterestingRangesForDisplay(ValueAtAbscissa evaluation, float * xMin, float * xMax, float * yMin, float * yMax, float tMin, float tMax, Context * context, const void * auxiliary) { assert(xMin && xMax && yMin && yMax); const bool hasIntervalOfDefinition = std::isfinite(tMin) && std::isfinite(tMax); @@ -136,6 +136,7 @@ void Zoom::InterestingRangesForDisplay(ValueAtAbscissa evaluation, float * xMin, /* Fallback to default range. */ resultX[0] = - k_defaultHalfRange; resultX[1] = k_defaultHalfRange; + return false; } else { /* Add breathing room around points of interest. */ float xRange = resultX[1] - resultX[0]; @@ -147,6 +148,8 @@ void Zoom::InterestingRangesForDisplay(ValueAtAbscissa evaluation, float * xMin, *yMin = std::min(resultYMin, *yMin); *yMax = std::max(resultYMax, *yMax); + + return true; } void Zoom::RefinedYRangeForDisplay(ValueAtAbscissa evaluation, float xMin, float xMax, float * yMin, float * yMax, Context * context, const void * auxiliary, bool boundByMagnitude) { @@ -222,6 +225,39 @@ void Zoom::SetToRatio(float yxRatio, float * xMin, float * xMax, float * yMin, f *tMin = center - newRange / 2.f; } +void Zoom::RangeWithRatioForDisplay(ValueAtAbscissa evaluation, float yxRatio, float * xMin, float * xMax, float * yMin, float * yMax, Context * context, const void * auxiliary) { + constexpr int searchSpeedUp = 13; + constexpr float rangeMagnitudeWeight = 0.2f; + constexpr float maxMagnitudeDifference = 1.2f; + + const float step = std::pow(k_stepFactor, searchSpeedUp); + float bestGrade = FLT_MAX; + float xRange = k_minimalDistance; + float yMinRange = FLT_MAX, yMaxRange = -FLT_MAX; + while (xRange < k_maximalDistance) { + RefinedYRangeForDisplay(evaluation, -xRange, xRange, &yMinRange, &yMaxRange, context, auxiliary, true); + float currentRatio = (yMaxRange - yMinRange) / (2 * xRange); + float grade = std::fabs(std::log(currentRatio / yxRatio)) + std::fabs(std::log(xRange / 10.f)) * rangeMagnitudeWeight; + if (std::fabs(std::log(currentRatio / yxRatio)) < maxMagnitudeDifference && grade < bestGrade) { + bestGrade = grade; + *xMin = -xRange; + *xMax = xRange; + *yMin = yMinRange; + *yMax = yMaxRange; + } + + xRange *= step; + } + if (bestGrade == FLT_MAX) { + *xMin = -k_defaultHalfRange; + *xMax = k_defaultHalfRange; + RefinedYRangeForDisplay(evaluation, *xMin, *xMax, yMin, yMax, context, auxiliary, true); + return; + } + + SetToRatio(yxRatio, xMin, xMax, yMin, yMax, true); +} + bool Zoom::IsConvexAroundExtremum(ValueAtAbscissa evaluation, float x1, float x2, float x3, float y1, float y2, float y3, Context * context, const void * auxiliary, int iterations) { if (iterations <= 0) { return false;