- AecXData 的 ctor/Free/CopyFrom 由头部 inline 移入 .cpp,结构体加 AECDLLIMPEXP 导出,修复其它模块构造 AecXData 时的 LNK2019。 - 抽出私有 SetXData(pszKey, xdata) 助手,替换各 SetAt 中重复的 find/Free+覆盖/insert 逻辑,并接管 xdata 所有权。 - 数组二进制块统一为 [kArrayMagic][元素类型][元素个数][数据...],元素类型 复用 AecXData::EType;新增元素类型无需再加魔数或类型标签。 - 矩阵/数组魔数集中到 .cpp 顶部常量,便于维护。 - List(CListCtrl*, int) 改为 List(std::vector<CString>&):去掉 MFC 控件与 nImage 依赖,每个元素输出 key/value 两项;CCKSXDlg::ListXDataMap 相应改为 构造 vector 后填充两列列表。
3768 lines
89 KiB
C++
3768 lines
89 KiB
C++
#include "stdafx.h"
|
||
#include "geassign.h"
|
||
#include "acutmem.h"
|
||
#include "AecDbObjXDataMap.h"
|
||
#include "AecDbObjXDataMapObj.h"
|
||
#include <algorithm>
|
||
#include "comdef.h"
|
||
#include "Base64.h"
|
||
#include "BIMEntity.h"
|
||
#include "shJson.h"
|
||
#include "Base64.h"
|
||
#include "EarThwormDef.h"
|
||
|
||
#ifdef _DEBUG
|
||
#undef THIS_FILE
|
||
static char THIS_FILE[]=__FILE__;
|
||
#define new DEBUG_NEW
|
||
#endif
|
||
|
||
#define MAP_BLOCK_BEGIN _T("TDBXDATAMAP_BLOCK_BEGIN_")
|
||
#define MAP_BLOCK_END _T("TDBXDATAMAP_BLOCK_END_")
|
||
#define DIF_VT_PT _T("$vector3d") // 设置向量是在键值pszkey后增加字符串"$vector3d",与点进行区分
|
||
#define BIM_REC_LEN _T("_`!@#$^&*BIM_REC_LEN*&^$#@!`_")
|
||
#define MAX_BINARYCHUNK 127
|
||
#define BINARY_CHUNKBLOCKS "binarychunkblocks"
|
||
#define BINARY_CHUNKBLOCKS1 "binarychunkblocks:"
|
||
|
||
#ifndef _ttof
|
||
#define _ttof(pszVal) _tcstod((pszVal), NULL)
|
||
#endif
|
||
|
||
|
||
// 文件头版本号(魔数 'AEC' + 版本),仅用于区分「有版本头 / 无版本头(老格式带 Base64 块标记)」。
|
||
const int AecDbObjXDataMap::g_nVersion = 0x41454301; // 'AEC' + 0x01
|
||
|
||
// 矩阵二进制块结构:[int 魔数][16个double],共 4+128=132 字节。
|
||
// 魔数写在块头,读取时先读一个 int:等于魔数即为新的二进制结构,否则是旧的字符串结构。
|
||
// (pData 与 pszVal 是同一个 union,不能靠它们区分,故用块头魔数)
|
||
static const int kMatrixMagic = 0x4D5458A5; // 'M''T''X' + 0xA5(非可打印,不会与字符串首字符冲突)
|
||
static const int kMatrixBinBytes = (int)(sizeof(int) + 16 * sizeof(double)); // 132
|
||
|
||
// 数组二进制块结构:[int 容器魔数][int 元素类型][int 元素个数][元素数据...]。
|
||
// 用"一个容器魔数 + 元素类型字段"来表达数组,而不是"每种元素类型一个魔数/类型标签":
|
||
// 新增元素类型(如 int/string 数组)时,只需扩展元素的编解码,无需新增魔数或类型标签。
|
||
// 元素类型沿用 AecXData::EType 的值(如 kTypeDouble / kTypePoint)。
|
||
// 数组沿用 kTypeBinary 保存(而非新增类型标签),这样可直接复用各处对 kTypeBinary 的
|
||
// 序列化处理(XData/DXF/DWG/JSON/CFile 等),无需逐个 switch 增加分支。
|
||
// 另外:XData/DXF 的二进制块本身不携带自定义标签(见 Resbuf2XDMap,二进制块统一还原为
|
||
// kTypeBinary),所以"自描述的块头"对数组是必要的,单靠 nVt 标签并不可靠。
|
||
static const int kArrayMagic = 0x41525259; // 'A''R''R''Y'
|
||
|
||
using namespace SHJson;
|
||
|
||
namespace
|
||
{
|
||
WValue& toJson(const AcGePoint3d &pt, WValue &v)
|
||
{
|
||
v.SetObject();
|
||
addMember(v, _T("x"), pt.x);
|
||
addMember(v, _T("y"), pt.y);
|
||
addMember(v, _T("z"), pt.z);
|
||
return v;
|
||
}
|
||
|
||
bool byJson(const WValue &v, AcGePoint3d &pt)
|
||
{
|
||
if (v.HasMember(_T("x")) && v.HasMember(_T("y")) && v.HasMember(_T("z")))
|
||
{
|
||
pt.x = v[_T("x")].GetDouble();
|
||
pt.y = v[_T("y")].GetDouble();
|
||
pt.z = v[_T("z")].GetDouble();
|
||
return true;
|
||
}
|
||
return false;
|
||
}
|
||
|
||
WValue& toJson(const AcGeVector3d &vt, WValue &v)
|
||
{
|
||
return toJson(AcGePoint3d(vt.x, vt.y, vt.z), v);
|
||
}
|
||
|
||
bool byJson(const WValue &v, AcGeVector3d &vt)
|
||
{
|
||
AcGePoint3d pt;
|
||
if (byJson(v, pt))
|
||
{
|
||
vt.x = pt.x;
|
||
vt.y = pt.y;
|
||
vt.z = pt.z;
|
||
}
|
||
return false;
|
||
}
|
||
|
||
WValue& toJson(const AcGeMatrix3d &mat, WValue &m)
|
||
{
|
||
m.SetObject();
|
||
|
||
AcGeVector3d x, y, z;
|
||
AcGePoint3d o;
|
||
mat.getCoordSystem(o, x, y, z);
|
||
|
||
WValue jX, jY, jZ, jO;
|
||
toJson(x, jX);
|
||
toJson(y, jY);
|
||
toJson(z, jZ);
|
||
toJson(o, jO);
|
||
|
||
addMember(m, _T("x"), jX);
|
||
addMember(m, _T("y"), jY);
|
||
addMember(m, _T("z"), jZ);
|
||
addMember(m, _T("o"), jO);
|
||
|
||
return m;
|
||
}
|
||
|
||
bool byJson(const WValue &v, AcGeMatrix3d &mat)
|
||
{
|
||
MCIt itX(v.FindMember(_T("x")));
|
||
MCIt itY(v.FindMember(_T("y")));
|
||
MCIt itZ(v.FindMember(_T("z")));
|
||
MCIt itO(v.FindMember(_T("o")));
|
||
|
||
if (itX != v.MemberEnd() && itY != v.MemberEnd() && itZ != v.MemberEnd() && itO != v.MemberEnd())
|
||
{
|
||
AcGeVector3d x, y, z;
|
||
AcGePoint3d o;
|
||
byJson(itX->value, x);
|
||
byJson(itY->value, y);
|
||
byJson(itZ->value, z);
|
||
byJson(itO->value, o);
|
||
mat.setCoordSystem(o, x, y, z);
|
||
}
|
||
return false;
|
||
}
|
||
|
||
// 矩阵内部以 [魔数][16个double] 的二进制块保存(pData, npszLen=132)。
|
||
// 只能保存文本的通道(XData/DXF/DWG/JSON等)仍按逗号分隔文本读写,用下面的函数转换。
|
||
// 判断矩阵是否为二进制块:看块头魔数;
|
||
// 注意 pData 与 pszVal 是同一个 union,不能靠它们区分,故把魔数写进块头。
|
||
bool IsMatrixBinary(const AecXData &xdata)
|
||
{
|
||
if (xdata.nVt != AecXData::kTypeMatrix || xdata.pData == NULL)
|
||
return false;
|
||
if (xdata.npszLen < (LONG_PTR)sizeof(int))
|
||
return false;
|
||
return *(const int *)xdata.pData == kMatrixMagic;
|
||
}
|
||
|
||
void MatrixToText(const AecXData &xdata, CString &sText)
|
||
{
|
||
sText.Empty();
|
||
if (xdata.nVt != AecXData::kTypeMatrix)
|
||
return;
|
||
|
||
if (IsMatrixBinary(xdata))
|
||
{
|
||
// 二进制块:[魔数][16个double] → 逗号分隔文本
|
||
const double *p = (const double *)((const int *)xdata.pData + 1);
|
||
CString sTemp;
|
||
for (int i = 0; i < 16; i++)
|
||
{
|
||
sTemp.Format(_T("%.9f"), p[i]);
|
||
if (i > 0) sText += _T(",");
|
||
sText += sTemp;
|
||
}
|
||
}
|
||
else if (xdata.pszVal != NULL)
|
||
{
|
||
// 旧的字符串形式:原样返回
|
||
sText = xdata.pszVal;
|
||
}
|
||
}
|
||
|
||
BOOL Script2StringArray(const CString &sScript, TCHAR tSpace, CStringArray &arTexts)
|
||
{
|
||
//x,y,z,d,a
|
||
int nPos = -1, nStart = 0;
|
||
CString sText;
|
||
|
||
while (TRUE)
|
||
{
|
||
nPos = sScript.Find(tSpace, nStart);
|
||
if (nPos != -1)
|
||
{
|
||
sText = sScript.Mid(nStart, nPos - nStart);
|
||
arTexts.Add(sText);
|
||
nStart = nPos + 1;
|
||
}
|
||
else
|
||
{
|
||
if (nStart <= sScript.GetLength() - 1)
|
||
{
|
||
sText = sScript.Mid(nStart);
|
||
arTexts.Add(sText);
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
return arTexts.GetSize() > 0;
|
||
}
|
||
|
||
|
||
bool TextToMatrix(const TCHAR *pszText, double *pOut)
|
||
{
|
||
if (pszText == NULL || pOut == NULL) return false;
|
||
|
||
CString sText(pszText);
|
||
CStringArray arTexts;
|
||
Script2StringArray(sText, _T(','), arTexts);
|
||
if (arTexts.GetSize() != 16) return false;
|
||
|
||
for (int i = 0; i < 16; i++)
|
||
pOut[i] = _ttof(arTexts.GetAt(i));
|
||
return true;
|
||
}
|
||
|
||
// 把 16 个 double 打包成矩阵二进制块 [魔数][16个double](调用方需保证 xdata 已清零)
|
||
void SetMatrixData(AecXData &xdata, const double *p)
|
||
{
|
||
xdata.nVt = AecXData::kTypeMatrix;
|
||
xdata.npszLen = kMatrixBinBytes;
|
||
xdata.pData = new byte[kMatrixBinBytes];
|
||
*(int *)xdata.pData = kMatrixMagic;
|
||
memcpy((int *)xdata.pData + 1, p, 16 * sizeof(double));
|
||
}
|
||
|
||
// 从 AecXData 取出 16 个 double(兼容旧的字符串形式)
|
||
bool GetMatrixData(const AecXData &xdata, double *pOut)
|
||
{
|
||
if (xdata.nVt != AecXData::kTypeMatrix || pOut == NULL) return false;
|
||
|
||
if (IsMatrixBinary(xdata))
|
||
{
|
||
memcpy(pOut, (const int *)xdata.pData + 1, 16 * sizeof(double));
|
||
return true;
|
||
}
|
||
// 兼容旧格式:逗号分隔字符串
|
||
if (xdata.pszVal != NULL)
|
||
return TextToMatrix(xdata.pszVal, pOut);
|
||
|
||
return false;
|
||
}
|
||
|
||
// 判断 kTypeBinary 数据块是否以指定魔数开头(用于区分普通二进制与数组二进制)
|
||
bool IsBinaryWithMagic(const AecXData &xdata, int nMagic)
|
||
{
|
||
if (xdata.nVt != AecXData::kTypeBinary || xdata.pData == NULL)
|
||
return false;
|
||
if (xdata.npszLen < (LONG_PTR)sizeof(int))
|
||
return false;
|
||
return *(const int *)xdata.pData == nMagic;
|
||
}
|
||
|
||
// 读取数组块头 [魔数][元素类型][元素个数],非数组块返回 false
|
||
bool GetArrayHeader(const AecXData &xdata, int &nElemVt, int &nCount)
|
||
{
|
||
if (!IsBinaryWithMagic(xdata, kArrayMagic)) return false;
|
||
if (xdata.npszLen < (LONG_PTR)(3 * sizeof(int))) return false;
|
||
|
||
const int *p = (const int *)xdata.pData;
|
||
nElemVt = p[1];
|
||
nCount = p[2];
|
||
return (nCount >= 0);
|
||
}
|
||
|
||
// 写入数组块头(调用方需保证 xdata 已清零),返回元素数据起始地址
|
||
double *SetArrayData(AecXData &xdata, int nElemVt, int nCount, int nElemBytes)
|
||
{
|
||
LONG_PTR nBytes = (LONG_PTR)3 * sizeof(int) + (LONG_PTR)nCount * nElemBytes;
|
||
|
||
xdata.nVt = AecXData::kTypeBinary;
|
||
xdata.npszLen = nBytes;
|
||
xdata.pData = new byte[nBytes];
|
||
|
||
int *p = (int *)xdata.pData;
|
||
p[0] = kArrayMagic;
|
||
p[1] = nElemVt;
|
||
p[2] = nCount;
|
||
|
||
return (double *)(p + 3);
|
||
}
|
||
|
||
// 数组元素数据起始地址(块头之后)
|
||
const double *ArrayElemPtr(const AecXData &xdata)
|
||
{
|
||
return (const double *)((const int *)xdata.pData + 3);
|
||
}
|
||
|
||
// double 数组 → 元素类型 kTypeDouble 的数组块
|
||
void SetDoubleArrayData(AecXData &xdata, const AcGeDoubleArray &arVal)
|
||
{
|
||
int nCount = arVal.length();
|
||
double *pd = SetArrayData(xdata, AecXData::kTypeDouble, nCount, (int)sizeof(double));
|
||
for (int i = 0; i < nCount; i++)
|
||
pd[i] = arVal[i];
|
||
}
|
||
|
||
// 从数组块取出 double 数组
|
||
bool GetDoubleArrayData(const AecXData &xdata, AcGeDoubleArray &arVal)
|
||
{
|
||
int nElemVt = 0, nCount = 0;
|
||
if (!GetArrayHeader(xdata, nElemVt, nCount)) return false;
|
||
if (nElemVt != AecXData::kTypeDouble) return false;
|
||
|
||
const double *pd = ArrayElemPtr(xdata);
|
||
|
||
arVal.setLogicalLength(0);
|
||
for (int i = 0; i < nCount; i++)
|
||
arVal.append(pd[i]);
|
||
return true;
|
||
}
|
||
|
||
// 点数组 → 元素类型 kTypePoint 的数组块(每个点3个double)
|
||
void SetPoint3dArrayData(AecXData &xdata, const AcGePoint3dArray &arPt)
|
||
{
|
||
int nCount = arPt.length();
|
||
double *pd = SetArrayData(xdata, AecXData::kTypePoint, nCount, (int)(3 * sizeof(double)));
|
||
for (int i = 0; i < nCount; i++)
|
||
{
|
||
pd[i * 3 + 0] = arPt[i].x;
|
||
pd[i * 3 + 1] = arPt[i].y;
|
||
pd[i * 3 + 2] = arPt[i].z;
|
||
}
|
||
}
|
||
|
||
// 从数组块取出点数组
|
||
bool GetPoint3dArrayData(const AecXData &xdata, AcGePoint3dArray &arPt)
|
||
{
|
||
int nElemVt = 0, nCount = 0;
|
||
if (!GetArrayHeader(xdata, nElemVt, nCount)) return false;
|
||
if (nElemVt != AecXData::kTypePoint) return false;
|
||
|
||
const double *pd = ArrayElemPtr(xdata);
|
||
|
||
arPt.setLogicalLength(0);
|
||
for (int i = 0; i < nCount; i++)
|
||
arPt.append(AcGePoint3d(pd[i * 3 + 0], pd[i * 3 + 1], pd[i * 3 + 2]));
|
||
return true;
|
||
}
|
||
}
|
||
|
||
AecDbObjXDataMap::AecDbObjXDataMap()
|
||
{
|
||
}
|
||
|
||
AecDbObjXDataMap::AecDbObjXDataMap(const AecDbObjXDataMap& datamap)
|
||
{
|
||
//map 互相复制(CopyFrom 内部会先 Empty 再深拷贝)
|
||
CopyFrom(&datamap);
|
||
}
|
||
|
||
AecDbObjXDataMap::~AecDbObjXDataMap()
|
||
{
|
||
Empty();
|
||
}
|
||
|
||
// 把 xdata 以 pszKey 存入(已存在则先 Free 再覆盖),并接管 xdata 的所有权:
|
||
// 存入后把源置空,避免源再次 Free 造成重复释放。
|
||
void AecDbObjXDataMap::SetXData(LPCTSTR pszKey, AecXData &xdata)
|
||
{
|
||
It it = m_xData.find(pszKey);
|
||
if (it != m_xData.end())
|
||
{
|
||
it->second.Free();
|
||
it->second = xdata;
|
||
}
|
||
else
|
||
{
|
||
m_xData.insert(std::pair<CString, AecXData>(pszKey, xdata));
|
||
}
|
||
|
||
xdata.nVt = 0;
|
||
xdata.npszLen = 0;
|
||
xdata.nVal = 0;
|
||
}
|
||
|
||
BOOL AecDbObjXDataMap::SetAt( LPCTSTR pszKey, const int &nVal )
|
||
{
|
||
if (pszKey != NULL)
|
||
{
|
||
AecXData xdata;
|
||
xdata.nVt = AecXData::kTypeInt;
|
||
xdata.nVal = nVal;
|
||
|
||
SetXData(pszKey, xdata);
|
||
return TRUE;
|
||
}
|
||
return FALSE;
|
||
}
|
||
|
||
BOOL AecDbObjXDataMap::SetAt(LPCTSTR pszKey, const Adesk::Int16 &nVal)
|
||
{
|
||
if (pszKey != NULL)
|
||
{
|
||
AecXData xdata;
|
||
xdata.nVt = AecXData::kTypeShort;
|
||
xdata.nVal = nVal;
|
||
|
||
SetXData(pszKey, xdata);
|
||
return TRUE;
|
||
}
|
||
return FALSE;
|
||
}
|
||
|
||
BOOL AecDbObjXDataMap::SetAt(LPCTSTR pszKey, const DWORD &dw)
|
||
{
|
||
if (pszKey != NULL)
|
||
{
|
||
AecXData xdata;
|
||
xdata.nVt = AecXData::kTypeInt;
|
||
xdata.nVal = dw;
|
||
|
||
SetXData(pszKey, xdata);
|
||
return TRUE;
|
||
}
|
||
return FALSE;
|
||
}
|
||
|
||
BOOL AecDbObjXDataMap::SetAt(LPCTSTR pszKey, const double &dVal)
|
||
{
|
||
if (pszKey != NULL)
|
||
{
|
||
AecXData xdata;
|
||
xdata.nVt = AecXData::kTypeDouble;
|
||
xdata.dVal[0] = dVal;
|
||
|
||
SetXData(pszKey, xdata);
|
||
return TRUE;
|
||
}
|
||
return FALSE;
|
||
}
|
||
|
||
BOOL AecDbObjXDataMap::SetAt(LPCTSTR pszKey,const AcGeDoubleArray& arVal)
|
||
{
|
||
// 整个数组保存为一个 [魔数][个数][double...] 的二进制块,避免精度丢失
|
||
if (pszKey == NULL)
|
||
return FALSE;
|
||
|
||
AecXData xdata;
|
||
SetDoubleArrayData(xdata, arVal);
|
||
|
||
SetXData(pszKey, xdata);
|
||
|
||
return TRUE;
|
||
}
|
||
BOOL AecDbObjXDataMap::SetAt(LPCTSTR pszKey,const AcGeVector3d& vt,BOOL bTransformBy)
|
||
{
|
||
/*
|
||
设置向量是在键值pszkey后增加字符串"$vector3d",与点进行区分
|
||
bTransformBy标识向量是否随cad实体所变化
|
||
*/
|
||
if (pszKey != NULL)
|
||
{
|
||
CString sTmpKey = pszKey;
|
||
sTmpKey += DIF_VT_PT;
|
||
AecXData xdata;
|
||
xdata.nVt = AecXData::kTypeVector;
|
||
if(bTransformBy)
|
||
{
|
||
// 向量随cad实体变化而改变
|
||
xdata.nVt = AecXData::kTypeVectorWorld;
|
||
}
|
||
xdata.dVal[0] = vt.x;
|
||
xdata.dVal[1] = vt.y;
|
||
xdata.dVal[2] = vt.z;
|
||
|
||
SetXData(sTmpKey, xdata);
|
||
return TRUE;
|
||
}
|
||
return FALSE;
|
||
}
|
||
|
||
BOOL AecDbObjXDataMap::SetAt(LPCTSTR pszKey,const AcGePoint3d& ptGe,BOOL bTransformBy)
|
||
{
|
||
/*
|
||
bTransformBy标识点是否随cad实体所变化
|
||
*/
|
||
if (pszKey != NULL)
|
||
{
|
||
AecXData xdata;
|
||
xdata.nVt = AecXData::kTypePoint;
|
||
if (bTransformBy)
|
||
{
|
||
// 点随cad实体变化而改变
|
||
xdata.nVt = AecXData::kTypePointWorld;
|
||
}
|
||
|
||
xdata.dVal[0] = ptGe.x;
|
||
xdata.dVal[1] = ptGe.y;
|
||
xdata.dVal[2] = ptGe.z;
|
||
|
||
SetXData(pszKey, xdata);
|
||
return TRUE;
|
||
}
|
||
return FALSE;
|
||
}
|
||
|
||
BOOL AecDbObjXDataMap::SetAt(LPCTSTR pszKey,const AcGePoint3dArray& arPt,BOOL bTransformBy)
|
||
{
|
||
// 整个点数组保存为一个 [魔数][个数][x,y,z...] 的二进制块,避免精度丢失
|
||
if (pszKey == NULL)
|
||
return FALSE;
|
||
|
||
AecXData xdata;
|
||
SetPoint3dArrayData(xdata, arPt);
|
||
|
||
SetXData(pszKey, xdata);
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
BOOL AecDbObjXDataMap::SetAt(LPCTSTR pszKey,const AcGeMatrix3d& xform)
|
||
{
|
||
if (pszKey != NULL)
|
||
{
|
||
double ar[16];
|
||
int k = 0;
|
||
for (int i = 0;i < 4;i++)
|
||
{
|
||
for (int j = 0;j < 4;j++)
|
||
{
|
||
ar[k++] = xform.entry[i][j];
|
||
}
|
||
}
|
||
|
||
AecXData xdata;
|
||
SetMatrixData(xdata, ar); // 打包成 [魔数][16个double] 的二进制块
|
||
|
||
SetXData(pszKey, xdata);
|
||
return TRUE;
|
||
}
|
||
return FALSE;
|
||
}
|
||
|
||
BOOL AecDbObjXDataMap::SetAt(LPCTSTR pszKey,void* pData,int nSize)
|
||
{
|
||
if (pszKey != NULL && nSize > 0 && pData != NULL)
|
||
{
|
||
AecXData xdata;
|
||
xdata.nVt = AecXData::kTypeBinary;
|
||
xdata.npszLen = nSize;
|
||
|
||
xdata.pData = new byte[nSize];
|
||
memcpy(xdata.pData,pData,nSize);
|
||
|
||
SetXData(pszKey, xdata);
|
||
return TRUE;
|
||
}
|
||
return FALSE;
|
||
}
|
||
|
||
CString AecDbObjXDataMap::MatrixToString(const AecXData& xdata)
|
||
{
|
||
CString sText;
|
||
MatrixToText(xdata, sText);
|
||
return sText;
|
||
}
|
||
|
||
BOOL AecDbObjXDataMap::GetAt(LPCTSTR pszKey,AcGeMatrix3d& xform) const
|
||
{
|
||
if (pszKey != NULL)
|
||
{
|
||
CIt it;
|
||
if ((it = m_xData.find(pszKey)) != m_xData.end())
|
||
{
|
||
double ar[16];
|
||
if (GetMatrixData((*it).second, ar))
|
||
{
|
||
int k = 0;
|
||
for (int i = 0;i < 4;i++)
|
||
for (int j = 0;j < 4;j++)
|
||
xform.entry[i][j] = ar[k++];
|
||
return TRUE;
|
||
}
|
||
}
|
||
}
|
||
return FALSE;
|
||
}
|
||
|
||
BOOL AecDbObjXDataMap::SetAt(LPCTSTR pszKey,LPCTSTR pszValue)
|
||
{
|
||
if (pszKey != NULL)
|
||
{
|
||
AecXData xdata;
|
||
xdata.nVt = AecXData::kTypeString;
|
||
xdata.npszLen = _tcslen(pszValue) + 1;
|
||
xdata.pszVal = new TCHAR[xdata.npszLen];
|
||
memset(xdata.pszVal, 0, xdata.npszLen * sizeof(TCHAR));
|
||
_tcsncpy_s(xdata.pszVal, xdata.npszLen, pszValue, xdata.npszLen - 1);
|
||
|
||
SetXData(pszKey, xdata);
|
||
return TRUE;
|
||
}
|
||
return FALSE;
|
||
}
|
||
|
||
BOOL AecDbObjXDataMap::SetAt(LPCTSTR pszKey,int iIndex,LPCTSTR pszValue)
|
||
{
|
||
if (pszKey != NULL)
|
||
{
|
||
CString sKey;
|
||
sKey.Format(_T("%s_%d"),pszKey,iIndex);
|
||
return SetAt(sKey,pszValue);
|
||
}
|
||
return FALSE;
|
||
}
|
||
|
||
BOOL AecDbObjXDataMap::GetAt(LPCTSTR pszKey,int iIndex,CString &sValue) const
|
||
{
|
||
if (pszKey != NULL)
|
||
{
|
||
CString sKey;
|
||
sKey.Format(_T("%s_%d"),pszKey,iIndex);
|
||
return GetAt(sKey,sValue);
|
||
}
|
||
return FALSE;
|
||
}
|
||
|
||
BOOL AecDbObjXDataMap::SetAt(LPCTSTR pszKey,int iIndex,const AecDbObjXDataMap& xDataMap)
|
||
{
|
||
//{key | type | inf}个隔开
|
||
CString sKey,sType,sInfo,sRecord,sText;
|
||
sText = _T("");
|
||
AecXData xdata;
|
||
memset(&xdata,0,sizeof(AecXData));
|
||
|
||
for (CIt it = xDataMap.m_xData.begin(); it != xDataMap.m_xData.end(); ++it)
|
||
{
|
||
xdata = (*it).second;
|
||
sKey = (*it).first;
|
||
sType = _T("");
|
||
sInfo = _T("");
|
||
|
||
switch (xdata.nVt)
|
||
{
|
||
case AecXData::kTypeShort:
|
||
{
|
||
sType.Format(_T("%d"), AecXData::kTypeShort);
|
||
sInfo.Format(_T("%d"), xdata.iVal);
|
||
sRecord.Format(_T("{%s|%s|%s}"), sKey, sType, sInfo);
|
||
sText += sRecord;
|
||
break;
|
||
}
|
||
case AecXData::kTypeInt: // 整型
|
||
{
|
||
sType.Format(_T("%d"),AecXData::kTypeInt);
|
||
sInfo.Format(_T("%d"),xdata.nVal);
|
||
sRecord.Format(_T("{%s|%s|%s}"),sKey,sType,sInfo);
|
||
sText += sRecord;
|
||
break;
|
||
}
|
||
case AecXData::kTypeSoftId:
|
||
{
|
||
sType.Format(_T("%d"),AecXData::kTypeSoftId);
|
||
sInfo.Format(_T("%d"),xdata.nVal);
|
||
sRecord.Format(_T("{%s|%s|%s}"),sKey,sType,sInfo);
|
||
sText += sRecord;
|
||
break;
|
||
}
|
||
case AecXData::kTypeHardId:
|
||
{
|
||
sType.Format(_T("%d"),AecXData::kTypeHardId);
|
||
sInfo.Format(_T("%d"),xdata.nVal);
|
||
sRecord.Format(_T("{%s|%s|%s}"),sKey,sType,sInfo);
|
||
sText += sRecord;
|
||
break;
|
||
}
|
||
case AecXData::kTypeDouble: // 浮点
|
||
{
|
||
sType.Format(_T("%d"),AecXData::kTypeDouble);
|
||
sInfo.Format(_T("%.9f"),xdata.dVal[0]);
|
||
sRecord.Format(_T("{%s|%s|%s}"),sKey,sType,sInfo);
|
||
sText += sRecord;
|
||
break;
|
||
}
|
||
case AecXData::kTypePoint: // 点
|
||
{
|
||
sType.Format(_T("%d"),AecXData::kTypePoint);
|
||
sInfo.Format(_T("%.4f,%.4f,%.4f"),xdata.dVal[0],xdata.dVal[1],xdata.dVal[2]);
|
||
sRecord.Format(_T("{%s|%s|%s}"),sKey,sType,sInfo);
|
||
sText += sRecord;
|
||
break;
|
||
}
|
||
case AecXData::kTypePointWorld: // cad变化点
|
||
{
|
||
sType.Format(_T("%d"),AecXData::kTypePointWorld);
|
||
sInfo.Format(_T("%.9f,%.9f,%.9f"),xdata.dVal[0],xdata.dVal[1],xdata.dVal[2]);
|
||
sRecord.Format(_T("{%s|%s|%s}"),sKey,sType,sInfo);
|
||
sText += sRecord;
|
||
break;
|
||
}
|
||
case AecXData::kTypeVector: // 向量
|
||
{
|
||
sType.Format(_T("%d"),AecXData::kTypeVector);
|
||
sInfo.Format(_T("%.9f,%.9f,%.9f"),xdata.dVal[0],xdata.dVal[1],xdata.dVal[2]);
|
||
sRecord.Format(_T("{%s|%s|%s}"),sKey,sType,sInfo);
|
||
sText += sRecord;
|
||
break;
|
||
}
|
||
case AecXData::kTypeVectorWorld: // 变化向量
|
||
{
|
||
sType.Format(_T("%d"),AecXData::kTypeVectorWorld);
|
||
sInfo.Format(_T("%.9f,%.9f,%.9f"),xdata.dVal[0],xdata.dVal[1],xdata.dVal[2]);
|
||
sRecord.Format(_T("{%s|%s|%s}"),sKey,sType,sInfo);
|
||
sText += sRecord;
|
||
break;
|
||
}
|
||
case AecXData::kTypeMatrix: // 矩阵
|
||
{
|
||
sType.Format(_T("%d"),AecXData::kTypeMatrix);
|
||
MatrixToText(xdata, sInfo);
|
||
sRecord.Format(_T("{%s|%s|%s}"),sKey,sType,sInfo);
|
||
sText += sRecord;
|
||
break;
|
||
}
|
||
case AecXData::kTypeBinary: // binary data
|
||
{
|
||
break;
|
||
}
|
||
case AecXData::kTypeString: // 字符串
|
||
{
|
||
sType.Format(_T("%d"),AecXData::kTypeString);
|
||
sInfo.Format(_T("%s"),xdata.pszVal);
|
||
sRecord.Format(_T("{%s|%s|%s}"),sKey,sType,sInfo);
|
||
sText += sRecord;
|
||
break;
|
||
}
|
||
break;
|
||
default:
|
||
break;
|
||
}
|
||
}
|
||
if (!sText.IsEmpty())
|
||
return SetAt(pszKey,iIndex,sText);
|
||
return FALSE;
|
||
}
|
||
|
||
BOOL AecDbObjXDataMap::ParseToRecords(CString& sText,CStringArray& arRecords) const
|
||
{
|
||
CString sRecord;
|
||
int nFr = 0,nTo = 0;
|
||
//{Key|Type|Info}...
|
||
while(TRUE)
|
||
{
|
||
nFr = sText.Find(_T("{"),0);
|
||
nTo = sText.Find(_T("}"),0);
|
||
if (nFr == 0 && nTo > 0)
|
||
{
|
||
sRecord = sText.Mid(nFr,nTo + 1);
|
||
sRecord.TrimLeft(_T("{"));
|
||
sRecord.TrimRight(_T("}"));
|
||
arRecords.Add(sRecord);
|
||
|
||
if (nTo + 1 < sText.GetLength())
|
||
{
|
||
sRecord = sText.Mid(nTo + 1);
|
||
sText = sRecord;
|
||
}
|
||
else
|
||
{
|
||
break;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
break;
|
||
}
|
||
}
|
||
return arRecords.GetSize() > 0;
|
||
}
|
||
|
||
BOOL AecDbObjXDataMap::ExtractRecord(CString& sRecord,CString& sKey,CString& sType,CString& sInfo) const
|
||
{
|
||
//Key|int|Info
|
||
int nFr = sRecord.Find(_T("|"),0);
|
||
if (nFr != -1)
|
||
{
|
||
CString sTemp;
|
||
sKey = sRecord.Mid(0,nFr);
|
||
if (nFr + 1 < sRecord.GetLength())
|
||
{
|
||
sTemp = sRecord.Mid(nFr + 1);
|
||
sRecord = sTemp;
|
||
|
||
nFr = sRecord.Find(_T("|"),0);
|
||
if (nFr != -1)
|
||
{
|
||
sType = sRecord.Mid(0,nFr);
|
||
if (nFr + 1 < sRecord.GetLength())
|
||
{
|
||
sInfo = sRecord.Mid(nFr + 1);
|
||
return TRUE;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
return FALSE;
|
||
}
|
||
|
||
BOOL AecDbObjXDataMap::StringToAcGePoint3d(CString& sText,AcGePoint3d& ptGe) const
|
||
{
|
||
//x,y,z
|
||
CString sX,sY,sZ;
|
||
|
||
int nFr = sText.Find(_T(","),0);
|
||
if (nFr != -1)
|
||
{
|
||
CString sTemp;
|
||
sX = sText.Mid(0,nFr);
|
||
if (nFr + 1 < sText.GetLength())
|
||
{
|
||
sTemp = sText.Mid(nFr + 1);
|
||
sText = sTemp;
|
||
|
||
nFr = sText.Find(_T(","),0);
|
||
if (nFr != -1)
|
||
{
|
||
sY = sText.Mid(0,nFr);
|
||
if (nFr + 1 < sText.GetLength())
|
||
{
|
||
sZ = sText.Mid(nFr + 1);
|
||
ptGe.set(_ttof(sX),_ttof(sY),_ttof(sZ));
|
||
return TRUE;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
return FALSE;
|
||
}
|
||
|
||
BOOL AecDbObjXDataMap::StringToAcGeVector3d(CString& sText,AcGeVector3d& vt) const
|
||
{
|
||
//x,y,z
|
||
AcGePoint3d ptGe;
|
||
if (StringToAcGePoint3d(sText,ptGe))
|
||
{
|
||
vt = ptGe.asVector();
|
||
return TRUE;
|
||
}
|
||
return FALSE;
|
||
}
|
||
|
||
BOOL AecDbObjXDataMap::GetAt(LPCTSTR pszKey,int iIndex,AecDbObjXDataMap& xDataMap) const
|
||
{
|
||
CString sKey,sType,sInfo,sText,sRecord;
|
||
AcGePoint3d ptGe;
|
||
AcGeVector3d vt;
|
||
BOOL bSuccess = FALSE;
|
||
AcDbObjectId id;
|
||
|
||
if (GetAt(pszKey,iIndex,sText))
|
||
{
|
||
sText.TrimLeft();
|
||
sText.TrimRight();
|
||
|
||
if (sText.GetLength() > 1)
|
||
{
|
||
CStringArray arRecords;
|
||
bSuccess = ParseToRecords(sText,arRecords);
|
||
|
||
for (int i = 0;i < arRecords.GetSize();i++)
|
||
{
|
||
sRecord = arRecords.GetAt(i);
|
||
if (ExtractRecord(sRecord,sKey,sType,sInfo))
|
||
{
|
||
int nVt = _ttoi(sType);
|
||
switch (nVt)
|
||
{
|
||
case AecXData::kTypeShort:
|
||
{
|
||
xDataMap.SetAt(sKey, (short)_ttoi(sInfo));
|
||
break;
|
||
}
|
||
case AecXData::kTypeInt: // 整型
|
||
{
|
||
xDataMap.SetAt(sKey,_ttoi(sInfo));
|
||
break;
|
||
}
|
||
case AecXData::kTypeSoftId:
|
||
{
|
||
id.setFromOldId((INT_PTR)_ttoi(sInfo));
|
||
xDataMap.SetAt(sKey,id);
|
||
break;
|
||
}
|
||
case AecXData::kTypeHardId:
|
||
{
|
||
id.setFromOldId((INT_PTR)_ttoi(sInfo));
|
||
xDataMap.SetAt(sKey,id,FALSE);
|
||
break;
|
||
}
|
||
case AecXData::kTypeDouble: // 浮点
|
||
{
|
||
xDataMap.SetAt(sKey,_ttof(sInfo));
|
||
break;
|
||
}
|
||
case AecXData::kTypePoint: // 点
|
||
{
|
||
if (StringToAcGePoint3d(sInfo,ptGe))
|
||
{
|
||
xDataMap.SetAt(sKey,ptGe);
|
||
}
|
||
break;
|
||
}
|
||
case AecXData::kTypePointWorld: // cad变化点
|
||
{
|
||
if (StringToAcGePoint3d(sInfo,ptGe))
|
||
{
|
||
xDataMap.SetAt(sKey,ptGe,TRUE);
|
||
}
|
||
break;
|
||
}
|
||
case AecXData::kTypeVector: // 向量
|
||
{
|
||
if (StringToAcGeVector3d(sInfo,vt))
|
||
{
|
||
sKey.Replace(DIF_VT_PT,_T(" "));
|
||
sKey.TrimRight();
|
||
xDataMap.SetAt(sKey,vt);
|
||
}
|
||
break;
|
||
}
|
||
case AecXData::kTypeVectorWorld: // 变化向量
|
||
{
|
||
if (StringToAcGeVector3d(sInfo,vt))
|
||
{
|
||
sKey.Replace(DIF_VT_PT,_T(" "));
|
||
sKey.TrimRight();
|
||
xDataMap.SetAt(sKey,vt,TRUE);
|
||
}
|
||
break;
|
||
}
|
||
case AecXData::kTypeMatrix: //矩阵
|
||
{
|
||
double ar[16];
|
||
if (TextToMatrix(sInfo, ar))
|
||
{
|
||
AcGeMatrix3d xf;
|
||
int k = 0;
|
||
for (int i = 0;i < 4;i++)
|
||
for (int j = 0;j < 4;j++)
|
||
xf.entry[i][j] = ar[k++];
|
||
xDataMap.SetAt(sKey, xf);
|
||
}
|
||
break;
|
||
}
|
||
case AecXData::kTypeBinary: //binary data
|
||
{
|
||
break;
|
||
}
|
||
case AecXData::kTypeString: // 字符串
|
||
{
|
||
xDataMap.SetAt(sKey,sInfo);
|
||
break;
|
||
}
|
||
break;
|
||
default:
|
||
break;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
//按照常规处理
|
||
xDataMap.SetAt(pszKey,iIndex,sText);
|
||
bSuccess = TRUE;
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
//按照常规处理
|
||
xDataMap.SetAt(pszKey,iIndex,sText);
|
||
bSuccess = TRUE;
|
||
}
|
||
}
|
||
return bSuccess;
|
||
}
|
||
|
||
BOOL AecDbObjXDataMap::SetAt(LPCTSTR pszKey, const AecDbObjXDataMap& xDataMap)
|
||
{
|
||
// 把整个子 map 按二进制格式序列化,作为单个二进制块(kTypeBinary)保存,
|
||
// 这样矩阵/数组等二进制数据也能无损地随子 map 一起保存。
|
||
if (pszKey == NULL)
|
||
return FALSE;
|
||
|
||
CMemFile mf;
|
||
if (!xDataMap.Write(&mf, FALSE))
|
||
return FALSE;
|
||
|
||
UINT nLen = (UINT)mf.GetLength();
|
||
if (nLen == 0)
|
||
return FALSE;
|
||
|
||
byte *pBuf = new byte[nLen];
|
||
mf.SeekToBegin();
|
||
mf.Read(pBuf, nLen);
|
||
|
||
BOOL bOk = SetAt(pszKey, pBuf, (int)nLen);
|
||
|
||
delete[] pBuf;
|
||
return bOk;
|
||
}
|
||
|
||
BOOL AecDbObjXDataMap::GetAt(LPCTSTR pszKey, AecDbObjXDataMap& xDataMap)
|
||
{
|
||
// 取出二进制块并按二进制格式反序列化回子 map
|
||
void *pData = NULL;
|
||
int nSize = 0;
|
||
if (!GetAt(pszKey, pData, nSize))
|
||
return FALSE;
|
||
|
||
CMemFile mf((BYTE *)pData, (UINT)nSize);
|
||
mf.SeekToBegin();
|
||
BOOL bOk = xDataMap.Read(&mf, FALSE);
|
||
|
||
delete[] (byte *)pData;
|
||
return bOk;
|
||
}
|
||
|
||
BOOL AecDbObjXDataMap::SetAt(LPCTSTR pszKey,const AcDbObjectId& id,BOOL bIsSoft)
|
||
{
|
||
if (pszKey != NULL)
|
||
{
|
||
AecXData xdata;
|
||
xdata.nVt = AecXData::kTypeSoftId;
|
||
if (!bIsSoft) xdata.nVt = AecXData::kTypeHardId;
|
||
xdata.nVal = id.asOldId();
|
||
SetXData(pszKey, xdata);
|
||
return TRUE;
|
||
}
|
||
return FALSE;
|
||
}
|
||
|
||
BOOL AecDbObjXDataMap::SetAt(LPCTSTR pszKey,const AcDbHandle& handle)
|
||
{
|
||
if (pszKey != NULL)
|
||
{
|
||
TCHAR szHandleStr[19];
|
||
memset(szHandleStr,0,sizeof(szHandleStr) );
|
||
handle.getIntoAsciiBuffer(szHandleStr);
|
||
|
||
LPCTSTR pszVal = szHandleStr;
|
||
return SetAt(pszKey,pszVal);
|
||
}
|
||
return FALSE;
|
||
}
|
||
|
||
BOOL AecDbObjXDataMap::SetAt(LPCTSTR pszKey,const AecXData& XData)
|
||
{
|
||
if (pszKey == NULL) return FALSE;
|
||
|
||
It it = m_xData.find(pszKey);
|
||
if (it != m_xData.end()) //找到
|
||
{
|
||
// 已存在:原地深拷贝覆盖(释放旧资源,允许类型变化)
|
||
return it->second.CopyFrom(XData) ? TRUE : FALSE;
|
||
}
|
||
|
||
// 未找到:先深拷贝再插入,避免与源共享字符串/二进制缓冲
|
||
AecXData xdata;
|
||
xdata.CopyFrom(XData);
|
||
|
||
std::pair<CString,AecXData> pa(pszKey,xdata);
|
||
m_xData.insert(pa);
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
BOOL AecDbObjXDataMap::GetAt(LPCTSTR pszKey,AecXData& XData) const
|
||
{
|
||
if (pszKey != NULL)
|
||
{
|
||
CIt it;
|
||
if ((it = m_xData.find(pszKey)) != m_xData.end())
|
||
{
|
||
XData = (*it).second;
|
||
return TRUE;
|
||
}
|
||
}
|
||
return FALSE;
|
||
}
|
||
|
||
BOOL AecDbObjXDataMap::GetAt(LPCTSTR pszKey,void*& pData,int& nSize) const
|
||
{
|
||
if (pszKey != NULL)
|
||
{
|
||
AecXData XData;
|
||
CIt it;
|
||
if ((it = m_xData.find(pszKey)) != m_xData.end())
|
||
{
|
||
XData = (*it).second;
|
||
if (XData.nVt == AecXData::kTypeBinary )
|
||
{
|
||
if (XData.npszLen > 0)
|
||
{
|
||
pData = new byte[XData.npszLen];
|
||
memcpy(pData,XData.pData,XData.npszLen);
|
||
nSize = XData.npszLen;
|
||
return TRUE;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
return FALSE;
|
||
}
|
||
|
||
BOOL AecDbObjXDataMap::GetAt(LPCTSTR pszKey, DWORD & dw) const
|
||
{
|
||
if (pszKey != NULL)
|
||
{
|
||
CIt it;
|
||
if ((it = m_xData.find(pszKey)) != m_xData.end())
|
||
{
|
||
AecXData xdata = (*it).second;
|
||
|
||
if (xdata.nVt == AecXData::kTypeInt)
|
||
{
|
||
dw = (int)xdata.nVal;
|
||
return TRUE;
|
||
}
|
||
}
|
||
}
|
||
return FALSE;
|
||
}
|
||
|
||
BOOL AecDbObjXDataMap::GetAt(LPCTSTR pszKey,int& nVal) const
|
||
{
|
||
if (pszKey != NULL)
|
||
{
|
||
CIt it;
|
||
if ((it = m_xData.find(pszKey)) != m_xData.end())
|
||
{
|
||
AecXData xdata = (*it).second;
|
||
|
||
if (xdata.nVt == AecXData::kTypeInt)
|
||
{
|
||
nVal = (int)xdata.nVal;
|
||
return TRUE;
|
||
}
|
||
}
|
||
}
|
||
return FALSE;
|
||
}
|
||
|
||
BOOL AecDbObjXDataMap::GetAt(LPCTSTR pszKey, short &nVal) const
|
||
{
|
||
if (pszKey != NULL)
|
||
{
|
||
CIt it;
|
||
if ((it = m_xData.find(pszKey)) != m_xData.end())
|
||
{
|
||
AecXData xdata = (*it).second;
|
||
|
||
if (xdata.nVt == AecXData::kTypeShort)//优先
|
||
{
|
||
nVal = (short)xdata.iVal;
|
||
return TRUE;
|
||
}
|
||
}
|
||
}
|
||
return FALSE;
|
||
}
|
||
|
||
BOOL AecDbObjXDataMap::GetAt(LPCTSTR pszKey,double& dVal) const
|
||
{
|
||
if (pszKey != NULL)
|
||
{
|
||
CIt it;
|
||
if ((it = m_xData.find(pszKey)) != m_xData.end())
|
||
{
|
||
AecXData xdata = (*it).second;
|
||
|
||
if (xdata.nVt == AecXData::kTypeDouble)
|
||
{
|
||
dVal = xdata.dVal[0];
|
||
return TRUE;
|
||
}
|
||
else if (xdata.nVt == AecXData::kTypeInt)
|
||
{
|
||
dVal = 1.0 * xdata.nVal;
|
||
return TRUE;
|
||
}
|
||
else if (xdata.nVt == AecXData::kTypeShort)//优先
|
||
{
|
||
dVal = 1.0 * xdata.iVal;
|
||
return TRUE;
|
||
}
|
||
}
|
||
}
|
||
return FALSE;
|
||
}
|
||
|
||
BOOL AecDbObjXDataMap::GetAt(LPCTSTR pszKey,AcGeDoubleArray& arVal) const
|
||
{
|
||
arVal.setLogicalLength(0);
|
||
if (pszKey == NULL)
|
||
return FALSE;
|
||
|
||
// 新格式:单个二进制块([魔数][个数][double...])
|
||
CIt it = m_xData.find(pszKey);
|
||
if (it != m_xData.end() && GetDoubleArrayData((*it).second, arVal))
|
||
return (arVal.length() > 0);
|
||
|
||
// 兼容旧格式:pszKey0, pszKey1, ...
|
||
CString sSubKey;
|
||
double dVal;
|
||
int nIndex = 0;
|
||
sSubKey.Format(_T("%s%d"),pszKey,nIndex++);
|
||
while(GetAt(sSubKey,dVal))
|
||
{
|
||
arVal.append(dVal);
|
||
sSubKey.Format(_T("%s%d"),pszKey,nIndex++);
|
||
}
|
||
|
||
return (arVal.length() > 0);
|
||
}
|
||
BOOL AecDbObjXDataMap::GetAt(LPCTSTR pszKey,AcGeVector3d& vt) const
|
||
{
|
||
/*
|
||
由于设置向量是将键值pszkey后增加字符串"$vector3d",
|
||
故获取向量时在键值pszkey后增加字符串"$vector3d"
|
||
*/
|
||
if (pszKey != NULL)
|
||
{
|
||
CString sTmpKey = pszKey;
|
||
sTmpKey += DIF_VT_PT;
|
||
CIt it;
|
||
if ((it = m_xData.find(sTmpKey)) != m_xData.end())
|
||
{
|
||
AecXData xdata = (*it).second;
|
||
|
||
if ((xdata.nVt == AecXData::kTypeVector)
|
||
|| (xdata.nVt == (AecXData::kTypeVectorWorld)))
|
||
{
|
||
vt.x = xdata.dVal[0];
|
||
vt.y = xdata.dVal[1];
|
||
vt.z = xdata.dVal[2];
|
||
|
||
return TRUE;
|
||
}
|
||
}
|
||
}
|
||
return FALSE;
|
||
}
|
||
|
||
BOOL AecDbObjXDataMap::GetAt(LPCTSTR pszKey,AcGePoint3d& ptGe) const
|
||
{
|
||
if (pszKey != NULL)
|
||
{
|
||
CIt it;
|
||
if ((it = m_xData.find(pszKey)) != m_xData.end())
|
||
{
|
||
AecXData xdata = (*it).second;
|
||
|
||
if ( (xdata.nVt == AecXData::kTypePoint)
|
||
|| (xdata.nVt == AecXData::kTypePointWorld))
|
||
{
|
||
ptGe.x = xdata.dVal[0];
|
||
ptGe.y = xdata.dVal[1];
|
||
ptGe.z = xdata.dVal[2];
|
||
|
||
return TRUE;
|
||
}
|
||
}
|
||
}
|
||
return FALSE;
|
||
}
|
||
|
||
BOOL AecDbObjXDataMap::GetAt(LPCTSTR pszKey,AcGePoint3dArray& arPt) const
|
||
{
|
||
arPt.setLogicalLength(0);
|
||
if (pszKey == NULL)
|
||
return FALSE;
|
||
|
||
// 新格式:单个二进制块([魔数][个数][x,y,z...])
|
||
CIt it = m_xData.find(pszKey);
|
||
if (it != m_xData.end() && GetPoint3dArrayData((*it).second, arPt))
|
||
return (arPt.length() > 0);
|
||
|
||
// 兼容旧格式:pszKey0, pszKey1, ...
|
||
CString sSubKey;
|
||
AcGePoint3d pt;
|
||
int nIndex = 0;
|
||
sSubKey.Format(_T("%s%d"),pszKey,nIndex++);
|
||
while(GetAt(sSubKey,pt))
|
||
{
|
||
arPt.append(pt);
|
||
sSubKey.Format(_T("%s%d"),pszKey,nIndex++);
|
||
}
|
||
|
||
return (arPt.length() > 0);
|
||
}
|
||
|
||
BOOL AecDbObjXDataMap::GetAt(LPCTSTR pszKey,CString &sValue) const
|
||
{
|
||
if (pszKey != NULL)
|
||
{
|
||
CIt it;
|
||
if ((it = m_xData.find(pszKey)) != m_xData.end())
|
||
{
|
||
AecXData xdata = (*it).second;
|
||
|
||
if (xdata.nVt == AecXData::kTypeString)
|
||
{
|
||
sValue = xdata.pszVal;
|
||
return TRUE;
|
||
}
|
||
else if (xdata.nVt == AecXData::kTypeMatrix)
|
||
{
|
||
MatrixToText(xdata, sValue);
|
||
return TRUE;
|
||
}
|
||
else if (xdata.nVt == AecXData::kTypeInt || xdata.nVt == AecXData::kTypeInt64)
|
||
{
|
||
sValue.Format(_T("%d"), xdata.nVal);
|
||
return TRUE;
|
||
}
|
||
else if (xdata.nVt == AecXData::kTypeShort)
|
||
{
|
||
sValue.Format(_T("%d"), xdata.iVal);
|
||
return TRUE;
|
||
}
|
||
else if (xdata.nVt == AecXData::kTypeDouble)
|
||
{
|
||
sValue.Format(_T("%.9f"), xdata.dVal[0]);
|
||
sValue.TrimRight(_T('0'));
|
||
return TRUE;
|
||
}
|
||
}
|
||
}
|
||
return FALSE;
|
||
}
|
||
|
||
BOOL AecDbObjXDataMap::GetAt(LPCTSTR pszKey,AcDbObjectId& id) const
|
||
{
|
||
if (pszKey != NULL)
|
||
{
|
||
CIt it;
|
||
if ((it = m_xData.find(pszKey) ) != m_xData.end())
|
||
{
|
||
AecXData xdata = (*it).second;
|
||
|
||
if (xdata.nVt == AecXData::kTypeSoftId ||
|
||
xdata.nVt == AecXData::kTypeHardId)
|
||
{
|
||
id.setFromOldId(xdata.nVal);
|
||
return TRUE;
|
||
}
|
||
}
|
||
}
|
||
return FALSE;
|
||
}
|
||
|
||
BOOL AecDbObjXDataMap::GetAt(LPCTSTR pszKey,AcDbHandle& handle,AcDbDatabase* pDb/* = NULL*/) const
|
||
{
|
||
CString sVal;
|
||
if (GetAt(pszKey,sVal))
|
||
{
|
||
AcDbHandle handleT((LPCTSTR)sVal);
|
||
|
||
if (pDb == NULL)
|
||
pDb = acdbCurDwg();
|
||
|
||
if (pDb != NULL)
|
||
{
|
||
AcDbObjectId id;
|
||
if ( Acad::eOk == pDb->getAcDbObjectId(id,false,handleT) )
|
||
{
|
||
handle = handleT;
|
||
return TRUE;
|
||
}
|
||
}
|
||
}
|
||
return FALSE;
|
||
}
|
||
|
||
BOOL AecDbObjXDataMap::GetAt(LPCTSTR pszKey, TCHAR * psz, const int & len) const
|
||
{
|
||
CString str(_T(""));
|
||
if (GetAt(pszKey, str))
|
||
{
|
||
if (str.GetLength() < len && psz)
|
||
{
|
||
::memset(psz, 0, len * sizeof(TCHAR));
|
||
_tcsncpy_s(psz, len, str, len-1);
|
||
return TRUE;
|
||
}
|
||
}
|
||
return FALSE;
|
||
}
|
||
|
||
BOOL AecDbObjXDataMap::HasKey(LPCTSTR pszKey,int& nVt) const
|
||
{
|
||
if (pszKey != NULL)
|
||
{
|
||
CString sTmpKey = pszKey;
|
||
sTmpKey += DIF_VT_PT;
|
||
|
||
CIt it;
|
||
it = m_xData.find(pszKey);
|
||
|
||
if (it != m_xData.end())
|
||
{
|
||
AecXData xdata = it->second;//m_xData[pszKey];
|
||
nVt = xdata.nVt;
|
||
return TRUE;
|
||
}
|
||
|
||
it = m_xData.find(sTmpKey);
|
||
if( it != m_xData.end())
|
||
{
|
||
AecXData xdata = it->second;//m_xData[sTmpKey];
|
||
nVt = xdata.nVt;
|
||
return TRUE;
|
||
}
|
||
else
|
||
{
|
||
return FALSE;
|
||
}
|
||
}
|
||
return FALSE;
|
||
}
|
||
|
||
void AecDbObjXDataMap::Empty()
|
||
{
|
||
for (It it = m_xData.begin(); it != m_xData.end(); ++it)
|
||
it->second.Free();
|
||
m_xData.clear();
|
||
}
|
||
|
||
BOOL AecDbObjXDataMap::RemoveAt(LPCTSTR pszKey)
|
||
{
|
||
if (!pszKey) return FALSE;
|
||
|
||
CString sTmpKey = pszKey;
|
||
sTmpKey += DIF_VT_PT;
|
||
It it = m_xData.find(pszKey);
|
||
It it1 = m_xData.find(sTmpKey);
|
||
|
||
BOOL bRemoved = FALSE;
|
||
if (it != m_xData.end())
|
||
{
|
||
it->second.Free(); // 释放内存
|
||
m_xData.erase(it);
|
||
bRemoved = TRUE;
|
||
}
|
||
|
||
if (it1 != m_xData.end())
|
||
{
|
||
it1->second.Free(); // 释放内存
|
||
m_xData.erase(it1);
|
||
bRemoved = TRUE;
|
||
}
|
||
|
||
return bRemoved;
|
||
}
|
||
|
||
BOOL AecDbObjXDataMap::RemoveAt(LPCTSTR pszKey,int nIndex)
|
||
{
|
||
if (pszKey != NULL)
|
||
{
|
||
CString sKey;
|
||
sKey.Format(_T("%s_%d"),pszKey,nIndex);
|
||
return RemoveAt(sKey);
|
||
}
|
||
return FALSE;
|
||
}
|
||
|
||
AecDbObjXDataMap& AecDbObjXDataMap::operator = (const AecDbObjXDataMap& srcMap)
|
||
{
|
||
//map 互相复制(CopyFrom 内部已处理 this == &srcMap 与 Empty)
|
||
CopyFrom(&srcMap);
|
||
return *this;
|
||
}
|
||
|
||
BOOL AecDbObjXDataMap::CopyFrom(const AecDbObjXDataMap* pSrc)
|
||
{
|
||
if (pSrc == NULL || this == pSrc)
|
||
return FALSE;
|
||
|
||
//map 互相复制:SetAt 内部走 AecXData::CopyFrom 深拷贝,
|
||
//字符串/矩阵/二进制都会重新分配,不与源共享缓冲
|
||
Empty();
|
||
|
||
for (CIt it = pSrc->m_xData.begin();it != pSrc->m_xData.end();it++)
|
||
{
|
||
SetAt((*it).first,(*it).second);
|
||
}
|
||
return TRUE;
|
||
}
|
||
|
||
BOOL AecDbObjXDataMap::AppendFrom(const AecDbObjXDataMap* pSrc)
|
||
{
|
||
if (pSrc == NULL || this == pSrc)
|
||
return FALSE;
|
||
|
||
//合并:同名键以 pSrc 的值覆盖(SetAt 语义)
|
||
for (CIt it = pSrc->m_xData.begin();it != pSrc->m_xData.end();it++)
|
||
{
|
||
SetAt((*it).first,(*it).second);
|
||
}
|
||
return TRUE;
|
||
}
|
||
|
||
AecDbObjXDataMap::It AecDbObjXDataMap::Begin()
|
||
{
|
||
return m_xData.begin();
|
||
}
|
||
|
||
BOOL AecDbObjXDataMap::GetNext(It& it,CString& sKey,AecXData& xData)
|
||
{
|
||
if (it != m_xData.end())
|
||
{
|
||
if ((*it).second.nVt == AecXData::kTypeString)
|
||
{
|
||
if ((*it).second.npszLen > 0 && (*it).second.pszVal != NULL)
|
||
{
|
||
memset(&xData, 0, sizeof(AecXData));
|
||
xData.nVt = AecXData::kTypeString;
|
||
xData.npszLen = (*it).second.npszLen;//!!!
|
||
xData.pszVal = new TCHAR[xData.npszLen];//!!!
|
||
_tcsncpy_s(xData.pszVal, xData.npszLen, (*it).second.pszVal, xData.npszLen - 1);//!!!
|
||
}
|
||
else
|
||
{
|
||
//异常-->AecXData::kTypeInt 0 代替
|
||
memset(&xData, 0, sizeof(AecXData));
|
||
xData.nVt = AecXData::kTypeInt;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
xData = (*it).second;
|
||
sKey = (*it).first;
|
||
}
|
||
++it;
|
||
return TRUE;
|
||
}
|
||
return FALSE;
|
||
}
|
||
|
||
AecDbObjXDataMap::It AecDbObjXDataMap::End()
|
||
{
|
||
return m_xData.end();
|
||
}
|
||
|
||
void AecDbObjXDataMap::List() const
|
||
{
|
||
AecXData xdata;
|
||
int nVt = -1;
|
||
AcGePoint3d ptVal;
|
||
AcGeVector3d vt;
|
||
AcDbObjectId id;
|
||
|
||
for (CIt it = m_xData.begin(); it != m_xData.end(); ++it)
|
||
{
|
||
xdata = (*it).second;
|
||
nVt = xdata.nVt;
|
||
|
||
acutPrintf(_T("\n%s:"),(const TCHAR *)(*it).first);
|
||
|
||
switch (nVt)
|
||
{
|
||
case AecXData::kTypeShort:
|
||
acutPrintf(_T("%d : VT_I2"), (int)xdata.iVal);
|
||
break;
|
||
case AecXData::kTypeInt: // 整型
|
||
acutPrintf(_T("%d : VT_I4"),(int)xdata.nVal);
|
||
break;
|
||
case AecXData::kTypeSoftId: //s id
|
||
#ifndef _WIN64
|
||
acutPrintf(_T("%ld : VT_UI4"),xdata.nVal);
|
||
#else
|
||
acutPrintf(_T("%d : VT_UI4"),xdata.nVal);
|
||
#endif
|
||
break;
|
||
case AecXData::kTypeHardId: //h id
|
||
#ifndef _WIN64
|
||
acutPrintf(_T("%ld : VT_UI4"),xdata.nVal);
|
||
#else
|
||
acutPrintf(_T("%d : VT_UI4"),xdata.nVal);
|
||
#endif
|
||
break;
|
||
case AecXData::kTypeDouble: // 浮点
|
||
acutPrintf(_T("%.9f : VT_R8"),xdata.dVal[0]);
|
||
break;
|
||
case AecXData::kTypePoint: // 点
|
||
acutPrintf(_T("%.9f,%.9f,%.9f : Point3d"),xdata.dVal[0],xdata.dVal[1],xdata.dVal[2]);
|
||
break;
|
||
case AecXData::kTypePointWorld: // cad变化点
|
||
acutPrintf(_T("%.9f,%.9f,%.9f : Point3d"),xdata.dVal[0],xdata.dVal[1],xdata.dVal[2]);
|
||
break;
|
||
case AecXData::kTypeVector: // 向量
|
||
acutPrintf(_T("%.9f,%.9f,%.9f : Vector3d"),xdata.dVal[0],xdata.dVal[1],xdata.dVal[2]);
|
||
break;
|
||
case AecXData::kTypeVectorWorld: // 变化向量
|
||
acutPrintf(_T("%.9f,%.9f,%.9f : Vector3d"),xdata.dVal[0],xdata.dVal[1],xdata.dVal[2]);
|
||
break;
|
||
case AecXData::kTypeMatrix: // 矩阵
|
||
{
|
||
CString sMat;
|
||
MatrixToText(xdata, sMat);
|
||
acutPrintf(_T("%s : Matrix3d"),(LPCTSTR)sMat);
|
||
}
|
||
break;
|
||
case AecXData::kTypeBinary: // binarydata
|
||
acutPrintf(_T("%p:%d bytes : Binary data"),xdata.pData,xdata.npszLen);
|
||
break;
|
||
case AecXData::kTypeString: // 字符串
|
||
acutPrintf(_T("%s : String"),xdata.pszVal);
|
||
break;
|
||
default:
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
void AecDbObjXDataMap::List(std::vector<CString>& pList) const
|
||
{
|
||
AecXData xdata;
|
||
int nVt = -1;
|
||
TCHAR szData[MAX_PATH * 4];
|
||
|
||
for (CIt it = m_xData.begin(); it != m_xData.end(); ++it)
|
||
{
|
||
xdata = (*it).second;
|
||
nVt = xdata.nVt;
|
||
|
||
memset(szData, 0, sizeof(szData));
|
||
|
||
switch (nVt)
|
||
{
|
||
case AecXData::kTypeShort:
|
||
swprintf(szData, _T("%d : VT_I4"), xdata.iVal);
|
||
break;
|
||
case AecXData::kTypeInt: // 整型
|
||
swprintf(szData,_T("%d : VT_I4"), (int)xdata.nVal);
|
||
break;
|
||
case AecXData::kTypeSoftId: //s id
|
||
#ifndef _WIN64
|
||
swprintf(szData, _T("%ld : VT_UI4"), xdata.nVal);
|
||
#else
|
||
swprintf(szData, _T("%d : VT_UI4"), (int)xdata.nVal);
|
||
#endif
|
||
break;
|
||
case AecXData::kTypeHardId: //h id
|
||
#ifndef _WIN64
|
||
swprintf(szData, _T("%ld : VT_UI4"), xdata.nVal);
|
||
#else
|
||
swprintf(szData, _T("%d : VT_UI4"), (int)xdata.nVal);
|
||
#endif
|
||
break;
|
||
case AecXData::kTypeDouble: // 浮点
|
||
swprintf(szData, _T("%.3f : VT_R8"), xdata.dVal[0]);
|
||
break;
|
||
case AecXData::kTypePoint: // 点
|
||
swprintf(szData, _T("(%.3f,%.3f,%.3f) : Point3d"), xdata.dVal[0], xdata.dVal[1], xdata.dVal[2]);
|
||
break;
|
||
case AecXData::kTypePointWorld: // cad变化点
|
||
swprintf(szData, _T("(%.3f,%.3f,%.3f) : Point3d"), xdata.dVal[0], xdata.dVal[1], xdata.dVal[2]);
|
||
break;
|
||
case AecXData::kTypeVector: // 向量
|
||
swprintf(szData, _T("(%.3f,%.3f,%.3f) : Vector3d"), xdata.dVal[0], xdata.dVal[1], xdata.dVal[2]);
|
||
break;
|
||
case AecXData::kTypeVectorWorld: // 变化向量
|
||
swprintf(szData, _T("(%.3f,%.3f,%.3f) : Vector3d"), xdata.dVal[0], xdata.dVal[1], xdata.dVal[2]);
|
||
break;
|
||
case AecXData::kTypeMatrix: // 矩阵
|
||
{
|
||
CString sMat;
|
||
MatrixToText(xdata, sMat);
|
||
swprintf(szData, _T("%s : Matrix3d"), (LPCTSTR)sMat);
|
||
}
|
||
break;
|
||
case AecXData::kTypeBinary: // binarydata
|
||
swprintf(szData, _T("%p:%d bytes : Binary data"), xdata.pData, (int)xdata.npszLen);
|
||
break;
|
||
case AecXData::kTypeString: // 字符串
|
||
{
|
||
//太长...多余的截掉
|
||
if (xdata.npszLen > MAX_PATH * 4)
|
||
{
|
||
wcsncpy(szData, xdata.pszVal, MAX_PATH * 4-4);
|
||
_tcscat(szData, _T("..."));
|
||
}
|
||
else
|
||
{
|
||
swprintf(szData, _T("%s : String"), xdata.pszVal);
|
||
}
|
||
break;
|
||
}
|
||
default:
|
||
break;
|
||
}
|
||
|
||
// 每个元素占两项:先 key(名称),后 value(数据)。
|
||
pList.push_back((*it).first);
|
||
pList.push_back(szData);
|
||
}
|
||
}
|
||
|
||
static bool XDataEqu(const AecXData& xdata1,const AecXData& xdata2)
|
||
{
|
||
if (xdata1.nVt != xdata2.nVt)
|
||
return false;
|
||
|
||
|
||
switch (xdata1.nVt)
|
||
{
|
||
case AecXData::kTypeShort:
|
||
if (xdata1.iVal != xdata2.iVal)
|
||
return false;
|
||
case AecXData::kTypeInt: // 整型
|
||
case AecXData::kTypeSoftId: //s id
|
||
case AecXData::kTypeHardId: //h id
|
||
if (xdata1.nVal != xdata2.nVal)
|
||
return false;
|
||
break;
|
||
case AecXData::kTypeDouble: // 浮点
|
||
if ( fabs(xdata1.dVal[0] - xdata2.dVal[0]) > 1.e-3)
|
||
return false;
|
||
break;
|
||
case AecXData::kTypePoint: // 点
|
||
case AecXData::kTypePointWorld: // cad变化点
|
||
case AecXData::kTypeVector: // 向量
|
||
case AecXData::kTypeVectorWorld: // 变化向量
|
||
|
||
if ( fabs(xdata1.dVal[0] - xdata2.dVal[0]) > 1.e-3)
|
||
return false;
|
||
|
||
if ( fabs(xdata1.dVal[1] - xdata2.dVal[1]) > 1.e-3)
|
||
return false;
|
||
|
||
if ( fabs(xdata1.dVal[2] - xdata2.dVal[2]) > 1.e-3)
|
||
return false;
|
||
break;
|
||
case AecXData::kTypeMatrix: // 矩阵
|
||
if (xdata1.npszLen != xdata2.npszLen)
|
||
return false;
|
||
if (xdata1.pData == NULL || xdata2.pData == NULL)
|
||
return false;
|
||
if (memcmp(xdata1.pData,xdata2.pData,(size_t)xdata1.npszLen) != 0)
|
||
return false;
|
||
break;
|
||
case AecXData::kTypeBinary: // binarydata
|
||
if (xdata1.npszLen != xdata2.npszLen)
|
||
return false;
|
||
break;
|
||
case AecXData::kTypeString: // 字符串
|
||
if (_tcscmp(xdata1.pszVal,xdata2.pszVal) != 0)
|
||
return false;
|
||
break;
|
||
default:
|
||
break;
|
||
}
|
||
return true;
|
||
}
|
||
|
||
int AecDbObjXDataMap::ComparedTo(const AecDbObjXDataMap* pXDataMap) const
|
||
{
|
||
if (pXDataMap == NULL)
|
||
return 1;
|
||
|
||
if (m_xData.size() != pXDataMap->m_xData.size())
|
||
return 1;
|
||
|
||
for (CIt it1 = m_xData.begin(); it1 != m_xData.end(); ++it1)
|
||
{
|
||
CIt it2 = pXDataMap->m_xData.find(it1->first);
|
||
if (it2 == pXDataMap->m_xData.end())
|
||
{
|
||
return 1;
|
||
}
|
||
else
|
||
{
|
||
if ( !XDataEqu(it1->second,it2->second))
|
||
{
|
||
return 1;
|
||
}
|
||
}
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
Acad::ErrorStatus AecDbObjXDataMap::dxfOutFields(AcDbDxfFiler* pFiler) const
|
||
{
|
||
if (pFiler == NULL) return Acad::eInvalidInput;
|
||
|
||
AecXData xdata;
|
||
int nVt = -1;
|
||
AcGePoint3d ptVal;
|
||
AcGeVector3d vt;
|
||
AcDbObjectId id;
|
||
|
||
pFiler->writeString(AcDb::kDxfXTextString, MAP_BLOCK_BEGIN);
|
||
|
||
for (CIt it = m_xData.begin(); it != m_xData.end(); ++it)
|
||
{
|
||
xdata = (*it).second;
|
||
nVt = xdata.nVt;
|
||
pFiler->writeString(AcDb::kDxfXdAsciiString, (const TCHAR *)(*it).first);
|
||
pFiler->writeInt32(AcDb::kDxfXdInteger32, nVt);
|
||
|
||
switch (nVt)
|
||
{
|
||
case AecXData::kTypeShort:
|
||
pFiler->writeInt16(AcDb::kDxfXdInteger16, xdata.iVal);
|
||
break;
|
||
case AecXData::kTypeInt: // 整型
|
||
pFiler->writeInt32(AcDb::kDxfXdInteger32, (int)xdata.nVal);
|
||
break;
|
||
case AecXData::kTypeSoftId: //s id
|
||
id.setFromOldId(xdata.nVal);
|
||
pFiler->writeObjectId(AcDb::kDxfSoftPointerId,id);
|
||
break;
|
||
case AecXData::kTypeHardId: //h id
|
||
id.setFromOldId(xdata.nVal);
|
||
pFiler->writeObjectId(AcDb::kDxfHardPointerId,id);
|
||
break;
|
||
case AecXData::kTypeDouble: // 浮点
|
||
pFiler->writeDouble(AcDb::kDxfXdReal, xdata.dVal[0]);
|
||
break;
|
||
case AecXData::kTypePoint: // 点
|
||
ptVal.x = xdata.dVal[0];
|
||
ptVal.y = xdata.dVal[1];
|
||
ptVal.z = xdata.dVal[2];
|
||
pFiler->writePoint3d(AcDb::kDxfXdXCoord, ptVal);
|
||
break;
|
||
case AecXData::kTypePointWorld: // cad变化点
|
||
ptVal.x = xdata.dVal[0];
|
||
ptVal.y = xdata.dVal[1];
|
||
ptVal.z = xdata.dVal[2];
|
||
pFiler->writePoint3d(AcDb::kDxfXdWorldXCoord, ptVal);
|
||
break;
|
||
case AecXData::kTypeVector: // 向量
|
||
vt.x = xdata.dVal[0];
|
||
vt.y = xdata.dVal[1];
|
||
vt.z = xdata.dVal[2];
|
||
pFiler->writeVector3d(AcDb::kDxfXdXCoord, vt);
|
||
break;
|
||
case AecXData::kTypeVectorWorld: // 变化向量
|
||
vt.x = xdata.dVal[0];
|
||
vt.y = xdata.dVal[1];
|
||
vt.z = xdata.dVal[2];
|
||
pFiler->writeVector3d(AcDb::kDxfXdWorldXDir, vt);
|
||
break;
|
||
case AecXData::kTypeMatrix: // 矩阵
|
||
{
|
||
CString sMat;
|
||
MatrixToText(xdata, sMat);
|
||
pFiler->writeString(AcDb::kDxfXdAsciiString, (LPCTSTR)sMat);
|
||
}
|
||
break;
|
||
case AecXData::kTypeBinary: // binary data
|
||
{
|
||
ads_binary binary;
|
||
binary.clen = xdata.npszLen;
|
||
binary.buf = (char*)xdata.pData;
|
||
pFiler->writeBChunk(AcDb::kDxfXdBinaryChunk,binary);
|
||
}
|
||
break;
|
||
case AecXData::kTypeString: // 字符串
|
||
pFiler->writeString(AcDb::kDxfXdAsciiString, xdata.pszVal);
|
||
break;
|
||
default:
|
||
break;
|
||
}
|
||
}
|
||
pFiler->writeString(AcDb::kDxfXTextString, MAP_BLOCK_END);
|
||
|
||
return Acad::eOk;
|
||
}
|
||
|
||
Acad::ErrorStatus AecDbObjXDataMap::dxfInFields(AcDbDxfFiler* pFiler)
|
||
{
|
||
if (pFiler == NULL) return Acad::eInvalidInput;
|
||
|
||
BOOL bFinded = FALSE;
|
||
long nVt = 0;
|
||
TCHAR* pszKey = NULL;
|
||
TCHAR* pszVal = NULL;
|
||
AcGePoint3d ptVal;
|
||
AcGeVector3d vt;
|
||
CString sKey,sTag;
|
||
|
||
struct resbuf rb;
|
||
while ((pFiler->readItem(&rb)) == Acad::eOk)
|
||
{
|
||
if(rb.restype == AcDb::kDxfXdAsciiString)
|
||
{
|
||
sTag = rb.resval.rstring;
|
||
if (sTag.CompareNoCase(MAP_BLOCK_BEGIN) == 0)
|
||
{
|
||
bFinded = TRUE;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
if (!bFinded) return Acad::eOk;
|
||
|
||
int nMapUnitIndex = 0;
|
||
AcDbObjectId id;
|
||
while ((pFiler->readItem(&rb)) == Acad::eOk)
|
||
{
|
||
nMapUnitIndex++;
|
||
if(nMapUnitIndex == 1)
|
||
{
|
||
if(rb.restype == AcDb::kDxfXdAsciiString)
|
||
{
|
||
sKey = rb.resval.rstring;
|
||
continue;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
nMapUnitIndex = 0;
|
||
}
|
||
|
||
nVt = rb.restype;
|
||
|
||
switch (nVt)
|
||
{
|
||
case AecXData::kTypeShort:
|
||
SetAt(sKey, rb.resval.rint);
|
||
break;
|
||
case AecXData::kTypeInt: // 整型
|
||
SetAt(sKey,rb.resval.rlong);
|
||
break;
|
||
case AecXData::kTypeSoftId: //s id
|
||
|
||
#ifdef _WIN64
|
||
id.setFromOldId(rb.resval.mnInt64);
|
||
#else
|
||
id.setFromOldId(rb.resval.rlong);
|
||
#endif
|
||
|
||
SetAt(sKey,id);
|
||
break;
|
||
case AecXData::kTypeHardId: //h id
|
||
|
||
#ifdef _WIN64
|
||
id.setFromOldId(rb.resval.mnInt64);
|
||
#else
|
||
id.setFromOldId(rb.resval.rlong);
|
||
#endif
|
||
|
||
SetAt(sKey,id,FALSE);
|
||
break;
|
||
case AecXData::kTypeDouble: // 浮点
|
||
SetAt(sKey,rb.resval.rreal);
|
||
break;
|
||
case AecXData::kTypePoint: // 点
|
||
SetAt(sKey, asPnt3d(rb.resval.rpoint));
|
||
break;
|
||
case AecXData::kTypePointWorld: // 变化点
|
||
SetAt(sKey, asPnt3d(rb.resval.rpoint),TRUE);
|
||
break;
|
||
case AecXData::kTypeVector: // 向量
|
||
sKey.Replace(DIF_VT_PT,_T(" "));
|
||
sKey.TrimRight();
|
||
SetAt(sKey, asPnt3d(rb.resval.rpoint));
|
||
break;
|
||
case AecXData::kTypeVectorWorld: // cad变化向量
|
||
sKey.Replace(DIF_VT_PT,_T(" "));
|
||
sKey.TrimRight();
|
||
SetAt(sKey, asPnt3d(rb.resval.rpoint),TRUE);
|
||
break;
|
||
case AecXData::kTypeMatrix: //矩阵
|
||
{
|
||
double ar[16];
|
||
if (TextToMatrix(rb.resval.rstring, ar))
|
||
{
|
||
AcGeMatrix3d xf;
|
||
int k = 0;
|
||
for (int i = 0;i < 4;i++)
|
||
for (int j = 0;j < 4;j++)
|
||
xf.entry[i][j] = ar[k++];
|
||
SetAt(sKey, xf);
|
||
}
|
||
}
|
||
break;
|
||
case AecXData::kTypeBinary: //binary data
|
||
SetAt(sKey,rb.resval.rbinary.buf,rb.resval.rbinary.clen);
|
||
break;
|
||
case AecXData::kTypeString: // 字符串
|
||
SetAt(sKey, rb.resval.rstring);
|
||
break;
|
||
default:
|
||
break;
|
||
}
|
||
}
|
||
return Acad::eOk;
|
||
}
|
||
|
||
// 增加 clone 的 xdatamap 的关系复制维护
|
||
void AecDbObjXDataMap::BeginCloneXlation(AecDbObjXDataMap* pMapClone,AcDbIdMapping& idMap) const
|
||
{
|
||
assert(pMapClone != NULL);
|
||
|
||
AcDbObjectId id;
|
||
AecXData xdata;
|
||
AcDbIdPair idpair;
|
||
|
||
for (CIt it = m_xData.begin();it != m_xData.end();it++)
|
||
{
|
||
xdata = (*it).second;
|
||
switch (xdata.nVt)
|
||
{
|
||
case AecXData::kTypeSoftId:
|
||
{
|
||
id.setFromOldId(xdata.nVal);
|
||
idpair.setKey(id);
|
||
if ( idMap.compute(idpair) )
|
||
{
|
||
pMapClone->SetAt((*it).first,idpair.value(),TRUE);
|
||
}
|
||
}
|
||
break;
|
||
case AecXData::kTypeHardId:
|
||
{
|
||
id.setFromOldId(xdata.nVal);
|
||
idpair.setKey(id);
|
||
if ( idMap.compute(idpair) )
|
||
{
|
||
pMapClone->SetAt((*it).first,idpair.value(),FALSE);
|
||
}
|
||
}
|
||
break;
|
||
default:
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
Acad::ErrorStatus AecDbObjXDataMap::dwgOutFields(AcDbDwgFiler* pFiler) const
|
||
{
|
||
if (pFiler != NULL)
|
||
{
|
||
AecXData xdata;
|
||
int nVt = -1;
|
||
AcGePoint3d ptVal;
|
||
AcGeVector3d vt;
|
||
AcDbSoftPointerId id;
|
||
|
||
pFiler->writeString(MAP_BLOCK_BEGIN);
|
||
|
||
for (CIt it = m_xData.begin(); it != m_xData.end(); ++it)
|
||
{
|
||
xdata = (*it).second;
|
||
nVt = xdata.nVt;
|
||
pFiler->writeString((const TCHAR *)(*it).first);
|
||
pFiler->writeInt32(nVt);
|
||
|
||
switch (nVt)
|
||
{
|
||
case AecXData::kTypeShort:
|
||
pFiler->writeInt16(xdata.iVal);
|
||
break;
|
||
case AecXData::kTypeInt: // 整型
|
||
pFiler->writeInt32((int)xdata.nVal);
|
||
break;
|
||
case AecXData::kTypeSoftId:
|
||
id.setFromOldId(xdata.nVal);
|
||
pFiler->writeSoftPointerId(id);
|
||
break;
|
||
case AecXData::kTypeHardId:
|
||
id.setFromOldId(xdata.nVal);
|
||
pFiler->writeHardPointerId(id);
|
||
break;
|
||
case AecXData::kTypeDouble: // 浮点
|
||
pFiler->writeDouble(xdata.dVal[0]);
|
||
break;
|
||
case AecXData::kTypePoint: // 点
|
||
case AecXData::kTypePointWorld:
|
||
ptVal.x = xdata.dVal[0];
|
||
ptVal.y = xdata.dVal[1];
|
||
ptVal.z = xdata.dVal[2];
|
||
pFiler->writePoint3d(ptVal);
|
||
break;
|
||
case AecXData::kTypeVector: // 向量
|
||
case AecXData::kTypeVectorWorld:
|
||
vt.x = xdata.dVal[0];
|
||
vt.y = xdata.dVal[1];
|
||
vt.z = xdata.dVal[2];
|
||
pFiler->writeVector3d(vt);
|
||
break;
|
||
case AecXData::kTypeMatrix: //矩阵
|
||
{
|
||
CString sMat;
|
||
MatrixToText(xdata, sMat);
|
||
pFiler->writeString((LPCTSTR)sMat);
|
||
}
|
||
break;
|
||
case AecXData::kTypeBinary: //binary data
|
||
{
|
||
pFiler->writeInt32(xdata.npszLen);
|
||
pFiler->writeBytes(xdata.pData,xdata.npszLen);
|
||
break;
|
||
}
|
||
break;
|
||
case AecXData::kTypeString: // 字符串
|
||
pFiler->writeString(xdata.pszVal);
|
||
break;
|
||
default:
|
||
break;
|
||
}
|
||
}
|
||
pFiler->writeString(MAP_BLOCK_END);
|
||
return Acad::eOk;
|
||
}
|
||
return Acad::eInvalidInput;
|
||
}
|
||
|
||
Acad::ErrorStatus AecDbObjXDataMap::dwgInFields(AcDbDwgFiler* pFiler)
|
||
{
|
||
if (pFiler == NULL) return Acad::eInvalidInput;
|
||
|
||
BOOL bFinded = FALSE;
|
||
Adesk::Int32 nVt = 0;
|
||
Adesk::Int16 iVal = 0;
|
||
AecXData xdata;
|
||
TCHAR* pszKey = NULL;
|
||
TCHAR* pszVal = NULL;
|
||
AcGePoint3d ptVal;
|
||
AcGeVector3d vt;
|
||
AcGeMatrix3d xform;
|
||
CString sKey,sTag;
|
||
|
||
CString sText;
|
||
CStringArray arTexts;
|
||
|
||
Empty();
|
||
|
||
while ((pFiler->readString(&pszVal)) == Acad::eOk)
|
||
{
|
||
sTag = pszVal;
|
||
if (pszVal != NULL) acutDelString(pszVal);
|
||
if (sTag.CompareNoCase(MAP_BLOCK_BEGIN) == 0)
|
||
{
|
||
bFinded = TRUE;
|
||
break;
|
||
}
|
||
}
|
||
if (!bFinded) return Acad::eOk;
|
||
|
||
while ((pFiler->readString(&pszKey)) == Acad::eOk)
|
||
{
|
||
sKey = pszKey;
|
||
if (pszKey != NULL) acutDelString(pszKey);
|
||
if (sKey.CompareNoCase(MAP_BLOCK_END) == 0)
|
||
{
|
||
break;
|
||
}
|
||
|
||
pFiler->readInt32(&nVt);
|
||
xdata.nVt = (int)nVt;
|
||
AcDbSoftPointerId id;
|
||
AcDbHardPointerId idh;
|
||
|
||
switch (nVt)
|
||
{
|
||
case AecXData::kTypeShort:
|
||
pFiler->readInt16(&iVal);
|
||
xdata.iVal = iVal;
|
||
SetAt(sKey, xdata.iVal);
|
||
break;
|
||
case AecXData::kTypeInt: // 整型
|
||
pFiler->readInt32(&nVt);
|
||
xdata.nVal = (int)nVt;
|
||
SetAt(sKey, (int)xdata.nVal);
|
||
break;
|
||
case AecXData::kTypeSoftId:
|
||
pFiler->readSoftPointerId(&id);
|
||
SetAt(sKey,id);
|
||
break;
|
||
case AecXData::kTypeHardId:
|
||
pFiler->readHardPointerId(&idh);
|
||
SetAt(sKey,idh,FALSE);
|
||
break;
|
||
case AecXData::kTypeDouble: // 浮点
|
||
pFiler->readDouble(&xdata.dVal[0]);
|
||
SetAt(sKey, xdata.dVal[0]);
|
||
break;
|
||
case AecXData::kTypePoint: // 点
|
||
pFiler->readPoint3d(&ptVal);
|
||
SetAt(sKey, ptVal);
|
||
break;
|
||
case AecXData::kTypePointWorld: // cad变化点
|
||
pFiler->readPoint3d(&ptVal);
|
||
SetAt(sKey, ptVal, TRUE);
|
||
break;
|
||
case AecXData::kTypeVector: // 向量
|
||
pFiler->readVector3d(&vt);
|
||
sKey.Replace(DIF_VT_PT,_T(" "));
|
||
sKey.TrimRight();
|
||
SetAt(sKey, vt);
|
||
break;
|
||
case AecXData::kTypeVectorWorld: // cad变化向量
|
||
pFiler->readVector3d(&vt);
|
||
sKey.Replace(DIF_VT_PT,_T(" "));
|
||
sKey.TrimRight();
|
||
SetAt(sKey, vt, TRUE);
|
||
break;
|
||
case AecXData::kTypeMatrix: //矩阵
|
||
pszVal = NULL;
|
||
pFiler->readString(&pszVal);
|
||
|
||
sText = pszVal;
|
||
arTexts.RemoveAll();
|
||
|
||
Script2StringArray(sText,_T(','),arTexts);
|
||
if (arTexts.GetSize() == 16)
|
||
{
|
||
for (int i = 0;i < 4;i++)
|
||
{
|
||
for (int j = 0;j < 4;j++)
|
||
{
|
||
xform.entry[i][j] = _ttof(arTexts.GetAt(i * 4 + j));
|
||
}
|
||
}
|
||
}
|
||
SetAt(sKey, xform);
|
||
if (pszVal != NULL) acutDelString(pszVal);
|
||
break;
|
||
case AecXData::kTypeBinary: //binary data
|
||
{
|
||
Adesk::Int32 nSize = 0;
|
||
pFiler->readInt32(&nSize);
|
||
|
||
if (nSize > 0)
|
||
{
|
||
void* pData = new byte[nSize];
|
||
pFiler->readBytes(pData,nSize);
|
||
SetAt(sKey,pData,nSize);
|
||
}
|
||
break;
|
||
}
|
||
case AecXData::kTypeString: // 字符串
|
||
pszVal = NULL;
|
||
pFiler->readString(&pszVal);
|
||
SetAt(sKey, pszVal);
|
||
if (pszVal != NULL) acutDelString(pszVal);
|
||
break;
|
||
default:
|
||
break;
|
||
}
|
||
}
|
||
return Acad::eOk;
|
||
}
|
||
|
||
//分区链块
|
||
static struct resbuf *PartitionBlocks(AecDbObjXDataMap::CIt iter, struct resbuf *&pTemp)
|
||
{
|
||
//最大65535 blocks
|
||
int nBlocks = iter->second.npszLen / 127 + ((iter->second.npszLen % 127 > 0) ? 1 : 0);
|
||
|
||
//head
|
||
const char *pszBlocks = BINARY_CHUNKBLOCKS;
|
||
struct resbuf *pTempNext = acutNewRb(AcDb::kDxfXdBinaryChunk);
|
||
pTempNext->resval.rbinary.clen = 66;
|
||
char *pBlocks = new char[66];//binarychunkblocks
|
||
memset(pBlocks, 0, 66);
|
||
pTempNext->resval.rbinary.buf = pBlocks;
|
||
|
||
sprintf(pBlocks, "%s:%d:%d", pszBlocks,nBlocks, (int)iter->second.npszLen);
|
||
|
||
pTemp->rbnext = pTempNext;
|
||
pTemp = pTempNext;
|
||
|
||
LONG_PTR nCut = iter->second.npszLen;
|
||
char *pData = (char *)iter->second.pData;
|
||
|
||
while (nCut > 127)
|
||
{
|
||
pTempNext = acutNewRb(AcDb::kDxfXdBinaryChunk);
|
||
pTempNext->resval.rbinary.clen = (nCut > 127) ? 127 : nCut;
|
||
pTempNext->resval.rbinary.buf = new char[pTempNext->resval.rbinary.clen];
|
||
memcpy(pTempNext->resval.rbinary.buf, pData, pTempNext->resval.rbinary.clen);
|
||
|
||
pTemp->rbnext = pTempNext;
|
||
pTemp = pTempNext;
|
||
|
||
//下一段
|
||
pData += 127;
|
||
nCut -= 127;
|
||
|
||
if (nCut < 127 && nCut > 0)//最后一段
|
||
{
|
||
pTempNext = acutNewRb(AcDb::kDxfXdBinaryChunk);
|
||
pTempNext->resval.rbinary.clen = nCut;
|
||
pTempNext->resval.rbinary.buf = new char[pTempNext->resval.rbinary.clen];
|
||
memcpy(pTempNext->resval.rbinary.buf, pData, pTempNext->resval.rbinary.clen);
|
||
|
||
pTemp->rbnext = pTempNext;
|
||
pTemp = pTempNext;
|
||
}
|
||
}
|
||
return pTempNext;
|
||
}
|
||
|
||
// bXRecord = fase 操作扩展数据 bXRecord = true 操作扩展词典
|
||
BOOL AecDbObjXDataMap::XDMap2Resbuf(LPCTSTR pszApp, struct resbuf*& pRb,BOOL bXRecord,BOOL bOnlyWriteSecond) const
|
||
{
|
||
if(pszApp == NULL || m_xData.empty()) return FALSE;
|
||
|
||
struct resbuf* pTemp = NULL;
|
||
|
||
// 链表头
|
||
if (!bXRecord)
|
||
{
|
||
// 扩展数据需要链表头
|
||
pTemp = acutNewRb(AcDb::kDxfRegAppName);
|
||
acutNewString(pszApp,pTemp->resval.rstring);
|
||
pRb = pTemp;
|
||
}
|
||
|
||
AcDbObjectId id;
|
||
ads_name adsName;
|
||
struct resbuf* pTempNext = NULL;
|
||
// 遍历map
|
||
for(CIt iter = m_xData.begin(); iter != m_xData.end(); iter++)
|
||
{
|
||
if (!bOnlyWriteSecond)//如果不写key
|
||
{
|
||
pTempNext = acutNewRb(AcDb::kDxfXdAsciiString);
|
||
acutNewString(iter->first, pTempNext->resval.rstring);
|
||
|
||
if (pRb == NULL)
|
||
{
|
||
pRb = pTempNext;
|
||
}
|
||
else
|
||
{
|
||
pTemp->rbnext = pTempNext;
|
||
}
|
||
pTemp = pTempNext;
|
||
}
|
||
|
||
pTempNext = NULL;
|
||
switch (iter->second.nVt)
|
||
{
|
||
case AecXData::kTypeShort:
|
||
{
|
||
pTempNext = acutNewRb(AcDb::kDxfXdInteger16);
|
||
pTempNext->resval.rint = (short)iter->second.iVal;
|
||
pTemp->rbnext = pTempNext;
|
||
break;
|
||
}
|
||
case AecXData::kTypeInt: // 整型
|
||
pTempNext = acutNewRb(AcDb::kDxfXdInteger32);
|
||
pTempNext->resval.rlong = (long)iter->second.nVal;
|
||
pTemp->rbnext = pTempNext;
|
||
break;
|
||
/*---------------------------------------------------------------------------------------
|
||
Extended data (xdata) is created by applications written with ObjectARX? or AutoLISP?
|
||
and can be added to any object. Xdata consists of a linked list of resbufs
|
||
used by the application. (AutoCAD maintains the information but doesn't use it.)
|
||
The data is associated with a DXF group code in the range of 1000 to 1071.
|
||
*/
|
||
/*
|
||
so someguy want save id to an entity xdata ,must save as kDxfXdHandle
|
||
kDxfXdHandle is same as string;
|
||
*/
|
||
case AecXData::kTypeSoftId: //s id
|
||
id.setFromOldId(iter->second.nVal);
|
||
acdbGetAdsName(adsName,id);
|
||
if(bXRecord)
|
||
pTempNext = acutBuildList(AcDb::kDxfSoftPointerId, adsName, 0);
|
||
else
|
||
{
|
||
pTempNext = acutNewRb(AcDb::kDxfXdHandle);
|
||
TCHAR szHandleStr[19];
|
||
memset(szHandleStr,0,sizeof(szHandleStr) );
|
||
id.handle().getIntoAsciiBuffer(szHandleStr);
|
||
#if ARX < 17
|
||
acutNewString(szHandleStr, pTempNext->resval.rstring);
|
||
#else
|
||
acutNewString(pTempNext->resval.rstring, (int)(_tcslen(szHandleStr) + 1));
|
||
_tcsncpy_s(pTempNext->resval.rstring, _tcslen(szHandleStr) + 1, szHandleStr, _tcslen(szHandleStr));
|
||
#endif
|
||
}
|
||
pTemp->rbnext = pTempNext;
|
||
break;
|
||
case AecXData::kTypeHardId: //h id not support xdata
|
||
id.setFromOldId(iter->second.nVal);
|
||
acdbGetAdsName(adsName,id);
|
||
if(bXRecord)
|
||
pTempNext = acutBuildList(AcDb::kDxfHardPointerId, adsName, 0);
|
||
else
|
||
{
|
||
pTempNext = acutNewRb(AcDb::kDxfXdHandle);
|
||
TCHAR szHandleStr[19];
|
||
memset(szHandleStr,0,sizeof(szHandleStr) );
|
||
id.handle().getIntoAsciiBuffer(szHandleStr);
|
||
#if ARX < 17
|
||
acutNewString(szHandleStr, pTempNext->resval.rstring);
|
||
#else
|
||
acutNewString(pTempNext->resval.rstring, (int)(_tcslen(szHandleStr) + 1));
|
||
_tcsncpy_s(pTempNext->resval.rstring, (int)(_tcslen(szHandleStr) + 1), szHandleStr, _tcslen(szHandleStr));
|
||
#endif
|
||
}
|
||
pTemp->rbnext = pTempNext;
|
||
break;
|
||
case AecXData::kTypeString: // 字符串
|
||
pTempNext = acutNewRb(AcDb::kDxfXdAsciiString);
|
||
acutNewString(iter->second.pszVal, pTempNext->resval.rstring);
|
||
pTemp->rbnext = pTempNext;
|
||
break;
|
||
case AecXData::kTypeDouble: // 浮点型
|
||
pTempNext = acutNewRb(AcDb::kDxfXdReal);
|
||
pTempNext->resval.rreal = iter->second.dVal[0];
|
||
pTemp->rbnext = pTempNext;
|
||
break;
|
||
case AecXData::kTypePoint: // 点
|
||
pTempNext = acutNewRb(AcDb::kDxfXdXCoord);
|
||
pTempNext->resval.rpoint[0] = iter->second.dVal[0];
|
||
pTempNext->resval.rpoint[1] = iter->second.dVal[1];
|
||
pTempNext->resval.rpoint[2] = iter->second.dVal[2];
|
||
pTemp->rbnext = pTempNext;
|
||
break;
|
||
case AecXData::kTypePointWorld: // 随cad实体变化的点
|
||
pTempNext = acutNewRb(AcDb::kDxfXdWorldXCoord);
|
||
pTempNext->resval.rpoint[0] = iter->second.dVal[0];
|
||
pTempNext->resval.rpoint[1] = iter->second.dVal[1];
|
||
pTempNext->resval.rpoint[2] = iter->second.dVal[2];
|
||
pTemp->rbnext = pTempNext;
|
||
break;
|
||
case AecXData::kTypeVector: // 向量
|
||
pTempNext = acutNewRb(AcDb::kDxfXdXCoord);
|
||
pTempNext->resval.rpoint[0] = iter->second.dVal[0];
|
||
pTempNext->resval.rpoint[1] = iter->second.dVal[1];
|
||
pTempNext->resval.rpoint[2] = iter->second.dVal[2];
|
||
pTemp->rbnext = pTempNext;
|
||
break;
|
||
case AecXData::kTypeVectorWorld: // 随cad实体变化的向量
|
||
pTempNext = acutNewRb(AcDb::kDxfXdWorldXDir);
|
||
pTempNext->resval.rpoint[0] = iter->second.dVal[0];
|
||
pTempNext->resval.rpoint[1] = iter->second.dVal[1];
|
||
pTempNext->resval.rpoint[2] = iter->second.dVal[2];
|
||
pTemp->rbnext = pTempNext;
|
||
break;
|
||
case AecXData::kTypeMatrix: // 矩阵
|
||
{
|
||
CString sMat;
|
||
MatrixToText(iter->second, sMat);
|
||
pTempNext = acutNewRb(AcDb::kDxfXdAsciiString);
|
||
acutNewString(sMat, pTempNext->resval.rstring);
|
||
pTemp->rbnext = pTempNext;
|
||
}
|
||
break;
|
||
case AecXData::kTypeBinary:
|
||
/*pTempNext = acutNewRb(AcDb::kDxfXdBinaryChunk);
|
||
pTempNext->resval.rbinary.clen = iter->second.npszLen;
|
||
pTempNext->resval.rbinary.buf = new char[iter->second.npszLen];
|
||
memcpy(pTempNext->resval.rbinary.buf,iter->second.pData,iter->second.npszLen);
|
||
pTemp->rbnext = pTempNext;
|
||
if (pTempNext->resval.rbinary.clen > 127)
|
||
acutPrintf(_T("\nBinaryChunk Data overflow!!!"));*/
|
||
|
||
if (iter->second.npszLen > MAX_BINARYCHUNK)
|
||
{
|
||
pTempNext = PartitionBlocks(iter, pTemp);
|
||
}
|
||
else
|
||
{
|
||
pTempNext = acutNewRb(AcDb::kDxfXdBinaryChunk);
|
||
pTempNext->resval.rbinary.clen = iter->second.npszLen;
|
||
pTempNext->resval.rbinary.buf = new char[iter->second.npszLen];
|
||
memcpy(pTempNext->resval.rbinary.buf, iter->second.pData, iter->second.npszLen);
|
||
pTemp->rbnext = pTempNext;
|
||
}
|
||
break;
|
||
default:
|
||
continue;
|
||
}
|
||
pTemp = pTempNext;
|
||
pTempNext = NULL;
|
||
}
|
||
return (pRb != NULL);
|
||
}
|
||
|
||
void AecDbObjXDataMap::SecondAsKey(CString& sTemp,AecXData& xData)
|
||
{
|
||
switch (xData.nVt)
|
||
{
|
||
case AecXData::kTypeShort:
|
||
sTemp.Format(_T("%d"), xData.iVal);
|
||
break;
|
||
case AecXData::kTypeInt: // 整型
|
||
sTemp.Format(_T("%d"),xData.nVal);
|
||
break;
|
||
case AecXData::kTypeSoftId:
|
||
sTemp.Format(_T("%d"),xData.nVal);
|
||
break;
|
||
case AecXData::kTypeHardId:
|
||
sTemp.Format(_T("%d"),xData.nVal);
|
||
break;
|
||
case AecXData::kTypeDouble: // 浮点
|
||
sTemp.Format(_T("%.9f"),xData.dVal[0]);
|
||
break;
|
||
case AecXData::kTypePoint: // 点
|
||
case AecXData::kTypePointWorld:
|
||
case AecXData::kTypeVector: // 向量
|
||
case AecXData::kTypeVectorWorld:
|
||
sTemp.Format(_T("%.9f,%.9f,%.9f"),xData.dVal[0],xData.dVal[1],xData.dVal[2]);
|
||
break;
|
||
case AecXData::kTypeMatrix: //矩阵
|
||
{
|
||
MatrixToText(xData, sTemp);
|
||
break;
|
||
}
|
||
case AecXData::kTypeString: // 字符串
|
||
{
|
||
sTemp = xData.pszVal;
|
||
break;
|
||
}
|
||
case AecXData::kTypeBinary: //binary data
|
||
{
|
||
CTime tNow = CTime::GetCurrentTime();
|
||
sTemp = tNow.Format(" %Y-%m-%d %H.%M.%S");
|
||
|
||
break;
|
||
}
|
||
default:
|
||
break;
|
||
}
|
||
}
|
||
|
||
//合并区链块
|
||
static bool MergeBlocks(AecXData &xData, struct resbuf*& pTemp)
|
||
{
|
||
if (pTemp == NULL)
|
||
return false;
|
||
|
||
char *pszBlocks = (char *)xData.pData;
|
||
if (NULL != strstr(pszBlocks, BINARY_CHUNKBLOCKS1))
|
||
{
|
||
//AAAA:5:635
|
||
|
||
//AAAA:
|
||
char *pszId = strstr(pszBlocks, BINARY_CHUNKBLOCKS1);
|
||
|
||
//5:635
|
||
char *pszNm = pszId;
|
||
pszNm += strlen(BINARY_CHUNKBLOCKS1);
|
||
int nBlocks = atoi(pszNm);
|
||
|
||
//:635
|
||
char *pszSz = strstr(pszNm, ":");
|
||
pszSz += 1;
|
||
|
||
//635
|
||
xData.npszLen = atoi(pszSz);
|
||
if (xData.npszLen == 0)
|
||
return false;
|
||
|
||
xData.pData = new char[xData.npszLen];
|
||
memset(xData.pData, 0, xData.npszLen);
|
||
|
||
struct resbuf *pLast = pTemp;
|
||
char *pPos = (char*)xData.pData;
|
||
|
||
pTemp = pTemp->rbnext;
|
||
for (int i = 0; i < nBlocks; i++)
|
||
{
|
||
assert(pTemp->restype == AcDb::kDxfXdBinaryChunk);//must
|
||
|
||
memcpy(pPos, pTemp->resval.rbinary.buf, pTemp->resval.rbinary.clen);
|
||
pPos += pTemp->resval.rbinary.clen;
|
||
|
||
pLast = pTemp;
|
||
pTemp = pTemp->rbnext;
|
||
}
|
||
|
||
//待后续下移一段,确保当前指向正读取数据段
|
||
pTemp = pLast;
|
||
return true;
|
||
}
|
||
return false;
|
||
}
|
||
|
||
// bXRecord = fase 操作扩展数据 bXRecord = true 操作扩展词典
|
||
BOOL AecDbObjXDataMap::Resbuf2XDMap(struct resbuf* pRb,BOOL bXRecord,AcDbDatabase* pDb,BOOL bKeyAsSecond/* = FALSE*/)
|
||
{
|
||
if(pRb == NULL) return FALSE;
|
||
Empty();
|
||
|
||
struct resbuf* pTemp = pRb;
|
||
|
||
// 跳过扩展数据头 扩展数据
|
||
if (!bXRecord)
|
||
{
|
||
pTemp = pRb->rbnext;
|
||
}
|
||
|
||
AcDbObjectId id;
|
||
int nMapUnitIndex = 1;
|
||
AecXData xData;
|
||
CString sTemp;
|
||
while (pTemp != NULL)
|
||
{
|
||
if (nMapUnitIndex == 1 && !bKeyAsSecond)
|
||
{
|
||
// skey键值
|
||
if (pTemp->restype == AcDb::kDxfXdAsciiString)
|
||
{
|
||
sTemp = pTemp->resval.rstring;
|
||
nMapUnitIndex++;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
// value
|
||
switch (pTemp->restype)
|
||
{
|
||
case AcDb::kDxfXdAsciiString: // 字符串
|
||
xData.nVt = AecXData::kTypeString;
|
||
xData.npszLen = _tcslen(pTemp->resval.rstring) + 1;
|
||
xData.pszVal = new TCHAR[xData.npszLen];
|
||
_tcsncpy_s(xData.pszVal, xData.npszLen, pTemp->resval.rstring, xData.npszLen - 1);
|
||
nMapUnitIndex++;
|
||
break;
|
||
case AcDb::kDxfXdInteger16:
|
||
xData.nVt = AecXData::kTypeShort;
|
||
xData.iVal = pTemp->resval.rint;
|
||
nMapUnitIndex++;
|
||
break;
|
||
case AcDb::kDxfXdInteger32: // 整型
|
||
xData.nVt = AecXData::kTypeInt;
|
||
xData.nVal = pTemp->resval.rlong;
|
||
nMapUnitIndex++;
|
||
break;
|
||
/*---------------------------------------------------------------------------------------
|
||
Extended data (xdata) is created by applications written with ObjectARX? or AutoLISP?
|
||
and can be added to any object. Xdata consists of a linked list of resbufs
|
||
used by the application. (AutoCAD maintains the information but doesn't use it.)
|
||
The data is associated with a DXF group code in the range of 1000 to 1071.
|
||
*/
|
||
case AcDb::kDxfSoftPointerId: //s id not support xdata
|
||
acdbGetObjectId(id, pTemp->resval.rlname);
|
||
xData.nVt = AecXData::kTypeSoftId;
|
||
xData.nVal = id.asOldId();
|
||
nMapUnitIndex++;
|
||
break;
|
||
case AcDb::kDxfHardPointerId: //h id not support xdata
|
||
acdbGetObjectId(id, pTemp->resval.rlname);
|
||
xData.nVt = AecXData::kTypeHardId;
|
||
xData.nVal = id.asOldId();
|
||
nMapUnitIndex++;
|
||
break;
|
||
//--------------------------------------------------------------------------------------
|
||
case AcDb::kDxfXdHandle: //handle for xdata
|
||
{
|
||
AcDbHandle handle(pTemp->resval.rstring);
|
||
if (pDb == NULL)
|
||
pDb = acdbCurDwg();
|
||
if (pDb != NULL)
|
||
{
|
||
if ( Acad::eOk == pDb->getAcDbObjectId(id,false,handle) )
|
||
{
|
||
xData.nVt = AecXData::kTypeSoftId;
|
||
xData.nVal = id.asOldId();
|
||
nMapUnitIndex++;
|
||
}
|
||
}
|
||
}
|
||
break;
|
||
case AcDb::kDxfXdReal: // 浮点型
|
||
xData.nVt = AecXData::kTypeDouble;
|
||
xData.dVal[0] = pTemp->resval.rreal;
|
||
nMapUnitIndex++;
|
||
break;
|
||
case AcDb::kDxfXdXCoord: // 点 向量
|
||
xData.nVt = AecXData::kTypePoint;
|
||
xData.dVal[0] = pTemp->resval.rpoint[0];
|
||
xData.dVal[1] = pTemp->resval.rpoint[1];
|
||
xData.dVal[2] = pTemp->resval.rpoint[2];
|
||
nMapUnitIndex++;
|
||
|
||
if(sTemp.Find(DIF_VT_PT) >= 0)
|
||
{
|
||
// 向量
|
||
xData.nVt = AecXData::kTypeVector;
|
||
}
|
||
break;
|
||
case AcDb::kDxfXdWorldXCoord:
|
||
{// 随cad实体变化的点
|
||
xData.nVt = AecXData::kTypePointWorld;
|
||
xData.dVal[0] = pTemp->resval.rpoint[0];
|
||
xData.dVal[1] = pTemp->resval.rpoint[1];
|
||
xData.dVal[2] = pTemp->resval.rpoint[2];
|
||
nMapUnitIndex++;
|
||
break;
|
||
}
|
||
case AcDb::kDxfXdWorldXDir: // 随cad实体变化的向量
|
||
{
|
||
xData.nVt = AecXData::kTypeVectorWorld;
|
||
xData.dVal[0] = pTemp->resval.rpoint[0];
|
||
xData.dVal[1] = pTemp->resval.rpoint[1];
|
||
xData.dVal[2] = pTemp->resval.rpoint[2];
|
||
nMapUnitIndex++;
|
||
break;
|
||
}
|
||
case AcDb::kDxfXdBinaryChunk:
|
||
{
|
||
xData.nVt = AecXData::kTypeBinary;
|
||
xData.npszLen = pTemp->resval.rbinary.clen;
|
||
xData.pData = pTemp->resval.rbinary.buf;
|
||
|
||
char* pszBlocks = (char *)xData.pData;
|
||
if (NULL != strstr(pszBlocks, BINARY_CHUNKBLOCKS) &&
|
||
NULL != strstr(pszBlocks, BINARY_CHUNKBLOCKS1) )
|
||
{
|
||
//aaaa:10:3333
|
||
MergeBlocks(xData, pTemp);
|
||
}
|
||
else
|
||
{
|
||
//...
|
||
}
|
||
nMapUnitIndex++;
|
||
break;
|
||
}
|
||
default:
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (bKeyAsSecond)
|
||
{
|
||
SecondAsKey(sTemp,xData);
|
||
nMapUnitIndex++;//3
|
||
}
|
||
|
||
if(nMapUnitIndex > 2)
|
||
{
|
||
// 插入一套 skey value
|
||
std::pair<CString,AecXData> pa(sTemp,xData);
|
||
m_xData.insert(pa);
|
||
nMapUnitIndex = 1;
|
||
}
|
||
|
||
//移向下一段
|
||
pTemp = pTemp->rbnext;
|
||
}
|
||
return !m_xData.empty();
|
||
}
|
||
|
||
//支持扩展数据的4个方法
|
||
// 根据实体指针插入链表 bXRecord = fase 操作扩展数据 bXRecord = true 操作扩展词典
|
||
BOOL AecDbObjXDataMap::Write(AcDbObject* pEnt, LPCTSTR pszApp, BOOL bXRecord,BOOL bAppend,BOOL bOnlyWriteSecond) const
|
||
{
|
||
if (pEnt == NULL || pszApp == NULL) return FALSE;
|
||
|
||
// 根据map生成链表
|
||
struct resbuf* pRb = NULL;
|
||
if (!XDMap2Resbuf(pszApp ,pRb ,bXRecord,bOnlyWriteSecond)) return FALSE;
|
||
Acad::ErrorStatus eStat = Acad::eOutOfMemory;
|
||
|
||
if (!bXRecord)
|
||
{
|
||
// 扩展数据
|
||
struct resbuf* pTmpRb = pEnt->xData(pszApp);
|
||
if (pTmpRb != NULL)
|
||
{
|
||
if (!bAppend)
|
||
{
|
||
// 存在清空
|
||
struct resbuf* pTmp = acutNewRb(AcDb::kDxfRegAppName);
|
||
acutNewString(pszApp,pTmp->resval.rstring);
|
||
|
||
pEnt->setXData(pTmp);
|
||
acutRelRb(pTmpRb);
|
||
acutRelRb(pTmp);
|
||
}
|
||
else//追加
|
||
{
|
||
struct resbuf* pTmpRbNext = pTmpRb->rbnext;
|
||
|
||
struct resbuf* pTemp = pRb;
|
||
while(pTemp != NULL)
|
||
{
|
||
if (pTemp->rbnext == NULL)
|
||
{
|
||
pTemp->rbnext = pTmpRbNext;
|
||
break;
|
||
}
|
||
pTemp = pTemp->rbnext;
|
||
}
|
||
|
||
// 存在清空
|
||
struct resbuf* pTmp = acutNewRb(AcDb::kDxfRegAppName);
|
||
acutNewString(pszApp,pTmp->resval.rstring);
|
||
|
||
pEnt->setXData(pTmp);
|
||
acutRelRb(pTmp);
|
||
}
|
||
}
|
||
|
||
// 注册扩展数据链表
|
||
int nRes = acdbRegApp(pszApp);
|
||
eStat = pEnt->setXData(pRb);
|
||
acutRelRb(pRb);
|
||
return (eStat == Acad::eOk);
|
||
}
|
||
|
||
// 扩展词典
|
||
AcDbObjectId dictObjId, xrecObjId;
|
||
pEnt->createExtensionDictionary();
|
||
dictObjId = pEnt->extensionDictionary();
|
||
|
||
// 打开扩展词典指针
|
||
AcDbDictionary* pDict = NULL;
|
||
if (Acad::eOk != acdbOpenObject(pDict, dictObjId, AcDb::kForWrite))
|
||
{
|
||
if (pRb != NULL) acutRelRb(pRb);
|
||
return FALSE;
|
||
}
|
||
|
||
AcDbXrecord* pXrec = NULL;
|
||
if (pDict->has(pszApp))
|
||
{
|
||
// 存在此扩展词典 获取扩展词典指针
|
||
AcDbObject* pObj = NULL;
|
||
pDict->getAt(pszApp,pObj,AcDb::kForWrite);
|
||
if(pObj != NULL)
|
||
{
|
||
pXrec = AcDbXrecord::cast(pObj);
|
||
if(pXrec != NULL)
|
||
{
|
||
// 重新设置扩展词典
|
||
eStat = pXrec->setFromRbChain(*pRb);
|
||
}
|
||
pObj->close();
|
||
}
|
||
pDict->close();
|
||
}
|
||
else
|
||
{
|
||
// 不存在此扩展词典
|
||
pXrec = new AcDbXrecord;
|
||
eStat = pXrec->setFromRbChain(*pRb);
|
||
eStat = pDict->setAt(pszApp,pXrec,xrecObjId);
|
||
pXrec->close();
|
||
pDict->close();
|
||
}
|
||
|
||
acutRelRb(pRb);
|
||
return (eStat == Acad::eOk);
|
||
}
|
||
|
||
// 根据实体id插入链表 bXRecord = fase 操作扩展数据 bXRecord = true 操作扩展词典
|
||
BOOL AecDbObjXDataMap::Write(const AcDbObjectId& id,LPCTSTR pszApp,BOOL bXRecord,BOOL bAppend,BOOL bOnlyWriteSecond) const
|
||
{
|
||
if(pszApp == NULL) return FALSE;
|
||
|
||
AcDbObject * pEnt = NULL;
|
||
BOOL bWriteIdXData = FALSE;
|
||
if(Acad::eOk == acdbOpenObject(pEnt, id, AcDb::kForWrite))
|
||
{
|
||
// 根据实体指针设置链表
|
||
bWriteIdXData = Write(pEnt,pszApp,bXRecord,bAppend,bOnlyWriteSecond);
|
||
pEnt->close();
|
||
}
|
||
return bWriteIdXData;
|
||
}
|
||
|
||
BOOL AecDbObjXDataMap::WriteExDic(AcDbObject* pObj,LPCTSTR pszApp) const
|
||
{
|
||
if (pObj == NULL || pszApp == NULL) return FALSE;
|
||
|
||
BOOL bWriteIdXData = FALSE;
|
||
pObj->createExtensionDictionary();
|
||
|
||
AcDbObjectId idDic = pObj->extensionDictionary();
|
||
|
||
AcDbObject* pDicObj = NULL;
|
||
if ( Acad::eOk == acdbOpenObject(pDicObj,idDic,AcDb::kForWrite))
|
||
{
|
||
AcDbDictionary* pDic = AcDbDictionary::cast(pDicObj);
|
||
if (pDic != NULL)
|
||
{
|
||
Acad::ErrorStatus es;
|
||
AcDbObjectId idXdata;
|
||
|
||
//先删除
|
||
es = pDic->getAt(pszApp,idXdata);
|
||
if (es == Acad::eOk)
|
||
{
|
||
AcDbObject* pXDataObj = NULL;
|
||
if ( Acad::eOk == acdbOpenObject(pXDataObj,idXdata,AcDb::kForWrite))
|
||
{
|
||
pXDataObj->erase();
|
||
pXDataObj->close();
|
||
}
|
||
}
|
||
|
||
//再加入
|
||
AecDbObjXDataMapObj* pXDataMapObj = new AecDbObjXDataMapObj;
|
||
pXDataMapObj->SetXDataMap(*this,false);
|
||
|
||
AcDbObjectId idMap;
|
||
Acad::ErrorStatus eRes = pDic->setAt(pszApp,pXDataMapObj,idMap);
|
||
pXDataMapObj->close();
|
||
bWriteIdXData = (eRes == Acad::eOk) ? TRUE : FALSE;
|
||
}
|
||
pDicObj->close();
|
||
}
|
||
return bWriteIdXData;
|
||
}
|
||
|
||
BOOL AecDbObjXDataMap::WriteExDic(const AcDbObjectId& id,LPCTSTR pszApp) const
|
||
{
|
||
if(pszApp == NULL) return FALSE;
|
||
|
||
AcDbObject * pObj = NULL;
|
||
BOOL bWriteIdXData = FALSE;
|
||
if(Acad::eOk == acdbOpenObject(pObj, id, AcDb::kForWrite))
|
||
{
|
||
bWriteIdXData = WriteExDic(pObj,pszApp);
|
||
pObj->close();
|
||
}
|
||
return bWriteIdXData;
|
||
}
|
||
|
||
BOOL AecDbObjXDataMap::ReadExDic(AcDbObject* pObj,LPCTSTR pszApp)
|
||
{
|
||
if (pObj == NULL || pszApp == NULL) return FALSE;
|
||
BOOL bSuccess = FALSE;
|
||
|
||
AcDbObjectId idDic = pObj->extensionDictionary();
|
||
|
||
AcDbObject* pDicObj = NULL;
|
||
if ( Acad::eOk == acdbOpenObject(pDicObj,idDic,AcDb::kForRead))
|
||
{
|
||
AcDbDictionary* pDic = AcDbDictionary::cast(pDicObj);
|
||
if (pDic != NULL)
|
||
{
|
||
AcDbObject* pXDataObj = NULL;
|
||
if ( Acad::eOk == pDic->getAt(pszApp,pXDataObj,AcDb::kForRead) )
|
||
{
|
||
AecDbObjXDataMapObj* pXDataMapObj = AecDbObjXDataMapObj::cast(pXDataObj);
|
||
if (pXDataMapObj != NULL)
|
||
{
|
||
bSuccess = pXDataMapObj->GetXDataMap(*this) ? TRUE : FALSE;
|
||
}
|
||
pXDataObj->close();
|
||
}
|
||
}
|
||
pDicObj->close();
|
||
}
|
||
return bSuccess;
|
||
}
|
||
|
||
BOOL AecDbObjXDataMap::ReadExDic(const AcDbObjectId& id,LPCTSTR pszApp)
|
||
{
|
||
if(pszApp == NULL) return FALSE;
|
||
|
||
AcDbObject * pObj = NULL;
|
||
BOOL bSuccess = FALSE;
|
||
if(Acad::eOk == acdbOpenObject(pObj, id, AcDb::kForRead))
|
||
{
|
||
bSuccess = ReadExDic(pObj,pszApp);
|
||
pObj->close();
|
||
}
|
||
return bSuccess;
|
||
}
|
||
|
||
BOOL AecDbObjXDataMap::Write(CFile* pFileOut,BOOL bWriteUserData) const
|
||
{
|
||
// 1. 永远在最开头写入文件头魔数版本号
|
||
int nVersion = g_nVersion;
|
||
pFileOut->Write(&nVersion, sizeof(int));
|
||
|
||
AecXData xdata;
|
||
int nVt = -1;
|
||
AcGePoint3d ptVal;
|
||
AcGeVector3d vt;
|
||
AcDbSoftPointerId id;
|
||
int nSize = 0;
|
||
CString sText,sVal;
|
||
|
||
if (bWriteUserData)
|
||
{
|
||
int count(0);
|
||
GetAt(BIM_REC_LEN, count);
|
||
CMapStringToString mapStr2Str;
|
||
for (int i = 0; i < count; i++) //1000条用户数据
|
||
{
|
||
sText.Format(_T("user%d"), i);
|
||
if (GetAt(sText, sVal))
|
||
{
|
||
mapStr2Str.SetAt(sText, sVal);
|
||
}
|
||
}
|
||
|
||
nSize = mapStr2Str.GetCount();
|
||
pFileOut->Write(&nSize, sizeof(int));
|
||
|
||
for (POSITION ps = mapStr2Str.GetStartPosition(); ps != NULL;)
|
||
{
|
||
mapStr2Str.GetNextAssoc(ps,sText,sVal);
|
||
|
||
// 【修复】彻底摒弃 _bstr_t,使用原生 TCHAR 直接序列化
|
||
nSize = sText.GetLength();
|
||
pFileOut->Write(&nSize, sizeof(int));
|
||
pFileOut->Write((LPCTSTR)sText, nSize * sizeof(TCHAR));
|
||
|
||
nVt = AecXData::kTypeString;
|
||
pFileOut->Write(&nVt, sizeof(int));
|
||
|
||
nSize = sVal.GetLength();
|
||
pFileOut->Write(&nSize, sizeof(int));
|
||
pFileOut->Write((LPCTSTR)sVal, nSize * sizeof(TCHAR));
|
||
}
|
||
}
|
||
else
|
||
{
|
||
//多少个
|
||
nSize = m_xData.size();
|
||
pFileOut->Write(&nSize,sizeof(int));
|
||
|
||
for (CIt it = m_xData.begin(); it != m_xData.end(); ++it)
|
||
{
|
||
xdata = (*it).second;
|
||
nVt = xdata.nVt;
|
||
|
||
sText = (*it).first;
|
||
|
||
//key
|
||
nSize = it->first.GetLength();
|
||
pFileOut->Write(&nSize,sizeof(int));
|
||
pFileOut->Write((LPCTSTR)it->first, nSize * sizeof(TCHAR));
|
||
|
||
//vt
|
||
pFileOut->Write(&nVt,sizeof(int));
|
||
|
||
switch (nVt)
|
||
{
|
||
case AecXData::kTypeShort:
|
||
pFileOut->Write(&xdata.iVal,sizeof(short));
|
||
break;
|
||
case AecXData::kTypeInt: // 整型
|
||
pFileOut->Write(&xdata.nVal,sizeof(int));
|
||
break;
|
||
case AecXData::kTypeSoftId:
|
||
pFileOut->Write(&xdata.nVal,sizeof(int));
|
||
break;
|
||
case AecXData::kTypeHardId:
|
||
pFileOut->Write(&xdata.nVal,sizeof(int));
|
||
break;
|
||
case AecXData::kTypeDouble: // 浮点
|
||
pFileOut->Write(&xdata.dVal[0],sizeof(double));
|
||
break;
|
||
case AecXData::kTypePoint: // 点
|
||
case AecXData::kTypePointWorld:
|
||
case AecXData::kTypeVector: // 向量
|
||
case AecXData::kTypeVectorWorld:
|
||
pFileOut->Write(xdata.dVal,sizeof(double) * 3);
|
||
break;
|
||
case AecXData::kTypeMatrix: //矩阵:二进制块([魔数][16个double]),自描述
|
||
{
|
||
double ar[16];
|
||
if (GetMatrixData(xdata, ar))
|
||
{
|
||
byte buf[kMatrixBinBytes];
|
||
int nMagic = kMatrixMagic;
|
||
memcpy(buf, &nMagic, sizeof(int));
|
||
memcpy(buf + sizeof(int), ar, 16 * sizeof(double));
|
||
pFileOut->Write(buf, kMatrixBinBytes);
|
||
}
|
||
}
|
||
break;
|
||
case AecXData::kTypeString: // 字符串
|
||
{
|
||
nSize = _tcsclen(xdata.pszVal);
|
||
pFileOut->Write(&nSize,sizeof(int));
|
||
pFileOut->Write(xdata.pszVal, nSize * sizeof(TCHAR));
|
||
}
|
||
break;
|
||
case AecXData::kTypeBinary:
|
||
{
|
||
pFileOut->Write(&xdata.npszLen,sizeof(int));
|
||
pFileOut->Write(xdata.pData, xdata.npszLen);
|
||
}
|
||
break;
|
||
default:
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
BOOL AecDbObjXDataMap::Write(CString &strOut, BOOL bWriteUserData) const
|
||
{
|
||
CMemFile mf;
|
||
if (Write(&mf, bWriteUserData))
|
||
{
|
||
mf.SeekToBegin();
|
||
strOut = Base64::EncodeF2W(&mf).c_str();
|
||
return 1;
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
// bXRecord = fase 操作扩展数据 bXRecord = true 操作扩展词典
|
||
BOOL AecDbObjXDataMap::Read(AcDbObject* pEnt,LPCTSTR pszApp,BOOL bXRecord,BOOL bKeyAsSecond/* = FALSE*/)
|
||
{
|
||
if(pEnt == NULL || pszApp == NULL) return FALSE;
|
||
struct resbuf* pRb = NULL;
|
||
BOOL bResbuf2XDmap = FALSE;
|
||
|
||
if (!bXRecord)
|
||
{
|
||
// 扩展数据
|
||
pRb = pEnt->xData(pszApp);
|
||
if(pRb == NULL) return FALSE;
|
||
bResbuf2XDmap = Resbuf2XDMap(pRb,bXRecord,pEnt->database(),bKeyAsSecond);
|
||
|
||
acutRelRb(pRb);
|
||
return bResbuf2XDmap;
|
||
}
|
||
|
||
// 获取扩展数据(词典)id
|
||
AcDbObjectId dictObjId, xrecObjId;
|
||
dictObjId = pEnt->extensionDictionary();
|
||
if (dictObjId.isNull())
|
||
{
|
||
// 没有扩展数据
|
||
return FALSE;
|
||
}
|
||
|
||
// 打开扩展词典实体
|
||
AcDbDictionary* pDict = NULL;
|
||
if (Acad::eOk != acdbOpenObject(pDict, dictObjId, AcDb::kForRead))
|
||
{
|
||
return FALSE;
|
||
}
|
||
|
||
AcDbXrecord *pXrec = NULL;
|
||
AcDbObject* pObj = NULL;
|
||
// 获取扩展数据链表
|
||
if (Acad::eOk == pDict->getAt(pszApp,pObj,AcDb::kForRead))
|
||
{
|
||
pXrec = AcDbXrecord::cast(pObj);
|
||
if (pXrec != NULL)
|
||
{
|
||
pXrec->rbChain(&pRb);
|
||
if (pRb != NULL)
|
||
{
|
||
bResbuf2XDmap = Resbuf2XDMap(pRb,bXRecord,pEnt->database(),bKeyAsSecond);
|
||
acutRelRb(pRb);
|
||
}
|
||
}
|
||
pObj->close();
|
||
}
|
||
else
|
||
{
|
||
// 获取链表失败
|
||
pDict->close();
|
||
return FALSE;
|
||
}
|
||
pDict->close();
|
||
|
||
return bResbuf2XDmap;
|
||
}
|
||
|
||
// bXRecord = fase 操作扩展数据 bXRecord = true 操作扩展词典
|
||
BOOL AecDbObjXDataMap::Read(const AcDbObjectId& id,LPCTSTR pszApp,BOOL bXRecord,BOOL bKeyAsSecond/* = FALSE*/)
|
||
{
|
||
AcDbObject * pEnt = NULL;
|
||
BOOL bReadIdXData = FALSE;
|
||
if(Acad::eOk == acdbOpenObject(pEnt, id, AcDb::kForRead))
|
||
{
|
||
bReadIdXData = Read(pEnt,pszApp,bXRecord,bKeyAsSecond);
|
||
pEnt->close();
|
||
}
|
||
return bReadIdXData;
|
||
}
|
||
|
||
BOOL AecDbObjXDataMap::Read(CFile *pFileOut, BOOL bWriteUserData)
|
||
{
|
||
Empty();
|
||
|
||
int nMarker = 0;
|
||
ULONGLONG startPos = pFileOut->GetPosition();
|
||
pFileOut->Read(&nMarker, sizeof(int));
|
||
|
||
BOOL bIsOldVersion = FALSE; // 无版本头(老格式,文件以 Base64 块标记开头)
|
||
|
||
if (nMarker != g_nVersion)
|
||
{
|
||
// 无版本头:回退跳过 Base64(MAP_BLOCK_BEGIN) 前缀
|
||
bIsOldVersion = TRUE;
|
||
pFileOut->Seek(startPos, CFile::begin);
|
||
|
||
CString sTemp = MAP_BLOCK_BEGIN;
|
||
_bstr_t bst((LPCTSTR)sTemp);
|
||
std::string str;
|
||
str.append((const char *)bst);
|
||
std::string str2 = Base64::Encode(str);
|
||
|
||
char *pszBuf = new char[str2.length() + 1];
|
||
memset(pszBuf, 0, str2.length() + 1);
|
||
pFileOut->Read(pszBuf, (UINT)str2.length());
|
||
delete[] pszBuf;
|
||
}
|
||
|
||
int nCount = 0;
|
||
pFileOut->Read(&nCount, sizeof(int));
|
||
|
||
AecXData xdata;
|
||
int nLen = 0;
|
||
for (int i = 0; i < nCount; i++)
|
||
{
|
||
::memset(&xdata, 0, sizeof(xdata));
|
||
|
||
pFileOut->Read(&nLen, sizeof(int));
|
||
TCHAR *pszKey = new TCHAR[nLen + 1];
|
||
::memset(pszKey, 0, (nLen + 1) * sizeof(TCHAR));
|
||
pFileOut->Read(pszKey, nLen * sizeof(TCHAR));
|
||
|
||
pFileOut->Read(&xdata.nVt, sizeof(int));
|
||
|
||
switch (xdata.nVt)
|
||
{
|
||
case AecXData::kTypeShort:
|
||
{
|
||
short sTemp = 0;
|
||
pFileOut->Read(&sTemp, sizeof(short));
|
||
xdata.iVal = sTemp;
|
||
break;
|
||
}
|
||
case AecXData::kTypeInt:
|
||
{
|
||
int nTemp = 0;
|
||
pFileOut->Read(&nTemp, sizeof(int));
|
||
xdata.nVal = nTemp;
|
||
break;
|
||
}
|
||
case AecXData::kTypeSoftId:
|
||
case AecXData::kTypeHardId:
|
||
{
|
||
unsigned int uTemp = 0;
|
||
pFileOut->Read(&uTemp, sizeof(int));
|
||
xdata.nVal = uTemp;
|
||
break;
|
||
}
|
||
case AecXData::kTypeDouble:
|
||
pFileOut->Read(&xdata.dVal[0], sizeof(double));
|
||
break;
|
||
case AecXData::kTypePoint:
|
||
case AecXData::kTypePointWorld:
|
||
case AecXData::kTypeVector:
|
||
case AecXData::kTypeVectorWorld:
|
||
pFileOut->Read(xdata.dVal, sizeof(double) * 3);
|
||
break;
|
||
case AecXData::kTypeString:
|
||
{
|
||
int nCharCount = 0;
|
||
pFileOut->Read(&nCharCount, sizeof(int)); // 读到字符数
|
||
xdata.npszLen = nCharCount + 1; // 修正:内部长度需包含 \0
|
||
xdata.pszVal = new TCHAR[xdata.npszLen];
|
||
::memset(xdata.pszVal, 0, sizeof(TCHAR) * xdata.npszLen);
|
||
pFileOut->Read(xdata.pszVal, sizeof(TCHAR) * nCharCount);
|
||
break;
|
||
}
|
||
case AecXData::kTypeMatrix:
|
||
{
|
||
// 先读一个 int:等于魔数即为新的二进制块,否则是旧的字符串结构(该 int 是字符数)
|
||
int nHead = 0;
|
||
pFileOut->Read(&nHead, sizeof(int));
|
||
|
||
if (nHead == kMatrixMagic)
|
||
{
|
||
// 新格式:紧接 16 个 double
|
||
double ar[16];
|
||
pFileOut->Read(ar, sizeof(ar));
|
||
SetMatrixData(xdata, ar);
|
||
}
|
||
else
|
||
{
|
||
// 旧格式:nHead 为字符数,读字符串后解析成二进制块
|
||
TCHAR* pszText = new TCHAR[nHead + 1];
|
||
::memset(pszText, 0, sizeof(TCHAR) * (nHead + 1));
|
||
pFileOut->Read(pszText, sizeof(TCHAR) * nHead);
|
||
|
||
double ar[16];
|
||
if (TextToMatrix(pszText, ar))
|
||
SetMatrixData(xdata, ar);
|
||
delete[] pszText;
|
||
}
|
||
break;
|
||
}
|
||
case AecXData::kTypeBinary:
|
||
{
|
||
pFileOut->Read(&xdata.npszLen, sizeof(int));
|
||
xdata.pData = new byte[xdata.npszLen];
|
||
::memset(xdata.pData, 0, xdata.npszLen); // 修正:使用 pData 统一语义
|
||
pFileOut->Read(xdata.pData, (UINT)xdata.npszLen);
|
||
break;
|
||
}
|
||
default:
|
||
delete[] pszKey;
|
||
continue;
|
||
}
|
||
|
||
It it = m_xData.find(pszKey);
|
||
if (it != m_xData.end())
|
||
{
|
||
it->second.Free();
|
||
it->second = xdata;
|
||
}
|
||
else
|
||
{
|
||
m_xData.insert(std::make_pair(pszKey, xdata));
|
||
}
|
||
delete[] pszKey;
|
||
}
|
||
|
||
// 修正:吃掉旧版本留在文件尾部的 MAP_BLOCK_END,防止污染文件流
|
||
if (bIsOldVersion)
|
||
{
|
||
CString sTemp = MAP_BLOCK_END;
|
||
_bstr_t bst((LPCTSTR)sTemp);
|
||
std::string str;
|
||
str.append((const char *)bst);
|
||
std::string str2 = Base64::Encode(str);
|
||
|
||
char *pszBuf = new char[str2.length() + 1];
|
||
memset(pszBuf, 0, str2.length() + 1);
|
||
pFileOut->Read(pszBuf, (UINT)str2.length());
|
||
delete[] pszBuf;
|
||
}
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
BOOL AecDbObjXDataMap::Read(LPCTSTR pszIn, BOOL bWriteUserData)
|
||
{
|
||
if (!pszIn) return 0;
|
||
CMemFile mf;
|
||
Base64::DecodeW2F(pszIn, &mf);
|
||
mf.SeekToBegin();
|
||
return Read(&mf, bWriteUserData);
|
||
}
|
||
|
||
SHJson::WValue& AecDbObjXDataMap::ToJson() const
|
||
{
|
||
AecXData xdata;
|
||
AcGePoint3d ptVal;
|
||
AcGeVector3d vt;
|
||
AcDbSoftPointerId id;
|
||
int type(-1);
|
||
std::wstring name(_T(""));
|
||
|
||
WValue node;
|
||
m_json.SetArray();
|
||
node.SetObject();
|
||
|
||
for (CIt it = m_xData.begin(); it != m_xData.end(); ++it)
|
||
{
|
||
xdata = (*it).second;
|
||
|
||
node.SetNull();
|
||
node.SetObject();
|
||
|
||
WValue value, name;
|
||
value.SetObject();
|
||
|
||
type = xdata.nVt;
|
||
|
||
addMember(node, _T("name"), it->first);
|
||
addMember(node, _T("type"), type);
|
||
|
||
switch (type)
|
||
{
|
||
case AecXData::kTypeShort:
|
||
addMember(node, _T("value"), xdata.iVal);
|
||
case AecXData::kTypeInt: // 整型
|
||
addMember(node, _T("value"), xdata.nVal);
|
||
break;
|
||
case AecXData::kTypeSoftId:
|
||
case AecXData::kTypeHardId:
|
||
addMember(node, _T("value"), xdata.nVal);
|
||
break;
|
||
case AecXData::kTypeDouble: // 浮点
|
||
addMember(node, _T("value"), xdata.dVal[0]);
|
||
break;
|
||
case AecXData::kTypePoint: // 点
|
||
case AecXData::kTypePointWorld:
|
||
toJson(AcGePoint3d(xdata.dVal[0], xdata.dVal[1], xdata.dVal[2]), value);
|
||
addMember(node, _T("value"), value);
|
||
break;
|
||
case AecXData::kTypeVector: // 向量
|
||
case AecXData::kTypeVectorWorld:
|
||
toJson(AcGeVector3d(xdata.dVal[0], xdata.dVal[1], xdata.dVal[2]), value);
|
||
addMember(node, _T("value"), value);
|
||
break;
|
||
case AecXData::kTypeMatrix: //矩阵
|
||
{
|
||
double ar[16];
|
||
if (GetMatrixData(xdata, ar))
|
||
{
|
||
AcGeMatrix3d xform;
|
||
int k = 0;
|
||
for (int i = 0; i < 4; i++)
|
||
for (int j = 0; j < 4; j++)
|
||
xform.entry[i][j] = ar[k++];
|
||
toJson(xform, value);
|
||
addMember(node, _T("value"), value);
|
||
}
|
||
break;
|
||
}
|
||
case AecXData::kTypeBinary: //binary data
|
||
{
|
||
char *p = new char[xdata.npszLen];
|
||
LONG_PTR len(sizeof(char) * xdata.npszLen);
|
||
::memset(p, 0, len);
|
||
::memcpy(p, xdata.pData, len);
|
||
|
||
std::wstring ws(_T(""));
|
||
|
||
value.SetObject();
|
||
addMember(value, _T("len"), len);
|
||
if (len)
|
||
{
|
||
std::string s = Base64::Encode(p, len);
|
||
ws = Base64::ansii2Unicode(s.c_str(), CP_UTF8);
|
||
}
|
||
addMember(value, _T("data"), ws.c_str());
|
||
addMember(node, _T("value"), value);
|
||
|
||
DELETE_ARR_(p);
|
||
break;
|
||
}
|
||
break;
|
||
case AecXData::kTypeString: // 字符串
|
||
addMember(node, _T("value"), xdata.pszVal);
|
||
break;
|
||
default:
|
||
break;
|
||
}
|
||
pushBack(m_json, node);
|
||
}
|
||
return m_json;
|
||
}
|
||
|
||
bool AecDbObjXDataMap::ByJson(const WValue &v)
|
||
{
|
||
if (!v.IsArray()) return false;
|
||
|
||
int type(-1);
|
||
std::wstring name(_T(""));
|
||
for (VCIt it = v.Begin(); it != v.End(); ++it)
|
||
{
|
||
WCValue &vv(*it);
|
||
|
||
if (!vv.IsObject()) continue;
|
||
|
||
if (!vv.HasMember(_T("type"))
|
||
|| !vv.HasMember(_T("name"))
|
||
|| !vv.HasMember(_T("value"))) continue;
|
||
|
||
type = vv[_T("type")].GetInt();
|
||
name = vv[_T("name")].GetString();
|
||
WCValue &va(vv[_T("value")]);
|
||
|
||
switch (type)
|
||
{
|
||
case AecXData::kTypeShort:
|
||
SetAt(name.c_str(), va.GetInt()); //??
|
||
return true;
|
||
case AecXData::kTypeInt: // 整型
|
||
SetAt(name.c_str(), va.GetInt());
|
||
return true;
|
||
case AecXData::kTypeSoftId:
|
||
SetAt(name.c_str(), (DWORD)va.GetUint());
|
||
return true;
|
||
case AecXData::kTypeHardId:
|
||
SetAt(name.c_str(), (DWORD)va.GetUint64());
|
||
return true;
|
||
case AecXData::kTypeDouble: // 浮点
|
||
SetAt(name.c_str(), va.GetDouble());
|
||
return true;
|
||
case AecXData::kTypePoint: // 点
|
||
case AecXData::kTypePointWorld:
|
||
{
|
||
AcGePoint3d pt;
|
||
if (!byJson(va, pt)) return false;
|
||
SetAt(name.c_str(), pt);
|
||
return true;
|
||
}
|
||
case AecXData::kTypeVector: // 向量
|
||
case AecXData::kTypeVectorWorld:
|
||
{
|
||
AcGeVector3d vt;
|
||
if (!byJson(va, vt)) return false;
|
||
SetAt(name.c_str(), vt);
|
||
return true;
|
||
}
|
||
case AecXData::kTypeMatrix: //矩阵
|
||
{
|
||
AcGeMatrix3d m;
|
||
if (byJson(va, m)) return false;
|
||
SetAt(name.c_str(), m);
|
||
return true;
|
||
}
|
||
case AecXData::kTypeBinary: //binary data
|
||
{
|
||
char *pBuffer(NULL);
|
||
|
||
if (va.IsObject())
|
||
{
|
||
MCIt itLen = va.FindMember(_T("len"));
|
||
MCIt itData = va.FindMember(_T("data"));
|
||
if (itLen != va.MemberEnd() && itData != va.MemberEnd())
|
||
{
|
||
LONG_PTR len = itLen->value.GetInt64();
|
||
std::wstring ws = itData->value.GetString();
|
||
std::string s = Base64::unicode2Ansii(ws.c_str(), CP_UTF8);
|
||
|
||
// 这么写的原因是 decode() 函数有问题,反回的长度会大于原有长度,其内存会用0补齐
|
||
// 所以,这里直接用原有长度,并不会影响内存的释放。
|
||
if (Base64::Decode(s, pBuffer) >= len)
|
||
{
|
||
SetAt(name.c_str(), pBuffer, len);
|
||
}
|
||
}
|
||
}
|
||
DELETE_ARR_(pBuffer);
|
||
return true;
|
||
}
|
||
case AecXData::kTypeString: // 字符串
|
||
SetAt(name.c_str(), va.GetString());
|
||
return true;
|
||
default:
|
||
break;
|
||
}
|
||
}
|
||
|
||
return false;
|
||
}
|
||
|
||
bool AecDbObjXDataMap::getBimDatas(const AecDbObjXDataMap & XData, SH_BIM_BLOCK & bim)
|
||
{
|
||
int count(0);
|
||
if (!XData.GetAt(BIM_REC_LEN, count)) return false;
|
||
|
||
bim.clear();
|
||
|
||
int idx(-1);
|
||
CString key, value, n, v;
|
||
for (int i = 0; i < count; ++i)
|
||
{
|
||
key.Format(_T("user%d"), i);
|
||
if (!XData.GetAt(key, value)) continue;
|
||
idx = value.Find(_T(":"));
|
||
if (idx == -1) continue;
|
||
n = value.Left(idx);
|
||
v = value.Right(value.GetLength() - idx - 1);
|
||
bim.push_back(std::make_pair(n, v));
|
||
}
|
||
return !bim.empty();
|
||
}
|
||
|
||
bool AecDbObjXDataMap::setBimDatas(AecDbObjXDataMap & XData, const SH_BIM_BLOCK & bim)
|
||
{
|
||
|
||
int count(0);
|
||
XData.GetAt(BIM_REC_LEN, count);
|
||
|
||
CString name, value;
|
||
for (int i = 0; i < count; ++i)
|
||
{
|
||
name.Format(_T("user%d"), i);
|
||
XData.RemoveAt(name);
|
||
}
|
||
|
||
if (XData.SetAt(BIM_REC_LEN, (int)bim.size()))
|
||
{
|
||
for (int i = 0; i < bim.size(); ++i)
|
||
{
|
||
const SH_BIM_REC &rec(bim[i]);
|
||
name.Format(_T("user%d"), i);
|
||
value.Format(_T("%s:%s"), rec.first, rec.second);
|
||
XData.SetAt(name, value);
|
||
}
|
||
return true;
|
||
}
|
||
return false;
|
||
}
|
||
|
||
bool AecDbObjXDataMap::findBimData(const AecDbObjXDataMap &XData
|
||
, LPCTSTR pszKey
|
||
, CString &strValue
|
||
, CString &strUserKey)
|
||
{
|
||
int count(0);
|
||
if (!XData.GetAt(BIM_REC_LEN, count)) return false;
|
||
|
||
int idx(-1);
|
||
CString key, value, n, v;;
|
||
for (int i = 0; i < count; ++i)
|
||
{
|
||
key.Format(_T("user%d"), i);
|
||
if (!XData.GetAt(key, value)) continue;
|
||
idx = value.Find(_T(":"));
|
||
if (idx == -1) continue;
|
||
n = value.Left(idx);
|
||
if (n == pszKey)
|
||
{
|
||
strUserKey = key;
|
||
strValue = value.Right(value.GetLength() - idx - 1);
|
||
return true;
|
||
}
|
||
}
|
||
return false;
|
||
}
|
||
|
||
bool AecDbObjXDataMap::getBimData(const AecDbObjXDataMap & XData, LPCTSTR pszKey, CString & strValue)
|
||
{
|
||
if (!pszKey) return false;
|
||
CString strUserKey;
|
||
if (!findBimData(XData, pszKey, strValue, strUserKey))
|
||
return false;
|
||
return true;
|
||
}
|
||
|
||
bool AecDbObjXDataMap::setBimData(AecDbObjXDataMap & XData, LPCTSTR pszKey, LPCTSTR pszValue)
|
||
{
|
||
if (!pszKey || !pszValue) return false;
|
||
|
||
CString strUserKey, strValue;
|
||
if (findBimData(XData, pszKey, strValue, strUserKey))
|
||
{
|
||
return XData.SetAt(strUserKey, CString(pszKey) + _T(":") + pszValue) ? true : false;
|
||
}
|
||
else
|
||
{
|
||
int count(0);
|
||
XData.GetAt(BIM_REC_LEN, count);
|
||
CString userKey(_T(""));
|
||
userKey.Format(_T("user%d"), count);
|
||
XData.SetAt(BIM_REC_LEN, count + 1);
|
||
return XData.SetAt(userKey, CString(pszKey) + _T(":") + pszValue) ? true : false;
|
||
}
|
||
return false;
|
||
}
|
||
|
||
bool AecDbObjXDataMap::delBimData(AecDbObjXDataMap & XData, LPCTSTR pszKey)
|
||
{
|
||
if (!pszKey) return false;
|
||
|
||
CString strUserKey, strValue;
|
||
if (!findBimData(XData, pszKey, strValue, strUserKey)) return false;
|
||
|
||
if (XData.RemoveAt(strUserKey))
|
||
{
|
||
int count(0);
|
||
XData.GetAt(BIM_REC_LEN, count);
|
||
if (count > 0)
|
||
XData.SetAt(BIM_REC_LEN, count - 1);
|
||
return true;
|
||
}
|
||
return false;
|
||
}
|
||
|
||
size_t AecDbObjXDataMap::Count() const
|
||
{
|
||
return m_xData.size();
|
||
}
|
||
|
||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
||
AecXData::AecXData()
|
||
{
|
||
nVt = 0;
|
||
npszLen = 0;
|
||
nVal = 0; // 清零 union,防止野指针
|
||
}
|
||
|
||
bool AecXData::CopyFrom(const AecXData& src)
|
||
{
|
||
if (this == &src) return true;
|
||
|
||
Free();
|
||
|
||
nVt = src.nVt;
|
||
npszLen = src.npszLen;
|
||
|
||
// 先整体复制 union(POD 类型一次到位),字符串/二进制随后重新分配覆盖
|
||
memcpy(dVal, src.dVal, sizeof(dVal));
|
||
|
||
if (src.nVt == AecXData::kTypeString)
|
||
{
|
||
// 字符串
|
||
pszVal = NULL;
|
||
if (src.pszVal != NULL && src.npszLen > 0)
|
||
{
|
||
pszVal = new TCHAR[src.npszLen];
|
||
_tcsncpy_s(pszVal, src.npszLen, src.pszVal, src.npszLen - 1);
|
||
}
|
||
else
|
||
{
|
||
npszLen = 0;
|
||
}
|
||
}
|
||
else if (src.nVt == AecXData::kTypeMatrix)
|
||
{
|
||
// 统一规范化为 [魔数][16个double] 的二进制块
|
||
double ar[16];
|
||
if (GetMatrixData(src, ar))
|
||
SetMatrixData(*this, ar);
|
||
else
|
||
{
|
||
nVt = 0;
|
||
npszLen = 0;
|
||
nVal = 0;
|
||
}
|
||
}
|
||
else if (src.nVt == AecXData::kTypeBinary)
|
||
{
|
||
// 二进制数据块
|
||
pData = NULL;
|
||
if (src.pData != NULL && src.npszLen > 0)
|
||
{
|
||
pData = new byte[src.npszLen];
|
||
memcpy(pData, src.pData, src.npszLen);
|
||
}
|
||
else
|
||
{
|
||
npszLen = 0;
|
||
}
|
||
}
|
||
|
||
return true;
|
||
}
|
||
|
||
void AecXData::Free()
|
||
{
|
||
// 字符串类型(用 pszVal 保存)
|
||
if (nVt == kTypeString)
|
||
{
|
||
if (pszVal != NULL && npszLen > 0)
|
||
{
|
||
delete[] pszVal;
|
||
pszVal = NULL;
|
||
}
|
||
}
|
||
// 二进制数据块类型(矩阵也以16个double的二进制块保存,同为 pData)
|
||
else if (nVt == kTypeBinary || nVt == kTypeMatrix)
|
||
{
|
||
if (pData != NULL && npszLen > 0)
|
||
{
|
||
// 必须强制转换 void* 为 byte* 才能触发 C++ 正确的数组析构逻辑
|
||
delete[] (byte*)pData;
|
||
pData = NULL;
|
||
}
|
||
}
|
||
|
||
// 重置状态
|
||
npszLen = 0;
|
||
nVt = 0;
|
||
nVal = 0;
|
||
}
|