发明内容
针对现有技术中存在的问题,本发明的目的是提供一种基于贝塞尔曲线封闭轮廓的字幕渲染方法。该方法将所有类型的字幕对象转换为由一次、二次或三次Bezier线段组成的矢量轮廓信息,并对转换后的矢量轮廓信息进行一系列的处理后再对字幕进行渲染,能够提高字幕的渲染效率,增强字幕的渲染效果,满足字幕的高级应用。
为达到以上目的,本发明采用的技术方案是:一种基于贝塞尔曲线封闭轮廓的字幕渲染方法,包括以下步骤:
(1)将字幕对象转换为由一次、二次或三次贝塞尔线段组成的包括N个封闭轮廓的矢量轮廓信息,所述的N为正整数;
(2)将步骤(1)获得的封闭轮廓中一次和三次贝塞尔线段转换成二次贝塞尔线段;
(3)将经步骤(2)转换后的矢量轮廓信息中自相交的封闭轮廓内含的闭合环路删除或者分割;
(4)对经步骤(3)处理后的矢量轮廓信息中相交的封闭轮廓进行规并整理,使封闭轮廓之间互不相交;
(5)将经步骤(4)处理后的矢量轮廓信息中的封闭轮廓转换成多边形;
(6)对经步骤(5)转换后的矢量轮廓信息中的多边形加内边或外边。
如上所述的一种基于贝塞尔曲线封闭轮廓的字幕渲染方法,步骤(1)中所述的将字幕对象转换为由一次、二次或三次贝塞尔线段组成的包括N个封闭轮廓的矢量轮廓信息的方法包括以下步骤:
①从当前字幕对象链表中取出一个与已取不同的字幕对象;
②判断字幕对象的类型,根据字幕对象的类型进行相应的处理,将字幕对象转换成由一次、二次或者三次贝塞尔线段组成的N个封闭轮廓;
所述的字幕对象的类型包括文字字幕、基本图形字幕和复合字幕,所述的复合字幕是指包括文字和基本图形的字幕;
如果字幕对象的类型为文字字幕,则获取文字字幕在TrueType字库中的矢量轮廓信息的方法包括以下步骤:
a.根据文字字幕对象的字体名称,创建逻辑字体对象F;
b.将逻辑字体对象F设置到操作系统的资源描述表中,并保存操作系统原来的逻辑字体;
c.根据当前字符的Unicode编码,从操作系统的当前资源描述表中获取当前字符的矢量轮廓信息在TrueType字库中占用的内存字节数B;
d.根据当前字符占用的内存字节数B,分配内存P;
e.根据当前字符的Unicode编码和占用的内存P,从操作系统当前资源描述表中获取当前字符的矢量轮廓信息G,并恢复操作系统原来的逻辑字体;
如果字幕对象的类型为基本图形字幕,则将其转换成矢量轮廓信息的方法包括以下步骤:
a.根据基本图形字幕的几何形状,将基本图形字幕划分成多条曲线段,所述的曲线段包括直线段、正玄或余玄曲线段、圆弧段和椭圆弧段;
b.根据基本图形字幕的外接矩形、每条曲线段的参数方程计算出每条曲线段转换成三次贝塞尔线段后的起始控制点和结束控制点的坐标;
c.对每条三次贝塞尔线段,根据起始控制点和结束控制点的坐标和三次贝塞尔参数方程,分别计算t=1/3和t=2/3处的另外两个控制点的坐标。
如果字幕对象的类型为复合字幕,则将其转换成矢量轮廓信息的方法包括以下步骤:
a.根据复合字幕对象的数据结构,将其拆分为M个基本字幕对象,所述的基本字幕对象为文字字幕对象或基本图形字幕对象,所述的M为正整数;
b.分别将文字字幕对象和基本图形字幕对象转换成由一次、二次或三次贝塞尔线段组成的封闭轮廓,得到M个基本字幕对象的矢量轮廓信息;
c.根据M个基本字幕对象的相对空间坐标,将步骤b中得到的M个矢量轮廓信息组合在一起,形成该复合字幕对象的最终矢量轮廓信息;
③根据字幕对象的旋转和变形参数,将步骤②中的矢量轮廓信息进行空间几何变换:
假设字幕对象的旋转角度为A,基本字幕对象的顶点个数为n,分别为P[0]至P[n-1],所述的n为正整数;
a.根据基本字幕对象的外接矩形的四个顶点坐标计算基本字幕对象的中心点Q的坐标;
b.按照如下公式修正旋转后的P[i]的坐标,0≤i≤n,i为正整数;
x=P[i].x-Q.x,
y=P[i].y-Q.y,
P[i].x=Q.x+x*cos(A)-y*sin(A),
P[i].y=Q.y+x*sin(A)+y*cos(A);
其中,P[i].x和P[i].y分别为P[i]点横、纵坐标,Q.x和Q.y分别为Q点的横、纵坐标;
④重复步骤①至步骤③,直到处理完当前字幕对象链表中所有字幕对象。
如上所述的一种基于贝塞尔曲线封闭轮廓的字幕渲染方法,步骤(2)中所述的将一次和三次贝塞尔线段转换为二次贝塞尔线段的方法包括以下步骤:
①遍历矢量轮廓信息,取出一个与已取不同的封闭轮廓G;
②遍历封闭轮廓G,取出一个与已取不同的贝塞尔线段B;
③判断贝塞尔线段B是几次贝塞尔线段,如果是一次或者三次贝塞尔线段,则将其转换为二次贝塞尔线段;
将一次贝塞尔线段转换为二次贝塞尔线段的方法为:假设一次贝塞尔线段的前后两个控制点分别为R0和R1,将R0和R1分别作为二次贝塞尔线段的第一个控制点和第三个控制点,将R0和R1的中点作为二次贝塞尔线段的第二个控制点;
将三次贝塞尔线段转换为二次贝塞尔线段的方法为:将一条三次贝塞尔线段转换为两条二次贝塞尔线段;假设三次贝塞尔线段的控制点分别为R0、R1、R2和R3;
Q1为R0和R1的中点,Q1.x=(R0.x+R1.x)/2,Q1.y=(R0.y+R1.y)/2;
Q2是R2和R3的中点,Q2.x=(R2.x+R3.x)/2,Q2.y=(R2.y+R3.y)/2;
Q3是R1和R2的中点,Q3.x=(R1.x+R2.x)/2,Q3.y=(R1.y+R2.y)/2;
Q4是Q1和Q3的中点,Q4.x=(Q1.x+Q3.x)/2,Q4.y=(Q1.y+Q3.y)/2;
Q5是Q2和Q3的中点,Q5.x=(Q2.x+Q3.x)/2,Q5.y=(Q2.y+Q3.y)/2;
Q6是Q4和Q5的中点,Q6.x=(Q4.x+Q5.x)/2,Q6.y=(Q4.y+Q5.y)/2;
Q7是Q4和Q5构成的直线与R0和R1构成直线的交点,Q7.x=(3*Q1.x+3*Q4.x-R0.x-Q6.x)/4,Q7.y=(3*Q1.y+3*Q4.y-R0.y-Q6.y)/4;
Q8是Q4和Q5构成的直线与R2和R3构成直线的交点,Q8.x=(3*Q2.x+3*Q5.x-R3.x-Q6.x)/4,Q8.y=(3*Q2.y+3*Q5.y-R3.y-Q6.y)/4;
将三次贝塞尔线段在Q6点处分成两条二次贝塞尔线段,其中一条二次贝塞尔线段的三个控制点分别为R0,Q7,Q6,另一条贝塞尔线段的三个控制点分别为Q6,Q8,R3。
④重复步骤②至步骤③,直到处理完封闭轮廓G中所有的贝塞尔线段;
⑤重复步骤①至步骤④,直到处理完矢量轮廓信息中所有的封闭轮廓。
如上所述的一种基于贝塞尔曲线封闭轮廓的字幕渲染方法,步骤(3)中将矢量轮廓信息中自相交的封闭轮廓内含的闭合环路删除或者分割的方法包括以下步骤:
①从字幕对象的矢量轮廓信息中取出一个与已取不同的封闭轮廓G;
②判断封闭轮廓G中是否存在二次贝塞尔线段自相交的情况,如果存在,则继续判断是相邻二次贝塞尔线段自相交还是非相邻二次贝塞尔线段自相交,如果是相邻二次贝塞尔线段自相交,则将封闭轮廓G中内含的包括自相交的相邻二次贝塞尔线段的闭合环路删除;如果是非相邻二次贝塞尔线段自相交,则将封闭轮廓G和其内含的包括自相交的非相邻二次贝塞尔线段的闭合环路分割成多个封闭轮廓;
③重复步骤②,直到封闭轮廓G中所有的自相交情况处理完毕;
④重复步骤①至步骤③,直到字幕对象矢量轮廓信息表中所有的封闭轮廓处理完毕。
如上所述的一种基于贝塞尔曲线封闭轮廓的字幕渲染方法,步骤②中判断封闭轮廓G是否存在二次贝塞尔线段自相交情况的方法为:假设G中有M个二次贝塞尔线段,分别是B[0]、B[1]、B[2]至B[M-1];依次取出G中每个二次贝塞尔线段B[j],判断B[j]与G中的其它二次贝塞尔线段是否相交,如果相交,则G中存在自相交情况;否则不存在自相交情况;
如果B[j]与相邻线段B[j+1]相交,则是相邻二次贝塞尔线段自相交,否则是非相邻二次贝塞尔线段自相交。
如上所述的一种基于贝塞尔曲线封闭轮廓的字幕渲染方法,其中,判断两条二次贝塞尔线段是否相交的方法包括以下步骤:
a.计算两条二次贝塞尔线段的外接矩形;
假设二次贝塞尔线段的三个控制点分别为P0、P1和P2,P0点的横坐标为P0.x,纵坐标为P0.y;P1点的横坐标为P1.x,纵坐标为P1.y;P2点的横坐标为P2.x,纵坐标为P2.y;计算由P0、P1和P2构成的三角形的外接矩形T,T即为该二次贝塞尔线段的外接矩形,公式如下:
T.left=min(P0.x,P1.x,P2.x),
T.right=max(P0.x,P1.x,P2.x),
T.top=min(P0.y,P1.y,P2.y),
T.bottom=max(P0.y,P1.y,P2.y);
其中,T.left表示外接矩形左边框的横坐标,T.right表示外接矩形右边框的横坐标,T.top表示外接矩形上边框的纵坐标,T.bottom表示外接矩形下边框的纵坐标;min函数表示取所有参数中的最小值,max函数表示取所有参数中的最大值;
b.判断两条二次贝塞尔线段的外接矩形是否存在交集,如果存在,则这两条二次贝塞尔线段相交,如果不存在,则这两条二次贝塞尔线段不相交。
如上所述的一种基于贝塞尔曲线封闭轮廓的字幕渲染方法,步骤②中将封闭轮廓G中内含的包括自相交的相邻二次贝塞尔线段的闭合环路删除的方法为:
假设G中有M个二次贝塞尔线段,分别是B[0]、B[1]、B[2]至B[M-1],两条自相交的相邻二次贝塞尔线段分别为B[j]和B[j+1];首先计算B[j]和B[j+1]的交点S;然后将B[j]的起始控制点与S相连构成一条新的二次贝塞尔线段B[j′],将S与B[j+1]的结束控制点相连构成一条新的二次贝塞尔线段B[j+1′],B[j′]、B[j+1′]与封闭轮廓G中原来的二次贝塞尔线段B[0]到B[j-1]、B[j+2]到B[M-1]构成了一个新的封闭轮廓G′,令G=G′;最后删除S与B[j]的结束控制点构成的封闭轮廓。
如上所述的一种基于贝塞尔曲线封闭轮廓的字幕渲染方法,步骤②中将封闭轮廓G和其内含的包括自相交的非相邻二次贝塞尔线段的闭合环路分割成多个封闭轮廓的方法为:
假设G中有M个二次贝塞尔线段,分别是B[0]、B[1]、B[2]至B[M-1],两条自相交的非相邻二次贝塞尔线段分别为B[j]和B[k],j<k;首先计算B[j]和B[k]的交点S;然后将B[j]的起始控制点与S相连构成一条新的二次贝塞尔线段B[j′],并将S与B[k]的结束控制点相连构成一条新的二次贝塞尔线段B[k′],B[j′]、B[k′]与封闭轮廓G中原来的线段B[0]到B[j-1]、B[k+1]到B[M-1]构成了一个新的封闭轮廓G′,令G=G′;最后将S与B[j]的结束控制点和B[k]的起始控制点相连,形成了两条新的二次贝塞尔线段,将这两条新的二次贝塞尔线段与B[j+1]到B[k-1]中所有的二次贝塞尔线段构成了一个新的封闭轮廓G",将G"加入到字幕对象矢量轮廓信息表中。
如上所述的一种基于贝塞尔曲线封闭轮廓的字幕渲染方法,步骤(4)中对矢量轮廓信息中相交的封闭轮廓进行规并整理的方法包括以下步骤:
①计算所有封闭轮廓中每条二次贝塞尔线段与其他封闭轮廓中的二次贝塞尔线段的交点;
②将所有存在交点的二次贝塞尔线段在交点处分割成多条首尾相连的二次贝塞尔线段;
③确定所有封闭轮廓中包含的每条二次贝塞尔线段的内外边属性;
④将属性为内边的二次贝塞尔线段删除,并重构矢量轮廓信息中的封闭轮廓;
⑤标记所有封闭轮廓的方向,所述的方向包括顺时针和逆时针。
如上所述的一种基于贝塞尔曲线封闭轮廓的字幕渲染方法,其中,计算两条二次贝塞尔线段的交点的方法包括以下步骤:
(I)假设两条相交的二次贝塞尔线段分别为B[j]和B[k],将B[j]和B[k]分别进行如下处理:
a.计算二次贝塞尔线段的起始控制点与结束控制点之间的空间直线距离L, ,其中,x0、y0为起始控制点横、纵坐标,x1和y1为结束控制点横、纵坐标;
b.判断L是否大于M,如果大于,则计算二次贝塞尔线段的中点,将二次贝塞尔线段在中点处划分成两条二次贝塞尔线段,所述的
c.重复步骤a至步骤b,直到划分后的每条二次贝塞尔线段的起始控制点与结束控制点之间的空间直线距离L小于或等于M;
(II)将B[j]和B[k]经过步骤(I)处理后,假设最终相交的两条二次贝塞尔线段分别为B[j′]和B[k′],计算B[j′]的起始控制点和结束控制点构成的直线段与B[k′]的起始控制点和结束控制点构成的直线段的交点。
如上所述的一种基于贝塞尔曲线封闭轮廓的字幕渲染方法,步骤②中将一条存在交点的二次贝塞尔线段在交点处分割成多条首尾相连的二次贝塞尔线段的方法包括以下步骤:
假设一条二次贝塞尔线段B的三个控制点分别是P[0]、P[1]、P[2],在B上有n个交点,分别为S[0]到S[n-1],每个交点对应的贝塞尔参数方程中的t值分别是S[0].t到S[n-1].t;
首先在S[0]点处将线段B分成两条线段B1和B1′;
B1的三个控制点分别为P[0]、Q[0]、S[0],P[0]和S[0]的坐标已知,Q[0]的坐标为:
Q[0].x=(1-t)*P[0].x+t*P[1].x,
Q[0].y=(1-t)*P[0].y+t*P[1].y;
B1′的三个控制点分别为S[0]、R[0]、P[2],S[0]和P[2]的坐标已知,R[0]的坐标为:
R[0].x=(1-t)*P[1].x+t*P[2].x,
R[0].y=(1-t)*P[1].y+t*P[2].y;
其中,Q[0].x表示Q[0]点的横坐标,Q[0].y表示Q[0]点的纵坐标,R[0].x表示R[0]点横坐标,R[0].y表示R[0]点纵坐标;t=(S[0].t-P[0].t)/(P[2].t-P[0].t),P[0].t为P[0]点对应的贝塞尔参数方程中的t值,P[2].t为P[2]点对应的贝塞尔方程中的t值;
然后在S[1]点处将线段B1′分成两条线段B2和B2′,方法与步骤①相同;
以此类推,最后在S[n-1]点处将线段Bn-1′分成两条线段Bn和Bn′;最终得到N+1条分割后的线段。
如上所述的一种基于贝塞尔曲线封闭轮廓的字幕渲染方法,步骤③中确定一条二次贝塞尔线段的内外边属性的方法为:判断二次贝塞尔线段的中点在字幕对象矢量轮廓信息的所有封闭轮廓中是内点还是外点;如果是内点,则包含该点的二次贝塞尔线段为内边;如果是外点,则包含该点的二次贝塞尔线段为外边;
判断二次贝塞尔线段的中点在字幕对象所有封闭轮廓中是内点还是外点的方法包括以下步骤:假设二次贝塞尔线段为B,B的三个控制点分别为P[0]、P[1]、P[2],中点为Q;
a.确定B的方向值d:如果P[2].y>P[0].y,则d=1;如果P[2].y<P[0].y,则d=-1;如果P[2].y=P[0].y,则d=0;所述的P[0].y和P[2].y分别表示P[0]和P[2]的纵坐标;
b.计算B的中点Q;
c.判断abs(P[2].y-P[0].y)是否大于abs(P[2].x-P[0].x),如是,则以Q点为起点,沿水平方向作一射线H;如否,则以Q点为起点沿竖直方向作一射线H;计算字幕对象所有封闭轮廓中与H相交的除B之外的所有二次贝塞尔线段,假设有M条二次贝塞尔线段与H相交,分别为B[0]、B[1]至B[M-1];所述的P[0].x和P[2].x分别表示P[0]和P[2]的横坐标,所述的abs函数为取绝对值函数;
d.分别计算B[i]的方向值d[i],方法与步骤①中计算d值的方法相同;所述的i=0、1、......、M-1;
e.计算d[i]的和值d′:d′=d[0]+d[1]+......+d[M-1];
f.根据d和d′计算B的内外边属性值a;如果a=0,则B为内边;如果a=1,则B为外边;
所述的a=1-abs(SIGN(d+d′)*SIGN(d′)),所述的SIGN(x)定义为(x==0)?0:((x>0)?1:-1))。
如上所述的一种基于贝塞尔曲线封闭轮廓的字幕渲染方法,步骤③中当确定了一个封闭轮廓中的一条二次贝塞尔线段的内外边属性后,则该封闭轮廓该条二次贝塞尔线段之后的二次贝塞尔线段的内外边属性与其相同,直到遇到一个交点为止。
如上所述的一种基于贝塞尔曲线封闭轮廓的字幕渲染方法,步骤④中将属性为内边的二次贝塞尔线段删除后,重构矢量轮廓信息中的封闭轮廓的方法包括以下步骤:
a.从所有封闭轮廓中取出一个与已取不同的封闭轮廓G1;
b.判断G1的最后一条二次贝塞尔线段的结束点坐标与第一条二次贝塞尔线段的起始点坐标的差值是否小于等于阀值T,T=0.00001,如是,则重复步骤a至步骤b,直到所有的封闭轮廓被处理完毕;
c.取出与G1相邻的下一个封闭轮廓G2;
d.判断G1的最后一条二次贝塞尔线段的结束点坐标与G2的第一条二次贝塞尔线段的起始点坐标的差值或者G1的第一条二次贝塞尔线段的起始点坐标与G2的最后一条二次贝塞尔线段的结束点坐标的差值是否小于等于阀值T,如是,则将G1、G2合并,并将G2从矢量轮廓中删除;
e.取出与G2相邻的下一个封闭轮廓G2′,令G2=G2′,重复步骤d,直到G2为最后一个封闭轮廓或者G2与G1相等;
f.重复步骤a至步骤e,直到所有的封闭轮廓被处理完毕。
如上所述的一种基于贝塞尔曲线封闭轮廓的字幕渲染方法,步骤⑤中所述的标记所有封闭轮廓的方向的方法包括以下步骤:
a.从封闭轮廓G中任取一条二次贝塞尔线段为B,假设B的三个控制点分别为P[0]、P[1]、P[2],中点为Q;
b.确定B的方向值d:如果P[2].y>P[0].y,则d=1;如果P[2].y<P[0].y,则d=-1;如果P[2].y=P[0].y,则d=0;
c.计算B的中点Q;
d.判断abs(P[2].y-P[0].y)是否大于abs(P[2].x-P[0].x),如是,则以Q点为起点,沿水平方向作一射线H;如否,则以Q点为起点沿竖直方向作一射线H;计算字幕对象所有封闭轮廓中与H相交的除B之外的所有二次贝塞尔线段,假设有M条二次贝塞尔线段与H相交,分别为B[0]、B[1]至B[M-1];
e.分别计算B[i]的方向值d[i],方法与步骤①中计算d值的方法相同;其中,i=0、1、......、M-1;
f.计算d[i]的和值d′:d′=d[0]+d[1]+......+d[M-1];
g.计算B的方向属性b的值,b=d*(1-2*abs(d′));如果b>0,则封闭轮廓G为顺时针方向,否则为逆时针方向。
如上所述的一种基于贝塞尔曲线封闭轮廓的字幕渲染方法,其中,计算二次贝塞尔线段的中点的方法为:假设二次贝塞尔线段的三个控制点分别为P0、P1和P2,函数表达式为
B(t)=(1-t)2P0+2t(1-t)2P1+t2P2 t∈[0,1];
令t=0.5,计算二次贝塞尔曲线方程上的一点Q,该点便是二次贝塞尔线段的中点,其坐标的计算公式为Q=(P0+2*P1+P2)/4。
如上所述的一种基于贝塞尔曲线封闭轮廓的字幕渲染方法,步骤(5)中将矢量轮廓信息中的封闭轮廓转换成多边形的方法包括以下步骤:
①遍历字幕对象的矢量轮廓信息,取出一个与已取不同的封闭轮廓G[i],i∈[0,N-1],i为正整数;
②遍历封闭轮廓G[i],取出一条与已取不同的二次贝塞尔线段B[j],假设G[i]中包含M个二次贝塞尔线段,则j∈[0,M-1],j为正整数;
③将B[j]离散化为直线段,具体的实现过程如下:
假设B[j]的三个控制点分别为P[0]、P[1]和P[2];P[0]为起始控制点,P[1]为中间控制点,P[2]为结束控制点;
首先,以P[0]点为起点,计算B[j]离散化后的第一条直线段L[j][0];
a.设置t的初始值,t=P[0].t+L,L=1/16;P[0].t为P[0]点对应的二次贝塞尔曲线方程中的t值,P[0].t=0;
b.根据二次贝塞尔曲线方程计算t值对应的二次贝塞尔曲线上点Q[0]的坐标;
c.计算P[0]点和Q[0]点之间的空间直线距离d, ,其中,x0、y0是P[0]的坐标,x1、y1是Q[0]的坐标;
d.判断 是否成立,如果成立,则令t=(P[0].t+Q[0].t)/2,其中,Q[0].t为Q[0]点对应二次贝塞尔曲线方程中的t值;重复步骤②至步骤④,直到 ;最终的Q[0]点与P[0]点构成的直线段便是第一条离散化后的直线L[j][0];
然后,以Q[0]点为起点,采用与计算B[j]离散化后的第一条直线段相同的方法计算第二条直线段L[j][1];
以此类推,直到处理到B[j]的结束控制点P[2]为止,获得K条直线段L[j][0]至L[j][K-1];
④重复步骤②至步骤③,直到G[i]中所有的二次贝塞尔线段处理完毕;
⑤重复步骤①至步骤④直到字幕对象的矢量轮廓中所有的封闭曲线处理完毕。
如上所述的一种基于贝塞尔曲线封闭轮廓的字幕渲染方法,步骤(6)中对矢量轮廓信息中的多边形加内边或外边的方法包括以下步骤:
①计算矢量轮廓信息中所有多边形的每条边的角度值a1、a2、a3以及每条边的加边矢量dx、dy的值;
所述的a1表示多边形的一条边与水平向右方向的夹角;所述的a2表示一条边的延长线和与其相邻的下一条边的夹角;a3表示一条边的延长线与下一条边的夹角的角平分线与水平向右方向的夹角;dx表示加边时一条边的起始点移动的水平矢量;dy表示加边时一条边的起始点移动的竖直矢量;
一条边的a1=atan((y1-y0)/(x1-x0)),其中,(x0,y0)为该条边的起始点坐标,(x1,y1)为该条边的结束点坐标,atan为反正切函数;
a2的值等于相邻两条边的a1值的差值;
a3=a1-a2/2;
dx=Cos(a3)÷Sin(a2/2);
dy=Sin(a3)÷Sin(a2/2);
其中Sin为正玄函数,Cos为余玄函数;
②遍历矢量轮廓信息中的多边形,取出一个与已取不同的多边形Q[i];
③复制Q[i],得到Q′[i];
④对于加外边的情况,如果Q′[i]的方向为逆时针,则取出其中的每条边L[j],按照如下公式修正每条边的a1和a2的值:
L[j].a1=L[j].a1+∏,L[j].a2=2∏-L[j].a2,其中∏=180度;
对于加内边的情况,如果Q′[i]的方向为顺时针,则取出其中的每条边L[j],按照如下公式修正每条边的a1和a2的值:
L[j].a1=L[j].a1+∏,L[j].a2=2∏-L[j].a2;
⑤确定加边类型;
如果加尖角边,则转至步骤⑥;
如果加方角边,假设有三个连续的顶点P[0]、P[1]、P[2],需要在原来的顶点为P[1]处增加一个新的顶点为P′;令P′的x坐标、y坐标、a1、a2、a3、dx、dy的初始值等于P[1]中的相应值,然后按照如下公式重新修正P[1]的各个属性值:
P[1].a1=P[0].a1+P′.a2/2;
P[1].a2=P[1].a1-P[0].a1;
P[1].a3=P[0].a1+P[1].a2/2;
P[1].dx=Cos(P[1].a3)÷Sin(P[1].a2/2);
P[1].dy=Sin(P[1].a3)÷Sin(P[1].a2/2)。
如果加圆角边,首先按照加方角边的方法,在顶点P[1]处增加一个新的顶点为P′,修正P[1]的各个属性值;然后判断修正后的P[1].a2是否小于∏/16,如果不小于,则重复上述步骤,继续在P[1]处增加一个新的顶点,直到P[1].a2<∏/16;
⑥重复步骤①至步骤⑤,直到处理完矢量轮廓信息中所有的多边形。
本发明的效果在于:在字幕对象渲染前,采用本发明所述的方法对字幕对象进行一系列的处理后,再将处理后的字幕对象进行渲染,提高了字幕对象的渲染效率,增强了字幕对象的渲染效果,并能够实现字符变形、字符倒影、字符反转、曲线摆放等高级的字幕应用需求。
具体实施方式
下面结合具体实施方式和附图对本发明进行详细描述。
本发明主要应用于广电行业电视节目制播机构的字幕编播系统的渲染引擎中,在字幕对象渲染之前对其进行一系列的预处理,以提高字幕对象的渲染效率和效果,并满足高级的字幕应用需求。
图1出示了本发明所述的字幕对象渲染的预处理方法的流程,主要包括以下步骤。
(1)将字幕对象转换为由一次、二次或三次贝塞尔线段组成的包括N(N为正整数)个封闭轮廓的矢量轮廓信息。
字幕对象可以分为文字字幕、基本图形字幕和复合字幕三种类型,复合字幕是指包括文字和基本图形的字幕。针对不同类型的字幕对象需要进行不同的处理,图2出示了将不同类型的字幕对象转换为由一次、二次或三次贝塞尔线段组成的包括N个封闭轮廓的矢量轮廓信息的方法流程,包括以下步骤。
①从当前字幕对象链表中取出一个字幕对象。
②判断步骤①中取出的字幕对象的类型。
如果字幕对象的类型为文字字幕,则可以直接使用操作系统的TrueType字库,无需转换。图3出示了获取文字字幕在TrueType字库中的矢量轮廓信息的方法流程,包括以下步骤:
a.根据文字字幕对象的字体名称,使用操作系统提供的API(CreateFont)创建逻辑字体对象F;
b.使用操作系统提供的API(SelectObject),将逻辑字体对象F设置到操作系统的资源描述表中,并保存操作系统原来的逻辑字体;
c.根据当前字符的Unicode编码,使用操作系统提供的API(GetGlyphOutline),从操作系统的当前资源描述表中获取当前字符的矢量轮廓信息在TrueType字库中占用的内存字节数B;
d.根据当前字符占用的内存字节数B,分配内存P;
e.根据当前字符的Unicode编码和占用的内存P,再次使用操作系统提供的API(GetGlyphOutline),从操作系统当前资源描述表中获取当前字符的矢量轮廓信息G,并恢复操作系统原来的逻辑字体。
如果字幕对象的类型为基本图形字幕,则将其转换成由若干条三次贝塞尔线段组成的封闭轮廓的矢量轮廓信息,主要是根据基本图形的几何参数确定每条贝塞尔线段上的控制点坐标,具体包括以下步骤:
a.根据基本图形字幕的几何形状,将基本图形字幕划分成多条曲线段,所述的曲线段包括直线段、正玄或余玄曲线段、圆弧段和椭圆弧段;
b.根据基本图形字幕的外接矩形、每条曲线段的参数方程计算出每条曲线段转换成三次贝塞尔线段后的起始控制点和结束控制点的坐标;
c.对每条三次贝塞尔线段,根据起始控制点和结束控制点的坐标和三次贝塞尔参数方程,分别计算t=1/3和t=2/3处的另外两个控制点的坐标。
以基本图形字幕为椭圆图元为例,如图4所示。首先,根据椭圆图元与其外接矩形的四个交点P400、P403、P406和P409将其分成四条曲线段,分别为从P400到P403、从P403到P406、从P406到P409和从P409到P400。将每条曲线段转换成三次贝塞尔曲线后,从P400到P403的三次贝塞尔线段的四个控制点分别为P400、P401、P402和P403,从P403到P406的三次贝塞尔线段的四个控制点分别为P403、P404、P405和P406,从P406到P409的三次贝塞尔线段的四个控制点分别为P406、P407、P408和P409,从P409到P400的三次贝塞尔线段的四个控制点分别为P409、P410、P411和P400。
然后,根据椭圆图元的外接矩形的四个顶点坐标计算出椭圆中心点的坐标(a,b)、横轴半径ra和纵轴半径rb。每条三次贝塞尔线段的各个控制点坐标的计算公式如下:
令PinA=ra*0.55179445,PinB=rb*0.55179445;
P400.x=a, P400.y=b+rb;
P401.x=a+PinA; P401.y=b+rb;
P402.x=a+ra; P402.y=b+PinB;
P403.x=a+ra; P403.y=b;
P404.x=a+ra; P404.y=b-PinB;
P405.x=a+PinA; P405.y=b-rb;
P406.x=a; P406.y=b-rb;
P407.x=a-PinA; P407.y=b-rb;
P408.x=a-ra; P408.y=b-PinB;
P409.x=a-ra; P409.y=b;
P410.x=a-ra; P410.y=b+PinB;
P411.x=a-PinA; P411.y=b+rb。
其中,P400.x表示P400点的横坐标,P400.y表示P400点的纵坐标。本实施方式中,其他类似的表示方式的含义与P400相同。
以基本图形字幕为波浪旗飘图元为例,如图5所示。首先,根据两条曲线段与两条直线段的四个交点P500、P503、P506和P509将其分成四条曲线段,分别为从P500到P503、从P503到P506、从P506到P509和从P509到P500。将每条曲线段转换成三次贝塞尔曲线后,从P500到P503的三次贝塞尔线段的四个控制点分别为P500、P501、P502和P503,从P503到P506的三次贝塞尔线段的四个控制点分别为P503、P504、P505和P506,从P506到P509的三次贝塞尔线段的四个控制点分别为P506、P507、P508和P509,从P509到P500的三次贝塞尔线段的四个控制点分别为P509、P510、P511和P500。
已知波浪旗飘形图元的外接矩形的四点坐标,可以计算出该图元外接矩形的宽度和高度,分别为W5和H5。此外,根据已知的调节波浪旗飘图元的水平和垂直幅度的参数fx和fy,可以计算出来P500点的坐标为(a,b),a=fx*W,b=fy*H。
每条三次贝塞尔线段上控制点坐标的计算过程包括以下步骤。
(a)基于正玄曲线方程,根据P500点坐标计算出P503点坐标。
P503.x=W5;
P503.y=b+b*0.9*sin((W5-a)*2*PI/W5)。
(b)以P500点为起点,以P503点为终点,根据三次贝塞尔曲线方程,分别计算t=1/3和t=2/3处的P501点和P502点的坐标。
P501.x=((m1*c2-m2*c1)-(a1*c2-a2*c1)*P500.x-(d1*c2-c1*d2)*P503.x)/(b1*c2-b2*c1)。
P502.x=((m1*b2-m2*b1)-(a1*b2-a2*b1)*P500.x-(d1*b2-d2*b1)*P503.x)/(c1*b2-c2*b1)。
其中,m1=a+(W5-a)/3,m2=a+(W5-a)*2/3;t1=1.0/3,t2=2.0/3;
a1=(1-t1)*(1-t1)*(1-t1);
b1=3*t1*(1-t1)*(1-t1);
c1=3*t1*t1*(1-t1);
d1=t1*t1*t1;
a2=(1-t2)*(1-t2)*(1-t2);
b2=3*t2*(1-t2)*(1-t2);
c2=3*t2*t2*(1-t2);
d2=t2*t2*t2。
P501.y=((n1*c2-n2*c1)-(a1*c2-a2*c1)*P500.y-(d1*c2-c1*d2)*P503.y)/(b1*c2-b2*c1)。
P502.y=((n1*b2-n2*b1)-(a1*b2-a2*b1)*P500.y-(d1*b2-d2*b1)*P503.y)/(c1*b2-c2*b1)。
其中,n1=b-b*0.9*sin((W5-a)*2*PI/(3*W5)),
n2=b-b*0.9*sin((W5-a)*2*PI*2/(3*W5))。
(c)基于正玄曲线方程,根据P500点坐标计算出P506点坐标。
P506.x=W5-a;
P506.y=H5-b-b*0.9*sin((W5-a)*2*PI/W5)
(d)计算P509点坐标。
P509.x=0;
P509.y=H5-b
(e)以P506点为起点,以P509点为终点,根据三次贝塞尔曲线方程,分别计算t=1/3和t=2/3处的P507点和P508点坐标,计算方法与计算P501点、P502点的坐标相同。
(f)P504点坐标等于P503点坐标,P505点坐标等于P506点坐标,P510点坐标等于P509点坐标,P511点坐标等于P500点坐标。之所以要重复这几个点,是为了使得该字幕对象的封闭矢量轮廓信息中的每条贝塞尔线段都是三次贝塞尔线段。实际上,由控制点P503、P504、P505、P506形成的三次贝塞尔线段,以及由控制点P509、P510、P511、P500形成的三次贝塞尔线段是一条直线段。
最后,获得的字幕对象的矢量轮廓信息由四条三次贝塞尔线段组成,分别为是由控制点(P500、P501、P502、P503)形成的三次贝塞尔线段,由控制点(P503、P504、P505、P506)形成的三次贝塞尔线段,由控制点(P506、P507、P508、P509)形成的三次贝塞尔线段,以及由控制点(P509、P510、P511、P512)形成的三次贝塞尔线段。
以基本图形字幕为心形图元为例,如图6所示。已知心形图元的外接矩形的四个顶点坐标,可以计算出该图元的宽度和高度,分别为W6和H6。首先将该图元分成8条曲线段,分别为从P600到P603、从P603到P606、从P606到P609、从P609到P612、从P612到P615、从P615到P618、P618到P620,从P620到P600。将每条曲线段转换成三次贝塞尔线段后各个控制点坐标的计算过程包括以下步骤。
(i)首先根据心形图元的形状特点,计算点P600、P603、P606和P609的坐标。
P600.x=0.73*W6+0.27*W6*cos(A),
P600.y=0.25*H6-0.25*H6*sin(A);
P603.x=0.73*W6+0.27*W6*cos(PI/3+A),
P603.y=0.25*H6-0.25*H6*sin(PI/3+A);
P606.x=0.73*W6+0.27*W6*cos(2*PI/3+A),
P606.y=0.25*H6-0.25*H6*sin(2*PI/3+A);
P609.x=0.73*W6+0.27*W6*cos(PI+A),
P609.y=0.25*H6-0.25*H6*sin(PI+A)。
其中PI和A为常数,PI=3.1415926,A=-0.5535442。
(ii)利用三次贝塞尔曲线方程,以P600点为起点,以P603点为终点,分别计算t=1/3和t=2/3处的P601点和P602点的坐标。三次贝塞尔曲线方程的矩阵形式如下:
t∈[0,1]
t∈[0,1]
t∈[0,1]
将上面矩阵展开后,得到:
X(t)=A0+A1*t+A2*t2+A3*t3
Y(t)=B0+B1*t+B2*t2+B3*t3
其中,A0=X0;A1=-3X0+3X1;A2=3X0-6X1+3X2;A3=-X0+3X1-3X2+X3;B0=Y0;B1=-3Y0+3Y1;B2=3Y0-6Y1+3Y2;B3=-Y0+3Y1-3Y2+Y3。
由于P600点和P603点的坐标X0、X3、Y0、Y3已知,P601点的t值为1/3,P602点的t值为2/3,因此可以列出一个如下四元一次方程组:
X1=A0+A1*(1/3)+A2*(1/3)2+A3*(1/3)3
Y1=B0+B1*(1/3)+B2*(1/3)2+B3*(1/3)3
X2=A0+A1*(2/3)+A2*(2/3)2+A3*(2/3)3
Y2=B0+B1*(2/3)+B2*(2/3)2+B3*(2/3)3
解该方程组,即可得到P601和P602点的坐标X1、X2、Y1、Y2的值。
(iii)利用三次Bezier参数方程,以P603点为起点,以P606点为终点,分别计算t=1/3和t=2/3处的P604点和P605点的坐标。方法与第③步中求P601、P602的坐标相同,不再赘述。
(iv)利用三次Bezier参数方程,以P606点为起点,以P609点为终点,分别计算t=1/3和t=2/3处的P607点和P608点的坐标。方法与第③步中求P601、P602的坐标相同,不再赘述。
(v)根据心形图元的左右对称性,可以得到P611、P612、P613、P614、P615、P616、P617和P618的坐标。
(vi)P620点的坐标为(W/2,H)。
(vii)P623、P624点的坐标等于P600点,P619点的坐标等于P618点,P621、P622点的坐标等于P620点。
最后,得到8条三次贝塞尔线段组成的矢量轮廓信息。这8条三次贝塞尔线段如下:
第一条线段由控制点(P600、P601、P602、P603)形成的三次贝塞尔线段;
第二条线段由控制点(P603、P604、P605、P606)形成的三次贝塞尔线段;
第三条线段由控制点(P606、P607、P608、P609)形成的三次贝塞尔线段;
第四条线段由控制点(P609、P610、P611、P612)形成的三次贝塞尔线段;
第五条线段由控制点(P612、P613、P614、P615)形成的三次贝塞尔线段;
第六条线段由控制点(P615、P616、P617、P618)形成的三次贝塞尔线段;
第七条线段由控制点(P618、P619、P620、P621)形成的三次贝塞尔线段(由于P618、P619的坐标相同,P620、P621的坐标相同,因此这条线段实际上是一条直线段);
第八条线段由控制点(P621、P622、P623、P624)形成的三次贝塞尔线段(由于P621、P622的坐标相同,P623、P624的坐标相同,因此这条线段实际上是一条直线段)。
对于其他类型的基本图形字幕对象,可以按照同样的思想,将其转换为由一次、二次或者三次Bezier线段组成的封闭轮廓。
如果字幕对象的类型为复合字幕,则将其转换成矢量轮廓信息的方法包括以下步骤:
a.根据复合字幕对象的数据结构,将其拆分为M个基本字幕对象,所述的基本字幕对象为文字字幕对象或基本图形字幕对象,所述的M为正整数;
b.分别将文字字幕对象和基本图形字幕对象转换成由一次、二次或三次贝塞尔线段组成的封闭轮廓,得到M个基本字幕对象的矢量轮廓信息;
c.根据M个基本字幕对象的相对空间坐标,将步骤b中得到的M个矢量轮廓信息组合在一起,形成该复合字幕对象的最终矢量轮廓信息。
③根据字幕对象的旋转、变形参数,将步骤②中的矢量轮廓信息进行空间几何变换。
假设字幕对象的旋转角度为A,基本字幕对象的控制点个数为n(n为正整数),分别为P[0]至P[n-1],则对一个基本字幕对象进行空间几何变换的过程包括以下步骤。
a.根据基本字幕对象的外接矩形的四个顶点坐标计算基本字幕对象的中心点Q的坐标。
b.按照如下公式修正旋转后的P[i](0≤i≤n,i为正整数)的坐标:
x=P[i].x-Q.x,
y=P[i].y-Q.y,
P[i].x=Q.x+x*cos(A)-y*sin(A),
P[i].y=Q.y+x*sin(A)+y*cos(A);
其中,P[i].x和P[i].y分别为P[i]点横、纵坐标,Q.x和Q.y分别为Q点的横、纵坐标。
④从字幕对象链表中取出下一个字幕对象,重复步骤①至步骤③,直到所有的字幕对象转换完毕。
(2)将步骤(1)获得的封闭轮廓中一次和三次贝塞尔线段转换成二次贝塞尔线段。
在将字幕对象转换成由一次、二次或三次贝塞尔线段组成的包含一个或多个封闭轮廓的矢量轮廓信息后,为了使渲染引擎在算法处理上的一致性,降低算法的复杂度,优化算法的效率,还需要将这些不同次数的贝塞尔线段统一转换为二次贝塞尔线段。
图7出示了将字幕对象矢量轮廓信息中的一次和三次贝塞尔线段转换为二次贝塞尔线段的方法流程,包括以下步骤:
①遍历矢量轮廓信息,取出一个与已取封闭轮廓不同的封闭轮廓G;
②遍历封闭轮廓G,取出一个与已取贝塞尔线段不同的贝塞尔线段B;
③判断贝塞尔线段B是几次贝塞尔线段,如果是一次或者三次贝塞尔线段,则将其转换为二次贝塞尔线段;
④重复步骤②至步骤③,直到处理完封闭轮廓G中所有的贝塞尔线段;
⑤重复步骤①至步骤④,直到处理完矢量轮廓信息中所有的封闭轮廓。
一次贝塞尔线段转换为二次贝塞尔线段的原理为:将一次贝塞尔线段的前后两个控制点R0和R1作为二次贝塞尔线段的第一和第三个控制点,R0和R1的中点作为二次贝塞尔线段的第二个控制点。
图8是一次贝塞尔线段转换为二次贝塞尔线段示意图,8a为转换前的一次贝塞尔线段,8b为转换后的二次贝塞尔线段。其中,P80=R80,P82=R81,P81=R80和R81的中点,即P81.x=(R80.x+R81.x)/2,P81.y=(R80.y+R81.y)/2。
三次贝塞尔线段转换为二次贝塞尔线段的原理为:将一条三次贝塞尔线段转换成两条二次贝塞尔线段。
图9中的9a和9b分别是将三次贝塞尔线段转换为两条二次贝塞尔线段的两种情况示意图。假设一个三次贝塞尔线段的控制点分别为R90、R91、R92、R93。Q1是R90和R91的中点,Q2是R92和R93的中点,Q3是R91和R92的中点,Q4是Q1和Q3的中点,Q5是Q2和Q3的中点,Q6是Q4和Q5的中点,Q7是Q4和Q5构成的直线与R0和R1构成直线的交点,Q8是Q4和Q5构成的直线与R92和R93构成直线的交点。
根据R90、R91、R92、R93四点的坐标以及贝塞尔参数方程计算出Q1、Q2、Q3、Q4、Q5、Q6、Q7、Q8的坐标如下:
Q1.x=(R90.x+R91.x)/2,Q1.y=(R90.y+R91.y)/2;
Q2.x=(R92.x+R93.x)/2,Q2.y=(R92.y+R93.y)/2;
Q3.x=(R91.x+R92.x)/2,Q3.y=(R91.y+R92.y)/2;
Q4.x=(Q1.x+Q3.x)/2,Q4.y=(Q1.y+Q3.y)/2;
Q5.x=(Q2.x+Q3.x)/2,Q5.y=(Q2.y+Q3.y)/2;
Q6.x=(Q4.x+Q5.x)/2,Q6.y=(Q4.y+Q5.y)/2;
Q7.x=(3*Q1.x+3*Q4.x-R0.x-Q6.x)/4,
Q7.y=(3*Q1.y+3*Q4.y-R0.y-Q6.y)/4;
Q8.x=(3*Q2.x+3*Q5.x-R3.x-Q6.x)/4,
Q8.y=(3*Q2.y+3*Q5.y-R3.y-Q6.y)/4。
将原来的三次贝塞尔线段在Q6点处分成两条二次贝塞尔线段,一条贝塞尔线段的三个控制点分别为R90,Q7,Q6,另一条贝塞尔线段的三个控制点分别为Q6,Q8,R93。
(3)将经步骤(2)转换后的矢量轮廓信息中自相交的封闭轮廓内含的闭合环路删除或者分割。
在字幕对象的矢量轮廓信息中,由二次贝塞尔线段组成的封闭轮廓内部可能存在自相交的二次贝塞尔线段的情况,即封闭轮廓中内含一个或多个闭合环路,如图11(a)、图12(a)和图15(a)所示。为了增强字幕对象的最终渲染效果,需要对这种情况进行处理,删除或者分割闭合环路。
图10出示了字幕对象矢量轮廓信息中自相交的二次贝塞尔曲线的处理流程,包括以下步骤。
①从字幕对象矢量轮廓信息表中取出一个与已取封闭轮廓不同的封闭轮廓G。
②判断封闭轮廓G中是否存在二次贝塞尔线段自相交的情况,如果存在,则继续判断是相邻二次贝塞尔线段自相交还是非相邻二次贝塞尔线段自相交,如果是相邻二次贝塞尔线段自相交,则将封闭轮廓G中内含的包括相邻二次贝塞尔线段自相交的闭合环路删除;如果是非相邻的二次贝塞尔线段自相交,则将封闭轮廓G和其内含的包括非相邻二次贝塞尔线段自相交的闭合环路分割成多个封闭轮廓。
判断封闭轮廓G中是否存在二次贝塞尔线段自相交的方法为:假设G中有M个二次贝塞尔线段,分别是B[0]、B[1]、B[2]至B[M-1];依次取出G中每个二次贝塞尔线段B[j],判断B[j]与G中的其它二次贝塞尔线段是否相交,如果相交,则G存在自相交情况;否则,不存在自相交情况。如果B[j]与相邻线段B[j+1]相交,则是相邻二次贝塞尔线段自相交,否则是非相邻二次贝塞尔线段自相交。
判断两条二次贝塞尔线段是否相交的方法为:计算两条二次贝塞尔线段的外接矩形;然后判断两条二次贝塞尔线段的外接矩形是否存在交集,如果存在,则这两条二次贝塞尔线段相交,如果不存在,则这两条二次贝塞尔线段不相交。
参照图13,计算一条二次贝塞尔线段的外接矩形的方法为:假设二次贝塞尔线段的三个控制点分别为P0、P1和P2,P0点的横坐标为P0.x,纵坐标为P0.y;P1点的横坐标为P1.x,纵坐标为P1.y;P2点的横坐标为P2.x,纵坐标为P2.y;计算由P0、P1和P2构成的三角形的外接矩形T,T即为该二次贝塞尔线段的外接矩形,公式如下:
T.left=min(P0.x,P1.x,P2.x),
T.right=max(P0.x,P1.x,P2.x),
T.top=min(P0.y,P1.y,P2.y),
T.bottom=max(P0.y,P1.y,P2.y);
其中,T.left表示外接矩形左边框的横坐标,T.right表示外接矩形右边框的横坐标,T.top表示外接矩形上边框的纵坐标,T.bottom表示外接矩形下边框的纵坐标;min函数表示取所有参数中的最小值,max函数表示取所有参数中的最大值。
参照图11,如果是相邻二次贝塞尔线段自相交,则将封闭轮廓G中内含的包括自相交的相邻二次贝塞尔线段的闭合环路删除的方法为:
假设G中有M个二次贝塞尔线段,分别是B[0]、B[1]、B[2]至B[M-1],两条自相交的相邻二次贝塞尔线段分别为B[j]和B[j+1];首先计算B[j]和B[j+1]的交点S;然后将B[j]的起始控制点与S相连构成一条新的二次贝塞尔线段B[j′],将S与B[j+1]的结束控制点相连构成一条新的二次贝塞尔线段B[j+1′],B[j′]、B[j+1′]与封闭轮廓G中原来的二次贝塞尔线段B[0]到B[j-1]、B[j+2]到B[M-1]构成了一个新的封闭轮廓G′,令G=G′;最后删除S与B[j]的结束控制点构成的封闭轮廓。图11中(11a)为处理前的封闭轮廓G,(11b)为处理后的封闭轮廓G,(11c)为删除的封闭轮廓。
参照图12,如果是非相邻二次贝塞尔线段自相交,则将封闭轮廓G和其内含的包括自相交的非相邻二次贝塞尔线段的闭合环路分割成多个封闭轮廓的方法为:
假设两条自相交的非相邻二次贝塞尔线段分别为B[j]和B[k],j<k;首先计算B[j]和B[k]的交点S;然后将B[j]的起始控制点与S相连构成一条新的二次贝塞尔线段B[j′],并将S与B[k]的结束控制点相连构成一条新的二次贝塞尔线段B[k′],B[j′]、B[k′]与封闭轮廓G中原来的线段B[0]到B[j-1]、B[k+1]到B[M-1]构成了一个新的封闭轮廓G′,令G=G′;最后将S与B[j]的结束控制点和B[k]的起始控制点相连,形成了两条新的二次贝塞尔线段,将这两条新的二次贝塞尔线段与B[j+1]到B[k-1]中所有的二次贝塞尔线段构成了一个新的封闭轮廓G",将G"加入到字幕对象矢量轮廓信息表。图12中(12a)为处理前的封闭轮廓G,(12b)为分割后的封闭轮廓G′,(12c)为分割出来的封闭轮廓G"。
计算字幕对象矢量轮廓信息中两条二次贝塞尔线段交点的方法,从理论上来说,可以根据两条二次Bezier曲线的联合参数方程计算。但这种方法是不可取的,因为不但计算量巨大,而且都是基于浮点数的运算,算法的效率会比较低。因此,本实施方式采用“二分迭代法”。该方法的核心思想为:如果两条二次Bezier线段相交,那么根据中点将这两条二次Bezier线段分别分成两条二次Bezier线段,得到4条二次Bezier线段;然后再按照同样的方法,处理这4条线段,直到最终每条线段的起始控制点和结束控制点的空间直线距离小于某一个值(通常情况下,这个值为
),最终可以归结为计算两条直线段的交点。该方法具体包括以下步骤:
(I)假设两条相交的二次贝塞尔线段分别为B[j]和B[k],将B[j]和B[k]分别进行如下处理:
a.计算二次贝塞尔线段的起始控制点与结束控制点之间的空间直线距离L, ,其中,x0、y0为起始控制点横、纵坐标,x1和y1为结束控制点横、纵坐标;
b.判断L是否大于M,如果大于,则计算二次贝塞尔线段的中点,将二次贝塞尔线段在中点处划分成两条二次贝塞尔线段,所述的
c.重复步骤a至步骤b,直到划分后的每条二次贝塞尔线段的起始控制点与结束控制点之间的空间直线距离L小于或等于M;
(II)将B[j]和B[k]经过步骤(I)处理后,假设最终相交的两条二次贝塞尔线段分别为B[j′]和B[k′],计算B[j′]的起始控制点和结束控制点构成的直线与B[k′]的起始控制点和结束控制点构成的直线的交点。
本实施方式中,计算二次贝塞尔线段的中点的方法为:假设二次贝塞尔线段的三个控制点分别为P0、P1和P2,函数表达式为
B(t)=(1-t)2P0+2t(1-t)2P1+t2P2 t∈[0,1];
令t=0.5,计算二次贝塞尔曲线方程上的一点,该点便是二次贝塞尔线段的中点,其坐标的计算公式为B=(P0+2*P1+P2)/4。
如图14所示,R1是直线(P0,P1)的中点,R2是直线(P1,P2)的中点,R3是直线(P2,P0)的中点,Q是直线(R1,R2)与直线(R3,P1)的交点。Q点便是二次Bezier曲线(P0,P1,P2)的中点。
R1点横坐标R1.x=(P0.x+P1.x)/2,R1点纵坐标R1.y=(P0.y+P1.y)/2;R2点横坐标R2.x=(P1.x+P2.x)/2,R2点纵坐标R2.y=(P1.y+P2.y)/2。其中,P0.x、P0.y为P0点横、纵坐标;P1.x、P1.y为P1点横、纵坐标;P2.x、P2.y为P2点横、纵坐标。
Q点的横坐标Q.x=(R1.x+R2.x)/2=(P0.x+2*P1.x+P2.x)/4,Q点的纵坐标Q.y=(R1.y+R2.y)/2=(P0.y+2*P1.y+P2.y)/4。
存在非相邻的二次贝塞尔线段自相交情况的封闭轮廓G经过一次处理后,分割出来的封闭轮廓中仍有可能存在自相交的情况,如图15所示。(15a)所示的封闭轮廓经过一次处理后,将其分割成(15b)、(15c)和(15d)所示的封闭轮廓,其中(15c)所示的封闭轮廓仍然存在自相交的情况,因此需要重复上述步骤对(15c)所示的封闭轮廓进行再处理,直到分割后的所有封闭轮廓中没有自相交的情况发生。(15c)所示的封闭轮廓经过再处理后,分割成(15c1)和(15c2)所示的两个封闭轮廓。
③重复步骤②,直到封闭轮廓G中所有的自相交情况处理完毕。
④重复步骤①至步骤③,直到字幕对象矢量轮廓信息表中所有的封闭轮廓处理完毕。
(4)对经步骤(3)处理后的矢量轮廓信息中相交的封闭轮廓进行处理,使封闭轮廓之间互不相交。
在字幕对象的矢量轮廓信息中,由二次贝塞尔线段组成的封闭轮廓之间也可能存在相交的情况,即两个或多个封闭轮廓之间存在若干个交点。为了增强字幕对象的最终渲染效果,还需要对这种情况进行处理。
图16出示了对矢量轮廓信息中相交的封闭轮廓进行处理的方法流程,包括以下步骤。
①计算所有封闭轮廓中每条二次贝塞尔线段与其他封闭轮廓中的二次贝塞尔线段的交点,包括以下步骤:
a.遍历字幕对象矢量轮廓信息中所有的封闭轮廓,假设共有N个封闭轮廓,取出一个与已取不同的封闭轮廓G[i];
b.遍历G[i]中的所有二次贝塞尔线段,假设共有M个二次贝塞尔线段,取出一个与已取不同的二次贝塞尔线段B[j];
c.遍历除了封闭轮廓G[i]之外的所有其它封闭轮廓(包括G[0]到G[i-1],G[i+1]到G[N-1])中的所有二次贝塞尔线段,取出一个与已取不同的二次贝塞尔线段B[k];
d.判断B[j]和B[k]的外接矩形是否存在交集。如果存在,则使用上述“二分迭代法”计算B[j]和B[k]的交点;
e.重复步骤c,直到处理完其它封闭轮廓中所有的二次贝塞尔线段;
f.重复步骤b,直到处理完G[i]中所有的二次贝塞尔线段;
g.重复步骤a,直到处理完矢量轮廓信息中所有的封闭轮廓。
②将所有存在交点的二次贝塞尔线段在交点处分割成多条首尾相连的二次贝塞尔线段。
假设一条二次贝塞尔线段B的三个控制点分别是P[0]、P[1]、P[2],在B上有n个交点,分别为S[0]到S[n-1],每个交点对应的贝塞尔参数方程中的t值分别是S[0].t到S[n-1].t。
首先,在S[0]点处将线段B分成两条线段B1和B1′。
B1的三个控制点分别为P[0]、Q[0]、S[0],P[0]和S[0]的坐标已知,Q[0]的坐标为:
Q[0].x=(1-t)*P[0].x+t*P[1].x,
Q[0].y=(1-t)*P[0].y+t*P[1].y。
B1′的三个控制点分别为S[0]、R[0]、P[2],S[0]和P[2]的坐标已知,R[0]的坐标为:
R[0].x=(1-t)*P[1].x+t*P[2].x,
R[0].y=(1-t)*P[1].y+t*P[2].y。
其中,Q[0].x表示Q[0]点的横坐标,Q[0].y表示Q[0]点的纵坐标,R[0].x表示R[0]点横坐标,R[0].y表示R[0]点纵坐标;t=(S[0].t-P[0].t)/(P[2].t-P[0].t),P[0].t为P[0]点对应的贝塞尔参数方程中的t值,P[2].t为P[2]点对应的贝塞尔方程中的t值。
然后,在S[1]点处将线段B1′分成两条线段B2和B2′,方法与步骤①相同。
以此类推,最后在S[n-1]点处将线段Bn-1′分成两条线段Bn和Bn′;最终得到N+1条分割后的线段。图17出示了一条存在四个交点的二次贝塞尔线段在交点处进行分割的过程。
③确定所有封闭轮廓中包含的每条二次贝塞尔线段的内外边属性。
确定一条二次贝塞尔线段的内边/外边属性,只需要确定该条二次贝塞尔线段上的任意一个点在整个字幕对象的矢量轮廓信息中是内点还是外点即可,通常情况下可以使用该条线段的中点。如果该线段的中点是内点,则该条线段为内边;如果是外点,则该条线段为外边。
判断二次贝塞尔线段的中点在字幕对象所有封闭轮廓中是内点还是外点的方法包括以下步骤。
假设二次贝塞尔线段为B,B的三个控制点分别为P[0]、P[1]、P[2],中点为Q。
①确定B的方向值d:如果P[2].y>P[0].y,则d=1;如果P[2].y<P[0].y,则d=-1;如果P[2].y=P[0].y,则d=0。其中,P[0].y和P[2].y分别表示P[0]和P[2]的纵坐标。
②计算B的中点Q坐标。
③判断abs(P[2].y-P[0].y)是否大于abs(P[2].x-P[0].x),如是,则以Q点为起点,沿水平方向向右作一射线H;如否,则以Q点为起点沿竖直方向向上作一射线H。本实施方式中,假设沿水平方向向右作一射线H,如图18所示。计算字幕对象所有封闭轮廓中与H相交的除B之外的所有二次贝塞尔线段,假设有M条二次贝塞尔线段与H相交,分别为B[0]、B[1]至B[M-1]。其中,P[0].x和P[2].x分别表示P[0]和P[2]的横坐标,abs函数为取绝对值函数。
④分别计算B[i]的方向值d[i],方法与步骤①中计算d值的方法相同。其中,i=0、1、......、M-1。
⑤计算d[i]的和值d′:d′=d[0]+d[1]+......+d[M-1]。
⑥根据d和d′计算B的内外边属性值a:
a=1-abs(SIGN(d+d′)*SIGN(d′))。其中,SIGN(x)定义为(x==0)?0:((x>0)?1:-1)),即如果x=0,则SIGN(x)=0;如果x>0,则SIGN(x)=1;如果x<0,则SIGN(x)=-1。
如果a=0,则B为内边;如果a=1,则B为外边。
当确定了一个封闭轮廓中的一条二次贝塞尔线段的内外边属性后,则该封闭轮廓该条二次贝塞尔线段之后的二次贝塞尔线段的内外边属性与其相同,直到遇到一个交点为止。
利用上述方法可以确定所有封闭轮廓中包含的每条二次贝塞尔线段的内外边属性。
④将属性为内边的二次贝塞尔线段删除,并根据交点重构矢量轮廓信息中的封闭轮廓。
当确定了矢量轮廓信息中所有的封闭轮廓中包含的每条二次贝塞尔线段的内外边属性后,删除所有标记为内边的二次贝塞尔线段的方法为:在每条二次贝塞尔线段中,都有一个边界属性变量表示内边/外边属性,遍历矢量轮廓信息中所有的二次贝塞尔线段,将边界属性为内边的二次贝塞尔线段从封闭轮廓中删除即可。
删除属性为内边的二次贝塞尔线段后,需要对所有的封闭轮廓重新进行规并,即根据交点将二次贝塞尔线段连接起来,重新构建每个封闭轮廓。重新构建的封闭轮廓一定是互为不相交的封闭轮廓。
规并一个字幕对象的具体方法包括以下步骤:
a.从所有封闭轮廓中取出一个与已取不同的封闭轮廓G1;
b.判断G1的最后一条二次贝塞尔线段的结束点坐标与第一条二次贝塞尔线段的起始点坐标的差值是否小于等于阀值T,通常T取0.00001,如是,则G1不需要处理,重复步骤a至步骤b,直到所有的封闭轮廓被处理完毕;
c.取出与G1相邻的下一个封闭轮廓G2;
d.判断G1的曲线尾与G2的曲线头或者G1的曲线头与G2的曲线尾是否重合,即判断G1的最后一条二次贝塞尔线段的结束点坐标与G2的第一条二次贝塞尔线段的起始点坐标的差值或者G1的第一条二次贝塞尔线段的起始点坐标与G2的最后一条二次贝塞尔线段的结束点坐标的差值是否小于等于阀值T,如是,则将G1、G2合并,并从矢量轮廓中删除G2;
e.取出与G2相邻的下一个封闭轮廓G2′,令G2=G2′,重复步骤d,直到G2为最后一个封闭轮廓或者G2与G1相等;
f.重复步骤a至步骤e,直到所有的封闭轮廓被处理完毕。
上述过程用伪代码描述如下:
G1=矢量轮廓中第一个封闭轮廓;
while(G1!=NULL)//遍历矢量轮廓中所有的封闭轮廓
{
while(G1需要重新处理)
{
G2=G1.Next;//G2是与G1相邻的下一个封闭轮廓
while(G2!=NULL && G2!=G1)
{
if(G2需要重新处理)
{
if(G1的曲线尾与G2的曲线头重合)
{
//将G1和G2首尾相连
G1.Tail.Next=G2.Head;
G1.Head.Prev=G2.Tail;
G2.Tail.Next=G1.Head;
G2.Head.Prev=G1.Tail;
G1.Tail=G2.Tail;
G′=G2;
G2=G2.Prev;
从封闭轮廓链表中删除G′;
}
else if(G1的曲线头与G2的曲线尾重合)
{
//将G1和G2首尾相连
G2.Tail.Next=G1.Head;
G2.Head.Prev=G1.Tail;
G1.Tail.Next=G2.Head;
G1.Head.Prev=G2.Tail;
G1.Head=G2.Head;
G′=G2;
G2=G2.Prev;
从封闭轮廓链表中删除G′;
}
}
G2=G2.Next;
}
}
G1=G1.Next;
}
⑤标记所有封闭轮廓的方向,包括顺时针方向和逆时针方向。顺时针方向标记为1,逆时针标记为-1。判断一条封闭曲线G的方向,只需要取出G中任意一条二次贝塞尔线段,判断其方向即可。具体处理步骤如下:
a.从封闭轮廓G中任取一条二次贝塞尔线段为B,假设B的三个控制点分别为P[0]、P[1]、P[2],中点为Q;
b.确定B的方向值d:如果P[2].y>P[0].y,则d=1;如果P[2].y<P[0].y,则d=-1;如果P[2].y=P[0].y,则d=0;
c.计算B的中点Q;
d.判断abs(P[2].y-P[0].y)是否大于abs(P[2].x-P[0].x),如是,则以Q点为起点,沿水平方向作一射线H;如否,则以Q点为起点沿竖直方向作一射线H;计算字幕对象所有封闭轮廓中与H相交的除B之外的所有二次贝塞尔线段,假设有M条二次贝塞尔线段与H相交,分别为B[0]、B[1]至B[M-1];
e.分别计算B[i]的方向值d[i],方法与步骤①中计算d值的方法相同;其中,i=0、1、......、M-1;
f.计算d[i]的和值d′:d′=d[0]+d[1]+......+d[M-1];
g.计算B的方向属性b的值,b=d*(1-2*abs(d′));如果b>0,则封闭轮廓G为顺时针方向,否则为逆时针方向。
(5)将经步骤(4)处理后的矢量轮廓信息中的封闭轮廓转换成多边形。
字幕对象的矢量轮廓信息经过上述处理后,在对其加内边、加外边、加侧边、加影等渲染之前,还需要将矢量轮廓信息中所有的封闭轮廓转换成多边形,即将所有的封闭轮廓离散化为直线段,也就是将封闭轮廓中所有的二次贝塞尔线段转换成直线段。之所以要这样处理,主要的原因包括以下几个方面。
第一,字幕对象加内边、加外边、加侧边、加影等渲染都是基于字幕矢量轮廓的。在加多个外边时,需要沿着这个矢量轮廓向四周等距的扩展X1个像素(X1为第一条边的厚度),而后再沿着经上面操作之后形成的矢量轮廓,再向四周等距的扩展X2个像素(X2为第二条边的厚度);加侧边时,需要沿着一个矢量轮廓(这个矢量轮廓是加完外边之后的矢量轮廓)的Y角度扩展X个像素(Y为侧边的方向,X为侧边的厚度)。如果按照贝塞尔曲线进行处理,那么一条二次Bezier曲线向外或向内扩展后的矢量轮廓就不是一个二次贝塞尔曲线了,而是一个高价的贝塞尔曲线,也就是说,在空间上与一条二次贝塞尔等距的曲线无法精确的用二次贝塞尔曲线方程来表示。这样一来,如果继续使用这个高阶的贝塞尔曲线进行后续的渲染,例如加多个内边、多个外边、多个侧边等,就需要首先将高阶的贝塞尔曲线进行降阶处理,降阶处理过程的计算量非常大,所需要的存储量也非常大,在实际实现中是不可行的。
但是如果使用一个多边形来表示一个矢量轮廓,就可以很容易的解决这个问题,因为一个多边形向外或向内扩展后的矢量轮廓仍然可以用一个多边形来表达。
第二,计算一条二次贝塞尔曲线的等距曲线自身算法复杂,而且需要很大的计算量,在实际实现中是不可行的。
第三,为了保证渲染精度,保证渲染细节上的效果,以上对贝塞尔曲线的处理都是基于原来像素空间的浮点数运算的。将贝塞尔封闭曲线离散化成由直线段组成的封闭多边形之后,可以将原来的像素空间放大512倍,将原来的浮点数坐标使用整数型来表示,所有的运算也就转化为整数型运算,从而大大提高渲染的效率。
第四,将原来的像素空间放大512倍之后,对于后续的计算,可以进行诸多的优化,例如对三角函数运算、反三角函数运算、除法运算幂运算、开方运算等占用大量机器指令的数学运算,可以事先建立一些表。在系统初始化时建好这些表,在后面的运算中直接查表即可。这样可以大大提高字幕渲染的效率。例如可以在0到512整数值之间定义一个反正切函数的表Atn,在系统初始化时,创建这个表:
Atn[i]=(int)(0.5+atan((double)i/512)*2048/3.14159265)
其中,atan是操作系统提供的反三角函数,i是从0到512的整型值。
在后面根据水平矢量dx和垂直矢量dy使用反正切函数计算一个角度A时,可以直接使用这个表:
if(abs(dy)>=abs(dx))
A=1024-Atn[(int)(abs(dx)÷abs(dy)×512+0.5)]
else
A=Atn[(int)(abs(dy)÷abs(dx)×512+0.5)]
对于其他的三角函数、反三角函数、除法运算、幂运算、开方运算等都可以使用同样的原理进行优化。
第五,将原来的像素空间放大512倍之后,在进行纹理贴图等后续一系列图像处理时,一个像素就分成512级别的子像素(Sub-Pixel),可以大大提高边缘反走样的效果。
将二次贝塞尔封闭轮廓离散化为直线段的核心思想包含了“t值的自适应步长选取”、“离散”、“化直”和“浮点坐标整数化”四个方面。
根据二次贝塞尔曲线参数方程,对t值从0到1每次步进一个数值,根据t值计算出对应的二次贝塞尔曲线上的点,假设相邻两个t值计算出来的点为Q0和Q1,如果Q0和Q1的空间直线距离大于
,则在Q0的t值和Q1的t值之间再次选择一个t值,直到每两个t值对应的二次贝塞尔曲线上的点Q0和Q1的空间直线距离小于等于
为止。这时Q0和Q1构成的直线就是离散化后的一条直线段,最后将每个点的坐标放大M倍,使原来的浮点数坐标变换为整数型坐标。
之所以将离散化后的每条直线段的空间距离限制在
,主要的思想是使得离散化后的每条直线段的起点和终点的水平距离和垂直距离都小于等于
,也就是使一条直线段最多经过
个像素。这样就可以保证字幕渲染的精度。
图19出示了将一个字幕对象的所有封闭轮廓离散化为直线段的具体方法流程,主要包括以下步骤。
①遍历字幕对象的矢量轮廓信息,取出一个与已取不同的封闭轮廓G[i],假设字幕对象的矢量轮廓信息中包括N个封闭轮廓,则i∈[0,N-1],N和i均为正整数。
②遍历封闭轮廓G[i],取出一条与已取不同的二次贝塞尔线段B[j],假设G[i]中包含M个二次贝塞尔线段,则j∈[0,M-1],j为正整数。
③将B[j]离散化为直线段,具体的实现过程如下。
参照图20,假设B[j]的三个控制点分别为P[0]、P[1]和P[2];P[0]为起始控制点,P[1]为中间控制点,P[2]为终止控制点。
首先,以P[0]点为起点,计算B[j]离散化后的第一条直线段L[j][0]。
a.设置t的初始值,t=P[0].t+L;其中,L为常数,0<L<1。本实施例中L=0.0625,取该值的意义是先假设将B[j]离散化为16条直线段,然后再根据每一条直线段的长度来确定是否继续进行细分。P[0].t为P[0]点对应的二次贝塞尔曲线方程中的t值,P[0].t=0。
b.根据二次贝塞尔曲线方程计算t值对应的二次贝塞尔曲线上点Q[0]的坐标。
c.计算P[0]点和Q[0]点之间的空间直线距离d, ,其中,x0、y0是P[0]的坐标,x1、y1是Q[0]的坐标。
d.判断 是否成立,如果成立,则令t=(P[0].t+Q[0].t)/2,其中,Q[0].t为Q[0]点对应二次贝塞尔曲线方程中的t值;重复步骤b至步骤d,直到 ;最终的Q[0]点与P[0]点构成的直线便是第一条离散化后的直线段L[j][0];将Q[0]点和坐标放大M倍,本实施例中M=512。
然后,以Q[0]点为起点,采用与计算B[j]离散化后的第一条直线段相同的方法计算第二条直线段L[j][1]。
以此类推,直到处理到B[j]的结束控制点P[2]为止,获得K条直线段L[j][0]至L[j][K-1]。
④重复步骤②至步骤③,直到G[i]中所有的二次贝塞尔线段处理完毕。
⑤重复步骤①至步骤④直到字幕对象的矢量轮廓信息中所有的封闭轮廓处理完毕。
(6)对经步骤(5)转换后的矢量轮廓信息中的多边形加内边或外边。
经过上面的离散化后,字幕对象的矢量轮廓信息由二次贝塞尔线段组成的封闭轮廓转换为了封闭多边形矢量轮廓。
每个封闭多边形的属性包括:
①指向前一个、后一个封闭多边形的指针,这两个指针变量使得整个字幕对象的矢量轮廓构成了一个双向循环链表,方便后续的处理;
②多边形中的所有直线段(多边形的边)链表;
③多边形的方向,顺时针为正,逆时针为负;
④多边形的外接矩形。
多边形中每条边的属性包括:
①指向前一条、后一条边的指针,这两个指针变量使得整个多边形的边构成了一个双向循环链表,方便后续的处理;
②边的起始点的x坐标和y坐标;
③边的角度a1,即边与X轴正向的夹角;
④边的延长线与和其相邻的下一条边的夹角a2;
⑤边的延长线与和其相邻的下一条边的角平分线的角度a3;
⑥边的起始点加边时移动的水平矢量dx;
⑦边的起始点加边时移动的垂直矢量dy。
其中,a1、a2、a3表示的角度如图21所示,多边形的方向为顺时针。
多边形的直线段链表、顺时针/逆时针方向属性、每条边的坐标都已经在离散化的过程中赋予了有效的值。
在对多边形进行后续处理之前,先要计算每个多边形的外接矩形和每条边的a1、a2、a3、dx、dy的属性值。
计算一个多边形的外接矩形,首先要计算构成这个多边形的每条边的外接矩形,然后将这些矩形并(Unoin)起来即可。边的外接矩形和多变形的外接矩形如图22所示。
如图21所示,a1根据P0的坐标(x0,y0)和P1的坐标(x1,y1)使用反三角函数计算,即a1=atan((y1-y0)/(x1-x0)),atan为反正切函数。
a2的值等于该边的a1值和与其相邻的下一条边的a1值的差值。
a3=a1-a2/2。
dx=Cos(a3)÷Sin(a2/2)。
dy=Sin(a3)÷Sin(a2/2)。
其中Sin为正玄函数,Cos为余玄函数。
在一个字幕对象的矢量轮廓中,既有顺时针方向的多边形,又有逆时针方向的多边形,在计算每条边的角度a1、a2、a3和加边矢量dx、dy时都是根据多边形的方向进行的。另外,在字幕对象的渲染中,可以对多边形加不同类型的边,例如尖角边、圆角边、方角边等。在加圆角边和方角边,需要在原来多边形的顶点处增加一些顶点。如图23所示,其中23a为加尖角边示意图;23b为加方角边示意图,此时需要增加一个顶点;23c为加圆角边示意图,此时需要增加多个顶点。
由于上述两个原因,需要根据原来的多边形矢量重新创建出不同的多边形矢量。创建出加内边或外边的多边形矢量轮廓的核心思想是:将原来的多边形轮廓中的封闭多边形逐个拷贝,同时根据加内边还是加外边,以及当前多边形的顺时针/逆时针方向,重新对其中每条边的a1和a2值进行修正;然后根据加边的类型(尖角边、圆角边、方角边等)对多边形的顶点进行处理,加尖角边时不需要增加顶点,加方角边时需要增加一个顶点,加圆角边时则需要根据顶点的角度增加足够多的点,以保证圆角边的平滑。
图24出示了创建出加内边或外边的矢量轮廓的具体流程,主要包括以下步骤。
①遍历矢量轮廓信息中的多边形,取出一个与已取不同的多边形Q[i]。
②复制Q[i],得到Q′[i]。
③对于加外边的情况,如果Q′[i]的方向为逆时针,则取出其中的每条边L[j],按照如下公式修正每条边的a1和a2的值:
L[j].a1=L[j].a1+∏;
L[j].a2=2∏-L[j].a2;其中,∏=180度。
如果Q′[i]的方向为顺时针,则不需要做任何处理。
对于加内边的情况,如果Q′[i]的方向为顺时针,则取出其中的每条边L[j],按照如下公式修正每条边的a1和a2的值:
L[j].a1=L[j].a1+∏;
L[j].a2=2∏-L[j].a2。
如果Q′[i]的方向为逆时针,则不需要做任何处理。
④判断加边类型,如果加尖角边,则不需要增加顶点,转至步骤。
如果加方角边,则需要增加一个顶点。假设有三个连续的顶点P[0]、P[1]、P[2],需要在原来的顶点为P[1]处增加一个新的顶点为P′。令P′的x坐标、y坐标、a1、a2、a3、dx、dy的初始值等于P[1]中的相应值,即P′=P[1]。然后按照如下公式重新修正P[1]的各个属性值:
P[1].a1=P[0].a1+P′.a2/2;
P[1].a2=P[1].a1-P[0].a1;
P[1].a3=P[0].a1+P[1].a2/2;
P[1].dx=Cos(P[1].a3)÷Sin(P[1].a2/2);
P[1].dy=Sin(P[1].a3)÷Sin(P[1].a2/2)。
如果加圆角边,则需要根据顶点的角度增加足够多的点,具体的实现过程为:首先按照上述“方角边增加一个顶点”的方法,在顶点P[1]处增加一个新的顶点为P′,修正P[1]的各个属性值;然后判断修正后的P[1].a2是否小于∏/16,如果不小于,则重复上述步骤,继续在P[1]处增加一个新的顶点,直到P[1].a2<∏/16。需要注意的是:在进行新的一次计算时,P[0]、P[1]、P[2]的值已经发生了变化,其中P[0]为新增加的顶点P′,P[1]是修正之后的P[1],P[2]的值不变。
⑤重复以上步骤,直到处理完矢量轮廓信息中所有的多边形。此时可以得到两个新的多边形矢量轮廓G1和G2,其中G1将用在加内边的后续处理中,G2将用在加外边的后续处理中。由于G1、G2与原来的矢量相比增加了一些顶点,所以需要重新计算G1和G2的外接矩形。
本发明所述的方法并不限于上述具体实施方式,本领域技术人员根据本发明的技术方案得出其他的实施方式,同样属于本发明的技术创新范围。