基于VC的STL文件读取
VC实现对XML文件的读写

VC实现对XML文件的读写VC实现对XML文件的读写点击:0 发布日期:2007-6-11 13:29:00 进入论坛1、安装MSXML 4.0 SP2。
在VC6中建立一个基于Dialog的工程。
如图:在界面上放置3个编辑框、1个按钮控件。
其中属性设置如下。
编辑框:ID Category Variable Type Variable NameIDC_ID Value CString m_strIdIDC_AUTHOR Value CString m_strAuthorIDC_TITLE Value CString m_strTitle按钮:ID CaptionIDC_GENERATE GenerateIDC_LOAD Load2、在App类的InitInstance函数里面加入如下代码:// Com口初始化AfxOleInit();3、在StdAfx.h中引入动态链接库MSXML.DLL(C:\windows\system32\msxml4.dll)#import < msxml4.dll >4、双击Generate按钮,在消息处理函数中添加如下代码:UpdateData(TRUE);MSXML2::IXMLDOMDocumentPtr pDoc;MSXML2::IXMLDOMElementPtr xmlRoot ;// 创建DOMDocument对象HRESULThr = pDoc.CreateInstance(__uuidof(MSXML2::DOMDocument4 0));if ( ! SUCCEEDED(hr)){MessageBox( " 无法创建DOMDocument对象,请检查是否安装了MS XML Parser 运行库! " );return ;}// 根节点的名称为Book// 创建元素并添加到文档中xmlRoot = pDoc -> createElement((_bstr_t) " Book " );// 设置属性xmlRoot -> setAttribute( " id " ,( const char * )m_strId);pDoc -> appendChild(xmlRoot);MSXML2::IXMLDOMElementPtr pNode;// 添加“author”元素pNode = pDoc -> createElement((_bstr_t) " Author " );pNode -> Puttext((_bstr_t)( const char * )m_strAuthor);xmlRoot -> appendChild(pNode);// 添加“Title”元素pNode = pDoc -> createElement( " Title " );pNode -> Puttext(( const char * )m_strTitle);xmlRoot -> appendChild(pNode);// 保存到文件// 如果不存在就建立,存在就覆盖pDoc -> save( " d:\\he.xml " );双击Load按钮,在消息处理函数中添加如下代码:MSXML2::IXMLDOMDocumentPtr pDoc;HRESULT hr;hr = pDoc.CreateInstance(__uuidof(MSXML2::DOMDocument40));if (FAILED(hr)){MessageBox( " 无法创建DOMDocument对象,请检查是否安装了MS XML Parser 运行库! " );return ;}// 加载文件pDoc -> load( " d:\\he.xml " );MSXML2::IXMLDOMNodePtr pNode;// 在树中查找名为Book的节点," // "表示在任意一层查找pNode = pDoc -> selectSingleNode( " //Book " );MSXML2::DOMNodeType nodeType;// 得到节点类型pNode -> get_nodeType( & nodeType);// 节点名称CString strName;strName = ( char * )pNode -> GetnodeName();// 节点属性,放在链表中MSXML2::IXMLDOMNamedNodeMapPtr pAttrMap = NULL;MSXML2::IXMLDOMNodePtr pAttrItem;_variant_t variantvalue;pNode -> get_attributes( & pAttrMap);long count;count = pAttrMap -> get_length( & count);pAttrMap -> get_item( 0 , & pAttrItem);// 取得节点的值pAttrItem -> get_nodeTypedValue( & variantvalue);m_strId = ( char * )(_bstr_t)variantvalue;UpdateData(FALSE);本文来自: 中国自学编程网() 详细出处参考:/html/20070611/22861.html。
VC+ANSI环境下按行读取ANSI、UNICODE+、UNICODE+big+endian、UTF-8四种文本文件

2012-04-19 20:07112人阅读评论(0)收藏举报VC ANSI环境下按行读取ANSI、UNICODE 、UNICODE big endian、UTF-8四种文本文件1.问题提出MFC提供的文件类CStdioFile,其中一个函数ReadString实现了文件的按行读取,但是不能满足不同类型的文本文件的按行读取,为了解决这一问题,笔者初步研究了一些编码知识,参考了网上的一些资料,实现了CStdioFile类的扩展类CStdioFileEx,完成了常见文本文件的按行读取(注明:不包括DOC、PDF等其他形式的文档).在此对网上分享编码经验的网友表示感谢,同时由于我编写的类还未经过严格测试,如有错误或方法过于复杂敬请各位指正。
2.问题解决(1)四种常见文本文件编码方式研究ANSI、UNICODE 、UNICODE big endian、UTF-8四种格式编码存在差别,简要介绍如下:ANSI编码:无文件头(文件编码开头标志性字节)ANSI编码字母数字占一个字节,汉字占两个字节,回车换行符单字节十六进制表示为0d 0aUNICODE编码:文件头,十六进制表示为FF FE每一个字符都用两个字节编码回车换行符双字节000d 000aUnicode big endian编码:文件头十六进制表示为FE FF ,后面编码是把字符的高位放在前面,低位放在后面,正好和Unicode编码颠倒。
回车换行符,双字节,十六进制表示为0d00 0a00UTF-8 编码:文件头,十六进制表示为EF BB BF。
UTF-8是Unicode的一种变长字符编码,数字、字母、回车、换行都用一个字节表示,汉字占3个字节.回车换行符,单字节,十六进制表示为0d 0a以中文"你好"二字为例,各种类型的编码对应的十六进制格式(可由EditPlus查看)如下图所示:由此可见上述的探讨是正确的。
(2)按行读取上述四种格式文本文件的解决方案针对不同文件编码的特点,通过先检测文件头判断文件编码类型,然后根据文件类型分别调用不同的读取函数实现文件的按行读取。
c++读取数据文件到数组的实例

c++读取数据文件到数组的实例摘要:1.介绍C++读取数据文件到数组的方法2.详细步骤说明3.代码实例及解析4.总结与拓展正文:C++作为一种广泛应用于计算机编程的语言,掌握如何读取数据文件到数组的方法对于编程初学者来说尤为重要。
本文将详细介绍C++读取数据文件到数组的方法,并通过一个简单的实例进行讲解。
一、介绍C++读取数据文件到数组的方法在C++中,我们可以使用文件流(fstream)来读取文件数据到数组。
文件流分为输入文件流(ifstream)和输出文件流(ofstream),在这里我们使用输入文件流来读取数据文件。
二、详细步骤说明1.包含头文件:首先,我们需要包含必要的头文件,如下所示:```cpp#include <iostream>#include <fstream>```2.声明变量:声明一个数组以及文件指针,如下所示:```cppint arr[100];ifstream file;```3.打开文件:使用文件流对象的open()函数打开文件,如下所示:```cppfile.open("data.txt", ios::in);```4.检查文件是否打开:使用文件流对象的is_open()函数检查文件是否成功打开,如下所示:```cppif (!file.is_open()) {std::cout << "文件打开失败!" << std::endl;return 1;}```5.读取文件数据到数组:使用文件流对象的read()函数读取文件数据到数组,如下所示:```cppfile.read(reinterpret_cast<char*>(arr), sizeof(arr));```6.关闭文件:在读取文件数据后,使用文件流对象的close()函数关闭文件,如下所示:```cppfile.close();```7.输出数组内容:使用循环输出数组中的内容,如下所示:```cppfor (int i = 0; i < sizeof(arr) / sizeof(arr[0]); ++i) {std::cout << arr[i] << " ";}```三、代码实例及解析以下是一个完整的C++代码实例,用于读取数据文件到数组:```cpp#include <iostream>#include <fstream>int main() {int arr[100];std::ifstream file("data.txt", std::ios::in);if (!file.is_open()) {std::cout << "文件打开失败!" << std::endl;return 1;}file.read(reinterpret_cast<char*>(arr), sizeof(arr));file.close();for (int i = 0; i < sizeof(arr) / sizeof(arr[0]); ++i) {std::cout << arr[i] << " ";}return 0;}```四、总结与拓展本文详细介绍了C++读取数据文件到数组的方法,并通过一个简单的实例进行讲解。
C技巧:VC读取和分析格式化文本配置文件

⼤多数的应⽤程序都有需要配置的参数,配置参数的保存有多种⽅法,⽐如采⽤数据库保存、⼆进制⽂件保存、格式化的⽂本⽂件保存,各有优缺点,对于⼀般⼩的安全性要求不⾼应⽤程序,推荐采⽤格式化⽂本⽂件保存⽅式,这样可以节约编辑修改的界⾯编程,使⽤记事本程序编辑即可。
早期的windows就是采⽤的INI格式⽂本⽂件。
现在很多应⽤程序包括⼤型的软件也还在采⽤格式化⽂本⽂件保存配置参数,⽐如Bentely MicroStation GIS平台GEOGRAPHICS8.0。
本⽂给出的就是利⽤VC来读取和分析配置⽂本⽂件,这是笔者这消防监控系统远程终端软件使⽤的⽅法。
同时给出⼀个C++类来封装配置⽂本⽂件的读取分析。
下⾯是我采⽤的配置⽂件的例⼦,包含单个参数定义,表格参数定义,注释: // 协议名称: TL // ⼯程: SQ // 配置⼈: JY #DEFINE_BEGIN //以下为常量定义 //通信参数 @COM_PORT \\\\.\\COM1 //COM⼝ @COM_BAUDRATE 1200 //波特率 @COM_BITSIZE 8 //数据位 number of bits/byte, 4-8 @COM_SBIT 0 // 0,1,2 对应 1, 1.5, 2 @COM_PARITY 0 //0-4对应no,odd,even,mark,space @STATIONNO 0 //终端号 @TCPIP_SERVERIP 192.168.0.10 //服务器IP地址 @TCPIP_PORTNO 3024 //端⼝ #DEFINE_END #TABLE_BEGIN //表格 //编号识别字符串 //例⼦如下 0 Ion Detector, ALU1, L1S43 //测量台2#离⼦烟感探测器报警 1 Thermal Det, ALU1, L1S39 //值班室温感探测器报警 #TABLE_END 语法解释: // 单⾏注释 #DEFINE_BEGIN 单个参数定义的开始标记 #DEFINE_END 单个参数定义的结束标记 #TABLE_BEGIN 表格参数开始标记 #TABLE_END 表格参数结束标记 单个参数的配置: 每个参数⼀⾏:以空格、TAB制表符作为分隔,注释可选,每⾏结束后有Enter键换⾏。
Visual-C++ 读取文本文件代码

<数据类型> <数组名>[常量表达式];
二维数组的声明方式如下: <数据类型> <数组名>[常量表达式] [常量表达式];
数组名后括号中的常量表达式表示数组的长度,即数组所 包含元素的数量。
例如. . .
数组声明语句: float score[30]; // 数组score有30个元素,其数据类型是float型 int Array[12][4]; // 数组Array有12×4个元素,其数据类型是int型
// 0.5用于四舍五入 // 使用if~else if语句
例 编写程序利用标准输入流接收用户从键盘输入的 数据,利用标准输出流将运算结果输出到屏幕。
#include <iostream.h> // 使用输入、输出流 void main(void) { cout<<"please enter the value of x , y , z :" ; // 输入提示 int x , y , z ; // 声明变量 cin>>x>>y>>z ; // 从键盘读取数据给变量x、y、z cout<<"The sum is "<<x+y+z<<'\n' ; // 输出结果 } 程序运行的结果为: please enter the value of x , y , z :2 4 6 The sum is 12
2.4.1 条件语句
包括if语句和switch语句,用于实现分支结构。 if 语句的一般形式: if(<表达式>) <语句> 如果表达式的值为真(非0),则执行其中的 语句(块),否则跳过该语句。 if语句的另一种形式: if(<表达式>)
如何在C++中实现文件的读取和写入

如何在C++中实现文件的读取和写入在C++中实现文件的读取和写入是一项非常基本且重要的任务。
利用这些功能,我们可以读取现有文件的内容,或者将数据写入到新的文件中。
在本文中,我将向您展示如何使用C++实现这些功能,并且会涵盖一些更高级的用法。
首先,让我们来看一下如何读取文件。
在C++中,我们使用`fstream`类来操作文件。
`fstream`类提供了一些方法,例如`open()`和`close()`,用于打开和关闭文件。
以下是读取文件的示例代码:```cpp#include <fstream>#include <iostream>int main() {std::ifstream file("example.txt"); //打开文件if (file.is_open()) {std::string line;while (std::getline(file, line)) {std::cout << line << std::endl; //打印每一行的内容}file.close(); //关闭文件}else {std::cout << "无法打开文件" << std::endl;}return 0;}```上述代码首先创建了一个`ifstream`对象,并使用`open()`方法打开名为"example.txt"的文件。
之后,我们使用`getline()`方法从文件中逐行读取内容,并将其打印到控制台。
最后,我们使用`close()`方法关闭文件。
接下来,让我们来看一下如何将数据写入文件。
同样地,我们使用`fstream`类来完成这个任务。
以下是将数据写入文件的示例代码:```cpp#include <fstream>int main() {std::ofstream file("output.txt"); //打开或创建一个文件if (file.is_open()) {file << "这是要写入文件的内容" << std::endl; //将数据写入文件file.close(); //关闭文件}else {std::cout << "无法打开文件" << std::endl;}return 0;}```上述代码中,我们创建了一个`ofstream`对象,并使用`open()`方法打开了一个名为"output.txt"的文件。
VC++中文件读写相关操作技巧
VC++中⽂件读写相关操作技巧CFile类的声明保存在afx.h头⽂件中。
CFile类是MFC⽂件类的基类,提供⾮缓冲⽅式的⼆进制磁盘输⼊、输出功能;并直接通过派⽣类来⽀持⽂本⽂件和内存⽂件。
提供访问本地⽂件内容的功能,不⽀持访问⽹络⽂件的功能。
CFile类的成员变量:m_hFile:表⽰⼀个打开⽂件的操作系统⽂件句柄。
通过对m_hFile 与 CFile::hFileNull的⽐较来判断该⽂件是否已经打开。
CFile类的成员函数:1、构造函数类CFile():在创建⼀个CFile对象时,我们可以采⽤3种⽅法实现。
A、CFile myFile;myFile.Open(LPCTSTR lpFileName,UINT nOpenFlags,CFileException * pError = NULL);B、CFile myFile(int hFile); 采⽤句柄⽅式创建使⽤该创建⽅法,在之前需要调⽤ CreateFile()函数,该函数的声明如下:HANDLE CreateFile(LPCTSTR lpFileName, ⽂件名称DWORD dwDesiredAccess, ⽂件访问的模式DWORD dwShareMode, ⽂件的共享模式LPSECURITY_ATTTRIBUTE lpSecurityAttribute,DWORD dwCreationDisposition, 怎么访问DWORD dwFlagsAndAttribute, ⽂件属性HANDLE hTemplateFile, 临时⽂件句柄);handle = ::CreateFile(“new.tmp”,GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_ALWAYS,FILE_FLAG_DELETE_ON_CLOSE,NULL);C、CFile(LPCTSTR lpFileName,UINT nOpenFlags); ⽂件名称,可以是相对路径,绝对路径或者⽹络路径。
基于VC6.0的24位真彩色图像读取与显示
基于VC6.0的24位真彩色图像读取与显示
摘要:在图像处理软件的设计中正确认识图像文件的结构至关重要。
对BMP图像的文件结构进行了系统介绍。
通过一个24位真彩色图像的实例,分析了真彩色图像的基本结构,给出了一种在VC6.0环境下读取与显示24位真彩色图像的方法。
关键词:BMP文件;24位真彩色图像;VC6.0
0 引言
随着输入输出设备的发展进步,以及人们对图像清晰度、图像色彩真实感的要求不断提高,针对真彩色图像处理的各类技术也在不断发展,而目前大多数文献以及参考资料都是对256色图像的处理,关于真彩色图像分析和处理的内容较少。
理解24位真彩色图像的结构,正确获得图像的数据信息,对于图像处理来说十分关键。
本文对24位真彩色图像的结构进行了系统的分析,并介绍在Visual C6.0下读取与显示真彩色图像的方法。
1 BMP图像文件结构
BMP格式的图像在Windows系统中比较常见,几乎所有的Windows应用程序都支持这种图像文件。
通常使用的BMP格式文件是一种与设备无关的位图DIB(Device Independnt Bitmap),它使用标准的Windows位图格式,包含颜色信息,并且可以在不同的机器或者系统中显示图像。
BMP图像一般包含文件头(BITMAPFILEHEADER)、信息头(BITMAPINFOHEADER)、调色
板(Palette)、位图数据(Data)四个部分。
BMP图像的文件格式如图1所示。
值得注意的是,24位真彩色图像不需要调色板,图像的信息头之后紧跟着的就是图像数据。
(1)位图文件头。
在wingdi.h中对位图的文件头结构有如下定义:。
c语言读取文件内容
c语言读取文件内容C语言读取文件内容。
在C语言中,我们经常需要读取文件的内容进行处理,比如配置文件、日志文件等。
下面我们就来学习一下如何在C语言中读取文件内容。
首先,我们需要使用C语言中的文件操作函数来打开文件。
我们可以使用fopen函数来打开一个文件,语法如下:```c。
FILE fopen(const char filename, const char mode);```。
其中,filename是要打开的文件名,mode是打开文件的模式,比如"r"表示只读,"w"表示只写,"a"表示追加写入等。
fopen函数会返回一个指向FILE类型的指针,我们可以通过这个指针来操作文件。
接下来,我们可以使用fgets函数来逐行读取文件内容,语法如下:```c。
char fgets(char str, int n, FILE stream);```。
其中,str是一个指向字符数组的指针,n是要读取的最大字符数,stream是指向FILE类型的指针。
fgets函数会读取文件中的一行内容,并将其存储到str指向的字符数组中。
另外,我们也可以使用fscanf函数来按照指定的格式来读取文件内容,语法如下:```c。
int fscanf(FILE stream, const char format, ...);```。
fscanf函数可以按照指定的格式从文件中读取内容,并将其存储到对应的变量中。
比如,我们可以使用%f来读取一个浮点数,%d来读取一个整数等。
在读取文件内容之后,我们需要使用fclose函数来关闭文件,以释放资源,语法如下:```c。
int fclose(FILE stream);```。
fclose函数会关闭由stream指向的文件,并释放相关的资源。
总结一下,我们可以通过fopen函数打开文件,然后使用fgets或者fscanf函数来读取文件内容,最后使用fclose函数关闭文件。
c++以行为单位读取文件
c++以行为单位读取文件张小强2012年11月qq:1532589421有的时候处理文本类型文件需要一行为单位进行处理,方法有很多种,我现在给大家提供一个应用stl库处理,得到结果保存在vector中。
我所提供的代码,直接拷贝下来写入头文件和源文件中,再include进您自己的工程就可以了,绝对方便使用。
头文件:#ifndef READFILEBYROW_H_H_H#define READFILEBYROW_H_H_H#include <stdio.h>#include <vector>#include <string>std::vector<std::string> ReadFileByRow(const std::string &filePath);#endif源文件#include "stdafx.h"#include "ReadFileByRow.h"std::vector<std::string> ReadFileByRow(const std::string &filePath){FILE *pFile;if((pFile=fopen(filePath.c_str(),"r"))!=NULL){char *pBuf,*p;fseek(pFile,0,SEEK_END);int len=ftell(pFile);pBuf=new char[len];rewind(pFile);memset(pBuf,0,len);std::vector<std::string> temp;while (1){p=fgets(pBuf,len,pFile);std::string str(pBuf);temp.push_back(str);if (!p){break;}}fclose(pFile);delete pBuf;return temp;}else{printf("文件无法读取!");fclose(pFile);std::vector<std::string> temp;return temp;}}使用指南:函数接口std::vector<std::string> ReadFileByRow(const std::string &filePath); 使用时传递string类型的文件路径,返回string的vector。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
第23卷第2期湖 北 工 业 大 学 学 报2008年4月Vol.23No.2 JournalofHubeiUniversityofTechnologyApr.2008
[收稿日期]2007-12-01[作者简介]张贞贞(1982-),女,湖北枣阳人,武汉理工大学硕士研究生,研究方向:计算机辅助设计与仿真.
[文章编号]1003-4684(2008)02-0044-03基于VC的STL文件读取
张贞贞1,陈定方2(1武汉理工大学计算机科学学院,湖北武汉430063;2武汉理工大学物流工程学院,湖北武汉430063)
[摘 要]就CAD系统较常用文件格式STL的快速读取问题展开讨论,分析了STL两种文件格式的特点,并讨论了冗余数据的消除.[关键词]STL文件;ASCÒ;二进制[中图分类号]TP391[文献标识码]:A
STL(StereoLithographyinterfacespecifica-tion)文件格式[1]最初出现于1989年美国3DSYS-TEM公司生产的SLA快速成型系统,是一种应用于CAD模型与成型系统之间数据转换的文件格式,现在已为大多数CAD系统和快速成型系统制造商所接受和采用,并且已经在快速成型技术领域中被誉为工业标准.本文旨在研究如何高效率读取STL文件.
1 STL文件格式的结构STL类似于实体数据模型的表面有限元网格划分.STL模型的数据通过给出组成三角形法向量的3个分量及三角形的3个顶点坐标来实现,STL文件记载了组成实体模型的所有三角形面片的法向量数据和顶点坐标数据,有文本文件(ASCII)和二进制文件(BINARY)两种格式.1.1 STL的ASCII文件格式ASCÒ码格式STL文件逐行给出三角面片的几何信息,每一行以1个或2个关键字开头.在STL文件中的三角面片的信息单元facet是一个带矢量方向的三角面片,STL模型就是由一组这样的三角面片构成.在一个STL文件中,每一个facet由7行数据组成,第1行是三角面片指向实体外部的法向失量数据,第2行说明随后的第3,4,5行数据分别是三角面片的3个顶点信息,沿指向实体外部的法向矢量(第1行数据)方向逆时针排列.ASCÒ[2]格式的STL文件结构如下:solidfilenamestlM文件路径及文件名facetnormalxyzM三角面片法向量的3个分量值outerloopvertexxyzM三角面片第一个顶点的坐标vertexxyzM三角面片第二个顶点的坐标vertexxyzM三角面片第三个顶点的坐标endloopendfacetM第一个三角面片定义完毕,,,,,,endsolidfilenamestlM整个文件结束1.2 STL的二进制文件格式二进制STL文件用固定的字节数来给出三角面片的几何信息.文件的起始80字节是文件头存储零件名,可以放入任何文字信息;紧随着用4个字节的整数来描述实体的三角面片个数,后面的内容就是逐个给出每个三角面片的几何信息.每个三角面片占用固定的50字节,它们依次是3个4字节浮点数,用来描述三角面片的法矢量;3个4字节浮点数,用来描述第1个顶点的坐标;3个4字节浮点数,用来描述第2个顶点的坐标;3个4字节浮点数,用来描述第3个顶点的坐标,每个三角面片的最后2个字节用来描述三角面片的属性信息(包括颜色属性等)暂时没有用.一个二进制STL文件的大小为三角形面片数乘以50再加上84个字节.比较这2种方式可知,二进制格式文件较小(通常是ASCÒ码格式的1/5)[3],节省存储空间,但ASCÒ码格式的文件可读性更强,能被人工识别并被修改.2 STL文件的读取与显示STL文件是由一系列的三角形面片无序排列组合在一起的,没有反映三角形面片之间的拓扑关系,而且每一个小三角形面片必须与相邻的三角形面片共用2个顶点,每个顶点通常被重用6次左右,文件数据重复很多,造成了STL文件在读取、存储等方面的效率问题.本文研究了如何消除冗余数据并快速读取STL文件,这对于后续三维图形的现实,是一个重要和基本的环节.去除冗余点的实质是,从STL文件中依次取出三角形,通过比较三角形顶点的坐标值,归并重复的点,从而建立一个无重复点的点表,去除冗余点最直接的方法就是比较法.对于新的顶点,读进来时依次对X坐标、Y坐标和Z坐标进行比较,且保证所有顶点依次按照X坐标、Y坐标和Z坐标排序.这样大大减少了查找范围,提高了排序和插入的效率,采用上述分析方法建立点表,有3个步骤:第一步,按三角形为单元,从文件中读入该三角形的3个顶点,逐点进行比较.第二步,判断该顶点是否已经在点表中存在,1)进行X坐标的比较.a)X坐标相同的顶点不存在,转入第三步.b)X坐标相同的顶点存在,转入2).2)在所有X坐标相同的顶点中,比较Y坐标.a)Y坐标相同的顶点不存在,转入第三步.3)Y坐标相同的顶点存在,转入4).4)在所有X坐标和Y坐标都相同的顶点中,比较Z坐标.a)Z坐标相同的顶点不存在,转入第三步.b)Z坐标相同的顶点存在,说明该顶点已经在存在于点表中所以新的顶点不加入点表中.第三不,向点表中插入新的顶点,同时完成排序.这样建立无冗余点的点表,效率很高,而且在搜索比较的同时,具有相同坐标值(X、Y或Z)的顶点自动排在一起,实现了自动分段功能,提高了后续搜索效率,实现上面的步骤.为实现上述步骤使用的VisualC++数据结构如下:structVertex{doublex;M顶点的X坐标值doubley;M顶点的Y坐标值doublez;M顶点的Z坐标值vertex*x_same;M指向X坐标值相同的下一个顶点vertex*y_same;M指向X坐标和Y坐标值都相同的下一个顶点vertex*next;M指向X坐标值不相同的下一个顶点}vertex;structFacet{doublex;M面片法向量的X坐标值doubley;M面片法向量的Y坐标值doublez;M面片法向量的Z坐标值vertex*vertex1;M指向该面片的第一个顶点vertex*vertex2;M指向该面片的第二个顶点vertex*vertex3;M指向该面片的第三个顶点}facet;使用上述方法对所读入的STL文件进行处理后,去除冗余点的同时也建立了点表,表中坐标值X升序排列,而每个X值后有一个或多个Y值,其中Y值也按升序排列;同理,每个Y值后有一个或多个Z值,其中Z值也是按升序排列的.图1给出了点表形成后的逻辑结构图.
图1 点表的逻辑结构图如图1所示,所有顶点以多重链表[4]形式连接:顶点v1,v2,v3,v4形成的链中各自的X坐标值互不相同;v1,v5,v8形成的链中各自的X坐标相同,Y坐标互不相同;v5、v7形成的链中各自的X坐标和Y坐标都相同,Z坐标不同;v2、v6形成的链类似于v5、v7
形成的链,其中各自的X坐标和Y坐标都相同,Z坐
标不同.此外,由结构体facet形成的链表(面表)记录了每个面片的法向量以及它的3个顶点的信息,使得面表和点表联系在一起,后续要显示三维图形时顺序读取面表,通过面表间接在点表中找到各顶点.这样,整个STL文件所有三角面片的数据可由facet结构的一个数组m_facet来记录.为实现动态存储,该数组定义如下:CArraym_facet;用指针vertex*head作为点表的头指针,判断一个顶点是否在点表中存在具体算法如下:vertex*Sort(vertex*v,vertex*head){vertex*p;veretex*q;M链表为空时插入点v
if(head==NULL){head=v;returnv;}else{p=head;q=NULL;while(p){if(v->x==p->x){M在X坐标值相同的链中查找
while(p){if(v->y==p->y){M在X,Y坐标值都相同的链中查找
while(p){M点表中已存在点v,返回其位置
if(v->z==p->z){returnp;}else{M在X,Y坐标值相同的链中查找并插入点vif(v->z>p->z){q=p;p=p->y_same;}
45 第23卷第2期 张贞贞等 基于VC的STL文件读取else{if(q==NULL){head=v;}else{if(q->next==p){q->next=v;}if(q->x_same==p){q->x_same=v;}if(q->y_same==p){q->y_same=v;}}v->y_same=p;v->x_same=p->x_same;p->x_same=NULL;v->next=p->next;p->next=NULL;returnv;}}}if(p==NULL){q->y_same=v;returnv;}}else{M在X坐标值相同的链中查找并插入点vif(v->y>p->y){q=p;p=p->x_same;}else{if(q==NULL){head=v;}else{if(q->next==p){q->next=v;}if(q->x_same==p){q->x_samev;}}v->x_same=p;v_next=p->next;p->next=NULL;returnv;}}}if(p==NULL){q->x_same=v;returnv;}}else{M在X,Y,Z坐标值均不同的链中查找并插入点vif(v->x>p->x){q=p;p=p->next;}else{if(q==NULL){head=v;}else{q->next=v;}v->next=p;returnv;}}}if(p==NULL){q->next=v;returnv;}}}然后读取ASCÒ形式的STL文件,存储文件
信息,具体算法如下:BOOLLoadSTLFile(LPCTSTRstlfile){FILE*file;if((file=fopen(stlfile,"r"))==NULL)returnfalse;charstr[80];vertex*v1,v2,v3;facet*f;while(fscanf(file,"%s",str)==1){if(strncmp(str,"normal",6)==0){v1=(vertex*)malloc(sizeof(vertex));v2=(vertex*)malloc(sizeof(vertex));v3=(vertex*)malloc(sizeof(vertex));f=(facet*)malloc(sizeof(facet));M读取面片的法向量
fscanf(file,"%1f%1f%1f",&(f->x),&(f->y),&(f->z));fscanf(file,"%*s%*s");M读取面片的三个顶点信息到v1,v2,v3