Tikz 找到缩短曲线的起点和终点的坐标

Tikz 找到缩短曲线的起点和终点的坐标

我在两点之间画了一条缩短的曲线。
我想获取该缩短线的起点和终点的坐标。

我尝试使用下面的代码
AB来定义弯曲线的坐标(红点),
我希望CD(黑点)是缩短线的起点和终点的坐标,但目前AC是相同的坐标。B和也一样,D如屏幕截图所示在此处输入图片描述

\documentclass[border=10pt]{standalone}
\usepackage{tikz}
\usetikzlibrary{
  arrows.meta,calc,decorations.markings,math,arrows.meta,positioning,automata}

\begin{document}
\begin{tikzpicture}
  \coordinate (A) at (3.5,3.5); 
  \coordinate (B) at (5.1,2.); 

  \draw[color=red,fill=red] (A) circle (0.15cm);
  \draw[color=red,fill=red] (B) circle (0.15cm);
 
  \draw (A) edge[out=-20,in=140,shorten >=15pt, shorten <=15pt] coordinate[pos=0.]  (C)  coordinate[pos=1] (D)  (B); 

  \draw[black,fill=black] (C) circle (0.05cm);
  \draw[black,fill=black] (D) circle (0.05cm);
\end{tikzpicture}
\end{document}

更一般地,我希望

  • pos = 0对应于缩短线的开头
  • pos = 1对应于缩短线的末尾

这样我就可以将点放置在缩短线上的任何我想要的位置(例如缩短线的 25%)。

有人知道解决办法吗?非常感谢

答案1

这里的问题是,缩短路径是在路径构建的最后阶段进行的,因此诸如定位节点之类的操作不会注意到缩短。我怀疑这是因为缩短是shorten >=15pt通过与添加箭头尖端相同的机制完成的,通常这不会影响路径上事物的定位。

因此,实现此目的的一种方法是强制缩短时间。理想情况下,人们会在计算定位内容之前执行此操作,但我不知道在哪里执行此操作,而且我碰巧知道在定义路径后指定路径上点的另一种方法,所以我改用这种方法。

使用 会使生活变得稍微复杂一些edge,因为它会创建一个在它自己的范围内绘制的单独路径,因此我们需要使用一些globals 来将事物从这些范围中取出。

这里有两种方法可以实现您的目标。第一种方法,我们保存缩短的路径,然后使用spath3库将圆圈放置在路径的末端。第二种方法,我们保存原始路径,然后使用库spath3将其缩短 - 这样做的好处是缩短是真正沿着路径进行的(每张图片中的绿线都是原始的未缩短路径)。

在这两种情况下,我们都使用spath3TikZ 库,然后使用语法访问缩短路径上位置的坐标(spath cs:<path name> <position>)

\documentclass{article}
%\url{https://tex.stackexchange.com/q/652865/86}
\usepackage{tikz}

\usetikzlibrary{spath3,intersections}

\makeatletter
\tikzset{
  shorten path early/.code={
    \tikz@addmode{%
      \pgf@prepare@end@of@path
      \pgf@prepare@start@of@path
      \pgfsetshortenstart{0pt}%
      \pgfsetshortenend{0pt}%
    }%
  },
  shorten then name path/.style={
    shorten path early,
    spath/save global=#1
  }
}
\makeatother


\begin{document}
\begin{tikzpicture}
% Version 1: save the shortened path
\begin{scope}
  \coordinate (A) at (3.5,3.5); 
  \coordinate (B) at (5.1,2.); 

  \draw[color=red,fill=red] (A) circle[radius=0.15cm];
  \draw[color=red,fill=red] (B) circle[radius=0.15cm];

  \draw[ultra thick, green] (A) edge[out=-20,in=140] (B); 


  \draw (A) edge[out=-20,in=140,shorten >=15pt, shorten <=15pt, shorten then name path=short] coordinate[pos=0] (C) coordinate[pos=1] (D) (B); 

  \draw[black,fill=black] (C) circle[radius=0.05cm];
  \draw[black,fill=black] (D) circle[radius=0.05cm];

\fill[magenta] (spath cs:short 0) circle[radius=0.05cm];
  \fill[magenta] (spath cs:short 1) circle[radius=0.05cm];
\end{scope}

% Version 2: save the path and shorten it afterwards
\begin{scope}[xshift=3cm]
  \coordinate (A) at (3.5,3.5); 
  \coordinate (B) at (5.1,2.); 

  \draw[color=red,fill=red] (A) circle[radius=0.15cm];
  \draw[color=red,fill=red] (B) circle[radius=0.15cm];

  \draw (A) edge[ultra thick, green, out=-20,in=140, spath/save global=short] coordinate[pos=0] (C) coordinate[pos=1] (D) (B); 

\tikzset{
  spath/shorten at both ends={short}{15pt}
}

\draw[spath/use=short];

  \draw[black,fill=black] (C) circle[radius=0.05cm];
  \draw[black,fill=black] (D) circle[radius=0.05cm];

\fill[magenta] (spath cs:short 0) circle[radius=0.05cm];
  \fill[magenta] (spath cs:short 1) circle[radius=0.05cm];
\end{scope}

\end{tikzpicture}

\end{document}

两条缩短的路径,带有标记的端点


经过思考,我认为spath3图书馆应该在保存路径之前应用缩短。我在开发版本中实现了它(在github)。使用该版本,可以进行以下操作:

\begin{tikzpicture}
  \coordinate (A) at (3.5,3.5); 
  \coordinate (B) at (5.1,2.); 

  \draw[color=red,fill=red] (A) circle[radius=0.15cm];
  \draw[color=red,fill=red] (B) circle[radius=0.15cm];

  \draw (A) edge[ultra thick, green, out=-20,in=140,shorten >=15pt, shorten <=15pt, spath/save global=short] coordinate[pos=0] (C) coordinate[pos=1] (D) (B); 

  \draw[black,fill=black] (C) circle[radius=0.05cm];
  \draw[black,fill=black] (D) circle[radius=0.05cm];

\fill[magenta] (spath cs:short 0) circle[radius=0.05cm];
  \fill[magenta] (spath cs:short 1) circle[radius=0.05cm];
\end{tikzpicture}

答案2

现在我只能想到使用markings如下方式访问这些点:

\documentclass[tikz, border=1cm]{standalone}
\usetikzlibrary{decorations.markings}
\begin{document}
\begin{tikzpicture}
\coordinate (A) at (3.5,3.5); 
\coordinate (B) at (5.1,2.); 
\fill[red] (A) circle[radius=0.15cm];
\fill[red] (B) circle[radius=0.15cm];
\draw[
shorten >=15pt, shorten <=15pt,
postaction=decorate, 
decoration={markings, 
  mark=at position 0 with {\coordinate (C) at (15pt,0);},
  mark=at position 1 with {\coordinate (D) at (-15pt,0);} 
},
] (A) to[out=-20,in=140]  (B); 
\fill (C) circle[radius=0.05cm];
\fill (D) circle[radius=0.05cm];
\end{tikzpicture}
\end{document}

带有红色和黑色圆圈的曲线

答案3

这是一个有趣的问题(并且15pt有很多缩短)!

最好创建一个自定义to path的,只移动起始和目标/结束坐标确定的量,而不使用实际的缩短量。可能还有一种方法可以做到这一点decorations.markings图书馆。

基本上,所有沿路径的节点定位均由 TikZ 完成。每次使用路径运算符(如 (a move to)、--(a line to)(也-||-)或 )时.. controls … ..,TikZ 都会保存起始坐标、结束坐标以及(在后者情况下)控制点。

是的,到最后所有这些bends、outs 和s 都只是一条道路。in.. controls (<p1>) and (<p2>) ..

但我们可以改变这个计时器。然而:计时器不知道它的路径是在路径的起点(或移动之后)还是在路径的终点(移动之前)。

这行

\draw[shorten <=15pt] (0,0) node{S} -- (1,0)
   to[out=90, in=30] node[at start]{x} (2,0);

将从 开始(15pt,0),节点x仍应位于。这就是为什么我将提供实际激活新计时器的(1,0)密钥。shortening position

当然,如果您只使用具有一个段的路径,则可以将此键赋予范围。

代码

\documentclass[border=10pt]{standalone}
\usepackage{tikz}
\tikzset{en/.style={edge node={coordinate[pos=#1/10] (c-#1)}}}
\makeatletter
\def\tikz@timer@curve@shorten{% tikz.code.tex, l 4947
  \pgftransformcurveattime{\tikz@time}
    {\pgfpointlineatdistance{\pgf@shorten@start@additional}{\tikz@timer@start}{\tikz@timer@cont@one}}
    {\tikz@timer@cont@one}{\tikz@timer@cont@two}
    {\pgfpointlineatdistance{\pgf@shorten@end@additional}{\tikz@timer@end}{\tikz@timer@cont@two}}}
\tikzset{shortening position/.code=\let\tikz@timer@curve\tikz@timer@curve@shorten}
\makeatother
\begin{document}
\begin{tikzpicture}[radius=.15cm]
  \filldraw[red] (3.5,3.5) coordinate (A) circle[]
                 (5.1,2.0) coordinate (B) circle[];
  \draw (A) edge[out=-20,in=140,shorten >=15pt, shorten <=15pt, en/.list={0,...,10}, shortening position] (B);

  \foreach \pos in {0,...,10}
    \draw[gray, shorten <=2pt] (c-\pos) --
      node[right,at end,inner sep=0pt,sloped,font=\tiny]
        {\pgfmathprint{!mod(\pos,2)?\pos:""}} +(45:.2);
  
  % the shortening is done at (0,0), the curve timer doesn't know about this
  \draw[shorten <=15pt] (0,0) node{S} -- (1,0) to[out=90, in=30] node[at start]{x} (2,0);
\end{tikzpicture}
\end{document}

代码

在此处输入图片描述

答案4

这是关于路径操作的一个有趣问题。我认为 TikZ 可以做到这一点,只需付出一些努力,请参阅上述答案。

这里我展示了 Asymptote 可以使用内置例程轻松做到这一点:arctime,,arcpointsubpathAsymptote 文档路径和指南)。我用的是cm单位,所以L=15pt/cm;15pt改成cm

在此处输入图片描述

// Determine a point on a given curve 
// via its length on the curve
// http://asymptote.ualberta.ca/
unitsize(1.5cm);
pair A=(3.5,3.5), B=(5.1,2);
path pAB=A..controls A+2dir(-20) and B+2dir(140)..B;
draw(pAB,green+1.5pt);
dot("$A$",align=W,A,red);
dot("$B$",align=E,B,red);

real L=15pt/cm;
real tC=arctime(pAB,L);
pair C=arcpoint(pAB,L);
real tD=arctime(pAB,arclength(pAB)-L);
pair D=arcpoint(pAB,arclength(pAB)-L);
path pCD=subpath(pAB,tC,tD); // a subpath of pAB
draw(pCD);
dot("$C$",align=NE,C);
dot("$D$",align=SW,D);

write("L is ",L);
write("The length of pAB is ",arclength(pAB));
write("The length of pCD is ",arclength(pCD));
write("Checking that 2*L+arclength(pCD) ",2*L+arclength(pCD));
write("that is arclength(pAB) with error 10^{-12}");
shipout(bbox(5mm,invisible)); 

Asymptote 可以在交互模式下打印出它的计算结果,如下所示,用于检查CD是否15pt来自初始曲线的两个端点pAB

在此处输入图片描述


附录通过其相对时间(路径上相对于其弧长的分数 l 的时间)其中pointsubpath

在此处输入图片描述

// Determine a point on a given curve 
// via its relative time
// http://asymptote.ualberta.ca/
unitsize(1.5cm);
pair A=(3.5,3.5), B=(5.1,2);
path pAB=A..controls A+2dir(-20) and B+2dir(140)..B;
draw(pAB,green+1.5pt);
dot("$A$",align=W,A,red);
dot("$B$",align=E,B,red);

real tC=.05, tD=.88;         // relative times in [0,1]
pair C=point(pAB,tC);
pair D=point(pAB,tD);
path pCD=subpath(pAB,tC,tD); // a subpath of pAB
draw(pCD);
dot("$C$",align=NE,C);
dot("$D$",align=SW,D);
shipout(bbox(5mm,invisible));

相关内容