Proyecciones ortogonales sobre elipsoides en TikZ

Proyecciones ortogonales sobre elipsoides en TikZ

En TikZ, quiero dibujar la proyección ortogonal desde un punto hasta una elipse (girada y desplazada). Como ejemplo particular, me gustaría dibujar la línea más corta desde el punto de la imagen hasta la elipse y preferiblemente marcar también el punto en la elipse:

ingrese la descripción de la imagen aquí

He logrado hacer esto con un círculo (ya que el punto viene dado por la intersección con el círculo y la línea que pasa por el punto mismo y el centro del círculo). Pero con la elipse, parece que no consigo que funcione en TikZ.

El código de ejemplo para la imagen de arriba es el siguiente:

\documentclass{standalone}
\usepackage{tikz,tkz-euclide}

\begin{document}

\newcommand{\boundellipse}[3]% center, xdim, ydim
{(#1) ellipse (#2 and #3)
}

\begin{tikzpicture}

\draw[shift={(-0.875,0)},rotate=25] \boundellipse{0,0}{1}{3};%left

\node at (0,4)[circle,fill,inner sep=1.5pt]{};

\end{tikzpicture}

\end{document}

Respuesta1

Sugiero descenso de gradiente TikZ +

\documentclass[tikz]{standalone}
\usepackage{tikz,tkz-euclide}

\begin{document}

\newcommand{\boundellipse}[3]% center, xdim, ydim
    {(#1) ellipse (#2 and #3)}

\makeatletter
\xdef\sx{-0.875} % shift x
\xdef\sy{0} % shift y
\xdef\ra{1} % radius a
\xdef\rb{3} % radius b
\xdef\ro{25} % rotation
\pgfpointxy{0}{4}
\xdef\Px{\the\pgf@x}\xdef\Py{\the\pgf@y}

% let \ang ("angle") be a free variable and run gradient descent
\def\ang{234} % choose your favorite initial value
\foreach\iterationcounter in{1,...,20}{
    \begin{tikzpicture}
        \draw(-5,-3)rectangle(1,5);
        \draw[shift={(-0.875,0)},rotate=25] \boundellipse{0,0}{1}{3};
        \node at (0,4)[circle,fill,inner sep=1.5pt]{};
        % evaluate Ellipse(\ang)
        \pgfpointxy{\sx + \rb*cos(\ang)*sin(\ro) + \ra*sin(\ang)*cos(\ro)}
                    {\sy - \rb*cos(\ang)*cos(\ro) + \ra*sin(\ang)*sin(\ro)}
        \xdef\Qx{\the\pgf@x}\xdef\Qy{\the\pgf@y}
        \draw(\Qx,\Qy)circle(.1);
        % evaluate diff vector to target point
        \xdef\Dx{\the\dimexpr\Px-\Qx}
        \xdef\Dy{\the\dimexpr\Py-\Qy}
        \draw[red,->](\Qx,\Qy)--+(\Dx,\Dy);
        % evaluate tangent line = d Ellipse(\ang) / d\ang 
        \pgfpointxy{- \rb*sin(\ang)*sin(\ro) + \ra*cos(\ang)*cos(\ro)}
                    {+ \rb*sin(\ang)*cos(\ro) + \ra*cos(\ang)*sin(\ro)}
        \xdef\Tx{\the\pgf@x}
        \xdef\Ty{\the\pgf@y}
        \draw[blue,->](\Qx,\Qy)--+(\Tx,\Ty);
        % inner product
        \pgfmathsetmacro\Inn{\Dx*\Tx + \Dy*\Ty}
        % rescale inner product
        \pgfmathsetmacro\inn{\Inn / sqrt(\Tx*\Tx+\Ty*\Ty)}
        \message{^^J thinbold: \inn ^^J}
        % update angle
        \pgfmathsetmacro\ang{\ang + \inn/10} % /10 is the step length
        \xdef\ang{\ang}
    \end{tikzpicture}
}

\end{document}

Respuesta2

El problema matemático y el enfoque algorítmico

Como sugiere @Thruston, se necesitan matemáticas para resolver el problema. De todos modos, esto conduce a una ecuación no trivial (cuártica) que es difícil de resolver de forma analítica (echemos un vistazo apregunta similaroAnálisis de ecuaciones de distancia punto a elipse y punto a elipsoide). Entonces la idea es resolver esa ecuación numéricamente. Enhttps://wet-robots.ghost.io/simple-method-for-distance-to-ellipse/Encontré un algoritmo geométrico y estable que encuentra el punto (proyección ortogonal) en la elipse minimizando la distancia desde el punto original.

el algoritmo

Los siguientes pasos y la imagen te sugerirán la idea.

  1. ConectarohyPAGpara poder conseguirUn inicio(esto permite ejecutar el algoritmo "en el lado derecho" de la elipse).
  2. Dibuja un círculo (azul) y obtén el punto medio de las dos intersecciones con el círculo azul y la elipse.
  3. Utilice el punto medio para dibujar un nuevo círculo más pequeño (morado) e iterar el proceso (es decir, rojo, naranja, rosa,...)

ingrese la descripción de la imagen aquí

El código

El código necesita los paquetes tikzy tkz-euclide, en particular, \usetikzlibrary{intersections}los puntos de intersección. Lo uso tkz-euclideporque me siento bien con los comandos. De todos modos puedes obtener el mismo resultado en tikz puro.

\begin{tikzpicture}

% INITIAL DATA %
% the arbitrary point P
\tkzDefPoint(3,2){P}
% the center of the ellipse
\tkzDefPoint(0,0){O}
% use rotate=angle to set the desired orientation
\path[draw,name path=theellipse,rotate=20] (O) ellipse (2cm and 1cm);
\tkzLabelPoints[above right](P)
\tkzLabelPoints[below left](O)

% STARTING POINT OF ALGORITHM %
\path[name path=OP] (O)--(P);
\path[name intersections={of=OP and theellipse,by={Aone}}];
% comment/erase if need next three code lines
\tkzLabelPoint[above left](Aone){$A_{\textrm{start}}$}
\tkzDrawCircle[help lines](P,Aone)
\tkzDrawPoints(Aone)

% ALGORITHM TO FIND THE ORTHOGONAL PROJECTION %
% set up a different number of steps if needed
% (algorithm converges relatively fast)
\foreach \i in {1,...,3}
{
% define a circle with center P through Aone
% (Astart for the first step)
\tkzDefCircle[radius](P,Aone)
\tkzGetLength{dPAone}
\path[name path=circle] (P) circle (\dPAone pt);

% find intersections of circle with ellipse (Aone, Atwo)
\path[name intersections={of=circle and theellipse,by={Atwo,Aone}}];

% find a "proper" midpoint of Aone -- Atwo on the ellipse
\tkzDefMidPoint(Aone,Atwo)\tkzGetPoint{Aone}
\path[name path=PAone] (P)--(Aone);
\path[name intersections={of=PAone and theellipse,by={Aone}}];
}


% GET AND PRINT OUT THE DISTANCE
\tkzDrawPoints(O,P,Aone)
\tkzDrawSegment[red](P,Aone)
\end{tikzpicture}

ingrese la descripción de la imagen aquí

Respuesta3

Sólo a modo de comparación, puedes hacer esto de forma muy sencilla enMetapostutilizando la solvemacro y una función auxiliar adecuada.

ingrese la descripción de la imagen aquí

\documentclass[border=5mm]{standalone}
\usepackage{luamplib}
\begin{document}
\mplibtextextlabel{enable}
\begin{mplibcode}
beginfig(1);

    path e; pair p; numeric k;
    e = fullcircle xscaled 233 yscaled 144 rotated 10;
    p = 160 dir 142;

    vardef acute(expr t) =
        direction t of e dotprod (p - point t of e) > 0
    enddef;

    k = solve acute(0, 4);

    drawarrow p -- point k of e withcolor red;
    draw e; 
    dotlabel.top(btex $p$ etex, p);

endfig;
\end{mplibcode}
\end{document}

Esto está incluido luamplibpara que puedas compilarlo con lualatex.

Notas

  • solvese explica en las páginas 176-177 deel libro metafont.

  • La idea es que definas una macro foode modo que foo(x)sea trueo false. Luego llamas solve foo(a, b)a donde ay bson valores tales que foo(a)son verdaderos y foo(b)falsos. solveutiliza una búsqueda binaria para encontrar el valor del borde entre ay b.

  • En este caso he definido una macro llamada acuteque usa el dotprodoperador para decirnos si la tangente en el punto tde la elipse forma un ángulo agudo con la línea que va desde pel punto tde la elipse.

  • solveencuentra el punto en el que el ángulo ya no es agudo, que por tanto es el punto en el que la recta a pes ortogonal a la tangente y, por tanto, es la más cercana a p.

  • Se requiere cierta habilidad y criterio para elegir los valores iniciales correctos para diferentes posiciones de p.

Como puedes ver mi explicación es bastante más larga que el código...

información relacionada