《测绘程序设计(VC.net)》
上机实验报告
(Visual C++.Net)
实验6 图形程序设计
班 级: 测 绘0803班
学 号: 0405080702
姓 名: 陈 琴 霞
序 号:
二零一零年四月
实验6 图形程序设计
一、实验目的
· 掌握VC++.net 坐标系和各项设置方法。
· 掌握GDI绘图方法。
· 理解交互式图形程序设计
二、实验内容
1.下列数据为一变形监测点的24期位移监测结果(分别为X,Y,H),编制程序绘制出该点的变形曲线图,每个方向一个位移序列图。
24
32.5801 -52.7876 0.1369
32.5786 -52.7892 0.1380
32.5784 -52.7845 0.1411
32.5812 -52.7852 0.1393
32.5782 -52.7863 0.1394
32.5791 -52.7852 0.1354
32.5788 -52.7841 0.1414
32.5788 -52.7817 0.1375
32.5745 -52.7833 0.1359
32.5815 -52.7854 0.1327
32.5822 -52.7841 0.1358
32.5839 -52.7826 0.1361
32.5820 -52.7852 0.1339
32.5800 -52.7863 0.1325
32.5792 -52.7845 0.1416
32.5807 -52.7834 0.1395
32.5778 -52.7846 0.1412
32.5792 -52.7843 0.1371
32.5794 -52.7833 0.1406
32.5806 -52.7841 0.1411
32.5800 -52.7863 0.1380
32.5785 -52.7840 0.1368
32.5811 -52.7848 0.1412
32.5828 -52.7863 0.1356
设计思路:
1) 自定义绘图的类,包括:逐行分割函数,数据读取函数,绘图的函数
2) 各函数的实现。
数据读取函数:打开观测数据,将三个方向的形变值,分别赋给X,Y,H三个动态数组。
绘图的函数:首先获得绘图区域,按比例绘制坐标网格,绘制坐标网格时,先确定四个顶点的坐标,剩下的就简单了。
我把三个方向的形变绘在了一个表格中,因此纵坐标有X,Y,H三种刻度,它们的形变曲线分别蓝、绿、红三种颜色表示。
主要代码:
文件一 DrawGraph.h
#pragma once
class DrawGraph
{
public:
DrawGraph(void);
~DrawGraph(void);
public:
CString *SplitString(CString str, char split, int& iSubStrs);
void ReadData(double *&X,double *&Y,double *&H);
void Draw(CDC* pDC, CRect& rect);
};
文件二 DrawGraph.cpp
#include "StdAfx.h"
#include "DrawGraph.h"
#include <locale.h>
DrawGraph::DrawGraph(void)
{
}
DrawGraph::~DrawGraph(void)
{
}
CString *DrawGraph::SplitString(CString str, char split, int& iSubStrs)
{
int iPos = 0; //分割符位置
int iNums = 0; //分割符的总数
CString strTemp = str;
CString strRight;
//先计算子字符串的数量
while (iPos != -1)
{
iPos = strTemp.Find(split);
if (iPos == -1)
{
break;
}
strRight = strTemp.Mid(iPos + 1, str.GetLength());
strTemp = strRight;
iNums++;
}
if (iNums == 0) //没有找到分割符
{
//子字符串数就是字符串本身
iSubStrs = 1;
return NULL;
}
//子字符串数组
iSubStrs = iNums + 1; //子串的数量= 分割符数量+ 1
CString* pStrSplit;
pStrSplit = new CString[iSubStrs];
strTemp = str;
CString strLeft;
for (int i = 0; i < iNums; i++)
{
iPos = strTemp.Find(split);
//左子串
strLeft = strTemp.Left(iPos);
//右子串
strRight = strTemp.Mid(iPos + 1, strTemp.GetLength());
strTemp = strRight;
pStrSplit[i] = strLeft;
}
pStrSplit[iNums] = strTemp;
return pStrSplit;
}
void DrawGraph::ReadData(double *&X,double *&Y,double *&H)
{
CFileDialog dlgFile(TRUE,_T("gmss.txt"),NULL,
OFN_ALLOWMULTISELECT|OFN_EXPLORER,
_T("(文本文件)|*.txt"));
if(dlgFile.DoModal()==IDCANCEL) return;
CString strFileName=dlgFile.GetPathName();
setlocale(LC_ALL,"");
CStdioFile sf;
if(!sf.Open(strFileName, CFile::modeRead)) return;
CString strLine;
CString strData;
strData.Empty();
BOOL bEOF=sf.ReadString(strLine);
while(bEOF)
{
strData+=strLine;
bEOF=sf.ReadString(strLine);
if(bEOF) strData+=_T("\r\n");
}
sf.Close();
int iLine;
//分行并存入字符串数组
CString *pstrLine=SplitString(strData,'\n',iLine);
if(iLine<2)
{
throw(_T("输入的数据不完整!"));
return;
}
int iTotalPoint = _ttoi(pstrLine[0]); //测量点数
CString *strTmp=NULL;
int n;
X=new double[iTotalPoint];
Y=new double[iTotalPoint];
H=new double[iTotalPoint];
//逐行用Split函数分离,获得三个方向的形变值
for(int i=0;i<iTotalPoint;i++)
{
strTmp = SplitString(pstrLine[i+1], ',',n);
X[i]=_tstof(strTmp[0]);
Y[i]=_tstof(strTmp[1]);
H[i]=_tstof(strTmp[2]);
if(strTmp!=NULL)//释放内存
{
delete[] strTmp;
strTmp=NULL;
}
}
if(strTmp!=NULL)//释放内存
{
delete[] strTmp;
strTmp=NULL;
}
}
void DrawGraph::Draw(CDC* pDC, CRect& rect)
{
CPen pen(PS_SOLID,2,RGB(0,0,0));
CPen* pOldPen=pDC->SelectObject(&pen);
pDC->Rectangle(rect);
int dOrgX,dOrgY;
int dEndX,dEndY;
dOrgX=rect.left+int(0.2*rect.Width());
dOrgY=rect.bottom-int(0.2*rect.Height());
dEndX=rect.right-int(0.1*rect.Width());
dEndY=rect.top+int(0.2*rect.Height());
pDC->MoveTo(dOrgX,dOrgY);
pDC->LineTo(dEndX,dOrgY);//横轴
pDC->MoveTo(dOrgX,dOrgY);
pDC->LineTo(dOrgX,dEndY);//纵轴
int dx,dy;
dy=(dOrgY-dEndY)/3;
dx=(dEndX-dOrgX)/24;
//绘制水平线
for(int i=0;i<3;i++)
{
pDC->MoveTo(dOrgX,dEndY+i*dy);
pDC->LineTo(dEndX,dEndY+i*dy);
}
pDC->SelectObject(pOldPen);
LOGFONT lf;
memset(&lf, 0, sizeof(LOGFONT));
// request a 16-pixel-height font
lf.lfHeight = 16;
// request a face name "Arial".
_tcsncpy_s(lf.lfFaceName, LF_FACESIZE, _T("宋体"), 4);
CFont font;//创建字体
font.CreateFontIndirect(&lf);
CFont* pOldFont=pDC->SelectObject(&font);
CString str;
//绘制时间刻度
for(int i=1;i<=24;i++)
{
pDC->MoveTo(dx*i+dOrgX,dOrgY);
pDC->LineTo(dx*i+dOrgX,dOrgY - 5);
str.Format(_T("%d"),i);
if(i!=0)
{
pDC->TextOut(dx*i+dOrgX,
dOrgY + 10,str);
}
}
pDC->TextOut(dOrgX+400,dOrgY+30,
_T("时间"));
pDC->TextOut(dOrgX+300,dEndY-50,
_T("蓝:X方向 绿:Y方向 红:H方向"));
pDC->SelectObject(pOldFont);
font.DeleteObject();
//绘制坐标X,Y,H刻度
CFont fontA;//创建坐标字体
fontA.CreateFontIndirect(&lf);
//CFont* pOldFont=pDC->SelectObject(&fontA);
pDC->TextOut(dOrgX-60,dEndY-30,
_T("X"),1);
pDC->TextOut(dOrgX-120,dEndY-30,
_T("Y"),1);
pDC->TextOut(dOrgX-180,dEndY-30,
_T("H"),1);
pDC->SelectObject(pOldFont);
for(int i=0;i<=3;i++)
{
str.Format(_T("%.3f"),32.585-0.005*i);
pDC->TextOut(dOrgX-60,dEndY+i*dy,
str);
}
for(int i=0;i<=3;i++)
{
str.Format(_T("%.3f"),-52.78-0.005*i);
pDC->TextOut(dOrgX-120,dEndY+i*dy,
str);
}
for(int i=0;i<=3;i++)
{
str.Format(_T("%.3f"),0.145-0.005*i);
pDC->TextOut(dOrgX-180,dEndY+i*dy,
str);
}
fontA.DeleteObject();
//调用数据读取函数,获得形变数据
double *X=NULL;
double *Y=NULL;
double *H=NULL;
ReadData(X,Y,H);
//创建蓝色画笔
CPen penBlue;
penBlue.CreatePen( PS_SOLID, 2, RGB(0,0,255));
pDC->SelectObject(penBlue);
POINT ptX[256]; //定义点结构体变量
for(int i=0;i<24;i++) //实际坐标与屏幕坐标的转化
{
ptX[i].x=dOrgX+i*dx;
ptX[i].y=dOrgY-int((X[i]-32.57)/0.015*3*dy);
}
pDC->Polyline(ptX,24); //绘制X方向变形曲线
// 恢复原来绘图属性
pDC->SelectObject(pOldPen);
penBlue.DeleteObject();
//创建绿色画笔绘制Y方向变形曲线
CPen penGreen;
penGreen.CreatePen( PS_SOLID, 2, RGB(0,255,0));
pDC->SelectObject(penGreen);
POINT ptY[256];
for(int i=0;i<24;i++)
{
ptY[i].x=dOrgX+i*dx;
ptY[i].y=dOrgY-int((Y[i]+52.795)/0.015*3*dy);
}
pDC->Polyline(ptY,24);
// 恢复原来绘图属性
pDC->SelectObject(pOldPen);
penGreen.DeleteObject();
//创建红色画笔绘制H方向变形曲线
CPen penRed;
penRed.CreatePen( PS_SOLID, 2, RGB(255,0,0));
pDC->SelectObject(penRed);
POINT ptH[256];
for(int i=0;i<24;i++)
{
ptH[i].x=dOrgX+i*dx;
ptH[i].y=dOrgY-int((H[i]-0.13)/0.015*3*dy);
}
pDC->Polyline(ptH,24);
// 恢复原来绘图属性
pDC->SelectObject(pOldPen);
penRed.DeleteObject();
}
文件三 TranGraphView.cpp
void CTranGraphView::OnDraw(CDC *pDC)
{
CTranGraphDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
if (!pDoc)
return;
// TODO: 在此处为本机数据添加绘制代码
CRect rect;
GetClientRect(&rect);
DrawGraph drawGraph;
drawGraph.Draw(pDC,rect);
}
运行结果:
总 结
这次实验是图形的绘制,比较麻烦,内容很多,既要打开文件读取数据,又要绘制坐标轴,坐标刻度,还要对坐标进行转化。虽然老师都给了我们相关的例题,但将它们完美地融合在一起却不简单。正所谓程序越复杂,实现的方法也就越多,遇到的问题也更加稀奇古怪了。如何更好的实现实验要求也得更加仔细思考了。
本实验需要绘制三个方向的型变量,如何去表示就是一个问题了,首先我是想在视图窗口中并列绘制三个坐标网格,但这样有很麻烦。后来一想干脆画在一个格网中,用三种不同颜色分开表示就好了,各形变之间还可对比。
这已经是第六个实验了,也学了编程的知识,虽然有的函数,代码我知道它是什么功能,我会用,但却不是很理解,将所学进行改编融合这方面我还是很欠缺的。
这个程序虽然是写完了,结果也运行出来了,但我知道它是写的很糟糕的,类只是函数的堆砌,完全算不上真正的类,运行也存在很大的问题。刚开始编译时还有好多错误,多编译几次竟然就通过了,但是通过之后有时是弹出两个或多个打开文件的对话框,有时是一个,往往还伴随着黑屏。我想应该是数据读取的函数调用有问题,具体是什么原因还不是很清楚,明天上午再去请教同学吧。
我害怕一调试就大片错误,因此写一点就调试一下,可这个程序貌似调试挺麻烦的,占用时间很长,而且不知道是怎么回事,一调试通过,电脑就会自动黑屏,几秒钟之后恢复,运行界面也跟着出来了,不知是不是电脑哪部分出故障了呢?
对各函数的功能还是多理解。