B
    [=                 @   s   d Z ddlmZ ddddddd	d
gZddlmZmZmZmZm	Z	m
Z
mZmZ ddlmZ ddlmZ ddlmZ ddlmZ ddlmZ dddZdddZdd Zdd ZdddZdddZdd	 Zdd
 ZdS )z
**Contains**

* refraction_angle
* deviation
* brewster_angle
* lens_makers_formula
* mirror_formula
* lens_formula
* hyperfocal_distance
* transverse_magnification
    )divisionrefraction_angle	deviationbrewster_anglelens_makers_formulamirror_formulalens_formulahyperfocal_distancetransverse_magnification)SymbolsympifysqrtMatrixacosooLimitatan2)is_sequence)Ray3D)intersection)Plane   )MediumNc             C   s  d}|dk	r|dk	rt dt| tsXt| r8t| }q\t| trNt| j}q\tdn| }|dk	rt|tsvtdt| trd}|| d }t|j	}n|t|tst|rt|}nXt|trt|j}t| trt| |}t
|dkrt dnd}|d }ntd	n|}d
\}	}
t|tr6|j}	nt|}	t|trR|j}
nt|}
|	|
 }ttdd |D }ttdd |D }|| }|| }|| }d|d d|d    }|jrdS || || t| |  }|| }|s|S t||dS dS )a1  
    This function calculates transmitted vector after refraction at planar
    surface. `medium1` and `medium2` can be `Medium` or any sympifiable object.

    If `incident` is an object of `Ray3D`, `normal` also has to be an instance
    of `Ray3D` in order to get the output as a `Ray3D`. Please note that if
    plane of separation is not provided and normal is an instance of `Ray3D`,
    normal will be assumed to be intersecting incident ray at the plane of
    separation. This will not be the case when `normal` is a `Matrix` or
    any other sequence.
    If `incident` is an instance of `Ray3D` and `plane` has not been provided
    and `normal` is not `Ray3D`, output will be a `Matrix`.

    Parameters
    ==========

    incident : Matrix, Ray3D, or sequence
        Incident vector
    medium1 : sympy.physics.optics.medium.Medium or sympifiable
        Medium 1 or its refractive index
    medium2 : sympy.physics.optics.medium.Medium or sympifiable
        Medium 2 or its refractive index
    normal : Matrix, Ray3D, or sequence
        Normal vector
    plane : Plane
        Plane of separation of the two media.

    Examples
    ========

    >>> from sympy.physics.optics import refraction_angle
    >>> from sympy.geometry import Point3D, Ray3D, Plane
    >>> from sympy.matrices import Matrix
    >>> from sympy import symbols
    >>> n = Matrix([0, 0, 1])
    >>> P = Plane(Point3D(0, 0, 0), normal_vector=[0, 0, 1])
    >>> r1 = Ray3D(Point3D(-1, -1, 1), Point3D(0, 0, 0))
    >>> refraction_angle(r1, 1, 1, n)
    Matrix([
    [ 1],
    [ 1],
    [-1]])
    >>> refraction_angle(r1, 1, 1, plane=P)
    Ray3D(Point3D(0, 0, 0), Point3D(1, 1, -1))

    With different index of refraction of the two media

    >>> n1, n2 = symbols('n1, n2')
    >>> refraction_angle(r1, n1, n2, n)
    Matrix([
    [                                n1/n2],
    [                                n1/n2],
    [-sqrt(3)*sqrt(-2*n1**2/(3*n2**2) + 1)]])
    >>> refraction_angle(r1, n1, n2, plane=P)
    Ray3D(Point3D(0, 0, 0), Point3D(n1/n2, n1/n2, -sqrt(3)*sqrt(-2*n1**2/(3*n2**2) + 1)))

    FNz%Either plane or normal is acceptable.z/incident should be a Matrix, Ray3D, or sequencez3plane should be an instance of geometry.plane.PlaneTr   z.Normal isn't concurrent with the incident ray.z-Normal should be a Matrix, Ray3D, or sequence)NNc             S   s   g | ]}|d  qS )    ).0ir   r   9lib/python3.7/site-packages/sympy/physics/optics/utils.py
<listcomp>   s    z$refraction_angle.<locals>.<listcomp>c             S   s   g | ]}|d  qS )r   r   )r   r   r   r   r   r      s    r   r   )direction_ratio)
ValueError
isinstancer   r   r   r   	TypeErrorr   r   normal_vectorlenr   refractive_indexr   r   sumdotZis_negative)incidentmedium1medium2normalplaneZ
return_ray	_incidentZintersection_pt_normaln1n2Zetamag_incident
mag_normalZc1Zcs2Zdrsr   r   r   r   "   sl    ;








c             C   sF  t | ||||d}|dkrBt|tr0t|j}t| tslt| rLt| }qpt| trbt| j}qptdn| }|dkrt|tst|rt|}qt|trt|j}qtdq|}n
t|j}tt	dd |D }tt	dd |D }	tt	d	d |D }
|| }||	 }||
 }t
||}t
||}|| S dS )
a1  
    This function calculates the angle of deviation of a ray
    due to refraction at planar surface.

    Parameters
    ==========

    incident : Matrix, Ray3D, or sequence
        Incident vector
    medium1 : sympy.physics.optics.medium.Medium or sympifiable
        Medium 1 or its refractive index
    medium2 : sympy.physics.optics.medium.Medium or sympifiable
        Medium 2 or its refractive index
    normal : Matrix, Ray3D, or sequence
        Normal vector
    plane : Plane
        Plane of separation of the two media.

    Examples
    ========

    >>> from sympy.physics.optics import deviation
    >>> from sympy.geometry import Point3D, Ray3D, Plane
    >>> from sympy.matrices import Matrix
    >>> from sympy import symbols
    >>> n1, n2 = symbols('n1, n2')
    >>> n = Matrix([0, 0, 1])
    >>> P = Plane(Point3D(0, 0, 0), normal_vector=[0, 0, 1])
    >>> r1 = Ray3D(Point3D(-1, -1, 1), Point3D(0, 0, 0))
    >>> deviation(r1, 1, 1, n)
    0
    >>> deviation(r1, n1, n2, plane=P)
    -acos(-sqrt(-2*n1**2/(3*n2**2) + 1)) + acos(-sqrt(3)/3)

    )r+   r,   r   z/incident should be a Matrix, Ray3D, or sequenceNz-normal should be a Matrix, Ray3D, or sequencec             S   s   g | ]}|d  qS )r   r   )r   r   r   r   r   r      s    zdeviation.<locals>.<listcomp>c             S   s   g | ]}|d  qS )r   r   )r   r   r   r   r   r      s    c             S   s   g | ]}|d  qS )r   r   )r   r   r   r   r   r      s    )r   r!   r   r   r   r   r"   r#   r   r&   r   r'   )r(   r)   r*   r+   r,   Z	refractedr-   r.   r1   r2   Zmag_refractedr   rr   r   r   r      sF    $









c             C   sF   d\}}t | tr| j}nt| }t |tr4|j}nt|}t||S )a  
    This function calculates the Brewster's angle of incidence to Medium 2 from
    Medium 1 in radians.

    Parameters
    ==========

    medium 1 : Medium or sympifiable
        Refractive index of Medium 1
    medium 2 : Medium or sympifiable
        Refractive index of Medium 1

    Examples
    ========

    >>> from sympy.physics.optics import brewster_angle
    >>> brewster_angle(1, 1.33)
    0.926093295503462

    )NN)r!   r   r%   r   r   )r)   r*   r/   r0   r   r   r   r      s    

c             C   sd   t | tr| j} nt| } t |tr,|j}nt|}t|}t|}d| | | d| d|    S )aD  
    This function calculates focal length of a thin lens.
    It follows cartesian sign convention.

    Parameters
    ==========

    n_lens : Medium or sympifiable
        Index of refraction of lens.
    n_surr : Medium or sympifiable
        Index of reflection of surrounding.
    r1 : sympifiable
        Radius of curvature of first surface.
    r2 : sympifiable
        Radius of curvature of second surface.

    Examples
    ========

    >>> from sympy.physics.optics import lens_makers_formula
    >>> lens_makers_formula(1.33, 1, 10, -10)
    15.1515151515151

    r   )r!   r   r%   r   )Zn_lensZn_surrZr1Zr2r   r   r   r   #  s    

c             C   s0  | r|r|rt dt| } t|}t|}|tkr<td}|tkrLtd}| tkr\td}| dkr|tkr|tkrtt|| ||  |t|t S |tkrt|| ||  |t S |tkrt|| ||  |t S || ||  S |dkr|tkr2| tkr2tt|| ||  |t|t S |tkrXt||  ||   |t S | tkr~t|| ||  |t S ||  ||   S |dkr,|tkr| tkrtt|| ||  |t|t S |tkrt||  ||   |t S | tkrt|| ||  |t S ||  ||   S dS )a  
    This function provides one of the three parameters
    when two of them are supplied.
    This is valid only for paraxial rays.

    Parameters
    ==========

    focal_length : sympifiable
        Focal length of the mirror.
    u : sympifiable
        Distance of object from the pole on
        the principal axis.
    v : sympifiable
        Distance of the image from the pole
        on the principal axis.

    Examples
    ========

    >>> from sympy.physics.optics import mirror_formula
    >>> from sympy.abc import f, u, v
    >>> mirror_formula(focal_length=f, u=u)
    f*u/(-f + u)
    >>> mirror_formula(focal_length=f, v=v)
    f*v/(-f + v)
    >>> mirror_formula(u=u, v=v)
    u*v/(u + v)

    z"Please provide only two parametersuvfN)r    r   r   r   r   doit)focal_lengthr4   r5   _u_v_fr   r   r   r   K  sF    $
$


$

c             C   s0  | r|r|rt dt| } t|}t|}|tkr<td}|tkrLtd}| tkr\td}| dkr|tkr|tkrtt|| ||  |t|t S |tkrt|| ||  |t S |tkrt|| ||  |t S || ||  S |dkr|tkr2| tkr2tt|| ||  |t|t S |tkrXt||  | |  |t S | tkr~t|| ||  |t S ||  | |  S |dkr,|tkr| tkrtt|| ||  |t|t S |tkrt||  ||   |t S | tkrt|| ||  |t S ||  ||   S dS )a  
    This function provides one of the three parameters
    when two of them are supplied.
    This is valid only for paraxial rays.

    Parameters
    ==========

    focal_length : sympifiable
        Focal length of the mirror.
    u : sympifiable
        Distance of object from the optical center on
        the principal axis.
    v : sympifiable
        Distance of the image from the optical center
        on the principal axis.

    Examples
    ========

    >>> from sympy.physics.optics import lens_formula
    >>> from sympy.abc import f, u, v
    >>> lens_formula(focal_length=f, u=u)
    f*u/(f + u)
    >>> lens_formula(focal_length=f, v=v)
    f*v/(f - v)
    >>> lens_formula(u=u, v=v)
    u*v/(u - v)

    z"Please provide only two parametersr4   r5   r6   N)r    r   r   r   r   r7   )r8   r4   r5   r9   r:   r;   r   r   r   r     sF    $
$


$

c             C   s,   t | } t |}t |}d||  | d  S )a  

    Parameters
    ==========
    f: sympifiable
    Focal length of a given lens

    N: sympifiable
    F-number of a given lens

    c: sympifiable
    Circle of Confusion (CoC) of a given image format

    Example
    =======
    >>> from sympy.physics.optics import hyperfocal_distance
    >>> from sympy.abc import f, N, c
    >>> round(hyperfocal_distance(f = 0.5, N = 8, c = 0.0033), 2)
    9.47
    r   r   )r   )r6   Ncr   r   r   r	     s    c             C   s   t | } t |}| |  S )au  

    Calculates the transverse magnification, which is the ratio of the
    image size to the object size.

    Parameters
    ==========
    so: sympifiable
    Lens-object distance

    si: sympifiable
    Lens-image distance

    Example
    =======
    >>> from sympy.physics.optics import transverse_magnification
    >>> transverse_magnification(30, 15)
    -2

    )r   )ZsiZsor   r   r   r
     s    )NN)NN)NNN)NNN)__doc__Z
__future__r   __all__Zsympyr   r   r   r   r   r   r   r   Zsympy.core.compatibilityr   Zsympy.geometry.liner   Zsympy.geometry.utilr   Zsympy.geometry.planer   Zmediumr   r   r   r   r   r   r   r	   r
   r   r   r   r   <module>   s0   (
 
Q$(
E
D