去年笔者发布了一篇关于使用turtle库来展示凸透镜成像规律的作品。现在发现程序有一些问题,今天就来改一下。
就是在点击时,文字
2
f
2f
2f(有时
f
f
f也会有)会莫名其妙的出现在轴心附近。
与文字差不多,它有时候点击会把一些线段加粗。
代码是没有问题的,所以笔者放弃turtle,转而使用Pygame来做。
修改后的代码如下:
import sys
import pygame
width, height = 1000, 600 # 屏幕的宽高
pygame.init() # Pygame初始化
screen = pygame.display.set_mode((width, height)) # 初始化屏幕
pygame.display.set_caption('凸透镜成像规律') # 设置标题
# 绘制线段的函数
def line(x1, y1, x2, y2, color=(0, 0, 0)): # 颜色color默认为黑色
# 这里出现"width // 2 +"与"height // 2 -"是为了与turtle使用的坐标轴一直,下同
pygame.draw.line(screen, color, (width // 2 + x1, height // 2 - y1), (width // 2 + x2, height // 2 - y2), 3)
# 写出字体
def text(txt, x, y):
f = pygame.font.Font('C://Windows//Fonts//ARIALN.TTF', 20) # 这里选用ARIALN字体
text = f.render(txt, True, (0, 0, 0))
t = text.get_rect()
t.center = (width // 2 + x, height // 2 - y)
screen.blit(text, t)
# 绘制出实心圆
def dot(x, y, size):
pygame.draw.circle(screen, (0, 0, 0), (width // 2 + x, height // 2 - y), size)
while True:
screen.fill((255, 255, 255)) # 设置背景为白色,但放到事件循环之外就不行
# 绘制横线与凸透镜(物理符号)
line(0 - width // 2, 0, width // 2, 0)
line(0, -150, 0, 150)
line(-10, 140, 0, 150)
line(10, 140, 0, 150)
line(-10, -140, 0, -150)
line(10, -140, 0, -150)
# 凸透镜中四个重要的点:左边的2f, f,右边的2f, f
text('2f', -200, 12)
dot(-200, 0, 3)
text('2f', 200, 12)
dot(200, 0, 3)
text('f', -100, 12)
dot(-100, 0, 3)
text('f', 100, 12)
dot(100, 0, 3)
# 这里的作用等同于上一篇文章里的image函数,但在这里没有必要单独拎出来
event = pygame.event.wait() # 获取事件
if event.type == pygame.MOUSEMOTION: # 判断鼠标是否移动
x, y = event.pos
x -= width // 2 # 因为函数里的x实际上减去了width // 2,所以这里也要减掉
if x <= 0: # 因为物体的x坐标不能超过0,所以如果物体的x坐标大于0,就要其x坐标设为0
n = x
else:
n = 0
# 绘制在作图时必要的线段
line(5 * n, 500, 4 * (0 - n), -400)
line(n, 100, 0, 100)
line(-400, 500, 500, -400)
# 绘制物体
line(n, 0, n, 100, (255, 0, 0))
line(n - 10, 90, n, 100, (255, 0, 0))
line(n + 10, 90, n, 100, (255, 0, 0))
if n != -100: # 因为物体在-100(左侧的f点)时不成像,所以这里要特殊处理一下
if n == 0: # 在x坐标等于0时会有除0报错(笔者也不知道为什么),也是特殊处理一下
kx = 0
else:
kx = (100 * n) / (n + 100) # kx的是什么后面会讲到
line(kx, 0, kx, 100 - kx, (255, 0, 0)) # 绘制虚像
if n <= -100: # 虚像的箭头方向要分正立倒立来处理
line(kx - 10, 110 - kx, kx, 100 - kx, (255, 0, 0))
line(kx + 10, 110 - kx, kx, 100 - kx, (255, 0, 0))
else:
line(kx - 10, 90 - kx, kx, 100 - kx, (255, 0, 0))
line(kx + 10, 90 - kx, kx, 100 - kx, (255, 0, 0))
for event in pygame.event.get(): # 点击右上角的叉号时要做的
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
pygame.display.flip() # 刷新屏幕
这里就是关于在 s c r e e n screen screen上面进行绘制操作的函数。
# 绘制线段的函数
def line(x1, y1, x2, y2, color=(0, 0, 0)): # 颜色color默认为黑色
# 这里出现"width // 2 +"与"height // 2 -"是为了与turtle使用的坐标轴一样,下同
pygame.draw.line(screen, color, (width // 2 + x1, height // 2 - y1), (width // 2 + x2, height // 2 - y2), 3)
# 写出字体
def text(txt, x, y):
f = pygame.font.Font('C://Windows//Fonts//ARIALN.TTF', 20) # 这里选用ARIALN字体
text = f.render(txt, True, (0, 0, 0))
t = text.get_rect()
t.center = (width // 2 + x, height // 2 - y)
screen.blit(text, t)
# 绘制出实心圆
def dot(x, y, size):
pygame.draw.circle(screen, (0, 0, 0), (width // 2 + x, height // 2 - y), size)
# 绘制横线与凸透镜(物理符号)
line(0 - width // 2, 0, width // 2, 0)
line(0, -150, 0, 150)
line(-10, 140, 0, 150)
line(10, 140, 0, 150)
line(-10, -140, 0, -150)
line(10, -140, 0, -150)
# 凸透镜中四个重要的点:左边的2f, f,右边的2f, f
text('2f', -200, 12)
dot(-200, 0, 3)
text('2f', 200, 12)
dot(200, 0, 3)
text('f', -100, 12)
dot(-100, 0, 3)
text('f', 100, 12)
dot(100, 0, 3)
这里的作用等同于上一篇文章里的image函数,但在这里没有必要单独拎出来。
# 这里的作用等同于上一篇文章里的image函数,但在这里没有必要单独拎出来
event = pygame.event.wait() # 获取事件
if event.type == pygame.MOUSEMOTION: # 判断鼠标是否移动
x, y = event.pos
x -= width // 2 # 因为函数里的x实际上减去了width // 2,所以这里也要减掉
if x <= 0: # 因为物体的x坐标不能超过0,所以如果物体的x坐标大于0,就要其x坐标设为0
n = x
else:
n = 0
# 绘制在作图时必要的线段
line(5 * n, 500, 4 * (0 - n), -400)
line(n, 100, 0, 100)
line(-400, 500, 500, -400)
# 绘制物体
line(n, 0, n, 100, (255, 0, 0))
line(n - 10, 90, n, 100, (255, 0, 0))
line(n + 10, 90, n, 100, (255, 0, 0))
if n != -100: # 因为物体在-100(左侧的f点)时不成像,所以这里要特殊处理一下
if n == 0: # 在x坐标等于0时会有除0报错(笔者也不知道为什么),也是特殊处理一下
kx = 0
else:
kx = (100 * n) / (n + 100) # kx的是什么后面会讲到
line(kx, 0, kx, 100 - kx, (255, 0, 0)) # 绘制虚像
if n <= -100: # 虚像的箭头方向要分正立倒立来处理
line(kx - 10, 110 - kx, kx, 100 - kx, (255, 0, 0))
line(kx + 10, 110 - kx, kx, 100 - kx, (255, 0, 0))
else:
line(kx - 10, 90 - kx, kx, 100 - kx, (255, 0, 0))
line(kx + 10, 90 - kx, kx, 100 - kx, (255, 0, 0))
很多读者都会疑惑这个
k
x
kx
kx是什么,其实这个是虚像的那个顶点的
x
x
x坐标。
但为什么是
k
x
=
(
100
?
n
)
/
(
n
+
100
)
kx = (100 * n) / (n + 100)
kx=(100?n)/(n+100)(即
100
?
n
n
+
100
{{100\,n}\over{n+100}}
n+100100n?)呢?(笔者在上篇文章中没有化到最简,这次就化到了最简)其实,就是初二的一次函数的知识就可以求出来(两条直线
y
=
k
x
+
b
y=kx+b
y=kx+b的交点)。
(笔者还是第二次用Markdown写这么长的
LaTeX
\LaTeX
LATE?X的代码呢)
设没经过原点的直线为
l
1
l_1
l1?,则经过原点的直线为
l
2
l_2
l2?,由上图可知
直线
l
1
l_1
l1?的表达式为
y
1
=
k
1
?
x
1
+
b
1
y_1=k_1·x_1+b_1
y1?=k1??x1?+b1?; ①
直线
l
2
l_2
l2?的表达式为
y
2
=
k
2
?
x
2
+
b
2
y_2=k_2·x_2+b_2
y2?=k2??x2?+b2?. ②
由图可知 直线
l
1
l_1
l1?经过坐标为
(
0
,
100
)
(0, 100)
(0,100)与坐标为
(
100
,
0
)
(100, 0)
(100,0)的点,直线
l
2
l_2
l2?经过坐标为
(
n
,
100
)
(n, 100)
(n,100)与坐标为
(
0
,
0
)
(0, 0)
(0,0)的点.
将坐标为
(
0
,
100
)
(0, 100)
(0,100)的点代入①,得
100
=
0
?
x
1
+
b
1
,
100=0·x_1+b_1,
100=0?x1?+b1?,
解得
b
1
=
100.
b_1=100.
b1?=100.
将坐标为
(
100
,
0
)
(100, 0)
(100,0)的点与
b
1
=
100
b_1=100
b1?=100代入①,得
0
=
100
k
1
+
100
,
0=100k_1+100,
0=100k1?+100,
解得
k
1
=
?
1.
k_1=-1.
k1?=?1.
∴
\therefore
∴ 直线
l
1
l_1
l1?的表达式为
y
1
=
?
x
1
+
100
y_1=-x_1+100
y1?=?x1?+100.
同理,将坐标为
(
n
,
100
)
(n, 100)
(n,100)与
(
0
,
0
)
(0, 0)
(0,0)的点代入②,得
b
2
=
0
,
k
2
=
100
n
,
b_2=0,k_2=\frac{100}{n},
b2?=0,k2?=n100?,
∴
\therefore
∴ 直线
l
2
l_2
l2?的表达式为
y
2
=
100
n
x
2
y_2=\frac{100}{n}x_2
y2?=n100?x2?.
∵
\because
∵所求的点为两直线
l
1
l
2
l_1l_2
l1?l2?的交点,
∴
\therefore
∴
{
y
=
?
x
+
100
y
=
100
n
x
\left\{\begin{matrix} y=-x+100 \\ y=\frac{100}{n}x \end{matrix}\right.
{y=?x+100y=n100?x?
解得
{
x
=
100
?
n
n
+
100
y
=
100
?
100
?
n
n
+
100
\left\{\begin{matrix} x={{100\,n}\over{n+100}} \\ y=100-{{100\,n}\over{n+100}} \end{matrix}\right.
{x=n+100100n?y=100?n+100100n??
综上所述,所求之点的坐标为
(
100
?
n
n
+
100
,
100
?
100
?
n
n
+
100
)
.
({{100\,n}\over{n+100}}, 100-{{100\,n}\over{n+100}}).
(n+100100n?,100?n+100100n?).
通过结论我们可以发现
x
x
x与
y
y
y坐标里都有一个
100
?
n
n
+
100
{{100\,n}\over{n+100}}
n+100100n?,所以,如果定义变量
k
x
=
100
?
n
n
+
100
kx={{100\,n}\over{n+100}}
kx=n+100100n?,则那个点的坐标为
(
k
x
,
100
?
k
x
)
(kx,100-kx)
(kx,100?kx).
证毕
在这里插入代码片import sys
import pygame
width, height = 1000, 600 # 屏幕的宽高
pygame.init() # Pygame初始化
screen = pygame.display.set_mode((width, height)) # 初始化屏幕
pygame.display.set_caption('凸透镜成像规律') # 设置标题
...
while True:
screen.fill((255, 255, 255)) # 设置背景为白色,但放到事件循环之外就不行
...
for event in pygame.event.get(): # 点击右上角的叉号时要做的
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
pygame.display.flip() # 刷新屏幕
本文章以凸透镜成像规律为基础,使用Python的tutle库把凸透镜成像规律的原理直观地表现了出来。再次希望读者再接再厉,让多学科融入代码里,创造更美好的未来!