[Python] Trying to create a great arc using 3 points

Discussão em 'Python' iniciado por Stack, Maio 15, 2025.

  1. Stack

    Stack Membro Participativo

    I am trying to create a program that creates a top-down polar plot of the paths of satellites using 3 points: start azimuth and elevation, maximum azimuth and elevation, and end azimuth and elevation as it passes over the horizon.

    [​IMG]

    Similar to this but from a top-down view.

    Currently, I have been using spherical linear interpolation (SLERP) to create two great arcs from start -> max then max -> end, then connecting them together to create a single arc. However the issue that I'm having is that the arc doesn't look like a normal arc, there is a bump as it approaches the maximum point.

    [​IMG]

    The real graph should be smooth, I have a feeling that using the two SLERP lines is causing this bump. Is there a better equation to create a single, smooth great arc using 3 points that I am just missing?

    import numpy as np
    import matplotlib.pyplot as plt

    def spherical_to_cartesian(az_deg, el_deg, radius=1.0):
    """Convert spherical (azimuth, elevation, radius) to Cartesian coordinates."""
    az = np.radians(az_deg)
    el = np.radians(el_deg)

    x = radius * np.cos(el) * np.sin(az)
    y = radius * np.cos(el) * np.cos(az)
    z = radius * np.sin(el)
    return np.array([x, y, z])

    def slerp(v0, v1, t):
    """Perform spherical linear interpolation between two vectors."""
    v0 = v0 / np.linalg.norm(v0)
    v1 = v1 / np.linalg.norm(v1)
    dot = np.clip(np.dot(v0, v1), -1.0, 1.0)
    omega = np.arccos(dot)

    if np.isclose(omega, 0):
    return v0
    return (np.sin((1 - t) * omega) * v0 + np.sin(t * omega) * v1) / np.sin(omega)

    def interpolate_hemisphere_arc(start_az, start_el, mid_az, mid_el, end_az, end_el, samples=50, radius=1.0):
    """Generate an interpolated arc on the upper hemisphere between three az/el points."""
    start = spherical_to_cartesian(start_az, start_el, radius)
    mid = spherical_to_cartesian(mid_az, mid_el, radius)
    end = spherical_to_cartesian(end_az, end_el, radius)

    path_xy = []

    # Interpolate start → mid
    for t in np.linspace(0, 1, samples // 2 + 1):
    p = slerp(start, mid, t)
    path_xy.append((p[0], p[1]))

    # Interpolate mid → end (skip the duplicate mid point)
    for t in np.linspace(0, 1, samples // 2 + 1)[1:]:
    p = slerp(mid, end, t)
    path_xy.append((p[0], p[1]))

    return path_xy

    if __name__ == "__main__":
    # Test case: plot a single interpolated satellite arc
    path = interpolate_hemisphere_arc(
    start_az=169.67,
    start_el=0,
    mid_az=256.75,
    mid_el=75.92,
    end_az=345.34,
    end_el=0
    )

    xs, ys = zip(*path)
    xs = np.array(xs)
    ys = np.array(ys)

    r = 90 - 90 * np.sqrt(xs**2 + ys**2)
    theta = np.arctan2(xs, ys)

    plt.figure(figsize=(6, 6))
    ax = plt.subplot(111, polar=True)
    ax.plot(theta, r)

    ax.set_theta_zero_location('N')
    ax.set_theta_direction(-1)
    ax.set_title("Top-Down Polar View of Interpolated Satellite Pass")
    ax.set_rlim(90.0, 0.0)

    plt.tight_layout()
    plt.show()

    Continue reading...

Compartilhe esta Página