Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

I'm trying to create some TikZ keys which allows to easily draw distributed loads on a mechanical structure (or truss). The code I wrote at the moment is:

\documentclass[a4paper]{article}

\usepackage{tikz}
\usetikzlibrary{calc,positioning}
\makeatletter
\tikzset{load start/.style={insert path={coordinate (mec@start@load)}},%
         load end/.style={insert path={coordinate (mec@end@load)}},
         load distance/.initial=1em,
         force distance/.initial=10pt,
         force length/.initial=.7cm}
\tikzset{forze/.code={%
    \coordinate (mec@X1) at ($(mec@start@load)!\pgfkeysvalueof{/tikz/load distance}!90:(mec@end@load)$);
    \coordinate (mec@X2) at ($(mec@end@load)!\pgfkeysvalueof{/tikz/load distance}!-90:(mec@start@load)$);
    \draw (mec@X1) -- (mec@X2);
    \pgfpointdiff{\pgfpointanchor{mec@X1}{center}}{\pgfpointanchor{mec@X2}{center}}
    \pgfmathsetmacro{\mec@force@distrib@lenght}{veclen(\pgf@x,\pgf@y)}
    \pgfmathsetmacro{\mec@force@number}{round(\mec@force@distrib@lenght/\pgfkeysvalueof{/tikz/force distance})}
    \pgfmathsetmacro{\mec@force@distance}{1/\mec@force@number}
    \pgfmathparse{1-\mec@force@distance}
    \foreach \i in {0,\mec@force@distance,...,\pgfmathresult}{
      \coordinate (endarrow) at   ($(mec@X1)!\i!(mec@X2)$);
      \coordinate (startarrow) at ($(endarrow)!\pgfkeysvalueof{/tikz/force length}!90:(mec@X2)$);
      \draw[-latex] (startarrow) -- (endarrow);
    }
    \coordinate (endarrow) at   ($(mec@X1)!1!(mec@X2)$);
    \coordinate (startarrow) at ($(mec@X2)!\pgfkeysvalueof{/tikz/force length}!-90:(mec@X1)$);
    \draw[-latex] (startarrow) -- (endarrow);
  }}%}
\makeatother
\begin{document}
\begin{tikzpicture}[node distance=1mm]
\coordinate (a) at (0,0) node[left=of a]{A};
\coordinate (b) at (0,3) node[left=of b]{B};
\coordinate (c) at (3,3) node[right=of c]{C};
\coordinate (d) at (3,0) node[right=of d]{D};
\draw[thick] (a) -- (b) [load start] -- (c) [load end] -- (d);
\path[forze] (a);
\draw (d) [load start] -- (b) [load end];
\path[forze] (a);
\end{tikzpicture}
\begin{tikzpicture}[node distance=1mm]
\coordinate (a1) at (0,0) node[left=of a1]{A1};
\coordinate (b1) at (0,3) node[left=of b1]{B1};
\coordinate (c1) at (3,3) node[right=of c1]{C1};
\coordinate (d1) at (3,0) node[right=of d1]{D1};
\draw[thick] (a1) -- (b1) [load start] -- (c1) [load end,forze] -- (d1);
\draw[forze] (a1) -- (d1);
\end{tikzpicture}
\end{document}

The load start and load end keys are used only to save the beginning and ending coordinates of the distributed load, and the forze key uses these coordinates and draws in the right way the baseline and all of the arrows. In the first example everything works fine but, as you can see, to get the right output it is necessary to define another path (after the one in which load start and load end are used) where the forze key is used.

In the second example I show the syntax I would like to use (basically I want to avoid the necessity to define the second "fake" path) but you can see that something is wrong:

  • In the first case the arrows appears, but the specificed path is disappeared (the structure disappears);
  • In the second case the path is there (the line from d1 to a1) but the arrows are overimposed to the previous ones.

I think that this happens because the code defined in the forze key is processed too early, when the start and end coordinates of the load are not yet correctly saved. I tried to use the append after command, execute at end to, execute at end note keys, but the result is always the same. Is there a better approach?

An additional question: is it correct to define macros (like \mec@force@number) via \pgfmathsetmacro within a key (like forze) or it should be better to define them outside it? Which is better from a "register consumption" point of view?

Update

As @percusse suggested, I tried to use the preaction and postaction keys. I tried those possibilities:

\draw[postaction={forze}] (a) -- (b) [load start] -- (c) [load end] -- (d);

Perfect result

\draw[thick,postaction={forze}] (a) -- (b) [load start] -- (c) [load end] -- (d);
% or
\draw[thick][postaction={forze}] (a) -- (b) [load start] -- (c) [load end] -- (d);
% or
\draw[thick][postaction={forze,thin}] (a) -- (b) [load start] -- (c) [load end] -- (d);

bad result: the load appears to be thick too

\draw[preaction={draw,thick},postaction={forze}] (a) -- (b) [load start] -- (c) [load end] -- (d);

perfect result, but not transparent to the user (that should use the preaction key). So it seems that the second time that the path is used, it automatically gets the options from the first one (the manual says that the options are different, but it seems that this is true only if the same options are redefined). Is it possible to avoid this allowing to normally specify options on the path and just use postaction={forze} to draw the load (which can be easily made by a specific key)?

share|improve this question
    
I guess you want to use the preaction and postaction options to reuse the path more than once. Also related : tex.stackexchange.com/questions/39242/… –  percusse Oct 8 '12 at 20:58
    
@percusse I updated the question with some considerations and trials. Thanks for the hint and for the related question (I really needed something like that) –  Spike Oct 9 '12 at 16:40
add comment

1 Answer

up vote 3 down vote accepted

The difficulty here is that not all options are handled in the same way. You can divide them roughly into "low" and "high", and into "immediate" and "delayed".

By low options I mean ones that set some TeX macro or similar. These are things like setting the line width, the colour. The basic style options. High options are ones that set things up a bit more, like setting up postactions.

Immediate options are ones that are processed right at the moment they are invoked. Delayed options are ones where the real setting part is done later (clearly something has to be done at the moment of invocation, but the real option is set later). Line width is set right there and then, colour is delayed.

Another consideration is that many of the low-level styles, being controlled by TeX macros (or similar), obey TeX groupings.

With that in mind, the problem with your latest code is that you are setting the options on the main path and these last for the postaction path because it is in the same group and so these style options persist. So if you want these not to apply to the postaction path, you need to save the style beforehand and then restore it within the postaction path. But then you need to take into account the delay factor.

So the following code goes a little way towards this. When the forze key is invoked, the style in force (currently the line width and the colour, but you could easily add more stuff) at that point is saved - but this might not be the style you think it is due to the delay on some options. The safest thing is to use forze first on a path.

\documentclass[a4paper]{article}
%\url{http://tex.stackexchange.com/q/75904/86}

\usepackage{tikz}
\usetikzlibrary{calc,positioning}
\makeatletter
\tikzset{load start/.style={insert path={coordinate
(mec@start@load)}},%
         load end/.style={insert path={coordinate (mec@end@load)}},
         load distance/.initial=1em,
         force distance/.initial=10pt,
         force length/.initial=.7cm,
         forze/.code={%
           \tikzset{
             save style=\forze@style,
             postaction={forze code},
           }
         },
         save style/.code={%
           \pgfutil@colorlet{forze@color}{.}%
           \edef#1{%
             line width=\the\pgflinewidth,
             color=forze@color,
           }
         },
         restore style/.code={%
           \expandafter\tikzset\expandafter{#1}%
         }
}
\tikzset{forze code/.code={%
    \message{got called}%
    \begin{scope}[restore style=\forze@style]%
    \coordinate (mec@X1) at
($(mec@start@load)!\pgfkeysvalueof{/tikz/load
distance}!90:(mec@end@load)$);
    \coordinate (mec@X2) at
($(mec@end@load)!\pgfkeysvalueof{/tikz/load
distance}!-90:(mec@start@load)$);
    \draw (mec@X1) -- (mec@X2);
    \pgfpointdiff{\pgfpointanchor{mec@X1}{center}}{\pgfpointanchor{mec@X2}{center}}
    \pgfmathsetmacro{\mec@force@distrib@lenght}{veclen(\pgf@x,\pgf@y)}
    \pgfmathsetmacro{\mec@force@number}{round(\mec@force@distrib@lenght/\pgfkeysvalueof{/tikz/force
distance})}
    \pgfmathsetmacro{\mec@force@distance}{1/\mec@force@number}
    \pgfmathparse{1-\mec@force@distance}
    \foreach \i in {0,\mec@force@distance,...,\pgfmathresult}{
      \coordinate (endarrow) at   ($(mec@X1)!\i!(mec@X2)$);
      \coordinate (startarrow) at
($(endarrow)!\pgfkeysvalueof{/tikz/force length}!90:(mec@X2)$);
      \draw[-latex] (startarrow) -- (endarrow);
    }
    \coordinate (endarrow) at   ($(mec@X1)!1!(mec@X2)$);
    \coordinate (startarrow) at ($(mec@X2)!\pgfkeysvalueof{/tikz/force
length}!-90:(mec@X1)$);
    \draw[-latex] (startarrow) -- (endarrow);
    \end{scope}
  }}%}
\makeatother
\begin{document}
\begin{tikzpicture}[node distance=1mm]
\coordinate (a) at (0,0) node[left=of a]{A};
\coordinate (b) at (0,3) node[left=of b]{B};
\coordinate (c) at (3,3) node[right=of c]{C};
\coordinate (d) at (3,0) node[right=of d]{D};
\draw[forze,ultra thick,red] (a) -- (b) [load start] -- (c) [load end]
-- (d);
\end{tikzpicture}

\begin{tikzpicture}[node distance=1mm]
\coordinate (a) at (0,0) node[left=of a]{A};
\coordinate (b) at (0,3) node[left=of b]{B};
\coordinate (c) at (3,3) node[right=of c]{C};
\coordinate (d) at (3,0) node[right=of d]{D};
\draw[red,ultra thick,forze] (a) -- (b) [load start] -- (c) [load end]
-- (d);
\end{tikzpicture}
\end{document}
share|improve this answer
    
This answers the question, indeed. So thanks a lot. But, how do you know about things like \pgfutil@colorlet{}{}? I can't find it in the manual! Is it necessary to read the low level TikZ code to know that? And the same question applies to the knowledge about the options. There is a "preferred way" to learn such things? Again, thanks –  Spike Oct 10 '12 at 20:53
    
Another question: why the postaction key is in a \tikzset command (and some trials show that it needs to be there)? –  Spike Oct 10 '12 at 21:16
1  
@Spike I learn by looking at the code. I don't know if there is an easier way. For the second, oops. The code went through several variations and so probably isn't the neatest. Try removing the \tikzset and braces, and put forze/.style= instead of forze/.code=. There was originally some non-trivial code in there but I moved it around. I also notice that I've left a \message in there! –  Loop Space Oct 11 '12 at 8:49
    
I should say that I don't think my code above is a very good implementation; it's more to highlight the things you need to think about when designing this. In similar situations I've used an extra key which sets a default style for the extra paths explicitly. Picking up on the ambient style is - as I tried to point out - problematic. In such cases, I find it easier to just give control over to the user rather than try to anticipate all possible eventualities. –  Loop Space Oct 11 '12 at 8:51
1  
There is a lot that's useful in the manual as well - even about the lower levels. But when I need to figure out why a particular thing happens, then I find myself reading the source code. –  Loop Space Oct 11 '12 at 21:21
show 1 more comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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