5

Using LaTeX and TikZ, is it possible to use a Line-To operation in the same command as a distance operation? I would like to draw a rectangle and then create a named node at the midpoint of the upper edge of the rectangle. To do this I am using a Distance Operation to find the center of the Rectangle and then a Line-To Operation to find the upper edge. See below for the MWE code that I think should work, but is not working.

\documentclass[11pt]{article}
\usepackage{tikz}
\usetikzlibrary{calc}

\begin{document}

\begin{tikzpicture}
\node (A) at (0,0) {};
\node (B) at (10,10) {};
\node [above right] at (A) {A};
\node [below left] at (B) {B};
\draw [draw=black] (B) rectangle (A);
\node at ($(A)!0.5!(B)$ |- B) {Top of Rect [incorrect]};
\node (ABMid) [below] at ($(A)!0.5!(B)$) {Midpoint AB};
\node (rectTop) [above] at (ABMid|-B) {Top of Rect [correct]};
\end{tikzpicture}
\end{document}
1

2 Answers 2

10

I would not use such mathematical calculation to get a coordinate at the middle of the top line. Nodes on path can be placed quite intelligently.

The problem here is that the node placement on the original rectangle path is only on a straight line between the two coordinates, so the nodes on the two following paths are on the same place with the same <pos>:

\path (c1) --        node[pos=<pos>] {} (c2);
\path (c1) rectangle node[pos=<pos>] {} (c2);

I’ll have three solutions for you.

  1. A simply auxiliary coordinate.
  2. Replacing the rectangle path with two |-/-| paths.
  3. Using a proper timer functions for the rectangle path via the ext.paths.timer from my tikz-ext package.

Solution 1

With an auxiliary coordinate you can simply do

\draw (B) rectangle coordinate (aux1) (A) node[above] at (aux1 |- B) {Top of the Rect};

Code

\documentclass[tikz]{standalone}
\begin{document}
\begin{tikzpicture}
\coordinate [label=above right:A] (A) at (0,0);
\coordinate [label=below left:B] (B) at (20,10);
\draw (B) rectangle coordinate (aux1) (A) node[above] at (aux1 |- B) {Top of the Rect};
\end{tikzpicture}
\end{document}

Solution 2

Use two combined |- or -| and the position .75 or .25 (respectively). The corners have the position .5 (→ Node on a jointed TikZ path).

Code

\documentclass[tikz]{standalone}
\begin{document}
\begin{tikzpicture}
\coordinate [label=above right:A] (A) at (0,0);
\coordinate [label=below left:B] (B) at (20,10);
\draw (B) -| node[pos=.25, above] {Top of the Rect} (A) -| (B);
\end{tikzpicture}
\end{document}

Solution 3

Load the ext.paths.timer library then you can use very near start (pos = 0.125) to access the middle of the first (top) side.

Code

\documentclass[tikz]{standalone}
\usetikzlibrary{ext.paths.timer}
\begin{document}
\begin{tikzpicture}
\coordinate [label=above right:A] (A) at ( 0, 0);
\coordinate [label=below  left:B] (B) at (20,10);
\draw (B) rectangle node[very near start, above] {Top of the Rect} (A);
\end{tikzpicture}
\end{document}

Output

enter image description here

5
  • I refrained from using the pos command as a rectangle is not necessarily a square, in which case it will be difficult (well, to a certain extent) to find the top point.
    – nickpapior
    Apr 2, 2013 at 17:08
  • @zeroth The middle of the top line lies always at 0.125 (solution A) or 1.875 (updated solution B). I have also changed the coordinate of B to (20,0) to highlight this. Of course, if you want a node at a specific distance on the line (and not a ratio of the path’s length), one should either use directly ([xshift=-<distance>] B), a timer function that calculates the position from a distance or the markings library with mark=at position <distance> with \node {…}. Apr 2, 2013 at 17:23
  • Great! I had completely forgotten about the pos=.5 == corner thingy! That was what was troubling me! Great! Thanks! :) Maybe if you elaborate on this in the post it will be more clear (as it generally is a non expected feature). I mean quarter way on a path is actually half-way on the first line segment when dealing with line-to operations!
    – nickpapior
    Apr 2, 2013 at 17:32
  • I will probably use the first solution with a slight modification: \draw[red, thick, rounded corners=3pt] (A) -| (B) coordinate[pos=0.25] (test) -| (A);
    – CrazyArm
    Apr 2, 2013 at 18:14
  • 1
    @zeroth See my update. Maybe \draw (B) rectangle coordinate (aux1) (A) node[above] at (aux1 |- B) {Top of the Rect}; (see my first solution) is the easiest. Though, I do not like solutions where I have to specify one coordinate twice. Apr 2, 2013 at 21:39
1

EDIT: An inline calculation is seen in the bottom.

In principle it is. I haven't really optimized the below, it could be reduced somewhat.

You can utilize the let operator (which also comes from the calc library).

What you want to do is obtain the maximum y coordinate and then select the half x coordinate. So you need the x and y coordinates of each point.

Furthermore you should never specify a coordinate using a node! This can give very unforseen problems. Remember that nodes retain a size, whereas coordinates does not.

I would do your system something like this:

\begin{tikzpicture}
  \coordinate (A) at (0,0);
  \node[above right] at (A) {A};
  \coordinate (B) at (10,10);
  \node[below left] at (B) {B};
  \draw [draw=black] (A) rectangle (B);
  \draw let \p1 = (A),
          \p2 = (B),
          \n{x} = {(\x1+\x2)/2},
          \n{y} = {max(\y1,\y2)} in
          (\n{x},\n{y}) node[above] {Top of Rect [incorrect]};
  \coordinate (ABMid) at ($(A)!0.5!(B)$);
  \node at (ABMid) {Midpoint AB};
\end{tikzpicture}

Of course, if you don't need the coordinate ABMid then just do \node at ($(A)!.5!(B)$) {...};

What the above does is calculating on the path the x and y coordinate of your top point. \p<int> = (<coordinate>) will save x and y in \x<int>,\y<int> for further computation within the let line. The \n{x} line calculates the x-coordinate of your top point, and the \n{y} line calculates the maximum y-coordinate.

The above will yield:

enter image description here

I realized that you really wanted something inline (which is doable but ugly). So what you can do is project B onto the vertical line starting in A, then calculate the middle point between this and B, that will give you the half way on the line you need.

So this can be done via this obscure construct:

\coordinate (ABMidTop) at ($(A)!(B)!($(A)+(0,1)$)!.5!(B)$); 
\node[above] at (ABMidTop) {Top of Rect [incorrect]};

It should be read like this:
draw the line A to A+(0,1), then project B onto this line. Then take the halfway point between the previous calculated point and B.

You must log in to answer this question.

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