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 have the following tikz code

% compilation command: pdflatex --jobname=Diag-f1 Diag.tex
\documentclass{book}
\usepackage{tikz}
\pgfrealjobname{Diag}
\begin{document}
\beginpgfgraphicnamed{Diag-f1}
\begin{tikzpicture}[node distance=3em]
\node(G)[rectangle,fill=red!5,draw=red,text width=5cm]{};
\node(H)[below of=G]{H};
\node(H1)[left of=H]{H1};
\node(H2)[right of=H]{H2};
\draw[->](G.south)-|(H1.north);
\draw[->](G.south)--(H.north);
\draw[->](G.south)-|(H2.north);
\end{tikzpicture}
\endpgfgraphicnamed
\end{document}

enter image description here

but I am not happy with the two arrows going from G.south to H1.north and H2.north. Because of the -| command, there is a spurious horizontal line. How can I achieve the same result without this annoying horizontal line? \draw[->](G.south)--(H1.north); is not a solution. There are available tricks but I may have missed an obvious solution here.

share|improve this question

2 Answers 2

up vote 23 down vote accepted

The line is normal: -| means: draw an horizontal line, then a vertical.

You could use this:

\draw[->] (G.south -| H1.north) -- (H1.north)

That will compute the intersection between a vertical line through H1.north and a horizontal one through G.south, and then draw a line from it to H1.north

share|improve this answer

I like the use of to paths.

Advantage: The target coordinate/node has only to be given once.

Code

\documentclass[tikz]{standalone}
\tikzset{
    *|/.style={
        to path={
            (perpendicular cs: horizontal line through={(\tikztostart)},
                                 vertical line through={(\tikztotarget)})
            % is the same as (\tikztostart -| \tikztotarget)
            % but just to be safe: http://tex.stackexchange.com/a/29781/16595
            -- (\tikztotarget) \tikztonodes
        }
    }
}
\begin{document}
\begin{tikzpicture}[node distance=3em]
\node(G)  [rectangle,fill=red!5,draw=red,text width=5cm] {};
\node(H)  [below of=G] {H};
\node(H1) [left of=H]  {H1};
\node(H2) [right of=H] {H2};
\draw[->,*|] (G.south) to     (H1.north);
\draw[->]    (G.south) --     (H.north);
\draw[->]    (G.south) to[*|] (H2.north);
\end{tikzpicture}
\end{document}

Output

enter image description here


For various different possibilities of this (and without the need to declare the anchors), you can define more styles like this. This is also part of my paths.ortho library (see my user info).

Note that this (as well as the original answer, see above) does currently not take the current transformation in account and just uses the anchors .north, .south, .east and .west.

Code

\documentclass[tikz]{standalone}
\makeatletter
\newif\iftikz@ortho@preflush
\tikz@ortho@preflushtrue
\let\tikz@origtotarget\pgfutil@empty
\tikzset{
  |-/.style={to path={|- (\tikztotarget) \tikztonodes}},
  -|/.style={to path={-| (\tikztotarget) \tikztonodes}},
  *|/.style={to path={%
    \pgfextra
      \iftikz@shapeborder
        \tikz@scan@one@point\pgfutil@firstofone(\tikztotarget)\relax
        \ifdim\pgf@y>\tikz@lasty\relax
          \edef\tikztostart{\tikztostart.north}%
        \else
          \edef\tikztostart{\tikztostart.south}%
        \fi
      \fi
    \endpgfextra
    (perpendicular cs: horizontal line through={(\tikztostart)},
                 vertical line through={(\tikztotarget)}) -- (\tikztotarget) \tikztonodes
  }},
  *-/.style={to path={%
    \pgfextra
      \iftikz@shapeborder
        \tikz@scan@one@point\pgfutil@firstofone(\tikztotarget)\relax
        \ifdim\pgf@x>\tikz@lastx\relax
          \edef\tikztostart{\tikztostart.east}%
        \else
          \edef\tikztostart{\tikztostart.west}%
        \fi
      \fi
    \endpgfextra
    (perpendicular cs: vertical line through={(\tikztostart)},
                     horizontal line through={(\tikztotarget)}) -- (\tikztotarget) \tikztonodes
  }},
  |*/.style={to path={%
    \pgfextra
      \tikz@scan@one@point\pgfutil@firstofone(\tikztotarget)\relax
      \iftikz@shapeborder
        \let\tikz@origtotarget\tikztotarget
        \ifdim\pgf@y>\tikz@lasty\relax
          \edef\tikztotarget{\tikztotarget.south}%
        \else
          \edef\tikztotarget{\tikztotarget.north}%
        \fi
      \fi
    \endpgfextra
    (\tikztostart) -- (perpendicular cs: vertical line through={(\tikztostart)},
                                         horizontal line through={(\tikztotarget)})
    \tikztonodes \ifx\tikz@origtotarget\pgfutil@empty\else\iftikz@ortho@preflush(\tikz@origtotarget)\fi\fi
  }},
  -*/.style={to path={%
    \pgfextra
      \tikz@scan@one@point\pgfutil@firstofone(\tikztotarget)\relax
      \iftikz@shapeborder
        \let\tikz@origtotarget\tikztotarget
        \ifdim\pgf@x>\tikz@lastx\relax
          \edef\tikztotarget{\tikztotarget.west}%
        \else
          \edef\tikztotarget{\tikztotarget.east}%
        \fi
      \fi
    \endpgfextra
    (\tikztostart) -- (perpendicular cs: horizontal line through={(\tikztostart)},
                                         vertical line through={(\tikztotarget)})
    \tikztonodes \ifx\tikz@origtotarget\pgfutil@empty\else\iftikz@ortho@preflush(\tikz@origtotarget)\fi\fi
  }},
  node as new start/.is if=tikz@ortho@preflush
}
\makeatother
\begin{document}
\begin{tikzpicture}
\begin{scope}[nodes={shape=rectangle, draw, minimum width=+1.5cm, minimum height=+1cm}]
  \node (a)                {A};
  \node (b) at (  .5, 2  ) {B};
  \node (c) at ( 2.5,- .2) {C};
  \node (d) at (- .5,-2  ) {D};
  \node (e) at (-2.5,  .2) {E};
\end{scope}
\tikzset{nodes={auto,font=\small\ttfamily}}
\path[->] (a) edge[*|]                 (b)
          (b) edge[*|] node {*|}       (a)
          (a) edge[*-]                 (c)
          (c) edge[*-] node[swap] {*-} (a)
          (a) edge[|*]                 (d)
          (d) edge[|*] node[swap] {|*} (a)
          (a) edge[-*]                 (e)
          (e) edge[-*] node       {-*} (a)
          %
          {[every edge/.append style=blue]
            {[|-]
              (e) edge (b)
                  edge (d)}
            {[-|]
              (b) edge (c)
              (d) edge (c)}}
;
\end{tikzpicture}
\begin{tikzpicture}[nodes={shape=rectangle, draw, minimum width=+1cm, minimum height=+1cm}]
  \node (a)              {A};
  \node (b) at ( .25, 2) {B};
  \node (c) at (1.25,-0) {C};
  \draw (a) to [|*] (b) to (c);

  \begin{scope}[xshift=3cm, node as new start=false]
    \node (a)              {A};
    \node (b) at ( .25, 2) {B};
    \node (c) at (1.25,-0) {C};
    \draw (a) to [|*] (b) to (c);
  \end{scope}
\end{tikzpicture}
\begin{tikzpicture}[nodes={rectangle,draw,anchor=west,minimum height=+1cm}]
\node (rechteck1)[minimum width=+3cm] at (1,5){};
\node (rechteck2)[minimum width=+2cm] at (1,3){};

\draw [->] (rechteck1) to[*|] (rechteck2);
\end{tikzpicture}
\end{document}

Output

enter image description here enter image description here enter image description here

share|improve this answer
    
very nice solution as well. Thanks –  pluton Dec 18 '12 at 15:38
    
thanks! This is a lifesaver, much easier. –  Jason S Apr 10 at 20:30
    
How do you make it work the other way? (drawing H to G), using the x-coordinate of H but the y-coordinate of G? –  Jason S Apr 10 at 20:32
    
@JasonS Are you interested in something like what my German answer on TeXwelt.de shows? The same code is used in my paths.ortho library (using files 1 and 2). –  Qrrbrbirlbel Apr 10 at 21:27
    
Hmm... not sure, still trying to understand what this code is doing + what I need. I essentially want a vertical (or horizontal) line between the given edges of shapes A and B, through a point C between them. (sometimes point C is an edge on shape A or B.) –  Jason S Apr 10 at 22:58

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.