電火花線切割切割漢字的編程技巧
電火花線切割要實(shí)現(xiàn)切割漢字首先要獲得漢字字形輪廓,這涉及到如何從字庫(kù)中提取漢字字形輪廓的問題。漢字的字體根據(jù)其實(shí)現(xiàn)形式的不同可分為點(diǎn)陣字體、矢量字體及TrueType字體等幾種。其中使用最廣泛的為TrueType字體,與其他字體相比,TrueType字體具有明顯的優(yōu)點(diǎn):
(1)它使用直線和曲線對(duì)字符進(jìn)行描述,具有放大和縮小不變形的特點(diǎn);
(2)具有處理速度快及與設(shè)備無關(guān)的特點(diǎn);
(3)它是Windows系統(tǒng)所使用的最廣泛的字體,因而Windows提供了大量的API函數(shù)來支持和處理這種字體,利用這些函數(shù)可方便地對(duì)TrueType字符進(jìn)行各種處理,如旋轉(zhuǎn)、變形等。
在TrueType字體中,字形輪廓是由一些直線和曲線的集合及一些對(duì)字體的描述信息所組成,這些直線和曲線定義了TrueType字體及符號(hào)的外形輪廓,而那些字體的描述信息則用來控制和調(diào)整直線的長(zhǎng)度和曲線的形狀,主要用來調(diào)整字形輪廓尺寸,使用這些描述信息可對(duì)TrueType字體或符號(hào)在保持其原始形狀的情況下進(jìn)行放大、縮小等處理。
Windows提供了許多函數(shù)來處理TrueType字體,其中與提取字形輪廓有關(guān)的最主要的函數(shù)為GetGlyphOutline,它可用來提取被選擇到指令設(shè)備環(huán)境(如內(nèi)存、顯示設(shè)備等)的字符的輪廓或位圖。在Windows
API中,GetGlyphOutline函數(shù)聲明如下:
DWORD GetGlyphOutiline(
HDC hdc,∥設(shè)備環(huán)境的句柄
UINT uChar,∥所要查詢的字符
UINT uFormat,∥所要返回的數(shù)據(jù)類型
LPGLYPHMETRICS lpgm,∥指向字符規(guī)格結(jié)構(gòu)的地址
DWORD cbBuffer,∥數(shù)據(jù)緩沖區(qū)的大小
LPVOLD lpvBuffer,∥數(shù)據(jù)緩沖區(qū)的地址
CONST MAT2*lpmat2,∥變換矩陣結(jié)構(gòu)的地址);
其中的主要參數(shù)說明如下:
uChar:指定所要查詢的字符,對(duì)漢字來說是指漢字的編碼,如:GB-2312和Unicode等編碼。
uFormat:指定函數(shù)所要提取的數(shù)據(jù)的格式,可取下面一些值:GGO_ITMAP、GGO_NATIVE、GGO_METRICS、GGO_GRAY2_BITMAP、GGO_GRAY4_BITMAP、GGO_GRAY8_BITMAP。
對(duì)于提取字符的字形輪廓來說,由于只需得到字形輪廓的二值圖象,不用得到灰度圖象,因此uFormat參數(shù)可取兩個(gè)值:GGO_BITMAP、GGO_NATIVE。如取GGO_BITMAP,函數(shù)將返回字符的字形輪廓位圖;取GGO_NATIVE,函數(shù)將返回用來描述字符外形輪廓的曲線的點(diǎn)的數(shù)據(jù),使用的單位是字體設(shè)計(jì)的單位,如uFormat參數(shù)取值為GGO_NATIVE,則任何lpmat2參數(shù)指定的變換矩陣將被忽略。由于可能需對(duì)提取出的字形輪廓作一定的變換處理(如:放大、縮小、旋轉(zhuǎn)及改變縱、橫比等),將參數(shù)uFormat的值設(shè)置為GGO_NATIVE。
調(diào)用GetGlyphOutline,函數(shù)將返回一系列的折線和樣條曲線,返回的折線和曲線的信息存儲(chǔ)在一個(gè)
TTPOLYGONHEADER結(jié)構(gòu)及緊隨其后的多個(gè)TTPOLYCURVE結(jié)構(gòu)中,這些信息主要為描述折線和曲線所需的點(diǎn)的坐標(biāo),要描述字形輪廓須使用這些信息。上述兩個(gè)結(jié)構(gòu)中所有的點(diǎn)都以POINTFX結(jié)構(gòu)形式返回,這些點(diǎn)描述的是絕對(duì)位置而不是相對(duì)位置。要描繪一個(gè)TrueType字符的字形輪廓,須同時(shí)使用折線和曲線。TTPOLYGONHEADER結(jié)構(gòu)中的pfxStart成員返回字形的封閉輪廓的起始點(diǎn),也是封閉輪廓的終止點(diǎn)。
下面對(duì)其中幾個(gè)重要的數(shù)據(jù)結(jié)構(gòu)作簡(jiǎn)要的說明。
其中,TTPOLYGONHEADER結(jié)構(gòu)指定一個(gè)TrueType字符的字形輪廓的起始點(diǎn)及該輪廓的類型(直線或曲線)。其定義為:
typedef struct_TTPOLYGONHEADER{//ttph
DWORD cb;
DWORD dwType;
POINTFX PfxStart;
}TTPOLYGONHEADER,FAR.LPTTPOLYGONHEADER;
其中成員cb指定描述字形輪廓的TTPOLYGONHEADER結(jié)構(gòu)和TTPOLYCURVE結(jié)構(gòu)所需的字節(jié)數(shù);dwType字符的輪廓類型;pfxStart指定輪廓的起始點(diǎn)。
TTPOLYCURVE結(jié)構(gòu)中包含了TrueType字符中有關(guān)字形輪廓曲線的信息。其定義為:
typedef struct tagTTPOLYCURVE { // ttpc
WORD WType;
WORD Cpfx;
POINTFX apfx [1];
} TTPOLYCURVE,FAR*LPTTPOLYCURVE;
其中成員wType指定TTPOLYCURVE結(jié)構(gòu)所描述的曲線類型,可有兩個(gè)取值;TT_PRIM_LINE和TT_PRIM_OSPLINE,分別代表曲線是折線和B樣條曲線;cpfx指定數(shù)組中POINTFX結(jié)構(gòu)的數(shù)目;apfx指定一個(gè)確定折線或者B樣條曲線的POINTFX結(jié)構(gòu)類型的數(shù)組。
POINTFX結(jié)構(gòu)中包含用來描述TrueType字符字形輪廓的點(diǎn)的坐標(biāo),其定義為:
typedef struct tagPOINTFX { // ptfx
FIXED X;
FIXED Y;
} POINTFX,
其中X和Y分別代表點(diǎn)的橫、縱坐標(biāo)。
在調(diào)用GetGlyphOutline函數(shù)得到描述字形輪廓的數(shù)據(jù)后,要將其描繪出來還需調(diào)用繪制直線和曲線的函數(shù)。一個(gè)TrueType字符由折線和二次樣條曲線描繪而成,調(diào)用GetGlyphOutline函數(shù)返回了描繪這些折線和曲線所需的點(diǎn)的有關(guān)信息,這些信息存儲(chǔ)在TTPOLYGONHEADER和TTPOLYCURVE結(jié)構(gòu)中,根據(jù)其中的成員wType所指定的不同值,來調(diào)用Windows
API所提供的相關(guān)繪制折線和樣條曲線的函數(shù),即可繪制出字符的字形輪廓。在繪制時(shí)還可根據(jù)需要對(duì)字形輪廓進(jìn)行各種處理,如放大、縮小、旋轉(zhuǎn)及改變字符的縱橫比等。圖1顯示了采用以上方法提取的“電”字的字形輪廓。
圖1 “電”字的字形輪廓
還有一個(gè)需解決的問題是如何獲得漢字編碼的問題。通常漢字是以字符串的形式輸入計(jì)算機(jī)的,要調(diào)用GetGlyphOutline函數(shù)得到某一漢字的字形輪廓,還須得到該漢字的編碼(一般指GB-2312編碼,在Windows
NT和Windows
2000下可使用Unicode編碼),用來指定GetGlyphOutline函數(shù)中的uChar參數(shù),這就需進(jìn)行由字符串到漢字編碼的轉(zhuǎn)換。下面給出了用Delphi實(shí)現(xiàn)的由漢字字符串到漢字的GB-2312編碼的轉(zhuǎn)換函數(shù),該函數(shù)的輸入?yún)?shù)為字符串的形式的單個(gè)漢字,返回值為輸入?yún)?shù)漢字的GB-2312編碼。
function CodeConvert(s:string):interger;
begin
result:=ord(WORD(s[1]shl 8)+WORD(s[2]));
end;
3 字形輪廓二值圖象的轉(zhuǎn)化及其編輯處理
由于受線切割機(jī)所能切割圖形形狀的限制,即在不重新穿絲的情況下,只能切割一筆畫成的圖形;加上漢字?jǐn)?shù)量眾多,字形千變?nèi)f化,且大多數(shù)漢字都不能一筆寫成,因此將漢字的字形輪廓提取出來后并不能直接用于切割,還需對(duì)其進(jìn)行一定的編輯處理,使其符合線切割加工的需要,即把它變成能一筆寫成的切割軌跡。且實(shí)際應(yīng)用中,多數(shù)情況下可能不是切割單個(gè)漢字而需一次切割多個(gè)漢字,這也要進(jìn)行編輯處理。而要進(jìn)行編輯處理,首先要將圖形轉(zhuǎn)化為圖象。還是以“電”字為例,在未經(jīng)編輯處理時(shí),在線切割機(jī)上只能切割出如圖2所示的不完整字形,在經(jīng)過適當(dāng)?shù)木庉嬏幚砗螅€切割機(jī)就可加工出如圖3所示的完整漢字的字形了。
圖2 未經(jīng)編輯處理時(shí)線切割機(jī)所能加工的“電”字字形輪廓
圖3 編輯處理后線切割機(jī)所能加工的“電”字字形輪廓
因?yàn)槲覀冎恍铇?biāo)識(shí)字形的邊界輪廓,因此將其轉(zhuǎn)化為二值圖象即可。將字形輪廓轉(zhuǎn)化為二值圖象,也就是將其轉(zhuǎn)化為一個(gè)用矩陣表示的象素點(diǎn)圖象,矩陣中的每一位都是二進(jìn)制數(shù),當(dāng)該位為1時(shí)表示字符的筆劃經(jīng)過此位,該位為0時(shí)表示字符的筆劃不經(jīng)過此位。因?yàn)橹灰直娉瞿滁c(diǎn)為0還是1,因此每個(gè)點(diǎn)只要用一位二進(jìn)制數(shù)表示即可,這樣1個(gè)字節(jié)就可以表示8個(gè)象素點(diǎn),但為方便敘述本文采用以1個(gè)字節(jié)表示1個(gè)點(diǎn)來進(jìn)行說明。
要將字形輪廓轉(zhuǎn)化為二值圖象,首先根據(jù)需要(如字體、尺寸大小、縱橫比、是否旋轉(zhuǎn)、變形等)在屏幕上繪制出所要切割字符的字形輪廓;然后對(duì)圖形進(jìn)行掃描,將有筆劃通過的點(diǎn)(對(duì)應(yīng)于與字符顏色相同象素的位)的值置為1,而其它的點(diǎn)則置為0,掃描完畢后便將字形輪廓轉(zhuǎn)化為二值圖象了。
生成二值圖象后還需對(duì)圖象進(jìn)行適當(dāng)?shù)男薷模詽M足線切割加工的需要。對(duì)圖象進(jìn)行編輯處理,可用一個(gè)小方塊代替一個(gè)放大了的象素,通過建立網(wǎng)格編輯區(qū),每一網(wǎng)格小方塊都是一個(gè)放大了的象素,這樣可對(duì)每個(gè)象素進(jìn)行編輯處理,控制鼠標(biāo)在相應(yīng)的網(wǎng)格眼內(nèi)填入字符或背景顏色,同時(shí)填入字符顏色所對(duì)應(yīng)的位置為1,填入背景顏色所對(duì)應(yīng)的位置為0。
4 切割指令的生成
將漢字的字形輪廓轉(zhuǎn)化為二值圖象且編輯處理后,為生成切割指令須用直線或圓弧對(duì)其進(jìn)行描述,由于漢字字形較適合用直線來對(duì)其進(jìn)行描述,因此采用直線段來實(shí)現(xiàn)對(duì)漢字字形的描述。
由于線切割機(jī)所能切割的圖形具有一定的特殊性(即需能以一筆畫完),因此只需采用某種算法對(duì)圖進(jìn)行一次遍歷便可得到加工軌跡。
要對(duì)圖象進(jìn)行遍歷,首先需確定搜索策略。由于能被切割的圖形具有特殊性,采用改進(jìn)了的深度優(yōu)先搜索方法來對(duì)圖象進(jìn)行遍歷。主要思想為:先確定圖象的起始點(diǎn),然后沿逆時(shí)針方向在該點(diǎn)周圍尋找下一點(diǎn),找到后沿著這兩點(diǎn)確定的方向繼續(xù)搜索,直至將該方向上的點(diǎn)搜索完畢,然后回溯,以回溯得到的點(diǎn)為基礎(chǔ)重復(fù)以上搜索,直至所有點(diǎn)都被搜索過,在搜索過程中將經(jīng)過的點(diǎn)的值從1置為0,同時(shí)記錄所經(jīng)過的直線。
下面介紹一下所要用到的主要數(shù)據(jù)結(jié)構(gòu)。
記錄直線所用結(jié)構(gòu)為TLineRecord,它用來記錄每段直線的起點(diǎn)和終點(diǎn)坐標(biāo),其定義如下:
TLineRecord=record
StartPoint, EndPoint: TPoint; //直線起始點(diǎn),終止點(diǎn)
end;
PLineRecord=^TLineRecord;
其中StartPoint, EndPoint分別為直線的起點(diǎn)和終點(diǎn)。
圖象采用二維數(shù)組進(jìn)行表示,首先按照行、列從小到大的順序找到圖象的起始點(diǎn),然后再采用逆時(shí)針方向來搜索下一點(diǎn)。搜索方向的定義為:
SearchDirection:array[0..7,0..1] of
interger=((1,0),(1,-1),(0,-1),(-1,-1),(-1,0),(-1,1),(0,1),(1,1));
遍歷算法如下:
(1)掃描圖象尋找起始點(diǎn),將其坐標(biāo)記為(k,1);用FirstPointX、FirstPointY記錄第一點(diǎn)橫、縱坐標(biāo)的值;
(2)初始化記錄直線的指針,建立記錄直線的鏈表;將起始點(diǎn)的k,1值作為直線起點(diǎn)和終點(diǎn)的橫、縱坐標(biāo),將該直線加入到直線紀(jì)錄的鏈表中去;
(3)以第一點(diǎn)為基準(zhǔn)點(diǎn)沿逆時(shí)針方向?qū)ふ蚁乱稽c(diǎn),如果搜索到值為1的點(diǎn)則記搜索方向?yàn)閕,該點(diǎn)的橫、縱坐標(biāo)記為(k,1),將記錄直線的終點(diǎn)橫、縱坐標(biāo)設(shè)置為k,1;
(4)置是否搜索完畢標(biāo)志SearchCompleted為False;
(5)如果SearchCompleted不為True則重復(fù)作6-13步;
(6)置SearchCompleted為True;
(7)置是否同一條線標(biāo)志SameLine為True;
(8)如果SameLine為True則重復(fù)作9-12步;
(9)置SameLine為False;
(10)沿i方向進(jìn)行搜索,即k:=k+SearchDirection [i][0];1:=1+SearchDirection [i][1];
(11)如果點(diǎn)(k,1)為1,則置SameLine為True;將直線的終點(diǎn)坐標(biāo)設(shè)置為(k,1);將點(diǎn)(k,1)的值設(shè)置為0;
(12)如果點(diǎn)(k,1)為0,則置SameLine為False;
(13)以點(diǎn)(k,1)為基準(zhǔn)點(diǎn)沿逆時(shí)針方向?qū)ふ蚁乱稽c(diǎn),如果搜索到值為1的點(diǎn),則記搜索方向?yàn)閕;在直線記錄列表中增加一條新的直線,k,1值作為直線起點(diǎn)的橫、縱坐標(biāo);將搜索到的點(diǎn)的橫、縱坐標(biāo)記為(k,1),將直線終點(diǎn)的橫、縱坐標(biāo)設(shè)置為(k,1);置Searhcompleted為False,置SameLine為True;將點(diǎn)(k,1)的值設(shè)置為0;
(14)進(jìn)行圖形封閉化處理,在直線記錄列表中增加一條直線,將k,1值作為直線起點(diǎn)的橫、縱坐標(biāo),F(xiàn)irstPointX、FirstPointY作為直線終點(diǎn)的橫、縱坐標(biāo)值。
這樣當(dāng)遍歷完成后,遍歷的軌跡就保存在直線記錄列表中了,也就是說已實(shí)現(xiàn)將漢字的字形輪廓用直線段進(jìn)行描述了。需指出的是,由于漢字字形本身或者編輯處理的原因,在進(jìn)行圖象遍歷的過程中,可能存在一些不和諧的點(diǎn),使遍歷不能完成(如存在斷點(diǎn)、尖點(diǎn)及多余點(diǎn)的情況),需在遍歷之前運(yùn)用圖象處理的技術(shù)將這些點(diǎn)補(bǔ)足或者剔除掉,以使遍歷能順利完成,有關(guān)這方面的算法不再贅述。
至此要實(shí)現(xiàn)切割漢字就只剩下如何生成切割指令的問題了。由于已將漢字的字形輪廓用直線進(jìn)行描述,且這些直線還首尾相接組成一個(gè)封閉輪廓,要生成線切割機(jī)的切割指令,只需按切割指令的要求將這些直線進(jìn)行轉(zhuǎn)換即可。
本文由中走絲,線切割機(jī)床,電解去毛刺,去毛刺設(shè)備-蘇州中航長(zhǎng)風(fēng)數(shù)控科技有限公司采集整理發(fā)布。
更多線切割,穿孔機(jī),電化學(xué)去毛刺文章資料請(qǐng)參考www.szcfedm.com www.zhchangfeng.com www.skwedm.com