summaryrefslogtreecommitdiff
path: root/graphics
diff options
context:
space:
mode:
authorNorbert Preining <norbert@preining.info>2022-04-09 03:00:48 +0000
committerNorbert Preining <norbert@preining.info>2022-04-09 03:00:48 +0000
commitb3472831ddfd1931359464019cc964efeac20d94 (patch)
tree3e7ec8497be830d593e5153a0cf227987e2a7862 /graphics
parentd1d30aef56e5df7bbe7ee55e9fecf7d72514b6bf (diff)
CTAN sync 202204090300
Diffstat (limited to 'graphics')
-rw-r--r--graphics/pgf/contrib/messagepassing/README.md28
-rw-r--r--graphics/pgf/contrib/messagepassing/messagepassing.dtx861
-rw-r--r--graphics/pgf/contrib/messagepassing/messagepassing.ins49
-rw-r--r--graphics/pgf/contrib/messagepassing/messagepassing.pdfbin0 -> 267669 bytes
-rw-r--r--graphics/pgf/contrib/robotarm/README.md3
-rw-r--r--graphics/pgf/contrib/robotarm/robotarm.dtx940
-rw-r--r--graphics/pgf/contrib/robotarm/robotarm.pdfbin0 -> 185467 bytes
-rw-r--r--graphics/pgf/contrib/robotarm/robotarm.sty375
8 files changed, 2256 insertions, 0 deletions
diff --git a/graphics/pgf/contrib/messagepassing/README.md b/graphics/pgf/contrib/messagepassing/README.md
new file mode 100644
index 0000000000..4af22705d4
--- /dev/null
+++ b/graphics/pgf/contrib/messagepassing/README.md
@@ -0,0 +1,28 @@
+# The `messagepassing` package
+
+This package provides an environement and commands to easily draw diagrams to represent communication protocols using message passing among processes.
+
+Processes are represented as horizontal (or vertical) lines, and communications as arrows between lines. The package also provides multiple macros to decorate those diagrams, for instance to annotate the diagram, to add crashes to the processes, checkpoints, etc..
+
+The package works on top of tikz, which makes it easy to add ad-hoc items using regular tikz commands.
+To use it, run the following commands:
+
+```
+$ latex messagepassing.ins
+$ pdflatex messagepassing.dtx
+```
+
+The first command generates the file messagepassing.sty that should be placed in the same folder than your main document. The second command generates the file messagepassing.pdf (you may require multiple runs to adjust internal references), which is the documentation for the package.
+
+
+## License
+
+This package is provided under the terms of the LaTeX Project Public License, version 1.3 or later.
+
+## Author
+
+The initial author of this package is Martin Vassor.
+
+## Related packages
+
+ - [msc](https://www.ctan.org/pkg/msc): used to typeset message sequence diagrams, according to the Recommendation Z.120 of the International Telecommunication Union;
diff --git a/graphics/pgf/contrib/messagepassing/messagepassing.dtx b/graphics/pgf/contrib/messagepassing/messagepassing.dtx
new file mode 100644
index 0000000000..3811f558a5
--- /dev/null
+++ b/graphics/pgf/contrib/messagepassing/messagepassing.dtx
@@ -0,0 +1,861 @@
+% \iffalse meta-comment
+% Copyright (C) 2022 by Martin Vassor
+% This file may be distributed and/or modified under the
+% conditions of the LaTeX Project Public License, either
+% version 1.3 of this license or (at your option) any later
+% version. The latest version of this license is in:
+%
+% http://www.latex-project.org/lppl.txt
+%
+% and version 1.3 or later is part of all distributions of
+% LaTeX version 2005/12/01 or later.
+%
+% \fi
+
+% \iffalse
+%<package> \NeedsTeXFormat{LaTeX2e}
+%<package> \ProvidesPackage{messagepassing}[2022/02/18 v1.0 A package to draw message passing diagrams]
+%<package> \RequirePackage{tikz}
+%<package> \usetikzlibrary{quotes, calc, arrows.meta}
+%<package> \RequirePackage{xparse}
+%<package> \RequirePackage{float}
+%
+
+%<*driver>
+\documentclass{ltxdoc}
+\usepackage{messagepassing}
+\usepackage[hidelinks]{hyperref}
+\usepackage{xspace}
+\usepackage[super]{nth}
+\usepackage{subcaption}
+\usepackage{listings}
+\lstset{
+ language=[LaTeX]{TeX},
+}
+\EnableCrossrefs
+\CodelineIndex
+\RecordChanges
+\begin{document}
+ \DocInput{messagepassing.dtx}
+\end{document}
+%</driver>
+% \fi
+
+% \CheckSum{0}
+%
+% \CharacterTable
+% {Upper-case \A\B\C\D\E\F\G\H\I\J\K\L\M\N\O\P\Q\R\S\T\U\V\W\X\Y\Z
+% Lower-case \a\b\c\d\e\f\g\h\i\j\k\l\m\n\o\p\q\r\s\t\u\v\w\x\y\z
+% Digits \0\1\2\3\4\5\6\7\8\9
+% Exclamation \! Double quote \" Hash (number) \#
+% Dollar \$ Percent \% Ampersand \&
+% Acute accent \' Left paren \( Right paren \)
+% Asterisk \* Plus \+ Comma \,
+% Minus \- Point \. Solidus \/
+% Colon \: Semicolon \; Less than \<
+% Equals \= Greater than \> Question mark \?
+% Commercial at \@ Left bracket \[ Backslash \\
+% Right bracket \] Circumflex \^ Underscore \_
+% Grave accent \` Left brace \{ Vertical bar \|
+% Right brace \} Tilde \~}
+%
+%
+% \changes{v1.0}{2022/02/18}{Initial version for publication}
+%
+% \GetFileInfo{messagepassing.sty}
+%
+% \title{The \textsf{messagepassing} package\thanks{This document
+% corresponds to \textsf{messagepassing}~\fileversion,
+% dated \filedate.}}
+% \author{Martin Vassor\\ \texttt{bromind+ctan@gresille.org}}
+%
+%
+% \maketitle
+% \tableofcontents
+% \newcommand{\TikZ}{Ti\textit{k}Z\xspace}
+
+% \section{Introduction}
+% This package provides an environment and associated macros to easily draw
+% message passing diagrams. For instance, Execution.~\ref{mp:ex1} shows the capabilities offered
+% by the package.
+%
+% \begin{messagepassing}[][An example of message passing][h][mp:ex1]
+% \newprocesswithlength{p}{9}
+% \newprocesswithlength{q}{9}
+% \newprocesswithlength{r}{5}
+% \crash{r}{5}{k}
+%
+% \checkpoint{p}{0}{c_p^0}
+% \checkpoint{q}{0}{c_q^0}
+% \checkpoint{r}{0}{c_r^0}
+% \checkpoint{p}{4}{c_p^1}
+%
+% \stateinterval{p}{0}{si_p^0}
+% \stateinterval{q}{0}{si_q^0}
+% \stateinterval{r}{0}{si_r^0}
+%
+% \sendwithstateinterval{p}{1}{q}{2}{si_q^1}
+% \sendwithstateinterval{r}{3}{q}{4}{si_q^2}
+% \sendwithstateintervalandname{q}{5}{p}{6}{si_p^1}{\(m\)}
+% \sendoutofband{q}{5}{r}{6}{\(m_\mathrm{copy}\)}
+% \stateinterval{r}{6}{si_r^0}
+% \restart{r}{6}{3}
+%
+% \annotate{r}{8}{restart}
+% \annotatexplicit{p}{8}{\(1+1=2\)}{note}
+%
+% \colouredbox{p}{q}{7}{9}{Protocol}
+%
+% \drawtimeline{9}
+% \end{messagepassing}
+
+%
+% \section{Usage}
+% \subsection{Loading the package}
+% The package accepts two options: \verb+vertical+ and \verb+annotatevertical+.
+% If the former is set, executions will be drawn with time going from top to
+% bottom, instead of from left to right. Doing so, almost all
+% labels\footnote{Annotations are not rotated, unless explicitly asked.} are
+% rotated as well. If, \emph{in addition}, \verb+annotatevertical+ is set, then
+% annotations (including named of colouredboxes) are rotated as well.
+
+% \subsection{Basic usage}
+% \subsubsection{Creating a diagram.}
+
+% \DescribeEnv{messagepassing} A diagram can easily be created using the
+% |messagepassing| environment. The syntax is:
+% |\begin{messagepassing}| \oarg{tikz} \oarg{caption} \oarg{placement}
+% \oarg{label}.
+% The first optional argument (\emph{tikz}) contains arguments that are passed
+% to the underlying tikz environment. The second argument (\emph{caption}) has
+% two effect: if set, it turns the diagram into a floating figure, and the
+% content of the argument is the caption of the floating figure. The third
+% argument (\emph{placement}) is the placement option of the figure, the default
+% is |p|. Finally, the fourth option (\emph{label}) is the label used to
+% reference the figure.
+%
+% For instance, the diagram in Figure~\ref{mp:ex1} is created with the following
+% commands:
+% \begin{verbatim}
+% \begin{messagepassing}[][An example of message passing][h][mp:ex1]
+% % ...
+% \end{messagepassing}
+% \end{verbatim}
+
+% \paragraph{Setting up the diagram.}
+% When created, the diagram is empty. Before actually writing the message
+% exchanges, we have to set up a few things: set whether we want a timeline (and
+% if it is the case, of which length), and set the number of processes with
+% their names, etc.
+% \subparagraph{Creating a new process.}
+% Each process is characterised by its name.
+% \DescribeMacro{\newprocess} The simplest macro to create a new process is then
+% |\newprocess| \marg{name}, where \marg{name} is the name of the process (resp.
+% \(p\), \(q\), and \(r\) in Figure~\ref{mp:ex1}).
+%
+% In addition, we often draw a horizontal\footnote{By default, the line is vertical if
+% the option |vertical| is used.} line that represent the running process.
+% Although this line can be manually
+% added\footnote{|processlength|\marg{process}\marg{length}
+% creates a line of length \emph{length} for process \emph{process}.}, we also
+% provide a simple macro that performs both actions:
+% \DescribeMacro{\newprocesswithlength}
+% |\newprocesswithlength|\marg{name}\marg{length}.
+%
+% An other alternative is to name the state in which the process starts (in
+% Fig~\ref{mp:ex1}, we call those states \(si\) as \emph{state intervals}).
+% Again, this can be achieved using individual commands, but we also provide
+% \DescribeMacro{\newprocesswithstateinterval}
+% |\newprocesswithstateinterval|\marg{name}\marg{state name}.
+%
+% Finally, an other way to create a process is to create a process that
+% (eventually) fails, which is represented by the process' line terminating
+% early with a cross. For that, we provide \DescribeMacro{\newprocesswithcrash}
+% |\newprocesswithcrash|\marg{name}\marg{length}\marg{crash coordinate name}.
+% The first two arguments are similar to |\newprocesswithlength|, and the latter
+% one is used to provide a name for the coordinate where the crash occurs. This
+% name can later be used to place nodes.
+%
+% Of course, we can imagine other combinations (e.g. a process with a length and
+% a state interval). We do not provide individual commands for each combination,
+% but the can be easily achieved using separate commands.
+%
+% As an example, the processes of Fig.~\ref{mp:ex1} are created as follows.
+% \begin{verbatim}
+% \newprocesswithlength{p}{9}
+% \newprocesswithlength{q}{9}
+% \newprocesswithlength{r}{5}
+% \end{verbatim}
+%
+% \subparagraph{Setting up a timeline.}
+% An other setup action consists in setting up (if wanted) the timeline. Notice
+% that this can be done \emph{at any place} in the diagram. To do so, simply use
+% the command \DescribeMacro{\drawtimeline}|\drawtimeline|\marg{length}, where
+% \emph{length} is the length of the desired timeline.
+
+% \subsubsection{Populating the run.}
+% Now that we have some processes, we have to populate the diagram with some
+% actions.
+%
+% \paragraph{Basic message.}
+% The most basic action is to send a message. For that, we provide the command
+% \DescribeMacro{\send} |\send|\marg{sender}\marg{send
+% time}\marg{receiver}\marg{receive time}. The sender and receiver are
+% identified with their names, and the sending and receiving times are given
+% according to their timestamp\footnote{Notice that nothing prevents sending
+% messages in the past, simply set a receiving time before the sending time.}.
+%
+% In addition, we can label the arrow with the message that is sent with
+% \DescribeMacro{\sendwithname}
+% |\sendwithname|\marg{sender}\marg{send time}\marg{receiver}\marg{receive
+% time}\marg{label}.
+% For instance, in Figure~\ref{fig:ex_msg}, we use |\send{p}{1}{q}{2}|.
+%
+% Finally, we sometimes distinguish \emph{out-of-band} messages, e.g. messages
+% that do not carry informations, but that are for instance used for metadata,
+% etc.. We provide the macro
+% \DescribeMacro{\sendoutofband}|\sendoutofband|\marg{sender}\marg{send time}\marg{receiver}\marg{receive
+% time}\marg{label}, which behaves similarly to |\sendwithname|, but prints the
+% message in an other colour.
+%
+% \begin{figure}
+% \centering
+% \begin{minipage}{.35\textwidth}
+% \begin{messagepassing}
+% \newprocesswithlength{p}{4}
+% \newprocesswithlength{q}{4}
+% \send{p}{1}{q}{2}
+% \sendwithname{p}{2}{q}{3}{msg}
+% \end{messagepassing}
+% \end{minipage}
+% ~
+% \begin{minipage}{.60\textwidth}
+% \iffalse
+%<*example>
+% \fi
+% \begin{lstlisting}
+\begin{messagepassing}
+ \newprocesswithlength{p}{4}
+ \newprocesswithlength{q}{4}
+ \send{p}{1}{q}{2}
+ \sendwithname{p}{2}{q}{3}{msg}
+\end{messagepassing}
+\end{lstlisting}
+% \iffalse
+%</example>
+% \fi
+% \end{minipage}
+% \caption{A very simple protocol with a single message exchanged.}
+% \label{fig:ex_msg}
+% \end{figure}
+%
+%
+
+% \paragraph{Process crash and restore.}
+% The crash of a process can be represented using
+% \DescribeMacro{\crash}
+% |\crash|\marg{process name}\marg{time}\marg{crash name}. The argument \emph{process name}
+% is the name of the process that crashes, and \emph{crash name} is used to give
+% a name to the crash. Naming the crash is useful for coordinates (see below).
+% Finally, \emph{time} specifies when the crash occurs. Notice that this does
+% not modify the timeline: it simply adds a crash token at the specified
+% coordinate. This means that (i) then timeline has to stop at the crash's time;
+% and (ii) it has to be restarted after. To stop the timeline, simply take the
+% crash into account when setting the initial timeline. To restart the timeline,
+% we provide the command
+% \DescribeMacro{\restart}|\restart|\marg{name}\marg{date}\marg{duration}.
+% \emph{name} specifies which process is to be restarted; \emph{date} specifies
+% when the process should be restarted, and \emph{duration} specifies how long
+% the process shoud be alive (i.e. what is the length of the timeline) after the
+% restart.
+% \begin{figure}
+% \centering
+% \begin{minipage}{.35\textwidth}
+% \begin{messagepassing}
+% \newprocesswithlength{p}{4}
+% \newprocesswithlength{q}{2}
+% \send{p}{1}{q}{2}
+% \crash{q}{2}{crash}
+% \restart{q}{3}{1}
+% \end{messagepassing}
+% \end{minipage}
+% ~
+% \begin{minipage}{.60\textwidth}
+% \iffalse
+%<*example>
+% \fi
+% \begin{lstlisting}
+ \begin{messagepassing}
+ \newprocesswithlength{p}{4}
+ \newprocesswithlength{q}{2}
+ \send{p}{1}{q}{2}
+ \crash{q}{2}{crash}
+ \restart{q}{3}{1}
+ \end{messagepassing}
+\end{lstlisting}
+% \iffalse
+%</example>
+% \fi
+% \end{minipage}
+% \caption{A protocol with a crashed process.}
+% \end{figure}
+%
+
+% \paragraph{Tokens on the run}
+%
+% The package also proposes two kinds of tokens that can be added on protocols'
+% lines. The first one is a \emph{checkpoint} (i.e. a state that is saved
+% somewhere) and the second is used to denote the begining of a \emph{state
+% interval} (a state interval denotes a period in which a process only performs
+% deterministic events). The former are denoted with a small black rectangle,
+% while the later is denoted with a vertical line. Although those two tokens are
+% intended for the usage mentionned above, we encourage users to use them for
+% other usages if need be.
+%
+% A checkpoint can be added with
+% \DescribeMacro{\checkpoint}|\checkpoint|\marg{process}\marg{time}\marg{name},
+% where \emph{process} is the name of the process which takes a checkpoint,
+% \emph{time} is the the time at which the checkpoint is taken, and \emph{name}
+% is the name of the checkpoint, that is printed next to it, and can be used as
+% a coordinate. Notice that the name is printed in a math environment, as we
+% expect most checkpoints names to be indexed, e.g.\(c_1\), \(c_2\), etc.
+% To have more control on the printed name, or if the proposed name is not a
+% valid coordinate name, we offer a variant
+% \DescribeMacro{\checkpointspecial}|\checkpointspecial|\marg{process}\marg{time}\marg{name}\marg{label},
+% where \emph{name} is the name of the coordinate of the checkpoint, and
+% \emph{label} is the label to be printed. Notice that, in that case, the label
+% is printed as is, i.e. not typeset as maths.
+
+%
+% A state interval can be added similarly with the command
+% \DescribeMacro{\stateinterval}|\stateinterval|
+% \marg{process}\marg{time}\marg{name}.
+%
+% For the sake of completeness, if you need the name of the coordinate and the
+% displayed label to be different (e.g. if the label can not be the name of a
+% coordinate, for whatever reason), we also provide the command
+% \DescribeMacro{\stateintervalspecial}
+% |\stateintervalspecial|\marg{process}\marg{time}\marg{name}\marg{label}, in
+% which \emph{name} is the name of the created coordinate, and \emph{label} is
+% the label attached to the state interval.
+
+% \begin{figure}
+% \centering
+% \begin{minipage}{.35\textwidth}
+% \begin{messagepassing}
+% \newprocesswithlength{q}{2}
+% \checkpoint{q}{1}{c_1}
+% \crash{q}{2}{crash}
+% \restart{q}{3}{1}
+% \end{messagepassing}
+% \end{minipage}
+% ~
+% \begin{minipage}{.60\textwidth}
+% \iffalse
+%<*example>
+% \fi
+% \begin{lstlisting}
+ \begin{messagepassing}
+ \newprocesswithlength{q}{2}
+ \checkpoint{q}{1}{c_1}
+ \crash{q}{2}{crash}
+ \restart{q}{3}{1}
+ \end{messagepassing}
+\end{lstlisting}
+% \iffalse
+%</example>
+% \fi
+% \end{minipage}
+% \caption{A protocol with a checkpoint.}
+% \end{figure}
+
+% \paragraph{Grey boxes}
+%
+% In Execution~\ref{mp:ex1}, we created a light-red box between processes \(p\)
+% and \(q\), from time \(7\) to \(9\), to indicate that they perform a given
+% protocol that we don't detail further. We call such boxes (which can be used for a lot
+% of other purposes) \emph{colouredboxes}, and they
+% can be added with \DescribeMacro{\colouredbox} |\colouredbox|\marg{first
+% process}\marg{second process}\marg{start time}\marg{end time}\marg{label}.
+% This creates a box that spans between \emph{first process} and \emph{second
+% process}, from \emph{start time} to \emph{end time}, with the label
+% \emph{label} printed.
+%
+% Notice that there are no technical restrictions to adding messages on top of a
+% box, typically to highlight a specific part of a larger execution.
+
+% \paragraph{Annotations}
+% Finally, it is possible to add annotations on the diagram. To do so, we
+% provide the macro
+% \DescribeMacro{\annotate}|\annotate|\marg{process}\marg{time}\marg{text} which
+% adds an annotation with \emph{text} over the timeline of the given
+% \emph{process} at time \emph{time}. This also creates a coordinate at the
+% annotation time, which name is the content of the annotation (i.e.\
+% \emph{text}). If \emph{text} is not a valid coordinate name, then the
+% alternative \DescribeMacro{\annotatexplicit}
+% |\annotatexplicit|\marg{process}\marg{time}\marg{text}\marg{name} behaves
+% similarly, except that the coordinate name is explicitly given in argument
+% \emph{name}.
+
+% \subsubsection{Combined commands}
+% The above commands are sufficient to use all primitives offered by the
+% package. In addition, we provide a lot of \emph{combined commands}, which, as
+% the name suggest, have the effect of multiple \emph{simple} commands.
+%
+% \begin{itemize}
+% \item |\newprocesswithlength|\marg{name}\marg{lifetime}: combination of
+% |\newprocess|\marg{name} and |\processlength|\marg{name}\marg{lifetime}
+% \item |\newprocesswithstateinterval|\marg{process name}\marg{state interval
+% name}: combination of |\newprocess|\marg{process name} and
+% |\stateinterval|\marg{process name}\marg{0}\marg{state interval name}
+% \item |\newprocesswithcrash|\marg{process name}\marg{crash time}\marg{crash
+% name}: creates a process \emph{process name} that runs until \emph{crash
+% time}. The crash is named \emph{crash name}.
+% \item |\sendwithstateinterval|\marg{sender}\marg{send
+% time}\marg{receiver}\marg{receive time}\marg{si name}: combines |\send| and
+% |\stateinterval|.
+% \item |\sendwithstateintervalandname|\marg{sender}\marg{send
+% time}\marg{receiver}\marg{receive time}\marg{si name}\marg{message name}:
+% combines |\sendwithname| and |\stateinterval|
+% \end{itemize}
+
+% \subsection{Advanced usage}
+% \subsubsection{Customising colours}
+%
+% Two parts of the package use colours: colouredboxes and out-of-band messages. By
+% default both are shades of red. We provide commands to change that if desired.
+%
+% \DescribeMacro{\colouredboxcolor}|\colouredboxcolor|\marg{colour} changes the colour
+% used for colouredboxes. Notice that this sets both the background colour (which is
+% a light variant of the provided colour) and the text colour (which uses the
+% provided colour).
+%
+% \DescribeMacro{\oobcolor}|\oobcolor|\marg{colour} changes the colour used for
+% out-of-band messages.
+%
+% \subsubsection{Coordinates}
+%
+% \paragraph{\TikZ coordinates.}
+% Message passing diagrams are drawn using \TikZ, which means that one can add
+% arbitrary commands to a diagram. In addition, the package defines useful
+% coordinates to refer to. Execution~\ref{mp:ex2} shows the \TikZ coordinate plan
+% overlayed on top of Execution~\ref{mp:ex1}.
+%
+% On \TikZ \(y\)-axis processes are instanciated one unit apart from each other,
+% in their declaration order.
+% To keep the coordinate system simple, processes expand in the negative (e.g.
+% the first process declared is at coordinate \((0, -1)\), the second at \((0,
+% -2)\), etc.).
+%
+% The \TikZ \(x\)-axis corresponds to the time axis of the diagram. Therefore,
+% e.g. coordinate \((3, -4)\) corresponds to the \nth{3} time step of the
+% \nth{4} process.
+%
+% \paragraph{Named coordinates.}
+% In addition to explicit coordinates explained above, the package names most of
+% the points of interest in the diagram.
+%
+% \subparagraph{Coordinates of processes.}
+% At each process declaration, a coordinate named after the name of the process
+% is created. The coordinate corresponds to the beginning of the corresponding
+% process' timeline (for instance, in Execution~\ref{mp:ex2}, we show coordinate
+% \((\texttt{q})\), that corresponds to the process \(q\)).
+%
+% \subparagraph{Coordinate of states intervals (resp. checkpoints, resp. crashes).}
+% Similarly to processes, each state interval (resp. checkpoint, resp. crashes) creates a
+% coordinate, named after the name of the state interval (resp. checkpoint,
+% resp. crashes), is created. The coordinates refers to the place of the state
+% interval (resp. checkpoint, resp. crashes). For instance, in
+% Execution~\ref{mp:ex2}, we show the coordinates \((\texttt{si\_q\^{}1})\),
+% \((\texttt{c\_p\^{}1})\) and \((\texttt{k})\), that respectively correspond to the state interval
+% \(si_q^1\), the checkpoint \(c_p^1\) and the crash\footnote{The names of
+% crashes are not printed on the figure, although they are internally defined.} \(k\).
+%
+% \subparagraph{Coordinates of annotations.}
+% When an annotation is created, a coordinate is created at the same place, on
+% the process' timeline\footnote{Notice that, using the explicit variant of |annotate|
+% (|annotatexplicit|), the name of the annotation has to be explicitly given.}
+% For instance, in Execution~\ref{mp:ex1}, the annotation \(1+1=2\) is created
+% with the explicit name ``\texttt{note}''. We show the corresponding coordinate in
+% Execution~\ref{mp:ex2}.
+%
+%
+% \begin{messagepassing}[][Showing \TikZ coordinates][h][mp:ex2]
+% \newprocesswithlength{p}{9}
+% \newprocesswithlength{q}{9}
+% \newprocesswithlength{r}{5}
+% \crash{r}{5}{k}
+%
+% \checkpoint{p}{0}{c_p^0}
+% \checkpoint{q}{0}{c_q^0}
+% \checkpoint{r}{0}{c_r^0}
+% \checkpoint{p}{4}{c_p^1}
+%
+% \stateinterval{p}{0}{si_p^0}
+% \stateinterval{q}{0}{si_q^0}
+% \stateinterval{r}{0}{si_r^0}
+%
+% \sendwithstateinterval{p}{1}{q}{2}{si_q^1}
+% \sendwithstateinterval{r}{3}{q}{4}{si_q^2}
+% \sendwithstateintervalandname{q}{5}{p}{6}{si_p^1}{\(m\)}
+% \sendoutofband{q}{5}{r}{6}{\(m_\mathrm{copy}\)}
+% \stateinterval{r}{6}{si_r^0}
+% \restart{r}{6}{3}
+%
+% \annotate{r}{8}{restart}
+% \annotatexplicit{p}{8}{\(1+1=2\)}{note}
+%
+% \colouredbox{p}{q}{7}{9}{Protocol}
+% \drawtimeline{9}
+%
+%
+% \fill[fill=white, opacity=0.8] (-1, 0) rectangle (10, -5);
+%
+% \draw[dotted, gray] (-1,0) grid (10,-5);
+% \draw[->, thick, red] (0, 0) -- (1, 0) node [anchor=south, text=black] {\((1, 0)\)};
+% \draw[->, thick, red] (0, 0) -- (0, -1) node [anchor=east, text=black] {\((0, -1)\)};
+%
+% \draw[fill] (q) circle [radius=.5mm];
+% \node[anchor=east] at (q) {\((\texttt{q})\)};
+%
+% \draw[fill] (si_q^1) circle [radius=.5mm];
+% \node[anchor=east] at (si_q^1) {\((\texttt{si\_q\^{}1})\)};
+%
+% \draw[fill] (c_p^1) circle [radius=.5mm];
+% \node[anchor=east] at (c_p^1) {\((\texttt{c\_p\^{}1})\)};
+%
+% \draw[fill] (k) circle [radius=.5mm];
+% \node[anchor=east] at (k) {\((\texttt{k})\)};
+%
+% \draw[fill] (note) circle [radius=.5mm];
+% \node[anchor=east] at (note) {\((\texttt{note})\)};
+%
+% \end{messagepassing}
+
+% \StopEventually{}
+%
+% \section{Implementation}
+
+% \begin{macrocode}
+\newcounter{processnb}
+\setcounter{processnb}{0}
+\newcounter{maxtime}
+
+\pgfdeclarelayer{background}
+\pgfsetlayers{background,main}
+
+\newfloat{float_messagepassing}{t b h p}{.mp}
+\floatname{float_messagepassing}{Execution}
+
+\newif\ifmp@vertical\mp@verticalfalse
+\DeclareOption{vertical}{
+ \mp@verticaltrue
+}
+\newif\ifmp@annotatevertical\mp@annotateverticalfalse
+\DeclareOption{annotatevertical}{
+ \mp@annotateverticaltrue
+}
+\ProcessOptions\relax
+
+\ifmp@vertical
+ \newcommand{\mp@processnameanchor}{south}
+ \newcommand{\mp@timeticksanchor}{east}
+ \newcommand{\mp@messagelabelanchor}{south}
+ \newcommand{\mp@stateintervalanchor}{north west}
+ \newcommand{\mp@checkpointanchor}{east}
+ \newcommand{\mp@verticalrotation}{270}
+ \ifmp@annotatevertical
+ \newcommand{\mp@annotaterotation}{270}
+ \else
+ \newcommand{\mp@annotaterotation}{0}
+ \fi
+\else
+ \newcommand{\mp@processnameanchor}{east}
+ \newcommand{\mp@timeticksanchor}{north}
+ \newcommand{\mp@messagelabelanchor}{west}
+ \newcommand{\mp@stateintervalanchor}{south west}
+ \newcommand{\mp@checkpointanchor}{north}
+ \newcommand{\mp@verticalrotation}{0}
+ \newcommand{\mp@annotaterotation}{0}
+\fi
+
+\newcommand{\mp@oobcolor}{red}
+\newcommand{\oobcolor}[1]{
+ \renewcommand\mp@oobcolor{#1}
+}
+
+\newcommand{\mp@colouredboxcolor}{red}
+\newcommand{\colouredboxcolor}[1]{
+ \renewcommand\mp@colouredboxcolor{#1}
+}
+
+\newif\iftimeline
+% \end{macrocode}
+%
+
+%\begin{environment}{messagepassing}
+% \begin{macrocode}
+\ExplSyntaxOn
+%% 1st argument: tikz arguments
+%% 2nd argument: Float caption (turns in floating)
+%% 3rd argument: Float placement (`p` by default)
+%% 4th argument: Float label
+ \NewDocumentEnvironment{messagepassing} {o o o o}
+ {
+ \timelinefalse
+ \setcounter{processnb}{0}
+ \IfNoValueTF{#2} {
+ }{
+ \IfNoValueTF{#3}{
+ \begin{float_messagepassing}[p]
+ } {
+ \begin{float_messagepassing}[#3]
+ }
+ \begin{center}
+ }
+ \IfNoValueTF{#1}{
+ \begin{tikzpicture}[rotate=\mp@verticalrotation]
+ } {
+ \begin{tikzpicture}[rotate=\mp@verticalrotation, #1]
+ }
+ }{
+ %% Draw timeline if boolean is true
+ \iftimeline
+ \begin{pgfonlayer}{background}
+ \setcounter{maxtime}{\@maxtime}
+ \addtocounter{maxtime}{-1}
+ \coordinate (maxtime) at (\@maxtime, 0);
+
+ \addtocounter{processnb}{1}
+ \coordinate (timeline) at (0, -\value{processnb});
+ \draw (timeline) node [anchor=\mp@processnameanchor] {{\it time}};
+ \draw[->] (timeline) -- ($(timeline) + (maxtime)$);
+ \foreach \i in {0,...,\value{maxtime}} {
+ \draw ($(timeline) + (\i, 0) + (0, 0.1)$) -- ($(timeline) + (\i, 0) + (0, -0.1)$) node [anchor=\mp@timeticksanchor] {$\i$};
+ }
+ \end{pgfonlayer}
+ \else
+ \fi
+ \end{tikzpicture}
+ \IfNoValueTF{#2} {
+ \linebreak
+ } {
+ \end{center}
+ \caption{#2}
+ \IfNoValueTF{#4} {
+ }{
+ \label{#4}
+ }
+ \end{float_messagepassing}
+ }
+ }
+\ExplSyntaxOff
+% \end{macrocode}
+% \end{environment}
+%
+% \begin{macrocode}
+%% #1: name
+\newcommand{\newprocess}[1]{
+ \addtocounter{processnb}{1}
+ \coordinate (#1) at (0, -\value{processnb});
+ \draw (#1) node[anchor=\mp@processnameanchor] {$#1$};
+}
+% \end{macrocode}
+%
+% \begin{macrocode}
+%% #1: name
+%% #2: width
+\newcommand{\newprocesswithlength}[2]{
+ \newprocess{#1}
+ \processlength{#1}{#2}
+}
+% \end{macrocode}
+%
+% \begin{macrocode}
+%% #1: name
+%% #2: state interval name
+\newcommand{\newprocesswithstateinterval}[2]{
+ \newprocess{#1}
+ \stateinterval{#1}{0}{#2}
+}
+% \end{macrocode}
+%
+% \begin{macrocode}
+%% #1: name
+%% #2: width
+%% #3: crash name
+\newcommand{\newprocesswithcrash}[3]{
+ \newprocess{#1}{#2}
+ \crash{#1}{#2}{#3}
+}
+% \end{macrocode}
+%
+% \begin{macrocode}
+%% #1: sender's name
+%% #2: send date
+%% #3: receiver's name
+%% #4: receive date
+\newcommand{\send}[4]{
+ \draw[->] (#1) +(#2, 0) -- ($ (#3) +(#4, 0) $);
+}
+% \end{macrocode}
+%
+% \begin{macrocode}
+%% #1: sender's name
+%% #2: send date
+%% #3: receiver's name
+%% #4: receive date
+%% #5: message name
+\newcommand{\sendwithname}[5]{
+ \draw[->] (#1) +(#2, 0) -- ($ (#3) +(#4, 0) $) node[anchor=\mp@messagelabelanchor, pos=0.3] {#5};
+}
+% \end{macrocode}
+%
+% \begin{macrocode}
+%% #1: process name
+%% #2: process width
+\newcommand{\processlength}[2]{
+ \draw (#1) -- +(#2, 0);
+}
+% \end{macrocode}
+%
+% \begin{macrocode}
+%% #1: sender's name
+%% #2: send date
+%% #3: receiver's name
+%% #4: receive date
+%% #5: state interval name
+\newcommand{\sendwithstateinterval}[5] {
+ \send{#1}{#2}{#3}{#4}
+ \stateinterval{#3}{#4}{#5}
+}
+% \end{macrocode}
+%
+% \begin{macrocode}
+%% #1: sender's name
+%% #2: send date
+%% #3: receiver's name
+%% #4: receive date
+%% #5: state interval name
+%% #6: message name
+\newcommand{\sendwithstateintervalandname}[6] {
+ \sendwithname{#1}{#2}{#3}{#4}{#6}
+ \stateinterval{#3}{#4}{#5}
+}
+% \end{macrocode}
+%
+% \begin{macrocode}
+%% #1: sender's name
+%% #2: send date
+%% #3: receiver's name
+%% #4: receive date
+%% #5: OoB message name
+\newcommand{\sendoutofband}[5]{
+ \draw[->, color=\mp@oobcolor] (#1) +(#2, 0) -- ($ (#3) +(#4, 0) $) node[anchor=\mp@messagelabelanchor, pos=0.3] {#5};
+}
+% \end{macrocode}
+%
+% \begin{macrocode}
+%% #1: process's name
+%% #2: state interval date
+%% #3: state interval name
+\newcommand{\stateinterval}[3] {
+ \stateintervalspecial{#1}{#2}{#3}{#3}
+}
+% \end{macrocode}
+%
+% \begin{macrocode}
+%% #1: process's name
+%% #2: state interval date
+%% #3: coordinate name
+%% #4: state interval label
+\newcommand{\stateintervalspecial}[4] {
+ \coordinate (#3) at ($ (#1) +(#2, 0) $);
+ \draw (#3) + (0, 0.1) -- +(0, -0.1) node[anchor=\mp@stateintervalanchor] {$#4$};
+}
+% \end{macrocode}
+%
+% \begin{macrocode}
+%% #1: process's name
+%% #2: checkpoint date
+%% #3: checkpoint name
+\newcommand{\checkpoint}[3]{
+ \coordinate (#3) at ($ (#1) + (#2, 0) $);
+ \fill (#3) + (-0.05, 0.1) rectangle +(0.05, -0.1);
+ \draw (#3) + (0, -0.1) node[anchor=\mp@checkpointanchor] {$#3$};
+}
+% \end{macrocode}
+%
+% \begin{macrocode}
+%% #1: process's name
+%% #2: checkpoint date
+%% #3: checkpoint coordinate name
+%% #4: checkpoint label
+\newcommand{\checkpointspecial}[4]{
+ \coordinate (#3) at ($ (#1) + (#2, 0) $);
+ \fill (#3) + (-0.05, 0.1) rectangle +(0.05, -0.1);
+ \draw (#3) + (0, -0.1) node[anchor=\mp@checkpointanchor] {#4};
+}
+% \end{macrocode}
+%
+% \begin{macrocode}
+%% #1: process's name
+%% #2: crash date
+%% #3: crash name
+\newcommand{\crash}[3]{
+ \coordinate (#3) at ($ (#1) + (#2, 0) $);
+ \draw (#3) + (-0.1, -0.1) -- +(0.1, 0.1);
+ \draw (#3) + (0.1, -0.1) -- +(-0.1, 0.1);
+}
+% \end{macrocode}
+%
+% \begin{macrocode}
+%% #1: process's name
+%% #2: restart date
+%% #3: restart length
+\newcommand{\restart}[3]{
+ \draw (#1) + (#2, 0) -- ($ (#1) + (#2, 0) + (#3, 0) $);
+}
+% \end{macrocode}
+%
+% \begin{macrocode}
+%% #1: first process's name
+%% #2: second process's name
+%% #3: begining of the grey box
+%% #4: end of the grey box
+%% #5: caption
+\newcommand{\colouredbox}[5]{
+ \begin{pgfonlayer}{background}
+ \fill[color=\mp@colouredboxcolor!20] ($(#1) + (#3, 0)$) rectangle ($(#2) + (#4, 0)$) node[midway, color = \mp@colouredboxcolor, rotate=\mp@annotaterotation]{#5};
+ \end{pgfonlayer}
+}
+% \end{macrocode}
+%
+% \begin{macrocode}
+%% #1: Timeline length
+\newcommand{\drawtimeline}[1]{
+ \timelinetrue
+ \def\@maxtime{#1}
+}
+% \end{macrocode}
+%
+% \begin{macrocode}
+%% #1: process's name
+%% #2: annotation date
+%% #3: annotation
+\newcommand{\annotate}[3]{
+ \annotatexplicit{#1}{#2}{#3}{#3}
+}
+% \end{macrocode}
+%
+% \begin{macrocode}
+%% Same than annotate, but with the coordinate name provided explicitly
+%% #1: process's name
+%% #2: annotation date
+%% #3: annotation
+%% #4: coordinate name
+\newcommand{\annotatexplicit}[4]{
+ \coordinate (#4) at ($ (#1) +(#2, 0.1) $);
+ \draw (#4) node[rotate=\mp@annotaterotation, anchor=south] {#3};
+}
+% \end{macrocode}
diff --git a/graphics/pgf/contrib/messagepassing/messagepassing.ins b/graphics/pgf/contrib/messagepassing/messagepassing.ins
new file mode 100644
index 0000000000..750bc28697
--- /dev/null
+++ b/graphics/pgf/contrib/messagepassing/messagepassing.ins
@@ -0,0 +1,49 @@
+%%
+%% Copyright (C) 2021 by Martin Vassor
+%%
+
+%% This file may be distributed and/or modified under the
+%% conditions of the LaTeX Project Public License, either
+%% version 1.3 of this license or (at your option) any later
+%% version. The latest version of this license is in:
+%%
+%% http://www.latex-project.org/lppl.txt
+%%
+%% and version 1.3 or later is part of all distributions of
+%% LaTeX version 2005/12/01 or later.
+%%
+
+\input docstrip.tex
+\keepsilent
+\usedir{tex/latex/messagepassing}
+\preamble
+This is a generated file.
+Copyright (C) 2022 by Martin Vassor
+
+This file may be distributed and/or modified under the
+conditions of the LaTeX Project Public License, either
+version 1.3 of this license or (at your option) any later
+version. The latest version of this license is in:
+
+ http://www.latex-project.org/lppl.txt
+
+and version 1.3 or later is part of all distributions of
+LaTeX version 2005/12/01 or later.
+
+\endpreamble
+
+\generate{\file{messagepassing.sty}{\from{messagepassing.dtx}{package}}}
+
+\Msg{*********************************************************}
+\Msg{*}
+\Msg{* To finish the installation you have to move the}
+\Msg{* following file into a directory searched by TeX:}
+\Msg{*}
+\Msg{* \space\space messagepassing.sty}
+\Msg{*}
+\Msg{* To produce the documentation run the file grammar.dtx}
+\Msg{* through LaTeX.}
+\Msg{*}
+\Msg{* Happy TeXing!}
+\Msg{*********************************************************}
+\endbatchfile
diff --git a/graphics/pgf/contrib/messagepassing/messagepassing.pdf b/graphics/pgf/contrib/messagepassing/messagepassing.pdf
new file mode 100644
index 0000000000..410b4d22ca
--- /dev/null
+++ b/graphics/pgf/contrib/messagepassing/messagepassing.pdf
Binary files differ
diff --git a/graphics/pgf/contrib/robotarm/README.md b/graphics/pgf/contrib/robotarm/README.md
new file mode 100644
index 0000000000..f95f712205
--- /dev/null
+++ b/graphics/pgf/contrib/robotarm/README.md
@@ -0,0 +1,3 @@
+# `robotarm` LaTeX package
+
+This LaTeX package uses Tikz to draw parameterized 2D robot arms, for example to be used in educational material. \ No newline at end of file
diff --git a/graphics/pgf/contrib/robotarm/robotarm.dtx b/graphics/pgf/contrib/robotarm/robotarm.dtx
new file mode 100644
index 0000000000..79986b388f
--- /dev/null
+++ b/graphics/pgf/contrib/robotarm/robotarm.dtx
@@ -0,0 +1,940 @@
+% \iffalse meta-comment
+%
+% Copyright (C) 2021 by M.J.W. Snippe
+% -----------------------------------
+%
+% This work may be distributed and/or modified under the
+% conditions of the LaTeX Project Public License, either version 1.3
+% of this license or (at your option) any later version.
+% The latest version of this license is in
+%
+% http://www.latex-project.org/lppl.txt
+%
+% and version 1.3 or later is part of all distributions of LaTeX
+% version 2005/12/01 or later.
+%
+% This work has the LPPL maintenance status `author-maintained'.
+%
+% This work consists of the files found at github.com/max-sn/robotarm.
+%
+% \fi
+%
+% \iffalse
+%<*driver>
+\documentclass{ltxdoc}
+\input{robotarm.doc.settings.sty}
+\EnableCrossrefs
+\RecordChanges
+\begin{document}
+ \DocInput{robotarm.dtx}
+\end{document}
+%</driver>
+%
+% \fi
+%
+% \iffalse
+%
+%<*robotarm-doc-settings>
+
+\usepackage[utf8]{inputenc}
+\usepackage{xspace}
+\usepackage{multicol}
+\usepackage{geometry}
+\usepackage{mathpazo}
+\usepackage{robotarm}
+\usepackage{biblatex}
+\usepackage{hypdoc}
+\usepackage{tcolorbox}
+
+\addbibresource{robotarm.doc.bib.bib}
+\defbibheading{robotarmbibheading}[\bibname]{%
+ \clearpage\section*{#1}\addcontentsline{toc}{section}{#1}}
+
+\geometry{pass}
+
+\tcbuselibrary{documentation,breakable,minted}
+\tcbset{
+ index german settings,
+ index colorize,
+ docexample/.append style={
+ before lower={\begin{center}\begin{tikzpicture}},
+ after lower={\end{tikzpicture}\end{center}},
+ documentation minted options={autogobble},
+ breakable,
+ }
+}
+
+\makeindex
+
+\renewcommand{\MacroFont}{\color{black!70!blue}\small\ttfamily}
+
+\def\robotarmpackage{\textsl{robotarm}\xspace}
+\def\Tikz{{\normalfont Ti\textit{k}Z}\xspace}
+
+%</robotarm-doc-settings>
+%
+%<*robotarm-doc-main>
+
+\title{The \robotarmpackage package}
+\author{Marcus J.W. Snippe \\
+ \normalsize\href{mailto:maxsnippe@gmail.nl}
+ {\texttt{maxsnippe[at]gmail.nl}}}
+\date{\filedate\\[0.4em]\normalsize\fileversion}
+
+\maketitle
+
+\begin{abstract}
+ With the \robotarmpackage package, you can draw configurable planar robot arms with ease, using \Tikz. It defines the macro (\refCom{robotArm}) and a lot of ways to configure it. Additionally, you can use or redefine the macros used to draw the base link (\refCom{robotArmBaseLink}), a single link (\refCom{robotArmLink}), or the end effector (\refCom{robotArmEndEffector}).
+\end{abstract}
+
+\begin{multicols}{2}
+ \tableofcontents
+\end{multicols}
+
+\section{Macros}
+
+ \subsection{\texttt{robotArm}}
+
+ \begin{docCommand}{robotArm}{\oarg{key-value list}\marg{num}}
+ This is the main macro of the \robotarmpackage package. It is meant to be used in the \texttt{tikzpicture} environment\footnote{The first example still includes the \texttt{tikzpicture} environment, but for following examples,it will be omitted in the example code.}, from the \Tikz\cite{tantau:tikz_and_pgf} package,
+ and installs some styles for additional drawing, e.g. \refKey{/tikz/in link}.
+
+ \begin{dispExample*}{before lower={}, after lower={}}
+ \begin{tikzpicture}
+ \robotArm[config={q1=60,q2=-40,q3=-50}]{3}
+ \end{tikzpicture}
+ \end{dispExample*}
+
+ \meta{num} defines the number of links that will be drawn. For an $N$ link robot arm, the $N$\textsuperscript{th} link will be the end effector link.
+
+ The \meta{key-value list} values can consist of the keys listed below.
+
+
+
+ \begin{docKey}{geometry}{=\meta{key-value list}}{}
+
+ The \refKey{geometry} key can be used to set geometrical configuration options of the robot arm, e.g. link length and link width. The keys in \meta{key-value list} can be one or more of the following.
+
+ ^^A \begin{docKey}[][doc label=/geometry/a0]{a0}{=\meta{value}}{initially \texttt{0.0}}
+ ^^A Sets the height of the base link.
+
+ ^^A \begin{dispExample}
+ ^^A \robotArm[config={q1=60},geometry={a0=2}]{2}
+ ^^A \end{dispExample}
+ ^^A \end{docKey}
+
+ \begin{docKeys}
+ [
+ doc parameter={=\meta{value}},
+ ]
+ {
+ {
+ doc name=a,
+ doc label=/geometry/a,
+ doc description={initially \texttt{2}}
+ },
+ {
+ doc name=a\meta{num},
+ doc label=/geometry/anum,
+ doc description={initially the value of \refKey{/geometry/a}}
+ },
+ }
+
+ The \refKey{/geometry/a} key sets the default length for all links that are drawn in the \refCom{robotArm} command. For every link, this can be overruled by the dynamically created keys \refKey{/geometry/anum}, e.g. to set only the length of link 3 to 3, use \texttt{a3=3}.
+
+ \begin{dispExample}
+ \robotArm[config={q1=20,q2=-20,q3=-20},
+ geometry={a=3,a3=1}]{3}
+ \end{dispExample}
+ \end{docKeys}
+
+ \begin{docKeys}
+ [
+ doc parameter={=\meta{value}}
+ ]
+ {
+ {
+ doc name=r,
+ doc label=/geometry/r,
+ doc description={initially \texttt{0.25}}
+ },
+ {
+ doc name=r\meta{num},
+ doc label=/geometry/rnum,
+ doc description={initially the value of \refKey{/geometry/r}}
+ },
+ }
+ The \refKey{/geometry/r} key sets the default joint radius for all links drawn in the \refCom{robotArm} command. For every link this can be overruled by the dynamically created keys \refKey{/geometry/rnum}.
+
+ \begin{dispExample}
+ \robotArm[config={q1=20,q2=-20},
+ geometry={r=0.5,r1=0.3}]{2}
+ \end{dispExample}
+ \end{docKeys}
+
+ \begin{docKeys}
+ [
+ doc parameter={=\meta{value}}
+ ]
+ {
+ {
+ doc name=w,
+ doc label=/geometry/w,
+ doc description={initially \texttt{0.4}}
+ },
+ {
+ doc name=w\meta{num},
+ doc label=/geometry/wnum,
+ doc description={initially the value of \refKey{/geometry/w}}
+ },
+ }
+ The \refKey{/geometry/w} key sets the default link width for all links drawn in the \refCom{robotArm} command. For every link this can be overruled by the dynamically created keys \refKey{/geometry/wnum}.
+ \end{docKeys}
+
+ \end{docKey}
+
+ \begin{dispExample}
+ \tikzset{/robotarm/geometry={a=1}}
+ \robotArm{1}
+ \begin{scope}[xshift=3cm]
+ \robotArm{6}
+ \end{scope}
+ \end{dispExample}
+
+ \begin{docKey}[robotarm/styles]{link}{}{default \texttt{draw,fill=lightgray}}
+ \end{docKey}
+
+ \end{docCommand}
+
+ \subsection{\texttt{robotArmBaseLink}}
+
+ \begin{docCommand}{robotArmBaseLink}{\oarg{key-value list}}
+ This command is used in \refCom{robotArm} to draw the base link. It can also be used to draw your own base link. The default base link looks as follows:
+ \begin{dispExample}
+ \robotArmBaseLink
+ \end{dispExample}
+ The \meta{key-value list} can consist of the keys listed below.
+
+ \begin{docKeys}
+ [
+ doc keypath={robotarm/base link},
+ doc parameter={=\meta{value}},
+ ]
+ {
+ {
+ doc name=height,
+ doc description={initially \texttt{0.6}}
+ },
+ {
+ doc name=width,
+ doc description={initially \texttt{0.3}}
+ },
+ }
+ The width and height of the base link can be specified with these keys. The height is measured from the center of the half-circle at the top, to the base.
+ \begin{dispExample}
+ \robotArmBaseLink[width=1, height=0.6]
+ \end{dispExample}
+ \end{docKeys}
+
+ \begin{docKeys}
+ [
+ doc keypath={robotarm/base link},
+ doc parameter={=\meta{value}},
+ ]
+ {
+ {
+ doc name=world width,
+ doc description={initially \texttt{1.0}},
+ },
+ {
+ doc name=world height,
+ doc description={initially \texttt{0.3}},
+ }
+ }
+ The width and height of the `world' drawn below the base link can be specified with these keys.
+ \begin{dispExample}
+ \robotArmBaseLink[world width=5, world height=1]
+ \end{dispExample}
+ \end{docKeys}
+
+ \begin{docKeys}
+ [
+ doc keypath={robotarm/base link},
+ doc description={code executing key},
+ ]
+ {
+ {doc name=draw base link},
+ {doc name=draw world},
+ }
+ These keys are used to draw the `world' and the base link. If the configuration options above are insufficient, you can redefine these keys, as shown in the not-so-creative example below.
+ \begin{dispExample}
+ \robotArmBaseLink[
+ draw world/.code={
+ \filldraw[fill=brown] (-2,-1) rectangle (2, -0.3);
+ },
+ draw base link/.code={
+ \filldraw[fill=black!60] (-0.5, -0.3) rectangle
+ (0.5, 0.3);
+ }]
+ \end{dispExample}
+ To access the values of the keys listed above you can use the following macros in your redefinition:
+ \begin{itemize}
+ \item \docAuxCommand{RA@baselink@width},
+ \item \docAuxCommand{RA@baselink@height},
+ \item \docAuxCommand{RA@baselink@worldwidth}, and
+ \item \docAuxCommand{RA@baselink@worldheight}.
+ \end{itemize}
+ \end{docKeys}
+
+ \end{docCommand}
+
+
+ \subsection{\texttt{robotArmLink}}
+
+ \begin{docCommand}{robotArmLink}{\oarg{key-value list}}
+ This command is used in \refCom{robotArm} to draw the links in a \texttt{foreach} loop. It can also be used to draw your own link(s). The default link looks as follows:
+ \begin{dispExample}
+ \robotArmLink
+ \end{dispExample}
+ The \meta{key-value list} can consist of the keys listed below.
+
+ \begin{docKeys}
+ [
+ doc keypath={robotarm/link},
+ doc parameter={=\meta{value}},
+ ]{
+ {
+ doc name=width,
+ doc description={initially \texttt{0.4}},
+ },
+ {
+ doc name=length,
+ doc description={initially \texttt{2.0}},
+ },
+ {
+ doc name=joint radius,
+ doc description={initially \texttt{0.25}},
+ },
+ }
+ The geometrical properties of the links can be configured with these keys.
+ \begin{dispExample}
+ \robotArmLink[width=0.75,joint radius=0.4,length=5]
+ \end{dispExample}
+ \end{docKeys}
+
+ \begin{docKeys}
+ [
+ doc keypath={robotarm/link},
+ doc description={code executing key},
+ ]
+ {
+ {doc name=draw link},
+ {doc name=draw joint},
+ }
+ Same as for the base link, the actual drawing is done by calling these keys. These can also be redefined to change the drawing.
+ \begin{dispExample}
+ \robotArmLink[draw link/.code={
+ \draw[line cap=round, double=lightgray,
+ double distance=4mm]
+ (0,0) to[bend left] (2,0);}]
+ \end{dispExample}
+ Of course you can also do this globally so it applies to all links\footnote{For the end effector to change too, you have to redefine \refKey{/robotarm/end effector/draw joint} too.}.
+ \begin{dispExample}
+ \pgfkeys{/robotarm/link/draw joint/.code={
+ \path[link style] (-0.3,-0.3) rectangle ++(0.6,0.6);
+ \path[link style] (0,0) circle (0.2);}}
+ \robotArm[geometry={a=1.5},
+ config={q1=60,q2=-30,q3=-30}]{3}
+ \end{dispExample}
+ To access the values of the keys listed above you can use the following macros in your redefinition:
+ \begin{itemize}
+ \item \docAuxCommand{RA@link@width},
+ \item \docAuxCommand{RA@link@length}, and
+ \item \docAuxCommand{RA@link@jointradius}.
+ \end{itemize}
+ \end{docKeys}
+
+ \end{docCommand}
+
+ \subsection{\texttt{robotArmEndEffector}}
+
+ \begin{docCommand}{robotArmEndEffector}{\oarg{key-value list}}
+ This command is used in \refCom{robotArm} to draw the final link with the end effector attached. You can also use it outside that command to draw your own end effector.
+ \begin{dispExample}
+ \robotArmEndEffector
+ \end{dispExample}
+ The \meta{key-value list} can consist of the keys listed below.
+
+ \begin{docKeys}
+ [
+ doc keypath={robotarm/end effector},
+ doc parameter={=\meta{value}},
+ ]
+ {
+ {
+ doc name=width,
+ doc description={initially \texttt{0.4}},
+ },
+ {
+ doc name=length,
+ doc description={initially \texttt{2.0}},
+ },
+ {
+ doc name=joint radius,
+ doc description={initially \texttt{0.25}},
+ },
+ {
+ doc name=gripper radius,
+ doc description={initially \texttt{0.3}},
+ },
+ {
+ doc name=gripper opening angle,
+ doc description={initially \texttt{60}},
+ doc parameter={=\meta{angle}},
+ },
+ }
+ The geometrical properties of the final link and the end effector, which defaults to a gripper, can be tuned with these keys. Due to some trigonometric functions in the drawing code of \refKey{/robotarm/end effector/draw end effector}, \refKey{/robotarm/end effector/gripper radius} should not be smaller than half of \refKey{/robotarm/end effector/width}.
+
+ \end{docKeys}
+
+ \begin{docKeys}
+ [
+ doc keypath={robotarm/end effector},
+ doc description={code executing key},
+ ]
+ {
+ {doc name=draw link},
+ {doc name=draw joint},
+ {doc name=draw end effector},
+ }
+ Again the actual drawing is done by calling these keys. And these can also be redefined to change how the end effector will look, as shown in the example below.
+ \begin{dispExample}
+ \robotArm[
+ config={q1=100,q2=-100},
+ end effector/.cd,
+ draw link/.code={
+ \draw[line cap=round, double=lightgray,
+ double distance=4mm]
+ (0,0) to[bend left] (2, 0.8);},
+ draw end effector/.code={
+ \path[link style]
+ (1.8, 0.8) arc (180:0:0.2) -- (2.1, 0.4)
+ -- (1.9, 0.4) -- cycle;
+ \path[link style]
+ (2.05,0.4) rectangle (1.95,0.0);
+ \fill (2,0) circle (0.05);}]{2}
+ \end{dispExample}
+ To access the values of the keys listed above you can use the following macros in your redefinition:
+ \begin{itemize}
+ \item \docAuxCommand{RA@endeff@width},
+ \item \docAuxCommand{RA@endeff@length},
+ \item \docAuxCommand{RA@endeff@jointradius},
+ \item \docAuxCommand{RA@endeff@gripperradius}, and
+ \item \docAuxCommand{RA@endeff@gripperopeningangle}.
+ \end{itemize}
+ \end{docKeys}
+
+ \end{docCommand}
+
+\section{\Tikz styles}
+
+ \begin{docKeys}
+ [
+ doc keypath=tikz,
+ doc description=style,
+ ]
+ {
+ {
+ doc name=in link,
+ doc parameter={=\meta{number}},
+ },
+ {
+ doc name=in base link,
+ },
+ {
+ doc name=in world,
+ },
+ {
+ doc name=in end effector,
+ }
+ }
+ Only installed after calling \refCom{robotArm} at least once (last called macro defines these styles, but within scope can be made unique).
+ \end{docKeys}
+
+ \begin{docKey}[tikz]{link style}{}{default \texttt{/robotarm/styles/link}}
+ Always installed, forwards to \refKey{/robotarm/styles/link}. Only works one way. To change link styles used in \refCom{robotArm}, change the appropriate \refKey{/robotarm/styles/link}.
+ \begin{dispExample}
+ \tikzset{link style/.style={draw=none, fill=red!50}}
+ \robotArm[config={q1=40},styles={
+ link 1/.style={fill=blue!50}}]{3}
+ \end{dispExample}
+ \end{docKey}
+
+
+ %^^A \section{\robotarmpackage keys}
+ %^^A \begin{docKeys}
+ %^^A [
+ %^^A doc keypath=robotarm/annotations/labels,
+ %^^A ]{
+ %^^A {
+ %^^A doc name=a,
+ %^^A doc description={no default, initially \texttt{a}},
+ %^^A },
+ %^^A {
+ %^^A doc name=q,
+ %^^A doc description={no default, initially \texttt{q}},
+ %^^A }
+ %^^A }
+ %^^A \begin{dispExample}
+ %^^A \robotArm[
+ %^^A config={q1=60,q2=-40,q3=40},
+ %^^A annotations/labels/a=l,
+ %^^A annotations/labels/q=\theta,
+ %^^A annotations/labels/q3=?]{3}
+ %^^A \end{dispExample}
+ %^^A \end{docKeys}
+
+ %^^A \section{\Tikz keys}
+
+
+ %^^A \begin{docKeys}
+ %^^A [
+ %^^A doc keypath=robotarm/frames,
+ %^^A doc description={style},
+ %^^A ]{
+ %^^A {doc name=in link 0},
+ %^^A {doc name=in link 1},
+ %^^A {doc name=in link 2},
+ %^^A {doc name=in link 3},
+ %^^A {doc name=in link 4},
+ %^^A {doc name=in link 5},
+ %^^A {doc name=in link 6}
+ %^^A }
+ %^^A \end{docKeys}
+
+
+%</robotarm-doc-main>
+%
+%<*robotarm-doc-bib>
+@manual{tantau:tikz_and_pgf,
+ author = {Till Tantau},
+ title = {The TikZ and PGF Packages},
+ subtitle = {Manual for version 3.1.8b},
+ url = {https://mirrors.ctan.org/graphics/pgf/base/doc/pgfmanual.pdf},
+ date = {2021-03-19},
+}
+%</robotarm-doc-bib>
+%
+% \fi
+%
+% \CheckSum{286}
+%
+% \CharacterTable
+% {Upper-case \A\B\C\D\E\F\G\H\I\J\K\L\M\N\O\P\Q\R\S\T\U\V\W\X\Y\Z
+% Lower-case \a\b\c\d\e\f\g\h\i\j\k\l\m\n\o\p\q\r\s\t\u\v\w\x\y\z
+% Digits \0\1\2\3\4\5\6\7\8\9
+% Exclamation \! Double quote \" Hash (number) \#
+% Dollar \$ Percent \% Ampersand \&
+% Acute accent \' Left paren \( Right paren \)
+% Asterisk \* Plus \+ Comma \,
+% Minus \- Point \. Solidus \/
+% Colon \: Semicolon \; Less than \<
+% Equals \= Greater than \> Question mark \?
+% Commercial at \@ Left bracket \[ Backslash \\
+% Right bracket \] Circumflex \^ Underscore \_
+% Grave accent \` Left brace \{ Vertical bar \|
+% Right brace \} Tilde \~}
+%
+%
+% \DoNotIndex{\angleannotationcase,\link@angleannotspacing,\begin,\begingroup,\DeclareDocumentCommand,\draw,\end,\endgroup,\fi,\foreach,\ifcase,\ifnum,\ifRA@robotarm@drawannotations,\lenghtannotationspacing,\link@lenght,\link@radius,\link@startangle,\link@width,\lengthannotationspacing,\link@length,\link@case}
+%
+% \changes{v0.1}{2022/03/08}{Initial version for publishing}
+%
+% \GetFileInfo{robotarm.sty}
+%
+% \input{robotarm.doc.main.tex}
+%
+% \StopEventually{\printbibliography[heading=robotarmbibheading]\printindex\PrintChanges}
+%
+% \section{Implementation}
+% \begin{macrocode}
+%<*robotarm-package>
+\NeedsTeXFormat{LaTeX2e}
+\ProvidesPackage{robotarm}
+ [2022/03/08 v0.1 Tikz commands to draw planar robot arms]
+
+\RequirePackage{tikz}
+
+\usetikzlibrary{patterns}
+
+\makeatletter
+
+\newif\ifRA@robotarm@drawannotations
+
+\pgfkeys{
+ /robotarm/base link/.cd,
+ width/.code={\pgfmathsetmacro\RA@baselink@width{#1}},
+ width=0.6,
+ height/.code={\pgfmathsetmacro\RA@baselink@height{#1}},
+ height=0.3,
+ world width/.code={\pgfmathsetmacro\RA@baselink@worldwidth{#1}},
+ world width=1.0,
+ world height/.code={\pgfmathsetmacro\RA@baselink@worldheight{#1}},
+ world height=0.3,
+ draw base link/.code={%
+ \path[link style]
+ (-1/2*\RA@baselink@width,0)
+ arc (180:0:1/2*\RA@baselink@width)
+ -- ++ (0, -\RA@baselink@height)
+ -- ++ (-\RA@baselink@width, 0)
+ -- cycle;
+ },
+ draw world/.code={%
+ \path[world style]
+ (-1/2*\RA@baselink@worldwidth,-\RA@baselink@height)
+ arc (180:360:{1/2*\RA@baselink@worldwidth}
+ and {\RA@baselink@worldheight}) -- cycle;
+ \path[draw, world style]
+ (-1/2*\RA@baselink@worldwidth,-\RA@baselink@height)
+ -- ++(\RA@baselink@worldwidth,0);
+ },
+ /robotarm/link/.cd,
+ width/.code={\pgfmathsetmacro\RA@link@width{#1}},
+ width=0.4,
+ length/.code={\pgfmathsetmacro\RA@link@length{#1}},
+ length=2.0,
+ joint radius/.code={\pgfmathsetmacro\RA@link@jointradius{#1}},
+ joint radius=0.25,
+ draw link/.code={%
+ \path[link style]
+ (0,1/2*\RA@link@width)
+ -- ++ ( \RA@link@length, 0)
+ arc (90:-90:1/2*\RA@link@width)
+ -- ++ (-\RA@link@length, 0)
+ arc (270:90:1/2*\RA@link@width)
+ -- cycle;
+ },
+ draw joint/.code={%
+ \path[link style]
+ (0,0) circle (\RA@link@jointradius);
+ \path[link style]
+ (0,0) circle (1/3*\RA@link@jointradius);
+ },
+ /robotarm/end effector/.cd,
+ width/.code={\pgfmathsetmacro\RA@endeff@width{#1}},
+ width=0.4,
+ length/.code={\pgfmathsetmacro\RA@endeff@length{#1}},
+ length=2,
+ joint radius/.code={\pgfmathsetmacro\RA@endeff@jointradius{#1}},
+ joint radius=0.25,
+ gripper radius/.code={\pgfmathsetmacro\RA@endeff@gripperradius{#1}},
+ gripper radius=0.3,
+ gripper opening angle/.code={%
+ \pgfmathsetmacro\RA@endeff@gripperopeningangle{#1}},
+ gripper opening angle=60,
+ draw joint/.code={%
+ \path[link style]
+ (0,0) circle (\RA@endeff@jointradius);
+ \path[link style]
+ (0,0) circle (1/3*\RA@endeff@jointradius);
+ },
+ draw link/.code={%
+ \pgfmathsetmacro{\link@startangle}{%
+ 180-asin(1/2*\RA@endeff@width/\RA@endeff@gripperradius)}
+ \pgfmathsetmacro{\link@endangle}{%
+ 180+asin(1/2*\RA@endeff@width/\RA@endeff@gripperradius)}
+
+ \path[link style]
+ (\RA@endeff@length, 0)
+ ++ (\link@startangle:\RA@endeff@gripperradius)
+ arc (\link@startangle:\link@endangle:\RA@endeff@gripperradius)
+ -- (0,0|-0,-1/2*\RA@endeff@width)
+ arc (-90:90:1/2*\RA@endeff@width)
+ -- cycle;
+ },
+ draw end effector/.code={
+ \draw[link style]
+ (\RA@endeff@length, 0)
+ ++ (-1/2*\RA@endeff@gripperopeningangle:%
+ \RA@endeff@gripperradius)
+ arc [start angle=-1/2*\RA@endeff@gripperopeningangle,
+ delta angle=-360+\RA@endeff@gripperopeningangle,
+ radius=\RA@endeff@gripperradius]
+ -- ++(180+1/2*\RA@endeff@gripperopeningangle:%
+ 0.4*\RA@endeff@gripperradius)
+ arc [start angle=1/2*\RA@endeff@gripperopeningangle,
+ delta angle=360-\RA@endeff@gripperopeningangle,
+ radius=0.6*\RA@endeff@gripperradius]
+ -- ++(-1/2*\RA@endeff@gripperopeningangle:%
+ 0.4*\RA@endeff@gripperradius)
+ -- cycle;
+ },
+ /robotarm/.cd,
+ draw annotations/.is if=RA@robotarm@drawannotations,
+ draw annotations=true,
+ every annotation/.style={},
+ every length annotation/.style={},
+ every length annotation arrow/.style={draw,->},
+ every length annotation node/.style={circle,inner sep=0.5pt},
+ every length annotation help line/.style={draw,help lines},
+ every angle annotation/.style={},
+ every angle annotation arrow/.style={draw,->},
+ every angle annotation node/.style={},
+ every angle annotation help line/.style={draw,help lines},
+ base link/.code=\pgfkeys{/robotarm/base link/.cd,#1},
+ link/.code=\pgfkeys{/robotarm/link/.cd,#1},
+ end effector/.code=\pgfkeys{/robotarm/end effector/.cd,#1},
+ geometry/.code=\pgfkeys{/robotarm/geometry/.cd,#1},
+ config/.code=\pgfkeys{/robotarm/config/.cd,#1},
+ spacing/.code=\pgfkeys{/robotarm/annotations/spacing/.cd,#1},
+ labels/.code=\pgfkeys{/robotarm/annotations/labels/.cd,#1},
+ styles/.code=\pgfkeys{/robotarm/styles/.cd,#1},
+ /robotarm/geometry/.cd,
+ a0/.initial=0,
+ a/.initial=2,
+ r/.initial=0.25,
+ w/.initial=0.4,
+ /robotarm/config/q/.initial=0,
+ /robotarm/frames/.cd,
+ in link 0/.style={},
+ in end effector/.style={
+ /robotarm/frames/in link \RA@robotarm@numlinks,
+ shift={%
+ (\pgfkeysvalueof{/robotarm/geometry/a\RA@robotarm@numlinks},0)},
+ },
+ in world/.style={
+ shift={(0,-\RA@baselink@height)}
+ },
+ /robotarm/styles/.cd,
+ world/.style={pattern=north west lines},
+ link/.style={
+ draw,
+ fill=lightgray,
+ },
+ link 0/.style={/robotarm/styles/link},
+ /robotarm/annotations/.cd,
+ spacing/.cd,
+ a/.initial=3,
+ q/.initial=1/2,
+ /robotarm/annotations/.cd,
+ labels/.cd,
+ a/.initial=a,
+ q/.initial=q,
+}
+\tikzset{
+ link style/.style={/robotarm/styles/link},
+ world style/.style={/robotarm/styles/world},
+}
+% \end{macrocode}
+% \begin{macro}{\robotarmset}
+% \begin{macrocode}
+\newcommand\robotarmset[1]{%
+ \pgfkeys{/robotarm/.cd,#1}%
+}
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\robotArmLink}
+% \begin{macrocode}
+\newcommand\robotArmLink[1][]{
+ \begingroup
+ \pgfkeys{/robotarm/link/.cd,#1}
+
+ \pgfkeys{/robotarm/link/draw link}
+ \pgfkeys{/robotarm/link/draw joint}
+ \endgroup
+}
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\robotArmEndEffector}
+% \begin{macrocode}
+\newcommand\robotArmEndEffector[1][]{
+ \begingroup
+ \pgfkeys{/robotarm/end effector/.cd,#1}
+
+ \pgfkeys{/robotarm/end effector/draw link}
+ \pgfkeys{/robotarm/end effector/draw joint}
+ \pgfkeys{/robotarm/end effector/draw end effector}
+
+ \endgroup
+}
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\robotArmBaseLink}
+% \begin{macrocode}
+\newcommand\robotArmBaseLink[1][]{
+ \begingroup
+ \pgfkeys{/robotarm/base link/.cd,#1}
+
+ \pgfkeys{/robotarm/base link/draw world}
+ \pgfkeys{/robotarm/base link/draw base link}
+ \endgroup
+}
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\robotArm}
+% \begin{macrocode}
+\newcommand\robotArm[2][]{
+ \pgfmathtruncatemacro\RA@robotarm@numlinks{#2}
+ \def\@tmpkeys{}
+ \foreach \@link [remember=\@link as \@prevlink (initially 0)] in %
+ {1,...,\RA@robotarm@numlinks}{
+ \xdef\@tmpkeys{\@tmpkeys%
+ /robotarm/geometry/a\@link/.initial=%
+ \pgfkeysvalueof{/robotarm/geometry/a},%
+ /robotarm/geometry/r\@link/.initial=%
+ \pgfkeysvalueof{/robotarm/geometry/r},%
+ /robotarm/geometry/w\@link/.initial=%
+ \pgfkeysvalueof{/robotarm/geometry/w},%
+ /robotarm/config/q\@link/.initial=%
+ \pgfkeysvalueof{/robotarm/config/q},%
+ /robotarm/styles/link \@link/.style={/robotarm/styles/link},%
+ /robotarm/annotations/labels/a\@link/.initial={%
+ $\pgfkeysvalueof{/robotarm/annotations/labels/a}_{\@link}$},%
+ /robotarm/annotations/labels/q\@link/.initial={%
+ $\pgfkeysvalueof{/robotarm/annotations/labels/q}_{\@link}$},%
+ /robotarm/annotations/spacing/a\@link/.initial={%
+ \pgfkeysvalueof{/robotarm/annotations/spacing/a}},%
+ /robotarm/annotations/spacing/q\@link/.initial={%
+ \pgfkeysvalueof{/robotarm/annotations/spacing/q}},%
+ }
+ }
+ \expandafter\pgfkeys\expandafter{\@tmpkeys}
+ \pgfkeys{/robotarm/.cd,#1}
+ \def\@tmpkeys{}
+ \foreach \@link [remember=\@link as \@prevlink (initially 0)] in %
+ {1,...,\RA@robotarm@numlinks}{
+ \xdef\@tmpkeys{\@tmpkeys%
+ /robotarm/frames/in link \@link/.style={%
+ /robotarm/frames/in link \@prevlink,
+ /tikz/shift={%
+ (\pgfkeysvalueof{/robotarm/geometry/a\@prevlink},0)},
+ /tikz/rotate={\pgfkeysvalueof{/robotarm/config/q\@link}},
+ },
+ }
+ }
+ \expandafter\pgfkeys\expandafter{\@tmpkeys}
+
+ \begin{scope}[/robotarm/frames/in link 0,
+ link style/.style={/robotarm/styles/link 0}]
+ \robotArmBaseLink
+ \end{scope}
+
+ \foreach\link@num in {1,...,\RA@robotarm@numlinks}{
+ \begin{scope}[/robotarm/frames/in link \link@num,
+ link style/.style={/robotarm/styles/link \link@num}]
+
+ \ifnum\link@num<\RA@robotarm@numlinks
+ \robotArmLink[
+ joint radius=\pgfkeysvalueof{/robotarm/geometry/r\link@num},
+ length=\pgfkeysvalueof{/robotarm/geometry/a\link@num},
+ width=\pgfkeysvalueof{/robotarm/geometry/w\link@num},
+ ]
+ \else
+ \robotArmEndEffector[
+ joint radius=\pgfkeysvalueof{/robotarm/geometry/r\link@num},
+ length=\pgfkeysvalueof{/robotarm/geometry/a\link@num},
+ width=\pgfkeysvalueof{/robotarm/geometry/w\link@num},
+ ]
+ \fi
+ \end{scope}
+ }
+ \foreach\link@num in {1,...,\RA@robotarm@numlinks}{
+ \begin{scope}[/robotarm/frames/in link \link@num]
+ \pgfmathsetmacro\link@length{\pgfkeysvalueof{%
+ /robotarm/geometry/a\link@num}}
+ \pgfmathsetmacro\link@angle{\pgfkeysvalueof{%
+ /robotarm/config/q\link@num}}
+
+ \ifRA@robotarm@drawannotations
+ \pgfmathsetmacro\link@lengthannotspacing{%
+ \pgfkeysvalueof{/robotarm/annotations/spacing/a\link@num}*
+ \pgfkeysvalueof{/robotarm/geometry/r\link@num}}
+ \pgfmathsetmacro\link@angleannotspacing{%
+ \pgfkeysvalueof{/robotarm/annotations/spacing/q\link@num}*
+ \link@length}
+
+ % Length annotation help lines
+ \path[/robotarm/every annotation,
+ /robotarm/every length annotation,
+ /robotarm/every length annotation help line]
+ (0,0) -- (\link@length,0);
+ \path[/robotarm/every annotation,
+ /robotarm/every length annotation,
+ /robotarm/every length annotation help line]
+ (0,0) -- ++ (0,{\link@lengthannotspacing +
+ 0.1*sign(\link@lengthannotspacing)});
+ \path[/robotarm/every annotation,
+ /robotarm/every length annotation,
+ /robotarm/every length annotation help line]
+ (\link@length,0) -- ++ (0,{\link@lengthannotspacing +
+ 0.1*sign(\link@lengthannotspacing)});
+% \end{macrocode}
+% Length annotation node
+% \begin{macrocode}
+ \path (0,\link@lengthannotspacing)
+ -- coordinate[pos=0.5] (coor) ++ (\link@length,0);
+ \node[/robotarm/every annotation,
+ /robotarm/every length annotation,
+ /robotarm/every length annotation node]
+ at (coor) (tag)
+ {\pgfkeysvalueof{/robotarm/annotations/labels/a\link@num}};
+% \end{macrocode}
+% Length annotation arrows
+% \begin{macrocode}
+ \path[/robotarm/every annotation,
+ /robotarm/every length annotation,
+ /robotarm/every length annotation arrow]
+ (tag) -- (0,\link@lengthannotspacing);
+ \path[/robotarm/every annotation,
+ /robotarm/every length annotation,
+ /robotarm/every length annotation arrow]
+ (tag) -- (\link@length,\link@lengthannotspacing);
+
+ \pgfmathsetmacro\angleannotationcase{%
+ ifthenelse(\link@angle==0.0, 0, 1)}
+ \ifnum\angleannotationcase>0
+ % Angle annotation help lines
+ \path[/robotarm/every annotation,
+ /robotarm/every angle annotation,
+ /robotarm/every angle annotation help line]
+ (0,0) -- ++(-\link@angle:{\link@angleannotspacing+0.1});
+ \path[/robotarm/every annotation,
+ /robotarm/every angle annotation,
+ /robotarm/every angle annotation help line]
+ (0,0) -- ++(0:{\link@angleannotspacing+0.1});
+
+ % Angle annotation arrow
+ \path[/robotarm/every annotation,
+ /robotarm/every angle annotation,
+ /robotarm/every angle annotation arrow]
+ (0,0) ++ (-\link@angle:\link@angleannotspacing)
+ arc (-\link@angle:0:\link@angleannotspacing);
+
+ % Angle annotation node
+ \node[/robotarm/every annotation,
+ /robotarm/every angle annotation,
+ /robotarm/every angle annotation node]
+ at (-\link@angle/2:\link@angleannotspacing+0.3)
+ {\pgfkeysvalueof{/robotarm/annotations/labels/q\link@num}};
+ \fi
+ \fi
+ \end{scope}
+ }
+% \end{macrocode}
+% Install \Tikz styles for coordinate transformations.
+% \begin{macrocode}
+ \tikzset{
+ in link/.style={/robotarm/frames/in link #1},
+ in base link/.style={/robotarm/frames/in link 0},
+ in end effector/.style={/robotarm/frames/in end effector},
+ in world/.style={/robotarm/frames/in world},
+ }
+}
+% \end{macrocode}
+% \end{macro}
+% \begin{macrocode}
+\makeatother
+%</robotarm-package>
+% \end{macrocode}
+% \Finale
+\endinput \ No newline at end of file
diff --git a/graphics/pgf/contrib/robotarm/robotarm.pdf b/graphics/pgf/contrib/robotarm/robotarm.pdf
new file mode 100644
index 0000000000..ab9689f9d9
--- /dev/null
+++ b/graphics/pgf/contrib/robotarm/robotarm.pdf
Binary files differ
diff --git a/graphics/pgf/contrib/robotarm/robotarm.sty b/graphics/pgf/contrib/robotarm/robotarm.sty
new file mode 100644
index 0000000000..5fb7f730aa
--- /dev/null
+++ b/graphics/pgf/contrib/robotarm/robotarm.sty
@@ -0,0 +1,375 @@
+%%
+%% This is file `robotarm.sty',
+%% generated with the docstrip utility.
+%%
+%% The original source files were:
+%%
+%% robotarm.dtx (with options: `robotarm-package')
+%%
+%% This is a generated file.
+%%
+%% Copyright (C) 2021 by M.J.W. Snippe
+%% -----------------------------------
+%%
+%% This file may be distributed and/or modified under the
+%% conditions of the LaTeX Project Public License, either
+%% version 1.3 of this license or (at your option) any later
+%% version. The latest version of this license is in:
+%%
+%% http://www.latex-project.org/lppl.txt
+%%
+%% and version 1.3 or later is part of all distributions of
+%% LaTeX version 2005/12/01 or later.
+%%
+%% This work has the LPPL maintenance status
+%% `author-maintained'.
+%%
+%% This work consists of the files found at github.com/max-sn/robotarm.
+%%
+\NeedsTeXFormat{LaTeX2e}
+\ProvidesPackage{robotarm}
+ [2022/03/08 v0.1 Tikz commands to draw planar robot arms]
+
+\RequirePackage{tikz}
+
+\usetikzlibrary{patterns}
+
+\makeatletter
+
+\newif\ifRA@robotarm@drawannotations
+
+\pgfkeys{
+ /robotarm/base link/.cd,
+ width/.code={\pgfmathsetmacro\RA@baselink@width{#1}},
+ width=0.6,
+ height/.code={\pgfmathsetmacro\RA@baselink@height{#1}},
+ height=0.3,
+ world width/.code={\pgfmathsetmacro\RA@baselink@worldwidth{#1}},
+ world width=1.0,
+ world height/.code={\pgfmathsetmacro\RA@baselink@worldheight{#1}},
+ world height=0.3,
+ draw base link/.code={%
+ \path[link style]
+ (-1/2*\RA@baselink@width,0)
+ arc (180:0:1/2*\RA@baselink@width)
+ -- ++ (0, -\RA@baselink@height)
+ -- ++ (-\RA@baselink@width, 0)
+ -- cycle;
+ },
+ draw world/.code={%
+ \path[world style]
+ (-1/2*\RA@baselink@worldwidth,-\RA@baselink@height)
+ arc (180:360:{1/2*\RA@baselink@worldwidth}
+ and {\RA@baselink@worldheight}) -- cycle;
+ \path[draw, world style]
+ (-1/2*\RA@baselink@worldwidth,-\RA@baselink@height)
+ -- ++(\RA@baselink@worldwidth,0);
+ },
+ /robotarm/link/.cd,
+ width/.code={\pgfmathsetmacro\RA@link@width{#1}},
+ width=0.4,
+ length/.code={\pgfmathsetmacro\RA@link@length{#1}},
+ length=2.0,
+ joint radius/.code={\pgfmathsetmacro\RA@link@jointradius{#1}},
+ joint radius=0.25,
+ draw link/.code={%
+ \path[link style]
+ (0,1/2*\RA@link@width)
+ -- ++ ( \RA@link@length, 0)
+ arc (90:-90:1/2*\RA@link@width)
+ -- ++ (-\RA@link@length, 0)
+ arc (270:90:1/2*\RA@link@width)
+ -- cycle;
+ },
+ draw joint/.code={%
+ \path[link style]
+ (0,0) circle (\RA@link@jointradius);
+ \path[link style]
+ (0,0) circle (1/3*\RA@link@jointradius);
+ },
+ /robotarm/end effector/.cd,
+ width/.code={\pgfmathsetmacro\RA@endeff@width{#1}},
+ width=0.4,
+ length/.code={\pgfmathsetmacro\RA@endeff@length{#1}},
+ length=2,
+ joint radius/.code={\pgfmathsetmacro\RA@endeff@jointradius{#1}},
+ joint radius=0.25,
+ gripper radius/.code={\pgfmathsetmacro\RA@endeff@gripperradius{#1}},
+ gripper radius=0.3,
+ gripper opening angle/.code={%
+ \pgfmathsetmacro\RA@endeff@gripperopeningangle{#1}},
+ gripper opening angle=60,
+ draw joint/.code={%
+ \path[link style]
+ (0,0) circle (\RA@endeff@jointradius);
+ \path[link style]
+ (0,0) circle (1/3*\RA@endeff@jointradius);
+ },
+ draw link/.code={%
+ \pgfmathsetmacro{\link@startangle}{%
+ 180-asin(1/2*\RA@endeff@width/\RA@endeff@gripperradius)}
+ \pgfmathsetmacro{\link@endangle}{%
+ 180+asin(1/2*\RA@endeff@width/\RA@endeff@gripperradius)}
+
+ \path[link style]
+ (\RA@endeff@length, 0)
+ ++ (\link@startangle:\RA@endeff@gripperradius)
+ arc (\link@startangle:\link@endangle:\RA@endeff@gripperradius)
+ -- (0,0|-0,-1/2*\RA@endeff@width)
+ arc (-90:90:1/2*\RA@endeff@width)
+ -- cycle;
+ },
+ draw end effector/.code={
+ \draw[link style]
+ (\RA@endeff@length, 0)
+ ++ (-1/2*\RA@endeff@gripperopeningangle:%
+ \RA@endeff@gripperradius)
+ arc [start angle=-1/2*\RA@endeff@gripperopeningangle,
+ delta angle=-360+\RA@endeff@gripperopeningangle,
+ radius=\RA@endeff@gripperradius]
+ -- ++(180+1/2*\RA@endeff@gripperopeningangle:%
+ 0.4*\RA@endeff@gripperradius)
+ arc [start angle=1/2*\RA@endeff@gripperopeningangle,
+ delta angle=360-\RA@endeff@gripperopeningangle,
+ radius=0.6*\RA@endeff@gripperradius]
+ -- ++(-1/2*\RA@endeff@gripperopeningangle:%
+ 0.4*\RA@endeff@gripperradius)
+ -- cycle;
+ },
+ /robotarm/.cd,
+ draw annotations/.is if=RA@robotarm@drawannotations,
+ draw annotations=true,
+ every annotation/.style={},
+ every length annotation/.style={},
+ every length annotation arrow/.style={draw,->},
+ every length annotation node/.style={circle,inner sep=0.5pt},
+ every length annotation help line/.style={draw,help lines},
+ every angle annotation/.style={},
+ every angle annotation arrow/.style={draw,->},
+ every angle annotation node/.style={},
+ every angle annotation help line/.style={draw,help lines},
+ base link/.code=\pgfkeys{/robotarm/base link/.cd,#1},
+ link/.code=\pgfkeys{/robotarm/link/.cd,#1},
+ end effector/.code=\pgfkeys{/robotarm/end effector/.cd,#1},
+ geometry/.code=\pgfkeys{/robotarm/geometry/.cd,#1},
+ config/.code=\pgfkeys{/robotarm/config/.cd,#1},
+ spacing/.code=\pgfkeys{/robotarm/annotations/spacing/.cd,#1},
+ labels/.code=\pgfkeys{/robotarm/annotations/labels/.cd,#1},
+ styles/.code=\pgfkeys{/robotarm/styles/.cd,#1},
+ /robotarm/geometry/.cd,
+ a0/.initial=0,
+ a/.initial=2,
+ r/.initial=0.25,
+ w/.initial=0.4,
+ /robotarm/config/q/.initial=0,
+ /robotarm/frames/.cd,
+ in link 0/.style={},
+ in end effector/.style={
+ /robotarm/frames/in link \RA@robotarm@numlinks,
+ shift={%
+ (\pgfkeysvalueof{/robotarm/geometry/a\RA@robotarm@numlinks},0)},
+ },
+ in world/.style={
+ shift={(0,-\RA@baselink@height)}
+ },
+ /robotarm/styles/.cd,
+ world/.style={pattern=north west lines},
+ link/.style={
+ draw,
+ fill=lightgray,
+ },
+ link 0/.style={/robotarm/styles/link},
+ /robotarm/annotations/.cd,
+ spacing/.cd,
+ a/.initial=3,
+ q/.initial=1/2,
+ /robotarm/annotations/.cd,
+ labels/.cd,
+ a/.initial=a,
+ q/.initial=q,
+}
+\tikzset{
+ link style/.style={/robotarm/styles/link},
+ world style/.style={/robotarm/styles/world},
+}
+\newcommand\robotarmset[1]{%
+ \pgfkeys{/robotarm/.cd,#1}%
+}
+\newcommand\robotArmLink[1][]{
+ \begingroup
+ \pgfkeys{/robotarm/link/.cd,#1}
+
+ \pgfkeys{/robotarm/link/draw link}
+ \pgfkeys{/robotarm/link/draw joint}
+ \endgroup
+}
+\newcommand\robotArmEndEffector[1][]{
+ \begingroup
+ \pgfkeys{/robotarm/end effector/.cd,#1}
+
+ \pgfkeys{/robotarm/end effector/draw link}
+ \pgfkeys{/robotarm/end effector/draw joint}
+ \pgfkeys{/robotarm/end effector/draw end effector}
+
+ \endgroup
+}
+\newcommand\robotArmBaseLink[1][]{
+ \begingroup
+ \pgfkeys{/robotarm/base link/.cd,#1}
+
+ \pgfkeys{/robotarm/base link/draw world}
+ \pgfkeys{/robotarm/base link/draw base link}
+ \endgroup
+}
+\newcommand\robotArm[2][]{
+ \pgfmathtruncatemacro\RA@robotarm@numlinks{#2}
+ \def\@tmpkeys{}
+ \foreach \@link [remember=\@link as \@prevlink (initially 0)] in %
+ {1,...,\RA@robotarm@numlinks}{
+ \xdef\@tmpkeys{\@tmpkeys%
+ /robotarm/geometry/a\@link/.initial=%
+ \pgfkeysvalueof{/robotarm/geometry/a},%
+ /robotarm/geometry/r\@link/.initial=%
+ \pgfkeysvalueof{/robotarm/geometry/r},%
+ /robotarm/geometry/w\@link/.initial=%
+ \pgfkeysvalueof{/robotarm/geometry/w},%
+ /robotarm/config/q\@link/.initial=%
+ \pgfkeysvalueof{/robotarm/config/q},%
+ /robotarm/styles/link \@link/.style={/robotarm/styles/link},%
+ /robotarm/annotations/labels/a\@link/.initial={%
+ $\pgfkeysvalueof{/robotarm/annotations/labels/a}_{\@link}$},%
+ /robotarm/annotations/labels/q\@link/.initial={%
+ $\pgfkeysvalueof{/robotarm/annotations/labels/q}_{\@link}$},%
+ /robotarm/annotations/spacing/a\@link/.initial={%
+ \pgfkeysvalueof{/robotarm/annotations/spacing/a}},%
+ /robotarm/annotations/spacing/q\@link/.initial={%
+ \pgfkeysvalueof{/robotarm/annotations/spacing/q}},%
+ }
+ }
+ \expandafter\pgfkeys\expandafter{\@tmpkeys}
+ \pgfkeys{/robotarm/.cd,#1}
+ \def\@tmpkeys{}
+ \foreach \@link [remember=\@link as \@prevlink (initially 0)] in %
+ {1,...,\RA@robotarm@numlinks}{
+ \xdef\@tmpkeys{\@tmpkeys%
+ /robotarm/frames/in link \@link/.style={%
+ /robotarm/frames/in link \@prevlink,
+ /tikz/shift={%
+ (\pgfkeysvalueof{/robotarm/geometry/a\@prevlink},0)},
+ /tikz/rotate={\pgfkeysvalueof{/robotarm/config/q\@link}},
+ },
+ }
+ }
+ \expandafter\pgfkeys\expandafter{\@tmpkeys}
+
+ \begin{scope}[/robotarm/frames/in link 0,
+ link style/.style={/robotarm/styles/link 0}]
+ \robotArmBaseLink
+ \end{scope}
+
+ \foreach\link@num in {1,...,\RA@robotarm@numlinks}{
+ \begin{scope}[/robotarm/frames/in link \link@num,
+ link style/.style={/robotarm/styles/link \link@num}]
+
+ \ifnum\link@num<\RA@robotarm@numlinks
+ \robotArmLink[
+ joint radius=\pgfkeysvalueof{/robotarm/geometry/r\link@num},
+ length=\pgfkeysvalueof{/robotarm/geometry/a\link@num},
+ width=\pgfkeysvalueof{/robotarm/geometry/w\link@num},
+ ]
+ \else
+ \robotArmEndEffector[
+ joint radius=\pgfkeysvalueof{/robotarm/geometry/r\link@num},
+ length=\pgfkeysvalueof{/robotarm/geometry/a\link@num},
+ width=\pgfkeysvalueof{/robotarm/geometry/w\link@num},
+ ]
+ \fi
+ \end{scope}
+ }
+ \foreach\link@num in {1,...,\RA@robotarm@numlinks}{
+ \begin{scope}[/robotarm/frames/in link \link@num]
+ \pgfmathsetmacro\link@length{\pgfkeysvalueof{%
+ /robotarm/geometry/a\link@num}}
+ \pgfmathsetmacro\link@angle{\pgfkeysvalueof{%
+ /robotarm/config/q\link@num}}
+
+ \ifRA@robotarm@drawannotations
+ \pgfmathsetmacro\link@lengthannotspacing{%
+ \pgfkeysvalueof{/robotarm/annotations/spacing/a\link@num}*
+ \pgfkeysvalueof{/robotarm/geometry/r\link@num}}
+ \pgfmathsetmacro\link@angleannotspacing{%
+ \pgfkeysvalueof{/robotarm/annotations/spacing/q\link@num}*
+ \link@length}
+
+ % Length annotation help lines
+ \path[/robotarm/every annotation,
+ /robotarm/every length annotation,
+ /robotarm/every length annotation help line]
+ (0,0) -- (\link@length,0);
+ \path[/robotarm/every annotation,
+ /robotarm/every length annotation,
+ /robotarm/every length annotation help line]
+ (0,0) -- ++ (0,{\link@lengthannotspacing +
+ 0.1*sign(\link@lengthannotspacing)});
+ \path[/robotarm/every annotation,
+ /robotarm/every length annotation,
+ /robotarm/every length annotation help line]
+ (\link@length,0) -- ++ (0,{\link@lengthannotspacing +
+ 0.1*sign(\link@lengthannotspacing)});
+ \path (0,\link@lengthannotspacing)
+ -- coordinate[pos=0.5] (coor) ++ (\link@length,0);
+ \node[/robotarm/every annotation,
+ /robotarm/every length annotation,
+ /robotarm/every length annotation node]
+ at (coor) (tag)
+ {\pgfkeysvalueof{/robotarm/annotations/labels/a\link@num}};
+ \path[/robotarm/every annotation,
+ /robotarm/every length annotation,
+ /robotarm/every length annotation arrow]
+ (tag) -- (0,\link@lengthannotspacing);
+ \path[/robotarm/every annotation,
+ /robotarm/every length annotation,
+ /robotarm/every length annotation arrow]
+ (tag) -- (\link@length,\link@lengthannotspacing);
+
+ \pgfmathsetmacro\angleannotationcase{%
+ ifthenelse(\link@angle==0.0, 0, 1)}
+ \ifnum\angleannotationcase>0
+ % Angle annotation help lines
+ \path[/robotarm/every annotation,
+ /robotarm/every angle annotation,
+ /robotarm/every angle annotation help line]
+ (0,0) -- ++(-\link@angle:{\link@angleannotspacing+0.1});
+ \path[/robotarm/every annotation,
+ /robotarm/every angle annotation,
+ /robotarm/every angle annotation help line]
+ (0,0) -- ++(0:{\link@angleannotspacing+0.1});
+
+ % Angle annotation arrow
+ \path[/robotarm/every annotation,
+ /robotarm/every angle annotation,
+ /robotarm/every angle annotation arrow]
+ (0,0) ++ (-\link@angle:\link@angleannotspacing)
+ arc (-\link@angle:0:\link@angleannotspacing);
+
+ % Angle annotation node
+ \node[/robotarm/every annotation,
+ /robotarm/every angle annotation,
+ /robotarm/every angle annotation node]
+ at (-\link@angle/2:\link@angleannotspacing+0.3)
+ {\pgfkeysvalueof{/robotarm/annotations/labels/q\link@num}};
+ \fi
+ \fi
+ \end{scope}
+ }
+ \tikzset{
+ in link/.style={/robotarm/frames/in link #1},
+ in base link/.style={/robotarm/frames/in link 0},
+ in end effector/.style={/robotarm/frames/in end effector},
+ in world/.style={/robotarm/frames/in world},
+ }
+}
+\makeatother
+\endinput
+%%
+%% End of file `robotarm.sty'.