diff --git a/AcDbX3dSolid-refactor-plan.md b/AcDbX3dSolid-refactor-plan.md index 892437f..5abecac 100644 --- a/AcDbX3dSolid-refactor-plan.md +++ b/AcDbX3dSolid-refactor-plan.md @@ -4,7 +4,7 @@ > > 范围:`SourceCode/Code2026/CoreLibrary/AcDbX3dSolid.cpp`(5596 行)、`inc/AcDbX3dSolid.h`、`CoreCommand/CoreTools.cpp`。 > -> 原则:**老图纸必须能读**;写入统一新格式;不改对象模型(`AcDbX3dSolid` 仍是可平凡复制的数据类)。 +> 原则:**单向兼容——新版必须能读老图纸,老版不保证能显示新图的 region 类型几何**(见 11.1);写入统一新格式;不改对象模型(`AcDbX3dSolid` 仍是可平凡复制的数据类)。 --- @@ -65,7 +65,7 @@ AcDbRegion* ──RegionToString()──► %TEMP%\Region1.sat ──读文件 `m_pSatBuffer` 的读写通道**已经打通并持久化**: ```cpp -// dwgOutFields :4808-4814 +// dwgOutFields :4822-4829 if (AcDbX3dSolid::kCurrentVersionNumber > 1) { pFiler->writeUInt32(m_nSatLen); if (m_pSatBuffer != NULL) @@ -107,20 +107,28 @@ struct RegionBlobHeader { ### 3.3 编解码 ```cpp -// AcDbX3dSolid.cpp 内部 static -static bool PackRegions(const AcArray& regs, void*& pBuf, Adesk::UInt32& nLen); -static bool UnpackRegions(const void* pBuf, Adesk::UInt32 nLen, AcArray& regs); - -// 单 region 的 SAT 字节(CoreTools 新增,与 RegionToString 共用临时文件逻辑) -bool CoreTools::RegionToBuffer(const AcDbRegion* pReg, void*& pBuf, Adesk::UInt32& nLen); +// AcDbX3dSolid.cpp 匿名 namespace +bool PackRegions(const AcArray& regs, void*& pBuf, Adesk::UInt32& nLen); +bool UnpackRegions(const void* pBuf, Adesk::UInt32 nLen, AcArray& regs); ``` -`UnpackRegions` 内部用**已存在**的 `CoreTools::StringToRegion(Adesk::UInt64 nLen, char* pszReg)`(`CoreTools.cpp:3525`),读端无需新代码。 +单 region 的 SAT 字节**不需要新函数**,直接复用已有的两个重载: + +```cpp +// 输出 SAT 的 ASCII 字节,返回长度,pszTxt 由调用方 delete[] +Adesk::UInt64 CoreTools::RegionToString(const AcDbRegion* pReg, char*& pszTxt); // CoreTools.cpp:3114 +// 从字节重建 region +AcDbRegion* CoreTools::StringToRegion(Adesk::UInt64 nLen, char* pszReg); // CoreTools.cpp:3581 +``` + +`RegionToString(char*&)` 内部已经用 `MakeTempSatPath()` + `DeleteFile`,`StringToRegion` 内部已经过 `fixACISFormat`,阶段一、二落地后这两条链路都是现成的。`PackRegions` 负责把拿到的字节拷进容器并 `delete[]`。 --- ## 4. 改动清单 +> 阶段一、二已合并;阶段三暂缓,取舍与前提见第 11 节。以下保留完整方案,供重启时参考。 + ### 阶段一:临时文件唯一化(纯 bug 修复) **位置**:`CoreCommand/CoreTools.cpp` @@ -178,40 +186,42 @@ void EnsureCreated() { if (m_bNeedCreate) { m_bNeedCreate = false; ReCreate(); } #### 4.3.1 写入点(`RegionToString` → `PackRegions`) -| 行 | 类型 | 现状 | +行号为当前 main(阶段一、二落地后),实施时以函数名定位。 + +| 行 | 类型 / 函数 | 现状 | | --- | --- | --- | -| `:1364` | `kExtrude2` | `RegionToString(pReg, m_sScr)` | -| `:1429-1432` | `kConePipe` | 外/内两个 → `sScr1`/`sScr2` → 拼 `m_sScr` | -| `:2034` | `kSlicePipe` | `RegionToString(pRegion, m_sScr)` | -| `:2120` | `kIntersect` | → `sScr1` → `m_sScr` | -| `:2174` | `kSliceSolid` | → `sSrc1` → `m_sScr` | -| `:2204` | `kRevolve` | → `m_sScr` | -| `:2235` | `kRevolve2` | → `m_sScr` | -| `:5020` | `kLoft` | `strAll`(`@region@` 拼接)→ `m_sScr` | -| `:5073`、`:5087` | `kSweep` | → `m_sScr` | -| `:4868`、`:4881` | `SetSolidData` | `m_sScr = srcRegion` | -| `:5121`、`:5141`、`:5162`、`:5192` | `SetExturd2Data` / `SetRevolve2Data` / `SetSweepData` / `SetLoftData`(`:5192` 所属函数实施时核对) | `m_sScr = sReg` | +| `:1371` | `kExtrude2` | `RegionToString(pReg, m_sScr)` | +| `:1436`、`:1439` | `kConePipe` | 外/内 → `sScr1`/`sScr2` → 拼 `m_sScr` | +| `:2041` | `kSlicePipe` | → `m_sScr` | +| `:2127` | `kIntersect` | → `sScr1` → `m_sScr` | +| `:2181` | `kSliceSolid` | → `sSrc1` → `m_sScr` | +| `:2211` | `kRevolve` | → `m_sScr` | +| `:2242` | `kRevolve2` | → `m_sScr` | +| `:5029` | `kLoft` | `strAll`(`@region@` 拼接)→ `m_sScr` | +| `:5087`、`:5101` | `kSweep` | → `m_sScr` | +| `:4882`、`:4895` | `SetSolidData` | `m_sScr = srcRegion` | +| `:5135`、`:5155`、`:5176`、`:5206` | `SetExturd2Data` / `SetRevolve2Data` / `SetSweepData` / `SetLoftData` | `m_sScr = sReg` | +| `:5516`、`:5528`、`:5542`、`:5562`、`:5589` | `TransformBy` | 变换后重新导出 | #### 4.3.2 读取点(`StringToRegion(m_sScr)` → `UnpackRegions`) -| 行 | 类型 | +| 行 | 类型 / 函数 | | --- | --- | -| `:4364` | `kSlicePipe` | -| `:4376` | `kExtrude2` | -| `:4400` | `kIntersect` | -| `:4438` | `kSliceSolid` | -| `:4466` | `kRevolve` | -| `:4486-4487` | `kConePipe` | -| `:4561` | `kRevolve2` | -| `:4585` | `kLoft` | -| `:4599` | `kSweep` | -| `:5307`、`:5331`、`:5356`、`:5439` | `ToJson` | -| `:5500`、`:5512`、`:5526`、`:5542`、`:5571` | `TransformBy` | -| `:5111`、`:5129`、`:5154` | `GetExturd2Data` / `GetRevolve2Data` / `GetSweepData` | +| `:4366` | `kSlicePipe` | +| `:4378` | `kExtrude2` | +| `:4402` | `kIntersect` | +| `:4440` | `kSliceSolid` | +| `:4468` | `kRevolve` | +| `:4488`、`:4489` | `kConePipe` | +| `:4563` | `kRevolve2` | +| `:4587` | `kLoft`(循环) | +| `:4601` | `kSweep` | +| `:5321`、`:5345`、`:5370`、`:5453` | `ToJson` | +| `:5512`、`:5524`、`:5538`、`:5558`、`:5584` | `TransformBy` | #### 4.3.3 序列化 -**不改**。`m_pSatBuffer` 的 `writeUInt32` + `writeBytes` 已经在 `:4808-4814`,`dwgInFields` 有对称读。 +**不改**。`m_pSatBuffer` 的 `writeUInt32` + `writeBytes` 已经在 `:4822-4829`,`dwgInFields` 有对称读。 只改一件事:region 类型写入时**不再写 `m_sScr`**(保持空字符串),管廊脚本类型不受影响。 @@ -235,7 +245,7 @@ else if (!m_sScr.IsEmpty()) 写入:只写新格式。 -**不升 `kCurrentVersionNumber`**。理由:字段都在,靠"哪个非空"即可判别;升版本会让老版本 CAD 读新图时走 `eMakeMeProxy`。 +**不升 `kCurrentVersionNumber`**。理由:字段都在,靠"哪个非空"即可判别;升版本会让老版本 CAD 读新图时走 `eMakeMeProxy`,新图在所有老版本上彻底不可编辑。代价是老版本看不到 region 类型的几何,这是已定的取舍,见 11.1。 #### 4.3.5 `kLoftReducer` 纳入统一容器 @@ -354,3 +364,42 @@ void SetSweepData(const CString& sReg, const AcDbCurve* pCurve); | 1 | `kLoftReducer`(22) 是否纳入统一容器 | **纳入**(4.3.5),老数据回退 `0x00c1` 切分 | | 2 | `kSHEarthWorm`(23) 是否仍在使用 | **已废弃**,但 `m_sScr` 字段本次保留不删,仅停止写入(4.3.6) | | 3 | 公开 `CString` 接口 | **签名不变**,内部转换,外部调用方零改动(第 5 节) | + +--- + +## 11. 阶段三暂缓(2026-10-22) + +**决定:暂不实施。** 阶段一(临时文件唯一化、越界读)、阶段二(懒重建)已合并,主要痛点已经解决;阶段三剩下的收益只有「region 部分 DWG 体积减半」,代价是新图在老版本插件里 region 几何不可见。当前时机未到。 + +### 11.1 兼容方向(已定) + +**单向兼容**:新版插件完整读取旧版图纸(`m_sScr` 老路径永久保留);旧版插件打开新图时,region 类型的 `AcDbX3dSolid` 几何不可见。 + +不可见不等于丢数据:`m_pSatBuffer` 老版本也会原样读写(版本 > 1 的通道一直都在),所以旧版打开后另存、再回新版打开,几何仍能恢复。非 region 类型(`m_sszPoint2ds` 点串、SubDMesh、管廊脚本)不受影响。 + +| 选项 | 后果 | 结论 | +| --- | --- | --- | +| 不升版本号,接受老插件缺几何 | 老插件能开图、参数都在,region 类型几何不显示;换新版可恢复 | **已定,选这个** | +| 升到 5,老插件显式 proxy | 不会静默缺几何,但新图在所有老版本上彻底不可编辑,且不可回退 | 不选 | +| 保留双写(`m_sScr` 仍写老格式) | 体积变成 2N + N,比现状更差 | 否决 | + +### 11.2 重启前还要定的事 + +1. `TransformBy`、`ToJson` 是否一起改——这两处在运行时会反复导出/解析 SAT,是阶段三改动量的大头 +2. 老图纸里 region 类型的实际占比——占比低的话体积收益有限,可以永久搁置 + +### 11.3 实施时的技术前提(已核对) + +- `kCurrentVersionNumber` 当前是 **4**。`m_pSatBuffer` 的读写通道在 `dwgOutFields:4822` / `dwgInFields:4754`,版本 > 1 即生效,阶段三不需要动序列化 +- **不需要**新增 `CoreTools::RegionToBuffer`:`RegionToString(const AcDbRegion*, char*&)`(`CoreTools.cpp:3114`)已经输出 SAT 的 ASCII 字节和长度,内部用 `MakeTempSatPath` + `DeleteFile` +- 读端 `StringToRegion(Adesk::UInt64, char*)`(`CoreTools.cpp:3581`)已经过 `fixACISFormat` +- `m_pSatBuffer` 当前有 4 种语义:`kFenceExtrude` 点数组(`:1514`)、`kFrom3JS` SubDMesh(`:1019`/`:1048`)、`kLoftReducer` 宽字符串(`:3132`/`:5405`)、SAT 导入原始字节(`:2872`)。容器头的 magic 是必需的 +- 拷贝构造对 `m_pSatBuffer` 做了深拷贝(`:274-280`),`Clone()` 不会共享指针 + +### 11.4 当前状态 + +| 阶段 | 状态 | PR | +| --- | --- | --- | +| 一:临时文件唯一化 | 已合并 | #22、#26 | +| 二:懒重建 | 已合并 | #25、#27 | +| 三:region 二进制化 | 暂缓 | — |