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