def normalize_points(point1, point2):
    """规范化两个点,确保小的点在前"""
    if point1 > point2:
        return point2, point1
    return point1, point2


def point_on_segment(px, py, x1, y1, x2, y2):
    """判断点是否在线段上"""
    if (x1 <= px <= x2 or x2 <= px <= x1) and (y1 <= py <= y2 or y2 <= py <= y1):
        cross_product = (py - y1) * (x2 - x1) - (px - x1) * (y2 - y1)
        if abs(cross_product) < 1e-10:
            return True
    return False


def perpendicular_line_from_point(point, line):
    # 提取点的坐标
    px, py = point
    # 提取线段的端点
    x1, y1, x2, y2 = line

    # 计算线段的方向向量
    dx = x2 - x1
    dy = y2 - y1

    # 计算线段长度的平方
    len_sq = dx ** 2 + dy ** 2
    if len_sq == 0:
        raise ValueError("线段的两个端点重合,无法计算垂线。")

    # 计算点在直线上的投影点(垂足)
    t = ((px - x1) * dx + (py - y1) * dy) / len_sq
    foot_x = x1 + t * dx
    foot_y = y1 + t * dy
    print(f"foot_x: {foot_x}, foot_y: {foot_y}, t: {t}")

    # 判断点是否在线段上
    if point_on_segment(px, py, x1, y1, x2, y2):
        # 点在线段上,返回点和线段的中心点
        mid_x = (x1 + x2) / 2
        mid_y = (y1 + y2) / 2
        return normalize_points((px, py), (mid_x, mid_y))
    elif 0 <= t <= 1:
        # 点不在线段上,但垂足在线段上,返回点和垂足点
        return normalize_points((px, py), (foot_x, foot_y))
    else:
        # 点在线段的延长线上,返回点和最近的端点
        dist_to_start = (px - x1) ** 2 + (py - y1) ** 2
        dist_to_end = (px - x2) ** 2 + (py - y2) ** 2
        if dist_to_start < dist_to_end:
            return normalize_points((px, py), (x1, y1))
        else:
            return normalize_points((px, py), (x2, y2))


# 示例用法
point = (2, 2)
line = (3, 1, 3, 4)
result = perpendicular_line_from_point(point, line)
print(result)  # 输出应为 ((2, 2), (3, 2))


point = (3, 5)
line = (3, 2, 3, 5)
result = perpendicular_line_from_point(point, line)
print(result)  # 输出应为 ((3, 2), (3, 3.5))

leng

def normalize_points(point1, point2):
    """规范化两个点,确保小的点在前"""
    if point1 > point2:
        return point2, point1
    return point1, point2


def point_on_segment(px, py, x1, y1, x2, y2):
    """判断点是否在线段上"""
    if (x1 <= px <= x2 or x2 <= px <= x1) and (y1 <= py <= y2 or y2 <= py <= y1):
        cross_product = (py - y1) * (x2 - x1) - (px - x1) * (y2 - y1)
        if abs(cross_product) < 1e-10:
            return True
    return False


def perpendicular_line_from_point(point, line, length=16):
    # 提取点的坐标
    px, py = point
    # 提取线段的端点
    x1, y1, x2, y2 = line

    # 计算线段的方向向量
    dx = x2 - x1
    dy = y2 - y1

    # 计算线段长度的平方
    len_sq = dx ** 2 + dy ** 2
    if len_sq == 0:
        raise ValueError("线段的两个端点重合,无法计算垂线。")

    # 计算点在直线上的投影点(垂足)
    t = ((px - x1) * dx + (py - y1) * dy) / len_sq
    foot_x = x1 + t * dx
    foot_y = y1 + t * dy
    print(f"foot_x: {foot_x}, foot_y: {foot_y}, t: {t}")

    # 判断点是否在线段上
    if point_on_segment(px, py, x1, y1, x2, y2):
        # 点在线段上,返回点和线段的中心点
        mid_x = (x1 + x2) / 2
        mid_y = (y1 + y2) / 2
        return normalize_points((px, py), (mid_x, mid_y))
    elif 0 <= t <= 1:
        # 点不在线段上,但垂足在线段上,返回点和垂足点
        return normalize_points((px, py), (foot_x, foot_y))
    else:
        # 点在线段的延长线上,返回点和最近的端点
        if (x1 == x2):  # 垂直线段
            if py < y1:
                return normalize_points((px, py), (x1, y1))
            else:
                return normalize_points((px, py), (x1, y2))
        elif (y1 == y2):  # 水平线段
            if px < x1:
                return normalize_points((px, py), (x1, y1))
            else:
                return normalize_points((px, py), (x2, y2))
        else:
            # 一般情况下,返回点和最近的端点
            dist_to_start = (px - x1) ** 2 + (py - y1) ** 2
            dist_to_end = (px - x2) ** 2 + (py - y2) ** 2
            if dist_to_start < dist_to_end:
                return normalize_points((px, py), (x1, y1))
            else:
                return normalize_points((px, py), (x2, y2))


def point_and_offset_on_segment(point, line, length=16):
    px, py = point
    x1, y1, x2, y2 = line

    if y1 == y2:  # 水平线段
        if px + length <= max(x1, x2):
            return (px, py), (px + length, py)
        else:
            return (max(x1, x2) - length, py), (max(x1, x2), py)
    elif x1 == x2:  # 垂直线段
        if py + length <= max(y1, y2):
            return (px, py), (px, py + length)
        else:
            return (px, max(y1, y2) - length), (px, max(y1, y2))
    else:
        return None


# 示例用法
point = (2, 2)
line = (3, 1, 3, 4)
result = perpendicular_line_from_point(point, line)
print(result)  # 输出应为 ((2, 2), (3, 2))

point = (3, 5)
line = (3, 2, 3, 5)
result = perpendicular_line_from_point(point, line)
print(result)  # 输出应为 ((3, 2), (3, 3.5))

# 新的测试用例
point = (2, 2)
line = (2, 2, 2, 60)
result = point_and_offset_on_segment(point, line, length=16)
print(result)  # 输出应为 ((2, 2), (18, 2))

point = (2, 10)
line = (2, 50, 2, 10)
result = point_and_offset_on_segment(point, line, length=16)
print(result)  # 输出应为 ((34, 2), (50, 2))