
Estou desenhando um diagrama de nós e uso o \clip
comando para ajudar a sombrear as regiões. No entanto, parece que o \strand
comando do knot
ambiente tem algum efeito estranho \clip
.
Por exemplo, o resultado correto deveria ser (vamos chamá-loDiagrama 1):
que é gerado por
% 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}
Observe que \clip
éantes \strand
.
No entanto, se eu mudar a ordem do fragmento de código que contém \clip
e \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}
O resultado se torna (vamos chamá-loDiagrama 2):
Como você pode ver, o sombreamento não cabe na curva.
Mesmo se eu usar o código para gerarDiagrama 1(onde \clip
está antes \strand
), o erro ainda apareceria quando houvesse outros \strand
comandos antes do \clip
código. Pode-se ver isso repetindo o código paraDiagrama 1duas vezes:
\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}
Você pode evidentemente ver que, embora eles sejam atraídos pelomesmoCódigos TikZ, os resultados não são os mesmos.
Alguém poderia explicar o que está acontecendo eComo consertar isto? Desde já, obrigado.
Responder1
Em alguns testes adicionais, isso não é um bug no hobby
or knots
, mas é um "recurso" de sua interação que provavelmente deve ser documentado em algum lugar.
Para criar uma curva de hobby fechada, pode-se digitar:
\draw[closed] (0,0) .. (1,1) .. (0,2) .. (-1,1) .. (0,0);
e closed
indica que a curva deve ser considerada uma curva fechada em vez de uma curva cujos pontos finais estão no mesmo ponto (consulte a hobby
documentação para obter mais informações sobre a diferença).
Agora a opção closed
no \draw
comando está um pouco deslocada porque o TikZ não sabe naquele momento que uma curva de hobby está a caminho. Portanto, temos que armazenar esse comando e dizer efetivamente "aplique isso à próxima curva de hobby que você encontrar". Afinal, pode haver algumas coisas que não sejam de hobby no caminho antes que a curva do hobby seja criada.
Normalmente, isso é muito bom e é a maneira mais fácil de especificar que uma curva de hobby deve ser fechada. Mas às vezes precisamos de um controle mais preciso, por exemplo, se usarmos duas construções de hobby no mesmo caminho. Nesta situação podemos adicionar a closed
opção de uma coordenada no caminho do hobby. Portanto, qualquer um dos seguintes desenharia o mesmo caminho acima:
\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);
No segundo e terceiro deles, o TikZ sabe que está construindo um caminho de hobby e então pode dizer "Certo, vamos fecharessecaminho.". No primeiro, a construção do hobby não foi acionada (o que acontece no primeiro ..
), entãoque closed
ainda é "Aplique isto ao próximo caminho de hobby.". Mas isso é um pequeno detalhe técnico.
Uma vez que as opções são aplicadas a um caminho de hobby, seja de uma configuração de estilo anterior ou de opções coletadas das coordenadas, então elassão limpos(e globalmente). Se algo der errado com a compensação, então existe um estilo clear next Hobby path options
que pode ser usado paraforçalimpe as opções.
Então hobby
está se comportando como deveria.
Vamos voltar para knots
. Quando você define uma vertente, (via \strand
), então o caminho é usadobastante. No mínimo, ele se acostuma a desenhar o próprio fio e depois cortar pedaços dos fios que ele passa (portanto, para cada interseção, o fio é redesenhado). As coisas ficam ainda piores quando a chave consider self intersections
é usada porque isso exige dividir o fio em componentes e considerar cada um deles separadamente. Então o fio é desenhadomuitas vezes.
Cada vez que é desenhado, precisa ser estilizado. Assim \strand
armazena suas opções de estilo e as invoca novamente cada vez que o fio é desenhado. Normalmente, isso é exatamente o que é necessário. Mas as opções que afetam oconstruçãodo caminho não são necessários aqui porque o caminho já foi construído. Normalmente, isso não importa – tais opções são geralmente descartadas.
Mas não a closed
opção por caminhos de hobby. Como este é um comando de ação retardada, ele fica esperando pelo próximo caminho de hobby. O caminho do hobby erasignificoupois foi construído e tratado. Então espera, com muita paciência, pelo próximo. E como esse próximo não é para ser fechado, você fica com a surpresa que fez.
Ok, então vamos às soluções. A solução mais simples, e a melhor IMHO, é mudar de closed
para \strand
uma das coordenadas.
\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);
Uma alternativa seria colocar a chave clear next Hobby path options
antes do caminho que está sendo confuso. Isso não parece tão elegante para mim, mas menciono isso como uma alternativa.
Pode-se argumentar que quando um caminho começa, as opções devem ser limpas para que cada caminho comece com uma tela em branco. No entanto, para tornar isso robusto, seria necessário conectar-se ao mecanismo de escopo do TikZ em um nível um pouco mais profundo do que fiz até agora com o pacote de hobby. Portanto, é algo que terei em mente se achar que preciso me conectar por outro motivo, mas por enquanto deixarei isso em segundo plano.
Com tudo isso resolvido, aqui está minha solução recomendada:
\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}