19

I have two nodes (A) and (B), and I want to only draw a central segment of the straight line between them, of a certain given length (say 2cm, but will vary). Is there some way I can do this? I am guaranteed that (A) and (B) are at least 2cm apart.

I know about shorten < and shorten >, but the problem is that I don't know the exact amount to shorten by, and I don't want to have to do the calculation myself each time.

4 Answers 4

16

I didn't read the question very carefully and thought you want to draw the middle part of of any kind of path. So I created a (meta-)decoration to do just that. For straight lines the other solutions given here are of course a lot simpler.

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

% A simple empty decoration, that is used to ignore the last bit of the path
\pgfdeclaredecoration{ignore}{final}
{
\state{final}{}
}

% Declare the actual decoration.
\pgfdeclaremetadecoration{middle}{initial}{
    \state{initial}[
        width={(\pgfmetadecoratedpathlength - \the\pgfdecorationsegmentlength)/2},
        next state=middle
    ]
    {\decoration{moveto}}

    \state{middle}[
        width={\the\pgfdecorationsegmentlength},
        next state=final
    ]
    {\decoration{curveto}}

    \state{final}
    {\decoration{ignore}}
}

% Create a key for easy access to the decoration (as suggested by Jake).
\tikzset{middle segment/.style={decoration={middle},decorate, segment length=#1}}

\begin{document}
\begin{tikzpicture}[radius=2pt]   
    \fill (0,0) circle;
    \fill (4,0) circle;
    \draw[middle segment=2cm,double,red,->] (0,0) to[out=30,in=150] (4,0);
\end{tikzpicture}
\end{document}

example

10
  • 3
    Excellent! Adding to that: If you define a style \tikzset{middle segment/.style={decoration={middle},decorate, segment length=#1}}, you can easily draw line segments with different lengths using \draw [middle segment=<length>] (a) -- (b);
    – Jake
    May 19, 2011 at 18:04
  • @Jake: Good idea!
    – Caramdir
    May 19, 2011 at 18:22
  • Hi Caramdir. I like your solution, it seems really flexible! I tried modify it so that the line segment would have an arrow at the end, but without any luck. Can someone give me a hand? May 19, 2011 at 19:20
  • @Jamie: Add \afterdecoration { \pgfsetarrowsend{to} \pgfusepath{stroke} } to the middle state (right after ...curveto}, before the second }). You can replace to by the arrow type you want. See also the example on page 601 of the (v2.10) manual.
    – Caramdir
    May 19, 2011 at 19:30
  • That's great! I actually just found that myself. But now I've also noticed that my [double] option is getting ignored, if I want make the line into two parallel lines ... how can I add that in? May 19, 2011 at 19:32
15

The calc library eats this sort of thing for breakfast.

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

\begin{document}
\begin{tikzpicture}
\node (a) at (0,0) {A};
\node (b) at (3,3) {B};
\draw ($($(a)!.5!(b)$)!1cm!(a)$) --  ($($(a)!.5!(b)$)!1cm!(b)$);
\end{tikzpicture}
\end{document}

The syntax works as follows: $...$ is interpreted as a "coordinate calculation" and it returns a coordinate. We start with $(a)!.5!(b)$ which is halfway between (a) and (b). Then we move 1cm from this point towards (a). That's our starting point. We draw a line from that to the same but with (b) in place of (a).

Result:

centre path

1
  • 2
    Thanks Andrew, I don't really know much about the calc package, this is a good advertisement for it. May 19, 2011 at 19:20
7

Along the same line as the other answers, but also using the intersections library.

\documentclass{minimal}

\usepackage{tikz}
\usetikzlibrary{calc}
\usetikzlibrary{intersections}

\begin{document}

\begin{tikzpicture}
\pgfmathsetmacro{\length}{2}

\coordinate (A) at (0,0) ;
\coordinate (B) at (4,4);

\coordinate (mid) at ($(A)!0.5!(B)$);

\path[name path=line,draw=lightgray] (A) node[left] {$A$} -- (B)  node[right] {$B$};
\path[name path=circle,draw=lightgray] (mid) circle[radius=0.5*\length];

\draw [red, blue,ultra thick, name intersections={of=line and circle}]
(intersection-1) -- (intersection-2);
\end{tikzpicture}

\end{document}

The output is

line

The length of the blue segment is determined by the value of the macro \length.

Another option is to clip the path :

\begin{tikzpicture}
\pgfmathsetmacro{\length}{2}

\coordinate[label=left:$A$] (A) at (0,0) ;
\coordinate[label=right:$B$] (B) at (4,4);

\coordinate (mid) at ($(A)!0.5!(B)$);

\begin{scope}
\clip (mid) circle[radius=0.5*\length];
\draw[blue,ultra thick] (A) -- (B);
\end{scope}
\end{tikzpicture}
3
  • This is a great illustration of named paths. Thanks! May 19, 2011 at 17:47
  • @Jamie : I just realized that the length of the line segment is the diameter of the circle !! I must divide the radius of the circle by 2. I fixed the code, but not the picture.
    – Frédéric
    May 19, 2011 at 17:53
  • Thanks Frédéric. It's funny that the first three solutions manage to do it in four different ways! May 19, 2011 at 19:21
6

How about that?

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

\begin{document}
\begin{tikzpicture}
    % def Points
    \fill (0,0) coordinate (A) circle (1pt) (5,2) coordinate (B) circle (1pt); 
    % two nodes A and B
    \node [below] at (A) {Node A};
    \node [above] at (B) {Node B};
    % line between
    \draw ($(A)!1cm!(B)$) -- ($(A)!3cm!(B)$);
\end{tikzpicture}
\end{document}

First I define two corrdinates, draw them and add two nodes. The I the ⟨p⟩!⟨factor/dimension⟩!⟨q⟩ syntax to get specified points between A and B.
Unfortunately in my solution you have to use two dimes to get a defined length. In ths case 3cm - 1cm = 2cm segment length.

See PGF manual, section “4.2.1 Using Partway Calculations for the Construction of D” in the Euclid Tutorial

0

You must log in to answer this question.

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