import os, datetime, math
import customtkinter as ctk
from tkinter import messagebox
import ephem
from skyfield.api import Loader
import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from PIL import Image
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
# ---> COPAS CITY_DB LENGKAP DARI KODE MASTER ANDA DI SINI <---
CITY_DB = {
"Selandia Baru": {"Gisborne": (-38.6623, 178.0176)},
"Amerika Serikat": {"Los Angeles": (34.0522, -118.2437)},
"Jawa Tengah": {"Semarang": (-7.0667, 110.4100)}
}
class Menu5App(ctk.CTk):
def __init__(self):
super().__init__()
self.title("Titik Pertama KHGT (Modul 5)")
self.geometry("1100x700")
ctk.set_appearance_mode("Dark")
self.load_obj = Loader(BASE_DIR, verbose=False)
self.ts = self.load_obj.timescale()
self.eph = self.load_obj('de421.bsp')
self.setup_ui()
def setup_ui(self):
self.sidebar = ctk.CTkFrame(self, width=250)
self.sidebar.pack(side="left", fill="y", padx=10, pady=10)
ctk.CTkLabel(self.sidebar, text="KOTA PERTAMA KHGT", font=("Segoe UI", 16, "bold")).pack(pady=20)
row = ctk.CTkFrame(self.sidebar, fg_color="transparent")
row.pack()
self.entry_d = ctk.CTkEntry(row, width=40); self.entry_d.insert(0, "17"); self.entry_d.pack(side="left", padx=2)
self.entry_m = ctk.CTkEntry(row, width=40); self.entry_m.insert(0, "2"); self.entry_m.pack(side="left", padx=2)
self.entry_y = ctk.CTkEntry(row, width=60); self.entry_y.insert(0, "2026"); self.entry_y.pack(side="left", padx=2)
ctk.CTkButton(self.sidebar, text="▶ LACAK GLOBAL", command=self.lacak).pack(pady=20)
self.main_frame = ctk.CTkFrame(self)
self.main_frame.pack(side="right", fill="both", expand=True, padx=10, pady=10)
def lacak(self):
for w in self.main_frame.winfo_children(): w.destroy()
y, m, d = int(self.entry_y.get()), int(self.entry_m.get()), int(self.entry_d.get())
waktu_tuple = (y, m, d, 12, 0, 0)
matahari, bulan = ephem.Sun(), ephem.Moon()
ijtimak_1 = ephem.previous_new_moon(waktu_tuple)
titik_hasil = []
# Pencarian brute-force
for offset_hari in range(4):
kandidat = []
waktu_pencarian = ephem.Date(ijtimak_1 + offset_hari)
for negara, kota_dict in CITY_DB.items():
for nama_kota, koordinat in kota_dict.items():
pengamat = ephem.Observer()
pengamat.lat, pengamat.lon = str(koordinat[0]), str(koordinat[1])
pengamat.date = waktu_pencarian
try:
ws = pengamat.next_setting(matahari)
pengamat.date = ws
matahari.compute(pengamat)
bulan.compute(pengamat)
# Pseudo-Geocentric (Untuk kecepatan Modul Standalone)
elong = math.degrees(ephem.separation(matahari, bulan))
alt = math.degrees(bulan.alt)
if alt >= 5.0 and elong >= 8.0:
kandidat.append({'kota': nama_kota, 'lat': koordinat[0], 'lon': koordinat[1], 'sunset': ws})
except: continue
if kandidat:
kandidat.sort(key=lambda x: x['sunset'])
titik_hasil.append(kandidat[0])
break
if not titik_hasil:
messagebox.showinfo("Hasil", "Tidak ditemukan daratan yang memenuhi kriteria.")
return
pt = titik_hasil[0]
# Plot Matplotlib Map
fig, ax = plt.subplots(figsize=(8, 5))
try:
img = Image.open(os.path.join(BASE_DIR, "map_topografi.jpg"))
ax.imshow(img, extent=[-180, 180, -90, 90])
except: pass
ax.scatter([pt['lon']], [pt['lat']], color='yellow', marker='*', s=300, edgecolor='red')
ax.text(pt['lon'], pt['lat']+5, f"Pertama: {pt['kota']}", color='white', bbox=dict(fc='black'))
ax.set_title(f"Titik Pertama Pemenuhan KHGT (PKG)")
canvas = FigureCanvasTkAgg(fig, master=self.main_frame)
canvas.draw()
canvas.get_tk_widget().pack(fill="both", expand=True)
if __name__ == "__main__":
app = Menu5App()
app.mainloop()