summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/source/latex/l3experimental/l3draw
diff options
context:
space:
mode:
authorKarl Berry <karl@freefriends.org>2018-02-23 21:54:14 +0000
committerKarl Berry <karl@freefriends.org>2018-02-23 21:54:14 +0000
commit87d871a3d83784d48b71fa3712b9f525bfc710d2 (patch)
treef12f9ffdc697b5af9ee14c06874ec0e2f72c9f94 /Master/texmf-dist/source/latex/l3experimental/l3draw
parentccc63194ce7813106830c8a8755c54d89de831b4 (diff)
l3 (22feb18)
git-svn-id: svn://tug.org/texlive/trunk@46720 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/source/latex/l3experimental/l3draw')
-rw-r--r--Master/texmf-dist/source/latex/l3experimental/l3draw/l3draw-paths.dtx901
-rw-r--r--Master/texmf-dist/source/latex/l3experimental/l3draw/l3draw-points.dtx960
-rw-r--r--Master/texmf-dist/source/latex/l3experimental/l3draw/l3draw-scopes.dtx141
-rw-r--r--Master/texmf-dist/source/latex/l3experimental/l3draw/l3draw-softpath.dtx323
-rw-r--r--Master/texmf-dist/source/latex/l3experimental/l3draw/l3draw-state.dtx193
-rw-r--r--Master/texmf-dist/source/latex/l3experimental/l3draw/l3draw-transforms.dtx286
-rw-r--r--Master/texmf-dist/source/latex/l3experimental/l3draw/l3draw.dtx575
-rw-r--r--Master/texmf-dist/source/latex/l3experimental/l3draw/l3draw.ins66
8 files changed, 3445 insertions, 0 deletions
diff --git a/Master/texmf-dist/source/latex/l3experimental/l3draw/l3draw-paths.dtx b/Master/texmf-dist/source/latex/l3experimental/l3draw/l3draw-paths.dtx
new file mode 100644
index 00000000000..2fa882e7f1a
--- /dev/null
+++ b/Master/texmf-dist/source/latex/l3experimental/l3draw/l3draw-paths.dtx
@@ -0,0 +1,901 @@
+% \iffalse meta-comment
+%
+%% File: l3draw-paths.dtx Copyright(C) 2018 The LaTeX3 Project
+%
+% It may be distributed and/or modified under the conditions of the
+% LaTeX Project Public License (LPPL), either version 1.3c of this
+% license or (at your option) any later version. The latest version
+% of this license is in the file
+%
+% http://www.latex-project.org/lppl.txt
+%
+% This file is part of the "l3experimental bundle" (The Work in LPPL)
+% and all files in that bundle must be distributed together.
+%
+% -----------------------------------------------------------------------
+%
+% The development version of the bundle can be found at
+%
+% https://github.com/latex3/latex3
+%
+% for those people who are interested.
+%
+%<*driver>
+\RequirePackage{expl3}
+\documentclass[full]{l3doc}
+\begin{document}
+ \DocInput{\jobname.dtx}
+\end{document}
+%</driver>
+% \fi
+%
+% \title{^^A
+% The \pkg{l3draw-paths} package\\ Drawing paths^^A
+% }
+%
+% \author{^^A
+% The \LaTeX3 Project\thanks
+% {^^A
+% E-mail:
+% \href{mailto:latex-team@latex-project.org}
+% {latex-team@latex-project.org}^^A
+% }^^A
+% }
+%
+% \date{Released 2018/02/21}
+%
+% \maketitle
+%
+% \begin{implementation}
+%
+% \section{\pkg{l3draw-paths} implementation}
+%
+% \begin{macrocode}
+%<*initex|package>
+% \end{macrocode}
+%
+% \begin{macrocode}
+%<@@=draw>
+% \end{macrocode}
+%
+% This sub-module covers more-or-less the same ideas as
+% \texttt{pgfcorepathconstruct.code.tex}, though using the expandable FPU
+% means that the implementation often varies. At present, equivalents of the
+% following are currently absent:
+% \begin{itemize}
+% \item \cs{pgfpatharcto}, \cs{pgfpatharctoprecomputed}: These are
+% extremely specialised and are very complex in implementation. If the
+% functionality is required, it is likely that it will be set up from
+% scratch here.
+% \item \cs{pgfpathparabola}: Seems to be unused other than defining
+% a Ti\emph{k}Z interface, which itself is then not used further.
+% \item \cs{pgfpathsine}, \cs{pgfpathcosine}: Need to see exactly how
+% these need to work, in particular whether a wider input range is
+% needed and what approximation to make.
+% \item \cs{pgfpathcurvebetweentime}, \cs{pgfpathcurvebetweentimecontinue}:
+% These don't seem to be used at all.
+% \end{itemize}
+%
+% \begin{variable}
+% {\l_@@_path_tmp_tl, \l_@@_path_tmpa_fp, \l_@@_path_tmpb_fp}
+% Scratch space.
+% \begin{macrocode}
+\tl_new:N \l_@@_path_tmp_tl
+\fp_new:N \l_@@_path_tmpa_fp
+\fp_new:N \l_@@_path_tmpb_fp
+% \end{macrocode}
+% \end{variable}
+%
+% \subsection{Tracking paths}
+%
+% \begin{variable}{\g_@@_path_lastx_dim, \g_@@_path_lasty_dim}
+% The last point visited on a path.
+% \begin{macrocode}
+\dim_new:N \g_@@_path_lastx_dim
+\dim_new:N \g_@@_path_lasty_dim
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{variable}
+% {
+% \g_@@_path_xmax_dim,
+% \g_@@_path_xmin_dim,
+% \g_@@_path_ymax_dim,
+% \g_@@_path_ymin_dim
+% }
+% The limiting size of a path.
+% \begin{macrocode}
+\dim_new:N \g_@@_path_xmax_dim
+\dim_new:N \g_@@_path_xmin_dim
+\dim_new:N \g_@@_path_ymax_dim
+\dim_new:N \g_@@_path_ymin_dim
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{macro}{\@@_path_update_limits:nn}
+% \begin{macro}{\@@_path_reset_limits:}
+% Track the limits of a path and (perhaps) of the picture as a whole.
+% (At present the latter is always true: that will change as more complex
+% functionality is added.)
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_path_update_limits:nn #1#2
+ {
+ \dim_gset:Nn \g_@@_path_xmax_dim
+ { \dim_max:nn \g_@@_path_xmax_dim {#1} }
+ \dim_gset:Nn \g_@@_path_xmin_dim
+ { \dim_min:nn \g_@@_path_xmin_dim {#1} }
+ \dim_gset:Nn \g_@@_path_ymax_dim
+ { \dim_max:nn \g_@@_path_ymax_dim {#2} }
+ \dim_gset:Nn \g_@@_path_ymin_dim
+ { \dim_min:nn \g_@@_path_ymin_dim {#2} }
+ \bool_if:NT \l_@@_update_bb_bool
+ {
+ \dim_gset:Nn \g_@@_xmax_dim
+ { \dim_max:nn \g_@@_xmax_dim {#1} }
+ \dim_gset:Nn \g_@@_xmin_dim
+ { \dim_min:nn \g_@@_xmin_dim {#1} }
+ \dim_gset:Nn \g_@@_ymax_dim
+ { \dim_max:nn \g_@@_ymax_dim {#2} }
+ \dim_gset:Nn \g_@@_ymin_dim
+ { \dim_min:nn \g_@@_ymin_dim {#2} }
+ }
+ }
+\cs_new_protected:Npn \@@_path_reset_limits:
+ {
+ \dim_gset:Nn \g_@@_path_xmax_dim { -\c_max_dim }
+ \dim_gset:Nn \g_@@_path_xmin_dim { \c_max_dim }
+ \dim_gset:Nn \g_@@_path_ymax_dim { -\c_max_dim }
+ \dim_gset:Nn \g_@@_path_ymin_dim { \c_max_dim }
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\@@_path_update_last:nn}
+% A simple auxiliary to avoid repetition.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_path_update_last:nn #1#2
+ {
+ \dim_gset:Nn \g_@@_path_lastx_dim {#1}
+ \dim_gset:Nn \g_@@_path_lasty_dim {#2}
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \subsection{Corner arcs}
+%
+% At the level of path \emph{construction}, rounded corners are handled
+% by inserting a marker into the path: that is then picked up once the
+% full path is constructed. Thus we need to set up the appropriate
+% data structures here, such that this can be applied every time it is
+% relevant.
+%
+% \begin{variable}{\l_@@_corner_xarc_dim, \l_@@_corner_yarc_dim}
+% The two arcs in use.
+% \begin{macrocode}
+\dim_new:N \l_@@_corner_xarc_dim
+\dim_new:N \l_@@_corner_yarc_dim
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{variable}{\l_@@_corner_arc_bool}
+% A flag to speed up the repeated checks.
+% \begin{macrocode}
+\bool_new:N \l_@@_corner_arc_bool
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{macro}{\draw_path_corner_arc:n}
+% \begin{macro}{\@@_path_corner_arc:nn}
+% Calculate the arcs, check they are non-zero.
+% \begin{macrocode}
+\cs_new_protected:Npn \draw_path_corner_arc:n #1
+ {
+ \@@_point_process:nn { \@@_path_corner_arc:nn } {#1}
+ }
+\cs_new_protected:Npn \@@_path_corner_arc:nn #1#2
+ {
+ \dim_set:Nn \l_@@_corner_xarc_dim {#1}
+ \dim_set:Nn \l_@@_corner_yarc_dim {#2}
+ \bool_lazy_and:nnTF
+ { \dim_compare_p:nNn \l_@@_corner_xarc_dim = { 0pt } }
+ { \dim_compare_p:nNn \l_@@_corner_yarc_dim = { 0pt } }
+ { \bool_set_false:N \l_@@_corner_arc_bool }
+ { \bool_set_true:N \l_@@_corner_arc_bool }
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\@@_path_mark_corner:}
+% Mark up corners for arc post-processing.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_path_mark_corner:
+ {
+ \bool_if:NT \l_@@_corner_arc_bool
+ {
+ \@@_softpath_roundpoint:VV
+ \l_@@_corner_xarc_dim
+ \l_@@_corner_yarc_dim
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \subsection{Basic path constructions}
+%
+% \begin{macro}{\draw_path_moveto:n, \draw_path_lineto:n}
+% \begin{macro}{\@@_path_moveto:nn, \@@_path_lineto:nn}
+% \begin{macro}{\draw_path_curveto:nnn}
+% \begin{macro}{\@@_path_curveto:nnnnnn}
+% At present, stick to purely linear transformation support and skip the
+% soft path business: that will likely need to be revisited later.
+% \begin{macrocode}
+\cs_new_protected:Npn \draw_path_moveto:n #1
+ {
+ \@@_point_process:nn
+ { \@@_path_moveto:nn }
+ { \draw_point_transform:n {#1} }
+ }
+\cs_new_protected:Npn \@@_path_moveto:nn #1#2
+ {
+ \@@_path_update_limits:nn {#1} {#2}
+ \@@_softpath_moveto:nn {#1} {#2}
+ \@@_path_update_last:nn {#1} {#2}
+ }
+\cs_new_protected:Npn \draw_path_lineto:n #1
+ {
+ \@@_point_process:nn
+ { \@@_path_lineto:nn }
+ { \draw_point_transform:n {#1} }
+ }
+\cs_new_protected:Npn \@@_path_lineto:nn #1#2
+ {
+ \@@_path_mark_corner:
+ \@@_path_update_limits:nn {#1} {#2}
+ \@@_softpath_lineto:nn {#1} {#2}
+ \@@_path_update_last:nn {#1} {#2}
+ }
+\cs_new_protected:Npn \draw_path_curveto:nnn #1#2#3
+ {
+ \@@_point_process:nnn
+ {
+ \@@_point_process:nn
+ {
+ \@@_path_mark_corner:
+ \@@_path_curveto:nnnnnn
+ }
+ { \draw_point_transform:n {#1} }
+ }
+ { \draw_point_transform:n {#2} }
+ { \draw_point_transform:n {#3} }
+ }
+\cs_new_protected:Npn \@@_path_curveto:nnnnnn #1#2#3#4#5#6
+ {
+ \@@_path_update_limits:nn {#1} {#2}
+ \@@_path_update_limits:nn {#3} {#4}
+ \@@_path_update_limits:nn {#5} {#6}
+ \@@_softpath_curveto:nnnnnn {#1} {#2} {#3} {#4} {#5} {#6}
+ \@@_path_update_last:nn {#5} {#6}
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\draw_path_close:}
+% A simple wrapper.
+% \begin{macrocode}
+\cs_new_protected:Npn \draw_path_close:
+ {
+ \@@_path_mark_corner:
+ \@@_softpath_closepath:
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \subsection{Computed curves}
+%
+% More complex operations need some calculations. To assist with those, various
+% constants are pre-defined.
+%
+% \begin{macro}{\draw_path_curveto:nn}
+% \begin{macro}{\@@_path_curveto:nnnn}
+% \begin{variable}{\c_@@_path_curveto_a_fp, \c_@@_path_curveto_b_fp}
+% A quadratic curve with one control point $(x_{\mathrm{c}},
+% y_{\mathrm{c}})$. The two required control points are then
+% \[
+% x_{1} = \frac{1}{3}x_{\mathrm{s}} + \frac{2}{3}x_{\mathrm{c}}
+% \quad
+% y_{1} = \frac{1}{3}y_{\mathrm{s}} + \frac{2}{3}y_{\mathrm{c}}
+% \]
+% and
+% \[
+% x_{2} = \frac{1}{3}x_{\mathrm{e}} + \frac{2}{3}x_{\mathrm{c}}
+% \quad
+% x_{2} = \frac{1}{3}y_{\mathrm{e}} + \frac{2}{3}y_{\mathrm{c}}
+% \]
+% using the start (last) point $(x_{\mathrm{s}}, y_{\mathrm{s}})$
+% and the end point $(x_{\mathrm{s}}, y_{\mathrm{s}})$.
+% \begin{macrocode}
+\cs_new_protected:Npn \draw_path_curveto:nn #1#2
+ {
+ \@@_point_process:nnn
+ { \@@_path_curveto:nnnn }
+ { \draw_point_transform:n {#1} }
+ { \draw_point_transform:n {#2} }
+ }
+\cs_new_protected:Npn \@@_path_curveto:nnnn #1#2#3#4
+ {
+ \fp_set:Nn \l_@@_path_tmpa_fp { \c_@@_path_curveto_b_fp * #1 }
+ \fp_set:Nn \l_@@_path_tmpb_fp { \c_@@_path_curveto_b_fp * #2 }
+ \use:x
+ {
+ \@@_path_mark_corner:
+ \@@_path_curveto:nnnnnn
+ {
+ \fp_to_dim:n
+ {
+ \c_@@_path_curveto_a_fp * \g_@@_path_lastx_dim
+ + \l_@@_path_tmpa_fp
+ }
+ }
+ {
+ \fp_to_dim:n
+ {
+ \c_@@_path_curveto_a_fp * \g_@@_path_lasty_dim
+ + \l_@@_path_tmpb_fp
+ }
+ }
+ {
+ \fp_to_dim:n
+ { \c_@@_path_curveto_a_fp * #3 + \l_@@_path_tmpa_fp }
+ }
+ {
+ \fp_to_dim:n
+ { \c_@@_path_curveto_a_fp * #4 + \l_@@_path_tmpb_fp }
+ }
+ {#3}
+ {#4}
+ }
+ }
+\fp_const:Nn \c_@@_path_curveto_a_fp { 1 / 3 }
+\fp_const:Nn \c_@@_path_curveto_b_fp { 2 / 3 }
+% \end{macrocode}
+% \end{variable}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\draw_path_arc:nnn}
+% \begin{macro}{\draw_path_arc:nnnn}
+% \begin{macro}{\@@_path_arc:nnnn}
+% \begin{macro}{\@@_path_arc:nnNnn}
+% \begin{macro}
+% {
+% \@@_path_arc_auxi:nnnnNnn,
+% \@@_path_arc_auxi:fnnnNnn,
+% \@@_path_arc_auxi:fnfnNnn
+% }
+% \begin{macro}{\@@_path_arc_auxii:nnnNnnnn}
+% \begin{macro}{\@@_path_arc_auxiii:nn}
+% \begin{macro}{\@@_path_arc_auxiv:nnnn}
+% \begin{macro}{\@@_path_arc_auxv:nn, \@@_path_arc_auxvi:nn}
+% \begin{macro}{\@@_path_arc_add:nnnn}
+% \begin{variable}{\l_@@_path_arc_delta_fp, \l_@@_path_arc_start_fp}
+% \begin{variable}{\c_@@_path_arc_90_fp,\c_@@_path_arc_60_fp}
+% Drawing an arc means dividing the total curve required into sections:
+% using Bézier curves we can cover at most $90^{\circ}$ at once. To allow
+% for later manipulations, we aim to have roughly equal last segments to
+% the line, with the split set at a final part of $115^{\circ}$.
+% \begin{macrocode}
+\cs_new_protected:Npn \draw_path_arc:nnn #1#2#3
+ { \draw_path_arc:nnnn {#1} {#2} {#3} {#3} }
+\cs_new_protected:Npn \draw_path_arc:nnnn #1#2#3#4
+ {
+ \use:x
+ {
+ \@@_path_arc:nnnn
+ { \fp_eval:n {#1} }
+ { \fp_eval:n {#2} }
+ { \fp_to_dim:n {#3} }
+ { \fp_to_dim:n {#4} }
+ }
+ }
+\cs_new_protected:Npn \@@_path_arc:nnnn #1#2#3#4
+ {
+ \fp_compare:nNnTF {#1} > {#2}
+ { \@@_path_arc:nnNnn {#1} {#2} - {#3} {#4} }
+ { \@@_path_arc:nnNnn {#1} {#2} + {#3} {#4} }
+ }
+\cs_new_protected:Npn \@@_path_arc:nnNnn #1#2#3#4#5
+ {
+ \fp_set:Nn \l_@@_path_arc_start_fp {#1}
+ \fp_set:Nn \l_@@_path_arc_delta_fp { abs( #1 - #2 ) }
+ \fp_while_do:nNnn { \l_@@_path_arc_delta_fp } > { 90 }
+ {
+ \fp_compare:nNnTF \l_@@_path_arc_delta_fp > { 115 }
+ {
+ \@@_path_arc_auxi:ffnnNnn
+ { \fp_to_decimal:N \l_@@_path_arc_start_fp }
+ { \fp_eval:n { \l_@@_path_arc_start_fp #3 90 } }
+ { 90 } {#2}
+ #3 {#4} {#5}
+ }
+ {
+ \@@_path_arc_auxi:ffnnNnn
+ { \fp_to_decimal:N \l_@@_path_arc_start_fp }
+ { \fp_eval:n { \l_@@_path_arc_start_fp #3 60 } }
+ { 60 } {#2}
+ #3 {#4} {#5}
+ }
+ }
+ \@@_path_mark_corner:
+ \@@_path_arc_auxi:fnfnNnn
+ { \fp_to_decimal:N \l_@@_path_arc_start_fp }
+ {#2}
+ { \fp_eval:n { abs( \l_@@_path_arc_start_fp - #2 ) } }
+ {#2}
+ #3 {#4} {#5}
+ }
+% \end{macrocode}
+% The auxiliary is responsible for calculating the required points.
+% The \enquote{magic} number required to determine the length of the
+% control vectors is well-established for a right-angle:
+% $\frac{4}{3}(\sqrt{2} - 1) = 0.552\,284\,75$. For other cases, we follow
+% the calculation used by \pkg{pgf} but with the second common case of
+% $60^{\circ}$ pre-calculated for speed.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_path_arc_auxi:nnnnNnn #1#2#3#4#5#6#7
+ {
+ \use:x
+ {
+ \@@_path_arc_auxii:nnnNnnnn
+ {#1} {#2} {#4} #5 {#6} {#7}
+ {
+ \fp_to_dim:n
+ {
+ \cs_if_exist_use:cF
+ { c_@@_path_arc_ #3 _fp }
+ { 4/3 * tand( 0.25 * #3 ) }
+ * #6
+ }
+ }
+ {
+ \fp_to_dim:n
+ {
+ \cs_if_exist_use:cF
+ { c_@@_path_arc_ #3 _fp }
+ { 4/3 * tand( 0.25 * #3 ) }
+ * #7
+ }
+ }
+ }
+ }
+\cs_generate_variant:Nn \@@_path_arc_auxi:nnnnNnn { fnf , ff }
+% \end{macrocode}
+% We can now calculate the required points. As everything here is
+% non-expandable, that is best done by using \texttt{x}-type expansion
+% to build up the tokens. The three points are calculated out-of-order,
+% since finding the second control point needs the position of the end
+% point. Once the points are found, fire-off the fundamental path
+% operation and update the record of where we are up to. The final
+% point has to be
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_path_arc_auxii:nnnNnnnn #1#2#3#4#5#6#7#8
+ {
+ \tl_clear:N \l_@@_path_tmp_tl
+ \@@_point_process:nn
+ { \@@_path_arc_auxiii:nn }
+ {
+ \@@_point_transform_noshift:n
+ { \draw_point_polar:nnn { #1 #4 90 } {#7} {#8} }
+ }
+ \@@_point_process:nn
+ {
+ \@@_point_process:nn
+ { \@@_path_arc_auxiv:nnnn }
+ {
+ \draw_point_transform:n
+ { \draw_point_polar:nnn {#1} {#5} {#6} }
+ }
+ }
+ {
+ \draw_point_transform:n
+ { \draw_point_polar:nnn {#2} {#5} {#6} }
+ }
+ \@@_point_process:nn
+ { \@@_path_arc_auxv:nn }
+ {
+ \@@_point_transform_noshift:n
+ { \draw_point_polar:nnn { #2 #4 -90 } {#7} {#8} }
+ }
+ \exp_after:wN \@@_path_curveto:nnnnnn \l_@@_path_tmp_tl
+ \fp_set:Nn \l_@@_path_arc_delta_fp { abs ( #2 - #3 ) }
+ \fp_set:Nn \l_@@_path_arc_start_fp {#2}
+ }
+% \end{macrocode}
+% The first control point.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_path_arc_auxiii:nn #1#2
+ {
+ \@@_path_arc_aux_add:nn
+ { \g_@@_path_lastx_dim + #1 }
+ { \g_@@_path_lasty_dim + #2 }
+ }
+% \end{macrocode}
+% The end point: simple arithmetic.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_path_arc_auxiv:nnnn #1#2#3#4
+ {
+ \@@_path_arc_aux_add:nn
+ { \g_@@_path_lastx_dim - #1 + #3 }
+ { \g_@@_path_lasty_dim - #2 + #4 }
+ }
+% \end{macrocode}
+% The second control point: extract the last point, do some
+% rearrangement and record.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_path_arc_auxv:nn #1#2
+ {
+ \exp_after:wN \@@_path_arc_auxvi:nn
+ \l_@@_path_tmp_tl {#1} {#2}
+ }
+\cs_new_protected:Npn \@@_path_arc_auxvi:nn #1#2#3#4#5#6
+ {
+ \tl_set:Nn \l_@@_path_tmp_tl { {#1} {#2} }
+ \@@_path_arc_aux_add:nn
+ { #5 + #3 }
+ { #6 + #4 }
+ \tl_put_right:Nn \l_@@_path_tmp_tl { {#3} {#4} }
+ }
+\cs_new_protected:Npn \@@_path_arc_aux_add:nn #1#2
+ {
+ \tl_put_right:Nx \l_@@_path_tmp_tl
+ { { \fp_to_dim:n {#1} } { \fp_to_dim:n {#2} } }
+ }
+\fp_new:N \l_@@_path_arc_delta_fp
+\fp_new:N \l_@@_path_arc_start_fp
+\fp_const:cn { c_@@_path_arc_90_fp } { 4/3 * (sqrt(2) - 1) }
+\fp_const:cn { c_@@_path_arc_60_fp } { 4/3 * tand(15) }
+% \end{macrocode}
+% \end{variable}
+% \end{variable}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\draw_path_arc_axes:nnnn}
+% A simple wrapper.
+% \begin{macrocode}
+\cs_new_protected:Npn \draw_path_arc_axes:nnnn #1#2#3#4
+ {
+ \draw_transform_triangle:nnn { 0cm , 0cm } {#3} {#4}
+ \draw_path_arc:nnn {#1} {#2} { 1pt }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\draw_path_ellipse:nnn}
+% \begin{macro}{\@@_path_ellipse:nnnnnn}
+% \begin{macro}[EXP]
+% {
+% \@@_path_ellipse_arci:nnnnnn ,
+% \@@_path_ellipse_arcii:nnnnnn ,
+% \@@_path_ellipse_arciii:nnnnnn ,
+% \@@_path_ellipse_arciv:nnnnnn
+% }
+% \begin{variable}{\c_@@_path_ellipse_fp}
+% Drawing an ellipse is an optimised version of drawing an arc, in particular
+% reusing the same constant. We need to deal with the ellipse in four parts
+% and also deal with moving to the right place, closing it and ending up
+% back at the center. That is handled on a per-arc basis, each in a
+% separate auxiliary for readability.
+% \begin{macrocode}
+\cs_new_protected:Npn \draw_path_ellipse:nnn #1#2#3
+ {
+ \@@_point_process:nnn
+ {
+ \@@_point_process:nn
+ { \@@_path_ellipse:nnnnnn }
+ { \draw_point_transform:n {#1} }
+ }
+ { \@@_point_transform_noshift:n {#2} }
+ { \@@_point_transform_noshift:n {#3} }
+ }
+\cs_new_protected:Npn \@@_path_ellipse:nnnnnn #1#2#3#4#5#6
+ {
+ \use:x
+ {
+ \@@_path_moveto:nn
+ { \fp_to_dim:n { #1 + #3 } } { \fp_to_dim:n { #2 + #4 } }
+ \@@_path_ellipse_arci:nnnnnn {#1} {#2} {#3} {#4} {#5} {#6}
+ \@@_path_ellipse_arcii:nnnnnn {#1} {#2} {#3} {#4} {#5} {#6}
+ \@@_path_ellipse_arciii:nnnnnn {#1} {#2} {#3} {#4} {#5} {#6}
+ \@@_path_ellipse_arciv:nnnnnn {#1} {#2} {#3} {#4} {#5} {#6}
+ }
+ \@@_softpath_closepath:
+ \@@_path_moveto:nn {#1} {#2}
+ }
+\cs_new:Npn \@@_path_ellipse_arci:nnnnnn #1#2#3#4#5#6
+ {
+ \@@_path_curveto:nnnnnn
+ { \fp_to_dim:n { #1 + #3 + #5 * \c_@@_path_ellipse_fp } }
+ { \fp_to_dim:n { #2 + #4 + #6 * \c_@@_path_ellipse_fp } }
+ { \fp_to_dim:n { #1 + #3 * \c_@@_path_ellipse_fp + #5 } }
+ { \fp_to_dim:n { #2 + #4 * \c_@@_path_ellipse_fp + #6 } }
+ { \fp_to_dim:n { #1 + #5 } }
+ { \fp_to_dim:n { #2 + #6 } }
+ }
+\cs_new:Npn \@@_path_ellipse_arcii:nnnnnn #1#2#3#4#5#6
+ {
+ \@@_path_curveto:nnnnnn
+ { \fp_to_dim:n { #1 - #3 * \c_@@_path_ellipse_fp + #5 } }
+ { \fp_to_dim:n { #2 - #4 * \c_@@_path_ellipse_fp + #6 } }
+ { \fp_to_dim:n { #1 - #3 + #5 * \c_@@_path_ellipse_fp } }
+ { \fp_to_dim:n { #2 - #4 + #6 * \c_@@_path_ellipse_fp } }
+ { \fp_to_dim:n { #1 - #3 } }
+ { \fp_to_dim:n { #2 - #4 } }
+ }
+\cs_new:Npn \@@_path_ellipse_arciii:nnnnnn #1#2#3#4#5#6
+ {
+ \@@_path_curveto:nnnnnn
+ { \fp_to_dim:n { #1 - #3 - #5 * \c_@@_path_ellipse_fp } }
+ { \fp_to_dim:n { #2 - #4 - #6 * \c_@@_path_ellipse_fp } }
+ { \fp_to_dim:n { #1 - #3 * \c_@@_path_ellipse_fp - #5 } }
+ { \fp_to_dim:n { #2 - #4 * \c_@@_path_ellipse_fp - #6 } }
+ { \fp_to_dim:n { #1 - #5 } }
+ { \fp_to_dim:n { #2 - #6 } }
+ }
+\cs_new:Npn \@@_path_ellipse_arciv:nnnnnn #1#2#3#4#5#6
+ {
+ \@@_path_curveto:nnnnnn
+ { \fp_to_dim:n { #1 + #3 * \c_@@_path_ellipse_fp - #5 } }
+ { \fp_to_dim:n { #2 + #4 * \c_@@_path_ellipse_fp - #6 } }
+ { \fp_to_dim:n { #1 + #3 - #5 * \c_@@_path_ellipse_fp } }
+ { \fp_to_dim:n { #2 + #4 - #6 * \c_@@_path_ellipse_fp } }
+ { \fp_to_dim:n { #1 + #3 } }
+ { \fp_to_dim:n { #2 + #4 } }
+ }
+\fp_const:Nn \c_@@_path_ellipse_fp { \fp_use:c { c_@@_path_arc_90_fp } }
+% \end{macrocode}
+% \end{variable}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\draw_path_circle:nn}
+% A shortcut.
+% \begin{macrocode}
+\cs_new_protected:Npn \draw_path_circle:nn #1#2
+ { \draw_path_ellipse:nnn {#1} { #2 , 0pt } { 0pt , #2 } }
+% \end{macrocode}
+% \end{macro}
+%
+% \subsection{Rectangles}
+%
+% \begin{macro}{\draw_path_rectangle:nn}
+% \begin{macro}{\@@_path_rectangle:nnnn, \@@_path_rectangle_rounded:nnnn}
+% Building a rectangle can be a single operation, or for rounded versions will
+% involve step-by-step construction.
+% \begin{macrocode}
+\cs_new_protected:Npn \draw_path_rectangle:nn #1#2
+ {
+ \@@_point_process:nnn
+ {
+ \bool_if:NTF \l_@@_corner_arc_bool
+ { \@@_path_rectangle_rounded:nnnn }
+ { \@@_path_rectangle:nnnn }
+ }
+ { \draw_point_transform:n {#1} }
+ {#2}
+ }
+\cs_new_protected:Npn \@@_path_rectangle:nnnn #1#2#3#4
+ {
+ \@@_path_update_limits:nn {#1} {#2}
+ \@@_path_update_limits:nn { #1 + #3 } { #2 + #4 }
+ \@@_softpath_rectangle:nnnn {#1} {#2} {#3} {#4}
+ \@@_path_update_last:nn {#1} {#2}
+ }
+\cs_new_protected:Npn \@@_path_rectangle_rounded:nnnn #1#2#3#4
+ {
+ \draw_path_moveto:n { #1 + #3 , #2 + #4 }
+ \draw_path_lineto:n { #1 , #2 + #4 }
+ \draw_path_lineto:n { #1 , #2 }
+ \draw_path_lineto:n { #1 + #3 , #2 }
+ \draw_path_close:
+ \draw_path_moveto:n { #1 , #2 }
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\draw_path_rectangle_corners:nn}
+% \begin{macro}{\@@_path_rectangle_corners:nnnn}
+% Another shortcut wrapper.
+% \begin{macrocode}
+\cs_new_protected:Npn \draw_path_rectangle_corners:nn #1#2
+ {
+ \@@_point_process:nnn
+ { \@@_path_rectangle_corners:nnnnn {#1} }
+ {#1} {#2}
+ }
+\cs_new_protected:Npn \@@_path_rectangle_corners:nnnnn #1#2#3#4#5
+ { \draw_path_rectangle:nn {#1} { #4 - #2 , #5 - #3 } }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \subsection{Grids}
+%
+% \begin{macro}{\draw_path_grid:nnnn}
+% \begin{macro}{\@@_path_grid:nnnnnn}
+% A simple set of loops.
+% \begin{macrocode}
+\cs_new_protected:Npn \draw_path_grid:nnnn #1#2#3#4
+ {
+ \@@_point_process:nnn
+ { \@@_path_grid:nnnnnn {#1} {#2} }
+ {#3} {#4}
+ }
+\cs_new_protected:Npn \@@_path_grid:nnnnnn #1#2#3#4#5#6
+ {
+ \dim_step_inline:nnnn
+ {#3} { \dim_compare:nNnF {#3} < {#5} { - } \dim_abs:n {#1} } {#5}
+ {
+ \draw_path_moveto:n { ##1 , #4 }
+ \draw_path_lineto:n { ##1 , #6 }
+ }
+ \dim_step_inline:nnnn
+ {#4} { \dim_compare:nNnF {#4} < {#6} { - } \dim_abs:n {#2} } {#6}
+ {
+ \draw_path_moveto:n { #3 , ##1 }
+ \draw_path_lineto:n { #5 , ##1 }
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \subsection{Using paths}
+%
+% \begin{variable}
+% {
+% \l_@@_path_use_clip_bool ,
+% \l_@@_path_use_fill_bool ,
+% \l_@@_path_use_stroke_bool
+% }
+% Actions to pass to the driver.
+% \begin{macrocode}
+\bool_new:N \l_@@_path_use_clip_bool
+\bool_new:N \l_@@_path_use_fill_bool
+\bool_new:N \l_@@_path_use_stroke_bool
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{variable}{\l_@@_path_use_bb_bool, \l_@@_path_use_clear_bool}
+% Actions handled at the macro layer.
+% \begin{macrocode}
+\bool_new:N \l_@@_path_use_bb_bool
+\bool_new:N \l_@@_path_use_clear_bool
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{macro}{\draw_path_use:n, \draw_path_use_clear:n}
+% \begin{macro}{\@@_path_use:n}
+% \begin{macro}{\@@_path_use_action_draw:}
+% \begin{macro}{\@@_path_use_stroke_bb:}
+% \begin{macro}{\@@_path_use_stroke_bb_aux:NnN}
+% There are a range of actions which can apply to a path: they are handled
+% in a single function which can carry out several of them. The first step
+% is to deal with the special case of clearing the path.
+% \begin{macrocode}
+\cs_new_protected:Npn \draw_path_use:n #1
+ {
+ \tl_if_blank:nF {#1}
+ { \@@_path_use:n {#1} }
+ }
+\cs_new_protected:Npn \draw_path_use_clear:n #1
+ {
+ \bool_lazy_or:nnTF
+ { \tl_if_blank_p:n {#1} }
+ { \str_if_eq_p:nn {#1} { clear } }
+ {
+ \@@_softpath_clear:
+ \@@_path_reset_limits:
+ }
+ { \@@_path_use:n { #1 , clear } }
+ }
+% \end{macrocode}
+% Map over the actions and set up the data: mainly just booleans,
+% but with the possibility to cover more complex cases. The business end
+% of the function is a series of checks on the various flags, then
+% taking the appropriate action(s).
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_path_use:n #1
+ {
+ \bool_set_false:N \l_@@_path_use_clip_bool
+ \bool_set_false:N \l_@@_path_use_fill_bool
+ \bool_set_false:N \l_@@_path_use_stroke_bool
+ \clist_map_inline:nn {#1}
+ {
+ \cs_if_exist:cTF { l_@@_path_use_ ##1 _ bool }
+ { \bool_set_true:c { l_@@_path_use_ ##1 _ bool } }
+ {
+ \cs_if_exist_use:cF { @@_path_use_action_ ##1 : }
+ { \ERROR }
+ }
+ }
+ \bool_lazy_and:nnT
+ { \l_@@_update_bb_bool }
+ { \l_@@_path_use_stroke_bool }
+ { \@@_path_use_stroke_bb: }
+ \bool_if:NTF \l_@@_path_use_clear_bool
+ { \@@_softpath_use_clear: }
+ { \@@_softpath_use: }
+ \bool_if:NT \l_@@_path_use_clip_bool
+ { \driver_draw_clip: }
+ \bool_lazy_or:nnT
+ { \l_@@_path_use_fill_bool }
+ { \l_@@_path_use_stroke_bool }
+ {
+ \use:c
+ {
+ driver_draw_
+ \bool_if:NT \l_@@_path_use_fill_bool { fill }
+ \bool_if:NT \l_@@_path_use_stroke_bool { stroke }
+ :
+ }
+ }
+ }
+\cs_new_protected:Npn \@@_path_use_action_draw:
+ {
+ \bool_set_true:N \l_@@_path_use_stroke_bool
+ }
+% \end{macrocode}
+% Where the path is relevant to size and is stroked, we need to allow for
+% the part which overlaps the edge of the bounding box.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_path_use_stroke_bb:
+ {
+ \@@_path_use_stroke_bb_aux:NnN x { max } +
+ \@@_path_use_stroke_bb_aux:NnN y { max } +
+ \@@_path_use_stroke_bb_aux:NnN x { min } -
+ \@@_path_use_stroke_bb_aux:NnN y { min } -
+ }
+\cs_new_protected:Npn \@@_path_use_stroke_bb_aux:NnN #1#2#3
+ {
+ \dim_compare:nNnF { \dim_use:c { g_@@_ #1#2 _dim } } = { #3 -\c_max_dim }
+ {
+ \dim_gset:cn { g_@@_ #1#2 _dim }
+ {
+ \use:c { dim_ #2 :nn }
+ { \dim_use:c { g_@@_ #1#2 _dim } }
+ {
+ \dim_use:c { g_@@_path_ #1#2 _dim }
+ #3 0.5 \g_@@_linewidth_dim
+ }
+ }
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macrocode}
+%</initex|package>
+% \end{macrocode}
+%
+% \end{implementation}
+%
+% \PrintIndex
diff --git a/Master/texmf-dist/source/latex/l3experimental/l3draw/l3draw-points.dtx b/Master/texmf-dist/source/latex/l3experimental/l3draw/l3draw-points.dtx
new file mode 100644
index 00000000000..01497992889
--- /dev/null
+++ b/Master/texmf-dist/source/latex/l3experimental/l3draw/l3draw-points.dtx
@@ -0,0 +1,960 @@
+% \iffalse meta-comment
+%
+%% File: l3draw-points.dtx Copyright(C) 2018 The LaTeX3 Project
+%
+% It may be distributed and/or modified under the conditions of the
+% LaTeX Project Public License (LPPL), either version 1.3c of this
+% license or (at your option) any later version. The latest version
+% of this license is in the file
+%
+% http://www.latex-project.org/lppl.txt
+%
+% This file is part of the "l3experimental bundle" (The Work in LPPL)
+% and all files in that bundle must be distributed together.
+%
+% -----------------------------------------------------------------------
+%
+% The development version of the bundle can be found at
+%
+% https://github.com/latex3/latex3
+%
+% for those people who are interested.
+%
+%<*driver>
+\RequirePackage{expl3}
+\documentclass[full]{l3doc}
+\begin{document}
+ \DocInput{\jobname.dtx}
+\end{document}
+%</driver>
+% \fi
+%
+% \title{^^A
+% The \pkg{l3draw-points} package\\ Calculating points^^A
+% }
+%
+% \author{^^A
+% The \LaTeX3 Project\thanks
+% {^^A
+% E-mail:
+% \href{mailto:latex-team@latex-project.org}
+% {latex-team@latex-project.org}^^A
+% }^^A
+% }
+%
+% \date{Released 2018/02/21}
+%
+% \maketitle
+%
+% \begin{implementation}
+%
+% \section{\pkg{l3draw-points} implementation}
+%
+% \begin{macrocode}
+%<*initex|package>
+% \end{macrocode}
+%
+% \begin{macrocode}
+%<@@=draw>
+% \end{macrocode}
+%
+% This sub-module covers more-or-less the same ideas as
+% \texttt{pgfcorepoints.code.tex}, though the approach taken to returning
+% values is different: point expressions here are processed by expansion
+% and return a co-ordinate pair in the form |{|\meta{x}|}{|\meta{y}|}|.
+% Equivalents of following \pkg{pgf} functions are deliberately omitted:
+% \begin{itemize}
+% \item \cs{pgfpointorigin}: Can be given explicitly as |{0pt}{0pt}|.
+% \item \cs{pgfextractx}, \cs{pgfextracty}: Available by applying
+% \cs{use_i:nn}/\cs{use_ii:nn} or similar to the \texttt{x}-type
+% expansion of a point expression.
+% \item \cs{pgfgetlastxy}: Unused in the entire \pkg{pgf} core, may be
+% emulated by \texttt{x}-type expansion of a point expression, then using
+% the result.
+% \end{itemize}
+% In addition, equivalents of the following \emph{may} be added in future but
+% are currently absent:
+% \begin{itemize}
+% \item \cs{pgfpointcylindrical}, \cs{pgfpointspherical}: The usefulness
+% of these commands is not currently clear.
+% \item \cs{pgfpointborderrectangle}, \cs{pgfpointborderellipse}: To be
+% revisited once the semantics and use cases are clear.
+% \item \cs{pgfqpoint}, \cs{pgfqpointscale}, \cs{pgfqpointpolar},
+% \cs{pgfqpointxy}, \cs{pgfqpointxyz}: The expandable approach taken in
+% the code here, along with the absolute requirement for \eTeX{}, means
+% it is likely many use cases for these commands may be covered in other
+% ways. This may be revisited as higher-level structures are constructed.
+% \end{itemize}
+%
+% \subsection{Support functions}
+%
+% \begin{macro}[EXP]{\@@_point_process:nn}
+% \begin{macro}[EXP]{\@@_point_process_auxi:nn, \@@_point_process_auxi:fn}
+% \begin{macro}[EXP]{\@@_point_process_auxii:nw}
+% \begin{macro}[EXP]{\@@_point_process:nnn}
+% \begin{macro}[EXP]{\@@_point_process_auxiii:nnn, \@@_point_process_auxiii:ffn}
+% \begin{macro}[EXP]{\@@_point_process_auxiv:nw}
+% Execute whatever code is passed to extract the $x$ and $y$ co-ordinates.
+% The first argument here should itself absorb two arguments. There is
+% also a version to deal with two co-ordinates: common enough to justify a
+% separate function.
+% \begin{macrocode}
+\cs_new:Npn \@@_point_process:nn #1#2
+ {
+ \@@_point_process_auxi:fn
+ { \@@_point_to_dim:n {#2} }
+ {#1}
+ }
+\cs_new:Npn \@@_point_process_auxi:nn #1#2
+ { \@@_point_process_auxii:nw {#2} #1 \q_stop }
+\cs_generate_variant:Nn \@@_point_process_auxi:nn { f }
+\cs_new:Npn \@@_point_process_auxii:nw #1 #2 , #3 \q_stop
+ { #1 {#2} {#3} }
+\cs_new:Npn \@@_point_process:nnn #1#2#3
+ {
+ \@@_point_process_auxiii:ffn
+ { \@@_point_to_dim:n {#2} }
+ { \@@_point_to_dim:n {#3} }
+ {#1}
+ }
+\cs_new:Npn \@@_point_process_auxiii:nnn #1#2#3
+ { \@@_point_process_auxiv:nw {#3} #1 \q_mark #2 \q_stop }
+\cs_generate_variant:Nn \@@_point_process_auxiii:nnn { ff }
+\cs_new:Npn \@@_point_process_auxiv:nw #1 #2 , #3 \q_mark #4 , #5 \q_stop
+ { #1 {#2} {#3} {#4} {#5} }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[EXP]{\@@_point_to_dim:n}
+% \begin{macro}[EXP]{\@@_point_to_dim_aux:n, \@@_point_to_dim_aux:f}
+% \begin{macro}[EXP]{\@@_point_to_dim_aux:w}
+% Co-ordinates are always returned as two dimensions.
+% \begin{macrocode}
+\cs_new:Npn \@@_point_to_dim:n #1
+ { \@@_point_to_dim_aux:f { \fp_eval:n {#1} } }
+\cs_new:Npn \@@_point_to_dim_aux:n #1
+ { \@@_point_to_dim_aux:w #1 }
+\cs_generate_variant:Nn \@@_point_to_dim_aux:n { f }
+\cs_new:Npn \@@_point_to_dim_aux:w ( #1 , ~ #2 ) { #1pt , #2pt }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \subsection{Co-ordinates}
+%
+% The most basic way of giving points is as simple $(x,y)$ co-ordinates.
+%
+% \begin{macro}[EXP]{\draw_point:nn}
+% Simply turn the given values into dimensions.
+% \begin{macrocode}
+\cs_new:Npn \draw_point:nn #1#2
+ { \@@_point_to_dim:n { #1 , #2 } }
+% \end{macrocode}
+% \end{macro}
+%
+% \subsection{Polar co-ordinates}
+%
+% \begin{macro}[EXP]{\draw_point_polar:nn}
+% \begin{macro}[EXP]{\draw_point_polar:nnn}
+% \begin{macro}[EXP]{\@@_draw_polar:nnn, \@@_draw_polar:fnn}
+% Polar co-ordinates may have either one or two lengths, so there is a need
+% to do a simple split before the calculation. As the angle gets used twice,
+% save on any expression evaluation there and force expansion.
+% \begin{macrocode}
+\cs_new:Npn \draw_point_polar:nn #1#2
+ { \draw_point_polar:nnn {#1} {#2} {#2} }
+\cs_new:Npn \draw_point_polar:nnn #1#2#3
+ { \@@_draw_polar:fnn { \fp_eval:n {#1} } {#2} {#3} }
+\cs_new:Npn \@@_draw_polar:nnn #1#2#3
+ { \@@_point_to_dim:n { cosd(#1) * (#2) , sind(#1) * (#3) } }
+\cs_generate_variant:Nn \@@_draw_polar:nnn { f }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \subsection{Point expression arithmetic}
+%
+% These functions all take point expressions as arguments.
+%
+% \begin{macro}[EXP]
+% {\draw_point_add:nn, \draw_point_diff:nn, \draw_point_scale:nn}
+% Simple mathematics.
+% \begin{macrocode}
+\cs_new:Npn \draw_point_add:nn #1#2
+ { \@@_point_to_dim:n { (#1) + (#2) } }
+\cs_new:Npn \draw_point_diff:nn #1#2
+ { \@@_point_to_dim:n { (#2) - (#1) } }
+\cs_new:Npn \draw_point_scale:nn #1#2
+ { \@@_point_to_dim:n { #1 * (#2) } }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[EXP]{\draw_point_unit_vector:n}
+% \begin{macro}[EXP]{\@@_point_unit_vector:nn}
+% Only a single point expression so the expansion is done here. The
+% outcome is the normalised vector from $(0,0)$ in the direction of
+% the point, \emph{i.e.}
+% \[
+% P_{x} = \frac{x}{\sqrt{x^{2} + y^{2}}} \quad
+% P_{y} = \frac{y}{\sqrt{x^{2} + y^{2}}}
+% \]
+% \begin{macrocode}
+\cs_new:Npn \draw_point_unit_vector:n #1
+ { \@@_point_process:nn { \@@_point_unit_vector:nn } {#1} }
+\cs_new:Npn \@@_point_unit_vector:nn #1#2
+ {
+ \@@_point_to_dim:n
+ { ( #1 , #2 ) / (sqrt(#1 * #1 + #2 * #2)) }
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \subsection{Intersection calculations}
+%
+% \begin{macro}[EXP]{\draw_point_intersect_lines:nnnn}
+% \begin{macro}[EXP]{\@@_point_intersect_lines:nnnnnn}
+% \begin{macro}[EXP]{\@@_point_intersect_lines:nnnnnnnn}
+% \begin{macro}[EXP]
+% {\@@_point_intersect_lines_aux:nnnnnn, \@@_point_intersect_lines_aux:ffffff}
+% The intersection point~$P$ between a line joining points $(x_{1}, y_{1})$
+% and $(x_{2}, y_{2})$ with a second line joining points $(x_{3}, y_{3})$
+% and $(x_{4}, y_{4})$ can be calculated using the formulae
+% \[
+% P_{x} =
+% \frac{(x_{1}y_{2} - y_{1}x_{2})(x_{3} - x_{4})
+% - (x_{3}y_{4} - y_{3}x_{4})(x_{1} - x_{2})}
+% {(x_{1} - x_{2})(y_{3} - y_{4}) - (y_{1} - y_{2})(x_{3} - x_{4})}
+% \]
+% and
+% \[
+% P_{y} =
+% \frac{(x_{1}y_{2} - y_{1}x_{2})(y_{3} - y_{5})
+% - (x_{3}y_{4} - y_{3}x_{4})(y_{1} - y_{2})}
+% {(x_{1} - x_{2})(y_{3} - y_{4}) - (y_{1} - y_{2})(x_{3} - x_{4})}
+% \]
+% The work therefore comes down to expanding the incoming data, then
+% pre-calculating as many parts as possible before the final work to find
+% the intersection. (Expansion and argument re-ordering is much less work
+% than additional floating point calculations.)
+% \begin{macrocode}
+\cs_new:Npn \draw_point_intersect_lines:nnnn #1#2#3#4
+ {
+ \@@_point_process:nnn
+ {
+ \@@_point_process:nnn
+ { \@@_point_intersect_lines:nnnnnnnn } {#3} {#4}
+ }
+ {#1} {#2}
+ }
+% \end{macrocode}
+% At this stage we have all of the information we need, fully expanded:
+% \begin{enumerate}[label = \#\arabic*, font = \ttfamily]
+% \item $x_{3}$
+% \item $y_{3}$
+% \item $x_{4}$
+% \item $y_{4}$
+% \item $x_{1}$
+% \item $y_{1}$
+% \item $x_{2}$
+% \item $y_{2}$
+% \end{enumerate}
+% so now just have to do all of the calculation.
+% \begin{macrocode}
+\cs_new:Npn \@@_point_intersect_lines:nnnnnnnn #1#2#3#4#5#6#7#8
+ {
+ \@@_point_intersect_lines_aux:ffffff
+ { \fp_eval:n { #1 * #4 - #2 * #3 } }
+ { \fp_eval:n { #5 * #8 - #6 * #7 } }
+ { \fp_eval:n { #1 - #3 } }
+ { \fp_eval:n { #5 - #7 } }
+ { \fp_eval:n { #2 - #4 } }
+ { \fp_eval:n { #6 - #8 } }
+ }
+\cs_new:Npn \@@_point_intersect_lines_aux:nnnnnn #1#2#3#4#5#6
+ {
+ \@@_point_to_dim:n
+ {
+ ( #2 * #3 - #1 * #4 , #2 * #5 - #1 * #6 )
+ / ( #4 * #5 - #6 * #3 )
+ }
+ }
+\cs_generate_variant:Nn \@@_point_intersect_lines_aux:nnnnnn { ffffff }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[EXP]{\draw_point_intersect_circles:nnnnn}
+% \begin{macro}[EXP]{\@@_point_intersect_circles_auxi:nnnnnnn}
+% \begin{macro}[EXP]
+% {
+% \@@_point_intersect_circles_auxii:nnnnnnn,
+% \@@_point_intersect_circles_auxii:ffnnnnn,
+% \@@_point_intersect_circles_auxiii:nnnnnnn,
+% \@@_point_intersect_circles_auxiii:ffnnnnn
+% }
+% \begin{macro}[EXP]
+% {
+% \@@_point_intersect_circles_auxiv:nnnnnnnn,
+% \@@_point_intersect_circles_auxiv:fnnnnnnn
+% }
+% \begin{macro}[EXP]
+% {
+% \@@_point_intersect_circles_auxv:nnnnnnnnn,
+% \@@_point_intersect_circles_auxv:ffnnnnnnn
+% }
+% \begin{macro}[EXP]
+% {
+% \@@_point_intersect_circles_auxvi:nnnnnnnn,
+% \@@_point_intersect_circles_auxvi:fnnnnnnn
+% }
+% \begin{macro}[EXP]
+% {
+% \@@_point_intersect_circles_auxvii:nnnnnnn,
+% \@@_point_intersect_circles_auxvii:fffnnnn
+% }
+% Another long expansion chain to get the values in the right places.
+% We have two circles, the first with center $(a, b)$ and radius~$r$,
+% the second with center $(c, d)$ and radius~$s$. We use the intermediate
+% values
+% \begin{align*}
+% e &= c - a \\
+% f &= d - b \\
+% p &= \sqrt{e^{2} + f^{2}} \\
+% k &= \frac{p^{2} + r^{2} - s^{2}}{2p}
+% \end{align*}
+% in either
+% \begin{align*}
+% P_{x} &= a + \frac{ek}{p} + \frac{f}{p}\sqrt{r^{2} - k^{2}} \\
+% P_{y} &= b + \frac{fk}{p} - \frac{e}{p}\sqrt{r^{2} - k^{2}}
+% \end{align*}
+% or
+% \begin{align*}
+% P_{x} &= a + \frac{ek}{p} - \frac{f}{p}\sqrt{r^{2} - k^{2}} \\
+% P_{y} &= b + \frac{fk}{p} + \frac{e}{p}\sqrt{r^{2} - k^{2}}
+% \end{align*}
+% depending on which solution is required. The rest of the work is simply
+% forcing the appropriate expansion and shuffling arguments.
+% \begin{macrocode}
+\cs_new:Npn \draw_point_intersect_circles:nnnnn #1#2#3#4#5
+ {
+ \@@_point_process:nnn
+ { \@@_point_intersect_circles_auxi:nnnnnnn {#2} {#4} {#5} }
+ {#1} {#3}
+ }
+\cs_new:Npn \@@_point_intersect_circles_auxi:nnnnnnn #1#2#3#4#5#6#7
+ {
+ \@@_point_intersect_circles_auxii:ffnnnnn
+ { \fp_eval:n {#1} } { \fp_eval:n {#2} } {#4} {#5} {#6} {#7} {#3}
+ }
+% \end{macrocode}
+% At this stage we have all of the information we need, fully expanded:
+% \begin{enumerate}[label = \#\arabic*, font = \ttfamily]
+% \item $r$
+% \item $s$
+% \item $a$
+% \item $b$
+% \item $c$
+% \item $d$
+% \item $n$
+% \end{enumerate}
+% Once we evaluate $e$ and $f$, the co-ordinate $(c,d)$ is no longer
+% required: handy as we will need various intermediate values in the
+% following.
+% \begin{macrocode}
+\cs_new:Npn \@@_point_intersect_circles_auxii:nnnnnnn #1#2#3#4#5#6#7
+ {
+ \@@_point_intersect_circles_auxiii:ffnnnnn
+ { \fp_eval:n { #5 - #3 } }
+ { \fp_eval:n { #6 - #4 } }
+ {#1} {#2} {#3} {#4} {#7}
+ }
+\cs_generate_variant:Nn \@@_point_intersect_circles_auxii:nnnnnnn { ff }
+\cs_new:Npn \@@_point_intersect_circles_auxiii:nnnnnnn #1#2#3#4#5#6#7
+ {
+ \@@_point_intersect_circles_auxiv:fnnnnnnn
+ { \fp_eval:n { sqrt( #1 * #1 + #2 * #2 ) } }
+ {#1} {#2} {#3} {#4} {#5} {#6} {#7}
+ }
+\cs_generate_variant:Nn \@@_point_intersect_circles_auxiii:nnnnnnn { ff }
+% \end{macrocode}
+% We now have $p$: we pre-calculate $1/p$ as it is needed a few times and
+% is relatively expensive. We also need $r^{2}$ twice so deal with that
+% here too.
+% \begin{macrocode}
+\cs_new:Npn \@@_point_intersect_circles_auxiv:nnnnnnnn #1#2#3#4#5#6#7#8
+ {
+ \@@_point_intersect_circles_auxv:ffnnnnnnn
+ { \fp_eval:n { 1 / #1 } }
+ { \fp_eval:n { #4 * #4 } }
+ {#1} {#2} {#3} {#5} {#6} {#7} {#8}
+ }
+\cs_generate_variant:Nn \@@_point_intersect_circles_auxiv:nnnnnnnn { f }
+\cs_new:Npn \@@_point_intersect_circles_auxv:nnnnnnnnn #1#2#3#4#5#6#7#8#9
+ {
+ \@@_point_intersect_circles_auxvi:fnnnnnnn
+ { \fp_eval:n { 0.5 * #1 * ( #2 + #3 * #3 - #6 * #6 ) } }
+ {#1} {#2} {#4} {#5} {#7} {#8} {#9}
+ }
+\cs_generate_variant:Nn \@@_point_intersect_circles_auxv:nnnnnnnnn { ff }
+% \end{macrocode}
+% We now have all of the intermediate values we require, with one division
+% carried out up-front to avoid doing this expensive step twice:
+% \begin{enumerate}[label = \#\arabic*, font = \ttfamily]
+% \item $k$
+% \item $1/p$
+% \item $r^{2}$
+% \item $e$
+% \item $f$
+% \item $a$
+% \item $b$
+% \item $n$
+% \end{enumerate}
+% There are some final pre-calculations, $k/p$,
+% $\frac{\sqrt{r^{2} - k^{2}}}{p}$ and the usage of $n$, then we
+% can yield a result.
+% \begin{macrocode}
+\cs_new:Npn \@@_point_intersect_circles_auxvi:nnnnnnnn #1#2#3#4#5#6#7#8
+ {
+ \@@_point_intersect_circles_auxvii:fffnnnn
+ { \fp_eval:n { #1 * #2 } }
+ { \int_if_odd:nTF {#8} { 1 } { -1 } }
+ { \fp_eval:n { sqrt ( #3 - #1 * #1 ) * #2 } }
+ {#4} {#5} {#6} {#7}
+ }
+\cs_generate_variant:Nn \@@_point_intersect_circles_auxvi:nnnnnnnn { f }
+\cs_new:Npn \@@_point_intersect_circles_auxvii:nnnnnnn #1#2#3#4#5#6#7
+ {
+ \@@_point_to_dim:n
+ { #6 + #4 * #1 + #2 * #3 * #5 , #7 + #5 * #1 + -1 * #2 * #3 * #4 }
+ }
+\cs_generate_variant:Nn \@@_point_intersect_circles_auxvii:nnnnnnn { fff }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \subsection{Interpolation on a line (vector) or arc}
+%
+% \begin{macro}[EXP]{\draw_point_interpolate_line:nnn}
+% \begin{macro}[EXP]
+% {
+% \@@_point_interpolate_line_aux:nnnnn,
+% \@@_point_interpolate_line_aux:fnnnn,
+% }
+% \begin{macro}[EXP]
+% {
+% \@@_point_interpolate_line_aux:nnnnnn,
+% \@@_point_interpolate_line_aux:fnnnnn,
+% }
+% Simple maths after expansion.
+% \begin{macrocode}
+\cs_new:Npn \draw_point_interpolate_line:nnn #1#2#3
+ {
+ \@@_point_process:nnn
+ { \@@_point_interpolate_line_aux:fnnnn { \fp_eval:n {#1} } }
+ {#2} {#3}
+ }
+\cs_new:Npn \@@_point_interpolate_line_aux:nnnnn #1#2#3#4#5
+ {
+ \@@_point_interpolate_line_aux:fnnnnn { \fp_eval:n { 1 - #1 } }
+ {#1} {#2} {#3} {#4} {#5}
+ }
+\cs_generate_variant:Nn \@@_point_interpolate_line_aux:nnnnn { f }
+\cs_new:Npn \@@_point_interpolate_line_aux:nnnnnn #1#2#3#4#5#6
+ { \@@_point_to_dim:n { #2 * #3 + #1 * #5 , #2 * #4 + #1 * #6 } }
+\cs_generate_variant:Nn \@@_point_interpolate_line_aux:nnnnnn { f }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[EXP]{\draw_point_interpolate_distance:nnn}
+% \begin{macro}[EXP]{\@@_point_interpolate_distance:nnnnn}
+% \begin{macro}[EXP]
+% {
+% \@@_point_interpolate_distance_aux:nnnnnnn,
+% \@@_point_interpolate_distance_aux:nnnnnnn,
+% }
+% \begin{macro}[EXP]
+% {
+% \@@_point_interpolate_distance_aux:nnnnnn,
+% \@@_point_interpolate_distance_aux:fnnnnn,
+% }
+% Same idea but using the normalised length to obtain the scale factor.
+% \begin{macrocode}
+\cs_new:Npn \draw_point_interpolate_distance:nnn #1#2#3
+ {
+ \@@_point_process:nnn
+ { \@@_point_interpolate_distance:nnnnn {#1} }
+ {#2} {#3}
+ }
+\cs_new:Npn \@@_point_interpolate_distance:nnnnn #1#2#3#4#5
+ {
+ \@@_point_interpolate_distance_aux:nnnnnnn
+ { \fp_eval:n { #4 - #2 } }
+ { \fp_eval:n { #5 - #3 } }
+ {#2} {#3} {#4} {#5} {#1}
+ }
+\cs_new:Npn \@@_point_interpolate_distance_aux:nnnnnnn #1#2#3#4#5#6#7
+ {
+ \@@_point_interpolate_distance_aux:fnnnn
+ { \fp_eval:n { (#7) / (sqrt ( #1 * #1 + #2 * #2 )) } }
+ {#3} {#4} {#5} {#6}
+ }
+\cs_generate_variant:Nn \@@_point_interpolate_distance_aux:nnnnnnn { ff }
+\cs_new:Npn \@@_point_interpolate_distance_aux:nnnnn #1#2#3#4#5
+ { \@@_point_to_dim:n { #2 + #1 * #4 , #3 + #1 * #5 } }
+\cs_generate_variant:Nn \@@_point_interpolate_distance_aux:nnnnn { f }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[EXP]{\draw_point_interpolate_arcaxes:nnnnnn}
+% \begin{macro}[EXP]{\@@_point_interpolate_arcaxes_auxi:nnnnnnnnn}
+% \begin{macro}[EXP]
+% {
+% \@@_point_interpolate_arcaxes_auxii:nnnnnnnnn,
+% \@@_point_interpolate_arcaxes_auxii:fnnnnnnnn
+% }
+% \begin{macro}[EXP]
+% {
+% \@@_point_interpolate_arcaxes_auxiii:nnnnnnn,
+% \@@_point_interpolate_arcaxes_auxiii:fnnnnnn
+% }
+% \begin{macro}[EXP]
+% {
+% \@@_point_interpolate_arcaxes_auxiv:nnnnnnnn,
+% \@@_point_interpolate_arcaxes_auxiv:ffnnnnnn
+% }
+% Finding a point on an ellipse arc is relatively easy: find the correct
+% angle between the two given, use the sine and cosine of that angle,
+% apply to the axes. We just have to work a bit with the co-ordinate
+% expansion.
+% \begin{macrocode}
+\cs_new:Npn \draw_point_interpolate_arcaxes:nnnnnn #1#2#3#4#5#6
+ {
+ \@@_point_process:nnn
+ {
+ \@@_point_process:nn
+ { \@@_point_interpolate_arcaxes_auxi:nnnnnnnnn {#1} {#5} {#6} }
+ {#4}
+ }
+ {#2} {#3}
+ }
+\cs_new:Npn \@@_point_interpolate_arcaxes_auxi:nnnnnnnnn #1#2#3#4#5#6#7#8#9
+ {
+ \@@_point_interpolate_arcaxes_auxii:fnnnnnnnn
+ { \fp_eval:n {#1} } {#2} {#3} {#6} {#7} {#8} {#9} {#4} {#5}
+ }
+% \end{macrocode}
+% At this stage, the three co-ordinate pairs are fully expanded but somewhat
+% re-ordered:
+% \begin{enumerate}[label = \#\arabic*, font = \ttfamily]
+% \item $p$
+% \item $\theta_{1}$
+% \item $\theta_{2}$
+% \item $x_{c}$
+% \item $y_{c}$
+% \item $x_{a1}$
+% \item $y_{a1}$
+% \item $x_{a2}$
+% \item $y_{a2}$
+% \end{enumerate}
+% We are now in a position to find the target angle, and from that
+% the sine and cosine required.
+% \begin{macrocode}
+\cs_new:Npn \@@_point_interpolate_arcaxes_auxii:nnnnnnnnn #1#2#3#4#5#6#7#8#9
+ {
+ \@@_point_interpolate_arcaxes_auxiii:fnnnnnn
+ { \fp_eval:n { #1 * (#3) + ( 1 - #1 ) * (#2) } }
+ {#4} {#5} {#6} {#7} {#8} {#9}
+ }
+\cs_generate_variant:Nn \@@_point_interpolate_arcaxes_auxii:nnnnnnnnn { f }
+\cs_new:Npn \@@_point_interpolate_arcaxes_auxiii:nnnnnnn #1#2#3#4#5#6#7
+ {
+ \@@_point_interpolate_arcaxes_auxiv:ffnnnnnn
+ { \fp_eval:n { cosd (#1) } }
+ { \fp_eval:n { sind (#1) } }
+ {#2} {#3} {#4} {#5} {#6} {#7}
+ }
+\cs_generate_variant:Nn \@@_point_interpolate_arcaxes_auxiii:nnnnnnn { f }
+\cs_new:Npn \@@_point_interpolate_arcaxes_auxiv:nnnnnnnn #1#2#3#4#5#6#7#8
+ {
+ \@@_point_to_dim:n
+ { #3 + #1 * #5 + #2 * #7 , #4 + #1 * #6 + #2 * #8 }
+ }
+\cs_generate_variant:Nn \@@_point_interpolate_arcaxes_auxiv:nnnnnnnn { ff }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[EXP]{\draw_point_interpolate_curve:nnnnn}
+% \begin{macro}[EXP]{\draw_point_interpolate_curve_auxi:nnnnnnnnn}
+% \begin{macro}[EXP]
+% {
+% \draw_point_interpolate_curve_auxii:nnnnnnnnn,
+% \draw_point_interpolate_curve_auxii:fnnnnnnnn,
+% }
+% \begin{macro}[EXP]
+% {
+% \draw_point_interpolate_curve_auxiii:nnnnnn,
+% \draw_point_interpolate_curve_auxiii:fnnnnn,
+% }
+% \begin{macro}[EXP]{\draw_point_interpolate_curve_auxiv:nnnnnn}
+% \begin{macro}[EXP]
+% {
+% \draw_point_interpolate_curve_auxv:nnw,
+% \draw_point_interpolate_curve_auxv:ffw,
+% }
+% \begin{macro}[EXP]{\draw_point_interpolate_curve_auxvi:n}
+% \begin{macro}[EXP]{\draw_point_interpolate_curve_auxvii:nnnnnnnn}
+% \begin{macro}[EXP]
+% {
+% \draw_point_interpolate_curve_auxviii:nnnnnn,
+% \draw_point_interpolate_curve_auxviii:ffnnnn,
+% }
+% Here we start with a proportion of the curve ($p$) and four points
+% \begin{enumerate}
+% \item The initial point $(x_{1},y_{1})$
+% \item The first control point $(x_{2},y_{2})$
+% \item The second control point $(x_{3},y_{3})$
+% \item The final point $(x_{4},y_{4})$
+% \end{enumerate}
+% The first phase is to expand out all of these values.
+% \begin{macrocode}
+\cs_new:Npn \draw_point_interpolate_curve:nnnnnn #1#2#3#4#5
+ {
+ \@@_point_process:nnn
+ {
+ \@@_point_process:nnn
+ { \@@_point_interpolate_curve_auxi:nnnnnnnnn {#1} }
+ {#4} {#5}
+ }
+ {#2} {#3}
+ }
+\cs_new:Npn \@@_point_interpolate_curve_auxi:nnnnnnnnn #1#2#3#4#5#6#7#8#9
+ {
+ \@@_point_interpolate_curve_auxii:fnnnnnnnn
+ { \fp_eval:n {#1} }
+ {#6} {#7} {#8} {#9} {#2} {#3} {#4} {#5}
+ }
+% \end{macrocode}
+% At this stage, everything is fully expanded and back in the input order.
+% The approach to finding the required point is iterative. We carry out
+% three phases. In phase one, we need all of the input co-ordinates
+% \begin{align*}
+% x_{1}' &= (1 - p)x_{1} + px_{2} \\
+% y_{1}' &= (1 - p)y_{1} + py_{2} \\
+% x_{2}' &= (1 - p)x_{2} + px_{3} \\
+% y_{2}' &= (1 - p)y_{2} + py_{3} \\
+% x_{3}' &= (1 - p)x_{3} + px_{4} \\
+% y_{3}' &= (1 - p)y_{3} + py_{4}
+% \end{align*}
+% In the second stage, we can drop the final point
+% \begin{align*}
+% x_{1}'' &= (1 - p)x_{1}' + px_{2}' \\
+% y_{1}'' &= (1 - p)y_{1}' + py_{2}' \\
+% x_{2}'' &= (1 - p)x_{2}' + px_{3}' \\
+% y_{2}'' &= (1 - p)y_{2}' + py_{3}'
+% \end{align*}
+% and for the final stage only need one set of calculations
+% \begin{align*}
+% P_{x} &= (1 - p)x_{1}'' + px_{2}'' \\
+% P_{y} &= (1 - p)y_{1}'' + py_{2}''
+% \end{align*}
+% Of course, this does mean a lot of calculations and expansion!
+% \begin{macrocode}
+\cs_new:Npn \@@_point_interpolate_curve_auxii:nnnnnnnnn
+ #1#2#3#4#5#6#7#8#9
+ {
+ \@@_point_interpolate_curve_auxiii:fnnnnn
+ { \fp_eval:n { 1 - #1 } }
+ {#1}
+ { {#2} {#3} } { {#4} {#5} } { {#6} {#7} } { {#8} {#9} }
+ }
+\cs_generate_variant:Nn \@@_point_interpolate_curve_auxii:nnnnnnnnn { f }
+% \begin{macrocode}
+% We need to do the first cycle, but haven't got enough arguments to keep
+% everything in play at once. So her ewe use a but of argument re-ordering
+% and a single auxiliary to get the job done.
+% \begin{macrocode}
+\cs_new:Npn \@@_point_interpolate_curve_auxiii:nnnnnn #1#2#3#4#5#6
+ {
+ \@@_point_interpolate_curve_auxiv:nnnnnn {#1} {#2} #3 #4
+ \@@_point_interpolate_curve_auxiv:nnnnnn {#1} {#2} #4 #5
+ \@@_point_interpolate_curve_auxiv:nnnnnn {#1} {#2} #5 #6
+ \prg_do_nothing:
+ \@@_point_interpolate_curve_auxvi:n { {#1} {#2} }
+ }
+\cs_generate_variant:Nn \@@_point_interpolate_curve_auxiii:nnnnnn { f }
+\cs_new:Npn \@@_point_interpolate_curve_auxiv:nnnnnn #1#2#3#4#5#6
+ {
+ \@@_point_interpolate_curve_auxv:ffw
+ { \fp_eval:n { #1 * #3 + #2 * #5 } }
+ { \fp_eval:n { #1 * #4 + #2 * #6 } }
+ }
+\cs_new:Npn \@@_point_interpolate_curve_auxv:nnw
+ #1#2#3 \prg_do_nothing: #4#5
+ {
+ #3
+ \prg_do_nothing:
+ #4 { #5 {#1} {#2} }
+ }
+\cs_generate_variant:Nn \@@_point_interpolate_curve_auxv:nnw { ff }
+% \begin{macrocode}
+% Get the arguments back into the right places and to the second and
+% third cycles directly.
+% \begin{macrocode}
+\cs_new:Npn \@@_point_interpolate_curve_auxvi:n #1
+ { \@@_point_interpolate_curve_auxvii:nnnnnnnn #1 }
+\cs_new:Npn \@@_point_interpolate_curve_auxvii:nnnnnnnn #1#2#3#4#5#6#7#8
+ {
+ \@@_point_interpolate_curve_auxviii:ffffnn
+ { \fp_eval:n { #1 * #5 + #2 * #3 } }
+ { \fp_eval:n { #1 * #6 + #2 * #4 } }
+ { \fp_eval:n { #1 * #7 + #2 * #5 } }
+ { \fp_eval:n { #1 * #8 + #2 * #6 } }
+ {#1} {#2}
+ }
+\cs_new:Npn \@@_point_interpolate_curve_auxviii:nnnnnn #1#2#3#4#5#6
+ {
+ \@@_point_to_dim:n
+ { #5 * #3 + #6 * #1 , #5 * #4 + #6 * #2 }
+ }
+\cs_generate_variant:Nn \@@_point_interpolate_curve_auxviii:nnnnnn { ffff }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \subsection{Vector support}
+%
+% As well as co-ordinates relative to the drawing
+%
+% \begin{variable}
+% {
+% \l_@@_xvec_x_dim,
+% \l_@@_xvec_y_dim,
+% \l_@@_yvec_x_dim,
+% \l_@@_yvec_y_dim,
+% \l_@@_zvec_x_dim,
+% \l_@@_zvec_y_dim
+% }
+% Base vectors to map to the underlying two-dimensional drawing space.
+% \begin{macrocode}
+\dim_new:N \l_@@_xvec_x_dim
+\dim_new:N \l_@@_xvec_y_dim
+\dim_new:N \l_@@_yvec_x_dim
+\dim_new:N \l_@@_yvec_y_dim
+\dim_new:N \l_@@_zvec_x_dim
+\dim_new:N \l_@@_zvec_y_dim
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{macro}{\draw_xvec:n, \draw_yvec:n, \draw_zvec:n}
+% \begin{macro}{\@@_vec:nn}
+% \begin{macro}{\@@_vec:nnn}
+% Calculate the underlying position and store it.
+% \begin{macrocode}
+\cs_new_protected:Npn \draw_xvec:n #1
+ { \@@_vec:nn { x } {#1} }
+\cs_new_protected:Npn \draw_yvec:n #1
+ { \@@_vec:nn { y } {#1} }
+\cs_new_protected:Npn \draw_zvec:n #1
+ { \@@_vec:nn { z } {#1} }
+\cs_new_protected:Npn \@@_vec:nn #1#2
+ {
+ \@@_point_process:nn { \@@_vec:nnn {#1} } {#2}
+ }
+\cs_new_protected:Npn \@@_vec:nnn #1#2#3
+ {
+ \dim_set:cn { l_@@_ #1 vec_x_dim } {#2}
+ \dim_set:cn { l_@@_ #1 vec_y_dim } {#3}
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% Initialise the vectors.
+% \begin{macrocode}
+\draw_xvec:n { 1cm , 0cm }
+\draw_yvec:n { 0cm , 1cm }
+\draw_zvec:n { -0.385cm , -0.385cm }
+% \end{macrocode}
+%
+% \begin{macro}[EXP]{\draw_point_vec:nn}
+% \begin{macro}[EXP]{\@@_point_vec:nn, \@@_point_vec:ff}
+% \begin{macro}[EXP]{\draw_point_vec:nnn}
+% \begin{macro}[EXP]{\@@_point_vec:nnn, \@@_point_vec:fff}
+% Force a single evaluation of each factor, then use these to work out the
+% underlying point.
+% \begin{macrocode}
+\cs_new:Npn \draw_point_vec:nn #1#2
+ { \@@_point_vec:ff { \fp_eval:n {#1} } { \fp_eval:n {#2} } }
+\cs_new:Npn \@@_point_vec:nn #1#2
+ {
+ \@@_point_to_dim:n
+ {
+ #1 * \l_@@_xvec_x_dim + #2 * \l_@@_yvec_x_dim ,
+ #1 * \l_@@_xvec_y_dim + #2 * \l_@@_yvec_y_dim
+ }
+ }
+\cs_generate_variant:Nn \@@_point_vec:nn { ff }
+\cs_new:Npn \draw_point_vec:nnn #1#2#3
+ {
+ \@@_point_vec:fff
+ { \fp_eval:n {#1} } { \fp_eval:n {#2} } { \fp_eval:n {#3} }
+ }
+\cs_new:Npn \@@_point_vec:nnn #1#2#3
+ {
+ \@@_point_to_dim:n
+ {
+ #1 * \l_@@_xvec_x_dim
+ + #2 * \l_@@_yvec_x_dim
+ + #3 * \l_@@_zvec_x_dim
+ ,
+ #1 * \l_@@_xvec_y_dim
+ + #2 * \l_@@_yvec_y_dim
+ + #3 * \l_@@_zvec_y_dim
+ }
+ }
+\cs_generate_variant:Nn \@@_point_vec:nnn { fff }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[EXP]{\draw_point_vec_polar:nn}
+% \begin{macro}[EXP]{\draw_point_vec_polar:nnn}
+% \begin{macro}[EXP]{\@@_point_vec_polar:nnn, \@@_point_vec_polar:fnn}
+% Much the same as the core polar approach.
+% \begin{macrocode}
+\cs_new:Npn \draw_point_vec_polar:nn #1#2
+ { \draw_point_vec_polar:nnn {#1} {#2} {#2} }
+\cs_new:Npn \draw_point_vec_polar:nnn #1#2#3
+ { \@@_draw_vec_polar:fnn { \fp_eval:n {#1} } {#2} {#3} }
+\cs_new:Npn \@@_draw_vec_polar:nnn #1#2#3
+ {
+ \@@_point_to_dim:n
+ {
+ cosd(#1) * (#2) * \l_@@_xvec_x_dim ,
+ sind(#1) * (#3) * \l_@@_yvec_y_dim
+ }
+ }
+\cs_generate_variant:Nn \@@_draw_vec_polar:nnn { f }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \subsection{Transformations}
+%
+% \begin{macro}[EXP]{\draw_point_transform:n}
+% \begin{macro}[EXP]{\@@_point_transform:nn}
+% Applies a transformation matrix to a point: see \texttt{l3draw-transforms}
+% for the business end. Where possible, we avoid the relatively expensive
+% multiplication step.
+% \begin{macrocode}
+\cs_new:Npn \draw_point_transform:n #1
+ {
+ \@@_point_process:nn
+ { \@@_point_transform:nn } {#1}
+ }
+\cs_new:Npn \@@_point_transform:nn #1#2
+ {
+ \bool_if:NTF \l_@@_transformcm_active_bool
+ {
+ \@@_point_to_dim:n
+ {
+ (
+ \l_@@_transformcm_aa_fp * #1
+ + \l_@@_transformcm_ba_fp * #2
+ + \l_@@_transformcm_xshift_dim
+ )
+ ,
+ (
+ \l_@@_transformcm_ab_fp * #1
+ + \l_@@_transformcm_bb_fp * #2
+ + \l_@@_transformcm_yshift_dim
+ )
+ }
+ }
+ {
+ \@@_point_to_dim:n
+ {
+ (#1, #2)
+ + ( \l_@@_transformcm_xshift_dim ,
+ \l_@@_transformcm_yshift_dim )
+ }
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[EXP]{\@@_point_transform_noshift:n}
+% \begin{macro}[EXP]{\@@_point_transform_noshift:nn}
+% A version with no shift: used for internal purposes.
+% \begin{macrocode}
+\cs_new:Npn \@@_point_transform_noshift:n #1
+ {
+ \@@_point_process:nn
+ { \@@_point_transform_noshift:nn } {#1}
+ }
+\cs_new:Npn \@@_point_transform_noshift:nn #1#2
+ {
+ \bool_if:NTF \l_@@_transformcm_active_bool
+ {
+ \@@_point_to_dim:n
+ {
+ (
+ \l_@@_transformcm_aa_fp * #1
+ + \l_@@_transformcm_ba_fp * #2
+ )
+ ,
+ (
+ \l_@@_transformcm_ab_fp * #1
+ + \l_@@_transformcm_bb_fp * #2
+ )
+ }
+ }
+ { \@@_point_to_dim:n { (#1, #2) } }
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macrocode}
+%</initex|package>
+% \end{macrocode}
+%
+% \end{implementation}
+%
+% \PrintIndex
diff --git a/Master/texmf-dist/source/latex/l3experimental/l3draw/l3draw-scopes.dtx b/Master/texmf-dist/source/latex/l3experimental/l3draw/l3draw-scopes.dtx
new file mode 100644
index 00000000000..b87a6a152b7
--- /dev/null
+++ b/Master/texmf-dist/source/latex/l3experimental/l3draw/l3draw-scopes.dtx
@@ -0,0 +1,141 @@
+% \iffalse meta-comment
+%
+%% File: l3draw-scopes.dtx Copyright(C) 2018 The LaTeX3 Project
+%
+% It may be distributed and/or modified under the conditions of the
+% LaTeX Project Public License (LPPL), either version 1.3c of this
+% license or (at your option) any later version. The latest version
+% of this license is in the file
+%
+% http://www.latex-project.org/lppl.txt
+%
+% This file is part of the "l3experimental bundle" (The Work in LPPL)
+% and all files in that bundle must be distributed together.
+%
+% -----------------------------------------------------------------------
+%
+% The development version of the bundle can be found at
+%
+% https://github.com/latex3/latex3
+%
+% for those people who are interested.
+%
+%<*driver>
+\RequirePackage{expl3}
+\documentclass[full]{l3doc}
+\begin{document}
+ \DocInput{\jobname.dtx}
+\end{document}
+%</driver>
+% \fi
+%
+% \title{^^A
+% The \pkg{l3draw} package\\ Drawing scopes^^A
+% }
+%
+% \author{^^A
+% The \LaTeX3 Project\thanks
+% {^^A
+% E-mail:
+% \href{mailto:latex-team@latex-project.org}
+% {latex-team@latex-project.org}^^A
+% }^^A
+% }
+%
+% \date{Released 2018/02/21}
+%
+% \maketitle
+%
+% \begin{implementation}
+%
+% \section{\pkg{l3draw-scopes} implementation}
+%
+% \begin{macrocode}
+%<*initex|package>
+% \end{macrocode}
+%
+% \begin{macrocode}
+%<@@=draw>
+% \end{macrocode}
+%
+% \subsection{Drawing environment}
+%
+% \begin{variable}
+% {\g_@@_xmax_dim, \g_@@_xmin_dim, \g_@@_ymax_dim, \g_@@_ymin_dim}
+% Used to track the overall (official) size of the image created: may
+% not actually be the natural size of the content.
+% \begin{macrocode}
+\dim_new:N \g_@@_xmax_dim
+\dim_new:N \g_@@_xmin_dim
+\dim_new:N \g_@@_ymax_dim
+\dim_new:N \g_@@_ymin_dim
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{variable}{\l_@@_update_bb_bool}
+% Flag to indicate that a path (or similar) should update the bounding box
+% of the drawing.
+% \begin{macrocode}
+\bool_new:N \l_@@_update_bb_bool
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{variable}{\l_@@_main_box}
+% Box for setting the drawing.
+% \begin{macrocode}
+\box_new:N \l_@@_main_box
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{macro}{\draw_begin:, \draw_end:}
+% Drawings are created by setting them into a box, then adjusting the box
+% before inserting into the surroundings. At present the content is simply
+% collected then dumped: work will be required to manipulate the size as
+% this data becomes more defined. It may be that a coffin construct is
+% better here in the longer term: that may become clearer as the code is
+% completed. Another obvious question is whether/where vertical mode should
+% be ended (\emph{i.e.}~should this behave like a raw |\vbox| or like
+% a coffin). In contrast to \pkg{pgf}, we use a vertical box here: material
+% between explicit instructions should not be present anyway. (Consider
+% adding an |\everypar| hook as done for the \LaTeXe{} preamble.)
+% \begin{macrocode}
+\cs_new_protected:Npn \draw_begin:
+ {
+ \vbox_set:Nw \l_@@_main_box
+ \driver_draw_begin:
+ \dim_gset:Nn \g_@@_xmax_dim { -\c_max_dim }
+ \dim_gset:Nn \g_@@_xmin_dim { \c_max_dim }
+ \dim_gset:Nn \g_@@_ymax_dim { -\c_max_dim }
+ \dim_gset:Nn \g_@@_ymin_dim { \c_max_dim }
+ \bool_set_true:N \l_@@_update_bb_bool
+ \draw_transform_reset:
+ \draw_linewidth:n { \l_draw_default_linewidth_dim }
+ }
+\cs_new_protected:Npn \draw_end:
+ {
+ \driver_draw_end:
+ \vbox_set_end:
+ \hbox_set:Nn \l_@@_main_box
+ {
+ \skip_horizontal:n { -\g_@@_xmin_dim }
+ \box_move_down:nn { \g_@@_ymin_dim }
+ { \box_use_drop:N \l_@@_main_box }
+ }
+ \box_set_ht:Nn \l_@@_main_box
+ { \g_@@_ymax_dim - \g_@@_ymin_dim }
+ \box_set_dp:Nn \l_@@_main_box { 0pt }
+ \box_set_wd:Nn \l_@@_main_box
+ { \g_@@_xmax_dim - \g_@@_xmin_dim }
+ \mode_leave_vertical:
+ \box_use_drop:N \l_@@_main_box
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macrocode}
+%</initex|package>
+% \end{macrocode}
+%
+% \end{implementation}
+%
+% \PrintIndex
diff --git a/Master/texmf-dist/source/latex/l3experimental/l3draw/l3draw-softpath.dtx b/Master/texmf-dist/source/latex/l3experimental/l3draw/l3draw-softpath.dtx
new file mode 100644
index 00000000000..f10d7928082
--- /dev/null
+++ b/Master/texmf-dist/source/latex/l3experimental/l3draw/l3draw-softpath.dtx
@@ -0,0 +1,323 @@
+% \iffalse meta-comment
+%
+%% File: l3draw-softpath.dtx Copyright(C) 2018 The LaTeX3 Project
+%
+% It may be distributed and/or modified under the conditions of the
+% LaTeX Project Public License (LPPL), either version 1.3c of this
+% license or (at your option) any later version. The latest version
+% of this license is in the file
+%
+% http://www.latex-project.org/lppl.txt
+%
+% This file is part of the "l3experimental bundle" (The Work in LPPL)
+% and all files in that bundle must be distributed together.
+%
+% -----------------------------------------------------------------------
+%
+% The development version of the bundle can be found at
+%
+% https://github.com/latex3/latex3
+%
+% for those people who are interested.
+%
+%<*driver>
+\RequirePackage{expl3}
+\documentclass[full]{l3doc}
+\begin{document}
+ \DocInput{\jobname.dtx}
+\end{document}
+%</driver>
+% \fi
+%
+% \title{^^A
+% The \pkg{l3draw-softpath} package\\ Soft paths^^A
+% }
+%
+% \author{^^A
+% The \LaTeX3 Project\thanks
+% {^^A
+% E-mail:
+% \href{mailto:latex-team@latex-project.org}
+% {latex-team@latex-project.org}^^A
+% }^^A
+% }
+%
+% \date{Released 2018/02/21}
+%
+% \maketitle
+%
+% \begin{implementation}
+%
+% \section{\pkg{l3draw-softpath} implementation}
+%
+% \begin{macrocode}
+%<*initex|package>
+% \end{macrocode}
+%
+% \begin{macrocode}
+%<@@=draw>
+% \end{macrocode}
+%
+% There are two linked aims in the code here. The most significant is to
+% provide a way to modify paths, for example to shorten the ends or round
+% the corners. This means that the path cannot be written piecemeal as
+% specials, but rather needs to be held in macros. The second aspect that
+% follows from this is performance: simply adding to a single macro a piece
+% at a time will have poor performance as the list gets long. Paths need to
+% be global (as specials are), so we cannot use \pkg{l3tl-build} or a similar
+% approach. Instead, we use the same idea as \pkg{pgf}: use a series of buffer
+% macros such that in most cases we don't add tokens to the main list. This
+% will get slow only for \emph{enormous} paths.
+%
+% Each marker (operation) token takes two arguments, which makes processing
+% more straight-forward. As such, some operations have dummy arguments, whilst
+% others have to be split over several tokens. As the code here is at a low
+% level, all dimension arguments are assumed to be explicit and fully-expanded.
+%
+% \begin{variable}
+% {
+% \g_@@_softpath_main_tl ,
+% \g_@@_softpath_buffer_a_tl ,
+% \g_@@_softpath_buffer_b_tl
+% }
+% The soft path itself.
+% \begin{macrocode}
+\tl_new:N \g_@@_softpath_main_tl
+\tl_new:N \g_@@_softpath_buffer_a_tl
+\tl_new:N \g_@@_softpath_buffer_b_tl
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{variable}
+% {
+% \g_@@_softpath_buffer_a_int ,
+% \g_@@_softpath_buffer_b_int
+% }
+% Tracking data.
+% \begin{macrocode}
+\int_new:N \g_@@_softpath_buffer_a_int
+\int_new:N \g_@@_softpath_buffer_b_int
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{macro}{\@@_softpath_add:n, \@@_softpath_add:x}
+% \begin{macro}{\@@_softpath_concat:n}
+% \begin{macro}{\@@_softpath_reset_buffers:}
+% The softpath itself is quite simple. We use three token lists to hold the
+% data: two buffers of limited length, and the main list of arbitrary size.
+% Most of the time this will mean that we don't add to the full list, so
+% performance will be acceptable.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_softpath_add:n #1
+ {
+ \int_compare:nNnTF \g_@@_softpath_buffer_a_int < { 40 }
+ {
+ \int_gincr:N \g_@@_softpath_buffer_a_int
+ \tl_gput_right:Nn \g_@@_softpath_buffer_a_tl {#1}
+ }
+ {
+ \int_compare:nNnTF \g_@@_softpath_buffer_b_int < { 40 }
+ {
+ \int_gincr:N \g_@@_softpath_buffer_b_int
+ \tl_gset:Nx \g_@@_softpath_buffer_b_tl
+ {
+ \exp_not:V \g_@@_softpath_buffer_b_tl
+ \exp_not:V \g_@@_softpath_buffer_a_tl
+ \exp_not:n {#1}
+ }
+ \int_gzero:N \g_@@_softpath_buffer_a_int
+ \tl_gclear:N \g_@@_softpath_buffer_a_tl
+ }
+ { \@@_softpath_concat:n {#1} }
+ }
+ }
+\cs_generate_variant:Nn \@@_softpath_add:n { x }
+\cs_new_protected:Npn \@@_softpath_concat:n #1
+ {
+ \tl_gset:Nx \g_@@_softpath_main_tl
+ {
+ \exp_not:V \g_@@_softpath_main_tl
+ \exp_not:V \g_@@_softpath_buffer_b_tl
+ \exp_not:V \g_@@_softpath_buffer_a_tl
+ \exp_not:n {#1}
+ }
+ \@@_softpath_reset_buffers:
+ }
+\cs_new_protected:Npn \@@_softpath_reset_buffers:
+ {
+ \int_gzero:N \g_@@_softpath_buffer_a_int
+ \tl_gclear:N \g_@@_softpath_buffer_a_tl
+ \int_gzero:N \g_@@_softpath_buffer_b_int
+ \tl_gclear:N \g_@@_softpath_buffer_b_tl
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\@@_softpath_get:N, \@@_softpath_set_eq:N}
+% Save and restore functions.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_softpath_get:N #1
+ {
+ \@@_softpath_concat:n { }
+ \tl_set_eq:NN #1 \g_@@_softpath_main_tl
+ }
+\cs_new_protected:Npn \@@_softpath_set_eq:N #1
+ {
+ \tl_gset_eq:NN \g_@@_softpath_main_tl #1
+ \@@_softpath_reset_buffers:
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}
+% {\@@_softpath_use:, \@@_softpath_clear:, \@@_softpath_use_clear:}
+% Using and clearing is trivial.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_softpath_use:
+ {
+ \g_@@_softpath_main_tl
+ \g_@@_softpath_buffer_b_tl
+ \g_@@_softpath_buffer_a_tl
+ }
+\cs_new_protected:Npn \@@_softpath_clear:
+ {
+ \tl_gclear:N \g_@@_softpath_main_tl
+ \tl_gclear:N \g_@@_softpath_buffer_a_tl
+ \tl_gclear:N \g_@@_softpath_buffer_b_tl
+ }
+\cs_new_protected:Npn \@@_softpath_use_clear:
+ {
+ \@@_softpath_use:
+ \@@_softpath_clear:
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{variable}{\g_@@_softpath_lastx_dim, \g_@@_softpath_lasty_dim}
+% For tracking the end of the path (to close it).
+% \begin{macrocode}
+\dim_new:N \g_@@_softpath_lastx_dim
+\dim_new:N \g_@@_softpath_lasty_dim
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{variable}{\g_@@_softpath_move_bool}
+% Track if moving a point should update the close position.
+% \begin{macrocode}
+\bool_new:N \g_@@_softpath_move_bool
+\bool_gset_true:N \g_@@_softpath_move_bool
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{macro}{\@@_softpath_curveto:nnnnnn}
+% \begin{macro}
+% {
+% \@@_softpath_lineto:nn,
+% \@@_softpath_moveto:nn
+% }
+% \begin{macro}{\@@_softpath_rectangle:nnnn}
+% \begin{macro}{\@@_softpath_roundpoint:nn, \@@_softpath_roundpoint:VV}
+% The various parts of a path expressed as the appropriate soft path
+% functions.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_softpath_closepath:
+ {
+ \@@_softpath_add:x
+ {
+ \@@_softpath_close_op:nn
+ { \dim_use:N \g_@@_softpath_lastx_dim }
+ { \dim_use:N \g_@@_softpath_lasty_dim }
+ }
+ }
+\cs_new_protected:Npn \@@_softpath_curveto:nnnnnn #1#2#3#4#5#6
+ {
+ \@@_softpath_add:n
+ {
+ \@@_softpath_curveto_opi:nn {#1} {#2}
+ \@@_softpath_curveto_opii:nn {#3} {#4}
+ \@@_softpath_curveto_opiii:nn {#5} {#6}
+ }
+ }
+\cs_new_protected:Npn \@@_softpath_lineto:nn #1#2
+ {
+ \@@_softpath_add:n
+ { \@@_softpath_lineto_op:nn {#1} {#2} }
+ }
+\cs_new_protected:Npn \@@_softpath_moveto:nn #1#2
+ {
+ \@@_softpath_add:n
+ { \@@_softpath_moveto_op:nn {#1} {#2} }
+ \bool_if:NT \g_@@_softpath_move_bool
+ {
+ \dim_gset:Nn \g_@@_softpath_lastx_dim {#1}
+ \dim_gset:Nn \g_@@_softpath_lasty_dim {#2}
+ }
+ }
+\cs_new_protected:Npn \@@_softpath_rectangle:nnnn #1#2#3#4
+ {
+ \@@_softpath_add:n
+ {
+ \@@_softpath_rectangle_opi:nn {#1} {#2}
+ \@@_softpath_rectangle_opii:nn {#3} {#4}
+ }
+ }
+\cs_new_protected:Npn \@@_softpath_roundpoint:nn #1#2
+ {
+ \@@_softpath_add:n
+ { \@@_softpath_roundpoint_op:nn {#1} {#2} }
+ }
+\cs_generate_variant:Nn \@@_softpath_roundpoint:nn { VV }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}
+% {
+% \@@_softpath_close_op:nn ,
+% \@@_softpath_curveto_opi:nn ,
+% \@@_softpath_curveto_opii:nn ,
+% \@@_softpath_curveto_opiii:nn ,
+% \@@_softpath_lineto_op:nn ,
+% \@@_softpath_moveto_op:nn ,
+% \@@_softpath_roundpoint_op:nn ,
+% \@@_softpath_rectangle_opi:nn ,
+% \@@_softpath_rectangle_opii:nn
+% }
+% \begin{macro}{\@@_softpath_curveto_opi:nnNnnNnn}
+% \begin{macro}{\@@_softpath_rectangle_opi:nnNnn}
+% The markers for operations: all the top-level ones take two arguments.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_softpath_close_op:nn #1#2
+ { \driver_draw_closepath: }
+\cs_new_protected:Npn \@@_softpath_curveto_opi:nn #1#2
+ { \@@_softpath_curveto_opi:nnNnnNnn {#1} {#2} }
+\cs_new_protected:Npn \@@_softpath_curveto_opi:nnNnnNnn #1#2#3#4#5#6#7#8
+ { \driver_draw_curveto:nnnnnn {#1} {#2} {#4} {#5} {#7} {#8} }
+\cs_new_protected:Npn \@@_softpath_curveto_opii:nn #1#2 { }
+\cs_new_protected:Npn \@@_softpath_curveto_opiii:nn #1#2 { }
+\cs_new_protected:Npn \@@_softpath_lineto_op:nn #1#2
+ { \driver_draw_lineto:nn {#1} {#2} }
+\cs_new_protected:Npn \@@_softpath_moveto_op:nn #1#2
+ { \driver_draw_moveto:nn {#1} {#2} }
+\cs_new_protected:Npn \@@_softpath_roundpoint_op:nn #1#2 { }
+\cs_new_protected:Npn \@@_softpath_rectangle_opi:nn #1#2
+ { \@@_softpath_rectangle_opi:nnNnn {#1} {#2} }
+\cs_new_protected:Npn \@@_softpath_rectangle_opi:nnNnn #1#2#3#4#5
+ { \driver_draw_rectangle:nnnn {#1} {#2} {#4} {#5} }
+ \cs_new_protected:Npn \@@_softpath_rectangle_opii:nn #1#2 { }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macrocode}
+%</initex|package>
+% \end{macrocode}
+%
+% \end{implementation}
+%
+% \PrintIndex
diff --git a/Master/texmf-dist/source/latex/l3experimental/l3draw/l3draw-state.dtx b/Master/texmf-dist/source/latex/l3experimental/l3draw/l3draw-state.dtx
new file mode 100644
index 00000000000..5e6eb424d05
--- /dev/null
+++ b/Master/texmf-dist/source/latex/l3experimental/l3draw/l3draw-state.dtx
@@ -0,0 +1,193 @@
+% \iffalse meta-comment
+%
+%% File: l3draw-state.dtx Copyright(C) 2018 The LaTeX3 Project
+%
+% It may be distributed and/or modified under the conditions of the
+% LaTeX Project Public License (LPPL), either version 1.3c of this
+% license or (at your option) any later version. The latest version
+% of this license is in the file
+%
+% http://www.latex-project.org/lppl.txt
+%
+% This file is part of the "l3experimental bundle" (The Work in LPPL)
+% and all files in that bundle must be distributed together.
+%
+% -----------------------------------------------------------------------
+%
+% The development version of the bundle can be found at
+%
+% https://github.com/latex3/latex3
+%
+% for those people who are interested.
+%
+%<*driver>
+\RequirePackage{expl3}
+\documentclass[full]{l3doc}
+\begin{document}
+ \DocInput{\jobname.dtx}
+\end{document}
+%</driver>
+% \fi
+%
+% \title{^^A
+% The \pkg{l3draw-state} package\\ Drawing graphics state^^A
+% }
+%
+% \author{^^A
+% The \LaTeX3 Project\thanks
+% {^^A
+% E-mail:
+% \href{mailto:latex-team@latex-project.org}
+% {latex-team@latex-project.org}^^A
+% }^^A
+% }
+%
+% \date{Released 2018/02/21}
+%
+% \maketitle
+%
+% \begin{implementation}
+%
+% \section{\pkg{l3draw-state} implementation}
+%
+% \begin{macrocode}
+%<*initex|package>
+% \end{macrocode}
+%
+% \begin{macrocode}
+%<@@=draw>
+% \end{macrocode}
+%
+% \begin{variable}{\g_@@_linewidth_dim, \g_@@_inner_linewidth_dim}
+% Linewidth for strokes: global as the scope for this relies on the graphics
+% state. The inner line width is used for places where two lines are used.
+% \begin{macrocode}
+\dim_new:N \g_@@_linewidth_dim
+\dim_new:N \g_@@_inner_linewidth_dim
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{variable}{\l_draw_default_linewidth_dim}
+% A default: this is used at the start of every drawing.
+% \begin{macrocode}
+\dim_new:N \l_draw_default_linewidth_dim
+\dim_set:Nn \l_draw_default_linewidth_dim { 0.4pt }
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{macro}{\draw_linewidth:n, \draw_inner_linewidth:n}
+% Set the linewidth: we need a wrapper as this has to pass to the driver
+% layer. The inner version is handled at the macro layer but is given a
+% consistent interface here.
+% \begin{macrocode}
+\cs_new_protected:Npn \draw_linewidth:n #1
+ {
+ \dim_gset:Nn \g_@@_linewidth_dim { \fp_to_dim:n {#1} }
+ \driver_draw_linewidth:n \g_@@_linewidth_dim
+ }
+\cs_new_protected:Npn \draw_inner_linewidth:n #1
+ { \dim_gset:Nn \g_@@_inner_linewidth_dim { \fp_to_dim:n {#1} } }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\draw_miterlimit:n}
+% Pass through to the driver layer.
+% \begin{macrocode}
+\cs_new_protected:Npn \draw_miterlimit:n #1
+ { \driver_draw_miterlimit:n { \fp_to_dim:n {#1} } }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}
+% {
+% \draw_cap_butt:, \draw_cap_rectangle:, \draw_cap_round:,
+% \draw_evenodd_rule:, \draw_nonzero_rule:,
+% \draw_join_bevel:, \draw_join_miter:, \draw_join_round:
+% }
+% All straight wrappers.
+% \begin{macrocode}
+\cs_new_protected:Npn \draw_cap_butt: { \driver_draw_cap_butt: }
+\cs_new_protected:Npn \draw_cap_rectangle: { \driver_draw_cap_rectangle: }
+\cs_new_protected:Npn \draw_cap_round: { \driver_draw_cap_round: }
+\cs_new_protected:Npn \draw_evenodd_rule: { \driver_draw_evenodd_rule: }
+\cs_new_protected:Npn \draw_nonzero_rule: { \driver_draw_nonzero_rule: }
+\cs_new_protected:Npn \draw_join_bevel: { \driver_draw_join_bevel: }
+\cs_new_protected:Npn \draw_join_miter: { \driver_draw_join_miter: }
+\cs_new_protected:Npn \draw_join_round: { \driver_draw_join_round: }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{variable}{\l_@@_color_tmp_tl}
+% Scratch space.
+% \begin{macrocode}
+\tl_new:N \l_@@_color_tmp_tl
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{variable}{\g_@@_fill_color_tl, \g_@@_stroke_color_tl}
+% For tracking.
+% \begin{macrocode}
+\tl_new:N \g_@@_fill_color_tl
+\tl_new:N \g_@@_stroke_color_tl
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{macro}{\draw_color:n, \draw_color_fill:n, \draw_color_stroke:n}
+% \begin{macro}{\@@_color:nn}
+% \begin{macro}{\@@_color_aux:nn, \@@_color_aux:Vn}
+% \begin{macro}{\@@_color:nw}
+% \begin{macro}
+% {
+% \@@_select_cmyk:nw, \@@_select_gray:nw,
+% \@@_select_rgb:nw, \@@_split_select:nw
+% }
+% Much the same as for core color support but calling the relevant
+% driver-level function.
+% \begin{macrocode}
+\cs_new_protected:Npn \draw_color:n #1
+ { \@@_color:nn { } {#1} }
+\cs_new_protected:Npn \draw_color_fill:n #1
+ { \@@_color:nn { fill } {#1} }
+\cs_new_protected:Npn \draw_color_stroke:n #1
+ { \@@_color:nn { stroke } {#1} }
+\cs_new_protected:Npn \@@_color:nn #1#2
+ {
+ \color_parse:nN {#2} \l_@@_color_tmp_tl
+ \tl_if_blank:nTF {#1}
+ {
+ \tl_gset_eq:NN \g_@@_fill_color_tl \l_@@_color_tmp_tl
+ \tl_gset_eq:NN \g_@@_stroke_color_tl \l_@@_color_tmp_tl
+ \@@_color_aux:Vn \l_@@_color_tmp_tl { color }
+ }
+ {
+ \tl_gset_eq:cN { g_@@_ #1 _color_tl } \l_@@_color_tmp_tl
+ \@@_color_aux:Vn \l_@@_color_tmp_tl { #1 }
+ }
+ }
+\cs_new_protected:Npn \@@_color_aux:nn #1#2
+ { \@@_color:nw {#2} #1 \q_stop }
+\cs_generate_variant:Nn \@@_color_aux:nn { V }
+\cs_new_protected:Npn \@@_color:nw #1#2 ~ #3 \q_stop
+ { \use:c { @@_color_ #2 :nw } {#1} #3 \q_stop }
+\cs_new_protected:Npn \@@_color_cmyk:nw #1#2 ~ #3 ~ #4 ~ #5 \q_stop
+ { \use:c { driver_draw_ #1 _cmyk:nnnn } {#2} {#3} {#4} {#5} }
+\cs_new_protected:Npn \@@_color_gray:nw #1#2 \q_stop
+ { \use:c { driver_draw_ #1 _gray:n } {#2} }
+\cs_new_protected:Npn \@@_color_rgb:nw #1#2 ~ #3 ~ #4 \q_stop
+ { \use:c { driver_draw_ #1 _rgb:nnn } {#2} {#3} {#4} }
+\cs_new_protected:Npn \@@_color_spot:nw #1#2 ~ #3 \q_stop
+ { \use:c { driver_draw_ #1 _spot:nn } {#2} {#3} }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macrocode}
+%</initex|package>
+% \end{macrocode}
+%
+% \end{implementation}
+%
+% \PrintIndex
diff --git a/Master/texmf-dist/source/latex/l3experimental/l3draw/l3draw-transforms.dtx b/Master/texmf-dist/source/latex/l3experimental/l3draw/l3draw-transforms.dtx
new file mode 100644
index 00000000000..4f325f01092
--- /dev/null
+++ b/Master/texmf-dist/source/latex/l3experimental/l3draw/l3draw-transforms.dtx
@@ -0,0 +1,286 @@
+% \iffalse meta-comment
+%
+%% File: l3draw-transforms.dtx Copyright(C) 2018 The LaTeX3 Project
+%
+% It may be distributed and/or modified under the conditions of the
+% LaTeX Project Public License (LPPL), either version 1.3c of this
+% license or (at your option) any later version. The latest version
+% of this license is in the file
+%
+% http://www.latex-project.org/lppl.txt
+%
+% This file is part of the "l3experimental bundle" (The Work in LPPL)
+% and all files in that bundle must be distributed together.
+%
+% -----------------------------------------------------------------------
+%
+% The development version of the bundle can be found at
+%
+% https://github.com/latex3/latex3
+%
+% for those people who are interested.
+%
+%<*driver>
+\RequirePackage{expl3}
+\documentclass[full]{l3doc}
+\begin{document}
+ \DocInput{\jobname.dtx}
+\end{document}
+%</driver>
+% \fi
+%
+% \title{^^A
+% The \pkg{l3draw-transforms} package\\ Transformations^^A
+% }
+%
+% \author{^^A
+% The \LaTeX3 Project\thanks
+% {^^A
+% E-mail:
+% \href{mailto:latex-team@latex-project.org}
+% {latex-team@latex-project.org}^^A
+% }^^A
+% }
+%
+% \date{Released 2018/02/21}
+%
+% \maketitle
+%
+% \begin{implementation}
+%
+% \section{\pkg{l3draw-transforms} implementation}
+%
+% \begin{macrocode}
+%<*initex|package>
+% \end{macrocode}
+%
+% \begin{macrocode}
+%<@@=draw>
+% \end{macrocode}
+%
+% \begin{variable}{\l_@@_transformcm_active_bool}
+% An internal flag to avoid redundant calculations.
+% \begin{macrocode}
+\bool_new:N \l_@@_transformcm_active_bool
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{variable}
+% {
+% \l_@@_transformcm_aa_fp, \l_@@_transformcm_ab_fp,
+% \l_@@_transformcm_ba_fp, \l_@@_transformcm_aa_fp,
+% \l_@@_transformcm_xshift_dim,
+% \l_@@_transformcm_yshift_dim
+% }
+% The active matrix itself.
+% \begin{macrocode}
+\fp_new:N \l_@@_transformcm_aa_fp
+\fp_new:N \l_@@_transformcm_ab_fp
+\fp_new:N \l_@@_transformcm_ba_fp
+\fp_new:N \l_@@_transformcm_bb_fp
+\dim_new:N \l_@@_transformcm_xshift_dim
+\dim_new:N \l_@@_transformcm_yshift_dim
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{macro}{\draw_transform_reset:}
+% Fast resetting.
+% \begin{macrocode}
+\cs_new_protected:Npn \draw_transform_reset:
+ {
+ \fp_set:Nn \l_@@_transformcm_aa_fp { 1}
+ \fp_zero:N \l_@@_transformcm_ab_fp
+ \fp_zero:N \l_@@_transformcm_ba_fp
+ \fp_set:Nn \l_@@_transformcm_bb_fp { 1 }
+ \dim_zero:N \l_@@_transformcm_xshift_dim
+ \dim_zero:N \l_@@_transformcm_yshift_dim
+ }
+\draw_transform_reset:
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\draw_transform:nnnnn}
+% \begin{macro}{\@@_transform:nnnnnnn}
+% Setting the transform matrix is straight-forward, with just a bit
+% of expansion to sort out. With the mechanism active, the identity
+% matrix is set.
+% \begin{macrocode}
+\cs_new_protected:Npn \draw_transform:nnnnn #1#2#3#4#5
+ {
+ \@@_point_process:nn
+ { \@@_transform:nnnnnnn {#1} {#2} {#3} {#4} }
+ {#5}
+ }
+\cs_new_protected:Npn \@@_transform:nnnnnnn #1#2#3#4#5#6
+ {
+ \fp_set:Nn \l_@@_transformcm_aa_fp {#1}
+ \fp_set:Nn \l_@@_transformcm_ab_fp {#2}
+ \fp_set:Nn \l_@@_transformcm_ba_fp {#3}
+ \fp_set:Nn \l_@@_transformcm_bb_fp {#4}
+ \dim_set:Nn \l_@@_transformcm_xshift_dim {#5}
+ \dim_set:Nn \l_@@_transformcm_yshift_dim {#6}
+ \bool_lazy_all:nTF
+ {
+ { \fp_compare_p:nNn \l_@@_transformcm_aa_fp = \c_one_fp }
+ { \fp_compare_p:nNn \l_@@_transformcm_ab_fp = \c_zero_fp }
+ { \fp_compare_p:nNn \l_@@_transformcm_ba_fp = \c_zero_fp }
+ { \fp_compare_p:nNn \l_@@_transformcm_bb_fp = \c_one_fp }
+ }
+ { \bool_set_false:N \l_@@_transformcm_active_bool }
+ { \bool_set_true:N \l_@@_transformcm_active_bool }
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\draw_transform_concat:nnnnn}
+% \begin{macro}{\@@_transform_concat:nnnnnn}
+% \begin{macro}{\@@_transform_concat_aux:nnnnnn}
+% Much the same story for adding to an existing matrix. The part that is more
+% complex is the calculations required: everything gets passed back to
+% \cs{@@_transform_set:nnnnnn}, with pre-expansion just in case there are
+% \emph{e.g}~random values. The final step is \texttt{x}-type expanded as
+% otherwise later values affect earlier ones.
+% \begin{macrocode}
+\cs_new_protected:Npn \draw_transform_concat:nnnnn #1#2#3#4#5
+ {
+ \@@_point_process:nn
+ { \@@_transform_concat:nnnnnn {#1} {#2} {#3} {#4} }
+ {#5}
+ }
+\cs_new_protected:Npn \@@_transform_concat:nnnnnn #1#2#3#4#5#6
+ {
+ \use:x
+ {
+ \@@_transform_concat_aux:nnnnnn
+ { \fp_eval:n {#1} }
+ { \fp_eval:n {#2} }
+ { \fp_eval:n {#3} }
+ { \fp_eval:n {#4} }
+ {#5}
+ {#6}
+ }
+ }
+\cs_new_protected:Npn \@@_transform_concat_aux:nnnnnn #1#2#3#4#5#6
+ {
+ \use:x
+ {
+ \@@_transform:nnnnnnn
+ { #1 * \l_@@_transformcm_aa_fp + #2 * \l_@@_transformcm_ba_fp }
+ { #1 * \l_@@_transformcm_ab_fp + #2 * \l_@@_transformcm_bb_fp }
+ { #3 * \l_@@_transformcm_aa_fp + #4 * \l_@@_transformcm_ba_fp }
+ { #3 * \l_@@_transformcm_ab_fp + #4 * \l_@@_transformcm_bb_fp }
+ {
+ \fp_to_dim:n
+ {
+ \l_@@_transformcm_xshift_dim
+ + \l_@@_transformcm_aa_fp * #5
+ + \l_@@_transformcm_ba_fp * #6
+ }
+ }
+ {
+ \fp_to_dim:n
+ {
+ \l_@@_transformcm_yshift_dim
+ + \l_@@_transformcm_ab_fp * #5
+ + \l_@@_transformcm_bb_fp * #6
+ }
+ }
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\draw_transform_invert:}
+% \begin{macro}{\@@_transform_invert:n, \@@_transform_invert:f}
+% Standard mathematics: calculate the inverse matrix and use that, then
+% undo the shifts.
+% \begin{macrocode}
+\cs_new_protected:Npn \draw_transform_invert:
+ {
+ \bool_if:NT \l_@@_transformcm_active_bool
+ {
+ \@@_transform_invert:f
+ {
+ \fp_eval:n
+ {
+ 1 /
+ (
+ \l_@@_transformcm_aa_fp * \l_@@_transformcm_bb_fp
+ - \l_@@_transformcm_ab_fp * \l_@@_transformcm_ba_fp
+ )
+ }
+ }
+ }
+ \dim_set:Nn \l_@@_transformcm_xshift_dim
+ {
+ \fp_to_dim:n
+ {
+ -\l_@@_transformcm_xshift_dim * \l_@@_transformcm_aa_fp
+ -\l_@@_transformcm_yshift_dim * \l_@@_transformcm_ba_fp
+ }
+ }
+ \dim_set:Nn \l_@@_transformcm_yshift_dim
+ {
+ \fp_to_dim:n
+ {
+ -\l_@@_transformcm_xshift_dim * \l_@@_transformcm_ab_fp
+ -\l_@@_transformcm_yshift_dim * \l_@@_transformcm_bb_fp
+ }
+ }
+ }
+\cs_new_protected:Npn \@@_transform_invert:n #1
+ {
+ \fp_set:Nn \l_@@_transformcm_aa_fp
+ { \l_@@_transformcm_bb_fp * #1 }
+ \fp_set:Nn \l_@@_transformcm_ab_fp
+ { -\l_@@_transformcm_ab_fp * #1 }
+ \fp_set:Nn \l_@@_transformcm_ba_fp
+ { -\l_@@_transformcm_ba_fp * #1 }
+ \fp_set:Nn \l_@@_transformcm_bb_fp
+ { \l_@@_transformcm_aa_fp * #1 }
+ }
+\cs_generate_variant:Nn \@@_transform_invert:n { f }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\draw_transform_triangle:nnn}
+% Simple maths to move the canvas origin to |#1| and the two axes to
+% |#2| and |#3|.
+% \begin{macrocode}
+\cs_new_protected:Npn \draw_transform_triangle:nnn #1#2#3
+ {
+ \@@_point_process:nnn
+ {
+ \@@_point_process:nn
+ { \@@_tranform_triangle:nnnnnn }
+ {#1}
+ }
+ {#2} {#3}
+ }
+\cs_new_protected:Npn \@@_tranform_triangle:nnnnnn #1#2#3#4#5#6
+ {
+ \use:x
+ {
+ \@@_transform:nnnnnnn
+ { #3 - #1 }
+ { #4 - #2 }
+ { #5 - #1 }
+ { #6 - #2 }
+ {#1}
+ {#2}
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macrocode}
+%</initex|package>
+% \end{macrocode}
+%
+% \end{implementation}
+%
+% \PrintIndex
diff --git a/Master/texmf-dist/source/latex/l3experimental/l3draw/l3draw.dtx b/Master/texmf-dist/source/latex/l3experimental/l3draw/l3draw.dtx
new file mode 100644
index 00000000000..9b7c04d5e54
--- /dev/null
+++ b/Master/texmf-dist/source/latex/l3experimental/l3draw/l3draw.dtx
@@ -0,0 +1,575 @@
+% \iffalse meta-comment
+%
+%% File: l3draw.dtx Copyright(C) 2018 The LaTeX3 Project
+%
+% It may be distributed and/or modified under the conditions of the
+% LaTeX Project Public License (LPPL), either version 1.3c of this
+% license or (at your option) any later version. The latest version
+% of this license is in the file
+%
+% http://www.latex-project.org/lppl.txt
+%
+% This file is part of the "l3experimental bundle" (The Work in LPPL)
+% and all files in that bundle must be distributed together.
+%
+% -----------------------------------------------------------------------
+%
+% The development version of the bundle can be found at
+%
+% https://github.com/latex3/latex3
+%
+% for those people who are interested.
+%
+%<*driver|package>
+\RequirePackage{expl3}
+%</driver|package>
+%<*driver>
+\documentclass[full]{l3doc}
+\begin{document}
+ \DocInput{\jobname.dtx}
+\end{document}
+%</driver>
+% \fi
+%
+% \title{^^A
+% The \pkg{l3draw} package\\ Core drawing support^^A
+% }
+%
+% \author{^^A
+% The \LaTeX3 Project\thanks
+% {^^A
+% E-mail:
+% \href{mailto:latex-team@latex-project.org}
+% {latex-team@latex-project.org}^^A
+% }^^A
+% }
+%
+% \date{Released 2018/02/21}
+%
+% \maketitle
+%
+% \begin{documentation}
+%
+% \section{\pkg{l3draw} documentation}
+%
+% The \pkg{l3draw} package provides a set of tools for creating (vector)
+% drawings in \pkg{expl3}. It is heavily inspired by the \pkg{pgf} layer of
+% the Ti\textit{k}Z system, with many of the interfaces having the same form.
+% However, the code provided here is build entirely on core \pkg{expl3} ideas
+% and uses the \LaTeX3 FPU for numerical support.
+%
+% Numerical expressions in \pkg{l3draw} are handled as floating point
+% expressions, unless otherwise noted. This means that they may contain or
+% omit explicit units. Where units are omitted, they will automatically be
+% taken as given in (\TeX{}) points.
+%
+% The code here is \emph{highly} experimental.
+%
+% \subsection{Drawings}
+%
+% \begin{function}{\draw_begin:, \draw_end:}
+% \begin{syntax}
+% \cs{draw_begin:}
+% ...
+% \cs{draw_end:}
+% \end{syntax}
+% Each drawing should be created within a \cs{draw_begin:}/\cs{draw_end:}
+% function pair. The \texttt{begin} function sets up a number of key
+% data structures for the rest of the functions here: unless otherwise
+% specified, use of |\draw_...| functions outside of this
+% \enquote{environment} is \emph{not supported}.
+%
+% The drawing created within the environment will be inserted into
+% the typesetting stream by the \cs{draw_end:} function, which will
+% switch out of vertical mode if required.
+% \end{function}
+%
+% \subsection{Graphics state}
+%
+% Within the drawing environment, a number of functions control how drawings
+% will appear. Note that these all apply \emph{globally}, though some are
+% rest at the start of each drawing (\cs{draw_begin:}).
+%
+% \begin{function}{\g_draw_linewidth_default_dim}
+% The default value of the linewidth for stokes, set at the start
+% of every drawing (\cs{draw_begin:}).
+% \end{function}
+%
+% \begin{function}{\draw_linewidth:n, \draw_inner_linewidth:n}
+% \begin{syntax}
+% \cs{draw_linewidth:n} \Arg{width}
+% \end{syntax}
+% Sets the width to be used for stroking to the \meta{width} (an
+% \meta{fp expr}).
+% \end{function}
+%
+% \begin{function}{\draw_nonzero_rule:, \draw_evenodd_rule:}
+% \begin{syntax}
+% \cs{draw_nonzero_rule:}
+% \end{syntax}
+% Active either the non-zero winding number or the even-odd rule,
+% respectively, for determining what is inside a fill or clip area.
+% For technical reasons, these command are not influenced by scoping
+% and apply on an ongoing basis.
+% \end{function}
+%
+% \begin{function}
+% {
+% \draw_cap_butt: ,
+% \draw_cap_rectangle: ,
+% \draw_cap_round:
+% }
+% \begin{syntax}
+% \cs{draw_cap_butt:}
+% \end{syntax}
+% Sets the style of terminal stroke position to one of butt, rectangle or
+% round.
+% \end{function}
+%
+% \begin{function}
+% {
+% \draw_join_bevel: ,
+% \draw_join_miter: ,
+% \draw_join_round:
+% }
+% \begin{syntax}
+% \cs{draw_cap_butt:}
+% \end{syntax}
+% Sets the style of stroke joins to one of bevel, miter or round.
+% \end{function}
+%
+% \begin{function}{\draw_miterlimit:n}
+% \begin{syntax}
+% \cs{draw_miterlimit:n} \Arg{limit}
+% \end{syntax}
+% Sets the miter \meta{limit} of lines joined as a miter, as described in the
+% PDF and PostScript manuals. The \meta{limit} is an \meta{fp expr}.
+% \end{function}
+%
+% \subsection{Points}
+%
+% Functions supporting the calculation of points (co-ordinates) are expandable
+% and may be used outside of the drawing environment. When used in this
+% way, they all yield a co-ordinate tuple, for example
+% \begin{verbatim}
+% \tl_set:Nx \l_tmpa_tl { \draw_point:nn { 1 } { 2 } }
+% \tl_show:N \l_tmpa_tl
+% \end{verbatim}
+% gives
+% \begin{verbatim}
+% > \l_tmpa_tl=1pt,2pt.
+% <recently read> }
+% \end{verbatim}
+%
+% This output form is then suitable as \emph{input} for subsequent point
+% calculations, \emph{i.e.}~where a \meta{point} is required it may be
+% given as a tuple. This \emph{may} include units and surrounding
+% parentheses, for example
+% \begin{verbatim}
+% 1,2
+% (1,2)
+% 1cm,3pt
+% (1pt,2cm)
+% 2 * sind(30), 2^4in
+% \end{verbatim}
+% are all valid input forms. Notice that each part of the tuple may itself
+% be a float point expression.
+%
+% Point co-ordinates are relative to the canvas axes, but can be transformed
+% by \cs{draw_point_transform:n}. These manipulation is applied by many
+% higher-level functions, for example path construction, and allows parts of
+% a drawing to be rotated, scaled or skewed. This occurs before writing any
+% data to the driver, and so such manipulations are tracked by the drawing
+% mechanisms. See \cs{driver_draw_transformcm:nnnnnn} for driver-level
+% manipulation of the canvas axes themselves.
+%
+% Notice that in contrast to \pkg{pgf} it is possible to give the positions
+% of points \emph{directly}.
+%
+% \subsubsection{Basic point functions}
+%
+% \begin{function}[EXP]{\draw_point:nn}
+% \begin{syntax}
+% \cs{draw_point:nn} \Arg{x} \Arg{y}
+% \end{syntax}
+% Gives the co-ordinates of the point at \meta{x} and \meta{y}, both of
+% which are \meta{fp expr}.
+% \end{function}
+%
+% \begin{function}[EXP]{\draw_point_polar:nn, \draw_point_polar:nnn}
+% \begin{syntax}
+% \cs{draw_point_polar:nn} \Arg{angle} \Arg{radius}
+% \cs{draw_point_polar:nnn} \Arg{angle} \Arg{radius-a} \Arg{radius-b}
+% \end{syntax}
+% Gives the co-ordinates of the point at \meta{angle} (an \meta{fp expr} in
+% \emph{degrees}) and \meta{radius}. The three-argument version accepts
+% two radii of different lengths.
+%
+% Note the interface here is somewhat different from that in \pkg{pgf}:
+% the one- and two-radii versions in \pkg{l3draw} use separate functions,
+% whilst in \pkg{pgf} they use the same function and a keyword.
+% \end{function}
+%
+% \begin{function}[EXP]{\draw_point_add:nn}
+% \begin{syntax}
+% \cs{draw_point_add:nn} \Arg{point1} \Arg{point2}
+% \end{syntax}
+% Adds \meta{point1} to \meta{point2}.
+% \end{function}
+%
+% \begin{function}[EXP]{\draw_point_diff:nn}
+% \begin{syntax}
+% \cs{draw_point_diff:nn} \Arg{point1} \Arg{point2}
+% \end{syntax}
+% Subtracts \meta{point1} from \meta{point2}.
+% \end{function}
+%
+% \begin{function}[EXP]{\draw_point_scale:nn}
+% \begin{syntax}
+% \cs{draw_point_scale:nn} \Arg{scale} \Arg{point}
+% \end{syntax}
+% Scales the \meta{point} by the \meta{scale} (an \meta{fp expr}).
+% \end{function}
+%
+% \begin{function}[EXP]{\draw_point_unit_vector:n}
+% \begin{syntax}
+% \cs{draw_point_unit_vector:n} \Arg{point}
+% \end{syntax}
+% Expands to the co-ordinates of a unit vector joining the \meta{point}
+% with the origin.
+% \end{function}
+%
+% \begin{function}[EXP]{\draw_point_transform:n}
+% \begin{syntax}
+% \cs{draw_point_transform:n} \Arg{point}
+% \end{syntax}
+% Evaluates the position of the \meta{point} subject to the current
+% transformation matrix. This operation is applied automatically by
+% most higher-level functions (\emph{e.g.}~path manipulations).
+% \end{function}
+%
+% \subsubsection{Points on a vector basis}
+%
+% As well as giving explicit values, it is possible to describe points
+% in terms of underlying direction vectors. The latter are initially
+% co-incident with the standard Cartesian axes, but may be altered by
+% the user.
+%
+% \begin{function}{\draw_xvec_set:n, \draw_yvec_set:n, \draw_zvec_set:n}
+% \begin{syntax}
+% \cs{draw_xvec_set:n} \Arg{point}
+% \end{syntax}
+% Defines the appropriate base vector to point toward the \meta{point}
+% on the canvas. The standard settings for the $x$- and $y$-vectors are
+% $1\,\mathrm{cm}$ along the relevant canvas axis, whilst for the
+% $z$-vector an appropriate direction is taken.
+% \end{function}
+%
+% \begin{function}[EXP]{\draw_point_vec:nn, \draw_point_vec:nnn}
+% \begin{syntax}
+% \cs{draw_point_vec:nn} \Arg{xscale} \Arg{yscale}
+% \cs{draw_point_vec:nnn} \Arg{xscale} \Arg{yscale} \Arg{zscale}
+% \end{syntax}
+% Expands to the co-ordinate of the point at \meta{xscale} times the
+% $x$-vector and \meta{yscale} times the $y$-vector. The three-argument
+% version extends this to include the $z$-vector.
+% \end{function}
+%
+% \begin{function}[EXP]{\draw_point_vec_polar:nn, \draw_point_vec_polar:nnn}
+% \begin{syntax}
+% \cs{draw_point_vec_polar:nn} \Arg{angle} \Arg{radius}
+% \cs{draw_point_vec_polar:nnn} \Arg{angle} \Arg{radius-a} \Arg{radius-b}
+% \end{syntax}
+% Gives the co-ordinates of the point at \meta{angle} (an \meta{fp expr} in
+% \emph{degrees}) and \meta{radius}, relative to the prevailing
+% $x$- and $y$-vectors. The three-argument version accepts two radii of
+% different lengths.
+%
+% Note the interface here is somewhat different from that in \pkg{pgf}:
+% the one- and two-radii versions in \pkg{l3draw} use separate functions,
+% whilst in \pkg{pgf} they use the same function and a keyword.
+% \end{function}
+%
+% \subsubsection{Intersections}
+%
+% \begin{function}[EXP]{\draw_point_intersect_lines:nnnn}
+% \begin{syntax}
+% \cs{draw_point_intersect_lines:nnnn} \Arg{point1} \Arg{point2} \Arg{point3} \Arg{point4}
+% \end{syntax}
+% Evaluates the point at the intersection of one line, joining
+% \meta{point1} and \meta{point2}, and a second line joining \meta{point3}
+% and \meta{point4}. If the lines do not intersect, or are coincident, and
+% error will occur.
+% \end{function}
+%
+% \begin{function}[EXP]{\draw_point_intersect_circles:nnnn}
+% \begin{syntax}
+% \cs{draw_point_intersect_circles:nnnnn}
+% \Arg{center1} \Arg{radius1} \Arg{center2} \Arg{radius2} \Arg{root}
+% \end{syntax}
+% Evaluates the point at the intersection of one circle with
+% \meta{center1} and \meta{radius1}, and a second circle with \meta{center2}
+% and \meta{radius2}. If the circles do not intersect, or are coincident, and
+% error will occur.
+%
+% Note the interface here has a different argument ordering from that in
+% \pkg{pgf}, which has the two centers then the two radii.
+% \end{function}
+%
+% \subsubsection{Interpolations}
+%
+% \begin{function}[EXP]{\draw_point_interpolate_line:nnn}
+% \begin{syntax}
+% \cs{draw_point_interpolate_line:nnn} \Arg{part} \Arg{point1} \Arg{point2}
+% \end{syntax}
+% Expands to the point which is \meta{part} way along the line joining
+% \meta{point1} and \meta{point2}. The \meta{part} may be an interpolation or
+% an extrapolation, and is a floating point value expressing a percentage
+% along the line, \emph{e.g.}~a value of \texttt{0.5} would be half-way
+% between the two points.
+% \end{function}
+%
+% \begin{function}[EXP]{\draw_point_interpolate_distance:nnn}
+% \begin{syntax}
+% \cs{draw_point_interpolate_distance:nnn} \Arg{distance} \Arg{point expr1} \Arg{point expr2}
+% \end{syntax}
+% Expands to the point which is \meta{distance} way along the line joining
+% \meta{point1} and \meta{point2}. The \meta{distance} may be an interpolation
+% or an extrapolation.
+% \end{function}
+%
+% \begin{function}[EXP]{\draw_point_interpolate_curve:nnnnnn}
+% \begin{syntax}
+% \cs{draw_point_interpolate_curve:nnnnnn} \Arg{part}
+% \Arg{start} \Arg{control1} \Arg{control2} \Arg{end}
+% \end{syntax}
+% Expands to the point which is \meta{part} way along the curve between
+% \meta{start} and \meta{end} and defined by \meta{control1} and
+% \meta{control2}. The \meta{part} may be an interpolation or
+% an extrapolation, and is a floating point value expressing a percentage
+% along the curve, \emph{e.g.}~a value of \texttt{0.5} would be half-way
+% along the curve.
+% \end{function}
+%
+% \subsection{Paths}
+%
+% Paths are constructed by combining one or more operations before applying
+% one or more actions. Thus until a path is \enquote{used}, it may be
+% manipulated or indeed discarded entirely. Only one path is active at
+% any one time, and the path is \emph{not} affected by \TeX{} grouping.
+%
+% \begin{function}{\draw_path_corner_arc:n}
+% \begin{syntax}
+% \cs{draw_path_corner_arc:n} \Arg{length}
+% \end{syntax}
+% Sets the degree of rounding applied to corners in a path: if the
+% \meta{length} is \texttt{0pt} then no rounding applies. The value of the
+% \meta{length} is local to the current \TeX{} group. \emph{At present,
+% corner arcs are not activated in the code.}
+% \end{function}
+%
+% \begin{function}{\draw_path_moveto:n}
+% \begin{syntax}
+% \cs{draw_path_moveto:n} \Arg{point}
+% \end{syntax}
+% Moves the reference point of the path to the \meta{point}, but will
+% not join this to any previous point.
+% \end{function}
+%
+% \begin{function}{\draw_path_lineto:n}
+% \begin{syntax}
+% \cs{draw_path_lineto:n} \Arg{point}
+% \end{syntax}
+% Joins the current path to the \meta{point} with a straight line.
+% \end{function}
+%
+% \begin{function}{\draw_path_curveto:nnn}
+% \begin{syntax}
+% \cs{draw_path_curveto:nnn} \Arg{control1} \Arg{control2} \Arg{end}
+% \end{syntax}
+% Joins the current path to the \meta{end} with a curved line defined by
+% cubic Bézier points \meta{control1} and \meta{control2}.
+% \end{function}
+%
+% \begin{function}{\draw_path_curveto:nn}
+% \begin{syntax}
+% \cs{draw_path_curveto:nn} \Arg{control} \Arg{end}
+% \end{syntax}
+% Joins the current path to the \meta{end} with a curved line defined by
+% quadratic Bézier point \meta{control}.
+% \end{function}
+%
+% \begin{function}{\draw_path_arc:nnn, \draw_path_arc:nnnn}
+% \begin{syntax}
+% \cs{draw_path_arc:nnn} \Arg{angle1} \Arg{angle2} \Arg{radius}
+% \cs{draw_path_arc:nnnn} \Arg{angle1} \Arg{angle2} \Arg{radius-a} \Arg{radius-b}
+% \end{syntax}
+% Joins the current path with an arc between \meta{angle1} and \meta{angle2}
+% and of \meta{radius}. The four-argument version accepts two radii of
+% different lengths.
+%
+% Note the interface here has a different argument ordering from that in
+% \pkg{pgf}, which has the two centers then the two radii.
+% \end{function}
+%
+% \begin{function}{\draw_path_arc_axes:nnnn}
+% \begin{syntax}
+% \cs{draw_path_arc_axes:nnn} \Arg{angle1} \Arg{angle2} \Arg{vector1} \Arg{vector2}
+% \end{syntax}
+% Appends the portion of an ellipse from \meta{angle1} to \meta{angle2} of an
+% ellipse with axes along \meta{vector1} and \meta{vector2} to the current path.
+% \end{function}
+%
+% \begin{function}{\draw_path_ellipse:nnnn}
+% \begin{syntax}
+% \cs{draw_path_ellipse:nnn} \Arg{center} \Arg{vector1} \Arg{vector2}
+% \end{syntax}
+% Appends an ellipse at \meta{center} with axes along \meta{vector1} and
+% \meta{vector2} to the current path.
+% \end{function}
+%
+% \begin{function}{\draw_path_circle:nn}
+% \begin{syntax}
+% \cs{draw_path_circle:nn} \Arg{center} \Arg{radius}
+% \end{syntax}
+% Appends a circle of \meta{radius} at \meta{center} to the current path.
+% \end{function}
+%
+% \begin{function}{\draw_path_rectangle:nn, \draw_path_rectangle_corners:nn}
+% \begin{syntax}
+% \cs{draw_path_rectangle:nn} \Arg{lower-left} \Arg{displacement}
+% \cs{draw_path_rectangle_corners:nn} \Arg{lower-left} \Arg{top-right}
+% \end{syntax}
+% Appends a rectangle starting at \meta{lower-left} to the current path,
+% with the size of the rectangle determined either by a \meta{displacement}
+% or the position of the \meta{top-right}.
+% \end{function}
+%
+% \begin{function}{\draw_path_grid:nnnn}
+% \begin{syntax}
+% \cs{draw_path_grid:nnnn} \Arg{xspace} \Arg{yspace} \Arg{lower-left} \Arg{upper-right}
+% \end{syntax}
+% Constructs a grid of \meta{xspace} and \meta{yspace} from the
+% \meta{lower-left} to the \meta{upper-right}, and appends this to the
+% current path.
+% \end{function}
+%
+% \begin{function}{\draw_path_close:}
+% \begin{syntax}
+% \cs{draw_path_close:}
+% \end{syntax}
+% Closes the current part of the path by appending a straight line from
+% the current point to the starting point of the path.
+% \end{function}
+%
+% \begin{function}{\draw_path_use:n, \draw_path_use_clear:n}
+% \begin{syntax}
+% \cs{draw_path_use:n} \Arg{action(s)}
+% \end{syntax}
+% Inserts the current path, carrying out one ore more possible \meta{actions}
+% (a comma list):
+% \begin{itemize}
+% \item \texttt{clear} Resets the path to empty
+% \item \texttt{clip} Clips any content outside of the path
+% \item \texttt{draw}
+% \item \texttt{fill} Fills the interior of the path with the current
+% file color
+% \item \texttt{stroke} Draws a line along the current path
+% \end{itemize}
+% \end{function}
+%
+% \subsection{Color}
+%
+% \begin{function}{\draw_color:n, \draw_fill:n, \draw_stroke:n}
+% \begin{syntax}
+% \cs{draw_color:n} \Arg{color expression}
+% \end{syntax}
+% Evaluates the \meta{color expression} as described for \pkg{l3color}.
+% \end{function}
+%
+% \subsection{Transformations}
+%
+% Points are normally used unchanged relative to the canvas axes. This can
+% be modified by applying a transformation matrix. The canvas axes themselves
+% may be adjusted using \cs{driver_draw_transformcm:nnnnnn}: note that this
+% is transparent to the drawing code so is not tracked.
+%
+% \begin{function}{\draw_transform_reset:}
+% \begin{syntax}
+% \cs{draw_transform_reset:}
+% \end{syntax}
+% Resets the matrix to the identity.
+% \end{function}
+%
+% \begin{function}{\draw_transform_concat:nnnnn}
+% \begin{syntax}
+% \cs{draw_transform_concat:nnnnn}
+% \Arg{a} \Arg{b} \Arg{c} \Arg{d} \Arg{vector}
+% \end{syntax}
+% Appends the given transformation to the currently-active one. The
+% transformation is made up of a matrix \meta{a}, \meta{b}, \meta{c} and
+% \meta{d}, and a shift by the \meta{vector}.
+% \end{function}
+%
+% \begin{function}{\draw_transform:nnnnn}
+% \begin{syntax}
+% \cs{draw_transform:nnnnn}
+% \Arg{a} \Arg{b} \Arg{c} \Arg{d} \Arg{vector}
+% \end{syntax}
+% Applies the transformation matrix specified, over-writing any existing
+% matrix. The transformation is made up of a matrix \meta{a}, \meta{b},
+% \meta{c} and \meta{d}, and a shift by the \meta{vector}.
+% \end{function}
+%
+% \begin{function}{\draw_transform_triangle:nnn}
+% \begin{syntax}
+% \cs{draw_transform_triangle:nnn}
+% \Arg{origin} \Arg{point1} \Arg{point2}
+% \end{syntax}
+% Applies a transformation such that the co-ordinates $(0, 0)$, $(1, 0)$
+% and $(0, 1)$ are given by the \meta{origin}, \meta{point1} and
+% \meta{point2}, respectively.
+% \end{function}
+%
+% \begin{function}{\draw_transform_invert:}
+% \begin{syntax}
+% \cs{draw_transform_invert:}
+% \end{syntax}
+% Inverts the current transformation matrix and reverses the current
+% shift vector.
+% \end{function}
+%
+% \end{documentation}
+%
+% \begin{implementation}
+%
+% \section{\pkg{l3draw} implementation}
+%
+% \begin{macrocode}
+%<*initex|package>
+% \end{macrocode}
+%
+% \begin{macrocode}
+%<@@=draw>
+% \end{macrocode}
+%
+% \begin{macrocode}
+%<*package>
+\ProvidesExplPackage{l3draw}{2018/02/21}{}
+ {L3 Experimental core drawing support}
+%</package>
+% \end{macrocode}
+%
+% \begin{macrocode}
+\RequirePackage { l3color }
+% \end{macrocode}
+%
+% Everything else is in the sub-files!
+%
+% \begin{macrocode}
+%</initex|package>
+% \end{macrocode}
+%
+% \end{implementation}
+%
+% \PrintIndex
diff --git a/Master/texmf-dist/source/latex/l3experimental/l3draw/l3draw.ins b/Master/texmf-dist/source/latex/l3experimental/l3draw/l3draw.ins
new file mode 100644
index 00000000000..d7c3616c607
--- /dev/null
+++ b/Master/texmf-dist/source/latex/l3experimental/l3draw/l3draw.ins
@@ -0,0 +1,66 @@
+\iffalse meta-comment
+
+File l3draw.ins Copyright (C) 2018 The LaTeX3 Project
+
+It may be distributed and/or modified under the conditions of the
+LaTeX Project Public License (LPPL), either version 1.3c of this
+license or (at your option) any later version. The latest version
+of this license is in the file
+
+ http://www.latex-project.org/lppl.txt
+
+This file is part of the "l3experimental bundle" (The Work in LPPL)
+and all files in that bundle must be distributed together.
+
+-----------------------------------------------------------------------
+
+The development version of the bundle can be found at
+
+ https://github.com/latex3/latex3
+
+for those people who are interested.
+
+-----------------------------------------------------------------------
+
+Any modification of this file should ensure that the copyright and
+license information is placed in the derived files.
+
+\fi
+
+\input l3docstrip.tex
+\askforoverwritefalse
+
+\preamble
+
+Copyright (C) 2018 The LaTeX3 Project
+
+It may be distributed and/or modified under the conditions of
+the LaTeX Project Public License (LPPL), either version 1.3c of
+this license or (at your option) any later version. The latest
+version of this license is in the file:
+
+ http://www.latex-project.org/lppl.txt
+
+This file is part of the "l3experimental bundle" (The Work in LPPL)
+and all files in that bundle must be distributed together.
+
+\endpreamble
+% stop docstrip adding \endinput
+\postamble
+\endpostamble
+
+\keepsilent
+
+\generate{\file{l3draw.sty}
+ {
+ \from{l3draw.dtx} {package}
+ \from{l3draw-paths.dtx} {package}
+ \from{l3draw-points.dtx} {package}
+ \from{l3draw-scopes.dtx} {package}
+ \from{l3draw-softpath.dtx} {package}
+ \from{l3draw-state.dtx} {package}
+ \from{l3draw-transforms.dtx} {package}
+ }
+}
+
+\endbatchfile