import numpy as np

def generate_scaled_circular_helix(ind, N_pts):
    """
        Function to generate a cicular helix of unit length.

        Inputs:
        - ind: float 
          Indice that will determine the number of spin in the helix (basically put indices between 10 and 35)
        - N_pts: int
          Number of sample points in the curve.

    """
    time = np.linspace(0, ind, N_pts)
    x = 0.5*np.cos(time)
    y = 0.5*np.sin(time)
    z = 0.5*time
    c = np.sqrt(0.5**2 + 0.5**2)
    arc_s = c*time
    f_arc_s_scale = lambda s: s
    L = arc_s[-1]
    x = (np.stack((x,y,z), axis=0).T)/L
    curv = lambda s: (0.5/c**2)*L + 0*s
    tors = lambda s: (0.5/c**2)*L + 0*s
    theta = lambda s: np.array([curv(s), tors(s)])
    Q0 = np.array([[0, -1, 0],[0.5/c, 0, -0.5/c],[0.5/c, 0, 0.5/c]])
    return x, theta, f_arc_s_scale, L, Q0

def curvature_one_pic(ind):
    """
        Function to generate a function of curvature with one peak located around the value pass in argument between 0.1 and 0.9.
    """
    if ind < 0.1 or ind > 0.9:
        print("the variable 'ind' must be between 0.1 and 0.9")
    else:
        f = lambda t: np.exp(15*np.power(np.sin(np.pi*t - ind*np.pi + np.pi/2),15))/50000
        return f

def curvature_spiral_2D(ind):
    """
        Function to generate a function of curvature that will define a 2D spiral.
    """
    f = lambda t: ind*np.log(t + 2)
    return f


""" Set of possible warping functions to change the parametrization of a curve. """

def omega(s,a):
    if np.abs(a)<1e-15:
        return s
    else:
        return np.around(np.log(s*(np.exp(a)-1)+1)/a, decimals=6)

def omega_prime(s,a):
    if np.abs(a)<1e-15:
        return 1 + s*0
    else:
        return (1/a)*(np.exp(a)-1)*(1/(s*(np.exp(a)-1)+1))

def gamma(s,a):
    if np.abs(a)<1e-15:
        return s
    else:
        return (np.exp(a*s) - 1)/(np.exp(a) - 1)

def gamma_prime(s,a):
    if np.abs(a)<1e-15:
        return 1 + s*0
    else:
        return a/(np.exp(a) - 1) * np.exp(a*s)

def h(s,a):
    if np.abs(a)<1e-15:
        return s
    else:
        return (np.sin(2*np.pi*s) + s/a)*a

def h_prime(s,a):
    if np.abs(a)<1e-15:
        return 1 + s*0
    else:
        return (2*np.pi*np.cos(2*np.pi*s) + 1/a)*a
