14
\$\begingroup\$

I'm currently working on a little latex package to bring rubber ducks into tikz (a continuation from https://tex.stackexchange.com/a/347458/36296). As this is the first bigger project in which I use tikz I'd like to hear your opinion about the current way it is implemented.

I'm looking forward to your suggestions!

A few questions I have in particular:

  • Do you find it acceptable to load xcolor with the option svgnames? This could lead to option clashes if used in projects that use other colour systems. On the other hand its so easy to use the pre-made colours, much less work than mixing or defining all the colours myself.

    -> confirmed that this is bad idea, see edit below

  • Do you think the commands needs to be more flexible, i.e. optional arguments to adjust specific colours/shapes of the subcomponents? For example I could introduce an optional argument to change the head colour independently from the body colour, but this might make using the package more complicated and more importantly the code much harder to read.

A cut down version of the package:

\documentclass{article}

\RequirePackage[svgnames]{xcolor}
\RequirePackage{tikz}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% combine ducks
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%1: skin colour
\newcommand{\duck}[1]{%
    \colorlet{duck}{#1}
    \colorlet{eye}{Cornsilk}
    \colorlet{pupil}{black}
    \colorlet{bill}{orange}

    \duckbody{duck}
    \duckhead{duck}
    \duckbill{bill}
    \duckeyes{pupil}{eye}
}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% body parts
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%1: skin colour
\newcommand{\duckbody}[1]{%
    \path[fill=#1] (0.5128,1.1446) .. controls (0.2669,1.1021) and (-0.1252,0.6574) .. (0.2894,0.2611) .. controls (0.7040,-0.1351) and (2.8627,0.1303) .. (1.8177,1.4188) .. controls (0.9375,0.9457) and (1.2396,1.3785) .. (0.5128,1.1446) -- cycle;
}

%1: skin colour
\newcommand{\duckhead}[1]{%
    \path[fill=#1] (0.90,1.50) ellipse (0.50 and 0.625);
}

%1: bill colour
\newcommand{\duckbill}[1]{%
    \path[fill=#1] (0.4056,1.4721) .. controls (0.6429,1.5298) and (0.5408,1.3034) .. (0.9095,1.37) .. controls (0.0825,0.85) and (0.2685,1.3690) .. (0.4058,1.4721) -- cycle;
}

%1: pupile colour
%2: eye colour
\newcommand{\duckeyes}[2]{%
    % right eye
    \path[fill=#2, rotate=-20] (0.23,1.7675) ellipse (0.0893 and 0.125);
    \path[fill=#1, rotate=-20] (0.26,1.7575) ellipse (0.0357 and 0.0714);

    % left eye
    \path[fill=#2, rotate=-20] (-0.06,1.74) ellipse (0.0786 and 0.1143);
    \path[fill=#1, rotate=-20] (-0.03,1.73) ellipse (0.0286 and 0.0643);
}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Accessories
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%1: frame colour
\newcommand{\addglasses}[1]{
    \path[draw=#1,line width=1] (0.93,1.62) -- (1.30,1.50);
    \draw[line width=1,color=#1] (0.73,1.67) arc (65:92:0.20);
    \path[draw=#1,line width=1,rotate=-20] (0.23,1.7675) circle (0.125);
    \path[draw=#1,line width=1,rotate=-20] (-0.06,1.74) circle (0.1143);
}

\begin{document}

\begin{tikzpicture}
	\duck{yellow}
	\addglasses{brown}
\end{tikzpicture}

\end{document}

enter image description here

Full code is available from https://github.com/samcarter8/tikzducks

P.S. I know that \RequirePackage is not meant to be used in documents, but as this part is copied from the .sty file, I decided to leave it as it is.


EDIT

new version of the code

  • without the svgnames option of xcolor
  • replaced \newcommand by \newcommand*
  • hopefully added the necessary %, probably added way to many ...

\documentclass{article}

\RequirePackage{xcolor}
\RequirePackage{tikz}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% combine ducks
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%1: skin colour
\newcommand*{\duck}[1]{%
  \colorlet{duck}{#1}%
  \colorlet{eye}{white!85!yellow}%
  \colorlet{pupil}{black}%
  \colorlet{bill}{orange}%

  \duckbody{duck}%
  \duckhead{duck}%
  \duckbill{bill}%
  \duckeyes{pupil}{eye}%
}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% body parts
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%1: skin colour
\newcommand*{\duckbody}[1]{%
  \path[fill=#1] (0.5128,1.1446) .. controls (0.2669,1.1021) and (-0.1252,0.6574) .. (0.2894,0.2611) .. controls (0.7040,-0.1351) and (2.8627,0.1303) .. (1.8177,1.4188) .. controls (0.9375,0.9457) and (1.2396,1.3785) .. (0.5128,1.1446) -- cycle;%
}

%1: skin colour
\newcommand*{\duckhead}[1]{%
  \path[fill=#1] (0.90,1.50) ellipse (0.50 and 0.625);%
}

%1: bill colour
\newcommand*{\duckbill}[1]{%
  \path[fill=#1] (0.4056,1.4721) .. controls (0.6429,1.5298) and (0.5408,1.3034) .. (0.9095,1.37) .. controls (0.0825,0.85) and (0.2685,1.3690) .. (0.4058,1.4721) -- cycle;%
}

%1: pupile colour
%2: eye colour
\newcommand*{\duckeyes}[2]{%
  % right eye
  \path[fill=#2, rotate=-20] (0.23,1.7675) ellipse (0.0893 and 0.125);%
  \path[fill=#1, rotate=-20] (0.26,1.7575) ellipse (0.0357 and 0.0714);%

  % left eye
  \path[fill=#2, rotate=-20] (-0.06,1.74) ellipse (0.0786 and 0.1143);%
  \path[fill=#1, rotate=-20] (-0.03,1.73) ellipse (0.0286 and 0.0643);%
}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Accessories
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%1: frame colour
\newcommand*{\addglasses}[1]{%
  \path[draw=#1,line width=1] (0.93,1.62) -- (1.30,1.50);%
  \draw[line width=1,color=#1] (0.73,1.67) arc (65:92:0.20);%
  \path[draw=#1,line width=1,rotate=-20] (0.23,1.7675) circle (0.125);%
  \path[draw=#1,line width=1,rotate=-20] (-0.06,1.74) circle (0.1143);%
}

\begin{document}

\begin{tikzpicture}
	\duck{yellow}%
	\addglasses{brown}%
\end{tikzpicture}

\end{document}
\$\endgroup\$
  • 2
    \$\begingroup\$ I would add a lot of trailing % and suggest the use of \newcommand* instead of \newcommand - the commands created by the non-star version are allways \long, which you normally don't want. \$\endgroup\$ – Reinstate Monica - M. Schröder Aug 1 '17 at 21:02
  • \$\begingroup\$ You're correct in being dubious about the option, because if another package loads xcolor without the svgnames option the clash would be unavoidable. The package defines Cornsilk to be the same as \definecolor{Cornsilk}{rgb}{1,.972,.864}. \$\endgroup\$ – egreg Aug 2 '17 at 8:43
  • \$\begingroup\$ @egreg Thanks for your feedback, I followed your advice and dropped the svgnames option. \$\endgroup\$ – samcarter Aug 2 '17 at 9:49
  • \$\begingroup\$ @MartinSchröder Thank you very much for your feedback! I implemented your suggestions, hopefully I did not miss any % where necessary, though I probably used a bit too many :) \$\endgroup\$ – samcarter Aug 2 '17 at 9:51
7
\$\begingroup\$

Not much to say about the last version; on the other hand, you could exploit PGF keys.

\documentclass{article}

\RequirePackage{xcolor}
\RequirePackage{tikz}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% combine ducks
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\makeatletter

%1: skin colour
\newcommand*{\duck}[1][]{\tikzset{/duck/.cd,#1}\duck@draw}

\tikzset{
  /duck/.cd,
  body/.code=\def\duck@body{#1},
  head/.code=\def\duck@head{#1},
  eye/.code=\def\duck@eye{#1},
  pupil/.code=\def\duck@pupil{#1},
  bill/.code=\def\duck@bill{#1},
  glasses/.code=\duck@glassestrue\def\duck@glasses{#1},
  % set defaults
  body=yellow,
  eye=white!85!yellow,
  pupil=black,
  bill=orange,
  glasses/.default=black,
}
\newif\ifduck@glasses

\def\duck@draw{
  % body
  \path[fill=\duck@body]
    (0.5128,1.1446) .. controls (0.2669,1.1021) and (-0.1252,0.6574) ..
    (0.2894,0.2611) .. controls (0.7040,-0.1351) and (2.8627,0.1303) ..
    (1.8177,1.4188) .. controls (0.9375,0.9457) and (1.2396,1.3785) ..
    (0.5128,1.1446) -- cycle;
  % head
  \ifdefined\duck@head\else\let\duck@head=\duck@body\fi
  \path[fill=\duck@head] (0.90,1.50) ellipse (0.50 and 0.625);
  % bill
  \path[fill=\duck@bill]
    (0.4056,1.4721) .. controls (0.6429,1.5298) and (0.5408,1.3034) ..
    (0.9095,1.37) .. controls (0.0825,0.85) and (0.2685,1.3690) ..
    (0.4058,1.4721) -- cycle;
  % right eye
  \path[fill=\duck@eye, rotate=-20] (0.23,1.7675) ellipse (0.0893 and 0.125);
  \path[fill=\duck@pupil, rotate=-20] (0.26,1.7575) ellipse (0.0357 and 0.0714);
  % left eye
  \path[fill=\duck@eye, rotate=-20] (-0.06,1.74) ellipse (0.0786 and 0.1143);
  \path[fill=\duck@pupil, rotate=-20] (-0.03,1.73) ellipse (0.0286 and 0.0643);
  % glasses
  \ifduck@glasses
    \path[draw=\duck@glasses,line width=1] (0.93,1.62) -- (1.30,1.50);
    \draw[line width=1,color=\duck@glasses] (0.73,1.67) arc (65:92:0.20);
    \path[draw=\duck@glasses,line width=1,rotate=-20] (0.23,1.7675) circle (0.125);
    \path[draw=\duck@glasses,line width=1,rotate=-20] (-0.06,1.74) circle (0.1143);
  \fi
}
\makeatother

\begin{document}

\begin{tikzpicture}
\duck
\end{tikzpicture}
\qquad
\begin{tikzpicture}
\duck[body=yellow,head=pink,glasses=brown]
\end{tikzpicture}
\qquad
\begin{tikzpicture}
\duck[body=red,glasses]
\end{tikzpicture}

\begin{tikzpicture}
\duck[glasses]
\end{tikzpicture}

\end{document}

enter image description here

\$\endgroup\$
  • \$\begingroup\$ Fantastic answer! This greatly improves the code! \$\endgroup\$ – samcarter Aug 2 '17 at 10:53
  • \$\begingroup\$ @samcarter We've taken also egreg in the duck fan club :) \$\endgroup\$ – CarLaTeX Aug 2 '17 at 18:23
  • \$\begingroup\$ @CarLaTeX He is the duck hero! Using keys is a great improvement. \$\endgroup\$ – samcarter Aug 2 '17 at 18:56

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.