4

I'm trying something experimental for a bigger project. (I don't know where to start though) I'm looking to write some macros that help me generate something like this

what I would like to end up with

based on the following code (syntax is not final, so changes possible).

\documentclass{article}
\usepackage[utf8]{inputenc}

\usepackage{tikz}

\begin{document}
\begin{figure}
\begin{tikzpicture}
    \tikzset{
        entity/.style={
            rectangle,
            draw
        },
        port/.style={
            draw,
            rectangle,
            minimum height=1cm,
            minimum width=1cm
        }
    }

    \node[draw,rectangle,minimum width=8cm,minimum height=4.5cm] (parent) {
        parent
        \node[port,west] {A};
        \node[port,west] {B};
        \node[port,west] {C};
        \node[port,east] {D};
        \node[port,east] {E};

        \node[entity,minimum width=5cm,minimum height=2cm] (subentity-1) {
            subentity-1
            \node[port,west] {1};
            \node[port,east] {2};
        }
        \node[entity,minimum width=5cm,minimum height=2cm] (subentity-2) {
            subentity-2
            \node[port,west] {1};
            \node[port,east] {2};
        }
    };
\end{tikzpicture}
\end{figure}

\end{document}

The things I am struggling with:

  • nodes inside nodes (entity nesting)

    How can I define one entity within another entity? (Perhaps several levels deep).

  • node nesting (and positioning west and east)

    If I place a port inside an entity, can I discover the parent-entity (i.e. the one that contains it) and position it at parent.east or parent.west accordingly?

  • distributing all port nodes evenly along the west (or east) edge

    I would like to calculate the height of the parent-entity and then spread the ports within that entity along the edge.

A simple algorithm in pseudo-code would look like this:

parent = this.parent
height = parent.minimum height
westports = parent.get-children().filter('west')
for idx, port in westports:
    offset = height/count(westports) * idx
    port.position = parent.north west - offset

Good pointers to existing questions/answers welcome. (I didn't find anything useful, mostly because I didn't know what to look for)

Edit: added clarifications to my problems.

Disclaimer: Accepted answer does not answer the questions above, but provides a valid solution to my problem.

  • Look at the fit library .... – cfr Nov 12 '17 at 23:54
6

EDIT: Automate Version

I created three commands \createBox, \subBox and \smallBox to create the big entity rectangle, the nodes inside nodes (subentity) and small port nodes, which could be placed on the lines.

  • createBox:

\createBox{<minimum width[cm]>}{<minimum height[cm]>}{<name>}{<text inside>}{<color>}

  • subBox:

\subBox{<minimum width [cm]>}{<minimum height[cm]>}{<xshift[cm]>}{<yshift[cm]>}{<node name>}{<node anchor name>}{<text inside>}{<color>}

Note: <xshift[cm]> and <yshift[cm]> in relation to <node anchor name>.center.

  • smallBox:

\smallBox{<node anchor name>}{<angle/position>}{<text inside>}{<color>}

Note: Node position: node anchor name.〈angle〉, angle between 0 (=east) and 360, measured counterclockwise. <xshift[cm]> and <yshift[cm]> in relation to <node anchor name>.center.

enter image description here

MWE: Version 2(auto)

\documentclass[border=10pt]{standalone}
\usepackage{tikz}
\usetikzlibrary{positioning,calc}
    \tikzset{
        entity/.style={
            rectangle,
            draw
        },
        port/.style={
            draw,
            rectangle,
            minimum height=1cm,
            minimum width=1cm
        },
        box/.style={draw,minimum width=0.5cm,minimum height=0.5cm,align=center,fill=white}   
    }

\newcommand{\createBox}[5]
{    
\node[#5,entity,minimum width=#1 cm,minimum height=#2 cm](#3) {#4};
}

\newcommand{\subBox}[8]
{    
\node[#8,port,minimum width=#1 cm,minimum height=#2 cm,xshift = #3 cm ,yshift = #4 cm](#5) at (#6.center) {#7};
}

\newcommand{\smallBox}[4]
{    
\node[#4,box] at (#1.#2) {#3};
}

\begin{document}
\begin{tikzpicture}

\createBox{6.5}{3.5}{Box_A}{My Box: A}{red}
\smallBox{Box_A}{165}{A}{blue}
\smallBox{Box_A}{180}{B}{blue}
\smallBox{Box_A}{195}{C}{blue}
\smallBox{Box_A}{10}{D}{blue}
\smallBox{Box_A}{-10}{E}{blue}

\subBox{3}{0.75}{0}{1}{Sub_Box_1}{Box_A}{My subbox: 1}{green}
\smallBox{Sub_Box_1}{0}{2}{blue}
\smallBox{Sub_Box_1}{180}{1}{blue}

\subBox{3}{0.75}{0}{-1}{Sub_Box_2}{Box_A}{My subbox: 2}{orange}
\smallBox{Sub_Box_2}{0}{2}{blue}
\smallBox{Sub_Box_2}{180}{1}{blue}
\end{tikzpicture}      

\end{document}


First Answer: Basic

Basicly you could use \usetikzlibrary{positioning} and \usetikzlibrary{calc} for positioning.

enter image description here

MWE: Version 1

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{positioning}
\usetikzlibrary{calc}
\begin{document}

\begin{tikzpicture}
    \tikzset{
        entity/.style={
            rectangle,
            draw
        },
        port/.style={
            draw,
            rectangle,
            minimum height=1cm,
            minimum width=1cm
        }
    }

\node[port](A) {A};
\node[port,below= 0.5cm of A](B) {B};
\node[port,below= 0.5cm of B](C) {C};
\node[port,right= 1cm of A](A1) {a1};
\node[port,right= 2cm of A1](A2) {a2};
\node[port,right= 1cm of C,yshift=0.3cm](C1) {c1};
\node[port,right= 2cm of C1](C2) {c2};
\node[port,right= 1cm of A2,yshift=-0.2cm](D) {D};
\node[port,right= 1cm of C2,yshift=0.2cm](E) {E};

\draw (A1.north) |- + (3,0.5) |- (A2.north);
\draw (A1.south) |- + (3,-0.5) |- (A2.south);

\node (S1) at ($(A1)!0.5!(A2)$) {subentity-1};

\draw (C1.north) |- + (3,0.5) |- (C2.north);
\draw (C1.south) |- + (3,-0.5) |- (C2.south);

\node (S2) at ($(C1)!0.5!(C2)$) {subentity-2};

\node (Ec) at ($(S1)!0.5!(S2)$) {entity};

\draw (A.north) |- + (7,1) |- (D.north);
\draw (A.south) -- (B.north);
\draw (B.south) -- (C.north);
\draw (C.south) |- + (7,-1) |- (E.south);
\draw (D.south) -- (E.north);
\end{tikzpicture}

\end{document}
  • @S.K. : So now you like to see some macros to automate the creating process? – Bobyandbob Nov 12 '17 at 22:30
  • Yes, the plan would be to automate it. My idea was to draw a rectangle and place the ports "inside". the horizontal position would be parent.west or parent.east (if I manage to figure out how to get parent). Vertical position is defined by iterating over e.g. the west nodes within an entity and calculating parent.north west + (parent.north - parent.south)/(count nodes with west`) * iteration index (I hope this explains it) – stklik Nov 12 '17 at 22:55
  • This is awesome! The positioning via angle is more hardcoded than I first described, but works as well. – stklik Nov 13 '17 at 8:59
  • @S.K. : You are right its an alternative way. I'm not sure about your input parameters of your pseudo-code. If you find an better way, please provide it as an new answer to help everyone here. You are welcome. – Bobyandbob Nov 13 '17 at 9:17

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.