% Copyright 2022 by Qrrbrbirlbel % % This file may be distributed and/or modified % % 1. under the LaTeX Project Public License and/or % 2. under the GNU Free Documentation License. % \usepgflibrary{shapes.geometric,intersections} \pgfset{ superellipse x exponent/.initial=2.5, superellipse y exponent/.initial=2.5, superellipse step/.initial=4, superellipse exponent/.style={/pgf/superellipse x exponent={#1},/pgf/superellipse y exponent={#1}}} % Evaluates the x-value of a superellipse around the center % #1 = t (0≤t≤90) % #2 = 2/m (x-exp) % #3 = a (x-rad) \pgfmathdeclarefunction{superellipsex}{3}{% \pgfmathcos@{#1}% \pgfmathpow@{\pgfmathresult}{#2}% \pgfmathmultiply@{\pgfmathresult}{#3}} % Evaluates the y-value of a superellipse around the center % #1 = t (0≤t≤90) % #2 = 2/n (y-exp) % #3 = a (y-rad) \pgfmathdeclarefunction{superellipsey}{3}{% \pgfmathsin@{#1}% \pgfmathpow@{\pgfmathresult}{#2}% \pgfmathmultiply@{\pgfmathresult}{#3}} % Evaluates the x- and y- value of superellipse around the center % #1 = t (0≤t≤90) % #2 = 2/m (x-exp) % #3 = 2/n (y-exp) % #4 = a (x-rad) % #5 = b (y-rad) \def\pgfmathsuperellipseXY#1#2#3#4#5{% \begingroup \pgfmathsuperellipsex@{#1}{#2}{#4}% \let\pgfmath@temp\pgfmathresult \pgfmathsuperellipsey@{#1}{#3}{#5}% \edef\pgfmath@temp{\def\noexpand\pgfmathresultX{\pgfmath@temp}% \def\noexpand\pgfmathresultY{\pgfmathresult}}% \expandafter \endgroup\pgfmath@temp} \pgfdeclareshape{superellipse}{% \inheritsavedanchors[from=ellipse] \inheritanchor[from=ellipse]{text}\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]{east} \inheritanchor[from=ellipse]{mid west}\inheritanchor[from=ellipse]{base west} \inheritanchor[from=ellipse]{mid east}\inheritanchor[from=ellipse]{base east} \anchor{north east}{% \pgf@process{\radius}% \pgfmathpow@{.70710678118}{\xexponent}% \pgf@x=\pgfmathresult\pgf@x \pgfmathpow@{.70710678118}{\yexponent}% \pgf@y=\pgfmathresult\pgf@y \pgfpointadd{}{\centerpoint}% } \anchor{north west}{% \pgf@process{\radius}% \pgfmathpow@{.70710678118}{\xexponent}% \pgf@x=-\pgfmathresult\pgf@x \pgfmathpow@{.70710678118}{\yexponent}% \pgf@y=\pgfmathresult\pgf@y \pgfpointadd{}{\centerpoint}% } \anchor{south west}{% \pgf@process{\radius}% \pgfmathpow@{.70710678118}{\xexponent}% \pgf@x=-\pgfmathresult\pgf@x \pgfmathpow@{.70710678118}{\yexponent}% \pgf@y=-\pgfmathresult\pgf@y \pgfpointadd{}{\centerpoint}% } \anchor{south east}{% \pgf@process{\radius}% \pgfmathpow@{.70710678118}{\xexponent}% \pgf@x=\pgfmathresult\pgf@x \pgfmathpow@{.70710678118}{\yexponent}% \pgf@y=-\pgfmathresult\pgf@y \pgfpointadd{}{\centerpoint}% } \savedmacro\xexponent{% \pgfmathreciprocal{\pgfkeysvalueof{/pgf/superellipse x exponent}}% \pgfmathmultiply@{\pgfmathresult}{2}% \let\xexponent\pgfmathresult } \savedmacro\yexponent{% \pgfmathreciprocal{\pgfkeysvalueof{/pgf/superellipse y exponent}}% \pgfmathmultiply@{\pgfmathresult}{2}% \let\yexponent\pgfmathresult } \savedmacro\step{% \pgfmathtruncatemacro\step{\pgfkeysvalueof{/pgf/superellipse step}}% } \backgroundpath{% \pgf@process{\radius}% \pgfmathsetmacro\xradius{\pgf@x-(\pgfkeysvalueof{/pgf/outer xsep})}% \pgfmathsetmacro\yradius{\pgf@y-(\pgfkeysvalueof{/pgf/outer ysep})}% \let\pgf@tempa\pgfutil@empty\let\pgf@tempb\pgfutil@empty \let\pgf@tempc\pgfutil@empty\let\pgf@tempd\pgfutil@empty \c@pgf@counta=\step \pgfutil@loop \ifnum\c@pgf@counta<90 \pgfmathsuperellipseXY{\the\c@pgf@counta}{\xexponent}{\yexponent}{\xradius}{\yradius}% \edef\pgf@temp{\noexpand\pgfplotstreampoint{\noexpand\pgfqpoint{\pgfmathresultX pt}{\pgfmathresultY pt}}}% \pgfutil@append@macrotomacro\pgf@tempa\pgf@temp \edef\pgf@temp{\noexpand\pgfplotstreampoint{\noexpand\pgfqpoint{-\pgfmathresultX pt}{\pgfmathresultY pt}}}% \pgfutil@prefix@macrotomacro\pgf@tempb\pgf@temp \edef\pgf@temp{\noexpand\pgfplotstreampoint{\noexpand\pgfqpoint{-\pgfmathresultX pt}{-\pgfmathresultY pt}}}% \pgfutil@append@macrotomacro\pgf@tempc\pgf@temp \edef\pgf@temp{\noexpand\pgfplotstreampoint{\noexpand\pgfqpoint{\pgfmathresultX pt}{-\pgfmathresultY pt}}}% \pgfutil@prefix@macrotomacro\pgf@tempd\pgf@temp \advance\c@pgf@counta by\step \pgfutil@repeat \pgftransformshift{\centerpoint}% \pgfplothandlerclosedcurve \pgfplotstreamstart \pgfplotstreampoint{\pgfqpoint{\xradius pt}{0pt}}% east \pgf@tempa \pgfplotstreampoint{\pgfqpoint{0pt}{\yradius pt}}% north \pgf@tempb \pgfplotstreampoint{\pgfqpoint{-\xradius pt}{0pt}}% west \pgf@tempc \pgfplotstreampoint{\pgfqpoint{0pt}{-\yradius pt}}% south \pgf@tempd \pgfplotstreamend \pgftransformshift{\centerpoint\pgf@x=-\pgf@x\pgf@y=-\pgf@y} } \anchorborder{% \pgfextract@process\externalpoint{}% \ifdim\pgf@x=0pt % catch special case x = 0 \ifdim\pgf@y<0pt \pgf@anchor@superellipse@south\else\pgf@anchor@superellipse@north\fi \else \ifdim\pgf@y=0pt % catch special case y = 0 \ifdim\pgf@x<0pt \pgf@anchor@superellipse@west\else\pgf@anchor@superellipse@east\fi \else % both are not zero % save original direction \pgf@xa=\pgf@x \pgf@ya=\pgf@y % make both positive, we're not looking at one quadrant \ifdim\pgf@xa<0pt \pgf@x=-\pgf@x\fi \ifdim\pgf@ya<0pt \pgf@y=-\pgf@y\fi % save that point again \pgfextract@process\externalpoint{}% % we need to do the calculations without any transformations % since we're using plots and \pgfpointborderrectangle \pgftransformreset \pgfintersectionofpaths{% % from center to point on rectangle that encompasses superellipse \pgf@relevantforpicturesizefalse \pgfpathmoveto{\pgfpointorigin}% \pgfpathlineto{\pgfpointborderrectangle{\externalpoint}{\radius}}% }{% \pgf@relevantforpicturesizefalse \pgf@process{\radius} \edef\xradius{\pgf@sys@tonumber\pgf@x}% \edef\yradius{\pgf@sys@tonumber\pgf@y}% \let\pgf@tempa\pgfutil@empty \c@pgf@counta=\step \pgfutil@loop \ifnum\c@pgf@counta<90 \pgfmathsuperellipseXY{\the\c@pgf@counta}{\xexponent}{\yexponent}{\xradius}{\yradius}% \edef\pgf@temp{\noexpand\pgfplotstreampoint{\noexpand\pgfqpoint{\pgfmathresultX pt}{\pgfmathresultY pt}}}% \pgfutil@append@macrotomacro\pgf@tempa\pgf@temp \advance\c@pgf@counta by\step \pgfutil@repeat % we're only using curveto since closedcurve % messes with our other path \pgfplothandlercurveto \pgfplotstreamstart \pgfplotstreampoint{\pgfqpoint{\xradius pt}{0pt}}% east \pgf@tempa \pgfplotstreampoint{\pgfqpoint{0pt}{\yradius pt}}% north \pgfplotstreamend }% \ifnum\pgfintersectionsolutions>0 % only if a solution was found \pgf@process{\pgfpointintersectionsolution{1}}% \else % otherwise take the border on the rectangle (close enough?) \pgf@process{\pgfpointborderrectangle{\externalpoint}{\radius}}% \fi \ifdim\pgf@xa<0pt \pgf@x=-\pgf@x\fi \ifdim\pgf@ya<0pt \pgf@y=-\pgf@y\fi \pgf@process{\pgfpointadd{}{\centerpoint}}% \fi \fi } } \def\pgfutil@prefix@macrotomacro#1#2{% \expandafter\expandafter\expandafter\def\expandafter\expandafter\expandafter% #1\expandafter\expandafter\expandafter{\expandafter#2#1}} \endinput