U
    #vh~W                     @   s   d Z dddddgZddlmZ dd	lmZ d
d Zdd Zd ddZd!ddZ	dd Z
d"ddZd#ddddZd$ddZG dd deZdd Zd%ddZedkrddlZddlZeejdkree  ee j dS )&z%Variation fonts interpolation models.normalizeValuenormalizeLocationsupportScalarpiecewiseLinearMapVariationModel    )noRound   )VariationModelErrorc                 C   s   dd | D S )Nc                 S   s   g | ]}|d k	r|qS N .0lr   r   ;/tmp/pip-unpacked-wheel-1ufboor8/fontTools/varLib/models.py
<listcomp>   s      znonNone.<locals>.<listcomp>r   lstr   r   r   nonNone   s    r   c                 C   s   t dd | D S )Nc                 s   s   | ]}|d kV  qd S r
   r   r   r   r   r   	<genexpr>   s     zallNone.<locals>.<genexpr>allr   r   r   r   allNone   s    r   Nc                    s>   d krt fdd|D S  t  fdd|D S )Nc                 3   s   | ]} |kV  qd S r
   r   r   item)refr   r   r      s     zallEqualTo.<locals>.<genexpr>c                 3   s   | ]} |kV  qd S r
   r   r   )mappedmapperr   r   r      s     r   )r   r   r   r   )r   r   r   r   
allEqualTo   s    r   c                 C   sB   | sdS t | }zt|}W n tk
r2   Y dS X t|||dS )NT)r   )iternextStopIterationr   )r   r   itfirstr   r   r   allEqual   s    r#   c                 C   s(   t | t |kstdd t|| D S )Nc                 S   s   g | ]\}}|r|qS r   r   )r   r   tr   r   r   r   ,   s      zsubList.<locals>.<listcomp>lenAssertionErrorzip)truthr   r   r   r   subList*   s    r*   Fc              
   C   s   |\}}}||  kr|ks@n t d|dd|dd|d|sTtt| ||} | |ksd||krhdS | |k rx||ks| |kr||kr| | ||  S | |kr||ks| |k r||kstd|  d| d| d| d	| | ||  S dS )	zNormalizes value based on a min/default/max triple.

    >>> normalizeValue(400, (100, 400, 900))
    0.0
    >>> normalizeValue(100, (100, 400, 900))
    -1.0
    >>> normalizeValue(650, (100, 400, 900))
    0.5
    z8Invalid axis values, must be minimum, default, maximum: z3.3fz,         zOoops... v=z
, triple=()N)
ValueErrormaxminr'   )vtripleextrapolatelowerdefaultupperr   r   r   r   /   s&    

 )validatec                C   st   |r8t |  t | ks8tt |  t |  i }| D ]*\}}| ||d }t|||d||< qD|S )a  Normalizes location based on axis min/default/max values from axes.

    >>> axes = {"wght": (100, 400, 900)}
    >>> normalizeLocation({"wght": 400}, axes)
    {'wght': 0.0}
    >>> normalizeLocation({"wght": 100}, axes)
    {'wght': -1.0}
    >>> normalizeLocation({"wght": 900}, axes)
    {'wght': 1.0}
    >>> normalizeLocation({"wght": 650}, axes)
    {'wght': 0.5}
    >>> normalizeLocation({"wght": 1000}, axes)
    {'wght': 1.0}
    >>> normalizeLocation({"wght": 0}, axes)
    {'wght': -1.0}
    >>> axes = {"wght": (0, 0, 1000)}
    >>> normalizeLocation({"wght": 0}, axes)
    {'wght': 0.0}
    >>> normalizeLocation({"wght": -1}, axes)
    {'wght': 0.0}
    >>> normalizeLocation({"wght": 1000}, axes)
    {'wght': 1.0}
    >>> normalizeLocation({"wght": 500}, axes)
    {'wght': 0.5}
    >>> normalizeLocation({"wght": 1001}, axes)
    {'wght': 1.0}
    >>> axes = {"wght": (0, 1000, 1000)}
    >>> normalizeLocation({"wght": 0}, axes)
    {'wght': -1.0}
    >>> normalizeLocation({"wght": -1}, axes)
    {'wght': -1.0}
    >>> normalizeLocation({"wght": 500}, axes)
    {'wght': -0.5}
    >>> normalizeLocation({"wght": 1000}, axes)
    {'wght': 0.0}
    >>> normalizeLocation({"wght": 1001}, axes)
    {'wght': 0.0}
    r   )r2   )setkeysr'   itemsgetr   )locationaxesr2   r6   outtagr1   r0   r   r   r   r   N   s    '&Tc                 C   s  |r|dkrt dd}| D ]\}\}}}	|rp|dkr>q ||ks ||	krPq |dk rb|	dkrbq | |d}
n|| ks|t| | }
|
|krq |rX|| \}}|
|k r||kr||kr||	k r||
|	 ||	  9 }q n||k r||
| ||  9 }q n`||
k rX||	krX||kr8||k r8||
| ||  9 }q n ||k rX||
|	 ||	  9 }q |
|ksl|	|
krvd} q|
|k r||
| ||  9 }q ||
|	 ||	  9 }q |S )a  Returns the scalar multiplier at location, for a master
    with support.  If ot is True, then a peak value of zero
    for support of an axis means "axis does not participate".  That
    is how OpenType Variation Font technology works.

    If extrapolate is True, axisRanges must be a dict that maps axis
    names to (axisMin, axisMax) tuples.

      >>> supportScalar({}, {})
      1.0
      >>> supportScalar({'wght':.2}, {})
      1.0
      >>> supportScalar({'wght':.2}, {'wght':(0,2,3)})
      0.1
      >>> supportScalar({'wght':2.5}, {'wght':(0,2,4)})
      0.75
      >>> supportScalar({'wght':2.5, 'wdth':0}, {'wght':(0,2,4), 'wdth':(-1,0,+1)})
      0.75
      >>> supportScalar({'wght':2.5, 'wdth':.5}, {'wght':(0,2,4), 'wdth':(-1,0,+1)}, ot=False)
      0.375
      >>> supportScalar({'wght':2.5, 'wdth':0}, {'wght':(0,2,4), 'wdth':(-1,0,+1)})
      0.75
      >>> supportScalar({'wght':2.5, 'wdth':.5}, {'wght':(0,2,4), 'wdth':(-1,0,+1)})
      0.75
      >>> supportScalar({'wght':3}, {'wght':(0,1,2)}, extrapolate=True, axisRanges={'wght':(0, 2)})
      -1.0
      >>> supportScalar({'wght':-1}, {'wght':(0,1,2)}, extrapolate=True, axisRanges={'wght':(0, 2)})
      -1.0
      >>> supportScalar({'wght':3}, {'wght':(0,2,2)}, extrapolate=True, axisRanges={'wght':(0, 2)})
      1.5
      >>> supportScalar({'wght':-1}, {'wght':(0,2,2)}, extrapolate=True, axisRanges={'wght':(0, 2)})
      -0.5
    Nz2axisRanges must be passed when extrapolate is Trueg      ?r+   )	TypeErrorr9   r:   r'   )r;   supportZotr2   
axisRangesscalaraxisr3   peakr5   r0   axisMinaxisMaxr   r   r   r      sN    "

c                   @   s   e Zd ZdZd(ddddZdd Zed	d
 Zeg fddZdd Z	dd Z
dd Zdd ZedddZedddZdd Zdd Zedd Zed d! Zd"d# Zedd$d%Zedd&d'ZdS ))r   a5  Locations must have the base master at the origin (ie. 0).

    If axis-ranges are not provided, values are assumed to be normalized to
    the range [-1, 1].

    If the extrapolate argument is set to True, then values are extrapolated
    outside the axis range.

      >>> from pprint import pprint
      >>> axisRanges = {'wght': (-180, +180), 'wdth': (-1, +1)}
      >>> locations = [       {'wght':100},       {'wght':-100},       {'wght':-180},       {'wdth':+.3},       {'wght':+120,'wdth':.3},       {'wght':+120,'wdth':.2},       {},       {'wght':+180,'wdth':.3},       {'wght':+180},       ]
      >>> model = VariationModel(locations, axisOrder=['wght'], axisRanges=axisRanges)
      >>> pprint(model.locations)
      [{},
       {'wght': -100},
       {'wght': -180},
       {'wght': 100},
       {'wght': 180},
       {'wdth': 0.3},
       {'wdth': 0.3, 'wght': 180},
       {'wdth': 0.3, 'wght': 120},
       {'wdth': 0.2, 'wght': 120}]
      >>> pprint(model.deltaWeights)
      [{},
       {0: 1.0},
       {0: 1.0},
       {0: 1.0},
       {0: 1.0},
       {0: 1.0},
       {0: 1.0, 4: 1.0, 5: 1.0},
       {0: 1.0, 3: 0.75, 4: 0.25, 5: 1.0, 6: 0.6666666666666666},
       {0: 1.0,
        3: 0.75,
        4: 0.25,
        5: 0.6666666666666667,
        6: 0.4444444444444445,
        7: 0.6666666666666667}]
    NF)rA   c                   s   t tdd  D t  kr&td _|d k	r8|ng _|_|d krx|r\ }ndd  D }dd |D }|_dd	  D  j jd
}t	 |d_
fdd	 D _ fdd	j
D _  i _d S )Nc                 s   s   | ]}t t| V  qd S r
   )tuplesortedr9   r   r   r   r   r     s     z*VariationModel.__init__.<locals>.<genexpr>zLocations must be unique.c                 S   s   h | ]}|  D ]}|qqS r   r8   r   locrC   r   r   r   	<setcomp>  s     
  z*VariationModel.__init__.<locals>.<setcomp>c                 S   s   i | ]
}|d qS ))r   r   r   rC   r   r   r   
<dictcomp>  s      z+VariationModel.__init__.<locals>.<dictcomp>c                 S   s   g | ]}d d |  D qS )c                 S   s   i | ]\}}|d kr||qS r+   r   r   kr0   r   r   r   rO     s       z6VariationModel.__init__.<locals>.<listcomp>.<dictcomp>r9   r   rK   r   r   r   r     s     z+VariationModel.__init__.<locals>.<listcomp>	axisOrder)keyc                    s   g | ]} j |qS r   	locationsindexr   selfr   r   r     s     c                    s   g | ]}  |qS r   rZ   r   rY   r   r   r     s     )r&   r7   r	   origLocationsrV   r2   computeAxisRangesrA   getMasterLocationsSortKeyFuncrH   rY   mappingreverseMapping_computeMasterSupports
_subModels)r\   rY   rV   r2   rA   allAxesZkeyFuncr   )rY   r\   r   __init__  s*     zVariationModel.__init__c                 C   sb   d|kr| |fS t dd |D }| j|}|dkrTtt|| j| j}|| j|< |t||fS )zReturn a sub-model and the items that are not None.

        The sub-model is necessary for working with the subset
        of items when some are None.

        The sub-model is cached.Nc                 s   s   | ]}|d k	V  qd S r
   r   r   r0   r   r   r   r   *  s     z-VariationModel.getSubModel.<locals>.<genexpr>)rG   re   r:   r   r*   r_   rV   )r\   r9   rW   ZsubModelr   r   r   getSubModel!  s    
zVariationModel.getSubModelc                 C   sb   i }dd | D }| D ]F}|D ]<}| |d}| |||f\}}t||t||f||< qq|S )Nc                 S   s   h | ]}|  D ]}|qqS r   rI   rJ   r   r   r   rL   4  s     
  z3VariationModel.computeAxisRanges.<locals>.<setcomp>r   )r:   r/   r.   )rY   rA   rf   rK   rC   valuerE   rF   r   r   r   r`   1  s    z VariationModel.computeAxisRangesc                 C   s   i | krt di }| D ]d}t|dkr*qtt|}|| }||krPdh||< ||| ksntd|||f || | qdd }|||}|S )NzBase master not found.r   r+   z&Value "%s" in axisPoints["%s"] -->  %sc                    s   dd  fdd}|S )Nc                 S   s   | dk rdS | dkrdS dS )Nr   rM   r   r   r0   r   r   r   signN  s    zJVariationModel.getMasterLocationsSortKeyFunc.<locals>.getKey.<locals>.signc              	      s   t  }fdd  D } fddD }|fddt  D  |t | tfdd|D t|t fdd|D t fdd|D fS )	Nc                    s(   g | ] \}}| kr| | kr|qS r   r   )r   rC   rj   )
axisPointsr   r   r   S  s    z]VariationModel.getMasterLocationsSortKeyFunc.<locals>.getKey.<locals>.key.<locals>.<listcomp>c                    s   g | ]}| kr|qS r   r   rN   rK   r   r   r   X  s      c                    s   g | ]}| kr|qS r   r   rN   rU   r   r   r   Z  s      c                 3   s$   | ]}| kr  |nd V  qdS )i   Nr]   rN   rU   r   r   r   _  s   z\VariationModel.getMasterLocationsSortKeyFunc.<locals>.getKey.<locals>.key.<locals>.<genexpr>c                 3   s   | ]} | V  qd S r
   r   rN   )rK   rl   r   r   r   d  s    c                 3   s   | ]}t  | V  qd S r
   )absrN   rn   r   r   r   g  s    )r&   r9   extendrH   r8   rG   )rK   ZrankZonPointAxesZorderedAxesrV   rm   rl   rn   r   rW   Q  s*    
zIVariationModel.getMasterLocationsSortKeyFunc.<locals>.getKey.<locals>.keyr   )rm   rV   rW   r   rq   r   getKeyM  s    z<VariationModel.getMasterLocationsSortKeyFunc.<locals>.getKey)r	   r&   r   r   r'   add)rY   rV   rm   rK   rC   rj   rr   retr   r   r   ra   <  s$    

!
z,VariationModel.getMasterLocationsSortKeyFuncc                    sj   fdd|D }fdd|D _ dd j D  fdd D _ fddjD _i _|S )Nc                    s   g | ]} | qS r   r   r   idx)master_listr   r   r   t  s     z1VariationModel.reorderMasters.<locals>.<listcomp>c                    s   g | ]} j | qS r   )r_   ru   r[   r   r   r   u  s     c                 S   s   g | ]}d d |  D qS )c                 S   s   i | ]\}}|d kr||qS rP   r   rQ   r   r   r   rO   w  s       z<VariationModel.reorderMasters.<locals>.<listcomp>.<dictcomp>rS   rT   r   r   r   r   v  s    c                    s   g | ]} j |qS r   rX   r   r[   r   r   r   y  s     c                    s   g | ]}  |qS r   r]   r   r^   r   r   r   z  s     )r_   rb   rY   rc   re   )r\   rw   rb   Znew_listr   )rY   rw   r\   r   reorderMastersq  s    zVariationModel.reorderMastersc                 C   s  g | _ |  }t|D ]h\}}t| }|d | D ]8}t| |krPq8d}| D ]D\}\}}	}
|| d |	ks\||| d   k r|
k s\n d} qq\|sq8i }d}| D ]}|| d }||kst|| \}}}
||
 }}||k r|}|| ||  }n ||k r|}|| |
|  }nq||kr>i }|}||kr|||f||< q| D ]\}}|||< q^q8| j | q|   d S )NTr   FrM   )	supports_locationsToRegions	enumerater7   r8   r9   r'   append_computeDeltaWeights)r\   regionsiregionZlocAxesZprev_regionZrelevantrC   r3   rD   r5   ZbestAxesZ	bestRatiovallocVZnewLowerZnewUpperZratior1   r   r   r   rd   ~  sV     
	


z%VariationModel._computeMasterSupportsc                 C   st   | j }| j}g }|D ]Z}i }| D ]>\}}|dkrLd||| d f||< q$|| d |df||< q$|| q|S )Nr   r   )rY   rA   r9   r|   )r\   rY   rA   r~   rK   r   rC   r   r   r   r   rz     s    z"VariationModel._locationsToRegionsc                 C   s`   g | _ t| jD ]J\}}i }t| jd | D ]\}}t||}|r.|||< q.| j | qd S r
   )deltaWeightsr{   rY   ry   r   r|   )r\   r   rK   ZdeltaWeightjr@   rB   r   r   r   r}     s    

z#VariationModel._computeDeltaWeightsroundc          
      C   s   t |t | jks(tt |t | jf| j}g }t| jD ]Z\}}|||  }| D ].\}}	|	dkrv||| 8 }qX||| |	 8 }qX||| q<|S )Nr   )r&   r   r'   rc   r{   r9   r|   )
r\   masterValuesr   rb   r=   r   weightsdeltar   weightr   r   r   	getDeltas  s    zVariationModel.getDeltasc                C   s"   |  |\}}|j||d|jfS )Nr   )ri   r   ry   )r\   r9   r   modelr   r   r   getDeltasAndSupports  s    z#VariationModel.getDeltasAndSupportsc                    s    fddj D S )zReturn scalars for each delta, for the given location.
        If interpolating many master-values at the same location,
        this function allows speed up by fetching the scalars once
        and using them with interpolateFromMastersAndScalars().c                    s    g | ]}t  |jjd qS ))r2   rA   )r   r2   rA   )r   r@   rK   r\   r   r   r     s      z-VariationModel.getScalars.<locals>.<listcomp>)ry   )r\   rK   r   r   r   
getScalars  s    zVariationModel.getScalarsc                    sp    | tttjD ]2\}}| D ] \}} |   | | 8  < q,q fddtt D   S )a  Return multipliers for each master, for the given location.
        If interpolating many master-values at the same location,
        this function allows speed up by fetching the scalars once
        and using them with interpolateFromValuesAndScalars().

        Note that the scalars used in interpolateFromMastersAndScalars(),
        are *not* the same as the ones returned here. They are the result
        of getScalars().c                    s   g | ]} j |  qS r   )rb   )r   r   r=   r\   r   r   r     s     z3VariationModel.getMasterScalars.<locals>.<listcomp>)r   reversedlistr{   r   r9   ranger&   )r\   ZtargetLocationr   r   r   r   r   r   r   getMasterScalars  s    	
zVariationModel.getMasterScalarsc                 C   sT   d}t | t |kstt| |D ],\}}|s0q"|| }|dkrF|}q"||7 }q"|S )aV  Interpolate from values and scalars coefficients.

        If the values are master-values, then the scalars should be
        fetched from getMasterScalars().

        If the values are deltas, then the scalars should be fetched
        from getScalars(); in which case this is the same as
        interpolateFromDeltasAndScalars().
        Nr%   )valuesscalarsr0   rj   rB   Zcontributionr   r   r   interpolateFromValuesAndScalars  s    
z.VariationModel.interpolateFromValuesAndScalarsc                 C   s   t | |S )z>Interpolate from deltas and scalars fetched from getScalars().)r   r   )deltasr   r   r   r   interpolateFromDeltasAndScalars  s    z.VariationModel.interpolateFromDeltasAndScalarsc                 C   s   |  |}| ||S )z)Interpolate from deltas, at location loc.)r   r   )r\   rK   r   r   r   r   r   interpolateFromDeltas  s    
z$VariationModel.interpolateFromDeltasc                C   s   |  |}| ||S )z0Interpolate from master-values, at location loc.)r   r   )r\   rK   r   r   r   r   r   r   interpolateFromMasters#  s    
z%VariationModel.interpolateFromMastersc                C   s   | j ||d}| ||S )zInterpolate from master-values, and scalars fetched from
        getScalars(), which is useful when you want to interpolate
        multiple master-values with the same location.r   )r   r   )r\   r   r   r   r   r   r   r    interpolateFromMastersAndScalars(  s    z/VariationModel.interpolateFromMastersAndScalars)NF)__name__
__module____qualname____doc__rg   ri   staticmethodr`   ra   rx   rd   rz   r}   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r      s4   2   

48

c                    s   |  }|s S  |kr |  S t|} |k r@ ||  | S t|} |kr` ||  | S t fdd|D }t fdd|D }|| }|| }|||  |  ||   S )Nc                 3   s   | ]}| k r|V  qd S r
   r   r   rR   rk   r   r   r   =  s      z%piecewiseLinearMap.<locals>.<genexpr>c                 3   s   | ]}| kr|V  qd S r
   r   r   rk   r   r   r   >  s      )r8   r/   r.   )r0   rb   r8   rR   abvaZvbr   rk   r   r   0  s     c           
         s\  ddl m} ddl}|jdtjd}|jdddd	d
 |jdd}|jdddtd |jdddddd |	| } || j
d ddlm} | jrddlm} | }|| j dd |jD }td || |  td dd |jD }|| n4dd ttd td!d" D   fd#d| jD }t|}	td$ ||	j td% ||	j dS )&z*Normalize locations on a given designspacer   )configLoggerNzfonttools varLib.models)descriptionz
--loglevelZLEVELINFOz Logging level (defaults to INFO))metavarr4   helpT)requiredz-dz--designspaceZDESIGNSPACE)r   typez-lz--locationsZLOCATION+zFMaster locations as comma-separate coordinates. One must be all zeros.)r   nargsr   )level)pprint)DesignSpaceDocumentc                 S   s   g | ]
}|j qS r   r;   r   sr   r   r   r   h  s     zmain.<locals>.<listcomp>zOriginal locations:zNormalized locations:c                 S   s   g | ]
}|j qS r   r   r   r   r   r   r   m  s     c                 S   s   g | ]}t |qS r   )chr)r   cr   r   r   r   p  s     AZr   c              	      s*   g | ]"}t t d d |dD qS )c                 s   s   | ]}t |V  qd S r
   )floatrh   r   r   r   r   r  s     z"main.<locals>.<listcomp>.<genexpr>,)dictr(   splitr   r<   r   r   r   q  s    zSorted locations:z	Supports:)Z	fontToolsr   argparseArgumentParsermainr   add_argumentadd_mutually_exclusive_groupstr
parse_argsZloglevelr   ZdesignspaceZfontTools.designspaceLibr   readsourcesprint	normalizer   ordrY   r   ry   )
argsr   r   parsergroupr   r   docZlocsr   r   r   r   r   D  sX    

 

r   __main__)N)N)F)F)TFN)N)r   __all__ZfontTools.misc.roundToolsr   errorsr	   r   r   r   r#   r*   r   r   r   objectr   r   r   r   doctestsysr&   argvexittestmodfailedr   r   r   r   <module>   s4   


2
Q  a
8