From c647bfe566b635e71867d0e9a4ab39afa4920518 Mon Sep 17 00:00:00 2001 From: Gabriel Ozouf Date: Thu, 15 Oct 2020 16:53:54 +0200 Subject: [PATCH] [poincare/zoom] Clean up and comment API Change-Id: I58347d7188551471817fb334bcb54d5c5b398f72 --- poincare/include/poincare/zoom.h | 12 +++- poincare/src/zoom.cpp | 114 +++++++++++++++---------------- 2 files changed, 67 insertions(+), 59 deletions(-) diff --git a/poincare/include/poincare/zoom.h b/poincare/include/poincare/zoom.h index bd3fb9bca..18995fe27 100644 --- a/poincare/include/poincare/zoom.h +++ b/poincare/include/poincare/zoom.h @@ -16,14 +16,22 @@ public: typedef float (*ValueAtAbscissa)(float abscissa, Context * context, const void * auxiliary); - /* Return false if the X range was given a default value because there were - * no points of interest. */ + /* Find the most suitable window to display the function's points of + * interest. 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); + /* Find the best Y range to display the function on [xMin, xMax], but crop + * the values that are outside of the function's order of magnitude. */ static void RefinedYRangeForDisplay(ValueAtAbscissa evaluation, float xMin, float xMax, float * yMin, float * yMax, Context * context, const void * auxiliary); + /* Find the best window to display functions, with a specified ratio + * between X and Y. Usually used to find the most fitting orthonormal range. */ static void RangeWithRatioForDisplay(ValueAtAbscissa evaluation, float yxRatio, float * xMin, float * xMax, float * yMin, float * yMax, Context * context, const void * auxiliary); static void FullRange(ValueAtAbscissa evaluation, float tMin, float tMax, float tStep, float * fMin, float * fMax, Context * context, const void * auxiliary); + /* Find the bounding box of the given ranges. */ static void CombineRanges(int length, const float * mins, const float * maxs, float * minRes, float * maxRes); + /* Ensures that the window is fit for display, with all bounds being proper + * numbers, with min < max. */ static void SanitizeRange(float * xMin, float * xMax, float * yMin, float * yMax, float normalRatio); /* If shrink is false, the range will be set to ratio by increasing the size diff --git a/poincare/src/zoom.cpp b/poincare/src/zoom.cpp index cb17dc509..98ec28c67 100644 --- a/poincare/src/zoom.cpp +++ b/poincare/src/zoom.cpp @@ -215,6 +215,63 @@ void Zoom::RefinedYRangeForDisplay(ValueAtAbscissa evaluation, float xMin, float } } +void Zoom::RangeWithRatioForDisplay(ValueAtAbscissa evaluation, float yxRatio, float * xMin, float * xMax, float * yMin, float * yMax, Context * context, const void * auxiliary) { + constexpr float units[] = {k_smallUnitMantissa, k_mediumUnitMantissa, k_largeUnitMantissa}; + constexpr float rangeMagnitudeWeight = 0.2f; + constexpr float maxMagnitudeDifference = 2.f; + + float bestGrade = FLT_MAX; + float xMagnitude = k_minimalDistance; + float yMinRange = FLT_MAX, yMaxRange = -FLT_MAX; + while (xMagnitude < k_maximalDistance) { + for(const float unit : units) { + const float xRange = unit * xMagnitude; + RefinedYRangeForDisplay(evaluation, -xRange, xRange, &yMinRange, &yMaxRange, context, auxiliary); + float currentRatio = (yMaxRange - yMinRange) / (2 * xRange); + float grade = std::fabs(std::log(currentRatio / yxRatio)); + /* When in doubt, favor ranges between [-1, 1] and [-10, 10] */ + grade += std::fabs(std::log(xRange / 10.f) * std::log(xRange)) * rangeMagnitudeWeight; + if (std::fabs(std::log(currentRatio / yxRatio)) < maxMagnitudeDifference && grade < bestGrade) { + bestGrade = grade; + *xMin = -xRange; + *xMax = xRange; + *yMin = yMinRange; + *yMax = yMaxRange; + } + } + xMagnitude *= 10.f; + } + if (bestGrade == FLT_MAX) { + *xMin = NAN; + *xMax = NAN; + *yMin = NAN; + *yMax = NAN; + return; + } + + SetToRatio(yxRatio, xMin, xMax, yMin, yMax); +} + +void Zoom::FullRange(ValueAtAbscissa evaluation, float tMin, float tMax, float tStep, float * fMin, float * fMax, Context * context, const void * auxiliary) { + float t = tMin; + *fMin = FLT_MAX; + *fMax = -FLT_MAX; + while (t <= tMax) { + float value = evaluation(t, context, auxiliary); + if (value < *fMin) { + *fMin = value; + } + if (value > *fMax) { + *fMax = value; + } + t += tStep; + } + if (*fMin > *fMax) { + *fMin = NAN; + *fMax = NAN; + } +} + void Zoom::CombineRanges(int length, const float * mins, const float * maxs, float * minRes, float * maxRes) { ValueAtAbscissa evaluation = [](float x, Context * context, const void * auxiliary) { int index = std::round(x); @@ -288,63 +345,6 @@ 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 float units[] = {k_smallUnitMantissa, k_mediumUnitMantissa, k_largeUnitMantissa}; - constexpr float rangeMagnitudeWeight = 0.2f; - constexpr float maxMagnitudeDifference = 2.f; - - float bestGrade = FLT_MAX; - float xMagnitude = k_minimalDistance; - float yMinRange = FLT_MAX, yMaxRange = -FLT_MAX; - while (xMagnitude < k_maximalDistance) { - for(const float unit : units) { - const float xRange = unit * xMagnitude; - RefinedYRangeForDisplay(evaluation, -xRange, xRange, &yMinRange, &yMaxRange, context, auxiliary); - float currentRatio = (yMaxRange - yMinRange) / (2 * xRange); - float grade = std::fabs(std::log(currentRatio / yxRatio)); - /* When in doubt, favor ranges between [-1, 1] and [-10, 10] */ - grade += std::fabs(std::log(xRange / 10.f) * std::log(xRange)) * rangeMagnitudeWeight; - if (std::fabs(std::log(currentRatio / yxRatio)) < maxMagnitudeDifference && grade < bestGrade) { - bestGrade = grade; - *xMin = -xRange; - *xMax = xRange; - *yMin = yMinRange; - *yMax = yMaxRange; - } - } - xMagnitude *= 10.f; - } - if (bestGrade == FLT_MAX) { - *xMin = NAN; - *xMax = NAN; - *yMin = NAN; - *yMax = NAN; - return; - } - - SetToRatio(yxRatio, xMin, xMax, yMin, yMax); -} - -void Zoom::FullRange(ValueAtAbscissa evaluation, float tMin, float tMax, float tStep, float * fMin, float * fMax, Context * context, const void * auxiliary) { - float t = tMin; - *fMin = FLT_MAX; - *fMax = -FLT_MAX; - while (t <= tMax) { - float value = evaluation(t, context, auxiliary); - if (value < *fMin) { - *fMin = value; - } - if (value > *fMax) { - *fMax = value; - } - t += tStep; - } - if (*fMin > *fMax) { - *fMin = NAN; - *fMax = NAN; - } -} - 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;