[poincare/zoom] Clean up and comment API

Change-Id: I58347d7188551471817fb334bcb54d5c5b398f72
This commit is contained in:
Gabriel Ozouf
2020-10-15 16:53:54 +02:00
committed by Émilie Feral
parent 91e1154bb8
commit c647bfe566
2 changed files with 67 additions and 59 deletions

View File

@@ -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

View File

@@ -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;