diff options
Diffstat (limited to 'graphics/pgf/contrib/tikz-ext/pgflibraryext.shapes.superellipse.code.tex')
-rw-r--r-- | graphics/pgf/contrib/tikz-ext/pgflibraryext.shapes.superellipse.code.tex | 198 |
1 files changed, 198 insertions, 0 deletions
diff --git a/graphics/pgf/contrib/tikz-ext/pgflibraryext.shapes.superellipse.code.tex b/graphics/pgf/contrib/tikz-ext/pgflibraryext.shapes.superellipse.code.tex new file mode 100644 index 0000000000..9a89b5a8a6 --- /dev/null +++ b/graphics/pgf/contrib/tikz-ext/pgflibraryext.shapes.superellipse.code.tex @@ -0,0 +1,198 @@ +% 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 |