我可以在 TeX 中将字母的贝塞尔控制点可视化吗?

我可以在 TeX 中将字母的贝塞尔控制点可视化吗?

在对字体一无所知的情况下,我无意中阅读了文章关于 Postscript/Truetype 贝塞尔曲线。

文章中的第一张图片展示了这封信,以及它的贝塞尔控制点。我想看看更多的字母(也包括希腊字母)及其贝塞尔构造。

因此我安装了该程序字体并从计算机现代字体(我相信)中加载了一封信/usr/share/texmf-dist/fonts/type1/public/amsfonts/cm/cmr10.pfb

欧米茄

这种可视化在技术上可能很有用,但不太令人满意。所以,我想知道,它可以在 TeX 中完成吗?也许使用 TikZcontrols函数: 在此处输入图片描述

此选项的说明:也可以用 TikZ 绘制字母,但我对控制点的良好可视化更感兴趣。

这肯定不容易,因为字体是以二进制格式存储的。也许可以转换?

编辑

  • @g.kov 使用以下方式展示了很好的可视化效果渐近线
  • 我修改了 Andrew Stacy 的剧本这个问题,我对此非常满意。见下文。

答案1

在此处输入图片描述

texpath()可以使用以下函数提取字形路径的控制点Asymptote

// glyph.asy :
//
size(7cm);
import fontsize;

defaultpen(fontsize(9pt));

real wd=0.6bp;
pen dotPen=deepblue+wd;
pen dotFill=dotPen;

pen dotPenB=blue+wd;
pen dotPenC=red+wd;

pen linePen=deepblue+wd;
pen fillPen=lightgreen+opacity(0.1);

pen thinLinePen=black+wd/2;


guide[] g;

g=texpath("$\Omega$");

filldraw(g,fillPen,linePen);

pair a,b,c,d;
pair labdir;
int pointNo=0;

for(int i=0;i<g.length;++i){
  for(int j=0;j<size(g[i])-1;++j){
    a=point(g[i],j);
    d=point(g[i],j+1);
    if(straight(g[i],j)){
      draw(a--d,thinLinePen);    
    }else{
      b=postcontrol(g[i],j);
      c=precontrol(g[i],j+1);
      draw(a--b--c--d,thinLinePen);
      dot(b,dotPenB,UnFill);
      dot(c,dotPenC,UnFill);
    }
    dot(a,dotPen,Fill(dotFill));
    labdir=rotate(-90)*dir(g[i],j);
    label("$\scriptsize "+string(pointNo)+"$",a,labdir);
    ++pointNo;
  }
  dot(d,dotPen,Fill(dotFill));
  labdir=rotate(-90)*dir(g[i],size(g[i])-1);
  label("$\scriptsize "+string(pointNo)+"$",d,labdir);
}

要获取 glyph.pdf,请运行:

asy -f pdf glyph.asy

答案2

修改后安德鲁的剧本,我得到:

在此处输入图片描述 欧米茄 百分号 字母g

怎么做:

  1. fontforge 脚本font2svg.fontforge

    #! /usr/bin/env fontforge
    Open($1)
    Generate($1:t:r + ".svg")
    
  2. 跑步 (chmod +x font2svg.fontforge

    ./font2svg.fontforge /usr/share/texmf-dist/fonts/type1/public/amsfonts/cm/cmr10.pfb
    

    将文件cmr10.svg放入您的文件夹。例如字母“Omega”:

    <glyph glyph-name="Omega" unicode="&#x2126;" horiz-adv-x="722"              
    d="M677 162l-33 -162h-159c-23 0 -26 0 -26 21c0 69 32 159 47 201c29 82 56 158 56 233c0 156 -106 228 -202 228c-91 0 -201 -68 -201 -228c0 -75 28 -154 49 -212c23 -64 54 -152 54 -222c0 -21 -3 -21 -25 -21h-160l-33 162h25c5 -25 10 -51 18 -74c5 -15 8 -23 66 -23
    h80c-13 56 -45 104 -89 170c-47 71 -88 140 -88 219c0 137 133 251 305 251c169 0 304 -112 304 -251c0 -79 -41 -148 -88 -219c-45 -66 -76 -114 -89 -170h80c58 0 61 8 66 24c9 24 13 47 18 73h25z" />
    

    很好,这些是路径规范。

  3. 运行修改脚本

    ./svgtopgf_mime.pl crm10.svg tmpstr
    

    我对 Andrew 的修改。它现在为每个字形写入三个文件

    • chars/gly_<prefix>N,其中N是十进制 Unicode 编号。此文件包含字形路径(与原始脚本的输出几乎相同)。
    • chars/bezier_<prefix>N包含贝塞尔控制手柄。TikZ 3.0 箭头。
    • chars/pts_<prefix>N包含字形轮廓上的所有点(未使用)
  4. 然后,绘制新的字形就像将它们包含在 tex 文件中一样简单:

    \documentclass[a4paper]{article}
    \usepackage{tikz} % loads xcolor
    \usetikzlibrary{arrows.meta}
    \begin{document}
    \definecolor{solbglight}{HTML}{FDF6E3}
    \definecolor{solblue}{HTML}{268BD2}
    \definecolor{solmagenta}{HTML}{D33682}
    \pagecolor{solbglight}
    
    %Omega
    \begin{tikzpicture}[scale=18]
    \input{chars/gly_tmpstr8486}
    \pgfusepath{fill}%
    \begin{scope}[thick,solblue]
      \input{chars/bezier_tmpstr8486}
    \end{scope}
    \end{tikzpicture}
    
    %Percent sign
    \begin{tikzpicture}[scale=15]
    \input{chars/gly_tmpstr37}
    \pgfusepath{fill}%
    \begin{scope}[thick,solblue]
      \input{chars/bezier_tmpstr37}
    \end{scope}
    \end{tikzpicture}
    
    %g
    \begin{tikzpicture}[scale=25]
    \input{chars/gly_tmpstr103}
    \pgfusepath{fill}%
    \begin{scope}[thick,solblue]
      \input{chars/bezier_tmpstr103}
    \end{scope}
    \end{tikzpicture}
    
    \end{document}
    

答案3

Metapost 也允许您使用运算符执行此glyph操作。

在此处输入图片描述

这是由第 9 节的字形可视化程序生成的MP手册,从“cmr10”改为显示 Ω,如下所示。

字体的名称是相关映射文件中定义的名称(通常是pdftex.map),而字形的名称则是通常的 PostScript 名称(参见附录 E)。PS 语言参考手册请参阅列表)。

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

beginfig(1);
  picture q;
  path p;
  interim ahlength := 9bp;
  interim ahangle := 25;
  q := glyph "Omega" of "cmr10" scaled .2;
  for item within q:
    p := pathpart item;
    drawarrow p withcolor (.6,.9,.6) withpen pencircle scaled 1.5;
    for j=0 upto length p:
      pickup pencircle scaled .7;
      draw (point j of p -- precontrol  j of p) dashed evenly withcolor blue;
      draw (point j of p -- postcontrol j of p) dashed evenly withcolor blue;
      pickup pencircle scaled 3;
      draw precontrol j of p withcolor red;
      draw postcontrol j of p withcolor red;
      pickup pencircle scaled 2;
      draw point j of p withcolor black;
    endfor
  endfor
endfig;
end.

相关内容