使用 latex 中的 postscript 在文本周围绘制一个椭圆,并在没有 tikz 包的情况下为其创建宏

使用 latex 中的 postscript 在文本周围绘制一个椭圆,并在没有 tikz 包的情况下为其创建宏

当我使用 tikz 之类的包时,解决方案很简单。但我不应该使用包。我需要在 latex 中使用 post script。我试图在宏中使用两条直线和两条曲线绘制这个椭圆,我需要将 currentpoint 传递给宏。我不知道如何将 currentpoint 传递给宏。有没有办法将 currentpoint(具有 x、y)传递给宏,以便使用这些 x 和 y 点绘制直线和曲线?我提到我不应该在我的程序中使用包,因为这是我的项目,我的教授让我在 LATEX 中使用 postscript 编写这个程序。

下面是我需要用我的程序执行的操作的示例: 在此处输入图片描述

据我所知,在我输入单词 LaTEX 后,当我说 \special{pS: currentpoint} 时,它指向单词 LaTEX 后面的点的 x 和 y 坐标。如果我将这些坐标传递给我的宏并计算点: 在此处输入图片描述

下面是我的代码:

\documentclass{article}                                             
\usepackage{calc} 
\begin{document}

\newcommand{\drawoval}[4] {

\newcommand\x{#1}
\newcommand\y{#2} 
\newcommand\length{#3}
\newcommand\height{#4}

\newcommand\x1{\the\numexpr\x-\length}
\newcommand\y1{\the\y} 
\newcommand\x2{\the\x}
\newcommand\y2{\the\y}
\newcommand\x3{\the\numexpr\x+5}
\newcommand\y3{\the\numexpr\y+\height/2}
\newcommand\x4{\the\x}
\newcommand\y4{\the\numexpr\y+\height}
\newcommand\x5{\the\numexpr\x-\length}
\newcommand\y5{\the\numexpr\y+\height}
\newcommand\x6{\the\numexpr\x-\length+5}
\newcommand\y6{\the\numexpr\y+\height/2}

\special{pS: x1 y1 x6 y6 x5 y5 curveto 1 0 0 setrgbcolor stroke}
\special{pS: x2 y2 x3 y3 x4 y4 curveto 1 0 0 setrgbcolor stroke}
\special{pS: x1 y1} \special{pS: x2 y2 moveto lineto 1 0 0 setrgbcolor stroke}
\special{pS: x5 y5} \special{pS: x4 y4 moveto lineto 1 0 0 setrgbcolor stroke}

}

\newlength{\wordlength} 
\newlength{\wordheight}

\settowidth{\wordlength}{Postscript}
\settoheight{\wordheight}{Postscript}
% This is the part where I am struck
This is an example of what I need to do in my program using Postscript in LaTEX \drawoval{x coordinate of currentpoint}{y coordinate of currentpoint}{\the\wordlength}{\the\wordheight} program
%\drawoval{\special{pS: currentpoint}}
\end{document}

下面的程序可以运行,但是当我尝试多次调用宏 \drawoval 时,会出现错误。请告诉我如何避免这种情况。

\documentclass{article}%%
\usepackage{calc}%%
\begin{document}%%
\makeatletter%%
    \def\strippt{\strip@pt}%%
\makeatother%%
\newsavebox\wordbox%%
\newcommand{\drawoval}[1] {%%
\sbox\wordbox{#1}%%
    \def\mywidth{\wd\wordbox}%%
    \def\myheight{\ht\wordbox}%%
    \newcommand\newwidth{\strippt\dimexpr\mywidth+4pt \relax}%%
    \newcommand\newwordwidth{\strippt\dimexpr\mywidth+0pt \relax}%%
    \newcommand\newheight{\strippt\dimexpr\myheight+6pt \relax}%%
    \newcommand\rightpoint{\strippt\dimexpr\mywidth+9pt \relax}%%
    \special{" 4 -8 moveto
                -2 2 -2 4 4 \newheight\space curveto
                \newwordwidth\space 0 rlineto
                \newwidth\space -8 moveto
                \rightpoint\space 2 \rightpoint\space 4 \newwidth\space \newheight\space curveto
                4 -8 moveto
                \newwordwidth\space 0 rlineto
                1 0 0 setrgbcolor
                stroke}
    #1
}%%
This is the \drawoval{demo program} of my project%%
\end{document}%%

答案1

由于这是家庭作业,我不会在这里提供完整的答案(也许几周后会安全过去)。但是,我会提供一些有关您的代码的提示。

要点 1:过多的空白

您的解决方案中存在大量多余的空白。特别是空行,将被视为新段落——这可能不是您想要的。所有以控制序列以外的任何内容结尾的行也会产生虚假空白。在每行末尾添加注释以排除空白。不过,行首的空白不是问题。

第 2 点:合法的控制序列名称

控制序列名称不能使用非字母字符来定义。因此,您无法\x1直接使用 来定义控制序列\newcommand(有多种方法可以做到这一点,但这里不需要它们)。相反,您可以定义\newcommand\tmpxi\newcommand\tmpxii等等。

第 3 点:\numexprvs\dimexpr

\numexpr只适用于整数值。如果你输入的不是整数,那么它会截断数字。如果你想操纵长度,请使用\dimexpr。但是,PostScripts 不会期望你输入单位。因此,你需要一种方法来在将长度输入到 PostScript 代码之前将单位从长度中剥离出来。你可以使用\strip@pt

例如,你可能想要定义

\makeatletter
\newcommand\tmpxi{\strip@pt\dimexpr\x-\length}
\makeatother

它们\makeat...必须能够@表现得像字母字符(见上面的第 2 点)。

要点 4:获取所需的 PostScript 坐标矩阵

您可能希望使用\special{"而不是\special{ps:,以便 PostScript 遵循您想要的长度。请参阅我自己对此有疑问,希望得到解释

第 5 点:控制序列后面的空格

在控制序列之后,空白将被吞噬。这可能会对 PostScript 代码产生意想不到的影响。例如,

\def\tmpxi{10}
\special{"
   0 0 moveto
   \tmpxi 0 lineto
   stroke
}

你会得到一个错误,因为 LaTeX 读取后会将其发送给dvi驱动程序

0 0 moveto
100 lineto
stroke

为了解决这个问题你可以写

\def\tmpxi{10}
\special{"
   0 0 moveto
   \tmpxi\space 0 lineto
   stroke 
 }

第 6 点:绝对命令与相对命令

rmoveto如果你使用相对命令和,那么你可能会更容易一些rlineto。这样你就不需要太担心在哪里currentpoint了。

建议 1:保存箱

如果您想要换行某个特定的单词,您可以创建一个命令将该单词保存到一个框中,测量该框的尺寸,然后使用这些尺寸更轻松地计算出在哪里画线。

例如

\newsavebox\mycontentbox
\newcommand\myoval[1]{%%
    \sbox\mycontentbox{#1}%%
    \def\mywidth{\wd\mycontentbox}%%
    ... 
    }

访问尺寸的其他命令是

\dp=depth
\ht=height (above the baseline)

最后结果

坚持这些一般原则,这就是我可以轻松制作的东西(盒子,而不是椭圆形尽管)

在此处输入图片描述

最后一点,在我的工作中我从来没有提到过currentpoint。另外你应该注意到,我没有对盒子本身如何粗鲁地侵占周围空间做出任何纠正。

解决方案

这是一个解决方案。有几点需要注意。首先,我尽量避免创建 LaTeX 宏。它们不是必需的;postscript 可以完成所有必要的算术计算。其次,现在我看到了你整理的更多内容,我会在前言到您的文档,而不是身体。第三,我对背景条纹的创建非常马虎:特别是,我不太注意它们相对于盒子本身的起点和终点。为了使事物终止于我希望它们终止的地方,我创建了路径,然后调用了后记clip。最后,我在后记代码中定义了几个函数,以使路径代码和条纹代码更易于阅读。

\documentclass{article}
\usepackage[margin=1in]{geometry}

\makeatletter
\newsavebox\myovalbox
\newcommand\myoval[1]{%%
  \sbox\myovalbox{#1}%%
  \special{"
    /mytxtht             \strip@pt\ht\myovalbox\space                      def
    /mytxtdp             \strip@pt\dp\myovalbox\space                      def
    /mytxtwd             \strip@pt\wd\myovalbox\space                      def
    %%
    /mytxtboxsep         3                                                 def
    /myboxwd             { mytxtboxsep dup add mytxtwd add }               def
    /myboxdp             { mytxtboxsep         mytxtdp add }               def    
    /myboxht             { mytxtboxsep dup add mytxtht mytxtdp add add }   def
    %%
    /myboxhstart         { mytxtboxsep neg }                               def    
    /myboxvstart         { myboxdp     neg }                               def
    %%
    /myinterstripesep    4                                                 def
    /mystripeprotrusion  6                                                 def
    /mystriperise        { mystripeprotrusion dup add myboxht add }        def
    /mystriperun         8                                                 def
    /mystripebot         { mystripeprotrusion         myboxdp add neg }    def
    /mystripestart       { mytxtboxsep dup add myinterstripesep add neg }  def
    /mystripeend         { mytxtboxsep myboxwd add}                        def
    %% draw the box
    newpath
    1 0 0 setrgbcolor
    myboxhstart   myboxvstart   moveto
    myboxwd       0             rlineto
    0             myboxht       rlineto
    myboxwd neg   0             rlineto
    closepath
    clip
    %% for loop:  start-value increment end-value { iteration action } for  
    %% the for loop takes the current value of the loop and                 
    %% places it at the beginning of iteration action, hence                
    %% the "moveto" below appears to only have one argument                 
    mystripestart myinterstripesep mystripeend 
      {             mystripebot   moveto 
        mystriperun mystriperise  rlineto 
      } 
    for
    stroke
    %%
  }%%
  \usebox{\myovalbox}}
\makeatother

\begin{document}

This is an example of what I need to do in my program using \myoval{Postscript in LaTeX} program.

\end{document}

在此处输入图片描述

网上有很多关于 PostScript 编码的资源。在发布的在这个网站. 即,

\def关于vs 的最后一点\newcommand

也许值得你花点时间仔细阅读以下问题和答案:\def和有什么区别\newcommand。很容易误用\def和破坏基本命令,从而对代码造成灾难性的影响。我自己的方法是使用和\def\newcommand表示\newcommand我打算在文档(用户界面)级别使用的命令。我使用\def和来表示使用户级界面执行我想要的操作的底层命令。而且,这个网站上有相当多的人似乎采取这种方法。如果你不确定哪些宏名已经被使用,那么你可以采取以下方法

\newcommand\mymacroname{}
\def\mymacroname{<my real definition>}

这种方法的优点是,如果\mymacroname已经定义了,则会发出警告,\newcommand这样您就不会意外地破坏您可能依赖的东西(并且有很多宏是您在不知情的情况下依赖的)。您可能会想,如果我这样做,为什么还要费心使用\def?好吧,\def您可以使用非常规方式将参数传递给\newcommand。有一个包xparse实际上允许您以比危险性小得多的方式创建这种非常规方法\def:值得一读。

我使用时做的第二件事\def是给它提供一个复杂的名称,以明确三件事:(1)我是它的作者,(2)我使用它的目的,(3)它的用途。因此,对于上面的宏\myoval,我可能有各种宏名称:

\def\ae@boxtext@determine@dimensions#1{....}

其中,ae表示我是谁、boxtext表示我使用此命令的目的,并determine@dimensions说明了该宏应该做什么。

答案2

我可以在这里使用 给出“圆角框问题”的解决方案\pdfliteral。仅用于与 PostScript 解决方案进行比较。这可以帮助您完成作业,因为您可以看到如何避免使用curveto运算符的想法。此解决方案只是对我的另一个答案的轻微修改这里

\def\mybox#1{\leavevmode \setbox0=\hbox{#1}%
   \edef\posxA{\expandafter\ignorept\the\wd0 \space}%
   \hbox{\kern3pt\pdfliteral{q 1 0 0 rg 1 0 0 RG .9963 0 0 .9963 0 0 cm
            1 j 6 w 0 0 \posxA 5.5 re B 5 w 1 g 1 G 0 0 \posxA 5.5 re B Q}%
         \box0 \kern3pt}%
}
{\lccode`\?=`\p \lccode`\!=`\t  \lowercase{\gdef\ignorept#1?!{#1}}}

This is a \mybox{test} of my \mybox{rounded box}.

结果:圆形的

主要思想是测量圆角框的宽度并将结果设置为\posxA(无pt单位)。运算符.9963 0 0 .9963 0 0 cm等于 PostScript .9963 .9963 scale,它将坐标系中的默认 PDF/PostScript 单位(bp)转换为 TeX 单位(pt)。然后绘制两个矩形。第一个矩形的轮廓直径为 6 pt(带圆角),颜色为红色。第二个矩形的轮廓直径为 5 pt,颜色为白色。可见结果只有第一个红色矩形的边框,厚度为 0.5pt。

答案3

为了进一步比较,这里有一个使用该gmp包嵌入 Metapost 图形的解决方案。这里,PostScript 的使用当然完全隐藏在 MP 语言后面,因此它可能不符合 OP 作业要求。

\documentclass{article}
\usepackage[shellescape]{gmp}
\newsavebox{\ringbox}
\newcommand{\ringer}[1]{\sbox\ringbox{#1}%
    \lower4pt\hbox to \wd\ringbox
    {\hss\smash{\MPring{\mpdim{\wd\ringbox}}{\mpdim{\ht\ringbox}}{red}}\hss}%
    \kern -\wd\ringbox \box\ringbox
}
\def\MPring#1#2#3{\begin{mpost}
        w := #1; h := #2; 
        path c; c = quartercircle scaled 4 shifted (w,1.2h)
                 -- quartercircle scaled 4 rotated  90 shifted (0,1.2h) 
                 -- quartercircle scaled 4 rotated 180 shifted (0,0)
                 -- quartercircle scaled 4 rotated 270 shifted (w,0)
                 -- cycle;
        for i=-100 upto 100: draw (left--right) scaled w rotated 42 shifted (6i,0)
        withcolor #3; endfor; clip currentpicture to c;
        draw c withcolor #3;
\end{mpost}}
\begin{document}

In theory, the interrelation of system and/or subsystem technologies must utilize
and be functionally interwoven with the preliminary qualification limit.  In
particular, any \ringer{associated supporting element} necessitates that
urgent consideration be applied to possible bidirectional logical
relationship approaches.  

\end{document}

有关解释,您可以阅读gmpCTAN 上的软件包。请注意,由于我使用了shellescape包选项,因此您需要使用它来编译它pdflatex -shell-escape

在此处输入图片描述

相关内容