)EjbdZddlmZddlZddlmZmZmZmZm Z ddl m Z ddl m Z ddlmZmZddlmZmZmZgd Ze eefZeeZee eeeeefZeeZee eefZGd d e ZGd d ZGddeZ Gdde Z!GddeZ"GddeZ#GddeZ$Gdde eZ%dS)a ========= PointPens ========= Where **SegmentPens** have an intuitive approach to drawing (if you're familiar with postscript anyway), the **PointPen** is geared towards accessing all the data in the contours of the glyph. A PointPen has a very simple interface, it just steps through all the points in a call from glyph.drawPoints(). This allows the caller to provide more data for each point. For instance, whether or not a point is smooth, and its name. ) annotationsN)AnyDictListOptionalTuple)StrEnum)LogMixin)DecomposedTransformIdentity) AbstractPenMissingComponentErrorPenError)AbstractPointPenBasePointToSegmentPenPointToSegmentPenSegmentToPointPenGuessSmoothPointPenReverseContourPointPenReverseFlippedceZdZdZdZdZdZdS)raHow to handle flipped components during decomposition. NO: Don't reverse flipped components KEEP_START: Reverse flipped components, keeping original starting point ON_CURVE_FIRST: Reverse flipped components, ensuring first point is on-curve no keep_starton_curve_firstN)__name__ __module__ __qualname____doc__NO KEEP_STARTON_CURVE_FIRSTIC:\PYTHON\MyICR_Suite\python\Lib\site-packages\fontTools/pens/pointPen.pyrr,s) BJ%NNNr#rcNeZdZdZddd Zdd Z d d!dZ dd"dZ dd#dZdS)$rzBaseclass for all PointPens.N identifier Optional[str]kwargsrreturnNonec t)zStart a new sub path.NotImplementedErrorselfr&r(s r$ beginPathzAbstractPointPen.beginPath<!!r#ct)zEnd the current sub path.r,r/s r$endPathzAbstractPointPen.endPath@r1r#FptTuple[float, float] segmentTypesmoothboolnamec t)z$Add a point to the current sub path.r,r/r5r7r8r:r&r(s r$addPointzAbstractPointPen.addPointDs "!r# baseGlyphNamestrtransformation/Tuple[float, float, float, float, float, float]c t)zAdd a sub glyph.r,)r/r>r@r&r(s r$ addComponentzAbstractPointPen.addComponentPs "!r# glyphNamer locationDict[str, float]c t)zAdd a VarComponent sub glyph. The 'transformation' argument must be a DecomposedTransform from the fontTools.misc.transform module, and the 'location' argument must be a dictionary mapping axis tags to their locations. )AttributeErrorr/rDr@rEr&r(s r$addVarComponentz AbstractPointPen.addVarComponentZs r#N)r&r'r(rr)r*r)r*NFNN)r5r6r7r'r8r9r:r'r&r'r(rr)r*) r>r?r@rAr&r'r(rr)r*) rDr?r@r rErFr&r'r(rr)r*) rrrrr0r4r=rCrJr"r#r$rr9s&&"""""""""&*"$( " " " " " %) """""%) r#rc<eZdZdZd dZddZdd Zd d Z dd ZdS)ra/ Base class for retrieving the outline in a segment-oriented way. The PointPen protocol is simple yet also a little tricky, so when you need an outline presented as segments but you have as points, do use this base implementation as it properly takes care of all the edge cases. r)r*cd|_dSrK) currentPathr3s r$__init__zBasePointToSegmentPen.__init__tsr#Nc @|jtdg|_dS)NzPath already begun.)rPrr.s r$r0zBasePointToSegmentPen.beginPathws(   '011 1r#segments SegmentListct)aOverride this method. It will be called for each non-empty sub path with a list of segments: the 'segments' argument. The segments list contains tuples of length 2: (segmentType, points) segmentType is one of "move", "line", "curve" or "qcurve". "move" may only occur as the first segment, and it signifies an OPEN path. A CLOSED path does NOT start with a "move", in fact it will not contain a "move" at ALL. The 'points' field in the 2-tuple is a list of point info tuples. The list has 1 or more items, a point tuple has four items: (point, smooth, name, kwargs) 'point' is an (x, y) coordinate pair. For a closed path, the initial moveTo point is defined as the last point of the last segment. The 'points' list of "move" and "line" segments always contains exactly one point tuple. r,)r/rSs r$ _flushContourz#BasePointToSegmentPen._flushContour|s 4"!r#c|jtd|j}d|_|sdSt|dkr/|d\}}}}}d||||fgfg}||dSg}|dddkr@|d\}}}}}|d||||fgf|dnhd}t t|D]} || d}|| }n||dn||dzd|d|dzz}g} |D]=\}}}}}| ||||f|$||| fg} >||dS)NzPath not begun.rmove)NqcurveNNN)rPrlenrVappendpoprange) r/pointsr5r7r8r:r(rS firstOnCurveicurrentSegments r$r4zBasePointToSegmentPen.endPaths   #,-- -!  F v;;!  4:1I 1B VT6&,FD&/I.J%K$LH   x ( ( ( F !9Q<6 ! !5;1I 1B VT6 OOVr64&@%AB C C C JJqMMMM  L3v;;''  $Qil *#$LE+# @AAAA q 0 2 23f=O|a?O=O6PP+-5;  1B VT6  ! !2vtV"< = = =" OO[.9 : : :NN 8$$$$$r#Fc p|jtd|j|||||fdSNPath not begun)rPrr\r<s r$r=zBasePointToSegmentPen.addPointsD   #+,, , [&$ GHHHHHr#rLrK)rSrTr)r*rM) rrrrrQr0rVr4r=r"r#r$rrks     """"8.%.%.%.%bIMIIIIIIr#rc*eZdZdZd d dZdZd d Zd S)rz Adapter class that converts the PointPen protocol to the (Segment)Pen protocol. NOTE: The segment pen does not support and will drop point names, identifiers and kwargs. FoutputImpliedClosingLiner9r)r*cVt|||_||_dSrK)rrQpenrg)r/ segmentPenrgs r$rQzPointToSegmentPen.__init__s+&&t,,,(@%%%r#c|std|j}|dddkrSd}|dd}t|dkrtdt||d\}}}}|d=nd}|d\}}|d\}}}}|n|||j}t|} |} t | D]} || \}}d |D}|d kret|dkrtd t||d} | dz| ks |s|r| | kr|| | } |d kr|j||d} |d kr|j||d} td||r| dS| dS)NzMust have at least one segment.rrYFrXz"Illegal move segment point count: Tcg|] \}}}}| Sr"r").0r5_s r$ z3PointToSegmentPen._flushContour..s 333[RAqb333r#linez"Illegal line segment point count: curverZzIllegal segmentType: ) rrir[moveTorgr^lineTocurveToqCurveTo closePathr4) r/rSriclosedr_movePtror7rg nSegmentslastPtrar5s r$rVzPointToSegmentPen._flushContours0 ><== =h A;q>V # #Fa[^F6{{aQCKKQQRRR$QiOFAq! F"*2, K$RjOFAq! >  JJv   #'#@ MM y!! F FA"*1+ K33F333Ff$$v;;!##"#UF #U#UVVVAYEY&&/'!'V||JJrNNNF'' V$$(( f%%D{DDEEE   MMOOOOO KKMMMMMr#Nc @~~|j||dSrK)rirCr/rD transformr&r(s r$rCzPointToSegmentPen.addComponents&   i33333r#)F)rgr9r)r*rK)rrrrrQrVrCr"r#r$rrs`AAAAA ???B444444r#rcNeZdZdZdddZddZdZdZd Zd Z d Z d Z d Z dS)rz] Adapter class that converts the (Segment)Pen protocol to the PointPen protocol. Tr)r*cP|rt||_n||_d|_dSrK)rricontour)r/pointPen guessSmooths r$rQzSegmentToPointPen.__init__+s-  *844DHHDHBF r#c|j}||jD]\}}||||dS)N)r7)rir0rr=r4)r/rir5r7s r$rVzSegmentToPointPen._flushContour2sUh #| 6 6OB LLL 5 5 5 5 r#cLg|_|j|dfdS)NrY)rr\r/r5s r$rszSegmentToPointPen.moveTo9s)  RL)))))r#cj|jtd|j|dfdS)N'Contour missing required initial moveTorq)rrr\rs r$rtzSegmentToPointPen.lineTo=s9 < DEE E RL)))))r#c|std|jtd|ddD]}|j|df|j|ddfdS)NMust pass in at least one pointrrlrr TypeErrorrrr\r/ptsr5s r$ruzSegmentToPointPen.curveToBs ?=>> > < DEE Ecrc( , ,B L  T + + + + SWg./////r#c|std|dg|_n|jtd|ddD]}|j|df|d$|j|ddfdSdS)NrrlrrZrrs r$rvzSegmentToPointPen.qCurveToKs ?=>> > r7?DLL|#HIIIcrc( , ,B L  T + + + + r7  L  R( 3 4 4 4 4 4  r#c|jtdt|jdkrl|jdd|jddkrD|jdd1|jdd|jd|jd<|jd=n"|jd\}}|dkr |df|jd<|d|_dS)NrrXrrlrYrq)rrr[rV)r/r5tps r$rwzSegmentToPointPen.closePathXs < DEE E    ! !a#t|B'7'::: Q". R #/"l2.DLO R  \!_FBV||"$f* Q  r#ch|jtd|d|_dS)Nr)rrrVr3s r$r4zSegmentToPointPen.endPathqs6 < DEE E  r#ch|jtd|j||dS)N1Components must be added before or after contours)rrrirC)r/rDr~s r$rCzSegmentToPointPen.addComponentws7 < #NOO O i33333r#N)TrL) rrrrrQrVrsrtrurvrwr4rCr"r#r$rr%s GGGGG****** 000 5 5 52 44444r#rcJeZdZdZd dZdZd dZdZ dd Zd d Z d d Z dS)rz Filtering PointPen that tries to determine whether an on-curve point should be "smooth", ie. that it's a "tangent" point or a "curve" point. 皙?c0||_||_d|_dSrK)_outPen_error_points)r/outPenerrors r$rQzGuessSmoothPointPen.__init__s   r#c<|jtd|j}t|}|sdS|dddkrtd|dz }n|dkrtd|dz }ng}|D]}||\}}}}} ||dz } |dz} || d|| d;||d}|| d} || d} || kr|| kr|d| dz |d| dz }}| d|dz | d|dz }}t j||}t j||}t ||z |jkr ||d|| f||<|D]\}}}}} |jj ||||fi| dS)NrerrXrYrlT) rrr[r^mathatan2absrrr=)r/r_nPointsindicesrar5r7ror:r(prevnextprevPtnextPtdx1dy1dx2dy2a1a2r8s r$rVz!GuessSmoothPointPen._flushContours < +,, ,f++  F !9Q<6 ! !Aw{++GG q[[B! ,,GGG D DA/5ay ,B Qf"q5Dq5Dd|A*vd|A/J1BD\!_FD\!_FV||f a56!9,befQi.?S!!9r!u,fQi"Q%.?SZS))ZS))rBw<<$+-- "KtV CF1I5; K K 1B VT6 !DL !"k64 J J6 J J J J K Kr#Nc r|jtdg|_|||d<|jjdi|dS)NPath already begunr&r")rrrr0r.s r$r0zGuessSmoothPointPen.beginPathsQ < #/00 0  !#-F<  (((((((r#cn||jd|_dSrK)rVrr4rr3s r$r4zGuessSmoothPointPen.endPaths3   r#Fc ~|jtd|||d<|j||d||fdS)Nrer&F)rrr\r<s r$r=zGuessSmoothPointPen.addPointsR < +,, ,  !#-F<  ReT6BCCCCCr#c h|jtd|||d<|jj||fi|dSNrr&)rrrrC)r/rDr@r&r(s r$rCz GuessSmoothPointPen.addComponentsN < #NOO O  !#-F< ! !)^FFvFFFFFr#c j|jtd|||d<|jj|||fi|dS)Nz4VarComponents must be added before or after contoursr&)rrrrJrIs r$rJz#GuessSmoothPointPen.addVarComponentsR < #QRR R  !#-F< $ $YSSFSSSSSr#)rrKrM) rrrrrQrVr0r4r=rCrJr"r#r$rr}s  &K&K&KP)))) IMDDDDGGGG?CTTTTTTr#rc>eZdZdZdZdZd dZdZ d dZd d Z dS) ra This is a PointPen that passes outline data to another PointPen, but reversing the winding direction of all contours. Components are simply passed through unchanged. Closed contours are reversed in such a way that the first point remains the first point. c"||_d|_dSrK)ricurrentContour)r/outputPointPens r$rQzReverseContourPointPen.__init__s!"r#c|j}|j}|s1||j|dS|dddk}|sd}nn||dd}tt|D]}||d|}n|d}n||d}| |s1|dd#|d|dd#||j|D]#\}}} } } ||} |}nd} |j |f| | | d| $|dS)N)r&rrXrY)r7r8r:) rirr0currentContourIdentifierr4r\r]r^r[reverser=) r/rirrxlastSegmentTyper`rar5nextSegmentTyper8r:r(r7s r$rVz$ReverseContourPointPen._flushContoursh%  MMT%BM C C C KKMMM FA&( ;$OO NN7;;q>> * * *L3w<<((  1:a=,#$LE-##'"),"7": !*Q-' A!*Q-' !> ???9@   5Bv*- "1" CL  +F  IO     r#Nc \|jtdg|_||_g|_dS)Nr)rrronCurver.s r$r0z ReverseContourPointPen.beginPaths5   */00 0 (2% r#ch|jtd|d|_dSrd)rrrVr3s r$r4zReverseContourPointPen.endPaths:   &+,, , "r#Fc ~|jtd|||d<|j|||||fdS)Nrer&)rrr\r<s r$r=zReverseContourPointPen.addPoint%sT   &+,, ,  !#-F<  ""B VT6#JKKKKKr#c ^|jtd|jj||fd|i|dSr)rrrirCr}s r$rCz#ReverseContourPointPen.addComponent.sD   *NOO OiTTzTVTTTTTr#rKrM) rrrrrQrVr0r4r=rCr"r#r$rrs### 000d###IMLLLLUUUUUUr#rc<eZdZdZdZeZdddd fdZd d ZxZS) DecomposingPointPena:Implements a 'addComponent' method that decomposes components (i.e. draws them onto self as simple contours). It can also be used as a mixin class (e.g. see DecomposingRecordingPointPen). You must override beginPath, addPoint, endPath. You may additionally override addVarComponent and addComponent. By default a warning message is logged when a base glyph is missing; set the class variable ``skipMissingComponents`` to False if you want all instances of a sub-class to raise a :class:`MissingComponentError` exception by default. TNF)skipMissingComponentsreverseFlippedrbool | ReverseFlippedctj|i|||_| |jjn||_|durt j|_dS|durt j|_dSt ||_dS)a=Takes a 'glyphSet' argument (dict), in which the glyphs that are referenced as components are looked up by their name. If the optional 'reverseFlipped' argument is True or a ReverseFlipped enum value, components whose transformation matrix has a negative determinant will be decomposed with a reversed path direction to compensate for the flip. The reverseFlipped parameter can be: - False or ReverseFlipped.NO: Don't reverse flipped components - True or ReverseFlipped.KEEP_START: Reverse, keeping original starting point - ReverseFlipped.ON_CURVE_FIRST: Reverse, ensuring first point is on-curve The optional 'skipMissingComponents' argument can be set to True/False to override the homonymous class attribute for a given pen instance. NFT) superrQglyphSet __class__rrrrr )r/rrrargsr(rs r$rQzDecomposingPointPen.__init__Fs. $)&)))  %, N 0 0& " U " ""0"3D    t # #"0";D   "0"@"@D   r#c ddlm} |j|}|}|tkr |||}|jt jkrS|dd\}} } } || z| | zz dkr5t|}|jt jkrddl m } | |}| |dS#t$r7|j st||jd|zYdSwxYw)zTransform the points of the base glyph and draw it onto self. The `identifier` parameter and any extra kwargs are ignored. r)TransformPointPenN)OnCurveFirstPointPenz,glyph '%s' is missing from glyphSet; skipped)fontTools.pens.transformPenrrr rrrrr!fontTools.pens.filterPenr drawPointsKeyErrorrrlogwarning) r/r>r@r&r(rglyphriabcdrs r$rCz DecomposingPointPen.addComponentlsO BAAAAA "M-0EC))''^<<"n&777,BQB/ 1aq51q5=1$$055C*n.KKKQQQQQQ32377   S ! ! ! ! !1   - ;+M::: H  >N       s B--=C.-C.)rrrK) rrrrrrrQrC __classcell__)rs@r$rr4s  !1 #05 $A$A$A$A$A$A$A$AL!"!"!"!"!"!"!"!"r#r)&r __future__rrtypingrrrrrfontTools.misc.enumToolsr fontTools.misc.loggingToolsr fontTools.misc.transformr r fontTools.pens.basePenr rr__all__floatPointr? PointNamer9SegmentPointList SegmentTyperTrrrrrrrrr"r#r$rs  #""""" 33333333333333,,,,,,000000BBBBBBBBOOOOOOOOOO    eUl SM huotYCDEsm 5&6678  & & & & &W & & &////////dbIbIbIbIbI,bIbIbIJR4R4R4R4R4-R4R4R4jU4U4U4U4U4 U4U4U4pWTWTWTWTWT*WTWTWTtZUZUZUZUZU-ZUZUZUzY"Y"Y"Y"Y"($4Y"Y"Y"Y"Y"r#