Files
envi-code/SourceCode/Code2026/AecRxBase/AecDbObjXDataMap.cpp
T
company-desktop-computer 199abb989c 重构: AecDbObjXDataMap 解耦 UI,并统一 SetAt/数组实现
- 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 后填充两列列表。
2026-10-13 15:28:19 +08:00

3768 lines
89 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#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;
}