from p3dsdk import CameraGroup, Database, Vector3
import ast
import math


def ask_vector3(prompt, default=None):
    while True:
        input_str = input(prompt).strip()
        if input_str == '' and default is not None:
            return default
        try:
            v = ast.literal_eval(input_str)
            return Vector3(*v)
        except (ValueError, TypeError):
            print("Format should be [x, y, z] or (x, y, z)!")


def ask_number(prompt, number_type):
    while True:
        input_str = input(prompt)
        try:
            return number_type(input_str)
        except ValueError:
            print("Enter a %s number!" % number_type)


def spherical_to_cartesian(azimuth: float, elevation: float, radius: float) -> Vector3:
    """azimuth and elevation are in degrees."""
    azimuth_rad = math.radians(azimuth)
    elevation_rad = math.radians(elevation)
    x = radius * math.cos(elevation_rad) * math.cos(azimuth_rad)
    y = radius * math.sin(elevation_rad)
    z = radius * math.cos(elevation_rad) * math.sin(azimuth_rad)
    return Vector3(x, y, z)


def create_cameras(data: Database, group: CameraGroup, target: Vector3,
                   radius: float, elevation: float, steps: int):
    assert steps > 0
    assert radius >= 0
    group_name = group.name if group is not None else "Turntable"
    for i in range(steps):
        azimuth = i * 360.0 / steps  # in degrees
        cam = data.create_camera(group)
        cam.name = "%s_%d" % (group_name, i)
        cam.view_from = spherical_to_cartesian(azimuth, elevation, radius)
        cam.view_to = target
        cam.view_up = (0, 1, 0)


if __name__ == "__main__":
    from p3dsdk import CurrentP3DSession

    with CurrentP3DSession(fallback_port=33900) as p3d:
        # Ask the parameters
        target = ask_vector3("Target point (default [0, 0, 0]): ", Vector3(0, 0, 0))
        radius = ask_number("Radius from target: ", float)
        elevation = ask_number("Elevation (in degrees): ", float)
        steps = ask_number("Number of cameras (steps): ", int)

        # Create the camera group
        group = p3d.data.create_camera_group("Turntable")

        # Create the cameras
        create_cameras(p3d.data, group, target, radius, elevation, steps)
