用 python 模拟水滴折射

1 注意点

在这里插入图片描述

2 完整代码

import numpy as np
import matplotlib.pyplot as plt

def calc_abc_from_line_2d(x0, y0, x1, y1):
    a = y0 - y1
    b = x1 - x0
    c = x0*y1 - x1*y0
    return a, b, c

# 求两直线的交点坐标
def get_line_cross_point(line1, line2):
    # line1 和 line2 是两个数组, 数组元素为 [x0, y0, x1, y1]
    a0, b0, c0 = calc_abc_from_line_2d(*line1)
    a1, b1, c1 = calc_abc_from_line_2d(*line2)
    D = a0 * b1 - a1 * b0
    if D == 0:
        return None
    x = (b0 * c1 - b1 * c0) / D
    y = (a1 * c0 - a0 * c1) / D
    # print(x, y)
    return x, y

# 基本信息
r = 1 # 圆的半径
a, b = (0., 0.) # 圆心
theta2 = 0.8 * np.pi # 入射光线与 x 轴夹角
angle1 = np.pi - theta2 # 入射角
rushedianx = a + r * np.cos(theta2)
rushediany = b + r * np.sin(theta2) # 入射点
n = 1.3 # 折射率
angle2 = angle1 / n # 折射角

# 画图准备
fig = plt.figure() # 创建画板
axes = fig.add_subplot(111) # “111”的含义:将画布分割成1行1列,图像画在从左到右从上到下的第1块
axes.axis('equal')

# 使用参数方程画圆
theta = np.arange(0, 2 * np.pi, 0.01) # np.arange()用法参考: https://blog.csdn.net/qq_41550480/article/details/89390579
x = a + r * np.cos(theta)
y = b + r * np.sin(theta) # 参考:https://www.runoob.com/numpy/numpy-array-from-existing-data.html
axes.plot(x, y, color='black')

# 画入射光
x2 = [rushedianx - 0.6, rushedianx]
y2 = [rushediany, rushediany]
axes.plot(x2, y2, color='black')
axes.arrow(x2[0], y2[0], 0.25, 0, head_width=0.05, head_length=0.1, fc='k', ec='k')

# 画折射内部法线
x3 = [0, rushedianx]
y3 = [0, rushediany]
axes.plot(x3, y3, color='black')

# 画折射外部法线
k = rushediany / rushedianx
axes.plot([rushedianx - 0.5, rushedianx], [rushediany - 0.5 * k, rushediany], c='k', linestyle='--')

# 画入射光辅助线
x4 = [rushedianx, rushedianx + 2.7]
y4 = [rushediany, rushediany]
axes.plot(x4, y4, color='black',linestyle='--')

# 画折射光线
angle3 = angle1-angle2 # 折射光线倾斜角的绝对值
x5 = [rushedianx, rushedianx + 1.77 * r * np.cos(angle3)]
y5 = [rushediany, rushediany - 1.77 * r * np.sin(angle3)]
axes.plot(x5, y5, color='black')

# 画反射法线
angle4 = 2 * angle2 - angle1 # 法线的倾斜角
axes.plot([0, a + 1.74 * r * np.cos(angle4)], [0, b + 1.74 * r * np.sin(angle4)], c='k', linestyle='--')

# 画反射光线
fanshedianx = a + r * np.cos(angle4)
fanshediany = b + r * np.sin(angle4) # 反射点
angle5 = 2 * angle2 - angle3
chushedianx = fanshedianx - 1.77 * r * np.cos(angle5)
chushediany = fanshediany - 1.77 * r * np.sin(angle5) # 出射点
x6 = [fanshedianx, chushedianx]
y6 = [fanshediany, chushediany]
axes.plot(x6, y6, color='black')

# 画出射辅助线
x7 = [a + 1.74 * r * np.cos(angle4), chushedianx]
y7 = [b + 1.74 * r * np.sin(angle4), chushediany]
axes.plot(x7, y7, color='black', linestyle='--')
k2 = (y7[1] - y7[0]) / (x7[1] - x7[0])

# 画出射折射法线
x8 = [chushedianx, 0]
y8 = [chushediany, 0]
axes.plot(x8, y8, color='black')

# 画出出射光线
axes.arrow(chushedianx, chushediany, -0.3, -0.3 * k2, head_width=0.05, head_length=0.1, fc='k', ec='k')

# 画阴影部分
xstart = rushedianx
xend = a + 1.74 * r * np.cos(angle4)
x9 = [0, 0]
y9 = [rushediany, 0]
i = xstart
while i < xend:
    x9[0] = i
    # 寻找高交点
    line1 = [x9[0], y9[0], x9[0] - 0.1, y9[0] - 0.1]
    line2 = [fanshedianx, fanshediany, rushedianx, rushediany]
    line3 = [0, 0, fanshedianx, fanshediany]
    p1, p2 = get_line_cross_point(line1, line2)
    p3, p4 = get_line_cross_point(line1, line3)
    if(p2 > p4):
        x9[1] = p1
        y9[1] = p2
    else:
        x9[1] = p3
        y9[1] = p4
    axes.plot(x9, y9, color='black')
    i += 0.1

# 画角
theta3 = np.arange(-angle1, -angle3, 0.01)
jiaox = rushedianx + 0.2 * np.cos(theta3)
jiaoy = rushediany + 0.2 * np.sin(theta3)
axes.plot(jiaox, jiaoy, color='black')


# 画批注字
font={'family':'Times New Roman',
     'style':'italic',
    'weight':'bold',
      'color':'black',
      'size':20
}
plt.text(-1.3, 0.34,"S", fontdict=font)
plt.text(-0.9, 0.7,  "A", fontdict=font)
plt.text(-1.3, 0.65,  "i", fontdict=font)
plt.text(-0.1, 1.2,  "i-r", fontdict=font)
plt.text(-0.42, 0.35,  "r", fontdict=font)
x10 = [-0.5, 0]
y10 = [b + r * np.sin(theta2), 1.15]
axes.plot(x10, y10, color='black')

plt.axis('off')
plt.show()

3 运行结果

在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

诸葛思颖

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值