代码

代码

考虑下面的 MWE。

我已经标记了 A 在 Y 轴上的投影,与 X 轴平行。现在我的问题是,是否有一种简单的方法可以将 A 投影到 Y 轴上,但与给定的线平行?

到目前为止,我一直在使用温度曲线和 Y 轴之间的交点。我想知道是否已经内置了更简单的方法。

\documentclass[a4paper]{memoir}
\usepackage{tikz}
\usetikzlibrary{calc}
\begin{document}
\begin{tikzpicture}
  \draw[<->] (0,3) -- (0,0) -- (3,0);
   \draw (0,0) -- (3,1);
   \fill (2,2) coordinate (A) circle (2pt) node[right] {A};
   \draw[dashed] (A) -- ($(A -| 0,0)$);
\end{tikzpicture}
\end{document}

在此处输入图片描述

答案1

有几个记录简单的 TikZ 功能在这里很有用:

  1. 当使用坐标计算将一个坐标投影到另外两个坐标之间的线上时,可以添加一个角度,使新坐标围绕投影的坐标旋转。也就是说,($(A)!(B)!(C)$)投影到和(C)之间的线上,并将该坐标旋转一个角度。(A)(B)($(A)!(B)!:<n>(C)$)(C)<n>

  2. 有一个intersection坐标系统(除了intersections库之外),它将坐标放置在两条线的交点处,每条线由两个坐标指定。语法是(intersection of A--B and C--D)(坐标周围没有括号)。对于此用例,此功能比path在点对之间创建并使用更好name intersections,因为后者仅当线相交而不是(无限长的)线。

考虑到这些,我们的想法是从初始坐标投影到第一条线,然后将结果坐标旋转 90 度。初始坐标和投影然后旋转的坐标之间的线与第一条线平行。然后我们可以将它与第二条线相交。以下是在 MWE 中执行此操作的方法:

\documentclass{standalone}
\usepackage{tikz}
\usetikzlibrary{calc}
\begin{document}
\begin{tikzpicture}
  \useasboundingbox (-0.1,-0.1) rectangle (3.1,3.1); 
  \draw[<->] (0,3) -- (0,0) -- (3,0);
   \draw (0,0) -- (3,1);
   \fill (2,2) coordinate (A) circle (2pt) node[right] {A};
   \coordinate (B) at ($(0,0)!(A)!90:(3,1)$);
   \draw[gray] (A) -- (intersection of A--B and 0,0--0,1);
\end{tikzpicture}
\end{document}

示例代码输出

下一个问题是:封装此过程的“TikZ 方式”是什么?将一个坐标投影到与线平行的线上的操作涉及五个输入:要投影的坐标,以及每条线的两个坐标。一个简单的宏需要五个参数;如果一个参数是要创建的坐标的名称,则可能需要第六个参数。此外,宏与 TikZ 以路径为主要对象的重点并不真正兼容。

这是一种计算,但据我所知,坐标计算不打算由用户扩展。另外,我发现坐标计算的语法有点接近级密度。无意冒犯 XY-Pic,但我认为语法是 TikZ 成为类别杀手的一个关键因素。

不过,TikZ 确实提供了一种定义坐标系的机制。常见的坐标系是polar,您可以通过半径和角度描述点。但pgfplots使用许多坐标系来定位图形窗口、轴、刻度标签等上的坐标。坐标系可以对其输入执行任何操作;它只需返回一个坐标即可。

因此我寻求创建一个坐标系统parallel到以下界面:

(parallel cs:from=P, to=A--B, on=C--D)

应指定投影到和(P)定义的线上的坐标,该坐标与和定义的线平行。(A)(B)(C)(D)

根据手册,坐标系统可以通过 来实现,以和之间的文本作为参数文本\tikzdeclarecoordinatesystem{<name>}{<code>} 。通常,该文本会贯穿、或以设置某些键。需要移动到所需的坐标并停止。(从技术上讲,它只需要在和中保存所需的尺寸)。它可以使用 TikZ 或 PGF 级别的命令来完成。<code>(<name> cs:)\setkeys\pgfkeys\tikzset<code>\pgf@x\pgf@y

实现如下:

\makeatletter
\tikzset{/tikz/parallel cs/.cd,
    to line initial coordinate/.store in=\tikz@parallelcs@toA,
    to line final coordinate/.store in=\tikz@parallelcs@toB,
    on line initial coordinate/.store in=\tikz@parallelcs@onA,
    on line final coordinate/.store in=\tikz@parallelcs@onB,
    from coordinate/.store in=\tikz@parallelcs@from,
    to/.style args={#1--#2}{
        to line initial coordinate=#1,
        to line final coordinate=#2,
    },
    on/.style args={#1--#2}{
        on line initial coordinate=#1,
        on line final coordinate=#2,
    },
    from/.style={
        from coordinate=#1
    }
}
\tikzdeclarecoordinatesystem{parallel}{
    \tikzset{/tikz/parallel cs/.cd,#1}
    \tikz@scan@one@point\pgfutil@firstofone%
    (intersection of \tikz@parallelcs@from --$(\tikz@parallelcs@toA)!(\tikz@parallelcs@from)!90:(\tikz@parallelcs@toB)$ and \tikz@parallelcs@onA--\tikz@parallelcs@onB)%
    \relax
}
\makeatother

这个\tikz@scan@one@point\pgfutil@firstofone模式出现在这个网站的许多答案中。我并没有完全理解它,但它允许用 TikZ 语言指定坐标,然后保存\pgf@x\pgf@y根据需要进行操作。其余代码是pgfkey玩具示例的升级版本。

然后您可以使用:

\begin{tikzpicture}
  \tikzset{point/.style={draw,circle,inner sep=0pt,outer sep=0pt,minimum width=2pt,fill}}
  \node[point,label=$P$] (P) at (3,3) {};
  \draw[blue] (0,0) node[point,label=$A$] (A) {} -- (3,1) node[point,label=$B$] (B) {};
  \draw       (0,1) node[point,label=$C$] (C) {} -- (2,3) node[point,label=$D$] (D) {};
  \draw[red] (P) -- (parallel cs:from=P,to=A--B,on=C--D) node [point,label=$Q$]{};
\end{tikzpicture}

示例代码输出#2

如您所见,即使投影点不在线段上,它也能起作用:

\begin{tikzpicture}
  \tikzset{point/.style={draw,circle,inner sep=0pt,outer sep=0pt,minimum width=2pt,fill}}
  \node[point,label=$P$] (P) at (3,3) {};
  \draw[blue] (1.75,0) node[point,label=$A$] (A) {} -- (3,1) node[point,label=$B$] (B) {};
  \draw       (0,1) node[point,label=$C$] (C) {} -- (2,3) node[point,label=$D$] (D) {};
  \draw[red] (P) -- (parallel cs:from=P,to=A--B,on=C--D) node [point,label=$Q$] (Q) {};
  \draw[black!30!white] (Q) -- (C) 
      (D) -- (intersection of C--D and current bounding box.north west--current bounding box.north east);
  \draw[blue!30!white] 
      (intersection of A--B and current bounding box.south west--current bounding box.south east) -- (A)
      (B) -- (intersection of A--B and current bounding box.north east--current bounding box.south east);
\end{tikzpicture}

示例代码输出#3

我最初的实现使用 TikZlet操作来指定坐标。当我尝试一些更复杂的构造时,它就崩溃了。但 Loop Space 的答案将其降低了一个级别,并且它起作用了。

\begin{tikzpicture}
    \tikzset{point/.style={draw,circle,inner sep=0pt,outer sep=0pt,minimum width=1pt,fill}}
    \node[point,label={90:$\scriptstyle P$}] (P) at (0,4) {};
    \node[point,label={180:$\scriptstyle B_{0}$}] (B-0) at (1,0) {};
    \node[point,label={0:$\scriptstyle A_1$}] (A-1) at (2,0) {};
    \node[point,label={180:$\scriptstyle B_{1}$}] (B-1) at (intersection of P--B-0 and 0,1--1,1) {};
    \draw (P) -- (B-0) (P) -- (A-1) (B-0) -- (A-1) -- (B-1);
    \foreach[remember=\i as \lasti (initially 1)] \i in {2,...,10} {
        \draw (B-\lasti) 
            -- (parallel cs:from=B-\lasti,to=B-0--A-1,on=P--A-1)
               node[point,label={0:$\scriptstyle A_{\i}$}] (A-\i) {}
            -- (parallel cs:from=A-\i,to=A-1--B-1,on=P--B-0)
               node[point,label={180:$\scriptstyle B_{\i}$}] (B-\i) {};
    }
\end{tikzpicture}

第三个示例输出

答案2

像这样?

在此处输入图片描述

代码

\documentclass{standalone}
\usepackage{tikz}
\usetikzlibrary{calc}
\begin{document}
    \begin{tikzpicture}
       \coordinate (O) at (0,0); % Initial point of the line
       \coordinate (L) at (3,1); % End point of the line
       \draw[<->] (0,3) -- (0,0) -- (3,0);
       \draw (O) -- (L);
       \fill (2,2) coordinate (A) circle (2pt) node[right] {A};
       \draw[dashed] (A) -- ($(A -| 0,0)$);     
       \draw[dashed] let \p1=(O), \p2=(L), \p3=(A) in \pgfextra{\pgfmathsetmacro{\auxy}{\y3 - (\y2-\y1)/(\x2-\x1) * \x3}} (A) -- (0,\auxy pt);
    \end{tikzpicture}
\end{document}

答案3

这是 Matthew 代码的一个版本,其中 TikZ 语法被更低级的代码所取代,这些代码不会破坏任何选项(但是,我不知道 Matthew 测试的示例是什么,所以我不确定)。

\makeatletter
\tikzset{/tikz/parallel cs/.cd,
    to line initial coordinate/.store in=\tikz@parallelcs@toA,
    to line final coordinate/.store in=\tikz@parallelcs@toB,
    on line initial coordinate/.store in=\tikz@parallelcs@onA,
    on line final coordinate/.store in=\tikz@parallelcs@onB,
    from coordinate/.store in=\tikz@parallelcs@from,
    to/.style args={#1--#2}{
        to line initial coordinate=#1,
        to line final coordinate=#2,
    },
    on/.style args={#1--#2}{
        on line initial coordinate=#1,
        on line final coordinate=#2,
    },
    from/.style={
        from coordinate=#1
    }
  }

  \tikzdeclarecoordinatesystem{parallel}{
    \tikzset{/tikz/parallel cs/.cd,#1}
    \tikz@scan@one@point\pgfutil@firstofone%
    (intersection of \tikz@parallelcs@from --$(\tikz@parallelcs@toA)!(\tikz@parallelcs@from)!90:(\tikz@parallelcs@toB)$ and \tikz@parallelcs@onA--\tikz@parallelcs@onB)%
    \relax
  }
\makeatother

相关内容