import pylab as plt
import numpy as np
import scipy.optimize
import matplotlib as mpl
from matplotlib.widgets import Slider, Button

mpl.rcParams['text.usetex'] = False #True pour mettre du beau LateX mais ça fait laguer ou False c'est moche mais ça lag pas
mpl.rcParams['axes.titlesize'] = 15
mpl.rcParams['axes.labelsize'] = 22
mpl.rcParams['lines.linewidth'] = 3
mpl.rcParams['lines.markersize'] = 8
mpl.rcParams['xtick.labelsize'] = 20
mpl.rcParams['ytick.labelsize'] = 20
mpl.rcParams['legend.fontsize'] = 15

#Source et Théorie : https://tel.archives-ouvertes.fr/tel-01684755/file/OBLIGADO_2013_diffusion.pdf (Chapitre 3)

##Le gros du calcul

# The parametrized function to be plotted
def to_plot(alpha,alpha_crit,m,u) : 
    #Paramètres physiques en SI
    m = m*1e-3 #conversion en kg
    rho = 1.3
    S = np.pi *5e-2**2
    d = 20e-2
    g=9.81
    alpha_crit = np.pi*alpha_crit/180
    alpha = np.pi*alpha/180
    
    def Cn(alpha,alpha_crit) :
        #Forme de coefficient de traînée normal (constant pour alpha<alpha_crit et linéaire pour alpha>alpha_crit)
        alpha_inf = alpha[np.where(alpha<=alpha_crit)]
        alpha_sup = alpha[np.where(alpha>alpha_crit)]
        Cn_inf = 1.2*np.ones((len(alpha_inf)))
        Cn_sup = 1.7*(alpha_sup-np.pi/2)/(alpha_crit-np.pi/2)
        return np.concatenate((Cn_inf,Cn_sup))
    
    def F(alpha,alpha_crit,m,g,rho,S,d,u) :
        #Calcul des coefficients de traînée et portance à partir du coefficient normal
        C = Cn(alpha,alpha_crit)
        Ct = C*np.cos(alpha)
        Cp = C*np.sin(alpha)
        #Calcul des forces
        ft = 0.5 * rho * S*np.cos(alpha) * Ct * u**2
        fp = 0.5 * rho * S*np.cos(alpha) * Cp * u**2
        #Calcul du couple total
        return ft * d*np.cos(alpha) + fp * d*np.sin(alpha)
        
    def P(alpha,alpha_crit,m,g,rho,S,d,u) :
        #Calcul du couple du poids
        return m*g* d*np.sin(alpha)
        
    def to_zero(alpha,alpha_crit,m,g,rho,S,d,u) :
        #Fait la différence des deux couples pour trouver les angles d'équilibres
        return F(alpha,alpha_crit,m,g,rho,S,d,u) - P(alpha,alpha_crit,m,g,rho,S,d,u)
    
    P0 = P(alpha,alpha_crit,m,g,rho,S,d,u)
    F0 = F(alpha,alpha_crit,m,g,rho,S,d,u)
    
    zeros = to_zero(alpha,alpha_crit,m,g,rho,S,d,u)
    alpha_eq = alpha[np.where(np.logical_and(zeros<0.0005,zeros>-0.0005))]
    
    alpha_eq = np.array(alpha_eq*180/np.pi)
    
    
    return P0,F0,alpha_eq
    
alpha = np.linspace(0,90,2000)

##Le plot avec sliders

# Define initial parameters
init_alpha_crit = 50
init_m = 100
init_u = 10


# Create the figure and the line that we will manipulate
fig, (ax1,ax2) = plt.subplots(1,2)
P,F,alpha_eq=to_plot(alpha,init_alpha_crit,init_m,init_u)
line_P, = ax1.plot(alpha, P,label='Couple du poids')
line_F, = ax1.plot(alpha, F,label='Couple des forces de traînée et portance')
line_alpha_crit = ax1.axvline(init_alpha_crit,linestyle='--',color='black')
ax1.set_xlabel(r'$\alpha$ (°)')
ax1.set_ylabel('Couples (N.m)')
ax1.set_xlim(0,90)
ax1.set_ylim(0,0.25)

global u_tab,alpha_eq_tab
u_tab = init_u*np.ones(len(alpha_eq))
alpha_eq_tab=alpha_eq

line2, = ax2.plot(u_tab,alpha_eq_tab,'o')
ax2.set_ylabel(r'$\alpha_\mathrm{éq}$ (°)')
ax2.set_xlabel(r'u (m/s)')
ax2.set_xlim(0,20)
ax2.set_ylim(0,90)

# Adjust the main plot to make room for the sliders
#plt.subplots_adjust(left=0.25, bottom=0.25)
plt.subplots_adjust(left=0.1,bottom=0.25,top=0.95)

# Make horizontal sliders to control the parameters.
ax_m = plt.axes([0.1, 0.07, 0.8, 0.03])
m_slider = Slider(
    ax=ax_m,
    label=r'$m$ (g)',
    valmin=0.01,
    valmax=200,
    valinit=init_m,
)
m_slider.label.set_size(20)
m_slider.valtext.set_fontsize(20)

ax_u = plt.axes([0.1, 0.1, 0.8, 0.03])
u_slider = Slider(
    ax=ax_u,
    label=r'$u$ (m/s)',
    valmin=0.01,
    valmax=20,
    valinit=init_u,
)
u_slider.label.set_size(20)
u_slider.valtext.set_fontsize(20)

ax_alpha_crit = plt.axes([0.1, 0.13, 0.8, 0.03])
alpha_crit_slider = Slider(
    ax=ax_alpha_crit,
    label=r'$\alpha_\mathrm{crit}$ (°)',
    valmin=0.01,
    valmax=90,
    valinit=init_alpha_crit,
)
alpha_crit_slider.label.set_size(20)
alpha_crit_slider.valtext.set_fontsize(20)



# The function to be called anytime a slider's value changes
def update(val):
    P,F,alpha_eq=to_plot(alpha,alpha_crit_slider.val, m_slider.val, u_slider.val)
    line_P.set_ydata(P)
    line_F.set_ydata(F)
    line_alpha_crit.set_xdata(alpha_crit_slider.val)
    
    global u_tab,alpha_eq_tab
    u_tab = np.concatenate((u_slider.val * np.ones(len(alpha_eq)) , u_tab ))
    alpha_eq_tab = np.concatenate((alpha_eq , alpha_eq_tab ))
    line2.set_ydata(alpha_eq_tab)
    line2.set_xdata(u_tab)
    fig.canvas.draw_idle()


# register the update function with each slider
m_slider.on_changed(update)
u_slider.on_changed(update)
alpha_crit_slider.on_changed(update)

# Create a `matplotlib.widgets.Button` to reset the sliders to initial values.
resetax = plt.axes([0.8, 0.025, 0.1, 0.04])
button = Button(resetax, 'Reset', hovercolor='0.975')

def reset(event):
    m_slider.reset()
    u_slider.reset()
    alpha_crit_slider.reset()
    global u_tab,alpha_eq_tab
    alpha_eq_tab = []
    u_tab = []
    line2.set_ydata(alpha_eq_tab)
    line2.set_xdata(u_tab)
    
button.on_clicked(reset)

#Bouton pour nettoyer la deuxième subplot avec le cycle d'hystérésis
clean_ax2_ax = plt.axes([0.7, 0.025, 0.1, 0.04])
button2 = Button(clean_ax2_ax, 'Nettoyer', hovercolor='0.975')

def clean_ax2(event):
    global u_tab,alpha_eq_tab
    alpha_eq_tab = []
    u_tab = []
    line2.set_ydata(alpha_eq_tab)
    line2.set_xdata(u_tab)
    
button2.on_clicked(clean_ax2)

ax1.legend(loc='upper right')
plt.show()


