4

I'm trying to build an array dynamically in latex then use it in tikz.

I'm a little confused about how to create an array and add evaluated mathematical expressions to it (I'm trying arrayjob).

Here's what I have so far; for some reason, I cannot access the values in the second foreach, getting the error (! Undefined control sequence. \pntAngles1~ ->\val), the first commented print in the first foreach works btw:

\documentclass{article}

\usepackage{tikz}

\usepackage{calc}
\usepackage{fp}
\usepackage{arrayjob}
\usepackage{ifthen}
\usepackage{amsmath}
% \usetikzlibrary{arrows,intersections}

\begin{document}

\def\n{8} % number of points
\FPeval{\lastn}{\n-1}
\FPeval{\angleOffset}{clip(360/\n)} % angle offset between dots

\newarray\pntAngles

\foreach \i in {0,...,\lastn} {
  \FPeval{\val}{clip(\i*\angleOffset)}
  \pntAngles(\i)= {\val}
  % \pntAngles(\i)
}

\foreach \i in {0,...,\lastn} {
  \pntAngles(\i)
}

\end{document}    

Would appreciate any advice. Thanks

  • 1
    Welcome to TeX.SX! With LaTeX you shouldn't be using arrayjob, but arrayjobx. Depending on what you want to use the array for, there may be better methods. Anyway, you should always remember that \foreach executes each cycle in a group, so the assignment to the array is lost when the group ends. – egreg Jun 23 '14 at 14:41
  • I'm not sure I understand what a group is; sounds like a scope? but the array was defined outside the foreach scope, so where did the values go? I'll play around with the scopes... thanks for the tip anyway :) – Daugmented Jun 23 '14 at 14:49
  • In TeX we usually talk about a group, but that's the idea. The assignment of values in TeX is local (so undone when a group/scope ends), unless explicitly marked as global. As far as I can see in the documentation of arrayjobx there's no provision for global assignments. – egreg Jun 23 '14 at 14:54
  • hi @egreg, thank for the reply. But if I cannot reuse the array outside the foreach what's the point in having an array? Is there some other way to construct an array dynamically so it can be used later? – Daugmented Jun 23 '14 at 14:57
4

The arrays defined by arrayjobx (which should be used in LaTeX instead of arrayjob) are local, so if they are assigned values in a group (or a scope, if you prefer), the value will be lost when the group ends.

Also, it seems that arrayjobx doesn't like 0 as an index.

A feature of \foreach is that it executes its cycles in a group, so you're in a blind alley.

You could define a new array type, let's call it a “global array”, but some other tricks are needed; a syntax like

\pntAngles(\i)={\val}

will assign \val to the correspondent array element, not the value of \val.

\documentclass{article}

\usepackage{tikz}

\usepackage{fp}
\usepackage{arrayjobx}
\usepackage{etoolbox}

% define a new data structure
\let\newglobalarray\newarray
\patchcmd{\newglobalarray}{\edef}{\xdef}{}{}

\begin{document}

\def\lastn{8} % number of points
\FPeval{\angleOffset}{clip(360/\lastn)} % angle offset between dots

\newglobalarray\pntAngles

\foreach \i in {1,...,\lastn} {
  \FPeval{\val}{clip((\i-1)*\angleOffset)}
  % expand \val before doing the assignment
  \begingroup\edef\x{\endgroup\noexpand\pntAngles(\i)= {\val}}\x
}

\foreach \i in {1,...,\lastn} {
  \pntAngles(\i)
}

\end{document}

enter image description here

A different approach with expl3 and property lists; sequences are more efficient, but this better emulates arrayjobx that allows any kind of index for its arrays.

\documentclass{article}

\usepackage{tikz}
\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentCommand{\newarray}{m}
 {
  \prop_new:c { g_daugmented_array_#1_prop }
 }

\DeclareExpandableDocumentCommand{\arrayget}{mm}
 {
  \prop_get:cx { g_daugmented_array_#1_prop } { #2 }
 }

\NewDocumentCommand{\arrayput}{mmm}
 {
  \prop_gput:cxx { g_daugmented_array_#1_prop } { #2 } { #3 }
 }

\cs_generate_variant:Nn \prop_get:Nn { cx }
\cs_generate_variant:Nn \prop_gput:Nnn { cxx }

\DeclareExpandableDocumentCommand{\fpeval}{m}
 {
  \fp_eval:n { #1 }
 }

\NewDocumentCommand{\fpevalset}{mm}
 {
  \cs_new:Npx #1 { \fp_eval:n { #2 } }
 }
\ExplSyntaxOff

\begin{document}

\fpevalset{\np}{8}
\fpevalset\lastn{\np-1} % number of points
\fpevalset{\angleOffset}{floor(360/\np)} % angle offset between dots

\newarray{pntAngles}

\foreach \i in {0,...,\lastn} {
  \arrayput{pntAngles}{\i}{\fpeval{floor(\i*\angleOffset)}}
}

\foreach \i in {0,...,\lastn} {
  \arrayget{pntAngles}{\i}
}

\end{document}    
  • Both seem to work nicely. I have no idea what's going on in either, but will try and use it as a black box. Thanks :) – Daugmented Jun 23 '14 at 16:50
  • @Daugmented In the first code I copied the code for \newarray in \newglobalarray and changed an \edef to \xdef to make the action of adding a value to the array global instead of local (\xdef is the same as \global\edef). In the second code I resorted to global assignments to begin with. – egreg Jun 23 '14 at 17:19
  • Thanks @egreg, and in the first, can elaborate a little more about: % expand \val before doing the assignment \begingroup\edef\x{\endgroup\noexpand\pntAngles(\i)= {\val}}\x – Daugmented Jun 23 '14 at 18:59
  • also, how would you assign the array values later (within a tikz picture) to new variables? something like \FPeval\xx{clip(\pntAngles(\i))} does not work for some reason (! Use of \pntAngles doesn't match its definition.) – Daugmented Jun 23 '14 at 19:14
  • sorry for all the questions, but I'm a little lost with all this. What I was really trying to do is something similar to: texample.net/tikz/examples/cn4-points-of-intersection but I want to parametrize a drawing and need to generate his array (\myangles) from these parameters, and already things got messy :-\ With your solution, when I trying using the array within the tikz I'm still not getting it to compile – Daugmented Jun 23 '14 at 19:21

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.