Skip to content

слияние #72

Open
wants to merge 17 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
# solar_project
Модель Солнечной системы на языке Python
Модель Солнечной системы на языке Python.
31 changes: 24 additions & 7 deletions solar_input.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@


def read_space_objects_data_from_file(input_filename):
"""Cчитывает данные о космических объектах из файла, создаёт сами объекты
"""Считывает данные о космических объектах из файла, создаёт сами объекты
и вызывает создание их графических образов

Параметры:
Expand All @@ -19,12 +19,14 @@ def read_space_objects_data_from_file(input_filename):
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
if object_type == "star":
star = Star()
parse_star_parameters(line, star)
objects.append(star)
else:
print("Unknown space object")
planet = Planet()
parse_planet_parameters(line, planet)
objects.append(planet)

return objects

Expand All @@ -43,8 +45,15 @@ def parse_star_parameters(line, star):
**line** — строка с описание звезды.
**star** — объект звезды.
"""
words = line.split()
star.R = float(words[1])
star.color = words[2]
star.m = float(words[3])
star.x = float(words[4])
star.y = float(words[5])
star.Vx = float(words[6])
star.Vy = float(words[7])

pass # FIXME: not done yet

def parse_planet_parameters(line, planet):
"""Считывает данные о планете из строки.
Expand All @@ -61,7 +70,14 @@ def parse_planet_parameters(line, planet):
**line** — строка с описание планеты.
**planet** — объект планеты.
"""
pass # FIXME: not done yet...
words = line.split()
planet.R = float(words[1])
planet.color = words[2]
planet.m = float(words[3])
planet.x = float(words[4])
planet.y = float(words[5])
planet.Vx = float(words[6])
planet.Vy = float(words[7])


def write_space_objects_data_to_file(output_filename, space_objects):
Expand All @@ -77,8 +93,9 @@ 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
print(obj.type, " ", obj.R, " ", obj.color, " ", obj.m, " ", obj.x,
" ", obj.y, " ", obj.Vx, " ", obj.Vy, file=out_file)


# FIXME: хорошо бы ещё сделать функцию, сохранающую статистику в заданный файл...

Expand Down
133 changes: 63 additions & 70 deletions solar_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,92 +2,78 @@
# license: GPLv3

import tkinter
from tkinter.filedialog import *
from solar_vis import *
from solar_model import *
from solar_input import *
import tkinter.filedialog as filedialog
import solar_vis as vis
import solar_model as model
import solar_input as inp

perform_execution = False
perform_execution = [False]
"""Флаг цикличности выполнения расчёта"""

physical_time = 0
"""Физическое время от начала расчёта.
Тип: float"""

displayed_time = None
"""Отображаемое на экране время.
Тип: переменная tkinter"""

time_step = None
"""Шаг по времени при моделировании.
Тип: float"""

space_objects = []
space_objects = [[]]
"""Список космических объектов."""


def execution():
def execution(perform, _physical_time, _displayed_time, _time_step, time_speed, space):
"""Функция исполнения -- выполняется циклически, вызывая обработку всех небесных тел,
а также обновляя их положение на экране.
Цикличность выполнения зависит от значения глобальной переменной perform_execution.
При perform_execution == True функция запрашивает вызов самой себя по таймеру через от 1 мс до 100 мс.
"""
global physical_time
global displayed_time
recalculate_space_objects_positions(space_objects, time_step.get())
for body in space_objects:
update_object_position(space, body)
physical_time += time_step.get()
displayed_time.set("%.1f" % physical_time + " seconds gone")

if perform_execution:
space.after(101 - int(time_speed.get()), execution)
model.recalculate_space_objects_positions(space_objects[0], _time_step.get())
for body in space_objects[0]:
vis.update_object_position(space, body)
_physical_time[0] += _time_step.get()
_displayed_time[0].set("%.1f" % _physical_time[0] + " seconds gone")
if perform[0]:
space.after(101 - int(time_speed.get()),
lambda: execution(perform, _physical_time, _displayed_time, _time_step, time_speed, space))


def start_execution():
def start_execution(perform, button, _physical_time, _displayed_time, _time_step, time_speed, space):
"""Обработчик события нажатия на кнопку Start.
Запускает циклическое исполнение функции execution.
"""
global perform_execution
perform_execution = True
start_button['text'] = "Pause"
start_button['command'] = stop_execution

execution()
perform[0] = True
button['text'] = "Pause"
button['command'] = lambda: stop_execution(perform, button, _physical_time, _displayed_time, _time_step, time_speed,
space)

execution(perform, _physical_time, _displayed_time, _time_step, time_speed, space)
print('Started execution...')


def stop_execution():
def stop_execution(perform, button, _physical_time, _displayed_time, _time_step, time_speed, space):
"""Обработчик события нажатия на кнопку Start.
Останавливает циклическое исполнение функции execution.
"""
global perform_execution
perform_execution = False
start_button['text'] = "Start"
start_button['command'] = start_execution
perform[0] = False
button['text'] = "Start"
button['command'] = lambda: start_execution(perform, button, _physical_time, _displayed_time, _time_step,
time_speed,
space)
print('Paused execution.')


def open_file_dialog():
def open_file_dialog(perform, space, _space_objects):
"""Открывает диалоговое окно выбора имени файла и вызывает
функцию считывания параметров системы небесных тел из данного файла.
Считанные объекты сохраняются в глобальный список space_objects
"""
global space_objects
global perform_execution
perform_execution = False
for obj in space_objects:
perform[0] = False
for obj in _space_objects[0]:
space.delete(obj.image) # удаление старых изображений планет
in_filename = askopenfilename(filetypes=(("Text file", ".txt"),))
space_objects = read_space_objects_data_from_file(in_filename)
max_distance = max([max(abs(obj.x), abs(obj.y)) for obj in space_objects])
calculate_scale_factor(max_distance)
in_filename = filedialog.askopenfilename(filetypes=(("Text file", ".txt"),))
_space_objects[0] = inp.read_space_objects_data_from_file(in_filename)
max_distance = max([max(abs(obj.x), abs(obj.y)) for obj in _space_objects[0]])
vis.calculate_scale_factor(max_distance, vis.scale_factor)

for obj in space_objects:
for obj in _space_objects[0]:
if obj.type == 'star':
create_star_image(space, obj)
vis.create_star_image(space, obj)
elif obj.type == 'planet':
create_planet_image(space, obj)
vis.create_planet_image(space, obj)
else:
raise AssertionError()

Expand All @@ -97,36 +83,40 @@ def save_file_dialog():
функцию считывания параметров системы небесных тел из данного файла.
Считанные объекты сохраняются в глобальный список space_objects
"""
out_filename = asksaveasfilename(filetypes=(("Text file", ".txt"),))
write_space_objects_data_to_file(out_filename, space_objects)
out_filename = filedialog.asksaveasfilename(filetypes=(("Text file", ".txt"),))
inp.write_space_objects_data_to_file(out_filename, space_objects[0])


def main():
"""Главная функция главного модуля.
Создаёт объекты графического дизайна библиотеки tkinter: окно, холст, фрейм с кнопками, кнопки.
"""
global physical_time
global displayed_time
global time_step
global time_speed
global space
global start_button

print('Modelling started!')
physical_time = 0
physical_time = [0]
"""Физическое время от начала расчёта.
Тип: float"""

root = tkinter.Tk()
# космическое пространство отображается на холсте типа Canvas
space = tkinter.Canvas(root, width=window_width, height=window_height, bg="black")
space = tkinter.Canvas(root, width=vis.window_width, height=vis.window_height, bg="black")
space.pack(side=tkinter.TOP)
# нижняя панель с кнопками
frame = tkinter.Frame(root)
frame.pack(side=tkinter.BOTTOM)

start_button = tkinter.Button(frame, text="Start", command=start_execution, width=6)
start_button.pack(side=tkinter.LEFT)
displayed_time = [tkinter.StringVar()]
"""Отображаемое на экране время.
Тип: переменная tkinter"""

displayed_time[0].set(str(physical_time[0]) + " seconds gone")
time_label = tkinter.Label(frame, textvariable=displayed_time[0], width=30)
time_label.pack(side=tkinter.RIGHT)

time_step = tkinter.DoubleVar()
"""Шаг по времени при моделировании.
Тип: float"""

time_step.set(1)
time_step_entry = tkinter.Entry(frame, textvariable=time_step)
time_step_entry.pack(side=tkinter.LEFT)
Expand All @@ -135,18 +125,21 @@ def main():
scale = tkinter.Scale(frame, variable=time_speed, orient=tkinter.HORIZONTAL)
scale.pack(side=tkinter.LEFT)

load_file_button = tkinter.Button(frame, text="Open file...", command=open_file_dialog)
start_button = tkinter.Button(frame, text="Start",
command=lambda: start_execution(perform_execution, start_button, physical_time,
displayed_time, time_step, time_speed, space),
width=6)
start_button.pack(side=tkinter.LEFT)

load_file_button = tkinter.Button(frame, text="Open file...",
command=lambda: open_file_dialog(perform_execution, space, space_objects))
load_file_button.pack(side=tkinter.LEFT)
save_file_button = tkinter.Button(frame, text="Save to file...", command=save_file_dialog)
save_file_button.pack(side=tkinter.LEFT)

displayed_time = tkinter.StringVar()
displayed_time.set(str(physical_time) + " seconds gone")
time_label = tkinter.Label(frame, textvariable=displayed_time, width=30)
time_label.pack(side=tkinter.RIGHT)

root.mainloop()
print('Modelling finished!')


if __name__ == "__main__":
main()
17 changes: 10 additions & 7 deletions solar_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ 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
body.Fx += gravitational_constant * body.m * obj.m / r ** 3 * (obj.x - body.x)
body.Fy += gravitational_constant * body.m * obj.m / r ** 3 * (obj.y - body.y)


def move_space_object(body, dt):
Expand All @@ -31,10 +31,13 @@ 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 += body.Vx * dt + ax * dt * dt / 2
body.Vx += ax * dt

ay = body.Fy / body.m
body.y += body.Vy * dt + ay * dt * dt / 2
body.Vy += ay * dt


def recalculate_space_objects_positions(space_objects, dt):
Expand Down
2 changes: 1 addition & 1 deletion solar_objects.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,4 +79,4 @@ class Planet:
"""Цвет планеты"""

image = None
"""Изображение планеты"""
"""Изображение планеты"""
Loading