U
    i2e=R                     @   s
  d Z ddl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lZddlZddlZd	d
 ZG dd deZG dd deZG dd deZdd Zdd Zdd Zdd Zdd Zd!ddZd"ddZed krddlZe Zeee e dS )#z
Tool to find wrong contour order between different masters, and
other interpolatability (or lack thereof) issues.

Call as:
$ fonttools varLib.interpolatable font1 font2 ...
    )AbstractPenBasePen)SegmentToPointPen)RecordingPen)StatisticsPen)OpenContourError)OrderedDictNc                 C   s8   t | }||; }|s| S | || d | d||   S )z{Rotate list by k items forward.  Ie. item at position 0 will be
    at position k in returned list.  Negative k is allowed.Nlen)lkn r   C/tmp/pip-unpacked-wheel-txsm8jh_/fontTools/varLib/interpolatable.py	_rot_list   s
    r   c                   @   sN   e Z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d Z
dS )PerContourPenNc                 C   s(   t | | || _|| _d | _g | _d S N)r   __init__Z	_glyphset_Pen_penvalue)selfZPenglyphsetr   r   r   r      s
    zPerContourPen.__init__c                 C   s   |    | j| d S r   )_newItemr   moveTo)r   Zp0r   r   r   _moveTo&   s    zPerContourPen._moveToc                 C   s   | j | d S r   )r   ZlineTo)r   p1r   r   r   _lineTo*   s    zPerContourPen._lineToc                 C   s   | j || d S r   )r   ZqCurveTo)r   r   p2r   r   r   _qCurveToOne-   s    zPerContourPen._qCurveToOnec                 C   s   | j ||| d S r   )r   ZcurveTo)r   r   r   Zp3r   r   r   _curveToOne0   s    zPerContourPen._curveToOnec                 C   s   | j   d | _ d S r   )r   	closePathr   r   r   r   
_closePath3   s    
zPerContourPen._closePathc                 C   s   | j   d | _ d S r   )r   endPathr"   r   r   r   _endPath7   s    
zPerContourPen._endPathc                 C   s   |    | _}| j| d S r   )r   r   r   append)r   Zpenr   r   r   r   ;   s    zPerContourPen._newItem)N)__name__
__module____qualname__r   r   r   r   r    r#   r%   r   r   r   r   r   r      s   
r   c                   @   s   e Zd Zdd ZdS )PerContourOrComponentPenc                 C   s   |    | jd || d S )N)r   r   addComponent)r   Z	glyphNameZtransformationr   r   r   r,   A   s    z%PerContourOrComponentPen.addComponentN)r'   r(   r)   r,   r   r   r   r   r*   @   s   r*   c                   @   s6   e Zd Zdd ZdddZddddZdd	d
ZdS )RecordingPointPenc                 C   s
   g | _ d S r   )r   r"   r   r   r   r   G   s    zRecordingPointPen.__init__Nc                 K   s   d S r   r   )r   
identifierkwargsr   r   r   	beginPathJ   s    zRecordingPointPen.beginPath)returnc                 C   s   d S r   r   r"   r   r   r   r$   M   s    zRecordingPointPen.endPathc                 C   s    | j ||d krdndf d S )NFT)r   r&   )r   ptZsegmentTyper   r   r   addPointP   s    zRecordingPointPen.addPoint)N)N)r'   r(   r)   r   r0   r$   r3   r   r   r   r   r-   F   s   
r-   c                 C   s   t dd t| |D S )Nc                 s   s   | ]\}}|| V  qd S r   r   ).0abr   r   r   	<genexpr>U   s     z_vdiff.<locals>.<genexpr>)tuplezip)v0v1r   r   r   _vdiffT   s    r<   c                 C   s   d}| D ]}||| 7 }q|S Nr   r   Zvecvxr   r   r   _vlenX   s    rA   c                 C   s&   d}| D ]}|t |t | 7 }q|S r=   )absr>   r   r   r   _complex_vlen_   s    rC   c                    s   t  fddt|D S )Nc                 3   s   | ]\}} | | V  qd S r   r   )r4   ijGr   r   r7   g   s     z!_matching_cost.<locals>.<genexpr>)sum	enumerate)rG   matchingr   rF   r   _matching_costf   s    rK   c                 C   s"  t | }zDddlm} || \}}|tt|k s:tt|t| |fW S  tk
r`   Y nX zDddl	m
} d g| }| | D ]\}}|||< q|t| |fW S  tk
r   Y nX |dkrtdtt|}tt|}	t| |	}
|D ]$}t| |}||
k rt|| }	}
q|	|
fS )Nr   )linear_sum_assignment)Munkres   z4Install Python module 'munkres' or 'scipy >= 0.17.0')r
   Zscipy.optimizerL   listrangeallAssertionErrorrK   ImportErrorZmunkresrM   Zcompute	Exception	itertoolspermutationsnext)rG   r   rL   ZrowscolsrM   rowcolrV   bestZ	best_costpZcostr   r   r   #min_cost_perfect_bipartite_matchingj   s4    



r]   Fc           4         s  |d kr| }|d kr"dd | D }g }t  fdd}|D ]}zd}g }g }	g }
t| |D ]\}}|| }|d kr|s||d|d |	d  |d  |
d  q`tt|d}z|j|d	d
 W n tk
r   || Y nX |j}~g }g }g }|	| || |
| t|D ]<\}}t	dd |jD }|| t
|d}z|| W n@ tk
r } z ||||dd W Y q&W 5 d }~X Y nX tt|jd }t|t|jt|jt|jd t|jd t|j| f}|| |d dkrq&|d dks(t|d dks:tt }t|d}|| d}|jD ]\}}|d> |B }q^t|j}d|> d } g }!||! t|D ]D}"||"> | @ |||" ? B }||kr|!tdd |jD |" qtt|j}#d}$|#D ]\}}|$d> |B }$qt|D ]B}"|$|"> | @ |$||" ? B }||kr|!tdd |#D |" qq&q`|	t dd |	D d }|	| }%t|	|d d  D ].\}"d krqt|%tkr||d|| |||" d  t|%td |%krqtt|%D ]\}&\}'}(|'|(kr,qt|'t|(krr||d|&|| |||" d  t|'t|(d qtt|'|(D ]F\})\}*}+|*|+kr||d|&|)|| |||" d  |*|+d  qqqq|t d!d |D d }|| }%t||d d  D ]\}"d krqt|%tkr2q|%s<qfd"d|%D t!\},}-ttt|%}.t"fd#dtt|%D }/|,|.kr|-|/d$ k r||d%|| |||" d  ttt|%|,d  qܐq|
t d&d |
D d }|
| }%t|
|d d  D ]\}"d kr(qt|%tkr>q|%sHqtt|%D ]t\}\}0}1|0d  d'd  fd(d|1D D t#}2d }3|2|3d$ k rV||d)||| |||" d  d* qVqW q< t$k
r } z||d+||d, W 5 d }~X Y q<X q<S )-Nc                 S   s   h | ]}|  D ]}|qqS r   keys)r4   r   gr   r   r   	<setcomp>   s     
  ztest.<locals>.<setcomp>c                    s     | g | d S r   )
setdefaultr&   )Z	glyphnameZproblem)problemsr   r   add_problem   s    ztest.<locals>.add_problemr   missing)typemasterr   T)ZoutputImpliedClosingLinec                 s   s   | ]}|d  V  qdS )r   Nr   )r4   Zinstructionr   r   r   r7      s     ztest.<locals>.<genexpr>	open_path)rg   contourrf   g      ?   r,   r   r+   )r!   r$   F   c                 S   s   g | ]\}}t | qS r   complexr4   r2   blr   r   r   
<listcomp>   s     ztest.<locals>.<listcomp>c                 S   s   g | ]\}}t | qS r   rm   ro   r   r   r   rq      s     c                 s   s   | ]}|d k	r|V  qd S r   r   r4   r@   r   r   r   r7      s      
path_count)rf   master_1master_2value_1value_2
node_count)rf   pathrt   ru   rv   rw   node_incompatibility)rf   ry   nodert   ru   rv   rw   c                 s   s   | ]}|d k	r|V  qd S r   r   rr   r   r   r   r7   3  s      c                    s   g | ]  fd dD qS )c                    s   g | ]}t t |qS r   )rA   r<   )r4   r;   r:   r   r   rq   ?  s     z#test.<locals>.<listcomp>.<listcomp>r   )r4   )m1r|   r   rq   ?  s     c                 3   s   | ]} | | V  qd S r   r   )r4   rD   )costsr   r   r7   B  s     gffffff?contour_orderc                 s   s   | ]}|d k	r|V  qd S r   r   rr   r   r   r   r7   V  s      c                 S   s   g | ]}|qS r   r   )r4   r?   r   r   r   rq   d  s    c                 3   s   | ]}t t |V  qd S r   )rC   r<   )r4   Zc1)c0r   r   r7   e  s     wrong_start_point)rf   rj   rt   ru   
math_error)rf   rg   error)%r   r9   r&   r*   r   Zdraw	TypeErrorr   rI   r8   r   Zreplayr   mathsqrtrB   areaintZmeanXZmeanYZstddevXZstddevYZcorrelationrR   r-   r   r
   rP   r   rO   reversedindexrW   r]   rH   min
ValueError)4	glyphsetsglyphsnamesignore_missinghistrd   Z
glyph_nameZm0idxZ
allVectorsZallNodeTypesZallContourIsomorphismsr   nameglyphZperContourPenZcontourPensZcontourVectorsZcontourIsomorphismsZ	nodeTypesixrj   ZnodeVecsstatsesizeZvectorZpoints	converterbitsr2   r6   r   maskZisomorphismsrD   mirroredZreversed_bitsZm0ZpathIxZnodes1Znodes2ZnodeIxZn1Zn2rJ   Zmatching_costZidentity_matchingZidentity_costZcontour0Zcontour1Zmin_costZ
first_costr   )r   r~   r}   rc   r   test   s   



 
























r   c           "         sZ  ddl }|jdtjd}|jdddd |jd	d
dd |jdd
dd |jdd
dd |jddtddd || } | jrt| j	 nd}ddl
m} g }g }t| jdkrr| jd drddlm} || jd }dd |jD | _n~| jd drJddlm}	m}
 |	| jd }||
| dd |D }g | _n(| jd drrddlm} || jd }d |krr|d  }t }|j D ]P}|D ]D}g }t|j D ]\}}|||d f q|t | qqi g}|d! t|d"d# d$D ]:}|t| i }|D ]\}}|||< q$|| q
|}~|D ]}||j!|d%d& qPg | _| jD ]b}|d'rdd(l"m#} ||| nddlm} ||| |||$d)dd  qxg }|D ]<}t%|d*r|!  n| | fd+d, & D  q|s:td-d |D }|D ]4 t & }|| }|r>|D ]}d |< q`q>t'|||| j(d.}| j)sL| j*rddl*}t+|,| n| D ]\}} t+d/| d0 | D ]n}!|!d1 d2krt+d3|!d4   |!d1 d5krt+d6|!d4   |!d1 d7krJt+d8|!d9 |!d: |!d; |!d< f  |!d1 d=krt+d>|!d? |!d9 |!d: |!d; |!d< f  |!d1 d@krt+dA|!dB |!d? |!d9 |!d: |!d; |!d< f  |!d1 dCkrt+dD|!d9 |!d: |!d; |!d< f  |!d1 dEkrt+dF|!dG |!d: |!d< f  |!d1 dHkrt+dI|!d4 |!dJ f  q֐q|rV|S dS )Kz/Test for interpolatability issues between fontsr   Nzfonttools varLib.interpolatable)descriptionz--glyphsstorez&Space-separate name of glyphs to check)actionhelpz--json
store_truezOutput report in JSON formatz--quietz%Only exit with code 1 or 0, no outputz--ignore-missingz<Will not report glyphs missing from sparse masters as errorsinputsFILE+zAInput a single DesignSpace/Glyphs file, or multiple TTF/UFO files)metavarrf   nargsr   )basenamerl   z.designspace)DesignSpaceDocumentc                 S   s   g | ]
}|j qS r   )ry   )r4   rg   r   r   r   rq     s     zmain.<locals>.<listcomp>z.glyphs)GSFontto_ufosc                 S   s    g | ]}d |j j|j jf qS )z%s-%s)infoZ
familyNameZ	styleName)r4   fr   r   r   rq     s     z.ttf)TTFontgvarz()c                 S   s   t | | fS r   r	   )r?   r   r   r   <lambda>      zmain.<locals>.<lambda>)keyT)location
normalizedz.ufo)	UFOReader.getGlyphSetc                    s   i | ]}| | qS r   r   )r4   r   rh   r   r   
<dictcomp>  s      zmain.<locals>.<dictcomp>c                 S   s   g | ]}|  D ]}|qqS r   r^   )r4   r   gnr   r   r   rq     s     
  )r   r   r   zGlyph z was not compatible: rf   re   z"    Glyph was missing in master %srg   ri   z'    Glyph has an open path in master %srs   z*    Path count differs: %i in %s, %i in %srv   rt   rw   ru   rx   z5    Node count differs in path %i: %i in %s, %i in %sry   rz   z7    Node %o incompatible in path %i: %s in %s, %s in %sr{   r   z-    Contour order differs: %s in %s, %s in %sr   z*    Contour %d start point differs: %s, %srj   r   z!    Miscellaneous error in %s: %sr   )-argparseArgumentParsermain__doc__add_argumentstr
parse_argsr   setsplitos.pathr   r
   r   endswithZfontTools.designspaceLibr   ZfromfilesourcesZ	glyphsLibr   r   extendZfontTools.ttLibr   
variationsvaluessortedZaxesitemsr&   addr8   r   ZfontTools.ufoLibr   rsplithasattrr_   r   r   quietjsonprintdumps)"argsr   parserr   r   Zfontsr   r   Zdesignspacer   r   Zgsfontr   fontr   Zlocsr   varloctagvalZnew_locsr   filenamer   r   ZglyphSetGlyphNamesZdiffr   rc   r   r   Zglyph_problemsr\   r   rh   r   r   |  sR   





    

	r   __main__)NNF)N)!r   ZfontTools.pens.basePenr   r   ZfontTools.pens.pointPenr   ZfontTools.pens.recordingPenr   ZfontTools.pens.statisticsPenr   ZfontTools.pens.momentsPenr   collectionsr   r   rU   sysr   r   r*   r-   r<   rA   rC   rK   r]   r   r   r'   rc   exitr   boolr   r   r   r   <module>   s4   
"#
 p
 H
