[Tex/LaTex] Discretize line directions in Tikz

fittikz-pgf

In a printed circuit board (pcb) layout, the lines can only direct horizontally, vertically and diagonally. Such that every line is a combination of a horizontal/vertical part combined with a diagonal part.

I am looking for a way to implement this knowledge in Tikz.
This means that when one for instance draws a line:

\draw (0,0) -- ++(5,2);

This should be drawn as:

\draw (0,0) -- ++(3,0) -- ++(2,2);

Where the horizontal and vertical direction always get priority over the diagonal one. Of course this can easily be implemented when the coordinates are given explicitly. But when for instance the coordinates have names, I don't see a way to do this.

Algorithmically the following should be done: say the two points are (x1,y1) and (x2,y2)

  1. calculate the difference (dx,dy)
  2. if abs(dx) >= abs(dy) do the following
  3. move (x1,y1) line (x1+sgn(dx)*(abs(dx)-abs(dy)),y1) and line (x2,y2).

if abs(dx) < abs(dy) simply swap the x-axis with the y-axis.

If the original line is a perfect diagonal, the result is a diagonal as well (since the horizontal part has a length of zero). In case the line is perfectly horizontal/vertical, the resulting line is horizontal/vertical as well (since the diagonal part has a length equal to zero).

Best Answer

The following example defines the macro \drawcircuitline that takes one optional argument for options of draw and two mandatory arguments, the coordinates, either explicit or as node name, in both cases without parentheses. The calculations need the function sign that seems to be missing. Therefore it is defined via \pgfmathdeclarefunction:

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{calc}

\makeatletter
\pgfmathdeclarefunction{sign}{1}{%
  \begingroup
    \ifdim#1pt>\z@
      \def\pgfmathresult{1}%
    \else
      \ifdim#1pt=\z@
        \def\pgfmathresult{0}%
      \else
        \def\pgfmathresult{-1}%
      \fi
    \fi
    \pgfmath@smuggleone\pgfmathresult
  \endgroup
}
\makeatother

\newcommand*{\drawcircuitline}[3][]{%
  \draw[{#1}]
    let \p1=($(#3)-(#2)$),
        \n2={abs(\x1) - abs(\y1)},
        \n3={(\n2 > 0) * sign(\x1) * \n2},
        \n4={(\n2 < 0) * sign(\y1) * (-\n2)},
        \p{m}=(\n{3}, \n{4})
    in
    (#2) -- ++(\p{m}) -- (#3);
}

\begin{document}
  \begin{tikzpicture}[thick]
    \draw[help lines] (-6,-6) grid (6,6);
    \foreach \x/\y in { 4/0, -4/0, 0/4, 0/-4,
         1/1, -1/1, -1/-1, 1/-1, 5/5, -5/5, -5/-5, 5/-5,
         6/3, 3/6, -3/6, -6/3, -6/-3, -3/-6, 3/-6, 6/-3}
      \fill (\x,\y) circle[radius=3pt];
    \coordinate (a) at (1,1);
    \coordinate (b) at (6,3);
    \drawcircuitline{a}{b}
    \drawcircuitline{a}{5,5}
    \drawcircuitline{a}{3,6}
    \drawcircuitline{-1,1}{-3,6}
    \drawcircuitline{-1,1}{-5,5}
    \drawcircuitline{-1,1}{-6,3}
    \drawcircuitline{-1,-1}{-6,-3}
    \drawcircuitline{-1,-1}{-5,-5}
    \drawcircuitline{-1,-1}{-3,-6}
    \drawcircuitline{1,-1}{3,-6}
    \drawcircuitline{1,-1}{5,-5}
    \drawcircuitline{1,-1}{6,-3}
    \drawcircuitline{-4,0}{4,0}
    \drawcircuitline{0,4}{0,-4}
  \end{tikzpicture}
\end{document}  

Result