11

What I want to do

I want to create a command \planfigur{<edges>}{<angles>} which draws a triangle using TikZ. \planfigur should have 2 mandatory arguments, which let me specify edges and/or angles (where a = alpha, b = beta and c = gamma) of the triangle, which are drawn in red instead of black color.

E. g. \planfigur{ab}{bc} draws a black triangle, where the edges a and b and the angles beta and gamma are red.

planfigur

I use expl3 and xparse. I already have read (Is it reasonable to expect an expl3-compatible release of TikZ/PGF in the future?), that there are problems in using expl3 and tikz together (which makes sense).

So I played around and tried to outsmart TikZ. I had the following idea, which unfortunately doesn't work (1:0 for TikZ :-)). The approach is to move all expl3 code into a new command, where I can use \tl_if_in:nnT to check the arguments.

Code

\documentclass{article}

\usepackage{expl3, xparse}

\usepackage{tikz}
\usetikzlibrary{calc}

\ExplSyntaxOn

\tl_new:N \__edu_planfigur_temp

\DeclareDocumentCommand \planfigurLines { m } {

  \tl_clear:N \__edu_planfigur_temp

  \tl_if_in:nnT {#1} {a} {
    \tl_put_right:Nn \__edu_planfigur_temp {\draw (b) -- (c);}
  }

  \tl_if_in:nnT {#1} {b} {
    \tl_put_right:Nn \__edu_planfigur_temp {\draw (a) -- (c);}
  }

  \tl_if_in:nnT {#1} {c} {
    \tl_put_right:Nn \__edu_planfigur_temp {\draw (a) -- (b);}
  }

  \tl_use:N \__edu_planfigur_temp
}

\DeclareExpandableDocumentCommand \planfigurAngles { m } {
  \tl_if_in:nnT {#1} {a} {
    \tl_put_right:Nn \__edu_planfigur_temp {\draw ($(a) + (0:1)$) arc (0:40:1) ($(a) + (20:0.7)$) node {$\alpha$};}
  }
  \tl_if_in:nnT {#1} {b} {
    \tl_put_right:Nn \__edu_planfigur_temp {\draw ($(b) + (120:1)$) arc (120:180:1) ($(b) + (150:0.7)$) node {$\beta$};}
  }
  \tl_if_in:nnT {#1} {c} {
    \tl_put_right:Nn \__edu_planfigur_temp {\draw ($(c) + (220:1)$) arc (220:300:1) ($(c) + (260:0.65)$) node {$\gamma$};}
  }

  \tl_use:N \__edu_planfigur_temp
}

\ExplSyntaxOff

\DeclareExpandableDocumentCommand \planfigur { m m } {
  \begin{tikzpicture}[scale=0.65, line join=round, thick]

    \coordinate (a) at (0,0);
    \coordinate (b) at (5,0);
    \coordinate (c) at (3.37, 2.83);

    \draw (a) -- node[below] {$c$} (b) -- node[above right] {$a$} (c) -- node[above left] {$b$} (a) -- cycle;

    \draw (a) node[left] {$A$};
    \draw (b) node[right] {$B$};
    \draw (c) node[above] {$C$};

    \begin{scope}[color=red, fill=red!25, very thick]
      \planfigurLines{#1}
      \planfigurAngles{#2}
    \end{scope}

\end{tikzpicture}
}

\begin{document}

\planfigur{ac}{a}

\end{document}

Error

! Package pgf Error: No shape named 0:1 is known.

See the pgf package documentation for explanation. Type H for immediate help. ...
l.70 \planfigur{ac}{a}

7
  • 2
    I strongly suspect that the problem is due to the fact that in expl3 then : has the catcode of a letter but TikZ expects it to be other. One way around this is to define a token list containing a colon with catcode "other" and use that in place of the bare : in your code. Commented Aug 19, 2014 at 20:18
  • @LoopSpace: Yeah, that makes sense. I forgot the problem with :. This would also explain, why the lines (which don't contain a :) work without any problem. Your approach sounds promising, but I don't know how to do this. :-(
    – dawu
    Commented Aug 19, 2014 at 20:23
  • 2
    You can do \tl_const:Nx \c_edu_colon_tl { \token_to_str:N : } and then use \c_edu_colon_tl instead of : in coordinates. \c_edu_colon_tl then contains a : with catcode 12 (other) instead of 11 (letter).
    – cgnieder
    Commented Aug 19, 2014 at 20:24
  • @cgnieder: Yes, this did it! You are my hero of the day. :-) What to do with the answer? Do you want to answes the question or should I answer it with the full working code?
    – dawu
    Commented Aug 19, 2014 at 20:26
  • @dawu Your \planfigur... commands are not expandable, so they should be declared with \NewDocumentCommand.
    – egreg
    Commented Aug 19, 2014 at 20:49

2 Answers 2

16

One of the things \ExplSyntaxOn does is giving the colon category code 11 (letter) so it can be used as part of macro names. In coordinates TikZ however expects a colon with category code 12 (other).

The easiest way: you can use the predefined \c_colon_str instead of : in TikZ' coordinates.

Original solution before \c_colon_str was available:

One solution that works is defining a token list that contains only a : with category code 12

\tl_const:Nx \c_edu_colon_tl { \token_to_str:N : } 

and then use said token list \c_edu_colon_tl instead of : in TikZ' coordinates.


BTW: your token list \__edu_planfigur_temp misses the recommended ending for a token list: _tl. It also misses the recommended start \l or \g which denotes if it is local or global. I'd rename it into \l__edu_planfigur_temp_tl.

In expl3 variables generally should start either with \l (local), \g (global) or \c (constant) and end with the type of variable (_tl for a token list, _int for an integer and so on).

4
  • Thanks for the explanation. I know about the naming conventions of expl3, but this example was very quick and dirty. But you are right, of course!
    – dawu
    Commented Aug 19, 2014 at 20:38
  • @dawu well, the answer is for you but also for others with a similar problem and they might not be aware of the naming convention. So it's better to repeat it. :) I'd also say it's better to follow the convention in MWEs, too: otherwise one might be tempted to get sloppy also in “real” code... :)
    – cgnieder
    Commented Aug 19, 2014 at 20:45
  • You are right. Should I correct it in my MWE? As you said, it would be better.
    – dawu
    Commented Aug 19, 2014 at 20:48
  • @dawu I don't think it's necessary: since I explained the convention in my answer we should be fine, I think.
    – cgnieder
    Commented Aug 19, 2014 at 20:50
3

Two more possibilities

\newcommand*\tikzangle[2]{#1:#2}
…
\ExplSyntaxOn
\draw (0,0) -- (\tikzangle{20}{2cm});
\ExplSyntaxOff

and a more practical one

\begingroup
\lccode`\X=`\:
\lowercase{\endgroup
  \gdef\tikzangle(#1X#2){#1:#2}}
\ExplSyntaxOn
\draw (0,0) -- \tikzangle(20:2cm);
\ExplSyntaxOff

To add the more general one, “easier to see” than cgnieder's

\def\othercolon{:}
\ExplSyntaxOn
\draw (0,0) -- (20\othercolon2cm);
\ExplSyntaxOff
6
  • Also very nice, thank you! It's always interesting to find new ways how to play a trick on the syntax. :o) But I think the first one is a bit "cleaner".
    – dawu
    Commented Aug 21, 2014 at 22:06
  • Nice. This must be adapted for arc (220:300:1) as well but that should not be a problem :)
    – cgnieder
    Commented Aug 21, 2014 at 22:49
  • @dawu The cool thing about the second one is that you just need to add \tikzangle (or whatever name you choose) before the angle you would write in TikZ (20:2cm).
    – Manuel
    Commented Aug 22, 2014 at 2:24
  • @cgnieder May be defining something like \tikzarc similar to this one.
    – Manuel
    Commented Aug 22, 2014 at 2:25
  • 1
    The expl3 version also will always have a : with catcode 12 while \def\othercolon{:} saves : with whatever catcode it has (possibly 13 with \usepackage[french]{babel} for example). The equivalent would rather be \newcommand\othercolon{}\edef\othercolon{\string:}
    – cgnieder
    Commented Aug 23, 2014 at 18:52

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .