3

The following code uses a decorator to add an arrow tip to an edge. Logically, the tip is part of the edge, and so I want it to be colored with the line-color. However, because the tip is rendered using \fill, it takes its color from the fill parameter. How can I make the color to respond to draw=red, and also not respond to fill=blue?

enter image description here

\documentclass[tikz, crop,border=1]{standalone}
\usetikzlibrary{decorations.markings, decorations.pathreplacing}

\newcommand{\drawArrow}[2]{
    \draw[
        decoration={
            markings,
            mark=at position 0.8 with {%
                \fill (0, 0.5pt) -- ++ (-0.25, 0.075) -- ++ (0, -0.075) -- cycle;
            }
        },
        postaction=decorate
    ] #1 -- #2;
}

\begin{document}
\begin{tikzpicture}[scale=2]
\tikzset{
    pe/.style={
        line width = 1pt,
        decoration={
            show path construction, 
            lineto code={%
                \drawArrow{(\tikzinputsegmentfirst)}{(\tikzinputsegmentlast)}
            },
            closepath code={%
                \drawArrow{(\tikzinputsegmentfirst)}{(\tikzinputsegmentlast)}
            }
        },
        postaction=decorate
    }
}

% Not what I want
\draw[pe, draw = red] (0, 0) -- (1, 0);

% Not what I want
\draw[pe, draw = red, fill=blue] (0, 0.25) -- (1, 0.25) -- (1, 0.5) -- (0, 0.5) -- cycle;

% What I want
\draw[pe, red] (0, 0.6) -- (1, 0.6);

% Not what I want
\draw[pe, red, fill=blue] (0, 0.75) -- (1, 0.75) -- (1, 1) -- (0, 1) -- cycle;

% What I want, simulated
\fill[pe, fill=blue] (0, 1.1) -- (1, 1.1) -- (1, 1.35) -- (0, 1.35) -- cycle;
\draw[pe, red] (0, 1.1) -- (1, 1.1) -- (1, 1.35) -- (0, 1.35) -- cycle;

\end{tikzpicture}
\end{document}
kaba
  • 599

3 Answers3

2

Update 2

You can make the color of the decoration a parameter of the style.

decoration={
    markings, mark=at position 0.8 with {%
        \fill[#1] (0, 0.5pt) -- ++ (-0.25, 0.075) -- ++ (0, -0.075) -- cycle;
    }

Just call this style pe=yellow, by default these style is red.

\documentclass[tikz, crop,border=1]{standalone}
\usetikzlibrary{decorations.markings}

\begin{document}
\begin{tikzpicture}
\tikzset{
    pe/.style={
        %line width = 1pt,
        decoration={
            markings, mark=at position 0.8 with {%
                \fill[#1] (0, 0.5pt) -- ++ (-0.25, 0.075) -- ++ (0, -0.075) -- cycle;
            }
        },
        postaction=decorate
    },
    pe/.default=red
}
% Incorrect
\draw[pe=yellow, draw = red] (0, 0) -- (1, 0);

% Incorrect
\draw[pe=black, draw = red, fill=blue] (0, 0.25) -- (1, 0.25) -- (1, 0.5) -- (0, 0.5) -- cycle;

% Correct
\draw[pe, red] (0, 0.6) -- (1, 0.6);

% Incorrect
\draw[pe, red, fill=blue] (0, 0.75) -- (1, 0.75) -- (1, 1) -- (0, 1) -- cycle;

% Correct, simulated
\fill[pe, fill=blue] (0, 1.1) -- (1, 1.1) -- (1, 1.35) -- (0, 1.35) -- cycle;
\end{tikzpicture}
\end{document}

pe default

Update

If I understood correctly, you must specify the color in the decoration.

decoration={
            markings, mark=at position 0.8 with {%
                \fill[red] (0, 0.5pt) -- ++ (-0.25, 0.075) -- ++ (0, -0.075) -- cycle;
            }
        },

decoration

\documentclass[tikz, crop,border=1]{standalone}
\usetikzlibrary{decorations.markings}

\begin{document}
\begin{tikzpicture}
\tikzset{
    pe/.style={
        %line width = 1pt,
        decoration={
            markings, mark=at position 0.8 with {%
                \fill[red] (0, 0.5pt) -- ++ (-0.25, 0.075) -- ++ (0, -0.075) -- cycle;
            }
        },
        postaction=decorate
    },
}

% Incorrect
\draw[pe, draw = red] (0, 0) -- (1, 0);

% Incorrect
\draw[pe, draw = red, fill=blue] (0, 0.25) -- (1, 0.25) -- (1, 0.5) -- (0, 0.5) -- cycle;

% Correct
\draw[pe, red] (0, 0.6) -- (1, 0.6);

% Incorrect
\draw[pe, red, fill=blue] (0, 0.75) -- (1, 0.75) -- (1, 1) -- (0, 1) -- cycle;

% Correct, simulated
\fill[pe, fill=blue] (0, 1.1) -- (1, 1.1) -- (1, 1.35) -- (0, 1.35) -- cycle;
\draw[pe, red] (0, 1.1) -- (1, 1.1) -- (1, 1.35) -- (0, 1.35) -- cycle;

\end{tikzpicture}
\end{document}

Simply by not specifying `draw=red`, but just `red`

    \draw[pe, red] (0, 0) -- (1, 0);

[![red][2]][2]

    \documentclass[tikz, crop,border=5mm]{standalone}
    \usetikzlibrary{decorations.markings}

    \begin{document}
    \begin{tikzpicture}
    \tikzset{
        pe/.style={
            decoration={
                markings, mark=at position 0.8 with {%
                    \fill (0, 0.5pt) -- ++ (-0.25, 0.075) -- ++ (0, -0.075) -- cycle;
                }
            },
            postaction=decorate
        }
    }
    \draw[pe, red] (0, 0) -- (1, 0);
    \end{tikzpicture}
    \end{document}
AndréC
  • 24,137
  • This modifies the fill color, which I want to control independently for filled polygons. – kaba Dec 10 '18 at 04:16
  • Show us an example of its effect. – AndréC Dec 10 '18 at 04:16
  • I was wrong in that it does not modify the fill color. However, specifying the fill color overrides the color for the arrow tip, which should not happen. – kaba Dec 10 '18 at 04:33
  • I don't understand what your problem is now, edit your question. – AndréC Dec 10 '18 at 04:34
  • Added new images. The arrow should respond to setting the draw color, and not respond to setting the fill color. – kaba Dec 10 '18 at 04:44
  • No, everything's normal. Read page 190 of the manual. – AndréC Dec 10 '18 at 04:47
  • I'm not implying there is a bug; I edited again for clarity. I would like it to behave in the way I specify, and am asking how to achieve that. – kaba Dec 10 '18 at 04:52
  • I'm sorry, I don't understand what the problem is. Instead, show us what you want to do but can't do it with the current TikZ rules. Have you read page 190? – AndréC Dec 10 '18 at 04:55
  • I have read page 190, but it is not relevant here. Above I'm showing an image of a polygon filled in blue, with a red line. The decorator is logically attached to the edge, so when I specify fill=blue, I want the arrow tip to preserve the red color, because that is the color of the edge. – kaba Dec 10 '18 at 05:05
  • I just updated my answer – AndréC Dec 10 '18 at 05:15
  • Specifying the color of the fill in the decorator is the crux of the problem as you noted. But how could it be made to adopt the current line-color, so that it responds to draw=red? – kaba Dec 10 '18 at 05:19
  • I just updated my answer – AndréC Dec 10 '18 at 05:31
2

Just define a style for the arrow and set it accordingly.

\documentclass[tikz, crop,border=1]{standalone}
\usetikzlibrary{decorations.markings, decorations.pathreplacing}
\tikzset{pearrow/.style={fill},
peset/.code={\tikzset{pearrow/.style={#1}}}}
\newcommand{\drawArrow}[2]{
    \draw[
        decoration={
            markings,
            mark=at position 0.8 with {%
                \path[pearrow] (0, 0.5pt) -- ++ (-0.25, 0.075) -- ++ (0, -0.075) -- cycle;
            }
        },
        postaction=decorate
    ] #1 -- #2;
}

\begin{document}
\begin{tikzpicture}[scale=2]
\tikzset{
    pe/.style={
        line width = 1pt,
        decoration={
            show path construction, 
            lineto code={%
                \drawArrow{(\tikzinputsegmentfirst)}{(\tikzinputsegmentlast)}
            },
            closepath code={%
                \drawArrow{(\tikzinputsegmentfirst)}{(\tikzinputsegmentlast)}
            }
        },
        postaction=decorate
    }
}


% with peset
\draw[pe, red, fill=blue,peset={fill=red}] (0, 0.75) -- (1, 0.75) -- (1, 1) -- (0, 1) -- cycle;

% What I want, simulated
\fill[pe, fill=blue] (0, 1.1) -- (1, 1.1) -- (1, 1.35) -- (0, 1.35) -- cycle;
\draw[pe, red] (0, 1.1) -- (1, 1.1) -- (1, 1.35) -- (0, 1.35) -- cycle;

\end{tikzpicture}
\end{document}

enter image description here

2

The following findArrowColor style, based on this Georg Sievelson's answer, picks the current stroke color if such is available, then the current text color if such is available, and black color as the last resort.

enter image description here

\documentclass[tikz, crop,border=1]{standalone}
\usetikzlibrary{decorations.markings, decorations.pathreplacing}

\usepackage{ifthen}

\makeatletter
\tikzset{
  /tikz/findArrowColor/.style={/utils/exec={%
    \ifthenelse{\equal{\tikz@strokecolor}{}}%
    {%
        \ifthenelse{\equal{\tikz@textcolor}{}}%
        {%
            \colorlet{#1}{black}%
        }%
        {\colorlet{#1}{\tikz@textcolor}}%
    }%
    {%
        \colorlet{#1}{\tikz@strokecolor}%
    }%
  }}
}
\makeatother

\newcommand{\drawArrow}[2]{
    \draw[
        decoration={
            markings,
            mark=at position 0.8 with {%
                \begin{scope}
                    \tikzset{findArrowColor=arrowColor}
                    \fill[fill=arrowColor] (0, 0.5pt) -- ++ (-0.25, 0.075) -- ++ (0, -0.075) -- cycle;
                \end{scope}
            }
        },
        postaction=decorate
    ] #1 -- #2;
}

\begin{document}
\begin{tikzpicture}[scale=2]

\tikzset{
    pe/.style={
        line width = 1pt,
        decoration={
            show path construction, 
            lineto code={%
                \begin{scope}[#1]
                \drawArrow{(\tikzinputsegmentfirst)}{(\tikzinputsegmentlast)}
                \end{scope}
            },
            closepath code={%
                \begin{scope}[#1]
                \drawArrow{(\tikzinputsegmentfirst)}{(\tikzinputsegmentlast)}
                \end{scope}
            }
        },
        postaction=decorate
    }
}

\draw[pe, fill = blue] (0, -0.2) -- (1, -0.2);
\draw[pe, draw = red] (0, 0) -- (1, 0);
\draw[pe, draw = red, fill=blue] (0, 0.25) -- (1, 0.25) -- (1, 0.5) -- (0, 0.5) -- cycle;
\draw[pe, red, fill=blue] (0, 0.75) -- (1, 0.75) -- (1, 1) -- (0, 1) -- cycle;

\fill[fill=blue] (0, 1.1) -- (1, 1.1) -- (1, 1.35) -- (0, 1.35) -- cycle;
\draw[pe, red] (0, 1.1) -- (1, 1.1) -- (1, 1.35) -- (0, 1.35) -- cycle;

\end{tikzpicture}
\end{document}
kaba
  • 599