diff --git a/SourceCode/Code2026/AecRxBase/AecDbObjXDataMap.cpp b/SourceCode/Code2026/AecRxBase/AecDbObjXDataMap.cpp index ea021b1..6a6ff2c 100644 --- a/SourceCode/Code2026/AecRxBase/AecDbObjXDataMap.cpp +++ b/SourceCode/Code2026/AecRxBase/AecDbObjXDataMap.cpp @@ -30,7 +30,24 @@ static char THIS_FILE[]=__FILE__; #endif -const int AecDbObjXDataMap::g_nVersion = 0x41454301; // 魔数: 'AEC' + 0x01; +// 文件头版本号(魔数 '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; @@ -115,6 +132,211 @@ namespace } 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() @@ -132,26 +354,35 @@ 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(pszKey, xdata)); + } + + xdata.nVt = 0; + xdata.npszLen = 0; + xdata.nVal = 0; +} + BOOL AecDbObjXDataMap::SetAt( LPCTSTR pszKey, const int &nVal ) { if (pszKey != NULL) { AecXData xdata; - memset(&xdata,0,sizeof(xdata)); xdata.nVt = AecXData::kTypeInt; xdata.nVal = nVal; - It it = m_xData.find(pszKey); - if (it != m_xData.end()) - { - it->second.Free(); - (*it).second = xdata; - } - else - { - std::pair pa(pszKey,xdata); - m_xData.insert(pa); - } + SetXData(pszKey, xdata); return TRUE; } return FALSE; @@ -162,21 +393,10 @@ BOOL AecDbObjXDataMap::SetAt(LPCTSTR pszKey, const Adesk::Int16 &nVal) if (pszKey != NULL) { AecXData xdata; - memset(&xdata, 0, sizeof(xdata)); xdata.nVt = AecXData::kTypeShort; xdata.nVal = nVal; - It it = m_xData.find(pszKey); - if (it != m_xData.end()) - { - it->second.Free(); - (*it).second = xdata; - } - else - { - std::pair pa(pszKey, xdata); - m_xData.insert(pa); - } + SetXData(pszKey, xdata); return TRUE; } return FALSE; @@ -187,21 +407,10 @@ BOOL AecDbObjXDataMap::SetAt(LPCTSTR pszKey, const DWORD &dw) if (pszKey != NULL) { AecXData xdata; - memset(&xdata,0,sizeof(xdata)); xdata.nVt = AecXData::kTypeInt; xdata.nVal = dw; - It it = m_xData.find(pszKey); - if (it != m_xData.end()) - { - it->second.Free(); - (*it).second = xdata; - } - else - { - std::pair pa(pszKey,xdata); - m_xData.insert(pa); - } + SetXData(pszKey, xdata); return TRUE; } return FALSE; @@ -212,21 +421,10 @@ BOOL AecDbObjXDataMap::SetAt(LPCTSTR pszKey, const double &dVal) if (pszKey != NULL) { AecXData xdata; - memset(&xdata,0,sizeof(xdata)); xdata.nVt = AecXData::kTypeDouble; xdata.dVal[0] = dVal; - - It it = m_xData.find(pszKey); - if (it != m_xData.end()) - { - it->second.Free(); - (*it).second = xdata; - } - else - { - std::pair pa(pszKey,xdata); - m_xData.insert(pa); - } + + SetXData(pszKey, xdata); return TRUE; } return FALSE; @@ -234,19 +432,16 @@ BOOL AecDbObjXDataMap::SetAt(LPCTSTR pszKey, const double &dVal) BOOL AecDbObjXDataMap::SetAt(LPCTSTR pszKey,const AcGeDoubleArray& arVal) { - if (pszKey != NULL) - { - CString sSubKey; - for (int i = 0;i < arVal.length();++i) - { - sSubKey.Format(_T("%s%d"),pszKey,i); - SetAt(sSubKey,arVal[i]); - } + // 整个数组保存为一个 [魔数][个数][double...] 的二进制块,避免精度丢失 + if (pszKey == NULL) + return FALSE; - return TRUE; - } + AecXData xdata; + SetDoubleArrayData(xdata, arVal); - return FALSE; + SetXData(pszKey, xdata); + + return TRUE; } BOOL AecDbObjXDataMap::SetAt(LPCTSTR pszKey,const AcGeVector3d& vt,BOOL bTransformBy) { @@ -259,7 +454,6 @@ BOOL AecDbObjXDataMap::SetAt(LPCTSTR pszKey,const AcGeVector3d& vt,BOOL bTransfo CString sTmpKey = pszKey; sTmpKey += DIF_VT_PT; AecXData xdata; - memset(&xdata,0,sizeof(xdata)); xdata.nVt = AecXData::kTypeVector; if(bTransformBy) { @@ -270,17 +464,7 @@ BOOL AecDbObjXDataMap::SetAt(LPCTSTR pszKey,const AcGeVector3d& vt,BOOL bTransfo xdata.dVal[1] = vt.y; xdata.dVal[2] = vt.z; - It it = m_xData.find(sTmpKey); - if (it != m_xData.end()) - { - it->second.Free(); - (*it).second = xdata; - } - else - { - std::pair pa(sTmpKey,xdata); - m_xData.insert(pa); - } + SetXData(sTmpKey, xdata); return TRUE; } return FALSE; @@ -294,7 +478,6 @@ BOOL AecDbObjXDataMap::SetAt(LPCTSTR pszKey,const AcGePoint3d& ptGe,BOOL bTransf if (pszKey != NULL) { AecXData xdata; - memset(&xdata,0,sizeof(xdata)); xdata.nVt = AecXData::kTypePoint; if (bTransformBy) { @@ -305,18 +488,8 @@ BOOL AecDbObjXDataMap::SetAt(LPCTSTR pszKey,const AcGePoint3d& ptGe,BOOL bTransf xdata.dVal[0] = ptGe.x; xdata.dVal[1] = ptGe.y; xdata.dVal[2] = ptGe.z; - - It it = m_xData.find(pszKey); - if (it != m_xData.end()) - { - it->second.Free(); - (*it).second = xdata; - } - else - { - std::pair pa(pszKey,xdata); - m_xData.insert(pa); - } + + SetXData(pszKey, xdata); return TRUE; } return FALSE; @@ -324,56 +497,36 @@ BOOL AecDbObjXDataMap::SetAt(LPCTSTR pszKey,const AcGePoint3d& ptGe,BOOL bTransf BOOL AecDbObjXDataMap::SetAt(LPCTSTR pszKey,const AcGePoint3dArray& arPt,BOOL bTransformBy) { - if (pszKey != NULL) - { - CString sSubKey; - for (int i = 0;i < arPt.length();++i) - { - sSubKey.Format(_T("%s%d"),pszKey,i); - SetAt(sSubKey,arPt[i],bTransformBy); - } - - return TRUE; - } - - return FALSE; + // 整个点数组保存为一个 [魔数][个数][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) { - AecXData xdata; - memset(&xdata,0,sizeof(xdata)); - xdata.nVt = AecXData::kTypeMatrix; - - CString sText = _T(""),sTemp; + double ar[16]; + int k = 0; for (int i = 0;i < 4;i++) { for (int j = 0;j < 4;j++) { - sTemp.Format(_T("%.9f"),xform.entry[i][j]); - sText += _T(",") + sTemp; + ar[k++] = xform.entry[i][j]; } } - sText.TrimLeft(_T(",")); - xdata.npszLen = sText.GetLength() + 1; - xdata.pszVal = new TCHAR[xdata.npszLen]; - ::memset(xdata.pszVal, 0, xdata.npszLen * sizeof(TCHAR)); - _tcsncpy_s(xdata.pszVal, xdata.npszLen, sText, xdata.npszLen - 1); + AecXData xdata; + SetMatrixData(xdata, ar); // 打包成 [魔数][16个double] 的二进制块 - It it = m_xData.find(pszKey); - if (it != m_xData.end()) //找到 - { - it->second.Free(); - (*it).second = xdata; - } - else //未找到 - { - std::pair pa(pszKey,xdata); - m_xData.insert(pa); - } + SetXData(pszKey, xdata); return TRUE; } return FALSE; @@ -384,55 +537,23 @@ BOOL AecDbObjXDataMap::SetAt(LPCTSTR pszKey,void* pData,int nSize) if (pszKey != NULL && nSize > 0 && pData != NULL) { AecXData xdata; - memset(&xdata,0,sizeof(xdata)); xdata.nVt = AecXData::kTypeBinary; xdata.npszLen = nSize; xdata.pData = new byte[nSize]; memcpy(xdata.pData,pData,nSize); - It it = m_xData.find(pszKey); - if (it != m_xData.end()) //找到 - { - it->second.Free(); - (*it).second = xdata; - } - else //未找到 - { - std::pair pa(pszKey,xdata); - m_xData.insert(pa); - } + SetXData(pszKey, xdata); return TRUE; } return FALSE; } -static BOOL Script2StringArray(const CString& sScript,TCHAR tSpace,CStringArray& arTexts) +CString AecDbObjXDataMap::MatrixToString(const AecXData& xdata) { - //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; + MatrixToText(xdata, sText); + return sText; } BOOL AecDbObjXDataMap::GetAt(LPCTSTR pszKey,AcGeMatrix3d& xform) const @@ -442,24 +563,14 @@ BOOL AecDbObjXDataMap::GetAt(LPCTSTR pszKey,AcGeMatrix3d& xform) const CIt it; if ((it = m_xData.find(pszKey)) != m_xData.end()) { - AecXData xdata = (*it).second; - if ( xdata.nVt == AecXData::kTypeMatrix) + double ar[16]; + if (GetMatrixData((*it).second, ar)) { - CString sText = xdata.pszVal; - CStringArray arTexts; - - 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)); - } - } - return TRUE; - } + 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; } } } @@ -468,28 +579,19 @@ BOOL AecDbObjXDataMap::GetAt(LPCTSTR pszKey,AcGeMatrix3d& xform) const BOOL AecDbObjXDataMap::SetAt(LPCTSTR pszKey,LPCTSTR pszValue) { - if (!pszKey) return FALSE; + 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); - if (!pszValue || _tcslen(pszValue) == 0) - return FALSE; - - int nVt = 0; - if (HasKey(pszKey, nVt)) - RemoveAt(pszKey); - - AecXData xdata; - memset(&xdata, 0, sizeof(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); - - std::pair pa(pszKey, xdata); - m_xData.insert(pa); - - return TRUE; + SetXData(pszKey, xdata); + return TRUE; + } + return FALSE; } BOOL AecDbObjXDataMap::SetAt(LPCTSTR pszKey,int iIndex,LPCTSTR pszValue) @@ -606,7 +708,7 @@ BOOL AecDbObjXDataMap::SetAt(LPCTSTR pszKey,int iIndex,const AecDbObjXDataMap& x case AecXData::kTypeMatrix: // 矩阵 { sType.Format(_T("%d"),AecXData::kTypeMatrix); - sInfo.Format(_T("%s"),xdata.pszVal); + MatrixToText(xdata, sInfo); sRecord.Format(_T("{%s|%s|%s}"),sKey,sType,sInfo); sText += sRecord; break; @@ -745,7 +847,6 @@ BOOL AecDbObjXDataMap::GetAt(LPCTSTR pszKey,int iIndex,AecDbObjXDataMap& xDataMa AcGeVector3d vt; BOOL bSuccess = FALSE; AcDbObjectId id; - AecXData xDat; if (GetAt(pszKey,iIndex,sText)) { @@ -830,12 +931,16 @@ BOOL AecDbObjXDataMap::GetAt(LPCTSTR pszKey,int iIndex,AecDbObjXDataMap& xDataMa } case AecXData::kTypeMatrix: //矩阵 { - memset(&xDat,0,sizeof(AecXData)); - xDat.npszLen = sInfo.GetLength() + 1; - xDat.pszVal = new TCHAR[xDat.npszLen]; - _tcsncpy_s(xDat.pszVal, xDat.npszLen, sInfo, xDat.npszLen - 1); - xDataMap.SetAt(sKey,xDat); - delete[] xDat.pszVal; + 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 @@ -870,26 +975,56 @@ BOOL AecDbObjXDataMap::GetAt(LPCTSTR pszKey,int iIndex,AecDbObjXDataMap& xDataMa 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; - memset(&xdata,0,sizeof(xdata)); xdata.nVt = AecXData::kTypeSoftId; if (!bIsSoft) xdata.nVt = AecXData::kTypeHardId; xdata.nVal = id.asOldId(); - It it = m_xData.find(pszKey); - if (it != m_xData.end()) - { - (*it).second.Free(); - (*it).second = xdata; - } - else - { - std::pair pa(pszKey,xdata); - m_xData.insert(pa); - } + SetXData(pszKey, xdata); return TRUE; } return FALSE; @@ -909,50 +1044,6 @@ BOOL AecDbObjXDataMap::SetAt(LPCTSTR pszKey,const AcDbHandle& handle) return FALSE; } -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 || src.nVt == AecXData::kTypeMatrix) - { - // 字符串 / 矩阵(矩阵以逗号分隔的字符串存储) - 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::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; -} - BOOL AecDbObjXDataMap::SetAt(LPCTSTR pszKey,const AecXData& XData) { if (pszKey == NULL) return FALSE; @@ -1101,18 +1192,23 @@ BOOL AecDbObjXDataMap::GetAt(LPCTSTR pszKey,double& dVal) const BOOL AecDbObjXDataMap::GetAt(LPCTSTR pszKey,AcGeDoubleArray& arVal) const { arVal.setLogicalLength(0); - if (pszKey != NULL) - { - CString sSubKey; - double dVal; + if (pszKey == NULL) + return FALSE; - int nIndex = 0; + // 新格式:单个二进制块([魔数][个数][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++); - while(GetAt(sSubKey,dVal)) - { - arVal.append(dVal); - sSubKey.Format(_T("%s%d"),pszKey,nIndex++); - } } return (arVal.length() > 0); @@ -1172,20 +1268,25 @@ BOOL AecDbObjXDataMap::GetAt(LPCTSTR pszKey,AcGePoint3d& ptGe) const BOOL AecDbObjXDataMap::GetAt(LPCTSTR pszKey,AcGePoint3dArray& arPt) const { arPt.setLogicalLength(0); - if (pszKey != NULL) + 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)) { - CString sSubKey; - AcGePoint3d pt; - - int nIndex = 0; + arPt.append(pt); 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); } @@ -1198,12 +1299,16 @@ BOOL AecDbObjXDataMap::GetAt(LPCTSTR pszKey,CString &sValue) const { AecXData xdata = (*it).second; - if (xdata.nVt == AecXData::kTypeString || - xdata.nVt == AecXData::kTypeMatrix) + 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); @@ -1491,7 +1596,11 @@ void AecDbObjXDataMap::List() const acutPrintf(_T("%.9f,%.9f,%.9f : Vector3d"),xdata.dVal[0],xdata.dVal[1],xdata.dVal[2]); break; case AecXData::kTypeMatrix: // 矩阵 - acutPrintf(_T("%s : Matrix3d"),xdata.pszVal); + { + 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); @@ -1505,28 +1614,18 @@ void AecDbObjXDataMap::List() const } } -void AecDbObjXDataMap::List(CListCtrl* pList,int nImage) const +void AecDbObjXDataMap::List(std::vector& pList) const { - if (pList == NULL) - return List(); - AecXData xdata; int nVt = -1; - AcGePoint3d ptVal; - AcGeVector3d vt; - AcDbObjectId id; - int nItem = -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)); - //acutPrintf(_T("\n%s:"), (const TCHAR *)(*it).first); - nItem = pList->InsertItem(pList->GetItemCount(), (const TCHAR *)(*it).first, nImage ); + memset(szData, 0, sizeof(szData)); switch (nVt) { @@ -1566,7 +1665,11 @@ void AecDbObjXDataMap::List(CListCtrl* pList,int nImage) const swprintf(szData, _T("(%.3f,%.3f,%.3f) : Vector3d"), xdata.dVal[0], xdata.dVal[1], xdata.dVal[2]); break; case AecXData::kTypeMatrix: // 矩阵 - swprintf(szData, _T("%s : Matrix3d"), xdata.pszVal); + { + 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); @@ -1589,10 +1692,9 @@ void AecDbObjXDataMap::List(CListCtrl* pList,int nImage) const break; } - if (_tcslen(szData) > 0) - { - pList->SetItemText(nItem, 1, szData); - } + // 每个元素占两项:先 key(名称),后 value(数据)。 + pList.push_back((*it).first); + pList.push_back(szData); } } @@ -1632,7 +1734,11 @@ static bool XDataEqu(const AecXData& xdata1,const AecXData& xdata2) return false; break; case AecXData::kTypeMatrix: // 矩阵 - if (_tcscmp(xdata1.pszVal,xdata2.pszVal) != 0) + 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 @@ -1738,7 +1844,11 @@ Acad::ErrorStatus AecDbObjXDataMap::dxfOutFields(AcDbDxfFiler* pFiler) const pFiler->writeVector3d(AcDb::kDxfXdWorldXDir, vt); break; case AecXData::kTypeMatrix: // 矩阵 - pFiler->writeString(AcDb::kDxfXdAsciiString, xdata.pszVal); + { + CString sMat; + MatrixToText(xdata, sMat); + pFiler->writeString(AcDb::kDxfXdAsciiString, (LPCTSTR)sMat); + } break; case AecXData::kTypeBinary: // binary data { @@ -1855,7 +1965,18 @@ Acad::ErrorStatus AecDbObjXDataMap::dxfInFields(AcDbDxfFiler* pFiler) SetAt(sKey, asPnt3d(rb.resval.rpoint),TRUE); break; case AecXData::kTypeMatrix: //矩阵 - SetAt(sKey, rb.resval.rstring); + { + 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); @@ -1963,7 +2084,11 @@ Acad::ErrorStatus AecDbObjXDataMap::dwgOutFields(AcDbDwgFiler* pFiler) const pFiler->writeVector3d(vt); break; case AecXData::kTypeMatrix: //矩阵 - pFiler->writeString(xdata.pszVal); + { + CString sMat; + MatrixToText(xdata, sMat); + pFiler->writeString((LPCTSTR)sMat); + } break; case AecXData::kTypeBinary: //binary data { @@ -2314,9 +2439,13 @@ BOOL AecDbObjXDataMap::XDMap2Resbuf(LPCTSTR pszApp, struct resbuf*& pRb,BOOL bXR pTemp->rbnext = pTempNext; break; case AecXData::kTypeMatrix: // 矩阵 - pTempNext = acutNewRb(AcDb::kDxfXdAsciiString); - acutNewString(iter->second.pszVal, pTempNext->resval.rstring); - pTemp->rbnext = pTempNext; + { + 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); @@ -2375,6 +2504,10 @@ void AecDbObjXDataMap::SecondAsKey(CString& sTemp,AecXData& xData) 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; @@ -2924,7 +3057,19 @@ BOOL AecDbObjXDataMap::Write(CFile* pFileOut,BOOL bWriteUserData) const case AecXData::kTypeVectorWorld: pFileOut->Write(xdata.dVal,sizeof(double) * 3); break; - case AecXData::kTypeMatrix: //矩阵 + 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); @@ -3042,10 +3187,11 @@ BOOL AecDbObjXDataMap::Read(CFile *pFileOut, BOOL bWriteUserData) ULONGLONG startPos = pFileOut->GetPosition(); pFileOut->Read(&nMarker, sizeof(int)); - BOOL bIsOldVersion = FALSE; + BOOL bIsOldVersion = FALSE; // 无版本头(老格式,文件以 Base64 块标记开头) if (nMarker != g_nVersion) { + // 无版本头:回退跳过 Base64(MAP_BLOCK_BEGIN) 前缀 bIsOldVersion = TRUE; pFileOut->Seek(startPos, CFile::begin); @@ -3110,7 +3256,6 @@ BOOL AecDbObjXDataMap::Read(CFile *pFileOut, BOOL bWriteUserData) case AecXData::kTypeVectorWorld: pFileOut->Read(xdata.dVal, sizeof(double) * 3); break; - case AecXData::kTypeMatrix: case AecXData::kTypeString: { int nCharCount = 0; @@ -3121,6 +3266,33 @@ BOOL AecDbObjXDataMap::Read(CFile *pFileOut, BOOL bWriteUserData) 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)); @@ -3228,23 +3400,17 @@ SHJson::WValue& AecDbObjXDataMap::ToJson() const break; case AecXData::kTypeMatrix: //矩阵 { - AcGeMatrix3d xform; - CString sText = xdata.pszVal; - CStringArray arTexts; - - Script2StringArray(sText, _T(','), arTexts); - if (arTexts.GetSize() == 16) + 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] = _ttof(arTexts.GetAt(i * 4 + j)); - } - } + xform.entry[i][j] = ar[k++]; + toJson(xform, value); + addMember(node, _T("value"), value); } - toJson(xform, value); - addMember(node, _T("value"), value); break; } case AecXData::kTypeBinary: //binary data @@ -3505,3 +3671,97 @@ 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; +} diff --git a/SourceCode/Code2026/CoreCommand/CCKSXDlg.cpp b/SourceCode/Code2026/CoreCommand/CCKSXDlg.cpp index bc155a1..062106f 100644 --- a/SourceCode/Code2026/CoreCommand/CCKSXDlg.cpp +++ b/SourceCode/Code2026/CoreCommand/CCKSXDlg.cpp @@ -1,6 +1,7 @@ #include "stdafx.h" #include "CCKSXDlg.h" #include "AecDbObjXDataMap.h" +#include IMPLEMENT_DYNAMIC(CCKSXDlg, CDialog) @@ -77,10 +78,19 @@ BOOL CCKSXDlg::OnInitDialog() void CCKSXDlg::ListXDataMap(AecDbObjXDataMap *pXDataMap) { - if (pXDataMap != NULL) + if (pXDataMap == NULL) + return; + + m_wndListXData.DeleteAllItems(); + + std::vector vecItems; + pXDataMap->List(vecItems); + + // List() 每个元素输出两项:先 key(名称列),后 value(数据列)。 + for (size_t i = 0; i + 1 < vecItems.size(); i += 2) { - m_wndListXData.DeleteAllItems(); - pXDataMap->List(&m_wndListXData, 0); + int nItem = m_wndListXData.InsertItem(m_wndListXData.GetItemCount(), vecItems[i]); + m_wndListXData.SetItemText(nItem, 1, vecItems[i + 1]); } } diff --git a/SourceCode/Code2026/inc/AecDbObjXDataMap.h b/SourceCode/Code2026/inc/AecDbObjXDataMap.h index 8e8eb48..591ed02 100644 --- a/SourceCode/Code2026/inc/AecDbObjXDataMap.h +++ b/SourceCode/Code2026/inc/AecDbObjXDataMap.h @@ -36,7 +36,9 @@ typedef std::pair SH_BIM_REC; typedef std::vector SH_BIM_BLOCK; -typedef struct AecXData +// AecXData 会被其它模块(CoreLibrary / 各 Cmd)直接构造使用,必须随 AecRxBase 一起导出, +// 否则成员函数定义在 .cpp 里时其它模块会 LNK2019(unresolved external symbol)。 +typedef struct AECDLLIMPEXP AecXData { // 数据类型标签(nVt)。直接用 wtypes.h 的 VARENUM(VT_*) 组合来表达,直观且与 // 原实现逐位一致;nVt 会写入 DWG/DXF/XData,改数值会破坏旧图兼容,务必保持不变。 @@ -53,7 +55,7 @@ typedef struct AecXData kTypePointWorld = (VT_BYREF | VT_R8) + 1, // 点,随实体变换 kTypeVector = (VT_BYREF | VT_R8) + 2, // 向量,不随实体变换 kTypeVectorWorld = (VT_BYREF | VT_R8) + 3, // 向量,随实体变换 - kTypeMatrix = (VT_BYREF | VT_R8) + 4, // 矩阵(16个double串) + kTypeMatrix = (VT_BYREF | VT_R8) + 4, // 矩阵(16个double,二进制块,128字节) kTypeBinary = (VT_BYREF | VT_R8) + 5, // 二进制块 }; @@ -70,44 +72,11 @@ typedef struct AecXData }; // 1. 默认构造函数,替代原有代码中散落的 memset(&xdata, 0, sizeof(xdata)); - // 注意:struct AecXData 未 dllexport,这两个函数必须 inline 在头文件里, - // 否则其它模块(CoreLibrary / 各 Cmd)构造 AecXData 时会链接不到。 - AecXData() - { - nVt = 0; - npszLen = 0; - nVal = 0; // 清零 union,防止野指针 - } + // 实现见 AecDbObjXDataMap.cpp(随本 DLL 导出,其它模块可直接构造)。 + AecXData(); // 2. 核心清理函数 - void Free() - { - // 字符串和矩阵类型(两者都用 pszVal 保存) - if (nVt == kTypeString || nVt == kTypeMatrix) - { - if (pszVal != NULL && npszLen > 0) - { - delete[] pszVal; - pszVal = NULL; - } - } - // 二进制数据块类型 - else if (nVt == kTypeBinary) - { - if (pData != NULL && npszLen > 0) - { - // 必须强制转换 void* 为 byte* 才能触发 C++ 正确的数组析构逻辑 - delete[] (byte*)pData; - pData = NULL; - } - } - - // 重置状态 - npszLen = 0; - nVt = 0; - nVal = 0; - } - + void Free(); // 3. 深拷贝:先释放自身已持有的资源,再从 src 深拷贝。 // 字符串/矩阵/二进制会重新分配内存,不与 src 共享缓冲; @@ -126,6 +95,9 @@ public: AecDbObjXDataMap(const AecDbObjXDataMap& datamap); virtual ~AecDbObjXDataMap(); + // 把 kTypeMatrix 的 16 个 double 二进制块格式化为逗号分隔文本(供显示/比较使用) + static CString MatrixToString(const AecXData& xdata); + public: BOOL SetAt(LPCTSTR pszKey, const int &nVal); BOOL SetAt(LPCTSTR pszKey, const DWORD &dw); @@ -150,6 +122,11 @@ public: BOOL SetAt(LPCTSTR pszKey,const AcGeMatrix3d& xform); BOOL SetAt(LPCTSTR pszKey,void* pData,int nSize); + + BOOL SetAt(LPCTSTR pszKey, const AecDbObjXDataMap& xDataMap); + + BOOL GetAt(LPCTSTR pszKey, AecDbObjXDataMap& xDataMap); + BOOL GetAt(LPCTSTR pszKey,void*& pData,int& nSize) const; BOOL GetAt(LPCTSTR pszKey,int& nVal) const; @@ -244,7 +221,8 @@ public: //prinf输出 void List() const; - void List(CListCtrl *pList, int nImage) const; + // 输出到字符串数组:每个元素占两项(先 key,后 value),供界面按两列展示。 + void List(std::vector &pList) const; int ComparedTo(const AecDbObjXDataMap* pXDataMap) const; @@ -297,6 +275,9 @@ private: void SecondAsKey(CString& sTemp,AecXData& xData); + // 把 xdata 以 pszKey 存入(已存在则覆盖)。接管 xdata 的所有权(内部把源置空)。 + void SetXData(LPCTSTR pszKey, AecXData &xdata); + private: mutable SHJson::WValue m_json;//临时,不序列化