1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261
|
% Copyright 2019 by Till Tantau
%
% This file may be distributed and/or modified
%
% 1. under the LaTeX Project Public License and/or
% 2. under the GNU Free Documentation License.
%
% See the file doc/generic/pgf/licenses/LICENSE for more details.
\section{Patterns}
\label{section-patterns}
\subsection{Overview}
There are many ways of filling a path. First, you can fill it using a solid
color and this is also the fastest method. Second, you can also fill it using a
shading, which means that the color changes smoothly between two (or more)
different colors. Third, you can fill it using a tiling pattern and it is
explained in the following how this is done.
A tiling pattern can be imagined as a rectangular tile (hence the name) on
which a small picture is painted. There is not a single tile, but
(conceptually) an infinite number of tiles, all showing the same picture, and
these tiles are arranged horizontally and vertically to fill the plane. When
you use a tiling pattern to fill a path, what happens is that the path clips
out a ``window'' through which we see part of this infinite plane.
Patterns come in two versions: \emph{inherently colored patterns} and
\emph{form-only patterns}. (These are often called ``color patterns'' and
``uncolored patterns'', but these names are misleading since uncolored patterns
do have a color and the color changes. As I said, the name is misleading\dots)
An inherently colored pattern is just a colored tile like, say, a red star with
a black outline. A form-only pattern can be imagined as a tile that is a kind
of rubber stamp. When this pattern is used, the stamp is used to print copies
of the stamp picture onto the plane, but we can use a different stamp color
each time we use a form-only pattern.
\pgfname\ provides a special support for patterns. You can declare a pattern
and then use it very much like a fill color. \pgfname\ directly maps patterns
to the pattern facilities of the underlying graphic languages (PostScript,
\textsc{pdf}, and \textsc{svg}). This means that filling a path using a pattern
will be nearly as fast as if you used a uniform color.
There are a number of pitfalls and restrictions when using patterns. First,
once a pattern has been declared, you cannot change it anymore. In particular,
it is not possible to enlarge it or change the line width. Such flexibility
would require that the repeating of the pattern were not done by the graphic
language, but on the \pgfname\ level. This would make patterns orders of
magnitude slower to produce and to render. However, \pgfname{} does provide a
more-or-less successful emulation of ``mutable'' patterns, although internally,
a new (fixed) instance of a pattern is declared when the parameters of a
pattern change.
Second, the phase of patterns is not well-defined, that is, it is not clear
where the origin of the ``first'' tile is. To be more precise, PostScript and
\textsc{pdf} on the one hand and \textsc{svg} on the other hand define the
origin differently. PostScript and \textsc{pdf} define a fixed origin that is
independent of where the path lies. This has the highly desirable effect that
if you use the same pattern to fill multiple paths, the outcome is the same as
if you had filled a single path consisting of the union of all these paths. By
comparison, \textsc{svg} uses the upper-left (?) corner of the path to be
filled as the origin. However, the \textsc{svg} specification is a bit vague on
this question.
\subsection{Declaring a Pattern}
Before a pattern can be used, it must be declared. The following command is
used for this:
\begin{command}{\pgfdeclarepatternformonly%
\opt{\oarg{variables}}%
\marg{name}%
\marg{bottom left}%
\marg{top right}%
\marg{tile size}%
\marg{code}%
}
This command declares a new form-only pattern. The \meta{name} is a name
for later reference. The two parameters \meta{lower left} and \meta{upper
right} must describe a bounding box that is large enough to encompass the
complete tile.
The size of a tile is given by \meta{tile size}, that is, a tile is a
rectangle whose lower left corner is the origin and whose upper right
corner is given by \meta{tile size}. This might make you wonder why the
second and third parameters are needed. First, the bounding box might be
smaller than the tile size if the tile is larger than the picture on the
tile. Second, the bounding box might be bigger, in which case the picture
will ``bleed'' over the tile.
The \meta{code} should be \pgfname\ code than can be protocolled. It should
not contain any color code.
%
\begin{codeexample}[preamble={\usetikzlibrary{patterns}}]
\pgfdeclarepatternformonly{stars}
{\pgfpointorigin}{\pgfpoint{1cm}{1cm}}
{\pgfpoint{1cm}{1cm}}
{
\pgftransformshift{\pgfpoint{.5cm}{.5cm}}
\pgfpathmoveto{\pgfpointpolar{0}{4mm}}
\pgfpathlineto{\pgfpointpolar{144}{4mm}}
\pgfpathlineto{\pgfpointpolar{288}{4mm}}
\pgfpathlineto{\pgfpointpolar{72}{4mm}}
\pgfpathlineto{\pgfpointpolar{216}{4mm}}
\pgfpathclose%
\pgfusepath{fill}
}
\begin{tikzpicture}
\filldraw[pattern=stars] (0,0) rectangle (1.5,2);
\filldraw[pattern=stars,pattern color=red]
(1.5,0) rectangle (3,2);
\end{tikzpicture}
\end{codeexample}
The optional argument \meta{variables} consists of a comma separated list
of macros, registers or keys, representing the parameters of the pattern
that may vary. If a variable is a key, then the full path name must be used
(specifically, it must start with |/|). As an example, a list might look
like the following: |\mymacro,\mydimen,/pgf/my key|. Note that macros and
keys should be ``simple''. They should only store values in themselves.
The effect of \meta{variables}, is the following: Normally, when this
argument is empty, once a pattern has been declared, it becomes ``frozen''.
This means that it is not possible to enlarge the pattern or change the
line width later on. By specifying \meta{variables}, no pattern is actually
created. Instead, the arguments are stored away (so the macros, registers
or keys do not have to be defined in advance).
When the fill pattern is set, \pgfname{} checks if the pattern has already
been created with the \meta{variables} set to their current values
(\pgfname{} is usually ``smart enough'' to distinguish between macros,
registers and keys). If so, this already-declared-pattern is used as the
fill pattern. If not, a new instance of the pattern (which will have a
unique internal name) is declared using the current values of
\meta{variables}. These values are then saved and the fill pattern set
accordingly.
The following shows an example of a pattern which varies according to the
values of the macro |\size|, the key |/tikz/radius|, and the \TeX{}
dimension |\thickness|.
%
\begin{codeexample}[preamble={\usetikzlibrary{patterns}}]
\pgfdeclarepatternformonly[/tikz/radius,\thickness,\size]{rings}
{\pgfpoint{-0.5*\size}{-0.5*\size}}
{\pgfpoint{0.5*\size}{0.5*\size}}
{\pgfpoint{\size}{\size}}
{
\pgfsetlinewidth{\thickness}
\pgfpathcircle\pgfpointorigin{\pgfkeysvalueof{/tikz/radius}}
\pgfusepath{stroke}
}
\newdimen\thickness
\tikzset{
radius/.initial=4pt,
size/.store in=\size, size=20pt,
thickness/.code={\thickness=#1},
thickness=0.75pt
}
\begin{tikzpicture}[rings/.style={pattern=rings}]
\filldraw [rings, radius=2pt, size=6pt] (0,0) rectangle +(1.5,2);
\filldraw [rings, radius=2pt, size=8pt] (2,0) rectangle +(1.5,2);
\filldraw [rings, radius=6pt, thickness=2pt] (0,2.5) rectangle +(1.5,2);
\filldraw [rings, radius=8pt, thickness=4pt] (2,2.5) rectangle +(1.5,2);
\end{tikzpicture}
\end{codeexample}
%
\end{command}
\begin{command}{\pgfdeclarepatterninherentlycolored
\opt{\oarg{variables}}
\marg{name}
\marg{lower left}
\marg{upper right}
\marg{tile size}
\marg{code}%
}
This command works like |\pgfdeclarepatternuncolored|, only the pattern
will have an inherent color. To set the color, you should use \pgfname's
color commands, not the |\color| command, since this fill is not
protocolled.
%
\begin{codeexample}[preamble={\usetikzlibrary{patterns}}]
\pgfdeclarepatterninherentlycolored{green stars}
{\pgfpointorigin}{\pgfpoint{1cm}{1cm}}
{\pgfpoint{1cm}{1cm}}
{
\pgfsetfillcolor{green!50!black}
\pgftransformshift{\pgfpoint{.5cm}{.5cm}}
\pgfpathmoveto{\pgfpointpolar{0}{4mm}}
\pgfpathlineto{\pgfpointpolar{144}{4mm}}
\pgfpathlineto{\pgfpointpolar{288}{4mm}}
\pgfpathlineto{\pgfpointpolar{72}{4mm}}
\pgfpathlineto{\pgfpointpolar{216}{4mm}}
\pgfpathclose%
\pgfusepath{stroke,fill}
}
\begin{tikzpicture}
\filldraw[pattern=green stars] (0,0) rectangle (3,2);
\end{tikzpicture}
\end{codeexample}
%
\end{command}
\subsection{Setting a Pattern}
Once a pattern has been declared, it can be used.
\begin{command}{\pgfsetfillpattern\marg{name}\marg{color}}
This command specifies that paths that are filled should be filled with the
``color'' by the pattern \meta{name}. For an inherently colored pattern,
the \meta{color} parameter is ignored. For form-only patterns, the
\meta{color} parameter specifies the color to be used for the pattern.
%
\begin{codeexample}[
preamble={\usetikzlibrary{patterns}
\pgfdeclarepatternformonly{stars}
{\pgfpointorigin}{\pgfpoint{1cm}{1cm}}
{\pgfpoint{1cm}{1cm}}
{
\pgftransformshift{\pgfpoint{.5cm}{.5cm}}
\pgfpathmoveto{\pgfpointpolar{0}{4mm}}
\pgfpathlineto{\pgfpointpolar{144}{4mm}}
\pgfpathlineto{\pgfpointpolar{288}{4mm}}
\pgfpathlineto{\pgfpointpolar{72}{4mm}}
\pgfpathlineto{\pgfpointpolar{216}{4mm}}
\pgfpathclose%
\pgfusepath{fill}
}
\pgfdeclarepatterninherentlycolored{green stars}
{\pgfpointorigin}{\pgfpoint{1cm}{1cm}}
{\pgfpoint{1cm}{1cm}}
{
\pgfsetfillcolor{green!50!black}
\pgftransformshift{\pgfpoint{.5cm}{.5cm}}
\pgfpathmoveto{\pgfpointpolar{0}{4mm}}
\pgfpathlineto{\pgfpointpolar{144}{4mm}}
\pgfpathlineto{\pgfpointpolar{288}{4mm}}
\pgfpathlineto{\pgfpointpolar{72}{4mm}}
\pgfpathlineto{\pgfpointpolar{216}{4mm}}
\pgfpathclose%
\pgfusepath{stroke,fill}
}}]
\begin{tikzpicture}
\pgfsetfillpattern{stars}{red}
\filldraw (0,0) rectangle (1.5,2);
\pgfsetfillpattern{green stars}{red}
\filldraw (1.5,0) rectangle (3,2);
\end{tikzpicture}
\end{codeexample}
%
\end{command}
%%% Local Variables:
%%% mode: latex
%%% TeX-master: "pgfmanual"
%%% End:
|