马上注册,结识高手,享用更多资源,轻松玩转三维网社区。
您需要 登录 才可以下载或查看,没有帐号?注册
x
摘 要 介绍了在线切割机上实现切割汉字的自动编程技术,将从字库中提取的字形轮廓经适当编辑处理后生成切割指令,可使线切割机增加切割汉字的功能。# J& |1 R1 g3 F2 t2 L: @8 T- W
1 引言 随着现代计算机和控制技术的发展,人们为线切割机装备了基于PC机且功能愈来愈强大的编程和控制系统,使线切割机的应用技术不断有新的发展。编程控制系统的发展是线切割加工技术发展的一个重要方面。对编程系统来讲,先是通过专用语言对待加工零件进行描述,然后转化为切割指令实现自动编程,后又把CAD技术引入编程中,从而实现了图形式输入方式,大大提高了编程效率和质量;在控制技术上,则从早期的开环控制过渡到了检测多个加工状态参数的自适应控制系统乃至模糊控制系统。8 W+ t; }: a# B4 ]
但直到现在,线切割机的应用范围还主要限制在机械零部件及模具的加工上,在线切割机上实现切割汉字可以说是一个空白。针对我国的国情,实现对汉字的切割既有现实的市场需求,又有广阔的应用前景。
/ x+ {. {$ J; X# h 在线切割机上进行加工,首先要通过编程系统将待加工零件转化为切割指令。为此要实现切割汉字的功能,也必须将要切割的汉字字形轮廓转化为切割指令。本文将从几个方面具体讲述在Windows操作系统的PC平台上,从TrueType字库中提取汉字字形轮廓,并将其转化为切割指令的自动编程技术。 2 字形轮廓的提取 要实现切割汉字首先要获得汉字字形轮廓,这涉及到如何从字库中提取汉字字形轮廓的问题。汉字的字体根据其实现形式的不同可分为点阵字体、
/ y- ?! \! Y+ I1 ^# E$ G& {矢量字体及TrueType字体等几种。其中使用最广泛的为TrueType字体,与其他字体相比,TrueType字体具有明显的优点:
% G) b0 W' q+ H' Q9 d+ e7 f, e0 f6 } (1)它使用直线和曲线对字符进行描述,具有放大和缩小不变形的特点;
, _. e/ p6 `; i( n (2)具有处理速度快及与设备无关的特点;6 G8 f8 ]; p$ C5 C6 Z! a
(3)它是Windows系统所使用的最广泛的字体,因而Windows提供了大量的API函数来支持和处理这种字体,利用这些函数可方便地对TrueType字符进行各种处理,如旋转、变形等。0 n) d0 }' [! @3 }. Y( x
在TrueType字体中,字形轮廓是由一些直线和曲线的集合及一些对字体的描述信息所组成,这些直线和曲线定义了TrueType字体及符号的外形轮廓,而那些字体的描述信息则用来控制和调整直线的长度和曲线的形状,主要用来调整字形轮廓尺寸,使用这些描述信息可对TrueType字体或符号在保持其原始形状的情况下进行放大、缩小等处理。' _; c3 B, f% N
Windows提供了许多函数来处理TrueType字体,其中与提取字形轮廓有关的最主要的函数为GetGlyphOutline,它可用来提取被选择到指令设备环境(如内存、显示设备等)的字符的轮廓或位图。在Windows API中,GetGlyphOutline函数声明如下:
% ^* m3 r, j; e) b+ e- G6 m DWORD GetGlyphOutiline(
6 S- X2 ?3 H1 c" @% B HDC hdc,∥设备环境的句柄
9 v, s3 t. o' m! y1 c8 @- m UINT uChar,∥所要查询的字符1 O7 e9 u+ m0 H7 j6 H5 _: | k+ L/ \
UINT uFormat,∥所要返回的数据类型
8 f; z3 Y0 _0 Q& }+ M+ w0 q7 d LPGLYPHMETRICS lpgm,∥指向字符规格结构的地址6 i! N G* b0 y0 S( W
DWORD cbBuffer,∥数据缓冲区的大小2 O& [: S/ T4 S3 C* L5 L. E$ V
LPVOLD lpvBuffer,∥数据缓冲区的地址
; W* ?; w8 T) |# Q CONST MAT2*lpmat2,∥变换矩阵结构的地址);. H M" ]. k; Q$ |1 ^
其中的主要参数说明如下:
; F3 K: k4 Z% Q. u5 m% b uChar:指定所要查询的字符,对汉字来说是指汉字的编码,如:GB-2312和Unicode等编码。
1 E1 C& q E4 `7 }! ?4 b1 e$ d" W uFormat:指定函数所要提取的数据的格式,可取下面一些值:GGO_ITMAP、GGO_NATIVE、GGO_METRICS、GGO_GRAY2_BITMAP、GGO_GRAY4_BITMAP、GGO_GRAY8_BITMAP。
7 x1 s# I' F! j% I, F* j8 c 对于提取字符的字形轮廓来说,由于只需得到字形轮廓的二值图象,不用得到灰度图象,因此uFormat参数可取两个值:GGO_BITMAP、GGO_NATIVE。如取GGO_BITMAP,函数将返回字符的字形轮廓位图;取GGO_NATIVE,函数将返回用来描述字符外形轮廓的曲线的点的数据,使用的单位是字体设计的单位,如uFormat参数取值为GGO_NATIVE,则任何lpmat2参数指定的变换矩阵将被忽略。由于可能需对提取出的字形轮廓作一定的变换处理(如:放大、缩小、旋转及改变纵、横比等),将参数uFormat的值设置为GGO_NATIVE。: E3 T, N6 d; G" Y5 e
调用GetGlyphOutline,函数将返回一系列的折线和样条曲线,返回的折线和曲线的信息存储在一个 TTPOLYGONHEADER结构及紧随其后的多个TTPOLYCURVE结构中,这些信息主要为描述折线和曲线所需的点的坐标,要描述字形轮廓须使用这些信息。上述两个结构中所有的点都以POINTFX结构形式返回,这些点描述的是绝对位置而不是相对位置。要描绘一个TrueType字符的字形轮廓,须同时使用折线和曲线。TTPOLYGONHEADER结构中的pfxStart成员返回字形的封闭轮廓的起始点,也是封闭轮廓的终止点。( ?! p* V* K k* G+ J
下面对其中几个重要的数据结构作简要的说明。
' g8 s! d5 @# O 其中,TTPOLYGONHEADER结构指定一个TrueType字符的字形轮廓的起始点及该轮廓的类型(直线或曲线)。其定义为:
- o4 N6 f+ b( _0 y L typedef struct_TTPOLYGONHEADER{//ttph- O6 z: _+ ]4 U" F: ]
DWORD cb;
4 d4 o3 G6 U; L. a5 j' _ DWORD dwType;( B7 C5 T6 N4 ^9 }, I
POINTFX PfxStart;
6 I5 f* E4 Y" I4 n) t$ k# [" Q }TTPOLYGONHEADER,FAR.LPTTPOLYGONHEADER;
, t4 _, S; S6 @) B( B 其中成员cb指定描述字形轮廓的TTPOLYGONHEADER结构和TTPOLYCURVE结构所需的字节数;dwType字符的轮廓类型;pfxStart指定轮廓的起始点。
f3 g, M2 M, h) G7 l TTPOLYCURVE结构中包含了TrueType字符中有关字形轮廓曲线的信息。其定义为:3 Y. e9 {$ t$ w, z) e9 M9 p6 y
typedef struct tagTTPOLYCURVE { // ttpc
" Z! K. [% T! n- t9 N WORD WType;- K k: ]$ V1 n- d. A5 [
WORD Cpfx;
# M* B; D. d5 x8 P5 U* `$ `/ a POINTFX apfx [1];
7 F' |4 e+ A% b- a5 O } TTPOLYCURVE,FAR*LPTTPOLYCURVE;/ L6 i4 ^: o Z" s3 {$ W" `
其中成员wType指定TTPOLYCURVE结构所描述的曲线类型,可有两个取值;TT_PRIM_LINE和TT_PRIM_OSPLINE,分别代表曲线是折线和B样条曲线;cpfx指定数组中POINTFX结构的数目;apfx指定一个确定折线或者B样条曲线的POINTFX结构类型的数组。/ n+ ~9 k6 E! ]% q8 U2 h: b
POINTFX结构中包含用来描述TrueType字符字形轮廓的点的坐标,其定义为:0 I% S0 a: S5 d6 M% q3 _; a3 W
typedef struct tagPOINTFX { // ptfx
3 n/ p( G1 L9 I, H; h* Q FIXED X;! `# n$ Y. u& N8 s
FIXED Y; f2 W: i( V! s" t" N
} POINTFX,6 O1 r/ w5 h3 Q" P: |; I9 t+ P+ ]
其中X和Y分别代表点的横、纵坐标。
( E) ]' |3 E( s! C$ q1 T% F 在调用GetGlyphOutline函数得到描述字形轮廓的数据后,要将其描绘出来还需调用绘制直线和曲线的函数。一个TrueType字符由折线和二次样条曲线描绘而成,调用GetGlyphOutline函数返回了描绘这些折线和曲线所需的点的有关信息,这些信息存储在TTPOLYGONHEADER和TTPOLYCURVE结构中,根据其中的成员wType所指定的不同值,来调用Windows API所提供的相关绘制折线和样条曲线的函数,即可绘制出字符的字形轮廓。在绘制时还可根据需要对字形轮廓进行各种处理,如放大、缩小、旋转及改变字符的纵横比等。图1显示了采用以上方法提取的“电”字的字形轮廓。 图1 “电”字的字形轮廓 还有一个需解决的问题是如何获得汉字编码的问题。通常汉字是以字符串的形式输入计算机的,要调用GetGlyphOutline函数得到某一汉字的字形轮廓,还须得到该汉字的编码(一般指GB-2312编码,在Windows NT和Windows 2000下可使用Unicode编码),用来指定GetGlyphOutline函数中的uChar参数,这就需进行由字符串到汉字编码的转换。下面给出了用Delphi实现的由汉字字符串到汉字的GB-2312编码的转换函数,该函数的输入参数为字符串的形式的单个汉字,返回值为输入参数汉字的GB-2312编码。3 _* S- O, G [- k' b8 d/ B l6 u
function CodeConvert(s:string):interger;
7 _ y) t+ {- d) w8 \2 f! j begin, ], z# G8 G7 y) A, u
result:=ord(WORD(s[1]shl 8)+WORD(s[2]));/ S# m1 l3 m: J% R
end; 3 字形轮廓二值图象的转化及其编辑处理 由于受线切割机所能切割图形形状的限制,即在不重新穿丝的情况下,只能切割一笔画成的图形;加上汉字数量众多,字形千变万化,且大多数汉字都不能一笔写成,因此将汉字的字形轮廓提取出来后并不能直接用于切割,还需对其进行一定的编辑处理,使其符合线切割加工的需要,即把它变成能一笔写成的切割轨迹。且实际应用中,多数情况下可能不是切割单个汉字而需一次切割多个汉字,这也要进行编辑处理。而要进行编辑处理,首先要将图形转化为图象。还是以“电”字为例,在未经编辑处理时,在线切割机上只能切割出如图2所示的不完整字形,在经过适当的编辑处理后,线切割机就可加工出如图3所示的完整汉字的字形了。 图2 未经编辑处理时线切割机所能加工的“电”字字形轮廓 图3 编辑处理后线切割机所能加工的“电”字字形轮廓 因为我们只需标识字形的边界轮廓,因此将其转化为二值图象即可。将字形轮廓转化为二值图象,也就是将其转化为一个用矩阵表示的象素点图象,矩阵中的每一位都是二进制数,当该位为1时表示字符的笔划经过此位,该位为0时表示字符的笔划不经过此位。因为只要分辨出某点为0还是1,因此每个点只要用一位二进制数表示即可,这样1个字节就可以表示8个象素点,但为方便叙述本文采用以1个字节表示1个点来进行说明。
( h/ i( l1 {0 G4 X$ R3 X 要将字形轮廓转化为二值图象,首先根据需要(如字体、尺寸大小、纵横比、是否旋转、变形等)在屏幕上绘制出所要切割字符的字形轮廓;然后对图形进行扫描,将有笔划通过的点(对应于与字符颜色相同象素的位)的值置为1,而其它的点则置为0,扫描完毕后便将字形轮廓转化为二值图象了。/ I4 S, O* J4 I# C( g3 a) x
生成二值图象后还需对图象进行适当的修改,以满足线切割加工的需要。对图象进行编辑处理,可用一个小方块代替一个放大了的象素,通过建立网格编辑区,每一网格小方块都是一个放大了的象素,这样可对每个象素进行编辑处理,控制鼠标在相应的网格眼内填入字符或背景颜色,同时填入字符颜色所对应的位置为1,填入背景颜色所对应的位置为0。 4 切割指令的生成 将汉字的字形轮廓转化为二值图象且编辑处理后,为生成切割指令须用直线或圆弧对其进行描述,由于汉字字形较适合用直线来对其进行描述,因此采用直线段来实现对汉字字形的描述。4 M' @# T. {7 g( v+ ]
由于线切割机所能切割的图形具有一定的特殊性(即需能以一笔画完),因此只需采用某种算法对图进行一次遍历便可得到加工轨迹。
/ u& P; H8 ]1 _2 F7 a 要对图象进行遍历,首先需确定搜索策略。由于能被切割的图形具有特殊性,采用改进了的深度优先搜索方法来对图象进行遍历。主要思想为:先确定图象的起始点,然后沿逆时针方向在该点周围寻找下一点,找到后沿着这两点确定的方向继续搜索,直至将该方向上的点搜索完毕,然后回溯,以回溯得到的点为基础重复以上搜索,直至所有点都被搜索过,在搜索过程中将经过的点的值从1置为0,同时记录所经过的直线。
1 q# {! T2 P0 \3 {6 l5 J/ e0 f3 X 下面介绍一下所要用到的主要数据结构。
7 \8 r- x, g9 ?- Q 记录直线所用结构为TLineRecord,它用来记录每段直线的起点和终点坐标,其定义如下:
. k! |8 O1 }9 w* V2 l2 o, A; g7 I+ j% [ TLineRecord=record0 e, P1 Z- S, K9 |, `
StartPoint, EndPoint: TPoint; //直线起始点,终止点6 J) F" U1 B2 k. n
end;# {5 o+ F# S- R% }2 ]: p- J
PLineRecord=^TLineRecord;
; }) R% @" ]2 h8 o% q% \; y 其中StartPoint, EndPoint分别为直线的起点和终点。: {) I7 a+ T2 Z
图象采用二维数组进行表示,首先按照行、列从小到大的顺序找到图象的起始点,然后再采用逆时针方向来搜索下一点。搜索方向的定义为:
2 R2 r! i/ q& v9 Z3 c( L- s SearchDirection:array[0..7,0..1] of interger=((1,0),(1,-1),(0,-1),(-1,-1),(-1,0),(-1,1),(0,1),(1,1));6 j% v- s0 a) W$ q
遍历算法如下:, C* i( C/ i& ]7 ~, N* V6 M
|