"""
    Utitlity functions for vector(x,y,z)
    ----------------------------------------------------------

    file under vectogebra - python module for vector algebra

    ----------------------------------------------------------

    vectogebra/src/utilities.py

    -------------------------
    This module contains the utility operations for vasious calculation related to vectors.
    
    requires: vectogebra/src/vector.py to be imported
    
    depends on: 
    1. vectogebra/src/vector.py
    2. math module 
    -------------------------------------------------
    copyright: (C) 2022 Mohammad Maasir
    license: MIT License (see LICENSE in project's main directory)
    -------------------------------------------------
    date created: 9th of May, 2022 (3:09 AM)
    last modified: 9th of May, 2022
    -------------------------------------------------

    contributor(s): Mohammad Maasir

    -------------------------------------------------

    github: github.com/maasir554/vectogebra/vectogrbra/utilities.py

    ----------------------------------------------------------------

    report an issue : https://github.com/maasir554/vectogebra/issues
    
    ---------------------------------------------------------------------
    
    email: maasir554@gmail.com

    ---------------------------------------------------------------------

    

"""
#importing math for trigonometric and inverse trigonometric functions :-

import math
#importing vector class from vector.py

import src.vectogebra.vector as v

#NOTE: the type of vector will also be reffered as alias i.e. in this case, v only.
#example: a = v(1,2,3)
# print(type(a) == v) => This will return True. NOTE: do NOT use "v" or 'v' or vector.v , just use alias as it is i.e.: v
#if we would have taken alias as vect then we would refer to it as vect only. and not "vect" or 'vect' or vector.vect
#if we did not had used alias, then we would refer to it as vector.vector
# Please don't get confused when working outside this module. there will be different conventions.

##########################################################

############# _____  ANGLE RELATED _____ ##################

##########################################################

#for angle between two vectors options : "radians"(default) or "degrees" 
def angle(v1,v2,format="radians"):
    if format == "radians":
        return(math.acos((v1*v2)/(v1.magnitude*v2.magnitude)))
    elif format == "degrees":
        return(math.degrees(math.acos((v1*v2)/(v1.magnitude*v2.magnitude))))

#function to check if the tow vectors are perpendicular or not
def is_perpendicular(v1,v2):   
    if angle(v1,v2,'degrees') == 90.0:
        return(True)
    else:
        return(False)
    
#function to check if the tow vectors are parallel or not
def is_parallel(v1,v2):
    if angle(v1,v2,'degrees') == 0.0:
        return(True)
    else:
        return(False)

#function to obtain unit vector from a given vector
def unit_vector(v):
    return(v/v.magnitude)
def direction(v):
    return(v/v.magnitude)

###########################################################

################_________ ALGEBRA _______###################

###########################################################

# addition of n vectors
def add(*args):
    v0 = v(0,0,0) 
    for i in args:
        if type(i)==v:
            v0 = v0+i
        else:
            raise TypeError("Arguments must be vectors")
    return(v0)
# function for dot product
def dot(v1,v2):
    return(v1*v2)

#function for cross product
def cross(v1,v2):
    return(v1^v2)

#magnitude of a vector or a number
def magnitude(v):
    if type(v)==v:
        return(v.magnitude)
    elif type(v)==int or type(v)==float:
        return((v**2)**0.5)
    else:
        raise TypeError("Argument must be a vector or a number")



###########################################################

################_________ GEOMETRY _______##################

###########################################################

# function to find area of parallelogram formed by two vectors
def parallelogram_area(a,b):
    return(a.magnitude*b.magnitude*math.sin(angle(a,b,'radians')))

# function to find volume of parallelopiped formed by three vectors or box product
def box(a,b,c):
    return(a*(b^c))

#function to check if three vectors are coplanar
def coplanar(a,b,c):
    if box(a,b,c)==0:
        return(True)
    else:
        return(False)

# scalar component of vector a along the direction of vector b or opposite to direction of vector b(if the angle is obtuse)
def scalar_component_collinear(a,b):
    if type(a)==v and type(b)==v:
        return(a*unit_vector(b))
    else:
        raise TypeError("Arguments must be vectors")
# vector component of vector a along the direction of vector b or opposite to direction of vector b(if the angle is obtuse)
def vector_component_collinear(a,b):
    return(a*unit_vector(b)*unit_vector(b))

#scalar component perpendicular to direction of vector b
def scalar_component_perpendicular(a,b):
    return((a^b)/b.magnitude)
#vector component perpendicular to direction of vector b
def vector_component_perpendicular(a,b):
    return(scalar_component_perpendicular(a,b)*unit_vector(b^(a^b))) # Thumb rule logics***


###########################################################

#############________ EXPORT A VECTOR _______##############

###########################################################


# dictionary from a vector 
def vector_to_dict(v):
    return({'x':v.x,'y':v.y,'z':v.z})

# list from a vector (it will contain its coordinates/components)
def vector_to_list(v): 
    return([v.x,v.y,v.z])    #returning a list of coordinates/components arranged in order of x,y,z

# tuple from a vector (it will contain its coordinates/components)
def vector_to_tuple(v):
    return((v.x,v.y,v.z))


###########################################################

############# CREATION OF VECTOR  #########################

###########################################################

# vector from a dictionary
def dict_to_vector(d):
    if type(d)==dict:
        return(v(d['x'],d['y'],d['z']))
    else:
        raise TypeError("Argument must be a dictionary")

# vector from a list
def list_to_vector(l):
    if type(l)==list:
        return(v(l[0],l[1],l[2]))
    else:
        raise TypeError("Argument must be a list")

# vector from a tuple
def tuple_to_vector(t):
    if type(t)==tuple:
        return(v(t[0],t[1],t[2]))
    else:
        raise TypeError("Argument must be a tuple")
 
 # 2d vector from polar coordinates
def polar_to_vector(r,theta):
    return(v(r*math.cos(theta),r*math.sin(theta),0))


