1001. A+B Format (20) (%0nd)

本文解析了一道经典的计算题目“A+B Format”,介绍了如何通过C语言实现按标准格式输出两个整数相加的结果,包括负数及不同位数的处理方式。

 

1001. A+B Format (20)

 

时间限制
400 ms
内存限制
65536 kB
代码长度限制
16000 B
判题程序
Standard
作者
CHEN, Yue

 

Calculate a + b and output the sum in standard format -- that is, the digits must be separated into groups of three by commas (unless there are less than four digits).

Input

Each input file contains one test case. Each case contains a pair of integers a and b where -1000000 <= a, b <= 1000000. The numbers are separated by a space.

 

Output

For each test case, you should output the sum of a and b in one line. The sum must be written in the standard format.

Sample Input
-1000000 9
Sample Output
-999,991

 

解题思路:这里主要是注意一下补0的问题

     %nd:n代表的是列宽长度。

 

     (1)%-nd   -  代表的是左对齐。

     (2)%nd       代表的是右对齐。

 

     (3)%0nd   0(数字零)代表的是不足n位长度的左补齐0。

 1 #include<stdio.h>
 2 #include<stdlib.h>
 3 
 4 int main()
 5 {
 6     int a,b;
 7     int sum = 0;
 8     scanf("%d %d",&a,&b);
 9 
10     sum = a+b;
11     if( sum<0){
12         printf("-");
13         sum = 0-sum;
14     }
15     if( sum>=1000000){
16         printf("%d,%03d,%03d",(sum/1000000),(sum/1000%1000),(sum%1000));
17     }
18     else if( sum>=1000){
19         printf("%d,%03d",(sum/1000),(sum%1000));
20     }
21     else printf("%d",sum);
22     return 0;
23 }

 

转载于:https://www.cnblogs.com/yuxiaoba/p/8421141.html

import openpyxl as pyxl class Surface: ''' Surface结构体 变量含:曲率半径(radius), 厚度(thickness), 物方折射率及像方折射率(nd0, nF0, nC0, nd1, nF1, nC1), 半通光孔径(semi_dia) (物在无穷远时代表视场角) ''' radius = 0 thickness = 0 nd0 = 0 nF0 = 0 nC0 = 0 nd1 = 0 nF1 = 0 nC1 = 0 semi_dia = 0 def __init__(self, _radius, _thickness, _nd1, _nF1, _nC1, _semi_dia): self.radius = _radius self.thickness = _thickness self.nd1 = _nd1 self.nF1 = _nF1 self.nC1 = _nC1 self.semi_dia = _semi_dia def read_excel(input_file_name = 'input.xlsx'): """ 作用: 读取输入表中的物面、镜面、入瞳、像面数据 输入: 同一目录下的文件名,或指定文件路径。缺省默认为'input.xlsx' 输出: object; lens[ ]数组,元素是每面数据; entrance_pupil; image """ wb = pyxl.load_workbook(input_file_name) ws = wb['Sheet1'] temp = ws.iter_rows() print(temp) parameter = [] for row in ws.rows: for cell in row: parameter.append(cell.value) i = 0 objdata = [] lensdata = [] imgdata = [] entrance_pupil = [] """ 作用: 首先略过输入表的列标题,读取物面信息, 再逐面读取光学面信息, 最后读取像面信息; """ for i in range(len(parameter)): if(i >= 14 and i < 21): objdata.append(parameter[i]) elif(i >= 21 and i < len(parameter)-7): lensdata.append(parameter[i]) elif(i >= len(parameter)-7): imgdata.append(parameter[i]) lensnumber = int(len(lensdata) / 7) object = Surface(objdata[1], objdata[2], objdata[3], objdata[4], objdata[5], objdata[6]) lens = [] for i in range(lensnumber-1): lens.append(Surface(lensdata[i*7+1], lensdata[i*7+2], lensdata[i*7+3], lensdata[i*7+4], lensdata[i*7+5], lensdata[i*7+6])) lens[i].nd0 = parameter[(i+2)*7+3] lens[i].nF0 = parameter[(i+2)*7+4] lens[i].nC0 = parameter[(i+2)*7+5] #读取光阑信息 entrance_pupil = Surface(lensdata[(lensnumber-1)*7+1], lensdata[(lensnumber-1)*7+2], lensdata[(lensnumber-1)*7+3], lensdata[(lensnumber-1)*7+4],\ lensdata[(lensnumber-1)*7+5], lensdata[(lensnumber-1)*7+6]) image = Surface(imgdata[1], imgdata[2], imgdata[3], imgdata[4], imgdata[5], imgdata[6]) return object, lens, entrance_pupil, image def write_excel(data1 = [], data2 = [], data3 = [], data4 = [], data5 = [], data6 = [], filename = 'output.xlsx'): """ 作用: 写EXCEL 输入: 共38个数据,分为 data1: f', l', lH', lp', y0', y0, 0.707', xt', xs', delta_x', F光近轴像位置, C光近轴像位置; 共12个数据 data2: 全孔径的 d光像点, F光像点, C光像点, 球差, 位置色差; 共5个数据 data3: 0.707孔径的 d光像点, F光像点, C光像点, 球差, 位置色差; 共5个数据 data4: 0孔径位置色差; 共1个数据 data5: 全视场的 全孔径子午彗差, 0.7孔径子午彗差, d光实际像高, F光实际像高, C光实际像高, 绝对畸变, 相对畸变, 倍率色差; 共8个数据 data6: 0.707视场的 全孔径子午彗差, 0.7孔径子午彗差, d光实际像高, F光实际像高, C光实际像高, 绝对畸变, 相对畸变, 倍率色差; 共8个数据 filename: 输出文件名 """ wb = pyxl.Workbook() ws = wb.active label1 = ['f\'', 'l\'', 'lH\'', 'lp\'', 'y0\'', 'y0, 0.707\'', 'xt\'', 'xs\'', 'delta_x\'', 'F光近轴像位置', 'C光近轴像位置'] for i in range(len(label1)): ws.cell(row = 1, column = i+1, value = label1[i]) ws.cell(row = 2, column = i+1, value = data1[i]) ws.merge_cells('A4:E4') ws['A4'] = '轴上点全孔径d、F、C光' label_DFC = ['d光像点', 'F光像点', 'C光像点', '球差', '位置色差'] for i in range(len(label_DFC)): ws.cell(row = 5, column = i+1, value = label_DFC[i]) ws.cell(row = 6, column = i+1, value = data2[i]) ws.merge_cells('A8:E8') ws['A8'] = '轴上点0.7孔径d、F、C光' for i in range(len(label_DFC)): ws.cell(row = 9, column = i+1, value = label_DFC[i]) ws.cell(row = 10, column = i+1, value = data3[i]) ws['A12'] = '轴上点0孔径位置色差' ws['A13'] = data4[0] ws.merge_cells('A15:H15') ws['A15'] = '全视场' label3 = ['全孔径子午彗差', '0.7孔径子午彗差', 'd光实际像高', 'F光实际像高', 'C光实际像高', '绝对畸变', '相对畸变', '倍率色差'] for i in range(len(label3)): ws.cell(row = 16, column = i+1, value = label3[i]) ws.cell(row = 17, column = i+1, value = data5[i]) ws.merge_cells('A19:H19') ws['A19'] = '0.7视场' for i in range(len(label3)): ws.cell(row = 20, column = i+1, value = label3[i]) ws.cell(row = 21, column = i+1, value = data6[i]) for c in range(1, 12): # 注意,列序数从1开始,但必须转变为A\B等字母 w = pyxl.utils.get_column_letter(c) # 把列序数转变为字母 ws.column_dimensions[w].width = 15 wb.save(filename) ''' ---迭代递推模块--- 包含: lens_recursion(...), 给定入射光线L、U,对各镜面进行光线追迹并返回各面L、U数据 astigmatism_recursion(...), 给定各面L、U、I、PA参数,求子午场曲,弧矢场曲,像散 ''' EPS = 1e-5 #PA校验精度 def lens_recursion(L, U, H, lens, raytype, isParallel): """ 函数作用: 给定轴上光线入射初值, 对每个镜面进行递推 输入: 初始物方截距(L)、物方倾斜角(U)、镜面数据(lens)、光线类型(raytype = 'd', 'F', 'C') 是否平行于主光轴(isParallel, 1平行, 0倾斜) 输出: 光线经过每面镜面后的L, L', U', I, I', PA数组 """ lensnumber = len(lens) recursion = 0 sinI = 0; sinII = 0 I = 0; II = 0 UU = 0 LL = 0 L_data = [L] LL_data = [] UU_data = [U] I_data = [] II_data = [] PA_data = [] if(raytype == 'd'): #d光,折射率取nd for recursion in range(lensnumber): if(recursion == 0 and isParallel): sinI = H / lens[recursion].radius else: sinI = (L - lens[recursion].radius) / lens[recursion].radius * np.sin(U) sinII = lens[recursion].nd0 / lens[recursion].nd1 * sinI if(np.abs(sinI) < 1 and np.abs(sinII) < 1): I = np.arcsin(sinI); II = np.arcsin(sinII) I_data.append(I); II_data.append(II) UU = U + I - II LL = lens[recursion].radius + lens[recursion].radius * sinII / np.sin(UU) LL_data.append(LL); UU_data.append(UU) #PA校对法 PA1 = L * np.sin(U) / np.cos((I-U)/2) PA2 = LL * np.sin(UU) / np.cos((II-UU)/2) if(np.abs(PA1-PA2) > EPS and isParallel == 0): print("Recursion not right.") print(f'PA1 = {PA1}, PA2 = {PA2}') PA_data.append(PA2) #过渡公式 U = UU L = LL - lens[recursion].thickness #舍去最后一个过渡的物方截距 if(recursion != lensnumber - 1): L_data.append(L) if(raytype == 'F'): #F光,折射率取nF for recursion in range(lensnumber): if(recursion == 0 and isParallel): sinI = H / lens[recursion].radius else: sinI = (L - lens[recursion].radius) / lens[recursion].radius * np.sin(U) sinII = lens[recursion].nF0 / lens[recursion].nF1 * sinI if(np.abs(sinI) < 1 and np.abs(sinII) < 1): I = np.arcsin(sinI); II = np.arcsin(sinII) I_data.append(I); II_data.append(II) UU = U + I - II LL = lens[recursion].radius + lens[recursion].radius * sinII / np.sin(UU) LL_data.append(LL); UU_data.append(UU) #PA校对法 PA1 = L * np.sin(U) / np.cos((I-U)/2) PA2 = LL * np.sin(UU) / np.cos((II-UU)/2) if(np.abs(PA1-PA2) > EPS and isParallel == 0): print("Recursion not right.") print(f'PA1 = {PA1}, PA2 = {PA2}') PA_data.append(PA2) #过渡公式 U = UU L = LL - lens[recursion].thickness #舍去最后一个过渡的物方截距 if(recursion != lensnumber - 1): L_data.append(L) if(raytype == 'C'): #C光,折射率取nC for recursion in range(lensnumber): if(recursion == 0 and isParallel): sinI = H / lens[recursion].radius else: sinI = (L - lens[recursion].radius) / lens[recursion].radius * np.sin(U) sinII = lens[recursion].nC0 / lens[recursion].nC1 * sinI if(np.abs(sinI) < 1 and np.abs(sinII) < 1): I = np.arcsin(sinI); II = np.arcsin(sinII) I_data.append(I); II_data.append(II) UU = U + I - II LL = lens[recursion].radius + lens[recursion].radius * sinII / np.sin(UU) LL_data.append(LL); UU_data.append(UU) #PA校对法 PA1 = L * np.sin(U) / np.cos((I-U)/2) PA2 = LL * np.sin(UU) / np.cos((II-UU)/2) if(np.abs(PA1-PA2) > EPS and isParallel == 0): print("Recursion not right.") print(f'PA1 = {PA1}, PA2 = {PA2}') PA_data.append(PA2) #过渡公式 U = UU L = LL - lens[recursion].thickness #舍去最后一个过渡的物方截距 if(recursion != lensnumber - 1): L_data.append(L) #print(f'LEN_DATA\n{len(L_data)}, {len(LL_data)}, {len(UU_data)}, {len(I_data)}, {len(II_data)}, {len(PA_data)}') return L_data, LL_data, UU_data, I_data, II_data, PA_data def astigmatism_recursion(L_data, LL_data, UU_data, I_data, II_data, PA_data, lens, raytype, isParallel): """ 函数作用: 求像散, 场曲 输入: 由lens_recursion算得的各参数 输出: 子午场曲(xt), 弧矢场曲(xs), 像散(delta_x) """ lensnumber = len(lens) for recursion in range(lensnumber): if(raytype == 'd'): x = PA_data[recursion] ** 2 / (2 * lens[recursion].radius) #求t、s初值 if(recursion == 0 and isParallel == 0): t = s = (L_data[0] - x) / np.cos(UU_data[0]) if(recursion == 1 and isParallel == 1): t = s = (L_data[1] - x) / np.cos(UU_data[1]) temp_tt = (lens[recursion].nd1 * np.cos(II_data[recursion]) - lens[recursion].nd0 * np.cos(I_data[recursion]))\ / lens[recursion].radius + lens[recursion].nd0 * np.cos(I_data[recursion]) ** 2 / t tt = 1 / temp_tt * lens[recursion].nd1 * np.cos(II_data[recursion]) ** 2 #t' temp_ss = (lens[recursion].nd1 * np.cos(II_data[recursion]) - lens[recursion].nd0 * np.cos(I_data[recursion]))\ / lens[recursion].radius + lens[recursion].nd0 / s ss = 1 / temp_ss * lens[recursion].nd1 #s' if(recursion < lensnumber-1): #过渡公式 xx = PA_data[recursion + 1] ** 2 / (2 * lens[recursion+1].radius) #x(i+1) D = (lens[recursion].thickness - x + xx) / np.cos(UU_data[recursion+1]) t = tt - D s = ss - D if(recursion == lensnumber-1): #最后一面 lt = tt * np.cos(UU_data[recursion + 1]) + x ls = ss * np.cos(UU_data[recursion + 1]) + x xt = lt - LL_data[-1] xs = ls - LL_data[-1] delta_x = xt - xs if(raytype == 'C'): x = PA_data[recursion] ** 2 / (2 * lens[recursion].radius) #求t、s初值 if(recursion == 0 and isParallel == 0): t = s = (L_data[0] - x) / np.cos(UU_data[0]) if(recursion == 1 and isParallel == 1): t = s = (L_data[1] - x) / np.cos(UU_data[1]) temp_tt = (lens[recursion].nC1 * np.cos(II_data[recursion]) - lens[recursion].nC0 * np.cos(I_data[recursion]))\ / lens[recursion].radius + lens[recursion].nC0 * np.cos(I_data[recursion]) ** 2 / t tt = 1 / temp_tt * lens[recursion].nC1 * np.cos(II_data[recursion]) ** 2 #t' temp_ss = (lens[recursion].nC1 * np.cos(II_data[recursion]) - lens[recursion].nC0 * np.cos(I_data[recursion]))\ / lens[recursion].radius + lens[recursion].nC0 / s ss = 1 / temp_ss * lens[recursion].nC1 #s' if(recursion < lensnumber-1): #过渡公式 xx = PA_data[recursion + 1] ** 2 / (2 * lens[recursion+1].radius) #x(i+1) D = (lens[recursion].thickness - x + xx) / np.cos(UU_data[recursion+1]) t = tt - D s = ss - D if(recursion == lensnumber-1): #最后一面 lt = tt * np.cos(UU_data[recursion + 1]) + x ls = ss * np.cos(UU_data[recursion + 1]) + x xt = lt - LL_data[recursion] xs = ls - LL_data[recursion] delta_x = xt - xs if(raytype == 'F'): x = PA_data[recursion] ** 2 / (2 * lens[recursion].radius) #求t、s初值 if(recursion == 0 and isParallel == 0): t = s = (L_data[0] - x) / np.cos(UU_data[0]) if(recursion == 1 and isParallel == 1): t = s = (L_data[1] - x) / np.cos(UU_data[1]) temp_tt = (lens[recursion].nF1 * np.cos(II_data[recursion]) - lens[recursion].nF0 * np.cos(I_data[recursion]))\ / lens[recursion].radius + lens[recursion].nF0 * np.cos(I_data[recursion]) ** 2 / t tt = 1 / temp_tt * lens[recursion].nF1 * np.cos(II_data[recursion]) ** 2 #t' temp_ss = (lens[recursion].nF1 * np.cos(II_data[recursion]) - lens[recursion].nF0 * np.cos(I_data[recursion]))\ / lens[recursion].radius + lens[recursion].nF0 / s ss = 1 / temp_ss * lens[recursion].nF1 #s' if(recursion < lensnumber-1): #过渡公式 xx = PA_data[recursion + 1] ** 2 / (2 * lens[recursion+1].radius) #x(i+1) D = (lens[recursion].thickness - x + xx) / np.cos(UU_data[recursion+1]) t = tt - D s = ss - D if(recursion == lensnumber-1): #最后一面 lt = tt * np.cos(UU_data[recursion + 1]) + x ls = ss * np.cos(UU_data[recursion + 1]) + x xt = lt - LL_data[recursion] xs = ls - LL_data[recursion] delta_x = xt - xs return xt, xs, delta_x ''' ---L、U计算模块--- 包含: Calc(...), 给定孔径系数、视场系数、物面、镜面、入瞳信息,光线类型,利用迭代递推模块进行中间计算,返回各面L、U、I、PA信息。 ''' def Calc(K_eta, K_W, object, lens, pupil, image, raytype): """ 作用:计算某一孔径、视场光线在逐个面的(L,U)坐标数据 输入:K_eta为孔径取点系数,K_W为视场取点系数 """ #初始化(L,U)坐标列表 L0 = [] L1 = [] U = [] I0 = [] I1 = [] PA = [] A = pupil.semi_dia #入瞳半径 eta = K_eta * A #像高 #物在无穷远且光线与光轴平行时的情形 if(object.thickness == None and K_W == 0): h0 = K_eta * pupil.semi_dia L0, L1, U, I0, I1, PA = lens_recursion(0, 0, h0, lens, raytype, 1) #其余情形 -> 转化为轴上点在有限远处 else: if((object.thickness == None and K_W != 0)): U = -K_W * object.semi_dia * np.pi/180 L = pupil.thickness + eta/np.tan(U) elif(object.semi_dia == 0): L = -object.thickness U = np.arcsin(K_eta * A/np.sqrt(A**2 + Lp**2)) elif(object.semi_dia != 0): Lp = pupil.thickness #第一面到入瞳的距离 y = K_W * object.semi_dia #物方线视场 U = np.arctan((y-eta)/(Lp+object.thickness)) L = Lp + eta/((y-eta)/(Lp+object.thickness)) L0, L1, U, I0, I1, PA = lens_recursion(L, U, 0, lens, raytype, 0) return L0, L1, U, I0, I1, PA ''' ---数据处理模块--- 包含: data_processing(...), 总输出函数,给定物面、镜面、入瞳、像面信息,向主函数返回所有待求量 Calc_ff(...), 计算计算像方焦距、焦点位置、主点位置 Calc_ll(...), 计算像距、像高、像散、场曲 Calc_lp(...), 计算出瞳距 Calc_sp(...), 计算全孔径和0.7孔径时的实际像距、球差、位置色差 Calc_coma(...), 计算全视场、0.7视场、正负全孔径、正负0.7孔径的彗差、两个视场dFC光实际像高,绝对畸变、相对畸变、倍率色差 ''' def data_processing(object, lens, pupil, image): ''' 共输出38个数据 data1:f', l', lH', lp', y0', y0, 0.707', xt', xs', delta_x', F光近轴像位置, C光近轴像位置;共12个数据 data2:轴上点全孔径的 d光像点, F光像点, C光像点, 球差, 位置色差;共5个数据 data3:轴上点0.707孔径的 d光像点, F光像点, C光像点, 球差, 位置色差;共5个数据 data4:轴上点0孔径位置色差;共1个数据 data5:全视场的 全孔径子午彗差, 0.7孔径子午彗差, d光实际像高, F光实际像高, C光实际像高, 绝对畸变, 相对畸变, 倍率色差;共8个数据 data6:0.707视场的 全孔径子午彗差, 0.7孔径子午彗差, d光实际像高, F光实际像高, C光实际像高, 绝对畸变, 相对畸变, 倍率色差;共8个数据 ''' oo = 1e-20 #定义近轴小量 ff, l_H = Calc_ff(object, lens, pupil, image, oo) ll, ll_F, ll_C, y0, y0_707, xt, xs, delta_x = Calc_ll(object, lens, pupil, image, oo, l_H, ff) l_p = Calc_lp(lens, pupil, image, oo) data1 = [ff, ll, l_H, l_p, y0, y0_707, xt, xs, delta_x, ll_F, ll_C] data2, data3, data4 = Calc_sp(object, lens, pupil, image, ll, oo) data5, data6 = Calc_coma(object, lens, pupil, image, oo, y0, y0_707) return data1, data2, data3, data4, data5, data6 #1、计算像方焦距、焦点位置、主点位置 def Calc_ff(object, lens, pupil, image, oo): #定义一个近轴无穷远物面 object_ = Surface(0, None, object.nd1, object.nF1, object.nC1, None) #计算平行入射的近轴光线 L0 = Calc(oo, 0, object_, lens, pupil, image, 'd')[0] L1 = Calc(oo, 0, object_, lens, pupil, image, 'd')[1] #计算L0,L1的乘积 L0_product = L1_product = L0F_product = L1F_product = L0C_product = L1C_product = 1 for i in range(len(L0)-1): L0_product = L0_product * L0[i+1] for i in range(len(L1)): L1_product = L1_product * L1[i] #利用正切计算法计算焦距 ff = L1_product/L0_product #计算像方焦点和主点位置 l_F = L1[-1] l_H = ff - l_F return ff, l_H #2、计算像距和像高,像散及场曲 def Calc_ll(object, lens, pupil, image, oo, l_H, ff): #计算物面入射的近轴光线 if(object.thickness == None): ll = ff-l_H else: L0 = Calc(oo, 0, object, lens, pupil, image, 'd')[0] L1 = Calc(oo, 0, object, lens, pupil, image, 'd')[1] ll = L1[-1] #最后一个光学面的像距 #计算像高 if(object.thickness == None): y0 = ff * np.tan(object.semi_dia * np.pi/180) y0_707 = ff * np.tan(0.70 * object.semi_dia * np.pi/180) else: A = object.semi_dia y0 = A for i in range(len(L1)): n0 = lens[i].nd0 n1 = lens[i].nd1 l0 = L0[i] l1 = L1[i] beta = (n0*l1)/(n1*l0) #理想的横向放大倍率 y0 = y0 * beta y0_707 = 0.70 * y0 if(object.thickness == None and object.semi_dia == None): isparallel = 1 else: isparallel = 0 #计算C光和F光的近轴像距 L1F = Calc(oo, 0, object, lens, pupil, image, 'F')[1] ll_F = L1F[-1] #F光 L1C = Calc(oo, 0, object, lens, pupil, image, 'C')[1] ll_C = L1C[-1] #C光 #计算场曲及像散 L0, L1, U, I0, I1, PA = Calc(0, 1, object, lens, pupil, image, 'd') if(object.thickness == None): L0[0] = 10**15 else: L0[0] = -object.thickness L1 = Calc(oo, 0, object, lens, pupil, image, 'd')[1] xt, xs, delta_x = astigmatism_recursion(L0, L1, U, I0, I1, PA, lens, 'd', isparallel) return ll, ll_F, ll_C, y0, y0_707, xt, xs, delta_x #3、计算出瞳距 def Calc_lp(lens, pupil, image, oo): #定义入瞳面 object_ = Surface(pupil.radius, pupil.thickness, pupil.nd1, pupil.nC1, pupil.nF1, pupil.semi_dia) L1 = Calc(oo, 0, object_, lens, pupil, image, 'd')[1] l_p = L1[-1] return l_p """ 4、计算全孔径和0.7孔径时的实际像距、球差、位置色差 变量:SPAB代表球差spherical aberration,PCA代表位置色差Position Chromatic Aberration """ def Calc_sp(object, lens, pupil, image, ll, oo): L1d1 = Calc(1, 0, object, lens, pupil, image, 'd')[1] ll_d1 = L1d1[-1] SPAB1 = ll_d1 - ll L1d707 = Calc(0.70, 0, object, lens, pupil, image, 'd')[1] ll_d707 = L1d707[-1] SPAB707 = ll_d707 - ll L1F1 = Calc(1, 0, object, lens, pupil, image, 'F')[1] ll_F1 = L1F1[-1] L1C1 = Calc(1, 0, object, lens, pupil, image, 'C')[1] ll_C1 = L1C1[-1] L1F707 = Calc(0.70, 0, object, lens, pupil, image, 'F')[1] ll_F707 = L1F707[-1] L1C707 = Calc(0.70, 0, object, lens, pupil, image, 'C')[1] ll_C707 = L1C707[-1] L1F0 = Calc(oo, 0, object, lens, pupil, image, 'F')[1] ll_F0 = L1F0[-1] L1C0 = Calc(oo, 0, object, lens, pupil, image, 'C')[1] ll_C0 = L1C0[-1] PCA1 = ll_F1 - ll_C1 PCA707 = ll_F707 - ll_C707 PCA0 = ll_F0 - ll_C0 data2 = [ll_d1, ll_F1, ll_C1, SPAB1, PCA1] data3 = [ll_d707, ll_F707, ll_C707, SPAB707, PCA707] data4 = [PCA0] return data2, data3, data4 #5、计算全视场、0.7视场、正负全孔径、正负0.7孔径的彗差、两个视场dFC光实际像高,绝对畸变、相对畸变、倍率色差 def Calc_coma(object, lens, pupil, image, oo, y0, y0_707): #轴上物点,求理想像面 LL_perfect_d = Calc(oo, 0, object, lens, pupil, image, 'd')[1] '''获取实际光线数据''' #全视场,全孔径数据 LL_upper_d = Calc(1, -1, object, lens, pupil, image, 'd')[1] UU_upper_d = Calc(1, -1, object, lens, pupil, image, 'd')[2] LL_central_d = Calc(0, -1, object, lens, pupil, image, 'd')[1] UU_central_d = Calc(0, -1, object, lens, pupil, image, 'd')[2] LL_down_d = Calc(-1, -1, object, lens, pupil, image, 'd')[1] UU_down_d = Calc(-1, -1, object, lens, pupil, image, 'd')[2] #全视场,0.7孔径数据 LL_upper_d_1_07 = Calc(0.7, -1, object, lens, pupil, image, 'd')[1] UU_upper_d_1_07 = Calc(0.7, -1, object, lens, pupil, image, 'd')[2] LL_central_d_1_07 = Calc(0, -1, object, lens, pupil, image, 'd')[1] UU_central_d_1_07 = Calc(0, -1, object, lens, pupil, image, 'd')[2] LL_down_d_1_07 = Calc(-0.7, -1, object, lens, pupil, image, 'd')[1] UU_down_d_1_07 = Calc(-0.7, -1, object, lens, pupil, image, 'd')[2] #0.7视场,全孔径数据 LL_upper_d_07_1 = Calc(1, -0.7, object, lens, pupil, image, 'd')[1] UU_upper_d_07_1 = Calc(1, -0.7, object, lens, pupil, image, 'd')[2] LL_central_d_07_1 = Calc(0, -0.7, object, lens, pupil, image, 'd')[1] UU_central_d_07_1 = Calc(0, -0.7, object, lens, pupil, image, 'd')[2] LL_down_d_07_1 = Calc(-1, -0.7, object, lens, pupil, image, 'd')[1] UU_down_d_07_1 = Calc(-1, -0.7, object, lens, pupil, image, 'd')[2] #0.7视场,0.7孔径数据 LL_upper_d_07_07 = Calc(0.7, -0.7, object, lens, pupil, image, 'd')[1] UU_upper_d_07_07 = Calc(0.7, -0.7, object, lens, pupil, image, 'd')[2] LL_central_d_07_07 = Calc(0, -0.7, object, lens, pupil, image, 'd')[1] UU_central_d_07_07 = Calc(0, -0.7, object, lens, pupil, image, 'd')[2] LL_down_d_07_07 = Calc(-0.7, -0.7, object, lens, pupil, image, 'd')[1] UU_down_d_07_07 = Calc(-0.7, -0.7, object, lens, pupil, image, 'd')[2] '''计算彗差''' #全视场、全孔径彗差 y_upper = (LL_perfect_d[-1] - LL_upper_d[-1]) * np.tan(UU_upper_d[-1]) y_down = (LL_perfect_d[-1] - LL_down_d[-1]) * np.tan(UU_down_d[-1]) y_central = (LL_perfect_d[-1] - LL_central_d[-1]) * np.tan(UU_central_d[-1]) COMA1 = (y_upper + y_down) / 2 - y_central #全视场,0.7孔径彗差 y_upper_1_07 = (LL_perfect_d[-1] - LL_upper_d_1_07[-1]) * np.tan(UU_upper_d_1_07[-1]) y_down_1_07 = (LL_perfect_d[-1] - LL_down_d_1_07[-1]) * np.tan(UU_down_d_1_07[-1]) y_central_1_07 = (LL_perfect_d[-1] - LL_central_d_1_07[-1]) * np.tan(UU_central_d_1_07[-1]) COMA2 = (y_upper_1_07 + y_down_1_07) / 2 - y_central_1_07 #0.7视场,全孔径 y_upper_07_1 = (LL_perfect_d[-1] - LL_upper_d_07_1[-1]) * np.tan(UU_upper_d_07_1[-1]) y_down_07_1 = (LL_perfect_d[-1] - LL_down_d_07_1[-1]) * np.tan(UU_down_d_07_1[-1]) y_central_07_1 = (LL_perfect_d[-1] - LL_central_d_07_1[-1]) * np.tan(UU_central_d_07_1[-1]) COMA3 = (y_upper_07_1 + y_down_07_1) / 2 - y_central_07_1 #0.7视场,0.7孔径 y_upper_07_07 = (LL_perfect_d[-1] - LL_upper_d_07_07[-1]) * np.tan(UU_upper_d_07_07[-1]) y_down_07_07 = (LL_perfect_d[-1] - LL_down_d_07_07[-1]) * np.tan(UU_down_d_07_07[-1]) y_central_07_07 = (LL_perfect_d[-1] - LL_central_d_07_07[-1]) * np.tan(UU_central_d_07_07[-1]) COMA4 = (y_upper_07_07 + y_down_07_07) / 2 - y_central_07_07 '''计算实际像高''' #全视场dFC光实际像高 LL_central_C = Calc(0, -1, object, lens, pupil, image, 'C')[1] UU_central_C = Calc(0, -1, object, lens, pupil, image, 'C')[2] LL_central_F = Calc(0, -1, object, lens, pupil, image, 'F')[1] UU_central_F = Calc(0, -1, object, lens, pupil, image, 'F')[2] y_d_1 = (LL_perfect_d[-1] - LL_central_d[-1]) * np.tan(UU_central_d[-1]) y_C_1 = (LL_perfect_d[-1] - LL_central_C[-1]) * np.tan(UU_central_C[-1]) y_F_1 = (LL_perfect_d[-1] - LL_central_F[-1]) * np.tan(UU_central_F[-1]) #0.7视场dFC光实际像高 LL_central_C_07_1 = Calc(0, -0.7, object, lens, pupil, image, 'C')[1] UU_central_C_07_1 = Calc(0, -0.7, object, lens, pupil, image, 'C')[2] LL_central_F_07_1 = Calc(0, -0.7, object, lens, pupil, image, 'F')[1] UU_central_F_07_1 = Calc(0, -0.7, object, lens, pupil, image, 'F')[2] y_d_07 = (LL_perfect_d[-1] - LL_central_d_07_1[-1]) * np.tan(UU_central_d_07_1[-1]) y_C_07 = (LL_perfect_d[-1] - LL_central_C_07_1[-1]) * np.tan(UU_central_C_07_1[-1]) y_F_07 = (LL_perfect_d[-1] - LL_central_F_07_1[-1]) * np.tan(UU_central_F_07_1[-1]) '''计算倍率色差''' MCA1 = (y_F_1 - y_C_1) #全视场倍率色差 MCA07 = (y_F_07 - y_C_07) #0.7视场倍率色差 '''计算绝对畸变,相对畸变''' DIS1 = y_d_1 - y0 rel_DIS1 = DIS1 / y0 DIS07 = y_d_07 - y0_707 rel_DIS07 = DIS07 / y0_707 #全视场的 全孔径子午彗差, 0.7孔径子午彗差, d光实际像高, F光实际像高, C光实际像高, 绝对畸变, 相对畸变, 倍率色差 data5 = [COMA1, COMA2, y_d_1, y_F_1, y_C_1, DIS1, rel_DIS1, MCA1] #0.707视场的 全孔径子午彗差, 0.7孔径子午彗差, d光实际像高, F光实际像高, C光实际像高, 绝对畸变, 相对畸变, 倍率色差 data6 = [COMA3, COMA4, y_d_07, y_F_07, y_C_07, DIS07, rel_DIS07, MCA07] return data5, data6 input_label = ['输入-无限远平行光.xlsx', '输入-轴上有限远物.xlsx'] output_label = ['输出-无限远平行光.xlsx', '输出-轴上有限远物.xlsx'] for i in range(2): object, lens, pupil, image = read_excel(input_label[i]) data1, data2, data3, data4, data5, data6 = data_processing(object, lens, pupil, image) write_excel(data1, data2, data3, data4, data5, data6, output_label[i]) print("\nOUTPUT SUCCESSFULLY!\n")以上是一个光学计算软件的程序,请为其编写一个GUI界面包括各种镜头参数的输入,光学表面及其参数的输入,结果的输出与显示,类似下面这种(形式差不多)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") # 物方参数 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:.4f}", f"{vd:.1f}" )) # 清空输入框 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") # 更新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)) # 加载表面数据 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:.4f}", f"{surface.vd:.1f}" )) 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] } 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:.4f}, vd={surf.vd:.1f}\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() # 物方参数 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)[0] self.system.results["ideal_image_distance"] = 0#Calculate.calculate_ideal_image_distance(self.system) self.system.results["actual_image_position"] =0# Calculate.calculate_actual_image_position(self.system) self.system.results["image_principal_plane"] = Calculate.calculate_focal_length(self.system)[1] self.system.results["exit_pupil_distance"] = 0#Calculate.calculate_exit_pupil_distance(self.system) self.system.results["ideal_image_height"] =0# Calculate.calculate_ideal_image_height(self.system) self.system.results["spherical_aberration"] = 0#Calculate.calculate_spherical_aberration(self.system) self.system.results["longitudinal_chromatic"] = 0#Calculate.calculate_longitudinal_chromatic(self.system) self.system.results["tangential_field_curvature"] = 0.15 self.system.results["sagittal_field_curvature"] = 0.12 self.system.results["astigmatism"] = 0#Calculate.calculate_astigmatism(self.system) self.system.results["actual_image_height"] =0#Calculate.calculate_actual_image_height(self.system) self.system.results["relative_distortion"] = -0.5 self.system.results["absolute_distortion"] =0# Calculate.calculate_distortion(self.system) self.system.results["lateral_chromatic"] =0# Calculate.calculate_lateral_chromatic(self.system) self.system.results["tangential_coma"] =0# 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") 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:.4f}, vd={surf.vd:.1f}\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.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
06-27
<think>我们有一个光学计算程序,现在需要为它创建一个GUI界面。根据提供的代码,程序主要包含以下功能:1.从Excel文件读取光学系统参数(物面、镜面、入瞳、像面数据)2.进行光线追迹和像差计算3.将计算结果写入Excel文件我们需要设计一个GUI,允许用户输入光学系统的参数(包括物方参数、入瞳参数、各个光学表面的参数),然后进行计算,并显示和保存结果。根据提供的示例GUI代码,我们可以参考其结构来设计。主要包含以下部分: -文件操作:加载和保存系统参数(可以保存为JSON或Excel格式?) -参数输入:包括入瞳参数、物方参数(选择无穷远或有限远,并输入相应参数)、光学表面列表(可以添加、删除表面,每个表面包括曲率半径、厚度、折射率、阿贝数等) -计算按钮:触发计算-结果显示区域:显示计算结果(文本形式,包括各种像差等)由于我们的计算程序已经实现了从Excel读取和写入,我们可以考虑在GUI中整合这些功能,同时提供用户友好的输入方式。步骤:1.设计主窗口,包含菜单栏、文件操作区域、参数输入区域、计算按钮、结果展示区域。2.参数输入区域分为几个部分:入瞳参数、物方参数、光学表面列表。3.光学表面列表使用Treeview来显示,并提供添加和删除按钮。4.计算按钮触发计算,调用我们已有的计算函数(注意:需要将GUI输入的数据转换为计算程序所需的格式,然后调用data_processing函数,最后将结果写入输出文件,并在GUI中显示结果)。5.结果展示区域可以使用Text控件,也可以考虑使用表格(Treeview)来展示多个计算结果。注意:我们的计算程序需要的数据结构包括:- object: Surface对象-lens:Surface对象列表-pupil:Surface对象- image: Surface对象在GUI中,我们需要收集这些数据。由于计算程序已经有两个输入案例(无限远平行光和轴上有限远物),我们可以通过物方参数的选择来区分。具体设计:1.文件操作:-加载系统参数:从JSON文件加载(因为JSON易于保存和读取,也可以考虑支持Excel,但示例中提供了JSON)-保存系统参数:将当前输入的系统参数保存为JSON文件-保存计算结果:将计算结果保存为文本文件或Excel文件(我们的计算程序原本是写入Excel,所以可以直接调用write_excel函数)2.入瞳参数:-入瞳直径(semi_dia?注意程序中的semi_dia是半通光孔径,所以这里应该是直径?需要确认。在程序中,物在无穷远时semi_dia代表视场角,但入瞳的semi_dia应该是半孔径。所以入瞳参数我们输入直径,然后在程序中除以2作为半孔径?或者直接输入半孔径?根据程序中的Surface定义,semi_dia是半通光孔径。所以我们在GUI中应该输入半孔径?但通常入瞳直径指的是直径。所以我们可以让用户输入直径,然后除以2作为半孔径存储。或者直接输入半孔径?为了和程序一致,我们让用户输入半孔径(单位:mm)和入瞳位置(单位:mm)。3.物方参数:-提供单选按钮:物在无穷远/物在有限远-无穷远:输入视场角(半视场角,单位:度)->对应object.semi_dia(注意在无穷远时,object.semi_dia代表视场角,而object.thickness为None)-有限远:输入物距(单位:mm)、物高(单位:mm)、孔径角(单位:度)?注意在程序中,有限远物面,object.semi_dia是物高(线视场的一半?还是全高?根据程序中的注释,物面semi_dia是半通光孔径,但根据有限远物的计算,它代表物高(半高)?在程序中,有限远物面,object.semi_dia是物高(半高),而object.thickness是物距(从第一面到物的距离,为负值?)。在read_excel函数中,有限远物的物面厚度是正数(因为是从物面到第一面的距离)。所以我们在GUI中:-物距:输入正数,表示从物面到第一面的距离(单位:mm)-物高:输入半高(单位:mm)?还是全高?根据程序中的注释,物面semi_dia是半通光孔径,但在有限远物中,它代表物高(半高)。所以输入半高。4.光学表面:-每个表面包括:-曲率半径(mm):可以是无穷大(平面)-厚度(mm):到下一面的距离-折射率(nd):d光的折射率-阿贝数(vd):用于计算F光和C光的折射率(nF =nd -1/vd,nC= nd+1/vd)?注意在程序中,每个面需要提供nd0,nF0,nC0(物方折射率)和nd1, nF1, nC1(像方折射率)。在GUI中,我们只需要输入像方折射率(nd)和阿贝数(vd),然后根据阿贝数计算nF和nC。注意相邻面的折射率关系:当前面的像方折射率等于下一面的物方折射率。所以我们需要在构建表面列表时,根据相邻面设置折射率。5.像面:在计算程序中,像面也是一个Surface对象,但通常厚度为0(或者最后一面的厚度就是像距?)。在GUI中,我们不需要单独输入像面参数,因为像面由最后一面的厚度决定(在计算中,最后一面的厚度就是像距)。所以我们在表面列表中,最后一面的厚度就是像距(从最后一面到像面的距离)。6.计算触发:-点击“计算”按钮,将收集的参数构建成object, lens, pupil, image对象,然后调用data_processing函数。-将计算结果写入输出Excel文件(可以指定路径),同时在GUI的结果区域显示主要结果。7.结果展示:-我们可以在文本区域显示计算结果,也可以考虑用表格显示多个结果(38个数据)。但文本区域比较简单,我们可以将计算结果格式化输出。8.注意:在计算程序中,我们有两种情况(无限远和有限远),在构建object对象时需要区分。实现:我们将创建一个类MainApplication,包含上述GUI元素。同时,我们需要定义Surface类(已经存在)和OpticalSystem类(用于存储整个系统的参数,包括入瞳、物方、表面列表等)。由于计算程序已经存在,我们只需要将GUI输入的数据转换为计算程序所需的数据结构即可。具体步骤:1.定义OpticalSystem类,用于存储系统参数(入瞳参数、物方参数、表面列表)。2.在GUI中,当用户点击“计算”时,从输入控件中读取参数,构建OpticalSystem对象。3.根据OpticalSystem对象创建object,lens,pupil,image对象。4.调用data_processing函数,得到6组数据(data1, data2,data3, data4,data5, data6)。5.调用write_excel函数将结果写入Excel文件(可以弹出保存对话框或使用默认路径)。6.在结果文本区域显示这些数据(格式化输出)。注意:在构建表面列表时,折射率的传递:第一个面的物方折射率是空气(1.0),然后每个面的像方折射率就是该面输入的折射率(nd),而下一个面的物方折射率等于当前面的像方折射率。所以我们需要在构建lens列表时,设置每个面的物方折射率(nd0, nF0, nC0)为前一面的像方折射率(nd1,nF1,nC1)。对于第一个面,物方折射率就是1.0(空气),然后根据阿贝数计算F光和C光的折射率(nF0=1.0,nC0=1.0?不对,应该是空气的折射率,F光和C光也是1.0)。对于入瞳,在计算中并不需要折射率,所以pupil的折射率可以忽略(在程序中,入瞳的折射率参数在计算中并未使用,因为入瞳只是一个孔径光阑,不改变光线方向)。关于折射率的计算:-对于每个表面,我们输入nd和vd(阿贝数),则:nF =nd -1/vd(注意:通常阿贝数vd=(nd-1)/(nF-nC),所以nF-nC=(nd-1)/vd,然后通常nF和nC的计算公式为:nF=nd-(nd-1)/vd,nC=nd+(nd-1)/vd?但实际折射率分布需要根据玻璃材料。这里我们采用:nF =nd -(nd-1)/vd, nC =nd +(nd-1)/vd?不对,标准公式是:nF= nd- (nd-1)/(vd *(nF-nC))?实际上,我们通常用近似公式:nF= nd- (nd-1)/vd *(1/(λF-λC)),但简单做法是使用:nF =nd -(nd-1)/vd*0.5?不对,阿贝数定义为:vd=(nd-1)/(nF-nC),所以nF-nC=(nd-1)/vd。而通常F光和C光的波长是固定的,所以我们可以认为nF和nC关于nd对称,即:nF =nd -(nd-1)/(2*vd),nC=nd +(nd-1)/(2*vd)。但更准确的做法是使用标准波长,这里我们采用简化公式。然而,在程序中,我们直接输入了每个面的nd1, nF1, nC1(像方折射率)。在GUI中,我们只输入nd和vd,所以我们需要由vd计算出nF和nC。根据阿贝数的定义:vd =(nd-1)/ (nF- nC)=>nF -nC= (nd -1) /vd然后,我们还需要知道F光和C光的折射率相对于d光的偏移。通常,我们使用以下公式:nF =nd -(nd-1)/ vd *K1nC =nd +(nd-1)/ vd *K2其中,K1和K2是系数,对于不同的波长区间,有不同的值。在标准光学计算中,通常取K1=0.5, K2=0.5?实际上,对于F光(486.1nm)和C光(656.3nm),d光是587.6nm,但具体偏移量没有固定比例。不过,在简化计算中,我们可以假设:nF =nd -(nd-1)/(2*vd)[因为nF-nC=(nd-1)/vd,所以从nd到nF的差为(nF-nC)/2?]nC= nd+ (nd-1)/(2*vd)但更常见的做法是使用预定义的表(比如玻璃库),但我们这里简化处理,使用上述公式。因此,对于每个表面,我们输入nd和vd后,计算:nF =nd -(nd-1)/ (2 *vd)nC =nd +(nd-1)/ (2 *vd)注意:当vd为0时(比如反射镜),我们无法计算,所以反射镜需要特殊处理(折射率相同,符号相反?但我们的程序目前不支持反射镜,所以先不考虑)。开始编写代码:我们将使用tkinter,并参考提供的示例GUI代码。由于代码较长,我们将分步骤实现。注意:由于计算程序使用了openpyxl和numpy,我们需要确保这些库已安装。步骤:1.创建主窗口,设置标题和大小。2.创建文件操作区域(浏览、加载、保存系统参数)。3.创建入瞳参数输入区域。4.创建物方参数输入区域(包括单选按钮切换)。5.创建光学表面输入区域(输入框和添加、删除按钮,以及表面列表)。6.创建计算按钮和结果展示区域。然后定义事件处理函数:-浏览文件-加载系统参数(从JSON)-保存系统参数(到JSON)-添加表面-删除表面-计算-保存计算结果(到Excel和文本显示)另外,我们需要一个OpticalSystem类来存储系统参数。由于原计算程序已经很长,我们将GUI和计算程序整合在一个文件中,或者将计算程序作为模块导入。为了方便,我们将整个程序放在一个文件中(但很长)。我们可以将计算程序放在一个单独的文件中,然后导入。但为了简化,我们这里放在一个文件中。注意:原计算程序使用了openpyxl和numpy,所以需要安装。由于代码量很大,我们只实现基本功能,确保能够运行计算。开始编写:</think># 光学计算软件GUI实现 我将基于您提供的代码实现一个完整的光学计算软件GUI界面。这个界面将包含参数输入、光学表面管理、计算执行和结果展示功能。 ```python import tkinter as tk from tkinter import ttk, filedialog, messagebox import json import os import numpy as np import openpyxl as pyxl # 从您提供的代码中导入计算函数 # 注意: 这里需要包含您之前提供的所有计算函数代码 # 由于代码长度限制,我将省略重复的计算函数代码 # 在实际应用中,请确保这些函数可用 class Surface: def __init__(self, radius=0, thickness=0, nd1=1.0, nF1=None, nC1=None, semi_dia=0, vd=None): self.radius = radius self.thickness = thickness self.nd1 = nd1 self.semi_dia = semi_dia # 如果提供了阿贝数,计算F光和C光的折射率 if vd is not None: self.vd = vd self.nF1 = nd1 - (nd1 - 1) / vd self.nC1 = nd1 + (nd1 - 1) / vd else: self.vd = vd self.nF1 = nF1 if nF1 is not None else nd1 self.nC1 = nC1 if nC1 is not None else nd1 # 物方折射率初始化为空气 (1.0) self.nd0 = 1.0 self.nF0 = 1.0 self.nC0 = 1.0 def to_dict(self): return { "radius": self.radius, "thickness": self.thickness, "nd1": self.nd1, "nF1": self.nF1, "nC1": self.nC1, "semi_dia": self.semi_dia, "vd": self.vd } @classmethod def from_dict(cls, data): return cls( radius=data.get("radius", 0), thickness=data.get("thickness", 0), nd1=data.get("nd1", 1.0), nF1=data.get("nF1", None), nC1=data.get("nC1", None), semi_dia=data.get("semi_dia", 0), vd=data.get("vd", None) ) class OpticalSystem: def __init__(self): self.entrance_pupil_diameter = None # 入瞳直径 (mm) self.entrance_pupil_position = None # 入瞳位置 (mm) self.light_type = "d" # 色光类型 (d, F, C) self.object_infinite = True # 物在无穷远 self.field_angle = None # 半视场角 () self.object_distance = None # 物距 (mm) self.object_height = None # 物高 (mm) self.aperture_angle = None # 孔径角 () self.surfaces = [] # 光学表面列表 # 计算结果存储 self.results = { "focal_length": None, # 焦距 f' (mm) "ideal_image_distance": None, # 理想像距 l' (mm) "actual_image_position": None, # 实际像位置 (mm) "image_principal_plane": None, # 像方主面位置 lH' (mm) "exit_pupil_distance": None, # 出瞳距 lp' (mm) "ideal_image_height": None, # 理想像高 y0' (mm) "spherical_aberration": None, # 球差 (mm) "longitudinal_chromatic": None, # 位置色差 (mm) "tangential_field_curvature": None, # 子午场曲 xt' (mm) "sagittal_field_curvature": None, # 弧矢场曲 xs' (mm) "astigmatism": None, # 像散 Δxts' (mm) "actual_image_height": None, # 实际像高 (mm) "relative_distortion": None, # 相对畸变 (%) "absolute_distortion": None, # 绝对畸变 (mm) "lateral_chromatic": None, # 倍率色差 (mm) "tangential_coma": None # 子午慧差 (mm) } 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") # 物方参数 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) # 设置标签样式 self.result_text.tag_configure("title", font=("Arial", 12, "bold")) self.result_text.tag_configure("subtitle", font=("Arial", 10, "bold")) 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=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:.4f}", f"{vd:.1f}" )) # 清空输入框 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.light_type = data.get("light_type", "d") 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") # 更新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.light_type_var.set(self.system.light_type) 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)) # 加载表面数据 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.radius == float('inf') else f"{surface.radius:.2f}" self.surface_tree.insert("", "end", values=( len(self.system.surfaces), r_str, f"{surface.thickness:.2f}", f"{surface.nd1:.4f}", f"{surface.vd:.1f}" if surface.vd is not None else "N/A" )) 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, "light_type": self.system.light_type, "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] } 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"), ("Excel文件", "*.xlsx"), ("所有文件", "*.*")] ) if not file_path: return try: if file_path.endswith(".xlsx"): # 保存为Excel文件 self.save_results_to_excel(file_path) else: # 保存为文本文件 self.save_results_to_text(file_path) 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_to_text(self, file_path): """将计算结果保存为文本文件""" 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.radius == float('inf') else f"{surf.radius:.2f} mm" f.write(f"表面 {i+1}: r={r_str}, d={surf.thickness:.2f} mm, nd={surf.nd1:.4f}, vd={surf.vd:.1f}\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") def save_results_to_excel(self, file_path): """将计算结果保存为Excel文件""" # 创建Excel工作簿 wb = pyxl.Workbook() ws = wb.active ws.title = "计算结果" # 写入系统参数 ws.append(["光学系统参数"]) ws.append(["入瞳直径 (mm)", self.system.entrance_pupil_diameter]) ws.append(["入瞳位置 (mm)", self.system.entrance_pupil_position]) ws.append(["色光类型", self.system.light_type]) ws.append(["物距类型", "无穷远" if self.system.object_infinite else "有限远"]) if self.system.object_infinite: ws.append(["半视场角 ()", self.system.field_angle]) else: ws.append(["物距 (mm)", self.system.object_distance]) ws.append(["物高 (mm)", self.system.object_height]) ws.append(["孔径角 ()", self.system.aperture_angle]) ws.append([]) ws.append(["光学表面参数"]) ws.append(["表面", "曲率半径 (mm)", "厚度 (mm)", "折射率 (nd)", "阿贝数 (vd)"]) for i, surf in enumerate(self.system.surfaces): r_str = "平面" if surf.radius == float('inf') else f"{surf.radius:.2f}" ws.append([i+1, r_str, surf.thickness, surf.nd1, surf.vd]) ws.append([]) ws.append(["计算结果"]) ws.append(["参数", "值"]) for key, value in self.system.results.items(): if value is not None: label = self.format_result_label(key) ws.append([label, value]) # 调整列宽 for column in ws.columns: max_length = 0 column = [cell for cell in column] for cell in column: try: if len(str(cell.value)) > max_length: max_length = len(cell.value) except: pass adjusted_width = (max_length + 2) * 1.2 ws.column_dimensions[column[0].column_letter].width = adjusted_width # 保存文件 wb.save(file_path) 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() # 物方参数 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 try: # 创建光学表面对象 object = Surface( radius=0, thickness=None if self.system.object_infinite else self.system.object_distance, nd1=1.0, # 物方折射率设为空气 semi_dia=self.system.field_angle if self.system.object_infinite else self.system.object_height ) # 创建入瞳对象 pupil = Surface( radius=0, thickness=self.system.entrance_pupil_position, nd1=1.0, semi_dia=self.system.entrance_pupil_diameter / 2 # 半通光孔径 ) # 创建镜面列表 lens = [] for i, surf in enumerate(self.system.surfaces): # 设置物方折射率为前一面的像方折射率 if i > 0: surf.nd0 = lens[i-1].nd1 surf.nF0 = lens[i-1].nF1 surf.nC0 = lens[i-1].nC1 lens.append(surf) # 创建像面对象 image = Surface( radius=0, thickness=0, # 像面厚度为0 nd1=1.0, semi_dia=0 ) # 调用计算函数 data1, data2, data3, data4, data5, data6 = data_processing(object, lens, pupil, image) # 将计算结果存储到系统对象 self.system.results["focal_length"] = data1[0] # f' self.system.results["ideal_image_distance"] = data1[1] # l' self.system.results["image_principal_plane"] = data1[2] # lH' self.system.results["exit_pupil_distance"] = data1[3] # lp' self.system.results["ideal_image_height"] = data1[4] # y0' self.system.results["spherical_aberration"] = data2[3] # 球差 self.system.results["longitudinal_chromatic"] = data2[4] # 位置色差 self.system.results["tangential_field_curvature"] = data1[6] # 子午场曲 xt' self.system.results["sagittal_field_curvature"] = data1[7] # 弧矢场曲 xs' self.system.results["astigmatism"] = data1[8] # 像散 Δxts' self.system.results["actual_image_height"] = data5[2] # 实际像高 (全视场) self.system.results["relative_distortion"] = data5[6] * 100 # 相对畸变 (%) self.system.results["absolute_distortion"] = data5[5] # 绝对畸变 (mm) self.system.results["lateral_chromatic"] = data5[7] # 倍率色差 (全视场) self.system.results["tangential_coma"] = data5[0] # 子午慧差 (全视场全孔径) except Exception as e: messagebox.showerror("计算错误", f"光学计算失败: {str(e)}") 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") 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", "subtitle") for i, surf in enumerate(self.system.surfaces): r_str = "平面" if surf.radius == float('inf') else f"{surf.radius:.2f} mm" self.result_text.insert(tk.END, f"表面 {i+1}: r={r_str}, d={surf.thickness:.2f} mm, nd={surf.nd1:.4f}, vd={surf.vd:.1f}\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]:.4f}\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) # 特殊处理百分比值 if key == "relative_distortion": self.result_text.insert(tk.END, f"{label}: {self.system.results[key]:.2f}%\n") else: self.result_text.insert(tk.END, f"{label}: {self.system.results[key]:.4f}\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.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) root.mainloop() ``` ## 代码解释 这个GUI界面包含以下主要功能: ### 1. 文件操作 - **浏览**:选择系统参数文件 - **加载系统参数**:从JSON文件加载光学系统配置 - **保存系统参数**:将当前配置保存为JSON文件 ### 2. 参数输入 - **入瞳参数**:入瞳直径和位置 - **色光类型**:选择d、F或C光 - **物方参数**: - 物在无穷远:输入半视场角 - 物在有限远:输入物距、物高和孔径角 - **光学表面参数**: - 曲率半径(可设为无穷大表示平面) - 厚度 - 折射率(nd) - 阿贝数(vd) - 添加/删除表面功能 ### 3. 计算功能 - **开始计算**:执行光学计算 - **保存计算结果**:将结果保存为文本或Excel文件 - **清除所有**:重置所有输入和结果 ### 4. 结果展示 - 显示系统参数摘要 - 显示光学表面参数列表 - 显示详细计算结果: - 焦距、像距、主面位置等基本参数 - 球差、位置色差、场曲、像散等像差分析 - 畸变、倍率色差、慧差等 ### 5. 数据结构 - **Surface类**:表示光学表面,包含曲率半径、厚度、折射率等参数 - **OpticalSystem类**:存储整个光学系统的配置和计算结果 - 支持JSON格式的导入导出 ## 使用说明 1. **输入系统参数**: - 设置入瞳参数 - 选择物方类型(无穷远或有限远) - 添加光学表面(至少一个) 2. **执行计算**: - 点击"开始计算"按钮执行光学计算 - 结果将显示在右侧面板中 3. **保存结果**: - 可以保存系统配置为JSON文件 - 可以保存计算结果为文本或Excel文件 4. **加载配置**: - 可以从JSON文件加载先前保存的系统配置 ## 注意事项 1. 在实际运行前,请确保已安装所需的依赖库: ``` pip install numpy openpyxl ``` 2. 本代码需要与您之前提供的光学计算函数配合使用。请确保这些函数可用并正确导入。 3. 对于复杂的系统,可能需要调整界面尺寸或添加滚动条以适应更多光学表面。 4. 计算结果保存功能支持文本和Excel两种格式,用户可以根据需要选择。 这个GUI界面提供了一个直观、用户友好的方式来配置光学系统参数、执行计算并查看结果,完全符合您的需求。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值