VC++6

2024-06-02

VC++6(精选9篇)

VC++6 篇1

0 引 言

随着计算机技术和现代通信技术的发展,人类已经步入以数字化和网络化为特征的知识经济时代。传统的通信模式如电话线路其成本高而且可视化的程度不如网络通信。随着网络的普及,网络通信的优势已经逐步显现,将成为未来人们通信的一种重要的方式[1]。

VC++6.0是一种面向对象的计算机程序设计语言,其界面友好,功能强大,可移植性好,广泛应用于各个行业,它既支持面向过程的程序设计,也支持面向对象的程序设计,适合大中小型的项目开发,因此本系统采用VC++6.0进行开发设计[2]。

利用VC++6.0的MFC设计网络通信,已经成为一种主流的设计方案,伴随着以太网的逐步发展,基于VC++6.0的网络通信可以有助于人们之间的信息交互,在未来的发展中将会得以进一步的成熟和完善。

1 软件系统总体设计流程

网络通信是人与人之间通过网络资源进行信息交流与传递。局域网中最常用的有3个网络协议:MICROSOFT的NETBEUI、NOVELL的IPX/SPX和交叉平台TCP/IP,由于只有TCP/IP允许与Internet完全地连接,所以本系统采用TCP/IP协议[3]。

在通信的过程中,位于局域网中的客户端可以与IP网络相连,通过VC++6.0内置的IP控件实现端与端之间的信息交互。网络整体架构如图1所示。

本系统包括即时通信模块和文件传输模块。采用基于对话框的MFC设计,基于事件触发的思想,界面设计包括基于VC的网络通信设计总界面、私聊界面和用户设置界面,其中总界面通过按键可以实现选择文件传送还是聊天功能,这些功能通过手动触发实现。系统总体设计流程如图2所示[4]。

2 系统设计思想

2.1 聊天功能设计思想

本系统设计的聊天功能主要是基于UDP协议的通信,采用Socket接口,所谓Socket通常也称作“套接字”,应用程序通常通过“套接字”向网络发出请求或者应答网络请求。Socket是建立网络连接时使用的,在连接成功时,应用程序两端都会产生一个Socket实例,操作这个实例,完成所需的会话,是TCP/IP网络的API[5]。

Socket有流式Socket(SOCK_STREAM)和数据报式Socket(SOCK_DGRAM)。流式Socket是一种面向连接的Socket,针对于面向连接的TCP服务应用;数据报式Socket是一种无连接的Socket,对应于无连接的UDP服务应用。在本系统中采用基于UDP的数据报式Socket。下面简要分析两者的优缺点[6]。

TCP协议基于三次握手机制,可以保证数据的安全性,顺序进行数据传输,但是TCP必须创建并且保持一个连接,这给系统增加了开销,而UDP协议尽最大可能进行保温传送,所以有效性远远不如UDP协议,因此一般的即时通信中都采用UDP协议,本系统采用了基于UDP协议设计聊天程序[7]。

聊天的创建程序如下:

wVersoinRequested = MAKEWORD(1,1);

m_socket=socket(AF_INET,SOCK_DGRAM,0); //创建一个UDP套接字

if(INVALID_SOCKET==m_socket)

{

MessageBox(″套接字创建失败!″);

return FALSE;

}

retval=bind(m_socket,(SOCKADDR*)&addrSock,sizeof(SOCKADDR)); //绑定

if(SOCKET_ERROR==retval)

{

closesocket(m_socket);

MessageBox(″绑定失败!″);

return FALSE;

}

2.2 文件传输功能设计思想

文件传输协议是一个用于不同的主机之间进行文件传送的协议标准,用来实现文件之间的共享、鼓励间接或者隐式地使用远程计算机、向用户屏蔽不同主机中各种文件存储系统的细节和进行可靠及高效地传输数据。在本系统的设计中采用TCP协议实现了文件的可靠传输与不同主机之间的资源共享[8]。

FTP有主动和被动两种模式。主动模式下有客户端和服务器端,并要求二者同时打开并监听端口,是一种面向连接的传输;被动模式下只要求服务器产生意见监听端口的进程,这样程序的运行就可以绕过防火墙。所以在本设计中采用了被动模式[9]。

文件传输的主程序设计如下:

IPselect=m_listIP.GetItemText(n,0); //获取选中的IP

CFileDialog fileDlg(TRUE); //文件对话框为打开

if(IDOK == fileDlg.DoModal()) //如果按确定按钮

{

CString filename=fileDlg.GetFileName();

CFile fileOpen;

if(!fileOpen.Open(fileDlg.GetPathName(),CFile::modeRead | CFile::typeBinary))

{

AfxMessageBox(″无法打开文件″, MB_OK | MB_ICONERROR);

return;

}

int len=fileOpen.GetLength();

char* data = new char[len];

fileOpen.Read(data,len); //读入文件内容

char *cc=new char[10000];

memset(cc,0,10000);

sprintf(cc,″%d%s%s%d%s%d%s%s%s″,strlen(IPselect),″文件″,IPselect,len,″@″,

filename.GetLength(),″@″,filename,data);

senddata(cc);

fileOpen.Close();

MessageBox(″文件发送完成!″);

}

3 各功能模块的设计

系统的界面分为总界面设计,私聊界面和用户设置界面三大部分,三部分分别执行相应的功能,下面逐步进行介绍。

3.1 总界面设计

该模块是整个系统的基础模块,它负责初始化整个应用程序,首先初始化套接字,并接收和发送各种消息信息,然后根据收到的信息进行判断该执行什么功能,进而建立应用进程。在该界面的设计当中为了使用户方便进行操作,建立了一个包含用户的IP地址和主机名的IP地址列表。在该界面的右侧是群聊窗口可以向所有的用户发送数据,并接收其他用户发来的消息。

为了方便用户操作,最右侧是一个该系统的介绍,最下面的几个按钮是方便用户进行功能选择所建立的,从而使该系统看起来比较直观。

3.2 用户设置界面设计

在该系统的通信过程中,如果靠记忆用户的IP地址来进行通信,容易使人烦躁,所以增加这个模块,来使该系统更加地人性化。在软件的使用中可以先进行通信获得其他用户的信息后,点击设置按钮来更改主机名,也可以修改自己的主机名。通过这两种方式可以让用户更加自主地设计主机名,并且方便用户识别自己的信息。

在该界面中包含自己的IP地址、所在的IP网段和主机名三部分,用户可以自主修改。修改后在主界面中就会显示用户信息了。

3.3 私聊界面设计

该模块可以和指定的用户进行聊天。可以通过选中IP列表中的用户信息单击进行私聊,但是用户不能和自己进行聊天,聊天的内容不会被其他用户看到。

在该程序设计中,应用了UDP协议,界面中安置了三个按钮:清空、发送、关闭,从而方便用户进行操作。该系统运行时,当一方退出程序,就会通知另一方,并把聊天记录存于指定的文本中,如果该文本已经存在,则把聊天记录插到该文本的后面,并保存该记录,方便用户日后进行查看。

3.4 刷新模块设计

该模块可以手动进行刷新用户信息,可以解决网络不同步带来的IP地址列表不能及时更新的问题,单击刷新按钮,系统会清空自己的IP地址列表,并向局域网发送自己的IP主机名和地址信息,其他用户收到后会恢复自己的IP地址和主机名,然后系统会更新自己的IP列表,从而达到网络的同步功能[10]。

3.5 发送文件模块设计

该模块可以向指定的用户发送文本文件。用户可以选中IP列表中的用户,单击发送文件按钮,把要发送的文本文件发送给指定的用户,对方接收后,会提示进行保存处理。

4 系统功能测试

私聊界面可以通过点击私聊开启,当编写完要发送的数据时点击发送即可,点击关闭按钮会弹出提示框,询问用户是否要退出该进程,如图3所示。

文件传送功能的使用,首先选择完用户后,单击文件传送,会弹出如图4所示的界面要求用户选择要传送的文件,在接收端,则要求用户选择存放的位置。

颜色的设定,由于不同的人有不同的喜好,所以增加该模块来方便用户设置背景颜色,如图5所示。

5 结 语

本文给出了一种基于UDP和FTP协议的网络通信设计方案,实现了基于UDP的即时通信和基于FTP协议的文件传输。本设计最大的优点是操作直观,可靠性高,文件传送中几乎不会发生数据的丢失。其主要缺点是没能实现视频的通信,其功能还不够全面,但是在一些小型的局域网中,由于其占用内存少且无需安装,因而有广泛的实际应用价值。

参考文献

[1]马丹.即时通信系统终端的设计与实现[D].成都:电子科技大学,2004.

[2]熊华胜,边信黔.VC++6.0环境下实现基于UDP协议的异步广播通信[J].应用科技,2004,31(2):44-46.

[3]中国教育和科研计算机网.网络协议TCP/IP、IPX/SPX、NETBEUI简介[EB/OL].[1994-01-11].http://www.edu.cn/20010830/210056.shtml.

[4]胡春安,胡中栋.MFC中对话框的创建和应用[J].电脑开发与应用,2005(9):58-59.

[5]杨阳,唐波.远程控制软件编程之多用户显示[J].黑客防线,2009(1):110-112.

[6]陈海蕊,郝世选.VC中基于Socket的局域网监控软件[J].濮阳职业技术学院学报,2009,22(6):136-138.

[7]宋玥玥,吴刚,杜刚.基于UDP协议的数据传输[J].中国电子商情:通信市场,2010(2):176-179.

[8]张喻平.基于互联网的视频远程回放技术的研究[D].武汉:武汉工业学院,2007.

[9]张承钊.互联网转换网关中FTP-ALG的设计与实现[D].成都:电子科技大学,2006.

[10]陈小兵.IP编址原则[J].网管员世界,2005(7):107.

VC++6 篇2

湖南大学(长沙410082) 于小亿 王 辉 张志学

摘 要 详细介绍了在Windows环境下应用VC++实现PC机与单片机的几种串行通信方法,给出了用Visual C++6.0编写的PC机程序和用C51编写的单片机通信程序。经实际应用系统运行稳定可靠。

关键词 Visual C++ 类 串行通信

工业控制领域(如DCS系统),经常涉及到串行通信问题。为了实现微机和单片机之间的数据交换,人们用各种不同方法实现串行通信,如DOS下采用汇编语言或C语言,但在Windows 环境下却存在一些困难和不足。在Windows操作系统已经占据统治地位的情况下(何况有些系统根本不支持DOS如Windows2000)开发Windows 环境下串行通信技术就显得日益重要。

VC++6.0是微软公司于1998年推出的一种开发环境,以其强大的功能,友好的界面,32位面向对象的程序设计及Active X的灵活性而受广大软件开发者的青睐,被广泛应用于各个领域。应用VC++开发串行通信目前通常有如下几种方法:一是利用Windows API通信函数;二是利用VC的标准通信函数_inp、_inpw、_inpd、_outp、_outpw、_outpd等直接对串口进行操作;三是使用Microsoft Visual C++的通信控件(MSComm);四是利用第三方编写的通信类。以上几种方法中第一种使用面较广,但由于比较复杂,专业化程度较高,使用较困难;第二种需要了解硬件电路结构原理;第三种方法看来较简单,只需要对串口进行简单配置,但是由于使用令人费解的VARIANT类,使用也不是很容易;第四种方法是利用一种用于串行通信的CSerial类(这种类是由第三方提供),只要理解这种类的几个成员函数,就能方便的使用。笔者利用CSerial类很方便地实现了在固定式EBM气溶胶灭火系统分区启动器(单片机系统)与上位机的通信。以下将结合实例,给出实现串行通信的几种方法。

1 Windows API通信函数方法

与通信有关的Windows API函数共有26个,但主要有关的有:

CreateFile() 用 “comn”(n为串口号)作为文件名就可以打开串口。

ReadFile() 读串口。

WriteFile() 写串口。

CloseHandle() 关闭串口句柄。初始化时应注意CreateFile()函数中串口共享方式应设为0,串口为不可共享设备,其它与一般文件读写类似。以下给出API实现的源代码。

1.1 发送的例程

//声明全局变量

HANDLE m_hIDComDev;

OVERLAPPED m_OverlappedRead, m_Over lappedWrite;

//初始化串口

void CSerialAPIView::OnInitialUpdate()

{

CView::OnInitialUpdate();

Char szComParams[50];

DCB dcb;

Memset(&m_OverlappedRead, 0, sizeof (OVERLAPPED));

Memset(&m_OverlappedWrite, 0, sizeof (OVERLAPPED));

m_hIDComDev = NULL;

m_hIDComDev = CreateFile(“COM2”, GENERIC_READ│GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL│FILE_FLAG_OVERLAPPED, NULL);

if (m_hIDComDev == NULL)

{

AfxMessageBox(“Can not open serial port!”);

goto endd;

}

memset(&m_OverlappedRead, 0, sizeof (OVERLAPPED));

memset(&m_OverlappedWrite, 0, sizeof (OVERLAPPED));

COMMTIMEOUTS CommTimeOuts;

CommTimeOuts. ReadIntervalTimeout=0×FFFFFFFF;

CommTimeOuts. ReadTotalTimeoutMultiplier = 0;

CommTimeOuts. ReadTotalTimeoutConstant= 0;

CommTimeOuts. WriteTotalTimeoutMultiplier = 0;

CommTimeOuts. WriteTotalTimeoutConstant = 5000;

SetCommTimeouts(m_hIDComDev, &CommTimeOuts);

Wsprintf(szComparams, “COM2:9600, n, 8, 1”);

m_OverlappedRead. hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);

m_OverlappedWrite. hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);

dcb. DCBlength = sizeof(DCB);

GetCommState(m_hIDComDev, &dcb);

dcb. BaudRate = 9600;

dcb. ByteSize= 8;

unsigned char ucSet;

ucSet = (unsigned char) ((FC_RTSCTS&FC_DTRDSR) != 0);

ucSet = (unsigned char) ((FC_RTSCTS&FC_RTSCTS) ! = 0);

ucSet = (unsigned char) ((FC_RTSCTS&FC_XONXOFF) ! = 0);

if (!SetCommState(m_hIDComDev, &dcb)‖

!SetupComm(m_hIDComDev,10000,10000)‖

m_OverlappedRead. hEvent ==NULL‖

m_OverlappedWrite. hEvent ==NULL)

{

DWORD dwError = GetLastError();

if (m_OverlappedRead. hEvent != NULL) CloseHandle(m_OverlappedRead. hEvent);

if (m_OverlappedWrite. hEvent != NULL) CloseHandle(m_OverlappedWrite. hEvent);

CloseHandle(m_hIDComDev);

}

endd:

;

}

//发送数据

void CSerialAPIView::OnSend()

{

char szMessage[20] = “thank you very much”;

DWORD dwBytesWritten;

for (int i=0; i

{

WriteFile(m_hIDComDev, (LPSTR)&szMessage[i], 1, &dwBytesWritten, &m_OverlappedWrite);

if (WaitForSingleObject(m_OverlapperWrite, hEvent, 1000))dwBytesWritten = 0;

else{

GentOverlappedResult(m_hIDComDev, &m_OverlappedWrite, &dwBytesWritten, FALSE);

m_OverlappedWrite. Offset += dwBytesWritten;

}

dwBytesWritten++;

}

}

1.2 接收例程

DCB ComDcb; //设备控制块

HANDLE hCom; //global handle

hCom = CreateFile (“COM1”,GENERIC_READ| GENERIC_WRITE,0,

NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);

if (hCom==INVALID_HANDLE_VALUE)

{

AfxMessageBox(“无法打开串行口”);

}

else

{

COMMTIMEOUTS CommTimeOuts ;

SetCommMask(hCom, EV_RXCHAR ) ;

SetupComm(hCom, 4096, 4096 ) ; /*设置收发缓冲区 尺寸为4K */

PurgeComm(hCom, PURGE_TXABORT| PURGE_RXABORT |

PURGE_TXCLEAR| PURGE_RXCLEAR ) ; //清收发缓冲区

//以下初始化结构变量CommTimeOuts, 设置超时参数 CommTimeOuts.ReadIntervalTimeout = 0×FFFFFFFF ;

CommTimeOuts.ReadTotalTimeoutMultiplier = 0 ;

CommTimeOuts.ReadTotalTimeoutConstant = 4000 ;

CommTimeOuts.WriteTotalTimeoutMultiplier = 0;

CommTimeOuts.WriteTotalTimeoutConstant = 4000 ;

SetCommTimeouts(hCom, &CommTimeOuts ); //设置超时参数

ComDcb.DCBlength = sizeof( DCB ) ;

GetCommState( hCom, &ComDcb ) ; //获取当前参数

ComDcb.BaudRate =9600; //波特率

ComDcb.ByteSize = 8; //数据位

ComDcb.Parity = 0; /*校验 0~4=no, odd, even, mark, space */

SetCommState(hCom, &ComDcb ) ;

} //设置新的通信参数

接收可用定时器或线程等

DWORD dRead,dReadNum;

unsigned char buff [200];

dRead=ReadFile(hCom, buff, 100, &dReadNum, NULL); //接收100个字符,

//dReadNum为实际接收字节数

2 利用端口函数直接操作

这种方式主要是采用两个端口函数_inp(), _outp()实现对串口的读写,其中读端口函数的原型为:

int _inp(unsigned shot port)

该函数从端口读取一个字节,端口号为0~65535。

写端口的函数原型为:

int _outp(unsigned shot port, int databyte)

该函数向指定端口写入一个字节。

不同的计算机串口地址可能不一样,通过向串口的控制及收发寄存器进行读写,可以实现灵活的串口通信功能,由于涉及具体的硬件电路讨论比较复杂,在此不加赘述,

3 MSComm控件

MSComm控件是微软开发的专用通信控件,封装了串口的所有功能,使用很方便,但在实际应用中要小心对其属性进行配置。下面详细说明该类应用方法。

3.1 MSComm控件的属性

CommPort:设置串口号,类型 short :1-comm1 2-comm2.

Settings:设置串口通信参数,类型 CString :B波特率,P奇偶性(N无校验,E偶校验,O奇校验),D字节有效位数,S停止位。

PortOpen:设置或返回串口状态,类型 BOOL:TURE打开,FALSE关闭。

InputMode:设置从接收缓冲区读取数据的格式,类型 long: 0-Text 1-Bin。

Input:从接收缓冲区读取数据,类型 VARIANT。

InBufferCount:接收缓冲区中的字节数,类型:short。

InBufferSize:接收缓冲区的大小,类型:short。

Output:向发送缓冲区写入数据,类型:VARIANT。

OutBufferCount:发送缓冲区中的字节数,类型:short。

OutBufferSize:发送缓冲区的大小,类型:short。

InputLen:设置或返回Input读出的字节数,类型:short。

CommEvent:串口事件,类型:short。

3.2 程序示例

串口初始化

if (!m_comm.GetPortOpen())

m_comm.SetPortOpen(TURE); /*打开串口*/

m_comm.SetSettings(“4800,n,8,1”); /*串口参数设置*/

m_comm.SetInputMode(0); /*设置TEXT缓冲区输入方式*/

m_comm.SetRthresHold(1); /*每接收一个字符则激发OnComm()事件*/

接收数据

m_comm.SetInputLen(1); /*每次读取一个字符

VARINAT V1=m_comm.GetInput();

/*读入字符*/

m_V1=V1.bstrval;

发送字符 m_comm.SetOutput(Colevariant (“Hello”); /*发送 “Hello” */

3.3 注意

SetOutput方法可以传输文本数据或二进制数据。用SetOutput方法传输文本数据,必须定义一个包含一个字符串的 Variant。发送二进制数据,必须传递一个包含字节数组的Variant 到 Output 属性。正常情况下,如果发送一个 ANSI 字符串到应用程序,可以以文本数据的形式发送。如果发送包含嵌入控制字符、Null 字符等的数据,要以二进制形式发送。此处望引起读者注意,笔者曾经在此犯错。

4 VC++类CSerial

4.1 串行通信类CSerial简介

Cserial 是由MuMega Technologies公司提供的一个免费的VC++类,可方便地实现串行通信。以下为该类定义的说明部分。

class CSerial

{

public:

CSerial();

~CSerial();

BOOL Open( int nPort = 2, int nBaud = 9600 );

BOOL Close( void );

int ReadData( void *, int );

int SendData( const char *, int );

int ReadDataWaiting( void );

BOOL IsOpened( void ){ return( m_bOpened ); }

protected:

BOOL WriteCommByte( unsigned char );

HANDLE m_hIDComDev;

OVERLAPPED m_OverlappedRead, m_OverlappedWrite;

BOOL m_bOpened;

}

4.2 串行通信类Cserial 成员函数简介

1. CSerial::Cserial是类构造函数,不带参数,负责初始化所有类成员变量。

2. CSerial:: Open这个成员函数打开通信端口。带两个参数,第一个是埠号,有效值是1到4,第二个参数是波特率,返回一个布尔量。

3. CSerial:: Close函数关闭通信端口。类析构函数调用这个函数,所以可不用显式调用这个函数。

4. CSerial:: SendData函数把数据从一个缓冲区写到串行端口。它所带的第一个参数是缓冲区指针,其中包含要被发送的资料;这个函数返回已写到端口的实际字节数。

5. CSerial:: ReadDataWaiting函数返回等待在通信端口缓冲区中的数据,不带参数。

6. CSerial:: ReadData函数从端口接收缓冲区读入数据。第一个参数是void*缓冲区指针,资料将被放入该缓冲区;第二个参数是个整数值,给出缓冲区的大小。

4.3 应用VC类的一个实例

1. 固定式EBM气溶胶灭火系统简介

固定式EBM气溶胶灭火装置分区启动器是专为EBM灭火装置设计的自动控制设备。可与两线制感温、感烟探测器配套使用,当监测部位发生火情时,探测器发出电信号给分区启动器,经逻辑判断后发出声、光报警,延时后自动启动EBM灭火装置。为了便于火灾事故的事后分析,需对重要的火警事件和关键性操作进行记录,记录应能从PC机读出来;PC机能控制、协调整个系统的工作,这些都涉及通信。本例中启动器采用RS-485通信接口,系统为主从式网络,PC机为上位机。具体的通信协议为:(1)下位机定时向上传送记录的事件;(2)应答发送,即PC机要得到最新事件记录,而传送时间未到时,PC机发送命令,下位机接收命令后,把最新记录传给上位机;(3)上位机发送其它命令如校时、启动、停止、手/自动等。

2. 通信程序设计

部分上位机程序

(1)发送命令字程序,代码如下

voidCCommDlg::OnSend()

{

CSerial Serial;

//构造串口类,初始化串行口

if (Serial.Open(2,9600)) //if-1

//打开串行口2,波特率为9600bps

{

static char szMessage[]=“0”;

//命令码(可定义各种命令码)

int nBytesSent;

int count=0;

resend:

nBytesSent=Serial.SendData(szMessage,strlen(szMessage));

//发送命令码

char rdMessage [20];

if (Serial.ReadDataWaiting()) //if-2

{

Serial.ReadData(rdMessage,88);

//rdMessage 定义接收字节存储区,为全局变量//

if ((rdMessage[0]!=0x7f)&&(count<3))

{

count++;

goto resend

}

if(count>=3)

MessageBox(“发送命令字失败”);

}

else //if-2

MessageBox(“接收数据错误”);

}

else //if-1

MessageBox(“串行口打开失败”);

}

下位机通信程序:

#include

#include

#include

#define count 9

#define com_code 0x00

#define com_code1 0xff

unsigned char buffer[count];

int po,year,month,date,hour;

int minute,second,recordID ;

int sum;

main()

{

/*初始化串口和定时器*/

TMOD=0×20;

TH1=0×fd;

TR1=0×01;

ET1=0×00;

ES=1;

EA=1;

/*待发送数据送缓冲区*/

buffer[0]=0×ff; //数据特征码

buffer[1]=count+1; //数据长度

buffer[2]=year; //年

buffer[3]=month; //月

buffer[4]=date; //日

buffer[5]=hour; //时

buffer[6]=minute; //分

buffer[7]=second; //秒

buffer[8]=recordID; //事件号

for(po=0;po

sum+=buffer[po];

buffer[9]=sum; //校验和

}

/*发送中断服务程序*/

void send(void) interrupt 4 using 1

{

int i;

RI=0;

EA=0;

do

{

for(i=0;i<=count;i++)

{

SBUF=buffer[i]; //发送数据和校验和//

while(TI==0);

TI=0;

}

while(RI==0);

RI=0;

}while(SBUF!=0); //主机接收不正确,重新发送//

EA=1;

Return;

}

5 应用总结

根据不同需要,选择合适的方法。我们选用的用VC++类实现的上位机和下位机的串行通信方法具有使用简单、编写程序方便的特点。经过半年多应用于EBM灭火系统的情况来看,该方法实现的系统运行稳定可靠,是一种值得推广的简单易行的通信方法。

参 考 文 献

1 Kate Gregory Visual C++6开发使用手册.北京:机械工业出版社,1999

2 何立民.单片机的C语言应用程序设计.北京:北京航空航天大学出版社,1997

3 马风格.VC控件与串行通讯.1999现代计算机,2000(4)

VC++6 篇3

关键词:虚拟现实;OpenGL;3DS;Visual C++

中图分类号:TP317 文献标识码:A文章编号:1009-3044(2007)15-30832-02

3DS Document Reader and Control Methods Based on VC + + 6.0 and OpenGL

DING Bin

(Northeastern University,Qinhuangdao 066004,China)

Abstract:This article introduced how uses the OpenGL read under Visual C and controls 3Ds Max production three-dimensional model method.

Key words:Virtual reality;OpenGL;3DS;Visual C++

1 引言

OpenGL和3DS Max 是三维图形开发的两个强有力的工具。

OpenGL作为一个性能优越的图形应用程序设计界面(API),其编程灵活、方便,有广泛的移植性和很强的交互式三维图形处理能力,被认为是高性能图形和交互式视景处理的标准。OpenGL除了能够对三维模型进行绘制外,还可以进行三维交互、动作模拟等。具体的功能主要有:模型绘制;模型观察;颜色模式的指定;光照应用;图形效果增强;纹理映射;实时动画;交互技术。此外,使用OpenGL编程有三个显著的特点:网络透明,可共享资源;程序移植性强,在不同的操作系统上不必重建模型;采用流水线机制,适于硬件加速。

3DS Max是Autodesk公司开发的一套优秀的三维建模、动画制作软件,利用该软件能够快速地构造出复杂的三维模型,并加以材质、贴图、纹理、灯光等效果。此外,3DS Max软件是基于WindowsNT平台的,方便易学,又因其相对低廉的价格优势,所以成为目前个人PC上最流行的三维建模软件。它所生成的3DS文件已经成为业界得标准,是一种非常普及的数据格式,以3DS格式保存的三维图形文件也非常丰富。

因此,通过OpenGL读取并控制3DS模型对于快速开发可视化图形应用软件以及虚拟现实系统具有十分现实的意义。

2 OpenGL的绘制流程

作为图形硬件的软件接口,OpenGL主要工作是将三维的物体投影到一个二维平面上,之后处理得到的像素,进行显示。首先将物体转化为可以描述物体几何性质的顶点与描述图像的像素,在执行其他操作后,最终将这些数据转化成像素数据。

2.1 针对每个顶点的操作和几何要素装配

每个顶点的空间坐标需要经过模型取景矩阵变换、法向矢量矩阵变换,若允许纹理自动生成,则由变换后的顶点坐标所生成的新纹理坐标替代原有的纹理坐标,再经过当前纹理矩阵变换。然后根据几何要素类型决定采取不同的几何要素装配方式。

2.2 像素操作

由主机读入的像素首先解压缩成适当的组分数目,然后进行数据放大、偏置,并经过像素映射处理,根据数据类型限制在适当的取值范围内。像素最后写入纹理内存,使用纹理映射或光栅化生成像素段。

2.3 像素段操作

当使用纹理映射时,每个像素段将产生纹素,再进行雾效果计算、反走样处理。接着进行剪裁处理、一致性检验、模板检验、深度缓冲区检验和抖动处理。

3 3DS文件格式

3DS文件由许多块(chunk)组成(大块中镶嵌子块),一个块由块信息和快数据组成。块的前两项信息分别是块的ID和快的长度(也是下一个块相对于该块的字节偏移量),块的ID是一个整型数,块的长度是一个长整型数。每个块是一个层次结构,不同类型的块,其层次结构也不相同。3DS文件中有一个基本块,其ID是4D4D,它包含了整个文件,每个3DS文件的开头都是由这样一个块构成。基本块中的子块是3D编辑程序和关键贞块,前者的ID是3D3D,后者的ID是B000。3D编辑程序块表明编辑程序数据开始,即物体的形体数据定义从此处开始。关键贞块表明下面开始定义关键贞信息。下面给出块中的基本结构图,

说明不同类型的块及其在块中的位置。

图1 3DS文件结构

在读入这种块结构(大块中嵌套小块,而块的结构固定)的文件时,完全可以用递归的方法实现,而返回上一级的条件则是当前已经读入的块的字节数是否等于块的长度。从父块砖向读入其子块,则可用switch语句实现,通过子块的ID判断进入哪个分支。块结构带来的另一个好处是可以根据需要选择读入的块,而不需要的块可以忽略掉。

此外,3DS文件中也用相同的方法标识了物体在场景树中的位置。场景中给予每个物体一个数字以标识其在场景树中的顺序,作为根物体赋予数字-1(FFFF)。当读取文件的时候,就会得到一系列的物体数字标识。如果当前数字标识比前一个大,那么当前物体时前一个物体的子物体;反之,则又回到上一层结构。

4 3DS文件的读取与控制

3DS格式文件的读入可以分为两大部分:文件内容的读入和3D对象的绘制。

4.1 文件内容的读入

根据3DS文件的结构定义,采用面向对象的技术,把3DS文件对3D模型的描述信息进行数据抽象,首先定义一系列的结构,用来存放对象的材质、位置矢量、关键贞等,然后定义用于处理3DS文件中各种对象的CTriObject类和处理对象序列的CTriList。CTriObject中主要包含以下成员变量:

float * x,* y ,* z;//对象的几何位置的坐标

float * nx,* ny, * nz; //对象的法向量

int* faces; //对象的面

tMaterial materials; //对象的材质

char* name; //对象的名称

还需要定义一个3DS文件的读入类C3dsReader,主要将3DS文件中的内容读入到上述两个对象中。C3dsReader类中有很多成员函数,用于读取不同的内容,主要的如下:

int Read3DSChunk (FILE* fp, Chunk3DS& chunk ) ;

//将块的内容读入块结构中

int ReadPercentage (FILE *fp, float& value);

//读入子块

int ReadColor (FILE *fp,float& red,float& green, float& blue );

//读入颜色定义

int ReadPointArray(CTriObject * newchild, long filezize,FILE *fp );

// 读入顶点

int ReadFaceArray(CTriObject * newchild, long unsigned filezize,FILE *fp );

// 读入多边形

VC++6 篇4

在科研与生产工作中, 绘图的应用可谓是无所不在, 比如在机械设计, 电子电路, 建筑等领域, 都需要设计图纸。在过去, 我们通过手绘的方式来设计图纸, 但这种方式的效率太低, 在计算机高速发展的今天已被绘图应用软件所代替。本文通过一个绘图程序的设计过程, 向读者详细介绍了绘图程序中很多具体功能的实现方式。

2、程序开发环境

该应用程序是在中文windows X P Professional环境下使用Microsoft Visual C++6.0开发而成的。

3、程序功能的分析与说明

本绘图应用程序需要实现的功能如下:

3.1 绘制图元

包括线段图元, 椭圆图元, 三角形图元, 矩形图元。

3.2 改变绘制条件

这包括:改变线条颜色, 线条类型, 线条宽度。

3.3 图形修改

包括删除, 拷贝, 剪切, 粘贴以及平移被选图元 (其中删除, 剪切和粘贴操作能够被撤销和恢复) , 撤销和恢复最近绘制的图元。

3.4 图元修改

包括修改被选图元颜色, 线型以及宽度。

3.5 文件的存取

本应用程序能够完成图形文件的保存, 打开。

根据以上的功能分析, 本程序可以被划分为以下功能模块:基本图元绘制, 图形修改, 图元修改, 图形文件存取。

4、程序框架设计

首先, 我们通过VC++提供的应用程序向导 (AppWizard) 来构建一个多文档的应用程序框架 (工程名为:Draw) , 然后再添加相应的代码和资源以实现该程序所需的功能。程序的总体设计思路如图1:

在构建好框架之后, 还需要添加一些菜单命令, 两个绘图工具栏 (分别用于选择绘图状态和绘制条件) 以及相应的代码 (当然还有每个功能模块的具体实现放到后面去讲) 。

5、图元数据的定义

在绘图中, 我们需要对图元进行存取。为避免浪费内存空间, 我们采用动态方式进行存储分配的链表结构来对图元进行存取。代码如下:

6、功能模块的设计

在构建好程序主框架后, 我们来对四个功能模块分别进行设计。

6.1 基本图元的绘制

图元的绘制包括:线段, 椭圆, 三角形, 矩形, 无论绘制哪种图元, 我们都是通过“按下鼠标左键 (L B U T T O N D O W N) -拖动鼠标 (M O U S E M O V E) ——释放鼠标左键 (LBUTTONUP) ”这样一个过程来确定所绘制图元的位置和具体形状。设计思路如下:

(1) .在LBUTTONDOWN的消息函数中, 记录下鼠标的位置作为起点;

(2) .在MOUSEMOVE的消息函数中, 画出图元的预览线;

(3) .在LBUTTONUP的消息函数中, 记录下鼠标的位置作为终点, 然后根据起点和终点最终画出所绘图元, 同时将图元的所有属性值存入图元链表。

在 (2) 和 (3) 这两步中, 均需要首先判断当前处于哪种图元绘制状态, 然后在进行相应的绘制工作。可以用switch语句来实现, 如下:

6.2 图形修改

图形的修改包括:删除, 拷贝, 剪切和平移被选图元 (其中删除和剪切操作能够被撤销和恢复) , 撤销和恢复最近绘制的图元。这四种基本功能的设计思路都是:在每种消息的消息映射函数中对被选择图元的结点的相应成员变量做相应修改 (例如删除操作时, 将其成员变量delete设置为TRUE, 平移操作时根据鼠标的移动将其表征图元位置的成员变量修改) , 修改完毕后, 再通过语句Invalidate Rect (NULL) 来自动引发对On Draw () 函数的调用, 在On Draw () 函数中按照修改后的图元结点的成员变量值来重新绘制这些图元 (比如delete为TRUR的图元结点不再绘制, 坐标位置被修改过的图元按新的坐标来绘制) , 从而实现了这四个基本功能。

6.3 图元修改

图元修改包括修改被选图元颜色, 线型以及宽度。其设计思路和前面图形修改的类似:根据新选择的图元属性 (线条颜色, 线型以及宽度) 来对被选图元的相应成员变量 (color, width, style) 进行修改, 然后再通过语句Invalidate Rect (NULL) 来自动引发对O n D r a w () 函数的调用, 在On Draw () 函数中按照修改后的图元结点的成员变量值来重新绘制这些图元, 从而实现了图元的修改功能。

6.4 图元文件存取

绘制完毕的图形需要存储起来 (图形文件的扩展名设定为:.dra) , 并且下次可以在该应用程序中将其载入, 我们可以通过“文件”菜单的“保存”和“打开”命令对应的消息影射函数来编程实现存取操作。存储时:将图元链表中的图元结点的所有成员变量值写入图元文件 (第一次存储时还应创建文件) ;载入文件时, 首先构建图元结点, 然后将文件中的数据读出, 再写到图元结点相应的成员变量中去, 再通过On Draw () 函数将它们重新绘制出, 从而实现了打开文件操作。

7、程序测试

在VC++6.0中, 我们对程序的各个功能模块进行了仔细的调式。通过调试, 发现了程序还存在一些问题, 比如无法执行删除操作, 经过对代码的仔细检查, 我们发现:在执行绘图的代码前遗漏了if (!head->del) , 因为只有在图元未删除时才能对其进行绘制。经过我们的修改, 程序基本实现了我们预期的功能。程序运行界面如图2:

摘要:绘图工作在很多工程领域是不可或缺的, 但不管是在哪个领域的应用, 绘图程序中很多功能的实现方式在本质上都是相通的。这篇论文通过一个绘图程序的设计与实现详细介绍了绘图操作中很多基本功能的实现方式。

关键词:图元,链表结构,功能模块

参考文献

[1]郑莉, 懂渊.C++语言程序设计 (M) .北京:清华大学出版社.2001.

[2]张卫华, 刘征.VisualC++程序设计实战训练 (M) .北京:人民邮电出版社.2004.

[3]张立科.VisualC++6.0MFC类库参考手册 (M) .北京:人民邮电出版社.2002.

[4]季海捐, 韩亚萍.VisualC++6.0基础培训百例.北京:机械工业出版社.2006.

VC++6 篇5

在进行电路分析和设计时,常使用Proteus、Multisim、EWB、OrCAD(Spice)、Protel等电路分析工具。但用这些软件来分析电路,所得数据精度难以提高,且软件界面固定,设计出的模型很难脱离分析环境独自运行。现代电路分析提供了一种用矩阵方式分析电路问题的解决方法,这种方法也是以上电路分析软件的基础,Matlab包含许多矩阵函数,可以快速地验证自己的模型和算法。虽然Matlab作为一种解释性语言,运行效率较低。但如果使用VC++6.0调用Matlab C++数学库,就可以编写出具有良好人机界面、运行效率较高、个性化的电路分析程序。

现代电路分析把基本的电路定律,即基尔霍夫电流定律(KCL)、基尔霍夫电压定律(KVL)和元件支路方程结合起来,建立网络方程组,主要用于研究线性时不变网络。该分析方法利用拓扑学的基本原理将电路图转换成矩阵形式,在电路图和计算机之间架起一座桥梁,即实现电路信息的计算机化。Matlab语言是一种解释型的高级语言,它包含自己的数据结构、程序流控制及文件输入输出等功能,并能很好地处理矩阵运算。其次,为了使程序的人机界面友好,Windows操作系统能支持的程序是较佳的选择,VC++6.0是Microsoft公司推出的可视化编程环境。主要适合在Windows下进行32位应用程序的开发。开发一个Win32应用程序是一件耗费时间的事,MFC即微软基础类是一种VC++语言类库,这样,利用VC++6.0的MFC功能来编制Win32程序时,程序员就能利用标准的类库来提高编程效率和程序的质量。Matlab6.5版本带有Matlab C++数学库,使程序员用VC++和Matlab混合编程更加容易。文中将具体介绍如何根据现代电路分析理论,采用节点分析法,使用VC++6.0和Matlab混合编程来编制Win32程序,有效解决线性电路电参数的计算机分析问题。

2 步骤

2.1 有向图

将电路转换成矩阵形式的第一步是要画出与电路对应的拓扑图,图1为示范用的电路。绘制该电路的拓扑图时,保留了电路的节点,并用线代替全部支路。有向图就是在拓扑图中加入表示对应支路电流方向的箭头,有向图表明节点和支路的连接关系,而不表明电路元件。图2就是与图1对应的有向图。

将电路转换成矩阵形式的第二步是要选择一个树。树是连接图的全部节点而不包含任何回路的支路的集合,组成树的支路叫树枝,不组成树的支路叫连支。在大部分网络中,存在着许多可能的树。由于树中无回路,基尔霍夫电压定律不能用来描述树枝电压之间的关系。因此,树枝电压是独立的。可以断定,在无独立电压源的情况下,网络中独立电压的个数等于树枝数。假定全部独立压源都包括在树里面,显然,每个独立压源都约束着一个节点相对于另一个节点的电压,因而使网络中独立电压的数目减少一个。同样,当每个连支加到图上而建立起一个回路时,该连支电流只在此回路中环流,因此连支电流是独立的。假定全部独立流源都作为连支包括进来,显然,每个独立流源都约束着一个连支电流,因此使网络中独立电流的数目减少一个。选择网络的树为选择独立变量最小集合提供了方法,根据这些变量能够求得全部网络电压和电流。

在利用树枝电压和连支电流的分析方法中,独立电源都假定他们与有限阻抗串联,或与有限阻抗并联。虽然有需要利用等效电路来处理的例外情况,但这在实践中是可行的。两种分析方法都要求定义如图3所示的标准支路。为了给下面的矩阵分析做准备,用下标r表示电路中第r支路的自阻抗或自导纳。

连支电流分析要求独立流源必须跨接在支路两端,树枝电压分析要求独立压源必须与阻抗Zrr相串联。对后面介绍的分析方法,戴维南定理可以用来将标准支路转化成简单等效电流源(Ir-YrrEr)或简单等效电压源(Er-ZrrIr),这时伪节点就没有了。对第r支路,欧姆定律表明Vr=Zrr·Ir对全部支路,可以同时用矩阵方程

式中,vT=[v1,v2,…,vb](vT为v的转置矩阵)

同样j=Yv(2-2)

式中

把基尔霍夫定律用到第r标准支路,得jr=Ir+ir和vr=Er+er或者对全部支路写成矩阵形式

式中

代入方程(2-1)和(2-2),并整理得

这些方程可逐个用到各支路上去,下面的矩阵分析法将利用这些方程,研究电路连接对支路电压和电流的约束。

将电路转换成矩阵形式的第三步是用基本切割方法切割第二步选择的树。所谓基本切割是指恰好切断一根树枝的切割,方向是被切断树枝的方向。通过基本切割获得割集矩阵,这种矩阵的元素由1、0或-1组成。首先把树枝由1开始编号,矩阵的行数对应于具有相同号数的电路支路。同样,矩阵的每一列对应于一个切割。图4即是与示例电路对应的一个树,和对该树所做的3个基本切割。

分块使矩阵分成上下两部分,上面部分用DT表示,它与树枝对应;下面部分DL则对应于连支。因为割集的切割数等于树枝数,且基本切割只能切断一根树枝,所以DT必然是单位矩阵。如果按行号数标记的支路被按列号数标记的切割所交割,并且支路电流方向与该切割的树枝电流方向相同,那么矩阵取值为+1;如果支路电流取相反方向,那么矩阵取为-1;如果支路不被切割,则取值为0。

2.2 求解电路各参数

根据上面步骤得到方程式(2-7),它是示范图割集基尔霍夫电流定律的矩阵表示形式。将该矩阵方程用字母方式表示为DTi=0。

矩阵D被称为割集矩阵,并由1、0或-1组成,图4中电路图的割集矩阵D重写为如下方程:

首先把树枝由1开始编号(如图4中的编号),矩阵的行数对应于具有相同号数的电路支路。同样,矩阵的每一列对应于一个切割。分块使矩阵分成上下两部分,上面部分用DT表示,它与树枝对应;下面部分DL则对应于连支。因为割集的切割数等于树枝数,且基本切割只能切断一根树枝,所以DT必然是单位矩阵。

割集矩阵的另一个特性是可用表示式DeT加以说明,其中eT是e与树枝有关的部分,完全展开得

在后面的分析中,将通过方程表示式v=E+e把独立压源包括进来。

割集分析的两个主要步骤是:将基尔霍夫电流定律用于割集和将连支电压用树枝电压来表示。这两步都已用割集矩阵来完成了,所以电路分析是能够表示成矩阵形式的。重写式(2-6)的支路相互关系为:

等式两边左乘DT,得到:

由前所知,根据基尔霍夫电流定律,DTi=0(见矩阵方程式(2-7)的字母表示形式)。用方程(2-10)的e代换,得到:

要把解表示成独立树枝电压的集合,需将矩阵DTYD求逆,得到:

网络中其余的电压和电流,都可将其代入式(2-3)、式(2-4)、式(2-10)和式(2-11)去求得,即:

支路电压e=DeT

支路电流i=Ye-(I-YE)

矩阵元电压v=e+E

矩阵元电流j=i+I

至此,已经可以对只有两端元件的电路进行矩阵分析了。只要用Matlab等数学软件对矩阵进行分析便可得到相应电路的V-I特性了。

3 电路分析程序

以求解图1示范电路为例,介绍运用VC++和Matlab混合编程实现电路分析程序。

3.1 运行环境

对话框是VC++6.0中重要的应用程序模式之一。对话框可以接收用户输入的信息或数据,一般是通过在对话框上添加控件来实现对话框的操作,对话框依靠这些控件与用户进行交互。

(1)启动Visual C++6.0,选择“文件”菜单的“新建”命令,在弹出的“新建”对话框中选择“工程”页面,在该页面下选择“MFC AppWizard(exe)”选项,并单击。在静态文本“工程”下的编辑框中输入程序的名称。在“位置”下的编辑框中输入程序项目的保存地址,然后单击“确定”按钮,进入创建工程向导界面。

(2)创建工程向导的第一步选择Dialog based(基本对话框)选项,同时还可以选择支持的语言,单击“Next”按钮,进入向导的第二步。

(3)在MFC向导的第二步,保持默认选项不变,直接单击“Finish”按钮后即出现对工程整体描述的对话框,单击“OK”按钮,进入开发界面。

(4)在资源窗口中单击鼠标右键,在弹出的对话框中选择Import,集成开发环境随即弹出导入资源对话框,在该对话框中选择图1示范电路,单击“Import”按钮,即把该示范电路加入到了程序工程环境中。使用该图作为程序界面使程序直观、易用。

(5)在图上添加编辑框控件,作为人机进行数据交流的接口。在VC++6.0中对话数据交换(DDX)和对话数据确认(DDV)是两个非常简单而又非常强大的功能。它们使得在MFC中从对话框字段或任何其他CWnd的派生类中插入和抽取数据变得非常容易。因此本程序将使用对话框的DDX和DDV功能具体进行人机数据交流。

3.2 矩阵运算

要在VC++中调用Matlab的功能,需要按照下面3个步骤改变VC++工程创建时的默认设置。

第一步,在VC++工程设置中加入的静态链接库:libmatpm.lib,libmx.lib,libmatlb.lib,libmat.lib,libmmfile.lib,sgl.lib和libmwsglm.lib。其中,sgl.lib和libmwsglm.lib只有在用到Matlab C++图形库的时候才需要在VC++工程设置中加入。

第二步,设置C/C++标签中的选项,在VC++6.0的IDE中选择Project菜单,在弹出的菜单中选择Project Settings(工程设置)选项,将出现Project Settings对话框,选择C/C++选项,将Category的下拉列表框内容设置位Code Generation,又将Use run-time library选项设置为Multithreaded DLL。将Category选项设置为Preprocessor,并且在Preprocessor definitions选项中增加如下内容:MSVC,MSWIND,IBMPC,D__STDC_,_AFXDLL。

第三步,在工程中包含相应的头文件。在Visual C++工程中如果不用Mablab C++图形库的时候,只需要包含头文件"matlab.hpp”;如果要用到Matlab C++图形库的时候,则需要包含头文件“matlab.hpp”和“libmwsglm.hpp”。

在做完以上三步的设置后,就可以在VC++工程中通过Matlab C++数学库调用Matlab的矩阵运算函数了。

3.3 难点问题及处理方法

由于平时使用的软件开发平台的数据存储格式与Matlab的数据存储格式不同,要将Matlab的功能运用于自己的程序中,就要解决好两种编程语言的沟通问题。对于多维数组,与C语言的数组元素在内存中按行的排列顺序不同,所有Matlab阵列在内存中都是按列排列的。因此,在程序中需要专门设置程序来实现两种编程语言的矩阵数据存储格式的相互转化。

其次,由于Matlab所有的运算都是采用双精度浮点型,因而整型阵列如果要参加运算,必须先转化为双精度型。Matlab C++数据库只有Matlab阵列一种数据类型。Matlab C++数据库中用mwArray类封装了Matlab阵列的数据及其基本操作函数。因此,可以使用mwArray类作为C++语言和Matlab语言的沟通桥梁。

如何将mxArray转化为C++语言可以直接使用的基本数据类型,或者如何将C语言的基本数据类型转化为mxArray类型?这个问题由Matlab通过提供一系列操作mxArray的API函数解决了。例如:

int mxGetM(const mxArray*array_ptr)函数可以得到Matlab阵列的行数,

int mxGetN(const mxArray*array_ptr)函数可以得到Matlab阵列的列数,

double*mxGetPr(const mxArray*array_ptr)函数可以得到Matlab双精度数值阵列的实部数据指针。

GetData()函数放回一个mxArray结构的指针,通过这个mxArray结构,开发人员可以通过Matlab C数学库的函数进行数据访问操作。使用GetData()函数需要注意的是,不要释放GetData()函数放回的mxArray指针指向的内存及mxArray中包含的数据。

ToString()函数可以将字符类型mwArray中的字符数据转化为C/C++语言字符串数据。

4 结语

在理解矩阵电路分析方法之后,就可以根据具体的线性电路运用网络拓扑的方法作出有向图,并选出一棵树,依顺序进行基本切割,获得割集矩阵,再利用VC++和Matlab混合编程实现人机界面友好的Win32电路分析应用程序。经过与EWB,PSPICE等电路分析软件比对,按该方法设计出的程序,其计算结果与这两款软件分析同一线性电路所得数据一致。这表明这种电路分析程序设计方法能够实际运用于工作之中。

摘要:在分析和设计电路时,常使用Proteus、Multisim、EWB、OrCAD(Spice)、Protel等电路分析工具,但要想得到更精确的电路分析数据或者个性化的电路模型,以上工具却难以应付。现代电路分析提供了一种用矩阵方式分析电路问题的解决方法,这种方法也是以上电路分析软件的基础。Matlab提供了许多矩阵运算函数,使用VC++6.0能够设计出接口良好的Windows程序。因此,使用VC++6.0和Matlab混合编程就能编写出矩阵电路程序,解决个性化的电路分析问题。

关键词:矩阵分析,VC++6.0,Matlab,混合编程

参考文献

[1]杜普选,等.现代电路分析[M].北京:北方交通大学出版社,2002.

[2]刘维.精通Matlab与C/C++混合程序设计[M].北京:北京航空航天大学出版社,2005.

[3]Marshall Brain,Lance Lovette,译星翻译.MFC开发人员指南[M].北京:机械工业出版社,1999.

[4]阮宇.Visual C++6.0基础教程[M].北京:清华大学出版社.

VC++6 篇6

数字地形模型 (DTM) 是地形表面形态属性信息的数字表达, 是带有空间位置特征和地形属性特征的数字描述。当数字地形模型中地形属性为高程时称为数字高程模型 (DEM) 。DEM和DTM主要用于描述地面起伏状况, 能用于提取各种地形参数, 如坡度、坡向、粗糙度等, 并进行通视分析、流域结构生成等应用分析。

其中, 通视分析有着广泛的应用背景。如:观察哨所的设定、森林中火灾监测点的设定、无线发射塔的设定等。在各种应用中, 两点间的通视分析判断是最基本、最常见的问题。DEM有多种表达方式, 包括网格、等高线、三角网等, 基于不同表达方式的DEM计算通视分析的方法差异非常大。在一次性构建约束Delaunay三角网DEM模型的基础上[1][2], 编程实现了两点间通视分析算法。

2 算法原理

在对已建成的模型进行通视分析时, 采用的是视线与边相交法[3]。其原理如下:设基于地形表面的有限采样数据点序列为S, 定义数字高程模型为D≡ (Σ, Φ) , (其中, Σ是以点序列{ (x, y) | (x, y, z) ∈S}作顶点的平面连通域的一种分割, Φ是一个二变量连续函数族) , 在D上有视点A和目标点B, 计算A与B之间的通视性。首先, 计算视线s≡AB在xy平面上的投影 (记为s') 与Σ边的交点。在s'与Σ的每一条边e的交点P处, 检验s是否位于D相对应于边e的地形上面。如果在所有这样的交点处视线s都在相应的地形上面, 那么视点A和目标点B是可以通视的, 否则, 是不能通视的。如图1所示。

3 算法实现

两点间通视分析算法的具体编程步骤如下:

步骤1定位视点A与目标点B所在的三角形 (TinA, TinB) , 并计算出视点A和目标点B的高程值。

(1) 确定点所在的网格位置。设average为单元格大小, 由待判断点的横、纵坐标, 根据公式 (1) 即可求出待判断点所在单元格位置:

(2) 基于面积坐标的点定位算法分别得到视点A与目标点B所在的三角形, 分别记为TinA和TinB。

(3) 分别计算出TinA、TinB的平面方程, 根据视点A和目标点B的横、纵坐标计算出两点的高程值。

计算三角形 (tinp) 平面方程系数 (a, b, c) 的核心代码如下:

由三角形平面方程即可得到待判断点的高程值 (Z=ax+by+c) 。

步骤2以视点A所在的三角形 (TinA) 为起始三角形 (tinp) , 以目标点B为方向点, 基于面积坐标的点定位算法, 得到与视线AB相交的一条边 (aspect-line) , 并将该边的另一侧三角形记为新的起始三角形 (tinp) 。

(1) 基于面积坐标的点定位算法[4][5]核心代码如下:

(2) 其中Sameside函数的核心代码如下:

步骤3计算得出相交边 (aspectline) 与视线的交点P, 利用线性插值判断视线在P点的高程值是否大于其在相交边P点处的高程值, 如果小于, 则视点A与目标点B之间不能通视。

计算交点P及判断高程值大小的核心代码如下:

步骤4如果大于, 则循环步骤2、3、4, 直到起始三角形即为目标点B所在的三角形 (TinB) 为止。

4 结语

在基于一次性构建Delaunay算法生成的DEM模型的基础上, 编程实现了利用视线与边相交法判断两点间的通视分析算法。任意两点间的通视分析判断结果如图2所示。

摘要:要充分发挥GIS的潜力, 在很大程度上依赖于强大的空间分析功能。地形分析作为空间分析的一种, 在地理数据的应用中发挥着举足轻重的作用。而通视分析作为一种复杂的地形分析, 有着广泛的应用背景。在VC++6.0编程环境中, 在已构建的DEM模型基础上, 编程实现了利用视线与边相交法判断两点间的通视分析算法。

关键词:VC++6.0,DEM模型,通视分析

参考文献

[1]任振娜, 李斌兵.一次性生成约束Delaunay三角网算法的编程与实现[J].测绘工程, 2006, 1:54-58.

[2]任振娜, 杨颖.一次性生成约束Delaunay三角网的算法研究[J].几何设计与计算的新进展, 2005.151-154.

[3]王智杰.TIN数字地形模型的通视性算法.情报指挥控制与仿真技术, 2005, 27 (5) :91-95.

[4]刘学军, 符锌砂, 赵建三.三角网数字地面模型快速构建算法研究.中国公路学报, 2000, 13 (2) :31-36.

VC++6 篇7

1.1 VC++6.0与数据库的连接

VC++6.0与数据库连接,要在头文件Std Afx.h中引入相应的库文件,代码如下所示:

1.2 使用UDL文件与数据库的连接

UDL文件的建立步骤[1]:

(1)在特定目录下,建立一个文本文件,并将文本文件名更改为“dblink.udl”。

(2)鼠标右键单击dblink.udl,选择“属性”命令,在弹出的属性对话框中选择“提供程序”选项卡,选定列表中的“Microsoft OLE DB Provider for SQL Sever”项。

(3)在属性对话框中选择“连接”选项卡,输入相应的服务器名称并选择相应的数据库,点击测试连接。

1.3 查询按钮函数代码

要实现查询结果的显示,需要在相应的对话框的头文件中添加函数声明,并在对应的.CPP文件中添加相应的处理函数。

1.4 查询结果显示

通过在种类查询、科室查询窗口中输入不同的查询条件进行查询,并将查询结果在列表框中显示,结果如图1、图2所示。

2 在基于对话框的程序中添加文档/视图架构

在基于对话框的应用程序中实现打印功能的时候,需要添加文档/视图架构。首先需要了解应用程序与文档、视图架构之间的关系。应用程序CWin App包含一个文档管理指针成员变量:CDoc Manager*m_p Doc Manager和一个指针序列,CDoc Manager包含的指针序列用来维护程序中的文档模板,详细步骤如下[2,3]:

(1)创建一个菜单资源,设定其ID。

(2)设置菜单资源的3个子菜单项的ID值,如图3所示。

(3)创建工具栏,其ID与菜单资源的ID相同,如图4所示。

(4)设置3个工具栏按钮ID与菜单资源的子菜单ID值相同。

(5)新建一个框架窗口CPrint,基类为“CFrame Wnd”。

(6)新建一个文档类CPrint Doc和视图类CPrint View,其基类分别为:CDocument和CScroll View。

(7)在视图类中添加“CPrint Doc*Get Document()”方法并添加消息映射代码。

(8)在CPrint类的消息映射部分添加映射宏并在初始化时添加文档模板,测试文档/视图架构。

3 查询结果的打印

为图1中打印按钮添加如下代码,实现查询结果的打印。结果如图5所示。

4 结束语

在进行数据库连接时应用了UDL文件,是比其他连接方式更为简洁的方式。在数据库连接字符串中通过“FILE NAME”指定UDL文件后,即可像使用常规数据库连接字符串那样使用。程序中,多处使用“try…catch…”语句进行异常捕捉,这样可以使代码更健壮和安全。

参考文献

[1]颜志军.Visual C++数据库开发典型模块与实例精讲[M].北京:电子工业出版社,2007:312-314.

[2]郑阿奇,丁有和,郑进,等.Visual C++使用教程[M].北京:电子工业出版社,2004:250-251.

[3]明日科技.Visual C++程序开发范例宝典[M].北京:人民邮电出版社,2007:504-507.

[4]刘志敏.数据集市——医院数据仓库应用中的选择[J].医疗卫生装备,2005,26(8):38.

VC++6 篇8

1“显性”问题及其应对策略

1.1“显性”问题的分析

用VC++6.0编译C程序有“显性”问题有:1)书写标识符时,忽略了大小写字母的区别;2)输入变量时忘记加地址运算符“&”;3)switch语句中漏写break语句;4)定义数组时误用变量等。读者可以参见谭浩强《C语言程序设计》(第四版)第十一章有详,这些“显性”问题主要是语法结构错误。

1.2“显性”问题的应对策略

“显性”问题的应对策略主要分为两种:(1)程序员在编写程序时,应该注意编写的习惯,例如:输入大括号时,要成对输入{};每一语句一行,在每一行后面加上“;”;字符输入时,一定要注意中英文的切换等。(2)通过VC++6.0软件的错误提示如下图:

2“隐性”问题及其应对策略

先看一下程序:

这个是一个输入“+”、“-”、“*”、“/”以实现两个数的四则运算,这个程序的本意是想用scanf()函数进行循环输入,然后判断。可是输入第一次没有问题,输入第二次就直接跳过,这就是C语言程序的“隐性问题”,其本质就是键盘输入缓冲区的理解,从键盘输入数值进行人机对话过程是这样的,先把键盘中输入的数值送到键盘输入缓冲区,等到键盘输入缓冲区满了之后,将把其内容输入到内存中,最后是程序调用内存里的数据,所以在循环使用scanf()函数输入数据时,第一次输入的数值输入到键盘输入缓冲区中,在键盘输入缓冲区没有清空的情况下,第二次scanf()会把第一次输入的内容直接给内存对应的变量,就没有实现循序人机对话,因此在循环语句中,scanf()前面加上fflush(stdin)语句就可以了。

另外,典型“隐身”问题有:1)在数组的定义长度和下标之间差1,因为C编译数组是从下标0开始的;2)指针变量pointer一定要一个初始值,且和for嵌套语句使用时一定要让pointer恢复初值;3)文件流操作时,一定要注意调用fclose()用来关闭文件,不然会文件中数据的丢失等等。

3 总结

经过笔者编程和教学实践表明:在编程时,对于“显性”问题,一定要熟悉C语言的语法结构,多练多看VC++6.0的提示信息。对于“隐性”问题,一定要对C语言的编译原理和“本质”,在实战中多积累,尤其是数组、指针和人机对话的理解。只要注意“显性”问题和“隐性”问题,编出来的C程序系统才能是移植性强可靠性高的程序。

摘要:用VC++6.0编译C程序除了有许多“显性”问题外,还有许多“隐性”问题,对其问题的本质认识不清,将影响用C程序系统功能的实现。改文分析了几种除经典问题之外的“隐性”问题,并提出其应对策略。多年的编程实践表明认识了基于VC++6.0的C程序编译问题的“本质”,将有助于程序员的程序设计。

关键词:VC++ 6.0,C语言,编译问题

参考文献

[1]谭浩强.C语言程序设计[M].4版.北京:清华大学出版社,2010.

[2]谭浩强.C语言程序设计学习辅导[M].4版.北京:清华大学出版社,2010.

VC++6 篇9

2008年年初中国南方地区发生特大雪灾,低温、高湿等气候因素引起高压线路覆冰,从而导致大面积输电线路截断和倒塌,严重影响了人们的生活和安全,给国家造成巨大的经济损失。而在北方的大部分高山地区,在冬春两季由于气候、地形等因素的影响,高压线路覆冰也是很常见的现象。高压线路覆冰超出设计的规定,会造成跳闸停电、导线折断和塔架倒塌等严重结果,可见高压线路覆冰是影响电网安全的重要因素。因此设计一套能够使得工程技术人员根据天气情况及时计算并获取覆冰对高压线路影响的软件,具有非常重要的价值。

VC++6.0软件是一种面向对象的程序化设计语言,具有良好的用户图形界面输入接口,ANSYS软件是美国AN-SYS公司研制的通用大型有限元分析软件,在航空航天、机械制造、电子等行业有着广泛的应用。APDL语言是ANSYS软件自带的一种批处理语言,它能自动完成一些通用性强的任务,也可以根据参数建立模型,并提供了自动完成循环的功能[1]。本文设计的高压线路覆冰受力分析软件将VC++6.0与ANSYS有机结合,利用VC++6.0可以通过APDL批处理命令流文件来调用ANSYS完成相应分析计算工作的特点,较好地解决了覆冰计算的实际问题,为电力系统运行单位迅速根据气候条件做出决策提供依据。

2 软件设计思路与实现

采用有限元分析的方法对高压线路受力情况进行分析计算是一个好方法,但是对于一般人员来说,很难在短时间内掌握ANSYS软件。而线路覆冰的计算参数比较固定,塔架的形式变化不多,所以应在ANSYS软件当中构建参数化的塔架模型,而相关参数采用VC++6.0编制的用户界面输入。在输入参数之后,根据每一个参数对线路的影响,计算出综合影响结果,把这个结果作为ANSYS的输入参数,并通过进程调用ANSYS完成覆冰条件下的受力分析。

高压线路覆冰受力分析系统的软件设计总体思路为:利用VC++6.0完成对ANSYS的封装,用户只需要使用VC++6.0开发出来的友好的、简单的人机图形界面接口,而复杂的ANSYS参数建模过程已由专业人员完成作为后台处理模块。用户只需要从界面输入温度、湿度等覆冰的相关参数,即可调用ANSYS在后台进行分析计算,分析计算完成之后,用户通过程序界面即可查看相关的结果,包括图形文件和参数文本文件。

图1所示是软件的工作流程。首先,工程技术人员在ANSYS用户界面下建立相应的参数模型并进行求解计算,所获得的APDL命令流文件作为程序的一个模块,它可以接收用户输入的参数。程序启动后,调用ANSYS批处理程序,再调用已经包含输入参数的APDL命令流文件进行分析计算,生成各种分析结果,用户可以根据需要来启动后处理程序查看分析结果。

3 软件实现

高压线路覆冰受力分析系统软件界面如图2所示,用户通过界面输入参数包括温度、湿度、覆冰时间、风速、风向、线路直径,当温度低于零摄氏度,湿度范围在60%以上时,根据覆冰模型[2]即可求得线路的覆冰重量,具体的覆冰模型可以查看参考文献[1]。在界面上,用户还需要输入的参数是塔间跨度,选择线路的材料即可计算线路的综合受力情况。对于VC++6.0应该实现的功能有[3]:(1)前处理参数输入功能;(2)根据用户输入参数修改APDL命令流文件中参数设置的功能;(3)将生成的APDL命令流文件提交给ANSYS进行批处理操作的功能;(4)按钮操作查看输出结果图形的功能。以下对于软件设计过程中的几个关键问题进行说明。

3.1 APDL命令流文件

APDL命令流文件可以由用户直接用APDL语言编写而成,但是这种方法不易掌握。一般情况下可以使用在建立通用模型时生成的命令流文件,如在高压线路覆冰受力分析系统软件设计中,所使用的命令流文件就是在建立模型时生成的log.txt文本文件。

APDL命令流文件log.txt文本文件包含设置参数的命令[4,5],根据这一特点,可以通过参数传递,将用户输入的参数值写入到已有模型的APDL命令流文件中。具体的程序实现如下[6]:

若用户界面上输入的参数根据程序运算结果为载荷力为-150N,现场情况可得塔架跨度的取值范围,设定输入塔架跨度为100m,则得到的APDL命令流文件log.txt是以下列形式开头的:

3.2 VC++6.0程序启动ANSYS

ANSYS提供的批处理模式可以使ANSYS在后台运行,在这个软件中,使用的版本是ANSYS10.0,VC++6.0本身也提供了很多函数可以用来调用其它的应用程序,最常见的函数有Win Exec、Shell Execute和Create Process,在这里使用的是Create Process函数[6],启动ANSYS以批处理方式运行的命令程序为:

其中,输入文件即为上文所述的APDL文件,就是log.txt文本文件,输出文件记录分析过程中使用的命令流、错误信息和计算求解结果等。在ANSYS运行之后,将会输出图形和文本文件等结果保存到指定路径,供用户查询模块来调用。

3.3 结果查询显示

ANSYS具有强大的后处理功能,结果以图形或者表格的形式显示出来供用户查询。在VC++6.0调用ANSYS批处理模式的情况下,如何把图形结果显示出来就是对AN-SYS后处理封装的关键。APDL命令流文件中在后处理器之后,必须包含对于输出图像的程序语句:

在这个软件设计中,通过对后处理部分的封装,实现了用户点击界面按钮就可以在弹出的对话框中看到结果的功能。具体的VC++6.0程序实现,为输出对话框新建立一个类Cshow Dlg,在新建类中包含对图像为jpeg格式的处理,点击按钮显示代码为[6]:

例如,点击界面上的输出框上的“应力图”按钮,就弹出分析所得的应力图对话框如图3所示。

4 结论

针对高压线路覆冰对线路的影响进行了分析,通过采用VC++6.0对ANSYS进行后台调用的方法,设计了一套用于覆冰条件下高压线路受力分析的软件,并根据实际应用对该软件进行了验证。

该软件为电力运行部门提供了有力的决策依据,为电力运行安全提供了有力保障,该软件的设计思路和方法还可以广泛用于ANSYS的二次开发。

摘要:首先采用流程图方式介绍软件的设计思路,然后根据开发的过程,对APDL命令流文件、VC++6.0程序启动ANSYS、结果查询显示三个部分进行了详细说明,给出了在某一实际天气条件下的输出图形。

关键词:高压线路覆冰,VC++6.0,ANSYS,APDL,批处理

参考文献

[1]夏瑞武.APDL参数化有限元分析技术及应用[J].机电产品开发与创新,2008,21(2):103-104.

[2]魏其巍.电线覆冰机理分析及在工程设计中的应用[J].电力建设,2007,28(3):26-28.

[3]崔俊伟,蔡川,徐长太,等.基于VC++调用APDL的GIS断路器电场计算[J].高压电气,2007,43(4):289-291.

[4]邵军,文先琪,李迎涛.基于VISUAL BASIC的ANSYS参数化设计[J].重庆科技学院学报,2006,8(3):98-100.

[5]吴剑,王洪飞.基于ANSYS的磁流变阻尼器磁路优化设计[J].机电工程,2008(2):74-76.

【VC++6】推荐阅读:

上一篇:分娩期的心理护理下一篇:租赁机器设备

本站热搜

    相关推荐