El contenido de la figura no aparece en páginas pares después de introducir cambios en la rutina de salida

El contenido de la figura no aparece en páginas pares después de introducir cambios en la rutina de salida

En un documento con márgenes amplios, quiero ofrecer un entorno de figura que se extienda hasta el área de margen. Además, quiero que el texto del título también se coloque en esta área, ya sea encima o debajo de la figura, dependiendo de la ubicación de la figura. Además, esto debería funcionar en páginas pares e impares (usándolas scrbooken mi caso, pero la twosideopción también tendría el mismo efecto).

Lo que me gustaría lograr al final podría ilustrarse mejor con las siguientes figuras (dibujos muy rápidos en Inkscape, no me importan los diferentes tamaños):

ingrese la descripción de la imagen aquíingrese la descripción de la imagen aquíingrese la descripción de la imagen aquí

En primer lugar, me gustaría recopilar las referencias de \cite-macros y mostrarlas en el margen inferior (esto funciona y, por lo tanto, no se muestra en el MWE). Una figura amplia también debe tener su título en el margen. Si aparece una figura ancha en la parte inferior, me gustaría que las referencias estuvieran encima del título de la figura en el margen. Puede ocurrir que también haya algo que se muestre en el margen superior. Como puede ver en las figuras, debería funcionar en twosidemodo.

Para detectar dónde está colocada una figura, utilizo código sugerido por David Carlisle. Para colocar el título en el margen, ya sea en la parte inferior o superior de una página, utilizocódigo sugerido por Heiko Oberdiek. Para probar si la página actual es par o impar, si la uso \ifthispageodddesde KOMA-Scripty para garantizar que la figura se extienda hasta el margen exterior, utilizo el addmargin*entorno desde KOMA-Script.

Además de varias advertencias que elegí abordar más adelante, el enfoque funciona como se esperaba en páginas impares, pero el contenido de mi nuevo widefigureentorno no aparece en páginas pares, aunque queda espacio en el área respectiva.

El problema es que ambas piezas de código mencionadas anteriormente tratan (de alguna manera) con la rutina de salida (la palabracambiosen el título puede no ser completamente correcto), lo cual es un cuadro negro para mí. Solo introduje cambios menores en el código (cambié el nombre de David's \floatswitcha \@floatswitch, \footo \@helpery cambié los argumentos de longitud de la \putmacro que Heiko usó para colocar las notas en el margen).

¿Alguien puede explicar por qué el contenido de las figuras no aparece en páginas pares (o, mejor aún, no hace que aparezcan)?

El MWE es largo debido a los fragmentos de código mencionados anteriormente. Intenté agregar algunos comentarios (en mi código) que ayuden a comprender el enfoque; el código de Heiko también fue 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}

Respuesta1

Modifiqué la solución para incluir los subtítulos. La macro \gettruepage ahora también devuelve la ubicación x,y (para comprobar si hay parte inferior o superior). Tenga en cuenta que, dado que utiliza el archivo auxiliar, se necesitan dos ejecuciones para funcionar correctamente.

\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}

Respuesta2

He encontrado algo que parece ser una solución. Aunque todavía no está completo y aparecen algunos cuadros insuficientes, más o menos hace lo que quiero. El espaciado tampoco parece ser correcto.

El objetivo de esta solución fue que me di cuenta (después de bastante tiempo de intentar comprender el código de David) que \@cfltse \@cflbexpanden según la posición del flotador. David usa esto para definir diferentes versiones de \FS@junklas cuales descarta los cuadros que no son necesarios y yo lo uso para establecer una longitud que se encuentra \vspace*en la parte superior o inferior del cuadro que contiene el contenido del margen.

Esto funciona hasta que aparecen dos flotadores en la misma página, ya que solo uso una longitud para almacenar la dimensión vertical del flotador, que simplemente se sobrescribe con el segundo flotador. En este caso, una solución podría ser hacer uso del respectivo contador (figura/tabla) o introducir uno nuevo.

Además, ya no uso un mecanismo basado en etiquetas rojas para detectar si la página es par o impar, lo que no genera quejas sobre etiquetas no definidas (el código de Herbert necesita etiquetas y, por lo tanto, dos ejecuciones, pero en la segunda ejecución no hay advertencias).

Aquí está el MWE (nuevamente largo, se incluyen ambos fragmentos de código vinculados anteriormente). Agregué algunos comentarios al código de David (hasta donde yo lo entiendo), tal vez eso ayude a otros a entenderlo mejor.

\documentclass[paper=a4,11pt]{scrbook}
\usepackage[T1]{fontenc}
\usepackage[izquierda=1pulg,arriba=1pulg,headsep=2\baselineskip,
  ancho de texto = 26 piezas, margen parsep = 2 piezas, ancho de margen = 12 piezas,
  textheight=44\baselineskip,headheight=\baselineskip]{geometría}

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

% Esta magia ha sido publicada por David Carlisle en TeX-SX:
% http://tex.stackexchange.com/questions/56017/formatting-floats- Differently-based-on-placement


%
% La macro \@floatswitch espera 4 argumentos que son el contenido del flotante
% que debe componerse si se coloca en la parte superior (#1), abajo (#2), en un solo
% página(#3) o aquí (#4)
%

\def\@floatswitch#1#2#3#4{%
  % (adivina) Estas líneas de alguna manera tratan con los contadores para evitar que el
  Los % del contador aumentan en más de uno.
  \def\@elt##1{\global\value{##1}\the\value{##1}\relax}%
  \edef\FS@ckpt{\cl@@ckpt}%
  \let\@elt\relajarse
  % La contracontratación termina aquí, pero la utiliza \FS@ckpt
  \hbox a 3sp{%
    \vbox{{\FS@ckpt#1\par}}%
    \vbox{{\FS@ckpt#2\par}}%
    \vbox{{\FS@ckpt#3\par}}%
    \vbox{{\FS@ckpt#4\par}}%
    \hss}\aftergroup\break%
}

%
% Aquí se selecciona la casilla correcta. La macro que hace el trabajo es \FS@junk,
% que tira las cajas que no se utilizan.
%
\def\FS@controlador#1{%#
  \ifdim\wd#1=3sp %
    \setbox\z@\caja#1%
    \begingroup
      \vmaldad\maxdimen
      \setbox\z@\vsplit\z@ a \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@basura
        \global\setbox\@ne\lastbox}%
    \endgroup
  \demás
    \global\setbox\@ne\box#1%
  \fi}


% No tengo idea sobre la siguiente macro

\def\@comflelt#1{%
  \FS@interruptor de verificación#1%
  \setbox\@tempboxa
     \vbox{\unvbox\@tempboxa\box\@ne\vskip\floatsep}}

% Obviamente (bueno, es sólo una suposición fundamentada), \@cflt se usa cuando un flotante
% se coloca en la parte superior de la página. Una vez que me di cuenta de esto, mi problema fue
% casi resuelto.

\let\saved@cflt\@cflt

\def\@cflt{%
  \def\FS@basura{%
    % Dado que el flotador está ubicado en la parte superior de la página, aumentamos el
    % \tmbparTopSepLength para obtener algo de espacio en la parte superior del cuadro
    % que contiene el contenido del margen
    \setlength{\tbmparTopSepLength}{\baselineskip}%
    \addtolength{\tbmparTopSepLength}{\captionlength}%
    \addtolength{\tbmparTopSepLength}{\contentlength}%
    \global\tbmparTopSepLength=\tbmparTopSepLongitud
    \setbox\z@\lastbox\setbox\z@\lastbox\setbox\z@\lastbox}%
  \guardado@cflt}

\let\FS@basura\relajarse

% Este es (otra suposición informada) el comando que se expande si se coloca un flotante
% colocado al final de una página. El método utilizado es el mismo que el anterior.
\let\saved@cflb\@cflb

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

% Nuevamente, ni idea.

\def\@helper#1\box\@currbox#2!!{%
  \def\@addtocurcol{%
    #1%
    \let\FS@basura\relajarse
    \FS@controlador\@currbox
    \caja\@ne
    #2}}%

\expandafter\@helper\@addtocurcol!!

% Y de nuevo, ni idea.

\def\@wtryfc #1{%
  \global\setbox\@outputbox\vbox{%
    \unvbox\@outputbox
    \vskip\@fpsep
  \def\FS@basura{\setbox\z@\lastbox}%
  \FS@interruptor de verificación#1%
  \caja\@ne}}


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



%
% Un entorno para tratar con contenido parecido a figuras.
%
\newsavebox{\@ContentCollectorBox}
\newsavebox{\@CaptionCollectorBox}
\newenvironment{@CollectContentAndCaption}[1][\linewidth]{%
  % Este entorno recopila su contenido en el cuadro \@ContentCollectorBox,
  % el ancho del cuadro viene dado por el argumento opcional #1 (el valor predeterminado es
  % \ancho de línea)
  % Además, redefine la macro \caption y guarda su contenido en el
  % macros \@CurrCaptionLong y \@CurrCaptionShort.
  %
  % El cuadro y las dos macros están disponibles globalmente.
  \begingroup
    \begin{lrbox}{0\null\global\setbox\@ContentCollectorBox}%
      \begin{minipágina}{#1}%
        \renewcommand\caption[2][]{%
           \gdef\@CurrCaptionLong{##2}%
           \ifx\\##1\\
             \gdef\@CurrCaptionShort{##2}%
           \demás
             \gdef\@CurrCaptionShort{##1}%
           \fi
        }%
{%
      \end{minipágina}%
    \end{lrbox}%
  \endgroup
}

%
% Un entorno que proporciona una figura flotante que se extiende en el margen.
%
\newenvironment{widefigure}[1][]{%
  % Almacena el argumento opcional. Si se proporcionan, agregue corchetes alrededor.
  \ifx\\#1\\
    \def\@rgOne{}%
  \demás
    \def\@rgOne{[#1]}%
  \fi
  %
  % Iniciar el entorno definido anteriormente
  \begin{@CollectContentAndCaption}[\dimexpr\textwidth+\marginparsep+\marginparwidth]%
{%
  % Acabar con el medio ambiente
  \end{@CollectContentAndCaption}%
  \begin{lrbox}{\@CaptionCollectorBox}%
    \begin{minipágina}{\marginparwidth}%
      \RaggedRight
      \@CurrCaptionLong
    \end{minipágina}
  \end{lrbox}
  % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%
  % Esto es parte de la solución (y genera nuevos problemas)
  % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%
  % Aquí establezco globalmente dos longitudes que contienen la dimensión vertical del
  % título y el contenido
  \setlength{\captionlength}{\ht\@CaptionCollectorBox}%
  \addtolength{\captionlength}{\dp\@CaptionCollectorBox}%
  \global\captionlength=\captionlength\relajarse
  \setlength{\contentlength}{\ht\@ContentCollectorBox}%
  \addtolength{\contentlength}{\dp\@ContentCollectorBox}%
  \global\contentlength=\contentlength\relajarse
  % Inicie el entorno de figura con el argumento opcional de
  % la parte \begin{widefigure}. Utilizo \figure aquí para evitar un
  % \expandafter-orgy para ampliar el argumento
  \expandafter\figura\@rgOne
  %
  % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%
  % Esto también es nuevo. En este caso aparecen algunas casillas insuficientemente llenas que aún deben limpiarse.
  % inspeccionado.
  % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%
  % \@floatswitch es un comando dentro de la magia, acabo de agregar @
    \@interruptordeflotación{%
      \ifodd\c@página%
        \rlap{\usebox{\@ContentCollectorBox}}%
        \vbox a 0pt{%
          \lap{%
            \hspace*{\dimexpr\textwidth+\marginparsep}%
            \usebox{\@CaptionCollectorBox}%
          }%
          \vss
        }
      \demás
        \rlap{\hspace*{\dimexpr-\marginparwidth-\marginparsep}\usebox{\@ContentCollectorBox}}%
        \vbox a 0pt{%
          \llap{%
            \usebox{\@CaptionCollectorBox}%
            \hspace*{\marginparsep}%
          }%
          \vss
        }%
      \fi
    {%
      %
      % Más o menos igual que el anterior, pero para la ubicación inferior.
      %
      \ifodd\c@página%
        \vbox a 0pt{%
          \vss
          \rlap{\hspace*{\dimexpr\textwidth+\marginparsep}%
            \usebox{\@CaptionCollectorBox}%
          }%
          \vspace*{\baselineskip}%
        }%
        \rlap{\usebox{\@ContentCollectorBox}}%
      \demás
        \vbox a 0pt{%
          \vss
          \llap{%
            \usebox{\@CaptionCollectorBox}%
            \hspace*{\marginparsep}%
          }%
          \vspace*{\baselineskip}%
        }%
        \rlap{\hspace*{\dimexpr-\marginparwidth-\marginparsep}\usebox{\@ContentCollectorBox}}%
      \fi
    {%
      % Todavía necesito algo para la colocación de la página
% \@wide{\wd\@ContentCollectorBox}{\usebox{\@ContentCollectorBox}}%
    {%
      % No quiero que se coloquen cifras [aquí]aquí. De todos modos necesito una solución
      % esto también.
% \@wide{\wd\@ContentCollectorBox}{\usebox{\@ContentCollectorBox}}%
    }%
  \endfigure
}


%
% Esta magia ha sido publicada por Heiko Oberdiek
% http://tex.stackexchange.com/questions/69517/send-and-stack-marginpar-to-the-top-or-the-bottom-of-the-page


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

% Defino cuatro nuevas longitudes, que sirven para dejar espacio en la parte superior y
% parte inferior de un nodo tbmpar

\newlength\tbmparTopSepLength
\newlength\tbmparBottomSepLength

% y dos que mantienen la dimensión vertical de los cuadros que contienen el título
% y contenido de un flotador
\nueva longitud\captionlength
\nueva longitud\longitud del contenido

% Dos comandos que se expanden en la parte superior e inferior del cuadro que contiene
% del contenido del margen
\newcommand*{\tbmparTopSep}{%
  \vspace*{\tbmparTopSepLength}%
}
\newcommand*{\tbmparBottomSep}{%
  \vspace*{\tbmparBottomSepLength}%
}

% Una macro para restablecer las longitudes.
\newcommand\restoreSeps{%
  \global\tbmparTopSepLength0pt\relax%\@zp
  \global\tbmparBottomSepLength0pt\relajarse
}
\restoreSeps

% Las siguientes líneas son el código de Heiko nuevamente.

% * Macros de usuario para configurar
%
% \tbmparItemSep se inserta entre notas marginales
% \tbmparMiddleSep se inserta entre las notas marginales superior e inferior.

\newcommand*{\tbmparItemSep}{%
  \vespacio{1ex menos .5ex}%
  \hrule
  \vespacio{1ex menos .5ex}%
}

\newcommand*{\tbmparMiddleSep}{%
  \vespacio*{0pt más 1fil}%
}
% * Mensajes de depuración
%
\newcommand*{\tbmparDebug}[1]{%
  \typeout{[tbmpar] #1}%
}

% * Gestión de etiquetas para recordar el número absoluto de página
%
% \tbmpar@PageByLabel almacena y carga el número de página absoluto desde
% etiqueta y define \tbmpar@page con número de página absoluto o
% cero si la etiqueta aún no está disponible.

\nuevocuenta\c@tbmpar@item
\c@tbmpar@artículo\z@

\newcommand*{\tbmpar@PageByLabel}{%
  \global\advance\c@tbmpar@item\@ne
  \zref@labelbyprops{tbmpar\the\c@tbmpar@item}{abspage}%
  \edef\tbmpar@página{%
    \zref@extractdefault{tbmpar\the\c@tbmpar@item}{abspage}{0}%
  }%
  \zref@refused{tbmpar\el\c@tbmpar@item}%
  \tbmparDebug{Artículo \el\c@tbmpar@item\espacio en la página \tbmpar@page}%
}

% * Gestión de registro de cajas

\nuevocuenta\c@tbmpar@box
\c@tbmpar@caja\z@

\let\tbmpar@boxfreelist\@empty

% Obtenga un nuevo registro de caja gratuito de la lista gratuita o,
% si la lista libre está vacía, asigne un nuevo registro de casilla.
\newcommand*{\tbmpar@NextBox}[1]{%
  \@siguiente#1\tbmpar@boxfreelist{%  
    \tbmparDebug{Cuadro reutilizado: #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{Nuevo cuadro: #1}%
  }%
}
% Poner casilla libre en la lista libre.
\newcommand*{\tbmpar@FreeBox}[1]{%
  \begingroup
    \let\@elt\relajarse
    \xdef\tbmpar@boxfreelist{%
      \tbmpar@boxfreelist
      \@elt#1%
    }%
    \tbmparDebug{Caja gratuita: #1}%
  \endgroup
}

\newsavebox{\tbmpar@box}

% Cada margenpar se coloca en un cuadro que se inicializa como
% parbox/minipágina.
\newcommand*{\tbmparBoxSetup}{}
\newcommand{\tbmpar@VBox}[1]{%
  \vbox{%
    \color@begingroup
    \hsize\marginparwidth
    \edef\tbmpar@restore@ifminipage{%
      \si@minipágina
        \noexpand\@minipagetrue
      \demás
        \noexpand\@minipagefalse
      \fi
    }%   
    \@parboxrestore
    \@marginparreset
    \tbmparBoxSetup
   #1%
    \tbmpar@restore@ifminipágina
    \color@endgroup
  }%
}   

% Macro \tbmpar@marginpar busca la página donde está la nota al margen
% pertenece, almacena la nota en un cuadro y agrega el cuadro al  
% registro recolector de notas de la página.
% A cada página se le asigna una caja de registros recopiladores que recopilan
% las notas altas y un registro que recoge las notas bajas.
% El nombre del registro de caja es \tbmpar@box.
\newcommand{\tbmpar@marginpar}[4]{%
  \ifhmodo
    \@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@página\endcsname
          \tbmpar@currbox
      \global\setbox\tbmpar@currbox=\vbox{%
        \unvbox\tbmpar@caja
      }%
    {%
      \tbmparDebug{Usar cuadro: \tbmpar@currbox}%
      \expandafter\let\expandafter\tbmpar@currbox
          \csname tbmpar@#1box\tbmpar@página\endcsname
      \global\setbox\tbmpar@currbox\tbmpar@VBox{%   
        \unvbox#3%
        \par
        \begingroup
          \tbmparItemSep
        \endgroup
        \unvbox#2%
      }%
    }%  
  \fi   
  \ifhmodo
    \@esphack
  \fi
}

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

% En el momento del envío buscamos los registros del coleccionista de cajas de este
% página y configure estos cuadros en el cuadro marginpar respetando  
% \topskip y \max Depth.
\def\@marginparxpos{0pt}\def\@marginparypos{0pt}%
\AlBeginShipout{%
  \AtBeginShipoutUpperLeft{%
    %
    % Agregué la siguiente definición de las longitudes correspondientes para poder
    % para distinguir páginas pares e impares.
    %
    \ifodd\c@página%
      \def\@marginparxpos{\dimexpr
        1in+\oddsidemargin+\textwidth+\marginparsep\relax}%
      \def\@marginparypos{-\dimexpr
        1in+\topmargin+\headheight+\headsep+\textheight\relax}%
    \demás
      \def\@marginparxpos{\dimexpr
        1in+\evensidemargin-\marginparsep-\marginparwidth\relax}%
      \def\@marginparypos{-\dimexpr
        1in+\topmargin+\headheight+\headsep+\textheight\relax}%
    \fi
    \poner(%
      \@marginparxpos,\@marginparypos%
    ){%
      \begingroup
        \global\let\tbmpar@inuse=N%
        \setbox\tbmpar@box=\tbmpar@VBox{%
          \penalización-\@M
          %
          % Aquí inserto el espacio en la parte superior.
          %
          \tbmparTopSep
          \edef\tbmpar@tmp{tbmpar@topbox\el\valor{zabspage}}%
          \@ifundefinido{\tbmpar@tmp}{%
          {%
            \expandafter\let\expandafter\tbmpar@currbox
                \csnombre\tbmpar@tmp\endcsnombre
            \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
                \csnombre\tbmpar@tmp\endcsnombre
            \unvbox\tbmpar@currbox
            \tbmpar@FreeBox\tbmpar@currbox
            \global\let\tbmpar@inuse=Y%   
          }%
          %
          % Aquí inserto el espacio en la parte inferior.
          %
          \tbmparBottomSep
        }%  
        \ifx\tbmpar@inuse Y%
          \splittopskip=\topskip
          \setbox0=\vsplit\tbmpar@caja a\z@
          \boxmaxprofundidad=\maxprofundidad
          \setbox\tbmpar@box=\vbox a\textheight{%
            \unvbox\tbmpar@caja
          }%
          \caja\tbmpar@caja
        \fi
      \endgroup
    }%
  }%  
  % Al final se restablecen las longitudes.
  \restoreSeps
}     

\makeatother
\begin{documento}
\lipsum[1]
\topmarginpar{¡Una nota alta más larga! ¡Una nota alta más larga! ¡Una nota alta más larga! ¡Una nota alta más larga! ¡Una nota alta más larga! }
 \begin{widefigure}[t]
   \color{verde}\rule{\linewidth}{2cm}
   \caption{¡Un título más largo en la parte superior! ¡Un título más largo en la parte superior! ¡Un título más largo en la parte superior! ¡Un título más largo en la parte superior!}
 \end{widefigure}
\botmarginpar{El margen inferior está en la parte inferior.}
\lipsum[2-5]
% Ahora estamos en una página par
\botmarginpar{¡Una nota de fondo más larga! ¡Una nota de fondo más larga! ¡Una nota de fondo más larga! ¡Una nota de fondo más larga!}
\begin{widefigure}[b]
  \color{verde}\rule{\linewidth}{2cm}
  \caption{Ubicación inferior con un título más largo. Ubicación inferior con un título más largo. Ubicación inferior con un título más largo. Ubicación inferior con un título más largo. Ubicación inferior con un título más largo. }
\end{widefigure}
\lipsum[1-3]

\begin{widefigure}[t]
  \color{rojo}\rule{\linewidth}{1cm}
  \caption{Un título superior, definido primero.}
\end{widefigure}
\topmarginpar{Una nota superior con una distancia demasiado grande.}
\botmarginpar{Una nota inferior con la misma distancia (en este caso está bien).}
\begin{widefigure}[b]
  \color{rojo}\rule{\linewidth}{2cm}
  \caption{Un título inferior, definido en segundo lugar Este es más largo que el superior
    uno. Además el contenido es más largo.}
\end{widefigure}
\lipsum
\end{documento}

información relacionada