1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
#!/usr/bin/python
# -*- coding: utf-8 -*-

"""
Численное решение задачи о теле, брошенном под углом к горизонту.
"""

from PyQt4 import QtGui, QtCore
import sys

g = 9.8

def eulerSolve(x0, y0, vx0, vy0, dt, nSteps):
    result = [ [x0, y0, vx0, vy0] ]
    (x, y, vx, vy) = (x0, y0, vx0, vy0)
    for i in range(nSteps):
        x += vx * dt
        y += vy * dt
        vy += -g * dt
        result.append([x, y, vx, vy])
    return result

def eulerKromerSolve(x0, y0, vx0, vy0, dt, nSteps):
    result = [ [x0, y0, vx0, vy0] ]
    (x, y, vx, vy) = (x0, y0, vx0, vy0)
    for i in range(nSteps):
        vy += -g * dt
        x += vx * dt
        y += vy * dt
        result.append([x, y, vx, vy])
    return result


class FallingBody(QtGui.QWidget):
    def __init__(self):
        super(FallingBody, self).__init__()
        
        self.initUI()
        
    def initUI(self):      

        self.setGeometry(300, 300, 300, 300)
        self.setWindowTitle('Falling body')
        self.show()

    def paintEvent(self, e):

        qp = QtGui.QPainter()
        qp.begin(self)
        self.drawTrajectory(qp)
        qp.end()
        
    def drawTrajectory(self, qp):
        max_x = 100 # Максимальная координата по y.
        max_y = 40 # Максимальная координата по x.
        qp.translate(0, self.height()) # Сдвиг центра координат
        qp.scale(self.width() / max_x, - self.height() / max_y) # масштабирование осей.
                            # Знак "-" перед вторым аргументом меняет направление оси y.
        pen1 = QtGui.QPen(QtCore.Qt.black, 0, QtCore.Qt.SolidLine)
        pen2 = QtGui.QPen(QtCore.Qt.red, 0, QtCore.Qt.SolidLine)
        pen3 = QtGui.QPen(QtCore.Qt.blue, 0, QtCore.Qt.SolidLine)

        qp.setPen(pen1)
        (x0, y0, vx0, vy0) =  (0, 0, 20, 20) # Компактное присваивание.
        for x, y, _, _ in eulerSolve(x0, y0, vx0, vy0, 0.05, 100): # каждый элемент списка 
                                            # будет распакован в переменные x, y, _, _
            qp.drawLine(QtCore.QPointF(x0, y0), QtCore.QPointF(x, y))
            x0 = x
            y0 = y

        qp.setPen(pen2)
        (x0, y0, vx0, vy0) =  (0, 0, 20, 20)
        for x, y, _, _ in eulerKromerSolve(x0, y0, vx0, vy0, 0.2, 25): 
            qp.drawLine(QtCore.QPointF(x0, y0), QtCore.QPointF(x, y))
            x0 = x
            y0 = y

        qp.setPen(pen3)
        (x0, y0, vx0, vy0) =  (0, 0, 20, 20)
        for x, y, _, _ in eulerKromerSolve(x0, y0, vx0, vy0, 0.05, 100):
            qp.drawLine(QtCore.QPointF(x0, y0), QtCore.QPointF(x, y))
            x0 = x
            y0 = y

def main():
    app = QtGui.QApplication(sys.argv)
    ex = FallingBody()
    sys.exit(app.exec_())

if __name__ == '__main__':
    main()