SAP84数据库文件接口说明与DLL支持

SAP84二次开发概述

本文档专门用于SAP84的二次开发，普通用户可以不必关心。若要对SAP84进行二次开发，用户一般需要了解以下内容，并且最好是采用C++语言（采用其它语言的工作量稍微大一点）：

  1. SAP84输入数据文件。此文件为文本文件，具体格式可以参考SAP84高级用户手册；

  2. SAP84数据库文件。文件格式和读取方式详见本文档；

  3. SAP84分析模块产生的结果文件。文件格式和读取方式详见本文档；

  4. SAP84计算和分析模块的调用方法。具体可参考本文档；

  5. SAP84型钢截面字符串的处理。具体可参考本文档；

  6. 其它内容。可以与SAP84开发小组联系。

用户在对SAP84进行二次开发时一般有如下几种情况：

  1. 如果用户希望独立开发自己的图形前后处理，仅仅利用SAP84的分析功能，用户可以在自己的前处理中产生SAP84输入数据文件，然后调用SAP84计算和分析模块，最后读取分析结果。SAP84提供了一些C++类简化后面两个步骤。

  2. 如果用户仅仅开发图形前处理，希望利用SAP84的分析功能和后处理功能，用户可以在自己的前处理中产生SAP84输入数据文件，并且最好能同时产生SAP84数据库文件（不产生也可，但这样会削弱SAP84图形后处理的功能），然后通过SAP84的集成环境系统对产生的数据文件进行计算与分析，并调用图形后处理。（注：也可以直接调用SAP84计算和分析模块，并启动SAP84后处理）。

  3. 如果用户仅仅开发图形后处理，希望利用SAP84的分析功能和前处理功能，用户需要读取SAP84图形交互系统产生的数据库文件和分析模块产生的结果文件。

  4. 如果希望利用SAP84的后处理功能，为自己的计算程序服务，可以产生类似SAP84分析模块的结果文件，详细可参考分析程序产生的结果文件一节。其中扩展名为“SYS”、“ID”、“XYZ”和“PL”的结果文件是最基本的四个必须文件，其余文件可根据需要增加。

  5. 如果用户希望利用SAP84的图形交互系统为自己的计算程序服务，可以与我们联系，然后讨论相关事宜。


数据库文件概述

SAP84数据库文件的扩展名一般为D84，该数据库并不是一个真正意义上的数据库系统，而只是一个格式很有规律的文件， 为方便数据库文件的读写和实现代码的共享，我们建立了一些基本的类，有些类你可能需要做进一步的继承（主要是单元类，例如DFrameBase<DSframeBase>等），而有些类可能不需要继承（例如：DFrameSect、DFrameLoad和DMaterial等）。 实现这些类库的相关文件如下（C++语言，最好是VC环境）：

SAP84lib.lib、SAP84lib.dll、sap84.h、fileio.h、array.h、classlib.h

用户二次开发时需要连接sap84lib.lib库，并包含头文件sap84.h，该文件会自动包含其余三个头文件。


SAP84数据库文件结构说明：

在建立SAP84数据库文件的数据结构时既要考虑其兼容性，同时又要考虑其扩充性，为此采用了下面的数据存储结构，这种数据存储方式以数据段为基本单元，每个数据段之间是相互独立的，也没有一定的顺序要求，它既适合于类的操作，又适合于传统C语言的操作，具有很大的灵活性和可扩充性。这里假设编译器接受：1个字节的char，2个字节的short，4个字节的int和long，4个字节的float和8个字节的double。

SAP84数据库文件的数据存储结构可描述为：

SAP84数据库文件标识串

版本号

数据段1

数据段2

.......

数据段n

SAP84数据库文件标识串：

必须是“SAP84DATA”+C语言中表示字符串结束的空字符‘\0’，总共10个字节， 字符必须大写 ；

版本号：

用一个两字节的short表示，最低版本号为100，表示版本1.00，125表示版本1.25；

数据段n：

数据段目前可以分为两类，一类是普通数据段，另一类是数组形式的数据段。一个具体的数据段是属于普通数据段还是数组形式的数据段，由数据段前面的引导字符串决定。

普通数据段的逻辑结构描述如下：

引导字符串 | 数据区占的字节数 | 数据区
八个字符加一个结束符'\0'，共9个字节 | 一个int整数，字节数不包括引导字符串和本身4个字节 | 该数据一般由一个类封装，可以调用相关类的Serialize()函数可实现数据的存取

数组形式的数据段的逻辑结构描述见下表，数组的类型一般可以用一个类来描述，然后用一个可变数组类来封装整个数组，目前SAP84数据库文件所支持的类库可以见后续表格。例如，目前提供了类DFrameBase<DSframeBase>封装框架单元的基本数据，你可以用MArrayID<DFrameBase<DSframeBase> >封装所有框架单元的数据，MArrayID提供了成员函数Serialize()用于存取数组的所有数据，该函数通过调用DFrameBase类的成员函数Serialize()实现。一般说来你需要在DFrameBase的基础之上继承一个新的类，例如class CFrame: public DFrameBase，然后用MArrayID<CFrame>封装框架单元数据，CFrame类不能重新定义Serialize()成员函数，如果CFrame还有自己的数据成员，这些数据成员的存取由你自己负责，如果你觉得某些数据非常重要，最好能放在DFrameBase中为大家所共用，可以向我们提出你的建议。

引导字符串 | 数据区占的字节数 | 数据区（n个元素的数组） 可以通过调用可变数组类的Serizlize()实现数据存取
 |  | 元素个数 | 第1个元素 | 第2个元素 | … | 第n个元素
八个字符加一个结束符'\0'，共9个字节 | 一个int整数，字节数不包括引导字符串和本身4个字节 | 4字节的整数，等于n | 相关数据由描述数组类型的类封装，调用类的Serialize()函数可实现数据的存取 | 相关数据由描述数组类型的类封装，调用类的Serialize()函数可实现数据的存取 | … | 相关数据由描述数组类型的类封装，调用类的Serialize()函数可实现数据的存取

这种分段式的存储结构具有很强的可扩充性，各段之间有很强的独立性，Serialize()的实现使数据具有一定的隐蔽性，随着数据库文件版本的发展，数据区内部的数据格式可能有所变化，这些变化统一由Serialize()根据版本号处理，外界无需关心数据格式的变化。

数据库文件目前支持的引导字符串可以参考“引导字符串和基本类库”一节，而相应数据区和数据区内的元素的格式需要参考引导字符串对应C++类的Serialize()成员函数的实现代码。


存取数据库文件方法概述：

读取文件时首先定义变量bifstream fin（"filename"）封装SAP84数据库文件，然后调用int fin.ReadHeader()，如果返回值非零则接着读取各数据段，读取各数据段的方法为：先读取9个字节的引导字符串，如果您不需要该数据段的数据，可以接着读入一个4字节的整数nSize，然后调用fin.Seek(nSize,SEEK_CUR)跳过相应数据；如果您需要该数据段的数据，请先跳过4个字节，然后调用相关类的Serialize(fin)成员函数读取数据。

写入文件时首先定义变量bofstream fout（"filename"）封装SAP84数据库文件，然后调用fout.WriteHeader()，接着写入各数据段，写数据段的方法为：先写入9个字节的引导字符串，然后调用fout.BeginSection()，接着调用相关类的Serialize(fout)成员函数写入该段的数据，最后调用fout.EndSection()结束该数据段，BeginSection和EndSection负责在9个引导字符串之后写入一个4字节的整数，该整数代表该数据段的数据（不包含引导字符串和这个整数本身）所占的字节数。


CLASS_DECLSPEC的含义

在产生DLL和使用DLL过程中需要导出和导入C++类，它们分别使用C++关键字__declspec(dllexport)和__declspec(dllimport)，
为了在同一头文件中既实现导出又实现导入，特定义宏CLASS_DECLSPEC，其定义如下：
#ifndef CLASS_DECLSPEC
#ifdef SAP84LIB_EXPORTS
   #define CLASS_DECLSPEC    __declspec(dllexport)
#else
   #define CLASS_DECLSPEC    __declspec(dllimport)
#endif
#endif
此外还定义了其它一些宏：
#define DXMASK 0x01		// 节点约束在nRest中对应位的掩码
#define DYMASK 0x02		// nRest&DXMASK!=0表示DX被约束
#define DZMASK 0x04
#define RXMASK 0x08
#define RYMASK 0x10
#define RZMASK 0x20
#define PI_2 1.5707963267948966192313216916398
#define PI 3.1415926535897932384626433832795
#define PI3_2 4.7123889803846898576939650749193
#define PI2 6.283185307179586476925286766559
#define DEG_RAD 0.017453292519943295769236907684886		// 度转换成弧度的系数
#define RAD_DEG 57.295779513082320876798154814105		// 弧度转换成度的系数
#define DBERROR 1.0E-10
#define FLOATERROR 1.0E-5
typedef double ARRAY3[3];
// 版本历史：100,110,111,120,121,125,127,128,129
// 当前支持的最高的版本号, 写入的时候是用此版本号, 以后更新版本必须更改这里的初始化值
#define SUPPORTVERSION 129	  // 此数可能会发生变化

用户一般说来不需要关心上述的宏定义。


DLL全局变量的说明：

在二次开发的头文件中包含了一些全局变量：

__declspec(dllimport) double LoadError = 1.0E-4 // 荷载参数相等的允许误差

__declspec(dllimport) double MaterialError = 1.0E-3 // 材料参数相等的允许误差

__declspec(dllimport) double SectionError = 1.0E-4 // 截面参数相等的允许误差

__declspec(dllimport) double NodeMinDist = 0.0001; // 节点坐标相等的允许误差

__declspec(dllimport) double MassSpringError = 1.0E-4; // 节点集中质量和刚度相等的允许误差

__declspec(dllimport) short nVersion; //版本号，读取时需要使用

__declspec(dllimport) const char * strSap84Header; // ==”SAP84DATA”

应用程序可以（应该）使用这些变量，也可以对其更改和保存（由应用程序员负责），如果你读取SAP84数据库文件时，没有调用bifstream::ReadHeader()，那你必须设置好变量nVersion否则各类的Serialize()可能出错，因为Serialize()需要根据nVersion确定SAP84数据库文件的格式。当前 类库支持的最高版本号由宏SUPPORTVERSION确定。


可变数组的支持：

array.h中提供了三个模板类用以支持各种形式的可变数组：class MArray<class TYPE>、class MArraySort<class TYPE>和class MArrayID<class TYPE>，它们都是class MArrayBase<class TYPE>的公有继承类。

MArrayBase采用索引的方式来存储数组，其保护成员MMemBlock<TYPE> ** m_ppVectBlock用来保存数组的所有元素，m_ppVectorBlock[i]负责管理grow（由类的构造函数决定）个数组大小的存储空间，每次申请或释放内存时都是以grow个元素所占的存储空间为基本单位，MArrayBase的保护成员int * m_pIndex用来保存第i个元素在m_ppVectBlock中的逻辑地址，即各元素的索引。

MArray用来支持按插入顺序存储的可变数组，而MArraySort用来支持按增序排列的数组，它要求class TYPE定义了operator <(const TYPE & other)成员函数。MArray和MArraySort第i个元素的逻辑地址存放在m_pIndex[i-1]中，元素的删除涉及到m_pIndex的移动，不涉及到元素数据本身的移动，MArraySort类要插入新的元素时也涉及到m_pIndex的移动。

MArrayID要求class TYPE有公有数据成员int nID（或short nID），同一数组各元素的nID不能相同，元素TYPE ele的逻辑地址存放在m_pIndex[ele.nID-1]中，元素的插入和删除都不涉及数据的移动，速度非常的快，通过ele.nID检索的速度也非常的快，为了提高依次检索（检索第i个元素，i从0到n-1，n为数组的长度）所有数据元素的速度，在MArrayID中增加了保护数据成员int m_nCurI, m_nCurIndex，用以表示前一次检索的元素，下一次检索只需在前一次的基础之上做一定偏移就可以了。

使用以MArrayBase为基类的MArray，MArraySort和MArrayID类的数组元素类必须提供下列成员函数：
default constructor ( TYPE::TYPE() )
copy constructor ( TYPE::TYPE( const TYPE & ) )
assign operator （TYPE & operator = ( const TYPE & ) ）
int operator ==( const TYPE & ) const或友员函数 int operator ==( const TYPE &, const TYPE & )
如果需要序列化则必须定义函数，同时还需要定义宏_SERIALIZE和
void Serialize( bifstream & fin );
void Serialize( bofstream & fout );

若使用MArraySort还必须另外提供下面的成员函数：
int operator <( const TYPE & ) const或友员函数int operator <( const TYPE &, const TYPE & )

若使用MArrayID类，数组元素类不需要定义int operator <(...)但是类必须有公有数据成员int nID和成员函数int operator ==( const TYPE & )

MArray中的元素是按插入的顺序存放的，而MArraySort中的元素是按升序排列的


辅助数据类型类

一些起辅助作用的数据类型类：

类名 | 说明 | 使用该简单数据类的类
DElementLoad | 为了定义单元荷载信息L=L1 L2 ...，可通过[]引用各组数据，ld[i].Global和ld[i].LocalID，分别用来定义单元荷载所在荷载种类号（载荷种类）和该单元荷载的nID号（一般指向单元的荷载类） | DS16Base、DShellBase、DThreedBase、DCframeBase、DFrameBase、DNodeBase、DPlaneBase、DSol21Base、DSol8rBase、DVframeBase和DWallBase
DNumFactors | 定义各荷载种类（振型或地震方向下）的系数，如，各荷载种类下的组合系数等 | DCombFactor、DHistory、DCommonData、DNodeDisplacement、DSpectrum
DTightWireIndex | 框架单元中的预应力钢索号和作用情况 | DFrameBase
DLoadPoints | 描述一维单元的跨内折线分布荷载、集中力或集中弯矩荷载，成员Pos[i]表示该集中荷载作用点离I端的绝对距离，Val[i]表示此作用点的荷载值 | DCframeLoad和DFrameLoad（DVframeLoad）
DWeightFactor | 描述各荷载种类下的自重乘子，成员Value[i][0]、Value[i][1]、Value[i][2]表示自重在X、Y、Z三个方向的乘子，Global表示对应的荷载种类号 | DCommonData
DDataSection | 存储所有的引导字符串常量 | 读写数据库文件时需要用到
bofstream | 从ofstream类继承过来，可以直接用operator <<( )函数，以二进制的方式把各种简单数据类型的变量存入文件 | 所有需要负责存储的类
bifstream | 从ifstream类继承过来，可以直接用operator >>( )函数，以二进制的方式把各种简单数据类型的变量从文件读入 | 所有需要负责读取的类


引导字符串和基本类库

目前SAP84数据库文件有效的引导字符串和对应的C++类见下表：

引导字符串分类 | 引导字符串 (所有字符串作为静态成员存储在一个类中) | 数据封装的类 |  | 数据说明 | GIS能否导入和导出
 |  | 数组类型，数组形式的数据段 （即实现单个元素的类，绝大部分要求有nID数据成员） | 非数组类型，对应普通数据段
楼层和图层信息 | LEVELINF | DLevelBase |  | 有关高层的信息 | √
 | LAYERINF | DLayerBase |  | 有关图层的信息 | √
材料数据 | MATERIAL | DMaterial |  | 所有单元共享 | √
预应力钢索 | FRAMETIW | DTightWire |  | Frame单元和Vframe单元需要 | √
LSPRING | NODESPRI | DNodeSpring |  | 节点接地弹簧和连接弹簧 | √
Node节点数据 | NODEELEM | DNodeBase |  | 节点信息 | √
 | NODEMASS | DNodeMass |  | 节点集中质量 | √
 | NODEDISP | DNodeDisplacement （没有nID数据成员） |  | 节点任意方向的指定位移节 | √
 | NODELOAD | DNodeLoad |  | 点集中力 | √
 | NODECONS | DNodeConstraint （没有nID数据成员） |  | 节点自由度强制约束信息，即SAP84的CONSTRAINT数据段 | √
Frame单元数据 | FRAMEELE | DFrameBase |  | 框架单元信息 | √
 | FRAMESEC | DFrameSect |  | 框架单元截面信息 | √
 | FRAMELOA | DFrameLoad |  | 框架单元跨内荷载信息 | √
SFrame单元数据 | SFRAMELE | DSframeBase |  | 钢框架单元信息 | √
 | SFRAMSEC | DSframeSect |  | 钢框架单元截面信息 | √
 | SFRAMLOA | DSframeLoad (typedef DFrameLoad DSframeLoad;) |  | 钢框架单元跨内荷载信息 | √
Truss单元数据 | TRUSSELE | DTrussBase |  | 桁架单元信息 |
 | TRUSSSEC | DTrussSect (typedef DFrameSect DTrussSect;) |  | 桁架单元截面信息，它与框架单元截面信息用的是同一个类 |
Cframe单元数据 | CFRAMELE | DCframeBase |  | 曲梁单元信息 |
 | CFRAMSEC | DCframeSect (typedef DFrameSect DCframeSect;) |  | 曲梁单元截面信息，它与框架单元截面信息用的是同一个类 |
 | CFRAMLOA | DCframeLoad |  | 曲梁单元跨内荷载信息 |
Vframe单元数据 | VFRAMELE | DVframeBase (#define DVframeBase DFrameBase) |  | 变截面梁单元信息 | √
 | VFRAMSEC | DVframeSect |  | 变截面梁单元截面信息 | √
 | VFRAMLOA | DVframeLoad (typedef DFrameLoad DVframeLoad;) |  | 变截面梁单元荷载信息 | √
Pipe单元数据 | PIPEELEM | DPipeBase |  | 管道单元信息 |
 | PIPESECT | DPipeSect |  | 管道单元截面信息 |
Plane单元数据 | PLANEELE | DPlaneBase |  | 平面单元信息 | √
 | PLANELOA | DPlaneLoad |  | 平面单元单元荷载信息 | √
Threed单元数据 | THREEELE | DThreedBase |  | 8节点非协调元信息 |
 | THREELOA | DThreedLoad (typedef DSol21Load DThreedLoad;) |  | 8节点非协调元荷载信息 |
Sol21单元数据 | SOL21ELE | DSol21Base |  | 4-21节点等参元信息 | √
 | SOL21LOA | DSol21Load |  | 4-21节点等参元荷载信息 | √
Sol8r单元数据 | SOL8RELE | DSol8rBase |  | Sol8r带旋转自由度非协调元信息，包括今后要增加的三棱柱单元 | √
 | SOL8RLOA | DSol8rLoad (typedef DSol21Load DSol8rLoad;) |  | Sol8r带旋转自由度非协调元荷载信息 | √
S16单元数据 | S16ELEME | DS16Base |  | 16节点非协调元信息 |
 | S16LOADE | DS16Load (typedef DSol21Load DS16Load;) |  | 16节点非协调元荷载信息 |
Shell单元数据 | SHELLELE | DShellBase |  | 板壳单元信息 | √
 | SHELLLOA | DShellLoad |  | 板壳单元荷载信息 | √
Wall单元数据 | WALLELEM | DWallBase |  | 墙单元信息 | √
 | WALLLOAD | DWallLoad |  | 墙单元荷载信息 | √
各类型单元第一部分数据的公共部分以及各类型单元第一部分数据中与荷载种类有关的数据 | COMMDATA |  | DCommonData | 存放平面单元类型、高斯积分阶数、采用的单位系统、是否进行整体稳定性计算。重力荷载和温度荷载在各个荷载种类下的载荷因子，即sap84数据文件中各单元第一部分数据的X=X1 X2 ...Xnl Y=... Z=... T=...，各单元信息中不再保留相关信息。另外还包括轴对称平面单元中各荷载种类下对应的角速度和角加速度。 | √
地震反应谱数据 | SPECDATA |  | DSpectrum | 地震反应谱的一些数据和抗震等级 | √
 | SPECTDIR | DSpectrumDir （没有nID数据成员） |  | 地震方向的数据 | √
 | SPECCURV | DSpectrumCurve |  | 用户自定义的地震反应谱曲线 | √
固有振型分析 | EIGENCOM |  | DEigen | 特征值分析的一些参数，只能同时支持子空间迭代法、Ritz向量法和Lanczos法中的一种 | √
配筋信息 | REINCOMM |  | DReinforce | 有关配筋的一些信息 | √
内力组合 | FORCECOM | DCombFactor （没有nID数据成员） |  | 如果只填写了一个数据段，另一个数据段跟它一样；如果都没有填，组合系数取静力和地震反应谱的单位对角矩阵 | √
位移组合 | DISPCOMB |  |
时程分析数据 | HISTCOMM |  | DHistory | 动力分析的总体控制参数，适用于DYNAMIC或STEP，支持阻尼的数据 | √
 | HISTCURV | DHistoryCurve |  | 定义荷载-时间函数或地面运动加速度曲线 | √
 | HISTLOAD | DHistoryLoad （没有nID数据成员） |  | 荷载的空间分布，节点的初位移、初速度、初加速度。适用于DYNAMIC或STEP | √

所有数据之间的索引都通过类的公用数据成员nID建立，有的nID（如封装单元、单元跨内荷载、节点集中力、节点集中刚度和集中质量等数据的类的nID）为4字节的int，而另外一些nID（如封装反应谱曲线、时程分析的荷载-时间曲线、截面、材料、层号和图层号等数据的类的nID）则为2字节的short。同一数组的所有元素的nID不能有相同的，并且必须大于零，数组存取时并不一定要求按nID的升序排列，如果你使用MArrayID类来实现可变数组，存取结果是升序的。对于没有nID的类的数组可以采用MArray来实现。


基本类库使用说明

如何利用基本类库和可变数组来建立合理的数据变量，使它能与SAP84数据库文件的结构相配合？

为了说明具体的使用办法，这里以框架和钢框架单元为例说明单元数据的组织方法，通过这个例子 用户可以了解如何使用MArrayID来处理有nID的类的数组：

  1. 定义楼层和图层数据变量。这部分数据为所有单元和节点共享。如果用户觉得DLevelBase或DLayerBase所定义的数据和函数成员不够用，可以在此基础之上继承一个新类CLevel或CLayer：

MArrayID<DLevelBase> Level;

  // 定义层数据，每个层都有一个标高
MArrayID<DLayerBase>
  Layer;
  // 定义图层数据，一个图层相当于一个集合，
// 它可以包括单元或节点

  2. 以DSframeBase为基定义一个新类CSframe，用以支持钢框架 （钢梁柱）单元SFRAME：

class CSframe:public DSframeBase {
public:
unsigned char nSelected; // 本单元是否被选中，在图形操作时经常使用 , 一般所有单元都需要增加该变量
...... // 其它新增的数据变量

public:
void Display();
  // 负责该单元的显示，一般说来单元荷载的显示也可以放在此函数中，
};

  3. 以DFrameBase为基定义一个新类CFrame，用以支持框架 （梁柱）单元FRAME：
    [ 注：DFrameBase是一个模板类，它的基类必须是DSframeBase的子类，下面的例子直接以CSframe作为基类，通过这种方式CFrame类可以继承上面定义的CSframe的成员变量和函数，如果需要修改某些函数，可以通过重载实现 ]

    class CFrame:public DFrameBase<CSframe> {
    public:
    ...... // 其它新增的数据变量

    public:
void Display();
  // 负责该单元的显示，一般说来单元荷载的显示也可以放在此函数中，
};

  4. 定义与框架和钢框架单元相关的数据变量。

MArrayID<DMaterial>  Material;
  // 所有单元材料数组
MArrayID<CFrame> Frame;
  // 框架单元数组
MArrayID<DFrameSect> FrameSect;
  // 框架单元截面数组
MArrayID<DFrameLoad> FrameLoad;
  // 框架单元跨内荷载数组
MArrayID<DTightWire> TightWire;
  // 框架单元的预应力钢索数组
MArrayID<CSframe> Sframe;
  // 钢框架单元数组
MArrayID<DSframeSect> SframeSect;
  // 钢框架单元截面数组
MArrayID<DSframeLoad> SframeLoad;
  // 钢框架单元跨内荷载数组

  4. 如何保存层、图层、框架和钢框架单元数据：

先打开一个文件用于保存数据：bofstream fout("filename.d84");
首先写入SAP84数据库文件标识串和版本号：fout.WriteHeader();
保存层和图层的数据：
fout.Write(DDataSection::LevelStr,9);
fout.BeginSection();
// 由MArrayID的基类MArrayBase调用Serialize()
Level.Serialize(fout);
fout.EndSection();
fout.Write(DDataSection::LayerStr,9);
fout.BeginSection();
Layer.Serialize(fout);
fout.EndSection();
保存框架单元数据：
fout.Write(DDataSection::FrameStr,9);
fout.BeginSection();
Frame.Serialize(fout);
fout.EndSection();
fout.Write(DDataSection::FrSectStr,9);
fout.BeginSection();
FrameSect.Serialize(fout);
fout.EndSection();
Material、FrameLoad和其它数据的保存也可以类似进行
然后保存其它数据：......

  5. 如何读取层、图层、框架和钢框架单元数据：

先打开一个文件用于读取数据：bifstream fin("filename.d84");
首先读入SAP84数据库文件标识串和版本号，并判断该文件是否SAP84数据库文件：
if(
  !fin.ReadHeader()) return;
  // 如果不是合法文件，返回
接着读入其它数据
int nSize;
char strSection[9];
while( 1 ) {

fin.Read(strSection, 9);
fin.Read( (char*)&nSize, sizeof(int) );  //
    这个整数表示本数据段数据区的长度
if( fin.Eof() ) break;
    // 文件结尾
if( strcmp(strSection,DDataSection::LevelStr)==0 ){
Level.Serialize( fin );
    // 读入楼层数据
}
else if( strcmp( strSection, DDataSection::LayerStr)==0 )
    {
Layer.Serialize( fin );

    //  读入图层的数据
}
else if( strcmp( strSection,DDataSection::FrameStr)==0 ) {
Frame.Serialize( fin );

    //  读入框架单元数据：
}
//  Material、FrameLoad和其它数据的读取也可以类似进行
else {  // 对一些不需要的数据段可作如下处理
fin.Seek( nSize, SEEK_CUR);
}

}

  6. 相互之间的关系如何？

顺序检索所有框架单元：
for( int i = 0; i < Frame.Entries(); i ++ ) {
Frame[i].nID=...
.....
}
如何取得单元号为101的单元的数据：
// 设置单元的I端节点号为10。必须保证101单元存在，否则会出错
Frame.Ref(101).nI=10
// 可以通过此nDisp判断101号单元所在的层是否显示,即101号单元是否显示
if( Level.Ref( Frame.Ref(101).nLevel ).nDisp ) ...
同样可以通过FrameSect.Ref( Frame.Ref(101).nSect )取得101号单元截面的相关数据
  ，在使用过程中必须判断nSect是否大于零，如果小于等于零，则不能调用FrameSect.Ref(...)函数
为了取得101号框架单元在第3种荷载种类下的跨内荷载，可以：
DFrameLoad load3;
   // 保存需要的跨内荷载
CFrame & copy = Frame.Ref(101);
for( int i = 0; i < copy.Load.Entries(); i ++ ) {
if(  Load[i].Global == 3 ){
load3 =
  FrameLoad.Ref(pLoad[i].LocalID);
break;
}
}

  7. 如何生成并插入新的单元？

CFrame ele;
......    // 设置新单元ele的有关数据
// 通常需要取得没有被利用的ID（这里相当于单元号），并判断单元ele是否已经存在
//
  即要求满足两个节点号之间不能有两个框架单元
int emptyid = Frame.FirstEmptyID()可以取得一个最小的大于0的空闲ID
// 该函数可以检测单元是否已经存在，它不是通过nID是
// 否相等来判断，而是通过ele的operator ==(...)判断，
//
  函数返回一个空闲的ID（等价于FirstEmptyID()）
Frame.Contains( ele, emptyid );
Frame.Contains( id )和Frame.Contains(ele)是通过id和ele.nID判断该单元号是否存在，其速度要比前一行提到的Contains要快很多，可惜它们不经常用
ele.nID
  = emptyid;
Frame.Insert( ele );
  // ele.nID设置好之后就可以插入了

  8. 如何删除单元？

只能通过单元的nID删除，Frame.Remove( ele )相当于Frame.RemoveFromID( ele.nID )，删除操作的速度非常的快，跟插入的速度一样的快。Frame.Clear()可以清除所有单元。

有些数组的元素类是不需要ID的，而且一般也不要求有序，例如力的内力组合数据段FORCECOM，你可以定义如下的数组：

MArray<DCombFactor> Force，它的存取与前面所举的例子是完全一样的，只是插入和删除稍微有些不一样，判断某种组合是否已经存在可以调用Force.Contains( DCombFactor & nforce )，插入某种组合可以调用Force.Insert( DCombFactor & nforce )或Force.Append( DCombFactor & nforce )，两个函数是完全等价的。Force.Remove( DCombFactor & nforce )可以删除组合等于nforce的组合，Force.RemoveAt( int index)可以删除第index+1种组合（index从0开始），删除操作带来删除元素后面所有元素的索引号的前移，删除大量的元素时如果仍旧调用RemoveAt(int index)速度非常之慢，你可以调用Force.Removes( int index[ ], int num)删除num个组合，删除的元素对应的号放在index[]中。

非数组类型的数据的存取与前面是完全一样的，例如时程分析的数据可以定义为：

DHistory history;
MArrayID<DHistoryCurve>
  hCurve;
MArray<DHistoryLoad> hLoad;
数据的保存可以通过下面的程序段实现：
fout.Write(DDataSection::HistStr,9);
fout.BeginSection();
history.Serialize(fout);
fout.EndSection();
fout.Write(DDataSection::HistCurvStr,9);
fout.BeginSection();
hCurve.Serialize(fout);
fout.EndSection();
fout.Write(DDataSection::HistLoadStr,9);
fout.BeginSection();
hLoad.Serialize(fout);
fout.EndSection();

通过hCurve.Ref(hLoad[i].nCurve)可以找到第i+1种空间分布荷载所对应的载荷曲线数据，当然首先
  得判断hLoad[i].nCurve是否大于零。


有关层和图层的一些约定：

层的概念主要是为了方便地处理分层或高层结构中的一些特殊问题而设置的，层指的是有一定高度的水平面，各单元中的nLevel并非真实的层号，它指向层数据的标识号，即DLevelBase中的nID，真实的层号等于nID（即单元中的nLevel）减去2，层号可以等于-1、0或者从1到n之间的任何数（n为总层数），如果增加或删除了一层，必须调整层数组（一般为DLevelBase类型）中层号大于被修改层的各元素的nID（不能简单修改，因为nID与存储位置相关）和Height值 ，同时还要调整单元和节点数据中的nLevel数据。对于不分层结构而言，所有单元和节点均处在-1层，即单元和节点数据中的nLevel等于1。对分层结构，单元或节点所处层号（nID-2）的确定一般遵从下面的约定：节点如果正好在某个层 范围内（即处在某一层的高度与下一层的高度之间，但不包含下一层所在高度）， 例如，节点在0.0高度上或以下，其层号为0，若节点高度在0.0（不含0.0）与1层高度（含）之间，则其层号为1，若节点处在最高层之上，其层号为最高层；单元的层号由组成单元的节点的最大层号决定，例如柱单元一端的节点在1层上，另外一端的节点在3层上，那么它的层号取3，如果两个节点的层号均为-1，则它的层号取-1。从上面的说明可以发现，一个结构不管是否分层，必须有DLevelBase的数组，并且至少存在一个nID等于1的层。

图层的概念相当于单元和节点的集合，一个结构必须至少有一个图层，该图层的nID号等于1，1号图层永远不能被删除，单元和节点的图层号nLayer必须大于等于1。


关于nID的补充说明：

由于nID决定了元素在数组中的位置，因而数组中个元素的nID不能随意修改，如：MArrayID<DFrameSect> FrameSect，如果FrameSect[3].nID等于11，你不能做如下修改：FrameSect[3].nID=14，如果非修改不可，可以采用如下两种做法：

  • DFrameSect tmp = FrameSect.Ref(11);
    FrameSect.RemoveFromID( 11 );
    tmp.nID = 13;
    FrameSect.Insert( tmp );

  • 采用MArrayID提供的成员函数：
    FrameSect.ChangeID( 11, 13 ); // 速度更快，更方便

SAP84数据库文件中各部分相关数据的联系都是通过nID建立的，这种方式在生成SAP84数据文件时会有问题。例如：单元的材料号，DFrameBase中有数据成员nMat，它指向DMaterial中的nID，在生成框架单元的材料时，材料号要求从1开始，并且中间不能间断，可是DMaterial中的nID可能不连续，起始号可能也不是1，为方便处理这种情况，MArrayID提供了一个成员函数ContinueID( int *IdChangedTo )，此函数可以使所有数组元素中的nID从1开始连续分布，指针IdChangedTo必须由调用函数分配内存，其大小为 改变前数组的最大nID号（可以通过成员函数MaximumID()得到），函数执行完成之后，IdChangedTo[i]表示原来nID=i+1的元素变化之后的nID，依据IdChangedTo可以修改引用此数组nID的数据，例如，如果把DMaterial数组中的nID连续化，则需要把所有单元中的nMat数据作修改以保证正确的索引。

SAP84要求节点号也必须从1开始，并且中间也不能间断（单元号没此要求），因而前处理程序产生的最终数据库文件的节点nID号必须从1开始，而且中间不能有间断。 尽管SAP84允许相同类型的两个单元有相同的单元号，但这会带来一系列的技术问题，因而在数据库文件中绝对不允许出现两个相同类型单元的单元号相等的情形。


不支持的数据结构

SAP84的一些数据没有得到支持：

不支持材料的温度变化和各向异性，不支持子结构，不支持PENALTY数据段引导的罚单元，不支持读入刚度单元（即STIFF数据段），不支持流固耦合，不支持钢筋混凝土配筋所需要的一些特别专用的信息，不支持BRIDGE模块的数据段，不支持结构动力修改模块SSDM，不支持管道单元的分支节点串功能，不支持考虑P-delta效应的数据，不支持随机地震响应分析，另外也不支持一些SAP84输出文件的控制变量。


C++类库声明

此网页使用了框架，但您的浏览器不支持框架。


C++类库实现

此网页使用了框架，但您的浏览器不支持框架。


分析结果类封装简介

SAP84分析程序所产生的结果文件是完全基于FORTRAN格式的，这种格式不适合于面向对象的后处理程序的编制；另外有些结果并非最终结果，后处理程序需对这些结果作进一步的处理。为了隐藏SAP84结果文件的内部格式，缩短后续程序开发的周期，减少结果文件格式的变动所带来的程序修改的工作量， 我们提供了DResult类用来封装SAP84的结果文件，二次开发程序员只需调用相关的成员函数即可得到相应的数据结果。

分析结果类封装所涉及到的文件包括：
SAP84lib.lib、SAP84lib.dll、result.h、fileio.h、array.h、classlib.h

用户二次开发时需要连接sap84lib.lib库，并包含头文件result.h，该文件会自动包含其余三个头文件。


分析结果封装的辅助类：

封装分析结果的类只有一个：DResult，所有的分析数据结果均由DResult的成员函数提供。

为了方便地实现某些单元结果的提取，还定义了一些辅助类，这些类定义的变量一般作为DResult的某些成员函数的参数传递变量，这些类包括：

类 | 作用
DFrameForce | 框架单元和钢框架单元的内力
DTrussForce | 桁架单元的内力
DCframeForce | 平面曲梁单元的内力
DVframeForce | 变截面梁单元的内力
DPipeForce | 管道单元的内力
DShellForce | 板壳单元的内力
DWallForce | 墙单元的内力
DSpringForce | 弹簧单元的弹簧力
DSframeCheck | SS88对钢结构的校核结果
DFrameRein | REIN的配筋结果


DResult的使用

DResult查询结果的成员函数的返回值全为int类型，如果查询成功返回1，查询失败则返回0。下面关于DResult的使用步骤，除第1步之外，其余步骤之间没有任何先后顺序。

  1. 调用DResult的构造函数初始化：
    例如，要处理的数据文件为filename，文件所在路径为d:\data，您可以使用下面的构造函数：
    DResult Result( "d:\\data\\filename.ext", nNode );
    如果d:\data为当前目录，可以去掉路径d:\\data\\，扩展名“.ext”可有可无，DResult会自动根据文件名filename找到不同结果对应的文件。nNode是结构有效的节点个数，一般说来 后处理所关心的节点个数要小于或等于SAP84分析结果中的节点个数（产生的原因包括：刚性楼板假定产生的主节点、开洞墙产生的附加节点），建议把后处理能得到坐标值的节点个数赋给nNode，如果不能确定，可以直接给0。
    初始化过程也可以通过下面的步骤实现：
    DResult Result;
    Result.SetFileName( "d:\\data\\filename.ext", nNode );
    可以采用下面三种方法查询初始化是否成功：
    if( !Result ) 不成功；
    if( Result ) 成功；
    if( Result.Good() ) 成功；

  2. 查询与节点变形相关的一些结果，例如，节点位移:
    对于每一类型的结果提供两种查询方式，一种是查询某荷载种类（或者是某荷载组合、某振型、地震方向、某响应号、某屈曲模态）下的所有节点的所有位移分量，如语句：
    Result.GetOneCondDisp(loadcondition,disp);
    它查询某荷载种类下的所有节点的位移，disp是形式为disp[nNode][6]的数组（nNode为结构有效的节点个数），disp所占用的内存空间的分配与释放由调用程序负责，而不是由DResult类负责；
    另外一种是查询某个节点在所有荷载种类（或者是某荷载组合、时程响应点）下的所有位移分量，如语句：
    Result.GetOneNodeAllCondDisp( nNdID, disp );
    它查询某节点（节点号为nNdID）在所有荷载种类下的位移，disp是形式为disp[nLoad][6]的数组（nLoad为荷载种类数），disp所占用的内存空间的分配与释放由调用程序负责，而不是由DResult类负责，对于振型、地震反应谱和屈曲模态没有提供这种方式，因为一般 不会有这种需求。

  3. 查询节点应力：
    例如，针对4-21节点三维等参元的应力提供了下面两个函数：
    int GetOneCombSol21Stress( int CombNo, double stress[][9] );
    int GetOneNodeAllCombSol21Stress( int ndNo, double stress[][9] );
    第一个函数用于读取所有节点在某荷载组合下的应力，第二个函数用于读取某个节点在所有荷载组合下的应力。

  4. 查询单元的内力结果：
    对于框架（梁柱）单元、钢框架（钢梁柱）单元、桁架单元、变截面梁柱单元、曲梁单元、管道单元、板壳单元、墙单元都提供了查询单元内力的函数，所有单元都提供了两个不同用途的函数，其中一个函数用于读取一个单元的所有组合的内力，另一个函数用于读取一种组合下所有单元的内力，另外多数单元还提供了一个函数用于循环读取所有单元所有组合下的内力。
    例如，针对框架（梁柱）单元内力提供了下面三个函数：

    int GetOneFrameAllCombForce( int FrameNo, MArrayID<DFrameForce> & FrameForce );
int GetOneCombAllFrameForce( int Comb, MArrayID<DFrameForce> & FrameForce );
int RecycleGetOneFrameForce( bifstream & fin, int & eleID, MArrayID<DFrameForce> & vForce );

    第一个函数用于读取某个梁柱单元所有组合下的内力，这时DFrameForce中的nID成员变量表示组合号，如果读取成功返回1，否则返回0；第二个函数用于读取某组合下所有梁柱单元的内力, DFrameForce中的nID成员变量表示单元号，如果读取成功返回1，否则返回0。
  第三个函数用于读取所有单元所有组合下的内力，由于这种情况下的数据量有可能非常大，无法一次性读入到内存中，此函数必须采用循环调用的方式（比循环调用前两个函数的速度要快），其使用方法如下：
bifstream fin;
int eleID;
MArrayID<DFrameForce> vForce;
while( RecycleGetOneFrameForce(fin,eleID,vForce) ) {
// 结果处理代码,vForce[i]表示框架单元eleID在荷载组合vForce[i].nID下的内力
// 如果中途跳出循环，需要做调用fin.Close()，例如下面代码
if( eleID > 1000 ) {
.....
fin.Close();
break;
}
}
由于板壳单元的内力结果文件的特殊性，DResult提供的用于读取所有板壳单元所有组合下的内力的函数有些特殊，RecycleGetAllShellForce调用之后返回的是某种荷载组合下所有单元的内力。

  5. DResult还提供了一些后处理程序经常要用到的变量，具体可以参考DResult声明中的公有数据成员。


分析程序产生的结果文件

下面这些文件是由SAP84分析程序直接产生的二进制的结果文件，所有这些文件已经完全为DResult类所封装，一般说来后续开发人员无需了解这些格式。但是如果开发人员并非采用C++语言，则可能会需要。

NAME.SYS NAME.ID NAME.XYZ NAME.PL NAME.U3 NAME.U6 NAME.U7
NAME.U8 NAME.U10 NAME.U30 NAME.U31 NAME.A2 NAME.A11 NAME.A17
NAME.A18 NAME.A14 NAME.A41 NAME.U41 NAME.U5 NAME.DIS NAME.VEC
NAME.EQU NAME.RES NAME.VEL NAME.ACC NAME.STP NAME.ACD NAME.FSJ
NAME.REF NAME.MAS NAME.CQC NAME.F88 NAME.RC2

下表中nNodeTotal为分析程序计算时的节点数，它包括墙细分增加的节点，一般说来该节点数大于数据文件中的节点数。nLoad为荷载种类数，nDispComb为位移组合数，由COMBINE数据段决定，nLoadComb为力的组合数，由FORCES数据段决定，如果COMBINE和FORCES数据段只填写了其中某一个，则两个组合数取相同的数，如果两个数据段都没有填写，则组合数取nLoad+nSpectrum，nSpectrum为地震反应谱计算的方向数，nActNum为施工模拟的步数。这些变量一般都已经作为 DResult 的公有数据成员。

下表中的文件结构大多采用FORTRAN语言的写入语句描述，FORTRAN语言的WRITE有一个非常重要的特点：如果文件不是记录文件（所谓的记录文件就是WRITE语句中包含REC，例如WRITE(NT,REC=...)...），则每一个WRITE语句的前面和后面会分别增加一个整数（4个字节），这个整数等于该WRITE语句所写数据的字节数。记录文件没有这个特点。例如语句：
WRITE(NT) NUME, nLoadComb
NUME和nLoadComb都是四字节的整数，该语句最终写了16个字节，前四个和最后四个字节都是一个整数，该整数的值等于8。而语句：
WRITE(NT, REC=ILJ+1) (SIG(NDE,1),NDE=1,nNodeTotal)
则没有这个特性，SIG是一个双精度实数数组，该语句最终写了8*nNodeTotal个字节。

下表中所有涉及到位移、力、距离、周期、时间、因子等参数的变量都是8字节的实数，而涉及到个数、类型、单元号等参数的变量为4字节的整数。

NAME.SYS

此文件包含的内容依次为：
long int size: 无用的四个字节
char[12]：文件名
long int EXT[55]:各种文件的扩展名
long int NEL[55]:各种类型单元的数目(与NTYPE[55]配对使用)
long int NTYPE[55]:单元类型
long int NDMAX, nLoad, NUMNP, NEG, NEQ, LEQ, NEX;
其中nLoad为荷载种类数，NUMNP为节点数(含墙细分节点)，NEQ为方程总数，NEX振型计算个数
long int NZZ[55];
long int numnp_input:数据文件中填写的节点数
long int TOTALLEVEL：总层数
long int size: 无用的四个字节

// 一些常用NZZ的说明(下标从0开始，后面的一些文件需要用到这些数据)：
NZZ[6]:地震方向数，
NZZ[7]:地震反应谱计算时所使用的振型个数
NZZ[9]:DYNAMIC的响应个数
NZZ[10]:DYNAMIC产生的结果类型，第1、2、3位分别决定是否输出位移、速度、加速度，不等于0表示输出相应结果，否则不输出
NZZ[11]:STEP的响应个数
NZZ[12]:STEP产生的结果类型，第1、2、3位分别决定是否输出位移、速度、加速度，不等于0表示输出相应结果，否则不输出
NZZ[22]:位移组合数nDispComb(决定于COMBINATION数据段)，如果没有运行求组合的程序段，该数值等于0
NZZ[23]:力的组合数nLoadComb(决定于FORCES数据段)，如果没有运行求力的程序段，该数值等于0
NZZ[29]:流体单元是否已经计算
NZZ[30]:施工模拟步数（若XCONSTR没有运行，该数为步数的负数）
NZZ[31]:施工模拟计算方法。=1逐层找平计算 =2分层计算,但采用完整结构 =3从顶向下计算(Choi的方法)
NAME.ID 节点自由度与方程号之间的对照表，FORTRAN语言写入的格式为：
WRITE(NT) nNodeTotal,7,nNodeTotal*7
WRITE(NT) ((ID(I,J), I＝1,nNodeTotal),* J＝1,7)

其中:
nNodeTotal:节点总数；
ID(I,J):
当J小于7时，表示节点I的第J个自由度（即三个平动和三个转动自由度）对应的方程号，如果ID(I,J)小于等于0(存在小于0的数），表示此自由度被约束了
当J等于7时，如果ID(I，J)大于0,它表示节点I的主节点号。由于从结点的Ux、Uy和Rz被约束了，它对应的位移需要通过主节点的位移和坐标差值计算得到，计算的公式为：
Rzs = Rzm
Uxs = Uxm-(Ys-Ym)*Rzm
Uys = Uym+(Xs-Xm)*Rzm
其中：Uxs、Uys和Rzs表示从结点的x、y方向的平动位移和z方向的转动位移，而Uxm、Uym和Rzm表示对应的主结点的x、y方向的平动位移和z方向的转动位移，Ys、Xs表示从结点的xy坐标，Ym、Xm表示对应的主节点的xy坐标
NAME.XYZ 所有节点的坐标值，FORTRAN语言写入的格式为：
WRITE(NT) nNodeTotal,3,nNodeTotal*3
WRITE(NT) ((X(I,J),I＝1,nNodeTotal),J＝1,3)

X(I,1)、X(I,2)、X(I,3)分别表示节点I的x、y、z坐标
NAME.PL 所有单元的节点编号，各种单元的类型代码和相关节点的顺序可以参考SAP84高级用户手册。

对每一种单元类型首先写一个记录：
WRITE(NT)NDE,KK
其中,
NDE＝0 表示一种新的单元类型开始；
KK — 该单元类型代码。
对于每个单元写一个记录:
WRITE(NT) K,N,(NNODE(I),I＝1,K)
式中,
K — 该单元的节点个数；
N — 单元号；
NNODE — 该单元的全部节点号(对平面单元和三维元的边中点可能为0值，表示该节点不存在)。

NAME.U3

框架单元的内力文件（由分析程序产生），FORTRAN语言写入的格式为：
WRITE(NT) NUME, nLoadComb
DO M=1, NUME
WRITE(NT) NE,MTYPE,MPRT,(X(I),I=1,MPRT)
 DO LCOMB=1, nLoadComb
DO I=1, MPRT
WRITE(NT) (F(L,I),L=1,6)
END DO
END DO
END DO
 其中：
 NUME：框架单元总数
 NE：单元号
MTYPE:单元类型,1梁 2柱 3斜柱
 MPRT：单元内力输出的断面数
 X(I)：各输出断面距I端的距离
 F(1-6,I)：轴力N、1-2平面内2方向剪力Q1-2、1-2平面内3方向弯矩M1-2、
1-3平面内3方向剪力Q1-3、1-3平面内2方向弯矩M1-3、扭矩T

NAME.U6

由分析程序生成的平面曲梁单元内力文件，FORTRAN写入的格式为：
WRITE(NT) NUME,nLoadComb
DO INUME=1, NUME
WRITE(NT7) NE
DO LCOMB=1, nLoadComb
WRITE(NT7) (D(I),I=1,12)
END DO
END DO
 其中：
 NE ：单元号
 D(1-6) ：单元I端内力N、Q1-2、M1-2、Q1-3、M1-3、T
D(7-12)：单元J端内力N、Q1-2、M1-2、Q1-3、M1-3、T

NAME.U7

变截面梁单元的内力文件（由分析程序产生），格式与NAME.U3完全一样

NAME.U8

桁架单元的内力文件，FORTRAN语言写入的格式为：
WRITE(NT) NUME,nLoadComb
DO M=1, NUME
WRITE(NT) NE
 DO LCOMB=1, nLoadComb
WRITE(NT) SIG
END DO
END DO
 其中：
 NUME：桁架单元总数
 NE：单元号
 SIG：轴力

NAME.U10

由分析程序生成的管道单元内力文件，FORTRAN写入的格式为：
WRITE(NT) NUME,nLoadComb
 DO INUME=1,NUME
WRITE(NT)NE，NS
DO LCOMB=1,nLoadComb
WRITE(NT) (R(I),I=1,NS)
END DO
END DO
 其中：
 NE：单元号
 NS： 项数，如果是直管单元=12，曲管单元=18
 若 NS=12 则：
 R(1-6)：单元I端内力N、Q1-2、M1-2、Q1-3、M1-3、T
R(7-12)：单元J端内力N、Q1-2、M1-2、Q1-3、M1-3、T
 若 NS=18 则：
 R(1-6)：单元I端内力N、Q1-2、M1-2、Q1-3、M1-3、T
 R(7-12)：单元中间内力N、Q1-2、M1-2、Q1-3、M1-3、T
R(12-18)：单元J端内力N、Q1-2、M1-2、Q1-3、M1-3、T

NAME.U30

钢框架单元的内力文件（由分析程序产生），格式与NAME.U3完全一样

NAME.U31

弹簧单元的弹簧力文件，FORTRAN语言写入的格式为：
WRITE(NT) NUME,nLoadComb
DO M=1, NUME
WRITE(NT) NE, NI, NJ
 DO LCOMB=1, nLoadComb
WRITE(NT) SPRINGFORCE
END DO
END DO
 其中：
 NUME：弹簧单元总数
 NE：单元号
NI，NJ：弹簧两端的节点号，对接地弹簧NJ=0
 SPRINGFORCE：弹簧力或力矩

NAME.A2

由分析程序生成的平面单元应力文件， FORTRAN写入的格式为：
 DO IL = 1, nLoadComb
DO J=1, 6
ILJ = 6*(IL-1)+J
WRITE(NT, REC = ILJ ) (AS(J,NDE),NDE=1,nNodeTotal)
END DO
WRITE(NT, REC=ILJ+1) (SIG(NDE,1),NDE=1,nNodeTotal)
WRITE(NT, REC=ILJ+2) (SIG(NDE,2),NDE=1,nNodeTotal)
WRITE(NT, REC=ILJ+3) (SIG(NDE,3),NDE=1,nNodeTotal)
END DO
 其中：
 nNodeTotal: 节点总数，包括墙细分节点，它大于nNode
 AS(1-6,NDE)的意义依赖于单元类型：
平面应力和平面应变单元：σyy,σzz,σxx,σyz,无用,无用
轴对称单元：σrr,σzz,σθθ,σrz,无用,无用
受扭转的轴对称单元：σrr,σzz,σθθ,σrz,σrθ,σθz
 SIG(NDE,1)：主应力σ1
SIG(NDE,2)：主应力σ2
SIG(NDE,3)：主应力方向与Y轴的夹角（度）

NAME.A11

由分析程序生成的 sol21 协调三维实体单元应力文件， FORTRAN写入的格式为：
 DO IL = 1, nLoadComb
DO J=1, 9
ILJ = 9*(IL-1)+J
WRITE(NT1, REC=ILJ) (AS(J,NDE), NDE=1,nNodeTotal)
END DO
END DO
 其中：
 AS(1-9,NDE)的意义如下：σxx,σyy,σzz,σxy,σyz,σxz,主应力σ1,主应力σ2,主应力σ3
在柱坐标下的意义为：σrr,σθθ,σzz,σrθ,σθz,σrz,主应力σ1,主应力σ2,主应力σ3

NAME.A17

由分析程序生成的带旋转自由度的 sol8r 非协调三维实体单元应力文件，格式与 NAME.A11 完全一样

NAME.A18

由分析程序生成的 s16 非协调三维实体单元应力文件，格式与 NAME.A11完全一样

NAME.A14

由分析程序生成的SHELL单元整体坐标系下的应力文件，格式与 NAME.A11 完全一样
应力分量的顺序为：σ xx、σ yy、σ zz、σ xy、σzx、σ zy、Mxx、Myy、Mxy

NAME.A41

板壳单元 局部坐标系下平均后的内力文件（由分析程序产生），FORTRAN语言写入的格式为：
WRITE(NT) NUME,nLoadComb
 DO LCOMB=1, nLoadComb
 DO M=1, NUME
WRITE(NT) NE,NODENUM
 DO I=1, NODENUM
WRITE(NT) (SIG(J,I), J=1,8)
END DO
END DO
END DO
 其中：
 NUME： 板壳单元总数
 NE： 单元号
NODENUM：这个单元的节点数目
 SIG(1,I)—SIG(8,I)：板壳单元各节点在中面处的σ1、σ2、σ12、Q31、Q32、M11、M22和M12

NAME.U41

板壳单元局部坐标系下平均前的内力文件（由分析程序产生），FORTRAN语言写入的格式为：
WRITE(NT) NUME,nLoadComb
DO M=1, NUME
WRITE(NT) NE,NODENUM
DO LCOMB=1, nLoadComb
DO I=1, NODENUM
WRITE(NT) (SIG(J,I), J=1,8)
END DO
END DO
END DO
其中：
NUME： 板壳单元总数
NE： 单元号
NODENUM：这个单元的节点数目
 SIG(1,I)—SIG(8,I)：板壳单元各节点在中面处的σ1、σ2、σ12、Q31、Q32、M11、M22和M12

NAME.U5

墙单元的内力文件（由分析程序产生）， FORTRAN语言写入的格式为：
   WRITE(NT) NUME,nLoadComb  !单元数, 组合数
   DO INUME=1,NUME       ! 对单元循环
      WRITE(NT) NE,HOLE,MTYPE,IDOOR,IOUT

C       NE:单元号   HOLE:单元类型号(1无洞,2有洞)  MTYPE:变形模式(0壳,1膜,2板)
C       IDOOR=1  <==> 开门洞
C            =0  <==> 开窗洞(无洞时IDOOR=0)
C       IOUT =1  <==> 对开窗洞情况输出四个子区域的内力
C            =0  <==> 对开窗洞情况不输出子区域的内力
C  以下输出墙单元的内力，如果MTYPE=1，以下语句输出面内内力，如果MTYPE=2，则输出面外内力
C           如果MTYPE=0，以下语句通过goto 35语句循环两次，分别输出面内和面外内力

35    IF (HOLE.EQ.1) THEN       ! 一类墙（无洞口）
         Do LCOMB=1, nLoadComb
            WRITE (NT) (SIGM(I),I=1,6)     !两个边上的内力值
      ELSE                    ! 二类墙（有洞口）
         if (idoor.gt.0) then        ! 开门洞
            Do LCOMB=1, nLoadComb
               WRITE (NT) (SIGM(I),I=1,6)  !第一子区域内力(左半部分)
            Do LCOMB=1, nLoadComb
               WRITE (NT) (SIGM(I),I=1,6)  !第二子区域内力(右半部分)
            Do LCOMB=1, nLoadComb
               WRITE (NT) (SIGM(I),I=1,6)  !第三子区域内力(上半部分)
         else             ! 开窗洞
            Do LCOMB=1, nLoadComb
               WRITE (NT) (SIGM(I),I=1,6)
            IF(iout.gt.0) THEN    ! 子区域详细内力
               Do LCOMB=1, nLoadComb
                  WRITE (NT) (SIGM(I),I=1,6)  !第一子区域内力(左半部分)
               Do LCOMB=1, nLoadComb
                  WRITE (NT) (SIGM(I),I=1,6)  !第二子区域内力(右半部分)
               Do LCOMB=1, nLoadComb
                  WRITE (NT) (SIGM(I),I=1,6)  !第三子区域内力(上半部分)
               Do LCOMB=1, nLoadComb
                  WRITE (NT) (SIGM(I),I=1,6)  !第四子区域内力(下半部分)
             ENDIF
         endif
      ENDIF
C
      if(mtype.eq.0) then
         mtype=2      !第一次输出的是面内内力，接下来再输出面外内力
         goto 35
      endif
   END DO

SIGM(1-3):分别表示墙单元（或各子区域）1号边的内力；
SIGM(4-6):分别表示墙单元（或各子区域）3号边的内力；
三个内力值的意义为：面内内力对应于N22、Q11和M33，而面外内力对应于M11、M12和Q33。
对无洞口墙只有整体的内力，对开门洞墙只有三个子区域的内力，没有整体的内力，
对开窗洞墙，一定包含整体的内力，四个子区域的内力则可能有也可能没有（依赖于IOUT）。
各区域1号、3号边的定义以及内力的方向可以参考SAP84分析程序帮助文档。
NAME.DIS 各方程号对应的荷载种类位移和组合位移，FORTRAN语言写入的格式为：
DO NREC＝1, nLoad
WRITE(NT,REC＝NREC) (DIS(I),I＝1,NEQ),E
END DO
DO NREC＝1, nDispComb
WRITE(NT,REC＝NREC) (DIS(I),I＝1,NEQ),E
END DO

NEQ：方程总数
nDispComb：位移组合数，如果没有运行求位移组合的程序段，nDispComb等于0
E：没有用的实数
NAME.VEC 存放结构的特征向量(振型)和特征值，FORTRAN语言写入的格式为：
DO NREC＝1,NEX
WRITE(NT,REC＝NREC) (VEC(I),I＝1,NEQ)，EIG
END DO

NEQ：方程总数
NEX：计算的振型个数（周期个数）
EIG：特征值，相应的周期为2*π/(sqrt(EIG))，sqrt表示开根号
NAME.EQU 存放地震反应谱计算的位移结果，FORTRAN语言写入的格式为：
DO NREC＝1,NDIR
WRITE(NT,REC＝NREC) (EQU(I),I＝1,NEQ)，E
END DO

NEQ：方程总数
NDIR：计算地震方向个数
E：没有用的实数
NAME.RES 存放时程分析中各时间响应点的位移响应值，FORTRAN语言写入的格式为：
DO NREC＝1,NRES
WRITE(NT,REC＝NREC) (DIS(I),I＝1,NEQ)，TIME
END DO

NEQ：方程总数
NRES：时间响应点的个数
TIME：各响应点的时间 		时程分析输出哪一个结果类型和文件决定于NAME.SYS文件中的相关数据。
NAME.VEL | 结构与NAME.RES完全相同，只是输出结果为速度结果
NAME.ACC | 结构与NAME.RES完全相同，只是输出结果为加速度结果
NAME.STP 存放整体稳定性分析的模态位移和特征值（荷载因子），FORTRAN语言写入的格式为：
DO NREC＝1,NUM
WRITE(NT,REC＝NREC) (DIS(I),I＝1,NEQ)，FACTOR
END DO

NEQ：方程总数
NUM：等于2*nLoadComb，每一种荷载组合进行进行两次稳定性分析，第一次为顺着原有荷载方向，第二次则沿着相反的方向加载
FACTOR：特征值，即失稳时的荷载比例因子
NAME.ACD 各步施工模拟的位移结果（方程号对应的位移），FORTRAN语言写入的格式为：
DO NREC＝1, nActNum
WRITE(NT,REC＝NREC) (DIS(I),I＝1,NEQ),E
END DO

NEQ：方程总数(整体结构的方程数，没有参与该步施工模拟的方程号对应的位移等于0)
nActNum：施工模拟步数
E：没有用的实数
NAME.FSJ 竖向构件或单元下端的组合内力（与反力方向相反），FORTRAN写入的格式为：
 DO lcomb = 1, nLoadComb
WRITE(NT1, REC=lcomb) ((fsj(i,n,lcomb),i=1,6),n=1,nNodeTotal)
END DO

 其中，nLoadComb为内力组合数，nNodeTotal为节点总数
注：在计算反力时只考虑了FRAME、SFRAME、VFRAME、TRUSS、WALL、SHELL、THREEDE、SOL21和SOL8R，没有考虑其它类型的单元，对前四种单元而言只计算下端（z坐标小的一端）的反力；对SHELL的处理方式为:若四个或三个点处在相同高度上，不处理，否则计算高度最小的一点（或两点，即两点的Z坐标同为最小）的反力；对SOL21和SOL8R的处理方式为：计算高度最小的一点反力，如果多个节点的Z坐标同为最小，则计算多个点的反力
NAME.REF 墙细分后的节点信息，FORTRAN语言写入的格式为：
DO ele=1, wallNum
 WRITE(NT) sub1,sub2,Q1,Q2,Q3,Q4,(nSub(I),I=1,subNum)
END DO

Q1,Q2,Q3,Q4:墙单元的四个节点号
sub1,sub2:沿着边Q1-Q2和边Q2-Q4方向的分段数，即沿着Q1-Q2和Q3-Q4边中间各增加sub1-1个节点，沿着Q2-Q4和Q4-Q1边中间各增加sub2-1个节点
nSub:细分增加的节点，细分节点总数subNum=(sub1+sub2-2)*2。细分节点的前后分布关系分别为：沿着Q1-Q2边（按距Q1的距离由近至远排列）细分的点，沿着Q2-Q4边细分的点，沿着Q3-Q4边细分的点，沿着Q1-Q4边细分的点。
每个墙单元（即使它不需要细分）都会产生以上信息
NAME.MAS 质量列向量（各方程对应的质量），FORTRAN语言写入的格式为：
WRITE(NT) NEQ,NCOLUMN,NEQ
WRITE(NT) (MASS(I),I＝1,NEQ)

NCOLUMN为列数（恒等于1)，NEQ为方程总数，MASS(i)为方程i对应的质量
NAME.CQC 存储地震反应谱的一些数据，FORTRAN语言写入的格式为：
WRITE(NT) ANINT
WRITE(NT) (NV(I),I＝1,NEC)
WRITE(NT) (ETT(I,J),I＝1,NEC),J=1,NDIR
WRITE(NT) (ALPHA(I,J),I＝1,NEC),J=1,NDIR
WRITE(NT) (ET(I,J),I＝1,NEC),J=1,NDIR
WRITE(NT) (CQC(I,J),I＝1,NEC),J=1,NEC

ANINT为地震设计烈度（双精度数)，NEC为反应谱计算时使用的振型个数，NV存储了相应的振型号
NDIR为计算的地震方向数，ETT(I,J)为第I个振型在第J个地震方向的地震参与系数
ALPHA(I,J)为第I个振型在第J个地震方向的地震影响系数（不同的地震方向可能采用不同的地震影响曲线）
ET和CQC为双精度数组
NAME.F88 SS88程序段钢结构校核的结果，FORTRAN语言写入的格式为：
WRITE(NT) NUME, nLoadComb
DO M=1, NUME
WRITE(NT) NE,MPRT,(XL(I),I=1,MPRT)
DO LCOMB=1, nLoadComb
DO I=1, MPRT
WRITE(NT) DS,DSRD,RD,DS1,DSRD1,SS,SSRS,RS,ALPHAA1,
* ALPHAA2, SL2,SLR1,SL3,SLR2,BT,BTM,HT,HTM,MDS5,SA
END DO
END DO
END DO
其中：
NUME：钢框架（钢梁柱）单元总数
NE：单元号
MPRT：单元内力输出的断面数，X(I)：各输出断面距I端的距离
DS：强度正应力 DSRD：强度正应力比值 RD：抗弯强度设计值
DS1：稳定正应力 DSRD1：稳定正应力比值 SS：剪应力
SSRS：剪应力比值 RS：抗剪强度设计值
ALPHAA1：强轴(12平面内)计算长度系数 ALPHAA2：弱轴(13平面内)计算长度系数
SL2：13平面长细比 SLR1：长细比限值（压） SL3：12平面长细比
SLR2：长细比限值(拉) BT：宽厚比 BTM：宽厚比限值
HT：高厚比 HTM：高厚比限值
MDS5: 最大应力的类型 =1时,强度应力最大 =3时,1-2平面内稳定应力最大 =5时,1-3平面外稳定应力最大
SA: 受弯构件的局部稳定性系数(>1表示不稳定,非受弯构件等于0)
NAME.RC2 配筋模块REIN产生的配筋结果文件（二进制），读取该文件的C语言代码可点击:
C语言读取代码


DResult处理后产生的结果文件

下面这些文件是DResult类为方便查询和提高查询速度而产生的文件，在调用了DResult的构造函数（非缺省构造函数）或DResult::SetFileName函数之后将产生这些文件，如果这些文件已经存在，DResult会自动根据时间判断是否需要更新这些文件。所有这些文件已经完全为DResult类所封装，一般说来程序后续开发人员无需了解这些格式。但是如果开发人员并非采用C++语言，则有可能用到这些文件：

NAME.NU3 NAME.NU30 NAME.NA41 NAME.NU5 NAME.NDIS NAME.NVEC
NAME.NRES NAME.NVEL NAME.NACC NAME.NEQU NAME.NSTA NAME.NACD
NAME.NMAS NAME.NFSJ

下表中的nNode表示节点数，此节点数为传递给DResult的关心的节点数，不包含墙细分增加的节点。nLoad为荷载种类数；nDispComb为位移组合数，由COMBINE数据段决定，nLoadComb为力的组合数，由FORCES数据段决定，如果COMBINE和FORCES数据段只填写了其中某一个，则两个组合数取相同的数，如果两个数据段都没有填写，则组合数取 nLoad+nSpectrum，nSpectrum为地震反应谱计算的方向数。这些变量和下表中所涉及到的一些变量一般都已经作为 DResult 的公有数据成员。

下表全部采用C++语言描述文件结构，fout为bofstream类的实例，当然也可以为ofstream类的实例，这并不影响文件结构的描述。

NAME.NU3
 （DResult类内部维护的数据文件）

各框架单元的结果信息在NAME.U3文件所处的位置，即WRITE(NT)NE,MTYPE,MPRT所写内容的前面4 个多余字节（FORTRAN语言中一次写入的字节数）所处的位置
fout.Write( &FrameElementMaxID, sizeof(int) );
 for( i=0; i<FrameElementMaxID;i++ )
fout.Write( &Position, sizeof(int) );
FrameElementMaxID为框架单元的最大单元号，中间可能存在一些没有被利用的单元号，这些虚假单元号对应的Position没有任何意义（被设置成-1）

NAME.NU30
 （DResult类内部维护的数据文件）

各 钢框架单元的结果信息在NAME.U30文件所处的位置，即WRITE(NT)NE,MTYPE,MPRT所写内容的前面4个多余字节（ FORTRAN 语言中一次写入的字节数）所处的位置
fout.Write( &SFrameElementMaxID, sizeof(int) );
 for( i=0; i<SFrameElementMaxID;i++ )
fout.Write( &Position, sizeof(int) );
SFrameElementMaxID为框架单元的最大单元号，中间可能存在一些没有被利用的单元号，这些虚假单元号对应的 Position 没有任何意义（被设置成-1）

NAME.NA41
 （ DResult 类内部维护的数据文件）

此文件的意义与别的索引文件的意义有一些区别：
板壳单元每一种组合下的内力结果信息在NAME.A41文件所处的位置，即第一个板壳单元的WRITE(NT) NE,NODENUM语句所写内容的前面4个多余字节（FORTRAN 语言中一次写入的字节数）所处的位置
fout.Write( &nLoadComb, sizeof(int) );
 for( i=0; i<nLoadComb;i++ )
fout.Write( &Position, sizeof(int) );
 nLoadComb为组合数

NAME.NU5
 （ DResult 类内部维护的数据文件）

各墙单元的结果信息在NAME.U5文件所处的位置，即WRITE(NT) NE,HOLE,MTYPE,IDOOR,IOUT所写内容的前面4个多余字节（ FORTRAN 语言中一次写入的字节数）所处的位置
 fout.Write( &WallElementMaxID, sizeof(int) );
 for( i=0; i<WallElementMaxID;i++ )
fout.Write( &Position, sizeof(int) );
WallElementMaxID为墙单元的最大单元号，中间可能存在一些没有被利用的单元号，这些虚假单元号对应的Position没有任何意义（被设置成-1）

NAME.NDIS
（DResult类内部维护的数据文件）

节点位移 ( 主从约束已经处理完毕 )
for( i = 0; i < nLoad; i ++ ){
for( j = 0; j < nNode; j ++ )
fout.Write( dis[j], 6*sizeof(double) );
} // 荷载种类位移
for( i = 0; i < nDispComb; i ++ ){
for( j = 0; j < nNode; j ++ )
fout.Write( dis[j], 6*sizeof(double) );
} // 组合位移（暂不包括地震位移）

NAME.NVEC
（DResult类内部维护的数据文件）

振型信息 ( 主从约束已经处理完毕 )
for( i = 0; i < nEigen; i ++ ) {
fout.Write( &Period, sizeof(double) );
for( j = 0; j < nNode; j ++ )
fout.Write( modedis[j], 6*sizeof(double) );
}
nEigen： 振型个数
 Period： 周期

NAME.NRES
（DResult类内部维护的数据文件）

时程分析的位移响应 结果(主从约束已经处理完毕)
for( i = 0; i < nResponse; i ++ ) {
fout.Write( &Time, sizeof(double) );
for( j = 0; j < nNode; j ++ )
fout.Write( hisdis[j], 6*sizeof(double) );
}
nResponse：响应个数
 Time：该响应对应的时间

NAME.NVEL
（DResult类内部维护的数据文件） 		时程分析的速度响应结果(主从约束已经处理完毕)
for( i = 0; i < nResponse; i ++ ) {
fout.Write( &Time, sizeof(double) );
for( j = 0; j < nNode; j ++ )
fout.Write( hisvel[j], 6*sizeof(double) );
}
nResponse：响应个数
 Time：该响应对应的时间
NAME.NACC
（DResult类内部维护的数据文件） 		时程分析的加位移响应结果(主从约束已经处理完毕)
for( i = 0; i < nResponse; i ++ ) {
fout.Write( &Time, sizeof(double) );
for( j = 0; j < nNode; j ++ )
fout.Write( hisacc[j], 6*sizeof(double) );
}
nResponse：响应个数
 Time：该响应对应的时间

NAME.NEQU
（DResult类内部维护的数据文件）

地震伪谱位移响应信息 ( 主从约束已经处理完毕 )
for( i = 0; i < nSpectrum; i ++ ) {
for( j = 0; j < nNode; j ++ )
fout.Write( eqdis[j], 6*sizeof(double) );
}
nSpectrum：地震方向个数

NAME.NSTA
（DResult类内部维护的数据文件）

屈曲模态信息 ( 主从约束已经处理完毕 )
for( i = 0; i < nBuckle; i ++ ) {
fout.Write( &LoadFactor, sizeof(double) );
for( j = 0; j < nNode; j ++ )
fout.Write( stadis[j], 6*sizeof(double) );
}
nBuckle：屈曲模态个数 =2*位移组合数(两个组成一对)
 LoadFactor：屈曲特征值，即荷载因子

NAME.NACD
（DResult类内部维护的数据文件） 		各施工模拟步对应的节点位移(主从约束已经处理完毕)，不属于相应施工步的节点的位移等于0
for( i = 0; i < nActNum; i ++ ){
for( j = 0; j < nNode; j ++ )
fout.Write( dis[j], 6*sizeof(double) );
} // 荷载种类位移
nActNum：施工模拟步数
nNode：整体结构的节点总数（并非各施工步对应的节点数）
NAME.NMAS
（DResult类内部维护的数据文件） 		节点集中质量矩阵(已经把墙细分节点处的质量分配到四个角点上)
for( i = 0; i < nNode; i ++ )
fout.Write( mass[i], 6*sizeof(double) );
mass[i][0-6]:第i+1号节点集中质量的6个分量
NAME.NFSJ
 （DResult类内部维护的数据文件） 		除了以下两点区别，此文件与分析程序产生的NAME.FSJ的文件结构是完全一样的：
1.每组数中存储了nNode个节点的力，而不是nNodeTotal个节点；
2.墙细分产生的边中节点处的力已经按照力的平衡原则转移到两端的节点上。


结果封装类的声明

此网页使用了框架，但您的浏览器不支持框架。


结果封装类的实现

此网页使用了框架，但您的浏览器不支持框架。


非C++环境对分析结果的处理

由于DResult类是用C++语言编制的，如果开发人员采用其它语言，则会有一定的难度，这时可以采用三种不同的办法处理SAP84分析结果：

  1. 采用其它语言与C++语言混合编程；

  2. 采用C++编一个小程序，这个小程序的目的是利用DResult转换一部分结果。小程序的编制方法为：先生成一个DResult类的变量，然后通过构造函数或DResult::SetFileName函数设置该类所封装的数据文件名，这时，DResult类会调用相关函数转换或者更新一些结果文件，然后可以采用各种办法保存DResult类中的公有成员变量（比如，nLoad,nEigen等），当然也可以直接读取NAME.SYS文件。每一次主程序需要更新结果文件时调用这个小程序，之后在主程序内部可以读取以下结果文件：
    NAME.NU3 NAME.NU30 NAME.NA41 NAME.NU5 NAME.NDIS NAME.NVEC NAME.NRES
    NAME.NVEL NAME.NACC NAME.NEQU NAME.NSTA NAME.NACD NAME.NMAS NAME.NFSJ

    NAME.SYS NAME.U3 NAME.U6 NAME.U7 NAME.U8 NAME.U10 NAME.U30 NAME.U31
    NAME.A2 NAME.A11 NAME.A17 NAME.A18 NAME.A14 NAME.A41 NAME.U5

  3. 完全绕开DResult类，直接读取分析程序产生的结果文件，这些文件的格式可以参考“分析程序产生的结果文件”一节。


如何提取型钢截面字符串中的信息：

如果 DSframeSect 类中的nSectType非零时，型钢截面信息采用字符串的形式来描述（存储在strNss变量中），例如：字符串BB500*12*576*16*400表示钢板焊接成的箱形截面，下面介绍如何从这样的字符串中提取相关的各种数据。为实现此功能，特提供了DSteelStrManager类，这个类的成员变量和函数的说明见本页的最后。由于此类的所有成员函数和变量都是静态的，故不需要为这个类声明任何对象。

例如：有字符串“BCC20a+S120*6@150”，提取数据的方法为（数组大小不能少于50）：

int index,type, num,
flag[50];
double data[50];
char info[50][20],str[]="BCC20a+S120*6@150";
DSteelStrManager::DetachNumberFromString(str,type,num,data,flag,0);
DSteelStrManager::DetachInfoFromString(str,index,num,info,flag,0);

函数结束后type等于12,num等于8,data数组中前8个数据分别为0.0、12.0、0.0、120.0、0.0、6.0、0.0、150.0，flag数组中前8个数分别为1、4、1、6、1、6、1、6，index等于11，info[0-7]的字符串分别为"BCC"、"20a"、"+S"、"120"、"*"、"6"、"@"、"150"。
上述两个函数执行的时间相对较长，若已经知道截面的类型号（一般可通过截面数据中的nSectType数据成员得到），可以重写上述两个函数调用，使得执行速度大大提高，改写之后的代码为：

int index=11,type=12,
num, flag[50];
double data[50];
char info[50][20],str[]="BCC20a+S120*6@150";
DSteelStrManager::DetachNumberFromString(str,type,num,data,flag,1);
DSteelStrManager::DetachInfoFromString(str,index,num,info,flag,1);

又例如：有字符串“GL200*125*14+S450*20+I56A@956”，提取数据的方法为：

int index,type, num,
flag[50];
double data[50];
char info[50][20],str[]="GL200*125*14+S450*20+I56A@956";
DSteelStrManager::DetachNumberFromString(str,type,num,data,flag,0);
DSteelStrManager::DetachInfoFromString(str,index,num,info,flag,0);

函数结束后type等于34,num等于6,data数组中前10个数据分别为0.0、63.0、0.0、450.0、0.0、20.0、0.0、29.0、0.0、956.0，flag数组中前10个数分别为1、5、1、6、1、6、1、3、1、6，index等于33，info[0-9]的字符串分别为"GL"、"200*125*14"、"+S"、"450"、"*"、"20"、"+I"、"56A"、"@"、"150"。

同样在已知截面类型号时可重写上述两个函数调用，使得执行速度大大提高，改写之后的代码为：

int index=33,type=34, num,
flag[50];
double data[50];
char info[50][20],str[]="GL200*125*14+S450*20+I56A@956";
DSteelStrManager::DetachNumberFromString(str,type,num,data,flag,1);
DSteelStrManager::DetachInfoFromString(str,index,num,info,flag,1);

DSteelStrManager类声明的主要框架如下：

class CLASS_DECLSPEC DSteelStrManager {
public:
    static const char *SectE[];	// 等边角钢数据
    static const char *SectI[];	// 工字钢数据
    static const char *SectC[];	// 槽钢数据
    static const char *SectL[];	// 不等边角钢数据
    static const char *SectHK[];	// 热轧宽翼缘H型钢HK系列
    static const char *SectHZ[];	// 热轧窄翼缘H型钢HZ系列
    static const char *SectHA[];	// 焊接H型钢,鞍钢规格HA系列
    static const char *SectHAQ[];	// 轻型焊接H型钢,鞍钢规格HAQ系列
    static const char *SectT[];		// 焊接T型钢,鞍钢规格T系列
    static const char *SectHW[];	// 热轧宽翼缘H型钢,美顿有限公司或马钢公司HW系列
    static const char *SectHM[];	// 热轧中翼缘H型钢,美顿有限公司或马钢公司HM系列
    static const char *SectHN[];	// 热轧窄翼缘H型钢,美顿有限公司或马钢公司HN系列
    static const char *SectIQ[];	// 热轧轻型工字钢IQ系列
    static const char *SectCQ[];	// 热轧轻型槽钢CQ系列
    static const char *SteelPattern[];	// 不同型钢的模式字符串
    static const char *SteelTypeStr[];	// 各种类型的截面的说明字符串，如Dd*t
public:
    // 从型钢字符串str(如:D100*8)中提取数值信息
    // 若typeNoIsValid=0, typeNo返回该截面的类型号(one-based)，若typeNoIsValid!=0,
    // typeNo在调用之前由已经设置好, 在函数内部将使用此编号以加快速度,由于sap84说明书中某些类
    // 型(类型17,26,31,32,34)实际上应该划分成两种类型，故该号与sap84说明
    // 书中的类型号有些出入，详细说明可以SteelTypeStr[]数组的初始化，这里
    // 返回的类型号为相应截面在该数组中/**/之间的号码，typeNo变成0则表示型钢字符串有误
    //  各种类型的图示和说明可以从GIS输入型钢材料时提示中得到。
    // items返回data和flag数组中的有效元素个数(data数组最好大于50)
    // flag[i]: 决定了data[i]存储内容的意义
    //         1: 对应的内容为提示字符串，data[i]的内容没有意义
    //         2: data[i]存储等边角钢字符串在数组SectE[]中的位置(实际是整数, one-based)
    //         3: data[i]存储工字钢字符串在数组SectI[]中的位置(实际是整数, one-based)
    //         4: data[i]存储了槽钢字符串在数组SectC[]中的位置(实际是整数, one-based)
    //         5: data[i]存储了不等边角钢字符串在数组SectL[]中的位置(实际是整数, one-based)
    //         6: data[i]存储了一个实数, 如：钢板厚度，间距等
    //         7: data[i]存储了型钢字符串在数组SectHK[i]中的位置(实际是整数, one-based)
    //         8: data[i]存储了型钢字符串在数组SectHZ[i]中的位置(实际是整数, one-based)
    //         9: data[i]存储了型钢字符串在数组SectHA[i]中的位置(实际是整数, one-based)
    //         10: data[i]存储了型钢字符串在数组SectHAQ[i]中的位置(实际是整数, one-based)
    //         11: data[i]存储了型钢字符串在数组SectT[i]中的位置(实际是整数, one-based)
    //         12: data[i]存储了型钢字符串在数组SectHW[i]中的位置(实际是整数, one-based)
    //         13: data[i]存储了型钢字符串在数组SectHM[i]中的位置(实际是整数, one-based)
    //         14: data[i]存储了型钢字符串在数组SectHN[i]中的位置(实际是整数, one-based)
    //         15: data[i]存储了型钢字符串在数组SectIQ[i]中的位置(实际是整数, one-based)
    //         16: data[i]存储了型钢字符串在数组SectCQ[i]中的位置(实际是整数, one-based)
    static void DetachNumberFromString( const char *str, int & typeNo, int &items,
        double data[], int flag[], int typeNoIsValid=0 );
    // 从型钢字符串str(如:D100*8)中提取相关信息
    // 若indexIsValid=0, index返回该截面在SteelTypeStr数组中的下标(即截面类型号减1)，
    // 若indexIsValid!=0, index在调用之前已经设置好，index变成-1则表示型钢字符串有误,
    // 其数值等于截面类型号减1，这样可以加速函数的执行
    // items返回info和flag数组中的有效元素个数(info数组最好大于50)
    // flag[i]: 决定了info[i]存储内容的意义
    //         1: info[i]存储了提示字符串, 如："BBC","*","L","@"等
    //         2: info[i]存储了一个SectE[]中的等边角钢字符串, 如：75*7
    //         3: info[i]存储了一个SectI[]中的工字钢字符串, 如：20A
    //         4: info[i]存储了一个SectC[]中的槽钢字符串, 如：18A
    //         5: info[i]存储了一个SectL[]中的不等边角钢字符串, 如：45*28*4
    //         6: info[i]存储了一个实数, 如：10
    //         7: info[i]存储了一个SectHK[i]字符串
    //         8: info[i]存储了一个SectHZ[i]字符串
    //         9: info[i]存储了一个SectHA[i]字符串
    //         10: info[i]存储了一个SectHAQ[i]字符串
    //         11: info[i]存储了一个SectT[i]字符串
    //         12: info[i]存储了一个SectHW[i]字符串
    //         13: info[i]存储了一个SectHM[i]字符串
    //         14: info[i]存储了一个SectHN[i]字符串
    //         15: info[i]存储了一个SectIQ[i]字符串
    //         16: info[i]存储了一个SectCQ[i]字符串
    static void DetachInfoFromString( const char *str, int &index, int &items,
        char info[][20], int flag[], int indexIsValid=0 );
    // 从模式串中提取相关信息, patternIndex为SteelPattern数组的下标(zero-based)
    // items返回info和flag数组中的有效元素个数(info数组最好大于50)
    // flag[i]: 决定了info[i]存储内容的意义(只有flag[i]=1才有意义)
    //         1: info[i]存储了提示字符串, 如："BBC","*","L","@"等
    //         2: 需要等边角钢, 即模式字符串中存在 >E
    //         3: 需要工字钢, 即模式字符串中存在 >I
    //         4: 需要槽钢, 即模式字符串中存在 >C
    //         5: 需要不等边角钢, 即模式字符串中存在 >L
    //         6: 需要一个实数, 即模式字符串中存在 >R
    //         7: 需要HK系列, 即模式字符串中存在 >K
    //         8: 需要HZ系列, 即模式字符串中存在 >Z
    //         9: 需要HA系列, 即模式字符串中存在 >A
    //         10: 需要HAQ系列, 即模式字符串中存在 >Q
    //         11: 需要T系列, 即模式字符串中存在 >T
    //         12: 需要HW系列, 即模式字符串中存在 >W
    //         13: 需要HM系列, 即模式字符串中存在 >M
    //         14: 需要HN系列, 即模式字符串中存在 >N
    //         15: 需要IQ系列, 即模式字符串中存在 >B
    //         16: 需要CQ系列, 即模式字符串中存在 >D
    static void DetachInfoFromPatternIndex( const int patternIndex, int &items,
        char info[][20], int flag[] );
    // 返回型钢模式串数组SteelPattern[]的数目，即钢截面总数(不含自定义类型)
    static int GetPatternNum();
    // 判断字符串中的数是否<=0,若存在间距<=0返回-1,若存在其它数值为0返回1,否则返回0
    // 如果字符串不合法，也返回1
    static int StringIncludeZero( const char * str );
    // 返回钢截面面积, str为Z=NZZ中的字符串，unit为所需单位制,
    // nSectType为截面类型,若等于0表示需要GetSteelArea根据字符串自动判断类型
    static double GetSteelArea( const char * str, int unit, int nSectType=0 );
    // 返回自定义截面的索引号(zero-based)，它永远排在其它型钢之后
    static int GetSelfDefSectIndex() { return GetPatternNum(); }
};


如何在程序中调用SAP84计算模块：

本节内容介绍如何在第三方程序中调用SAP84计算模块，调用之前需要产生SAP84文本格式的数据文件。此功能需要以下文件：ProManager.h、Analysis.lib、Analysis.dll。 由于Analysis模块在初始化过程中会自动根据所在文件夹设置SAP84环境变量和PATH环境变量 ，故要求analysis.dll最好放置在SAP84安装文件夹内，否则要求调用之前已经设置好SAP84环境变量。

由于SAP84计算模块在运行过程中会有字符串输出和各种控制信息，Analysis模块需要两个窗口句柄：输出字符串接受窗口m_hOutputWnd和进程调度窗口m_hManagerWnd，这两个窗口句柄可以由外部提供，也可以由Analysis模块自己负责，第三方程序在使用Analysis模块时，最好提供进程调度窗口m_hManagerWnd。在使用Analysis模块时有以下两种方式：

  1. 由Analysis模块自动产生一个字符串接受窗口，而进程调度窗口则由第三方程序负责：
    • 定义CProcessManager对象ProManager，请确保此变量的生存周期包含整个数据的计算时间；
    • 调用ProManager.SetMemoryAccordNodes(int nodeNum)函数（参数为节点总数），由Analysis自动根据系统内存大致估算计算所需内存。也可以通过成员变量m_sap84MemorySize直接设置；
    • 调用ProManager.SetFullPathName(const char * fullPathName)函数，函数参数是所需计算的数据文件名（包含路径），数据文件名的长度不能超过8个字符，并且不能包含汉字（路径可以包含汉字），数据文件名可以带扩展名，也可以不带扩展名；
    • 调用ProManager.SetProcessManagerWnd(HWND hWnd)函数设置进程调度窗口（该窗口由第三方程序负责创建）的句柄，Analysis模块在运行过程中会给此窗口发送一种消息，具体参考本节的后半部分；
    • 调用ProManager.SetOutputWnd(HWND hWnd)函数，函数的参数hWnd为0；
    • 调用ProManager.ComputeSap84Data(BOOL needSelect = FALSE, BOOL freeStructMode = FALSE)函数开始进行计算，如果needSelect为TRUE，在计算之前Analysis会让您选择需要运行的SAP84模块，freeStructMode为TRUE表示对完全自由的结构仅仅进行模态分析；
  2. 字符串接受窗口和进程调度窗口都由第三方程序负责：
    • 定义CProcessManager对象ProManager，请确保此变量的生存周期包含整个数据的计算时间；
    • 调用ProManager.SetMemoryAccordNodes(int nodeNum)函数（参数为节点总数）；
    • 调用ProManager.SetFullPathName(const char * fullPathName)函数；
    • 调用ProManager.SetProcessManagerWnd(HWND hWnd)函数设置进程调度窗口（该窗口由第三方程序负责创建）的句柄，Analysis模块在运行过程中会给此窗口发送三种消息，具体参考本节的后半部分；
    • 调用ProManager.SetOutputWnd(HWND hWnd)函数设置字符串接受窗口（该窗口由第三方程序负责创建）的句柄，Analysis模块在运行过程中会给此窗口发送一种消息，具体参考本节的后半部分；
    • 调用ProManager.ComputeSap84Data(BOOL needSelect = FALSE, BOOL freeStructMode = FALSE)函数开始进行计算，如果needSelect为TRUE，在计算之前Analysis会让您选择需要运行的SAP84模块，freeStructMode为TRUE表示对完全自由的结构仅仅进行模态分析；

在计算模块运行过程中，可以调用函数ProcessIsStillActive检测是否在运行过程中，也可以调用TerminateProcessAndWaiting强制停止计算（参数为等待的时间）。

进程调度窗口需要处理的消息有：

  • 消息WM_PROCESS_ENDED：计算完毕之后发送的消息，如果正常结束则(int)WPARAM的值等于1，如果出现错误或者强行中止(int)WPARAM的值等于0，LPARAM没有用；
  • 消息WM_START_ANOTHERPROGRAM：Analysis每结束SAP84某个计算模块之后（如，SAP.EXE、SOLVE.EXE等）发送的消息，WPARAM和LPARAM没有用。该消息的响应函数必须调用ProManager.StartAnotherProgram函数。如果字符串接受窗口由Analysis自动产生（即上述的第一种方式），此消息无效；
  • 消息WM_PROCESS_BEGIN：Analysis每次启动SAP84某个计算模块之前（如，SAP.EXE、SOLVE.EXE等）发送的消息，WPARAM存储的是命令行字符串指针。如果字符串接受窗口由Analysis自动产生（即上述的第一种方式），此消息无效。

字符串接受窗口的实现：

字符串接受窗口需要处理的消息有只有WM_ADD_OUTPUT_STRING，此消息的响应函数用于处理SAP84计算模块输出的字符串，WPARAM和LPARAM都是字符指针，分别指向输出字符串的起始位置和结束位置（最后一个有效字符的后一字节），此消息响应函数必须调用ProManager.ReadStringFinished函数。字符串接受窗口除了需要响应此消息之外，一般还需要负责显示文字、滚动文字以及文字显示的行数等，为简化该窗口的编制，Analysis特为Visual C++提供了COutputWndBase类，此类一般作为窗口类的基类，它提供的公有成员函数有：

  • void CopyOutputToClipboard()：把输出字符串复制到剪贴板内；
  • void AddOutpuString( CWnd *pWnd, WPARAM wParam, LPARAM lParam)：在WM_ADD_OUTPUT_STRING的响应函数中调用，调用完此函数之后需调用CProcessManager::ReadStringFinished()函数。其中wParam和lParam就是消息对应的两个变量，pWnd传递字符串接受窗口的指针，对上面的例子而言，传递COutputWnd对象的指针即可；
  • void SetBufferLineNum( short num )：设置字符串接受窗口缓冲区所能容纳的最大行数；
  • short GetBufferLineNum()：得到字符串接受窗口缓冲区所能容纳的最大行数；
  • short GetViewLineNums()：得到字符串接受窗口所能容纳的行数，即窗口滚动时行数。

下面是一个具体使用COutputWndBase的例子：

///////////////////////类的声明
class COutputWnd : public CWnd, public COutputWndBase
{
    ..............
    DECLARE_MESSAGE_MAP()
public:
    afx_msg void OnPaint();
    afx_msg void OnSize(UINT nType, int cx, int cy);
    afx_msg void OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar);
    afx_msg BOOL OnEraseBkgnd(CDC* pDC);
    afx_msg LRESULT OnAddOutpuString(WPARAM wParam, LPARAM lParam);
};
///////////////////////类的实现
BEGIN_MESSAGE_MAP(COutputWnd, CWnd)
    ON_WM_PAINT()
    ON_WM_SIZE()
    ON_WM_VSCROLL()
    ON_WM_ERASEBKGND()
    ON_MESSAGE(WM_ADD_OUTPUT_STRING, OnAddOutpuString)
END_MESSAGE_MAP()
// COutputWnd message handlers
void COutputWnd::OnPaint()
{
    CPaintDC dc(this); // device context for painting
    OnDraw( &dc );		// 由COutputWndBase实现
}
void COutputWnd::OnSize(UINT nType, int cx, int cy)
{
    __super::OnSize(nType, cx, cy);
    SetViewRange( this );	// 由COutputWndBase实现
}
void COutputWnd::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
    COutputWndBase::OnVScroll( this, nSBCode, nPos, pScrollBar);
}
BOOL COutputWnd::OnEraseBkgnd(CDC* pDC)
{
    return COutputWndBase::OnEraseBkgnd(pDC);
}
LRESULT COutputWnd::OnAddOutpuString(WPARAM wParam, LPARAM lParam)
{
    AddOutpuString( this, wParam, lParam );
    ProManager.ReadStringFinished();
    return -1;
}


一些函数的说明：

在classlib.h头文件内定义了两个常用的模板函数：

template <class Type>
void Free( Type * & pMem )
{
    free(pMem);
    pMem = NULL;
}
template < class T >
void swap ( T & a, T & b )
{
    T temp;
    temp = a;  a = b;  b = temp;
}

另外还定义了一个类GFunc，此类包含了一些常用的静态函数成员，还有坐标变换类CTransferMatrix和三维向量类CVector。
具体可以参考头文件的内容。


bifstream的定义

int bifstream::Read( void *buffer, int byteSize)
{
    if( byteSize <= 0 ) return 1;
    return fread( buffer, byteSize, 1, pFile )==1;
}
int bifstream::ReadHeader()
{
    char strHeader[10];
    Read( strHeader, 10 );
    if( strcmp( strHeader, strSap84Header ) ) return 0;
    Read( &nVersion, sizeof(short) );
    if( nVersion > SUPPORTVERSION ) return 0;
    return 1;
}

bifstream & bifstream::operator >> ( unsigned char & c)
{
    Read( &c, sizeof(unsigned char) );
    return *this;
}
bifstream & bifstream::operator >> ( char & c)
{
    Read( &c, sizeof(char) );
    return *this;
}
bifstream & bifstream::operator >>( unsigned short & c)
{
    Read( &c, sizeof(unsigned short) );
    return *this;
}
bifstream & bifstream::operator >>( short & c)
{
    Read( &c, sizeof(short) );
    return *this;
}
bifstream & bifstream::operator >>( int & c)
{
    Read( &c, sizeof(int) );
    return *this;
}
bifstream & bifstream::operator >>( unsigned int & c)
{
    Read( &c, sizeof(unsigned int) );
    return *this;
}
bifstream & bifstream::operator >>( unsigned long & c)
{
    Read( &c, sizeof(unsigned long) );
    return *this;
}
bifstream & bifstream::operator >>( long & c)
{
    Read( &c, sizeof(long) );
    return *this;
}
bifstream & bifstream::operator >>( float & c)
{
    Read( &c, sizeof(float) );
    return *this;
}
bifstream & bifstream::operator >>( double & c)
{
    Read( &c, sizeof(double) );
    return *this;
}
bifstream & bifstream::operator >>( long double & c)
{
    Read( &c, sizeof(long double) );
    return *this;
}


bifstream的声明

class CLASS_DECLSPEC bifstream: public biobase
{
public:
    bifstream():biobase() {}
    bifstream(const char * szName) { biobase::Open( szName, "rb" ); }
    int Open( const char* szName ) { return biobase::Open(szName,"rb"); }
    int Eof() { return feof(pFile); }	// 必须在读入函数之后，Seek之前
    int Read( void *buffer, int byteSize);	// 如果成功返回1, 否则返回0
    int ReadHeader();	// 读取数据库表识字符串和版本号，如果版本号大于当前支持的版本号返回0

    bifstream & operator >> ( char & );
    bifstream & operator >> ( unsigned char & );
    bifstream & operator >> ( short & );
    bifstream & operator >> ( unsigned short & );
    bifstream & operator >> ( int &);
    bifstream & operator >> ( unsigned int &);
    bifstream & operator >> ( long &);
    bifstream & operator >> ( unsigned long &);
    bifstream & operator >> ( float &);
    bifstream & operator >> ( double &);
    bifstream & operator >> ( long double &);
};


biobase的定义

biobase::biobase(const char * szName, char *mode )
{
    Open( szName, mode );
}
int biobase::Open( const char* szName, char * mode )
{
    pFile = fopen( szName, mode );
    return pFile!=NULL;
}
void biobase::Close()
{
    if( pFile ) fclose(pFile);
    pFile = NULL;
}


biobase的声明

// 处理二进制的文本io
class CLASS_DECLSPEC biobase
{
protected:
    FILE * pFile;
public:
    biobase() { pFile=NULL; }
    ~biobase() { Close(); }
    biobase(const char * szName, char *mode );
    int Open( const char* szName, char * mode );
    void Close();
    int operator !() { return pFile==NULL; }
    int IsOpen() { return pFile!=NULL; }
    int IsGood() { return !ferror(pFile); }
    void ClearError() { clearerr(pFile); }
    long TellPos() { return ftell(pFile); }
    // orgin的取值范围为SEEK_SET,SEEK_CUR,SEEK_END
    int Seek( long pos, int orgin ) { return fseek(pFile, pos, orgin)==0; }
    void Rewind() { rewind(pFile); }
};


bofstream的定义

bofstream::bofstream() : biobase()
{
#if defined( _DEBUG )
    nFilePos = -1;
#endif
}

bofstream::bofstream(const char * szName)
{
    biobase::Open( szName, "wb" );
#if defined( _DEBUG )
    nFilePos = -1;
#endif
}
int bofstream::Write( const void * buffer, int byteSize ) {
    if( byteSize <= 0 ) return 1;
    return fwrite(buffer,byteSize,1,pFile)==1;
}

void bofstream::WriteHeader() {
    short nCurVersion = SUPPORTVERSION;
    Write( strSap84Header, 10 );
    Write( &nCurVersion, sizeof(short) );
}

void bofstream::BeginSection()
{
#if defined( _DEBUG )
    assert( nFilePos == -1 );
#endif
    nFilePos = TellPos();
    Write( &nFilePos, sizeof(long) );
}
void bofstream::EndSection()
{
#if defined( _DEBUG )
    assert( nFilePos != -1 );
#endif
    long nPos = TellPos();
    long nSize = nPos-nFilePos-sizeof(long);
    Seek( nFilePos-nPos, SEEK_CUR );
    Write( &nSize, sizeof(long) );
    Seek( nSize, SEEK_CUR );
#if defined( _DEBUG )
    nFilePos = -1;
#endif
}

bofstream & bofstream::operator << ( const char c)
{
    Write( &c, sizeof(char) );
    return *this;
}
bofstream & bofstream::operator << ( const unsigned char c)
{
    Write( &c, sizeof(unsigned char) );
    return *this;
}
bofstream & bofstream::operator <<( const short c)
{
    Write( &c, sizeof(short) );
    return *this;
}
bofstream & bofstream::operator <<( const unsigned short c)
{
    Write( &c, sizeof(unsigned short) );
    return *this;
}
bofstream & bofstream::operator <<( const int c)
{
    Write( &c, sizeof(int) );
    return *this;
}
bofstream & bofstream::operator <<( const unsigned int c)
{
    Write( &c, sizeof(unsigned int) );
    return *this;
}
bofstream & bofstream::operator <<( const unsigned long c)
{
    Write( &c, sizeof(unsigned long) );
    return *this;
}
bofstream & bofstream::operator <<( const long c)
{
    Write( &c, sizeof(long) );
    return *this;
}
bofstream & bofstream::operator <<( const float c)
{
    Write( &c, sizeof(float) );
    return *this;
}
bofstream & bofstream::operator <<( const double c)
{
    Write( &c, sizeof(double) );
    return *this;
}
bofstream & bofstream::operator <<( const long double c)
{
    Write( &c, sizeof(long double) );
    return *this;
}


bofstream的声明

class CLASS_DECLSPEC bofstream: public biobase
{
private:
    long nFilePos;
public:
    bofstream();
    bofstream(const char * szName);
    int Open( const char* szName ) { return biobase::Open( szName, "wb" ); }
    int Flush() { return fflush(pFile); }
    int Write( const void * buffer, int byteSize );	// 如果成功返回1, 否则返回0
    void WriteHeader();	// 写入数据库表识字符串和版本号
    // 下面两个函数必须成对出现
    void BeginSection();	// 留出4个字节，用来写入该数据段所占的字节数
    void EndSection();		// 在BeginSection中留出的4个字节中写入该数据段所占的字节数

    bofstream & operator << ( const char );
    bofstream & operator << ( const unsigned char );
    bofstream & operator << ( const short );
    bofstream & operator << ( const unsigned short );
    bofstream & operator << ( const int );
    bofstream & operator << ( const unsigned int );
    bofstream & operator << ( const long );
    bofstream & operator << ( const unsigned long );
    bofstream & operator << ( const float );
    bofstream & operator << ( const double );
    bofstream & operator << ( const long double );

};


C++类库声明汇总

可变数组类：MMemBlock MArrayBase MArray MArraySort MArrayID

二进制文件流类：biobase bifstream bofstream

辅助类：DElementLoad DNumFactors DTightWireIndex DLoadPoints DWeightFactor DDataSection

支持数据库文件的基本类库：
DLevelBase DLayerBase DMaterial DTightWire DCommonData DSpectrumCurve DSpectrum
DSpectrumDir DEigen DReinforce DCombFactor DHistory DHistoryCurve DHistoryLoad

DNodeSpring DNodeBase DNodeConstraint DNodeLoad DNodeMass DNodeDisplacement
DFrameBase DFrameLoad DFrameSect DSframeBase DSframeSect DSframeLoad
DTrussBase DTrussSect DCframeBase DCframeLoad DCframeSect
DVframeBase DVframeLoad DVframeSect DPipeBase DPipeSect DPlaneBase DPlaneLoad
DThreedBase DThreedLoad DSol21Base DSol21Load DSol8rBase DSol8rLoad
DS16Base DS16Load DShellBase DShellLoad DWallBase DWallLoad


C++类库实现汇总

二进制文件流类：biobase bifstream bofstream

辅助类：DElementLoad DNumFactors DTightWireIndex DLoadPoints DWeightFactor

支持数据库文件的基本类库：
DLevelBase DLayerBase DMaterial DTightWire DCommonData DSpectrumCurve DSpectrum DDataSection
DSpectrumDir DEigen DReinforce DCombFactor DHistory DHistoryCurve DHistoryLoad

DNodeSpring DNodeBase DNodeConstraint DNodeLoad DNodeMass DNodeDisplacement
DFrameBase DFrameLoad DFrameSect DSframeBase DSframeSect DSframeLoad
DTrussBase DTrussSect DCframeBase DCframeLoad DCframeSect
DVframeBase DVframeLoad DVframeSect DPipeBase DPipeSect DPlaneBase DPlaneLoad
DThreedBase DThreedLoad DSol21Base DSol21Load DSol8rBase DSol8rLoad
DS16Base DS16Load DShellBase DShellLoad DWallBase DWallLoad


DCframeBase的实现

DCframeBase::DCframeBase( )
{
    nID = 0;
    nLevel = 1;
    nLayer = 1;
    nI = nJ = 0;
    nSect = nMat = 0;
    nType = 0;
    H = B = (float)0.0;
    for( int i = 0; i < 5; i ++ ) {
        X[i] = Y[i] = (float)0.0;
    }
    for( i = 0; i < 3; i ++ )
        Local[i] = (float)0.0;
    nRMi2 = nRMi3 = nRMj2 = nRMj3 = nRTor = nRAxis = 100;
    nAct = 1;
}
DCframeBase::DCframeBase( int i, int j )
{
    nID = 0;
    nLevel = 1;
    nLayer = 1;
    nI = i;
    nJ = j;
    nSect = nMat = 0;
    nType = 0;
    H = B = (float)0.0;
    for( int k = 0; k < 5; k ++ ) {
        X[k] = Y[k] = (float)0.0;
    }
    for( i = 0; i < 3; i ++ )
        Local[i] = (float)0.0;
    nRMi2 = nRMi3 = nRMj2 = nRMj3 = nRTor = nRAxis = 100;
    nAct = 1;
}
DCframeBase::DCframeBase( const DCframeBase & Copy)
{
    *this = Copy;
}
DCframeBase::~DCframeBase( )
{
}
DCframeBase & DCframeBase::operator = ( const DCframeBase & Copy )
{
    if( this != &Copy ) {
        nID = Copy.nID;
        nLevel = Copy.nLevel;
        nLayer = Copy.nLayer;
        nI = Copy.nI;
        nJ = Copy.nJ;
        nSect = Copy.nSect;
        nMat = Copy.nMat;
        nType = Copy.nType;
        H = Copy.H;
        B = Copy.B;
        for( int i = 0; i < 5; i ++ ) {
            X[i] = Copy.X[i];
            Y[i] = Copy.Y[i];
        }
        for( i = 0; i < 3; i ++ )
            Local[i] = Copy.Local[i];
        nRMi2 = Copy.nRMi2;
        nRMi3 = Copy.nRMi3;
        nRMj2 = Copy.nRMj2;
        nRMj3 = Copy.nRMj3;
        nRTor = Copy.nRTor;
        nRAxis = Copy.nRAxis;
        Load = Copy.Load;
        nAct = Copy.nAct;
    }
    return *this;
}
int DCframeBase::operator == ( const DCframeBase & Other )
{
    return ((nI==Other.nI)&&(nJ==Other.nJ))||((nI==Other.nJ)&&(nJ==Other.nI));
}
void DCframeBase::SetCircle( double h )
{
    H = (float)h;
    nType = 1;
}
void DCframeBase::SetParabola( double h )
{
    H = (float)h;
    nType = 2;
}
void DCframeBase::SetHyperbola( double h, double b )
{
    H = (float)h;
    B = (float)b;
    nType = 3;
}
void DCframeBase::SetSpline( double x[5], double y[5] )
{
    for( int i = 0; i < 5; i ++ ) {
        X[i] = (float)x[i];
        Y[i] = (float)y[i];
    }
    nType = 4;
}

int DCframeBase::GetCircle( double & h )
{
    h = H;
    return IsCircle();
}
int DCframeBase::GetParabola( double & h )
{
    h = H;
    return IsParabola();
}
int DCframeBase::GetHyperbola( double & h, double & b )
{
    h = H;
    b = B;
    return IsHyperbola();
}
int DCframeBase::GetSpline( double x[5], double y[5] )
{
    for( int i = 0; i < 5; i ++ ) {
        x[i] = X[i];
        y[i] = Y[i];
    }
    return IsSpline();
}

void DCframeBase::Serialize( bofstream & fout )
{
    fout << nID << nLevel << nLayer << nI << nJ << nSect << nMat;
    fout << nType << H << B;
    fout.Write( X, sizeof(float)*5 );
    fout.Write( Y, sizeof(float)*5 );
    fout.Write( Local, sizeof(float)*3 );
    fout << nRMi2 << nRMi3 << nRMj2 << nRMj3 << nRTor << nRAxis;
    Load.Serialize( fout );
    fout << nAct;
}
void DCframeBase::Serialize( bifstream & fin )
{
    fin >> nID >> nLevel >> nLayer >> nI >> nJ >> nSect >> nMat;
    fin >> nType >> H >> B;
    fin.Read( X, sizeof(float)*5 );
    fin.Read( Y, sizeof(float)*5 );
    fin.Read( Local, sizeof(float)*3 );
    fin >> nRMi2 >> nRMi3 >> nRMj2 >> nRMj3 >> nRTor >> nRAxis;
    Load.Serialize( fin );
    if( nVersion > 100 ) fin >> nAct;
}


DCframeBase的声明

class CLASS_DECLSPEC DCframeBase {
public:
    int nID;		// 单元号，如果要用于array.h中的MArrayID类，其名称必须为nID
        short nLevel;   // 层标识号(指向DLevelBase的nID)，层号=nID-2
    short nLayer;	// (指向DLayerBase的nID)，与层号相互独立，缺省为1
        int nI,nJ;      // node I, node J.
    // 分别指向类DCframeSect(即DFrameSect)、DMaterial数组的nID
        short nSect,nMat;// 截面号和材料号, 该号指向截面或材料类的nID数据成员
    unsigned char nType;//  nType =1,2,3,4分别对应于四种不同的曲梁
    float H, B;		//  曲梁中点处梁的高度和四分之一梁跨处梁的高度
                    //  分别用于定义第(1,2,3)和(3)类曲梁
    float X[5],Y[5];	//  Spline插值点在局部坐标系中的坐标
                        //  用来定义第4类曲梁
        float Local[3];	// 局部坐标系2轴所指方向的坐标，生成数据文件时需做一定的处理
    unsigned char nRMi2,nRMi3,nRMj2,nRMj3,nRTor,nRAxis;
                    // I、J端两个方向(2和3)弯矩放松因子和扭矩、轴力放松因子
                    // 取值范围0-100, 缺省值为100(刚性连接)，0表示完全放松
    // Load[i].LocalID指向类DCframeLoad数组的nID
        DElementLoad  Load;//
    用于描述各总体荷载种类(荷载种类)下作用的跨内荷载 short nAct; // 施工模拟的步号(one-based)
public:
    DCframeBase();
    DCframeBase( int i, int j );
    DCframeBase( const DCframeBase & Copy);
    virtual ~DCframeBase();
    DCframeBase & operator = ( const DCframeBase & Copy );
    int operator == ( const DCframeBase & Other );
    // 曲梁为圆弧，自动设置类型参数Type=1
    void SetCircle( double h );
    // 曲梁为抛物线，自动设置类型参数Type=2
    void SetParabola( double h );
    // 曲梁为双曲线，自动设置类型参数Type=3
    void SetHyperbola( double h, double b );
    // 曲梁为平面二次曲线，自动设置类型参数Type=4
    void SetSpline( double x[5], double y[5] );
    int IsCircle( ) { return nType == 1; }
    int IsParabola( ) { return nType == 2; }
    int IsHyperbola( ) { return nType == 3; }
    int IsSpline( ) { return nType == 4; }
    int GetCircle( double & h );
    int GetParabola( double & h );
    int GetHyperbola( double & h, double & b );
    int GetSpline( double x[5], double y[5] );

    virtual void Serialize( bifstream & fin );
    virtual void Serialize( bofstream & fout );
};


DCframeForce的实现

DCframeForce::DCframeForce()
{
    nID = 0;
    memset( FI, 0x00, sizeof(double)*6 );
    memset( FJ, 0x00, sizeof(double)*6 );
}
DCframeForce::DCframeForce( DCframeForce & Copy )
{
    *this = Copy;
}
DCframeForce & DCframeForce::operator = ( const DCframeForce & Copy )
{
    if( this != &Copy ) {
        nID = Copy.nID;
        memcpy( FI, Copy.FI, sizeof(FI) );
        memcpy( FJ, Copy.FJ, sizeof(FJ) );
    }
    return *this;
}
void DCframeForce::Serialize(bofstream & fout)
{
    fout << nID;
    fout.Write( FI, sizeof(FI) );
    fout.Write( FJ, sizeof(FJ) );
}
void DCframeForce::Serialize(bifstream & fin)
{
    fin >> nID;
    fin.Read( FI, sizeof(FI) );
    fin.Read( FJ, sizeof(FJ) );
}


DCframeForce的声明

class CLASS_DECLSPEC DCframeForce {
public:
    // 单元号或组合号
    int nID;
    // I端的轴力、1-2平面内的剪力和弯矩、1-3平面内的剪力和弯矩、扭矩
    double FI[6];
    // J端的轴力、1-2平面内的剪力和弯矩、1-3平面内的剪力和弯矩、扭矩
    double FJ[6];
public:
    DCframeForce();
    DCframeForce( DCframeForce & Copy );
    virtual ~DCframeForce() {}
    DCframeForce & operator = ( const DCframeForce & Copy );
    // 尽管下面两个函数暂时没有用处，但是为了方便定义可变数组类对象还是定义了这两个函数
    void Serialize(bofstream & fout);
    void Serialize(bifstream & fin);
};


DCframeLoad的实现

DCframeLoad::DCframeLoad()
{
    nID = 0;
    T = Nor = (float)0.0;
    for( int i = 0; i < 3; i ++ ) L[i] = (float)0.0;
}
DCframeLoad::DCframeLoad( DCframeLoad & Copy )
{
    *this = Copy;
}
DCframeLoad::~DCframeLoad()
{
}
DCframeLoad & DCframeLoad::operator = ( const DCframeLoad & Copy )
{
    if( this != &Copy ) {
        nID = Copy.nID;
        T = Copy.T;
        Nor = Copy.Nor;
        for( int i = 0; i < 3; i ++ ) {
            L[i] = Copy.L[i];
            F[i] = Copy.F[i];
            M[i] = Copy.M[i];
        }
    }
    return *this;
}
int DCframeLoad::operator == ( const DCframeLoad & Other )
{
    double tmp;
    tmp = T - Other.T;
    if( tmp < -LoadError || tmp > LoadError ) return 0;
    tmp = Nor - Other.Nor;
    if( tmp < -LoadError || tmp > LoadError ) return 0;
    for( int i = 0; i < 3; i ++ ) {
        tmp = L[i] - Other.L[i];
        if( tmp < -LoadError || tmp > LoadError ) return 0;
        if( !(F[i] == Other.F[i]) ) return 0;
        if( !(M[i] == Other.M[i]) ) return 0;
    }
    return 1;
}

void DCframeLoad::Serialize( bofstream & fout )
{
    fout << nID << T << Nor;
    fout.Write( L, sizeof(float)*3 );
    F[0].Serialize( fout );
    F[1].Serialize( fout );
    F[2].Serialize( fout );
    M[0].Serialize( fout );
    M[1].Serialize( fout );
    M[2].Serialize( fout );
}
void DCframeLoad::Serialize( bifstream & fin )
{
    fin >> nID >> T >> Nor;
    fin.Read( L, sizeof(float)*3 );
    F[0].Serialize( fin );
    F[1].Serialize( fin );
    F[2].Serialize( fin );
    M[0].Serialize( fin );
    M[1].Serialize( fin );
    M[2].Serialize( fin );
}


DCframeLoad的声明

// CFRAME单元垮内分布荷载
class CLASS_DECLSPEC DCframeLoad {
public:
    int nID;
    float T; // 沿曲梁弧线的升温
    // 沿曲梁弧线外法向的均布荷载密度
    float Nor;
    // 在局部坐标系下的均布荷载L[3], L=W1 W2 W3
    float L[3];
    DLoadPoints F[3];	// 三个局部坐标轴方向的跨内集中力
    DLoadPoints M[3];	// 三个局部坐标轴方向的跨内集中弯矩
public:
    DCframeLoad();
    DCframeLoad( DCframeLoad & Copy );
    virtual ~DCframeLoad();
    DCframeLoad & operator = ( const DCframeLoad & Copy );
    int operator == ( const DCframeLoad & Other );

    virtual void Serialize( bofstream & fout );
    virtual void Serialize( bifstream & fin );
};


DCframeSect的声明

typedef DFrameSect DCframeSect;


DCombFactor的实现

DCombFactor::DCombFactor()
{
    nSeismicType = 2;
    nDynCombType = 2;
    nResNo = 0;
    ResFactor = (float)0.0;
    actComb = 0.0f;
}
DCombFactor::DCombFactor( const DCombFactor & Copy )
{
    *this = Copy;
}
DCombFactor::~DCombFactor()
{
}
DCombFactor & DCombFactor::operator =( const DCombFactor & Copy)
{
    if( this != &Copy ) {
        staFactor = Copy.staFactor;
        nSeismicType = Copy.nSeismicType;
        eqFactor = Copy.eqFactor;
        nDynCombType = Copy.nDynCombType;
        nResNo = Copy.nResNo;
        ResFactor = Copy.ResFactor;
        actComb = Copy.actComb;
    }
    return *this;
}
int DCombFactor::operator ==( const DCombFactor & Other)
{
    double tmp;
    if( !(staFactor==Other.staFactor) ) return 0;
    if( nSeismicType != Other.nSeismicType ) return 0;
    if( !(eqFactor==Other.eqFactor) ) return 0;
    if( nResNo != Other.nResNo ) return 0;
    if( nResNo > 0 ) {
        if( nDynCombType != Other.nDynCombType ) return 0;
        tmp = ResFactor - Other.ResFactor;
        if( tmp < -CombinationError || tmp > CombinationError ) return 0;
    }
    tmp = actComb-Other.actComb;
    if( tmp > CombinationError || tmp < -CombinationError ) return 0;
    return 1;
}
void DCombFactor::Serialize(bofstream & fout)
{
    staFactor.Serialize(fout);
    fout << nSeismicType;
    eqFactor.Serialize(fout);
    fout << nDynCombType << nResNo << ResFactor;
    fout << actComb;
}
void DCombFactor::Serialize(bifstream & fin)
{
    staFactor.Serialize(fin);
    fin >> nSeismicType;
    eqFactor.Serialize(fin);
    fin >> nDynCombType >> nResNo >> ResFactor;
    if( nVersion > 100 ) fin >> actComb;
}


DCombFactor的声明

// 位移或力(两者可以分开)的组合系数 无需nID数据成员，数组不需排序
class CLASS_DECLSPEC DCombFactor {
public:
    DNumFactors staFactor;	// 静载组合系数
    // 地震组合的类型: 1(E)，2(A)，3(Q)   (只能有一种)[2]
    unsigned char nSeismicType;
    // 地震组合系数，写sap84数据文件时填E=、A=、Q=依赖于nSeismicType
    DNumFactors eqFactor;
    // 1:Dynamic的代数和相加 EDI=...  2:Dynamic的绝对值相加 ADI=...
    // 3:Step的代数和相加 ETI=...  4:Step的绝对值相加 ATI=...  [2]
    // 尽管SAP84允许EDI(or ADI)与ETI(or ATI)同时存在，这里则不允许同时存在
    unsigned char nDynCombType;
    int nResNo;			// 与静力进行组合时动力时程响应的步长号(响应号), 0表示不考虑动力响应组合
    float ResFactor;	// 动力响应组合系数(STEP和DYNAMIC使用相同的系数,对应与nI)
    float actComb; // 施工模拟结果的组合系数
public:
    DCombFactor();
    DCombFactor( const DCombFactor & Copy );
    virtual ~DCombFactor();
    DCombFactor & operator = ( const DCombFactor & Copy );
    int operator == ( const DCombFactor & Other );

    virtual void Serialize( bofstream & fout );
    virtual void Serialize( bifstream & fin );
};


DCommonData的实现

DCommonData::DCommonData()
{
    Initialize();
}
DCommonData::~DCommonData()
{
}
void DCommonData::Initialize()
{
    nPlaneType = 2;
    nGaoshi1 = nGaoshi2 = nGaoshi3 = 2;
    nUnit = nStable = 0;
    weightFactor.Clear();
    tempFactor.Clear();
    tightwireFactor.Clear();
    loadConVelo.Clear();
    loadConAcce.Clear();
    actType = 0;
    actNum = 1;
}
DCommonData & DCommonData::operator = ( DCommonData & Copy )
{
    if( this != &Copy ) {
        nPlaneType = Copy.nPlaneType;
        nGaoshi1 = Copy.nGaoshi1;
        nGaoshi2 = Copy.nGaoshi2;
        nGaoshi3 = Copy.nGaoshi3;
        nUnit = Copy.nUnit;
        nStable = Copy.nStable;
        weightFactor = Copy.weightFactor;
        tempFactor = Copy.tempFactor;
        tightwireFactor = Copy.tightwireFactor;
        loadConVelo = Copy.loadConVelo;
        loadConAcce = Copy.loadConAcce;
        actType = Copy.actType;
        actNum = Copy.actNum;
    }
    return *this;
}
double DCommonData::ForceFactor( int unit )
{
    if( unit == 0 || unit == 1 ) return 1.0;
    else if( unit == 2 || unit == 4 ) return 1000.0;
    else if( unit == 3 ) return 1000000.0;
    return 1.0;
}

double DCommonData::MassFactor( int unit )
{
    return ForceFactor(unit)/DimensionFactor(unit);
}

double DCommonData::DimensionFactor( int unit )
{
    if( unit == 0 || unit == 2 ) return 1.0;
    else if( unit == 3 || unit == 4 ) return 1000.0;
    else if( unit == 1 ) return 100.0;
    return 1.0;
}
void DCommonData::Serialize( bofstream & fout )
{
    fout << nPlaneType << nGaoshi1 << nGaoshi2 << nGaoshi3;
    fout << nUnit << nStable;
    weightFactor.Serialize(fout);
    tempFactor.Serialize(fout);
    loadConVelo.Serialize(fout);
    loadConAcce.Serialize(fout);
    fout << actType;
    tightwireFactor.Serialize(fout);
    fout << actNum;
}
void DCommonData::Serialize( bifstream & fin )
{
    fin >> nPlaneType >> nGaoshi1 >> nGaoshi2 >> nGaoshi3;
    fin >> nUnit >> nStable;
    weightFactor.Serialize(fin);
    tempFactor.Serialize(fin);
    loadConVelo.Serialize(fin);
    loadConAcce.Serialize(fin);
    if( nVersion > 100 ) {
        fin >> actType;
        if( nVersion > 110 ) tightwireFactor.Serialize(fin);
        if( nVersion > 111 ) fin >> actNum;
    }
}


DCommonData的声明

class CLASS_DECLSPEC DCommonData {
public:
    unsigned char nPlaneType;//  平面单元的类型( 0 - 4 )，缺省为平面应力单元	[2]
                        //  0：Y-Z平面内的轴对称体单元
                        //  1：Y-Z平面内的平面应变单元
                        //  2：Y-Z平面内的平面应力单元
                        //  3：X-Y-Z空间内的平面应力膜单元
                        //  4：X-Y-Z空间内的可受扭矩的轴对称体单元
    // 三个自然坐标系方向的高斯积分阶数(缺省均为2)，对平面单元而言高斯
    // 积分点数等于nGaoshi1*nGaoshi2，对三维单元而言为nGaoshi1*nGaoshi2*nGaoshi3	[2]
    unsigned char nGaoshi1, nGaoshi2, nGaoshi3;
    unsigned char nUnit;	// 0:kN-kkg-m 1:kN-100kkg-cm 2:N-kg-m 3:mN-kg-mm 4:N-kkg-mm [0]
    unsigned char nStable;	// 是否计算整体稳定性，即是否输出stability数据段 [0]
    // 用于决定重力荷载和温度荷载在各个荷载种类下的载荷因子
    // 即sap84数据文件中各单元第一部分数据的X=X1 X2 ...Xnl Y=... Z=... T=...
    // 各单元信息中不再保留相关信息
    DWeightFactor weightFactor;
    // 用于决定温度荷载在各个荷载种类下的载荷因子
    DNumFactors tempFactor;
    // 用于决定预应力钢索在各个荷载种类下的载荷因子
    DNumFactors tightwireFactor;
    // 下面两行是为轴对称平面单元服务的
    DNumFactors loadConVelo;	// 各荷载种类对应的角速度值
    DNumFactors loadConAcce;	// 各荷载种类对应的角加速度值
    unsigned char actType; // 施工模拟的方法: 0-不做施工模拟 1-逐层找平 2-分层计算，但采用完整结构 3-从顶向下计算
    short actNum; // 施工模拟的步数
public:
    DCommonData();
    virtual ~DCommonData();
    void Initialize();
    DCommonData & operator = ( DCommonData & Copy );
    // 千牛.吨.米单位制转换到单位制unit, 力值需要乘的系数
    static double ForceFactor( int unit );
    // 千牛.吨.米单位制转换到单位制unit, 质量需要乘的系数
    static double MassFactor( int unit );
    // 千牛.吨.米单位制转换到单位制unit, 长度需要乘的系数
    static double DimensionFactor( int unit );

    virtual void Serialize( bifstream & fin );
    virtual void Serialize( bofstream & fout );
};


DWallLoad的声明

// 这个类用于存储各个数据段的引导字符串
class CLASS_DECLSPEC DDataSection {
public:
    static const char * LevelStr;
    static const char * LayerStr;
    static const char * MatStr;
    static const char * TightWireStr;
    static const char * SpringStr;
    static const char * NodeStr;
    static const char * NdMassStr;
    static const char * NdDispStr;
    static const char * NdLoadStr;
    static const char * NdConsStr;
    static const char * FrameStr;
    static const char * FrSectStr;
    static const char * FrLoadStr;
    static const char * SframeStr;
    static const char * SfrSectStr;
    static const char * SfrLoadStr;
    static const char * TrussStr;
    static const char * TruSectStr;
    static const char * CframeStr;
    static const char * CfrSectStr;
    static const char * CfrLoadStr;
    static const char * VframeStr;
    static const char * VfrSectStr;
    static const char * VfrLoadStr;
    static const char * PipeStr;
    static const char * PipSectStr;
    static const char * PlaneStr;
    static const char * PlaLoadStr;
    static const char * ThreedStr;
    static const char * ThrLoadStr;
    static const char * Sol21Str;
    static const char * Sol21LoadStr;
    static const char * Sol8rStr;
    static const char * Sol8rLoadStr;
    static const char * S16Str;
    static const char * S16LoadStr;
    static const char * ShellStr;
    static const char * ShellLoadStr;
    static const char * WallStr;
    static const char * WallLoadStr;
    static const char * CommDataStr;
    static const char * SpecStr;
    static const char * SpecDirStr;
    static const char * SpecCurStr;
    static const char * EigenStr;
    static const char * ReinStr;
    static const char * ForeCombStr;
    static const char * DispCombStr;
    static const char * HistStr;
    static const char * HistCurvStr;
    static const char * HistLoadStr;
};

const char * DDataSection::LevelStr="LEVELINF";
const char * DDataSection::LayerStr="LAYERINF";
const char * DDataSection::MatStr="MATERIAL";
const char * DDataSection::TightWireStr="FRAMETIW";
const char * DDataSection::SpringStr="NODESPRI";
const char * DDataSection::NodeStr="NODEELEM";
const char * DDataSection::NdMassStr="NODEMASS";
const char * DDataSection::NdDispStr="NODEDISP";
const char * DDataSection::NdLoadStr="NODELOAD";
const char * DDataSection::NdConsStr="NODECONS";
const char * DDataSection::FrameStr="FRAMEELE";
const char * DDataSection::FrSectStr="FRAMESEC";
const char * DDataSection::FrLoadStr="FRAMELOA";
const char * DDataSection::SframeStr="SFRAMELE";
const char * DDataSection::SfrSectStr="SFRAMSEC";
const char * DDataSection::SfrLoadStr="SFRAMLOA";
const char * DDataSection::TrussStr="TRUSSELE";
const char * DDataSection::TruSectStr="TRUSSSEC";
const char * DDataSection::CframeStr="CFRAMELE";
const char * DDataSection::CfrSectStr="CFRAMSEC";
const char * DDataSection::CfrLoadStr="CFRAMLOA";
const char * DDataSection::VframeStr="VFRAMELE";
const char * DDataSection::VfrSectStr="VFRAMSEC";
const char * DDataSection::VfrLoadStr="VFRAMLOA";
const char * DDataSection::PipeStr="PIPEELEM";
const char * DDataSection::PipSectStr="PIPESECT";
const char * DDataSection::PlaneStr="PLANEELE";
const char * DDataSection::PlaLoadStr="PLANELOA";
const char * DDataSection::ThreedStr="THREEELE";
const char * DDataSection::ThrLoadStr="THREELOA";
const char * DDataSection::Sol21Str="SOL21ELE";
const char * DDataSection::Sol21LoadStr="SOL21LOA";
const char * DDataSection::Sol8rStr="SOL8RELE";
const char * DDataSection::Sol8rLoadStr="SOL8RLOA";
const char * DDataSection::S16Str="S16ELEME";
const char * DDataSection::S16LoadStr="S16LOADE";
const char * DDataSection::ShellStr="SHELLELE";
const char * DDataSection::ShellLoadStr="SHELLLOA";
const char * DDataSection::WallStr="WALLELEM";
const char * DDataSection::WallLoadStr="WALLLOAD";
const char * DDataSection::CommDataStr="COMMDATA";
const char * DDataSection::SpecStr="SPECDATA";
const char * DDataSection::SpecDirStr="SPECTDIR";
const char * DDataSection::SpecCurStr="SPECCURV";
const char * DDataSection::EigenStr="EIGENCOM";
const char * DDataSection::ReinStr="REINCOMM";
const char * DDataSection::ForeCombStr="FORCECOM";
const char * DDataSection::DispCombStr="DISPCOMB";
const char * DDataSection::HistStr="HISTCOMM";
const char * DDataSection::HistCurvStr="HISTCURV";
const char * DDataSection::HistLoadStr="HISTLOAD";


DEigen的实现

DEigen::DEigen()
{
    Initialize();
}
DEigen::DEigen(const DEigen & Copy)
{
    *this = Copy;
}
DEigen & DEigen::operator =(const DEigen & Copy)
{
    if( this != &Copy ) {
        nValid = Copy.nValid;
        nType = Copy.nType;
        nEigenNum = Copy.nEigenNum;
        Tolerance = Copy.Tolerance;
        nSturm = Copy.nSturm;
        SelectPara = Copy.SelectPara;
        nPurpose = Copy.nPurpose;
    }
    return *this;
}
void DEigen::Initialize()
{
    nValid = 1;
    nType = 1;
    nEigenNum = 10;
    Tolerance = (float)0.1E-5;
    nSturm = 0;
    SelectPara = 0.0;
    nPurpose = 1;
}
int DEigen::operator ==(const DEigen & Other)
{
    double tmp;
    if( nValid != Other.nValid ) return 0;
    if( nType != Other.nType ) return 0;
    if( nEigenNum != Other.nEigenNum ) return 0;
    tmp = Tolerance - Other.Tolerance;
    if( tmp < -1.0E-6 || tmp > 1.0E-6 ) return 0;
    if( nSturm != Other.nSturm ) return 0;
    if( nType == 2 || nType == 3 ) {
        tmp = SelectPara - Other.SelectPara;
        if( tmp < -1.0E-4 || tmp > 1.0E-4 ) return 0;
        if( nPurpose != Other.nPurpose ) return 0;
    }
    return 1;
}
void DEigen::SetRitzPara(int eigennum, int purpose,
                           double selectpara, double tolerance)
{
    nType = 1;
    nEigenNum = eigennum;
    nPurpose = purpose;
    SelectPara = (float)selectpara;
    Tolerance = (float)tolerance;
}
void DEigen::SetEigenPara(int eigennum, double tolerance)
{
    nType = 2;
    nEigenNum = eigennum;
    Tolerance = (float)tolerance;
}
void DEigen::SetLanczosPara(int eigennum, int purpose,
                           double selectpara )
{
    nType = 3;
    nEigenNum = eigennum;
    nPurpose = purpose;
    SelectPara = (float)selectpara;
}
void DEigen::Serialize(bofstream & fout)
{
    fout << nValid << nType << nEigenNum << Tolerance << nSturm;
    fout << SelectPara << nPurpose;
}
void DEigen::Serialize(bifstream & fin)
{
    fin >> nValid >> nType >> nEigenNum >> Tolerance >> nSturm;
    fin >> SelectPara >> nPurpose;
}


DEigen的声明

class CLASS_DECLSPEC DEigen {
public:
    // 是否计算振型, 数据的存取不受nValid的影响 [1]
    unsigned char nValid;
    // 振型计算方法 1：RITZ方法 2：EIGEN方法 3：LANCZOS方法  [1]
    unsigned char nType;
    short nEigenNum;	// 需要的特征值个数[10](计算的特征向量取两倍)
    float Tolerance;	// 精度允许值(误差允许值) C=C1或E=ER [0.1E-5]
    unsigned char nSturm;	// 是否进行sturm校验和迭代
        // 以下参数只对nType=1、3有效，但不影响存取
    // 振型选择参数 C=C1  [0]
    float SelectPara;
    // 分析目的参数 M=M1 1：一般的特征分析  2：为动力分析DYNAMIC做准备
    //	 3：为地震反应谱分析做准备  [1]
    unsigned char nPurpose;
public:
    DEigen();
    DEigen( const DEigen & Copy );
    DEigen & operator = ( const DEigen & Copy );
    void Initialize();
    int operator == ( const DEigen & Other );
    void SetRitzPara( int eigennum,int purpose = 1,
        double selectpara = 0.0, double tolerance = 0.0001 );
    void SetEigenPara( int eigennum, double tolerance = 0.0001 );
    void SetLanczosPara( int eigennum,int purpose = 1,
        double selectpara = 0.0 );

    void SetValid() { nValid = 1; }
    void SetUnvalid() { nValid = 0; }
    int IsValid() { return nValid; }

    int IsRitzMethod( ) { return nType == 1; }
    int IsEigenMethod( ) { return nType == 2; }
    int IsLanzosMethod( ) { return nType == 3; }

    virtual void Serialize( bofstream & fout );
    virtual void Serialize( bifstream & fin );
};


DElementLoadIndex的实现

DElementLoad::DElementLoad()
{
    nNum = 0;
    ld = NULL;
}
DElementLoad::~DElementLoad()
{
    Clear();
}
DElementLoad & DElementLoad::operator = ( const DElementLoad & Copy )
{
    if( this != &Copy ) {
        Clear();
        nNum = Copy.nNum;
        if( nNum > 0 ) {
            ld = (DLoadIndex*)malloc( sizeof(DLoadIndex)*nNum );
            memcpy( ld, Copy.ld, sizeof(DLoadIndex)*nNum );
        }
    }
    return (*this);
}
int DElementLoad::operator==( const DElementLoad & Other) const
{
    if( nNum != Other.nNum ) return 0;
    for( int i = 0; i < nNum; i ++ ) {
        if( ld[i].Global != ld[i].Global ) return 0;
        if( ld[i].LocalID != ld[i].LocalID ) return 0;
    }
    return 1;
}
DLoadIndex & DElementLoad::operator[](const int index)
{
    assert(index<nNum && index>=0);
    return ld[index];
}
int DElementLoad::Index( short global )
{
    int i=0, j=nNum-1, tmp;
    while( i <= j ) {
        tmp = ((i+j)>>1);
        if( ld[tmp].Global < global ) i = tmp+1;
        else if( ld[tmp].Global == global ) return tmp;
        else j = tmp-1;
    }
    return -1;
}
int DElementLoad::Insert( short global, int localID )
{
    if( global <= 0 ) return 0;
    int i=0, j=nNum-1, tmp;
    while( i <= j ) {
        tmp = ((i+j)>>1);
        if( ld[tmp].Global < global ) i = tmp+1;
        else if( ld[tmp].Global == global ) {
            if( localID <= 0 ) {	// 删除
                if( nNum == 1 ) Clear();
                else {
                    for( j = tmp; j < nNum-1; j ++ ) ld[j] = ld[j+1];
                    nNum --;
                    ld = (DLoadIndex*)realloc( ld, sizeof(DLoadIndex)*nNum );
                }
            }
            else ld[tmp].LocalID = localID;
            return 1;
        }
        else j = tmp-1;
    }
    if( localID <= 0 ) return 0;
    nNum ++;
    ld = (DLoadIndex*)realloc( ld, sizeof(DLoadIndex)*nNum );
    for( j = nNum-1; j > i; j -- ) ld[j] = ld[j-1];
    ld[i].Global = global;
    ld[i].LocalID = localID;
    return 1;
}
void DElementLoad::RemoveAt( const int i )
{
    if( i < 0 || i >= nNum ) return;
    if( nNum <= 1 ) {
        Clear();
        return;
    }
    for( int j = i; j < nNum-1; j ++ ) ld[j] = ld[j+1];
    nNum --;
}
void DElementLoad::Clear()
{
    nNum = 0;
    if( ld ) {
        free(ld);
        ld = NULL;
    }
}
void DElementLoad::SetSize( int num )
{
    nNum = num;
    ld = (DLoadIndex*)realloc( ld, sizeof(DLoadIndex)*nNum );
}
void DElementLoad::Serialize( bofstream & fout )
{
    fout << nNum;
    for( int i = 0; i < nNum; i ++ ) {
        fout << ld[i].Global << ld[i].LocalID;
    }
}

void DElementLoad::Serialize( bifstream & fin )
{
    Clear();
    fin >> nNum;
    if( nNum > 0 ) {
        ld = (DLoadIndex*)malloc( sizeof(DLoadIndex)*nNum );
        for( int i = 0; i < nNum; i ++ ) {
            fin >> ld[i].Global >> ld[i].LocalID;
        }
    }
}


DElementLoadIndex的声明

struct CLASS_DECLSPEC DLoadIndex {
    short Global;		// 荷载种类
    int LocalID;	// 单元荷载记录号
};
// 记录单元荷载与荷载种类的对应关系
class CLASS_DECLSPEC DElementLoad{
protected:
    int nNum;
    DLoadIndex *ld;	// 数据必须按Global排序
public:
    DElementLoad();
    ~DElementLoad();
    DElementLoad( const DElementLoad & Copy ) {
        (*this) = Copy;
    }
    DElementLoad & operator = ( const DElementLoad & Copy );
    int operator==( const DElementLoad &Other) const;
    int Entries() { return nNum; }
    DLoadIndex & operator[](const int index);
    // 查找荷载种类global所处的索引号，返回-1(没有找到)或大于等于0的索引值
    int Index( short global );
    // 如果localID=0, 表示删除global荷载种类, 如果global荷载种类已经存在，则作替换
    // 如果global＝0,返回0
    int Insert( short global, int localID );
    // 删除某种荷载种类
    int Remove( short global ) { return Insert( global, 0 ); }
    void RemoveAt( const int i ); // 依据位置索引号(zero-based)删除
    void Clear();
    void SetSize( int num ); // 设置nNum为num，同时分配好内存

    void Serialize( bofstream & fout );
    void Serialize( bifstream & fin );
};


DFrameBase的声明

// 模板类DFrameBase的基类sub_DSframeBase必须是DSframeBase的子类
// 把DFrameBase做成模板类的原因是您可能需要在DSframeBase和DFrameBase基础做生成子类，
// 而它们一般有许多共同的东西，您可以利用模板把共同的东西放在一起，例如：
//	class CSframe: public DSframeBase {
//		public:
//			int active;
//			......
//			void Draw();
//	};
//	class CFrame: public DFrameBase<CSframe> {
//	};
//	利用这种方式，CFrame可以集成CSframe中的一些函数，如：void Draw()等

// 此类适用于Frame
template < class sub_DSframeBase = DSframeBase >
class DFrameBase: public sub_DSframeBase {
public:
    DTightWireIndex Prestress;	// 预应力钢索
public:
    DFrameBase( ): sub_DSframeBase() {}
    DFrameBase( const int i, const int j ): sub_DSframeBase(i,j) {}
    DFrameBase( const DFrameBase & Copy): sub_DSframeBase(Copy) { Prestress = Copy.Prestress; }
    virtual ~DFrameBase() {};
    DFrameBase & operator = ( const DFrameBase & Copy ) {
        sub_DSframeBase::operator =(Copy);
        Prestress = Copy.Prestress;
        return *this;
    }
    // 判断((nI==Other.nI)&&(nJ==Other.nJ))||((nI==Other.nJ)&&(nJ==Other.nI))
    int operator == ( const DFrameBase & Other ) {
        return sub_DSframeBase::operator==(Other);
    }

    virtual void Serialize( bifstream & fin ) {
        sub_DSframeBase::Serialize(fin);
        Prestress.Serialize(fin);
    }
    virtual void Serialize( bofstream & fout ) {
        sub_DSframeBase::Serialize(fout);
        Prestress.Serialize(fout);
    }
};


DFrameForce的实现

DFrameForce::DFrameForce()
{
    nID = 0;
    nSectNum = 0;
    F = NULL;
}
DFrameForce::DFrameForce( DFrameForce & Copy )
{
    F = NULL;
    *this = Copy;
}
DFrameForce::~DFrameForce()
{
    Clear();
}
DFrameForce & DFrameForce::operator = ( const DFrameForce & Copy )
{
    if( this != &Copy ) {
        Clear();
        nID = Copy.nID;
        nSectNum = Copy.nSectNum;
        if( nSectNum > 0 ) {
            F = (double (*)[7])malloc(nSectNum*sizeof(F[0]));
            memcpy( F, Copy.F, nSectNum*sizeof(F[0]) );
        }
    }
    return *this;
}
void DFrameForce::CopyFrom( const DTrussForce & Copy, const double len )
{
    Clear();
    nID = Copy.nID;
    nSectNum = 2;
    F = (double (*)[7])malloc(2*sizeof(F[0]));
    memset( F, 0, 2*sizeof(F[0]) );
    F[1][0] = len;
    F[0][1] = F[1][1] = Copy.Axis;
}
void DFrameForce::CopyFrom( const DCframeForce & Copy, const double len )
{
    Clear();
    nID = Copy.nID;
    nSectNum = 2;
    F = (double (*)[7])malloc(2*sizeof(F[0]));
    F[0][0] = 0.0;
    F[1][0] = len;
    memcpy( &F[0][1], Copy.FI, sizeof(double)*6 );
    memcpy( &F[1][1], Copy.FJ, sizeof(double)*6 );
}
void DFrameForce::CopyFrom( const DPipeForce & Copy, const double len )
{
    Clear();
    nID = Copy.nID;
    if( Copy.HaveMid ) nSectNum = 3;
    else nSectNum = 2;
    F = (double (*)[7])malloc(nSectNum*sizeof(F[0]));
    F[0][0] = 0.0;
    memcpy( &F[0][1], Copy.FI, sizeof(double)*6 );
    if( Copy.HaveMid ) {
        F[1][0] = len/2.0;
        F[2][0] = len;
        memcpy( &F[1][1], Copy.FMid, sizeof(double)*6 );
        memcpy( &F[2][1], Copy.FJ, sizeof(double)*6 );
    }
    else {
        F[1][0] = len;
        memcpy( &F[1][1], Copy.FJ, sizeof(double)*6 );
    }
}
void DFrameForce::SetSectForce( int SectNum, double (*f)[7] )
{
    nSectNum = (unsigned char)SectNum;
    if( F != NULL ) Free(F);
    if( nSectNum > 0 ) {
        F = (double (*)[7])malloc(nSectNum*sizeof(F[0]));
        memcpy( F, f, nSectNum*sizeof(F[0]) );
    }
}
void DFrameForce::AddSectForce( double f[7] )
{
    nSectNum ++;
    F = (double (*)[7])realloc( F, nSectNum*sizeof(F[0]) );
    memcpy( F[nSectNum-1], f, sizeof(F[0]) );
}
void DFrameForce::Clear( )
{
    nSectNum = 0;
    if( F != NULL ) Free(F);
}
void DFrameForce::Serialize(bofstream & fout)
{
    fout << nID << nSectNum;
    fout.Write( F, sizeof(F[0])*nSectNum );
}
void DFrameForce::Serialize(bifstream & fin)
{
    fin >> nID >> nSectNum;
    F = (double (*)[7])realloc( F, sizeof(F[0])*nSectNum );
    fin.Read( F, sizeof(F[0])*nSectNum );
}


DFrameForce的声明

class CLASS_DECLSPEC DFrameForce {
public:
    // 单元号或组合号
    int nID;
    // 单元内力计算的截面数
    unsigned char nSectNum;
    // F[i][0-6]分别表示：截面距I端距离、轴力、1-2平面内的剪力和弯矩、
    // 1-3平面内的剪力和弯矩、扭矩
    double (*F)[7];
public:
    DFrameForce();
    DFrameForce( DFrameForce & Copy );
    virtual ~DFrameForce();
    DFrameForce & operator = ( const DFrameForce & Copy );
    void CopyFrom( const DTrussForce & Copy, const double len );
    void CopyFrom( const DCframeForce & Copy, const double len );
    void CopyFrom( const DPipeForce & Copy, const double len );
    // 设置所有截面的内力参数
    void SetSectForce( int SectNum, double (*f)[7] );
    // 在原来基础之上添加一个截面的内力，它不判断该截面是否已经存在
    // 如果要使用AddSectForce函数，最初的时候一定不要设置nSectNum，
    // 因为每次调用该函数后，nSectNum会加1
    void AddSectForce( double f[7] );
    // 把所有截面参数置零，释放相关内存
    void Clear();
    // 尽管下面两个函数暂时没有用处，但是为了方便定义可变数组类对象还是定义了这两个函数
    void Serialize(bofstream & fout);
    void Serialize(bifstream & fin);
};


DFrameLoad的实现

DFrameLoad::DFrameLoad()
{
    T[0] = T[1] = T[2] = (float)0.0;
    nID = 0;
}
DFrameLoad::DFrameLoad( DFrameLoad & Copy )
{
    *this = Copy;
}
DFrameLoad::~DFrameLoad()
{
}
DFrameLoad & DFrameLoad::operator = ( const DFrameLoad & Copy )
{
    int i;
    if( this != &Copy ) {
        nID = Copy.nID;
        T[0] = Copy.T[0];
        T[1] = Copy.T[1];
        T[2] = Copy.T[2];
        for( i = 0; i < 6; i ++ ) {
            P[i] = Copy.P[i];
            M[i] = Copy.M[i];
            F[i] = Copy.F[i];
        }
    }
    return *this;
}
int DFrameLoad::operator == ( const DFrameLoad & Other )
{
    int i;
    for( i = 0; i < 3; i ++ ) {
        tmp = T[i] - Other.T[i];
        if( tmp < -LoadError || tmp > LoadError ) return 0;
    }
    for( i = 0; i < 6; i ++ ) {
        if( !(P[i]==Other.P[i]) ) return 0;
        if( !(M[i]==Other.M[i]) ) return 0;
        if( !(F[i]==Other.F[i]) ) return 0;
    }
    return 1;
}
void DFrameLoad::Serialize( bofstream & fout )
{
    int i, j;
    DLoadPoints *lp;
    fout << nID;
    fout.Write( T, sizeof(float)*3 );
    for( i = 0; i < 3; i ++ ) {
        if( i == 0 ) lp = P;
        else if( i == 1 ) lp = M;
        else lp = F;
        for( j = 0; j < 6; j ++ ) lp[j].Serialize( fout );
    }
}
void DFrameLoad::Serialize( bifstream & fin )
{
    int i, j;
    DLoadPoints *lp;
    fin >> nID;
    fin.Read( T, sizeof(float)*3 );
    for( i = 0; i < 3; i ++ ) {
        if( i == 0 ) lp = P;
        else if( i == 1 ) lp = M;
        else lp = F;
        for( j = 0; j < 6; j ++ ) lp[j].Serialize( fin );
    }
}


DFrameLoad的声明

// FRAME单元垮内分布荷载
// 此载荷类也适用于SFRAME和VFRAME单元
class CLASS_DECLSPEC DFrameLoad {
public:
    int nID;
    float T[3]; // 轴向温度变化和沿着截面的2和3方向的温度梯度
    DLoadPoints P[6];	// 各方向(整体坐标和单元局部坐标)的折线荷载: PX PY PZ P1 P2 P3
    DLoadPoints M[6];	// 各方向(整体坐标和单元局部坐标)的弯矩: MXX MYY MZZ M11 M22 M33
    DLoadPoints F[6];	// 各方向(整体坐标和单元局部坐标)的集中力: FX FY FZ F1 F2 F3
public:
    DFrameLoad();
    DFrameLoad( DFrameLoad & Copy );
    virtual ~DFrameLoad();
    DFrameLoad & operator = ( const DFrameLoad & Copy );
    int operator == ( const DFrameLoad & Other );

    virtual void Serialize( bofstream & fout );
    virtual void Serialize( bifstream & fin );
};


DFrameRein的实现

DFrameRein::DFrameRein()
{
    nID = 0;
    nType = 1;
    nSectNum = 0;
    RS = NULL;
    warn_t = 12;
    nComb_t = 0;
    rsa_t = rsr_t = space_th = rsr_th = 0.0f;
}
DFrameRein::DFrameRein( DFrameRein & Copy )
{
    RS = NULL;
    *this = Copy;
}
void DFrameRein::Clear( )
{
    nSectNum = 0;
    if( RS != NULL ) Free(RS);
    warn_t = 12;
    nComb_t = 0;
    rsa_t = rsr_t = space_th = rsr_th = 0.0f;
}
void DFrameRein::SetSectNum( int sectNum )
{
    nSectNum = sectNum;
    RS = (DReinData*)realloc( RS, sizeof(DReinData)*nSectNum );
}
DFrameRein & DFrameRein::operator = ( const DFrameRein & Copy )
{
    if( this != &Copy ) {
        nID = Copy.nID;
        nType = Copy.nType;
        SetSectNum( Copy.nSectNum );
        if( nSectNum > 0 )
            memcpy( RS, Copy.RS, nSectNum*sizeof(DReinData) );
        warn_t = Copy.warn_t;
        nComb_t = Copy.nComb_t;
        rsa_t = Copy.rsa_t;
        rsr_t = Copy.rsr_t;
        space_th = Copy.space_th;
        rsr_th = Copy.rsr_th;
    }
    return *this;
}
void DFrameRein::SetSectData( int SectNum, DReinData r[] )
{
    SetSectNum( SectNum );
    if( nSectNum > 0 )
        memcpy( RS, r, nSectNum*sizeof(DReinData) );
}
void DFrameRein::Serialize(bofstream & fout)
{
    fout << nID << nType << nSectNum;
    fout.Write( RS, sizeof(DReinData)*nSectNum );
    fout << warn_t << nComb_t << rsa_t << rsr_t << space_th << rsr_th;
}
void DFrameRein::Serialize(bifstream & fin)
{
    fin >> nID >> nType >> nSectNum;
    SetSectNum( nSectNum );
    fin.Read( RS, sizeof(DReinData)*nSectNum );
    fin >> warn_t >> nComb_t >> rsa_t >> rsr_t >> space_th >> rsr_th;
}
void DFrameRein::ReadUpperRein( int sectIndex, bifstream & fin )
{
    double d[3];
    int ncomb;
    DReinData * pd = &RS[sectIndex];
    fin.Read( d, 3 );
    fin >> ncomb;
    pd->nComb_u = (unsigned short)ncomb;
    pd->pos = (float)d[0];
    pd->rsa_u = (float)d[1];
    pd->rsr_u = (float)d[2];
}
void DFrameRein::ReadDownRein( int sectIndex, bifstream & fin )
{
    double d[3];
    int ncomb;
    DReinData * pd = &RS[sectIndex];
    fin.Read( d, 3 );
    fin >> ncomb;
    pd->nComb_d = (unsigned short)ncomb;
    pd->pos = (float)d[0];
    pd->rsa_d = (float)d[1];
    pd->rsr_d = (float)d[2];
}
void DFrameRein::ReadHoopRein( int sectIndex, bifstream & fin )
{
    double d[3];
    int ncomb;
    DReinData * pd = &RS[sectIndex];
    fin >> ncomb;
    pd->warn_h = ncomb;
    if( pd->warn_h == 1 ) {
        fin.Read( d, 3 );
        fin >> ncomb;
        pd->nComb_h = (unsigned short)ncomb;
        pd->pos = (float)d[0];
        pd->space_h = (float)d[1];
        pd->rsr_h = (float)d[2];
    }
    else {
        pd->nComb_h = 0;
        pd->space_h = pd->rsr_h = 0.0;
    }
}
void DFrameRein::ReadDir2Rein( int sectIndex, bifstream & fin )
{
    double d[3];
    int ncomb;
    DReinData * pd = &RS[sectIndex];
    fin >> ncomb;
    pd->warn_2 = ncomb;
    if( pd->warn_2 == 1 ) {
        fin.Read( d, 3 );
        fin >> ncomb;
        pd->nComb_2 = (unsigned short)ncomb;
        pd->pos = (float)d[0];
        pd->rsa_2 = (float)d[1];
        pd->rsr_2 = (float)d[2];
    }
    else if( pd->warn_2 == 3 ) {
        fin >> d[0] >> ncomb;
        pd->nComb_2 = (unsigned short)ncomb;
        pd->pos = (float)d[0];
        pd->rsa_2 = pd->rsr_2 = 0.0;
    }
    else if( pd->warn_2 == 4 ) {
        fin >> d[0] >> d[1] >> ncomb;
        pd->nComb_2 = (unsigned short)ncomb;
        pd->pos = (float)d[0];
        pd->rsr_2 = (float)d[1];
        pd->rsa_2 = 0.0;
    }
    else if( pd->warn_2 == 5 ) {
        fin >> d[0] >> d[1] >> ncomb;
        pd->nComb_2 = (unsigned short)ncomb;
        pd->pos = (float)d[0];
        pd->rsa_2 = (float)d[1];
        pd->rsr_2 = 0.0;
    }
    else if( pd->warn_2 == 6 ) {
        fin >> d[0] >> ncomb;
        pd->nComb_2 = (unsigned short)ncomb;
        pd->pos = (float)d[0];
        pd->rsa_2 = pd->rsr_2 = 0.0;
    }
    else {
        pd->nComb_2 = 0;
        pd->rsa_2 = pd->rsr_2 = 0.0;
    }
}
void DFrameRein::ReadDir3Rein( int sectIndex, bifstream & fin )
{
    double d[3];
    int ncomb;
    DReinData * pd = &RS[sectIndex];
    fin >> ncomb;
    pd->warn_3 = ncomb;
    if( pd->warn_3 == 1 ) {
        fin.Read( d, 3 );
        fin >> ncomb;
        pd->nComb_3 = (unsigned short)ncomb;
        pd->pos = (float)d[0];
        pd->rsa_3 = (float)d[1];
        pd->rsr_3 = (float)d[2];
    }
    else if( pd->warn_3 == 3 ) {
        fin >> d[0] >> ncomb;
        pd->nComb_3 = (unsigned short)ncomb;
        pd->pos = (float)d[0];
        pd->rsa_3 = pd->rsr_3 = 0.0;
    }
    else if( pd->warn_3 == 4 ) {
        fin >> d[0] >> d[1] >> ncomb;
        pd->nComb_3 = (unsigned short)ncomb;
        pd->pos = (float)d[0];
        pd->rsr_3 = (float)d[1];
        pd->rsa_3 = 0.0;
    }
    else if( pd->warn_3 == 5 ) {
        fin >> d[0] >> d[1] >> ncomb;
        pd->nComb_3 = (unsigned short)ncomb;
        pd->pos = (float)d[0];
        pd->rsa_3 = (float)d[1];
        pd->rsr_3 = 0.0;
    }
    else if( pd->warn_3 == 6 ) {
        fin >> d[0] >> ncomb;
        pd->nComb_3 = (unsigned short)ncomb;
        pd->pos = (float)d[0];
        pd->rsa_3 = pd->rsr_3 = 0.0;
    }
    else if( pd->warn_3 == 7 ) {
        fin >> d[0] >> d[1] >> ncomb;
        pd->nComb_3 = (unsigned short)ncomb;
        pd->pos = pd->rsa_3 = pd->rsr_3 = 0.0;
    }
    else {
        pd->nComb_2 = 0;
        pd->rsa_2 = pd->rsr_2 = 0.0;
    }
}
void DFrameRein::ReadTorRein( bifstream & fin )
{
    double d[4];
    int ncomb;
    fin >> ncomb;
    warn_t = ncomb;
    if( warn_t == 11 ) {
        fin.Read( d, sizeof(d) );
        fin >> ncomb;
        nComb_t = (unsigned short)ncomb;
        rsa_t = (float)d[0];
        rsr_t = (float)d[1];
        space_th = (float)d[2];
        rsr_th = (float)d[3];
    }
    else {
        rsa_t = rsr_t = space_th = rsr_th = 0.0f;
    }
}


DFrameRein的声明

// REIN的配筋结果数据(读取时只读取配筋的梁柱)
class CLASS_DECLSPEC DFrameRein {
public:
    struct DReinData {	// 某个截面上的配筋数据
        float pos;	// 截面位置（即距I端的距离）
    // 上筋数据(对柱无用), rsa means Reinforce Steel Area, rsr means Reinforce Steel Ratio
        unsigned short nComb_u;	// 上筋对应的内力组合号
        float rsa_u, rsr_u;		// 上筋配筋面积(cm^2)和配筋率
    // 下筋数据(对柱无用)
        unsigned short nComb_d;	// 下筋对应的内力组合号
        float rsa_d, rsr_d;		// 下筋配筋面积(cm^2)和配筋率
    // 偏心受压  1-2平面配筋数据(对梁无用)
        // 1:正常  2:请加大截面！(V > 0.2~0.25*B*H0*Fc) 后两行数据无效
        // 3:长细比过大！只有nComb_2有效  4:配筋率大于5％！只有nComb_2和rsr_2有效
        // 5:正常，但只有nComb_2和rsa_2有效  6:全截面受拉！只有nComb_2有效
        unsigned char warn_2;
        unsigned short nComb_2;	// 上筋对应的内力组合号
        float rsa_2, rsr_2;		// 1-2方向单边筋配筋面积(cm^2)和配筋率
    // 偏心受压  1-3平面配筋数据(对梁无用)
        // 1:正常  2:请加大截面！(V > 0.2~0.25*B*H0*Fc) 后两行数据无效
        // 3:长细比过大！只有nComb_2有效  4:配筋率大于5％！只有nComb_2和rsr_2有效
        // 5:正常，但只有nComb_2和rsa_2有效  6:全截面受拉！只有nComb_2有效
        // 7:轴压比超过限值！只有nComb_2和rsr_3(表示轴压比)有效
        unsigned char warn_3;
        unsigned short nComb_3;	// 上筋对应的内力组合号
        float rsa_3, rsr_3;		// 1-3方向单边筋配筋面积(cm^2)和配筋率
    // 箍筋数据  h means Hoop
        unsigned char warn_h;	// 1:正常  2:请加大截面！(V > 0.2~0.25*B*H0*Fc), 下两行数据无效
        unsigned short nComb_h;	// 箍筋对应的内力组合号
        float space_h, rsr_h;		// 箍筋间距(cm)和配箍率
    };
public:
    int nID;	// 单元号
    unsigned char nType;	// 单元类型  1:梁  2:柱 3:支撑
    unsigned char nSectNum;	// 单元内力计算的截面数, 即RS数组的长度
    DReinData *RS;	// 各截面的配筋数据
// 扭筋数据 (对柱无效，不分截面输出)
    unsigned char warn_t;	// 11:正常(只有此时后两行才有效) 10:请增大构件截面尺寸以满足弯剪扭构件的要求 12:忽略扭矩
    unsigned short nComb_t;	// 扭筋对应的内力组合号
    float rsa_t, rsr_t, space_th, rsr_th;	// 抗扭纵筋(cm^2)和纵筋配筋率,抗剪扭箍筋间距(cm)和配箍率
public:
    DFrameRein();
    DFrameRein( DFrameRein & Copy );
    virtual ~DFrameRein() { Clear(); }
    DFrameRein & operator = ( const DFrameRein & Copy );
    // 设置截面数，同时分配好合适的内存
    void SetSectNum( int sectNum );
    // 清除所有截面的配筋数据，释放相关内存
    void Clear();
    // 设置所有截面的配筋数据
    void SetSectData( int SectNum, DReinData r[] );
    // 尽管下面两个函数暂时没有用处，但是为了方便定义可变数组类对象还是定义了这两个函数
    void Serialize(bofstream & fout);
    void Serialize(bifstream & fin);
private:
    friend class DResult;
    void ReadUpperRein( int sectIndex, bifstream & fin );	// 读取某截面的上筋数据
    void ReadDownRein( int sectIndex, bifstream & fin );	// 读取某截面的下筋数据
    void ReadHoopRein( int sectIndex, bifstream & fin );	// 读取某截面的箍筋数据
    void ReadDir2Rein( int sectIndex, bifstream & fin );	// 读取某截面的1-2方向的配筋数据
    void ReadDir3Rein( int sectIndex, bifstream & fin );	// 读取某截面的1-3方向的配筋数据
    void ReadTorRein( bifstream & fin ); // 读取抗扭配筋数据
};


DFrameSect的实现

DFrameSect::DFrameSect( )
{
    nID = 0;
    nType = 0;
    memset( B, 0x00, sizeof(float)*6 );
    name = new char[20];
    strcpy( name, "section" );
}
DFrameSect::~DFrameSect()
{
    if( name ) delete[] name;
}
DFrameSect::DFrameSect( DFrameSect & Copy )
{
    name = NULL;
    *this = Copy;
}
DFrameSect & DFrameSect::operator = ( const DFrameSect & Copy )
{
    if( this != &Copy ) {
        nID = Copy.nID;
        nType = Copy.nType;
        memcpy( B, Copy.B, sizeof(float)*6 );
        SetName( Copy.name );
    }
    return *this;
}
void DFrameSect::SetName( const char * nameStr )
{
    int len = strlen(nameStr)+1;
    if( name ) delete[] name;
    name = new char[len];
    strcpy( name, nameStr );
}
int DFrameSect::GetParaNum( int type )
{
    if( type == 1 || type == 7 ) return 2;
    else if( type == 2 || type == 40 ) return 6;
    else if( type == 3 || type == 4 || type == 6 || type == 9 || type == 10 )
        return 4;
    else if( type == 5 || type == 8 ) return 3;
    return 0;
}
int DFrameSect::operator == ( const DFrameSect & Other )
{
    return (strcmp( name, Other.name)==0);
    /*
    if( Other.nType != nType ) return 0;
    double tmp;
    int dnum;
    dnum = GetParaNum(nType);
    for( int i = 0; i < dnum; i ++ ) {
        tmp = B[i] - Other.B[i];
        if( tmp < -SectionError || tmp > SectionError ) return 0;
    }
    return 1;
    */
}
void DFrameSect::SetSect( double Aa, double Ii[2], double Jj, double Ss[2] )
{
    nType = 40;
    A = (float)Aa;
    I33 = (float)Ii[0];
    I22 = (float)Ii[1];
    J = (float)Jj;
    A3 = (float)Ss[0];
    A2 = (float)Ss[1];
}
void DFrameSect::SetTrussSect( double Aa, double Ii )
{
    nType = 40;
    A = (float)A;
    I33 = (float)Ii;
    I22 = J = A3 = A2 = 0;
}
void DFrameSect::SetSect( int No, double b[] )
{
    int dnum;
    nType = No;
    dnum = GetParaNum(No);
    for( int i = 0; i < dnum; i ++ )
        B[i] = (float)b[i];
}

int DFrameSect::GetSect( double & Aa, double Ii[2], double & Jj, double Ss[2] )
{
    if( nType != 40 ) return 0;
    Aa = A;
    Ii[0] = I33;
    Ii[1] = I22;
    Jj = J;
    Ss[0] = A3;
    Ss[1] = A2;
    return 1;
}
int DFrameSect::GetTrussSect( double & Aa, double & Ii )
{
    if( nType != 40 ) return 0;
    Aa = A;
    Ii = I33;
    return 1;
}

int DFrameSect::GetSect( int & No, double b[6] )
{
    if( nType < 1 || nType > 10  ) return 0;
    int dnum;
    No = nType;
    dnum = GetParaNum( No );
    for( int i = 0; i < dnum; i ++ )
        b[i] = B[i];
    return dnum;
}

double DFrameSect::GetSectArea( )
{
    if( nType == 40 ) {
        return A;
    }
    else if( nType >= 1 && nType <= 10 ) {
        if( nType == 1 ) {
            return B[0] * B[1];
        }
        else if( nType == 2 ) {
            return B[0]*B[3] + B[1]*B[4] + B[2]*B[5];
        }
        else if( nType == 3 || nType == 4 ) {
            return B[0]*B[2] + B[1]*B[3];
        }
        else if( nType == 5 ) {
            return (B[0]+B[1]-B[2])*B[2];
        }
        else if( nType == 6 ) {
            return (B[0]+B[1]+B[2])*B[3];
        }
        else if( nType == 7 ) {
            return PI*(B[1]*B[1]-B[0]*B[0]);
        }
        else if( nType == 8 ) {
            return PI*B[2]*(2*B[0]*B[1]+B[0]*B[0])/360.0;
        }
        else if( nType == 9 ) {
            return B[0]*B[1]-(B[0]-2.0*B[3])*(B[1]-2.0*B[2]);
        }
        else {// nType == 10
            return 2.0*B[0]*B[3]+(B[1]-2.0*B[3])*B[2];
        }
    }
    return 0.0;
}
void DFrameSect::Serialize( bofstream & fout )
{
    int len = strlen( name )+1;
    fout << nID << nType;
    fout.Write( &len, sizeof(int) );
    fout.Write( name, len );
    fout.Write( B, sizeof(float)*6 );
}
void DFrameSect::Serialize( bifstream & fin )
{
    int len;
    fin >> nID >> nType;
    fin.Read( &len, sizeof(int) );
    if( name ) delete[] name;
    name = new char[len];
    fin.Read( name, len );
    fin.Read( B, sizeof(float)*6 );
}


DFrameSect的声明

// 材料的几何属性。
// 如果材料参数中写的是零(但是一般说来该参数不可能为零)表示
// 它取sap84的缺省值，在写sap84数据文件时不写该项即可，这种习惯
// 在其它文件中也类似地存在

// 由于十种特殊的截面已经包含了四种特殊的截面，这里不再支持四种特殊截面
// 类DFrameSect适合于FRAME，TRUSS，CFRAME单元
    ////////////////////////////////////////////////////////////////////////
    // 截面类型  1：sap84中框架单元十种特殊截面的第一种截面
    //	(nType)	 2：sap84中框架单元十种特殊截面的第二种截面
    //              ......
    //			10：sap84中框架单元十种特殊截面的第十种截面
    ////////////////////////////////////////////////////////////////////////
    //		    40：一般性的几何属性描述，没有具体的截面尺寸，
    //				只有一般的几何参数。
    // 缺省值为0，即截面属性无效
    ////////////////////////////////////////////////////////////////////////
class CLASS_DECLSPEC DFrameSect {
public:
    short nID;
    unsigned char nType;	// 截面类型
    char *name;	// 保存时先保存字符长度(含c语言的结束符), 再保存字符串(含结束符)
    union {
        // nType =1--10,十种特殊截面(第7种截面中的
        float B[6];		//厚度B[2]无效,该种截面只有B[0]和B[1])
        struct {		// nType=40,通过一般性的几何参数描述截面性质
            float A;		// A=A1,横截面积
            float J;		// 扭转刚度G1J1因子之一 对TRUSS无用
            float I33,I22;	// 关于3轴和2轴的惯性矩 对TRUSS单元只需要I=I1(取min(I33,I22))
            float A2,A3;	// 2、3方向的剪切面积	对TRUSS无用
        };
    };
public:
    DFrameSect( );
    ~DFrameSect( );
    DFrameSect( DFrameSect & Copy );
    DFrameSect & operator = ( const DFrameSect & Copy );
    // 通过名称确定是否相等
    int operator == ( const DFrameSect & Other );
    // 设置截面标识名称
    void SetName( const char * nameStr );
    // 设置截面属性为第一种截面，其意义可参考SAP84手册
    // 对单元FRAME, CFRAME有效
    void SetSect( double Aa, double Ii[2], double Jj, double Ss[2] );
    // 对单元TRUSS有效
    void SetTrussSect( double Aa, double Ii );
    // No必须是从1到10，并且B[]数组的个数必须与SAP84要求的一致
    // 对单元FRAME, TRUSS,CFRAME有效
    void SetSect( int No, double b[] );
    int IsGenSect( ) { return nType == 40; }
    int IsSpecSect() { return (nType>=1&&nType <=10); }
    int GetSect( double & Aa, double Ii[2], double & Jj, double Ss[2] );
    int GetTrussSect( double & Aa, double & Ii );
    // No返回的是从1到10的特殊截面号，若当前截面为特殊截面，返回b中有效元素的个数,
    // 否则返回0. 第七种截面类型参数个数为2，并非说明书中的3
    int GetSect( int & No, double b[6] );
    // 计算截面的面积
    double GetSectArea( );
    virtual void Serialize( bofstream & fout );
    virtual void Serialize( bifstream & fin );
public:
    // 返回十种端面类型需要的参数个数, 第七种断面的参数个数为2
    static int GetParaNum( int type );
};


DHistory的实现

DHistory::DHistory()
{
    Initialize();
}
DHistory::DHistory( const DHistory & Copy )
{
    *this = Copy;
}
void DHistory::Initialize()
{
    nType = 0;	//  不作时程分析
    nResp = 20;
    nbegInt = 1;
    nIntegral = 200;
    TStep = (float)0.001;
    nOut = 0x01;
    nDamp = 0;
    Ck = Cm = (float)0.0;
    eigenDamp.Clear();
    for( int i = 1; i < 11; i ++ )
        eigenDamp.Insert( i, 0, 1 );
    Para[0] = 0.5;
    Para[1] = 0.25;
    Para[2] = 1.0;
    accOutNd = 0;
    accOutDir = 0;
    accOutFile[0]='\0';
}
DHistory::~DHistory()
{
}
DHistory & DHistory::operator =(const DHistory & Copy)
{
    if( this != &Copy ) {
        nType = Copy.nType;
        nResp = Copy.nResp;
        nbegInt = Copy.nbegInt;
        nIntegral = Copy.nIntegral;
        TStep = Copy.TStep;
        nOut = Copy.nOut;
        nDamp = Copy.nDamp;
        Ck = Copy.Ck;
        Cm = Copy.Cm;
        eigenDamp = Copy.eigenDamp;
        for( int i = 0; i < 3; i ++ )
            Para[i] = Copy.Para[i];
        accOutNd = Copy.accOutNd;
        accOutDir = Copy.accOutDir;
        strcpy( accOutFile, Copy.accOutFile );
    }
    return *this;
}
int DHistory::operator ==(const DHistory & Other)
{
    double tmp;
    if( nType != Other.nType ) return 0;
    if( nResp != Other.nResp ) return 0;
    if( nbegInt != Other.nbegInt ) return 0;
    if( nIntegral != Other.nIntegral ) return 0;
    tmp = TStep - Other.TStep;
    if( tmp < - LoadError || tmp > LoadError ) return 0;
    if( nOut != Other.nOut ) return 0;
    if( nDamp != Other.nDamp ) return 0;
    if( nDamp != 0 ) {
        tmp = Ck - Other.Ck;
        if( tmp < - LoadError || tmp > LoadError ) return 0;
        tmp = Cm - Other.Cm;
        if( tmp < - LoadError || tmp > LoadError ) return 0;
    }
    if( nType == 1 ) {
        if( !(eigenDamp==Other.eigenDamp) ) return 0;
    }
    else if( nType == 2 ) {
        for( int i = 0; i < 3; i ++ ) {
            tmp = Para[i] - Other.Para[i];
            if( tmp < - LoadError || tmp > LoadError ) return 0;
        }
    }
    if( accOutNd != Other.accOutNd ) return 0;
    if( accOutDir != Other.accOutDir ) return 0;
    return 1;
}
void DHistory::Serialize(bofstream & fout)
{
    fout << nType << nResp << nbegInt << nIntegral << TStep << nOut;
    fout << nDamp << Ck << Cm;
    eigenDamp.Serialize( fout );
    fout.Write( Para, sizeof(float)*3 );
    fout << accOutNd << accOutDir << accOutFile;
}
void DHistory::Serialize(bifstream & fin)
{
    fin >> nType >> nResp >> nIntegral >> nbegInt >> TStep >> nOut;
    fin >> nDamp >> Ck >> Cm;
    eigenDamp.Serialize( fin );
    fin.Read( Para, sizeof(float)*3 );
    if( nVersion >= 128 ) fin >> accOutNd >> accOutDir >> accOutFile;
}


DHistoryCurve的实现

DHistoryCurve::DHistoryCurve()
{
    nID = nNum = 0;
    T = F = NULL;
    Tc = Tb = A = B = Ts = To = Tf = Tt = (float)0.0;
}
DHistoryCurve::~DHistoryCurve()
{
    Clear();
}
DHistoryCurve::DHistoryCurve( const DHistoryCurve & Copy )
{
    T = F = NULL;
    *this = Copy;
}
void DHistoryCurve::Clear()
{
    nNum = 0;
    if( T != NULL ) {
        free(T);
        T = NULL;
    }
    if( F != NULL ) {
        free(F);
        F = NULL;
    }
}
DHistoryCurve & DHistoryCurve::operator =(const DHistoryCurve & Copy)
{
    if( this != &Copy ) {
        Clear();
        nID = Copy.nID;
        nNum = Copy.nNum;
        Tc = Copy.Tc;
        Tb = Copy.Tb;
        A = Copy.A;
        B = Copy.B;
        Ts = Copy.Ts;
        To = Copy.To;
        Tf = Copy.Tf;
        Tt = Copy.Tt;
        if( nNum > 0 ) {
            F = (float*)malloc(sizeof(float)*nNum);
            T = (float*)malloc(sizeof(float)*nNum);
            memcpy( F, Copy.F, sizeof(float)*nNum );
            memcpy( T, Copy.T, sizeof(float)*nNum );
        }
    }
    return *this;
}
int DHistoryCurve::operator ==(const DHistoryCurve & Other)
{
    if( nNum != Other.nNum ) return 0;
    double tmp;
    for( int i = 0; i < nNum; i ++ ) {
        tmp = F[i] - Other.F[i];
        if( tmp < - LoadError || tmp > LoadError ) return 0;
        tmp = T[i] - Other.T[i];
        if( tmp < - 1.0E-6 || tmp > 1.0E-6 ) return 0;
    }
    tmp = Tc - Other.Tc;
    if( tmp < - 1.0E-6 || tmp > 1.0E-6 ) return 0;
    tmp = Tb - Other.Tb;
    if( tmp < - 1.0E-6 || tmp > 1.0E-6 ) return 0;
    tmp = A - Other.A;
    if( tmp < - LoadError || tmp > LoadError ) return 0;
    tmp = B - Other.B;
    if( tmp < - LoadError || tmp > LoadError ) return 0;
    tmp = Ts - Other.Ts;
    if( tmp < - 1.0E-6 || tmp > 1.0E-6 ) return 0;
    tmp = To - Other.To;
    if( tmp < - 1.0E-6 || tmp > 1.0E-6 ) return 0;
    tmp = Tf - Other.Tf;
    if( tmp < - 1.0E-6 || tmp > 1.0E-6 ) return 0;
    tmp = Tt - Other.Tt;
    if( tmp < - 1.0E-6 || tmp > 1.0E-6 ) return 0;
    return 1;
}
void DHistoryCurve::SetCurve(const int num, const double t[], const double f[] )
{
    nNum = num;
    SetCurveBuffer(num);
    for( int i = 0; i < num; i ++ ) {
        T[i] = (float)t[i];
        F[i] = (float)f[i];
    }
}
void DHistoryCurve::SetCurveBuffer( const int num )
{
    T = (float*)realloc( T, sizeof(float)*num );
    F = (float*)realloc( F, sizeof(float)*num );
}
void DHistoryCurve::Serialize( bofstream & fout )
{
    fout << nID << nNum;
    fout.Write( T, sizeof(float)*nNum );
    fout.Write( F, sizeof(float)*nNum );
    fout << Tc << Tb << A << B << Ts << To << Tf << Tt;
}
void DHistoryCurve::Serialize( bifstream & fin )
{
    if( nVersion < 125 ) {
        short sid;
        fin >> sid;
        nID = sid;
        fin.Seek( sizeof(float), SEEK_CUR ); // skip Factor
    }
    else fin >> nID;
    fin >> nNum;
    T = (float*)realloc( T, sizeof(float)*nNum );
    F = (float*)realloc( F, sizeof(float)*nNum );
    fin.Read( T, sizeof(float)*nNum );
    fin.Read( F, sizeof(float)*nNum );
    fin >> Tc >> Tb >> A >> B >> Ts >> To >> Tf >> Tt;
}


DHistoryCurve的声明

class CLASS_DECLSPEC DHistoryCurve {
public:
    int  nID;		// 在生成数据文件时必须从1开始连续分布
    int nNum;		// 描述该曲线的点数，如果nNum==0时，T,F必须置NULL
    float *T, *F;		// 曲线在各点的时间和荷载值 T[nNum], F[nNum]
    float Tc,Tb;	// 表示该曲线在Tb之后有周期性，周期为Tc
    // 在曲线上叠加一个谐波荷载，A*exp(B*t)*sin{2*PI*(t-T0)/Ts} when Tf≤t≤Tt
    float A,B,Ts,To,Tf,Tt;
public:
    DHistoryCurve();
    DHistoryCurve( const DHistoryCurve & Copy );
    virtual ~DHistoryCurve();
    void Clear();
    DHistoryCurve &  operator = ( const DHistoryCurve & Copy );
    int operator == ( const DHistoryCurve & Other );
    // 如果num==0,则F将自动清除
    void SetCurve( const int num,const double t[], const double f[] );
    // 把曲线存储的指针变量T,F设置成大小为num的数组
    void SetCurveBuffer( const int num );

    virtual void Serialize( bofstream & fout );
    virtual void Serialize( bifstream & fin );
};


DHistory的声明

class CLASS_DECLSPEC DHistory {
public:
    // 时程分析的方法 0:不进行时程分析 1:dynamic 2:step  [0]
    // nType不影响数据存取的范围，即存取类中所有数据
    unsigned char nType;
    unsigned short nResp;	// 要输出的响应个数
    unsigned short nbegInt;	// 第一个响应输出对应的积分步号(后面的响应将等间隔分布)
    unsigned short nIntegral;	// 积分的步数
    float TStep;			// 积分时间步长
    unsigned char nOut;		// if(nOut&&0x01!=0)表示要求输出位移响应，否则不输出位移响应 [0x01]
                            // if(nOut&&0x02!=0)表示要求输出速度响应，否则不输出速度响应
                            // if(nOut&&0x04!=0)表示要求输出加速度响应，否则不输出加速度响应
    unsigned char nDamp;	// 是否考虑阻尼，不管是否考虑阻尼，阻尼都要存取
    float Ck,Cm;			// Rayleigh阻尼
    DNumFactors eigenDamp;	// 振型迭加时采用的振型号和对应的阻尼比(只针对振型迭加法)
    float Para[3];			// 逐步积分法中三个参数的选定(只针对逐步积分法)[0.5,0.25,1]
    // 以下数据用于输出某个节点的加速度时间曲线(只对振型迭加法有效)
    int accOutNd;	// >0表示输出加速度曲线的节点号
    char accOutDir;	// bit0-5分别表示输出加速度的方向(Ux,Uy,Uz,Rx,Ry,Rz,=0表示相应方向不输出)
    char accOutFile[20];	// 输出加速度文件名
public:
    DHistory();
    DHistory( const DHistory & Copy );
    void Initialize();
    virtual ~DHistory();
    DHistory & operator = ( const DHistory & Copy );
    int operator == ( const DHistory & Other );
    void SetDynamic() { nType = 1; }
    void SetStep() { nType = 2; }
    int IsDynamic() { return nType == 1; }
    int IsStep() { return nType == 2; }
    int IsValid() { return (nType==1||nType==2); }

    virtual void Serialize( bofstream & fout );
    virtual void Serialize( bifstream & fin );
};


DHistoryLoad的实现

DHistoryLoad::DHistoryLoad()
{
    nNode = 0;
    nCurve = 0;
    for( int i = 0; i < 6; i ++ ) {
        U[i] = V[i] = A[i] = C[i] = 0.0f;
    }
    for( i = 0; i < 3; i ++ ) {
        LoadDir[i] = R[i] = 0.0f;
    }
    LoadDir[0] = 1.0f;
    curveType = 3;
}
DHistoryLoad::DHistoryLoad( const DHistoryLoad & Copy )
{
    *this = Copy;
}
DHistoryLoad & DHistoryLoad::operator =(const DHistoryLoad & Copy)
{
    if( this != &Copy ) {
        nNode = Copy.nNode;
        nCurve = Copy.nCurve;
        for( int i = 0; i < 6; i ++ ) {
            U[i] = Copy.U[i];
            V[i] = Copy.V[i];
            A[i] = Copy.A[i];
            C[i] = Copy.C[i];
        }
        for( i = 0; i < 3; i ++ ) {
            LoadDir[i] = Copy.LoadDir[i];
            R[i] = Copy.R[i];
        }
        curveType = Copy.curveType;
    }
    return *this;
}
int DHistoryLoad::operator ==(const DHistoryLoad & Other) const
{
    if( nNode != Other.nNode ) return 0;
    if( nCurve != nCurve ) return 0;
    double tmp;
    for( int i = 0; i < 6; i ++ ) {
        tmp = U[i] - Other.U[i];
        if( tmp < - LoadError || tmp > LoadError ) return 0;
        tmp = V[i] - Other.V[i];
        if( tmp < - LoadError || tmp > LoadError ) return 0;
        tmp = A[i] - Other.A[i];
        if( tmp < - LoadError || tmp > LoadError ) return 0;
        tmp = C[i] - Other.C[i];
        if( tmp < - LoadError || tmp > LoadError ) return 0;
    }
    for( i = 0; i < 3; i ++ ) {
        tmp = R[i] - Other.R[i];
        if( tmp < - LoadError || tmp > LoadError ) return 0;
        tmp = LoadDir[i] - Other.LoadDir[i];
        if( tmp < - LoadError || tmp > LoadError ) return 0;
    }
    if( curveType != Other.curveType ) return 0;
    return 1;
}
void DHistoryLoad::Serialize( bofstream & fout )
{
    fout << nNode << nCurve;
    fout.Write( U, sizeof(U) );
    fout.Write( V, sizeof(V) );
    fout.Write( A, sizeof(A) );
    fout.Write( C, sizeof(C) );
    fout << curveType;
    fout.Write( LoadDir, sizeof(LoadDir) );
    fout.Write( R, sizeof(R) );
}
void DHistoryLoad::Serialize( bifstream & fin )
{
    float F[6], D[6];
    unsigned char uf[6];
    fin >> nNode;
    if( nVersion < 125 ) {
        short sCurve;
        fin >> sCurve;
        fin.Read( uf, sizeof(uf) );
        nCurve = sCurve;
        for( int i = 0; i < 6; i ++ ) F[i] = uf[i];
    }
    else {
        fin >> nCurve;
        if( nVersion < 128 ) fin.Read( F, sizeof(F) );
    }
    fin.Read( U, sizeof(U) );
    fin.Read( V, sizeof(V) );
    fin.Read( A, sizeof(A) );
    fin.Read( C, sizeof(C) );
    if( nVersion < 128 ) {
        fin.Read( D, sizeof(float)*3 );
        fin.Read( uf, sizeof(unsigned char)*3 );
        D[3] = uf[0];	D[4] = uf[1];	D[5] = uf[2];
        if( !GFunc::IsZero(D,3,0.0001) ) {
            curveType = 3;
            memcpy( LoadDir, D, sizeof(float)*3 );
        }
        else if( !GFunc::IsZero(&D[3],3,0.0001) ) {
            curveType = 4;
            memcpy( LoadDir, &D[3], sizeof(float)*3 );
        }
        else if( !GFunc::IsZero(F,3,0.0001) ) {
            curveType = 1;
            memcpy( LoadDir, F, sizeof(float)*3 );
        }
        else if( !GFunc::IsZero(&F[3],3,0.0001) ) {
            curveType = 2;
            memcpy( LoadDir, &F[3], sizeof(float)*3 );
        }
        else {
            curveType = 3;
            LoadDir[0] = 1.0f;	LoadDir[2] = LoadDir[1] = 0.0f;
        }
    }
    else {
        fin >> curveType;
        fin.Read( LoadDir, sizeof(LoadDir) );
    }
    fin.Read( R, sizeof(R) );
}


DHistoryLoad的声明

class CLASS_DECLSPEC DHistoryLoad {
public:
    // 荷载作用节点号, 如果nNode=-1表示荷载曲线作用在所有的结点上，加速度曲线多数是这种情况
    int nNode;
    // 小于等于0表示下面的数据仅仅用于指定初始位移、速度和加速度，
    // 大于0表示节点对应的荷载或加速度曲线号，即DHistoryCurve中的nID
    int nCurve;
    float U[6],V[6];	// 节点的初始位移、初始速度
    float A[6],C[6];	// 初始加速度和非比例阻尼(对振型迭加法无效)
    unsigned char curveType;	// 荷载曲线类型  1:力的曲线 2:力矩曲线 3:加速度曲线 4:角加速度曲线
    float LoadDir[3];	// 荷载曲线作用的方向（最好归一化，否则荷载作用效果会相应放大）
    float R[3];			// 转动中心的坐标(curveType=4时才有效)
public:
    DHistoryLoad();
    DHistoryLoad( const DHistoryLoad & Copy );
    DHistoryLoad &  operator = ( const DHistoryLoad & Copy );
    int operator == ( const DHistoryLoad & Other );

    virtual void Serialize( bofstream & fout );
    virtual void Serialize( bifstream & fin );
};


DLayerBase的实现

DLayerBase::DLayerBase()
{
    nID = 0;
    name = NULL;
    SetName( "固定图层" );
    nDisp = 1;
    DispColor = 0xffff00;
}
DLayerBase::~DLayerBase()
{
    if( name ) delete[] name;
}
DLayerBase::DLayerBase(const DLayerBase & Copy)
{
    *this = Copy;
}
DLayerBase & DLayerBase::operator =(const DLayerBase & Copy)
{
    if( this != &Copy ) {
        nID = Copy.nID;
        SetName( Copy.name );
        nDisp = Copy.nDisp;
        DispColor = Copy.DispColor;
    }
    return *this;
}
int DLayerBase::operator ==(const DLayerBase & Other) const
{
    return (strcmp(name, Other.name )==0);
}
void DLayerBase::SetName( const char newName[] )
{
    int len = strlen(newName)+1;
    if( name ) delete[] name;
    name = new char[len];
    strcpy( name, newName );
}
void DLayerBase::Serialize(bofstream & fout)
{
    short len = strlen( name )+1;
    fout << nID << len;
    fout.Write( name, len );
    fout << nDisp << DispColor;
}
void DLayerBase::Serialize(bifstream & fin)
{
    short len;
    fin >> nID >> len;
    if( name ) delete[] name;
    name = new char[len];
    fin.Read( name, len );
    fin >> nDisp >> DispColor;
}


DLayerBase的声明

// 图层类，向单元一些单元或节点的一个集合, 必须有一个nID=1的图层，相当于固定图层，
// 该图层不能进行任何变动
class CLASS_DECLSPEC DLayerBase{
public:
    short nID;	// nID>0
    // 图层的名称，必须以'\0'结束，
    // 保存字符串之前保存了一个字节，该字节表示name的长度(不含'\0')
    // 保存字符串时包含'\0'字符和它前面的字节(长度+1)
    char *name;
    unsigned char nDisp;	// 该图层是否显示
    unsigned long DispColor;		// 显示颜色
public:
    DLayerBase();
    ~DLayerBase();
    DLayerBase( const DLayerBase & Copy );
    DLayerBase & operator = ( const DLayerBase & Copy );
    int operator == ( const DLayerBase & Other ) const;
    void SetName( const char newName[] );

    virtual void Serialize( bofstream & fout );
    virtual void Serialize( bifstream & fin );
};


DLevelBase的实现

DLevelBase::DLevelBase()
{
    nID = 1;
    Height = DeltH = (float)0.0;
    nDisp = 1;
}
DLevelBase::DLevelBase(const DLevelBase & Copy)
{
    *this = Copy;
}
DLevelBase & DLevelBase::operator =(const DLevelBase & Copy)
{
    if( this != &Copy ) {
        nID = Copy.nID;
        Height = Copy.Height;
        DeltH = Copy.DeltH;
        nDisp = Copy.nDisp;
    }
    return *this;
}
int DLevelBase::operator ==(const DLevelBase & Other)
{
    if( Height-Other.Height < -1.0E-4 || Height-Other.Height > 1.0E-4 ) return 0;
    if( DeltH-Other.DeltH < -1.0E-4 || DeltH-Other.DeltH > 1.0E-4 ) return 0;
    return 1;
}
void DLevelBase::Serialize(bofstream & fout)
{
    fout << nID << Height << DeltH << nDisp;
}
void DLevelBase::Serialize(bifstream & fin)
{
    fin >> nID >> Height >> DeltH >> nDisp;
}


DLevelBase的声明

// 高层的层类，不管结构是否分层至少有一个nID=1的层
class CLASS_DECLSPEC DLevelBase {
public:
    // 层号，单元中的nLevel指向的是该号, 此号等于实际的层号加2
    // nID=1,2,3,4...n+2  代表着LEV=-1,0,1,2...n层
    // LEV=0表示单元或节点在高度为0.0的水平面上，LEV=-1表示节点
    // 不在任何层面上. 当删除或增加一层时, 必须修改该层以上各层
    // 的nID和标高Height, 同时修改各层单元的nLevel号
    short nID;
    // 这一层的标高和层高，如果nID=1(即LEV=-1)，标高和层高没有
    // 任何意义，如果nID=2(即LEV=0)，标高和层高均等于0
    float Height,DeltH;
    // 该层是否显示
    unsigned char nDisp;
public:
    DLevelBase();
    DLevelBase( const DLevelBase & Copy );
    DLevelBase & operator = ( const DLevelBase & Copy );
    int operator == ( const DLevelBase & Other );

    virtual void Serialize( bofstream & fout );
    virtual void Serialize( bifstream & fin );
};


DLoadPoints的实现

DLoadPoints::DLoadPoints()
{
    nPoints = 0;
    Pos = Val = NULL;
}
DLoadPoints::~DLoadPoints()
{
    Clear();
}
DLoadPoints & DLoadPoints::operator = ( const DLoadPoints & Copy )
{
    Clear();
    nPoints = Copy.nPoints;
    if( nPoints > 0 ) {
        int size = sizeof(float)*nPoints;
        Pos = (float*)malloc(size);
        Val = (float*)malloc(size);
        for( size = 0; size < nPoints; size ++ ) {
            Pos[size] = Copy.Pos[size];
            Val[size] = Copy.Val[size];
        }
    }
    return *this;
}
int DLoadPoints::operator == ( const DLoadPoints & Other )
{
    if( nPoints != Other.nPoints ) return 0;
    double tmp;
    for( int i = 0; i < nPoints; i ++ ) {
        tmp = Pos[i] - Other.Pos[i];
        if( tmp < -LoadError || tmp > LoadError ) return 0;
        tmp = Val[i] - Other.Val[i];
        if( tmp < -LoadError || tmp > LoadError ) return 0;
    }
    return 1;
}
void DLoadPoints::SetPoints( short num, float position[], float value[] )
{
    Clear();
    nPoints = num;
    if( nPoints > 0 ) {
        int size = sizeof(float)*nPoints;
        Pos = (float*)malloc(size);
        Val = (float*)malloc(size);
        for( size = 0; size < nPoints; size ++ ) {
            Pos[size] = position[size];
            Val[size] = value[size];
        }
    }
}
void DLoadPoints::SetPoints( int num, double position[], double value[] )
{
    Clear();
    nPoints = num;
    if( nPoints > 0 ) {
        int size = sizeof(float)*nPoints;
        Pos = (float*)malloc(size);
        Val = (float*)malloc(size);
        for( size = 0; size < nPoints; size ++ ) {
            Pos[size] = (float)position[size];
            Val[size] = (float)value[size];
        }
    }
}
void DLoadPoints::Clear()
{
    nPoints = 0;
    if( Pos != NULL ) Free(Pos);
    if( Val != NULL ) Free(Val);
}

int DLoadPoints::AppendLineLoad( int num, double position[], double value[] )
{
    int i, isNeg=0, isPos=0;
    for( i = 0; i < nPoints; i ++ ) {
        if( Pos[i] < -LoadError ) isNeg = 1;
        else if( Pos[i] > LoadError ) isPos = 1;
    }
    for( i = 0; i < num; i ++ ) {
        if( position[i] < -LoadError ) isNeg = 1;
        else if( position[i] > LoadError ) isPos = 1;
    }
    if( isNeg && isPos ) return 0;	// Error happened
    if( isNeg ) {	// Change the negative to positive
        for( i = 0; i < nPoints; i ++ ) Pos[i] = -Pos[i];
        for( i = 0; i < num; i ++ ) position[i] = -position[i];
    }
    for( i = 0; i < num-1; i ++ )
        AppendOneLineLoad( position[i], value[i], position[i+1], value[i+1] );
    if( isNeg ) {
        for( i = 0; i < nPoints; i ++ ) Pos[i] = -Pos[i];
        for( i = 0; i < num; i ++ ) position[i] = -position[i];
    }
    return 1;
}
int DLoadPoints::AppendPointLoad( int num, double position[], double value[] )
{
    int i, j, size;
    double tmp;
    size = sizeof(float)*(nPoints + num);
    Pos = (float*)realloc( Pos, size );
    Val = (float*)realloc( Val, size );
    for( i = 0; i < num; i ++ ) {
        for( j = 0; j < nPoints; j ++ ) {
            tmp = position[i]-Pos[j];
            if( tmp > -LoadError && tmp < LoadError ) break;
        }
        if( j < nPoints ) Val[j] += (float)value[i];
        else {
            Pos[nPoints] = (float)position[i];
            Val[nPoints] = (float)value[i];
            nPoints++;
        }
    }
    return 1;
}
int DLoadPoints::IsZero()
{
    for( int i = 0; i < nPoints; i ++ ) {
        if( Val[i] < -LoadError || Val[i] > LoadError ) return 0;
    }
    return 1;
}
void DLoadPoints::InsertPointAt( int index, double pos, double f )
{
    int size;
    size = sizeof(float)*(nPoints+1);
    Pos = (float*)realloc( Pos, size );
    Val = (float*)realloc( Val, size );
    for( size = nPoints; size > index; size -- ) {
        Pos[size] = Pos[size-1];
        Val[size] = Val[size-1];
    }
    Pos[index] = (float)pos;
    Val[index] = (float)f;
    nPoints++;
}
void DLoadPoints::RemovePointAt( int index )
{
    if( index >= nPoints || index < 0 ) return;
    for( int i = index; i < nPoints-1; i ++ ) {
        Pos[i] = Pos[i+1];
        Val[i] = Val[i+1];
    }
    nPoints--;
    if( nPoints == 0 ) {
        Free(Pos);
        Free(Val);
    }
}
void DLoadPoints::AppendPoint( double pos, double f )
{
    int size;
    size = sizeof(float)*(nPoints+1);
    Pos = (float*)realloc( Pos, size );
    Val = (float*)realloc( Val, size );
    Pos[nPoints] = (float)pos;
    Val[nPoints] = (float)f;
    nPoints++;
}
int DLoadPoints::AppendOneLineLoad( double pos1, double f1, double pos2, double f2 )
{
    int i, mIndex, i1, i2;
    short update1, update2;
    double p, v, orgValue;

    if( fabs(f1)+fabs(f2) < LoadError ) return 0;
    if( fabs(pos1-pos2) < LoadError ) return 0;
    if( pos1 > pos2 ) {
        v = pos1;	pos1 = pos2;	pos2 = v;
        v = f1;		f1 = f2;	f2 = v;
    }
    update1 = update2 = 0;
    mIndex = nPoints-1;
    if( mIndex < 0 ) {
        AppendPoint( pos1, f1 );
        AppendPoint( pos2, f2 );
        return 1;
    }
    if( pos2 < Pos[0]+LoadError ) {	// By the left
        InsertPointAt( 0, pos1, f1 );
        if( pos2 > Pos[1]-LoadError ) {
            if( fabs(f2-Val[1]) > LoadError ) InsertPointAt( 1, pos2, f2 );
        }
        else {
            InsertPointAt( 1, pos2, f2 );
            InsertPointAt( 2, pos2, 0.0 );
            InsertPointAt( 3, Pos[3], 0.0 );
        }
        return 1;
    }
    else if( pos1 > Pos[mIndex]-LoadError ) {	// By the right
        if( pos1 < Pos[mIndex]+LoadError ) {
            if( fabs(f1-Val[mIndex]) > LoadError ) InsertPointAt( ++mIndex, pos1, f1 );
        }
        else {
            InsertPointAt( mIndex+1, Pos[mIndex], 0.0 );
            mIndex++;
            InsertPointAt( ++mIndex, pos1, 0.0 );
            InsertPointAt( ++mIndex, pos1, f2 );
        }
        InsertPointAt( ++mIndex, pos2, f2 );
        return 1;
    }
    else if( pos1 < Pos[0]+LoadError || pos2 > Pos[mIndex]-LoadError ) {
        if( pos1 < Pos[0]+LoadError ) {	// (pos1,f1) is by the left, not (pos2,f2)
            if( pos1 > Pos[0]-LoadError ) Val[0] += (float)f1;
            else {
                InsertPointAt( 0, pos1,f1 );
                InsertPointAt( 1, Pos[1],0.0 );
            }
        }
        else update1 = 1;
        mIndex = nPoints-1;
        if( pos2 > Pos[mIndex]-LoadError ) {	// (pos2,f2) is by the right, not (pos1,f1)
            if( pos2 < Pos[mIndex]+LoadError ) Val[mIndex] += (float)f2;
            else {
                InsertPointAt( mIndex+1, Pos[mIndex], 0.0 );
                InsertPointAt( mIndex+2, pos2, f2 );
            }
        }
        else update2 = 1;
        i1 = 0;
        i2 = mIndex = nPoints-1;
    }
    else {
        update1 = update2 = 1;
    }
    if( update1 ) {	// i1 will exist between the first and the last items
        for( i = 1; i < nPoints; i ++ ) {
            if( Pos[i]-LoadError > pos1 ) break; // pos1 locates in [i-1,i)
        }
        if( Pos[i-1]+LoadError > pos1 ) {	// pos1 is equal to i-1
            orgValue = Val[i-1];
            Val[i-1] += (float)f1;
            i1 = i-1;
            // Combine the two points i-2 and i-1
            if( fabs(Pos[i-2]-Pos[i-1])<LoadError && fabs(Val[i-2]-Val[i-1])<LoadError ) {
                RemovePointAt(i-1);
                i1--;
            }
        }
        else {	// pos1 locates in (i-1, i)
            p = pos1;
            v = Val[i-1] + (Val[i]-Val[i-1])*(pos1-Pos[i-1])/(Pos[i]-Pos[i-1]);
            orgValue = v;
            InsertPointAt( i, p, v );
            i1 = i;
            if( f1<-LoadError || f1>LoadError ) {
                v += f1;
                InsertPointAt( i+1, p, v );
                i1++;
            }
        }
        if( update2 && pos2 < Pos[i1+1]-LoadError ) {// pos1 and pos2 lie between the same section
            p = pos2;
            v = orgValue + (Val[i1+1]-orgValue)*(pos2-Pos[i1])/(Pos[i1+1]-Pos[i1]);
            InsertPointAt( i1+1, p, v );
            i2 = i1+1;
            if( f2<-LoadError || f2>LoadError ) {
                v += f2;
                InsertPointAt( i1+1, p, v );
            }
            update2 = -1;
        }
    }
    else i1 = 0;
    if( update2 > 0 ) {	// i2 will exist between the first and the last items
        for( i = nPoints-1; i >= 0; i -- ) {
            if( Pos[i]+LoadError < pos2 ) break; // pos2 locates in (i,i+1]
        }
        if( Pos[i+1]-LoadError < pos2 ) {	 // pos2 is equal to i+1
            Val[i+1] += (float)f2;
            i2 = i+1;
            // Combine the two points i+1 and i+2
            if( fabs(Pos[i+2]-Pos[i+1])<LoadError && fabs(Val[i+2]-Val[i+1])<LoadError ) {
                RemovePointAt(i+1);
            }
        }
        else {	// pos2 locates in (i,i+1)
            p = pos2;
            v = Val[i] + (Val[i+1]-Val[i])*(pos2-Pos[i])/(Pos[i+1]-Pos[i]);
            InsertPointAt( i+1, p, v );
            if( f2<-LoadError || f2>LoadError ) {
                v += f2;
                InsertPointAt( i+1, p, v );
            }
            i2 = i+1;
        }
    }
    else if( update2 == 0 ) i2 = nPoints-1;
    for( i = i1+1; i < i2; i ++ ) {
        Val[i] += (float)(f1+(Pos[i]-pos1)*(f2-f1)/(pos2-pos1));
    }
    return 1;
}
void DLoadPoints::Serialize( bofstream & fout )
{
    fout << nPoints;
    int size = sizeof(float)*nPoints;
    fout.Write( Pos, size );
    fout.Write( Val, size );
}
void DLoadPoints::Serialize( bifstream & fin )
{
    fin >> nPoints;
    int size = sizeof(float)*nPoints;
    Pos = (float*)realloc( Pos, size );
    Val = (float*)realloc( Val, size );
    if( nPoints > 0 ) {
        fin.Read( Pos, size );
        fin.Read( Val, size );
    }
}


DLoadPoints的声明

// class DLoadPoints 适用于Frame、Sframe、Cframe和Vframe单元
// Pos[i]要么全都为负数，要么全都为正数
class CLASS_DECLSPEC DLoadPoints {
public:
    short nPoints;
    float *Pos;	// Pos[0—nPoints-1]:荷载作用点距离I端的距离，如果是负数表示相对距离
    float *Val;	// Val[0—nPoints-1]:此作用点的荷载值(可能是线荷载值、集中力或者集中弯矩)
public:
    DLoadPoints();
    ~DLoadPoints();
    DLoadPoints & operator = ( const DLoadPoints & Copy );
    int operator == ( const DLoadPoints & Other );
    void SetPoints( short num, float position[], float value[] ); // 替换原来的荷载作用点值
    void SetPoints( int num, double position[], double value[] );	// 替换原来的荷载作用点值
    int AppendLineLoad( int num, double position[], double value[] );	// 叠加折线荷载
    int AppendPointLoad( int num, double position[], double value[] );	// 叠加点荷载(如集中力和集中弯矩)
    void Clear();
    int IsZero();
    void Serialize( bofstream & fout );
    void Serialize( bifstream & fin );
private:
    int AppendOneLineLoad( double pos1, double f1, double pos2, double f2 );
    void InsertPointAt( int index, double pos, double f );	// 插入荷载作用点, index is zerobased
    void RemovePointAt( int index ); // 删除荷载作用点, index is zerobased
    void AppendPoint( double pos, double f );	// 附加荷载作用点
};


DMaterial的实现

DMaterial::DMaterial()
{
    nID = 0;
    U = E = V = W = M = A = (float)0.0;
    name = new char[10];
    strcpy( name, "material" );
}
DMaterial::DMaterial( DMaterial & Copy )
{
    name = NULL;
    *this = Copy;
}
DMaterial::~DMaterial()
{
    if( name ) delete[] name;
}
DMaterial & DMaterial::operator = ( const DMaterial & Copy )
{
    if( this != &Copy ) {
        nID = Copy.nID;
        SetName( Copy.name );
        U = Copy.U;
        E = Copy.E;
        V = Copy.V;
        W = Copy.W;
        M = Copy.M;
        A = Copy.A;
    }
    return *this;
}

void DMaterial::SetName( const char * nameStr )
{
    int len = strlen(nameStr)+1;
    if( name ) delete[] name;
    name = new char[len];
    strcpy( name, nameStr );
}
double DMaterial::GetElasticModule(int unit)
{
    if( E>1.0E-5 ) return E;
    else if( U>7 ) return GetElasticModuleFromConcret(U,unit);
    return 0;
}
double DMaterial::GetElasticModuleFromConcret( double con,int unit )
{
    double us[14]={15,20,25,30,35,40,45,50,55,60,65,70,75,80};
    double es[14]={2.2,2.55,2.8,3.0,3.15,3.45,3.55,3.6,3.65,3.7,3.75,3.8};
    double dim=DCommonData::DimensionFactor(unit);
    return GFunc::GetYToXOnSomeData( con, us, es, 14, 1, 1 )*1.0E7*DCommonData::ForceFactor(unit)/dim/dim;
}
double DMaterial::GetVolWeight( int unit )
{
    if( W > 1.0E-5 ) return W;
    if( U > 7 ) {
        double f = DCommonData::DimensionFactor(unit);
        return DCommonData::ForceFactor(unit)*24.5/f/f/f;
    }
    return 0.0;
}
double DMaterial::GetVolMass( int unit )
{
    if( M > 1.0E-5 ) return M;
    if( U > 7 ) {
        double f = DCommonData::DimensionFactor(unit);
        return DCommonData::MassFactor(unit)*2.5/f/f/f;
    }
    return 0.0;
}
int DMaterial::operator == ( const DMaterial & Other )
{
    return (strcmp( name, Other.name)==0);
    /*
    double tmp;
    tmp = C - Other.C;
    if( tmp < -MaterialError || tmp > MaterialError ) return 0;
    tmp = W - Other.W;
    if( tmp < -MaterialError || tmp > MaterialError ) return 0;
    tmp = M - Other.M;
    if( tmp < -MaterialError || tmp > MaterialError ) return 0;
    for( int i = 0; i < nT; i ++ ) {
        if( !(pTempMat[i]==Other.pTempMat[i]) ) return 0;
    }
    return 1;
    */
}

void DMaterial::Serialize( bofstream & fout )
{
    fout << nID;
    int len = strlen( name )+1;
    fout.Write( &len, sizeof(int) );
    fout.Write( name, len );
    fout << U << E << V << W << M << A;
}
void DMaterial::Serialize( bifstream & fin )
{
    int len;
    fin >> nID;
    fin.Read( &len, sizeof(int) );
    if( name ) delete[] name;
    name = new char[len];
    fin.Read( name, len );
    fin >> U >> E >> V >> W >> M >> A;
}


DMaterial的声明

class CLASS_DECLSPEC DMaterial {
public:
    short nID;
    char *name;	// 保存时先保存字符长度(含c语言的结束符), 再保存字符串(含结束符)
    float U;	// 混凝土号
    float E;	// 弹性模量
    float V;	// 泊松比
    float W;	// 重度
    float M;	// 密度
    float A;	// 热膨胀系数
public:
    DMaterial();
    DMaterial( DMaterial & Copy );
    virtual ~DMaterial();
    DMaterial & operator = ( const DMaterial & Copy );
    // 通过名称确定是否相等
    int operator == ( const DMaterial & Other );
    // 设置截面标识名称
    void SetName( const char * nameStr );
    // 返回材料的弹性模量
    double GetElasticModule(int unit);
    // 根据混凝土标号求得弹性模量, 单位制为unit
    static double GetElasticModuleFromConcret( double con, int unit );
    // 返回材料的比重
    double GetVolWeight( int unit );
    // 返回材料的密度
    double GetVolMass( int unit );

    virtual void Serialize( bofstream & fout );
    virtual void Serialize( bifstream & fin );
};


DNodeBase的实现

DNodeBase::DNodeBase()
{
    nID = 0;
    nLevel = 1;
    nLayer = 1;
    for( int i = 0; i < 3; i ++ )
        Coord[i] = 0.0;
    nLink = 0;
    nRest = 0;
    nMaster = 0;
    nMasterType = 1;
    nMass = 0;
    Temp = (float)0.0;
    nTower = 1;
}

DNodeBase::DNodeBase( double xyz[3] )
{
    nID = 0;
    nLevel = 1;
    nLayer = 1;
    nLink = 0;
    nRest = 0;
    nMaster = 0;
    nMasterType = 1;
    nMass = 0;
    Temp = (float)0.0;
    nTower = 1;
    for( int i = 0; i < 3; i ++ )
        Coord[i] = xyz[i];
}

DNodeBase::DNodeBase( const DNodeBase & Copy )
{
    *this = Copy;
}
DNodeBase::~DNodeBase()
{
}
DNodeBase & DNodeBase::operator = ( const DNodeBase & Copy )
{
    if( this != &Copy ) {
        nID = Copy.nID;
        nLevel = Copy.nLevel;
        nLayer = Copy.nLayer;
        for( int i = 0; i < 3; i ++ )
            Coord[i] = Copy.Coord[i];
        nLink = Copy.nLink;
        nRest = Copy.nRest;
        nMaster = Copy.nMaster;
        nMasterType = Copy.nMasterType;
        nMass = Copy.nMass;
        Temp = Copy.Temp;
        nTower = Copy.nTower;
        Load = Copy.Load;
    }
    return *this;
}

int DNodeBase::operator == ( const DNodeBase & Other ) const
{
    double tmp;
    for( int i = 0; i < 3; i ++ ) {
        tmp = Coord[i] - Other.Coord[i];
        if( tmp > NodeMinDist || tmp < -NodeMinDist) return 0;
    }
    return 1;
}
void DNodeBase::Serialize( bofstream & fout )
{
    fout << nID << nLevel << nLayer;
    fout.Write( Coord, sizeof(double)*3 );
    fout << nLink << nRest << nMaster << nMasterType << nMass << Temp << nTower;
    Load.Serialize( fout );
}
void DNodeBase::Serialize( bifstream & fin )
{
    fin >> nID >> nLevel >> nLayer;
    fin.Read( Coord, sizeof(double)*3 );
    fin >> nLink >> nRest >> nMaster >> nMasterType >> nMass >> Temp >> nTower;
    Load.Serialize( fin );
}


DNodeBase的声明

class CLASS_DECLSPEC DNodeBase {
public:
    int  nID;		// 节点号，在最后的结果中节点号必须连续
    short nLevel;   // 层标识号(指向DLevelBase的nID)，层号=nID-2
    short nLayer;	// 图层号(指向DLayerBase的nID)，与层号相互独立，缺省为1
    double Coord[3];	// 节点坐标值，鉴于其精度对图形操作非常重要，这里使用了double
    unsigned char nLink;// 与节点相连的单元数目(不超过255个)
    unsigned char nRest;// 节点的Resistaint信息
    int nMaster;		// The master node.
    unsigned char nMasterType;// 主从约束类型，1：刚性楼板主从约束，其它类型待定
    // 指向类DNodeMass数组的nID
    int nMass;	// 节点集中质量的索引号，如果小于等于零，表示没有集中质量
    float Temp;			// 节点温度，初始化为0
    unsigned char nTower; // 塔号(从1开始)
    // Load[i].LocalID指向类DNodeLoad数组的nID
    DElementLoad Load;// 用于描述各总体荷载种类下作用的节点集中力
public:
    DNodeBase();
    DNodeBase( double xyz[3] );
    DNodeBase( const DNodeBase & Copy );
    virtual ~DNodeBase();
    int operator == ( const DNodeBase & Other ) const;
    DNodeBase & operator = ( const DNodeBase & Copy );
    double & operator[]( int i ) {	// 返回节点的坐标值
        assert(i>=0 && i<3);
        return Coord[i];
    }
    int IsRest( const int i ) {		// 判断第i个自由度是否被约束(i从1到6)
        return (nRest&(0x01<<(i-1)));
    }
    void Rest( const int i ) {	// 约束第i个自由度(i从1到6)
        nRest |= (0x01<<(i-1));
    }
    void UnRest( const int i ) {	// 放松第i个自由度(i从1到6)
        nRest &= (~(0x01<<(i-1)));
    }

    virtual void Serialize( bifstream & fin );
    virtual void Serialize( bofstream & fout );
};


DNodeConstraint的实现

DNodeConstraint::DNodeConstraint()
{
nConstrainted = 0;
for( int i = 0; i < 6; i ++ )
nConstraintTo[i] = 0;
}

DNodeConstraint::DNodeConstraint( int coned, int conto[6] )
{
nConstrainted = coned;
for( int i = 0; i < 6; i ++ )
nConstraintTo[i] = conto[i];
}
DNodeConstraint::DNodeConstraint( DNodeConstraint & Copy )
{
*this = Copy;
}

DNodeConstraint & DNodeConstraint::operator = ( const DNodeConstraint & Copy )
{
if( this != &Copy ) {
nConstrainted = Copy.nConstrainted;
for( int i = 0; i < 6; i ++ )
nConstraintTo[i] =
  Copy.nConstraintTo[i];
}
return *this;
}
int DNodeConstraint::operator == ( const DNodeConstraint & Other )
{
if( nConstrainted != Other.nConstrainted ) return 0;
for( int i = 0; i < 6; i ++ )
if( nConstraintTo[i] != Other.nConstraintTo[i]
  ) return 0;
return 1;
}

void DNodeConstraint::Serialize( bofstream & fout )
{
fout << nConstrainted;
fout.Write( nConstraintTo, sizeof(int)*6 );
}
void DNodeConstraint::Serialize( bifstream & fin )
{
fin >> nConstrainted;
fin.Read( nConstraintTo, sizeof(int)*6 );
}


DNodeConstraint的声明

class CLASS_DECLSPEC DNodeConstraint {
public:
int nConstrainted; // 被强制元素的节点的nID号，指向DNodeBase中的nID
int nConstraintTo[6]; // 如果nConstraintTo[i]不等于零，则nConstrainted节点在第i个自由度
// 上的位移等于节点nConstraintTo[i]的相应位移。均指向DNodeBase中的nID
public:
DNodeConstraint();
DNodeConstraint( int coned, int conto[6] );
DNodeConstraint( DNodeConstraint & Copy );
DNodeConstraint & operator = ( const DNodeConstraint & Copy );
int operator == ( const DNodeConstraint & Other );

virtual void Serialize( bifstream & fin );
virtual void Serialize( bofstream & fout );
};


DNodeDisplacement的实现

DNodeDisplacement::DNodeDisplacement()
{
    ndNo = 0;
    isTransfer = 1;
    dir[0] = dir[1] = dir[2] = (float)0.0;
}
DNodeDisplacement & DNodeDisplacement::operator =(const DNodeDisplacement &other)
{
    ndNo = other.ndNo;
    isTransfer = other.isTransfer;
    lcDisp = other.lcDisp;
    memcpy( dir, other.dir, sizeof(float)*3 );
    return *this;
}
int DNodeDisplacement::operator ==(const DNodeDisplacement &other) const
{
    if( ndNo != other.ndNo ) return 0;
    if( isTransfer != other.isTransfer ) return 0;
    if( fabs(dir[0]*other.dir[1]-dir[1]*other.dir[0]) > 1.0E-3 ) return 0;
    if( fabs(dir[1]*other.dir[2]-dir[2]*other.dir[1]) > 1.0E-3 ) return 0;
    if( fabs(dir[0]*other.dir[2]-dir[2]*other.dir[0]) > 1.0E-3 ) return 0;
    // 方向正好相反
    //if( dir[0]*other.dir[0]+dir[1]*other.dir[1]+dir[2]*other.dir[2] < 0 ) return 0;
    return 1;
}
void DNodeDisplacement::Serialize( bifstream & fin )
{
    fin >> ndNo >> isTransfer;
    lcDisp.Serialize( fin );
    fin.Read( dir, sizeof(float)*3 );
}
void DNodeDisplacement::Serialize( bofstream & fout )
{
    fout << ndNo << isTransfer;
    lcDisp.Serialize( fout );
    fout.Write( dir, sizeof(float)*3 );
}


DNodeDisplacement的声明

// 节点任意方向的指定位移
class CLASS_DECLSPEC DNodeDisplacement {
public:
    int ndNo;	// 节点nID号
    int isTransfer;	// =1表示指定节点平移位移，=0则表示指定节点转角
    // lcDisp[i].Factor表示荷载种类lcDisp[i].no下的指定位移，
    // 没有出现的荷载种类表示指定位移等于0
    DNumFactors lcDisp;
    float dir[3];	// 指定位移所在的方向(不一定要求归一化)
public:
    DNodeDisplacement();
    DNodeDisplacement( const DNodeDisplacement & copy ) {
        *this = copy;
    }
    DNodeDisplacement & operator =(const DNodeDisplacement &other);
    // 只要节点号、类型和方向相同即认为相等
    int operator == (const DNodeDisplacement &other) const;

    virtual void Serialize( bifstream & fin );
    virtual void Serialize( bofstream & fout );
};


DNodeLoad的实现

DNodeLoad::DNodeLoad()
{
nID = 0;
for( int i = 0; i < 6; i ++ ) {
F[i] = (float)0.0;
U[i] = (float)0.0;
}
}
DNodeLoad::DNodeLoad( int id, double * f, double *u )
{
nID = id;
for( int i = 0; i < 6; i ++ ) {
if( f != NULL ) F[i] = (float)f[i];
else F[i] = 0.0;
if( u != NULL ) U[i] = (float)u[i];
else U[i] = 0.0;
}
}
DNodeLoad::DNodeLoad( DNodeLoad & Copy )
{
*this = Copy;
}

DNodeLoad & DNodeLoad::operator = ( const DNodeLoad & Copy )
{
if( this != &Copy ) {
nID = Copy.nID;
for( int i = 0; i < 6; i ++ ) {
F[i] = Copy.F[i];
U[i] = Copy.U[i];
}
}
return *this;
}
int DNodeLoad::operator == ( const DNodeLoad & Other )
{
double tmp;
for( int i = 0; i < 6; i ++ ) {
tmp = F[i] - Other.F[i];
if( tmp > LoadError || tmp < -LoadError)
  return 0;
tmp = U[i] - Other.U[i];
if( tmp > LoadError || tmp < -LoadError)
  return 0;
}
return 1;
}
void DNodeLoad::SetForce( double f[6] )
{
for( int i = 0; i < 6; i ++ )
F[i] = (float)f[i];
}
void DNodeLoad::SetDisplace( double u[6] )
{
for( int i = 0; i < 6; i ++ )
U[i] = (float)u[i];
}

void DNodeLoad::IncreaseForce( double f[6] )
{
for( int i = 0; i < 6; i ++ )
F[i] += (float)f[i];
}
void DNodeLoad::DecreaseForce( double f[6] )
{
for( int i = 0; i < 6; i ++ )
F[i] -= (float)f[i];
}
void DNodeLoad::IncreaseDisplace( double u[6] )
{
for( int i = 0; i < 6; i ++ )
U[i] += (float)u[i];
}
void DNodeLoad::DecreaseDisplace( double u[6] )
{
for( int i = 0; i < 6; i ++ )
U[i] -= (float)u[i];
}

void DNodeLoad::Serialize( bofstream & fout )
{
fout << nID;
fout.Write( F, sizeof(float)*6 );
fout.Write( U, sizeof(float)*6 );
}
void DNodeLoad::Serialize( bifstream & fin )
{
fin >> nID;
fin.Read( F, sizeof(float)*6 );
fin.Read( U, sizeof(float)*6 );
}


DNodeLoad的声明

// 节点的集中荷载，一个节点在某一载荷种类下只允许存在DNodeLoad对象
class CLASS_DECLSPEC DNodeLoad {
public:
    int nID;	// 标示ID
    float F[6];	// x,y,z方向的集中力和集中弯矩
    float U[6];	// 节点强制位移和转角:ux,uy,uz,rx,ry,rz
public:
    DNodeLoad();
    DNodeLoad( int id, double * f = NULL, double *u = NULL );
    DNodeLoad( DNodeLoad & Copy );
    DNodeLoad & operator = ( const DNodeLoad & Copy );
    int operator == ( const DNodeLoad & Other );
    void SetForce( double f[6] );
    void SetDisplace( double u[6] );

    void IncreaseForce( double f[6] );
    void DecreaseForce( double f[6] );
    void IncreaseDisplace( double u[6] );
    void DecreaseDisplace( double u[6] );

    virtual void Serialize( bifstream & fin );
    virtual void Serialize( bofstream & fout );
};


DNodeMass的实现

DNodeMass::DNodeMass()
{
    nID = 0;
    memset(Mass, 0, sizeof(Mass) );
}
DNodeMass::DNodeMass( int ID, double m[6] )
{
    nID = ID;
    for( int i = 0; i < 6; i ++ ) {
        if( m != NULL )
            Mass[i] = (float)m[i];
        else Mass[i] = 0.0;
    }
}

DNodeMass::DNodeMass( DNodeMass & Copy )
{
    *this = Copy;
}
DNodeMass & DNodeMass::operator = ( const DNodeMass & Copy )
{
    if( this != &Copy ) {
        nID = Copy.nID;
        memcpy( Mass, Copy.Mass, sizeof(Mass) );
    }
    return *this;
}
int DNodeMass::operator == ( const DNodeMass & Other )
{
    double tmp;
    for( int i = 0; i < 6; i ++ ) {
        tmp = Mass[i] - Other.Mass[i];
        if( tmp > MassSpringError || tmp < -MassSpringError) return 0;
    }
    return 1;
}

void DNodeMass::SetMass( double m[6] )
{
    for( int i = 0; i < 6; i ++ ) {
        Mass[i] = (float)m[i];
    }
}

void DNodeMass::IncreaseMass( double m[6] )
{
    for( int i = 0; i < 6; i ++ ) {
        Mass[i] += (float)m[i];
    }
}
void DNodeMass::DecreaseMass( double m[6] )
{
    for( int i = 0; i < 6; i ++ ) {
        Mass[i] -= (float)m[i];
    }
}

void DNodeMass::Serialize( bofstream & fout )
{
    fout << nID;
    fout.Write( Mass, sizeof(Mass) );
}
void DNodeMass::Serialize( bifstream & fin )
{
    fin >> nID;
    fin.Read( Mass, sizeof(Mass) );
}


DNodeMass的声明

// 节点的集中质量
class CLASS_DECLSPEC DNodeMass {
public:
    int nID;	// 索引号, 并非节点号，它所归属的节点只能从DNodeBase中的nMass看出
    float Mass[6];
public:
    DNodeMass();
    DNodeMass( int ID, double * m = NULL );
    DNodeMass( DNodeMass & Copy );
    DNodeMass & operator = ( const DNodeMass & Copy );
    int operator == ( const DNodeMass & Other );
    void SetMass( double m[6] );

    void IncreaseMass( double m[6] );
    void DecreaseMass( double m[6] );

    virtual void Serialize( bifstream & fin );
    virtual void Serialize( bofstream & fout );
};


DNodeSpring的实现

DNodeSpring::DNodeSpring()
{
    nID = 0;
    fromNd = toNd = 0;
    type = 0;
    k = 0;
    dir[0] = dir[1] = dir[2] = 0.0;
    nAct = 1;
}
DNodeSpring & DNodeSpring::operator =(const DNodeSpring &other)
{
    if( type != other.type ) return 0;
    if( this != &other ) {
        fromNd = other.fromNd;
        toNd = other.toNd;
        type = other.type;
        k = other.k;
        memcpy( dir, other.dir, sizeof(dir) );
        nAct = other.nAct;
    }
    return *this;
}
int DNodeSpring::operator ==(const DNodeSpring &Other) const
{
    if( toNd > 0 ) {
        return ( (fromNd == Other.fromNd && toNd == Other.toNd) ||
            (fromNd == Other.toNd && toNd == Other.fromNd) );
    }
    else {
        if( fromNd != Other.fromNd ) return 0;
        if( fabs(dir[0]*Other.dir[1]-dir[1]*Other.dir[0]) > 1.0E-3 ) return 0;
        if( fabs(dir[1]*Other.dir[2]-dir[2]*Other.dir[1]) > 1.0E-3 ) return 0;
        if( fabs(dir[0]*Other.dir[2]-dir[2]*Other.dir[0]) > 1.0E-3 ) return 0;
    }
    return 1;
}
void DNodeSpring::Serialize( bifstream & fin )
{
    if( nVersion > 100 ) fin >> nID;
    else {
        curSprnID ++;
        nID = curSprnID;
    }
    fin >> fromNd >> toNd >> type >> k;
    fin.Read( dir, sizeof(dir) );
    if( nVersion > 110 ) fin >> nAct;
}
void DNodeSpring::Serialize( bofstream & fout )
{
    fout << nID << fromNd << toNd << type << k;
    fout.Write( dir, sizeof(dir) );
    fout << nAct;
}


DNodeSpring的声明

// 连接两点节点的弹簧
class CLASS_DECLSPEC DNodeSpring{
public:
    int nID;
    // 弹簧连接的起始和终端节点nID号, 如果toNd==0表示接地弹簧,否则表示连接弹簧
    int fromNd, toNd;
    unsigned char type; // 弹簧类型 0: 直弹簧 1: 扭转弹簧
    double k; // 直弹簧或扭转弹簧的刚度
    double dir[3];	// 接地弹簧的方向(toNd=0时才有效)
    short nAct; // 施工模拟的步号(one-based)
public:
    DNodeSpring();
    DNodeSpring( const DNodeSpring & copy ) {
        *this = copy;
    }
    DNodeSpring & operator =(const DNodeSpring &other);
    // 不仅节点需要相等，弹簧类型也要求相同，对于接地弹簧还要求方向一致(刚度不要求相等)
    int operator == (const DNodeSpring &other) const;

    virtual void Serialize( bifstream & fin );
    virtual void Serialize( bofstream & fout );
};


DNumFactors的实现

DNumFactors::DNumFactors()
{
    nNum = 0;
    nf = NULL;
}
DNumFactors::~DNumFactors()
{
    Clear();
}
DNumFactors & DNumFactors::operator = ( const DNumFactors & Copy )
{
    if( this != &Copy ) {
        Clear();
        nNum = Copy.nNum;
        if( nNum > 0 ) {
            nf = (DNumFactorPair*)malloc( sizeof(DNumFactorPair)*nNum );
            memcpy( nf, Copy.nf, sizeof(DNumFactorPair)*nNum );
        }
    }
    return (*this);
}
int DNumFactors::operator==( const DNumFactors &Other) const
{
    double tmp;
    if( nNum != Other.nNum ) return 0;
    for( int i = 0; i < nNum; i ++ ) {
        if( nf[i].No != nf[i].No ) return 0;
        tmp = nf[i].Factor-nf[i].Factor;
        if( tmp > CombinationError || tmp < -CombinationError ) return 0;
    }
    return 1;
}
DNumFactorPair & DNumFactors::operator[](const int index)
{
    assert(index<nNum && index>=0);
    return nf[index];
}
int DNumFactors::Index( short no )
{
    int i=0, j=nNum-1, tmp;
    while( i <= j ) {
        tmp = ((i+j)>>1);
        if( nf[tmp].No < no ) i = tmp+1;
        else if( nf[tmp].No == no ) return tmp;
        else j = tmp-1;
    }
    return -1;
}
int DNumFactors::Insert( short no, float factor, int factorCanBeZero )
{
    if( no <= 0 ) return 0;
    int i=0, j=nNum-1, tmp, factorIsZero=1;
    if( factor < -CombinationError || factor > CombinationError ) factorIsZero = 0;
    while( i <= j ) {
        tmp = ((i+j)>>1);
        if( nf[tmp].No < no ) i = tmp+1;
        else if( nf[tmp].No == no ) {
            if( factorIsZero && !factorCanBeZero ) {	// 删除
                if( nNum == 1 ) Clear();
                else {
                    for( j = tmp; j < nNum-1; j ++ ) nf[j] = nf[j+1];
                    nNum --;
                    nf = (DNumFactorPair*)realloc( nf, sizeof(DNumFactorPair)*nNum );
                }
            }
            else nf[tmp].Factor = factor;
            return 1;
        }
        else j = tmp-1;
    }
    if( factorIsZero && !factorCanBeZero ) return 0;
    nNum ++;
    nf = (DNumFactorPair*)realloc( nf, sizeof(DNumFactorPair)*nNum );
    for( j = nNum-1; j > i; j -- ) nf[j] = nf[j-1];
    nf[i].No = no;
    nf[i].Factor = factor;
    return 1;
}
void DNumFactors::Clear()
{
    nNum = 0;
    if( nf ) {
        free(nf);
        nf = NULL;
    }
}
void DNumFactors::Serialize( bofstream & fout )
{
    fout << nNum;
    for( int i = 0; i < nNum; i ++ ) {
        fout << nf[i].No << nf[i].Factor;
    }
}

void DNumFactors::Serialize( bifstream & fin )
{
    Clear();
    fin >> nNum;
    if( nNum > 0 ) {
        nf = (DNumFactorPair*)malloc( sizeof(DNumFactorPair)*nNum );
        for( int i = 0; i < nNum; i ++ ) {
            fin >> nf[i].No >> nf[i].Factor;
        }
    }
}


DNumFactors的声明

// 用于描述整数对应的系数，例如，某荷载种类下的组合系数等
struct CLASS_DECLSPEC DNumFactorPair {
    short No;
    float Factor;
};
// 记录整数与实数的对应关系，如，荷载种类和组合系数等
class CLASS_DECLSPEC DNumFactors {
private:
    short nNum;
    DNumFactorPair *nf;	// 数据必须按No排序
public:
    DNumFactors();
    ~DNumFactors();
    DNumFactors( const DNumFactors & Copy ) {
        (*this) = Copy;
    }
    DNumFactors & operator = ( const DNumFactors & Copy );
    int operator==( const DNumFactors &Other) const;
    int Entries() { return nNum; }
    DNumFactorPair & operator[](const int index);
    // 查找整数no所处的索引号，返回-1(没有找到)或大于等于0的索引值
    int Index( short no );
    // 如果整数no已经存在，则作替换, 如果no＝0,返回0
    // 如果factorCanBeZero=0并且factor=0, 则表示删除no对应的项,
    int Insert( short no, float factor, int factorCanBeZero );
    // 删除整数no对应的项
    int Remove( short no ) { return Insert( no, 0, 0 ); }
    void Clear();

    void Serialize( bofstream & fout );
    void Serialize( bifstream & fin );
};


DPipeBase的实现

DPipeBase::DPipeBase( )
{
    nID = 0;
    nLevel = 1;
    nLayer = 1;
    nI = nJ = 0;
    nType = 0;
    for( int i = 0; i < 3; i ++ ) {
        Local[i] = (float)0;
        KCoord[i] = (float)0;
    }
    nSect = nMat = 0;
    Pressure = (float)0;
    T0 = R = (float)0;
    nKType = 0;
    nAct = 1;
}
DPipeBase::DPipeBase( int i, int j )
{
    nID = 0;
    nLevel = 1;
    nLayer = 1;
    nI = i;
    nJ = j;
    nType = 0;
    for( int k = 0; k < 3; k ++ ) {
        Local[k] = (float)0;
        KCoord[k] = (float)0;
    }
    nSect = nMat = 0;
    Pressure = (float)0;
    T0 = R = (float)0;
    nKType = 0;
    nAct = 1;
}
DPipeBase::DPipeBase( const DPipeBase & Copy)
{
    *this = Copy;
}
DPipeBase & DPipeBase::operator = ( const DPipeBase & Copy )
{
    if( this != &Copy ) {
        nID = Copy.nID;
        nLevel = Copy.nLevel;
        nLayer = Copy.nLayer;
        nI = Copy.nI;
        nJ = Copy.nJ;
        nType = Copy.nType;
        for( int i = 0; i < 3; i ++ ) {
            Local[i] = Copy.Local[i];
            KCoord[i] = Copy.KCoord[i];
        }
        nSect = Copy.nSect;
        nMat = Copy.nMat;
        Pressure = Copy.Pressure;
        T0 = Copy.T0;
        R = Copy.R;
        nKType = Copy.nKType;
        nAct = Copy.nAct;
    }
    return *this;
}
int DPipeBase::operator == ( const DPipeBase & Other )
{
    return ((nI==Other.nI)&&(nJ==Other.nJ))||((nI==Other.nJ)&&(nJ==Other.nI));
}
void DPipeBase::SetLocal2( double local[3] )
{
    for( int i = 0; i < 3; i ++ )
        Local[i] = (float)local[i];
    nType = 1;
}
void DPipeBase::SetCurveData( double radius, double kcoord[3], int ktype )
{
    R = (float)radius;
    for( int i = 0; i < 3; i ++ )
        KCoord[i] = (float)kcoord[i];
    nKType = (unsigned char)ktype;
    nType = 2;
}

int DPipeBase::GetLocal2( double local[3] )
{
    if( nType != 1 ) return 0;
    for( int i = 0; i < 3; i ++ )
        local[i] = Local[i];
    return 1;
}
int DPipeBase::GetCurveData( double & radius, double kcoord[3], int & ktype )
{
    if( nType != 2 ) return 0;
    radius = R;
    for( int i = 0; i < 3; i ++ )
        kcoord[i] = KCoord[i];
    ktype = nKType;
    return 1;
}
void DPipeBase::Serialize( bofstream & fout )
{
    fout << nID << nLevel << nLayer << nI << nJ << nType;
    fout.Write( Local, sizeof(float)*3 );
    fout << nSect << nMat << Pressure << T0;
    if( nType == 2 ) {
        fout << R << nKType;
        fout.Write( KCoord, sizeof(float)*3 );
    }
    fout << nAct;
}
void DPipeBase::Serialize( bifstream & fin )
{
    fin >> nID >> nLevel >> nLayer >> nI >> nJ >> nType;
    fin.Read( Local, sizeof(float)*3 );
    fin >> nSect >> nMat >> Pressure >> T0;
    if( nType == 2 ) {
        fin >> R >> nKType;
        fin.Read( KCoord, sizeof(float)*3 );
    }
    if( nVersion > 100 ) fin >> nAct;
}


DPipeBase的声明

class CLASS_DECLSPEC DPipeBase {
public:
    int nID;		// 单元号，如果要用于array.h中的MArrayID类，其名称必须为nID
    short nLevel;   // 层标识号(指向DLevelBase的nID)，层号=nID-2
    short nLayer;	// (指向DLayerBase的nID)，与层号相互独立，缺省为1
    int nI,nJ;      // node I, node J.
    unsigned char nType;	// 单元类型	 1：直管；2：曲管
    float Local[3];	// 局部坐标系e2轴所指方向的坐标，仅仅用于直管单元
    // 分别指向类DPipeSect、DMaterial数组的nID
    short nSect,nMat;// 截面号和材料号, 该号指向截面或材料类的nID数据成员
    float Pressure;	//	单元内压
    float T0;		// 无应力状态参考温度
        //  下面三行数据仅仅用于曲管单元(nType == 2 ),只有==
    2时才保存 float			R;  //
    曲管的曲率半径 unsigned char	nKType;  //
                            参考点K的类型1(K为曲管中心线在两端的切线交点)               //
    2(K为曲率中心) float		KCoord[3];  //
    参考点K的坐标 short nAct; // 施工模拟的步号(one-based)
public:
    DPipeBase( );
    DPipeBase( int i, int j );
    DPipeBase( const DPipeBase & Copy);
    DPipeBase & operator = ( const DPipeBase & Copy );
    int operator ==  ( const DPipeBase & Other
    ); //设置直管单元的局部坐标e2的参考向量，若nType!=1,将设置nType=
    1 void SetLocal2( double local[3]
    ); //设置曲管单元的几何参数，nType!=2,将设置nType=2
    // kcoord为参考点的坐标，ktype为参考点的类型
    void SetCurveData( double radius, double kcoord[3], int ktype = 1 );
    // 如果单元并非直管单元，返回0
    int GetLocal2( double local[3] );
    int GetCurveData( double & radius, double kcoord[3], int & ktype );

    virtual void Serialize( bifstream & fin );
    virtual void Serialize( bofstream & fout );
};


DPipeForce的实现

DPipeForce::DPipeForce()
{
    nID = 0;
    HaveMid = 0;
    memset( FI, 0x00, sizeof(FI) );
    memset( FMid, 0x00, sizeof(FMid) );
    memset( FJ, 0x00, sizeof(FJ) );
}
DPipeForce::DPipeForce( DPipeForce & Copy )
{
    *this = Copy;
}
DPipeForce & DPipeForce::operator = ( const DPipeForce & Copy )
{
    if( this != &Copy ) {
        nID = Copy.nID;
        HaveMid = Copy.HaveMid;
        memcpy( FI, Copy.FI, sizeof(FI) );
        memcpy( FMid, Copy.FMid, sizeof(FMid) );
        memcpy( FJ, Copy.FJ, sizeof(FJ) );
    }
    return *this;
}
void DPipeForce::Serialize(bofstream & fout)
{
    fout << nID << HaveMid;
    fout.Write( FI, sizeof(double)*6 );
    fout.Write( FMid, sizeof(double)*6 );
    fout.Write( FJ, sizeof(double)*6 );
}
void DPipeForce::Serialize(bifstream & fin)
{
    fin >> nID >> HaveMid;
    fin.Read( FI, sizeof(double)*6 );
    fin.Read( FMid, sizeof(double)*6 );
    fin.Read( FJ, sizeof(double)*6 );
}


DPipeForce的声明

class CLASS_DECLSPEC DPipeForce {
public:
    int nID;		// 单元号或组合号
    // 如果!=0，表示FMid有效，否则FMid无效
    char HaveMid;
    // I端的轴力、1-2平面内的剪力和弯矩、1-3平面内的剪力和弯矩、扭矩
    double FI[6];
    // 中端的轴力、1-2平面内的剪力和弯矩、1-3平面内的剪力和弯矩、扭矩
    double FMid[6];
    // J端的轴力、1-2平面内的剪力和弯矩、1-3平面内的剪力和弯矩、扭矩
    double FJ[6];
public:
    DPipeForce();
    DPipeForce( DPipeForce & Copy );
    virtual ~DPipeForce() {}
    DPipeForce & operator = ( const DPipeForce & Copy );
    // 尽管下面两个函数暂时没有用处，但是为了方便定义可变数组类对象还是定义了这两个函数
    void Serialize(bofstream & fout);
    void Serialize(bifstream & fin);
};


DPipeSect的实现

DPipeSect::DPipeSect( )
{
    nID = 0;
    Diameter = Thick = 0.0;
    Shear = 2.0;
    name = new char[10];
    strcpy( name, "psection" );
}
DPipeSect::~DPipeSect()
{
    if( name ) delete[] name;
}
DPipeSect::DPipeSect( DPipeSect & Copy )
{
    name = NULL;
    *this = Copy;
}
DPipeSect & DPipeSect::operator = ( const DPipeSect & Copy )
{
    if( this != &Copy ) {
        nID = Copy.nID;
        Diameter = Copy.Diameter;
        Thick = Copy.Thick;
        Shear = Copy.Shear;
        SetName( Copy.name );
    }
    return *this;
}
void DPipeSect::SetName( const char * nameStr )
{
    int len = strlen(nameStr)+1;
    if( name ) delete[] name;
    name = new char[len];
    strcpy( name, nameStr );
}
int DPipeSect::operator == ( const DPipeSect & Other )
{
    return (strcmp( name, Other.name)==0);
    /*
    double tmp;
    tmp = Diameter - Other.Diameter;
    if( tmp < -SectionError || tmp > SectionError ) return 0;
    tmp = Thick - Other.Thick;
    if( tmp < -SectionError || tmp > SectionError ) return 0;
    tmp = Shear - Other.Shear;
    if( tmp < -SectionError || tmp > SectionError ) return 0;
    return 1;
    */
}
double DPipeSect::GetSectArea( )
{
    return PI*Thick*(Diameter-Thick);
}
void DPipeSect::Serialize( bofstream & fout )
{
    int len = strlen( name )+1;
    fout << nID;
    fout.Write( &len, sizeof(int) );
    fout.Write( name, len );
    fout << Diameter << Thick << Shear;
}
void DPipeSect::Serialize( bifstream & fin )
{
    int len;
    fin >> nID;
    fin.Read( &len, sizeof(int) );
    if( name ) delete[] name;
    name = new char[len];
    fin.Read( name, len );
    fin >> Diameter >> Thick >> Shear;
}


DPipeSect的声明

// 材料的几何属性。
// 此类适合于PIPE单元
class CLASS_DECLSPEC DPipeSect {
public:
    short nID;
    char *name;	// 保存时先保存字符长度(含c语言的结束符), 再保存字符串(含结束符)
    float Diameter, Thick, Shear;	// 管截面外直径、管壁厚度和剪切系数
public:
    DPipeSect( );
    ~DPipeSect( );
    DPipeSect( DPipeSect & Copy );
    DPipeSect & operator = ( const DPipeSect & Copy );
    // 通过名称确定是否相等
    int operator == ( const DPipeSect & Other );
    double GetSectArea( );
    // 设置截面标识名称
    void SetName( const char * nameStr );

    virtual void Serialize( bofstream & fout );
    virtual void Serialize( bifstream & fin );
};


DPlaneBase的实现

DPlaneBase::DPlaneBase()
{
    nID = 0;
    nLevel = 1;
    nLayer = 1;
    for( int i = 0; i < 9; i ++ )
        nNode[i] = 0;
    nMat = 0;
    H = 1.0f;
    T0 = 0.0f;
    nAct = 1;
}
DPlaneBase::DPlaneBase(const DPlaneBase & Copy)
{
    *this = Copy;
}
DPlaneBase::~DPlaneBase()
{
}
DPlaneBase & DPlaneBase::operator = (const DPlaneBase & Copy)
{
    if( this != &Copy ) {
        nID = Copy.nID;
        nLevel = Copy.nLevel;
        nLayer = Copy.nLayer;
        for( int i = 0; i < 9; i ++ )
            nNode[i] = Copy.nNode[i];
        nMat = Copy.nMat;
        H = Copy.H;
        T0 = Copy.T0;
        Load = Copy.Load;
        nAct = Copy.nAct;
    }
    return *this;
}
int DPlaneBase::operator ==( const DPlaneBase & Other)
{
    return GFunc::IsEqual( nNode, Other.nNode, 9 );
}
void DPlaneBase::SetQuadNodes(int nd [ 9 ])
{
    memcpy( nNode, nd, sizeof(nNode) );
}
void DPlaneBase::SetTriangleNodes(int nd [ 6 ])
{
    memcpy( nNode, nd, sizeof(int)*6 );
    nNode[6] = nNode[7] = nNode[8] = 0;
}
int DPlaneBase::IsTriangle()
{
    return (nNode[6]+nNode[7]+nNode[8]<1);
}
void DPlaneBase::GetVertex( int nd[4], int & ndNum )
{
    if( IsTriangle() ) {
        ndNum = 3;
        nd[0] = nNode[0];
        nd[1] = nNode[1];
        nd[2] = nNode[2];
    }
    else {
        ndNum = 4;
        nd[0] = nNode[0];
        nd[1] = nNode[2];
        nd[2] = nNode[8];
        nd[3] = nNode[6];
    }
}
void DPlaneBase::Serialize( bofstream & fout )
{
    fout << nID << nLevel << nLayer;
    fout.Write( nNode, sizeof(nNode) );
    fout << nMat << H << T0;
    Load.Serialize(fout);
    fout << nAct;
}
void DPlaneBase::Serialize( bifstream & fin )
{
    fin >> nID >> nLevel >> nLayer;
    fin.Read( nNode, sizeof(nNode) );
    fin >> nMat >> H >> T0;
    Load.Serialize( fin );
    if( nVersion > 100 ) fin >> nAct;
}


DPlaneBase的声明

class CLASS_DECLSPEC DPlaneBase {
public:
    int nID;		// 单元号，如果要用于array.h中的MArrayID类，其名称必须为nID
    short nLevel;   // 层标识号(指向DLevelBase的nID)，层号=nID-2
    short nLayer;	// (指向DLayerBase的nID)，与层号相互独立，缺省为1
    // 单元节点号，四边形单元的存储顺序为: 1,2,3为底边的三个节
    // 点,5为中心节点,4,6为两竖边的边中点,7,8,9为定边的三个节点
    // 三角形单元的存储顺序为:1,2,3为三角形三个顶点，4,5,6分别为
    // 三条边1-2,2-3,3-1的边中点
    int nNode[9];
    short nMat;		// 材料号, 该号指向材料类的DMaterial的nID数据成员
    float H;		// 仅仅对平面应力和膜单元有效
    float T0;		// 无应力状态参考温度（目前sap84不支持）
    // 对应于单元左、右、上、下的主节点号, 平面单元已经取消主从节点功能
    // int L[3],R[3],T[3],B[3];
    // Load[i].LocalID指向类DPlaneLoad数组的nID
    DElementLoad  Load;//
    用于描述各总体荷载种类下作用的跨内荷载 short nAct; // 施工模拟的步号(one-based)
public:
    DPlaneBase();
    DPlaneBase( const DPlaneBase & Copy );
    virtual ~DPlaneBase();
    DPlaneBase & operator = ( const DPlaneBase & Copy );
    // 只要四个角点一样即认为相等
    int operator == ( const DPlaneBase & Other );
    // index 从零开始
    int & operator [] ( int index ) {
        assert( index >=0 && index < 9 );
        return nNode[index];
    }
    // 设置四边形单元的节点
    void SetQuadNodes( int nd[9] );
    // 设置三角形单元的节点
    void SetTriangleNodes( int nd[6] );
    // 判断单元是否为三角形单元
    int IsTriangle();
    void GetVertex( int nd[4], int & ndNum ); // 返回单元的顶点号和顶点数

    virtual void Serialize( bofstream & fout );
    virtual void Serialize( bifstream & fin );
};


DPlaneLoad的实现

DPlaneLoad::DPlaneLoad()
{
    nID = 0;
    memset( S, 0, sizeof(S) );
    memset( nSide, 0, sizeof(nSide) );
    G = (float)0.0;
    memset( C, 0, sizeof(C) );
    memset( N, 0, sizeof(N) );
}
DPlaneLoad::DPlaneLoad( const DPlaneLoad & Copy )
{
    *this = Copy;
}
DPlaneLoad & DPlaneLoad::operator = ( const DPlaneLoad & Copy )
{
    if( this != &Copy ) {
        nID = Copy.nID;
        memcpy( S, Copy.S, sizeof(S) );
        memcpy( nSide, Copy.nSide, sizeof(nSide) );
        G = Copy.G;
        memcpy( C, Copy.C, sizeof(C) );
        memcpy( N, Copy.N, sizeof(N) );
    }
    return *this;
}
int DPlaneLoad::operator == ( const DPlaneLoad & Other )
{
    int i, k, haveWater = 0;
    double tmp;
    for( i = 0, k = 0; i < 4; i ++, k += 2 ) {
        if( nSide[i] != Other.nSide[i] ) return 0;
        if( nSide[i] ) haveWater = 1;
    }
    for( i = 0; i < 8; i ++ ) {
        tmp = S[i] - Other.S[i];
        if( tmp < -LoadError || tmp > LoadError ) return 0;
    }
    if( haveWater ) {
        tmp = G - Other.G;
        if( tmp < -LoadError || tmp > LoadError ) return 0;
        for( i = 0; i < 3; i ++ ) {
            tmp = C[i] - Other.C[i];
            if( tmp < -LoadError || tmp > LoadError ) return 0;
            tmp = N[i] - Other.N[i];
            if( tmp < -LoadError || tmp > LoadError ) return 0;
        }
    }
    return 1;
}

void DPlaneLoad::Serialize( bofstream & fout )
{
    fout << nID;
    fout.Write( S, sizeof(S) );
    fout.Write( nSide, sizeof(nSide) );
    fout << G;
    fout.Write( C, sizeof(C) );
    fout.Write( N, sizeof(N) );
}
void DPlaneLoad::Serialize( bifstream & fin )
{
    fin >> nID;
    fin.Read( S, sizeof(S) );
    fin.Read( nSide, sizeof(nSide) );
    fin >> G;
    fin.Read( C, sizeof(C) );
    fin.Read( N, sizeof(N) );
}


DPlaneLoad的声明

class CLASS_DECLSPEC DPlaneLoad {
public:
    int nID;				// 标识号
    float S[8];				// 线性分布荷载值，分别与1-4(三角形则1-3)号边对应的值(没有则置零)
    unsigned char nSide[4];	// 静水压作用的边号, nSide[i]不等于0表示i+1号边作用有静水压
    float G, C[3], N[3];	// 静水压力:水的比重、液面上一点及液面法向上的一点
public:
    DPlaneLoad();
    DPlaneLoad( const DPlaneLoad & Copy );
    DPlaneLoad & operator = ( const DPlaneLoad & Copy );
    int operator == ( const DPlaneLoad & Other );

    virtual void Serialize( bifstream & fin );
    virtual void Serialize( bofstream & fout );
};


DReinforce的实现

DReinforce::DReinforce()
{
    Initialize();
}
DReinforce::DReinforce( DReinforce & Copy )
{
    *this = Copy;
}
DReinforce & DReinforce::operator =(DReinforce & Copy)
{
    if( this != &Copy ) {
        nValid = Copy.nValid;
        Ft = Copy.Ft;
        Fy = Copy.Fy;
        Kb = Copy.Kb;
        Kc = Copy.Kc;
        Kbs = Copy.Kbs;
        Z = Copy.Z;
        P = Copy.P;
        bGR = Copy.bGR;
        cGR = Copy.cGR;
        bGN = Copy.bGN;
        cGN = Copy.cGN;
        Fyv = Copy.Fyv;
        Tkoci = Copy.Tkoci;
        T1 = Copy.T1;
    }
    return *this;
}
void DReinforce::Initialize()
{
    nValid = 1;
    Ft = Fy = (float)3.0E5;
    Kb = Kc = 0.544f;
    Kbs = 0.35f;
    Z = 0.004f;
    P= 0.8f;
    bGR = cGR = 0.008f;
    bGN = cGN = 2;
    Fyv = (float)2.1E5;
    Tkoci = 1.2f;
    T1 = 0.7f;
}
void DReinforce::Serialize(bofstream & fout)
{
    fout << nValid << Ft << Fy << Kb << Kc << Kbs << Z;
    fout << P << bGR << cGR << bGN << cGN << Fyv << Tkoci << T1;
}
void DReinforce::Serialize(bifstream & fin)
{
    fin >> nValid >> Ft >> Fy >> Kb >> Kc >> Kbs >> Z;
    fin >> P >> bGR >> cGR >> bGN >> cGN >> Fyv >> Tkoci >> T1;
}


DReinforce的声明

class CLASS_DECLSPEC DReinforce {
public:
// 配筋信息段REINFORCEMENT相关的数据
    unsigned char nValid;	// 结构计算过程中是否配筋(墙单元控制信息中也需要)[1]
                            // 数据的存取不受nValid影响
    float Ft,Fy;	// 钢筋的抗拉和抗压强度设计值[310000kN/m*m]
    float Kb,Kc,Kbs;// 梁柱的相对受压高度限值[0.544 0.544 0.35]
    float Z;		// 框架柱中全部纵筋的最小配筋率[0.4%]
    float P;		// 考虑地震作用组合时的框架柱的轴压比[0.8]
    float bGR, cGR; // 梁和柱的箍筋直径[0.008m, 0.008m]
    unsigned char bGN, cGN; // 梁和柱箍筋的肢数[2, 2]
    // 箍筋的设计强度、受扭构件纵向配筋与箍筋的配筋强度的比值[210000kN/m*m 1.2]
    float Fyv,Tkoci;
    float T1;		// 梁扭矩的折减系数[0.7]
public:
    DReinforce();
    DReinforce( DReinforce & Copy );
    DReinforce & operator = ( DReinforce & Copy );
    int IsValid() { return nValid!=0; }
    void Initialize();

    virtual void Serialize( bofstream & fout );
    virtual void Serialize( bifstream & fin );
};


DResult的公有成员函数

DResult的公有成员函数如下，其私有成员函数可参考“DResult私有成员函数”一节

DResult::DResult()
{
    SetZero();
}
DResult::DResult( const char *Name, int nodeNumConcerned )
{
    SetZero();
    SetFileName(Name,nodeNumConcerned);
}
DResult::~DResult()
{
}
DResult::operator void *() const
{
    if(!Good()) return 0;
    return (void *)this;
}
int DResult::GetOneCondDisp( int loadcondition, double disp[][6] )
{
    if( loadcondition<=0 || loadcondition>nLoad ) return 0;
    return GetAllNodeDisp( "NDIS", loadcondition, disp, 0, NULL );
}
int DResult::GetOneNodeAllCondDisp( int nNdID, double disp[][6] )
{
    return GetOneNodeDisp( "NDIS", nNdID, nLoad, disp, 0, NULL );
}
int DResult::GetOneCombDisp( int loadcombination, double disp[][6] )
{
    if( loadcombination<=0 || loadcombination>nDispComb ) return 0;
    return GetAllNodeDisp( "NDIS", loadcombination, disp, 1, NULL );
}
int DResult::GetOneNodeAllCombDisp( int nNdID, double disp[][6] )
{
    return GetOneNodeDisp( "NDIS", nNdID, nDispComb, disp, 1, NULL );
}

int DResult::GetEigenDisp( int EigenNo, double disp[][6], double & period )
{
    if( EigenNo<=0 || EigenNo>nEigen ) return 0;
    return GetAllNodeDisp( "NVEC", EigenNo, disp, 0, &period );
}
int DResult::GetEigenPeriod( double period[] )
{
    char Name[_MAX_PATH];
    int i, size;
    if( nEigen < 1 ) return 0;
    GetFileName( Name, "NVEC" );
    bifstream fin( Name );
    if( !fin ) return 0;
    size = 6*nNode*sizeof(double);
    for( i = 0; i < nEigen; i ++ ) {
        fin >> period[i];
        if( fin.Eof() ) return 0;
        fin.Seek( size, SEEK_CUR );
    }
    fin.Close();
    return 1;
}
int DResult::GetOneHistResDisp( int RespNo, double resdisp[][6], double & time )
{
    if( RespNo<=0 || RespNo>nResponse ) return 0;
    return GetAllNodeDisp( "NRES", RespNo, resdisp, 0, &time );
}
int DResult::GetOneNodeAllHistResDisp( int nNdID, double resdisp[][6], double time[] )
{
    return GetOneNodeDisp( "NRES", nNdID, nResponse, resdisp, 0, time );
}
int DResult::GetOneHistResVel( int RespNo, double resvel[][6], double & time )
{
    if( RespNo<=0 || RespNo>nResponse ) return 0;
    return GetAllNodeDisp( "NVEL", RespNo, resvel, 0, &time );
}
int DResult::GetOneNodeAllHistResVel( int nNdID, double resvel[][6], double time[] )
{
    return GetOneNodeDisp( "NVEL", nNdID, nResponse, resvel, 0, time );
}
int DResult::GetOneHistResAcc( int RespNo, double resacc[][6], double & time )
{
    if( RespNo<=0 || RespNo>nResponse ) return 0;
    return GetAllNodeDisp( "NACC", RespNo, resacc, 0, &time );
}
int DResult::GetOneNodeAllHistResAcc( int nNdID, double resacc[][6], double time[] )
{
    return GetOneNodeDisp( "NACC", nNdID, nResponse, resacc, 0, time );
}
int DResult::GetOneSpecDirDisp( int SpectrumNo, double disp[][6] )
{
    if( SpectrumNo<=0 || SpectrumNo>nSpectrum ) return 0;
    return GetAllNodeDisp( "NEQU", SpectrumNo, disp, 0, NULL );
}
int DResult::GetOneNodeAllSpecDirDisp( int nNdID, double disp[][6] )
{
    return GetOneNodeDisp( "NEQU", nNdID, nSpectrum, disp, 0, NULL );
}
int DResult::GetSpectrumCalData( int ModeNo[], double part[], double effect[] )
{
#ifndef v60
    bifstream fin;
    char Name[_MAX_PATH];
    GetFileName( Name, "CQC" );
    if( !fin.Open( Name ) ) return 0;
    fin.Seek( 20, SEEK_CUR );
    fin.Read( ModeNo, sizeof(int)*nSpecModeNum );
    fin.Seek( 8, SEEK_CUR );
    fin.Read( part, sizeof(double)*nSpecModeNum*nSpectrum );
    fin.Seek( 8, SEEK_CUR );
    fin.Read( effect, sizeof(double)*nSpecModeNum*nSpectrum );
    return !fin.Eof();
#else
    return 0;
#endif
}
int DResult::GetSpecMassPartRatio( MArray<DSpectrumDir>& dir, int mode[], double ratio[] )
{
    if( dir.Entries() != nSpectrum || nSpectrum<1 ) return 0;
    double (*mass)[6], (*dirm)[6], mtotal, m;
    float Dir[3];
    int i, j, ret=1;
    mass = new double[nNode][6];
    dirm = new double[nEigen][6];
    try {
        FILE *fp;
        char Name[_MAX_PATH];
        if( !GetAllNodeMass( mass ) ) throw 1;
        mtotal = 0.0;
        for( i = 0; i < nNode; i ++ ) {
            mtotal += mass[i][2];
        }
        if( mtotal < 1.0E-8 ) throw 1;
        GetFileName(Name, "DIR");
        if( !(fp=fopen(Name,"rb")) ) throw 1;
        fseek( fp, 24, SEEK_CUR );
        fread( dirm, sizeof(double), nEigen*6, fp );
        // dirm[n-1]:存储了φT*Mx*φ  φT*My*φ  φT*Mz*φ φT*Mx  φT*My  φT*Mz
        // 后面三个数是乘积之后的向量的所有元素之和
        fclose(fp);
        for( i = 0; i < nSpectrum; i ++ ) {
            memcpy( Dir, dir[i].Dir, sizeof(Dir) );
            CVector::Normalize(Dir);
            for( j = 0; j < nSpecModeNum; j ++ ) {
                m = dirm[mode[j]-1][3]*Dir[0] + dirm[mode[j]-1][4]*Dir[1] +dirm[mode[j]-1][5]*Dir[2];
                ratio[i*nSpecModeNum+j] = m*m/mtotal;
            }
        }
    }
    catch( int ) {
        ret = 0;
    }
    delete[] mass;
    delete[] dirm;
    return ret;
}
int DResult::GetOneBuckleDisp( int BuckleNo, double disp[][6], double & lfactor )
{
    if( BuckleNo<=0 || BuckleNo>nBuckle ) return 0;
    return GetAllNodeDisp( "NSTA", BuckleNo, disp, 0, &lfactor );
}
int DResult::GetBuckleFactor( double factor[] )
{
    char Name[_MAX_PATH];
    int i, size;
    if( nBuckle < 1 ) return 0;
    GetFileName( Name, "NSTA" );
    bifstream fin( Name );
    if( !fin ) return 0;
    size = 6*nNode*sizeof(double);
    for( i = 0; i < nBuckle; i ++ ) {
        fin >> factor[i];
        if( fin.Eof() ) return 0;
        fin.Seek( size, SEEK_CUR );
    }
    fin.Close();
    return 1;
}
int DResult::GetOneConstrDisp( int actConstr, double disp[][6] )
{
    if( actConstr<=0 || actConstr>nActNum ) return 0;
    return GetAllNodeDisp( "NACD", actConstr, disp, 0, NULL );
}
int DResult::GetOneNodeAllConstrDisp( int nNdID, double disp[][6] )
{
    return GetOneNodeDisp( "NACD", nNdID, nActNum, disp, 0, NULL );
}

int DResult::GetOneFrameAllCombForce( int FrameNo, MArrayID<DFrameForce> & FrameForce )
{
    return GetOneFrameOrSframeAllCombForce( 0, FrameNo, FrameForce );
}
int DResult::GetOneCombAllFrameForce( int Comb, MArrayID<DFrameForce> & FrameForce )
{
    return GetOneCombAllFrameOrSframeForce( 0, Comb, FrameForce );
}
int DResult::RecycleGetOneFrameForce( bifstream & fin, int & eleID, MArrayID<DFrameForce> & vForce )
{
    return RecycleGetOneSframeOrFrameForce( 0, fin, eleID, vForce );
}
int DResult::GetOneFrameReinData( int FrameNo, DFrameRein & reinForce )
{
    return GetOneOrAllFrameReinData( NULL, FrameNo, &reinForce );
}
int DResult::GetAllFrameReinData( MArrayID<DFrameRein> & reinForce )
{
    return GetOneOrAllFrameReinData( &reinForce, 0, NULL );
}
int DResult::GetOneSframeAllCombForce( int FrameNo, MArrayID<DFrameForce> & SframeForce )
{
    return GetOneFrameOrSframeAllCombForce( 1, FrameNo, SframeForce );
}
int DResult::GetOneCombAllSframeForce( int Comb, MArrayID<DFrameForce> & SframeForce )
{
    return GetOneCombAllFrameOrSframeForce( 1, Comb, SframeForce );
}
int DResult::RecycleGetOneSframeForce( bifstream & fin, int & eleID, MArrayID<DFrameForce> & vForce )
{
    return RecycleGetOneSframeOrFrameForce( 1, fin, eleID, vForce );
}
int DResult::GetOneSframeAllCombCheck( int SframeNo, MArrayID<DSframeCheck> & CheckResult )
{
    char Name[_MAX_PATH];
    int i, n, ele, SectNum, dir;
    double F[20][SFRCHKNUM];
    DSframeCheck Check;
    bifstream fin;

    CheckResult.Clear();
    GetFileName( Name, "F88" );
    if( !fin.Open( Name ) ) return 0;
    fin.Seek( 16, SEEK_SET );
    while(1) {
        fin.Seek( 4, SEEK_CUR );
        fin >> ele >> SectNum;
        if( fin.Eof() || !fin.IsGood() ) return 0;
        if( ele != SframeNo )
        fin.Seek( 8*SectNum+4+nLoadComb*SectNum*164, SEEK_CUR );
        else {
            assert( SectNum<=20 );
            for( n = 0; n < SectNum; n ++ )
                fin >> F[n][0];
            fin.Seek( 4, SEEK_CUR );
            for( n = 0; n < nLoadComb; n ++ ) {
                Check.nID = n+1;
                for( i = 0; i < SectNum; i ++ ) {
                    fin.Seek( 4, SEEK_CUR );
                    fin.Read( &F[i][1], 144 );
                    fin >> dir;
                    F[i][SFRCHKNUM-2] = dir;
                    fin >> F[i][SFRCHKNUM-1];
                    fin.Seek( 4, SEEK_CUR );
                }
                Check.SetSectCheck( SectNum, F );
                CheckResult.Insert( Check );
            }
            break;
        }
    }
    fin.Close();
    return 1;
}
int DResult::GetOneCombAllSframeCheck( int Comb, MArrayID<DSframeCheck> & CheckResult )
{
    char Name[_MAX_PATH];
    bifstream fin;
    DSframeCheck Check;
    int SectNum, i, dir;
    double F[20][SFRCHKNUM];

    CheckResult.Clear();
    if( Comb<1 || Comb>nLoadComb ) return 0;
    GetFileName( Name, "F88" );
    if( !fin.Open( Name ) ) return 0;
    fin.Seek( 16, SEEK_SET );
    while(1) {
        fin.Seek( 4, SEEK_CUR );
        fin >> Check.nID >> SectNum;
        if( fin.Eof() || !fin.IsGood() ) break;
        for( i = 0; i < SectNum; i ++ )
            fin >> F[i][0];
        fin.Seek( 4, SEEK_CUR );
        fin.Seek( (Comb-1)*SectNum*164, SEEK_CUR );
        assert( SectNum <= 20 );
        for( i = 0; i < SectNum; i ++ ) {
            fin.Seek( 4, SEEK_CUR );
            fin.Read( &F[i][1], 144 );
            fin >> dir;
            F[i][SFRCHKNUM-2] = dir;
            fin >> F[i][SFRCHKNUM-1];
            fin.Seek( 4, SEEK_CUR );
        }
        fin.Seek( (nLoadComb-Comb)*SectNum*164, SEEK_CUR );
        Check.SetSectCheck( SectNum, F );
        CheckResult.Insert( Check );
    }
    fin.Close();
    return 1;
}
int DResult::RecycleGetOneSframeCheck( bifstream & fin, int & eleID, MArrayID<DSframeCheck> & vCheck )
{
    int n, SectNum, dir;
    double F[20][SFRCHKNUM];
    DSframeCheck Check;

    vCheck.Clear();
    if( !fin.IsOpen() ) {
        char Name[_MAX_PATH];
        GetFileName( Name, "F88" );
        if( !fin.Open( Name ) ) return 0;
        fin.Seek( 16, SEEK_SET );
    }
    fin.Seek( 4, SEEK_CUR );
    fin >> eleID;
    fin >> SectNum;
    if( fin.Eof() || !fin.IsGood() ) {
        fin.Close();	// 校核结果循环读取结束，必须关闭文件
        return 0;
    }
    assert( SectNum<=20 );
    for( n = 0; n < SectNum; n ++ )
        fin >> F[n][0];
    fin.Seek( 4, SEEK_CUR );
    for( n = 0; n < nLoadComb; n ++ ) {
        Check.nID = n+1;
        for( int i = 0; i < SectNum; i ++ ) {
            fin.Seek( 4, SEEK_CUR );
            fin.Read( &F[i][1], (SFRCHKNUM-3)*sizeof(double) );
            fin >> dir;
            F[i][SFRCHKNUM-2] = dir;
            fin >> F[i][SFRCHKNUM-1];
            fin.Seek( 4, SEEK_CUR );
        }
        Check.SetSectCheck( SectNum, F );
        vCheck.Insert( Check );
    }
    return 1;
}

int DResult::GetOneTrussAllCombForce( int TrussNo, MArrayID<DTrussForce> & TrussForce )
{
    char Name[_MAX_PATH];
    bifstream fin;
    DTrussForce Force;
    int Element;

    TrussForce.Clear();
    GetFileName( Name, "U8" );
    if( !fin.Open( Name ) ) return 0;
    fin.Seek( 16, SEEK_SET );
    while(1) {
        fin.Seek( 4, SEEK_CUR );
        fin >> Element;
        if( fin.Eof() || !fin.IsGood() ) return 0;
        fin.Seek( 4, SEEK_CUR );
        if( Element != TrussNo ) fin.Seek( 16*nLoadComb, SEEK_CUR );
        else {
            for( int i = 0; i < nLoadComb; i ++ ) {
                Force.nID = i+1;
                fin.Seek( 4, SEEK_CUR );
                fin >> Force.Axis;
                fin.Seek( 4, SEEK_CUR );
                TrussForce.Insert( Force );
            }
            break;
        }
    }
    fin.Close();
    return 1;
}
int DResult::GetOneCombAllTrussForce( int Comb, MArrayID<DTrussForce> & TrussForce )
{
    char Name[_MAX_PATH];
    bifstream fin;
    DTrussForce Force;

    TrussForce.Clear();
    if( Comb<=0 || Comb>nLoadComb ) return 0;
    GetFileName( Name, "U8" );
    if( !fin.Open( Name ) ) return 0;

    fin.Seek( 16, SEEK_SET );
    while(1) {
        fin.Seek( 4, SEEK_CUR );
        fin >> Force.nID;
        if( fin.Eof() || !fin.IsGood() ) break;
        fin.Seek( 4, SEEK_CUR );
        fin.Seek( 16*(Comb-1), SEEK_CUR );
        fin.Seek( 4, SEEK_CUR );
        fin >> Force.Axis;
        fin.Seek( 4, SEEK_CUR );
        fin.Seek( 16*(nLoadComb-Comb), SEEK_CUR );
        TrussForce.Insert( Force );
    }
    fin.Close();
    return 1;
}
int DResult::RecycleGetOneTrussForce( bifstream & fin, int & eleID,
                                     MArrayID<DTrussForce> & vForce )
{
    int n;
    DTrussForce Force;

    vForce.Clear();
    if( !fin.IsOpen() ) {
        char Name[_MAX_PATH];
        GetFileName( Name, "U8" );
        if( !fin.Open( Name ) ) return 0;
        fin.Seek( 16, SEEK_SET );
    }
    fin.Seek( 4, SEEK_CUR );
    fin >> eleID;
    if( fin.Eof() || !fin.IsGood() ) {
        fin.Close();	// 内力循环读取结束，必须关闭文件
        return 0;
    }
    fin.Seek( 4, SEEK_CUR );
    for( n = 0; n < nLoadComb; n ++ ) {
        Force.nID = n+1;
        fin.Seek( 4, SEEK_CUR );
        fin >> Force.Axis;
        fin.Seek( 4, SEEK_CUR );
        vForce.Insert( Force );
    }
    return 1;
}
int DResult::GetOneCframeAllCombForce( int CframeNo, MArrayID<DCframeForce> & CframeForce )
{
    char Name[_MAX_PATH];
    bifstream fin;
    DCframeForce Force;
    int Element;

    CframeForce.Clear();
    GetFileName( Name, "U6" );
    if( !fin.Open( Name ) ) return 0;
    fin.Seek( 16, SEEK_SET );
    while(1) {
        fin.Seek( sizeof(int), SEEK_CUR );
        fin >> Element;
        if( fin.Eof() || !fin.IsGood() ) return 0;
        fin.Seek( sizeof(int), SEEK_CUR );
        if( Element != CframeNo ) fin.Seek( 104*nLoadComb, SEEK_CUR );
        else {
            for( int i = 0; i < nLoadComb; i ++ ) {
                Force.nID = i+1;
                fin.Seek( sizeof(int), SEEK_CUR );
                fin.Read( Force.FI, sizeof(double)*6 );
                fin.Read( Force.FJ, sizeof(double)*6 );
                fin.Seek( sizeof(int), SEEK_CUR );
                CframeForce.Insert( Force );
            }
            break;
        }
    }
    fin.Close();
    return 1;
}
int DResult::GetOneCombAllCframeForce( int Comb, MArrayID<DCframeForce> & CframeForce )
{
    char Name[_MAX_PATH];
    bifstream fin;
    DCframeForce Force;

    CframeForce.Clear();
    if( Comb<=0 || Comb>nLoadComb ) return 0;
    GetFileName( Name, "U6" );
    if( !fin.Open( Name ) ) return 0;
    fin.Seek( 16, SEEK_SET );
    while(1) {
        fin.Seek( sizeof(int), SEEK_CUR );
        fin >> Force.nID;
        if( fin.Eof() || !fin.IsGood() ) break;
        fin.Seek( sizeof(int), SEEK_CUR );
        fin.Seek( 104*(Comb-1), SEEK_CUR );
        fin.Seek( sizeof(int), SEEK_CUR );
        fin.Read( Force.FI, sizeof(double)*6 );
        fin.Read( Force.FJ, sizeof(double)*6 );
        fin.Seek( sizeof(int), SEEK_CUR );
        fin.Seek( 104*(nLoadComb-Comb), SEEK_CUR );
        CframeForce.Insert( Force );
    }
    fin.Close();
    return 1;
}
int DResult::RecycleGetOneCframeForce( bifstream & fin, int & eleID, MArrayID<DCframeForce> & vForce )
{
    int n;
    DCframeForce Force;

    vForce.Clear();
    if( !fin.IsOpen() ) {
        char Name[_MAX_PATH];
        GetFileName( Name, "U6" );
        if( !fin.Open( Name ) ) return 0;
        fin.Seek( 16, SEEK_SET );
    }
    fin.Seek( 4, SEEK_CUR );
    fin >> eleID;
    if( fin.Eof() || !fin.IsGood() ) {
        fin.Close();	// 内力循环读取结束，必须关闭文件
        return 0;
    }
    fin.Seek( 4, SEEK_CUR );
    for( n = 0; n < nLoadComb; n ++ ) {
        Force.nID = n+1;
        fin.Seek( 4, SEEK_CUR );
        fin.Read( Force.FI, sizeof(double)*6 );
        fin.Read( Force.FJ, sizeof(double)*6 );
        fin.Seek( 4, SEEK_CUR );
        vForce.Insert( Force );
    }
    return 1;
}

int DResult::GetOneVframeAllCombForce( int VframeNo, MArrayID<DVframeForce> & VframeForce )
{
    char Name[_MAX_PATH];
    bifstream fin;
    DVframeForce Force;
    int Element, SectNum, i, n;
    double F[20][7];

    VframeForce.Clear();
    GetFileName( Name, "U7" );
    if( !fin.Open( Name ) ) return 0;
    fin.Seek( 16, SEEK_SET );
    while(1) {
        fin.Seek( 4, SEEK_CUR );
        fin >> Element >> n >> SectNum;
        assert( SectNum <= 20 );
        for( i = 0; i < SectNum; i ++ )
            fin >> F[i][0];
        if( fin.Eof() || !fin.IsGood() ) return 0;
        fin.Seek( 4, SEEK_CUR );
        if( Element != VframeNo ) fin.Seek( nLoadComb*SectNum*56, SEEK_CUR );
        else {
            for( n = 0; n < nLoadComb; n ++ ) {
                Force.nID = n+1;
                for( i = 0; i < SectNum; i ++ ) {
                    fin.Seek( sizeof(int), SEEK_CUR );
                    fin.Read( &F[i][1], 6*sizeof(double) );
                    fin.Seek( sizeof(int), SEEK_CUR );
                }
                Force.SetSectForce( SectNum, F );
                VframeForce.Insert( Force );
            }
            break;
        }
    }
    fin.Close();
    return 1;
}
int DResult::GetOneCombAllVframeForce( int Comb, MArrayID<DVframeForce> & VframeForce )
{
    char Name[_MAX_PATH];
    bifstream fin;
    DVframeForce Force;
    int SectNum, i;
    double F[20][7];

    VframeForce.Clear();
    if( Comb<=0 || Comb>nLoadComb ) return 0;
    GetFileName( Name, "U7" );
    if( !fin.Open( Name ) ) return 0;
    fin.Seek( 16, SEEK_SET );
    while(1) {
        fin.Seek( 4, SEEK_CUR );
        fin >> Force.nID >> i >> SectNum;
        assert( SectNum <= 20 );
        for( i = 0; i < SectNum; i ++ )
            fin >> F[i][0];
        if( fin.Eof() || !fin.IsGood() ) break;
        fin.Seek( 4, SEEK_CUR );
        fin.Seek( (Comb-1)*SectNum*56, SEEK_CUR );
        assert( SectNum<=20 );
        for( i = 0; i < SectNum; i ++ ) {
            fin.Seek( sizeof(int), SEEK_CUR );
            fin.Read( &F[i][1], 6*sizeof(double) );
            fin.Seek( sizeof(int), SEEK_CUR );
        }
        fin.Seek( (nLoadComb-Comb)*SectNum*56, SEEK_CUR );
        Force.SetSectForce( SectNum, F );
        VframeForce.Insert( Force );
    }
    fin.Close();
    return 1;
}
int DResult::RecycleGetOneVframeForce( bifstream & fin, int & eleID,
                                     MArrayID<DVframeForce> & vForce )
{
    int n, SectNum;
    double F[20][7];
    DVframeForce Force;

    vForce.Clear();
    if( !fin.IsOpen() ) {
        char Name[_MAX_PATH];
        GetFileName( Name, "U7" );
        if( !fin.Open( Name ) ) return 0;
        fin.Seek( 16, SEEK_SET );
    }
    fin.Seek( 4, SEEK_CUR );
    fin >> eleID;
    fin.Seek( 4, SEEK_CUR );	// 跳过单元类型
    fin >> SectNum;
    if( fin.Eof() || !fin.IsGood() ) {
        fin.Close();	// 内力循环读取结束，必须关闭文件
        return 0;
    }
    assert( SectNum<=20 );
    for( n = 0; n < SectNum; n ++ )
        fin >> F[n][0];
    fin.Seek( 4, SEEK_CUR );
    for( n = 0; n < nLoadComb; n ++ ) {
        Force.nID = n+1;
        for( int i = 0; i < SectNum; i ++ ) {
            fin.Seek( 4, SEEK_CUR );
            fin.Read( &F[i][1], 6*sizeof(double) );
            fin.Seek( 4, SEEK_CUR );
        }
        Force.SetSectForce( SectNum, F );
        vForce.Insert( Force );
    }
    return 1;
}

int DResult::GetOnePipeAllCombForce( int PipeNo, MArrayID<DPipeForce> & PipeForce )
{
    char Name[_MAX_PATH];
    bifstream fin;
    DPipeForce Force;
    int Element, ItemNum;

    PipeForce.Clear();
    GetFileName( Name, "U10" );
    if( !fin.Open( Name ) ) return 0;
    fin.Seek( 16, SEEK_SET );
    while(1) {
        fin.Seek( sizeof(int), SEEK_CUR );
        fin >> Element >> ItemNum;
        if( fin.Eof() || !fin.IsGood() ) return 0;
        fin.Seek( sizeof(int), SEEK_CUR );
        if( Element != PipeNo ) fin.Seek( (sizeof(double)*ItemNum+8)*nLoadComb, SEEK_CUR );
        else {
            for( int i = 0; i < nLoadComb; i ++ ) {
                Force.nID = i+1;
                fin.Seek( sizeof(int), SEEK_CUR );
                fin.Read( Force.FI, sizeof(double)*6 );
                if( ItemNum > 12 ) {
                    fin.Read( Force.FMid, sizeof(double)*6 );
                    Force.HaveMid = 1;
                }
                else Force.HaveMid = 0;
                fin.Read( Force.FJ, sizeof(double)*6 );
                fin.Seek( sizeof(int), SEEK_CUR );
                PipeForce.Insert( Force );
            }
            break;
        }
    }
    fin.Close();
    return 1;
}
int DResult::GetOneCombAllPipeForce( int Comb, MArrayID<DPipeForce> & PipeForce )
{
    char Name[_MAX_PATH];
    bifstream fin;
    DPipeForce Force;
    int ItemNum;

    PipeForce.Clear();
    if( Comb<=0 || Comb>nLoadComb ) return 0;
    GetFileName( Name, "U10" );
    if( !fin.Open( Name ) ) return 0;
    fin.Seek( 16, SEEK_SET );
    while(1) {
        fin.Seek( sizeof(int), SEEK_CUR );
        fin >> Force.nID >> ItemNum;
        if( fin.Eof() || !fin.IsGood() ) break;
        fin.Seek( sizeof(int), SEEK_CUR );
        fin.Seek( (sizeof(double)*ItemNum+8)*(Comb-1), SEEK_CUR );
        fin.Seek( sizeof(int), SEEK_CUR );
        fin.Read( Force.FI, sizeof(double)*6 );
        if( ItemNum > 12 ) {
            fin.Read( Force.FMid, sizeof(double)*6 );
            Force.HaveMid = 1;
        }
        else Force.HaveMid = 0;
        fin.Read( Force.FJ, sizeof(double)*6 );
        fin.Seek( sizeof(int), SEEK_CUR );
        fin.Seek( (sizeof(double)*ItemNum+8)*(nLoadComb-Comb), SEEK_CUR );
        PipeForce.Insert( Force );
    }
    fin.Close();
    return 1;
}
int DResult::RecycleGetOnePipeForce( bifstream & fin, int & eleID, MArrayID<DPipeForce> & vForce )
{
    int n, ItemNum;
    DPipeForce Force;

    vForce.Clear();
    if( !fin.IsOpen() ) {
        char Name[_MAX_PATH];
        GetFileName( Name, "U10" );
        if( !fin.Open( Name ) ) return 0;
        fin.Seek( 16, SEEK_SET );
    }
    fin.Seek( 4, SEEK_CUR );
    fin >> eleID >> ItemNum;
    if( fin.Eof() || !fin.IsGood() ) {
        fin.Close();	// 内力循环读取结束，必须关闭文件
        return 0;
    }
    fin.Seek( 4, SEEK_CUR );
    for( n = 0; n < nLoadComb; n ++ ) {
        Force.nID = n+1;
        fin.Seek( 4, SEEK_CUR );
        fin.Read( Force.FI, sizeof(double)*6 );
        if( ItemNum > 12 ) {
            fin.Read( Force.FMid, sizeof(double)*6 );
            Force.HaveMid = 1;
        }
        else Force.HaveMid = 0;
        fin.Read( Force.FJ, sizeof(double)*6 );
        fin.Seek( 4, SEEK_CUR );
        vForce.Insert( Force );
    }
    return 1;
}

int DResult::GetOneSpringAllCombForce( int SpringNo, MArrayID<DSpringForce> & SpringForce )
{
    char Name[_MAX_PATH];
    bifstream fin;
    DSpringForce Force;
    int Element;

    SpringForce.Clear();
    GetFileName( Name, "U31" );
    if( !fin.Open( Name ) ) return 0;
    fin.Seek( 16, SEEK_SET );
    while(1) {
        fin.Seek( sizeof(int), SEEK_CUR );
        fin >> Element;
        if( fin.Eof() || !fin.IsGood() ) return 0;
        fin.Seek( sizeof(int)*3, SEEK_CUR );
        if( Element != SpringNo ) fin.Seek( 16*nLoadComb, SEEK_CUR );
        else {
            for( int i = 0; i < nLoadComb; i ++ ) {
                Force.nID = i+1;
                fin.Seek( sizeof(int), SEEK_CUR );
                fin >> Force.springForce;
                fin.Seek( sizeof(int), SEEK_CUR );
                SpringForce.Insert( Force );
            }
            break;
        }
    }
    fin.Close();
    return 1;
}
int DResult::GetOneCombAllSpringForce( int Comb, MArrayID<DSpringForce> & SpringForce )
{
    char Name[_MAX_PATH];
    bifstream fin;
    DSpringForce Force;

    SpringForce.Clear();
    if( Comb<=0 || Comb>nLoadComb ) return 0;
    GetFileName( Name, "U31" );
    if( !fin.Open( Name ) ) return 0;

    fin.Seek( 16, SEEK_SET );
    while(1) {
        fin.Seek( sizeof(int), SEEK_CUR );
        fin >> Force.nID;
        if( fin.Eof() || !fin.IsGood() ) break;
        fin.Seek( sizeof(int)*3, SEEK_CUR );
        fin.Seek( 16*(Comb-1), SEEK_CUR );
        fin.Seek( sizeof(int), SEEK_CUR );
        fin >> Force.springForce;
        fin.Seek( sizeof(int), SEEK_CUR );
        fin.Seek( 16*(nLoadComb-Comb), SEEK_CUR );
        SpringForce.Insert( Force );
    }
    fin.Close();
    return 1;
}
int DResult::RecycleGetOneSpringForce( bifstream & fin, int & eleID,
                                     MArrayID<DSpringForce> & vForce )
{
    int n;
    DSpringForce Force;

    vForce.Clear();
    if( !fin.IsOpen() ) {
        char Name[_MAX_PATH];
        GetFileName( Name, "U31" );
        if( !fin.Open( Name ) ) return 0;
        fin.Seek( 16, SEEK_SET );
    }
    fin.Seek( 4, SEEK_CUR );
    fin >> eleID;
    if( fin.Eof() || !fin.IsGood() ) {
        fin.Close();	// 内力循环读取结束，必须关闭文件
        return 0;
    }
    fin.Seek( 12, SEEK_CUR );
    for( n = 0; n < nLoadComb; n ++ ) {
        Force.nID = n+1;
        fin.Seek( 4, SEEK_CUR );
        fin >> Force.springForce;
        fin.Seek( 4, SEEK_CUR );
        vForce.Insert( Force );
    }
    return 1;
}

int DResult::GetOneCombPlaneStress( int CombNo, double stress[][9] )
{
    return GetAllNodeStress( "A2", CombNo, stress );
}
int DResult::GetOneNodeAllCombPlaneStress( int ndNo, double stress[][9] )
{
    return GetOneNodeStress( "A2", ndNo, stress );
}
int DResult::GetSomeNodePlaneStress( int ndNum, int nd[21], double stress[][21][9] )
{
    return GetSomeNodeStress( "A2", ndNum, nd, stress );
}
/*
int DResult::GetOneCombThreedStress( int CombNo, double stress[][9] )
{
    return GetAllNodeStress( "A12", CombNo, stress );
}
int DResult::GetOneNodeAllCombThreedStress( int ndNo, double stress[][9] )
{
    return GetOneNodeStress( "A12", ndNo, stress );
}
*/
int DResult::GetOneCombSol21Stress( int CombNo, double stress[][9] )
{
    return GetAllNodeStress( "A11", CombNo, stress );
}
int DResult::GetOneNodeAllCombSol21Stress( int ndNo, double stress[][9] )
{
    return GetOneNodeStress( "A11", ndNo, stress );
}
int DResult::GetSomeNodeSol21Stress( int ndNum, int nd[21], double stress[][21][9] )
{
    return GetSomeNodeStress( "A11", ndNum, nd, stress );
}
int DResult::GetOneCombS16Stress( int CombNo, double stress[][9] )
{
    return GetAllNodeStress( "A18", CombNo, stress );
}
int DResult::GetOneNodeAllCombS16Stress( int ndNo, double stress[][9] )
{
    return GetOneNodeStress( "A18", ndNo, stress );
}
int DResult::GetSomeNodeS16Stress( int ndNum, int nd[21], double stress[][21][9] )
{
    return GetSomeNodeStress( "A18", ndNum, nd, stress );
}
int DResult::GetOneCombSol8rStress( int CombNo, double stress[][9] )
{
    return GetAllNodeStress( "A17", CombNo, stress );
}
int DResult::GetOneNodeAllCombSol8rStress( int ndNo, double stress[][9] )
{
    return GetOneNodeStress( "A17", ndNo, stress );
}
int DResult::GetSomeNodeSol8rStress( int ndNum, int nd[21], double stress[][21][9] )
{
    return GetSomeNodeStress( "A17", ndNum, nd, stress );
}
int DResult::GetOneCombShellStress( int CombNo, double stress[][9] )
{
    return GetAllNodeStress( "A14", CombNo, stress );
}
int DResult::GetOneNodeAllCombShellStress( int ndNo, double stress[][9] )
{
    return GetOneNodeStress( "A14", ndNo, stress );
}
int DResult::GetOneShellAllCombForce( int ShellNo, MArrayID<DShellForce> & ShellForce )
{
    char Name[_MAX_PATH];
    int eleNum, no, nodeNum, i, n, j;
    double F[10][8];
    bifstream fin;
    DShellForce Force;

    ShellForce.Clear();
    GetFileName( Name, "A41" );
    if( !fin.Open( Name ) ) return 0;
    fin.Seek( 4, SEEK_SET );
    fin >> eleNum;
    fin.Seek( 8, SEEK_CUR );
    for( n = 1; n <= nLoadComb; n ++ ) {
        Force.nID = n;
        for( j = 0; j < eleNum; j ++ ) {
            fin.Seek( sizeof(int), SEEK_CUR );
            fin >> no >> nodeNum;
            fin.Seek( sizeof(int), SEEK_CUR );
            if( fin.Eof() || !fin.IsGood() ) {
                ShellForce.Clear();		// 格式有错误
                return 0;
            }
            if( no != ShellNo ) fin.Seek( nodeNum*72, SEEK_CUR );
            else {
                for( i = 0; i < nodeNum; i ++ ) {
                    fin.Seek( sizeof(int), SEEK_CUR );
                    fin.Read( F[i], 8*sizeof(double) );
                    fin.Seek( sizeof(int), SEEK_CUR );
                }
                Force.SetNodeForce( nodeNum, F );
                ShellForce.Insert( Force );
            }
        }
        if( ShellForce.Entries() != n ) {
            ShellForce.Clear();	// 在当前循环的组合下没有找到此单元
            return 0;
        }
    }
    fin.Close();
    return 1;
}
int DResult::GetOneShellAllCombForceNoAve( int ShellNo, MArrayID<DShellForce> & ShellForce )
{
    char Name[_MAX_PATH];
    int no, nodeNum, i, n, Pos;
    double F[10][8];
    bifstream fin;
    DShellForce Force;

    ShellForce.Clear();
    GetFileName( Name, "NU41" );	// 读取U41的索引文件
    if( !fin.Open( Name ) ) return 0;
    fin >> n;
    if( ShellNo<1 || ShellNo>n ) return 0;
    fin.Seek( (ShellNo-1)*sizeof(int), SEEK_SET );
    Pos = -1;
    fin >> Pos;
    fin.Close();
    if( Pos < 0 ) return 0;		// 不存在单元号为ShellNo的板壳单元

    GetFileName( Name, "U41" );
    if( !fin.Open( Name ) ) return 0;
    fin.Seek( Pos, SEEK_SET );
    fin.Seek( sizeof(int), SEEK_CUR );
    fin >> no >> nodeNum;
    fin.Seek( sizeof(int), SEEK_CUR );
    for( n = 1; n <= nLoadComb; n ++ ) {
        Force.nID = n;
        for( i = 0; i < nodeNum; i ++ ) {
            fin.Seek( sizeof(int), SEEK_CUR );
            fin.Read( F[i], 8*sizeof(double) );
            if( fin.Eof() || !fin.IsGood() ) {
                ShellForce.Clear();		// 格式有错误
                return 0;
            }
            fin.Seek( sizeof(int), SEEK_CUR );
        }
        Force.SetNodeForce( nodeNum, F );
        ShellForce.Insert( Force );
    }
    fin.Close();
    return 1;
}
int DResult::GetOneCombAllShellForce( int Comb, MArrayID<DShellForce> & ShellForce )
{
    char Name[_MAX_PATH];
    int Pos, i, j, eleNum, nodeNum;
    double F[9][8];
    DShellForce Force;
    bifstream fin;

    ShellForce.Clear();
    if( Comb<=0 || Comb>nLoadComb ) return 0;
    GetFileName( Name, "NA41" );	// 读取A41的索引文件
    if( !fin.Open( Name ) ) return 0;
    fin.Seek( Comb*sizeof(int), SEEK_SET );
    Pos = -1;
    fin >> Pos;
    fin.Close();
    if( Pos < 0 ) return 0;		// 不存在单元号为ShellNo的板壳单元

    GetFileName( Name, "A41" );
    if( !fin.Open( Name ) ) return 0;
    fin.Seek( 4, SEEK_SET );
    fin >> eleNum;
    fin.Seek( Pos, SEEK_SET );
    for( j = 0; j < eleNum; j ++ ) {
        fin.Seek( sizeof(int), SEEK_CUR );
        fin >> Force.nID >> nodeNum;
        if( fin.Eof() || !fin.IsGood() ) {
            ShellForce.Clear();		// 格式有错误
            return 0;
        }
        fin.Seek( sizeof(int), SEEK_CUR );
        for( i = 0; i < nodeNum; i ++ ) {
            fin.Seek( sizeof(int), SEEK_CUR );
            fin.Read( F[i], 8*sizeof(double) );
            fin.Seek( sizeof(int), SEEK_CUR );
        }
        Force.SetNodeForce( nodeNum, F );
        ShellForce.Insert( Force );
    }
    fin.Close();
    return 1;
}
int DResult::GetOneCombAllShellForceNoAve( int Comb, MArrayID<DShellForce> & ShellForce )
{
    char Name[_MAX_PATH];
    int i, j, eleNum, nodeNum;
    double F[9][8];
    DShellForce Force;
    bifstream fin;

    ShellForce.Clear();
    if( Comb<=0 || Comb>nLoadComb ) return 0;

    GetFileName( Name, "U41" );
    if( !fin.Open( Name ) ) return 0;
    fin.Seek( 4, SEEK_SET );
    fin >> eleNum;
    fin.Seek( 8, SEEK_CUR );
    for( j = 0; j < eleNum; j ++ ) {
        fin.Seek( sizeof(int), SEEK_CUR );
        fin >> Force.nID >> nodeNum;
        if( fin.Eof() || !fin.IsGood() ) {
            ShellForce.Clear();		// 格式有错误
            return 0;
        }
        fin.Seek( sizeof(int)+(Comb-1)*nodeNum*72, SEEK_CUR );
        for( i = 0; i < nodeNum; i ++ ) {
            fin.Seek( sizeof(int), SEEK_CUR );
            fin.Read( F[i], 8*sizeof(double) );
            fin.Seek( sizeof(int), SEEK_CUR );
        }
        fin.Seek( (nLoadComb-Comb)*nodeNum*72, SEEK_CUR );
        Force.SetNodeForce( nodeNum, F );
        ShellForce.Insert( Force );
    }
    fin.Close();
    return 1;
}
int DResult::RecycleGetAllShellForce( bifstream & fin, int & combNo,
                                     MArrayID<DShellForce> & vForce )
{
    static int shellNum=0;
    int i, n, nodeNum;
    double F[9][8];
    DShellForce Force;

    vForce.Clear();
    if( !fin.IsOpen() ) {
        char Name[_MAX_PATH];
        GetFileName( Name, "A41" );
        if( !fin.Open( Name ) ) return 0;
        fin.Seek( 4, SEEK_SET );
        fin >> shellNum;
        combNo = 0;
        fin.Seek( 8, SEEK_CUR );
    }
    fin >> n;	// 为了下面的if服务
    if( fin.Eof() || !fin.IsGood() ) {
        fin.Close();	// 内力循环读取结束，必须关闭文件
        return 0;
    }
    combNo ++;
    for( n = 0; n < shellNum; n ++ ) {
        if( n > 0 ) fin.Seek( 4, SEEK_CUR );
        fin >> Force.nID >> nodeNum;
        fin.Seek( 4, SEEK_CUR );
        for( i = 0; i < nodeNum; i ++ ) {
            fin.Seek( 4, SEEK_CUR );
            fin.Read( F[i], 8*sizeof(double) );
            fin.Seek( 4, SEEK_CUR );
        }
        Force.SetNodeForce( nodeNum, F );
        vForce.Insert( Force );
    }
    return 1;
}
int DResult::RecycleGetAllShellForceNoAve( bifstream & fin, int & combNo,
                                     MArrayID<DShellForce> & vForce )
{
    int i, j, eleNum, nodeNum;
    double F[9][8];
    DShellForce Force;

    vForce.Clear();
    if( !fin.IsOpen() ) {
        char Name[_MAX_PATH];
        GetFileName( Name, "U41" );
        if( !fin.Open( Name ) ) return 0;
        combNo = 0;
    }
    else fin.Rewind();
    combNo ++;
    if( combNo > nLoadComb ) {
        fin.Close();
        return 0;
    }
    fin.Seek( 4, SEEK_SET );
    fin >> eleNum;
    fin.Seek( 8, SEEK_CUR );
    for( j = 0; j < eleNum; j ++ ) {
        fin.Seek( sizeof(int), SEEK_CUR );
        fin >> Force.nID >> nodeNum;
        if( fin.Eof() || !fin.IsGood() ) {
            vForce.Clear();		// 格式有错误
            fin.Close();
            return 0;
        }
        fin.Seek( sizeof(int)+(combNo-1)*nodeNum*72, SEEK_CUR );
        for( i = 0; i < nodeNum; i ++ ) {
            fin.Seek( sizeof(int), SEEK_CUR );
            fin.Read( F[i], 8*sizeof(double) );
            fin.Seek( sizeof(int), SEEK_CUR );
        }
        fin.Seek( (nLoadComb-combNo)*nodeNum*72, SEEK_CUR );
        Force.SetNodeForce( nodeNum, F );
        vForce.Insert( Force );
    }
    return 1;
}
int DResult::GetOneWallAllCombForce( int WallNo, MArrayID<DWallForce> & WallForce )
{
    int Pos, i, n, hole,type,door,out;
    char Name[_MAX_PATH];
    DWallForce Force;
    DWallForceElement *pe;
    bifstream fin;

    WallForce.Clear();
    GetFileName( Name, "NU5" );	// 读取U5的索引文件
    if( !fin.Open( Name ) ) return 0;
    fin >> n;
    if( WallNo <1 || WallNo > n ) return 0;	// 越界
    fin.Seek( (WallNo-1)*sizeof(int), SEEK_CUR );
    Pos = -1;
    fin >> Pos;
    fin.Close();
    if( Pos < 0 ) return 0;		// 不存在单元号为WallNo的板壳单元

    GetFileName( Name, "U5" );
    if( !fin.Open( Name ) ) return 0;
    fin.Seek( Pos+sizeof(int), SEEK_SET );
    fin >> n >> hole >> type >> door >> out;
    fin.Seek( sizeof(int), SEEK_CUR );
    Force.nType = (unsigned char)type;
    if( hole == 1 ) Force.nHole = 0;
    else {
        if( door > 0 ) Force.nHole = 1;
        else if( out > 0 ) Force.nHole = 3;
        else Force.nHole = 2;
    }
    Force.AllocAndZeroMemoryAccordnHole();
    // AllocAndZeroMemoryAccordnHole函数已经根据需要设置好需要哪些内力结果
    for( i = 0; i < nLoadComb; i ++ ) {
        Force.nID = i+1;
        WallForce.Insert( Force );
    }
    if( type == 0 || type == 1 ) {	// 面内内力
        for( n = 0; n < 5; n ++ ) {
            if( Force.ARRAYF[n] == NULL ) continue;	// 不需要此内力
            for( i = 0; i < nLoadComb; i ++ ) {
                pe = WallForce.Ref(i+1).ARRAYF[n];
                assert( pe != NULL );
                fin.Seek( sizeof(int), SEEK_CUR );
                fin.Read( pe->InF1, 3*sizeof(double) );
                fin.Read( pe->InF3, 3*sizeof(double) );
                fin.Seek( sizeof(int), SEEK_CUR );
            }
        }
    }
    if( type != 1 ) {	// 面外内力
        for( n = 0; n < 5; n ++ ) {
            if( Force.ARRAYF[n] == NULL ) continue;	// 不需要此内力
            for( i = 0; i < nLoadComb; i ++ ) {
                pe = WallForce.Ref(i+1).ARRAYF[n];
                assert( pe != NULL );
                fin.Seek( sizeof(int), SEEK_CUR );
                fin.Read( pe->OutF1, 3*sizeof(double) );
                fin.Read( pe->OutF3, 3*sizeof(double) );
                fin.Seek( sizeof(int), SEEK_CUR );
            }
        }
    }

    fin.Close();
    return 1;
}
int DResult::GetOneCombAllWallForce( int Comb, MArrayID<DWallForce> & WallForce )
{
    char Name[_MAX_PATH];
    int hole,type,door,out, i, size;
    bifstream fin;
    DWallForce Force;
    DWallForceElement *pe;

    WallForce.Clear();
    if( Comb<=0 || Comb>nLoadComb ) return 0;
    GetFileName( Name, "U5" );
    if( !fin.Open( Name ) ) return 0;
    fin.Seek( 16, SEEK_SET );
    size = sizeof(double)*6+sizeof(int)*2;
    while(1) {
        fin.Seek( sizeof(int), SEEK_CUR );
        fin >> Force.nID >> hole >> type >> door >> out;
        if( fin.Eof() || !fin.IsGood() ) break;
        fin.Seek( sizeof(int), SEEK_CUR );
        Force.nType = (unsigned char)type;
        if( hole == 1 ) Force.nHole = 0;
        else {
            if( door > 0 ) Force.nHole = 1;
            else if( out > 0 ) Force.nHole = 3;
            else Force.nHole = 2;
        }
        Force.AllocAndZeroMemoryAccordnHole();
        if( type == 0 || type == 1 ) {	// 面内内力
            for( i = 0; i < 5; i ++ ) {
                pe = Force.ARRAYF[i];
                if( pe == NULL ) continue;	// 不需要此内力
                fin.Seek( (Comb-1)*size, SEEK_CUR );
                fin.Seek( sizeof(int), SEEK_CUR );
                fin.Read( pe->InF1, 3*sizeof(double) );
                fin.Read( pe->InF3, 3*sizeof(double) );
                fin.Seek( sizeof(int), SEEK_CUR );
                fin.Seek( (nLoadComb-Comb)*size, SEEK_CUR );
            }
        }
        if( type != 1 ) {	// 面外内力
            for( i = 0; i < 5; i ++ ) {
                pe = Force.ARRAYF[i];
                if( pe == NULL ) continue;	// 不需要此内力
                fin.Seek( (Comb-1)*size, SEEK_CUR );
                fin.Seek( sizeof(int), SEEK_CUR );
                fin.Read( pe->OutF1, 3*sizeof(double) );
                fin.Read( pe->OutF3, 3*sizeof(double) );
                fin.Seek( sizeof(int), SEEK_CUR );
                fin.Seek( (nLoadComb-Comb)*size, SEEK_CUR );
            }
        }
        WallForce.Insert( Force );
    }
    fin.Close();
    return 1;
}
int DResult::RecycleGetOneWallForce( bifstream & fin, int & eleID,
                                    MArrayID<DWallForce> & vForce )
{
    int i, n, hole,type,door,out;
    DWallForce Force;
    DWallForceElement *pe;

    vForce.Clear();
    if( !fin.IsOpen() ) {
        char Name[_MAX_PATH];
        GetFileName( Name, "U5" );
        if( !fin.Open( Name ) ) return 0;
        fin.Seek( 16, SEEK_SET );
    }

    fin.Seek( 4, SEEK_CUR );
    fin >> eleID >> hole >> type >> door >> out;
    if( fin.Eof() || !fin.IsGood() ) {
        fin.Close();	// 内力循环读取结束，必须关闭文件
        return 0;
    }
    fin.Seek( 4, SEEK_CUR );
    Force.nType = (unsigned char)type;
    if( hole == 1 ) Force.nHole = 0;
    else {
        if( door > 0 ) Force.nHole = 1;
        else if( out > 0 ) Force.nHole = 3;
        else Force.nHole = 2;
    }
    Force.AllocAndZeroMemoryAccordnHole();
    // AllocAndZeroMemoryAccordnHole函数已经根据需要设置好需要哪些内力结果
    for( i = 0; i < nLoadComb; i ++ ) {
        Force.nID = i+1;
        vForce.Insert( Force );
    }
    if( type == 0 || type == 1 ) {	// 面内内力
        for( n = 0; n < 5; n ++ ) {
            if( Force.ARRAYF[n] == NULL ) continue;	// 不需要此内力
            for( i = 0; i < nLoadComb; i ++ ) {
                pe = vForce.Ref(i+1).ARRAYF[n];
                assert( pe != NULL );
                fin.Seek( 4, SEEK_CUR );
                fin.Read( pe->InF1, 3*sizeof(double) );
                fin.Read( pe->InF3, 3*sizeof(double) );
                fin.Seek( 4, SEEK_CUR );
            }
        }
    }
    if( type != 1 ) {	// 面外内力
        for( n = 0; n < 5; n ++ ) {
            if( Force.ARRAYF[n] == NULL ) continue;	// 不需要此内力
            for( i = 0; i < nLoadComb; i ++ ) {
                pe = vForce.Ref(i+1).ARRAYF[n];
                assert( pe != NULL );
                fin.Seek( 4, SEEK_CUR );
                fin.Read( pe->OutF1, 3*sizeof(double) );
                fin.Read( pe->OutF3, 3*sizeof(double) );
                fin.Seek( 4, SEEK_CUR );
            }
        }
    }
    return 1;
}
int DResult::GetAllNodeAboveForce( int nComb, double force[][6] )
{
    char Name[_MAX_PATH];

    if( nComb < 1 || nComb > nLoadComb ) return 0;
    GetFileName( Name, "NFSJ" );
    bifstream fin( Name );
    if( !fin ) return 0;
    fin.Seek( 6*nNode*sizeof(double)*(nComb-1), SEEK_SET );
    fin.Read( force, 6*nNode*sizeof(double) );
    fin.Close();
    return 1;
}
int DResult::GetOneNodeAboveForce( int nNdID, double force[][6] )
{
    char Name[_MAX_PATH];

    if( nNdID < 1 || nNdID > nNode ) return 0;
    GetFileName( Name, "NFSJ" );
    bifstream fin( Name );
    if( !fin ) return 0;
    int size = 6*sizeof(double);
    for( int i = 0; i < nLoadComb; i ++ ) {
        fin.Seek( (nNdID-1)*size, SEEK_CUR );
        fin.Read( force[i], size );
        fin.Seek( (nNode-nNdID)*size, SEEK_CUR );
    }
    fin.Close();
    return 1;
}
int DResult::GetAllNodeMass( double mass[][6] )
{
    char Name[_MAX_PATH];

    GetFileName( Name, "NMAS" );
    bifstream fin( Name );
    if( !fin ) return 0;
    fin.Read( mass, sizeof(double)*6*nNode );
    // fin的析构函数将自动关闭文件
    return 1;
}


DResult的私有成员函数：

void DResult::SetZero()
{
    strName[0] = '\0';
    nNodeTotal = nNode = 0;
    nLoad = nDispComb = nLoadComb = 0;
    nEquation = 0;
    nEigen = 0;
    nResponse = 0;
    nResponseType = 1;
    nSpectrum = nBuckle = nSpecModeNum = 0;
    nActNum = 0;
}
int DResult::SetFileName(const char *Name, int nodeNumConcerned )
{
    char file[_MAX_PATH], ext[20];
    SetZero();
    GFunc::ExtractFilePathName( Name, strName, file, ext );
    strcat( strName, file );
    nNode = nodeNumConcerned;
    if( !UpdateResult() ) {
        strName[0] = '\0';
        return 0;
    }
    return 1;
}
void DResult::GetFileName( char Name[_MAX_PATH], const char * Ext )
{
    strcpy( Name, strName );
    if( Ext != NULL ) {
        strcat( Name, "." );
        strcat( Name, Ext );
    }
}
void DResult::DeleteTemporaryFiles()
{
    char Name[_MAX_PATH];
    const char * ext[] = { "NU3", "NU30", "NA41", "NU5", "NDIS", "NVEC",
            "NRES", "NVEL", "NACC", "NEQU", "NSTA", "NACD", "NMAS", "NFSJ" };
    for( int i = 0; i < sizeof(ext)/sizeof(const char*); i ++ ) {
        GetFileName( Name, ext[i] );
        remove( Name );
    }
}
int DResult::IsNewThanPLFile( const char * Name )
{
    char PLFile[_MAX_PATH];
    GetFileName( PLFile, "PL" );
    return GFunc::GetFileTime(PLFile)<=GFunc::GetFileTime(Name);
}
int DResult::FileTimeComp( const char * Ext1, const char * Ext2 )
{
    char Name[_MAX_PATH];
    int t;
    GetFileName( Name, Ext1 );
    t = GFunc::GetFileTime( Name );
    GetFileName( Name, Ext2 );
    t = t-GFunc::GetFileTime( Name );
    if( t < 0 ) return -1;
    else if( t > 0 ) return 1;
    return 0;
}
int DResult::AllocNodeMemory(int* &id, int* &id1, int* &id2, int* &id3, int* &id4,
        int* &id5, int* &id6, int* &id7, double* &Displace, double* &Fx, double* &Fy,
        double* &Fz, double* &Rx, double* &Ry, double* &Rz, double* &xyz,
        double* &x, double* &y, double* &z, double* &Dis)
{
    int num;
    char Name[_MAX_PATH];
    bifstream fin1, fin2;

    GetFileName( Name, "ID" );
    if( !fin1.Open( Name ) ) return 0;
    GetFileName( Name, "XYZ" );
    if( !fin2.Open( Name ) ) return 0;

    id = new int[7*nNodeTotal];
    Displace= new double[6*nNodeTotal];
    xyz = new double[3*nNodeTotal];
    Dis = new double[nEquation];
    if( id==NULL || Displace==NULL || xyz==NULL || Dis==NULL ) {
        if( id ) {
            delete[] id;
            id = NULL;
        }
        if( Displace ) {
            delete[] Displace;
            Displace = NULL;
        }
        if( xyz ) {
            delete[] xyz;
            xyz = NULL;
        }
        if( Dis ) {
            delete[] Dis;
            Dis = NULL;
        }
        return 0;
    }
    id1 = id;				id2 = id1+nNodeTotal;	id3 = id2+nNodeTotal;
    id4 = id3+nNodeTotal;	id5 = id4+nNodeTotal;	id6 = id5+nNodeTotal;
    id7 = id6+nNodeTotal;
    Fx  = Displace;				Fy  = Fx+nNodeTotal;	Fz  = Fy+nNodeTotal;
    Rx  = Fz+nNodeTotal;	Ry  = Rx+nNodeTotal;	Rz  = Ry+nNodeTotal;
    x = xyz;	y = xyz+nNodeTotal;	z = y+nNodeTotal;

    num = nNodeTotal*7;
    fin1.Seek( sizeof(int)*6, SEEK_SET );
    fin1.Read( id, num*sizeof(int) );
    fin1.Close();
    for( int i = 0; i < num; i ++ ) {
        if( id[i] < 0 ) id[i] = 0;
    }
    fin2.Seek( sizeof(int)*6, SEEK_SET );
    fin2.Read( xyz, nNodeTotal*3*sizeof(double) );
    fin2.Close();
    return 1;
}
int DResult::UpdateResult()
{
    char Name[_MAX_PATH],RefName[_MAX_PATH], *Ext, *RefExt;
    int i, j, Nzz[55], memsize, maxno, preNode;
    int *id=NULL, *id1, *id2, *id3, *id4, *id5, *id6, *id7;
    double *Displace=NULL, *Fx, *Fy, *Fz, *Rx, *Ry, *Rz;
    double *xyz=NULL, *x, *y, *z;
    double *Dis=NULL, E;
    // char UpdateDis;
    bifstream fin;
    bofstream fout;
    //************************************

    GetFileName( Name, "NSYS" );	// 文件中保存了上一次调用DResult时的节点数
    preNode = 0;
    if( IsNewThanPLFile(Name) && fin.Open(Name) ) {
        fin >> preNode;
        fin.Close();
        if( nNode <= 0 ) nNode = preNode;
    }
    // 读取name.sys中的一些关键数据
    GetFileName( Name, "SYS" );
    if( !fin.Open( Name ) ) return 0;
    // skip size,name[12],ext[55],nel[55],ntype[55],ndmax
    fin.Seek( sizeof(int)+sizeof(char)*12+(sizeof(int)*55)*3+sizeof(int), SEEK_SET );
    fin.Read( Nzz, sizeof(int)*6 );
    nLoad = (short)Nzz[0];
    nNodeTotal = Nzz[1];
    nEquation = Nzz[3];
    nEigen = (short)Nzz[5];
    fin.Read( Nzz, sizeof(int)*55 );
    nDispComb = Nzz[22];
    nLoadComb = Nzz[23];
    if( Nzz[9]>0 && Nzz[11]>0 ) {
        // 同时用了两种方法进行时程分析
        if( FileTimeComp( "DYN", "STP" ) < 0 ) {
            nResponse = Nzz[11];
            nResponseType = Nzz[12];
        }
        else {
            nResponse = Nzz[9];
            nResponseType = Nzz[10];
        }
    }
    else if( Nzz[9] > 0 ) {
        nResponse = Nzz[9];
        nResponseType = Nzz[10];
    }
    else if( Nzz[11] > 0 ) {
        nResponse = Nzz[11];
        nResponseType = Nzz[12];
    }
    else {
        nResponse = 0;
        nResponseType = 0;
    }
#ifndef v60
    if( nResponseType == 3 ) nResponseType = 4;
#endif
    nActNum = Nzz[30];
    if( nActNum < 0 ) nActNum = 0;
    nSpectrum = Nzz[6];
    nSpecModeNum = Nzz[7];
    GetFileName( Name, "STA" );
    if( GFunc::FileExist(Name) ) nBuckle = 2*nLoadComb;
    else nBuckle = 0;

    if( nNode>nNodeTotal || nNode==0) {
        fin >> nNode;
        if( nNode>nNodeTotal || nNode==0 ) nNode = nNodeTotal;
    }
    fin.Close();
    if( nNode != preNode ) {
        GetFileName( Name, "NSYS" );
        if( fout.Open( Name ) ) {
            fout << nNode;
            fout.Close();
        }
    }

    //************************************
    // 更新变形的相关文件
    // 转换与节点相关的一些结果文件
    // UpdateDis = 0;
    char *vExt[]={"NDIS"/*0*/,"NVEC"/*1*/,"NRES"/*2*/,"NVEL"/*3*/,
        "NACC"/*4*/,"NEQU"/*5*/,"NSTA"/*6*/,"NACD"/*7*/,"NMAS"/*8*/,"NFSJ"/*9*/};
    char *vRefExt[]={"DIS"/*0*/,"VEC"/*1*/,"RES"/*2*/,"VEL"/*3*/,
        "ACC"/*4*/,"EQU"/*5*/,"STA"/*6*/,"ACD"/*7*/,"MAS"/*8*/,"FSJ"/*9*/};
    int vNum[]={nLoad+nDispComb/*0*/,nEigen/*1*/,nResponse/*2*/,nResponse/*3*/,
        nResponse/*4*/,nSpectrum/*5*/,nBuckle/*6*/,nActNum/*7*/,1/*8*/,0/*9*/};
    for( i = 0; i < sizeof(vExt)/sizeof(vExt[i]); i ++ ) {
        Ext = vExt[i];
        RefExt = vRefExt[i];
        GetFileName( Name, Ext );
        GetFileName( RefName, RefExt );
        if( !IsNewThanPLFile(RefName) || FileTimeComp(Ext,RefExt)>=0 )
            continue;	// 不需要更新
        fin.Open( RefName );
        fout.Open( Name );
        if( !fin || !fout ) {
            fin.Close();
            fout.Close();
            continue;
        }
        if( id == NULL ) {	// 第一次循环
            if( !AllocNodeMemory( id, id1, id2, id3, id4, id5, id6, id7, Displace,
                Fx, Fy, Fz, Rx, Ry, Rz, xyz, x, y, z, Dis ) )
                return 0;	// 内存不足
        }
        // if( i == 0 ) UpdateDis = 1;
        if( i == 9 ) UpdateNodeAboveForce(fin,fout,x,y,z);
        // 当i==9时，vNum[i]=0，故不会进入下面的for循环
        for( j = 0; j < vNum[i]; j ++ ) {
            if( i == 8 ) fin.Seek( 24, SEEK_CUR );	// 质量矩阵文件
            fin.Read( Dis, sizeof(double)*nEquation );
            if( i != 8 ) fin.Read( &E, sizeof(double) );
            if( i == 1 ) E = PI2/sqrt(E);		// 由特征值求周期
            // 如果包含CONSTRAINT,同一节点指向同一自由度，为避免质量被重复计算
            // 在转换质量的时候，某一自由度的质量被使用之后将被设成0
            for( int n = 0; n < nNodeTotal; n ++ ) {
                if( id1[n] > 0 ) {
                    Fx[n] = Dis[id1[n]-1];
                    if( i == 8 ) Dis[id1[n]-1] = 0.0;
                }
                else Fx[n] = 0.0;
                if( id2[n] > 0 ) {
                    Fy[n] = Dis[id2[n]-1];
                    if( i == 8 ) Dis[id2[n]-1] = 0.0;
                }
                else Fy[n] = 0.0;
                if( id3[n] > 0 ) {
                    Fz[n] = Dis[id3[n]-1];
                    if( i == 8 ) Dis[id3[n]-1] = 0.0;
                }
                else Fz[n] = 0.0;
                if( id4[n] > 0 ) {
                    Rx[n] = Dis[id4[n]-1];
                    if( i == 8 ) Dis[id4[n]-1] = 0.0;
                }
                else Rx[n] = 0.0;
                if( id5[n] > 0 ) {
                    Ry[n] = Dis[id5[n]-1];
                    if( i == 8 ) Dis[id5[n]-1] = 0.0;
                }
                else Ry[n] = 0.0;
                if( id6[n] > 0 ) {
                    Rz[n] = Dis[id6[n]-1];
                    if( i == 8 ) Dis[id6[n]-1] = 0.0;
                }
                else Rz[n] = 0.0;
            }
            if( i == 8 ) {
                DistriMassOfWallRefNode( Fx, Fy, Fz, Rx, Ry, Rz );
            }
            else {
                // 对位移处理主从约束关系
                for( n = 0; n < nNodeTotal; n ++ ) {
                    memsize = id7[n]-1;
                    if( memsize < 0 ) continue;
                    Rz[n] = Rz[memsize];
                    Fx[n] = Fx[memsize] - Rz[n]*(y[n]-y[memsize]);
                    Fy[n] = Fy[memsize] + Rz[n]*(x[n]-x[memsize]);
                }
                if( i == 1 || (i>=2&&i<=4) || i == 6 )
                    fout.Write( &E, sizeof(double) );
            }
            for( n = 0; n < nNode; n ++ ) {
                fout << Fx[n] << Fy[n] << Fz[n] << Rx[n] << Ry[n] << Rz[n];
            }
        }
        fin.Close();
        fout.Close();
    }
    // 如果没有发生更新，则不会分配以下的内存
    if( id ) delete[] id;
    if( Displace ) delete[] Displace;
    if( xyz ) delete[] xyz;
    if( Dis ) delete[] Dis;
    //************************************
    // 更新框架和钢框架单元的内力索引文件
    for( i = 0; i < 2; i ++ ) {
        if( i == 0 ) {
            GetFileName( Name, "NU3" );
            GetFileName( RefName, "U3" );
        }
        else {
            GetFileName( Name, "NU30" );
            GetFileName( RefName, "U30" );
        }
        if( IsNewThanPLFile(RefName) && (GFunc::GetFileTime(Name)<GFunc::GetFileTime(RefName)) ) {
            fin.Open( RefName );
            fout.Open( Name );
            if( !fin || !fout ) {
                fin.Close();
                fout.Close();
                continue;
            }
            memsize = 1000;
            maxno = 0;		// 最大单元号
            id = (int*)malloc(memsize*sizeof(int));
            memset( id, 0xFF, sizeof(int)*memsize );	// 初始化为-1
            fin.Seek( 16, SEEK_SET );
            int ElementNo, Inter, Pos;
            while(1) {
                Pos = fin.TellPos();
                fin.Seek( sizeof(int), SEEK_CUR );
                fin.Read( &ElementNo, sizeof(int) );
                fin.Seek( sizeof(int), SEEK_CUR );
                fin.Read( &Inter, sizeof(int) );
                if( fin.Eof() || !fin.IsGood() ) break;
                fin.Seek( Inter*sizeof(double)+sizeof(int), SEEK_CUR );
                if( memsize < ElementNo ) {
                    id = (int*)realloc( id, (ElementNo+1000)*sizeof(int) );
                    memset( &id[memsize], 0xFF, (ElementNo+1000-memsize)*sizeof(int) );
                    memsize = ElementNo+1000;
                }
                if( ElementNo > maxno ) maxno = ElementNo;
                id[ElementNo-1] = Pos;
                fin.Seek( nLoadComb*Inter*56, SEEK_CUR );
            }
            fout.Write( &maxno, sizeof(int) );
            fout.Write( id, sizeof(int)*maxno );
            fin.Close();
            fout.Close();
            delete[] id;
        }
    }
    //************************************
    // 更新板壳单元的内力索引文件
    GetFileName( Name, "NA41" );
    GetFileName( RefName, "A41" );
    if( IsNewThanPLFile(RefName) && (GFunc::GetFileTime(Name)<GFunc::GetFileTime(RefName)) ) {
        fin.Open( RefName );
        fout.Open( Name );
        if( !fin || !fout ) {
            fin.Close();
            fout.Close();
        }
        else {
            int eleNum, NodeNum;
            id = (int*)malloc(nLoadComb*sizeof(int));
            memset( id, 0xFF, sizeof(int)*nLoadComb );	// 初始化为-1
            fin.Seek( sizeof(int), SEEK_SET );
            fin >> eleNum;
            fin.Seek( 8, SEEK_CUR );
            for( i = 0; i < nLoadComb; i ++ ) {
                id[i] = fin.TellPos();
                for( j = 0; j < eleNum; j ++ ) {
                    fin.Seek( sizeof(int)*2, SEEK_CUR );
                    fin >> NodeNum;
                    fin.Seek( sizeof(int)+NodeNum*72, SEEK_CUR );
                }
            }
            NodeNum = nLoadComb;
            fout.Write( &NodeNum, sizeof(int) );
            fout.Write( id, sizeof(int)*nLoadComb );
            fin.Close();
            fout.Close();
            delete[] id;
        }
    }
    GetFileName( Name, "NU41" );
    GetFileName( RefName, "U41" );
    if( IsNewThanPLFile(RefName) && (GFunc::GetFileTime(Name)<GFunc::GetFileTime(RefName)) ) {
        fin.Open( RefName );
        fout.Open( Name );
        if( !fin || !fout ) {
            fin.Close();
            fout.Close();
        }
        else {
            int eleNum, ElementNo, Pos, NodeNum;
            memsize = 1000;
            maxno = 0;		// 最大单元号
            id = (int*)malloc(memsize*sizeof(int));
            memset( id, 0xFF, sizeof(int)*memsize );	// 初始化为-1
            fin.Seek( sizeof(int), SEEK_SET );
            fin >> eleNum;
            fin.Seek( 8, SEEK_CUR );
            for( i = 0; i < eleNum; i ++ ) {
                Pos = fin.TellPos();
                fin.Seek( sizeof(int), SEEK_CUR );
                fin >> ElementNo >> NodeNum;
                fin.Seek( sizeof(int), SEEK_CUR );
                if( memsize < ElementNo ) {
                    id = (int*)realloc( id, (ElementNo+1000)*sizeof(int) );
                    memset( &id[memsize], 0xFF, (ElementNo+1000-memsize)*sizeof(int) );
                    memsize = ElementNo+1000;
                }
                if( ElementNo > maxno ) maxno = ElementNo;
                id[ElementNo-1] = Pos;
                fin.Seek( nLoadComb*NodeNum*72, SEEK_CUR );
            }
            fout.Write( &maxno, sizeof(int) );
            fout.Write( id, sizeof(int)*maxno );
            fin.Close();
            fout.Close();
            delete[] id;
        }
    }
    //************************************
    // 更新墙单元的内力索引文件
    GetFileName( Name, "NU5" );
    GetFileName( RefName, "U5" );
    if( IsNewThanPLFile(RefName) && (GFunc::GetFileTime(Name)<GFunc::GetFileTime(RefName)) ) {
        fin.Open( RefName );
        fout.Open( Name );
        if( !fin || !fout ) {
            fin.Close();
            fout.Close();
        }
        else {
            memsize = 1000;
            maxno = 0;		// 最大单元号
            id = (int*)malloc(memsize*sizeof(int));
            memset( id, 0xFF, sizeof(int)*memsize );	// 初始化为-1
            fin.Seek( 16, SEEK_SET );
            int ElementNo, Hole, Type, Door, IOut, Pos, size;
            while(1) {
                Pos = fin.TellPos();
                fin.Seek( sizeof(int), SEEK_CUR );
                fin >> ElementNo >> Hole >> Type >> Door >> IOut;
                if( fin.Eof() || !fin.IsGood() ) break;
                fin.Seek( sizeof(int), SEEK_CUR );
                if( memsize < ElementNo ) {
                    id = (int*)realloc( id, (ElementNo+1000)*sizeof(int) );
                    memset( &id[memsize], 0xFF, (ElementNo+1000-memsize)*sizeof(int) );
                    memsize = ElementNo+1000;
                }
                if( ElementNo > maxno ) maxno = ElementNo;
                id[ElementNo-1] = Pos;
                if( Hole == 1 ) size = 1;
                else {
                    if( Door > 0 ) size = 3;
                    else {
                        if( IOut > 0 ) size = 5;
                        else size = 1;
                    }
                }
                if( Type == 0 ) size *= 2;
                fin.Seek( nLoadComb*size*56, SEEK_CUR );
            }
            fout.Write( &maxno, sizeof(int) );
            fout.Write( id, sizeof(int)*maxno );
            fin.Close();
            fout.Close();
            delete[] id;
        }
    }
    //************************************
    return 1;
}
int DResult::GetOneFrameOrSframeAllCombForce( int isSframe, int FrameNo,
                            MArrayID<DFrameForce> & FrameForce )
{
    const char *indexExt, *uExt;
    char Name[_MAX_PATH];
    int Pos, n, SectNum;
    double F[20][7];
    DFrameForce Force;
    bifstream fin;

    if( isSframe ) {
        indexExt = "NU30";
        uExt = "U30";
    }
    else {
        indexExt = "NU3";
        uExt = "U3";
    }
    FrameForce.Clear();
    GetFileName( Name, indexExt );	// 读取u3的索引文件
    if( !fin.Open( Name ) ) return 0;
    fin >> n;
    if( FrameNo < 1 || FrameNo > n ) return 0;	// 越界
    fin.Seek( (FrameNo-1)*sizeof(int), SEEK_CUR );
    Pos = -1;
    fin >> Pos;
    fin.Close();
    if( Pos < 0 ) return 0;		// 不存在单元号为FrameNo的框架单元

    GetFileName( Name, uExt );
    if( !fin.Open( Name ) ) return 0;
    fin.Seek( Pos+sizeof(int)*3, SEEK_SET );
    fin >> SectNum;
    assert( SectNum<=20 );
    for( n = 0; n < SectNum; n ++ )
        fin >> F[n][0];
    fin.Seek( sizeof(int), SEEK_CUR );
    for( n = 0; n < nLoadComb; n ++ ) {
        Force.nID = n+1;
        for( int i = 0; i < SectNum; i ++ ) {
            fin.Seek( sizeof(int), SEEK_CUR );
            fin.Read( &F[i][1], 6*sizeof(double) );
            fin.Seek( sizeof(int), SEEK_CUR );
        }
        Force.SetSectForce( SectNum, F );
        FrameForce.Insert( Force );
    }
    fin.Close();
    return 1;
}
int DResult::GetOneCombAllFrameOrSframeForce( int isSframe, int Comb,
                            MArrayID<DFrameForce> & FrameForce )
{
    const char *uExt;
    char Name[_MAX_PATH];
    bifstream fin;
    DFrameForce Force;
    int SectNum, i;
    double F[20][7];

    if( isSframe ) uExt = "U30";
    else uExt = "U3";

    FrameForce.Clear();
    if( Comb<1 || Comb>nLoadComb ) return 0;
    GetFileName( Name, uExt );
    if( !fin.Open( Name ) ) return 0;
    fin.Seek( 16, SEEK_SET );
    while(1) {
        fin.Seek( sizeof(int), SEEK_CUR );
        fin >> Force.nID;
        fin.Seek( sizeof(int), SEEK_CUR );
        fin >> SectNum;
        if( fin.Eof() || !fin.IsGood() ) break;
        for( i = 0; i < SectNum; i ++ )
            fin >> F[i][0];
        fin.Seek( sizeof(int), SEEK_CUR );
        fin.Seek( (Comb-1)*SectNum*56, SEEK_CUR );
        assert( SectNum <= 20 );
        for( i = 0; i < SectNum; i ++ ) {
            fin.Seek( 4, SEEK_CUR );
            fin.Read( &F[i][1], 6*sizeof(double) );
            fin.Seek( 4, SEEK_CUR );
        }
        fin.Seek( (nLoadComb-Comb)*SectNum*56, SEEK_CUR );
        Force.SetSectForce( SectNum, F );
        FrameForce.Insert( Force );
    }
    fin.Close();
    return 1;
}
int DResult::RecycleGetOneSframeOrFrameForce( int isSframe, bifstream & fin,
                        int & eleID, MArrayID<DFrameForce> & vForce )
{
    int n, SectNum;
    double F[20][7];
    DFrameForce Force;

    vForce.Clear();
    if( !fin.IsOpen() ) {
        char Name[_MAX_PATH];
        if( isSframe ) GetFileName( Name, "U30" );
        else GetFileName( Name, "U3" );
        if( !fin.Open( Name ) ) return 0;
        fin.Seek( 16, SEEK_SET );
    }
    fin.Seek( 4, SEEK_CUR );
    fin >> eleID;
    fin.Seek( 4, SEEK_CUR );	// 跳过单元类型
    fin >> SectNum;
    if( fin.Eof() || !fin.IsGood() ) {
        fin.Close();	// 内力循环读取结束，必须关闭文件
        return 0;
    }
    assert( SectNum<=20 );
    for( n = 0; n < SectNum; n ++ )
        fin >> F[n][0];
    fin.Seek( 4, SEEK_CUR );
    for( n = 0; n < nLoadComb; n ++ ) {
        Force.nID = n+1;
        for( int i = 0; i < SectNum; i ++ ) {
            fin.Seek( 4, SEEK_CUR );
            fin.Read( &F[i][1], 6*sizeof(double) );
            fin.Seek( 4, SEEK_CUR );
        }
        Force.SetSectForce( SectNum, F );
        vForce.Insert( Force );
    }
    return 1;
}
int DResult::GetOneOrAllFrameReinData( MArrayID<DFrameRein> * allReinForce,
    int FrameNo, DFrameRein * oneReinForce )
{
    char Name[_MAX_PATH];
    int i, n[2], find=0;;
    DFrameRein rein;
    bifstream fin;

    assert( !allReinForce || !oneReinForce );
    if( allReinForce ) allReinForce->Clear();
    GetFileName( Name, "RC2" );
    if( !fin.Open( Name ) ) return 0;
    fin.Seek( 4, SEEK_CUR );	// 跳过单元总数
    while(1) {
        fin >> rein.nID >> n[0];
        if( fin.Eof() || !fin.IsGood() ) return 0;
        if( n[0] !=1 ) continue;
        fin >> n[0] >> n[1];
        rein.nType = n[0];
        rein.SetSectNum( n[1] );
        for( i = 0; i < rein.nSectNum; i ++ ) {
            if( rein.nType == 1 ) {		// 梁
                rein.ReadDownRein(i,fin);
                rein.ReadUpperRein(i,fin);
                rein.ReadHoopRein(i,fin);
            }
            else if( rein.nType == 2 ) {	// 柱
                rein.ReadHoopRein(i,fin);
                rein.ReadDir2Rein(i,fin);
                rein.ReadDir3Rein(i,fin);
            }
            else {	// 支撑
                rein.ReadDownRein(i,fin);
                rein.ReadUpperRein(i,fin);
                rein.ReadHoopRein(i,fin);
                rein.ReadDir2Rein(i,fin);
                rein.ReadDir3Rein(i,fin);
            }
        }
        if( rein.nType != 2 ) rein.ReadTorRein(fin);
        if( allReinForce ) allReinForce->Insert( rein );
        else if( oneReinForce && rein.nID == FrameNo ) {
            *oneReinForce = rein;
            find = 1;
            break;
        }
    }
    fin.Close();
    if( oneReinForce && !find ) return 0;
    return 1;
}
int DResult::GetAllNodeDisp( const char * Ext, int No, double dis[][6],
                            int isDispComb, double * head )
{
    char Name[_MAX_PATH];
    int headSize;
    if( isDispComb ) No += nLoad;
    GetFileName( Name, Ext );
    bifstream fin( Name );
    if( !fin ) return 0;
    if( head != NULL ) headSize = sizeof(double);
    else headSize = 0;
    int size = 6*nNode*sizeof(double);
    fin.Seek( (size+headSize)*(No-1), SEEK_SET );
    if( headSize )
        fin.Read( head, headSize );
    fin.Read( dis, size );
    fin.Close();
    return 1;
}
int DResult::GetOneNodeDisp( const char * Ext, int ndNo, int num, double disp[][6],
        int isDispComb, double *head )
{
    char Name[_MAX_PATH];
    int headSize = 0;

    if( ndNo < 1 || ndNo > nNode ) return 0;
    GetFileName( Name, Ext );
    bifstream fin( Name );
    if( !fin ) return 0;
    if( head != NULL ) headSize = sizeof(double);
    int size = 6*sizeof(double);
    if( isDispComb ) fin.Seek( nLoad*nNode*size, SEEK_SET );	// 跳过荷载种类位移
    for( int i = 0; i < num; i ++ ) {
        if( headSize ) fin.Read( &head[i], headSize );
        fin.Seek( (ndNo-1)*size, SEEK_CUR );
        fin.Read( disp[i], size );
        fin.Seek( (nNode-ndNo)*size, SEEK_CUR );
    }
    fin.Close();
    return 1;
}

int DResult::GetAllNodeStress( const char * Ext, int CombNo, double stress[][9] )
{
    char Name[_MAX_PATH];
    bifstream fin;
    double *buf;

    if( CombNo < 1 || CombNo > nLoadComb ) return 0;
    GetFileName( Name, Ext );
    if( !fin.Open( Name ) ) return 0;
    int size = nNodeTotal*sizeof(double);
    fin.Seek( size*9*(CombNo-1), SEEK_SET );
    buf = new double[nNodeTotal];
    for( int i = 0; i < 9; i ++ ) {
        fin.Read( buf, size );
        for( int j = 0; j < nNode; j ++ ) stress[j][i] = buf[j];
    }
    delete[] buf;
    fin.Close();
    return 1;
}
int DResult::GetOneNodeStress( const char * Ext, int ndNo, double stress[][9] )
{
    int i, j;
    char Name[_MAX_PATH];
    bifstream fin;

    if( ndNo < 1 || ndNo > nNode ) return 0;
    GetFileName( Name, Ext );
    if( !fin.Open( Name ) ) return 0;
    for( i = 0; i < nLoadComb; i ++ ) {
        for( j = 0; j < 9; j ++ ) {
            fin.Seek( (ndNo-1)*sizeof(double), SEEK_CUR );
            fin >> stress[i][j];
            fin.Seek( (nNodeTotal-ndNo)*sizeof(double), SEEK_CUR );
        }
    }
    fin.Close();
    return 1;
}
int sortInt( const void * op1, const void * op2 )
{
    if( *((int*)op1) < *((int*)op2) ) return -1;
    else if( *((int*)op1) > *((int*)op2) ) return 1;
    return 0;
}
int DResult::GetSomeNodeStress( const char * Ext, int ndNum, int nd[21], double stress[][21][9] )
{
    int i, j, k, pre, *index, node[21];
    char Name[_MAX_PATH];
    bifstream fin;

    if( ndNum < 1 || ndNum > 21 ) return 0;
    GetFileName( Name, Ext );
    if( !fin.Open( Name ) ) return 0;
    index = new int[nNode];
    for( i = 0; i < ndNum; i ++ ) {
        if( nd[i] < 1 ) continue;
        index[nd[i]-1] = i;
        node[i] = nd[i];
    }
    qsort( node, ndNum, sizeof(int), sortInt );
    for( i = 0; i < nLoadComb; i ++ ) {
        for( j = 0; j < 9; j ++ ) {
            pre = 0;
            for( k = 0; k < ndNum; k ++ ) {
                if( node[k] < 1 ) continue;
                fin.Seek( (node[k]-pre-1)*sizeof(double), SEEK_CUR );
                fin >> stress[i][index[node[k]-1]][j];
                pre = node[k];
            }
            fin.Seek( (nNodeTotal-node[ndNum-1])*sizeof(double), SEEK_CUR );
        }
    }
    delete[] index;
    fin.Close();
    return 1;
}
// 把墙细分的节点的质量转移到四个角节点的质量上
void DResult::DistriMassOfWallRefNode( double *mx, double *my, double *mz,double *mrx, double *mry, double *mrz )
{
#ifndef v60
    char Name[_MAX_PATH];
    int i, j, k, sub[2], Q[5], nd, num, refnd[40], cur;
    double ratio, m, *pm[6]={mx,my,mz,mrx,mry,mrz};
    bifstream fin;
    GetFileName( Name, "REF" );
    if( !IsNewThanPLFile(Name) ) return;
    fin.Open( Name );
    if( !fin ) return;
    while(1) {
        fin >> num;
        if( fin.Eof() || !fin.IsGood() ) break;
        fin.Read( sub, sizeof(sub) );
        sub[0] --;		sub[1] --;
        fin.Read( Q, sizeof(int)*4 );
        // 使节点按逆时针排列
        Q[4] = Q[2];		Q[2] = Q[3];
        Q[3] = Q[4];		Q[4] = Q[0];
        if( sub[0] < 0 || sub[1] < 0 ) break;	// 数据内容有误
        num = (sub[0]+sub[1])*2;
        fin.Read( refnd, sizeof(int)*num );	// 读取细分的节点
        fin.Seek( sizeof(int), SEEK_CUR );
        if( num < 1 ) continue;
        // 按原有的质量比例进行分摊
        cur = 0;
        for( i = 0; i < 4; i ++ ) {
            num = sub[i%2];
            for( k = 0; k < 6; k ++ ) {
                // 求相应边上细分节点质量之和
                m = 0.0;
                for( j = 0; j < num; j ++ ) {
                    nd = refnd[cur+j];
                    if( nd > nNode && nd <= nNodeTotal ) {	// 细分节点超出后处理处理的节点范围
                        m += pm[k][nd-1];
                        pm[k][nd-1] = 0.0;	// 避免相邻墙单元重复处理此质量
                    }
                }
                // 分配质量
                if( m > 1.0E-8 ) {
                    ratio = pm[k][Q[i]-1]+pm[k][Q[i+1]-1];	// 求两端的质量之和
                    if( ratio < 1.0E-8 ) ratio = 0.5;
                    else ratio = pm[k][Q[i]-1]/ratio;
                    pm[k][Q[i]-1] += m*ratio;
                    pm[k][Q[i+1]-1] += m*(1.0-ratio);
                }
            }
            cur += num;
        }
    }
    fin.Close();
#endif
}
void DResult::UpdateNodeAboveForce( bifstream & fin, bofstream & fout, double *x, double *y, double *z )
{
#ifndef v60
    int i, j, k, l, sub[2], Q[4], nd, num=0, cur=0, *file=NULL;
    char Name[_MAX_PATH];
    struct _stat Buff;
    double (*f)[6], ratio, len;
    bifstream finm;

    GetFileName( Name, "REF" );
    if( !IsNewThanPLFile(Name) || !finm.Open( Name ) ) goto WRITE;

    if( _stat( Name, &Buff ) != 0 || Buff.st_size<1 ) goto WRITE;
    file = new int[Buff.st_size/2];	// 我们只需要存储Q1-Q2边上细分的节点
    if( !file ) goto WRITE;

    while(1) {
        finm >> sub[0];
        if( finm.Eof() || !finm.IsGood() ) break;
        finm.Read( sub, sizeof(sub) );
        sub[0] --;		sub[1] --;
        finm.Read( Q, sizeof(int)*4 );
        if( sub[0] < 0 || sub[1] < 0 ) break;	// 数据内容有误
        if( sub[0] > 0 ) {
            if( z[Q[0]-1] < z[Q[2]-1] ) {
                file[cur++] = Q[0];
                file[cur++] = Q[1];
                file[cur++] = sub[0];
                finm.Read( &file[cur], sizeof(int)*sub[0] );	// 读取细分的节点
                cur += sub[0];
                num ++;
                finm.Seek( sizeof(int)*(sub[0]+2*sub[1]), SEEK_CUR );
            }
            else {	// Q1,Q2在上端
                file[cur++] = Q[2];
                file[cur++] = Q[3];
                file[cur++] = sub[0];
                finm.Seek( sizeof(int)*(sub[0]+sub[1]), SEEK_CUR );
                finm.Read( &file[cur], sizeof(int)*sub[0] );	// 读取细分的节点
                cur += sub[0];
                num ++;
                finm.Seek( sizeof(int)*sub[1], SEEK_CUR );
            }
        }
        else if( sub[1] > 0 ) finm.Seek( sizeof(int)*sub[1], SEEK_CUR );
        finm.Seek( sizeof(int), SEEK_CUR );
    }
    finm.Close();

WRITE:
    f = new double[nNodeTotal][6];
    for( i = 0; i < nLoadComb; i ++ ) {
        fin.Read( f, 6*nNodeTotal*sizeof(double) );
        cur = 0;
        for( j = 0; j < num; j ++ ) {	// 把墙细分节点处的反力分配到两端的节点上
            Q[0] = file[cur++]-1;
            Q[1] = file[cur++]-1;
            sub[0] = file[cur++];
            len = GFunc::GetDistance(x[Q[0]],y[Q[0]],z[Q[0]],x[Q[1]],y[Q[1]],z[Q[1]]);
            for( k = 0; k < sub[0]; k ++ ) {
                nd = file[cur+k]-1;
                if( nd<nNode || nd>=nNodeTotal ) continue;	// 此节点没有超出nNode的范围
                ratio = GFunc::GetDistance(x[Q[0]],y[Q[0]],z[Q[0]],x[nd],y[nd],z[nd])/len;
                for( l = 0; l < 6; l ++ ) {
                    f[Q[0]][l] += f[nd][l]*ratio;
                    f[Q[1]][l] += f[nd][l]*(1.0-ratio);
                }
                f[Q[0]][3] += f[nd][1]*ratio*(z[Q[0]]-z[nd])+f[nd][2]*ratio*(y[nd]-y[Q[0]]);
                f[Q[0]][4] += f[nd][0]*ratio*(z[nd]-z[Q[0]])+f[nd][2]*ratio*(x[Q[0]]-x[nd]);
                f[Q[0]][5] += f[nd][0]*ratio*(y[Q[0]]-y[nd])+f[nd][1]*ratio*(x[nd]-x[Q[0]]);
                f[Q[1]][3] += f[nd][1]*(1.0-ratio)*(z[Q[1]]-z[nd])+f[nd][2]*(1.0-ratio)*(y[nd]-y[Q[1]]);
                f[Q[1]][4] += f[nd][0]*(1.0-ratio)*(z[nd]-z[Q[1]])+f[nd][2]*(1.0-ratio)*(x[Q[1]]-x[nd]);
                f[Q[1]][5] += f[nd][0]*(1.0-ratio)*(y[Q[1]]-y[nd])+f[nd][1]*(1.0-ratio)*(x[nd]-x[Q[1]]);
                memset( f[nd], 0, sizeof(double)*6 );	// 防止在处理相邻墙细分节点时再次分配
            }
            cur += sub[0];
        }
        fout.Write( f, 6*nNode*sizeof(double) );
    }
    delete[] f;
    if( file ) delete[] file;
#endif
}


DResult的声明

class CLASS_DECLSPEC DResult
{
public:		// 下面这些数据最好不要在外部修改，只需读取
    // 后处理程序能够控制(有节点坐标等信息)的节点个数，此数目一般等于数据文件中
    // 的节点数，但是可以有时也可以小一些，例如，数据文件中可能有大量的节点是另
    // 有它用的，比如用于梁柱局部坐标系的定义，这些节点一般放置在最后，调用程序
    // 可以传入此数目，如果不传入则由此类负责处理. 涉及到节点数的结果输出均以此节点数为准
    int nNode;
    short nLoad;	// 静载种类数
    short nDispComb;// 位移组合数
    short nLoadComb;// 内力组合数
    int nEquation;	// 结构计算的方程总数
    short nEigen;	// 计算的特征向量的个数
    // 如果同时计算了dynamic和step，则以.dyn和.stp的时间新的为准
    int nResponse;	// 动力分析的响应个数
    char nResponseType;	// 动力分析的结果类型,第1,2,3位分别表示是否输出位移,速度,加速度结果(不等于0表示输出,否则不输出)
    short nSpectrum;	// 地震方向个数
    short nBuckle;		// 屈曲模态个数=2*内力组合数
    short nActNum; // 施工模拟的步数
    short nSpecModeNum;	// 地震反应谱计算时所使用的振型数
public:
    DResult();
    // nodeNumConcerned(即nNode)非常重要，它表示您所关心的节点数
    DResult( const char *Name, int nodeNumConcerned );
    virtual ~DResult();
    // 传入扩展名，返回文件名。Ext不包含'.'字符
    void GetFileName( char Name[_MAX_PATH], const char * Ext );
    // 设置文件名，该文件名最好带路径, 但是不能带扩展名,
    // nodeNumConcerned(即nNode)非常重要，它表示您所关心的节点数
    int SetFileName( const char *Name, int nodeNumConcerned );
    int Good() const;	// 测试类对象的初始化是否正确
    void DeleteTemporaryFiles();
    operator void *() const;
    int operator!() const { return !Good(); }

    // ********** 读取节点位移，该位移来源于文件name.dis *************
    // 读取某荷载种类下的所有节点的位移, disp[nNode][6]
    int GetOneCondDisp( int loadcondition, double disp[][6] );
    // 读取一个节点nNdID所有荷载种类下的位移, disp[nLoad][6]
    int GetOneNodeAllCondDisp( int nNdID, double disp[][6] );
    // 读取某位移组合下的所有节点的位移, disp[nNode][6]
    int GetOneCombDisp( int loadcombination, double disp[][6] );
    // 读取一个节点nNdID所有位移组合的位移, disp[nDispComb][6]
    int GetOneNodeAllCombDisp( int nNdID, double disp[][6] );
    // ***************************************************************

    // ********** 获取各种振型对应的的节点变形和周期 ******************
    // ***这里没有提供读取一个节点在所有振型下变形的函数，因为它没有实际意义**
    // 读取某振型下的所有节点的变形, disp[nNode][6], period为周期
    int GetEigenDisp( int EigenNo, double disp[][6], double & period );
    // 读取所有振型的周期, period[nEigen]用于存储所有的周期
    int GetEigenPeriod( double period[] );
    // ***************************************************************

    // **  获取时程分析的位移、速度、加速度, 是否存在此类型的结果取决于nResponseType ***
    // 读取某个响应号下的所有节点的位移值, resdisp[nNode][6], time为对应的时间
    int GetOneHistResDisp( int RespNo, double resdisp[][6], double & time );
    // 读取一个节点nNdID在所有在所有响应号下的位移值, resdisp[nResponse][6], time[nResponse]
    int GetOneNodeAllHistResDisp( int nNdID, double resdisp[][6], double time[] );
    // 读取某个响应号下的所有节点的速度值, resvel[nNode][6], time为对应的时间
    int GetOneHistResVel( int RespNo, double resvel[][6], double & time );
    // 读取一个节点nNdID在所有在所有响应号下的速度值, resvel[nResponse][6], time[nResponse]
    int GetOneNodeAllHistResVel( int nNdID, double resvel[][6], double time[] );
    // 读取某个响应号下的所有节点的加速度值, resacc[nNode][6], time为对应的时间
    int GetOneHistResAcc( int RespNo, double resacc[][6], double & time );
    // 读取一个节点nNdID在所有在所有响应号下的加位移值, resacc[nResponse][6], time[nResponse]
    int GetOneNodeAllHistResAcc( int nNdID, double resacc[][6], double time[] );
    // ***************************************************************

    // *****************  地震反应谱的位移 ***************************
    // 读取某地震方向下的所有节点的位移, disp[nNode][6]
    int GetOneSpecDirDisp( int SpectrumNo, double disp[][6] );
    // 读取一个节点在所有地震方向下的位移值, disp[nSpectrum][6]
    int GetOneNodeAllSpecDirDisp( int nNdID, double disp[][6] );
    // ModeNo[]返回地震反应谱计算过程中使用的振型号,数组大小为nSpecModeNum
    // part[]返回各地震方向下所有振型的参与系数,共有nSpectrum组数,每一组数包含nSpecModeNum个double
    // effect[]返回各地震方向下所有振型的地震影响系数,数组大小为nSpecModeNum*nSpectrum
    int GetSpectrumCalData( int ModeNo[], double part[], double effect[] );
    // ***************************************************************

    // *****************  屈曲模态位移 ***************************
    // ***这里没有提供读取一个节点在所有屈曲模态下变形的函数，因为它没有实际意义**
    // 读取某屈曲模态对应的所有节点的变形, disp[nNode][6], lfactor为荷载因子
    int GetOneBuckleDisp( int BuckleNo, double disp[][6], double & lfactor );
    // 读取所有屈曲模态对应的荷载比例因子, factor[nBuckle]用于存储所荷载因子
    int GetBuckleFactor( double factor[] );
    // ***************************************************************

    // ********** 读取节点施工模拟的位移，该位移来源于文件name.acd *************
    // 读取某施工模拟步下的所有节点的位移, disp[nNode][6]
    int GetOneConstrDisp( int actConstr, double disp[][6] );
    // 读取一个节点nNdID所有施工模拟步下的位移, disp[nActNum][6]
    int GetOneNodeAllConstrDisp( int nNdID, double disp[][6] );
    // ***************************************************************

    // *****************  框架单元的内力 ***************************
    // 获取某个梁柱单元所有组合下的内力，DFrameForce中的nID表示
    // 的是组合号，如果成功返回1，否则返回0
    int GetOneFrameAllCombForce( int FrameNo, MArrayID<DFrameForce> & FrameForce );
    // 获取某组合下所有梁柱单元的内力, DFrameForce中的nID表示
    // 的是单元号，如果成功返回1，否则返回0
    int GetOneCombAllFrameForce( int Comb, MArrayID<DFrameForce> & FrameForce );
    // 连续读取所有梁柱单元所有组合的内力(只能采用多次循环调用,一直到函数返回值
    // 等于0截至, 如果中途返回, 则需要调用fin.Close() ),
    // eleID返回读到的内力所属的单元号，vForce返回该单元所有组合下的内力，
    // DFrameForce中的nID表示的是组合号，如果成功返回1(需要循环调用)，否则返回0
    int RecycleGetOneFrameForce( bifstream & fin, int & eleID, MArrayID<DFrameForce> & vForce );
    // ***************************************************************

    // *****************  混凝土框架的配筋 ***************************
    // 获取单根梁柱单元的配筋数据
    int GetOneFrameReinData( int FrameNo, DFrameRein & reinForce );
    // 获取所有梁柱单元的配筋数据
    int GetAllFrameReinData( MArrayID<DFrameRein> & reinForce );
    // ***************************************************************

    // *****************  钢框架(梁柱)单元的内力 ***************************
    // 获取某个钢梁柱单元所有组合下的内力，DFrameForce中的nID表示
    // 的是组合号，如果成功返回1，否则返回0
    int GetOneSframeAllCombForce( int FrameNo, MArrayID<DFrameForce> & FrameForce );
    // 获取某组合下所有钢梁柱单元的内力, DFrameForce中的nID表示
    // 的是单元号，如果成功返回1，否则返回0
    int GetOneCombAllSframeForce( int Comb, MArrayID<DFrameForce> & FrameForce );
    // 连续读取所有钢梁柱单元所有组合的内力(只能采用多次循环调用,一直到函数返回值
    // 等于0截至, 如果中途返回, 则需要调用fin.Close() ),
    // eleID返回读到的内力所属的单元号，vForce返回该单元所有组合下的内力，
    // DFrameForce中的nID表示的是组合号，如果成功返回1(需要循环调用)，否则返回0
    int RecycleGetOneSframeForce( bifstream & fin, int & eleID, MArrayID<DFrameForce> & vForce );
    // ***************************************************************

    // *****************  钢框架(梁柱)单元的校核结果 ***************************
    // 获取某个钢梁柱单元所有组合下的校核结果，DSframeCheck中的nID表示
    // 的是组合号，如果成功返回1，否则返回0
    int GetOneSframeAllCombCheck( int SframeNo, MArrayID<DSframeCheck> & CheckResult );
    // 获取某组合下所有钢梁柱单元的校核结果, DSframeCheck中的nID表示
    // 的是单元号，如果成功返回1，否则返回0
    int GetOneCombAllSframeCheck( int Comb, MArrayID<DSframeCheck> & CheckResult );
    // 连续读取所有钢梁柱单元所有组合的校核结果(只能采用多次循环调用,一直到函数返回值
    // 等于0截至, 如果中途返回, 则需要调用fin.Close() ),
    // eleID返回读到的校核结果所属的单元号，vCheck返回该单元所有组合下的校核结果，
    // DSframeCheck中的nID表示的是组合号，如果成功返回1(需要循环调用)，否则返回0
    int RecycleGetOneSframeCheck( bifstream & fin, int & eleID, MArrayID<DSframeCheck> & vCheck );
    // ***************************************************************

    // *****************  桁架单元的内力 ***************************
    // 返回某桁架单元所有组合下的轴力, DTrussForce中的nID表示的是组合号
    int GetOneTrussAllCombForce( int TrussNo, MArrayID<DTrussForce> & TrussForce );
    // 返回某组合下所有桁架单元的轴力, DTrussForce中的nID表示的是单元号
    int GetOneCombAllTrussForce( int Comb, MArrayID<DTrussForce> & TrussForce );
    // 连续读取所有桁架单元所有组合的内力(只能采用多次循环调用,一直到函数返回值
    // 等于0截至, 如果中途返回, 则需要调用fin.Close() ),
    // eleID返回读到的内力所属的单元号，vForce返回该单元所有组合下的内力，
    // DTrussForce中的nID表示的是组合号，如果成功返回1(需要循环调用)，否则返回0
    int RecycleGetOneTrussForce( bifstream & fin, int & eleID, MArrayID<DTrussForce> & vForce );
    // ***************************************************************

    // *****************  曲梁单元的内力 ***************************
    // 获取某个曲梁单元所有组合下的内力, DCframeForce中的nID表示的是组合号
    int GetOneCframeAllCombForce( int CframeNo, MArrayID<DCframeForce> & CframeForce );
    // 获取所有曲梁单元在某组合下的内力, CframeForce中的nID表示的是单元号
    int GetOneCombAllCframeForce( int Comb, MArrayID<DCframeForce> & CframeForce );
    // 连续读取所有曲梁单元所有组合的内力(只能采用多次循环调用,一直到函数返回值
    // 等于0截至, 如果中途返回, 则需要调用fin.Close() ),
    // eleID返回读到的内力所属的单元号，vForce返回该单元所有组合下的内力，
    // DCframeForce中的nID表示的是组合号，如果成功返回1(需要循环调用)，否则返回0
    int RecycleGetOneCframeForce( bifstream & fin, int & eleID, MArrayID<DCframeForce> & vForce );
    // ***************************************************************

    // *****************  变截面梁单元的内力 ***************************
    // 获取某个变截面梁单元所有组合下的内力，DVframeForce(实际上就是DFrameForce)中
    // 的nID表示的是组合号，如果成功返回1，否则返回0 (变截面梁单元目前只能计算两端的内力)
    int GetOneVframeAllCombForce( int VframeNo, MArrayID<DVframeForce> & VframeForce );
    // 获取某组合下所有变截面梁单元的内力, DVframeForce(实际上就是DFrameForce)中
    // 的nID表示的是单元号，如果成功返回1，否则返回0
    int GetOneCombAllVframeForce( int Comb, MArrayID<DVframeForce> & VframeForce );
    // 连续读取所有变截面梁单元所有组合的内力(只能采用多次循环调用,一直到函数返回值
    // 等于0截至, 如果中途返回, 则需要调用fin.Close() ),
    // eleID返回读到的内力所属的单元号，vForce返回该单元所有组合下的内力，
    // DVframeForce中的nID表示的是组合号，如果成功返回1(需要循环调用)，否则返回0
    int RecycleGetOneVframeForce( bifstream & fin, int & eleID, MArrayID<DVframeForce> & vForce );
    // ***************************************************************

    // *****************  管道单元的内力 ***************************
    // 获取某个管道单元所有组合下的内力, DPipeForce中的nID表示的是组合号
    int GetOnePipeAllCombForce( int PipeNo, MArrayID<DPipeForce> & PipeForce );
    // 获取某组合下所有管道单元的内力, DPipeForce中的nID表示的是单元号
    int GetOneCombAllPipeForce( int Comb, MArrayID<DPipeForce> & PipeForce );
    // 连续读取所有管道单元所有组合的内力(只能采用多次循环调用,一直到函数返回值
    // 等于0截至, 如果中途返回, 则需要调用fin.Close() ),
    // eleID返回读到的内力所属的单元号，vForce返回该单元所有组合下的内力，
    // DPipeForce中的nID表示的是组合号，如果成功返回1(需要循环调用)，否则返回0
    int RecycleGetOnePipeForce( bifstream & fin, int & eleID, MArrayID<DPipeForce> & vForce );
    // ***************************************************************

    // *****************  弹簧单元的弹簧 ***************************
    // 返回某弹簧单元所有组合下的弹簧力, DSpringForce中的nID表示的是组合号
    int GetOneSpringAllCombForce( int SpringNo, MArrayID<DSpringForce> & SpringForce );
    // 返回某组合下所有弹簧单元的弹簧力, DSpringForce中的nID表示的是单元号
    int GetOneCombAllSpringForce( int Comb, MArrayID<DSpringForce> & SpringForce );
    // 连续读取所有弹簧单元所有组合的内力(只能采用多次循环调用,一直到函数返回值
    // 等于0截至, 如果中途返回, 则需要调用fin.Close() ),
    // eleID返回读到的内力所属的单元号，vForce返回该单元所有组合下的内力，
    // DSpringForce中的nID表示的是组合号，如果成功返回1(需要循环调用)，否则返回0
    int RecycleGetOneSpringForce( bifstream & fin, int & eleID, MArrayID<DSpringForce> & vForce );
    // ***************************************************************

    // *************  平面单元的节点应力和主应力方向角 ***************
    // 9个应力分量的意义可以参考接口说明中相关的应力文件格式说明
    // 读取所有节点在某内力组合下平面单元的应力,
    // CombNo为内力组合, stress[nNode][9]
    int GetOneCombPlaneStress( int CombNo, double stress[][9] );
        // 读取某个节点在所有内力组合下平面单元的应力，
    // ndNo为节点号，stress[nLoadComb][9]
    int GetOneNodeAllCombPlaneStress( int ndNo, double stress[][9] );
    // 读取多个节点(小于21个)在所有内力组合下的应力，ndNum为节点数(<21)，stress[nLoadComb][21][9]
    int GetSomeNodePlaneStress( int ndNum, int nd[21], double stress[][21][9] );
    // ***************************************************************

    // *************  八节点非协调三维单元的节点应力 *****************
    // 9个应力分量的意义可以参考接口说明中相关的应力文件格式说明
    // 读取所有节点在某内力组合下八节点非协调元的应力,
    // CombNo为内力组合, stress[nNode][9]
    //int GetOneCombThreedStress( int CombNo, double stress[][9] );
    // 读取某个节点在所有内力组合下八节点非协调元的应力，
    // ndNo为节点号，stress[nLoadComb][9]
    //int GetOneNodeAllCombThreedStress( int ndNo, double stress[][9] );
    // ***************************************************************

    // ***************  等参三维实体单元的节点应力 *******************
    // 9个应力分量的意义可以参考接口说明中相关的应力文件格式说明
    // 读取所有节点在某内力组合下等参三维元的应力,
    // CombNo为内力组合, stress[nNode][9]
    int GetOneCombSol21Stress( int CombNo, double stress[][9] );
    // 读取某个节点在所有内力组合下等参三维元的应力，
    // ndNo为节点号，stress[nLoadComb][9]
    int GetOneNodeAllCombSol21Stress( int ndNo, double stress[][9] );
    // 读取多个节点(小于21个)在所有内力组合下的应力，ndNum为节点数(<21)，stress[nLoadComb][21][9]
    int GetSomeNodeSol21Stress( int ndNum, int nd[21], double stress[][21][9] );
    // ***************************************************************

    // **************  16节点非协调三维实体单元的节点应力 ************
    // 9个应力分量的意义可以参考接口说明中相关的应力文件格式说明
    // 读取所有节点在某内力组合下16节点非协调三维元的应力,
    // CombNo为内力组合, stress[nNode][9]
    int GetOneCombS16Stress( int CombNo, double stress[][9] );
    // 读取某个节点在所有内力组合下16节点非协调三维元的应力，
    // ndNo为节点号，stress[nLoadComb][9]
    int GetOneNodeAllCombS16Stress( int ndNo, double stress[][9] );
    // 读取多个节点(小于21个)在所有内力组合下的应力，ndNum为节点数(<21)，stress[nLoadComb][21][9]
    int GetSomeNodeS16Stress( int ndNum, int nd[21], double stress[][21][9] );
    // ***************************************************************

    // *************  带旋转自由度的三维实体非协调元sol8r ************
    // 9个应力分量的意义可以参考接口说明中相关的应力文件格式说明
    // 读取所有节点在某内力组合下带旋转自由度的三维实体非协调元的应力,
    // CombNo为内力组合, stress[nNode][9]
    int GetOneCombSol8rStress( int CombNo, double stress[][9] );
    // 读取某个节点在所有内力组合下带旋转自由度的三维实体非协调元的应力，
    // ndNo为节点号，stress[nLoadComb][9]
    int GetOneNodeAllCombSol8rStress( int ndNo, double stress[][9] );
    // 读取多个节点(小于21个)在所有内力组合下的应力，ndNum为节点数(<21)，stress[nLoadComb][21][9]
    int GetSomeNodeSol8rStress( int ndNum, int nd[21], double stress[][21][9] );
    // ***************************************************************

    // *************  板壳单元 SHELL ************
    // 9个应力分量的意义可以参考接口说明中相关的应力文件格式说明
    // 读取所有节点在某内力组合下板壳单元整体坐标系下的应力,
    // CombNo为内力组合, stress[nNode][9]
    int GetOneCombShellStress( int CombNo, double stress[][9] );
    // 读取某个节点在所有内力组合下板壳单元整体坐标系下的应力，
    // ndNo为节点号，stress[nLoadComb][9]
    int GetOneNodeAllCombShellStress( int ndNo, double stress[][9] );
    // 获取某个板壳单元所有组合下的内力, DShellForce中的nID表示的是组合号
    //////////以下六个函数分成两组,带NoAve的是读取非平均的内应力,其余三个读取平均后的值////////
    // 获取某个板壳单元所有组合下的内力, DShellForce中的nID表示的是组合号
    int GetOneShellAllCombForce( int ShellNo, MArrayID<DShellForce> & ShellForce );
    int GetOneShellAllCombForceNoAve( int ShellNo, MArrayID<DShellForce> & ShellForce );
    // 获取所有板壳单元在某组合下的内力, DShellForce中的nID表示的是单元号
    int GetOneCombAllShellForce( int Comb, MArrayID<DShellForce> & ShellForce );
    int GetOneCombAllShellForceNoAve( int Comb, MArrayID<DShellForce> & ShellForce );
    // 连续读取所有板壳单元所有组合的内力(只能采用多次循环调用,一直到函数返回值
    // 等于0截至, 如果中途返回, 则需要调用fin.Close() ),
    // combNo返回读到的内力所属的组合号，vForce返回该组合下所有单元的内力，
    // DShellForce中的nID表示的是单元号，如果成功返回1(需要循环调用)，否则返回0
    int RecycleGetAllShellForce( bifstream & fin, int & combNo,MArrayID<DShellForce> & vForce );
    int RecycleGetAllShellForceNoAve( bifstream & fin, int & combNo,MArrayID<DShellForce> & vForce );
    // ***************************************************************

    // *************  墙单元 WALL ************
    // 获取某个墙单元所有组合下的内力, DWallForce中的nID表示的是组合号
    int GetOneWallAllCombForce( int WallNo, MArrayID<DWallForce> & WallForce );
    // 获取所有墙单元在某组合下的内力, DWallForce中的nID表示的是单元号
    int GetOneCombAllWallForce( int Comb, MArrayID<DWallForce> & WallForce );
    // 连续读取所有墙单元所有组合的内力(只能采用多次循环调用,一直到函数返回值
    // 等于0截至, 如果中途返回, 则需要调用fin.Close() ),
    // eleID返回读到的内力所属的单元号，vForce返回该单元所有组合下的内力，
    // DWallForce中的nID表示的是组合号，如果成功返回1(需要循环调用)，否则返回0
    int RecycleGetOneWallForce( bifstream & fin, int & eleID, MArrayID<DWallForce> & vForce );
    // ***************************************************************

    // ***** 读取单元下端节点的反力，具体说明请参考关于NAME.FSJ文件的说明 *****
    // 读取某内力组合下的所有节点的由上端单元产生的反力,force[][6]的大小为nNode，nComb为内力组合号
    int GetAllNodeAboveForce( int nComb, double force[][6] );
    // 读取节点nNdID所有内力组合下的由上端单元产生的反力,返回后force[][6]包含nLoadComb组反力
    int GetOneNodeAboveForce( int nNdID, double force[][6] );
    // ***************************************************************

    // ** 读取所有节点的集中质量，一个节点有6个分量, mass[][6]的大小为nNode **
    int GetAllNodeMass( double mass[][6] );
    // ***************************************************************
private:
    // 不带无扩展名的文件名，可以包括路径，也可以不包括
    char strName[_MAX_PATH];
    // SAP84分析结果中的节点数(包含数据文件中的节点以及墙细分增加的节点),
    // 一般大于nNode, 并且多出来的节点号总是在最后面
    int nNodeTotal;
private:
    void SetZero();
    // 传入扩展名，返回文件名。Ext不包含'.'字符
    void GetFileName( char Name[_MAX_PATH], const char * Ext );
    // 比较两个文件的修改时间,扩展名不包括'.'字符,返回-1(Ext1比Ext2旧),0,1(新)
    int FileTimeComp( const char * Ext1, const char * Ext2 );
    // 判断文件Name是否比name.pl新
    int IsNewThanPLFile( const char * Name );
    // 为了更新节点结果文件而分配必须的内存,同时读取ID数组和坐标数组
    // id[7][nNodeTotal], double Displace[6][nNodeTotal], double xyz[3][nNodeTotal]
    // double Dis[nEquation]
    int AllocNodeMemory(int* &id, int* &id1, int* &id2, int* &id3, int* &id4,
        int* &id5, int* &id6, int* &id7, double* &Displace, double* &Fx, double* &Fy,
        double* &Fz, double* &Rx, double* &Ry, double* &Rz, double* &xyz,
        double* &x, double* &y, double* &z, double* &Dis);

    // 更新必须的结果文件和中间文件,如果没有最基本的数据结果返回0，否则返回1
    int UpdateResult();

    // 获取某个梁柱单元或钢梁柱单元所有组合下的内力
    int GetOneFrameOrSframeAllCombForce( int isSframe, int FrameNo,
                MArrayID<DFrameForce> & FrameForce );
    // 获取某组合下所有梁柱单元或钢梁柱单元的内力
    int GetOneCombAllFrameOrSframeForce( int isSframe, int Comb,
                MArrayID<DFrameForce> & FrameForce );
    // 循环读取所有组合下所有梁柱单元或钢梁柱单元的内力
    int RecycleGetOneSframeOrFrameForce( int isSframe, bifstream & fin,
                    int & eleID, MArrayID<DFrameForce> & Force );
    // 获取单根(oneReinForce!=NULL)或所有(allReinForce!=NULL)梁柱单元的配筋数据
    int GetOneOrAllFrameReinData( MArrayID<DFrameRein> * allReinForce,
        int FrameNo, DFrameRein * oneReinForce )
    // 读取所有节点在某荷载种类号（或组合或振型或地震方向或时程响应点或某屈曲模态）
    // 下的位移值，No为这个号,dis中将保存nNode个节点6个方向的位移，
    // isDispComb表明是否要读取组合下的位移值
    // head表示每一组前是否有一个实数头（即周期、时程响应点的时间和荷载因子）
    int GetAllNodeDisp( const char * Ext, int No, double dis[][6],
        int isDispComb=0, double * head=NULL );
    // 读取某个节点在所有荷载种类（或组合或振型或地震方向或时程响应点或某屈曲模态）
    // 下的位移值, ndNo为节点号，disp大小为disp[num][6]，其中num为荷载种类数量，
    // 或组合数，或振型数，或地震方向数，或时程响应点数，或屈曲模态数
    // isDispComb表明是否要读取组合下的位移值
    // head是一个数组head[num], 它用于存储各振型的周期，或各时程响应点的时间，
    // 或屈曲模态对应的荷载因子，读取节点位移和地震反应谱位移时，head必须设置成NULL
    int GetOneNodeDisp( const char * Ext, int ndNo, int num, double disp[][6],
        int isDispComb, double *head );
    // 读取所有节点在某内力组合下的应力, CombNo为内力组合, stress[nNode][9]
    // 应力文件中存储的节点数为nNodeTotal
    int GetAllNodeStress( const char * Ext,int CombNo, double stress[][9] );
    // 读取某个节点在所有内力组合下的应力，ndNo为节点号，stress[nLoadComb][9]
    int GetOneNodeStress( const char * Ext, int ndNo, double stress[][9] );
    // 读取多个节点(小于21个)在所有内力组合下的应力，ndNum为节点数(<21)，stress[nLoadComb][21][9]
    int GetSomeNodeStress( const char * Ext, int ndNum, int nd[21], double stress[][21][9] );
    // 把墙细分处的节点质量分配到四个角点上
    void DistriMassOfWallRefNode( double *mx, double *my, double *mz,double *mrx, double *mry, double *mrz );
    // 根据FSJ文件(已通过fin打开)生成NFSJ文件(已通过fout打开)
    void UpdateNodeAboveForce( bifstream & fin, bofstream & fout, double *x, double *y, double *z );
};


DS16Base的实现

DS16Base::DS16Base()
{
    nID = 0;
    nLevel = 1;
    nLayer = 1;
    for( int i = 0; i < 16; i ++ )
        nNode[i] = 0;
    nMat = 0;
    T0 = (float)0.0;
    nAct = 1;
}
DS16Base::DS16Base(const DS16Base & Copy)
{
    *this = Copy;
}
DS16Base::~DS16Base()
{
}
DS16Base & DS16Base::operator = (const DS16Base & Copy)
{
    if( this != &Copy ) {
        nID = Copy.nID;
        nLevel = Copy.nLevel;
        nLayer = Copy.nLayer;
        for( int i = 0; i < 16; i ++ )
            nNode[i] = Copy.nNode[i];
        nMat = Copy.nMat;
        T0 = Copy.T0;
        Load = Copy.Load;
        nAct = Copy.nAct;
    }
    return *this;
}
int DS16Base::operator ==( const DS16Base & Other)
{
    return GFunc::IsEqual( nNode, Other.nNode, 16 );
}
void DS16Base::SetNodes( int nd[16] )
{
    for( int i = 0; i < 16; i ++ ) nNode[i] = nd[i];
}
void DS16Base::Serialize( bofstream & fout )
{
    fout << nID << nLevel << nLayer;
    fout.Write( nNode, sizeof(int)*16 );
    fout << nMat << T0;
    Load.Serialize(fout);
    fout << nAct;
}
void DS16Base::Serialize( bifstream & fin )
{
    fin >> nID >> nLevel >> nLayer;
    fin.Read( nNode, sizeof(int)*16 );
    fin >> nMat >> T0;
    Load.Serialize(fin);
    if( nVersion > 100 ) fin >> nAct;
}


DS16Base的声明

// 第一部分数据中的P=P1 P2 ...Pnl，在这里得不到支持，生成数据文件时只需要填写
// P=1 1 ... 1(NL个1)

// 这里不考虑应力输出位置的变化，在此我们假设输出所有可能点的应力,
// 输出数据文件时可以做如下处理：应力输出位置的组数NOPSET等于1
// 第一组：L=1 2 ... 23(包括一个单元形心和六个面形心)
// 在单元信息数据中填O=1
class CLASS_DECLSPEC DS16Base {
public:
    int nID;		// 单元号，如果要用于array.h中的MArrayID类，其名称必须为nID
    short nLevel;   // 层标识号(指向DLevelBase的nID)，层号=nID-2
    short nLayer;	// (指向DLayerBase的nID)，与层号相互独立，缺省为1
    int nNode[16];	// 单元节点号，必须全部非零
    short nMat;		// 材料号, 该号指向材料类的DMaterial的nID数据成员，不考虑各向异性
    float T0;		// 无应力状态参考温度

    // Load[i].LocalID指向类DS16Load数组的nID
    DElementLoad  Load;//
    用于描述各总体荷载种类下作用的跨内荷载 short nAct; // 施工模拟的步号(one-based)
public:
    DS16Base();
    DS16Base( const DS16Base & Copy );
    virtual ~DS16Base();
    DS16Base & operator = ( const DS16Base & Copy );
    int operator == ( const DS16Base & Other );
    // index 从零开始零开始
    int & operator [] ( int index ){
        assert( index >= 0 && index < 16 );
        return nNode[index];
    }
    void SetNodes( int nd[16] );

    virtual void Serialize( bofstream & fout );
    virtual void Serialize( bifstream & fin );
};


DS16Load的声明

typedef DSol21Load DS16Load;


DSframeBase的实现

DSframeBase::DSframeBase( )
{
    nID = 0;
    nLevel = 1;
    nLayer = 1;
    nI = 0;
    nJ = 0;
    for( int i = 0; i < 3; i ++ ) {
        Local[i] = (float)0.0;
    }
    nSect = 0;
    nMat = 0;
    Ei = Ej = Eccenti2 = Eccenti3 = Eccentj2 = Eccentj3 = (float)0.0;
    nRMi2 = nRMi3 = nRMj2 = nRMj3 = nRTor = nRAxis = 100;
    nType = 1;
    nT = 1;
    nAct = 1;
}
DSframeBase::DSframeBase( const int i, const int j )
{
    nID = 0;
    nLevel = 1;
    nLayer = 1;
    nI = i;
    nJ = j;
    for( int k = 0; k < 3; k ++ ) {
        Local[k] = (float)0.0;
    }
    nSect = 0;
    nMat = 0;
    Ei = Ej = Eccenti2 = Eccenti3 = Eccentj2 = Eccentj3 = (float)0.0;
    nRMi2 = nRMi3 = nRMj2 = nRMj3 = nRTor = nRAxis = 100;
    nT = 1;
    nAct = 1;
}
DSframeBase::DSframeBase( const DSframeBase & Copy)
{
    *this = Copy;
}
DSframeBase::~DSframeBase()
{
}
DSframeBase & DSframeBase::operator = ( const DSframeBase & Copy )
{
    if( this != &Copy ) {
        nID = Copy.nID;
        nLevel = Copy.nLevel;
        nLayer = Copy.nLayer;
        nI = Copy.nI;
        nJ = Copy.nJ;
        for( int i = 0; i < 3; i ++ ) {
            Local[i] = Copy.Local[i];
        }
        nSect = Copy.nSect;
        nMat = Copy.nMat;
        Ei = Copy.Ei;
        Ej = Copy.Ej;
        Eccenti2 = Copy.Eccenti2;
        Eccenti3 = Copy.Eccenti3;
        Eccentj2 = Copy.Eccentj2;
        Eccentj3 = Copy.Eccentj3;
        nRMi2 = Copy.nRMi2;
        nRMi3 = Copy.nRMi3;
        nRMj2 = Copy.nRMj2;
        nRMj3 = Copy.nRMj3;
        nRTor = Copy.nRTor;
        nRAxis = Copy.nRAxis;
        nType = Copy.nType;
        nT = Copy.nT;
        Load = Copy.Load;
        nAct = 1;
    }
    return *this;
}
int DSframeBase::operator == ( const DSframeBase & Other )
{
    return ((nI==Other.nI)&&(nJ==Other.nJ))||((nI==Other.nJ)&&(nJ==Other.nI));
}
void DSframeBase::Serialize( bofstream & fout )
{
    fout << nID << nLevel << nLayer << nI << nJ;
    fout.Write( Local, sizeof(float)*3 );
    fout << nSect << nMat << Ei << Ej << Eccenti2 << Eccenti3 << Eccentj2 << Eccentj3;
    fout << nRMi3 << nRMj3 << nRAxis << nRMi2 << nRMj2 << nRTor << nType;
    fout << nT;
    Load.Serialize( fout );
    fout << nAct;
}
void DSframeBase::Serialize( bifstream & fin )
{
    fin >> nID >> nLevel >> nLayer >> nI >> nJ;
    fin.Read( Local, sizeof(float)*3 );
    fin >> nSect >> nMat >> Ei >> Ej >> Eccenti2 >> Eccenti3 >> Eccentj2 >> Eccentj3;
    fin >> nRMi3 >> nRMj3 >> nRAxis >> nRMi2 >> nRMj2 >> nRTor >> nType;
    fin >> nT;
    Load.Serialize( fin );
    if( nVersion > 100 ) fin >> nAct;
}


DSframeBase的声明

#define BEAM 1
#define COLUMN 2
#define SLOPE 3
#define SUPPORT 4
// 此类适用于SFRAME
class CLASS_DECLSPEC DSframeBase {
public:
    int nID;		// 单元号，如果要用于array.h中的MArrayID类，其名称必须为nID
    short nLevel;   // 层标识号(指向DLevelBase的nID)，层号=nID-2
    short nLayer;	// (指向DLayerBase的nID)，与层号相互独立，缺省为1
    int nI,nJ;      // node I, node J.
    float Local[3];	// 局部坐标系2轴所指方向的坐标，生成数据文件时需做一定的处理
        // 分别指向类DFrameSect(钢结构对应为CSFrameSect,变截面对应于DVframeSect)、DMaterial数组的nID
    short nSect,nMat;// 截面号和材料号, 该号指向截面或材料类的nID数据成员
            // 钢结构材料缺省为钢材（Q235），这时可以不输入材料，应该置nMat=0，
             // 以区别于无材料的单元, 如果与缺省的不一致，可以按常规输入材料号
    float Ei,Ej;	// Stiffness region of I and J.
    float Eccenti2, Eccenti3, Eccentj2, Eccentj3;	// 两端2、3方向的偏心
    // I、J端两个方向(2和3)弯矩放松因子和扭矩、轴力放松因子
    // 取值范围0-100, 缺省值为0(刚性连接)，100表示完全放松
    unsigned char nRMi3,nRMj3,nRAxis,nRMi2,nRMj2,nRTor;
    unsigned char nType;	// 单元类型：1：梁  2：柱  3：斜梁  4：斜支撑（非主要受力构件） [1]
    unsigned char nT;// 内力插值点数目(缺省为0,即只计算两端的内力)
    // Load[i].LocalID指向类DFrameLoad数组的nID
    DElementLoad  Load;//
    用于描述各总体荷载种类下作用的跨内荷载
    short nAct; // 施工模拟的步号(one-based)
public:
    DSframeBase( );
    DSframeBase( const int i, const int j );
    DSframeBase( const DSframeBase & Copy);
    virtual ~DSframeBase();
    DSframeBase & operator =    ( const DSframeBase
    & Copy);//判断((nI==Other.nI)&&(nJ==Other.nJ))||((nI==Other.nJ)&&(nJ==Other.nI))
    int operator == ( const DSframeBase & Other );

    virtual void Serialize( bifstream & fin );
    virtual void Serialize( bofstream & fout );
};


DSframeCheck的实现

DSframeCheck::DSframeCheck()
{
    nID = 0;
    nSectNum = 0;
    F = NULL;
}
DSframeCheck::DSframeCheck( DSframeCheck & Copy )
{
    F = NULL;
    *this = Copy;
}
DSframeCheck::~DSframeCheck()
{
    Clear();
}
DSframeCheck & DSframeCheck::operator = ( const DSframeCheck & Copy )
{
    if( this != &Copy ) {
        Clear();
        nID = Copy.nID;
        nSectNum = Copy.nSectNum;
        if( nSectNum > 0 ) {
            F = (double (*)[SFRCHKNUM])malloc(nSectNum*sizeof(F[0]));
            memcpy( F, Copy.F, nSectNum*sizeof(F[0]) );
        }
    }
    return *this;
}
void DSframeCheck::SetSectCheck( int SectNum, double (*f)[SFRCHKNUM] )
{
    nSectNum = (unsigned char)SectNum;
    if( F != NULL ) Free(F);
    if( nSectNum > 0 ) {
        F = (double (*)[SFRCHKNUM])malloc(nSectNum*sizeof(F[0]));
        memcpy( F, f, nSectNum*sizeof(F[0]) );
    }
}
void DSframeCheck::AddSectCheck( double f[SFRCHKNUM] )
{
    nSectNum ++;
    F = (double (*)[20])realloc( F, nSectNum*sizeof(F[0]) );
    memcpy( F[nSectNum-1], f, sizeof(F[0]) );
}
void DSframeCheck::Clear( )
{
    nSectNum = 0;
    if( F != NULL ) Free(F);
}
void DSframeCheck::Serialize(bofstream & fout)
{
    fout << nID << nSectNum;
    fout.Write( F, sizeof(F[0])*nSectNum );
}
void DSframeCheck::Serialize(bifstream & fin)
{
    fin >> nID >> nSectNum;
    F = (double (*)[SFRCHKNUM])realloc( F, sizeof(F[0])*nSectNum );
    fin.Read( F, sizeof(F[0])*nSectNum );
}


DSframeCheck的声明

#define SFRCHKNUM 21
// SS88的钢结构校核结果
class CLASS_DECLSPEC DSframeCheck {
public:
    // 单元号或组合号
    int nID;
    // 单元内力计算的截面数
    unsigned char nSectNum;
    // F[i][0]分别表示：截面距I端距离
    // F[i][1-18]依次表示：强度正应力[1]，强度正应力比值[2]，抗弯强度设计值[3]
    // 稳定正应力[4]，稳定正应力比值[5]，剪应力[6]，剪应力比值[7]，抗剪强度设计值[8],
    // 强轴(12平面内)计算长度系数[9]，弱轴(13平面内)计算长度系数[10]，2向长细比[11]，
    // 长细比限值(压)[12]，3向长细比[13]，长细比限值(拉)[14]，宽厚比[15]，
    // 宽厚比限值[16]，高厚比[17]，高厚比限值[18],
    // 稳定应力是2轴大(=2)还是3轴大(=3)[19,以double的方式存储整数]
    // 受弯构件的局部稳定性系数([20] >1表示不稳定,非受弯构件等于0)
    double (*F)[SFRCHKNUM];
public:
    DSframeCheck();
    DSframeCheck( DSframeCheck & Copy );
    virtual ~DSframeCheck();
    DSframeCheck & operator = ( const DSframeCheck & Copy );
    // 设置所有截面的校核结果
    void SetSectCheck( int SectNum, double (*f)[SFRCHKNUM] );
    // 在原来基础之上添加一个截面的校核结果，它不判断该截面是否已经存在
    // 如果要使用AddSectForce函数，最初的时候一定不要设置nSectNum，
    // 因为每次调用该函数后，nSectNum会加1
    void AddSectCheck( double f[SFRCHKNUM] );
    // 把所有截面校核结果置零，释放相关内存
    void Clear();
    // 尽管下面两个函数暂时没有用处，但是为了方便定义可变数组类对象还是定义了这两个函数
    void Serialize(bofstream & fout);
    void Serialize(bifstream & fin);
};


DSframeLoad的声明

typedef DFrameLoad DSframeLoad


DSframeSect的实现

DSframeSect::DSframeSect( )
{
    nID = 0;
    nSectType = 10;
    memset( strNss, 0x00, sizeof(strNss) );
    strcpy( strNss, "D100*8" );
    no = 3;
    zType = 0;
    zSpace = zArea3 = zArea2 = 0.0;
    name = new char[9];
    strcpy( name, "sfrSect" );
}
DSframeSect::DSframeSect( const DSframeSect & Copy )
{
    name = NULL;
    *this = Copy;
}
DSframeSect::~DSframeSect()
{
    if( name ) delete[] name;
}
DSframeSect & DSframeSect::operator = ( const DSframeSect & Copy )
{
    if( this != &Copy ) {
        nID = Copy.nID;
        nSectType = Copy.nSectType;
        memcpy( strNss, Copy.strNss, sizeof(strNss) );
        no = Copy.no;
        zSpace = Copy.zSpace;
        zArea3 = Copy.zArea3;
        zArea2 = Copy.zArea2;
        SetName( Copy.name );
    }
    return *this;
}
void DSframeSect::SetName( const char * nameStr )
{
    int len = strlen(nameStr)+1;
    if( name ) delete[] name;
    name = new char[len];
    strcpy( name, nameStr );
}
double DSframeSect::GetSectArea(int unit)
{
    if( nSectType > 0 ) {
        return DSteelStrManager::GetSteelArea( strNss, unit, nSectType );
    }
    if( nIst == 81 || nIst == 82 ) return O[1]+O[8];
    return A[0];
}
int DSframeSect::operator == ( const DSframeSect & Other ) const
{
    return (stricmp( name, Other.name)==0);
    /*
    double tmp;
    int i;
    if( Other.nType != nType ) return 0;
    if( nType == 1 ) {
        if( strcmp( strNss, Other.strNss ) != 0 ) return 0;
    }
    else if( nType == 2 ) {
        for( i = 0; i < 44; i ++ ) {
            tmp = T[i] - Other.T[i];
            if( tmp < -SectionError || tmp > SectionError ) return 0;
        }
        if( nIst != Other.nIst || nIst1 != Other.nIst1 ) return 0;
        if( nIst2 != Other.nIst2 || nNstl != Other.nNstl ) return 0;
    }
    tmp = zSpace - Other.zSpace;
    if( tmp < -SectionError || tmp > SectionError ) return 0;
    tmp = zArea3 - Other.zArea3;
    if( tmp < -SectionError || tmp > SectionError ) return 0;
    tmp = zArea2 - Other.zArea2;
    if( tmp < -SectionError || tmp > SectionError ) return 0;
    if( nNjt != Other.nNjt || nNa != Other.nNa ) return 0;
    return 1;
    */
}

void DSframeSect::Serialize( bofstream & fout )
{
    int len = strlen( name )+1;
    fout << nID << nSectType;
    fout.Write( &len, sizeof(int) );
    fout.Write( name, len );
    if( nSectType > 0 ) {
        unsigned char strSize = strlen(strNss)+1;
        fout.Write( &strSize, sizeof(unsigned char) );
        fout.Write( strNss, strSize );
    }
    else {
        fout.Write( T, sizeof(float)*44 );
        fout << nIst << nIst1 << nIst2;
    }
    fout << no << zType << zSpace << zArea3 << zArea2;
}
void DSframeSect::Serialize( bifstream & fin )
{
    int len;
    fin >> nID >> nSectType;
    fin.Read( &len, sizeof(int) );
    if( name ) delete[] name;
    name = new char[len];
    fin.Read( name, len );
    if( (nVersion<128 && nSectType==1) || (nVersion>=128 && nSectType>0) ) {
        unsigned char strSize;
        fin.Read( &strSize, sizeof(unsigned char) );
        fin.Read( strNss, strSize );
    }
    else if( (nVersion<128 && nSectType==2) || (nVersion>=128 && nSectType<=0) ) {
        fin.Read( T, sizeof(float)*44 );
        fin >> nIst >> nIst1 >> nIst2;
        if( nVersion < 128 ) fin.Seek( sizeof(short) );
    }
    fin >> no >> zType >> zSpace >> zArea3 >> zArea2;

    if( nVersion < 128 ) {	// 需重新设置nSectType变量
        if( nSectType == 1 ) {
            int index, items, flag[40];
            char info[40][20];
            DSteelStrManager::DetachInfoFromString( strNss, index, items, info, flag, 0 );
            nSectType = index+1;
        }
        else nSectType = 0;	// 自定义截面
    }
}


DSframeSect的声明

// 类DFrameSect适合于SFRAME单元
////////////////////////////////////////////////////////////////////////
// 截面类型		0：SS88中一般的钢材
//	(nSectType)	1-58: SS88能自动查询截面特性的型钢，凡是能自动查询的截面参数
//			这里均不再支持，即这些参数只能使用查询值
////////////////////////////////////////////////////////////////////////
class CLASS_DECLSPEC DSframeSect {
public:
    short nID;
    unsigned char nSectType;	// 截面类型，含义请参考后面的文字
    char *name;	// 保存时先保存字符长度(含c语言的结束符), 再保存字符串(含结束符)
    union {
        struct {	// nSectType = 0，通过填写具体截面参数实现型钢的输入
            // 对格构式构件: 若格构式的两肢完全相同, 输入过程中只需要输入O[0-7]，
            //			输入完后程序应该把后面七个数据取成与前七个一样
            // 对非格构式构件：某些默认值取成跟某数一样的(如：W3n，W31n缺省等于W3，W31)，
            //			在输入完成后，若该数据等于零，程序应该设成更某数一样

            // 以下数据T(不含TD)、V、A、I、F、S对格构式构件无用
            float T[7];		// T=TD b1 t1 b t tw b0
            float V[8];		// V=W3,W31,W2,W21,W3n,W31n,W2n,W21n
            float A[2];		// A=A1,An
            float I[4];		// I =I33 I22 SI33 SI22
            float F[3];		// F=h hw h0
            float S[4];		// S=A2(A22),A3(A33),S2,S3
            // O对非格构式构件无用
            float O[15];	// O=a,A1,I13,I12,W13,W131,W2,W121,A2,I23,I22,W23,W231,W22,W221
            float J;		// J=j1
            // nIst==81 or 82表示格构式构件，其它则表示非格构式构件(此时nIst1,nIst2无用)
            short nIst,nIst1,nIst2;	// K=IST(ISECT) IST1 IST2
            // 以上共有44*4+2*3=182个字节
        };
        char  strNss[182];	// nSectType = 1,2,...58, 通过填写Z=ZSS实现的型钢, 具体可查看DSteelStrManager::SteelTypeStr[]所包含的字符串
            // 保存字符串之前保存了一个字节，该字节表示strNss的长度+1(含'\0')
            // 保存字符串时包含'\0'字符
    };
    unsigned char no;	// H=NA  1: Q345    2:Q390   3:Q235  4:Q420
    unsigned char zType;	// 缀材类型 0:缀条   1:缀板
    float zSpace, zArea3, zArea2;	//缀材间距、两个方向的截面面积
public:
    DSframeSect( );
    ~DSframeSect( );
    DSframeSect( DSframeSect & Copy );
    DSframeSect & operator = ( const DSframeSect & Copy );
    // 通过名称确定是否相等
    int operator == ( const DSframeSect & Other );
    // 设置截面标识名称
    void SetName( const char * nameStr );
    double GetSectArea( int unit ); // 返回截面面积

    virtual void Serialize( bofstream & fout );
    virtual void Serialize( bifstream & fin );
};


DShellBase的实现

DShellBase::DShellBase()
{
    nID = 0;
    nLevel = 1;
    nLayer = 1;
    nType = nIP = 0;
    for( int i = 0; i < 4; i ++ )
        nNode[i] = 0;
    nMat = 0;
    HFilm = HSlab = HFilm2=HSlab2=HFilm3=HSlab3=HFilm4=HSlab4=1.0f;
    nDiscount = 100;
    T0 = (float)0.0;
    nAct = 1;
}
DShellBase::DShellBase(const DShellBase & Copy)
{
    *this = Copy;
}
DShellBase::~DShellBase()
{
}
DShellBase & DShellBase::operator = (const DShellBase & Copy)
{
    if( this != &Copy ) {
        nID = Copy.nID;
        nLevel = Copy.nLevel;
        nLayer = Copy.nLayer;
        nType = Copy.nType;
        nIP = Copy.nIP;
        for( int i = 0; i < 4; i ++ )
            nNode[i] = Copy.nNode[i];
        nMat = Copy.nMat;
        HFilm = Copy.HFilm;
        HSlab = Copy.HSlab;
        HFilm2 = Copy.HFilm2;
        HSlab2 = Copy.HSlab2;
        HFilm3 = Copy.HFilm3;
        HSlab3 = Copy.HSlab3;
        HFilm4 = Copy.HFilm4;
        HSlab4 = Copy.HSlab4;
        nDiscount = Copy.nDiscount;
        T0 = Copy.T0;
        Load = Copy.Load;
        nAct = Copy.nAct;
    }
    return *this;
}
int DShellBase::operator ==( const DShellBase & Other)
{
    if( nType != Other.nType ) return 0;
    return GFunc::IsEqual( nNode, Other.nNode, 4 );
}
void DShellBase::SetNodes( int nd[4], int type )
{
    for( int i = 0; i < 4; i ++ ) {
        nNode[i] = nd[i];
    }
    nType = type;
}
void DShellBase::SetShell(int nd[4], double h1, double h2 )
{
    SetNodes( nd, 0 );
    HFilm=HFilm2=HFilm3=HFilm4=(float)h1;
    if( h2 > SectionError ) HSlab=HSlab2=HSlab3=HSlab4=(float)h2;
    else HSlab=HSlab2=HSlab3=HSlab4=(float)h1;
}
void DShellBase::SetFilm(int nd[4], double h )
{
    SetNodes( nd, 1 );
    HFilm=HFilm2=HFilm3=HFilm4=(float)h;
    HSlab=HSlab2=HSlab3=HSlab4=0.0;
}
void DShellBase::SetSlab(int nd[4], double h )
{
    SetNodes( nd, 2 );
    HSlab=HSlab2=HSlab3=HSlab4=(float)h;
    HFilm=HFilm2=HFilm3=HFilm4=0.0f;
}
void DShellBase::SetThick( double h1, double h2 )
{
    if( nType == 0 ) {
        HFilm=HFilm2=HFilm3=HFilm4=(float)h1;
        if( h2 > SectionError ) HSlab=HSlab2=HSlab3=HSlab4=(float)h2;
        else HSlab=HSlab2=HSlab3=HSlab4=(float)h1;
    }
    else if( nType == 1 ) {
        HFilm=HFilm2=HFilm3=HFilm4=(float)h1;
        HSlab=HSlab2=HSlab3=HSlab4=0.0;
    }
    else if( nType == 2 ) {
        HFilm=HFilm2=HFilm3=HFilm4=0.0;
        HSlab=HSlab2=HSlab3=HSlab4=(float)h1;
    }
}
void DShellBase::GetAverageThick( double & hfilm, double & hslab )
{
    if( IsTriangle() ) {
        hslab = (HSlab+HSlab2+HSlab3)/3.0;
        hfilm = (HFilm+HFilm2+HFilm3)/3.0;
    }
    else {
        hslab = (HSlab+HSlab2+HSlab3+HSlab4)/4.0;
        hfilm = (HFilm+HFilm2+HFilm3+HFilm4)/4.0;
    }
}
void DShellBase::Serialize( bofstream & fout )
{
    fout << nID << nLevel << nLayer << nType << nIP;
    fout.Write( nNode, sizeof(int)*4 );
    fout << nMat << HFilm << HSlab << nDiscount << T0;
    Load.Serialize(fout);
    fout << nAct;
    fout << HFilm2 << HSlab2 << HFilm3 << HSlab3 << HFilm4 << HSlab4;
}
void DShellBase::Serialize( bifstream & fin )
{
    fin >> nID >> nLevel >> nLayer >> nType >> nIP;
    fin.Read( nNode, sizeof(int)*4 );
    fin >> nMat >> HFilm >> HSlab >> nDiscount >> T0;
    Load.Serialize(fin);
    if( nVersion > 100 ) fin >> nAct;
    if( nVersion > 120 )
        fin >> HFilm2 >> HSlab2 >> HFilm3 >> HSlab3 >> HFilm4 >> HSlab4;
    else {
        HFilm2 = HFilm3 = HFilm4 = HFilm;
        HSlab2 = HSlab3 = HSlab4 = HSlab;
    }
}


DShellBase的声明

class CLASS_DECLSPEC DShellBase {
public:
    int nID;		// 单元号，如果要用于array.h中的MArrayID类，其名称必须为nID
    short nLevel;   // 层标识号(指向DLevelBase的nID)，层号=nID-2
    short nLayer;	// (指向DLayerBase的nID)，与层号相互独立，缺省为1
    unsigned char nType;// 单元类型  0：壳单元  1：膜单元 2：板单元(缺省为0)
    unsigned char nIP;	// 板变形是否为杂交元 1：杂交元 0：非杂交元
    int nNode[4];	// 单元节点号(对三角形单元，nNode[3]=0)
    // 顺序与SAP84的定义不一样,Q1 Q2 Q4 Q3, 跨内分布荷载的顺序也不一样,P1 P2 P4 P3
    // 相当于把SAP84的Q3 Q4互换
    short nMat;		// 材料号, 该号指向材料类的DMaterial的nID数据成员
    float HFilm,HSlab; // 第1个点处膜厚度和板厚度 (单元的质量由膜和板厚度的平均值决定)
    float HFilm2,HSlab2,HFilm3,HSlab3,HFilm4,HSlab4; // 板壳第2,3,4号节点处的厚度
    unsigned char nDiscount;// O=O1 板刚度的折减系数*100(缺省为100)
    float T0;		// 无应力状态参考温度

    // Load[i].LocalID指向类DShellLoad数组的nID
    DElementLoad  Load;//
    用于描述各总体荷载种类下作用的跨内荷载 short nAct; // 施工模拟的步号(one-based)
public:
    DShellBase();
    DShellBase( const DShellBase & Copy );
    virtual ~DShellBase();
    DShellBase & operator = ( const DShellBase & Copy );
    // 不仅比较节点，而且比较类型
    int operator == ( const DShellBase & Other );
    // index 从零开始零开始
    int & operator [] ( int index ) {
        assert( index >= 0 && index < 4 );
        return nNode[index];
    }
    int IsTriangle() { return nNode[3]==0; }
    int GetNodeNum() { return (nNode[3]==0?3:4); }
    void SetNodes( int nd[4], int type = 0 );
    // 如果h2小于等于零,板的厚度取h1
    void SetShell( int nd[4], double h1 = 0.0, double h2 = 0.0 );
    void SetFilm( int nd[4], double h=0.0 );
    void SetSlab( int nd[4], double h=0.0 );
    // 如果单元类型是壳单元，h1:膜的厚度 h2:板的厚度，若只填h1，则板的厚度也取h1
    // 如果单元类型为膜单元，h1:膜的厚度 h2:无意义
    // 如果单元类型为板单元，h1:板的厚度 h2:无意义
    void SetThick( double h1, double h2 = 0.0 );
    void GetAverageThick( double & hfilm, double & hslab ); // 计算膜和板的平均厚度

    int IsShell() { return nType == 0; }
    int IsFilm() { return nType == 1; }
    int IsSlab() { return nType == 2; }

    virtual void Serialize( bofstream & fout );
    virtual void Serialize( bifstream & fin );
};


DShellForce的定义

DShellForce::DShellForce()
{
    nID = 0;
    ndNum = 0;
    F = NULL;
}
DShellForce::DShellForce( DShellForce & Copy )
{
    F = NULL;
    *this = Copy;
}
DShellForce::~DShellForce()
{
    if( F != NULL ) Free(F);
}
DShellForce & DShellForce::operator = ( const DShellForce & Copy )
{
    if( this != &Copy ) {
        if( F != NULL ) Free(F);
        nID = Copy.nID;
        ndNum = Copy.ndNum;
        if( ndNum > 0 ) {
            F = (double (*)[8])malloc(ndNum*sizeof(double)*8);
            memcpy( F, Copy.F, sizeof(double)*8*ndNum );
        }
    }
    return *this;
}
void DShellForce::SetNodeForce( int nodeNum, double (*f)[8] )
{
    ndNum = nodeNum;
    if( F != NULL ) Free(F);
    if( ndNum > 0 ) {
        F = (double (*)[8])malloc(ndNum*sizeof(double)*8);
        memcpy( F, f, sizeof(double)*8*ndNum );
    }
}
void DShellForce::Serialize(bofstream & fout)
{
    fout << nID << ndNum;
    fout.Write( F, sizeof(double)*8*ndNum );
}
void DShellForce::Serialize(bifstream & fin)
{
    fin >> nID >> ndNum;
    F = (double (*)[8])realloc( F, sizeof(double)*8*ndNum );
    fin.Read( F, sizeof(double)*8*ndNum );
}


DShellForce的声明

class CLASS_DECLSPEC DShellForce {
public:
    // 单元号或组合号
    int nID;
    // 单元的节点数目(等于4或3), 决定了F数组的大小
    short ndNum;
    // 各节点的内力：依次为σ1、σ2、σ12、Q31、Q32、M11、M22和M12
    // 这里的节点顺序与DShellBase::nNode[4]中节点的顺序一致
    double (*F)[8];
public:
    DShellForce();
    DShellForce( DShellForce & Copy );
    virtual ~DShellForce();
    DShellForce & operator = ( const DShellForce & Copy );
    // 设置节点内力, f的大小为[nodeNum][8]
    void SetNodeForce( int nodeNum, double (*f)[8] );
    // 尽管下面两个函数暂时没有用处，但是为了方便定义可变数组类对象还是定义了这两个函数
    void Serialize(bofstream & fout);
    void Serialize(bifstream & fin);
};


DShellLoad的实现

DShellLoad::DShellLoad()
{
    nID = 0;
    for( int i = 0; i < 4;i ++ ) {
        P[i] = Pd[i] = (float)0.0;
    }
    for( i = 0; i < 8; i ++ ) {
        S[i] = T[i] = Q[i] = B[i] = (float)0.0;
    }
    for( i = 0; i < 3; i ++ ) {
        C[i] = N[i] = dir[i] = (float)0.0;
    }
    G = (float)0.0;
    dir[2] = -1.0;
}
DShellLoad::DShellLoad(const DShellLoad & Copy)
{
    *this = Copy;
}
DShellLoad & DShellLoad::operator = (const DShellLoad & Copy)
{
    if( this != &Copy ) {
        nID = Copy.nID;
        for( int i = 0; i < 4;i ++ ) {
            P[i] = Copy.P[i];
            Pd[i] = Copy.Pd[i];
        }
        for( i = 0; i < 8; i ++ ) {
            S[i] = Copy.S[i];
            T[i] = Copy.T[i];
            Q[i] = Copy.Q[i];
            B[i] = Copy.B[i];
        }
        for( i = 0; i < 3; i ++ ) {
            C[i] = Copy.C[i];
            N[i] = Copy.N[i];
            dir[i] = Copy.dir[i];
        }
        G = Copy.G;
    }
    return *this;
}
int DShellLoad::operator ==(const DShellLoad & Other)
{
    double tmp;
    for( int i = 0; i < 4; i ++ ) {
        tmp = P[i] - Other.P[i];
        if( tmp < -LoadError || tmp > LoadError ) return 0;
        tmp = Pd[i] - Other.Pd[i];
        if( tmp < -LoadError || tmp > LoadError ) return 0;
    }
    for( i = 0; i < 8; i ++ ) {
        tmp = S[i] - Other.S[i];
        if( tmp < -LoadError || tmp > LoadError ) return 0;
        tmp = T[i] - Other.T[i];
        if( tmp < -LoadError || tmp > LoadError ) return 0;
        tmp = Q[i] - Other.Q[i];
        if( tmp < -LoadError || tmp > LoadError ) return 0;
        tmp = B[i] - Other.B[i];
        if( tmp < -LoadError || tmp > LoadError ) return 0;
    }
    tmp = G - Other.G;
    if( tmp < -LoadError || tmp > LoadError ) return 0;
    for( i = 0; i < 3; i ++ ) {
        tmp = C[i] - Other.C[i];
        if( tmp < -LoadError || tmp > LoadError ) return 0;
        tmp = N[i] - Other.N[i];
        if( tmp < -LoadError || tmp > LoadError ) return 0;
        tmp = dir[i] - Other.dir[i];
        if( tmp < -LoadError || tmp > LoadError ) return 0;
    }
    return 1;
}

void DShellLoad::Serialize( bofstream & fout )
{
    fout << nID;
    fout.Write( P, sizeof(float)*4 );
    fout.Write( Pd, sizeof(float)*4 );
    fout.Write( dir, sizeof(float)*3 );
    fout.Write( S, sizeof(float)*8 );
    fout.Write( T, sizeof(float)*8 );
    fout.Write( Q, sizeof(float)*8 );
    fout.Write( B, sizeof(float)*8 );
    fout.Write( C, sizeof(float)*3 );
    fout.Write( N, sizeof(float)*3 );
    fout << G;
}
void DShellLoad::Serialize( bifstream & fin )
{
    fin >> nID;
    fin.Read( P, sizeof(float)*4 );
    fin.Read( Pd, sizeof(float)*4 );
    fin.Read( dir, sizeof(float)*3 );
    fin.Read( S, sizeof(float)*8 );
    fin.Read( T, sizeof(float)*8 );
    fin.Read( Q, sizeof(float)*8 );
    fin.Read( B, sizeof(float)*8 );
    fin.Read( C, sizeof(float)*3 );
    fin.Read( N, sizeof(float)*3 );
    fin >> G;
}


DshellLoad的声明

class CLASS_DECLSPEC DShellLoad {
public:
    int nID;
    // P和Pd顺序与SAP84的定义不一样,相当于把SAP84的P3 P4互换
    float P[4]; // 面分布荷载
    float Pd[4]; // 作用方向为任意方向的面分布荷载, 其方向余弦由dir[3]决定
    float dir[3];
    // 假设线分布荷载作用在所有的边上，如果相应的边没有荷载，用零表示，
    // 写sap84数据时，NSD1 NSD2 NSD3 NSD4 应分别为1 2 3 4
    float S[8], T[8];	// 边法向的分布膜荷载 和 切向的分布膜荷载
    float Q[8], B[8];	// 垂直的线分布荷载 和 法向的线分布弯矩
    float C[3], N[3], G;// 静水压：水面的一点、液面反方向中的一点和液体比重
public:
    DShellLoad();
    DShellLoad( const DShellLoad & Copy );
    DShellLoad & operator = ( const DShellLoad & Copy );
    int operator == ( const DShellLoad & Other );

    virtual void Serialize( bofstream & fout );
    virtual void Serialize( bifstream & fin );
};


DSol8rBase的实现

DSol8rBase::DSol8rBase()
{
    nID = 0;
    nLevel = 1;
    nLayer = 1;
    nType = 1;
    memset( node, 0, sizeof(node) );
    nMat = 0;
    T0 = (float)0.0;
    nAct = 1;
}
DSol8rBase::DSol8rBase(const DSol8rBase & Copy)
{
    *this = Copy;
}
DSol8rBase::~DSol8rBase()
{
}
DSol8rBase & DSol8rBase::operator = (const DSol8rBase & Copy)
{
    if( this != &Copy ) {
        nID = Copy.nID;
        nLevel = Copy.nLevel;
        nLayer = Copy.nLayer;
        nType = Copy.nType;
        memcpy( node, Copy.node, sizeof(int)*8 );
        nMat = Copy.nMat;
        T0 = Copy.T0;
        Load = Copy.Load;
        nAct = Copy.nAct;
    }
    return *this;
}
int DSol8rBase::operator ==( const DSol8rBase & Other)
{
    if( nType != Other.nType ) return 0;
    int num = 0;
    if( nType == 1 ) num = 8;
    else if( nType == 3 ) num = 6;
    return GFunc::IsEqual( node, Other.node, num );
}
void DSol8rBase::SetNodes( int nd[], int type )
{
    int num=0;
    nType = type;
    if( type == 1 ) num = 8;
    else if( type == 3 ) num = 6;
    memcpy( node, nd, sizeof(int)*num );
}
void DSol8rBase::Serialize( bofstream & fout )
{
    int num = 0;
    if( nType == 1 ) num = 8;
    else if( nType == 3 ) num = 6;
    fout << nID << nLevel << nLayer << nType;
    fout.Write( node, sizeof(int)*num );
    fout << nMat << T0;
    Load.Serialize(fout);
    fout << nAct;
}
void DSol8rBase::Serialize( bifstream & fin )
{
    fin >> nID >> nLevel >> nLayer >> nType;
    int num = 0;
    if( nType == 1 ) num = 8;
    else if( nType == 3 ) num = 6;
    fin.Read( node, sizeof(int)*num );
    if( num < 8 ) memset( &node[num], 0x00, sizeof(int)*(8-num) );
    fin >> nMat >> T0;
    Load.Serialize(fin);
    if( nVersion > 100 ) fin >> nAct;
}


DSol8rBase的声明

// 这里的数据结构支持带旋转自由度6节点的三棱柱非协调元

// 第一部分数据中的P=P1 P2 ...Pnl，在这里得不到支持，生成数据文件时只需要填写
// P=1 1 ... 1(NL个1)

// 这里不考虑应力输出位置的变化，在此我们假设输出所有可能点的应力,
// 输出数据文件时可以做如下处理：应力输出位置的组数NOPSET等于2
// 第一组：L=1 2 ... 15(包括一个单元形心和六个面的形心) 第二组：
// L= 1 2
...12(包括一个单元形心和5个面的形心) //在单元信息数据中六面体单元填O=1，三棱柱单元填O=2
class CLASS_DECLSPEC DSol8rBase {
public:
    int nID;		// 单元号，如果要用于array.h中的MArrayID类，其名称必须为nID
    short nLevel;   // 层标识号(指向DLevelBase的nID)，层号=nID-2
    short nLayer;	// (指向DLayerBase的nID)，与层号相互独立，缺省为1
    unsigned char nType;// 单元类型 1：六面体  3：三棱柱 (缺省=1)
    // 六面体:节点为node[0-7] 三棱柱:节点为node[0-5]
    // 保存时只保存可能有效的节点数8和6，不同的单元类型保存结构的大小也不同
    int node[8];	// 单元节点号
    short nMat;		// 材料号, 该号指向材料类的DMaterial的nID数据成员，不考虑各向异性
    float T0;		// 无应力状态参考温度

    // Load[i].LocalID指向类DSol8rLoad数组的nID
    DElementLoad  Load;//
    用于描述各总体荷载种类下作用的跨内荷载 short nAct; // 施工模拟的步号(one-based)
public:
    DSol8rBase();
    DSol8rBase( const DSol8rBase & Copy );
    virtual ~DSol8rBase();
    DSol8rBase & operator = ( const DSol8rBase & Copy );
    int operator == ( const DSol8rBase & Other );
    // index 从零开始零开始
    int & operator [] ( int index ){
        assert( index >= 0 && index < 8 );
        return node[index];
    }
    // nd的维数由type确定，如果type=1要求int nd[8]，如果type=3要求int nd[6]
    void SetNodes( int nd[], int type );
    // 函数自动设置nType参数
    void SetHexahedron( int nd[8] ) {
        SetNodes( nd, 1 );
    }
    void SetPrism( int nd[6] ) {
        SetNodes( nd, 3 );
    }

    int IsHexahedron() { return nType == 1; }
    int IsPrism() { return nType == 3; }

    virtual void Serialize( bofstream & fout );
    virtual void Serialize( bifstream & fin );
};


DSol8rLoad的声明

typedef DSol21Load DSol8rLoad;


DSol21Base的实现

DSol21Base::DSol21Base()
{
    nID = 0;
    nLevel = 1;
    nLayer = 1;
    nType = 1;
    ndNum = 0;
    memset( node, 0, sizeof(node) );
    nMat = 0;
    T0 = (float)0.0;
    nAct = 1;
}
DSol21Base::DSol21Base(const DSol21Base & Copy)
{
    *this = Copy;
}
DSol21Base & DSol21Base::operator = (const DSol21Base & Copy)
{
    if( this != &Copy ) {
        nID = Copy.nID;
        nLevel = Copy.nLevel;
        nLayer = Copy.nLayer;
        ndNum = Copy.ndNum;
        nType = Copy.nType;
        memcpy( node, Copy.node, sizeof(int)*ndNum );
        memset( &node[ndNum], 0, sizeof(int)*(21-ndNum) );
        nMat = Copy.nMat;
        T0 = Copy.T0;
        Load = Copy.Load;
        nAct = Copy.nAct;
    }
    return *this;
}
int DSol21Base::operator ==( const DSol21Base & Other)
{
    if( nType != Other.nType ) return 0;
    if( ndNum != Other.ndNum ) return 0;
    return GFunc::IsEqual( node, Other.node, ndNum );
}
void DSol21Base::SetNodes( const int nd[], const int num, const int type )
{
#ifdef _DEBUG
    if( type == 1 ) assert( num>=8 );
    else if( type == 2 ) assert( num>=4 );
    else if( type == 3 ) assert( num>=6 );
    else assert(3==2);
#endif
    ndNum = num;
    nType = type;
    memcpy( node, nd, sizeof(int)*num );
}
void DSol21Base::Serialize( bofstream & fout )
{
    fout << nID << nLevel << nLayer << nType << ndNum;
    fout.Write( node, sizeof(int)*ndNum );
    fout << nMat << T0;
    Load.Serialize(fout);
    fout << nAct;
}
void DSol21Base::Serialize( bifstream & fin )
{
    fin >> nID >> nLevel >> nLayer >> nType >> ndNum;
    fin.Read( node, sizeof(int)*ndNum );
    memset( &node[ndNum], 0x00, sizeof(int)*(21-ndNum) );
    fin >> nMat >> T0;
    Load.Serialize(fin);
    if( nVersion > 100 ) fin >> nAct;
}


DSol21Base的声明

// 第一部分数据中的P=P1 P2 ...Pnl，在这里得不到支持，生成数据文件时只需要填写
// P=1 1 ... 1(NL个1)

// 这里不考虑应力输出位置的变化，在此我们假设输出所有可能点的应力,
// 输出数据文件时可以做如下处理：应力输出位置的组数NOPSET等于3
// 第一组：L=1 2 ... 27 第二组：L=1 2 ...15 第三组：L=
1 2...21//在单元信息数据中六面体单元填O=1，四面体单元填O=2,三棱柱单元填O=3
class CLASS_DECLSPEC DSol21Base {
public:
    int nID;		// 单元号，如果要用于array.h中的MArrayID类，其名称必须为nID
        short nLevel;   // 层标识号(指向DLevelBase的nID)，层号=nID-2
    short nLayer;	// (指向DLayerBase的nID)，与层号相互独立，缺省为1
    unsigned char nType;// 单元类型 1：六面体  2：四面体 3：三棱柱 (缺省=1)
    // 六面体:节点个数为8－21,  四面体:节点个数为4-10 三棱柱:节点个数为6-15
    unsigned char ndNum;	// node数组中可能有效的节点数
        int node[21];	// 单元节点号，中间可能包含0
        short nMat;		// 材料号, 该号指向材料类的DMaterial的nID数据成员，不考虑各向异性
    float T0;		// 无应力状态参考温度
    // Load[i].LocalID指向类DSol21Load数组的nID
        DElementLoad  Load;//
    用于描述各总体荷载种类下作用的跨内荷载 short nAct; // 施工模拟的步号(one-based)
public:
    DSol21Base();
    DSol21Base( const DSol21Base & Copy );
    DSol21Base & operator = ( const DSol21Base & Copy );
    int operator == ( const DSol21Base & Other );
    // index 从零开始零开始
    int & operator [] ( int index ){
#ifdef _DEBUG
        assert( index >= 0 && index < 21 );
#endif
        return node[index];
    }
    // num为nd数组的个数，nd[]中可以有零元素,
    // 对六面体而言，前八个元素必须非零，四面体，则前四个要求非零
    // 三棱柱则要求前六个元素非零.
    void SetNodes( const int nd[], const int num, const int type );
    void SetHexahedron( const int nd[], const int num ) {
        SetNodes( nd, num, 1 );
    }
    void SetTetrahedron( const int nd[], const int num ) {
        SetNodes( nd, num, 2 );
    }
    void SetPrism( const int nd[] , const int num ) {
        SetNodes( nd, num, 3 );
    }

    int IsHexahedron() { return nType == 1; }
    int IsTetrahedron() { return nType == 2; }
    int IsPrism() { return nType == 3; }

    virtual void Serialize( bofstream & fout );
    virtual void Serialize( bifstream & fin );
};


DSol21Load的实现

DSol21Load::DSol21Load()
{
    nID = 0;
    for( int i = 0; i < 24; i ++ )
        P[i] = (float)0.0;
    for( i = 0; i < 6; i ++ ) {
        nWater[i] = 0;
    }
    G = (float)0.0;
    for( i = 0; i < 3; i ++ ) {
        C[i] = N[i] = (float)0.0;
    }
}
DSol21Load::DSol21Load(const DSol21Load & Copy)
{
    *this = Copy;
}
DSol21Load & DSol21Load::operator = (const DSol21Load & Copy)
{
    if( this != &Copy ) {
        nID = Copy.nID;
        for( int i = 0; i < 24; i ++ )
            P[i] = Copy.P[i];
        for( i = 0; i < 6; i ++ ) {
            nWater[i] = Copy.nWater[i];
        }
        G = Copy.G;
        for( i = 0; i < 3; i ++ ) {
            C[i] = Copy.C[i];
            N[i] = Copy.N[i];
        }
    }
    return *this;
}
int DSol21Load::operator ==(const DSol21Load & Other)
{
    double tmp;
    int i, HaveWater = 0;
    for( i = 0; i < 24; i ++ ) {
        tmp = P[i] - Other.P[i];
        if( tmp < -LoadError || tmp > LoadError ) return 0;
    }
    for( i = 0; i < 6; i ++ ) {
        if( nWater[i] != Other.nWater[i] ) return 0;
        if( nWater[i] != 0 ) HaveWater = 1;
    }
    if( HaveWater ) {
        tmp = G - Other.G;
        if( tmp < -LoadError || tmp > LoadError ) return 0;
        for( i = 0; i < 3; i ++ ) {
            tmp = C[i] - Other.C[i];
            if( tmp < -LoadError || tmp > LoadError ) return 0;
            tmp = N[i] - Other.N[i];
            if( tmp < -LoadError || tmp > LoadError ) return 0;
        }
    }
    return 1;
}
void DSol21Load::Serialize( bofstream & fout )
{
    fout << nID;
    fout.Write( P, sizeof(float)*24 );
    fout.Write( nWater, sizeof(unsigned char)*6 );
    fout << G;
    fout.Write( C, sizeof(float)*3 );
    fout.Write( N, sizeof(float)*3 );
}
void DSol21Load::Serialize( bifstream & fin )
{
    fin >> nID;
    fin.Read( P, sizeof(float)*24 );
    fin.Read( nWater, sizeof(unsigned char)*6 );
    fin >> G;
    fin.Read( C, sizeof(float)*3 );
    fin.Read( N, sizeof(float)*3 );
}


DSol21Load的声明

class CLASS_DECLSPEC DSol21Load {
    // 适合于sol21、sol8r和S16单元
public:
    int nID;				// 标识号
    float P[24];	// 各表面垂直压力荷载, 四个一组, 分别对应第1、2、3、4、5、6个表面
        // 四个角点上的压力值，对表面为三角形表面，每一组数中的第四个数无效
        // 六面体：24个数都有效    四面体：前16个数有效    三棱柱：前20个数有效
    unsigned char nWater[6];	// nWater[i]!=0表示第i+1个面作用有静水压，=0则表示这个面没有静水压
        // 有效的面号有   六面体：1-6    四面体：1-4     三棱柱：1-5
    float G,C[3],N[3];	// 静水压力的流体的比重
                // C[3];	流体自由表面一点的坐标
                // N[3];	另一点的坐标，CN指向流体深度增加的方向
public:
    DSol21Load();
    DSol21Load( const DSol21Load & Copy );
    DSol21Load & operator = ( const DSol21Load & Copy );
    int operator == ( const DSol21Load & Other );

    virtual void Serialize( bifstream & fin );
    virtual void Serialize( bofstream & fout );
};


DSpectrum的实现

DSpectrum::DSpectrum()
{
    nSeismicLevel = 0;
    nValid = 1;
    discount = (float)1.0;
    nQ = 0;
    Ck = Cm = (float)0.0;
}
DSpectrum::DSpectrum( const DSpectrum & Copy )
{
    *this = Copy;
}
DSpectrum & DSpectrum::operator =(const DSpectrum & Copy)
{
    if( this != &Copy ) {
        nSeismicLevel = Copy.nSeismicLevel;
        nValid = Copy.nValid;
        discount = Copy.discount;
        nQ = Copy.nQ;
        Ck = Copy.Ck;
        Cm = Copy.Cm;
        modeDamp = Copy.modeDamp;
    }
    return *this;
}
int DSpectrum::operator ==(const DSpectrum & Other) const
{
    float tmp;
    if( nSeismicLevel != Other.nSeismicLevel ) return 0;
    if( nValid != Other.nValid ) return 0;
    tmp = discount-Other.discount;
    if( tmp < -1.0E-3 || tmp > 1.0E-3 ) return 0;
    if( nQ != Other.nQ ) return 0;
    tmp = Ck-Other.Ck;
    if( tmp < -1.0E-3 || tmp > 1.0E-3 ) return 0;
    tmp = Cm-Other.Cm;
    if( tmp < -1.0E-3 || tmp > 1.0E-3 ) return 0;
    if( !(modeDamp == Other.modeDamp) ) return 0;
    return 1;
}
void DSpectrum::Serialize(bofstream & fout)
{
    fout << nSeismicLevel << nValid << discount << nQ << Ck << Cm;
    modeDamp.Serialize( fout );
}
void DSpectrum::Serialize(bifstream & fin)
{
    fin >> nSeismicLevel >> nValid;
    if( nVersion < 128 ) fin.Seek(sizeof(float)*4+sizeof(unsigned char)*2);
    fin >> discount;
    if( nVersion < 128 ) fin.Seek(sizeof(unsigned char));
    fin >> nQ >> Ck >> Cm;
    if( nVersion > 125 && nVersion < 128 ) fin.Seek(sizeof(float));
    modeDamp.Serialize( fin );
}


DSpectrumCurve的实现

DSpectrumCurve::DSpectrumCurve()
{
    nID = nNum = 0;
    nI = (float)7.0;
    nFreq = 1;
    A1530 = 0;
    Amax = (float)0.0;
    groundType = 2;
    nGroup = 1;
    Tg = (float)0.0;
    nS = 1;
    Beta = 2.0f;
    T = A = NULL;
}
DSpectrumCurve::~DSpectrumCurve()
{
    Clear();
}
DSpectrumCurve::DSpectrumCurve( const DSpectrumCurve & Copy )
{
    *this = Copy;
}
void DSpectrumCurve::Clear()
{
    if( T != NULL ) Free(T);
    if( A != NULL ) Free(A);
}
DSpectrumCurve & DSpectrumCurve::operator =(const DSpectrumCurve & Copy)
{
    if( this != &Copy ) {
        Clear();
        nID = Copy.nID;
        nI = Copy.nI;
        nFreq = Copy.nFreq;
        A1530 = Copy.A1530;
        Amax = Copy.Amax;
        groundType = Copy.groundType;
        nGroup = Copy.nGroup;
        Tg = Copy.Tg;
        nS = Copy.nS;
        Beta = Copy.Beta;
        nNum = Copy.nNum;
        if( nNum > 0 ) {
            T = (float*)malloc(sizeof(float)*nNum);
            A = (float*)malloc(sizeof(float)*nNum);
            memcpy( T, Copy.T, sizeof(float)*nNum );
            memcpy( A, Copy.A, sizeof(float)*nNum );
        }
    }
    return *this;
}
int DSpectrumCurve::operator ==(const DSpectrumCurve & Other) const
{
    double tmp;
    tmp = nI-Other.nI;
    if( tmp < -1.0E-3 || tmp > 1.0E-3 ) return 0;
    if( nFreq != Other.nFreq ) return 0;
    if( A1530 != Other.A1530 ) return 0;
    tmp = Amax-Other.Amax;
    if( tmp < -1.0E-3 || tmp > 1.0E-3 ) return 0;
    tmp = groundType-Other.groundType;
    if( tmp < -1.0E-3 || tmp > 1.0E-3 ) return 0;
    if( nGroup != Other.nGroup ) return 0;
    tmp = Tg-Other.Tg;
    if( tmp < -1.0E-3 || tmp > 1.0E-3 ) return 0;
    if( nS != Other.nS ) return 0;
    tmp = Beta-Other.Beta;
    if( tmp < -1.0E-3 || tmp > 1.0E-3 ) return 0;

    if( nNum != Other.nNum ) return 0;
    for( int i = 0; i < nNum; i ++ ) {
        tmp = T[i] - Other.T[i];
        if( tmp < - LoadError || tmp > LoadError ) return 0;
        tmp = A[i] - Other.A[i];
        if( tmp < - LoadError || tmp > LoadError ) return 0;
    }
    return 1;
}
void DSpectrumCurve::SetCurve(const int num,const float t[],const float a[])
{
    nNum = num;
    T = (float*)realloc( T, sizeof(float)*num );
    A = (float*)realloc( A, sizeof(float)*num );
    for( int i = 0; i < num; i ++ ) {
        T[i] = t[i];
        A[i] = a[i];
    }
}
void DSpectrumCurve::Serialize( bofstream & fout )
{
    fout << nID << nNum;
    fout << nI << nFreq << Amax << groundType << nGroup << Tg << nS << Beta << A1530;
    fout.Write( T, sizeof(float)*nNum );
    fout.Write( A, sizeof(float)*nNum );
}
void DSpectrumCurve::Serialize( bifstream & fin )
{
    fin >> nID >> nNum;
    if( nVersion >= 128 ) {
        fin >> nI >> nFreq >> Amax >> groundType >> nGroup >> Tg >> nS >> Beta;
        if( nVersion >128 ) fin >> A1530;
    }
    T = (float*)realloc( T, sizeof(float)*nNum );
    A = (float*)realloc( A, sizeof(float)*nNum );
    fin.Read( T, sizeof(float)*nNum );
    fin.Read( A, sizeof(float)*nNum );
}


DSpectrumCurve的声明

class CLASS_DECLSPEC DSpectrumCurve {
public:
    short nID;		// ID号，地震方向中的数据nCurve指向此ID
    unsigned char nS;		// 1：按土建规范    2：按水工规范  10:输入反应谱曲线 11:输入地基加速度曲线  [1]
    float nI;				// 设计烈度值[7]
    unsigned char nFreq;	// 地震发生频度，1：多遇地震  2: 罕遇地震 (水工规范无效)
    unsigned char A1530; // 设计基本地震加速度是否为0.15g和0.30g的地区
    float Amax;				// 水平地震影响系数最大值(或水平向设计地震加速度的代表值) [0]
                            //  (=0表示由nI或nFreq根据规范表格查询)
    float groundType;		// 场地类别 [2]  (水工规范无效)
    unsigned char nGroup;	// 设计地震分组	 [1]   (水工规范无效)
    float Tg;				// 特征周期 [0]	  (=0表示由groundType和nGroup根据规范表格查询,水工规范则必须输入)
    float Beta;				// 设计反应谱最大值的代表值   [2.0]  (只对水工规范有效)
    // 以下三个参数只对nS=10或11有效
    int nNum;		// 描述该反应谱曲线的点数，如果nNum==0时，T和A必须置NULL
    float *T;		// 反应谱曲线的横坐标周期 T[nNum]
    float *A;		// 与T对应的反应谱曲线的最大加速度值 A[nNum]
public:
    DSpectrumCurve();
    DSpectrumCurve( const DSpectrumCurve & Copy );
    virtual ~DSpectrumCurve();
    void Clear();
    DSpectrumCurve &  operator = ( const DSpectrumCurve & Copy );
    int operator == ( const DSpectrumCurve & Other );
    // 如果num==0,则T和A将自动清除
    void SetCurve( const int num, const float t[], const float a[] );

    virtual void Serialize( bofstream & fout );
    virtual void Serialize( bifstream & fin );
};


DSpectrumDir的实现

DSpectrumDir::DSpectrumDir()
{
    nCurve = 0;
    memset( Dir, 0x00, sizeof(Dir) );
    Dir[0] = 1.0;
}
DSpectrumDir::DSpectrumDir( short curveNo, float dir[3], float Zcoef )
{
    nCurve = curveNo;
    Dir[0] = dir[0];
    Dir[1] = dir[1];
    Dir[2] = dir[2];
    Dir[3] = Zcoef;
}
DSpectrumDir & DSpectrumDir::operator = ( const DSpectrumDir & Copy )
{
    if( this != &Copy ) {
        nCurve = Copy.nCurve;
        memcpy( Dir, Copy.Dir, sizeof(Dir) );
    }
    return (*this);
}
int DSpectrumDir::operator==( const DSpectrumDir & Other) const
{
    if( fabs(Dir[0]*Other.Dir[1]-Dir[1]*Other.Dir[0]) > 1.0E-3 ) return 0;
    if( fabs(Dir[0]*Other.Dir[2]-Dir[2]*Other.Dir[0]) > 1.0E-3 ) return 0;
    return 1;
}
int DSpectrumDir::IsZero()
{
    return (fabs(Dir[0])+fabs(Dir[1])+fabs(Dir[2]) < 1.0E-3 );
}
void DSpectrumDir::Serialize( bofstream & fout )
{
    fout << nCurve;
    fout.Write( Dir, sizeof(Dir) );
}

void DSpectrumDir::Serialize( bifstream & fin )
{
    fin >> nCurve;
    fin.Read( Dir, sizeof(Dir) );
}


DSpectrumDir的声明

class CLASS_DECLSPEC DSpectrumDir {
public:
    short nCurve;	// 反应谱曲线号(DSpectrumCurve中的nID)，必须大于0
    float Dir[4];	// 地震的三个方向余弦和铅直方向的地震折减系数
public:
    DSpectrumDir();
    DSpectrumDir( short curveNo, float dir[3], float Zcoef );
    DSpectrumDir( const DSpectrumDir & Copy ) {
        (*this) = Copy;
    }
    DSpectrumDir & operator = ( const DSpectrumDir & Copy );
    // 只要方向相等即可
    int operator==( const DSpectrumDir & Other) const;
    int IsZero();	// 根据方向判断是否为0

    void Serialize( bofstream & fout );
    void Serialize( bifstream & fin );
};


DSpectrum的声明

class CLASS_DECLSPEC DSpectrum {
public:
    // 有关地震的一些参数，墙单元总体信息和别的地方需要这些参数
    // 抗震等级：1、2、3、4, 0表示非抗震设计结构
    unsigned char nSeismicLevel;
    unsigned char nValid;	// 是否进行地震反应谱分析 [1]
                            // 不管nValid值如何，保存时保存所有的数据
    float discount;			// 周期折减系数 [1.0]
    unsigned char nQ;		// 计算方法的指标 [0]
                            //  0: 平方和开方(SRSS)；1：完全平方和(CQC)
    float Ck, Cm;			// Rayleigh阻尼
    DNumFactors modeDamp;	// 所采用的振型编号和对应的阻尼组成的数据对
public:
    DSpectrum();
    DSpectrum( const DSpectrum & Copy );
    DSpectrum & operator = ( const DSpectrum & Copy );
    int operator == ( const DSpectrum & Other );
    void SetValid() { nValid = 1; }
    void SetUnvalid() { nValid = 0; }
    int IsValid() { return nValid != 0; }

    virtual void Serialize( bofstream & fout );
    virtual void Serialize( bifstream & fin );
};


DSpringForce的定义

DSpringForce::DSpringForce()
{
    nID = 0;
    springForce = 0.0;
}
DSpringForce::DSpringForce( DSpringForce & Copy )
{
    *this = Copy;
}
DSpringForce & DSpringForce::operator = ( const DSpringForce & Copy )
{
    if( this != &Copy ) {
        nID = Copy.nID;
        springForce = Copy.springForce;
    }
    return *this;
}
void DSpringForce::Serialize(bofstream & fout)
{
    fout << nID << springForce;
}
void DSpringForce::Serialize(bifstream & fin)
{
    fin >> nID >> springForce;
}


DSpringForce的声明

class CLASS_DECLSPEC DSpringForce {
public:
    int nID;		// 弹簧单元号或组合号
    double springForce;	// 弹簧力
public:
    DSpringForce();
    DSpringForce( DSpringForce & Copy );
    DSpringForce & operator = ( const DSpringForce & Copy );
    // 尽管下面两个函数暂时没有用处，但是为了方便定义可变数组类对象还是定义了这两个函数
    void Serialize(bofstream & fout);
    void Serialize(bifstream & fin);
};


DThreedBase的实现

DThreedBase::DThreedBase()
{
    nID = 0;
    nLevel = 1;
    nLayer = 1;
    for( int i = 0; i < 8; i ++ )
        nNode[i] = 0;
    nMat = 0;
    T0 = (float)0;
    nAct = 1;
}
DThreedBase::DThreedBase(const DThreedBase & Copy)
{
    *this = Copy;
}
DThreedBase::~DThreedBase()
{
}
DThreedBase & DThreedBase::operator = (const DThreedBase & Copy)
{
    if( this != &Copy ) {
        nID = Copy.nID;
        nLevel = Copy.nLevel;
        nLayer = Copy.nLayer;
        for( int i = 0; i < 8; i ++ )
            nNode[i] = Copy.nNode[i];
        nMat = Copy.nMat;
        T0 = Copy.T0;
        Load = Copy.Load;
        nAct = Copy.nAct;
    }
    return *this;
}
int DThreedBase::operator ==( const DThreedBase & Other)
{
    return GFunc::IsEqual( nNode, Other.nNode, 8 );
}
void DThreedBase::SetNodes(int nd [8])
{
    for( int i = 0; i < 8; i ++ ) {
        nNode[i] = nd[i];
    }
}
void DThreedBase::Serialize( bofstream & fout )
{
    fout << nID << nLevel << nLayer;
    fout.Write( nNode, sizeof(int)*8 );
    fout << nMat << T0;
    Load.Serialize(fout);
    fout << nAct;
}
void DThreedBase::Serialize( bifstream & fin )
{
    fin >> nID >> nLevel >> nLayer;
    fin.Read( nNode, sizeof(int)*8 );
    fin >> nMat >> T0;
    Load.Serialize(fin);
    if( nVersion > 100 ) fin >> nAct;
}


DThreedBase的声明

class CLASS_DECLSPEC DThreedBase {
public:
    int nID;		// 单元号，如果要用于array.h中的MArrayID类，其名称必须为nID
    short nLevel;   // 层标识号(指向DLevelBase的nID)，层号=nID-2
    short nLayer;	// (指向DLayerBase的nID)，与层号相互独立，缺省为1
    int nNode[8];	// 单元节点号
    short nMat;		// 材料号, 该号指向材料类的DMaterial的nID数据成员
    // 高斯积分的阶数能放在总体信息内
    float T0;		// 无应力状态参考温度（目前sap84不支持）
    // Load[i].LocalID指向类DThreedLoad数组的nID
    DElementLoad  Load;//
    用于描述各总体荷载种类下作用的跨内荷载 short nAct; // 施工模拟的步号(one-based)
public:
    DThreedBase();
    DThreedBase( const DThreedBase & Copy );
    virtual ~DThreedBase();
    DThreedBase & operator = ( const DThreedBase & Copy );
    int operator == ( const DThreedBase & Other );
    // index 从零开始
    int & operator[] ( int index ) {
        assert( index >= 0 && index < 8 );
        return nNode[index];
    }
    void SetNodes( int nd[8] );

    virtual void Serialize( bofstream & fout );
    virtual void Serialize( bifstream & fin );
};


DThreedLoad的声明

typedef DSol21Load DThreedLoad; // 与SAP84中的定义不太一致


DTightWire的定义

DTightWire::DTightWire()
{
    nID = 0;
    Disti = Distc = Distj = T = L = 0.0;
}
DTightWire::DTightWire( const DTightWire & Copy )
{
    *this = Copy;
}
DTightWire & DTightWire::operator = ( const DTightWire & Copy )
{
    if( this != &Copy ) {
        nID = Copy.nID;
        Disti = Copy.Disti;
        Distc = Copy.Distc;
        Distj = Copy.Distj;
        T = Copy.T;
        L = Copy.L;
    }
    return *this;
}
int DTightWire::operator == ( const DTightWire & Other )
{
    double tmp;
    tmp = Disti - Other.Disti;
    if( tmp < -NodeMinDist || tmp > NodeMinDist ) return 0;
    tmp = Distc - Other.Distc;
    if( tmp < -NodeMinDist || tmp > NodeMinDist ) return 0;
    tmp = Distj - Other.Distj;
    if( tmp < -NodeMinDist || tmp > NodeMinDist ) return 0;
    tmp = T - Other.T;
    if( tmp < -LoadError || tmp > LoadError ) return 0;
    tmp = L - Other.L;
    if( tmp < -NodeMinDist || tmp > NodeMinDist ) return 0;
    return 1;
}

void DTightWire::Serialize( bifstream & fin )
{
    fin >> nID >> Disti >> Distc >> Distj >> T >> L;
}
void DTightWire::Serialize( bofstream & fout )
{
    fout << nID << Disti << Distc << Distj << T << L;
}


DTightWire的声明

// 定义预应力钢索的参数
class CLASS_DECLSPEC DTightWire {
public:
    int nID;	// 钢索号，最后，所有钢索的nID必须从1开始连续，不能间断
    float Disti, Distc, Distj;	// 钢索I端悬距，钢索在中点的悬距，钢索J端的悬距，沿着2方向为正
    float T;	// 预应力拉力值
    float L;	// 钢索的投影长度
public:
    DTightWire();
    DTightWire( const DTightWire & Copy );
    virtual ~DTightWire() {}
    DTightWire & operator = ( const DTightWire & Copy );
    int operator == ( const DTightWire & Other );

    virtual void Serialize( bifstream & fin );
    virtual void Serialize( bofstream & fout );
};


TightWireIndex的定义

DTightWireIndex::DTightWireIndex()
{
    nNum = 0;
    Wires = NULL;
}
DTightWireIndex::~DTightWireIndex()
{
    Clear();
}
DTightWireIndex & DTightWireIndex::operator = ( const DTightWireIndex & Copy )
{
    if( this != &Copy ) {
        Clear();
        nNum = Copy.nNum;
        if( nNum > 0 ) {
            int size = sizeof(struct TightWirePara)*nNum;
            Wires = (struct TightWirePara*)malloc( size );
            memcpy( Wires, Copy.Wires, size );
        }
    }
    return *this;
}
int DTightWireIndex::operator == ( const DTightWireIndex & Other )
{
    double tmp;
    if( nNum != Other.nNum ) return 0;
    for( int i = 0; i < nNum; i ++ ) {
        if( Wires[i].nNo != Other.Wires[i].nNo ) return 0;
        tmp = Wires[i].Pi - Other.Wires[i].Pi;
        if( tmp < -NodeMinDist || tmp > NodeMinDist ) return 0;
        tmp = Wires[i].Pj - Other.Wires[i].Pj;
        if( tmp < -NodeMinDist || tmp > NodeMinDist ) return 0;
    }
    return 1;
}
void DTightWireIndex::Add( int no, float pi, float pj )
{
    Wires = (struct TightWirePara*)realloc( Wires, sizeof(struct TightWirePara)*(nNum+1) );
    Wires[nNum].nNo = no;
    Wires[nNum].Pi = pi;
    Wires[nNum].Pj = pj;
    nNum++;
}
void DTightWireIndex::Clear()
{
    nNum = 0;
    if( Wires != NULL ) Free(Wires);
}
void DTightWireIndex::Serialize( bofstream & fout )
{
    fout << nNum;
    if( nNum > 0 )
        fout.Write( Wires, sizeof(struct TightWirePara)*nNum );
}
void DTightWireIndex::Serialize( bifstream & fin )
{
    Clear();
    fin >> nNum;
    if( nNum > 0 ) {
        int size = sizeof(struct TightWirePara)*nNum;
        Wires = (struct TightWirePara*)realloc( Wires, size );
        fin.Read( Wires, size );
    }
}


DTightWireIndex的声明

// 框架单元中的预应力钢索号和作用情况
class CLASS_DECLSPEC DTightWireIndex {
public:
    short nNum;		// 数组Wires的个数
    struct TightWirePara {
        int nNo;	// 钢索号, 指向类DTightWire数组元素的nID, 数组Wires中不允许出现钢索号相重
        float Pi, Pj;	// 单元I端距离钢索I端的距离, 单元J端距离钢索I端的距离
    } *Wires;
public:
    DTightWireIndex();
    ~DTightWireIndex();
    DTightWireIndex & operator = ( const DTightWireIndex & Copy );
    int operator == ( const DTightWireIndex & Other );
    void Add( int no, float pi, float pj );	// no:钢索号, 不考虑是否相重
    void Clear();	// 清除所有预应力钢索

    void Serialize( bofstream & fout );
    void Serialize( bifstream & fin );
};


DTrussBase的实现

DTrussBase::DTrussBase( )
{
nID = 0;
nLevel = 1;
nLayer = 1;
nI = nJ = 0;
nSect = nMat = 0;
T = (float)0.0;
nAct = 1;
}
DTrussBase::DTrussBase( int i, int j )
{
nID = 0;
nLevel = 1;
nLayer = 1;
nI = i;
nJ = j;
nSect = nMat = 0;
T = (float)0.0;
nAct = 1;
}
DTrussBase::DTrussBase( const DTrussBase & Copy)
{
*this = Copy;
}
DTrussBase & DTrussBase::operator = ( const DTrussBase & Copy )
{
if( this != &Copy ) {
nID = Copy.nID;
nLevel = Copy.nLevel;
nLayer = Copy.nLayer;
nI = Copy.nI;
nJ = Copy.nJ;
nSect = Copy.nSect;
nMat = Copy.nMat;
T = Copy.T;
nAct = Copy.nAct;
}
return *this;
}
int DTrussBase::operator == ( const DTrussBase & Other )
{
return ((nI==Other.nI)&&(nJ==Other.nJ) ||
       (nI==Other.nJ)&&(nJ==Other.nI));
}
void DTrussBase::Serialize( bofstream & fout
       )
{
fout << nID << nLevel << nLayer
       << nI << nJ << nSect << nMat << T;
fout << nAct;
}
void DTrussBase::Serialize( bifstream & fin )
{
fin >> nID >> nLevel >> nLayer
       >> nI >> nJ >> nSect >> nMat >> T;
if( nVersion > 100 ) fin >> nAct;
}


DTrussBase的声明

class CLASS_DECLSPEC DTrussBase {
public:
int nID; // 单元号，如果要用于sap84.h中的MArrayID类，其名称必须为nID
short nLevel; // 层标识号(指向DLevelBase的nID)，层号=nID-2
short nLayer; // (指向DLayerBase的nID)，与层号相互独立，缺省为1
int nI,nJ; // node I, node J.
// 分别指向类DTrussSect(即DFrameSect)、DMaterial数组的nID
short nSect,nMat;// 截面号和材料号, 该号指向截面或材料类的nID数据成员
 float T; // 轴向温度
// 温度荷载所在的荷载种类号由总体荷载分布信息(DCommonData)决定
short nAct; // 施工模拟的步号(one-based)
public:
DTrussBase( );
DTrussBase( int i, int j );
DTrussBase( const DTrussBase & Copy);
DTrussBase & operator = ( const DTrussBase & Copy );
int operator == ( const DTrussBase & Other );
virtual void Serialize( bifstream & fin );
virtual void Serialize( bofstream & fout );
};


DTrussForce的实现

DTrussForce::DTrussForce()
{
    nID = 0;
    Axis = 0.0;
}
DTrussForce::DTrussForce( DTrussForce & Copy )
{
    *this = Copy;
}
DTrussForce & DTrussForce::operator = ( const DTrussForce & Copy )
{
    if( this != &Copy ) {
        nID = Copy.nID;
        Axis = Copy.Axis;
    }
    return *this;
}
void DTrussForce::Serialize(bofstream & fout)
{
    fout << nID << Axis;
}
void DTrussForce::Serialize(bifstream & fin)
{
    fin >> nID >> Axis;
}


DTrussForce的声明

class CLASS_DECLSPEC DTrussForce {
public:
    int nID;		// 单元号或组合号
    double Axis;  // 轴力
public:
    DTrussForce();
    DTrussForce( DTrussForce & Copy );
    virtual ~DTrussForce() {}
    DTrussForce & operator = ( const DTrussForce & Copy );
    // 尽管下面两个函数暂时没有用处，但是为了方便定义可变数组类对象还是定义了这两个函数
    void Serialize(bofstream & fout);
    void Serialize(bifstream & fin);
};


DTrussSect的声明

typedef DFrameSect DTrussSect;


DVframeBase的声明

#define DVframeBase DFrameBase


DVframeForce的声明

typedef DFrameForce DVframeForce;


DVframeLoad的声明

typedef DFrameLoad DVframeLoad;


DVframeSect的实现

DVframeSect::DVframeSect( )
{
    nID = 0;
    nType = 0;
    memset( BI, 0x00, sizeof(BI) );
    memset( BJ, 0x00, sizeof(BJ) );
    name = new char[10];
    strcpy( name, "vsection" );
}
DVframeSect::~DVframeSect()
{
    if( name ) delete[] name;
}
DVframeSect::DVframeSect( DVframeSect & Copy )
{
    name = NULL;
    *this = Copy;
}
DVframeSect & DVframeSect::operator = ( const DVframeSect & Copy )
{
    if( this != &Copy ) {
        nID = Copy.nID;
        nType = Copy.nType;
        memcpy( BI, Copy.BI, sizeof(BI) );
        memcpy( BJ, Copy.BJ, sizeof(BJ) );
        SetName( Copy.name );
    }
    return *this;
}
void DVframeSect::SetName( const char * nameStr )
{
    int len = strlen(nameStr)+1;
    if( name ) delete[] name;
    name = new char[len];
    strcpy( name, nameStr );
}
double DVframeSect::GetSectArea()
{
    if( nType == 1 ) {
        return (BI[0]*BI[1]+BJ[0]*BJ[1])/2.0;
    }
    else if( nType == 2 ) {
        return (BI[0]*BI[3]+BI[1]*BI[4]+BI[2]*BI[5]+BJ[0]*BJ[3]+BJ[1]*BJ[4]+BJ[2]*BJ[5])/2.0;
    }
    else if( nType == 3 || nType == 4 ) {
        return (BI[0]*BI[2]+BI[1]*BI[3]+BJ[0]*BJ[2]+BJ[1]*BJ[3])/2.0;
    }
    else if( nType == 7 ) {
        return PI*(BI[1]*BI[1]-BI[0]*BI[0]+BJ[1]*BJ[1]-BJ[0]*BJ[0])/2.0;
    }
    else return 0.0;
}
int DVframeSect::operator == ( const DVframeSect & Other )
{
    return (strcmp( name, Other.name)==0);
}
int DVframeSect::GetParaNum( int type )
{
    if( type == 1 || type == 7 ) return 2;
    else if( type == 2 ) return 6;
    else if( type == 3 || type == 4 /*|| type == 6 || type == 9 || type == 10*/ )
        return 4;
    //else if( type == 5 || type == 8 ) return 3;
    return 0;
}
void DVframeSect::Serialize( bofstream & fout )
{
    int len = strlen( name )+1;
    fout << nID << nType;
    fout.Write( &len, sizeof(int) );
    fout.Write( name, len );
    fout.Write( BI, sizeof(BI) );
    fout.Write( BJ, sizeof(BJ) );
}

void DVframeSect::Serialize( bifstream & fin )
{
    int len;
    fin >> nID >> nType;
    fin.Read( &len, sizeof(int) );
    delete[] name;
    name = new char[len];
    fin.Read( name, len );
    fin.Read( BI, sizeof(BI) );
    fin.Read( BJ, sizeof(BJ) );
}


DVframeSect的声明

// 材料的几何属性。
// 此类适合于VFRAME单元
    ////////////////////////////////////////////////////////////////////////
    // 其截面类型的定义类似于FRAME单元，只是目前只支持1,2,3,4,7号截面
    // BI[6], BJ[6]的参数说明完全类似于FRAME中的B的说明
    //	截面类型	1:	变截面梁单元中的矩形截面
    //	 (nType)	2:	变截面梁单元中的工字形截面
    //				3:	变截面梁单元中的梯形截面
    //				4:	变截面梁单元中的倒梯形截面
    //				7:	变截面梁单元中的圆形截面(厚度B[2]无效,该种截面只有B[0]和B[1])
    //		缺省值为0，即截面属性无效
    ////////////////////////////////////////////////////////////////////////
class CLASS_DECLSPEC DVframeSect {
public:
    short nID;
    // 截面类型nType =1,2,3,4,7
    unsigned char nType;
    char *name;	// 保存时先保存字符长度(含c语言的结束符), 再保存字符串(含结束符)
    float BI[6];		//	I端截面的参数（具体可以参考SAP84中FRAME单元的十种断面的B说明）
    float BJ[6];		//	J端截面的参数（具体可以参考SAP84中FRAME单元的十种断面的B说明）
public:
    DVframeSect( );
    ~DVframeSect( );
    DVframeSect( DVframeSect & Copy );
    DVframeSect & operator = ( const DVframeSect & Copy );
    // 通过名称确定是否相等
    int operator == ( const DVframeSect & Other );
    // 设置截面标识名称
    void SetName( const char * nameStr );
    double GetSectArea(); // 返回截面的平均面积

    virtual void Serialize( bofstream & fout );
    virtual void Serialize( bifstream & fin );
public:
    // 返回三种端面类型需要的参数个数
    static int GetParaNum( int type );
};


DWallBase的实现

DWallBase::DWallBase()
{
    nID = 0;
    nLevel = 1;
    nLayer = 1;
    nType = nIP = 0;
    nHole = 1;
    for( int i = 0; i < 4; i ++ ) {
        B[i] = (float)0.0;
        nNode[i] = 0;
    }
    nMat = 0;
    HFilm = HSlab = (float)0.0;
    T0 = Eccent = (float)0.0;
    nEnhance = 0;
    nAct = 1;
}
DWallBase::DWallBase(const DWallBase & Copy)
{
    *this = Copy;
}
DWallBase::~DWallBase()
{
}
DWallBase & DWallBase::operator = (const DWallBase & Copy)
{
    if( this != &Copy ) {
        nID = Copy.nID;
        nLevel = Copy.nLevel;
        nLayer = Copy.nLayer;
        nType = Copy.nType;
        nIP = Copy.nIP;
        nHole = Copy.nHole;
        for( int i = 0; i < 4; i ++ ) {
            B[i] = Copy.B[i];
            nNode[i] = Copy.nNode[i];
        }
        nMat = Copy.nMat;
        HFilm = Copy.HFilm;
        HSlab = Copy.HSlab;
        T0 = Copy.T0;
        Eccent = Copy.Eccent;
        nEnhance = Copy.nEnhance;
        Load = Copy.Load;
        nAct = Copy.nAct;
    }
    return *this;
}
int DWallBase::operator ==( const DWallBase & Other)
{
    if( nType != Other.nType ) return 0;
    return GFunc::IsEqual( nNode, Other.nNode, 4 );
}
void DWallBase::SetNodes( int nd[4], int distype )
{
    for( int i = 0; i < 4; i ++ ) {
        nNode[i] = nd[i];
    }
    nType = distype;
}
void DWallBase::SetShellWall(int nd[4], double h1, double h2 )
{
    SetNodes( nd, 0 );
    HFilm = (float)h1;
    if( h2 > SectionError ) HSlab = (float)h2;
    else HSlab = HFilm;
}
void DWallBase::SetFilmWall(int nd[4], double h )
{
    SetNodes( nd, 1 );
    HFilm = (float)h;
    HSlab = 0.0;
}
void DWallBase::SetSlabWall(int nd[4], double h )
{
    SetNodes( nd, 2 );
    HFilm = 0.0;
    HSlab = (float)h;
}
void DWallBase::SetThick( double h1, double h2 )
{
    if( nType == 0 ) {
        HFilm = (float)h1;
        if( h2 > SectionError ) HSlab = (float)h2;
        else HSlab = HFilm;
    }
    else if( nType == 1 ) {
        HFilm = (float)h1;
        HSlab = 0.0;
    }
    else if( nType == 2 ) {
        HFilm = 0.0;
        HSlab = (float)h1;
    }
}
void DWallBase::SetHole(double b[4])
{
    nHole = 1;
    for( int i = 0; i < 4; i ++ ) {
        if( b[i] > SectionError ) nHole = 2;
        B[i] = (float)b[i];
    }
}
void DWallBase::Serialize( bofstream & fout )
{
    fout << nID << nLevel << nLayer << nType << nIP << nHole;
    fout.Write( B, sizeof(float)*4 );
    fout.Write( nNode, sizeof(int)*4 );
    fout << nMat << HFilm << HSlab <<  T0 << Eccent << nEnhance;
    Load.Serialize(fout);
    fout << nAct;
}
void DWallBase::Serialize( bifstream & fin )
{
    fin >> nID >> nLevel >> nLayer >> nType >> nIP >> nHole;
    fin.Read( B, sizeof(float)*4 );
    fin.Read( nNode, sizeof(int)*4 );
    fin >> nMat >> HFilm >> HSlab >>  T0 >> Eccent >> nEnhance;
    Load.Serialize(fin);
    if( nVersion > 100 ) fin >> nAct;
}


DWallBase的声明

// 墙单元的输出：0 只输出整体的内力和配筋  1：还输出四个小部分的内力和配筋
// 上述信息在DCommonData类中
// 结构是否配筋的信息存放在DReinforce类中
// 结构抗震等级、是否高层建筑信息在存放在DSpectrum类中
class CLASS_DECLSPEC DWallBase {
public:
    int nID;		// 单元号，如果要用于array.h中的MArrayID类，其名称必须为nID
    short nLevel;   // 层标识号(指向DLevelBase的nID)，层号=nID-2
    short nLayer;	// (指向DLayerBase的nID)，与层号相互独立，缺省为1
    unsigned char nType;// 单元类型  0：壳变形  1：膜变形 2：板变形(缺省为0)
    unsigned char nIP;	// 板变形是否为杂交元 1：杂交元 0：非杂交元
    unsigned char nHole;// 单元类型  1：第一类墙单元(无开洞)  2：第二类墙单元(有开洞) 缺省为1
    float B[4];			// nHole=2时第二类墙单元的墙洞尺寸
    // 顺序与SAP84的定义不一样,Q1 Q2 Q4 Q3,相当于把SAP84的Q3 Q4互换
    int nNode[4];	// 单元节点号
    short nMat;		// 材料号, 该号指向材料类的DMaterial的nID数据成员
    float HFilm,HSlab;	// 膜厚度和板厚度两者的平均值决定了单元的质量
    float T0;		// 无应力状态参考温度 即Z=Z1
    float Eccent;	// 单元偏心距离
    unsigned char nEnhance;	// 是否为加强部位  0：非加强部位
                            //				   1：一般加强部位
                            //				   2：底部加强部位

    // Load[i].LocalID指向类DWallLoad数组的nID
    DElementLoad  Load;//
    用于描述各总体荷载种类下作用的跨内荷载 short nAct; // 施工模拟的步号(one-based)
public:
    DWallBase();
    DWallBase( const DWallBase & Copy );
    virtual ~DWallBase();
    DWallBase & operator = ( const DWallBase & Copy );
    // 不仅比较节点，而且比较变形类型
    int operator == ( const DWallBase & Other );
    // index 从零开始零开始
    int & operator [] ( int index ) {
        assert( index >= 0 && index < 4 );
        return nNode[index];
    }
    // 墙单元的变形模式一般都是壳模式，即无需输入distype参数
    void SetNodes( int nd[4], int distype = 0 );
    void SetShellWall( int nd[4], double h1 = 0.0, double h2 = 0.0 );
    void SetFilmWall( int nd[4], double h = 0.0 );
    void SetSlabWall( int nd[4], double h = 0.0 );
    // 如果变形模式是壳变形，h1:膜的厚度 h2:板的厚度，若只填h1，则板的厚度也取h1
    // 如果变形模式为膜变形，h1:膜的厚度 h2:无意义
    // 如果变形模式为板变形，h1:板的厚度 h2:无意义
    void SetThick( double h1, double h2 = 0.0 );
    // 如果尺寸b[]有非零值，将设置nHole = 2，
    // 否则设置nHole = 1
    void SetHole( double b[4] );
    int IsShellWall() { return nType == 0; }
    int IsFilmWall() { return nType == 1; }
    int IsSlabWall() { return nType == 2; }

    virtual void Serialize( bofstream & fout );
    virtual void Serialize( bifstream & fin );
};


DWallForce的定义

DWallForce::DWallForce()
{
    nID = 0;
    nHole = 0;
    nType = 0;
    wholeF = reg1F = reg2F = reg3F = reg4F = NULL;
}
DWallForce::DWallForce( DWallForce & Copy )
{
    wholeF = reg1F = reg2F = reg3F = reg4F = NULL;
    *this = Copy;
}
DWallForce::~DWallForce()
{
    ClearMemory();
}
void DWallForce::ClearMemory()
{
    if( wholeF ) delete wholeF;
    if( reg1F ) delete reg1F;
    if( reg2F ) delete reg2F;
    if( reg3F ) delete reg3F;
    if( reg4F ) delete reg4F;
    wholeF = reg1F = reg2F = reg3F = reg4F = NULL;
}
int DWallForce::IsValid()
{
    if( nID < 1 ) return 0;
    if( nType < 0 || nType > 2 ) return 0;
    if( nHole == 0 || nHole == 2 )
        return (wholeF && !reg1F && !reg2F && !reg3F && !reg4F);
    else if( nHole == 1 )
        return (!wholeF && reg1F && reg2F && reg3F && !reg4F);
    else if( nHole == 3 )
        return (wholeF && reg1F && reg2F && reg3F && reg4F);
    return 0;
}
DWallForce & DWallForce::operator = ( const DWallForce & Copy )
{
    if( this != &Copy ) {
        ClearMemory();
        nID = Copy.nID;
        nHole = Copy.nHole;
        nType = Copy.nType;
        if( Copy.wholeF ) {
            wholeF = new DWallForceElement;
            memcpy( wholeF, Copy.wholeF, sizeof(DWallForceElement) );
        }
        if( Copy.reg1F ) {
            reg1F = new DWallForceElement;
            memcpy( reg1F, Copy.reg1F, sizeof(DWallForceElement) );
        }
        if( Copy.reg2F ) {
            reg2F = new DWallForceElement;
            memcpy( reg2F, Copy.reg2F, sizeof(DWallForceElement) );
        }
        if( Copy.reg3F ) {
            reg3F = new DWallForceElement;
            memcpy( reg3F, Copy.reg3F, sizeof(DWallForceElement) );
        }
        if( Copy.reg4F ) {
            reg4F = new DWallForceElement;
            memcpy( reg4F, Copy.reg4F, sizeof(DWallForceElement) );
        }
    }
    return *this;
}
void DWallForce::AllocAndZeroMemoryAccordnHole()
{
    ClearMemory();
    if( nHole == 0 || nHole == 2 ) {
        wholeF = new DWallForceElement;
    }
    else if( nHole == 1 ) {
        reg1F = new DWallForceElement;
        reg2F = new DWallForceElement;
        reg3F = new DWallForceElement;
    }
    else if( nHole == 3 ) {
        wholeF = new DWallForceElement;
        reg1F = new DWallForceElement;
        reg2F = new DWallForceElement;
        reg3F = new DWallForceElement;
        reg4F = new DWallForceElement;
    }
    if( wholeF ) memset( wholeF, 0x00, sizeof(DWallForceElement) );
    if( reg1F ) memset( reg1F, 0x00, sizeof(DWallForceElement) );
    if( reg2F ) memset( reg2F, 0x00, sizeof(DWallForceElement) );
    if( reg3F ) memset( reg3F, 0x00, sizeof(DWallForceElement) );
    if( reg4F ) memset( reg4F, 0x00, sizeof(DWallForceElement) );
}
void DWallForce::Serialize(bofstream & fout)
{
    if( !IsValid() ) nHole = -1;
    fout << nID << nHole << nType;
    if( nHole != -1 ) {
        if( wholeF ) fout.Write( wholeF, sizeof(DWallForceElement) );
        if( reg1F ) fout.Write( reg1F, sizeof(DWallForceElement) );
        if( reg2F ) fout.Write( reg2F, sizeof(DWallForceElement) );
        if( reg3F ) fout.Write( reg3F, sizeof(DWallForceElement) );
        if( reg4F ) fout.Write( reg4F, sizeof(DWallForceElement) );
    }
}
void DWallForce::Serialize(bifstream & fin)
{
    fin >> nID >> nHole >> nType;
    AllocAndZeroMemoryAccordnHole();
    if( wholeF ) fin.Read( wholeF, sizeof(DWallForceElement) );
    if( reg1F ) fin.Read( reg1F, sizeof(DWallForceElement) );
    if( reg2F ) fin.Read( reg2F, sizeof(DWallForceElement) );
    if( reg3F ) fin.Read( reg3F, sizeof(DWallForceElement) );
    if( reg4F ) fin.Read( reg4F, sizeof(DWallForceElement) );
}


DWallForce的声明

// 定义墙单元整体或各子区域在1号和3号边的内力，边号定义和
// 子区域的划分可以参考SAP84分析程序帮助文档
struct CLASS_DECLSPEC DWallForceElement {
    // 1号边的面内内力:N22、Q11和M33
    double InF1[3];
    // 3号边的面内内力:N22、Q11和M33
    double InF3[3];
    // 1号边的面外内力:M11、M12和Q33
    double OutF1[3];
    // 3号边的面外内力:M11、M12和Q33
    double OutF3[3];
};

class CLASS_DECLSPEC DWallForce {
public:
    // 单元号或组合号
    int nID;
    // nHole: 0 <==> 没有开洞：reg1F=reg2F=reg3F=reg4F=NULL
    //		  1 <==> 开门洞：wholeF=reg4F=NULL
    //		  2 <==> 开窗洞，但不要求输出各子区域的内力：reg1F=reg2F=reg3F=reg4F=NULL
    //		  3 <==> 开窗洞，要求输出各子区域的内力
    //		 -1  数据无效
    unsigned char nHole;
    // nType:变形模式, 0面内面外都有内力，1只有面内内力  2只有面外内力
    unsigned char nType;
    union {
        // wholeF存储墙单元的整体内力（门洞情况下等于NULL）
        // reg1-4F存储各子区域的内力(不开洞时全等于NULL，开门洞情况下reg4F等于NULL)
        // 开窗洞但不要求输出详细内力时，四个变量全等于NULL
        struct {
            DWallForceElement *wholeF, *reg1F, *reg2F, *reg3F, *reg4F;
        };
        DWallForceElement *ARRAYF[5];
    };
public:
    DWallForce();
    DWallForce( DWallForce & Copy );
    virtual ~DWallForce();
    void ClearMemory();
    // 根据nHole的值分配内存，并初始化为0
    void AllocAndZeroMemoryAccordnHole();
    // 判断数据之间是否有矛盾，主要根据nHole判断各种内力指针是否设置正确
    int IsValid();
    DWallForce & operator = ( const DWallForce & Copy );
    // 尽管下面两个函数暂时没有用处，但是为了方便定义可变数组类对象还是定义了这两个函数
    void Serialize(bofstream & fout);
    void Serialize(bifstream & fin);
};


DWallLoad的实现

DWallLoad::DWallLoad()
{
    nID = 0;
    P = (float)0.0;
    memset( S, 0x00, sizeof(S) );
}
DWallLoad::DWallLoad(const DWallLoad & Copy)
{
    *this = Copy;
}
DWallLoad & DWallLoad::operator = (const DWallLoad & Copy)
{
    if( this != &Copy ) {
        nID = Copy.nID;
        P = Copy.P;
        memcpy( S, Copy.S, sizeof(S) )
    }
    return *this;
}
int DWallLoad::operator ==(const DWallLoad & Other)
{
    double tmp;
    tmp = P - Other.P;
    if( tmp < -LoadError || tmp > LoadError ) return 0;
    for( int i = 0; i < 6; i ++ ) {
        tmp = S[i] - Other.S[i];
        if( tmp < -LoadError || tmp > LoadError ) return 0;
    }
    return 1;
}
void DWallLoad::SetSideLoad( int sideno, double s[2] )
{
    if( sideno < 2 || sideno > 4 ) return;
    sideno -= 2;
    S[sideno*2] = (float)s[0];
    S[sideno*2+1] = (float)s[1];
}

void DWallLoad::Serialize( bofstream & fout )
{
    fout << nID << P;
    fout.Write( S, sizeof(S) );
}
void DWallLoad::Serialize( bifstream & fin )
{
    fin >> nID >> P;
    fin.Read( S, sizeof(S) );
}


DWallLoad的声明

class CLASS_DECLSPEC DWallLoad {
public:
    int nID;
    float P;	// 侧向均匀分布荷载, 与nNode[0] nNode[1] nNode[2] nNode[3]形成的右手螺旋方向相反
    float S[6];	// 面内分布荷载在边2、3和4号边上的值
public:
    DWallLoad();
    DWallLoad( const DWallLoad & Copy );
    DWallLoad & operator = ( const DWallLoad & Copy );
    int operator == ( const DWallLoad & Other );
    void SetSideLoad( int sideno, double s[2] );

    virtual void Serialize( bifstream & fin );
    virtual void Serialize( bofstream & fout );
};


DWeightFactor的实现

DWeightFactor::DWeightFactor()
{
    nNum = 0;
    wf = NULL;
}
DWeightFactor::~DWeightFactor()
{
    Clear();
}
DWeightFactor & DWeightFactor::operator = ( const DWeightFactor & Copy )
{
    if( this != &Copy ) {
        Clear();
        nNum = Copy.nNum;
        if( nNum > 0 ) {
            wf = (DWeightFactorItem*)malloc( sizeof(DWeightFactorItem)*nNum );
            memcpy( wf, Copy.wf, sizeof(DWeightFactorItem)*nNum );
        }
    }
    return (*this);
}
int DWeightFactor::operator==( const DWeightFactor & Other) const
{
    double tmp;
    if( nNum != Other.nNum ) return 0;
    for( int i = 0; i < nNum; i ++ ) {
        if( wf[i].Global != wf[i].Global ) return 0;
        tmp = wf[i].Factorx-wf[i].Factorx;
        if( tmp > CombinationError || tmp < -CombinationError ) return 0;
        tmp = wf[i].Factory-wf[i].Factory;
        if( tmp > CombinationError || tmp < -CombinationError ) return 0;
        tmp = wf[i].Factorz-wf[i].Factorz;
        if( tmp > CombinationError || tmp < -CombinationError ) return 0;
    }
    return 1;
}
DWeightFactorItem & DWeightFactor::operator[](const int index)
{
    assert(index<nNum && index>=0);
    return wf[index];
}
int DWeightFactor::Index( short global )
{
    int i=0, j=nNum-1, tmp;
    while( i <= j ) {
        tmp = ((i+j)>>1);
        if( wf[tmp].Global < global ) i = tmp+1;
        else if( wf[tmp].Global == global ) return tmp;
        else j = tmp-1;
    }
    return -1;
}
int DWeightFactor::Insert( short global, float factorx, float factory, float factorz )
{
    if( global <= 0 ) return 0;
    int i=0, j=nNum-1, tmp, factorIsZero=1;
    if( fabs(factorx)+fabs(factory)+fabs(factorz) > CombinationError ) factorIsZero = 0;
    while( i <= j ) {
        tmp = ((i+j)>>1);
        if( wf[tmp].Global < global ) i = tmp+1;
        else if( wf[tmp].Global == global ) {
            if( factorIsZero ) {	// 删除
                if( nNum == 1 ) Clear();
                else {
                    for( j = tmp; j < nNum-1; j ++ ) wf[j] = wf[j+1];
                    nNum --;
                    wf = (DWeightFactorItem*)realloc( wf, sizeof(DWeightFactorItem)*nNum );
                }
            }
            else {
                wf[tmp].Factorx = factorx;
                wf[tmp].Factory = factory;
                wf[tmp].Factorz = factorz;
            }
            return 1;
        }
        else j = tmp-1;
    }
    if( factorIsZero ) return 0;
    nNum ++;
    wf = (DWeightFactorItem*)realloc( wf, sizeof(DWeightFactorItem)*nNum );
    for( j = nNum-1; j > i; j -- ) wf[j] = wf[j-1];
    wf[i].Global = global;
    wf[i].Factorx = factorx;
    wf[i].Factory = factory;
    wf[i].Factorz = factorz;
    return 1;
}
void DWeightFactor::Clear()
{
    nNum = 0;
    if( wf ) {
        free(wf);
        wf = NULL;
    }
}
void DWeightFactor::Serialize( bofstream & fout )
{
    fout << nNum;
    for( int i = 0; i < nNum; i ++ ) {
        fout << wf[i].Global << wf[i].Factorx << wf[i].Factory << wf[i].Factorz;
    }
}

void DWeightFactor::Serialize( bifstream & fin )
{
    Clear();
    fin >> nNum;
    if( nNum > 0 ) {
        wf = (DWeightFactorItem*)malloc( sizeof(DWeightFactorItem)*nNum );
        for( int i = 0; i < nNum; i ++ ) {
            fin >> wf[i].Global >> wf[i].Factorx >> wf[i].Factory >> wf[i].Factorz;
        }
    }
}


DWeightFactor的声明

// 用于各荷载种类下的自重因子
struct CLASS_DECLSPEC DWeightFactorItem {
    short Global;	// 荷载种类
    float Factorx, Factory, Factorz;	// 荷载种类Global下三个方向的自重因子
};
class CLASS_DECLSPEC DWeightFactor {
private:
    short nNum;
    DWeightFactorItem *wf;	// 数据必须按Global排序
public:
    DWeightFactor();
    ~DWeightFactor();
    DWeightFactor( const DWeightFactor & Copy ) {
        (*this) = Copy;
    }
    DWeightFactor & operator = ( const DWeightFactor & Copy );
    int operator==( const DWeightFactor &Other) const;
    int Entries() { return nNum; }
    DWeightFactorItem & operator[](const int index);
    // 查找整数global所处的索引号，返回-1(没有找到)或大于等于0的索引值
    int Index( short global );
    // 如果整数global已经存在，则作替换, 如果global＝0,返回0
    // 如果factorx=0,factory=0,factorz=0, 则表示删除global对应的项,
    int Insert( short global, float factorx, float factory, float factorz );
    // 删除整数global对应的项
    int Remove( short global ) { return Insert( global,0,0,0 ); }
    void Clear();

    void Serialize( bofstream & fout );
    void Serialize( bifstream & fin );
};


CVectBase的声明

template <class TYPE>
class MArrayBase {
protected:
    int m_nGrowExp;			// 分配的内存块大小的指数: 2^m_nGrowExp
    int m_nEntriesNum;		// 当前有效向量元素的个数

    int m_nInitNum;			// 已经分配的内存块数
    int m_nBegin, m_nEnd;	// 分别指向可能存在空闲内存的内存块的开始和终止位置，
                            // 从零开始计。空闲内存块号i满足，m_nBegin<=i<=m_nEnd.
    MMemBlock<TYPE> ** m_ppVectBlock;	// 保存内存块
    char * m_strHaveFree;	// 1->m_nInitNum，如果m_ppVectBlock[i]没有可用内存，
                        // m_strHaveFree[i]==0，否则等于非零
    int  * m_pIndex;	// 向量元素的索引号，从零开始，删除一个元素后
                        // 它后面的元素的索引号会向前移. 例如：
                        // MArrayBase A;   若删除了A[3]之后，A[4]会变成A[3],
                        // A[5]会变成A[4].....
protected:
    void BaseAssign( const MArrayBase<TYPE> * Source ) {
        if( this != Source ) {
            this->Clear();
            if( Source->m_nEntriesNum > 0 ) {
                Resize( Source->m_nEntriesNum );
                for( int i = 0; i < Source->m_nEntriesNum; i ++ ) {
                    InsertAt( m_nEntriesNum, (*Source)[i] );
                }
            }
        }
    }
    // 在index之前插入一个元素, index从0开始,
    // 若成功返回索引号，从1开始，否则返回0
    virtual int  InsertAt( const int index, const TYPE & ele ) {
        int bi, ci;
        if( m_nEntriesNum == (m_nInitNum<<m_nGrowExp) ) {
            m_ppVectBlock = (MMemBlock<TYPE> **)realloc( m_ppVectBlock,
                (sizeof(MMemBlock<TYPE>*))*(m_nInitNum + 1) );
            m_ppVectBlock[m_nInitNum] = new MMemBlock<TYPE>( (0x01<<m_nGrowExp) );
            m_strHaveFree = (char*)realloc( m_strHaveFree, sizeof(char)*(1+m_nInitNum) );
            m_strHaveFree[m_nInitNum] = 0x01;
            m_pIndex = (int*)realloc( m_pIndex, sizeof(int)*((1+m_nInitNum)<<m_nGrowExp) );
            if( m_pIndex == NULL ) {
                if( m_ppVectBlock[m_nInitNum] ) delete m_ppVectBlock[m_nInitNum];
                return 0;
            }
            m_nEnd = m_nInitNum;
            bi = m_nInitNum;
            m_nInitNum ++;
        }
        else {
            for( int i = m_nBegin; i <= m_nEnd; i ++ ) {
                if( m_strHaveFree[i] ) {
                    bi = i;
                    break;
                }
            }
        }
        m_ppVectBlock[bi]->RegisterOneCell( ci );
        (*m_ppVectBlock[bi])[ci] = ele;
        m_nBegin = bi;
        if( !m_ppVectBlock[bi]->HaveFreeCell() ) {
            m_strHaveFree[bi] = 0x00;
            m_nBegin ++;
        }
        memmove( &m_pIndex[index+1], &m_pIndex[index], sizeof(int)*(m_nEntriesNum-index) );
        m_pIndex[index] = (bi<<m_nGrowExp)+ci;
        m_nEntriesNum ++;
        return index+1;
    }
public:
    // 如果您使用得数组可能会变得比较大，请初始化比较大的grow值，
    // 否则内存的利用率非常的低，因为每增加一块grow大小的内存，需要
    // 额外增加20多字节的内存开销(包括系统动态内存分配需要的开销)，
    // 并且造成内存块数过多。
    MArrayBase( const int length = VECTOR_DEFAULT_LENGTH,
        const int grow = VECTOR_DEFAULT_GROW ) {
        m_nEntriesNum = 0;
        m_nGrowExp = 1;
        while( grow>>m_nGrowExp ) m_nGrowExp++;
        if( grow <= (0x01<<m_nGrowExp) ) m_nGrowExp--;
        m_nInitNum = ((length+(0x01<<m_nGrowExp)-1)>>m_nGrowExp);
        if( m_nInitNum > 0 ) {
            m_ppVectBlock = (MMemBlock<TYPE> **)malloc( sizeof(MMemBlock<TYPE>*)*m_nInitNum );
            for( int i = 0; i < m_nInitNum; i ++ )
                m_ppVectBlock[i] = new MMemBlock<TYPE>( (0x01<<m_nGrowExp) );
            m_strHaveFree = (char*)malloc( sizeof(char)*m_nInitNum );
            memset( m_strHaveFree, 0x01, sizeof(char)*m_nInitNum );
            m_pIndex = (int*)malloc( sizeof(int)*(m_nInitNum<<m_nGrowExp) );
        }
        else {
            m_ppVectBlock = NULL;
            m_strHaveFree = NULL;
            m_pIndex = NULL;
        }
        m_nBegin = 0;
        m_nEnd = m_nInitNum-1;
    }
    virtual ~MArrayBase() {
        for( int i = 0; i < m_nInitNum; i ++ )
            delete m_ppVectBlock[i];
        if( m_ppVectBlock != NULL )	Free( m_ppVectBlock );
        if( m_strHaveFree != NULL ) Free( m_strHaveFree );
        if( m_pIndex != NULL ) Free( m_pIndex );
        m_nInitNum = m_nEntriesNum = 0;
        m_nBegin = 0;
        m_nEnd = -1;
    }
    virtual void Clear() {   // 清除内存，置相关的一些变量为零
        // 不能采用Free()的方式，否则调试版的DLL不能调用Clear()
#ifdef _DEBUG
        Resize(0);
#else
        for( int i = 0; i < m_nInitNum; i ++ )
            delete m_ppVectBlock[i];
        if( m_ppVectBlock != NULL )	Free( m_ppVectBlock );
        if( m_strHaveFree != NULL ) Free( m_strHaveFree );
        if( m_pIndex != NULL ) Free( m_pIndex );
        m_nInitNum = m_nEntriesNum = 0;
        m_nBegin = 0;
        m_nEnd = -1;
#endif
    }
    int Entries() {    // 返回向量元素的个数
        return m_nEntriesNum;
    }
    int IsEmpty( ) {   // 向量个数是否为零
        return (m_nEntriesNum == 0);
    }
        //  删除第 index 个向量元素(index 从0开始)
        //  程序自动删除过多的内存(但保留一定的剩余内存), 若成功返回1，否则返回0
    virtual int RemoveAt( const int index ) {
        assert( index>=0 && index < m_nEntriesNum );
        int bi, ci;
        ci = m_pIndex[index];
        bi = (ci>>m_nGrowExp);
        ci = ci - (bi<<m_nGrowExp);
        if( bi < m_nBegin )  m_nBegin = bi;
        if( m_nEnd < bi )  m_nEnd = bi;
        m_ppVectBlock[bi]->UnregisterOneCell( ci );
        m_strHaveFree[bi] = 0x01;
        memcpy( m_pIndex+index, m_pIndex+index+1 , sizeof(int)*(m_nEntriesNum-index-1) );
        m_nEntriesNum --;
        if( bi == m_nInitNum-1 && m_ppVectBlock[bi]->BlockNotUsed() ) {
            // May be too many block not used
            int FirstFree = bi;
            while( FirstFree > 0 && m_ppVectBlock[FirstFree-1]->BlockNotUsed() )
                FirstFree--;
            if( FirstFree < bi ) {
                // Only left one block not use at the end continuously
                for( int i = FirstFree+1; i <= bi; i ++ ) {
                    delete m_ppVectBlock[i];
                }
                m_nInitNum = FirstFree+1;
                m_ppVectBlock = (MMemBlock<TYPE> **)realloc( m_ppVectBlock,
                    (sizeof(MMemBlock<TYPE>*))*m_nInitNum );
                m_strHaveFree = (char*)realloc( m_strHaveFree, sizeof(char)*m_nInitNum );
                m_pIndex = (int*)realloc( m_pIndex, sizeof(int)*(m_nInitNum<<m_nGrowExp) );
                m_nEnd = FirstFree;
            }
        }
        return 1;
    }
    virtual int Remove( const TYPE & ele ) { // 删除包含 ele 的第一个元素,若成功返回1，否则返回0
        int index = Contains( ele );
        if( !index ) return 0;
        return RemoveAt( index-1 );
    }
    // 删除一组元素，元素的索引号（从0开始）放在int index[num]内
    // 这种方式的速度要比调用num次RemoveAt快不少，返回num
    // 该函数只是为MArray<TYPE>和MArraySort<TYPE>服务的
    // MArrayID<TYPE>不需要此函数，因为它通过nID的删除速度非常的快
    virtual int Removes( const int index[], const int num ) {
        int bi, ci;
        for( int i = 0; i < num; i ++ ) {
            assert( index[i]>=0 && index[i] < m_nEntriesNum );
            ci = m_pIndex[index[i]];
            m_pIndex[index[i]] = -1;
            bi = (ci>>m_nGrowExp);
            ci = ci - (bi<<m_nGrowExp);
            if( bi < m_nBegin )  m_nBegin = bi;
            if( m_nEnd < bi )  m_nEnd = bi;
            m_ppVectBlock[bi]->UnregisterOneCell( ci );
            m_strHaveFree[bi] = 0x01;
            if( bi == m_nInitNum-1 && m_ppVectBlock[bi]->BlockNotUsed() ) {
                // May be too many block not used
                int FirstFree = bi;
                while( FirstFree > 0 && m_ppVectBlock[FirstFree-1]->BlockNotUsed() )
                    FirstFree--;
                if( FirstFree < bi ) {
                    // Only left one block not use at the end continuously
                    for( int i = FirstFree+1; i <= bi; i ++ ) {
                        delete m_ppVectBlock[i];
                    }
                    m_nInitNum = FirstFree+1;
                    m_ppVectBlock = (MMemBlock<TYPE> **)realloc( m_ppVectBlock,
                        (sizeof(MMemBlock<TYPE>*))*m_nInitNum );
                    m_strHaveFree = (char*)realloc( m_strHaveFree, sizeof(char)*m_nInitNum );
                    m_pIndex = (int*)realloc( m_pIndex, sizeof(int)*(m_nInitNum<<m_nGrowExp) );
                    m_nEnd = FirstFree;
                }
            }
        }
        int nDeletedNum=0, nValidNum = m_nEntriesNum;
        if( (m_nInitNum<<m_nGrowExp) < m_nEntriesNum )
            nValidNum = m_nInitNum<<m_nGrowExp;
        for( i = 0; i < nValidNum; i ++ ) {
            if( m_pIndex[i] < 0 ) nDeletedNum++;
            else m_pIndex[i-nDeletedNum] = m_pIndex[i];
        }
        m_nEntriesNum -= num;
        return num;
    }
    // 使向量个数强制为size个，若原向量元素个数
    // 大于size，后面的元素将被删除，若size大于元向量个数
    // 程序将分配size个元素的内存
    virtual int Resize( const int size ) {
        if( size > (m_nInitNum<<m_nGrowExp) ) {
            int GrowBlockNum = ((size + (0x01<<m_nGrowExp) -1)>>m_nGrowExp) - m_nInitNum;
            m_ppVectBlock = (MMemBlock<TYPE> **)realloc( m_ppVectBlock,
                (sizeof(MMemBlock<TYPE>*))*(m_nInitNum+GrowBlockNum) );
            for( int i = m_nInitNum; i < m_nInitNum+GrowBlockNum; i ++ )
                m_ppVectBlock[i] = new MMemBlock<TYPE>( (0x01<<m_nGrowExp) );
            m_strHaveFree = (char*)realloc( m_strHaveFree, sizeof(char)*(GrowBlockNum+m_nInitNum) );
            memset( m_strHaveFree+m_nInitNum, 0x01, GrowBlockNum );
            m_pIndex = (int*)realloc( m_pIndex, sizeof(int)*((GrowBlockNum+m_nInitNum)<<m_nGrowExp) );
            if( m_pIndex == NULL ) {
                for( i = m_nInitNum; i < m_nInitNum+GrowBlockNum; i ++ )
                    if( m_ppVectBlock[i] ) delete m_ppVectBlock[i];
                return 0;
            }
            m_nInitNum += GrowBlockNum;
            m_nEnd = m_nInitNum-1;
        }
        else if( size < m_nEntriesNum ) {
            for( int i = m_nEntriesNum; i > size; i -- ) {
                RemoveAt( i-1 );
            }
        }
        return 1;
    }
    virtual TYPE & operator []( const int i ) {   // i 从零开始
        assert( i >= 0 && i < m_nEntriesNum );
        int bi, ci;
        ci = m_pIndex[i];
        bi = (ci>>m_nGrowExp);
        ci = ci - (bi<<m_nGrowExp);
        return (*m_ppVectBlock[bi])[ci];
    }
    virtual const TYPE & operator []( const int i ) const {   // i 从零开始
        assert( i >= 0 && i < m_nEntriesNum );
        int bi, ci;
        ci = m_pIndex[i];
        bi = (ci>>m_nGrowExp);
        ci = ci - (bi<<m_nGrowExp);
        return (*m_ppVectBlock[bi])[ci];
    }
                // 查找包含元素ele的第一个索引号
                // 若存在返回index+1, 即从1开始
                // 否则返回0.
    virtual int Contains( const TYPE & ele ) = 0;
                // 插入一个向量元素, 返回索引号(从1开始), 插到最后
    virtual int Insert( const TYPE & ele ) = 0;
#if defined(_SERIALIZE)
    virtual void Serialize( bifstream & fin ) {
        int num;
        this->Clear();
        fin >> num;
        this->Resize( num );
        TYPE tmp;
        for( int i = 0; i < num; i ++ ) {
            tmp.Serialize( fin );
            this->Insert( tmp );
        }
    }
    virtual void Serialize( bofstream & fout ) {
        fout << m_nEntriesNum;
        for( int i = 0; i < m_nEntriesNum; i ++ ) {
            (*this)[i].Serialize( fout );
        }
    }
#endif
};


MArray的声明

// MArray中的元素是按插入的顺序存放的
// 而MArraySort中的元素是按升序排列的
template <class TYPE>
class MArray : public MArrayBase<TYPE> {
public:
    // 如果您使用得数组可能会变得比较大，请初始化比较大的grow值，
    // 否则内存的利用率非常的低，因为每增加一块grow大小的内存，需要
    // 额外增加20多字节的内存开销(包括系统动态内存分配需要的开销)，
    // 并且造成内存块数过多。
    MArray( const int length = VECTOR_DEFAULT_LENGTH,
        const int grow = VECTOR_DEFAULT_GROW )
        : MArrayBase<TYPE>( length, grow ) { }
    MArray( const MArray & Source ) {
        BaseAssign( &Source );
    }
    virtual ~MArray() {}
    MArray<TYPE> & operator = ( const MArray<TYPE> & Source ) {
        BaseAssign( &Source );
        return (*this);
    }
    int Append( const TYPE & ele ) {  // 与Insert 是一样的
        return Insert( ele );
    }
    // 查找包含元素ele的第一个索引号
    // 若存在返回 index+1, 从1开始
    // 否则返回0.
    int Contains( const TYPE & ele ) {
        for( int i = 0; i < Entries(); i ++ ) {
            if( (*this)[i] == ele ) return i+1;
        }
        return 0;
    }
    // 查找包含元素ele的第一个索引号
    // 若存在返回 index, 从0开始
    // 否则返回-1.
    int Index( const TYPE & ele ) {
        for( int i = 0; i < Entries(); i ++ ) {
            if( (*this)[i] == ele ) return i;
        }
        return -1;
    }
    // 插入一个向量元素, 返回索引号(从1开始), 插到最后
    int Insert( const TYPE & ele ) {
        return InsertAt( Entries(), ele );
    }
};


MArrayID的声明

//	MArrayID与MArraySort是类似的，但是数组元素类不需要定义
//	int operator < (...)成员函数，可是需要有公有数据成员TYPE::nID(nID>0),
//  另外还需要int operator ==()成员函数，因为数组在插入元素之前往往
//  需要判断该元素是否已经存在，而是否存在的判据一般都不是通过
//  比较nID进行，而是通过int operator == ()进行
//  对MArrayID数组元素的索引通常是通过成员函数Ref( int id )进行
//  MArrayID为了提高Ref的速度, 第i个元素ele[i]在m_pIndex中的位置不再是i,而是
//  ele[i].nID-1，这实际上是一种散列的存储方法，由于nID之间不可能相同，因而没有
//  碰撞问题. 为了加快对第i个元素的索引（经常是从头到尾依次索引）增加了变量
//  int m_nCurI和int m_nCurIndex.
template <class TYPE>
class MArrayID : public MArrayBase<TYPE> {
protected:
    int m_nCurI, m_nCurIndex; // 第m_nCurI个(从0开始)元素的地址放在m_pIndex[m_nCurIndex]中,[-1,-1]
    int m_nIndexNum;	// m_pIndex数组的长度
    int m_nEndIndex;	// 最后一个有效元素所在的索引(从0开始)
protected:
    // 在index位置上插入一个元素, 如果index上已经有元素(即ele.nID已经存在)
    // ele将替换原来的数据，index从0开始,要求index==ele.nID-1
    // 若成功返回1，否则返回0
    virtual int  InsertAt( const int index, const TYPE & ele ) {
        int bi, ci;
        assert( index == ele.nID-1 );
        if( index < m_nIndexNum && m_pIndex[index] >= 0 ) {	// ele.nID已经存在
            ci = m_pIndex[index];
            bi = (ci>>m_nGrowExp);
            ci = ci - (bi<<m_nGrowExp);
            (*m_ppVectBlock[bi])[ci] = ele;
            return 1;
        }
        if( m_nEntriesNum == (m_nInitNum<<m_nGrowExp) ) {
            m_ppVectBlock = (MMemBlock<TYPE> **)realloc( m_ppVectBlock,
                (sizeof(MMemBlock<TYPE>*))*(m_nInitNum + 1) );
            m_ppVectBlock[m_nInitNum] = new MMemBlock<TYPE>( (0x01<<m_nGrowExp) );
            m_strHaveFree = (char*)realloc( m_strHaveFree, sizeof(char)*(1+m_nInitNum) );
            m_strHaveFree[m_nInitNum] = 0x01;
            if( m_strHaveFree == NULL ) {
                if( m_ppVectBlock[m_nInitNum] ) delete m_ppVectBlock[m_nInitNum];
                return 0;
            }
            m_nEnd = m_nInitNum;
            bi = m_nInitNum;
            m_nInitNum ++;
        }
        else {
            for( int i = m_nBegin; i <= m_nEnd; i ++ ) {
                if( m_strHaveFree[i] ) {
                    bi = i;
                    break;
                }
            }
        }
        m_ppVectBlock[bi]->RegisterOneCell( ci );
        (*m_ppVectBlock[bi])[ci] = ele;
        m_nBegin = bi;
        if( !m_ppVectBlock[bi]->HaveFreeCell() ) {
            m_strHaveFree[bi] = 0x00;
            m_nBegin ++;
        }
        if( index >= m_nIndexNum ) {
            int nAddNum = index+1-m_nIndexNum+(0x01<<m_nGrowExp);
            m_pIndex = (int*)realloc( m_pIndex, sizeof(int)*(m_nIndexNum+nAddNum) );
            memset( &m_pIndex[m_nIndexNum], 0xFF, sizeof(int)*nAddNum );
            m_nIndexNum += nAddNum;
        }
        if( m_nCurIndex > index ) m_nCurI++;
        m_pIndex[index] = (bi<<m_nGrowExp)+ci;
        if( index > m_nEndIndex ) m_nEndIndex = index;
        m_nEntriesNum ++;
        return 1;
    }
public:
    MArrayID( const int length = VECTOR_DEFAULT_LENGTH,
        const int grow = VECTOR_DEFAULT_GROW )
        : MArrayBase<TYPE>( length, grow ) {
        m_nIndexNum = (m_nInitNum<<m_nGrowExp);
        memset( m_pIndex, 0xFF, sizeof(int)*m_nIndexNum );
        m_nCurI = m_nCurIndex = m_nEndIndex = -1;
    }
    MArrayID( MArrayID<TYPE> & Source ) {
        (*this) = Source;
    }
    MArrayID<TYPE> & operator = ( const MArrayID<TYPE> & Source ) {
        if( this != &Source ) {
            this->Clear();
            if( Source.m_nEntriesNum > 0 ) {
                Resize( Source.m_nEntriesNum );
                for( int i = 0; i < Source.m_nEntriesNum; i ++ ) {
                    Insert( Source[i] );
                }
            }
        }
        return (*this);
    }
    virtual ~MArrayID() {
    }
    void Clear() {     // 清除内存，置相关的一些变量为零
        MArrayBase<TYPE>::Clear();
        m_nCurI = m_nCurIndex = m_nEndIndex = -1;
        m_nIndexNum = 0;
    }
    // 把索引位置(zero-based)转换成相应的ID号(one-based)，此函数并不
    // 是通过引用元素中的nID号而实现，而是通过数组的内部存储结构与nID之间的
    // 关系而实现的，它一般用于检测是否存在逻辑错误
    int IndexToID( const int i ) {
        // 结束后对应的ID就是m_nCurIndex+1
        assert( i >= 0 && i < m_nEntriesNum );
        if( i != m_nCurI ) {
            if( i == m_nEntriesNum-1 ) {
                m_nCurI = i;
                m_nCurIndex = m_nEndIndex;
            }
            else if( m_nCurI < 0 || m_nCurIndex < 0 || i == 0 ) {
                m_nCurI = m_nCurIndex = 0;
                while( m_pIndex[m_nCurIndex] < 0 ) {
                    m_nCurIndex ++;
                    assert( m_nCurIndex <= m_nEndIndex );
                }
                // m_pIndex[m_nCurIndex]为第一个有效元素的索引
            }
            while( m_nCurI < i ) {
                do {	// 找下一个有效元素的位置
                    m_nCurIndex++;
                    assert( m_nCurIndex <= m_nEndIndex );
                } while( m_pIndex[m_nCurIndex] < 0 );
                m_nCurI++;	// 该元素是第m_nCurI个有效元素
            }
            while( m_nCurI > i ) {
                do {	// 找前一个有效元素的位置
                    m_nCurIndex--;
                    assert( m_nCurIndex >= 0 );
                } while( m_pIndex[m_nCurIndex] < 0 );
                m_nCurI--;	// 该元素是第m_nCurI个有效元素
            }
        }
        return (m_nCurIndex+1);
    }
    TYPE & operator []( const int i ) {   // i 从零开始
        int bi, ci;
        IndexToID(i);
        ci = m_pIndex[m_nCurIndex];
        bi = (ci>>m_nGrowExp);
        ci = ci - (bi<<m_nGrowExp);
        return (*m_ppVectBlock[bi])[ci];
    }
    const TYPE & operator []( const int i ) const {   // i 从零开始
        int bi, ci;
        ((MArrayID<TYPE> *)this)->IndexToID(i);
        ci = m_pIndex[m_nCurIndex];
        bi = (ci>>m_nGrowExp);
        ci = ci - (bi<<m_nGrowExp);
        return (*m_ppVectBlock[bi])[ci];
    }
    TYPE & Ref( const int id ) {
        assert( id > 0 && id <= m_nIndexNum );
        int bi, ci;
        ci = m_pIndex[id-1];
        assert( ci >= 0 );		// if(ci<0) id对应的元素不存在
        bi = (ci>>m_nGrowExp);
        ci = ci - (bi<<m_nGrowExp);
        return (*m_ppVectBlock[bi])[ci];
    }
    // Contains(int id)和Contains( TYPE & ele )都是通过nID号判断nID或ele.nID是否存在
    // 若存在返回元素对应的nID, 这时可以通过Ref(nID)找到该元素
    // 否则返回0.
    int Contains( const int id ) {
        if( id > 0 && id <= m_nIndexNum ) {
            if( m_pIndex[id-1] >= 0 ) return id;
        }
        return 0;
    }
    // 通过ele.nID查找
    int Contains( const TYPE & ele ) {
        if( ele.nID > 0 && ele.nID <= m_nIndexNum ) {
            if( m_pIndex[ele.nID-1] >= 0 ) return ele.nID;
        }
        return 0;
    }
    // Contains(TYPE & ele, int & emptyID)通过class TYPE的成
    //	  员函数int operator == () 依次查找查找是否包含ele, 如果
    //	  ele不存在，还将同时返回一个最小的没有被使用的ID号给emptyID
    // 若存在返回元素对应的nID, 这时可以通过Ref(nID)找到该元素
    // 否则返回0.
    int Contains( const TYPE & ele, int & emptyID ) {
        int bi, ci, nFind = 0;
        emptyID = m_nEndIndex+2;
        for( int i = 0; i <= m_nEndIndex; i ++ ) {
            ci = m_pIndex[i];
            if( ci < 0 ) {
                if( i+1 < emptyID ) emptyID = i+1;
            }
            else {
                bi = (ci>>m_nGrowExp);
                ci = ci - (bi<<m_nGrowExp);
                if( (*m_ppVectBlock[bi])[ci] == ele ) nFind=(*m_ppVectBlock[bi])[ci].nID;
            }
            if( nFind && emptyID <= m_nIndexNum ) return nFind;
        }
        return nFind;
    }
    // 返回一个最小的没有被使用的ID号
    int FirstEmptyID() {
        if( m_nEntriesNum >= m_nEndIndex+1 ) return m_nEndIndex+2;
        for( int i = 0; i <= m_nEndIndex; i ++ ) {
            if( m_pIndex[i] < 0 ) return i+1;
        }
        return m_nIndexNum+1;
    }
    //  删除第 index 个向量元素(index 从0开始)
    //  程序自动删除过多的内存(但保留一定的剩余内存), 若成功返回1，否则返回0
    virtual int RemoveAt( const int index ) {
        return RemoveFromID( (*this)[index].nID );
    }
    // 删除nID为id的元素
    int RemoveFromID( const int id ) {
        if( id<=0 || id > m_nEndIndex+1 ) return 0;
        if( m_pIndex[id-1] < 0 ) return 0;
        int bi, ci;
        ci = m_pIndex[id-1];
        bi = (ci>>m_nGrowExp);
        ci = ci - (bi<<m_nGrowExp);
        if( bi < m_nBegin )  m_nBegin = bi;
        if( m_nEnd < bi )  m_nEnd = bi;
        m_ppVectBlock[bi]->UnregisterOneCell( ci );
        m_strHaveFree[bi] = 0x01;
        if( m_nCurIndex == id-1 ) {	// m_nCurI指向第下一个元素或者前一个元素（如果id已经是最后一个元素）
            if( m_nCurI < m_nEntriesNum-1 ) {	// 删除的并不是最后一个元素
                do { m_nCurIndex++;
                     assert( m_nCurIndex < m_nIndexNum );
                } while( m_pIndex[m_nCurIndex] < 0 );	// 使m_nCurIndex所指的仍旧是第m_nCurI个(从0开始)元素
            }
            else {
                m_nCurI--;
                if( m_nCurI < 0 ) m_nCurIndex = -1;
                else {
                    do { m_nCurIndex--;
                         assert( m_nCurIndex >= 0 );
                    } while( m_pIndex[m_nCurIndex] < 0 );	// 使m_nCurIndex所指的变成第m_nCurI-1个(从0开始)元素
                }
            }
        }
        else if( m_nCurIndex > id-1 ) m_nCurI--;
        m_pIndex[id-1] = -1;
        m_nEntriesNum --;
        if( id == m_nEndIndex+1 ) {	// 删除的是当前最后一个有效的元素，应该考虑内存的部分释放
                // 查找最后一个有效的index
            while( m_nEndIndex>=0 && m_pIndex[m_nEndIndex] < 0 ) m_nEndIndex--;
            int KeepNum = m_nEndIndex+1+(0x01<<m_nGrowExp);
            if( m_nIndexNum > KeepNum ) {
                m_pIndex = (int*)realloc( m_pIndex, sizeof(int)*KeepNum );
                m_nIndexNum = KeepNum;
            }
        }
        if( bi == m_nInitNum-1 && m_ppVectBlock[bi]->BlockNotUsed() ) {
            // May be too many block not used
            int FirstFree = bi;
            while( FirstFree > 0 && m_ppVectBlock[FirstFree-1]->BlockNotUsed() )
                FirstFree--;
            if( FirstFree < bi ) {
                // Only left one block not use at the end continuously
                for( int i = FirstFree+1; i <= bi; i ++ ) {
                    delete m_ppVectBlock[i];
                }
                m_nInitNum = FirstFree+1;
                m_ppVectBlock = (MMemBlock<TYPE> **)realloc( m_ppVectBlock,
                    (sizeof(MMemBlock<TYPE>*))*m_nInitNum );
                m_strHaveFree = (char*)realloc( m_strHaveFree, sizeof(char)*m_nInitNum );
                m_nEnd = FirstFree;
            }
        }
        return 1;
    }
    // 为了兼容性提供了此函数，建议最好直接通过RemoveFromID(int id)依次删除元素，不要使用此函数
    // 因为该函数比依次调用RemoveFromID(int id )慢,index[i]从0开始
    virtual int Removes( const int index[], const int num ) {
        for( int i = 0; i < num; i ++ )
            RemoveAt( index[i] );
        return num;
    }
    // 通过ele.nID删除对应的元素
    virtual int Remove( const TYPE & ele ) {
        return RemoveFromID( ele.nID );
    }
        // 插入一个向量元素, 若成功返回1，否则返回0
        // 插入位置由nID确定，若ele.nID已经存在，则替换原来的数据
    virtual int Insert( const TYPE & ele ) {
        return InsertAt( ele.nID-1, ele );
    }
    // 把nID号为nFrom的元素的nID改成nTo，如果nFrom存在，且nTo不存在，返回1，否则返回0
    int ChangeID( const int nFrom, const int nTo ) {
        if( m_pIndex[nFrom-1] < 0 || (nTo<m_nIndexNum && m_pIndex[nTo-1]>=0) ) return 0;
        Ref( nFrom ).nID = nTo;
        if( m_nCurIndex == nFrom-1 ) {	// m_nCurI指向第下一个元素或者前一个元素（如果nFrom已经是最后一个元素）
            if( m_nCurI < m_nEntriesNum-1 ) {	// 删除的并不是最后一个元素
                do { m_nCurIndex++;
                     assert( m_nCurIndex < m_nIndexNum );
                } while( m_pIndex[m_nCurIndex] < 0 );	// 使m_nCurIndex所指的仍旧是第m_nCurI个(从0开始)元素
            }
            else {
                m_nCurI--;
                if( m_nCurI < 0 ) m_nCurIndex = -1;
                else {
                    do { m_nCurIndex--;
                         assert( m_nCurIndex >= 0 );
                    } while( m_pIndex[m_nCurIndex] < 0 );	// 使m_nCurIndex所指的变成第m_nCurI-1个(从0开始)元素
                }
            }
        }
        else if( m_nCurIndex > nFrom-1 ) m_nCurI--;
        if( nTo > m_nIndexNum ) {
            int nAddNum = nTo-m_nIndexNum+(0x01<<m_nGrowExp);
            m_pIndex = (int*)realloc( m_pIndex, sizeof(int)*(m_nIndexNum+nAddNum) );
            memset( &m_pIndex[m_nIndexNum], 0xFF, sizeof(int)*nAddNum );
            m_nIndexNum += nAddNum;
        }
        if( m_nCurIndex >= nTo ) m_nCurI++;
        if( nTo-1 > m_nEndIndex ) m_nEndIndex = nTo-1;
        m_pIndex[nTo-1] = m_pIndex[nFrom-1];
        m_pIndex[nFrom-1] = -1;
        if( nFrom-1 == m_nEndIndex ) {	// 替换的是当前最后一个有效的元素，应该考虑内存的部分释放
                // 查找最后一个有效的index
            while( m_nEndIndex>=0 && m_pIndex[m_nEndIndex] < 0 ) m_nEndIndex--;
            int KeepNum = m_nEndIndex+1+(0x01<<m_nGrowExp);
            if( m_nIndexNum > KeepNum ) {
                m_pIndex = (int*)realloc( m_pIndex, sizeof(int)*KeepNum );
                m_nIndexNum = KeepNum;
            }
        }
        return 1;
    }
    // 使所有的nID从1开始连续分布, IdChangedTo必须是大小为MaximumID()大小
    // 的数组, 函数执行完成之后, IdChangedTo[i]表示原来nID=i+1的元素变化之后的nID
    void ContinueID( int *IdChangedTo ) {
        int i, id, max;
        ASSERT(IdChangedTo);
        max = MaximumID();
        memset( IdChangedTo, 0, sizeof(int)*max );
        for( i = 0; i < Entries(); i ++ ) {
            id = (*this)[i].nID;
            IdChangedTo[id-1] = i+1;
        }
        for( i = 0; i < max; i ++ ) {
            id = IdChangedTo[i];
            if( id <= 0 || id == i+1 ) continue;
#ifdef _DEBUG
            ASSERT(ChangeID( i+1, id ));
#else
            ChangeID( i+1, id );
#endif
        }
    }
    // 使向量个数强制为size个，若原向量元素个数
    // 大于size，后面的元素将被删除，若size大于元向量个数
    // 程序将分配size个元素的内存
    virtual int Resize( const int size ) {
        int GrowBlockNum;
        if( size > m_nIndexNum ) {
            // 使数组大小为2^m_nGrowExp的倍数
            GrowBlockNum = (((size + (0x01<<m_nGrowExp) -1)>>m_nGrowExp)<<m_nGrowExp) - m_nIndexNum;
            m_pIndex = (int*)realloc( m_pIndex, sizeof(int)*(m_nIndexNum+GrowBlockNum) );
            memset( &m_pIndex[m_nIndexNum], 0xFF, sizeof(int)*GrowBlockNum );
            m_nIndexNum += GrowBlockNum;
        }
        if( size > (m_nInitNum<<m_nGrowExp) ) {
            GrowBlockNum = ((size + (0x01<<m_nGrowExp) -1)>>m_nGrowExp) - m_nInitNum;
            m_ppVectBlock = (MMemBlock<TYPE> **)realloc( m_ppVectBlock,
                (sizeof(MMemBlock<TYPE>*))*(m_nInitNum+GrowBlockNum) );
            for( int i = m_nInitNum; i < m_nInitNum+GrowBlockNum; i ++ )
                m_ppVectBlock[i] = new MMemBlock<TYPE>( (0x01<<m_nGrowExp) );
            m_strHaveFree = (char*)realloc( m_strHaveFree, sizeof(char)*(GrowBlockNum+m_nInitNum) );
            memset( m_strHaveFree+m_nInitNum, 0x01, GrowBlockNum );
            if( m_strHaveFree == NULL ) {
                for( i = m_nInitNum; i < m_nInitNum+GrowBlockNum; i ++ )
                    if( m_ppVectBlock[i] ) delete m_ppVectBlock[i];
                return 0;
            }
            m_nInitNum += GrowBlockNum;
            m_nEnd = m_nInitNum-1;
        }
        else if( size < m_nEntriesNum ) {
            for( int i = m_nEntriesNum; i > size; i -- ) {
                RemoveAt(size);
                // 删除一个元素后，原来的第i+1个元素变成了第i个元素, 不从后往前删除的原因
                // 是避免每一次都回收内存，从前往后删除可以在最后一次删除时回收内存
            }
        }
        return 1;
    }
    // 返回当前使用的最大的ID号
    int MaximumID() {
        if( Entries() <= 0 ) return 0;
        return (*this)[Entries()-1].nID;
    }
};


MArraySort的声明

// 而MArraySort中的元素是按升序排列的
template <class TYPE>
class MArraySort : public MArrayBase<TYPE> {
public:
    // 如果您使用得数组可能会变得比较大，请初始化比较大的grow值，
    // 否则内存的利用率非常的低，因为每增加一块grow大小的内存，需要
    // 额外增加20多字节的内存开销(包括系统动态内存分配需要的开销)，
    // 并且造成内存块数过多。
    MArraySort( const int length = VECTOR_DEFAULT_LENGTH,
        const int grow = VECTOR_DEFAULT_GROW )
        : MArrayBase<TYPE>( length, grow ) { }
    MArraySort( const MArraySort & Source ) {
        BaseAssign( &Source );
    }
    virtual ~MArraySort() {}
    MArraySort<TYPE> & operator = ( const MArraySort<TYPE> & Source ){
        BaseAssign( &Source );
        return (*this);
    }
            // 查找包含元素ele的第一个索引号
            // 若存在返回 index+1, 从1开始
            // 否则返回0.
    int Contains( const TYPE & ele ) {
        int i, j, tmp;
        TYPE * cur;
        i = 0;
        j = Entries()-1;
        while( i <= j ) {
            tmp = ((i+j)>>1);
            cur = &((*this)[tmp]);
            if( *cur < ele ) {
                i = tmp+1;
            }
            else if( *cur == ele ) {
                return tmp+1;
            }
            else {
                j = tmp-1;
            }
        }
        return 0;
    }
            // 插入一个向量元素, 返回索引号(从1开始),插到适当的位置
            // 若ele元素已经存在，仅仅返回其索引号
    int Insert( const TYPE & ele ) {
        int i, j, tmp;
        TYPE * cur;
        i = 0;
        j = Entries()-1;
        while( i <= j ) {
            tmp = ((i+j)>>1);
            cur = &((*this)[tmp]);
            if( *cur < ele ) {
                i = tmp+1;
            }
            else if( *cur == ele ) {
                return tmp+1;
            }
            else {
                j = tmp-1;
            }
        }
        return InsertAt( i, ele );
    }
};


MMemBlock的声明

// 这个类对二次开发来说没什么作用，列在这里只是为了帮助可变数组类的理解

#define VECTOR_DEFAULT_LENGTH 0
#define VECTOR_DEFAULT_GROW 128
template <class TYPE>
class MMemBlock {		// MMemBlock is a small memory block class
private:
    TYPE * m_pBlock;		// Store the memory of a fixed length
    char * m_strUsed;		// The cell of Block is used or not (in bit)
    short m_nInitNum;		// Cell number of Block
    short m_sUsedNum;		// Cell number used to store class TYPE
    short m_sUpLimit;
    short m_sDownLimit;		// The limit index of unused cell
public:
    MMemBlock(const short Size = VECTOR_DEFAULT_GROW ) {
        m_pBlock = new TYPE[Size];
        m_strUsed = new char[(Size+7)>>3];
        memset( m_strUsed, 0x00, sizeof(char)*((Size+7)>>3) );
        m_nInitNum = Size;
        m_sUsedNum = 0;
        m_sUpLimit = Size - 1;
        m_sDownLimit = 0;
    }
    virtual ~MMemBlock() {
        delete[] m_pBlock;
        delete[] m_strUsed;
    }
    int HaveFreeCell( ) {  // 检查是否还有空闲的内存返回
        return m_sUsedNum < m_nInitNum;
    }
    int BlockNotUsed( ) {    // 该内存模块全都空闲
        return m_sUsedNum==0;
    }
    // 要求使用一块，调用前您必须确认该Block有可用内存，
    // 返回可用内存的索引号index，从0开始.
    int RegisterOneCell( int & index ) {
        char * UsedC, Bit;
        for( index = m_sDownLimit; index <= m_sUpLimit; index ++ ) {
            UsedC = &m_strUsed[index>>3];
            Bit = char(0x01<<(index&0x07));
            if( !(*UsedC & Bit) ) {   // Find a free cell
                *UsedC |= Bit;
                m_sDownLimit = index+1;
                m_sUsedNum ++;
                return 1;
            }
        }
        index = -1;
        return 0;
    }
    // 放弃使用某块内存,index从0开始
    void UnregisterOneCell( const int index ) {
        m_strUsed[index>>3] &= char(~(0x01<<(index&0x07)));
        m_sUsedNum --;
        if( m_sDownLimit > index ) m_sDownLimit = index;
        if( m_sUpLimit < index )  m_sUpLimit = index;
    }
    TYPE & operator [] ( const int index ) {    //  index 从0开始
        return m_pBlock[index];
    }
    const TYPE & operator [] ( const int index ) const {    //  index 从0开始
        return m_pBlock[index];
    }
};


DSteelStrManager类中型钢字符串数组包含的内容：

 // 等边角钢数据
const char *DSteelStrManager::SectE[]={"20*3","20*4","25*3","25*4","30*3","30*4",
         "36*3","36*4","36*5","40*3","40*4","40*5","45*3",
         "45*4","45*5","45*6","50*3","50*4","50*5","50*6",
         "56*3","56*4","56*5","56*8","63*4","63*5","63*6",
         "63*8","63*10","70*4","70*5","70*6","70*7","70*8",
         "75*5","75*6","75*7","75*8","75*10","80*5","80*6",
         "80*7","80*8","80*10","90*6","90*7","90*8",
         "90*10","90*12","100*6","100*7","100*8","100*10",
         "100*12","100*14","100*16","110*7","110*8","110*10",
         "110*12","110*14","125*8","125*10","125*12","125*14",
         "140*10","140*12","140*14","140*16","160*10","160*12",
         "160*14","160*16","180*12","180*14","180*16","180*18",
         "200*14","200*16","200*18","200*20","200*24",NULL};
// 工字钢数据
const char *DSteelStrManager::SectI[]={"10","12.6","14","16","18","20A","20B","22A",
         "22B","25A","25B","28A","28B","32A","32B","32C","36A",
         "36B","36C","40A","40B","40C","45A","45B","45C","50A",
         "50B","50C","56A","56B","56C","63A","63B","63C",NULL};
// 槽钢数据
const char *DSteelStrManager::SectC[]={"5","6.3","8","10","12.6","14A","14B","16A",
         "16B","18A","18B","20A","20B","22A","22B","25A",
         "25B","25C","28A","28B","28C","32A","32B","32C",
         "36A","36B","36C","40A","40B","40C",NULL};
// 不等边角钢数据
const char *DSteelStrManager::SectL[]={"25*16*3","25*16*4","32*20*3","32*20*4",
         "40*25*3","40*25*4","45*28*3","45*28*4","50*32*3",
         "50*32*4","56*36*3","56*36*4","56*36*5","63*40*4",
         "63*40*5","63*40*6","63*40*7","70*45*4","70*45*5",
         "70*45*6","70*45*7","75*50*5","75*50*6","75*50*8",
         "75*50*10","80*50*5","80*50*6","80*50*7","80*50*8",
         "90*56*5","90*56*6","90*56*7","90*56*8","100*63*6",
         "100*63*7","100*63*8","100*63*10","100*80*6","100*80*7",
         "100*80*8","100*80*10","110*70*6","110*70*7","110*70*8",
         "110*70*10","125*80*7","125*80*8","125*80*10","125*80*12",
         "140*90*8","140*90*10","140*90*12","140*90*14","160*100*10",
         "160*100*12","160*100*14","160*100*16","180*110*10",
         "180*110*12","180*110*14","180*110*16","200*125*12",
         "200*125*14","200*125*16","200*125*18",NULL};
// 热轧宽翼缘H型钢HK系列
const char *DSteelStrManager::SectHK[]={"100A","100B","100C","120A","120B","120C","140A","140B",
    "140C","160A","160B","160C","180A","180B","180C","200A","200B","200C",
    "220A","220B","220C","240A","240B","240C","260A","260B","260C",
    "280A","280B","280C","300A","300B","300C","300D","320A","320B",
    "320C","320D","320E","320F","320G","340A","340B","340C","360A",
    "360B","360C","360D","360E","360F","360G","360K","400A","400B",
    "400C","400D","400E","430A","430B","430C","430D","450A","450B",
    "450C","500A","500B","500C","550A","550B","550C","600A","600B",
    "600C","650A","650B","650C","700A","700B","700C","800A","800B",
    "800C","900A","900B","900C", NULL};
// 热轧窄翼缘H型钢HZ系列
const char *DSteelStrManager::SectHZ[]={"80","100","120","140","160","180","200","220","240",
    "270","300","330","360","400","450","500","550","600", NULL};
// 焊接H型钢,鞍钢规格HA系列
const char *DSteelStrManager::SectHA[]={"300*200A","300*200B","300*200C","300*250A","300*250B",
    "300*300A","300*300B","300*300C","350*175A","350*175B","350*200A","350*200B",
    "350*200C","350*200D","350*250A","350*250B","350*250C","350*300A","350*300B",
    "350*350A","350*350B","350*350C","400*200A","400*200B","400*200C","400*200D",
    "400*250A","400*250B","400*250C","400*250D","400*300A","400*300B","400*300C",
    "400*400A","400*400B","400*400C","400*400D","400*400E","400*400F","392*400",
    "410*400","424*400","440*400","450*250A","450*250B","450*250C","450*300A",
    "450*300B","450*300C","450*300D","450*400A","450*400B","450*400C","500*250A",
    "500*250B","500*250C","500*300A","500*300B","500*300C","500*400A","500*400B",
    "500*400C","600*300A","600*300B","600*300C","600*400A","600*400B","600*400C",
    "600*400D","700*300A","700*300B","700*300C","700*350A","700*350B","700*350C",
    "700*400A","700*400B","700*400C","800*300A","800*300B","800*300C","800*350A",
    "800*350B","800*350C","800*400A","800*400B","800*400C","800*400D","900*350A",
    "900*350B","900*350C","900*350D","900*400A","900*400B","900*400C","900*400D",
    "900*450A","900*450B","900*450C","900*450D","1000*400A","1000*400B","1000*400C",
    "1000*400D","1000*450A","1000*450B","1000*450C","1000*450D","1000*500A","1000*500B",
    "1000*500C","1000*500D","1100*400A","1100*400B","1100*400C","1100*500A","1100*500B",
    "1200*400A","1200*400B","1200*400C","1200*400D","1200*450A","1200*450B","1200*500A",
    "1200*500B","1200*500C","1200*600A","1200*600B","1200*600C",NULL};
// 轻型焊接H型钢,鞍钢规格HAQ系列
const char *DSteelStrManager::SectHAQ[]={"250*125","250*150","250*200","252*250","300*150",
    "300*200","302*250","304*300","350*200","350*250","350*300","400*200","400*250",
    "404*300","450*200","454*250","454*300",NULL};
// 焊接T型钢,鞍钢规格T系列
const char *DSteelStrManager::SectT[]={"87.5*175","100*100","97*150","100*200","100*204",
    "125*125","122*175","125*250","122*252","125*255","150*150","147*200","150*300",
    "150*305","175*175","170*250","175*350","200*200","195*300","200*400","207*405",
    "214*407","229*471","249*432","194*402","197*405","200*408","223*199","225*200",
    "220*300","250*200","241*300","244*300","300*200","291*300","294*300","297*302",NULL};
// 热轧宽翼缘H型钢,美顿有限公司或马钢公司HW系列
const char *DSteelStrManager::SectHW[]={"100*100","125*125","150*150","175*175","200*200A",
    "200*200B","250*250A","250*250B","300*300A","300*300B","300*300C","350*350A",
    "350*350B","400*400A","400*400B","400*400C","400*400D","400*400E","400*400F",
    "400*400G","400*400H",NULL};
// 热轧中翼缘H型钢,美顿有限公司或马钢公司HM系列
const char *DSteelStrManager::SectHM[]={"150*100","200*150","250*175","300*200","350*250",
    "400*300","450*300","500*300A","500*300B","600*300A","600*300B","600*300C",NULL};
// 热轧窄翼缘H型钢,美顿有限公司或马钢公司HN系列
const char *DSteelStrManager::SectHN[]={"100*50","125*60","150*75","175*90","200*100A",
    "200*100B","250*125A","250*125B","300*150A","300*150B","350*175A","350*175B",
    "400*150","400*200A","400*200B","450*150","450*200A","450*200B","500*150",
    "500*200A","500*200B","500*200C","600*200A","600*200B","600*200C","700*300A",
    "700*300B","800*300A","800*300B","900*300A","900*300B","900*300C",NULL};
// 热轧轻型工字钢IQ系列
const char *DSteelStrManager::SectIQ[]={"10","12","14","16","18","18A","20","20A","22",
    "22A","24","24A","27","27A","30","30A","33","36","40","45","50","55","60",
    "65","70","70A","70B",NULL};
// 热轧轻型槽钢CQ系列
const char *DSteelStrManager::SectCQ[]={"10","12","14","14A","16","16A","18","18A","20",
    "20A","22","22A","24","24A","27","30","33","36","40",NULL};

// >E 表示等边角钢数据SectE[]
// >I 表示工字钢数据SectI[]
// >C 表示槽钢数据SectC[]
// >L 表示不等边角钢数据SectL[]
// >K 表示热轧宽翼缘H型钢HK系列SectHK[]
// >Z 表示热轧窄翼缘H型钢HZ系列SectHZ[]
// >A 表示焊接H型钢,鞍钢规格HA系列SectHA[]
// >Q 表示轻型焊接H型钢,鞍钢规格HAQ系列SectHAQ[]
// >T 表示焊接T型钢,鞍钢规格系列SectT[]
// >W 表示热轧宽翼缘H型钢,美顿有限公司HW系列SectHW[]
// >M 表示热轧中翼缘H型钢,美顿有限公司HM系列SectHM[]
// >N 表示热轧窄翼缘H型钢,美顿有限公司HN系列SectHN[]
// >B 表示热轧轻型工字钢IQ系列SectIQ[]
// >D 表示热轧轻型槽钢CQ系列SectCQ[]
// 以上的>#(#表示上述的某个字符)之后必须是除*之后的字符
// >R: meaning one real number
// SAP84说明书中的第17,26,31,32,34号截面有等边和不等边之分，以下的截面编号把它们分成
// 两种不同的截面，故最大编号比SAP84中的最大编号大5
const char *DSteelStrManager::SteelPattern[]={/*1*/"L>E",/*2*/"I>I",/*3*/"C>C",/*4*/"2E>E@>R",
         /*5*/"2L>L@>R",/*6*/"2S>L@>R",/*7*/"2C>C@>R",/*8*/"XL>E@>R",
         /*9*/"4L>E@>R",/*10*/"D>R*>R",/*11*/"BB>R*>R*>R*>R*>R",
         /*12*/"BCC>C+S>R*>R@>R", /*13*/"BBC>C+S>R*>R@>R",/*14*/"BI>I+S>R*>R@>R",
         /*15*/"BI>I", /*16*/"BC>C",/*17*/"ZL>E+S>R*>R@>R",/*18*/"ZL>L+S>R*>R@>R",
         /*19*/"ZS>R*>R+I>I",/*20*/"ZC>C+S>R*>R",/*21*/"ZI>I+S>R*>R",
         /*22*/"ZH>R*>R*>R*>R+S>R*>R",/*23*/"ZS>R*>R+S>R*>R+I>I",
         /*24*/"ZS>R*>R+S>R*>R+H>R*>R*>R*>R", /*25*/"ZC>C+S>R*>R+I>I",
         /*26*/"ZC>C+S>R*>R+H>R*>R*>R*>R",/*27*/"ZH>R*>R*>R*>R",
         /*28*/"ZH>R*>R*>R*>R+H>R*>R*>R*>R", /*29*/"GCC>C@>R",/*30*/"GBC>C@>R",
         /*31*/"GC>C+I>I@>R", /*32*/"GC>C+H>R*>R*>R*>R@>R",/*33*/"GL>E+S>R*>R+I>I@>R",
         /*34*/"GL>L+S>R*>R+I>I@>R", /*35*/"GL>E+S>R*>R+H>R*>R*>R*>R@>R",
         /*36*/"GL>L+S>R*>R+H>R*>R*>R*>R@>R",/*37*/"GI>I@>R", /*38*/"GH>R*>R*>R*>R@>R",
         /*39*/"GH>R*>R*>R*>R+H>R*>R*>R*>R@>R",/*40*/"HK>K",/*41*/"HZ>Z",
         /*42*/"HA>A",/*43*/"HAQ>Q",/*44*/"T>T",
         /*45*/"H>R*>R*>R*>R*>R",/*46*/"RT>R*>R",/*47*/"HW>W",
         /*48*/"HM>M",/*49*/"HN>N",/*50*/"CR>R",/*51*/"IQ>B",/*52*/"CQ>D",
         /*53*/"GL>E@>R@>R",/*54*/"GDF>R*>R@>R@>R",/*55*/"GDT>R*>R@>R@>R",
         /*56*/"TU>R*>R*>R*>R",/*57*/"TD>R*>R*>R*>R",/*58*/"HR>R*>R*>R"};
// 各种类型的截面编号顺序和对应的说明字符串，/**/之间的数字为函数DetachNumberFromString提取的类型号
// 它与SAP84说明书中的截面编号不尽相同，因为SAP84说明书中的第17,26,31,32,34号截面有等边和不等边之分
// 故这里的最大编号比SAP84中的最大编号大5(其中第58种类型SAP84暂不支持,写数据文件时须转换成11的BB类型)
const char *DSteelStrManager::SteelTypeStr[] = {/*1*/"热轧等边角钢:Lnn",
        /*2*/"热轧普通工字钢:Inn",/*3*/" 热轧普通槽钢:Cnn",
        /*4*/"两个热轧等边角钢的组合截面:2Enn@a",
        /*5*/"两个热轧不等边角钢，两长边相连的组合截面:2Lnn@a",
        /*6*/"两个热轧不等边角钢，两短边相连的组合截面:2Snn@a",
        /*7*/"两个热轧普通槽钢的组合截面:2Cnn@a",
        /*8*/"两轧制等边角钢以填块连接成十字截面:XLnn@a",
        /*9*/"四轧制等边角钢组成的十字截面:4Lnn@a",/*10*/"热轧无缝钢管或焊接钢管:Dd*t",
        /*11*/"钢板焊接成的箱形截面:BBb*t*h0*tw*b0",
        /*12*/"两热轧普通槽钢（槽对槽）与钢板焊接而成的箱形截面:BCCnn+Sb*t@a",
        /*13*/"两热轧普通槽钢（背对背）与钢板焊接而成的箱形截面:BBCnn+Sb*t@a",
        /*14*/"两热轧普通工字钢与钢板焊接而成的箱形截面:BInn+Sb*t@a",
        /*15*/"两热轧普通工字钢相焊接而成的箱形截面:BInn",
        /*16*/"两热轧普通槽钢相焊接而成的箱形截面:BCnn",
        /*17*/"两热轧等边角钢与钢板焊接而成的槽形截面:ZLnn+Sb*t@a",
        /*18*/"两热轧不等边角钢与钢板焊接而成的槽形截面:ZLnnn+Sb*t@a",
        /*19*/"热轧普通工字钢二翼缘与两块钢板焊接而成的截面:ZSb*t+Inn",
        /*20*/"两热轧普通槽钢与钢板焊接而成的截面:ZCnn+Sb*t",
        /*21*/"两热轧普通工字钢与钢板焊接而成的截面:ZInn+Sb*t",
        /*22*/"两焊接H 型钢与钢板焊接而成的截面:ZHb1*t1*b2*t2+Sb*t",
        /*23*/"热轧普通工字钢与钢板焊接而成的截面:ZSb1*t1+Sb*t+Inn",
        /*24*/"焊接H型钢与钢板焊接而成的截面:ZSb1*t1+Sb*t+Hb2*t2*b3*t3",
        /*25*/"热轧普通工字钢与热轧普通槽钢通过钢板焊接而成的截面:ZCnn1+Sb*t+Inn2",
        /*26*/"焊接H 型钢与热轧普通槽钢通过钢板焊接而成的截面:ZZCnn+Sb*t+Hb1*t1*b2*t2",
        /*27*/"钢板焊接而成的截面(两个焊接工字钢相同):ZHb1*t1*b2*t2",
        /*28*/"钢板焊接而成的截面(两个焊接工字钢不相同):ZHb1*t1*b2*t2+Hb3*t3*b4*t4",
        /*29*/"两热轧普通槽钢槽对槽构成的格构式截面:GCCnn@a",
        /*30*/"两热轧普通槽钢背对背构成的格构式截面:GBCnn@a",
        /*31*/"热轧普通槽钢与热轧普通工字钢构成的格构式截面:GCnn1+Inn2@a",
        /*32*/"热轧普通槽钢与焊接H 型钢构成的格构式截面:GCnn+Hb1*t1*b2*t2@a",
        /*33*/"热轧等边角钢与热轧普通工字钢构成的格构式截面:GLnn1+Sb*t+Inn2@a",
        /*34*/"热轧不等边角钢与热轧普通工字钢构成的格构式截面:GLnnn1+Sb*t+Inn2@a",
        /*35*/"热轧等边角钢与焊接H型钢构成的格构式截面:GLnn1+Sb*t+Hb1*t1*b2*t2@a",
        /*36*/"热轧不等边角钢与焊接H型钢构成的格构式截面:GLnnn1+Sb*t+Hb1*t1*b2*t2@a",
        /*37*/"两热轧普通工字钢构成的格构式截面:GInn@a",
        /*38*/"两焊接H型钢构成的格构式截面(两肢相等):GHb1*t1*b2*t2@a",
        /*39*/"两焊接H型钢构成的格构式截面:GHb1*t1*b2*t2+Hb3*t3*b4*t4@a",
        /*40*/"热轧宽翼缘H型钢:HKnn",			/*41*/"热轧窄翼缘H型钢:HZnn",
        /*42*/"焊接H型钢:HAnn (鞍钢规格)",		/*43*/"轻型焊接H型钢:HAQnn (鞍钢规格)",
        /*44*/"焊接T型钢:Tnn (鞍钢规格)",		/*45*/"焊接工字钢:Hb1*t1*h0*tw*b2",
        /*46*/"矩形:RTb*t",
        /*47*/"热轧宽翼缘H型钢:HWnn (美顿有限公司或马钢公司)",
        /*48*/"热轧中翼缘H型钢:HMnn (美顿有限公司或马钢公司)",
        /*49*/"热轧窄翼缘H型钢:HNnn (美顿有限公司或马钢公司)",
        /*50*/"圆形(d为直径):CRd", /*51*/"热轧轻型工字钢:IQn",/*52*/"热轧轻型槽钢:CQn",
        /*53*/"四热轧等边角钢构成的格构式截面:GLnn@a@b",
        /*54*/"四圆管构成的格构式截面:GDFd*t@a@b",
        /*55*/"三圆管构成的格构式截面:GDTd*t@a@b",
        /*56*/"钢板焊接梯形截面:TUb1*t1*h0*tw",
        /*57*/"钢板焊接倒梯形截面:TDh0*tw*b1*t1",
        /*58*/"矩形钢管:HRb*h*t"};


结果封装类的声明汇总

主类：DResult

辅助类：DFrameForce DTrussForce DCframeForce DVframeForce DPipeForce DShellForce DWallForce DSpringForce DSframeCheck DFrameRein


结果封装类的实现汇总

主类：DResult的公有成员函数 DResult的私有成员函数

辅助类：DFrameForce DTrussForce DCframeForce DVframeForce DPipeForce DShellForce DWallForce DSpringForce DSframeCheck DFrameRein