U
    mdKR                     @   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   X/home/sam/Atlas/atlas_env/lib/python3.8/site-packages/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   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   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   r2   r%   r5   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    rC   c                 C   s&   d}| D ]}|t |t | 7 }q|S r?   )absr@   r   r   r   _complex_vlen_   s    rE   c                    s   t  fddt|D S )Nc                 3   s   | ]\}} | | V  qd S r   r   )r6   ijGr   r   r9   g   s     z!_matching_cost.<locals>.<genexpr>)sum	enumerate)rI   matchingr   rH   r   _matching_costf   s    rM   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.optimizerN   listrangeallAssertionErrorrM   ImportErrorZmunkresrO   Zcompute	Exception	itertoolspermutationsnext)rI   r   rN   rowscolsrO   rowcolrX   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)r6   r   gr   r   r   	<setcomp>   s     
  ztest.<locals>.<setcomp>c                    s     | g | d S r   )
setdefaultr'   )Z	glyphname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   )r6   Zinstructionr   r   r   r9      s     ztest.<locals>.<genexpr>	open_path)rk   contourrj   g      ?   r.   r   r-   )r"   r%   F   c                 S   s   g | ]\}}t | qS r   complexr6   r4   blr   r   r   
<listcomp>   s     ztest.<locals>.<listcomp>c                 S   s   g | ]\}}t | qS r   rq   rs   r   r   r   ru      s     c                 s   s   | ]}|d k	r|V  qd S r   r   r6   rB   r   r   r   r9      s      
path_count)rj   master_1master_2value_1value_2
node_count)rj   pathrx   ry   rz   r{   node_incompatibility)rj   r}   noderx   ry   rz   r{   c                 s   s   | ]}|d k	r|V  qd S r   r   rv   r   r   r   r9   3  s      c                    s   g | ]  fd dD qS )c                    s   g | ]}t t |qS r   )rC   r>   )r6   r=   r<   r   r   ru   ?  s     z#test.<locals>.<listcomp>.<listcomp>r   )r6   )m1r   r   ru   ?  s     c                 3   s   | ]} | | V  qd S r   r   )r6   rF   )costsr   r   r9   B  s     gffffff?contour_orderc                 s   s   | ]}|d k	r|V  qd S r   r   rv   r   r   r   r9   V  s      c                 S   s   g | ]}|qS r   r   )r6   rA   r   r   r   ru   d  s    c                 3   s   | ]}t t |V  qd S r   )rE   r>   )r6   c1)c0r   r   r9   e  s     wrong_start_point)rj   rn   rx   ry   
math_error)rj   rk   error)%r   r;   r'   r,   r   Zdraw	TypeErrorr   rK   r:   r   Zreplayr   mathsqrtrD   ZareaintZmeanXZmeanYZstddevXZstddevYZcorrelationrT   r/   r   r
   rR   r   rQ   reversedindexrY   r`   rJ   min
ValueError)4	glyphsetsglyphsnamesignore_missinghistrh   Z
glyph_nameZm0idxZ
allVectorsZallNodeTypesZallContourIsomorphismsr   nameglyphZperContourPenZcontourPensZcontourVectorsZcontourIsomorphismsZ	nodeTypesZixrn   ZnodeVecsstatsesizeZvectorZpoints	converterbitsr4   r8   r   maskZisomorphismsrF   mirroredZreversed_bitsZm0ZpathIxZnodes1Znodes2ZnodeIxZn1Zn2rL   Zmatching_costZidentity_matchingZidentity_costZcontour0Zcontour1Zmin_costZ
first_costr   )r   r   r   rg   r   test   s   



 















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




r   c           "         s6  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tddd || } d}ddlm} g }g }t	| j
dkrN| j
d drddlm} || j
d }dd |jD | _
n~| j
d dr&ddlm}	m}
 |	| j
d }||
| dd |D }g | _
n(| j
d drNddlm} || j
d }d|krN|d }t }|j D ]P}|D ]D}g }t|j D ]\}}|||d f q|t| q|qti g}|d t|dd  d!D ]:}|t| i }|D ]\}}|||< q || q|}~|D ]}||j|d"d# q,g | _
| j
D ]b}|d$rdd%l m!} ||| nddlm} ||| |||"d&dd  qTg }|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's(| j(rddl(}t)|*| n| D ]\}} t)d,| d- | D ]n}!|!d. d/krt)d0|!d1   |!d. d2krt)d3|!d1   |!d. d4kr&t)d5|!d6 |!d7 |!d8 |!d9 f  |!d. d:kr^t)d;|!d< |!d6 |!d7 |!d8 |!d9 f  |!d. d=krt)d>|!d? |!d< |!d6 |!d7 |!d8 |!d9 f  |!d. d@krt)dA|!d6 |!d7 |!d8 |!d9 f  |!d. dBkrt)dC|!dD |!d7 |!d9 f  |!d. dEkrt)dF|!d1 |!dG f  qq|r2|S dS )Hz/Test for interpolatability issues between fontsr   Nzfonttools varLib.interpolatable)descriptionz--json
store_truezOutput report in JSON format)actionhelpz--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)metavarrj   nargsr   )basenamerp   z.designspace)DesignSpaceDocumentc                 S   s   g | ]
}|j qS r   )r}   )r6   rk   r   r   r   ru     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)r6   fr   r   r   ru     s     z.ttf)TTFontgvarz()c                 S   s   t | | fS r   r	   )rA   r   r   r   <lambda>      zmain.<locals>.<lambda>)keyT)location
normalizedz.ufo)	UFOReader.getGlyphSetc                    s   i | ]}| | qS r   r   )r6   r   rl   r   r   
<dictcomp>  s      zmain.<locals>.<dictcomp>c                 S   s   g | ]}|  D ]}|qqS r   ra   )r6   r   gnr   r   r   ru     s     
  )r   r   r   zGlyph z was not compatible: rj   ri   z"    Glyph was missing in master %srk   rm   z'    Glyph has an open path in master %srw   z*    Path count differs: %i in %s, %i in %srz   rx   r{   ry   r|   z5    Node count differs in path %i: %i in %s, %i in %sr}   r~   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, %srn   r   z!    Miscellaneous error in %s: %sr   )+argparseArgumentParsermain__doc__add_argumentstr
parse_argsos.pathr   r
   r   endswithZfontTools.designspaceLibr   fromfilesourcesZ	glyphsLibr   r   extendZfontTools.ttLibr   set
variationsvaluessortedZaxesitemsr'   addr:   r   ZfontTools.ufoLibr   rsplithasattrrb   r   r   quietjsonprintdumps)"argsr   parserr   r   Zfontsr   r   Zdesignspacer   r   Zgsfontr   Zfontr   Zlocsr   varloctagvalZnew_locsr   filenamer   r   ZglyphSetGlyphNamesdiffr   rg   r   r   Zglyph_problemsr_   r   rl   r   r   |  sH   





    

	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   rW   sysr   r   r,   r/   r>   rC   rE   rM   r`   r   r   r)   rg   exitr   boolr   r   r   r   <module>   s4   
"#
 p
 E
