% \iffalse meta-comment % % makeshape.dtx % 25 January 2013 % % This is version 1.0 of makeshape.dtx % It generates a style file (makeshape.sty), a sample shape (sampleshape.tex), % and a user guide and documentation (makeshape.pdf). % % Generation of the makeshape.sty and sampleshape.tex is with % pdflatex makeshape.ins % which contains % \generate{\file{makeshape.sty} % {\from{makeshape.dtx}{package}}} % \generate{\file{sampleshape.tex} % {\from{makeshape.dtx}{sample}}} % % Generation of makeshape.pdf is with % pdflatex makeshape.dtx % % The \OnlyDescription command is used to suppress implementation % documentation. % % This is part of Silhouette 2.1 % % ----------------------------------------------------------- % \fi % %^^A------------------------------------------------------------------- %^^A .sty file header %^^A------------------------------------------------------------------- % \iffalse %\NeedsTeXFormat{LaTeX2e}[2011/06/27] %^^A - ** Use package version number (not file version) ** %\ProvidesPackage{makeshape} % [2013/01/25 2.1 Making custom shapes for PGF/TikZ] %\RequirePackage{tikz} %\usepgflibrary{intersections} % %^^A------------------------------------------------------------------- %^^A Preamble for documentation %^^A------------------------------------------------------------------- %<*driver> \documentclass[10pt,a4paper]{ltxdoc} \usepackage[T1]{fontenc} \usepackage{lmodern} \usepackage{fancyvrb} \usepackage{enumitem} \usepackage{url} \usepackage{bigstrut} \usepackage[draft]{hyperref} %\usepackage{hyperref} \usepackage{tikz} \usetikzlibrary{patterns} \usetikzlibrary{arrows} \usetikzlibrary{positioning} \usepgflibrary{intersections} \input{sampleshape} % includes makeshape.sty \newcommand{\mnote}[1] {\marginpar{\scriptsize \raggedright #1 }} \newcommand{\pfgManCiteA}{\cite{pgfMan}, \emph{Constructing Paths}, \S71, pp 579-589} \newcommand{\pfgManCiteB}{\cite{pgfMan}, \emph{Declaring New Shapes}, \S75.5, pp 625-631} \EnableCrossrefs \CodelineIndex \RecordChanges \OnlyDescription % comment out for code implementation \begin{document} \DocInput{makeshape.dtx} \end{document} % % \fi % %^^A------------------------------------------------------------------- %^^A Change log... %^^A------------------------------------------------------------------- %^^A %^^A 0.0 - 5 January 2013 % \changes{0.0}{2013/01/05}{ % Experimental - % Develop the style file and a sample shape. % Write the user guide. % Incorporate makeshape.sty generation and documentation. % Generate the samplshape.tex file. % } %^^A %^^A 0.1 - 11 January 2013 % \changes{0.1}{2013/01/11}{ % Experimental - % Fix the sample shape's cardinal anchor points problem by % correcting a bug in the north-east saved anchor. % Correct errors in the user guide and fill in omissions. % \emph{Experimental phase complete.}} %^^A %^^A 25 January 2013 % \changes{1.0}{2013/01/25}{ % Prepare for publication - % Very minor changes made to the style file code. % Standard path commands used in sample shape code. % A lot of the report is rewritten. % An abstract is added, and its contents removed. } %^^A %^^A------------------------------------------------------------------- %^^A Check sums... %^^A------------------------------------------------------------------- % %^^A \CheckSum{0} ^^A no checksum for development % \CheckSum{272} % \CharacterTable % {Upper-case \A\B\C\D\E\F\G\H\I\J\K\L\M\N\O\P\Q\R\S\T\U\V\W\X\Y\Z % Lower-case \a\b\c\d\e\f\g\h\i\j\k\l\m\n\o\p\q\r\s\t\u\v\w\x\y\z % Digits \0\1\2\3\4\5\6\7\8\9 % Exclamation \! Double quote \" Hash (number) \# % Dollar \$ Percent \% Ampersand \& % Acute accent \' Left paren \( Right paren \) % Asterisk \* Plus \+ Comma \, % Minus \- Point \. Solidus \/ % Colon \: Semicolon \; Less than \< % Equals \= Greater than \> Question mark \? % Commercial at \@ Left bracket \[ Backslash \\ % Right bracket \] Circumflex \^ Underscore \_ % Grave accent \` Left brace \{ Vertical bar \| % Right brace \} Tilde \~} % %^^A=========================================================================== %^^A Generate figure files for input into this report %^^A=========================================================================== % %^^A--------------------------------------------------------------------------- %^^A Background path diagram file %^^A--------------------------------------------------------------------------- % \begin{VerbatimOut}[gobble=5]{msbackground.tmp} % %^^A - The background path diagram, part of makeshape,dtx % %^^A - This is a temporary file and should be deleted % %^^A % \begin{tikzpicture}[>=latex',font={\sf \small}] % % %^^A-- diagram 1 -------------------------------------------- % \begin{scope} % % \def\ctbw{88pt} % \def\ctbh{14pt} % % \def\ctbnex{\ctbw/2} % \def\ctbney{\ctbh/2} % % \node (outer) at (0,0) [draw, rectangle, pattern=crosshatch dots, % minimum width=\ctbw+20pt, % minimum height=\ctbh+20pt, % ] {} ; % % \node at (\ctbnex,\ctbney) [circle, fill=white] {}; % % \node (ctb) at (0,0) [draw, rectangle, fill=white, % minimum width=\ctbw, % minimum height=\ctbh, % ] {}; % % \node (ctbne) at (\ctbnex,\ctbney) [draw, circle] {}; % % %^^A - Labels % \node (ctbneLabel) at (4cm,1cm) % [inner sep = 0] {(\verb|\ctbnex|,\verb|\ctbney|)}; % \node (ctbLabel) at (2cm,-1.2cm) % [inner sep = 0] {corrected text box}; % \node (innerLabel) at (-1.8cm,1.2cm) % [] {inner surface}; % \node (outerLabel) at (-2cm,-1.2cm) % [inner sep = 0] {outer surface}; % % \draw [->] (ctbneLabel.south west) -- (ctbne); % \draw [->] (ctbLabel.north west) -- (ctb.320); % \draw [->] (innerLabel.320) -- (ctb.160); % \draw [->] (outerLabel.north east) -- (outer); % % %^^A - xy axis % \draw [dotted] (0,0) -- ++(2.5cm,0); % origin % \draw [dotted] (0,0) -- ++(-2.5cm,0); % origin % \draw [dotted] (0,0) -- ++(0,1cm); % origin % \draw [dotted] (0,0) -- ++(0,-1cm); % origin % % \end{scope} % % %^^A-- diagram 2 -------------------------------------------- % \begin{scope}[yshift=-4cm] % % \def\ctbw{88pt} % \def\ctbh{14pt} % % \def\ctbnex{\ctbw/2} % \def\ctbney{\ctbh/2} % % \node (outer) at (0,0) [draw, rectangle, pattern=crosshatch dots, % minimum width=\ctbw+40pt, % minimum height=\ctbh+40pt, % ] {} ; % % \node at (\ctbnex,\ctbney) [circle, fill=white] {}; % % \node (inner) at (0,0) [draw, rectangle, fill=white, % minimum width=\ctbw+20pt, % minimum height=\ctbh+20pt, % ] {}; % % \node (ctb) at (0,0) [draw, rectangle, fill=white, % minimum width=\ctbw, % minimum height=\ctbh, % ] {}; % % \node at (\ctbnex,\ctbney) [draw, circle] (ctbne) {}; % % %^^A - Labels % \node (ctbneLabel) at (4cm,1cm) % [inner sep = 0] {(\verb|\ctbnex|,\verb|\ctbney|)}; % \node (ctbLabel) at (2cm,-1.5cm) % [inner sep = 0] {corrected text box}; % \node (innerLabel) at (-2cm,-2cm) % [inner sep = 0] {inner surface}; % \node (outerLabel) at (-2.5cm,-1.5cm) % [inner sep = 0] {outer surface}; % % \draw [->] (ctbneLabel.south west) -- (ctbne); % \draw [->] (ctbLabel.north west) -- (ctb.320); % \draw [->] (innerLabel.north east) -- (inner.250); % \draw [->] (outerLabel.north east) -- (outer); % % %^^A - minimum dimensions % \node (a) [coordinate, left=15pt of outer.south west] {}; % \node (b) [coordinate, left=15pt of outer.north west] {}; % \draw [|<->|] (a) -- (b) node [midway,left] {\tt minimum height}; % % \node (c) [coordinate, above=15pt of outer.north west] {}; % \node (d) [coordinate, above=15pt of outer.north east] {}; % \draw [|<->|] (c) -- (d) node [midway,above] {\tt minimum width}; % % %^^A - xy axis % \draw [dotted] (0,0) -- ++(2.8cm,0); % origin % \draw [dotted] (0,0) -- ++(-2.5cm,0); % origin % \draw [dotted] (0,0) -- ++(0,1.2cm); % origin % \draw [dotted] (0,0) -- ++(0,-1.2cm); % origin % % \end{scope} % % \end{tikzpicture} % \end{VerbatimOut} % %^^A--------------------------------------------------------------------------- %^^A Anchor path diagram file %^^A--------------------------------------------------------------------------- % \begin{VerbatimOut}[gobble=5]{msanchor.tmp} % %^^A - The anchor path diagram, part of makeshape,dtx % %^^A - This is a temporary file and should be deleted % %^^A % \begin{tikzpicture}[>=latex',font={\sf \small}] % % \def\ctbw{88pt} % \def\ctbh{14pt} % % \def\ctbnex{\ctbw/2} % \def\ctbney{\ctbh/2} % % %^^A-- diagram 1 -------------------------------------------- % \begin{scope} % % \node (outer) at (0,0) [draw, rectangle, pattern=crosshatch dots, % minimum width=\ctbw+20pt, % minimum height=\ctbh+20pt, % ] {}; % % \node at (\ctbnex,\ctbney) [circle, fill=white] {}; % % \node (ctb) at (0,0) [draw, rectangle, fill=white, % minimum width=\ctbw, % minimum height=\ctbh, % ] {}; % % \node (ctbne) at (\ctbnex,\ctbney) [draw, circle] {}; % % %^^A - Labels % \node (ctbneLabel) at (4cm,1cm) % [inner sep = 0] {(\verb|\ctbnex|,\verb|\ctbney|)}; % \node (ctbLabel) at (2cm,-1.2cm) % [inner sep = 0] {corrected text box}; % \node (spaceLabel) at (-1.8cm,1.2cm) % [] {background path space}; % \node (outerLabel) at (-2.3cm,-1.2cm) % [inner sep = 0] {outer shape surface}; % \node (anchorLabel) at (-1.5cm,-1.7cm) % [inner sep = 0] {anchor surface}; % % \draw [->] (ctbneLabel.south west) -- (ctbne); % \draw [->] (ctbLabel.north west) -- (ctb.320); % \draw [->, shorten >=5pt] (spaceLabel.320) -- (ctb.160); % \draw [->] (outerLabel.north east) -- (outer); % \draw [->] (anchorLabel.north east) -- (outer); % % %^^A - xy axis % \draw [dotted] (0,0) -- ++(2.5cm,0); % origin % \draw [dotted] (0,0) -- ++(-2.5cm,0); % origin % \draw [dotted] (0,0) -- ++(0,1cm); % origin % \draw [dotted] (0,0) -- ++(0,-1cm); % origin % % \end{scope} % % %^^A-- diagram 2 -------------------------------------------- % \begin{scope}[yshift=-5cm] % % \node (anchor) at (0,0) [draw, rectangle, % minimum width=\ctbw+70pt, % minimum height=\ctbh+70pt, % ] {} ; % % \node (outer) at (0,0) [draw, rectangle, pattern=crosshatch dots, % minimum width=\ctbw+40pt, % minimum height=\ctbh+40pt, % ] {} ; % % \node at (\ctbnex,\ctbney) [circle, fill=white] {}; % % \node (inner) at (0,0) [draw, rectangle, fill=white, % minimum width=\ctbw+20pt, % minimum height=\ctbh+20pt, % ] {}; % % \node (ctb) at (0,0) [draw, rectangle, fill=white, % minimum width=\ctbw, % minimum height=\ctbh, % ] {}; % % \node at (\ctbnex,\ctbney) [draw, circle] (ctbne) {}; % % %^^A - Labels % \node (ctbneLabel) at (4.3cm,1cm) % [inner sep = 0] {(\verb|\ctbnex|,\verb|\ctbney|)}; % \node (ctbLabel) at (2cm,-1.8cm) % [inner sep = 0] {corrected text box}; % \node (spaceLabel) at (-3.3cm,-1.8cm) % [inner sep = 0] {background path space}; % \node (outerLabel) at (-2.8cm,-2.3cm) % [inner sep = 0] {outer path surface}; % \node (anchorLabel) at (-2.7cm,-2.8cm) % [inner sep = 0] {anchor path surface}; % % \draw [->] (ctbneLabel.south west) -- (ctbne); % \draw [->] (ctbLabel.north west) -- (ctb.320); % \draw [->, shorten >=4pt] (spaceLabel.north east) -- (inner.210); % \draw [->] (outerLabel.north east) -- (outer.227); % \draw [->] (anchorLabel.north east) -- (anchor); % % %^^A - minimum dimensions % \node (a) [coordinate, left=30pt of outer.south west] {}; % \node (b) [coordinate, left=30pt of outer.north west] {}; % \draw [|<->|] (a) -- (b) node [midway,left] {\tt minimum height}; % % \node (c) [coordinate, above=30pt of outer.north west] {}; % \node (d) [coordinate, above=30pt of outer.north east] {}; % \draw [|<->|] (c) -- (d) node [midway,above] {\tt minimum width}; % % \node (e) [coordinate, left=15pt of anchor.north west] {}; % \draw [<->|] (b) -- (e) node [midway,left] {\tt outer ysep}; % % \node (f) [coordinate, above=15pt of anchor.north east] {}; % \draw [<->|] (d) -- (f) node [right,above] {\hspace{30pt}\tt outer xsep}; % % \draw [dotted] (a) -- ++(30pt,0); % \draw [dotted] (b) -- ++(30pt,0); % \draw [dotted] (c) -- ++(0,-30pt); % \draw [dotted] (d) -- ++(0,-30pt); % % %^^A - xy axis % \draw [dotted] (0,0) -- ++(3cm,0); % origin % \draw [dotted] (0,0) -- ++(-3cm,0); % origin % \draw [dotted] (0,0) -- ++(0,1.2cm); % origin % \draw [dotted] (0,0) -- ++(0,-1.2cm); % origin % % \end{scope} % % \end{tikzpicture} % \end{VerbatimOut} % %^^A=========================================================================== %^^A Start report body %^^A=========================================================================== % % \GetFileInfo{makeshape.sty} % % \title{The {\sf makeshape} package\thanks{ % This document corresponds to \textsf{makeshape}~\fileversion, % dated~\filedate.}\\ % and\\ % A Method for Creating Custom Shapes in PGF} % % \author{Adrian P. Robson\thanks{\texttt{adrian.robson@nepsweb.co.uk}}} % \date{25 January 2013} % % \maketitle % %^^A - Abstract % \vspace{-3ex} % \begin{quote} % The {\sf makeshape} package simplifies writing PGF shapes. % Declaring a custom shape with a correct anchor border can be difficult. % Complex shapes often need complicated calculations to find the touching point % of a connecting line. % This package only requires that a developer write a PGF path describing the % anchor border. % It also provides macros that help with the management of shape parameters % and the definition of anchor points. % \end{quote} % % %^^A \tableofcontents % %\section{Introduction} % % The |\pgfdeclareshape| command can be used to create new shapes with the PGF package % (\pfgManCiteB). % The following are typically needed: % \begin{itemize} [itemsep=-0.5ex] % \item A shape name. % \item Code for computing saved anchors and saved dimensions. % \item Code for computing anchor positions in terms of the saved anchors. % \item Code for computing border anchors (|\anchorborder|). % \item Code for drawing a background path. % \end{itemize} % Writing these can be hard for completely new shapes, and in particular the declaration of a % suitable |\anchorborder| command can be very difficult for complex shapes. % % \emph{This paper presents a method that makes the process of writing new shapes from scratch % a little easier.} % Its key features are: % a mechanism for specifying the |\anchorborder| behaviour as a path; % a package that provides a set of useful macros for writing and allocating anchor % and background paths; % and an example |\pgfdeclareshape| command that can be used as a template for new shapes. % % The method involves writing some original code and modifying the template. % In brief, the process involves: % \begin{enumerate} [itemsep=-0.5ex] % \item Writing \emph{background path} and \emph{anchor path} macros. % \item Writing one or more \emph{saved anchors}. % \item Writing \emph{anchors} using the above saved anchors. % \end{enumerate} % % % \section{Preliminaries} % % \subsection{Background Path Macro}\label{sec:backgroundpath} % % \begin{figure} % \begin{center} % \input{msbackground.tmp} % \end{center} % \caption{The Background Path}\label{fig:backgroundpath} % \end{figure} % % The \emph{background path}, as illustrated in figure~\ref{fig:backgroundpath}, % describes the curves that form the actual shape. % It can be just a single line and does not have to be closed. % However, there are no limits on is complexity. % If it is more than a simple outline, then its \emph{inner} and \emph{outer} surfaces % need to be considered separately. % % The inner surface should contain the \emph{corrected text box}, % which is the shape's text box surrounded by the space specified by its % {\tt inner xsep} and {\tt inner ysep} keys. % The coordinates of this box are given by the package's |\ctbnex| and |\ctbnex| macros, % which are described in \S\ref{sec:corrctdTextBox}. % % The outer surface should have height and width dimensions that are the same as % the shape's {\tt minimum} {\tt width} and {\tt minimum} {\tt height} % keys if these are larger than the basic dimensions. % These keys can be obtained with the |\pgfshapeminwidth| and |\pgfshapeminheight| macros, % as described in \S\ref{sec:keycommands}. % The |\mincorrect| macro described in \S\ref{sec:mincorrmacro} can be used make the necessary % comparison and assignment. % % \subsubsection{Background Path Algorithm}\label{sec:backgroundpathmacro} % % The background path should be implemented as a macro with the following structure: % \begin{enumerate} % % \item \label{item:ctb} Use |\ctbnex| and |\ctbnex|, % which give the north east corner of the corrected text box, % to calculate significant reference coordinates. % % \item \label{item:mindim} Use |\mincorrect| to modify the reference coordinates to % take account of the shape's minimum dimension keys, % which are given by |\pgfshapeminwidth| and |\pgfshapeminheight|. % % % \item Use the reference coordinates from step \ref{item:mindim} to draw the actual path % using PGF path commands (\pfgManCiteA). Typical commands are % |\pgfpathmoveto|, % |\pgfpathlineto| and % |\pgfpathclose|. % The |\pgfpoint| command will also be needed. % Do this for % \begin{enumerate} % \item the outer surface curve, and \label{item:outer} % \item curves in the shape's inner path space % \end{enumerate} % Usually when a path is defined, it is displayed with |\pgfusepath{stroke}|. % However, it is not needed here. % % \end{enumerate} % % \subsection{Anchor Path Macro}\label{sec:anchorpath} % % The \emph{anchor path}, as illustrated in figure~\ref{fig:anchorpath}, % describes the curve that forms the surface where connecting lines meet the shape. % It it must be a single closed path, and it is normally strongly related to % background path's outer surface (see \S\ref{sec:backgroundpath}). % % Like the background path, it should use the fundamental reference point of the % \emph{corrected text box}, which automatically includes the shape's inner % separation. % It should also take regard of the shape's {\tt minimum} {\tt width} % and {\tt minimum} {\tt height} keys if these are larger than the basic dimensions. % Furthermore, it should compensate for the {\tt outer} {\tt xsep} and {\tt outer} {\tt ysep} % keys as shown in figure~\ref{fig:anchorpath}. % % The corrected text box macros are decribed in \S\ref{sec:corrctdTextBox}. % The minimum dimension keys are given by |\pgfshapeminwidth| and |\pgfshapeminheight|, % and the outer separation keys are given by |\pgfshapeouterxsep| and % |\pgfshapeouterysep|, as described in \S\ref{sec:keycommands}. % The minimum dimension comparision and assignment is provided by |\mincorect| macro, % which is discussed in \S\ref{sec:mincorrmacro}. % % \subsubsection{Anchor Path Algorithm}\label{sec:anchorpathmacro} % % % The anchor path should be implemented as a macro with the following structure: % \begin{enumerate} % % \item Use |\ctbnex| and |\ctbnex|, % which give the north east corner of the corrected text box, % to calculate significant reference coordinates. (Normally the same as % \S\ref{sec:backgroundpathmacro} step \ref{item:ctb}). % \label{item:apctb} % % \item Use |\mincorrect| to modify the reference coordinates to % take account of the shape's minimum dimension keys, % which given by |\pgfshapeminwidth| and |\pgfshapeminheight|. % (Normally the same as \S\ref{sec:backgroundpathmacro} step \ref{item:mindim}). % \label{item:apmindim} % % \item Modify the reference coordinates to take account of outer separation, % which is given by |\pgfshapeouterxsep| and |\pgfshapeouterysep|. % \label{item:apouter} % % \item Use the corrected reference coordinates from step \ref{item:apouter} to specify % the anchor path using PGF path commands (\pfgManCiteA). % The path should be closed so a |\pgfpathclose| command is required. % The path will not actually be drawn, and the |\pgfusepath{stroke}| macro % should not be used. % (Normally the same as \S\ref{sec:backgroundpathmacro} step \ref{item:outer}). % \label{item:appath} % % \end{enumerate} % % \subsection{Anchors} % % A PGF shape requires the definition of a set of anchor point commands, % and these need \emph{saved anchors} to provide necessary coordinates. % All anchor macros should return a point coordinate by assigning values to the % registers |\pgf@x| and |\pgf@y|. % % Like the anchor path macro, saved anchors should use the fundamental reference point of the % \emph{corrected text box}, which automatically includes the shape's inner % separation. % They should also take regard of the shape's {\tt minimum} {\tt width} % and {\tt minimum} {\tt height} keys if these are larger than the basic dimensions. % Furthermore, they should compensate for the {\tt outer} {\tt xsep} and {\tt outer} {\tt ysep} % keys as shown in figure~\ref{fig:anchorpath}. % % The corrected text box macros are decribed in \S\ref{sec:corrctdTextBox}. % The minimum dimension keys are given by |\pgfshapeminwidth| and |\pgfshapeminheight|, % and the outer separation keys are given by |\pgfshapeouterxsep| and % |\pgfshapeouterysep|, as described in \S\ref{sec:keycommands}. % The minimum dimension comparision and assignment is provided by |\mincorect| macro, % which is discussed in \S\ref{sec:mincorrmacro}. % % \begin{figure} % \begin{center} % \input{msanchor.tmp} % \end{center} % \caption{The Anchor Path}\label{fig:anchorpath} % \end{figure} % % \subsubsection{Saved Anchor Algorithm} % % A saved anchor must set the PGF registers |\pgf@x| and |\pgf@y| % with the required coordinates. % It has a structure similar to the anchor path. % % \begin{enumerate} % % \item Use |\ctbnex| and |\ctbnex|, % which give the north east corner of the corrected text box, % to calculate significant reference coordinates. % (Normally similar to \S\ref{sec:anchorpathmacro} step \ref{item:apctb}). % % \item Use |\mincorrect| to modify the reference coordinates to % take account of the shape's minimum dimension keys, % which given by |\pgfshapeminwidth| and |\pgfshapeminheight|. % (Normally the same as \S\ref{sec:anchorpathmacro} step \ref{item:apmindim}). % % \item Modify the reference coordinates to take account of outer separation, % which is given by |\pgfshapeouterxsep| and |\pgfshapeouterxsep|. % (Normally the same as \S\ref{sec:anchorpathmacro} step \ref{item:apouter}). % \label{item:sanchosep} % % \item Use the reference coordinates from step \ref{item:sanchosep} to calculate the % location of the anchor point, and assign values to the |\pgf@x| and |\pgf@y| % registers. % % \end{enumerate} % % \section{Making a Shape} % % \subsection{Helper Macros}\label{sec:macros} % % The following macros are available for use in the anchor path, % background path and saved anchors. % % \subsubsection{Corrected text box}\label{sec:corrctdTextBox} % % The \emph{corrected text box} is a bounding box for the % shape's text that includes the shape's {\tt inner} {\tt xsep} and {\tt inner} {\tt ysep} keys. % The box is symmetric about the origin. % Its x and y coordinates are given by the following commands: % % \begin{description} [itemsep=-0.5ex, labelindent=-0.5em] % % \item[] |\ctbnex|: % The x-coordinate of the north east corner of the shape's corrected text box. % % \item[] |\ctbney|: % The y-coordinate of the north east corner of the shape's % corrected text box. % % \end{description} % % \subsubsection{Correcting for minimum dimensions}\label{sec:mincorrmacro} % % A shape's size should be corrected for its % {\tt minimum} {\tt width} and {\tt minimum} {\tt height} keys. % The |\mincorrect| macro is provided to help with this. % % \begin{description} [itemsep=-0.5ex, labelindent=-0.5em] % % \item[] |\mincorrect{|{\it dimreg\/}|}{|{\it minkey\/}|}|: % Correct an x or y outer bound dimension for {\tt minimum} {\tt width} or % {\tt minimum} {\tt height} keys. % % \vspace{-1.5ex} % \begin{description} % % \item[{\it dimreg} \rm --] A dimension register. % On entry, it should hold the normal dimension of the shape. % On exit, $dimreg$ is assigned the larger of its original value or $minkey/2$. % % \item[{\it minkey} \rm--] A minimum dimension key value. % In practice, one of the minimum height or width commands given in % \S\ref{sec:keycommands} below. % % \end{description} % % \end{description} % % \subsubsection{Getting key values}\label{sec:keycommands} % % The shape's key values can be accesses with the following commands: % % \begin{center} % \begin{tabular}{ll} % \hline % key & command \bigstrut\\\hline % {\tt minimum} {\tt width} & |\pgfshapeminwidth| \bigstrut[t]\\ % {\tt minimum} {\tt height} & |\pgfshapeminheight| \\ % {\tt outer} {\tt xsep} & |\pgfshapeouterxsep| \\ % {\tt outer} {\tt ysep} & |\pgfshapeouterysep| \bigstrut[b]\\\hline % \end{tabular} % \end{center} % % \noindent % The outer separation keys are not relevant to the background path, % but should be used by the anchor path and saved anchors. % % The shape's inner separation keys are automatically included in the \emph{corrected text box} % coordinates |\ctbnex| and |\ctbney|. % % \subsubsection{Testing support} % % There are a couple of macros can be used in the background path to delineate a % shape's text box during development: %\begin{description}[nosep] % \item[{\tt \textbackslash path@textbox}] draws a line around the the shape's text % that is the uncorrected text box. % \item[{\tt \textbackslash path@ctextbox}] shows the shape's corrected text box, % which includes inner separation. % \end{description} % These macros should not be used in `production' shapes. % % \subsection{Procedure} % % The procedure in outline for making a new shape is as follows: % \medskip % % \begin{enumerate}[nosep] % \item Create the border path % \item Create the anchor path %\item Declare the shape % \begin{enumerate}[nosep] % \item Use |\setpaths| to employ the paths % \item Create the anchors % \end{enumerate} % \end{enumerate} % \medskip % % The sample shape given in \S\ref{sec:samplecode} can be used as a template to % create a new shape. % The code can be copied from there, or it can be acquired as the file |sampleshape.tex|, % which is part of the package's distribution. % % The procedure for adapting the template code is as follows: % \begin{enumerate} % % \item Change the name of the shape in the |\pgfdeclareshape| command % from `{\tt sample}' to the name of the new shape. % % \item \label{item:steppaths} Write \emph{anchor path} and \emph{background path} macros. % % These and any sub macros are placed at the start of the file and replace % the sample |\sampleanchor| and |\sampleborder| macros. % % As discussed in \S\ref{sec:backgroundpath} and \S\ref{sec:anchorpath}, % the background path should take account of the minimum dimension keys, % and the anchor path should handle the minimum keys, and outer % separation. % The macros given in \S\ref{sec:macros} are provided to help with this, % and the sample code gives an indication of how they can be used. % % \item Change the arguments of |\setpaths| in the template to the macros written % in step \ref{item:steppaths}. % The first is the anchor path and the second is the background path. % % \item \label{item:stepsavedanchors} Write the saved anchors that will needed by the anchors % written in step~\ref{item:stepanchors}. % % Saved anchors, like the anchor path written in step \ref{item:steppaths}, % should correct for outer separation, and minimum dimensions % using the macros in \S\ref{sec:macros}. % They should set the |\pgf@x| and |\pgf@y| registers. % % \item \label{item:stepanchors} % Write anchors that set |\pgf@x| and |\pgf@y| registers using % the saved anchors from step \ref{item:stepsavedanchors}. % % \begin{enumerate} % % \item Write anchors for the cardinal and sub cardinal points: % % \begin{VerbatimOut}[gobble=5]{\jobname.tmp} % \anchor{north}{ ... } % \anchor{north east}{ ... } % \anchor{east}{ ... } % \anchor{south east}{ ... } % \anchor{south}{ ... } % \anchor{south west}{ ... } % \anchor{west}{ ... } % \anchor{north west}{ ... } % \end{VerbatimOut} % \VerbatimInput{\jobname.tmp} % % \item Write any additional anchors that the shape needs. % % \end{enumerate} % % \end{enumerate} % % The PGF registers used throughout this method of declaring new shapes have the % |@| character in their names. % Unfortunately, this character has a special role in \LaTeX{}. % So either the |\makeatletter| and |\makeatother| commands must be used as in % |sampleshape.tex|, or the shape must be defined in a |sty| file. % % \section{Path and Anchor Examples} % % Here an example of an actual shape that is implemented using the {\sf makeshape} method: % % \bigskip % % \begin{tikzpicture}%[>=latex',font={\sf \small}] % \node at (0,0) [draw, sample, % minimum width=2cm, % minimum height=1cm] {}; % \end{tikzpicture} % \bigskip % % Its background path, anchor path, and anchor points use a common macro that gives % the space between the outer and inner boundaries of the shape. % % \begin{VerbatimOut}[gobble=5]{\jobname.tmp} % \def\gap{4pt} % \end{VerbatimOut} % \VerbatimInput{\jobname.tmp} % % \subsection{Background Path}\label{sec:backgroundpathexmpl} % % In this example, the background path macro is called {\tt sampleshape}. % \begin{VerbatimOut}[gobble=5]{\jobname.tmp} % \def\sampleshape{ % \end{VerbatimOut} % \VerbatimInput[numbers=left]{\jobname.tmp} % First we get the corrected text box coordinates, % and add space for the shape using the |\gap| macro. % \begin{VerbatimOut}[gobble=5]{\jobname.tmp} % \pgf@xa=\ctbnex % \pgf@ya=\ctbney % \advance\pgf@xa by \gap % \advance\pgf@ya by \gap % \end{VerbatimOut} % \VerbatimInput[numbers=left, firstnumber=2]{\jobname.tmp} % Then the standard correction for minimum size is applied using the |\mincorrect| macro. % \begin{VerbatimOut}[gobble=5]{\jobname.tmp} % \mincorrect{\pgf@xa}{\pgfshapeminwidth} % \mincorrect{\pgf@ya}{\pgfshapeminheight} % \end{VerbatimOut} % \VerbatimInput[numbers=left, firstnumber=6]{\jobname.tmp} % Using these coordinates the outer boundary of the shape can be drawn % \begin{VerbatimOut}[gobble=5]{\jobname.tmp} % \pgfpathmoveto{\pgfpoint{\pgf@xa}{\pgf@ya}} % \pgfpathlineto{\pgfpoint{\pgf@xa}{-\pgf@ya}} % \pgfpathlineto{\pgfpoint{-\pgf@xa}{-\pgf@ya}} % \pgfpathlineto{\pgfpoint{-\pgf@xa}{\pgf@ya}} % \pgfpathclose % \end{VerbatimOut} % \VerbatimInput[numbers=left, firstnumber=8]{\jobname.tmp} % Finally, the reference coordinates are moved to the inner boundary and the shape is completed % \begin{VerbatimOut}[gobble=5]{\jobname.tmp} % \advance\pgf@xa by -\gap % \advance\pgf@ya by -\gap % \pgfpathmoveto{\pgfpoint{\pgf@xa}{\pgf@ya}} % \pgfpathlineto{\pgfpoint{\pgf@xa}{-\pgf@ya}} % \pgfpathlineto{\pgfpoint{-\pgf@xa}{-\pgf@ya}} % \pgfpathlineto{\pgfpoint{-\pgf@xa}{\pgf@ya}} % \pgfpathclose % } % \end{VerbatimOut} % \VerbatimInput[numbers=left, firstnumber=13]{\jobname.tmp} % % \subsection{Anchor Path}\label{sec:anchorpathexmpl} % % The shape's anchor path macro called {\tt sampleanchor}, % and is similar to the path macro in \S\ref{sec:backgroundpathexmpl}, % but it also handles outer separation. % \begin{VerbatimOut}[gobble=5]{\jobname.tmp} % \def\sampleanchor{ % \end{VerbatimOut} % \VerbatimInput[numbers=left]{\jobname.tmp} % First we get the corrected text box coordinates, and add space for the shape using % the |\gap| macro. % \begin{VerbatimOut}[gobble=5]{\jobname.tmp} % \pgf@xa=\ctbnex % \pgf@ya=\ctbney % \advance\pgf@xa by \gap % \advance\pgf@ya by \gap % \end{VerbatimOut} % \VerbatimInput[numbers=left, firstnumber=2]{\jobname.tmp} % Then corrections for minimum size and outer separation are applied: % \begin{VerbatimOut}[gobble=5]{\jobname.tmp} % \mincorrect{\pgf@xa}{\pgfshapeminwidth} % \advance\pgf@xa\pgfshapeouterxsep % \mincorrect{\pgf@ya}{\pgfshapeminheight} % \advance\pgf@ya\pgfshapeouterysep % \end{VerbatimOut} % \VerbatimInput[numbers=left, firstnumber=6]{\jobname.tmp} % Using these coordinates the anchor boundary path is finally drawn % \begin{VerbatimOut}[gobble=5]{\jobname.tmp} % \pgfpathmoveto{\pgfpoint{\pgf@xa}{\pgf@ya}} % \pgfpathlineto{\pgfpoint{\pgf@xa}{-\pgf@ya}} % \pgfpathlineto{\pgfpoint{-\pgf@xa}{-\pgf@ya}} % \pgfpathlineto{\pgfpoint{-\pgf@xa}{\pgf@ya}} % \pgfpathclose % } % \end{VerbatimOut} % \VerbatimInput[numbers=left, firstnumber=10]{\jobname.tmp} % % \subsection{Shape Declaration and Anchor Points} % % The {\tt sample} shape declaration is started with % \begin{VerbatimOut}[gobble=5]{\jobname.tmp} % \pgfdeclareshape{sample}{ % \end{VerbatimOut} % \VerbatimInput[numbers=left]{\jobname.tmp} % Then the shape and anchor paths, which were defined in \S\ref{sec:backgroundpathexmpl} % and \S\ref{sec:anchorpathexmpl}, are employed with % \begin{VerbatimOut}[gobble=5]{\jobname.tmp} % \setpaths{\sampleanchor}{\sampleshape} % \end{VerbatimOut} % \VerbatimInput[numbers=left, firstnumber=2]{\jobname.tmp} % % \subsubsection{Anchors} % % Next in the shape's declaration are its saved anchors. % In this case, we establish the north east anchor location with code that is equivalent % to the first part of the anchor path macro (\S\ref{sec:anchorpathexmpl}). % Note how the anchor point's coordinate is returned in |\pgf@x| and |\pgf@y|. % \begin{VerbatimOut}[gobble=5]{\jobname.tmp} % \savedanchor{\northeast}{ % \pgf@x = \ctbnex % \pgf@y = \ctbney % \advance\pgf@xa by \gap % \advance\pgf@ya by \gap % \mincorrect{\pgf@x}{\pgfshapeminwidth} % \mincorrect{\pgf@y}{\pgfshapeminheight} % \advance\pgf@x\pgfshapeouterxsep % \advance\pgf@y\pgfshapeouterysep % } % \end{VerbatimOut} % \VerbatimInput[numbers=left, firstnumber=3]{\jobname.tmp} % % \noindent % The saved anchor is then used to construct the shape's anchors, % and the declaration is ended as follows: % % \begin{VerbatimOut}[gobble=5]{\jobname.tmp} % \anchor{north}{\northeast \pgf@x=0pt} % \anchor{north east}{\northeast} % \anchor{east}{\northeast \pgf@y=0pt} % \anchor{south east}{\northeast \pgf@y=-\pgf@y} % \anchor{south}{\northeast \pgf@x=0pt \pgf@y=-\pgf@y} % \anchor{south west}{\northeast \pgf@x=-\pgf@x \pgf@y=-\pgf@y} % \anchor{west}{\northeast \pgf@x=-\pgf@x \pgf@y=0pt} % \anchor{north west}{\northeast \pgf@x=-\pgf@x} % } % \end{VerbatimOut} % \VerbatimInput[numbers=left, firstnumber=13]{\jobname.tmp} % % % \subsection{Sample Shape Code}\label{sec:samplecode} % % The following is a full listing of the code needed to make the sample shape % described above. % It can be used as a templete for new shapes. % A copy of this code can be found in the the file {\tt sampleshape.tex}, % which is included in the package's distribution. % Note the use of the |\makeatletter| and |\makeatother| commands, which are required % because the sample shape is in a |tex| file. % %^^A - Code must be < 67 characters to fit on page at 10pt ... % \VerbatimInput[ ^^A numbers=left, % firstline=40, lastline=127]{sampleshape} % % %^^A=========================================================================== %^^A References %^^A=========================================================================== % %^^A - Used in \StopEventually ... % % \def\printBib{ % \begin{thebibliography}{9} % \raggedright % % \bibitem{pgfMan} % Till Tantau, % \emph{The TikZ and PGF Packages, Manual for version 2.10}, % 2010. % Available as % \href{http://mirrors.ctan.org/graphics/pgf/base/doc/generic/pgf/pgfmanual.pdf} % {\tt pgfmanual.pdf} % from the \href{http://ctan.org}{Comprehensive TeX Archive Network}. % %^^A in pgfMan \emph{Constructing Paths}, section 71, pp 579-589. %^^A in pgfMan \emph{Declaring New Shapes}, section 75.5, pp 625-631. % % \end{thebibliography} % } % % %^^A=========================================================================== %^^A Start code implementation %^^A=========================================================================== % % \StopEventually{ \printBib } %^^A \StopEventually{ \printBib \PrintChanges } %^^A -> Run pdfLaTeX makeshape.dtx %^^A makeindex -s gglo.ist -o makeshape.gls makeshape.glo %^^A pdfLaTeX makeshape.dtx % % \section{Implementation} % % \subsection{Text Box Calculations}\label{sec:textboxcalc} % % The shape's text is at its centre for shape's made with this package. % The text box position is defined by the shape's |text| anchor, which must give the coordinate % of the west end of the text's base line. % PGF provides three useful dimensions: % % \smallskip % \begin{tabular}{lll} % |\wd\pgfnodeparttextbox| & width & $wd$\\ % |\ht\pgfnodeparttextbox| & height & $ht$\\ % |\dp\pgfnodeparttextbox| & depth & $dp$\\ % \end{tabular} % % \smallskip\noindent % These are related as follows: % \medskip % %^^A---------------------------------- %^^A- Text box diagram - start %^^A---------------------------------- % \begin{tikzpicture}[>=latex',font={\sf \small}] % % \def\tbht{30pt} ^^A - text box height % \def\tbdp{15pt} ^^A - text box depth % \def\tbwd{150pt} ^^A - text box width % % \def\blwx{-\tbwd/2} ^^A - baseline west x % \def\blwy{-\tbht/2+\tbdp/2} ^^A - baseline west y % % \def\tbnex{\tbwd/2} ^^A - text box north east x % \def\tbney{\tbht/2+\tbdp/2} ^^A - text box north east y % % \node (textbox) at (0,0) [draw, rectangle, fill=white, % minimum width=\tbwd, % minimum height=\tbht+\tbdp, % ] {}; % \draw [] (\blwx,\blwy) -- ++(\tbwd,0); % % \node (textanchor) [coordinate] at (\blwx,\blwy){}; % % \node at (textanchor) [draw, circle] (blinewest) {}; % %^^A - Labels % \node (blinelable) at (3.5cm,\blwy) [inner sep = 0] {baseline}; % \node (textanchlabel) at (\blwx+28pt,\blwy+8pt) [inner sep = 0] {text anchor}; % %^^A - Dimensions % \node (hta) [coordinate, left=15pt of textbox.south west] {}; % \node (htc) [coordinate, left=15pt of textbox.north west] {}; % \node (htb) [coordinate, left=15pt of textanchor] {}; % \draw [|<->|] (hta) -- (htb) node [midway,left] {depth}; % \draw [<->|] (htb) -- (htc) node [midway,left] {height}; % \node (wda) [coordinate, above=10pt of textbox.north west] {}; % \node (wdb) [coordinate, above=10pt of textbox.north east] {}; % \draw [|<->|] (wda) -- (wdb) node [midway,above] {width}; % %^^A - xy axis % \def\xaxisdim{0.5cm} % \def\yaxisdim{0.5cm} % \draw [dotted] (0,0) -- ++(\xaxisdim,0); ^^A - origin % \draw [dotted] (0,0) -- ++(-\xaxisdim,0); ^^A - origin % \draw [dotted] (0,0) -- ++(0,\yaxisdim); ^^A - origin % \draw [dotted] (0,0) -- ++(0,-\yaxisdim); ^^A - origin % % \end{tikzpicture} %^^A---------------------------------- %^^A- Text box diagram - end %^^A---------------------------------- %\medskip % % For this box to be centred on the origin, we need to calculate suitable coordinates for % the |text| anchor. % So, if the box's south west corner is at $(x_{sw},y_{sw})$ and the box is centred, then % $x_{sw} = -wd/2$ and $y_{sw}=-(ht+dp)/2$. % If the |text| anchor is at $(x_{text},y_{text})$, then % \vspace{-2ex} %\begin{eqnarray} % x_{text} & = & x_{sw} = -\frac{wd}{2}\label{eqn:xtext}\\ % y_{text} & = & y_{sw} + dp = -\frac{ht}{2} - \frac{dp}{2} + dp % = \frac{dp}{2} - \frac{ht}{2} \label{eqn:ytext} %\end{eqnarray} % % Furthermore, the shape's north east corner $(x_{ne},y_{ne})$ is at %\begin{eqnarray} % x_{ne} & = & \frac{wd}{2} \label{eqn:xne}\\[1ex] % y_{ne} & = & \frac{ht+dp}{2} \label{eqn:yne} %\end{eqnarray} % %\iffalse %<*package> %\fi % %\subsection{Symetric bounding box}\label{sec:symbbox} % % We require a rectangle that contains the anchor path, and has its centre at the origin. % Such a rectangle, defined by the coordinate of its north east corner, is needed % in the anchor border algorithm described in \S\ref{sec:anchoralgorithm}. % % \vspace{2ex} % %^^A---------------------------------- %^^A- Bounding box diagram - start %^^A---------------------------------- % \begin{tikzpicture}[>=latex',font={\sf \small}] % % \def\bbnex{60pt} ^^A - box ne x % \def\bbney{30pt} ^^A - box ne y % % \node (boundingbox) at (0,0) [draw, rectangle, dashed, % minimum width=2*\bbnex, % minimum height=2*\bbney, % ] {}; % % \node at (\bbnex,\bbney) [draw, circle] (boxne) {}; % % \def\nx{0pt} \def\ny{20pt} % \def\ex{30pt} \def\ey{-10pt} % \def\sx{-20pt} \def\sy{-\bbney} % \def\wx{-\bbnex} \def\wy{10pt} % %^^A - Anchor path % \draw [] (\nx,\ny) -- (\ex,\ey); % \draw [] (\ex,\ey) -- (\sx,\sy); % \draw [] (\sx,\sy) -- (\wx,\wy); % \draw [] (\wx,\wy) -- (\nx,\ny); % %^^A - mins and maxs with labels % \draw [dotted] (\nx,\ny) -- (\bbnex+10pt,\ny); % \draw [dotted] (\bbnex,\sy) -- (\bbnex+10pt,\sy); % \draw [dotted] (\ex,\ey) -- (\ex,-\bbney-10pt); % \draw [dotted] (\wx,-\bbney) -- (\wx,-\bbney-10pt); % \node (maxy) at (\bbnex+24pt,\ny) [inner sep = 0] {$y_{max}$}; % \node (miny) at (\bbnex+24pt,\sy) [inner sep = 0] {$y_{min}$}; % \node (maxx) at (\wx,-\bbney-16pt) [inner sep = 0] {$x_{min}$}; % \node (maxx) at (\ex,-\bbney-16pt) [inner sep = 0] {$x_{max}$};% % %^^A - Labels % \node (path) at (\wx-40pt,\wy-32pt) [inner sep = 0] {anchor path}; % \draw [->] (path.east) -- (-40pt,-10pt); % \node (box) at (\wx-40pt,\wy+13pt) [inner sep = 0] {bounding box}; % \draw [->] (box.east) -- (\wx,23pt); % \node (bbne) at (\bbnex+25pt,\bbney+10pt) [inner sep = 0] {$(x_{ne},y_{ne})$}; % %^^A - xy axis % \def\xaxisdim{0.2cm} % \def\yaxisdim{0.2cm} % \draw [] (0,0) -- ++(\xaxisdim,0); ^^A - origin % \draw [] (0,0) -- ++(-\xaxisdim,0); ^^A - origin % \draw [] (0,0) -- ++(0,\yaxisdim); ^^A - origin % \draw [] (0,0) -- ++(0,-\yaxisdim); ^^A - origin % % \end{tikzpicture} %^^A---------------------------------- %^^A- Bounding box diagram - end %^^A---------------------------------- % % \medskip % The \emph{symmetric bounding box} is defined by the coordinate of its north east corner: % \vspace{-3ex} % \begin{eqnarray} % x_{ne} &=& \max{(\vert x_{min} \vert \, ,\vert x_{max} \vert )} \label{eqn:bbx}\\ % y_{ne} &=& \max{(\vert y_{min} \vert \, ,\vert y_{max} \vert )} \label{eqn:bby} % \end{eqnarray} % % \subsection{The Anchor Border Algorithm}\label{sec:anchoralgorithm} % % A shape's |\anchorborder| command must calculate the intersection of a line drawn % between the origin and a target point, and the shape's border. % The aim here is to do this calculation using an \emph{anchor path} that describes % the shapes outer border. % % The |\pgfintersectionofpaths| command can be used to do this, but it will only work % for points that are outside the anchor path. % The solution is to \emph{externalise the point} using the |\pgfpointborderrectangle| command. % % \bigskip %^^A------------------------------------------------ %^^A- Anchor border point algorithm diagram - start %^^A------------------------------------------------ % \begin{tikzpicture}[>=latex',font={\sf \small}] % %^^A - xy axis % \def\xaxisdim{0.2cm} % \def\yaxisdim{0.2cm} % \draw [] (0,0) -- ++(-\xaxisdim,0); ^^A - origin % \draw [] (0,0) -- ++(0,\yaxisdim); ^^A - origin % \draw [] (0,0) -- ++(0,-\yaxisdim); ^^A - origin % \filldraw[white] (0,0) circle (2pt); % %^^A - Bounding box % \def\bbnex{60pt} ^^A - box ne x % \def\bbney{30pt} ^^A - box ne y % % \node (boundingbox) at (0,0) [draw, rectangle, dashed, % minimum width=2*\bbnex, % minimum height=2*\bbney, % ] {}; % % \draw ((\bbnex,\bbney) circle (2pt); % %^^A - Anchor path % \def\nx{30pt} \def\ny{20pt} % \def\ex{50pt} \def\ey{-20pt} % \def\sx{-20pt} \def\sy{-\bbney} % \def\wx{-\bbnex} \def\wy{10pt} % % \def\apath{ % \pgfpathmoveto{\pgfpoint{\nx}{\ny}} % \pgfpathlineto{\pgfpoint{\ex}{\ey}} % \pgfpathlineto{\pgfpoint{\sx}{\sy}} % \pgfpathlineto{\pgfpoint{\wx}{\wy}} % \pgfpathclose } % %^^A - Draw the anchor path % \apath % \pgfusepath{stroke} % %^^A - Target point and vectors % \def\tx{20pt} % \def\ty{5pt} % \def\endx{3.5*\tx} % \def\endy{3.5*\ty} % % \draw [] (0,0) -- (\tx,\ty); % \draw [dotted] (\tx,\ty) -- (\endx,\endy); % \filldraw (\tx,\ty) circle (2pt); % %^^A - Intersection with bounding box % \pgfpathcircle{\pgfpointborderrectangle{\pgfpoint{\tx}{\ty}} % {\pgfpoint{\bbnex}{\bbney}}}{2pt} % \pgfusepath{stroke} % %^^A - intersection with anchor path % \pgfintersectionofpaths{\apath} % { \pgfpathmoveto{\pgfpoint{0}{0}} % \pgfpathlineto{\pgfpoint{\endx}{\endy}} } % \pgfpathcircle{\pgfpointintersectionsolution{1}}{2pt} % \pgfusepath{stroke} % %^^A - Labels % \node (path) at (\wx-40pt,\wy-32pt) [inner sep = 0] {anchor path}; % \draw [->] (path.east) -- (-40pt,-10pt); % \node (box) at (\wx-40pt,\wy+13pt) [inner sep = 0] {bounding box}; % \draw [->] (box.east) -- (\wx,23pt); % \node (p1) at (\tx+5pt,\ty-8pt) [inner sep = 0] {p1}; % \node (p2) at (\bbnex+10pt,\bbney+5pt) [inner sep = 0] {p2}; % \node (p3) at (\bbnex+10pt,8pt) [inner sep = 0] {p3}; % \node (p4) at (40pt,18pt) [inner sep = 0] {p4}; % %^^A - point key %^^A \def\pkeyx{90pt} %^^A \def\pkeyy{10pt} %^^A \def\pkeystep{-10pt} %^^A \node (key1) at (\pkeyx,\pkeyy) [right, inner sep = 0] {p1 = target point}; %^^A \node (key2) at (\pkeyx,\pkeyy+\pkeystep) [right, inner sep = 0] {p2 = bounding box corner}; %^^A \node (key3) at (\pkeyx,\pkeyy+2*\pkeystep) [right, inner sep = 0] %^^A {p3 = bounding box intersection}; %^^A \node (key4) at (\pkeyx,\pkeyy+3*\pkeystep) [right, inner sep = 0] %^^A {p4 = anchor path intersection}; % % \end{tikzpicture} %^^A------------------------------------------------ %^^A- Anchor border point algorithm diagram - end %^^A------------------------------------------------ % %\bigskip % %\begin{description} % % \item[Step 1 - Externalise the target point] % % The vector to the target point {\sf p1} is extended to the bounding box to find % the intersection {\sf p3}. % The bounding box is by definition outside the anchor path. % Thus point {\sf p3} must also be outside the anchor path. % % To achieve this, the |\pgfpointborderrectangle| command is applied to the target point {\sf p1} % and the centred rectangle defined by {\sf p2}, which is the symmetric bounding box defined % in \S\ref{sec:symbbox}. % % \item[Step 2 - Find the border intersection] % % The line from the origin to the point {\sf p3} passes through {\sf p1}, % and its intersection with the anchor path is the required point {\sf p4}. % % The intersection is found with the |\pgfintersectionofpaths| command, % which takes the anchor path and the path of the line from the origin to {\sf p3} as input. % Since {\sf p3} is always outside the anchor path, such an intersection will always be found. % % \end{description} % % \subsection{Declare Shape Commands} % % \begin{macro}{\setpaths} % The |\setpaths| macro is used in |\pgfdeclareshape| definitions to specify the shape's paths. % It has two parameters: % \begin{description}[nosep] % \item[\tt ~\#1] is a macro defining the anchor path. % \item[\tt ~\#2] is a macro defining the background path. % \end{description} % % \begin{macrocode} \def\setpaths#1#2{ % \end{macrocode} % % \noindent % It defines saved macros for use in the shape's path macros and saved anchors. % There are also macros defined that are only used within the packages other macros. % % \subsubsection{Corrected text box saved macros} % % These two saved macros give the x and y coordinates of the corrected text box's north east corner. % They are invoked by users of the package to define a shape's path macros. % % \begin{macro}{\ctbnex} % The |\ctbnex| saved macro gives the x-coordinate, % which is calculated as described by equation \ref{eqn:xne} in \S\ref{sec:textboxcalc}. % \begin{macrocode} \savedmacro\ctbnex{ \pgf@x=.5\wd\pgfnodeparttextbox \pgfmathsetlength\pgf@xa{\pgfshapeinnerxsep} \advance\pgf@x\pgf@xa \edef\temp@x{\the\pgf@x} \let\ctbnex\temp@x } % \end{macrocode} % \end{macro} % % \begin{macro}{\ctbney} % The y-coordinate is given by the |\ctbney| saved macro, % which implements equation \ref{eqn:yne} in \S\ref{sec:textboxcalc}. % \begin{macrocode} \savedmacro\ctbney{ \pgf@y=.5\ht\pgfnodeparttextbox \advance\pgf@y.5\dp\pgfnodeparttextbox \pgfmathsetlength\pgf@ya{\pgfshapeinnerysep} \advance\pgf@y\pgf@ya \edef\temp@y{\the\pgf@y} \let\ctbney\temp@y } % \end{macrocode} % \end{macro} % % \subsubsection{Key value saved macros} % % These saved macros give the values of significant shape keys. % They have the same names as the standard PGF macros, % and allow the user's anchor and background path macros to use the standard names. % % \begin{macro}{\pgfshapeouterxsep} % The value of the x outer separation key is given by |\pgfshapeouterxsep|. % \begin{macrocode} \savedmacro\pgfshapeouterxsep{ \pgfkeysgetvalue{/pgf/outer xsep}{\temp@sep} \let\pgfshapeouterxsep\temp@sep } % \end{macrocode} % \end{macro} % % \begin{macro}{\pgfshapeouterysep} % The value of the y outer separation key is given by |\pgfshapeouterysep|. % \begin{macrocode} \savedmacro\pgfshapeouterysep{ \pgfkeysgetvalue{/pgf/outer ysep}{\temp@sep} \let\pgfshapeouterysep\temp@sep } % \end{macrocode} % \end{macro} % % \begin{macro}{\pgfshapeminwidth} % The value of the minimum width key is given by |\pgfshapeminwidth|. % \begin{macrocode} \savedmacro{\pgfshapeminwidth}{ \pgfkeysgetvalue{/pgf/minimum width}{\temp@wd} \let\pgfshapeminwidth\temp@wd } % \end{macrocode} % \end{macro} % % \begin{macro}{\pgfshapeminheight} % The value of the minimum height key is given by |\pgfshapeminheight|. % \begin{macrocode} \savedmacro{\pgfshapeminheight}{ \pgfkeysgetvalue{/pgf/minimum height}{\temp@ht} \let\pgfshapeminheight\temp@ht } % \end{macrocode} % \end{macro} % % \subsubsection{Saved anchors}\label{sec:savedanchors} % % The saved anchors are used to implement the anchors provided by the package, % but can be used by the user to define custom anchors if required. % They are required to return the coordinates of a point in |\pgf@x| and |\pgf@y|. % % \begin{macro}{\centre} % The |\centre| saved anchor is used to implement the package |center| anchor. % The |\pgfpointorigin| command sets |\pgf@x| and |\pgf@y|. % \begin{macrocode} \savedanchor{\centre}{ \pgfpointorigin } % \end{macrocode} % \end{macro} % % \begin{macro}{\text} % The |\text| saved anchor is used to implement the package |text| anchor. % It gives the coordinate of the west end of the text base line. % The calculation it uses is explained in \S\ref{sec:textboxcalc}. % Equation \ref{eqn:xtext} gives the x-coordinate % and equation \ref{eqn:ytext} gives the y-coordinate. % \begin{macrocode} \savedanchor{\text}{ \pgf@y=-0.5\ht\pgfnodeparttextbox \advance\pgf@y by 0.5\dp\pgfnodeparttextbox \pgf@x=-0.5\wd\pgfnodeparttextbox } % \end{macrocode} % \end{macro} % % \begin{macro}{\boundbox@ne} % The |\boundbox@ne| saved anchor gives the north east corner of the % anchor path's symmetric bounding rectangle (see \S\ref{sec:symbbox}). % \begin{macrocode} \savedanchor{\boundbox@ne}{ % \end{macrocode} % % First clear any existing path, and then execute the anchor path macro given as % the first parameter of |\setpaths|. % \begin{macrocode} \pgfusepath{} #1 % \end{macrocode} % Store the path's minimum and maximum coordinates, and then discard the path. % \begin{macrocode} \pgf@xb=\pgf@pathmaxx \pgf@yb=\pgf@pathmaxy \pgf@xc=\pgf@pathminx \pgf@yc=\pgf@pathminy \pgfusepath{} % \end{macrocode} % % The north east corner x-coordinate of the symmetric bounding box is calculated using % equation \ref{eqn:bbx} from \S\ref{sec:symbbox}. % % \begin{macrocode} \ifdim\pgf@xb<0pt \pgf@xb=-\pgf@xb \fi \ifdim\pgf@xc<0pt \pgf@xc=-\pgf@xc \fi \ifdim\pgf@xb<\pgf@xc \pgf@x=\pgf@xc \else \pgf@x=\pgf@xb \fi % \end{macrocode} % The y-coordinate is calculated with equation \ref{eqn:bby}: % \begin{macrocode} \ifdim\pgf@yb<0pt \pgf@yb=-\pgf@yb \fi \ifdim\pgf@yc<0pt \pgf@yc=-\pgf@yc \fi \ifdim\pgf@yb<\pgf@yc \pgf@y=\pgf@yc \else \pgf@y=\pgf@yb \fi } % \end{macrocode} % \end{macro} % % \subsubsection{Anchors} % % \begin{macro}{center} % \begin{macro}{text} % PGF shapes require |center| and |text| anchors. % They are implemented by the saved anchors |\center| and |\text| (see \ref{sec:savedanchors}), % and in effect centre the shape's text on the origin. % \begin{macrocode} \anchor{center}{\centre} \anchor{text}{\text} % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\anchorborder} % The |\anchorborder| anchor is critically responsible for calculating points on % the shape's boundary % Its algoritm is explained in \S\ref{sec:anchoralgorithm}. % \begin{macrocode} \anchorborder{ % \end{macrocode} % On entry, the coordinates of the target point are supplied in |\pgf@x| and |\pgf@y|, % and these are immediately saved: % \begin{macrocode} \edef\targpointx{\the\pgf@x} \edef\targpointy{\the\pgf@y} % \end{macrocode} % % A couple of settings are needed to support shapes that are not centred on the origin: % \begin{macrocode} \pgf@relevantforpicturesizefalse \pgftransformreset % \end{macrocode} % The first suppresses updating of the picture bounding box and ensures correct positioning % of the shape. % The second stops coordinate transformations being applied, % which is needed for the correct behaviour of points relying on the |\anchorborder| command. % % Start the computation by finding the north east corner of the anchor path's bounding box: % \begin{macrocode} \boundbox@ne \pgf@xa=\pgf@x \pgf@ya=\pgf@y % \end{macrocode} % Perform step 1 of the algorithm described in \S\ref{sec:anchoralgorithm} to externalise % the target to a point on the bounding box: % \begin{macrocode} \pgfpointborderrectangle{\pgfpoint{\targpointx}{\targpointy}} {\pgfpoint{\pgf@xa}{\pgf@ya}} \edef\corrx{\the\pgf@x} \edef\corry{\the\pgf@y} % \end{macrocode} % Next, use this externalised point to find the required boundary point with step 2 of % the algorithm. % The anchor path is |#1|, which is the first argument |setpaths|. % \begin{macrocode} \pgfintersectionofpaths { #1 }{ \pgfpathmoveto{\pgfpoint{0}{0}} \pgfpathlineto{\pgfpoint{\corrx}{\corry}} } % \end{macrocode} % Finally, the command |\pgfpointintersectionsolution| puts the point's coordinates in % |\pgf@x| and |\pgf@y|. % \begin{macrocode} \pgfpointintersectionsolution{1} } % \end{macrocode} % \end{macro} % % \subsubsection{Background path} % % \begin{macro}{\backgroundpath} % The shape is actually drawn by |\backgroundpath|, which executes the second argument of % |\setpaths|, which is the shape's background path. % \begin{macrocode} \backgroundpath{ #2 } % \end{macrocode} % \end{macro} % Finally, |setpaths| is completed. % \begin{macrocode} } % \end{macrocode} % \end{macro} % % \subsection{Utility macros} % % \subsubsection{Dimension correction} % % \begin{macro}{\mincorrect} % The |\mincorrect| macro finds the larger of two dimensions. % It is applied to shape coordinates and keys. % It uses a working dimension register, and has two parameters % \begin{macrocode} \newdimen\crct@dim \def\mincorrect#1#2{ % \end{macrocode} % The parameters have the following roles: % \begin{description}[nosep] % \item[\tt ~\#1] A register holding the normal outer bound dimension of the shape, % and then the largest value, in a PGF register such as |\pgf@xa|. % \item[\tt ~\#2] A key value, normally one of |\pgfshapeminwidth| or |\pgfshapeminheight|. % \end{description} % The |\crct@dim| register is used to calculate half of |#2|: % \begin{macrocode} \pgfmathsetlength\crct@dim{#2} \pgfmathsetlength\crct@dim{0.5\crct@dim} % \end{macrocode} % % Then if |#1| is larger than |\crct@dim|, |#1| is assigned this value % otherwise |#1| remains unchanged. % \begin{macrocode} \ifdim#1<\crct@dim #1=\crct@dim \fi } % \end{macrocode} % \end{macro} % % \subsubsection{Macros for testing} % % There are a couple of macros can be used to delineate a shape's text box during development. % They should not be used in `production' shapes. % % \begin{macro}{\path@textbox} % The |\path@textbox| macro draws a line around the the shape's text that is the % uncorrected text box. % \begin{macrocode} \def\path@textbox{ \pgf@xa=.5\wd\pgfnodeparttextbox \pgf@ya=.5\ht\pgfnodeparttextbox \advance\pgf@ya.5\dp\pgfnodeparttextbox \typeout{**** TEST text box (x,y) = (\the\pgf@xa,\the\pgf@ya) } \pgfpathmoveto{\pgfpoint{\pgf@xa}{\pgf@ya}} \pgfpathlineto{\pgfpoint{\pgf@xa}{-\pgf@ya}} \pgfpathlineto{\pgfpoint{-\pgf@xa}{-\pgf@ya}} \pgfpathlineto{\pgfpoint{-\pgf@xa}{\pgf@ya}} \pgfpathclose } % \end{macrocode} % \end{macro} % % \begin{macro}{\path@ctextbox} % The |\path@ctextbox| macro shows the shape's corrected text box, % which includes inner separation. % \begin{macrocode} \def\path@ctextbox{ \pgf@xa=.5\wd\pgfnodeparttextbox \pgfmathsetlength\pgf@xc{\pgfshapeinnerxsep} \advance\pgf@xa\pgf@xc \pgf@ya=.5\ht\pgfnodeparttextbox \advance\pgf@ya.5\dp\pgfnodeparttextbox \pgfmathsetlength\pgf@yc{\pgfshapeinnerysep} \advance\pgf@ya\pgf@yc \typeout{**** TEST corrected text box (x,y) = (\the\pgf@xa,\the\pgf@ya) } \pgfpathmoveto{\pgfpoint{\pgf@xa}{\pgf@ya}} \pgfpathlineto{\pgfpoint{\pgf@xa}{-\pgf@ya}} \pgfpathlineto{\pgfpoint{-\pgf@xa}{-\pgf@ya}} \pgfpathlineto{\pgfpoint{-\pgf@xa}{\pgf@ya}} \pgfpathclose } % \end{macrocode} % \end{macro} % %\iffalse % %\fi % % \Finale % %^^A########################################################################### %^^A# Additional installed files # %^^A########################################################################### % %^^A - Option = sample ... %^^A - This is the package's sample shape. %^^A - It is included in the report, and it is given as a file to be used as %^^A - a template for new shapes. %\iffalse %<*sample> %%-------------------------------------------------- %% %% This is a sample shape for the makeshape package %% %% It can be adapted for other shapes. See %% makeshape.pdf for instructions. %% %% 25 January 2013 \usepackage{makeshape} \makeatletter %% Constant for sample shape \def\gap{4pt} %% Anchor path <- change and rename as required \def\sampleanchor{ % get corrected text box \pgf@xa=\ctbnex \pgf@ya=\ctbney % make room for shape \advance\pgf@xa by \gap \advance\pgf@ya by \gap % correct for minheight and minwidth and % for outerxsep or outerysep \mincorrect{\pgf@xa}{\pgfshapeminwidth} \advance\pgf@xa\pgfshapeouterxsep \mincorrect{\pgf@ya}{\pgfshapeminheight} \advance\pgf@ya\pgfshapeouterysep % draw the path \pgfpathmoveto{\pgfpoint{\pgf@xa}{\pgf@ya}} \pgfpathlineto{\pgfpoint{\pgf@xa}{-\pgf@ya}} \pgfpathlineto{\pgfpoint{-\pgf@xa}{-\pgf@ya}} \pgfpathlineto{\pgfpoint{-\pgf@xa}{\pgf@ya}} \pgfpathclose } %% Background path <- change and rename as required \def\sampleborder{ % get corrected text box \pgf@xa=\ctbnex \pgf@ya=\ctbney % make room for shape \advance\pgf@xa by \gap \advance\pgf@ya by \gap % correct for minheight and minwidth but % not for outerxsep or outerysep \mincorrect{\pgf@xa}{\pgfshapeminwidth} \mincorrect{\pgf@ya}{\pgfshapeminheight} % draw outer shape \pgfpathmoveto{\pgfpoint{\pgf@xa}{\pgf@ya}} \pgfpathlineto{\pgfpoint{\pgf@xa}{-\pgf@ya}} \pgfpathlineto{\pgfpoint{-\pgf@xa}{-\pgf@ya}} \pgfpathlineto{\pgfpoint{-\pgf@xa}{\pgf@ya}} \pgfpathclose % draw inner shape \advance\pgf@xa by -\gap \advance\pgf@ya by -\gap \pgfpathmoveto{\pgfpoint{\pgf@xa}{\pgf@ya}} \pgfpathlineto{\pgfpoint{\pgf@xa}{-\pgf@ya}} \pgfpathlineto{\pgfpoint{-\pgf@xa}{-\pgf@ya}} \pgfpathlineto{\pgfpoint{-\pgf@xa}{\pgf@ya}} \pgfpathclose } %%------------------------------------------------ %% Shape declaration <- Change name as required \pgfdeclareshape{sample}{ % Set paths <- change path macros as required \setpaths{\sampleanchor}{\sampleborder} % Saved anchors <- change as required \savedanchor{\northeast}{ \pgf@x = \ctbnex \pgf@y = \ctbney \advance\pgf@x by \gap \advance\pgf@y by \gap \mincorrect{\pgf@x}{\pgfshapeminwidth} \mincorrect{\pgf@y}{\pgfshapeminheight} \advance\pgf@x\pgfshapeouterxsep \advance\pgf@y\pgfshapeouterysep } % Anchors <- change as required \anchor{north}{\northeast \pgf@x=0pt} \anchor{north east}{\northeast} \anchor{east}{\northeast \pgf@y=0pt} \anchor{south east}{\northeast \pgf@y=-\pgf@y} \anchor{south}{\northeast \pgf@x=0pt \pgf@y=-\pgf@y} \anchor{south west}{\northeast \pgf@x=-\pgf@x \pgf@y=-\pgf@y} \anchor{west}{\northeast \pgf@x=-\pgf@x \pgf@y=0pt} \anchor{north west}{\northeast \pgf@x=-\pgf@x} } \makeatother % %\fi % \endinput