如何用Python绘制两个圆之间的8条公切线
引言
在几何学中,两圆之间存在多种类型的公共切线。本文将通过Python代码演示如何绘制两个同心圆(半径分别为1.0和3.0)之间的8条公切线,并解释相关数学原理与代码实现细节。
环境准备
import matplotlib.pyplot as plt
import numpy as np
这两个库是绘制图形的基础:
matplotlib
用于可视化numpy
提供数值计算支持
参数设置
radius = 1.0 # 小圆半径
radius_large = 3.0 # 大圆半径
num_lines = 8 # 切线数量
theta_step = 2 * np.pi / num_lines
参数说明:
radius
和radius_large
定义两个圆的半径num_lines
控制切线的数量(这里选择8条)theta_step
计算每个角度间隔
角度生成
thetas = np.linspace(0, 2 * np.pi, num_lines, endpoint=False)
thetas = thetas.tolist() + [0]
这个步骤的目的是生成均匀分布的角度点:
- 使用
linspace
生成不包括终点的8个点 - 添加0作为闭合循环的最后一个点
绘制基本图形
plt.figure(figsize=(6, 6))
plt.axis('equal') # 确保坐标轴比例一致# 绘制两个圆
plt.plot(radius * np.cos(thetas), radius * np.sin(thetas), label='Original Circle')
plt.plot(radius_large * np.cos(thetas), radius_large * np.sin(thetas), label='Large Circle')
plt.axis('equal')
确保图形保持正圆形状,避免变形。
切线绘制分析
问题所在
原始代码中的切线绘制存在逻辑错误:
for theta, theta1 in zip(thetas[1:], thetas[:-1]):# 原始圆上的点x1 = radius * np.cos(theta)y1 = radius * np.sin(theta)x2 = radius_large * np.cos(theta1)y2 = radius_large * np.sin(theta1)plt.plot([x1, x2], [y1, y2], 'r-', label='Tangent Line (Small Circle)')
这段代码的问题在于:
thetas
的处理导致循环配对错误- 直接连接两个圆上的点无法保证是公切线
正确做法
要正确绘制两圆之间的公切线,需要计算切线方程:
- 两圆心距离:d = radius_large - radius = 2.0
- 切线长度:L = sqrt(d² + r²)(r为半径差)
正确的切线方向向量应为:
dx = (radius_large * np.cos(theta) - radius * np.cos(theta))
dy = (radius_large * np.sin(theta) - radius * np.sin(theta))
但更准确的计算需要使用几何公式:
改进代码
# 计算公切线方向向量
dx_tangent_small = np.sin(thetas)
dy_tangent_small = -np.cos(thetas)dx_tangent_large = np.sin(thetas)
dy_tangent_large = -np.cos(thetas)line_length = 2.0for theta in thetas:# 小圆切线点x1 = radius * np.cos(theta)y1 = radius * np.sin(theta)x2 = x1 + dx_tangent_small[theta] * line_lengthy2 = y1 + dy_tangent_small[theta] * line_length# 大圆切线点x3 = radius_large * np.cos(theta)y3 = radius_large * np.sin(theta)x4 = x3 + dx_tangent_large[theta] * line_lengthy4 = y3 + dy_tangent_large[theta] * line_lengthplt.plot([x1, x2], [y1, y2], 'r-', label='Tangent Line (Small Circle)')plt.plot([x3, x4], [y3, y4], 'b-', label='Tangent Line (Large Circle)')
注意事项
- 切线方向计算:正确的切线方向是圆周的法向量(-sinθ, cosθ)
- 长度控制:确保线段在圆外延伸
- 闭合循环:thetas数组需要正确闭合以形成完整图形
- 图例显示:建议使用
plt.legend()
展示所有元素
最终效果
运行代码后,会得到一个包含:
- 两个同心圆
- 8条公切线(红色和蓝色分别代表小圆和大圆的切线)
- 均匀分布的切线方向
总结
通过分析原始代码并理解几何原理,我们修正了切线绘制方法。正确的做法是:
- 计算切线方向向量
- 确保线段长度在圆外
- 正确闭合循环形成完整图形
这种可视化可以帮助深入理解圆的公切线性质,在工程制图、计算机视觉等领域有广泛应用价值。
import matplotlib.pyplot as plt
import numpy as np# 圆的参数设置
radius = 1.0 # 原始圆半径
radius_large = 3.0 # 较大的圆半径
num_lines = 8 # 线段数量
theta_step = 2 * np.pi / num_lines # 每条线段对应的角度步长# 计算角度(均匀分布)
thetas = np.linspace(0, 2 * np.pi, num_lines, endpoint=False)
thetas = thetas.tolist()+[0]
# 初始化绘图区域
plt.figure(figsize=(6, 6))
plt.axis('equal') # 确保坐标轴比例一致,绘制圆形# 绘制两个圆
plt.plot(radius * np.cos(thetas), radius * np.sin(thetas), label='Original Circle')
plt.plot(radius_large * np.cos(thetas), radius_large * np.sin(thetas), label='Large Circle')# 定义线段长度(确保在圆外)
line_length = 2.0# 绘制切线方向的8条线
for theta,theta1 in zip(thetas[1:],thetas[:-1]):# 原始圆上的点x1 = radius * np.cos(theta)y1 = radius * np.sin(theta)x2 = radius_large * np.cos(theta1)y2 = radius_large * np.sin(theta1)plt.plot([x1, x2], [y1, y2], 'r-', label='Tangent Line (Small Circle)')# 较大圆上的点# x1_large = radius_large * np.cos(theta)# y1_large = radius_large * np.sin(theta)## dx_tangent_large = -np.sin(theta)# dy_tangent_large = np.cos(theta)## x2_large = x1_large + dx_tangent_large * line_length# y2_large = y1_large + dy_tangent_large * line_length## plt.plot([x1_large, x2_large], [y1_large, y2_large], 'b-', label='Tangent Line (Large Circle)')# 去除刻度线和网格线
plt.tick_params(axis='both', which='both', length=0)
plt.grid(False)# 添加图例(可选)
# plt.legend()# 显示图形
plt.title("8 Tangent Lines on Two Circles")
plt.show()