[VC新手]问矢量轮廓描述与填充算法 请问 Windows 下矢量字体是如何描述的,如以 TrueType 字体为例,其格式如何?我要做的应用是最终控制物理器件的运动轨迹走出汉字(大小可变)的外形轮廓,然后以水平、垂直或45°方向的直线填充(密度可调),请问该用什么算法实现?由于我对矢量格式一无所知,希望大家能教以方法,或提供基础性资料,网址亦可 解决方案 » 免费领取超大流量手机卡,每月29元包185G流量+100分钟通话, 中国电信官方发货 显示汉字GetPath将汉字轮廓以线段与贝赛尔线的形式存在数组中下面的自己研究! GetPath是个通用的方法:不只是text,支持path的GDI作图函数都可以.但通用的速度就般般了.可以用GetGlyphOutline函数解决问题,Get出来的数据处理起来有些麻烦,你要找些原代码看看.看你的问题,是只要填充?好象用FillPath就可以了吧. fillPath 好像只能在电脑输出设备上看到结果,但我不仅仅要在显示器上处理我需要矢量的描述数据,然后控制两个步进电机,使其运动轨迹为矢量数据所描述的轮廓 要实践你的功能,不一定要用GetPath,我的思路是,先在Form上画出你需要的字,然后用扫描线的方法复制到你的设备上,设备只需用MoveTo及LineTovoid __fastcall TForm1::Button1Click(TObject *Sender){ String ch="噗"; //可以多个字符 Canvas->Font->Name="宋体"; Canvas->Font->Color=clBlack; Canvas->Font->Size=40; Canvas->TextOut(100,100,ch); int w=Canvas->TextWidth(ch); int h=Canvas->TextHeight(ch); TColor c,oldc; for(int j=0;j<h;j++) { oldc=c=clWhite; for(int i=0;i<w;i++) { c=Canvas->Pixels[100+i][100+j]; if (c!=oldc) { if (c==clBlack) Canvas->MoveTo(300+i,100+j); //在你的设备上MoveTo else Canvas->LineTo(300+i,100+j); //在你的设备上LineTo oldc=c; } } }} 感谢 bluebohe(薄荷) 你的方法给了我一个方向,我要做的跟“用铣刀在铁板上刻字”差不多,但精度要求很高,就是用激光在任何材料表面(或在透明材料内部雕刻)刻文字或图形,文字可能很大也可能小到要用放大镜看。 我现在的思路是先编辑好各种对象,然后开一个预览窗口,将各个对象逐个显示在预览窗口中进行线扫描。但是假如我只需要汉字的轮廓并不填充的话,可能速度会比较慢,还有文字很小的话不知道精度够不够。 我本来是做单片的编程的,对Windows编程很生疏,为了做这个事才开始真正接触,对你上面这段BCB代码(我猜的,不知是不是)要表达的原理基本能猜懂:),我选择的工具是VC,自己看书学了快三个月了,基本实现的软件的界面和编辑功能,但感觉还是没有摸着Windows编程的门,有时候一个很小的问题会将我难住好几天,希望以后能得到你更多的指点。 我是拷贝别人的代码,这些代码我找了一上午,http://expert.csdn.net/Expert/topic/2098/2098463.xml?temp=.3817255 现在我已经知道了怎样获取矢量数据了,其中曲线部分大多用贝塞尔线来描述的,但是我是要用来做控制的,不能用库函数画,现在的问题是如何生成贝塞尔曲线给定贝塞尔曲线的三个关键点,怎样用moveto,lineto或putpixel等来生成这条曲线呢? typedef struct xyz { double x; double y; double z;}XYZ,*PXYZ;//生成两点间插值点//参数:nCurPos为待计算点相对于已有点的位置,pOrgPt为已有点,ptPrev// 为已计算出的前一个点,o_pt存储计算出的插值点,g_cDivNum 杨条插值点段数void CalcInterpolatePt( const short nCurPos, const PXYZ pOrgPt, const PXYZ ptPrev, PXYZ o_pt ,unsigned char g_cDivNum){ XYZ pta, ptb, ptc; short nCurEndPos = 0; if( nCurPos ) { pta = *ptPrev; nCurEndPos = g_cDivNum - 1; } else nCurEndPos = 0; ptb = pOrgPt[0]; //TTPOLYCURVE结构中存储的已知控制点 ptc.x = o_pt[nCurEndPos].x = ( pOrgPt[0].x + pOrgPt[1].x )/2; ptc.y = o_pt[nCurEndPos].y = ( pOrgPt[0].y + pOrgPt[1].y )/2; o_pt[nCurEndPos].z = 0.0; if( g_cDivNum == 1 ) //不必再插入插值点 return; else if( nCurPos == 0 ) //起始段 return; //按指定段数加入插值点 else { double t = 0.0; double dUnit = 1/(double)g_cDivNum; for( short i = 0; i < g_cDivNum - 1; i ++ ) { //从VC帮助中查出样条插值点计算公式 //x(t) = (xA-2xB+xC)*t^2 + (2xB-2xA)*t + xA //y(t) = (yA-2yB+yC)*t^2 + (2yB-2yA)*t + yA t = ( i + 1 ) * dUnit; o_pt[i].x = ( pta.x - 2 * ptb.x + ptc.x ) * t * t + 2 * ( ptb.x - pta.x ) * t + pta.x; o_pt[i].y = ( pta.y - 2 * ptb.y + ptc.y ) * t * t + 2 * ( ptb.y - pta.y ) * t + pta.y; o_pt[i].z = 0.0; } } return;}//对由p指向的wPtNum个控制点表示的样条进行插值计算,将计算出的//插值点记录在o_pPts指向的点数组中void InterpolateSpline( const WORD wPtNum, const XYZ * p, XYZ * o_pPts,unsigned char g_cDivNum ){ ASSERT( AfxIsValidAddress( p, 3 * wPtNum * sizeof(double) ) ); ASSERT( o_pPts ); //计算插值后点数 short nPtNum = ( wPtNum - 2 )*( g_cDivNum - 1 ) + wPtNum + 1; //计算各点坐标 o_pPts[0] = p[0]; //起点 for( short i = 0, j = 1; i < wPtNum && j < nPtNum; i ++ ) { if( ( i + 1 ) != wPtNum ) //中间各点 { //生成两点间插值点 CalcInterpolatePt( i, (XYZ *)&p[i], &o_pPts[j-1], &o_pPts[j] ,g_cDivNum); if( i ) j += g_cDivNum; else j ++; } else //终点 { o_pPts[j] = p[i]; j ++; } }} 怎样使列表控件的边框具有凹陷边缘但不带黑线边框? 关于strtok函数问题,帮着找找错 UDP 分包问题? CAsyncSocket类问题 vs2003 运行库设置如何更改为 多线程MT调用 大哥们,谁看过了《深入浅出MFC》?谈谈心得吧 telnet 连接 CSocket服务器,消息发送问题 急!!在线!!求图象处理算法源码--三次样条曲线、三次参数样条曲线、Bezier曲线、B样条曲线 每个100分!! 关于CString 高分相求---------->if(满足)一定给分!!! 100分求读取USB设备的供应商ID和产品ID 问矢量轮廓描述与填充算法
GetPath将汉字轮廓以线段与贝赛尔线的形式存在数组中
下面的自己研究!
但通用的速度就般般了.
可以用GetGlyphOutline函数解决问题,Get出来的数据处理起来有些麻烦,你要找些原代码看看.
看你的问题,是只要填充?好象用FillPath就可以了吧.
然后用扫描线的方法复制到你的设备上,设备只需用MoveTo及LineTovoid __fastcall TForm1::Button1Click(TObject *Sender)
{
String ch="噗"; //可以多个字符
Canvas->Font->Name="宋体";
Canvas->Font->Color=clBlack;
Canvas->Font->Size=40;
Canvas->TextOut(100,100,ch);
int w=Canvas->TextWidth(ch);
int h=Canvas->TextHeight(ch);
TColor c,oldc;
for(int j=0;j<h;j++)
{
oldc=c=clWhite;
for(int i=0;i<w;i++)
{
c=Canvas->Pixels[100+i][100+j];
if (c!=oldc)
{
if (c==clBlack)
Canvas->MoveTo(300+i,100+j); //在你的设备上MoveTo
else
Canvas->LineTo(300+i,100+j); //在你的设备上LineTo
oldc=c;
}
}
}
}
我现在的思路是先编辑好各种对象,然后开一个预览窗口,将各个对象逐个显示在预览窗口中进行线扫描。但是假如我只需要汉字的轮廓并不填充的话,可能速度会比较慢,还有文字很小的话不知道精度够不够。
我本来是做单片的编程的,对Windows编程很生疏,为了做这个事才开始真正接触,对你上面这段BCB代码(我猜的,不知是不是)要表达的原理基本能猜懂:),我选择的工具是VC,自己看书学了快三个月了,基本实现的软件的界面和编辑功能,但感觉还是没有摸着Windows编程的门,有时候一个很小的问题会将我难住好几天,希望以后能得到你更多的指点。
http://expert.csdn.net/Expert/topic/2098/2098463.xml?temp=.3817255
double x;
double y;
double z;
}XYZ,*PXYZ;//生成两点间插值点
//参数:nCurPos为待计算点相对于已有点的位置,pOrgPt为已有点,ptPrev
// 为已计算出的前一个点,o_pt存储计算出的插值点,g_cDivNum 杨条插值点段数
void CalcInterpolatePt( const short nCurPos, const PXYZ pOrgPt,
const PXYZ ptPrev, PXYZ o_pt ,unsigned char g_cDivNum)
{
XYZ pta, ptb, ptc;
short nCurEndPos = 0;
if( nCurPos )
{
pta = *ptPrev;
nCurEndPos = g_cDivNum - 1;
}
else
nCurEndPos = 0;
ptb = pOrgPt[0]; //TTPOLYCURVE结构中存储的已知控制点
ptc.x = o_pt[nCurEndPos].x = ( pOrgPt[0].x + pOrgPt[1].x )/2;
ptc.y = o_pt[nCurEndPos].y = ( pOrgPt[0].y + pOrgPt[1].y )/2;
o_pt[nCurEndPos].z = 0.0;
if( g_cDivNum == 1 ) //不必再插入插值点
return;
else if( nCurPos == 0 ) //起始段
return;
//按指定段数加入插值点
else
{
double t = 0.0;
double dUnit = 1/(double)g_cDivNum;
for( short i = 0; i < g_cDivNum - 1; i ++ )
{
//从VC帮助中查出样条插值点计算公式
//x(t) = (xA-2xB+xC)*t^2 + (2xB-2xA)*t + xA
//y(t) = (yA-2yB+yC)*t^2 + (2yB-2yA)*t + yA
t = ( i + 1 ) * dUnit;
o_pt[i].x = ( pta.x - 2 * ptb.x + ptc.x ) * t * t +
2 * ( ptb.x - pta.x ) * t + pta.x;
o_pt[i].y = ( pta.y - 2 * ptb.y + ptc.y ) * t * t +
2 * ( ptb.y - pta.y ) * t + pta.y;
o_pt[i].z = 0.0;
}
}
return;
}//对由p指向的wPtNum个控制点表示的样条进行插值计算,将计算出的
//插值点记录在o_pPts指向的点数组中
void InterpolateSpline( const WORD wPtNum, const XYZ * p,
XYZ * o_pPts,unsigned char g_cDivNum )
{
ASSERT( AfxIsValidAddress( p, 3 * wPtNum * sizeof(double) ) );
ASSERT( o_pPts );
//计算插值后点数
short nPtNum = ( wPtNum - 2 )*( g_cDivNum - 1 ) + wPtNum + 1;
//计算各点坐标
o_pPts[0] = p[0]; //起点
for( short i = 0, j = 1; i < wPtNum && j < nPtNum; i ++ )
{
if( ( i + 1 ) != wPtNum ) //中间各点
{
//生成两点间插值点
CalcInterpolatePt( i, (XYZ *)&p[i], &o_pPts[j-1],
&o_pPts[j] ,g_cDivNum);
if( i )
j += g_cDivNum;
else
j ++;
}
else //终点
{
o_pPts[j] = p[i];
j ++;
}
}
}