31

Although I now use TikZ, every so often I find myself looking for very useful PSTricks commands which don't seem to exist in TikZ. The pst-node package has an \ncbar command which allows one to connect two nodes with arms dropping down, typically at a 90 degree angle. Here's an example:

\documentclass{article}
\usepackage{pst-node}
\begin{document}
\rput(0,0){\rnode{A}{\psframebox{A}}}
\rput(2,0){\rnode{B}{\psframebox{B}}}
\ncbar[angle=90]{A}{B}
\end{document}

output of code

Is there a TikZ equivalent to this useful command? If not, how easy would it be to create one?

3 Answers 3

29

There's no direct equivalent, but you can use the to path mechanism together with the calc library to do something similar. If you set:

\tikzset{
    ncbar angle/.initial=90,
    ncbar/.style={
        to path=(\tikztostart)
        -- ($(\tikztostart)!#1!\pgfkeysvalueof{/tikz/ncbar angle}:(\tikztotarget)$)
        -- ($(\tikztotarget)!($(\tikztostart)!#1!\pgfkeysvalueof{/tikz/ncbar angle}:(\tikztotarget)$)!\pgfkeysvalueof{/tikz/ncbar angle}:(\tikztostart)$)
        -- (\tikztotarget)
    },
    ncbar/.default=0.5cm,
}

you can draw a rectangular connection between two coordinates using \draw (a) to [ncbar] (b);. The offset of the line can be controlled using the optional parameter: \draw (a) to [ncbar=1cm] (b);. To change the angle of the connecting line, you can use the key ncbar angle: \draw [blue] (a) to [ncbar=1.5cm, ncbar angle=70] (b);

\documentclass[landscape]{article}
\usepackage{tikz}
\usetikzlibrary{calc}

\tikzset{
    ncbar angle/.initial=90,
    ncbar/.style={
        to path=(\tikztostart)
        -- ($(\tikztostart)!#1!\pgfkeysvalueof{/tikz/ncbar angle}:(\tikztotarget)$)
        -- ($(\tikztotarget)!($(\tikztostart)!#1!\pgfkeysvalueof{/tikz/ncbar angle}:(\tikztotarget)$)!\pgfkeysvalueof{/tikz/ncbar angle}:(\tikztostart)$)
        -- (\tikztotarget)
    },
    ncbar/.default=0.5cm,
}

\begin{document}
\begin{tikzpicture}
\node [draw] (a) {A};
\node at (2,-1) [draw] (b) {B};

\draw  (a) to [ncbar] (b);
\draw [red] (a) to [ncbar=-1cm] (b);
\draw [blue] (a) to [ncbar=1.5cm, ncbar angle=70] (b);
\end{tikzpicture}
\end{document}
7
  • With some fancy code, you could make it ncbar=1cm at 90 to be able to specify the angle as well (for extra points, ncbar=1cm and ncbar should also work). May 9, 2012 at 13:16
  • I think @AndrewStacey is referring to a ncbar/.style args={#1 at #2}{....} type of input parsing. Nevertheless, great stuff.
    – percusse
    May 9, 2012 at 13:26
  • 1
    @percusse Almost. You'd have to be a bit more sneaky to be able to handle ncbar=1cm and ncbar=1cm at 90. May 9, 2012 at 13:28
  • @AndrewStacey: I'm not sure that that syntax would be preferable, though (not just because it's much more work to implement): If you have a separate angle key, you can set it for all ncbars without specifying it explicitly.
    – Jake
    May 9, 2012 at 13:34
  • 1
    Would it be possible to add a node for a label in the middle of the bar?
    – Ash
    Nov 9, 2015 at 15:51
14

Reference

Code

\documentclass{article}
\usepackage{pst-node,tikz}
\usetikzlibrary{paths.ortho}
\begin{document}
\hspace{.125cm}
\rput(0,0){\rnode{A}{\psframebox{A}}}
\rput(2,1){\rnode{B}{\psframebox{B}}}
\ncbar[angle=90]{A}{B}
\ncbar[angle=45]{A}{B}

\par
\begin{tikzpicture}[thick,nodes=draw]
\node (A)          {A};
\node (B) at (2,1) {B};

\draw (A) ud (B);
\draw[rotate=45] (A) rl (B);
\end{tikzpicture}
\end{document}

Output

enter image description here

1
  • You can mention your tikz-ext package ! :-) May 26, 2023 at 13:04
2

An another answer that gives a command equivalent to the PSTricks \ncbar command :

enter image description here

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

\begin{document}


\tikzset{% TikZ equivalent to the PSTricks \ncbar command
  label anchor/.initial={west},%
  label rotate/.initial={0},%
  arm angleA/.initial={0},%
  arm lengthA/.initial={1em},%
}
\newcommand{\anchorL}{\pgfkeysvalueof{/tikz/label anchor}}%
\newcommand{\rotateL}{\pgfkeysvalueof{/tikz/label rotate}}%
\newcommand{\angleA}{\pgfkeysvalueof{/tikz/arm angleA}}%
\newcommand{\lengthA}{\pgfkeysvalueof{/tikz/arm lengthA}}%

 \tikzstyle{arrow}=[->, >=stealth, thick, shorten <= 3pt, shorten >= 3pt]%

\newcommand{\nbar}[4][]{% \nbar[options]{node A}{node B}{label}
  \begin{tikzpicture}[remember picture,overlay,#1]
    \coordinate (p1) at ($(#2)+(\angleA:\lengthA)$) ;
    \coordinate (p2) at ($(#3)+(\angleA:\lengthA)$) ;
    \pgfmathanglebetweenpoints{\pgfpointanchor{p1}{center}}
    {\pgfpointanchor{p2}{center}}
    \pgfmathnotless{cos(\pgfmathresult-\angleA)}{0}
    \ifnum\number\pgfmathresult=1
    % Find the projection of the p2 point on the line from #2 to p1
    \coordinate (inter) at ($(#2)!(p2)!(p1)$) ;
    \draw[arrow] (#2) -- (inter) -- (p2) -- (#3) ;
    \path (inter) -- (p2) node[rotate=\rotateL,anchor=\anchorL,midway]{#4} ;
    \else
    % Find the projection of the p1 point on the line from #3 to p2
    \coordinate (inter) at ($(#3)!(p1)!(p2)$) ;
    \draw[arrow] (#2) -- (p1) -- (inter) -- (#3) ;
    \path (p1) -- (inter) node[sloped,rotate=\rotateL,anchor=\anchorL,midway]{#4} ;
    \fi
  \end{tikzpicture}}

\newcommand{\node}[3][]{% \node[options]{node's name}{my node}
  \tikz[remember picture,baseline = (#2.base)] \node[#1] (#2) {$#3$};}

\renewcommand{\node}[3][]{% \node[options]{node's name}{my node}
  \tikz[remember picture,baseline = (#2.base)] \node[#1] (#2) {#3};}

\begin{minipage}{10cm}
  \begin{center}
  \node[circle,dashed,draw]{A}{Node A}
  \hspace*{3cm}
  \raisebox{-10mm}{\node[draw]{B}{Node B}}
\end{center}
\end{minipage}


\nbar[red, arm angleA=70, arm lengthA=5mm,
label anchor=south,label rotate=\angleA-90]{A.\angleA}{B.\angleA}{label}
\nbar[green, arm angleA=150, arm lengthA=5mm,
label anchor=0,label rotate=-90]{A.\angleA}{B.\angleA}{label}
\nbar[blue, arm angleA=-90, arm lengthA=5mm,
label anchor=north,label rotate=0]{A.\angleA}{B.\angleA}{label}
 
\end{document}

You must log in to answer this question.

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