提问人:Jack2023 提问时间:11/16/2023 最后编辑:Jack2023 更新时间:11/16/2023 访问量:69
如何获得更美观的平凸酰晶透镜 2D(俯视图/侧视图)图纸?[关闭]
How do I obtain better-looking plano-convex acylindrical lens 2D (top/side views) drawing? [closed]
问:
我正在通过 Python matplotlib 绘制平凸酰基透镜 2D(顶/侧视图)绘图。与LibreCAD / FreeCAD / SolidWorks等的绘图相比,这种方法更吸引我,因为:
- 它是免费的,无需安装繁重的软件。
- 在绘制大量变体时,它可以节省时间。
- 它很容易实现非球面曲线并显示方程。
- 我特别想玩 Python。
目标不是从 CAD 软件中重现完全相同的结果。相反,我想改进绘图并使其更好看。
到目前为止,我制作了一个简单的模板,请参阅下面的代码。请注意,我画的不是真正的镜头,所以不要注意数值。我正在寻找帮助来制作更美观的细节和/或更好地实现 Python 方法。更详细的子问题:
- 我用 \genfrac 显示了容差。如何使用较小的字体使 +- 值与其他文本对齐?
- 至于表面下垂方程,我如何使所有东西,尤其是分子和分母,字体大小相同?
- 对于柱面透镜,我需要半径尺寸。我绘制了一个角度为 theta 且文本旋转 90 度 (theta) 的示例。但文本没有对齐。如何计算正确的旋转角度?
- 引线(S1,S2)采用“弧形”连接方式制成,这不是一个糟糕的解决方案。引线只是一个箭头加上一段水平线。有什么简单的方法可以在不创建用户定义的函数的情况下实现领导者?
- 如何在没有用户定义的形状的情况下使注释箭头更薄更长?
以下是输出pdf文件:
以下是我的代码:
#This script is to automatically generate acylindrical lens drawing.
#Created by Jack.
#Last updated: 11/15/2023. Last run took 2.3 seconds on i7 laptop.
import time
start_time = time.time()
from numpy import *
import matplotlib.pyplot as plt
import matplotlib.patches as mpatches
#Lens information.
n = 1.9 #Glass material.
EFL = 7.0 #Effective focal length of lens.
BFL = 6.000000 #Read from "System Data" in Zemax.
W = 6.0 #Width of the lens.
H = 6.0 #Height of the lens.
t = 2.0 #Desirable lens central thickness. To be modified based on drawing and edge thickness.
#The acylindrical surface coefficients from Zemax.
R = 5.8
k = 0.04
A4 = -5E-004
A6 = -3E-005
A8 = -1E-007
A10 = -7E-009
A12 = 9E-011
A14 = -4E-011
#Lens dsrawing settings. For all labeling of point see the plot visualization section below.
#Start point of drawing: focal point (point "Q").
qx = 14 #X-coordinate in mm.
qy = 10 #Y-coordinate in mm.
#Gap between the views.
gap = 3 #In mm.
#Lens coordinates: SAOL top view.
vx = qx - BFL - t #Vertex "V" of the lens curved surface: the central point.
vy = qy
px = qx - EFL #Optical center "P".
py = qy
ax = qx - BFL #Lens upper edge vertex of the flat side: point "A".
ay = qy + W/2
bx = ax #Lens lower edge vertex of the flat side: point "B".
by = qy - W/2
#To define the acylindrical surface
y0 = linspace(-W/2, W/2, int(W*100+1), endpoint=True)
sag = y0**2/R/(1+sqrt(1-(1+k)*y0**2/R**2)) + A4*y0**4 + A6*y0**6 + A8*y0**8 + A10*y0**10 + A12*y0**12 + A14*y0**14
edge = t-(max(sag)-min(sag))
cx = qx - BFL - edge #Lens upper edge vertex of the curved side: point "C".
cy = ay
dx = cx #Lens upper edge vertex of the curved side: point "D".
dy = by
#Lens coordinates: SAOL side view.
ex = ax #Lens upper edge vertex of the flat side: point "E".
ey = ay + gap + H
fx = ex #Lens lower edge vertex of the flat side: point "F".
fy = ey - H
gx = cx #Lens upper edge vertex of the middle side: point "G".
gy = ey
hx = gx #Lens lower edge vertex of the middle side: point "H".
hy = fy
ix = vx #Lens upper edge vertex of the curved side: point "I".
iy = gy
jx = ix #Lens lower edge vertex of the curved side: point "J".
jy = hy
#Make the plot.
plt.figure(1)
#General settings.
linewidth = 0.5
#To visualize all critical points. Uncomment the scatter and text to visualize.
x_all = [ax,bx,cx,dx,ex,fx,gx,hx,ix,jx,px,qx,vx]
y_all = [ay,by,cy,dy,ey,fy,gy,hy,iy,jy,py,qy,vy]
letters = ['A','B','C','D','E','F','G','H','I','J','P','Q','V']
plt.scatter(x_all, y_all, label='critical_points', marker='x', color='tab:blue', s=20)
plt.xlim(-0, 30)
plt.ylim(-0, 30)
#To label all critical points.
for i in range(len(x_all)):
plt.text(x_all[i]+0.1, y_all[i]+0.2, letters[i], fontsize=6, color='tab:blue')
i+= 0 #Do nothing to keep the for loop if "plt.text' commented.
#To make the lens top view (SAOL).
plt.plot([ax,bx], [ay,by], color='k', lw=linewidth)
plt.plot([ax,cx], [ay,cy], color='k', lw=linewidth)
plt.plot([bx,dx], [by,dy], color='k', lw=linewidth)
#To draw the curve.
plt.plot(sag+vx, y0+qy, color='k', lw=linewidth)
#To make the lens side view (SAOL).
plt.plot([ex,fx], [ey,fy], color='k', lw=linewidth)
plt.plot([fx,jx], [fy,jy], color='k', lw=linewidth)
plt.plot([jx,ix], [jy,iy], color='k', lw=linewidth)
plt.plot([ix,ex], [iy,ey], color='k', lw=linewidth)
plt.plot([gx,hx], [gy,hy], color='k', lw=linewidth)
#To mark the optical center and focal point.
plt.plot([px,px], [py+1,py-1], color='magenta', lw=linewidth)
plt.plot([qx,qx], [qy+0.75,qy-0.75], color='magenta', lw=linewidth)
plt.plot([qx-0.75,qx+0.75], [qy,qy], color='magenta', lw=linewidth)
#Dimensioning.
font_dim = 8 #Fontsize of dimensioning.
#Define function of annotating dimensions.
def dim(pointA, pointB, depth, text_string, horizontal):
if horizontal==True:
if depth > 0:
start_level = min(pointA[1],pointB[1],by) - 0.2
end_level = start_level - depth
#To draw the limit lines.
plt.plot([pointA[0],pointA[0]], [start_level,end_level], color='magenta', lw=linewidth)
plt.plot([pointB[0],pointB[0]], [start_level,end_level], color='magenta', lw=linewidth)
#To annotate.
plt.annotate("", [pointA[0],end_level+0.4], [pointB[0],end_level+0.4],
arrowprops=dict(arrowstyle='<|-|>', color='magenta', lw=linewidth, mutation_scale=10, shrinkA=0, shrinkB=0))
plt.text((pointA[0]+pointB[0])/2, end_level+0.8, text_string, fontsize=font_dim,
color='magenta', horizontalalignment='center', verticalalignment='center')
else:
start_level = max(pointA[1],pointB[1],ey) + 0.2
end_level = start_level - depth
#To draw the limit lines.
plt.plot([pointA[0],pointA[0]], [start_level,end_level], color='magenta', lw=linewidth)
plt.plot([pointB[0],pointB[0]], [start_level,end_level], color='magenta', lw=linewidth)
#To annotate.
plt.annotate("", [pointA[0],end_level-0.4], [pointB[0],end_level-0.4],
arrowprops=dict(arrowstyle='<|-|>', color='magenta', lw=linewidth, mutation_scale=10, shrinkA=0, shrinkB=0))
plt.text((pointA[0]+pointB[0])/2, end_level+0.05, text_string, fontsize=font_dim,
color='magenta', horizontalalignment='center', verticalalignment='center')
elif horizontal==False:
start_level = min(pointA[0],pointB[0],vx) - 0.2
end_level = start_level - depth
#To draw the limit lines.
plt.plot([start_level,end_level], [pointA[1],pointA[1]], color='magenta', lw=linewidth)
plt.plot([start_level,end_level], [pointB[1],pointB[1]], color='magenta', lw=linewidth)
#To annotate.
plt.annotate("", [end_level+0.4,pointA[1]], [end_level+0.4,pointB[1]],
arrowprops=dict(arrowstyle='<|-|>', color='magenta', lw=linewidth, mutation_scale=10, shrinkA=0, shrinkB=0))
plt.text(end_level+0.12, (pointA[1]+pointB[1])/2, text_string, fontsize=font_dim,
color='magenta', horizontalalignment='center', verticalalignment='center', rotation=90)
#Dimensions of lens top view (SAOL).
dim([bx,by], [qx,qy], 2, f'BFL={round(BFL,2):.2f}'+r'$\genfrac{}{}{0}{1}{+0.5}{-0.5}$', horizontal=True)
dim([px,py], [qx,qy], 4, f'EFL={round(EFL,2):.2f}'+r'$\genfrac{}{}{0}{1}{+0.5}{-0.5}$', horizontal=True)
dim([ax,ay], [bx,by], 1, f'{round(W,2):.1f}'+r'$\genfrac{}{}{0}{1}{+0.5}{-0.5}$', horizontal=False)
#Dimensions of lens side view (SAOL).
dim([ex,ey], [ix,iy], -2, f'{round(t,2):.1f}'+r'$\genfrac{}{}{0}{1}{+0.5}{-0.5}$', horizontal=True)
dim([ix,iy], [jx,jy], 1, f'{round(H,2):.1f}'+r'$\genfrac{}{}{0}{1}{+0.5}{-0.5}$', horizontal=False)
#Leaders.
#For 'S2'.
connectionstyle = 'arc,angleA=0,angleB=45,armA=0,armB=43.5,rad=0'
plt.annotate("",
xy=(ex, ey-1.5), xycoords='data',
xytext=(ex+3.0, ey+0.5), textcoords='data',
arrowprops=dict(arrowstyle="->", color='magenta', lw=linewidth,
shrinkA=0, shrinkB=0,
patchA=None, patchB=None,
connectionstyle=connectionstyle,
),
)
plt.text(ex+2.25, ey+0.8, 'S2', fontsize=font_dim,
color='magenta', horizontalalignment='center', verticalalignment='center', rotation=0)
#For 'S1'.
connectionstyle = 'arc,angleA=0,angleB=135,armA=0,armB=43.5,rad=0'
plt.annotate("",
xy=(ix, iy-1.5), xycoords='data',
xytext=(ix-3.0, iy+0.5), textcoords='data',
arrowprops=dict(arrowstyle="->", color='magenta', lw=linewidth,
shrinkA=0, shrinkB=0,
patchA=None, patchB=None,
connectionstyle=connectionstyle,
),
)
plt.text(ix-2.2, iy+0.8, 'S1', fontsize=font_dim,
color='magenta', horizontalalignment='center', verticalalignment='center', rotation=0)
#Text section.
line_gap = 1.0
fontsize_text = 8
plt.text(ex+7, ey, 'Mterial: Glass type Schott', fontsize=fontsize_text, color='magenta')
plt.text(ex+7, ey-line_gap, 'S1, S2:', fontsize=fontsize_text, color='magenta')
plt.text(ex+7, ey-line_gap*2, '1) Scratch/Dig - ', fontsize=fontsize_text, color='magenta')
plt.text(ex+7, ey-line_gap*3, r'2) AR coating - R$\leq$ % @ nm wavelength', fontsize=fontsize_text, color='magenta')
plt.text(ex+7, ey-line_gap*4, r'3) Damage threshold - MW/$\mathrm{cm^2}$', fontsize=fontsize_text, color='magenta')
#Texts for acylindrical lens.
formula = r'$\mathrm{sag=\frac{X^2}{R(1+\sqrt{1-(1+k)X^2/R^2})}+A_4X^4+A_6X^6+A_8X^8+A_{10}X^{10}+A_{12}X^{12}+A_{14}X^{14}}$'
plt.text(ex+7, ey-line_gap*6, formula, fontsize=fontsize_text, color='magenta')
coefficients = rf'$R={round(R,1)}, k={round(k,1)}, A_4=0, A_6=0, A_8=0, A_{{10}}=0, A_{{12}}=0, A_{{14}}=0$'
plt.text(ex+7, ey-line_gap*7, coefficients, fontsize=fontsize_text, color='magenta')
#To denote optional theta.
theta = arctan((edge+BFL)/(qy-by))
plt.plot([qx,dx], [qy,dy], color='b', lw=linewidth, linestyle='--')
plt.plot([qx,qx], [qy,dy], color='b', lw=linewidth, linestyle='--')
angles0 = linspace(1.5*pi-theta, 1.5*pi, 1000, endpoint=True)
xc0 = 0.5*cos(angles0) + qx
yc0 = 0.5*sin(angles0) + qy
plt.plot(xc0, yc0, color='b', lw=linewidth)
plt.text((min(xc0)+max(xc0))/2, (min(yc0)+max(yc0))/2-0.3, r'$\theta$', fontsize=6,
color='b', horizontalalignment='center', verticalalignment='center', rotation=0)
plt.text((qx+dx)/2, (qy+dy)/2+0.3, f'Cylindrical case: R={R}', fontsize=6,
color='b', horizontalalignment='center', verticalalignment='center', rotation=90-degrees(theta))
#Hide all axis objects.
plt.xticks([])
plt.yticks([])
plt.box(False)
#Set A4 size.
plt.figure(1).set_size_inches(11.69,8.27)
plt.figure(1).savefig('test_acyl.pdf')
end_time = time.time()
elapsed_time = end_time - start_time
print("The time elapsed is: ", round(elapsed_time,1))
plt.show()
答: 暂无答案
评论