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))
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
- 34.
- 35.
- 36.
- 37.
- 38.
- 39.
- 40.
- 41.
- 42.
- 43.
- 44.
- 45.
- 46.
- 47.
- 48.
- 49.
- 50.
- 51.
- 52.
- 53.
- 54.
- 55.
- 56.
- 57.
- 58.
- 59.
- 60.
- 61.
- 62.
- 63.
- 64.
- 65.
- 66.
- 67.
- 68.
- 69.
- 70.
- 71.
- 72.
- 73.
- 74.
- 75.
- 76.
- 77.
- 78.
- 79.
- 80.
- 81.
- 82.
- 83.
- 84.
- 85.
- 86.
- 87.
- 88.
- 89.
- 90.
- 91.
- 92.
- 93.
- 94.
- 95.
- 96.
- 97.
- 98.
- 99.
- 100.
- 101.
- 102.
- 103.
- 104.
- 105.
- 106.
- 107.