Mejorando las patatas TikZ

Mejorando las patatas TikZ

Mi objetivo es proporcionar herramientas para dibujar algunas formas irregulares más fácilmente. Por supuesto, soy consciente de las tramas fluidas proporcionadas por Ti.kZ, pero mi objetivo es permitir un enfoque alternativo. Muy a menudo, las formas están más o menos definidas por algunos puntos extremos, en los cuales la distancia al baricentro de la forma es extrema (los ejemplos se muestran a continuación). Pude obtener algunas formas, pero sólo a expensas de tomar prestadas rutinas de otros lugares, que cito, y estas rutinas parecen ser más complejas de lo necesario. Además, mi código sólo trata 4 coordenadas. En principio, ahora sé cómo ampliarlo, pero creo que debería simplificar las cosas antes. Este es mi código hasta ahora:

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{calc}
\usetikzlibrary{hobby}
\makeatletter % from https://tex.stackexchange.com/a/283273/121799
% Here we define the comparison macro for pairs (a,b)
% We assume decimal numbers acceptable to \ifdim tests
\long\def\xintdothis #1#2\xintorthat #3{\fi #1}%
\let\xintorthat \@firstofone

\long\def\@thirdoffour  #1#2#3#4{#3}%
\long\def\@fourthoffour #1#2#3#4{#4}%

\def\IfFirstPairIsGreaterTF #1#2{\@IfFirstPairIsGreaterTF #1,#2,}%

\def\@IfFirstPairIsGreaterTF #1,#2,#3,#4,{%
    \ifdim #1\p@=#3\p@
       \xintdothis{%
         \ifdim #2\p@>#4\p@\expandafter\@firstoftwo
         \else\expandafter\@secondoftwo\fi}\fi
    \ifdim #1\p@>#3\p@\expandafter\@thirdoffour
                      \else\expandafter\@fourthoffour\fi
    \xintorthat{}%
}%

% not needed for numerical inputs
% \catcode`! 3
% \catcode`? 3

% Here there is a very strange \romannumeral0\romannumeral0, this is
% due to some convoluted scheme to avoid double spaces or no spaces
% in between coordinate pairs. Trust me.
\def\QSpairs {\romannumeral0\romannumeral0\qspairs }%
% first we check if empty list
\def\qspairs   #1{\expandafter\qspairs@a\romannumeral-`0#1(!)(?)}%
\def\qspairs@a #1(#2{\ifx!#2\expandafter\qspairs@abort\else
                        \expandafter\qspairs@b\fi (#2}%
\edef\qspairs@abort #1(?){\space\space}%
%
% we check if empty of single and if not pick up the first as Pivot:
\def\qspairs@b #1(#2)#3(#4){\ifx?#4\xintdothis\qspairs@empty\fi
                   \ifx!#4\xintdothis\qspairs@single\fi
                   \xintorthat \qspairs@separate {}{}{#2}(#4)}%
\def\qspairs@empty  #1(?){ }%
\edef\qspairs@single #1#2#3#4(?){\space\space(#3)}%
\def\qspairs@separate #1#2#3#4(#5)%
{%
    \ifx!#5\expandafter\qspairs@separate@done\fi
    \IfFirstPairIsGreaterTF {#5}{#3}%
          \qspairs@separate@appendtogreater
          \qspairs@separate@appendtosmaller {#5}{#1}{#2}{#3}%
}%
%
\def\qspairs@separate@appendtogreater #1#2{\qspairs@separate {#2 (#1)}}%
\def\qspairs@separate@appendtosmaller #1#2#3{\qspairs@separate {#2}{#3 (#1)}}%
%
\def\qspairs@separate@done\IfFirstPairIsGreaterTF #1#2%
    \qspairs@separate@appendtogreater
    \qspairs@separate@appendtosmaller #3#4#5#6(?)%
{%
    \expandafter\qspairs@f\expandafter
    {\romannumeral0\qspairs@b #4(!)(?)}{\qspairs@b #5(!)(?)}{ (#2)}%
}%
%
\def\qspairs@f #1#2#3{#2#3#1}%
%
% \catcode`! 12
% \catcode`? 12

\makeatother
\makeatletter % from https://tex.stackexchange.com/a/412901/121799
\newcommand{\Distance}[3]{% % from https://tex.stackexchange.com/q/56353/121799
\tikz@scan@one@point\pgfutil@firstofone($#1-#2$)\relax  
\pgfmathsetmacro{#3}{veclen(\the\pgf@x,\the\pgf@y)/28.45274}
}
\makeatother 
\newcount\nbofwords
\makeatletter% from https://tex.stackexchange.com/a/12819/121799
\def\myutil@empty{}
\def\multiwords#1 #2\@nil{% 
 \def\NextArg{#2}%
 \advance\nbofwords by  1 %   
 \expandafter\edef\csname word\@alph\nbofwords\endcsname{#1}% 
 \ifx\myutil@empty\NextArg
     \let\next\@gobble
 \fi
 \next#2\@nil
}%    
\def\GetWords#1{%
   \let\next\multiwords 
   \nbofwords=0 %
   \expandafter\next#1 \@nil %
}% 
\makeatother

\long\def\First(#1,#2){#1}
\long\def\Second(#1,#2){#2}
\tikzset{declare
function={interpolator(\x,\xmin,\xmax,\rmin,\rmax)=(\rmin+\rmax)/2+((\rmin-\rmax)/2)*cos((\x-\xmin)*(180/(\xmax-\xmin)));}}
%\tikzset{declare function={PotatoeRadius(\x,\angleA,\angleB,\angleC,\angleD,\distanceA,\distanceB,\distanceC,\distanceD)=\distanceA+(\x-\angleA)*((\distanceB-\distanceA)/(\angleB-\angleA)+(\x-\angleB)*(((-1)*((\distanceB-\distanceA)/(\angleB-\angleA))+(\distanceC-\distanceB)/(\angleC-\angleB))/(\angleC-\angleA)+(((-1)*(((-1)*((\distanceB-\distanceA)/(\angleB-\angleA))+(\distanceC-\distanceB)/(\angleC-\angleB))/(\angleC-\angleA))+((-1)*((\distanceC-\distanceB)/(\angleC-\angleB))+(\distanceD-\distanceC)/(\angleD-\angleC))/(\angleD-\angleB))*(\x-\angleC))/(\angleD-\angleA)));}}
%(\angleC*(\angleC-\angleD)*\angleD*((\distanceA-\distanceB)*(\angleC-\x)*(\angleD-\x)*\x+pow(\angleA,3)*(-(\angleC*pow(\angleD,2)*\distanceB)+\angleD*(\distanceB-\distanceC)*(\angleD-\x)*\x+\angleC*(\distanceB-\distanceD)*pow(\x,2)+pow(\angleC,2)*(\angleD*\distanceB+(-\distanceB+\distanceD)*\x))+pow(\angleB,3)*(-(\angleA*pow(\angleD,2)*\distanceC)-\angleD*(\distanceA-\distanceC)*(\angleD-\x)*\x+\angleA*(\distanceC-\distanceD)*pow(\x,2)+pow(\angleC,2)*(-(\angleD*\distanceA)+\angleA*\distanceD+\distanceA*\x-\distanceD*\x)+pow(\angleA,2)*(\angleD*\distanceC-\distanceC*\x+\distanceD*\x)+\angleC*(pow(\angleD,2)*\distanceA-pow(\angleA,2)*\distanceD+(-\distanceA+\distanceD)*pow(\x,2)))+pow(\angleA,2)*(-(\angleD*(\distanceB-\distanceC)*(\angleD-\x)*\x*(\angleD+\x))-pow(\angleC,3)*(\angleD*\distanceB+(-\distanceB+\distanceD)*\x)+\angleC*(pow(\angleD,3)*\distanceB+(-\distanceB+\distanceD)*pow(\x,3)))+\angleA*(pow(\angleD,2)*(\distanceB-\distanceC)*(\angleD-\x)*pow(\x,2)+pow(\angleC,3)*(pow(\angleD,2)*\distanceB+(-\distanceB+\distanceD)*pow(\x,2))-pow(\angleC,2)*(pow(\angleD,3)*\distanceB+(-\distanceB+\distanceD)*pow(\x,3)))+pow(\angleB,2)*(\angleD*(\distanceA-\distanceC)*(\angleD-\x)*\x*(\angleD+\x)+pow(\angleC,3)*(\angleD*\distanceA-\angleA*\distanceD-\distanceA*\x+\distanceD*\x)-pow(\angleA,3)*(\angleD*\distanceC+(-\distanceC+\distanceD)*\x)+\angleC*(-(pow(\angleD,3)*\distanceA)+pow(\angleA,3)*\distanceD+(\distanceA-\distanceD)*pow(\x,3))+\angleA*(pow(\angleD,3)*\distanceC+(-\distanceC+\distanceD)*pow(\x,3)))+\angleB*(-(pow(\angleD,2)*(\distanceA-\distanceC)*(\angleD-\x)*pow(\x,2))+pow(\angleC,3)*(-(pow(\angleD,2)*\distanceA)+pow(\angleA,2)*\distanceD+(\distanceA-\distanceD)*pow(\x,2))+pow(\angleA,3)*(pow(\angleD,2)*\distanceC+(-\distanceC+\distanceD)*pow(\x,2))+pow(\angleC,2)*(pow(\angleD,3)*\distanceA-pow(\angleA,3)*\distanceD+(-\distanceA+\distanceD)*pow(\x,3))-pow(\angleA,2)*(pow(\angleD,3)*\distanceC+(-\distanceC+\distanceD)*pow(\x,3))))/((\angleA-\angleB)*(\angleA-\angleC)*(\angleB-\angleC)*(\angleA-\angleD)*(\angleB-\angleD)*(\angleC-\angleD)));}}
\newcommand{\DrawArcAngle}[6][]{% just for emergencies
\pgfmathanglebetweenpoints{\pgfpointanchor{#3}{center}}{\pgfpointanchor{#2}{center}}
\xdef\angleA{\pgfmathresult}
\pgfmathanglebetweenpoints{\pgfpointanchor{#3}{center}}{\pgfpointanchor{#4}{center}}
\xdef\angleB{\pgfmathresult}
\draw[#1] ($(#3)+(\angleA:#5)$) arc [start angle=\angleA,end angle=\angleB,radius=#5]
#6;
}
\newcommand{\DrawPotato}[5][]{
\coordinate (PotatoCenter) at (barycentric cs:#2=1,#3=1,#4=1,#5=1);
\pgfmathanglebetweenpoints{\pgfpointanchor{PotatoCenter}{center}}{\pgfpointanchor{#2}{center}}
\xdef\angleA{\pgfmathresult}
\pgfmathanglebetweenpoints{\pgfpointanchor{PotatoCenter}{center}}{\pgfpointanchor{#3}{center}}
\xdef\angleB{\pgfmathresult}
\pgfmathanglebetweenpoints{\pgfpointanchor{PotatoCenter}{center}}{\pgfpointanchor{#4}{center}}
\xdef\angleC{\pgfmathresult}
\pgfmathanglebetweenpoints{\pgfpointanchor{PotatoCenter}{center}}{\pgfpointanchor{#5}{center}}
\xdef\angleD{\pgfmathresult}

\Distance{(PotatoCenter)}{(#2)}{\distanceA}
\Distance{(PotatoCenter)}{(#3)}{\distanceB}
\Distance{(PotatoCenter)}{(#4)}{\distanceC}
\Distance{(PotatoCenter)}{(#5)}{\distanceD}
\xdef\coordList{(\angleA,\distanceA) (\angleB,\distanceB) (\angleC,\distanceC) (\angleD,\distanceD)}%
\typeout{\coordList}
\xdef\sortedList{\QSpairs{\coordList}}%
\GetWords{\sortedList}
\xdef\NewList{\worda,\wordb,\wordc,\wordd}%
\xdef\NewList{\expandafter\First\worda/\expandafter\Second\worda, 
\expandafter\First\wordb/\expandafter\Second\wordb,
\expandafter\First\wordc/\expandafter\Second\wordc,
\expandafter\First\wordd/\expandafter\Second\wordd}% this list is not used
\xdef\angleA{\expandafter\First\worda}%
\xdef\distanceA{\expandafter\Second\worda}%
\xdef\angleB{\expandafter\First\wordb}%
\xdef\distanceB{\expandafter\Second\wordb}%
\xdef\angleC{\expandafter\First\wordc}%
\xdef\distanceC{\expandafter\Second\wordc}%
\xdef\angleD{\expandafter\First\wordd}%
\xdef\distanceD{\expandafter\Second\wordd}%
\begin{scope}[shift=(PotatoCenter)]
\draw[#1,smooth,samples=50] plot[variable=\x,domain=\angleA:\angleB] %
(\x:{interpolator(\x,\angleA,\angleB,\distanceA,\distanceB)})
-- 
plot[variable=\x,domain=\angleB:\angleC] %
(\x:{interpolator(\x,\angleB,\angleC,\distanceB,\distanceC)})
--
plot[variable=\x,domain=\angleC:\angleD] %
(\x:{interpolator(\x,\angleC,\angleD,\distanceC,\distanceD)})
--
plot[variable=\x,domain=\angleD:{\angleA+360}] %
(\x:{interpolator(\x,\angleD,{\angleA+360},\distanceD,\distanceA)});
\end{scope}
}
\begin{document}
\begin{tabular}{cc}
potato & potato (ordering) \\
\begin{tikzpicture}
\coordinate (A) at (-1,1);
\coordinate (B) at (3,0.5);
\coordinate (C) at (4,-1);
\coordinate (D) at (1,-1);
\foreach \p in {A,B,C,D}
{\draw[fill=black] (\p) circle (1pt);}
\DrawPotato[blue]{A}{B}{C}{D}
\draw[red] plot[smooth cycle,tension=1] coordinates{(A) (B) (C) (D)};
\end{tikzpicture}& 
\begin{tikzpicture}
\coordinate (A) at (-1,1);
\coordinate (B) at (3,0.5);
\coordinate (C) at (4,-1);
\coordinate (D) at (1,-1);
\foreach \p in {A,B,C,D}
{\draw[fill=black] (\p) circle (1pt);}
\DrawPotato[blue]{A}{C}{B}{D}
\draw[purple] plot[smooth cycle,tension=1] coordinates{(A) (C) (B) (D)};
\end{tikzpicture}
\end{tabular}
\begin{tabular}{ll}
filled potato&filled peanut\\
\begin{tikzpicture}
\coordinate (A) at (-1,1);
\coordinate (B) at (3,0.5);
\coordinate (C) at (4,-1);
\coordinate (D) at (1,-1);
\foreach \p in {A,B,C,D}
{\draw[fill=black] (\p) circle (1pt);}
\DrawPotato[fill=blue]{A}{C}{B}{D}
\end{tikzpicture}
&
\begin{tikzpicture}
\coordinate (A) at (-1,1);
\coordinate (B) at (2,0.5);
\coordinate (C) at (4,-1);
\coordinate (D) at (1,-1);
\foreach \p in {A,B,C,D}
{\draw[fill=black] (\p) circle (1pt);}
\DrawPotato[blue,fill=red]{A}{B}{C}{D}
\begin{scope}[closed hobby]
\draw[thick] plot  coordinates{(A) (B) (C) (D)};
\end{scope}
\end{tikzpicture}
\end{tabular}
\end{document}

ingrese la descripción de la imagen aquí

No es difícil ver que el código es un verdadero desastre, pero hace más o menos lo que quiero, es decir, dibuja patatas definidas por los puntos extremos (marcados con viñetas negras). A modo de comparación (las comparaciones nunca son justas ;-) también dibujo los resultados de los gráficos suaves mencionados anteriormente. Mi verdadera pregunta es cómo se pueden simplificar las cosas, lo más importante

  • el orden angular de las coordenadas,

  • mi forma de hacer que las formas sean "rellenables" ciertamente no es óptima,

  • el análisis de las coordenadas ordenadas en una macro que acepta un número arbitrario de puntos (es decir, 4 o más puntos). Cualquier comentario es muy bienvenido.

EDITAR: Se agregó el resultado del algoritmo Hobby en la figura del maní para comparar.

ACTUALIZAR: "Papa" corregida. Para mí está claro que con una buena cantidad de ajustes adicionales se pueden recrear estas formas con gráficos suaves o gráficos Hobby. Sin embargo, el objetivo aquí es evitar estos ajustes adicionales. Por supuesto, si alguien pudiera indicarme un diccionario que me permita traducir el código de la papa al lenguaje Hobby, sería genial.

SEGUNDA ACTUALIZACIÓN: Agregué una animación simple que ilustra lo que hace el código hasta ahora.

\documentclass{beamer}
\usepackage{tikz}
\usetikzlibrary{calc}
%\usetikzlibrary{hobby}
\makeatletter % from https://tex.stackexchange.com/a/283273/121799
% Here we define the comparison macro for pairs (a,b)
% We assume decimal numbers acceptable to \ifdim tests
\long\def\xintdothis #1#2\xintorthat #3{\fi #1}%
\let\xintorthat \@firstofone

\long\def\@thirdoffour  #1#2#3#4{#3}%
\long\def\@fourthoffour #1#2#3#4{#4}%

\def\IfFirstPairIsGreaterTF #1#2{\@IfFirstPairIsGreaterTF #1,#2,}%

\def\@IfFirstPairIsGreaterTF #1,#2,#3,#4,{%
    \ifdim #1\p@=#3\p@
       \xintdothis{%
         \ifdim #2\p@>#4\p@\expandafter\@firstoftwo
         \else\expandafter\@secondoftwo\fi}\fi
    \ifdim #1\p@>#3\p@\expandafter\@thirdoffour
                      \else\expandafter\@fourthoffour\fi
    \xintorthat{}%
}%

% not needed for numerical inputs
% \catcode`! 3
% \catcode`? 3

% Here there is a very strange \romannumeral0\romannumeral0, this is
% due to some convoluted scheme to avoid double spaces or no spaces
% in between coordinate pairs. Trust me.
\def\QSpairs {\romannumeral0\romannumeral0\qspairs }%
% first we check if empty list
\def\qspairs   #1{\expandafter\qspairs@a\romannumeral-`0#1(!)(?)}%
\def\qspairs@a #1(#2{\ifx!#2\expandafter\qspairs@abort\else
                        \expandafter\qspairs@b\fi (#2}%
\edef\qspairs@abort #1(?){\space\space}%
%
% we check if empty of single and if not pick up the first as Pivot:
\def\qspairs@b #1(#2)#3(#4){\ifx?#4\xintdothis\qspairs@empty\fi
                   \ifx!#4\xintdothis\qspairs@single\fi
                   \xintorthat \qspairs@separate {}{}{#2}(#4)}%
\def\qspairs@empty  #1(?){ }%
\edef\qspairs@single #1#2#3#4(?){\space\space(#3)}%
\def\qspairs@separate #1#2#3#4(#5)%
{%
    \ifx!#5\expandafter\qspairs@separate@done\fi
    \IfFirstPairIsGreaterTF {#5}{#3}%
          \qspairs@separate@appendtogreater
          \qspairs@separate@appendtosmaller {#5}{#1}{#2}{#3}%
}%
%
\def\qspairs@separate@appendtogreater #1#2{\qspairs@separate {#2 (#1)}}%
\def\qspairs@separate@appendtosmaller #1#2#3{\qspairs@separate {#2}{#3 (#1)}}%
%
\def\qspairs@separate@done\IfFirstPairIsGreaterTF #1#2%
    \qspairs@separate@appendtogreater
    \qspairs@separate@appendtosmaller #3#4#5#6(?)%
{%
    \expandafter\qspairs@f\expandafter
    {\romannumeral0\qspairs@b #4(!)(?)}{\qspairs@b #5(!)(?)}{ (#2)}%
}%
%
\def\qspairs@f #1#2#3{#2#3#1}%
%
% \catcode`! 12
% \catcode`? 12

\makeatother
\makeatletter % from https://tex.stackexchange.com/a/412901/121799
\newcommand{\Distance}[3]{% % from https://tex.stackexchange.com/q/56353/121799
\tikz@scan@one@point\pgfutil@firstofone($#1-#2$)\relax  
\pgfmathsetmacro{#3}{veclen(\the\pgf@x,\the\pgf@y)/28.45274}
}
\makeatother 
\newcount\nbofwords
\makeatletter% from https://tex.stackexchange.com/a/12819/121799
\def\myutil@empty{}
\def\multiwords#1 #2\@nil{% 
 \def\NextArg{#2}%
 \advance\nbofwords by  1 %   
 \expandafter\edef\csname word\@alph\nbofwords\endcsname{#1}% 
 \ifx\myutil@empty\NextArg
     \let\next\@gobble
 \fi
 \next#2\@nil
}%    
\def\GetWords#1{%
   \let\next\multiwords 
   \nbofwords=0 %
   \expandafter\next#1 \@nil %
}% 
\makeatother

\long\def\First(#1,#2){#1}
\long\def\Second(#1,#2){#2}
\tikzset{declare
function={interpolator(\x,\xmin,\xmax,\rmin,\rmax)=(\rmin+\rmax)/2+((\rmin-\rmax)/2)*cos((\x-\xmin)*(180/(\xmax-\xmin)));}}
%\tikzset{declare function={PotatoeRadius(\x,\angleA,\angleB,\angleC,\angleD,\distanceA,\distanceB,\distanceC,\distanceD)=\distanceA+(\x-\angleA)*((\distanceB-\distanceA)/(\angleB-\angleA)+(\x-\angleB)*(((-1)*((\distanceB-\distanceA)/(\angleB-\angleA))+(\distanceC-\distanceB)/(\angleC-\angleB))/(\angleC-\angleA)+(((-1)*(((-1)*((\distanceB-\distanceA)/(\angleB-\angleA))+(\distanceC-\distanceB)/(\angleC-\angleB))/(\angleC-\angleA))+((-1)*((\distanceC-\distanceB)/(\angleC-\angleB))+(\distanceD-\distanceC)/(\angleD-\angleC))/(\angleD-\angleB))*(\x-\angleC))/(\angleD-\angleA)));}}
%(\angleC*(\angleC-\angleD)*\angleD*((\distanceA-\distanceB)*(\angleC-\x)*(\angleD-\x)*\x+pow(\angleA,3)*(-(\angleC*pow(\angleD,2)*\distanceB)+\angleD*(\distanceB-\distanceC)*(\angleD-\x)*\x+\angleC*(\distanceB-\distanceD)*pow(\x,2)+pow(\angleC,2)*(\angleD*\distanceB+(-\distanceB+\distanceD)*\x))+pow(\angleB,3)*(-(\angleA*pow(\angleD,2)*\distanceC)-\angleD*(\distanceA-\distanceC)*(\angleD-\x)*\x+\angleA*(\distanceC-\distanceD)*pow(\x,2)+pow(\angleC,2)*(-(\angleD*\distanceA)+\angleA*\distanceD+\distanceA*\x-\distanceD*\x)+pow(\angleA,2)*(\angleD*\distanceC-\distanceC*\x+\distanceD*\x)+\angleC*(pow(\angleD,2)*\distanceA-pow(\angleA,2)*\distanceD+(-\distanceA+\distanceD)*pow(\x,2)))+pow(\angleA,2)*(-(\angleD*(\distanceB-\distanceC)*(\angleD-\x)*\x*(\angleD+\x))-pow(\angleC,3)*(\angleD*\distanceB+(-\distanceB+\distanceD)*\x)+\angleC*(pow(\angleD,3)*\distanceB+(-\distanceB+\distanceD)*pow(\x,3)))+\angleA*(pow(\angleD,2)*(\distanceB-\distanceC)*(\angleD-\x)*pow(\x,2)+pow(\angleC,3)*(pow(\angleD,2)*\distanceB+(-\distanceB+\distanceD)*pow(\x,2))-pow(\angleC,2)*(pow(\angleD,3)*\distanceB+(-\distanceB+\distanceD)*pow(\x,3)))+pow(\angleB,2)*(\angleD*(\distanceA-\distanceC)*(\angleD-\x)*\x*(\angleD+\x)+pow(\angleC,3)*(\angleD*\distanceA-\angleA*\distanceD-\distanceA*\x+\distanceD*\x)-pow(\angleA,3)*(\angleD*\distanceC+(-\distanceC+\distanceD)*\x)+\angleC*(-(pow(\angleD,3)*\distanceA)+pow(\angleA,3)*\distanceD+(\distanceA-\distanceD)*pow(\x,3))+\angleA*(pow(\angleD,3)*\distanceC+(-\distanceC+\distanceD)*pow(\x,3)))+\angleB*(-(pow(\angleD,2)*(\distanceA-\distanceC)*(\angleD-\x)*pow(\x,2))+pow(\angleC,3)*(-(pow(\angleD,2)*\distanceA)+pow(\angleA,2)*\distanceD+(\distanceA-\distanceD)*pow(\x,2))+pow(\angleA,3)*(pow(\angleD,2)*\distanceC+(-\distanceC+\distanceD)*pow(\x,2))+pow(\angleC,2)*(pow(\angleD,3)*\distanceA-pow(\angleA,3)*\distanceD+(-\distanceA+\distanceD)*pow(\x,3))-pow(\angleA,2)*(pow(\angleD,3)*\distanceC+(-\distanceC+\distanceD)*pow(\x,3))))/((\angleA-\angleB)*(\angleA-\angleC)*(\angleB-\angleC)*(\angleA-\angleD)*(\angleB-\angleD)*(\angleC-\angleD)));}}
\newcommand{\DrawArcAngle}[6][]{% just for emergencies
\pgfmathanglebetweenpoints{\pgfpointanchor{#3}{center}}{\pgfpointanchor{#2}{center}}
\xdef\angleA{\pgfmathresult}
\pgfmathanglebetweenpoints{\pgfpointanchor{#3}{center}}{\pgfpointanchor{#4}{center}}
\xdef\angleB{\pgfmathresult}
\draw[#1] ($(#3)+(\angleA:#5)$) arc [start angle=\angleA,end angle=\angleB,radius=#5]
#6;
}
\newcommand{\DrawPotato}[5][]{
\coordinate (PotatoCenter) at (barycentric cs:#2=1,#3=1,#4=1,#5=1);
\pgfmathanglebetweenpoints{\pgfpointanchor{PotatoCenter}{center}}{\pgfpointanchor{#2}{center}}
\xdef\angleA{\pgfmathresult}
\pgfmathanglebetweenpoints{\pgfpointanchor{PotatoCenter}{center}}{\pgfpointanchor{#3}{center}}
\xdef\angleB{\pgfmathresult}
\pgfmathanglebetweenpoints{\pgfpointanchor{PotatoCenter}{center}}{\pgfpointanchor{#4}{center}}
\xdef\angleC{\pgfmathresult}
\pgfmathanglebetweenpoints{\pgfpointanchor{PotatoCenter}{center}}{\pgfpointanchor{#5}{center}}
\xdef\angleD{\pgfmathresult}

\Distance{(PotatoCenter)}{(#2)}{\distanceA}
\Distance{(PotatoCenter)}{(#3)}{\distanceB}
\Distance{(PotatoCenter)}{(#4)}{\distanceC}
\Distance{(PotatoCenter)}{(#5)}{\distanceD}
\xdef\coordList{(\angleA,\distanceA) (\angleB,\distanceB) (\angleC,\distanceC) (\angleD,\distanceD)}%
\typeout{\coordList}
\xdef\sortedList{\QSpairs{\coordList}}%
\GetWords{\sortedList}
\xdef\NewList{\worda,\wordb,\wordc,\wordd}%
\xdef\NewList{\expandafter\First\worda/\expandafter\Second\worda, 
\expandafter\First\wordb/\expandafter\Second\wordb,
\expandafter\First\wordc/\expandafter\Second\wordc,
\expandafter\First\wordd/\expandafter\Second\wordd}% this list is not used
\xdef\angleA{\expandafter\First\worda}%
\xdef\distanceA{\expandafter\Second\worda}%
\xdef\angleB{\expandafter\First\wordb}%
\xdef\distanceB{\expandafter\Second\wordb}%
\xdef\angleC{\expandafter\First\wordc}%
\xdef\distanceC{\expandafter\Second\wordc}%
\xdef\angleD{\expandafter\First\wordd}%
\xdef\distanceD{\expandafter\Second\wordd}%
\begin{scope}[shift=(PotatoCenter)]
\draw[#1,smooth,samples=50] plot[variable=\x,domain=\angleA:\angleB] %
(\x:{interpolator(\x,\angleA,\angleB,\distanceA,\distanceB)})
-- 
plot[variable=\x,domain=\angleB:\angleC] %
(\x:{interpolator(\x,\angleB,\angleC,\distanceB,\distanceC)})
--
plot[variable=\x,domain=\angleC:\angleD] %
(\x:{interpolator(\x,\angleC,\angleD,\distanceC,\distanceD)})
--
plot[variable=\x,domain=\angleD:{\angleA+360}] %
(\x:{interpolator(\x,\angleD,{\angleA+360},\distanceD,\distanceA)});
\end{scope}
}
\begin{document}
\begin{frame}
\frametitle{What does the current code do?}
\begin{overlayarea}{\textwidth}{\textheight}
\begin{tikzpicture}
\path[use as bounding box] (-5,-3) rectangle (7,5);
\node[text width=8cm] (text) at (0,3){%
\only<1>{input: four points, here A, B, C \& D}
\only<2>{step one: compute the barycenter of those points}
\only<3>{imagine now a circle around the barycenter with radius equal to the 
average distance}
\only<4>{the code simply adds some sine functions to the radius such that the
contour runs through the points and the distance is extremal at those points}
\only<5>{however, the code is extremely clumsy and slow, and I have the feeling
that I'm re--inventing the wheel when dealing with lists etc.}
};
\coordinate (A) at (-1,1);
\coordinate (B) at (2,0.5);
\coordinate (C) at (4,-1);
\coordinate (D) at (1,-1);
\coordinate (Center) at (barycentric cs:A=1,B=1,C=1,D=1);
\pgfmathsetmacro{\TotalDistance}{0}
\xdef\DistanceList{}
\foreach \p in {A,B,C,D}
{\draw[fill=black] (\p) circle (1pt) node[below]{\p};
}
\Distance{(Center)}{(A)}{\DistanceA}
\Distance{(Center)}{(B)}{\DistanceB}
\Distance{(Center)}{(C)}{\DistanceC}
\Distance{(Center)}{(D)}{\DistanceD}
\pgfmathsetmacro{\AverageDistance}{(\DistanceA+\DistanceB+\DistanceC+\DistanceD)/4}
\pause
\draw[fill=black] (Center) circle (1pt) node[below]{Center};
\pause
\draw[-,dashed] (Center) circle (\AverageDistance);
\pause
\only<4->{
\DrawPotato[blue]{A}{B}{C}{D}
}
\end{tikzpicture}


\end{overlayarea}
\end{frame}
\end{document}

ingrese la descripción de la imagen aquí

Respuesta1

Con las bibliotecas mathy calc, es posible hacerlo un poco más sencillo. Puede invertir dos coordenadas cualesquiera para ver que también funciona para coordenadas que aún no están ordenadas (solo probé el cambio Ay Bdebería funcionar para todas).

No cambié nada entre \begin{document}y \end{document}todavía \Distanceestá allí, pero no lo uso en mi definición, por \DrawPotatolo que realmente no lo necesitas.

ingrese la descripción de la imagen aquí

\documentclass{beamer}
\usepackage{tikz}
\usetikzlibrary{calc,math}

% I don't use this in my \DrawPotato
\makeatletter % from https://tex.stackexchange.com/a/412901/121799
\newcommand{\Distance}[3]{% % from https://tex.stackexchange.com/q/56353/121799
    \tikz@scan@one@point\pgfutil@firstofone($#1-#2$)\relax  
    \pgfmathsetmacro{#3}{veclen(\the\pgf@x,\the\pgf@y)/28.45274}
}
\makeatother

\tikzset{
    declare function={
        interpolator(\x,\xmin,\xmax,\rmin,\rmax)=
            1/28.4527*((\rmin+\rmax)/2+((\rmin-\rmax)/2)*cos((\x-\xmin)*(180/(\xmax-\xmin))));
    }
}

\newcommand\DrawPotato[5][]{%
    \tikzmath{
        coordinate \p,\cent;
        \p0 = {(#2)};
        \p1 = {(#3)};
        \p2 = {(#4)};
        \p3 = {(#5)};
        \cent = ({(\px0+\px1+\px2+\px3)/4},{(\py0+\py1+\py2+\py3)/4}); % Average point
        real \angl,\dist;
        int \i,\j;
        for \i in {0,1,2,3}{
            \angl{\i} = atan2(\py{\i}-\centy,\px{\i}-\centx);
            \dist{\i} = veclen(\py{\i}-\centy,\px{\i}-\centx);
        };
        for \i in {0,1,2,3}{
            for \j in {0,1,2,3}{
                if min(\angl{0},\angl{1},\angl{2},\angl{3}) == \angl{\j} then {
                    \sortang{\i} = \angl{\j};
                    \sortind{\i} = \j;
                };
            };
            \angl{\sortind{\i}} = 500; % Arbitrary large value
            \sortdis{\i} = \dist{\sortind{\i}};
        };
    }
    \draw[#1,smooth,samples=50,shift={(\cent)}] 
        plot[variable=\x,domain=\sortang{0}:\sortang{1}] %
            (\x:{interpolator(\x,{\sortang{0}},{\sortang{1}},{\sortdis{0}},{\sortdis{1}})}) --
        plot[variable=\x,domain=\sortang{1}:\sortang{2}] %
            (\x:{interpolator(\x,{\sortang{1}},{\sortang{2}},{\sortdis{1}},{\sortdis{2}})}) --
        plot[variable=\x,domain=\sortang{2}:\sortang{3}] %
            (\x:{interpolator(\x,{\sortang{2}},{\sortang{3}},{\sortdis{2}},{\sortdis{3}})}) --
        plot[variable=\x,domain=\sortang{3}:\sortang{0}+360] %
            (\x:{interpolator(\x,{\sortang{3}},{\sortang{0}+360},{\sortdis{3}},{\sortdis{0}})}) --
        cycle ;
}

\begin{document}
\begin{frame}
\frametitle{What does the current code do?}
\begin{overlayarea}{\textwidth}{\textheight}
\begin{tikzpicture}
\path[use as bounding box] (-5,-3) rectangle (7,5);
\node[text width=8cm] (text) at (0,3){%
\only<1>{input: four points, here A, B, C \& D}
\only<2>{step one: compute the barycenter of those points}
\only<3>{imagine now a circle around the barycenter with radius equal to the 
average distance}
\only<4>{the code simply adds some sine functions to the radius such that the
contour runs through the points and the distance is extremal at those points}
\only<5>{however, the code is extremely clumsy and slow, and I have the feeling
that I'm re--inventing the wheel when dealing with lists etc.}
};
\coordinate (A) at (-1,1);
\coordinate (B) at (2,0.5);
\coordinate (C) at (4,-1);
\coordinate (D) at (1,-1);
\coordinate (Center) at (barycentric cs:A=1,B=1,C=1,D=1);
\pgfmathsetmacro{\TotalDistance}{0}
\xdef\DistanceList{}
\foreach \p in {A,B,C,D}
{\draw[fill=black] (\p) circle (1pt) node[below]{\p};
}
\Distance{(Center)}{(A)}{\DistanceA}
\Distance{(Center)}{(B)}{\DistanceB}
\Distance{(Center)}{(C)}{\DistanceC}
\Distance{(Center)}{(D)}{\DistanceD}
\pgfmathsetmacro{\AverageDistance}{(\DistanceA+\DistanceB+\DistanceC+\DistanceD)/4}
\pause
\draw[fill=black] (Center) circle (1pt) node[below]{Center};
\pause
\draw[-,dashed] (Center) circle (\AverageDistance);
\pause
\only<4->{
\DrawPotato[blue]{A}{B}{C}{D}
}
\end{tikzpicture}


\end{overlayarea}
\end{frame}
\end{document}

información relacionada