Starting a tikz loop at the margin. How to properly specify the starting position

diagramsmarginsmemoirtikz-pgfunit-of-measure

I am attempting to encourage the reader to take notes in my book by making extra-wide margins and drawing lines down the outer edge. But I can't seem to get the lines to start in the right place.

Expectation: For even pages, the first line should be x-offset by the left margin and y-offset by the top margin + the header. If I start the line under the headsep and draw them as wide as the marginpar, they should fit neatly into the page margins every time

Reality: I suspect there is a mismatch between the units I am offsetting by and the units I am expecting. So the horizontal offset is much larger than expected and the vertical offset is much smaller than expected. I'm not sure how to account for that without setting it to an absolute position, but I'm clearly misunderstanding something

\documentclass[10pt, twoside, openright]{memoir}
\usepackage{lipsum}
\usepackage{calc,fancyhdr}
 
% define the margins and text block size
\setlrmarginsandblock{14mm}{50mm}{*}
\setulmarginsandblock{27mm}{22mm}{*}
\checkandfixthelayout

% define the image command. This command should draw lines as wide
% as the margin paragraph starting at the top-left corner of the 
% margin and moving down by 15pt until it runs out of text block. 
% The first line is red just to illustrate where the pattern starts
\usepackage{tikz}
\newcommand{\drawNoteRules}{
  \begin{tikzpicture}[remember picture, overlay]
    \pgfmathtruncatemacro{\lineSpacing}{15 pt}
    \pgfmathtruncatemacro{\yPosOffset}{\topmargin+\headheight+\headsep}
    \foreach \y in {0,\lineSpacing,...,\textheight} {
        \ifnum\y=0
            \draw[red] (current page.north west) ++(\leftmargin,-\y-\yPosOffset mm) -- ++(\marginparwidth,0);
        \else   
            \draw[] (current page.north west) ++(\leftmargin,-\y-\yPosOffset mm) -- ++(\marginparwidth,0);
        \fi
    }
  \end{tikzpicture}
}

% fancy header that pushes into the margins, add the tikz image to the header
\fancypagestyle{bookpage}{
    \fancyheadoffset[LE,RO]{\marginparsep+\marginparwidth}
    \fancyhead[EL]{\thepage\drawNoteRules}
}

\begin{document}
\pagestyle{bookpage}
\lipsum[1-20]
\end{document}

actual image. not offset by expected amount

Best Answer

In case you are interested in getting a drawing showing layout parameters of pages of your document, via \usepackage{layout} load the package layout and use the command \layout.


From vertical margins you only specify the top-margin, the head-height and the head-sep. The bottom-margin comes into being by placing a textblock of height \textheight whose top border is on vertical position 1in+\topmargin+\headheight+\headsep and whose height is \textheight on a paper of height \paperheight. \topskip is the distance between the baseline of the first line of the textblock and the top border of the textblock.

Thus from the top border of the page to the baseline of the first line of the textblock you have a vertical distance of 1in+\topmargin+\headheight+\headsep+\topskip.

With your TikZ-pictures you calculate from (current page.north west), which is in the top left corner of the page, thus everything needs to go downward=needs to go upward in negative direction.

With pages of twoside-documents:

  • LaTeX considers pages with

    • even page numbers to be left hand pages/verso-pages.
    • odd page numbers to be right hand pages/recto-pages.
  • From the horizontal margins you only specify the left margin. The right margin comes into being as the result of there being a left margin and a textblock of width \textwidth on a paper of width \paperwidth.

  • From horizontal margins you specify left margins for the case of there being a verso page/left hand page and for the case of there being a recto page/right hand page.

  • From the left border of the paper of pages that have odd page numbers (right hand pages/recto pages) to the left border of the textblock you have a horizontal distance of 1in + \oddsidemargin. (That's the inner margins with a double page of a book with a verso page on the left and a recto page on the right.)

  • From the left border of the paper of pages that have even page numbers (left hand pages/verso pages) to the left border of the textblock you have a horizontal distance of 1in + \evensidemargin. (That's the outer margins with a double page of a book with a verso page on the left and a recto page on the right.)

  • With a right hand page/recto page/a page whose page number is odd, from the right border of the textblock to the left border of a margin-paragraph in the right margin you have a gap of with \marginparsep. Margin-paragraphs are of width \marginparwidth.

  • With a left hand page/verso page/a page whose page number is even, from the left border of the textblock to the right border of a margin-paragraphs in the left margin you have a gap of with \marginparsep. Margin-paragraphs are of width \marginparwidth.

  • If you use \reversemarginpar, then with twoside-documents margin-paragraphs will be on the inner margins and with one-side-documents margin-paragraphs will be on the right margin instead of the left margin.

  • It is said that ratio outer horizontal margin:inner horizontal margin usually is to be 2:1 so that the vertical stripe formed by the two inner horizontal margins is of same width as each of the vertical stripes that form the outer horizontal margins. I (Ulrich Diez, the author of the first version of this answer, October 16, 2023) prefer ratio top:outer:inner:bottom = 4:6:3:8 while calculating \textheight so that \textheight-\topskip is a multiple of \baselineskip. But all this is a matter of taste, so your settings were not changed in the example below. But with the example below the freedom was taken to change the line style to dotted. You can easily undo that in your real-life-scenario if you don't like that. ;-)

With pages of "oneside"-documents:

  • Recto means the front side of the paper and verso means the back side of the paper.

  • Margins for all pages are set according to those parameters that with twoside-documents determine margins of right hand pages/recto pages/pages whose page-numbers are odd.

In any case

  • the equation
    1in + \evensidemargin + \textwidth + 1in + \oddsidemargin = \paperwidth
    should hold.
  • \marginparwidth + \marginparsep should not exceed 1in + \evensidemargin as otherwise margin-paragraphs stick out of the paper. In case of doing \reversemarginpar for having margin-paragraphs on inner margins, \marginparwidth + \marginparsep should not exceed 1in + \oddsidemargin.
  • If \marginparwidth + 2*\marginparsep= 1in + \evensidemargin, then the horizontal gap between the outer horizontal paper border and the border of the box containing the margin paragraph is as wide as the horizontal gap between the border of the box containing the textblock and the border of the box containing the margin paragraph.

Thickness of lines with TikZ is:

/tikz/ultra thin - Sets the line width to 0.1pt = 0.03514598 mm.
/tikz/very thin - Sets the line width to 0.2pt = 0.07029196 mm.
/tikz/thin - Sets the line width to 0.4pt = 0.14058392 mm.
/tikz/semithick - Sets the line width to 0.6pt = 0.21087588 mm.
/tikz/thick - Sets the line width to 0.8pt = 0.28116784 mm.
/tikz/very thick - Sets the line width to 1.2pt = 0.42175176 mm.
/tikz/ultra thick - Sets the line width to 1.6pt = 0.56233568 mm.


If you use dimension-registers or \dimexpr...\relax, then \the⟨dimension register / \the\dimexpr...\relax gets you a string of explicit character tokens which denote the length in question converted to the unit pt. Trailing character tokens pt denoting the unit are a component of the result of \the. \pgfmathtruncatemacro truncates so that only the integer component of the numerical value of the result of the remains. The character tokens denoting the decimal component and the character tokens denoting the unit pt are removed by \pgfmathtruncatemacro.

When you use a dimension-register or a \dimexpr...\relax in place of a count register, without \the, then it is treated as an integer which denotes the numerical value of the length in question when it is measured in the unit sp.


The following might be a starting-point. (But probably a mechanism would be interesting, where for each paragraph y-coordinate of the first baseline and y-coordinate of the last baseline is stored via coordinates in a [remember picture, overlay] tikz-picture so that throughout the entire page horizontal lines can be produced that are aligned with the baselines of lines of paragraphs.)

\documentclass[10pt, twoside, openright]{memoir}
\usepackage{lipsum}
\usepackage{calc,fancyhdr}
 
% define the margins and text block size
\setlrmarginsandblock{14mm}{50mm}{*}
\setulmarginsandblock{27mm}{22mm}{*}
\checkandfixthelayout

% define the image command. This command should draw lines as wide
% as the margin paragraph starting at the top-left corner of the 
% margin and moving down by 15pt until it runs out of text block. 
% The first line is red just to illustrate where the pattern starts
\usepackage{tikz}
\newcommand{\drawNoteRules}[1]{%
  \begin{tikzpicture}[remember picture, overlay]
    \pgfmathtruncatemacro{\lineSpacing}{\the\dimexpr15pt\relax}
    \pgfmathtruncatemacro{\yPosOffset}{-\the\dimexpr1in+\topmargin+\headheight+\headsep+\topskip+.4pt\relax}
    \foreach \y in {0,\lineSpacing,...,\textheight} {
        \ifnum\y=0 \draw[red, dotted]\else\draw[dotted]\fi
         (current page.north west) 
         ++(\the\dimexpr\if E#1-\marginparwidth+\else\paperwidth-\fi\dimexpr+1in+\evensidemargin-\marginparsep\relax\relax, \yPosOffset pt-\y pt)%
         -- %
         ++(\the\dimexpr\marginparwidth\relax, 0);
    }
  \end{tikzpicture}%
}

% fancy header that pushes into the margins, add the tikz image to the header
\fancypagestyle{bookpage}{
    \fancyheadoffset[LE,RO]{\marginparsep+\marginparwidth}
    \fancyhead[LE]{\thepage\drawNoteRules{E}}
    \fancyhead[RO]{\thepage\drawNoteRules{O}}
}

\begin{document}
\pagestyle{bookpage}
\lipsum[1-40]
\end{document}

enter image description here


To the questions you asked in comments:

There's two things I don't get. For one, what's up with the additions to the y-offset? I get that \topskip makes it look better aligned with the text, but where did +1in and +.4pt come from?

The top margin is 1in + \topmargin in LaTeX. When going down 1in + \topmargin from the top border of the sheet of paper, you reach the top border of the box containing page header. When going down \headheight from the top border of the box containing the page header you reach the bottom border of the box containing the page header. When going down \headsep from the bottom border of the box containing the page header you reach the top border of the box containing the textblock. When going down \topskip from the top border of the box containing the textblock, you reach the baseline of the first line of text of the textblock.
If you draw a horizontal rule on that baseline, that rule can be considered a rectangular bar whose bottom border is aligned with the baseline and whose top border is a bit above the baseline. "A bit above" means ".4pt above" because this is the rule-thickness with this kind of horizontal TikZ-rule. Therefore that horizontal rule needs to be shifted downwards .4pt so that the top border of the rectangular bar which forms the rule is aligned with the baseline of the first line of the textblock.

And for two, I genuinely do not understand what is happening on line 22.

Line 22 is:

++(\the\dimexpr\if E#1-\marginparwidth+\else\paperwidth-\fi\dimexpr+1in+\evensidemargin-\marginparsep\relax\relax, \yPosOffset pt-\y pt)%

This line is about coordinates.

The vertical coordinate/y-coordinate is formed by the expression

\yPosOffset pt-\y pt

.

The horizontal coordinate/x-coordinate is formed by the expression

\the\dimexpr\if E#1-\marginparwidth+\else\paperwidth-\fi\dimexpr+1in+\evensidemargin-\marginparsep\relax\relax

.

If the argument of \drawNoteRules is E, then for the horizontal coordinate you get s.th. like:

\the\dimexpr
      -\marginparwidth
      +\dimexpr+1in+\evensidemargin-\marginparsep\relax
    \relax

1in + \evensidemargin is the outer horizontal margin of a sheet of paper of the twoside-document. With even-numbered pages/lefthand-pages/verso-pages the outer horizontal margin of the sheet of paper is the left margin.

So for even-numbered pages/lefthand-pages/verso-pages you specify argument E and thus with even-numbered pages/lefthand-pages/verso-pages from the left border of the sheet of paper you go 1in+\evensidemargin to the right and reach the left border of the box containing the textblock. From the left border of the box containing the textblock you go \marginparsep to the left and reach the right border of the box that makes a margin-paragraph. From the right border of the margin-paragraph-box you go \marginparwidth to the left and reach the left border of the margin-paragraph-box. That's the horizontal position of where TiKZ shall begin to draw the horizontal rule. Due to ++(\the\dimexpr\marginparwidth\relax, 0); from that position the horizontal rule goes to the right and has a length of \marginparwidth. Thus the left end of the (dotted) horizontal TiKZ-rule is aligned with the left border of the margin-paragraph-box and the right end of the (dotted) horizontal TiKZ-rule is aligned with the right border of the margin-paragraph-box.

If the argument of \drawNoteRules is not E, then for the horizontal coordinate you get s.th. like:

\the\dimexpr
      \paperwidth
      -\dimexpr+1in+\evensidemargin-\marginparsep\relax
    \relax

1in + \evensidemargin is the outer horizontal margin of a sheet of paper of the twoside-document. With odd-numbered pages/righthand-pages/recto-pages the outer horizontal margin of the sheet of paper is the right margin.

So for odd-numbered pages/righthand-pages/recto-pages you specify argument other than E, e.g., O, and thus with odd numbered pages/righthand-pages/recto-pages from the left border of the sheet of paper you go \paperwidth to the right and reach the right border of the sheet of paper. From the right border of the sheet of paper you go 1in+\evensidemargin to the left and reach the right border of the box containing the textblock. From the right border of the box containing the textblock you go \marginparsep to the right and reach the left border of the box that makes a margin-paragraph. That's the horizontal position of where TiKZ shall begin to draw the horizontal rule. Due to ++(\the\dimexpr\marginparwidth\relax, 0); from that position the horizontal rule goes to the right and has a length of \marginparwidth. Thus the left end of the (dotted) horizontal TiKZ-rule is aligned with the left border of the \marginpar-textblock and the right end of the (dotted) horizontal TiKZ-rule is aligned with the right border of the \marginpar-textblock.
(Alternatively from the left border of the sheet of paper you could go 1in+\oddsidemargun+\textwidth+\marginparsep to the right in order to find the left end of the (dotted) horizontal TiKZ-rule.)