如何获得更美观的平凸酰晶透镜 2D(俯视图/侧视图)图纸?[关闭]

How do I obtain better-looking plano-convex acylindrical lens 2D (top/side views) drawing? [closed]

提问人:Jack2023 提问时间:11/16/2023 最后编辑:Jack2023 更新时间:11/16/2023 访问量:69

问:


想改进这个问题吗?更新问题,使其仅通过编辑这篇文章来关注一个问题。

7天前关闭。

我正在通过 Python matplotlib 绘制平凸酰基透镜 2D(顶/侧视图)绘图。与LibreCAD / FreeCAD / SolidWorks等的绘图相比,这种方法更吸引我,因为:

  • 它是免费的,无需安装繁重的软件。
  • 在绘制大量变体时,它可以节省时间。
  • 它很容易实现非球面曲线并显示方程。
  • 我特别想玩 Python。

目标不是从 CAD 软件中重现完全相同的结果。相反,我想改进绘图并使其更好看。

到目前为止,我制作了一个简单的模板,请参阅下面的代码。请注意,我画的不是真正的镜头,所以不要注意数值。我正在寻找帮助来制作更美观的细节和/或更好地实现 Python 方法。更详细的子问题:

  1. 我用 \genfrac 显示了容差。如何使用较小的字体使 +- 值与其他文本对齐?
  2. 至于表面下垂方程,我如何使所有东西,尤其是分子和分母,字体大小相同?
  3. 对于柱面透镜,我需要半径尺寸。我绘制了一个角度为 theta 且文本旋转 90 度 (theta) 的示例。但文本没有对齐。如何计算正确的旋转角度?
  4. 引线(S1,S2)采用“弧形”连接方式制成,这不是一个糟糕的解决方案。引线只是一个箭头加上一段水平线。有什么简单的方法可以在不创建用户定义的函数的情况下实现领导者?
  5. 如何在没有用户定义的形状的情况下使注释箭头更薄更长?

以下是输出pdf文件:

输出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()

python matplotlib 格式 绘制 圆柱形

评论

0赞 LMC 11/16/2023
也许这个问题更适合代码审查网站。任何其他工具如何完成相同的绘图?
1赞 Jack2023 11/16/2023
@LMC 谢谢你的建议。在这种特定情况下,我正在寻求帮助,但即使不理解代码的任何部分,人们也可能帮助我。例如,通过查看旋转文本未对齐的输出屏幕截图,有些人可能会给出有关计算旋转角度的建议。如果有更令人信服的理由,我会去你的代码审查网站。此外,我的目标不是通过其他工具重现完全相同的结果。相反,只要上述细节得到解决,对我来说应该是完美的。这就是为什么我没有通过其他工具发布“标准”图的原因。
1赞 Jack2023 11/16/2023
@LMC 我刚刚根据您的评论编辑了我的“目标”并删除了以前的问题 1 和 7。
0赞 Jack2023 11/16/2023
@LMC@TrentonMcKinney 由于所有子问题都与 matplotlib 的文本格式和箭头整形有关,您是否建议我将标题更改为“2D 平凸透镜绘图和规格的文本格式和箭头整形 (matplotlib)”?
0赞 LMC 11/16/2023
我会在一个更简单的例子中处理箭头形状,并仔细检查θ角是如何计算的。也可能有助于从错误中拆分值并向 dim() 添加字体大小参数

答: 暂无答案