B
    ScD                 @   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
 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 )"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   >lib/python3.7/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 )N)_newItemr   moveTo)r   Zp0r   r   r   _moveTo#   s    zPerContourPen._moveToc             C   s   | j | d S )N)r   ZlineTo)r   p1r   r   r   _lineTo'   s    zPerContourPen._lineToc             C   s   | j || d S )N)r   ZqCurveTo)r   r   p2r   r   r   _qCurveToOne*   s    zPerContourPen._qCurveToOnec             C   s   | j ||| d S )N)r   ZcurveTo)r   r   r   Zp3r   r   r   _curveToOne-   s    zPerContourPen._curveToOnec             C   s   | j   d | _ d S )N)r   	closePath)r   r   r   r   
_closePath0   s    
zPerContourPen._closePathc             C   s   | j   d | _ d S )N)r   endPath)r   r   r   r   _endPath4   s    
zPerContourPen._endPathc             C   s   |    | _}| j| d S )N)r   r   r   append)r   Zpenr   r   r   r   8   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)   >   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 )N)r   )r   r   r   r   r   E   s    zRecordingPointPen.__init__Nc             K   s   d S )Nr   )r   Z
identifierkwargsr   r   r   	beginPathH   s    zRecordingPointPen.beginPath)returnc             C   s   d S )Nr   )r   r   r   r   r!   K   s    zRecordingPointPen.endPathc             C   s    | j ||d krdndf d S )NFT)r   r#   )r   ptZsegmentTyper   r   r   addPointN   s    zRecordingPointPen.addPoint)N)N)r$   r%   r&   r   r,   r!   r/   r   r   r   r   r*   C   s   
r*   c             C   s   t dd t| |D S )Nc             s   s   | ]\}}|| V  qd S )Nr   ).0abr   r   r   	<genexpr>S   s    z_vdiff.<locals>.<genexpr>)tuplezip)v0v1r   r   r   _vdiffR   s    r8   c             C   s"   d}x| D ]}||| 7 }q
W |S )Nr   r   )vecvxr   r   r   _vlenV   s    
r<   c             C   s*   d}x | D ]}|t |t | 7 }q
W |S )Nr   )abs)r9   r:   r;   r   r   r   _complex_vlen\   s    
r>   c                s   t  fddt|D S )Nc             3   s   | ]\}} | | V  qd S )Nr   )r0   ij)Gr   r   r3   d   s    z!_matching_cost.<locals>.<genexpr>)sum	enumerate)rA   matchingr   )rA   r   _matching_costc   s    rE   c             C   s&  t | }yBddlm} || \}}|tt|k s:tt|t| |fS  tk
r^   Y nX yFddl	m
} d g| }x | | D ]\}}|||< qW |t| |fS  tk
r   Y nX |dkrtdtt|}tt|}	t| |	}
x,|D ]$}t| |}||
k rt|| }	}
qW |	|
fS )Nr   )linear_sum_assignment)Munkres   z4Install Python module 'munkres' or 'scipy >= 0.17.0')r	   Zscipy.optimizerF   listrangeallAssertionErrorrE   ImportErrorZmunkresrG   Zcompute	Exception	itertoolspermutationsnext)rA   r   rF   ZrowsZcolsrG   rowcolrP   ZbestZ	best_costpZcostr   r   r   #min_cost_perfect_bipartite_matchingg   s4    



rU   c       2         s  |d kr| }|d kr | d   }g }t fdd}xB|D ]8}yg }g }g }x t| |D ]\}	}
||	kr||d|
d qb|	| }tt|	d}y|j|dd W n tk
r   || Y nX |j}~g }g }g }|| || || xRt	|D ]D\}}t
d	d
 |jD }|| t|	d}y|| W n: tk
r } z|||
|dd w
W d d }~X Y nX t|jd 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}x |jD ]\}}|d> |B }q<W t|j}d|> d }g }|| xPt|D ]D} || > |@ |||  ? B }||kr|tdd |jD |  qW tt|j}!d}"x|!D ]\}}|"d> |B }"qW xNt|D ]B} |"| > |@ |"||  ? B }||kr|tdd |!D |  qW q
W qbW |d }#x2t	|dd  D ]\} t|#tkr||d|d || d  t|#td |#krȐqtxt	t|#D ]\}$\}%}&|%|&krqt|%t|&kr4||d|$|d || d  t|%t|&d qxTt	t|%|&D ]B\}'\}(})|(|)krD||d|$|'|d || d  |(|)d qDqDW qW qtW |d }#xt	|dd  D ]\} t|#tkrΐ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 || d  ttt|#|*d P qW |d }#xt	|dd  D ]\} t|#tkrq|#sqxt	t|#D ]p\}\}.}/|.d  d"d  fd#d
|/D D t }0d }1|0|1d  k r||d$||d || d  d% qW qW W q> t!k
rv } z||d&|
|d' W d d }~X Y q>X q>W S )(Nr   c                s     | g | d S )N)
setdefaultr#   )Z	glyphnameZproblem)problemsr   r   add_problem   s    ztest.<locals>.add_problemmissing)typemaster)r   T)ZoutputImpliedClosingLinec             s   s   | ]}|d  V  qdS )r   Nr   )r0   Zinstructionr   r   r   r3      s    ztest.<locals>.<genexpr>	open_path)r[   contourrZ   g      ?   r)   r   r(   )r   r!   F   c             S   s   g | ]\}}t | qS r   )complex)r0   r.   blr   r   r   
<listcomp>   s    ztest.<locals>.<listcomp>c             S   s   g | ]\}}t | qS r   )r`   )r0   r.   ra   r   r   r   rb      s    
path_count)rZ   master_1master_2value_1value_2
node_count)rZ   pathrd   re   rf   rg   node_incompatibility)rZ   ri   noderd   re   rf   rg   c                s   g | ]  fd dD qS )c                s   g | ]}t t |qS r   )r<   r8   )r0   r7   )r6   r   r   rb   '  s    z#test.<locals>.<listcomp>.<listcomp>r   )r0   )m1)r6   r   rb   '  s    c             3   s   | ]} | | V  qd S )Nr   )r0   r?   )costsr   r   r3   *  s    gffffff?contour_orderc             S   s   g | ]}|qS r   r   )r0   r:   r   r   r   rb   A  s    c             3   s   | ]}t t |V  qd S )N)r>   r8   )r0   Zc1)c0r   r   r3   A  s    wrong_start_point)rZ   r]   rd   re   Z
math_error)rZ   r[   error)"keysr   r5   r'   r   Zdraw	TypeErrorr   r#   rC   r4   r   Zreplayr   r=   ZareaintZmeanXZmeanYZstddevXZstddevYZcorrelationrL   r*   r   r	   rJ   r   rI   reversedrU   rB   min
ValueError)2	glyphsetsglyphsnamesZhistrX   Z
glyph_nameZ
allVectorsZallNodeTypesZallContourIsomorphismsr   nameglyphZperContourPenZcontourPensZcontourVectorsZcontourIsomorphismsZ	nodeTypesZixr]   ZnodeVecsZstatsesizeZvectorZpointsZ	converterbitsr.   r2   r   maskZisomorphismsr?   ZmirroredZreversed_bitsZm0ZpathIxZnodes1Znodes2ZnodeIxZn1Zn2rD   Zmatching_costZidentity_matchingZidentity_costZcontour0Zcontour1Zmin_costZ
first_costr   )ro   rm   rl   rW   r   test   s6   











"
*








"$r   c             C   s  ddl }|jdtjd}|jdddd |jd	d
tddd || } d}ddlm} g }g }t	| j
dkrF| 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rFddlm} || j
d }d|krF|d }t }xf|j D ]X}xP|D ]H}g }x.t|j D ]\}}|||d f qxW |t| q`W qVW i g}|d xRt|dd dD ]>}|t| i }x|D ]\}}|||< qW || qW |}~x"|D ]}||j|dd q"W g | _
xl| j
D ]b}|d rzdd!l m!} ||| nddlm} ||| |||"d"dd  qNW t#|d d#rd$d |D }n|}t$|||d%}| j%rddl%}t&|'| nx~| D ]p\}}t&d&| d' xR|D ]H}|d( d)krZt&d*|d+   |d( d,krxt&d-|d+   |d( d.krt&d/|d0 |d1 |d2 |d3 f  |d( d4krt&d5|d6 |d0 |d1 |d2 |d3 f  |d( d7kr t&d8|d9 |d6 |d0 |d1 |d2 |d3 f  |d( d:krRt&d;|d0 |d1 |d2 |d3 f  |d( d<kr6t&d=|d> |d1 |d3 f  q6W qW |r|S dS )?z/Test for interpolatability issues between fontsr   Nzfonttools varLib.interpolatable)Zdescriptionz--json
store_truezOutput report in JSON format)actionhelpinputsZFILE+zInput TTF/UFO files)metavarrZ   nargsr   )basenamer_   z.designspace)DesignSpaceDocumentc             S   s   g | ]
}|j qS r   )ri   )r0   r[   r   r   r   rb   w  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)r0   fr   r   r   rb   }  s    z.ttf)TTFontgvarz()c             S   s   t | | fS )N)r	   )r:   r   r   r   <lambda>      zmain.<locals>.<lambda>)keyT)locationZ
normalizedz.ufo)	UFOReader.getGlyphSetc             S   s   g | ]}|  qS r   )r   )r0   fontr   r   r   rb     s    )ry   rz   zGlyph z was not compatible: rZ   rY   z"    Glyph was missing in master %sr[   r\   z'    Glyph has an open path in master %src   z*    Path count differs: %i in %s, %i in %srf   rd   rg   re   rh   z5    Node count differs in path %i: %i in %s, %i in %sri   rj   z7    Node %o incompatible in path %i: %s in %s, %s in %srk   rn   z-    Contour order differs: %s in %s, %s in %srp   z*    Contour %d start point differs: %s, %sr]   )(argparseArgumentParsermain__doc__add_argumentstr
parse_argsos.pathr   r	   r   endswithZfontTools.designspaceLibr   ZfromfileZsourcesZ	glyphsLibr   r   extendZfontTools.ttLibr   set
variationsvaluessortedZaxesitemsr#   addr4   r   ZfontTools.ufoLibr   rsplithasattrr   jsonprintdumps)argsr   parserry   r   Zfontsrz   r   Zdesignspacer   r   Zgsfontr   r   r   Zlocsr   varZloctagvalZnew_locsr
   filenamer   rx   rW   r   r|   Zglyph_problemsrT   r   r   r   r   W  s    






  r   __main__)NN)N) r   ZfontTools.pens.basePenr   r   ZfontTools.pens.pointPenr   ZfontTools.pens.recordingPenr   ZfontTools.pens.statisticsPenr   ZfontTools.pens.momentsPenr   collectionsr   rO   sysr   r   r'   r*   r8   r<   r>   rE   rU   r   r   r$   rW   exitrt   boolr   r   r   r   <module>   s2   	"#
 N
 
