3

On page 1024 of the PGF manual there is a small code to draw random paths which are "contained", or which don't escape too far from their starting points. I copied part of the code to draw that sort of curve on the background of a picture which already contains random elements; I modified the code by adding the macros \xmax and \ymax to the computation of the coordinates. The result is that this random path always ends very far from the first picture. This result persists whether or not the random path is drawn on the background layer, whatever the parameter in \pgfmathsetseed{<param>}, and whether or not I call the seed function again when drawing it. Here's the code:

\documentclass[tikz]{standalone}

\usetikzlibrary{
    calc, 
    math, 
    backgrounds,
    shapes
}

\pgfmathsetseed%{\number\pdfrandomseed}
    {1}
\newcommand\RandNum[1]{random(1,#1)/#1}

\definecolor{almond}{rgb}{0.94, 0.87, 0.8}

\begin{document}
\begin{tikzpicture}[scale = 3.5]

\pgfmathsetmacro{\xmax}{5.5}
\pgfmathsetmacro{\ymax}{3.1}
\pgfmathtruncatemacro{\totfigs}{1.5*(\ymax*\xmax)}
\pgfmathsetmacro{\MaxRand}{\xmax*\ymax}

\foreach ~ in {0,0.2, ..., \totfigs}{
    \pgfmathsetmacro{\R}{random(3,12)}
    \pgfmathsetmacro{\rsizex}{\RandNum{\MaxRand}}
    \pgfmathsetmacro{\rsizey}{\RandNum{\MaxRand}}
    \pgfmathsetmacro{\rsize}{\RandNum{\MaxRand}}
    \pgfmathsetmacro{\rot}{rnd}
    \pgfmathsetmacro{\blau}{rnd}
    \pgfmathsetmacro{\grun}{rnd}
    \definecolor{coul}{rgb}{\rot,\grun,\blau}
    \definecolor{pigm}{cmy}{\rot,\grun,\blau}
    \fill[
    fill = coul, 
    opacity = \RandNum{8},
    ] (rnd*\xmax,rnd*\ymax)%
    circle [x radius = \rsizex*0.35, y radius = \rsizey*0.25];
    \node[
        fill = pigm, 
        regular polygon, 
        regular polygon sides = \R, 
        minimum size = \rsize*2 cm, 
        opacity = \RandNum{4}, 
        rotate = {random(0,27)}
        ] at (rnd*\xmax,rnd*\ymax) {};
}

    \begin{scope}[on background layer, scale = 0.3, x = 10pt, y = 10pt]
        \fill[almond] (current bounding box.south west) rectangle (current bounding box.north east);
        \pgfmathsetseed{1}
%%%% THIS PIECE OF CODE: FROM HERE
        \coordinate (current point) at (0,0);
        \coordinate (old velocity) at (current point);
        \coordinate (new velocity) at (rand*\xmax,rand*\ymax);
        \foreach ~ in {0,...,100}{
            \pgfmathsetmacro{\rot}{rnd}
            \pgfmathsetmacro{\blau}{rnd}
            \pgfmathsetmacro{\grun}{rnd}
            \definecolor{col}{rgb}{\rot,\grun,\blau}
            \draw[col, thick] 
                (current point) .. controls ++([scale=-1]old velocity) and ++(new velocity) .. 
                    ++(rnd,rnd) coordinate (current point); 
            \coordinate (old velocity) at (new velocity); 
            \coordinate (new velocity) at (rand*\xmax,rand*\ymax);
        }
%%%%% UP TO HERE
    \end{scope}

\end{tikzpicture}
\end{document}

If I run the same code (the one between the comments in uppercase) on a separate document, it produces a "contained" path, as expected. I attach pictures of both behaviours. However, if I remove the macros \xmax and \ymax from that piece of code and run it, I also obtain a random path that "escapes"; that is, if I compile the following code:

\documentclass[tikz]{standalone}

\usetikzlibrary{calc, math}

\pgfmathsetseed{\number\pdfrandomseed}

\begin{document}

\pgfmathsetmacro{\xmax}{5.5}
\pgfmathsetmacro{\ymax}{3.1}

\begin{tikzpicture}

    \coordinate (current point) at (0,0);
    \coordinate (old velocity) at (current point);
    \coordinate (new velocity) at (rand,rand);
    \foreach ~ in {0,...,100}{
        \pgfmathsetmacro{\rot}{rnd}
        \pgfmathsetmacro{\blau}{rnd}
        \pgfmathsetmacro{\grun}{rnd}
        \definecolor{col}{rgb}{\rot,\grun,\blau}
        \draw[col, thick] 
        (current point) .. controls ++([scale=-1]old velocity) and ++(new velocity) .. 
        ++(rnd,rnd) coordinate (current point); 
        \coordinate (old velocity) at (new velocity); 
        \coordinate (new velocity) at (rand,rand);
    }
\end{tikzpicture}

\end{document}

I obtain the third picture. How can I correct this and obtain a path as in the second picture every time? Thanks!

The result. The code with <code>\xmax</code> and <code>\ymax</code> on a separate file. The code without <code>\xmax</code> and <code>\ymax</code> on a separate file.

mathbekunkus
  • 1,389

1 Answers1

3

The pgf function rnd yields a random number between 0 and 1, so you always advance in positive x and y directions. You probably want rnd-0.5.

\documentclass[tikz]{standalone}

\usetikzlibrary{calc, math}

\pgfmathsetseed{\number\pdfrandomseed}

\begin{document}

\pgfmathsetmacro{\xmax}{5.5}
\pgfmathsetmacro{\ymax}{3.1}

\begin{tikzpicture}

    \coordinate (current point) at (0,0);
    \coordinate (old velocity) at (current point);
    \coordinate (new velocity) at (rand,rand);
    \foreach ~ in {0,...,100}{
        \pgfmathsetmacro{\rot}{rnd}
        \pgfmathsetmacro{\blau}{rnd}
        \pgfmathsetmacro{\grun}{rnd}
        \definecolor{col}{rgb}{\rot,\grun,\blau}
        \draw[col, thick] 
        (current point) .. controls ++([scale=-1]old velocity) and ++(new velocity) .. 
        ++(rnd-0.5,rnd-0.5) coordinate (current point); 
        \coordinate (old velocity) at (new velocity); 
        \coordinate (new velocity) at (rand,rand);
    }
\end{tikzpicture}

\end{document}

enter image description here

If you want to squeeze the path in a box, I do not see any way than keeping track of the coordinates.

\documentclass[tikz]{standalone}

\usetikzlibrary{calc, math}

\pgfmathsetseed{\number\pdfrandomseed}

\begin{document}

\pgfmathsetmacro{\xmax}{5.5}
\pgfmathsetmacro{\ymax}{3.1}

\begin{tikzpicture}
    \draw (0,0) rectangle (\xmax,\ymax);
    \coordinate (current point) at (0,0);
    \coordinate (old velocity) at (current point);
    \pgfmathsetmacro{\currentx}{rnd}
    \pgfmathsetmacro{\currenty}{rnd}
    \coordinate (new velocity) at (\currentx,\currenty);
    \foreach \X  [remember=\currentx as \currentx,remember=\currenty as \currenty]
        in {0,...,100}{
        \pgfmathsetmacro{\rot}{rnd}
        \pgfmathsetmacro{\blau}{rnd}
        \pgfmathsetmacro{\grun}{rnd}
        \definecolor{col}{rgb}{\rot,\grun,\blau}
        \pgfmathsetmacro{\currentx}{max(0,min(\xmax,\currentx+rand))}
        \pgfmathsetmacro{\currenty}{max(0,min(\ymax,\currenty+rand))}
        \draw[col, thick] 
        (current point) .. controls ++([scale=-1]old velocity) and ++(new velocity) .. 
        (\currentx,\currenty) coordinate (current point); 
        \coordinate (old velocity) at (new velocity); 
        \coordinate (new velocity) at (rand,rand);
    }
\end{tikzpicture}

\end{document}

enter image description here

This can still overshoot, as one can see. If you want to remove the overshoot, one also has to keep track of the control points.

  • 3
    Is it a "Picasso" -:-)? – Sebastiano May 24 '20 at 21:10
  • 2
    @Sebastiano Picasso can be found here. –  May 24 '20 at 21:12
  • 2
    @Schrödinger'scat According to the PGF manual (v. 3.1.5b, page 1039) rand "generates a pseudo-random number between -1 and 1 [...]"; the purpose of \xmax and ymax is to bound the generation of random figures in the first picture of my question. – mathbekunkus May 24 '20 at 21:19
  • 1
    @ÓscarGuajardo You are right. My bad. However, the important translation is due to rnd and not rand. I had not looked carefully. The correct statement is that you want rnd-0.5. And rnd really creates a random number between 0 and 1. –  May 24 '20 at 21:26
  • What I would like to understand is why, when using rand (third picture, second piece of code on my question) the path still "escapes". – mathbekunkus May 24 '20 at 21:43
  • 2
    @ÓscarGuajardo Can you point which piece of the code you mean precisely? I seem to always see ++(rnd,rnd). –  May 24 '20 at 21:45
  • Just saw it on reviewing the code again. Thanks!! :) – mathbekunkus May 24 '20 at 21:46