6

I want to draw polygons that have a fixed width shading or border on the inside. Here is an image made in mspaint illustrating the kind of thing I'd like to draw:

Example image

This question addresses this issue, and an answer is given using code suggested by Mark Wibrow. But Wibrow's code includes a fill command that specifies white as the fill colour. What if I want a choice of fill colour? I could make that a second parameter of the key, but this is conceptually the wrong way to organise things. Fill colour and internal border are separate concerns, and the internal border drawing key shouldn't have to be told about the fill colour. In other words, we should be able to just choose whether to combine our new key with the "fill" key, and it should just work that way.

This might be produced by code (essentially Wibrow's) that looks like this, except that it doesn't quite work:

\documentclass{standalone}

\usepackage{tikz}

\newlength{\internalborderwidth}
\setlength{\internalborderwidth}{1mm}

\tikzset{internal border/.style = {
    preaction = {clip, postaction = {draw = #1, line width = \internalborderwidth}}
}}

\definecolor{lightpeach}  {rgb}{0.9765, 0.9608, 0.8588}
\definecolor{mylightgreen}{rgb}{0.7098, 0.9020, 0.1137}
\definecolor{mylightblue} {rgb}{0.6000, 0.8510, 0.9176}
\definecolor{mypink}      {rgb}{1.0000, 0.6824, 0.7882}

\begin{document}
    \begin{tikzpicture}
        \draw [fill = lightpeach, internal border = mylightgreen]
              (0, 0) -- (2, 5) -- (6, 3) -- cycle;
        \draw [fill = lightpeach, internal border = mylightblue]
              (0, 0) -- (6, 3) -- (7, 1) -- cycle;
        \draw [fill = lightpeach, internal border = mypink]
              (0, 0) -- (7, 1) -- (3.5, -1.5) -- cycle;
    \end{tikzpicture}
\end{document}

The reason why it doesn't work is that the "fill" action occurs after the preaction. So the coloured border gets filled over. But Wibrow's action can't be used as a postaction either; then it would happen after the ordinary border (the thin black line) was drawn, so it would wipe that out. Maybe you could add "draw" in there to get it drawn again, but you'd lose any styles applied alongside the internal border key, like if I had specified a colour for it.

Really what I need is to be able to specify an action to occur in between filling and drawing (when fill and draw are combined, it is filling that occurs first, per page 171 of the TikZ/PGF version 3 manual). Of course, I could specify the path twice, first to fill it and then to draw it, but I do not want to have to repeat myself like that.

8

I'm not quite sure why you don't want to use a postaction. It seems quite easy to redraw the black border:

Edit:

You can pass options to second draw command in the postaction, but from the comment I got that you don't want it. But you should set all options for the internal border (e.g. solid) to avoid side effects. The example now shows also a red, dashed external border.

\documentclass{standalone}

\usepackage{tikz}

\newlength{\internalborderwidth}
\setlength{\internalborderwidth}{1mm}

\tikzset{
internal border/.style = {
    postaction = {clip, postaction = {draw = #1, solid, line width = \internalborderwidth},
                        postaction = {draw}}
}}

\definecolor{lightpeach}  {rgb}{0.9765, 0.9608, 0.8588}
\definecolor{mylightgreen}{rgb}{0.7098, 0.9020, 0.1137}
\definecolor{mylightblue} {rgb}{0.6000, 0.8510, 0.9176}
\definecolor{mypink}      {rgb}{1.0000, 0.6824, 0.7882}

\begin{document}
    \begin{tikzpicture}\tracingmacros=1
        \draw [fill = lightpeach, internal border = mylightgreen]
              (0, 0) -- (2, 5) -- (6, 3) -- cycle;
        \draw [fill = mylightblue!50!white, internal border =mylightblue]
              (0, 0) -- (6, 3) -- (7, 1) -- cycle;
        \draw [dashed,red, fill = mypink!50!white, internal border = mypink]
              (0, 0) -- (7, 1) -- (3.5, -1.5) -- cycle;
    \end{tikzpicture}
\end{document}

enter image description here

Edit 2

You naturally can also put the fill in a preaction (instead of a separate key, it could also be added to the border key):

\documentclass{standalone}

\usepackage{tikz}

\newlength{\internalborderwidth}
\setlength{\internalborderwidth}{1mm}

\tikzset{
pre fill/.style = {preaction={fill=#1}},
internal border/.style = {
    preaction ={clip, postaction = {draw = #1, solid, line width = \internalborderwidth},
                        }
}}

\definecolor{lightpeach}  {rgb}{0.9765, 0.9608, 0.8588}
\definecolor{mylightgreen}{rgb}{0.7098, 0.9020, 0.1137}
\definecolor{mylightblue} {rgb}{0.6000, 0.8510, 0.9176}
\definecolor{mypink}      {rgb}{1.0000, 0.6824, 0.7882}

\begin{document}
    \begin{tikzpicture}\tracingmacros=1
        \draw [pre fill=mylightgreen!50!white,internal border = mylightgreen]
              (0, 0) -- (2, 5) -- (6, 3) -- cycle;
        \draw [pre fill = mylightblue!50!white, internal border =mylightblue]
              (0, 0) -- (6, 3) -- (7, 1) -- cycle;
        \draw [dashed,red, pre fill = mypink!50!white, internal border = mypink]
              (0, 0) -- (7, 1) -- (3.5, -1.5) -- cycle;
    \end{tikzpicture}
\end{document}

enter image description here

  • As I said in the question: "Maybe you could add 'draw' in there to get it drawn again, but you'd lose any styles applied alongside the internal border key, like if I had specified a colour for it." You've hardcoded that the border line should be black, width 0.4pt. What if the styles I specify provide that the border line should be thick and red? I'll get (due to the clipping) half of a thick red line on the outside and a 0.2pt black line on the inside. Thus your key doesn't "play nice" with other keys I might reasonably wish to combine it with. – Hammerite Jan 2 '16 at 16:52
  • @Hammerite: I edited the answer, you can remove options from the second draw key, if you don't want them. – Ulrike Fischer Jan 2 '16 at 17:10
  • I see. I did not realise that using the "draw" key in a post- or preaction would cause the styles set in the "calling code" to be used... I'm not sure whether to accept this answer though, because it still hardcodes that "draw" is used at all: try removing the "draw" key from the calling code; a default-style border is drawn. But arguably you would be writing bad code if you tried to do this without using draw (because why are you doing something that effectively draws the outline of the shape, without making use of the key that is supposed to be used for that purpose...?) – Hammerite Jan 2 '16 at 17:36
  • I'm working on my own solution that involves using decorations, but it's not finished yet and I'm going out now. I'll make a decision about this in the next few days. – Hammerite Jan 2 '16 at 18:03
  • Imho also with decoration you will have to draw the "black" border at last -- there will always the problem that you want an inner border and so need to clip. But you can naturally move the fill to a preaction see my edit. – Ulrike Fischer Jan 2 '16 at 18:48

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.