import numpy as np
import cv2
import torch

def arc_to_mask(xc, yc, a, b, theta, phi1, phi2, H, W, line_width=1):
    """
    Generate a binary mask of an elliptical arc.

    Args:
        xc, yc (float): 椭圆中心
        a, b (float): 长半轴、短半轴 (a >= b)
        theta (float): 椭圆旋转角度（**弧度**，逆时针，相对于 x 轴）
        phi1, phi2 (float): 起始和终止参数角（**弧度**，在 [0, 2π) 内）
        H, W (int): 输出 mask 的高度和宽度
        line_width (int): 弧线宽度（像素）

    Returns:
        mask (Tensor): [H, W], dtype=torch.uint8, 0/255
    """
    # 确保 phi1 -> phi2 是正向（可处理跨 2π 的情况）
    if phi2 < phi1:
        phi2 += 2 * np.pi

    # 生成参数角（足够密集，避免断线）
    num_points = max(int(200 * abs(phi2 - phi1) / (2 * np.pi)), 10)
    phi = np.linspace(phi1, phi2, num_points)

    # 椭圆参数方程（先在未旋转坐标系下计算）
    x_local = a * np.cos(phi)
    y_local = b * np.sin(phi)

    # 应用旋转和平移
    cos_t = np.cos(theta)
    sin_t = np.sin(theta)
    x_rot = x_local * cos_t - y_local * sin_t + xc
    y_rot = x_local * cos_t + y_local * sin_t + yc

    # 转为整数坐标（OpenCV 需要 int32）
    points = np.stack([x_rot, y_rot], axis=1).astype(np.int32)

    # 创建空白图像
    img = np.zeros((H, W), dtype=np.uint8)

    # 绘制折线（antialias=False 更适合 mask）
    cv2.polylines(img, [points], isClosed=False, color=255, thickness=line_width, lineType=cv2.LINE_AA)

    return torch.from_numpy(img).byte()  # [H, W], values: 0 or 255


# 椭圆参数
xc, yc = 100.0, 100.0
a, b = 80.0, 40.0
theta = np.radians(30)      # 30度 → 弧度
phi1 = np.radians(0)        # 从右侧开始
phi2 = np.radians(180)      # 到左侧结束（上半椭圆）

H, W = 200, 200

mask = arc_to_mask(xc, yc, a, b, theta, phi1, phi2, H, W, line_width=2)
# print(mask.shape)  # torch.Size([200, 200])
# print(mask.dtype)  # torch.uint8

# 可视化（调试用）
import matplotlib.pyplot as plt
plt.imshow(mask.numpy(), cmap='gray')
plt.title("Elliptical Arc Mask")
plt.show()
