nós: O comando \strand parece ter um efeito estranho em relação ao comando \clip

nós: O comando \strand parece ter um efeito estranho em relação ao comando \clip

Estou desenhando um diagrama de nós e uso o \clipcomando para ajudar a sombrear as regiões. No entanto, parece que o \strandcomando do knotambiente tem algum efeito estranho \clip.

Por exemplo, o resultado correto deveria ser (vamos chamá-loDiagrama 1):O resultado desejado 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 \clipe \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): imagem ruim Como você pode ver, o sombreamento não cabe na curva.

Mesmo se eu usar o código para gerarDiagrama 1(onde \clipestá antes \strand), o erro ainda apareceria quando houvesse outros \strandcomandos antes do \clipcó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}

insira a descrição da imagem aqui 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 hobbyor 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 closedindica que a curva deve ser considerada uma curva fechada em vez de uma curva cujos pontos finais estão no mesmo ponto (consulte a hobbydocumentação para obter mais informações sobre a diferença).

Agora a opção closedno \drawcomando 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 closedopçã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 closedainda é "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 optionsque pode ser usado paraforçalimpe as opções.

Então hobbyestá 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 \strandarmazena 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 closedopçã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 closedpara \stranduma 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 optionsantes 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}

Uso correto de hobby e nós

informação relacionada