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 want to shift the lines specification through a polygon. My current code looks like this (not DRY at all):

\documentclass{article}
\usepackage{tikz}
\begin{document}

\usetikzlibrary{shapes,arrows}
\usetikzlibrary{calc}
\usetikzlibrary{shapes,arrows}

\newcommand{\door} {
\begin{scope}[yshift=-0.1cm,xshift=2cm]
\draw[red] (0,0) arc (180:270:1cm);
\draw[black] (1,-1) -- (1,-0) node[right,  near start]{};
\draw[black,dotted] (0,-0) -- (1,-0)node(doorstepcenter)[pos=0.5]{} ;
\end{scope}
}

 \newcommand{\room} {
 \coordinate (a) at  (0,0) ;
 \coordinate (b) at (5,0);
 \coordinate (c) at (5,5);
 \coordinate (d) at     (0,4);
 \coordinate (e) at     (1,3)   ;
}

\tikzstyle{seed}=[-latex,red];

\begin{tikzpicture}[node distance =4.5cm,thick]
 \tikzstyle{door} = [red,thick];

\room;
\draw (a) -- (b);
\draw[seed] (b)--(c);
\draw  (c)--(d);
\draw (d)--(e) node[draw,anchor=north west]{} ;
\draw (d) --(a);
\door;


\begin{scope}[xshift=6cm]
    \room;  
    \draw (a) -- (b);
    \draw[dashed] (b)--(c);
    \draw[seed]  (c)--(d);
    \draw (d)--(e) node[draw,anchor=north west]{} ;
    \draw (d) --(a);
    \door;
\end{scope}

\begin{scope}[xshift=12cm]
    \room;  
    \draw (a) -- (b);
    \draw[dashed] (b)--(c);
    \draw[dashed]  (c)--(d);
    \draw[seed] (d)--(e) node[draw=black,anchor=north west]{} ;
    \draw (d) --(a);
    \door;
\end{scope}
\end{tikzpicture}
\end{document}

There are more polygons to treat as well so this will get pretty ugly. How can I compact this example to something more neat ?

EDIT:

So after learning a lot tikz in the last days here the version I'm aiming at (thanks to many different answers here)

\begin{document}

\usetikzlibrary{shapes,arrows}
\usetikzlibrary{calc}

\newcommand{\door}[1] {
\begin{scope}[shift={#1}]
\draw[red] (-0.5,0) arc (180:270:1cm);
\draw[black] (0.5,-1) -- (0.5,-0) node[right,  near start]{};
\draw[black,dotted] (-0.5,0) -- (0.5,-0)node(doorstepcenter)[pos=0.5]{} ;
\end{scope}
};

\tikzstyle{seed}=[-latex,red, thick];

 \newcommand{\room} { %[2]
 \coordinate (a1) at  (4.5,0.5);
 \coordinate (a2) at  (4.5,4.5);
 \coordinate (a3) at  (0,4);
 \coordinate (a4) at  (1,3);
 \coordinate (a5) at  (1.4,3)  ;
 \coordinate (a6) at  (1.4,2.6)  ;
 \coordinate (a7) at  (1,2.6)  ;
 \coordinate (a8) at  (1,3);
 \coordinate (a9) at  (0,4);
 \coordinate (a10) at  (0,0.5) ;
 \coordinate (a11) at  (4.5,0.5); 
}

\newcommand{\makerow}[3]{
 \pgfmathsetmacro{\rows}{#1}
 \pgfmathsetmacro{\rowe}{#2}
 \pgfmathsetmacro{\ys}{#3}
 \pgfmathsetmacro{\n}{10}
\foreach \i in {\rows,...,\rowe}{
    \pgfmathsetmacro{\li}{\i+1}
    \pgfmathsetmacro{\si}{6*(\i-\rows)}
    \begin{scope}[xshift=\si cm, ,yshift=\ys cm]
        \room;      
        \door{ ($ (a10)!0.5! (a1) -(0,0.1)  $) };
        \foreach \k in {1,...,\n}{
            \pgfmathsetmacro{\hk}{\k+1}   
            \draw[solid] plot coordinates{(a\k) (a\hk)};
        }
        \foreach \k in {1,...,\i}{
            \pgfmathsetmacro{\hk}{\k+1}   
            \draw[dashed,white,thick] plot coordinates{(a\k) (a\hk)};
        }
        \draw[seed] plot coordinates{(a\i) (a\li)}; 
    \end{scope}
}
}


\begin{tikzpicture}%[node distance =4.5cm,thick]
\makerow{1}{5}{0};
\makerow{6}{10}{-6};
\end{tikzpicture}
\end{document}

enter image description here

While this is very close to the figure I wanted to achieve it has still some defects. I have to draw white over black to get the dashes since any approach I tried with a nested foreach having a variable start and end failed. I think I have to read some more about foreach, but at least this solution has far less spaghetti code than before. If you have further suggestions I would be glad to learn more.

share|improve this question

2 Answers 2

up vote 5 down vote accepted

One way is to use a \foreach loop, but not sure it offers you the complete flexibility you are looking for

\foreach \xShift/\BCStyle/\CDStyle/\DEStyle in {%
             0cm/seed/none/none,
             6cm/dashed/seed/none,
            12cm/dashed/dashed/seed}{%
    \begin{scope}[xshift=\xShift]
        \room;  
        \draw (a) -- (b);
        \draw [\BCStyle] (b)--(c);
        \draw [\CDStyle] (c)--(d);
        \draw [\DEStyle] (d)--(e) 
                node[draw=black,anchor=north west]{} ;
        \draw (d) --(a);
        \door;
    \end{scope}
}%
\end{scope}

As requested in the commented, I added another paramater to the \foreach loop to place text within each picture:

\foreach \xShift/\BCStyle/\CDStyle/\DEStyle/\Text in {%
             0cm/seed/none/none/{Part One},
             6cm/dashed/seed/none/{Part Two},
            12cm/dashed/dashed/seed/{Part Three}}{%

I wasn't sure exactly where you wanted the text to be placed, so I defined another coordinate and just placed it at this value:

\coordinate (TextLocation) at (2,2);
\node at (TextLocation) {\Text};

You could of course place this relative to an existing node.

The first 3 images below are the ones your code produces, and the second three are the ones produced by the foreach loop:

enter image description here

Notes:

Further Enhancements:

  • Given your updated version, I would recommend that you give each line a number in the order that the lines become red. Then loop through and increment a counter, iterationCount, and use an algorithm along the following lines to determine the style to apply to each line:

    if \lineNumber < iterationCount use a solid line

    else if \lineNumber = iterationCount use a red, solid line

    else use a dashed line

Code:

\documentclass{article}
\usepackage[paperwidth=10.0in]{geometry}
\usepackage{tikz}
\usetikzlibrary{calc}

\begin{document}

\newcommand{\door} {
    \begin{scope}[yshift=-0.1cm,xshift=2cm]
        \draw[red] (0,0) arc (180:270:1cm);
        \draw[black] (1,-1) -- (1,-0) node[right,  near start]{};
        \draw[black,dotted] (0,-0) -- (1,-0)node(doorstepcenter)[pos=0.5]{} ;
    \end{scope}
}

\newcommand{\room} {
 \coordinate (a) at (0,0);
 \coordinate (b) at (5,0);
 \coordinate (c) at (5,5);
 \coordinate (d) at (0,4);
 \coordinate (e) at (1,3);
 \coordinate (TextLocation) at (2,2);
}

\tikzset{seed/.style={-latex,red}}
\tikzset{none/.style={}}

\noindent
\begin{tikzpicture}[node distance =4.5cm,thick]
 \tikzstyle{door} = [red,thick];

\begin{scope}[xshift=0cm]
    \room;
    \draw (a) -- (b);
    \draw[seed] (b)--(c);
    \draw (c)--(d);
    \draw (d)--(e) node[draw,anchor=north west]{} ;
    \draw (d) --(a);
    \door;
\end{scope}


\begin{scope}[xshift=6cm]
    \room;  
    \draw (a) -- (b);
    \draw[dashed] (b)--(c);
    \draw[seed]  (c)--(d);
    \draw (d)--(e) node[draw,anchor=north west]{} ;
    \draw (d) --(a);
    \door;
\end{scope}

\begin{scope}[xshift=12cm]
    \room;  
    \draw (a) -- (b);
    \draw[dashed] (b)--(c);
    \draw[dashed]  (c)--(d);
    \draw[seed] (d)--(e) node[draw=black,anchor=north west]{} ;
    \draw (d) --(a);
    \door;
\end{scope}

% --------------------------------------------------
% Draws all three of the above shifted below by 6cm:
%
\begin{scope}[yshift=-6cm]
\foreach \xShift/\BCStyle/\CDStyle/\DEStyle/\Text in {%
             0cm/seed/none/none/{Part One},
             6cm/dashed/seed/none/{Part Two},
            12cm/dashed/dashed/seed/{Part Three}}{%
    \begin{scope}[xshift=\xShift]
        \room;  
        \draw (a) -- (b);
        \draw [\BCStyle] (b)--(c);
        \draw [\CDStyle] (c)--(d);
        \draw [\DEStyle] (d)--(e) 
                node[draw=black,,anchor=north west]{} ;
        \node at (TextLocation) {\Text};
        \draw (d) --(a);
        \door;
    \end{scope}
}%
\end{scope}
\end{tikzpicture}
\end{document}
share|improve this answer
    
Little problem with the little square red and not black in the third picture –  Alain Matthes May 4 '12 at 16:21
    
@Altermundus: Thanks. Have corrected that. –  Peter Grill May 4 '12 at 16:32
    
Wow!!! Thanks for the amazing answer.This solves already a lot of the problems I have and teaches me even more about tikz. Have you got any idea how I could place custom Text inside each figure ? –  Martin May 4 '12 at 16:36
    
To place text in each figure just add another parameter to the \foreach loop -- you might need to enclose the text within a {}. –  Peter Grill May 4 '12 at 17:00
    
I have updated the solution to show how to place text in each picture. –  Peter Grill May 4 '12 at 17:09

I think more flexible but longer is to use styles. It's more flexible because you can add others styles easily

\documentclass[landscape]{article}
\usepackage{tikz}
\begin{document}

\usetikzlibrary{shapes,arrows}
\usetikzlibrary{calc}
\usetikzlibrary{shapes,arrows}

\newcommand{\door} {
\begin{scope}[yshift=-0.1cm,xshift=2cm]
\draw[red] (0,0) arc (180:270:1cm);
\draw[black] (1,-1) -- (1,-0) node[right,  near start]{};
\draw[black,dotted] (0,-0) -- (1,-0)node(doorstepcenter)[pos=0.5]{} ;
\end{scope}
}

 \newcommand{\room} {
 \coordinate (a) at (0,0) ;
 \coordinate (b) at (5,0);
 \coordinate (c) at (5,5);
 \coordinate (d) at (0,4);
 \coordinate (e) at (1,3)   ;
}

\newcommand\myfig{
\room;
\draw       (a) -- (b);
\draw[st1]  (b)--(c);
\draw[st2]  (c)--(d);
\draw[st3]  (d)--(e) node[st4]{} ;
\draw (d) --(a);
\door;  
} 

\tikzset{seed/.style={-latex,red}}      
\tikzset{door/.style={red,thick}}
\tikzset{st1/.style={seed}}
\tikzset{st2/.style={}} 
\tikzset{st3/.style={}}
\tikzset{st4/.style={draw,anchor=north west}}    

\begin{tikzpicture}[node distance =4.5cm,thick]

\myfig

\begin{scope}[xshift=6cm,st1/.style ={dashed},
                         st2/.style={seed}] 
\myfig
\end{scope}

\begin{scope}[xshift=12cm,st1/.style ={dashed}, 
                          st2/.style ={dashed},
                          st3/.style ={seed},
                          st4/.append style ={draw=black}]
\myfig   
\end{scope}
\end{tikzpicture}
\end{document} 

enter image description here

share|improve this answer
    
Far neater than my solution but Peters just beats it. By the way I have 10 Figures to draw so foreach seems easier. A question on your experience: Does foreach pay most of the times or is your approach your favoured one for a modest number of repetitions ? –  Martin May 5 '12 at 12:27
    
It depends on the circumstances. The number of arguments, the number of iterations etc. The method that I proposed is only another approach but this is not necessarily the best. It's interesting to know what method is the more easy to adapt if you have to add some arguments. –  Alain Matthes May 5 '12 at 12:54
    
Im just warming to tikz but I already see that there is no free lunch in it as well ;-) Actually it turns out that the foreach version proposed by peter is not easily adaptable to my entire problem... –  Martin May 5 '12 at 13:00

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.