%% eurion.sty -- EURion constellation overlay for LaTeX documents
%% v0.1.0, 2026-04-26
%% Copyright (C) 2026 originalsouth <5300799+originalsouth@users.noreply.github.com>
%%
%% License: WTFPL (see LICENSE). The author does not endorse this
%% license; it was picked because CTAN distribution requires *some*
%% license to be selected.
%%
%% Draws the five-circle "EURion" anti-photocopy pattern across document
%% pages. Visual reproduction only -- not a real anti-counterfeiting feature.
%%
%% Usage:
%%   \usepackage{eurion}                              % default scatter, gold
%%   \usepackage[scatter, color=yellow]{eurion}
%%   \usepackage[corner=top-right, color=green]{eurion}
%%   \usepackage[manual]{eurion}                      % then call \eurion[..]{x,y}
%%
%% References used to derive the geometry:
%%   - https://gist.github.com/petrkutalek/93b7eebf22f4dbcfab8cd80a91fd27a8
%%   - https://en.wikipedia.org/wiki/EURion_constellation
%%   - https://everything2.com/user/spiregrain/writeups/EURion+Constellation

\NeedsTeXFormat{LaTeX2e}
\ProvidesPackage{eurion}[2026/04/26 v0.1.0 EURion constellation overlay]

\RequirePackage{xkeyval}
\RequirePackage{tikz}
\RequirePackage{eso-pic}

%% --- color presets -------------------------------------------------------
\definecolor{eurion@gold}{cmyk}{0,0.1933,0.5714,0.0667}% kutalek default
\definecolor{eurion@yellow}{rgb}{1,0.85,0}
\definecolor{eurion@green}{rgb}{0.45,0.75,0.3}
\definecolor{eurion@orange}{rgb}{1,0.6,0.1}

%% --- option storage with defaults ---------------------------------------
\def\eurion@mode{scatter}
\def\eurion@color{eurion@gold}
\def\eurion@size{1}
\def\eurion@density{20}
\def\eurion@rotate{random}
\def\eurion@corner{north east}
\def\eurion@seed{1}

\def\eurion@rot@random{random}
\def\eurion@rot@none{none}

%% --- corner-name parser (top-right -> north east, etc.) ----------------
\def\eurion@parsecorner#1{%
  \def\eurion@tmp{#1}%
  \def\eurion@TL{top-left}\def\eurion@TR{top-right}%
  \def\eurion@BL{bottom-left}\def\eurion@BR{bottom-right}%
  \ifx\eurion@tmp\eurion@TL \def\eurion@corner{north west}\else
  \ifx\eurion@tmp\eurion@TR \def\eurion@corner{north east}\else
  \ifx\eurion@tmp\eurion@BL \def\eurion@corner{south west}\else
  \ifx\eurion@tmp\eurion@BR \def\eurion@corner{south east}\else
                            \def\eurion@corner{north east}%
  \fi\fi\fi\fi}

%% --- color-name resolver (preset vs user xcolor expr) ------------------
\def\eurion@parsecolor#1{%
  \@ifundefined{\string\color @eurion@#1}%
    {\def\eurion@color{#1}}%             user color or xcolor expression
    {\def\eurion@color{eurion@#1}}}%     built-in preset

%% --- runtime keyval keys (used by \eurion[...] at point of call) -------
\define@key{eurion}{color}{\eurion@parsecolor{#1}}
\define@key{eurion}{size}{\def\eurion@size{#1}}
\define@key{eurion}{density}{\def\eurion@density{#1}}
\define@key{eurion}{rotate}{\def\eurion@rotate{#1}}
\define@key{eurion}{seed}{\def\eurion@seed{#1}}
\define@key{eurion}{corner}{\eurion@parsecorner{#1}}
\define@key{eurion}{mode}{\def\eurion@mode{#1}}

%% --- package options (load-time) ---------------------------------------
\DeclareOptionX{scatter}[]{\def\eurion@mode{scatter}}
\DeclareOptionX{manual}[]{\def\eurion@mode{manual}}
\DeclareOptionX{corner}[__flag__]{%
  \def\eurion@tmpa{#1}\def\eurion@tmpb{__flag__}%
  \ifx\eurion@tmpa\eurion@tmpb
    \def\eurion@mode{corner}%
  \else
    \eurion@parsecorner{#1}%
    \def\eurion@mode{corner}%
  \fi}
\DeclareOptionX{mode}{\def\eurion@mode{#1}}
\DeclareOptionX{color}{\eurion@parsecolor{#1}}
\DeclareOptionX{size}{\def\eurion@size{#1}}
\DeclareOptionX{density}{\def\eurion@density{#1}}
\DeclareOptionX{rotate}{\def\eurion@rotate{#1}}
\DeclareOptionX{seed}{\def\eurion@seed{#1}}
\DeclareOptionX*{\PackageWarning{eurion}{Unknown option `\CurrentOption' ignored}}
\ProcessOptionsX

%% --- the constellation itself ------------------------------------------
%% Polar centers (from petrkutalek): (0,0), (2.5,0deg), (2.6,78deg),
%% (4.0,188deg), (3.8,258deg), all in mm. Stroked 0.4mm rings.
%% Public lore: 1mm circle diameter, ~4mm max spread, squared distances
%% reportedly form integer ratios (Andrew Steer); the exact spec is secret.
\newcommand{\eurion@constellation}{%
  \draw (0mm,0mm) circle (0.4mm);
  \draw (2.5mm,0mm) circle (0.4mm);
  \begin{scope}[rotate=78]
    \draw (2.6mm,0mm) circle (0.4mm);
    \begin{scope}[rotate=110]
      \draw (4.0mm,0mm) circle (0.4mm);
      \begin{scope}[rotate=70]
        \draw (3.8mm,0mm) circle (0.4mm);
      \end{scope}
    \end{scope}
  \end{scope}%
}

%% --- rotation resolver -------------------------------------------------
%% Sets \eurion@theta from \eurion@rotate ("random" / "none" / number).
\newcommand{\eurion@computetheta}{%
  \ifx\eurion@rotate\eurion@rot@random
    \pgfmathsetmacro{\eurion@theta}{rnd*360}%
  \else
    \ifx\eurion@rotate\eurion@rot@none
      \def\eurion@theta{0}%
    \else
      \edef\eurion@theta{\eurion@rotate}%
    \fi
  \fi
}

%% --- scatter background -----------------------------------------------
\newcommand{\eurion@scatterpage}{%
  \begin{tikzpicture}[remember picture, overlay]
    \pgfmathsetseed{\numexpr\eurion@seed + \value{page}\relax}%
    \pgfmathsetmacro{\eurion@pw}{\paperwidth}%
    \pgfmathsetmacro{\eurion@ph}{\paperheight}%
    \foreach \eurion@i in {1,...,\eurion@density}{%
      \pgfmathsetmacro{\eurion@x}{rnd*\eurion@pw}%
      \pgfmathsetmacro{\eurion@y}{rnd*\eurion@ph}%
      \eurion@computetheta
      \begin{scope}[shift={(\eurion@x pt, \eurion@y pt)},
                    rotate=\eurion@theta,
                    scale=\eurion@size,
                    draw=\eurion@color,
                    line width=0.3mm]
        \eurion@constellation
      \end{scope}%
    }%
  \end{tikzpicture}%
}

%% --- corner background ------------------------------------------------
\newcommand{\eurion@cornerpage}{%
  \begin{tikzpicture}[remember picture, overlay]
    \begin{scope}[shift={([shift={(\eurion@dx,\eurion@dy)}]current page.\eurion@corner)},
                  scale=\eurion@size,
                  draw=\eurion@color,
                  line width=0.3mm]
      \eurion@constellation
    \end{scope}
  \end{tikzpicture}%
}

%% --- install background hook based on selected mode --------------------
\AtBeginDocument{%
  \def\eurion@modes{scatter}%
  \def\eurion@modec{corner}%
  \def\eurion@modem{manual}%
  \ifx\eurion@mode\eurion@modes
    \AddToShipoutPictureBG{\eurion@scatterpage}%
  \else
    \ifx\eurion@mode\eurion@modec
      \def\eurion@nw{north west}\def\eurion@ne{north east}%
      \def\eurion@sw{south west}\def\eurion@se{south east}%
      \ifx\eurion@corner\eurion@nw \def\eurion@dx{ 15mm}\def\eurion@dy{-15mm}\else
      \ifx\eurion@corner\eurion@ne \def\eurion@dx{-15mm}\def\eurion@dy{-15mm}\else
      \ifx\eurion@corner\eurion@sw \def\eurion@dx{ 15mm}\def\eurion@dy{ 15mm}\else
      \ifx\eurion@corner\eurion@se \def\eurion@dx{-15mm}\def\eurion@dy{ 15mm}\else
                                    \def\eurion@dx{-15mm}\def\eurion@dy{-15mm}%
      \fi\fi\fi\fi
      \AddToShipoutPictureBG{\eurion@cornerpage}%
    \fi
  \fi
}

%% --- public macro: \eurion[opts]{coord-or-x,y} -------------------------
%% The user passes a TikZ coordinate (e.g. "current page.center" or
%% "5cm,3cm"); the macro draws one constellation there in an overlay.
\newcommand{\eurion}[2][]{%
  \begingroup
    \setkeys{eurion}{#1}%
    \eurion@computetheta
    \begin{tikzpicture}[remember picture, overlay]
      \begin{scope}[shift={(#2)},
                    rotate=\eurion@theta,
                    scale=\eurion@size,
                    draw=\eurion@color,
                    line width=0.3mm]
        \eurion@constellation
      \end{scope}
    \end{tikzpicture}%
  \endgroup
}

\endinput
