图形程序设计--变形曲线绘制C++代码

一、程序内容

    为一变形监测点的 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

四、运行结果

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值