derek tingle
Initial commit
6062b47
"""Camera angle data structures for Fibo Edit."""
from dataclasses import dataclass
from enum import Enum
class View(Enum):
"""Camera view angles"""
BACK_VIEW = "back view"
BACK_LEFT_QUARTER = "back-left quarter view"
BACK_RIGHT_QUARTER = "back-right quarter view"
FRONT_VIEW = "front view"
FRONT_LEFT_QUARTER = "front-left quarter view"
FRONT_RIGHT_QUARTER = "front-right quarter view"
LEFT_SIDE = "left side view"
RIGHT_SIDE = "right side view"
class Shot(Enum):
"""
Camera shot angles (measured from horizontal/eye-level as 0 degrees)
- ELEVATED: 45-60 degrees above subject (moderately elevated)
- EYE_LEVEL: 0 degrees (horizontal with subject)
- HIGH_ANGLE: 60-90 degrees above subject (steep overhead, bird's eye)
- LOW_ANGLE: Below eye level (looking up at subject)
"""
ELEVATED = "elevated shot"
EYE_LEVEL = "eye-level shot"
HIGH_ANGLE = "high-angle shot"
LOW_ANGLE = "low-angle shot"
class Zoom(Enum):
"""Camera zoom levels"""
CLOSE_UP = "close-up"
MEDIUM = "medium shot"
WIDE = "wide shot"
@dataclass
class AngleInstruction:
view: View
shot: Shot
zoom: Zoom
def __str__(self):
return f"<sks> {self.view.value} {self.shot.value} {self.zoom.value}"
@classmethod
def from_camera_params(cls, rotation: float, tilt: float, zoom: float) -> "AngleInstruction":
"""
Create an AngleInstruction from camera parameters.
Args:
rotation: Horizontal rotation in degrees (-180 to 180)
-180/180: back view, -90: left view, 0: front view, 90: right view
tilt: Vertical tilt (-1 to 1)
-1 to -0.33: low-angle shot
-0.33 to 0.33: eye-level shot
0.33 to 0.66: elevated shot
0.66 to 1: high-angle shot
zoom: Zoom level (0 to 10)
0-3.33: wide shot
3.33-6.66: medium shot
6.66-10: close-up
Returns:
AngleInstruction instance
"""
# Map rotation to View
# Normalize rotation to -180 to 180 range
rotation = rotation % 360
if rotation > 180:
rotation -= 360
# Determine view based on rotation
if -157.5 <= rotation < -112.5:
view = View.BACK_LEFT_QUARTER
elif -112.5 <= rotation < -67.5:
view = View.LEFT_SIDE
elif -67.5 <= rotation < -22.5:
view = View.FRONT_LEFT_QUARTER
elif -22.5 <= rotation < 22.5:
view = View.FRONT_VIEW
elif 22.5 <= rotation < 67.5:
view = View.FRONT_RIGHT_QUARTER
elif 67.5 <= rotation < 112.5:
view = View.RIGHT_SIDE
elif 112.5 <= rotation < 157.5:
view = View.BACK_RIGHT_QUARTER
else: # 157.5 to 180 or -180 to -157.5
view = View.BACK_VIEW
# Map tilt to Shot
if tilt < -0.33:
shot = Shot.LOW_ANGLE
elif tilt < 0.33:
shot = Shot.EYE_LEVEL
elif tilt < 0.66:
shot = Shot.ELEVATED
else:
shot = Shot.HIGH_ANGLE
# Map zoom to Zoom
if zoom < 3.33:
zoom_level = Zoom.WIDE
elif zoom < 6.66:
zoom_level = Zoom.MEDIUM
else:
zoom_level = Zoom.CLOSE_UP
return cls(view=view, shot=shot, zoom=zoom_level)