利用VC绘制对数坐标系
目标:绘制以任意频率为起点、任意频率为终点的对数坐标,并能对坐标进行任意缩放。
实现方法:
1、定义
标准频率:频率值为10N的相应的频率点,其中N=…-2,-1,0,1,2,3…,单位MHz。如0.01MHZ、0.1MHz、1MHz、10MHz、100MHz等都是标准频率。
2、思路
首先找出标准频率,画出标准频率线,然后根据标准频率画出其他频率线。
3、实现
(1)对数坐标系数学基础
如图所示的对数坐标系中:
由此,若知道上图中的三个点的坐标,可以求出另一点的坐标。
(2)找出起始|终止标准频率的代码:
double stdStartFreq,stdStopFreq;// 标准频率起始点、终止点
// 格式化标准起始频率
for(int i=0;i<7;++i)
{
if(StartFreq==pow((double)10,i-2))
{
stdStartFreq=StartFreq;
break;
}
else if(StartFreq>pow((double)10,i-2) && StartFreq<pow((double)10,i-1))
{
stdStartFreq=pow((double)10,i-1);
break;
}
}
// 格式化标准终止频率
for(int i=0;i<7;++i)
{
if(StopFreq==pow((double)10,i-2))
{
stdStopFreq=StopFreq;
break;
}
else if(StopFreq>pow((double)10,i-2) && StopFreq<pow((double)10,i-1))
{
stdStopFreq=pow((double)10,i-2);
break;
}
}
起始标准频率就是第一个大于起始频率的标准频率;终止标准频率就是最后一个小于终止频率的标准频率。
举例:如果起始频率为1.9MHz,终止频率为201MHz,那么起始标准频率为10MHz,终止标准频率为100MHz;如果起始频率为1.9MHz,终止频率为20.1MHz,那么起始标准频率为10MHz,终止标准频率为10MHz;如果起始频率为1.9MHz,终止频率为2.01MHz,那么起始标准频率为10MHz,终止标准频率为1MHz。
(3)三种情况
①起始频率≤起始标准频率<终止标准频率≤终止频率
在这种情况下,首先画出起始|终止标准频率线。对于起始频率和起始标准频率之间的部分,由起始标准频率递减向起始频率画出虚线;对于终止标准频率和终止频率之间的部分,由终止标准频率向终止频率递增画出虚线;对于起始标准频率和终止标准频率之间的部分,首先找到二者之间的标准频率,然后根据标准频率(包括起始|终止标准频率)画出其间的虚线。
②起始频率<起始标准频率=终止标准频率<终止频率
这种情况是第一种情况的特例。因为起始标准频率=终止标准频率,所以第一种情况里只有两种情况来画虚线。
③终止标准频率<起始频率<终止频率<起始标准频率
在这种情况下,先找出终止标准频率,然后依据终止标准频率递增画出起始频率和终止频率之间的虚线。
4、其他问题
(1)细化间隔
由于对数坐标相同频率段的间隔不同,如10~20MHz的间隔与80~90MHz的间隔不同,前者大于后者;另外,考虑到坐标系放大时,如200MHz~300MHz频率段,整个坐标系中无虚线,只有横线,很难对测试曲线中某个点的频率进行粗略判断。因此,对于比较大的间隔,应该进行细化。
方法就是利用相邻两虚线的间隔所占坐标横轴的比例进行判断,若大于某个数值则有必要进行细化。由于间隔有大有小,考虑到细化的间隔不能影响整体对数坐标的效果,因此细化的竖线用灰色虚线表示,且将间隔分成不同等级,不同等级画不同条灰色虚线。
(2)坐标标注
坐标标注同样利用相邻两虚线的间隔所占坐标横轴的比例来进行判断,大于某个设定值后才进行标注,否则不进行标注。
【源代码如下:】
//绘制对数坐标
voidCEMCView::DrawLogCoords(CDC*pDC,doubleStartFreq,doubleStopFreq)
...{
CStringnote;
CRectrect;
this->GetClientRect(&rect);
ORIGIN_X=rect.left+rect.Width()/10;//坐标原点X坐标
ORIGIN_Y=rect.bottom-rect.Height()/10;//坐标原点Y坐标
COORD_TOP=rect.top+rect.Height()/10;//坐标系最高点Y坐标
COORD_RIGHT=rect.right-rect.Width()/10;//坐标系最右点X坐标
pDC->MoveTo(ORIGIN_X,ORIGIN_Y);
pDC->LineTo(ORIGIN_X,COORD_TOP);//画纵坐标轴
pDC->MoveTo(ORIGIN_X,ORIGIN_Y);
pDC->LineTo(COORD_RIGHT,ORIGIN_Y);//画横坐标轴
note.Format(L"%4.2fM",StartFreq);
pDC->TextOutW(ORIGIN_X-15,ORIGIN_Y+5,note);//原点标注
//画横格线
doubleyInc=(ORIGIN_Y-COORD_TOP)/9.0;
doubletmp=(double)ORIGIN_Y-yInc;
for(inti=0;i<8;++i)
...{
pDC->MoveTo(ORIGIN_X,(int)tmp);
pDC->LineTo(COORD_RIGHT,(int)tmp);
note.Format(L"%d",10*(i+1));
pDC->TextOutW(ORIGIN_X-25,(int)tmp-8,note);//z纵坐标标注
tmp-=yInc;
}
pDC->MoveTo(ORIGIN_X,COORD_TOP);
pDC->LineTo(COORD_RIGHT,COORD_TOP);
note.Format(L"%d",90);
pDC->TextOutW(ORIGIN_X-25,COORD_TOP-8,note);//z纵坐标标注
note.Format(L"[dBuV]");
pDC->TextOutW(ORIGIN_X-25,COORD_TOP-28,note);//z纵坐标标注
//画竖格线
//|..|.
//|..|.
//|..|.
//|..|.
//|..|.
//|..|.
//定义:标准频率,是指0.01MHz、0.1MHz、1MHz
//10MHZ、100MHz、1000MHz等频率
doublestdStartFreq,stdStopFreq;//标准频率起始点、终止点
//格式化标准起始频率
for(inti=0;i<7;++i)
...{
if(StartFreq==pow((double)10,i-2))
...{
stdStartFreq=StartFreq;
break;
}
elseif(StartFreq>pow((double)10,i-2)&&StartFreq<pow((double)10,i-1))
...{
stdStartFreq=pow((double)10,i-1);
break;
}
}
//格式化标准终止频率
for(inti=0;i<7;++i)
...{
if(StopFreq==pow((double)10,i-2))
...{
stdStopFreq=StopFreq;
break;
}
elseif(StopFreq>pow((double)10,i-2)&&StopFreq<pow((double)10,i-1))
...{
stdStopFreq=pow((double)10,i-2);
break;
}
}
doubletotalRatio=log10(StopFreq/StartFreq);//整个频率段所占的比例
inttotalLen=COORD_RIGHT-ORIGIN_X;//总长度
if(stdStartFreq<=stdStopFreq)//起始频率和终止频率相差大于等于一个数量级,如StartFreq=2.5,StopFreq=200
...{
doublestartRatio=log10(stdStartFreq/StartFreq)/totalRatio;//起始频率与标准起始频率之间的部分所占的比例
doublestdRatio=log10(stdStopFreq/stdStartFreq)/totalRatio;//标准起始频率和标准终止频率之间部分所占的比例
doublestopRatio=log10(StopFreq/stdStopFreq)/totalRatio;//标准终止频率和终止频率之间部分所占的比例
doublexStdStart=ORIGIN_X+startRatio*totalLen;//标准起始频率所在的X坐标
pDC->MoveTo((int)xStdStart,ORIGIN_Y);
pDC->LineTo((int)xStdStart,COORD_TOP);//绘制标准起始频率所在的垂直实线
note.Format(L"%4.2fM",stdStartFreq);
pDC->TextOutW((int)xStdStart-15,ORIGIN_Y+5,note);//坐标标注
doublexStdStop=xStdStart+stdRatio*totalLen;//标准终止频率所在的X坐标
pDC->MoveTo((int)xStdStop,ORIGIN_Y);
pDC->LineTo((int)xStdStop,COORD_TOP);//绘制标准终止频率所在的垂直实线
note.Format(L"%4.2fM",stdStopFreq);
pDC->TextOutW((int)xStdStop-15,ORIGIN_Y+5,note);//坐标标注
doublextmp=xStdStart;
for(inti=0;i<(int)(stdRatio*totalRatio);++i)//绘制标准起始频率和标准终止频率之间的垂直实线
...{
xtmp+=totalLen/totalRatio;
pDC->MoveTo((int)xtmp,ORIGIN_Y);
pDC->LineTo((int)xtmp,COORD_TOP);//绘制个关键频率所在的垂直实线
note.Format(L"%4.2fM",stdStartFreq*pow((double)10,i+1));
pDC->TextOutW((int)xtmp-15,ORIGIN_Y+5,note);//坐标标注
}
pDC->MoveTo(COORD_RIGHT,ORIGIN_Y);//终止频率X坐标为COORD_RIGHT
pDC->LineTo(COORD_RIGHT,COORD_TOP);
note.Format(L"%4.2fM",StopFreq);
pDC->TextOutW(COORD_RIGHT-15,ORIGIN_Y+5,note);//坐标标注
CPendotPen(PS_DOT,1,RGB(0,0,0));
CPen*pOldPen=pDC->SelectObject(&dotPen);
//绘制起始频率与标准起始频率之间的虚线
doubletmpFreqL=stdStartFreq-stdStartFreq/10;//低频率
doubletmpFreqH=stdStartFreq;//高频率
doubletmpRatio;
xtmp=xStdStart;
while((tmpFreqL-StartFreq)>0.000001)/**//////由于double型浮点数精度的问题,不得不采用这种方法进行判断/////
...{
tmpRatio=log10(tmpFreqH/tmpFreqL)/totalRatio;
xtmp-=tmpRatio*totalLen;
pDC->MoveTo((int)xtmp,ORIGIN_Y);
pDC->LineTo((int)xtmp,COORD_TOP);//绘制虚线
if(tmpRatio>=0.06)
...{
note.Format(L"%4.2fM",tmpFreqL);
pDC->TextOutW(xtmp-15,ORIGIN_Y+5,note);//坐标标注
}
//如果两个频率之间的间隔所占长度大于等于横坐标全长的10%,
//用灰色虚线画出中间频率线
if(tmpRatio>=0.10)
...{
CPengrayPen(PS_DOT,0.5,RGB(192,192,192));
CPen*pDotPen=pDC->SelectObject(&grayPen);//灰色画笔
doublegrayInc;
if(tmpRatio<0.15)
grayInc=(tmpFreqH-tmpFreqL)/2;//画1条灰色虚线
elseif(tmpRatio>=0.15&&tmpRatio<0.20)
grayInc=(tmpFreqH-tmpFreqL)/4;//画3条灰色虚线
elseif(tmpRatio>=0.20)
grayInc=(tmpFreqH-tmpFreqL)/6;//画5条灰色虚线
doublegrayFreqH=tmpFreqL+grayInc;
doublegrayFreqL=tmpFreqL;
doublegrayLen=tmpRatio*totalLen;
doublexgray=xtmp;
doublegrayRatio;
while(tmpFreqH-grayFreqH>0.000001)
...{
grayRatio=log10(grayFreqH/grayFreqL)/log10(tmpFreqH/tmpFreqL);
xgray+=grayRatio*grayLen;
pDC->MoveTo(xgray,ORIGIN_Y);
pDC->LineTo(xgray,COORD_TOP);//绘制灰色虚线
grayFreqH+=grayInc;
grayFreqL+=grayInc;
}
pDC->SelectObject(pDotPen);
}
tmpFreqH-=stdStartFreq/10;
tmpFreqL-=stdStartFreq/10;
}
//起始频率和第一条黑色虚线之间的灰色虚线
//如果两个频率之间的间隔所占长度大于等于横坐标全长的10%
//用灰色虚线画出全部中间频率线
tmpRatio=log10(tmpFreqH/StartFreq)/totalRatio;
if(tmpRatio>=0.10)
...{
CPengrayPen(PS_DOT,0.5,RGB(192,192,192));
CPen*pDotPen=pDC->SelectObject(&grayPen);//灰色画笔
doublegrayInc;
if(tmpRatio<0.15)
grayInc=(tmpFreqH-tmpFreqL)/2;//画1条灰色虚线
elseif(tmpRatio>=0.15&&tmpRatio<0.20)
grayInc=(tmpFreqH-tmpFreqL)/4;//画2条灰色虚线
elseif(tmpRatio>=0.20&&tmpRatio<0.25)
grayInc=(tmpFreqH-tmpFreqL)/6;//画5条灰色虚线
elseif(tmpRatio>=0.25&&tmpRatio<0.30)
grayInc=(tmpFreqH-tmpFreqL)/8;//画7条灰色虚线
elseif(tmpRatio>=0.30&&tmpRatio<0.4)
grayInc=(tmpFreqH-tmpFreqL)/9;//画8条灰色虚线
elseif(tmpRatio>=0.40)
grayInc=(tmpFreqH-tmpFreqL)/10;//画8条灰色虚线
doublegrayFreqH=tmpFreqH;
doublegrayFreqL=tmpFreqH-grayInc;
doublexgray=xtmp;
doublegrayRatio;
while(grayFreqL-StartFreq>0.000001)
...{
grayRatio=log10(grayFreqH/grayFreqL)/log10(tmpFreqH/StartFreq);
xgray-=(xtmp-ORIGIN_X)*grayRatio;
pDC->MoveTo(xgray,ORIGIN_Y);
pDC->LineTo(xgray,COORD_TOP);//绘制灰色虚线
grayFreqH-=grayInc;
grayFreqL-=grayInc;
}
pDC->SelectObject(pDotPen);
}
//绘制标准起始频率和标准终止频率之间的垂直虚线
tmp=xStdStart;
doubletmpFreq=stdStartFreq;
for(inti=0;i<(int)(stdRatio*totalRatio);++i)
...{
xtmp=tmp;//tmp代表关键频率所在的X坐标,xtmp代表将要绘制的虚线的X坐标
tmpFreqL=tmpFreq;
tmpFreqH=2*tmpFreq;
//由低频向高频绘制虚线
for(intj=0;j<8;++j)
...{
tmpRatio=log10(tmpFreqH/tmpFreqL)/totalRatio;
xtmp+=tmpRatio*totalLen;
pDC->MoveTo(xtmp,ORIGIN_Y);
pDC->LineTo(xtmp,COORD_TOP);//绘制虚线
if(tmpRatio>=0.06)
...{
note.Format(L"%4.2fM",tmpFreqH);
pDC->TextOutW(xtmp-15,ORIGIN_Y+5,note);//坐标标注
}
//如果两个频率之间的间隔所占长度大于等于横坐标全长的10%,
//用灰色虚线画出中间频率线
if(tmpRatio>=0.10)
...{
CPengrayPen(PS_DOT,0.5,RGB(192,192,192));
CPen*pDotPen=pDC->SelectObject(&grayPen);//灰色画笔
doublegrayInc;
if(tmpRatio<0.15)
grayInc=(tmpFreqH-tmpFreqL)/2;//画1条灰色虚线
elseif(tmpRatio>=0.15&&tmpRatio<0.20)
grayInc=(tmpFreqH-tmpFreqL)/4;//画3条灰色虚线
elseif(tmpRatio>=0.20)
grayInc=(tmpFreqH-tmpFreqL)/6;//画3条灰色虚线
doublegrayFreqH=tmpFreqL+grayInc;
doublegrayFreqL=tmpFreqL;
doublegrayLen=tmpRatio*totalLen;
doublexgray=xtmp-grayLen;
doublegrayRatio;
while(tmpFreqH-grayFreqH>0.00001)
...{
grayRatio=log10(grayFreqH/grayFreqL)/log10(tmpFreqH/tmpFreqL);
xgray+=grayRatio*grayLen;
pDC->MoveTo(xgray,ORIGIN_Y);
pDC->LineTo(xgray,COORD_TOP);//绘制灰色虚线
grayFreqH+=grayInc;
grayFreqL+=grayInc;
}
pDC->SelectObject(pDotPen);
}
tmpFreqL+=tmpFreq;
tmpFreqH+=tmpFreq;
}
tmpFreq*=10;//tmpFreq代表关键频率
tmp+=totalLen/totalRatio;
}
//绘制标准终止频率和终止频率之间的垂直虚线
xtmp=xStdStop;
tmpFreqL=stdStopFreq;
tmpFreqH=2*stdStopFreq;
while((StopFreq-tmpFreqH)>0.000001)
...{
tmpRatio=log10(tmpFreqH/tmpFreqL)/totalRatio;
xtmp+=tmpRatio*totalLen;
pDC->MoveTo(xtmp,ORIGIN_Y);
pDC->LineTo(xtmp,COORD_TOP);//绘制虚线
if(tmpRatio>=0.06)
...{
note.Format(L"%4.2fM",tmpFreqH);
pDC->TextOutW(xtmp-15,ORIGIN_Y+5,note);//坐标标注
}
//如果两个频率之间的间隔所占长度大于等于横坐标全长的10%
//用灰色虚线画出全部中间频率线
if(tmpRatio>=0.10)
...{
CPengrayPen(PS_DOT,0.5,RGB(192,192,192));
CPen*pDotPen=pDC->SelectObject(&grayPen);//灰色画笔
doublegrayInc;
if(tmpRatio<0.15)
grayInc=(tmpFreqH-tmpFreqL)/2;//画1条灰色虚线
elseif(tmpRatio>=0.15&&tmpRatio<0.20)
grayInc=(tmpFreqH-tmpFreqL)/4;//画3条灰色虚线
elseif(tmpRatio>=0.20)
grayInc=(tmpFreqH-tmpFreqL)/6;//画5条灰色虚线
doublegrayFreqH=tmpFreqL+grayInc;
doublegrayFreqL=tmpFreqL;
doublegrayLen=tmpRatio*totalLen;//要画灰色虚线频率之间的距离
doublexgray=xtmp-grayLen;
doublegrayRatio;
while(tmpFreqH-grayFreqH>0.000001)
...{
grayRatio=log10(grayFreqH/grayFreqL)/log10(tmpFreqH/tmpFreqL);
xgray+=grayRatio*grayLen;
pDC->MoveTo(xgray,ORIGIN_Y);
pDC->LineTo(xgray,COORD_TOP);//绘制灰色虚线
grayFreqH+=grayInc;
grayFreqL+=grayInc;
}
pDC->SelectObject(pDotPen);
}
tmpFreqL+=stdStopFreq;
tmpFreqH+=stdStopFreq;
}
//黑色虚线和终止频率之间的灰色虚线
//如果两个频率之间的间隔所占长度大于等于横坐标全长的10%
//用灰色虚线画出全部中间频率线
tmpRatio=log10(StopFreq/tmpFreqL)/totalRatio;
if(tmpRatio>=0.10)
...{
CPengrayPen(PS_DOT,0.5,RGB(192,192,192));
CPen*pDotPen=pDC->SelectObject(&grayPen);//灰色画笔
doublegrayInc;
if(tmpRatio<0.15)
grayInc=(tmpFreqH-tmpFreqL)/2;//画1条灰色虚线
elseif(tmpRatio>=0.15&&tmpRatio<0.20)
grayInc=(tmpFreqH-tmpFreqL)/4;//画2条灰色虚线
elseif(tmpRatio>=0.20&&tmpRatio<0.25)
grayInc=(tmpFreqH-tmpFreqL)/6;//画5条灰色虚线
elseif(tmpRatio>=0.25&&tmpRatio<0.30)
grayInc=(tmpFreqH-tmpFreqL)/8;//画7条灰色虚线
elseif(tmpRatio>=0.30&&tmpRatio<0.4)
grayInc=(tmpFreqH-tmpFreqL)/9;//画8条灰色虚线
elseif(tmpRatio>=0.40)
grayInc=(tmpFreqH-tmpFreqL)/10;//画9条灰色虚线
doublegrayFreqH=tmpFreqL+grayInc;
doublegrayFreqL=tmpFreqL;
doublexgray=xtmp;
doublegrayRatio;
while(StopFreq-grayFreqL>0.000001)
...{
grayRatio=log10(grayFreqH/grayFreqL)/log10(StopFreq/tmpFreqL);
xgray+=(COORD_RIGHT-xtmp)*grayRatio;
pDC->MoveTo(xgray,ORIGIN_Y);
pDC->LineTo(xgray,COORD_TOP);//绘制灰色虚线
grayFreqH+=grayInc;
grayFreqL+=grayInc;
}
pDC->SelectObject(pDotPen);
}
pDC->SelectObject(pOldPen);
}
else//起始频率和终止频率在同一数量级,如StartFreq=200,StopFreq=500
...{
pDC->MoveTo(COORD_RIGHT,ORIGIN_Y);
pDC->LineTo(COORD_RIGHT,COORD_TOP);//最右端边界线
note.Format(L"%4.2fM",StopFreq);
pDC->TextOutW(COORD_RIGHT-15,ORIGIN_Y+5,note);//坐标标注
CPendotPen(PS_DOT,1,RGB(0,0,0));
CPen*pOldPen=pDC->SelectObject(&dotPen);
doubleunitLen=totalLen/totalRatio;//标准频率之间应有的距离
doublexStdStop=ORIGIN_X-log10(StartFreq/stdStopFreq)*unitLen;//标准终止频率(此时在起始频率的左边)的X坐标
doublextmp=xStdStop;
doubletmpFreqH=2*stdStopFreq;
doubletmpFreqL=stdStopFreq;
doubletmpRatio;
//根据标准终止频率(此时在起始频率的左边)绘制标准虚线
while((StartFreq-tmpFreqH>0.000001))//找到第一根标准虚线的X坐标
...{
tmpRatio=log10(tmpFreqH/tmpFreqL);
xtmp+=tmpRatio*unitLen;
tmpFreqH+=stdStopFreq;
tmpFreqL+=stdStopFreq;
}
while(StopFreq-tmpFreqL>0.000001)
...{
tmpRatio=log10(tmpFreqH/tmpFreqL);
if(tmpFreqL>StartFreq)
...{
pDC->MoveTo(xtmp,ORIGIN_Y);
pDC->LineTo(xtmp,COORD_TOP);//绘制虚线
if(tmpRatio>=0.06)
...{
note.Format(L"%4.2fM",tmpFreqL);
pDC->TextOutW(xtmp-15,ORIGIN_Y+5,note);//坐标标注
}
}
//如果两个频率之间的间隔所占长度大于等于横坐标全长的10%
//用灰色虚线画出全部中间频率线
doublegrayTmpRatio=tmpRatio/log10(StopFreq/StartFreq);
if(grayTmpRatio>=0.10)
...{
CPengrayPen(PS_DOT,0.5,RGB(192,192,192));
CPen*pDotPen=pDC->SelectObject(&grayPen);//灰色画笔
doublegrayInc;
if(grayTmpRatio<0.15)
grayInc=(tmpFreqH-tmpFreqL)/2;//画1条灰色虚线
elseif(grayTmpRatio>=0.15&&grayTmpRatio<0.20)
grayInc=(tmpFreqH-tmpFreqL)/4;//画2条灰色虚线
elseif(grayTmpRatio>=0.20&&grayTmpRatio<0.25)
grayInc=(tmpFreqH-tmpFreqL)/6;//画5条灰色虚线
elseif(grayTmpRatio>=0.25&&grayTmpRatio<0.30)
grayInc=(tmpFreqH-tmpFreqL)/8;//画7条灰色虚线
elseif(grayTmpRatio>=0.30&&grayTmpRatio<0.35)
grayInc=(tmpFreqH-tmpFreqL)/9;//画8条灰色虚线
elseif(grayTmpRatio>=0.35)
grayInc=(tmpFreqH-tmpFreqL)/10;//画9条灰色虚线
doublegrayFreqH=tmpFreqL+grayInc;
doublegrayFreqL=tmpFreqL;
doublegrayLen=tmpRatio*unitLen;//要画的灰色虚线频率之间的距离
doublexgray=xtmp;
doublegrayRatio;
while((tmpFreqH-grayFreqH>0.000001)&&grayFreqH<StopFreq)
...{
grayRatio=log10(grayFreqH/grayFreqL)/log10(tmpFreqH/tmpFreqL);
xgray+=grayRatio*grayLen;
pDC->MoveTo(xgray,ORIGIN_Y);
pDC->LineTo(xgray,COORD_TOP);//绘制灰色虚线
grayFreqH+=grayInc;
grayFreqL+=grayInc;
}
pDC->SelectObject(pDotPen);
}
xtmp+=tmpRatio*unitLen;
tmpFreqH+=stdStopFreq;
tmpFreqL+=stdStopFreq;
}
pDC->SelectObject(pOldPen);
}
}
目标:绘制以任意频率为起点、任意频率为终点的对数坐标,并能对坐标进行任意缩放。
附录:
1 读者来信问道:
您好,我是在校的学生,看了您关于“利用VC绘制对数坐标系”http://blog.csdn.net/bonny95/archive/2008/02/21/2111368.aspx 的博文,于是自己写了一个在不同坐标系(直角坐标系和对数坐标系)上描点并选择一些点进行线性拟合的C++程序,结果发现我的点不能很好的在对数坐标坐标上显示出来。
因此我想问您关于实际点到对数坐标系上的页面坐标点转换的过程,您的想法是什么样的呢?
比如点(1998,200)落在1000-10000的标准频率段内,并且是在1000-2000之间,这其中的如何正确地把该点在对数坐标上绘制出来呢。如果您有时间能给我这个解答的话不胜感激。
【答】首先我觉得有必要明确一下直角坐标系和对数坐标系的区别:直角坐标系的X轴、Y轴全部为线性坐标轴,也即1、2、3、……10、……100,1和2,2和3,99和100之间的距离是相等的;而对数坐标系(确切而言是半对数坐标系)的X轴(横坐标)是对数坐标,是非线性的,而Y轴是线性变化的,X轴上1、10、100之间的距离是相等的,而1和2,2和3,99和100之间的距离是不等的。
对于对数坐标系的横坐标,两个点之间的相对位置与两个点代表的频率值的对数呈正比,即:如果屏幕上某个像素点X1在屏幕上的坐标(计算机屏幕上的坐标系为线性坐标系)为(x1,y),X2的坐标为(x2,y),X3的坐标为(x3,y),X1、X2、X3分别为对数坐标系横轴上的三点,对应的频率值分别为f1, f2, f3,则有:
屏幕上的像素点位置比例 (x2-x1)/(x2-x3) = [lg(f2)-lg(f1)]/[lg(f2)-lg(f3)] 对数坐标系的频率值取对数之后的比例
根据上述公式,设对数坐标横轴上频率1000对应的屏幕坐标为x1, 1998对应的屏幕坐标为x2, 10000对应的屏幕坐标为x3,带入上述公式就可以了。当然,对数坐标的原点对应的屏幕像素值你要自己设定。
因此,其实把测量仪器测得的直角坐标系的曲线(或像素点)转换成计算机屏幕上显示的对数坐标系的曲线(或像素点)的关键在于计算机屏幕直角坐标系和对数坐标系的转换:屏幕上对数坐标系在屏幕上显示的位置要你自己来设定(比如原点为(200,600),横轴(200~800,600),纵轴(200, 600~150)),你设定了这个坐标系的位置之后,就要进行对数坐标(横轴为频率值;也可以理解为频率值的对数,这样频率值的对数也是线性的)和直角坐标系(横轴为屏幕像素点的位置)的转换。
另外,对于纵轴,尽管都是线性坐标,但也要进行一些等比例变换,不然绘制出来的也有可能不对。
祝你好运!
分享到:
相关推荐
vc 绘制坐标系在用VC绘图的时候,需要自定义坐标系,即改变坐标的映射模式,在网上查找了很多相关的知识,也还是很糊涂,天极网上有一篇文章(有位Hier也转载了这篇文章,或者也许他就是作者),图文并貌,稍微详细...
VC2008 Opengl绘制三个坐标轴源码,按上下左右键可选择,帮助理解Open GL坐标。
使用C#开发的自动绘制坐标轴的工具,可以定义坐标轴中X,Y轴的长度,使用GDI+
vc6.0中在对话框中绘制直角坐标系,适合初学者,文档内含有源代码
利用VC实现了可随视点变化而不断旋转的三维房子
自己做的一个小控件 可以改变大小 和坐标颜色
VC画坐标轴源程序,文本格式,可直接复制使用
本文在参考《VC6绘制3D饼状图 - 完美版》(http://www.vckbase.com/document/viewdoc/?id=1820)一文的基础上将绘制饼状图的过程封装成一个独立的类以便调用,调用时只需给出指定矩形区域以及相关参数,即可画出所...
VC中坐标轴及曲线的实现 两种方法 希望对你有帮助
vc绘制图像和方格 AppWizard has created this selrect application for you. This application not only demonstrates the basics of using the Microsoft Foundation classes but is also a starting point for ...
本人花了好几天写的VC坐标系的建立,实现World 坐标系(逻辑)和设备坐标系的转换。里面有注释,希望对大家有所帮助。原理都在注释里面。
VC 绘制几何图形填充图形的例子,可绘制直线、椭圆、矩形,可以设置线宽和填充色,点击墨水瓶图标即可填充闭合的几何图形,一定是闭合的图形哦,不闭合是不能填充的。本源代码可让你了解VC 简单的图形绘制方面的技巧...
做毕业设计时在国外网站上找到的VC绘制Bezier曲线和B样条曲线的程序,非常实用,给自己的毕业设计带来很大的便利。
该资源里的代码是有关图像旋转的,中间用到了坐标系之间的转换以及双线性差值等方法
基于VC的大地坐标系转换程序设计,柳根,曾繁慧,随着空间定位技术的发展,坐标系转换问题在测绘工程中的应用越来越广泛。本文首先根据空间大地直角坐标系与大地坐标系的关系推导
VC 绘制矩形和椭圆形方法演示,是自动绘制的,选择菜单中的画椭圆和画矩形的命令,直接在下边绘制出图形,不是用鼠标适时绘制,不知对你是否有用,源代码开源,在VC6.0下可编译运行。
VC 利用OpenGL绘制NURBS曲线,程序将进行缓冲区交换,交换缓冲区,运行后将生成一个三维曲线图,模拟NURBS曲线效果,最终效果请参见示例图所示。
VC绘制bmp图设置背景透明,倾力奉献!!
自制的基于MFC、OpenGL平台的三维坐标图程序,在vc2008编译通过
计算机图形学实验课资料 原创的,里面点击TEST菜单里面选项就 可以清屏和绘制 不过工程移植会出一些问题 具体参见:http://aishuishou.spaces.live.com/?_c11_BlogPart_BlogPart=summary&_c=BlogPart 相关博客