一、程序内容
为一变形监测点的 24 期位移监测结果(分别为 X,Y,H),编制程序绘制出该点的变形曲线图,每个方向一个位移序列图。
二、设计思路
1.新建变形监测类 CDefMonitor
私有数据成员:结构体指针,指针大小
成员函数:设置并返回观测期数、指定期数的观测值,返回观测结果X、Y、H的最大值及最小值。
2.新建绘图类 CGragh 绘制坐标框架
保护类数据成员:屏幕坐标的原点、刻度,实际坐标的刻度值。
坐标框架的绘制:
a.Y轴的屏幕刻度总长度的1/3,X轴的屏幕刻度为总长度的时期数分之一。
b.创建画笔,绘制X轴和Y轴并绘制平行于Y轴的三条水平线。
c.绘制时间刻度线并标明刻度值。
d.设置X,Y,H的苦读范围,并在水平线位置标明刻度值。
e.绘制图例文字及符号。
3.新建CGragh 类的公有派生类CDefMonitiorGragh,绘制变形曲线。
a.调用基类绘图函数绘制坐标框架。
b.将实际坐标转化为屏幕坐标。
c.通过for循环绘制一段段直线完成曲线的绘制。
4.给打开按钮创建事件处理函数,完成文件的读取、字符串的分割,并将数据保存在变形监测类的对象CDef中。
5.在CRS_120_ZQL_EX7View类的OnDraw()函数中调用CDefMonitiorGragh类的绘图函数,绘制变形曲线。
三、主要代码
//CDefMonitor.h:头文件(变形监测类)
#pragma once
struct Point3D //三维坐标结构体
{
double X;
double Y;
double Z;
};
class CDefMonitor
{
public:
CDefMonitor(void);
~CDefMonitor(void);
CDefMonitor(int n); //构造函数重载
private:
struct Point3D *point; //变形监测数据指针
int iPointCount; //数组的大小
public:
void SetCount(int n); //设置监测期数
void SetPoint(int n,struct Point3D p);//设置第n期的监测数据
int GetCount(); //返回期数
struct Point3D GetPoint(int n);//返回指定期数的观测值
//观测值的最大值及最小值
double GetMaxX();
double GetMaxY();
double GetMaxZ();
double GetMinX();
double GetMinY();
double GetMinZ();
};
//CDefMonitor.h:实现文件(变形监测类)
#include "StdAfx.h"
#include "CDefMonitor.h"
CDefMonitor::CDefMonitor(void)
{
iPointCount=0; //默认构造函数监测期数为
}
CDefMonitor::~CDefMonitor(void)
{
}
CDefMonitor::CDefMonitor(int n)
{
iPointCount=n;
point=new struct Point3D[iPointCount];
}
void CDefMonitor::SetCount(int n)
{
iPointCount=n;
point=new struct Point3D[iPointCount];
}
void CDefMonitor::SetPoint(int n,struct Point3D p)
{
point[n-1]=p;
}
int CDefMonitor::GetCount()
{
return iPointCount;
}
struct Point3D CDefMonitor::GetPoint(int n)
{
return point[n-1];
}
double CDefMonitor::GetMaxX()
{
double dMax=point[0].X;
for (int i=0;i<iPointCount;i++)
{
if(point[i].X>dMax)
dMax=point[i].X;
}
return dMax;
}
double CDefMonitor::GetMinX()
{
double dMin=point[0].X;
for (int i=0;i<iPointCount;i++)
{
if(point[i].X<dMin)
dMin=point[i].X;
}
return dMin;
}
double CDefMonitor::GetMaxY()
{
double dMax=point[0].Y;
for (int i=0;i<iPointCount;i++)
{
if(point[i].Y>dMax)
dMax=point[i].Y;
}
return dMax;
}
double CDefMonitor::GetMinY()
{
double dMin=point[0].Y;
for (int i=0;i<iPointCount;i++)
{
if(point[i].Y<dMin)
dMin=point[i].Y;
}
return dMin;
}
double CDefMonitor::GetMaxZ()
{
double dMax=point[0].Z;
for (int i=0;i<iPointCount;i++)
{
if(point[i].Z>dMax)
dMax=point[i].Z;
}
return dMax;
}
double CDefMonitor::GetMinZ()
{
double dMin=point[0].Z;
for (int i=0;i<iPointCount;i++)
{
if(point[i].Z<dMin)
dMin=point[i].Z;
}
return dMin;
}
//Gragh.h:头文件(绘图类)绘制坐标框架
#pragma once
#include "CDefMonitor.h"
class CGragh
{
public:
CGragh(void);
~CGragh(void);
double Round(double X,int m); //四舍五入函数
protected:
int dScaleX; //X坐标刻度
int dScaleY; //Y坐标刻度
int dOrgX; //坐标原点
int dOrgY;
int dEndX; //坐标终点
int dEndY;
double dMinX,dMaxX; //坐标刻度值的范围
double dMinY,dMaxY;
double dMinZ,dMaxZ;
public:
void DrawFrame(CDC* pDC,CRect& rect,CDefMonitor CDef);
//绘制框架
};
//Gragh.cpp:实现文件(绘图类)绘制坐标框架
#include "StdAfx.h"
#include "Gragh.h"
#include "math.h"
CGragh::CGragh(void)
{
}
CGragh::~CGragh(void)
{
}
double CGragh::Round(double X,int m)
{
X=X*pow(10.0,m);
double r=X-int(X);
if (r>0.5)
{
r=floor(r + 0.5);
}
else
{
r=ceil(r - 0.5);
}
return (int(X)+r)*pow(10.0,-m);
}
void CGragh::DrawFrame(CDC* pDC,CRect& rect,CDefMonitor CDef)
{
CPen pen(PS_SOLID,2,RGB(0,0,0)); //创建画笔
CPen* pOldPen=pDC->SelectObject(&pen);
//根据客户区的顶点设置坐标原点和终点
dOrgX=rect.left+int(0.2*rect.Width());
dOrgY=rect.bottom-int(0.2*rect.Height());
dEndX=rect.right-int(0.25*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);//纵轴
dScaleY=(dOrgY-dEndY)/3; //取Y轴总长度的/3为刻度
dScaleX=(dEndX-dOrgX)/CDef.GetCount();//取X轴的时期数分之一为刻度
//绘制三条水平线
for(int i=0;i<3;i++)
{
pDC->MoveTo(dOrgX,dEndY+i*dScaleY);
pDC->LineTo(dEndX,dEndY+i*dScaleY);
}
pDC->SelectObject(pOldPen);
pen.DeleteObject();
LOGFONT lf;
memset(&lf, 0, sizeof(LOGFONT));
lf.lfHeight = 16;
_tcsncpy_s(lf.lfFaceName, LF_FACESIZE, _T("宋体"), 4);
CFont font;//创建字体
font.CreateFontIndirect(&lf);
CFont* pOldFont=pDC->SelectObject(&font);
for(int i=1;i<=CDef.GetCount();i++)//绘制时间刻度线并标明刻度值
{
pDC->MoveTo(dOrgX+dScaleX*i,dOrgY);
pDC->LineTo(dOrgX+dScaleX*i,dOrgY-8);
CString str;
str.Format(_T("%1i"),i);
pDC->TextOut(dScaleX*i+dOrgX,dOrgY+10,str);
}
pDC->TextOut(dOrgX+dScaleX*12,dOrgY+40,_T("时间"));
pDC->TextOut(dOrgX+dScaleX*10,dEndY-40,_T("变形曲线示意图"));
pDC->TextOut(dOrgX+dScaleX*26,dEndY+130,_T("Z方向变形曲线"));//图例文字
pDC->TextOut(dOrgX+dScaleX*26,dEndY+100,_T("Y方向变形曲线"));
pDC->TextOut(dOrgX+dScaleX*26,dEndY+72,_T("X方向变形曲线"));
pDC->SelectObject(pOldFont);
font.DeleteObject();
//画图例符号
//蓝色为X方向
CPen BluePen(PS_SOLID,2,RGB(0,0,255));
CPen* pOldPen1=pDC->SelectObject(&BluePen);
pDC->MoveTo(dOrgX+dScaleX*26+125,dEndY+78);
pDC->LineTo(dOrgX+dScaleX*26+225,dEndY+78);
pDC->SelectObject(pOldPen1);
BluePen.DeleteObject();
//红色为Y方向
CPen RedPen(PS_SOLID,2,RGB(255,0,0));
CPen* pOldPen2=pDC->SelectObject(&RedPen);
pDC->MoveTo(dOrgX+dScaleX*26+125,dEndY+106);
pDC->LineTo(dOrgX+dScaleX*26+225,dEndY+106);
pDC->SelectObject(pOldPen2);
RedPen.DeleteObject();
//绿色为Z方向
CPen GreenPen(PS_SOLID,2,RGB(0,255,0));
CPen* pOldPen3=pDC->SelectObject(&GreenPen);
pDC->MoveTo(dOrgX+dScaleX*26+125,dEndY+136);
pDC->LineTo(dOrgX+dScaleX*26+225,dEndY+136);
pDC->SelectObject(pOldPen3);
GreenPen.DeleteObject();
//设置刻度的范围
dMaxX=Round(CDef.GetMaxX(),3)+0.002;
dMinX=Round(CDef.GetMinX(),3)-0.002;
double dx=(dMaxX-dMinX)/3;
dMaxY=Round(CDef.GetMaxY(),3)+0.002;
dMinY=Round(CDef.GetMinY(),3)-0.002;
double dy=(dMaxY-dMinY)/3;
dMaxZ=Round(CDef.GetMaxZ(),3)+0.002;
dMinZ=Round(CDef.GetMinZ(),3)-0.002;
double dz=(dMaxZ-dMinZ)/3;
//绘制坐标X,Y,H刻度
CFont fontA;//创建字体
fontA.CreateFontIndirect(&lf);
pDC->TextOut(dOrgX-40,dEndY-30,_T("X"));
pDC->TextOut(dOrgX-95,dEndY-30,_T("Y"));
pDC->TextOut(dOrgX-150,dEndY-30,_T("H"));
pDC->SelectObject(pOldFont);
CString str;
for(int i=0;i<4;i++)
{
str.Format(_T("%.3f"),dMaxX-dx*i);
pDC->TextOut(dOrgX-55,dEndY+i*dScaleY,str);
}
for(int i=0;i<=3;i++)
{
str.Format(_T("%.3f"),dMaxY-dy*i);
pDC->TextOut(dOrgX-115,dEndY+i*dScaleY,str);
}
for(int i=0;i<=3;i++)
{
str.Format(_T("%.3f"),dMaxZ-dz*i);
pDC->TextOut(dOrgX-160,dEndY+i*dScaleY,str);
}
pDC->SelectObject(pOldFont);
font.DeleteObject();
}
//CDefMonitiorGragh.h:头文件(绘图类)绘制变形曲线
#pragma once
#include "gragh.h"
class CDefMonitiorGragh :
public CGragh
{
public:
CDefMonitiorGragh(void);
~CDefMonitiorGragh(void);
public:
void Draw(CDC* pDC,CRect& rect,CDefMonitor CDef);
//绘制变形曲线示意图
};
//DefMonitiorGragh.cpp:实现文件(绘图类)绘制变形曲线
#include "StdAfx.h"
#include "DefMonitiorGragh.h"
CDefMonitiorGragh::CDefMonitiorGragh(void)
{
}
CDefMonitiorGragh::~CDefMonitiorGragh(void)
{
}
void CDefMonitiorGragh::Draw(CDC* pDC,CRect& rect,CDefMonitor CDef)
{
if(CDef.GetCount()==0) return;//如果没有观测数据则绘图部分不执行
DrawFrame(pDC,rect,CDef); //调用基类CGraph函数绘制坐标框架
//绘制X方向变形曲线
CPen BluePen(PS_SOLID,2,RGB(0,0,255)); //创建画笔
CPen* pOldPen=pDC->SelectObject(&BluePen);
POINT ptX[256];
for(int i=0;i<CDef.GetCount()+1;i++) //实际坐标转化为屏幕坐标
{
ptX[i].x=dOrgX+i*dScaleX;
ptX[i].y=dOrgY-(int)((CDef.GetPoint(i).X-dMinX)/(dMaxX-dMinX)*3*dScaleY);
}
for (int i=0;i<CDef.GetCount()-1;i++)
{
pDC->MoveTo(ptX[i+1].x,ptX[i+1].y);
pDC->LineTo(ptX[i+2].x,ptX[i+2].y);
}
pDC->SelectObject(pOldPen);
BluePen.DeleteObject(); //删除画笔资源
//绘制Y方向变形曲线
CPen RedPen(PS_SOLID,2,RGB(255,0,0)); //创建画笔
CPen* pOldPen1=pDC->SelectObject(&RedPen);
POINT ptY[256];
for(int i=0;i<CDef.GetCount()+1;i++) //实际坐标转化为屏幕坐标
{
ptY[i].x=dOrgX+i*dScaleX;
ptY[i].y=dOrgY-(int)((CDef.GetPoint(i).Y-dMinY)/(dMaxY-dMinY)*3*dScaleY);
}
for (int i=0;i<CDef.GetCount()-1;i++)
{
pDC->MoveTo(ptY[i+1].x,ptY[i+1].y);
pDC->LineTo(ptY[i+2].x,ptY[i+2].y);
}
pDC->SelectObject(pOldPen1);
RedPen.DeleteObject(); //删除画笔资源
//绘制Z方向变形曲线
CPen GreenPen(PS_SOLID,2,RGB(0,255,0));//创建画笔
CPen* pOldPen2=pDC->SelectObject(&GreenPen);
POINT ptZ[256];
for(int i=0;i<CDef.GetCount()+1;i++) //实际坐标转化为屏幕坐标
{
ptZ[i].x=dOrgX+i*dScaleX;
ptZ[i].y=dOrgY-(int)((CDef.GetPoint(i).Z-dMinZ)/(dMaxZ-dMinZ)*3*dScaleY);
}
for (int i=0;i<CDef.GetCount()-1;i++)
{
pDC->MoveTo(ptZ[i+1].x,ptZ[i+1].y);
pDC->LineTo(ptZ[i+2].x,ptZ[i+2].y);
}
pDC->SelectObject(pOldPen2);
GreenPen.DeleteObject(); //删除画笔资源
}
// RS_120_ZQL_EX7View.h : CRS_120_ZQL_EX7View 类的接口
#include "CDefMonitor.h"
class CRS_120_ZQL_EX7View : public CView
{
public:
afx_msg void OnFileOpen();
int SplitStringArray(CString str,char split,CStringArray &astr);
CDefMonitor CDef;
};
// RS_120_ZQL_EX7View.cpp : CRS_120_ZQL_EX7View 类的实现
void CRS_120_ZQL_EX7View::OnDraw(CDC* pDC)
{
CRS_120_ZQL_EX7Doc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
if (!pDoc)
return;
// TODO: 在此处为本机数据添加绘制代码
CRS_120_ZQL_EX7Doc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
if (!pDoc)
return;
// TODO: 在此处为本机数据添加绘制代码
CRect rect; //定义客户区
GetClientRect(&rect); //获得客户区大小
CDefMonitiorGragh CDefGragh;
CDefGragh.Draw(pDC,rect,CDef); //调用CDefMonitorGragh类的成员函数绘制曲线
}
// CRS_120_ZQL_EX7View 消息处理程序
int CRS_120_ZQL_EX7View::SplitStringArray(CString str,char split,CStringArray &astr)
{
int startIdx=0;
int idx=str.Find(split,startIdx);
astr.RemoveAll();
while(-1!=idx)
{
CString stmp=str.Mid(startIdx,idx-startIdx);
astr.Add(stmp);
startIdx=idx+1;
idx=str.Find(split,startIdx);
}
CString stmp=str.Right(str.GetLength()-startIdx);
if(!stmp.IsEmpty())
{
astr.Add(stmp);
}
return astr.GetSize();
}
void CRS_120_ZQL_EX7View::OnFileOpen()
{
// TODO: 在此添加命令处理程序代码
CFileDialog dlgFile(TRUE,_T("txt")); //创建打开文件对话框
if(dlgFile.DoModal()==IDCANCEL) return;//如果选择取消按钮,则退出
CString strFileName=dlgFile.GetPathName();//获取选择的文件的名
CStdioFile sf; //创建文件对象
//以读的形式打开文件,如果打开失败则返回
if(!sf.Open(strFileName, CFile::modeRead)) return;
CString strLine;
BOOL bEOF=sf.ReadString(strLine);//读取第一行
if(!bEOF) //如果读取失败,则说明数据格式有问题,退出
{
MessageBox(_T("数据有误,请检查数据文件!"));
return;
}
int iPointCount;//观测期数
iPointCount= _ttoi((strLine)); //把读取的第一行字符串转换为数值型
CDef.SetCount(iPointCount);
int i=0,n=0;
while(bEOF)//开始读取数据
{
bEOF=sf.ReadString(strLine);
CStringArray stmp;
n=SplitStringArray(strLine,'\t',stmp);
if(stmp.GetSize()==0) continue;//如果是空行则下面不执行
struct Point3D p;
p.X=_tstof(stmp[0]);
p.Y=_tstof(stmp[1]);
p.Z=_tstof(stmp[2]);
CDef.SetPoint(i+1,p);//设置观测点数据
i++;
}
sf.Close();//关闭文件
Invalidate(true);
}
三、测试数据
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
四、运行结果