37

This is my minimal example:

\documentclass{article} 
\usepackage{tikz} 
\begin{document} 
   \begin{tikzpicture}
           \node[rounded corners=3pt, draw, fill=red!20]{Hallo!};
   \end{tikzpicture}
\end{document}

I'd like to define different values for rounded corners (i.e. 5pt for north-west and north-east and 2pt for south-east and south-west).

3

2 Answers 2

40

The Tikz manual gives an example for this on page 588. This is just for drawing a rectangle with your specs though. We need to declare a shape, so that Tikz can use it as a node. This is what the code below does. The shape creation is explained in chapter 75 of the manual and some nice examples are given.

\documentclass{article}
\usepackage{tikz}
\begin{document}
\makeatletter
\pgfdeclareshape{myNode}{
  \inheritsavedanchors[from=rectangle] % this is nearly a rectangle
  \inheritanchorborder[from=rectangle]
  \inheritanchor[from=rectangle]{center}
  \inheritanchor[from=rectangle]{north}
  \inheritanchor[from=rectangle]{south}
  \inheritanchor[from=rectangle]{west}
  \inheritanchor[from=rectangle]{east}
  \backgroundpath{% this is new
    % store lower right in xa/ya and upper right in xb/yb
    \southwest \pgf@xa=\pgf@x \pgf@ya=\pgf@y
    \northeast \pgf@xb=\pgf@x \pgf@yb=\pgf@y
    % construct main path
    \pgfsetcornersarced{\pgfpoint{5pt}{5pt}}
    \pgfpathmoveto{\pgfpoint{\pgf@xa}{\pgf@ya}}
    \pgfpathlineto{\pgfpoint{\pgf@xa}{\pgf@yb}}
    \pgfpathlineto{\pgfpoint{\pgf@xb}{\pgf@yb}}
    \pgfsetcornersarced{\pgfpoint{2pt}{2pt}}
    \pgfpathlineto{\pgfpoint{\pgf@xb}{\pgf@ya}}
    \pgfpathclose
 }
}
\makeatother
\begin{tikzpicture}
  \node[draw,shape=myNode] {Long piece of text};
\end{tikzpicture}
\end{document}

The resulting node looks like this:

Node with differenly rounded corners

Perhaps there is an easier way, I am not aware of it though.

Edit: (added by Andrew Stacey). Making it possible to customise the amount that the corners are rounded is straightforward. The following code is a simple adaptation of the above to do this (note that I changed the node name; as "rounded rectangle" is already taken, I had to pick something else).

\documentclass{article}
\usepackage{tikz}
\begin{document}
\tikzset{
  rectangle with rounded corners north west/.initial=4pt,
  rectangle with rounded corners south west/.initial=4pt,
  rectangle with rounded corners north east/.initial=4pt,
  rectangle with rounded corners south east/.initial=4pt,
}
\makeatletter
\pgfdeclareshape{rectangle with rounded corners}{
  \inheritsavedanchors[from=rectangle] % this is nearly a rectangle
  \inheritanchorborder[from=rectangle]
  \inheritanchor[from=rectangle]{center}
  \inheritanchor[from=rectangle]{north}
  \inheritanchor[from=rectangle]{south}
  \inheritanchor[from=rectangle]{west}
  \inheritanchor[from=rectangle]{east}
  \inheritanchor[from=rectangle]{north east}
  \inheritanchor[from=rectangle]{south east}
  \inheritanchor[from=rectangle]{north west}
  \inheritanchor[from=rectangle]{south west}
  \backgroundpath{% this is new
    % store lower right in xa/ya and upper right in xb/yb
    \southwest \pgf@xa=\pgf@x \pgf@ya=\pgf@y
    \northeast \pgf@xb=\pgf@x \pgf@yb=\pgf@y
    % construct main path
    \pgfkeysgetvalue{/tikz/rectangle with rounded corners north west}{\pgf@rectc}
    \pgfsetcornersarced{\pgfpoint{\pgf@rectc}{\pgf@rectc}}
    \pgfpathmoveto{\pgfpoint{\pgf@xa}{\pgf@ya}}
    \pgfpathlineto{\pgfpoint{\pgf@xa}{\pgf@yb}}
    \pgfkeysgetvalue{/tikz/rectangle with rounded corners north east}{\pgf@rectc}
    \pgfsetcornersarced{\pgfpoint{\pgf@rectc}{\pgf@rectc}}
    \pgfpathlineto{\pgfpoint{\pgf@xb}{\pgf@yb}}
    \pgfkeysgetvalue{/tikz/rectangle with rounded corners south east}{\pgf@rectc}
    \pgfsetcornersarced{\pgfpoint{\pgf@rectc}{\pgf@rectc}}
    \pgfpathlineto{\pgfpoint{\pgf@xb}{\pgf@ya}}
    \pgfkeysgetvalue{/tikz/rectangle with rounded corners south west}{\pgf@rectc}
    \pgfsetcornersarced{\pgfpoint{\pgf@rectc}{\pgf@rectc}}
    \pgfpathclose
 }
}
\makeatother
\begin{tikzpicture}
  \node[
  draw,
  shape=rectangle with rounded corners,
  minimum height=2cm,
  rectangle with rounded corners north west=20pt,
  rectangle with rounded corners south west=0pt,
  rectangle with rounded corners north east=0pt,
  rectangle with rounded corners south east=20pt,
] (a) {Long piece of text};

  \node[
  draw,
  shape=rectangle with rounded corners,
  minimum height=2cm,
  minimum width=2cm,
  rectangle with rounded corners north west=30pt,
  rectangle with rounded corners south west=30pt,
  rectangle with rounded corners north east=30pt,
  rectangle with rounded corners south east=30pt,
] at (0,-3) (b) {text};

\foreach \anchor in {north west,south west,north east,south east} {
  \fill[red] (b.\anchor) circle[radius=2pt];
}
\foreach \angle in {0,5,...,355} {
  \fill[blue] (b.\angle) circle[radius=1pt];
}
\end{tikzpicture}
\end{document}

I've also added the corner anchors. To illustrate my comment about the anchors, the lower picture has lots of dots where the anchors are. As can be seen, they aren't on the actual boundary of the node. This isn't necessarily a bad thing, but is something you should be aware of.

rounded rectangles as shapes

Edit: (added by wh1t3). I took a look at how anchors work in Tikz and decided to add some code that places the anchors in the corners correctly, for the sake of completion. It is not completely straightforward, since you have to use saved anchors instead of regular anchors. Because regular anchors can't use the values we assign to keys. This is the code used:

\documentclass{article}
\usepackage{tikz}
\begin{document}
\tikzset{
  rectangle with rounded corners north west/.initial=4pt,
  rectangle with rounded corners south west/.initial=4pt,
  rectangle with rounded corners north east/.initial=4pt,
  rectangle with rounded corners south east/.initial=4pt,
}
\makeatletter
\pgfdeclareshape{rectangle with rounded corners}{
  \inheritanchorborder[from=rectangle]
  \savedmacro{\neoffset}{
    \pgfkeysgetvalue{/tikz/rectangle with rounded corners north east}{\pgf@rectc}
    \let\neoffset\pgf@rectc
  }
  \savedmacro{\nwoffset}{
    \pgfkeysgetvalue{/tikz/rectangle with rounded corners north west}{\pgf@rectc}
    \let\nwoffset\pgf@rectc
  }
  \savedmacro{\seoffset}{
    \pgfkeysgetvalue{/tikz/rectangle with rounded corners south east}{\pgf@rectc}
    \let\seoffset\pgf@rectc
  }
  \savedmacro{\swoffset}{
    \pgfkeysgetvalue{/tikz/rectangle with rounded corners south west}{\pgf@rectc}
    \let\swoffset\pgf@rectc
  }
  \savedanchor{\north}{
    \pgf@y=.5\ht\pgfnodeparttextbox
    \pgf@x=0pt
    \setlength{\pgf@ya}{\pgfshapeminheight}
    \ifdim\pgf@y<.5\pgf@ya
      \pgf@y=.5\pgf@ya
    \fi
  }
  \savedanchor{\south}{
    \pgf@y=-.5\ht\pgfnodeparttextbox
    \pgf@x=0pt
    \setlength{\pgf@ya}{\pgfshapeminheight}
    \ifdim\pgf@y>-.5\pgf@ya
      \pgf@y=-.5\pgf@ya
    \fi
  }
  \savedanchor{\east}{
    \pgf@y=0pt
    \pgf@x=.5\wd\pgfnodeparttextbox
    \addtolength{\pgf@x}{2ex}
    \setlength{\pgf@xa}{\pgfshapeminwidth}
    \ifdim\pgf@x<.5\pgf@xa
      \pgf@x=.5\pgf@xa
    \fi
  }
  \savedanchor{\west}{
    \pgf@y=0pt
    \pgf@x=-.5\wd\pgfnodeparttextbox
    \addtolength{\pgf@x}{-2ex}
    \setlength{\pgf@xa}{\pgfshapeminwidth}
    \ifdim\pgf@x>-.5\pgf@xa
      \pgf@x=-.5\pgf@xa
    \fi
  }
  \savedanchor{\northeast}{
    \pgf@y=.5\ht\pgfnodeparttextbox % height of the box
    \pgf@x=.5\wd\pgfnodeparttextbox % width of the box
    \addtolength{\pgf@x}{2ex}
    \setlength{\pgf@xa}{\pgfshapeminwidth}
    \ifdim\pgf@x<.5\pgf@xa
      \pgf@x=.5\pgf@xa
    \fi
    \setlength{\pgf@ya}{\pgfshapeminheight}
    \ifdim\pgf@y<.5\pgf@ya
      \pgf@y=.5\pgf@ya
    \fi
  }
  \savedanchor{\southwest}{
    \pgf@y=-.5\ht\pgfnodeparttextbox
    \pgf@x=-.5\wd\pgfnodeparttextbox
    \addtolength{\pgf@x}{-2ex}
%     \pgf@x=0pt
    \setlength{\pgf@xa}{\pgfshapeminwidth}
    \ifdim\pgf@x>-.5\pgf@xa
      \pgf@x=-.5\pgf@xa
    \fi
    \setlength{\pgf@ya}{\pgfshapeminheight}
    \ifdim\pgf@y>-.5\pgf@ya
      \pgf@y=-.5\pgf@ya
    \fi
  }
  \anchor{text}{%
    \northeast%
    \pgf@x=-.5\wd\pgfnodeparttextbox%
    \pgfmathsetlength{\pgf@y}{-.5ex}
  }
  \anchor{north east}{
    \northeast
    \pgfmathsetmacro{\nw}{(1-sin(45))*\neoffset}
    \addtolength{\pgf@x}{-\nw pt}
    \addtolength{\pgf@y}{-\nw pt}
  }
  \anchor{center}{
    \pgf@x=0pt
    \pgf@y=0pt
  }
  \anchor{south west}{
    \southwest
    \pgfmathsetmacro{\nw}{(1-sin(45))*\swoffset}
    \addtolength{\pgf@x}{\nw pt}
    \addtolength{\pgf@y}{\nw pt}
  }
  \anchor{north west}{
    \northeast
    \pgfmathsetmacro{\temp@x}{\pgf@x}
    \southwest
    \pgfmathsetmacro{\temp@xtwo}{\pgf@x}
    \northeast
    \pgfmathsetmacro{\xdiff}{\temp@x-\temp@xtwo}
    \def\pgf@xa{\pgf@x-\xdiff}
            \pgfmathsetmacro{\nw}{(1-sin(45))*\nwoffset}
    \def\pgf@xaa{\pgf@xa+\nw}
    \def\pgf@yaa{\pgf@y-\nw}
    \pgfpoint{\pgf@xaa}{\pgf@yaa}
  }
  \anchor{south east}{
    \southwest
    \pgfmathsetmacro{\temp@x}{\pgf@x}
    \northeast
    \pgfmathsetmacro{\temp@xtwo}{\pgf@x}
    \southwest
    \pgfmathsetmacro{\xdiff}{\temp@x-\temp@xtwo}
    \def\pgf@xa{\pgf@x-\xdiff}
    \pgfmathsetmacro{\nw}{(1-sin(45))*\seoffset}
    \def\pgf@xaa{\pgf@xa-\nw}
    \def\pgf@yaa{\pgf@y+\nw}
    \pgfpoint{\pgf@xaa}{\pgf@yaa}
  }
  \anchor{south}{\south}
  \anchor{north}{\north}
  \anchor{east}{\east}
  \anchor{west}{\west}
  \backgroundpath{% this is new
    % store lower right in xa/ya and upper right in xb/yb
    \southwest \pgf@xa=\pgf@x \pgf@ya=\pgf@y
    \northeast \pgf@xb=\pgf@x \pgf@yb=\pgf@y
    % construct main path
    \pgfkeysgetvalue{/tikz/rectangle with rounded corners north west}{\pgf@rectc}
    \pgfsetcornersarced{\pgfpoint{\pgf@rectc}{\pgf@rectc}}
    \pgfpathmoveto{\pgfpoint{\pgf@xa}{\pgf@ya}}
    \pgfpathlineto{\pgfpoint{\pgf@xa}{\pgf@yb}}
    \pgfkeysgetvalue{/tikz/rectangle with rounded corners north east}{\pgf@rectc}
    \pgfsetcornersarced{\pgfpoint{\pgf@rectc}{\pgf@rectc}}
    \pgfpathlineto{\pgfpoint{\pgf@xb}{\pgf@yb}}
    \pgfkeysgetvalue{/tikz/rectangle with rounded corners south east}{\pgf@rectc}
    \pgfsetcornersarced{\pgfpoint{\pgf@rectc}{\pgf@rectc}}
    \pgfpathlineto{\pgfpoint{\pgf@xb}{\pgf@ya}}
    \pgfkeysgetvalue{/tikz/rectangle with rounded corners south west}{\pgf@rectc}
    \pgfsetcornersarced{\pgfpoint{\pgf@rectc}{\pgf@rectc}}
    \pgfpathclose
 }
}
\makeatother
\begin{tikzpicture}
  \node[
  draw,
  shape=rectangle with rounded corners,
  minimum height=2cm,
  rectangle with rounded corners north west=20pt,
  rectangle with rounded corners south west=0pt,
  rectangle with rounded corners north east=0pt,
  rectangle with rounded corners south east=20pt,
] (a) {Long piece of text};

  \node[
  draw,
  shape=rectangle with rounded corners,
  minimum height=3cm,
  minimum width=3cm,
  rectangle with rounded corners north west=30pt,
  rectangle with rounded corners south west=30pt,
  rectangle with rounded corners north east=30pt,
  rectangle with rounded corners south east=30pt,
] at (0,-4) (b) {text};

\foreach \anchor/\color in {west/black,east/black,north/black,south/black,north west/red,south west/green,north east/yellow,south east/blue} {
  \fill[color=\color] (b.\anchor) circle[radius=2pt];
}
\foreach \angle in {0,5,...,355} {
  \fill[blue] (b.\angle) circle[radius=1pt];
}

\foreach \anchor/\color in {west/black,east/black,north/black,south/black,north west/red,south west/green,north east/yellow,south east/blue} {
  \fill[color=\color] (a.\anchor) circle[radius=2pt];
}
\foreach \angle in {0,5,...,355} {
  \fill[blue] (a.\angle) circle[radius=1pt];
}

\end{tikzpicture}
\end{document}

The saved macros are used to enable access to the keys in the regular anchors. The output now looks like this:

Nodes with correct corner anchors

The additional 2ex in the code, is to give the text a little bit of room. This should normally be done with a key of course, we should also take innersep, outersep etc. into consideration. This is merely meant as a possible start. Also notice the blue circles still aren't on the border. This is because I have not implemented \anchorborder, it is still inherited from rectangle. This is because this is very complicated (it will be a lot of nested if/then/else and won't make the rest clearer).

5
  • More complicated than I thought, but it's really cool! Thanks again! Commented Oct 27, 2011 at 10:04
  • It's not hard to make the corners customisable, may I edit your answer to add that code in? (Oh, and one minor issue with this code is that the anchors will be on the original rectangle, not the one with the corners. To do that would involve a bit more calculation.) Commented Oct 27, 2011 at 10:50
  • To answer your first question, feel absolutely free. On the matter of the anchors, I thought about that and the anchors that are actually 'visible' are on the shape correctly. The anchors on the corners, if added, would indeed not be on the border of the shape. However, I felt that a handle of the place where the corner would 'normally' be is more valuable. When you place a nodes north west corner at the origin, you would not want it to protrude above the x-axis would you? Granted, there are other examples where it is wanted. Do you have a good example why they should be on the border? Commented Oct 27, 2011 at 11:29
  • Certainly for positioning other nodes having the anchors at the rectangular border is better. Where the actual boundary is useful is with having arrows or lines coming to this node. They stop at the anchor boundary, which in this case is the rectangle. I don't mean this as a criticism, more as something that a user should be aware of as they might be expecting different behaviour. Commented Oct 27, 2011 at 11:54
  • Bother - I'm not allowed to vote twice. Nice work with the anchors. Commented Oct 28, 2011 at 20:10
37

Here you have another possibility with append after command. First you place a node with its contain and with at least two append after command options you can draw the border with one, two, three or four rounded corners different or not.

Please, observe that this option need to use \draw node ..., with just \node, it fails.

In any case I think Roelof and Andrew solution is the way to go, but if your forget to copy their code ...

\documentclass[border=3mm]{standalone}
\usepackage{tikz}

\begin{document}
\begin{tikzpicture}
\draw node[
    append after command={[rounded corners=0pt](b.west)|-(b.north)},
    append after command={[rounded corners=3pt](b.north)-|(b.east)},
    append after command={[rounded corners=1pt](b.east)|-(b.south)},
    append after command={[rounded corners=5pt](b.south)-|(b.west)}] 
(b) {Another piece of text};
\end{tikzpicture}
\end{document}

enter image description here

Edit:

In Fill a node shape has been shown that previous code doesn't work if you want to fill the node and Qrrbrbirlbel has provided a better code to solve the problem which (for completion) I copy here adapted to my example:

\documentclass[tikz, border=1mm]{standalone}

\tikzset{weird fill/.style={append after command={
   \pgfextra
        \draw[sharp corners, fill=#1]% 
    (\tikzlastnode.west)% 
    [rounded corners=3pt] |- (\tikzlastnode.north)% 
    [rounded corners=1pt] -| (\tikzlastnode.east)% 
    [rounded corners=5pt] |- (\tikzlastnode.south)% 
    [rounded corners=0pt] -| (\tikzlastnode.west);
   \endpgfextra}}}

\begin{document}

\begin{tikzpicture}
\path node [
    weird fill=blue!20,
    text width=3cm,align=center] {Right filled node\\ thank you to\\ Qrrbrbirlbel's\\ solution};
\end{tikzpicture}
\end{document}

enter image description here

2
  • What does that '%' do at each line? Isn't that just comment of nothing?
    – Huy Ngo
    Commented May 1, 2017 at 3:46
  • @HuyNgo Sometimes the white space at end of line (or the white space at begining of line) are not completely suppressed by tex and they produce undesired results. I cannot explain it better but I've found two related questions here. I hope they help you to understand it: tex.stackexchange.com/q/278146/1952, tex.stackexchange.com/q/34844/1952
    – Ignasi
    Commented May 1, 2017 at 7:20

You must log in to answer this question.

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