diff options
author | Karl Berry <karl@freefriends.org> | 2010-10-29 00:31:31 +0000 |
---|---|---|
committer | Karl Berry <karl@freefriends.org> | 2010-10-29 00:31:31 +0000 |
commit | 6bc1f5497cfb2f56d65c80a4c36ea3bad6dc046c (patch) | |
tree | f7751da75030fb1e06653eeb44e579fcee09c65f /Master/texmf-dist/tex/generic/pgf/modules | |
parent | ed0c7c756e441b2d2ba3633da233fc24361ac0d3 (diff) |
pgf 2.10 (28oct10)
git-svn-id: svn://tug.org/texlive/trunk@20236 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/tex/generic/pgf/modules')
8 files changed, 4247 insertions, 82 deletions
diff --git a/Master/texmf-dist/tex/generic/pgf/modules/pgfmoduledatavisualization.code.tex b/Master/texmf-dist/tex/generic/pgf/modules/pgfmoduledatavisualization.code.tex new file mode 100644 index 00000000000..1c78bb221e6 --- /dev/null +++ b/Master/texmf-dist/tex/generic/pgf/modules/pgfmoduledatavisualization.code.tex @@ -0,0 +1,3035 @@ +% 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 $Header: /cvsroot/pgf/pgf/generic/pgf/modules/pgfmoduledatavisualization.code.tex,v 1.37 2010/08/24 21:28:58 tantau Exp $ + +\usepgfmodule{oo,shapes} +\usepgflibrary{fpu} + + +% This module defines the basic framework for data visualization. + +% In order to visualize data, you first need data. The format for this +% data is not specified, indeed, different formats are possible. A +% data point is created each time the command \pgfdatapoint is +% used. The "parameters" of the data point are just the current values +% of the keys or macros in the current scope. +% +% A set of data points created using the \pgfdata command. +% When a data point is created, a number of signals are emitted, see +% the description of \pgfdatapoint. To actually visualize something, +% objects should be created that listen to these signals and that +% handle them. +% +% The following class manages a data visualization + +\pgfooclass{data visualization} +{ + % Class data visualization + % + % This class is used to "manage" a data visualization. It provides + % methods for hooking into the data visualization process and its + % constructor initializes the signals that are issued during a data + % visualization. + % + % When a data visualization object is created, a whole bunch of + % signal objects. You should then create objects that connect to + % these signals. They will be emitted when datapoints come + % available. + % + % It is permissible to have several data visualization objects + % active at the same time. + % + % To use a data visualization object, you should (possibly + % repeatedly) call the method add data() or the macro \pgfdata. You should also + % create transformation, mapping and visualization objects. Then, + % you should, first, call the method survey, which will "survey" the + % data, allowing the mapping and bounding objects to compute the + % correct ranges. You may then create further objects based on this + % data. Then, you should call the "visualize" method, which will + % invoke the visualization signals for the data points. + + + % These attribute store code that should be executed at certain + % points. The order is the following: + % + % 1. "before survey" code + % 2. "begin survey" phase signal + % 3. "at start survey" code + % 4. data points are processed + % 5. "at end survey" code + % 6. "end survey" phase signal + % 7. "after survey" code + % + % The first seven points will be repeated until the method "do + % another survey" is no longer called during a survey. + % + % 8. "before visualization" code + % 9. "begin visualization" phase signal + % 10. "at start visualization" code + % 11. data points are processed once more + % 12. "at end visualization" code + % 13. "end visualization" phase signal + % 14. "after visualization" code + \attribute before survey; + \attribute at start survey; + \attribute at end survey; + \attribute after survey; + \attribute before visualization; + \attribute at start visualization; + \attribute at end visualization; + \attribute after visualization; + + % + % Survey counts and handling + % + + \attribute survey count=1; + % Each time a survey is done before the visualization is done, this + % count is incremented. Normally, there is only one survey, but + % objects may request another survey or even more surveys to be + % done, giving them a chance to setup further internal values. By + % accessing this count (via the get survey count method), you can + % find out which survey is currently being done. + + \attribute number of surveys=1; + % By increasing this count, you can request additional surveys to be + % done. + + + % Stores the to-be-visualized data + \attribute data; + + + % Stores the signal objects + \attribute prepare datapoint signal; + \attribute map datapoint signal; + \attribute transform datapoint signal; + \attribute visualize datapoint signal; + \attribute finish datapoint signal; + \attribute survey datapoint signal; + \attribute phase signal; + \attribute path signal; + \attribute direction signal; + \attribute style signal; + + + % Constructor + % + % Inits the signals + \method data visualization() { + \pgfoonew{prepare datapoint signal}=new signal()% + \pgfoonew{map datapoint signal}=new signal()% + \pgfoonew{transform datapoint signal}=new signal()% + \pgfoonew{visualize datapoint signal}=new signal()% + \pgfoonew{finish datapoint signal}=new signal()% + \pgfoonew{survey datapoint signal}=new signal()% + \pgfoonew{phase signal}=new signal()% + \pgfoonew{path signal}=new signal()% + \pgfoonew{direction signal}=new signal()% + \pgfoonew{style signal}=new signal()% + % + % Store this object in a key + % + \pgfoothis.get handle(\pgf@dv@me) + \pgfkeyslet{/pgf/data visualization/obj}\pgf@dv@me + } + + % The phase signal will emit the following constants: + \def\pgfdvbeforesurvey{1} + \def\pgfdvbeginsurvey{2} + \def\pgfdvendsurvey{3} + \def\pgfdvaftersurvey{4} + \def\pgfdvbeforevisualization{5} + \def\pgfdvbeginvisualization{6} + \def\pgfdvendvisualization{7} + \def\pgfdvaftervisualization{8} + + % The path signale will meit the following constants: + \def\pgfdvpathmovetotoken{5} + \def\pgfdvpathlinetotoken{6} + \def\pgfdvdirectionfromtoken{7} + \def\pgfdvdirectiontotoken{8} + + % Method + % + % Connect the object #1's slot "#2" to the signal named "#3" + \method connect(#1,#2,#3) { + \pgfoovalueof{#3}.connect(#1,#2) + } + + % Method + % + % Add data that is to be visualized. The code #1 should call the + % \pgfdatapoint macro for each data point it creates. + \method add data(#1) { + \pgfooappend{data}{#1} + } + + + % Setters + \method before survey(#1) { + \pgfooappend{before survey}{#1} + } + \method at start survey(#1) { + \pgfooappend{at start survey}{#1} + } + \method before visualization(#1) { + \pgfooappend{before visualization}{#1} + } + \method at start visualization(#1) { + \pgfooappend{at start visualization}{#1} + } + + % Method + \method at end survey(#1) { + \pgfooprefix{at end survey}{#1} + } + \method after survey(#1) { + \pgfooprefix{after survey}{#1} + } + \method at end visualization(#1) { + \pgfooprefix{at end visualization}{#1} + } + \method after visualization(#1) { + \pgfooprefix{after visualization}{#1} + } + + + % Method + % + % Copy the signals to macros. This is just for efficiency (ha!) + \method prepare signal macros() { + \pgfooget{prepare datapoint signal}\pgf@signalpreparedatapoint + \pgfooget{map datapoint signal}\pgf@signalmapdatapoint + \pgfooget{transform datapoint signal}\pgf@signaltransformdatapoint + \pgfooget{visualize datapoint signal}\pgf@signalvisualizedatapoint + \pgfooget{finish datapoint signal}\pgf@signalfinishdatapoint + \pgfooget{survey datapoint signal}\pgf@signalsurveydatapoint + \pgfooget{phase signal}\pgf@signalphase + \pgfooget{path signal}\pgf@signalpath + \pgfooget{direction signal}\pgf@signaldirection + \pgfooget{style signal}\pgf@signalstyle + } + + + % Survey method + % + % Call this method to "survey" the data. This should be done before + % the "visualize" method is called. + \method survey() { + % Survey phase. + \let\pgfdatapoint=\pgfdatapoint@surveyphase% + \pgfoothis.prepare signal macros() + \pgfooset{survey count}{1} + \pgfutil@loop + \pgf@signalphase.emit(\pgfdvbeforesurvey) + \pgfoovalueof{before survey}% + \pgf@signalphase.emit(\pgfdvbeginsurvey) + \pgfoovalueof{at start survey} + \pgfoovalueof{data}% + \pgfoovalueof{at end survey} + \pgf@signalphase.emit(\pgfdvendsurvey)% + \pgfoovalueof{after survey} + \pgf@signalphase.emit(\pgfdvaftersurvey) + \c@pgf@counta=\pgfoovalueof{survey count}\relax + \c@pgf@countb=\pgfoovalueof{number of surveys}\relax + \ifnum\c@pgf@counta<\c@pgf@countb + \advance\c@pgf@counta by1\relax + \pgfooeset{survey count}{\the\c@pgf@counta} + \pgfutil@repeat + } + + % Getter + \method get survey count(#1) { + \pgfooget{survey count}{#1} + } + + % Request another survey to be done + \method do an additional survey() { + \c@pgf@counta=\pgfoovalueof{number of surveys}\relax + \advance\c@pgf@counta by1\relax + \pgfooeset{number of surveys}{\the\c@pgf@counta} + } + + % Visualize method + % + % This method will cause the actual visualization. + \method visualize() { + % Visualization phase. + \let\pgfdatapoint=\pgfdatapoint@visualizationphase% + \pgfoothis.prepare signal macros() + \pgf@signalphase.emit(\pgfdvbeforevisualization)% + \pgfoovalueof{before visualization} + \pgf@signalphase.emit(\pgfdvbeginvisualization)% + \pgfoovalueof{at start visualization} + \pgfoovalueof{data}% + \pgfoovalueof{at end visualization} + \pgf@signalphase.emit(\pgfdvendvisualization)% + \pgfoovalueof{after visualization} + \pgf@signalphase.emit(\pgfdvaftervisualization)% + } +} + + +% +% The data point keys +% +% Unlike other keys, the subkeys of /data point/ can simply be set +% directly. If the key has not been initialized, it will automatically +% be. +\pgfkeys{/data point/.unknown/.code={% + \pgfkeyssetvalue{/data point/\pgfkeyscurrentname}{#1} + }} + + + + +% Create and handle a data point +% +% Description: +% +% This command is called by the survey and the visualize methods +% whenever a complete data point has been produced. Depending on the +% current circumstances, different signals will be emitted. +% +% The data that is represented by the data point is not given as a +% parameter. Rather, it is stored in macros and keys, that is, the +% data point is conceptually given by the settings of all the keys and +% macros in the local scope. +% +% There are two phases to data processing: In the survey phase data +% points are produced and handled in order to find out things like +% their number or the minimum and maximum values of attributes, so +% that axes and picture sizes can be prepared correctly. In the +% visualization phase, data point are actually shown. +% +% During the survey phase, for each data point the signal +% "surveydatapoint" is emitted. +% +% During the visualization phase, more signals are emitted. A prepare +% signal is emitted first, giving all objects a +% chance to "prepare" for the data point. Note that it is permissible +% for an object to manipulate the data point here (and also +% in later on). +% +% Next, the command \pgfdvmapdatapointtocanvas is called. Mainly, +% the effect of this command is to setup the keys /data point/canvas x +% and /data point/canvas y, see the description of this command for +% more details. +% +% The next step consists of signaling "visualize data point". Objects +% listening to this will cause some form of visualization of the +% data point to occur. +% +% Before the visualization is started, it is checked whether the key +% /data point/name is set (to a non-empty value). If so, +% a coordinate is created with the given canvas x and y values and +% this key's value as name. +% +% Finally, finish data point allows objects to do any final processing +% of the data point. + +\def\pgfdatapoint@surveyphase{% + \pgf@signalpreparedatapoint.emit()% + \pgf@signalmapdatapoint.emit()% + \pgf@signalsurveydatapoint.emit()% +} + +\def\pgfdatapoint@visualizationphase{% + \pgf@signalpreparedatapoint.emit()% + \pgfdvmapdatapointtocanvas% + \pgfkeysifdefined{/data point/name} + {% + \pgfcoordinate{\pgfkeysvalueof{/data point/name}}{\pgfpointdvdatapoint}% + }{}% + \pgf@signalvisualizedatapoint.emit()% + \pgf@signalfinishdatapoint.emit()% +} + + + +% Compute a position of a data point +% +% Description: +% +% This command uses a special signal to compute the position where a +% data point should be visualized on the canvas. In detail, the +% following happens: +% +% A local scope is created and the +% transformation matrix is reset. Then, two signals are emitted: First, +% "map data points" and then "transform data point". The first +% lets listening objects "map" the object by setting up +% attributes of the data point. The second asks objects +% listening to this signal to transform the current transformation +% matrix. After the signals, we compute where +% the origin lies inside this transformed coordinate system. Then the +% two keys /data point/canvas x and /data point/canvas y are set to +% the values of this position. The local scope ends (but the settings +% of the keys persist by a bit of magic), thus restoring the +% transformation matrix to its original value. + +\def\pgfdvmapdatapointtocanvas{% + {% + \pgfpointdvlocaldatapoint + % Smuggle outside group + \expandafter% + }% + \edef\pgf@marshal{% + \noexpand\pgfkeyssetvalue{/data point/canvas x}{\the\pgf@x} + \noexpand\pgfkeyssetvalue{/data point/canvas y}{\the\pgf@y} + }% + \pgf@marshal% +} + +% Help functions for locating a canvas data point +% +% Description: +% +% The first function returns the data point computed by a +% canvasposition... call. + +\def\pgfpointdvdatapoint{% + \pgfqpoint{\pgfkeysvalueof{/data point/canvas x}}{\pgfkeysvalueof{/data point/canvas y}}% +} + +\def\pgfpointdvlocaldatapoint{% + {% + % only returns the data point in \pgf@x and \pgf@y, does not set + % canvas x and canvas y + \pgf@signalmapdatapoint.emit()% + \pgftransformreset% + \pgf@signaltransformdatapoint.emit()% + \pgfpointtransformed{\pgfpointorigin}% + }% +} + + + +% +% Special path constructions commands +% +% +% The following commands are used to construct paths based on +% datapoints. +% +% Normally, all these methods need to do is to compute the current +% canvas position of the current data point and then do a moveto, +% lineto or some other operation to this position. +% +% However, when the coordinate system is weird, like with polar +% coordinates or spherical or log-polar coordinate or whatever, a +% straight line "along an attribute" is no longer a straight line. +% In this case, two actions can be taken: +% +% 1. The problem can be ignored, resulting in a wrong line. +% 2. Some clever algorithm kicks in an replaces the straight line by +% the correct replacement. +% +% As always, when a computer tries to be clever, things can go +% wrong... Nevertheless, some support for the second method is +% given. This works as follows: Objects can register to the data +% visualization path signal. This signal is emitted every time the +% lineto or moveto commands are executed. If an object reacts to such +% a command and handles it, it should set +% \pgfdvhandledtrue. + +\newif\ifpgfdvhandled + +\def\pgfdv@generic#1#2#3{% + {% + \pgfdvhandledfalse% + \pgf@signalmapdatapoint.emit()% + #1.emit(#2)% + \ifpgfdvhandled% + \else% + \pgf@process{% + \pgftransformreset% + \pgf@signaltransformdatapoint.emit()% + \pgfpointtransformed{\pgfpointorigin}% + }% + #3{}% + \fi% + }% +} + + +% Handle a moveto +% +% This command has no parameters since the target of the moveto is +% given by the canvas position of the current local data point. +\def\pgfpathdvmoveto{% + \pgfdv@generic{\pgf@signalpath}{\pgfdvpathmovetotoken}{\pgfpathmoveto} +} + + +% Handle a lineto +% +% This command has no parameters since the target of the moveto is +% given by the canvas position of the current local data point. +\def\pgfpathdvlineto{% + \pgfdv@generic{\pgf@signalpath}{\pgfdvpathlinetotoken}{\pgfpathlineto} +} + + + +% Compute a normalized vector pointing from some point to another. +% +% #1 = code for setting the attributes of the first point +% #2 = code for setting the attributes of the second point +% +% Using #1 and #2 you specify two data points. These are then +% localized on the canvas and a vector pointing from the first data +% point to the second one is returned. However, for instance in polar +% coordinates the vector may actually "point along" the angle axis. +% +% Internally, this command first sets up the first data point and then +% emits a "path" signal with the \pgfdvpathdirectionfromtoken set and +% then sets up the second point and emits the corresponding +% ...totoken. +% + +\def\pgfpointdvdirection#1#2{% + { + { + #1 + \pgfdv@generic{\pgf@signaldirection}{\pgfdvdirectionfromtoken}{\xdef\pgf@dv@from{\noexpand\pgfqpoint{\the\pgf@x}{\the\pgf@y}}} + } + { + #2 + \pgfdv@generic{\pgf@signaldirection}{\pgfdvdirectiontotoken}{ + \edef\pgf@dv@dir@xa{\the\pgf@x} + \edef\pgf@dv@dir@ya{\the\pgf@y} + \pgf@process{ + \pgfpointnormalised{% + \pgfpointdiff{\pgf@dv@from}{\pgfqpoint{\pgf@dv@dir@xa}{\pgf@dv@dir@ya}} + } + } + } + } + } +} + + + + + +% +% +% Data parsing and formatting +% +% + + + +% Run the rendering pipeline on a dataset. +% +% #1 = options with path /pgf/data/ +% #2 = optionally data given inline in curly braces. +% +% Description: +% +% This command is used to define a data set. For a single data +% visualization, multiple data sets can be defined, they will +% accumulate. Data can be in different formats, as specified by the +% "format" key, and you can define new formats. +% +% The setting of the following keys is important: +% +% /pgf/data visualization/obj contains a handle to the dv-object +% /pgf/data/format stores the format (see below) +% /pgf/data/source determines where the data is. +% +% If source is empty, the data is stored in the argument that +% follows. Otherwise, the file whose name is stored in source is read. +% This data is stored in an internal variable, which is local to the +% current group. +% +% After the group, the key "/pgf/data/continue code" will be +% executed. +% +% When the data is actually used later on (during a survey or a +% visualization), independently of what source is used, a format +% handler is started for each data set. This works as follows: first, +% the handler's startup code is executed. Then for each line of the +% data file/the data given inline, the line handler function is +% called. Finally, the data format end handler is called. +% +% The format handler's job is to call \pgfdatapoint each time a +% complete data point has been produced. +% +% Example: +% +% \pgfoonew \dv=new data visualization() +% \pgfoonew \obj=new attribute mapper(...) +% ... +% +% \pgfkeys{/pgf/data/.cd, +% column 1=dax/low, +% column 2=dax/high, +% column 3=dax/entry, +% column 4=dax/exit} +% +% \pgfdata[format=space separated columns] +% { +% % today +% 2000 2300 2100 2200 +% 2000 2350 2200 2500 +% 2200 2300 2250 2260 +% 1800 2260 2260 1900 +% 2000 2300 2100 2200 +% } +% +% \pgfdata[format=comma separated columns] +% { +% % yesterday +% 2000, 2350, 2200, 2250 +% 2200, 2300, 2250, 2260 +% } +% +% \pgfdata[source=data,format=comma separated columns] +% +% \dv.survey() +% \dv.visualize() + +\def\pgfdata{\pgfutil@ifnextchar[{\pgf@dataset@data@opt}{\pgf@dataset@data@opt[]}}%} +\def\pgf@dataset@data@opt[#1]{% + % Ok, add one data thing... + \pgfkeysvalueof{/pgf/data visualization/obj}.add data(\pgf@do@data{#1})% + \begingroup% + \pgfkeys{/pgf/data/.cd,/pgf/every data/.try,#1}% + \pgfkeysgetvalue{/pgf/data/continue code}\pgf@dv@cont@code% + \global\let\pgf@dv@cont@code\pgf@dv@cont@code% + \pgfkeysgetvalue{/pgf/data/format}\pgf@dv@format% + \expandafter\let\expandafter\pgf@dv@format@catcodes\csname pgfdv@format@\pgf@dv@format @catcodes\endcsname% + \ifx\pgf@dv@format@catcodes\relax + \PackageError{pgf}{Unknown data format '\pgf@dv@format'}{}% + \else% + \pgfkeysgetvalue{/pgf/data/source}\pgf@dv@source% + \ifx\pgf@dv@source\pgfutil@empty% + \let\pgf@next\pgf@dataset@grab@inline% + \else% + \let\pgf@next\pgf@dataset@grab@external% + \fi% + \pgf@next% +} +\def\pgf@dataset@grab@inline{% + \pgfutil@ifnextchar\bgroup{% + \begingroup% + \catcode`\^^M=\active% + \pgf@dv@format@catcodes% + \pgf@dataset@grab@@inline}% + {\PackageError{pgf}{Opening brace expected}{}}% +} +\def\pgf@dataset@grab@external{% + \fi% + \endgroup% + \pgfkeysvalueof{/pgf/data visualization/obj}.add data({{{\pgf@dataset@do@external}}})% + \pgf@dv@cont@code% +} + +{\catcode`\^^M=\active% + \gdef\pgf@dataset@grab@@inline#1{% + \endgroup% + \pgfkeysvalueof{/pgf/data visualization/obj}.add data({{{\pgf@dataset@do@inline#1^^M\pgf@@eol}}})% + \fi% + \endgroup% + \pgf@dv@cont@code% + }% +}% +\def\pgf@@eol{\pgf@eol} + +\def\pgf@do@data#1#2{% + \begingroup% + \pgfkeys{/pgf/data/.cd,/pgf/every data/.try,#1}% + \pgfkeysgetvalue{/pgf/data/format}\pgf@dv@format% + \expandafter\let\expandafter\pgf@dv@format@line\csname pgfdv@format@\pgf@dv@format @line\endcsname% + \expandafter\let\expandafter\pgf@dv@format@emptyline\csname pgfdv@format@\pgf@dv@format @empty\endcsname% + \csname pgfdv@format@\pgfkeysvalueof{/pgf/data/format}@startup\endcsname% + #2% + \csname pgfdv@format@\pgfkeysvalueof{/pgf/data/format}@end\endcsname% + \endgroup% +} + + +% +% Read external file +% + +\def\pgf@dataset@do@external{% + \csname pgfdv@format@\pgfkeysvalueof{/pgf/data/format}@catcodes\endcsname% + \immediate\openin\r@pgf@reada=\pgfkeysvalueof{/pgf/data/source} % + \ifeof\r@pgf@reada\relax + \PackageError{pgf}{Data source '\pgfkeysvalueof{/pgf/data/source}' not found}{}% + \else + \pgf@dataset@readline% + \fi + \immediate\closein\r@pgf@reada% +} + +\def\pgf@partext{\par}% +\def\pgf@dataset@readline{% + \immediate\read\r@pgf@reada to \pgf@temp% + \ifx\pgf@temp\pgf@partext% + \pgf@dv@format@emptyline% + \else% + \ifx\pgf@temp\pgfutil@empty% + \pgf@dv@format@emptyline% + \else% + \expandafter\pgf@dv@format@line\pgf@temp\pgfeol% + \fi% + \fi% + \ifeof\r@pgf@reada\else\expandafter\pgf@dataset@readline\fi% +} + + +% +% Read inline data +% + +\def\pgf@dataset@do@inline{% + \pgf@dv@handle@line% +} + +{\catcode`\^^M=\active% +\gdef\pgf@dv@handle@line{% + \pgfutil@ifnextchar^^M{\pgf@dv@format@emptyline\expandafter\pgf@dv@handle@line\pgfutil@gobble}% + {\pgfutil@ifnextchar\pgf@@eol{\pgfutil@gobble}{\pgf@dv@handle@nonemptyline}}% +}% +\gdef\pgf@dv@handle@nonemptyline#1^^M{% + \pgf@dv@format@line#1\pgfeol% + \pgf@dv@handle@line% +}% +} + +\pgfkeys{ + /pgf/data/data visualization obj/.initial=\undefined, + /pgf/data/format/.initial=table,% the default format + /pgf/data/source/.initial=, + /pgf/data/continue code/.initial= +} + + + + + + +% Define a data format +% +% #1 = format name +% #2 = catcode code +% #3 = startup code +% #4 = line arguments +% #5 = line code +% #6 = empty line code +% #7 = end code +% +% Description: +% +% This command defines a new data format for data visualization. When +% a data set is visualized and the format is set to #1, this handler +% is used to parse the data. +% +% In detail, the \dataset command will select a source. Before this +% source is read, #2 will be executed to setup the +% catcodes. Additionally, each time the data is parsed, #3 will be +% called. Then, for each nonempty line of the source, the +% command #5 is executed, where the line will be matched against the +% argument pattern given in #4. For empty lines, #6 will be executed +% instead. At the end of the source, #7 will be executed. + +\def\pgfdeclaredataformat#1#2#3#4#5#6#7{% + \expandafter\def\csname pgfdv@format@#1@catcodes\endcsname{#2}% + \expandafter\def\csname pgfdv@format@#1@startup\endcsname{#3}% + \expandafter\def\csname pgfdv@format@#1@line\endcsname#4\pgfeol{#5}% + \expandafter\def\csname pgfdv@format@#1@empty\endcsname{#6}% + \expandafter\def\csname pgfdv@format@#1@end\endcsname{#7}% +} + + + +% +% Predefined standard formats +% + +% TeX code format +% +% Description: +% +% The lines of the data set are assumed to contain executable TeX +% code that will call \pgfdatapoint. +% +% Example: +% +% \pgfdatavisualizationrender[format=TeX code] +% \dataset{ +% \pgfkeyssetvalue{/data point/x}{5} +% \pgfkeyssetvalue{/data point/y}{5} +% \pgfdatapoint +% \pgfkeyssetvalue{/data point/x}{6} +% \pgfkeyssetvalue{/data point/y}{6} +% \pgfdatapoint +% } + +\pgfdeclaredataformat{TeX code}{}{}{#1}{#1 }{}{} + + + +% Key-value lines format +% +% Description: +% +% The lines of the data set are passed to \pgfkeys with the path set +% to /data point. +% +% Example: +% +% \data[format=key value pairs] { +% x=5, y=6, hi=9 +% x=7, y=6, lo=10 +% } + +\pgfdeclaredataformat{key value pairs}{}{}{#1}{{\pgfkeys{/data point/.cd,#1}\pgfdatapoint}}{}{} + + + + + +% Table format +% +% Description: +% +% A table consists of a head line, which contains the attribute names +% of the values that will be found in the following lines. Each line +% (except for the headline) contains one data point. +% +% Inside each line the data points are separated by a separator like a +% comma or a space or a colon. The separator can be configured using +% the key /pgf/data/separator (leave the separator empty or set it to +% \space for a space as separator). The default separator is a comma. +% +% Some tables will miss the headline. In this case, using the +% /pgf/data/headline key you can provide a headline yourself. +% +% Example: +% +% \data[format=table] { +% x y +% 10 5 +% 11 6 +% 6 7 +% } +% +% \data[format=table,separator={,}] { +% x, y +% 10, 5 +% 11, 6 +% 6, 7 +% } +% +% \data[format=table,headline=x y] { +% 10 5 +% 11 6 +% 6 7 +% } + +\pgfdeclaredataformat{table} +{} % no catcodes +{ + \pgfkeysgetvalue{/pgf/data/headline}\pgf@dv@headline + \pgfkeysgetvalue{/pgf/data/separator}\pgf@dv@separator + \ifx\pgf@dv@separator\pgfutil@empty + \let\pgf@dv@separator\space + \fi + \ifx\pgf@dv@separator\pgf@dv@spacetext + \let\pgf@dv@separator\space + \fi + \expandafter\def\expandafter\pgf@dv@till@separator% + \expandafter##\expandafter1\pgf@dv@separator{\pgf@dv@table@handle{##1}} + \expandafter\def\expandafter\pgf@dv@till@separator@head% + \expandafter##\expandafter1\pgf@dv@separator{\pgf@dv@head@handle{##1}} + \ifx\pgf@dv@headline\pgfutil@empty + % Ok, read headline from file + \pgfdv@firstlinetrue + \else + % Headline already set + \pgfdv@firstlinefalse + \expandafter\pgf@dv@parse@headline\expandafter{\pgf@dv@headline} + \fi +} +{#1} % special line pattern, so read everything +{ + \ifpgfdv@firstline + \pgfdv@firstlinefalse + \pgf@dv@parse@headline{#1} + \else + { + \c@pgf@counta=0\relax% keep track of attribute number + \def\pgf@marshal{\pgf@dv@parse@table#1} + \expandafter\expandafter\expandafter\pgf@marshal% + \expandafter\pgf@dv@separator\expandafter\pgfeol\pgf@dv@separator + \pgfdatapoint + } + \fi +} +{} % ignore empty lines +{} % no special end code + +\newif\ifpgfdv@firstline + +\pgfkeys{ + /pgf/data/separator/.initial={,}, + /pgf/data/headline/.initial= +} +\def\pgf@dv@spacetext{\space} + +\def\pgf@dv@parse@table{% + \pgfutil@ifnextchar"% Special, but ignored right now... + {\PackageError{pgf}{csv with quotes not yet implemented}{}} + {\pgf@dv@till@separator} +} +\def\pgf@dv@table@handle#1{% + \def\pgf@temp{#1}% + \ifx\pgf@temp\pgfeoltext% + % Bingo! Stop + \let\pgf@next=\relax% + \else% + \advance\c@pgf@counta by1\relax% + \pgfkeysgetvalue{/pgf/data/table/attribute \the\c@pgf@counta}\pgf@dv@target + \ifx\pgf@dv@target\relax% + \edef\pgf@dv@target{attribute \the\c@pgf@counta} + \pgfkeyslet{/pgf/data/table/attribute \the\c@pgf@counta}\pgf@dv@target + \fi + \pgfkeyssetvalue{/data point/\pgf@dv@target}{#1} + \let\pgf@next=\pgf@dv@parse@table% + \fi% + \pgf@next% +} + + + +\def\pgf@dv@parse@headline#1{ + \c@pgf@counta=0\relax% keep track of attribute number + \def\pgf@marshal{\pgf@dv@doparse@headline#1} + \expandafter\expandafter\expandafter\pgf@marshal% + \expandafter\pgf@dv@separator\expandafter\pgfeol\pgf@dv@separator +} + +\def\pgf@dv@doparse@headline{% + \pgfutil@ifnextchar"% Special, but ignored right now... + {\PackageError{pgf}{csv with quotes not yet implemented}{}} + {\pgf@dv@till@separator@head} +} +\def\pgf@dv@head@handle#1{% + \def\pgf@temp{#1}% + \ifx\pgf@temp\pgfeoltext% + % Bingo! Stop + \let\pgf@next=\relax% + \else% + \advance\c@pgf@counta by1\relax% + \pgfkeyssetvalue{/pgf/data/table/attribute \the\c@pgf@counta}{#1} + \let\pgf@next=\pgf@dv@doparse@headline% + \fi% + \pgf@next% +} + +\def\pgfeoltext{\pgfeol} + + +% +% +% Micro math kernel for dv +% +% + +% The idea behind the following methods is to "abstract away" which +% math engine is used. In the future, something fancy build on luatex +% might be used, so it would we should not rely directly on the +% fpu library code. +% +% The system works as follows: First, you "enter" a number into the +% engine. When you do so, it is converted into some internal +% representation that cannot be accessed any more and is called a +% "math variable" henceforth. All commands of the +% math system only work on math variables. +% +% In order to "exit" a value stored in a math variable from the +% engine, some other macros can be used. +% +% Operations like addition or multiplication take two math variables +% and store the result in another math variable. + + + +% Store a value in a math variable of the math engine +% +% #1 = a math variable (a macro name) that is to store the value +% #2 = an expression describing a number +% +% +% Description: +% +% The #2 should be an expression that evaluates to a number. However, +% due to the way the pgf math engine(s) work, currently, there are +% several restrictions/the syntax is not as simple as one might +% hope. Fortunately, the syntax is hopefully compatible with +% easier-to-use future systems. +% +% The syntax is as follows: #2 may be +% +% 1. a simple high-precision number. This number is currently directly +% passed to \pgfmathfloatparsenumber, so typical permissible values +% are "100" or "10000000000000" or "nan" or "-5.673543345345e9000" +% +% 2. a mathematical expression, which *must* be surrounded by +% parantheses. From a "mathematical" point of view these +% parantheses are superfluous, but the they are used to help pgf +% distinguish expressions from high-precision numbers. (If, in the +% future, expressions may contain high precision numbers, the +% parantheses will simply be ignored.) +% +% The expression is evaluated using \pgfmathparse, which means that +% TeX-precision is used. This means, for instance, that numbers +% larger than about 16500 will create error messages. +% +% The advantage is that you may say write things like "(5+6)" or +% "(pi/2)". +% +% 3. In case #2 starts with an exclamation mark (indicating an +% "escape"), everything following the mark is simply evaluated by +% TeX. The effect of evaluating #2 should be that the math +% variable "\pgfdvmathvalue" is set to some value. This value will +% then be transferred to #1. +% +% 4. In case #2 is the result of calling \pgfdvmathexitbyserializing, the +% "serialized" value is restored. The idea is that the serialized +% will turn its internal representation of a number into something +% that can be stored as a text somewhere. +% +% Currently, "@" at the beginning of #2 is used to indicate that +% what follows is a serialized version of a math variable. +% +% In order to determine which of the above cases is to be used for a +% variable, the first symbol #2 is checked, *after* the first symbol +% of #2 has been expanded once (using \expandafter once). +% +% Example: +% +% \pgfdvmathenter{\mymacro}{20000000000000} +% \pgfdvmathenter{\mymacro}{(5+pi)} +% \pgfdvmathenter{\mymacro}{!\pgfdvmathadd{\pgfdvmathvalue}{\a}{\b}} +% +% \pgfdvmathenter{\foo}{5} +% \pgfdvmathexitbyserializing{\somevalue}{\foo} +% \pgfdvmathenter{\mymacro}{\somevalue} + +\def\pgfdvmathenter#1#2{% + \expandafter\pgfdvmathenter@check\expandafter#1#2\pgfdvmath@end% +} +\def\pgfdvmathenter@check#1{% + \pgfutil@ifnextchar @{\pgfdvmath@internal#1}{% + \pgfutil@ifnextchar ({\pgfdvmath@expression#1}{%) + \pgfutil@ifnextchar !{\pgfdvmath@execute#1}{\pgfdvmath@normal#1}}}% +} + +\def\pgfdvmath@internal#1@#2\pgfdvmath@end{% + \def#1{#2}% +} +\def\pgfdvmath@expression#1(#2)#3\pgfdvmath@end{% + \pgfmathparse{#2}% + \pgfmathfloatparsenumber{\pgfmathresult}% + \let#1=\pgfmathresult% +} +\def\pgfdvmath@execute#1!#2\pgfdvmath@end{% + #2% + \let#1=\pgfdvmathvalue% +} +\def\pgfdvmath@normal#1#2\pgfdvmath@end{% + \pgfmathfloatparsenumber{#2}% + \let#1=\pgfmathresult% +} + + + +% Print a math variable in the math engine using \pgfmathprintnumber +% +% #1 = math variable +% +% Description: +% +% See the description of \pgfmathprintnumber +% +% Example: +% +% \pgfdvmathenter{\mymacro}{20000000000000} +% \pgfdvmathexitbyprinting{\mymacro} + +\def\pgfdvmathexitbyprinting#1{% + \pgfmathprintnumber{#1}% +} + + + +% Exit a math variable as a number in a scientific and portable number +% format in a macro +% +% #1 = macro in which to store the value +% #2 = math variable +% +% Description: +% +% You can exit a number using this operation. You can then directly +% reenter the number using \pgfdvmathenter +% +% Example: +% +% \pgfdvmathenter{\mynumber}{20000000000000} +% \pgfdvmathexitbyscientificformat{\mymacro}{\mynumber} + +\def\pgfdvmathexitbyscientificformat#1#2{% + \edef#1{\pgfmathfloatvalueof#2}% +} + + + +% Exit a math variable as a "serialized" (= string-based) +% version. +% +% #1 = macro in which to store the value +% #2 = math variable +% +% Description: +% +% The serialized version can be reentered using +% \pgfmathenter and is similar to \pgfdvmathexitbyscientificformat, +% but exiting and entering are (a bit) faster. +% +% Example: +% +% \pgfdvmathenter{\mynumber}{20000000000000} +% \pgfdvmathexitbyserializing{\mymacro}{\mynumber} + +\def\pgfdvmathexitbyserializing#1#2{% + \edef#1{@#2}% +} + + + + + +% Operations on two numbers +% +% #1 = macro that should store the result of applying the +% corresponding operation to the following: +% #2 = entered number +% #3 = entered number +% +% Description: +% +% Sets #1 to the result of applying an operation to #2 and #3 +% +% Example: +% +% \pgfdvmathenter{\a}{2000} +% \pgfdvmathenter{\b}{5+6} +% \pgfdvmathadd{\c}{\a}{\b} + +\def\pgfdvmathadd#1#2#3{% + \pgfmathfloatadd{#2}{#3}% + \let#1=\pgfmathresult% +} +\def\pgfdvmathsub#1#2#3{% + \pgfmathfloatsubtract{#2}{#3}% + \let#1=\pgfmathresult% +} +\def\pgfdvmathmul#1#2#3{% + \pgfmathfloatmultiply{#2}{#3}% + \let#1=\pgfmathresult% +} +\def\pgfdvmathdiv#1#2#3{% + \pgfmathfloatdivide{#2}{#3}% + \let#1=\pgfmathresult% +} + + + + +% Log, ln and exponent functions +% +% #1 = a math variable +% #2 = a math variable +% +% Description +% +% \pgfdvmathln will compute #1 = ln(#2) +% \pgfdvmathlog will compute #1 = log_{10}(#2) +% \pgfdvmathexp will compute #1 = exp(#2) +% \pgfdvmathpowten will compute #1 = 10^{#2} + +\def\pgfdvmathln#1#2{% + \pgfmathfloatln{#2}% + \let#1=\pgfmathresult% +} + +\def\pgfdvmathlog#1#2{% + \pgfmathfloatln{#2}% + \pgfmathfloatmultiply{\pgfmathresult}{\pgfdvmathalwaysloge}% + \let#1=\pgfmathresult% +} + +\def\pgfdvmathexp#1#2{% + \pgfmathfloatexp{#2}% + \let#1=\pgfmathresult% +} + +\def\pgfdvmathpowten#1#2{% + \pgfmathfloattofixed{#2}% + \let\pgf@dv@temp=\pgfmathresult% + \pgfmathround{\pgf@dv@temp}% + \let\pgf@dv@temp@round=\pgfmathresult% + \pgf@x=\pgf@dv@temp@round pt% + \pgf@x=-\pgf@x% + \advance\pgf@x by\pgf@dv@temp pt\relax% + \ifdim\pgf@x>0.0002pt% + \pgfmathfloatmultiply{#2}{\pgfdvmathalwayslnten}% + \pgfmathfloatexp{\pgfmathresult}% + \else + \ifdim\pgf@x<-0.0002pt% + \pgfmathfloatmultiply{#2}{\pgfdvmathalwayslnten}% + \pgfmathfloatexp{\pgfmathresult}% + \else + \pgf@x=\pgf@dv@temp@round sp% + \c@pgf@counta=\pgf@x% + \pgfmathfloatcreate{1}{1.0}{\the\c@pgf@counta}% + \fi + \fi + \let#1=\pgfmathresult% +} + + +% Floor functions +% +% #1 = a math variable +% #2 = a math variable +% +% Description +% +% Sets #1 to the largest integer less or equal to #2 + +\def\pgfdvmathfloor#1#2{% + \pgfmathifisint{#2}{% + \let#1=#2% + }{% + \pgfmathfloatgetflags#2\c@pgf@counta% + \ifcase\c@pgf@counta + \let#1=\pgfdvmathalwayszero% + \or + \pgfmathfloatfloor{#2}% + \let#1=\pgfmathresult% + \or + \pgfmathfloatsubtract{\pgfdvmathalwaysone}{#2}% + \pgfmathfloatfloor{\pgfmathresult}% + \pgfmathfloatsubtract{\pgfdvmathalwayszero}{\pgfmathresult}% + \let#1=\pgfmathresult% + \or\let#1=#2% + \or\let#1=#2% + \or\let#1=#2% + \fi% + }% +} + + +% Advanced unary operations +% +% #1 = macro that should store the result of applying the +% operation to an entered number +% #2 = the operation (as a string like "ln") +% #3 = entered number +% +% Description: +% +% Sets #1 to the result of applying #2 to #3 +% +% Example: +% +% \pgfdvmathenter{\a}{2000} +% \pgfdvmathunaryop{\b}{ln}{\a} + +\def\pgfdvmathunaryop#1#2#3{% + \csname pgfmathfloat#2\endcsname{#3}% + \let#1=\pgfmathresult% +} + + +% Advanced binary operations +% +% #1 = macro that should store the result of applying the +% operation to two entered number +% #2 = the operation (as a string like "veclen") +% #3 = first argument (an entered number) +% #4 = second argument (an entered number) +% +% Description: +% +% Sets #1 to the result of applying #2 to #3 +% +% Example: +% +% \pgfdvmathenter{\a}{3} +% \pgfdvmathenter{\b}{4} +% \pgfdvmathbinop{\c}{veclen}{\a}{\b} + +\def\pgfdvmathbinop#1#2#3#4{% + \csname pgfmathfloat#2\endcsname{#3}{#4}% + \let#1=\pgfmathresult% +} + + + +% Comparing values +% +% #1 = first math variable +% #2 = second math variable +% #3 = code to-be-executed if #1 < #2 +% #4 = code to-be-executed if #1 >= #2 +% +% +% Example: +% +% \pgfdvmathenter{\a}{3} +% \pgfdvmathenter{\b}{4} +% \pgfdvmathifless{\a}{\b}{yes}{should not happen} + +\def\pgfdvmathifless#1#2#3#4{% + \pgfmathfloatlessthan{#1}{#2}% + \ifpgfmathfloatcomparison#3\else#4\fi% +} + + + + +% +% +% Standard objects for data visualization +% +% + + +% +% Transformers +% + +\pgfooclass{linear transformer} +{ + % Class linear transformer + % + % This class is a transformer class. It reacts to the transform + % datapoint signal. When this signal is raised, it will shift the + % coordinate system as follows: If the current value of /data + % point/this.attribute is 0, then the system is shifted to the + % current value of this.origin. If the current value is 1, the + % system is shifted to this.origin + this.unit vector. For other + % values of /data point/this.attribuate, the shift is interpolated + % between these two values. + + + \attribute attribute; + % The attribute (/data point/this.attribute) by which + % the unit vector is multiplied. If it is empty (which is + % different from 0), no transformation is done at all. + + \attribute origin = \pgfpointorigin; + % The shift in case the /data point/this.attribute is 0. + + \attribute unit vector; + % The coordinate system is additionally shifted by this amount + % times the current value of /data point/this.attribute. + + + % Constructor + % + % #1 = attribute that is being transformed. Example: x + % #2 = a vector corresponding to one unit of #1. + % Example: \pgfpoint{1cm}{0cm} + \method linear transformer(#1,#2) { + \pgfooset{attribute}{#1} + \pgf@process{#2} + \edef\pgf@temp{\noexpand\pgfqpoint{\the\pgf@x}{\the\pgf@y}} + \pgfoolet{unit vector}\pgf@temp% + } + + % Method + \method default connects() { + \pgfoothis.get handle(\pgf@dv@me) + \pgfkeysvalueof{/pgf/data visualization/obj}.connect(\pgf@dv@me,transform,transform datapoint signal) + } + + % Setter + \method set origin(#1) { + \pgf@process{#1} + \edef\pgf@temp{\noexpand\pgfqpoint{\the\pgf@x}{\the\pgf@y}} + \pgfoolet{origin}\pgf@temp% + } + + % Slot + % + % This slot should be connected to the transform datapoint + % signal. When this signal is emitted, the coordinate system will be + % shifted according to the current value of the attribute. + \method transform() { + \pgfkeysgetvalue{/data point/\pgfoovalueof{attribute}}\pgf@dv@val% + \ifx\pgf@dv@val\pgfutil@empty% + \else% + \ifx\pgf@dv@val\relax% + \else% + \pgfdvmathenter{\pgf@dv@math@var}{\pgf@dv@val}% + \pgfdvmathexitbyscientificformat{\pgf@dv@val}{\pgf@dv@math@var}% + \pgftransformshift{\pgfoovalueof{origin}}% + \pgfmathfloatgetexponent\pgf@dv@math@var\c@pgf@counta% + \ifnum\c@pgf@counta<-3\relax% + \else% + \pgftransformshift{\pgfpointscale{\pgf@dv@val}{\pgfoovalueof{unit vector}}}% + \fi% + \fi% + \fi% + } + +} + + +% +% Numerical mapping of attributes to other attributes +% + +\pgfooclass{interval mapper} +{ + % Class interval mapper + % + % This interval mapper reacts to the map datapoint signal. Its purpose is to + % map one attribute to another attribute. For the first attribute, + % an intervals is specified. + % + % In addition to the in interval [a,b] there is also an outinterval + % [c,d]. Values in the range [a,b] are linearly mapped to the + % range [c,d] and the result is stored in the second attribute. + % + % For instance, if the first range is [10,20] and the second range + % is [0,100], then 10 is mapped to 0, 11 is mapped to 10, 20 is + % mapped to 100 and 30 is mapped to 200. + % + % It is permissible to specify an additional non-linear + % transformation function f. In this case, for an input value x the + % position of f(x) inside the interval [f(a),f(b)] is determined and + % this position is linearly mapped to [c,d]. + % + % For example, if f(x) = log_10 (x) and the first range [a,b] = + % [10,1000] and the second range is [1,2], then 10 is mapped to 1, + % 100 is mapped to 1.5 (since f(100) = 3 lies in the middle + % between f(10) = 2 and f(1000) = 4) and 100000 is mapped to 3. + + + \attribute in; + % The name of the input attribute. If the value of this attribute + % is empty or undefined, no mapping is done. + % + % The in attribute may have a subkey called .../const. If this key + % has a value different from \relax, it will always be used instead + % of the in attribute itself. This can be useful to temporarily + % set a constant value to a key inside a mapping chain. + +% \attribute clip; +% % The code for clipping the interval. Will set \pgf@dvcliptrue, if a +% % clip is necessary. + + \attribute out; + % The name of the output attribute. + + \attribute trans; + % Stores (more or less) the transformation function. + + \attribute out min; + % Start of the second range (the value of c). + + \attribute trans in min; + % Transformed value of the start of the first range (the value + % f(a)). + + \attribute scale; + % The scaling factor, that is, the value of (f(d)-f(c))/(b-a). + + + % Constructor + % + % #1 = input attribute. Example: velocity. + % #2 = output attribute. Example: x + % #3 = optional transformation function. The input value for this + % function is stored in entered number \pgfvalue. + % The output of the function should be stored in the + % same entered number. + % + % The intervals are set using setter methods later on. + % + \method interval mapper(#1,#2,#3) { + \pgfooset{in}{#1} + \pgfooset{out}{#2} + \def\pgf@temp{#3}% + \ifx\pgf@temp\pgfutil@empty% + \else% + \pgfooset{trans}{% + #3% + }% + \fi% + } + + % Method + \method default connects() { + \pgfoothis.get handle(\pgf@dv@me) + \pgfkeysvalueof{/pgf/data visualization/obj}.connect(\pgf@dv@me,map,map datapoint signal) + } + +% % Method +% \method set clip interval(#1,#2) { +% \def\pgfdvmin{#1}% +% \def\pgfdvmax{#2}% +% \ifx\pgfdvmin\pgfutil@empty% +% \else% +% \pgfdvmathenter{\pgf@dv@temp}{\pgfdvmin}% +% \pgfdvmathexitbyserializing{\pgfdvmin}{\pgf@dv@temp}% +% \fi +% \ifx\pgfdvmax\pgfutil@empty% +% \else% +% \pgfdvmathenter{\pgf@dv@temp}{\pgfdvmax}% +% \pgfdvmathexitbyserializing{\pgfdvmax}{\pgf@dv@temp}% +% \fi +% \pgfooeset{clip}{% +% \noexpand\pgf@dvclipfalse% +% \ifx\pgfdvmin\pgfutil@empty% +% \else% +% \noexpand\pgfdvmathenter{\noexpand\pgf@dv@temp}{\pgfdvmin}% +% \noexpand\pgfdvmathifless{\noexpand\pgfvalue}{\noexpand\pgf@dv@temp}{\noexpand\pgf@dvcliptrue}{}% +% \fi% +% \ifx\pgfdvmax\pgfutil@empty% +% \else% +% \noexpand\pgfdvmathenter{\noexpand\pgf@dv@temp}{\pgfdvmax}% +% \noexpand\pgfdvmathifless{\noexpand\pgf@dv@temp}{\noexpand\pgfvalue}{\noexpand\pgf@dvcliptrue}{}% +% \fi% +% } +% } + + % Method + % + % #1 = in interval minimum + % #2 = in interval maximum + % #3 = out interval minimum + % #4 = out interval maximum + % + % This method will (re)compute the correct mappings for the interval + % mapper. + \method set interval values(#1,#2,#3,#4) { + {% + \pgfdvmathenter{\pgf@in@interval@min}{#1} + \pgfdvmathenter{\pgf@in@interval@max}{#2} + \pgfdvmathenter{\pgf@out@interval@min}{#3} + \pgfdvmathenter{\pgf@out@interval@max}{#4} + % Let's start with the output, it's easier... + \pgfoolet{out min}{\pgf@out@interval@min} + \pgfdvmathsub{\pgf@out@diff}{\pgf@out@interval@max}{\pgf@out@interval@min} + \let\pgfvalue=\pgf@in@interval@min + \pgfoovalueof{trans} + \let\pgf@in@interval@min@transformed=\pgfvalue + \pgfoolet{trans in min}{\pgf@in@interval@min@transformed}% + \let\pgfvalue=\pgf@in@interval@max + \pgfoovalueof{trans} + \let\pgf@in@interval@max@transformed=\pgfvalue + \pgfdvmathsub{\pgf@diff@in@transformed}{\pgf@in@interval@max@transformed}{\pgf@in@interval@min@transformed} + % + % Precompute the scaling + % + \pgfdvmathdiv{\pgf@scale}{\pgf@out@diff}{\pgf@diff@in@transformed}% + \pgfoolet{scale}{\pgf@scale}% + }% + } + + % Slot + \method map() { + \pgfooget{scale}\pgf@temp + \ifx\pgf@temp\pgfutil@empty% + % not yet setup + \else% + \pgfkeysgetvalue{/data point/\pgfoovalueof{in}/const}\pgf@dv@external@value% + \ifx\pgf@dv@external@value\relax% + \pgfkeysgetvalue{/data point/\pgfoovalueof{in}}\pgf@dv@external@value% + \fi% + \ifx\pgf@dv@external@value\pgfutil@empty% + \else% + \ifx\pgf@dv@external@value\relax% + \else% +% % Clip? + \pgfdvmathenter{\pgfvalue}{\pgf@dv@external@value}% +% \pgfoovalueof{clip}% +% \ifpgf@dvclip% +% \pgfkeyslet{/data point/\pgfoovalueof{out}}\pgfutil@empty% +% \else% + \pgf@dv@mapper@trans{} +% \fi% + \fi% + \fi% + \pgfkeysgetvalue{/data point/\pgfoovalueof{in}/min}\pgf@dv@external@value% + \ifx\pgf@dv@external@value\relax\else% + \ifx\pgf@dv@external@value\pgfutil@empty\else% + \pgfdvmathenter{\pgfvalue}{\pgf@dv@external@value}% + \pgf@dv@mapper@trans{/min} + \fi + \fi + \pgfkeysgetvalue{/data point/\pgfoovalueof{in}/max}\pgf@dv@external@value% + \ifx\pgf@dv@external@value\relax\else% + \ifx\pgf@dv@external@value\pgfutil@empty\else% + \pgfdvmathenter{\pgfvalue}{\pgf@dv@external@value}% + \pgf@dv@mapper@trans{/max} + \fi + \fi + \fi% + } + + \def\pgf@dv@mapper@trans#1{ + \pgfooget{trans in min}{\pgf@dv@trans@in@min}% + \pgfooget{scale}{\pgf@dv@scale}% + \pgfooget{out min}{\pgf@dv@out@min}% + \pgfoovalueof{trans}% + \pgfdvmathsub{\pgfvalue}{\pgfvalue}{\pgf@dv@trans@in@min}% + \pgfdvmathmul{\pgfvalue}{\pgfvalue}{\pgf@dv@scale}% + \pgfdvmathadd{\pgfvalue}{\pgfvalue}{\pgf@dv@out@min}% + \pgfkeysgetvalue{/data point/\pgfoovalueof{out}#1/offset}\pgf@dv@external@offset% + \ifx\pgf@dv@external@offset\relax\else% + \ifx\pgf@dv@external@offset\pgfutil@empty\else% + \pgfdvmathenter{\pgf@dv@offset}{\pgf@dv@external@offset}% + \pgfdvmathadd{\pgfvalue}{\pgfvalue}{\pgf@dv@offset} + \fi + \fi + \pgfdvmathexitbyserializing{\pgf@temp}{\pgfvalue}% + \pgfkeyslet{/data point/\pgfoovalueof{out}#1}\pgf@temp% + } +} + + + + + +%\newif\ifpgf@dvclip +\newif\ifpgf@dvignore + +\pgfooclass{scaling mapper} +{ + % Class scaling mapper + % + % A scaling mapper is (mainly) used to scale an attribute in such a way + % that it can be rendered easily on a page. The idea is that you + % specify some attribute and a desired target interval size (like + % [0,5]). The scaling mapper will then survey the data and will setup a + % interval mapper in such a way that the minimum value present in the data is + % mapped to 0 and the maximum to 5. However, it is also possible to, + % say, only have the maximum value mapped to 5 and have 0 be mapped + % to 0. Other, more complicated specifications are also possible. + % + % The scaling mapper internally creates several objects: First, a surveyor + % for determining the minimum and maximum values of the attribute + % and a interval mapper for then mapping the values to the scaled + % values. Additionally, interval objects are needed. + + \attribute in; + % The to-be-scaled attribute; + + \attribute out; + % The attribute storing the scaled value. + + \attribute in range obj; + % This interval keep track of the range of the in attribute + + \attribute scaling spec; + % A specification of how the scaling should be performed. + % + % The format is the following: + % + % #1 at #2 and #3 at #4 + % + % Here, #2 and #4 must be numbers. #1 and #3 can either be numbers + % or #1 can be the text "min" and #3 can be the text "max". + % + % The effect of such a specification is the following: The value #1 + % is mapped to #2, the value #3 is mapped to #4 and values between + % #1 and #3 (or outside this range) are mapped linearly to a value + % between (or outside) #2 and #4. In case #1 is set to "min", the + % smallest observed value of the in-attribute is mapped to #3 and + % similarly for a value of "max" for #3. + % + % Additionally, as for a interval mapper, a function f might be specified + % that deforms the linear mapping. In case f is specified, + % f(#1) is mapped to #2 and f(#3) is mapped to #4. + + \attribute function; + % Stores the function + + \attribute interval mapper; + % Stores the interval mapper object + + \attribute range surveyor; + % Stores the range surveyor object + + + % Constructor + % + % #1 = in attribute + % #2 = out attribute + % #3 = scaling specification + % #4 = optional function + % + \method scaling mapper(#1,#2,#3,#4) { + % + % Save the parameters in attributes + % + \pgfooset{in}{#1} + \pgfooset{out}{#2} + \pgfooset{scaling spec}{#3} + \pgfooset{function}{#4} + % + % Now setup the objects for the before survey phase + % + % + % First, the in range interval + \pgfoonew \pgf@dv@in@range@obj=new interval(,) + \pgfoolet{in range obj}\pgf@dv@in@range@obj + % Second, the in range surveyor. We do not need to store this + % object, it will "do its work in the background" + \pgfoonew \pgf@dv@range@obj=new range surveyor(#1,\pgf@dv@in@range@obj) + \pgf@dv@range@obj.default connects() + \pgfoolet{range surveyor}\pgf@dv@range@obj + % + % + % The interval mapper: + % + \pgfoonew{interval mapper}=new interval mapper(#1,#2,#4) + \pgfoovalueof{interval mapper}.default connects() + } + + % Method + \method default connects() { + \pgfoothis.get handle(\pgf@dv@me) + \pgfkeysvalueof{/pgf/data visualization/obj}.connect(\pgf@dv@me,phase,phase signal) + } + + +% % Method +% % +% % #1 = a min clip -- everything below this value will be clipped +% % #2 = a max value -- everything above this value will be clipped +% % +% % Sets a clipping for the underlying interval mapper. +% % +% \method set clip interval(#1,#2) { +% \pgfoovalueof{interval mapper}.set clip interval({#1},{#2})% +% } + + % Getter + % + % Returns an interval object that stores the range of the in + % attribute. + \method get in range interval() { + \pgfooget{in range obj}\pgfdvinrangeinterval + } + + + % Getter + % + % Returns the out attribute. + % + \method get out() { + \pgfooget{out}\pgfdvout + } + + % Getter + % + % Returns the function attribute. + % + \method get function(#1) { + \pgfooget{function}#1 + } + + % Method + % + % #1 = a included in value + % + % This method only affects the survey. The value #1 is recorded as + % if it were encountered for the in attribute at some point. + % + \method include in value(#1) { + \pgfoovalueof{range surveyor}.include attribute value({#1}) + } + + + % Method + % + % #1 = value for the attribute + % + % Sets the attribute to the (evaluated) given value (evaluation + % using \pgfmathparse). When the value is evaluated, the values of + % \pgfdvmin and \pgfdvmax will be set to the minimum and maximum + % values of the in interval. (See \pgfdvmathenter with the "!"-notation). + % + % In case #1 is set to the special value "min", it evaluates to + % \pgfdvmin, when set to "max" it evaluates to \pgfdvmax. + % + \method set in to(#1) { + \edef\pgf@temp{#1} + \ifx\pgf@temp\pgf@min@text + \pgf@dv@lib@set@mm% + \let\pgf@dv@value\pgfdvmin + \else + \ifx\pgf@temp\pgf@max@text + \pgf@dv@lib@set@mm% + \let\pgf@dv@value\pgfdvmax + \else + \pgfdvmathenter{\pgf@dv@value}{\pgf@temp} + \fi + \fi + \pgfdvmathexitbyserializing{\pgf@dv@serial}{\pgf@dv@value} + \pgfkeyslet{/data point/\pgfoovalueof{in}}\pgf@dv@serial + } + \def\pgf@dv@lib@set@mm{ + \pgfooget{in range obj}\pgfdvinrangeinterval + \pgfdvinrangeinterval.get min and max()% + } + + + % Slot + \method phase(#1) { + \ifx#1\pgfdvendsurvey + % Ok, we setup the interval mapper. + % + % We start by computing the interval borders: + \pgfoovalueof{in range obj}.get min and max() + \ifx\pgfdvmin\pgfutil@empty% undefined, since no data points + \else% + \pgfooget{scaling spec}\pgf@temp + \expandafter\pgf@lib@dv@parse@scaling\pgf@temp\pgf@stop% + \pgfoovalueof{interval mapper}.set interval values(% + \pgf@lib@dv@min,\pgf@lib@dv@max,% + \pgf@lib@dv@min@at,\pgf@lib@dv@max@at) + \fi + \fi + } + + + % Internal helper + \def\pgf@lib@dv@parse@scaling#1 at#2and #3 at#4\pgf@stop{% + \def\pgf@lib@dv@min{#1}% + \pgfdvmathenter{\pgf@lib@dv@min@at@mv}{#2} + \def\pgf@lib@dv@max{#3}% + \pgfdvmathenter{\pgf@lib@dv@max@at@mv}{#4} + \ifx\pgf@lib@dv@min\pgf@min@text% + \let\pgf@lib@dv@min@mv\pgfdvmin + \else + \pgfdvmathenter{\pgf@lib@dv@min@mv}{\pgf@lib@dv@min} + \fi + \ifx\pgf@lib@dv@max\pgf@max@text% + \let\pgf@lib@dv@max@mv\pgfdvmax + \else + \pgfdvmathenter{\pgf@lib@dv@max@mv}{\pgf@lib@dv@max} + \fi + \pgfdvmathexitbyserializing{\pgf@lib@dv@min}{\pgf@lib@dv@min@mv} + \pgfdvmathexitbyserializing{\pgf@lib@dv@min@at}{\pgf@lib@dv@min@at@mv} + \pgfdvmathexitbyserializing{\pgf@lib@dv@max}{\pgf@lib@dv@max@mv} + \pgfdvmathexitbyserializing{\pgf@lib@dv@max@at}{\pgf@lib@dv@max@at@mv} + } + \def\pgf@min@text{min} + \def\pgf@max@text{max} +} + + + + + +% +% Surveyors +% + +\pgfooclass{range surveyor} +{ + % Class range surveyor + % + % A range surveyor is used only in the survey phase. Its job is to + % determine the minimum and maximum values of an attribute that are + % "seen" during the survey phase. Based on this value, the size of, + % say, an axis can be detemined later on. + % + % In case the attribute has the sub-attributes "min" and "max", they + % are also taken into account. + + \attribute attribute; + % The to-be-surveyed attribute + + \attribute interval obj; + % The interval object that protocols the minimum and maximum + % values. + + + % Constructor + % + % #1 = the attribute + % #2 = handle to the interval object + % + \method range surveyor(#1,#2) { + \pgfooset{attribute}{#1} + \pgfoolet{interval obj}#2 + } + + % Method + \method default connects() { + \pgfoothis.get handle(\pgf@dv@me) + \pgfkeysvalueof{/pgf/data visualization/obj}.connect(\pgf@dv@me,survey,survey datapoint signal) + } + + % Method + % + % #1 = a value + % + % Adjust the interval as if during the survey this value were + % encountered + \method include attribute value(#1) { + \def\pgf@dv@val{#1} + \pgfoovalueof{interval obj}.adjust(\pgf@dv@range@surv) + } + + % Slot + % + % This slot should be connected to the survey datapoint signal. For + % each datapoint, this method will call the adjust method of the + % interval. + % + \method survey() { + \pgfkeysgetvalue{/data point/\pgfoovalueof{attribute}}\pgf@dv@val% + \pgfoovalueof{interval obj}.adjust(\pgf@dv@range@surv) + \pgfkeysgetvalue{/data point/\pgfoovalueof{attribute}/min}\pgf@dv@val% + \pgfoovalueof{interval obj}.adjust(\pgf@dv@range@surv) + \pgfkeysgetvalue{/data point/\pgfoovalueof{attribute}/max}\pgf@dv@val% + \pgfoovalueof{interval obj}.adjust(\pgf@dv@range@surv) + } + + \def\pgf@dv@range@surv{% + \ifx\pgf@dv@val\relax% + \else% + \edef\pgf@dv@val{\pgf@dv@val}% + \ifx\pgf@dv@val\pgfutil@empty% + \else% + \pgfdvmathenter{\pgf@dv@value}{\pgf@dv@val}% + % Now, protocol value + \ifx\pgfdvmin\pgfutil@empty% + \let\pgfdvmin\pgf@dv@value% + \else% + \pgfdvmathifless{\pgf@dv@value}{\pgfdvmin}{\let\pgfdvmin\pgf@dv@value}{}% + \fi% + \ifx\pgfdvmax\pgfutil@empty% + \let\pgfdvmax\pgf@dv@value% + \else% + \pgfdvmathifless{\pgfdvmax}{\pgf@dv@value}{\let\pgfdvmax\pgf@dv@value}{}% + \fi% + \fi% + \fi + } +} + + + +% +% Visualizers +% + +\usepgflibrary{plothandlers} + + + +\pgfooclass{plot handler visualizer} +{ + % Class plot handler visualizer + % + % This visualizer uses one or more plot handlers to visualize data points. + % As the data points are processed, the canvas positions of the data + % points are recorded. At the end of a group of data points, the + % recorded stream of canvas position is visualized (rendered) + % using plot handlers. For instance, when the lineto plot handler + % is used, the data points are connected by straight lines, when the + % curveto plot handler is used, they are connected by smooth curves + % and so on. + % + % Since plot lines are not drawn immediately, but only at the end, + % when everything has been collected, multiple plot handlers can + % coexist peacefully at the same time. + % + % You can specify a "filter", which will cause only those data + % points to be visualized by the visualizer that pass the test. The + % filter should set \pgfdvfilterpassedfalse for to-be-filtered data + % point. + % + % The keys /data point/<name>/execute at begin and /data + % point/<name>/execute at end, where <name> is the name of + % the visualizer, should store code that is to be executed directly + % before and after the stream of coordinates is created. Typically, + % these keys will store commands to use the path created by the plot + % handler. + + \attribute handlers; + % The to-be-used handlers + + \attribute name; + % Filter code + + \attribute filter=\pgfdvnamedvisualizerfilter; + % Filter code + + \attribute positions; + % An internal protocol of the positions on the stream + + \attribute cache; + % An internal cache. Positions are first inserted into this + % cache. Every 100 steps this cache is moved to positions. The idea + % behind this is that it will avoid the quadratic time increase that + % is normally caused when a protocol is build in TeX. + + + % Constructor + % + % #1 = A name + % #2 = A comma-separated list of handlers like + % "\pgfplothandlerlineto,\pgfplothandlercurveto" + % + \method plot handler visualizer(#1,#2) { + \pgfooset{name}{#1} + \pgfooset{handlers}{#2} + } + + % Method + \method default connects() { + \pgfoothis.get handle(\pgf@dv@me) + \pgfkeysvalueof{/pgf/data visualization/obj}.connect(\pgf@dv@me,protocol,visualize datapoint signal) + \pgfkeysvalueof{/pgf/data visualization/obj}.connect(\pgf@dv@me,phase,phase signal) + } + + % Setter + \method set filter(#1) { + \pgfooset{filter}{#1} + } + + % Slot + \method protocol() { + \pgfdvfilterpassedtrue + \pgfoovalueof{filter} + \ifpgfdvfilterpassed% + \pgf@dv@line@cache@it + \fi% + } + + \def\pgf@dv@line@cache@it{ + % Cache it + \pgfooget{cache}\pgf@dv@cache + \edef\pgf@dv@add{\noexpand\pgf@dv@ph{\pgfkeysvalueof{/data point/canvas x}}{\pgfkeysvalueof{/data point/canvas y}}}% + \expandafter\expandafter\expandafter\def% + \expandafter\expandafter\expandafter\pgf@dv@cache% + \expandafter\expandafter\expandafter{\expandafter\pgf@dv@cache\pgf@dv@add}% + % Possibly flush cache + \global\advance\pgf@lib@dv@cache@count by1\relax% + \ifnum\pgf@lib@dv@cache@count=100\relax% + \global\pgf@lib@dv@cache@count=0\relax% + % Append cache to positions + \pgfooget{positions}\pgf@dv@temp + \expandafter\expandafter\expandafter\def% + \expandafter\expandafter\expandafter\pgf@dv@temp% + \expandafter\expandafter\expandafter{\expandafter\pgf@dv@temp\pgf@dv@cache}% + \pgfoolet{positions}\pgf@dv@temp + \let\pgf@dv@cache\pgfutil@empty + \fi + \pgfoolet{cache}\pgf@dv@cache + } + + % Slot + \method phase(#1) {% + \ifx#1\pgfdvendvisualization% + \pgfoothis.render()% + \fi% + } + + % Internal method + \method render() { + \pgfscope + \pgfooget{handlers}\tikz@dv@temp@list + \foreach\tikz@dv@temp in\tikz@dv@temp@list{ + \ifx\tikz@dv@temp\pgfutil@empty + \else + \pgfkeysvalueof{/data point/\pgfoovalueof{name}/execute at begin} + \tikz@dv@temp + \pgfplotstreamstart + \pgfoovalueof{positions} + \pgfoovalueof{cache} + \pgfplotstreamend + \pgfkeysvalueof{/data point/\pgfoovalueof{name}/execute at end} + \fi + } + \endpgfscope + \pgfoolet{positions}\pgfutil@empty + \pgfoolet{cache}\pgfutil@empty + } + + \def\pgf@dv@ph#1#2{\pgfplotstreampoint{\pgfqpoint{#1}{#2}}} +} + +\newcount\pgf@lib@dv@cache@count + + +% A possible filter for unnamed visualizers +% +% #1 = Text to be compared with key /data point/visualizer +% +% Description: +% +% In a data visualization with multiple visualizers, data points +% typically "belong" only to a single visualizer. It is, thus, +% necessary to filter data points accoring to the current +% visualizer. This current visualizer is assumed to be stored in /data +% point/visualizer. +% +% When objects allow you to set a filter, you can use this filter to +% test against /data point/visualizer being equal to #1. + +\def\pgfdvvisualizerfilter#1{% + \pgfkeysgetvalue{/data point/visualizer}\pgf@dv@visualizer% + \def\pgf@temp{#1}% + \ifx\pgf@temp\pgf@dv@visualizer% + \else + \pgfdvfilterpassedfalse + \fi% +} + + + +% A filter for named visualizer +% +% Description: +% +% This filter works like \pgfdvvisualizerfilter, only it assumes the +% the object defines a "name" attribute. In this case, the value of +% /data point/visualizer is tested against this attribute. + +\def\pgfdvnamedvisualizerfilter{% + \pgfkeysgetvalue{/data point/visualizer}\pgf@dv@visualizer% + \pgfooget{name}\pgf@temp% + \ifx\pgf@temp\pgf@dv@visualizer% + \else + \pgfdvfilterpassedfalse + \fi% +} + + + +\pgfooclass{rectangle visualizer} +{ + % Class rectangle visualizer + % + % This visualizer visualizes a datapoint as a rectangle. It needs + % two attributes a1 and a2, each of which must have min and max + % subattributes. Then, it draws a rectangle between (a1/min,a2/min) + % and (a1/max,a2/max). + + \attribute attribute 1; + \attribute attribute 2; + % The attributes + + \attribute use path attribute; + % The attribute that stores the to-be-taken action + + + % Constructor + % + % #1 = first attribute + % #2 = second attribute + % + \method rectangle visualizer(#1,#2,#3) { + \pgfooset{attribute 1}{#1} + \pgfooset{attribute 2}{#2} + \pgfooset{use path attribute}{#3} + } + + % Method + \method default connects() { + \pgfoothis.get handle(\pgf@dv@me) + \pgfkeysvalueof{/pgf/data visualization/obj}.connect(\pgf@dv@me,visualize,visualize datapoint signal) + } + + % Slot + \method visualize() { + { + \pgfkeysgetvalue{/data point/\pgfoovalueof{attribute 1}/min}\pgf@dv@amin + \pgfkeysgetvalue{/data point/\pgfoovalueof{attribute 1}/max}\pgf@dv@amax + \pgfkeysgetvalue{/data point/\pgfoovalueof{attribute 2}/min}\pgf@dv@bmin + \pgfkeysgetvalue{/data point/\pgfoovalueof{attribute 2}/max}\pgf@dv@bmax + \ifx\pgf@dv@amin\relax\else\ifx\pgf@dv@amin\pgfutil@empty\else + \ifx\pgf@dv@bmin\relax\else\ifx\pgf@dv@bmin\pgfutil@empty\else + \ifx\pgf@dv@amax\relax\else\ifx\pgf@dv@amax\pgfutil@empty\else + \ifx\pgf@dv@bmax\relax\else\ifx\pgf@dv@bmax\pgfutil@empty\else + \pgfkeyssetvalue{/data point/\pgfoovalueof{attribute 1}}{\pgf@dv@amin} + \pgfkeyssetvalue{/data point/\pgfoovalueof{attribute 2}}{\pgf@dv@bmin} + \pgfpathdvmoveto + \pgfkeyssetvalue{/data point/\pgfoovalueof{attribute 2}}{\pgf@dv@bmax} + \pgfpathdvlineto + \pgfkeyssetvalue{/data point/\pgfoovalueof{attribute 1}}{\pgf@dv@amax} + \pgfpathdvlineto + \pgfkeyssetvalue{/data point/\pgfoovalueof{attribute 2}}{\pgf@dv@bmin} + \pgfpathdvlineto + \pgfkeyssetvalue{/data point/\pgfoovalueof{attribute 1}}{\pgf@dv@amin} + \pgfpathdvlineto + \pgfpathclose + \pgfkeysvalueof{/data point/\pgfoovalueof{use path attribute}} + \fi\fi + \fi\fi + \fi\fi + \fi\fi + } + } +} + +\newcount\pgf@lib@dv@cache@count + + + +% +% Label positioning classes +% + +\pgfooclass{label visualizer} +{ + % Class label visualizer + % + % The job of this class is to visualize a label of a curve or some + % other object. + % + % The idea is as follows: This class monitors a certain + % attribute. When this attribute reaches a certain value for the + % first time, the following happens: A normalized vector of the line + % connecting the current canvas position to the canvas position of + % the previous data point is computed and stored in pgf@x/pgf@y. The + % coordinate system is shifted so that the current data point is at + % the origin. Then, some drawing code is executed. + + \attribute attribute; + % The monitored attribute + + \attribute filter; + % Filter code, see plot handler visualizer doc. + + \attribute threshold; + % When the attribute exceeds this threshold, the drawing code is + % executed + + \attribute before canvas position=; + % Stores canvas position of the data point before the interesting one + + \attribute canvas position=; + % Stores canvas position of the data point + + \attribute code; + % To-be-executed code when the label should be drawn + + + % Constructor + % + % #1 = attribute + % #2 = a macro, storing the threshold + % #3 = code + % #4 = filter code + % + \method label visualizer(#1,#2,#3,#4) { + \pgfooset{attribute}{#1} + \ifx#2\pgfutil@empty + \else + \pgfdvmathenter{\pgf@temp}{#2} + \fi + \pgfoolet{threshold}\pgf@temp + \pgfooset{code}{#3} + \pgfooset{filter}{#4} + } + + % Method + \method default connects() { + \pgfoothis.get handle(\pgf@dv@me) + \pgfkeysvalueof{/pgf/data visualization/obj}.connect(\pgf@dv@me,test,visualize datapoint signal) + \pgfkeysvalueof{/pgf/data visualization/obj}.connect(\pgf@dv@me,phase,phase signal) + } + + % Slot + \method test() { + \pgfdvfilterpassedtrue + \pgfoovalueof{filter} + \ifpgfdvfilterpassed% + \pgfooget{attribute}\pgf@dv@attribute + \ifx\pgf@dv@attribute\pgfutil@empty% + % nothing to do (anymore) + \else% + \pgf@dv@label@vis@record + \fi% + \fi% + } + + \def\pgf@dv@label@vis@record{ + % Record current position + \edef\pgf@dv@pos{% + \noexpand\pgfqpoint% + {\pgfkeysvalueof{/data point/canvas x}}% + {\pgfkeysvalueof{/data point/canvas y}}}% + \pgfooget{canvas position}\pgf@dv@temp% + \pgfoolet{before canvas position}\pgf@dv@temp% + \pgfoolet{canvas position}\pgf@dv@pos% + % Now check threshold + \pgfooget{threshold}\pgf@dv@thres% + \ifx\pgf@dv@thres\pgfutil@empty% + \else% + % Hmm, have to check, whether the value is, indeed, correct + \pgfkeysgetvalue{/data point/\pgfoovalueof{attribute}}\pgf@dv@val + \ifx\pgf@dv@val\relax% + \else\ifx\pgf@dv@val\pgfutil@empty% + \else% + \pgfdvmathenter{\pgf@dv@value}{\pgf@dv@val}% + \pgfooget{threshold}{\pgf@dv@thres} + % Now, protocol value + \pgfdvmathifless{\pgf@dv@value}{\pgf@dv@thres}{}{% + \pgfoolet{attribute}\pgfutil@empty% Stop! + }% + \fi\fi% + \fi% + } + + % Slot + \method phase(#1) {% + \ifx#1\pgfdvendvisualization% + \scope + \pgfcoordinate{label visualizer coordinate}{\pgfoovalueof{canvas position}} + \pgfcoordinate{label visualizer coordinate'}{\pgfoovalueof{before canvas position}} + \pgfoovalueof{code} + \endscope + \fi% + } + +} + + + +% +% Style sheets +% +\pgfooclass{style attribute} +{ + % Class style attribute + % + % Instances of this class are used to select a style based on the + % current value of an attribute. + % + % Instances of this class monitor an attribute. Whenever the "style" + % signal is raised, the object investigates the current value of the + % attribute. It then looks up /pgf/data visualization/style + % sheets/<name of style sheet>/<value of the attribute> and executes + % this key, provided it is defined. If it not defined, the key + % /pgf/data visualization/style sheets/<name of style sheet>/default + % style is executed with the value as a parameter. + + \attribute attribute; + % The name of the attribute + + \attribute style sheet name; + % The styling function + + % Constructor + % + % #1 = attribute (including, if present, /data point/) + % #2 = style sheet name + % + \method style attribute(#1,#2) { + \pgfooset{attribute}{#1} + \pgfooset{style sheet name}{#2} + } + + % Method + \method default connects() { + \pgfoothis.get handle(\pgf@dv@me) + \pgfkeysvalueof{/pgf/data visualization/obj}.connect(\pgf@dv@me,invoke style,style signal) + } + + % Slots + \method invoke style() { + \pgfooget{attribute}\pgf@dv@temp + \pgfkeysgetvalue{\pgf@dv@temp}\pgf@dv@temp@val + \ifx\pgf@dv@temp@val\pgfutil@empty%do nothing + \else\ifx\pgf@dv@temp@val\relax%do nothing + \else% + \pgfkeysifdefined{\pgf@dv@temp/\pgf@dv@temp@val}{\pgfkeysgetvalue{\pgf@dv@temp/\pgf@dv@temp@val}\pgf@dv@temp@val}{}% redirect + \edef\pgf@temp{/pgf/data visualization/style sheets/\pgfoovalueof{style sheet name}} + \pgfkeysifassignable{\pgf@temp/\pgf@dv@temp@val}{% + \pgfkeysalso{\pgf@temp/\pgf@dv@temp@val}}{% + \pgfkeysalso{\pgf@temp/default style/.expand once=\pgf@dv@temp@val} + } + \fi\fi% + } +} + + +% Declares a new style sheet +% +% #1 = name of style sheet +% #2 = settings +% +% Description: +% +% This is a shortcut for doing a /.cd to /pgf/data visualization/style sheets/#1 + +\def\pgfdvdeclarestylesheet#1#2{ + \pgfkeys{/pgf/data visualization/style sheets/#1/.cd,#2} +} + + + + + + + + + +% +% Legend container class +% + +\pgfooclass{legend} +{ + % Class legend + % + % This class is used to collect entries into a legend. The idea is + % that, say, for each line of a picture you would like to have an + % entry in a legend. Then you prepare these entries and send + % them to a legend container object. It will collect the entries + % and, at the end, arrange them in rows and columns by + % separating them using \pgfdvnextcell and \pgfdvendrow. + % + % By surrounding the resulting arrangement by a call to \pgfmatrix or + % a call to \halign you can then create a legend. + % + % To specify how the entries should be arranged, a size + % specification and two directions are needed. + % + % For the size specification you specify either the ideal number of + % columns and the maximum number of rows or you specify the ideal + % number of rows and the maximum number of columns. In the first + % case, the class first tries to create as many columns as specified + % by the "ideal" parameter. If there are less entries than this + % parameter, you obviously get less columns, namely as many as there + % are entries, each column containing only one entry. If there are + % more entries that the ideal number of columns, you get multiple + % columns, each containing as many entries to make sure that the + % ideal number is met. However, if a column would get more than the + % specified maximum number of elements per column, you get more + % columns that the ideal number -- to ensure that no column contains + % more than the desired number. The case is symmetric, but with the + % roles of columns and rows exchanged. + % + % Here is an example: You specify that you want 2 columns, ideally, + % each having a maximum of 4 entries. Here is what you would get: + % + % Number of entries & Number of resulting columns ... & ... and rows + % 1 & 1 & 1 + % 2 & 2 & 1 + % 3 & 2 & 2 + % 4 & 2 & 2 + % 5 & 2 & 3 + % 6 & 2 & 3 + % 7 & 2 & 4 + % 8 & 2 & 4 + % 9 & 3 & 4 + % 10 & 3 & 4 + % 11 & 3 & 4 + % 12 & 3 & 4 + % 13 & 4 & 4 + % + % + % Once the number of columns and rows has been computed, the next + % step is to "fill" the table. For this, eight strategies may be + % specified: right then down, right then up, left then down, left + % then up, up then right, up then left, down then right, down then + % left. A strategy like "right then up" means the following: Each + % new entry should placed right of the previous entry in the + % arrangement. However, once the maximum number of elements in a row + % has been reached, the a new row should be started that is placed + % above ("up") then just-assembled row. + % + % + % + % + % Example: + % + % You create an object \legend and then call + % + % \pgfoofnew \legend=new legend(columns,2,3,down then right) + % \legend.add entry(first) + % \legend.add entry(second) + % \legend.add entry(third) + % \legend.add entry(fourth) + % \legend.add entry(fifth) + % \legend.add entry(sixth) + % \legend.add entry(seventh) + % \legend.get arrangment(\arrangement) + % + % Then \arrangment will expand to + % + % first \pgfdvnextcell fourth \pgfdvnextcell seventh \pgfdvendrow + % second \pgfdvnextcell fifth \pgfdvnextcell third \pgfdvendrow + % third \pgfdvendrow sixth \pgfdvnextcell \pgfdvendrow + % + % By saying \let\pgfdvendrow=\\ and \let\pgfdvnextcell=&, you + % can use \arrangment inside a table. + + + \attribute entries; + % Collectes the entries + + \attribute columns or rows; + % Specifies whether columns or rows are specified + + \attribute ideal; + % The ideal number of columns/rows + + \attribute max; + % The maximum number of entries per column/row + + \attribute strategy; + % Specifies how the matrix should be filled + + \attribute number of entries=0; + % Counts the number of entries that have been stored + + + % Constructor + % + % #1 = "columns" or "rows" -> specifies whether the ideal number and + % the max entries number refer to columns or the row + % #2 = the ideal number of #1's + % #3 = the maximum number of entries in a #1 + % #4 = one of the eight strategies + % + \method legend(#1,#2,#3,#4) { + \pgfooset{columns or rows}{#1} + \pgfooset{ideal}{#2} + \pgfooset{max}{#3} + \pgfooset{strategy}{#4} + } + + % Method + \method add entry(#1) { + \pgfooappend{entries}{{#1}} + \c@pgf@counta=\pgfoovalueof{number of entries}\relax% + \advance\c@pgf@counta by1\relax% + \pgfooeset{number of entries}{\the\c@pgf@counta} + } + + % Method + \method get arrangement(#1) { + { + % + % Step 1: Compute the desired number of rows or columns + % + % + % Compute the ideal number of entries per row/column (called + % "target" in the following) and entries per colum/row (called + % "per target" in the following) + % + % if (number of entries > ideal) + \ifnum\pgfoovalueof{number of entries}>\pgfoovalueof{ideal}\relax% + % { + % if (ideal * max > number of entries) + \c@pgf@counta=\pgfoovalueof{ideal}\relax% + \multiply\c@pgf@counta by\pgfoovalueof{max}\relax% + \ifnum\c@pgf@counta>\pgfoovalueof{number of entries}\relax + % { + % target = ideal; + % per target = ceil (number of entries / ideal); + \c@pgf@counta=\pgfoovalueof{ideal}\relax% + \c@pgf@countb=\pgfoovalueof{number of entries}\relax + \advance\c@pgf@countb by-1\relax + \divide\c@pgf@countb by\c@pgf@counta\relax% + \advance\c@pgf@countb by1\relax% + % } + % else + % { + % target = ceil(number of entries / max); + % per target = max; + \else + \c@pgf@countb=\pgfoovalueof{max}\relax% + \c@pgf@counta=\pgfoovalueof{number of entries}\relax + \advance\c@pgf@counta by-1\relax + \divide\c@pgf@counta by\c@pgf@countb\relax% + \advance\c@pgf@counta by1\relax% + \fi + % } + % } + % else + % { + % target = number of entries; + % per target = 1; + % } + \else + \c@pgf@counta=\pgfoovalueof{number of entries}\relax% + \c@pgf@countb=1\relax% + \fi% + % + % Ensure that counta = rows, countb = columns + % + \pgfooget{columns or rows}\pgf@temp + \ifx\pgf@temp\pgf@dv@columnstext% + \c@pgf@countc=\c@pgf@counta\relax + \c@pgf@counta=\c@pgf@countb\relax + \c@pgf@countb=\c@pgf@countc\relax + \fi + \edef\temp{rows: \the\c@pgf@counta, columns: \the\c@pgf@countb}\temp + % + % Now arrange the matrix + % + \csname pgf@dv@legend@init@\pgfoovalueof{strategy}\endcsname + \expandafter\let\expandafter\pgf@dv@updater\csname pgf@dv@legend@update@\pgfoovalueof{strategy}\endcsname + \pgfooget{entries}\pgf@temp + \expandafter\pgf@dv@legend@arrange\pgf@temp\pgf@stop + % + % Now assemble the matrix + % + \edef\pgf@dv@row@list{1,...,\the\c@pgf@counta} + \edef\pgf@dv@column@list{1,...,\the\c@pgf@countb} + \global\let\pgf@dv@matrix\pgfutil@empty + \foreach \pgf@dv@row in \pgf@dv@row@list + { + \global\let\pgf@dv@matrix@row\pgf@dv@first@mark + \foreach \pgf@dv@column in \pgf@dv@column@list + { + \expandafter\let\expandafter\pgf@temp\csname pgf@dv@legend@entry@\pgf@dv@row @\pgf@dv@column\endcsname + \ifx\pgf@temp\relax + \let\pgf@temp\pgfutil@empty + \fi + \ifx\pgf@dv@matrix@row\pgf@dv@first@mark + \global\let\pgf@dv@matrix@row\pgf@temp + \else + \expandafter\pgfutil@g@addto@macro\expandafter\pgf@dv@matrix@row\expandafter{\expandafter\pgfdvnextcell\pgf@temp} + \fi + } + \pgfutil@g@addto@macro\pgf@dv@matrix@row{\pgfdvendrow} + \expandafter\pgfutil@g@addto@macro\expandafter\pgf@dv@matrix\expandafter{\pgf@dv@matrix@row} + } + \global\let\pgf@dv@matrix@row\relax + } + \let#1\pgf@dv@matrix + \global\let\pgf@dv@matrix\relax + } + + \def\pgf@dv@first@mark{\pgf@dv@first@mark} + + \def\pgf@dv@legend@arrange{% + \pgfutil@ifnextchar\pgf@stop{\pgfutil@gobble}{\pgf@dv@legend@handle@entry} + } + + \def\pgf@dv@legend@handle@entry#1{ + \expandafter\def\csname pgf@dv@legend@entry@\the\c@pgf@countc @\the\c@pgf@countd\endcsname{#1}% + \pgf@dv@updater% + \pgf@dv@legend@arrange% + } + + \expandafter\def\csname pgf@dv@legend@init@down then right\endcsname{% + \c@pgf@countc=1\relax% + \c@pgf@countd=1\relax% + } + + \expandafter\def\csname pgf@dv@legend@update@down then right\endcsname{% + \advance\c@pgf@countc by1\relax + \ifnum\c@pgf@countc>\c@pgf@counta\relax% + \c@pgf@countc=1\relax% + \advance\c@pgf@countd by1\relax% + \fi% + } + + \expandafter\def\csname pgf@dv@legend@init@right then down\endcsname{% + \c@pgf@countc=1\relax% + \c@pgf@countd=1\relax% + } + + \expandafter\def\csname pgf@dv@legend@update@right then down\endcsname{% + \advance\c@pgf@countd by1\relax + \ifnum\c@pgf@countd>\c@pgf@countb\relax% + \c@pgf@countd=1\relax% + \advance\c@pgf@countc by1\relax% + \fi% + } + + \expandafter\def\csname pgf@dv@legend@init@up then right\endcsname{% + \c@pgf@countc=\c@pgf@counta\relax% + \c@pgf@countd=1\relax% + } + + \expandafter\def\csname pgf@dv@legend@update@up then right\endcsname{% + \advance\c@pgf@countc by-1\relax + \ifnum\c@pgf@countc=0\relax% + \c@pgf@countc=\c@pgf@counta\relax% + \advance\c@pgf@countd by1\relax% + \fi% + } + + \expandafter\def\csname pgf@dv@legend@init@right then up\endcsname{% + \c@pgf@countc=\c@pgf@counta\relax% + \c@pgf@countd=1\relax% + } + + \expandafter\def\csname pgf@dv@legend@update@right then up\endcsname{% + \advance\c@pgf@countd by1\relax + \ifnum\c@pgf@countd>\c@pgf@countb\relax% + \c@pgf@countd=1\relax% + \advance\c@pgf@countc by-1\relax% + \fi% + } + + \expandafter\def\csname pgf@dv@legend@init@left then up\endcsname{% + \c@pgf@countc=\c@pgf@counta\relax% + \c@pgf@countd=\c@pgf@countb\relax% + } + + \expandafter\def\csname pgf@dv@legend@update@left then up\endcsname{% + \advance\c@pgf@countd by-1\relax + \ifnum\c@pgf@countd=0\relax% + \c@pgf@countd=\c@pgf@countb\relax% + \advance\c@pgf@countc by-1\relax% + \fi% + } + + \expandafter\def\csname pgf@dv@legend@init@up then left\endcsname{% + \c@pgf@countc=\c@pgf@counta\relax% + \c@pgf@countd=\c@pgf@countb\relax% + } + + \expandafter\def\csname pgf@dv@legend@update@up then left\endcsname{% + \advance\c@pgf@countc by-1\relax + \ifnum\c@pgf@countc=0\relax% + \c@pgf@countc=\c@pgf@counta\relax% + \advance\c@pgf@countd by-1\relax% + \fi% + } + + \expandafter\def\csname pgf@dv@legend@init@left then down\endcsname{% + \c@pgf@countc=1\relax% + \c@pgf@countd=\c@pgf@countb\relax% + } + + \expandafter\def\csname pgf@dv@legend@update@left then down\endcsname{% + \advance\c@pgf@countd by-1\relax + \ifnum\c@pgf@countd=0\relax% + \c@pgf@countd=\c@pgf@countb\relax% + \advance\c@pgf@countc by1\relax% + \fi% + } + + \expandafter\def\csname pgf@dv@legend@init@down then left\endcsname{% + \c@pgf@countc=1\relax% + \c@pgf@countd=\c@pgf@countb\relax% + } + + \expandafter\def\csname pgf@dv@legend@update@down then left\endcsname{% + \advance\c@pgf@countc by1\relax + \ifnum\c@pgf@countc>\c@pgf@countb\relax% + \c@pgf@countc=1\relax% + \advance\c@pgf@countd by-1\relax% + \fi% + } + + \def\pgf@dv@columnstext{columns} +} + + + +% +% Help classes +% + +\pgfooclass{interval} +{ + % Class interval + % + % Instances of this class store intervals. When either the min or + % the max value is empty, this corresponds to "not yet set", (not to + % "infinity). + + \attribute min; + % The minimum value of the interval + + \attribute max; + % The maximum value of the interval + + % Constructor + % + % #1 = initial minimum value + % #2 = initial maximum value + % + \method interval(#1,#2) { + \pgfooset{min}{#1} + \pgfooset{max}{#2} + } + + % Method + \method default connects() { + } + + % Sets the minimum/maximum to a new value + \method set min(#1) { + \pgfooset{min}{#1} + } + \method set max(#1) { + \pgfooset{max}{#1} + } + + % Getter + % + % Returns the current values of the minimum and maximum in the + % macros \pgfdvmin and \pgfdvmax. + \method get min and max() { + \pgfooget{min}\pgfdvmin + \pgfooget{max}\pgfdvmax + } + + % Adjusts the mimum and maximum values + % + % #1 = some code. When this code is executed, the values of + % \pgfdvmin and \pgfdvmax will be set to the current values of + % the minimum/maximum. The code may change these values. The + % changed values will then be stored. + % + % This method does nothing that cannot be achieved also by calling + % set/get methods, but it is easier to use and faster. + \method adjust(#1) { + {% + \pgfooget{min}\pgfdvmin + \pgfooget{max}\pgfdvmax + #1% + \pgfoolet{min}\pgfdvmin + \pgfoolet{max}\pgfdvmax + }% + } +} + + + +\pgfooclass{count} +{ + % Class count + % + % This class can be used to count the number of data points that are + % present or that have a certain property. By default, for every + % data point a counter is incremented and the value of this counter + % is stored in an attribute. You can also specify an increment for + % the counter and some action that should be taken when the counter + % reaches zero. You can also specify that certain data points should + % not have an effect on the counter. + % + % Counters can serve different purposes. + % + % 1. For plotting points in a table or sequence, the counter can be + % used to provide the position along one axis. + % 2. By using the counter as a repetitive count down one can for + % instance have only every 10th data point be marked. + + \attribute attribute; + % The attribute that will be set to the current value of the counter + + \attribute val=0; + % The current value of the counter + + \attribute step=1; + % The stepping by which the counter is incremented for each + % datapoint + + \attribute start val=0; + % The start value of the counter + + \attribute filter=; + % This attribute stores some code that is executed for each + % data point. If the data point sets the TeX-if ifpgfdvfilterpassed to + % true, then the counter is not incremented. + + + % Constructor + % + % #1 = The attribute in which the counter value is stored + % + \method count(#1) { + \pgfooset{attribute}{#1} + } + + % Method + \method default connects() { + \pgfoothis.get handle(\pgf@dv@me) + \pgfkeysvalueof{/pgf/data visualization/obj}.connect(\pgf@dv@me,apply,prepare datapoint signal) + \pgfkeysvalueof{/pgf/data visualization/obj}.connect(\pgf@dv@me,phase,phase signal) + } + + % Setter + \method set value(#1) { + \pgfooset{val}{#1} + \pgfkeyssetvalue{/data point/\pgfoovalueof{attribute}}{#1}% + } + + % Setter + \method set start value(#1) { + \pgfooset{start val}{#1} + } + + % Setter + \method set filter(#1) { + \pgfooset{filter}{#1} + } + + % Setter + \method set step(#1) { + \pgfooset{step}{#1} + } + + % Slot + \method apply() { + \pgfdvfilterpassedtrue% + \pgfoovalueof{filter}% + \ifpgfdvfilterpassed% + \pgfmathparse{\pgfoovalueof{val}+\pgfoovalueof{step}}% + \pgfoolet{val}\pgfmathresult% + \pgfkeyslet{/data point/\pgfoovalueof{attribute}}\pgfmathresult% + \fi% + } + + % Slot + \method phase(#1) { + \ifx#1\pgfdvbeginsurvey + \pgfooeset{val}{\pgfoovalueof{start val}} + \else \ifx#1\pgfdvbeginvisualization + \pgfooeset{val}{\pgfoovalueof{start val}} + \fi\fi + } +} + +\newif\ifpgfdvfilterpassed + + + + +\pgfooclass{accumulator} +{ + % Class accumulator + % + % This class is used to keep track of the sum of the values of some + % attribute. When this object is connected to some attribute, the + % subkey attribute/sum will always contain the sum of all values in + % all previous data points with respect to this + % attribute. Furthermore, the subkey attribute/prev key will hold + % the previous sum, which is sometimes also useful to have access + % to. + + \attribute attribute; + % The attribute to-be-accumulated + + \attribute sum; + % The initial value of the sum + + % Constructor + % + % #1 = to-be-accumulated attribute + \method accumulator(#1) { + \pgfooset{attribute}{#1} + \pgfoothis.reset() + } + + % Method + \method default connects() { + \pgfoothis.get handle(\pgf@dv@me) + \pgfkeysvalueof{/pgf/data visualization/obj}.connect(\pgf@dv@me,apply,prepare datapoint signal) + \pgfkeysvalueof{/pgf/data visualization/obj}.connect(\pgf@dv@me,phase,phase signal) + } + + % Slot + \method apply() {% + % Save old sum + \pgfkeysgetvalue{/data point/\pgfoovalueof{attribute}/sum}\pgf@temp% + \pgfkeyslet{/data point/\pgfoovalueof{attribute}/prev sum}\pgf@temp% + % Add new attribute... + \pgfkeysgetvalue{/data point/\pgfoovalueof{attribute}}{\pgf@temp@b}% + \pgfdvmathenter{\pgf@dv@new@val}{\pgf@temp@b}% + % ... to sum + \pgfooget{sum}\pgf@dv@sum% + \pgfdvmathadd{\pgf@dv@sum}{\pgf@dv@new@val}{\pgf@dv@sum}% + \pgfoolet{sum}\pgf@dv@sum + % Record in attribute + \pgfdvmathexitbyscientificformat{\pgf@dv@serial@sum}{\pgf@dv@sum} + \pgfkeyslet{/data point/\pgfoovalueof{attribute}/sum}\pgf@dv@serial@sum + } + + % Method + % + % Use this method to reset the sum at any point. + % + \method reset() { + \pgfdvmathenter{\pgf@dv@temp}{0} + \pgfoolet{sum}{\pgf@dv@temp} + \pgfdvmathexitbyserializing{\pgf@dv@zero}{\pgf@dv@temp} + \pgfkeyslet{/data point/\pgfoovalueof{attribute}/prev sum}{\pgf@dv@zero} + \pgfkeyslet{/data point/\pgfoovalueof{attribute}/sum}{\pgf@dv@zero} + } + + % Slot + \method phase(#1) { + \ifx#1\pgfdvbeginsurvey + \pgfoothis.reset() + \else \ifx#1\pgfdvbeginvisualization + \pgfoothis.reset() + \fi\fi + } +} + + + + + + + +% +% +% Help keys and, attributes +% +% + +\pgfkeys{% do not even think of changing the values of the following: + /data point/always true/.initial=true, + /data point/always false/.initial=false, + /data point/always 0/.initial=0, + /data point/always 1/.initial=1, + /data point/always empty/.initial=, + /data point/always pgfusepath stroke/.initial=\pgfusepath{stroke} +} + +\pgfdvmathenter{\pgfdvmathalwaysloge}{0.434294481903252} +\pgfdvmathenter{\pgfdvmathalwayslnten}{2.302585092994046} +\pgfdvmathenter{\pgfdvmathalwayszero}{0} +\pgfdvmathenter{\pgfdvmathalwaysone}{1} + + +\endinput + + + + + + diff --git a/Master/texmf-dist/tex/generic/pgf/modules/pgfmoduledecorations.code.tex b/Master/texmf-dist/tex/generic/pgf/modules/pgfmoduledecorations.code.tex index 739a28395c2..9834e91f0ec 100644 --- a/Master/texmf-dist/tex/generic/pgf/modules/pgfmoduledecorations.code.tex +++ b/Master/texmf-dist/tex/generic/pgf/modules/pgfmoduledecorations.code.tex @@ -1,4 +1,4 @@ -% Copyright 2008 by Mark Wibrow +% Copyright 2008 by Mark Wibrow and Till Tantau % % This file may be distributed and/or modified % @@ -57,10 +57,11 @@ start radius/.initial=2.5pt, end radius/.initial=2.5pt, radius/.style={start radius=#1,end radius=#1}, - path has corners/.is if=pgfdecoratepathhascorners + path has corners/.is if=pgfdecoratepathhascorners, + reverse path/.is if=pgf@decorate@inputsegmentobjects@reverse } \newif\ifpgfdecoratepathhascorners - +\newif\ifpgf@decorate@inputsegmentobjects@reverse % Declare a decoration % @@ -490,6 +491,7 @@ } + % Enviroment \pgfmetadecoration \endpgfmetadecoration % % Decorate a path with decoration automatons! @@ -539,12 +541,12 @@ % \endpgfpicture % \def\pgfmetadecoration#1{% - \begingroup% - \let\decoration\pgf@metadecoration@decoration% - \let\beforedecoration\pgf@metadecoration@beforedecoration% - \let\afterdecoration\pgf@metadecoration@afterdecoration% - \def\pgf@metadecoration@name{#1}% - \pgf@decoration@env% + \begingroup% + \let\decoration\pgf@metadecoration@decoration% + \let\beforedecoration\pgf@metadecoration@beforedecoration% + \let\afterdecoration\pgf@metadecoration@afterdecoration% + \def\pgf@metadecoration@name{#1}% + \pgf@decoration@env% } \def\endpgfmetadecoration{% @@ -611,6 +613,21 @@ \bgroup% } +\def\pgf@decorate@path@check@moveto#1{% + \expandafter\pgf@decorate@path@@check@moveto#1\pgf@decorate@stop\pgf@decorate@@stop} + +\def\pgf@decorate@token@stop{\pgf@decorate@stop}% +\def\pgf@decorate@path@@check@moveto#1#2#3#4\pgf@decorate@@stop#5#6{% + \def\pgf@decorate@temp{#4}% + \pgf@x=#2\relax% + \pgf@y=#3\relax% + \ifx\pgf@decorate@temp\pgf@decorate@token@stop% + #5% + \else% + #6% + \fi% +} + \def\pgf@decoration@endenv{% \egroup% \pgftransformreset% @@ -623,6 +640,18 @@ \ifx\pgfdecoratedpath\pgfutil@empty% \PackageError{PGF}{I cannot decorate an empty path}{}% \else% + % + % If the path consists of a single moveto token, make it + % a very small horizontal line. + % + \pgf@decorate@path@check@moveto\pgfdecoratedpath{% + \advance\pgf@x by0.0001pt\relax% + \edef\pgfdecoratedpath{% + \expandafter\noexpand\pgfdecoratedpath% + \noexpand\pgfsyssoftpath@linetotoken{\the\pgf@x}{\the\pgf@y}% + }% + }% + {}% % % Remove special round tokens and get points. % @@ -631,6 +660,16 @@ % Parse the soft path into a series of decorated input segment objects. % \pgf@decorate@parsesoftpath{\pgfdecoratedpath}{\pgf@decorate@inputsegmentobjects}% + % + % Setup further options + % + \pgfkeys{/pgf/every decoration/.try}% + % + % Reverse objects if necessary. + % + \ifpgf@decorate@inputsegmentobjects@reverse% + \pgf@decorate@inputsegmentobjects@reverse{\pgf@decorate@inputsegmentobjects}{\pgf@decorate@inputsegmentobjects}% + \fi% % \let\pgf@decorated@remainingdistance\pgf@decorate@totalpathlength% % @@ -647,13 +686,8 @@ \pgf@decorate@getnextinputsegmentobject\pgf@decorate@nextinputsegmentobject% \pgf@decorate@processnextinputsegmentobject% \pgf@decorate@distancetomove0pt\relax% - % - % Setup further options - % - \pgfkeys{/pgf/every decoration/.try}% \fi% -}% - +}% @@ -1194,25 +1228,24 @@ % Process the next input segment object. % \def\pgf@decorate@processnextinputsegmentobject{% - % + \let\pgfdecorationpreviousinputsegment\pgfdecoratecurrentinputsegment% \let\pgf@decorate@currentinputsegmentobject\pgf@decorate@nextinputsegmentobject% \pgf@decorate@getnextinputsegmentobject\pgf@decorate@nextinputsegmentobject% - % + % % If the current input segment object is a moveto, execute the % object macro and get the next input segment object. % - \expandafter\pgfutil@in@\expandafter\pgf@decorate@inputsegmentobject@moveto% - \expandafter{\pgf@decorate@currentinputsegmentobject}% - \ifpgfutil@in@% - \pgf@decorate@currentinputsegmentobject% + \pgf@decorate@is@closepath@false% + \pgf@decorate@currentinputsegmentobject% + \ifx\pgfdecorationcurrentinputsegment\pgfdecorationinputsegmentmoveto% + \pgfpathmoveto{\pgf@decorate@inputsegment@first}% + \let\pgfdecorationpreviousinputsegment\pgfdecorationcurrentinputsegment% \let\pgf@decorate@currentinputsegmentobject\pgf@decorate@nextinputsegmentobject% \pgf@decorate@getnextinputsegmentobject\pgf@decorate@nextinputsegmentobject% - \relax% + \pgf@decorate@is@closepath@false% + \pgf@decorate@currentinputsegmentobject% \fi% % - \pgf@decorate@is@closepath@false% - \pgf@decorate@currentinputsegmentobject% - % % Teensy hack in case a path goes nowhere. % \ifdim\pgfdecoratedinputsegmentlength=0pt\relax% @@ -1221,8 +1254,41 @@ \pgfdecoratedinputsegmentremainingdistance\pgfdecoratedinputsegmentlength\relax% \pgfdecoratedinputsegmentcompleteddistance0pt\relax% \def\pgf@decorate@inputsegmenttime{0}% - \pgfmathanglebetweenpoints{\pgf@decorate@inputsegment@first}{\pgf@decorate@inputsegment@supporta}% - \let\pgfdecoratedangle\pgfmathresult% + % + % Get the angle at the start of the input segment. + % + \ifx\pgfdecorationcurrentinputsegment\pgfdecorationinputsegmentcurveto% + \pgfmathanglebetweenpoints{\pgf@decorate@inputsegment@first}{\pgf@decorate@inputsegment@supporta}% + \let\pgfdecoratedangle\pgfmathresult% + \let\pgfdecoratedinputsegmentstartangle\pgfmathresult% + \pgfmathanglebetweenpoints{\pgf@decorate@inputsegment@supportb}{\pgf@decorate@inputsegment@last}% + \let\pgfdecoratedinputsegmentendangle\pgfmathresult% + \else% + \pgfmathanglebetweenpoints{\pgf@decorate@inputsegment@first}{\pgf@decorate@inputsegment@last}% + \let\pgfdecoratedangle\pgfmathresult% + \let\pgfdecoratedinputsegmentstartangle\pgfmathresult% + \let\pgfdecoratedinputsegmentendangle\pgfmathresult% + \fi% + % + % Get the angle to the next input segment. + % + \begingroup% + \pgf@decorate@nextinputsegmentobject% + \global\let\pgf@decorate@temp\pgfdecorationcurrentinputsegment% + \ifx\pgfdecorationcurrentinputsegment\pgfdecorationinputsegmentmoveto% + \expandafter\pgf@decorate@currentinputsegmentobject% + \fi% + \ifx\pgfdecorationcurrentinputsegment\pgfdecorationinputsegmentcurveto% + \pgfmathanglebetweenpoints{\pgf@decorate@inputsegment@first}{\pgf@decorate@inputsegment@supporta}% + \else% + \pgfmathanglebetweenpoints{\pgf@decorate@inputsegment@first}{\pgf@decorate@inputsegment@last}% + \fi% + \pgf@x-\pgfdecoratedangle pt\relax% + \advance\pgf@x\pgfmathresult pt\relax% + \edef\pgfdecoratedangletonextinputsegment{\the\pgf@x}% + \pgfmath@smuggleone\pgfdecoratedangletonextinputsegment% + \endgroup% + \let\pgfdecorationnextinputsegmentobject\pgf@decorate@temp% } @@ -1232,18 +1298,30 @@ \newif\ifpgf@decorate@is@closepath@% +% Input segment types. +% +% These allow comparison with \ifx using +% +% \pgfdecorationcurrentinputsegment +% \pgfdecorationnextinputsegment +% \pgfdecorationcurrentprevioussegment +% +\def\pgfdecorationinputsegmentmoveto{moveto} +\def\pgfdecorationinputsegmentlineto{lineto} +\def\pgfdecorationinputsegmentcurveto{curveto} +\def\pgfdecorationinputsegmentclosepath{closepath} +\def\pgfdecorationinputsegmentlast{last} % Input segment object moveto. % \def\pgf@decorate@inputsegmentobject@moveto#1{% - \pgfpathmoveto{#1}% \def\pgf@decorate@inputsegment@first{#1}% \def\pgf@decorate@inputsegment@supporta{#1}% \def\pgf@decorate@inputsegment@supportb{#1}% \def\pgf@decorate@inputsegment@last{#1}% \edef\pgf@decorate@lastmoveto{#1}% \def\pgfdecoratedinputsegmentlength{0pt}% - \let\pgf@decorate@splitinputsegmentobject\pgf@decorate@splitinputsegmentobject@move% + \let\pgfdecorationcurrentinputsegment\pgfdecorationinputsegmentmoveto% } % Input segment object lineto. @@ -1251,17 +1329,28 @@ \def\pgf@decorate@inputsegmentobject@lineto#1#2#3{% \def\pgfdecoratedinputsegmentlength{#1}% \def\pgf@decorate@inputsegment@first{#2}% + \def\pgf@decorate@inputsegment@last{#3}% % - % OK, lines don't need supports, but this means angle calculations - % do not have to be done individually for each object. + % Supports should be defined like this, so if treated as a curve, + % equal time steps will correspond to equal distances. % - \def\pgf@decorate@inputsegment@supporta{#3}% - \def\pgf@decorate@inputsegment@supportb{#2}% - \def\pgf@decorate@inputsegment@last{#3}% + \pgfpointdiff{#2}{#3}% + \pgf@xa\pgf@x% + \pgf@ya\pgf@y% + \pgfextract@process\pgf@decorate@inputsegment@supporta{% + \pgf@process{#2}% + \advance\pgf@x0.333333\pgf@xa% + \advance\pgf@y0.333333\pgf@ya% + }% + \pgfextract@process\pgf@decorate@inputsegment@supportb{% + \pgf@process{#2}% + \advance\pgf@x0.666666\pgf@xa% + \advance\pgf@y0.666666\pgf@ya% + }% % \let\pgf@decorate@movealonginputsegment\pgf@decorate@movealonginputsegment@line% \let\pgf@decorate@transformtoinputsegment\pgf@decorate@transformtoinputsegment@line% - \let\pgf@decorate@splitinputsegmentobject\pgf@decorate@splitinputsegmentobject@line% + \let\pgfdecorationcurrentinputsegment\pgfdecorationinputsegmentlineto% } % Input segment object curveto. @@ -1275,7 +1364,7 @@ % \let\pgf@decorate@movealonginputsegment\pgf@decorate@movealonginputsegment@curve% \let\pgf@decorate@transformtoinputsegment\pgf@decorate@transformtoinputsegment@curve% - \let\pgf@decorate@splitinputsegmentobject\pgf@decorate@splitinputsegmentobject@curve% + \let\pgfdecorationcurrentinputsegment\pgfdecorationinputsegmentcurveto% } % Input segment object closepath. @@ -1287,18 +1376,33 @@ % \def\pgfdecoratedinputsegmentlength{#1}% \def\pgf@decorate@inputsegment@first{#2}% - \def\pgf@decorate@inputsegment@supporta{#3}% - \def\pgf@decorate@inputsegment@supportb{#2}% - \def\pgf@decorate@inputsegment@last{#3}% - % + \def\pgf@decorate@inputsegment@last{#3}% + % + \pgfpointdiff{#2}{#3}% + \pgf@xa\pgf@x% + \pgf@ya\pgf@y% + \pgfextract@process\pgf@decorate@inputsegment@supporta{% + \pgf@process{#2}% + \advance\pgf@x0.333333\pgf@xa% + \advance\pgf@y0.333333\pgf@ya% + }% + \pgfextract@process\pgf@decorate@inputsegment@supportb{% + \pgf@process{#2}% + \advance\pgf@x0.666666\pgf@xa% + \advance\pgf@y0.666666\pgf@ya% + }% + % \let\pgf@decorate@movealonginputsegment\pgf@decorate@movealonginputsegment@line% \let\pgf@decorate@transformtoinputsegment\pgf@decorate@transformtoinputsegment@line% - \let\pgf@decorate@splitinputsegmentobject\pgf@decorate@splitinputsegmentobject@line% + \let\pgfdecorationcurrentinputsegment\pgfdecorationinputsegmentclosepath% } + % Input segment object endofinputsegments. % -\def\pgf@decorate@inputsegmentobject@endofinputsegments{} +\def\pgf@decorate@inputsegmentobject@endofinputsegments{% + \let\pgfdecorationcurrentinputsegment\pgfdecorationinputsegmentlast% +} @@ -1493,7 +1597,7 @@ % \pgfpathlineto{\pgfpoint{12pt}{0pt}} % \pgfgetpath\softpath % -% \pgf@decorate@parsesoftpath{\softpath}{\parsedsoftpath}{} +% \pgf@decorate@parsesoftpath{\softpath}{\parsedsoftpath} % % results in: % @@ -1855,6 +1959,150 @@ } +% Macro to reverse a set of input segment objects. +% +% #1 - a macro holding the input segment objects. +% #2 - a macro holding the reversed input segment objects. +% +\def\pgf@decorate@inputsegmentobjects@reverse#1#2{% + \def\pgf@decorate@path@storein{#2}% + \def\pgf@decorate@inputsegments@@temp{}% + \expandafter\pgf@decorate@inputsegments@@reverse@pass@first#1\pgf@stop} + +\def\pgf@decorate@inputsegments@@reverse@pass@first#1#2\pgf@stop{% + \def\pgf@decorate@temp{#1}% + \expandafter\expandafter\expandafter\def\expandafter\expandafter\expandafter% + \pgf@decorate@inputsegments@@temp\expandafter\expandafter\expandafter% + {\expandafter\pgf@decorate@temp\pgf@decorate@inputsegments@@temp}% + \def\pgf@decorate@test{#2} + \ifx\pgf@decorate@test\pgfutil@empty% + \def\pgf@decorate@next{% + \expandafter\pgf@decorate@inputsegmentobjects@reverse@pass@second\pgf@decorate@inputsegments@@temp\pgf@stop% + }% + \else% + \def\pgf@decorate@next{\pgf@decorate@inputsegments@@reverse@pass@first#2\pgf@stop}% + \fi% + \pgf@decorate@next% +} +\def\pgf@decorate@inputsegmentobjects@reverse@pass@second#1#2#3\pgf@stop{% + \def\pgf@decorate@inputsegments@temp{#3}% + \def\pgf@decorate@inputsegments@@temp{}% + \let\pgf@decorate@current@inputsegmentobject=\pgfutil@empty + \let\pgf@decorate@last@object=\pgfutil@empty + \pgf@decorate@inputsegmentobjects@reverse@moveto@waitingtrue% + \pgf@decorate@inputsegmentobjects@reverse@closepath@waitingfalse% + \expandafter\pgf@decorate@path@@reverse@pass@second\pgf@decorate@inputsegments@temp\pgf@stop}% + + +\def\pgf@decorate@path@@reverse@pass@second#1{% + \ifx#1\pgf@stop% + \expandafter\def\expandafter\pgf@decorate@inputsegments@@temp\expandafter{% + \pgf@decorate@inputsegments@@temp% + {\pgf@decorate@inputsegmentobject@endofinputsegments}% + {\pgf@decorate@inputsegmentobject@endofinputsegments} + }% + \expandafter\let\pgf@decorate@path@storein=\pgf@decorate@inputsegments@@temp% + \let\pgf@decorate@next=\relax% + \else% + \ifx#1\pgf@decorate@inputsegmentobject@moveto% + \let\pgf@decorate@next=\pgf@decorate@inputsegmentobjects@reverse@moveto% + \else% + \ifx#1\pgf@decorate@inputsegmentobject@lineto% + \let\pgf@decorate@next=\pgf@decorate@inputsegmentobjects@reverse@lineto% + \else% + \ifx#1\pgf@decorate@inputsegmentobject@curveto% + \let\pgf@decorate@next=\pgf@decorate@inputsegmentobjects@reverse@curveto% + \else% + \ifx#1\pgf@decorate@inputsegmentobject@closepath% + \let\pgf@decorate@next=\pgf@decorate@inputsegmentobjects@reverse@closepath% + \else% + \fi% + \fi% + \fi% + \fi% + \fi% + \pgf@decorate@next% +} + +\newif\ifpgf@decorate@inputsegmentobjects@reverse@moveto@waiting + +\def\pgf@decorate@inputsegmentobjects@reverse@moveto#1{% + \ifpgf@decorate@inputsegmentobjects@reverse@closepath@waiting% + \edef\pgf@decorate@current@inputsegmentobject{% + {\noexpand\pgf@decorate@inputsegmentobject@closepath% + {\pgf@decorate@reverse@closepath@length}% + {\pgf@decorate@last}% + {#1}% + }% + }% + \pgf@decorate@inputsegmentobjects@reverse@closepath@waitingfalse% + \else% + \let\pgf@decorate@current@inputsegmentobject=\pgfutil@empty% + \fi% + \pgf@decorate@inputsegmentobjects@reverse@moveto@waitingtrue% + \pgf@decorate@path@@@reverse@pass@second% +} + +\newif\ifpgf@decorate@inputsegmentobjects@reverse@closepath@waiting + +\def\pgf@decorate@inputsegmentobjects@reverse@closepath#1#2#3{% + \pgf@decorate@inputsegmentobjects@reverse@closepath@waitingtrue% + \def\pgf@decorate@reverse@closepath@length{#1}% + \def\pgf@decorate@current@inputsegmentobject{}% + \pgf@decorate@inputsegmentobjects@reverse@lineto{#1}{#2}{#3}% +} + +\def\pgf@decorate@inputsegmentobjects@reverse@lineto#1#2#3#4{% + \ifpgf@decorate@inputsegmentobjects@reverse@moveto@waiting% + \def\pgf@decorate@current@inputsegmentobject{{\pgf@decorate@inputsegmentobject@moveto{#3}}}% + \pgf@decorate@inputsegmentobjects@reverse@moveto@waitingfalse% + \else% + \let\pgf@decorate@current@inputsegmentobject=\pgfutil@empty% + \fi% + \def\pgf@decorate@append@inputsegmentobject{{\pgf@decorate@inputsegmentobject@lineto{#1}{#3}{#2}}}% + \ifx#4\pgf@decorate@inputsegmentobject@moveto% + \ifpgf@decorate@inputsegmentobjects@reverse@closepath@waiting% + \def\pgf@decorate@append@inputsegmentobject{{\pgf@decorate@inputsegmentobject@closepath{#1}{#3}{#2}}}% + \pgf@decorate@inputsegmentobjects@reverse@closepath@waitingfalse% + \else% + \def\pgf@decorate@append@inputsegmentobject{{\pgf@decorate@inputsegmentobject@lineto{#1}{#3}{#2}}}% + \fi% + \fi% + \expandafter\expandafter\expandafter\def\expandafter\expandafter\expandafter% + \pgf@decorate@current@inputsegmentobject\expandafter\expandafter\expandafter% + {\expandafter\pgf@decorate@current@inputsegmentobject\pgf@decorate@append@inputsegmentobject} + \def\pgf@decorate@last{#2}% + \pgf@decorate@path@@@reverse@pass@second#4% +} + +\def\pgf@decorate@inputsegmentobjects@reverse@curveto#1#2#3#4#5{% + \ifpgf@decorate@inputsegmentobjects@reverse@moveto@waiting% + \def\pgf@decorate@current@inputsegmentobject{% + {\pgf@decorate@inputsegmentobject@moveto{#5}}% + {\pgf@decorate@inputsegmentobject@curveto{#1}{#5}{#4}{#3}{#2}}% + }% + \pgf@decorate@inputsegmentobjects@reverse@moveto@waitingfalse% + \else% + \def\pgf@decorate@current@inputsegmentobject{{\pgf@decorate@inputsegmentobject@curveto{#1}{#5}{#4}{#3}{#2}}}% + \fi% + \def\pgf@decorate@last{#2}% + \pgf@decorate@path@@@reverse@pass@second% +} + +\def\pgf@decorate@path@@@reverse@pass@second{% + \ifx\pgf@decorate@current@inputsegmentobject\pgfutil@empty% + \else% + \expandafter\expandafter\expandafter\def\expandafter\expandafter\expandafter% + \pgf@decorate@inputsegments@@temp\expandafter\expandafter\expandafter% + {\expandafter\pgf@decorate@inputsegments@@temp\pgf@decorate@current@inputsegmentobject}% + \fi% + \pgf@decorate@path@@reverse@pass@second% +}% + + + + + \let\startpgfdecoration=\pgfdecoration \let\stoppgfdecoration=\endpgfdecoration diff --git a/Master/texmf-dist/tex/generic/pgf/modules/pgfmodulematrix.code.tex b/Master/texmf-dist/tex/generic/pgf/modules/pgfmodulematrix.code.tex index c808f60d762..32024c047d6 100644 --- a/Master/texmf-dist/tex/generic/pgf/modules/pgfmodulematrix.code.tex +++ b/Master/texmf-dist/tex/generic/pgf/modules/pgfmodulematrix.code.tex @@ -7,7 +7,7 @@ % % See the file doc/generic/pgf/licenses/LICENSE for more details. -\ProvidesFileRCS $Header: /cvsroot/pgf/pgf/generic/pgf/modules/pgfmodulematrix.code.tex,v 1.1 2008/01/15 10:27:34 tantau Exp $ +\ProvidesFileRCS $Header: /cvsroot/pgf/pgf/generic/pgf/modules/pgfmodulematrix.code.tex,v 1.4 2010/08/24 21:28:58 tantau Exp $ \usepgfmodule{shapes} @@ -77,7 +77,7 @@ % % Next, the whole resulting matrix, which is given as #7, is placed % inside a node whose name is given as #3, whose shape is #1, and -% whose anchor is #1. This means that the resulting node is shifted +% whose anchor is #2. This means that the resulting node is shifted % such that the given anchor lies at the origin. Then, as for a normal % node, the #4 path usage command is used for the node. % @@ -159,6 +159,7 @@ \PackageError{pgf}{You cannot nest pgfmatrix environments, yet}{} \fi% \bgroup% + \everycr{}% #6% \def\pgf@matrix@par@shape{#1}% \def\pgf@matrix@par@anchor{#2}% @@ -360,6 +361,9 @@ % Step 4: Collect everything in a cell box % \setbox\pgf@matrix@cell=\hbox\bgroup\bgroup% + % make sure that cell pictures are not affected if matrizes have + % 'overlay' option on: + \pgf@relevantforpicturesizetrue \pgfsys@beginpicture% \normalbaselines% % Find out whether the cell is empty: diff --git a/Master/texmf-dist/tex/generic/pgf/modules/pgfmoduleoo.code.tex b/Master/texmf-dist/tex/generic/pgf/modules/pgfmoduleoo.code.tex new file mode 100644 index 00000000000..e80d3ac06bb --- /dev/null +++ b/Master/texmf-dist/tex/generic/pgf/modules/pgfmoduleoo.code.tex @@ -0,0 +1,451 @@ +% 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 $Header: /cvsroot/pgf/pgf/generic/pgf/modules/pgfmoduleoo.code.tex,v 1.8 2010/02/22 22:49:21 tantau Exp $ + + + +% Support of object-oriented programming in TeX. + + +% The oo support works as follows: +% +% The main supported concepts are classes, objects, methods, +% attributes and signal/slots. A class defines a set of methods, which are, +% in the end, just normal TeX macros. Once a class has been created, +% it can be instantiated by calling the \pgfoonew command, resulting +% in a new object. Objects are local to their group. Given an object, +% you can send it a message, resulting in the method code of the +% object's method to be executed. While an object exists, it has a set +% of attributes whose values can change over time. Attributes values +% are not local to TeX groups, rather their life-cycle is the same as +% the object's (which, however, is local to the group in which the +% object was declared). +% +% The implementation is as follows: There is an ID counter that is +% increased each time an object is created. This counter is local to +% the group, which means that when a group ends the counter will +% revert to the previous value, allowing objects to the reused in +% subsequent groups. +% +% A method is just a normal \TeX macro, but to call it you write +% \objecthandle.methodname(parameters). The \objecthandle is a macro +% that is created when you say \pgfoonew. The special object +% \pgfoothis is the current object. +% +% Attributes are stored globally in internal TeX macros whose name is +% composed of the object number and the attribute name. + + + + +% Declares a class +% +% #1 = class name +% #2 = methods +% +% Description: +% +% This command declares a class for futurue use. Inside #2, the macro +% \method can be used to declare a method. The \method macro takes a +% method name, parameters (methods are normal TeX macros, after all) +% and body. + +\long\def\pgfooclass#1#2{% + \def\pgfoo@classname{#1}% + \let\pgfoo@origmethod=\method% + \let\pgfoo@origattribute=\attribute% + \let\method=\pgfoo@declaremethod% + \let\attribute=\pgfoo@declareattribute% + \let\pgfoo@attribute@collection=\pgfutil@empty% + \let\pgfoo@attribute@collection@gc=\pgfutil@empty% + #2% + % Attribute initializer: + \expandafter\let\csname pgfooY\pgfoo@classname.@pgfooinit\endcsname\pgfoo@attribute@collection% + \expandafter\let\csname pgfooY\pgfoo@classname.@pgfoogc\endcsname\pgfoo@attribute@collection@gc% + % Always persent methods: + \expandafter\let\csname pgfooY\pgfoo@classname.get handle\endcsname\pgfoo@obj% + \expandafter\let\csname pgfooY\pgfoo@classname.get id\endcsname\pgfoo@id% + \let\method=\pgfoo@origmethod% + \let\attribute=\pgfoo@origattribute% +} + + + +% Declare a method +% +% Description: +% +% Defines a method. To use/invoke this method for an object \object, +% you write \object.methodname(parameters). This will cause the method +% body to be invoked with the argument "(parameters)". +% +% To define the method \method should be directly followed by the +% method name and, then, by (, followed by a parameter pattern, +% followed by ), followed by the message body. Spaces are allowed only +% after "\method" and after the closing ). +% +% Example: +% +% \pgfooclass{MyPlot}{ +% +% \attribute x=0; +% \attribute y=0; +% +% \method MyPlot() { +% } +% +% \method getX(#1) { +% \pgfooget{x}{#1} +% } +% +% \method setPoint(#1,#2) { +% \pgfooset{x}{#1} +% \pgfooset{y}{#2} +% } +% } + +\def\pgfoo@declaremethod#1(#2)#3{% + \expandafter\long\expandafter\def\csname pgfooY\pgfoo@classname.#1\endcsname(#2){#3}% +} + + +% Declare an attribute +% +% #1 = attribute name +% #2 = optional default value +% +% Description: +% +% Declares the attribute #1 for the current class. If the attribute +% name is followed by =, the text following the equal sign is the +% default value. + +\def\pgfoo@declareattribute#1;{% + \pgfutil@in@{ =}{#1}% + \ifpgfutil@in@% + \pgfoo@declareunpackspace#1;% + \else% + \pgfutil@in@={#1}% + \ifpgfutil@in@% + \pgfoo@declareunpack#1;% + \else% + \expandafter\def\expandafter\pgfoo@attribute@collection\expandafter{\pgfoo@attribute@collection\pgfoolet{#1}\pgfutil@empty}% + \expandafter\def\expandafter\pgfoo@attribute@collection@gc\expandafter{\pgfoo@attribute@collection@gc\pgfoolet{#1}\relax}% + \fi% + \fi% +} +\def\pgfoo@declareunpack#1=#2;{% + \expandafter\def\expandafter\pgfoo@attribute@collection\expandafter{\pgfoo@attribute@collection\pgfooset{#1}{#2}}% + \expandafter\def\expandafter\pgfoo@attribute@collection@gc\expandafter{\pgfoo@attribute@collection@gc\pgfoolet{#1}\relax}% +} +\def\pgfoo@declareunpackspace#1 =#2;{% + \expandafter\def\expandafter\pgfoo@attribute@collection\expandafter{\pgfoo@attribute@collection\pgfooset{#1}{#2}}% + \expandafter\def\expandafter\pgfoo@attribute@collection@gc\expandafter{\pgfoo@attribute@collection@gc\pgfoolet{#1}\relax}% +} + + +\newcount\pgfoo@objectcount +\newcount\pgfoothis@count + +% The attribute value method +% +% #1 = attr +% +% This method inserts the current value of the given attribute for the +% current object. + +\def\pgfoovalueof#1{% + \csname pgfooX\the\pgfoothis@count @#1\endcsname% +} + + +% The attribute get method +% +% #1 = attr +% #2 = macro +% +% This method makes the macro equal to the current value of the +% attribute for the current object. + +\def\pgfooget#1#2{% + \expandafter\let\expandafter#2\csname pgfooX\the\pgfoothis@count @#1\endcsname% +} + + +% The attribute set method +% +% #1 = attr +% #2 = value +% +% This method sets the given attribute for the current object to the +% given value. + +\long\def\pgfooset#1#2{% + \expandafter\gdef\csname pgfooX\the\pgfoothis@count @#1\endcsname{#2}% +} + + +% The attribute set method (expanded version) +% +% #1 = attr +% #2 = value +% +% This method sets the given attribute for the current object to the +% expanded version of the given value. + +\long\def\pgfooeset#1#2{% + \expandafter\xdef\csname pgfooX\the\pgfoothis@count @#1\endcsname{#2}% +} + + +% The attribute let method +% +% #1 = attr +% #2 = value +% +% This method sets the given attribute for the current object to the +% given value using \let. + +\def\pgfoolet#1#2{% + \expandafter\global\expandafter\let\csname pgfooX\the\pgfoothis@count @#1\endcsname#2% +} + + +% Add something to an attribute at the end +% +% #1 = attr +% #2 = code +% +% This method adds the give code to the attr at the end. + +\def\pgfooappend#1#2{% + \expandafter\expandafter\expandafter\def% + \expandafter\expandafter\expandafter\pgf@oo@temp\expandafter\expandafter\expandafter{\csname pgfooX\the\pgfoothis@count @#1\endcsname#2}% + \expandafter\global\expandafter\let\csname pgfooX\the\pgfoothis@count @#1\endcsname\pgf@oo@temp% +} + + +% Add something to an attribute at the beginning +% +% #1 = attr +% #2 = code +% +% This method adds the give code to the attr at the beginning. + +\def\pgfooprefix#1#2{% + \pgfooget{#1}\pgf@oo@temp% + \def\pgf@oo@@temp{#2}% + \expandafter\expandafter\expandafter\def% + \expandafter\expandafter\expandafter\pgf@oo@temp% + \expandafter\expandafter\expandafter{\expandafter\pgf@oo@@temp\pgf@oo@temp}% + \pgfoolet{#1}\pgf@oo@temp% +} + + + +% Instantiate an object +% +% Possible syntax: +% +% 1) \pgfoonew new <class name>(<constructor parameters) +% 2) \pgfoonew \<objectname>=new <class name>(<constructor parameters) +% 3) \pgfoonew{attribute}=new <class name>(<constructor parameters) +% +% Description: +% +% Creates an object. After the object has been created, the method +% called <class name> (the constructor) is invoked. If the +% \<objectname>= part is present, the macro is assigned to the newly +% created object. + +\def\pgfoonew{% + \pgfutil@ifnextchar n{% + \pgfoo@new\pgfoo@dummy=% + }{% + \pgfutil@ifnextchar\bgroup{% + \pgfoo@new@attribute% + }{% + \pgfoo@new% + }% + }% +} +\def\pgfoo@new#1=new #2(#3){% + \expandafter\ifx\csname pgfooY#2.get id\endcsname\relax% + \PackageError{pgfoo}{Unknown class '#2'}{}% + \else% + \advance\pgfoo@objectcount by 1\relax% + \edef\pgfoolastobj{\noexpand\pgfoo@caller{\the\pgfoo@objectcount}}% + \expandafter\gdef\csname pgfooX\the\pgfoo@objectcount @class\endcsname{#2}% + \let#1\pgfoolastobj% + {% + \pgfoothis@count\pgfoo@objectcount% + \csname pgfooY\csname pgfooX\the\pgfoothis@count @class\endcsname.@pgfooinit\endcsname% + }% + \pgfoolastobj.#2(#3)% + \aftergroup\pgfoogc% cleanup after group + \fi% +} +\def\pgfoo@new@attribute#1=new #2(#3){% + \pgfoo@new\pgf@oo@temp=new #2(#3)% + \pgfoolet{#1}\pgf@oo@temp% +} + + +\def\pgfoo@caller#1.#2(#3){% + \def\pgf@marshal{% + \pgfoothis@count=#1\relax% + \csname pgfooY\csname pgfooX\the\pgfoothis@count @class\endcsname.#2\endcsname(#3)% + }% + \expandafter\pgf@marshal\expandafter\pgfoothis@count\the\pgfoothis@count\relax% +} +\let\pgfoo@orig@caller=\pgfoo@caller + +% The special "this" object + +\def\pgfoothis.#1(#2){% + \csname pgfooY\csname pgfooX\the\pgfoothis@count @class\endcsname.#1\endcsname(#2)% +} + + + + + +% Get the object id +% +% #1 = macro to store the id +% +% Description: +% +% This special method allows you to access the object id. You can then +% use \pgfoocall to call a method using this id. This is mainly useful +% when you wish to store the id for a longer time. + +\def\pgfoo@id(#1){% + \edef#1{\the\pgfoothis@count}% +} + +% Yields the object with the given id +% +% #1 = id +% +% Description: +% +% Given an object id, \pgfooobj{<id>} will yield the object having +% this id. + +\def\pgfooobj#1{% + \pgfoo@caller{#1}% +} + + +% Get the object +% +% #1 = macro to store the object +% +% Description: +% +% This special method allows you to get a new handle to a given +% object. If \obj is an object, you could normally just say +% \let#1=\obj. However, if \obj happens to be \pgfoothis, then you may +% wish to get a handle to the object itself, not to the special macro +% \pgfoothis. In this case you can say \obj.get handle(#1). + +\def\pgfoo@obj(#1){% + \edef#1{\noexpand\pgfoo@caller{\the\pgfoothis@count}}% +} + + + +% The garbage collector +% +% Description: +% +% This method frees space ocupied by unused objects. Garbage are +% objects that have been destroyed because of the end of the scope in +% which they were created. In this case, however, the memory used by +% this object is not immediately reused because the attributes of the +% object are actually stored in global variables. When the garbage +% collector is called, it will set all these global variables to +% \relax, thereby ensuring that no memory is needed for them. + +\def\pgfoogc{% + {% + % We do this in a group... + \pgfoothis@count\pgfoo@objectcount% this is temporary... + \let\pgfoo@next=\pgfoo@dogc% + \pgfoo@next% + }% +} +\def\pgfoo@dogc{% + \advance\pgfoothis@count by 1\relax% + \expandafter\ifx\csname pgfooX\the\pgfoothis@count @class\endcsname\relax% + \let\pgfoo@next=\relax% + \else% + % Cleanup this object: + % The following is the fast version of \pgfooobj{\the\pgfoo@objectcount}.@pgfoogc: + \csname pgfooY\csname pgfooX\the\pgfoothis@count @class\endcsname.@pgfoogc\endcsname% + \expandafter\global\expandafter\let\csname pgfooX\the\pgfoothis@count @class\endcsname\relax% + \fi% + \pgfoo@next% +} + + + + +% +% +% Signal class +% +% + +\pgfooclass{signal} +{ + % + % This class implements signals. + % + % After you have created a signal object, you can call + % connect to connect a slot. Then, whenever the emit method is + % called, all connected methods get called. + + % Attribute + \attribute emitter; + % Collects the objects that should be called. + + % Constructor + \method signal() {} + + % Connect a slot (method) #2 of object #1 + \method connect(#1,#2) {% + {% + #1.get id(\pgf@tempid)% + % Save in emmiter + \pgfooget{emitter}\pgf@temp% + \let\pgfoo@signal@call=\relax% avoid expansion + \edef\pgf@temp{\pgf@temp\pgfoo@signal@call{\pgf@tempid}{#2}}% + \pgfoolet{emitter}\pgf@temp% + }% + } + + \def\pgfoo@signal@call#1#2{% + \def\pgf@temp{\pgfooobj{#1}.#2}% + \expandafter\pgf@temp\expandafter(\pgfoo@signal@args)% + } + + % Emit a signal + \method emit(#1) {% + \def\pgfoo@signal@args{#1}% + \pgfoovalueof{emitter} + } +} + + + + +\endinput diff --git a/Master/texmf-dist/tex/generic/pgf/modules/pgfmoduleparser.code.tex b/Master/texmf-dist/tex/generic/pgf/modules/pgfmoduleparser.code.tex new file mode 100644 index 00000000000..ed13b25324c --- /dev/null +++ b/Master/texmf-dist/tex/generic/pgf/modules/pgfmoduleparser.code.tex @@ -0,0 +1,111 @@ +% Copyright 2009 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/modules/pgfmoduleparser.code.tex,v 1.1 2009/01/12 12:56:09 tantau Exp $ + +% +% This file defines commands for defining a letter-by-letter parser +% based on a dfa. +% + + + + +% Parse the following text +% +% #1 = parser +% +% Description: +% +% This command starts the parser #1 in the initial state "initial". It +% will parse the following text, stopping when the state "final" has +% been reached. + +\def\pgfparserparse#1{% + \def\pgf@parser{#1}% + \def\pgf@parser@state{initial}% + \pgf@parser@parse% +} +\def\pgf@parser@parse{% + \futurelet\pgf@parser@symbol\pgf@parser@cont% +} +\def\pgf@parser@cont{% + % Ok, defined? + \expandafter\let\expandafter\pgf@parser@action% + \csname pgf@parser@a@\pgf@parser @\pgf@parser@state @\meaning\pgf@parser@symbol\endcsname% + \ifx\pgf@parser@action\relax% + \expandafter\let\expandafter\pgf@parser@action% + \csname pgf@parser@a@\pgf@parser @all@\meaning\pgf@parser@symbol\endcsname% + \ifx\pgf@parser@action\relax% + \PackageError{pgfparse}{Unexpected character + '\meaning\pgf@parser@symbol' in parser '\pgf@parser' in state + '\pgf@parser@state'}{}% + \fi% + \fi% + \pgf@parser@action% + \ifx\pgf@parser@symbol\pgfutil@sptoken% + \expandafter\pgf@parser@rid@space% + \else% + \expandafter\pgf@parser@rid@other% + \fi% +} + +\def\pgf@parser@ridded{% + \ifx\pgf@parser@state\pgf@parser@final@text% + % done + \else% + \expandafter\pgf@parser@parse% + \fi% +} + +\def\pgf@parser@final@text{final} + +{% + \def\:{\pgf@parser@rid@space} \expandafter\gdef\: {\futurelet\pgf@parser@ignore\pgf@parser@ridded} + \gdef\pgf@parser@rid@other{\afterassignment\pgf@parser@ridded\let\pgf@parser@ignore=} +} + + + +% Switches the state +% +% #1 = new state +% +% Description: +% +% This command can be used inside a state action to switch to a +% different state. + +\def\pgfparserswitch#1{\def\pgf@parser@state{#1}} + + + + +% Defines an action to be taken in a state for some symbol +% +% #1 = parser +% #2 = state +% #3 = symbol text (result of saying \meaning on the symbol) +% #4 = action +% +% Description: +% +% When the parser encounters #3 while being in state #2, then code #4 +% is executed. +% +% When #2 is set to the special text "all", then the symbol is handled +% in all states by #4, except when a state defines something special +% for this symbol + +\def\pgfparserdef#1#2#3#4{% + \expandafter\def\csname pgf@parser@a@#1@#2@#3\endcsname{#4} +} + + +\endinput diff --git a/Master/texmf-dist/tex/generic/pgf/modules/pgfmoduleplot.code.tex b/Master/texmf-dist/tex/generic/pgf/modules/pgfmoduleplot.code.tex index 5e7a703fd37..ea55ca8517b 100644 --- a/Master/texmf-dist/tex/generic/pgf/modules/pgfmoduleplot.code.tex +++ b/Master/texmf-dist/tex/generic/pgf/modules/pgfmoduleplot.code.tex @@ -7,7 +7,7 @@ % % See the file doc/generic/pgf/licenses/LICENSE for more details. -\ProvidesFileRCS $Header: /cvsroot/pgf/pgf/generic/pgf/modules/pgfmoduleplot.code.tex,v 1.1 2008/01/15 10:27:34 tantau Exp $ +\ProvidesFileRCS $Header: /cvsroot/pgf/pgf/generic/pgf/modules/pgfmoduleplot.code.tex,v 1.8 2010/10/22 17:34:17 ludewich Exp $ % PGF's plotting interface works as follows: @@ -33,7 +33,7 @@ % \pgfplotstreamend % % By themselves, the \pgfplotstreamxxxx commands do not do anything by -% default. Rather, the ``use'' such a stream, you must first install a +% default. Rather, to ``use'' such a stream, you must first install a % stream handler. For example, the ``lineto'' handler will simply % translate every \pgfplotstreampoint into a \pgfpathlineto. % @@ -118,6 +118,29 @@ +% This handler turns creates a series of lineto commands, with the +% last command being a closepath, resulting in a closed path. +% +% Example: +% +% \pgfplothandlerpolygon +% \pgfplotxyfile{mytable} + +\def\pgfplothandlerpolygon{% + \def\pgf@plotstreamstart{% + \global\let\pgf@plotstreampoint=\pgf@plot@line@handler@close% + \global\let\pgf@plotstreamspecial=\pgfutil@gobble% + \global\let\pgf@plotstreamend=\pgfpathclose% + }% +} + +\def\pgf@plot@line@handler@close#1{% + \pgfpathmoveto{#1}% + \global\let\pgf@plotstreampoint=\pgfpathlineto% +} + + + % More handlers are defined in pgflibraryplothandlers @@ -187,8 +210,8 @@ \def\pgfplotxyfile#1{% \begingroup% \pgfplotstreamstart% - \openin1=#1 - \ifeof1 + \openin\r@pgf@reada=#1 + \ifeof\r@pgf@reada \PackageWarning{pgf}{Plot data file `#1' not found.} \else \catcode`\#=14 @@ -201,7 +224,7 @@ \let\pgf@savedpar=\par% \def\pgf@partext{\par} \def\pgf@readxyfile{% - \read1 to \pgf@temp% + \pgfutil@read\r@pgf@reada to \pgf@temp% \let\par=\pgf@savedpar% \edef\pgf@temp{\pgf@temp}% \ifx\pgf@temp\pgfutil@empty% @@ -209,7 +232,7 @@ \else% \expandafter\pgf@parsexyline\pgf@temp\pgf@stop% \fi\fi% - \ifeof1\else\expandafter\pgf@readxyfile\fi% + \ifeof\r@pgf@reada\else\expandafter\pgf@readxyfile\fi% } \def\pgf@parsexyline#1 #2 #3\pgf@stop{% @@ -236,8 +259,8 @@ \def\pgfplotxyzfile#1{% \begingroup% \pgfplotstreamstart% - \openin1=#1 - \ifeof1 + \openin\r@pgf@reada=#1 + \ifeof\r@pgf@reada \PackageWarning{pgf}{Plot data file `#1' not found.} \else \catcode`\#=14 @@ -248,13 +271,13 @@ } \def\pgf@readxyzfile{% - \read1 to \pgf@temp% + \pgfutil@read\r@pgf@reada to \pgf@temp% \ifx\pgf@temp\pgfutil@empty% \else\ifx\pgf@temp\pgf@partext% \else% \expandafter\pgf@parsexyzline\pgf@temp\pgf@stop% \fi\fi% - \ifeof1\else\expandafter\pgf@readxyzfile\fi% + \ifeof\r@pgf@reada\else\expandafter\pgf@readxyzfile\fi% } \def\pgf@parsexyzline#1 #2 #3 #4\pgf@stop{% @@ -285,38 +308,58 @@ { \catcode`\%=12 \catcode`\"=12 - \xdef\pgf@gnuplot@head#1{set terminal table; set output "#1.table"; set format "%.5f"} + \xdef\pgf@gnuplot@head{set table \noexpand\pgf@plottablefile@quoted; set format "%.5f"} } -\newwrite\pgf@plotwrite +\let\pgf@plotwrite=\w@pgf@writea \newif\ifpgf@resample@plot \def\pgfplotgnuplot{\pgfutil@ifnextchar[{\pgf@plotgnuplot}{\pgf@plotgnuplot[\jobname]}}%} \def\pgf@plotgnuplot[#1]#2{% \pgf@resample@plottrue% + \pgfutilpreparefilename{#1.gnuplot}% + \let\pgf@plotgnuplotfile=\pgfretval + \pgfutilpreparefilename{#1.table}% + \let\pgf@plottablefile=\pgfretval + \let\pgf@plottablefile@quoted=\pgfretvalquoted % Check, whether it is up-to-date - \openin\pgfutil@inputcheck=#1.gnuplot + \openin\pgfutil@inputcheck=\pgf@plotgnuplotfile\relax \ifeof\pgfutil@inputcheck% \else% - \read\pgfutil@inputcheck to\pgf@temp% ignored - \read\pgfutil@inputcheck to\pgf@plot@line% + \pgfutil@read\pgfutil@inputcheck to\pgf@temp% ignored + \pgfutil@read\pgfutil@inputcheck to\pgf@plot@line% + \closein\pgfutil@inputcheck \edef\pgf@plot@code{#2\space}% \ifx\pgf@plot@code\pgf@plot@line% - \openin\pgfutil@inputcheck=#1.table + \openin\pgfutil@inputcheck=\pgfretval\relax \ifeof\pgfutil@inputcheck% \else% + \closein\pgfutil@inputcheck \pgf@resample@plotfalse% \fi% \fi% \fi \ifpgf@resample@plot% - \immediate\openout\pgf@plotwrite=#1.gnuplot - \immediate\write\pgf@plotwrite{\pgf@gnuplot@head{#1}}% - \immediate\write\pgf@plotwrite{#2}% + \immediate\openout\pgf@plotwrite=\pgf@plotgnuplotfile\relax + \immediate\pgfutil@write\pgf@plotwrite{\pgf@gnuplot@head}% + \immediate\pgfutil@write\pgf@plotwrite{#2}% \immediate\closeout\pgf@plotwrite% - \immediate\write18{gnuplot #1.gnuplot} + \immediate\pgfutil@write18{gnuplot \pgf@plotgnuplotfile}% + \fi% + % temporarily redefine \pgf@parsexyline + \let\pgf@savedparsexyline=\pgf@parsexyline% + \let\pgf@parsexyline=\pgf@parsegnuplotxyline% + \pgfplotxyfile{\pgf@plottablefile}% + \let\pgf@parsexyline=\pgf@savedparsexyline% +} + +\def\pgf@parsegnuplotxyline#1 #2 #3\pgf@stop{% + \edef\pgf@xyline@flag@val{#3}% + \edef\pgf@xyline@flag@undef{u\space}% + \ifx\pgf@xyline@flag@val\pgf@xyline@flag@undef% + \else% + \pgfplotstreampoint{\pgfpointxy{#1}{#2}}% \fi% - \pgfplotxyfile{#1.table} } diff --git a/Master/texmf-dist/tex/generic/pgf/modules/pgfmoduleshapes.code.tex b/Master/texmf-dist/tex/generic/pgf/modules/pgfmoduleshapes.code.tex index 63f6bf5be9b..da75b3e2e43 100644 --- a/Master/texmf-dist/tex/generic/pgf/modules/pgfmoduleshapes.code.tex +++ b/Master/texmf-dist/tex/generic/pgf/modules/pgfmoduleshapes.code.tex @@ -7,7 +7,7 @@ % % See the file doc/generic/pgf/licenses/LICENSE for more details. -\ProvidesFileRCS $Header: /cvsroot/pgf/pgf/generic/pgf/modules/pgfmoduleshapes.code.tex,v 1.4 2008/02/13 15:10:06 tantau Exp $ +\ProvidesFileRCS $Header: /cvsroot/pgf/pgf/generic/pgf/modules/pgfmoduleshapes.code.tex,v 1.13 2010/09/09 13:52:57 cjorssen Exp $ @@ -43,6 +43,7 @@ {% \let\pgf@sh@savedmacros=\pgfutil@empty% MW \let\pgf@sh@savedpoints=\pgfutil@empty% + \def\shape@name{#1}% CJ \csname pgf@sh@s@#1\endcsname% \pgf@sh@savedpoints% \pgf@sh@savedmacros% MW @@ -52,20 +53,30 @@ \pgf@y=-\pgf@y% }% \expandafter\pgfsavepgf@process\csname pgf@sh@sa@#3\endcsname{% - \pgf@sh@reanchor{#1}{#2}% + \pgf@sh@reanchor{#1}{#2}% FIXME : this is double work! }% % Save the saved points and the transformation matrix - \edef\pgf@test{#3}% - \ifx\pgf@test\pgfutil@empty% + \edef\pgf@node@name{#3}% + \ifx\pgf@positionnodelater@macro\relax% \else% - \expandafter\xdef\csname pgf@sh@ns@#3\endcsname{#1}% - \edef\pgf@sh@@temp{\noexpand\gdef\expandafter\noexpand\csname pgf@sh@np@#3\endcsname}% + % Rename node + \edef\pgf@node@name{not yet positioned@\pgf@node@name}% + % Interrupt bounding box! + \pgfinterruptboundingbox% + % Put everything in our box: + \setbox\pgfpositionnodelaterbox=\hbox\bgroup% + % + \fi% + \ifx\pgf@node@name\pgfutil@empty% + \else% + \expandafter\xdef\csname pgf@sh@ns@\pgf@node@name\endcsname{#1}% + \edef\pgf@sh@@temp{\noexpand\gdef\expandafter\noexpand\csname pgf@sh@np@\pgf@node@name\endcsname}% \expandafter\pgf@sh@@temp\expandafter{\pgf@sh@savedpoints}% - \edef\pgf@sh@@temp{\noexpand\gdef\expandafter\noexpand\csname pgf@sh@ma@#3\endcsname}% MW + \edef\pgf@sh@@temp{\noexpand\gdef\expandafter\noexpand\csname pgf@sh@ma@\pgf@node@name\endcsname}% MW \expandafter\pgf@sh@@temp\expandafter{\pgf@sh@savedmacros}% MW \pgfgettransform\pgf@temp - \expandafter\xdef\csname pgf@sh@nt@#3\endcsname{\pgf@temp}% - \expandafter\xdef\csname pgf@sh@pi@#3\endcsname{\pgfpictureid}% + \expandafter\xdef\csname pgf@sh@nt@\pgf@node@name\endcsname{\pgf@temp}% + \expandafter\xdef\csname pgf@sh@pi@\pgf@node@name\endcsname{\pgfpictureid}% \fi% \pgfutil@ifundefined{pgf@sh@bbg@#1}{} {{\pgfscope\csname pgf@sh@bbg@#1\endcsname\endpgfscope}}% @@ -87,7 +98,18 @@ {\csname pgf@sh@fg@#1\endcsname#4}% \pgfutil@ifundefined{pgf@sh@ffg@#1}{}% {{\pgfscope\csname pgf@sh@ffg@#1\endcsname\endpgfscope}}% - \pgf@nodecallback{#3}% + \ifx\pgf@positionnodelater@macro\relax% + \expandafter\pgf@nodecallback\expandafter{\pgf@node@name}% + \else% + \egroup% Close box + \edef\pgfpositionnodelaterminx{\the\pgf@picminx}% + \edef\pgfpositionnodelaterminy{\the\pgf@picminy}% + \edef\pgfpositionnodelatermaxx{\the\pgf@picmaxx}% + \edef\pgfpositionnodelatermaxy{\the\pgf@picmaxy}% + \let\pgfpositionnodelatername=\pgf@node@name% + \pgf@positionnodelater@macro% + \endpgfinterruptboundingbox% + \fi% }% }% } @@ -144,6 +166,109 @@ } } + + +% Create a node that is positioned later +% +% #1 = macro to be called after the next node has been created +% +% Description: +% +% You can use this command to create a node that is "positioned +% later". The idea is the following: Normally, when a node is created +% using a command like \pgfnode, the node is immediately inserted into +% the current picture. In particular, you have no chance to change the +% position of a created node after it has been create. +% +% Using \pgfpositionnodelater, you can change the default +% behaviour. This command is not a replacement for \pgfnode, but is +% called before such a command and will cause the following to happen: +% The node is created, but not inserted into the picture. Instead, it +% is stored in the box \pgfpositionnodelaterbox. Furthermore, the node +% is not relevant for the picture's bounding box, but a bounding box +% for the node is computed and stored in the macros +% \pgfpositionnodelaterboundboxminx to +% \pgfpositionnodelaterboundboxmaxy. Finally, the +% macro #1 is called with the following macros setup: +% +% \pgfpositionnodelaterbox +% A box register (box 0 by default) that stores the node's paths and +% texts. You should move the contents of this box to a box of your +% choice. +% +% \pgfpositionnodelatername +% The name of the just-created-node. This name will be the +% originally "desired" name of the box plus the prefix "not yet +% positioned box@". +% +% \pgfpositionnodelaterminx +% \pgfpositionnodelatermaxx +% \pgfpositionnodelaterminy +% \pgfpositionnodelatermaxy +% These four macros store the bounding box as dimensions that are +% guarenteed to end with "pt". +% +% By setting #1 to \relax (which is the default), you can switch off +% the whole mechanism +% +% Once a late node has been created, you can add arbitrary code in the +% same picture. Then, at some later point, you call +% \pgfpositionnodenow to finally position the node at a given position. +% +% When \pgfpositionnodenow is called, the macros mentioned above +% should have the exact same values they had when #1 is called. + +\def\pgfpositionnodelater#1{\let\pgf@positionnodelater@macro=#1\relax} +\pgfpositionnodelater{\relax} +\def\pgfpositionnodelaterbox{0} + + +% Position a node that has been scheduled for later insertion +% +% #1 = position in the picture, where the original anchor should go, +% now +% +% Description: +% +% This command works in concert with \pgfpositionnodelater, see the +% description there. When \pgfpositionnodenow is called, the macros +% \pgfpositionnodelaterbox and so one should be set to the values they +% had when the macro given to \pgfpositionnodelater was called. Then, +% the box described by these macros will be inserted into the picture +% at the position given #1. More precisely, the original node will +% have been positioned such that the anchor given upon invocation is +% at (0,0) and the node is now shifted by #1 before being inserted +% into the actual picture. + +\def\pgfpositionnodenow#1{% + {% + \pgfpointtransformed{#1}% + \edef\pgf@temp@shift{\noexpand\pgfqpoint{\the\pgf@x}{\the\pgf@y}} + \pgftransformreset% + \pgftransformshift{\pgf@temp@shift}% + \setbox\pgfpositionnodelaterbox=\hbox{\pgfsys@beginpicture\box\pgfpositionnodelaterbox\pgfsys@endpicture}% + \pgfqboxsynced{\pgfpositionnodelaterbox}% + \pgf@shift@node{\pgfpositionnodelatername}{\pgf@temp@shift}% + % Bounding box update... + \pgfpointtransformed{\pgfqpoint{\pgfpositionnodelaterminx}{\pgfpositionnodelaterminy}}% + \pgf@protocolsizes{\pgf@x}{\pgf@y} + \pgfpointtransformed{\pgfqpoint{\pgfpositionnodelatermaxx}{\pgfpositionnodelatermaxy}}% + \pgf@protocolsizes{\pgf@x}{\pgf@y} + % Naming and callbacks + \expandafter\pgfpositionnodenow@rename\pgfpositionnodelatername\relax% + }% +} + +\def\pgfpositionnodenow@rename not yet positioned@#1\relax{% + \pgfnoderename{#1}{not yet positioned@#1} + \pgf@nodecallback{#1}% +} + + + + + + % Alias a node % % #1 = new node name @@ -165,12 +290,68 @@ \pgf@node@gnamelet{pgf@sh@nt@#1}{pgf@sh@nt@#2}% \pgf@node@gnamelet{pgf@sh@pi@#1}{pgf@sh@pi@#2}% \pgf@node@gnamelet{pgf@sh@ma@#1}{pgf@sh@ma@#2}% + \pgf@nodecallback{#1}% } \def\pgf@node@gnamelet#1#2{% \expandafter\let\expandafter\pgf@temp\csname #2\endcsname% \expandafter\global\expandafter\let\csname #1\endcsname=\pgf@temp% } +% Rename a node +% +% #1 = new name +% #2 = old name +% +% Description: +% +% Renames a node. This is like an alias, only the memory used for the +% old name is freed. + +\def\pgfnoderename#1#2{% + \pgfnodealias{#1}{#2}% + \expandafter\global\expandafter\let\csname pgf@sh@ns@#2\endcsname\relax + \expandafter\global\expandafter\let\csname pgf@sh@np@#2\endcsname\relax + \expandafter\global\expandafter\let\csname pgf@sh@nt@#2\endcsname\relax + \expandafter\global\expandafter\let\csname pgf@sh@pi@#2\endcsname\relax + \expandafter\global\expandafter\let\csname pgf@sh@ma@#2\endcsname\relax +} + + +% Quickly create a coordinate node +% +% #1 = name +% #2 = coordinate +% +% Description: +% +% Creates a node of shape coordinate. The following have the same +% effect, only the second is much faster: +% +% { \pgftransformshift{\pgfpoint{1cm}{2cm} \pgfnode{coordinate}{center}{}{foo}{} } +% \pgfcoordinate{foo}{\pgfpoint{1cm}{2cm}} + +\def\pgfcoordinate#1#2{% + \edef\pgf@temp{#1}% + \ifx\pgf@temp\pgfutil@empty% do nothing + \else% + \pgf@process{\pgfpointtransformed{#2}}% + \expandafter\gdef\csname pgf@sh@ns@#1\endcsname{coordinate}% + \expandafter\xdef\csname pgf@sh@np@#1\endcsname{% + \noexpand\def\noexpand\centerpoint{\noexpand\pgfqpoint{\the\pgf@x}{\the\pgf@y}}% + } + \expandafter\gdef\csname pgf@sh@nt@#1\endcsname{{1}{0}{0}{1}{0pt}{0pt}}% + \expandafter\global\expandafter\let\csname pgf@sh@ma@#1\endcsname\pgfutil@empty% + \expandafter\gdef\csname pgf@sh@pi@#1\endcsname{\pgfpictureid}% + \fi% +} + +\def\pgf@sh@redeferredanchor#1#2{% CJ + \expandafter\gdef\csname pgf@anchor@\shape@name @#1\endcsname{#2}}% CJ + + + + + \def\pgf@sh@resavedanchor#1#2{% \pgf@process{#2}% @@ -191,14 +372,12 @@ \pgf@sh@marshal% } -% MW -\newtoks\toks@savedmacro \def\pgf@sh@resavedmacro#1#2{% \let#1\pgfutil@empty% \def\addtosavedmacro##1{% \expandafter\def\expandafter\pgf@sh@addtomacro@temp\expandafter{#1\noexpand\def\noexpand##1{##1}}% - \expandafter\toks@savedmacro\expandafter{\pgf@sh@addtomacro@temp}% - \expandafter\def\expandafter#1\expandafter{\the\toks@savedmacro}% + {\expandafter\pgfutil@toks@\expandafter{\pgf@sh@addtomacro@temp}\expandafter}% + \expandafter\def\expandafter#1\expandafter{\the\pgfutil@toks@}% }% #2\relax% \edef\pgf@sh@marshal{% @@ -212,12 +391,31 @@ \def\pgf@sh@reanchor#1#2{% \pgfutil@ifundefined{pgf@anchor@#1@#2}% {% - \pgfmathsetcounter{pgf@counta}{#2}% - \csname pgf@anchor@#1@border\endcsname{\pgfqpointpolar{\c@pgf@counta}{1pt}}% + \pgfutil@ifundefined{pgf@anchor@generic@#2}{% + \pgfmathsetcounter{pgf@counta}{#2}% + \csname pgf@anchor@#1@border\endcsname{\pgfqpointpolar{\c@pgf@counta}{1pt}}% + }{% + \csname pgf@anchor@generic@#2\endcsname{#1}% + }% }% {\csname pgf@anchor@#1@#2\endcsname}% } +% Defines a generic anchor, i.e. one which gets the associated shape +% as first argument. +% +% #1: the anchor name. +% #2: the code of the anchor. It may depend upon '##1', the shape's +% name. +% +% The anchor will be defined locally in the current TeX scope. +% +% If the anchor will be referenced later by \pgfpointanchor, the macro \pgfreferencednodename +% can be used to query the referenced node's name. +% This macro is not defined during node creation. +\def\pgfdeclaregenericanchor#1#2{% + \expandafter\def\csname pgf@anchor@generic@#1\endcsname##1{#2}% +}% % Retrieves an anchor of a shape @@ -241,6 +439,7 @@ \pgfpointorigin}% {% \pgf@process{% + \edef\pgfreferencednodename{#1}% for use inside of anchors. % MW install special macros \csname pgf@sh@ma@#1\endcsname% MW % install special coordinates @@ -305,6 +504,7 @@ \pgfpointorigin}% {% \pgf@process{% + \edef\pgfreferencednodename{#1}% for use inside of anchors. % MW install special macros \csname pgf@sh@ma@#1\endcsname% MW % install special coordinates @@ -409,6 +609,7 @@ \let\savedanchor=\pgf@sh@savedanchor \let\saveddimen=\pgf@sh@saveddimen \let\savedmacro=\pgf@sh@savedmacro% MW + \let\deferredanchor=\pgf@sh@deferredanchor% CJ \let\anchor=\pgf@sh@anchor \let\anchorborder=\pgf@sh@anchorborder \let\behindbackgroundpath=\pgf@sh@behindbgpath @@ -443,6 +644,9 @@ \def\pgf@sh@savedmacro#1#2{% MW \expandafter\pgfutil@g@addto@macro\csname pgf@sh@s@\shape@name\endcsname{\pgf@sh@resavedmacro{#1}{#2}}}% MW \def\pgf@sh@anchor#1#2{\expandafter\gdef\csname pgf@anchor@\shape@name @#1\endcsname{#2}} +\def\pgf@sh@deferredanchor#1#2{% CJ + \expandafter\pgfutil@g@addto@macro + \csname pgf@sh@s@\shape@name\endcsname{\pgf@sh@redeferredanchor{#1}{#2}}}% CJ \def\pgf@sh@anchorborder#1{\expandafter\gdef\csname pgf@anchor@\shape@name @border\endcsname##1{\pgf@process{##1}#1}} \long\def\pgf@sh@behindbgpath#1{\expandafter\gdef\csname pgf@sh@bbg@\shape@name\endcsname{#1}} \long\def\pgf@sh@bgpath#1{\expandafter\gdef\csname pgf@sh@bg@\shape@name\endcsname{#1}} diff --git a/Master/texmf-dist/tex/generic/pgf/modules/pgfmodulesorting.code.tex b/Master/texmf-dist/tex/generic/pgf/modules/pgfmodulesorting.code.tex new file mode 100644 index 00000000000..b85fde14501 --- /dev/null +++ b/Master/texmf-dist/tex/generic/pgf/modules/pgfmodulesorting.code.tex @@ -0,0 +1,69 @@ +% Copyright 2008 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/modules/pgfmodulesorting.code.tex,v 1.1 2008/11/12 23:39:37 tantau Exp $ + +% +% This file defines commands for sorting data. This is useful for 3d plots, +% but also for drawing things in the correct order. +% + + +\newcount\pgfsortingbuckets + + +% Init the sorting +% +% #1 = number of buckets +% +% Description: +% +% This macro inits a sorting. At any time there can be only one active +% sorting. When you init the sorting, #1 should be a number of +% buckets. You can then call \pgfsortinginsert to insert code into the +% buckets. Once you are done, calling \pgfsortingexecute will execute +% first the code in buckets 0, then the code in bucket 1, and so on to +% bucket number #1-1. +% +\def\pgfsortinginit#1{ + \pgfsortingbuckets#1\relax% + \c@pgf@counta=0\relax + \pgfutil@loop + \ifnum\c@pgf@counta<\c@pgf@countb\relax% + \expandafter\global\expandafter\let\csname pgf@sort@\the\c@pgf@counta\endcsname\pgfutil@empty% + \advance\c@pgf@counta by1\relax% + \pgfutil@repeat +} + +% Insert code into some bucket +% +% #1 = the bucket +% #2 = the code +% +\def\pgfsortinginsert#1#1{ + \expandafter\let\expandafter\pgf@temp\csname pgf@lib@sort@#1\endcsname% + \expandafter\def\expandafter\pgf@temp\expandafter{\pgf@temp#2}% + \expandafter\global\expandafter\let\csname pgf@lib@sort@\the\c@pgf@counta\endcsname\pgf@temp% +} + + +% After all code has been inserted into the buckets, you can call +% this method to execute the code in the order of the buckets. +\def\pgfsortingexecute{ + \c@pgf@countb=\pgfoovalueof{buckets}\relax + \c@pgf@counta=0\relax + \pgfutil@loop + \ifnum\c@pgf@counta<\c@pgf@countb\relax% + \csname pgf@lib@sort@\the\c@pgf@counta\endcsname% + \advance\c@pgf@counta by1\relax% + \pgfutil@repeat +} + + +\endinput |