5

I am trying to create some basic optic elements (a beam splitter in this case) to be used in PGF/TikZ. Well, since I am quite new to PGF/TikZ (and even LaTeX), there is something I am not quite sure. The shape I want to create is almost as same as the predefined rectangle shape, except including an extra diagonal. My question is could I just append some code to the backgroudpath inherited from the predefined shape while not overwrite them, rather than copying all the predefined backgroundpath code together with my appending code?

Although I got some ideas from the example on page 631 in pgfmanual version 2.10. The shape I already created seemed working fine

enter image description here

The code I am using is:

\documentclass{article}
\usepackage{pgf}    % pgfcore, modules shapes and plot
\usepackage{tikz}

\makeatletter
\pgfdeclareshape{bs}{
  \inheritsavedanchors[from=rectangle]
  \inheritanchorborder[from=rectangle]

  \inheritbehindbackgroundpath[from=rectangle]
  \inheritbackgroundpath[from=rectangle]
  \inheritbeforebackgroundpath[from=rectangle]
  \inheritbehindforegroundpath[from=rectangle]
  \inheritforegroundpath[from=rectangle]
  \inheritbeforeforegroundpath[from=rectangle]  
  \inheritanchor[from=rectangle]{center}
  \inheritanchor[from=rectangle]{north}
  \inheritanchor[from=rectangle]{south}
  \inheritanchor[from=rectangle]{west}
  \inheritanchor[from=rectangle]{east}  

  \backgroundpath{
    % store lower left 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
    \pgfpathmoveto{\pgfpoint{\pgf@xa}{\pgf@ya}}
    \pgfpathlineto{\pgfpoint{\pgf@xa}{\pgf@yb}}
    \pgfpathlineto{\pgfpoint{\pgf@xb}{\pgf@yb}}
    \pgfpathlineto{\pgfpoint{\pgf@xb}{\pgf@ya}}
    \pgfpathclose   
    % add diagonal
    \pgfpathmoveto{\pgfpoint{\pgf@xa}{\pgf@ya}}
    \pgfpathlineto{\pgfpoint{\pgf@xb}{\pgf@yb}}
}   
}

\makeatother
\begin{document}
\begin{tikzpicture}
  \draw[help lines] (-1,-1) grid (1,1);
  \node[shape=bs,draw,minimum size=1cm,label=below:BS] (x) {};
\end{tikzpicture}
\end{document}

However if I try to remove the code for constructing rectangle and only leaving the diagonal code in \backgroundpath{} environment. I got a shape like following. It seemed this action has overwritten the inherited backgroundpath.

enter image description here

The code for above shape is:

\documentclass{article}
\usepackage{pgf}    % pgfcore, modules shapes and plot
\usepackage{tikz}

\makeatletter
\pgfdeclareshape{bs}{
  \inheritsavedanchors[from=rectangle]
  \inheritanchorborder[from=rectangle]

  \inheritbehindbackgroundpath[from=rectangle]
  \inheritbackgroundpath[from=rectangle]
  \inheritbeforebackgroundpath[from=rectangle]
  \inheritbehindforegroundpath[from=rectangle]
  \inheritforegroundpath[from=rectangle]
  \inheritbeforeforegroundpath[from=rectangle]  
  \inheritanchor[from=rectangle]{center}
  \inheritanchor[from=rectangle]{north}
  \inheritanchor[from=rectangle]{south}
  \inheritanchor[from=rectangle]{west}
  \inheritanchor[from=rectangle]{east}  

  \backgroundpath{
    % store lower left 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
    %\pgfpathmoveto{\pgfpoint{\pgf@xa}{\pgf@ya}}
    %\pgfpathlineto{\pgfpoint{\pgf@xa}{\pgf@yb}}
    %\pgfpathlineto{\pgfpoint{\pgf@xb}{\pgf@yb}}
    %\pgfpathlineto{\pgfpoint{\pgf@xb}{\pgf@ya}}
    %\pgfpathclose  
    % add diagonal
    \pgfpathmoveto{\pgfpoint{\pgf@xa}{\pgf@ya}}
    \pgfpathlineto{\pgfpoint{\pgf@xb}{\pgf@yb}}
}   
}

\makeatother
\begin{document}
\begin{tikzpicture}
  \draw[help lines] (-1,-1) grid (1,1);
  \node[shape=bs,draw,minimum size=1cm,label=below:BS] (x) {};
\end{tikzpicture}
\end{document}

Since Till Tantau said the code for the shape rectangle may be quite complicated in reality (and thus may be more stable, fast and flexible?), so that is why I try to inherit the original backgroundpath with my extra diagonal code appended. Any suggestions or help will be truly appreciated:)

  • Welcome to TeX.SX!. It is better to provide a full minimal working example (MWE) both in order to demonstrate what you are trying to do and to help others help you. The MWE should like like \documentclass...\begin{document}...\end{document}, it should compile and contain close to the minimal amount of code needed to explain/demonstrate what you are asking. This saves a lot of time for everyone. – Andrew Oct 15 '14 at 2:39
  • Hi Andrew, thanks for the suggestion. I just modified the post to include a MWE. – Fanpeng Oct 15 '14 at 3:02
  • Just in case you want to draw more complex optical setups: pst-optexp. – Christoph Nov 17 '14 at 16:28
5

When \backgroundpath is used in a shape definition it will overwrite any previous background-path specification inherited or otherwise.

The actual code for the rectangle background path is:

\pgfpathrectanglecorners
{\pgfpointadd{\southwest}{\pgfpoint{\pgfkeysvalueof{/pgf/outer xsep}}{\pgfkeysvalueof{/pgf/outer ysep}}}}
    {\pgfpointadd{\northeast}{\pgfpointscale{-1}{\pgfpoint{\pgfkeysvalueof{/pgf/outer xsep}}{\pgfkeysvalueof{/pgf/outer ysep}}}}}

Which looks a bit unfriendly but is simply taking into account the value of the outer xsep and outer ysep keys.

The code could be copy/pasted into the \backgroundpath code for a new shape or the internal command \pgf@sh@bg@rectangle could be used (it contains the code for background path for the rectangle).

Either way the proposed additional diagonal would also have to take into account the outer sep. I think a possibly more efficient way (i.e., less calls to the PGF mathematical engine) for doing the whole thing would be:

\pgfextract@process\outersep{\pgfpoint{\pgfkeysvalueof{/pgf/outer xsep}}%
  {\pgfkeysvalueof{/pgf/outer ysep}}}%
\pgfextract@process\southwest{\pgfpointadd{\southwest}{\outersep}}%
\pgfextract@process\northeast{\pgfpointadd{\northeast}{\pgfpointscale{-1}{\outersep}}}%
\pgfpathrectanglecorners{\southwest}{\northeast}%
\pgfpathmoveto{\southwest}%
\pgfpathlineto{\northeast}%
  • Dear Mark, thank you so much for your detailed explanation.I replaced my backgroundpath with your code and it works perfectly now (I guess it must be more efficient and flexible).Also I got some idea about PGF/TikZ programming manner from you answer:) Though I did not find how to reward your answer here, please let me know how to make it if possible. BTW, did you dig into the particular library/package to find the \backgroundpath code for rectangle? I didn't find them on the PGF/TikZ manual. Thanks~ – Fanpeng Oct 15 '14 at 6:53
  • The code for the rectangle (and circle) is in pgfmoduleshapes.code.tex. The rest of the shapes are in the files that start with pgflibraryshapes. – Mark Wibrow Oct 15 '14 at 7:01

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.