6

A while back I asked some help to find an easy way to draw some component diagrams with TIkZ. The answer was awesome, but when adaption the solution to my case, I ended up copy-pasting the same code several times.

Here is a part of the code (without all the copy-pasted code).

\definecolor{darkgreen}{rgb}{0.18,0.54,0.34}
\tikzset{
    component/.style={
        rectangle,
        rounded corners=0.35cm,
        fill=green!50!black,
        minimum width=2.5cm,
        minimum height=1.5cm,
        drop shadow
    },
    composite/.style={
        component,
        fill=green!12,
        inner sep=0.5cm
    },
    corba/.style={thick,darkgreen},
    u/.style={draw,circle,minimum size=6mm,outer sep=0pt},
    p/.style={draw,circle,minimum size=4.5mm,outer sep=0pt},
    urec/.style={draw,rectangle,minimum size=6mm,outer sep=0pt},
    prec/.style={draw,rectangle,minimum size=4.5mm,outer sep=0pt},
    utri/.style={draw,regular polygon,regular polygon sides=3,shape border rotate=-30,minimum size=6mm,outer sep=0pt},
    ptri/.style={draw,regular polygon,regular polygon sides=3,shape border rotate=-30,minimum size=4.5mm,outer sep=0pt,inner sep=0pt},
    stick port/.style={inner sep=0},
    % Balls shapes
    ueast/.style 2 args={
        stick port,
        append after command={
            \pgfextra
                \begin{scope}
                    \clip ([yshift={#1+4mm}]\tikzlastnode.east) rectangle ++(1cm,-8mm);
                    \draw ([yshift=#1]\tikzlastnode.east) -- ++(0:6.8mm) node[u,anchor=west] (\tikzlastnode-#2) {};
                \end{scope}
            \endpgfextra
        }
    },
    ueast/.default={0mm}{ueast},
    uwest/.style 2 args={
        stick port,
        append after command={
            \pgfextra
                \begin{scope}
                    \clip ([yshift={#1+4mm}]\tikzlastnode.west) rectangle ++(-1cm,-8mm);
                    \draw ([yshift=#1]\tikzlastnode.west) -- ++(180:6.8mm) node[u,anchor=east] (\tikzlastnode-#2) {};
                \end{scope}
            \endpgfextra
        }
    },
    uwest/.default={0mm}{uwest},
    unorth/.style 2 args={
        stick port,
        append after command={
            \pgfextra
                \begin{scope}
                    \clip ([xshift={#1+4mm}]\tikzlastnode.north) rectangle ++(-8mm,1cm);
                    \draw ([xshift=#1]\tikzlastnode.north) -- ++(90:6.8mm) node[u,anchor=south] (\tikzlastnode-#2) {};
                \end{scope}
            \endpgfextra
        }
    },
    unorth/.default={0mm}{unorth},
    usouth/.style 2 args={
        stick port,
        append after command={
            \pgfextra
                \begin{scope}
                    \clip ([xshift={#1+4mm}]\tikzlastnode.south) rectangle ++(-8mm,-1cm);
                    \draw ([xshift=#1]\tikzlastnode.south) -- ++(-90:6.8mm) node[u,anchor=north] (\tikzlastnode-#2) {};
                \end{scope}
            \endpgfextra
        }
    },
    usouth/.default={0mm}{usouth},
    peast/.style 2 args={
        stick port,
        append after command={
            \pgfextra
                \draw ([yshift=#1]\tikzlastnode.east) -- ++(0:7.75mm) node[p,anchor=west] (\tikzlastnode-#2) {};
            \endpgfextra
        }
    },
    peast/.default={0mm}{peast},
    pwest/.style 2 args={
        stick port,
        append after command={
            \pgfextra
                \draw ([yshift=#1]\tikzlastnode.west) -- ++(180:7.75mm) node[p,anchor=east] (\tikzlastnode-#2) {};
            \endpgfextra
        }
    },
    pwest/.default={0mm}{pwest},
    pnorth/.style 2 args={
        stick port,
        append after command={
            \pgfextra
                \draw ([xshift=#1]\tikzlastnode.north) -- ++(90:7.75mm) node[p,anchor=south] (\tikzlastnode-#2) {};
            \endpgfextra
        }
    },
    pnorth/.default={0mm}{pnorth},
    psouth/.style 2 args={
        stick port,
        append after command={
            \pgfextra
                \draw ([xshift=#1]\tikzlastnode.south) -- ++(-90:7.75mm) node[p,anchor=north] (\tikzlastnode-#2) {};
            \endpgfextra
        }
    },
    psouth/.default={0mm}{psouth},
    % CORBA shapes
    ueastcorba/.style 2 args={
        stick port,
        append after command={
            \pgfextra
                \begin{scope}
                    \clip ([yshift={#1+4mm}]\tikzlastnode.east) rectangle ++(1cm,-8mm);
                    \draw [corba] ([yshift=#1]\tikzlastnode.east) -- ++(0:6.8mm) node[u,anchor=west] (\tikzlastnode-#2) {};
                \end{scope}
            \endpgfextra
        }
    },
    ueastcorba/.default={0mm}{ueast},
    % [...] same for uwestcorba, unorthcorba, usouthcorba, peastcorba, pwestcorba, pnorthcorba, psouthcorba
    % Rectangle shapes
    ureceast/.style 2 args={
        stick port,
        append after command={
            \pgfextra
                \begin{scope}
                    \clip ([yshift={#1+4mm}]\tikzlastnode.east) rectangle ++(1.15cm,-8mm);
                    \draw ([yshift=#1]\tikzlastnode.east) -- ++(0:6.8mm) node[urec,anchor=west] (\tikzlastnode-#2) {};
                \end{scope}
            \endpgfextra
        }
    },
    ureceast/.default={0mm}{ueast},
    % [...] same for urecwest, urecnorth, urecsouth, preceast, precwest, precnorth, precsouth
    % Triangle shapes
    utrieast/.style 2 args={
        stick port,
        append after command={
            \pgfextra
                \begin{scope}
                    \clip ([yshift={#1+4mm}]\tikzlastnode.east) rectangle ++(1.15cm,-8mm);
                    \draw ([yshift=#1]\tikzlastnode.east) -- ++(0:6.8mm) node[utri,anchor=west] (\tikzlastnode-#2) {};
                \end{scope}
            \endpgfextra
        }
    },
    utrieast/.default={0mm}{uwest},
    % [...] same for utriwest, utrinorth, utrisouth, ptrieast, ptriwest, ptrinorth, ptrisouth
}

The styles ueast, uwest, unorth, usouth defines the use port to draw on every side of the component they're attached. The styles peast, pwest, pnorth, psouth define the provide ports. And there are 4 variations of them.

The plain one that draw black circles / half-circles.

Circle ports

One that draw thick green circles / half circles.

Green thick circles

One that draw triangles as ports (not cut in half and shapes rotated).

Triangle ports

One that draw squares (not cut in half).

Square ports

So it's 4 variations of 8 styles, which makes 32 very similar TIkZ styles.

Is there a way to write those styles more concisely? Possibily without using macros to generate the code. Ideally, it would rotate automagically the port.

I can include the missing code if needed.

  • 2
    write a macro that the style specifications as arguments – Herr K. Feb 19 '15 at 21:19
  • With @KevinC's suggestion, don't forget to double-up the parameter specifications in the macro itself. E.g \newcommand\thing[1]{something that's different: #1 \tikzsetstylestuff{blah blah = blah ##1}} – Sean Allred Feb 19 '15 at 21:22
  • 2
    Please make your code compilable i.e. a complete, small document. We don't need the other cases of the styles, but being able to copy-paste-compile is useful both to people trying to help (easier to help), you (more likely to get help), and users who aren't able to help (can learn easily from your example). – cfr Feb 20 '15 at 0:17
2

The code has been reduced to four styles xeast, xwest, xnorth and xsouth, each one with 6 parameters, a sufix, possible shifting, color, border rotation, kind of port and port (long|middle)-open or closed. All original styles are just a particular case for these new ones.

A better solution could be trying to build something similar to label but I don't know how to do it.

\documentclass[tikz,border=2mm]{standalone}
\usetikzlibrary{positioning,shadows,shapes.geometric}
\usepackage{siunitx}

\begin{document}

\definecolor{darkgreen}{rgb}{0.18,0.54,0.34}
\tikzset{
    component/.style={
        rectangle,
        rounded corners=0.35cm,
        fill=green!50!black,
        minimum width=2.5cm,
        minimum height=1.5cm,
        drop shadow
    },
    composite/.style={
        component,
        fill=green!12,
        inner sep=0.5cm
    },
    corba/.style={thick,darkgreen},
    u/.style={draw,circle,minimum size=6mm,outer sep=0pt},
    p/.style={draw,circle,minimum size=4.5mm,outer sep=0pt},
    urec/.style={draw,rectangle,minimum size=6mm,outer sep=0pt},
    prec/.style={draw,rectangle,minimum size=4.5mm,outer sep=0pt},
    utri/.style={draw,regular polygon,regular polygon sides=3,shape border rotate=-30,minimum size=6mm,outer sep=0pt},
    ptri/.style={draw,regular polygon,regular polygon sides=3,shape border rotate=-30,minimum size=5.25mm,outer sep=0pt,inner sep=0pt},
    stick port/.style={inner sep=0},
    %Nou
    xeast/.style n args={6}{
% #1 - shift distance
% #2 - name sufix
% #3 - kind of port (u,rec,tri)
% #4 - color
% #5 - closed (0) /middle clipped port (1)/long clipped port (2)
% #6 - shape border rotate angle
        stick port,
        append after command={
            \pgfextra
                \begin{scope}
                    \ifnum#5=1
                    \clip ([yshift={#1+4mm}]\tikzlastnode.east) rectangle ++(1cm,-8mm);
                    \else
                     \ifnum#5=2
                    \clip ([yshift={#1+4mm}]\tikzlastnode.east) rectangle ++(1.15cm,-8mm);
                    \fi\fi
                    \draw[#4] ([yshift=#1]\tikzlastnode.east) -- ++(0:6.8mm) node[#3,anchor=west,#6] (\tikzlastnode-#3#2) {};
                \end{scope}
            \endpgfextra
        }
    },
    xwest/.style n args={6}{
% #1 - shift distance
% #2 - name sufix
% #3 - kind of port (u,rec,tri)
% #4 - color
% #5 - closed (0) /clipped port (1)
% #6 - shape border rotate angle
        stick port,
        append after command={
            \pgfextra
                \begin{scope}
                    \ifnum#5=1
                    \clip ([yshift={#1+4mm}]\tikzlastnode.west) rectangle ++(-1cm,-8mm);
                    \else
                    \ifnum#5=2
                    \clip ([yshift={#1+4mm}]\tikzlastnode.west) rectangle ++(-1.15cm,-8mm);
                    \fi\fi
                    \draw[#4] ([yshift=#1]\tikzlastnode.west) -- ++(180:6.8mm) node[#3,anchor=east,#6] (\tikzlastnode-#3#2) {};
                \end{scope}
            \endpgfextra
        }
    },
    xnorth/.style n args={6}{
% #1 - shift distance
% #2 - name sufix
% #3 - kind of port (u,rec,tri)
% #4 - color
% #5 - closed (0) /clipped port (1)
% #6 - shape border rotate angle
        stick port,
        append after command={
            \pgfextra
                \begin{scope}
                    \ifnum#5=1
                    \clip ([xshift={#1+4mm}]\tikzlastnode.north) rectangle ++(-8mm,1cm);
                    \else
                    \ifnum#5=2
                    \clip ([xshift={#1+4mm}]\tikzlastnode.north) rectangle ++(-8mm,1.15cm);
                    \fi\fi
                    \draw[#4] ([xshift=#1]\tikzlastnode.north) -- ++(90:6.8mm) node[#3,anchor=south,#6] (\tikzlastnode-#3#2) {};
                \end{scope}
            \endpgfextra
        }
    },
    xsouth/.style n args={6}{
% #1 - shift distance
% #2 - name sufix
% #3 - kind of port (u,rec,tri)
% #4 - color
% #5 - closed (0) /clipped port (1)
% #6 - shape border rotate angle
        stick port,
        append after command={
            \pgfextra
                \begin{scope}
                    \ifnum#5=1
                    \clip ([xshift={#1+4mm}]\tikzlastnode.south) rectangle ++(-8mm,-1cm);
                    \else
                    \ifnum#5=2
                    \clip ([xshift={#1+4mm}]\tikzlastnode.south) rectangle ++(-8mm,-1.15cm);
                    \fi\fi
                    \draw[#4] ([xshift=#1]\tikzlastnode.south) -- ++(-90:6.8mm) node[#3,anchor=north,#6] (\tikzlastnode-#3#2) {};
                \end{scope}
            \endpgfextra
        }
    },
    ueast/.style 2 args={xeast={#1}{#2}{u}{}{1}{}},
    ueast/.default={0mm}{ueast},
    peast/.style 2 args={xeast={#1}{#2}{p}{}{0}{}},
    peast/.default={0mm}{peast},
    ueastcorba/.style 2 args={xeast={#1}{#2}{u}{corba}{1}{}},
    ueastcorba/.default={0mm}{ueast},
    peastcorba/.style 2 args={xeast={#1}{#2}{p}{corba}{0}{}},
    peastcorba/.default={0mm}{peast},
    ureceast/.style 2 args={xeast={#1}{#2}{urec}{}{2}{}},
    ureceast/.default={0mm}{ueast},
    preceast/.style 2 args={xeast={#1}{#2}{prec}{}{0}{}},
    preceast/.default={0mm}{peast},
    utrieast/.style 2 args={xeast={#1}{#2}{utri}{}{2}{shape border rotate=90}},
    utrieast/.default={0mm}{ueast},
    ptrieast/.style 2 args={xeast={#1}{#2}{ptri}{}{0}{shape border rotate=30}},
    ptrieast/.default={0mm}{peast},
    uwest/.style 2 args={xwest={#1}{#2}{u}{}{1}{}},
    uwest/.default={0mm}{uwest},
    pwest/.style 2 args={xwest={#1}{#2}{p}{}{0}{}},
    pwest/.default={0mm}{pwest},
    uwestcorba/.style 2 args={xwest={#1}{#2}{u}{corba}{1}{}},
    uwestcorba/.default={0mm}{uwest},
    pwestcorba/.style 2 args={xwest={#1}{#2}{p}{corba}{0}{}},
    pwestcorba/.default={0mm}{pwest},
    urecwest/.style 2 args={xwest={#1}{#2}{urec}{}{2}{}},
    urecwest/.default={0mm}{uwest},
    precwest/.style 2 args={xwest={#1}{#2}{prec}{}{0}{}},
    precwest/.default={0mm}{pwest},
    utriwest/.style 2 args={xwest={#1}{#2}{utri}{}{2}{shape border rotate=30}},
    utriwest/.default={0mm}{uwest},
    ptriwest/.style 2 args={xwest={#1}{#2}{ptri}{}{0}{}},
    ptriwest/.default={0mm}{pwest},
    unorth/.style 2 args={xnorth={#1}{#2}{u}{}{1}{}},
    unorth/.default={0mm}{unorth},
    pnorth/.style 2 args={xnorth={#1}{#2}{p}{}{0}{}},
    pnorth/.default={0mm}{pnorth},
    unorthcorba/.style 2 args={xnorth={#1}{#2}{u}{corba}{1}{}},
    unorthcorba/.default={0mm}{unorth},
    pnorthcorba/.style 2 args={xnorth={#1}{#2}{p}{corba}{0}{}},
    pnorthcorba/.default={0mm}{pnorth},
    urecnorth/.style 2 args={xnorth={#1}{#2}{urec}{}{2}{}},
    urecnorth/.default={0mm}{unorth},
    precnorth/.style 2 args={xnorth={#1}{#2}{prec}{}{0}{}},
    precnorth/.default={0mm}{pnorth},
    utrinorth/.style 2 args={xnorth={#1}{#2}{utri}{}{2}{shape border rotate=60}},
    utrinorth/.default={0mm}{unorth},
    ptrinorth/.style 2 args={xnorth={#1}{#2}{ptri}{}{0}{shape border rotate=0}},
    ptrinorth/.default={0mm}{pnorth},
    usouth/.style 2 args={xsouth={#1}{#2}{u}{}{1}{}},
    usouth/.default={0mm}{usouth},
    psouth/.style 2 args={xsouth={#1}{#2}{p}{}{0}{}},
    psouth/.default={0mm}{psouth},
    usouthcorba/.style 2 args={xsouth={#1}{#2}{u}{corba}{1}{}},
    usouthcorba/.default={0mm}{usouth},
    psouthcorba/.style 2 args={xsouth={#1}{#2}{p}{corba}{0}{}},
    psouthcorba/.default={0mm}{psouth},
    urecsouth/.style 2 args={xsouth={#1}{#2}{urec}{}{2}{}},
    urecsouth/.default={0mm}{usouth},
    precsouth/.style 2 args={xsouth={#1}{#2}{prec}{}{0}{}},
    precsouth/.default={0mm}{psouth},
    utrisouth/.style 2 args={xsouth={#1}{#2}{utri}{}{2}{shape border rotate=0}},
    utrisouth/.default={0mm}{usouth},
    ptrisouth/.style 2 args={xsouth={#1}{#2}{ptri}{}{0}{shape border rotate=60}},
    ptrisouth/.default={0mm}{psouth},    
}

\begin{tikzpicture}
\node[component, 
    utrieast={4mm}{a}, preceast={-4mm}{b}, 
    urecnorth={4mm}{c}, ptrinorth={-4mm}{d},
    utriwest={4mm}{d},precwest={-4mm}{e}] (A) {A};
\node[component, 
    ptriwest={4mm}{a}, urecwest={-4mm}{b}, 
    unorth={4mm}{c},pnorthcorba={-4mm}{d},
    ptrieast={4mm}{c},preceast={-4mm}{d}, right=19mm of A] (B) {B};

\node[component, 
    ueastcorba={4mm}{a}, peast={-4mm}{b}, 
    utrisouth={-4mm}{c}, precsouth={4mm}{d}, above=19mm of A] (C) {C};
\node[component, 
    uwest={-4mm}{a}, pwestcorba={4mm}{b}, 
    usouthcorba={-4mm}{c},psouth={4mm}{d}, above=19mm of B] (D) {D};

\end{tikzpicture}
\end{document}

enter image description here

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.