%% fxpicture.sty
%%
%% Line styles for LaTeX's picture environment, on top of pict2e.
%%
%% Written by Claude AI (Anthropic), with direction from CodeCogs Ltd.
%% A working implementation: https://fxeditor.codecogs.com
%%
%% Copyright (C) 2026 CodeCogs Ltd.
%%
%% This work may be distributed and/or modified under the conditions of the LaTeX Project
%% Public License, either version 1.3c of this license or (at your option) any later version.
%% The latest version of this license is in https://www.latex-project.org/lppl.txt
%%
%% This work has the LPPL maintenance status `maintained'. The Current Maintainer of this
%% work is CodeCogs Ltd. This work consists of the files fxpicture.sty and fxpicture-doc.tex,
%% and the derived file fxpicture-doc.pdf.
%%
%%   \usepackage{fxpicture}            % loads pict2e; options are passed to it
%%
%%   \linestyle{solid}                 % the default
%%   \linestyle{dashed}                % on 3pt, off 3pt
%%   \linestyle{dotted}                % on one line width, off 2pt
%%   \linestyle{dashdot}               % on 3pt, off 2pt, on one line width, off 2pt
%%   \dashpattern{<on>}{<off>}         % a dash pattern of your own, eg \dashpattern{3pt}{2pt}
%%
%% Both are ordinary declarations, like \linethickness: they last to the end of the group, and
%% apply to every line pict2e strokes - \line, \vector's shaft, \Line, \polyline, \polygon,
%% \circle, \oval, \arc, \qbezier, \cbezier and \strokepath. Filled shapes (\circle*, \polygon*,
%% \arc*, arrowheads) are not dashed.
%%
%%   {\linestyle{dashed}
%%     \put(10,10){\line(1,0){40}}
%%     \put(10,20){\oval(40,10)}
%%     \put(10,30){\qbezier(0,0)(20,15)(40,0)}
%%   }
%%
%% The lengths of \dashpattern are lengths (3pt, 1mm), or bare numbers as multiples of
%% \unitlength as it is when \dashpattern is given. The pattern starts afresh at the beginning
%% of each path. The named styles follow TikZ's (dashed, dotted, dash dot), so a picture and a
%% TikZ drawing side by side match; dotted and dashdot dots are as long as the line is thick,
%% whatever \linethickness is when the line is drawn.
%%
%% Works with each of pict2e's drivers (pdftex, luatex, xetex, dvips, dvipdfm).
%%
%%   \grid(<wd>,<ht>)(<dx>,<dy>)                % a grid, its lower-left corner at the point
%%   \grid(<wd>,<ht>)(<dx>,<dy>)[<x0>,<y0>]     % its lines numbered from x0 and y0
%%
%% epic's \grid, drawn as epic draws it - the same lines, the same numbers in the same places -
%% but taking no room: written straight in the picture rather than in a \put, epic's moves what
%% follows along by the grid's width, this one leaves it where it is. The lengths may have units,
%% as the picture package allows; the numbers count up by the steps in \unitlength. Its lines
%% are rules, as epic's are, so \linestyle does not dash them. When epic is loaded, before or
%% after this package, epic's \grid is the one used.
%%
\NeedsTeXFormat{LaTeX2e}
\ProvidesPackage{fxpicture}[2026/10/15 v1.1 Line styles and grids for the picture environment]

\DeclareOption*{\PassOptionsToPackage{\CurrentOption}{pict2e}}
\ProcessOptions\relax
\RequirePackage{pict2e}[2020/09/30]

% The dash operator of the output: PostScript for dvips, PDF otherwise. pict2e has already set
% its user space to points (\pIIe@scale@PTtoBP), so the lengths are written in pt.
\ifnum\pIIe@mode=\@ne
  \def\fxp@setdash@op{setdash}
\else
  \def\fxp@setdash@op{d}
\fi

% \fxp@dash expands, inside pict2e's \edef, to the dash operator of the current style, or to
% nothing for solid lines - so a picture without \linestyle comes out exactly as pict2e makes it.
\let\fxp@dash\@empty
\def\fxp@w{\strip@pt\@wholewidth}

\@namedef{fxp@style@solid}{\let\fxp@dash\@empty}
\@namedef{fxp@style@dashed}{%
  \def\fxp@dash{ [3 3] 0 \fxp@setdash@op}}
\@namedef{fxp@style@dotted}{%
  \def\fxp@dash{ [\fxp@w\space 2] 0 \fxp@setdash@op}}
\@namedef{fxp@style@dashdot}{%
  \def\fxp@dash{ [3 2 \fxp@w\space 2] 0 \fxp@setdash@op}}

\DeclareRobustCommand*\linestyle[1]{%
  \@ifundefined{fxp@style@#1}%
    {\PackageError{fxpicture}{Unknown line style `#1'}%
       {The line styles are solid, dashed, dotted and dashdot;\MessageBreak
        \protect\dashpattern{on}{off} makes one of your own.}}%
    {\@nameuse{fxp@style@#1}}%
  \ignorespaces}

\DeclareRobustCommand*\dashpattern[2]{%
  \@defaultunitsset\@tempdima{#1}\unitlength
  \@defaultunitsset\@tempdimb{#2}\unitlength
  \ifdim\@tempdima<\z@ \fxp@baddash \else
  \ifdim\@tempdimb<\z@ \fxp@baddash \else
  \ifdim\dimexpr\@tempdima+\@tempdimb\relax=\z@ \fxp@baddash \else
    \edef\fxp@dash{ [\strip@pt\@tempdima\space\strip@pt\@tempdimb] 0 \noexpand\fxp@setdash@op}%
  \fi\fi\fi
  \ignorespaces}
\def\fxp@baddash{%
  \PackageError{fxpicture}{Bad \protect\dashpattern}%
    {Its lengths can't be negative, nor both zero.}}

% pict2e strokes every path through \pIIe@drawGraph; this is pict2e's own (v0.4b, 2020) with
% \fxp@dash after the line join, in the branch that strokes. With no driver (pict2e's
% `original' option) pict2e draws nothing of its own, and there is nothing to dash.
\ifnum\pIIe@mode>\z@
  \def\fxp@drawGraph@pIIe{%
      \edef\x{\pIIe@debug@comment\space
              \pIIe@scale@PTtoBP}%
      \if@tempswa
        \edef\y{\pIIe@fill@op}%
      \else
        \edef\x{\x\space
          \strip@pt\@wholewidth\space\pIIe@setlinewidth@op
          \pIIe@linecap\pIIe@linejoin\space}%
        \edef\y{\pIIe@stroke@op}%
      \fi
      \expandafter\pIIe@code\expandafter{%
        \expandafter\x\the\pIIe@GRAPH\space\y}%
      \global\pIIe@GRAPH{}\xdef\pIIe@CPx{}\xdef\pIIe@CPy{}%
    \endgroup}
  \ifx\pIIe@drawGraph\fxp@drawGraph@pIIe\else
    \PackageWarningNoLine{fxpicture}{%
      This pict2e's \string\pIIe@drawGraph\space is not the one\MessageBreak
      fxpicture was written for; line styles may not work}%
  \fi
  \def\pIIe@drawGraph{%
      \edef\x{\pIIe@debug@comment\space
              \pIIe@scale@PTtoBP}%
      \if@tempswa
        \edef\y{\pIIe@fill@op}%
      \else
        \edef\x{\x\space
          \strip@pt\@wholewidth\space\pIIe@setlinewidth@op
          \pIIe@linecap\pIIe@linejoin\fxp@dash\space}%
        \edef\y{\pIIe@stroke@op}%
      \fi
      \expandafter\pIIe@code\expandafter{%
        \expandafter\x\the\pIIe@GRAPH\space\y}%
      \global\pIIe@GRAPH{}\xdef\pIIe@CPx{}\xdef\pIIe@CPy{}%
    \endgroup}
\fi

% pict2e's arrows (\vector, \Vector, \polyvector) are one filled outline, shaft and head
% together. With a line style, the outline is drawn without the shaft - its back corners are the
% only points at x=0, in both the LaTeX and the PSTricks arrowheads - and the shaft is stroked
% on its own, from the tail to half way into the head, under the head. Solid arrows are pict2e's
% own. \ltxarrows and \pstarrows still choose the arrowhead.
\ifnum\pIIe@mode>\z@
  \let\fxp@vector@orig\pIIe@vector
  \def\ltxarrows{\let\fxp@vector@orig\pIIe@vector@ltx}
  \def\pstarrows{\let\fxp@vector@orig\pIIe@vector@pst}
  \def\pIIe@vector{%
    \ifx\fxp@dash\@empty \fxp@vector@orig \else \fxp@dashedvector \fi}
  \def\fxp@dashedvector{%
    \edef\fxp@concat{\the\pIIe@GRAPH}%
    \let\fxp@lineto\pIIe@lineto
    \let\pIIe@lineto\fxp@headlineto
    \fxp@vector@orig
    \let\pIIe@lineto\fxp@lineto
    \ifdim\@xdim>\z@
      \edef\fxp@head{\the\pIIe@GRAPH}%
      \global\pIIe@GRAPH\expandafter{\fxp@concat}%
      \@tempdimc\@xdim \advance\@tempdimc\@linelen \divide\@tempdimc\tw@
      \pIIe@moveto\z@\z@ \pIIe@lineto\@tempdimc\z@
      \pIIe@strokeGraph
      \global\pIIe@GRAPH\expandafter{\fxp@head}%
    \fi}
  \def\fxp@headlineto#1#2{\ifdim#1=\z@ \else \fxp@lineto{#1}{#2}\fi}
\fi

% epic's \grid(wd,ht)(dx,dy)[x0,y0], in a \put(0,0) of its own so that it takes no room. The lines
% are epic's rules: as many each way as the integer division of size by step, and one more. The
% numbers are epic's \makebox(0,-2)[t] below, (0,0)[b] above (raised the 2mm epic's \vspace{2mm}
% gives), [r] on the left and [l] on the right, a space from the grid.
\newcount\fxp@gridcnt
\newcount\fxp@gridstep
\newcount\fxp@gridn
\newdimen\fxp@gridw
\newdimen\fxp@gridh
\newdimen\fxp@griddx
\newdimen\fxp@griddy
\def\fxp@gridcmd(#1,#2)(#3,#4){%
  \@ifnextchar[{\fxp@grid(#1,#2)(#3,#4)}{\fxp@grid(#1,#2)(#3,#4)[@,@]}}
\long\def\fxp@grid(#1,#2)(#3,#4)[#5,#6]{%
  \@defaultunitsset\fxp@gridw{#1}\unitlength
  \@defaultunitsset\fxp@gridh{#2}\unitlength
  \@defaultunitsset\fxp@griddx{#3}\unitlength
  \@defaultunitsset\fxp@griddy{#4}\unitlength
  \ifdim\fxp@griddx>\z@ \ifdim\fxp@griddy>\z@
  \put(0,0){%
    % The upright lines, and their numbers.
    \fxp@gridn\fxp@gridw \divide\fxp@gridn\fxp@griddx \advance\fxp@gridn\@ne
    \multiput(0,0)(#3,0){\fxp@gridn}{\hb@xt@\z@{\hskip-\@halfwidth
      \vrule\@width\@wholewidth\@height\fxp@gridh\@depth\z@\hss}}%
    \ifx#5@\else
      \fxp@gridstep\fxp@griddx \divide\fxp@gridstep\unitlength
      \global\fxp@gridcnt=#5\relax
      \multiput(0,0)(#3,0){\fxp@gridn}{\makebox(0,-2)[t]{%
        \number\fxp@gridcnt\global\advance\fxp@gridcnt\fxp@gridstep}}%
      \global\fxp@gridcnt=#5\relax
      \multiput(0,#2)(#3,0){\fxp@gridn}{\makebox(0,0)[b]{\raisebox{2mm}{%
        \number\fxp@gridcnt}\global\advance\fxp@gridcnt\fxp@gridstep}}%
    \fi
    % The level lines, and theirs.
    \fxp@gridn\fxp@gridh \divide\fxp@gridn\fxp@griddy \advance\fxp@gridn\@ne
    \multiput(0,0)(0,#4){\fxp@gridn}{\vrule\@height\@halfwidth\@depth\@halfwidth
      \@width\fxp@gridw}%
    \ifx#6@\else
      \fxp@gridstep\fxp@griddy \divide\fxp@gridstep\unitlength
      \global\fxp@gridcnt=#6\relax
      \multiput(0,0)(0,#4){\fxp@gridn}{\makebox(0,0)[r]{%
        \number\fxp@gridcnt\ \global\advance\fxp@gridcnt\fxp@gridstep}}%
      \global\fxp@gridcnt=#6\relax
      \multiput(#1,0)(0,#4){\fxp@gridn}{\makebox(0,0)[l]{%
        \ \number\fxp@gridcnt\global\advance\fxp@gridcnt\fxp@gridstep}}%
    \fi}%
  \else \fxp@badgrid \fi \else \fxp@badgrid \fi
  \ignorespaces}
\def\fxp@badgrid{%
  \PackageError{fxpicture}{Bad \protect\grid}{Its steps must be more than zero.}}
% Decided at \begin{document}, so that epic, loaded before or after, keeps its own.
\AtBeginDocument{%
  \@ifundefined{grid}%
    {\let\grid\fxp@gridcmd}%
    {\PackageInfo{fxpicture}{\string\grid\space is already defined (by epic?): kept}}}

\endinput
