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.

The goal I want to obtain is to have a parallel curve to a generic curve defined in a \draw command trough TikZ. To achieve it, I used the TikZ decorations library and the command \pgfdeclaredecoration to create it. The solution adopted by me is not very efficient but it works conceptually. Here it is a minimal example of my listing:

\documentclass{standalone}

\usepackage{tikz}

\usetikzlibrary{calc,decorations}
\makeatletter
\newlength\@l
\newcount\@c
\tikzset{
raise line/.initial   = 25pt,
raise points/.initial = 100
}
\pgfdeclaredecoration{Parallel Line}{initial}{
\state{initial}[persistent precomputation={%
                   \pgfmathsetlength{\@l}%
                   {\pgfdecoratedpathlength/(\pgfkeysvalueof{/tikz/raise points})}%
                   \@c=1%
                 },
                 next state = middle,
                 width      =\@l]{\coordinate (DecoratedPointRaised-\the\@c) at 
                                       ($(0,0)+(0,\pgfkeysvalueof{/tikz/raise line})$);}

\state{middle}[persistent precomputation = {\@c=\numexpr\the\@c+1\relax},
               width = \@l]{\coordinate (DecoratedPointRaised-\the\@c) at
                                 ($(0,0)+(0,\pgfkeysvalueof{/tikz/raise line})$);}

\state{final}[persistent precomputation  = {\@c=\numexpr\the\@c+1\relax},
              persistent postcomputation = {\foreach[count=\t from 1]\n in{2,...,100}{ %
                                            \draw (DecoratedPointRaised-\t)--          % Here it does not work!!
                                            (DecoratedPointRaised-\n);}}]{             %
\pgfcoordinate{DecoratedPointRaised-\the\@c}{\pgfpointdecoratedpathlast}
}
}
\makeatother
\begin{document}
\begin{tikzpicture}
\draw (0,0) .. controls++(1,1) and (6,-3).. (7,0);

\draw[decorate,decoration=Parallel Line] (0,0)  .. controls++(1,1) and (6,-3).. (7,0);

%\foreach[count=\t from 1]\n in{2,...,100}{                       %                  
%     \draw (DecoratedPointRaised-\t)--(DecoratedPointRaised-\n); % Here it works!!!!
%}                                                                % 
\end{tikzpicture}
\end{document}

This is what I draw:

enter image description here

The line below is the original one while the above one is the decoration.

The step to create the parallel curve are the following:

  1. I create a new length \@l which is the step of the decoration. I create a new counter \@c to have a sequential name of thecoordinate I will create.
  2. The first state is initial where it is computed the pitch \@l and where at the beginning \@c is set equal to one. Then the first coordinate of the DecoratedPointRaised-\the\@c series is created. Finished the initial state, the decoration passes to the middle state.
  3. In the middle state precomputation it is computed the new \@c as \@c=\@c+1. After the \@c coordinate is created.
  4. When necessary, the decoration passes to the final state, where the last \@c coordinate is computed. Here I use post computation to draw all the segments that connect all created coordinates.

The problem is that the post computation in the final state doesn't work, while, if I write the code inside it after the \draw command, I have no problem. Why? How can I avoid it?

In the final state, is the coordinate system I use into the \state command the global one and not the transformed one?

share|improve this question
    
I don't know if it is what you wanted but have you tried \draw[double distance = 1cm] (0,0) .. controls++(1,1) and (6,-3).. (7,0); –  percusse Oct 16 '11 at 10:51
    
@percusse: no because it is not what I want –  Azoun Oct 16 '11 at 13:29
    
I see. Can you elaborate a little bit further how it differs? Because it also draws a generic pointwise parallel curve in a \draw command as you stated in the question. I can see that you want to finish what you have started but I was trying to give an alternative way. Apparently it is not what you desire. –  percusse Oct 16 '11 at 14:56
1  
I'd also like to know a bit more about why you are trying to do this, purely out of curiosity as it's something that's come up once or twice and I've thought that a decoration would be a good way to implement it so I'm very interested in your method and would like to know what led you to do this. (I'll also have a think about the specific question as well.) –  Loop Space Oct 16 '11 at 16:46
    
@Andrew Stacy: I'm drawing some node shape to obtain something like you can see at this link dic.unipi.it/stefano.bennati/2011-02-11-PS_SdCI_A&C.pdf. I want to obtain the distibuted forces on beams.( What is your question?) –  Azoun Oct 16 '11 at 20:03

2 Answers 2

I can give a solution that can be compiled only with LuaLaTeX and wit the latest version of PGF 2.10-CVS because it uses the luamath capabilities into pgf. Here it is the listing

% !TEX encoding   = UTF-8
% !TEX program    = LuaLaTeX
% !TEX spellcheck = en_GB
\documentclass{standalone}

%\usepackage[margin=2.5cm,left=3cm]{geometry}

\usepackage{tikz}

\usepgflibrary{luamath}
\pgfkeys{/pgf/luamath=true}%<-Put it fase to see what happen

\usetikzlibrary{decorations}
\makeatletter
\newlength\pgf@distributed@force@pitch
\newcount\pgf@distributed@force@new@point
\newcount\pgf@distributed@force@old@point
\newcount\pgf@distributed@force@pitch@points

\tikzset{
distributed force intensity/.initial       = 20pt,
distributed force angle/.initial           = 90,
distributed force intervals/.initial       = 8,
distributed force points/.initial          = 200,%<-I used this value because it does not give problems at path end.
                                                 % change it to see what I mean
}
\pgfdeclaredecoration{Distributed Force}{initial}{
\state{initial}[persistent precomputation={%
                   \pgfmathsetmacro{\pgf@distributed@force@draw@arrow@index}%
                   {\pgfkeysvalueof{/tikz/distributed force points}/\pgfkeysvalueof{/tikz/distributed force intervals}}
                   \pgfmathsetlength{\pgf@distributed@force@pitch}%
                   {\pgfdecoratedpathlength/(\pgfkeysvalueof{/tikz/distributed force points})}%
                 },
                 next state = middle,
                 width      =\pgf@distributed@force@pitch]
                                 {\global\pgf@distributed@force@new@point=0%
                                  \global\pgf@distributed@force@pitch@points=0%
                                  \draw[<-] (0,0)--
                                            (0,\pgfkeysvalueof{/tikz/distributed force intensity})
                                             coordinate (DecoratedPointRaised-\the\pgf@distributed@force@new@point);}

\state{middle}[width=\pgf@distributed@force@pitch]
                {\global\pgf@distributed@force@old@point=\pgf@distributed@force@new@point
                 \global\pgf@distributed@force@new@point=\numexpr\the\pgf@distributed@force@new@point+1\relax
                 \global\pgf@distributed@force@pitch@points=\numexpr\the\pgf@distributed@force@pitch@points+1\relax
                 \draw (0,\pgfkeysvalueof{/tikz/distributed force intensity})
                       coordinate(DecoratedPointRaised-\the\pgf@distributed@force@new@point)--
                       (DecoratedPointRaised-\the\pgf@distributed@force@old@point);
                       \ifnum\pgf@distributed@force@pitch@points=\pgf@distributed@force@draw@arrow@index
                      \draw[<-] (0,0)--(0,\pgfkeysvalueof{/tikz/distributed force intensity});
                      \global\pgf@distributed@force@pitch@points=0
                      \fi
                  }

\state{final}{\global\pgf@distributed@force@old@point=\pgf@distributed@force@new@point
                \global\pgf@distributed@force@new@point=\numexpr\the\pgf@distributed@force@new@point+1\relax
                \pgftransformshift{\pgfpointdecoratedpathlast}
                \draw[<-] (0,0)--++(0,\pgfkeysvalueof{/tikz/distributed force intensity})
                 coordinate(DecoratedPointRaised-\the\pgf@distributed@force@new@point);
                \draw (DecoratedPointRaised-\the\pgf@distributed@force@new@point)--
                      (DecoratedPointRaised-\the\pgf@distributed@force@old@point);
}
}
\makeatother
\tikzset{distributed force/.style = {postaction=decorate,decoration=Distributed Force}}
\begin{document}
\centering
\begin{tikzpicture}

\draw[distributed force,yshift=-3cm,distributed force intensity=10pt]
                     (0,1)  .. controls (1,2) and (6,-2).. (7,0);
\draw[distributed force] (0,0)--++(8,0);
\end{tikzpicture}
\end{document}

This is what I obtain enter image description here

share|improve this answer

This also seems to work with a small artifact at the start of double line but using the standard release of TikZ v2.10.

\usetikzlibrary{decorations.markings}

\tikzset{forcedist/.style={decorate, decoration={markings,
mark=between positions 0 and 1 step 0.0999 with {\draw[<-] (0,-#1) -- (0,#1); }}}}%Here

\begin{tikzpicture}
\draw [double distance = 1cm,thick]  (0,0) .. controls++(1,1) and (6,-3).. (7,0);
\draw [forcedist=5mm]  (0,0) .. controls++(1,1) and (6,-3).. (7,0);

\draw [double distance = 5mm,thick]  (0,3) --++(8,0);
\draw [forcedist=2.5mm]  (0,3)--++(8,0);
\end{tikzpicture}

resulting with

enter image description here

You can adjust the spacing of the arrows and the height of the beams rather easily. Notice the weird mismatch of tangent computation. The straight line does not suffer from this.

I did not try to combine these two commands, first I don't know if that's what you wanted and second you can use your own code to draw the shifted line and add this on top of it.

EDIT : The hack I have used is as the following : I overlay a decoration onto a double line. I am providing the coordinates that would lie in the middle or center of this decorated line, not the edges. But probably, you are using the coordinates as one of the edges and duplicate it, since the one of the black lines passes from the center of the red curve. I will try to blend this into the code.

EDIT2 To be able to use the given path as the edge, I think you can use the \pgfsetinnerlinewidth{} command given in Section 73.2.7 Inner Lines in the manual of TikZ v2.10. I did not try it yet but seems the easiest way out.

EDIT3 (By Andrew Stacey) Here's a slighty ad-hoc method of getting the arrows on the specified line. We draw the double line, but clip against itself so that only one half gets drawn (see Is there a way to draw TikZ lines on the "inside" or "outside" of a path? for more on this technique). This is where the crudest bit of the design comes in: since the paths aren't closed, we need to close them to make the clip. Then we draw the line itself. Finally, we decorate it using percusse's decoration, only we adjust the coordinates so that the base of the arrow is on the line.

\documentclass{standalone}
%\url{http://tex.stackexchange.com/q/31707/86}
\usepackage{tikz}
\usetikzlibrary{decorations.markings}

\tikzset{forcedist/.style={decorate, decoration={markings,
mark=between positions 0 and 1 step 0.0999 with {\draw[->] (0,0) -- (0,-#1); }}}}%Here
\begin{document}
\begin{tikzpicture}
\begin{scope}
\clip[overlay] (0,0) .. controls++(1,1) and (6,-3).. (7,0) -- ++(3,0) -- ++(0,-5) -- ++(-13,0) -- ++(0,5) -- cycle;
\draw [double distance=2cm,thick]  (0,0) .. controls++(1,1) and (6,-3).. (7,0);
\end{scope}
\draw [thick]  (0,0) .. controls++(1,1) and (6,-3).. (7,0);
\draw [forcedist=1cm]  (0,0) .. controls++(1,1) and (6,-3).. (7,0);

\begin{scope}
\clip[overlay] (0,3) -- ++(8,0)  -- ++(3,0) -- ++(0,-5) -- ++(-13,0) -- ++(0,5) -- cycle;
\draw [double distance=2cm,thick]  (0,3) --++(8,0);
\end{scope}

\draw [thick]  (0,3) --++(8,0);
\draw [forcedist=1cm]  (0,3)--++(8,0);
\end{tikzpicture}
\end{document}

Result:

parallel lines with arrows

(That the initial arrow looks like that is because of the curvature of the line at that point.)

share|improve this answer
    
Congrats for your very smart and concise solution. I never used the pgfkey double and its "family" and my curiosity about creating new decoration/shapes led me to the solution I gave. However, at the following link img21.imagevenue.com/…, you can see the difference bewteen my(BLACK) and your(RED) solution. What I want is to apply a decoration to a path where its left side is "hitted" by the arrows. Your solution achieves it but it gives also a right "decoration" to the path and this is unwanted. Maybe it can be avoided. I don't know. –  Azoun Oct 16 '11 at 23:09
    
Thanks for the words. But I still don't get your exact problem. (not that smart here eh?). Do you mean the last arrow on the right side? If that is the case you can replace the 0.0999 with 0.1. Or you mean the the thickness of the curve? Let me edit the answer so we can communicate more clearly (i have the feeling that I get what you say except the left and right bit. –  percusse Oct 16 '11 at 23:19
    
@percusse: I had a hack for drawing one side of a line from another question and it fixed what I think is Azoun's issue with your solution. As it's really your solution, I edited it in to this answer. Hope that's okay. (Feel free to revert if not.) –  Loop Space Oct 17 '11 at 6:52
    
@AndrewStacey No problem at all. Thank you for the fix I am still a little bit puzzled about the double line tangent mismatch problem though. I will read on more hopefully before sleep :) –  percusse Oct 17 '11 at 9:34
    
I could need something like that, thank you. Is there a way to achieve the same result (double distance and decoration) with only one \draw command? @AndrewStacey –  Spike Oct 14 '12 at 6:48

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.