fix: 修复 AecDbEwEquipment 的 10 处逻辑缺陷

3.2 subErase:sName.Find(_T("接头")) 当布尔用,找不到返回 -1 也为真,
    整个条件恒成立,删除任何设备都走阀门/接头的合并管线分支。补 != -1。

3.3 DrawHandFlg:else 分支写成 sFlag == _T("Y"),液动阀(3)符号文字一直是空串。

3.4 ProcessHlrResult:遍历 map 时 erase(it) 之后仍然 ++it。改成 while +
    erase(it++),没有用 it = erase(it),因为 R190 走 C++98 标准,
    C++03 的 map::erase(iterator) 返回 void。

3.5 GetSectionDraw:返回 nCount - nCoundPre(调用前减调用后),恒为 0 或负数。
    改为 nCoundPre - nCount。全库调用点都忽略返回值,此前无实际故障。

3.8 copyFrom:补拷 m_bVert / m_idDash / m_idCenter。原来复制粘贴竖放阀门
    会变横放,虚线与中心线的图层也丢失。

3.9 MakeBlockRefSet:判断的是累加器 ext 而不是本次的 extAdd,第一轮 ext 还是
    空状态,第一个实体的范围永远加不进去;块参照分支不 continue,extAdd 会
    沿用上一轮的值被重复累加。改为块参照跳过、extAdd 每轮新建并检查返回值。

3.10 byJson:br._len 是字节数,却按 new PVOID[br._len] 分配、按
     sizeof(PVOID)*br._len 拷贝,源缓冲区越界读 7 倍。改为按字节分配拷贝,
     并用 br._len 覆盖 m_nSize。

3.11 dwgInFieldsForXPrim:加 16MB 上限(kMaxXPrimDataSize),超限置
     eInvalidInput 让整个 dwgInFields 退出;readBytes 检查返回值,失败时释放。

3.13 GetBodyBox:恒返回 TRUE,调用方无法区分是否取到几何;_ext 在循环外定义,
     会把上一轮的累积结果重复并入。改为返回实际结果、每轮新建 _ext。

3.14 clearGeoBuffer:函数体只有 AssertWriteEnabled(),改完参数几何不刷新。
     改为 Clean2DBuffer() + Clean3DBuffer()。

未处理,见文档 5.4:3.6 HLR_CALC 序列化(要动 AecDbObjXDataMap 公共类)、
3.7 GetInterface 数组版单位(影响 67 处调用)、3.12 mat4 双次变换(需确认是否刻意)。
This commit is contained in:
company-desktop committed 2026-10-25 11:21:11 +08:00
1 parent 44f53dede4
commit f668e29b6c
2 files changed
+142 -47

No files matched your search

@@ -76,6 +76,9 @@ struct Point2d
namespace
{
//单个几何单元的参数块上限:正常只有几十字节到几十 KB,超出即视为图纸损坏
const Adesk::Int32 kMaxXPrimDataSize = 16 * 1024 * 1024;
bool isValidExtents(const AcDbExtents &ext)
{
// 检查是否仍然处于初始化的“反转”状态
@@ -188,10 +191,24 @@ namespace
pFiler->readInt32(&nSize);
pSolid->m_nSize = nSize;
//单个单元的参数块只有几十字节到几十 KB,超出上限说明图纸损坏。
//直接 new byte[巨量] 会当场失败,这里标记文件错误让整个 dwgInFields 退出
if (pSolid->m_nSize > kMaxXPrimDataSize)
{
pSolid->m_nSize = 0;
pFiler->setFilerStatus(Acad::eInvalidInput);
return pSolid;
}
if (pSolid->m_nSize > 0)
{
pSolid->m_pData = new byte[pSolid->m_nSize];
pFiler->readBytes(pSolid->m_pData, (Adesk::UInt32)pSolid->m_nSize);
if (pFiler->readBytes(pSolid->m_pData, (Adesk::UInt32)pSolid->m_nSize) != Acad::eOk)
{
delete[] (byte*)pSolid->m_pData;
pSolid->m_pData = NULL;
pSolid->m_nSize = 0;
}
}
//ID 存2个32为
@@ -825,8 +842,15 @@ namespace
it = v.FindMember(_T("__pData__"));
if (it == v.MemberEnd()) return false;
GEO2JSON::binary br(it->value);
p->m_pData = new PVOID[br._len];
::memcpy(p->m_pData, br._data, sizeof(PVOID) * br._len);
//br._len 是字节数,与 __nSize__ 同单位。原来按 PVOID 个数分配、
//再按 sizeof(PVOID)*len 拷贝,源缓冲区会越界读 7 倍。
//两者不一致说明 JSON 被改过,按实际数据长度为准
p->m_nSize = (int)br._len;
if (br._len > 0 && br._data != NULL)
{
p->m_pData = new byte[br._len];
::memcpy(p->m_pData, br._data, br._len);
}
it = v.FindMember(_T("__nActiveInf__"));
if (it == v.MemberEnd()) return false;
@@ -2110,7 +2134,11 @@ Acad::ErrorStatus AecDbEwEquipment::subErase(Adesk::Boolean erasing)
int nVal = 1;
m_mapSpecXData.GetAt(PIPE_VALVE, nVal);
if (eSubType == eValve || sName.Find(_T("阀") ) != -1 || sName.Find(_T("接头")))
//第三个条件原来写成 sName.Find(_T("接头")),Find 找不到返回 -1,
//非 0 即真,整个条件恒成立,删除任何设备都会走下面的合并管线逻辑
if (eSubType == eValve
|| sName.Find(_T("阀")) != -1
|| sName.Find(_T("接头")) != -1)
{
AecEqui::ValveType eVlvType = (AecEqui::ValveType)nVal;
//if (eVlvType >= AecEqui::eGateVlv && eVlvType <= AecEqui::eJYF)
@@ -2184,6 +2212,13 @@ Acad::ErrorStatus AecDbEwEquipment::copyFrom(const AcRxObject* pSrc)
m_nInfActive = pImp->m_nInfActive;
m_ptInsert = pImp->m_ptInsert;
m_vtDir = pImp->m_vtDir;
//这三个原来漏拷:m_bVert 决定阀门横放还是竖放(TransformEntity 要用),
//m_idDash / m_idCenter 是虚线与中心线所在的图层,丢了会跑到默认图层
m_bVert = pImp->m_bVert;
m_idDash = pImp->m_idDash;
m_idCenter = pImp->m_idCenter;
AecEqui::XPrimData* pSolid = NULL;
AecEqui::XPrimData* pSolid2 = NULL;
@@ -2646,7 +2681,7 @@ Acad::ErrorStatus AecDbEwEquipment::DrawHandFlg(AcGiDraw &dc) const
CString sFlag(_T(""));
if (nVt == 1) sFlag = _T("M");
else if (nVt == 2) sFlag = _T("G");
else sFlag == _T("Y");
else sFlag = _T("Y"); //液动;原来写成 ==,sFlag 一直是空串
AecInterface inf1, inf2;
GetInterface(0, inf1);
@@ -4220,14 +4255,21 @@ int AecDbEwEquipment::GetBodyBox(AcDbExtents& ext) const
Draw3d(dc);
}
AcDbExtents _ext;
//原来恒返回 TRUE,调用方无法区分"没取到几何"。
//_ext 也改为每轮新建,避免把上一轮的累积结果重复并入
BOOL bRet(FALSE);
for (size_t i = 0; i < ar3D.length(); i++)
{
AcDbEntity *p = (AcDbEntity*)ar3D[(int)i];
p->getGeomExtents(_ext);
if (p == NULL) continue;
AcDbExtents _ext;
if (p->getGeomExtents(_ext) != Acad::eOk) continue;
ext.addExt(_ext);
bRet = TRUE;
}
return TRUE;
return bRet;
}
AecDbObjXDataMap* AecDbEwEquipment::GetSpecialtyData(AcDb::OpenMode bMode)
@@ -12540,15 +12582,26 @@ void AecDbEwEquipment::setSectionID(const ESection &es, AcDbObjectId & id)
//取中心位置为做块的插入位置
DLLIMPEXP bool MakeBlockRefSet(AcDbVoidPtrArray& arEntPtrs,const AcDbObjectId& idLay,Adesk::Boolean bDoSubent,LPCTSTR pszName,AcDbDatabase* pDb = NULL)
{
AcDbExtents ext, extAdd;
AcDbExtents ext;
AcDbEntity *pEnt = NULL;
CString s;
for (int i = 0;i < arEntPtrs.length();i++)
{
pEnt = (AcDbEntity*)arEntPtrs.at(i);
if (!AcDbBlockReference::cast(pEnt))
pEnt->getGeomExtents(extAdd);
if (isValidExtents(ext))
if (pEnt == NULL) continue;
//块参照本身没有几何。原来不跳过,extAdd 会保留上一轮的值被重复累加
if (AcDbBlockReference::cast(pEnt))
continue;
//每轮重新取,避免 getGeomExtents 失败时沿用上一轮的范围
AcDbExtents extAdd;
if (pEnt->getGeomExtents(extAdd) != Acad::eOk)
continue;
//原来判断的是累加器 ext:第一轮它还是空状态,
//第一个实体的范围永远加不进去
if (isValidExtents(extAdd))
ext.addExt(extAdd);
}
@@ -12803,7 +12856,8 @@ int AecDbEwEquipment::GetSectionDraw(const AcGePoint3d& ptFr,const AcGePoint3d&
GetSectionDraw(plan,vtTo,arRegionPtrs);
int nCoundPre = arRegionPtrs.length();
return (nCount - nCoundPre);
//返回本次新增的个数。原来写成 nCount - nCoundPre(调用前减调用后),恒为 0 或负数
return (nCoundPre - nCount);
}
bool AecDbEwEquipment::GetPositionGrip(int nIndex, AecGripData *&pGrip) const
@@ -12915,6 +12969,11 @@ bool AecDbEwEquipment::ByJson(const SHJson::WValue &v)
void AecDbEwEquipment::clearGeoBuffer()
{
AssertWriteEnabled();
//调用方(改参数、改颜色之后)期望清掉缓存强制重建,
//原来函数体是空的,改完参数旧几何还在
Clean2DBuffer();
Clean3DBuffer();
}
void AecDbEwEquipment::TransformEntity(AcDbEntity *p
@@ -13179,13 +13238,14 @@ void AecDbEwEquipment::ProcessHlrResult(const AcArray<AcDbEntity *> &ar
_ar.removeAll();
// 把 preAr 中的 region 生成的结果挑出来,不显示
// 原来 erase(it) 之后仍然 ++it,迭代器已失效
std::map<AcDbEntity *, AcArray<AcDbEntity *>>::iterator it(_preAr.begin());
for (; it != _preAr.end(); ++it)
while (it != _preAr.end())
{
if (AcDbRegion::cast(it->first))
{
_preAr.erase(it);
}
_preAr.erase(it++); //先取下一个迭代器再删当前
else
++it;
}
}