如何完成切向着色(即非径向着色)?

如何完成切向着色(即非径向着色)?

我想要制作一个开口环,其颜色渐变从白色(或淡红色)变为红色,然后在角度/切线方向上变回白色(或淡红色)。

在下面的图片中,渐变是线性的,不符合我的喜好。我想要的是逆时针渐变:两点钟方向为白色 - 九点钟方向为红色 - 四点钟方向为白色。

在此处输入图片描述

理想情况下,我希望采用一种灵活的方法,可以任意设置起始和停止角度。

我花了很多时间阅读 pgf/tikz 手册和这个论坛。我还没能找到解决方案。有什么想法吗?

代码示例:

\documentclass[tikz,]{standalone}
\usepackage{tikz}
\begin{document}
\begin{centering}
\begin{tikzpicture}[scale=1]

\def\aStartA{30}
\def\aStopA{330}

\filldraw[gray!50,left color=white!25, right color=white!25, middle color=red!25] (\aStartA:2cm)--(\aStartA:2cm)--(\aStartA:3cm) arc (\aStartA:\aStopA:3cm)--(\aStopA:2cm)--(\aStopA:2cm) arc (\aStopA:\aStartA:2cm);
\draw[thin, color=gray] (\aStartA:0)--(\aStartA:3.5cm);
\draw[thin, color=gray] (\aStopA:0)--(\aStopA:3.5cm);
\end{tikzpicture}
\end{centering}
\end{document}

答案1

更新:基于的解决方案色轮修改

\documentclass[tikz,border=3.14pt]{standalone}

\makeatletter
\newtoks\pgf@ps@toks
\newcount\c@pgf@ps

\def\pgf@ps@sp{ }

\def\pgf@ps@esettoks#1{\edef\pgf@ps@tmp{#1}\pgf@ps@toks\expandafter{\pgf@ps@tmp}}

\def\pgf@ps@repop#1#2{%
  \c@pgf@countb=#2\relax%
  \def\pgf@ps@op{#1}%
  \def\pgf@ps@ops{}\pgf@ps@@repop}
\def\pgf@ps@@repop{%
  \ifnum\c@pgf@countb<1\relax%
  \else%
    \edef\pgf@ps@ops{\pgf@ps@op\pgf@ps@ops}%
    \advance\c@pgf@countb by-1\relax%
    \expandafter\pgf@ps@@repop%
  \fi%
}

\def\pgf@ps@generate@ps{%
  \c@pgf@counta=\pgf@ps@ncol\relax%
  \c@pgf@countb=\c@pgf@counta%
  \advance\c@pgf@countb by-1\relax%
  \pgf@ps@esettoks{ \noexpand\pgf@ps@interp{col@\the\c@pgf@counta}{col@\the\c@pgf@countb} }%
  \pgfmathloop
  \ifnum\c@pgf@counta<2\relax%
  \else%
    \c@pgf@countb=-\c@pgf@counta%
    \advance\c@pgf@countb by\pgf@ps@ncol\relax%
    \advance\c@pgf@counta by-1\relax%
    \pgf@ps@repop{pop\pgf@ps@sp}{\c@pgf@countb}%
    \c@pgf@countb=\c@pgf@counta%
    \advance\c@pgf@countb by-1\relax%
    \ifnum\c@pgf@countb=0\relax%
      \c@pgf@countb=\pgf@ps@ncol\relax%
    \fi%
    \pgf@ps@esettoks{ \the\c@pgf@counta\pgf@ps@sp eq { \pgf@ps@ops \noexpand\pgf@ps@interp{col@\the\c@pgf@counta}{col@\the\c@pgf@countb} }{ \the\pgf@ps@toks } ifelse}%
  \repeatpgfmathloop%
  \c@pgf@counta=\pgf@ps@ncol\relax%
  \advance\c@pgf@counta by-2\relax%
  \pgf@ps@repop{dup\pgf@ps@sp}{\c@pgf@counta}%
  \pgf@ps@esettoks{ \pgf@ps@ops \the\pgf@ps@toks }%
}

\def\pgf@ps@colorstorgb#1{%
  \c@pgf@ps=1\relax%
  \pgfutil@for\pgf@ps@:={#1}\do{%
     \pgf@ps@coltorgb{\pgf@ps@}{col@\the\c@pgf@ps}%
     \advance\c@pgf@ps by1\relax}%
}

\def\pgf@ps@coltorgb#1#2{%
 \edef\pgf@ps@marshal{\noexpand\pgfshadecolortorgb{#1}}%
 \expandafter\pgf@ps@marshal\expandafter{\csname#2\endcsname}%
}

\def\pgf@ps@rgb#1{\csname#1\endcsname}
\def\pgf@ps@interp#1#2{%
  \pgf@ps@rgb{#1red} mul exch \pgf@ps@rgb{#2red} mul add
    5 1 roll
  \pgf@ps@rgb{#1green} mul exch \pgf@ps@rgb{#2green} mul add
    3 1 roll
  \pgf@ps@rgb{#1blue} mul exch \pgf@ps@rgb{#2blue} mul add
}




\def\pgfdeclarecolorwheelshading#1#2#3{%
  \pgf@ps@getcols{#3}%
  \pgfmathparse{mod(#2+360/\pgf@ps@ncol-90,360)}%
  \pgf@x=\pgfmathresult pt\relax%
  \ifdim\pgf@x<0pt\relax%
    \advance\pgf@x by360pt\relax%
  \fi%
  \edef\pgf@ps@rot{\pgfmath@tonumber{\pgf@x}}%
  \pgf@ps@generate@ps%
  \pgf@ps@esettoks{%
    \noexpand\pgfdeclarefunctionalshading[#3]{#1}%
    {\noexpand\pgfpoint{-50bp}{-50bp}}{\noexpand\pgfpoint{50bp}{50bp}}%
    {\noexpand\pgf@ps@colorstorgb{#3}}%
    {%
      2 copy abs exch abs add 0.0001 ge { atan } { pop } ifelse
      \pgf@ps@rot\pgf@ps@sp add dup 360 ge { -360 add } { } ifelse
      360 \pgf@ps@ncol\pgf@ps@sp 
      div div dup floor dup 3 1 roll neg add dup neg 1 add exch
      2 copy 2 copy 7 -1 roll 1 add
      \the\pgf@ps@toks}}%
  \edef\pgf@ps@marshal{\the\pgf@ps@toks}%
  \pgf@ps@marshal}

\def\pgf@ps@getcols#1{%
  \c@pgf@ps=0\relax%
  \pgfutil@for\pgf@ps@:={#1}\do{\advance\c@pgf@ps by1}%
  \edef\pgf@ps@ncol{\the\c@pgf@ps}%
}

\pgfdeclarecolorwheelshading{Austria}{0}{white,red!80,red,red!80}
\usetikzlibrary{shadings}
\usepgfmodule{nonlineartransformations}
\makeatletter

\begin{document}
\begin{centering}
\begin{tikzpicture}[scale=1]

\def\aStartA{30}
\def\aStopA{330}

\draw[thin, color=gray] (\aStartA:0)--(\aStartA:3.5cm);
\draw[thin, color=gray] (\aStopA:0)--(\aStopA:3.5cm);
\begin{scope}
\clip (\aStartA:2cm)--(\aStartA:2cm)--(\aStartA:3cm) arc (\aStartA:\aStopA:3cm)--(\aStopA:2cm)--(\aStopA:2cm) arc (\aStopA:\aStartA:2cm);
\shade[shading=Austria,rotate=45] [even odd rule]
        (0,0) circle (3);
\end{scope}
\end{tikzpicture}
\end{centering}
\end{document}

在此处输入图片描述

这是 acroread 的输出。它看起来非常与预览不同。

原始答案:这是一个使用非线性变换的提议。pgfmanual 第 103.4 节中的非线性变换将水平框精确地转换为弧线,如您的图所示。所以我只是线性地对水平框进行着色,然后对其进行非线性变换。

\documentclass[tikz,]{standalone}
\usepackage{tikz}
\usetikzlibrary{shadings}
\usepgfmodule{nonlineartransformations}
\makeatletter
\def\polartransformation{%
% \pgf@x will contain the radius
% \pgf@y will contain the distance 
\pgfmathsincos@{\pgf@sys@tonumber\pgf@x}%
% pgfmathresultx is now the cosine of radius and 
% pgfmathresulty is the sine of radius 
\pgf@x=\pgfmathresultx\pgf@y% 
\pgf@y=\pgfmathresulty\pgf@y%
}
\makeatother

\begin{document}
\begin{centering}
\begin{tikzpicture}[scale=1]

\def\aStartA{30}
\def\aStopA{330}

\filldraw[gray!50,left color=white!25, right color=white!25, middle color=red!25] (\aStartA:2cm)--(\aStartA:2cm)--(\aStartA:3cm) arc (\aStartA:\aStopA:3cm)--(\aStopA:2cm)--(\aStopA:2cm) arc (\aStopA:\aStartA:2cm);
\draw[thin, color=gray] (\aStartA:0)--(\aStartA:3.5cm);
\draw[thin, color=gray] (\aStopA:0)--(\aStopA:3.5cm);
\clip (\aStartA:2cm)--(\aStartA:2cm)--(\aStartA:3cm) arc (\aStartA:\aStopA:3cm)--(\aStopA:2cm)--(\aStopA:2cm) arc (\aStopA:\aStartA:2cm);
\pgftransformnonlinear{\polartransformation}
\shade[left color=red,right color=white](-6.33,2) -- (-1,2)--(-1,3) --(-6.33,3) -- cycle;
\shade[left color=red,right color=white](6.33,2) -- (1,2)--(1,3) --(6.33,3) -- cycle;
\end{tikzpicture}
\end{centering}
\end{document}

在此处输入图片描述

附录:我尝试通过切换到低级命令并使用\pgfsetadditionalshadetransform阴影来使代码更简洁。不幸的是,成功率非常有限

\documentclass[tikz,]{standalone}
\usepackage{tikz}
\usetikzlibrary{shadings}
\usepgfmodule{nonlineartransformations}
\makeatletter
\def\polartransformation{%
% \pgf@x will contain the radius
% \pgf@y will contain the distance 
\pgfmathsincos@{\pgf@sys@tonumber\pgf@x}%
% pgfmathresultx is now the cosine of radius and 
% pgfmathresulty is the sine of radius 
\pgf@x=\pgfmathresultx\pgf@y% 
\pgf@y=\pgfmathresulty\pgf@y%
}
\makeatother

\begin{document}
\pgfdeclarehorizontalshading{myshadingG}{5.34cm}
 {color(0cm)=(red); color(1cm)=(red!90);  color(3.34cm)=(red!10); 
 color(4.34cm)=(white)}



\begin{centering}
\begin{tikzpicture}[scale=1]

\def\aStartA{30}
\def\aStopA{330}

\draw[thin, color=gray] (\aStartA:0)--(\aStartA:3.5cm);
\draw[thin, color=gray] (\aStopA:0)--(\aStopA:3.5cm);
\begin{scope}
\clip (\aStartA:2cm)--(\aStartA:2cm)--(\aStartA:3cm) arc (\aStartA:\aStopA:3cm)--(\aStopA:2cm)--(\aStopA:2cm) arc (\aStopA:\aStartA:2cm);
\pgftransformnonlinear{\polartransformation}
\pgfsetadditionalshadetransform{\polartransformation}
\pgfpathrectangle{\pgfpoint{-6.34cm}{2.00cm}}{\pgfpoint{5.34cm}{1cm}}
\pgfpathrectangle{\pgfpoint{-6.34cm}{2.00cm}}{\pgfpoint{-5.34cm}{1cm}}
\pgfshadepath{myshadingG}{0}
\end{scope}
\end{tikzpicture}
\end{centering}
\end{document}

在此处输入图片描述

(是的,我也看到有一个小间隙,但这不是重点。)重点是 \pgfsetadditionalshadetransform{\polartransformation} 似乎没有效果。但是,也没有错误消息。对我来说,这有点像被忽略了。

相关内容