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))