#!/usr/bin/env python3
# -*- Encoding: utf-8 -*-

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.widgets import Slider

# ===========================================================
# --- CONSTANTES & PARAMÈTRES PHYSIQUES ---------------------
# ===========================================================

c = 299792458.0       # Vitesse lumière m/s
L_bras = 11.0         # Longueur des bras (11m pour l'expérience historique)
alpha = 0.5e-4        # Angle du coin d'air (pour la largeur des franges)

# Longueurs d'onde (RGB) pour la lumière blanche
lambdas = { 'R': 650e-9, 'G': 550e-9, 'B': 450e-9 }

# Configuration de l'écran (capteur)
N_pixels = 2000
largeur_ecran = 0.1 # 10 cm
x = np.linspace(-largeur_ecran/2, largeur_ecran/2, N_pixels)
y = np.linspace(-largeur_ecran/2, largeur_ecran/2, N_pixels)
X, Y = np.meshgrid(x, y)

# ===========================================================
# --- MODÈLE PHYSIQUE ---------------------------------------
# ===========================================================

def calculer_image(v_ether_kms, angle_deg):
    """
    Calcule la matrice RGB de l'image pour une vitesse et une rotation données.
    """
    v = v_ether_kms * 1000.0
    beta = v / c
    
    # Conversion angle en radians
    theta = np.deg2rad(angle_deg)
    
    # --- Différence de marche (Ether) ---
    # La différence varie en cos(2*theta).
    # theta = 0   -> cos(0)=1   (Max retard)
    # theta = 45  -> cos(90)=0  (Annulation)
    # theta = 90  -> cos(180)=-1 (Inversion)
    delta_ether_max = L_bras * (beta**2)
    delta_ether = delta_ether_max * np.cos(2 * theta) # Al Kashi
    
    # --- Différence de marche (Coin d'air) ---
    delta_geo = 2 * alpha * X
    
    # Total
    delta_total = delta_geo + delta_ether
    
    # --- Calcul de l'intensité RGB ---
    img_rgb = np.zeros((N_pixels, N_pixels, 3))
    
    # Enveloppe de cohérence (contraste diminue si on s'éloigne du contact optique)
    Lc = (lambdas['G']**2)/(lambdas['R']-lambdas['B'])
    envelope = np.exp(-(delta_total/(Lc))**2)
    #envelope = np.abs(np.sinc(delta_total / Lc))
    
    # Intensité I = I0 * (1 + cos(2*pi*delta/lambda))
    img_rgb[:,:,0] = 0.5 * (1 + np.cos(2 * np.pi * delta_total / lambdas['R'])) * envelope
    img_rgb[:,:,1] = 0.5 * (1 + np.cos(2 * np.pi * delta_total / lambdas['G'])) * envelope
    img_rgb[:,:,2] = 0.5 * (1 + np.cos(2 * np.pi * delta_total / lambdas['B'])) * envelope
    
    return img_rgb, delta_ether

# ===========================================================
# --- INTERFACE GRAPHIQUE (Matplotlib Standard) -------------
# ===========================================================

# 1. Création de la figure
fig, ax = plt.subplots(figsize=(10, 8))
plt.subplots_adjust(bottom=0.30) # Espace pour 2 sliders

# 2. Calcul initial (v=0, angle=0)
img_init, shift_init = calculer_image(0, 0)

# 3. Affichage de l'image
extent = [x.min()*1000, x.max()*1000, y.min()*1000, y.max()*1000] # en mm
im_display = ax.imshow(img_init, extent=extent, origin='lower', aspect='auto')

# Réticule fixe
ax.axvline(0, color='white', linestyle='--', linewidth=1, alpha=0.8)

# Titres et cosmétique
ax.set_xlabel("Position (mm)")
ax.get_yaxis().set_visible(False)
title_text = ax.set_title(f"Simulation Michelson-Morley\nInitialisation...")

# ===========================================================
# --- CRÉATION DES SLIDERS ----------------------------------
# ===========================================================

# Slider Vitesse
ax_slider_v = plt.axes([0.2, 0.15, 0.6, 0.03], facecolor='lightgoldenrodyellow')
slider_v = Slider(
    ax=ax_slider_v,
    label='Vitesse (km/s) ',
    valmin=0,
    valmax=60,
    valinit=0,  # On commence à 0 pour montrer "l'avant"
    valstep=1
)

# Slider Angle (Rotation du plateau)
ax_slider_angle = plt.axes([0.2, 0.08, 0.6, 0.03], facecolor='lightblue')
slider_angle = Slider(
    ax=ax_slider_angle,
    label='Rotation (°)',
    valmin=0,
    valmax=180, # 180 suffisent pour voir l'aller-retour complet
    valinit=0,
    valstep=1
)

# Fonction de mise à jour commune
def update(val):
    v = slider_v.val
    angle = slider_angle.val
    
    # Recalcul
    new_img, delta = calculer_image(v, angle)
    
    # Mise à jour graphique
    im_display.set_data(new_img)
    
    # Mise à jour titre
    shift_nm = delta * 1e9
    nb_franges = delta / lambdas['G']
    
    title_text.set_text(
        f"Simu Michelson-Morley ($L=11$m)\n"
        f"Vitesse: {v:.0f} km/s | Angle: {angle:.0f}°\n"
        f"Décalage éther: {shift_nm:.1f} nm ({nb_franges:.2f} franges)"
    )
    
    fig.canvas.draw_idle()

# Connexion
slider_v.on_changed(update)
slider_angle.on_changed(update)

# Premier appel pour mettre le titre à jour
update(0)

plt.show()