%% %% Package: spectralsequences.sty version 1.0 %% Author: Hood Chatham %% Email: hood@mit.edu %% Date: 2017-06-18 %% License: Latex Project Public License %% %% File: sseqdrawing.code.tex %% %% Defines the macros that draw the features of the spectral sequence (at least, those that aren't drawn by tikz). %% Everything here has to be super optimized, because like 90% of the execution time is in these functions. %% In particular, tikz is a horrible performance hole that must be avoided at all costs. For example, the code %% the code to produce the axis ticks used to use the tikz \node command, and in the file example_KF3n.tex drawing %% the axes ticks was taking about 1/3 of the compile time (a little under 1s out of a 3.2) %% %%% %%% 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 \fi } \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 \fi } \def\sseq@drawxaxis{ \bgroup \pgftransformreset \sseq@globaldetonetransform % \bgroup \pgftransformxshift{\sseq@xaxis@end@extend}\pgftransformyshift{-\sseq@xaxisgap} \sseq@globalscaletransform \pgfpathmoveto{\pgfpoint{\sseq@xmax cm}{\sseq@ymin cm}} \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 \egroup \pgfusepath{stroke} } \def\sseq@drawyaxis{ \bgroup \pgftransformreset \sseq@globaldetonetransform \bgroup \pgftransformyshift{\sseq@yaxis@end@extend}\pgftransformxshift{-\sseq@yaxisgap} \sseq@globalscaletransform \pgfpathmoveto{\pgfpoint{\sseq@xmin cm}{\sseq@ymax cm}} \egroup \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 \pgfusepath{stroke}% } \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 \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 \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 \sseq@ytickstyle \tikz@options \pgftext{\hbox{$\sseq@ytickfn{\the\sseq@tempy}$}} \egroup \advance\sseq@tempy\sseq@ytickstep\relax \ifnum\sseq@tempy<\sseq@tempmax\repeat } \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}} \bgroup \xmin\ymin\sseq@globalscaletransform \pgfpathmoveto{\pgfpoint{\sseq@xmin cm}{\sseq@ymin cm}} \egroup \bgroup \xmin\ymax\sseq@globalscaletransform \pgfpathlineto{\pgfpoint{\sseq@xmin cm}{\sseq@ymax cm}} \egroup \bgroup \xmax\ymax\sseq@globalscaletransform \pgfpathlineto{\pgfpoint{\sseq@xmax cm}{\sseq@ymax cm}} \egroup \bgroup \xmax\ymin\sseq@globalscaletransform \pgfpathlineto{\pgfpoint{\sseq@xmax cm}{\sseq@ymin cm}} \egroup \egroup \pgfpathclose \pgfgetpath\sseq@theclippath % This stores the clipping so I can find intersections 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}} \pgfpathclose \egroup \pgfgetpath\sseq@therangepath % Only for deciding whether to draw "tricky edges" \pgfusepath{discard} \else \def\sseq@temp{\path[name path=temp]} \@xptwo\sseq@temp\@xp\@gobble\sseq@customclip \pgfgetpath\sseq@theclippath \let\sseq@theclippath\tikz@intersect@path@name@temp \fi \else \let\sseq@theclippath\relax \fi } \def\sseq@useclip{\ifx\sseq@theclippath\relax\else\pgfsetpath\sseq@theclippath\pgfusepath{clip}\fi} \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 } \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 } \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 } \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 } %%% %%% Draw Classes %%% %%% Class offsets \sseqnewclasspattern{standard}{ (0,0); (-0.13,0)(0.13,0); (-0.2,0)(0,0)(0.2,0); (-0.13,-0.13)(0.13,-0.13)(-0.13,0.13)(0.13,0.13); (-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); (-0.2,0)(0,0)(0.2,0); (-0.3,0)(-0.1,0)(0.1,0)(0.3,0); (-0.4,0)(-0.2,0)(0,0)(0.2,0)(0.4,0); (-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}}} } \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} \def\sseq@thisclassnum{#5} } \def\sseqtooltip#1#2{% \edef\temp{\detokenize\@xpthree{#2}}% \edef\temp{\@xp\sseqtooltip@replaceslashes\@xp{\temp}}% \sseq@eval{\@nx\pdftooltip{\unexpanded{#1}}{\temp}}% } \bgroup\lccode`\!=`\\\lowercase{\egroup \def\sseqtooltip@replaceslashes#1{\sseqtooltip@replaceslashes@#1!\sseq@nil} \def\sseqtooltip@replaceslashes@#1!#2{% #1% \ifx\sseq@nil#2\@xp\@gobble\else \@nx\@nx\@nx\textbackslash \@xp\sseqtooltip@replaceslashes@ \fi#2% } } % #1 -- the name of the node object \def\sseq@class@drawnode#1{% \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 \sseq@theclassstyle \ifnum\sseq@obj{#1.page}=\sseq@infinitycount \sseq@thepermanentcyclestyle \else \sseq@thetransientcyclestyle \ifsseq@thispage \sseq@thethispagecyclestyle \fi \fi \the\sseq@scope@toks \sseq@obj{#1.needstikz} % \sseq@outofrangetrue \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 \let\tikz@options\pgfutil@empty \let\tikz@alias=\pgfutil@empty \def\pgfkeysdefaultpath{/sseqpages/class/} \sseq@options@secondpassmode \sseq@thesseqstyle \sseq@theclassstyle \ifnum\sseq@obj{#1.page}=\sseq@infinitycount \sseq@thepermanentcyclestyle \else \sseq@thetransientcyclestyle \ifsseq@thispage \sseq@thethispagecyclestyle \fi \fi \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}}} \iftikz@fullytransformed\pgfgettransform{\savetransform}\fi \pgftransformresetnontranslations \sseq@globalrotatetransform \sseq@classplacementtransform \sseq@obj@ifdef{#1.offset}{\sseq@obj{#1.offset}}{% \sseq@offset{\sseq@thisposnum}{\sseq@obj{partcoord.\sseq@thispos.numnodes}}% }% \iftikz@fullytransformed\pgfsettransform{\savetransform}\else\pgftransformresetnontranslations\ifsseq@rotatelabels\sseq@globalrotatetransform\fi\fi \tikz@options \ifsseq@needstikz \let\sseq@mode\tikz@mode \tikzset{every text node part/.code/.expand once={\sseq@globalrotatetransform\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}; }% \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 \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@ifdef{#1.tooltip}{ \pgfpointanchor{\sseq@thisnodename}{west} \pgf@xa=\pgf@x \pgfpointanchor{\sseq@thisnodename}{south} \pgf@ya=\pgf@y % \pgf@process{\pgfpointdiff{\pgfpointtransformed{\pgfpointanchor{\sseq@thisnodename}{west}}}{\pgfpointtransformed{\pgfpointanchor{\sseq@thisnodename}{east}}}} \pgf@xb=\pgf@x \pgf@process{\pgfpointdiff{\pgfpointtransformed{\pgfpointanchor{\sseq@thisnodename}{south}}}{\pgfpointtransformed{\pgfpointanchor{\sseq@thisnodename}{north}}}} \pgf@yb=\pgf@y % \setbox\tikz@tempbox=\hbox{ \pgfinterruptpicture \sseqtooltip{\rule{\pgf@xb}{0pt}\rule{0pt}{\pgf@yb}}{\sseq@obj{#1.tooltip}} \endpgfinterruptpicture } {% \pgftransformshift{\pgfpoint{\pgf@xa}{\pgf@ya}}% \pgfapproximatenonlineartransformation% \pgfqboxsynced{\tikz@tempbox}% }% }{} \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}}} \pgftransformresetnontranslations \sseq@globalrotatetransform \sseq@classplacementtransform \sseq@offset{\sseq@thisposnum}{\sseq@obj{partcoord.\sseq@thispos.numnodes}} \pgfcoordinate{\sseq@thisnodename}{\pgfpointorigin}% \fi \endgroup } \def\sseq@setnodetext{% \setbox\pgfnodeparttextbox=\hbox{% \pgfscope% \tikzset{every text node part/.try}% \sseq@classnodetextoptions \ifx\tikz@textopacity\pgfutil@empty% \else% \pgfsetfillopacity{\tikz@textopacity}% \pgfsetstrokeopacity{\tikz@textopacity}% \fi% \pgfinterruptpicture \ifx\tikz@text@width\pgfutil@empty% \tikz@textfont% \else% \begingroup% \pgfmathsetlength{\pgf@x}{\tikz@text@width}% \pgfutil@minipage[t]{\pgf@x}\leavevmode\hbox{}% \tikz@textfont% \tikz@text@action% \fi% \ifx\tikz@textcolor\pgfutil@empty% \else% \pgfutil@colorlet{.}{\tikz@textcolor}% \fi% \pgfsetcolor{.}% \tikz@atbegin@node% \sseq@classnodetext% \tikz@atend@node% \ifx\tikz@text@width\pgfutil@empty% \else% \pgfutil@endminipage% \endgroup% \fi% \endpgfinterruptpicture \endpgfscope% }% \ifx\tikz@text@width\pgfutil@empty% \else% \pgfmathsetlength{\pgf@x}{\tikz@text@width}% \wd\pgfnodeparttextbox=\pgf@x% \fi% \ifx\tikz@text@height\pgfutil@empty% \else% \pgfmathsetlength{\pgf@x}{\tikz@text@height}% \ht\pgfnodeparttextbox=\pgf@x% \fi% \ifx\tikz@text@depth\pgfutil@empty% \else% \pgfmathsetlength{\pgf@x}{\tikz@text@depth}% \dp\pgfnodeparttextbox=\pgf@x% \fi% } \def\sseq@drawnode{% \pgfutil@tempdima=\pgflinewidth% {% \tikz@mode% %\iftikz@mode@clip \sseq@error@internal{Clip shouldn't happen here, but this error should be caught earlier}{}\fi % \iftikz@mode@draw% \iftikz@mode@double% % Change line width \begingroup% \pgfsys@beginscope% \tikz@double@setup% \fi% \fi% % % Step 10: Do stroke/fill as needed % \sseq@eval{\noexpand\pgfusepath{% \iftikz@mode@fill fill,\fi% \iftikz@mode@draw draw,\fi% }}% % % Step 11: Double stroke, if necessary % \iftikz@mode@draw% \iftikz@mode@double% \pgfsys@endscope% \endgroup% \fi% \fi }% \global\pgflinewidth=\pgfutil@tempdima% } %%% %%% Drawing edges %%% \def\sseq@ifinrange(#1){\sseq@ifinrange@#1,\sseq@nil} \def\sseq@ifinrange@#1,#2,#3\sseq@nil{% \sseq@tempx=#1\relax\sseq@tempy=#2\relax \sseq@outofrangetrue \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 \fi\fi\fi\fi \ifsseq@outofrange \@xp\pgfutil@secondoftwo \else \@xp\pgfutil@firstoftwo \fi } \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) % #2 -- target (full) % #3 -- which type of edge (either "structline" or "differential") % #4 -- options \def\sseq@drawedge(#1)(#2)#3#4{% \begingroup\pgfscope \def\sseq@edgetype{#3} \let\sseq@edgesourceanchor\pgfutil@empty \let\sseq@edgetargetanchor\pgfutil@empty % \sseq@needstikzfalse \def\pgfkeysdefaultpath{/sseqpages/#3/}% \sseq@options@bothpassmode \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 % \tikz@options \tikz@mode \def\temparrowstartspec{}% \def\temparrowendspec{}% \pgfcoordinate{tempa}{\tempaf}% \pgfcoordinate{tempb}{\tempbf}% \pgftransformreset \sseq@ifinrange(#1){\sseq@ifinrange(#2){\sseq@outofrangefalse}{\sseq@outofrangetrue}}{\sseq@outofrangetrue}% \ifsseq@outofrange \sseq@handleoffpageedge{#1}{#2}{#3}% \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} \pgfmathveclen{\pgf@x}{\pgf@y}% \@xp\pgfmathint\@xp{\pgfmathresult}% \ifnum\pgfmathresult<10\relax%%17? % TODO: Fix this predicate \tikzset{every text node part/.append code={\pgfsetcolor{white}}}% I wonder why this is here... \ifx\temparrowstartspec\pgfutil@empty \else \def\temparrowstartspec{\pgfsetarrowsstart{}}% \fi \ifx\temparrowendspec\pgfutil@empty \else \def\temparrowendspec{\pgfsetarrowsend{}}% \fi \fi \ifsseq@needstikz \draw[/sseqpages, /utils/exec={\sseq@thesseqstyle\sseq@theedgestyle\csname sseq@the#3style\endcsname\the\sseq@scope@toks \temparrowstartspec\temparrowendspec #4}% ] (tempa) to (tempb);% \else \temparrowstartspec \temparrowendspec \pgfpathmoveto{\pgfpointanchor{tempa}{center}}% \pgfpathlineto{\pgfpointanchor{tempb}{center}}% \sseq@eval{\noexpand\pgfusepath{% \iftikz@mode@fill fill,\fi \iftikz@mode@draw draw,\fi }}% \fi \fi \sseq@breakpoint \endpgfscope\endgroup } % TODO: this macro is super expensive. Make it faster (avoid \def\sseq@handleoffpageedge#1#2#3{ \pgfpathmoveto{\tempaf}% \pgfpathlineto{\tempbf}% \pgfgetpath\thispath \pgfusepath{discard}% \pgfintersectionofpaths{\pgfsetpath\sseq@theclippath}{\pgfsetpath\thispath}% \ifcase\pgfintersectionsolutions\relax % No intersections, but one or both endpoints may be out of range but still in clipping region due to scaling. Add ellipses as appropriate. \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 }% \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} }{% \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}% }{\sseq@drawedge@handletrickyedge}% Uh-oh, both ends are out of range. } \or% an orphan \ifsseq@draworphanedges \sseq@drawedge@handleorphan \else \sseq@drawedgefalse % Don't draw "orphaned edges" \fi \else \sseq@error{clip-not-convex}% \sseq@breakfifi \fi } \def\sseq@drawedge@handletrickyedge{% \ifsseq@draworphanedges \pgfintersectionofpaths{\pgfsetpath\sseq@therangepath}{\pgfsetpath\thispath}% \ifnum\pgfintersectionsolutions=\z@ \sseq@drawedgefalse % don't draw orphan edges that never intersect actual range \else% Now we have to make a line through tempa and tempb long enough so that it intersects the original clip area twice. \pgfmathanglebetweenpoints{\pgfpointanchor{tempa}{center}}{\pgfpointanchor{tempb}{center}}% \edef\tempangle{\pgfmathresult} \pgfpathmoveto{\pgfpointadd{\pgfpointanchor{tempa}{center}}{\pgfpointpolar{\tempangle}{100cm}}}% a really long line \pgfpathlineto{\pgfpointadd{\pgfpointanchor{tempa}{center}}{\pgfpointpolar{\tempangle}{-100cm}}}% \pgfgetpath\thispath \pgfusepath{discard} \pgfintersectionofpaths{\pgfsetpath\sseq@theclippath}{\pgfsetpath\thispath} \sseq@drawedge@handleorphan \fi \else \sseq@drawedgefalse \fi } \def\sseq@drawedge@handleorphan{% \def\tempaf{\pgfpointintersectionsolution{1}}% \def\tempbf{\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}% } % % #1 -- first coordinate % #2 -- second coordinate % #3 -- uid \def\sseq@circleclass@draw#1#2#3{ \begingroup \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 \node[ rotate fit=\tempangle, /utils/exec={\sseq@thesseqstyle\sseq@thecircleclassstyle\the\sseq@scope@toks\sseq@savedoptioncode \sseq@obj{#1.options} \sseq@obj{#1.fitnodes} \@xp\pgfkeysalso\@xp{\romannumeral0\sseq@obj{#1.tikzprimoptions}} } ] {}; \endgroup } % Modifies tikz commands \tikz@lib@fit@scan@handle from \pgf\frontendlayer\tikz\libraries\tikzlibraryfit.code.tex line 81 and % \tikz@calc@anchor from \pgf\frontendlayer\tikz\tikz.code.tex line 5164 % make it so that fit silently ignores nodes that are not defined. % This is copied with modification from \pgf\frontendlayer\tikz\libraries\tikzlibraryfit.code.tex line 81 \def\sseq@fit@tikz@lib@fit@scan@handle#1{% \ifsseq@tempif % this has been set in the following macro to be true if there is a node with the given name. If it's not true, ignore this. \iftikz@shapeborder% % Ok, fit all four external anchors, if they exist \tikz@lib@fit@adjust{\pgfpointanchor{\tikz@shapeborder@name}{west}}% \tikz@lib@fit@adjust{\pgfpointanchor{\tikz@shapeborder@name}{east}}% \tikz@lib@fit@adjust{\pgfpointanchor{\tikz@shapeborder@name}{north}}% \tikz@lib@fit@adjust{\pgfpointanchor{\tikz@shapeborder@name}{south}}% \else% \tikz@lib@fit@adjust{#1}% \fi% \fi \sseq@tempiftrue \tikz@lib@fit@scan% } % This is copied with modification from \pgf\frontendlayer\tikz\tikz.code.tex line 5164 \def\sseq@fit@tikz@calc@anchor#1.#2\tikz@stop{% \pgfutil@ifundefined{pgf@sh@ns@#1}{\sseq@tempiffalse}{%If the node doesn't exist, don't throw an error but record that we should skip it \pgfpointanchor{\tikz@pp@name{#1}}{#2}% }%s } %% New shapes and arrows %% These use lots of keys with spaces so it's convenient to turn off ExplSyntax. % Stolen from: https://tex.stackexchange.com/a/24621 \pgfqkeys{/pgf}{ ellipse ratio/.code={\pgfkeyssetvalue{/pgf/ellipse ratio}{#1}}, ellipse ratio/.initial=1 } \pgfdeclareshape{newellipse} { \inheritsavedanchors[from=ellipse] \inheritanchorborder[from=ellipse] \savedanchor\radius{% % % Caculate ``height radius'' % \pgf@y=.5\ht\pgfnodeparttextbox% \advance\pgf@y by.5\dp\pgfnodeparttextbox% \pgfmathsetlength\pgf@yb{\pgfkeysvalueof{/pgf/inner ysep}}% \advance\pgf@y by\pgf@yb% % % Caculate ``width radius'' % \pgf@x=.5\wd\pgfnodeparttextbox% \pgfmathsetlength\pgf@xb{\pgfkeysvalueof{/pgf/inner xsep}}% \advance\pgf@x by\pgf@xb% % % Adjust % \pgfkeysgetvalue{/pgf/ellipse ratio}{\ratioscale} \pgfmathsetmacro\widthfactor{sqrt(\ratioscale^2+1)/\ratioscale} \pgfmathsetmacro\heightfactor{sqrt(\ratioscale^2+1)} \pgf@x=\widthfactor\pgf@x% \pgf@y=\heightfactor\pgf@y% % % Adjust height, if necessary % \pgfmathsetlength\pgf@yc{\pgfkeysvalueof{/pgf/minimum height}}% \ifdim\pgf@y<.5\pgf@yc% \pgf@y=.5\pgf@yc% \fi% % % Adjust width, if necessary % \pgfmathsetlength\pgf@xc{\pgfkeysvalueof{/pgf/minimum width}}% \ifdim\pgf@x<.5\pgf@xc% \pgf@x=.5\pgf@xc% \fi% % % Add outer sep % \pgfmathsetlength{\pgf@xb}{\pgfkeysvalueof{/pgf/outer xsep}}% \pgfmathsetlength{\pgf@yb}{\pgfkeysvalueof{/pgf/outer ysep}}% \advance\pgf@x by\pgf@xb% \advance\pgf@y by\pgf@yb% } \inheritanchor[from=ellipse]{center} \inheritanchor[from=ellipse]{mid} \inheritanchor[from=ellipse]{base} \inheritanchor[from=ellipse]{north} \inheritanchor[from=ellipse]{south} \inheritanchor[from=ellipse]{west} \inheritanchor[from=ellipse]{mid west} \inheritanchor[from=ellipse]{base west} \inheritanchor[from=ellipse]{north west} \inheritanchor[from=ellipse]{south west} \inheritanchor[from=ellipse]{east} \inheritanchor[from=ellipse]{mid east} \inheritanchor[from=ellipse]{base east} \inheritanchor[from=ellipse]{north east} \inheritanchor[from=ellipse]{south east} \inheritbackgroundpath[from=ellipse] } %% %% %% n concentric circles %% \tikzset{circlen/.code={\def\circlen@n{#1}\pgfkeysalso{shape=circlen@shape}}} \pgfdeclareshape{circlen@shape} { \savedanchor\centerpoint{% \pgf@x=.5\wd\pgfnodeparttextbox% \pgf@y=.5\ht\pgfnodeparttextbox% \advance\pgf@y by-.5\dp\pgfnodeparttextbox% } \saveddimen\radius{% % % Caculate ``height radius'' % \pgf@ya=.5\ht\pgfnodeparttextbox% \advance\pgf@ya by.5\dp\pgfnodeparttextbox% \pgfmathsetlength\pgf@yb{\pgfkeysvalueof{/pgf/inner ysep}}% \advance\pgf@ya by\pgf@yb% % % Caculate ``width radius'' % \pgf@xa=.5\wd\pgfnodeparttextbox% \pgfmathsetlength\pgf@xb{\pgfkeysvalueof{/pgf/inner xsep}}% \advance\pgf@xa by\pgf@xb% % % Calculate length of radius vector: % \pgf@process{\pgfpointnormalised{\pgfqpoint{\pgf@xa}{\pgf@ya}}}% \ifdim\pgf@x>\pgf@y% \c@pgf@counta=\pgf@x% \ifnum\c@pgf@counta=\z@% \else% \divide\c@pgf@counta by 255\relax% \pgf@xa=16\pgf@xa\relax% \divide\pgf@xa by\c@pgf@counta% \pgf@xa=16\pgf@xa\relax% \fi% \else% \c@pgf@counta=\pgf@y% \ifnum\c@pgf@counta=\z@% \else% \divide\c@pgf@counta by 255\relax% \pgf@ya=16\pgf@ya\relax% \divide\pgf@ya by\c@pgf@counta% \pgf@xa=16\pgf@ya\relax% \fi% \fi% \pgf@x=\pgf@xa% % % If necessary, adjust radius so that the size requirements are % met: % \pgfmathsetlength{\pgf@xb}{\pgfkeysvalueof{/pgf/minimum width}}% \pgfmathsetlength{\pgf@yb}{\pgfkeysvalueof{/pgf/minimum height}}% \ifdim\pgf@x<.5\pgf@xb% \pgf@x=.5\pgf@xb% \fi% \ifdim\pgf@x<.5\pgf@yb% \pgf@x=.5\pgf@yb% \fi% % % Now, add larger of outer sepearations. % \pgfmathsetlength{\pgf@xb}{\pgfkeysvalueof{/pgf/outer xsep}}% \pgfmathsetlength{\pgf@yb}{\pgfkeysvalueof{/pgf/outer ysep}}% \ifdim\pgf@xb<\pgf@yb% \advance\pgf@x by\pgf@yb% \else% \advance\pgf@x by\pgf@xb% \fi% \pgf@xb=2pt \multiply\pgf@xb\circlen@n \advance\pgf@x\pgf@xb \advance\pgf@x-2pt\relax } % % Anchors % \anchor{center}{\centerpoint} \anchor{mid}{\centerpoint\pgfmathsetlength\pgf@y{.5ex}} \anchor{base}{\centerpoint\pgf@y=0pt} \anchor{north}{\centerpoint\advance\pgf@y by\radius} \anchor{south}{\centerpoint\advance\pgf@y by-\radius} \anchor{west}{\centerpoint\advance\pgf@x by-\radius} \anchor{east}{\centerpoint\advance\pgf@x by\radius} \anchor{mid west}{\centerpoint\advance\pgf@x by-\radius\pgfmathsetlength\pgf@y{.5ex}} \anchor{mid east}{\centerpoint\advance\pgf@x by\radius\pgfmathsetlength\pgf@y{.5ex}} \anchor{base west}{\centerpoint\advance\pgf@x by-\radius\pgf@y=0pt} \anchor{base east}{\centerpoint\advance\pgf@x by\radius\pgf@y=0pt} \anchor{north west}{ \centerpoint \pgf@xa=\radius \advance\pgf@x by-0.707107\pgf@xa \advance\pgf@y by0.707107\pgf@xa } \anchor{south west}{ \centerpoint \pgf@xa=\radius \advance\pgf@x by-0.707107\pgf@xa \advance\pgf@y by-0.707107\pgf@xa } \anchor{north east}{ \centerpoint \pgf@xa=\radius \advance\pgf@x by0.707107\pgf@xa \advance\pgf@y by0.707107\pgf@xa } \anchor{south east}{ \centerpoint \pgf@xa=\radius \advance\pgf@x by0.707107\pgf@xa \advance\pgf@y by-0.707107\pgf@xa } \anchorborder{ \pgf@xa=\pgf@x% \pgf@ya=\pgf@y% \edef\pgf@marshal{% \noexpand\pgfpointborderellipse {\noexpand\pgfqpoint{\the\pgf@xa}{\the\pgf@ya}} {\noexpand\pgfqpoint{\radius}{\radius}}% }% \pgf@marshal% \pgf@xa=\pgf@x% \pgf@ya=\pgf@y% \centerpoint% \advance\pgf@x by\pgf@xa% \advance\pgf@y by\pgf@ya% } % % Background path % \behindbackgroundpath{ \pgfutil@tempdima=\radius% \pgfmathsetlength{\pgf@xb}{\pgfkeysvalueof{/pgf/outer xsep}}% \pgfmathsetlength{\pgf@yb}{\pgfkeysvalueof{/pgf/outer ysep}}% \ifdim\pgf@xb<\pgf@yb% \advance\pgfutil@tempdima by-\pgf@yb% \else% \advance\pgfutil@tempdima by-\pgf@xb% \fi% \sseq@tempcount=\@ne \loop \pgfpathcircle{\centerpoint}{\pgfutil@tempdima}% \advance\pgfutil@tempdima-2pt\relax \advance\sseq@tempcount\@ne \ifnum\sseq@tempcount<\circlen@n \repeat \tikz@mode \sseq@eval{\noexpand\pgfusepath{ \iftikz@mode@draw draw,\fi }} } \backgroundpath{% \pgfutil@tempdima=\radius% \pgfmathsetlength{\pgf@xb}{\pgfkeysvalueof{/pgf/outer xsep}}% \pgfmathsetlength{\pgf@yb}{\pgfkeysvalueof{/pgf/outer ysep}}% \ifdim\pgf@xb<\pgf@yb% \advance\pgfutil@tempdima by-\pgf@yb% \else% \advance\pgfutil@tempdima by-\pgf@xb% \fi% \advance\pgfutil@tempdima2pt\relax \pgfutil@tempdimb=-2pt\relax \multiply\pgfutil@tempdimb\circlen@n \advance\pgfutil@tempdima\pgfutil@tempdimb\relax \pgfpathcircle{\centerpoint}{\pgfutil@tempdima} } } % For out of bounds edges: \pgfdeclarearrow{ name = ..., parameters = { \the\pgfarrowlength\the\pgflinewidth}, setup code = { % The different end values: \pgfarrowssetlineend{-\pgfarrowlength} \pgfarrowssetbackend{-0.6\pgfarrowlength} % The hull \pgfarrowshullpoint{-\pgfarrowlength}{0pt} \pgfarrowshullpoint{\pgfarrowlength}{0pt} % Saves: Only the length: \pgfarrowssavethe\pgfarrowlength \pgfarrowssavethe\pgflinewidth }, drawing code = { \pgfpathcircle{\pgfpoint{-0.7\pgfarrowlength}{0pt}}{1.5\pgflinewidth} \pgfpathcircle{\pgfpoint{-0.4\pgfarrowlength}{0pt}}{1.5\pgflinewidth} \pgfpathcircle{\pgfpoint{-0.1\pgfarrowlength}{0pt}}{1.5\pgflinewidth} \pgfpathclose \pgfusepathqfill }, defaults = { length = 0.3cm } }