48

How to generate in LaTeX (TikZ or something similar) the following image:

crayon fill for cylinder crayon fill for triangle

This was not drawn by hand, as far as I known, but with some Mac tool.

3

3 Answers 3

56

Here is a quick one: I've used the decoration that Forkrul Assail linked to and basically it's going back and forth between the corners just as you would do to hatch. However it's not really following the outer contour and you can make it more detailed if you define this as a genuine decoration following precisely the shape border. I didn't do it because I think Inkscape or something similar is much easier to perform this and I doubt that it is worth automating. Nevertheless the idea is essentially the same for the decoration anyhow.

Also much to my surprise the line join option is really showing a difference.

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{shapes.geometric,calc,positioning,decorations}

\makeatletter
\pgfdeclaredecoration{penciline}{initial}{
    \state{initial}[width=+\pgfdecoratedinputsegmentremainingdistance,auto corner on length=1mm,]{
        \pgfpathcurveto%
        {% From
            \pgfqpoint{\pgfdecoratedinputsegmentremainingdistance}
                            {\pgfdecorationsegmentamplitude}
        }
        {%  Control 1
        \pgfmathrand
        \pgfpointadd{\pgfqpoint{\pgfdecoratedinputsegmentremainingdistance}{0pt}}
                        {\pgfqpoint{-\pgfdecorationsegmentaspect\pgfdecoratedinputsegmentremainingdistance}%
                                        {\pgfmathresult\pgfdecorationsegmentamplitude}
                        }
        }
        {%TO 
        \pgfpointadd{\pgfpointdecoratedinputsegmentlast}{\pgfpoint{1pt}{1pt}}
        }
    }
    \state{final}{}
}
\makeatother

\begin{document}
\begin{tikzpicture}[decoration={penciline,amplitude=2pt}]
\node[regular polygon,regular polygon sides=3,minimum height=2cm,draw] (a) {};
\node[below= 0.5cm of a] {\textsc{Working Copy}};
\draw[blue,opacity=0.3,decorate,line width=1mm,line join=round] (a.corner 3)
\foreach \x[remember=\x as \lastx(initially 0)] in {0.07,0.15,...,1.1}{
 -- ($(a.corner 1)!\lastx!(a.corner 2)$) --($(a.corner 3)!\lastx+0.05!(a.corner 2)$)
}--(a.corner 2);

\node[cylinder, shape border rotate=90, aspect = 0.65,draw,
        minimum height=1.7cm,minimum width=1.5cm] (b) at (4cm,0.2cm) {};
\node[below= 0.45cm of b] {\textsc{Copying Work}};
\draw[red,opacity=0.3,decorate,line width=0.9mm,line join=bevel] (b.after top)
\foreach \x[remember=\x as \lastx(initially 0)] in {0.1,0.2,...,1.1}{
 -- ($(b.after top)!\lastx!(b.before bottom)$) --($(b.after top)!\lastx+0.05!(b.before top)$)
} --(b.before bottom) 
\foreach \x[remember=\x as \lastx(initially 0)] in {0.1,0.2,...,1.1}{
 -- ($(b.before bottom)!\lastx!(b.after bottom)$) -- ($(b.before top)!\lastx+0.05!(b.after bottom)$)
};
\end{tikzpicture}
\end{document}

enter image description here

2
  • 13
    This site restores my hope in humanity daily. Great work! Commented Oct 18, 2012 at 14:26
  • @ForkrulAssail Your comment is certainly among those nice things that you see on this site, thank you!
    – percusse
    Commented Oct 18, 2012 at 19:25
20

I think for this one idea should be create a custom pattern, but my solution is far from being good. Indeed I remember having read somewhere that paths are evils and today I discover why: bit modifications of the parameters lead to very different outputs. To have something a bit stable, one could set the seed by means of:

\pgfmathsetseed{<some value>}

As starting point I used Custom and built in TikZ fill patterns.

The code:

\documentclass{article}
% for the font
\renewcommand*\sfdefault{augie} 
\renewcommand*\familydefault{\sfdefault}
\usepackage{tikz}
\usetikzlibrary{positioning,patterns,shapes.geometric}

% defining the new dimensions
\newlength{\hatchspread}
\newlength{\hatchthickness}
% declaring the keys in tikz
\tikzset{hatchspread/.code={\setlength{\hatchspread}{#1}},
         hatchthickness/.code={\setlength{\hatchthickness}{#1}}}
% setting the default values
\tikzset{hatchspread=3pt,
         hatchthickness=0.4pt}
% declaring the pattern
\pgfdeclarepatternformonly[\hatchspread,\hatchthickness]% variables
   {custom north west lines}% name
   {\pgfqpoint{-2\hatchthickness}{-2\hatchthickness}}% lower left corner
   {\pgfqpoint{\dimexpr\hatchspread+2\hatchthickness}{\dimexpr\hatchspread+2\hatchthickness}}% upper right corner
   {\pgfpoint{\hatchspread}{\hatchspread}}% tile size
   {% shape description
    \pgfsetlinewidth{\hatchthickness*rand}
    \pgfpathmoveto{\pgfpoint{rand*0.2pt}{\hatchspread}}
   \pgfpathcurveto
{\pgfqpoint{\dimexpr\hatchspread+6pt}{0.2pt}}{\pgfpoint{\hatchspread+4pt}{rand*3pt}}{\pgfqpoint{\dimexpr\hatchspread+0.1pt}{0.15pt}}
    \pgfsetstrokeopacity{0.175}
    \pgfsetstrokecolor{blue}
    \pgfusepath{stroke}
   }

\begin{document}
\pgfmathsetseed{123564} % to have always the same result
\begin{tikzpicture}
\node[draw,cylinder,scale=8,rotate=90,aspect=0.25, pattern= custom north west lines, ,hatchspread=6.2pt,hatchthickness=17pt] at (0,-3){};
\node at (0,-4.5) {\textsc{Repository}};

\node[draw,regular polygon,regular polygon sides=3, scale=4.25, yshift=-0.02cm,
pattern= custom north west lines, ,hatchspread=6.2pt,hatchthickness=17pt] at (5,-3){};
\node at (5,-4.5) {\textsc{Working Copy}};

\end{tikzpicture}%


\end{document}

and the result is:

enter image description here

BTW: If one needs to fill something with almost roof tiles, here's a code to do that:

\documentclass{article}

\usepackage{tikz}
\usetikzlibrary{calc,decorations.pathmorphing,patterns,shapes.geometric}

% To draw tiles
% defining the new dimensions
\newlength{\hatchspread}
\newlength{\hatchthickness}
% declaring the keys in tikz
\tikzset{hatchspread/.code=\setlength{\hatchspread}{#1},
         hatchthickness/.code=\setlength{\hatchthickness}{#1},
         hatchspread=3pt,hatchthickness=0.4pt}
% declaring the pattern
\pgfdeclarepatternformonly[\hatchspread,\hatchthickness]% variables
   {custom north west lines}% name
   {\pgfqpoint{-2\hatchthickness}{-2\hatchthickness}}% lower left corner
   {\pgfqpoint{\dimexpr\hatchspread+2\hatchthickness}{\dimexpr\hatchspread+2\hatchthickness}}% upper right corner
   {\pgfpoint{\hatchspread}{\hatchspread}}% tile size
   {% shape description
    \pgfsetlinewidth{\hatchthickness*rand}
    \pgfpathmoveto{\pgfpoint{rand*0.2pt}{\hatchspread}}
   \pgfpathcurveto
{\pgfqpoint{\dimexpr\hatchspread+3pt}{0.2pt}}{\pgfpoint{\hatchspread+2pt}{20pt}}{\pgfqpoint{\dimexpr\hatchspread+0.15pt}{0.15pt}}
    \pgfsetstrokeopacity{0.5}
    \pgfusepath{stroke}
   }       

\begin{document}
\pgfmathsetseed{123561} % to have always the same result
\begin{tikzpicture}
\node[draw,trapezium,scale=9, pattern= custom north west lines,hatchspread=6pt,hatchthickness=9pt] (s) at (0,-3){};
\end{tikzpicture}%
\end{document}

The output:

enter image description here


Just for fun (and for fans of hand drawns):

enter image description here

\documentclass{article}

\usepackage{tikz}
\usetikzlibrary{backgrounds,calc,decorations,decorations.pathmorphing,patterns,shapes.geometric}

\makeatletter
\pgfdeclaredecoration{penciline}{initial}{
    \state{initial}[width=+\pgfdecoratedinputsegmentremainingdistance,auto corner on length=1mm,]{
        \pgfpathcurveto%
        {% From
            \pgfqpoint{\pgfdecoratedinputsegmentremainingdistance}
                            {\pgfdecorationsegmentamplitude}
        }
        {%  Control 1
        \pgfmathrand
        \pgfpointadd{\pgfqpoint{\pgfdecoratedinputsegmentremainingdistance}{0pt}}
                        {\pgfqpoint{-\pgfdecorationsegmentaspect\pgfdecoratedinputsegmentremainingdistance}%
                                        {\pgfmathresult\pgfdecorationsegmentamplitude}
                        }
        }
        {%TO 
        \pgfpointadd{\pgfpointdecoratedinputsegmentlast}{\pgfpoint{1pt}{1pt}}
        }
    }
    \state{final}{}
}
\makeatother


% To draw tiles
% defining the new dimensions
\newlength{\hatchspread}
\newlength{\hatchthickness}
% declaring the keys in tikz
\tikzset{hatchspread/.code=\setlength{\hatchspread}{#1},
         hatchthickness/.code=\setlength{\hatchthickness}{#1},
         hatchspread=3pt,hatchthickness=0.4pt}
% declaring the pattern
\pgfdeclarepatternformonly[\hatchspread,\hatchthickness]% variables
   {custom north west lines}% name
   {\pgfqpoint{-2\hatchthickness}{-2\hatchthickness}}% lower left corner
   {\pgfqpoint{\dimexpr\hatchspread+2\hatchthickness}{\dimexpr\hatchspread+2\hatchthickness}}% upper right corner
   {\pgfpoint{\hatchspread}{\hatchspread}}% tile size
   {% shape description
    \pgfsetlinewidth{\hatchthickness*rand}
    \pgfpathmoveto{\pgfpoint{rand*0.2pt}{\hatchspread}}
   \pgfpathcurveto
{\pgfqpoint{\dimexpr\hatchspread+3pt}{0.2pt}}{\pgfpoint{\hatchspread+2pt}{20pt}}{\pgfqpoint{\dimexpr\hatchspread+0.15pt}{0.15pt}}
    \pgfsetstrokeopacity{0.5}
    \pgfusepath{stroke}
   }

\tikzset{window/.style={
        draw, fill=cyan!20,
        rectangle, minimum size=8bp,
        decorate, decoration=penciline,
        append after command={
            [shorten >=1.5\pgflinewidth, shorten <=1.5\pgflinewidth,]           
        (\tikzlastnode.north) edge[decorate, decoration=penciline] (\tikzlastnode.south)
        (\tikzlastnode.east) edge[decorate, decoration=penciline] (\tikzlastnode.west)
        }
    }
}


\begin{document}
\pgfmathsetseed{123561}
\begin{tikzpicture}
\node[draw,trapezium,scale=5, 
    decorate, decoration=penciline,
    pattern= custom north west lines,
    hatchspread=6pt,hatchthickness=9pt,
    preaction={fill=red!80!black!50}] (s) at (0,0){};

\begin{scope}[on background layer]
\draw[decorate,decoration=penciline,fill=yellow!15] ($(s.bottom left corner)!0.3!(s.south west)$)--++(0,-1.5)--++(2.2,0)--    ($(s.bottom right corner)!0.3!(s.south east)$);
\end{scope}

\draw[decorate,decoration=penciline,fill=brown!50] ([yshift=-1.5cm]$(s.bottom side)!0.3!(s.south west)$)--++(0,0.65)--++(0.4,0)--    ([yshift=-1.4cm]$(s.bottom side)!0.3!(s.south east)$);
\draw[fill=brown] ([yshift=-1.2cm]$(s.bottom side)!0.2!(s.south east)$) circle(1bp);

\node[window,yshift=-0.5cm] at (s.south west) {};
\node[window,yshift=-0.5cm] at (s.south east) {};

\end{tikzpicture}%
\end{document}
5
  • they are too regular, but still they're nice :)
    – yo'
    Commented Oct 19, 2012 at 15:30
  • Thanks. :) When I started I thought was possible to make patterns a bit more random, but after some trials I recognize that it's not so obvious.. anyway I really like this roof tiles :D Commented Oct 19, 2012 at 15:36
  • Haha! I've just seen the house. Instant classic.
    – percusse
    Commented Oct 19, 2012 at 18:42
  • @percusse: If answers had tags, mine should go under {fun} :D. Commented Oct 20, 2012 at 9:23
  • very nice!! =D The application that you found for this feature is very cool.
    – tcpaiva
    Commented Oct 20, 2012 at 14:03
13

If someone knows how to speed up the code ...

enter image description here

\documentclass{article}
\usepackage{xparse,tikz}
\usetikzlibrary{calc,intersections,shapes.geometric}

\makeatletter
    %%%%                        ---- Use path several times
    %%%%                        ---- thanks to Andrew Stacey
    \makeatletter
    \tikzset{
      use path for main/.code={%
        \tikz@addmode{%
          \expandafter\pgfsyssoftpath@setcurrentpath\csname tikz@intersect@path@name@#1\endcsname
        }%
      },
      use path for actions/.code={%
        \expandafter\def\expandafter\tikz@preactions\expandafter{\tikz@preactions\expandafter\let\expandafter\tikz@actions@path\csname tikz@intersect@path@name@#1\endcsname}%
      },
      use path/.style={%
        use path for main=#1,
        use path for actions=#1,
      }
    }
    \makeatother

\tikzset{HandFill/.style={%
                        thick,
                        line cap=round,
                        line join=round,
                        opacity=.95
                        }
        }

\NewDocumentCommand{\HandFill}{%
    D<>{1pt}    % lines density
    O{10}       % lines angle
    m           % path-cyle to fill
    m           % starting point inside the path    
    O{orange!40}% lines color
    D<>{10}     % lines length for intersection 
    }{%

    % fill above an below the starting point
    \foreach \z in {-1,1} {%

    % Creat the intersection points
    \begin{scope}[shift=#4,rotate=#2]
    \clip[use path=#3] ;
    \pgfmathtruncatemacro\i{0}
    \loop
        \path[name path=trait, % randomize density of lines
                shift={(0,\z*(.5*\i*#1+rand*.2*#1))}]
            (-#6,0)--(#6,0) ;
        \path[name intersections={%
            of=trait and #3,
            name=\i-A,
            total=\t}]
            \pgfextra{\xdef\InterNb{\t}} ;    
        \pgfmathtruncatemacro\i{\i+1}
        \ifnum\InterNb>0
    \repeat
    \pgfmathtruncatemacro\i{\i-3}
    \xdef\i{\i}
    \end{scope}

    \foreach \k in {1,3,...,\i} {
        \pgfmathtruncatemacro\j{\k-1}
        \pgfmathtruncatemacro\l{\k+1}    
        %randomize length of lines
        \coordinate (\k-A-2) at ($(\k-A-2)!rand*.015!(\j-A-1)$) ;
        \coordinate (\l-A-1) at ($(\l-A-1)!rand*.015!(\k-A-2)$) ;
        \draw[HandFill,#5] (\j-A-1) -- (\k-A-2) -- (\l-A-1)  ;
    } % end foreach \k
    } % end foreach \z
    } % end command

\begin{document}

\begin{tikzpicture}

\draw[name path=cercle] (2,0) circle (1) ;
\draw[name path=triangle,shift={(3.2,-.86)},scale=2]
        (0,0)
        --(1,0) coordinate[midway] (tr1)
        --(60:1) coordinate (tr2)
        --cycle ;
\node[name path=cylinder,cylinder, shape border rotate=90, aspect = 0.65, draw,minimum height=1.7cm,minimum width=1.5cm] (b) at (0,0) {} ;

\HandFill{cylinder}{(b)}
\HandFill<2pt>[60]{cercle}{{(2,0)}}[blue!40]
\HandFill<2pt>[-30]{cercle}{{(2,0)}}[blue!40]
\HandFill<1.5pt>[-25]{triangle}{($(tr1)!.5!(tr2)$)}[red!40]

\end{tikzpicture}

\end{document}

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .