# How to get element position in LaTeX?

I have a test with check boxes made in LaTeX for result recognition in queXF. This works fine, but if I change something in source boxes are being relocated and queXF recognition boxes are becoming invalid.

Is it possible to make output of absolute box element position and sizes to external file?

For example, I have the following code:

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{calc}
\newcommand{\checkBox}[1]{
\begin{tikzpicture}[color=black, line width=0.2mm]
\draw (0,0) rectangle (5mm,5mm);
\end{tikzpicture}
}
\begin{document}
Question:\\
\end{document}

Output is:

And I want to get information about box positions and sizes (if possible) according to their IDs. Maybe something like this:

\Q1A{3cm}{2cm}{5mm}{5mm}
\Q2B{3cm}{2.5cm}{5mm}{5mm}

Or in any other format that could be parsed.

Any ideas are greatly appreciated.

-

If you use the remember picture option of tikzpicture the picture origin is written to the auxiliary file (.aux). The used unit is scaled points sp which is 65536sp = 1pt = 1/72.27inch. The origin is IIRC the lower left page corner. You can also save any content in a box register and write its size into the auxiliary file or another one.

Even better is the zref-abspos package which allows you to get the absolute position of any point, also in sp. You need to place a \zsavepos{<name>} at these coordinates and then can get the coordinates after one compilation using \zposx{<name>} and \zposy{<name>}. The manual states that it is only good for relative positions because there is no official reference origin, but in all my tests it was also the lower left page corner.

The following code should demonstrate this:

\documentclass{article}
\usepackage{zref-user}
\usepackage{zref-abspos}
\usepackage{tikz}
\usetikzlibrary{calc}
\newcommand{\checkBox}[1]{%
\begin{tikzpicture}[color=black, line width=0.2mm]
\draw (0,0)
node {\zsavepos{#1-ll}}
rectangle (5mm,5mm)
node {\zsavepos{#1-ur}};
\end{tikzpicture}%
\write\mywrite{#1: \zposx{#1-ll}, \zposy{#1-ll}, \zposx{#1-ur}, \zposy{#1-ur}}%
}
\newwrite\mywrite
\openout\mywrite=\jobname.pos\relax
\begin{document}
Question:\\
\end{document}

It writes a .pos file which holds the positions like this:

Q1A: 9017948, 41890363, 9950287, 42822702
Q1B: 9017948, 40455628, 9950287, 41387967
Q1C: 9017948, 39020893, 9950287, 39953232
Q1D: 9017948, 37586158, 9950287, 38518497

The format can also be changed to get the values in pt or another unit, or the origin plus size instead of the absolute position of the lower left and upper right corner like it is now.

For mm output replace the \write content with:

\write\mywrite{#1: (%
\dimtomm{\zposx{#1-ll}sp},
\dimtomm{\zposy{#1-ll}sp}) + (%
\dimtomm{\zposx{#1-ur}sp-\zposx{#1-ll}sp},
\dimtomm{\zposy{#1-ur}sp-\zposy{#1-ll}sp})%
}%

\makeatletter
\newcommand\dimtomm[1]{%
\strip@pt\dimexpr 0.351459804\dimexpr#1\relax\relax mm%
}
\makeatother

Then you get:

Q1A: (48.36134mm, 224.64914mm) + (4.99992mm, 4.99992mm)
Q1B: (48.36134mm, 216.95496mm) + (4.99992mm, 4.99992mm)
Q1C: (48.36134mm, 209.26077mm) + (4.99992mm, 4.99992mm)
Q1D: (48.36134mm, 201.5666mm) + (4.99992mm, 4.99992mm)

If you mind the shown precision and like to round the numbers instead have a look at \pgfmathprintnumber of PGF/TikZ. However, if you parse these files anyway you can do it then as well.

If you are using DVI mode (i.e. latex not pdflatex), the tikzpicture is created using PostScript code executed by dvips after the TeX processing. In this case both nodes are not yet placed and get the same coordinates which should be the origin of the picture. Instead I would only save one point and measure the size of the picture to get the other one. Note that I added some PGF/TiKZ code to make sure that \zsavepos doesn't influence the size of the picture.

\documentclass[a4paper]{article}
\usepackage{zref-user}
\usepackage{zref-abspos}
\usepackage{tikz}
\usetikzlibrary{calc}
\newsavebox\mybox
\newcommand{\checkBox}[1]{%
\begingroup
\sbox\mybox{%
\begin{tikzpicture}[color=black, line width=0.2mm]
% Pace the save pos "whatsit" without influencing the bounding box / size of the picture
\begin{pgfinterruptboundingbox}
\node at (0,0) {\zsavepos{#1-ll}};
\end{pgfinterruptboundingbox}
\draw (0,0) rectangle (5mm,5mm);
\end{tikzpicture}%
}%
\usebox\mybox
\immediate\write\mywrite{#1: (%
\dimtomm{\zposx{#1-ll}sp},
\dimtomm{\zposy{#1-ll}sp}) + (%
\dimtomm{\wd\mybox},
\dimtomm{\ht\mybox+\dp\mybox})%
}%
\endgroup
}
\makeatletter
\newcommand\dimtomm[1]{%
\strip@pt\dimexpr 0.351459804\dimexpr#1\relax\relax mm%
}
\makeatother
\newwrite\mywrite
\immediate\openout\mywrite=\jobname.pos\relax
\begin{document}
Question:\\
\end{document}
-
Thank you! It is even more, than I could imagine. –  Yuriy Petrovskiy Dec 6 '11 at 14:31
@Martin -- 1pt does not equal 72.27 inches; 1 inch = 72.27 points. 1pt = .013837in. (see the texbook, p.57.) 72+ inches is more than 6 feet, nearly 2 meters. i really don't think that is what you mean. –  barbara beeton Dec 6 '11 at 16:02
@barbarabeeton: Sure, I simply forgot the 1/. –  Martin Scharrer Dec 6 '11 at 17:48
@YuriyPetrovskiy: Are you using pdflatex? You need to compile twice and also ensure that the nodes are placed correctly. Fell free to edit you question to show your used code. –  Martin Scharrer Dec 6 '11 at 21:15
@YuriyPetrovskiy: In this case (DVI mode) both nodes are placed with PostScript and the positions in TeX fall to the origin of the tikzpicture. If you position the \zsavepos manually, maybe using \raisebox{<amount>}{<content>}, outside the picture it should work. –  Martin Scharrer Dec 6 '11 at 21:48

using tikz for the boxes is totally overkill ...

\documentclass{article}
\usepackage{xcolor,zref-savepos}
\newcommand\checkBox[1]{\zsavepos{#1}{\fboxsep=0pt\fbox{\color{white}\rule{5mm}{5mm}}}}
\newdimen\DimX \newdimen\DimY
\makeatletter
\newcommand\getCM[1]{%
\DimX=\zposx{#1}sp\relax \DimX=0.0347\DimX
\DimY=\zposy{#1}sp\relax \DimY=0.0347\DimY
\strip@pt\DimX:\strip@pt\DimY}
\makeatother

\begin{document}
Question:\\