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.

1
  • Look at the fit library ....
    – cfr
    Commented Nov 12, 2017 at 23:54

1 Answer 1

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}
4
  • @S.K. : So now you like to see some macros to automate the creating process?
    – Bobyandbob
    Commented Nov 12, 2017 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
    Commented Nov 12, 2017 at 22:55
  • This is awesome! The positioning via angle is more hardcoded than I first described, but works as well.
    – stklik
    Commented Nov 13, 2017 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
    Commented Nov 13, 2017 at 9:17

You must log in to answer this question.

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