7

I want to create a macro, namely \newpoint{<point name>}{<point style>}, that creates macros like \Point<point name>{<x coord>}{<y coord>}{<label>}.

I've seen How to define a macro to create a new macro with a name passed as its argument? which is half way through as it does not show how to make the created macro receive arguments.

I tried:

\newcommand*{\newpoint}[2]{%
   \tikzset{#1/.style={#2}}%
   \newcounter{point#1}\setcounter{point#1}{0}%
   \def\csname Point#1\endcsname (##1,##2)|##3;{%
        \stepcounter{point#1}\fill[#1] (##1,##2) circle (2pt) node[above](#1-\thepoint#1){##3};}%
}

But it didn't work, appearently Use of \csname doesn't match it's definition and honestly... I don't know what I'm doing anymore.

Here is my M(N)WE:

\documentclass[tikz, border=2mm]{standalone}
\newcommand*{\newpoint}[2]{%
   \tikzset{#1/.style={#2}}%
   \newcounter{point#1}\setcounter{point#1}{0}%
   \def\csname Point#1\endcsname (##1,##2)|##3;{%
        \stepcounter{point#1}\fill[#1] (##1,##2) circle (2pt) node[above](#1-\thepoint#1){##3};}%
}
\newpoint{A}{red}
\begin{document}
 \begin{tikzpicture}
  \PointA(1,2)|A;
 \end{tikzpicture}
\end{document} 
  • 1
    \expandafter\def\csname ..., the counter stuff seems very bad. What exactly are you trying there? – daleif Nov 17 '16 at 12:15
  • This is actually a simplified version of what I'm doing, the macro \PointA does way more than just the circle. But essencially, that's it, it does some drawing and uses automatic naming, therefore the counter is absolutely mantadory here. Using \expandafter gives a new error Undefined \thepoint , which means \thepoint#1 is not working, I may have to change the question... – Guilherme Zanotelli Nov 17 '16 at 12:26
  • really are you sure you want to allocate a new counter for every point (in classic tex for example that would limit you to 100 or so points) or a lot less if you have loaded many packages. – David Carlisle Nov 17 '16 at 12:28
  • @DavidCarlisle, I had no idea about that, but I think my drawing won't have as much as 100 Points. After done with one drawing I reset the counter. Are there better ways to Keep track of the Point numbers? – Guilherme Zanotelli Nov 17 '16 at 12:31
  • 1
    @PietvanOostrum at least you got the tick, not egreg, so all is not lost! – David Carlisle Nov 17 '16 at 15:00
5

As @daleif remarked, put\expandafter before \def. And to get \thepointA you have to use \csname ... \endcsname there. I guess this is what you want:

\newcommand*{\newpoint}[2]{%
   \tikzset{#1/.style={#2}}%
   \newcounter{point#1}\setcounter{point#1}{0}%
   \expandafter\def\csname Point#1\endcsname (##1,##2)|##3;{%
        \stepcounter{point#1}\fill[#1] (##1,##2) circle (2pt) node[above](#1-\csname thepoint#1\endcsname){##3};}%
}

And here is a solution without a real counter for each call of \newpoint, based on the solution with a pseudo-counter by @egreg, but with an increment of the pseudo-counter, each time the \point<name> macro is called.

\newcounter{pointnumber}
\newcommand\StepPointNumber[1]{%
    \setcounter{pointnumber}{\csname number@point#1\endcsname}%
    \stepcounter{pointnumber}
    \expandafter\xdef\csname number@point#1\endcsname{\thepointnumber}%
              \expandafter\show\csname number@point#1\endcsname
}
\newcommand*{\newpoint}[2]{%
   \tikzset{#1/.style={#2}}%
   \expandafter\def\csname number@point#1\endcsname{0}%
   \expandafter\def\csname Point#1\endcsname (##1,##2)|##3;{%
        \StepPointNumber{#1}%
        \fill[#1] (##1,##2) circle (2pt) node[above](#1-\csname number@point#1\endcsname){##3-\csname number@point#1\endcsname};}%
}
  • Would you care to elaborate why using the pseudo counter would be an improvement as to having each \Point having its own counter? To me it seems unlogical. – Guilherme Zanotelli Nov 17 '16 at 13:54
  • As David Carlisle said in the comments, counters are a scarce resource, although in modern LaTeX systems there are 32768 available (of which some 100+ are already in use). So it was mainly an intellectual exercise. But in a very complicated and/or large document with many points (more than 30000) it could be helpful. – Piet van Oostrum Nov 17 '16 at 14:08
  • Interesting... Although this was more an approach to reduce the preamble size and easily create (if needed be) other \Point like macros, I've been meaning to do something like it for a while, but now I've used to improve my answer in this question. Thank's for the insights! ;D – Guilherme Zanotelli Nov 17 '16 at 14:17
4

I don't see the need to allocate a new counter, unless you want to do arithmetic with it.

The main point, though, is that you need to use \csname in the right way:

\documentclass[tikz, border=2mm]{standalone}

\newcommand*{\newpoint}[2]{%
   \tikzset{#1/.style={#2}}%
   \expandafter\def\csname number@point#1\endcsname{0}%
   \expandafter\def\csname Point#1\endcsname (##1,##2)|##3;{%
        \fill[#1] (##1,##2) circle (2pt) node[above](#1-\csname number@point#1\endcsname){##3};}%
}

\newpoint{A}{red}

\begin{document}

\begin{tikzpicture}
  \PointA(1,2)|A;
\end{tikzpicture}

\end{document}
  • Indeed, the counter made no sense. I had forgot the \stepcounter inside the definition of \Point#1. I've edited the question... – Guilherme Zanotelli Nov 17 '16 at 12:38

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.