diff --git a/2016-solar_project b/2016-solar_project new file mode 160000 index 00000000..a2df8244 --- /dev/null +++ b/2016-solar_project @@ -0,0 +1 @@ +Subproject commit a2df8244e8e07a313879c2bf322f8567fff2b00d diff --git a/README.md b/README.md index a542148c..e2b46a42 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,4 @@ # solar_project Модель Солнечной системы на языке Python + +Работает!! \ No newline at end of file diff --git a/feature b/feature deleted file mode 100644 index 36b21249..00000000 --- a/feature +++ /dev/null @@ -1 +0,0 @@ -dsfsdf diff --git a/planet_and_moon.py b/planet_and_moon.py new file mode 100644 index 00000000..8d7fb5cd --- /dev/null +++ b/planet_and_moon.py @@ -0,0 +1,107 @@ +#!/usr/bin/env python3 +# https://github.com/python/cpython/tree/master/Lib/turtledemo +""" turtle-example-suite: + tdemo_planets_and_moon.py +Gravitational system simulation using the +approximation method from Feynman-lectures, +p.9-8, using turtlegraphics. +Example: heavy central body, light planet, +very light moon! +Planet has a circular orbit, moon a stable +orbit around the planet. +You can hold the movement temporarily by +pressing the left mouse button with the +mouse over the scrollbar of the canvas. +""" +from turtle import Shape, Turtle, mainloop, Vec2D as Vec + +G = 8 + +class GravSys(object): + def __init__(self): + self.planets = [] + self.t = 0 + self.dt = 0.01 + def init(self): + for p in self.planets: + p.init() + def start(self): + for i in range(10000): + self.t += self.dt + for p in self.planets: + p.step() + +class Star(Turtle): + def __init__(self, m, x, v, gravSys, shape): + Turtle.__init__(self, shape=shape) + self.penup() + self.m = m + self.setpos(x) + self.v = v + gravSys.planets.append(self) + self.gravSys = gravSys + self.resizemode("user") + self.pendown() + def init(self): + dt = self.gravSys.dt + self.a = self.acc() + self.v = self.v + 0.5*dt*self.a + def acc(self): + a = Vec(0,0) + for planet in self.gravSys.planets: + if planet != self: + v = planet.pos()-self.pos() + a += (G*planet.m/abs(v)**3)*v + return a + def step(self): + dt = self.gravSys.dt + self.setpos(self.pos() + dt*self.v) + if self.gravSys.planets.index(self) != 0: + self.setheading(self.towards(self.gravSys.planets[0])) + self.a = self.acc() + self.v = self.v + dt*self.a + +## create compound yellow/blue turtleshape for planets + +def main(): + s = Turtle() + s.reset() + s.getscreen().tracer(0,0) + s.ht() + s.pu() + s.fd(6) + s.lt(90) + s.begin_poly() + s.circle(6, 180) + s.end_poly() + m1 = s.get_poly() + s.begin_poly() + s.circle(6,180) + s.end_poly() + m2 = s.get_poly() + + planetshape = Shape("compound") + planetshape.addcomponent(m1,"orange") + planetshape.addcomponent(m2,"blue") + s.getscreen().register_shape("planet", planetshape) + s.getscreen().tracer(1,0) + + ## setup gravitational system + gs = GravSys() + sun = Star(1000000, Vec(0,0), Vec(0,-2.5), gs, "circle") + sun.color("yellow") + sun.shapesize(1.8) + sun.pu() + earth = Star(12500, Vec(210,0), Vec(0,195), gs, "planet") + earth.pencolor("green") + earth.shapesize(0.8) + moon = Star(1, Vec(220,0), Vec(0,295), gs, "planet") + moon.pencolor("blue") + moon.shapesize(0.5) + gs.init() + gs.start() + return "Done!" + +if __name__ == '__main__': + main() + mainloop() diff --git a/solar_input.py b/solar_input.py index d45e0401..83b1d709 100644 --- a/solar_input.py +++ b/solar_input.py @@ -4,64 +4,44 @@ from solar_objects import Star, Planet -def read_space_objects_data_from_file(input_filename): - """Cчитывает данные о космических объектах из файла, создаёт сами объекты - и вызывает создание их графических образов - - Параметры: - - **input_filename** — имя входного файла - """ - - objects = [] - with open(input_filename) as input_file: - for line in input_file: - if len(line.strip()) == 0 or line[0] == '#': - continue # пустые строки и строки-комментарии пропускаем - object_type = line.split()[0].lower() - if object_type == "star": # FIXME: do the same for planet - star = Star() - parse_star_parameters(line, star) - objects.append(star) - else: - print("Unknown space object") +space_objects = [] - return objects +# Заменила функции parse_planet_parameters и parse_star_parameters на эту: +def parse_object_parameters(line): -def parse_star_parameters(line, star): - """Считывает данные о звезде из строки. + """Считывает данные о звезде или планете из строки. Входная строка должна иметь слеюущий формат: Star <радиус в пикселах> <цвет> <масса> + Planet <радиус в пикселах> <цвет> <масса> - Здесь (x, y) — координаты зведы, (Vx, Vy) — скорость. + Здесь (x, y) — координаты зведы или планеты, (Vx, Vy) — скорость. Пример строки: Star 10 red 1000 1 2 3 4 - - Параметры: - - **line** — строка с описание звезды. - **star** — объект звезды. """ + type_, R, color, m, x, y, Vx, Vy = line.split(' ') + type_ = type_.lower() - pass # FIXME: not done yet + if type_ == 'planet': + obj = Planet() + elif type_ == 'star': + obj = Star() + else: + print('Invalid type of object.') + raise ValueError -def parse_planet_parameters(line, planet): - """Считывает данные о планете из строки. - Предполагается такая строка: - Входная строка должна иметь слеюущий формат: - Planet <радиус в пикселах> <цвет> <масса> + obj.type_ = type_ + obj.R = float(R) + obj.color = color + obj.m = float(m) + obj.y = float(y) + obj.x = float(x) + obj.Vy = float(Vy) + obj.Vx = float(Vx) - Здесь (x, y) — координаты планеты, (Vx, Vy) — скорость. - Пример строки: - Planet 10 red 1000 1 2 3 4 + space_objects.append(obj) - Параметры: - - **line** — строка с описание планеты. - **planet** — объект планеты. - """ - pass # FIXME: not done yet... + return obj def write_space_objects_data_to_file(output_filename, space_objects): @@ -77,10 +57,34 @@ def write_space_objects_data_to_file(output_filename, space_objects): """ with open(output_filename, 'w') as out_file: for obj in space_objects: - print(out_file, "%s %d %s %f" % ('1', 2, '3', 4.5)) - # FIXME: should store real values + out_file.write(' '.join([obj.type_, str(obj.R), obj.color, str(obj.m), str(obj.Fx), str(obj.Fy), str(obj.Vx), str(obj.Vy)])) + + +def read_space_objects_data_from_file(input_filename): + """Cчитывает данные о космических объектах из файла, создаёт сами объекты + и вызывает создание их графических образов + + Параметры: + **input_filename** — имя входного файла + """ + + objects = [] + with open(input_filename) as input_file: + for line in input_file: + if len(line.strip()) == 0 or line[0] == '#': + continue # пустые строки и строки-комментарии пропускаем + object_type = line.split(' ')[0].lower() + if object_type == 'star' or object_type == 'planet': + obj = parse_object_parameters(line) + objects.append(obj) + + else: + print("Unknown space object") + + return objects # FIXME: хорошо бы ещё сделать функцию, сохранающую статистику в заданный файл... +# D: Статистику чего? if __name__ == "__main__": print("This module is not for direct call!") diff --git a/solar_main.py b/solar_main.py index d77bddca..ff209fe4 100644 --- a/solar_main.py +++ b/solar_main.py @@ -84,9 +84,9 @@ def open_file_dialog(): calculate_scale_factor(max_distance) for obj in space_objects: - if obj.type == 'star': + if obj.type_ == 'star': create_star_image(space, obj) - elif obj.type == 'planet': + elif obj.type_ == 'planet': create_planet_image(space, obj) else: raise AssertionError() diff --git a/solar_model.py b/solar_model.py index 7cb63d65..78c1cb8e 100644 --- a/solar_model.py +++ b/solar_model.py @@ -18,10 +18,12 @@ def calculate_force(body, space_objects): for obj in space_objects: if body == obj: continue # тело не действует гравитационной силой на само себя! - r = ((body.x - obj.x)**2 + (body.y - obj.y)**2)**0.5 - body.Fx += 1 # FIXME: нужно вывести формулу... - body.Fy += 2 # FIXME: нужно вывести формулу... - + r = (((body.x - obj.x)**2) + ((body.y - obj.y)**2)) ** 0.5 + F = - gravitational_constant * body.m * obj.m/r**2 + cos = (-obj.x + body.x)/r + sin = (-obj.y + body.y)/r + body.Fx += F * cos + body.Fy += F * sin def move_space_object(body, dt): """Перемещает тело в соответствии с действующей на него силой. @@ -31,10 +33,12 @@ def move_space_object(body, dt): **body** — тело, которое нужно переместить. """ - ax = body.Fx/body.m - body.x += 42 # FIXME: не понимаю как менять... - body.Vx += ax*dt - # FIXME: not done recalculation of y coordinate! + ax = body.Fx / body.m + body.x += ax * (dt ** 2) / 2 + body.Vx * dt + body.Vx += ax * dt + ay = body.Fy / body.m + body.y += ay * (dt ** 2) / 2 + body.Vy * dt + body.Vy += ay * dt def recalculate_space_objects_positions(space_objects, dt): diff --git a/solar_objects.py b/solar_objects.py index 0c73668b..d69bf6f8 100644 --- a/solar_objects.py +++ b/solar_objects.py @@ -8,7 +8,7 @@ class Star: а также визуальный радиус звезды в пикселах и её цвет. """ - type = "star" + type_ = "star" """Признак объекта звезды""" m = 0 @@ -41,6 +41,20 @@ class Star: image = None """Изображение звезды""" + def __repr__(self): + return print({ + 'type': self.type_, + 'm': self.m, + 'x': self.x, + 'y': self.y, + 'Vx': self.Vx, + 'Vy': self.Vy, + 'Fx': self.Fx, + 'Fy': self.Fy, + 'R': self.R, + 'color': self.color + }) + class Planet: """Тип данных, описывающий планету. @@ -48,7 +62,7 @@ class Planet: а также визуальный радиус планеты в пикселах и её цвет """ - type = "planet" + type_ = "planet" """Признак объекта планеты""" m = 0 @@ -79,4 +93,18 @@ class Planet: """Цвет планеты""" image = None - """Изображение планеты""" \ No newline at end of file + """Изображение планеты""" + + def __repr__(self): + return print({ + 'type': self.type_, + 'm': self.m, + 'x': self.x, + 'y': self.y, + 'Vx': self.Vx, + 'Vy': self.Vy, + 'Fx': self.Fx, + 'Fy': self.Fy, + 'R': self.R, + 'color': self.color + }) diff --git a/solar_system.txt b/solar_system.txt index 7aa333bb..91b46927 100644 --- a/solar_system.txt +++ b/solar_system.txt @@ -1,5 +1,5 @@ -# Солнечная система -Star 2 red 1.98892E30 0 0 0 0 +# Солнце +Star 25 red 1.98892E30 0 0 0 0 # Меркурий Planet 2 orange 3.302E23 57.909E9 0 0 47.87E3 diff --git a/solar_vis.py b/solar_vis.py index ae972ba4..138dddad 100644 --- a/solar_vis.py +++ b/solar_vis.py @@ -9,10 +9,10 @@ header_font = "Arial-16" """Шрифт в заголовке""" -window_width = 800 +window_width = 1200 """Ширина окна""" -window_height = 800 +window_height = 1000 """Высота окна""" scale_factor = None @@ -54,7 +54,7 @@ def scale_y(y): **y** — y-координата модели. """ - return y # FIXME: not done yet + return int(y*scale_factor) + window_width//2.5 def create_star_image(space, star): @@ -80,7 +80,10 @@ def create_planet_image(space, planet): **space** — холст для рисования. **planet** — объект планеты. """ - pass # FIXME: сделать как у звезды + x = scale_x(planet.x) + y = scale_y(planet.y) + r = planet.R + planet.image = space.create_oval([x-r, y-r], [x+r, y+r], fill=planet.color) def update_system_name(space, system_name): diff --git a/test.txt b/test.txt new file mode 100644 index 00000000..e1c671ae --- /dev/null +++ b/test.txt @@ -0,0 +1 @@ +planet 5 green (5.974e+24+0j) (149600000000+0j) 0j 0j (29760+0j) \ No newline at end of file diff --git a/tests.py b/tests.py new file mode 100644 index 00000000..a11c8ead --- /dev/null +++ b/tests.py @@ -0,0 +1,45 @@ +from solar_input import * + + +class TestSolarInput: + space_objects = [] + def test_parse_object_parameters(): + + objects = [ + 'Planet 5 green 5.974E24 149.60E9 0 0 29.76E3', + # 'Star 30 red 1.98892E30 0 0 0 0', + # 'foe negn prekk mkmktk mmop409 09' + + ] + + for i in objects: + object_type = i.split()[0].lower() + if object_type == 'planet': + o = parse_object_parameters(i) + assert o.type_ == 'planet' + assert o.R == 5 + assert o.color == 'green' + assert o.m == complex(5.974E24) + + elif object_type == 'star': + o = parse_object_parameters(i) + assert o.type_ == 'star' + assert o.R == 30 + assert o.color == 'red' + assert o.m == complex(1.98892E30) + else: + raise ValueError + + space_objects.append(o) + + def test_reader_and_writer(): + + write_space_objects_data_to_file('test.txt', space_objects) + + output_obj = read_space_objects_data_from_file('test.txt') + + for i in range(len(space_objects)): + assert space_objects[i].type_ == output_obj[i].type_ + assert space_objects[i].R == output_obj[i].R + assert space_objects[i].color == output_obj[i].color + assert space_objects[i].m == output_obj[i].m