5

I'm still improving my answer to Need help creating a 3D cube from a 2D set of nodes in TikZ. One of the options should be to emphasize the edges of the cuboid. This would mean e.g.

\draw[red, very thick, dashed] <some coordinates>

I'm using keyval to define parameters for the cuboid. Now my quesrion is, how can I pass all these commands to a single key? I would do this:

\tikzcuboid{%
        emphedge=Y,%
        emphstyle=very thick,
    }

I can only pass one option (here very thick), as further commas (e.g. very thick, red, dashed) are interpreted as delimiters for keys by keyval. I tried several things, like

emphstyle={very thick, red, dashed}
emphstyle=style={very thick, red, dashed}
emphstyle=(very thick, red, dashed)

So my question basically is: are there some kind of special delimiters for keyval that I can put a list of comma separated arguments in? These special delimiters should however not be passed on, since this would probably cause problems with TikZ.

Tom Bombadil
  • 40,123
  • 1
    Why are you using keyval and not pgfkeys? Having two different key/value packages used together just causes troubles. You don't provide a MWE so I can't test anything, but when wrapping the comma separated list in { } doesn't protect the commas try two sets of braces, e.g. emphstyle={{very thick, red, dashed}}. One might be already removed by keyval. – Martin Scharrer Oct 04 '11 at 12:31
  • Have a look at the linked question, you find an (almost) MWE there (under Edit 3), after the definitions there are 6 examples. Thanks for the hint about double braces, I'll try that. – Tom Bombadil Oct 04 '11 at 13:02
  • Unfortunately, that did not work. And I used keyval as I had an old .tex file where I used it and thus had a starting point. To be honest, I didn't know pgfkeys existed. – Tom Bombadil Oct 04 '11 at 13:06
  • 1
    Imho one layer of braces should be enough to protect the commas in the value. So if emphstyle={very thick, red, dashed} doesn't work the problem is somewhere in the definition/processing/code of the emphstyle-key. – Ulrike Fischer Oct 04 '11 at 13:23
  • Like Martin, I prefer pgfkeys but xkeyvalis a solution because during a period, in the sources of Tikz, xkeyval and pgfkeys worked together. Now I'm not sure If xkeyval is not faster than pgfkeys. – Alain Matthes Oct 04 '11 at 14:48
  • @Altermundus: xkeyval might be faster as pgfkeys but IMHO it would be weird to not use pgfkeys for something TikZ related. – Martin Scharrer Oct 04 '11 at 18:10
  • @Martin I agree with you and I prefer pgfkeys but do not forget two arguments: the first is that many packages use xkeyval and the second is that early versions of Tikz too. Some users have become accustomed to use xkeyval to create their own packages. It's not easy to learn pgfkeys. – Alain Matthes Oct 04 '11 at 20:40

2 Answers2

7

If you'd be willing to switch to using \pgfkeys then this is quite simple. It's possible to declare a key to be an alias to a list of keys. This is done via:

\tikzset{my key/.style={list,of,other,keys}}

Then the key my key expands to list,of,other,keys in the proper way.

Here's an example of how to do it, based on your code at the linked question. I've added some spaces into the key names to make them easier (which meant that I saw some errors: you had dimy in place of dimz a couple of times). I've replaced the \ifthenelse by a boolean key. I've also condensed the line and fill keys to one single style which gives greater flexibility. You could replace the \filldraw by a simple \path for maximum flexibility here, then the grids could be filled or not filled at leisure.

Here's the code:

\documentclass[parskip]{scrartcl}
\usepackage[margin=15mm,landscape]{geometry}
\usepackage{tikz}
%====================================
%emphasize vertices --> switch and emph style (e.g. thick,black)
%====================================

\newif\ifcuboidshaded
\newif\ifcuboidemphedge

\tikzset{
  cuboid/.is family,
  cuboid,
  shift x/.initial=0,
  shift y/.initial=0,
  dim x/.initial=3,
  dim y/.initial=3,
  dim z/.initial=3,
  scale/.initial=1,
  density x/.initial=1,
  density y/.initial=1,
  density z/.initial=1,
  rotation/.initial=0,
  angle x/.initial=0,
  angle y/.initial=90,
  angle z/.initial=225,
  scale x/.initial=1,
  scale y/.initial=1,
  scale z/.initial=sqrt(0.5),
  front/.style={draw=black,fill=white},
  top/.style={draw=black,fill=white},
  right/.style={draw=black,fill=white},
  shaded/.is if=cuboidshaded,
  shade color/.initial=black,
  shade perc/.initial=25,
  emph edge/.is if=cuboidemphedge,
  emph style/.style={thick},
}

\newcommand{\tikzcuboidkey}[1]{\pgfkeysvalueof{/tikz/cuboid/#1}}

% Commands
\newcommand{\tikzcuboid}[1]{
    \tikzset{cuboid,#1} % Process Keys passed to command
    \pgfmathsetmacro{\vectorxx}{\tikzcuboidkey{scale x}*cos(\tikzcuboidkey{angle x})}
    \pgfmathsetmacro{\vectorxy}{\tikzcuboidkey{scale x}*sin(\tikzcuboidkey{angle x})}
    \pgfmathsetmacro{\vectoryx}{\tikzcuboidkey{scale y}*cos(\tikzcuboidkey{angle y})}
    \pgfmathsetmacro{\vectoryy}{\tikzcuboidkey{scale y}*sin(\tikzcuboidkey{angle y})}
    \pgfmathsetmacro{\vectorzx}{\tikzcuboidkey{scale z}*cos(\tikzcuboidkey{angle z})}
    \pgfmathsetmacro{\vectorzy}{\tikzcuboidkey{scale z}*sin(\tikzcuboidkey{angle z})}
    \begin{scope}[xshift=\tikzcuboidkey{shift x}, yshift=\tikzcuboidkey{shift y}, scale=\tikzcuboidkey{scale}, rotate=\tikzcuboidkey{rotation}, x={(\vectorxx,\vectorxy)}, y={(\vectoryx,\vectoryy)}, z={(\vectorzx,\vectorzy)}]
    \pgfmathsetmacro{\steppingx}{1/\tikzcuboidkey{density x}}
    \pgfmathsetmacro{\steppingy}{1/\tikzcuboidkey{density y}}
    \pgfmathsetmacro{\steppingz}{1/\tikzcuboidkey{density z}}
    \newcommand{\dimx}{\tikzcuboidkey{dim x}}
    \newcommand{\dimy}{\tikzcuboidkey{dim y}}
    \newcommand{\dimz}{\tikzcuboidkey{dim z}}
    \pgfmathsetmacro{\secondx}{2*\steppingx}
    \pgfmathsetmacro{\secondy}{2*\steppingy}
    \pgfmathsetmacro{\secondz}{2*\steppingz}
    \foreach \x in {\steppingx,\secondx,...,\dimx}
    {   \foreach \y in {\steppingy,\secondy,...,\dimy}
        {   \pgfmathsetmacro{\lowx}{(\x-\steppingx)}
            \pgfmathsetmacro{\lowy}{(\y-\steppingy)}
            \filldraw[cuboid/front] (\lowx,\lowy,\dimz) -- (\lowx,\y,\dimz) -- (\x,\y,\dimz) -- (\x,\lowy,\dimz) -- cycle;

        }
    }
    \foreach \x in {\steppingx,\secondx,...,\dimx}
    {   \foreach \z in {\steppingz,\secondz,...,\dimz}
        {   \pgfmathsetmacro{\lowx}{(\x-\steppingx)}
            \pgfmathsetmacro{\lowz}{(\z-\steppingz)}
            \filldraw[cuboid/top] (\lowx,\dimy,\lowz) -- (\lowx,\dimy,\z) -- (\x,\dimy,\z) -- (\x,\dimy,\lowz) -- cycle;
        }
    }
    \foreach \y in {\steppingy,\secondy,...,\dimy}
    {   \foreach \z in {\steppingz,\secondz,...,\dimz}
        {   \pgfmathsetmacro{\lowy}{(\y-\steppingy)}
            \pgfmathsetmacro{\lowz}{(\z-\steppingz)}
            \filldraw[cuboid/right] (\dimx,\lowy,\lowz) -- (\dimx,\lowy,\z) -- (\dimx,\y,\z) -- (\dimx,\y,\lowz) -- cycle;
        }
    }
    \ifcuboidemphedge
        \draw[cuboid/emph style] (0,\dimy,0) -- (\dimx,\dimy,0) -- (\dimx,\dimy,\dimz) -- (0,\dimy,\dimz) -- cycle;%
        \draw[cuboid/emph style] (0,\dimy,\dimz) -- (0,0,\dimz) -- (\dimx,0,\dimz) -- (\dimx,\dimy,\dimz);%
        \draw[cuboid/emph style] (\dimx,\dimy,0) -- (\dimx,0,0) -- (\dimx,0,\dimz);%
    \fi
    \end{scope}
}

\makeatother

\begin{document}

\begin{tikzpicture}
    \tikzcuboid{shift x=0cm,%
        shift y=0cm,%
        scale=1.00,%
        rotation=30,%
        density x=1,%
        density y=2,%
        density z=3,%
        dim x=4,%
        dim y=5,%
        dim z=2,%
        front/.style={draw=yellow!30!black,fill=yellow!30!white},%
        top/.style={draw=red!30!black,fill=red!30!white},%
        right/.style={draw=blue!30!black,fill=blue!30!white}%
    }
    \tikzcuboid{%
        shift x=0cm,%
        shift y=8cm,%
        scale=1.00,%
        rotation=60,%
        density x=3,%
        density y=2,%
        density z=5,%
        dim x=4,%
        dim y=4,%
        dim z=4,%
        front/.style={draw=orange!75!black,fill=orange!75!white},%
        top/.style={draw=green!75!black,fill=green!75!white},%
        right/.style={draw=violet!75!black,fill=violet!75!white}%
    }
    \tikzcuboid{%
        shift x=8cm,%
        shift y=8cm,%
        scale=1.00,%
        rotation=45,%
        density x=1,%
        density y=(2/3),%
        density z=2,%
        dim x=3,%
        dim y=3,%
        dim y=3,%
        front/.style={draw=white!15!black,fill=black!15!white},%
        top/.style={draw=white!30!black,fill=black!30!white},%
        right/.style={draw=white!45!black,fill=black!45!white}%
    }
    \tikzcuboid{%
        shift x=8cm,%
        shift y=0cm,%
        scale=1.00,%
        rotation=75,%
        density x=2,%
        density y=3,%
        density z=2,%
        dim x=6,%
        dim y=8,%
        dim z=1,%
        front/.style={draw=red!75!black,fill=red!25!white},%
        top/.style={draw=red!50!black,fill=red!50!white},%
        right/.style={draw=red!25!black,fill=red!75!white}%
    }
    \tikzcuboid{%
        shift x=16cm,%
        shift y=8cm,%
        scale=1.00,%
        rotation=0,%
        density x=2,%
        density y=2,%
        density z=2,%
        dim x=4,%
        dim y=4,%
        dim y=4,%
        front/.style={draw=green!75!black,fill=green!25!white},%
        top/.style={draw=green!50!black,fill=green!50!white},%
        right/.style={draw=green!25!black,fill=green!75!white},%
        emph edge,%
        emph style/.style={very thick},
    }
    \tikzcuboid{%
        shift x=16cm,%
        shift y=0cm,%
        scale=1.00,%
        rotation=0,%
        density x=1,%
        density y=1,%
        density z=1,%
        dim x=4,%
        dim y=4,%
        dim z=4,%
        front/.style={draw=blue!75!black,fill=blue!25!white},%
        right/.style={draw=blue!25!black,fill=blue!75!white},%
        top/.style={draw=blue!50!black,fill=blue!50!white},%
        angle x=15,%
        angle y=135,%
        angle z=225,%
        scale x=1,%
        scale y=1,%
        scale z=1,%
        emph edge=false,%
    }
\end{tikzpicture}

\end{document}
Tom Bombadil
  • 40,123
Andrew Stacey
  • 153,724
  • 43
  • 389
  • 751
  • Hey, thanks for the effort, it works fine. I think I'll switch to pgfkeys, however I will still write keys as dimx (things like verythick instead of very thick constantly break my neck, I really don't like spaces in keys or variables). I also spotted the errors in the other post, I will correct them with my next edit. I'm sorry I can award only one "accepted answer", yours would deserve it as well – Tom Bombadil Oct 04 '11 at 21:28
  • Oh, and as I pointed out below Altermundus' post, drawing three cycles for emphasizing is only fine for slid lines, but not for e.g. dashed ones, so I changed it there. – Tom Bombadil Oct 04 '11 at 21:36
  • As an alternative to the spaces, you could define them hierarchically. Then you have a directory called dim with three subkeys dim/x, dim/y, and dim/z. (I'm not saying you should do this, just saying that it's possible.) – Andrew Stacey Oct 05 '11 at 08:42
  • And as penance for not accepting my answer, you should make a proper package out of your code and upload it to CTAN. – Andrew Stacey Oct 05 '11 at 08:42
  • Okay, will do :D – Tom Bombadil Oct 05 '11 at 11:07
5

To protect the commas in your code you can do this

\ifthenelse{\equal{\tikzcuboid@emphedge}{Y}}%
    {\protected@edef\cube@temp{%
\noexpand\draw[\tikzcuboid@emphstyle](0,\dimy,0) -- (\dimx,\dimy,0) -- (\dimx,\dimy,\dimz) -- (0,\dimy,\dimz) -- cycle;     
\noexpand\draw[\tikzcuboid@emphstyle] (0,\dimy,\dimz) -- (0,0,\dimz) -- (\dimx,0,\dimz) -- (\dimx,\dimy,\dimz);
\noexpand\draw[\tikzcuboid@emphstyle](\dimx,\dimy,0) -- (\dimx,0,0) -- (\dimx,0,\dimz);
      }\cube@temp   
    }%
    {}

the result with

\tikzcuboid{%
    shiftx=16cm,%
    shifty=8cm,%
    scale=1.00,%
    rotation=0,%
    densityx=2,%
    densityy=2,%
    densityz=2,%
    dimx=4,%
    dimy=4,%
    dimy=4,%
    linefront=green!75!black,%
    linetop=green!50!black,%
    lineright=green!25!black,%
    fillfront=green!25!white,%
    filltop=green!50!white,%
    fillright=green!75!white,%
    emphedge=Y,%
    emphstyle={very thick, red, dashed}
} 

and the picture

enter image description here

Tom Bombadil
  • 40,123
Alain Matthes
  • 95,075
  • Nice, it works! However, you wrote the dirst \draw twice. Furthermore I noticed that drawing three cycles is not good, as e.g. dashed lines are overwritten, my bad. So I'll take the liberty to edit your post. – Tom Bombadil Oct 04 '11 at 21:07
  • @Tom: no problem for the code ! – Alain Matthes Oct 05 '11 at 03:50