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