Orthogonale Projektionen auf Ellipsoide in TikZ

Orthogonale Projektionen auf Ellipsoide in TikZ

In TikZ möchte ich die orthogonale Projektion von einem Punkt auf eine (gedrehte und verschobene) Ellipse zeichnen. Als konkretes Beispiel möchte ich die kürzeste Linie vom Punkt im Bild zur Ellipse zeichnen und vorzugsweise auch den Punkt auf der Ellipse markieren:

Bildbeschreibung hier eingeben

Bei einem Kreis ist mir das gelungen (da der Punkt einfach durch den Schnittpunkt mit dem Kreis und der Linie durch den Punkt selbst und den Mittelpunkt des Kreises gegeben ist). Bei der Ellipse scheint es in TikZ jedoch nicht zu funktionieren.

Der Beispielcode für das obige Bild lautet wie folgt:

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

Antwort1

Ich schlage TikZ + Gradientenabstieg vor

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

Antwort2

Das mathematische Problem und der algorithmische Ansatz

Wie @Thruston andeutet, ist Mathematik erforderlich, um das Problem zu lösen. Wie dem auch sei, dies führt zu einer nicht trivialen (quartischen) Gleichung, die auf analytische Weise schwer zu lösen ist (sehen wir uns entwederähnliche FrageoderAnalyse der Punkt-zu-Ellipse- und Punkt-zu-Ellipsoid-Distanzgleichungen). Die Idee ist also, eine Gleichung numerisch zu lösen.https://wet-robots.ghost.io/simple-method-for-distance-to-ellipse/Ich habe einen geometrischen und stabilen Algorithmus gefunden, der den Punkt (orthogonale Projektion) auf der Ellipse findet, indem er die Entfernung vom ursprünglichen Punkt minimiert.

Der Algorithmus

Die folgenden Schritte und das Bild vermitteln einen Eindruck davon.

  1. VerbindenÖUndPum zu bekommenEin Anfang(dadurch kann der Algorithmus „auf der rechten Seite“ der Ellipse ausgeführt werden).
  2. Zeichnen Sie einen Kreis (blau) und ermitteln Sie den Mittelpunkt der beiden Schnittpunkte mit dem blauen Kreis und der Ellipse.
  3. Verwenden Sie den Mittelpunkt, um einen neuen, kleineren Kreis (lila) zu zeichnen, und wiederholen Sie den Vorgang (z. B. rot, orange, rosa, …).

Bildbeschreibung hier eingeben

Der Code

Der Code benötigt die Pakete tikzund tkz-euclideinsbesondere \usetikzlibrary{intersections}für die Schnittpunkte. Ich verwende, tkz-euclideweil ich mit den Befehlen gut zurechtkomme. Trotzdem können Sie mit reinem Tikz dasselbe Ergebnis erzielen.

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

Bildbeschreibung hier eingeben

Antwort3

Nur zum Vergleich: Sie können dies ganz einfach inMetapostmithilfe des solveMakros und einer passenden Hilfsfunktion.

Bildbeschreibung hier eingeben

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

Dies ist in zusammengefasst, luamplibsodass Sie es mit kompilieren können lualatex.

Anmerkungen

  • solvewird auf den Seiten 176-177 vondas Metafont-Buch.

  • Die Idee besteht darin, dass Sie ein Makro so definieren, foodass foo(x)entweder trueoder ist false. Dann rufen Sie auf, solve foo(a, b)wobei aund bWerte sind, sodass foo(a)wahr und foo(b)falsch ist. solveverwendet eine binäre Suche, um den Randwert zwischen aund zu finden b.

  • In diesem Fall habe ich ein Makro namens definiert, acutedas den dotprodOperator verwendet, um uns mitzuteilen, ob die Tangente am Punkt tder Ellipse einen spitzen Winkel mit der Linie vom pPunkt zum Punkt tder Ellipse bildet.

  • solvefindet den Punkt, an dem der Winkel nicht mehr spitz ist, also den Punkt, an dem die Linie zu porthogonal zur Tangente ist und daher am nächsten zu liegt p.

  • Es sind einiges Geschick und Urteilsvermögen erforderlich, um die richtigen Anfangswerte für verschiedene Positionen von auszuwählen p.

Wie Sie sehen, ist meine Erklärung etwas länger als der Code ...

verwandte Informationen