我可以定义一个具有预定义填充和阴影的新形状用于装饰吗?

我可以定义一个具有预定义填充和阴影的新形状用于装饰吗?

我定义了一个新形状,用预定义的填充和颜色绘制一朵花:

\makeatletter
\pgfdeclareshape{flower}{
  \savedanchor{\center}{%
    \pgfpointorigin}
  \anchor{center}{\center}
\backgroundpath{%  
\begingroup
  \tikz@mode
    \iftikz@mode@draw
      \foreach \a in {60,120,...,360} {
        \pgftransformrotate{\a}
        \pgfpathellipse{\pgfpointxy{0}{0.7}}{\pgfpointxy{0.25}{0}}{\pgfpointxy{0}{0.5}}
      }
      \pgfpathcircle{\pgfpoint{0}{0}}{0.4cm}

      \let\my@color\tikz@strokecolor!60!\tikz@fillcolor
      \foreach \a in {30,60,...,360} {%
        \pgftransformrotate{\a+7}%
        \pgfpathmoveto{\pgfpointxy{0}{0.1}}
        \def\y{0.6+0.05*rand}
        \pgfpathlineto{\pgfpointxy{0}{\y}}
        \pgfpathcircle{\pgfpointxy{0}{\y}}{0.05cm}
      }
    \fi
    \iftikz@mode@fill
      \begin{scope}
        \foreach \a in {60,120,...,360} {
          \pgftransformrotate{\a}
          \pgfpathellipse{\pgfpointxy{0}{0.7}}{\pgfpointxy{0.25}{0}}{\pgfpointxy{0}{0.5}}
        }
        \pgfusepath{clip}
        \pgfpathcircle{\pgfpointxy{0}{0}}{1.2cm}
        \pgfutil@colorlet{tikz@radial@outer}{\tikz@fillcolor!70}
        \pgfutil@colorlet{tikz@radial@inner}{\tikz@fillcolor!60!\tikz@strokecolor}
        \pgfshadepath{radial}{0}
        \pgfusepath{}
      \end{scope}
      % \tikz@mode@clipfalse

      \let\my@strokecolor\tikz@strokecolor
      \let\my@fillcolor\tikz@fillcolor

      \pgfsetfillcolor{\my@strokecolor}
      \pgfpathcircle{\pgfpointxy{0}{0}}{0.4cm}
      \pgfusepath{fill}          

      \foreach \a in {30,60,...,360} {%
        \pgftransformrotate{\a+7}%
        \pgfpathmoveto{\pgfpointxy{0}{0.1}}
        \def\y{0.5+0.05*rand}
        \pgfpathlineto{\pgfpointxy{0}{\y}}
        \pgfpathcircle{\pgfpointxy{0}{\y}}{0.05cm}
      }
      \let\my@color\my@fillcolor
      \pgfutil@colorlet{\my@color}{\my@strokecolor!60!\my@fillcolor}
      \pgfsetstrokecolor{\my@color}
      \pgfsetfillcolor{\my@color}
      \pgfusepath{stroke,fill}
    \fi
   \endgroup
 }
}
\makeatother

使用时可产生饱满且色彩鲜艳的花朵:

\node[flower, fill=pink, draw=purple] {};

花

不过,我仍有几个问题和疑问,我自己无法找到答案。

1) 如果我不使用 \begin{scope} 和 \end{scope},我不知道如何停止我在填充部分所做的剪辑。有没有办法避免使用范围?或者把它们放在那里完全没问题?

2)在绘制雄蕊时,可以使用随机函数稍微改变雄蕊的高度

    \def\y{0.6+0.05*rand}
    \pgfpathlineto{\pgfpointxy{0}{\y}}
    \pgfpathcircle{\pgfpointxy{0}{\y}}{0.05cm}

但每次都会重新计算 \y 的值,我不知道如何在这里修复它。

3)如果我没有指定描边和填充的颜色

fill=pink, draw=purple

我遇到了编译错误。如果我使用

\node[flower, fill, color=red] {};

那么,我该如何使用默认颜色?

4) 我想定义一个新的装饰,用随机大小的花朵装饰一条路径,而且我希望这些花朵与上图上的花朵完全相同。这是我的装饰的代码:

\pgfdeclaredecoration{flowers}{initial}{
  \state{initial}[width=1cm]
{
\pgfmathparse{round(rnd*90)}
\pgftransformrotate{\pgfmathresult}
\pgfmathparse{0.2+rand*0.1}
\pgftransformscale{\pgfmathresult}
\pgfsetlinewidth{\pgfmathresult*\pgflinewidth}
\pgfsetcolor{pink}
\pgfsetfillcolor{pink}
\pgfsetstrokecolor{purple}
\pgfnode{flower}{center}{}{}{\pgfusepath{stroke,fill}}
}
\state{final}
{
  \pgfpathmoveto{\pgfpointdecoratedpathlast}
}
}

我的第一个问题是,我通过调用

\draw[decorate, decoration={flowers}] (-4,-3) -- (4,-3);

用鲜花装饰的线条

而不是漂亮的填充/着色。我应该修改花的定义中的哪些部分?

那么,我更愿意使用在花朵之间随机移动的方式,该怎么做呢?

答案1

这可能还有点远,因为有几个地方我不确定你想要什么。

  1. 如果我不使用 \begin{scope} 和 \end{scope},我不知道如何停止我在填充部分所做的剪辑。有没有办法避免使用范围?或者把它们放在那里完全没问题?

    您必须以clip某种方式限制范围,这是实现此目的的正确方法。您可以使用较低级别的命令\pgfscope\endpgfscope以与命令的使用保持一致\pgf...

  2. 在绘制雄蕊时,可以使用随机函数稍微改变它们的高度

    \def\y{0.6+0.05*rand}
    \pgfpathlineto{\pgfpointxy{0}{\y}}
    \pgfpathcircle{\pgfpointxy{0}{\y}}{0.05cm}
    

    但每次都会重新计算 \y 的值,我不知道如何在这里修复它。

    我看到过此代码的几种用法,我猜您希望它们都相互一致。有两个问题:一个是上面的代码,另一个是全局重用。上面的代码\y会计算两次,每次都会使用不同的随机数。因此,您\def\y{...}不想让\y结果该计算的。为此,使用。第二个问题通过在适当的位置\pgfmathsetmacro\y{...}重置 的随机种子来解决。这是使用 完成的。\pgfmath\pgfmathsetseed

  3. 如果我没有指定描边和填充的颜色

    fill=pink, draw=purple

    我遇到了编译错误。如果我使用

    \node[flower, fill, color=red] {};

    那么,我该如何使用默认颜色?

    TikZ 仅在或选项指定了明确颜色时才设置\tikz@strokecolor和。一般颜色保存为(请注意,这是一个颜色名称,而不是宏),因此您需要使用它。我建议在代码顶部放置一个“获取正确的颜色”位,然后使用您自己的名称。正如我在评论中所说,我并不完全清楚哪种颜色对应于花朵各部分的哪种操作(填充、描边、淡入淡出),所以我的代码(如下)可能会出错。\tikz@fillcolordrawfilltikz@color

  4. 我想定义一个新的装饰,用随机大小的花朵装饰一条路径,而且我希望这些花朵与上图上的完全相同。这是我的装饰的代码:

    我的第一个问题是,我通过调用得到的是“普通”花朵,而不是漂亮的填充/着色。我应该在花朵的定义中修改什么?

    那么,我更愿意使用在花朵之间随机移动的方式,该怎么做呢?

    简单的花朵来自于这样一个事实:您使用低级命令 ( \pgfsetstrokecolor) 定义装饰中的颜色,但从 TikZ 级别命令 () 中提取颜色\tikz@strokecolor。据我所知,没有办法提取当前的笔触颜色,所以我们必须使用 TikZ 方法设置它们。strokefill动作也是如此。正如您在代码中使用的那样,您必须使用指定和\tikz@mode@...的 TikZ 方法。drawfill

    每次width都会重新评估,因此您可以将其设置为新的dimen,然后在每次运行时调整此尺寸。

这是我根据您代码的改编,实现了上述所有内容。正如我所说,我认为在几个地方我并没有完全理解您所寻找的内容,但希望它足够接近,以便您知道下一步该怎么做。

\documentclass{article}
%\url{http://tex.stackexchange.com/q/110047/86}
\usepackage{tikz}
\usetikzlibrary{decorations.pathreplacing}

\makeatletter

\def\pgfmathgetseed#1{%
  \let#1=\pgfmath@rnd@z}

\pgfdeclareshape{flower}{
  \savedanchor{\center}{%
    \pgfpointorigin}
  \anchor{center}{\center}
\backgroundpath{%  
\begingroup
    \ifx\tikz@strokecolor\pgfutil@empty
    \def\my@strokecolor{tikz@color}
    \else
    \let\my@strokecolor\tikz@strokecolor
    \fi
    \ifx\tikz@fillcolor\pgfutil@empty
    \def\my@fillcolor{tikz@color}
    \else
    \let\my@fillcolor\tikz@fillcolor
    \fi
    \pgfmathgetseed{\flower@seed}
  \tikz@mode
    \iftikz@mode@draw
      \foreach \a in {60,120,...,360} {
        \pgftransformrotate{\a}
        \pgfpathellipse{\pgfpointxy{0}{0.7}}{\pgfpointxy{0.25}{0}}{\pgfpointxy{0}{0.5}}
      }
      \pgfpathcircle{\pgfpoint{0}{0}}{0.4cm}
    \pgfmathsetseed{\flower@seed}
      \foreach \a in {30,60,...,360} {%
        \pgftransformrotate{\a+7}%
        \pgfpathmoveto{\pgfpointxy{0}{0.1}}
        \pgfmathsetmacro\y{0.6+0.05*rand}
        \pgfpathlineto{\pgfpointxy{0}{\y}}
        \pgfpathcircle{\pgfpointxy{0}{\y}}{0.05cm}
      }
    \pgfsetstrokecolor{\my@strokecolor}
      \pgfusepath{stroke}
    \fi
    \iftikz@mode@fill
    \pgfscope
        \foreach \a in {60,120,...,360} {
          \pgftransformrotate{\a}
          \pgfpathellipse{\pgfpointxy{0}{0.7}}{\pgfpointxy{0.25}{0}}{\pgfpointxy{0}{0.5}}
        }
        \pgfusepath{clip}
        \pgfpathcircle{\pgfpointxy{0}{0}}{1.2cm}
        \pgfutil@colorlet{tikz@radial@outer}{\my@fillcolor!70}
        \pgfutil@colorlet{tikz@radial@inner}{\my@fillcolor!60!\my@strokecolor}
        \pgfshadepath{radial}{0}
        \pgfusepath{discard}
      \endpgfscope
      % \tikz@mode@clipfalse

      \pgfsetfillcolor{\my@strokecolor}
      \pgfpathcircle{\pgfpointxy{0}{0}}{0.4cm}
      \pgfusepath{fill}          

    \pgfmathsetseed{\flower@seed}
      \foreach \a in {30,60,...,360} {%
        \pgftransformrotate{\a+7}%
        \pgfpathmoveto{\pgfpointxy{0}{0.1}}
        \pgfmathsetmacro\y{0.6+0.05*rand}
        \pgfpathlineto{\pgfpointxy{0}{\y}}
        \pgfpathcircle{\pgfpointxy{0}{\y}}{0.05cm}
      }
      \let\my@color\my@fillcolor
      \pgfutil@colorlet{\my@color}{\my@strokecolor!60!\my@fillcolor}
      \pgfsetstrokecolor{\my@color}
      \pgfsetfillcolor{\my@color}
      \pgfusepath{stroke,fill}
    \fi
   \endgroup
 }
}

\newdimen\flower@sep
\flower@sep=1cm\relax

\pgfdeclaredecoration{flowers}{initial}{
  \state{initial}[width=\flower@sep]
{
\pgfmathparse{round(rnd*90)}
\pgftransformrotate{\pgfmathresult}
\pgfmathparse{0.2+rand*0.1}
\pgftransformscale{\pgfmathresult}
\pgfsetlinewidth{\pgfmathresult*\pgflinewidth}
\def\tikz@strokecolor{purple}
\def\tikz@fillcolor{pink}
\tikz@mode@drawtrue
\tikz@mode@filltrue
\pgfnode{flower}{center}{}{}{}
\pgfmathsetlength\flower@sep{1cm + rand*0.5cm}
\global\flower@sep=\flower@sep
}
\state{final}
{
  \pgfpathmoveto{\pgfpointdecoratedpathlast}
}
}


\makeatother

\begin{document}

\tikz \node[flower, fill=pink, draw=purple] {};

\tikz \node[flower, fill, color=red] {};


\tikz \draw[decorate, decoration={flowers}] (-4,-3) -- (4,-3);

\end{document}

花朵


更新我仔细检查了一下代码,删除了一些重复部分,并整理了一些内容。代码中的注释。

\documentclass{article}
%\url{http://tex.stackexchange.com/q/110047/86}
\usepackage{tikz}
\usetikzlibrary{decorations.pathreplacing}

\makeatletter

\tikzset{
  flower shade colour/.store in=\my@shadecolour,
  flower shade color/.store in=\my@shadecolour,
  flower shade colour=white
}

\pgfdeclareshape{flower}{
  \savedanchor{\center}{%
    \pgfpointorigin}
  \anchor{center}{\center}
%
% We use \beforebackgroundpath since we're handling the stroke and
% fills ourselves.
%
\beforebackgroundpath{%
\begingroup
%
% Do our very best to set the colours.
%
% Was a stroke colour set explicitly (via draw=<colour>)?
    \ifx\tikz@strokecolor\pgfutil@empty
% No, so test if a general colour was set.
    \@ifundefinedcolor{tikz@color}{%
% No, so take the current colour.
    \def\my@strokecolor{.}%
      }{%
% General colour was set so use that
    \def\my@strokecolor{tikz@color}%
      }%
    \else
% Stroke colour was set, so use that
    \let\my@strokecolor\tikz@strokecolor
    \fi
%
% Now the same for the fill colour.
% Was a fill colour set explicitly?
    \ifx\tikz@fillcolor\pgfutil@empty
% No, so was a general colour set?
    \@ifundefinedcolor{tikz@color}{%
% No, so reuse the stroke colour.
    \let\my@fillcolor\my@strokecolor
      }{%
% General colour was set, use that.
    \def\my@fillcolor{tikz@color}%
      }%
    \else
% Specific fill colour was set, so use that.
    \let\my@fillcolor\tikz@fillcolor
    \fi

%
% Test for the mode
%
    \tikz@mode
%
% Draw the petals.
%
    \foreach \a in {60,120,...,360} {
          \pgftransformrotate{\a}
      \pgfpathellipse{\pgfpointxy{0}{0.7}}{\pgfpointxy{0.25}{0}}{\pgfpointxy{0}{0.5}}
        }
%
% If fill is requested, shade them using the fill colour and the
% (extra) shade colour.
%
    \iftikz@mode@fill
        \pgfutil@colorlet{tikz@radial@outer}{\my@fillcolor}
        \pgfutil@colorlet{tikz@radial@inner}{\my@shadecolour}
        \pgfshadepath{radial}{0}
        \pgfusepath{discard}
    \else
    \iftikz@mode@draw
%
% If fill mode was not requested but draw mode was, stroke the path.
%
    \pgfusepath{stroke}
    \fi
    \fi

%
% Now the centre of the flower; filled if requested, if not filled
% then drawn if requested.
%
    \pgfpathcircle{\pgfpointxy{0}{0}}{0.4cm}
    \iftikz@mode@fill
      \pgfsetfillcolor{\my@strokecolor}
      \pgfusepath{fill}          
    \else
    \iftikz@mode@draw
      \pgfsetstrokecolor{\my@strokecolor}
    \pgfusepath{stroke}
    \fi
    \fi

%
% Lastly the stamen.
% If fill was requested then we also stroke the paths (to get the
% stalk part - biology was never my strong point).
% Note that we push the circles out by their radius so that if
% drawn then it still looks right.
%
      \foreach \a in {30,60,...,360} {%
        \pgftransformrotate{\a+7}%
        \pgfpathmoveto{\pgfpointxy{0}{0.1}}
        \pgfmathsetmacro\y{0.6+0.05*rand}
        \pgfpathlineto{\pgfpointxy{0}{\y}}
        \pgfpathcircle{\pgfpointxy{0}{\y + 0.05}}{0.05cm}
      }
      \let\my@color\my@fillcolor
      \pgfutil@colorlet{\my@color}{\my@strokecolor!60!\my@fillcolor}
      \pgfsetstrokecolor{\my@color}
    \iftikz@mode@fill
      \pgfsetfillcolor{\my@color}
      \pgfusepath{stroke,fill}
    \else
    \iftikz@mode@draw
    \pgfusepath{stroke}
    \fi
    \fi

   \endgroup
 }
}

%
% This holds our state widths for the decoration so that we
% can vary them each time.
%
\newdimen\flower@sep
\flower@sep=1cm\relax

\pgfdeclaredecoration{flowers}{initial}{
  \state{initial}[width=\flower@sep]
{
\pgfmathparse{round(rnd*90)}
\pgftransformrotate{\pgfmathresult}
\pgfmathparse{0.2+rand*0.1}
\pgftransformscale{\pgfmathresult}
\pgfsetlinewidth{\pgfmathresult*\pgflinewidth}
%
% These should be customisable, I guess.
%
\def\tikz@strokecolor{purple}
\def\tikz@fillcolor{pink}
\tikz@mode@drawtrue
\tikz@mode@filltrue
\pgfnode{flower}{center}{}{}{}
%
% Reset the width
%
\pgfmathsetlength\flower@sep{1cm + rand*0.5cm}
\global\flower@sep=\flower@sep
}
\state{final}
{
  \pgfpathmoveto{\pgfpointdecoratedpathlast}
}
}


\makeatother

\begin{document}

\tikz \node[flower, fill=pink, draw=purple] {};

\tikz \node[flower, fill, color=red] {};

\tikz \node[flower, draw=red] {};


\tikz \draw[decorate, decoration={flowers}] (-4,-3) -- (4,-3);

\end{document}

更多鲜花

相关内容