diff options
Diffstat (limited to 'macros/latex/contrib/wargame/source/util/core.dtx')
-rw-r--r-- | macros/latex/contrib/wargame/source/util/core.dtx | 1299 |
1 files changed, 1299 insertions, 0 deletions
diff --git a/macros/latex/contrib/wargame/source/util/core.dtx b/macros/latex/contrib/wargame/source/util/core.dtx new file mode 100644 index 0000000000..a3c656a2b3 --- /dev/null +++ b/macros/latex/contrib/wargame/source/util/core.dtx @@ -0,0 +1,1299 @@ +% \iffalse +% ==================================================================== +% \fi +% +% \subsection{The \texttt{wargame.util} \TikZ{} library} +% \label{sec:impl:util} +% +% This library contains some utilities for use in the other +% libraries. +% +% \iffalse +%<*utils> +%\fi +% +% +% \iffalse +% -------------------------------------------------------------------- +% \fi +% +% \subsubsection{Miscellaneous macros} +% +% \begin{Macro}{\wg@dbg} +% Debugging support. The counter \cs{wargamedbglvl} sets the debug +% level. The package code then uses \cs{wg@dbg} to print out +% debugging messages. This macro takes two arguments --- the first +% is the \emph{least} debug level at which the message is printed, and +% the second is the message it self. +% +% \begin{macrocode} +\newcount\wargamedbglvl\wargamedbglvl=0 +\def\wg@dbg#1#2{% + \ifnum#1>\wargamedbglvl\relax\else\message{^^J#2}\fi} +% \end{macrocode} +% \end{Macro} +% +% \begin{Macro}{\wg@addto@macro} +% +% The macro \cs{wg@addto@macro}\marg{macro}\marg{other} adds the +% definition of the macro \meta{other} to the macro \meta{macro}. +% This uses the \cs{toks} trick of storing the \emph{tokens} of the +% definition of a \meta{macro} and \meta{other} into \spec{@} and +% expanding that token into the definition of \meta{macro}. +% Effectively, this means that the top-level definition of +% \meta{macro} and \meta{other} are expanded (i.e., macros used in +% the definition of either macro is \emph{not} expanded) and then +% that becomes the new definition of \meta{macro}. +% +% We will use this macro to do \emph{shallow} definitions of macros +% to contain keys and such. +% +% \begin{macrocode} +\long\def\wg@addto@macro#1#2{% + \begingroup + \toks@\expandafter\expandafter\expandafter{\expandafter#1#2}% + \xdef#1{\the\toks@}% + \endgroup} +% \end{macrocode} +% \end{Macro} +% +% +% \begin{Macro}{\wg@sub@nchor} +% Get anchor from sub node. We cannot use \cs{pgfpointanchor} since +% that returns the anchor coordinates in the global coordinate +% system. +% +% \begin{macrocode} +\def\wg@sub@nchor#1#2{% + \wg@dbg{3}{^^JGet `#2' in `#1'}% + \@ifundefined{pgf@sh@ns@#1}{% + \pgf@x=0cm\pgf@y=0cm}{% + \pgf@process{% + \csname pgf@sh@ma@#1\endcsname% MW + \csname pgf@sh@np@#1\endcsname% + \pgf@sh@reanchor{\csname pgf@sh@ns@#1\endcsname}{#2}}}% + \wg@dbg{10}{-> \the\pgf@x,\the\pgf@y}% +} +% \end{macrocode} +% \end{Macro} +% +% +% Scratch dimensions +% +% \begin{macrocode} +\newdimen\wg@tmpa +\newdimen\wg@tmpb +\newdimen\wg@tmpc +\newdimen\wg@tmpd +% \end{macrocode} +% +% +% Macro to easy restore a saved path +% +% \begin{macrocode} +\def\settosave#1{ + \pgfsyssoftpath@setcurrentpath{#1}} +% \end{macrocode} +% +% \iffalse +% -------------------------------------------------------------------- +% \fi +% +% \subsubsection{Pictures in compound nodes} +% +% \begin{Macro}{\wg@pic} +% The macro \cs{wg@pic} will render a \texttt{pic}. This is used by +% the \texttt{natoapp6cs}, \texttt{chit}, and \texttt{hex} node +% shapes extensively. +% +% The arguments are +% \begin{enumerate} +% \item Prefix +% \item Position +% \item Fixed options +% \item User options +% \item Picture. +% \end{enumerate} +% +% That is, the macro expects calls like +% \begin{Syntax} +% \cs{wg@pic}\oarg{options}\meta{picture}\cs{@endwg@pic}\marg{prefix}\marg{position}\marg{options} +% \end{Syntax} +% +% Note the \cs{@endwg@pic} at the end of the call to swallow up +% \meta{picture}. Typically this macro is used as +% +% \begin{Syntax} +% \cs{edef}\cs{args}\{\meta{something}\} +% \cs{expandafter}\cs{wg@pic}\cs{args}\cs{@endwg@pic}\marg{prefix}\parg{position}\marg{options} +% \end{Syntax} +% +% where \meta{something} typically expands to \oarg{user +% option}\meta{picture} +% +% First, the top-level macro \cs{wg@pic} that looks for user +% options. +% +% \begin{macrocode} +\def\wg@pic{% + \@ifnextchar[{\wg@@pic}{\wg@@pic[]}%] +} +% \end{macrocode} +% +% This macro then forwards to \cs{wg@@pic} to gobble up +% \meta{picture}. +% +% \begin{enumerate} +% \item User options +% \item Arguments +% \end{enumerate} +% +% \begin{macrocode} +\def\wg@@pic[#1]#2\@endwg@pic{% + \wg@dbg{2}{Options: `#1', picture: `#2'}% + \wg@@@pic{#1}{#2}% +} +% \end{macrocode} +% +% \begin{enumerate} +% \item User options +% \item Arguments +% \item Prefix +% \item Coordinates +% \item Fixed options +% \end{enumerate} +% +% \begin{macrocode} +\def\wg@@@pic#1#2#3#4#5{% + \ifx|#2|\wg@dbg{3}{No picture given}% + \else% + \wg@dbg{3}{^^JWG Pic: + ^^J User options: #1 + ^^J Picture: #2 + ^^J Prefix: #3 + ^^J Coordinates: #4 + ^^J Fixed options: #5}% + % \wg@dbg{2}{\string\pic[#5,#1] at (#4) {#3#2}}% + \pic[#5,#1] at (#4) {#3#2};% + \ifwg@s@ve% + \pgf@relevantforpicturesizetrue% + \begin{getbbl}% + \pic[draw=none,fill=none,transform shape] at (#4) {#3#2};% + \end{getbbl}% + \wg@dbg{5}{Clipping to local bounding box}% + \clip (L.south west) rectangle (L.north east);% + \pgf@relevantforpicturesizefalse \global\wg@s@vefalse% + \fi + \fi% + \wg@dbg{3}{End of WG Pic} +} +% \end{macrocode} +% \end{Macro} +% +% +% \begin{Macro}{\wg@pic@all} +% +% This macro sets all pictures in a list. +% +% \begin{enumerate} +% \item List +% \item Prefix +% \item Position +% \item Styles +% \end{enumerate} +% +% +% \begin{macrocode} +\def\wg@pic@all#1#2#3#4{% + \wg@dbg{2}{WG picture loop + ^^J List: \meaning#1 + ^^J Prefix: `#2' + ^^J Position: `#3' + ^^J Styles: `#4'} + \foreach \p in #1{% + \wg@dbg{2}{WG picture element: \meaning\p}% + \expandafter\wg@pic\p\@endwg@pic {#2}{#3}{#4}% + }% +} +% \end{macrocode} +% \end{Macro} +% +% \iffalse +% -------------------------------------------------------------------- +% \fi +% +% \subsubsection{Nodes in compound nodes} +% +% \begin{Macro}{\wg@node} +% The macro \cs{wg@node} will render a \texttt{node}. This can be +% used by the \texttt{natoapp6cs}, \texttt{chit}, and \texttt{hex} +% node shapes. +% +% The arguments are +% \begin{enumerate} +% \item Prefix +% \item Position +% \item Fixed options +% \item User options +% \item Body. +% \end{enumerate} +% +% That is, the macro expects calls like +% \begin{Syntax} +% \cs{wg@node}\oarg{options}\meta{body}\cs{@endwg@node}\marg{prefix}\marg{position}\marg{options} +% \end{Syntax} +% +% Note the \cs{@endwg@node} at the end of the call to swallow up +% \meta{body}. Typically this macro is used as +% +% \begin{Syntax} +% \cs{edef}\cs{args}\{\meta{something}\} +% \cs{expandafter}\cs{wg@node}\cs{args}\cs{@endwg@node}\marg{prefix}\parg{position}\marg{options} +% \end{Syntax} +% +% where \meta{something} typically expands to \oarg{user +% option}\meta{body} +% +% First, the top-level macro \cs{wg@node} that looks for user +% options. +% +% \begin{macrocode} +\def\wg@node{% + \@ifnextchar[{\wg@@node}{\wg@@node[]}%] +} +% \end{macrocode} +% +% This macro then forwards to \cs{wg@@node} to gobble up +% \meta{body}. +% +% \begin{enumerate} +% \item User options +% \item Arguments +% \end{enumerate} +% +% \begin{macrocode} +\def\wg@@node[#1]#2\@endwg@node{% + \wg@dbg{2}{Options: `#1', body: `#2'}% + \wg@@@node{#1}{#2}% +} +% \end{macrocode} +% +% \begin{enumerate} +% \item User options +% \item Arguments +% \item Prefix +% \item Coordinates +% \item Fixed options +% \end{enumerate} +% +% \begin{macrocode} +\def\wg@@@node#1#2#3#4#5{% + \ifx|#2|\wg@dbg{3}{No body given}% + \else% + \wg@dbg{3}{^^JWG Pic: + ^^J User options: #1 + ^^J Body: #2 + ^^J Prefix: #3 + ^^J Coordinates: #4 + ^^J Fixed options: #5}% + % \wg@dbg{2}{\string\pic[#5,#1] at (#4) {#3#2}}% + \node[#5,#1] at (#4) {#3#2};% + \fi% + \wg@dbg{3}{End of WG Node} +} +% \end{macrocode} +% \end{Macro} +% +% +% \begin{Macro}{\wg@node@all} +% +% This macro sets all pictures in a list. +% +% \begin{enumerate} +% \item List +% \item Prefix +% \item Position +% \item Styles +% \end{enumerate} +% +% +% \begin{macrocode} +\def\wg@node@all#1#2#3#4{% + \wg@dbg{2}{WG picture loop + ^^J List: \meaning#1 + ^^J Prefix: `#2' + ^^J Position: `#3' + ^^J Styles: `#4'} + \foreach \p in #1{% + \wg@dbg{2}{WG picture element: \meaning\p}% + \expandafter\wg@node\p\@endwg@node {#2}{#3}{#4}% + }% +} +% \end{macrocode} +% \end{Macro} +% +% \iffalse +% -------------------------------------------------------------------- +% \fi +% +% \subsubsection{Bounding boxes} +% +% Bounding box dimensions +% +% +% \begin{macrocode} +\newdimen\wg@bb@minx +\newdimen\wg@bb@miny +\newdimen\wg@bb@maxx +\newdimen\wg@bb@maxy +% \end{macrocode} +% +% +% +% Enable or disable bounding box tracking +% +% \begin{macrocode} +\newif\ifwg@notrelevantforpathsize\wg@notrelevantforpathsizefalse +% \end{macrocode} +% +% +% \begin{Macro}{wg@resetbb} +% Reset the bounding box tracking dimensions +% +% \begin{macrocode} +\def\wg@resetbb{% + \global\wg@bb@minx=16000pt\relax% + \global\wg@bb@miny=16000pt\relax% + \global\wg@bb@maxx=-16000pt\relax% + \global\wg@bb@maxy=-16000pt\relax% +} +% \end{macrocode} +% \end{Macro} +% +% \begin{Macro}{\old@pgf@protocolsize} +% Save PGF's bounding box algorithm +% +% \begin{macrocode} +\let\old@pgf@protocolsize\pgf@protocolsizes +% \end{macrocode} +% \end{Macro} +% +% \begin{Macro}{\wg@protocolsizes} +% Our bounding box algorithm +% +% \begin{macrocode} +\def\wg@protocolsizes#1#2{% + \old@pgf@protocolsize{#1}{#2} + \ifwg@notrelevantforpathsize\else% + \ifdim#1<\wg@bb@minx\global\wg@bb@minx#1\fi% + \ifdim#1>\wg@bb@maxx\global\wg@bb@maxx#1\fi% + \ifdim#2<\wg@bb@miny\global\wg@bb@miny#2\fi% + \ifdim#2>\wg@bb@maxy\global\wg@bb@maxy#2\fi% + \fi +} +% \end{macrocode} +% \end{Macro} +% +% % \begin{environment}{getbbl} +% Environment that tracks the local bounding box +% +% \begin{macrocode} +\newenvironment{getbbl}{% + \wg@resetbb% + \wg@notrelevantforpathsizefalse% + \global\let\pgf@protocolsizes\wg@protocolsizes}{% + \gdef\pgf@sh@ns@L{rectangle} + \gdef\pgf@sh@np@L{% + \def\southwest{\pgfqpoint{\the\wg@bb@minx}{\the\wg@bb@miny}}% + \def\northeast{\pgfqpoint{\the\wg@bb@maxx}{\the\wg@bb@maxy}}% + } + \gdef\pgf@sh@nt@L{{1}{0}{0}{1}{0pt}{0pt}} + \gdef\pgf@sh@pi@L{\pgfpictureid} + \global\let\pgf@protocolsizes\old@pgf@protocolsize +} +% \end{macrocode} +% \end{environment} +% +% \begin{environment}{getbb} +% Environment to track global bounding box +% +% \begin{macrocode} +\newenvironment{getbb}{% + \wg@resetbb% + \wg@notrelevantforpathsizefalse% + \global\let\pgf@protocolsizes\wg@protocolsizes}{% + \gdef\pgf@sh@ns@M{rectangle} + \gdef\pgf@sh@np@M{% + \def\southwest{\pgfqpoint{\the\wg@bb@minx}{\the\wg@bb@miny}}% + \def\northeast{\pgfqpoint{\the\wg@bb@maxx}{\the\wg@bb@maxy}}% + } + \gdef\pgf@sh@nt@M{{1}{0}{0}{1}{0pt}{0pt}} + % \pgfgettransform\pgf@temp% + % \xdef\pgf@sh@nt@M{\pgf@temp} + % \pgfgettransformentries{\wg@tmp@a}{\wg@tmp@b}{\wg@tmp@c}{\wg@tmp@d}{\pgf@temp}{\pgf@temp} + % \message{^^JTransform of M: \meaning\pgf@temp} + % \xdef\pgf@sh@nt@M{{\wg@tmp@a}{\wg@tmp@b}{\wg@tmp@c}{\wg@tmp@d}{0pt}{0pt}}% + % \message{^^JTransform of M: \meaning\pgf@sh@nt@M} + \gdef\pgf@sh@pi@M{\pgfpictureid} + \global\let\pgf@protocolsizes\old@pgf@protocolsize +} +% \end{macrocode} +% \end{environment} +% +% \iffalse +% -------------------------------------------------------------------- +% \fi +% +% \subsubsection{Other Tikz utilities} +% +% \begin{TikzKey}{tikz/reverseclip} +% +% A reverse clipping path. This is used to cut out stuff outside of +% path defined. +% +% \begin{macrocode} +\tikzstyle{reverseclip}=[insert path={(current bounding box.north east) -- + (current bounding box.south east) -- + (current bounding box.south west) -- + (current bounding box.north west) -- + (current bounding box.north east)}] +% \end{macrocode} +% \end{TikzKey} +% +% \begin{TikzKey}{tikz/clip even odd rule} +% A reverse clipping path +% +% \begin{macrocode} +\tikzset{ + clip even odd rule/.code={\pgfseteorule}, % Credit to Andrew Stacey +} +% \end{macrocode} +% \end{TikzKey} +% +% +% \begin{TikzKey}{tikz/invclip} +% +% Inverse clipping. This should be an option \emph{after} the path to +% do the inverse clipping by. This works by adding a \emph{large} +% (page) path to the current path, and then use that as clipping. +% +% \begin{macrocode} +\tikzset{ + invclip/.style={ + clip,insert path= + [clip even odd rule]{ + [reset cm](-\maxdimen,-\maxdimen)rectangle(\maxdimen,\maxdimen) + } + }, +} +% \end{macrocode} +% \end{TikzKey} +% +% \begin{TikzKey}{save clip} +% +% An option for use with sub-elements of NATO App 6(c) or chit +% nodes. This will save the current path as a clipping path for the +% next paths to be drawn in the sub-element +% +% \begin{macrocode} +\newif\ifwg@s@ve\wg@s@vefalse +\tikzset{ + save clip/.is choice, + save clip/true/.code={\global\wg@s@vetrue}, + save clip/false/.code={\global\wg@s@vefalse}, + save clip/.default={true}, + save clip/.initial={false}, +} +% \end{macrocode} +% \end{TikzKey} +% +% \begin{TikzKey}{scale line widths} +% +% Scales any line width specified in the node options. +% +% Use like +% +% \begin{verbatim} +% \tikzset{ +% some/.style={ +% scale line widths, +% line width=1pt} +% } +% \end{verbatim} +% +% Note that the order is important. +% +% \begin{macrocode} +\tikzset{ + scale line widths/.style={% + /utils/exec=\def\tikz@semiaddlinewidth##1{% + \pgfgettransformentries{% + \wg@jaca}{% + \wg@jacb}{% + \wg@jacc}{% + \wg@jacd}{% + \wg@tmp}{% + \wg@tmp}% + \pgfmathsetmacro{\wg@jac}{sqrt(abs(\wg@jaca*\wg@jacd-\wg@jacb*\wg@jacc))}% + \wg@dbg{4}{Scaling line width ##1 by \wg@jac} + \pgfmathsetmacro{\wg@lw}{\wg@jac*##1}% + \wg@dbg{4}{Scaled ##1 -> \wg@lw} + \tikz@addoption{\pgfsetlinewidth{\wg@lw pt}}% + \wg@dbg{4}{Added scaled option \wg@lw} + \pgfmathsetlength\pgflinewidth{\wg@lw pt} + \wg@dbg{4}{Did set line width \wg@lw pt} + }}, + relative line width/.style={% + /utils/exec=\def\tikz@semiaddlinewidth##1{% + \wg@dbg{4}{Relative line width #1 times ##1}% + \pgfmathsetmacro{\wg@lv}{#1*##1}% + \tikz@addoption{\pgfsetlinewidth{\wg@lw pt}}% + \pgfmathsetlength\pgflinewidth{\wg@lw pt}}} +} +% \end{macrocode} +% \end{TikzKey} +% +% \begin{TikzKey}{sub pic actions} +% +% This is key that propagates actions to sub pictures of pictures. +% The normal \texttt{pic actions} cannot be used as it causes an +% infinite loop. +% +% \begin{macrocode} +\tikzset{ + sub pic actions/.code={% + \tikz@picmode% + \edef\opts{% + \iftikz@mode@draw draw,\else draw=none,\fi + \iftikz@mode@fill fill\else fill=none\fi} + \wg@dbg{5}{^^JSub Mode: \meaning\tikz@picmode \meaning\opts} + \pgfset{/tikz/.cd} + \pgfkeysalsofrom{\opts} + }} +% \end{macrocode} +% \end{TikzKey} +% +% \begin{TikzKey}{wg/debug show} +% +% Show debugging information +% +% \begin{macrocode} +\tikzset{ + wg/debug show/.code={% + \extractcolorspec{pgfstrokecolor}{\wg@tmp@fg} + \def\wg@tmp@bg{none} + \@ifundefinedcolor{pgffillcolor}{}{ + \extractcolorspec{pgffillcolor}{\wg@tmp@bg}} + \begingroup + \tikz@mode + \wargamedbglvl=#1 + \wg@dbg{3}{Drawing with w/stroke `\wg@tmp@fg' + (\tikz@strokecolor,\iftikz@mode@draw\else not\space\fi drawing) + and fill `\wg@tmp@bg' (\tikz@fillcolor,\iftikz@mode@fill\else + not\space\fi filling)} + \endgroup + } +} +% \end{macrocode} +% \end{TikzKey} +% +% +% \iffalse +% -------------------------------------------------------------------- +% \fi +% +% \subsubsection{Random IDs} +% +% +% \begin{macrocode} +\def\wg@r@ndom@id{% + \def\wg@uuid{} + \foreach \i in {1,...,8}{% + \pgfmathparse{Hex(random(0,15))} + \xdef\wg@uuid{\wg@uuid\pgfmathresult}}} +% \end{macrocode} +% +% \iffalse +%</utils> +%\fi +% \iffalse +% ==================================================================== +% \fi +% +% \subsection{The \texttt{wgexport} class} +% \label{sec:impl:util} +% +% This document class is used for exporting game component to be used +% in a VASSAL module +% libraries. +% +% \iffalse +%<*exportcls> +%\fi +% +% Class identification and load \texttt{wargame} package +% +% \begin{macrocode} +\ProvidesClass{wgexport} +\PassOptionsToClass{multi=tikzpicture,varwidth=false}{standalone} +\DeclareOption{noterrainpic}{% + \PassOptionsToPackage{\CurrentOption}{wargame}} +\DeclareOption{terrainpic}{% + \PassOptionsToPackage{\CurrentOption}{wargame}} +\DeclareOption*{% + \PassOptionsToClass{\CurrentOption}{standalone}} +\ProcessOptions\relax +\LoadClass{standalone} +\RequirePackage{wargame} +% \end{macrocode} +% +% We need a few utilities before we get to the actual environment. +% First, we need a tools to write out literal left and right curly +% braces. We do a bit of catcode hackery to accomplish that. +% +% \begin{macrocode} +\begingroup +\catcode`\^^I=12 +\def\@tabchar{^^I} +\catcode`<=1 \catcode`>=2 +\catcode`{=12 \catcode`}=12 +\gdef\@lbchar<{> +\gdef\@rbchar<}> +\endgroup +% \end{macrocode} +% +% Above, we temporarily set the tab, and left and right curly brace +% characters to be regular letters (12), and the catcodes of less than +% and greater than to be those of left and right curly braces +% respectively. We then define the macros \cs{@tabchar}, +% \cs{@lbchar}, and \cs{@rbchar} to produce literal characters. +% \LaTeX already has \cs{@percentchar}. +% +% Everything we do should go inside this environment. The single +% optional argument is the file name stem of the output JSON file. +% +% \begin{macrocode} +\newenvironment{imagelist}[1][\jobname]{% + \newwrite\mk@out% + \def\mk@i{}% + \def\mk@w{\immediate\write\mk@out}% + \immediate\openout\mk@out=#1.json + \mk@w{[} +}{ + \mk@w{\mk@i \@lbchar "name":"End of list", "category": "<<eol>>", + "subcategory": "" \@rbchar } + \mk@w{]} + \immediate\closeout\mk@out +} +% \end{macrocode} +% +% +% Preceed all images (\textsf{tikzpicture}) with this command +% +% First argument is the name of the image. This can be anything. +% Note that for counters, if the name ends in \texttt{flipped} then it +% is considered the backside of a counter. +% +% Second argument is the type of image. Recognised types are +% +% \begin{itemize} +% \item \texttt{board} for boards +% \item \texttt{oob} for OOBs +% \item \texttt{chart} for charts +% \item \texttt{counter} for counters +% \item \texttt{front} for front page +% \end{itemize} +% +% Other types can be used, and the images will be exported, but the +% Python script pays no particular attention to those then. Use for +% example to prepare images for help or the like. +% +% The third argument is the sub type. This is most relevant for the +% counters. Sub types can be anything, but since the counters will +% receive different prototypes based on the sub type, it makes sense +% to divide into sub types a la +% +% \begin{itemize} +% \item factions +% \item common markers +% \end{itemize} +% +% The faction sub types should just be the name of the faction. +% E.g., Allies, Axis, Soviet, NATO, Warsaw Pact. Spaces should not +% matter. +% +% For common markers, there are a few names that are recognised +% specifically by the Python script. These are +% +% \begin{itemize} +% \item \texttt{common} +% \item \texttt{all} +% \item \texttt{marker} +% \item \texttt{markers} +% \end{itemize} +% +% Counters that has these sub-types will no be considered to belong +% to any faction. +% +% Note that the Python script uses the faction names to guess the +% players of the game, and uses them in several places. +% +% +% \begin{macrocode} +\def\info{% + \@ifstar{\@@info{,}}{\@@info{\@rbchar,}}} +\def\@@info#1#2#3#4{% + \chit@dbg{2}{Making image `#2' of type `#3'/`#4' on page \thepage}% + \mk@w{ \@lbchar}% + \mk@w{ \space "name": "#2",}% + \mk@w{ \space "category": "#3",}% + \mk@w{ \space "subcategory": "#4", }% + \mk@w{ \space "number": \thepage #1}% + \let\oldmk@i\mk@i% + \ifx#1,\relax\edef\mk@i{\mk@i\space\space}\fi} +\def\end@info{% + \let\mk@i\oldmk@i% + \mk@w{ \space \@rbchar,}} +% \end{macrocode} +% +% Make separate images for each counter (single sided). +% +% \begin{macrocode} +\newcommand\chitimages[2][]{% + \begingroup% + \let\chit@report\do@chit@report% + \let\natoapp@report\do@natoapp@report% + \chit@dbg{2}{chits to make images of `#2'}% + \foreach[count=\ti from 0] \t/\x in #2{% + \ifx\t\empty\else% Ignore empty rows + \message{^^JSubcategory: `\x' (default `#1')} + \ifx\t\x\def\x{#1}\fi% Take sub-category or default + \foreach \u/\m in \t{% + \ifx\u\empty\else% Ignore empty cells + \chit@dbg{2}{Next chit `\u' with possible multiplicity `\m'}% + \ifx\m\@empty\def\m{1}\fi% If not multiplicity defined + \ifx\u\m\def\m{1}\fi% If the same as unit + \chit@dbg{2}{Next chit `\u' multiplicity `\m'}% + %% We only make one copy of the chit, since we can duplicate + %% it in VASSAL + \info*{\u}{counter}{\x} + \begin{tikzpicture} + \chit[\u=\ti]% + \end{tikzpicture} + \end@info% + %% \foreach \n in {1,...,\m}{% Make a number of copies + %% \ifx\u\chit@blank% + %% \chit@dbg{3}{Ignoring blank chit:\u}% + %% \else% + %% \info{\u}{counter}{#2} + %% \begin{tikzpicture} + %% \chit[\u=\ti](\c,\r)% + %% \end{tikzpicture} + %% \fi% + %% }% + \fi% + }% + \chit@dbg{2}{End of inner loop}% + \fi% + }% + \chit@dbg{2}{End of outer loop}% + \endgroup% +} +% \end{macrocode} +% +% Make separate images for each counter (double sided). The back-side +% counters must be defined by append `\texttt{ flipped}' the front +% face name +% +% \begin{macrocode} +\newcommand\doublechitimages[2][]{% + \begingroup% + \let\chit@report\do@chit@report% + \let\natoapp@report\do@natoapp@report% + \foreach[count=\ti from 0] \t/\x in #2{% + \ifx\t\empty\else% Ignore empty rows + \message{^^JSubcategory: `\x' (default `#1')} + \ifx\t\x\def\x{#1}\fi% Take sub-category or default + \foreach \u/\m in \t{% + \ifx\u\empty\else% Ignore empty cells + \chit@dbg{2}{Next chit `\u' with possible multiplicity `\m'}% + \ifx\m\@empty\def\m{1}\fi% If not multiplicity defined + \ifx\u\m\def\m{1}\fi% If the same as unit + \chit@dbg{2}{Next chit `\u' multiplicity `\m'}% + %% Flipped chit + \edef\s{\u\space flipped}% + %% We only make one copy of the chit, since we can duplicate + %% it in VASSAL + \info*{\u}{counter}{\x}% + \begin{tikzpicture}% + \chit[\u=\ti]% + \end{tikzpicture}% + \end@info% + \info*{\s}{counter}{\x}% + \begin{tikzpicture}% + \chit[\s=\ti]% + \end{tikzpicture}% + \end@info% + %% \foreach \n in {1,...,\m}{% Make a number of copies + %% \ifx\u\chit@blank% + %% \chit@dbg{3}{Ignoring blank chit:\u}% + %% \else% + %% \info{\u}{counter}{#2} + %% \begin{tikzpicture} + %% \chit[\u=\ti](\c,\r)% + %% \end{tikzpicture} + %% \fi% + %% }% + \fi% + }% + \fi% + }% + \endgroup% +} +% \end{macrocode} +% +% Special for boards, we have the environment \textsf{boardimage}. +% Like \cs{info} we must specify the name and sub-category of the +% board, but the category is assumed to be \texttt{board} (though the +% optional argument can specify a different category). +% +% Within this environment some specific styles are defined that allows +% the user to specify VASSAL zones on the board. For this to work +% properly, the parent \textsf{tikzpicture} \emph{must} have the style +% \texttt{zoned}. This style will record the bounding box of the +% picture which we will need to calculate VASSAL coordinates later +% on. +% +% Other styles are \texttt{zone scope}, to be applied to +% \texttt{scope}s in the picture, and \texttt{zone path} to be applied +% to \texttt{path}s (or \cs{draw}, \cs{fill}, or the like) in the +% picture. These will record coordinates of these elements in side +% the picture. The Python script will then define VASSAL zones based +% on these coordinates. +% +% For \texttt{zone scope} applied to a \texttt{scope}, what is +% recorded are +% +% \begin{itemize} +% \item The current coordinate transformation matrix +% \item The current translation +% \item The bounding box, within the current transformation and +% translation. +% \end{itemize} +% +% To define a zone in the board, simply enclose it in a +% +% \begin{verbatim} +% \begin{scope}[zone scope=name] +% ... +% \end{scope} +% \end{verbatim} +% +% The \meta{name} will be the name of the scope. If this contains the +% sub-string \texttt{hex} (upper, lower, or mixed case), then the zone +% will get a hex grid with numbering attached to it. +% +% If the \meta{name} contains the sub-string \texttt{turn} (any case), +% then it is assumed to be a turn track and a rectangular grid will be +% attached. The column and row separator will be set to \texttt{T}, +% so that it won't collide with the main zone. Similar if \meta{name} +% contains \texttt{oob}, except the separator is set to \texttt{O}. +% +% If \meta{name} contains the sub-string \texttt{pool}, then it is +% assumed to be a pool of counters, and \emph{no} grid is attached. +% +% For \texttt{zone path} applied to a \texttt{path}, what is recorded +% is the path coordinates (as straight line segments) in the global +% coordinate system. +% +% Both styles take one argument --- the name of the zone. If that +% name contains the sub-string \texttt{hex} anywhere in the name, then +% the zone is assumed to contain a hex grid. Otherwise, a rectangular +% grid (of fixed size) will be applied to it. +% +% The environment \texttt{boardimage} also records the coordinate +% options currently in use (keys \texttt{hex/first row is}, +% \texttt{hex/row direction is}, and so on), as well as the current +% label option (as defined by \texttt{every hex} or \texttt{every hex +% node}). +% +% All coordinates, and such are recorded in centimetres. It is worth +% remembering that the Tikz coordinate system has the $y$ axis point +% upward, while typical image software has the $y$ axis point down. +% \texttt{pdftocairo} typically assumes a 150 PPI (pixels-per-inch) +% resolution. +% +% That means that scaling factor becomes +% +% $$\frac{150\mathrm{pixel}}{2.54\mathrm{cm}}=59.055\frac{\mathrm{pixel}}{\mathrm{cm}}$$ +% +% \iffalse +% Using definition in terms of printers feet - the one to use! +% +% PNG: 1674 x 1101 +% PDF: "lower left": [-0.02107,-0.02107], +% "upper right": [28.31705,18.60843] +% Width: 28.31705+0.02107 = 28.33812 +% Height: 18.60843+0.02107 = 18.62950 +% Pixel / cm: 1674 / 28.33812 = 59.07237318495369488166 +% 1101 / 18.62950 = 59.09981480984460130438 +% Average = 59.08609399739914809302 +% +% Calculated = 150 / 2.54 = 59.05511811023622047244 +% +% Using 1/72.27 +% +% "lower left": [-0.02109,-0.02109], +% "upper right": [28.321,18.61102] +% Width: 28.321+0.02109=28.34209 +% Height: 18.61102+0.02109=18.63211 +% Pixel / cm: 1674 / 28.34209 = 59.06409866033168337267 +% 1101 / 18.63211 = 59.09153606328000425072 +% Average = 59.07781736180584381169 +% \fi +% +% The information extracted is written to the +% \cs{jobname}\texttt{.json} file as a sub-object (with name given by +% the first optional argument) of the image object. In that way, we +% can later on easily get the information from our catalogue of +% images. +% +% Note, the styles \texttt{zoned}, \texttt{zone scope}, and +% \texttt{zone path} are defined in \texttt{wargame} to be dummies so +% that one can have them in the definition of the board without +% impact. +% +% Since we want to write all dimensions in centimetres, we need to be +% able to convert \texttt{pt} dimensions to centimetres. We make two +% macros to do that for us. +% +% The exact definition of 1pt is +% +% $$1\,\mathrm{pt} = \frac{249}{250}12"\frac{1}{864}=\frac{83}{6000}1" +% = 0.03513\overline{6}$$ +% +% \begin{macrocode} +% 2.54 / 72.27 = .03514598035145980351 +% \def\pt@to@cm#1{\pgfmathparse{#1 * 0.0351460}} +\def\pt@to@cm#1{\pgfmathparse{#1 * 0.0351367}} +\def\ptpoint@to@cm#1#2{% + \pt@to@cm{#1}\edef\x{\pgfmathresult}% + \pt@to@cm{#2}\edef\y{\pgfmathresult}} +% \end{macrocode} +% \begin{macrocode} +\def\get@bb#1{% + \pgfpointanchor{#1}{south west}% + \pgfgetlastxy\tmp@llx\tmp@lly% + \pgfpointanchor{#1}{north east}% + \pgfgetlastxy\tmp@urx\tmp@ury% + \pt@to@cm{\tmp@llx}\edef\llx{\pgfmathresult} + \pt@to@cm{\tmp@lly}\edef\lly{\pgfmathresult} + \pt@to@cm{\tmp@urx}\edef\urx{\pgfmathresult} + \pt@to@cm{\tmp@ury}\edef\ury{\pgfmathresult}} +% \end{macrocode} +% \begin{macrocode} +\def\mk@transform{% + \pgfgettransformentries{\mxx}{\mxy}{\myx}{\myy}{\ptdx}{\ptdy} + \pt@to@cm{\ptdx}\edef\dx{\pgfmathresult} + \pt@to@cm{\ptdy}\edef\dy{\pgfmathresult} + \mk@w{ \mk@i "xx": \mxx,} + \mk@w{ \mk@i "xy": \mxy,} + \mk@w{ \mk@i "yx": \myx,} + \mk@w{ \mk@i "yy": \myy,} + \mk@w{ \mk@i "dx": \dx,} + \mk@w{ \mk@i "dy": \dy,} +} +% \end{macrocode} +% \begin{macrocode} +\def\mk@bb#1{% + \get@bb{#1} + \mk@w{ \mk@i "lower left": [\llx,\lly],} + \mk@w{ \mk@i "upper right": [\urx,\ury],} + \begingroup + % \pgftransforminvert + \pgfpointanchor{#1}{south west}% + \pgfgetlastxy\tmp@llx\tmp@lly% + \pgfpointtransformed{\pgfpoint{\tmp@llx}{\tmp@lly}} + \pgf@xa=\pgf@x + \pgf@ya=\pgf@y + % + \pgfpointanchor{#1}{north east}% + \pgfgetlastxy\tmp@urx\tmp@ury% + \pgfgetlastxy\tmp@llx\tmp@lly% + \pgfpointtransformed{\pgfpoint{\tmp@urx}{\tmp@ury}} + \pgf@xb=\pgf@x + \pgf@yb=\pgf@y + \pt@to@cm{\the\pgf@xa}\edef\llx{\pgfmathresult} + \pt@to@cm{\the\pgf@ya}\edef\lly{\pgfmathresult} + \pt@to@cm{\the\pgf@xb}\edef\urx{\pgfmathresult} + \pt@to@cm{\the\pgf@yb}\edef\ury{\pgfmathresult}x + \mk@w{ \mk@i "global lower left": [\llx,\lly],} + \mk@w{ \mk@i "global upper right": [\urx,\ury]} + \endgroup +} +% \end{macrocode} +% +% For the key \texttt{zone path} to work, we need to be able to record +% the path as it moves along. To that end, we make a custom +% decoration that will do that for us, and, once the path is finished, +% write the path to our JSON file. +% +% \begin{macrocode} +\pgfdeclaredecoration{record path construction}{initial}{% + \state{initial}[width=0pt,next state=more]{ + \begingroup + \pgf@decorate@inputsegment@first + \ptpoint@to@cm{\the\pgf@x}{\the\pgf@y} + \xdef\wg@path{[\x,\y]} + \endgroup + }% + \state{more}[width=\pgfdecoratedinputsegmentremainingdistance]{% + \begingroup + \pgf@decorate@inputsegment@last + \ptpoint@to@cm{\the\pgf@x}{\the\pgf@y} + \xdef\wg@path{\wg@path,[\x,\y]} + \endgroup + } + \state{final}{% + \begingroup + \pgf@decorate@inputsegment@last + \ptpoint@to@cm{\the\pgf@x}{\the\pgf@y} + \xdef\wg@path{\wg@path,[\x,\y]} + \endgroup + \mk@w{ \mk@i "zone path \wg@record@path@name": \@lbchar} + \mk@w{ \mk@i\space "path": [\wg@path] \@rbchar,} + } +}% +% \end{macrocode} +% +% Now we can make our environment +% +% The first thing we do is to use the \cs{info} macro to mark the +% image. Then we open our JSON file. We make a short-hand macro for +% writing to that file. The macro \cs{bd@i} records the current +% indention (which is important in JSON) +% +% \begin{macrocode} +\newenvironment{boardimage}[3][board]{% + \def\bd@n{#2} + \newcount\mk@point + \mk@point=0 + \let\oomk@i\mk@i% +% \end{macrocode} +% +% +% Then, to extract the label option, we make a dummy \texttt{node} +% with the styles \texttt{every hex} and \texttt{every hex node}, so +% we can extract that option. +% +% \begin{macrocode} + \info{dummy}{<<dummy>>}{}% + %\tikz{}% + \tikz{\scoped[every hex/.try,every hex node/.try]{% + \node[inner sep=0,outer sep=0]{% + \global\let\mk@label\hex@label}}}% +% \end{macrocode} +% +% The next thing we do is to make an object. The first things we put +% in are the units used (``cm''), and the grid options. +% +% \begin{macrocode} + \info*{#2}{#1}{#3}% + \mk@w{ \mk@i "zones": \@lbchar}% + \edef\mk@i{\mk@i\space} + %% Everything is made into centimeters + \mk@w{ \mk@i "units": "cm",} + \message{^^Jlabel: \meaning\mk@label} + \@ifundefined{mk@label}{}{\mk@w{ \mk@i "labels": "\mk@label",}} + %% Write out coordinate options as "coords" object + \mk@w{ \mk@i"coords": \@lbchar}% + \mk@w{ \mk@i "row": \@lbchar}% + \mk@w{ \mk@i\space "offset": \hex@coords@row@off,}% + \mk@w{ \mk@i\space "factor": \hex@coords@row@fac \@rbchar,}% + \mk@w{ \mk@i "column": \@lbchar}% + \mk@w{ \mk@i\space "offset": \hex@coords@col@off,}% + \mk@w{ \mk@i\space "factor": \hex@coords@col@fac,}% + \mk@w{ \mk@i\space "top short": "\hex@top@short@col",}% + \mk@w{ \mk@i\space "bottom short": "\hex@bot@short@col" \@rbchar}% + \mk@w{ \mk@i\@rbchar,}% +% \end{macrocode} +% +% We then monkey-patch \cs{boardframe} to also output coordinates to +% our JSON file. Note that this will probably be embedded in a +% different object. +% +% \begin{macrocode} + %% + \let\oldbo@rdframe\bo@rdframe% + \def\bo@rdframe[##1](##2)(##3){% + \oldbo@rdframe[##1](##2)(##3)% + \mk@w{ \mk@i"board frame": \@lbchar} + \mk@w{ \mk@i\space "lower left": [\llx,\lly],} + \mk@w{ \mk@i\space "upper right": [\urx,\ury],} + \mk@w{ \mk@i\space "margin": \margin,} + \mk@w{ \mk@i\space "width": \w,} + \mk@w{ \mk@i\space "height": \h \@rbchar,}}% +% \end{macrocode} +% +% Next, we make the style \texttt{zoned} to be applied to the +% \texttt{tikzpicture} environment. This records the bounding box of +% the full picture. +% +% \begin{macrocode} + \tikzset{ + zoned/.code={% Apply to whole picture + \pgfkeys{% + % This needs to be done in the picture! + /tikz/execute at end picture={% + \mk@w{ \mk@i "zoned": \@lbchar} + \mk@transform% + \mk@bb{current bounding box} + \mk@w{ \mk@i \@rbchar,} + } + } + }, +% \end{macrocode} +% +% The next style is the \texttt{zone scope}. At the start of the +% scope we record the current transformation matrix. Then we install +% a handler to extract the bounding box at the end of the scope. Note +% that we increase indention here. +% +% \begin{macrocode} + zone scope/.code={% + \mk@w{ \mk@i"zone scope ##1": \@lbchar} + \let\omk@i\mk@i + \edef\mk@i{\mk@i\space} + \mk@transform% + %\bd@w{ \@rbchar,} + \gdef\wg@export@box{##1}% + \pgfkeys{% + /tikz/local bounding box=wg export box, + /tikz/execute at end scope={ + \mk@bb{wg export box} + \let\mk@i\omk@i + \mk@w{ \mk@i\@rbchar,}}, + } % pgfkeys + }, % zone scope +% \end{macrocode} +% The next style gets the global coordinates of the current (0,0) +% point - f.ex. in a node - and outputs that +% \begin{macrocode} + zone point/.code n args={3}{ + \advance\mk@point1 + \global\mk@point=\mk@point + \pgf@xa=##2 cm + \pgf@ya=##3 cm + \pgfpointtransformed{\pgfpoint{\pgf@xa}{\pgf@ya}} + % \pgfpointtransformed{\pgfpoint{0pt}{0pt}} + \pgf@xa=\pgf@x + \pgf@ya=\pgf@y + \pt@to@cm{\the\pgf@xa}\edef\px{\pgfmathresult} + \pt@to@cm{\the\pgf@ya}\edef\py{\pgfmathresult} + \mk@w{ \mk@i "point\the\mk@point": \@lbchar "name": "##1", "type": "point", "coords": [\px,\py] + \@rbchar, } + %\message{^^JZone point \the\mk@point\space ##1: ##2,##3 -> \px,\py} + }, +% \end{macrocode} +% +% The \texttt{zone path} style is a bit more simple, but only because +% the bulk of the work is done in a decoration. We need to be able to +% pass a name to that decoration, s we make a key for that. The user +% need not think about that though. +% +% \begin{macrocode} + /pgf/decoration/record path name/.store in=\wg@record@path@name, + zone path/.style={% + postaction={decorate,decoration={ + record path construction, + record path name=##1}} + } % zone path + }% tikzset +} +% \end{macrocode} +% +% That finishes the first part of the environment. At the end of the +% environment, we simple write the name of the picture, and close our +% JSON output. +% +% \begin{macrocode} +{% + \mk@w{ \mk@i "name": "\bd@n" }% + \let\mk@i\oomk@i% + \mk@w{ \mk@i\@rbchar}% + \end@info% +} +% \end{macrocode} +% +% +% TO BE DONE: We could add hooks to both the \texttt{hex} and +% \texttt{chit} shapes that would allow us to write out the settings +% for each of these. This would allow us to make data files that +% contain the information available in the \LaTeX{} code. For +% example, we could write a counters +% +% \begin{itemize} +% \item Left and right identifiers +% \item Upper left, upper right, lower left, and lower right +% identifiers. (some care must be taken if these contains graphics +% and not just text.) +% \item Factors +% \item NATO symbol +% \begin{itemize} +% \item Faction, command, echelon +% \item Mains +% \item Left, right, top, and bottom attributes and modifiers +% \item Below attribute +% \end{itemize} +% \end{itemize} +% +% If one then assumed that for example the upper left corner holds the +% start-up hex, then one could use that information. +% +% The code below exports the chit information to the JSON file. Not +% sure how to use it though. +% +% \begin{macrocode} +\tikzset{ + zone turn/.store in=\zone@turn, + zone mult/.store in=\zone@mult +} +\def\do@chit@report{% + \mk@w{ \mk@i "chit": \@lbchar} + \@ifundefined{id}{} {\mk@w{ \mk@i\space "id": "\id", }}% + \@ifundefined{chit@symbol}{} {\mk@w{ \mk@i\space "symbol": "true", }}% + \@ifundefined{chit@full}{} {\mk@w{ \mk@i\space "full": "\chit@full", }} + \@ifundefined{chit@factors}{} {\mk@w{ \mk@i\space "factors": "\chit@factors", }}% + \@ifundefined{chit@left}{} {\mk@w{ \mk@i\space "left": "\chit@left", }}% + \@ifundefined{chit@right}{} {\mk@w{ \mk@i\space "right": "\chit@right", }}% + \@ifundefined{chit@upper@left}{} {\mk@w{ \mk@i\space "upper left": "\chit@upper@left", }}% + \@ifundefined{chit@lower@left}{} {\mk@w{ \mk@i\space "lower left": "\chit@lower@left", }}% + \@ifundefined{chit@upper@right}{}{\mk@w{ \mk@i\space "upper right": "\chit@upper@right", }}% + \@ifundefined{chit@lower@right}{}{\mk@w{ \mk@i\space "lower right": "\chit@lower@right}", }% + \mk@w{ \mk@i\space "end": 0} + \@ifundefined{chit@symbol}{ + \mk@w{ \mk@i \@rbchar } + }{ + \mk@w{ \mk@i \@rbchar, }% NATOAPP6c will follow + }% +} +\def\do@natoapp@report{% + \mk@w{ \mk@i "natoapp6c": \@lbchar} + \@ifundefined{id}{}{\mk@w{ \mk@i\space "id": "\id", }} + \@ifundefined{natoapp@fac}{}{\mk@w{ \mk@i\space "faction": "\natoapp@fac", }} + \@ifundefined{natoapp@cmd}{}{\mk@w{ \mk@i\space "command": "\natoapp@cmd", }} + \@ifundefined{natoapp@ech}{}{\mk@w{ \mk@i\space "echelon": "\natoapp@ech", }} + \@ifundefined{natoapp@main}{}{\mk@w{ \mk@i\space "main": "\natoapp@main", }} + \@ifundefined{natoapp@left}{}{\mk@w{ \mk@i\space "left": "\natoapp@left", }} + \@ifundefined{natoapp@right}{}{\mk@w{ \mk@i\space "right": "\natoapp@right", }} + \@ifundefined{natoapp@upper}{}{\mk@w{ \mk@i\space "upper": "\natoapp@upper", }} + \@ifundefined{natoapp@lower}{}{\mk@w{ \mk@i\space "lower": "\natoapp@lower", }} + \@ifundefined{natoapp@below}{}{\mk@w{ \mk@i\space "below": "\natoapp@below", }} + \mk@w{ \mk@i\space "end": 0} + \mk@w{ \mk@i \@rbchar} +} +% \end{macrocode} +% \iffalse +%</exportcls> +%\fi +% |