summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/doc/generic/pgf/text-en/pgfmanual-en-base-arrows.tex
diff options
context:
space:
mode:
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.tex1451
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