测绘程序设计 图形程序设计 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();
}
}