% Copyright 2007 by Mark Wibrow % % 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. % This file loads all the parsing, functions and operator stuff % % Version 1.414213 29/9/2007 \input pgfmathutil.code.tex \input pgfmathparser.code.tex \input pgfmathfunctions.code.tex %\input pgfmathbase.code.tex % \pgfmathsetlength, \pgfmathaddtolength % % #1 = dimension register % #2 = expression % % Description: % % These functions work similar to \setlength and \addtolength. Only, % they allow #2 to contain an expression, which is evaluated before % assignment. Furthermore, the font is setup before the assignment is % done, so that dimensions like 1em are evaluated correctly. % % If #2 starts with "+", then a simple assignment is done (but the % font is still setup). This is orders of magnitude faster than a % parsed assignment. \def\pgfmathsetlength#1#2{% \expandafter\pgfmath@onquick#2\pgfmath@% {% % Ok, quick version: \begingroup% \pgfmath@selectfont% \pgfmath@x#2\unskip% \pgfmath@returnone\pgfmath@x% \endgroup% #1\pgfmathresult pt\relax% }% {% \pgfmathparse{#2}% #1\pgfmathresult pt\relax% }% \ignorespaces% } % \pgfmathaddtolength % % Add to #1 the result of evaluating #2. % % #1 - a dimension register % #2 - an expression % \def\pgfmathaddtolength#1#2{% \expandafter\pgfmath@onquick#2\pgfmath@% {% \begingroup% \pgfmath@selectfont% \pgfmath@x#1\relax% \advance\pgfmath@x#2\unskip% \pgfmath@returnone\pgfmath@x% \endgroup% #1\pgfmathresult pt\relax% }% {% \pgfmathparse{#2}% \advance#1\pgfmathresult pt\relax% }% \ignorespaces% } % \pgfmathsetcount % % Assign #1 the truncated evaluation of #2. % % #1 - a count register % #2 - an expression % \def\pgfmathsetcount#1#2{% \expandafter\pgfmath@onquick#2\pgfmath@% {% \afterassignment\pgfmath@gobbletilpgfmath@% #1#2\relax\pgfmath@% }% {% \pgfmathparse{#2}% \afterassignment\pgfmath@gobbletilpgfmath@% #1\pgfmathresult\relax\pgfmath@% }% \ignorespaces% } % \pgfmathaddtocount % % Add to #1 the truncated evaluation of #2. % % #1 - a count register % #2 - an expression % \def\pgfmathaddtocount#1#2{% \expandafter\pgfmath@onquick#2\pgfmath@% {% \edef\pgfmath@addtocounttemp{\the#1}% \afterassignment\pgfmath@gobbletilpgfmath@% #1#2\relax\pgfmath@% \advance#1\pgfmath@addtocounttemp\relax% }% {% \edef\pgfmath@addtocounttemp{\the#1}% \pgfmathparse{#2}% \afterassignment\pgfmath@gobbletilpgfmath@% #1\pgfmathresult\relax\pgfmath@% \advance#1\pgfmath@addtocounttemp\relax% }% \ignorespaces% } % \pgfmathnewcounter % % LaTeX style counter which also works in plain TeX. Defines % \c@ as a count register and also defines \the. % % #1 the name of the counter. % % Example: % % \pgfmathnewcounter{counter} % \pgfmathsetcounter{counter}{12} % \thecounter (same as \the\c@counter) % \def\pgfmathnewcounter#1{% \expandafter\ifx\csname c@#1\endcsname\relax% \def\pgfmath@marshal{\csname newcount\endcsname}% Ha! Who cares about \outer? \expandafter\pgfmath@marshal\csname c@#1\endcsname% \expandafter\def\csname the#1\endcsname{\expandafter\the\csname c@#1\endcsname}% \fi% } % \pgfmathsetcounter % % Set the counter #1 to the evaluation of #2. % % #1 - a counter name % #2 - an expression % \def\pgfmathsetcounter#1#2{% \expandafter\pgfmathsetcount\csname c@#1\endcsname{#2}% } % \pgfmathaddtocounter % % Add the counter #1 to the evaluation of #2. % % #1 - a counter name % #2 - an expression % \def\pgfmathaddtocounter#1#2{% \expandafter\pgfmathaddtocount\csname c@#1\endcsname{#2}% } % \pgfmathmakecounterglobal % % Make the current value of a counter globally defined. % % #1 - a (valid) counter name. % \def\pgfmath@pgftext{pgf} \def\pgfmath@tikztext{tikz} \def\pgfmathmakecounterglobal#1{% \pgfmath@ifundefined{c@#1}{}{% \expandafter\pgfmath@in@\expandafter{\pgfmath@pgftext}{#1}% \ifpgfmath@in@% \else% \expandafter\pgfmath@in@\expandafter{\pgfmath@tikztext}{#1}% \ifpgfmath@in@% \else% \expandafter\global\csname c@#1\endcsname\csname c@#1\endcsname\relax% \fi% \fi% }% } % \pgfmathsetmacro % % \edef#1 as the result of evaluating #2. % % #1 - a macro % #2 - an expression % \def\pgfmathsetmacro#1#2{% \begingroup% \pgfmathsetlength\pgfmath@x{#2}% \edef#1{\pgfmath@tonumber{\pgfmath@x}}% \pgfmath@smuggleone{#1}% \endgroup% } % \pgfmathsetlengthmacro % % \edef#1 as the result of evaluating #2 with pt. % % #1 - a macro % #2 - an expression % \def\pgfmathsetlengthmacro#1#2{% \begingroup% \pgfmathsetlength\pgfmath@x{#2}% \edef#1{\the\pgfmath@x}% \pgfmath@smuggleone{#1}% \endgroup% } % \pgfmathtruncatemacro % % \edef#1 as the truncated result of evaluating #2. % % #1 - a macro % #2 - an expression % \def\pgfmathtruncatemacro#1#2{% \begingroup% \pgfmathsetcount\c@pgfmath@counta{#2}% \edef#1{\the\c@pgfmath@counta}% \pgfmath@smuggleone{#1}% \endgroup% } % Check whether a given parameter starts with quick. % % The command should be followed by nonempty text, ending with % \pgfmath@ as a stop-token. Then should follow % % #1 - code to execute if text starts with + % #2 - code to execute if text does not % % Example: % % \pgfmath@onquick+0pt\pgfmath@{is quick}{is slow} \def\pgfmath@onquick{% \futurelet\pgfmath@next% \pgfmath@@onquick} \def\pgfmath@@onquick#1\pgfmath@{% \ifx\pgfmath@next+% \let\pgfmath@next=\pgfmath@firstoftwo% \else% \let\pgfmath@next=\pgfmath@secondoftwo% \fi% \pgfmath@next% } % *** The following commands DO NOT WORK without the rest of PGF *** % % (a dumping ground for stuff that doesn't really belong anywhere else) % \pgfmathanglebetweenpoints % % Define \pgfmathresult as the angle between points #1 and #2 % Should get the quadrants right as well. % \def\pgfmathanglebetweenpoints#1#2{% \begingroup% \pgf@process{\pgfpointdiff{#1}{#2}}% % % First approximate the angle of the external point... % \pgf@xa\pgf@x% \pgf@ya\pgf@y% \pgf@xb\pgf@x% \pgf@yb\pgf@y% \ifdim\pgf@xa<0pt\relax% \pgf@xa-\pgf@xa% \fi% \ifdim\pgf@ya<0pt\relax% \pgf@ya-\pgf@ya% \fi% \ifdim\pgf@ya>\pgf@xa% \pgf@x\pgf@xa% \pgf@y\pgf@ya% \else% \pgf@x\pgf@ya% \pgf@y\pgf@xa% \fi% \ifdim\pgf@y=0pt\relax% \pgf@x0pt% \else% \pgfmathreciprocal@{\pgfmath@tonumber{\pgf@y}}% \pgf@x\pgfmathresult\pgf@x% \fi% \multiply\pgf@x1000\relax% \afterassignment\pgfmath@gobbletilpgfmath@% \expandafter\c@pgf@counta\the\pgf@x\relax\pgfmath@% \expandafter\pgf@x\csname pgfmath@atan@\the\c@pgf@counta\endcsname pt\relax% \ifdim\pgfmath@ya>\pgfmath@xa\relax% \pgf@x-\pgf@x% \advance\pgf@x90pt% \fi% \ifdim\pgf@xb<0pt% \ifdim\pgf@yb>0pt% \pgf@x-\pgf@x% \fi% \advance\pgf@x180pt\relax% \else% \ifdim\pgf@yb<0pt% \pgf@x-\pgf@x% \advance\pgf@x360pt\relax% \fi\fi% \pgfmath@returnone\pgf@x% \endgroup% } % % \pgfmathrotatepointaround % % Rotate point #1 about point #2 by #3 degrees. % \def\pgfmathrotatepointaround#1#2#3{% \pgf@process{% \pgf@process{#1}% \pgf@xc=\pgf@x% \pgf@yc=\pgf@y% \pgf@process{#2}% \pgf@xa\pgf@x% \pgf@ya\pgf@y% \pgf@xb\pgf@x% \pgf@yb\pgf@y% \pgf@x=\pgf@xc% \pgf@y=\pgf@yc% \advance\pgf@x-\pgf@xa% \advance\pgf@y-\pgf@ya% \pgfmathsetmacro\angle{#3}% \pgfmathsin@{\angle}% \let\sineangle\pgfmathresult% \pgfmathcos@{\angle}% \let\cosineangle\pgfmathresult% \pgf@xa\cosineangle\pgf@x% \advance\pgf@xa-\sineangle\pgf@y% \pgf@ya\sineangle\pgf@x% \advance\pgf@ya\cosineangle\pgf@y% \pgf@x\pgf@xb% \pgf@y\pgf@yb% \advance\pgf@x\pgf@xa% \advance\pgf@y\pgf@ya% }% } % \pgfmathanglebetweenlines % % Calculate the clockwise angle between a line from point #1 % to point #2 and a line from #3 to point #4. % \def\pgfmathanglebetweenlines#1#2#3#4{% \begingroup% \pgfmathanglebetweenpoints{#1}{#2}% \let\firstangle\pgfmathresult% \pgfmathanglebetweenpoints{#3}{#4}% \let\secondangle\pgfmathresult% \ifdim\firstangle pt>\secondangle pt\relax% \pgfmathadd@{\secondangle}{360}% \let\secondangle\pgfmathresult% \fi% \pgfmathsubtract@{\secondangle}{\firstangle}% \pgfmath@smuggleone\pgfmathresult% \endgroup% } % \pgfmathpointreflectalongaxis % % Reflects point #2 around an axis centered on #2 at an angle #3. % \def\pgfmathreflectpointalongaxis#1#2#3{% \pgf@process{% \pgfmathanglebetweenpoints{#2}{#1}% \pgfmath@tempdima\pgfmathresult pt\relax% \pgfmathparse{#3}% \advance\pgfmath@tempdima-\pgfmathresult pt\relax% \pgfmath@tempdima-2.0\pgfmath@tempdima% \pgfmathrotatepointaround{#1}{#2}{\pgfmath@tonumber{\pgfmath@tempdima}}% }% } % \pgfmathpointintersectionoflineandarc % % A bit experimental at the moment: % % Locates the point where a line crosses an eliptical arc. If the line % does not cross the arc, a meaningless point will result. % % #1 the point of the line on the "convex" side of the arc. % #2 the point of the line on the "concave" side of the arc. % #3 the center of the eliptical arc. % #4 start angle of the arc. % #5 end angle of the arc. % #6 radii of the arc. % \def\pgfmathpointintersectionoflineandarc#1#2#3#4#5#6{% \pgf@process{% % % Get the required angle. % \pgfmathanglebetweenpoints{#2}{#1}% \let\x\pgfmathresult% % % Get the radii of the arc. % \pgfmath@in@{and }{#6}% \ifpgfmath@in@% \pgf@polar@#6\@@% \else% \pgf@polar@#6 and #6\@@% \fi% \edef\xarcradius{\the\pgf@x}% \edef\yarcradius{\the\pgf@y}% % % Get the start and end angles of the arc... % \pgfmathsetmacro\s{#4}% \pgfmathsetmacro\e{#5}% % % ...and also with rounding. % \pgfmathmod@{\s}{360}% \ifdim\pgfmathresult pt<0pt\relax% \pgfmathadd@{\pgfmathresult}{360}% \fi% \let\ss\pgfmathresult% \pgfmathmod@{\e}{360}% \ifdim\pgfmathresult pt<0pt\relax% \pgfmathadd@{\pgfmathresult}{360}% \fi% \let\ee\pgfmathresult% % % Hackery for when arc straddles zero. % \ifdim\ee pt<\ss pt\relax% \pgfmathadd@{\x}{180}% \pgfmathmod@{\pgfmathresult}{360}% \let\x\pgfmathresult% \fi% \def\m{360}% Measure of nearness. \pgfmathadd@{\s}{\e}% \pgfmathdivide@{\pgfmathresult}{2}% \let\n\pgfmathresult% The best estimate (default to middle of arc). \pgfmathloop% \pgfmathadd@{\s}{\e}% \pgfmathdivide@{\pgfmathresult}{2}% \let\p\pgfmathresult% \ifdim\p pt=\s pt\relax% \else% \pgfmathanglebetweenpoints{#2}{% \pgfpointadd{#3}{% \pgf@x\xarcradius\relax% \pgfmathcos@{\p}% \pgf@x\pgfmathresult\pgf@x% \pgf@y\yarcradius\relax% \pgfmathsin@{\p}% \pgf@y\pgfmathresult\pgf@y% }% }% % % Hackery for when arc straddles zero. % \ifdim\ee pt<\ss pt\relax% \pgfmathadd@{\pgfmathresult}{180}% \pgfmathmod@{\pgfmathresult}{360}% \fi% \let\q\pgfmathresult% % % More hackery... % \ifdim\x pt>335pt\relax% \ifdim\q pt<45pt\relax% \pgfmathadd@{\q}{360}% \let\q\pgfmathresult% \fi% \fi% \ifdim\x pt=\q pt% Found it! \pgfmathbreakloop% Breaks after current iteration is complete. \else \ifdim\x pt<\q pt\relax% \let\e\p% \else% \let\s\p% \fi% \fi% \pgfmathsubtract@{\x}{\q}% \pgfmathabs@{\pgfmathresult}% % % Save the estimate if it is better than any previous estimate. % \ifdim\pgfmathresult pt<\m pt\relax% \let\m\pgfmathresult% \let\n\p% \fi% \repeatpgfmathloop% \pgfpointadd{#3}{\pgfpointpolar{\n}{\xarcradius and \yarcradius}}% }% } % \pgfmathangleonellipse % % Find the angle corresponding to a point on the border of an ellispe. % % #1 - the point on the border. % #2 - the radii of the ellipse. % \def\pgfmathangleonellipse#1#2{% \begingroup% \pgfmath@in@{and }{#2}% \ifpgfmath@in@% \pgf@polar@#2\@@% \else% \pgf@polar@#2 and #2\@@% \fi% \pgf@xa\pgf@x% \pgf@ya\pgf@y% \pgf@process{#1}% \ifdim\pgf@x=0pt\relax% \pgfutil@tempdima1pt\relax% \else% \pgfutil@tempdima\pgf@x% \pgfmathdivide@{\pgfmath@tonumber{\pgf@xa}}{\pgfmath@tonumber{\pgfutil@tempdima}}% \pgfutil@tempdima\pgfmathresult pt\relax% \fi% \ifdim\pgf@y=0pt\relax% \pgfutil@tempdima1pt\relax% \else% \pgfmathdivide@{\pgfmath@tonumber{\pgf@y}}{\pgfmath@tonumber{\pgf@ya}}% \pgfutil@tempdima\pgfmathresult\pgfutil@tempdima% \pgfmathatan@{\pgfmath@tonumber{\pgfutil@tempdima}}% \fi% % \pgfutil@tempdima\pgfmathresult pt\relax% \ifdim\pgfutil@tempdima<0pt\relax% \advance\pgfutil@tempdima360pt\relax% \fi% \ifdim\pgf@x<0pt\relax% \ifdim\pgf@y=0pt\relax% \pgfutil@tempdima180pt\relax% \else% \ifdim\pgf@y<0pt\relax% \advance\pgfutil@tempdima180pt\relax% \else% \advance\pgfutil@tempdima-180pt\relax% \fi% \fi% \else% \ifdim\pgf@x=0pt\relax% \ifdim\pgf@y<0pt\relax% \pgfutil@tempdima270pt\relax% \else% \pgfutil@tempdima90pt\relax% \fi% \else% \ifdim\pgf@y=0pt\relax% \pgfutil@tempdima0pt\relax% \fi% \fi% \fi% \pgfmath@returnone\pgfutil@tempdima% \endgroup% }