我有一些类似于以下代码的内容(对于较长的示例表示歉意,但这对精确数字相当敏感):
\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{
knots,
hobby,
}
\tikzset{
knot diagram/every knot diagram/.append style={
consider self intersections=true,
ignore endpoint intersections=false,
end tolerance=1pt,
clip draw radius=12pt
},
knot diagram/only when rendering/.style={
ultra thick,
draw=blue!40!black,
double=white,
double distance=12pt
}
}
\begin{document}
\begin{tikzpicture}
\begin{knot}[
draft mode=crossings,
flip crossing/.list={2,4,6,7,10,12}
]
\strand
([closed]0.5,0.5) to[out=-5,in=-135]
(1.8,0.8) to[out=45,in=-135]
(4.25,3.25) to[out=45,in=135]
(5.75,3.25) to[out=-45,in=135]
(8.2,0.8) to[out=-45,in=-175]
(9.5,0.5) to[out=85,in=-45]
%
(9.2,1.8) to[out=135,in=-45]
(7.75,3.25) to[out=135,in=45]
(6.25,3.25) to[out=-135,in=45]
(3.75,0.75) to[out=-135,in=-45]
(2.25,0.75) to[out=135,in=-45]
(0.8,2.2) to[out=135,in=-95]
(0.5,3.5) to[out=5,in=135]
%
(1.8,3.2) to[out=-45,in=135]
(4.25,0.75) to[out=-45,in=-135]
(5.75,0.75) to[out=45,in=-135]
(8.2,3.2) to[out=45,in=175]
(9.5,3.5) to[out=-85,in=45]
%
(9.2,2.2) to[out=-135,in=45]
(7.75,0.75) to[out=-135,in=-45]
(6.25,0.75) to[out=135,in=-45]
(3.75,3.25) to[out=135,in=45]
(2.25,3.25) to[out=-135,in=45]
(0.8,1.8) to[out=-135,in=95] cycle;
\end{knot}
\useasboundingbox (-0.5,-0.5) rectangle (10.5,4.5);
\end{tikzpicture}
\begin{tikzpicture}
\begin{knot}[
draft mode=crossings,
flip crossing/.list={2,4,6,7,10,12}
]
\strand
([closed]0.5,0.5) to[out=-5,in=-135]
(1.9,0.9) to[out=45,in=-135]
(4.25,3.25) to[out=45,in=135]
(5.75,3.25) to[out=-45,in=135]
(8.1,0.9) to[out=-45,in=-175]
(9.5,0.5) to[out=85,in=-45]
%
(9.1,1.9) to[out=135,in=-45]
(7.75,3.25) to[out=135,in=45]
(6.25,3.25) to[out=-135,in=45]
(3.75,0.75) to[out=-135,in=-45]
(2.25,0.75) to[out=135,in=-45]
(0.9,2.1) to[out=135,in=-95]
(0.5,3.5) to[out=5,in=135]
%
(1.9,3.1) to[out=-45,in=135]
(4.25,0.75) to[out=-45,in=-135]
(5.75,0.75) to[out=45,in=-135]
(8.1,3.1) to[out=45,in=175]
(9.5,3.5) to[out=-85,in=45]
%
(9.1,2.1) to[out=-135,in=45]
(7.75,0.75) to[out=-135,in=-45]
(6.25,0.75) to[out=135,in=-45]
(3.75,3.25) to[out=135,in=45]
(2.25,3.25) to[out=-135,in=45]
(0.9,1.9) to[out=-135,in=95] cycle;
\end{knot}
\useasboundingbox (-0.5,-0.5) rectangle (10.5,4.5);
\end{tikzpicture}
\end{document}
每个结点都以不同的方式显示问题,可能有不同的原因,以及一个偶然的问题(与第一个/最后一个点有关)。以下是输出:
请注意,我无法使用该celtic
软件包,因为我不想要交替结 - 据我所知,使用该软件包无法实现这一点。(这些结看起来是非交替的,因为由于第一个/最后一个点的问题,交叉点变得不稳定)
主要问题是部分交叉。在第一个结中,我不知道为什么会发生这种情况;在第二个结中,控制点非常靠近另一个弧,我认为这是通过限制剪切圆而导致问题的,因为将这些控制点移开会使这个问题消失(按时间顺序,第一个结是为了解决这个问题而创建的)。但第一个结没有这样的问题;它只是出现了。
这似乎只是绘图方面的问题。只有double
启用此功能时才会发生这种情况,但文档中并未实际记录此功能knots
,因此我几乎没有其他方法可以继续处理。
需要注意的一个有趣的事情是剪辑圆的混叠伪影的平面的方向 - 特别是在第一幅图像中将其翻转以穿过 10(第二幅图像中为 9......我不确定为什么这些交叉数字会发生变化)
在我的实际文档中,第一个点和最后一个点产生交叉的问题并没有发生,所以我并不担心这个问题。
答案1
这里发生了几件事,其中一件事与如何最好地绘制这样的图片有关(我应该将其添加到文档中),其中一件事揭示了 knots 包中的一个小错误。
使用 knots 包绘制凯尔特风格的结时,double
路径结果会出现一些问题。随着时间的推移,通过这里的几个问题,出现了一种绘制这些结的最佳方法,但这并不是显而易见的方法。
但更重要的是,由于您的控制点非常接近交叉点,并且您的路径非常宽,那么您就会遇到end tolerance
使用方式的错误。此键用于告诉结库“靠近端点”是什么意思。这使用了两次,一次是为了抛出一个段“相交”下一个段的虚假交叉点。对于此测试,您需要将其设置end tolerance
为非常小,因为您的控制点接近(真正的)交叉点(选项ignore endpoint intersections=false
是导致左下角出现虚假交叉的原因;因为您的控制点都不是实际上在交叉点处,通过删除此选项并保持end tolerance
较小值,您可以摆脱此交叉点而不影响图片的其余部分)。
但end tolerance
在另一个地方也使用。当算法检测到交叉点时,它会在交叉点附近再次绘制上部线。通常,它只绘制路径的相关段。但如果该段在交叉点附近结束,那么它还会绘制下一个(或上一个,视情况而定)段。算法end tolerance
在这里再次使用。因此,end tolerance
设置为非常小,这意味着应该绘制的段不是因为发现交叉点距离段的端点更远。我应该这里使用的是剪切半径。
我认为这就是你的半交叉所发生的情况。在检查自相交时,例行程序中还有一个步骤,即(可能)将贝塞尔曲线一分为二,以确保它们本身不会自相交。这(可能)发生在对角线路径上,然后由于路径end tolerance
较小,因此只渲染了该路径的一部分。
这是您的代码:
\documentclass{article}
%\url{https://tex.stackexchange.com/q/580472/86}
\usepackage{tikz}
\usetikzlibrary{
knots,
hobby,
}
\tikzset{
knot diagram/every knot diagram/.append style={
consider self intersections=true,
% ignore endpoint intersections=false,
end tolerance=1pt,
clip width=1,
background color=blue!40!black,
only when rendering/.style={
basic strand
},
every intersection/.style={
crossing strand
},
},
basic strand/.style={
ultra thick,
draw=blue!40!black,
double=white,
double distance=10pt
},
crossing strand/.style={
line width=13.2pt,
only when rendering/.style={%
draw=white,%
line width=10pt,
double=none,
}
}
}
\begin{document}
\begin{tikzpicture}
\begin{knot}[
% draft mode=crossings,
flip crossing/.list={4,6,7,10,12}
]
\strand
(0.5,0.5) to[out=-5,in=-135]
(1.8,0.8) to[out=45,in=-135]
(4.25,3.25) to[out=45,in=135]
(5.75,3.25) to[out=-45,in=135]
(8.2,0.8) to[out=-45,in=-175]
(9.5,0.5) to[out=85,in=-45]
%
(9.2,1.8) to[out=135,in=-45]
(7.75,3.25) to[out=135,in=45]
(6.25,3.25) to[out=-135,in=45]
(3.75,0.75) to[out=-135,in=-45]
(2.25,0.75) to[out=135,in=-45]
(0.8,2.2) to[out=135,in=-95]
(0.5,3.5) to[out=5,in=135]
%
(1.8,3.2) to[out=-45,in=135]
(4.25,0.75) to[out=-45,in=-135]
(5.75,0.75) to[out=45,in=-135]
(8.2,3.2) to[out=45,in=175]
(9.5,3.5) to[out=-85,in=45]
%
(9.2,2.2) to[out=-135,in=45]
(7.75,0.75) to[out=-135,in=-45]
(6.25,0.75) to[out=135,in=-45]
(3.75,3.25) to[out=135,in=45]
(2.25,3.25) to[out=-135,in=45]
(0.8,1.8) to[out=-135,in=95] cycle;
\end{knot}
\useasboundingbox (-0.5,-0.5) rectangle (10.5,4.5);
\end{tikzpicture}
\begin{tikzpicture}
\begin{knot}[
% draft mode=crossings,
flip crossing/.list={2,4,6,7,10,12}
]
\strand
([closed]0.5,0.5) to[out=-5,in=-135]
(1.9,0.9) to[out=45,in=-135]
(4.25,3.25) to[out=45,in=135]
(5.75,3.25) to[out=-45,in=135]
(8.1,0.9) to[out=-45,in=-175]
(9.5,0.5) to[out=85,in=-45]
%
(9.1,1.9) to[out=135,in=-45]
(7.75,3.25) to[out=135,in=45]
(6.25,3.25) to[out=-135,in=45]
(3.75,0.75) to[out=-135,in=-45]
(2.25,0.75) to[out=135,in=-45]
(0.9,2.1) to[out=135,in=-95]
(0.5,3.5) to[out=5,in=135]
%
(1.9,3.1) to[out=-45,in=135]
(4.25,0.75) to[out=-45,in=-135]
(5.75,0.75) to[out=45,in=-135]
(8.1,3.1) to[out=45,in=175]
(9.5,3.5) to[out=-85,in=45]
%
(9.1,2.1) to[out=-135,in=45]
(7.75,0.75) to[out=-135,in=-45]
(6.25,0.75) to[out=135,in=-45]
(3.75,3.25) to[out=135,in=45]
(2.25,3.25) to[out=-135,in=45]
(0.9,1.9) to[out=-135,in=95] cycle;
\end{knot}
\useasboundingbox (-0.5,-0.5) rectangle (10.5,4.5);
\end{tikzpicture}
\end{document}
我刚刚将修复版本上传到github。
(但我仍然可以看到其中上部的轻微伪影,这表明我可能还没有完全正确地修复 - 对于任何有数学倾向的人来说,这可能是因为我使用 l^1 范数来表示速度而不是 l^2 范数,所以我可能需要在某处使用 sqrt(2) 的因子。)
答案2
我为您提供另一种方法,直接使用 tikz。我的绘图是凯尔特式的,因为我真的不知道您想如何重叠线条。还有一个额外的示例供您了解如何任意重叠线条。
这是我的代码:
\begin{document}
\begin{tikzpicture}[line join=round, line cap=round, thick, blue, fill=blue!10]
% Coordinates
\pgfmathsetmacro\r{sqrt(2)}
\foreach\x in {1,...,5} \foreach\y in {1,2}
{
\coordinate (\x-\y-O) at (1.5*\r*\x,1.5*\r*\y);
\coordinate (\x-\y-N) at ($(\x-\y-O)+(0,0.5*\r)$);
\coordinate (\x-\y-S) at ($(\x-\y-O)-(0,0.5*\r)$);
\coordinate (\x-\y-E) at ($(\x-\y-O)+(0.5*\r,0)$);
\coordinate (\x-\y-W) at ($(\x-\y-O)-(0.5*\r,0)$);
}
% Middle section
\foreach\x in {2,3,4}
{
\pgfmathtruncatemacro\xx{\x-1}
\filldraw (\x-1-N) ++ (225:1) arc (225:315:1) --++ (45:1.5) --++
(315:0.5) --++ (225:1.5) --++ (0,0) arc (315:225:1.5) --cycle;
\filldraw (\x-2-W) --++ (315:2.5) --++ (225:0.5) --++ (135:2.5) -- cycle;
\filldraw (\xx-2-S) --++ (45:1.5) --++ (0,0) arc (135:45:1.5) --++
(225:0.5) --++ (0,0) arc (45:135:1) --++ (225:1.5) -- cycle;
}
% Corners
\foreach \x/\y/\c/\a in {1/1/N/0, 1/2/E/270, 5/1/W/90, 5/2/S/180}
{
\begin{scope}[shift={(\x-\y-\c)},rotate=\a]
\filldraw (0,0) --++ (135:0.5) --++ (0,0) arc (135:180:1.5) --++ (270:1.5-0.5*\r) --++
(0:1.5-0.5*\r) --++ (0,0) arc (270:315:1.5) --++ (45:1.5) --++ (135:0.5) --++
(225:1.5) --++ (0,0) arc (315:270:1) --++ (180:1-0.5*\r) --++ (90:1-0.5*\r) --++
(0,0) arc (180:135:1) -- cycle;
\end{scope}
}
% Non-celtic example (superposed, comment it if you want)
\filldraw[draw=red,fill=red!10] (2-1-N) --++ (225:1.5) --++ (0,0) arc (315:270:1.5) --++
(180:1.5-0.5*\r) --++ (90:1.5-0.5*\r) --++ (0,0) arc (180:135:1.5) --++ (45:2) --++
(0,0) arc (135:45:1.5) --++ (315:3) --++ (225:0.5) --++ (135:3) --++
(0,0) arc (45:135:1) --++ (225:2) --++ (0,0) arc (135:180:1) --++
(270:1-0.5*\r) --++ (0:1-0.5*\r) --++ (0,0) arc (270:315:1) --++ (45:1.5) -- cycle;
% Auxiliar grid of squares
% \foreach\x in {1,...,5} \foreach\y in {1,2}
% {
% \draw[thin,black,dashed] (\x-\y-E) -- (\x-\y-N) -- (\x-\y-W) -- (\x-\y-S) -- cycle;
% }
\end{tikzpicture}
\end{document}
答案3
我知道这个问题的最佳解决方案是 Andy 提出的解决方案,他使用了 knots 库,正如 OP 所希望的那样。
但我对之前的解决方案并不完全满意,它更适合凯尔特人的情况。所以,为了好玩,我只是画了另一个解决方案,更加参数化,轴也发生了变化,更适合非凯尔特人的情况。
新代码:
\documentclass[border=2mm]{standalone}
\usepackage {tikz}
\usetikzlibrary{calc}
\begin{document}
\begin{tikzpicture}[line join=round, line cap=round, thick, blue, rotate=-45]
% Parameters
\def\na{4} % number of middle arcs
\def\sp{1} % separation between paths
\def\wp{0.5} % width of the path
% Distances
\pgfmathsetmacro\sm {\sp+\wp}
\pgfmathsetmacro\spd{sqrt(2)*\sp}
\pgfmathsetmacro\wpd{sqrt(2)*\wp}
\pgfmathsetmacro\smd{sqrt(2)*\sm}
\pgfmathsetmacro\lc {0.5*(\spd-\sp)}
% Central pattern (without crossings)
\foreach\i in {1,...,\na}
{
\pgfmathsetmacro\x{\i*\sm}
\coordinate (\i-O) at (\x,\x); % Square, center
\coordinate (\i-N) at ($(\i-O)+(-0.5*\sm, 0.5*\sm)$); % Square, north
\coordinate (\i-S) at ($(\i-O)+( 0.5*\sm,-0.5*\sm)$); % ...
\coordinate (\i-E) at ($(\i-O)+( 0.5*\sm, 0.5*\sm)$);
\coordinate (\i-W) at ($(\i-O)+(-0.5*\sm,-0.5*\sm)$);
% \node[red] at (\i-O) {\small\i-O};
% \node[red] at (\i-N) {\small\i-N};
% \node[red] at (\i-S) {\small\i-S};
% \node[red] at (\i-E) {\small\i-E};
% \node[red] at (\i-W) {\small\i-W};
\draw ($(\i-O)-( 0.5*\sp, 0.5*\sp)$) rectangle ($(\i-O)+(0.5*\sp,0.5*\sp)$);
\draw ($(\i-N)+(-0.5*\wp, 0.5*\wp)$) arc (90:135:\sp+\wp);
\draw ($(\i-N)+(-0.5*\wp, 0.5*\wp)$) arc (180:135:\sp+\wp);
\draw ($(\i-S)+( 0.5*\wp,-0.5*\wp)$) arc (270:315:\sp+\wp);
\draw ($(\i-S)+( 0.5*\wp,-0.5*\wp)$) arc (0:-45:\sp+\wp);
\draw ($(\i-E)+(-0.5*\wp, 0.5*\wp)$) --++ (-\sp,0) --++ (0,0) arc (180:135:\sp);
\draw ($(\i-E)+( 0.5*\wp,-0.5*\wp)$) --++ (0,-\sp) --++ (0,0) arc (270:315:\sp);
\draw ($(\i-W)+(-0.5*\wp, 0.5*\wp)$) --++ (0,\sp) --++ (0,0) arc (90:135:\sp);
\draw ($(\i-W)+( 0.5*\wp,-0.5*\wp)$) --++ (\sp,0) --++ (0,0) arc (0:-45:\sp);
}
% Left corners
\draw ($(1-W)+( 0.5*\wp,-0.5*\wp)$) arc (180:225:\sp) --++ (\lc,-\lc) --++ (\lc,\lc);
\draw ($(1-W)+(-0.5*\wp, 0.5*\wp)$) arc (270:225:\sp) --++ (-\lc,\lc) --++ (\lc,\lc);
\draw ($(1-W)+(-0.5*\wp,-0.5*\wp)$) arc (180:225:\sm) --++ ( 0.5*\wpd+\lc,-0.5*\wpd-\lc)
--++ (0.5*\wpd+\lc,0.5*\wpd+\lc);
\draw ($(1-W)+(-0.5*\wp,-0.5*\wp)$) arc (270:225:\sm) --++ (-0.5*\wpd-\lc, 0.5*\wpd+\lc)
--++ (0.5*\wpd+\lc,0.5*\wpd+\lc);
% Right corners
\draw ($(\na-E)+(-0.5*\wp, 0.5*\wp)$) arc (0:45:\sp) --++ (-\lc,\lc) --++ (-\lc,-\lc);
\draw ($(\na-E)+( 0.5*\wp,-0.5*\wp)$) arc (90:45:\sp) --++ (\lc,-\lc) --++ (-\lc,-\lc);
\draw ($(\na-E)+( 0.5*\wp, 0.5*\wp)$) arc (0:45:\sm) --++ (-0.5*\wpd-\lc, 0.5*\wpd+\lc)
--++ (-0.5*\wpd-\lc,-0.5*\wpd-\lc);
\draw ($(\na-E)+( 0.5*\wp, 0.5*\wp)$) arc (90:45:\sm) --++ ( 0.5*\wpd+\lc,-0.5*\wpd-\lc)
--++ (-0.5*\wpd-\lc,-0.5*\wpd-\lc);
% NE Crossings
\foreach \i/\C in {1/W, 1/S, 1/N, 2/S, 3/S, 3/N, 4/N, 4/S}
{
\draw ($(\i-\C)+(-0.5*\wp,-0.5*\wp)$) --++ (0,\wp);
\draw ($(\i-\C)+( 0.5*\wp,-0.5*\wp)$) --++ (0,\wp);
}
% NW Crossings
\foreach \i/\C in {2/W, 2/N, 3/W, 4/W, 4/E}
{
\draw ($(\i-\C)+(-0.5*\wp, 0.5*\wp)$) --++ (\wp,0);
\draw ($(\i-\C)+(-0.5*\wp,-0.5*\wp)$) --++ (\wp,0);
}
\end{tikzpicture}
\end{document}