%% $Id: pst-bezier.tex 87 2009-01-29 10:37:06Z herbert $ %% %% This is file `pst-bezier.tex', %% %% IMPORTANT NOTICE: %% %% Package `pst-bezier.tex' %% %% Tobias Nähring (www.tn-home.de) %% Herbert Voss %% %% This program can be redistributed and/or modified under the terms %% of the LaTeX Project Public License Distributed from CTAN archives %% in directory CTAN:/macros/latex/base/lppl.txt. %% %% DESCRIPTION: %% `pst-bezier' is a PSTricks package to draw spline curves %% %% \csname PSTbezierLoaded\endcsname \let\PSTbezierLoaded\endinput \def\fileversion{0.01} \def\filedate{2009/01/29} \message{ v\fileversion, \filedate} \ifx\PSTricksLoaded\endinput\else\input pstricks.tex\fi \ifx\PSTXKeyLoaded\endinput\else\input pst-xkey \fi \edef\TheAtCode{\the\catcode`\@}\catcode`\@=11 \pst@addfams{pst-bezier} %% We need this: \expandafter\if\csname gobble\endcsname\relax\def\gobble#1{}\fi %% %% \newcommand is not native TeX. Therefore the following definition. %%%%%%%%%%%% %% \defopt defines a macro with one optional argument. %% Syntax: %% \defopt\MyNewMacro{DefaultValue}[#1]#2{StuffToBeAssignedToMyNewMacro} %% where \myNewMacro, DefaultValue, and StuffToBeAssignedToMyNewMacro %% have the obvious meaning. Instead of #2 up to #9 arguments can be %% specified. \def\defopt#1#2{% \def\defopt@tmp##1{% \expandafter\def\csname##1\endcsname{% \def\defopt@tmp{\futurelet\defopt@arg}% \expandafter\defopt@tmp\csname##1@opt\endcsname% }% \expandafter\def\csname##1@opt\endcsname{% \if\defopt@arg[%] \def\next{\csname##1@@opt\endcsname}% \else% \def\next{\csname##1@@opt\endcsname[#2]}% \fi\next}% }% \edef\defopt@arg{\expandafter\gobble\string#1} \expandafter\defopt@tmp\expandafter{\defopt@arg}% \expandafter\def\csname\expandafter\gobble\string#1@@opt\endcsname% } %% The postscript part of pst-bezier: \pstheader{pst-bezier.pro} %% A list of TeX-code fragments is generated when parsing \psbcurve. %% The list is managed with the help of these two counters: \newcount\psbcurve@codeCntrEnd \newcount\psbcurve@codeCntr %% These counters should never be set globally. %% Also the code fragments should never be set globally. %% The list entries are numberated (therefore the entries can be %% accessed via \csname only). %% E. g. for the third entry you have the following items: %% \csname psbcurve@code3l\endcsname (the left control point) %% \csname psbcurve@code3r\endcsname (the right control point) %% \csname psbcurve@code3\endcsname (the interpolated point) %% \csname psbcurve@code3sl\endcsname (the left scaling factor) %% \csname psbcurve@code3sr\endcsname (the right scaling factor) %% \csname psbcurve@code3addon\endcsname (additional code that is run at %% first) %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Auxiliary macros for dealing %% with the list TeX-code fragments %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Syntax: %% \psbcurve@def[offset]{item}{TeXcode} %% Where offset is some number (default:0), %% and item is one of {l,r,sl,sr,addon}. %% TeXcode will be assigned to the item of the list entry at %% \psbcurve@codeCntrEnd + offset. \defopt\psbcurve@def{0}[#1]#2{ \psbcurve@codeCntr\psbcurve@codeCntrEnd \advance\psbcurve@codeCntr by #1 \expandafter\def\csname psbcurve@code\the\psbcurve@codeCntr#2\endcsname} %% Essentially the same as \psbcurve@def, but %% the list item will only be set if it is undefined. \defopt\psbcurve@defIfVoid{0}[#1]#2{ \psbcurve@codeCntr\psbcurve@codeCntrEnd \let\next\relax \advance\psbcurve@codeCntr by #1 \expandafter\ifx\csname % psbcurve@code\the\psbcurve@codeCntr#2\endcsname\relax% \def\next{\expandafter\def\csname % psbcurve@code\the\psbcurve@codeCntr#2\endcsname}% \fi\next} %% Essentially the same as \psbcurve@def (just \def replaced by \let): \defopt\psbcurve@let{0}[#1]#2{ \psbcurve@codeCntr\psbcurve@codeCntrEnd \advance\psbcurve@codeCntr by #1 \expandafter\let\csname psbcurve@code\the\psbcurve@codeCntr#2\endcsname} %% Syntax: %% \psbcurve@letvar[offset]{item}\MyVarToBeSet %% sets \MyVarToBeSet to the value of the list entry. %% See the definition of \psbcurve@def for a description %% of the list entry. \defopt\psbcurve@letvar{0}[#1]#2#3{ \psbcurve@codeCntr\psbcurve@codeCntrEnd \advance\psbcurve@codeCntr by #1 \def#3{\noexpand#3}% \expandafter\let\expandafter#3\csname psbcurve@code\the\psbcurve@codeCntr#2\endcsname} %% Syntax: %% \psbcurve@ifx[offset]{item}\MyVarToBeCompared %% That is essentially an \ifx with the list item compared to %% \MyVarToBeCompared. \defopt\psbcurve@ifx{0}[#1]#2{ \psbcurve@codeCntr\psbcurve@codeCntrEnd \advance\psbcurve@codeCntr by #1 \expandafter\ifx\csname psbcurve@code\the\psbcurve@codeCntr#2\endcsname} %% Syntax: %% \psbcurve@get{item} %% This expands to the macro corresponding to `item' from the %% list entry at \psbcurve@codeCntr. \def\psbcurve@get#1{\csname psbcurve@code\the\psbcurve@codeCntr#1\endcsname} %% Auxiliary macros: %%%%%%%%%%%%%%%%%%%%% %% Multiple branching %% Syntax: %% \psbcurve@switch\ExpandingToKey{KeyI,\MacroI,KeyII,\MacroII,...and so on...} %% If \ExpandingToKey expands to one of the keys KeyI, \KeyII, ... %% the corresponding \MacroI, \MacroII, ..., resp. is called. %% The key value \relax is special. Its corresponding \Macro is the %% default action which is taken if none of the Keys matches. \def\psbcurve@switch#1#2{% \def\next##1,##2,##3|{% \ifx#1##1\relax\def\next####1|{\let\next##2}\fi% \ifx##1\relax\def\next####1|{\let\next##2}\fi% \next##3|% }% \next#2,\relax,\relax,|\next} %% The user interface to psbcurve: %% Usage: See description in pst-bezier-doc.tex. %% The default value \relax for the optional argument indicates that %% there are no optional arguments. \defopt\psbcurve\relax[#1](#2){% \bgroup% Makes optional pstricks-settings local to this \psbcurve call. \ifx#1\relax\else% \psset{#1}% \fi% \def\psbcurve@code{% \moveto(#2)% \code{ << /Splines [%] begin of the array of splines [%] begin of the first dummy spline (just the start point) /n /n /n /n } \coor(#2) \code{% /n /n %[ ] % end of the first dummy spline }% end of \code }% %% Initialise the list of postscript code fragments: \psbcurve@codeCntrEnd0% \psbcurve@pointSetDefaults%% Init first spline. \psbcurve@def{l}{\coor(#2)}%% Default left control point of the first spline. \psbcurve@next%% Now, get the next arguments... } %% The following macro declare the pstricks option psbcurveTension %% and set it to its default value. \define@key[psset]{pst-bezier}{bcurveTension}[0.25]{\def\psk@bcurveTension{#1}} \psset{bcurveTension=0.25} %% Points of a spline that are not set yet %% to a certain value or action %% get the following value: \def\psbcurve@ptNotDef{\code{ /n /n }} %% A newly allocated spline gets the following defaults: \def\psbcurve@pointSetDefaults{% \psbcurve@defIfVoid{l}{\psbcurve@ptNotDef}% \psbcurve@defIfVoid{r}{\psbcurve@ptNotDef}% \psbcurve@defIfVoid{sl}{\code{ \psk@bcurveTension\space}}% \psbcurve@defIfVoid{sr}{\code{ \psk@bcurveTension\space}}% \psbcurve@defIfVoid{addon}{}% } %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Now, there comes a series of commands. Depending on the next optional modifier %% in the argument list of \psbcurve one of these is called. If there follows a %% point (x,y) without modifier \psbcurve@nextPoint is called. If there follows a token that %% does not make sense to \psbcurve \psbcurve@end is called. %% the modifier l \def\psbcurve@lPoint#1(#2){% \psbcurve@def{l}{\coor(#2)}% \psbcurve@next} %% the modifier r \def\psbcurve@rPoint#1(#2){% \psbcurve@def{r}{\coor(#2)}% \psbcurve@next} %% the modifier L \def\psbcurve@LPoint#1(#2){% \psbcurve@def{l}{\coor(#2)}% \psbcurve@def[-1]{r}{\code{ /s /s }}% \psbcurve@next} %% the modifier T \def\psbcurve@Tension#1#2{% \psbcurve@def{addon}{\psset{bcurveTension=#2}}% \psbcurve@next} %% The t modifier has some sub-modifiers %% These are recognised by this macro and the %% corresponding action is taken. \def\psbcurve@tension#1{\futurelet\psbcurve@tmp\psbcurve@@tension} %% \def\psbcurve@@tension{% \psbcurve@switch\psbcurve@tmp{% l,\psbcurve@ltension,% r,\psbcurve@rtension,% s,\psbcurve@stension,% \relax,\psbcurve@@@tension% }} %% the modifier t without further sub-modifiers \def\psbcurve@@@tension#1{% \psbcurve@def{sr}{\code{ #1 }}% \psbcurve@def{sl}{\code{ #1 }}% \psbcurve@next} %% the modifier ts \def\psbcurve@stension#1#2{% symmetric \psbcurve@def[-1]{sr}{\code{ #2 }}% \psbcurve@def{sl}{\code{ #2 }}% \psbcurve@next} %% the modifier tl \def\psbcurve@ltension#1#2{% left control point \psbcurve@def{sl}{\code{ #2 }}% \psbcurve@next} %% the modifier tr \def\psbcurve@rtension#1#2{% right control point \psbcurve@def{sr}{\code{ #2 }}% \psbcurve@next} %% This macro is called if the next token is %% no modifier but a point (x,y) \def\psbcurve@nextPoint(#1){% \psbcurve@def{}{\coor(#1)}% \advance\psbcurve@codeCntrEnd by 1 \psbcurve@pointSetDefaults% \psbcurve@next} %% If the next token does not make sense to \psbcurve %% the curve is finished. \def\psbcurve@end{ %% Do we need to set the last control point to its default? \def\tmp{\psbcurve@ptNotDef}% \psbcurve@ifx[-1]{r}\tmp% \psbcurve@letvar[-1]{}\tmp% \tmp is set to the end point \psbcurve@let[-1]{r}\tmp% last control point is set to \tmp \fi% %% pscustom deactivates showpoints: reverse this: \let\if@psbcurve@showpoints\ifshowpoints% \pscustom{% %% Following, the TeX-code fragments in \psbcurve@code... %% are executed. These compose the postscript spline array. \psbcurve@code% \psbcurve@codeCntr0 \loop% \code{[ %] }% \psbcurve@get{addon}% additional code \psbcurve@get{l}% left control point \psbcurve@get{r}% right control point \psbcurve@get{}% interpolation point \psbcurve@get{sl}% left scaling factor \psbcurve@get{sr}% right scaling factor \code{ %[ ] }% end of the spline. \advance\psbcurve@codeCntr by 1 \ifnum\psbcurve@codeCntr<\psbcurve@codeCntrEnd% \repeat% \code{%[ ] % end of the spline array /K 1 >> pstBCurve }% \if@psbcurve@showpoints% \pst@OpenShowPoints %% works fine, only the dashed lines are missing: \code{ \tx@BezierShowPoints }% \fi% }% \egroup% } %% The following macro reads the next argument from the \psbcurve argument list %% recognises optional modifiers and branches to the corresponding macro. \def\psbcurve@next{\futurelet\psbcurve@tmp\psbcurve@@next} \def\psbcurve@@next{% \psbcurve@switch\psbcurve@tmp{% (,\psbcurve@nextPoint,%) l,\psbcurve@lPoint,% r,\psbcurve@rPoint,% L,\psbcurve@LPoint,% t,\psbcurve@tension,% T,\psbcurve@Tension,% \relax,\psbcurve@end}% } \catcode`\@=\TheAtCode\relax \endinput