diff options
author | Karl Berry <karl@freefriends.org> | 2018-02-23 21:54:14 +0000 |
---|---|---|
committer | Karl Berry <karl@freefriends.org> | 2018-02-23 21:54:14 +0000 |
commit | 87d871a3d83784d48b71fa3712b9f525bfc710d2 (patch) | |
tree | f12f9ffdc697b5af9ee14c06874ec0e2f72c9f94 /Master/texmf-dist/source/latex/l3experimental/l3draw | |
parent | ccc63194ce7813106830c8a8755c54d89de831b4 (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')
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 |