Projeções ortogonais em elipsóides em TikZ

Projeções ortogonais em elipsóides em TikZ

No TikZ, quero desenhar a projeção ortogonal de um ponto para uma elipse (girada e deslocada). Como exemplo específico, eu gostaria de desenhar a linha mais curta do ponto na imagem até a elipse e, de preferência, marcar também o ponto na elipse:

insira a descrição da imagem aqui

Consegui fazer isso com um círculo (já que o ponto é dado apenas pela interseção com o círculo e a linha que passa pelo próprio ponto e pelo centro do círculo). Mas com a elipse, não consigo fazê-la funcionar no TikZ.

O código de exemplo para a imagem acima é o seguinte:

\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}

Responder1

Eu sugiro TikZ + descida gradiente

\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}

Responder2

O problema matemático e a abordagem algorítmica

Como sugere @Thruston, a matemática é necessária para resolver o problema. De qualquer forma, isso leva a uma equação não trivial (quártica) que é difícil de resolver do modo analítico (vamos dar uma olhada empergunta semelhanteouAnálise de equações de distância ponto a elipse e ponto a elipsóide). Então a ideia é resolver essa equação numericamente. Sobrehttps://wet-robots.ghost.io/simple-method-for-distance-to-ellipse/Encontrei um algoritmo geométrico e estável que encontra o ponto (projeção ortogonal) na elipse minimizando a distância do ponto original.

O algoritmo

Os passos a seguir e a imagem irão sugerir a ideia.

  1. ConectarÓePpara conseguirUm começo(isso permite executar o algoritmo "no lado direito" da elipse).
  2. Desenhe um círculo (azul) e obtenha o ponto médio das duas interseções com o círculo azul e a elipse.
  3. Use o ponto médio para desenhar um novo círculo menor (roxo) e repetir o processo (ou seja, vermelho, laranja, rosa,...)

insira a descrição da imagem aqui

O código

O código precisa dos pacotes tikze tkz-euclide, em particular, \usetikzlibrary{intersections}dos pontos de intersecção. Eu uso tkz-euclideporque me sinto bem com os comandos. De qualquer forma, você pode obter o mesmo resultado em 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}

insira a descrição da imagem aqui

Responder3

Apenas para comparação, você pode fazer isso de forma muito simples emMetapostusando a solvemacro e uma função auxiliar adequada.

insira a descrição da imagem aqui

\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}

Isso está incluído luamplibpara que você possa compilá-lo com o lualatex.

Notas

  • solveé explicado nas páginas 176-177 deo livro Metafont.

  • A ideia é que você defina a macro foocomo foo(x)ou . Então você chama onde e são valores que são verdadeiros e falsos. usa uma pesquisa binária para encontrar o valor da borda entre e .truefalsesolve foo(a, b)abfoo(a)foo(b)solveab

  • Neste caso defini uma macro chamada acuteque usa o dotprodoperador para nos dizer se a tangente no ponto tda elipse forma um ângulo agudo com a linha que vai do pponto tda elipse.

  • solveencontra o ponto em que o ângulo não é mais agudo, que é, portanto, o ponto em que a linha to pé ortogonal à tangente e é, portanto, o mais próximo de p.

  • É necessária alguma habilidade e julgamento para escolher os valores iniciais corretos para diferentes posições de p.

Como você pode ver, minha explicação é um pouco mais longa que o código ...

informação relacionada