Para una especie de ilustración matemática, consideremos el caso en el que se requieren varios sombreados distinguibles, todos en blanco y negro, y una dirección precisa tiene significado.
Doy un ejemplo sencillo de un patrón de sombreado en el MWE.
1¿Existe alguna forma general de escribir simplemente una macro para generar un patrón de sombreado de este tipo pero con una única variable numérica que controle la dirección?
Para aclarar todos mis intentos de hacer una macro, llámala MCR, tal que:
pattern=MCR x ,pattern color=...
donde x=2 o 1 o 0 para horizontal, o 0,5 para vertical, o 0,25 para diagonal, y aproximadamente en el medio.
O
Hasta ahora también he usado una macro para importar un gráfico en un nodo para usarlo como patrón, escalándolo o estirándolo, y a menudo usando la configuración [clip] de \draw y el orden de ejecución ordenada para obtener el efecto deseado. . Una macro breve facilita el uso repetido.
2Entonces, alternativamente, ¿es posible construir un gráfico de sombreado, uno de noroeste a sureste, además del dado de suroeste a noreste, y luego enviarlo a un archivo y usar gráficos de entrada en un nodo para rotar la imagen y usarlo como patrón? La solución a1es preferible a esto, si1es posible.
\documentclass{standalone}\usepackage{pgfplots,tikz}\usetikzlibrary{patterns}
\def\dotshading{figuretonedots}
\def\toning #1 #2 #3 {\node at (#1) {\includegraphics[width=#3\textwidth]{\csname #2\endcsname}};}
\begin{document}\begin{tikzpicture}%
\pgfdeclarepatternformonly{ltrtoning}%
{\pgfqpoint{-1pt}{-1pt}}{\pgfqpoint{10pt}{10pt}}%
{\pgfqpoint{9pt}{9pt}}{
\pgfsetlinewidth{0.32pt}
\pgfpathmoveto{\pgfqpoint{0pt}{0pt}}
\pgfpathlineto{\pgfqpoint{9.1pt}{9.1pt}}
\pgfusepath{stroke}}%
%\toning 6.78,6.78 dotshading 1.1 %removing this removes toning
\draw[draw=none,pattern=ltrtoning,pattern color=black!64]rectangle(13.4,13.4);
\end{tikzpicture}\end{document}
Respuesta1
Actualmente, PGF no admite agregar una matriz de transformación al patrón, por lo que no es posible una rotación general.
Se podrían (con cierta sobrecarga computacional) utilizar imágenes de ruta.
Sin embargo, lo siguiente muestra una forma (ciertamente muy mala) de lograr patrones rotados pirateando la capa del sistema para incluir una matriz de transformación para los patrones y explotando el hecho de que los patrones "mutables" (que en realidad no son mutables) se crean justo antes de que se aplican dependiendo del valor de las variables proporcionadas en la definición del patrón.
\documentclass[tikz, border=5]{standalone}
\usetikzlibrary{patterns}
\makeatletter
\def\pgfsys@patternmatrix{1.0 0.0 0.0 1.0 0.0 0.0}
\def\pgfsys@declarepattern#1#2#3#4#5#6#7#8#9{%
% Start building the pattern dictionary:
\pgf@xa=#2\relax%
\pgf@ya=#3\relax%
\pgf@xb=#4\relax%
\pgf@yb=#5\relax%
\pgf@xc=#6\relax%
\pgf@yc=#7\relax%
\pgf@sys@bp@correct\pgf@xa%
\pgf@sys@bp@correct\pgf@ya%
\pgf@sys@bp@correct\pgf@xb%
\pgf@sys@bp@correct\pgf@yb%
\pgf@sys@bp@correct\pgf@xc%
\pgf@sys@bp@correct\pgf@yc%
% Now create the pattern object:
\immediate\pdfobj stream
attr
{
/Type /Pattern
/PatternType 1
/PaintType \ifnum#9=0 2 \else 1 \fi
/TilingType 1
/BBox [\pgf@sys@tonumber\pgf@xa\space\pgf@sys@tonumber\pgf@ya\space\pgf@sys@tonumber\pgf@xb\space\pgf@sys@tonumber\pgf@yb]
/XStep \pgf@sys@tonumber\pgf@xc\space
/YStep \pgf@sys@tonumber\pgf@yc\space
/Matrix [\pgfsys@patternmatrix]
/Resources << >> %<<
}
{#8}%
\pgfutil@addpdfresource@patterns{/pgfpat#1\space \the\pdflastobj\space 0 R}%
}
\def\pgf@sp{ }%
\def\pgftransformextractmatrix#1#2{%
\begingroup%
\pgftransformreset%
#2%
\xdef\pgf@tmp{\pgf@pt@aa\pgf@sp\pgf@pt@ab\pgf@sp\pgf@pt@ba\pgf@sp\pgf@pt@bb\pgf@sp\pgf@sys@tonumber\pgf@pt@x\pgf@sp\pgf@sys@tonumber\pgf@pt@y}%
\endgroup%
\let#1=\pgf@tmp}
\pgfdeclarepatternformonly[\patternangle]{rotated hatch}%
{\pgfqpoint{-.1pt}{-1.pt}}{\pgfqpoint{5pt}{5pt}}
{\pgfqpoint{5pt}{5pt}}
{
\pgfsetlinewidth{.5pt}
\pgfpathmoveto{\pgfqpoint{-.1pt}{-.1pt}}
\pgfpathlineto{\pgfqpoint{5pt}{5pt}}
\pgfpathmoveto{\pgfqpoint{5pt}{-.1pt}}
\pgfpathlineto{\pgfqpoint{-.1pt}{5pt}}
\pgfusepath{stroke}
}
\tikzset{%
pattern angle/.code={%
\pgfmathparse{#1}\let\patternangle=\pgfmathresult
\pgftransformextractmatrix\pgfsys@patternmatrix{\pgftransformrotate{\patternangle}}%
},
pattern angle=0
}
\begin{document}
\begin{tikzpicture}[x=3cm,y=3cm];
\foreach \i [count=\j from 0] in {0,7,...,105}{
\draw [pattern=rotated hatch, pattern angle=\i]
({mod(\j,4)}, {floor(\j/4)}) rectangle ++(0.75,0.75)
node [above] {$\i^\circ$};
}
\end{tikzpicture}
\end{document}
O...
Aquí hay una implementación incompleta de patrones mutables con transformaciones. Se ve un poco diferente cuando intenté traducir la forma en que la nueva arrows.meta
biblioteca crea flechas a una nueva forma de definir patrones:
\pgfdeclarepattern{name=hatch,
type=uncolored,
parameters={\hatchsize, \hatchangle, \hatchlinewidth},
bottom left={x=-.1pt, y=-.1pt},
top right={x=\hatchsize+.1pt, y=\hatchsize+.1pt},
tile size={width=\hatchsize, height=\hatchsize},
transformation={rotate=\hatchangle},
code={
\pgfsetlinewidth{\hatchlinewidth}
\pgfpathmoveto{\pgfpoint{-.1pt}{-.1pt}}
\pgfpathlineto{\pgfpoint{\hatchsize+.1pt}{\hatchsize+.1pt}}
\pgfpathmoveto{\pgfpoint{-.1pt}{\hatchsize+.1pt}}
\pgfpathlineto{\pgfpoint{\hatchsize+.1pt}{-.1pt}}
\pgfusepath{stroke}
}}
Pueden parameters
ser macros o dimensiones, etc., pero si se utilizan dimensiones o recuentos, deben tener el prefijo \the
. Es posible (no lo he probado) que las claves se puedan incluir usando \pgfkeysvalueof{mykey}
.
Hackea tanto la capa del sistema como la capa básica, así que ya estás advertido...
\documentclass[tikz, border=5]{standalone}
\usetikzlibrary{patterns}
\makeatletter
% Alternate system layer pattern definition.
% Takes 15(!) arguments
\def\pgfsys@declarepattern@alt#1#2#3#4#5#6#7{%
% Start building the pattern dictionary:
\pgf@xa=#2\relax%
\pgf@ya=#3\relax%
\pgf@xb=#4\relax%
\pgf@yb=#5\relax%
\pgf@xc=#6\relax%
\pgf@yc=#7\relax%
\pgf@sys@bp@correct\pgf@xa%
\pgf@sys@bp@correct\pgf@ya%
\pgf@sys@bp@correct\pgf@xb%
\pgf@sys@bp@correct\pgf@yb%
\pgf@sys@bp@correct\pgf@xc%
\pgf@sys@bp@correct\pgf@yc%
\pgfsys@@declarepattern@alt{#1}}
\def\pgfsys@@declarepattern@alt#1#2#3#4#5#6#7#8#9{%
\pgfutil@tempdima=#6\relax%
\pgfutil@tempdimb=#7\relax%
\pgf@sys@bp@correct\pgf@xa%
\pgf@sys@bp@correct\pgf@ya%
% Now create the pattern object:
\immediate\pdfobj stream
attr
{
/Type /Pattern
/PatternType 1
/PaintType \ifnum#9=0 2 \else 1 \fi
/TilingType 1
/BBox [\pgf@sys@tonumber\pgf@xa\space\pgf@sys@tonumber\pgf@ya\space\pgf@sys@tonumber\pgf@xb\space\pgf@sys@tonumber\pgf@yb]
/XStep \pgf@sys@tonumber\pgf@xc\space
/YStep \pgf@sys@tonumber\pgf@yc\space
/Matrix [#2\space#3\space#4\space#5\space\pgf@sys@tonumber\pgfutil@tempdima\space\pgf@sys@tonumber\pgfutil@tempdimb]
/Resources << >> %<<
}
{#8}%
\pgfutil@addpdfresource@patterns{/pgfpat#1\space \the\pdflastobj\space 0 R}%
}
% Pattern keys
\pgfkeys{/pgf/patterns/.cd,
name/.code=\edef\pgf@pat@name{#1},
type/.is choice,
type/uncolored/.code=\def\pgf@pat@type{0},
type/colored/.code=\def\pgf@pat@type{1},
parameters/.store in=\pgf@pat@parameters,
bottom left/.store in=\pgf@pat@bottomleft,
top right/.store in=\pgf@pat@topright,
tile size/.store in=\pgf@pat@tilesize,
transformation/.store in=\pgf@pat@transformation,
code/.store in=\pgf@pat@code,
name=,
type=uncolored,
parameters=,
bottom left=,
top right=,
transformation=,
code=,
points/.style={/pgf/patterns/points/.cd, #1},
transformations/.style={/pgf/patterns/transformations/.cd,#1},
/pgf/patterns/points/.cd,
x/.store in=\pgf@pat@x,
y/.store in=\pgf@pat@y,
width/.store in=\pgf@pat@x,
height/.store in=\pgf@path@y,
/pgf/patterns/transformations/.cd,
rotate/.code=\pgftransformrotate{#1},
xscale/.code=\pgftransformxscale{#1},
yscale/.code=\pgftransformyscale{#1},
% Plus others...
}
% Points can be specified using PGF commands
% or x and y keys
\def\pgf@pat@processpoint#1{%
\def\pgf@marshal{\pgfutil@in@=}%
\expandafter\pgf@marshal\expandafter{#1}%
\ifpgfutil@in@%
\pgfkeys{/pgf/patterns/points/.expanded=#1}%
\pgf@process{\pgfpoint{\pgf@pat@x}{\pgf@pat@y}}%
\else%
\pgf@process{#1}%
\fi%
}
% Transformations can be specified using PGF commands
% or keys (currently only rotate, xscale and yscale)
\def\pgf@pat@processtransformations#1{%
\def\pgf@marshal{\pgfutil@in@=}%
\expandafter\pgf@marshal\expandafter{#1}%
\ifpgfutil@in@%
\pgfkeys{/pgf/patterns/transformations/.expanded=#1}%
\else%
#1%
\fi%
}
% New pattern definition command
%
% #1 is a list of keys.
\def\pgfdeclarepattern#1{%
\begingroup%
\def\pgf@pat@opts{#1}%
\pgfkeys{/pgf/patterns/.cd,#1}%
\pgfutil@ifundefined{pgf@pattern@name\pgf@pat@name}{%
\ifx\pgf@pat@parameters\pgfutil@empty%
\expandafter\global\expandafter\let\csname pgf@pattern@name@\pgf@pat@name @parameters\endcsname=\pgfutil@empty%
\pgf@declarepattern%
\else%
\expandafter\global\expandafter\let\csname pgf@pattern@name@\pgf@pat@name @parameters\endcsname=\pgf@pat@parameters
\expandafter\global\expandafter\let\csname pgf@pattern@name@\pgf@pat@name\endcsname=\pgf@pat@opts%
\fi%
}{%
\pgferror{Pattern `\pgf@pat@type' already defined}%
}%
\endgroup%
}
\def\pgf@declarepattern{%
\pgfsysprotocol@getcurrentprotocol\pgf@pattern@temp%
{%
\pgfinterruptpath%
\pgfpicturetrue%
\pgf@relevantforpicturesizefalse%
\pgftransformreset%
\pgfsysprotocol@setcurrentprotocol\pgfutil@empty%
\pgfsysprotocol@bufferedtrue%
\pgfsys@beginscope%
\pgfsetarrows{-}%
\pgf@pat@code%
\pgfsys@endscope%
\pgfsysprotocol@getcurrentprotocol\pgf@pattern@code%
\global\let\pgf@pattern@code=\pgf@pattern@code%
\endpgfinterruptpath%
\pgf@pat@processpoint{\pgf@pat@bottomleft}%
\pgf@xa=\pgf@x%
\pgf@ya=\pgf@y%
\pgf@pat@processpoint{\pgf@pat@topright}%
\pgf@xb=\pgf@x%
\pgf@yb=\pgf@y%
\pgf@pat@processpoint{\pgf@pat@tilesize}%
\pgf@xc=\pgf@x%
\pgf@yc=\pgf@y%
\begingroup%
\pgftransformreset%
\pgf@pat@processtransformations\pgf@pat@transformation%
\pgfgettransformentries\aa\ab\ba\bb\shiftx\shifty%
\global\edef\pgf@pattern@matrix{{\aa}{\ab}{\ba}{\bb}{\shiftx}{\shifty}}%
\endgroup%
% Now, build a name for the pattern
\pgfutil@tempcnta=\pgf@pattern@number%
\advance\pgfutil@tempcnta by1\relax%
\xdef\pgf@pattern@number{\the\pgfutil@tempcnta}%
\expandafter\xdef\csname pgf@pattern@name@\pgf@pat@name\endcsname{\the\pgfutil@tempcnta}%
\expandafter\xdef\csname pgf@pattern@type@\pgf@pat@name\endcsname{\pgf@pat@type}%
\xdef\pgf@marshal{\noexpand\pgfsys@declarepattern@alt%
{\csname pgf@pattern@name@\pgf@pat@name\endcsname}
{\the\pgf@xa}{\the\pgf@ya}{\the\pgf@xb}{\the\pgf@yb}{\the\pgf@xc}{\the\pgf@yc}\pgf@pattern@matrix{\pgf@pattern@code}{\pgf@pat@type}}%
}%
\pgf@marshal%
\pgfsysprotocol@setcurrentprotocol\pgf@pattern@temp%
}
\def\pgfsetfillpattern#1#2{%
\pgfutil@ifundefined{pgf@pattern@name@#1}%
{%
\pgferror{Undefined pattern `#1'}%
}%
{%
% Patterns from library won't have pgf@pattern@name@#1@parameters
\pgfutil@ifundefined{pgf@pattern@name@#1@parameters}{%
\pgf@set@fillpattern{#1}{#2}%
}{%
\expandafter\ifx\csname pgf@pattern@name@#1@parameters\endcsname\pgfutil@empty%
\pgf@set@fillpattern{#1}{#2}%
\else
\edef\pgf@pat@currentparameters{\csname pgf@pattern@name@#1@parameters\endcsname}%
\edef\pgf@pat@mutablename{#1@\pgf@pat@currentparameters}%
\pgfutil@ifundefined{pgf@pattern@name@\pgf@pat@mutablename}%
{%
\expandafter\expandafter\expandafter\pgfdeclarepattern\expandafter\expandafter\expandafter{\csname pgf@pattern@name@#1\endcsname,
name=\pgf@pat@mutablename,parameters=}%
}%
{}%
\expandafter\pgf@set@fillpattern\expandafter{\pgf@pat@mutablename}{#2}%
\fi%
}%
}%
}
\def\pgf@set@fillpattern#1#2{%
% Pattern types are 0 (uncolored) or 1 (colored)
\ifcase\csname pgf@pattern@type@#1\endcsname\relax%
\pgfutil@colorlet{pgf@tempcolor}{#2}%
\pgfutil@ifundefined{applycolormixins}{}{\applycolormixins{pgf@tempcolor}}%
\pgfutil@extractcolorspec{pgf@tempcolor}{\pgf@tempcolor}%
\expandafter\pgfutil@convertcolorspec\pgf@tempcolor{rgb}{\pgf@rgbcolor}%
\expandafter\pgf@set@fill@patternuncolored\pgf@rgbcolor\relax{#1}%
\or
\pgfsys@setpatterncolored{\csname pgf@pattern@name@#1\endcsname}%
\else
\fi
}
\def\tikzdeclarepattern#1{%
\begingroup%
\pgfkeys{/pgf/patterns/code/.code={\def\pgf@pat@code{%
\let\tikz@transform=\relax\tikz@installcommands##1}}}
\pgfdeclarepattern{#1,type=colored}%
\endgroup%
}
\makeatother
\pgfdeclarepattern{name=hatch,
type=uncolored,
parameters={\hatchsize, \hatchangle, \hatchlinewidth},
bottom left={x=-.1pt, y=-.1pt}, % or \pgfqpoint{-.1pt}{-.1pt} will also work
top right={x=\hatchsize+.1pt, y=\hatchsize+.1pt},
tile size={width=\hatchsize, height=\hatchsize},
transformation={rotate=\hatchangle},
code={
\pgfsetlinewidth{\hatchlinewidth}
\pgfpathmoveto{\pgfpoint{-.1pt}{-.1pt}}
\pgfpathlineto{\pgfpoint{\hatchsize+.1pt}{\hatchsize+.1pt}}
\pgfpathmoveto{\pgfpoint{-.1pt}{\hatchsize+.1pt}}
\pgfpathlineto{\pgfpoint{\hatchsize+.1pt}{-.1pt}}
\pgfusepath{stroke}
}}
\tikzset{%
hatch size/.store in=\hatchsize,
hatch angle/.store in=\hatchangle,
hatch line width/.store in=\hatchlinewidth,
hatch size=5pt,
hatch angle=0pt,
hatch line width=.5pt,
}
\begin{document}
\begin{tikzpicture}
\foreach \r in {1,...,4}
\draw [pattern=hatch, pattern color=red]
(\r*3,0) rectangle ++(2,2);
\foreach \r in {1,...,4}
\draw [pattern=hatch, pattern color=green, hatch size=2pt]
(\r*3,3) rectangle ++(2,2);
\foreach \r in {1,...,4}
\draw [pattern=hatch, pattern color=blue, hatch size=10pt, hatch angle=21]
(\r*3,6) rectangle ++(2,2);
\foreach \r in {1,...,4}
\draw [pattern=hatch, pattern color=orange, hatch line width=2pt]
(\r*3,9) rectangle ++(2,2);
\end{tikzpicture}
\end{document}
Además, abre la posibilidad de especificar patrones usando TikZ (el código \tikzdeclarepattern
se incluye arriba):
\tikzdeclarepattern{name=flower,
type=uncolored,
bottom left={x=-.1pt, y=-.1pt},
top right={x=10.1pt, y=10.1pt},
tile size={width=10pt, height=10pt},
code={
\tikzset{x=1pt,y=1pt}
\path [draw=green] (5,2.5) -- (5, 7.5);
\foreach \i in {0,60,...,300}
\path [fill=pink, shift={(5,7.5)}, rotate=-\i]
(0,0) .. controls ++(120:4) and ++(60:4) .. (0,0);
\path [fill=red] (5,7.5) circle [radius=1];
\foreach \i in {-45,45}
\path [fill=green, shift={(5,2.5)}, rotate=-\i]
(0,0) .. controls ++(120:4) and ++(60:4) .. (0,0);
}}
Que luego se utiliza de la forma habitual:
\tikz\draw [pattern=flower] circle [radius=1];
y produce: