From ff587f620cc7c6d0068c33b27a8e554bce2b08fe Mon Sep 17 00:00:00 2001 From: Karl Berry Date: Thu, 3 Aug 2017 21:07:30 +0000 Subject: spectralsequences (3aug17) git-svn-id: svn://tug.org/texlive/trunk@44942 c570f23f-e606-0410-a88d-b1316a301751 --- .../latex/spectralsequences/sseqdrawing.code.tex | 924 +++++++++++++++------ 1 file changed, 691 insertions(+), 233 deletions(-) (limited to 'Master/texmf-dist/tex/latex/spectralsequences/sseqdrawing.code.tex') diff --git a/Master/texmf-dist/tex/latex/spectralsequences/sseqdrawing.code.tex b/Master/texmf-dist/tex/latex/spectralsequences/sseqdrawing.code.tex index 098e73f9110..c8bba066b23 100644 --- a/Master/texmf-dist/tex/latex/spectralsequences/sseqdrawing.code.tex +++ b/Master/texmf-dist/tex/latex/spectralsequences/sseqdrawing.code.tex @@ -1,8 +1,8 @@ %% -%% Package: spectralsequences.sty version 1.0 +%% Package: spectralsequences v1.1.0 %% Author: Hood Chatham %% Email: hood@mit.edu -%% Date: 2017-06-18 +%% Date: 2017-08-02 %% License: Latex Project Public License %% %% File: sseqdrawing.code.tex @@ -14,165 +14,314 @@ %% the axes ticks was taking about 1/3 of the compile time (a little under 1s out of a 3.2) %% +% Only for integer valued coordinates... +\def\sseq@qpointxy#1#2{\pgfqpointxy{\numexpr#1+\sseq@xoffset\relax}{\numexpr#2+\sseq@yoffset\relax}} +\def\sseq@transform@xymirror{ + \pgfsetxvec{\pgfqpoint{1cm}{0cm}} + \pgfsetyvec{\pgfqpoint{0cm}{1cm}} + \pgftransformcm{0}{1}{1}{0}{\pgfpointxy{\sseq@xoffset*\sseq@xscale }{\sseq@yoffset*\sseq@yscale}} % Reflect x and y axes, + \pgftransformshift{\pgfpointxy{-\sseq@xoffset*\sseq@yscale}{-\sseq@yoffset*\sseq@xscale}} % but we need to conjugate by a shift of (xoffset,yoffset) + \pgfsetyvec{\pgfqpoint{0cm}{\sseq@xscale cm}} + \pgfsetxvec{\pgfqpoint{\sseq@yscale cm}{0cm}} +} + + +\def\sseq@setlayoutparameter#1#2{\@xp\let\csname sseq@#1\@xp\endcsname\csname sseq@#1@#2\endcsname} +\def\sseq@setlayoutparameters{ + \sseq@setlayoutparameter{yaxisorigin}{x\sseq@xaxistype} + \sseq@setlayoutparameter{drawyaxis}{x\sseq@xaxistype} + \sseq@setlayoutparameter{yaxisstartoffset}{x\sseq@xaxistype} + \sseq@setlayoutparameter{yaxisendoffset}{x\sseq@xaxistype} + \sseq@setlayoutparameter{bottomgridpadding}{x\sseq@xaxistype} + \sseq@setlayoutparameter{topgridpadding}{x\sseq@xaxistype} + \sseq@setlayoutparameter{bottomclippadding}{x\sseq@xaxistype} + \sseq@setlayoutparameter{topclippadding}{x\sseq@xaxistype} + \sseq@setlayoutparameter{xlabelposition}{x\sseq@xaxistype} +% + \sseq@setlayoutparameter{xaxisorigin}{y\sseq@yaxistype} + \sseq@setlayoutparameter{drawxaxis}{y\sseq@xaxistype} + \sseq@setlayoutparameter{xaxisstartoffset}{y\sseq@yaxistype} + \sseq@setlayoutparameter{xaxisendoffset}{y\sseq@yaxistype} + \sseq@setlayoutparameter{leftgridpadding}{y\sseq@yaxistype} + \sseq@setlayoutparameter{rightgridpadding}{y\sseq@yaxistype} + \sseq@setlayoutparameter{leftclippadding}{y\sseq@yaxistype} + \sseq@setlayoutparameter{rightclippadding}{y\sseq@yaxistype} + \sseq@setlayoutparameter{ylabelposition}{y\sseq@xaxistype} +} + +% The appropriate one of these is chosen by the "axis type" keys in sseqkeys. + +% Used to determine axis and ticks placement +\def\sseq@xaxisorigin@yborder{\sseq@xmin} +\def\sseq@xaxisorigin@yframe{\sseq@xmin} +\def\sseq@xaxisorigin@ycenter{\sseq@xaxisorigin@center@} +\def\sseq@yaxisorigin@xborder{\sseq@ymin} +\def\sseq@yaxisorigin@xframe{\sseq@ymin} +\def\sseq@yaxisorigin@xcenter{\sseq@yaxisorigin@center@} + +% Used to determine clipping and grid boundaries +\def\sseq@leftgridpadding@yborder{\dimexpr\sseq@yaxisgap-\sseq@yclip@axisgap\relax} +\def\sseq@rightgridpadding@yborder{\sseq@xaxis@end@extend} +\def\sseq@leftgridpadding@ycenter{\sseq@xaxis@start@extend} +\def\sseq@rightgridpadding@ycenter{\sseq@xaxis@end@extend} +\def\sseq@leftgridpadding@yframe{\dimexpr\sseq@yaxisgap-\sseq@yclip@axisgap\relax} +\def\sseq@rightgridpadding@yframe{5cm} % Just make it big enough to push off the end of the clip +\def\sseq@leftgridpadding@ynone{\sseq@yaxisgap} +\def\sseq@rightgridpadding@ynone{\sseq@yaxisgap} + + +\def\sseq@bottomgridpadding@xborder{\dimexpr\sseq@xaxisgap-\sseq@xclip@axisgap\relax} +\def\sseq@topgridpadding@xborder{\sseq@yaxis@end@extend} +\def\sseq@bottomgridpadding@xcenter{\sseq@yaxis@start@extend} +\def\sseq@topgridpadding@xcenter{\sseq@yaxis@end@extend} +\def\sseq@bottomgridpadding@xframe{\dimexpr\sseq@xaxisgap-\sseq@xclip@axisgap\relax} +\def\sseq@topgridpadding@xframe{5cm} +\def\sseq@bottomgridpadding@xnone{\sseqxaxisgap} +\def\sseq@topgridpadding@xnone{\sseq@xaxisgap} + +\def\sseq@leftclippadding@yborder{\dimexpr-\sseq@yaxisgap+\sseq@yclip@axisgap\relax} +\def\sseq@rightclippadding@yborder{\dimexpr\sseq@xaxis@end@extend+\sseq@clip@padding@right\relax} +\def\sseq@leftclippadding@ycenter{\dimexpr-\sseq@xaxis@start@extend-\sseq@clip@padding@left\relax} +\def\sseq@rightclippadding@ycenter{\dimexpr\sseq@xaxis@end@extend+\sseq@clip@padding@right\relax} +\def\sseq@leftclippadding@yframe{\dimexpr-\sseq@yaxisgap+\sseq@yclip@axisgap\relax} +\def\sseq@rightclippadding@yframe{\dimexpr\sseq@yaxisgap-\sseq@yclip@axisgap\relax} +\def\sseq@leftclippadding@ynone{\dimexpr-\sseq@yaxisgap-\sseq@clip@padding@left\relax} +\def\sseq@rightclippadding@ynone{\dimexpr\sseq@yaxisgap+\sseq@clip@padding@right\relax} + +\def\sseq@bottomclippadding@xborder{\dimexpr-\sseq@xaxisgap+\sseq@xclip@axisgap\relax} +\def\sseq@topclippadding@xborder{\dimexpr\sseq@yaxis@end@extend+\sseq@clip@padding@top\relax} +\def\sseq@bottomclippadding@xcenter{\dimexpr-\sseq@yaxis@start@extend-\sseq@clip@padding@bottom\relax} +\def\sseq@topclippadding@xcenter{\dimexpr\sseq@yaxis@end@extend+\sseq@clip@padding@top\relax} +\def\sseq@bottomclippadding@xframe{\dimexpr-\sseq@xaxisgap+\sseq@xclip@axisgap\relax} +\def\sseq@topclippadding@xframe{\dimexpr\sseq@xaxisgap-\sseq@xclip@axisgap\relax} +\def\sseq@bottomclippadding@xnone{\dimexpr-\sseq@xaxisgap-\sseq@clip@padding@bottom\relax} +\def\sseq@topclippadding@xnone{\dimexpr\sseq@xaxisgap+\sseq@clip@padding@top\relax} + +% Used to figure out how much further beyond (min -- max) to draw axes +\def\sseq@xaxisstartoffset@yborder{\dimexpr\sseq@xaxis@tail+\sseq@yaxisgap\relax} +\def\sseq@xaxisendoffset@yborder{\sseq@xaxis@end@extend} +\def\sseq@xaxisstartoffset@ycenter{\sseq@xaxis@start@extend} +\def\sseq@xaxisendoffset@ycenter{\sseq@xaxis@end@extend} +\def\sseq@xaxisstartoffset@yframe{\sseq@yaxisgap} +\def\sseq@xaxisendoffset@yframe{\sseq@yaxisgap} +\def\sseq@yaxisstartoffset@xborder{\dimexpr\sseq@yaxis@tail+\sseq@xaxisgap\relax} +\def\sseq@yaxisendoffset@xborder{\sseq@yaxis@end@extend} +\def\sseq@yaxisstartoffset@xcenter{\sseq@yaxis@start@extend} +\def\sseq@yaxisendoffset@xcenter{\sseq@yaxis@end@extend} +\def\sseq@yaxisstartoffset@xframe{\sseq@xaxisgap} +\def\sseq@yaxisendoffset@xframe{\sseq@xaxisgap} + +\def\sseq@xlabelposition@xborder{(0,-\sseq@xaxisstartoffset)} +\def\sseq@xlabelposition@xcenter{(-\sseq@yaxisgap,-\sseq@xaxisstartoffset-5pt)} +\def\sseq@xlabelposition@xframe{(0,-\sseq@xaxisgap-\sseq@xlabelgap-10pt)} +\def\sseq@xlabelposition@xnone{(0,0)} + +\def\sseq@ylabelposition@yborder{(0,\sseq@yaxisstartoffset)} +\def\sseq@ylabelposition@ycenter{(-\sseq@xaxisgap,\sseq@yaxisstartoffset+5pt)} +\def\sseq@ylabelposition@yframe{(0,\sseq@yaxisgap+\sseq@ylabelgap+10pt)} +\def\sseq@ylabelposition@ynone{(0,0)} %%% %%% Draw axes and clip %%% \def\sseq@handlexaxis{ - \ifsseq@drawxaxis - \bgroup - \ifsseq@borderxaxis\else - \let\sseq@ymin\sseq@yaxisorigin % Warning: this is a stupid, lazy hack. - \fi - \sseq@drawxaxis - \ifsseq@drawxaxisticks - \sseq@drawxticks - \fi - \egroup + \bgroup + \sseq@drawxaxis + \ifsseq@drawxaxisticks + \sseq@drawxticks \fi + \egroup } \def\sseq@handleyaxis{ - \ifsseq@drawyaxis - \bgroup - \ifsseq@borderyaxis\else - \let\sseq@xmin\sseq@xaxisorigin % Warning: this is a stupid, lazy hack. - \fi - \sseq@drawyaxis - \ifsseq@drawyaxisticks - \sseq@drawyticks - \fi - \egroup + \bgroup + \sseq@drawyaxis + \ifsseq@drawyaxisticks + \sseq@drawyticks \fi + \egroup } -\def\sseq@drawxaxis{ - \bgroup - \pgftransformreset - \sseq@globaldetonetransform - % + +% Draws an x axis. Use with \sseq@transform@xymirror to draw y axis. +% #1 -- horizontal start offset +% #2 -- horizontal end offset +% #3 -- vertical offset +% #4 -- start value +% #5 -- end value +% #6 -- vertical value +\def\sseq@drawaxis@generic#1#2#3#4#5#6{ \bgroup - \pgftransformxshift{\sseq@xaxis@end@extend}\pgftransformyshift{-\sseq@xaxisgap} - \sseq@globalscaletransform - \pgfpathmoveto{\pgfpoint{\sseq@xmax cm}{\sseq@ymin cm}} + \pgftransformshift{\pgfqpoint{#2}{#3}} + \pgfpathmoveto{\sseq@qpointxy{#5}{#6}} \egroup +% \bgroup - \pgftransformxshift{-\sseq@yaxisgap} - %\pgftransformxshift{-\sseq@ylabelgap} - \pgftransformxshift{-\sseq@xaxis@start@extend} - \pgftransformyshift{-\sseq@xaxisgap} - \sseq@globalscaletransform - \pgfpathlineto{\pgfpoint{\sseq@xmin cm}{\sseq@ymin cm}} - \egroup + \pgftransformshift{\pgfqpoint{#1}{#3}} + \pgfpathlineto{\sseq@qpointxy{#4}{#6}} \egroup +} + +\def\sseq@drawxaxis@ynone{ + \sseq@drawxaxisticksfalse +} +\def\sseq@drawyaxis@xnone{ + \sseq@drawyaxisticksfalse +} + +\def\sseq@drawxaxis@yborder{ + \sseq@drawaxis@generic{-\sseq@xaxisstartoffset}{\sseq@xaxisendoffset}{-\sseq@xaxisgap}{\sseq@xmin}{\sseq@xmax}{\sseq@yaxisorigin} \pgfusepath{stroke} } -\def\sseq@drawyaxis{ - \bgroup - \pgftransformreset - \sseq@globaldetonetransform +\let\sseq@drawxaxis@ycenter\sseq@drawxaxis@yborder + +\def\sseq@drawxaxis@yframe{ + \sseq@drawaxis@generic{-\sseq@xaxisstartoffset}{\sseq@xaxisendoffset}{-\sseq@xaxisgap}{\sseq@xmin}{\sseq@xmax}{\sseq@ymin} + \sseq@drawaxis@generic{-\sseq@xaxisstartoffset}{\sseq@xaxisendoffset}{ \sseq@xaxisgap}{\sseq@xmin}{\sseq@xmax}{\sseq@ymax} + \pgfusepath{stroke} +} +\def\sseq@drawyaxis@xborder{ \bgroup - \pgftransformyshift{\sseq@yaxis@end@extend}\pgftransformxshift{-\sseq@yaxisgap} - \sseq@globalscaletransform - \pgfpathmoveto{\pgfpoint{\sseq@xmin cm}{\sseq@ymax cm}} + \sseq@transform@xymirror + \sseq@drawaxis@generic{-\sseq@yaxisstartoffset}{\sseq@yaxisendoffset}{-\sseq@yaxisgap}{\sseq@ymin}{\sseq@ymax}{\sseq@xaxisorigin} + \pgfusepath{stroke}% \egroup +} +\let\sseq@drawyaxis@xcenter\sseq@drawyaxis@xborder +\def\sseq@drawyaxis@xframe{ \bgroup - \pgftransformyshift{-\sseq@xaxisgap} - %\pgftransformyshift{-\sseq@xlabelgap} - \pgftransformyshift{-\sseq@yaxis@start@extend} - \pgftransformxshift{-\sseq@yaxisgap} - \sseq@globalscaletransform - \pgfpathlineto{\pgfpoint{\sseq@xmin cm}{\sseq@ymin cm}} - \egroup - \egroup + \sseq@transform@xymirror + \sseq@drawaxis@generic{-\sseq@yaxisstartoffset}{\sseq@yaxisendoffset}{-\sseq@yaxisgap}{\sseq@ymin}{\sseq@ymax}{\sseq@xmin} + \sseq@drawaxis@generic{-\sseq@yaxisstartoffset}{\sseq@yaxisendoffset}{ \sseq@yaxisgap}{\sseq@ymin}{\sseq@ymax}{\sseq@xmax} \pgfusepath{stroke}% + \egroup } -\def\sseq@drawxticks{ - \sseq@tempy=\sseq@ymin\relax - \sseq@tempx=\sseq@xmax\relax - \advance\sseq@tempx\@ne\relax - \edef\sseq@temp{\the\sseq@tempx}% - \sseq@tempx=\sseq@xmin\relax + +\ExplSyntaxOn +\def\sseq@intdivceiling#1#2{% + \ifnum#1>\z@ % \int_div_truncate:nn rounds towards 0. We want \int_div_ceiling + \int_div_truncate:nn{#1+#2-1}{#2} % if positive, use ceil(p/q)=floor((p+q-1)/q) for p,q integers + \else + \int_div_truncate:nn{#1}{#2} % if we are negative, towards 0 is ceiling + \fi +} +\def\sseq@intdivfloor#1#2{% + \ifnum#1<\z@ % \int_div_truncate:nn rounds towards 0. We want \int_div_floor + \int_div_truncate:nn{#1-#2+1}{#2} % if we are negative, use floor(p/q) = ceil(p-q+1/q) for p,q integers + \else + \int_div_truncate:nn{#1}{#2} % if positive, towards 0 is floor + \fi +} +\ExplSyntaxOff + +% #1 -- xmin +% #2 -- xmax +% #3 -- step +% #4 -- offset +% #5 -- ymin +% #6 -- xaxisgap +% #7 -- code +\def\sseq@tickloop@generic#1#2#3#4#5#6#7{ + \sseq@tempx=\numexpr % min + \sseq@intdivceiling{#1}{#3} * #3 + - + \sseq@intdivceiling{#4}{#3} * #3 + #4 + \relax + \ifnum\sseq@tempx<#1\relax + \advance\sseq@tempx#3\relax + \fi + \sseq@tempxb=\numexpr#2+1\relax % max \loop \bgroup - \sseq@eval{\@nx\pgftransformshift{\@nx\pgfpoint{\the\sseq@tempx cm}{\the\sseq@tempy cm}}} - \pgftransformresetnontranslations - \sseq@globaldetonetransform - \pgftransformyshift{-\sseq@xlabelgap}\pgftransformyshift{-\sseq@xaxisgap} - \pgftransformresetnontranslations - \ifsseq@rotatelabels\sseq@globalrotatetransform\fi + \pgftransformshift{\sseq@qpointxy{\sseq@tempx}{#5}}% + \pgftransformshift{\pgfqpoint{0pt}{#6}} + #7 + \egroup + \advance\sseq@tempx#3\relax + \ifnum\sseq@tempx<\sseq@tempxb\repeat +} + + +\def\sseq@drawxticks{% + \sseq@tickloop@generic{\sseq@xmin}{\sseq@xmax}{\sseq@xtickstep}{\sseq@xtickstepoffset}{\sseq@yaxisorigin}{-\sseq@xaxisgap}{ \sseq@xtickstyle \tikz@options - \pgftext{\hbox{$\sseq@xtickfn{\the\sseq@tempx}$}} - \egroup - \advance\sseq@tempx\sseq@xtickstep\relax - \ifnum\sseq@tempx<\sseq@temp\repeat -} -\def\sseq@drawyticks{ - \sseq@tempx=\sseq@xmin\relax - \sseq@tempy=\sseq@ymax\relax - \advance\sseq@tempy\@ne\relax - \edef\sseq@tempmax{\the\sseq@tempy} - \sseq@tempy=\sseq@ymin\relax - \loop - \bgroup - \sseq@eval{\@nx\pgftransformshift{\@nx\pgfpoint{\the\sseq@tempx cm}{\the\sseq@tempy cm}}} - \pgftransformresetnontranslations - \sseq@globaldetonetransform - \pgftransformxshift{-\sseq@ylabelgap}\pgftransformxshift{-\sseq@yaxisgap} - \pgftransformresetnontranslations - \ifsseq@rotatelabels\sseq@globalrotatetransform\fi + \pgftransformshift{\pgfqpoint{0pt}{-\sseq@ylabelgap}} + \pgftext{\hbox{$\sseq@xtickfn{\the\sseq@tempx}$}}% + } + \ifnum\sseq@xmajortickstep>\z@ + \sseq@tickloop@generic{\sseq@xmin}{\sseq@xmax}{\sseq@xmajortickstep}{\sseq@xtickstepoffset}{\sseq@yaxisorigin}{-\sseq@xaxisgap}{ + \pgfpathmoveto{\pgfpointorigin} + \pgfpathlineto{\pgfpoint{0}{-0.4*\sseq@xaxisgap}} + } + \fi + \ifnum\sseq@xminortickstep>\z@ + \sseq@tickloop@generic{\sseq@xmin}{\sseq@xmax}{\sseq@xminortickstep}{\sseq@xtickstepoffset}{\sseq@yaxisorigin}{-\sseq@xaxisgap}{ + \pgfpathmoveto{\pgfpointorigin} + \pgfpathlineto{\pgfpoint{0}{-0.2*\sseq@xaxisgap}} + } + \fi + \pgfusepath{stroke} +} +\def\sseq@drawyticks{% + \sseq@transform@xymirror + \sseq@tickloop@generic{\sseq@ymin}{\sseq@ymax}{\sseq@ytickstep}{\sseq@ytickstepoffset}{\sseq@xaxisorigin}{-\sseq@yaxisgap}{ \sseq@ytickstyle \tikz@options - \pgftext{\hbox{$\sseq@ytickfn{\the\sseq@tempy}$}} - \egroup - \advance\sseq@tempy\sseq@ytickstep\relax - \ifnum\sseq@tempy<\sseq@tempmax\repeat + \pgftransformshift{\pgfqpoint{0pt}{-\sseq@ylabelgap}} + \pgftransformresetnontranslations + \pgftext{\hbox{$\sseq@ytickfn{\the\sseq@tempx}$}}% + } + \ifnum\sseq@ymajortickstep>\z@ + \sseq@tickloop@generic{\sseq@ymin}{\sseq@ymax}{\sseq@ymajortickstep}{\sseq@ytickstepoffset}{\sseq@xaxisorigin}{-\sseq@yaxisgap}{ + \pgfpathmoveto{\pgfpointorigin} + \pgfpathlineto{\pgfpoint{0}{-0.4*\sseq@yaxisgap}} + } + \fi + \ifnum\sseq@yminortickstep>\z@ + \sseq@tickloop@generic{\sseq@ymin}{\sseq@ymax}{\sseq@yminortickstep}{\sseq@ytickstepoffset}{\sseq@xaxisorigin}{-\sseq@yaxisgap}{ + \pgfpathmoveto{\pgfpointorigin} + \pgfpathlineto{\pgfpoint{0}{-0.2*\sseq@yaxisgap}} + } + \fi + \pgfusepath{stroke} } + + \def\sseq@setupclip{ %\clip(\sseq@xmin-0.4,\sseq@ymin-0.4) rectangle (\sseq@xmax+0.5,\sseq@ymax+0.5);% \ifsseq@clip \ifx\sseq@customclip\pgfutil@empty \bgroup - \pgftransformreset - \sseq@globaldetonetransform - \ifsseq@borderyaxis - \def\xmin{\pgftransformxshift{-\sseq@yaxisgap}\pgftransformxshift{\sseq@yclip@axisgap}} - \else - \def\xmin{\pgftransformxshift{-\sseq@xaxis@start@extend}\pgftransformxshift{-\sseq@clip@padding@left}} - \fi - \ifsseq@borderxaxis - \def\ymin{\pgftransformyshift{-\sseq@xaxisgap}\pgftransformyshift{\sseq@xclip@axisgap}} - \else - \def\ymin{\pgftransformyshift{-\sseq@yaxis@start@extend}\pgftransformyshift{-\sseq@clip@padding@bottom}} - \fi - \def\xmax{\pgftransformxshift{\sseq@xaxis@end@extend}\pgftransformxshift{\sseq@clip@padding@right}} - \def\ymax{\pgftransformyshift{\sseq@yaxis@end@extend}\pgftransformyshift{\sseq@clip@padding@top}} + \def\xmin{\pgftransformshift{\pgfqpoint{\sseq@leftclippadding}{0pt}}} + \def\ymin{\pgftransformshift{\pgfqpoint{0pt}{\sseq@bottomclippadding}}} + \def\xmax{\pgftransformshift{\pgfqpoint{\sseq@rightclippadding}{0pt}}} + \def\ymax{\pgftransformshift{\pgfqpoint{0pt}{\sseq@topclippadding}}} \bgroup - \xmin\ymin\sseq@globalscaletransform - \pgfpathmoveto{\pgfpoint{\sseq@xmin cm}{\sseq@ymin cm}} + \xmin\ymin + \pgfpathmoveto{\pgfqpointxy{\numexpr\sseq@xmin+\sseq@xoffset\relax}{\numexpr\sseq@ymin+\sseq@yoffset\relax}} \egroup \bgroup - \xmin\ymax\sseq@globalscaletransform - \pgfpathlineto{\pgfpoint{\sseq@xmin cm}{\sseq@ymax cm}} + \xmin\ymax + \pgfpathlineto{\pgfqpointxy{\numexpr\sseq@xmin+\sseq@xoffset\relax}{\numexpr\sseq@ymax+\sseq@yoffset\relax}} \egroup \bgroup - \xmax\ymax\sseq@globalscaletransform - \pgfpathlineto{\pgfpoint{\sseq@xmax cm}{\sseq@ymax cm}} + \xmax\ymax + \pgfpathlineto{\pgfqpointxy{\numexpr\sseq@xmax+\sseq@xoffset\relax}{\numexpr\sseq@ymax+\sseq@yoffset\relax}} \egroup \bgroup - \xmax\ymin\sseq@globalscaletransform - \pgfpathlineto{\pgfpoint{\sseq@xmax cm}{\sseq@ymin cm}} + \xmax\ymin + \pgfpathlineto{\pgfqpointxy{\numexpr\sseq@xmax+\sseq@xoffset\relax}{\numexpr\sseq@ymin+\sseq@yoffset\relax}} \egroup \egroup \pgfpathclose - \pgfgetpath\sseq@theclippath % This stores the clipping so I can find intersections later + \pgfgetpath\sseq@theclippath % This stores the clipping so I can apply it later \pgfusepath{discard}% This has to be after the egroup or else the clipping gets screwed up +% \bgroup - %\sseq@globalscaletransform - \pgfpathmoveto{\pgfpoint{\sseq@xmin cm}{\sseq@ymin cm}} - \pgfpathlineto{\pgfpoint{\sseq@xmin cm}{\sseq@ymax cm}} - \pgfpathlineto{\pgfpoint{\sseq@xmax cm}{\sseq@ymax cm}} - \pgfpathlineto{\pgfpoint{\sseq@xmax cm}{\sseq@ymin cm}} + \pgfpathmoveto{\pgfqpointxy{\numexpr\sseq@xmin+\sseq@xoffset\relax}{\numexpr\sseq@ymin+\sseq@yoffset\relax}} + \pgfpathlineto{\pgfqpointxy{\numexpr\sseq@xmin+\sseq@xoffset\relax}{\numexpr\sseq@ymax+\sseq@yoffset\relax}} + \pgfpathlineto{\pgfqpointxy{\numexpr\sseq@xmax+\sseq@xoffset\relax}{\numexpr\sseq@ymax+\sseq@yoffset\relax}} + \pgfpathlineto{\pgfqpointxy{\numexpr\sseq@xmax+\sseq@xoffset\relax}{\numexpr\sseq@ymin+\sseq@yoffset\relax}} \pgfpathclose \egroup \pgfgetpath\sseq@therangepath % Only for deciding whether to draw "tricky edges" @@ -188,66 +337,194 @@ \fi } \def\sseq@useclip{\ifx\sseq@theclippath\relax\else\pgfsetpath\sseq@theclippath\pgfusepath{clip}\fi} + + +% sets \pgf@xa and \pgf@ya equal to the coordinates of (1,1), sets \pgf@xb and \pgf@xb equal to (x grid step, y grid step) +\def\sseq@grid@setstepandgridstep{ + \pgf@process{\pgfqpointxy{1}{1}} + \pgf@xa=\pgf@x + \pgf@ya=\pgf@y + \pgf@process{\pgfqpointxy{\sseq@xgridstep}{\sseq@ygridstep}} + \pgf@xb=\pgf@x + \pgf@yb=\pgf@y +} + +% #1 -- macro to store result in +% #2 -- "x" or "y" as appropriate +% #3 -- length (with units) +% #4 -- fraction of gridstep +% If #2 is x, then it either sets #1 to #3/(x scale) or xgridstep*#4, whichever is smaller +% The output is intended for use with \pgfpointxy. +\def\sseq@grid@atmostgridstep#1#2#3#4{ + \ifdim#3<\dimexpr\csname pgf@#2b\endcsname*#4\relax + \pgfmathparse{#3/\csname pgf@#2a\endcsname} + \let#1\pgfmathresult + \else + \edef#1{\csname sseq@#2gridstep\endcsname*#4} + \fi +} + +% This grid was a huge pain in the ass to get right... \def\sseq@grid@chess{ - \bgroup - \pgfscope - \sseq@useclip - \pgflowlevelsynccm - \pgfsetlinewidth{1cm} - \pgfsetdash{{1cm}{1cm}}{1cm} - \pgfsetcolor{lightgray} - \pgfpathgrid[stepx=2cm,stepy=2cm]{\pgfpoint{-0.5cm}{-0.5cm}}{\pgfpoint{\sseq@xmax cm+0.499cm}{\sseq@ymax cm+0.499cm}} - \pgfusepath{stroke} - \endpgfscope - \egroup + \bgroup + \pgfscope + % Pad on the right and top by either the grid padding, or the remaining piece of the checkerboard before it would start a new square + % (it looks ugly to have a tiny sliver). Annoyingly, mod returns its result with the same sign as its input, so in order to reduce mod + % \sseq@xgridstep and get a positive result, we have to do it twice. The 0.5cm*scale here matches the -0.5 in the \pgfpathgrid call. + \pgfmathsetmacro\sseq@rightpadding{min( + \sseq@rightgridpadding, + 1cm* mod(mod(-\sseq@xmax,\sseq@xgridstep)+\sseq@xgridstep,\sseq@xgridstep)+0.5cm*\sseq@xscale-0.05cm + )} + \pgfmathsetmacro\sseq@toppadding{min( + \sseq@topgridpadding, + 1cm * mod(mod(-\sseq@ymax,\sseq@ygridstep)+\sseq@ygridstep,\sseq@ygridstep)+0.5cm*\sseq@yscale-0.02cm + )} + % Because of complicated aliasing issues that arise when misusing the \pgfgrid command in this way, + % it's more convenient to add a clip than to actually stop things in the right place. + \clip (\sseq@xmin-\sseq@xoffset,\sseq@ymin-\sseq@yoffset) ++ (-0.48, -0.48) + rectangle ([shift={(\sseq@rightpadding pt,\sseq@toppadding pt)}]\sseq@xmax,\sseq@ymax); +% + \sseq@useclip + \pgfsetcolor{\sseq@gridcolor} + \pgfsetstrokeopacity{0.3} % We don't set low opacity for the other grids, but this one is visible even if it is very faint. + \sseq@grid@setstepandgridstep +% +% Use ifdim with cm to compare real scalars b/c tex is dumb. + % okay, now we need to be careful in order to avoid overflows. The hack we are using requires that the xvec and the yvec are equal + % because we can't apply these via lowlevelsynccm. However, xvec and yvec are the things that prevent overflows. + % What we need to do is set them both equal to the smaller value. Now the scale factor determines the size of the squares, + % so we mix in the grid steps. We also need to scale the larger scaled coordinate by the ratio of the two scales. + \ifdim\sseq@xscale cm<\sseq@yscale cm\relax + % x is smaller so set both x and y vecs to \sseq@xscale cm. + \pgfsetxvec{\pgfpoint{\sseq@xscale cm}{0cm}} + \pgfsetyvec{\pgfpoint{0cm}{\sseq@xscale cm}} + \def\sseq@xadjustscale{\sseq@xgridstep} + \def\sseq@yadjustscale{\sseq@yscale/\sseq@xscale*\sseq@ygridstep} + \def\sseq@stepscale{\sseq@xscale} + \else + \pgfsetxvec{\pgfpoint{\sseq@yscale cm}{0cm}} + \pgfsetyvec{\pgfpoint{0cm}{\sseq@yscale cm}} + \def\sseq@xadjustscale{(\sseq@xscale/\sseq@yscale*\sseq@xgridstep)} + \def\sseq@yadjustscale{\sseq@ygridstep} + \def\sseq@stepscale{\sseq@yscale} + \fi + \pgftransformxscale{\sseq@xadjustscale} + \pgftransformyscale{\sseq@yadjustscale} + % Now we have to put in some ridiculously complicated shift in order to get the bottom corner in the right place. + % I found this formula mostly by trial and error. + % The basic idea that we should be making something divisible by twice the grid step (which is the actual period of our grid) + % is reasonable enough, but what the heck are these other two terms for? I don't know either, thank god it works. + \pgftransformshift{\pgfpointxy{ + floor((\sseq@xgridstep-1)/2)/\sseq@xgridstep + + \ifodd\sseq@xgridstep\space 0 \else 0.5/\sseq@xgridstep\fi + + mod(1+\sseq@xmin/\sseq@xgridstep,2*\sseq@xgridstep) + }{ + floor((\sseq@ygridstep-1)/2)/\sseq@ygridstep + + \ifodd\sseq@ygridstep\space 0\else 0.5/\sseq@ygridstep\fi + + mod(1+\sseq@ymin/\sseq@ygridstep,2*\sseq@ygridstep) + } + } + % We use lowlevelsynccm to make the scale adjust the line width. Normally scaling doesn't affect line width, text size, etc, which is sensible. + % When you apply \pgflowlevelsynccm, pgf loses track of the coordinate matrix and it gets indiscriminately applied to everything. + % This is good for us, because we're doing this absurd thing where we make a checkerboard by drawing a really really fat line. + \pgflowlevelsynccm + \pgfsetlinewidth{1cm*\sseq@stepscale} + \pgfsetdash{{1cm*\sseq@stepscale}{1cm*\sseq@stepscale}}{1cm*\sseq@stepscale} +% + % Naturally some trial and error occurred here too. + % Note the huge multiples of \sseq@xgridstep I added in -- they probably aren't necessary, but I don't understand what's going on so whatever. + % The basic idea is that things need to be divisible by twice the grid step. The part I added in the shift above + % was the remainder when you divide \sseq@xmin by twice the grid step, now we need to add in the multiple of twice the grid step. + % The -0.5 is ensuring that the checkerboard boundaries lie at half-integer coordinates (I think). + \pgfpathgrid[stepx= 2cm*\sseq@stepscale,stepy=2cm*\sseq@stepscale] + { \pgfpointxy + { -0.5 + \sseq@intdivfloor{\numexpr\sseq@xmin - \sseq@xgridstep\relax}{2*\sseq@xgridstep}*2*\sseq@xgridstep + \sseq@xoffset - 50*\sseq@xgridstep } + { -0.5 + \sseq@intdivfloor{\numexpr\sseq@ymin - \sseq@ygridstep\relax}{2*\sseq@ygridstep}*2*\sseq@ygridstep + \sseq@yoffset - 50*\sseq@ygridstep} + }{ \pgfpointxy + { \sseq@xmax + \sseq@xoffset + 50*\sseq@xgridstep } + { \sseq@ymax + \sseq@yoffset + 50*\sseq@ygridstep } + } + \pgfusepath{stroke} + \endpgfscope + \egroup } + \def\sseq@grid@crossword{ - \bgroup - \pgfscope - \pgfsetlinewidth{\the\sseq@gridstrokethickness} - \sseq@useclip - \pgftransformxshift{-0.5cm} - \pgftransformyshift{-0.5cm} - \pgfpathgrid[stepx=1cm,stepy=1cm]{\pgfpoint{-1cm}{-1cm}}{\pgfpoint{\xmax cm+0.99cm}{\ymax cm+0.99cm}} - \pgfusepath{stroke} - \endpgfscope - \egroup + \bgroup + \pgfscope + \sseq@useclip + \pgfsetcolor{\sseq@gridcolor} + \pgfsetlinewidth{\the\sseq@gridstrokethickness} + \sseq@grid@setstepandgridstep +% + % We don't want the grid to end with an extra line, so extend it by one half the step distance or + % \sseq@---gridpadding, whichever is shorter. + \sseq@grid@atmostgridstep\sseq@xminpadding{x}{\sseq@leftgridpadding}{1/2} + \sseq@grid@atmostgridstep\sseq@xmaxpadding{x}{\sseq@rightgridpadding}{1/2} + \sseq@grid@atmostgridstep\sseq@yminpadding{y}{\sseq@bottomgridpadding}{1/2} + \sseq@grid@atmostgridstep\sseq@ymaxpadding{y}{\sseq@topgridpadding}{1/2} +% + \pgftransformshift{\pgfpointxy{-\sseq@xgridstep/2}{-\sseq@ygridstep/2}} + \pgfpathgrid[stepx=\pgf@xb,stepy=\pgf@yb] + { \pgfpointxy + { \sseq@xmin - \sseq@xminpadding + 0.01 + \sseq@xoffset + \sseq@xgridstep/2 } + { \sseq@ymin - \sseq@yminpadding + 0.01 + \sseq@yoffset + \sseq@ygridstep/2 } } + { \pgfpointxy + { \sseq@xmax + \sseq@xmaxpadding - 0.01 + \sseq@xoffset + \sseq@xgridstep/2 } + { \sseq@ymax + \sseq@ymaxpadding - 0.01 + \sseq@yoffset + \sseq@ygridstep/2 } } + \pgfusepath{stroke} + \endpgfscope + \egroup } \def\sseq@grid@go{ - \bgroup - \pgfscope - \sseq@useclip - \pgfsetlinewidth{\the\sseq@gridstrokethickness} - \pgfpathgrid[stepx=1cm,stepy=1cm]{\pgfpoint{-1cm}{-1cm}}{\pgfpoint{\xmax cm+0.5cm}{\ymax cm+0.5cm}} - \pgfusepath{stroke} - \endpgfscope - \egroup + \bgroup + \pgfscope + \sseq@useclip + \pgfsetcolor{\sseq@gridcolor} + \pgfsetlinewidth{\the\sseq@gridstrokethickness} + \sseq@grid@setstepandgridstep +% + % We don't want the grid to end with an extra line, so extend it by one step distance or + % \sseq@---gridpadding, whichever is shorter. + \sseq@grid@atmostgridstep\sseq@xminpadding{x}{\sseq@leftgridpadding}{1} + \sseq@grid@atmostgridstep\sseq@xmaxpadding{x}{\sseq@rightgridpadding}{1} + \sseq@grid@atmostgridstep\sseq@yminpadding{y}{\sseq@bottomgridpadding}{1} + \sseq@grid@atmostgridstep\sseq@ymaxpadding{y}{\sseq@topgridpadding}{1} +% + \pgfpathgrid[stepx=\pgf@xb,stepy=\pgf@yb] + { \pgfpointxy + { \sseq@xmin - \sseq@xminpadding + 0.01 + \sseq@xoffset } + { \sseq@ymin - \sseq@yminpadding + 0.01 + \sseq@yoffset } } + { \pgfpointxy + { \sseq@xmax + \sseq@xmaxpadding - 0.01 + \sseq@xoffset } + { \sseq@ymax + \sseq@ymaxpadding - 0.01 + \sseq@yoffset } + } + \pgfusepath{stroke} + \endpgfscope + \egroup } \def\sseq@grid@none{} \def\sseq@grid@dots{ - \bgroup - \pgfscope - \pgfgettransform\sseq@savetransform - \pgftransformreset - \sseq@globalscaletransform - \pgfgettransformentries{\sseq@a}{\sseq@b}{\sseq@c}{\sseq@d}{\sseq@u}{\sseq@v} - \pgfsettransform\sseq@savetransform - \sseq@useclip - \pgftransformxshift{-1.5cm} - \pgftransformyshift{-0.5cm} - \pgfsetdash{{1pt}{\sseq@a*1cm-1pt}}{0.5cm+.5pt} - \pgfsetlinewidth{1pt} - \sseq@tempy=\sseq@ymin\relax - \advance\sseq@tempy\m@ne - \loop - \advance\sseq@tempy\@ne - \pgfpathmoveto{\pgfpoint{\sseq@xmin cm+0.5cm/\sseq@a}{\the\sseq@tempy cm}} - \pgfpathlineto{\pgfpoint{\sseq@xmax cm+1.01cm }{\the\sseq@tempy cm}} - \ifnum\sseq@tempy<\sseq@ymax\repeat - %\pgfpathgrid[stepx=1cm,stepy=1cm]{\pgfpoint{-0.5cm}{-0.5cm}}{\pgfpoint{\xmax cm-0.5cm}{\ymax cm-0.5cm}} - \pgfusepath{stroke} - \endpgfscope - \egroup + \bgroup + \pgfscope + \pgfgettransform\sseq@savetransform + \pgfgettransformentries{\sseq@a}{\sseq@b}{\sseq@c}{\sseq@d}{\sseq@u}{\sseq@v} + \pgfsettransform\sseq@savetransform + \sseq@useclip + \pgftransformshift{\pgfqpoint{-1.5cm}{-0.5cm}} + \pgfsetdash{{1pt}{\sseq@a*1cm-1pt}}{0.5cm+.5pt} + \pgfsetlinewidth{1pt} + \sseq@tempy=\sseq@ymin\relax + \advance\sseq@tempy\m@ne + \loop + \advance\sseq@tempy\@ne + \pgfpathmoveto{\pgfpointxy{\sseq@xmin + 0.5/\sseq@a}{\the\sseq@tempy}} + \pgfpathlineto{\pgfpointxy{\sseq@xmax + 1.01 }{\the\sseq@tempy}} + \ifnum\sseq@tempy<\sseq@ymax\repeat + %\pgfpathgrid[stepx=1cm,stepy=1cm]{\pgfpoint{-0.5cm}{-0.5cm}}{\pgfpoint{\xmax cm-0.5cm}{\ymax cm-0.5cm}} + \pgfusepath{stroke} + \endpgfscope + \egroup } %%% %%% Draw Classes @@ -261,6 +538,7 @@ (-0.16,-0.16)(0.16,-0.16)(-0.16,0.16)(0.16,0.16)(0,0); (-0.13,-0.2)(-0.13,0)(-0.13,0.2)(0.13,-0.2)(0.13,0)(0.13,0.2); } + \sseqnewclasspattern{linear}{ (0,0); (-0.13,0)(0.13,0); @@ -270,15 +548,21 @@ (-0.5,0)(-0.3,0)(-0.1,0)(0.1,0)(0.3,0)(0.5,0); } \def\sseq@offset#1#2{ - \sseq@eval{\@nx\pgftransformshift{\@nx\pgfpoint{0\csname sseq@\sseq@classpattern xoffset#1/#2\endcsname cm}{0\csname sseq@\sseq@classpattern yoffset#1/#2\endcsname cm}}} + \sseq@eval{\@nx\pgftransformshift{ + \@nx\pgfqpointxy + { \csname sseq@\sseq@classpattern xoffset#1/#2\endcsname } + { \csname sseq@\sseq@classpattern yoffset#1/#2\endcsname } + }} } \def\sseq@class@getparts#1(#2,#3,#4)[#5].{ \sseq@seterrorannotation@drawing{#1}{#2}{#3}{#4}{#5} \def\sseq@thisclassname{class.(#2,#3,#4)} \def\sseq@thisnodename{sseq{#2,#3,#4}} \def\sseq@thispos{(#2,#3)} - \def\sseq@thisposnum{#4} + \edef\sseq@thisposnum{\sseq@obj{class.(#2,#3,#4).n}} \def\sseq@thisclassnum{#5} + \sseq@tempx=#2\relax + \sseq@tempy=#3\relax } \def\sseqtooltip#1#2{% @@ -298,11 +582,14 @@ } % #1 -- the name of the node object +% Someday I should document this horrible mess of code here +\newif\ifsseq@permanentcycle +\newcount\sseq@totalclassesdrawn +\AtEndDocument{\message{Total classes: \the\sseq@totalclassesdrawn}} \def\sseq@class@drawnode#1{% + \global\advance\sseq@totalclassesdrawn\@ne \begingroup \sseq@class@getparts#1. - \sseq@tempx=\sseq@obj{\sseq@thisclassname.x}\relax - \sseq@tempy=\sseq@obj{\sseq@thisclassname.y}\relax \sseq@needstikzfalse \sseq@options@firstpassmode \sseq@thesseqstyle @@ -318,7 +605,7 @@ \the\sseq@scope@toks \sseq@obj{#1.needstikz} % - \sseq@outofrangetrue + \sseq@outofrangetrue\relax % Mysterious that we need this \relax here... \ifnum\sseq@tempx<\sseq@xmaxpp\relax\ifnum\sseq@tempx>\sseq@xminmm\relax\ifnum\sseq@tempy<\sseq@ymaxpp\relax\ifnum\sseq@tempy>\sseq@yminmm\relax \sseq@outofrangefalse \pgfscope @@ -329,17 +616,19 @@ \sseq@thesseqstyle \sseq@theclassstyle \ifnum\sseq@obj{#1.page}=\sseq@infinitycount + \sseq@permanentcycletrue % This is to communicate with family style code... \sseq@thepermanentcyclestyle \else + \sseq@permanentcyclefalse \sseq@thetransientcyclestyle \ifsseq@thispage \sseq@thethispagecyclestyle \fi \fi + \def\sseq@collections@featuretype{class} \the\sseq@scope@toks \sseq@obj{#1.options}% - \sseq@eval{\@nx\pgftransformshift{\@nx\pgfpoint{\the\sseq@tempx cm}{\the\sseq@tempy cm}}} - \sseq@eval{\@nx\pgftransformshift{\@nx\pgfpoint{-\the\sseq@x cm}{-\the\sseq@y cm}}} + \pgftransformshift{\pgfqpointxy{\numexpr\sseq@tempx +\sseq@xoffset-\sseq@x\relax}{\numexpr\sseq@tempy + \sseq@yoffset-\sseq@y\relax}} \iftikz@fullytransformed\pgfgettransform{\savetransform}\fi \pgftransformresetnontranslations \sseq@globalrotatetransform @@ -351,24 +640,23 @@ \tikz@options \ifsseq@needstikz \let\sseq@mode\tikz@mode - \tikzset{every text node part/.code/.expand once={\sseq@globalrotatetransform\sseq@obj{#1.nodetext.options}}}% + \tikzset{every text node part/.code/.expand once={\sseq@globalrotatetransform\sseq@obj@ifdef{#1.nodetext.options}{\sseq@obj{#1.nodetext.options}}{}}}% \sseq@eval{% \@nx\node[/utils/exec={\let\@nx\tikz@mode\@nx\sseq@mode}, /handlers/first char syntax/the character "/.initial=\@nx\sseq@handlequote - ] (\sseq@thisnodename) {\unexpanded\@xpthree{\sseq@obj{#1.nodetext}}} - [every text node part/.code={}] - \@nx\sseq@obj{#1.labelnodes}; + ] (\sseq@thisnodename) {\sseq@obj@ifdef{#1.nodetext}{\unexpanded\@xpthree{\sseq@obj{#1.nodetext}}}{}} + [every text node part/.code={}]; }% \else \tikz@node@textfont - \edef\sseq@classnodetextoptions{\@xptwo\@nx\sseq@obj{#1.nodetext.options}} - \edef\sseq@classnodetext{\@xptwo\@nx\sseq@obj{#1.nodetext}} - \sseq@setnodetext + \edef\sseq@classnodetextoptions{\sseq@obj@ifdef{#1.nodetext.options}{\@xptwo\@nx\sseq@obj{#1.nodetext.options}}{}} + \edef\sseq@classnodetext{\sseq@obj@ifdef{#1.nodetext}{\@xptwo\@nx\sseq@obj{#1.nodetext}}{}} + \sseq@setnodetext{\sseq@classnodetext}{\sseq@classnodetextoptions} \let\tikz@fig@name\sseq@thisnodename \pgfmultipartnode{\tikz@shape}{\tikz@anchor}{\tikz@fig@name}{\sseq@drawnode}% \tikz@alias - \sseq@obj{#1.labelnodes} \fi + \sseq@obj{#1.labelnodes} \sseq@obj@ifdef{#1.tooltip}{ \pgfpointanchor{\sseq@thisnodename}{west} \pgf@xa=\pgf@x @@ -386,7 +674,7 @@ \endpgfinterruptpicture } {% - \pgftransformshift{\pgfpoint{\pgf@xa}{\pgf@ya}}% + \pgftransformshift{\pgfqpoint{\pgf@xa}{\pgf@ya}}% \pgfapproximatenonlineartransformation% \pgfqboxsynced{\tikz@tempbox}% }% @@ -394,8 +682,7 @@ \endpgfscope \fi\fi\fi\fi \ifsseq@outofrange - \sseq@eval{\@nx\pgftransformshift{\@nx\pgfpoint{\the\sseq@tempx cm}{\the\sseq@tempy cm}}}% - \sseq@eval{\@nx\pgftransformshift{\@nx\pgfpoint{-\the\sseq@x cm}{-\the\sseq@y cm}}} + \sseq@eval{\@nx\pgftransformshift{\@nx\pgfqpointxy{\numexpr\sseq@tempx+\sseq@xoffset-\sseq@x\relax}{\numexpr\sseq@tempy+\sseq@yoffset-\sseq@y\relax}}}% \pgftransformresetnontranslations \sseq@globalrotatetransform \sseq@classplacementtransform @@ -404,11 +691,14 @@ \fi \endgroup } -\def\sseq@setnodetext{% + +% #1 -- label text +% #2 -- options +\def\sseq@setnodetext#1#2{% \setbox\pgfnodeparttextbox=\hbox{% \pgfscope% + #2 \tikzset{every text node part/.try}% - \sseq@classnodetextoptions \ifx\tikz@textopacity\pgfutil@empty% \else% \pgfsetfillopacity{\tikz@textopacity}% @@ -430,7 +720,7 @@ \fi% \pgfsetcolor{.}% \tikz@atbegin@node% - \sseq@classnodetext% + #1% \tikz@atend@node% \ifx\tikz@text@width\pgfutil@empty% \else% @@ -489,6 +779,51 @@ \global\pgflinewidth=\pgfutil@tempdima% } +%%% Labels + +% #1 -- label text +% #2 -- options +\def\sseq@drawlabel#1#2{ + \bgroup\pgfscope + \def\tikz@mode{} + \let\sseq@tikz@transform@save\tikz@transform + \pgfkeyssetvalue{/pgf/inner xsep}{2pt} + \pgfkeyssetvalue{/pgf/inner ysep}{2pt} + \def\tikz@shape{rectangle} + \let\tikz@transform\empty % The next line was set up to fix the classlabelstyle glitch + \sseq@options@secondpassmode + \sseq@thesseqstyle\sseq@thelabelstyle\sseq@theclasslabelstyle#2 + \tikz@options + \pgftransformreset + \pgftransformshift{\tikz@node@at} + \tikz@lib@pos@call + \tikz@transform + \tikz@mode + \let\tikz@transform\sseq@tikz@transform@save + \sseq@setnodetext{\sseq@labeltextfn{#1}}{} + \pgfmultipartnode{\tikz@shape}{\tikz@anchor}{label}{\sseq@drawnode}% + \ifsseq@pin + \def\sseq@pinoptions{} + \let\tikz@options\empty + \let\tikz@mode\empty + \sseq@thepinstyle + #2 + \sseq@pinoptions + \tikz@options + \tikz@mode + \sseq@drawedge@findsourcetarget{\tikz@fig@name}{}{label}{} + \pgfpathmoveto{\sseq@sourcecoord}% + \pgfpathlineto{\sseq@targetcoord}% + \sseq@eval{\noexpand\pgfusepath{% + draw + \iftikz@mode@fill fill,\fi + \iftikz@mode@draw draw,\fi + }}% + \fi + \endpgfscope\egroup +} + + %%% %%% Drawing edges %%% @@ -506,6 +841,34 @@ \fi } +% #1 -- source node +% #2 -- source anchor +% #3 -- target node +% #4 -- target anchor +% Calculate actual start and end of the edge (node borders), return the results stored in \sseq@sourcecoord, \sseq@targetcoord +\def\sseq@drawedge@findsourcetarget#1#2#3#4{ + \edef\sseq@edgesourceanchor{#2} + \edef\sseq@edgetargetanchor{#4} + \let\tempaf\pgfutil@empty + \ifx\sseq@edgesourceanchor\pgfutil@empty % Check that the source doesn't have a specified anchor + \def\tempa{\pgfpointanchor{#1}{center}}% if so, start by taking the center of that coordinate + \else + \edef\tempa{\@nx\pgfpointanchor{#1}{\sseq@edgesourceanchor}} % If it has an anchor, use that + \let\tempaf\tempa + \fi + \ifx\sseq@edgetargetanchor\pgfutil@empty % check that the target doesn't have a specified anchor + \def\tempb{\pgfpointshapeborder{#3}{\tempa}}% if so, our end point is the point on the boundary of node b that is in the direction of our initial start coordinate + \else + \edef\tempb{\@nx\pgfpointanchor{#3}{\sseq@edgetargetanchor}}% If it has a specified anchor, use that + \fi + \let\tempbf\tempb + \ifx\tempaf\pgfutil@empty% + \def\tempaf{\pgfpointshapeborder{#1}{\tempb}}% + \fi + \let\sseq@sourcecoord\tempaf + \let\sseq@targetcoord\tempbf +} + \def\sseq@fullcoord@to@partialcoord(#1){\sseq@fullcoord@to@partialcoord@#1,\@nil} \def\sseq@fullcoord@to@partialcoord@#1,#2,#3\@nil{{#1cm}{#2cm}} % #1 -- source (full) @@ -514,7 +877,15 @@ % #4 -- options \def\sseq@drawedge(#1)(#2)#3#4{% \begingroup\pgfscope + % If either class is part of a family we aren't drawing, don't draw the edge either. + \expandafter\ifx\csname pgf@sh@pi@sseq{#1}\endcsname\pgfpictureid\else + \@xp\sseq@break + \fi + \expandafter\ifx\csname pgf@sh@pi@sseq{#2}\endcsname\pgfpictureid\else + \@xp\sseq@break + \fi \def\sseq@edgetype{#3} + \let\sseq@collections@featuretype\sseq@edgetype \let\sseq@edgesourceanchor\pgfutil@empty \let\sseq@edgetargetanchor\pgfutil@empty % @@ -524,40 +895,34 @@ \sseq@thesseqstyle \sseq@theedgestyle\csname sseq@the#3style\endcsname\the\sseq@scope@toks #4% - \sseq@eval{\@nx\pgftransformshift{\@nx\pgfpoint{-\the\sseq@x cm}{-\the\sseq@y cm}}}% - % First calculate actual start and end of the edge - \let\tempaf\pgfutil@empty - \ifx\sseq@edgesourceanchor\pgfutil@empty % Check that the source doesn't have a specified anchor - \def\tempa{\pgfpointanchor{sseq{#1}}{center}}% if so, start by taking the center of that coordinate - \else - \edef\tempa{\@nx\pgfpointanchor{sseq{#1}}{\sseq@edgesourceanchor}} % If it has an anchor, use that - \let\tempaf\tempa - \fi - \ifx\sseq@edgetargetanchor\pgfutil@empty % check that the target doesn't have a specified anchor - \def\tempb{\pgfpointshapeborder{sseq{#2}}{\tempa}}% if so, our end point is the point on the boundary of node b that is in the direction of our initial start coordinate - \else - \edef\tempb{\@nx\pgfpointanchor{sseq{#2}}{\sseq@edgetargetanchor}}% If it has a specified anchor, use that - \fi - \let\tempbf\tempb - \ifx\tempaf\pgfutil@empty% - \def\tempaf{\pgfpointshapeborder{sseq{#1}}{\tempb}}% - \fi + \csname sseq@collections@#3@hook\endcsname + \pgftransformshift{\pgfqpointxy{-\the\sseq@x}{-\the\sseq@y}}% + % puts results into \sseq@sourcecoord and \sseq@targetcoord + \sseq@drawedge@findsourcetarget{sseq{#1}}{\sseq@edgesourceanchor}{sseq{#2}}{\sseq@edgetargetanchor} % \tikz@options \tikz@mode \def\temparrowstartspec{}% \def\temparrowendspec{}% - \pgfcoordinate{tempa}{\tempaf}% - \pgfcoordinate{tempb}{\tempbf}% + \pgfcoordinate{tempa}{\sseq@sourcecoord}% + \pgfcoordinate{tempb}{\sseq@targetcoord}% \pgftransformreset - \sseq@ifinrange(#1){\sseq@ifinrange(#2){\sseq@outofrangefalse}{\sseq@outofrangetrue}}{\sseq@outofrangetrue}% + \sseq@outofrangefalse + \sseq@ifinrange(#1){}{ + \edef\temparrowstartspec{\@nx\pgfsetarrowsstart{\csname sseq@runoffarrow@start@#3@spec\endcsname}} + \sseq@outofrangetrue + }% + \sseq@ifinrange(#2){}{ + \edef\temparrowendspec{\@nx\pgfsetarrowsend{\csname sseq@runoffarrow@end@#3@spec\endcsname}} + \sseq@outofrangetrue + } \ifsseq@outofrange - \sseq@handleoffpageedge{#1}{#2}{#3}% + \sseq@handleoffpageedge{#1}{#2}% \fi \ifsseq@drawedge % TODO: should some sort of transformation manipulation be here? Maybe allow user to specify preference? % Don't draw dots on very short segments - \pgfpointdiff{\tempbf}{\tempaf} + \pgfpointdiff{\sseq@targetcoord}{\sseq@sourcecoord} \pgfmathveclen{\pgf@x}{\pgf@y}% \@xp\pgfmathint\@xp{\pgfmathresult}% \ifnum\pgfmathresult<10\relax%%17? % TODO: Fix this predicate @@ -591,10 +956,10 @@ \endpgfscope\endgroup } -% TODO: this macro is super expensive. Make it faster (avoid -\def\sseq@handleoffpageedge#1#2#3{ - \pgfpathmoveto{\tempaf}% - \pgfpathlineto{\tempbf}% +% TODO: this macro is super expensive. Make it faster +\def\sseq@handleoffpageedge#1#2{ + \pgfpathmoveto{\sseq@sourcecoord}% + \pgfpathlineto{\sseq@targetcoord}% \pgfgetpath\thispath \pgfusepath{discard}% \pgfintersectionofpaths{\pgfsetpath\sseq@theclippath}{\pgfsetpath\thispath}% @@ -603,20 +968,16 @@ \sseq@ifinrange(#1){% If the first endpoint is in range, the second must be out of range b/c sseq@outofrange is true. %\edef\temparrowendspec{\@nx\pgfsetarrowsend{\csname sseq@runoffarrow@end@#3@spec\endcsname}} }{% - \sseq@ifinrange(#2){% - \edef\temparrowstartspec{\@nx\pgfsetarrowsstart{\csname sseq@runoffarrow@start@#3@spec\endcsname}} - }{\sseq@drawedge@handletrickyedge}% uh-oh, both ends are out of range + \sseq@ifinrange(#2){}{\sseq@drawedge@handletrickyedge}% uh-oh, both ends are out of range }% \or \sseq@ifinrange(#1){% If the startpoint is in range, the intersection must be the end. - \def\tempbf{\pgfpointintersectionsolution{1}} - \edef\temparrowendspec{\@nx\pgfsetarrowsend{\csname sseq@runoffarrow@end@#3@spec\endcsname}} - \pgfcoordinate{tempb}{\tempbf} + \def\sseq@targetcoord{\pgfpointintersectionsolution{1}} + \pgfcoordinate{tempb}{\sseq@targetcoord} }{% \sseq@ifinrange(#2){% If the startpoint is out of range and the endpoint is in range, the intersection must be the start - \def\tempaf{\pgfpointintersectionsolution{1}}% - \edef\temparrowstartspec{\@nx\pgfsetarrowsstart{\csname sseq@runoffarrow@start@#3@spec\endcsname}}% - \pgfcoordinate{tempa}{\tempaf}% + \def\sseq@sourcecoord{\pgfpointintersectionsolution{1}}% + \pgfcoordinate{tempa}{\sseq@sourcecoord}% }{\sseq@drawedge@handletrickyedge}% Uh-oh, both ends are out of range. } \or% an orphan @@ -653,26 +1014,33 @@ \def\sseq@drawedge@handleorphan{% - \def\tempaf{\pgfpointintersectionsolution{1}}% - \def\tempbf{\pgfpointintersectionsolution{2}}% + \def\sseq@sourcecoord{\pgfpointintersectionsolution{1}}% + \def\sseq@targetcoord{\pgfpointintersectionsolution{2}}% \edef\temparrowstartspec{\@nx\pgfsetarrowsstart{\csname sseq@runoffarrow@start@\sseq@edgetype @spec\endcsname}}% \edef\temparrowendspec{\@nx\pgfsetarrowsend{\csname sseq@runoffarrow@end@\sseq@edgetype @spec\endcsname}}% - \pgfcoordinate{tempa}{\tempaf}% - \pgfcoordinate{tempb}{\tempbf}% + \pgfcoordinate{tempa}{\sseq@sourcecoord}% + \pgfcoordinate{tempb}{\sseq@targetcoord}% } -% -% #1 -- first coordinate -% #2 -- second coordinate -% #3 -- uid +% #1 -- uid +% #2 -- first coordinate +% #3 -- second coordinate \def\sseq@circleclass@draw#1#2#3{ \begingroup + % If either class is part of a family we aren't drawing, don't draw the fit either. + \expandafter\ifx\csname pgf@sh@pi@sseq{#2}\endcsname\pgfpictureid\else + \@xp\sseq@break + \fi + \expandafter\ifx\csname pgf@sh@pi@sseq{#3}\endcsname\pgfpictureid\else + \@xp\sseq@break + \fi \pgfmathanglebetweenpoints{\pgfpointanchor{sseq{#2}}{center}}{\pgfpointanchor{sseq{#3}}{center}} \let\tempangle\pgfmathresult \let\tikz@lib@fit@scan@handle\sseq@fit@tikz@lib@fit@scan@handle % install fit modifications. \let\tikz@calc@anchor\sseq@fit@tikz@calc@anchor \sseq@tempiftrue + \sseq@options@secondpassmode \node[ rotate fit=\tempangle, /utils/exec={\sseq@thesseqstyle\sseq@thecircleclassstyle\the\sseq@scope@toks\sseq@savedoptioncode @@ -681,6 +1049,7 @@ \@xp\pgfkeysalso\@xp{\romannumeral0\sseq@obj{#1.tikzprimoptions}} } ] {}; + \sseq@breakpoint \endgroup } % Modifies tikz commands \tikz@lib@fit@scan@handle from \pgf\frontendlayer\tikz\libraries\tikzlibraryfit.code.tex line 81 and @@ -711,6 +1080,94 @@ } +%% +%% Patch tikz coords +%% + +\def\sseq@patchtikzcoords{ + \let\sseq@tikz@scan@one@point@noshift\sseq@tikz@scan@one@point@noshift@active + \tikzoption{shift}{\sseq@tikzshift{##1}} + \let\tikz@@@parse@regular\sseq@tikz@@@parse@regular + \let\tikz@to@curve@path\sseq@tikz@to@curve@path + \let\tikz@@@to@compute@relative\sseq@tikz@@@to@compute@relative + + \let\tikz@grid\sseq@tikz@grid + \let\tikz@scan@handle@options\sseq@tikz@scan@handle@options + \let\tikz@@@parse@polar\sseq@tikz@@@parse@polar +} + +% Some of the stuff in tikzlibrarycalc will probably be broken, hopefully not too much +\let\sseq@tikz@scan@one@point@noshift\tikz@scan@one@point +\let\sseq@tikz@@@parse@regular@save\tikz@@@parse@regular + +\def\sseq@tikz@scan@one@point@noshift@active#1{% + \let\tikz@@@parse@regular\sseq@tikz@@@parse@regular@save + \def\sseq@scanonepoint@cmd{\let\tikz@@@parse@regular\sseq@tikz@@@parse@regular#1} + \tikz@scan@one@point\sseq@scanonepoint@cmd% +} + +% Probably there are more places that shouldn't have shifts inserted. +\def\sseq@tikzshift#1{\tikz@addtransform{\sseq@tikz@scan@one@point@noshift\pgftransformshift#1\relax}} + + +\def\sseq@tikz@to@curve@path{% + [every curve to] + \pgfextra{ + \let\tikz@@@parse@regular\sseq@tikz@@@parse@regular@save % I added this to prevent repeated offsets from screwing us up + %\let\sseq@tikz@scan@one@point@noshift\tikz@scan@one@point + \iftikz@to@relative\tikz@to@compute@relative\else\tikz@to@compute\fi + } + \tikz@computed@path + \tikztonodes% +} + +\let\sseq@tikz@@@to@compute@relative\tikz@@@to@compute@relative + + +\patchcmd\sseq@tikz@@@to@compute@relative{% + \let\tikz@second@point=\tikz@toto +}{% + \pgf@process{\pgfpointadd{\tikz@toto}{\pgfqpointxy{\sseq@xoffset}{\sseq@yoffset}}}% + \edef\tikz@toto{\@nx\pgfpoint{\the\pgf@x}{\the\pgf@y}}% + \let\tikz@second@point=\tikz@toto +}{}{\error} + + + + +% \tikz@parse@splitxyz: we should set up an error to make this unreachable? +\let\sseq@tikz@grid\tikz@grid % line 3158 +\let\sseq@tikz@scan@handle@options\tikz@scan@handle@options % 4959 +\let\sseq@tikz@@@parse@polar\tikz@@@parse@polar % 5063 + +\def\sseq@tikz@@@parse@regular#1#2#3){% + \pgfutil@in@,{#3}% + \ifpgfutil@in@% + \tikz@parse@splitxyz{#1}{#2}#3,% + \else% + \tikz@checkunit{#2}% + \iftikz@isdimension% + \tikz@checkunit{#3}% + \iftikz@isdimension% + \def\@next{#1{\pgfpointxy{(#2)/1cm+\sseq@xoffset}{(#3)/1cm+\sseq@yoffset}}}% + \else% + \def\@next{#1{\pgfpointxy{(#2)/1cm+\sseq@xoffset}{#3+\sseq@yoffset}}}% + \fi% + \else% + \tikz@checkunit{#3}% + \iftikz@isdimension% + \def\@next{#1{\pgfpointxy{#2+\sseq@xoffset}{(#3)/1cm+\sseq@yoffset}}}% + \else% + \def\@next{#1{\pgfpointxy{#2+\sseq@xoffset}{#3+\sseq@yoffset}}}% + \fi% + \fi% + \fi% + \@next% +} + + + + %% New shapes and arrows %% These use lots of keys with spaces so it's convenient to turn off ExplSyntax. @@ -987,4 +1444,5 @@ \pgfusepathqfill }, defaults = { length = 0.3cm } -} \ No newline at end of file +} + -- cgit v1.2.3