)Ej> dZddlmZmZmZddlmZddlZddlm Z  ddl Z n#e e f$r ddl m Z YnwxYwe jZdZe dgd Zgd ZdWd Zd Ze je je je je je je je je je je jdZe je je je je je je je je je jdWdZdZdZe je je je je je je jdZe je je je je je jdZ dZ!e je je je je je je je je je je je je je je je je je jdZ"dZ#e je je je je je je je je je j d!Z$d"Z%d#Z&e je je je je je je je je je je je je j$d%Z'd&Z(d'Z)d(Z*d)Z+d*Z,d+Z-e je je je je je je je je j,d-Z.e je je je je je je je je je je j.e je je je je j/d0Z/d1Z0d2Z1e je je je je je je je je je je je je je j3 d4Z2dd5lm3Z3m4Z4m5Z5m6Z6e3fd6Z7d7Z8d8Z9d9Z:e je je je je je je je je je j:d;Z;d<Zd?Z>d@Z?dAZ@dBZAe je je je je je je je jCe je je je jDdEZBdFZCdGZDdHZEdIZFdJZGdKZHdLZIdMZJdNZK dXdPZLdQZMdRZNdSZOdTZPdUZQeRdVkr,ddlSZSddlTZTeSjUeTjVjWdSdS)YzNfontTools.misc.bezierTools.py -- tools for working with Bezier path segments. ) calcBoundssectRectrectArea)IdentityN) namedtuple)cythong& .> Intersectionptt1t2)approximateCubicArcLengthapproximateCubicArcLengthCapproximateQuadraticArcLengthapproximateQuadraticArcLengthCcalcCubicArcLengthcalcCubicArcLengthCcalcQuadraticArcLengthcalcQuadraticArcLengthCcalcCubicBoundscalcQuadraticBounds splitLinesplitQuadratic splitCubicsplitQuadraticAtT splitCubicAtTsplitCubicAtTCsplitCubicIntoTwoAtTCsolveQuadratic solveCubicquadraticPointAtT cubicPointAtTcubicPointAtTC linePointAtTsegmentPointAtTlineLineIntersectionscurveLineIntersectionscurveCurveIntersectionssegmentSegmentIntersections{Gzt?c`tt|t|t|t||S)aCalculates the arc length for a cubic Bezier segment. Whereas :func:`approximateCubicArcLength` approximates the length, this function calculates it by "measuring", recursively dividing the curve until the divided segments are shorter than ``tolerance``. Args: pt1,pt2,pt3,pt4: Control points of the Bezier as 2D tuples. tolerance: Controls the precision of the calcuation. Returns: Arc length value. )rcomplex)pt1pt2pt3pt4 tolerances LC:\PYTHON\MyICR_Suite\python\Lib\site-packages\fontTools/misc/bezierTools.pyrr8s1  w}gsmWc]I  c||d||zzz|zdz}||z|z |z dz}|||zdz||z |f|||z||zdz|ffS)Ng??)p0p1p2p3midderiv3s r2_split_cubic_into_twor>Kso R"W  "e +C2glR5 (F b2g_cFlC0 cFlR"WOR0 r3)r8r9r:r;)multarchboxc(t||z }t||z t||z zt||z z}||ztz|kr||zdzSt||||\}}t|g|Rt|g|RzSNr6)absEPSILONr>_calcCubicArcLengthCRecurse) r?r8r9r:r;r@rAonetwos r2rFrFTs rBw<>> calcQuadraticArcLength((0, 0), (0, 0), (0, 0)) # empty segment 0.0 >>> calcQuadraticArcLength((0, 0), (50, 0), (80, 0)) # collinear points 80.0 >>> calcQuadraticArcLength((0, 0), (0, 50), (0, 80)) # collinear points vertical 80.0 >>> calcQuadraticArcLength((0, 0), (50, 20), (100, 40)) # collinear points 107.70329614269008 >>> calcQuadraticArcLength((0, 0), (0, 100), (100, 0)) 154.02976155645263 >>> calcQuadraticArcLength((0, 0), (0, 50), (100, 0)) 120.21581243984076 >>> calcQuadraticArcLength((0, 0), (50, -10), (80, 50)) 102.53273816445825 >>> calcQuadraticArcLength((0, 0), (40, 0), (-40, 0)) # collinear points, control point outside 66.66666666666667 >>> calcQuadraticArcLength((0, 0), (40, 0), (0, 0)) # collinear points, looping back 40.0 )rr,r-r.r/s r2rrs#@ #7C='3-# O OOr3)r-r.r/d0d1dn)scaleorigDistabx0x1Lenc8||z }||z }||z }|dz}t|}|dkrt||z St||}t|tkrUt||dkrt||z St|t|} } | | z| | zz| | zz St|||z } t|||z } tdt| t| z z|z|| | z zz } | S)a$Calculates the arc length for a quadratic Bezier segment. Args: pt1: Start point of the Bezier as a complex number. pt2: Handle point of the Bezier as a complex number. pt3: End point of the Bezier as a complex number. Returns: Arc length value. y?rrX)rDrTepsilonr])r-r.r/r`rarbrcrdrerfrgrhrirjs r2rrs@ sB sB RA BA FFE ||39~~Ar{{H 8}}w B<<1  sSy>> !2wwB1AA !a%(( ax B ax B a;r??[__45@ERRTWDUV W WC Jr3cNtt|t|t|S)aCalculates the arc length for a quadratic Bezier segment. Uses Gauss-Legendre quadrature for a branch-free approximation. See :func:`calcQuadraticArcLength` for a slower but more accurate result. Args: pt1: Start point of the Bezier as 2D tuple. pt2: Handle point of the Bezier as 2D tuple. pt3: End point of the Bezier as 2D tuple. Returns: Approximate arc length value. )rr,r_s r2rrs# *'3-#QT V VVr3r_)v0rNrOctd|zd|zzd|zz}t||z dz}td|zd|zz d|zz}||z|zS)aCalculates the arc length for a quadratic Bezier segment. Uses Gauss-Legendre quadrature for a branch-free approximation. See :func:`calcQuadraticArcLength` for a slower but more accurate result. Args: pt1: Start point of the Bezier as a complex number. pt2: Handle point of the Bezier as a complex number. pt3: End point of the Bezier as a complex number. Returns: Approximate arc length value. g̔xb߿gb?gFVW?gqq?gFVWg̔xb?rD)r-r.r/rorNrOs r2rrsB S #4s#::=ORU=UU  B S3Y, ,B c!$5$;;>ORU>UU  B 7R<r3c, t|||\\\ \ dz}dz}g}|dkr| |z |dkr| |z  fd|D||gz}t|S)aCalculates the bounding rectangle for a quadratic Bezier segment. Args: pt1: Start point of the Bezier as a 2D tuple. pt2: Handle point of the Bezier as a 2D tuple. pt3: End point of the Bezier as a 2D tuple. Returns: A four-item tuple representing the bounding rectangle ``(xMin, yMin, xMax, yMax)``. Example:: >>> calcQuadraticBounds((0, 0), (50, 100), (100, 0)) (0, 0, 100, 50.0) >>> calcQuadraticBounds((0, 0), (100, 0), (100, 100)) (0.0, 0.0, 100, 100) @rctg|]4}d|cxkrdknn"|z|z|zzz|z|z|zzzf5SrrYr7).0taxaybxbycxcys r2 z'calcQuadraticBounds..Dsk ::::A::::: a!b1f r !26A:Q#6#;< ::r3)calcQuadraticParametersappendr) r-r.r/ax2ay2rootspointsrxryrzr{r|r}s @@@@@@r2rr*s$$;3S#I#I HRhr2R s(C s(C E axx bS3Y axx bS3Y c F f  r3c^tt|t|t|t|S)aApproximates the arc length for a cubic Bezier segment. Uses Gauss-Lobatto quadrature with n=5 points to approximate arc length. See :func:`calcCubicArcLength` for a slower but more accurate result. Args: pt1,pt2,pt3,pt4: Control points of the Bezier as 2D tuples. Returns: Arc length value. Example:: >>> approximateCubicArcLength((0, 0), (25, 100), (75, 100), (100, 0)) 190.04332968932817 >>> approximateCubicArcLength((0, 0), (50, 0), (100, 50), (100, 100)) 154.8852074945903 >>> approximateCubicArcLength((0, 0), (50, 0), (100, 0), (150, 0)) # line; exact result should be 150. 149.99999999999991 >>> approximateCubicArcLength((0, 0), (50, 0), (100, 0), (-50, 0)) # cusp; exact result should be 150. 136.9267662156362 >>> approximateCubicArcLength((0, 0), (50, 0), (100, -50), (-50, 0)) # cusp 154.80848416537057 )rr,rIs r2rrLs/2 & w}gsmWc]  r3)rorNrOv3v4c8t||z dz}td|zd|zzd|zzd|zz}t||z |z|z dz}td|zd|zz d|zz d|zz}t||z dz}||z|z|z|zS) zApproximates the arc length for a cubic Bezier segment. Args: pt1,pt2,pt3,pt4: Control points of the Bezier as complex numbers. Returns: Arc length value. g333333?gc1g85$t?gu|Y?g#$?g?g#$gc1?rq) r-r.r/r0rorNrOrrs r2rrjs> S3Y$ B S c ! " c ! " c ! "  B S3Y_s " # #&9 9B S c ! " c ! " c ! "  B S3Y$ B 7R<" r !!r3cH t||||\\ \\\ dz} dz}dz}dz}dt||D}dt||D} || z} fd| D||gz} t| S)aXCalculates the bounding rectangle for a quadratic Bezier segment. Args: pt1,pt2,pt3,pt4: Control points of the Bezier as 2D tuples. Returns: A four-item tuple representing the bounding rectangle ``(xMin, yMin, xMax, yMax)``. Example:: >>> calcCubicBounds((0, 0), (25, 100), (75, 100), (100, 0)) (0, 0, 100, 75.0) >>> calcCubicBounds((0, 0), (50, 0), (100, 50), (100, 100)) (0.0, 0.0, 100, 100) >>> print("%f %f %f %f" % calcCubicBounds((50, 0), (0, 100), (100, 100), (50, 0))) 35.566243 0.000000 64.433757 75.000000 @rsc2g|]}d|cxkrdknn|Srur7rvrws r2r~z#calcCubicBounds..- D D DAa!ar3c2g|]}d|cxkrdknn|Srur7rs r2r~z#calcCubicBounds..rr3cg|]<}|z|z|z|z|zz|zzz|z|z|z|z|zz|zz zf=Sr7r7) rvrwrxryrzr{r|r}dxdys r2r~z#calcCubicBounds..s  FQJNR!VaZ '"q& 02 5 FQJNR!VaZ '"q& 02 5 r3)calcCubicParametersrr)r-r.r/r0ax3ay3bx2by2xRootsyRootsrrrxryrzr{r|r}rrs @@@@@@@@r2rrs$.Ac3PS-T-T*HRhr2R(2r s(C s(C s(C s(C D DS"55 D D DF D DS"55 D D DF VOE   c F f  r3c|\}}|\}}||z }||z } |} |} || f|} | dkr||fgS|| | f|z | z } d| cxkrdkrnn|| z| z| | z| zf}||f||fgS||fgS)a Split a line at a given coordinate. Args: pt1: Start point of line as 2D tuple. pt2: End point of line as 2D tuple. where: Position at which to split the line. isHorizontal: Direction of the ray splitting the line. If true, ``where`` is interpreted as a Y coordinate; if false, then ``where`` is interpreted as an X coordinate. Returns: A list of two line segments (each line segment being two 2D tuples) if the line was successfully split, or a list containing the original line. Example:: >>> printSegments(splitLine((0, 0), (100, 100), 50, True)) ((0, 0), (50, 50)) ((50, 50), (100, 100)) >>> printSegments(splitLine((0, 0), (100, 100), 100, True)) ((0, 0), (100, 100)) >>> printSegments(splitLine((0, 0), (100, 100), 0, True)) ((0, 0), (0, 0)) ((0, 0), (100, 100)) >>> printSegments(splitLine((0, 0), (100, 100), 0, False)) ((0, 0), (0, 0)) ((0, 0), (100, 100)) >>> printSegments(splitLine((100, 0), (0, 0), 50, False)) ((100, 0), (50, 0)) ((50, 0), (0, 0)) >>> printSegments(splitLine((0, 100), (0, 0), 50, True)) ((0, 100), (0, 50)) ((0, 50), (0, 0)) rrYr7)r-r.where isHorizontalpt1xpt1ypt2xpt2yrxryrzr{rfrwmidPts r2rrsHJD$JD$ B B B B RAAvvc | "b,' '1,AAzzzzzzzzzQ R!Vb[(e ucl++c |r3ct|||\}}}t|||||||z }td|D}|s|||fgSt|||g|RS)aSplit a quadratic Bezier curve at a given coordinate. Args: pt1,pt2,pt3: Control points of the Bezier as 2D tuples. where: Position at which to split the curve. isHorizontal: Direction of the ray splitting the curve. If true, ``where`` is interpreted as a Y coordinate; if false, then ``where`` is interpreted as an X coordinate. Returns: A list of two curve segments (each curve segment being three 2D tuples) if the curve was successfully split, or a list containing the original curve. Example:: >>> printSegments(splitQuadratic((0, 0), (50, 100), (100, 0), 150, False)) ((0, 0), (50, 100), (100, 0)) >>> printSegments(splitQuadratic((0, 0), (50, 100), (100, 0), 50, False)) ((0, 0), (25, 50), (50, 50)) ((50, 50), (75, 50), (100, 0)) >>> printSegments(splitQuadratic((0, 0), (50, 100), (100, 0), 25, False)) ((0, 0), (12.5, 25), (25, 37.5)) ((25, 37.5), (62.5, 75), (100, 0)) >>> printSegments(splitQuadratic((0, 0), (50, 100), (100, 0), 25, True)) ((0, 0), (7.32233, 14.6447), (14.6447, 25)) ((14.6447, 25), (50, 75), (85.3553, 25)) ((85.3553, 25), (92.6777, 14.6447), (100, -7.10543e-15)) >>> # XXX I'm not at all sure if the following behavior is desirable: >>> printSegments(splitQuadratic((0, 0), (50, 100), (100, 0), 50, True)) ((0, 0), (25, 50), (50, 50)) ((50, 50), (50, 50), (50, 50)) ((50, 50), (75, 50), (100, 0)) c3:K|]}d|cxkrdknn|VdSrrYNr7rs r2 z!splitQuadratic.."6::QqAzzzzzzzzzqzzzz::r3)rrsorted_splitQuadraticAtT) r-r.r/rrrfrgc solutionss r2rrsF&c344GAq! ,<!L/E*AI::):::::I !c3  aA 2 2 2 22r3ct||||\}}}} t||||||| ||z } td| D} | s||||fgSt|||| g| RS)aSplit a cubic Bezier curve at a given coordinate. Args: pt1,pt2,pt3,pt4: Control points of the Bezier as 2D tuples. where: Position at which to split the curve. isHorizontal: Direction of the ray splitting the curve. If true, ``where`` is interpreted as a Y coordinate; if false, then ``where`` is interpreted as an X coordinate. Returns: A list of two curve segments (each curve segment being four 2D tuples) if the curve was successfully split, or a list containing the original curve. Example:: >>> printSegments(splitCubic((0, 0), (25, 100), (75, 100), (100, 0), 150, False)) ((0, 0), (25, 100), (75, 100), (100, 0)) >>> printSegments(splitCubic((0, 0), (25, 100), (75, 100), (100, 0), 50, False)) ((0, 0), (12.5, 50), (31.25, 75), (50, 75)) ((50, 75), (68.75, 75), (87.5, 50), (100, 0)) >>> printSegments(splitCubic((0, 0), (25, 100), (75, 100), (100, 0), 25, True)) ((0, 0), (2.29379, 9.17517), (4.79804, 17.5085), (7.47414, 25)) ((7.47414, 25), (31.2886, 91.6667), (68.7114, 91.6667), (92.5259, 25)) ((92.5259, 25), (95.202, 17.5085), (97.7062, 9.17517), (100, 1.77636e-15)) c3:K|]}d|cxkrdknn|VdSrr7rs r2rzsplitCubic..Grr3)rr r_splitCubicAtT) r-r.r/r0rrrfrgrrbrs r2rr(s6%S#sC88JAq!Q ,<!L/1\?U;RI::):::::I &c3$%% !Q1 1y 1 1 11r3cJt|||\}}}t|||g|RS)aSplit a quadratic Bezier curve at one or more values of t. Args: pt1,pt2,pt3: Control points of the Bezier as 2D tuples. *ts: Positions at which to split the curve. Returns: A list of curve segments (each curve segment being three 2D tuples). Examples:: >>> printSegments(splitQuadraticAtT((0, 0), (50, 100), (100, 0), 0.5)) ((0, 0), (25, 50), (50, 50)) ((50, 50), (75, 50), (100, 0)) >>> printSegments(splitQuadraticAtT((0, 0), (50, 100), (100, 0), 0.5, 0.75)) ((0, 0), (25, 50), (50, 50)) ((50, 50), (62.5, 50), (75, 37.5)) ((75, 37.5), (87.5, 25), (100, 0)) )rr)r-r.r/tsrfrgrs r2rrMs5(&c344GAq! aA + + + ++r3ct||||\}}}}t||||g|R} |g| dddR| d<g| ddd|R| d<| S)aSplit a cubic Bezier curve at one or more values of t. Args: pt1,pt2,pt3,pt4: Control points of the Bezier as 2D tuples. *ts: Positions at which to split the curve. Returns: A list of curve segments (each curve segment being four 2D tuples). Examples:: >>> printSegments(splitCubicAtT((0, 0), (25, 100), (75, 100), (100, 0), 0.5)) ((0, 0), (12.5, 50), (31.25, 75), (50, 75)) ((50, 75), (68.75, 75), (87.5, 50), (100, 0)) >>> printSegments(splitCubicAtT((0, 0), (25, 100), (75, 100), (100, 0), 0.5, 0.75)) ((0, 0), (12.5, 50), (31.25, 75), (50, 75)) ((50, 75), (59.375, 75), (68.75, 68.75), (77.3438, 56.25)) ((77.3438, 56.25), (85.9375, 43.75), (93.75, 25), (100, 0)) rrYN)rr) r-r.r/r0rrfrgrrbsplits r2rres(%S#sC88JAq!Q 1aA + + + +E #eAhqrrl##E!H&%)CRC.&#&&E"I Lr3)r-r.r/r0rfrgrrbc'dKt||||\}}}}t||||g|REd{VdS)aSplit a cubic Bezier curve at one or more values of t. Args: pt1,pt2,pt3,pt4: Control points of the Bezier as complex numbers.. *ts: Positions at which to split the curve. Yields: Curve segments (each curve segment being four complex numbers). N)calcCubicParametersC_splitCubicAtTC) r-r.r/r0rrfrgrrbs r2rrsW(&c3S99JAq!Qq!Q/B////////////r3)rwr-r.r/r0pointAtToff1off2)r _1_t_1_t_2_2_t_1_tc||z}d|z }||z}d|z|z}||z|zd||z|z||z|zzzz||z|zz} ||z||zz||zz} ||z||zz||zz} |||z |zz}|||z |zz}||| | f| | ||ffS)aSplit a cubic Bezier curve at t. Args: pt1,pt2,pt3,pt4: Control points of the Bezier as complex numbers. t: Position at which to split the curve. Returns: A tuple of two curve segments (each curve segment being four complex numbers). rYrXr5r7) r-r.r/r0rwr rrrrrrs r2rrs0 QB q5D D[F1ut|H a6A:#3dRi#o#EFFaRUU  C<(S. (28 3D C<(S. (28 3D sa C sd" "C #tX &4c(B CCr3ct|}g}|dd|d|\}}|\}}|\} } tt |dz D]} || } || dz} | | z }||z}||z}||z}d|z| z|z|z}d|z| z|z|z}| | z}||z|| zz| z}||z|| zz| z}t ||f||f||f\}}}||||f|S)NrrlrKrYrX)listinsertrrangelencalcQuadraticPoints)rfrgrrsegmentsrxryrzr{r|r}ir r deltadelta_2a1xa1yb1xb1yt1_2c1xc1yr-r.r/s r2rrsS bBHIIaIIcNNN FB FB FB 3r77Q;  )) U AYR%-7l7l2v{R5(2v{R5(Bw4i"r'!B&4i"r'!B&+S#Jc S#JOO S#c3(((( Or3ct|}|dd|dg}|\}}|\}} |\} } |\} } tt |dz D]}||}||dz}||z }||z}||z}||z}||z}||z}||z}d|z|z|z|z}d|z|z| z|z}d|z|z| zd|z|zz|z}d| z|z| zd|z|zz|z}||z||zz| |zz| z}||z| |zz| |zz| z}t ||f||f||f||f\}}} }!|||| |!f|SNrrlrKrYr5rX)rrrrrcalcCubicPoints)"rfrgrrbrrrxryrzr{r|r}rrrr r rrdelta_3rt1_3rrrrrrd1xd1yr-r.r/r0s" r2rrs bBIIaIIcNNNH FB FB FB FB 3r77Q;  .. U AYR%-'/BwDy7l7l2v{R7*2v{R7*2v{R!b&4-/582v{R!b&4-/584i"t)#b2g-24i"t)#b2g-2, #Jc S#Jc   S#s c3,---- Or3) rfrgrrbr r rrra1b1c1rac'Kt|}|dd|dtt |dz D]}||}||dz}||z }||z} || z} ||z} || z} || z} d|z|z|z| z}d|z|z|zd|z| zz|z}|| z|| zz||zz|z}t | |||\}}}}||||fVdSr)rrrrrcalcCubicPointsC)rfrgrrbrrr r rrrrrrrrrar-r.r/r0s r2rrs< bBIIaIIcNNN 3r77Q;  ## U AYR%-'/BwDy[!ebj1n '!ebj1nq1ut|+u 4 XD 1r6 )A --b"b"==S#sCc"""""!##r3)r[acoscospict|tkr#t|tkrg}nB| |z g}n:||zd|z|zz }|dkr$||}| |zdz |z | |z dz |z g}ng}|S)uKSolve a quadratic equation. Solves *a*x*x + b*x + c = 0* where a, b and c are real. Args: a: coefficient of *x²* b: coefficient of *x* c: constant term Returns: A list of roots. Note that the returned list is neither guaranteed to be sorted nor to contain unique values! @rlrsrDrm)rfrgrr[rDDrDDs r2rr/s 1vv q66G  EER!VHEEUS1Wq[  99$r((Cb3h#%)QBH+;a+?@EEE Lr3c  t|tkrt|||St|}||z }||z }||z }||zd|zz dz }d|z|z|zd|z|zz d|zzdz }||z} ||z|z} | tkrdn| } t| tkrdn| } | | z } | dkr$| dkrt | dz t } | | | gS| tdzkrt tt|t| z d d } d t|z}|dz }|t| dz z|z }|t| dtzzdz z|z }|t| d tzzdz z|z }t|||g\}}}||z tkr1||z tkr#t ||z|zdz t x}x}}n||z tkr3t ||zdz t x}}t |t }n||z tkr3t |t }t ||zdz t x}}n?t |t }t |t }t |t }|||gStt| t|zd } | || z z} |dkr| } t | |dz z t } | gS)utSolve a cubic equation. Solves *a*x*x*x + b*x*x + c*x + d = 0* where a, b, c and d are real. Args: a: coefficient of *x³* b: coefficient of *x²* c: coefficient of *x* d: constant term Returns: A list of roots. Note that the returned list is neither guaranteed to be sorted nor to contain unique values! Examples:: >>> solveCubic(1, 1, -6, 0) [-3.0, -0.0, 2.0] >>> solveCubic(-10.0, -9.0, 48.0, -29.0) [-2.9, 1.0, 1.0] >>> solveCubic(-9.875, -9.0, 47.625, -28.75) [-2.911392, 1.0, 1.0] >>> solveCubic(1.0, -4.5, 6.75, -3.375) [1.5, 1.5, 1.5] >>> solveCubic(-12.0, 18.0, -9.0, 1.50023651123) [0.5, 0.5, 0.5] >>> solveCubic( ... 9.0, 0.0, 0.0, -7.62939453125e-05 ... ) == [-0.0, -0.0, -0.0] True rg"@rsg;@gK@rrlr6rKggrUUUUUU?)rDrmrfloatround epsilonDigitsrmaxminr[rrrpow)rfrgrrbra2a3QRR2Q3R2_Q3rVthetarQ2a1_3rhrix2s r2r r Ps0L 1vvaA&&& aA QB QB QB b38 s"A rB cBhm +dRi 74?A QB QB7llB"ggRB GE SyyR3YY 2#)] + +1ay 'C-  SQb\3//6677T!WWnCx 3us{## #d * 3b(C/00 04 7 3b(C/00 04 7RRL)) B 7W  b7!2!2 "r'B,#!5}EE EB Ebb "Ww  R"WO];; ;Br=))BB "Ww  r=))BR"WO];; ;Br=))Br=))Br=))BB| U c!ff$g . . AI 88A !b3h, . .s r3cv|\}}|\}}|\}}||z dz} ||z dz} ||z | z } ||z | z } | | f| | f||ffS)Nrsr7) r-r.r/ry2x3y3r|r}rzr{rxrys r2rrsj FB FB FB r'SB r'SB b2B b2B 8b"XBx ''r3c|\}}|\}}|\}} |\} } || z dz} || z dz} ||z dz| z }||z dz| z }|| z | z |z }| | z | z |z }||f||f| | f| | ffSNrr7)r-r.r/r0rrrrx4y4rrr|r}rzr{rxrys r2rrs FB FB FB FB r'SB r'SB r'S2 B r'S2 B b2 B b2 B 8b"XBx"b 11r3)r-r.r/r0rfrgrcJ||z dz}||z dz|z }||z |z |z }||||fSrr7)r-r.r/r0rrgrfs r2rrsE scA scAA c A A q!S>r3c~|\}}|\}}|\}}|} |} |dz|z} |dz|z} ||z|z} ||z|z}| | f| | f| |ffSrCr7)rfrgrrxryrzr{r|r}riy1rrrrs r2rrst FB FB FB B B s(bB s(bB b2B b2B 8b"XBx ''r3c|\}}|\}}|\}} |\} } | } | } |dz | z}| dz | z}||zdz |z}|| zdz |z}|| z|z|z}|| z| z|z}| | f||f||f||ffSrr7)rfrgrrbrxryrzr{r|r}rrrirrrrrrrs r2rrs FB FB FB FB B B s(bB s(bB r'S2 B r'S2 B b2 B b2 B 8b"XBx"b 11r3rfrgrrbr:r;p4cJ|dz|z}||zdz|z}||z|z|z}||||fS)Nrr7rs r2rrsC eqB a%E R B QQB r2r?r3cj|dd|z z|d|zz|dd|z z|d|zzfS)zFinds the point at time `t` on a line. Args: pt1, pt2: Coordinates of the line as 2D tuples. t: The time along the line. Returns: A 2D tuple with the coordinates of the point. rrYr7)r-r.rws r2r$r$sCVq1u A *c!fA.>Q!.K MMr3cd|z d|z z|dzdd|z z|z|dzz||z|dzz}d|z d|z z|dzdd|z z|z|dzz||z|dzz}||fS)zFinds the point at time `t` on a quadratic curve. Args: pt1, pt2, pt3: Coordinates of the curve as 2D tuples. t: The time along the curve. Returns: A 2D tuple with the coordinates of the point. rYrrXr7)r-r.r/rwrVys r2r!r!s Q1q5CF"Q!a%[1_s1v%==AANA Q1q5CF"Q!a%[1_s1v%==AANA q6Mr3c ||z}d|z }||z}||z|dzd||z|dz||z|dzzzz||z|dzz}||z|dzd||z|dz||z|dzzzz||z|dzz} || fS)zFinds the point at time `t` on a cubic curve. Args: pt1, pt2, pt3, pt4: Coordinates of the curve as 2D tuples. t: The time along the curve. Returns: A 2D tuple with the coordinates of the point. rYrr5r7) r-r.r/r0rwr rrrVrs r2r"r",s QB q5D D[F A vzCF"TBYQ%77 8 9 q&3q6/   A vzCF"TBYQ%77 8 9 q&3q6/  q6Mr3)rwr-r.r/r0)r rrcl||z}d|z }||z}||z|zd||z|z||z|zzzz||z|zzS)zFinds the point at time `t` on a cubic curve. Args: pt1, pt2, pt3, pt4: Coordinates of the curve as complex numbers. t: The time along the curve. Returns: A complex number with the coordinates of the point. rYr5r7)r-r.r/r0rwr rrs r2r#r#Fs]& QB q5D D[F D=3 fqj3&6S&H!I IBQRFUXL XXr3ct|dkrtg||RSt|dkrtg||RSt|dkrtg||RSt dNrXr5Unknown curve degree)rr$r!r" ValueError)segrws r2r%r%_s 3xx1}}$S$!$$$$ SQ )#)q)))) SQ%c%1%%%% + , ,,r3c|\}}|\}}|\}}t||z tkrt||z tkrdSt||z t||z kr ||z ||z z S||z ||z z S)Nrr) ser sxsyexeypxpys r2 _line_t_of_ptrns FB FB FB 27||g#b2g,,"8"8r 27||c"r'll""RBG$$RBG$$r3c|d|dz |d|dz z}|d|dz |d|dz z}|dko|dk S)NrrYrlr7)rfrgoriginxDiffyDiffs r2'_both_points_are_on_same_side_of_originr|s` qTF1I !A$"2 3E qTF1I !A$"2 3E -# ..r3c |\}}|\}}|\}} |\} } tj|| r,tj||rtj||sgStj| | r,tj||rtj|| sgStj|| rtj| | rgStj||rtj||rgStj||rM|} | | z | |z z } | | |z z| z}| |f}t|t|||t|||gStj|| rM|} ||z ||z z }|| |z z|z}| |f}t|t|||t|||gS||z ||z z }| | z | |z z } tj|| rgS||z|z | |zz | z|| z z } || |z z|z}| |f}t |||rBt |||r1t|t|||t|||gSgS)aFinds intersections between two line segments. Args: s1, e1: Coordinates of the first line as 2D tuples. s2, e2: Coordinates of the second line as 2D tuples. Returns: A list of ``Intersection`` objects, each object having ``pt``, ``t1`` and ``t2`` attributes containing the intersection point, time on first segment and time on second segment respectively. Examples:: >>> a = lineLineIntersections( (310,389), (453, 222), (289, 251), (447, 367)) >>> len(a) 1 >>> intersection = a[0] >>> intersection.pt (374.44882952482897, 313.73458370177315) >>> (intersection.t1, intersection.t2) (0.45069111555824465, 0.5408153767394238) r )rZiscloser rr)s1e1s2e2s1xs1ye1xe1ys2xs2ye2xe2yrVslope34rr slope12s r2r&r&s.HCHCHCHC S##'<S#9#9BF,sTWBXBX  S##'<S#9#9BF,sTWBXBX  |C$,sC"8"8  |C$,sC"8"8  |C  9s+ q3w # %V -B33 b"b8Q8Q      |C  9s+ q3w # %V -B33 b"b8Q8Q     SyS3Y'GSyS3Y'G |GW%% 3 w} ,s 2w7HIA1s7c!A QB. B 1"b" = =  -B33 b"b8Q8Q     Ir3c|d}|d}tj|d|dz |d|dz }tj| |d |d S)NrrrY)rZatan2rrotate translate)segmentstartendangles r2_alignment_transformationr5so AJE "+C Js1va(#a&58*; < .s6<<cQmmmm!mmmmm!mmmm<s-d33CCEJJM 5zzQ)=91a&qtQqT1Q488 Uq(-8 1a"1Q41qtQqT:: /000 <<]<<< < <>> curve = [ (100, 240), (30, 60), (210, 230), (160, 30) ] >>> line = [ (25, 260), (230, 20) ] >>> intersections = curveLineIntersections(curve, line) >>> len(intersections) 3 >>> intersections[0].pt (84.9000930760723, 189.87306176459828) r5r r r ) rr!r"r r>rr$rr )r:r; pointFinderr=rwr line_ts r2r'r's* 5zzQ' Uq# /000M ( 5 5CC [ #% # # # #))b)))  (4 ( ( ( (\RA&AAABBBB r3ct|dkr t|St|dkr t|Std)Nr5r r )rrrr )rs r2 _curve_boundsrC sE 1vv{{"A&& Q1"" + , ,,r3ct|dkr|\}}t|||}||f||fgSt|dkrtg||RSt|dkrtg||RSt dr )rr$rrr )rrwrrmidpoints r2_split_segment_at_trFs 1vv{{11a((H !}-- 1vv{{ '!'Q'''' Q1#a##### + , ,,r3MbP?c t|}t|}|sd}|sd}t||\}}|sgSd} t|kr*t|kr| || |fgSt|d\} } |d| |f} | ||df} t|d\}}|d| |f}| ||df}g}|t | || ||t | || ||t | || ||t | || |fd}t }g}|D]<}||}||vr||||=|S)N)rlrKc*d|d|dzzS)Nr6rrYr7)rs r2rEz._curve_curve_intersections_t..midpoint1sadQqTk""r3r6rrY)range1range2cdt|dz t|dz fS)NrrY)int)r precisions r2z._curve_curve_intersections_t..Vs.SA!233SA9J5K5KLr3) rCrrrFextend_curve_curve_intersections_tsetaddr)curve1curve2rOrKrLbounds1bounds2 intersects_rEc11c12 c11_range c12_rangec21c22 c21_range c22_rangefound unique_keyseen unique_valuesrkeys ` r2rRrR!sF##GF##G  Wg..MJ  ###9$$'):):Y)F)F&!!88F#3#3455"63//HCHHV,,-I&!!6!9-I"63//HCHHV,,-I&!!6!9-I E LL$ i )     LL$ i )     LL$ i )     LL$ i )    MLLLJ 55DM!!jnn $;;   R    r3cxt||}td|DS)Nc3LK|]}tj|ddV dS)rYrlN)rZr)rvps r2rz_is_linelike..fs2::1t|AaD#&&::::::r3)r5r9all)r1 maybelines r2 _is_linelikermds:)'22BB7KKI :: ::: : ::r3cntrYddf}t|r|d|df}tg||RSt||}d|DSt|r |d|df}t|St|}fd|DS)a Finds intersections between a curve and a curve. Args: curve1: List of coordinates of the first curve segment as 2D tuples. curve2: List of coordinates of the second curve segment as 2D tuples. Returns: A list of ``Intersection`` objects, each object having ``pt``, ``t1`` and ``t2`` attributes containing the intersection point, time on first segment and time on second segment respectively. Examples:: >>> curve1 = [ (10,100), (90,30), (40,140), (220,220) ] >>> curve2 = [ (5,150), (180,20), (80,250), (210,190) ] >>> intersections = curveCurveIntersections(curve1, curve2) >>> len(intersections) 3 >>> intersections[0].pt (81.7831487395506, 109.88904552375288) rrcPg|]#}t|j|j|j$Sr r r r r rvrVs r2r~z+curveCurveIntersections..s-JJJLADQTad;;;JJJr3c tg|]4}tt|d|d|d5S)rrYr )r r%)rvrrUs r2r~z+curveCurveIntersections..sN     1662a5RUKKK   r3)rmr&r'rR)rUrVline1line2hitsintersection_tss` r2r(r(is*F 5q 6":%    K1Ivbz)E(8%8%888 8)&%88DKJTJJJ J f  5q 6":%%fe444266BBO    !   r3cd}t|t|kr||}}d}t|dkr5t|dkrt||}nUt||}nDt|dkr"t|dkrtg||R}nt d|s|Sd|DS)a)Finds intersections between two segments. Args: seg1: List of coordinates of the first segment as 2D tuples. seg2: List of coordinates of the second segment as 2D tuples. Returns: A list of ``Intersection`` objects, each object having ``pt``, ``t1`` and ``t2`` attributes containing the intersection point, time on first segment and time on second segment respectively. Examples:: >>> curve1 = [ (10,100), (90,30), (40,140), (220,220) ] >>> curve2 = [ (5,150), (180,20), (80,250), (210,190) ] >>> intersections = segmentSegmentIntersections(curve1, curve2) >>> len(intersections) 3 >>> intersections[0].pt (81.7831487395506, 109.88904552375288) >>> curve3 = [ (100, 240), (30, 60), (210, 230), (160, 30) ] >>> line = [ (25, 260), (230, 20) ] >>> intersections = segmentSegmentIntersections(curve3, line) >>> len(intersections) 3 >>> intersections[0].pt (84.9000930760723, 189.87306176459828) FTrXz4Couldn't work out which intersection function to usecPg|]#}t|j|j|j$Srprqr8s r2r~z/segmentSegmentIntersections..s- K K KLADQTad 3 3 3 K K Kr3)rr(r'r&r )seg1seg2swappedr=s r2r)r)s<G 4yy3t994d 4yy1}} t99q==3D$??MM24>>MM TaCIINN-;t;d;;; OPPP  K K] K K KKr3c t|}ddd|DzS#t$rd|zcYSwxYw)zw >>> _segmentrepr([1, [2, 3], [], [[2, [3, 4], [0.1, 2.2]]]]) '(1, (2, 3), (), ((2, (3, 4), (0.1, 2.2))))' z(%s)z, c34K|]}t|VdSrQ) _segmentreprrrs r2rz_segmentrepr..s(!>!>a,q//!>!>!>!>!>!>r3z%g)iterjoin TypeError)objits r2rrsg ? #YY !>!>2!>!>!>>>>> czs3AAcH|D]}tt|dS)zlHelper for the doctests, displaying each segment in a list of segments on a single line as a tuple. N)printr)rr1s r2 printSegmentsrs6%% l7##$$$$%%r3__main__)r*)rGNN)X__doc__fontTools.misc.arrayToolsrrrfontTools.misc.transformrrZ collectionsrrAttributeError ImportErrorfontTools.misccompiledCOMPILEDrEr __all__rr>returnsdoublelocalsr,rFrrrmcfuncinlinerTr]rrrrrrrrrrrrrrrrrrr[rrrrr rrrrrrr$r!r"r#r%rrr&r5r>r'rCrFrRrmr(r)rr__name__sysdoctestexittestmodfailedr7r3r2rsa EDDDDDDDDD------ """"""&MMMM $&&&%%%%%%%%& ? z.*<*<*<==    @&  ~ ~ ~ ~  FM 6=III   JI      m  A A A   A  &.V^444&&54& ;; ; P P PF  ~ ~ n n - ] m m } } &@WWW"   } } }   BD<    } } } } } !"!" !"H###L666r*3*3*3Z"2"2"2J,,,0> n n n n    0 0   0 m ^      }6=DD   D46   F n n n n } } - M M ~ ~ ~ ~###6%$$$$$$$$$$$"&BYYYB((( 2 2 2 n n n ( ( ( 2 2 2  n n n n ~ ~ ~ N N N   4 m &-fmFMJJJ Y YKJ  Y --- % % %/// KKK\CCC = = =###L--- - - -9=@@@@F;;; '''T-L-L-L` ? ? ?%%% zJJJNNN CH_W_   %&&&&& s # 33