O conteúdo da figura não aparece nas páginas pares após a introdução de alterações na rotina de saída

O conteúdo da figura não aparece nas páginas pares após a introdução de alterações na rotina de saída

Num documento com margens amplas, quero oferecer um ambiente de figura que se estenda até a área marginpar. Além disso, quero que o texto da legenda também seja colocado nesta área, acima ou abaixo da figura, dependendo do posicionamento da figura. Além disso, isso deve funcionar em páginas pares e ímpares (usando scrbookno meu caso, mas a twosideopção também teria o mesmo efeito).

O que eu gostaria de alcançar no final pode ser melhor ilustrado pelas figuras a seguir (desenhos muito rápidos no inkscape, não me importo com os diferentes tamanhos):

insira a descrição da imagem aquiinsira a descrição da imagem aquiinsira a descrição da imagem aqui

Em primeiro lugar, gostaria de coletar as referências de \cite-macros e exibi-las na margem inferior (isso está funcionando e, portanto, não é mostrado no MWE). Uma figura larga também deve ter sua legenda na margem. Se ocorrer uma figura larga na parte inferior, gostaria que as referências estivessem acima da legenda da figura na margem. Pode acontecer que haja algo que também seja produzido na margem superior. Como você pode ver nas figuras, deve funcionar no twosidemodo.

Para detectar onde uma figura é colocada, eu uso código sugerido por David Carlisle. Para posicionar a legenda na margem, seja na parte inferior ou superior de uma página, utilizocódigo sugerido por Heiko Oberdiek. Para testar se a página atual é ímpar ou par, se usar \ifthispageoddfrom KOMA-Scripte para garantir que a figura se estende até a margem externa, utilizo o addmargin*ambiente from KOMA-Script.

Além de vários avisos que optei por tratar posteriormente, a abordagem funciona conforme o esperado nas páginas ímpares, mas o conteúdo do meu novo widefigureambiente não aparece nas páginas pares, embora ainda haja espaço na respectiva área.

O problema é que ambas as partes do código mencionadas acima lidam (de alguma forma) com a rotina de saída (a palavramudançasno título pode não estar completamente correto), o que é uma caixa preta para mim. Introduzi apenas pequenas alterações no código (renomeei David \floatswitchpara \@floatswitch, \foopara \@helpere alterei os argumentos de comprimento da \putmacro que Heiko usou para posicionar as notas na margem).

Alguém pode explicar por que o conteúdo das figuras não aparece nas páginas pares (ou, melhor ainda, fazê-las aparecer)?

O MWE é longo devido aos trechos de código mencionados acima. Tentei adicionar alguns comentários (no meu código) que ajudam a entender a abordagem, o código do Heiko também foi comentado.

\documentclass[paper=a4,11pt]{scrbook}

\usepackage[left=1in,top=1in,headsep=2\baselineskip,
  textwidth=26pc,marginparsep=2pc,marginparwidth=12pc,
  textheight=44\baselineskip,headheight=\baselineskip]{geometry}

% It took me a while to figure out the (x)color here is not merely used for
% providing color...

\usepackage{xcolor,atbegshi,picture,zref-abspage}
\usepackage{lipsum}
\makeatletter
%\input{../features/widefigures.tex}

% This magic has been posted by David Carlisle on TeX-SX:
% https://tex.stackexchange.com/questions/56017/formatting-floats-differently-based-on-placement

\def\@floatswitch#1#2#3#4{%
  \def\@elt##1{\global\value{##1}\the\value{##1}\relax}%
  \edef\FS@ckpt{\cl@@ckpt}%
  \let\@elt\relax
\hbox to 3sp{%
\vbox{{\FS@ckpt#1\par}}%
\vbox{{\FS@ckpt#2\par}}%
\vbox{{\FS@ckpt#3\par}}%
\vbox{{\FS@ckpt#4\par}}%
\hss}\aftergroup\break}

\def\FS@checkswitch#1{%
\ifdim\wd#1=3sp %
\setbox\z@\box#1%
\begingroup
\vbadness\maxdimen
\setbox\z@\vsplit\z@ to \textheight
\setbox\z@\vbox{\unvbox\z@\global\setbox\@ne\lastbox}%
\setbox\z@\vbox{\unvbox\@ne\unskip\global\setbox\@ne\lastbox}
\setbox\z@\hbox{\unhbox\@ne\unskip
\FS@junk
\global\setbox\@ne\lastbox}%
\endgroup
\else
\global\setbox\@ne\box#1%
\fi}

\def\@comflelt#1{%
\FS@checkswitch#1%
\setbox\@tempboxa
      \vbox{\unvbox\@tempboxa\box\@ne\vskip\floatsep}}

\let\saved@cflt\@cflt
\def\@cflt{%
\def\FS@junk{\setbox\z@\lastbox\setbox\z@\lastbox\setbox\z@\lastbox}%
\saved@cflt}

\let\FS@junk\relax
\let\saved@cflb\@cflb
\def\@cflb{%
\def\FS@junk{\setbox\z@\lastbox\setbox\z@\lastbox}%
\saved@cflb}


\def\@helper#1\box\@currbox#2!!{%
\def\@addtocurcol{%
#1%
\let\FS@junk\relax
\FS@checkswitch\@currbox
\box\@ne
#2}}%
\expandafter\@helper\@addtocurcol!!

\def\@wtryfc #1{%
  \global\setbox\@outputbox\vbox{%
    \unvbox\@outputbox
    \vskip\@fpsep
\def\FS@junk{\setbox\z@\lastbox}%
\FS@checkswitch#1%
\box\@ne}}

%
% Provide a macro that allows typesetting into the margin 
%

\newcommand\@wide[2]{%#1%
  \begin{addmargin*}[0cm]{#1}#2\end{addmargin*}%
}

%
% An environment to deal with figure-like content
%

\newsavebox{\@ContentCollectorBox}
\newenvironment{@CollectContentAndCaption}[1][\linewidth]{%
  % This environment collects its content in the box \@ContentCollectorBox,
  % the width of the box is given by the optional argument #1 (defaults to
  % \linewidth) 
  % Furthermore, it redefines the \caption macro and saves its content in the
  % macros \@CurrCaptionLong and \@CurrCaptionShort. 
  %
  % The box and the two macros are available globally.
  \begingroup
    \begin{lrbox}{0\null\global\setbox\@ContentCollectorBox}%
      \begin{minipage}{#1}
        \renewcommand\caption[2][]{%
           \gdef\@CurrCaptionLong{##2}%
           \ifx\\##1\\
             \gdef\@CurrCaptionShort{##2}%
           \else
             \gdef\@CurrCaptionShort{##1}%
           \fi
        }%
}{%
      \end{minipage}
    \end{lrbox}
  \endgroup
}

%
% An environment providing a floating figure which extends in the margin.
%

\newenvironment{widefigure}[1][]{%
  % Store the optional argument. If provided, add square brackets around.
  \ifx\\#1\\
    \def\@rgOne{}%
  \else
    \def\@rgOne{[#1]}%
  \fi
  %
  % Start the environment defined above
  \begin{@CollectContentAndCaption}[\dimexpr\textwidth+\marginparsep+\marginparwidth]%
}{%
  % End the environment 
  \end{@CollectContentAndCaption}%
  % Start the figure-environment with the optional argument from
  % the \begin{widefigure} part. I use \figure here to avoid an
  % \expandafter-orgy to expand the argument
  \expandafter\figure\@rgOne
  % \@floatswitch is a command from within the magic, I just added the @ 
    \@floatswitch{%
      % If you comment the \topmarginpar-commands here, the figure content
      % will appear at the desired position.
      %
      % Output the caption. 
      \topmarginpar{\@CurrCaptionLong}%
      % add a rule to the topmargin-collection with a width of zero and the
      % height+depth of the box containing the content without the caption
      % from the environment used  above.
      \topmarginpar{\rule{0pt}{%
          \dimexpr\ht\@ContentCollectorBox+\dp\@ContentCollectorBox}}%
      %
      %
      % use the content of the widefigure-environment.
      %%%
      %%% This does not appear on even pages
      %%%
      \@wide{\wd\@ContentCollectorBox}{\usebox{\@ContentCollectorBox}}%
    }{%
      % Same as above. If you comment the \botmarginpar-commands here, the
      % figure content  will appear at the desired position.
      %
      \botmarginpar{\@CurrCaptionLong}%
      \botmarginpar{\rule{0pt}{%
          \dimexpr\ht\@ContentCollectorBox+\dp\@ContentCollectorBox}}%
      % The bottom-content appears only on odd pages
      \@wide{\wd\@ContentCollectorBox}{\usebox{\@ContentCollectorBox}}%
    }{%
      \@wide{\wd\@ContentCollectorBox}{\usebox{\@ContentCollectorBox}}%
    }{%
      \@wide{\wd\@ContentCollectorBox}{\usebox{\@ContentCollectorBox}}%
    }
  \endfigure
}

%
% This magic has been posted by Heiko Oberdiek
%  https://tex.stackexchange.com/questions/69517/send-and-stack-marginpar-to-the-top-or-the-bottom-of-the-page


\providecommand*{\c@zabspage}{\c@abspage}
% * User macros for configuring
%
% \tbmparItemSep is inserted between marginal notes
% \tbmparMiddleSep is inserted between top and bottom marginal notes.

\newcommand*{\tbmparItemSep}{%
  \vspace{1ex minus .5ex}%
  \hrule
  \vspace{1ex minus .5ex}%
}
\newcommand*{\tbmparMiddleSep}{%
  \vspace*{0pt plus 1fil}%
}
% * Debug messages
%
\newcommand*{\tbmparDebug}[1]{%
  \typeout{[tbmpar] #1}%
}

% * Label management to remember absolute page number
%
% \tbmpar@PageByLabel stores and loads absolute page number from
% label and defines \tbmpar@page with absolute page number or
% zero if the label is not yet available.

\newcount\c@tbmpar@item
\c@tbmpar@item\z@

\newcommand*{\tbmpar@PageByLabel}{%
  \global\advance\c@tbmpar@item\@ne
  \zref@labelbyprops{tbmpar\the\c@tbmpar@item}{abspage}%
  \edef\tbmpar@page{%
    \zref@extractdefault{tbmpar\the\c@tbmpar@item}{abspage}{0}%
  }%
  \zref@refused{tbmpar\the\c@tbmpar@item}%
  \tbmparDebug{Item \the\c@tbmpar@item\space on page \tbmpar@page}%
}

% * Box register management

\newcount\c@tbmpar@box
\c@tbmpar@box\z@

\let\tbmpar@boxfreelist\@empty

% Get a new free box register either from the free list or,
% if the free list is empty, allocate a new box register.
\newcommand*{\tbmpar@NextBox}[1]{%
  \@next#1\tbmpar@boxfreelist{%  
    \tbmparDebug{Reused box: #1}%
  }{%
    \global\advance\c@tbmpar@box\@ne
    \expandafter\newbox\csname tbmpar@box\the\c@tbmpar@box\endcsname
    \edef#1{\csname tbmpar@box\the\c@tbmpar@box\endcsname}%
    \tbmparDebug{New box: #1}%
  }%
}
% Put free box in free list.
\newcommand*{\tbmpar@FreeBox}[1]{%
  \begingroup
    \let\@elt\relax
    \xdef\tbmpar@boxfreelist{%
      \tbmpar@boxfreelist
      \@elt#1%
    }%
    \tbmparDebug{Free box: #1}%
  \endgroup
}

\newsavebox{\tbmpar@box}

% Each marginpar is put in a box that is initialized as
% parbox/minipage.
\newcommand*{\tbmparBoxSetup}{}
\newcommand{\tbmpar@VBox}[1]{% 
  \vbox{%
    \color@begingroup
    \hsize\marginparwidth
    \edef\tbmpar@restore@ifminipage{%
      \if@minipage
        \noexpand\@minipagetrue
      \else
        \noexpand\@minipagefalse
      \fi
    }%   
    \@parboxrestore
    \@marginparreset
    \tbmparBoxSetup 
    #1%
    \tbmpar@restore@ifminipage
    \color@endgroup
  }%
}   

% Macro \tbmpar@marginpar looks for the page, where the margin note
% belongs to, stores the note in a box and appends the box to the  
% note collector register of the page.
% Each page is assigned a box collector registers that collect
% the top notes and a register that collect the bottom notes. 
% The name of the box register is \tbmpar@<top|bot>box<page>. 
\newcommand{\tbmpar@marginpar}[4]{%
  \ifhmode
    \@bsphack
  \fi
  \tbmpar@PageByLabel
  \ifnum\tbmpar@page>\z@
    \setbox\tbmpar@box\tbmpar@VBox{#4}%
    \@ifundefined{tbmpar@#1box\tbmpar@page}{%
      \tbmpar@NextBox\tbmpar@currbox
      \global\expandafter\let
          \csname tbmpar@#1box\tbmpar@page\endcsname
          \tbmpar@currbox
      \global\setbox\tbmpar@currbox=\vbox{%
        \unvbox\tbmpar@box
      }%
    }{% 
      \tbmparDebug{Use box: \tbmpar@currbox}%
      \expandafter\let\expandafter\tbmpar@currbox
          \csname tbmpar@#1box\tbmpar@page\endcsname
      \global\setbox\tbmpar@currbox\tbmpar@VBox{%   
        \unvbox#3%
        \par
        \begingroup
          \tbmparItemSep
        \endgroup
        \unvbox#2%
      }%
    }%  
  \fi   
  \ifhmode
    \@esphack
  \fi
}

\newcommand*{\topmarginpar}{%
  \tbmpar@marginpar{top}\tbmpar@currbox\tbmpar@box
}
\newcommand*{\botmarginpar}{%
  \tbmpar@marginpar{bot}\tbmpar@box\tbmpar@currbox
}

% At shipout time we look for the box collector registers of this
% page and set these boxes in the marginpar box with respecting  
% \topskip and \maxdepth.
\def\@marginparxpos{0pt}\def\@marginparypos{0pt}%
\AtBeginShipout{%
  \AtBeginShipoutUpperLeft{%
    %
    % I added the following definition of the corresponding lengths to be able
    % to distinguish odd and even pages. 
    %
    \ifthispageodd{%
      \def\@marginparxpos{\dimexpr
        1in+\oddsidemargin+\textwidth+\marginparsep\relax}%
      \def\@marginparypos{-\dimexpr
        1in+\topmargin+\headheight+\headsep+\textheight\relax}% 
    }{%
      \def\@marginparxpos{\dimexpr
        1in+\evensidemargin-\marginparsep-\marginparwidth\relax}%
      \def\@marginparypos{-\dimexpr
        1in+\topmargin+\headheight+\headsep+\textheight\relax}% 
    }
    \put(%
      \@marginparxpos,\@marginparypos%
    ){%
      \begingroup
        \global\let\tbmpar@inuse=N%
        \setbox\tbmpar@box=\tbmpar@VBox{%
          \penalty-\@M
          \edef\tbmpar@tmp{tbmpar@topbox\the\value{zabspage}}%
          \@ifundefined{\tbmpar@tmp}{%
          }{%
            \expandafter\let\expandafter\tbmpar@currbox
                \csname\tbmpar@tmp\endcsname
            \unvbox\tbmpar@currbox
            \tbmpar@FreeBox\tbmpar@currbox
            \global\let\tbmpar@inuse=Y%   
          }%
          \endgraf
          \tbmparMiddleSep
          \edef\tbmpar@tmp{tbmpar@botbox\the\value{zabspage}}%
          \@ifundefined{\tbmpar@tmp}{%
          }{%
            \expandafter\let\expandafter\tbmpar@currbox
                \csname\tbmpar@tmp\endcsname
            \unvbox\tbmpar@currbox
            \tbmpar@FreeBox\tbmpar@currbox
            \global\let\tbmpar@inuse=Y%   
          }%
        }%  
        \ifx\tbmpar@inuse Y%
          \splittopskip=\topskip
          \setbox0=\vsplit\tbmpar@box to\z@
          \boxmaxdepth=\maxdepth
          \setbox\tbmpar@box=\vbox to\textheight{%
            \unvbox\tbmpar@box
          }%
          \box\tbmpar@box
        \fi
      \endgroup
    }%
  }%  
}     

\makeatother
\begin{document}
%
% If you comment the next line, there is an additional error. If someone could
% solve this, help is appreciated. But currently that's not the main issue.
\topmarginpar{}
 \begin{widefigure}[t]
   \color{green}\rule{\linewidth}{2cm}
   \caption{Top placement of figure, odd page.} 
 \end{widefigure}
\botmarginpar{Bottom margin note seems to be fine.}
\lipsum[2-5]
% Now we are on an even page
\topmarginpar{\lipsum[57]}
\botmarginpar{\lipsum[57]}
\lipsum[1-6]
% On an odd page, again
\begin{widefigure}[b]
  \color{green}\rule{\linewidth}{2cm}
  \caption{Bottom placement, odd page}
\end{widefigure}
\lipsum[1-3]
% Now we are on an even page!
\begin{widefigure}[t]
  \color{red}\rule{\linewidth}{2cm}
  \caption[A normal caption]{Top placement, even page. Figure vanished!}
\end{widefigure}
\lipsum
\begin{widefigure}[b]
  \color{red}\rule{\linewidth}{2cm}
  \caption[A normal caption]{Bottom placement, even page. Figure vanished!}
\end{widefigure}
\lipsum[1-12]
\end{document}

Responder1

Modifiquei a solução para incluir as legendas. A macro \gettruepage agora também retorna a localização x,y (para verificar a parte inferior versus superior). Observe que, como ele usa o arquivo aux, são necessárias duas execuções para funcionar corretamente.

\documentclass[paper=a4,11pt]{scrbook}

\usepackage[left=1in,top=1in,headsep=2\baselineskip,
  textwidth=26pc,marginparsep=2pc,marginparwidth=12pc,
  textheight=44\baselineskip,headheight=\baselineskip]{geometry}

% It took me a while to figure out the (x)color here is not merely used for
% providing color...

\usepackage{xcolor}
\usepackage{lipsum}
\usepackage{environ}% create an environment using \BODY

% The \gettruepage marcro returns the page number (as \truepage} in places where \thepage won't,
% such as inside floats or paragraphs split over 2 pages.

\pdfpageheight=\paperheight
\pdfpagewidth=\paperwidth

\newcounter{truepageindex}
\newcount{\truepage}% returns page
\newlength{\truex}% returns distance from left side of text area
\newlength{\truey}% returns distance from top of text area

\newcommand{\newtruepage}[4]% #1 = \thetruepageindex, #2 = \thepage, #3 = \pdflastxpos, #4 = \pdflastypos
{\global\expandafter\edef\csname truepage#1\endcsname{#2}%
 \global\expandafter\edef\csname truex#1\endcsname{#3}%
 \global\expandafter\edef\csname truey#1\endcsname{#4}}

\makeatletter
\newcommand{\gettruepage}{\stepcounter{truepageindex}%
  \pdfsavepos
  \protected@write\@auxout{}{\string\newtruepage{\thetruepageindex}{\thepage}
    {\noexpand\number\pdflastxpos}{\noexpand\number\pdflastypos}}%
  \@ifundefined{truepage\thetruepageindex}%
   {\truepage=\c@page \truex=0pt \truey=0pt}%
   {\truepage=\csname truepage\thetruepageindex\endcsname\relax
    \truex=\csname truex\thetruepageindex\endcsname sp\relax
    \truey=\csname truey\thetruepageindex\endcsname sp\relax
    \truey=\dimexpr \paperheight-\truey-1in-\topmargin-\headheight-\headsep\relax
    \advance\truex by -1in
    \ifodd\truepage\relax\advance\truex by -\oddsidemargin
    \else \advance\truex by -\evensidemargin
    \fi}%
}%
\makeatother

% caption handler
\newif{\iffakecaption}
\newcommand{\fakecaptiontext}{}% reserve name
\makeatletter
\newcommand{\fakecaption}[2][\@empty]% #1 = short caption (optional), #2 = long caption
 {\global\fakecaptiontrue
  \refstepcounter{figure}%
  \ifx#1\@empty\def\fakecaptiontext{#2}%
  \else\def\fakecaptiontext{#1}%
  \fi
  \addcontentsline{lof}{figure}{\string\numberline {\thefigure}{\ignorespaces \fakecaptiontext}}%
  \gdef\fakecaptiontext{#2}}
\makeatother

% widefigure environment

\newsavebox{\widefigurebox}
\newsavebox{\widefigurecaption}
\newlength{\widefiguretest}% compares middle of figure to middle of text area
\newlength{\widefigureup}% baseline to baseline for caption above
\newlength{\widefiguredown}% baseline to baseline for caption below
\newlength{\widefiguresize}% total height of figure plus caption plus extra \marginparpush
\newcount{\widefigurelast}% last page with figure on bottom

\NewEnviron{widefigure}[1][\empty]{%
\figure[#1]%
\let\oldcaption=\caption
\let\caption=\fakecaption
\fakecaptionfalse
\savebox{\widefigurebox}{\begin{minipage}{\dimexpr \textwidth+\marginparsep+\marginparwidth}%
\BODY\end{minipage}}%
\let\caption=\oldcaption
\settoheight{\widefigureup}{\usebox{\widefigurebox}}%
\settodepth{\widefiguredown}{\usebox{\widefigurebox}}%
\widefiguretest=\dimexpr .5\textheight-.5\widefigureup +.5\widefiguredown\relax
\advance\widefigureup by \marginparpush
\iffakecaption
  \savebox{\widefigurecaption}{\parbox{\marginparwidth}%
    {\raggedright\textbf{Figure \thefigure: }\fakecaptiontext}}%
    \settodepth{\widefiguresize}{\usebox{\widefigurecaption}}%
    \advance\widefigureup by \widefiguresize
  \settoheight{\widefiguresize}{\usebox{\widefigurecaption}}%
    \advance\widefiguredown by \widefiguresize
  \advance\widefiguredown by \marginparpush
\fi
\gettruepage
\leavevmode% needed for \rlap and \llap
\ifodd\truepage\relax
  \rlap{\usebox{\widefigurebox}}%
  \iffakecaption
      \ifdim\truey>\widefiguretest\relax
      \rlap{\hspace{\textwidth}\hspace{\marginparsep}%
        \raisebox{\widefigureup}[0pt][0pt]{\usebox{\widefigurecaption}}}%
      \global\widefigurelast=\truepage
    \else
      \rlap{\hspace{\textwidth}\hspace{\marginparsep}%
        \raisebox{-\widefiguredown}[0pt][0pt]{\usebox{\widefigurecaption}}}%
    \fi
  \fi
\else
  \rlap{\hspace{-\marginparwidth}\hspace{-\marginparsep}\usebox{\widefigurebox}}%
  \iffakecaption
      \ifdim\truey>\widefiguretest\relax
      \llap{\raisebox{\widefigureup}[0pt][0pt]{\usebox{\widefigurecaption}}%
        \hspace{\marginparsep}}%
      \global\widefigurelast=\truepage
    \else
      \llap{\raisebox{-\widefiguredown}[0pt][0pt]{\usebox{\widefigurecaption}}%
        \hspace{\marginparsep}}%
    \fi
  \fi
\fi
\advance\widefigureup by \widefiguredown
\global\widefiguresize=\widefigureup
\endfigure}

\begin{document}
%
% If you comment the next line, there is an additional error. If someone could
% solve this, help is appreciated. But currently that's not the main issue.
%\topmarginpar{}
\begin{widefigure}[t]
   \color{green}\rule{\linewidth}{2cm}%  percent needed to prevent blank line at botttom
   \caption{Top placement of figure, odd page.}\label{test}
\end{widefigure}
This is a label test for Figure \ref{test}.
The height of the figure plus caption is \the\widefiguresize.

\lipsum[2-5]
% Now we are on an even page
\lipsum[1-6]
% On an odd page, again
\begin{widefigure}[b]
  \color{green}\rule{\linewidth}{2cm}%
  \caption{Bottom placement, odd page}
\end{widefigure}
\lipsum[1-3]
% Now we are on an even page!
\begin{widefigure}[t]
  \color{red}\rule{\linewidth}{2cm}%
  \caption[A normal caption]{Top placement, even page. Figure vanished!}
\end{widefigure}
\lipsum
\begin{widefigure}[b]
  \color{red}\rule{\linewidth}{2cm}%
  \caption[A normal caption]{Bottom placement, even page. Figure vanished!}
\end{widefigure}
\lipsum[1-3]
\listoffigures
\end{document}

Responder2

Encontrei algo que parece ser uma solução. Embora ainda não esteja completo e ocorram algumas caixas insuficientes, ele faz mais ou menos o que eu quero. O espaçamento também parece não estar correto.

O objetivo desta solução foi que eu percebi (depois de um bom tempo tentando entender o código de David) que \@cflteles \@cflbsão expandidos dependendo do posicionamento do float. David usa isso para definir diferentes versões de \FS@junkquais descartam as caixas desnecessárias e eu uso para definir um comprimento que está \vspace*na parte superior ou inferior da caixa que contém o conteúdo da margem.

Isso funciona até que dois carros alegóricos apareçam na mesma página, já que eu uso apenas um comprimento para armazenar a dimensão vertical do carro alegórico, que é simplesmente substituída pelo segundo carro alegórico. Aqui, uma solução poderá passar por utilizar o respectivo contador (figura/tabela) ou introduzir um novo.

Além disso, eu não uso mais um mecanismo baseado em rótulo vermelho para detectar se a página é par ou ímpar, o que não leva a reclamações sobre rótulos indefinidos (o código de Herbert precisa de rótulos e, portanto, de duas execuções, mas na segunda execução não há avisos).

Aqui está o MWE (novamente, ambos os trechos de código vinculados acima estão incluídos). Adicionei alguns comentários ao código de David (até onde entendi), talvez isso ajude outras pessoas a entendê-lo melhor.

\documentclass[paper=a4,11pt]{scrbook}
\usepackage[T1]{fontenc}
\usepackage[left=1in,top=1in,headsep=2\baselineskip,
  largura de texto = 26 unidades, margem parsep = 2 unidades, largura de margem = 12 unidades,
  textheight=44\baselineskip,headheight=\baselineskip]{geometria}

\usepackage{xcolor,atbegshi,imagem,zref-abspage,ragged2e}
\usepackage{lipsum}
\makeatletter

% Esta mágica foi postada por David Carlisle no TeX-SX:
% http://tex.stackexchange.com/questions/56017/formatting-floats- Differently-based-on-placement


%
% O \@floatswitch-macro espera 4 argumentos que é o conteúdo do float
% que deve ser composta se posicionada na parte superior (#1), inferior (#2), em um único
% página(#3) ou aqui (#4)
%

\def\@floatswitch#1#2#3#4{%
  % (palpite) Estas linhas de alguma forma lidam com os contadores para evitar que o
  % do contador são aumentados em mais de um.
  \def\@elt##1{\global\value{##1}\the\value{##1}\relax}%
  \edef\FS@ckpt{\cl@@ckpt}%
  \deixe\@elt\relaxar
  % A contra-negociação termina aqui, mas é usada por \FS@ckpt
  \hbox para 3sp{%
    \vbox{{\FS@ckpt#1\par}}%
    \vbox{{\FS@ckpt#2\par}}%
    \vbox{{\FS@ckpt#3\par}}%
    \vbox{{\FS@ckpt#4\par}}%
    \hss}\aftergroup\break%
}

%
% Aqui, a caixa correta é selecionada. A macro que faz o trabalho é \FS@junk,
% que deita fora as caixas que não são utilizadas.
%
\def\FS@checkswitch#1{%#
  \ifdim\wd#1=3sp%
    \setbox\z@\box#1%
    \begingroup
      \vmaldade\maxdimen
      \setbox\z@\vsplit\z@ para \textheight
      \setbox\z@\vbox{\unvbox\z@\global\setbox\@ne\lastbox}%
      \setbox\z@\vbox{\unvbox\@ne\unskip\global\setbox\@ne\lastbox}%
      \setbox\z@\hbox{\unhbox\@ne\unskip
        \FS@lixo
        \global\setbox\@ne\lastbox}%
    \endgroup
  \outro
    \global\setbox\@ne\box#1%
  \fi}


% Não tenho ideia sobre a seguinte macro

\def\@comflelt#1{%
  \FS@checkswitch#1%
  \setbox\@tempboxa
     \vbox{\unvbox\@tempboxa\box\@ne\vskip\floatsep}}

% Obviamente (bem, é apenas um palpite), \@cflt é usado quando um float
% está posicionado no topo da página. Depois que percebi isso, meu problema foi
% quase resolvido.

\deixe\salvo@cflt\@cflt

\def\@cflt{%
  \def\FS@lixo{%
    % Como o float está posicionado no topo da página, aumentamos o
    % \tmbparTopSepLength para obter algum espaço no topo da caixa
    % contendo o conteúdo da margem
    \setlength{\tbmparTopSepLength}{\baselineskip}%
    \addtolength{\tbmparTopSepLength}{\captionlength}%
    \addtolength{\tbmparTopSepLength}{\contentlength}%
    \global\tbmparTopSepLength=\tbmparTopSepLength
    \setbox\z@\lastbox\setbox\z@\lastbox\setbox\z@\lastbox}%
  \salvo@cflt}

\deixe\FS@lixo\relaxe

% Este é (outro palpite educado) o comando que é expandido se um float for
% colocado na parte inferior de uma página. O método utilizado é o mesmo acima.
\deixe\salvo@cflb\@cflb

\def\@cflb{%
  \def\FS@lixo{%
    \setlength{\tbmparBottomSepLength}{2\baselineskip}%
    \addtolength{\tbmparBottomSepLength}{\captionlength}%
    \addtolength{\tbmparBottomSepLength}{\contentlength}%
    \global\tbmparBottomSepLength=\tbmparBottomSepLength
    \setbox\z@\lastbox\setbox\z@\lastbox}%
  \salvo@cflb}

% Novamente, não faço ideia.

\def\@helper#1\box\@currbox#2!!{%
  \def\@addtocurcol{%
    #1%
    \deixe\FS@lixo\relaxe
    \FS@checkswitch\@currbox
    \caixa\@ne
    #2}}%

\expandafter\@helper\@addtocurcol!!

% E novamente, não faço ideia.

\def\@wtryfc #1{%
  \global\setbox\@outputbox\vbox{%
    \unvbox\@caixa de saída
    \vskip\@fpsep
  \def\FS@junk{\setbox\z@\lastbox}%
  \FS@checkswitch#1%
  \caixa\@ne}}


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%



%
% Um ambiente para lidar com conteúdo semelhante a figuras
%
\newsavebox{\@ContentCollectorBox}
\newsavebox{\@CaptionCollectorBox}
\newenvironment{@CollectContentAndCaption}[1][\linewidth]{%
  % Este ambiente coleta seu conteúdo na caixa \@ContentCollectorBox,
  % a largura da caixa é dada pelo argumento opcional #1 (o padrão é
  % \espessura da linha)
  % Além disso, redefine a macro \caption e salva seu conteúdo no
  % macros \@CurrCaptionLong e \@CurrCaptionShort.
  %
  % A caixa e as duas macros estão disponíveis globalmente.
  \begingroup
    \begin{lrbox}{0\null\global\setbox\@ContentCollectorBox}%
      \begin{minipágina}{#1}%
        \renewcommand\caption[2][]{%
           \gdef\@CurrCaptionLong{##2}%
           \ifx\\##1\\
             \gdef\@CurrCaptionShort{##2}%
           \outro
             \gdef\@CurrCaptionShort{##1}%
           \fi
        }%
}{%
      \end{minipágina}%
    \end{lrbox}%
  \endgroup
}

%
% Um ambiente que fornece uma figura flutuante que se estende na margem.
%
\newenvironment{widefigure}[1][]{%
  % Armazene o argumento opcional. Se fornecido, adicione colchetes ao redor.
  \ifx\\#1\\
    \def\@rgOne{}%
  \outro
    \def\@rgOne{[#1]}%
  \fi
  %
  % Inicia o ambiente definido acima
  \begin{@CollectContentAndCaption}[\dimexpr\textwidth+\marginparsep+\marginparwidth]%
}{%
  % Acabar com o meio ambiente
  \end{@CollectContentAndCaption}%
  \begin{lrbox}{\@CaptionCollectorBox}%
    \begin{minipágina}{\marginparwidth}%
      \RaggedRight
      \@CurrCaptionLong
    \end{minipágina}
  \end{lrbox}
  % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%
  % Isso faz parte da solução (e cria novos problemas)
  % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%
  % Aqui eu defino globalmente dois comprimentos que contêm a dimensão vertical do
  % legenda e o conteúdo
  \setlength{\captionlength}{\ht\@CaptionCollectorBox}%
  \addtolength{\captionlength}{\dp\@CaptionCollectorBox}%
  \global\captionlength=\captionlength\relaxar
  \setlength{\contentlength}{\ht\@ContentCollectorBox}%
  \addtolength{\contentlength}{\dp\@ContentCollectorBox}%
  \global\contentlength=\contentlength\relaxar
  % Inicie o figure-environment com o argumento opcional de
  % a parte \begin{widefigure}. Eu uso \figure aqui para evitar um
  % \expandafter-orgy para expandir o argumento
  \expandafter\figura\@rgOne
  %
  % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%
  % Isso também é novo. Aqui ocorrem algumas caixas subcheias que ainda precisam ser
  % inspecionado.
  % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%
  % \@floatswitch é um comando de dentro da mágica, acabei de adicionar o @
    \@interruptor flutuante{%
      \ifodd\c@page%
        \rlap{\usebox{\@ContentCollectorBox}}%
        \vbox para 0pt{%
          \rlap{%
            \hspace*{\dimexpr\textwidth+\marginparsep}%
            \usebox{\@CaptionCollectorBox}%
          }%
          \vss
        }
      \outro
        \rlap{\hspace*{\dimexpr-\marginparwidth-\marginparsep}\usebox{\@ContentCollectorBox}}%
        \vbox para 0pt{%
          \llap{%
            \usebox{\@CaptionCollectorBox}%
            \hspace*{\marginparsep}%
          }%
          \vss
        }%
      \fi
    }{%
      %
      % Mais ou menos igual ao acima, mas para posicionamento inferior.
      %
      \ifodd\c@page%
        \vbox para 0pt{%
          \vss
          \rlap{\hspace*{\dimexpr\textwidth+\marginparsep}%
            \usebox{\@CaptionCollectorBox}%
          }%
          \vspace*{\baselineskip}%
        }%
        \rlap{\usebox{\@ContentCollectorBox}}%
      \outro
        \vbox para 0pt{%
          \vss
          \llap{%
            \usebox{\@CaptionCollectorBox}%
            \hspace*{\marginparsep}%
          }%
          \vspace*{\baselineskip}%
        }%
        \rlap{\hspace*{\dimexpr-\marginparwidth-\marginparsep}\usebox{\@ContentCollectorBox}}%
      \fi
    }{%
      % Ainda preciso de algo para posicionamento de página
% \@wide{\wd\@ContentCollectorBox}{\usebox{\@ContentCollectorBox}}%
    }{%
      % Não quero que os números sejam colocados aqui. De qualquer forma, preciso de uma solução para
      % isto também.
% \@wide{\wd\@ContentCollectorBox}{\usebox{\@ContentCollectorBox}}%
    }%
  \endfigure
}


%
% Esta mágica foi postada por Heiko Oberdiek
% http://tex.stackexchange.com/questions/69517/send-and-stack-marginpar-to-the-top-or-the-bottom-of-the-page


\providecommand*{\c@zabspage}{\c@abspage}

% Defino quatro novos comprimentos, que servem para deixar espaço no topo e
% inferior de um nó tbmpar

\newlength\tbmparTopSepLength
\newlength\tbmparBottomSepLength

% e dois que mantêm a dimensão vertical das caixas que contêm a legenda
% e conteúdo de um float
\newlength\captionlength
\newlength\contentlength

% Dois comandos que são expandidos na parte superior e inferior da caixa que contém
% do conteúdo da margem
\newcommand*{\tbmparTopSep}{%
  \vspace*{\tbmparTopSepLength}%
}
\newcommand*{\tbmparBottomSep}{%
  \vspace*{\tbmparBottomSepLength}%
}

% Uma macro para redefinir os comprimentos
\newcommand\restoreSeps{%
  \global\tbmparTopSepLength0pt\relax%\@zp
  \global\tbmparBottomSepLength0pt\relaxar
}
\restoreSeps

% As próximas linhas são o código de Heiko novamente

% * Macros de usuário para configuração
%
% \tbmparItemSep é inserido entre notas marginais
% \tbmparMiddleSep é inserido entre as notas marginais superior e inferior.

\newcommand*{\tbmparItemSep}{%
  \vespaço{1ex menos 0,5ex}%
  \hrule
  \vespaço{1ex menos 0,5ex}%
}

\newcommand*{\tbmparMiddleSep}{%
  \vespaço*{0pt mais 1fil}%
}
% * Mensagens de depuração
%
\newcommand*{\tbmparDebug}[1]{%
  \typeout{[tbmpar] #1}%
}

% * Gerenciamento de etiquetas para lembrar o número absoluto da página
%
% \tbmpar@PageByLabel armazena e carrega o número absoluto da página de
% rótulo e define \tbmpar@page com número absoluto de página ou
% zero se o rótulo ainda não estiver disponível.

\newcount\c@tbmpar@item
\c@tbmpar@item\z@

\newcommand*{\tbmpar@PageByLabel}{%
  \global\advance\c@tbmpar@item\@ne
  \zref@labelbyprops{tbmpar\the\c@tbmpar@item}{abspage}%
  \edef\tbmpar@page{%
    \zref@extractdefault{tbmpar\the\c@tbmpar@item}{abspage}{0}%
  }%
  \zref@refused{tbmpar\the\c@tbmpar@item}%
  \tbmparDebug{Item \c@tbmpar@item\espaço na página \tbmpar@page}%
}

% * Gerenciamento de caixa registradora

\newcount\c@tbmpar@caixa
\c@tbmpar@caixa\z@

\deixe\tbmpar@boxfreelist\@empty

% Obtenha um novo registro de caixa grátis na lista gratuita ou,
% se a lista livre estiver vazia, aloque um novo registrador de caixa.
\newcommand*{\tbmpar@NextBox}[1]{%
  \@próximo#1\tbmpar@boxfreelist{%  
    \tbmparDebug{Caixa reutilizada: #1}%
  }{%
    \global\advance\c@tbmpar@box\@ne
    \expandafter\newbox\csname tbmpar@box\the\c@tbmpar@box\endcsname
    \edef#1{\csname tbmpar@box\the\c@tbmpar@box\endcsname}%
    \tbmparDebug{Nova caixa: #1}%
  }%
}
% Coloque a caixa gratuita na lista gratuita.
\newcommand*{\tbmpar@FreeBox}[1]{%
  \begingroup
    \deixe\@elt\relaxar
    \xdef\tbmpar@boxfreelist{%
      \tbmpar@boxfreelist
      \@elt#1%
    }%
    \tbmparDebug{Caixa grátis: #1}%
  \endgroup
}

\newsavebox{\tbmpar@box}

% Cada marginpar é colocado em uma caixa que é inicializada como
% parbox/minipágina.
\newcommand*{\tbmparBoxSetup}{}
\newcommand{\tbmpar@VBox}[1]{%
  \vcaixa{%
    \color@begingroup
    \hsize\marginparwidth
    \edef\tbmpar@restore@ifminipage{%
      \se@minipágina
        \noexpand\@minipagetrue
      \outro
        \noexpand\@minipagefalse
      \fi
    }%   
    \@parboxrestore
    \@margemparreset
    \tbmparBoxSetup
   #1%
    \tbmpar@restore@ifminipage
    \color@endgroup
  }%
}   

% Macro \tbmpar@marginpar procura a página onde está a nota de margem
% pertence, armazena a nota em uma caixa e anexa a caixa ao  
% registro coletor de notas da página.
% Cada página recebe registros coletores de caixa que coletam
% as notas de topo e um registo que recolhe as notas de fundo.
% O nome do registrador de caixa é \tbmpar@box.
\newcommand{\tbmpar@marginpar}[4]{%
  \ifhmode
    \@bsphack
  \fi
  \tbmpar@PageByLabel
  \ifnum\tbmpar@página>\z@
    \setbox\tbmpar@box\tbmpar@VBox{#4}%
    \@ifundefinido{tbmpar@#1box\tbmpar@page}{%
      \tbmpar@NextBox\tbmpar@currbox
      \global\expandafter\let
          \csname tbmpar@#1box\tbmpar@page\endcsname
          \tbmpar@currbox
      \global\setbox\tbmpar@currbox=\vbox{%
        \unvbox\tbmpar@box
      }%
    }{%
      \tbmparDebug{Usar caixa: \tbmpar@currbox}%
      \expandafter\let\expandafter\tbmpar@currbox
          \csname tbmpar@#1box\tbmpar@page\endcsname
      \global\setbox\tbmpar@currbox\tbmpar@VBox{%   
        \unvbox#3%
        \par
        \begingroup
          \tbmparItemSep
        \endgroup
        \unvbox#2%
      }%
    }%  
  \fi   
  \ifhmode
    \@esphack
  \fi
}

\newcommand*{\topmarginpar}{%
  \tbmpar@marginpar{topo}\tbmpar@currbox\tbmpar@box
}
\newcommand*{\botmarginpar}{%
  \tbmpar@marginpar{bot}\tbmpar@box\tbmpar@currbox
}

% No momento do embarque procuramos os registros do coletor de caixas deste
% página e defina essas caixas na caixa marginpar respeitando  
% \topskip e \maxprofundidade.
\def\@marginparxpos{0pt}\def\@marginparypos{0pt}%
\AtBeginShipout{%
  \AtBeginShipoutUpperLeft{%
    %
    % Adicionei a seguinte definição dos comprimentos correspondentes para poder
    % para distinguir páginas pares e ímpares.
    %
    \ifodd\c@page%
      \def\@marginparxpos{\dimexpr
        1in+\oddsidemargin+\textwidth+\marginparsep\relax}%
      \def\@marginparypos{-\dimexpr
        1in+\topmargin+\headheight+\headsep+\texttheight\relax}%
    \outro
      \def\@marginparxpos{\dimexpr
        1in+\evensidemargin-\marginparsep-\marginparwidth\relax}%
      \def\@marginparypos{-\dimexpr
        1in+\topmargin+\headheight+\headsep+\texttheight\relax}%
    \fi
    \colocar(%
      \@marginparxpos,\@marginparypos%
    ){%
      \begingroup
        \global\let\tbmpar@inuse=N%
        \setbox\tbmpar@box=\tbmpar@VBox{%
          \penalidade-\@M
          %
          % Aqui insiro o espaço no topo
          %
          \tbmparTopSep
          \edef\tbmpar@tmp{tbmpar@topbox\the\value{zabspage}}%
          \@ifundefinido{\tbmpar@tmp}{%
          }{%
            \expandafter\let\expandafter\tbmpar@currbox
                \csname\tbmpar@tmp\endcsname
            \unvbox\tbmpar@currbox
            \tbmpar@FreeBox\tbmpar@currbox
            \global\let\tbmpar@inuse=Y%   
          }%
          \endgraf
          \tbmparMiddleSep
          \edef\tbmpar@tmp{tbmpar@botbox\the\value{zabspage}}%
          \@ifundefinido{\tbmpar@tmp}{%
          }{%
            \expandafter\let\expandafter\tbmpar@currbox
                \csname\tbmpar@tmp\endcsname
            \unvbox\tbmpar@currbox
            \tbmpar@FreeBox\tbmpar@currbox
            \global\let\tbmpar@inuse=Y%   
          }%
          %
          % Aqui eu insiro o espaço na parte inferior
          %
          \tbmparBottomSep
        }%  
        \ifx\tbmpar@inuse Y%
          \splittopskip=\topskip
          \setbox0=\vsplit\tbmpar@caixa para\z@
          \boxmaxprofundidade=\maxprofundidade
          \setbox\tbmpar@box=\vbox to\texttheight{%
            \unvbox\tbmpar@box
          }%
          \caixa\tbmpar@caixa
        \fi
      \endgroup
    }%
  }%  
  % No final, os comprimentos são redefinidos.
  \restoreSeps
}     

\makeatother
\begin{documento}
\lipsum[1]
\topmarginpar{Uma nota de topo mais longa! Uma nota de topo mais longa! Uma nota de topo mais longa! Uma nota de topo mais longa! Uma nota de topo mais longa! }
 \begin{figura larga}[t]
   \color{verde}\rule{\linewidth}{2cm}
   \caption{Uma legenda mais longa no topo! Uma legenda mais longa no topo! Uma legenda mais longa no topo! Uma legenda mais longa no topo!}
 \end{figura larga}
\botmarginpar{A margem inferior está na parte inferior.}
\lipsum[2-5]
% Agora estamos em uma página equilibrada
\botmarginpar{Uma nota de fundo mais longa! Uma nota inferior mais longa! Uma nota inferior mais longa! Uma nota inferior mais longa!}
\begin{figura larga}[b]
  \color{verde}\rule{\linewidth}{2cm}
  \caption{Colocação inferior com legenda mais longa. Colocação inferior com uma legenda mais longa. Colocação inferior com uma legenda mais longa. Colocação inferior com uma legenda mais longa. Colocação inferior com uma legenda mais longa. }
\end{figura larga}
\lipsum[1-3]

\begin{figura larga}[t]
  \color{vermelho}\rule{\linewidth}{1cm}
  \caption{Uma legenda superior, definida primeiro.}
\end{figura larga}
\topmarginpar{Uma nota de topo com distância muito grande.}
\botmarginpar{Uma nota inferior com a mesma distância (neste caso ok).}
\begin{figura larga}[b]
  \color{vermelho}\rule{\linewidth}{2cm}
  \caption{Uma legenda inferior, definida em segundo lugar Esta é mais longa que a superior
    um. Além disso, o conteúdo é mais longo.}
\end{figura larga}
\lipsum
\end{documento}

informação relacionada