o
    Ae=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rddlZe Zeee e dS 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   `/home/www/facesmatcher.com/pyenv/lib/python3.10/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      | j   d | _ d S r   )r   	closePathr   r   r   r   
_closePath3      

zPerContourPen._closePathc                 C   r"   r   )r   endPathr$   r   r   r   _endPath7   r&   zPerContourPen._endPathc                 C   s   |    | _}| j| d S r   )r   r   r   append)r   penr   r   r   r   ;   s   zPerContourPen._newItemr   )__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   r0   A   s   z%PerContourOrComponentPen.addComponentN)r+   r,   r-   r0   r   r   r   r   r.   @   s    r.   c                   @   s2   e Zd Zdd ZdddZ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      d S r   r   )r   
identifierkwargsr   r   r   	beginPathJ      zRecordingPointPen.beginPathreturnc                 C   r2   r   r   r$   r   r   r   r'   M   r6   zRecordingPointPen.endPathc                 C   s    | j ||d u r
dndf d S )NFT)r   r)   )r   ptZsegmentTyper   r   r   addPointP   s    zRecordingPointPen.addPointr   )r7   N)r+   r,   r-   r   r5   r'   r9   r   r   r   r   r1   F   s
    

r1   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       z_vdiff.<locals>.<genexpr>)tuplezip)v0v1r   r   r   _vdiffT   s   rC   c                 C   s   d}| D ]}||| 7 }q|S Nr   r   Zvecvxr   r   r   _vlenX   s   rH   c                 C   s&   d}| D ]}|t |t | 7 }q|S rD   )absrE   r   r   r   _complex_vlen_   s   rJ   c                    s   t  fddt|D S )Nc                 3   s     | ]\}} | | V  qd S r   r   )r:   ijGr   r   r=   g   s    z!_matching_cost.<locals>.<genexpr>)sum	enumerate)rN   matchingr   rM   r   _matching_costf   s   rR   c                 C   s  t | }z"ddlm} || \}}|tt|k sJ t|t| |fW S  ty/   Y nw z"ddlm	} d g| }| 
| D ]\}}|||< qB|t| |fW S  ty[   Y nw |dkrdtdtt|}tt|}	t| |	}
|D ]}t| |}||
k rt||}	}
qx|	|
fS )Nr   )linear_sum_assignment)Munkres   z4Install Python module 'munkres' or 'scipy >= 0.17.0')r
   Zscipy.optimizerS   listrangeallrR   ImportErrorZmunkresrT   Zcompute	Exception	itertoolspermutationsnext)rN   r   rS   rowscolsrT   rowcolr\   bestZ	best_costpZcostr   r   r   #min_cost_perfect_bipartite_matchingj   s:   



rd   Fc           4         s  |d u r| }|d u rdd | D }g }t  fdd}|D ]]}z>d}g }g }	g }
t| |D ]z\}}|| }|d u rW|sG||d|d |	d  |d  |
d  q0tt|d}z	|j|d	d
 W n tyt   || Y nw |j}~g }g }g }|	| || |
| t|D ]\}}t	dd |jD }|| t
|d}z|| W n ty } z||||dd W Y d }~qd }~ww 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J |d dv sJ t }t|d}|| d}|jD ]\}}|d> |B }q(t|j}d|> d } g }!||! t|D ]"}"||"> | @ |||" ? B }||krk|!tdd |jD |" qJtt|j}#d}$|#D ]\}}|$d> |B }$qxt|D ]!}"|$|"> | @ |$||" ? B }||kr|!tdd |#D |" qqq0|	tdd |	D d }|	| }%t|	|d d  D ]\}"d u rҐqt|%tkr||d|| |||" d  t|%td |%krqtt|%D ]\\}&\}'}(|'|(krq t|'t|(kr0||d|&|| |||" d  t|'t|(d q tt|'|(D ]#\})\}*}+|*|+krY||d|&|)|| |||" d  |*|+d  q7q7q q|td!d |D d }|| }%t||d d  D ]j\}"d u rqzt|%tkrqz|%sqz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qz|
td&d |
D d }|
| }%t|
|d d  D ]^\}"d u rq t|%tkrq |%sq tt|%D ]:\}\}0}1|0d  d'd  fd(d|1D D t"}2d }3|2|3d$ k r[||d)||| |||" d  d* q"q W q t#y| } z||d+||d, W Y d }~qd }~ww S )-Nc                 S   s   h | ]}|  D ]}|qqS r   keys)r:   r   gr   r   r   	<setcomp>       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   )r:   Zinstructionr   r   r   r=      s    ztest.<locals>.<genexpr>	open_path)rp   contourro   g      ?   r0   r   r/   )r#   r'   F   c                 S      g | ]\}}t | qS r   complexr:   r8   blr   r   r   
<listcomp>       ztest.<locals>.<listcomp>c                 S   rv   r   rw   ry   r   r   r   r{      r|   c                 s       | ]	}|d ur|V  qd S r   r   r:   rG   r   r   r   r=      r>   
path_count)ro   master_1master_2value_1value_2
node_count)ro   pathr   r   r   r   node_incompatibility)ro   r   noder   r   r   r   c                 s   r}   r   r   r~   r   r   r   r=   3  r>   c                    s   g | ]  fd dD qS )c                    s   g | ]	}t t |qS r   )rH   rC   )r:   rB   rA   r   r   r{   ?  s    z#test.<locals>.<listcomp>.<listcomp>r   )r:   )m1r   r   r{   ?  ri   c                 3   s    | ]	} | | V  qd S r   r   )r:   rK   )costsr   r   r=   B  r>   gffffff?contour_orderc                 s   r}   r   r   r~   r   r   r   r=   V  r>   c                 S   s   g | ]}|qS r   r   )r:   rF   r   r   r   r{   d  s    c                 3   s    | ]
}t t |V  qd S r   )rJ   rC   )r:   c1)c0r   r   r=   e  s    wrong_start_point)ro   rs   r   r   
math_error)ro   rp   error)$r   r@   r)   r.   r   Zdraw	TypeErrorr   rP   r?   r   Zreplayr   mathsqrtrI   ZareaintZmeanXZmeanYZstddevXZstddevYZcorrelationr1   r   r
   rW   r   rV   reversedindexr]   rd   rO   min
ValueError)4	glyphsetsglyphsnamesignore_missinghistrm   Z
glyph_nameZm0idxZ
allVectorsZallNodeTypesZallContourIsomorphismsr   nameglyphZperContourPenZcontourPensZcontourVectorsZcontourIsomorphismsZ	nodeTypesZixrs   ZnodeVecsstatsesizeZvectorZpoints	converterbitsr8   r<   r   maskZisomorphismsrK   mirroredZreversed_bitsZm0ZpathIxZnodes1Znodes2ZnodeIxZn1Zn2rQ   Zmatching_costZidentity_matchingZidentity_costZcontour0Zcontour1Zmin_costZ
first_costr   )r   r   r   rl   r   test   s  
















?




"




r   c           "         sF  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rEt| j	 nd}ddl
m} g }g }t| jdkr2| jd dryddlm} || jd }dd |jD | _n| jd drddlm}	m}
 |	| jd }||
| dd |D }g | _n| jd dr2ddlm} || jd }d |v r2|d  }t }|j D ]%}|D ] }g }t|j D ]\}}|||d f q|t | qqi g}|d! t|d"d# d$D ]}|t| i }|D ]	\}}|||< q|| q|}~|D ]}||j!|d%d& q!g | _| jD ]1}|d'rKdd(l"m#} ||| nddlm} ||| |||$d)dd  q5g }|D ]}t%|d*rx|!  n| | fd+d, & D  qk|std-d |D }|D ] t & }|| }|r|D ]}d |< qqt'|||| j(d.}| j)s| j*rddl*}t+|,| n| D ]\}} t+d/| d0 | D ]}!|!d1 d2krt+d3|!d4   |!d1 d5krt+d6|!d4   |!d1 d7krt+d8|!d9 |!d: |!d; |!d< f  |!d1 d=kr7t+d>|!d? |!d9 |!d: |!d; |!d< f  |!d1 d@krVt+dA|!dB |!d? |!d9 |!d: |!d; |!d< f  |!d1 dCkrot+dD|!d9 |!d: |!d; |!d< f  |!d1 dEkrt+dF|!dG |!d: |!d< f  |!d1 dHkrt+dI|!d4 |!dJ f  qq|r|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)metavarro   nargsr   )basenameru   z.designspace)DesignSpaceDocumentc                 S   s   g | ]}|j qS r   )r   )r:   rp   r   r   r   r{     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)r:   fr   r   r   r{     s     z.ttf)TTFontgvarz()c                 S   s   t | | fS r   r	   )rF   r   r   r   <lambda>  s    zmain.<locals>.<lambda>)keyT)location
normalizedz.ufo)	UFOReader.getGlyphSetc                    s   i | ]}| | qS r   r   )r:   r   rq   r   r   
<dictcomp>  s    zmain.<locals>.<dictcomp>c                 S   s   g | ]}|  D ]}|qqS r   re   )r:   r   gnr   r   r   r{     ri   )r   r   r   zGlyph z was not compatible: ro   rn   z"    Glyph was missing in master %srp   rr   z'    Glyph has an open path in master %sr   z*    Path count differs: %i in %s, %i in %sr   r   r   r   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, %srs   r   z!    Miscellaneous error in %s: %sr   )-argparseArgumentParsermain__doc__add_argumentstr
parse_argsr   setsplitZos.pathr   r
   r   endswithZfontTools.designspaceLibr   fromfilesourcesZ	glyphsLibr   r   extendZfontTools.ttLibr   
variationsvaluessortedZaxesitemsr)   addr?   r   ZfontTools.ufoLibr   rsplithasattrrf   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   rl   r   r   Zglyph_problemsrc   r   rq   r   r   |  sV  




 

	<r   __main__)NNFr   )!r   ZfontTools.pens.basePenr   r   ZfontTools.pens.pointPenr   ZfontTools.pens.recordingPenr   ZfontTools.pens.statisticsPenr   ZfontTools.pens.momentsPenr   collectionsr   r   r[   sysr   r   r.   r1   rC   rH   rJ   rR   rd   r   r   r+   rl   exitr   boolr   r   r   r   <module>   s8    
"
# 
p H