% 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
