座標曲線的程式設計實現 (轉)

gugu99發表於2008-01-27
座標曲線的程式設計實現 (轉)[@more@]

座標曲線的實現

lipku@water.pku.edu.cn

由於統計圖的直觀顯示,在實際應用中經常會要畫各種統計圖。座標曲線圖是其中比較常用的一種。而座標曲線在各種統計圖中應該算比較難畫的,主要是很難將座標值與圖中的位置對應起來。我在做一個網站的專案中曾遇到過要畫座標曲線,由於沒有易用免費的可用,只好自己來實現。因此對畫座標曲線有了一點心得。

畫座標曲線的主要思路是:先找到座標值中x的最小值minX,最大值maxX。同樣取到y的最小值minY,最大值maxY。設圖形寬度為width,高度為height,於是對於座標(x,y)對應到圖上的位置是 :

((x-minX)*width/(maxX-minX),(y-minY)*height/(maxY-minY))

下面結合具體程式碼給以詳細解釋。這段程式碼基本適合畫各種座標曲線,既可以把原點畫在座標軸上,也可以不畫在座標軸上。為了方便大家執行,我全部改成了VC程式碼,只要在VC中新建一個project,把下面的程式碼複製到OnDraw()中即可實現。各位只要稍微修改一下,就可以在其他各種程式語言中實現。

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void CDrawCoorView::OnDraw(CDC* pDC)

{

  CDrawCoorDoc* pDoc = GetDocument();

  ASSERT_VALID(pDoc);

  // TODO: add draw code for native data here

 :namespace prefix = o ns = "urn:schemas--com::office" />

  //初始化座標值,一般從取得。這裡為了示例方便取得比較簡單

  const int num=10;

  float initX[num]={1,2,3,4,5,6,7,8,9,10};

  float initY[num]={0.5,2,2.8,4,5.6,6,7,9.4,13.8,23.4};

 

  //分別取得X和Y最大值,最小值

  float maxX=initX[0];

  float minX=initX[0];

  float maxY=initY[0];

  float minY=initY[0];

  for(int i=0;i

  {

    if(initX[i]>maxX)

    maxX=initX[i];

    if(initX[i]

    minX=initX[i];

    if(initY[i]>maxY)

    maxY=initY[i];

    if(initY[i]

    minY=initY[i];

  }

 

  //如果原點必須在X軸上,加上下面2行,否則註釋掉

  if(minX>0)

    minX=0;

 

  //如果原點必須在Y軸上,加上下面2行,否則註釋掉

  if(minY>0)

    minY=0;

 

 

  //確定圖象顯示大小

  int width=500;

  int height=300;

 

  //確定座標圖四周預留的空白大小

  const int mytop=10;

  const int mybottom=40;

  const int myleft=80;

  const int myright=50;

 

  //確定X,Y軸每單位顯示寬度

  float intervalX=(width-myleft-myright)/(maxX-minX);

  float intervalY=(height-mybottom-mytop)/(maxY-minY);

 

  //繪製曲線。由於繪圖座標的Y軸是向下延升,所以這裡每個點的Y值是用

  //圖象高度減去y值大小。

  pDC->MoveTo(int(myleft+(initX[0]-minX)*intervalX),

    int(height-(mybottom+(initY[0]-minY)*intervalY)));

  for(i=0;i

  {

    pDC->Lo(int(myleft+(initX[i]-minX)*intervalX),

    int(height-(mybottom+(initY[i]-minY)*intervalY)));

  }

 

  //繪製X,Y軸

  //X軸從圖形區域最左端到最右端

  float bottomY=0;

  float leftX=0;

  //bottomY表示X軸的y值,leftX表示Y軸的x值

  if(minY>0)

    bottomY=minY;

  if(minX>0)

    leftX=minX;

 

  pDC->MoveTo(int(myleft),int(height-(mybottom+(bottomY-minY)*intervalY)));

  pDC->LineTo(int(width-myright),int(height-(mybottom+(bottomY-minY)*intervalY)));

  //Y軸從圖形區域最底端到最頂端

  pDC->MoveTo(int(myleft+(leftX-minX)*intervalX),int(height-mybottom));

  pDC->LineTo(int(myleft+(leftX-minX)*intervalX),int(mytop));

 

  //確定顯示刻度個數

  const int count=5;

 

  //確定每個顯示刻度之間的寬度

  float spaceX=(width-myleft-myright)/count;

  float spaceY=(height-mybottom-mytop)/count;

 

  //繪製刻度和刻度值

  CString str;

  //X軸

  for(i=0;i<=count;i++)

  {

    str.Format("%.1f",minX+i*(maxX-minX)/count);

    pDC->MoveTo(int(myleft+spaceX*i),int(height-(mybottom+(bottomY-minY)*intervalY)));

    pDC->LineTo(int(myleft+spaceX*i),int(height-(mybottom+(bottomY-minY)*intervalY+5)));

    pDC->TextOut(int(myleft+spaceX*i-10),

    int(height-(mybottom+(bottomY-minY)*intervalY-5)),str);

  }

 

  //Y軸

  for(i=0;i<=count;i++)

  {

    str.Format("%.1f",minY+i*(maxY-minY)/count);

    pDC->MoveTo(int(myleft+(leftX-minX)*intervalX),int(height-(mybottom+spaceY*i)));

    pDC->LineTo(int(myleft+(leftX-minX*intervalX+5),int(height-(mybottom+spaceY*i)));

    pDC->TextOut(int(myleft+(leftX-minX)*intervalX-30),

    int(height-(mybottom+spaceY*i+8)),str);

  }

 

  //繪製X,Y軸的變數名

  pDC->TextOut(width/2,height-20,"時間(h)");

  pDC->TextOut(0,height/2,"產量(kg)");

 

}


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10748419/viewspace-998549/,如需轉載,請註明出處,否則將追究法律責任。

相關文章