8

So I noticed when \hoffset or \voffset is changed, TikZ no longer finds the correct origin. Is it possible to help TikZ find the correct origin? (like a global shift or something?)

Also, why does the geometry package not just set \hoffset and \voffset to -1in in the first place instead of including it in the calculations later? Anyway, it uses \def\Gm@magtooffset{% and mentions each offset 4 times, so it does something with them.

Anyway, I have tried writing my own code before looking at the geometry code. I noticed that how I would do it differs from how geometry does it, which I will call the Top-down, Left-right Method and the Fixed Body Text Area Method, respectively.

Top-down, Left-right Method

Just for info \topmargin is making me crazy. Even size10.clo contains

 \addtolength\topmargin{-\footskip}     % this might be wrong!

I think it is wrong (unless used to perfectly center body text area by dividing by 2, which I guess it does when it multiples itself by .5)

  1. Start by reversing the built-in TeX margins of 1 inch.

Top-down

  1. Set\headheight
  2. Set \headsep
  3. Set \footskip
  4. From those, calculate \topmargin and \textheight.

Left-right

  1. Start with \oddsidemargin
  2. From that, calculate the \textwidth

Note that even if I set the offsets to 0 and take away 1 inch from oddsidemargin and topmargin, TikZ cannot find the right origin in this method. Also note that I do not need or plan on using margin notes in my document, so I just set those values to zero.

Fixed Body Text Area Method

From the geometry package: enter image description here

Note the fixed text height and text width (uses as basis for other calculations) and how this code subtracts 1 inch in the calculations of \topmargin and \oddsidemargin, which I assume are to negate the 1 inch built-in TeX margins.

Derived Article Class derivedarticle.cls

Both methods are left uncommented, which means that the bottom method will overwrite the first method. The Fixed Body Text Area Method is below and takes precedence here.

\ProvidesClass{derivedarticle}[1642 v 0.01 derived article class with different dimensions (jlk)]
\LoadClass{article}

\global\def\@mm{mm}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% TOP DOWN, LEFT RIGHT METHOD: HOW I WOULD DO IT
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% BASELINE PAGE OFFSETS
\hoffset         -1in % <-- reverse irritating TeX built-in 1in left margin
\voffset         -1in % <-- reverse irritating TeX built-in 1in top margin
% TOP DOWN ALIGNMENT
\headheight             1\baselineskip  % header box height
\headsep                10\@mm  % distance from bottom of header box to top of body box, can cancel out footer margin!
\footskip               \dimexpr 10\@mm + \baselineskip\relax  % distance from bottom of body box to BOTTOM of footer box, if 0, then body box will not subtract anything from its height and extend to end of the page

\topmargin              \dimexpr \headheight + \headsep \relax % distance from top of page to top of header box
\textheight             \dimexpr \paperheight - \headheight - \headsep - \footskip -2cm \relax

\marginparpush          0\@mm  % minimum space below margin notes boxes and the next box

% LEFT RIGHT ALIGNMENT
\oddsidemargin          \dimexpr 20\@mm \relax  % left margin for even/odd pages in single-side docs
\textwidth              \dimexpr (\paperwidth - 2\oddsidemargin) \relax

\marginparsep           0\@mm  % distance from right of body area to margin notes area


%END%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% FIXED BODY TEXT AREA METHOD: GEOMETRY PACKAGE
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% \setlength\textwidth{7in}
%      \setlength\textheight{10in}
%      \setlength\oddsidemargin{(\paperwidth-\textwidth)/2 - 1in}
%      \setlength\topmargin{(\paperheight-\textheight
% -\headheight-\headsep-\footskip)/2 - 1in}

% BASELINE PAGE OFFSETS
\hoffset         0in % <-- reverse irritating TeX built-in 1in left margin
\voffset         0in % <-- reverse irritating TeX built-in 1in top margin

% TOP DOWN ALIGNMENT
\headheight             1\baselineskip  % header box height
\headsep                10\@mm  % distance from bottom of header box to top of body box, can cancel out footer margin!
\footskip               \dimexpr 10\@mm + \baselineskip\relax  % distance from bottom of body box to BOTTOM of footer box, if 0, then body box will not subtract anything from its height and extend to end of the page

\textheight             43\baselineskip % <-- FIXED TEXTHEIGHT
\topmargin              \dimexpr (\paperheight - \textheight - \headheight - \headsep - \footskip)/2 - 1 in \relax % <-- reverse irritating TeX build-in 1in left margin here


\marginparpush          0\@mm  % minimum space below margin notes boxes and the next box

% LEFT RIGHT ALIGNMENT
\textwidth              7 in % <-- FIXED TEXTWIDTH
\oddsidemargin          \dimexpr (\paperwidth-\textwidth)/2 - 1 in % <-- reverse irritating TeX build-in 1in left margin here


\marginparsep           0\@mm  % distance from right of body area to margin notes area

\endinput

Document Using Derived Article Class

This document has a TikZ overlay for demonstration purposes.

\documentclass{derivedarticle}
\usepackage{fontspec}% xelatex
\usepackage{tikz}
\usetikzlibrary{calc}% for calculating distance between points
\usepackage{tikzpagenodes}% get area nodes
\usepackage{atbegshi}% for shipout access
\usepackage{lipsum}% for dummy text
\definecolor{blueprint}{cmyk}{.85,.51,0,0}% For visual effect

\AtBeginShipout{\AtBeginShipoutUpperLeftForeground{\draftpage}}% use upperleftforeground to make (0,0) at north west corner as TikZ expects

\def\draftpage{% <-- normally in a savebox to calculate once for better performance
  \begin{tikzpicture}[overlay,remember picture]
    \tikzset{blueprintmeasurement/.style={draw,dashed,color=blueprint,<->,opacity=0.5}}
    \tikzset{blueprintborder/.style={draw,color=blueprint,opacity=0.5}}
    \tikzset{blueprinttext/.style={color=blueprint,opacity=0.5}}
    \node [blueprinttext,anchor=north east,font=\sffamily\bfseries] at ($(current page.north east)+(-2mm,-2mm)$) {{Developer Mode}};
     % Draw Current Page Text Area Frame
    \draw [blueprintborder]% text area west
      let \p{pathID1} = ($(current page text area.south west)-(current page text area.north west)$)
        in
          (current page text area.north west)
          node [left,yshift=-1cm] {\pgfmathparse{veclen(\x{pathID1},\y{pathID1})/1mm}\pgfmathprintnumber[precision=2]{\pgfmathresult} mm}
        to
          (current page text area.south west);
    \draw [blueprintborder]% text area north
      let \p{pathID} = ($(current page text area.north east)-(current page text area.north west)$)
        in
          (current page text area.north west)
          node [above,xshift=1cm] {\pgfmathparse{veclen(\x{pathID},\y{pathID})/1mm}\pgfmathprintnumber[precision=2]{\pgfmathresult} mm}
        to (current page text area.north east);
    \draw [blueprintborder] % text area east
      (current page text area.north east)
      to (current page text area.south east);
    \draw [blueprintborder] % text area south
      (current page text area.south east)
      to (current page text area.south west);
        % Margins
    \draw [blueprintmeasurement]% left margin
      let \p{pathID} = ($(current page text area.west)-(current page.west)$)
        in
        (current page.west)
          node [above,xshift=10mm] {\pgfmathparse{veclen(\x{pathID},\y{pathID})/1mm}\pgfmathprintnumber[precision=2]{\pgfmathresult} mm}
        to (current page.west -| current page text area.west);
    \draw [blueprintmeasurement]% right margin
      let \p{pathID} = ($(current page text area.east)-(current page.east)$)
        in
        (current page.east)
          node [above,xshift=-10mm] {\pgfmathparse{veclen(\x{pathID},\y{pathID})/1mm}\pgfmathprintnumber[precision=2]{\pgfmathresult} mm}
        to (current page.west -| current page text area.east);
    \draw [blueprintmeasurement]% top margin
      let \p{pathID} = ($(current page text area.north)-(current page.north)$)
        in
        (current page.north)
          node [left,yshift=-10mm] {\pgfmathparse{veclen(\x{pathID},\y{pathID})/1mm}\pgfmathprintnumber[precision=2]{\pgfmathresult} mm}
        to (current page text area.north -| current page.north);
    \draw [blueprintmeasurement]% top margin
      let \p{pathID} = ($(current page text area.south)-(current page.south)$)
        in
        (current page.south)
          node [left,yshift=20mm] {\pgfmathparse{veclen(\x{pathID},\y{pathID})/1mm}\pgfmathprintnumber[precision=2]{\pgfmathresult} mm}
        to (current page text area.south -| current page.south);
  \end{tikzpicture}
}

\begin{document}
\lipsum
\end{document}

Output with hoffset and voffset set to -1in

enter image description here

Output with hoffset and voffset unchanged

enter image description here

  • 7
    “Why does the geometry package not just set \hoffset and \voffset to -1in in the first place instead of including it in the calculations later?” Because several package rely on \hoffset and \voffset being zero. These parameters should only be used for small corrections due to printing devices. – egreg Jan 9 '18 at 10:54
  • @egreg Super useful to know and should probably be emphasized in all documentation regarding page dimensions. The interesting thing is, when I leave them both at 0pt and apply -1in to \oddsidemargin and \topmargin in the Top-down, Left-right Method, TikZ still calculates the wrong origin. – Jonathan Komar Jan 9 '18 at 12:55
  • 2
    \oddsidemargin is the left margin minus 1in – egreg Jan 9 '18 at 13:04
  • @egreg Ah, I see the confusion in the size10.clo file. So it also seems that LaTeX takes the fixed \textwidth and \textheight approach, effectively prioritizing the body text area and basing the other numbers off of that using \addtolength and \tempdima. I am still not sure why that is the best way to go. – Jonathan Komar Jan 9 '18 at 13:29
  • 1
    Is there any particular reason you want to design a square wheel? It is just that the round ones have been working pretty well for a while - not perfect, admittedly, but pretty functional, all things considered. – cfr Jan 10 '18 at 1:32
3

It looks like the answer is two-fold.

Don't change the offsets because

  1. Many packages (perhaps erroneously) rely on \hoffset and \voffset being 0. Summary: Don't change it. (unless there are computer-to-printer interface issues) - thanks egreg
  2. TikZ does find the correct page origins if the 1 inch is taken from margins.

I'm stubborn, I'm changing the hoffset and voffsets anyway!

This is not recommended. The way to adjust tikzpagenodes is to add this after loading it and remove the inch adjustment:

\def\current@textarea@left{(-1in+\hoffset+\currentsidemargin)}
\def\current@textarea@top{(-1in+\voffset+\topmargin+\headheight+\headsep)}

I am not sure how to do this in tikz yet, more or less because there are many files to sort through.

My Musings on the Package Presumptions

It does not seem like a good idea for all packages to blindly rely on offsets being 0. For example, what if I really do have a printing error (as a realistic situation proposed by egreg in the comments)? I would need to adjust my offsets by some small amount, in which case, the TikZ overlay coordinates would be off by that same amount. It is a minor issue, but alignment is important for visually appealing documentation.

\documentclass{derivedarticle}
\usepackage{fontspec}% xelatex
\usepackage{tikz}
\usetikzlibrary{calc}% for calculating distance between points
\usepackage{tikzpagenodes}% get area nodes
\usepackage{atbegshi}% for shipout access
\usepackage{lipsum}% for dummy text
\definecolor{blueprint}{cmyk}{.85,.51,0,0}% For visual effect

\AtBeginShipout{\AtBeginShipoutUpperLeftForeground{\draftoverlay}}% use upperleftforeground to make (0,0) at north west corner as TikZ expects


\def\draftoverlay{% <-- normally in a savebox to calculate once for better performance
  \begin{tikzpicture}[overlay,remember picture]
    \tikzset{blueprintmeasurement/.style={draw,dashed,color=blueprint,<->,opacity=0.5}}
    \tikzset{blueprintborder/.style={draw,color=blueprint,opacity=0.5}}
    \tikzset{blueprinttext/.style={color=blueprint,opacity=0.5}}
    \node [blueprinttext,anchor=north east,font=\sffamily\bfseries] at ($(current page.north east)+(-2mm,-2mm)$) {{Developer Mode}};
     % Draw Current Page Text Area Frame
    \draw [blueprintborder]% text area west
      let \p{pathID1} = ($(current page text area.south west)-(current page text area.north west)$)
        in
          (current page text area.north west)
          node [left,yshift=-1cm] {\pgfmathparse{veclen(\x{pathID1},\y{pathID1})/1mm}\pgfmathprintnumber[precision=2]{\pgfmathresult} mm}
        to
          (current page text area.south west);
    \draw [blueprintborder]% text area north
      let \p{pathID} = ($(current page text area.north east)-(current page text area.north west)$)
        in
          (current page text area.north west)
          node [above,xshift=1cm] {\pgfmathparse{veclen(\x{pathID},\y{pathID})/1mm}\pgfmathprintnumber[precision=2]{\pgfmathresult} mm}
        to (current page text area.north east);
    \draw [blueprintborder] % text area east
      (current page text area.north east)
      to (current page text area.south east);
    \draw [blueprintborder] % text area south
      (current page text area.south east)
      to (current page text area.south west);
        % Margins
    \draw [blueprintmeasurement]% left margin
      let \p{pathID} = ($(current page text area.west)-(current page.west)$)
        in
        (current page.west)
          node [above,xshift=10mm] {\pgfmathparse{veclen(\x{pathID},\y{pathID})/1mm}\pgfmathprintnumber[precision=2]{\pgfmathresult} mm}
        to (current page.west -| current page text area.west);
    \draw [blueprintmeasurement]% right margin
      let \p{pathID} = ($(current page text area.east)-(current page.east)$)
        in
        (current page.east)
          node [above,xshift=-10mm] {\pgfmathparse{veclen(\x{pathID},\y{pathID})/1mm}\pgfmathprintnumber[precision=2]{\pgfmathresult} mm}
        to (current page.west -| current page text area.east);
    \draw [blueprintmeasurement]% top margin
      let \p{pathID} = ($(current page text area.north)-(current page.north)$)
        in
        (current page.north)
          node [left,yshift=-10mm] {\pgfmathparse{veclen(\x{pathID},\y{pathID})/1mm}\pgfmathprintnumber[precision=2]{\pgfmathresult} mm}
        to (current page text area.north -| current page.north);
    \draw [blueprintmeasurement]% top margin
      let \p{pathID} = ($(current page text area.south)-(current page.south)$)
        in
        (current page.south)
          node [left,yshift=20mm] {\pgfmathparse{veclen(\x{pathID},\y{pathID})/1mm}\pgfmathprintnumber[precision=2]{\pgfmathresult} mm}
        to (current page text area.south -| current page.south);
  \end{tikzpicture}
}
\begin{document}
\draftoverlay%
\tikz [overlay,remember picture] \node [fill=black,anchor=north west] at (current page.north west) {};%
\tikz [overlay,remember picture] \node [fill=black,anchor=south west] at (current page.south west) {};%
\tikz [overlay,remember picture] \node [fill=black,anchor=north east] at (current page.north east) {};%
\tikz [overlay,remember picture] \node [fill=black,anchor=south east] at (current page.south east) {};%
\lipsum
\end{document}
  • 1
    The assumption of zero offsets is very long-standing: for a new format, I think a different choice would (will?) be made ... – Joseph Wright Jan 10 '18 at 12:04
  • 1
    @JosephWright One should keep in mind that there are two different issues here: on the one side there are \hoffset and \voffset that should be used to fix problems with the device drivers; on the other side there is the standard origin that's not at the upper left corner of the page where it should be instead: I'd favor moving it. Packages should be agnostic with respect to \hoffset and \voffset (that is, ignore them). – egreg Jan 11 '18 at 13:54

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.