U
    Pe)9                     @   s~   d Z dZddlZddlZddlZddlZddlmZ ddlm	Z	 G dd de
ZG dd	 d	ZG d
d dZG dd dZdS )a  
Gesture recognition
===================

This class allows you to easily create new
gestures and compare them::

    from kivy.gesture import Gesture, GestureDatabase

    # Create a gesture
    g = Gesture()
    g.add_stroke(point_list=[(1,1), (3,4), (2,1)])
    g.normalize()

    # Add it to the database
    gdb = GestureDatabase()
    gdb.add_gesture(g)

    # And for the next gesture, try to find it!
    g2 = Gesture()
    # ...
    gdb.find(g2)

.. warning::

   You don't really want to do this: it's more of an example of how
   to construct gestures dynamically. Typically, you would
   need a lot more points, so it's better to record gestures in a file and
   reload them to compare later. Look in the examples/gestures directory for
   an example of how to do that.

)GestureGestureDatabaseGesturePointGestureStroke    N)Vector)BytesIOc                   @   s:   e Zd ZdZdd Zdd Zddd	Zd
d Zdd ZdS )r   z#Class to handle a gesture database.c                 C   s
   g | _ d S N)dbself r   0/tmp/pip-unpacked-wheel-xzebddm3/kivy/gesture.py__init__1   s    zGestureDatabase.__init__c                 C   s   | j | dS )z"Add a new gesture to the database.N)r	   append)r   gesturer   r   r   add_gesture4   s    zGestureDatabase.add_gesture?Tc                 C   sJ   |sdS d}|}| j D ]"}|||}||k r0q|}|}q|sBdS ||fS )z(Find a matching gesture in the database.N)r	   	get_score)r   r   Zminscorerotation_invariantbestZ	bestscoregscorer   r   r   find8   s    
zGestureDatabase.findc                 C   s4   t  }t|}|| tt| d}|S )z'Convert a gesture into a unique string.	   )	r   picklePicklerdumpbase64	b64encodezlibcompressgetvalue)r   r   iopdatar   r   r   gesture_to_strI   s
    

zGestureDatabase.gesture_to_strc                 C   s*   t tt|}t|}| }|S )z%Convert a unique string to a gesture.)r   r   
decompressr   	b64decoder   	Unpicklerload)r   r$   r"   r#   r   r   r   r   str_to_gestureQ   s    
zGestureDatabase.str_to_gestureN)r   T)	__name__
__module____qualname____doc__r   r   r   r%   r*   r   r   r   r   r   .   s   
r   c                   @   s$   e Zd Zdd Zdd Zdd ZdS )r   c                 C   s   t || _t || _dS )z5Stores the x,y coordinates of a point in the gesture.N)floatxyr   r0   r1   r   r   r   r   [   s    
zGesturePoint.__init__c                 C   s    |  j |9  _ |  j|9  _| S )z& Scales the point by the given factor.r0   r1   )r   Zfactorr   r   r   scale`   s    zGesturePoint.scalec                 C   s   d| j | jf S )NzMouse_point: %f,%fr3   r
   r   r   r   __repr__f   s    zGesturePoint.__repr__N)r+   r,   r-   r   r4   r5   r   r   r   r   r   Y   s   r   c                   @   s|   e Zd ZdZdd Zedd Zedd Zedd	 Zed
d Z	dd Z
dd Zdd ZdddZdddZdd ZdS )r   z- Gestures can be made up of multiple strokes.c                 C   s   t  | _t  | _dS )z A stroke in the gesture.N)listpointsscreenpointsr
   r   r   r   r   m   s    zGestureStroke.__init__c                 C   s&   t | jdkrdS t| jdd djS )Nr   c                 S   s   | j S r   r0   ptr   r   r   <lambda>w       z%GestureStroke.max_x.<locals>.<lambda>key)lenr7   maxr0   r
   r   r   r   max_xs   s    zGestureStroke.max_xc                 C   s&   t | jdkrdS t| jdd djS )Nr   c                 S   s   | j S r   r9   r:   r   r   r   r<   }   r=   z%GestureStroke.min_x.<locals>.<lambda>r>   )r@   r7   minr0   r
   r   r   r   min_xy   s    zGestureStroke.min_xc                 C   s&   t | jdkrdS t| jdd djS )Nr   c                 S   s   | j S r   r1   r:   r   r   r   r<      r=   z%GestureStroke.max_y.<locals>.<lambda>r>   )r@   r7   rA   r1   r
   r   r   r   max_y   s    zGestureStroke.max_yc                 C   s&   t | jdkrdS t| jdd djS )Nr   c                 S   s   | j S r   rE   r:   r   r   r   r<      r=   z%GestureStroke.min_y.<locals>.<lambda>r>   )r@   r7   rC   r1   r
   r   r   r   min_y   s    zGestureStroke.min_yc                 C   s&   | j t|| | j||f dS )zQ
        add_point(x=x_pos, y=y_pos)
        Adds a point to the stroke.
        N)r7   r   r   r8   r2   r   r   r   	add_point   s    zGestureStroke.add_pointc                    s    fdd| j D | _ dS )zb
        scale_stroke(scale_factor=float)
        Scales the stroke down by scale_factor.
        c                    s   g | ]}|  qS r   )r4   .0r;   scale_factorr   r   
<listcomp>   s     z.GestureStroke.scale_stroke.<locals>.<listcomp>N)r7   )r   rL   r   rK   r   scale_stroke   s    zGestureStroke.scale_strokec                 C   s.   |j |j  }|j|j }t|| ||  S )z
        points_distance(point1=GesturePoint, point2=GesturePoint)
        Returns the distance between two GesturePoints.
        )r0   r1   mathsqrt)r   Zpoint1Zpoint2r0   r1   r   r   r   points_distance   s    zGestureStroke.points_distanceNc                 C   sX   |dkr| j }d}t|dkr"|S tt|d D ] }|| || ||d  7 }q2|S )zlFinds the length of the stroke. If a point list is given,
           finds the length of that list.
        N           )r7   r@   rangerQ   )r   
point_listZgesture_lengthir   r   r   stroke_length   s     
zGestureStroke.stroke_length    c                 C   s4  t | jdks| | jdkr"dS | | jt| }t }|| jd  | jd }d}|}| jdd D ]}| ||}|dkrl|}|| }||k rl|j|j }	|j|j }
|| | }|	| |j }|
| |j }|t	|| | | jt| t | }qqlt ||ks*t
dt ||f || _dS )zNormalizes strokes so that every stroke has a standard number of
           points. Returns True if stroke is normalized, False if it can't be
           normalized. sample_points controls the resolution of the stroke.
        rS   rR   Fr   Nz>Invalid number of strokes points; got %d while it should be %dT)r@   r7   rW   r/   r6   r   rQ   r0   r1   r   
ValueError)r   Zsample_pointsZtarget_stroke_sizeZ
new_pointsprevZsrc_distanceZdst_distancecurrdZx_dirZy_dirZratioZto_xZto_yr   r   r   normalize_stroke   s@    


zGestureStroke.normalize_strokec                 C   s,   | j D ] }| j|8  _| j|8  _qdS )z,Centers the stroke by offsetting the points.N)r7   r0   r1   )r   Zoffset_xZoffset_ypointr   r   r   center_stroke   s    
zGestureStroke.center_stroke)N)rX   )r+   r,   r-   r.   r   propertyrB   rD   rF   rG   rH   rN   rQ   rW   r]   r_   r   r   r   r   r   j   s    



	

.r   c                   @   s   e Zd ZdZ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d Zd'ddZdd Zdd Zdd Zdd Zd d! Zd"d# ZdS )(r   zA python implementation of a gesture recognition algorithm by
    Oleg Dopertchouk: http://www.gamedev.net/reference/articles/article2039.asp

    Implemented by Jeiel Aranal (chemikhazi@gmail.com),
    released into the public domain.
    g?Nc                 C   s6   d| _ d| _d| _t | _|dkr,tj| _n|| _dS )zu
        Gesture([tolerance=float])
        Creates a new gesture with an optional matching tolerance value.
        rR   N)widthheightgesture_productr6   strokesr   DEFAULT_TOLERANCE	tolerance)r   rf   r   r   r   r      s    
zGesture.__init__c           	      C   s   t dd | jD }tdd | jD }t dd | jD }tdd | jD }|| }|| _|| }|| _t||}|dkrdS d| }| jD ]}|| qd	S )
z( Scales down the gesture to a unit of 1.c                 S   s   g | ]
}|j qS r   )rD   rJ   stroker   r   r   rM     s     z*Gesture._scale_gesture.<locals>.<listcomp>c                 S   s   g | ]
}|j qS r   )rB   rg   r   r   r   rM     s     c                 S   s   g | ]
}|j qS r   )rG   rg   r   r   r   rM     s     c                 S   s   g | ]
}|j qS r   )rF   rg   r   r   r   rM     s     rR   F      ?T)rC   rd   rA   ra   rb   rN   )	r   rD   rB   rG   rF   Zx_lenZy_lenrL   rh   r   r   r   _scale_gesture   s    

zGesture._scale_gesturec                 C   s   d}d}d}| j D ]J}tdd |jD }tdd |jD }||7 }||7 }|t|j7 }q|dkrjdS || }|| }| j D ]}||| qdS )z+ Centers the Gesture.points of the gesture.rR   r   c                 S   s   g | ]
}|j qS r   rE   rI   r   r   r   rM     s     z+Gesture._center_gesture.<locals>.<listcomp>c                 S   s   g | ]
}|j qS r   r9   rI   r   r   r   rM     s     FT)rd   sumr7   r@   r_   )r   Ztotal_xZtotal_yZtotal_pointsrh   Zstroke_yZstroke_xr   r   r   _center_gesture  s     

zGesture._center_gesturec                 C   s   | j t  t|ts"t|tr|D ]n}t|trH| j d j| q&t|ts\t|trt|dkrpt	d| j d 
|d |d  q&tdq&n|dk	rt	d| j d S )	zAdds a stroke to the gesture and returns the Stroke instance.
           Optional point_list argument is a list of the mouse points for
           the stroke.
           z#Stroke entry must have 2 values maxr   rS   zSThe point list should either be tuples of x and y or a list of GesturePoint objectsNz!point_list should be a tuple/list)rd   r   r   
isinstancer6   tupler   r7   r@   rY   rH   	TypeError)r   rU   r^   r   r   r   
add_stroke*  s    
zGesture.add_strokerX   c                 C   s@   |   r|  sd| _dS | jD ]}|| q | | | _dS )zcRuns the gesture normalization algorithm and calculates the dot
        product with self.
        FN)rj   rl   rc   rd   r]   dot_product)r   Zstroke_samplesrh   r   r   r   	normalize@  s    
zGesture.normalizec                 C   s   t | jdk s"t | jd jdk r&dS t |jdk sHt |jd jdk rLdS |jd jd }t|j|jg}t|j|jg}||S )a"  
        Extract the rotation to apply to a group of points to minimize the
        distance to a second group of points. The two groups of points are
        assumed to be centered. This is a simple version that just picks
        an angle based on the first point of the gesture.
        rS   r   )r@   rd   r7   r   r0   r1   angle)r   Zdstptsr#   targetsourcer   r   r   get_rigid_rotationK  s    ""zGesture.get_rigid_rotationc           	      C   s   t |jt | jkrdS t|dddks8t| dddkr<dS d}ttt| j|jD ]L\}\}}ttt|j|jD ](\}\}}||j|j |j|j  7 }qxqV|S )z@ Calculates the dot product of the gesture with another gesture.rm   rc   TFrR   )	r@   rd   getattr	enumerater6   zipr7   r0   r1   )	r   comparison_gesturers   Zstroke_indexZ	my_strokeZ
cmp_strokeZpt_indexZmy_pointZ	cmp_pointr   r   r   rs   [  s"    

zGesture.dot_productc                 C   s\   t  }| jD ]>}g }|jD ]$}t|j|jg|}|| q|| q|	||_
|S r   )r   rd   r7   r   r0   r1   rotater   rr   rs   rc   )r   ru   r   rh   tmpjvr   r   r   r}   k  s    

zGesture.rotateTc                 C   sV   t |trR|r"| |}||}| |}|dkr8|S |t| j|j  }|S dS )zL Returns the matching score of the gesture against another gesture.
        r   N)ro   r   rx   r}   rs   rO   rP   rc   )r   r|   r   ru   r   r   r   r   r   v  s    




zGesture.get_scorec                 C   sB   t |tr:| |}|d| j kr4|d| j k r4dS dS ntS dS )z3 Allows easy comparisons between gesture instances.ri   TFN)ro   r   r   rf   NotImplemented)r   r|   r   r   r   r   __eq__  s    

zGesture.__eq__c                 C   s    |  |}|tkr|S | S d S r   )r   r   )r   r|   resultr   r   r   __ne__  s    
zGesture.__ne__c                 C   s   t dd S )Nz"Gesture cannot be evaluated with <rq   r   r|   r   r   r   __lt__  s    zGesture.__lt__c                 C   s   t dd S )Nz"Gesture cannot be evaluated with >r   r   r   r   r   __gt__  s    zGesture.__gt__c                 C   s   t dd S )Nz#Gesture cannot be evaluated with <=r   r   r   r   r   __le__  s    zGesture.__le__c                 C   s   t dd S )Nz#Gesture cannot be evaluated with >=r   r   r   r   r   __ge__  s    zGesture.__ge__)N)N)rX   )T)r+   r,   r-   r.   re   r   rj   rl   rr   rt   rx   rs   r}   r   r   r   r   r   r   r   r   r   r   r   r      s"   



r   )r.   __all__r   r   r   rO   Zkivy.vectorr   r"   r   objectr   r   r   r   r   r   r   r   <module>   s   !+|