Turn tikz drawing into a macro
You can use a pic
. The interface here isn't that good, but I think it works. To just add a black shape use e.g. \pic at (0,0) {randomblob};
. As set up, randomblob
has four key-value arguments, used as randomblob={<key>=<value>}
. They are
edgecolor
- the color of the line, black by default.fillcolor
- fill color. If not specified, no filling is done.label
- the text of a node placed in the center of the shape.arrowtip
- an arrow tip. If specified, 10 arrow tips are placed evenly along the path.
Other settings such as thick
and fill opacity
can be added to the pic
, not randomblob
.
\documentclass[tikz]{standalone}
\usetikzlibrary{decorations.markings,arrows.meta}
\pgfmathsetseed{\number\pdfrandomseed}
\tikzset{randomblob/.pic={
\tikzset{%
/randomblob/.cd,
edgecolor=black,
fillcolor=none,
arrowtip={},
label={},
#1
}
% Set random in/out angles for the points
\pgfmathsetmacro{\a}{random(45,135)}
\pgfmathsetmacro{\b}{random(300,190)}
\pgfmathsetmacro{\c}{random(290,380)}
\pgfmathsetmacro{\d}{random(340,430)}
\pgfmathsetmacro{\e}{random(20,110)}
\pgfmathsetmacro{\f}{random(110,200)}
\pgfmathsetmacro{\g}{random(160,250)}
\pgfmathsetmacro{\h}{random(200,290)}
% Set random location for points.
% These points are based on an ellipse with horizontal radius 8 and vertical radius 6
\coordinate (a) at (8+1.5*rand,1.5*rand);
\coordinate (b) at (6+1.5*rand,4+1.5*rand);
\coordinate (c) at (1.5*rand,6+1.5*rand);
\coordinate (d) at (-6+1.5*rand,4+1.5*rand);
\coordinate (e) at (-8+1.5*rand,1.5*rand);
\coordinate (f) at (-6+1.5*rand,-4+1.5*rand);
\coordinate (g) at (1.5*rand,-6+1.5*rand);
\coordinate (h) at (6+1.5*rand,-4+1.5*rand);
\draw [
decoration={
markings,
mark=between positions 0 and 0.9 step 0.1 with {\arrow{\blobarrow}}
},
postaction={decorate},
fill=\blobfillclr,draw=\blobedgeclr]
(a) to[out=\a, in=\b] (b)
to[out=\b+180, in=\c] (c)
to[out=\c+180, in=\d] (d)
to[out=\d+180, in=\e] (e)
to[out=\e+180, in=\f] (f)
to[out=\f+180, in=\g] (g)
to[out=\g+180, in=\h] (h)
to[out=\h+180, in=\a+180] (a);
\node (0,0) {\bloblabel};
},
/randomblob/.search also={/tikz},
/randomblob/.cd,
label/.store in=\bloblabel,
edgecolor/.store in=\blobedgeclr,
fillcolor/.store in=\blobfillclr,
arrowtip/.store in=\blobarrow
}
\begin{document}
\begin{tikzpicture}[x=0.3cm,y=0.3cm]
\pic at (0,0) {randomblob={label=$a+b$,arrowtip={Stealth}}};
\pic [fill opacity=0.2,very thick] at (5,-2) {randomblob={fillcolor=blue,edgecolor=red}};
\pic[thick,blue] at (-5,-5) {randomblob={label={What?},arrowtip=latex,edgecolor=brown}};
\end{tikzpicture}
\end{document}
(I looked rather hard at https://tex.stackexchange.com/a/281102/586 when writing that code. In other words, I used pretty much exactly the same, so thanks cfr.)
Original answer
At the moment it doesn't fulfill your bonus points though, will have to get back to you on that. (Probably wont have time during the day, but maybe I can figure something out during the afternoon/evening.)
\documentclass[tikz]{standalone}
\pgfmathsetseed{\number\pdfrandomseed}
\tikzset{randomblob/.pic={
% Set random in/out angles for the points
\pgfmathsetmacro{\a}{random(45,135)}
\pgfmathsetmacro{\b}{random(300,190)}
\pgfmathsetmacro{\c}{random(290,380)}
\pgfmathsetmacro{\d}{random(340,430)}
\pgfmathsetmacro{\e}{random(20,110)}
\pgfmathsetmacro{\f}{random(110,200)}
\pgfmathsetmacro{\g}{random(160,250)}
\pgfmathsetmacro{\h}{random(200,290)}
% Set random location for points.
% These points are based on an ellipse with horizontal radius 8 and vertical radius 6
\coordinate (a) at (8+1.5*rand,1.5*rand);
\coordinate (b) at (6+1.5*rand,4+1.5*rand);
\coordinate (c) at (1.5*rand,6+1.5*rand);
\coordinate (d) at (-6+1.5*rand,4+1.5*rand);
\coordinate (e) at (-8+1.5*rand,1.5*rand);
\coordinate (f) at (-6+1.5*rand,-4+1.5*rand);
\coordinate (g) at (1.5*rand,-6+1.5*rand);
\coordinate (h) at (6+1.5*rand,-4+1.5*rand);
% Draw the randomly generated closed shape.
\draw (a) to[out=\a, in=\b] (b)
to[out=\b+180, in=\c] (c)
to[out=\c+180, in=\d] (d)
to[out=\d+180, in=\e] (e)
to[out=\e+180, in=\f] (f)
to[out=\f+180, in=\g] (g)
to[out=\g+180, in=\h] (h)
to[out=\h+180, in=\a+180] (a);
}}
\begin{document}
\begin{tikzpicture}
\pic at (0,0) {randomblob};
\pic[blue] at (2,2) {randomblob};
\pic[thick,red] at (-2,-2) {randomblob};
\end{tikzpicture}
\end{document}
As others have mentioned the pic
is a useful way to go. Note, that if the loop is drawn using individual paths then a fill is not possible. Conversely, if the loop was drawn as one path then it would not be possible to get arrows on the individual segments of the loop without redrawing individual segments, unless a decoration is used:
\documentclass[tikz,border=5]{standalone}
\usetikzlibrary{decorations.pathreplacing,math}
\tikzset{pics/random loop/.style={code={
\tikzmath{%
integer \a; coordinate \p;
\a1 = random(45,135); \a2 = random(300,190);
\a3 = random(290,380); \a4 = random(340,430);
\a5 = random(20,110); \a6 = random(110,200);
\a7 = random(160,250); \a8 = random(200,290);
\p1 = (8+1.5*rand,1.5*rand); \p2 = (6+1.5*rand,4+1.5*rand);
\p3 = (1.5*rand,6+1.5*rand); \p4 = (-6+1.5*rand,4+1.5*rand);
\p5 = (-8+1.5*rand,1.5*rand); \p6 = (-6+1.5*rand,-4+1.5*rand);
\p7 = (1.5*rand,-6+1.5*rand); \p8 = (6+1.5*rand,-4+1.5*rand);
}
\path [pic actions/.try, postaction={decoration={show path construction,
curveto code={\path [pic outline/.try]
(\tikzinputsegmentfirst) .. controls(\tikzinputsegmentsupporta)
and (\tikzinputsegmentsupportb) .. (\tikzinputsegmentlast);
}}, decorate}] (\p1)
\foreach \i [evaluate={\j=int(mod(\i, 8)+1);
\u = \a\i + (\i > 1) * 180; \v = \a\j + (\i == 8) * 180;}] in {1,...,8}{
to [out=\u, in=\v] (\p\j) } -- cycle;
}}}
\begin{document}
\begin{tikzpicture}
\foreach \c [count=\i] in {red, yellow, pink, green, orange, purple, blue}
\pic [fill=\c!50,
pic outline/.style={draw=\c!75!black, line width=0.25cm, ->}]
at (360/7*\i:16) {random loop};
\end{tikzpicture}
\end{document}
Here's a Metapost alternative. I like the fact that in MP you can make a macro that returns a path
that you can assign to a variable, and then pass it to other commands like draw
, reverse
, fill
and apply transformations to it like shifted
, rotated
, etc.
prologues := 3;
outputtemplate := "%j%c.eps";
% Make a random ellipsoid with semiaxes a,b and r amount of randomness
vardef random_ellipse(expr a,b,r) =
save e; path e;
e = fullcircle xscaled a yscaled b;
for i=1 upto length e:
point i of e shifted (r*normaldeviate, r*normaldeviate) ..
endfor cycle
enddef;
% Draw n evenly-space arrows along path p
vardef draw_arrows_along(expr p, n) =
save a; a = arclength p / n;
for i=1 upto n:
drawarrow subpath (arctime (i-1)*a of p, arctime i*a of p) of p;
endfor
enddef;
beginfig(1);
randomseed := 3142;
path e[];
e1 = random_ellipse(144,89,13);
e2 = random_ellipse(144,89,13) shifted (200, 0);
e3 = random_ellipse(144,89,13) shifted (200, 150);
e4 = random_ellipse(144,89,13) shifted ( 0, 150);
draw e1;
drawoptions(withcolor .67 red);
draw_arrows_along(e2,13);
drawoptions(withcolor .4 green);
draw_arrows_along(reverse e3, 32);
drawoptions();
fill e4 withcolor .8[blue,white];
draw e4 withcolor .67 blue;
label("A", center e1);
label("B", center e2);
label("C", center e3);
label("D", center e4);
endfig;
end.