26

I would like to be able to calculate two new \coordinates by starting from two existing coordinates. I have defined two coordinates c1 and c2. A minimal example would be

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

\begin{document}
    \begin{tikzpicture}[x={(.05\textwidth,0)},y={(0,.05\textwidth)}]
    \def\arrowlength{0.5}
    \coordinate (c1) at (1,0);
    \coordinate (c2) at (4,1);

    \draw (c1) -- (c2);
    \end{tikzpicture}
\end{document}

Continuing from here, I would like to calculate a third coordinate, c3, that lies in the middle of c1 and c2. I have tried

\coordinate (c3) at (0.5*c1+0.5*c2);

but that gives me the error

Package pgf Error: No shape named 0 is known

Second, I would like to draw an arrow from c3, orthogonal to the line between c1 and c2. So I would like to take the difference c2-c1, rotate that vector by 90 degrees, normalize it, multiply it with the length the arrow is supposed to have, then add it to c3 and store it as a new coordinate called c4. Is this possible? (I want to avoid calculating the coordinates manually since I have to do this a lot of times and I want to be able to make changes to it easily)

Edit 1: Thanks to Jake and percusse, I reallized that I have to enclose the expression in $-signs and enclose the coordinates in parentheses. I have now updated the minimal example to

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

\begin{document}
    \begin{tikzpicture}[x={(.05\textwidth,0)},y={(0,.05\textwidth)}]
    \def\arrowlength{0.5}
    \coordinate (c1) at (1,0);
    \coordinate (c2) at (4,1);
    \coordinate (c3) at (5,0);

    \coordinate (c4) at ($(c1)!0.5!(c2)$);
    \coordinate (c5) at ($(c4)!\arrowlength!90:(c2)$);

    \coordinate (c6) at ($(c2)!0.5!(c3)$);
    \coordinate (c7) at ($(c6)!\arrowlength!90:(c3)$);

    \draw (c1) -- (c2) -- (c3);
    \draw[->] (c4) -- (c5);
    \draw[->] (c6) -- (c7);
    \end{tikzpicture}
\end{document}

which produces the image

Arrows are not equally long

As can be seen, the arrows are not equally long, so replacing 2cm (which Jake used) with 0.5 (which I assumed would automatically, like all other coordinates specified without a unit, use the x and y vectors) did apparently not work. Any ideas for how to specify the length of the arrow in terms of "unit lengths"? (The coordinate (4,1) for example is 4 unit lengths in the x-direction and 1 unit length in the y-direction)

Edit 2:

I updated my example according to Jakes suggestion to

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

\begin{document}
    \def\unitlength{0.05\textwidth}
    \begin{tikzpicture}[x={(\unitlength,0)},y={(0,\unitlength)}]
    \def\arrowlength{0.5*\unitlength}
    \coordinate (c1) at (1,0);
    \coordinate (c2) at (4,1);
    \coordinate (c3) at (5,0);

    \coordinate (c4) at ($(c1)!0.5!(c2)$);
    \coordinate (c5) at ($(c4)!\arrowlength!90:(c2)$);

    \coordinate (c6) at ($(c2)!0.5!(c3)$);
    \coordinate (c7) at ($(c6)!\arrowlength!90:(c3)$);

    \draw (c1) -- (c2) -- (c3);
    \draw[->] (c4) -- (c5);
    \draw[->] (c6) -- (c7);
    \end{tikzpicture}
\end{document}

and now the arrows are equally long.

3
  • 4
    For questions like this, you should always post a minimal example document.
    – Jake
    Aug 13, 2012 at 9:31
  • 1
    @Jake: Got it – I will try to remember that in the future. Aug 13, 2012 at 10:59
  • Under your nickname, it shows what percent of the questions you have asked has an accepted solution.
    – percusse
    Aug 15, 2012 at 10:02

2 Answers 2

32

You can use the calc library for this. See section 13.5 Coordinate Calculations of the manual.

To get the halfway point between two coordinates, you can use the syntax ($(A)!0.5!(B)$) or ($0.5*(A)+0.5*(B)$). For the rotated vector, you can use ($(A)!<length>!<angle>:(B)$).

The midpoint between two coordinates can also be found using a \path command, as Altermundus points out in a comment.

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


\begin{document}
\begin{tikzpicture}
\coordinate (C1) at (0,0);
\coordinate (C2) at (3,2);

%% Use one of the next two lines for calculating the midpoint between two coordinates using the calc library...
\coordinate (C3) at ($(C1)!0.5!(C2)$);
%\coordinate (C3) at ($0.5*(C1)+0.5*(C2)$);

%% Or create coordinates C1, C2 and C3 in one go using a path command (thanks, Altermundus!)
%\path (0,0) coordinate (C1) -- coordinate (C3) (3,2) coordinate (C2);

\coordinate (C4) at ($(C3)!2cm!90:(C2)$);

\draw (C3) -- (C2);
\draw [red] (C3) -- (C4);

\node at (C1) {C1};
\node at (C2) {C2};
\node at (C3) {C3};
\node at (C4) {C4};
\end{tikzpicture}


\end{document}  

7
  • Nice! But I'm running into problems when I'm trying to replace the 2cm with a dimensionless quantity. I've updated my question to include that. Aug 13, 2012 at 12:15
  • 1
    I can't think of a simple way to do this, since you can specify different lengths for x and y. What (physical) length would you expect the dimensionless length 1 to have? I would recommend defining a macro \def\unitlength{0.05\textwidth} before your tikzpicture, and using that macro both in the definition of x and y and in the coordinate calculations. In your example, you could use \def\unitlength{0.05\textwidth} \begin{tikzpicture}[x=\unitlength,y=\unitlength] \def\arrowlength{0.5*\unitlength}
    – Jake
    Aug 13, 2012 at 12:21
  • That would definitely be a solution. I recal I have even used a similar method for another problem I ran in to. Aug 13, 2012 at 12:23
  • 2
    Possible to get C3 : \path (0,0) coordinate (C1) -- coordinate (C3) (3,2) coordinate (C2); Aug 13, 2012 at 12:33
  • 2
    Assuming the coordinate system is not skewed, the macro \pgf@xx holds the unit x vector. So {\arrowlength*\pgf@xx} would give 0.5 times the unit x vector. But requires \makeatletter somewhere before that
    – percusse
    Aug 13, 2012 at 12:46
5

In addition to Jake's answer, when one wants to do a little more complicated point weighting etc. the local shift and scale options are useful (both with x and y counterparts). They map to lower level PGF commands \pgfpointadd and \pgfpointscale commands.

\documentclass[border=2mm]{standalone}
\usepackage{tikz}
\usetikzlibrary{calc}
\begin{document}
\begin{tikzpicture}
\draw[style=help lines] (-1,-1) grid[step=1] (1,1);
\node (c1) at (1,1) {c1};
\node (c2) at (-1,-1) {c2};
\node (c3) at (-1,1) {c3};
\coordinate (c4) at ($([shift={(-1,-1)}]c1)+(c2)+([xscale=-1]c3)$);
\draw[-latex] (c4) -- (1,-1);
\end{tikzpicture}
\end{document}

enter image description here

5
  • Nice! Although for ([shift={(-1,-1)}]c1), I'd prefer the equivalent expression (c1)+(-1,-1), just because it uses less brackets.
    – Jake
    Aug 13, 2012 at 10:14
  • @Jake Sure. But if you want to add and scale at the same time, it would cause some trouble. The order of the keys still matter.
    – percusse
    Aug 13, 2012 at 11:09
  • Nice. I didn't know that you could scale and shift coordinates that easily. I guess these are also options that you can give to \draw? Aug 13, 2012 at 12:20
  • 1
    @StrawberryFieldsForever Yes, this also works : \draw[shift={(2,2)},scale=2,rotate=90] (0,0) -- (1,1);
    – percusse
    Aug 13, 2012 at 12:30
  • 1
    How about 3D? and dot product? for example $(a_1,b_1,c_1).(a_2,b_2,c_2)=a_1 b_1 + a_2 b_2 + a_3 c_3$ ? Nov 9, 2015 at 16:40

You must log in to answer this question.

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