exercises/solutions/pgfsubpic.tex
author Eugen Sawin <sawine@me73.com>
Sun, 03 Jun 2012 20:15:28 +0200
changeset 11 5112f3e2f3d2
permissions -rw-r--r--
Stuff.
     1 %    pgfsubpic.tex
     2 %    Version 1.1, 25 Dec 2009
     3 
     4 %    Copyright 2009 by David Chiang
     5 
     6 %    This program is free software; you can redistribute it and/or modify
     7 %    it under the terms of the GNU General Public License as published by
     8 %    the Free Software Foundation; either version 2 of the License, or
     9 %    (at your option) any later version.
    10 
    11 %    This program is distributed in the hope that it will be useful,
    12 %    but WITHOUT ANY WARRANTY; without even the implied warranty of
    13 %    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    14 %    GNU General Public License for more details.
    15 
    16 %    You should have received a copy of the GNU General Public License along
    17 %    with this program; if not, write to the Free Software Foundation, Inc.,
    18 %    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
    19 
    20 % New in version 1.1:
    21 % - the ability to save a subpicture in local variables
    22 % - nodes in subpictures are tracked if the subpicture is placed with arbitrary transforms
    23 % - new \pgffitsubpicture macro to transform a subpicture (preserving aspect) to fit in a desired box
    24 
    25 \newdimen\pgf@subpicminx
    26 \newdimen\pgf@subpicminy
    27 \newdimen\pgf@subpicmaxx
    28 \newdimen\pgf@subpicmaxy
    29 
    30 % Special virtual node for current subpicture's bounding box
    31 \expandafter\def\csname pgf@sh@ns@current subpicture\endcsname{rectangle}
    32 \expandafter\def\csname pgf@sh@np@current subpicture\endcsname{%
    33   \def\southwest{\pgfqpoint{\pgf@subpicminx}{\pgf@subpicminy}}%
    34   \def\northeast{\pgfqpoint{\pgf@subpicmaxx}{\pgf@subpicmaxy}}%
    35 }
    36 \expandafter\def\csname pgf@sh@nt@current subpicture\endcsname{{\pgf@pt@aa}{\pgf@pt@ab}{\pgf@pt@ba}{\pgf@pt@bb}{\the\pgf@pt@x}{\the\pgf@pt@y}} % the transformation at invocation time
    37 \expandafter\def\csname pgf@sh@pi@current subpicture\endcsname{\pgfpictureid}
    38 
    39 % Create a pgfpicture inside an hbox for delayed placement
    40 \def\pgfsubpicture{%
    41 \expandafter\global\expandafter\setbox\pgf@hbox=\hbox\bgroup
    42 \pgfinterruptpicture
    43 \pgfpicture
    44 \relax % not sure why. otherwise a curly brace immediately after causes an error
    45 }
    46 
    47 \def\endpgfsubpicture{
    48 \global\pgf@subpicminx=\pgf@picminx
    49 \global\pgf@subpicminy=\pgf@picminy
    50 \global\pgf@subpicmaxx=\pgf@picmaxx
    51 \global\pgf@subpicmaxy=\pgf@picmaxy
    52 \global\edef\subpictureid{\pgfpictureid}%
    53 \pgfsetbaseline{\pgf@picminy}%
    54 \endpgfpicture%
    55 \endpgfinterruptpicture%
    56 \egroup
    57 }
    58 
    59 % Allocate registers for saving a subpicture. #1 is text, not a control sequence.
    60 \def\pgfnewsubpicture#1{%
    61 \expandafter\newbox\csname pgf@subpic@hbox@#1\endcsname
    62 \expandafter\newdimen\csname pgf@subpic@minx@#1\endcsname
    63 \expandafter\newdimen\csname pgf@subpic@miny@#1\endcsname
    64 \expandafter\newdimen\csname pgf@subpic@maxx@#1\endcsname
    65 \expandafter\newdimen\csname pgf@subpic@maxy@#1\endcsname
    66 }
    67 
    68 % saved subpictures are local to the current group
    69 \def\pgfsavesubpicture#1{%
    70 \expandafter\setbox\csname pgf@subpic@hbox@#1\endcsname\box\pgf@hbox
    71 \csname pgf@subpic@minx@#1\endcsname\pgf@subpicminx
    72 \csname pgf@subpic@miny@#1\endcsname\pgf@subpicminy
    73 \csname pgf@subpic@maxx@#1\endcsname\pgf@subpicmaxx
    74 \csname pgf@subpic@maxy@#1\endcsname\pgf@subpicmaxy
    75 \expandafter\edef\csname pgf@subpic@id@#1\endcsname{\subpictureid}%
    76 }
    77 
    78 % place current subpicture into named subpicture
    79 \def\pgfmergesubpicture#1{%
    80 \begin{pgfsubpicture}
    81 % place current subpicture
    82 \pgfplacesubpicture
    83 % override containing picture
    84 \expandafter\xdef\csname pgf@sh@pi@\subpictureid\endcsname{\csname pgf@subpic@id@#1\endcsname}%
    85 % copy contents of #1
    86 \pgfrestoresubpicture{#1}
    87 \pgflowlevelobj{\pgftransformshift{\pgfqpoint{\the\pgf@subpicminx}{\the\pgf@subpicminy}}}{\pgfqbox\pgf@hbox}
    88 \pgfpathrectanglecorners{\pgfqpoint{\the\pgf@subpicminx}{\the\pgf@subpicminy}}{\pgfqpoint{\the\pgf@subpicmaxx}{\the\pgf@subpicmaxy}}%
    89 \pgfusepath{use as bounding box}%
    90 %
    91 \end{pgfsubpicture}
    92 \expandafter\setbox\csname pgf@subpic@hbox@#1\endcsname\box\pgf@hbox
    93 \csname pgf@subpic@minx@#1\endcsname\pgf@subpicminx
    94 \csname pgf@subpic@miny@#1\endcsname\pgf@subpicminy
    95 \csname pgf@subpic@maxx@#1\endcsname\pgf@subpicmaxx
    96 \csname pgf@subpic@maxy@#1\endcsname\pgf@subpicmaxy
    97 % but don't save the new picture id, keep the existing one
    98 }
    99 
   100 \def\pgfrestoresubpicture#1{%
   101 \edef\act{\global\noexpand\setbox\pgf@hbox\noexpand\box\csname pgf@subpic@hbox@#1\endcsname}\act
   102 \expandafter\global\expandafter\pgf@subpicminx\csname pgf@subpic@minx@#1\endcsname
   103 \expandafter\global\expandafter\pgf@subpicminy\csname pgf@subpic@miny@#1\endcsname
   104 \expandafter\global\expandafter\pgf@subpicmaxx\csname pgf@subpic@maxx@#1\endcsname
   105 \expandafter\global\expandafter\pgf@subpicmaxy\csname pgf@subpic@maxy@#1\endcsname
   106 \xdef\subpictureid{\csname pgf@subpic@id@#1\endcsname}%
   107 }
   108 
   109 % Place a previously-created subpicture, lining up its origin with the current origin
   110 \def\pgfplacesubpicture{
   111 \pgfscope
   112 % expand current bounding box to accommodate subpicture
   113 \pgfpathrectanglecorners{\pgfqpoint{\the\pgf@subpicminx}{\the\pgf@subpicminy}}{\pgfqpoint{\the\pgf@subpicmaxx}{\the\pgf@subpicmaxy}}%
   114 \pgfusepath{use as bounding box}%
   115 %
   116 % make the subpicture a node in the containing picture
   117 \expandafter\gdef\csname pgf@sh@ns@\subpictureid\endcsname{rectangle}%
   118 \expandafter\xdef\csname pgf@sh@np@\subpictureid\endcsname{%
   119   \noexpand\def\noexpand\southwest{\noexpand\pgfqpoint{\the\pgf@subpicminx}{\the\pgf@subpicminy}}%
   120   \noexpand\def\noexpand\northeast{\noexpand\pgfqpoint{\the\pgf@subpicmaxx}{\the\pgf@subpicmaxy}}%
   121 }%
   122 \pgfgettransform\pgf@temp
   123 \expandafter\xdef\csname pgf@sh@nt@\subpictureid\endcsname{\pgf@temp}%
   124 \expandafter\xdef\csname pgf@sh@pi@\subpictureid\endcsname{\pgfpictureid}%
   125 %
   126 % align origin of subpicture with origin
   127 \pgftransformshift{\pgfqpoint{\the\pgf@subpicminx}{\the\pgf@subpicminy}}%
   128 \pgfqboxsynced{\pgf@hbox}%
   129 \endpgfscope
   130 }
   131 
   132 % Hook onto existing macro \pgf@shape@interpictureshift.
   133 % This is called whenever we look up an anchor of a node.
   134 % This hook recursively checks to see if the node's picture
   135 % is a subpicture of another, and if so, adjusts its position accordingly.
   136 
   137 % This is slow. It makes drawing trees O(n^2) in the depth of the tree.
   138 % The alternative is to store, for each picture, a list of the nodes
   139 % inside it. But this way doesn't require us to hijack \pgfnode, and
   140 % is robust to re-placement of a subpicture. A compromise would be
   141 % to store, for each picture, a list of the *subpictures* inside it.
   142 
   143 \let\orig@pgf@shape@interpictureshift\pgf@shape@interpictureshift
   144 \def\unwind@subpic#1{%
   145 % is #1 the current picture?
   146 \edef\subpicid{#1}%
   147 \ifx\subpicid\pgfpictureid
   148 % yes, we're done
   149 \else
   150 % does #1 have a parent picture?
   151 \expandafter\ifx\csname pgf@sh@pi@#1\endcsname\relax
   152 % no, the original node was not inside the current picture
   153 \fallback
   154 \else
   155 % yes, apply transform and move up to parent picture
   156 {%
   157   \pgfsettransform{\csname pgf@sh@nt@#1\endcsname}%
   158   \pgf@pos@transform{\pgf@x}{\pgf@y}%
   159   \global\pgf@x=\pgf@x
   160   \global\pgf@y=\pgf@y
   161 }%
   162 \unwind@subpic{\csname pgf@sh@pi@#1\endcsname}%
   163 \fi
   164 \fi
   165 }
   166 \def\pgf@shape@interpictureshift#1{%
   167 \edef\fallback{\pgf@x=\the\pgf@x\pgf@y=\the\pgf@y\noexpand\orig@pgf@shape@interpictureshift{#1}}%
   168 \unwind@subpic{\csname pgf@sh@pi@#1\endcsname}%
   169 }
   170 
   171 % \pgffitsubpicture{sw}{ne}
   172 % Make the subpicture fit in the rectangle from sw to ne, preserving its aspect ratio.
   173 \def\pgffitsubpicture#1#2{%
   174 % current size
   175 \pgfpointdiff{\pgfpointanchor{current subpicture}{south west}}{\pgfpointanchor{current subpicture}{north east}}%
   176 \pgf@xa=\pgf@x \pgf@ya=\pgf@y
   177 % desired size
   178 \pgf@process{\pgfpointdiff{#1}{#2}}%
   179 \pgf@xb=\pgf@x \pgf@yb=\pgf@y
   180 \pgfmathparse{min(\pgf@xb/\pgf@xa,\pgf@yb/\pgf@ya)}%
   181 \pgfmathparse{min(1,\pgfmathresult)}%
   182 \pgftransformscale{\pgfmathresult}%
   183 %
   184 % current position
   185 \pgfpointanchor{current subpicture}{center}%
   186 \pgf@xa=\pgf@x \pgf@ya=\pgf@y
   187 % desired position
   188 % we scaled transform, so apply reverse scaling to argument
   189 \pgfmathparse{1/\pgfmathresult}%
   190 \pgf@process{\pgfpointscale{\pgfmathresult}{\pgfpointlineattime{0.5}{#1}{#2}}}%
   191 \pgf@xb=\pgf@x \pgf@yb=\pgf@y
   192 \pgfpointdiff{\pgfpoint{\pgf@xa}{\pgf@ya}}{\pgfpoint{\pgf@xb}{\pgf@yb}}%
   193 \pgftransformshift{\pgfpoint{\pgf@x}{\pgf@y}}%
   194 }
   195 
   196 % utility functions -- not currently used
   197 
   198 \def\pgfnodedelete#1{%
   199 \expandafter\global\expandafter\let\csname pgf@sh@ns@#1\endcsname\relax
   200 \expandafter\global\expandafter\let\csname pgf@sh@np@#1\endcsname\relax
   201 \expandafter\global\expandafter\let\csname pgf@sh@nt@#1\endcsname\relax
   202 \expandafter\global\expandafter\let\csname pgf@sh@pi@#1\endcsname\relax
   203 \expandafter\global\expandafter\let\csname pgf@sh@ma@#1\endcsname\relax
   204 }
   205 
   206 \def\pgfnodeifexists#1#2#3{%
   207 \expandafter\ifx\csname pgf@sh@ns@#1\endcsname\relax#3\else#2\fi
   208 }
   209