如何有条件地在 ConTeXt 中绘制 MetaPost 图形的各个部分?

如何有条件地在 ConTeXt 中绘制 MetaPost 图形的各个部分?

我的问题的基础是我正在制作一个 14x14 的填字游戏,我有来自外部文档的 196 个单元格中的每一个的数据,但只需要内部带有文本的单元格有边框。

我尝试使用 MetaPost 来解决这个问题。为简单起见,我在这里将代码简化为 14x1 网格示例。

我创建了一个外部脚本,它为我提供了网格内应包含的所有值。例如,如果第一行有“cat”,则它会给出以下内容:

\setvalue{1}{c}
\setvalue{2}{a}
\setvalue{3}{t}
\setvalue{4}{}
\setvalue{5}{}
\setvalue{6}{}
\setvalue{7}{}
\setvalue{8}{}
\setvalue{9}{}
\setvalue{10}{}
\setvalue{11}{}
\setvalue{12}{}
\setvalue{13}{}
\setvalue{14}{}

完整的 14x14 示例有 196 个这样的变量,但通过脚本放在另一个文件中,因此它们并不笨重。

我使用 MetaPost 创建了许多框而不是表格,因为我找不到干净的方法将下标文本添加到表格中单元格的角落,而不会将该单元格中的字母推到右侧。

以下是解决方案页面的最小工作示例:

\setvalue{1}{c}
\setvalue{2}{a}
\setvalue{3}{t}
\setvalue{4}{}
\setvalue{5}{}
\setvalue{6}{}
\setvalue{7}{}
\setvalue{8}{}
\setvalue{9}{}
\setvalue{10}{}
\setvalue{11}{}
\setvalue{12}{}
\setvalue{13}{}
\setvalue{14}{}

\define\crosswordsolution{%
    \scale[width=\textwidth]{%
        \startMPcode
            draw (0,0)--(100,0)--(100,100)--(0,100)--(0,0);
            draw (100,0)--(200,0)--(200,100)--(100,100)--(100,0);
            draw (200,0)--(300,0)--(300,100)--(200,100)--(200,0);
            draw (300,0)--(400,0)--(400,100)--(300,100)--(300,0);
            draw (400,0)--(500,0)--(500,100)--(400,100)--(400,0);
            draw (500,0)--(600,0)--(600,100)--(500,100)--(500,0);
            draw (600,0)--(700,0)--(700,100)--(600,100)--(600,0);
            draw (700,0)--(800,0)--(800,100)--(700,100)--(700,0);
            draw (800,0)--(900,0)--(900,100)--(800,100)--(800,0);
            draw (900,0)--(1000,0)--(1000,100)--(900,100)--(900,0);
            draw (1000,0)--(1100,0)--(1100,100)--(1000,100)--(1000,0);
            draw (1100,0)--(1200,0)--(1200,100)--(1100,100)--(1100,0);
            draw (1200,0)--(1300,0)--(1300,100)--(1200,100)--(1200,0);
            draw (1300,0)--(1400,0)--(1400,100)--(1300,100)--(1300,0);

            label("\getvalue{1}", (50,50));
            label("\getvalue{2}", (150,50));
            label("\getvalue{3}", (250,50));
            label("\getvalue{4}", (350,50));
            label("\getvalue{5}", (450,50));
            label("\getvalue{6}", (550,50));
            label("\getvalue{7}", (650,50));
            label("\getvalue{8}", (750,50));
            label("\getvalue{9}", (850,50));
            label("\getvalue{10}", (950,50));
            label("\getvalue{11}", (1050,50));
            label("\getvalue{12}", (1150,50));
            label("\getvalue{13}", (1250,50));
            label("\getvalue{14}", (1350,50));
            label("1", (25,75));
        \stopMPcode
    }%
}%

\starttext
    \crosswordsolution
\stoptext

我遇到的问题是,我只需要绘制里面有字母的框。空框根本不需要绘制。换句话说,只需要绘制包含 CAT 中字母的框,其他框是不可见的。

我尝试在 MetaPost 中使用简单的 TeX 条件,检查变量是否为空,但代码出现错误,所以我怀疑 MetaPost 里面不能有 TeX 或 ConTeXt\startMPcode代码\endMPcode

是否有某种方法可以创建条件,仅当匹配变量有文本时才允许绘制特定的框?

答案1

您会发现使用 Metapost 逻辑结构更容易。这里有一些简单的 MP,可以满足您的要求(我认为):

prologues := 3;
outputtemplate := "%j%c.eps";

beginfig(1);

    string cell[];
    cell1 := "C";
    cell2 := "A";
    cell3 := "T";
    cell4 := "";
    cell5 := "S";
    cell6 := "A";
    cell7 := "T";
    cell8 := "";
    cell9 := "";
    cell10 := "";
    cell11 := "H";
    cell12 := "E";
    cell13 := "R";
    cell14 := "E";

    path box;
    box = unitsquare shifted -(1/2, 1/2) scaled 10;

    numeric x, y;
    y = 5;
    x = 5;
    for i=1 upto 14:
        if cell[i] <> "": 
            label(cell[i], (x, y));
            draw box shifted (x, y);
        fi
        x := x + 10; 
    endfor

endfig;
end.

如果你用纯文本编译它,mpost你应该得到这个:

在此处输入图片描述

在 和 之间的普通 Metapost 中运行的所有内容都应该在 Context 中的beginfig和之间endfig无须改变地运行。\startMPcode\stopMPcode

cell1 := "\getvalue{1}"您可以通过分配等方式使其适应您的价值观。

答案2

在 MetaPost 中使用 TeX 条件,但它们必须是完全可扩展的,并避免“不完整的 if”问题。生成的代码并不漂亮,Toby 的答案显然更可取。

\setvalue{1}{c}
\setvalue{2}{a}
\setvalue{3}{t}
\setvalue{4}{}
\setvalue{5}{}
\setvalue{6}{}
\setvalue{7}{}
\setvalue{8}{}
\setvalue{9}{}
\setvalue{10}{}
\setvalue{11}{}
\setvalue{12}{}
\setvalue{13}{}
\setvalue{14}{}

% \getvalue only yields its value after two expansion steps,
% therefore we need to use \doubleexpandafter
\def\expdoifvalue#1%
    {\doubleexpandafter\ifx\getvalue{#1}\empty
         \expandafter\gobbleoneargument
     \else
         \expandafter\firstofoneargument
     \fi}

\define\crosswordsolution{%
    \scale[width=\textwidth]{%
        \startMPcode
            \expdoifvalue{1}{
                draw (0,0)--(100,0)--(100,100)--(0,100)--(0,0);
                label("\getvalue{1}", (50,50));
            }
            \expdoifvalue{2}{
                draw (100,0)--(200,0)--(200,100)--(100,100)--(100,0);
                label("\getvalue{2}", (150,50));
            }
            \expdoifvalue{3}{
                draw (200,0)--(300,0)--(300,100)--(200,100)--(200,0);
                label("\getvalue{3}", (250,50));
            }
            \expdoifvalue{4}{
                draw (300,0)--(400,0)--(400,100)--(300,100)--(300,0);
                label("\getvalue{4}", (350,50));
            }
            \expdoifvalue{5}{
                draw (400,0)--(500,0)--(500,100)--(400,100)--(400,0);
                label("\getvalue{5}", (450,50));
            }
            \expdoifvalue{6}{
                draw (500,0)--(600,0)--(600,100)--(500,100)--(500,0);
                label("\getvalue{6}", (550,50));
            }
            \expdoifvalue{7}{
                draw (600,0)--(700,0)--(700,100)--(600,100)--(600,0);
                label("\getvalue{7}", (650,50));
            }
            \expdoifvalue{8}{
                draw (700,0)--(800,0)--(800,100)--(700,100)--(700,0);
                label("\getvalue{8}", (750,50));
            }
            \expdoifvalue{9}{
                draw (800,0)--(900,0)--(900,100)--(800,100)--(800,0);
                label("\getvalue{9}", (850,50));
            }
            \expdoifvalue{10}{
                draw (900,0)--(1000,0)--(1000,100)--(900,100)--(900,0);
                label("\getvalue{10}", (950,50));
            }
            \expdoifvalue{11}{
                draw (1000,0)--(1100,0)--(1100,100)--(1000,100)--(1000,0);
                label("\getvalue{11}", (1050,50));
            }
            \expdoifvalue{12}{
                draw (1100,0)--(1200,0)--(1200,100)--(1100,100)--(1100,0);
                label("\getvalue{12}", (1150,50));
            }
            \expdoifvalue{13}{
                draw (1200,0)--(1300,0)--(1300,100)--(1200,100)--(1200,0);
                label("\getvalue{13}", (1250,50));
            }
            \expdoifvalue{14}{
                draw (1300,0)--(1400,0)--(1400,100)--(1300,100)--(1300,0);
                label("\getvalue{14}", (1350,50));
            }

            label("1", (25,75));
        \stopMPcode
    }%
}%

\starttext
    \crosswordsolution
\stoptext

除了实现之外,\expdoifvalue{1}{...}您还可以使用内置的\expdoifnot{\getvalue{1}}{}{...}。但是,\expdoifnot执行完全扩展可能并不总是理想的。

相关内容