diff options
Diffstat (limited to 'Master/texmf-dist/tex/generic/pgf/frontendlayer/tikz/libraries/tikzlibrarycalc.code.tex')
-rw-r--r-- | Master/texmf-dist/tex/generic/pgf/frontendlayer/tikz/libraries/tikzlibrarycalc.code.tex | 549 |
1 files changed, 549 insertions, 0 deletions
diff --git a/Master/texmf-dist/tex/generic/pgf/frontendlayer/tikz/libraries/tikzlibrarycalc.code.tex b/Master/texmf-dist/tex/generic/pgf/frontendlayer/tikz/libraries/tikzlibrarycalc.code.tex new file mode 100644 index 00000000000..f79f5343bb5 --- /dev/null +++ b/Master/texmf-dist/tex/generic/pgf/frontendlayer/tikz/libraries/tikzlibrarycalc.code.tex @@ -0,0 +1,549 @@ +% Copyright 2006 by Till Tantau +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\ProvidesFileRCS[v\pgfversion] $Header: /cvsroot/pgf/pgf/generic/pgf/frontendlayer/tikz/libraries/tikzlibrarycalc.code.tex,v 1.5 2008/02/04 17:19:55 tantau Exp $ + +% +% +% Part I: The let path command +% +% + + +% +% Syntax: let \p{name1} = (coord), \p{name2} = (coord), ... in ... +% +% Currently (this may get more fancy in the future), the (coord)s are +% evaluated one by one. If the first evaluates to, say, (10pt,20pt), +% the macro \p{name1} is set to "10pt,20pt" (without parantheses), the +% macro \x{name1} is set to "10pt" and the macro \y{name1} is set to +% "20pt". +% +% If you use a number for {name}, you need no parantheses, so you +% could write: +% +% \draw let +% \p1 = (1,1), +% \p2 = ($ 2.5*(3,2) $) +% in +% (\x1,\x2) -- (\y1,\y2); + +\def\tikz@let@command et{% + \let\p=\tikz@cc@dop% + \let\x=\tikz@cc@dox% + \let\y=\tikz@cc@doy% + \let\n=\tikz@cc@don% + \pgfutil@ifnextchar i{\tikz@cc@stop@let}{\tikz@cc@handle@line}% +} +\def\tikz@cc@handle@line{% + \pgfutil@ifnextchar\p{% + \tikz@cc@handle@coor% + }{% + \pgfutil@ifnextchar\n{% + \tikz@cc@handle@num% + }{% + \PackageError{tikz}{``\string\p'' or ``\string\n'' expected}{}% + }% + }% +} +\def\tikz@cc@handle@num\n#1#2=#3{% + \pgfmathparse{#3}% + \expandafter\edef\csname tikz@cc@n@#1\endcsname{\pgfmathresult\ifpgfmathunitsdeclared pt\fi} + \pgfutil@ifnextchar,{\tikz@cc@handle@nextline}{\tikz@cc@stop@let}% +} +\def\tikz@cc@handle@coor\p#1#2={% + \def\tikz@cc@coord@name{#1}% + \tikz@scan@one@point\tikz@cc@dolet% +} +\def\tikz@cc@dolet#1{% + \pgf@process{#1}% + \expandafter\edef\csname tikz@cc@p@\tikz@cc@coord@name\endcsname{\the\pgf@x,\the\pgf@y}% + \expandafter\edef\csname tikz@cc@x@\tikz@cc@coord@name\endcsname{\the\pgf@x}% + \expandafter\edef\csname tikz@cc@y@\tikz@cc@coord@name\endcsname{\the\pgf@y}% + \pgfutil@ifnextchar,{\tikz@cc@handle@nextline}{\tikz@cc@stop@let}% +} +\def\tikz@cc@handle@nextline,{% + \tikz@cc@handle@line% +} +\def\tikz@cc@stop@let in{% + \tikz@scan@next@command% +}% + +\def\tikz@cc@dop#1{\csname tikz@cc@p@#1\endcsname} +\def\tikz@cc@dox#1{\csname tikz@cc@x@#1\endcsname} +\def\tikz@cc@doy#1{\csname tikz@cc@y@#1\endcsname} +\def\tikz@cc@don#1{\csname tikz@cc@n@#1\endcsname} + + + +% +% +% Part II: The ($...$) parser +% +% + +\def\tikz@parse@calculator#1(${%$ + \def\tikz@cc@command{#1}% + \begingroup% + % + % Parse main computation. It's a series of optional factors in front + % of coordiantes. + % + \pgf@xa=0pt% We accumulate the result in here. + \pgf@ya=0pt% + \tikz@cc@parse+% +} + +\def\tikz@cc@parse{% + \pgfutil@ifnextchar${%$ + % Ok, we found the end... + \tikz@cc@end% + } + {\pgfutil@ifnextchar+{% + % Ok, we found a coordinate... + \tikz@cc@add% + }{% + \pgfutil@ifnextchar-{% + \tikz@cc@sub% + }{% + \PackageError{tikz}{+ or - expected}{}% + \tikz@cc@end$%$ + }% + }% + }% +} + +% +% The end is reached with $ +% +\def\tikz@cc@end$#1){%$ + \xdef\tikz@marshal{\noexpand\pgfqpoint{\the\pgf@xa}{\the\pgf@ya}}% + \endgroup% + \expandafter\tikz@cc@command\expandafter{\tikz@marshal}% +} + + +% +% Another coordinate with +/-, possibly with a factor +% +\def\tikz@cc@add+{% + \def\tikz@cc@factor{1}% + \tikz@cc@factororcoordinate% +} +\def\tikz@cc@sub-{% + \def\tikz@cc@factor{-1}% + \tikz@cc@factororcoordinate% +} + +% +% Check for a factor: If we see a (, its a coordinate... +% +\def\tikz@cc@factororcoordinate{% + \pgfutil@ifnextchar({%) + % Ok, found coordinate + \tikz@cc@coordinate% + }{% + \tikz@cc@parse@factor% + }% +} + +% +% ... otherwise it's a factor. It ends at ...*( +% +\def\tikz@cc@parse@factor#1*({% + \pgfmathparse{#1*\tikz@cc@factor}% + \let\tikz@cc@factor=\pgfmathresult% + \tikz@cc@coordinate(%) +} + +\def\tikz@cc@coordinate{% + \tikz@scan@absolute\tikz@cc@after@coordinate% +} +\def\tikz@cc@after@coordinate#1{% + \pgf@process{#1}% + \pgf@xb=\pgf@x% + \pgf@yb=\pgf@y% + \tikz@cc@mid@checks% +} + + +% +% A coordinate can be followed by !...!(...) +% + +\def\tikz@cc@mid@checks{ + \pgfutil@ifnextchar!{% + \tikz@cc@mid% + }{% + \advance\pgf@xa by\tikz@cc@factor\pgf@xb% + \advance\pgf@ya by\tikz@cc@factor\pgf@yb% + \tikz@cc@parse% continue + }% +} + +\def\tikz@cc@mid!{% + \pgfutil@ifnextchar({% + \tikz@scan@one@point\tikz@cc@project% + }{% + \tikz@cc@mid@num% + }% +} + +% +% Partway case: (coord a)!number!(coord b) +% +% Returns the position that is at <number> fraction on the way from a +% to b. This, (a)!0!(b) is (a), (a)!.5!(b) is the middle and (a)!1!(b) +% is (b) +% +\def\tikz@cc@mid@num#1!{% + \pgfmathparse{#1}% + \ifpgfmathunitsdeclared% + \let\tikz@cc@mid@unit=\pgfmathresult% + \expandafter\tikz@cc@scan@rot\expandafter\tikz@cc@after@unit% + \else% + \let\tikz@cc@mid@factor=\pgfmathresult% + \pgfmathparse{1-\tikz@cc@mid@factor}% + \let\tikz@cc@mid@factor@one=\pgfmathresult% + \expandafter\tikz@cc@scan@rot\expandafter\tikz@cc@after@num% + \fi% +} + +\def\tikz@cc@after@num#1{% + \pgf@process{#1}% + \pgf@xb=\tikz@cc@mid@factor@one\pgf@xb% + \pgf@yb=\tikz@cc@mid@factor@one\pgf@yb% + \advance\pgf@xb by\tikz@cc@mid@factor\pgf@x% + \advance\pgf@yb by\tikz@cc@mid@factor\pgf@y% + \tikz@cc@mid@checks% +} + + + +% +% Distance case: (coord a)!dimension!(coord b) +% +% Returns the position that is at <dimension> removed from (coord a) +% in the direction of (coord b). +% + +\def\tikz@cc@after@unit#1{% + \pgf@process{#1}% + \advance\pgf@x by-\pgf@xb% + \advance\pgf@y by-\pgf@yb% + \pgf@process{\pgfpointnormalised{}}% + \advance\pgf@xb by\tikz@cc@mid@unit\pgf@x% + \advance\pgf@yb by\tikz@cc@mid@unit\pgf@y% + \tikz@cc@mid@checks% +} + +% +% Projection case: (a)!(p)!(b) +% +% Projection of p on line from a to b +% +\def\tikz@cc@project#1{% + \pgf@process{#1}% + % Save in c + \pgf@xc=\pgf@x% + \pgf@yc=\pgf@y% + \expandafter\tikz@cc@scan@rot\expandafter\tikz@cc@after@project\tikz@cc@scan@ex% +} + +\def\tikz@cc@scan@ex!{} + +\def\tikz@cc@after@project#1{% + \pgf@process{#1}% + % Ok, now we need to project (xc,yc) on the line (xb,xc) to (x,y) + \advance\pgf@x by-\pgf@xb% + \advance\pgf@y by-\pgf@yb% + \advance\pgf@xc by-\pgf@xb% + \advance\pgf@yc by-\pgf@yb% + \pgf@process{\pgfpointnormalised{}}% + % Scalar product + \pgf@xc=\pgf@sys@tonumber{\pgf@xc}\pgf@x% + \advance\pgf@xc by\pgf@sys@tonumber{\pgf@yc}\pgf@y% + % and add + \advance\pgf@xb by\pgf@sys@tonumber{\pgf@xc}\pgf@x% + \advance\pgf@yb by\pgf@sys@tonumber{\pgf@xc}\pgf@y% + \tikz@cc@mid@checks% +} + +% +% Rotational scanner: radius:(x) +% + +\def\tikz@cc@scan@rot#1{% + \pgfutil@ifnextchar({%) + \tikz@scan@one@point#1% normal + }% + { + \def\tikz@cc@scan@rot@cmd{#1} + \tikz@cc@scan@one@rot% + }% +} + +\def\tikz@cc@scan@one@rot#1:{% + \def\tikz@cc@scan@rot@angle{#1}% + \tikz@scan@one@point\tikz@cc@handle@rot% +} + +\def\tikz@cc@handle@rot#1{% + \pgf@process{#1}% + % Ok, now we need to rotate x/y around xb/xb by ...rot@angle + {% + \pgftransformreset% + % Save them... + \pgf@xc=\pgf@x% + \pgf@yc=\pgf@y% + \pgftransformshift{\pgfqpoint{\pgf@xb}{\pgf@yb}}% + \pgftransformrotate{\tikz@cc@scan@rot@angle}% + \pgftransformshift{\pgfqpoint{-\pgf@xb}{-\pgf@yb}}% + \pgfpointtransformed{\pgfqpoint{\pgf@xc}{\pgf@yc}}% + \expandafter + }% + \edef\tikz@marshal{\noexpand\tikz@cc@scan@rot@cmd{\noexpand\pgfqpoint{\the\pgf@x}{\the\pgf@y}}}% + \tikz@marshal% +} + + + + +% +% +% Part III: Calculation coordinate systems +% +% + +% Tangent cs: Keys are a node and a point. Depending on the type of +% node, the appropriate tanent computation should be done. + +\tikzdeclarecoordinatesystem{tangent} +{% + \tikzset{cs/.cd,#1}% + \expandafter\ifx\csname tikz@tangent@\tikz@cs@type\endcsname\relax% + \PackageError{tikz}{I do not know how to compute the tangent to + a \tikz@cs@type}{}% + \pgfpointorigin% + \else% + \expandafter\tikz@scan@one@point\expandafter\tikz@lib@do@tangent\tikz@cs@point% + \fi% +} + +\tikzset{cs/node/.code=\tikz@cs@unpack{\tikz@cs@node}{\tikz@cs@type}{#1}} +\tikzset{cs/point/.store in=\tikz@cs@point} + +\def\tikz@lib@do@tangent{\csname tikz@tangent@\tikz@cs@type\endcsname} + +\def\tikz@tangent@coordinate#1{% + \pgfpointanchor{\tikz@cs@node}{center}% +} + +\def\tikz@tangent@circle#1{% + {% + % Step 1: Compute the transformed position of the input: + \pgf@process{\pgfpointtransformed{#1}}% + \pgf@xa=\pgf@x% + \pgf@ya=\pgf@y% + % + % Step 2: Compute vector from center of circle to transformed #1 + % + \pgf@process{\pgfpointtransformed{\pgfpointanchor{\tikz@cs@node}{center}}}% + \advance\pgf@xa by-\pgf@x% + \advance\pgf@ya by-\pgf@y% + % + % Step 2: Reset transformations, they distract... + % + \pgftransformreset% + % + % Step 3: Transform to the center of the circle. + % + \pgftransformshift{\pgfpointanchor{\tikz@cs@node}{center}}% + % + % Step 4: Compute the radius + % + \pgf@process{\pgfpointanchor{\tikz@cs@node}{east}}% + \pgf@xc=\pgf@x% + % + % Now, (xa,ya) is a point. Compute the tangent from this point to + % a circle around the origin of radius xc. + % + % acos(radius/veclen(xa,ya)) is the angle of the tangent. + \pgfmathparse{veclen(\the\pgf@xa,\the\pgf@ya)} + \pgfmathparse{acos(\the\pgf@xc/\pgfmathresult)} + \ifnum\pgfkeysvalueof{/tikz/cs/solution}>1\relax% + \pgfmathsubtract{0}{\pgfmathresult}% + \fi% + \let\tikz@lib@temp=\pgfmathresult% + % + % Now \pgfmathparse contains the desired angle. Use this to + % compute the correct position on the circle... + % + % But, first, rotate to the point. + \pgf@process{\pgfpointnormalised{\pgfqpoint{\pgf@xa}{\pgf@ya}}}% + \pgf@ya=-\pgf@y% + \pgftransformcm{\pgf@sys@tonumber{\pgf@x}}{\pgf@sys@tonumber{\pgf@y}}{\pgf@sys@tonumber{\pgf@ya}}{\pgf@sys@tonumber{\pgf@x}}{\pgfpointorigin}% + % Finally, rotate... + \pgf@process{\pgfpointtransformed{\pgfpointpolar{\tikz@lib@temp}{\the\pgf@xc}}}% + % + % Ok, undo transformations... + }% + % \pgf@x, \pgf@y have been smuggled outside by \pgf@process + {% + \pgftransforminvert% + \pgf@process{\pgfpointtransformed{}}% + }% +} + + +% Implementation of intersections + + +\def\tikz@intersect@circle@and@circle{% + {% + \pgftransformreset% transformations only confuse us, here... + % + % Compute origin and radius of first circle + % + \pgf@process{\pgfpointanchor{\tikz@cs@node@a}{center}}% + \pgf@xa=\pgf@x% + \pgf@ya=\pgf@y% + \pgf@process{\pgfpointanchor{\tikz@cs@node@a}{east}}% + \advance\pgf@x by-\pgf@xa% + \pgf@xc=\pgf@x% ok, pgf@xc is first radius, (xa,ya) is center + % + % Compute origin and radius of second circle + % + \pgf@process{\pgfpointanchor{\tikz@cs@node@b}{center}}% + \pgf@xb=\pgf@x% + \pgf@yb=\pgf@y% + \pgf@process{\pgfpointanchor{\tikz@cs@node@b}{east}}% + \advance\pgf@x by-\pgf@xb% + \pgf@yc=\pgf@x% \pgf@yc is second radius, (xb,yb) is center + % + \pgf@process{% + \pgfpointintersectionofcircles{\pgfqpoint{\pgf@xa}{\pgf@ya}}{\pgfqpoint{\pgf@xb}{\pgf@yb}}{\pgf@xc}{\pgf@yc}{\pgfkeysvalueof{/tikz/cs/solution}}% + }% + }% + % \pgf@x, \pgf@y have been smuggled outside by \pgf@process, + % reinstall transformations... + {% + \pgftransforminvert% + \pgf@process{\pgfpointtransformed{}}% + }% +} + + +\def\tikz@intersect@line@and@circle{% + {% + % + % Step 1: Get line + % + \expandafter\tikz@scan@one@point\expandafter\tikz@parse@line\tikz@cs@line@a% + \pgf@process{\pgfpointtransformed{}}% + \pgf@xb=\pgf@x% + \pgf@yb=\pgf@y% + \pgf@process{\pgfpointtransformed{\pgfqpoint{\pgf@xc}{\pgf@yc}}}% + \pgf@xa=\pgf@x% + \pgf@ya=\pgf@y% + % + % Step 2: Subtract center of circle + % + \pgf@process{\pgfpointtransformed{\pgfpointanchor{\tikz@cs@node@b}{center}}}% + \advance\pgf@xa by-\pgf@x% + \advance\pgf@ya by-\pgf@y% + \advance\pgf@xb by-\pgf@x% + \advance\pgf@yb by-\pgf@y% + % + % Step 3: Reset transformations, they distract... + % + \pgftransformreset% + % + % Step 4: Transform to the center of the circle. + % + \pgftransformshift{\pgfpointanchor{\tikz@cs@node@b}{center}}% + % + % Step 5: Compute the radius + % + \pgf@process{\pgfpointanchor{\tikz@cs@node@b}{east}}% + \edef\tikz@lib@saved@radius{\pgf@sys@tonumber{\pgf@x}}% + % + % Step 6: Compute projection of origin on line (xa,ya) -- (xb,yb), + % store in (xa,ya) + \pgf@x=\pgf@xb% + \pgf@y=\pgf@yb% + \advance\pgf@x by-\pgf@xa% + \advance\pgf@y by-\pgf@ya% + \pgf@process{\pgfpointnormalised{}}% + % Scalar product + \pgf@xc=\pgf@sys@tonumber{\pgf@xa}\pgf@x% + \advance\pgf@xc by\pgf@sys@tonumber{\pgf@ya}\pgf@y% + \pgf@xc=-\pgf@xc% + % and add + \advance\pgf@xa by\pgf@sys@tonumber{\pgf@xc}\pgf@x% + \advance\pgf@ya by\pgf@sys@tonumber{\pgf@xc}\pgf@y% + % + % Now, we have a triangle with a right angle at (xa,ya). The + % second point of the triangle is the origin. The third point is + % sought. + % Save x/y + \pgf@xc=\pgf@x% + \pgf@yc=\pgf@y% + % Square radius + \pgf@xb=\tikz@lib@saved@radius pt% + % + % First, make numbers smaller, in case they are too large + % + \c@pgf@counta=1\relax% + \loop% + \ifdim\pgf@xb>50pt% + \multiply\c@pgf@counta by2\relax% + \divide\pgf@xa by2\relax% + \divide\pgf@ya by2\relax% + \divide\pgf@xb by2\relax% + \repeat% + \pgf@xb=\pgf@sys@tonumber{\pgf@xb}\pgf@xb% + % Subtract xa^2 + ya^2 + \pgf@yb=\pgf@sys@tonumber{\pgf@xa}\pgf@xa% + \advance\pgf@xb by-\pgf@yb% + \pgf@yb=\pgf@sys@tonumber{\pgf@ya}\pgf@ya% + \advance\pgf@xb by-\pgf@yb% + % Square root + \ifdim\pgf@xb<0pt% + \pgf@xb=0pt% + \fi% + \pgfmathsqrt@{\pgf@sys@tonumber{\pgf@xb}}% + \pgfmathmultiply@{\pgfmathresult}{\the\c@pgf@counta}% + \multiply\pgf@xa by\c@pgf@counta\relax% + \multiply\pgf@ya by\c@pgf@counta\relax% + \ifnum\pgfkeysvalueof{/tikz/cs/solution}>1\relax% + \pgfmathsubtract{0}{\pgfmathresult}% + \fi% + % Ok, now add things... + \advance\pgf@xa by \pgfmathresult\pgf@xc% + \advance\pgf@ya by \pgfmathresult\pgf@yc% + \pgf@process{\pgfpointtransformed{\pgfqpoint{\pgf@xa}{\pgf@ya}}}% + % Ok, undo transformations... + }% + % \pgf@x, \pgf@y have been smuggled outside by \pgf@process + {% + \pgftransforminvert% + \pgf@process{\pgfpointtransformed{}}% + }% +} + +\def\tikz@intersect@circle@and@line{% + % Swap + {% + \let\tikz@cs@node@b=\tikz@cs@node@a% + \let\tikz@cs@line@a=\tikz@cs@line@b% + \tikz@intersect@line@and@circle% + }% +} + |