Python实现L1与L∞度量下两点间平分线的绘制需求
嘿,这个问题我之前做计算几何可视化的时候也遇到过!带绝对值和max的方程确实没法直接用y=ax+b这种直线公式来绘制,但咱们有两种靠谱的方案可以搞定——一种是分区域拆解方程,精确绘制分段线性的平分线,另一种是数值采样点集,快速验证并绘制。下面给你详细拆解,附Python代码示例:
方案一:分区域拆解方程(精确绘制)
这种方法的核心是去掉绝对值和max函数,把原方程拆成多个带约束的线性方程,每个方程对应平面上的一个区域,然后绘制每个区域内符合条件的线段。
1. L₁度量(曼哈顿距离)的平分线
你的方程是:|x-x₁| + |y-y₁| = |x-x₂| + |y-y₂|,整理后可以拆成两条互相垂直的直线:
x + y = (x₁ + y₁ + x₂ + y₂)/2x - y = (x₁ - y₁ + x₂ - y₂)/2
所有满足原方程的点都在这两条直线上,直接绘制即可覆盖全部平分线区域。
2. L∞度量(切比雪夫距离)的平分线
你的方程是:max(|x-x₁|, |y-y₁|) = max(|x-x₂|, |y-y₂|),可以拆成四种带约束的情况:
- 当|x-x₁| ≥ |y-y₁|且|x-x₂| ≥ |y-y₂|:方程简化为
x = (x₁+x₂)/2,仅在y的范围[y₁ - |(x₂-x₁)/2|, y₁ + |(x₂-x₁)/2|]内有效 - 当|x-x₁| ≥ |y-y₁|且|x-x₂| < |y-y₂|:方程变为
|x-x₁| = |y-y₂|,对应两条直线y = x - (x₁ - y₂)和y = -x + (x₁ + y₂),需筛选满足约束的线段 - 当|x-x₁| < |y-y₁|且|x-x₂| ≥ |y-y₂|:方程变为
|y-y₁| = |x-x₂|,对应两条直线y = x + (y₁ - x₂)和y = -x + (y₁ + x₂),需筛选满足约束的线段 - 当|x-x₁| < |y-y₁|且|x-x₂| < |y-y₂|:方程简化为
y = (y₁+y₂)/2,仅在x的范围[x₁ - |(y₂-y₁)/2|, x₁ + |(y₂-y₁)/2|]内有效
把这些线段组合起来,就是L∞度量下的完整平分线。
方案二:数值采样法(快速实现)
如果不想花时间推导分段方程,数值采样是个偷懒但有效的方法:生成大量的(x,y)点,判断每个点是否满足平分线方程(可以加一个微小的误差容忍,比如abs(left_side - right_side) < 1e-3),然后把符合条件的点收集起来绘制。
Python代码示例(两种方案结合)
import matplotlib.pyplot as plt import numpy as np # 定义两点坐标 x1, y1 = 0, 0 x2, y2 = 3, 2 # -------------------------- # 方案一:精确绘制L1和L∞平分线 # -------------------------- fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 5)) # L1度量平分线 l1_line1 = lambda x: (x1 + y1 + x2 + y2)/2 - x l1_line2 = lambda x: x - (x1 - y1 + x2 - y2)/2 x_l1 = np.linspace(min(x1, x2)-2, max(x1, x2)+2, 100) ax1.plot(x_l1, l1_line1(x_l1), label='L1 平分线1', color='red') ax1.plot(x_l1, l1_line2(x_l1), label='L1 平分线2', color='blue') ax1.scatter([x1, x2], [y1, y2], color='black', s=50) ax1.set_title('L₁度量下的两点平分线') ax1.legend() ax1.grid(True) # L∞度量平分线 dx = x2 - x1 dy = y2 - y1 mid_x = (x1 + x2)/2 mid_y = (y1 + y2)/2 # 情况1:x=mid_x,满足约束 y_range1 = np.linspace(y1 - abs(dx/2), y1 + abs(dx/2), 100) ax2.plot([mid_x]*len(y_range1), y_range1, color='red', label='L∞ 线段1') # 情况4:y=mid_y,满足约束 x_range4 = np.linspace(x1 - abs(dy/2), x1 + abs(dy/2), 100) ax2.plot(x_range4, [mid_y]*len(x_range4), color='blue', label='L∞ 线段4') # 情况2:|x-x1|=|y-y2|,筛选约束点 x_range2 = np.linspace(min(x1, x2)-2, max(x1, x2)+2, 100) y2_1 = x_range2 - (x1 - y2) y2_2 = -x_range2 + (x1 + y2) mask2_1 = (abs(x_range2 - x1) >= abs(y2_1 - y1)) & (abs(x_range2 - x2) < abs(y2_1 - y2)) mask2_2 = (abs(x_range2 - x1) >= abs(y2_2 - y1)) & (abs(x_range2 - x2) < abs(y2_2 - y2)) ax2.plot(x_range2[mask2_1], y2_1[mask2_1], color='green', label='L∞ 线段2') ax2.plot(x_range2[mask2_2], y2_2[mask2_2], color='green') # 情况3:|y-y1|=|x-x2|,筛选约束点 y3_1 = x_range2 + (y1 - x2) y3_2 = -x_range2 + (y1 + x2) mask3_1 = (abs(x_range2 - x1) < abs(y3_1 - y1)) & (abs(x_range2 - x2) >= abs(y3_1 - y2)) mask3_2 = (abs(x_range2 - x1) < abs(y3_2 - y1)) & (abs(x_range2 - x2) >= abs(y3_2 - y2)) ax2.plot(x_range2[mask3_1], y3_1[mask3_1], color='orange', label='L∞ 线段3') ax2.plot(x_range2[mask3_2], y3_2[mask3_2], color='orange') ax2.scatter([x1, x2], [y1, y2], color='black', s=50) ax2.set_title('L∞度量下的两点平分线') ax2.legend() ax2.grid(True) # -------------------------- # 方案二:数值采样法示例(L1) # -------------------------- fig2, ax3 = plt.subplots(figsize=(6,5)) x_sample = np.linspace(min(x1,x2)-3, max(x1,x2)+3, 500) y_sample = np.linspace(min(y1,y2)-3, max(y1,y2)+3, 500) X, Y = np.meshgrid(x_sample, y_sample) l1_diff = abs(X - x1) + abs(Y - y1) - (abs(X - x2) + abs(Y - y2)) mask = abs(l1_diff) < 1e-3 ax3.scatter(X[mask], Y[mask], s=1, color='purple', label='L1 采样点') ax3.scatter([x1, x2], [y1, y2], color='black', s=50) ax3.set_title('数值采样法绘制L₁平分线') ax3.legend() ax3.grid(True) plt.tight_layout() plt.show()
补充说明
- 方案一的精确绘制需要注意约束条件,否则会画出超出有效区域的线段,代码里已经通过mask做了筛选;
- 方案二的采样密度可以通过调整
linspace的点数来控制,点数越多精度越高,但计算量也会增加; - 如果你需要处理特殊情况(比如两点重合、在同一水平线/垂直线上),可以在代码里添加判断分支做特殊处理。
内容的提问来源于stack exchange,提问作者gaganso
相关产品推荐
相关产品推荐

