L ivdZddlmZmZmZddlmZddlZddlm Z  ddl Z e jZdZe dgd Zgd ZdUd Zd Ze j*e j,e j.e j0e j0e j0e j0 e j.e j,e j,e j,dZe j*e j,e j.e j0e j0e j0e j0e j.e j,e j,dUdZdZdZe j:e j<e j*e j,e j.e j0e j0dZe j:e j<e j*e j,e j.e j,dZ dZ!e j*e j,e j.e j0e j0e j0e j0e j0e j0e j0e j.e j,e j,e j,e j,e j,e j,e j,dZ"dZ#e j*e j,e j.e j0e j0e j0e j.e j,e j,e j,d Z$d!Z%d"Z&e j*e j,e j.e j0e j0e j0e j0e j.e j,e j,e j,e j,e j,#d$Z'd%Z(d&Z)d'Z*d(Z+d)Z,d*Z-e j.e j0e j0e j0e j0e j0e j0e j0e j0+d,Z.e j*e j0e j.e j,e j0e j0e j0e j0e j0e j0e j0-e j.e j,e j,e j,e j,.d/Z/d0Z0d1Z1e j.e j0e j0e j0e j0e j,e j,e j,e j,e j,e j0e j0e j0e j02 d3Z2dd4lm3Z3m4Z4m5Z5m6Z6e3fd5Z7d6Z8d7Z9d8Z:e j:e j<e j.e j0e j0e j0e j0e j0e j0e j09d:Z;d;ZZ>d?Z?d@Z@dAZAe j*e j0e j.e j,e j0e j0e j0e j0Be j.e j,e j,e j,CdDZBdEZCdFZDdGZEdHZFdIZGdJZHdKZIdLZJdMZK dVdNZLdOZMdPZNdQZOdRZPdSZQeRdTk(r4ddlSZSddlTZTeSjeTjjyy#e e f$r ddl m Z YwxYw)WzNfontTools.misc.bezierTools.py -- tools for working with Bezier path segments. ) calcBoundssectRectrectArea)IdentityN) namedtuple)cythong& .> Intersectionptt1t2)approximateCubicArcLengthapproximateCubicArcLengthCapproximateQuadraticArcLengthapproximateQuadraticArcLengthCcalcCubicArcLengthcalcCubicArcLengthCcalcQuadraticArcLengthcalcQuadraticArcLengthCcalcCubicBoundscalcQuadraticBounds splitLinesplitQuadratic splitCubicsplitQuadraticAtT splitCubicAtTsplitCubicAtTCsplitCubicIntoTwoAtTCsolveQuadratic solveCubicquadraticPointAtT cubicPointAtTcubicPointAtTC linePointAtTsegmentPointAtTlineLineIntersectionscurveLineIntersectionscurveCurveIntersectionssegmentSegmentIntersectionscPtt|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 `/mnt/ssd/data/python-lab/Trading/venv/lib/python3.12/site-packages/fontTools/misc/bezierTools.pyrr8s,  w}gsmWc]I c||d||zzz|zdz}||z|z |z dz}|||zdz||z |f|||z||zdz|ffS)Ng??)p0p1p2p3midderiv3s r1_split_cubic_into_twor=Kso R"W  "e +C2glR5 (F b2g_cFlC0 cFlR"WOR0 r2)r7r8r9r:)multarchboxct||z }t||z t||z zt||z z}||ztz|k\r||zdzSt||||\}}t|g|t|g|zSNr5)absEPSILONr=_calcCubicArcLengthCRecurse) r>r7r8r9r:r?r@onetwos r1rErETs rBwc0dd|zz}t|||||S)zCalculates the arc length for a cubic Bezier segment. Args: pt1,pt2,pt3,pt4: Control points of the Bezier as complex numbers. tolerance: Controls the precision of the calcuation. Returns: Arc length value. ?g?)rE)r,r-r.r/r0r>s r1rrhs%* y D &tS#sC @@r2g|=v1v2c<||jzjSN) conjugaterealrLs r1_dotrSs   % %%r2xcv|tj|dzdzzdz tj|dz zS)N)mathsqrtasinhrTs r1 _intSecAtanr\s7 tyyA" "Q &A): ::r2c@tt|t|t|S)aCalculates the arc length for a quadratic Bezier segment. 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: Arc length value. Example:: >>> 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 r1rrs @ #7C='3-# OOr2)r,r-r.d0d1dn)scaleorigDistabx0x1Lenc||z }||z }||z }|dz}t|}|dk(rt||z St||}t|tkrDt||dk\rt||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?rrW)rCrSepsilonr\)r,r-r.r_r`rarbrcrdrerfrgrhris r1rrs@ sB sB RA BA FE |39~Ar{H 8}w B<1 sSy> !2wB1AA !a%(( ax B ax B a;r?[_45@ERRTWDUV WC Jr2c@tt|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 r1rrs  *'3-#QT VVr2r^)v0rMrNctd|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?rC)r,r-r.rnrMrNs r1rrs|B S #4s#::=ORU=UU B S3Y, ,B c!$5$;;>ORU>UU B 7R<r2c\t|||\\}}\}}\}}|dz} |dz} g} | dk7r| j| | z | dk7r| j| | z | D cgc]2} d| cxkrdkr%nn"|| z| z|| zz|z|| z| z|| zz|zf4c} ||gz} t| Scc} w)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) @rrX)calcQuadraticParametersappendr)r,r-r.axaybxbycxcyax2ay2rootstpointss r1rr*s$$;3S#I HRhr2R s(C s(C E ax bS3Y ax bS3Y :A: a!b1f r !26A:Q#6#;< c F f  s7B)cNtt|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+rHs r1rrLs*2 & w}gsmWc] r2)rnrMrNv3v4ct||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?rp) r,r-r.r/rnrMrNrrs r1rrjs> S3Y$ B S c ! " c ! " c ! " B S3Y_s " #&9 9B S c ! " c ! " c ! " B S3Y$ B 7R<" r !!r2ct||||\\}}\}}\}} \} } |dz} |dz} |dz}|dz}t| ||Dcgc]}d|cxkrdksnn|}}t| || Dcgc]}d|cxkrdksnn|}}||z}|Dcgc]<}||z|z|z||z|zz||zz| z||z|z|z||z|zz| |zz| zf>c}||gz}t|Scc}wcc}wcc}w)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 @rrrrX)calcCubicParametersrr)r,r-r.r/rurvrwrxryrzdxdyax3ay3bx2by2r~xRootsyRootsr}rs r1rrsC$.Ac3PS-T*HRhr2R(2r s(C s(C s(C s(C'S"5 DAa!a DF D'S"5 DAa!a DF D VOE   FQJNR!VaZ '"q& 02 5 FQJNR!VaZ '"q& 02 5  c F f E DsC#C#,C(=C(AC-c|\}}|\}}||z }||z } |} |} || f|} | dk(r||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)) rrXr6)r,r-where isHorizontalpt1xpt1ypt2xpt2yrurvrwrxrer~midPts r1rrsHJD$JD$ B B B B RAAvc | "b,' '1,AAzzQ R!Vb[(e ucl++c |r2ct|||\}}}t|||||||z }td|D}|s|||fgSt|||g|S)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|cxkrdksnn|ywrrXNr6.0r~s r1 z!splitQuadratic..":QqAzzq: )rsrsorted_splitQuadraticAtT) r,r-r.rrrerfc solutionss r1rrssF&c34GAq! ,<!L/E*AI:)::I c3  aA 2 22r2ct||||\}}}} t||||||| ||z } td| D} | s||||fgSt|||| g| S)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|cxkrdksnn|ywrr6rs r1rzsplitCubic..Grr)rr r_splitCubicAtT) r,r-r.r/rrrerfrrars r1rr(s6%S#sC8JAq!Q ,<!L/1\?U;RI:)::I c3$%% !Q1 1y 11r2c@t|||\}}}t|||g|S)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)) )rsr)r,r-r.tsrerfrs r1rrMs,(&c34GAq! aA + ++r2ct||||\}}}}t||||g|} |g| ddd| d<g| ddd|| 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)) rrXN)rr) r,r-r.r/rrerfrrasplits r1rresp(%S#sC8JAq!Q 1aA + +E #eAhqrl#E!H&%)CR.&#&E"I Lr2)r,r-r.r/rerfrrac'dKt||||\}}}}t||||g|Ed{y7w)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.r/rrerfrras r1rrs9(&c3S9JAq!Qq!Q/B///s &0.0)r~r,r-r.r/pointAtToff1off2)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). rXrWr4r6) r,r-r.r/r~r rrrrrrs r1rrs0 QB q5D D[F1ut|H a6A:#3dRi#o#EFFaRUU  C<(S. (28 3D C<(S. (28 3D sa C sd" "C #tX &4c(B CCr2ct|}g}|jdd|jd|\}}|\}}|\} } 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\}}}|j|||f|S)NrrkrJrXrW)listinsertrtrangelencalcQuadraticPoints)rerfrrsegmentsrurvrwrxryrzir r deltadelta_2a1xa1yb1xb1yt1_2c1xc1yr,r-r.s r1rrs8 bBHIIaIIcN FB FB FB 3r7Q; ) U AYR%-7l7l2v{R5(2v{R5(Bw4i"r'!B&4i"r'!B&+S#Jc S#JO S#c3() Or2cjt|}|jdd|jdg}|\}}|\}} |\} } |\} } 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\}}} }!|j||| |!f|SNrrkrJrXr4rW)rrrtrrcalcCubicPoints)"rerfrrarrrurvrwrxryrzrrrr r rrdelta_3rt1_3rrrrrrd1xd1yr,r-r.r/s" r1rrs bBIIaIIcNH FB FB FB FB 3r7Q; . 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,--.. Or2) rerfrrar r rrra1b1c1r`c'Kt|}|jdd|jdtt |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 | |||\}}}}||||fywr)rrrtrrcalcCubicPointsC)rerfrrarrr r rrrrrrrrr`r,r-r.r/s r1rrs bBIIaIIcN 3r7Q; # U AYR%-'/BwDy[!ebj1n '!ebj1nq1ut|+u 4 XD 1r6 )A --b"b"=S#sCc""!#sC C )rZacoscospict|tkrt|tkrg}|S| |z g}|S||zd|z|zz }|dk\r"||}| |zdz |z | |z dz |z g}|Sg}|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! @rkrrrCrl)rerfrrZr}DDrDDs r1rr/s 1v q6G E LR!VHE LUS1Wq[  9r(Cb3h#%)QBH+;a+?@E LE Lr2c t|tkr t|||St|}||z }||z }||z }||zd|zz dz }d|z|z|zd|z|zz d|zzdz }||z} ||z|z} | tkrdn| } t| tkrdn| } | | z } | dk(r| dk(rt | dz t } | | | gS| tdzkrut 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 tkr*||z tkrt ||z|zdz t x}x}}n||z tkr)t ||zdz t x}}t |t }ne||z tkr)t |t }t ||zdz t x}}n0t |t }t |t }t |t }|||gStt| t|zd } | || z z} |dk\r| } 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"@rrg;@gK@rrkr5rJggrUUUUUU?)rCrlrfloatround epsilonDigitsrmaxminrZrrrpow)rerfrrara2a3QRR2Q3R2_Q3rUthetarQ2a1_3rgrhx2s r1r r PsL 1vaA&& aA QB QB QB b38 s"A rB cBhm +dRi 74?A QB QB7lB"gRB GE SyR3Y 2#)] +1ay 'C- SQb\3/67T!WnCx 3us{# #d * 3b(C/0 04 7 3b(C/0 04 7RRL) B 7W b7!2 "r'B,#!5}E EB Eb "Ww R"WO]; ;Br=)B "Ww r=)BR"WO]; ;Br=)Br=)Br=)BB| U c!f$g . AI 8A !b3h, .s r2cv|\}}|\}}|\}}||z dz} ||z dz} ||z | z } ||z | z } | | f| | f||ffS)Nrrr6) r,r-r.ry2x3y3ryrzrwrxrurvs r1rsrssj FB FB FB r'SB r'SB b2B b2B 8b"XBx ''r2c|\}}|\}}|\}} |\} } || z dz} || z dz} ||z dz| z }||z dz| z }|| z | z |z }| | z | z |z }||f||f| | f| | ffSNrr6)r,r-r.r/rrrrx4y4rrryrzrwrxrurvs r1rrs FB FB FB FB r'SB r'SB r'S2 B r'S2 B b2 B b2 B 8b"XBx"b 11r2)r,r-r.r/rerfrcJ||z dz}||z dz|z }||z |z |z }||||fSrr6)r,r-r.r/rrfres r1rrsE scA scAA c A A q!S>r2c~|\}}|\}}|\}}|} |} |dz|z} |dz|z} ||z|z} ||z|z}| | f| | f| |ffSrBr6)rerfrrurvrwrxryrzrhy1rrrrs r1rrst FB FB FB B B s(bB s(bB b2B b2B 8b"XBx ''r2c|\}}|\}}|\}} |\} } | } | } |dz | z}| dz | z}||zdz |z}|| zdz |z}|| z|z|z}|| z| z|z}| | f||f||f||ffSrr6)rerfrrarurvrwrxryrzrrrhrrrrrrrs r1rrs FB FB FB FB B B s(bB s(bB r'S2 B r'S2 B b2 B b2 B 8b"XBx"b 11r2rerfrrar9r:p4cJ|dz|z}||zdz|z}||z|z|z}||||fS)Nrr6rs r1rrsC eqB a%E R B QQB r2r?r2cR|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. rrXr6)r,r-r~s r1r$r$sCVq1u A *c!fA.>Q!.K MMr2cd|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. rXrrWr6)r,r-r.r~rUys r1r!r!s Q1q5CF"Q!a%[1_s1v%==AANA Q1q5CF"Q!a%[1_s1v%==AANA q6Mr2c||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. rXrr4r6) r,r-r.r/r~r rrrUrs r1r"r",s QB q5D D[F A vzCF"TBYQ%77 8 9 q&3q6/   A vzCF"TBYQ%77 8 9 q&3q6/  q6Mr2)r~r,r-r.r/)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. rXr4r6)r,r-r.r/r~r rrs r1r#r#Fs]& QB q5D D[F D=3 fqj3&6S&H!I IBQRFUXL XXr2ct|dk(r tg||St|dk(r tg||St|dk(r tg||St dNrWr4Unknown curve degree)rr$r!r" ValueError)segr~s r1r%r%_sh 3x1}$S$!$$ SQ )#)q)) SQ%c%1%% + ,,r2c|\}}|\}}|\}}t||z tkrt||z tkryt||z t||z kDr ||z ||z z S||z ||z z S)Nrr) ser sxsyexeypxpys r1 _line_t_of_ptrns} FB FB FB 27|g#b2g,"8 27|c"r'l"RBG$$RBG$$r2cx|d|dz |d|dz z}|d|dz |d|dz z}|dkxr|dk S)NrrXrkr6)rerforiginxDiffyDiffs r1'_both_points_are_on_same_side_of_originr|s` qTF1I !A$"2 3E qTF1I !A$"2 3E -# ..r2c x|\}}|\}}|\}} |\} } tj|| r.tj||rtj||sgStj| | r.tj||rtj|| sgStj|| rtj| | rgStj||rtj||rgStj||rA|} | | z | |z z } | | |z z| z}| |f}t|t|||t|||gStj|| rA|} ||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 |||r2t |||r%t|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 )rYiscloser rr)s1e1s2e2s1xs1ye1xe1ys2xs2ye2xe2yrUslope34rr slope12s r1r&r&sf.HCHCHCHC S#4<<S#9$,,sTWBX  S#4<<S#9$,,sTWBX  ||C$,,sC"8  ||C$,,sC"8  ||C 9s+ q3w # %V -B3 b"b8Q    ||C 9s+ q3w # %V -B3 b"b8Q   SyS3Y'GSyS3Y'G ||GW% 3 w} ,s 2w7HIA1s7c!A QB. B 1"b" = -B3 b"b8Q   Ir2c|d}|d}tj|d|dz |d|dz }tj| j |d |d S)NrrrX)rYatan2rrotate translate)segmentstartendangles r1_alignment_transformationr.sj AJE "+C JJs1va(#a&58*; t|j|}t|dk(r#t|\}}}t |d|d|d}nAt|dk(r(t |\}}}}t |d|d|d|d}n tdtd|DS)Nr4rXrrc3>K|]}d|cxkrdksnn|yw)rkrXNr6)rrs r1rz._curve_line_intersections_t..s<cQm!m!>> 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) r4rrr ) rr!r"rr6rr$rtr )r2r3 pointFinderr5r~r line_ts r1r'r's* 5zQ' Uq# /00M ( 5C  #% # #))b)  (4 ( (\RA&AB C r2cpt|dk(rt|St|dk(rt|Std)Nr4rr)rrrr)rs r1 _curve_boundsr; s: 1v{"A&& Q1"" + ,,r2ct|dk(r|\}}t|||}||f||fgSt|dk(r tg||St|dk(r tg||St dr)rr$rrr)rr~rr midpoints r1_split_segment_at_tr>s 1v{11a(H !}-- 1v{ '!'Q'' Q1#a### + ,,r2c t|}t|}|sd}|sd}t||\}}|sgSd} t|krt|kr| || |fgSt|d\} } |d| |f} | ||df} t|d\}}|d| |f}| ||df}g}|j t | || ||j t | || ||j t | || ||j t | || |fd}t }g}|D]1}||}||vr|j||j|3|S)N)rkrJcd|d|dzzS)Nr5rrXr6)rs r1r=z._curve_curve_intersections_t..midpoint1sadQqTk""r2r5rrX)range1range2cHt|dz t|dz fS)NrrX)int)r precisions r1z._curve_curve_intersections_t..Vs(SA!23SA9J5KLr2) r;rrr>extend_curve_curve_intersections_tsetaddrt)curve1curve2rFrBrCbounds1bounds2 intersects_r=c11c12 c11_range c12_rangec21c22 c21_range c22_rangefound unique_keyseen unique_valuesrkeys ` r1rIrI!sF#GF#G  Wg.MJ  #9$'):Y)F&!8F#3455"63/HCHV,-I&!6!9-I"63/HCHV,-I&!6!9-I E LL$ i )   LL$ i )   LL$ i )   LL$ i )  MJ 5DM!n $;   R ! r2cZt|j|}td|DS)Nc3NK|]}tj|ddyw)rXrkN)rYr)rps r1rz_is_linelike..fs:1t||AaD#&:s#%)r.r1all)r* maybelines r1 _is_linelikerdds()'2BB7KI : : ::r2c Jt|r8|d|df}t|r|d|df}tg||St||St|r|d|df}t||St||}|Dcgc]#}t t ||d|d|d%c}Scc}w)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) rrrXr )rdr&r'rIr r%)rLrMline1line2intersection_tsrs r1r(r(is*Fq 6":%  1Ivbz)E(8%8%8 8)&%8 8 f q 6":%%fe44266BO"   162a5RUK  s5(B cd}t|t|kDr||}}d}t|dkDr(t|dkDr t||}nBt||}n5t|dk(rt|dk(rtg||}n t d|s|S|Dcgc].}t |j |j|j0c}Scc}w)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) FTrWz4Couldn't work out which intersection function to user ) rr(r'r&rr r r r )seg1seg2swappedr5rs r1r)r)s<G 4y3t94d 4y1} t9q=3D$?M24>M TaCIN-;t;d; OPP =J KLADDQTTadd 3 KK Ks3C cx t|}ddjd|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, c32K|]}t|ywrP) _segmentrepr)rrUs r1rz_segmentrepr..s!>a,q/!>sz%g)iterjoin TypeError)objits r1rorosG ? #Y !>2!>>>> czs (99c:|D]}tt|y)zlHelper for the doctests, displaying each segment in a list of segments on a single line as a tuple. N)printro)rr*s r1 printSegmentsrws % l7#$%r2__main__)g{Gzt?)gMbP?NN)X__doc__fontTools.misc.arrayToolsrrrfontTools.misc.transformrrY collectionsrrAttributeError ImportErrorfontTools.misccompiledCOMPILEDrDr __all__rr=returnsdoublelocalsr+rErrrlcfuncinlinerSr\rrrrrrrrrrrrrrrrrrrZrrrrr rsrrrrrr$r!r"r#r%rrr&r.r6r'r;r>rIrdr(r)rorw__name__sysdoctestexittestmodfailedr6r2r1rsED- "& ?? .*<=  @&  ~~ ~~ ~~ ~~  FMM 6==I  J      mm  A   A  &..V^^4&5& ; ; PF  ~~ ~~ nn nn -- ]] mm mm }} }} &@W"   }} }} }}   BD<    }} }} }} }} }} !" !"H#L6r*3Z"2J,0> nn nn nn nn  0  0 mm ^^    }}6==D  D46 F nn nn nn nn }} }} -- MM MM ~~ ~~ ~~ ~~##6%$"&BYB( 2 nn nn nn ( 2  nn nn nn nn ~~ ~~ ~~ N 4 mm &--fmmFMMJ YK  Y - %/ K\C =#L- -9=@F; $N-L` ?% z CHH_W__  % %& S.  $&%%&sb'' b87b8