4

I'm trying to write some code that allows me to reveal in stages the content of a pre-existing file (a pspicture showing a geometric construction). I'm trying to write this using LaTeX3. I've got some working code, but I don't like how I'm implementing it. Currently, the working version is a hobbled together collection of commands. I want to streamline this using l3keys. However, I'm getting stuck.

What's working:

Here's what I've got that's working. There are three files:

File in which I define the expl3 interface: this is put in a file called stages.tex

%% defining stages
\usepackage{xparse}
\usepackage{verbatim}
\ExplSyntaxOn

\tl_new:N    \ace_reveal_tl
\tl_gset:Nn  \ace_reveal_tl {REVEAL}
\tl_new:N    \ace_conceal_tl
\tl_gset:Nn  \ace_conceal_tl {CONCEAL}

\NewDocumentCommand{\revealstage}{ m }{
        \tl_gset:cV { ace__reveal__ #1 __stage__new } \ace_reveal_tl
    }
\NewDocumentCommand{\burystage}{ m }{
        \tl_gset:cV { ace__reveal__ #1 __stage__new } \ace_conceal_tl
}

\NewDocumentCommand{\testforstage}{ m m m }{
            \tl_if_eq:cNTF { ace__reveal__ #1 __stage__new } \ace_reveal_tl
                           {#2}
                           {#3}    
}

\NewDocumentEnvironment{stage}{ m }
        {
            \tl_if_eq:cNF { ace__reveal__ #1 __stage__new } \ace_reveal_tl
                          {\expandafter\comment}
        }
        {
            \tl_if_eq:cNF { ace__reveal__ #1 __stage__new } \ace_reveal_tl
                          {\expandafter\endcomment}
          }

\ExplSyntaxOff  

File in which I define the picture I'm using in which I implement stages: this file is called diagram.tex

\begin{pspicture}[showgrid=false](-20,-13)(20,13)
    %..% compass directions %..% 
    {
        \psset{PointName=none,PointSymbol=none} 
        \pstGeonode(0,0){o}(1,0){r}(0,1){u}
        \pstRotation[RotAngle=20]{o}{r}[r1] 
        \pstGeonode(0,0){Q}
    }
    %% temporarily define midpont of segment(PQ) --> M to control positioning
    \pstGeonode[PointName=none,PointSymbol=none,PosAngle=0](0,0){tM}
    %% point outside the circle and the center of circle
    \pstTranslation[DistCoef=14,PosAngle=80]{o}{r1}{tM}[Q]
    \pstTranslation[DistCoef=10,PosAngle=-100]{r1}{o}{tM}[P]
    %% construct circle centered at P
    \pstCircleOA[Radius=\pstDistVal{9}]{P}{}

    %% construct mid-point between P and Q
    \pstTranslation[DistCoef=9,PointName=none,PointSymbol=none]{o}{r}{P}[B]
    \pstTranslation[DistCoef=0.5,PointName=none,PointSymbol=none]{P}{Q}{P}[M]
    %% show constructions
    \begin{stage}{midpoint}
        \pstLineAB[linecolor=blue,linewidth=0.1pt,linestyle=dashed]{P}{Q}
        \pstGeonode[PointName=M,PosAngle=-90](M){showM}
    \end{stage}

    %% construct circle centered at M passing through P and Q
    \begin{stage}{large circle}
        \pstCircleOA[linecolor=blue,linewidth=0.2pt,linestyle=dashed]{M}{P}
    \end{stage}

    %% construct tangents
    \pstInterCC[PointName=none,PointSymbol=none,RadiusB=\pstDistVal{9}]{M}{P}{P}{}{U}{V}
    \begin{stage}{tangents}
        \testforstage{large circle}{
            \pstGeonode[PointName={U},PosAngle=-90](U){showU}
            \pstGeonode[PointName={V},PosAngle=110](V){showV}
        }{
            \pstGeonode[PointName={U},PosAngle=-50](U){showU}
            \pstGeonode[PointName={V},PosAngle=90](V){showV}
        }
        \pstLineAB[linecolor=red,nodesep=-8]{Q}{V}
        \pstLineAB[linecolor=red,nodesep=-8]{Q}{U}
    \end{stage}

\end{pspicture}

The main document:

\documentclass{article}
\usepackage{pstricks,pst-eucl}
\psset{unit=0.15cm}
\usepackage[margin=1in]{geometry}
\input{stages}
\pagestyle{empty}
\begin{document}

    \input{diagram} 

    \revealstage{midpoint}
    \input{diagram}

    \revealstage{large circle}
    \input{diagram}

    \revealstage{tangents}
    \input{diagram}

    \burystage{midpoint}
    \burystage{large circle}
    \input{diagram}

\end{document}

This creates:

enter image description here

What's not working:

I would really like to be able to write something like the following lines in the main document:

\activatestage[reveal=midpoint,
               conceal={large circle,
                        midpoint}]
              {diagram}

But this above example is a bit more sophisticated than I've currently tried to implement. Currently, I haven't written code to handle passing multiple values to be parse by the key. I've only written something that I believe should be able to handle the following:

\activatestage[reveal=midpoint,
               conceal=large circle]
              {diagram}

And this is the code I use to try to implement this:

%% defining keys
\ExplSyntaxOn
\keys_define:nn { stages }{
    reveal  .code:n = \fnc_reveal_stages:n #1,
    conceal .code:n = \fnc_conceal_stages:n #1
}

\cs_new:Npn \fnc_reveal_stages:n #1 {
        \tl_gset:cV { ace__reveal__ #1 __stage__new } \ace_reveal_tl
}

\cs_new:Npn \fnc_conceal_stages:n #1 {
        \tl_gset:cV { ace__reveal__ #1 __stage__new } \ace_conceal_tl
}

\NewDocumentCommand{\activatestage}{ o m }{
        \tl_set:Nn  \l__no_value_tl         { \NoValue    }
        \tl_set:Nn  \l__keys_present_tl     { #1 }
        \tl_show:N \l__keys_present_tl
        \bool_if:nF {        \tl_if_eq_p:NN \l__keys_present_tl  \l__no_value_tl) }
                {
                    \keys_set:nn{ stages }{#1}
                }
        \input{#2}
}
\ExplSyntaxOff

I've put the above in its own file called additions.tex

Here's the main document where I try to implement the new approach:

\documentclass{article}
\usepackage{pstricks,pst-eucl}
\psset{unit=0.15cm}
\usepackage[margin=1in]{geometry}
\input{stages}
\input{additions}
\pagestyle{empty}
\begin{document}

    \input{diagram} 

    \revealstage{midpoint}
    \input{diagram}

    \revealstage{large circle}
    \input{diagram}

    \revealstage{tangents}
    \input{diagram}

    \activatestage[reveal=midpoint,
                   conceal=large circle]
                  {diagram}

\end{document}

But this results in:

enter image description here

But this isn't doing what I expect (as you can see by comparing to my working example). The key seems to only see the first letter of the value being passed to it. How do I get the key to see the entire value?

6
  • At least it should be reveal .code:n = \fnc_reveal_stages:n {#1} Always put braces around an n-type argument.
    – egreg
    Commented Jan 26, 2013 at 18:10
  • @egreg. Oh how humiliating! Such a simple mistake. Thank you!
    – A.Ellett
    Commented Jan 26, 2013 at 18:12
  • You should use a boolean, instead of comparing token lists for concealing or revealing the environment.
    – egreg
    Commented Jan 26, 2013 at 18:13
  • @egreg. I'm not sure how to implement that. The reason is that I would like the user to have the freedom to define the names for the blocks to be revealed/concealed.
    – A.Ellett
    Commented Jan 26, 2013 at 18:18
  • You can define "named" conditionals with \bool_new:c, maybe checking first if they are already existent; then you can use \bool_gset_true:c and \bool_gset_false:c for setting them and \bool_if:cTF for using them.
    – egreg
    Commented Jan 26, 2013 at 18:22

1 Answer 1

5

Enclose n-type arguments in braces: it should be

\keys_define:nn { stages }
 {
  reveal  .code:n = \fnc_reveal_stages:n  { #1 },
  conceal .code:n = \fnc_conceal_stages:n { #1 },
 }

Here's a proposal using booleans and a good deal of simplifications. However, you should also add a command for defining all allowed "stages".

\documentclass{article}
\usepackage{pstricks,pst-eucl}
\psset{unit=0.15cm}

\usepackage[margin=1in]{geometry}

%% defining stages
\usepackage{xparse}
\usepackage{verbatim}
\ExplSyntaxOn

\NewDocumentCommand{\revealstage}{ m }
 {
  \ace_reveal_stage:n { #1 }
 }
\cs_new_protected:Npn \ace_reveal_stage:n #1
 {
  \bool_if_exist:cF { g__ace_reveal_ #1 _stage_bool }
   { \bool_new:c { g__ace_reveal_ #1 _stage_bool } }
  \bool_gset_true:c { g__ace_reveal_ #1 _stage_bool }
 }
\NewDocumentCommand{\burystage}{ m }
 {
  \ace_conceal_stage:n { #1 }
 }
\cs_new_protected:Npn \ace_conceal_stage:n #1
 {
  \bool_if_exist:cF { g__ace_reveal_ #1 _stage_bool }
   { \bool_new:c { g__ace_reveal_ #1 _stage_bool } }
  \bool_gset_false:c { g__ace_reveal_ #1 _stage_bool }
 }

\NewDocumentCommand{\testforstage}{ m m m }
 {
  \bool_if:cTF { g__ace_reveal_ #1 _stage_bool } { #2 } { #3 }
 }

\NewDocumentEnvironment{stage}{ m }
 {
  \bool_if:cF { g__ace_reveal_ #1 _stage_bool } {\comment}
 }
 {
  \bool_if:cF { g__ace_reveal_ #1 _stage_bool } {\endcomment}
 }

%%% Keyval syntax

\keys_define:nn { stages }{
    reveal  .code:n = \ace_reveal_stage:n  { #1 },
    conceal .code:n = \ace_conceal_stage:n { #1 },
}

\NewDocumentCommand{\activatestage}{ O{} m }
 {
  \keys_set:nn { stages } { #1 }
  \input{#2}
 }

\ExplSyntaxOff  

\pagestyle{empty}
\begin{document}

\activatestage[reveal=midpoint,
               conceal=large circle]
              {diagram}

\end{document}

enter image description here

Notes

  1. Comparing token lists is not an efficient way; booleans are surely better.

  2. Please, stick to the naming conventions; variables should start with l_ or g_ (or l__ and g__ if they are "internal").

  3. \keys_set:nn is perfectly happy to process an empty argument, so

    \NewDocumentCommand{\activatestage}{ O{} m }
    

    is much more efficient than your testing of \NoValue. In any case, you should use \IfNoValueTF to test for the presence of an optional argument.

1
  • Other than the accessor commands, your MWE is pretty much exactly how I rewrote my document after your suggestion to use booleans. Thank you for showing the \bool_if_exist. I've also implemented setting multiple values through \clist_set:Nn \l__ace_stages {#1} and then calling \clist_map_inline:Nn \l__ace_stage { \bool_gset_true:c { g__ace_reveal_ ##1 _stage_new } }. And mutatis mutandis, for the conceal side of things. I have some very nice code now. Thank you again.
    – A.Ellett
    Commented Jan 26, 2013 at 19:08

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .