revert: 删除 modeler filer 存 3D 缓存的全部代码(实测该 API 写读不能配对)
结论(用户实测):acdbModelerSaveEntityToDwgFiler 写出的数据, 用 acdbModelerRestoreEntityFromDwgFiler 读回来 CAD 直接报错、实体丢失。 这两个函数不是一对可逆读写,不能用来把绘制缓存塞进 DWG 再取回来。 本仓库自己的现象与之一致: - 单条静态数据时"读回 len=1 / setASMBody 成功 / 包围盒正确"只是巧合; - 一旦多条混排或与别的字段交错,读端就错位,表现为 "打开图形文件发现一个错误" + 实体变 ZOMBIEENTITY(造型.dwg 的 2D5 就是); - 之前加的读端防护(magic/count/尾标记/失败回退)只能保证不把文件写得更坏, 改变不了"写进去的字节读不回同一个几何"这个根本问题。 删除范围(对应之前几个 PR): - AecDbEntityCommon: Write3DBufferBlock / Read3DBufferBlock(#125) - AecDbEwFitting: 上述两个函数的调用点(#125) - AecDbX3dPartEntity: WriteX3dGeomBlock / ReadX3dGeomBlock 及调用点(#118) - AecDbX3dPart.h/.cpp: GetDwgCacheSolid / SetDwgCacheSolid(#118) - AecDbMultiPartEntity: 3D 缓存块,版本号回到 3(#131/#132) - cmakelists.txt: AEC_HAS_MODELER_FILER 能力宏 共 -612 行。 保留:AEC_PERF_COUNTER 计时(EwPipeBase::Draw3d / X3dPart::Rebuild / MultiPartEntity::Draw3d)。它们只回答"开图期画了多少、花了多久",与存盘格式无关, 以后评估"隐藏块里放真实 3DSOLID"或 SAT 通道时还用得上。 结论与后续方向写进 3d-cache-dwg-verdict.md §10。 验证:R230 Debug 编译通过(CoreCommand_BAL_REMOTE,零 error)。
This commit is contained in:
1 parent
bec6cb996d
commit
4523690cc5
8 files changed
+7
-608
No files matched your search
@@ -12,10 +12,6 @@
|
||||
#include "AcGiExplodeDraw.h"
|
||||
#include "AecDbSlab.h"
|
||||
#include "AecDbXDrawPointer.h"
|
||||
#include "SectionPerfCounter.h"
|
||||
#ifdef AEC_HAS_MODELER_FILER
|
||||
#include "dbacis.h"
|
||||
#endif
|
||||
|
||||
extern CString IDCreate();
|
||||
extern double PixelToWcs(int nPixel);
|
||||
@@ -49,183 +45,6 @@ static const Adesk::UInt16 kColorByLayer = 256;
|
||||
|
||||
Adesk::UInt32 AecDbX3dPartEntity::kCurrentVersionNumber = 2;
|
||||
|
||||
// ===========================================================================
|
||||
// 3D 几何缓存随存盘(modeler filer 通道)
|
||||
//
|
||||
// 为什么挂在 AecDbX3dPartEntity 这一层:
|
||||
// - 3D 几何(AecDbX3dPart::m_pSolid)是布尔运算的结果,重建一次 15 ms 量级;
|
||||
// 而把它当 ASM body 存取只要不到 1 ms(实测见 3d-cache-dwg-verdict.md §7)。
|
||||
// - AecDbX3dPart 是嵌在实体流**中间**的子流(它后面还有 m_drawable2d),
|
||||
// 往里加块会让老版本插件把块的字节当成它后面的字段读(管道那次就这样把 XWall 读崩了)。
|
||||
// 而 AecDbX3dPartEntity 的 dwgOutFields 末尾就是本实体流的结尾,老版本读到自己
|
||||
// 需要的字段就停,尾部多出来的字节会被忽略(AutoCAD 流按对象定长)。
|
||||
// - 不升 kCurrentVersionNumber:老版本读新图 = 读不到块 = 照旧重建。
|
||||
//
|
||||
// 语义:
|
||||
// - 存:part 的几何有效(没被置脏、且建过)才写;没有就写 count=0,等于没存;
|
||||
// - 读:读不到 magic(老图/开关关掉)或任何一步失败 → 静默回退重建。
|
||||
// ===========================================================================
|
||||
namespace
|
||||
{
|
||||
#ifdef AEC_HAS_MODELER_FILER
|
||||
|
||||
// 开关:AEC_3D_DWG_CACHE=0 时既不再写块、也不读块(A/B 对照用)
|
||||
bool IsX3dDwgCacheEnabled()
|
||||
{
|
||||
static int s_nOn = -1;
|
||||
if (s_nOn < 0)
|
||||
{
|
||||
const char* psz = ::getenv("AEC_3D_DWG_CACHE");
|
||||
s_nOn = (psz != NULL && psz[0] != '0') ? 1 : 0; // default off until the win is proven
|
||||
}
|
||||
return s_nOn == 1;
|
||||
}
|
||||
|
||||
// 试点跟踪(AEC_3D_CACHE_TRACE=1):确认存盘/开图时这个块的调用情况
|
||||
void Trace3DCache(const char* pszFmt, ...)
|
||||
{
|
||||
static int s_nOn = -1;
|
||||
if (s_nOn < 0)
|
||||
{
|
||||
const char* psz = ::getenv("AEC_3D_CACHE_TRACE");
|
||||
s_nOn = (psz != NULL && psz[0] != '0') ? 1 : 0;
|
||||
}
|
||||
if (s_nOn != 1) return;
|
||||
|
||||
TCHAR szTmp[MAX_PATH + 1];
|
||||
::memset(szTmp, 0, sizeof(szTmp));
|
||||
if (::GetTempPath(MAX_PATH, szTmp) == 0) return;
|
||||
TCHAR szFile[MAX_PATH + 1];
|
||||
::_stprintf_s(szFile, MAX_PATH, _T("%saec_x3d_cache.log"), szTmp);
|
||||
FILE* fp = NULL;
|
||||
if (_tfopen_s(&fp, szFile, _T("a")) != 0 || fp == NULL) return;
|
||||
va_list args;
|
||||
va_start(args, pszFmt);
|
||||
vfprintf(fp, pszFmt, args);
|
||||
va_end(args);
|
||||
fputc(10, fp);
|
||||
fclose(fp);
|
||||
}
|
||||
const Adesk::UInt32 kX3dMagic = 0x50443341; // 'A3DP'
|
||||
const Adesk::UInt32 kX3dMagicEnd = 0x50443341 ^ 0xFFFFFFFF;
|
||||
const Adesk::UInt16 kX3dBlkVer = 1;
|
||||
|
||||
// 内存 filer(clone / copyFrom / 剪贴板)不参与:它的读取语义与 DWG 流不同,
|
||||
// 写进去也只会让拷贝出来的实体带着一份用不上的缓存
|
||||
bool IsMemoryFiler(AcDbDwgFiler* pFiler)
|
||||
{
|
||||
return (pFiler != NULL) && pFiler->isKindOf(CMFCDbDwgFiler::desc());
|
||||
}
|
||||
|
||||
void WriteX3dGeomBlock(AcDbDwgFiler* pFiler, const AecDbX3dPart* pPart)
|
||||
{
|
||||
if (pFiler == NULL || pPart == NULL)
|
||||
return;
|
||||
if (IsMemoryFiler(pFiler) || !IsX3dDwgCacheEnabled())
|
||||
return;
|
||||
|
||||
AcDb3dSolid* pSolid = pPart->GetDwgCacheSolid();
|
||||
const bool bHasSolid = (pSolid != NULL);
|
||||
Trace3DCache("write hasSolid=%d", bHasSolid ? 1 : 0);
|
||||
|
||||
// 没有几何也写头(count=0):读端才知道"这次真的没缓存",而不是老数据
|
||||
pFiler->writeUInt32(kX3dMagic);
|
||||
pFiler->writeUInt16(kX3dBlkVer);
|
||||
pFiler->writeUInt16(0); // flags 预留
|
||||
pFiler->writeUInt32(bHasSolid ? 1 : 0);
|
||||
|
||||
if (!bHasSolid)
|
||||
{
|
||||
pFiler->writeUInt32(kX3dMagicEnd);
|
||||
return;
|
||||
}
|
||||
|
||||
SectionPerf::Scope perfScope("X3dGeom.write");
|
||||
|
||||
ENTITY* pAsm = (ENTITY*)pSolid->getLockedASMBody();
|
||||
if (pAsm == NULL)
|
||||
{
|
||||
// 拿不到 body:块已经写了一半,补 0 让读端当"没有缓存"
|
||||
pFiler->writeUInt32(0);
|
||||
return;
|
||||
}
|
||||
|
||||
AcDbDatabase* pDb = pSolid->database();
|
||||
if (pDb == NULL)
|
||||
pDb = acdbHostApplicationServices()->workingDatabase();
|
||||
|
||||
// modelerVersion = -1:跟随 filer 的 DWG 版本,不硬编码
|
||||
Acad::ErrorStatus es = acdbModelerSaveEntityToDwgFiler(pFiler, pAsm, pDb, -1);
|
||||
pSolid->unlockASMBody();
|
||||
|
||||
if (es != Acad::eOk)
|
||||
{
|
||||
pFiler->writeUInt32(0); // 同上:让读端回退
|
||||
return;
|
||||
}
|
||||
|
||||
pFiler->writeUInt32(kX3dMagicEnd);
|
||||
}
|
||||
|
||||
// 返回 true = 成功用块里的几何接管了 part
|
||||
bool ReadX3dGeomBlock(AcDbDwgFiler* pFiler, AecDbX3dPart* pPart)
|
||||
{
|
||||
if (pFiler == NULL || pPart == NULL)
|
||||
return false;
|
||||
if (IsMemoryFiler(pFiler))
|
||||
return false;
|
||||
|
||||
// 老图 / 写端关掉:读到的不是 magic,直接回退(不刷日志)
|
||||
Adesk::UInt32 nMagic = 0;
|
||||
if (pFiler->readUInt32(&nMagic) != Acad::eOk || nMagic != kX3dMagic)
|
||||
{
|
||||
SectionPerf::Scope missScope("X3dGeom.miss");
|
||||
Trace3DCache("read nomagic");
|
||||
return false;
|
||||
}
|
||||
|
||||
Adesk::UInt16 nBlkVer = 0;
|
||||
Adesk::UInt16 nFlags = 0;
|
||||
Adesk::UInt32 nCount = 0;
|
||||
if (pFiler->readUInt16(&nBlkVer) != Acad::eOk || nBlkVer != kX3dBlkVer)
|
||||
return false;
|
||||
if (pFiler->readUInt16(&nFlags) != Acad::eOk)
|
||||
return false;
|
||||
if (pFiler->readUInt32(&nCount) != Acad::eOk)
|
||||
return false;
|
||||
|
||||
Trace3DCache("read magic=ok count=%u", (unsigned)nCount);
|
||||
if (nCount == 0 || nCount > 4)
|
||||
return false; // 没缓存 / 数据不可信
|
||||
|
||||
ENTITY* pAsm = NULL;
|
||||
int nModelerVer = -1;
|
||||
if (acdbModelerRestoreEntityFromDwgFiler(pFiler, pAsm, &nModelerVer, kReadStrangerEntityDefault) != Acad::eOk)
|
||||
return false;
|
||||
|
||||
Adesk::UInt32 nEnd = 0;
|
||||
if (pFiler->readUInt32(&nEnd) != Acad::eOk || nEnd != kX3dMagicEnd)
|
||||
return false; // 半成品块:回退重建
|
||||
|
||||
if (pAsm == NULL)
|
||||
return false;
|
||||
|
||||
AcDb3dSolid* pSolid = new AcDb3dSolid();
|
||||
if (pSolid->setASMBody(pAsm) != Acad::eOk)
|
||||
{
|
||||
delete pSolid;
|
||||
return false;
|
||||
}
|
||||
|
||||
pPart->SetDwgCacheSolid(pSolid);
|
||||
|
||||
SectionPerf::Scope hitScope("X3dGeom.read.ok");
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif // AEC_HAS_MODELER_FILER
|
||||
}
|
||||
|
||||
ACRX_DXF_DEFINE_MEMBERS (AecDbX3dPartEntity, AecDbEntityBase,
|
||||
AcDb::kDHL_CURRENT, AcDb::kMReleaseCurrent,
|
||||
AcDbProxyEntity::kNoOperation | AcDbProxyEntity::kDisableProxyWarning,
|
||||
@@ -2005,17 +1824,8 @@ Acad::ErrorStatus AecDbX3dPartEntity::dwgInFields (AcDbDwgFiler* pFiler)
|
||||
//开图时不建布尔结果:dwgInFields 里已置脏,首次绘制或取几何时由 EnsureCreated 重建
|
||||
|
||||
m_drawable2d.dwgInFields(pFiler, version);
|
||||
if (pFiler->filerStatus() != Acad::eOk)
|
||||
return (pFiler->filerStatus ());
|
||||
|
||||
#ifdef AEC_HAS_MODELER_FILER
|
||||
// 末尾探测 3D 几何块;读不到就是老图(或开关关掉),part 保持"待重建"
|
||||
ReadX3dGeomBlock(pFiler, m_pPart);
|
||||
#endif
|
||||
|
||||
// 注意:不能用 return pFiler->filerStatus()。探测块时 readUInt32 在老图上会
|
||||
// 把状态置成 eEndOfFile,那样整个实体都会被判成读取失败。
|
||||
return Acad::eOk;
|
||||
return (pFiler->filerStatus ());
|
||||
}
|
||||
|
||||
Acad::ErrorStatus AecDbX3dPartEntity::dwgOutFields(AcDbDwgFiler* pFiler) const
|
||||
@@ -2038,11 +1848,6 @@ Acad::ErrorStatus AecDbX3dPartEntity::dwgOutFields(AcDbDwgFiler* pFiler) const
|
||||
m_pPart->dwgOutFields(pFiler);
|
||||
m_drawable2d.dwgOutFields(pFiler, AecDbX3dPartEntity::kCurrentVersionNumber);
|
||||
|
||||
#ifdef AEC_HAS_MODELER_FILER
|
||||
// 3D 几何块:只能在**本实体流末尾**追加(见文件顶部那段说明)
|
||||
WriteX3dGeomBlock(pFiler, m_pPart);
|
||||
#endif
|
||||
|
||||
return (pFiler->filerStatus ());
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user