Hadlock

planet(-oid) barycenter calculator v3

May 1st, 2026
84
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 6.27 KB | Source Code | 0 0
  1. import pygame, sys, math
  2. # bary v3
  3. pygame.init()
  4. W, H = 980, 580
  5. S = pygame.display.set_mode((W, H)); pygame.display.set_caption("Solar Barycenter Calculator")
  6. F  = pygame.font.SysFont("monospace", 13)
  7. FB = pygame.font.SysFont("monospace", 14, bold=True)
  8. FT = pygame.font.SysFont("monospace", 17, bold=True)
  9.  
  10. MS = 1.989e30   # Sun mass (kg)
  11. RS = 696000     # Sun radius (km)
  12. AU = 1.496e8    # 1 AU in km
  13. ME = 5.972e24   # Earth mass (kg)
  14.  
  15. # (name, distance in AU, mass in Earth masses)
  16. PL = [("Mercury",0.387,0.0553),("Venus",0.723,0.815),("Earth",1.000,1.0),
  17.       ("Mars",1.524,0.107),("Jupiter",5.204,317.8),("Saturn",9.582,95.16),
  18.       ("Uranus",19.20,14.54),("Neptune",30.05,17.15),("Pluto",39.48,0.0022),
  19.       ("Eris",67.78,0.00277),("Ceres",2.768,0.000158)]
  20. PR = [("Eris",67.78,0.00277),("Pluto",39.48,0.0022),("Haumea",43.13,6.71e-4),
  21.       ("Makemake",45.79,5.19e-4),("Gonggong",67.49,2.93e-4),("Charon",39.48,2.66e-4),
  22.       ("Quaoar",43.69,2.34e-4),("Sedna",506.0,1.67e-4),("Orcus",39.42,1.06e-4),
  23.       ("Salacia",42.18,8.24e-5),("Ceres",2.768,1.58e-4)]
  24. SL = {"d": 5.204, "m": 317.8}   # custom-row defaults: Jupiter
  25. DR = None
  26.  
  27. def bc(au, me):
  28.     r = au * AU * me * ME / (MS + me * ME)
  29.     return r, r - RS, r < RS
  30.  
  31. def panel(rect, col=(25,25,45), r=6):
  32.     pygame.draw.rect(S, col, rect, border_radius=r)
  33.     pygame.draw.rect(S, (50,50,80), rect, 1, border_radius=r)
  34.  
  35. def sldr(lbl, k, x, y, mn, mx_, w=270):
  36.     v = SL[k]
  37.     pct = max(0, min(1, (math.log10(v)-math.log10(mn)) / (math.log10(mx_)-math.log10(mn))))
  38.     kx = x + int(pct*w)
  39.     panel(pygame.Rect(x-8, y-22, w+16, 44), (20,20,38))
  40.     pygame.draw.rect(S, (40,40,65),  (x, y+5, w, 5), border_radius=3)
  41.     pygame.draw.rect(S, (80,170,255),(x, y+5, kx-x, 5), border_radius=3)
  42.     pygame.draw.circle(S, (30,30,50),  (kx, y+7), 9)
  43.     pygame.draw.circle(S, (80,170,255),(kx, y+7), 7)
  44.     pygame.draw.circle(S, (180,220,255),(kx-2, y+5), 2)
  45.     S.blit(F.render(f"{lbl}: {v:.4g}", 1, (170,190,220)), (x, y-18))
  46.     return pygame.Rect(x-4, y+1, w+8, 14)
  47.  
  48. BG=(10,10,20); CI=(60,220,100); CO=(255,70,70); CH=(80,180,255); CK=(140,100,255); CY=(255,230,60)
  49. COLS = [("Body",120),("Dist AU",80),("Mass/ME",88),("Bary (km)",105),("Diff (km)",110),("Inside?",72)]
  50. TW = sum(w for _, w in COLS)
  51. SR = {}
  52. clock = pygame.time.Clock()
  53. D_MIN, D_MAX = 0.1, 1000.0    # AU (1000 covers Sedna's 506 AU semi-major)
  54. M_MIN, M_MAX = 1e-6, 400.0    # Earth masses
  55.  
  56. # Pluto-Charon two-body system: the only known dwarf-planet pair whose barycenter
  57. # lies outside the primary. Computed independently of the Sun-relative bc().
  58. PC_D, PC_MP, PC_MC, PC_RP = 19591, 1.303e22, 1.586e21, 1188.3   # km, kg, kg, km
  59. PC_R = PC_D * PC_MC / (PC_MP + PC_MC)   # bary distance from Pluto center (km)
  60. PC_OUT = PC_R > PC_RP
  61.  
  62. def stars():
  63.     t = pygame.time.get_ticks()
  64.     for i in range(45):
  65.         b = 80 + (i*37 + t//80) % 120
  66.         pygame.draw.circle(S, (b,b,b+20), ((i*173+11)%W, (i*97+7)%110), 1 if i%3 else 0)
  67.  
  68. while True:
  69.     S.fill(BG); stars()
  70.     mx, my = pygame.mouse.get_pos()
  71.     for e in pygame.event.get():
  72.         if e.type == pygame.QUIT: sys.exit()
  73.         if e.type == pygame.MOUSEBUTTONUP: DR = None
  74.         if e.type == pygame.MOUSEBUTTONDOWN:
  75.             if SR.get("d") and SR["d"].collidepoint(e.pos): DR = "d"
  76.             if SR.get("m") and SR["m"].collidepoint(e.pos): DR = "m"
  77.             for i, (n, a, m) in enumerate(PR):
  78.                 if pygame.Rect(W-165, 130+i*32, 150, 26).collidepoint(e.pos):
  79.                     SL["d"] = a; SL["m"] = m
  80.         if e.type == pygame.MOUSEMOTION and DR:
  81.             for k, x, mn, mx_, w in [("d",30,D_MIN,D_MAX,270), ("m",340,M_MIN,M_MAX,270)]:
  82.                 if DR == k:
  83.                     SL[k] = mn * (mx_/mn) ** max(0, min(1, (mx-x)/w))
  84.  
  85.     S.blit(FT.render("SOLAR BARYCENTER CALCULATOR", 1, CH), (30, 12))
  86.     S.blit(F.render(f"Sun radius: {RS:,} km  |  Inside = barycenter within solar surface", 1, (80,80,110)), (30, 34))
  87.     SR["d"] = sldr("Distance (AU)",  "d",  30, 75, D_MIN, D_MAX)
  88.     SR["m"] = sldr("Mass (x Earth)", "m", 340, 75, M_MIN, M_MAX)
  89.  
  90.     panel(pygame.Rect(W-170, 108, 160, 22 + len(PR)*32 + 8), (18,18,36))
  91.     S.blit(F.render("PRESETS", 1, (100,100,150)), (W-160, 113))
  92.     for i, (n, a, m) in enumerate(PR):
  93.         br = pygame.Rect(W-162, 130+i*32, 144, 24); hot = br.collidepoint(mx, my)
  94.         panel(br, (45,35,80) if hot else (30,25,55))
  95.         S.blit(FB.render(n, 1, CK if hot else (150,130,220)), (W-155, 134+i*32))
  96.  
  97.     hx, hy = 18, 140
  98.     panel(pygame.Rect(hx-2, hy, TW+4, 22), (20,30,65))
  99.     for h, w in COLS:
  100.         S.blit(FB.render(h, 1, CH), (hx+3, hy+4)); hx += w
  101.  
  102.     for i, (nm, au, me) in enumerate(PL + [("Custom", SL["d"], SL["m"])]):
  103.         r, df, ins = bc(au, me)
  104.         ry, rx = 164 + i*20, 18
  105.         custom = nm == "Custom"
  106.         pygame.draw.rect(S, (30,22,55) if custom else ((24,24,42) if i%2 else (18,18,32)), (rx-2, ry, TW+4, 19))
  107.         if custom: pygame.draw.rect(S, (70,50,120), (rx-2, ry, TW+4, 19), 1)
  108.         vs = [nm, f"{au:.3f}", f"{me:.5g}", f"{r:,.0f}", f"{abs(df):,.0f}", "YES" if ins else "NO"]
  109.         for j, ((h, w), v) in enumerate(zip(COLS, vs)):
  110.             tc = CI if (j==5 and ins) else CO if j==5 else CY if custom else (200,200,210)
  111.             S.blit(F.render(v, 1, tc), (rx+2, ry+3)); rx += w
  112.  
  113.     by = 410
  114.     panel(pygame.Rect(16, by, TW+4, 118), (28,18,38))
  115.     S.blit(FB.render("BINARY: Pluto-Charon  (only known case where the barycenter sits outside the primary)", 1, CK), (24, by+6))
  116.     S.blit(F.render(f"Separation: {PC_D:,} km     Pluto radius: {PC_RP:,.0f} km     Charon/Pluto mass ratio: {PC_MC/PC_MP*100:.2f}%", 1, (190,190,210)), (24, by+28))
  117.     S.blit(F.render(f"Pluto mass:  {PC_MP:.3e} kg     Charon mass: {PC_MC:.3e} kg", 1, (190,190,210)), (24, by+46))
  118.     S.blit(F.render(f"Barycenter: {PC_R:,.0f} km from Pluto center", 1, (200,200,220)), (24, by+64))
  119.     pc_col = CO if PC_OUT else CI
  120.     pc_msg = f"OUTSIDE Pluto by {PC_R-PC_RP:,.0f} km" if PC_OUT else f"INSIDE Pluto by {PC_RP-PC_R:,.0f} km"
  121.     S.blit(FB.render(pc_msg, 1, pc_col), (24, by+86))
  122.  
  123.     pygame.draw.line(S, (40,40,70), (18, H-28), (W-18, H-28))
  124.     S.blit(F.render("Green=inside primary  Red=outside  Yellow=custom  Sliders are log-scale", 1, (65,65,95)), (18, H-20))
  125.     pygame.display.flip(); clock.tick(60)
Advertisement
Add Comment
Please, Sign In to add comment