number of arguments that is a multiple of a number in a macro for curves with continuously varying thickness
You can use the macro \scanargs \macro x1,y1 x2,y2 ... xn,yn;
and then you can use the scanned arguments in your \macro
in the form \x1
, \x2
, ... \x9, \y9
, but \x{10}, \y{22}
etc. I show the example using your example:
\documentclass{article}\usepackage{tikz}
\newcount\tmpnum
\def\scanargs #1#2;{\let\tmp=#1\tmpnum=0 \scanargsA #2 {},{} }
\def\scanargsA #1,#2 {\ifx,#1,\expandafter\tmp \else
\advance\tmpnum by1
\expandafter\def\csname x:\the\tmpnum\endcsname{#1}%
\expandafter\def\csname y:\the\tmpnum\endcsname{#2}%
\expandafter\scanargsA \fi
}
\def\x#1{\csname x:#1\endcsname}
\def\y#1{\csname y:#1\endcsname}
\def\ltrinking {\foreach \n in {0,0.01,0.02,...,0.09}
{\path[line width=2pt,rounded corners=48pt,draw]
(\x1+\n/.4,\y1+\n/.4)--(\x2+\n/.6,\y2+\n/.6)--(\x3+\n/1,\y3-\n/1)to[bend left]
(\x4+\n/4,\y4-\n/4)--cycle;}
\path[line width=2pt,rounded corners=48pt]
(\x1,\y1)--(\x2,\y2)--(\x3,\y3)to[bend left](\x4,\y4)--cycle;
}
\def\ltrstroke {\foreach \n in {0,0.01,0.02,...,0.09}
{\path[line width=1pt,rounded corners=48pt,line cap=round,draw]
(\x1+\n/1,\y1+\n/1)--(\x2+\n/4,\y2+\n/4)--(\x3+\n/3,\y3-\n/3)--(\x4+\n/4,\y4-\n/4);}
}
\begin{document}\begin{tikzpicture}[bend angle=8];
\scanargs\ltrinking 0,0 4,4 8,3 4,-1;
\scanargs\ltrstroke 0,5 0.2,5.2 3,8 2,6;
\end{tikzpicture}
\end{document}
Edit: There is a little "adding value" in egreg's answer: \newdrawingcommand
declarator. You can use \newdrawingcommand\lrstroke{...}
and then simply \lrstroke arguments
in the code without \scanarg
explicitly used. If you like such feature then it can be implemented by:
\def\newdrawingcommand#1{%
\edef#1{\noexpand\scanargs\csname s:\string#1\endcsname}%
\expandafter\def\csname s:\string#1\endcsname
}
An implementation with expl3
, where I define a \newdrawingcommand
that takes as arguments a command name and the replacement text; optionally a command based on \foreach
can be added, for greater flexibility.
In the replacement text, the various points can be referred to by \x
and \y
; these macros are available only there (they won't clobber other existing definitions).
\documentclass{article}
\usepackage{xparse}
\usepackage{tikz}
\ExplSyntaxOn
\NewDocumentCommand{\newdrawingcommand}{m O{\guidoforeach} m}
{
\cs_new_protected:Npn #1 ##1;
{
\group_begin:
\cs_set_eq:NN \x \guido_x_coord:n
\cs_set_eq:NN \y \guido_y_coord:n
\guido_parse_arg:n { ##1 }
#2 { #3 }
\group_end:
}
}
\seq_new:N \l_guido_arg_list_seq
\seq_new:N \l_guido_x_list_seq
\seq_new:N \l_guido_y_list_seq
\cs_new_protected:Npn \guido_parse_arg:n #1
{
\seq_clear:N \l_guido_x_list_seq
\seq_clear:N \l_guido_y_list_seq
\seq_set_split:Nnn \l_guido_arg_list_seq { ~ } { #1 }
\seq_map_inline:Nn \l_guido_arg_list_seq
{
\tl_if_blank:nF { ##1 }
{% the last item is empty if ; is preceded by a space
\seq_put_right:Nx \l_guido_x_list_seq { \clist_item:nn { ##1 } { 1 } }
\seq_put_right:Nx \l_guido_y_list_seq { \clist_item:nn { ##1 } { 2 } }
}
}
}
\cs_new:Npn \guido_x_coord:n #1
{
\seq_item:Nn \l_guido_x_list_seq { #1 }
}
\cs_new:Npn \guido_y_coord:n #1
{
\seq_item:Nn \l_guido_y_list_seq { #1 }
}
\ExplSyntaxOff
\newcommand{\guidoforeach}[1]{%
\foreach \n in {0,0.01,0.02,...,0.09}{#1}%
}
\newcommand{\guidoforeachdouble}[1]{%
\foreach \n in {0,0.01,...,0.36}{#1}%
}
\newdrawingcommand{\ltrstroke}[\guidoforeachdouble]{%
\path[
line width=1pt,rounded corners=48pt,line cap=round,draw
]
(\x{1}+\n/1,\y{1}+\n/1)--
(\x{2}+\n/2,\y{2}+\n/2)--
(\x{3}+\n/3,\y{3}-\n/3)--
(\x{4}+\n/4,\y{4}-\n/4);
}
\newdrawingcommand{\ltrinking}{%
\path[
line width=2pt,rounded corners=48pt,draw
](\x{1}+\n/.4,\y{1}+\n/.4)--
(\x{2}+\n/.6,\y{2}+\n/.6)--
(\x{3}+\n/1,\y{3}-\n/1) to
[bend left](\x{4}+\n/4,\y{4}-\n/4)--cycle;
\path[
line width=2pt,rounded corners=48pt
](\x{1},\y{1})--(\x{2},\y{2})--(\x{3},\y{3}) to
[bend left](\x{4},\y{4})--cycle;
}
\begin{document}
\begin{tikzpicture}[bend angle=8];
\ltrinking 0,0 4,4 8,3 4,-1 ;
\ltrstroke 0,5 0.2,5.2 3,8 2,6 ;
\end{tikzpicture}
\end{document}
The \guido_parse_arg:n
function splits (at blanks) the argument, which should be terminated by a trailing semicolon, into comma separated pairs (at blanks); then each item in a pair is added either to the list of x-coordinates or to the list of y-coordinates. Calling \x{
k}
will access the x-coordinate of the k-th point and similarly for \y
.
In the definition of \ltrstroke
I've used a different \foreach
loop, just to show the usage. If you remove the optional argument, the \foreach
loop defaults to \guidoforeach
. This might be useful for debugging, without modifying the main replacement text.
In the argument to a drawing macro you're allowed to have a trailing space before the semicolon, but no spaces around the commas.
With a change in syntax we can accommodate for n-tuples, where n is arbitrary. I've shown the example with the first command, where the four points are specified instead as two quadruples.
\documentclass{article}
\usepackage{xparse}
\usepackage{tikz}
\ExplSyntaxOn
\NewDocumentCommand{\newdrawingcommand}{m O{\guidoforeach} m}
{
\cs_new_protected:Npn #1 ##1;
{
\group_begin:
\cs_set_eq:NN \x \guido_x_coord:n
\cs_set_eq:NN \y \guido_y_coord:n
\cs_set_eq:NN \z \guido_z_coord:n
\cs_set_eq:NN \p \guido_coord:nn
\guido_parse_arg:n { ##1 }
#2 { #3 }
\group_end:
}
}
\seq_new:N \l_guido_arg_list_seq
\prop_new:N \l_guido_point_list_prop
\cs_new_protected:Npn \guido_parse_arg:n #1
{
% clear the list of points
\prop_clear:N \l_guido_point_list_prop
% split the arg list at |
\seq_set_split:Nnn \l_guido_arg_list_seq { | } { #1 }
% add each tuple to the property list
\int_step_inline:nnnn { 1 } { 1 } { \seq_count:N \l_guido_arg_list_seq }
{
\__guido_add_point:nx { ##1 } { \seq_item:Nn \l_guido_arg_list_seq { ##1 } }
}
}
\cs_new_protected:Npn \__guido_add_point:nn #1 #2
{
\int_step_inline:nnnn { 1 } { 1 } { \clist_count:n { #2 } }
{
\prop_put:Nnx \l_guido_point_list_prop { ##1 , #1 }
{
\clist_item:nn { #2 } { ##1 }
}
}
}
\cs_generate_variant:Nn \__guido_add_point:nn { nx }
\cs_new:Npn \guido_coord:nn #1 #2
{
\prop_item:Nn \l_guido_point_list_prop { #1,#2 }
}
\cs_new:Npn \guido_x_coord:n #1
{
\guido_coord:nn { #1 } { 1 }
}
\cs_new:Npn \guido_y_coord:n #1
{
\guido_coord:nn { #1 } { 2 }
}
\cs_new:Npn \guido_z_coord:n #1
{
\guido_coord:nn { #1 } { 3 }
}
\ExplSyntaxOff
\newcommand{\guidoforeach}[1]{%
\foreach \n in {0,0.01,0.02,...,0.09}{#1}%
}
\newcommand{\guidoforeachdouble}[1]{%
\foreach \n in {0,0.01,...,0.36}{#1}%
}
\newdrawingcommand{\ltrstroke}[\guidoforeachdouble]{%
\path[
line width=1pt,rounded corners=48pt,line cap=round,draw
]
(\p{1}{1}+\n/1,\p{2}{1}+\n/1)--
(\p{1}{2}+\n/2,\p{2}{2}+\n/2)--
(\p{1}{3}+\n/3,\p{2}{3}-\n/3)--
(\p{1}{4}+\n/4,\p{2}{4}-\n/4);
}
\newdrawingcommand{\ltrinking}{%
\path[
line width=2pt,rounded corners=48pt,draw
](\x{1}+\n/.4,\y{1}+\n/.4)--
(\x{2}+\n/.6,\y{2}+\n/.6)--
(\x{3}+\n/1,\y{3}-\n/1) to
[bend left](\x{4}+\n/4,\y{4}-\n/4)--cycle;
\path[
line width=2pt,rounded corners=48pt
](\x{1},\y{1})--(\x{2},\y{2})--(\x{3},\y{3}) to
[bend left](\x{4},\y{4})--cycle;
}
\begin{document}
\begin{tikzpicture}[bend angle=8];
\ltrinking 0,4,8,4 | 0,4,3,-1 ;
\ltrstroke 0,5 | 0.2 , 5.2 | 3 , 8 | 2,6 ;
\end{tikzpicture}
\end{document}
It would have been possible to still delimit n-tuples by spaces, but it would be more difficult to check correctness; in the example, I show that with this syntax, spaces are essentially ignored.
The output is the same as before, of course.
I missed this first time round, but while it has nothing to do with the question about multiple arguments, the calligraphy
TikZ library (which originated in 'Poster' fountain pen nib style text) can draw paths with varying thickness. When combined with the awesome hobby
package (from Curve through a sequence of points with Metapost and TikZ), it is quite straightforward to produce nicely curved lines of varying width.
\documentclass{article}
%\url{https://tex.stackexchange.com/q/242025/86}
\usepackage{tikz}
\usetikzlibrary{calligraphy,hobby}
\begin{document}
\begin{tikzpicture}[use Hobby shortcut,line width=2pt]
\pen (0,0);
\calligraphy[scale=.02,heavy] (0,0)..(100,-32)..(192,192)..(256,64);
\end{tikzpicture}
\end{document}