diff options
Diffstat (limited to 'Master/texmf-dist/doc/generic/pgf/text-en/pgfmanual-en-base-arrows.tex')
-rw-r--r-- | Master/texmf-dist/doc/generic/pgf/text-en/pgfmanual-en-base-arrows.tex | 1451 |
1 files changed, 780 insertions, 671 deletions
diff --git a/Master/texmf-dist/doc/generic/pgf/text-en/pgfmanual-en-base-arrows.tex b/Master/texmf-dist/doc/generic/pgf/text-en/pgfmanual-en-base-arrows.tex index aac739b9d1f..15926efe567 100644 --- a/Master/texmf-dist/doc/generic/pgf/text-en/pgfmanual-en-base-arrows.tex +++ b/Master/texmf-dist/doc/generic/pgf/text-en/pgfmanual-en-base-arrows.tex @@ -1,4 +1,4 @@ -% Copyright 2006 by Till Tantau +% Copyright 2013 by Till Tantau % % This file may be distributed and/or modified % @@ -8,54 +8,30 @@ % See the file doc/generic/pgf/licenses/LICENSE for more details. -\section{Arrow Tips} +\section{Defining New Arrow Tip Kinds} \label{section-arrows} \subsection{Overview} -\subsubsection{When Does PGF Draw Arrow Tips?} - -\pgfname\ offers an interface for placing \emph{arrow tips} at the end -of lines. The interface works as follows: - -\begin{enumerate} -\item - You (or someone else) assigns a name to a certain kind of arrow - tips. For example, the - arrow tip |latex| is the arrow tip used by the standard \LaTeX\ - picture environment; the arrow tip |to| looks like the tip of the - arrow in \TeX's |\to| command; and so on. - - This is done once at the beginning of the document. -\item - Inside some picture, at some point you specify that in the current - scope from now on you would like tips of, say, kind |to| to be added - at the end and/or beginning of all paths. - - When an arrow kind has been installed and when \pgfname\ is about to - stroke a path, the following things happen: - \begin{enumerate} - \item - The beginning and/or end of the path is shortened appropriately. - \item - The path is stroked. - \item - The arrow tip is drawn at the beginning and/or end of the path, - appropriately rotated and appropriately resized. - \end{enumerate} -\end{enumerate} - -In the above description, there are a number of ``appropriately.'' -The exact details are not quite trivial and described later on. - - -\subsubsection{Meta-Arrow Tips} - -In \pgfname, arrows are ``meta-arrows'' in the same way that fonts in -\TeX\ are ``meta-fonts.'' When a meta-arrow is resized, it is not -simply scaled, but a possibly complicated transformation is applied to -the size. +In present section we have a look at how you can define new arrow tips +for use in \pgfname. The low-level commands for selecting which arrow +tips are to be used have already been described in +Section~\ref{section-tips}, the general syntax rules for using arrows +are detailed in Section~\ref{section-tikz-arrows}. Although +Section~\ref{section-tikz-arrows} describes the use of arrows in +\tikzname, in reality, \tikzname\ itself does not actually do anything +about arrow tips; all of the functionality is implemented on the +\pgfname\ level in the commands described in +Section~\ref{section-tikz-arrows}. Indeed, even the |/.tip| key +handler described in Section~\ref{section-tikz-arrows} is actually +implemented on the \pgfname\ layer. + +What has \emph{not} yet been covered is how you can actually define a +complete new arrow tip. In \pgfname, arrows are ``meta-arrows'' in the +same way that fonts in \TeX\ are ``meta-fonts.'' When a meta-arrow is +resized, it is not simply scaled, but a possibly complicated +transformation is applied to the size. A meta-font is not one particular font at a specific size with a specific stroke width (and with a large number of other parameters @@ -73,84 +49,42 @@ text was scaled down, while the second text is a ``normal'' tiny text. The second text is easier to read. \pgfname's meta-arrows work in a similar fashion: The shape of an -arrow tip can vary according to the line width of the arrow tip is -used. Thus, an arrow tip drawn at a line width of 5pt will typically -\emph{not} be five times as large as an arrow tip of line width -1pt. Instead, the size of the arrow will get bigger only slowly as the -line width increases. +arrow tip can vary according to a great number of parameters, the line +width of the arrow tip being one of them. Thus, an arrow tip drawn at +a line width of 5pt will typically \emph{not} be five times as large +as an arrow tip of line width 1pt. Instead, the size of the arrow will +get bigger only slowly as the line width increases. -To appreciate the difference, here are the |latex| and |to| arrows, as -drawn by \pgfname\ at four different sizes: +To appreciate the difference, here are the |Latex| and +|Classical TikZ Rightarrow| arrows, as drawn by \pgfname\ at four different sizes: \medskip -\begin{tikzpicture} - \draw[-latex,line width=0.1pt] (0pt,0ex) -- +(3,0) node[thin,right] {line width is 0.1pt}; - \draw[-latex,line width=0.4pt] (0pt,-2em) -- +(3,0) node[thin,right] {line width is 0.4pt}; - \draw[-latex,line width=1.2pt] (0pt,-4em) -- +(3,0) node[thin,right] {line width is 1.2pt}; - \draw[-latex,line width=5pt] (0pt,-6em) -- +(3,0) node[thin,right] {line width is 5pt}; - - \draw[-to,line width=0.1pt] (6cm,0ex) -- +(3,0) node[thin,right] {line width is 0.1pt}; - \draw[-to,line width=0.4pt] (6cm,-2em) -- +(3,0) node[thin,right] {line width is 0.4pt}; - \draw[-to,line width=1.2pt] (6cm,-4em) -- +(3,0) node[thin,right] {line width is 1.2pt}; - \draw[-to,line width=5pt] (6cm,-6em) -- +(3,0) node[thin,right] {line width is 5pt}; +\begin{tikzpicture}[1/.tip=Latex, 2/.tip=Classical TikZ Rightarrow] + \draw[-1, line width=0.1pt] (0pt,0ex) -- +(3,0) node[thin,right] {line width is 0.1pt}; + \draw[-1, line width=0.4pt] (0pt,-2em) -- +(3,0) node[thin,right] {line width is 0.4pt}; + \draw[-1, line width=1.2pt] (0pt,-4em) -- +(3,0) node[thin,right] {line width is 1.2pt}; + \draw[-1, line width=5pt] (0pt,-6em) -- +(3,0) node[thin,right] {line width is 5pt}; + + \draw[-2, line width=0.1pt] (6cm,0ex) -- +(3,0) node[thin,right] {line width is 0.1pt}; + \draw[-2, line width=0.4pt] (6cm,-2em) -- +(3,0) node[thin,right] {line width is 0.4pt}; + \draw[-2, line width=1.2pt] (6cm,-4em) -- +(3,0) node[thin,right] {line width is 1.2pt}; + \draw[-2, line width=5pt] (6cm,-6em) -- +(3,0) node[thin,right] {line width is 5pt}; \end{tikzpicture} \medskip -Here, by comparison, is the same arrow when it is simply ``resized'' -(as done by some programs): - -\pgfarrowsdeclare{bad latex}{bad latex} -{ - \pgfarrowsleftextend{-1\pgflinewidth} - \pgfarrowsrightextend{9\pgflinewidth} -} -{ - \pgfpathmoveto{\pgfpoint{9\pgflinewidth}{0pt}} - \pgfpathcurveto - {\pgfpoint{6.3333\pgflinewidth}{.5\pgflinewidth}} - {\pgfpoint{2\pgflinewidth}{2\pgflinewidth}} - {\pgfpoint{-1\pgflinewidth}{3.75\pgflinewidth}} - \pgfpathlineto{\pgfpoint{-1\pgflinewidth}{-3.75\pgflinewidth}} - \pgfpathcurveto - {\pgfpoint{2\pgflinewidth}{-2\pgflinewidth}} - {\pgfpoint{6.3333\pgflinewidth}{-.5\pgflinewidth}} - {\pgfpoint{9\pgflinewidth}{0pt}} - \pgfusepathqfill -} - -\pgfarrowsdeclare{bad to}{bad to} -{ - \pgfarrowsleftextend{-2\pgflinewidth} - \pgfarrowsrightextend{\pgflinewidth} -} -{ - \pgfsetlinewidth{0.8\pgflinewidth} - \pgfsetdash{}{0pt} - \pgfsetroundcap - \pgfsetroundjoin - \pgfpathmoveto{\pgfpoint{-3\pgflinewidth}{4\pgflinewidth}} - \pgfpathcurveto - {\pgfpoint{-2.75\pgflinewidth}{2.5\pgflinewidth}} - {\pgfpoint{0pt}{0.25\pgflinewidth}} - {\pgfpoint{0.75\pgflinewidth}{0pt}} - \pgfpathcurveto - {\pgfpoint{0pt}{-0.25\pgflinewidth}} - {\pgfpoint{-2.75\pgflinewidth}{-2.5\pgflinewidth}} - {\pgfpoint{-3\pgflinewidth}{-4\pgflinewidth}} - \pgfusepathqstroke -} +Here, by comparison, are the same arrows when they are simply ``resized'': \medskip -\begin{tikzpicture} - \draw[-bad latex,line width=0.1pt] (0pt,0ex) -- +(3,0) node[thin,right] {line width is 0.1pt}; - \draw[-bad latex,line width=0.4pt] (0pt,-2em) -- +(3,0) node[thin,right] {line width is 0.4pt}; - \draw[-bad latex,line width=1.2pt] (0pt,-4em) -- +(3,0) node[thin,right] {line width is 1.2pt}; - \draw[-bad latex,line width=5pt] (0pt,-6em) -- +(3,0) node[thin,right] {line width is 5pt}; - - \draw[-bad to,line width=0.1pt] (6cm,0ex) -- +(3,0) node[thin,right] {line width is 0.1pt}; - \draw[-bad to,line width=0.4pt] (6cm,-2em) -- +(3,0) node[thin,right] {line width is 0.4pt}; - \draw[-bad to,line width=1.2pt] (6cm,-4em) -- +(3,0) node[thin,right] {line width is 1.2pt}; - \draw[-bad to,line width=5pt] (6cm,-6em) -- +(3,0) node[thin,right] {line width is 5pt}; +\begin{tikzpicture}[1/.tip=Latex, 2/.tip=Classical TikZ Rightarrow] + \draw[-{1[length=1pt]}, line width=0.1pt] (0pt,0ex) -- +(3,0) node[thin,right] {line width is 0.1pt}; + \draw[-{1[length=4pt]}, line width=0.4pt] (0pt,-2em) -- +(3,0) node[thin,right] {line width is 0.4pt}; + \draw[-{1[length=12pt]}, line width=1.2pt] (0pt,-4em) -- +(3,0) node[thin,right] {line width is 1.2pt}; + \draw[-{1[length=32pt]}, line width=5pt] (0pt,-6em) -- +(3,0) node[thin,right] {line width is 5pt}; + + \draw[-{2[length=0.455pt]}, line width=0.1pt] (6cm,0ex) -- +(3,0) node[thin,right] {line width is 0.1pt}; + \draw[-{2[length=1.82pt]}, line width=0.4pt] (6cm,-2em) -- +(3,0) node[thin,right] {line width is 0.4pt}; + \draw[-{2[length=5.46pt]}, line width=1.2pt] (6cm,-4em) -- +(3,0) node[thin,right] {line width is 1.2pt}; + \draw[-{2[length=14.56pt]}, line width=5pt] (6cm,-6em) -- +(3,0) node[thin,right] {line width is 5pt}; \end{tikzpicture} \bigskip @@ -163,632 +97,807 @@ appearance of an arrow tip. In particular, the width of the inner line tips as well as other options that are specific to the arrow tip. +\subsection{Terminology} +\label{section-arrow-terminology} -\subsection{Declaring an Arrow Tip Kind} - -To declare an arrow kind ``from scratch,'' the following command is -used: +Before we have a look at the exact commands used for defining arrow +tips, we need to fix some terminology. Consider the following drawing +of an arrow tip where the arrow tip is drawn transparently so that we +can see what is ``happening behind it'': -\begin{command}{\pgfarrowsdeclare\marg{start name}\marg{end - name}\marg{extend code}\marg{arrow tip code}} - This command declares a new arrow kind. An arrow kind has two names, - which will typically be the same. When the arrow tip needs to be - drawn, the \meta{arrow tip code} will be invoked, but the canvas - transformation is setup beforehand to a rotation such that when an - arrow tip pointing right is specified, the arrow tip that is - actually drawn points in the direction of the line. +\begin{tikzpicture} + \draw [red!50, ,line width=1cm] (0,0) -- (4,0); + \path [tips, opacity=.25,line width=1cm, -{Stealth[black,line width=0pt,length=4cm, width=4cm, inset=1cm]}] (0,0) -- (6,0); + + \draw [->,thick] (1,0) -- (8,0) node [right] {$x$-axis}; + \draw [->,thick] (5,-2.25) -- (5,2.25) node [above] {$y$-axis}; + + \foreach \i in {-3,-2,-1,1,2} \draw (\i+5,-1mm) -- (\i+5,1mm) node [above] {\small$\i$}; + \foreach \i in {-2,-1,1,2} \draw (49mm,\i) -- (51mm,\i) node [right] {\small$\i$};; +\end{tikzpicture} - \medskip - \textbf{Naming the arrow kind.} - The \meta{start name} is the name - used for the arrow tip when it is at the start of a path, the \meta{end - name} is the name used at the end of a path. For example, the - arrow kind that looks like a parenthesis has the \meta{start - name} |(| and the \meta{end name} |)| so that you can say - |\pgfsetarrows{(-)}| to specify that you want parenthesis arrows and - both ends. - - The \meta{end name} and \meta{start name} can be quite arbitrary and - may contain spaces. +I have also added a coordinate system. The code for drawing an arrow +tip always draws it in the way shown above: Pointing right along the +$x$-axis. + +We will use the following terminology: +\begin{itemize} +\item The point where tip of the arrow ends is called the + \emph{tip end}. It is at $(1,0)$ in our example and we always + assume it to lie on the $x$-axis, so we just treat it as a distance, + 1 in this case. This is the position where the original path was + supposed to end (so if the arrow tip had not been added to the red + path, it would have ended here). +\item The \emph{back end} of the arrow is where a vertical line just + to the left of the arrow intersects the $x$-axis. In our case, this + is the point $(-3,0)$ and again we treat it as a distance, $-3$ in + this case. +\item The \emph{line end} is the position where the path now + ends. This should be a position inside the arrow head that gets + ``covered'' by the path. Note that a path may have a round or a rect + head and should still be covered. Clearly, necessary shortening of + the path will be the difference between the tip end and the line + end. +\item The \emph{visual back end} is the position where the path and + the the arrow head ``meet last'' on the path. In our case, because + of the inset, the visual back end is not the same as the back end: + The arrow ends ``visually'' at $(-2,0)$. The difference between the + back end and the visual back end is important when the arrow tip is + flexed, see Section~\ref{section-arrow-flex} for an explanation of + flexing. +\item There is also a \emph{visual tip end}, the counterpart of the + visual back end for the front. In our case, the visual tip end and + the tip end obviously coincide, but if we were to reverse the arrow + tip, the visual tip end would be different form the tip end (while + the visual back end would then coincide with the new back end). +\item There are four points that make up the \emph{convex hull} of the + arrow tip: $(1,0)$, $(-3,2)$, and $(-3,-2)$. + + Normally, \pgfname\ automatically keeps track of a bounding box of + everything you draw. However, since arrow tips are drawn so often, + \pgfname\ caches the code needing for drawing arrow tips internally + and because of this cache it cannot determine the size of the arrow + tip just based on the drawing commands used for drawing the + tip. Instead, a convex hull of the arrow tip must be explicitly + provided in the definition. +\end{itemize} + +When you design a new arrow tip, all of the above parameters must be +defined. + +\subsection{Caching and Rendering of Arrows} + +As a last preparation for the description of the commands for +declaring arrows, it is important to understand the exact process by +which \pgfname\ draws arrows. - \medskip - \textbf{Basics of the arrow tip code.} - Let us next have a look at the \meta{arrow tip code}. This code will - be used to draw the arrow tip when \pgfname\ thinks this is - necessary. The code should draw an arrow that ``points right,'' - which means that is should draw an arrow at the end of a line coming - from the left and ending at the origin. - - As an example, suppose we wanted to declare an arrow tip consisting - of two arcs, that is, we want the arrow tip to look more or less - like the red part of the following picture: -\begin{codeexample}[] -\begin{tikzpicture}[line width=3pt] - \draw (-2,0) -- (0,0); - \draw[red,line join=round,line cap=round] - (-10pt,10pt) arc (180:270:10pt) arc (90:180:10pt); -\end{tikzpicture} -\end{codeexample} +\begin{enumerate} +\item First, you have to define an arrow tip kind using + |\pgfdeclarearrow{name=foo,...|. This will tell \pgfname\ that %} + |foo| is now the name of an arrow tip. In particular, the + parser for arrow tip specifications will now treat |foo| as the name + of an arrow tip and will not try to consider |f|, |o|, and |o| as + the names of single-char shorthands. + + Other than storing the definitions in the declaration internally, + this command has little other effect. In particular, no drawing or + other processing takes place. +\item Now assume that at some point the arrow tip |foo| is actually + used. In this case, certain options may have been set, for instance + the user may have requested the arrow tip + |foo[length=5pt,open]|. What happens next depends on whether it is + the first time the arrow tip |foo| is used with \emph{these exact + options} ornot. +\item Assume that is the first time |foo| is requested at a length of + 5pt and in an ``open'' version. \pgfname\ now retrieves the + definition of the arrow tip kind that it stored in the first step + and executes the so-called \emph{setup} code. When this code is + executed, all the options will be in force (for + instance, |\pgfarrowlength| will equal |5pt| in our case). The job + of the setup code is two-fold: First, it needs to compute all of the + parameters listed in Section~\ref{section-arrow-terminology}, that + is, it has to compute where the tip end will lie in the arrow tip's + coordinate system \emph{at the particular size of 5pt}, where the + back end will be, where the convex hull points lie, and so + on. Second, the setup code should precompute values that will be + important for constructing the path of the arrow. In our example, + there is little to do in this regard, but for more complicated + arrows, all time-consuming preparations are done now. + + It is \emph{not} the job of the setup to actually draw the arrow + tip, only to ``prepare'' this as much as possible. + + The setup code will always be executed only once for each arrow tip + kind for a given set of options. Thus, when a user uses + |foo[length=5pt,open]| once more later anywhere in the document, the + setup code will not be executed again. +\item The next thing that happens is that we have a look at the + \emph{drawin code} stored in the |code| field of the arrow. In our + example, the drawing code would consist of creating a filled path + with four straight segments. + + In most cases, what happens now is that the drawing code is executed in a + special sandbox in which the low-level driver commands that do the + actual drawing are intercepted and stored away in a so-called + \emph{cache}. Once such a cache has been created, its contents will + be reused whenever |foo[length=5pt,open]| is requested by a user and + just like the setup code, the drawing code will not be executed + again. + + There are, however, two cases in which the drawing code gets executed + each time the arrow is used: First, an arrow tip kind can specify + that this should always happen by saying |cachable=false| in its + definition. This is necessary if the drawing code contains + low-level drawing commands that cannot be intercepted such as a use + of |\pgftext| for arrow tips that ``contain text.'' Second, when the + |bend| option is used, the same arrow tip will look different each + time it is used, namely in dependence on the exact curvature of the + path to which it is added. + + Because the drawing code may be executed several times, while the + setup code may not, we must find a way to ``communicate'' the + values computed by the setup code to the drawing code. This is done + by explicitly calling |\pgfarrowssave| inside the setup + code. Whatever is ``saved'' in this way is restored each time before + the drawing code is executed. +\end{enumerate} - We could use the following as \meta{arrow tip code} for this: -\begin{codeexample}[code only] -\pgfarrowsdeclare{arcs}{arcs}{...} -{ - \pgfsetdash{}{0pt} % do not dash - \pgfsetroundjoin % fix join - \pgfsetroundcap % fix cap - \pgfpathmoveto{\pgfpoint{-10pt}{10pt}} - \pgfpatharc{180}{270}{10pt} - \pgfpatharc{90}{180}{10pt} - \pgfusepathqstroke -} -\end{codeexample} +As can be seen, the process is a bit involved, but it leads to +a reasonably fast arrow tip management. - Indeed, when the |...| is set appropriately (in a moment), we can - write the following: -\pgfarrowsdeclare{arcs}{arcs}{\pgfarrowsleftextend{0pt}\pgfarrowsrightextend{0pt}} -{ - \pgfsetdash{}{0pt} % do not dash - \pgfsetroundjoin % fix join - \pgfsetroundcap % fix cap - \pgfpathmoveto{\pgfpoint{-10pt}{10pt}} - \pgfpatharc{180}{270}{10pt} - \pgfpatharc{90}{180}{10pt} - \pgfusepathqstroke -} -\begin{codeexample}[] -\begin{tikzpicture} - \draw[-arcs,line width=3pt] (-2,0) -- (0,0); - \draw[arcs-arcs,line width=1pt] (-2,-1.5) -- (0,-1); - \useasboundingbox (-2,-2) rectangle (0,0.75); -\end{tikzpicture} -\end{codeexample} - As can be seen in the second example, the arrow tip is automatically - rotated as needed when the arrow is drawn. This is achieved by a - canvas rotation. +\subsection{Declaring an Arrow Tip Kind} +\begin{command}{\pgfdeclarearrow\marg{config}} + This command is both used to define a new arrow tip kind and to to + declare a so-called shorthand. We have a look at the case that a + complete new arrow tip kind is created and then have a look how the + command can be used to create shorthands. + \medskip - \textbf{Special considerations about the arrow tip code.} - There are several things you need to be aware of when designing - arrow tip code: - \begin{itemize} - \item - Inside the code, you may not use the |\pgfusepath| - command. The reason is that this command internally calls arrow - construction commands, which is something you obviously do not want - to happen. - - Instead of |\pgfusepath|, use the quick versions. Typically, you - will use |\pgfusepathqstroke|, |\pgfusepathqfill|, or - |\pgfusepathqfillstroke|. - \item - The code will be executed only once, namely the first time the - arrow tip needs to be drawn. The resulting low-level driver - commands are protocolled and stored away. In all subsequent - uses of the arrow tip, the protocolled code is directly inserted. - \item - However, the code will be executed anew for each line width. Thus, - an arrow of line width 2pt may result in a different protocol than - the same arrow for a line width of 0.4pt. - \item - If you stroke the path that you construct, you should first set - the dashing to solid and setup fixed joins and caps, as - needed. This will ensure that the arrow tip will always look the - same. - \item - When the arrow tip code is executed, it is automatically put - inside a low-level scope, so nothing will ``leak out'' from the - scope. - \item - The high-level coordinate transformation matrix will be set to the - identity matrix when the code is executed for the first time. - \end{itemize} + \noindent\textbf{Defining a Complete New Arrow Tip Kind.} + The \meta{config} is a key--value list in which different keys are + used to setup the to-be defined arrow. The following keys can be given: - \medskip - \textbf{Designing meta-arrows.} - The \meta{arrow tip code} should adjust the size of the arrow in - accordance with the line width. For a small line width, the arrow - tip should be small, for a large line width, it should be - larger. However, the size of the arrow typically \emph{should not} - grow in direct proportion to the line width. On the other hand, the - size of the arrow head typically \emph{should} grow ``a bit'' with - the line width. - - For these reasons, \pgfname\ will not simply executed your arrow - code within a scaled scope, where the scaling depends on the line - width. Instead, your \meta{arrow tip code} is reexecuted again for - each different line width. - - In our example, we could use the following code for the new arrow - tip kind |arc'| (note the prime): + \begin{itemize} + \item \declare{|name|}|=|\meta{name} or |name=|\meta{start name}|-|\meta{end + name} + + This defines the name of the arrow tip. It is legal to define an + arrow tip a second time, in this case the previous definition will + be overwritten in the current \TeX\ scope. It is customary to use + a name with an uppercase fist letter for a ``complete'' arrow tip + kind. Short names and lower case names should be used for + shorthands that change their meaning inside a document, while + arrow tips with uppercase first letters should not be redefined. + + If the name contains a hyphen, the second syntax is assumed and + everything before the hyphen will be the name used in start arrow + specifications, while the text after the hyphen is the name used + in end specifications. + \item \declare{|parameters|}|=|\marg{list of macros} + + As explained earlier, an arrow tip typically needs to be redrawn + each time an option like |length| or |inset| is changed. However, + for some arrow tips, the |inset| has no influence, while for other + it is important whether the arrow is reversed or not. (How keys + like |length| actually set \TeX\ dimensions like |\pgfarrowlength| + is explained in Section~\ref{section-arrow-options}.) + + The job of the |parameters| key is to specify which dependencies + the arrow tip has. Everything that will influence any of the + parameters computed in the setup code or used in the drawing code + should be listed here. + + The \meta{list of macros} will be used inside a + |\csname|-|\endcsname| pair and should expand to the current + values of the relevant parameters have. For example, if the arrow + tip depends on the current value of |\pgfarrowlength| and + |\pgfarrowwidth| only, then \meta{list of macros} should be set to + |\the\pgfarrowlength,\the\pgfarrowwidth|. (Actually, the comma is + optional, the \meta{list of macros} does not really have to be a + list, just something that can be expanded unambiuously.) + + Note that the line width (|\pgflinewidth|) and the inner line + width (|\pgfinnerlinewidth|) are always parameters and need not be + specified in the |parameters|. + + It is important to get this parameter right. Otherwise, arrow tips + may look wrong because \pgfname\ thinks that it can reuse some + code when, in reality, this code actually depends on a parameter + not listed here. + + \item \declare{|setup code|}|=|\marg{code} + + When an arrow tip is used, the value stored in |parameters| is + expanded and it is tested whether the result was encountered + before. If not, the \meta{code} gets executed (only this + once). The code can now do aribtrarily complicated computations + the prepare the later drawing of the arrow tip. Also the + \meta{code} must specify the different tip and back ends and the + convex hull points. This is done by calling the following macros + inside the \meta{code}: + + \begin{command}{\pgfarrowssettipend\marg{dimension}} + When this command is called inside the setup code of an arrow + tip, it specifies that the tip of the drawn arrow will end + exactly at \meta{dimension}. For example, for our earlier + example of the large arrow tip, where the tip end was at 1cm, we + would call \begin{codeexample}[code only] -\newdimen\arrowsize -\pgfarrowsdeclare{arcs'}{arcs'}{...} -{ - \arrowsize=0.2pt - \advance\arrowsize by .5\pgflinewidth - \pgfsetdash{}{0pt} % do not dash - \pgfsetroundjoin % fix join - \pgfsetroundcap % fix cap - \pgfpathmoveto{\pgfpoint{-4\arrowsize}{4\arrowsize}} - \pgfpatharc{180}{270}{4\arrowsize} - \pgfpatharc{90}{180}{4\arrowsize} - \pgfusepathqstroke -} +\pgfarrowssettipend{1cm} \end{codeexample} -\newdimen\arrowsize -\pgfarrowsdeclare{arcs'}{arcs'}{\pgfarrowsleftextend{0pt}\pgfarrowsrightextend{0pt}} -{ - \arrowsize=0.2pt - \advance\arrowsize by .5\pgflinewidth - \pgfsetdash{}{0pt} % do not dash - \pgfsetroundjoin % fix join - \pgfsetroundcap % fix cap - \pgfpathmoveto{\pgfpoint{-4\arrowsize}{4\arrowsize}} - \pgfpatharc{180}{270}{4\arrowsize} - \pgfusepathqstroke - \pgfpathmoveto{\pgfpointorigin} - \pgfpatharc{90}{180}{4\arrowsize} - \pgfusepathqstroke -} -\begin{codeexample}[] -\begin{tikzpicture} - \draw[-arcs',line width=3pt] (-2,0) -- (0,0); - \draw[arcs'-arcs',line width=1pt] (-2,-1.5) -- (0,-1); - \useasboundingbox (-2,-1.75) rectangle (0,0.5); -\end{tikzpicture} + Note that for efficience reasons, the \meta{dimension} is not + passed through |\pgfmathsetlength|; rather what happens is that + |\pgf@x=|\meta{dimension} gets executed. In particular, you can + pack further computations into the \meta{dimension} by simply + starting it with a number and then appending some code that + modifies |\pgf@x|. Here is an example where instead of 1cm we + use $1\mathrm{cm} - \frac12\mathrm{linewidth}$ as the tip end: +\begin{codeexample}[code only] +\pgfarrowssettipend{1cm\advance\pgf@x by-.5\pgflinewidth} \end{codeexample} + If the command is not called at all inside the setup code, the + tip end is set to |0pt|. + \end{command} - However, sometimes, it can also be useful to have arrows that do not - resize at all when the line width changes. This can be achieved by - giving absolute size coordinates in the code, as done for |arc|. On - the other hand, you can also have the arrow resize linearly with the - line width by specifying all coordinates as multiples of - |\pgflinewidth|. - - \medskip - \textbf{The left and right extend.} - Let us have another look at the exact left and right ``ends'' of our - arrow tip. Let us draw the arrow tip |arc'| at a very large size: - -\begin{codeexample}[] -\begin{tikzpicture} - \draw[help lines] (-2,-1) grid (1,1); - \draw[line width=10pt,-arcs'] (-2,0) -- (0,0); - \draw[line width=2pt,white] (-2,0) -- (0,0); -\end{tikzpicture} + \begin{command}{\pgfarrowssetbackend\marg{dimension}} + Works like the command for the tip end, only it sets the back + end. In our example we would call +\begin{codeexample}[code only] +\pgfarrowssettipend{-3cm} \end{codeexample} + Defaults to |0pt|. + \end{command} + + \begin{command}{\pgfarrowssetlineend\marg{dimension}} + Sets the line end, so in the example we have + |\pgfarrowssettipend{-1cm}|. Default to |0pt|. + \end{command} + + \begin{command}{\pgfarrowssetvisualbackend\marg{dimension}} + Sets the visual back end, |\pgfarrowssetvisualbackend{-2cm}| in + our example. Default to the value of the normal back end. + \end{command} + + \begin{command}{\pgfarrowssetvisualtipend\marg{dimension}} + Sets the visual tip end. Default to the value of the normal tip + end and, thus, we need not set it in our example. + \end{command} + + \begin{command}{\pgfarrowshullpoint\marg{x dimension}\marg{y dimension}} + Adds a point to the convex hull of the arrow tip. As for the + previous commands, no math parsing is done; instead \pgfname\ + says |\pgf@x=|\meta{x dimension} and then |\pgf@y=|\meta{y + dimension}. Thus, both ``dimensions'' can contain code for + advancing and thus modifying |\pgf@x| and |\pgf@y|. + + In our example we would write +\begin{codeexample}[code only] +\pgfarrowshullpoint{1cm}{0pt} +\pgfarrowshullpoint{-3cm}{2cm} +\pgfarrowshullpoint{-3cm}{-2cm} +\end{codeexample} + \end{command} - As one can see, the arrow tip does not ``touch'' the origin as it - should, but protrudes a little over the origin. One remedy to this - undesirable effect is to change the code of the arrow tip such that - everything is shifted half an |\arrowsize| to the left. While this - will cause the arrow tip to touch the origin, the line itself will - then interfere with the arrow: The arrow tip will be partly - ``hidden'' by the line itself. - - \pgfname\ uses a different approach to solving the problem: The - \meta{extend code} argument can be used to ``tell'' \pgfname\ how - much the arrow protrudes over the origin. The argument is also used - to tell \pgfname\ where the ``left'' end of the arrow is. However, - this number is important only when the arrow is being reversed or - composed with other arrow tips. - - Once \pgfname\ knows the right extend of an arrow kind, it can - \emph{shorten} lines by this amount when drawing arrows. - Here is a picture that shows what the visualizes the extends. The - arrow tip itself is shown in red once more: + \begin{command}{\pgfarrowsupperhullpoint\marg{x dimension}\marg{y dimension}} + This command works like the previous command, only it normally + adds \emph{two} points to the convex hull: First, the point $(\meta{x + dimension},\meta{y dimension})$ and, secondly, the point $(\meta{x + dimension},-\meta{y dimension})$. However, the second point is + only added if the arrow is not a harpoon. - \medskip - \begin{tikzpicture} - \draw[line width=1cm,-arcs',red] (-6,0) -- (0,0); - \draw[line width=1cm,black] (-6,0) -- (0,0); - \draw[help lines] (-6,0) -- (2,0) (0,-3) -- (0,3) coordinate (a); - \draw[help lines,xshift=0.5cm] (0,-3) -- (0,3) coordinate (b); - \draw[help lines,xshift=-2.5cm-0.8pt] (0,-3) -- (0,3) coordinate (c); - - \coordinate (xline 1) at (0,1.5); - \coordinate (xline 2) at (0,2.8); - - \draw[|->|] (xline 1 -| a) -- node[above=2pt] {right extend} (xline 1 -| b); - \draw[|<-|] (xline 2 -| c) -- node[above=2pt] {left extend} (xline 2 -| a); - - \draw (0,0) -- (1,-1) node[below right] {origin}; - \end{tikzpicture} - - - The \meta{extend code} is normal \TeX\ code that is executed - whenever \pgfname\ wants to know how far the arrow tip will protrude - to the right and left. The code should call the following two - commands: \declare{|\pgfarrowsrightextend|} and - \declare{|\pgfarrowsleftextend|}. Both arguments take one argument - that specifies the size. Here is the final code for the |arc''| arrow - tip: -\begin{codeexample}[] -\pgfarrowsdeclare{arcs''}{arcs''} -{ - \arrowsize=0.2pt - \advance\arrowsize by .5\pgflinewidth - \pgfarrowsleftextend{-4\arrowsize-.5\pgflinewidth} - \pgfarrowsrightextend{.5\pgflinewidth} -} -{ - \arrowsize=0.2pt - \advance\arrowsize by .5\pgflinewidth - \pgfsetdash{}{0pt} % do not dash - \pgfsetroundjoin % fix join - \pgfsetroundcap % fix cap - \pgfpathmoveto{\pgfpoint{-4\arrowsize}{4\arrowsize}} - \pgfpatharc{180}{270}{4\arrowsize} - \pgfusepathqstroke - \pgfpathmoveto{\pgfpointorigin} - \pgfpatharc{90}{180}{4\arrowsize} - \pgfusepathqstroke -} -\begin{tikzpicture} - \draw[help lines] (-2,-1) grid (1,1); - \draw[line width=10pt,-arcs''] (-2,0) -- (0,0); - \draw[line width=2pt,white] (-2,0) -- (0,0); -\end{tikzpicture} + Thus, in our example we could simplify the convex hull to +\begin{codeexample}[code only] +\pgfarrowshullpoint{1cm}{0pt} +\pgfarrowsupperhullpoint{-3cm}{2cm} \end{codeexample} + If the \meta{y dimension} is zero or less, only one point, + namely $(\meta{x dimension},\meta{y dimension})$, is added to + the hull. Thus, we could also have used the upper convex hull + command in the first of the two of the above commands. + \end{command} + + \begin{command}{\pgfarrowssave\marg{macro}} + As explained earlier, the setup code needs to ``communicate'' + with the drawing code via ``saved values.'' This command get the + name of a macro and will store the value this macro had + internally. Then, each time drawing code is executed, the value + of this macro will be restored. + \end{command} + + \begin{command}{\pgfarrowssavethe\marg{register}} + Works like |\pgfarrowssave|, only the parameter must be a + register and |\the|\meta{register} will be saved. + Typically, you will write something like +\begin{codeexample}[code only] +\pgfarrowssavethe{\pgfarrowlength} +\pgfarrowssavethe{\pgfarrowwidth} +\end{codeexample} + To ensure that inside the drawing code the the dimension + registers |\pgfarrowlength| and |\pgfarrowwidth| are setup with + the values they had during the setup. + \end{command} + + \item \declare{|drawing code|}|=|\marg{code} + + This code will be executed at least once for each setting of the + parameters when the time arrow tip is actually drawn. Usually, + this one execution will be all and the + low-level commands generated inside the \meta{code} will we stored + in a special cache; but in some cases the \meta{code} gets + executed each time the arrow tip is used, so do not assume + anything about it. Inside the \meta{code}, you have access to all + values that were saved in the setup code as well as to the line + width. + + The \meta{code} should draw the arrow tip ``going right along the + $x$-axis.'' \pgfname\ will take care of setting up a canvas + transformation beforehand to a rotation such that when the + drawing is rendered, the arrow tip that is actually drawn points + in the direction of the line. Alternatively, when bending is + switched on, even more complicated low-level transformations will + be done automatically. + + The are some special considerations concerning the \meta{code}: + \begin{itemize} + \item + In the \meta{code} you may \emph{not} use |\pgfusepath| + since this would try to add arrow tips to the arrow tip and lead + to a recursion. Use the ``quick'' versions |\pgfusepathqstroke| + and so on instead, which never try to add arrow tips. + \item + If you stroke the path that you construct, you should first set + the dashing to solid and set up fixed joins and caps, as + needed. This will ensure that the arrow tip will always look the + same. + \item + When the arrow tip code is executed, it is automatically put + inside a low-level scope, so nothing will ``leak out'' from the + scope. + \item + The high-level coordinate transformation matrix will be set to the + identity matrix when the code is executed for the first time. + \end{itemize} + + \item \declare{|cache|}|=|\meta{true or false} + + When set to |true|, which is the default, the \meta{code} will be + executed only once for a partiular value of parameters and the + low-level commands created by the drawing code (using the system + layer protocol subsystem, see Section~\ref{section-protocols}) + will be cached and reused later on. However, when the drawing code + contains ``uncachable'' code like a call to |\pgftext|, caching + must be switched off by saying |cache=false|. + + \item \declare{|bending mode|}|=|\meta{mode} + + This key is important only when the |bend| option is used with an + arrow, see Section~\ref{section-arrow-flex} for an introduction to + this option. The |bend| option asks us to, well, bend the arrow + head. For some arrow head this is not possible or leads to very + strange drawings (for instance, when the |\pgftext| command is + used) and then it is better to switch bending off for the arrow + head (|flex| will then be used instead). To achieve this, set + \meta{mode} to |none|. + + For most arrow tips it does, however, make sense to bend + them. There are (at least) two different mathematical ways of + doing so, see Section~\ref{section-library-curvilinear} for details. Which of + these ways is use can be configured by setting \meta{mode} to + either |orthogonal| or to |polar|. It is best to try simply try + out both when designing an arrow tip to see which works + better. Since |orthogonal| is quicker and often gives good oder + even better results, it is the default. Some arrow tips, however, + profit from saying |bending mode=polar|. + + \item \declare{|defaults|}|=|\meta{arrow keys} + + The \meta{arrow keys} allow you to configure the default values + for the parameters on which an arrow tip depends. The \meta{arrow + keys} will be executed first before any other arrow tip options + are executed, see Section~\ref{section-arrow-scopes} for the exact + sequence. Also see Section~\ref{section-arrow-options} below for + more details on arrow options. + \end{itemize} - \medskip - \textbf{Taking inner lines into account.} - In addition to the line width, there is another parameter that (may) - influence the way an arrow looks: The inner line width, which is the - line width of the second line that is stroked on top of a normal - line in order to create the effect of a ``double'' line. When this - line width changes, the arrow tip code is also reexecuted (and - cached), so your code may depend on the current value of the inner - line width. - - The following example shows how this works. The |implies| arrow - defined below has to setup the line width not for the ``main'' line - width, but for the main line width minus the inner line width, - divided by~2. + This concludes the description of the keys you provide for the + declaration of an arrow. Let us now have a look at a simple example + that uses these features: We want to define an arrow tip kind |foo| + that produces the arrow tip we used as our running examlpe. However, + to make things a bit more interesting, let us make it + ``configurable'' insofar as the length of the arrow tip can be + configured using the |length| option, which sets the + |\pgfarrowlength|. By default, this length should be the gigantic + 4cm we say in the example, but uses should be able to set it to + anything they like. We will not worry about the arrow width or + insets, of arrow line width, or harpoons, or anything else in this + example to keep it simple. + + Here is the code: \begin{codeexample}[code only] -\pgfarrowsdeclare{implies}{implies}{...} -{ - \pgfmathsetlength{\pgfutil@tempdimb}{.5\pgflinewidth-.5*\pgfinnerlinewidth}% - \pgfsetlinewidth{\pgfutil@tempdimb} - \pgfsetdash{}{0pt} - \pgfsetroundcap - \pgfsetroundjoin - \pgfmathsetlength{\pgfutil@tempdima}{.25\pgflinewidth+.25*\pgfinnerlinewidth}% - \pgfpathmoveto {\pgfpoint{-1.4\pgfutil@tempdima}{2.65\pgfutil@tempdima}} - \pgfpathcurveto{\pgfpoint{-0.75\pgfutil@tempdima}{1.25\pgfutil@tempdima}} - {\pgfpoint{1\pgfutil@tempdima}{0.05\pgfutil@tempdima}} - {\pgfpoint{2\pgfutil@tempdima}{0pt}} - \pgfpathcurveto{\pgfpoint{1\pgfutil@tempdima}{-0.05\pgfutil@tempdima}} - {\pgfpoint{-.75\pgfutil@tempdima}{-1.25\pgfutil@tempdima}} - {\pgfpoint{-1.4\pgfutil@tempdima}{-2.65\pgfutil@tempdima}} - \pgfusepathqstroke -} +\pgfdeclarearrow{ + name = foo, + parameters = { \the\pgfarrowlength }, + setup code = { + % The different end values: + \pgfarrowssettipend{.25\pgfarrowlength} + \pgfarrowssetlineend{-.25\pgfarrowlength} + \pgfarrowssetvisualbackend{-.5\pgfarrowlength} + \pgfarrowssetbackend{-.75\pgfarrowlength} + % The hull + \pgfarrowshullpoint{.25\pgfarrowlength}{0pt} + \pgfarrowshullpoint{-.75\pgfarrowlength}{.5\pgfarrowlength} + \pgfarrowshullpoint{-.75\pgfarrowlength}{-.5\pgfarrowlength} + % Saves: Only the length: + \pgfarrowssavethe\pgfarrowlength + }, + drawing code = { + \pgfpathmoveto{.25\pgfarrowlength}{0pt} + \pgfpathlineto{-.75\pgfarrowlength}{.5\pgfarrowlength} + \pgfpathlineto{-.5\pgfarrowlength}{0pt} + \pgfpathlineto{-.75\pgfarrowlength}{-.5\pgfarrowlength} + \pgfpathclose + \pgfusepathqfill + }, + defaults = { length = 4cm } +} \end{codeexample} - Here is the effect for different combinations of line width and - inner line width: + We can now use it: +\pgfdeclarearrow{ + name = foo, + parameters = { \the\pgfarrowlength }, + setup code = { + % The different end values: + \pgfarrowssettipend{.25\pgfarrowlength} + \pgfarrowssetlineend{-.25\pgfarrowlength} + \pgfarrowssetvisualbackend{-.5\pgfarrowlength} + \pgfarrowssetbackend{-.75\pgfarrowlength} + % The hull + \pgfarrowshullpoint{.25\pgfarrowlength}{0pt} + \pgfarrowshullpoint{-.75\pgfarrowlength}{.5\pgfarrowlength} + \pgfarrowshullpoint{-.75\pgfarrowlength}{-.5\pgfarrowlength} + % Saves: Only the length: + \pgfarrowssavethe\pgfarrowlength + }, + drawing code = { + \pgfpathmoveto{\pgfqpoint{.25\pgfarrowlength}{0pt}} + \pgfpathlineto{\pgfqpoint{-.75\pgfarrowlength}{.5\pgfarrowlength}} + \pgfpathlineto{\pgfqpoint{-.5\pgfarrowlength}{0pt}} + \pgfpathlineto{\pgfqpoint{-.75\pgfarrowlength}{-.5\pgfarrowlength}} + \pgfpathclose + \pgfusepathqfill + }, + defaults = { length = 4cm } +} \begin{codeexample}[] -\begin{tikzpicture} - \foreach \linewidth in {2,2.4,...,4.4} - \foreach \innerlinewidth in {0.4,0.8,...,1.8} - { - \pgfsetlinewidth{\linewidth pt} - \pgfsetinnerlinewidth{\innerlinewidth pt} - \draw [-implies] (\innerlinewidth*50pt,\linewidth*40pt) -- ++(4mm,0); - } -\end{tikzpicture} +\tikz \draw [-foo] (0,0) -- (8,0); +\end{codeexample} +\begin{codeexample}[] +\tikz \draw [-{foo[length=2cm,bend]}] (0,0) to [bend left] (3,0); \end{codeexample} \medskip - \textbf{Arrow options.} - You may wish to have further option influence the appearance of an - arrow tip. For instance, for a ``pointed'' arrow you may wish to set - the opening angle of the tip. Then, whenever this option changes - that arrow tip code also needs to be reexecuted, even though the - line width has stayed the same. - - You can use the commands |\pgfsetarrowoptions| and - |\pgfgetarrowoptions| to set such options for an arrow tip. Whenever - an arrow tip needs to be rendered, it is checked whether the arrow - tip code has already been executed for the current (expanded) value of the - options. If so, the cached code is used; otherwise the code is - executed once more. Naturally, inside the code the current value of - the arrow options should be taken into account. - - Arrow options can and must be specified individually for each arrow - type. - - In the following example, we make the arc angle an option. -\begin{codeexample}[] -\pgfarrowsdeclare{var arc}{var arc} % options is an angle -{ - \arrowsize=0.2pt - \advance\arrowsize by .5\pgflinewidth - \pgfarrowsleftextend{-4\arrowsize-.5\pgflinewidth} - \pgfarrowsrightextend{.5\pgflinewidth} -} -{ - \arrowsize=0.2pt - \advance\arrowsize by .5\pgflinewidth - \pgfsetdash{}{0pt} % do not dash - \pgfsetroundjoin % fix join - \pgfsetroundcap % fix cap - \pgfpathmoveto{\pgfpointorigin} - \pgfpatharc{-90}{-180+\pgfgetarrowoptions{var arc}}{4\arrowsize} - \pgfusepathqstroke - \pgfpathmoveto{\pgfpointorigin} - \pgfpatharc{90}{180-\pgfgetarrowoptions{var arc}}{4\arrowsize} - \pgfusepathqstroke -} -\begin{tikzpicture} - \draw[help lines] (-2,-4) grid (1,4); - \foreach \option in {-60,-50,...,60} - { - \pgfsetarrowoptions{var arc}{\option} - \draw[ultra thick,-var arc] (-2,\option/15) -- (0,\option/15); - } -\end{tikzpicture} + \noindent\textbf{Defining a Shorthand.} + The |\pgfdeclarearrow| command can also used to define + \emph{shorthands}. This works as follows: + \begin{itemize} + \item First, you must provide a |name| just in the same way as when + you define a full-flung new arrow tip kind. + \item Second, instead of all of the other options listed above, you + just use one more option: + + \smallskip + \declare{|means|}|=|\meta{end arrow specification} + + This sets up things so that whenever \meta{name} is now used in an + arrow specification, it will be replaced by the \meta{end arrow + specification} (the problems resulting form the \meta{name} + begin used in a start arrow specification are taken care of + automatically). See also Section~\ref{section-arrow-tip-macro} for + details on the order in which options get executed in such cases. + + Note that the \meta{end arrow specification} will be executed + immediately to build the so-called arrow option caches, a concept + explored in more detail in + Section~\ref{section-arrow-option-cache}. In practice, this has + mainly two effects: First, all arrow tips referred to in the + specification must already exist (at least as ``dummy'' + versions). Second, all dimensions mentioned in options of the + \meta{end arrow specification} will be evaluated immediately. For + instance, when you write +\begin{codeexample}[code only] +\pgfdeclarearrow{ name=foo, means = bar[length=2cm+\mydimen] } \end{codeexample} + The value |2cm+\mydimen| is evaluated immediately. When |foo| is + used later on and |\mydimen| has changed, this has no effect. + \end{itemize} \end{command} -\pgfarrowsdeclare{arcs''}{arcs''} -{ - \arrowsize=0.2pt - \advance\arrowsize by .5\pgflinewidth - \pgfarrowsleftextend{-4\arrowsize-.5\pgflinewidth} - \pgfarrowsrightextend{.5\pgflinewidth} -} -{ - \arrowsize=0.2pt - \advance\arrowsize by .5\pgflinewidth - \pgfsetdash{}{0pt} % do not dash - \pgfsetroundjoin % fix join - \pgfsetroundcap % fix cap - \pgfpathmoveto{\pgfpoint{-4\arrowsize}{4\arrowsize}} - \pgfpatharc{180}{270}{4\arrowsize} - \pgfusepathqstroke - \pgfpathmoveto{\pgfpointorigin} - \pgfpatharc{90}{180}{4\arrowsize} - \pgfusepathqstroke -} - -\begin{command}{\pgfsetarrowoptions\marg{arrow tip}\marg{text}} - Sets the options for the \meta{arrow tip} to \meta{text}. The - default, before any call to this macro is made, is 0. -\end{command} -\begin{command}{\pgfgetarrowoptions\marg{arrow tip}} - This will expand to the current value of the options for the - \meta{arrow tip}. -\end{command} +\subsection{Handling Arrow Options} +\label{section-arrow-options} -\subsection{Declaring a Derived Arrow Tip Kind} +When you declare an arrow tip, your drawing code should take into +account the different arrow keys set for it (like the arrow tip length, +width, or harpooning). The different arrow keys that are available +have been described in detail in Section~\ref{section-arrow-config}; but +how do we access the values set by an option like |length| or +|harpoon| or |bend| in the drawing code? In the present section we +have a look at how this works. -It is possible to declare arrow kinds in terms of existing ones. For -these command to work correctly, the left and right extends must be -set correctly. -\begin{command}{\pgfarrowsdeclarealias\marg{start name}\marg{end - name}\marg{old start name}\marg{old end name}} - This command can be used to create an alias (another name) for an - existing arrow kind. +\subsubsection{Dimension Options} -\begin{codeexample}[] -\pgfarrowsdeclarealias{<}{>}{arcs''}{arcs''}% -\begin{tikzpicture} - \pgfsetarrows{<->} - \pgfsetlinewidth{1ex} - \pgfpathmoveto{\pgfpointorigin} - \pgfpathlineto{\pgfpoint{3.5cm}{2cm}} - \pgfusepath{stroke} - \useasboundingbox (-0.25,-0.25) rectangle (3.75,2.25); -\end{tikzpicture} -\end{codeexample} -\end{command} +Most arrow keys, like |length| or |width'|, simple set a \TeX\ +dimension register to a certain value. For example, |length| sets the +value of the \TeX\ dimension register |\pgfarrowlength|. Note that +|length| takes several values as input with a complicated semantics as +explained for the |length| key on +page~\pageref{length-arrow-key}. All of these settings are not +important for the setup code: When it gets executed, the code behind +the |length| key will have computed a simple number that is stored +in |\pgfarrowlength|. Indeed, inside the setup code you do not have +access to the exact value given to the |length| key; just to the +final computed value. +The following \TeX\ dimensions are available to the setup code: -\begin{command}{\pgfarrowsdeclarereversed\marg{start name}\marg{end - name}\marg{old start name}\marg{old end name}} - This command creates a new arrow kind that is the ``reverse'' of an - existing arrow kind. The (automatically cerated) code of the new - arrow kind will contain a flip of the canvas and the meanings of the - left and right extend will be reversed. +\begin{itemize} +\item |\pgfarrowslength|. It gets set by the arrow keys |length| and |angle|. +\item |\pgfarrowswidth|. It gets set by |width|, |width'|, and |angle|. +\item |\pgfarrowsinset|. It gets set by |inset| and |inset'|. +\item |\pgfarrowslinewidth|. It gets set by |line width| and |line width'|. +\end{itemize} -\begin{codeexample}[] -\pgfarrowsdeclarereversed{arcs reversed}{arcs reversed}{arcs''}{arcs''}% -\begin{tikzpicture} - \pgfsetarrows{arcs reversed-arcs reversed} - \pgfsetlinewidth{1ex} - \pgfpathmoveto{\pgfpointorigin} - \pgfpathlineto{\pgfpoint{3.5cm}{2cm}} - \pgfusepath{stroke} - \useasboundingbox (-0.25,-0.25) rectangle (3.75,2.25); -\end{tikzpicture} -\end{codeexample} -\end{command} +If your setup code depends on any of them, add them to the +|parameters| key of the arrow tip. +\subsubsection{True--False Options} -\begin{command}{\pgfarrowsdeclarecombine\opt{|*|}\opt{\oarg{offset}}\marg{start - name}\marg{end name}\marg{first start name}\marg{first end - name}\penalty0\marg{second start name}\marg{second end name}} - This command creates a new arrow kind that combines two existing - arrow kinds. The first arrow kind is the ``innermost'' arrow kind, - the second arrow kind is the ``outermost.'' +A number of arrow keys just do a yes/no switch, like |reversed|. All +of them setup a \TeX-if that you can access in the setup code: - The code for the combined arrow kind will install a canvas - translation before the innermost arrow kind in drawn. This - translation is calculated such that the right tip of the innermost - arrow touches the right end of the outermost arrow. The optional - \meta{offset} can be used to increase (or decrease) the distance - between the inner and outermost arrow. +\begin{itemize} +\item |\ifpgfarrowreversed| is setup by |reversed|. +\item |\ifpgfarrowswap| is setup by |swap| and also |right|. +\item |\ifpgfarrowharpoon| is setup by |harpoon| and also |left| and |right|. +\item |\ifpgfarrowroundcap| is set to true by |line cap=round| and set + to false by |line cap=butt|. It also gets (re)set by |round| and |sharp|. +\item |\ifpgfarrowroundjoin| is set to true by |line join=round| and set + to false by |line join=miter|. It also gets (re)set by |round| and |sharp|. +\item |\ifpgfarrowopen| is set to true by |fill=none| and by |open| + (which is a shorthand for |fill=none|) and set to false by |color| + and all other |fill=|\meta{color}. +\end{itemize} -\begin{codeexample}[] -\pgfarrowsdeclarecombine[\pgflinewidth] - {combined}{combined}{arcs''}{arcs''}{latex}{latex}% -\begin{tikzpicture} - \pgfsetarrows{combined-combined} - \pgfsetlinewidth{1ex} - \pgfpathmoveto{\pgfpointorigin} - \pgfpathlineto{\pgfpoint{3.5cm}{2cm}} - \pgfusepath{stroke} - \useasboundingbox (-0.25,-0.25) rectangle (3.75,2.25); -\end{tikzpicture} +If you code depends on any of these, you must add them to +the |parameters| in such a way that the parameters are different when +the \TeX-if is set from when it is not set. An easy way to achieve +this is to write something like +\begin{codeexample}[code only] + parameters = { \the\pgfarrowlength,..., + \ifpgfarrowharpoon h\fi\ + \ifpgfarrowroundjoin j\fi} \end{codeexample} +In other words, for each set parameter on which the arrow tip depends, +a specific letter is added to the parameters, making them unique. + +The first two of the above keys are a bit special: Reversing and swapping an +arrow tip can be done just by fiddling with the +transformation matrix: a reverse is a ``flip'' along the $y$-axis and +a swap is a flip along the $x$-axis. This is done automatically by +\pgfname. + +Nevertheless, you may wish to modify you code in dependence +especially of the |reverse| key: When |\ifpgfarrowreverse| is true, +\pgfname\ will flip the coordinate system along the $y$-axis, will +negate all end values (like line end, tip end, and so on) and will +exchange the meaning of back end and tip end as well as of visual back +end and visual back end. Usually, this is exactly what one need; +\emph{except} that the line end may no longer be appropriate. After +all, the line end should be chosen so that it is completely covered by +the arrow. Now, when the arrow tip is open, a reversed arrow should no +longer have the line end near the old visual back end, but near to the +old visual tip end. + +For these reasons, you may need to make the computation of the line +end dependent on whether the arrow is reversed or not. Note that when +you specify a different line end for a reversed arrow tip, the +transformation and inverting of the coordinate system will still be +done, meaning that if |reverse| is true, you need to specify a line +end in the ``old'' coordinate system that is at the position where, +after everything is inverted, it will be at the correct +position. Usually that means that if the |reverse| option is set, you +need to \emph{increase} the line end. + + +\subsubsection{Inaccessible Options} + +There are some options that influence the way an arrow tip looks, but +that you cannot access inside the setup code. Handling these options +lies entirely with \pgfname. If you wish your setup code to handle +these options, you have to setup your own ``parallel'' options. + +\begin{itemize} +\item |quick|, |flex|, |flex'|, and |bend| are all handled + automatically. You can, however, set the |bending mode| to avoid + bending of your arrow tip. +\item The colors set by |color| and |fill|. You can, however, access + them indirectly, namely through the current stroke and fill colors. +\item |sep| +\end{itemize} + + +\subsubsection{Defining New Arrow Keys} +\label{section-arrow-option-cache} + +The set of predefined options is already quite long and most arrow +tips will not need more than the predefined options. However, +sometimes an arrow tip may need to introduce a new special-purpose +option. For instance, suppose we wish to introcue a new fictive arrow +key |depth|. In such cases, you must do two things: - In the star variant, the end of the line is not in the outermost - arrow, but inside the innermost arrow. - -\begin{codeexample}[] -\pgfarrowsdeclarecombine*[\pgflinewidth] - {combined'}{combined'}{arcs''}{arcs''}{latex}{latex}% -\begin{tikzpicture} - \pgfsetarrows{combined'-combined'} - \pgfsetlinewidth{1ex} - \pgfpathmoveto{\pgfpointorigin} - \pgfpathlineto{\pgfpoint{3.5cm}{2cm}} - \pgfusepath{stroke} - \useasboundingbox (-0.25,-0.25) rectangle (3.75,2.25); -\end{tikzpicture} +\begin{enumerate} +\item + Introduce a new dimension register or macro that will hold the + configuration value and which will be accessed by the setup + code. The could be achieved by saying +\begin{codeexample}[code only] +\newdimen\pgfarrowdepth \end{codeexample} -\end{command} - - -\begin{command}{\pgfarrowsdeclaredouble\opt{\oarg{offset}}\marg{start - name}\marg{end name}\marg{old start name}\marg{old end - name}} - This command is a shortcut for combining an arrow kind with itself. +\item + Introduce a new arrow key option |/pgf/arrow keys/depth| that allows + users to configure the new macro or register. +\end{enumerate} -\begin{codeexample}[] -\pgfarrowsdeclaredouble{<<}{>>}{arcs''}{arcs''}% -\begin{tikzpicture} - \pgfsetarrows{<<->>} - \pgfsetlinewidth{1ex} - \pgfpathmoveto{\pgfpointorigin} - \pgfpathlineto{\pgfpoint{3.5cm}{2cm}} - \pgfusepath{stroke} - \useasboundingbox (-0.25,-0.25) rectangle (3.75,2.25); -\end{tikzpicture} +When an arrow is selected via for instance |foo[depth=5pt]|, the +key--value pairs between the square brackets are executed with the +path prefix |/pgf/arrow keys|. Thus, in the example, our depth key +would get executed. Thus, it is temping to write something like +\begin{codeexample}[code only] +\pgfkeys{/pgf/arrow keys/depth/.code = \pgfmathsetlength{\pgfarrowdepth}{#1}} \end{codeexample} -\end{command} - - -\begin{command}{\pgfarrowsdeclaretriple\opt{\oarg{offset}}\marg{start - name}\marg{end name}\marg{old start name}\marg{old end - name}} - This command is a shortcut for combining an arrow kind with itself - and then again. -\begin{codeexample}[] -\pgfarrowsdeclaretriple{<<<}{>>>}{arcs''}{arcs''}% -\begin{tikzpicture} - \pgfsetarrows{<<<->>>} - \pgfsetlinewidth{1ex} - \pgfpathmoveto{\pgfpointorigin} - \pgfpathlineto{\pgfpoint{3.5cm}{2cm}} - \pgfusepath{stroke} - \useasboundingbox (-0.25,-0.25) rectangle (3.75,2.25); -\end{tikzpicture} +Sadly, this will not work. The reason is that the is yet another level +of caching involved when \pgfname\ processes arrow tips: The option +cache! The problem is each time an arrow tip is used, even when the +drawing code of the arrow tip is nicely cached, we still need to +process the options in |foo[length=5pt]| to find out which version in +the cache we would like to access. To make matters worse, |foo| might +be a shorthand that calls other arrow tips, which add more options, +and so on. Unfortunately, executing keys is quite an expensive +operation (\pgfname's key--value parser is powerful, but that power +comes at a price). So, whenever possible, we do \emph{not} want the +key--value parser to be started. + +For these reasons, when something like |foo[|\meta{options}|]| is +encountered inside a shorthand, the \meta{options} are executed only +once. They should now setup the \emph{arrow option cache}, which is +some code that, when executed, should setup the values that the +\meta{options} configure. In our example, the |depth| key should add +something to the arrow option cache that sets |\pgfarrowdepth| to the +given value. + +Adding something to the arrow option cache is done using the following +command: + +\begin{command}{\pgfarrowsaddtooptions\marg{code}} + This command should be called by keys with the prefix + |/pgf/arrow keys| to add code to the arrow option cache. For our + |depth| key example, we could use this key as follows: +\begin{codeexample}[code only] +\pgfkeys{/pgf/arrow keys/depth/.code= + \pgfarrowsaddtooptions{\pgfmathsetlength{\pgfarrowdepth}{#1}} +\end{codeexample} + Actually, this is still not optimal since the expensive + |\pgfmathsetlength| command is now called each time an arrow tip is + used with the |depth| option set. The trick is to do the expensive + operation only once and then store only very quick code in the arrow + option cache: +\begin{codeexample}[code only] +\pgfkeys{/pgf/arrow keys/depth/.code= + \pgfmathsetlength{\somedimen}{#1} + \pgfarrowsaddtooptions{\pgfarrowdepth=\somedimen} % buggy +\end{codeexample} + The above code will not (yet) work since |\somedimen| will surely + have a different value when the cache is executed. The trick is to + use some |\expandafter|s: +\begin{codeexample}[code only] +\pgfkeys{/pgf/arrow keys/depth/.code= + \pgfmathsetlength{\somedimen}{#1} + \expandafter\pgfarrowsaddtooptions\expandafter{\expandafter\pgfarrowdepth\expandafter=\the\somedimen} \end{codeexample} \end{command} +\begin{command}{\pgfarrowsaddtolateoptions\marg{code}} + This command works like |\pgfarrowsaddtooptions|, only the + \meta{code} will be executed ``later'' than the code added by the + normal version of the command. This is useful for keys that depend + on the length of an arrow: Keys like |width'| want to define the + arrow width as a multiple of the arrow length, but when the |width'| + key is given, the length may not yet have been specified. By making + the computation of the width a ``late'' option, we ensure that + |\pgfarrowlength| will have been setup correctly. +\end{command} +If you define a new option that sets a dimensions and if that +dimension should change in accordance to the setting of either +|scale length| or |scale width|, you need to make \pgfname\ ``aware'' +of this using the following key: +\begin{command}{\pgfarrowsaddtolengthscalelist\marg{dimension register}} + Each time an arrow tip is used, the given \meta{dimension register} + will be multiplied by the |scale length| factor prior to the actual + drawing. You call this command only once in the preamble somewhere. +\end{command} - -\subsection{Using an Arrow Tip Kind} - -The following commands install the arrow kind that will be used when -stroking is done. - -\begin{command}{\pgfsetarrowsstart\marg{start arrow kind}} - Installs the given \meta{start arrow kind} for all subsequent - strokes in the in the current \TeX-group. If \meta{start arrow kind} - is empty, no arrow tips will be drawn at the start of the last - segment of paths. -\begin{codeexample}[] -\begin{tikzpicture} - \pgfsetarrowsstart{latex} - \pgfsetlinewidth{1ex} - \pgfpathmoveto{\pgfpointorigin} - \pgfpathlineto{\pgfpoint{3.5cm}{2cm}} - \pgfusepath{stroke} - \useasboundingbox (-0.25,-0.25) rectangle (3.75,2.25); -\end{tikzpicture} -\end{codeexample} +\begin{command}{\pgfarrowsaddtowidthscalelist\marg{dimension register}} + Works like |\pgfarrowsaddtolengthscalelist|, only for width parameters. \end{command} -\begin{command}{\pgfsetarrowsend\marg{start arrow kind}} - Like |\pgfsetarrowsstart|, only for the end of the arrow. + +\begin{command}{\pgfarrowsthreeparameters\marg{line-width dependent + size specification}} + This command is useful for parsing the values given to keys like + |length| or |width| the expect a dimension followed optionally for + some numbers. This command converts the \meta{line-width dependent + size specification}, which may consist of one, two, or three + numbers, into a triple of three numbers in curly braces, which gets + stored in the macro |\pgfarrowstheparameters|. Here is an example, + where |\showvalueofmacro| is used in this example to show the value + stored in a macro: + \makeatletter + \def\showvalueofmacro#1{% + \texttt{\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\pgfutil@gobble\expandafter\expandafter\expandafter\string\expandafter\csname#1\endcsname} + } \begin{codeexample}[] -\begin{tikzpicture} - \pgfsetarrowsend{latex} - \pgfsetlinewidth{1ex} - \pgfpathmoveto{\pgfpointorigin} - \pgfpathlineto{\pgfpoint{3.5cm}{2cm}} - \pgfusepath{stroke} - \useasboundingbox (-0.25,-0.25) rectangle (3.75,2.25); -\end{tikzpicture} +\pgfarrowsthreeparameters{2pt 1} +\showvalueofmacro\pgfarrowstheparameters \end{codeexample} \end{command} -\emph{Warning:} If the compatibility mode is active (which is the -default), there also exist old commands called |\pgfsetstartarrow| and -|\pgfsetendarrow|, which are incompatible with the meta-arrow -management. +\begin{command}{\pgfarrowslinewidthdependent\marg{dimension}\marg{line + width factor}\marg{outer factor}} + This command take three parameters and does the ``line width + dependent computation'' described on page~\pageref{length-arrow-key} + for the |length| key. The result is returned in |\pgf@x|. -\begin{command}{\pgfsetarrows\texttt{\char`\{}\meta{start kind}|-|\meta{end kind}\texttt{\char`\}}} - Calls |\pgfsetarrowsstart| for \meta{start kind} and - |\pgfsetarrowsend| for \meta{end kind}. -\begin{codeexample}[] -\begin{tikzpicture} - \pgfsetarrows{latex-to} - \pgfsetlinewidth{1ex} - \pgfpathmoveto{\pgfpointorigin} - \pgfpathlineto{\pgfpoint{3.5cm}{2cm}} - \pgfusepath{stroke} - \useasboundingbox (-0.25,-0.25) rectangle (3.75,2.25); -\end{tikzpicture} + The idea is that you can setup line-width dependent keys like + |length| or |width| using code like the following: +\begin{codeexample}[code only] +\pgfkeys{/pgf/arrow keys/depth/.code={% + \pgfarrowsthreeparameters{#1}% + \expandafter\pgfarrowsaddtolateoptions\expandafter{% + \expandafter\pgfarrowslinewidthdependent\pgfarrowstheparameters% compute... + \pgfarrowdepth\pgf@x% ... and store. + }% +} \end{codeexample} \end{command} +\begin{command}{\pgfarrowslengthdependent\marg{dimension}\marg{length factor}\marg{dummy}} + This command take three parameters, of which the last one is + ignored, and does the ``length dependent computation'' described for + the |width'| and |inset'| keys. The result is returned in |\pgf@x|. -\subsection{Predefined Arrow Tip Kinds} - -\label{standard-arrows} - -The following arrow tip kinds are always defined: + You can setup length dependent keys using code like the following: +\begin{codeexample}[code only] +\pgfkeys{/pgf/arrow keys/depth'/.code={% + \pgfarrowsthreeparameters{#1}% + \expandafter\pgfarrowsaddtolateoptions\expandafter{% + \expandafter\pgfarrowslengthdependent\pgfarrowstheparameters% compute... + \pgfarrowdepth\pgf@x% ... and store. + }% +} +\end{codeexample} +\end{command} -{ -\bigskip -\catcode`\|=12 -\begin{tabular}{ll} - \sarrow{stealth}{stealth} \\ - \sarrow{stealth reversed}{stealth reversed} \\ - \sarrow{to}{to} \\ - \sarrow{to reversed}{to reversed} \\ - \sarrow{latex}{latex} \\ - \sarrow{latex reversed}{latex reversed} \\ - \index{*vbar@\protect\texttt{\protect\myvbar} arrow tip}% - \index{Arrow tips!*vbar@\protect\texttt{\protect\myvbar}} - \texttt{|-|}& yields thick - \begin{tikzpicture}[arrows={|-|},thick] - \useasboundingbox (0pt,-0.5ex) rectangle (1cm,2ex); - \draw (0,0) -- (1,0); - \end{tikzpicture} and thin - \begin{tikzpicture}[arrows={|-|},thin] - \useasboundingbox (0pt,-0.5ex) rectangle (1cm,2ex); - \draw (0,0) -- (1,0); - \end{tikzpicture} -\end{tabular} -} - -For further arrow tips, see page~\pageref{section-library-arrows}. %%% Local Variables: %%% mode: latex |