GIS程序设计(七)实现基本矢量图形系统的文档和视图(3) 实现矢量图形系统的视图
GIS程序设计(七)实现基本矢量图形系统的文档和视图(3)
实现矢量图形系统的视图
本节将在上两节的基础之上,实现矢量图形系统的视图,完成矢量图形系统的图形元素绘制功能。
1、建立坐标系
在组织一幅图形时,采用哪一种映像方式组织矢量图形系统的坐标系值得进行研究。在本矢量图形系统中,可以建立一个坐标原点在左下角的坐标系,然后建立这个坐标系和Windows各个坐标系映像方式之间的转换关系。在此坐标系中,取左下角为原点,给定这个点的实际坐标为(m_xStart,m_yStart),并确定一个变量blc,作为逻辑坐标和实际坐标的比例关系。
为了实现实际坐标和逻辑坐标之间的转换,在视图类【CDrawView】中定义如下的两个转换函数:
public:
void DPtoVP(float x,float y,int *X,int *Y);
void VPtoDP(int x,int y,float *X,float *Y);
在实现文件中实现此两个函数
两个转换函数中用到的成员变量在视图类中定义:
float m_xStart,m_yStart,blc; //绘制图形时的起点坐标和比例尺
int m_hScreen,m_wScreen; //当前视图的高度和宽度
int m_MapMode; //映像模式
在视图类的构造函数中完成初始化:
m_xStart=0;
m_yStart=0;
blc=1.0;
m_MapMode=1; //映像模式初始化
成员变量m_hScreen,m_wScreen在消息处理函数OnSize中初始化,当窗口创建或窗口大小发生变化时,OnSize消息处理函数被调用。
为视图类添加消息处理函数OnSize();
//当视图的大小变化时被调用,cx,cy为变化后屏幕顶长、宽(像素)
为了在应用程序的其他类中能够使用这两个坐标函数,可以定义两个全局函数来实现转换操作功能。在实现文件【Drawdoc.cpp】中定义两个全局函数如下:
//全局函数,坐标转换,为了能在视图类中使用
void DPtoVP(float x,float y,int *X,int *Y);
void VPtoDP(int x,int y,float *X,float *Y);
还是在实现文件【Drawdoc.cpp】中加入这两个函数的实现代码:
void DPtoVP(float x,float y,int *X,int *Y)
{
p_View->DPtoVP(x,y,X,Y);
}
void VPtoDP(int x,int y,float *X,float *Y)
{
p_View->VPtoDP(x,y,X,Y);
}
以上两个全局函数利用视图类指针p_View调用视图类的两个坐标转换函数,来完成坐标的转换操作功能。如果要在某个实现文件中使用这两个全局函数,只需在这个实现文件的开始处加入全局函数的外部引用
extern void DPtoVP(float x,float y,int *X,int *Y);
extern void VPtoDP(int x,int y,float *X,float *Y);
在以上的两个全局函数中,p_View指向当前**的视图对象。p_View是一个在实现文件【Drawview.cpp】中全局定义的视图类指针:
CDrawView *p_View;
在视图类的重载虚函数【OnActiveView】中,对p_View指针进行初始化,以保证p_View指针时刻指向当前**的视图对象:
void CDrawView::OnActivateView(BOOL bActivate, CView* pActivateView, CView* pDeactiveView)
{
// TODO: Add your specialized code here and/or call the base class
p_View = this;
CView::OnActivateView(bActivate, pActivateView, pDeactiveView);
}
2、实现各图形元素类的绘制函数
利用虚函数来实现各种图形元素的绘制功能。在图形元素基类CDraw中,抽象定义一个进行绘制的虚函数。因为不需要用【CDraw】类直接来定义对象,所以可以将虚函数定义成纯虚函数。
virtual void Draw(CDC *pDC,int m_DrawMode,int m_DrawMode1,short BackColor)=0;
参数说明:
pDC:指向当前绘图对象的指针
m_DrawMode:绘制模式 1-R2_COPYPEN 2-R2_NOT
m_DrawMode1: 直线绘制方式。0-正常显示 1-特殊显示 2-用指定颜色绘制
在各种图形元素类中,重载虚函数。
virtual void Draw(CDC *pDC,int m_DrawMode,int m_DrawMode1,short BackColor);
3.1直线的绘制
在直线类的实现代码中,加入重载函数的实现代码:
3.2 连续直线和多边形区域的绘制
3.3 圆和填充圆的绘制
3.4 圆弧的绘制
3.5 标注文本的绘制
IMPLEMENT_SERIAL(CText,CObject,1)
void CText::Draw(CDC *pDC,int m_DrawMode,int m_DrawMode1,short BackColor)
{
if(b_Delete) //如果已经处于删除状态
return;
short ColorPen=m_ColorPen;
if(m_DrawMode1==2) //指定颜色绘制
ColorPen=BackColor;
CFont cjcf; //定义一个字模
int high,wide,cc1,cc2,cd,angg;
unsigned char c1,c2;
float x1,y1,ang1;
char bz[4];
const char *ls1;
if(m_DrawMode==0)
pDC->SetROP2(R2_COPYPEN);
else if(m_DrawMode==1)
pDC->SetROP2(R2_NOT);
pDC->SetBkMode(TRANSPARENT);
high=DLtoVL(m_TextHeight); //得到字体的点阵高度
ang1=(float)(m_Angle1*pi/180);
if(high<3||high>200)
return; //字体太小或太大将不显示
x1=m_StartX-m_TextHeight*(float)sin(ang1);
y1=m_StartY+m_TextHeight*(float)cos(ang1);
angg=(int)(m_Angle2*10);
wide=DLtoVL(m_TextWide);
//起始点的屏幕点阵坐标
DPtoVP(x1,y1,&cc1,&cc2);
//创建字模
cjcf.CreateFont(high,wide,angg,0,50,0,0,0,255,OUT_TT_PRECIS,CLIP_CHARACTER_PRECIS,DEFAULT_QUALITY,FIXED_PITCH,"cjc");
//选中字模
CFont* cjcbakf=pDC->SelectObject(&cjcf);
pDC->SetBkMode(TRANSPARENT); //设定显示方式
pDC->SetTextColor(p_GraphPara->GetColor(ColorPen)); //设定文本颜色
ls1=(const char *)c_Text; //文本内容
cd=strlen(ls1); //文本字符长度
while(cd>0) //绘出所有的字符
{
c1=*ls1;
c2=*(ls1+1);
if(c1>127&&c2>127) //如果是一个汉字
{
strncpy(bz,ls1,2);//拷贝一个汉字到bz中
bz[2]=0;
ls1=ls1+2; //跳过汉字指向下一个字符位置
pDC->TextOut(cc1,cc2,bz); //在屏幕上写这个汉字
cd=cd-2; //字符数减2
//下一个字符的显示位置
x1=x1+(m_TextWide*2+m_OffWide)*(float)cos(ang1);
y1=y1+(m_TextWide*2+m_OffWide)*(float)sin(ang1);
//下一个字符显示位置的屏幕坐标
DPtoVP(x1,y1,&cc1,&cc2);
}
else //如果是一个西文字符
{
strncpy(bz,ls1,1); //拷贝一个字符到bz中
bz[1]=0;
ls1++; //跳过这一个字符到下一个字符
pDC->TextOut(cc1,cc2,bz);//在屏幕上写字符
cd=cd-1; //字符数减1
//下一个字符的显示位置的实际坐标
x1=x1+(m_TextWide+m_OffWide/2)*(float)cos(ang1);
y1=y1+(m_TextWide+m_OffWide/2)*(float)sin(ang1);
//下一个字符显示位置的屏幕坐标
DPtoVP(x1,y1,&cc1,&cc2);
}
}
pDC->SelectObject(cjcbakf);//恢复字模
}
4、视图类的OnDraw函数。实现视图
为了实现应用程序的图形绘制工作,在文档类【CDrawDoc】中定义一个函数如下:
void Draw(CDC *pDC,int m_DrawMode,int m_DrawMode1,short BackColor);
在实现函数中加入这个函数的实现代码:
void CDrawDoc::Draw(CDC *pDC,int m_DrawMode,int m_DrawMode1,short BackColor)
{
for(int i=1; i<=5 ; i++)
{
int nn = GetGraphUpperBound(i)+1;
while(nn--)
GetGraph(i,nn)->Draw(pDC,m_DrawMode, m_DrawMode1, BackColor);
}
}
以上函数实现了对5中图形元素的绘制工作。对于每一类图形元素,绘制过程如下:
①调用GetGraphUpperBound()函数,得到存储这类图形元素对象指针的最大数组下标、
②对所有的图形元素循环,得到指向每一个图形元素对象的指针。然后通过这个指针调用图形元素类的Draw函数实现图形元素的绘制操作。
1、为了实现图形元素在视图中的绘制,对视图类的OnDraw函数进行修改,修改后的OnDraw函数实现代码如下:
void CDrawView::OnDraw(CDC* pDC)
{
CDrawDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
// TODO: add draw code for native data here
CBrush brush(p_GraphPara->GetColor(m_bColor)); //创建CBrush对象
CBrush* pOldBrush = pDC->SelectObject(&brush); //将画刷选入绘图对象
pDC->PatBlt(0,0,m_wScreen,m_hScreen,PATCOPY); //用画刷填充视图区域
pDC->SelectObject(pOldBrush); //恢复原来的画刷
pDoc->Draw(pDC,0,0,m_bColor);
}
在OnDraw函数中,调用了文档类的Draw函数来绘制所有的图形元素。
CBrush brush(p_GraphPara->GetColor(m_bColor)); 这个函数调用的文档类中CGraphPara类的成员函数,
所以需要在视图类的实现文件中添加外部引用。
参考资料:陈建春,Visual C++开发GIS系统--开发实例剖析。
地理信息科学
Writed By NX
QQ:1051926720