|
|
from numpy import *
|
|
|
import matplotlib.pyplot as plt
|
|
|
from mpl_toolkits.mplot3d import Axes3D
|
|
|
from convert_formula import convert_formula # 导入转换函数
|
|
|
import matplotlib
|
|
|
|
|
|
|
|
|
# 全局配置中文字体(新增)
|
|
|
matplotlib.rcParams['font.sans-serif'] = ['SimHei'] # 使用黑体(Windows系统常用中文字体)
|
|
|
matplotlib.rcParams['axes.unicode_minus'] = False # 解决负号显示问题
|
|
|
|
|
|
|
|
|
def plot_plane_curve(a, b, M, f1, f2, title='平面曲线'):
|
|
|
'''
|
|
|
绘制平面参数曲线
|
|
|
|
|
|
参数:
|
|
|
a (float): 参数t的起始值
|
|
|
b (float): 参数t的终止值(需满足 a <= b)
|
|
|
M (int): 参数t的采样点数(需为正整数)
|
|
|
f1 (callable): X坐标关于t的函数(输入一维数组,输出一维数组)
|
|
|
f2 (callable): Y坐标关于t的函数(输入一维数组,输出一维数组)
|
|
|
title (str): 图形标题
|
|
|
'''
|
|
|
# 参数校验
|
|
|
if not (isinstance(M, int) and M > 0):
|
|
|
raise ValueError(f'采样点数M={M}需为正整数')
|
|
|
if a > b:
|
|
|
raise ValueError(f'参数范围需满足a={a} <= b={b}')
|
|
|
|
|
|
t = linspace(a, b, M)
|
|
|
X = f1(t)
|
|
|
Y = f2(t)
|
|
|
plt.figure()
|
|
|
plt.plot(X, Y)
|
|
|
plt.xlabel('X')
|
|
|
plt.ylabel('Y')
|
|
|
plt.title(title) # 标题使用用户输入的中文
|
|
|
plt.grid(True)
|
|
|
plt.show()
|
|
|
|
|
|
|
|
|
def plot_space_surface(a, b, M, c, d, N, F1, F2, F3, title='空间曲面'):
|
|
|
'''
|
|
|
绘制空间参数曲面
|
|
|
|
|
|
参数:
|
|
|
a/b (float): 参数t的取值范围(a <= b)
|
|
|
M (int): t的采样点数(正整数)
|
|
|
c/d (float): 参数s的取值范围(c <= d)
|
|
|
N (int): s的采样点数(正整数)
|
|
|
F1/F2/F3 (callable): X/Y/Z坐标关于s,t的函数(输入二维网格,输出二维网格)
|
|
|
title (str): 图形标题
|
|
|
'''
|
|
|
# 参数校验
|
|
|
for var, name in [(M, 'M'), (N, 'N')]:
|
|
|
if not (isinstance(var, int) and var > 0):
|
|
|
raise ValueError(f'采样点数{name}={var}需为正整数')
|
|
|
for start, end, name in [(a, b, 't'), (c, d, 's')]:
|
|
|
if start > end:
|
|
|
raise ValueError(f'{name}参数范围需满足{start} <= {end}')
|
|
|
|
|
|
fig = plt.figure()
|
|
|
ax = fig.add_subplot(111, projection='3d')
|
|
|
t = linspace(a, b, M)
|
|
|
s = linspace(c, d, N)
|
|
|
s_grid, t_grid = meshgrid(s, t)
|
|
|
X = F1(s_grid, t_grid)
|
|
|
Y = F2(s_grid, t_grid)
|
|
|
Z = F3(s_grid, t_grid)
|
|
|
ax.plot_surface(X, Y, Z, cmap='viridis')
|
|
|
ax.set_xlabel('X')
|
|
|
ax.set_ylabel('Y')
|
|
|
ax.set_zlabel('Z')
|
|
|
ax.set_title(title) # 标题使用用户输入的中文
|
|
|
plt.show()
|
|
|
|
|
|
|
|
|
def plot_space_curve(a, b, M, F1, F2, F3, title='空间曲线'):
|
|
|
'''
|
|
|
绘制单参数空间曲线(如螺旋线)
|
|
|
|
|
|
参数:
|
|
|
a/b (float): 参数t的取值范围(a <= b)
|
|
|
M (int): t的采样点数(正整数)
|
|
|
F1/F2/F3 (callable): X/Y/Z坐标关于t的函数(输入一维数组,输出一维数组)
|
|
|
title (str): 图形标题
|
|
|
'''
|
|
|
# 参数校验
|
|
|
if not (isinstance(M, int) and M > 0):
|
|
|
raise ValueError(f'采样点数M={M}需为正整数')
|
|
|
if a > b:
|
|
|
raise ValueError(f'参数范围需满足a={a} <= b={b}')
|
|
|
|
|
|
fig = plt.figure()
|
|
|
ax = fig.add_subplot(111, projection='3d')
|
|
|
t = linspace(a, b, M)
|
|
|
X = F1(t)
|
|
|
Y = F2(t)
|
|
|
Z = F3(t)
|
|
|
ax.plot3D(X, Y, Z, color='blue', linewidth=2) # 使用plot3D绘制曲线
|
|
|
ax.set_xlabel('X')
|
|
|
ax.set_ylabel('Y')
|
|
|
ax.set_zlabel('Z')
|
|
|
ax.set_title(title) # 标题使用用户输入的中文
|
|
|
plt.show()
|
|
|
|
|
|
|
|
|
def test_plane_and_space_curves():
|
|
|
# 测试平面曲线:单位圆
|
|
|
plot_plane_curve(
|
|
|
a=0, b=2*pi, M=1000,
|
|
|
f1=lambda t: np.cos(t),
|
|
|
f2=lambda t: np.sin(t),
|
|
|
title='单位圆(参数方程)'
|
|
|
)
|
|
|
|
|
|
# 测试平面曲线:抛物线y=x²
|
|
|
plot_plane_curve(
|
|
|
a=-2, b=2, M=100,
|
|
|
f1=lambda t: t,
|
|
|
f2=lambda t: t**2,
|
|
|
title='抛物线 y=x²(参数方程)'
|
|
|
)
|
|
|
|
|
|
|
|
|
# 测试空间曲面:球面
|
|
|
plot_space_surface(
|
|
|
a=0, b=pi, M=50,
|
|
|
c=0, d=2*pi, N=50,
|
|
|
F1=lambda s,t: np.sin(t)*np.cos(s),
|
|
|
F2=lambda s,t: np.sin(t)*np.sin(s),
|
|
|
F3=lambda s,t: np.cos(t),
|
|
|
title='球面(参数方程)'
|
|
|
)
|
|
|
|
|
|
# 新增测试空间曲线:圆锥螺旋线(半径随z轴增大)
|
|
|
plot_space_curve(
|
|
|
a=0, b=8*pi, M=1000,
|
|
|
F1=lambda t: t * np.cos(t),
|
|
|
F2=lambda t: t * np.sin(t),
|
|
|
F3=lambda t: t,
|
|
|
title='圆锥螺旋线(参数方程)'
|
|
|
)
|
|
|
|
|
|
|
|
|
def UI():
|
|
|
'''命令行交互界面(支持用户输入采样点范围)'''
|
|
|
while True:
|
|
|
print("\n=== 解析几何绘图工具 ===")
|
|
|
print("1. 绘制平面曲线")
|
|
|
print("2. 绘制空间曲线")
|
|
|
print("3. 绘制空间曲面")
|
|
|
print("4. 退出程序")
|
|
|
choice = input("请选择功能(输入1-4): ")
|
|
|
|
|
|
if choice == '4':
|
|
|
print("已退出程序")
|
|
|
break
|
|
|
|
|
|
# 平面曲线(单参数t)
|
|
|
elif choice == '1':
|
|
|
print("\n--- 平面曲线绘制 ---\n提示:变量用t,如输入cos(t)会自动转换为np.cos(t),参数范围支持输入pi(如2*pi)")
|
|
|
x_expr = input("X(t)表达式: ")
|
|
|
y_expr = input("Y(t)表达式: ")
|
|
|
a_input = input("请输入t的起始值(如0或pi): ").strip().lower() # 支持pi输入
|
|
|
b_input = input("请输入t的结束值(如2*pi): ").strip().lower()
|
|
|
|
|
|
try:
|
|
|
a = eval(a_input)
|
|
|
b = eval(b_input)
|
|
|
x_func = eval(f"lambda t: {convert_formula(x_expr)}")
|
|
|
y_func = eval(f"lambda t: {convert_formula(y_expr)}")
|
|
|
plot_plane_curve(a=a, b=b, M=1000, f1=x_func, f2=y_func, title=f"平面曲线: X(t)={x_expr}, Y(t)={y_expr}")
|
|
|
except Exception as e:
|
|
|
print(f"错误: {str(e)}")
|
|
|
|
|
|
# 空间曲线(单参数t)
|
|
|
elif choice == '2':
|
|
|
print("\n--- 空间曲线绘制 ---\n提示:变量用t,参数范围支持输入pi(如8*pi)")
|
|
|
x_expr = input("X(t)表达式: ")
|
|
|
y_expr = input("Y(t)表达式: ")
|
|
|
z_expr = input("Z(t)表达式: ")
|
|
|
a_input = input("请输入t的起始值(如0或pi): ").strip().lower()
|
|
|
b_input = input("请输入t的结束值(如8*pi): ").strip().lower()
|
|
|
|
|
|
try:
|
|
|
a = eval(a_input)
|
|
|
b = eval(b_input)
|
|
|
x_func = eval(f"lambda t: {convert_formula(x_expr)}")
|
|
|
y_func = eval(f"lambda t: {convert_formula(y_expr)}")
|
|
|
z_func = eval(f"lambda t: {convert_formula(z_expr)}")
|
|
|
plot_space_curve(a=a, b=b, M=10000, F1=x_func, F2=y_func, F3=z_func, title=f"空间曲线: X(t)={x_expr}, Y(t)={y_expr}, Z(t)={z_expr}")
|
|
|
except Exception as e:
|
|
|
print(f"错误: {str(e)}")
|
|
|
|
|
|
# 空间曲面(双参数s/t)
|
|
|
elif choice == '3':
|
|
|
print("\n--- 空间曲面绘制 ---\n提示:变量用s和t,参数范围支持输入pi(如2*pi)")
|
|
|
x_expr = input("X(s,t)表达式: ")
|
|
|
y_expr = input("Y(s,t)表达式: ")
|
|
|
z_expr = input("Z(s,t)表达式: ")
|
|
|
c_input = input("请输入s的起始值(如0或pi): ").strip().lower()
|
|
|
d_input = input("请输入s的结束值(如2*pi): ").strip().lower()
|
|
|
a_input = input("请输入t的起始值(如0或pi): ").strip().lower()
|
|
|
b_input = input("请输入t的结束值(如pi): ").strip().lower()
|
|
|
|
|
|
try:
|
|
|
c = eval(c_input)
|
|
|
d = eval(d_input)
|
|
|
a = eval(a_input)
|
|
|
b = eval(b_input)
|
|
|
x_func = eval(f"lambda s,t: {convert_formula(x_expr)}")
|
|
|
y_func = eval(f"lambda s,t: {convert_formula(y_expr)}")
|
|
|
z_func = eval(f"lambda s,t: {convert_formula(z_expr)}")
|
|
|
plot_space_surface(a=a, b=b, M=50, c=c, d=d, N=50, F1=x_func, F2=y_func, F3=z_func, title=f"空间曲面: X(s,t)={x_expr}, Y(s,t)={y_expr}, Z(s,t)={z_expr}")
|
|
|
except Exception as e:
|
|
|
print(f"错误: {str(e)}")
|
|
|
|
|
|
else:
|
|
|
print("输入无效,请重新选择")
|
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
UI() # 启动命令行界面
|
|
|
#test_plane_and_space_curves()
|