
Я рисую диаграмму узлов и использую \clip
команду, чтобы помочь затенить регионы. Однако, похоже, что \strand
команда окружения knot
имеет какой-то странный эффект на \clip
.
Например, правильный результат должен быть (назовем егоДиаграмма 1):
который генерируется
% Diagram 1
\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{knots}
\usetikzlibrary{hobby}
\begin{document}
\definecolor{skyblue}{RGB}{60,120,234}
\scalebox{0.3}{\begin{tikzpicture}[use Hobby shortcut]
\pgfdeclarelayer{foreground}
\pgfsetlayers{main,foreground}
\begin{pgfonlayer}{foreground}
\begin{scope}
\clip (-2,3) .. (0,2) .. (0.4,1)
.. (0,0) .. (-0.4,-1)
.. (0,-2) .. (2,-3)
.. (4.8,0) .. (2,3)
.. (0,2) .. (-0.4,1) -- (-2,3);
\clip (-2,-3) .. (0,-2) .. (0.4,-1)
.. (0,0) .. (-0.4,1)
.. (0,2) .. (2,3)
.. (4.8,0) .. (2,-3)
.. (0,-2) .. (-0.4,-1) -- (-2,-3);
\fill[skyblue,opacity=0.2] (-4.8,-3) rectangle (4.8,3);
\end{scope}
\begin{scope}
\clip (2,3) .. (0,2) .. (-0.4,1)
.. (0,0) .. (0.4,-1)
.. (0,-2) .. (-2,-3)
.. (-4.8,0) .. (-2,3)
.. (0,2) .. (0.4,1) -- (2,3);
\clip (2,-3) .. (0,-2) .. (-0.4,-1)
.. (0,0) .. (0.4,1)
.. (0,2) .. (-2,3)
.. (-4.8,0) .. (-2,-3)
.. (0,-2) .. (0.4,-1) -- (2,-3);
\fill[skyblue,opacity=0.2] (-4.8,-3) rectangle (4.8,3);
\end{scope}
\draw (-2.2,0) node[scale=3] {$+$};
\draw (2.2,0) node[scale=3] {$-$};
\draw (5,2.5) node[scale=3] {$M$};
\end{pgfonlayer}
\begin{knot}[
consider self intersections,
clip width=10,
clip radius=0.5cm,
ignore endpoint intersections=false,
flip crossing/.list={6,14}
]
\strand[very thick,black,closed]
(0.4,1) .. (0,2) .. (-2,3)
.. (-4.8,0) .. (-2,-3)
.. (0,-2) .. (0.4,-1)
.. (0,0) .. (-0.4,1)
.. (0,2) .. (2,3)
.. (4.8,0) .. (2,-3)
.. (0,-2) .. (-0.4,-1) .. (0,0);
\end{knot}
\end{tikzpicture}}
\end{document}
Обратите внимание, что \clip
этодо \strand
.
Однако если я поменяю порядок фрагмента кода, содержащего \clip
и \strand
:
% Diagram 2
\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{knots}
\usetikzlibrary{hobby}
\begin{document}
\definecolor{skyblue}{RGB}{60,120,234}
\scalebox{0.3}{\begin{tikzpicture}[use Hobby shortcut]
\pgfdeclarelayer{foreground}
\pgfsetlayers{main,foreground}
\begin{knot}[
consider self intersections,
clip width=10,
clip radius=0.5cm,
ignore endpoint intersections=false,
flip crossing/.list={6,14}
]
\strand[very thick,black,closed]
(0.4,1) .. (0,2) .. (-2,3)
.. (-4.8,0) .. (-2,-3)
.. (0,-2) .. (0.4,-1)
.. (0,0) .. (-0.4,1)
.. (0,2) .. (2,3)
.. (4.8,0) .. (2,-3)
.. (0,-2) .. (-0.4,-1) .. (0,0);
\end{knot}
\begin{pgfonlayer}{foreground}
\begin{scope}
\clip (-2,3) .. (0,2) .. (0.4,1)
.. (0,0) .. (-0.4,-1)
.. (0,-2) .. (2,-3)
.. (4.8,0) .. (2,3)
.. (0,2) .. (-0.4,1) -- (-2,3);
\clip (-2,-3) .. (0,-2) .. (0.4,-1)
.. (0,0) .. (-0.4,1)
.. (0,2) .. (2,3)
.. (4.8,0) .. (2,-3)
.. (0,-2) .. (-0.4,-1) -- (-2,-3);
\fill[skyblue,opacity=0.2] (-4.8,-3) rectangle (4.8,3);
\end{scope}
\begin{scope}
\clip (2,3) .. (0,2) .. (-0.4,1)
.. (0,0) .. (0.4,-1)
.. (0,-2) .. (-2,-3)
.. (-4.8,0) .. (-2,3)
.. (0,2) .. (0.4,1) -- (2,3);
\clip (2,-3) .. (0,-2) .. (-0.4,-1)
.. (0,0) .. (0.4,1)
.. (0,2) .. (-2,3)
.. (-4.8,0) .. (-2,-3)
.. (0,-2) .. (0.4,-1) -- (2,-3);
\fill[skyblue,opacity=0.2] (-4.8,-3) rectangle (4.8,3);
\end{scope}
\draw (-2.2,0) node[scale=3] {$+$};
\draw (2.2,0) node[scale=3] {$-$};
\draw (5,2.5) node[scale=3] {$M$};
\end{pgfonlayer}
\end{tikzpicture}}
\end{document}
Результат становится (назовем егоДиаграмма 2):
Как видите, штриховка не вписывается в кривую.
Даже если я использую код для генерацииДиаграмма 1(где \clip
находится перед \strand
), ошибка все равно будет появляться, когда есть другие \strand
команды перед \clip
кодом. Это можно увидеть, повторив код дляДиаграмма 1дважды:
\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{knots}
\usetikzlibrary{hobby}
\begin{document}
\definecolor{skyblue}{RGB}{60,120,234}
\scalebox{0.3}{\begin{tikzpicture}[use Hobby shortcut]
\pgfdeclarelayer{foreground}
\pgfsetlayers{main,foreground}
\begin{pgfonlayer}{foreground}
\begin{scope}
\clip (-2,3) .. (0,2) .. (0.4,1)
.. (0,0) .. (-0.4,-1)
.. (0,-2) .. (2,-3)
.. (4.8,0) .. (2,3)
.. (0,2) .. (-0.4,1) -- (-2,3);
\clip (-2,-3) .. (0,-2) .. (0.4,-1)
.. (0,0) .. (-0.4,1)
.. (0,2) .. (2,3)
.. (4.8,0) .. (2,-3)
.. (0,-2) .. (-0.4,-1) -- (-2,-3);
\fill[skyblue,opacity=0.2] (-4.8,-3) rectangle (4.8,3);
\end{scope}
\begin{scope}
\clip (2,3) .. (0,2) .. (-0.4,1)
.. (0,0) .. (0.4,-1)
.. (0,-2) .. (-2,-3)
.. (-4.8,0) .. (-2,3)
.. (0,2) .. (0.4,1) -- (2,3);
\clip (2,-3) .. (0,-2) .. (-0.4,-1)
.. (0,0) .. (0.4,1)
.. (0,2) .. (-2,3)
.. (-4.8,0) .. (-2,-3)
.. (0,-2) .. (0.4,-1) -- (2,-3);
\fill[skyblue,opacity=0.2] (-4.8,-3) rectangle (4.8,3);
\end{scope}
\draw (-2.2,0) node[scale=3] {$+$};
\draw (2.2,0) node[scale=3] {$-$};
\draw (5,2.5) node[scale=3] {$M$};
\end{pgfonlayer}
\begin{knot}[
consider self intersections,
clip width=10,
clip radius=0.5cm,
ignore endpoint intersections=false,
flip crossing/.list={6,14}
]
\strand[very thick,black,closed]
(0.4,1) .. (0,2) .. (-2,3)
.. (-4.8,0) .. (-2,-3)
.. (0,-2) .. (0.4,-1)
.. (0,0) .. (-0.4,1)
.. (0,2) .. (2,3)
.. (4.8,0) .. (2,-3)
.. (0,-2) .. (-0.4,-1) .. (0,0);
\end{knot}
\end{tikzpicture}}
\scalebox{0.3}{\begin{tikzpicture}[use Hobby shortcut]
\pgfdeclarelayer{foreground}
\pgfsetlayers{main,foreground}
\begin{pgfonlayer}{foreground}
\begin{scope}
\clip (-2,3) .. (0,2) .. (0.4,1)
.. (0,0) .. (-0.4,-1)
.. (0,-2) .. (2,-3)
.. (4.8,0) .. (2,3)
.. (0,2) .. (-0.4,1) -- (-2,3);
\clip (-2,-3) .. (0,-2) .. (0.4,-1)
.. (0,0) .. (-0.4,1)
.. (0,2) .. (2,3)
.. (4.8,0) .. (2,-3)
.. (0,-2) .. (-0.4,-1) -- (-2,-3);
\fill[skyblue,opacity=0.2] (-4.8,-3) rectangle (4.8,3);
\end{scope}
\begin{scope}
\clip (2,3) .. (0,2) .. (-0.4,1)
.. (0,0) .. (0.4,-1)
.. (0,-2) .. (-2,-3)
.. (-4.8,0) .. (-2,3)
.. (0,2) .. (0.4,1) -- (2,3);
\clip (2,-3) .. (0,-2) .. (-0.4,-1)
.. (0,0) .. (0.4,1)
.. (0,2) .. (-2,3)
.. (-4.8,0) .. (-2,-3)
.. (0,-2) .. (0.4,-1) -- (2,-3);
\fill[skyblue,opacity=0.2] (-4.8,-3) rectangle (4.8,3);
\end{scope}
\draw (-2.2,0) node[scale=3] {$+$};
\draw (2.2,0) node[scale=3] {$-$};
\draw (5,2.5) node[scale=3] {$M$};
\end{pgfonlayer}
\begin{knot}[
consider self intersections,
clip width=10,
clip radius=0.5cm,
ignore endpoint intersections=false,
flip crossing/.list={6,14}
]
\strand[very thick,black,closed]
(0.4,1) .. (0,2) .. (-2,3)
.. (-4.8,0) .. (-2,-3)
.. (0,-2) .. (0.4,-1)
.. (0,0) .. (-0.4,1)
.. (0,2) .. (2,3)
.. (4.8,0) .. (2,-3)
.. (0,-2) .. (-0.4,-1) .. (0,0);
\end{knot}
\end{tikzpicture}}
\end{document}
Вы можете, очевидно, видеть, что даже если они нарисованытакой жеКоды TikZ, результаты не те же.
Может ли кто-нибудь объяснить, что происходит икак это исправить? Заранее спасибо.
решение1
При более детальном тестировании выяснилось, что это не ошибка ни в одном из них, hobby
ни knots
в , а «особенность» их взаимодействия, которая, вероятно, должна быть где-то задокументирована.
Чтобы создать замкнутую кривую хобби, можно ввести:
\draw[closed] (0,0) .. (1,1) .. (0,2) .. (-1,1) .. (0,0);
а closed
указывает на то, что кривую следует рассматривать как замкнутую кривую, а не как кривую, конечные точки которой находятся в одной точке ( hobby
более подробную информацию об этом различии см. в документации).
Теперь опция closed
в \draw
команде немного не к месту, потому что TikZ в этот момент не знает, что кривая хобби уже на подходе. Поэтому нам нужно сохранить эту команду и фактически сказать «примени это к следующей кривой хобби, с которой ты столкнешься». В конце концов, на пути могут быть некоторые нехобби-вещи до того, как будет создана кривая хобби.
Обычно это все хорошо и хорошо, и это самый простой способ указать, что кривая хобби должна быть замкнутой. Но иногда нам нужен более тонкий контроль, например, если мы используем две конструкции хобби на одном пути. В этой ситуации мы можем добавить опцию closed
к координате в пути хобби. Таким образом, любой из следующих вариантов нарисует тот же путь, что и выше:
\draw ([closed]0,0) .. (1,1) .. (0,2) .. (-1,1) .. (0,0);
\draw (0,0) .. ([closed]1,1) .. (0,2) .. (-1,1) .. (0,0);
\draw (0,0) .. (1,1) .. (0,2) .. (-1,1) .. ([closed]0,0);
Во втором и третьем из них TikZ знает, что он строит хобби-путь, и поэтому может сказать: «Ладно, мы закроемэтотpath.". В первом случае конструкция хобби не была запущена (что происходит в первом случае ..
), поэтомучто closed
по-прежнему "Примени это к следующему хобби". Но это небольшая формальность.
После того, как параметры применены к пути хобби, будь то из более ранней настройки стиля или из параметров, собранных из координат, ониочищены(и в целом). Если что-то пойдет не так с расчисткой, то есть стиль clear next Hobby path options
, который можно использовать, чтобысилаочистите параметры.
Так же как hobby
и вести себя должным образом.
Давайте обратимся к knots
. Когда вы определяете нить, (через \strand
), то путь используетсямного. Если ничего другого, он используется для рисования самой нити, а затем для вырезания кусочков из нитей, по которым он проходит (так что для каждого пересечения нить перерисовывается). Все становится еще хуже, когда consider self intersections
используется ключ, потому что это требует разделения нити на компоненты и рассмотрения каждой из них отдельно. Поэтому нить рисуетсямного раз.
Каждый раз, когда он рисуется, его нужно стилизовать. Поэтому \strand
сохраняет свои параметры стиля и вызывает их заново каждый раз, когда нить рисуется. Обычно это именно то, что нужно. Но параметры, которые влияют настроительствопути здесь не нужны, так как путь уже построен. Обычно это не имеет значения - такие варианты обычно отбрасываются.
Но не closed
вариант для хобби-путей. Поскольку это команда с отложенным действием, она висит в ожидании следующего хобби-путя. Хобби-путь, который былимел в видуибо был построен и с ним разобрались. Поэтому он терпеливо ждет следующего. И поскольку этот следующий не должен быть закрыт, вы получаете сюрприз, который вы сделали.
Ладно, перейдем к решениям. Самое простое и, ИМХО, лучшее решение — переместить из closed
в \strand
одну из координат.
\strand[very thick,black]
([closed]0.4,1) .. (0,2) .. (-2,3)
.. (-4.8,0) .. (-2,-3)
.. (0,-2) .. (0.4,-1)
.. (0,0) .. (-0.4,1)
.. (0,2) .. (2,3)
.. (4.8,0) .. (2,-3)
.. (0,-2) .. (-0.4,-1) .. (0,0);
Альтернативой было бы поместить ключ clear next Hobby path options
перед путем, который запутывается. Мне это не кажется таким уж элегантным, но я упоминаю это как альтернативу.
Можно утверждать, что когда начинается путь, он должен очищать опции, чтобы каждый путь начинался с чистого листа. Однако, чтобы сделать это надежным, потребуется подключиться к механизму определения области действия TikZ на немного более глубоком уровне, чем я делал до сих пор с пакетом хобби. Так что это то, что я буду иметь в виду, если обнаружу, что мне нужно подключиться по другой причине, но пока я оставлю это на заднем плане.
Учитывая все это, вот мое рекомендуемое решение:
\documentclass{standalone}
% \url{https://tex.stackexchange.com/q/505080/86}
\usepackage{tikz}
\usetikzlibrary{knots}
\usetikzlibrary{hobby}
\begin{document}
\definecolor{skyblue}{RGB}{60,120,234}
\scalebox{0.3}{\begin{tikzpicture}[use Hobby shortcut]
\pgfdeclarelayer{foreground}
\pgfsetlayers{main,foreground}
\begin{pgfonlayer}{foreground}
\begin{scope}
\clip (-2,3) .. (0,2) .. (0.4,1)
.. (0,0) .. (-0.4,-1)
.. (0,-2) .. (2,-3)
.. (4.8,0) .. (2,3)
.. (0,2) .. (-0.4,1) -- (-2,3);
\clip (-2,-3) .. (0,-2) .. (0.4,-1)
.. (0,0) .. (-0.4,1)
.. (0,2) .. (2,3)
.. (4.8,0) .. (2,-3)
.. (0,-2) .. (-0.4,-1) -- (-2,-3);
\fill[skyblue,opacity=0.2] (-4.8,-3) rectangle (4.8,3);
\end{scope}
\begin{scope}
\clip (2,3) .. (0,2) .. (-0.4,1)
.. (0,0) .. (0.4,-1)
.. (0,-2) .. (-2,-3)
.. (-4.8,0) .. (-2,3)
.. (0,2) .. (0.4,1) -- (2,3);
\clip (2,-3) .. (0,-2) .. (-0.4,-1)
.. (0,0) .. (0.4,1)
.. (0,2) .. (-2,3)
.. (-4.8,0) .. (-2,-3)
.. (0,-2) .. (0.4,-1) -- (2,-3);
\fill[skyblue,opacity=0.2] (-4.8,-3) rectangle (4.8,3);
\end{scope}
\draw (-2.2,0) node[scale=3] {$+$};
\draw (2.2,0) node[scale=3] {$-$};
\draw (5,2.5) node[scale=3] {$M$};
\end{pgfonlayer}
\begin{knot}[
consider self intersections,
clip width=10,
clip radius=0.5cm,
ignore endpoint intersections=false,
flip crossing/.list={6,14}
]
\strand[very thick,black]
([closed]0.4,1) .. (0,2) .. (-2,3)
.. (-4.8,0) .. (-2,-3)
.. (0,-2) .. (0.4,-1)
.. (0,0) .. (-0.4,1)
.. (0,2) .. (2,3)
.. (4.8,0) .. (2,-3)
.. (0,-2) .. (-0.4,-1) .. (0,0);
\end{knot}
\end{tikzpicture}}
\scalebox{0.3}{\begin{tikzpicture}[use Hobby shortcut]
\pgfdeclarelayer{foreground}
\pgfsetlayers{main,foreground}
\begin{pgfonlayer}{foreground}
\begin{scope}
\clip (-2,3) .. (0,2) .. (0.4,1)
.. (0,0) .. (-0.4,-1)
.. (0,-2) .. (2,-3)
.. (4.8,0) .. (2,3)
.. (0,2) .. (-0.4,1) -- (-2,3);
\clip (-2,-3) .. (0,-2) .. (0.4,-1)
.. (0,0) .. (-0.4,1)
.. (0,2) .. (2,3)
.. (4.8,0) .. (2,-3)
.. (0,-2) .. (-0.4,-1) -- (-2,-3);
\fill[skyblue,opacity=0.2] (-4.8,-3) rectangle (4.8,3);
\end{scope}
\begin{scope}
\clip (2,3) .. (0,2) .. (-0.4,1)
.. (0,0) .. (0.4,-1)
.. (0,-2) .. (-2,-3)
.. (-4.8,0) .. (-2,3)
.. (0,2) .. (0.4,1) -- (2,3);
\clip (2,-3) .. (0,-2) .. (-0.4,-1)
.. (0,0) .. (0.4,1)
.. (0,2) .. (-2,3)
.. (-4.8,0) .. (-2,-3)
.. (0,-2) .. (0.4,-1) -- (2,-3);
\fill[skyblue,opacity=0.2] (-4.8,-3) rectangle (4.8,3);
\end{scope}
\draw (-2.2,0) node[scale=3] {$+$};
\draw (2.2,0) node[scale=3] {$-$};
\draw (5,2.5) node[scale=3] {$M$};
\end{pgfonlayer}
\begin{knot}[
consider self intersections,
clip width=10,
clip radius=0.5cm,
ignore endpoint intersections=false,
flip crossing/.list={6,14}
]
\strand[very thick,black]
([closed]0.4,1) .. (0,2) .. (-2,3)
.. (-4.8,0) .. (-2,-3)
.. (0,-2) .. (0.4,-1)
.. (0,0) .. (-0.4,1)
.. (0,2) .. (2,3)
.. (4.8,0) .. (2,-3)
.. (0,-2) .. (-0.4,-1) .. (0,0);
\end{knot}
\end{tikzpicture}}
\end{document}