python调用math函数_Python math.isinf() 方法

本文介绍Python中使用math.isinf()方法来判断一个数值是否为正无穷大或负无穷大的用法。通过实例演示如何判断不同类型的数值。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Python math.isinf() 方法

例如:

检查值是否为无穷大:# Import math Library

import math

# 检查这些值是否为无穷大

print(math.isinf(56))

print(math.isinf(-45.34))

print(math.isinf(+45.34))

print(math.isinf(math.inf))

print(math.isinf(float("nan")))

print(math.isinf(float("inf")))

print(math.isinf(float("-inf")))

print(math.isinf(-math.inf))

1、定义和用法

math.isinf()方法检查数字是否为无限。

如果指定的数字为正或负无穷大,则此方法返回True,否则返回False。

2、调用语法math.isinf(x)

3、参数说明参数描述

x必需的参数, 检查号码

4、方法说明返回值:bool值,如果x是正负无穷大则为True,否则为False

Python Version:2.6

from re import A import tkinter as tk from tkinter import ttk, messagebox, filedialog import json import os import math import mpmath as mp #from cv2 import line import numpy as np #from sympy import Float class OpticalSystem: def __init__(self): self.surfaces = [] # 存储光学表面对象 self.entrance_pupil_diameter = None # 入瞳直径 (mm) self.entrance_pupil_position = None # 入瞳位置 (相对第一个面顶点) (mm) self.object_infinite = True # 物在无穷远 self.field_angle = None # 半视场角 (度) self.object_distance = None # 物距 (有限远) (mm) self.object_height = None # 物高 (有限远) (mm) self.aperture_angle = None # 孔径角 (有限远) (度) self.light_type = "d" # 色光类型,默认d光 self.aperture_coefficient = 1.0 # 孔径系数 self.field_coefficient = 1.0 # 视场系数 # 计算结果存储 self.results = { "focal_length": None, # 焦距 f' "ideal_image_distance": None, # 理想像距 l' "actual_image_position": None, # 实际像位置 "image_principal_plane": None, # 像方主面位置 lH' "exit_pupil_distance": None, # 出瞳距 lp' "ideal_image_height": None, # 理想像高 y0' "spherical_aberration": None, # 球差 "longitudinal_chromatic": None, # 位置色差 "tangential_field_curvature": None, # 子午场曲 xt' "sagittal_field_curvature": None, # 弧矢场曲 xs' "astigmatism": None, # 像散 Δxts' "actual_image_height": None, # 实际像高 "relative_distortion": None, # 相对畸变 "absolute_distortion": None, # 绝对畸变 "lateral_chromatic": None, # 倍率色差 "tangential_coma": None # 子午慧差 } class Surface: def __init__(self, r=float('inf'), d=0.0, nd=1.0, nf=1.0, nc=1.0): self.r = r # 曲率半径 (mm) self.d = d # 厚度/间隔 (mm) self.nd = nd # d光折射率 self.nf = nf # F光折射率 self.nc = nc # C光折射率 def to_dict(self): """将表面数据转换为字典""" return { "r": self.r, "d": self.d, "nd": self.nd, "nf": self.nf, "nc": self.nc } @classmethod def from_dict(cls, data): """从字典创建表面对象""" return cls( r=data.get('r', float('inf')), d=data.get('d', 0.0), nd=data.get('nd', 1.0), nf=data.get('nf', 1.0), nc=data.get('nc', 1.0) ) class calculate: def trace_paraxial_ray(surfaces, h0, u0, n0=1.0): """ 近轴光线追迹函数 :param surfaces: 光学表面列表 :param h0: 初始光线高度 :param u0: 初始光线角度(弧度) :param n0: 初始介质折射率 :return: 最后的光线高度和角度 """ h = h0 u = u0 n = n0 # 当前介质折射率 for i, surf in enumerate(surfaces): # 计算曲率(平面时曲率为0) c = 0.0 if math.isinf(surf.r) else 1.0 / surf.r # 折射公式:n'u' = nu + (n - n') * c * h n_prime = surf.nd # 折射后折射率 u_prime = (n * u + (n - n_prime) * c * h) / n_prime # 如果当前不是最后一个面,计算传播到下个面的高度 if i < len(surfaces) - 1: d = surf.d # 到下一个面的距离 h_next = h + d * u_prime else: h_next = h # 最后一个面后不需要传播 # 更新参数 h = h_next u = u_prime n = n_prime # 更新为当前面后的折射率 return h, u def calculate_focal_length(surfaces): """ 计算系统焦距 :param surfaces: 光学表面列表 :return: 焦距值(mm) """ # 追迹平行于光轴的光线(无穷远物) h0 = 1.0 # 任意高度,取1便于计算 u0 = 0.0 # 平行于光轴 h_final, u_final = calculate.trace_paraxial_ray(surfaces, h0, u0) # 焦距 f' = -h0 / u_final if abs(u_final) < 1e-10: # 防止除零错误 return float('inf') return -h0 / u_final def calculate_ideal_image_distance(surfaces, object_infinite, object_distance=None): """ 计算理想像距 :param surfaces: 光学表面列表 :param object_infinite: 物是否在无穷远 :param object_distance: 物距(有限远时) :return: 理想像距(mm) """ #获取倒序的surfaces reversed_surfaces = [] for i in range(len(surfaces)): j=((i+2)%len(surfaces))*(-1) surf=Surface() surf.d=surfaces[j].d surf.nd=surfaces[j].nd surf.nf=surfaces[j].nf surf.nc=surfaces[j].nc surf.r =-1.0*surfaces[len(surfaces)-i-1].r reversed_surfaces.append(surf) reversed_surfaces[-1].d = 10000.0 #物方主面 object_main_plain=calculate.calculate_principal_plane_position(reversed_surfaces)*(-1.0) if object_infinite: # 无穷远物:理想像距等于焦距对应的像距 return calculate.calculate_focal_length(surfaces)+calculate.calculate_principal_plane_position(surfaces) else: # 有限远物:使用高斯公式计算理想像距 if object_distance is None: raise ValueError("有限远物需要提供物距") # 计算系统焦距 f_prime = calculate.calculate_focal_length(surfaces) #厚度 # 高斯公式:1/f' = 1/l' - 1/l # 其中 l 为物距(负值),l' 为像距 l = -object_distance # 物距为负值(物在左侧) # 计算像距 l' if abs(f_prime) < 1e-10: return float('inf') main_plain=calculate.calculate_principal_plane_position(surfaces) l_prime = 1 / (1.0/f_prime + 1.0/(l-object_main_plain)) l_prime = l_prime+main_plain return l_prime def calculate_principal_plane_position(surfaces): """ 计算像方主面位置 :param surfaces: 光学表面列表 :return: 主面位置(相对于最后一个面顶点,正值表示在右侧) """ # 计算焦距 f_prime = calculate.calculate_focal_length(surfaces) # 追迹平行于光轴的光线 h0 = 1.0 # 初始高度 u0 = 0.0 # 平行于光轴 h_final, u_final = calculate.trace_paraxial_ray(surfaces, h0, u0) # 主面位置 lH' = -h_final / u_final - f_prime if abs(u_final) < 1e-10: return float('inf') return -h_final / u_final - f_prime def calculate_exit_pupil_distance(surfaces, entrance_pupil_position): """ 计算系统的出瞳距 :param surfaces: 光学表面列表 :param entrance_pupil_position: 入瞳位置(相对于第一个面顶点) :return: 出瞳距(相对于最后一个面顶点) """ # 定义初始光线参数 u0 = 0.01 # 小角度(弧度) # 计算第一个面的光线高度 h0 = -entrance_pupil_position * u0 # 进行近轴光线追迹 h_final, u_final = calculate.trace_paraxial_ray(surfaces, h0, u0) # 计算出瞳距:l' = -h_final / u_final if abs(u_final) < 1e-10: # 防止除零错误 return float('inf') return -h_final / u_final def calculate_ideal_image_height(system): """ 计算理想像高 :param system: OpticalSystem对象 :return: 理想像高(mm) """ # 获取系统焦距 focal_length = calculate.calculate_focal_length(system.surfaces) if system.object_infinite: # 无穷远物 # 理想像高 y0' = -f' * tan(ω) field_angle_rad = math.radians(system.field_angle*system.field_coefficient) return -focal_length * math.tan(field_angle_rad) else: # 有限远物 #获取倒序的surfaces surfaces = system.surfaces reversed_surfaces = [] for i in range(len(surfaces)): j=((i+2)%len(surfaces))*(-1) surf=Surface() surf.d=surfaces[j].d surf.nd=surfaces[j].nd surf.nf=surfaces[j].nf surf.nc=surfaces[j].nc surf.r =-1.0*surfaces[len(surfaces)-i-1].r reversed_surfaces.append(surf) reversed_surfaces[-1].d = 10000.0 #物方主面 object_main_plain=calculate.calculate_principal_plane_position(reversed_surfaces)*(-1.0) # 获取理想像距 ideal_image_distance = calculate.calculate_ideal_image_distance( system.surfaces, system.object_infinite, system.object_distance ) # 获取主面位置 principal_plane = calculate.calculate_principal_plane_position(system.surfaces) # 计算实际像位置(从最后一个面顶点) actual_image_position = ideal_image_distance - principal_plane # 计算放大率 β = l'/l # l = -object_distance(物在左侧为负) magnification = actual_image_position / (-system.object_distance-object_main_plain) # 理想像高 y0' = β * y return magnification * system.object_height*system.field_coefficient def trace_real_ray(surfaces, h0, u0, l0,light_type): """ 实际光线追迹函数 :param surfaces: 光学表面列表 :param h0: 初始光线高度 :param u0: 初始光线角度(弧度) :param l0: 初始光线距离(mm) :return: 最后的光线距离和角度 """ h = h0 u = u0 L = l0 # 当前光线距离 npre = 1 LL = [] PA =[] LI =[] LR =[] LW = [L] UU = [u] #初始化内部变量 si = 0 sii = 0 uu = 0 for i, surf in enumerate(surfaces): # 选择色光折射率 if light_type == 'd': n_surf = surf.nd elif light_type == 'f': n_surf = surf.nf elif light_type == 'c': n_surf = surf.nc else: n_surf = surf.nd # 默认d光 # 计算曲率(平面时曲率为0) c = 0.0 if math.isinf(surf.r) else 1.0 / surf.r if(i == 0 and u==0.0): si = h/surf.r else: si = (L-surf.r)*np.sin(u)/surf.r sii = npre*si/n_surf si = np.clip(si, -1.0, 1.0) sii = np.clip(sii, -1.0, 1.0) uu = u +np.arcsin(si)-np.arcsin(sii) L = surf.r+surf.r*sii/np.sin(uu) PA .append( L * np.sin(uu) / np.cos((np.arcsin(sii)-uu)/2)) LL.append(L) UU.append(uu) LI.append(np.arcsin(si)) LR.append(np.arcsin(sii)) #传递到下一个表面 if i < len(surfaces) - 1: u = uu L = L -surf.d npre = n_surf # 折射后折射率 LW.append(L) return LW, LL,UU,LI,LR,PA def calculate_actual_image(system,light_type): """ 计算轴上点的实际像位置(相对于最后一个面顶点) 参数: system: OpticalSystem对象,包含: - surfaces: 表面列表 - entrance_pupil_diameter: 入瞳直径 (mm) - entrance_pupil_position: 入瞳位置 (相对第一个面顶点) (mm) - aperture_coefficient: 孔径系数 (0~1) - object_infinite: 物是否在无穷远 - object_distance: 物距 (有限远时) (mm) - light_type: 色光类型 (这里只影响折射率选择) 返回: 实际像位置 (mm) (正值表示在最后一个面右侧) """ # 1. 计算实际入瞳半径 actual_entrance_radius = (system.entrance_pupil_diameter * system.aperture_coefficient) / 2 # 2. 根据物方情况设置初始光线参数 if system.object_infinite: # 无穷远物:光线平行于光轴 u0 = 0.0 # 初始角度 (弧度) h0 = actual_entrance_radius # 初始高度 (取入瞳边缘) l0 = 0 # 物方截距 (无穷远) L_final = calculate.trace_real_ray(system.surfaces, h0, u0, l0,light_type)[1] else: # 有限远物 # 计算物点到入瞳平面的距离 d_object_to_entrance = system.object_distance - system.entrance_pupil_position # 计算初始角度 (物点发出的光线通过入瞳边缘) u0 = math.atan(actual_entrance_radius/ d_object_to_entrance) l0 = -1.0*system.object_distance # 负号表示在左侧 h0 = 0 L_final= calculate.trace_real_ray(system.surfaces, h0, u0, l0,light_type)[1] return L_final[-1] def calculate_spherical_aberration(system): # 计算实际像位置 actual_image_position = calculate.calculate_actual_image(system,system.light_type) # 计算理想像距 ideal_image_distance = calculate.calculate_ideal_image_distance( system.surfaces, system.object_infinite, system.object_distance ) # 计算球差 return actual_image_position - ideal_image_distance def calculate_longitudinal_chromatic(system): #计算位置色差 #F光 imageF = calculate.calculate_actual_image(system,'f') #C光 imageC = calculate.calculate_actual_image(system,'c') return imageF -imageC def calculate_actual_image_height(system,light_type): """ 计算实际像高(主光线在像平面上的高度) 参数: system: OpticalSystem对象 返回: 实际像高 (mm) """ # 1. 计算像面位置(相对于最后一个面顶点) l_prime = calculate.calculate_ideal_image_distance( system.surfaces, system.object_infinite, system.object_distance ) # 2. 确定主光线初始参数 if system.object_infinite: # 无限远物 W=math.radians(system.field_angle) W=math.atan2(math.tan(W)*system.field_coefficient, 1.0) omega_rad = W # 半视场角(弧度) u0 = omega_rad # 主光线角度 h0 = 0 L0 = system.entrance_pupil_position else: # 有限远物 # = math.radians(system.field_angle) W_object_height = system.object_height * system.field_coefficient d_obj = system.object_distance - system.entrance_pupil_position u0 = math.atan(W_object_height / d_obj) d0 = -system.entrance_pupil_position h0 = d0 * math.tan(u0) L0 = system.entrance_pupil_position # 3. 追迹主光线 L_last = calculate.trace_real_ray(system.surfaces, h0, u0, L0,light_type)[1] u_last = calculate.trace_real_ray(system.surfaces, h0, u0, L0,light_type)[2] # 4. 计算实际像高 actual_image_height = (L_last[-1] - l_prime) * math.tan(u_last[-1]) return actual_image_height def calculate_astigmatism(system, light_type): # 1. 获取主光线参数 if system.object_infinite: omega_rad = math.radians(system.field_angle*system.field_coefficient) u0 = omega_rad h0 = 0 L0 = system.entrance_pupil_position else: d_obj = system.object_distance - system.entrance_pupil_position u0 = math.atan(system.object_height / d_obj) h0 = -system.entrance_pupil_position * math.tan(u0) L0 = system.entrance_pupil_position # 2. 追迹主光线获取入射/折射角 _, LL, UU, LI, LR, PA = calculate.trace_real_ray(system.surfaces, h0, u0, L0, light_type) # 3. 初始化子午和弧矢截距 n = 1.0 # 初始介质折射率(空气) t = s = 0.0 # 根据物方条件设置初始截距 if system.object_infinite: t = s = float('inf') else: t = s = -system.object_distance/math.cos(UU[0])-PA[0]**2/ (2*system.surfaces[0].r) # 物在左侧为负 # 4. 逐面计算 for i, surf in enumerate(system.surfaces): # 获取当前面折射率 if light_type == 'd': n_prime = surf.nd elif light_type == 'f': n_prime = surf.nf elif light_type == 'c': n_prime = surf.nc else: n_prime = surf.nd # 计算曲率 c = 0.0 if math.isinf(surf.r) else 1.0 / surf.r # 获取主光线角度 U = UU[i] I = LI[i] I_prime = LR[i] # Coddington方程计算新截距 # 子午光线 if math.isinf(t): num_t = n_prime * (math.cos(I_prime)**2) den_t = (n_prime * math.cos(I_prime) - n * math.cos(I)) * c t_prime = num_t / den_t if den_t != 0 else float('inf') else: term_t = (n_prime * math.cos(I_prime) - n * math.cos(I)) * c t_prime = n_prime * (math.cos(I_prime)**2) / (term_t + n * math.cos(I)**2 / t) # 弧矢光线 if math.isinf(s): num_s = n_prime den_s = (n_prime * math.cos(I_prime) - n * math.cos(I)) * c s_prime = num_s / den_s if den_s != 0 else float('inf') else: term_s = (n_prime * math.cos(I_prime) - n * math.cos(I)) * c s_prime = n_prime / (term_s + n / s) # 5. 面间过渡(最后一面前) if i < len(system.surfaces) : # 计算沿主光线方向的实际距离 r=system.surfaces[i].r U_next = UU[i+1] if i < len(system.surfaces)-1 else U x=PA[i]**2/ (2*r) x_next = PA[i+1]**2 / (2*system.surfaces[i+1].r) if i < len(system.surfaces)-1 else x d_eff = (surf.d-x +x_next)/ math.cos(U_next) # 更新截距 t = t_prime - d_eff s = s_prime - d_eff n = n_prime # 更新折射率 # 6. 计算理想像距作为参考 ideal_image_distance = calculate.calculate_ideal_image_distance( system.surfaces, system.object_infinite, system.object_distance ) # 7. 计算场曲和像散 # 子午场曲 = 子午焦点位置 - 理想像面位置 xt_prime = t_prime - ideal_image_distance/math.cos(UU[-1]) # 弧矢场曲 = 弧矢焦点位置 - 理想像面位置 xs_prime = s_prime - ideal_image_distance/math.cos(UU[-1]) # 像散 = 子午场曲 - 弧矢场曲 delta_xts = xt_prime - xs_prime return xt_prime, xs_prime, delta_xts def calculate_relative_distortion(system, light_type): # 1. 计算实际像高 actual_image_height = calculate.calculate_actual_image_height(system,light_type) # 2. 计算理想像高 ideal_image_height = calculate.calculate_ideal_image_height(system) # 3. 绝对畸变 = 实际像高 / 理想像高 if ideal_image_height == 0: return float('inf') return (actual_image_height -ideal_image_height)/ ideal_image_height*100.0 def calculate_absolute_distortion(system, light_type): # 1. 计算实际像高 actual_image_height = calculate.calculate_actual_image_height(system,light_type) # 2. 计算理想像高 ideal_image_height = calculate.calculate_ideal_image_height(system) # 3. 相对畸变 = 实际像高 - 理想像高 return ideal_image_height - actual_image_height def calculate_lateral_chromatic(system): # 计算倍率色差 # F光 imageF = calculate.calculate_actual_image_height(system,'f') # C光 imageC = calculate.calculate_actual_image_height(system,'c') return (imageF - imageC)*1.0 def calculate_tangential_coma(system:OpticalSystem): ideal_image_Position = calculate.calculate_ideal_image_height(system) aperture_height= system.entrance_pupil_diameter / 2.0* system.aperture_coefficient W=math.radians(system.field_angle) W=math.atan2(math.tan(W)*system.field_coefficient, 1.0) pupil_position=-1.0*abs(system.entrance_pupil_position) if system.object_infinite and system.field_angle!=0:#无穷远物且有视场角 UpL=-1.0*aperture_height/math.tan(W)+pupil_position DownL=aperture_height/math.tan(W)+pupil_position up_light=calculate.trace_real_ray(system.surfaces,0 , W*(-1.0), UpL,'d') down_light=calculate.trace_real_ray(system.surfaces,0 , W*(-1.0), DownL,'d') center_light= calculate.trace_real_ray(system.surfaces,0 , W*(-1.0), 0,'d') #不考虑出射光线平行的情况 ideal_image_distance=calculate.calculate_ideal_image_distance(system.surfaces,system.object_infinite,system.object_distance) h_up = up_light[1][-1]*math.tan(up_light[2][-1])*(up_light[1][-1]-ideal_image_distance)/up_light[1][-1] h_down= down_light[1][-1]*math.tan(down_light[2][-1])*(down_light[1][-1]-ideal_image_distance)/down_light[1][-1] h_center = center_light[1][-1]*math.tan(center_light[2][-1])*(center_light[1][-1]-ideal_image_distance)/center_light[1][-1] return (h_up + h_down) / 2.0 - h_center else:#有限远物 W=math.atan2(system.object_height*system.field_coefficient, abs(system.object_distance)+abs(system.entrance_pupil_position)) UpU=math.atan2(math.tan(W)*abs(system.object_distance)+aperture_height,abs(system.object_distance))*(-1.0) UpL=-1.0*aperture_height/math.tan(UpU)+pupil_position DownU = math.atan2(math.tan(W)*abs(system.object_distance)-aperture_height,abs(system.object_distance))*(-1.0) if DownU!=0.0: DownL= aperture_height/math.tan(DownU)+pupil_position else: DownL=math.inf() up_light = calculate.trace_real_ray(system.surfaces,0 , UpU, UpL,'d') down_light = calculate.trace_real_ray(system.surfaces,aperture_height , DownU, DownL,'d') center_light = calculate.trace_real_ray(system.surfaces,0 , W*(-1), -1.0*abs(system.entrance_pupil_position),'d') ideal_image_distance=calculate.calculate_ideal_image_distance(system.surfaces,system.object_infinite,system.object_distance)- calculate.calculate_principal_plane_position(system.surfaces)-system.surfaces[-2].d h_up = math.tan(up_light[2][-1])*(up_light[1][-1]-ideal_image_distance) h_down= math.tan(down_light[2][-1])*(down_light[1][-1]-ideal_image_distance) h_center = math.tan(center_light[2][-1])*(center_light[1][-1]-ideal_image_distance) ''' cross_point= line_intersection(down_light[1][-1],down_light[2][-1],up_light[1][-1],up_light[2][-1]) h_center= (cross_point[0]-center_light[1][-1])*math.tan(center_light[2][-1]) ''' return (h_up + h_down) / 2.0 - h_center class MainApplication: def __init__(self, root): self.root = root self.root.title("光学系统计算程序") self.root.geometry("1000x850") # 创建光学系统对象 self.system = OpticalSystem() # 创建GUI组件 self.create_widgets() # 加载默认设置(如果有) self.load_default_settings() def create_widgets(self): # 主框架 main_frame = ttk.Frame(self.root) main_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10) # 文件操作框架 file_frame = ttk.LabelFrame(main_frame, text="文件操作") file_frame.pack(fill=tk.X, padx=5, pady=5) # 文件路径输入 ttk.Label(file_frame, text="文件路径:").grid(row=0, column=0, padx=5, pady=5) self.file_path_entry = ttk.Entry(file_frame, width=50) self.file_path_entry.grid(row=0, column=1, padx=5, pady=5) # 文件操作按钮 browse_btn = ttk.Button(file_frame, text="浏览...", command=self.browse_file) browse_btn.grid(row=0, column=2, padx=5, pady=5) load_btn = ttk.Button(file_frame, text="加载系统参数", command=self.load_system) load_btn.grid(row=0, column=3, padx=5, pady=5) save_btn = ttk.Button(file_frame, text="保存系统参数", command=self.save_system) save_btn.grid(row=0, column=4, padx=5, pady=5) # 左侧面板 - 输入参数 left_frame = ttk.LabelFrame(main_frame, text="系统参数输入") left_frame.pack(side=tk.LEFT, fill=tk.BOTH, expand=True, padx=5, pady=5) # 右侧面板 - 结果展示 right_frame = ttk.LabelFrame(main_frame, text="计算结果") right_frame.pack(side=tk.RIGHT, fill=tk.BOTH, expand=True, padx=5, pady=5) # 创建左侧面板的子组件 self.create_input_panel(left_frame) # 创建右侧面板的子组件 self.create_result_panel(right_frame) # 计算按钮 calc_frame = ttk.Frame(main_frame) calc_frame.pack(fill=tk.X, padx=5, pady=10) calc_btn = ttk.Button(calc_frame, text="开始计算", command=self.calculate, width=15) calc_btn.grid(row=0, column=0, padx=10, pady=2, sticky="ew") save_result_btn = ttk.Button(calc_frame, text="保存计算结果", command=self.save_results, width=15) save_result_btn.grid(row=1, column=0, padx=10, pady=2, sticky="ew") clear_btn = ttk.Button(calc_frame, text="清除所有", command=self.clear_all, width=15) clear_btn.grid(row=2, column=0, padx=10, pady=2, sticky="ew") def browse_file(self): """浏览文件按钮处理函数""" file_path = filedialog.askopenfilename( title="选择文件", filetypes=[("JSON文件", "*.json"), ("所有文件", "*.*")] ) if file_path: self.file_path_entry.delete(0, tk.END) self.file_path_entry.insert(0, file_path) def create_input_panel(self, parent): # 入瞳参数 pupil_frame = ttk.LabelFrame(parent, text="入瞳参数") pupil_frame.pack(fill=tk.X, padx=5, pady=5) ttk.Label(pupil_frame, text="入瞳直径 (mm):").grid(row=0, column=0, padx=5, pady=5, sticky="w") self.entrance_diameter_entry = ttk.Entry(pupil_frame, width=15) self.entrance_diameter_entry.grid(row=0, column=1, padx=5, pady=5) ttk.Label(pupil_frame, text="入瞳位置 (mm):").grid(row=0, column=2, padx=5, pady=5, sticky="w") self.entrance_position_entry = ttk.Entry(pupil_frame, width=15) self.entrance_position_entry.grid(row=0, column=3, padx=5, pady=5) # 色光类型选择 ttk.Label(pupil_frame, text="色光类型:").grid(row=1, column=0, padx=5, pady=5, sticky="w") self.light_type_var = tk.StringVar(value="d") self.light_type_combo = ttk.Combobox(pupil_frame, textvariable=self.light_type_var, width=12, state="readonly") self.light_type_combo["values"] = ("d", "f", "c") self.light_type_combo.grid(row=1, column=1, padx=5, pady=5, sticky="w") # 添加孔径系数和视场系数输入 ttk.Label(pupil_frame, text="孔径系数:").grid(row=1, column=2, padx=5, pady=5, sticky="w") self.aperture_coeff_entry = ttk.Entry(pupil_frame, width=8) self.aperture_coeff_entry.insert(0, "1.0") self.aperture_coeff_entry.grid(row=1, column=3, padx=5, pady=5) ttk.Label(pupil_frame, text="视场系数:").grid(row=1, column=4, padx=5, pady=5, sticky="w") self.field_coeff_entry = ttk.Entry(pupil_frame, width=8) self.field_coeff_entry.insert(0, "1.0") self.field_coeff_entry.grid(row=1, column=5, padx=5, pady=5) # 物方参数 object_frame = ttk.LabelFrame(parent, text="物方参数") object_frame.pack(fill=tk.X, padx=5, pady=5) # 物距选择 self.object_var = tk.BooleanVar(value=True) # True: 无穷远, False: 有限远 ttk.Radiobutton(object_frame, text="物在无穷远", variable=self.object_var, value=True, command=self.toggle_object_input).grid(row=0, column=0, padx=5, pady=5) ttk.Radiobutton(object_frame, text="物在有限远", variable=self.object_var, value=False, command=self.toggle_object_input).grid(row=0, column=1, padx=5, pady=5) # 无穷远参数 self.infinite_frame = ttk.Frame(object_frame) self.infinite_frame.grid(row=1, column=0, columnspan=2, sticky="w", padx=5, pady=5) ttk.Label(self.infinite_frame, text="半视场角 (度):").grid(row=0, column=0, padx=5, pady=5, sticky="w") self.field_angle_entry = ttk.Entry(self.infinite_frame, width=15) self.field_angle_entry.grid(row=0, column=1, padx=5, pady=5) # 有限远参数 (初始隐藏) self.finite_frame = ttk.Frame(object_frame) self.finite_frame.grid(row=1, column=0, columnspan=2, sticky="w", padx=5, pady=5) self.finite_frame.grid_remove() # 初始隐藏 ttk.Label(self.finite_frame, text="物距 (mm):").grid(row=0, column=0, padx=5, pady=5, sticky="w") self.object_distance_entry = ttk.Entry(self.finite_frame, width=15) self.object_distance_entry.grid(row=0, column=1, padx=5, pady=5) ttk.Label(self.finite_frame, text="物高 (mm):").grid(row=0, column=2, padx=5, pady=5, sticky="w") self.object_height_entry = ttk.Entry(self.finite_frame, width=15) self.object_height_entry.grid(row=0, column=3, padx=5, pady=5) ttk.Label(self.finite_frame, text="孔径角 (度):").grid(row=0, column=4, padx=5, pady=5, sticky="w") self.aperture_angle_entry = ttk.Entry(self.finite_frame, width=15) self.aperture_angle_entry.grid(row=0, column=5, padx=5, pady=5) # 光学表面输入 surface_frame = ttk.LabelFrame(parent, text="光学表面参数") surface_frame.pack(fill=tk.BOTH, expand=True, padx=5, pady=5) # 表面输入控件 input_frame = ttk.Frame(surface_frame) input_frame.pack(fill=tk.X, padx=5, pady=5) ttk.Label(input_frame, text="曲率半径 (mm):").grid(row=0, column=0, padx=4, pady=5) self.radius_entry = ttk.Entry(input_frame, width=6) self.radius_entry.grid(row=0, column=1, padx=3, pady=5) self.radius_entry.insert(0, "50") ttk.Label(input_frame, text="厚度 (mm):").grid(row=0, column=2, padx=4, pady=5) self.thickness_entry = ttk.Entry(input_frame, width=6) self.thickness_entry.grid(row=0, column=3, padx=3, pady=5) self.thickness_entry.insert(0, "5") ttk.Label(input_frame, text="折射率 (nd):").grid(row=0, column=4, padx=4, pady=5) self.nd_entry = ttk.Entry(input_frame, width=6) self.nd_entry.grid(row=0, column=5, padx=3, pady=5) self.nd_entry.insert(0, "1.5") ttk.Label(input_frame, text="折射率 (nf):").grid(row=0, column=6, padx=4, pady=5) self.nf_entry = ttk.Entry(input_frame, width=6) self.nf_entry.grid(row=0, column=7, padx=3, pady=5) self.nf_entry.insert(0, "1.52") # 默认值 ttk.Label(input_frame, text="折射率 (nc):").grid(row=0, column=8, padx=4, pady=5) self.nc_entry = ttk.Entry(input_frame, width=6) self.nc_entry.grid(row=0, column=9, padx=3, pady=5) self.nc_entry.insert(0, "1.48") # 默认值 button_frame = ttk.Frame(input_frame) button_frame.grid(row=0, column=10, padx=8) add_btn = ttk.Button(button_frame, text="添加表面", command=self.add_surface) add_btn.pack(side=tk.LEFT, padx=4) remove_btn = ttk.Button(button_frame, text="删除表面", command=self.remove_surface) remove_btn.pack(side=tk.LEFT, padx=4) # 表面列表 list_frame = ttk.Frame(surface_frame) list_frame.pack(fill=tk.BOTH, expand=True, padx=4, pady=5) columns = ("#", "曲率半径 (mm)", "厚度 (mm)", "折射率 (nd)", "折射率 (nf)","折射率 (nc)") self.surface_tree = ttk.Treeview(list_frame, columns=columns, show="headings", height=8) for col in columns: self.surface_tree.heading(col, text=col) self.surface_tree.column(col, width=80, anchor=tk.CENTER) vsb = ttk.Scrollbar(list_frame, orient="vertical", command=self.surface_tree.yview) self.surface_tree.configure(yscrollcommand=vsb.set) self.surface_tree.pack(side=tk.LEFT, fill=tk.BOTH, expand=True) vsb.pack(side=tk.RIGHT, fill=tk.Y) def create_result_panel(self, parent): # 结果文本框 self.result_text = tk.Text(parent, wrap=tk.WORD) result_scroll_y = ttk.Scrollbar(parent, orient="vertical", command=self.result_text.yview) result_scroll_x = ttk.Scrollbar(parent, orient="horizontal", command=self.result_text.xview) self.result_text.configure(yscrollcommand=result_scroll_y.set, xscrollcommand=result_scroll_x.set) result_scroll_y.pack(side=tk.RIGHT, fill=tk.Y) result_scroll_x.pack(side=tk.BOTTOM, fill=tk.X) self.result_text.pack(side=tk.LEFT, fill=tk.BOTH, expand=True) # 设置初始文本 self.result_text.insert(tk.END, "计算结果将显示在此处...\n\n") self.result_text.configure(state=tk.DISABLED) def toggle_object_input(self): """切换物方参数输入界面""" if self.object_var.get(): # 无穷远 self.infinite_frame.grid() self.finite_frame.grid_remove() else: # 有限远 self.infinite_frame.grid_remove() self.finite_frame.grid() def add_surface(self): """添加光学表面""" try: # 获取输入值 r = self.radius_entry.get().strip() d = self.thickness_entry.get().strip() nd = self.nd_entry.get().strip() nf = self.nf_entry.get().strip() nc = self.nc_entry.get().strip() # 处理输入值 r = float(r) if r and r.lower() != "inf" else float('inf') d = float(d) if d else 0.0 nd = float(nd) if nd else 1.0 nf = float(nf) if nf else 1.0 nc = float(nc) if nc else 1.0 # 添加到系统 surface = Surface(r, d, nd, nf, nc) self.system.surfaces.append(surface) # 添加到树形视图 r_str = "平面" if r == float('inf') else f"{r:.2f}" self.surface_tree.insert("", "end", values=( len(self.system.surfaces), r_str, f"{d:.2f}", f"{nd:.8f}", f"{nf:.8f}", f"{nc:.8f}" )) # 清空输入框 self.radius_entry.delete(0, tk.END) self.thickness_entry.delete(0, tk.END) self.nd_entry.delete(0, tk.END) self.nf_entry.delete(0, tk.END) self.nc_entry.delete(0, tk.END) self.radius_entry.focus_set() except ValueError: messagebox.showerror("输入错误", "请输入有效的数字") def remove_surface(self): """删除选中的光学表面""" selected = self.surface_tree.selection() if selected: # 从树形视图中删除 for item in selected: index = int(self.surface_tree.item(item, "values")[0]) - 1 self.surface_tree.delete(item) # 从系统中删除 if 0 <= index < len(self.system.surfaces): self.system.surfaces.pop(index) # 更新剩余表面的序号 for i, item in enumerate(self.surface_tree.get_children()): values = list(self.surface_tree.item(item, "values")) values[0] = i + 1 self.surface_tree.item(item, values=values) def load_system(self): """加载系统参数文件""" file_path = self.file_path_entry.get().strip() if not file_path: messagebox.showwarning("警告", "请输入文件路径") return try: with open(file_path, 'r') as f: data = json.load(f) # 加载系统参数 self.system.entrance_pupil_diameter = data.get("entrance_pupil_diameter") self.system.entrance_pupil_position = data.get("entrance_pupil_position") self.system.object_infinite = data.get("object_infinite", True) self.system.field_angle = data.get("field_angle") self.system.object_distance = data.get("object_distance") self.system.object_height = data.get("object_height") self.system.aperture_angle = data.get("aperture_angle") self.system.aperture_coefficient = data.get("aperture_coefficient", 1.0) self.system.field_coefficient = data.get("field_coefficient", 1.0) # 更新UI中的参数值 if self.system.entrance_pupil_diameter is not None: self.entrance_diameter_entry.delete(0, tk.END) self.entrance_diameter_entry.insert(0, str(self.system.entrance_pupil_diameter)) if self.system.entrance_pupil_position is not None: self.entrance_position_entry.delete(0, tk.END) self.entrance_position_entry.insert(0, str(self.system.entrance_pupil_position)) self.object_var.set(self.system.object_infinite) self.toggle_object_input() if self.system.field_angle is not None: self.field_angle_entry.delete(0, tk.END) self.field_angle_entry.insert(0, str(self.system.field_angle)) if self.system.object_distance is not None: self.object_distance_entry.delete(0, tk.END) self.object_distance_entry.insert(0, str(self.system.object_distance)) if self.system.object_height is not None: self.object_height_entry.delete(0, tk.END) self.object_height_entry.insert(0, str(self.system.object_height)) if self.system.aperture_angle is not None: self.aperture_angle_entry.delete(0, tk.END) self.aperture_angle_entry.insert(0, str(self.system.aperture_angle)) if self.aperture_coeff_entry.get(): self.system.aperture_coefficient = float(self.aperture_coeff_entry.get()) if self.field_coeff_entry.get(): self.system.field_coefficient = float(self.field_coeff_entry.get()) # 加载表面数据 self.system.surfaces = [] self.surface_tree.delete(*self.surface_tree.get_children()) surfaces_data = data.get("surfaces", []) for surf_data in surfaces_data: surface = Surface.from_dict(surf_data) self.system.surfaces.append(surface) r_str = "平面" if surface.r == float('inf') else f"{surface.r:.2f}" self.surface_tree.insert("", "end", values=( len(self.system.surfaces), r_str, f"{surface.d:.2f}", f"{surface.nd:.8f}", f"{surface.nf:.8f}", f"{surface.nc:.8f}" )) messagebox.showinfo("成功", f"系统参数已从 {os.path.basename(file_path)} 加载") # 显示加载的系统信息 self.result_text.configure(state=tk.NORMAL) self.result_text.delete(1.0, tk.END) self.result_text.insert(tk.END, f"已加载系统参数文件: {file_path}\n") self.result_text.insert(tk.END, f"包含 {len(self.system.surfaces)} 个光学表面\n") self.result_text.configure(state=tk.DISABLED) except FileNotFoundError: messagebox.showerror("错误", f"文件不存在: {file_path}") except Exception as e: messagebox.showerror("加载错误", f"加载文件失败: {str(e)}") def save_system(self): """保存系统参数文件""" # 更新系统参数 if not self.update_system_from_ui(): return # 如果没有表面数据,提示用户 if not self.system.surfaces: messagebox.showwarning("警告", "没有光学表面数据,无法保存") return file_path = self.file_path_entry.get().strip() if not file_path: messagebox.showwarning("警告", "请输入保存路径") return try: # 准备保存数据 data = { "entrance_pupil_diameter": self.system.entrance_pupil_diameter, "entrance_pupil_position": self.system.entrance_pupil_position, "object_infinite": self.system.object_infinite, "field_angle": self.system.field_angle, "object_distance": self.system.object_distance, "object_height": self.system.object_height, "aperture_angle": self.system.aperture_angle, "surfaces": [surf.to_dict() for surf in self.system.surfaces], "aperture_coefficient": self.system.aperture_coefficient, "field_coefficient": self.system.field_coefficient, } with open(file_path, 'w') as f: json.dump(data, f, indent=4) messagebox.showinfo("成功", f"系统参数已保存到 {os.path.basename(file_path)}") # 显示保存信息 self.result_text.configure(state=tk.NORMAL) self.result_text.insert(tk.END, f"系统参数已保存到: {file_path}\n") self.result_text.configure(state=tk.DISABLED) except Exception as e: messagebox.showerror("保存错误", f"保存文件失败: {str(e)}") def save_results(self): """保存计算结果到文件""" if not self.system.results or all(v is None for v in self.system.results.values()): messagebox.showwarning("警告", "没有计算结果可保存") return file_path = filedialog.asksaveasfilename( title="保存计算结果", defaultextension=".txt", filetypes=[("文本文件", "*.txt"), ("所有文件", "*.*")] ) if not file_path: return try: with open(file_path, 'w') as f: # 写入系统参数摘要 f.write("===== 光学系统参数 =====\n") f.write(f"入瞳直径: {self.system.entrance_pupil_diameter} mm\n") f.write(f"入瞳位置: {self.system.entrance_pupil_position} mm\n") f.write(f"色光类型: {self.system.light_type}\n") f.write("物距类型: " + ("无穷远" if self.system.object_infinite else "有限远") + "\n") if self.system.object_infinite: f.write(f"半视场角: {self.system.field_angle} 度\n") else: f.write(f"物距: {self.system.object_distance} mm\n") f.write(f"物高: {self.system.object_height} mm\n") f.write(f"孔径角: {self.system.aperture_angle} 度\n") f.write("\n光学表面参数:\n") for i, surf in enumerate(self.system.surfaces): r_str = "平面" if surf.r == float('inf') else f"{surf.r:.2f} mm" f.write(f"表面 {i+1}: r={r_str}, d={surf.d:.2f} mm, nd={surf.nd:.8f}, nf={surf.nf:.8f}, nc={surf.nc:.8f}\n") # 写入计算结果 f.write("\n\n===== 计算结果 =====\n") for key, value in self.system.results.items(): if value is not None: # 格式化键名 label = self.format_result_label(key) f.write(f"{label}: {value}\n") messagebox.showinfo("成功", f"计算结果已保存到 {os.path.basename(file_path)}") # 显示保存信息 self.result_text.configure(state=tk.NORMAL) self.result_text.insert(tk.END, f"计算结果已保存到: {file_path}\n") self.result_text.configure(state=tk.DISABLED) except Exception as e: messagebox.showerror("保存错误", f"保存计算结果失败: {str(e)}") def format_result_label(self, key): """格式化结果标签为中文描述""" labels = { "focal_length": "焦距 f' (mm)", "ideal_image_distance": "理想像距 l' (mm)", "actual_image_position": "实际像位置 (mm)", "image_principal_plane": "像方主面位置 lH' (mm)", "exit_pupil_distance": "出瞳距 lp' (mm)", "ideal_image_height": "理想像高 y0' (mm)", "spherical_aberration": "球差 (mm)", "longitudinal_chromatic": "位置色差 (mm)", "tangential_field_curvature": "子午场曲 xt' (mm)", "sagittal_field_curvature": "弧矢场曲 xs' (mm)", "astigmatism": "像散 Δxts' (mm)", "actual_image_height": "实际像高 (mm)", "relative_distortion": "相对畸变 (%)", "absolute_distortion": "绝对畸变 (mm)", "lateral_chromatic": "倍率色差 (mm)", "tangential_coma": "子午慧差 (mm)" } return labels.get(key, key) def update_system_from_ui(self): """从UI更新系统参数""" try: # 入瞳参数 if self.entrance_diameter_entry.get(): self.system.entrance_pupil_diameter = float(self.entrance_diameter_entry.get()) if self.entrance_position_entry.get(): self.system.entrance_pupil_position = float(self.entrance_position_entry.get()) # 色光类型 self.system.light_type = self.light_type_var.get() # 孔径系数 if self.aperture_coeff_entry.get(): self.system.aperture_coefficient = float(self.aperture_coeff_entry.get()) # 视场系数 if self.field_coeff_entry.get(): self.system.field_coefficient = float(self.field_coeff_entry.get()) # 物方参数 self.system.object_infinite = self.object_var.get() if self.system.object_infinite: if self.field_angle_entry.get(): self.system.field_angle = float(self.field_angle_entry.get()) else: if self.object_distance_entry.get(): self.system.object_distance = float(self.object_distance_entry.get()) if self.object_height_entry.get(): self.system.object_height = float(self.object_height_entry.get()) if self.aperture_angle_entry.get(): self.system.aperture_angle = float(self.aperture_angle_entry.get()) except ValueError: messagebox.showerror("输入错误", "请输入有效的数字") return False return True def calculate(self): """执行光学计算""" # 更新系统参数 if not self.update_system_from_ui(): return # 检查必要参数 if not self.system.surfaces: messagebox.showwarning("警告", "请至少添加一个光学表面") return if self.system.entrance_pupil_diameter is None: messagebox.showwarning("警告", "请输入入瞳直径") return if self.system.object_infinite and self.system.field_angle is None: messagebox.showwarning("警告", "请输入半视场角") return if not self.system.object_infinite and ( self.system.object_distance is None or self.system.object_height is None or self.system.aperture_angle is None ): messagebox.showwarning("警告", "请输入完整的有限远参数") return # 执行计算 - 这里调用您的计算函数 self.perform_calculations() # 显示结果 self.display_results() # 显示计算完成消息 messagebox.showinfo("计算完成", "光学计算已完成,结果已显示在结果区域") def perform_calculations(self): """执行光学计算 - 这里调用计算函数""" # 重置结果 for key in self.system.results: self.system.results[key] = None # 示例:设置一些假结果用于演示 # 实际应用中,您需要调用您自己的计算函数 self.system.results["focal_length"] = calculate.calculate_focal_length(self.system.surfaces) self.system.results["ideal_image_distance"] = calculate.calculate_ideal_image_distance(self.system.surfaces,self.system.object_infinite, self.system.object_distance) self.system.results["actual_image_position"] = calculate.calculate_actual_image(self.system, self.system.light_type) self.system.results["image_principal_plane"] = calculate.calculate_principal_plane_position(self.system.surfaces) self.system.results["exit_pupil_distance"] = calculate.calculate_exit_pupil_distance(self.system.surfaces,self.system.entrance_pupil_position) self.system.results["ideal_image_height"] = calculate.calculate_ideal_image_height(self.system) self.system.results["spherical_aberration"] = calculate.calculate_spherical_aberration(self.system) self.system.results["longitudinal_chromatic"] = calculate.calculate_longitudinal_chromatic(self.system) self.system.results["tangential_field_curvature"] = calculate.calculate_astigmatism(self.system,self.system.light_type)[0] self.system.results["sagittal_field_curvature"] = calculate.calculate_astigmatism(self.system,self.system.light_type)[1] self.system.results["astigmatism"] = calculate.calculate_astigmatism(self.system,self.system.light_type)[2] self.system.results["actual_image_height"] = calculate.calculate_actual_image_height(self.system,self.system.light_type) self.system.results["relative_distortion"] = calculate.calculate_relative_distortion(self.system,self.system.light_type) self.system.results["absolute_distortion"] = calculate.calculate_absolute_distortion(self.system,self.system.light_type) self.system.results["lateral_chromatic"] = calculate.calculate_lateral_chromatic(self.system) self.system.results["tangential_coma"] = calculate.calculate_tangential_coma(self.system) def display_results(self): """在结果文本框中显示计算结果""" self.result_text.configure(state=tk.NORMAL) self.result_text.delete(1.0, tk.END) # 添加系统参数摘要 self.result_text.insert(tk.END, "===== 光学系统参数 =====\n", "title") self.result_text.insert(tk.END, f"入瞳直径: {self.system.entrance_pupil_diameter} mm\n") self.result_text.insert(tk.END, f"入瞳位置: {self.system.entrance_pupil_position} mm\n") self.result_text.insert(tk.END, "物距类型: " + ("无穷远" if self.system.object_infinite else "有限远") + "\n") self.result_text.insert(tk.END, f"色光类型: {self.system.light_type}\n") self.result_text.insert(tk.END, f"孔径系数: {self.system.aperture_coefficient}\n") self.result_text.insert(tk.END, f"视场系数: {self.system.field_coefficient}\n") if self.system.object_infinite: self.result_text.insert(tk.END, f"半视场角: {self.system.field_angle} 度\n") else: self.result_text.insert(tk.END, f"物距: {self.system.object_distance} mm\n") self.result_text.insert(tk.END, f"物高: {self.system.object_height} mm\n") self.result_text.insert(tk.END, f"孔径角: {self.system.aperture_angle} 度\n") self.result_text.insert(tk.END, "\n光学表面参数:\n") for i, surf in enumerate(self.system.surfaces): r_str = "平面" if surf.r == float('inf') else f"{surf.r:.2f} mm" self.result_text.insert(tk.END, f"表面 {i+1}: r={r_str}, d={surf.d:.2f} mm, nd={surf.nd:.8f}, nf={surf.nf:.8f}, nc={surf.nc:.8f}\n") # 添加计算结果 self.result_text.insert(tk.END, "\n\n===== 计算结果 =====\n", "title") # 计算关键结果 key_results = [ "focal_length", "ideal_image_distance", "actual_image_position", "image_principal_plane", "exit_pupil_distance", "ideal_image_height" ] for key in key_results: if self.system.results[key] is not None: label = self.format_result_label(key) self.result_text.insert(tk.END, f"{label}: {self.system.results[key]}\n") # 添加像差结果 self.result_text.insert(tk.END, "\n像差分析:\n", "subtitle") aberrations = [ "spherical_aberration", "longitudinal_chromatic", "tangential_field_curvature", "sagittal_field_curvature", "astigmatism", "actual_image_height", "relative_distortion", "absolute_distortion", "lateral_chromatic", "tangential_coma" ] for key in aberrations: if self.system.results[key] is not None: label = self.format_result_label(key) self.result_text.insert(tk.END, f"{label}: {self.system.results[key]}\n") self.result_text.configure(state=tk.DISABLED) def clear_all(self): """清除所有输入和结果""" # 清除系统参数 self.system = OpticalSystem() # 清除UI输入 self.file_path_entry.delete(0, tk.END) self.entrance_diameter_entry.delete(0, tk.END) self.entrance_position_entry.delete(0, tk.END) self.field_angle_entry.delete(0, tk.END) self.object_distance_entry.delete(0, tk.END) self.object_height_entry.delete(0, tk.END) self.aperture_angle_entry.delete(0, tk.END) self.aperture_coeff_entry.delete(0, tk.END) self.aperture_coeff_entry.insert(0, "1") self.field_coeff_entry.delete(0, tk.END) self.field_coeff_entry.insert(0, "0") self.radius_entry.delete(0, tk.END) self.radius_entry.insert(0, "50") self.thickness_entry.delete(0, tk.END) self.thickness_entry.insert(0, "5") self.nd_entry.delete(0, tk.END) self.nd_entry.insert(0, "1.5") self.nf_entry.delete(0, tk.END) self.nf_entry.insert(0, "1.5") self.nc_entry.delete(0, tk.END) self.nc_entry.insert(0, "1.5") # 清除表面列表 self.surface_tree.delete(*self.surface_tree.get_children()) self.system.surfaces = [] # 清除结果 self.result_text.configure(state=tk.NORMAL) self.result_text.delete(1.0, tk.END) self.result_text.insert(tk.END, "计算结果将显示在此处...\n\n") self.result_text.configure(state=tk.DISABLED) # 重置物距类型 self.object_var.set(True) self.toggle_object_input() messagebox.showinfo("清除完成", "所有输入和结果已清除") def load_default_settings(self): """加载默认设置(可选)""" # 这里可以添加加载默认设置的逻辑 pass if __name__ == "__main__": root = tk.Tk() app = MainApplication(root) # 设置文本样式 app.result_text.tag_config("title", font=("Arial", 10, "bold")) app.result_text.tag_config("subtitle", font=("Arial", 9, "bold")) root.mainloop() 这里计算用的参数和输入的参数对应吗?为什么我只是稍微修改了一点GUI的界面,现在计算结果全错了
最新发布
06-30
from re import A import tkinter as tk from tkinter import ttk, messagebox, filedialog import json import os import math import numpy as np class OpticalSystem: def __init__(self): self.surfaces = [] # 存储光学表面对象 self.entrance_pupil_diameter = None # 入瞳直径 (mm) self.entrance_pupil_position = None # 入瞳位置 (相对第一个面顶点) (mm) self.object_infinite = True # 物在无穷远 self.field_angle = None # 半视场角 (度) self.object_distance = None # 物距 (有限远) (mm) self.object_height = None # 物高 (有限远) (mm) self.aperture_angle = None # 孔径角 (有限远) (度) self.light_type = "d" # 色光类型,默认d光 self.aperture_coefficient = 1.0 # 孔径系数 self.field_coefficient = 1.0 # 视场系数 # 计算结果存储 self.results = { "focal_length": None, # 焦距 f' "ideal_image_distance": None, # 理想像距 l' "actual_image_position": None, # 实际像位置 "image_principal_plane": None, # 像方主面位置 lH' "exit_pupil_distance": None, # 出瞳距 lp' "ideal_image_height": None, # 理想像高 y0' "spherical_aberration": None, # 球差 "longitudinal_chromatic": None, # 位置色差 "tangential_field_curvature": None, # 子午场曲 xt' "sagittal_field_curvature": None, # 弧矢场曲 xs' "astigmatism": None, # 像散 Δxts' "actual_image_height": None, # 实际像高 "relative_distortion": None, # 相对畸变 "absolute_distortion": None, # 绝对畸变 "lateral_chromatic": None, # 倍率色差 "tangential_coma": None # 子午慧差 } class Surface: def __init__(self, r=float('inf'), d=0.0, nd=1.0, vd=0.0): self.r = r # 曲率半径 (mm) self.d = d # 厚度/间隔 (mm) self.nd = nd # d光折射率 self.vd = vd # 阿贝数 def to_dict(self): """将表面数据转换为字典""" return { "r": self.r, "d": self.d, "nd": self.nd, "vd": self.vd } @classmethod def from_dict(cls, data): """从字典创建表面对象""" return cls( r=data.get('r', float('inf')), d=data.get('d', 0.0), nd=data.get('nd', 1.0), vd=data.get('vd', 0.0) ) class calculate: def trace_paraxial_ray(surfaces, h0, u0, light_type='d',n0=1.0): """ 近轴光线追迹函数 :param surfaces: 光学表面列表 :param h0: 初始光线高度 :param u0: 初始光线角度(弧度) :param n0: 初始介质折射率 :return: 最后的光线高度和角度 """ h = h0 u = u0 n = n0 # 当前介质折射率 for i, surf in enumerate(surfaces): # 计算曲率(平面时曲率为0) c = 0.0 if math.isinf(surf.r) else 1.0 / surf.r # 折射公式:n'u' = nu + (n - n') * c * h # 选择色光折射率 if light_type == 'd': n_prime = surf.nd elif light_type == 'f': n_prime = surf.nd + (surf.nd - 1) / (2 * surf.vd) elif light_type == 'c': n_prime = surf.nd - (surf.nd - 1) / (3 * surf.vd) else: n_prime = surf.nd # 默认d光 u_prime = (n * u + (n - n_prime) * c * h) / n_prime # 如果当前不是最后一个面,计算传播到下个面的高度 if i < len(surfaces) - 1: d = surf.d # 到下一个面的距离 h_next = h + d * u_prime else: h_next = h # 最后一个面后不需要传播 # 更新参数 h = h_next u = u_prime n = n_prime # 更新为当前面后的折射率 return h, u def calculate_focal_length(surfaces,light_type): """ 计算系统焦距 :param surfaces: 光学表面列表 :return: 焦距值(mm) """ # 追迹平行于光轴的光线(无穷远物) h0 = 1.0 # 任意高度,取1便于计算 u0 = 0.0 # 平行于光轴 h_final, u_final = calculate.trace_paraxial_ray(surfaces, h0, u0,light_type) # 焦距 f' = -h0 / u_final if abs(u_final) < 1e-10: # 防止除零错误 return float('inf') return -h0 / u_final def calculate_ideal_image_distance(surfaces, object_infinite, object_distance=None,light_type= 'd'): """ 计算理想像距 :param surfaces: 光学表面列表 :param object_infinite: 物是否在无穷远 :param object_distance: 物距(有限远时) :return: 理想像距(mm) """ if object_infinite: # 无穷远物:理想像距等于焦距对应的像距 return calculate.calculate_focal_length(surfaces,light_type)+calculate.calculate_principal_plane_position(surfaces,light_type) else: # 有限远物:使用高斯公式计算理想像距 if object_distance is None: raise ValueError("有限远物需要提供物距") # 计算系统焦距 f_prime = calculate.calculate_focal_length(surfaces,light_type) # 高斯公式:1/f' = 1/l' - 1/l # 其中 l 为物距(负值),l' 为像距 l = -object_distance # 物距为负值(物在左侧) # 计算像距 l' if abs(f_prime) < 1e-10: return float('inf') l_prime = 1 / (1/f_prime + 1/l) l_prime = l_prime+calculate.calculate_principal_plane_position(surfaces,light_type) return l_prime def calculate_principal_plane_position(surfaces,light_type): """ 计算像方主面位置 :param surfaces: 光学表面列表 :return: 主面位置(相对于最后一个面顶点,正值表示在右侧) """ # 计算焦距 f_prime = calculate.calculate_focal_length(surfaces,light_type) # 追迹平行于光轴的光线 h0 = 1.0 # 初始高度 u0 = 0.0 # 平行于光轴 h_final, u_final = calculate.trace_paraxial_ray(surfaces, h0, u0,light_type) # 主面位置 lH' = -h_final / u_final - f_prime if abs(u_final) < 1e-10: return float('inf') return -h_final / u_final - f_prime def calculate_exit_pupil_distance(surfaces, entrance_pupil_position,): """ 计算系统的出瞳距 :param surfaces: 光学表面列表 :param entrance_pupil_position: 入瞳位置(相对于第一个面顶点) :return: 出瞳距(相对于最后一个面顶点) """ # 定义初始光线参数 u0 = 0.01 # 小角度(弧度) # 计算第一个面的光线高度 h0 = -entrance_pupil_position * u0 # 进行近轴光线追迹 h_final, u_final = calculate.trace_paraxial_ray(surfaces, h0, u0) # 计算出瞳距:l' = -h_final / u_final if abs(u_final) < 1e-10: # 防止除零错误 return float('inf') return -h_final / u_final def calculate_ideal_image_height(system): """ 计算理想像高 :param system: OpticalSystem对象 :return: 理想像高(mm) """ # 获取系统焦距 focal_length = calculate.calculate_focal_length(system.surfaces,system.light_type) if system.object_infinite: # 无穷远物 # 理想像高 y0' = -f' * tan(ω) field_angle_rad = math.radians(system.field_angle) return -focal_length * math.tan(field_angle_rad) else: # 有限远物 # 获取理想像距 ideal_image_distance = calculate.calculate_ideal_image_distance( system.surfaces, system.object_infinite, system.object_distance, system.light_type ) # 获取主面位置 principal_plane = calculate.calculate_principal_plane_position(system.surfaces,system.light_type) # 计算实际像位置(从最后一个面顶点) actual_image_position = ideal_image_distance + principal_plane # 计算放大率 β = l'/l # l = -object_distance(物在左侧为负) magnification = actual_image_position / (-system.object_distance) # 理想像高 y0' = β * y return magnification * system.object_height def trace_real_ray(surfaces, h0, u0, l0,light_type): """ 实际光线追迹函数 :param surfaces: 光学表面列表 :param h0: 初始光线高度 :param u0: 初始光线角度(弧度) :param l0: 初始光线距离(mm) :return: 最后的光线距离和角度 """ h = h0 u = u0 L = l0 # 当前光线距离 npre = 1 LL = [] PA =[] LI =[] LR =[] LW = [L] UU = [u] #初始化内部变量 si = 0 sii = 0 uu = 0 for i, surf in enumerate(surfaces): # 选择色光折射率 if light_type == 'd': n_surf = surf.nd elif light_type == 'f': n_surf = surf.nd + (surf.nd - 1) / (2 * surf.vd) elif light_type == 'c': n_surf = surf.nd - (surf.nd - 1) / (3 * surf.vd) else: n_surf = surf.nd # 默认d光 # 计算曲率(平面时曲率为0) c = 0.0 if math.isinf(surf.r) else 1.0 / surf.r if(i == 0 and u==0.0): si = h/surf.r else: si = (L-surf.r)*np.sin(u)/surf.r sii = npre*si/n_surf uu = u +np.arcsin(si)-np.arcsin(sii) L = surf.r+surf.r*sii/np.sin(uu) PA .append( L * np.sin(uu) / np.cos((np.arcsin(sii)-uu)/2)) LL.append(L) UU.append(uu) LI.append(np.arcsin(si)) LR.append(np.arcsin(sii)) #传递到下一个表面 if i < len(surfaces) - 1: u = uu L = L -surf.d npre = n_surf # 折射后折射率 LW.append(L) return LW, LL,UU,LI,LR,PA def calculate_actual_image(system,light_type): """ 计算轴上点的实际像位置(相对于最后一个面顶点) 参数: system: OpticalSystem对象,包含: - surfaces: 表面列表 - entrance_pupil_diameter: 入瞳直径 (mm) - entrance_pupil_position: 入瞳位置 (相对第一个面顶点) (mm) - aperture_coefficient: 孔径系数 (0~1) - object_infinite: 物是否在无穷远 - object_distance: 物距 (有限远时) (mm) - light_type: 色光类型 (这里只影响折射率选择) 返回: 实际像位置 (mm) (正值表示在最后一个面右侧) """ # 1. 计算实际入瞳半径 actual_entrance_radius = (system.entrance_pupil_diameter * system.aperture_coefficient) / 2 # 2. 根据物方情况设置初始光线参数 if system.object_infinite: # 无穷远物:光线平行于光轴 u0 = 0.0 # 初始角度 (弧度) h0 = actual_entrance_radius # 初始高度 (取入瞳边缘) l0 = 0 # 物方截距 (无穷远) L_final = calculate.trace_real_ray(system.surfaces, h0, u0, l0,light_type)[1] else: # 有限远物 # 计算物点到入瞳平面的距离 d_object_to_entrance = system.object_distance - system.entrance_pupil_position # 计算初始角度 (物点发出的光线通过入瞳边缘) u0 = math.atan(actual_entrance_radius/ d_object_to_entrance) l0 = system.object_distance # 负号表示在左侧 h0 = 0 L_final= calculate.trace_real_ray(system.surfaces, h0, u0, l0,light_type)[1] return L_final[-1] def calculate_spherical_aberration(system): # 计算实际像位置 actual_image_position = calculate.calculate_actual_image(system,system.light_type) # 计算理想像距 ideal_image_distance = calculate.calculate_ideal_image_distance( system.surfaces, system.object_infinite, system.object_distance ) # 计算球差 return actual_image_position - ideal_image_distance def calculate_longitudinal_chromatic(system): #计算位置色差 #F光 imageF = calculate.calculate_actual_image(system,'f') #C光 imageC = calculate.calculate_actual_image(system,'c') return imageF -imageC def calculate_actual_image_height(system,light_type): """ 计算实际像高(主光线在像平面上的高度) 参数: system: OpticalSystem对象 返回: 实际像高 (mm) """ # 1. 计算像面位置(相对于最后一个面顶点) l_prime = calculate.calculate_ideal_image_distance( system.surfaces, system.object_infinite, system.object_distance ) # 2. 确定主光线初始参数 if system.object_infinite: # 无限远物 omega_rad = math.radians(system.field_angle) u0 = omega_rad # 主光线角度 h0 = 0 L0 = system.entrance_pupil_position else: # 有限远物 d_obj = system.object_distance - system.entrance_pupil_position u0 = math.atan(system.object_height / d_obj) d0 = -system.entrance_pupil_position h0 = d0 * math.tan(u0) L0 = system.entrance_pupil_position # 3. 追迹主光线 L_last = calculate.trace_real_ray(system.surfaces, h0, u0, L0,light_type)[1] u_last = calculate.trace_real_ray(system.surfaces, h0, u0, L0,light_type)[2] # 4. 计算实际像高 actual_image_height = (L_last[-1] - l_prime) * math.tan(u_last[-1]) return actual_image_height def calculate_astigmatism(system, light_type): # 1. 获取主光线参数 if system.object_infinite: omega_rad = math.radians(system.field_angle) u0 = omega_rad h0 = 0 L0 = system.entrance_pupil_position else: d_obj = system.object_distance - system.entrance_pupil_position u0 = math.atan(system.object_height / d_obj) h0 = -system.entrance_pupil_position * math.tan(u0) L0 = system.entrance_pupil_position # 2. 追迹主光线获取入射/折射角 _, _, UU, LI, LR, PA = calculate.trace_real_ray(system.surfaces, h0, u0, L0, light_type) # 3. 初始化子午和弧矢截距 n = 1.0 # 初始介质折射率(空气) t = s = 0.0 # 根据物方条件设置初始截距 if system.object_infinite: t = s = float('inf') else: t = s = -system.object_distance # 物在左侧为负 # 4. 逐面计算 for i, surf in enumerate(system.surfaces): # 获取当前面折射率 if light_type == 'd': n_prime = surf.nd elif light_type == 'f': n_prime = surf.nd + (surf.nd - 1) / (2 * surf.vd) elif light_type == 'c': n_prime = surf.nd - (surf.nd - 1) / (3 * surf.vd) else: n_prime = surf.nd # 计算曲率 c = 0.0 if math.isinf(surf.r) else 1.0 / surf.r # 获取主光线角度 U = UU[i] I = LI[i] I_prime = LR[i] # Coddington方程计算新截距 # 子午光线 if math.isinf(t): num_t = n_prime * math.cos(I_prime)**2 den_t = (n_prime * math.cos(I_prime) - n * math.cos(I)) * c t_prime = num_t / den_t if den_t != 0 else float('inf') else: term_t = (n_prime * math.cos(I_prime) - n * math.cos(I)) * c t_prime = n_prime * math.cos(I_prime)**2 / (term_t + n * math.cos(I)**2 / t) # 弧矢光线 if math.isinf(s): num_s = n_prime den_s = (n_prime * math.cos(I_prime) - n * math.cos(I)) * c s_prime = num_s / den_s if den_s != 0 else float('inf') else: term_s = (n_prime * math.cos(I_prime) - n * math.cos(I)) * c s_prime = n_prime / (term_s + n / s) # 5. 面间过渡(最后一面前) if i < len(system.surfaces) - 1: # 计算沿主光线方向的实际距离 d_eff = surf.d / math.cos(U) # 更新截距 t = t_prime - d_eff s = s_prime - d_eff n = n_prime # 更新折射率 # 6. 计算理想像距作为参考 ideal_image_distance = calculate.calculate_ideal_image_distance( system.surfaces, system.object_infinite, system.object_distance ) # 7. 计算场曲和像散 # 子午场曲 = 子午焦点位置 - 理想像面位置 xt_prime = t_prime - ideal_image_distance # 弧矢场曲 = 弧矢焦点位置 - 理想像面位置 xs_prime = s_prime - ideal_image_distance # 像散 = 子午场曲 - 弧矢场曲 delta_xts = xt_prime - xs_prime return xt_prime, xs_prime, delta_xts def calculate_relative_distortion(system, light_type): # 1. 计算实际像高 actual_image_height = calculate.calculate_actual_image_height(system,light_type) # 2. 计算理想像高 ideal_image_height = calculate.calculate_ideal_image_height(system) # 3. 绝对畸变 = 实际像高 / 理想像高 if ideal_image_height == 0: return float('inf') return (actual_image_height -ideal_image_height)/ ideal_image_height*100.0 def calculate_absolute_distortion(system, light_type): # 1. 计算实际像高 actual_image_height = calculate.calculate_actual_image_height(system,light_type) # 2. 计算理想像高 ideal_image_height = calculate.calculate_ideal_image_height(system) # 3. 相对畸变 = 实际像高 - 理想像高 return ideal_image_height - actual_image_height def calculate_lateral_chromatic(system): # 计算倍率色差 # F光 imageF = calculate.calculate_actual_image_height(system,'f') # C光 imageC = calculate.calculate_actual_image_height(system,'c') return (imageF - imageC)*1.0 def calculate_tangential_coma(system): ideal_image_Position = calculate.calculate_ideal_image_height(system) aperture_height= system.entrance_pupil_diameter / 2.0* system.aperture_coefficient W=math.radians(system.field_angle) if system.object_infinite and system.field_angle!=0:#无穷远物且有视场角 UpL=-1.0*aperture_height/math.tan(W) DownL=aperture_height/math.tan(W) up_light=calculate.trace_real_ray(system.surfaces,0 , W*(-1.0), UpL,'d') down_light=calculate.trace_real_ray(system.surfaces,0 , W*(-1.0), DownL,'d') center_light= calculate.trace_real_ray(system.surfaces,0 , W*(-1.0), 0,'d') #不考虑出射光线平行的情况 h_up = up_light[1][-1]*math.tan(up_light[2][-1])*(up_light[1][-1]-calculate.calculate_ideal_image_distance(system.surfaces,system.object_infinite))/up_light[1][-1] h_down= down_light[1][-1]*math.tan(down_light[2][-1])*(down_light[1][-1]-calculate.calculate_ideal_image_distance(system.surfaces,system.object_infinite))/down_light[1][-1] h_center = center_light[1][-1]*math.tan(center_light[2][-1])*(center_light[1][-1]-calculate.calculate_ideal_image_distance(system.surfaces,system.object_infinite))/center_light[1][-1] return (h_up + h_down) / 2.0 - h_center else:#有限远物 UpU=math.atan2(math.tan(W)*abs(system.object_distance)+aperture_height,abs(system.object_distance))*(-1.0) UpL=-1.0*aperture_height/math.tan(UpU) DownU = math.atan2(math.tan(W)*abs(system.object_distance)-aperture_height,abs(system.object_distance))*(-1.0) DownL= aperture_height/math.tan(DownU) up_light = calculate.trace_real_ray(system.surfaces,0 , UpU, UpL,'d') down_light = calculate.trace_real_ray(system.surfaces,0 , DownU, DownL,'d') center_light = calculate.trace_real_ray(system.surfaces,0 , W*(-1), 0,'d') h_up = up_light[1][-1]*math.tan(up_light[2][-1])*(up_light[1][-1]-calculate.calculate_ideal_image_distance(system.surfaces,system.object_infinite,system.object_distance))/up_light[1][-1] h_down= down_light[1][-1]*math.tan(down_light[2][-1])*(down_light[1][-1]-calculate.calculate_ideal_image_distance(system.surfaces,system.object_infinite,system.object_distance))/down_light[1][-1] h_center = center_light[1][-1]*math.tan(center_light[2][-1])*(center_light[1][-1]-calculate.calculate_ideal_image_distance(system.surfaces,system.object_infinite,system.object_distance))/center_light[1][-1] return (h_up + h_down) / 2.0 - h_center class MainApplication: def __init__(self, root): self.root = root self.root.title("光学系统计算程序") self.root.geometry("1000x850") # 创建光学系统对象 self.system = OpticalSystem() # 创建GUI组件 self.create_widgets() # 加载默认设置(如果有) self.load_default_settings() def create_widgets(self): # 主框架 main_frame = ttk.Frame(self.root) main_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10) # 文件操作框架 file_frame = ttk.LabelFrame(main_frame, text="文件操作") file_frame.pack(fill=tk.X, padx=5, pady=5) # 文件路径输入 ttk.Label(file_frame, text="文件路径:").grid(row=0, column=0, padx=5, pady=5) self.file_path_entry = ttk.Entry(file_frame, width=50) self.file_path_entry.grid(row=0, column=1, padx=5, pady=5) # 文件操作按钮 browse_btn = ttk.Button(file_frame, text="浏览...", command=self.browse_file) browse_btn.grid(row=0, column=2, padx=5, pady=5) load_btn = ttk.Button(file_frame, text="加载系统参数", command=self.load_system) load_btn.grid(row=0, column=3, padx=5, pady=5) save_btn = ttk.Button(file_frame, text="保存系统参数", command=self.save_system) save_btn.grid(row=0, column=4, padx=5, pady=5) # 左侧面板 - 输入参数 left_frame = ttk.LabelFrame(main_frame, text="系统参数输入") left_frame.pack(side=tk.LEFT, fill=tk.BOTH, expand=True, padx=5, pady=5) # 右侧面板 - 结果展示 right_frame = ttk.LabelFrame(main_frame, text="计算结果") right_frame.pack(side=tk.RIGHT, fill=tk.BOTH, expand=True, padx=5, pady=5) # 创建左侧面板的子组件 self.create_input_panel(left_frame) # 创建右侧面板的子组件 self.create_result_panel(right_frame) # 计算按钮 calc_frame = ttk.Frame(main_frame) calc_frame.pack(fill=tk.X, padx=5, pady=10) calc_btn = ttk.Button(calc_frame, text="开始计算", command=self.calculate, width=15) calc_btn.pack(side=tk.LEFT, padx=10) save_result_btn = ttk.Button(calc_frame, text="保存计算结果", command=self.save_results, width=15) save_result_btn.pack(side=tk.LEFT, padx=10) clear_btn = ttk.Button(calc_frame, text="清除所有", command=self.clear_all, width=15) clear_btn.pack(side=tk.LEFT, padx=10) def browse_file(self): """浏览文件按钮处理函数""" file_path = filedialog.askopenfilename( title="选择文件", filetypes=[("JSON文件", "*.json"), ("所有文件", "*.*")] ) if file_path: self.file_path_entry.delete(0, tk.END) self.file_path_entry.insert(0, file_path) def create_input_panel(self, parent): # 入瞳参数 pupil_frame = ttk.LabelFrame(parent, text="入瞳参数") pupil_frame.pack(fill=tk.X, padx=5, pady=5) ttk.Label(pupil_frame, text="入瞳直径 (mm):").grid(row=0, column=0, padx=5, pady=5, sticky="w") self.entrance_diameter_entry = ttk.Entry(pupil_frame, width=15) self.entrance_diameter_entry.grid(row=0, column=1, padx=5, pady=5) ttk.Label(pupil_frame, text="入瞳位置 (mm):").grid(row=0, column=2, padx=5, pady=5, sticky="w") self.entrance_position_entry = ttk.Entry(pupil_frame, width=15) self.entrance_position_entry.grid(row=0, column=3, padx=5, pady=5) # 色光类型选择 ttk.Label(pupil_frame, text="色光类型:").grid(row=1, column=0, padx=5, pady=5, sticky="w") self.light_type_var = tk.StringVar(value="d") self.light_type_combo = ttk.Combobox(pupil_frame, textvariable=self.light_type_var, width=12, state="readonly") self.light_type_combo["values"] = ("d", "f", "c") self.light_type_combo.grid(row=1, column=1, padx=5, pady=5, sticky="w") # 添加孔径系数和视场系数输入 ttk.Label(pupil_frame, text="孔径系数:").grid(row=1, column=2, padx=5, pady=5, sticky="w") self.aperture_coeff_entry = ttk.Entry(pupil_frame, width=8) self.aperture_coeff_entry.insert(0, "1.0") self.aperture_coeff_entry.grid(row=1, column=3, padx=5, pady=5) ttk.Label(pupil_frame, text="视场系数:").grid(row=1, column=4, padx=5, pady=5, sticky="w") self.field_coeff_entry = ttk.Entry(pupil_frame, width=8) self.field_coeff_entry.insert(0, "1.0") self.field_coeff_entry.grid(row=1, column=5, padx=5, pady=5) # 物方参数 object_frame = ttk.LabelFrame(parent, text="物方参数") object_frame.pack(fill=tk.X, padx=5, pady=5) # 物距选择 self.object_var = tk.BooleanVar(value=True) # True: 无穷远, False: 有限远 ttk.Radiobutton(object_frame, text="物在无穷远", variable=self.object_var, value=True, command=self.toggle_object_input).grid(row=0, column=0, padx=5, pady=5) ttk.Radiobutton(object_frame, text="物在有限远", variable=self.object_var, value=False, command=self.toggle_object_input).grid(row=0, column=1, padx=5, pady=5) # 无穷远参数 self.infinite_frame = ttk.Frame(object_frame) self.infinite_frame.grid(row=1, column=0, columnspan=2, sticky="w", padx=5, pady=5) ttk.Label(self.infinite_frame, text="半视场角 (度):").grid(row=0, column=0, padx=5, pady=5, sticky="w") self.field_angle_entry = ttk.Entry(self.infinite_frame, width=15) self.field_angle_entry.grid(row=0, column=1, padx=5, pady=5) # 有限远参数 (初始隐藏) self.finite_frame = ttk.Frame(object_frame) self.finite_frame.grid(row=1, column=0, columnspan=2, sticky="w", padx=5, pady=5) self.finite_frame.grid_remove() # 初始隐藏 ttk.Label(self.finite_frame, text="物距 (mm):").grid(row=0, column=0, padx=5, pady=5, sticky="w") self.object_distance_entry = ttk.Entry(self.finite_frame, width=15) self.object_distance_entry.grid(row=0, column=1, padx=5, pady=5) ttk.Label(self.finite_frame, text="物高 (mm):").grid(row=0, column=2, padx=5, pady=5, sticky="w") self.object_height_entry = ttk.Entry(self.finite_frame, width=15) self.object_height_entry.grid(row=0, column=3, padx=5, pady=5) ttk.Label(self.finite_frame, text="孔径角 (度):").grid(row=0, column=4, padx=5, pady=5, sticky="w") self.aperture_angle_entry = ttk.Entry(self.finite_frame, width=15) self.aperture_angle_entry.grid(row=0, column=5, padx=5, pady=5) # 光学表面输入 surface_frame = ttk.LabelFrame(parent, text="光学表面参数") surface_frame.pack(fill=tk.BOTH, expand=True, padx=5, pady=5) # 表面输入控件 input_frame = ttk.Frame(surface_frame) input_frame.pack(fill=tk.X, padx=5, pady=5) ttk.Label(input_frame, text="曲率半径 (mm):").grid(row=0, column=0, padx=5, pady=5) self.radius_entry = ttk.Entry(input_frame, width=10) self.radius_entry.grid(row=0, column=1, padx=5, pady=5) self.radius_entry.insert(0, "50") ttk.Label(input_frame, text="厚度 (mm):").grid(row=0, column=2, padx=5, pady=5) self.thickness_entry = ttk.Entry(input_frame, width=10) self.thickness_entry.grid(row=0, column=3, padx=5, pady=5) self.thickness_entry.insert(0, "5") ttk.Label(input_frame, text="折射率 (nd):").grid(row=0, column=4, padx=5, pady=5) self.nd_entry = ttk.Entry(input_frame, width=10) self.nd_entry.grid(row=0, column=5, padx=5, pady=5) self.nd_entry.insert(0, "1.5") ttk.Label(input_frame, text="阿贝数 (vd):").grid(row=0, column=6, padx=5, pady=5) self.vd_entry = ttk.Entry(input_frame, width=10) self.vd_entry.grid(row=0, column=7, padx=5, pady=5) self.vd_entry.insert(0, "60") button_frame = ttk.Frame(input_frame) button_frame.grid(row=0, column=8, padx=10) add_btn = ttk.Button(button_frame, text="添加表面", command=self.add_surface) add_btn.pack(side=tk.LEFT, padx=5) remove_btn = ttk.Button(button_frame, text="删除表面", command=self.remove_surface) remove_btn.pack(side=tk.LEFT, padx=5) # 表面列表 list_frame = ttk.Frame(surface_frame) list_frame.pack(fill=tk.BOTH, expand=True, padx=5, pady=5) columns = ("#", "曲率半径 (mm)", "厚度 (mm)", "折射率 (nd)", "阿贝数 (vd)") self.surface_tree = ttk.Treeview(list_frame, columns=columns, show="headings", height=8) for col in columns: self.surface_tree.heading(col, text=col) self.surface_tree.column(col, width=100, anchor=tk.CENTER) vsb = ttk.Scrollbar(list_frame, orient="vertical", command=self.surface_tree.yview) self.surface_tree.configure(yscrollcommand=vsb.set) self.surface_tree.pack(side=tk.LEFT, fill=tk.BOTH, expand=True) vsb.pack(side=tk.RIGHT, fill=tk.Y) def create_result_panel(self, parent): # 结果文本框 self.result_text = tk.Text(parent, wrap=tk.WORD) result_scroll_y = ttk.Scrollbar(parent, orient="vertical", command=self.result_text.yview) result_scroll_x = ttk.Scrollbar(parent, orient="horizontal", command=self.result_text.xview) self.result_text.configure(yscrollcommand=result_scroll_y.set, xscrollcommand=result_scroll_x.set) result_scroll_y.pack(side=tk.RIGHT, fill=tk.Y) result_scroll_x.pack(side=tk.BOTTOM, fill=tk.X) self.result_text.pack(side=tk.LEFT, fill=tk.BOTH, expand=True) # 设置初始文本 self.result_text.insert(tk.END, "计算结果将显示在此处...\n\n") self.result_text.configure(state=tk.DISABLED) def toggle_object_input(self): """切换物方参数输入界面""" if self.object_var.get(): # 无穷远 self.infinite_frame.grid() self.finite_frame.grid_remove() else: # 有限远 self.infinite_frame.grid_remove() self.finite_frame.grid() def add_surface(self): """添加光学表面""" try: # 获取输入值 r = self.radius_entry.get().strip() d = self.thickness_entry.get().strip() nd = self.nd_entry.get().strip() vd = self.vd_entry.get().strip() # 处理输入值 r = float(r) if r and r.lower() != "inf" else float('inf') d = float(d) if d else 0.0 nd = float(nd) if nd else 1.0 vd = float(vd) if vd else 0.0 # 添加到系统 surface = Surface(r, d, nd, vd) self.system.surfaces.append(surface) # 添加到树形视图 r_str = "平面" if r == float('inf') else f"{r:.2f}" self.surface_tree.insert("", "end", values=( len(self.system.surfaces), r_str, f"{d:.2f}", f"{nd:.8f}", f"{vd:.8f}" )) # 清空输入框 self.radius_entry.delete(0, tk.END) self.thickness_entry.delete(0, tk.END) self.nd_entry.delete(0, tk.END) self.vd_entry.delete(0, tk.END) self.radius_entry.focus_set() except ValueError: messagebox.showerror("输入错误", "请输入有效的数字") def remove_surface(self): """删除选中的光学表面""" selected = self.surface_tree.selection() if selected: # 从树形视图中删除 for item in selected: index = int(self.surface_tree.item(item, "values")[0]) - 1 self.surface_tree.delete(item) # 从系统中删除 if 0 <= index < len(self.system.surfaces): self.system.surfaces.pop(index) # 更新剩余表面的序号 for i, item in enumerate(self.surface_tree.get_children()): values = list(self.surface_tree.item(item, "values")) values[0] = i + 1 self.surface_tree.item(item, values=values) def load_system(self): """加载系统参数文件""" file_path = self.file_path_entry.get().strip() if not file_path: messagebox.showwarning("警告", "请输入文件路径") return try: with open(file_path, 'r') as f: data = json.load(f) # 加载系统参数 self.system.entrance_pupil_diameter = data.get("entrance_pupil_diameter") self.system.entrance_pupil_position = data.get("entrance_pupil_position") self.system.object_infinite = data.get("object_infinite", True) self.system.field_angle = data.get("field_angle") self.system.object_distance = data.get("object_distance") self.system.object_height = data.get("object_height") self.system.aperture_angle = data.get("aperture_angle") self.system.aperture_coefficient = data.get("aperture_coefficient", 1.0) self.system.field_coefficient = data.get("field_coefficient", 1.0) # 更新UI中的参数值 if self.system.entrance_pupil_diameter is not None: self.entrance_diameter_entry.delete(0, tk.END) self.entrance_diameter_entry.insert(0, str(self.system.entrance_pupil_diameter)) if self.system.entrance_pupil_position is not None: self.entrance_position_entry.delete(0, tk.END) self.entrance_position_entry.insert(0, str(self.system.entrance_pupil_position)) self.object_var.set(self.system.object_infinite) self.toggle_object_input() if self.system.field_angle is not None: self.field_angle_entry.delete(0, tk.END) self.field_angle_entry.insert(0, str(self.system.field_angle)) if self.system.object_distance is not None: self.object_distance_entry.delete(0, tk.END) self.object_distance_entry.insert(0, str(self.system.object_distance)) if self.system.object_height is not None: self.object_height_entry.delete(0, tk.END) self.object_height_entry.insert(0, str(self.system.object_height)) if self.system.aperture_angle is not None: self.aperture_angle_entry.delete(0, tk.END) self.aperture_angle_entry.insert(0, str(self.system.aperture_angle)) if self.aperture_coeff_entry.get(): self.system.aperture_coefficient = float(self.aperture_coeff_entry.get()) if self.field_coeff_entry.get(): self.system.field_coefficient = float(self.field_coeff_entry.get()) # 加载表面数据 self.system.surfaces = [] self.surface_tree.delete(*self.surface_tree.get_children()) surfaces_data = data.get("surfaces", []) for surf_data in surfaces_data: surface = Surface.from_dict(surf_data) self.system.surfaces.append(surface) r_str = "平面" if surface.r == float('inf') else f"{surface.r:.2f}" self.surface_tree.insert("", "end", values=( len(self.system.surfaces), r_str, f"{surface.d:.2f}", f"{surface.nd:.8f}", f"{surface.vd:.8f}" )) messagebox.showinfo("成功", f"系统参数已从 {os.path.basename(file_path)} 加载") # 显示加载的系统信息 self.result_text.configure(state=tk.NORMAL) self.result_text.delete(1.0, tk.END) self.result_text.insert(tk.END, f"已加载系统参数文件: {file_path}\n") self.result_text.insert(tk.END, f"包含 {len(self.system.surfaces)} 个光学表面\n") self.result_text.configure(state=tk.DISABLED) except FileNotFoundError: messagebox.showerror("错误", f"文件不存在: {file_path}") except Exception as e: messagebox.showerror("加载错误", f"加载文件失败: {str(e)}") def save_system(self): """保存系统参数文件""" # 更新系统参数 if not self.update_system_from_ui(): return # 如果没有表面数据,提示用户 if not self.system.surfaces: messagebox.showwarning("警告", "没有光学表面数据,无法保存") return file_path = self.file_path_entry.get().strip() if not file_path: messagebox.showwarning("警告", "请输入保存路径") return try: # 准备保存数据 data = { "entrance_pupil_diameter": self.system.entrance_pupil_diameter, "entrance_pupil_position": self.system.entrance_pupil_position, "object_infinite": self.system.object_infinite, "field_angle": self.system.field_angle, "object_distance": self.system.object_distance, "object_height": self.system.object_height, "aperture_angle": self.system.aperture_angle, "surfaces": [surf.to_dict() for surf in self.system.surfaces], "aperture_coefficient": self.system.aperture_coefficient, "field_coefficient": self.system.field_coefficient, } with open(file_path, 'w') as f: json.dump(data, f, indent=4) messagebox.showinfo("成功", f"系统参数已保存到 {os.path.basename(file_path)}") # 显示保存信息 self.result_text.configure(state=tk.NORMAL) self.result_text.insert(tk.END, f"系统参数已保存到: {file_path}\n") self.result_text.configure(state=tk.DISABLED) except Exception as e: messagebox.showerror("保存错误", f"保存文件失败: {str(e)}") def save_results(self): """保存计算结果到文件""" if not self.system.results or all(v is None for v in self.system.results.values()): messagebox.showwarning("警告", "没有计算结果可保存") return file_path = filedialog.asksaveasfilename( title="保存计算结果", defaultextension=".txt", filetypes=[("文本文件", "*.txt"), ("所有文件", "*.*")] ) if not file_path: return try: with open(file_path, 'w') as f: # 写入系统参数摘要 f.write("===== 光学系统参数 =====\n") f.write(f"入瞳直径: {self.system.entrance_pupil_diameter} mm\n") f.write(f"入瞳位置: {self.system.entrance_pupil_position} mm\n") f.write(f"色光类型: {self.system.light_type}\n") f.write("物距类型: " + ("无穷远" if self.system.object_infinite else "有限远") + "\n") if self.system.object_infinite: f.write(f"半视场角: {self.system.field_angle} 度\n") else: f.write(f"物距: {self.system.object_distance} mm\n") f.write(f"物高: {self.system.object_height} mm\n") f.write(f"孔径角: {self.system.aperture_angle} 度\n") f.write("\n光学表面参数:\n") for i, surf in enumerate(self.system.surfaces): r_str = "平面" if surf.r == float('inf') else f"{surf.r:.2f} mm" f.write(f"表面 {i+1}: r={r_str}, d={surf.d:.2f} mm, nd={surf.nd:.8f}, vd={surf.vd:.8f}\n") # 写入计算结果 f.write("\n\n===== 计算结果 =====\n") for key, value in self.system.results.items(): if value is not None: # 格式化键名 label = self.format_result_label(key) f.write(f"{label}: {value}\n") messagebox.showinfo("成功", f"计算结果已保存到 {os.path.basename(file_path)}") # 显示保存信息 self.result_text.configure(state=tk.NORMAL) self.result_text.insert(tk.END, f"计算结果已保存到: {file_path}\n") self.result_text.configure(state=tk.DISABLED) except Exception as e: messagebox.showerror("保存错误", f"保存计算结果失败: {str(e)}") def format_result_label(self, key): """格式化结果标签为中文描述""" labels = { "focal_length": "焦距 f' (mm)", "ideal_image_distance": "理想像距 l' (mm)", "actual_image_position": "实际像位置 (mm)", "image_principal_plane": "像方主面位置 lH' (mm)", "exit_pupil_distance": "出瞳距 lp' (mm)", "ideal_image_height": "理想像高 y0' (mm)", "spherical_aberration": "球差 (mm)", "longitudinal_chromatic": "位置色差 (mm)", "tangential_field_curvature": "子午场曲 xt' (mm)", "sagittal_field_curvature": "弧矢场曲 xs' (mm)", "astigmatism": "像散 Δxts' (mm)", "actual_image_height": "实际像高 (mm)", "relative_distortion": "相对畸变 (%)", "absolute_distortion": "绝对畸变 (mm)", "lateral_chromatic": "倍率色差 (mm)", "tangential_coma": "子午慧差 (mm)" } return labels.get(key, key) def update_system_from_ui(self): """从UI更新系统参数""" try: # 入瞳参数 if self.entrance_diameter_entry.get(): self.system.entrance_pupil_diameter = float(self.entrance_diameter_entry.get()) if self.entrance_position_entry.get(): self.system.entrance_pupil_position = float(self.entrance_position_entry.get()) # 色光类型 self.system.light_type = self.light_type_var.get() #系数 if self.aperture_coeff_entry.get(): self.system.aperture_coefficient = float(self.aperture_coeff_entry.get()) if self.field_coeff_entry.get(): self.system.field_coefficient = float(self.field_coeff_entry.get()) # 物方参数 self.system.object_infinite = self.object_var.get() if self.system.object_infinite: if self.field_angle_entry.get(): self.system.field_angle = float(self.field_angle_entry.get()) else: if self.object_distance_entry.get(): self.system.object_distance = float(self.object_distance_entry.get()) if self.object_height_entry.get(): self.system.object_height = float(self.object_height_entry.get()) if self.aperture_angle_entry.get(): self.system.aperture_angle = float(self.aperture_angle_entry.get()) except ValueError: messagebox.showerror("输入错误", "请输入有效的数字") return False return True def calculate(self): """执行光学计算""" # 更新系统参数 if not self.update_system_from_ui(): return # 检查必要参数 if not self.system.surfaces: messagebox.showwarning("警告", "请至少添加一个光学表面") return if self.system.entrance_pupil_diameter is None: messagebox.showwarning("警告", "请输入入瞳直径") return if self.system.object_infinite and self.system.field_angle is None: messagebox.showwarning("警告", "请输入半视场角") return if not self.system.object_infinite and ( self.system.object_distance is None or self.system.object_height is None or self.system.aperture_angle is None ): messagebox.showwarning("警告", "请输入完整的有限远参数") return # 执行计算 - 这里调用您的计算函数 self.perform_calculations() # 显示结果 self.display_results() # 显示计算完成消息 messagebox.showinfo("计算完成", "光学计算已完成,结果已显示在结果区域") def perform_calculations(self): """执行光学计算 - 这里调用计算函数""" # 重置结果 for key in self.system.results: self.system.results[key] = None # 示例:设置一些假结果用于演示 # 实际应用中,您需要调用您自己的计算函数 self.system.results["focal_length"] = calculate.calculate_focal_length(self.system.surfaces,self.system.light_type) self.system.results["ideal_image_distance"] = calculate.calculate_ideal_image_distance(self.system.surfaces,self.system.object_infinite, self.system.object_distance,self.system.light_type) self.system.results["actual_image_position"] = calculate.calculate_actual_image(self.system, self.system.light_type) self.system.results["image_principal_plane"] = calculate.calculate_principal_plane_position(self.system.surfaces,self.system.light_type) self.system.results["exit_pupil_distance"] = calculate.calculate_exit_pupil_distance(self.system.surfaces,self.system.entrance_pupil_position) self.system.results["ideal_image_height"] = calculate.calculate_ideal_image_height(self.system) self.system.results["spherical_aberration"] = calculate.calculate_spherical_aberration(self.system) self.system.results["longitudinal_chromatic"] = calculate.calculate_longitudinal_chromatic(self.system) self.system.results["tangential_field_curvature"] = calculate.calculate_astigmatism(self.system,self.system.light_type)[0] self.system.results["sagittal_field_curvature"] = calculate.calculate_astigmatism(self.system,self.system.light_type)[1] self.system.results["astigmatism"] = calculate.calculate_astigmatism(self.system,self.system.light_type)[2] self.system.results["actual_image_height"] = calculate.calculate_actual_image_height(self.system,self.system.light_type) self.system.results["relative_distortion"] = calculate.calculate_relative_distortion(self.system,self.system.light_type) self.system.results["absolute_distortion"] = calculate.calculate_absolute_distortion(self.system,self.system.light_type) self.system.results["lateral_chromatic"] = calculate.calculate_lateral_chromatic(self.system) self.system.results["tangential_coma"] = calculate.calculate_tangential_coma(self.system) def display_results(self): """在结果文本框中显示计算结果""" self.result_text.configure(state=tk.NORMAL) self.result_text.delete(1.0, tk.END) # 添加系统参数摘要 self.result_text.insert(tk.END, "===== 光学系统参数 =====\n", "title") self.result_text.insert(tk.END, f"入瞳直径: {self.system.entrance_pupil_diameter} mm\n") self.result_text.insert(tk.END, f"入瞳位置: {self.system.entrance_pupil_position} mm\n") self.result_text.insert(tk.END, "物距类型: " + ("无穷远" if self.system.object_infinite else "有限远") + "\n") self.result_text.insert(tk.END, f"色光类型: {self.system.light_type}\n") self.result_text.insert(tk.END, f"孔径系数: {self.system.aperture_coefficient}\n") self.result_text.insert(tk.END, f"视场系数: {self.system.field_coefficient}\n") if self.system.object_infinite: self.result_text.insert(tk.END, f"半视场角: {self.system.field_angle} 度\n") else: self.result_text.insert(tk.END, f"物距: {self.system.object_distance} mm\n") self.result_text.insert(tk.END, f"物高: {self.system.object_height} mm\n") self.result_text.insert(tk.END, f"孔径角: {self.system.aperture_angle} 度\n") self.result_text.insert(tk.END, "\n光学表面参数:\n") for i, surf in enumerate(self.system.surfaces): r_str = "平面" if surf.r == float('inf') else f"{surf.r:.2f} mm" self.result_text.insert(tk.END, f"表面 {i+1}: r={r_str}, d={surf.d:.2f} mm, nd={surf.nd:.8f}, vd={surf.vd:.8f}\n") # 添加计算结果 self.result_text.insert(tk.END, "\n\n===== 计算结果 =====\n", "title") # 计算关键结果 key_results = [ "focal_length", "ideal_image_distance", "actual_image_position", "image_principal_plane", "exit_pupil_distance", "ideal_image_height" ] for key in key_results: if self.system.results[key] is not None: label = self.format_result_label(key) self.result_text.insert(tk.END, f"{label}: {self.system.results[key]}\n") # 添加像差结果 self.result_text.insert(tk.END, "\n像差分析:\n", "subtitle") aberrations = [ "spherical_aberration", "longitudinal_chromatic", "tangential_field_curvature", "sagittal_field_curvature", "astigmatism", "actual_image_height", "relative_distortion", "absolute_distortion", "lateral_chromatic", "tangential_coma" ] for key in aberrations: if self.system.results[key] is not None: label = self.format_result_label(key) self.result_text.insert(tk.END, f"{label}: {self.system.results[key]}\n") self.result_text.configure(state=tk.DISABLED) def clear_all(self): """清除所有输入和结果""" # 清除系统参数 self.system = OpticalSystem() # 清除UI输入 self.file_path_entry.delete(0, tk.END) self.entrance_diameter_entry.delete(0, tk.END) self.entrance_position_entry.delete(0, tk.END) self.field_angle_entry.delete(0, tk.END) self.object_distance_entry.delete(0, tk.END) self.object_height_entry.delete(0, tk.END) self.aperture_angle_entry.delete(0, tk.END) self.aperture_coeff_entry.delete(0, tk.END) self.aperture_coeff_entry.insert(0, "1") self.field_coeff_entry.delete(0, tk.END) self.field_coeff_entry.insert(0, "0") self.radius_entry.delete(0, tk.END) self.radius_entry.insert(0, "50") self.thickness_entry.delete(0, tk.END) self.thickness_entry.insert(0, "5") self.nd_entry.delete(0, tk.END) self.nd_entry.insert(0, "1.5") self.vd_entry.delete(0, tk.END) self.vd_entry.insert(0, "60") # 清除表面列表 self.surface_tree.delete(*self.surface_tree.get_children()) self.system.surfaces = [] # 清除结果 self.result_text.configure(state=tk.NORMAL) self.result_text.delete(1.0, tk.END) self.result_text.insert(tk.END, "计算结果将显示在此处...\n\n") self.result_text.configure(state=tk.DISABLED) # 重置物距类型 self.object_var.set(True) self.toggle_object_input() messagebox.showinfo("清除完成", "所有输入和结果已清除") def load_default_settings(self): """加载默认设置(可选)""" # 这里可以添加加载默认设置的逻辑 pass if __name__ == "__main__": root = tk.Tk() app = MainApplication(root) # 设置文本样式 app.result_text.tag_config("title", font=("Arial", 10, "bold")) app.result_text.tag_config("subtitle", font=("Arial", 9, "bold")) root.mainloop() 如何添加一个计算结果保存按钮,点击后创建一个文件保存右边文本框显示的计算结果和参数
06-28
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值