1

I recently stumbled over this issue when declaring own tikz shapes with makeshape, but see for yourself:

\documentclass{article} \usepackage{tikz} \usetikzlibrary{positioning,fit} \usepackage{demoProblem} \begin{document} \begin{tikzpicture} \node[draw] (origin) {origin}; \begin{scope}[local bounding box=A1] \node[myShape, right=3cm of origin] {}; \end{scope} \node[draw,fit=(A1), label=below:{box}] (box) {}; \end{tikzpicture} \begin{tikzpicture} \node[draw] (origin) {origin}; \begin{scope}[local bounding box=A1] \node[myShape, right=3cm of origin, left] {}; \end{scope} \node[draw,fit=(A1), label=below:{box}] (box) {}; \end{tikzpicture} \begin{tikzpicture} \node[draw] (origin) {origin}; \begin{scope}[local bounding box=A1] \node[myShape] at (3,0) {}; \end{scope} \node[draw,fit=(A1), label=below:{box}] (box) {}; \end{tikzpicture} \end{document} 

With the following demoProblem.sty:

\RequirePackage{makeshape} \def\myShapeAnchor{ \pgf@xa=\pgfshapeminwidth \pgf@ya=\pgfshapeminwidth \pgf@xa=.5\pgf@xa \pgf@ya=.5\pgf@ya \pgfpathmoveto{\pgfpoint{.75\pgf@xa}{.4\pgf@ya}} \pgfpathlineto{\pgfpoint{-.75\pgf@xa}{.4\pgf@ya}} \pgfpathlineto{\pgfpoint{-.97\pgf@xa}{-.18\pgf@ya}} \pgfpathlineto{\pgfpoint{-.99\pgf@xa}{-.18\pgf@ya}} \pgfpathlineto{\pgfpoint{-.99\pgf@xa}{-.4\pgf@ya}} \pgfpathlineto{\pgfpoint{.99\pgf@xa}{-.4\pgf@ya}} \pgfpathlineto{\pgfpoint{.99\pgf@xa}{-.18\pgf@ya}} \pgfpathlineto{\pgfpoint{.97\pgf@xa}{-.18\pgf@ya}} \pgfpathclose % \pgfusepath{stroke} } \def\myShapeBorder{ % Deckel \pgfmoveto{\northeast \pgf@x=.75\pgf@x \pgf@y=.4\pgf@y} \pgflineto{\northeast \pgf@x=.97\pgf@x \pgf@y=-.18\pgf@y} \pgflineto{\northeast \pgf@x=-.97\pgf@x \pgf@y=-.18\pgf@y} \pgflineto{\northeast \pgf@x=-.75\pgf@x \pgf@y=.4\pgf@y} \pgfclosepath \pgfusepath{stroke} } \pgfdeclareshape{@myShape}{ \setpaths{\myShapeAnchor}{\myShapeBorder} \savedanchor\northeast{% \pgf@x = \pgfshapeminwidth \pgf@y = \pgfshapeminwidth \pgf@x=.5\pgf@x \pgf@y=.5\pgf@y } \anchor{north}{\northeast \pgf@y=.4\pgf@y \pgf@x=0pt} \anchor{east}{\northeast \pgf@x=.9\pgf@x \pgf@y=0pt} \anchor{south}{\northeast \pgf@x=0pt \pgf@y=-.4\pgf@y} \anchor{west}{\northeast \pgf@x=-.9\pgf@x \pgf@y=0pt} } \tikzset{ myShape/.style 2 args={ shape=@myShape, minimum size=#1, fill=#2 }, myShape/.default={1cm}{black} } 

All this results in the following output:

output of the code shown above

You see the boxes in the first two lines are extended to the right/left compared what I'd expect.

Now I already have that \pgfusepath{stroke} in the \myShapeAnchor which currently is commented out. Adding it back in, I see the path specified there is drawn/evaluated right/left of the actual node correlating to the extend.

Now I think I already found out the issue is that when using the positioning library, pgf/tikz evaluates the anchorpath first in order to know where to place the node. Now in this evaluation, the node draws a path which is captured by the bounding box, resulting in this weird extension of the box.

  1. Do I see this correctly?

Now I wonder of course if this can be fixed with the shape (I'd still like to use the bounding box). Looking at the docs of makeshape, it says

Its key features are: a mechanism for specifying the \anchorborder behaviour as a path

  1. Am I correct in that when I want to fix this at the shape level, I need to stop using makeshape essentially (thereby go the hard way of declaring the anchorborder with potentially complex operations)? (or at least makeshape is not of much help anymore when not using that feature)
0

1 Answer 1

1

Interrupting the bounding box calculation when creating the anchor path seems to work:

\begin{filecontents}[overwrite]{\jobname.sty} \RequirePackage{makeshape} \def\myShapeAnchor{ \pgf@xa=\pgfshapeminwidth \pgf@ya=\pgfshapeminwidth \pgf@xa=.5\pgf@xa \pgf@ya=.5\pgf@ya \begin{pgfinterruptboundingbox} \pgfpathmoveto{\pgfpoint{.75\pgf@xa}{.4\pgf@ya}} \pgfpathlineto{\pgfpoint{-.75\pgf@xa}{.4\pgf@ya}} \pgfpathlineto{\pgfpoint{-.97\pgf@xa}{-.18\pgf@ya}} \pgfpathlineto{\pgfpoint{-.99\pgf@xa}{-.18\pgf@ya}} \pgfpathlineto{\pgfpoint{-.99\pgf@xa}{-.4\pgf@ya}} \pgfpathlineto{\pgfpoint{.99\pgf@xa}{-.4\pgf@ya}} \pgfpathlineto{\pgfpoint{.99\pgf@xa}{-.18\pgf@ya}} \pgfpathlineto{\pgfpoint{.97\pgf@xa}{-.18\pgf@ya}} \pgfpathclose \end{pgfinterruptboundingbox} % \pgfusepath{stroke} } \def\myShapeBorder{ % Deckel \pgfmoveto{\northeast \pgf@x=.75\pgf@x \pgf@y=.4\pgf@y} \pgflineto{\northeast \pgf@x=.97\pgf@x \pgf@y=-.18\pgf@y} \pgflineto{\northeast \pgf@x=-.97\pgf@x \pgf@y=-.18\pgf@y} \pgflineto{\northeast \pgf@x=-.75\pgf@x \pgf@y=.4\pgf@y} \pgfclosepath \pgfusepath{stroke} } \pgfdeclareshape{@myShape}{ \setpaths{\myShapeAnchor}{\myShapeBorder} \savedanchor\northeast{% \pgf@x = \pgfshapeminwidth \pgf@y = \pgfshapeminwidth \pgf@x=.5\pgf@x \pgf@y=.5\pgf@y } \anchor{north}{\northeast \pgf@y=.4\pgf@y \pgf@x=0pt} \anchor{east}{\northeast \pgf@x=.9\pgf@x \pgf@y=0pt} \anchor{south}{\northeast \pgf@x=0pt \pgf@y=-.4\pgf@y} \anchor{west}{\northeast \pgf@x=-.9\pgf@x \pgf@y=0pt} } \tikzset{ myShape/.style 2 args={ shape=@myShape, minimum size=#1, fill=#2 }, myShape/.default={1cm}{black} } \end{filecontents} \documentclass{article} \usepackage{tikz} \usetikzlibrary{positioning,fit} \usepackage{\jobname} \begin{document} \begin{tikzpicture} \node[draw] (origin) {origin}; \begin{scope}[local bounding box=A1] \node[myShape, right=3cm of origin] {A}; \end{scope} \node[draw,fit=(A1), label=below:{box a}] (box) {}; \end{tikzpicture} \begin{tikzpicture} \node[draw] (origin) {origin}; \begin{scope}[local bounding box=A1] \node[myShape, right=3cm of origin, left] {B}; \end{scope} \node[draw,fit=(A1), label=below:{box b}] (box) {}; \end{tikzpicture} \begin{tikzpicture} \node[draw] (origin) {origin}; \begin{scope}[local bounding box=A1] \node[myShape] (s) at (3,0) {C}; \path [fill=red] (s.center) circle (.5pt); \end{scope} \node[draw,fit=(A1), label=below:{box c}] (box) {}; \end{tikzpicture} \end{document} 
3
  • Oh nice fix. Not sure if you have experience with the makeshape package: I wonder if it would make sense to pgfinterruptboundingbox before/after the anchorborder in general (I guess capturing the paths in the bounding box is not the desired behavior in general, is it?) Commented Sep 11 at 20:58
  • @atticus I've never used the package - actually, I'd never heard of it before your question. but it is hard to see why you'd want the anchors to contribute to the bounding box at that point. I mean pgf does things in a particular order for particular reasons and generally the result is intuitively 'right'. when it isn't, violating it makes sense. but here? put it this way: there is probably a reason this isn't how pgf says how to declare a new node shape ;). but I don't know if there might be other side-effects, since makeshape makes a fairly fundamental change here. Commented Sep 11 at 22:33
  • Generally I agree. The way pgf works here is quite good described / comprehensible. Still in the case of the anchorborder I see why people want to simplify the process by not calculating manually, instead just describe the outer border and the package does the rest for you (especially if the shape gets more complex and is not a simple rectangle). Commented Sep 12 at 15:46

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.