Skip to content

Commit d26141b

Browse files
Now you've got a control panel!
1 parent 96d2e33 commit d26141b

1 file changed

Lines changed: 82 additions & 55 deletions

File tree

  • multi-body-orbital-mechanics
Lines changed: 82 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,73 +1,60 @@
11
import matplotlib.pyplot as plt
22
import matplotlib.animation as animation
33
import math
4+
from matplotlib.widgets import Button
45

56
# --- Physics constants ---
67
G = 6.67430e-11 # gravitational constant
7-
dt = 60 * 60 * 24 # time step (24 hours)
8-
frame_count = 0 # to animate glow pulsing
8+
dt = 60 * 60 * 24 # 1 day per frame
9+
frame_count = 0
10+
sun_gravity_on = True # Sun gravity toggle
911

1012
# --- Planet data ---
1113
planets = [
12-
{
13-
"pos": [0.39 * 1.496e11, 0], # Mercury
14-
"vel": [0, 47360],
15-
"mass": 3.285e23,
16-
"x_path": [],
17-
"y_path": [],
18-
"color": "gray"
19-
},
20-
{
21-
"pos": [0.72 * 1.496e11, 0], # Venus
22-
"vel": [0, 35020],
23-
"mass": 4.867e24,
24-
"x_path": [],
25-
"y_path": [],
26-
"color": "orange"
27-
},
28-
{
29-
"pos": [1.496e11, 0], # Earth
30-
"vel": [0, 29780],
31-
"mass": 5.972e24,
32-
"x_path": [],
33-
"y_path": [],
34-
"color": "blue"
35-
},
36-
{
37-
"pos": [1.52 * 1.496e11, 0], # Mars
38-
"vel": [0, 24077],
39-
"mass": 6.417e23,
40-
"x_path": [],
41-
"y_path": [],
42-
"color": "red"
43-
}
14+
{"name": "Mercury", "pos": [0.39 * 1.496e11, 0], "vel": [0, 47360],
15+
"mass": 3.285e23, "mass_on": True, "x_path": [], "y_path": [], "color": "gray"},
16+
{"name": "Venus", "pos": [0.72 * 1.496e11, 0], "vel": [0, 35020],
17+
"mass": 4.867e24, "mass_on": True, "x_path": [], "y_path": [], "color": "orange"},
18+
{"name": "Earth", "pos": [1.496e11, 0], "vel": [0, 29780],
19+
"mass": 5.972e24, "mass_on": True, "x_path": [], "y_path": [], "color": "blue"},
20+
{"name": "Mars", "pos": [1.52 * 1.496e11, 0], "vel": [0, 24077],
21+
"mass": 6.417e23, "mass_on": True, "x_path": [], "y_path": [], "color": "red"},
22+
{"name": "Jupiter", "pos": [5.2 * 1.496e11, 0], "vel": [0, 13070],
23+
"mass": 1.898e27, "mass_on": True, "x_path": [], "y_path": [], "color": "brown"}
4424
]
4525

26+
# --- Store initial positions/velocities for reset ---
27+
initial_states = []
28+
for p in planets:
29+
initial_states.append({"pos": p["pos"][:], "vel": p["vel"][:]})
30+
4631
# --- Setup figure ---
4732
fig, ax = plt.subplots()
4833
fig.patch.set_facecolor('black')
4934
ax.set_facecolor("black")
5035
ax.set_aspect('equal', adjustable='box')
5136

37+
# --- Physics update ---
5238
def update_positions():
5339
for i, p1 in enumerate(planets):
5440
fx = fy = 0
5541
for j, p2 in enumerate(planets):
56-
if i != j:
42+
if i != j and p2["mass_on"]:
5743
dx = p2["pos"][0] - p1["pos"][0]
5844
dy = p2["pos"][1] - p1["pos"][1]
5945
dist = math.sqrt(dx**2 + dy**2)
6046
F = G * p1["mass"] * p2["mass"] / dist**2
6147
fx += F * dx / dist
6248
fy += F * dy / dist
6349

64-
# Add Sun gravity
65-
dx = 0 - p1["pos"][0]
66-
dy = 0 - p1["pos"][1]
67-
dist = math.sqrt(dx**2 + dy**2)
68-
F = G * p1["mass"] * 1.989e30 / dist**2
69-
fx += F * dx / dist
70-
fy += F * dy / dist
50+
# Sun gravity (toggleable)
51+
if sun_gravity_on:
52+
dx = 0 - p1["pos"][0]
53+
dy = 0 - p1["pos"][1]
54+
dist = math.sqrt(dx**2 + dy**2)
55+
F = G * p1["mass"] * 1.989e30 / dist**2
56+
fx += F * dx / dist
57+
fy += F * dy / dist
7158

7259
# Update velocity & position
7360
p1["vel"][0] += fx / p1["mass"] * dt
@@ -79,35 +66,75 @@ def update_positions():
7966
p1["x_path"].append(p1["pos"][0])
8067
p1["y_path"].append(p1["pos"][1])
8168

69+
# --- Animation ---
8270
def animate(frame):
8371
global frame_count
8472
frame_count += 1
8573
ax.clear()
8674
ax.set_facecolor("black")
8775
ax.set_aspect('equal', adjustable='box')
88-
ax.set_xlim(-2.5e11, 2.5e11)
89-
ax.set_ylim(-2.5e11, 2.5e11)
9076
ax.axis('off')
9177

9278
update_positions()
9379

94-
# --- Sun breathing glow ---
95-
glow_alpha = 0.3 + 0.25 * (math.sin(frame_count * 0.05) + 1) / 2
96-
ax.scatter(0, 0, color='yellow', s=200, zorder=3)
97-
ax.scatter(0, 0, color='yellow', s=900, alpha=glow_alpha, zorder=1)
80+
# Automatic scaling
81+
max_distance = max(math.sqrt(p["pos"][0]**2 + p["pos"][1]**2) for p in planets)
82+
margin = 0.3 * max_distance
83+
ax.set_xlim(-max_distance - margin, max_distance + margin)
84+
ax.set_ylim(-max_distance - margin, max_distance + margin)
85+
86+
# Sun core & subtle halo
87+
glow_alpha = 0.2 + 0.1 * (math.sin(frame_count * 0.05) + 1) / 2
88+
ax.scatter(0, 0, color='yellow', s=200, zorder=3) # Sun core
89+
ax.scatter(0, 0, color='yellow', s=100, alpha=glow_alpha, zorder=1) # subtle halo
9890

99-
# --- Planets ---
91+
# Planets
10092
for p in planets:
10193
# Orbit path
10294
ax.plot(p["x_path"], p["y_path"], color=p["color"], lw=1)
95+
# Planet core
96+
ax.scatter(p["pos"][0], p["pos"][1], color=p["color"], s=30, zorder=4)
97+
# Planet glow halo
98+
planet_alpha = 0.1 + 0.05 * (math.sin(frame_count * 0.1) + 1) / 2
99+
ax.scatter(p["pos"][0], p["pos"][1], color=p["color"], s=150, alpha=planet_alpha, zorder=2)
100+
101+
# --- Button callbacks ---
102+
def reset(event):
103+
for i, p in enumerate(planets):
104+
p["pos"] = initial_states[i]["pos"][:]
105+
p["vel"] = initial_states[i]["vel"][:]
106+
p["x_path"].clear()
107+
p["y_path"].clear()
108+
109+
def toggle_mass(planet_index):
110+
def inner(event):
111+
planets[planet_index]["mass_on"] = not planets[planet_index]["mass_on"]
112+
status = "ON" if planets[planet_index]["mass_on"] else "OFF"
113+
print(f"{planets[planet_index]['name']} mass toggled {status}")
114+
return inner
115+
116+
def toggle_sun_gravity(event):
117+
global sun_gravity_on
118+
sun_gravity_on = not sun_gravity_on
119+
status = "ON" if sun_gravity_on else "OFF"
120+
print(f"Sun gravity toggled {status}")
121+
122+
# --- Add buttons ---
123+
ax_reset = plt.axes([0.81, 0.05, 0.1, 0.05])
124+
btn_reset = Button(ax_reset, 'Reset')
125+
btn_reset.on_clicked(reset)
103126

104-
# Planet
105-
ax.scatter(p["pos"][0], p["pos"][1], color=p["color"], s=30, zorder=3)
127+
# Buttons for each planet
128+
for i, p in enumerate(planets):
129+
ax_btn = plt.axes([0.01, 0.05 + i*0.06, 0.1, 0.05])
130+
btn = Button(ax_btn, p["name"])
131+
btn.on_clicked(toggle_mass(i))
106132

107-
# Glow halo
108-
planet_alpha = 0.3 + 0.25 * (math.sin(frame_count * 0.1) + 1) / 2
109-
ax.scatter(p["pos"][0], p["pos"][1],
110-
color=p["color"], s=200, alpha=planet_alpha, zorder=1)
133+
# Sun gravity toggle button
134+
ax_sun = plt.axes([0.81, 0.12, 0.1, 0.05])
135+
btn_sun = Button(ax_sun, "Sun Gravity")
136+
btn_sun.on_clicked(toggle_sun_gravity)
111137

138+
# --- Run animation ---
112139
ani = animation.FuncAnimation(fig, animate, frames=360, interval=20)
113140
plt.show()

0 commit comments

Comments
 (0)