16

I want to create a decoration that would decorate a path with gray transparent clouds with random shifts, random number of puffs and scaling size. The idea is that it should look like smoke coming up.

I tried to define my own decoration, tried using shape backgrounds and markings, but nothing really worked. In the end, I managed to draw the clouds in a loop, but of course it is not the most elegant solutions. So this is the code of my solution and attempts, and the expected result:

\documentclass[tikz,border=5]{standalone}

\usetikzlibrary{decorations.pathmorphing, decorations.markings, decorations.shapes}
\usetikzlibrary{shapes,calc}

\makeatletter
\newdimen\cloud@sep
\cloud@sep=0.2cm\relax

\pgfdeclaredecoration{smoke}{initial}{
  \state{initial}[width=\cloud@sep]
  {
    \pgfsetfillopacity{0.3}
    \def\tikz@fillcolor{mygray}
    \tikz@mode@filltrue
    \pgfnode{cloud}{center}{}{}{}
    \pgfmathsetlength\cloud@sep{0.2cm + rand*0.2cm}
    \global\cloud@sep=\cloud@sep
  }
  \state{final}
  {
    \pgfpathmoveto{\pgfpointdecoratedpathlast}
  }
}
\makeatother

\begin{document}
\begin{tikzpicture}
  \foreach \i [evaluate={\j=\i-1;}] in {1,2,...,20} {%
    \node[shape=cloud, cloud puffs=9+5*rnd, fill=gray, opacity=0.4, %
    minimum width=4+\j, minimum height=3+0.5*\j] at %
    ($(60:1) + 0.09*(\i,0) + 0.1*(0,\i) + 0.25*(rand,0) + 0.1*(0,rand)$) {}; }
\end{tikzpicture}

%% the code that does not work
\begin{tikzpicture}
  \path[decorate,decoration={smoke, shape start width=1.5mm, shape end
    width=2.5mm, shape start height=2mm, shape end height=3mm},
  decoration={shape scaled}, fill=gray] (60:1.5) -- (50:3);
\end{tikzpicture}

\begin{tikzpicture}
  \path[decorate,decoration={shape backgrounds, shape=cloud, shape
    width=4mm+rand, shape height=3mm+rand}, cloud puffs=11+3*rand, fill=gray,
  opacity=0.3] (60:1.5) -- (50:3);
\end{tikzpicture}
  \end{document}

Smoke

Is it possible to define/specify such a decoration? Note that, it would be nice to have a decoration where each cloud is in a different transparency group, that is, one could see their overlapping.

  • Even better would be to have the possibility to use the fade out fading – Elena Dec 14 '14 at 1:39
15

First Version

Here is a possible solution via a markings decoration (the gray clouds are on a line and the orange clouds are on a circle):

enter image description here

\documentclass[tikz,border=5]{standalone}

\usetikzlibrary{decorations.markings,shapes,calc}

\tikzset{
  random clouds/.style={
    decoration={markings,mark=between positions 0 and 1 step 5mm with {
        \pgfmathsetmacro\myh{5mm+ rnd*1cm}
        \pgfmathsetmacro\myw{\myh + 5mm + rnd*1cm}
        \node[shape=cloud, cloud puffs={10+int(5*rnd)}, fill=#1, opacity=0.4,
        minimum width=\myw,minimum height=\myh]
        at (rand * 1cm,rand * 1cm) {};
      }},
  },
}
\begin{document}
\begin{tikzpicture}
  \path[decorate,random clouds=gray]
  (0,0) -- (10,10);

  \path[decorate,random clouds=red]
  (5,5) circle (3cm);
\end{tikzpicture}
\end{document}

Second Version (with fade out fading)

enter image description here

\documentclass[tikz,border=5]{standalone}

\usetikzlibrary{decorations.markings,shapes,calc}

\tikzset{
  random clouds/.style={
    decoration={markings,mark=between positions 0 and 1 step 5mm with {
        \pgfmathsetmacro\myh{15mm + rnd*1cm}
        \pgfmathsetmacro\myw{\myh + 5mm + rnd*1cm}
        \pgfkeysgetvalue{/pgf/decoration/mark info/distance from start}{\currdist}
        \pgfmathsetmacro\myop{1-\currdist/\pgfdecoratedpathlength}
        \node[shape=cloud, cloud puffs={10+int(5*rnd)}, fill=#1, opacity=\myop,
        minimum width=\myw,minimum height=\myh]
        at (rand * 1cm,rand * 1cm) {};
      }},
  },
}
\begin{document}
\begin{tikzpicture}
  \path[decorate,random clouds=orange]
  (0,0) -- (10,10);

\end{tikzpicture}
\end{document}

Third Version (with keys to control size and color)

In this version, clouds sizes are not random.

enter image description here

\documentclass[tikz,border=5]{standalone}
\usetikzlibrary{decorations.markings,shapes,calc}

\makeatletter
\tikzset{
  random clouds/.is family,
  random clouds,
  color/.store in=\randomclouds@c,
  start width/.store in=\randomclouds@startw,
  start height/.store in=\randomclouds@starth,
  end width/.store in=\randomclouds@endw,
  end height/.store in=\randomclouds@endh,
  color=gray,
  start width=22mm,start height=12mm,
  end width=14mm,end height=8mm
}
\tikzset{
  random clouds decoration/.style={
    decoration={markings,mark=between positions 0 and 1 step 5mm with {
        \tikzset{random clouds,#1}
        \pgfkeysgetvalue{/pgf/decoration/mark info/distance from start}{\currdist}
        \pgfmathsetmacro\myop{1-\currdist/\pgfdecoratedpathlength}
        \pgfmathsetmacro\myw{\randomclouds@endw+\myop*(\randomclouds@startw-\randomclouds@endw)}
        \pgfmathsetmacro\myh{\randomclouds@endh+\myop*(\randomclouds@starth-\randomclouds@endh)}
        \node[shape=cloud, cloud puffs={10+int(5*rnd)},fill=\randomclouds@c, opacity=\myop,
        minimum width=\myw,minimum height=\myh]
        at (rand * 1cm,rand * 1cm) {};
      }},
  },
}
\makeatother

\pgfmathsetseed{\pdfuniformdeviate 1000000}

\begin{document}
\begin{tikzpicture}
  \path[decorate,random clouds decoration]
  (0,0) -- (10,10);

  \path[decorate,random clouds decoration={
    color=orange,
    start width=12mm,end width=5mm,
    start height=22mm,end height=10mm,
  }]
  (5,0) -- (15,10);

\end{tikzpicture}
\end{document}
  • would it be possible to add something like decoration={shape scaled, shape start width=1.5mm, shape end width=2.5mm, shape start height=2mm, shape end height=3mm} to the path? – Elena Dec 14 '14 at 2:38
  • @Elena shape scaled and others cited keys come with decorations.shapes. Here, I use decorations.markings. So, I must emulate similar keys (in my third version). – Paul Gaborit Dec 14 '14 at 3:02
  • 2
    @PaulGaborit Would it be possible to have a style for Gandalf smoke "rings"? – user10274 Dec 14 '14 at 14:16
22

I started out trying to do what was required but got sidetracked. The result looks cool (as long as you don't look too closely) but completely impractical:

\documentclass[tikz,border=5]{standalone}
\usetikzlibrary{decorations.pathmorphing,backgrounds}
\begin{document}
\begin{tikzpicture}[background rectangle/.style={fill=black},
show background rectangle]
\foreach \i in {1,...,10}
\fill [gray, even odd rule, opacity=0.125,rounded corners=2pt, decoration={random steps, amplitude=.125cm, segment length=.125cm}, decorate]
(0,0) plot [domain=0:360, samples=50] ({sin(\x*4)/500*\x+rand/(2.9-\x/180)}, \x/100+rand/2) -- 
plot [domain=360:0, samples=50] ({sin(\x*4)/500*\x+rand/(2.9-\x/180)}, \x/100+rand/2);
\end{tikzpicture}
\end{document}

enter image description here

You could probably smoke several pipe-loads of tobacco before this compiles:

\documentclass[tikz,border=5]{standalone}
\usetikzlibrary{decorations.pathmorphing,backgrounds}
\begin{document}
\foreach \n in {1,1.1,...,4}{
\begin{tikzpicture}[background rectangle/.style={fill=black},
show background rectangle]
\useasboundingbox (-5,4) rectangle (5,10);
\foreach \i in {1,...,10}
\fill [gray, even odd rule, opacity=0.125, decoration={random steps, amplitude=.125cm*\n, segment length=.125cm}, decorate]
(\n,\n*3) arc (0:360:\n\space and \n/4) arc (360:0:\n\space and \n/4) -- cycle;
\end{tikzpicture}
}
\end{document}

enter image description here

  • 1
    you are a true artist! – Elena Dec 15 '14 at 17:49

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.