TikZ의 상징적 3D 좌표

TikZ의 상징적 3D 좌표

경고: 이 질문에 답하려면 약간의 노력이 필요할 수 있습니다. 질문의 목적은 "Ti를 가르치는 것입니다.케이Z 3d 좌표". 그게 무슨 뜻인가요? Ti에서 좌표를 정의하면케이지,

 \path (<x>,<y>) coordinate(A);

이 좌표는 A위치를 지정하는 2개의 길이와 연관됩니다. 변환된(이동, 회전, 기울어진) 좌표계에서 우리는 여전히 이 좌표를 참조하고 화살표를 그릴 수 있습니다. 이 질문에서 더 중요한 것은, 우리는 항상 거꾸로 작업하여 다른 좌표에 대한 상대 위치가 무엇인지 알아낼 수 있다는 것입니다(예: 계산 라이브러리를 사용).

\path let \p1=($(A)-(B)$),\n1={veclen(\x1,\y1)},\n2={atan2(\y1,\x1)} in <do something with this information>;

Ti 이후로 3D에서는 불가능합니다.케이Z는 좌표를 자릅니다..

이를 처리할 수 있는 한 가지 방법이 제안되었습니다.이 좋은 대답. 이것은 훌륭하지만 위에서 언급한 calc 구문만큼 원활하게 작동하지는 않습니다. 아마도 더 중요한 것은 3D 좌표를 저장하기 위해 추가 노력을 기울여야 한다는 것입니다. 이상적으로는 다음과 같은 것이 있습니다.

 \path (x,y,z) coordinate(A);

그리고 티케이Z z도 좌표를 기억할 것입니다.

이 요청은 언뜻 보기에 실제보다 더 순진하게 들릴 수 있습니다. 2D에는 미리 정의된 참조 프레임인 화면 좌표가 있습니다. 더욱이 회전은 Abelian 그룹을 형성하므로 이를 추적하고 반전시키는 것이 덜 번거롭습니다. 위에서 언급한 답변은 로컬 프레임에 좌표를 저장하므로 다른 프레임의 좌표를 비교할 수 없습니다. 그러나 이는 예를 들어 canvas is xy plane at z=0. 이상적으로, 이 질문에 대한 답은 각 기호 점을 영리하게 선택된 참조 프레임의 좌표인 세 가지 길이와 연관시켜야 하며, veclen다음 과 유사하게 좌표 독립적인 방식으로 두 점의 상대적 위치를 결정하는 수단이 있어야 합니다. 2d.

세상에서 가장 좋은 점은 스칼라 곱, 벡터 곱, 벡터의 노름 계산, 행렬 곱셈, 즉 직교 변환을 수행할 수 있는 적절한 파서가 함께 제공된다는 것입니다. (직교 변환을 넘어서는 것은 행렬 반전이 정말 번거로울 것이기 때문에 엉망이라고 생각합니다.) 구문 분석에 관한 일부 진전은 다음과 같습니다.이 질문에 대한 답변하지만 다시 말하지만 이것이 아직 2d만큼 편리하지는 않다고 말하는 것이 타당할 것입니다.

답변은 를 기반으로 할 수도 있고 그렇지 않을 수도 있습니다 tikz-3dplot. ( tikz-3dplot멋진 직교 투영이 제공됩니다.) 물론 모든 옵션 중 가장 좋은 것은 다음과도 작동하는 것입니다.3점 투시도서관.

일부 행렬 연산이 패키지에 구현되었습니다 calculator. 많은 것들과 그 루틴이 여기 작업에 유용할 수 있다는 인상적인 패키지입니다. 이런 종류의 다른 패키지가 있는지 여부는 모르겠습니다.

답변1

그 라인에 따라 뭔가를 요리하는 것이 가능합니다. 이것은 그 방향의 몇 가지 결과입니다.

주요 포인트

Ti를 해킹할 수 있다케이Z는 비엘바인을 녹음합니다. 사용자가 직교 뷰를 갖고 있다고 가정하면 두 개의 기저 벡터이면 충분합니다. 이 두 기본 벡터에는 e_1=(\pgf@xx,\pgf@yx,\pgf@zx)과 의 구성요소가 있으며 e_2=(\pgf@xy,\pgf@yy,\pgf@zy), 화면의 법선은 간단히 입니다 e_3=e_1 x e_2. 이제 화면에서 좌표까지의 (가상) 거리를 "화면 깊이"라고 합니다. 그것은 단순히 입니다 . 포인트는 p.e_3어디에 있습니까?p

vielbein을 자동으로 녹음하려면 Ti를 "해킹"해야 합니다.케이Z(또는 그에 대한 스타일 정의). 따라서 이 중 어느 하나를 수행하는 것이 불편하다면 읽기를 중단하세요.

제한 사항

현재로서는 직교 좌표로 생성된 좌표/노드에 대해서만 작동하며 축척 비율은 (아직?) 고려되지 않습니다. 또한 구문을 갖는 것이 바람직할 수도 있습니다.

\path let \p1=(A) in <do something with \z1>;

여기서 \z1은 화면 깊이입니다. 이것은 (아직?) 구현되지 않았습니다.

명시적인 예

screendepth이 코드는 위에서 언급한 화면 깊이를 반환하는 함수를 정의합니다 . 분명히 좌표계와는 독립적입니다. 특히 3D 순서를 구현하려면 화면 깊이가 더 큰 개체를 마지막에 그려야 합니다. 3D 뷰 설치 방법에 관계없이 작동합니다. 예를 들어, 도서관 tikz-3dplot대신 사용할 수도 있었습니다 perspective.

\documentclass[tikz,border=3mm]{standalone}
\usetikzlibrary{calc,perspective}
\makeatletter
\pgfmathdeclarefunction{tdnormal}{6}{\begingroup
\pgfmathsetmacro\pgfutil@tmpa{(#2/1cm)*(#6)-(#3/1cm)*(#5)}%
\pgfmathsetmacro\pgfutil@tmpb{(#3/1cm)*(#4)-(#1/1cm)*(#6)}%
\pgfmathsetmacro\pgfutil@tmpc{(#1/1cm)*(#5)-(#2/1cm)*(#4)}%
\edef\pgfmathresult{\pgfutil@tmpa,\pgfutil@tmpb,\pgfutil@tmpc}%
\pgfmathsmuggle\pgfmathresult%
\endgroup}%
\pgfmathdeclarefunction{screendepth}{1}{\begingroup
\def\tikz@td@pp(##1){\edef\pgfutil@tmp{\csname tikz@dcl@coord@##1\endcsname}}%
\edef\pgfutil@tmp{\csname tikz@dcl@coord@#1\endcsname}% 
\loop
\pgfutil@tempcnta=0%
\pgfutil@for\pgf@tmp:={\pgfutil@tmp}\do{\advance\pgfutil@tempcnta by1}%
\ifnum\pgfutil@tempcnta=1\relax
\expandafter\tikz@td@pp\pgfutil@tmp%
\repeat
\edef\pgfmathresult{0}%
\ifcase\pgfutil@tempcnta
\message{Something is wrong here.^^J}
\or
\message{Something is wrong here.^^J}
\or
\or
\edef\tikz@td@vielbein{\csname tikz@vielbein@#1\endcsname}%
\pgfmathsetmacro{\tikz@td@normal}{tdnormal(\tikz@td@vielbein)}%
\def\tikz@td@strip@brackets(##1,##2,##3)##4,##5,##6;{%
\edef\pgf@tmp{(##1)*(##4)+(##2)*(##5)+(##3)*(##6)}}%
\edef\temp{\noexpand\tikz@td@strip@brackets\pgfutil@tmp\tikz@td@normal;}%
\temp
\pgfmathparse{\pgf@tmp}%
\fi
\pgfmathsmuggle\pgfmathresult%
\endgroup}
\def\tikz@@fig@main{%
    \pgfutil@ifundefined{pgf@sh@s@\tikz@shape}%
    {\tikzerror{Unknown shape ``\tikz@shape.'' Using ``rectangle'' instead}%
      \def\tikz@shape{rectangle}}%
    {}%
    \expandafter\xdef\csname tikz@dcl@coord@\tikz@fig@name\endcsname{%
      \csname tikz@scan@point@coordinate\endcsname}%
    \expandafter\xdef\csname tikz@vielbein@\tikz@fig@name\endcsname{%
       \the\pgf@xx,\the\pgf@xy,\the\pgf@yx,\the\pgf@yy,\the\pgf@zx,\the\pgf@zy}%
    \expandafter\xdef\csname tikz@trafo@\tikz@fig@name\endcsname{%
       {{\pgf@pt@aa,\pgf@pt@ab},{\pgf@pt@ba,\pgf@pt@bb},%
       {\the\pgf@pt@x,\the\pgf@pt@y}}}%
    \tikzset{every \tikz@shape\space node/.try}%
    \tikz@node@textfont%
    \tikz@node@begin@hook%
    \iftikz@is@matrix%
      \let\tikz@next=\tikz@do@matrix%
    \else%
      \let\tikz@next=\tikz@do@fig%
    \fi%
    \tikz@next%
}%
\makeatother

\begin{document}
\begin{tikzpicture}[dot/.style={circle,fill,inner sep=1.2pt}]
 \begin{scope}[3d view]
  \draw[-stealth] (0,0,0) -- (2,0,0) node[pos=1.2]{$\vec x$};
  \draw[-stealth] (0,0,0) -- (0,2,0) node[pos=1.2]{$\vec y$};
  \draw[-stealth] (0,0,0) -- (0,0,2) node[pos=1.2]{$\vec z$};
  \path[nodes=dot] (1,2,3) node (A){} (4,5) node (B){} (A) node (C){};
  \path let \p1=(A),\p2=(B),\p3=(C) in 
   (A) node[above] {$A=({}$\x1,\y1,\pgfmathparse{screendepth("A")}\pgfmathresult pt)}
   (B) node[above] {$B=({}$\x2,\y2,\pgfmathparse{screendepth("B")}\pgfmathresult pt)}
   (C) node[below] {$C=({}$\x3,\y3,\pgfmathparse{screendepth("C")}\pgfmathresult pt)};
 \end{scope}  
 \begin{scope}[xshift=6cm,3d view={110}{20}]
  \draw[-stealth] (0,0,0) -- (2,0,0) node[pos=1.2]{$\vec x'$};
  \draw[-stealth] (0,0,0) -- (0,2,0) node[pos=1.2]{$\vec y'$};
  \draw[-stealth] (0,0,0) -- (0,0,2) node[pos=1.2]{$\vec z'$};
  \path[nodes=dot] (1,2,3) node (A'){} (4,5) node (B'){} (A') node (C'){};
  \path let \p1=(A'),\p2=(B'),\p3=(C') in 
   (A') node[above] {$A'=({}$\x1,\y1,\pgfmathparse{screendepth("A'")}\pgfmathresult pt)}
   (B') node[above] {$B'=({}$\x2,\y2,\pgfmathparse{screendepth("B'")}\pgfmathresult pt)}
   (C') node[below] {$C'=({}$\x3,\y3,\pgfmathparse{screendepth("C'")}\pgfmathresult pt)};
 \end{scope}  
\end{tikzpicture}
\end{document}

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

결과는 눈에 띄지 않거나 Ti에서 3D 주문을 시도하는 것 외에는 아무것도 아닙니다.케이Z 조금 덜 번거롭습니다.

calc또는 Ti 대신 "해킹"할 수 있습니다 .케이Z. 이 해킹은 완전히 대칭이 아니므로 원래 이름으로 좌표를 참조해야 하며 물론 ($(A)+(B)$). 이렇게 하려면 더 실질적인 수술이 필요합니다. 그러나 구문을 사용하면 "물리적" 구성 요소를 얻을 수 있습니다 calc.

\documentclass[tikz,border=3mm]{standalone}
\usetikzlibrary{calc,perspective}
\makeatletter
\pgfmathdeclarefunction{tdnormal}{6}{\begingroup
\pgfmathsetmacro\pgfutil@tmpa{(#2/1cm)*(#6)-(#3/1cm)*(#5)}%
\pgfmathsetmacro\pgfutil@tmpb{(#3/1cm)*(#4)-(#1/1cm)*(#6)}%
\pgfmathsetmacro\pgfutil@tmpc{(#1/1cm)*(#5)-(#2/1cm)*(#4)}%
\edef\pgfmathresult{\pgfutil@tmpa,\pgfutil@tmpb,\pgfutil@tmpc}%
\pgfmathsmuggle\pgfmathresult%
\endgroup}%
\pgfmathdeclarefunction{z3d}{1}{\begingroup
\def\tikz@td@pp(##1){\edef\pgfutil@tmp{\csname tikz@dcl@coord@##1\endcsname}}%
\edef\pgfutil@tmp{\csname tikz@dcl@coord@#1\endcsname}% 
\loop
\pgfutil@tempcnta=0%
\pgfutil@for\pgf@tmp:={\pgfutil@tmp}\do{\advance\pgfutil@tempcnta by1}%
\ifnum\pgfutil@tempcnta=1\relax
\expandafter\tikz@td@pp\pgfutil@tmp%
\repeat
\edef\pgfmathresult{0}%
\ifcase\pgfutil@tempcnta
\message{Something is wrong here.^^J}%
\or
\message{Something is wrong here.^^J}%
\or
\or
\pgfmathsetmacro{\tikz@td@normal}{tdnormal(\the\pgf@xx,\the\pgf@xy,\the\pgf@yx,\the\pgf@yy,\the\pgf@zx,\the\pgf@zy)}%
\def\tikz@td@strip@brackets(##1,##2,##3)##4,##5,##6;{%
\edef\pgf@tmp{(##1)*(##4)+(##2)*(##5)+(##3)*(##6)}}%
\edef\temp{\noexpand\tikz@td@strip@brackets\pgfutil@tmp\tikz@td@normal;}%
\temp
\pgfmathparse{\pgf@tmp}%
\fi
\pgfmathsmuggle\pgfmathresult%
\endgroup}
\def\tikz@let@command et{%
  \let\p=\tikz@cc@dop%
  \let\x=\tikz@cc@dox%
  \let\y=\tikz@cc@doy%
  \let\z=\tikz@cc@doz%
  \let\n=\tikz@cc@don%
  \pgfutil@ifnextchar i{\tikz@cc@stop@let}{\tikz@cc@handle@line}%
}%
\def\tikz@cc@doz#1{\csname tikz@cc@z@#1\endcsname}%
\def\tikz@cc@dolet#1{%
  \pgf@process{#1}%
  \expandafter\edef\csname tikz@cc@p@\tikz@cc@coord@name\endcsname{\the\pgf@x,\the\pgf@y}%
  \expandafter\edef\csname tikz@cc@x@\tikz@cc@coord@name\endcsname{\the\pgf@x}%
  \expandafter\edef\csname tikz@cc@y@\tikz@cc@coord@name\endcsname{\the\pgf@y}%
  \pgfutil@ifnextchar,{\tikz@cc@handle@nextline}{\tikz@cc@stop@let}%
}%
\tikzset{record z/.style={execute at end node={%
\pgfmathparse{z3d("\tikz@fig@name")}%
\expandafter\xdef\csname tikz@cc@z@\tikz@fig@name\endcsname{\pgfmathresult pt}}}}
\makeatother

\begin{document}
\begin{tikzpicture}[dot/.style={circle,fill,inner sep=1.2pt,record z}]
 \begin{scope}[3d view]
  \draw[-stealth] (0,0,0) -- (2,0,0) node[pos=1.2]{$\vec x$};
  \draw[-stealth] (0,0,0) -- (0,2,0) node[pos=1.2]{$\vec y$};
  \draw[-stealth] (0,0,0) -- (0,0,2) node[pos=1.2]{$\vec z$};
  \path[nodes=dot] (1,2,3) node (A){} (4,5) node (B){} (A) node (C){};
  \path let \p1=(A),\p2=(B),\p3=(C) in 
   (A) node[above] {$A=({}$\x1,\y1,\z{A})}
   (B) node[above] {$B=({}$\x2,\y2,\z{B}\pgfmathresult pt)}
   (C) node[below] {$C=({}$\x3,\y3,\z{C})};
 \end{scope}  
 \begin{scope}[xshift=6cm,3d view={110}{20}]
  \draw[-stealth] (0,0,0) -- (2,0,0) node[pos=1.2]{$\vec x'$};
  \draw[-stealth] (0,0,0) -- (0,2,0) node[pos=1.2]{$\vec y'$};
  \draw[-stealth] (0,0,0) -- (0,0,2) node[pos=1.2]{$\vec z'$};
  \path[nodes=dot] (1,2,3) node (A'){} (4,5) node (B'){} (A') node (C'){};
  \path let \p1=(A'),\p2=(B'),\p3=(C'),\p4=(A),\p5=(B),\p6=(C) in 
   (A') node[above] {$A'=({}$\x1,\y1,\z{A'})}
   (B') node[above] {$B'=({}$\x2,\y2,\z{B'})}
   (C') node[below] {$C'=({}$\x3,\y3,\z{C'})}
   (A) edge[edge label={\pgfmathparse{sqrt(pow(\x1/1cm-\x4/1cm,2)+pow(\y1/1cm-\y4/1cm,2)+pow(\z{A}/1cm-\z{A'}/1cm,2))}%
   $d=\pgfmathprintnumber\pgfmathresult$cm}] (A');
 \end{scope}  
\end{tikzpicture}
\end{document}

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

z3d기능은 해킹 가능성에 관계없이 사용할 수 있지만 z사용자가 좌표계를 전환하지 않았다고 가정하여 구성 요소를 계산합니다.

관련 정보