13

I'd like to draw a rectilinear path by starting at a particular location, and then prescribing increments in the horizontal and vertical directions.

I am currently doing something like this

\documentclass{standalone}
\usepackage{tikz}

\begin{document}
\begin{tikzpicture}
    \draw [ultra thick] (20,12) -- (18,12);
    \draw [ultra thick] (18,12) -- (18,10);
    \draw [ultra thick] (18,10) -- (16,10);
    \draw [ultra thick] (16,10) -- (16,8);
    \draw [ultra thick] (16,8) -- (12,8);
    \draw [ultra thick] (12,8) -- (12,10);
    \draw [ultra thick] (12,10) -- (8,10);
    \draw [ultra thick] (8,10) -- (8,12);
    \draw [ultra thick] (8,12) -- (6,12);
    \draw [ultra thick] (6,12) -- (6,14);
    \draw [ultra thick] (6,14) -- (4,14);
    % etc ...

\end{tikzpicture}
\end{document}

enter image description here

But this requires that I locate each point, when what is much easier (for my particular case) is to just indicate the horizontal or vertical distance from one point to the next.

I have tried something like this

\documentclass{standalone}
\usepackage{tikz}

\begin{document}

\begin{tikzpicture}
   \node (A) at (20,12) {};
   \node (B) at (18,12) {};
   \node (C) at (18,10) {};
   \node (D) at (16,10) {};

   \draw (A) |- ++ (-2,0)  -| (B);
   \draw (B) |- ++ (0, -2) -| (C);
   \draw (C) |- ++ (-2, 0) -| (D);
   % etc
\end{tikzpicture}
\end{document}

It looks like the ++ (-2,0) bit seems to be on the right track, but naming the nodes is tedious, and this doesn't produce what I have in mind.

Is there some way to do what I have in mind with simple notation? Something like

Start at (20,12)
Go left 2 units
Go down 2 units
Go left 2 units
% etc

Aka, Etch-a-Sketch style?

3 Answers 3

18

\draw (20,12) -- ++(2,0) -- ++(0,2) -- ++(-3,0) -- ++(45:3);

Use ++ before each new incremental coordinate to make it relative to the last one and put the pencil there.

Here's a complete example:

\documentclass{article}
\usepackage{tikz}
\begin{document}
\tikz\draw (20,12) -- ++(2,0) -- ++(0,2) -- ++(-3,0) -- ++(30:3) {[rounded corners=10pt]-- ++(5,0) -- ++(0,-6)} -- ++(-7,0) -- cycle;
\end{document}

enter image description here

Of course, combining this with the -| or |- path operators can simplify the code even further; the following two pieces of code produce the same result:

\tikz\draw (20,12) -- ++(2,0) -- ++(0,2) -- ++(3,0) -- ++(0,1) -- ++(1,0) -- ++(0,-3) -- ++(2,0);\par\bigskip

and

\tikz\draw (20,12) -| ++(2,2) -| ++(3,1) -- ++(1,0) |- ++(2,-3);

I don't think that defining commands in this case adds anything; in fact, I think it reduces the functionality of the existing syntax (which is already simple). The example demonstrates that you can use, for example, polar coordinates and modify (up to TikZ limitations) the path attributes midways; even if the current question doesn't require this, it's a good thing to have the possibility to do those kind of modification if they are required.

5
  • Thanks - this is in fact exactly what I wanted. And it doesn't have the problem that segments aren't meeting up exactly at the corners. Perfect!
    – Donna
    Commented Sep 26, 2015 at 21:57
  • 1
    @Donna You're welcome. Please see my updated answer. Commented Sep 26, 2015 at 23:25
  • Thanks! So it looks like there are a couple of new features here, at least one of which I was wondering about. It looks like you can change the line style midstream, which is very handy, and exactly something I wanted to do. I want to fill the resulting rectilinear polygons, so always need closed polygons, but only want portions of the border to be, say, ultra thick. So I'll try your trick above for getting rounded corners midway. But what does the (30:3) notation do? And cycle?
    – Donna
    Commented Sep 27, 2015 at 11:14
  • Trying this out, I see that the (30:3) indicates an angle (30 degrees), and cycle means "return to the beginning" (or so it seems). Turns out, though, it is not possible to change the line style midway. Oh well.
    – Donna
    Commented Sep 27, 2015 at 11:50
  • @Donna Yes, (<angle>:<distance>) has the meaning you guesses, and yes, line width (as well as color and other attributes) cannot be changed midway for a single path due to TikZ limitations. Commented Sep 27, 2015 at 14:56
19

Not sure it is what is required, but here is a rectilinear decoration which sort of achieves the required effect:

\documentclass[tikz,border=5]{standalone}
\usetikzlibrary{decorations}
\pgfdeclaredecoration{rectilinear}{start}{%
\state{start}[width=\pgfdecorationsegmentlength/2,
  next state=draw above]{%
  \pgfpathmoveto{\pgfpointorigin}%
  \pgfcoordinate{@1}{\pgfpointorigin}%
}
\state{draw above}[width=\pgfdecorationsegmentlength/2, 
  next state=draw below]{%
  \pgfcoordinate{@2}{\pgfpointorigin}%
  \pgftransformreset%
  \pgfpointanchor{@1}{center}\pgfgetlastxy\a\b%
  \pgfpointanchor{@2}{center}\pgfgetlastxy\c\d%
  \pgfpathlineto{\pgfqpoint{\a}{\d}}%
  \pgfpathlineto{\pgfqpoint{\c}{\d}}%
  \pgfnodealias{@1}{@2}%
}
\state{draw below}[width=\pgfdecorationsegmentlength/2, 
  next state=draw above]{%
  \pgfcoordinate{@2}{\pgfpointorigin}%
  \pgftransformreset%
  \pgfpointanchor{@1}{center}\pgfgetlastxy\a\b%
  \pgfpointanchor{@2}{center}\pgfgetlastxy\c\d%
  \pgfpathlineto{\pgfqpoint{\c}{\b}}%
  \pgfpathlineto{\pgfqpoint{\c}{\d}}%
  \pgfnodealias{@1}{@2}%
}
\state{final}{%
  \pgftransformreset%
  \pgfpointanchor{@1}{center}\pgfgetlastxy\a\b%
  \pgfpointdecoratedpathlast\pgfgetlastxy\c\d%
  \pgfpathlineto{\pgfqpoint{\a}{\d}}%
  \pgfpathlineto{\pgfqpoint{\c}{\d}}%
}
}
\tikzset{rectilinear/.style={
  decoration={rectilinear, #1}, decorate
}}
\begin{document}
\begin{tikzpicture}[very thick, line join=round, line cap=round]
\draw [gray, postaction={rectilinear, draw=red}]
  (0,4) -- ++(30:2) -- ++(300:3);
\draw [gray, postaction={rectilinear, draw=green!50!black}]
  (0,2) circle [radius=1];
\draw  [gray, postaction={rectilinear={segment length=0.25cm}, draw=blue}]
  (0,0) -- (3,1) arc (90:-90:1) .. controls ++(180:1) and ++(225:1) .. cycle;
\end{tikzpicture}
\end{document}

enter image description here

5

Here four macro \Start, \Goleft, \Godown and \Goup to creat the desired path.

Code

\documentclass[border=5mm]{standalone}
\usepackage{tikz}
\usetikzlibrary{calc}

\tikzset{every node/.style={inner sep=0pt,minimum size=0pt}}

\newcommand{\Start}[1]{\node (A) at #1 {};}
\newcommand{\Goleft}[1]{\draw($(A)+( -0.5\pgflinewidth ,0.5\pgflinewidth)$)--+(#1,0)node(A){};}
\newcommand{\Godown}[1]{\draw($(A)+(-0.5\pgflinewidth,0)$)--+(0,-#1)node(A){};}
\newcommand{\Goup}[1]{\draw($(A)+(-0.5\pgflinewidth,0)$)--+(0,#1)node(A){};}

\begin{document}

\begin{tikzpicture}
   \Start{(20,12)}
   \Goleft{2}
   \Godown{2}
   \Goleft{3}
   \Godown{1}
   \Goleft{4}
   \Goup{3}
\end{tikzpicture}

\end{document}

Output

enter image description here

5
  • Thanks - that helps alot. i'd like to also adjust the line width, which did by adding `[line width=8pt] for example. The problem, though is that the lines don't match up, and so the line edges are visible at the corners. it seems like I need to add something like a small filled square at each corner.
    – Donna
    Commented Sep 26, 2015 at 21:10
  • Just add line width=1pt (or what satisfy you) in the front of tikzpicture environment like this \begin{tikzpikture}[line width=1pt]
    – Salim Bou
    Commented Sep 26, 2015 at 21:11
  • Yes, I did that. But it still seemed to suffer from this problem that the corner segments don't match up. The solution from @GonzaloMedina doesn't have this problem.
    – Donna
    Commented Sep 26, 2015 at 22:02
  • My bad. I fixed a bug, and this solution works just as the one below. Thanks!
    – Donna
    Commented Sep 26, 2015 at 22:12
  • Nice implementation. Funny that you chose to call Goleft the macro which actually go... right! ^^
    – SebGlav
    Commented Jan 12, 2021 at 21:39

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .