<?phpnamespace App\Render;/** * A camera for the 2D drawing: a point of the world at the centre of the screen and a scale. The physics never sees it (bodies keep * their own coordinates); the scene asks x() / y() / len() when it draws. zoomTo() glides to a new scale in log space (the same * speed feeling from x1 to x2 as from x8 to x16) with a smooth ease in and out. rebase() keeps an endless zoom bounded. */final class ZoomView{ public float $scale = 1.0; private float $from = 1.0; private float $to = 1.0; private float $time = 0.0; private float $duration = 0.0; private bool $moving = false; public function __construct(public float $cx = 0.0, public float $cy = 0.0, public float $sx = 0.0, public float $sy = 0.0) { } public function reset(float $scale = 1.0): void { $this->scale = $this->from = $this->to = $scale; $this->moving = false; } public function zoomTo(float $target, float $seconds): void { $this->from = $this->scale; $this->to = $target; $this->time = 0.0; $this->duration = max(0.001, $seconds); $this->moving = true; } public function isZooming(): bool { return $this->moving; } public function target(): float { return $this->to; } public function update(float $dt): void { if (!$this->moving) { return; } $this->time += $dt; $k = min(1.0, $this->time / $this->duration); $this->scale = exp(log($this->from) + (log($this->to) - log($this->from)) * self::ease($k)); if ($k >= 1.0) { $this->scale = $this->to; $this->moving = false; } } /** Smooth in and out (cubic). */ public static function ease(float $k): float { $k = max(0.0, min(1.0, $k)); return $k < 0.5 ? 4 * $k ** 3 : 1 - (-2 * $k + 2) ** 3 / 2; } public function x(float $wx): float { return $this->sx + ($wx - $this->cx) * $this->scale; } public function y(float $wy): float { return $this->sy + ($wy - $this->cy) * $this->scale; } public function len(float $l): float { return $l * $this->scale; }}