测绘程序设计 图形程序设计 CSU

1. 实验内容和要求

下列数据为一个三角网络数据,编制程序绘制出该网络结构,要求绘制一个坐标轴和尺度。
实验数据格式结果示例:

结果示例

2. 实验设计思路

1、 界面设计思路:在“打开文件”按钮上添加映射函数“OnFileOpen”。
2、 绘制三角网类的设计思路:设计三角形顶点结构体,成员包括坐标X,Y,Z,设计三角形结构体,成员包括指向三个顶点的指针。类中私有成员包括顶点数,三角形个数,指向顶点结构体数组和三角形结构体数组的指针,坐标X和Y的最大值、最小值以及它们的差值。公有成员函数包括构造函数,析构函数,拷贝构造函数,确定绘图比例函数,从文件中读取数据的函数,画三角网的函数以及画坐标轴和比例尺的函数。
3、 OnDraw函数中添加的代码:获得客户区,确定绘图比例,画三角网的函数,画坐标轴和比例尺的函数。
4、 “OnFileOpen”函数中的代码:以文本框的形式打开文件,读取数据,重新执行OnDraw函数的“Invalidat(true)”。

3. 代码展示

3.1 OnDraw函数:

下面展示一些 内联代码片

void CCHtest8View::OnDraw(CDC* pDC)
{
	CCHtest8Doc* pDoc = GetDocument();
	ASSERT_VALID(pDoc);
	if (!pDoc)
		return;

	// TODO: 在此处为本机数据添加绘制代码
	CRect rect;
	GetClientRect(&rect);

	TND.SetdScale(rect);//确定绘图比例
	TND.DrawFrame(pDC, rect);//画坐标轴和比例尺
	TND.DrawTriNet(pDC, rect);//画三角网
}

3.2 OnOpenFile函数

void CCHtest8View::OnFileOpen()
{
	// TODO: 在此添加命令处理程序代码
	CStdioFile sf;
	OpenFile(sf);//打开文件
	TND.ReadData(sf);//读取数据
	sf.Close();
	Invalidate(true);
}

3.3 打开文件函数OpenFile函数

//以文件对话框的方式打开文件
void CCHtest8View::OpenFile(CStdioFile& sf)
{
	CFileDialog dlgFile(TRUE, _T("txt"), NULL,
		OFN_ALLOWMULTISELECT | OFN_EXPLORER,
		_T("(文本文件)|*.txt"));
	if (dlgFile.DoModal() == IDCANCEL) return;
	CString strFileName = dlgFile.GetPathName();
	setlocale(LC_ALL, "");
	if (!sf.Open(strFileName, CFile::modeRead)) return;
}

3.4 绘制三角网的类的函数

头文件

#pragma once

//定义三角形顶点结构体
//xyz
struct triPoint
{
	double dX;
	double dY;
	double dZ;
};

//定义三角形
struct Triangle
{
	triPoint* pA;
	triPoint* pB;
	triPoint* pC;
};


class TriNetDraw
{
private:
	int iPointCount;//顶点个数
	int iTriCount;//三角形个数
	triPoint* TriPoi;//动态存储三角形顶点
	Triangle* TriAng;//动态存储三角形
	double Xmin;
	double Ymin;
	double detX;
	double detY;
	double dScale;//绘图比例
public:
	TriNetDraw(void);//构造函数
	~TriNetDraw();//析构函数
	TriNetDraw(TriNetDraw& TriNetwork);//拷贝构造函数

	void SetdScale(double dScale_ = 1);//用户设置绘图比例
	void SetdScale(CRect& rect);//自适应窗口的绘图比例

	void ReadData(CStdioFile& sf);//读取数据
	triPoint LPtoCP(triPoint* TriPoi);//从逻辑坐标转换到客户区坐标
	void DrawTriNet(CDC* pDC, CRect& rect);//画三角网
	void DrawFrame(CDC* pDC, CRect& rect);//画坐标轴和比例尺

};

Cpp文件

#include "pch.h"
#include "TriNetDraw.h"

//构造函数
TriNetDraw::TriNetDraw(void)
{
	iPointCount = 0;
	iTriCount = 0;
	detX = 0;
	detY = 0;
	Xmin = 0;
	Ymin = 0;
	dScale = 0;
	TriPoi = NULL;
	TriAng = NULL;
}


//析构函数
TriNetDraw::~TriNetDraw()
{
	if (TriPoi != NULL)
	{
		delete[] TriPoi;
		TriPoi = NULL;
	}
	if (TriAng != NULL)
	{
		delete[] TriAng;
		TriAng = NULL;
	}
}


//拷贝构造函数
TriNetDraw::TriNetDraw(TriNetDraw& TriNetwork)
{
	iPointCount = TriNetwork.iPointCount;
	TriPoi = new triPoint[iPointCount];
	for (int i = 0; i < iPointCount; i++)
	{
		TriPoi[i] = TriNetwork.TriPoi[i];
	}
	iTriCount = TriNetwork.iTriCount;
	TriAng = new Triangle[iTriCount];
	for (int i = 0; i < iTriCount; i++)
	{
		TriAng[i] = TriNetwork.TriAng[i];
	}
	detX = TriNetwork.detX;
	detY = TriNetwork.detY;
	Xmin = TriNetwork.Xmin;
	Ymin = TriNetwork.Ymin;
	dScale = TriNetwork.dScale;
}

//用户设置绘图比例尺
void TriNetDraw::SetdScale(double dScale_)
{
	dScale = dScale_;
}

//自适应窗口的绘图比例尺
void TriNetDraw::SetdScale(CRect& rect)
{
	double ry = double(rect.Width()) * 2 / 3 / detY;//宽度扩大到2/3,方便在右边画坐标轴和比例尺
	double rx = double(rect.Height()) / detX;
	dScale = rx < ry ? rx : ry;
}


//读取数据
void TriNetDraw::ReadData(CStdioFile& sf)
{
	CString strLine;
	for (int i = 0; i < 6; i++)
	{
		sf.ReadString(strLine);
	}
	iPointCount = _ttoi(strLine);//读取顶点数
	sf.ReadString(strLine);
	iTriCount = _ttoi(strLine);//读取三角形个数

	TriPoi = new triPoint[iPointCount];
	TriAng = new Triangle[iTriCount];

	CStringArray arrTmp;
	
	//逐行读取顶点数据
	for (int i = 0; i < iPointCount; i++)
	{
		sf.ReadString(strLine);
		SplitStringArray(strLine, ' ', arrTmp);
		TriPoi[i].dX = _tstof(arrTmp[1]);
		TriPoi[i].dY = _tstof(arrTmp[2]);
		TriPoi[i].dZ = _tstof(arrTmp[3]);
	}

	//逐行读取三角形数据
	for (int i = 0; i < iTriCount; i++)
	{
		sf.ReadString(strLine);
		SplitStringArray(strLine, ' ', arrTmp);
		TriAng[i].pA = &TriPoi[_ttoi(arrTmp[1]) - 1];
		TriAng[i].pB = &TriPoi[_ttoi(arrTmp[2]) - 1];
		TriAng[i].pC = &TriPoi[_ttoi(arrTmp[3]) - 1];
	}

	double Xmax, Ymax;
	Xmin = Xmax = TriPoi[0].dX;
	Ymin = Ymax = TriPoi[0].dY;

	//得到X、Y的最大值和最小值
	for (int i = 1; i < iPointCount; i++)
	{
		Xmin = Xmin < TriPoi[i].dX ? Xmin : TriPoi[i].dX;
		Ymin = Ymin < TriPoi[i].dY ? Ymin : TriPoi[i].dY;
		Xmax = Xmax > TriPoi[i].dX ? Xmax : TriPoi[i].dX;
		Ymax = Ymax > TriPoi[i].dY ? Ymax : TriPoi[i].dY;
	}

	//得到X、Y的最大值和最小值之差
	detX = Xmax - Xmin;
	detY = Ymax - Ymin;
}


//从逻辑坐标转换到客户区坐标
triPoint TriNetDraw::LPtoCP(triPoint* TriPoi)
{
	triPoint P;
	P.dY = (detX + Xmin - TriPoi->dX) * dScale;
	P.dX = (TriPoi->dY - Ymin) * dScale;
	return P;
}

//画三角网
void TriNetDraw::DrawTriNet(CDC* pDC, CRect& rect)
{
	CPen pen(PS_SOLID, 1, RGB(255, 0, 0));
	CPen* pOldPen = pDC->SelectObject(&pen);
	for (int i = 0; i < iTriCount; i++)
	{
		triPoint pA;
		triPoint pB;
		triPoint pC;
		pA = LPtoCP(TriAng[i].pA);
		pB = LPtoCP(TriAng[i].pB);
		pC = LPtoCP(TriAng[i].pC);
		pDC->MoveTo(pA.dX, pA.dY);
		pDC->LineTo(pB.dX, pB.dY);
		pDC->LineTo(pC.dX, pC.dY);
		pDC->LineTo(pA.dX, pA.dY);
	}

	pDC->SelectObject(pOldPen);
	pen.DeleteObject();
}

//画坐标轴和比例尺
void TriNetDraw::DrawFrame(CDC* pDC, CRect& rect)
{
	if (iTriCount > 0)
	{
		double dLen = 30 * dScale;//30m长对应的长度

		//坐标轴的坐标原点
		double dOrgX = detY * dScale + dLen;
		double dOrgY = double(rect.Height()) / 2;


		CPen pen(PS_SOLID, 1, RGB(255, 0, 0));
		CPen* pOldPen = pDC->SelectObject(&pen);
		pDC->Rectangle(rect);
		pDC->MoveTo(dOrgX, dOrgY);
		pDC->LineTo(dOrgX + dLen, dOrgY);//Y轴
		pDC->MoveTo(dOrgX, dOrgY);
		pDC->LineTo(dOrgX, dOrgY - dLen);//X轴

		pDC->MoveTo(dOrgX + dLen - 10, dOrgY - 5);
		pDC->LineTo(dOrgX + dLen, dOrgY);
		pDC->MoveTo(dOrgX + dLen - 10, dOrgY + 5);
		pDC->LineTo(dOrgX + dLen, dOrgY);//Y轴箭头

		pDC->MoveTo(dOrgX - 5, dOrgY - dLen + 10);
		pDC->LineTo(dOrgX, dOrgY - dLen);
		pDC->MoveTo(dOrgX + 5, dOrgY - dLen + 10);
		pDC->LineTo(dOrgX, dOrgY - dLen);//X轴箭头


		//画比例尺
		pDC->MoveTo(dOrgX, dOrgY + 75);
		pDC->LineTo(dOrgX, dOrgY + 80);
		pDC->LineTo(dOrgX + dLen, dOrgY + 80);
		pDC->LineTo(dOrgX + dLen, dOrgY + 75);

		pDC->SelectObject(pOldPen);
		pen.DeleteObject();


		CFont font;//创建字体
		VERIFY(font.CreateFont(
			15,                        // nHeight
			0,                         // nWidth
			0,                         // nEscapement
			0,                         // nOrientation*
			FW_NORMAL,                 // nWeight
			FALSE,                     // bItalic
			FALSE,                     // bUnderline
			0,                         // cStrikeOut
			ANSI_CHARSET,              // nCharSet
			OUT_DEFAULT_PRECIS,        // nOutPrecision
			CLIP_DEFAULT_PRECIS,       // nClipPrecision
			DEFAULT_QUALITY,           // nQuality
			DEFAULT_PITCH | FF_SWISS,  // nPitchAndFamily
			_T("宋体")));                 // lpszFacename

		CFont* pOldFont = pDC->SelectObject(&font);
		pDC->TextOut(dOrgX + dLen - 10, dOrgY + 5, _T("Y"), 1);//标注Y
		pDC->TextOut(dOrgX - 15, dOrgY - dLen, _T("X"), 1);//标注X

		//标注比例尺
		pDC->TextOutW(dOrgX + dLen / 2 - 15, dOrgY + 85, _T("30 m"));
		

		pDC->SelectObject(pOldFont);
		font.DeleteObject();
	}
}

4. 结果展示

结果展示

  • 5
    点赞
  • 45
    收藏
    觉得还不错? 一键收藏
  • 10
    评论
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值