diff options
author | Karl Berry <karl@freefriends.org> | 2018-03-07 21:50:56 +0000 |
---|---|---|
committer | Karl Berry <karl@freefriends.org> | 2018-03-07 21:50:56 +0000 |
commit | f11f49763fc33ac8427d8c175d98a8d1275e4c5c (patch) | |
tree | 79aacd4b6ab168db69112977f42c2c99204e1621 /Master/texmf-dist/source/latex/l3experimental/l3draw | |
parent | fb72b3560bdc8a98d78bf919da56c3316fa7723d (diff) |
l3 (6mar18)
git-svn-id: svn://tug.org/texlive/trunk@46875 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/source/latex/l3experimental/l3draw')
9 files changed, 1646 insertions, 328 deletions
diff --git a/Master/texmf-dist/source/latex/l3experimental/l3draw/l3draw-boxes.dtx b/Master/texmf-dist/source/latex/l3experimental/l3draw/l3draw-boxes.dtx new file mode 100644 index 00000000000..0cfd7239da9 --- /dev/null +++ b/Master/texmf-dist/source/latex/l3experimental/l3draw/l3draw-boxes.dtx @@ -0,0 +1,153 @@ +% \iffalse meta-comment +% +%% File: l3draw-boxes.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\\ Boxes in drawings^^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/03/05} +% +% \maketitle +% +% \begin{implementation} +% +% \section{\pkg{l3draw-boxes} implementation} +% +% \begin{macrocode} +%<*initex|package> +% \end{macrocode} +% +% \begin{macrocode} +%<@@=draw> +% \end{macrocode} +% +% Inserting boxes requires us to \enquote{interrupt} the drawing state, +% so is closely linked to scoping. At the same time, there are a few +% additional features required to make text work in a flexible way. +% +% \begin{variable}{\l_@@_tmp_box} +% \begin{macrocode} +\box_new:N \l_@@_tmp_box +% \end{macrocode} +% \end{variable} +% +% \begin{macro}{\draw_box_use:N} +% \begin{macro}{\@@_box_use:Nnnnn} +% Before inserting a box, we need to make sure that the bounding box is being +% updated correctly. As drawings track transformations as a whole, rather +% than as separate operations, we do the insertion using an almost-raw +% matrix. The process is split into two so that coffins are also supported. +% \begin{macrocode} +\cs_new_protected:Npn \draw_box_use:N #1 + { + \@@_box_use:Nnnnn #1 + { 0pt } { -\box_dp:N #1 } { \box_wd:N #1 } { \box_ht:N #1 } + } +\cs_new_protected:Npn \@@_box_use:Nnnnn #1#2#3#4#5 + { + \bool_if:NT \l_draw_bb_update_bool + { + \@@_point_process:nn + { \@@_path_update_limits:nn } + { \draw_point_transform:n { #2 , #3 } } + \@@_point_process:nn + { \@@_path_update_limits:nn } + { \draw_point_transform:n { #4 , #3 } } + \@@_point_process:nn + { \@@_path_update_limits:nn } + { \draw_point_transform:n { #4 , #5 } } + \@@_point_process:nn + { \@@_path_update_limits:nn } + { \draw_point_transform:n { #2 , #5 } } + } + \group_begin: + \hbox_set:Nn \l_@@_tmp_box + { + \use:x + { + \driver_draw_box_use:Nnnnn #1 + { \fp_use:N \l_@@_matrix_a_fp } + { \fp_use:N \l_@@_matrix_b_fp } + { \fp_use:N \l_@@_matrix_c_fp } + { \fp_use:N \l_@@_matrix_d_fp } + } + } + \hbox_set:Nn \l_@@_tmp_box + { + \tex_kern:D \l_@@_xshift_dim + \box_move_up:nn { \l_@@_yshift_dim } + { \box_use_drop:N \l_@@_tmp_box } + } + \box_set_ht:Nn \l_@@_tmp_box { 0pt } + \box_set_dp:Nn \l_@@_tmp_box { 0pt } + \box_set_wd:Nn \l_@@_tmp_box { 0pt } + \box_use_drop:N \l_@@_tmp_box + \group_end: + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\draw_coffin_use:Nnn} +% Slightly more than a shortcut: we have to allow for the fact that coffins +% have no apparent width before the reference point. +% \begin{macrocode} +\cs_new_protected:Npn \draw_coffin_use:Nnn #1#2#3 + { + \group_begin: + \hbox_set:Nn \l_@@_tmp_box + { \coffin_typeset:Nnnnn #1 {#2} {#3} { 0pt } { 0pt } } + \@@_box_use:Nnnnn \l_@@_tmp_box + { \box_wd:N \l_@@_tmp_box - \coffin_wd:N #1 } + { -\box_dp:N \l_@@_tmp_box } + { \box_wd:N \l_@@_tmp_box } + { \box_ht:N \l_@@_tmp_box } + \group_end: + } +% \end{macrocode} +% \end{macro} +% +% \begin{macrocode} +%</initex|package> +% \end{macrocode} +% +% \end{implementation} +% +% \PrintIndex diff --git a/Master/texmf-dist/source/latex/l3experimental/l3draw/l3draw-paths.dtx b/Master/texmf-dist/source/latex/l3experimental/l3draw/l3draw-paths.dtx index 2fa882e7f1a..09df8391d17 100644 --- a/Master/texmf-dist/source/latex/l3experimental/l3draw/l3draw-paths.dtx +++ b/Master/texmf-dist/source/latex/l3experimental/l3draw/l3draw-paths.dtx @@ -42,7 +42,7 @@ % }^^A % } % -% \date{Released 2018/02/21} +% \date{Released 2018/03/05} % % \maketitle % @@ -128,7 +128,7 @@ { \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 + \bool_if:NT \l_draw_bb_update_bool { \dim_gset:Nn \g_@@_xmax_dim { \dim_max:nn \g_@@_xmax_dim {#1} } @@ -185,15 +185,10 @@ % \end{macrocode} % \end{variable} % -% \begin{macro}{\draw_path_corner_arc:n} -% \begin{macro}{\@@_path_corner_arc:nn} +% \begin{macro}{\draw_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 +\cs_new_protected:Npn \draw_path_corner_arc:nn #1#2 { \dim_set:Nn \l_@@_corner_xarc_dim {#1} \dim_set:Nn \l_@@_corner_yarc_dim {#2} @@ -205,7 +200,6 @@ } % \end{macrocode} % \end{macro} -% \end{macro} % % \begin{macro}{\@@_path_mark_corner:} % Mark up corners for arc post-processing. @@ -295,6 +289,33 @@ % \end{macrocode} % \end{macro} % +% \subsection{Canvas path constructions} +% +% \begin{macro}{\draw_path_canvas_moveto:n, \draw_path_canvas_lineto:n} +% \begin{macro}{\draw_path_canvas_curveto:nnn} +% Operations with no application of the transformation matrix. +% \begin{macrocode} +\cs_new_protected:Npn \draw_path_canvas_moveto:n #1 + { \@@_point_process:nn { \@@_path_moveto:nn } {#1} } +\cs_new_protected:Npn \draw_path_canvas_lineto:n #1 + { \@@_point_process:nn { \@@_path_lineto:nn } {#1} } +\cs_new_protected:Npn \draw_path_canvas_curveto:nnn #1#2#3 + { + \@@_point_process:nnn + { + \@@_point_process:nn + { + \@@_path_mark_corner: + \@@_path_curveto:nnnnnn + } + {#1} + } + {#2} {#3} + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% % \subsection{Computed curves} % % More complex operations need some calculations. To assist with those, various @@ -690,7 +711,9 @@ { \@@_point_process:nnn { - \bool_if:NTF \l_@@_corner_arc_bool + \bool_lazy_or:nnTF + { \l_@@_corner_arc_bool } + { \l_@@_matrix_active_bool } { \@@_path_rectangle_rounded:nnnn } { \@@_path_rectangle:nnnn } } @@ -736,33 +759,71 @@ % \subsection{Grids} % % \begin{macro}{\draw_path_grid:nnnn} -% \begin{macro}{\@@_path_grid:nnnnnn} -% A simple set of loops. +% \begin{macro} +% { +% \@@_path_grid_auxi:nnnnnn, \@@_path_grid_auxi:ffnnnn, +% \@@_path_grid_auxii:nnnnnn, +% \@@_path_grid_auxiii:nnnnnn, \@@_path_grid_auxiiii:ffnnnn +% } +% \begin{macro} +% {\@@_path_grid_auxiv:nnnnnnnn, \@@_path_grid_auxiv:ffnnnnnn} +% The main complexity here is lining up the grid correctly. +% To keep it simple, we tidy up the argument ordering first. % \begin{macrocode} \cs_new_protected:Npn \draw_path_grid:nnnn #1#2#3#4 { \@@_point_process:nnn - { \@@_path_grid:nnnnnn {#1} {#2} } + { + \@@_path_grid_auxi:ffnnnn + { \dim_eval:n { \dim_abs:n {#1} } } + { \dim_eval:n { \dim_abs:n {#2} } } + } {#3} {#4} } -\cs_new_protected:Npn \@@_path_grid:nnnnnn #1#2#3#4#5#6 +\cs_new_protected:Npn \@@_path_grid_auxi:nnnnnn #1#2#3#4#5#6 + { + \dim_compare:nNnTF {#3} > {#5} + { \@@_path_grid_auxii:nnnnnn {#1} {#2} {#5} {#4} {#3} {#6} } + { \@@_path_grid_auxii:nnnnnn {#1} {#2} {#3} {#4} {#5} {#6} } + } +\cs_generate_variant:Nn \@@_path_grid_auxi:nnnnnn { ff } +\cs_new_protected:Npn \@@_path_grid_auxii:nnnnnn #1#2#3#4#5#6 + { + \dim_compare:nNnTF {#4} > {#6} + { \@@_path_grid_auxiii:nnnnnn {#1} {#2} {#3} {#6} {#5} {#4} } + { \@@_path_grid_auxiii:nnnnnn {#1} {#2} {#3} {#4} {#5} {#6} } + } +\cs_new_protected:Npn \@@_path_grid_auxiii:nnnnnn #1#2#3#4#5#6 + { + \@@_path_grid_auxiv:ffnnnnnn + { \fp_to_dim:n { #1 * trunc(#3/(#1)) } } + { \fp_to_dim:n { #2 * trunc(#4/(#2)) } } + {#1} {#2} {#3} {#4} {#5} {#6} + } +\cs_new_protected:Npn \@@_path_grid_auxiv:nnnnnnnn #1#2#3#4#5#6#7#8 { \dim_step_inline:nnnn - {#3} { \dim_compare:nNnF {#3} < {#5} { - } \dim_abs:n {#1} } {#5} + {#1} + {#3} + {#7} { - \draw_path_moveto:n { ##1 , #4 } - \draw_path_lineto:n { ##1 , #6 } + \draw_path_moveto:n { ##1 , #6 } + \draw_path_lineto:n { ##1 , #8 } } \dim_step_inline:nnnn - {#4} { \dim_compare:nNnF {#4} < {#6} { - } \dim_abs:n {#2} } {#6} + {#2} + {#4} + {#8} { - \draw_path_moveto:n { #3 , ##1 } - \draw_path_lineto:n { #5 , ##1 } + \draw_path_moveto:n { #5 , ##1 } + \draw_path_lineto:n { #7 , ##1 } } } +\cs_generate_variant:Nn \@@_path_grid_auxiv:nnnnnnnn { ff } % \end{macrocode} % \end{macro} % \end{macro} +% \end{macro} % % \subsection{Using paths} % @@ -790,7 +851,7 @@ % % \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_action_draw:, \@@_path_use_action_fillstroke:} % \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 @@ -833,8 +894,9 @@ { \ERROR } } } + \@@_softpath_round_corners: \bool_lazy_and:nnT - { \l_@@_update_bb_bool } + { \l_draw_bb_update_bool } { \l_@@_path_use_stroke_bool } { \@@_path_use_stroke_bb: } \bool_if:NTF \l_@@_path_use_clear_bool @@ -859,6 +921,11 @@ { \bool_set_true:N \l_@@_path_use_stroke_bool } +\cs_new_protected:Npn \@@_path_use_action_fillstroke: + { + \bool_set_true:N \l_@@_path_use_fill_bool + \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. @@ -892,6 +959,75 @@ % \end{macro} % \end{macro} % +% \subsection{Scoping paths} +% +% \begin{variable} +% { +% \l_@@_path_lastx_dim, \l_@@_path_lasty_dim, +% \l_@@_path_xmax_dim, \l_@@_path_xmin_dim, +% \l_@@_path_ymax_dim, \l_@@_path_ymin_dim +% } +% \begin{variable}{\l_@@_softpath_corners_bool} +% Local storage for global data. There is already a +% \cs{l_@@_softpath_main_tl} for path manipulation, so we can reuse that +% (it is always grouped when the path is being reconstructed). +% \begin{macrocode} +\dim_new:N \l_@@_path_lastx_dim +\dim_new:N \l_@@_path_lasty_dim +\dim_new:N \l_@@_path_xmax_dim +\dim_new:N \l_@@_path_xmin_dim +\dim_new:N \l_@@_path_ymax_dim +\dim_new:N \l_@@_path_ymin_dim +\dim_new:N \l_@@_softpath_lastx_dim +\dim_new:N \l_@@_softpath_lasty_dim +\bool_new:N \l_@@_softpath_corners_bool +% \end{macrocode} +% \end{variable} +% \end{variable} +% +% \begin{macro}{\draw_path_scope_begin:, \draw_path_scope_end:} +% Scoping a path is a bit more involved, largely as there are a number +% of variables to keep hold of. +% \begin{macrocode} +\cs_new_protected:Npn \draw_path_scope_begin: + { + \group_begin: + \dim_set_eq:NN \l_@@_path_lastx_dim \g_@@_path_lastx_dim + \dim_set_eq:NN \l_@@_path_lasty_dim \g_@@_path_lasty_dim + \dim_set_eq:NN \l_@@_path_xmax_dim \g_@@_path_xmax_dim + \dim_set_eq:NN \l_@@_path_xmin_dim \g_@@_path_xmin_dim + \dim_set_eq:NN \l_@@_path_ymax_dim \g_@@_path_ymax_dim + \dim_set_eq:NN \l_@@_path_ymin_dim \g_@@_path_ymin_dim + \dim_set_eq:NN \l_@@_softpath_lastx_dim \g_@@_softpath_lastx_dim + \dim_set_eq:NN \l_@@_softpath_lasty_dim \g_@@_softpath_lasty_dim + \@@_path_reset_limits: + \@@_softpath_concat:n { } + \tl_set_eq:NN \l_@@_softpath_main_tl \g_@@_softpath_main_tl + \bool_set_eq:NN + \l_@@_softpath_corners_bool + \g_@@_softpath_corners_bool + \@@_softpath_clear: + } +\cs_new_protected:Npn \draw_path_scope_end: + { + \bool_gset_eq:NN + \g_@@_softpath_corners_bool + \l_@@_softpath_corners_bool + \@@_softpath_clear: + \tl_gset_eq:NN \g_@@_softpath_main_tl \l_@@_softpath_main_tl + \dim_gset_eq:NN \g_@@_softpath_lastx_dim \l_@@_softpath_lastx_dim + \dim_gset_eq:NN \g_@@_softpath_lasty_dim \l_@@_softpath_lasty_dim + \dim_gset_eq:NN \g_@@_path_xmax_dim \l_@@_path_xmax_dim + \dim_gset_eq:NN \g_@@_path_xmin_dim \l_@@_path_xmin_dim + \dim_gset_eq:NN \g_@@_path_ymax_dim \l_@@_path_ymax_dim + \dim_gset_eq:NN \g_@@_path_ymin_dim \l_@@_path_ymin_dim + \dim_gset_eq:NN \g_@@_path_lastx_dim \l_@@_path_lastx_dim + \dim_gset_eq:NN \g_@@_path_lasty_dim \l_@@_path_lasty_dim + \group_end: + } +% \end{macrocode} +% \end{macro} +% % \begin{macrocode} %</initex|package> % \end{macrocode} diff --git a/Master/texmf-dist/source/latex/l3experimental/l3draw/l3draw-points.dtx b/Master/texmf-dist/source/latex/l3experimental/l3draw/l3draw-points.dtx index 01497992889..69ca8b6ae73 100644 --- a/Master/texmf-dist/source/latex/l3experimental/l3draw/l3draw-points.dtx +++ b/Master/texmf-dist/source/latex/l3experimental/l3draw/l3draw-points.dtx @@ -42,7 +42,7 @@ % }^^A % } % -% \date{Released 2018/02/21} +% \date{Released 2018/03/05} % % \maketitle % @@ -485,39 +485,31 @@ % \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, +% \@@_point_interpolate_distance:nnnnnn, +% \@@_point_interpolate_distance:fnnnnn, % } % Same idea but using the normalised length to obtain the scale factor. +% The start point is needed twice, so we force evaluation, but the end +% point is needed only the once. % \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} + \@@_point_process:nn + { \@@_point_interpolate_distance:nnnn {#1} {#3} } + {#2} } -\cs_new:Npn \@@_point_interpolate_distance_aux:nnnnnnn #1#2#3#4#5#6#7 +\cs_new:Npn \@@_point_interpolate_distance:nnnn #1#2#3#4 { - \@@_point_interpolate_distance_aux:fnnnn - { \fp_eval:n { (#7) / (sqrt ( #1 * #1 + #2 * #2 )) } } - {#3} {#4} {#5} {#6} + \@@_point_process:nn + { + \@@_point_interpolate_distance:fnnnn + { \fp_eval:n {#1} } {#3} {#4} + } + { \draw_point_unit_vector:n { ( #2 ) - ( #3 , #4 ) } } } -\cs_generate_variant:Nn \@@_point_interpolate_distance_aux:nnnnnnn { ff } -\cs_new:Npn \@@_point_interpolate_distance_aux:nnnnn #1#2#3#4#5 +\cs_new:Npn \@@_point_interpolate_distance: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 } +\cs_generate_variant:Nn \@@_point_interpolate_distance:nnnnn { f } % \end{macrocode} % \end{macro} % \end{macro} @@ -605,7 +597,6 @@ % \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} @@ -889,20 +880,20 @@ } \cs_new:Npn \@@_point_transform:nn #1#2 { - \bool_if:NTF \l_@@_transformcm_active_bool + \bool_if:NTF \l_@@_matrix_active_bool { \@@_point_to_dim:n { ( - \l_@@_transformcm_aa_fp * #1 - + \l_@@_transformcm_ba_fp * #2 - + \l_@@_transformcm_xshift_dim + \l_@@_matrix_a_fp * #1 + + \l_@@_matrix_c_fp * #2 + + \l_@@_xshift_dim ) , ( - \l_@@_transformcm_ab_fp * #1 - + \l_@@_transformcm_bb_fp * #2 - + \l_@@_transformcm_yshift_dim + \l_@@_matrix_b_fp * #1 + + \l_@@_matrix_d_fp * #2 + + \l_@@_yshift_dim ) } } @@ -910,8 +901,7 @@ \@@_point_to_dim:n { (#1, #2) - + ( \l_@@_transformcm_xshift_dim , - \l_@@_transformcm_yshift_dim ) + + ( \l_@@_xshift_dim , \l_@@_yshift_dim ) } } } @@ -930,18 +920,18 @@ } \cs_new:Npn \@@_point_transform_noshift:nn #1#2 { - \bool_if:NTF \l_@@_transformcm_active_bool + \bool_if:NTF \l_@@_matrix_active_bool { \@@_point_to_dim:n { ( - \l_@@_transformcm_aa_fp * #1 - + \l_@@_transformcm_ba_fp * #2 + \l_@@_matrix_a_fp * #1 + + \l_@@_matrix_c_fp * #2 ) , ( - \l_@@_transformcm_ab_fp * #1 - + \l_@@_transformcm_bb_fp * #2 + \l_@@_matrix_b_fp * #1 + + \l_@@_matrix_d_fp * #2 ) } } diff --git a/Master/texmf-dist/source/latex/l3experimental/l3draw/l3draw-scopes.dtx b/Master/texmf-dist/source/latex/l3experimental/l3draw/l3draw-scopes.dtx index b87a6a152b7..451226ccdef 100644 --- a/Master/texmf-dist/source/latex/l3experimental/l3draw/l3draw-scopes.dtx +++ b/Master/texmf-dist/source/latex/l3experimental/l3draw/l3draw-scopes.dtx @@ -42,7 +42,7 @@ % }^^A % } % -% \date{Released 2018/02/21} +% \date{Released 2018/03/05} % % \maketitle % @@ -72,11 +72,11 @@ % \end{macrocode} % \end{variable} % -% \begin{variable}{\l_@@_update_bb_bool} +% \begin{variable}{\l_draw_bb_update_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 +\bool_new:N \l_draw_bb_update_bool % \end{macrocode} % \end{variable} % @@ -87,47 +87,161 @@ % \end{macrocode} % \end{variable} % +% \begin{variable}{\g_@@_id_int} +% The drawing number. +% \begin{macrocode} +\int_new:N \g_@@_id_int +% \end{macrocode} +% \end{variable} +% +% \begin{macro}{\@@_reset_bb:} +% A simple auxiliary. +% \begin{macrocode} +\cs_new_protected:Npn \@@_reset_bb: + { + \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 } + } +% \end{macrocode} +% \end{macro} +% % \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.) +% before inserting into the surroundings. Color is set here using the drawing +% mechanism largely as it then sets up the internal data structures. It may be +% that a coffin construct is better here in the longer term: that may become +% clearer as the code is completed. As we need to avoid any insertion of +% baseline skips, the outer box here has to be an |hbox|. % \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 } + \group_begin: + \int_gincr:N \g_@@_id_int + \hbox_set:Nw \l_@@_main_box + \driver_draw_begin: + \@@_reset_bb: + \@@_path_reset_limits: + \bool_set_true:N \l_draw_bb_update_bool + \draw_transform_matrix_reset: + \draw_transform_shift_reset: + \@@_softpath_clear: + \draw_linewidth:n { \l_draw_default_linewidth_dim } + \draw_color:n { . } } \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 + \driver_draw_end: + \hbox_set_end: + \dim_compare:nNnT \g_@@_xmin_dim = \c_max_dim + { + \dim_gzero:N \g_@@_xmax_dim + \dim_gzero:N \g_@@_xmin_dim + \dim_gzero:N \g_@@_ymax_dim + \dim_gzero:N \g_@@_ymin_dim + } + \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 + \group_end: + } +% \end{macrocode} +% \end{macro} +% +% \subsection{Scopes} +% +% \begin{variable}{\l_@@_linewidth_dim} +% \begin{variable}{\l_@@_fill_color_tl, \l_@@_stroke_color_tl} +% Storage for local variables. +% \begin{macrocode} +\dim_new:N \l_@@_linewidth_dim +\tl_new:N \l_@@_fill_color_tl +\tl_new:N \l_@@_stroke_color_tl +% \end{macrocode} +% \end{variable} +% \end{variable} +% +% \begin{macro}{\draw_scope_begin:, \draw_scope_begin:} +% As well as the graphics (and \TeX{}) scope, also deal with global +% data structures. +% \begin{macrocode} +\cs_new_protected:Npn \draw_scope_begin: + { + \driver_draw_scope_begin: + \group_begin: + \dim_set_eq:NN \l_@@_linewidth_dim \g_@@_linewidth_dim + \draw_path_scope_begin: + } +\cs_new_protected:Npn \draw_scope_end: + { + \draw_path_scope_end: + \dim_gset_eq:NN \g_@@_linewidth_dim \l_@@_linewidth_dim + \group_end: + \driver_draw_scope_end: + } +% \end{macrocode} +% \end{macro} +% +% \begin{variable} +% {\l_@@_xmax_dim, \l_@@_xmin_dim, \l_@@_ymax_dim, \l_@@_ymin_dim} +% Storage for the bounding box. +% \begin{macrocode} +\dim_new:N \l_@@_xmax_dim +\dim_new:N \l_@@_xmin_dim +\dim_new:N \l_@@_ymax_dim +\dim_new:N \l_@@_ymin_dim +% \end{macrocode} +% \end{variable} +% +% \begin{macro}{\@@_scope_bb_begin:, \@@_scope_bb_end:} +% The bounding box is simple: a straight group-based save and restore +% approach. +% \begin{macrocode} +\cs_new_protected:Npn \@@_scope_bb_begin: + { + \group_begin: + \dim_set_eq:NN \l_@@_xmax_dim \g_@@_xmax_dim + \dim_set_eq:NN \l_@@_xmin_dim \g_@@_xmin_dim + \dim_set_eq:NN \l_@@_ymax_dim \g_@@_ymax_dim + \dim_set_eq:NN \l_@@_ymin_dim \g_@@_ymin_dim + \@@_reset_bb: + } +\cs_new_protected:Npn \@@_scope_bb_end: + { + \dim_gset_eq:NN \g_@@_xmax_dim \l_@@_xmax_dim + \dim_gset_eq:NN \g_@@_xmin_dim \l_@@_xmin_dim + \dim_gset_eq:NN \g_@@_ymax_dim \l_@@_ymax_dim + \dim_gset_eq:NN \g_@@_ymin_dim \l_@@_ymin_dim + \group_end: + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\draw_suspend_begin:, \draw_suspend_end:} +% Suspend all parts of a drawing. +% \begin{macrocode} +\cs_new_protected:Npn \draw_suspend_begin: + { + \@@_scope_bb_begin: + \draw_path_scope_begin: + \draw_transform_matrix_reset: + \draw_transform_shift_reset: + } +\cs_new_protected:Npn \draw_suspend_end: + { + \draw_path_scope_end: + \@@_scope_bb_end: } % \end{macrocode} % \end{macro} diff --git a/Master/texmf-dist/source/latex/l3experimental/l3draw/l3draw-softpath.dtx b/Master/texmf-dist/source/latex/l3experimental/l3draw/l3draw-softpath.dtx index f10d7928082..f98083584bd 100644 --- a/Master/texmf-dist/source/latex/l3experimental/l3draw/l3draw-softpath.dtx +++ b/Master/texmf-dist/source/latex/l3experimental/l3draw/l3draw-softpath.dtx @@ -42,7 +42,7 @@ % }^^A % } % -% \date{Released 2018/02/21} +% \date{Released 2018/03/05} % % \maketitle % @@ -58,6 +58,8 @@ %<@@=draw> % \end{macrocode} % +% \subsection{Managing soft paths} +% % 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 @@ -100,6 +102,13 @@ % \end{macrocode} % \end{variable} % +% \begin{variable}{\g_@@_softpath_corners_bool} +% Allow for optimised path use. +% \begin{macrocode} +\bool_new:N \g_@@_softpath_corners_bool +% \end{macrocode} +% \end{variable} +% % \begin{macro}{\@@_softpath_add:n, \@@_softpath_add:x} % \begin{macro}{\@@_softpath_concat:n} % \begin{macro}{\@@_softpath_reset_buffers:} @@ -155,22 +164,6 @@ % \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. @@ -186,6 +179,7 @@ \tl_gclear:N \g_@@_softpath_main_tl \tl_gclear:N \g_@@_softpath_buffer_a_tl \tl_gclear:N \g_@@_softpath_buffer_b_tl + \bool_gset_false:N \g_@@_softpath_corners_bool } \cs_new_protected:Npn \@@_softpath_use_clear: { @@ -267,6 +261,7 @@ { \@@_softpath_add:n { \@@_softpath_roundpoint_op:nn {#1} {#2} } + \bool_gset_true:N \g_@@_softpath_corners_bool } \cs_generate_variant:Nn \@@_softpath_roundpoint:nn { VV } % \end{macrocode} @@ -290,6 +285,8 @@ % \begin{macro}{\@@_softpath_curveto_opi:nnNnnNnn} % \begin{macro}{\@@_softpath_rectangle_opi:nnNnn} % The markers for operations: all the top-level ones take two arguments. +% The support tokens for curves have to be different in meaning to a +% round point, hence being quark-like. % \begin{macrocode} \cs_new_protected:Npn \@@_softpath_close_op:nn #1#2 { \driver_draw_closepath: } @@ -297,8 +294,10 @@ { \@@_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_curveto_opii:nn #1#2 + { \@@_softpath_curveto_opii:nn } +\cs_new_protected:Npn \@@_softpath_curveto_opiii:nn #1#2 + { \@@_softpath_curveto_opiii:nn } \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 @@ -314,6 +313,364 @@ % \end{macro} % \end{macro} % +% \subsection{Rounding soft path corners} +% +% The aim here is to find corner rounding points and to replace them with +% arcs of appropriate length. The approach is exactly that in \pkg{pgf}: +% step through, find the corners, find the supporting data, do the rounding. +% +% \begin{variable}{\l_@@_softpath_main_tl} +% For constructing the updated path. +% \begin{macrocode} +\tl_new:N \l_@@_softpath_main_tl +% \end{macrocode} +% \end{variable} +% +% \begin{variable}{\l_@@_softpath_part_tl} +% Data structures. +% \begin{macrocode} +\tl_new:N \l_@@_softpath_part_tl +\tl_new:N \l_@@_softpath_curve_end_tl +% \end{macrocode} +% \end{variable} +% +% \begin{variable} +% {\l_@@_softpath_lastx_fp, \l_@@_softpath_lasty_fp} +% \begin{variable} +% {\l_@@_softpath_corneri_dim, \l_@@_softpath_cornerii_dim} +% \begin{variable}{\l_@@_softpath_first_tl, \l_@@_softpath_move_tl} +% Position tracking: the token list data may be entirely empty or set to +% a co-ordinate. +% \begin{macrocode} +\fp_new:N \l_@@_softpath_lastx_fp +\fp_new:N \l_@@_softpath_lasty_fp +\dim_new:N \l_@@_softpath_corneri_dim +\dim_new:N \l_@@_softpath_cornerii_dim +\tl_new:N \l_@@_softpath_first_tl +\tl_new:N \l_@@_softpath_move_tl +% \end{macrocode} +% \end{variable} +% \end{variable} +% \end{variable} +% +% \begin{variable}{\c_@@_softpath_arc_fp} +% The magic constant. +% \begin{macrocode} +\fp_const:Nn \c_@@_softpath_arc_fp { 4/3 * (sqrt(2) - 1) } +% \end{macrocode} +% \end{variable} +% +% \begin{macro}{\@@_softpath_round_corners:} +% \begin{macro}{\@@_softpath_round_loop:Nnn} +% \begin{macro}{\@@_softpath_round_action:nn} +% \begin{macro}{\@@_softpath_round_action:Nnn} +% \begin{macro}{\@@_softpath_round_action_curveto:NnnNnn} +% \begin{macro}{\@@_softpath_round_action_close:} +% \begin{macro}{\@@_softpath_round_lookahead:NnnNnn} +% \begin{macro}{\@@_softpath_round_roundpoint:NnnNnnNnn} +% \begin{macro}{\@@_softpath_round_calc:nnnNnn} +% \begin{macro}[EXP] +% {\@@_softpath_round_calc:nnnnnn, \@@_softpath_round_calc:fVnnnn} +% \begin{macro}[EXP]{\@@_softpath_round_calc:nnnnw} +% \begin{macro}{\@@_softpath_round_close:nn} +% \begin{macro}[EXP]{\@@_softpath_round_close:w} +% \begin{macro}{\@@_softpath_round_end:} +% Rounding corners on a path means going through the entire path and +% adjusting it. As such, we avoid this entirely if we know there are no +% corners to deal with. Assuming there is work to do, we recover the existing +% path and start a loop. +% \begin{macrocode} +\cs_new_protected:Npn \@@_softpath_round_corners: + { + \bool_if:NT \g_@@_softpath_corners_bool + { + \group_begin: + \tl_clear:N \l_@@_softpath_main_tl + \tl_clear:N \l_@@_softpath_part_tl + \fp_zero:N \l_@@_softpath_lastx_fp + \fp_zero:N \l_@@_softpath_lasty_fp + \tl_clear:N \l_@@_softpath_first_tl + \tl_clear:N \l_@@_softpath_move_tl + \@@_softpath_concat:n { } + \exp_after:wN \@@_softpath_round_loop:Nnn + \g_@@_softpath_main_tl + \q_recursion_tail ? ? + \q_recursion_stop + \group_end: + } + \bool_gset_false:N \g_@@_softpath_corners_bool + } +% \end{macrocode} +% The loop can take advantage of the fact that all soft path operations are +% made up of a token followed by two arguments. At this stage, there is +% a simple split: have we round a round point. If so, is there any actual +% rounding to be done: if the arcs have come through zero, just ignore it. +% In cases where we are not at a corner, we simply move along the path, +% allowing for any new part starting due to a \texttt{moveto}. +% \begin{macrocode} +\cs_new_protected:Npn \@@_softpath_round_loop:Nnn #1#2#3 + { + \quark_if_recursion_tail_stop_do:Nn #1 { \@@_softpath_round_end: } + \token_if_eq_meaning:NNTF #1 \@@_softpath_roundpoint_op:nn + { \@@_softpath_round_action:nn {#2} {#3} } + { + \tl_if_empty:NT \l_@@_softpath_first_tl + { \tl_set:Nn \l_@@_softpath_first_tl { {#2} {#3} } } + \fp_set:Nn \l_@@_softpath_lastx_fp {#2} + \fp_set:Nn \l_@@_softpath_lasty_fp {#3} + \token_if_eq_meaning:NNTF #1 \@@_softpath_moveto_op:nn + { + \tl_put_right:No \l_@@_softpath_main_tl + \l_@@_softpath_move_tl + \tl_put_right:No \l_@@_softpath_main_tl + \l_@@_softpath_part_tl + \tl_set:Nn \l_@@_softpath_move_tl { #1 {#2} {#3} } + \tl_clear:N \l_@@_softpath_first_tl + \tl_clear:N \l_@@_softpath_part_tl + } + { \tl_put_right:Nn \l_@@_softpath_part_tl { #1 {#2} {#3} } } + \@@_softpath_round_loop:Nnn + } + } +\cs_new_protected:Npn \@@_softpath_round_action:nn #1#2 + { + \dim_set:Nn \l_@@_softpath_corneri_dim {#1} + \dim_set:Nn \l_@@_softpath_cornerii_dim {#2} + \bool_lazy_and:nnTF + { \dim_compare_p:nNn \l_@@_softpath_corneri_dim = { 0pt } } + { \dim_compare_p:nNn \l_@@_softpath_cornerii_dim = { 0pt } } + { \@@_softpath_round_loop:Nnn } + { \@@_softpath_round_action:Nnn } + } +% \end{macrocode} +% We now have a round point to work on and have grabbed the next item in +% the path. There are only a few cases where we have to do anything. Each of +% them is picked up by looking for the appropriate action. +% \begin{macrocode} +\cs_new_protected:Npn \@@_softpath_round_action:Nnn #1#2#3 + { + \tl_if_empty:NT \l_@@_softpath_first_tl + { \tl_set:Nn \l_@@_softpath_first_tl { {#2} {#3} } } + \token_if_eq_meaning:NNTF #1 \@@_softpath_curveto_opi:nn + { \@@_softpath_round_action_curveto:NnnNnn } + { + \token_if_eq_meaning:NNTF #1 \@@_softpath_close_op:nn + { \@@_softpath_round_action_close: } + { + \token_if_eq_meaning:NNTF #1 \@@_softpath_lineto_op:nn + { \@@_softpath_round_lookahead:NnnNnn } + { \@@_softpath_round_loop:Nnn } + } + } + #1 {#2} {#3} + } +% \end{macrocode} +% For a curve, we collect the two control points then move on to grab the +% end point and add the curve there: the second control point becomes our +% starter. +% \begin{macrocode} +\cs_new_protected:Npn \@@_softpath_round_action_curveto:NnnNnn + #1#2#3#4#5#6 + { + \tl_put_right:Nn \l_@@_softpath_part_tl + { #1 {#2} {#3} #4 {#5} {#6} } + \fp_set:Nn \l_@@_softpath_lastx_fp {#5} + \fp_set:Nn \l_@@_softpath_lasty_fp {#6} + \@@_softpath_round_lookahead:NnnNnn + } +\cs_new_protected:Npn \@@_softpath_round_action_close: + { + \bool_lazy_and:nnTF + { ! \tl_if_empty_p:N \l_@@_softpath_first_tl } + { ! \tl_if_empty_p:N \l_@@_softpath_move_tl } + { + \exp_after:wN \@@_softpath_round_close:nn + \l_@@_softpath_first_tl + } + { \@@_softpath_round_loop:Nnn } + } +% \end{macrocode} +% At this stage we have a current (sub)operation (|#1|) and the next +% operation (|#4|), and can therefore decide whether to round or not. +% In the case of yet another rounding marker, we have to look a bit +% further ahead. +% \begin{macrocode} +\cs_new_protected:Npn \@@_softpath_round_lookahead:NnnNnn #1#2#3#4#5#6 + { + \bool_lazy_any:nTF + { + { \token_if_eq_meaning_p:NN #4 \@@_softpath_lineto_op:nn } + { \token_if_eq_meaning_p:NN #4 \@@_softpath_curveto_opi:nn } + { \token_if_eq_meaning_p:NN #4 \@@_softpath_close_op:nn } + } + { + \@@_softpath_round_calc:nnnNnn + \@@_softpath_round_loop:Nnn {#5} {#6} + } + { + \token_if_eq_meaning:NNTF #4 \@@_softpath_roundpoint_op:nn + { \@@_softpath_round_roundpoint:NnnNnnNnn } + { \@@_softpath_round_loop:Nnn } + } + #1 {#2} {#3} + #4 {#5} {#6} + } +\cs_new_protected:Npn \@@_softpath_round_roundpoint:NnnNnnNnn + #1#2#3#4#5#6#7#8#9 + { + \@@_softpath_round_calc:nnnNnn + \@@_softpath_round_loop:Nnn + {#8} {#9} #1 {#2} {#3} + #4 {#5} {#6} #7 {#8} {#9} + } +% \end{macrocode} +% We now have all of the data needed to construct a rounded corner: all that +% is left to do is to work out the detail! At this stage, we have details +% of where the corner itself is (|#4|, |#5|), and where the next point is +% (|#1|, |#2|). There are two types of calculations to do. First, we +% need to interpolate from those two points in the direction of the +% corner, in order to work out where the curve we are adding will start +% and end. From those, plus the points we already have, we work out where +% the control points will lie. All of this is done in an expansion to +% avoid multiple calls to |\tl_put_right:Nx|. The end point of the line +% is worked out up-front and saved: we need that if dealing with a +% close-path operation. +% \begin{macrocode} +\cs_new_protected:Npn \@@_softpath_round_calc:nnnNnn #1#2#3#4#5#6 + { + \tl_set:Nx \l_@@_softpath_curve_end_tl + { + \draw_point_interpolate_distance:nnn + \l_@@_softpath_cornerii_dim + { #5 , #6 } { #2 , #3 } + } + \tl_put_right:Nx \l_@@_softpath_part_tl + { + \exp_not:N #4 + \@@_softpath_round_calc:fVnnnn + { + \draw_point_interpolate_distance:nnn + \l_@@_softpath_corneri_dim + { #5 , #6 } + { + \l_@@_softpath_lastx_fp , + \l_@@_softpath_lasty_fp + } + } + \l_@@_softpath_curve_end_tl + {#5} {#6} {#2} {#3} + } + \fp_set:Nn \l_@@_softpath_lastx_fp {#5} + \fp_set:Nn \l_@@_softpath_lasty_fp {#6} + #1 + } +% \end{macrocode} +% At this stage we have the two curve end points, but they are in +% co-ordinate form. So we split them up (with some more reordering). +% \begin{macrocode} +\cs_new:Npn \@@_softpath_round_calc:nnnnnn #1#2#3#4#5#6 + { + \@@_softpath_round_calc:nnnnw {#3} {#4} {#5} {#6} + #1 \q_mark #2 \q_stop + } +\cs_generate_variant:Nn \@@_softpath_round_calc:nnnnnn { fV } +% \end{macrocode} +% The calculations themselves are relatively straight-forward, as we use a +% quadratic Bézier curve. +% \begin{macrocode} +\cs_new:Npn \@@_softpath_round_calc:nnnnw + #1#2#3#4 #5 , #6 \q_mark #7 , #8 \q_stop + { + {#5} {#6} + \exp_not:N \@@_softpath_curveto_opi:nn + { + \fp_to_dim:n + { #5 + \c_@@_softpath_arc_fp * ( #1 - #5 ) } + } + { + \fp_to_dim:n + { #6 + \c_@@_softpath_arc_fp * ( #2 - #6 ) } + } + \exp_not:N \@@_softpath_curveto_opii:nn + { + \fp_to_dim:n + { #7 + \c_@@_softpath_arc_fp * ( #1 - #7 ) } + } + { + \fp_to_dim:n + { #8 + \c_@@_softpath_arc_fp* ( #2 - #8 ) } + } + \exp_not:N \@@_softpath_curveto_opiii:nn + {#7} {#8} + } +% \end{macrocode} +% To deal with a close-path operation, we need to do some manipulation. +% It needs to be treated as a line operation for rounding, and then +% have the close path operation re-added at the point where the curve +% ends. That means saving the end point in the calculation step (see +% earlier), and shuffling a lot. +% \begin{macrocode} +\cs_new_protected:Npn \@@_softpath_round_close:nn #1#2 + { + \use:x + { + \@@_softpath_round_calc:nnnNnn + { + \tl_set:Nx \exp_not:N \l_@@_softpath_move_tl + { + \@@_softpath_moveto_op:nn + \exp_not:N \exp_after:wN + \exp_not:N \@@_softpath_round_close:w + \exp_not:N \l_@@_softpath_curve_end_tl + \exp_not:N \q_stop + } + \use:x + { + \exp_not:N \exp_not:N \exp_not:N \use_i:nnnn + { + \@@_softpath_round_loop:Nnn + \@@_softpath_close_op:nn + \exp_not:N \exp_after:wN + \exp_not:N \@@_softpath_round_close:w + \exp_not:N \l_@@_softpath_curve_end_tl + \exp_not:N \q_stop + } + } + } + {#1} {#2} + \@@_softpath_lineto_op:nn + \exp_after:wN \use_none:n \l_@@_softpath_move_tl + } + } +\cs_new:Npn \@@_softpath_round_close:w #1 , #2 \q_stop { {#1} {#2} } +% \end{macrocode} +% Tidy up the parts of the path, complete the built token list and put +% it back into action. +% \begin{macrocode} +\cs_new_protected:Npn \@@_softpath_round_end: + { + \tl_put_right:No \l_@@_softpath_main_tl + \l_@@_softpath_move_tl + \tl_put_right:No \l_@@_softpath_main_tl + \l_@@_softpath_part_tl + \tl_gset_eq:NN \g_@@_softpath_main_tl \l_@@_softpath_main_tl + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% % \begin{macrocode} %</initex|package> % \end{macrocode} diff --git a/Master/texmf-dist/source/latex/l3experimental/l3draw/l3draw-state.dtx b/Master/texmf-dist/source/latex/l3experimental/l3draw/l3draw-state.dtx index 5e6eb424d05..4c6bade4569 100644 --- a/Master/texmf-dist/source/latex/l3experimental/l3draw/l3draw-state.dtx +++ b/Master/texmf-dist/source/latex/l3experimental/l3draw/l3draw-state.dtx @@ -42,7 +42,7 @@ % }^^A % } % -% \date{Released 2018/02/21} +% \date{Released 2018/03/05} % % \maketitle % @@ -94,7 +94,7 @@ % 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} } } + { \driver_draw_miterlimit:n { \fp_eval:n {#1} } } % \end{macrocode} % \end{macro} % @@ -124,14 +124,6 @@ % \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} @@ -144,8 +136,7 @@ % 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_eq:NN \draw_color:n \color_select:n \cs_new_protected:Npn \draw_color_fill:n #1 { \@@_color:nn { fill } {#1} } \cs_new_protected:Npn \draw_color_stroke:n #1 @@ -153,16 +144,7 @@ \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 } - } + \@@_color_aux:Vn \l_@@_color_tmp_tl {#1} } \cs_new_protected:Npn \@@_color_aux:nn #1#2 { \@@_color:nw {#2} #1 \q_stop } @@ -170,13 +152,13 @@ \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} } + { \use:c { driver_draw_color_ #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} } + { \use:c { driver_draw_color_ #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} } + { \use:c { driver_draw_color_ #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} } + { \use:c { driver_draw_color_ #1 _spot:nn } {#2} {#3} } % \end{macrocode} % \end{macro} % \end{macro} diff --git a/Master/texmf-dist/source/latex/l3experimental/l3draw/l3draw-transforms.dtx b/Master/texmf-dist/source/latex/l3experimental/l3draw/l3draw-transforms.dtx index 4f325f01092..9b1478b48b7 100644 --- a/Master/texmf-dist/source/latex/l3experimental/l3draw/l3draw-transforms.dtx +++ b/Master/texmf-dist/source/latex/l3experimental/l3draw/l3draw-transforms.dtx @@ -42,7 +42,7 @@ % }^^A % } % -% \date{Released 2018/02/21} +% \date{Released 2018/03/05} % % \maketitle % @@ -58,149 +58,159 @@ %<@@=draw> % \end{macrocode} % -% \begin{variable}{\l_@@_transformcm_active_bool} +% This sub-module covers more-or-less the same ideas as +% \texttt{pgfcoretransformations.code.tex}. At present, equivalents of the +% following are currently absent: +% \begin{itemize} +% \item \cs{pgfgettransform}, \cs{pgfgettransformentries}: Awaiting use cases. +% \item \cs{pgftransformlineattime}, \cs{pgftransformarcaxesattime}, +% \cs{pgftransformcurveattime}: Need to look at the use cases for +% these to fully understand them. +% \item \cs{pgftransformarrow}: Likely to be done when other arrow functions +% are added. +% \item \cs{pgflowlevelsynccm}, \cs{pgflowlevel}: Likely to be added when +% use cases are encountered in other parts of the code. +% \end{itemize} +% +% \begin{variable}{\l_@@_matrix_active_bool} % An internal flag to avoid redundant calculations. % \begin{macrocode} -\bool_new:N \l_@@_transformcm_active_bool +\bool_new:N \l_@@_matrix_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 +% \l_@@_matrix_a_fp, +% \l_@@_matrix_b_fp, +% \l_@@_matrix_c_fp, +% \l_@@_matrix_a_fp, +% \l_@@_xshift_dim, +% \l_@@_yshift_dim % } -% The active matrix itself. +% The active matrix and shifts. % \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 +\fp_new:N \l_@@_matrix_a_fp +\fp_new:N \l_@@_matrix_b_fp +\fp_new:N \l_@@_matrix_c_fp +\fp_new:N \l_@@_matrix_d_fp +\dim_new:N \l_@@_xshift_dim +\dim_new:N \l_@@_yshift_dim % \end{macrocode} % \end{variable} % -% \begin{macro}{\draw_transform_reset:} +% \begin{macro}{\draw_transform_matrix_reset:, \draw_transform_shift_reset:} % Fast resetting. % \begin{macrocode} -\cs_new_protected:Npn \draw_transform_reset: +\cs_new_protected:Npn \draw_transform_matrix_reset: + { + \fp_set:Nn \l_@@_matrix_a_fp { 1 } + \fp_zero:N \l_@@_matrix_b_fp + \fp_zero:N \l_@@_matrix_c_fp + \fp_set:Nn \l_@@_matrix_d_fp { 1 } + } +\cs_new_protected:Npn \draw_transform_shift_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 + \dim_zero:N \l_@@_xshift_dim + \dim_zero:N \l_@@_yshift_dim } -\draw_transform_reset: +\draw_transform_matrix_reset: +\draw_transform_shift_reset: % \end{macrocode} % \end{macro} % -% \begin{macro}{\draw_transform:nnnnn} -% \begin{macro}{\@@_transform:nnnnnnn} +% \begin{macro}{\draw_transform_matrix:nnnn} +% \begin{macro}{\draw_transform_shift:n} +% \begin{macro}{\@@_transform_shift:nn} % 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 +\cs_new_protected:Npn \draw_transform_matrix:nnnn #1#2#3#4 { - \@@_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} + \fp_set:Nn \l_@@_matrix_a_fp {#1} + \fp_set:Nn \l_@@_matrix_b_fp {#2} + \fp_set:Nn \l_@@_matrix_c_fp {#3} + \fp_set:Nn \l_@@_matrix_d_fp {#4} \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 } + { \fp_compare_p:nNn \l_@@_matrix_a_fp = \c_one_fp } + { \fp_compare_p:nNn \l_@@_matrix_b_fp = \c_zero_fp } + { \fp_compare_p:nNn \l_@@_matrix_c_fp = \c_zero_fp } + { \fp_compare_p:nNn \l_@@_matrix_d_fp = \c_one_fp } } - { \bool_set_false:N \l_@@_transformcm_active_bool } - { \bool_set_true:N \l_@@_transformcm_active_bool } + { \bool_set_false:N \l_@@_matrix_active_bool } + { \bool_set_true:N \l_@@_matrix_active_bool } + } +\cs_new_protected:Npn \draw_transform_shift:n #1 + { + \@@_point_process:nn + { \@@_transform_shift:nn } {#1} + } +\cs_new_protected:Npn \@@_transform_shift:nn #1#2 + { + \dim_set:Nn \l_@@_xshift_dim {#1} + \dim_set:Nn \l_@@_yshift_dim {#2} } % \end{macrocode} % \end{macro} % \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{macro}{\draw_transform_matrix_concat:nnnn} +% \begin{macro}{\@@_transform_concat:nnnn} +% \begin{macro}{\draw_transform_shift_concat:n} +% \begin{macro}{\@@_transform_shift_concat:nn} +% Much the same story for adding to an existing matrix, with a bit of +% pre-expansion so that the calculation uses \enquote{frozen} values. % \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 +\cs_new_protected:Npn \draw_transform_matrix_concat:nnnn #1#2#3#4 { \use:x { - \@@_transform_concat_aux:nnnnnn + \@@_transform_concat:nnnn { \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 +\cs_new_protected:Npn \@@_transform_concat:nnnn #1#2#3#4 { \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 - } - } + \draw_transform_matrix:nnnn + { #1 * \l_@@_matrix_a_fp + #2 * \l_@@_matrix_c_fp } + { #1 * \l_@@_matrix_b_fp + #2 * \l_@@_matrix_d_fp } + { #3 * \l_@@_matrix_a_fp + #4 * \l_@@_matrix_c_fp } + { #3 * \l_@@_matrix_b_fp + #4 * \l_@@_matrix_d_fp } } } +\cs_new_protected:Npn \draw_transform_shift_concat:n #1 + { + \@@_point_process:nn + { \@@_transform_shift_concat:nn } {#1} + } +\cs_new_protected:Npn \@@_transform_shift_concat:nn #1#2 + { + \dim_set:Nn \l_@@_xshift_dim { \l_@@_xshift_dim + #1 } + \dim_set:Nn \l_@@_yshift_dim { \l_@@_yshift_dim + #2 } + } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} +% \end{macro} % -% \begin{macro}{\draw_transform_invert:} +% \begin{macro}{\draw_transform_matrix_invert:} % \begin{macro}{\@@_transform_invert:n, \@@_transform_invert:f} +% \begin{macro}{\draw_transform_shift_invert:} % Standard mathematics: calculate the inverse matrix and use that, then % undo the shifts. % \begin{macrocode} -\cs_new_protected:Npn \draw_transform_invert: +\cs_new_protected:Npn \draw_transform_matrix_invert: { - \bool_if:NT \l_@@_transformcm_active_bool + \bool_if:NT \l_@@_matrix_active_bool { \@@_transform_invert:f { @@ -208,44 +218,34 @@ { 1 / ( - \l_@@_transformcm_aa_fp * \l_@@_transformcm_bb_fp - - \l_@@_transformcm_ab_fp * \l_@@_transformcm_ba_fp + \l_@@_matrix_a_fp * \l_@@_matrix_d_fp + - \l_@@_matrix_b_fp * \l_@@_matrix_c_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 } + \fp_set:Nn \l_@@_matrix_a_fp + { \l_@@_matrix_d_fp * #1 } + \fp_set:Nn \l_@@_matrix_b_fp + { -\l_@@_matrix_b_fp * #1 } + \fp_set:Nn \l_@@_matrix_c_fp + { -\l_@@_matrix_c_fp * #1 } + \fp_set:Nn \l_@@_matrix_d_fp + { \l_@@_matrix_a_fp * #1 } } \cs_generate_variant:Nn \@@_transform_invert:n { f } +\cs_new_protected:Npn \draw_transform_shift_invert: + { + \dim_set:Nn \l_@@_xshift_dim { -\l_@@_xshift_dim } + \dim_set:Nn \l_@@_yshift_dim { -\l_@@_yshift_dim } + } % \end{macrocode} % \end{macro} % \end{macro} +% \end{macro} % % \begin{macro}{\draw_transform_triangle:nnn} % Simple maths to move the canvas origin to |#1| and the two axes to @@ -265,18 +265,69 @@ { \use:x { - \@@_transform:nnnnnnn + \draw_transform_matrix:nnnn { #3 - #1 } { #4 - #2 } { #5 - #1 } { #6 - #2 } - {#1} - {#2} + \draw_transform_shift:n { #1 , #2 } } } % \end{macrocode} % \end{macro} % +% \begin{macro} +% {\draw_transform_scale:n, \draw_transform_xscale:n, \draw_transform_yscale:n} +% \begin{macro} +% {\draw_transform_xshift:n, \draw_transform_yshift:n} +% \begin{macro} +% {\draw_transform_xslant:n, \draw_transform_yslant:n} +% Lots of shortcuts. +% \begin{macrocode} +\cs_new_protected:Npn \draw_transform_scale:n #1 + { \draw_transform_matrix_concat:nnnn { #1 } { 0 } { 0 } { #1 } } +\cs_new_protected:Npn \draw_transform_xscale:n #1 + { \draw_transform_matrix_concat:nnnn { #1 } { 0 } { 0 } { 1 } } +\cs_new_protected:Npn \draw_transform_yscale:n #1 + { \draw_transform_matrix_concat:nnnn { 1 } { 0 } { 0 } { #1 } } +\cs_new_protected:Npn \draw_transform_xshift:n #1 + { \draw_transform_shift_concat:n { #1 , 0 } } +\cs_new_protected:Npn \draw_transform_yshift:n #1 + { \draw_transform_shift_concat:n { 0 , #1 } } +\cs_new_protected:Npn \draw_transform_xslant:n #1 + { \draw_transform_matrix_concat:nnnn { 1 } { 0 } { #1 } { 1 } } +\cs_new_protected:Npn \draw_transform_yslant:n #1 + { \draw_transform_matrix_concat:nnnn { 1 } { #1 } { 0 } { 1 } } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\draw_transform_rotate:n} +% \begin{macro} +% { +% \@@_transform_rotate:n, \@@_transform_rotate:f, +% \@@_transform_rotate:nn, \@@_transform_rotate:ff +% } +% Slightly more involved: evaluate the angle only once, and the sine and +% cosine only once. +% \begin{macrocode} +\cs_new_protected:Npn \draw_transform_rotate:n #1 + { \@@_transform_rotate:f { \fp_eval:n {#1} } } +\cs_new_protected:Npn \@@_transform_rotate:n #1 + { + \@@_transform_rotate:ff + { \fp_eval:n { cosd(#1) } } + { \fp_eval:n { sind(#1) } } + } +\cs_generate_variant:Nn \@@_transform_rotate:n { f } +\cs_new_protected:Npn \@@_transform_rotate:nn #1#2 + { \draw_transform_matrix_concat:nnnn {#1} {#2} { -#2 } { #1 } } +\cs_generate_variant:Nn \@@_transform_rotate:nn { ff } +% \end{macrocode} +% \end{macro} +% \end{macro} +% % \begin{macrocode} %</initex|package> % \end{macrocode} diff --git a/Master/texmf-dist/source/latex/l3experimental/l3draw/l3draw.dtx b/Master/texmf-dist/source/latex/l3experimental/l3draw/l3draw.dtx index 9b7c04d5e54..7cefc6d837d 100644 --- a/Master/texmf-dist/source/latex/l3experimental/l3draw/l3draw.dtx +++ b/Master/texmf-dist/source/latex/l3experimental/l3draw/l3draw.dtx @@ -25,6 +25,71 @@ %</driver|package> %<*driver> \documentclass[full]{l3doc} +\usepackage[utf8]{inputenc} +\usepackage{l3draw} +% For creating code demonstrations +% This needs access to some code-level interfaces in listings +\usepackage{listings} +\makeatletter +\lst@RequireAspects{writefile} +\newsavebox\demo@box +\lstnewenvironment{demo}[1][code and example] + {% + \global\let\lst@intname\@empty + \edef\demo@end{% + \expandafter\noexpand\csname demo@@#1@end\endcsname + }% + \@nameuse{demo@@#1}% + } + {\demo@end} +\newcommand\demo@new[3]{% + \@namedef{demo@@#1}{#2}% + \@namedef{demo@@#1@end}{#3}% +} +\newcommand*\demo@common{% + \setkeys{lst} + {% + basicstyle = \small\ttfamily, + basewidth = 0.51em, + gobble = 5, + language = [LaTeX]{TeX}, + }% +} +\newcommand*\demo@input{% + \ExplSyntaxOn + \catcode`\^^M = 10\relax + \catcode`\% = 14\relax + \input{\jobname.tmp}% + \ExplSyntaxOff +} +\demo@new{code and example}{% + \setbox\demo@box=\hbox\bgroup + \lst@BeginAlsoWriteFile{\jobname.tmp}% + \demo@common +}{% + \lst@EndWriteFile + \egroup + \begin{center} + \ifdim\wd\demo@box > 0.75\linewidth + \begin{minipage}{\linewidth} + \usebox\demo@box + \end{minipage}% + \par + \begin{minipage}{\linewidth} + \demo@input + \end{minipage} + \else + \begin{minipage}{0.25\linewidth} + \demo@input + \end{minipage}% + \hfil + \begin{minipage}{0.75\linewidth} + \usebox\demo@box + \end{minipage}% + \fi + \end{center} +} +\makeatother \begin{document} \DocInput{\jobname.dtx} \end{document} @@ -44,7 +109,7 @@ % }^^A % } % -% \date{Released 2018/02/21} +% \date{Released 2018/03/05} % % \maketitle % @@ -82,6 +147,64 @@ % 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. +% \begin{demo} +% \dim_new:N \l_mypos_dim +% \draw_begin: +% \draw_path_moveto:n { 0cm , \l_mypos_dim } +% \draw_path_lineto:n { 1cm , \l_mypos_dim } +% \dim_set:Nn \l_mypos_dim { 1cm } +% \draw_path_lineto:n { 1cm , \l_mypos_dim } +% \draw_path_close: +% \draw_path_use_clear:n { stroke } +% \draw_end: +% \end{demo} +% +% Within a drawing, the only commands that should appear are those directly +% aimed at drawing (from \pkg{l3draw}) and those which produce \emph{no} +% typeset output. For example, it is possible to include loops inside a +% drawing using |\int_step_function:nnnn| or similar. On the other hand, +% text should not be included directly in drawings, but should rather be +% inserted using the appropriate \pkg{l3draw} command. +% \end{function} +% +% Within a drawing, there are different ways of referring to a position. +% The co-ordinates of a point are given relative to the current +% \emph{drawing axes}. These can be manipulated and tracked at the code +% level. Underlying this is the \meta{canvas}, which is at the \pkg{draw} +% level essentially fixed and in line with the paper. Initially, the two +% sets of axes are coincident. (It is possible to manipulate the canvas +% axes at the driver level: this is then \enquote{transparent} to the +% \pkg{draw} level, and so should be used only when strictly required.) +% +% \begin{function}{\draw_suspend_begin:, \draw_suspend_end:} +% \begin{syntax} +% \cs{draw_suspend_begin:} +% ... +% \cs{draw_suspend_end:} +% \end{syntax} +% Suspends all of the drawing mechanisms to allow \enquote{normal} +% material to be created. Typically, this environment will be applied +% inside a box which may contain nested pictures. +% \begin{demo} +% \draw_begin: +% \draw_path_moveto:n { 0cm , 0cm } +% \hbox_set:Nn \l_tmpa_box +% { +% \draw_suspend_begin: +% This~is~normal~text. +% \draw_begin: % A subpicture +% \draw_path_moveto:n { 1cm , 0cm } +% \draw_path_lineto:n { 1cm , 1cm } +% \draw_path_use_clear:n { stroke } +% \draw_end: +% More~text. +% \draw_suspend_end: +% } +% \draw_box_use:N \l_tmpa_box +% \draw_path_lineto:n { 0cm , 1cm } +% \draw_path_use_clear:n { stroke } +% \draw_end: +% \end{demo} % \end{function} % % \subsection{Graphics state} @@ -90,10 +213,10 @@ % 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} +% \begin{variable}{\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} +% \end{variable} % % \begin{function}{\draw_linewidth:n, \draw_inner_linewidth:n} % \begin{syntax} @@ -140,10 +263,54 @@ % % \begin{function}{\draw_miterlimit:n} % \begin{syntax} -% \cs{draw_miterlimit:n} \Arg{limit} +% \cs{draw_miterlimit:n} \Arg{factor} % \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}. +% Sets the miter \meta{factor} of lines joined as a miter, as described in the +% PDF and PostScript manuals. The \meta{factor} is an \meta{fp expr}. +% \end{function} +% +% \subsection{Scoping drawing elements} +% +% Scoping drawing elements is necessary to allowing nesting of subparts. +% These features have specific use requirements: the preconditions must be +% met. In particular, each type of drawing scope also constitutes a +% group (\cs{groupd_being:}/\cs{group_end:} pair): as such, they must be +% nested correctly. +% +% \begin{function}{\draw_scope_begin:, \draw_scope_end:} +% \begin{syntax} +% \cs{draw_scope_begin:} +% ... +% \cs{draw_scope_end:} +% \end{syntax} +% Creates a scope for localisation of state settings within a drawing. +% A scope forms a \TeX{} group but will also localise global state +% variables (such as \cs{g_draw_linewidth_default_dim}), and driver-level +% concepts such as the termination of lines. +% \begin{demo} +% \draw_begin: +% \draw_scope_begin: +% \group_begin: +% \draw_linewidth:n { 2pt } +% \draw_path_rectangle:nn { 0 , 0 } { 2ex , 2ex } +% \draw_path_use:n { stroke } +% \group_end: +% \draw_path_rectangle:nn { 3ex , 0ex } { 2ex , 2ex } +% \draw_path_use:n { stroke } +% \draw_scope_end: +% \draw_path_rectangle:nn { 6ex , 0ex } { 2ex , 2ex } +% \draw_path_use_clear:n { stroke } +% \draw_end: +% \end{demo} +% Global graphical concepts restricted by scope are +% \begin{itemize} +% \item Line width +% \item Stroke and fill color +% \item Dash pattern +% \item Line joining and capping, including the miter limit +% \item Clipping paths +% \item Canvas (driver) transformations +% \end{itemize} % \end{function} % % \subsection{Points} @@ -180,7 +347,7 @@ % 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 +% mechanisms. See \cs{driver_draw_cm:nnnn} for driver-level % manipulation of the canvas axes themselves. % % Notice that in contrast to \pkg{pgf} it is possible to give the positions @@ -235,8 +402,8 @@ % \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. +% Expands to the co-ordinates of a unit vector in the direction of the +% \meta{point} from the origin. % \end{function} % % \begin{function}[EXP]{\draw_point_transform:n} @@ -255,9 +422,9 @@ % 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{function}{\draw_xvec:n, \draw_yvec:n, \draw_zvec:n} % \begin{syntax} -% \cs{draw_xvec_set:n} \Arg{point} +% \cs{draw_xvec: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 @@ -358,16 +525,86 @@ % 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{function}{\draw_path_corner_arc:nn} +% \begin{syntax} +% \cs{draw_path_corner_arc:n} \Arg{length1} \Arg{length2} +% \end{syntax} +% Sets the degree of rounding applied to corners in a path: the two +% \meta{length} values are the distances from the corner at which the curving +% should start. The first \meta{length} applies to the part of the path +% \enquote{leading in} to the corner (\emph{i.e.}~from the previous path +% operation), and the second to that \enquote{leading out}. If both +% values are \texttt{0pt} then corners will not be rounded. The values +% apply within the scope of the current \TeX{} group. +% \begin{demo} +% \draw_begin: +% \draw_path_corner_arc:nn { 5mm } { 5mm } +% \draw_path_rectangle_corners:nn +% { 0cm , 0cm } { 3cm , 2cm } +% \draw_path_use_clear:n { stroke } +% \draw_end: +% \end{demo} +% \begin{demo} +% \draw_begin: +% \draw_path_corner_arc:nn { 10mm } { 5mm } +% \draw_path_moveto:n { 0cm , 0cm } +% \draw_path_lineto:n { 0cm , 2cm } +% \draw_path_lineto:n { 3cm , 2cm } +% \draw_path_curveto:nnn +% { 3cm , 0cm } { 2cm , 0cm } { 1cm , 0 cm } +% \draw_path_use_clear:n { stroke } +% \draw_end: +% \end{demo} +% The corners created are quarter-circles for exact right-angles and +% close approximations otherwise. Closing a path will result in rounding +% correctly. +% \begin{demo} +% \draw_begin: +% \draw_path_corner_arc:nn { 4pt } { 4pt } +% \draw_path_moveto:n +% { \draw_point_polar:nn { 0 } { 1cm } } +% \int_step_inline:nnnn { 72 } { 72 } { 359 } +% { +% \draw_path_lineto:n +% { \draw_point_polar:nn { #1 } { 1cm } } +% } +% \draw_path_close: +% \draw_path_use_clear:n { stroke } +% \draw_end: +% \end{demo} +% \end{function} +% +% \begin{function}{\draw_path_close:} % \begin{syntax} -% \cs{draw_path_corner_arc:n} \Arg{length} +% \cs{draw_path_close:} % \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.} +% Closes the current part of the path by appending a straight line from +% the current point to the starting point of the path. In general, any +% path to be \emph{filled} should include a close instructions. % \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} +% +% \subsubsection{Path operations on drawing axes} +% +% The standard path functions are all influenced by the active transformation +% matrix, \emph{i.e.}~the work relative to the drawing axes rather than +% the canvas. +% % \begin{function}{\draw_path_moveto:n} % \begin{syntax} % \cs{draw_path_moveto:n} \Arg{point} @@ -381,6 +618,32 @@ % \cs{draw_path_lineto:n} \Arg{point} % \end{syntax} % Joins the current path to the \meta{point} with a straight line. +% In general, for reliable treatment by viewers, a \cs{draw_path_moveto:n} +% operation should precede the first use of a \cs{draw_path_lineto:n} +% on a path. +% \begin{demo} +% \draw_begin: +% \draw_path_moveto:n { 0cm , 0cm } +% \draw_path_lineto:n { 1cm , 1cm } +% \draw_path_lineto:n { 2cm , 1cm } +% \draw_path_lineto:n { 3cm , 0.5cm } +% \draw_path_lineto:n { 3cm , 0cm } +% \draw_color_fill:n { yellow!80!black } +% \draw_path_use_clear:n { fill , stroke } +% \draw_end: +% \end{demo} +% \begin{demo} +% \draw_begin: +% \draw_path_moveto:n { 0cm , 0cm } +% \draw_path_lineto:n { 1cm , 1cm } +% \draw_path_lineto:n { 2cm , 1cm } +% \draw_path_moveto:n { 2cm , 1cm } % Begins a new part +% \draw_path_lineto:n { 3cm , 0.5cm } +% \draw_path_lineto:n { 3cm , 0cm } +% \draw_color_fill:n { yellow!80!black } +% \draw_path_use_clear:n { fill , stroke } +% \draw_end: +% \end{demo} % \end{function} % % \begin{function}{\draw_path_curveto:nnn} @@ -388,7 +651,21 @@ % \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}. +% cubic Bézier points \meta{control1} and \meta{control2}. The bounding box +% of the path (and image) will fully-contain the curve and control points, +% \emph{i.e.}~it may be bigger than strictly necessary to contain the curve +% \emph{alone}. +% \begin{demo} +% \draw_begin: +% \draw_path_moveto:n { 0cm , 0cm } +% \draw_path_curveto:nnn +% { 1cm , 1cm } % First control +% { 2cm , 1cm } % Second control +% { 3cm , 0cm } % End +% \draw_color_fill:n { yellow!80!black } +% \draw_path_use_clear:n { fill , stroke } +% \draw_end: +% \end{demo} % \end{function} % % \begin{function}{\draw_path_curveto:nn} @@ -396,7 +673,20 @@ % \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}. +% quadratic Bézier point \meta{control}. The bounding box +% of the path (and image) will fully-contain the curve and computed (cubic) +% control points, \emph{i.e.}~it may be bigger than strictly necessary to +% contain the curve \emph{alone}. +% \begin{demo} +% \draw_begin: +% \draw_path_moveto:n { 0cm , 0cm } +% \draw_path_curveto:nn +% { 1cm , 1cm } +% { 2cm , 0cm } +% \draw_color_fill:n { yellow!80!black } +% \draw_path_use_clear:n { fill , stroke } +% \draw_end: +% \end{demo} % \end{function} % % \begin{function}{\draw_path_arc:nnn, \draw_path_arc:nnnn} @@ -407,9 +697,26 @@ % 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. +% \begin{demo} +% \draw_begin: +% \draw_path_moveto:n { 0cm , 0cm } +% \draw_path_lineto:n { 0cm , 1cm } +% \draw_path_arc:nnn { 180 } { 90 } { 0.5cm } +% \draw_path_lineto:n { 3cm , 1.5cm } +% \draw_path_arc:nnn { 90 } { -45 } { 0.5cm } +% \draw_path_use_clear:n { fill } +% \draw_end: +% \end{demo} % % Note the interface here has a different argument ordering from that in % \pkg{pgf}, which has the two centers then the two radii. +% \begin{demo} +% \draw_begin: +% \draw_path_moveto:n { 0cm , 0cm } +% \draw_path_arc:nnnn { 180 } { 45 } { 2cm } { 1cm } +% \draw_path_use_clear:n { stroke } +% \draw_end: +% \end{demo} % \end{function} % % \begin{function}{\draw_path_arc_axes:nnnn} @@ -417,15 +724,49 @@ % \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. +% ellipse with axes along \meta{vector1} and \meta{vector2} to the current +% path. +% \begin{demo} +% \draw_begin: +% \draw_path_moveto:n { 0cm , 0cm } +% \draw_path_lineto:n { 2cm , 5mm } +% \draw_path_moveto:n { 0cm , 0cm } +% \draw_path_lineto:n { 0cm , 1cm } +% \draw_path_moveto:n { 2cm , 5mm } +% \draw_path_arc_axes:nnnn { 0 } { 90 } +% { 2cm , 5mm } { 0cm , 1cm } +% \draw_path_use_clear:n { stroke } +% \draw_end: +% \end{demo} % \end{function} % -% \begin{function}{\draw_path_ellipse:nnnn} +% \begin{function}{\draw_path_ellipse:nnn} % \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. +% \meta{vector2} to the current path. A new part is started if the path +% is already non-empty. Notice that the underlying drawing is constructed +% from arcs with appropriate moves: the interfaces is a more efficient +% convenience. +% \begin{demo} +% \draw_begin: +% \draw_path_ellipse:nnn +% { 1cm , 0cm } +% { 1.5cm , 0cm } +% { 0cm , 1cm } +% \draw_path_use_clear:n { stroke } +% \draw_color:n { red } +% \draw_path_ellipse:nnn +% { 1cm , 0cm } +% { 1cm , 1cm } +% { -0.5cm , 0.5cm } +% \draw_path_use_clear:n { stroke } +% \draw_end: +% \end{demo} +% +% Note that any transformation is applied to the completed ellipse rather than +% to the axes. % \end{function} % % \begin{function}{\draw_path_circle:nn} @@ -433,6 +774,7 @@ % \cs{draw_path_circle:nn} \Arg{center} \Arg{radius} % \end{syntax} % Appends a circle of \meta{radius} at \meta{center} to the current path. +% This is a shortcut for \cs{draw_path_ellipse:nnn}. % \end{function} % % \begin{function}{\draw_path_rectangle:nn, \draw_path_rectangle_corners:nn} @@ -443,44 +785,179 @@ % 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}. +% \begin{demo} +% \draw_begin: +% \draw_path_rectangle:nn +% { 1cm , 0cm } +% { 1.5cm , 1cm } +% \draw_path_rectangle:nn +% { 1.5cm , 0.25cm } +% { 1.5cm , 1cm } +% \draw_path_rectangle:nn +% { 2cm , 0.5cm } +% { 1.5cm , 1cm } +% \draw_path_use_clear:n { draw } +% \draw_end: +% \end{demo} +% \begin{demo} +% \draw_begin: +% \draw_path_rectangle_corners:nn +% { 1cm , 0cm } +% { 1.5cm , 1cm } +% \draw_path_use_clear:n { draw } +% \draw_end: +% \end{demo} % \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} +% \cs{draw_path_grid:nnnn} \Arg{xstep} \Arg{ystep} \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. +% Constructs a grid of \meta{xstep} and \meta{ystep} inside the rectangle +% defined by the \meta{lower-left} and the \meta{upper-right}, and appends +% this to the current path. The grid will be aligned such that grid lines +% pass through the origin, which may result in \enquote{protruding} ends +% if the start/end positions do not fully align. +% \begin{demo} +% \draw_begin: +% \draw_linewidth:n { 0.8pt } +% \draw_path_grid:nnnn +% { 1cm } { 1cm } +% { -3mm , -3mm } +% { 33mm , 23mm } +% \draw_path_use_clear:n { stroke } +% \draw_linewidth:n { 0.4pt } +% \draw_path_grid:nnnn +% { 1mm } { 1mm } +% { -1.5mm , -1.5mm } +% { 31.5mm , 21.5mm } +% \draw_path_use_clear:n { stroke } +% \draw_end: +% \end{demo} +% +% Any transformation is applied to the finished grid. +% \begin{demo} +% \draw_begin: +% \draw_transform_rotate:n { 10 } +% \draw_path_grid:nnnn +% { 1mm } { 2mm } +% { 0mm , 0mm } +% { 30mm , 30mm } +% \draw_path_use_clear:n { stroke } +% \draw_end: +% \end{demo} % \end{function} % -% \begin{function}{\draw_path_close:} +% \subsubsection{Path scope} +% +% \begin{function}{\draw_path_scope_begin:, \draw_path_scope_end:} % \begin{syntax} -% \cs{draw_path_close:} +% \cs{draw_path_scope_begin:} +% ... +% \cs{draw_path_scope_end:} % \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. +% Suspends (and saves) the current (partial) path, initialising a new +% path within the scope. Path operations are written to output only when +% used, so the scoped path is stored at the \pkg{expl3} level, not +% in the output. % \end{function} % -% \begin{function}{\draw_path_use:n, \draw_path_use_clear:n} +% \subsubsection{Path operations on canvas axes} +% +% For \emph{specialist} work, a small number of functions are provided +% which work relative to the canvas axes, \emph{i.e.}~these functions +% ignore the transformation matrix. +% +% \begin{function}{\draw_path_canvas_moveto:n} % \begin{syntax} -% \cs{draw_path_use:n} \Arg{action(s)} +% \cs{draw_path_canvas_moveto:n} \Arg{canvas point} % \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} +% Moves the reference point of the path to the \meta{canvas point}, but will +% not join this to any previous point. +% \end{function} +% +% \begin{function}{\draw_path_canvas_lineto:n} +% \begin{syntax} +% \cs{draw_path_canvas_lineto:n} \Arg{canvas point} +% \end{syntax} +% Joins the current path to the \meta{canvas point} with a straight line. +% \end{function} +% +% \begin{function}{\draw_path_canvas_curveto:nnn} +% \begin{syntax} +% \cs{draw_path_canvas_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}. These positions +% are given as canvas points. +% \end{function} +% +% \subsection{Bounding box} +% +% \begin{variable}{\l_draw_bb_update_bool} +% All functions automatically update the bounding box of the image, unless +% specified otherwise. This behavior is selectable using the +% \cs{l_draw_bb_update_bool} boolean. +% \end{variable} +% +% \subsection{Boxes and coffins} +% +% \begin{function}{\draw_box_use:N} +% \begin{syntax} +% \cs{draw_box_use:N} \meta{box} +% \end{syntax} +% Inserts the \meta{box} into a drawing, taking account of the current +% transformation matrix and shift, and adjusting the drawing bounding +% box to contain the (apparent) size of the box if this is active +% (see \cs{l_draw_bb_update_bool}). +% \begin{demo} +% \draw_begin: +% \draw_path_moveto:n { 0cm , 0cm } +% \draw_path_lineto:n { 0cm , 1cm } +% \draw_path_use_clear:n { stroke } +% \hbox_set:Nn \l_tmpa_box +% { This~is~text. } +% \draw_box_use:N \l_tmpa_box +% \draw_end: +% \end{demo} +% \begin{demo} +% \draw_begin: +% \draw_transform_matrix:nnnn { 2 } { 0 } { 1 } { 2 } +% \draw_path_moveto:n { 0cm , 0cm } +% \draw_path_lineto:n { 0cm , 1cm } +% \draw_path_use_clear:n { stroke } +% \hbox_set:Nn \l_tmpa_box +% { This~is~text. } +% \draw_box_use:N \l_tmpa_box +% \draw_end: +% \end{demo} +% \end{function} +% +% \begin{function}{\draw_coffin_use:Nnn} +% \begin{syntax} +% \cs{draw_coffin_use:N} \meta{coffin} \Arg{hpole} \Arg{vpole} +% \end{syntax} +% Inserts the \meta{coffin} into a drawing, taking account of the current +% transformation matrix and shift, and adjusting the drawing bounding +% box to contain the (apparent) size of the box if this is active +% (see \cs{l_draw_bb_update_bool}). The alignment point of the coffin to +% the origin is specified by the intersection of the \meta{hpole} and the +% \meta{vpole}. +% \begin{demo} +% \draw_begin: +% \draw_path_moveto:n { 0cm , 0cm } +% \draw_path_lineto:n { 0cm , 1cm } +% \draw_path_use_clear:n { stroke } +% \hcoffin_set:Nn \l_tmpa_coffin +% { This~is~text. } +% \draw_coffin_use:Nnn \l_tmpa_coffin { hc } { vc } +% \draw_end: +% \end{demo} % \end{function} % % \subsection{Color} % -% \begin{function}{\draw_color:n, \draw_fill:n, \draw_stroke:n} +% \begin{function}{\draw_color:n, \draw_color_fill:n, \draw_color_stroke:n} % \begin{syntax} % \cs{draw_color:n} \Arg{color expression} % \end{syntax} @@ -491,34 +968,28 @@ % % 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 +% may be adjusted using \cs{driver_draw_cm:nnnn}: 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{function} +% {\draw_transform_matrix:nnnn, \draw_transform_matrix_concat:nnnn} % \begin{syntax} -% \cs{draw_transform_concat:nnnnn} -% \Arg{a} \Arg{b} \Arg{c} \Arg{d} \Arg{vector} +% \cs{draw_transform_matrix:nnnnn} +% \Arg{a} \Arg{b} \Arg{c} \Arg{d} % \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}. +% Applies the transformation matrix $[ \meta{a} \meta{b} \meta{c} \meta{d}]$. +% The basic version over-writes the current matrix, the |concat| version +% concatenates. +% This assignment is local. % \end{function} % -% \begin{function}{\draw_transform:nnnnn} +% \begin{function}{\draw_transform_shift:n, \draw_transform_shift_concat:n} % \begin{syntax} -% \cs{draw_transform:nnnnn} -% \Arg{a} \Arg{b} \Arg{c} \Arg{d} \Arg{vector} +% \cs{draw_transform_shift:n} \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}. +% Applies the transformation \meta{vector} to points. The basic version +% over-writes the current vector, the |concat| version concatenates. +% This assignment is local. % \end{function} % % \begin{function}{\draw_transform_triangle:nnn} @@ -529,14 +1000,77 @@ % 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. +% This assignment is local. +% \end{function} +% +% \begin{function}{\draw_transform_rotate:n} +% \begin{syntax} +% \cs{draw_transform_rotate:n} \Arg{angle} +% \end{syntax} +% Applies a rotation by the \meta{angle}, measured anti-clockwise in degrees. +% This rotation is \emph{additional} to any prevailing transformation. +% This assignment is local. % \end{function} % -% \begin{function}{\draw_transform_invert:} +% \begin{function} +% { +% \draw_transform_scale:n, +% \draw_transform_xscale:n, +% \draw_transform_xscale:n +% } +% \begin{syntax} +% \cs{draw_transform_scale:n} \Arg{scale} +% \end{syntax} +% Applies the \meta{scale} in either $x$ or $y$ (or both). +% This scale is \emph{added} to any prevailing transformation. +% This assignment is local. +% \end{function} +% +% \begin{function} +% { +% \draw_transform_xshift:n, +% \draw_transform_yshift:n +% } +% \begin{syntax} +% \cs{draw_transform_shift:n} \Arg{vector} +% \cs{draw_transform_xshift:n} \Arg{xshift} +% \end{syntax} +% Applies an \meta{xshift} or \meta{yshift}, as appropriate. This shift is +% \emph{added} to any prevailing one. +% This assignment is local. +% \end{function} +% +% \begin{function} +% { +% \draw_transform_xslant:n, +% \draw_transform_yslant:n +% } +% \begin{syntax} +% \cs{draw_transform_xslant:n} \Arg{slant} +% \end{syntax} +% Applies the \meta{slant} (a factor) in either $x$ or $y$. +% This slant is \emph{added} to any prevailing transformation. +% This assignment is local. +% \end{function} +% +% \begin{function} +% {\draw_transform_matrix_invert:, \draw_transform_shift_invert:} +% \begin{syntax} +% \cs{draw_transform_matrix_invert:} +% \end{syntax} +% Inverts the current transformation matrix or shift vector, as +% appropriate. +% This assignment is local. +% \end{function} +% +% \begin{function} +% {\draw_transform_matrix_reset, \draw_transform_shift_reset:} % \begin{syntax} -% \cs{draw_transform_invert:} +% \cs{draw_transform_matrix_reset:} % \end{syntax} -% Inverts the current transformation matrix and reverses the current -% shift vector. +% Resets the current transformation matrix or shift vector, as +% appropriate. +% This assignment is local. % \end{function} % % \end{documentation} @@ -555,7 +1089,7 @@ % % \begin{macrocode} %<*package> -\ProvidesExplPackage{l3draw}{2018/02/21}{} +\ProvidesExplPackage{l3draw}{2018/03/05}{} {L3 Experimental core drawing support} %</package> % \end{macrocode} diff --git a/Master/texmf-dist/source/latex/l3experimental/l3draw/l3draw.ins b/Master/texmf-dist/source/latex/l3experimental/l3draw/l3draw.ins index d7c3616c607..e91015c2ba1 100644 --- a/Master/texmf-dist/source/latex/l3experimental/l3draw/l3draw.ins +++ b/Master/texmf-dist/source/latex/l3experimental/l3draw/l3draw.ins @@ -54,6 +54,7 @@ and all files in that bundle must be distributed together. \generate{\file{l3draw.sty} { \from{l3draw.dtx} {package} + \from{l3draw-boxes.dtx} {package} \from{l3draw-paths.dtx} {package} \from{l3draw-points.dtx} {package} \from{l3draw-scopes.dtx} {package} |