[英]Changing the operation of the turtle graphics
首先,我對編程非常陌生,而且我在這里咀嚼的東西太多了。 反正...
我正在嘗試使用此代碼作為模型在 python 中構建太陽系/軌道模擬。
這是我的完整代碼:
# Import math and turtle
import math
from turtle import *
import turtle
# Gravitational Constant
G = 6.67428e-11
# Scale: 1 pixel = 1 astronomical unit
# 1 astronomical unit = 1 AU = 149597900 km
AU = (149.6e6 * 1000) # 149.6 million km in meters
Scale = 250 / AU
wn = turtle.Screen()
wn = turtle.bgcolor('black')
class body(Turtle):
# Subclass of turtle representing a body
# Additional attributes:
# mass in kg
# vx, vy: x, y velocities in m/sc
# px, py: x, y positions in m
# Set background to black
# Turtle.bgcolor('black')
name = 'body'
mass = None
vx = vy = 0.0
px = py = 0.0
def attraction(self, other):
# (body): (fx, fy)
# returns the force exerted on this body by the other body.
# Report and error if the other object is the same as this one.
if self is other:
raise ValueError("Attraction of object %r to itself requested" % self.name)
# Compute the distance of the other body:
sx, sy = self.px, self.py
ox, oy = other.px, other.py
dx = (ox - sx)
dy = (oy - sy)
d = math.sqrt(dx**2 + dy**2)
# Report an Error if the distance is 0
# ZeroDivisionError would happen later otherwise
if d == 0:
raise ValueError("Collision between objects %r and %r" % (self.name, other.name))
# Compute the force of attraction
f = G * self.mass * other.mass / (d**2)
# Compute the direction of the force
theta = math.atan2(dy, dx)
fx = math.cos(theta) * f
fy = math.sin(theta) * f
return fx, fy
def updateInfo(step, bodies):
# (int, [body])
# Displays infomation about status of simulation.
print('Step #{}'.format(step))
for body in bodies:
s = '{:<8} Pos.={:>6.2f} Vel.={:>10.3f}'.format(body.name, body.px/AU, body.py/AU, body.vy)
print(s)
print()
def loop(bodies):
# (body)
# Never returns; loop through the simulation and updates the positions of given bodies
timestep = 24*3600 # One Day
for body in bodies:
body.penup()
body.hideturtle()
step = 1
while True:
updateInfo(step, bodies)
step += 1
force = {}
for body in bodies:
# Adds all the forces exerted on a body
totalFx = totalFy = 0.0
for other in bodies:
# Don't calculate attraction to itself
if body is other:
continue
fx, fy = body.attraction(other)
totalFx += fx
totalFy += fy
# Record the total force exerted
force[body] = (totalFx, totalFy)
# Update velocities based on the force.
for body in bodies:
fx, fy = force[body]
body.vx += fx / body.mass * timestep
body.vy += fy / body.mass * timestep
# Update positions
body.px += body.vx * timestep
body.py += body.vy * timestep
body.goto(body.px*Scale, body.py*Scale)
body.dot(5)
def main():
sun = body()
sun.name = 'Sun'
sun.mass = 1.98892 * 10**30
sun.pencolor('yellow')
earth = body()
earth.name = 'Earth'
earth.mass = 5.9742 * 10**24
earth.px = -1*AU
earth.vy = 29.783 * 1000
earth.pencolor('blue')
venus = body()
venus.name = 'Venus'
venus.mass = 4.8685 * 10**24
venus.px = 0.723 * AU
venus.vy = -35.02 * 1000
venus.pencolor('orange')
loop([sun, earth, venus])
if __name__ == '__main__':
main()
我為我的窗口添加了一條import turtle
線,因為我想將窗口顏色更改為黑色。 我知道兩種導入樣式之間的主要區別,以及為什么有些人更喜歡一種而不是另一種(或者為什么一種不好)。 我想改變類的結構,這樣我就可以更好地控制模擬的圖形,並遠離from x import *
方法。 歡迎任何建議!
我的選擇是使用導入:
from turtle import Screen, Turtle
通過阻塞功能接口來強制面向對象的接口使用烏龜。 但我會更進一步:
fx, fy = force[body]
body.vx += fx / body.mass * timestep
body.vy += fy / body.mass * timestep
# Update positions
body.px += body.vx * timestep
body.py += body.vy * timestep
Turtle 可以使用向量 ( Vec2D
),因此我們不需要對 x 和 y 值進行單獨的操作。
for body in bodies:
body.penup()
body.hideturtle()
這可以是Body
類初始值設定項的一部分。
body.goto(body.px*Scale, body.py*Scale)
我們可以預先縮放海龜的坐標系,避免在主循環中進行縮放操作。
while True:
不是在像烏龜這樣的事件驅動的世界中——使用ontimer()
代替。 以下返工實現了上述建議,以展示我可能如何解決這個問題:
# Import math and turtle
import math
from turtle import Screen, Turtle, Vec2D
# Gravitational Constant
G = 6.67428e-11
# Scale: 1 pixel = 1 astronomical unit
# 1 astronomical unit = 1 AU = 149597900 km
AU = 149.6e6 * 1000 # 149.6 million km in meters
TIME_STEP = 24 * 3600 # One day
FORMAT = "{:<8} Pos.={:>6.2f} Vel.={:>10.3f}"
CURSOR_SIZE = 20
class Body(Turtle):
''' Subclass of turtle representing a body. '''
# Additional attributes:
# mass in kg
# velocity in m/sc
# position in m
name = 'body'
mass = None
velocity = Vec2D(0.0, 0.0)
Position = Vec2D(0.0, 0.0) # Position to avoid conflict with turtle's position() method
def __init__(self, dot_size=5):
super().__init__(shape='circle')
self.shapesize(dot_size / CURSOR_SIZE)
self.penup()
def attraction(self, other):
''' Return the force exerted on this body by the other body. '''
# Report an error if the other object is the same as this one.
if self is other:
raise ValueError("Attraction of object {} to itself requested".format(self.name))
# Compute the distance of the other body:
dx, dy = other.Position - self.Position
distance = math.sqrt(dx**2 + dy**2)
# Report an Error if the distance is 0
# ZeroDivisionError would happen later otherwise
if distance == 0:
raise ValueError("Collision between objects {} and {}".format(self.name, other.name))
# Compute the force of attraction
force = G * self.mass * other.mass / distance**2
# Compute the direction of the force
theta = math.atan2(dy, dx)
direction = Vec2D(math.cos(theta), math.sin(theta))
return direction * force
def updateInfo(step: int, bodies: list):
''' Display information about status of simulation. '''
print('Step #{}'.format(step))
for body in bodies:
print(FORMAT.format(body.name, abs(body.Position * (1 / AU)), abs(body.velocity)))
print()
def single_step(bodies, step=1):
''' Step through the simulation and updates the positions of given bodies. '''
updateInfo(step, bodies)
for body in bodies:
# Adds all the forces exerted on a body
totalForce = Vec2D(0.0, 0.0)
for other in bodies:
# Don't calculate attraction to itself
if body is not other:
totalForce += body.attraction(other)
# Update velocities based on the force.
body.velocity += totalForce * (1 / body.mass) * TIME_STEP
# Update position
body.Position += body.velocity * TIME_STEP
body.setposition(body.Position)
screen.update()
screen.ontimer(lambda: single_step(bodies, step + 1))
if __name__ == '__main__':
screen = Screen()
screen.bgcolor('black')
screen.setworldcoordinates(-2 * AU, -2 * AU, 2 * AU, 2 * AU)
screen.tracer(False)
sun = Body(10)
sun.name = 'Sun'
sun.mass = 1.98892 * 10**30
sun.color('yellow')
earth = Body()
earth.name = 'Earth'
earth.mass = 5.9742 * 10**24
earth.Position = Vec2D(-AU, 0.0)
earth.velocity = Vec2D(0.0, 29.783 * 1000)
earth.color('blue')
venus = Body()
venus.name = 'Venus'
venus.mass = 4.8685 * 10**24
venus.Position = Vec2D(0.723 * AU, 0.0)
venus.velocity = Vec2D(0.0, -35.02 * 1000)
venus.color('orange')
single_step([sun, earth, venus])
screen.mainloop()
updateInfo()
函數讓我感到困惑,因為它打印了四個數據參數中的三個。 (即打印 Y 位置作為速度!)我只是做了一些隨機的事情,打印矢量的絕對值。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.