% \iffalse % -------------------------------------------------------------------- %<*hex> % \fi % % \subsubsection{Hex coordinate system} % % \begin{Macro}{\hex@xx,\hex@yy} % % Some offsets along $x$ and $y$ due to offset of every second hex % column. % % \begin{align*} % \delta_x &= \cos60^{\circ}\\ % \delta_y &= \sin60^{\circ}\\ % \end{align*} % % These numbers are calculated once here and then used several times % in the following code. % % \begin{macrocode} \pgfmathparse{cos(60)} \xdef\hex@xx{\pgfmathresult} \pgfmathparse{sin(60)} \xdef\hex@yy{\pgfmathresult} \pgfmathparse{\hex@yy*cos(30)}\xdef\hex@e@xx{\pgfmathresult} \pgfmathparse{\hex@yy*sin(30)}\xdef\hex@e@yy{\pgfmathresult} \newdimen\hex@radius\hex@radius=1cm \newdimen\hex@dx \expandafter\hex@dx=\hex@xx cm \newdimen\hex@dy \expandafter\hex@dy=\hex@yy cm \newdimen\hex@e@dx \expandafter\hex@e@dx=\hex@e@xx cm \newdimen\hex@e@dy \expandafter\hex@e@dy=\hex@e@yy cm % \end{macrocode} % \end{Macro} % % Some code we need for some options % % \begin{macrocode} \newif\ifhex@label@is@name\hex@label@is@namefalse \def\hex@short@col{isfalse} \def\hex@got@short{isfalse} \pgfmathdeclarefunction{isfalse}{1}{% \begingroup \def\pgfmathresult{0}% \pgfmath@smuggleone\pgfmathresult \endgroup} \pgfmathdeclarefunction{istrue}{1}{% \begingroup \def\pgfmathresult{1}% \pgfmath@smuggleone\pgfmathresult \endgroup} % \end{macrocode} % % What follows is a way to configure the hex coordinate system. For % example, if the rows goes down, then we can flag that, but still add % hexes straightforwardly. Similar for columns. We can also specify % that the first row or column has number 1 (instead of 0). Since % this is dealt with a the coordinate level, it means most of the rest % of the code is agnostic to these choices. % % Which is the first coordinate (0 or 1) % % \begin{macrocode} \tikzset{ hex/first row is/.is choice, hex/first row is/0/.code={\def\hex@coords@row@off{0}}, hex/first row is/1/.code={\def\hex@coords@row@off{-1}}, hex/first row is=0, hex/first column is/.is choice, hex/first column is/0/.code={\def\hex@coords@col@off{0}}, hex/first column is/1/.code={\def\hex@coords@col@off{-1}}, hex/first column is=0, hex/first row and column are/.is choice, hex/first row and column are/0/.style={ hex/first row is=0,% hex/first column is=0}, hex/first row and column are/1/.style={ hex/first row is=1,% hex/first column is=1}, % \end{macrocode} % % Which way does the column and row numbers go % % \begin{macrocode} hex/row direction is/.is choice, hex/row direction is/normal/.code={\def\hex@coords@row@fac{1}}, hex/row direction is/reversed/.code={\def\hex@coords@row@fac{-1}}, hex/row direction is/up/.style={hex/row direction is=normal}, hex/row direction is/down/.style={hex/row direction is=reversed}, hex/row direction is/positive/.style={hex/row direction is=normal}, hex/row direction is/negative/.style={hex/row direction is=reversed}, hex/row direction is=normal, hex/column direction is/.is choice, hex/column direction is/normal/.code={\def\hex@coords@col@fac{1}}, hex/column direction is/reversed/.code={\def\hex@coords@col@fac{-1}}, hex/column direction is/right/.style={hex/column direction is=normal}, hex/column direction is/left/.style={hex/column direction is=reversed}, hex/column direction is/positive/.style={hex/column direction is=normal}, hex/column direction is/negative/.style={hex/column direction is=reversed}, hex/column direction is=normal, % \end{macrocode} % % Make labels names of shapes of the hexes so we can use labels to % place stuff % % \begin{macrocode} hex/label is name/.is if=hex@label@is@name, % \end{macrocode} % % If we have uneven number of rows in some columns. % % \begin{macrocode} hex/short bottom columns/.is choice, hex/short bottom columns/odd/.code={% \def\hex@bot@short@col{isodd} \def\hex@got@bot@short{istrue} \hex@dbg{4}{Short columns (odd): \meaning\hex@bot@short@col}}, hex/short bottom columns/even/.code={ \def\hex@bot@short@col{iseven} \def\hex@got@bot@short{istrue} \hex@dbg{4}{Short column (even): \meaning\hex@bot@short@col}}, hex/short bottom columns/none/.code={ \def\hex@bot@short@col{isfalse} \def\hex@got@bot@short{isfalse} \hex@dbg{4}{Short columns (none): \meaning\hex@bot@short@col}}, hex/short bottom columns=none, hex/short columns/.forward to=hex/short bottom columns, hex/short top columns/.is choice, hex/short top columns/odd/.code={% \def\hex@top@short@col{isodd} \def\hex@got@top@short{istrue} \hex@dbg{4}{Short columns (odd): \meaning\hex@top@short@col}}, hex/short top columns/even/.code={ \def\hex@top@short@col{iseven} \def\hex@got@top@short{istrue} \hex@dbg{4}{Short column (even): \meaning\hex@top@short@col}}, hex/short top columns/none/.code={ \def\hex@top@short@col{isfalse} \def\hex@got@top@short{isfalse} \hex@dbg{4}{Short columns (none): \meaning\hex@top@short@col}}, hex/short top columns=none, } \message{^^JInitial hex coordinate setup: Rows: factor=\hex@coords@row@fac, offset=\hex@coords@row@off Columns: factor=\hex@coords@col@fac, offset=\hex@coords@col@off} % \end{macrocode} % % \begin{HexKey*}{ % hex/coords/column, % hex/coords/row, % hex/coords/vertex, % hex/coords/edge, % hex/coords/offset} % % We define the keys for hexagon coordinates. These are the % \spec{row}, \spec{column}, possible \spec{vertex} or % \spec{edge}. Vertexes and edges are defined as % multiple-choice. \spec{offset} specifies the offset from the % centre in the direction of a vertex or edge. By default, the % offset is one, meaning all the way to the vertex or edge. % % The key \spec{inverse row} specifies that the rows are given from % the top down, but coordinates should be calculated as if the row % was negative. This (should) allow us to design boards where rows % increase downward, while still keeping the interface and remaining % code somewhat reasonable and agnostic. % % Similarly, the key \spec{column 1}, will allow us to start the % columns with 1. % % % % \begin{macrocode} \tikzset{ /hex/coords/.cd, column/.store in=\hex@col, c/.store in=\hex@col, row/.store in=\hex@row, r/.store in=\hex@row, offset/.store in=\hex@off, o/.store in=\hex@off, vertex/.is choice, vertex/none/.code={\global\let\hex@vtx\@empty}, vertex/east/.code={\def\hex@vtx{0}}, vertex/north east/.code={\def\hex@vtx{60}}, vertex/north west/.code={\def\hex@vtx{120}}, vertex/west/.code={\def\hex@vtx{180}}, vertex/south west/.code={\def\hex@vtx{240}}, vertex/south east/.code={\def\hex@vtx{300}}, vertex/E/.code={\def\hex@vtx{0}}, vertex/NE/.code={\def\hex@vtx{60}}, vertex/NW/.code={\def\hex@vtx{120}}, vertex/W/.code={\def\hex@vtx{180}}, vertex/SW/.code={\def\hex@vtx{240}}, vertex/SE/.code={\def\hex@vtx{300}}, vertex/.default=none, v/.forward to=/hex/coords/vertex=#1, edge/.is choice, edge/none/.code={\global\let\hex@edg\@empty}, edge/north east/.code={\def\hex@edg{30}}, edge/north/.code={\def\hex@edg{90}}, edge/north west/.code={\def\hex@edg{150}}, edge/south west/.code={\def\hex@edg{210}}, edge/south/.code={\def\hex@edg{270}}, edge/south east/.code={\def\hex@edg{330}}, edge/NE/.code={\def\hex@edg{30}}, edge/N/.code={\def\hex@edg{90}}, edge/NW/.code={\def\hex@edg{150}}, edge/SW/.code={\def\hex@edg{210}}, edge/S/.code={\def\hex@edg{270}}, edge/SE/.code={\def\hex@edg{330}}, edge/.default=none, e/.forward to=/hex/coords/edge, } % \end{macrocode} % \end{HexKey*} % % \begin{Macro}{\hex@coords@reset} % % This macro resets the hex coordinates to default values. That is % row and column 0, no vertex or edge. % % \begin{macrocode} \def\hex@coords@reset{% \tikzset{% /hex/coords/.cd, column=0, row=0, edge=none, vertex=none, offset=1}} % \end{macrocode} % \end{Macro} % % The following calculates the Cartesian coordinates from Hex % coordinates % % \begin{Syntax} % (cs:hex column=\meta{C},row=\meta{R},vertex=\meta{V},edge=\meta{E}) % \end{Syntax} % % Given the hexagon column $C$ and row $R$ with hexagon radius $r$, % the centre of the hexagon is at % % \begin{eqnarray*} % x &=& 2C\frac{3}{4}r\\ % y &=& r(R - (C \% 2)\sin60^{\circ}) % \end{eqnarray*} % % If \meta{V} or \meta{E} are given, then these are added to the % centre point. % % Note, $C$ and $R$ may be fractional numbers, which will specify a % point inside a hex. % % We set-up the translation to Cartesian coordinates. First % thing is to reset keys in \spec{/hex/coords}, and then parse out the % keys given. % % \begin{macrocode} \def\hex@coords@conv#1{% \hex@coords@reset% \tikzset{/hex/coords/.cd, #1}% % \end{macrocode} % % Then we calculate the $x$ coordinate and set the dimension % \cs{pgf@x}. We do this by % % $$x=c_e \frac{3}{2}\quad,$$ % % where % % $$c_e = f_c (c+o_c)\quad,$$ % % is the effective column (stored in \cs{hex@eff@col}) calculated from % is the direction factor $f_c$ (set by \spec{hex/column direction % is}) and the offset $o_c$ (set by \spec{hex/first column is}). % % \begin{macrocode} \pgfmathparse{int(\hex@coords@col@fac*(\hex@col+\hex@coords@col@off))}% \xdef\hex@eff@col{\pgfmathresult}% \hex@dbg{2}{Effective column: \hex@coords@col@fac * (\hex@col + \hex@coords@col@off) -> \hex@eff@col}% \pgfmathparse{\hex@eff@col*1.5}% \xdef\hex@x{\pgfmathresult}% % \end{macrocode} % % And then for the $y$ coordinate and set the dimension \cs{pgf@y}. % % $$y = 2\left(r_e - c_e \operatorname{mod} 2\right) \cos60^{\circ}\quad,$$ % % where % % $$r_e= 2 f_r (r+o_r) - (c+o_c) \operatorname{mod} 2\quad,$$ % % is the effective row (stored as \cs{hex@eff@row}) calculated from % the the direction factor $f_r$ (set by \spec{hex/row % direction is}) and the offset $o_r$ (set by \spec{hex/first % row is}). % % \begin{macrocode} \pgfmathparse{int(\hex@coords@row@fac*(\hex@row+\hex@coords@row@off))}% \xdef\hex@eff@row{\pgfmathresult}% \hex@dbg{2}{Effective row: \hex@coords@row@fac * (\hex@row + \hex@coords@row@off) -> \hex@eff@row}% \pgfmathparse{(2*\hex@eff@row-mod(round((\hex@col+\hex@coords@col@off)),2))*\hex@yy}% \pgfmathparse{(2*\hex@eff@row-mod(abs(round(\hex@col+\hex@coords@col@off)),2))*\hex@yy}% \xdef\hex@y{\pgfmathresult}% % \end{macrocode} % % If we have a vertex specification add that location to the current % coordinates. If not, set the point. % % \begin{macrocode} \ifx\hex@vtx\@empty\else% \pgfmathparse{\hex@x+\hex@off*cos(\hex@vtx)}\xdef\hex@x{\pgfmathresult} \pgfmathparse{\hex@y+\hex@off*sin(\hex@vtx)}\xdef\hex@y{\pgfmathresult} \fi% % \ifx\hex@vtx\@empty\pgfpointxy{\hex@x}{\hex@y}\else% % \pgfpointadd{\pgfpointxy{\hex@x}{\hex@y}}{% % \pgfpointscale{\hex@off}{\pgfpointpolarxy{\hex@vtx}{1}}}\fi% % \end{macrocode} % % If we have an edge specification add that location to the current % coordinates. % % \begin{macrocode} \ifx\hex@edg\@empty\else% \pgfmathparse{\hex@x+\hex@off*\hex@yy*cos(\hex@edg)}% \xdef\hex@x{\pgfmathresult}% \pgfmathparse{\hex@y+\hex@off*\hex@yy*sin(\hex@edg)}% \xdef\hex@y{\pgfmathresult}% \fi% % \ifx\hex@edg\@empty\else% % \pgfpointadd{\pgfpointxy{\hex@x}{\hex@y}}{% % \pgfpointscale{\hex@off}{\pgfpointpolarxy{\hex@edg}{\hex@yy}}}\fi % \end{macrocode} % % For debugging, we can print out stuff. % % \begin{macrocode} \pgfpointxy{\hex@x}{\hex@y} \hex@dbg{2}{Hex coordinates: #1 ^^J c=\hex@col' ^^J r=\hex@row' ^^J v=\hex@vtx' ^^J e=\hex@edg' ^^J o=\hex@off' ^^J x=\hex@x' ^^J y=`\hex@y'}% \global\let\hex@x\hex@x% \global\let\hex@y\hex@y% \global\let\hex@row\hex@row% \global\let\hex@col\hex@col% } \tikzdeclarecoordinatesystem{hex}{% \hex@coords@conv{#1}} % \end{macrocode} % \iffalse % % -------------------------------------------------------------------- % \fi