nudos: El comando \strand parece tener un efecto extraño respecto al comando \clip

nudos: El comando \strand parece tener un efecto extraño respecto al comando \clip

Estoy dibujando un diagrama de nudos y uso el \clipcomando para ayudar a sombrear las regiones. Sin embargo, parece que el \strandmando del knotentorno tiene algún efecto extraño \clip.

Por ejemplo, el resultado correcto debería ser (llamémosloDiagrama 1):El resultado deseado que es generado 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}

Note que \clipesantes \strand.

Sin embargo, si cambio el orden del fragmento de código que contiene \clipy \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}

El resultado se convierte (llamémosloDiagrama 2): mala imagen Como puedes ver, el sombreado no encaja en la curva.

Incluso si uso el código para generarDiagrama 1(donde \clipestá antes \strand), el error seguirá apareciendo cuando haya otros \strandcomandos antes del \clipcódigo. Se puede ver esto repitiendo el código paraDiagrama 1dos veces:

\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}

ingrese la descripción de la imagen aquí Evidentemente puedes ver que a pesar de que están atraídos por elmismoCódigos TikZ, los resultados no son los mismos.

¿Alguien podría explicar qué está pasando yCómo arreglar esto? Gracias de antemano.

Respuesta1

Tras realizar pruebas un poco más exhaustivas, esto no es un error en ninguno de los hobbydos knots, sino que es una "característica" de su interacción que probablemente debería documentarse en alguna parte.

Para crear una curva de hobby cerrada, se puede escribir:

\draw[closed] (0,0) .. (1,1) .. (0,2) .. (-1,1) .. (0,0);

y closedindica que la curva debe considerarse como una curva cerrada en lugar de una curva cuyos puntos finales se encuentran en el mismo punto (consulte la hobbydocumentación para obtener más información sobre la diferencia).

Ahora la opción closeden el \drawcomando está un poco fuera de lugar porque TikZ no sabe en ese momento que una curva de hobby está en camino. Así que tenemos que almacenar ese comando y efectivamente decir "aplica esto a la siguiente curva de hobby que encuentres". Después de todo, podría haber algunas cosas que no sean de pasatiempos en el camino antes de que se cree la curva de pasatiempos.

Normalmente, esto está muy bien y es la forma más sencilla de especificar que se debe cerrar una curva de hobby. Pero a veces necesitamos un control más preciso, por ejemplo si utilizamos dos construcciones de hobby en el mismo camino. En esta situación podemos agregar la closedopción a una coordenada en la ruta del hobby. Entonces, cualquiera de los siguientes dibujaría el mismo camino que el anterior:

\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);

En el segundo y tercer caso, TikZ sabe que está construyendo un camino de afición y por eso puede decir: "Bien, cerramos".estecamino". En el primero, la construcción del hobby no se ha activado (lo que sucede en el primero ..), por lo queeso closedsigue siendo "Aplicar esto al próximo pasatiempo". Pero ese es un pequeño tecnicismo.

Una vez que se aplican las opciones a una ruta de hobby, ya sea de una configuración de estilo anterior o de opciones recopiladas de las coordenadas, entoncesestan limpios(y a nivel mundial). Si algo sale mal con el claro, entonces hay un estilo clear next Hobby path optionsque se puede utilizar parafuerzaborre las opciones.

También lo hobbyes comportarse como se debe.

Pasemos a knots. Cuando defines una hebra, (a través de\strand ), entonces se utiliza la rutamucho. Al menos, se acostumbra a dibujar la hebra y luego a cortar trozos de las hebras sobre las que pasa (por lo que, para cada intersección, la hebra se vuelve a dibujar). Las cosas empeoran aún más cuando consider self intersectionsse utiliza la clave porque esto requiere dividir el hilo en componentes y considerar cada uno por separado. Entonces la hebra se dibujamuchas veces.

Cada vez que se dibuja, es necesario diseñarlo. Así \strandalmacena sus opciones de estilo y las reinvoca cada vez que se dibuja el hilo. Normalmente, esto es exactamente lo que se necesita. Pero las opciones que afectan laconstruccióndel camino no son necesarios aquí porque el camino ya ha sido construido. Normalmente esto no importa: estas opciones suelen descartarse.

Pero no la closedopción para los caminos de hobby. Debido a que se trata de un comando de acción retrasada, se queda esperando el próximo camino de hobby. El camino del hobby fuequiso decirporque ha sido construido y ha sido tratado. Así que espera, con mucha paciencia, el siguiente. Y como el siguiente no está destinado a cerrarse, te llevas la sorpresa de que lo hiciste.

Bien, pasemos a las soluciones. La solución más simple, y en mi humilde opinión la mejor, es cambiar las coordenadas closedde a una.\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);

Una alternativa sería poner la llave clear next Hobby path optionsantes del camino que se está confundiendo. Esto no me parece tan elegante, pero lo menciono como alternativa.

Se podría argumentar que cuando comienza un camino, se deben borrar las opciones para que cada camino comience con una pizarra en blanco. Sin embargo, para hacerlo robusto sería necesario conectarse al mecanismo de alcance de TikZ a un nivel ligeramente más profundo que el que he hecho hasta ahora con el paquete hobby. Así que es algo que tendré en cuenta si encuentro que necesito conectarme por otra razón, pero por ahora lo dejaré en un segundo plano.

Con todo eso aclarado, aquí está mi solución 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 correcto de pasatiempos y nudos.

información relacionada