[shared/interactive_curve_view_range] Change normalization tolerance

The loss of significance that occurs when subtracting the bounds of the
axes must be taken into account when asserting whether the range is
orthonormal.
This commit is contained in:
Gabriel Ozouf
2020-12-28 11:37:39 +01:00
committed by EmilieNumworks
parent e09bd0a18c
commit ea4770fc81
2 changed files with 17 additions and 12 deletions

View File

@@ -157,12 +157,8 @@ void InteractiveCurveViewRange::normalize(bool forceChangeY) {
m_yRange.setMin(newYMin, k_lowerMaxFloat, k_upperMaxFloat);
MemoizedCurveViewRange::protectedSetYMax(newYMax, k_lowerMaxFloat, k_upperMaxFloat);
/* When the coordinates reach 10^6, the float type is not precise enough to
* properly normalize. */
// FIXME : Fine a more precise way to filter the edge cases
constexpr float limit = 1e6f;
assert(isOrthonormal() || xMin() < -limit || xMax() > limit || yMin() < -limit || yMax() > limit);
(void) limit; // Silence compilation warning about unused variable.
/* The range should be close to orthonormal, unless it has been clipped because the maximum bounds have been reached. */
assert(isOrthonormal() || xMin() <= - k_lowerMaxFloat || xMax() >= k_lowerMaxFloat || yMin() <= - k_lowerMaxFloat || yMax() >= k_lowerMaxFloat);
setZoomNormalize(isOrthonormal());
}
@@ -281,8 +277,17 @@ void InteractiveCurveViewRange::panToMakePointVisible(float x, float y, float to
}
bool InteractiveCurveViewRange::isOrthonormal(float tolerance) const {
if (tolerance == 0.f) {
float xr = std::fabs(xMin()) > std::fabs(xMax()) ? xMax() / xMin() : xMin() / xMax();
float yr = std::fabs(yMin()) > std::fabs(yMax()) ? yMax() / yMin() : yMin() / yMax();
/* The subtraction x - y induces a loss of significance of -log2(1-x/y)
* bits. Since normalizing requires computing xMax - xMin and yMax - yMin,
* the ratio of the normalized range will deviate from the Normal ratio. We
* add an extra two lost bits to account for loss of precision from other
* sources. */
tolerance = std::pow(2.f, - std::log2(std::min(1.f - xr, 1.f - yr)) - 23.f + 2.f);
}
float ratio = (yMax() - yMin()) / (xMax() - xMin());
float ratioDifference = std::fabs(std::log(ratio / NormalYXRatio()));
return ratioDifference <= tolerance;
return ratio <= NormalYXRatio() + tolerance && ratio >= NormalYXRatio() - tolerance;
}
}

View File

@@ -24,9 +24,9 @@ public:
}
static constexpr float NormalYXRatio() { return NormalizedYHalfRange(1.f) / NormalizedXHalfRange(1.f); }
/* A tolerance of 0.001 is necessary to cover the imprecision with the
* largest ranges, around 10^7 */
bool isOrthonormal(float tolerance = 1e-3f) const;
/* If the tolerance is null, isOrthonormal will adapt the tolerance to take
* the loss of significance when changing the ratio into account. */
bool isOrthonormal(float tolerance = 0.f) const;
void setDelegate(InteractiveCurveViewRangeDelegate * delegate);
uint32_t rangeChecksum() override;
@@ -62,7 +62,7 @@ protected:
constexpr static float k_lowerMaxFloat = 9E+7f;
constexpr static float k_maxRatioPositionRange = 1E5f;
/* The tolerance is chosen to normalize sqrt(x) */
constexpr static float k_orthonormalTolerance = 0.7f;
constexpr static float k_orthonormalTolerance = 0.24f;
static float clipped(float x, bool isMax) { return Range1D::clipped(x, isMax, k_lowerMaxFloat, k_upperMaxFloat); }
/* In normalized settings, we put each axis so that 1cm = 2 units. For now,
* the screen has size 43.2mm * 57.6mm.