贝塞尔曲线两端的“直”(切线)连接

贝塞尔曲线两端的“直”(切线)连接

我想绘制一条相对较粗的贝塞尔曲线,一直延伸到矩形的边缘。在下面的 MWE 中,最终的剪裁边界由绘制的矩形表示。

我喜欢从 (0,10) 到 (20,30) 的曲线形状,但我希望那个小的剩余三角形也能被填充。我发现该([turn]...)语法对于曲线的末端很有效,但对于曲线的起点却不起作用。

我的笨拙解决方案是绘制两次曲线,一次从顶部开始,一次从底部开始,但似乎一定有更好的方法。

在实际使用中,这些曲线并非像 MWE 中那样简单地来自点,而是相对于图像的其他维度参数化的,这就是为什么我不想手动计算切线并对数字进行硬编码。

编辑:我意识到我可能在寻求问题的特定解决方案,而不仅仅是最简单的解决方案。如果有一种方法可以“直线”延伸不涉及([turn]...)或切线的路径,我也愿意接受这种解决方案。(尽管如此,最初的问题对我来说仍然很有趣。)

\documentclass[tikz, margin=1cm]{standalone}
\usetikzlibrary{calc}

\begin{document}
\begin{tikzpicture}
    \draw (0, 0) rectangle (30, 30);

    \draw[line width=1.333cm, line cap=rect] (0, 10) .. controls ($(0, 10)!0.333!(20, 30) + (-1, 1)$) and ($(0, 10)!0.666!(20, 30) + (-1, 1)$) .. (20, 30);
    \draw[green, opacity=0.25, line width=1.333cm, line cap=rect] (0, 10) .. controls ($(0, 10)!0.333!(20, 30) + (-1, 1)$) and ($(0, 10)!0.666!(20, 30) + (-1, 1)$) .. (20, 30) -- ([turn]0:2);
    \draw[blue, opacity=0.25, line width=1.333cm, line cap=rect] (20, 30) .. controls ($(0, 10)!0.666!(20, 30) + (-1, 1)$) and ($(0, 10)!0.333!(20, 30) + (-1, 1)$) .. (0, 10) -- ([turn]0:2);

    \draw[red] (0, 10) -- ($(0, 10)!0.333!(20, 30) +(-1, 1)$) -- ($(0, 10)!0.666!(20, 30) + (-1, 1)$) -- (20, 30);
\end{tikzpicture}
\end{document}

output of the MWE

编辑 2:为清楚起见添加了箭头(抱歉,我使用 Preview.app 来添加它们,而不是 TeX :P)

我希望黑线延伸得足够远,这样它就会被矩形“平整”地剪掉,而不会留下那个小的内部三角形。

MWE annotated with arrows to show the problem area

答案1

假设我理解了要求,使用负值的技巧可能会产生所需的结果shorten >shorten <

\documentclass[tikz,border=1cm]{standalone}
\usetikzlibrary{calc}
\begin{document}
\begin{tikzpicture}
 \draw (0, 0) rectangle (30, 30);
 \draw [line width=1.333cm, line cap=rect, shorten >=-0.5cm, shorten <=-0.5cm] 
  (0, 10) .. controls 
  ($(0, 10)!0.333!(20, 30) + (-1, 1)$) and 
  ($(0, 10)!0.666!(20, 30) + (-1, 1)$) .. 
  (20, 30);
\end{tikzpicture}
\end{document}

enter image description here

答案2

我明白了。现在好些了吗?这在两端增加了一些平滑的延续性。

\documentclass[tikz, margin=1cm]{standalone}
\usetikzlibrary{calc}

\begin{document}
\begin{tikzpicture}
    \draw (0, 0) rectangle (30, 30);
    \draw[line width=1.333cm, line cap=rect] (0, 10) .. controls ($(0, 10)!0.333!(20, 30) + (-1, 1)$) and ($(0,
    10)!0.666!(20, 30) + (-1, 1)$) .. (20, 30) coordinate[pos=-0.1] (aux1) coordinate[pos=0] (aux2)
    coordinate[pos=1.1] (aux3) coordinate[pos=1] (aux4)
    (aux1) -- (aux2) (aux3) -- (aux4);
\end{tikzpicture}
\end{document}

enter image description here

当然,你可以将其作为一种风格。

\documentclass[tikz, margin=1cm]{standalone}
\usetikzlibrary{calc}

\begin{document}
\begin{tikzpicture}[continuation/.style={insert path={coordinate[pos=-#1] (aux1) coordinate[pos=0] (aux2)
    coordinate[pos=1+#1] (aux3) coordinate[pos=1] (aux4)
    (aux1) -- (aux2) (aux3) -- (aux4)}}]
    \draw (0, 0) rectangle (30, 30);
    \draw[line width=1.333cm, line cap=rect] (0, 10) .. controls ($(0, 10)!0.333!(20, 30) + (-1, 1)$) and ($(0,
    10)!0.666!(20, 30) + (-1, 1)$) .. (20, 30) [continuation=0.1];
\end{tikzpicture}
\end{document}

并制作强制性动画

\documentclass[tikz, margin=1cm]{standalone}
\usetikzlibrary{calc}

\begin{document}
\tikzset{continuation/.style={insert path={coordinate[pos=-#1] (aux1) coordinate[pos=0] (aux2)
    coordinate[pos=1+#1] (aux3) coordinate[pos=1] (aux4)
    (aux1) -- (aux2) (aux3) -- (aux4)}}}
\foreach \X in {0.01,0.02,...,0.25}
{\begin{tikzpicture}
    \draw (0, 0) rectangle (30, 30);
    \draw[line width=1.333cm, line cap=rect] (0, 10) .. controls ($(0, 10)!0.333!(20, 30) + (-1, 1)$) and ($(0,
    10)!0.666!(20, 30) + (-1, 1)$) .. (20, 30) [continuation=\X];
\end{tikzpicture}}
\end{document}

enter image description here

答案3

我已决定采用以下利用decorations.markingsTikZ 库的解决方案。

\documentclass[tikz, margin=1cm]{standalone}
\usetikzlibrary{calc}
\usetikzlibrary{decorations.markings}

\begin{document}
\begin{tikzpicture}[
    continuation/.style={
        decoration={
            markings,
            mark=
                at position 0
                with {\draw[red, thin] (0.1, 0) -- (-1, 0);},
            mark=
                at position 0.99999
                with {\draw[blue, thin] (-0.1, 0) -- (1, 0);}
        },
        postaction=decorate,
    }]
    \draw (0, 0) rectangle (30, 30);

    \draw[line width=1.333cm, continuation] (0, 10) .. controls ($(0, 10)!0.333!(20, 30) + (-1, 1)$) and ($(0, 10)!0.666!(20, 30) + (-1, 1)$) .. (20, 30);

    \draw[red] (0, 10) -- ($(0, 10)!0.333!(20, 30) + (-1, 1)$) -- ($(0, 10)!0.666!(20, 30) + (-1, 1)$) -- (20, 30);

    \draw[green, shorten >=-0.5cm] ($(0, 10)!0.333!(20, 30) +(-1, 1)$) -- (0, 10);
    \draw[green, shorten >=-0.5cm] ($(0, 10)!0.666!(20, 30) +(-1, 1)$) -- (20, 30);
\end{tikzpicture}
\end{document}

output of the mwe

这里有两个考虑因素。首先,这是否会产生实际切线?贝塞尔曲线末端的红色和蓝色延伸是由continuation使用 的样式产生的markings。我在这里通过用绿色绘制穿过贝塞尔曲线的切线并用 延长它来确认这一点shorten >=-0.5cm。放大两端可以确认这些是相同的线。(我想我可以尝试从 PDF 中提取实际路径并进行数学检查,但……这不是今天的项目。)

第二个考虑是错误markings库中。在这种情况下,可以设置的最远结束位置是0.99999;再一个9会导致错误。通过检查这张图片,因为我知道我将使用的贝塞尔曲线不会是末端弯曲,我认为这样很好。

我考虑过在贝塞尔曲线上进行“计算”并手动插入“完美”的延长线,但这似乎不太浪费我的时间,尤其是因为我想参数化我的最终图像。

相关内容