TikZ의 타원체에 대한 직교 투영

TikZ의 타원체에 대한 직교 투영

TikZ에서는 한 점에서 (회전 및 이동된) 타원까지 직교 투영을 그리고 싶습니다. 특별한 예로, 그림의 점에서 타원까지 가장 짧은 선을 그리고 바람직하게는 타원에도 점을 표시하고 싶습니다.

여기에 이미지 설명을 입력하세요

나는 원을 사용하여 이 작업을 수행하는 데 성공했습니다(점은 원과 점 자체 및 원의 중심을 통과하는 선과의 교차점에 의해 제공되기 때문입니다). 하지만 타원을 사용하면 TikZ에서 작동하지 않는 것 같습니다.

위 그림의 예제 코드는 다음과 같습니다.

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

답변1

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}

답변2

수학 문제와 알고리즘 접근 방식

@Thruston이 제안한 것처럼 문제를 해결하려면 수학이 필요합니다. 어쨌든 이것은 분석적인 방법으로 풀기 어려운 사소하지 않은(사차) 방정식으로 이어집니다(둘 중 하나를 살펴보겠습니다).비슷한 질문또는점-타원 및 점-타원체 거리 방정식 분석). 그래서 아이디어는 방정식을 수치적으로 해결하는 것입니다. ~에https://wet-robots.ghost.io/simple-method-for-distance-to-ellipse/원점과의 거리를 최소화하여 타원 위의 점(직교 투영)을 찾는 기하학적이고 안정적인 알고리즘을 찾았습니다.

알고리즘

다음 단계와 이미지는 아이디어를 제안합니다.

  1. 연결하다영형그리고얻기 위해서A_start(이렇게 하면 타원의 "오른쪽"에서 알고리즘을 실행할 수 있습니다).
  2. 원(파란색)을 그리고 파란색 원과 타원이 있는 두 교차점의 중간점을 얻습니다.
  3. 중간점을 사용하여 새로운 작은 원(보라색)을 그리고 프로세스를 반복합니다(예: 빨간색, 주황색, 분홍색 등).

여기에 이미지 설명을 입력하세요

코드

코드에는 패키지 tikz, tkz-euclide특히 \usetikzlibrary{intersections}교차점이 필요합니다. tkz-euclide명령이 기분이 좋아서 사용합니다 . 어쨌든 순수 tikz에서도 동일한 결과를 얻을 수 있습니다.

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

여기에 이미지 설명을 입력하세요

답변3

비교를 위해 다음과 같이 매우 간단하게 이 작업을 수행할 수 있습니다.메타포스트solve매크로와 적절한 도우미 기능을 사용합니다 .

여기에 이미지 설명을 입력하세요

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

이것은 로 포장되어 luamplib있으므로 lualatex.

노트

  • solve176~177페이지에 설명되어 있습니다.메타폰트 책.

  • 아이디어는 또는 와 foo같은 매크로를 정의한다는 것입니다 . 그런 다음 where 및 is 값이 true이고 false 인지 호출합니다 . 이진 검색을 사용하여 과 사이의 간선 값을 찾습니다 .foo(x)truefalsesolve foo(a, b)abfoo(a)foo(b)solveab

  • 이 경우 나는 타원 점의 접선이 타원 점 사이의 선과 예각을 이루는 지 여부를 알려주기 위해 연산자를 acute사용하는 매크로를 정의했습니다.dotprodtpt

  • solve각도가 더 이상 예각이 아닌 지점을 찾습니다. 따라서 이 지점은 에 대한 선이 접선 p에 직교하고 에 가장 가까운 지점입니다 p.

  • 의 다양한 위치에 대한 올바른 초기 값을 선택하려면 약간의 기술과 판단이 필요합니다 p.

보시다시피 내 설명은 코드보다 더 깁니다 ...

관련 정보