0

If possible, I want to draw following figure, where two nodes side-by-side inside a cloud:

enter image description here

  • In order to achieve this should I use fit for the both inner-nodes? I was not able to fit two-muliple nodes into \AsymCloud.
  • Should I first draw cloud and than align nodes' positions inside the cloud? I was able to manage this by try-and-error:
\documentclass[journal,onecolumn]{IEEEtran}
\usepackage{tikz}
\usetikzlibrary{fit,matrix,positioning,shadows}
\usetikzlibrary{shapes.geometric,fit}
\usetikzlibrary{shapes.misc}
\usetikzlibrary{arrows,shapes,shapes.geometric,shapes.multipart,trees}

\tikzset{fileshape/.style 2 args={chamfered rectangle,
        draw, ultra thick,
        chamfered rectangle corners=north east,
        minimum height=12mm, minimum width=10mm,
        #1, label={[text=#1]270:{\sffamily #2}}
    }}

\newcommand{\AsymCloud}[3]{
    \begin{scope}[shift={#1},scale=#3,thick,draw=cyan]
        \draw (-1.6,-0.7) .. controls (-2.3,-1.1)
        and (-2.7,0.3) .. (-1.7,0.3)coordinate(asy1) .. controls (-1.6,0.7)
        and (-1.2,0.9) .. (-0.8,0.7) .. controls (-0.5,1.5)
        and (0.6,1.3) .. (0.7,0.5) .. controls (1.5,0.4)
        and (1.2,-1) .. (0.4,-0.6)coordinate(asy2) .. controls (0.2,-1)
        and (-0.2,-1) .. (-0.5,-0.7) .. controls (-0.9,-1)
        and (-1.3,-1) .. cycle;
        \path (asy1) -- (asy2) node[pos=0.5] {#2};
    \end{scope}
}

\usepackage{hyperref}
\begin{document}
\begin{figure}[!htp]
    \centering
    \begin{tikzpicture}[%
        >=latex,shorten >=2pt,shorten <=2pt,shape aspect=1,
        arrow/.style={<->, >=stealth, semithick},
        block/.style={},
        every node/.style = {font=\scriptsize}
        ]
        \AsymCloud{(3.3, 0.55)}{}{0.75}
        \node[cylinder,shape border rotate=90,draw,fill=white,inner xsep=3pt,align=center,xshift=35mm,yshift=0.5cm] (A) {};
        \node[cylinder,shape border rotate=90,draw,fill=green,inner xsep=3pt,align=center,left of=A] (A') {};

        %% Here I was not able to fit the node into \AsymCloud
        \node[cylinder,shape border rotate=90,draw,fill=white,shape aspect=0.2,font={\baselineskip=9pt},
        inner xsep=3pt,align=center,xshift=3mm,yshift=-2mm] (D') {};
        \node[draw,cloud,inner sep=-1.2pt,draw=cyan,thick,fit=(D')] (D) {};
    \end{tikzpicture}
\end{figure}

\end{document}

Output fit and positioning approach:

enter image description here

2
  • 1
    You could use the backgound layer (\usetikzlibrary{backgrounds}) to draw the cloud. BTW, you loaded the positioning library 3 times. Aug 12, 2023 at 13:55
  • Could you use a multipart node rather than separate nodes?
    – cfr
    Aug 12, 2023 at 16:37

2 Answers 2

2

You can use the fit library to fit a rectangle around your cylinders and use that as reference to draw the cloud. (Meaning, we measure how much space they need and use that space as a reference for drawing the cloud.)

I've adjusted the path of the cloud to be 0.3 shifted to the right so that the content seems more centered in it.

I'm assuming the clouds are always oriented the same and you will never need to rotate them, otherwise the logic is a bit more complicated. I'm using the calc library for now but this could be written very easily more efficient with basic PGF macros or actually turned into a shape if necessary. (Though, not with the same functionalities as other shapes, that would need much more work.)

This doesn't truly makes sure that the nodes are actually inside the cloud but the path of the cloud is just right that it will be.

Code

\documentclass[tikz]{standalone}
\usetikzlibrary{calc, fit, positioning, shapes.geometric, shapes.symbols}
\tikzset{
  AsymFit/.style={
    reset cm, % just to be safe
    insert path={
      node[overlay, shape=rectangle, inner sep=+0pt,
        outer sep=+0pt, path only, fit={#1}](@){}
      [shift=(@)] let \p X=(@.east), \p Y=(@.north), \n@={max(\x X, \y Y)} in},
    x={(right:\n@)}, y={(up:\n@)}, AsymCloud},
  AsymCloud/.style={insert path={
    (-1.3,-0.7) .. controls (-2.0,-1.1) and (-2.4, 0.3) .. (-1.3, 0.3)
                .. controls (-1.3, 0.7) and (-0.9, 0.9) .. (-0.5, 0.7)
                .. controls (-0.2, 1.5) and ( 0.9, 1.3) .. ( 1.0, 0.5)
                .. controls ( 1.8, 0.4) and ( 1.5,-1  ) .. ( 0.8,-0.6)
                .. controls ( 0.5,-1  ) and ( 0.1,-1  ) .. (-0.2,-0.7)
                .. controls (-0.6,-1  ) and (-1.0,-1  ) .. cycle}}}
\begin{document}
\begin{tikzpicture}[
  Cylinder/.style={shape=cylinder, shape border rotate=90, draw, inner xsep=+3pt}]
\node[Cylinder]            (A)  {};
\node[Cylinder, left=of A] (A') {};

\draw[cyan, thick, AsymFit=(A)(A')];
\end{tikzpicture}
\end{document}

Output

enter image description here

3
  • 2
    Load the bbox library and use bezier bounding box on the cloud path to get a close bounding box around the cloud. (Though we could hard-code this in if you need this often.) Aug 12, 2023 at 21:12
  • Is it possible to reduce size of the \AsymCloud? originally I was scaling it using ex: \AsymCloud{(3.3, 0.55)}{}{0.75}
    – alper
    Aug 14, 2023 at 16:26
  • 1
    @alper Sure. Just adjust the value \n@, say \n@={0.75*max(\x X, \y Y)}, though the cloud might clip the fitted area now. You might have to adjust the cloud drawing accordingly. Aug 14, 2023 at 17:07
2

This fits a saved tikzpicture of the cloud to a local bounding box. The problem is, you need to define inner and outer rectangles for the cloud. The inner rectangle holds the contents while the outer rectangle is used for the bounding box.

I wound up making the outer rectangle 2.2 times the size of the inner rectangle with the same center. Then all I have to do is increase the size by 2.2.

\documentclass{standalone}
\usepackage{tikz}
\usetikzlibrary{calc}
\usetikzlibrary{shapes.misc}
\usetikzlibrary{arrows,shapes,shapes.geometric,shapes.multipart}

\newsavebox{\cloud}
\savebox\cloud{\begin{tikzpicture}
    \begin{scope}[thick,draw=cyan]
        \draw (-1.6,-0.7) .. controls (-2.3,-1.1)
        and (-2.7,0.3) .. (-1.7,0.3) coordinate(asy1) .. controls (-1.6,0.7)
        and (-1.2,0.9) .. (-0.8,0.7) .. controls (-0.5,1.5)
        and (0.6,1.3) .. (0.7,0.5) .. controls (1.5,0.4)
        and (1.2,-1) .. (0.4,-0.6) coordinate(asy2) .. controls (0.2,-1)
        and (-0.2,-1) .. (-0.5,-0.7) .. controls (-0.9,-1)
        and (-1.3,-1) .. cycle;
        \path (asy1) -- (asy2);
    \end{scope}
    \pgfresetboundingbox
    %\draw (-1.4,-0.5) rectangle (0.6,0.6);% inner rectangle
    \coordinate (center) at ($(-1.4,-0.5)!0.5!(0.6,0.6)$);
    \path ($(center)!2.2!(-1.4,-0.5)$) ($(center)!2.2!(0.6,0.6)$);% outer rectangle
    %\draw[red] (current bounding box.south west) rectangle (current bounding box.north east);
\end{tikzpicture}}

\newcommand{\ACwidth}{}% reserve global names
\newcommand{\ACheight}{}

\newcommand{\AsymCloud}[1]{% #1 = target bounding box
  \begin{pgfinterruptboundingbox}
    \pgfpointdiff{\pgfpointanchor{#1}{south west}}%
      {\pgfpointanchor{#1}{north east}}%
    \pgfgetlastxy{\ACwidth}{\ACheight}%
    \global\let\ACwidth=\ACwidth
    \global\let\ACheight=\ACheight
  \end{pgfinterruptboundingbox}
  \node[inner sep=0pt] at ({#1})
   {\setlength{\dimen0}{\ACwidth}%
    \setlength{\dimen1}{\ACheight}%
    \resizebox{2.2\dimen0}{2.2\dimen1}{\usebox\cloud}};
}

\begin{document}
    \begin{tikzpicture}[%
        >=latex,shorten >=2pt,shorten <=2pt,shape aspect=1,
        arrow/.style={<->, >=stealth, semithick},
        block/.style={},
        every node/.style = {font=\scriptsize}
        ]
        \begin{scope}[local bounding box=target]
          \node[cylinder,shape border rotate=90,draw,fill=white,inner xsep=3pt] at (3.5,0.5) (A) {};
          \node[cylinder,shape border rotate=90,draw,fill=green,inner xsep=3pt,left of=A] (A') {};
        \end{scope}
        \AsymCloud{target}
        
        \begin{scope}[local bounding box=D2]
          \node[cylinder,shape border rotate=90,draw,fill=white,shape aspect=0.2] at(0.4, -0.2) (D) {};
        \end{scope}% note: D is not a rectangle
        %\draw[red] (D2.south west) rectangle (D2.north east);
        \AsymCloud{D2}
    \end{tikzpicture}

\end{document}

demo

You must log in to answer this question.

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