繁体   English   中英

改变海龟图形的操作

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM