细说元笔画
在搞汉字笔画组字时,必须用50种左右的汉字笔画。比较起来,英文字母似乎简单得多,好像可以只要半圆弧和直线段两种。实际却不然。因为半圆弧和直线段,都可有4种不同的方向,那就要8种元笔画。而且这8种元笔画,仍难以组成其它ASCII字符,此外还有大量各种拼音文字的不同字母及形态各异的日本假名。…………说实在,当我给自己提出这个任务后,很长一段时间里,还搞不清“元笔画”到底应该是怎样的。
经过反复摸索,慢慢变得清楚起来。现在我说的一个“元笔画”,是指可由简单的小程序画出的一类图形,文后附有最后使用的VB子程序。目前共7类,毎类用一个ASCII字符加几个参数(即字符串),就可画出需要的图形,再由它们组合成所有非汉字字符。这些类是:
元笔画名称 代表字符
1.线段 !
2.圆孤 @
3.螺旋形 &
4.多角形 #
5.波形 $
6.不定形 %
7.任意曲线 ~
我虽然把汉字库里的所有ASCII及其他非汉字字符都用这样的“元笔画”组出来了。但离我的最高目标(由它们能够很方便地组出所有文字,或所有字母),还很远,组出的字形也很差,还需要研究和创造。最后会成为什么样子,很难预料。汉字笔画也应该由元笔画组出。您看到,比笔画复杂得多的平假名都已用元笔画组出来了,组出所有汉字笔画是不困难的。这样,计算机真的不需要任何字模,完全无字库了。当然,常用的字母、字符、汉字笔画、字根等,应该有一定的标准写法,最好指定一个标准字符串并规定其内码。但它已不是现在意义下、用.ttf文件存贮的的字库了。如果仍要称它为字库,那么全世界就只有这一个字库,内码长度不超过2字节,所有文字都由它们组出。还可以写出种种符号,例如任意的八角星、十角星、十二角星,各种形状的序数符(如写在六角形内的序数)等等。
现在对现有的7种元笔画进一步进行解说。实际上只要说清下面的《元笔画各参数意义表》就可以了。每个元笔画是用一个“首符”再加几个作为参数的字符组成的串来表示的。前6种元笔画的参数都是数字0-9,前5种元笔画的参数最多只有5个,即表中列的a1~ a5,且可以缺省,各有一定的缺省值。例如无参数的一个字符“!”,是一水平线,缺省的参数值a1=0,位置在正中a2=5,宽度最小 a3=1,长度最大a4=9。实际用到绘图语句中,要乘以括弧内的数字,因为直线长度是从中点开始算的,所以少一半。a1不为0时,a1*18是直线的斜角,5*18=90度,所以“!5”就是一根位在中间的垂线,参数a1>5,则是向后倒的。参照此表,再在计算机上试验一下,不难得到需要的元笔画。
圆孤@的参数a1<6时,是简单的圆环,调节参数a2,可增环宽直至成黑圆点。参数a1>=6时,才是圆弧(有开口的圆环), a1-6=0~3是开口方向,0向右,1向上,2向左,3向下。开口角度等于a2*30,最大是240度。特别设a2=9,生成U字形,即开口是180度,与a2=6一样,但开口两边各接一段直线段,开口向上时,就是U,开口向其它3个方向,则是数学符号。这个元笔画的轮廓线主要由两个圆在两开口点连接而成。外圆固定为最大,内圆按宽度a3而缩小。a4=0时,两圆是同心圆,为了生成字符“C”,内圆要向右偏,弧的左边就比开口处宽厚,故要用串“@6311”。
螺旋形&的参数a1<3时,是发散的圆螺旋线,大于3时,则是螺旋折线,a1指一圈折线的角数。用a3还可整体顺转一定角度,以满足需要(上一个圆孤@的参数a5,下一个星形#的参数a3,也是起同样的作用)。
星形#的参数a3=0时,是实心的星形,a2为星形的内圆(星体)大小。a3>0时,实为多角形,如五角星应为“#221”,而“#22”则是有五个光芒的星形。
波形$的诸参数,意义清楚,用不着再加说明。
不定形%的参数一定要刚好是11个数字。除a1外的5对数字描述两条曲线,毎条曲线5个点。如果a1是偶数,曲线的走向是横向的,那么它们都在均匀分布的5条垂直线上,首尾两点在字符空间的左右两端,而毎对数字分别是上下两条曲线的纵向坐标。如果a1是奇数,毎对数字是分别是左右两条曲线的横向坐标。而a1的大小,则规定曲线是否经过平滑化,表中说得很清楚。例如字符“【”的串为“%55957565759”,a1=5,是奇数,曲线纵向,左曲线的横坐标都为5,是位居中部的垂直线,不平滑,右曲线横坐标依次是97679,曲线经平滑成凸向左边的圆弧。
任意曲线~的参数,是唯一可以用英文字母的,参数个数原则上无限制(实际受可存贮的字串长度的限制)。它是把写字符的空间,平分为8*7个方格,每个方格的位置指定一个字符表示,如表末尾所示。这样,一个字符串就可连一条折线,如果要多条线,中间可用0隔开(0不是点)。第一个参数a1是数字时,是指定曲线的宽度,如果是字母,则认为a1=0。a1还有区分曲线性质的作用,当a1<5时,曲线是平滑曲线,曲线的宽度等于a1+1;a1>5时,则是折线,宽度等于a1-4。日文片假名就可用这种元笔画生成,如串“~Cb0QLW0dO7ElvX”就会画出“ぁ”。
这些元笔画可以和汉字笔画、字根、汉字或其他字符本身,再组成更复杂的字符。这时,单个元笔画的结构属性是上下结构。要改为左右结构时,后加结构符“””。如果加“=”号,后面的笔画将叠加其上。要调节笔画位置,可用空白符Z,象汉字笔画组字中的z。
元笔画各参数意义表
元笔画 首符 参数a1 a2 a3 a4 a5
线段 ! 直线斜角 (*18) 水平位置(*70) 直线宽度 直线长度(*40)
0为水平线 垂直位置(*70) 直线宽度 直线长度(*40)
圆孤 @ <6为圆径 圆环宽度1-9
-6为开口方向 开口角度(9为U) 圆弧宽度1-9 内圆心偏离程度 整体顺转角度(*5)
螺旋形 & 2顺,1逆,0有圆心 旋线宽=旋线隙 整体顺转角度
>=3为一周角数 旋线宽=旋线隙 整体顺转角度
星形 # 星形的角数(+3) 星形的内圆大小
0 旋转角度
多角形的角数(+3) 间a2-1角连直线 连线宽度 旋转角度
波形 $ 波数 波幅 波线宽度 a4>0,波向垂直
不定形 % a1指定曲线的特性:奇数,方向垂直,等于1;3;5时,分别为两边;左边;右边已经平滑,否则是折线
偶数,方向水平,等于0;2;4时,分别为上下;上边;下边已经平滑,否则是折线
第二个数开始的10个数串指定的点组成封闭曲线。第02468和13579个数分别成左右两曲线。
任意曲线 ~ a1<5时为平滑曲线宽度(+1),a1>5时是折线,宽度为a1-4
任意曲线形由依次的符号点连成,各符号平面位置如下(碰到0则中断):
1 A
I Q a
i q
2 B
J R r
j r
3 C
K S c
k s
4 D
L T d
l t
5 E
M U e
m u
6 F
N V f
n v
7 G
O W g
o w
8 H
P X h p x
画元笔画的子程序txdrw
Sub txdrw(p)
'在p指定的pictureBox中,画已由zganalys分析,并记在zz中的元笔画图形
pp = p
Dim Pt(280) As POINTAPI '多边形顶点变量数组
Dim Pts(10) As POINTAPI
Dim hRgn, hBrush As Long '多边形句柄,画刷句柄
pi = 3.1415926535
z = Left(zz, 1): zz = Trim(zz)
a1 = Val(Mid(zz, 2, 1)): a2 = Val(Mid(zz, 3, 1))
a3 = Val(Mid(zz, 4, 1)): a4 = Val(Mid(zz, 5, 1)): a5 = Val(Mid(zz, 6, 1))
Select Case z
Case "!" '线段
a1 = pi * a1 * 18 / 180 'a1为直线角度
If a2 = 0 Then a2 = 5
a2 = a2 * 70 'a1=0时为a2为直线垂直位置,否则是水平位置
If a3 = 0 Then a3 = 1
If a4 = 0 Then a4 = 9
a3 = Atn(a3 / a4 / 2) 'a3为直线宽度
a4 = a4 * 33 'a4为直线长度
If a1 > 0 Then a4 = a4 / Sin(a1)
If a1 > 0 Then
Pt(0).x = a2 + a4 * Cos(a1 - a3): Pt(1).x = a2 + a4 * Cos(a1 + a3): Pt(2).x = a2 + a4 * Cos(pi + a1 - a3): Pt(3).x = a2 + a4 * Cos(pi + a1 + a3)
Pt(0).y = 350 - a4 * Sin(a1 - a3): Pt(1).y = 350 - a4 * Sin(a1 + a3): Pt(2).y = 350 - a4 * Sin(pi + a1 - a3): Pt(3).y = 350 - a4 * Sin(pi + a1 + a3)
Else
Pt(0).x = 350 + a4 * Cos(a1 - a3): Pt(1).x = 350 + a4 * Cos(a1 + a3): Pt(2).x = 350 + a4 * Cos(pi + a1 - a3): Pt(3).x = 350 + a4 * Cos(pi + a1 + a3)
Pt(0).y = a2 - a4 * Sin(a1 - a3): Pt(1).y = a2 - a4 * Sin(a1 + a3): Pt(2).y = a2 - a4 * Sin(pi + a1 - a3): Pt(3).y = a2 - a4 * Sin(pi + a1 + a3)
End If
Pt(4) = Pt(0)
Case "@" '圆孤
If a1 < 6 Then
a1 = a1 * 50 + 50 '以a1+1为半径的圆
For i = 0 To 71
Pt(i).x = 350 + a1 * Cos(i * pi / 35): Pt(i).y = 350 + a1 * Sin(i * pi / 35)
Next i
n0 = 72
If a1 <> 50 And a2 = 0 Then a2 = 1
If a2 > 0 Then
a1 = a1 - 25 * a2 '以a2为圆弧宽度
For i = 0 To 71
Pt(i + 72).x = 350 + a1 * Cos((72 - i) * pi / 35): Pt(i + 72).y = 350 + a1 * Sin((72 - i) * pi / 35)
Next i
n0 = 144
End If
Pt(n0) = Pt(0)
Else '否则,a1为圆弧开口方向
a1 = a1 - 6: s = a1
s1 = s * 90 - 5 * a5 + a2 * 15: s2 = s * 90 - 5 * a5 - a2 * 15 + 360 'a2为圆弧开口大小
If a2 = 9 Then s1 = s * 90 + 90: s2 = s * 90 - 90 + 360 'a2为圆弧开口大小
If s1 < 0 Then s1 = s1 + 360
a3 = 300 - a3 * 33.3 'a3为圆弧宽度
a5 = s * 90 - 5 * a5: a4 = a4 * 30 'a4为内圆心偏离程度,a5为内圆心偏离方向
k = 0
For i = s1 To s2 Step 5
Pt(k).x = 350 + 300 * Cos(pi * i / 180): Pt(k).y = 350 - 300 * Sin(pi * i / 180): k = k + 1
Next i
xx = 350 + a4 * Cos(a5 * pi / 180): yy = 350 - a4 * Sin(a5 * pi / 180)
For i = s2 To s1 Step -5
Pt(k).x = xx + a3 * Cos(pi * i / 180): Pt(k).y = yy - a3 * Sin(pi * i / 180): k = k + 1
Next i
Pt(k) = Pt(0)
If a2 = 9 Then
Pt(k + 1).x = 350: Pt(k + 1).y = 50
Pt(k + 2).x = 650: Pt(k + 2).y = 50
Pt(k + 3).x = 650: Pt(k + 3).y = 350 - a3
Pt(k + 4).x = 350: Pt(k + 4).y = 350 - a3
Pt(k + 5).x = 350: Pt(k + 5).y = 50
Pt(k + 6).x = 350: Pt(k + 6).y = 650
Pt(k + 7).x = 650: Pt(k + 7).y = 650
Pt(k + 8).x = 650: Pt(k + 8).y = 350 + a3
Pt(k + 9).x = 350: Pt(k + 9).y = 350 + a3
Pt(k + 10).x = 350: Pt(k + 10).y = 650
If s = 2 Or s = 1 Then Pt(k + 2).x = 50: Pt(k + 3).x = 50: Pt(k + 7).x = 50: Pt(k + 8).x = 50
If s = 1 Or s = 3 Then
For i = k + 1 To k + 10: yy = Pt(i).y: Pt(i).y = Pt(i).x: Pt(i).x = yy: Next i
End If
Pt(k + 11) = Pt(0)
End If
End If
Case "&" '螺旋形
n1 = 0: a4 = -1
If a1 = 1 Then n1 = 15: a4 = 1 'a1=2时顺时针方向,a1=1时逆时针方向,a1=0时无中心圆点
If a1 = 2 Then a4 = -1: n1 = 15
If a1 < 3 Then a1 = 30 'a1为角数,小于3为旋弧
a2 = a2 * 15 'a2为旋线宽和旋线隙
a3 = a3 * pi / 4 'a3*45为整体顺转角度
aa = 2 * pi / a1
nn = n1 + Int(a1 * 125 / a2): If nn > 138 Then nn = 138
If n1 = 15 Then
a5 = a2
For i = 0 To n1
Pt(i).x = 350 + a4 * a5 * Cos((15 + i) * aa + a3): Pt(i).y = 350 - a5 * Sin((15 + i) * aa + a3)
Next i
Else
a5 = a2
End If
For i = 0 To nn - n1
Pt(i + n1).x = 350 + a4 * a5 * Cos(i * aa + a3): Pt(i + n1).y = 350 - a5 * Sin(i * aa + a3)
a5 = a5 + 2 * a2 / a1
If a5 > 300 Then nn = i + n1: Exit For
Next i
a5 = a5 - a2
For i = nn - n1 To n1 Step -1
a5 = a5 - 2 * a2 / a1
Pt(2 * nn - n1 - i + 1).x = 350 + a4 * a5 * Cos(i * aa + a3): Pt(2 * nn - n1 - i + 1).y = 350 - a5 * Sin(i * aa + a3)
Next i
If n1 = 0 Then Pt(2 * (nn - n1) + 2) = Pt(n1)
Case "$" '波形
If a1 = 0 Then a1 = 1
If a2 = 0 Then a2 = 9
If a3 = 0 Then a3 = 1
a2 = a2 * 30 'a1为波数,a2为波幅
a3 = a3 * 30 'a3为弧线宽度,a4不为0,波向垂直
aa = pi * a1 / 60
If a4 = 0 Then
For i = 0 To 120: Pt(i).x = 5 * i: Pt(i).y = 350 - a2 * Sin(i * aa) - a3: Next i
For i = 121 To 241: Pt(i).x = Pt(241 - i).x: Pt(i).y = Pt(241 - i).y + 2 * a3: Next i
Else
For i = 0 To 120: Pt(i).y = 5 * i: Pt(i).x = 350 - a2 * Sin(i * aa) - a3: Next i
For i = 121 To 241: Pt(i).y = Pt(241 - i).y: Pt(i).x = Pt(241 - i).x + 2 * a3: Next i
End If
Pt(242) = Pt(0)
Case "#" '星形
a1 = a1 + 3 'a1+3为多角形的角数
a2 = a2 'a2-1为多角形的两直线相连角之间的角数
a4 = a4 * 15 * pi / 180
If a3 = 0 Then
a2 = a2 * 30 'a3为0时,a2为星形的内圆大小。非0时,a2-1为多角形的两直线相连角之间的角数
For i = 0 To a1
a5 = a4 + pi / 2 + i * 2 * pi / a1
Pt(2 * i).x = 350 + 300 * Cos(a5): Pt(2 * i).y = 350 - 300 * Sin(a5)
a5 = a5 + pi / a1
Pt(2 * i + 1).x = 350 + a2 * Cos(a5): Pt(2 * i + 1).y = 350 - a2 * Sin(a5)
Next i
Pt(2 * i) = Pt(0)
Else
If a1 = 3 Then
aa = 360: a3 = aa - a3 * 40
Else
aa = 300: a3 = aa - a3 * 33.333333 'a3为多角形的两角连线宽度
End If
k = 0: a5 = a1 / a2: If a5 - Int(a5) > 0 Then a5 = 1 Else a5 = a2
For k1 = 0 To a5 - 1
a6 = a4 + pi / 2 + k1 * 2 * pi / a1
For i = 0 To a1 / a5
Pt(k).x = 350 + aa * Cos(a6): Pt(k).y = 350 - aa * Sin(a6): k = k + 1
a6 = a6 + 2 * pi * a2 / a1
Next i
a6 = a6 - 2 * pi * a2 / a1
For i = a1 / a5 To 0 Step -1
Pt(k).x = 350 + a3 * Cos(a6): Pt(k).y = 350 - a3 * Sin(a6): k = k + 1
a6 = a6 - 2 * pi * a2 / a1
Next i
Pt(k) = Pt(k1 * 2 * (1 + a1 / a5) + k1): k = k + 1
Next k1
For k1 = a5 - 1 To 0 Step -1: Pt(k) = Pt(k1 * 2 * (1 + a1 / a5) + k1): k = k + 1: Next k1
End If
Case "%" '不定形。由%后第二个数开始的10个数串0123456789指定的点组成封闭曲线。02468和13579分别成左右两曲线。
'而第一个数a1指定曲线的特性:奇偶定方向垂直或水平,等于4、5,2、3,6、7分别为左,右,两边是折线(不平滑)
For i = 80 To 100: Pt(i).x = 650: Pt(100 + i).x = 50: Next i
For i = 0 To 80: Pt(i).x = 50 + i * 7.5: Pt(180 - i).x = 50 + i * 7.5: Next i
For i = 0 To 4: