18

Is there a way of testing if a \pageref is the current page? For example, in the next code:

\newcommand\figureref[1]{%
  Figure~\ref{#1} (p.~\pageref{#1})
}

I would like to eliminate the (p.~\pageref{#1}) if the referenced figure is on the same page as the reference. I tried using the varioref package and but couldn't tweak it to the desired behavior.

UPDATE:

Going back to the original question of testing for current page, this almost worked:

\newcounter{cPage}
\newcommand\figureref[1]{%
  Figure~\ref{#1}%
  \setcounter{cPage}{\value{page}}\addtocounter{cPage}{1}%
  \ifthenelse{\value{cPage}=\pageref{#1}}{}{(p.~\pageref{#1})}%
}

But, the page value is not very consistent. Sometimes it changes in the middle of a page. The offset varies, between -1/1 and +1/2, and I can't seem to find any logic behind it.

3
  • The current answer you got from TH. seems to do the work. Can you explain explain why it is not working or produce a minimal example that shows any compilation errors? Aug 30, 2010 at 11:44
  • I've accepted the answer from Ulrike. Despite all the great efforts from TH, Ulrike's solution was simpler and faithful to the original question. I did not try to find a minimal example exhibiting compilation errors, though... Once the 24h limit on the bounty passes, I'll award it to Ulrike (unless, of course, any limitation in his answer is raised which would make TH. solution the best one). Aug 30, 2010 at 22:57
  • As Ulrike mentioned, you probably omitted the \makeatletter for the second of my three solutions. Anyway, my third solution was to basically copy what varioref does to solve this problem, so it's not really very original.
    – TH.
    Aug 31, 2010 at 4:31

2 Answers 2

13
+50

If you want to compare a \pageref with the current page you should use \pageref for the current page too by setting an internal label. E.g.:

\documentclass{article}
\usepackage{ifthen}
\newcounter{cPage}
\newcommand\figureref[1]{%
  Figure~\ref{#1}%
 \refstepcounter{cPage}\label{current\thecPage}%
 \ifthenelse{\equal{\pageref{#1}}{\pageref{current\thecPage}}}%
  {}{~(p.~\pageref{#1})}}%

\begin{document}
\begin{figure}
 \caption{blub}\label{bla}
 \end{figure}

 \figureref{bla} \newpage \figureref{bla} abc
\end{document}

(varioref is setting such internal labels too, and I'm rather certain that one could get the wanted behaviour with varioref but I don't have the time to look it up).

Your \spacefactor error is probably due to a missing \makeatletter.

5
  • 2
    varioref doesn't use \label internally because there is apparently some issue with hyperref and amsmath. That's why I copied what it does and reproduce the behavior of \label. That said, your code works for me even with hyperref so I don't know what the problem was.
    – TH.
    Aug 30, 2010 at 12:28
  • +1 to your comment. It worries me that Ulrike code could have some issues with hyperref. This said, I'm now using it for my PhD thesis, and in 210pages and more than 30 images, I have yet to find somewhere it fails. I'm now also applying the same logic for Tables and Listings. Aug 30, 2010 at 23:28
  • I didn't intent my code to be a "complete" solution. I only wanted to show you the principle: that you have to use a label/ref-method. It is certainly possible to break the code by redefining \pageref or \thepage so that \equal is no longer able to compare the values. In this case it could be necessary to use another label/ref-system e.g. through the zref package. Aug 31, 2010 at 11:12
  • If you're going to be using it for more than one thing, you should abstract it so that you only have to write it once like I did with the \ifrefthispage. It should be easy to package up Ulrike's solution in a similar manner. I'm curious what's wrong with using varioref still. It seems like it's designed to do what you want.
    – TH.
    Aug 31, 2010 at 16:03
  • Just a note: In certain rare instances, it looks like this approach may require at least three (if not more) passes of LaTeX to work. The reason is that the width of the box that is typeset by \figureref is dependent on the location of the figure, which will require at least one pass to resolve. If the figure turns out to be on a different page, the width of the \figureref box will increase, due to the ~(p.~\pageref... text. That small increase might push figures that were on the current page do a later page, thus requiring another pass.
    – ESultanik
    Feb 23, 2011 at 13:42
6

Looks like you want something like

\newcommand*\figureref[1]{Figure~\vref{#1}}
\renewcommand*\reftextbefore{(p.~\thevpagerefnum)}
\let\reftextfacebefore\reftextbefore
\let\reftextafter\reftextbefore
\let\reftextfaceafter\reftextbefore
\renewcommand*\reftextfaraway[1]{(p.~\pageref{#1})}

Edit: After reading varioref more closely, I see my redefinition of \vref was unnecessary.

Edit 2: You didn't mention anything about hyperref before. I'm not sure what the best way to go about this is, but the following sort of works.

\newcommand*\figureref[1]{Figure~\ref{#1}\vpageref[]{#1}}
\makeatletter
\let\old@vpageref\@vpageref
\def\@vpageref[#1]{\@ifnextchar[%]
        {\vpageref@interpose{#1}}%
        {\vpageref@interpose{#1}[\unskip\vref@space]}%
}
\def\vpageref@interpose#1[#2]#3{%
        \def\thereflabel{#3}%
        \@@vpageref{#1}[#2]{#3}%
}
\makeatother
\renewcommand*\reftextbefore{\reftextfaraway{\thereflabel}}
\let\reftextfacebefore\reftextbefore
\let\reftextafter\reftextbefore
\let\reftextfaceafter\reftextbefore
\renewcommand*\reftextfaraway[1]{(p.~\pageref{#1})}

I think hyperref changes \@@vpageref which is why I didn't just modify that directly.

Update:

Okay, going back to your original question. This is essentially what varioref does to solve this problem.

\documentclass{article}

\newcount\testpagecount
\testpagecount0
\DeclareRobustCommand\ifrefthispage[3]{%
        \global\advance\testpagecount1
        \getpagenum\refstartnum{tpcstart\the\testpagecount}%
        \getpagenum\refendnum{tpcend\the\testpagecount}%
        \getpagenum\labelnum{#1}%
        \ifx\refstartnum\refendnum\else
                \GenericWarning{}{Reference to #1 fell on page
                boundary \refstartnum-\refendnum}%
        \fi
        \testpagelabel{tpcstart\the\testpagecount}%
        \ifx\labelnum\refendnum
                #2%
        \else
                #3%
        \fi
        \testpagelabel{tpcend\the\testpagecount}%
}

\makeatletter
\def\getpagenum#1#2{%
        \@ifundefined{r@#2}{\@namedef{r@#2}{{??}{??}}}{}%
        \protected@edef#1{\expandafter\expandafter\expandafter
                \@cdr\csname r@#2\endcsname\@nil}%
}

\def\testpagelabel#1{%
        \protected@write\@auxout{}{\string\newlabel{#1}{{}{\thepage}}}%
}
\makeatother

\begin{document}

\section{Foo}\label{sec:foo}
\ifrefthispage{sec:foo}{Ref is on this page}{Ref is not on this page}
\newpage
\ifrefthispage{sec:foo}{Ref is on this page}{Ref is not on this page}
\end{document}

Basically, it generates two new labels, one on either side of the two replacement texts using \testpagelabel which is nearly identical to the standard \label, just without the actual label. On subsequent runs, it checks if the two labels straddle a page boundary. If they do, a warning is issued. (Admittedly, I didn't check that code path.) Then, if the second label is on the same page as the label you want to test, it uses the tokens in the second argument, otherwise it use the tokens in the third argument.

Note that on page boundaries, it could change every time you compile. I don't really know of a way to handle that .

4
  • Very, very good. Just one problem with the style (sorry to nitpick) :( To be consistent with the rest of the document, i.e., color, I needed that only the page number appeared as an hyperlink, instead of the whole (p. xxx). Is it asking too much? :) Aug 27, 2010 at 14:33
  • Does that work for you?
    – TH.
    Aug 27, 2010 at 23:27
  • It gives me a compilation error: You can't use `\spacefactor' in vertical mode. Aug 28, 2010 at 2:11
  • Hmm, can you give me the usage that causes the problem? In vertical mode, the F from Figure should put it into horizontal mode so I'm not clear where the \spacefactor could cause any problems.
    – TH.
    Aug 28, 2010 at 4:42

You must log in to answer this question.

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