evaluateTargetZoom method
Calculates desired target zoom level based on target bounding box area relative to scan window ROI.
Enhanced v3.0: Uses smooth interpolation with velocity limiting and hysteresis band to prevent zoom oscillation.
Implementation
double evaluateTargetZoom({
required Rect targetBoundingBox,
required Rect roiScanWindow,
required Size frameSize,
}) {
if (targetBoundingBox.isEmpty ||
roiScanWindow.isEmpty ||
roiScanWindow.width <= 0) {
// No target detected — slowly zoom back towards minimum
if (_currentZoom > minZoom + 0.1) {
_targetZoom = math.max(minZoom, _currentZoom - 0.05);
_currentZoom = _smoothStep(_currentZoom, _targetZoom, lerpFactor);
_lastZoomChangeTime = DateTime.now();
_stableFrameCount = 0;
_isSettled = false;
}
return _currentZoom;
}
final targetArea = targetBoundingBox.width * targetBoundingBox.height;
final roiArea = roiScanWindow.width * roiScanWindow.height;
if (roiArea <= 0 || targetArea <= 0) return _currentZoom;
final currentRatio = targetArea / roiArea;
// Hysteresis: ignore small area changes within the dead zone
if ((_lastAreaRatio - currentRatio).abs() < hysteresisBand &&
_stableFrameCount > 0) {
_stableFrameCount++;
if (_stableFrameCount >= settlingFrameCount) {
_isSettled = true;
}
return _currentZoom;
}
_lastAreaRatio = currentRatio;
// Calculate desired zoom based on area ratio
if (currentRatio < targetAreaFraction) {
// Target is too small — zoom in
final neededScale =
math.sqrt(targetAreaFraction / math.max(0.01, currentRatio));
_targetZoom = (_currentZoom * neededScale).clamp(minZoom, maxZoom);
} else if (currentRatio > 0.6 && _currentZoom > minZoom) {
// Target fills > 60% of ROI — zoom out
_targetZoom = math.max(minZoom, _currentZoom / 1.15);
} else {
// Target is well-framed — maintain current zoom
_stableFrameCount++;
if (_stableFrameCount >= settlingFrameCount) {
_isSettled = true;
}
return _currentZoom;
}
// Apply velocity limiting
final delta = _targetZoom - _currentZoom;
final clampedDelta = delta.clamp(-maxZoomVelocity, maxZoomVelocity);
final velocityLimitedTarget = _currentZoom + clampedDelta;
// Smooth ease-out interpolation towards target
_currentZoom = _smoothStep(
_currentZoom,
velocityLimitedTarget,
lerpFactor,
);
_lastZoomChangeTime = DateTime.now();
_stableFrameCount = 0;
_isSettled = false;
return _currentZoom;
}