docs: 阶段三取消,记录理由并补开图速度方向
决定不做 region 二进制化,两条理由: 1. 主要收益只是图纸体积,而当前图纸大小在可接受范围内 2. 改动会改变存储格式,新图在老插件上读不出 region 几何,要么升版本号 变 proxy,要么额外做降级导出兜底,性价比不足 文档调整: - 开头原则改为状态说明,明确格式保持现状、新老插件双向可读 - 第 3、4、12 节标注为存档;第 9、10 节同步阶段三取消 - 第 11 节由「暂缓」改为「取消」,11.1 改为取消后的兼容状态, 11.2 保留重启前提与改动范围核对结果 - 新增第 13 节:开图速度方向。瓶颈是 X3dPartEntity::dwgInFields:1824 无条件调用 Create(),成本约 N×(acisIn+clone) + (N−1)×布尔; 列出懒执行与缓存布尔结果两个候选
This commit is contained in:
1 parent
a792194aa9
commit
2c374b92e5
1 file changed
+50
-28
@@ -4,7 +4,7 @@
|
||||
>
|
||||
> 范围:`SourceCode/Code2026/CoreLibrary/AcDbX3dSolid.cpp`(5596 行)、`inc/AcDbX3dSolid.h`、`CoreCommand/CoreTools.cpp`。
|
||||
>
|
||||
> 原则:**单向兼容——新版必须能读老图纸,老版不保证能显示新图的 region 类型几何**(见 11.1);写入统一新格式;不改对象模型(`AcDbX3dSolid` 仍是可平凡复制的数据类)。
|
||||
> 状态(2026-10-22):阶段一、二已合并;**阶段三(region 二进制化)决定不做**,存储格式保持现状,新老插件双向可读。理由见第 11 节,后续方向见第 13 节。
|
||||
|
||||
---
|
||||
|
||||
@@ -60,6 +60,8 @@ AcDbRegion* ──RegionToString()──► %TEMP%\Region1.sat ──读文件
|
||||
|
||||
## 3. 目标存储格式
|
||||
|
||||
> 阶段三已取消(第 11 节),以下为存档方案。
|
||||
|
||||
### 3.1 为什么可以复用 `m_pSatBuffer`
|
||||
|
||||
`m_pSatBuffer` 的读写通道**已经打通并持久化**:
|
||||
@@ -144,7 +146,7 @@ AcDbRegion* CoreTools::StringToRegion(Adesk::UInt64 nLen, char* pszReg);
|
||||
|
||||
## 4. 改动清单
|
||||
|
||||
> 阶段一、二已合并;阶段三暂缓,取舍与前提见第 11 节。以下保留完整方案,供重启时参考。
|
||||
> 阶段一、二已合并;阶段三已取消(第 11 节),以下保留完整方案作存档。
|
||||
|
||||
### 阶段一:临时文件唯一化(纯 bug 修复)
|
||||
|
||||
@@ -262,7 +264,7 @@ else if (!m_sScr.IsEmpty())
|
||||
|
||||
写入:只写新格式。
|
||||
|
||||
**不升 `kCurrentVersionNumber`**。理由:字段都在,靠"哪个非空"即可判别;升版本会让老版本 CAD 读新图时走 `eMakeMeProxy`,新图在所有老版本上彻底不可编辑。代价是老版本看不到 region 类型的几何,这是已定的取舍,见 11.1。
|
||||
**不升 `kCurrentVersionNumber`**。理由:字段都在,靠"哪个非空"即可判别;升版本会让老版本 CAD 读新图时走 `eMakeMeProxy`。代价是老版本看不到 region 类型的几何——这一条正是阶段三取消的原因之一,见第 11 节。
|
||||
|
||||
#### 4.3.5 `kLoftReducer` 纳入统一容器
|
||||
|
||||
@@ -367,8 +369,8 @@ void SetSweepData(const CString& sReg, const AcDbCurve* pCurve);
|
||||
| 顺序 | 阶段 | 改动量 | 风险 | 收益 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| 1 | 一:临时文件唯一化 | 小 | 低 | 消除并发错乱、越界读 |
|
||||
| 2 | 二:懒重建 | 中 | 中 | 开图性能(最大) |
|
||||
| 3 | 三:region 二进制化 | 大 | 中高 | DWG 体积减半、去编码转换 |
|
||||
| 2 | 二:懒重建 | 中 | 中 | 开图性能(实际最大瓶颈在 `X3dPart::Create`,见 13) |
|
||||
| 3 | 三:region 二进制化 | 大 | 中高 | DWG 体积减半、去编码转换(**已取消**) |
|
||||
|
||||
每个阶段独立提交、独立 PR,前一阶段验证通过后再进下一阶段。
|
||||
|
||||
@@ -378,40 +380,41 @@ void SetSweepData(const CString& sReg, const AcDbCurve* pCurve);
|
||||
|
||||
| # | 事项 | 结论 |
|
||||
| --- | --- | --- |
|
||||
| 1 | `kLoftReducer`(22) 是否纳入统一容器 | **纳入**(4.3.5),老数据回退 `0x00c1` 切分 |
|
||||
| 1 | `kLoftReducer`(22) 是否纳入统一容器 | 原定**纳入**(4.3.5),随阶段三取消 |
|
||||
| 2 | `kSHEarthWorm`(23) 是否仍在使用 | **已废弃**,但 `m_sScr` 字段本次保留不删,仅停止写入(4.3.6) |
|
||||
| 3 | 公开 `CString` 接口 | **签名不变**,内部转换,外部调用方零改动(第 5 节) |
|
||||
|
||||
---
|
||||
|
||||
## 11. 阶段三暂缓(2026-10-22)
|
||||
## 11. 阶段三取消(2026-10-22)
|
||||
|
||||
**决定:暂不实施。** 阶段一(临时文件唯一化、越界读)、阶段二(懒重建)已合并,主要痛点已经解决;阶段三剩下的收益只有「region 部分 DWG 体积减半」,代价是新图在老版本插件里 region 几何不可见。当前时机未到。
|
||||
**决定:不实施。** 两条理由:
|
||||
|
||||
### 11.1 兼容方向(已定)
|
||||
1. 阶段三的主要收益是图纸体积(region 部分约减半),而当前图纸大小在可接受范围内,这个收益不值一次格式变更
|
||||
2. 改动会改变存储格式:新图里的 region 类型在老插件上读不出几何,要么升 `kCurrentVersionNumber` 变成 proxy,要么额外做降级导出兜底,两头都要付代价,性价比不足
|
||||
|
||||
**单向兼容**:新版插件完整读取旧版图纸(`m_sScr` 老路径永久保留);旧版插件打开新图时,region 类型的 `AcDbX3dSolid` 几何不可见。
|
||||
阶段一、二已经解决了并发临时文件错乱、越界读、开图时的重复重建,剩下的痛点不足以支撑一次格式变更。开图速度的问题另有更直接的着手点,见第 13 节。
|
||||
|
||||
不可见不等于丢数据:`m_pSatBuffer` 老版本也会原样读写(版本 > 1 的通道一直都在),所以旧版打开后另存、再回新版打开,几何仍能恢复。非 region 类型(`m_sszPoint2ds` 点串、SubDMesh、管廊脚本)不受影响。
|
||||
### 11.1 取消后的兼容状态
|
||||
|
||||
需要把图交给老版本用户时,用第 12 节的降级导出:存盘瞬间把容器翻成老格式的 `m_sScr`,老插件就能正常显示几何,当前文档本身不受影响。
|
||||
存储格式保持现状:`m_sScr` 继续写 UTF-16 的 SAT 文本,`m_pSatBuffer` 的语义也不变。新老插件双向可读,不存在单向兼容问题,也不需要第 12 节的降级导出。
|
||||
|
||||
| 选项 | 后果 | 结论 |
|
||||
| --- | --- | --- |
|
||||
| 不升版本号,接受老插件缺几何 | 老插件能开图、参数都在,region 类型几何不显示;换新版可恢复 | **已定,选这个** |
|
||||
| 升到 5,老插件显式 proxy | 不会静默缺几何,但新图在所有老版本上彻底不可编辑,且不可回退 | 不选 |
|
||||
| 保留双写(`m_sScr` 仍写老格式) | 体积变成 2N + N,比现状更差 | 否决 |
|
||||
> 存档:当初评估过三个兼容选项——不升版本(老插件缺几何,换新版可恢复)、升到 5(老插件显式 proxy)、双写(体积更差)——都随阶段三取消而不适用。
|
||||
|
||||
### 11.2 重启前还要定的事
|
||||
### 11.2 重启的前提
|
||||
|
||||
1. **已定:`TransformBy`、`ToJson` 必须一起改**(2026-10-22)。这两处都是 `m_sScr` 的读者,容器化后不改不是「导出数据不对」,而是功能直接坏:
|
||||
- `TransformBy`(`:5488`)5 个类型都靠 `StringToRegion(m_sScr)` 取截面,取不到就 `bChanged = false`,末尾不 `ReCreate`。`kExtrude2` 会留下「参数已变换、几何未变」的不一致;`kRevolve` / `kRevolve2` / `kSweep` 整段分支不执行,完全不动
|
||||
- `kLoft` 更严重:`vec` 为空导致 `strAll` 为空,`:5567` 把 `m_sScr` 覆盖成空字符串,`ReCreate` 里 `CreateLoft` 因空输入直接 `return false`(`:5006`)——**一次移动就永久丢掉截面数据**
|
||||
- `ToJson`(`:5211`)三个分支(`kSweep`、单 region、多 region)全靠 `m_sScr` 解析出 `__sScr__`,不改则导出的 JSON 里 region 几何为空
|
||||
- 因此阶段三的范围是「所有 `m_sScr` 读写者」,不存在「只改生成路径、留着这两处」的做法。`m_sScr` 在 `AcDbX3dSolid.cpp` 共 66 处、24 个函数:`ReCreate` 18、`TransformBy` 10、`ToJson` 9、9 个 `Create*` 各 1、4 组 Get/Set 各 1、`dwgIn/OutFields` 各 1
|
||||
2. 老图纸里 region 类型的实际占比——占比低的话体积收益有限,可以永久搁置
|
||||
1. 图纸体积重新成为瓶颈——阶段三的收益只有这一项
|
||||
2. 能接受格式变更,或愿意同时做降级导出(第 12 节)
|
||||
3. `TransformBy`、`ToJson` 与 4 组 Get/Set 必须一起改,核对结果见下
|
||||
|
||||
### 11.3 实施时的技术前提(已核对)
|
||||
`m_sScr` 在 `AcDbX3dSolid.cpp` 共 66 处、24 个函数:`ReCreate` 18、`TransformBy` 10、`ToJson` 9、9 个 `Create*` 各 1、4 组 Get/Set 各 1、`dwgIn/OutFields` 各 1。范围是「所有 `m_sScr` 读写者」,不存在「只改生成路径」的做法:
|
||||
|
||||
- `TransformBy`(`:5488`)5 个类型都靠 `StringToRegion(m_sScr)` 取截面,取不到就 `bChanged = false`,末尾不 `ReCreate`。`kExtrude2` 会留下「参数已变换、几何未变」的不一致;`kRevolve` / `kRevolve2` / `kSweep` 整段分支不执行,完全不动
|
||||
- `kLoft` 更严重:`vec` 为空导致 `strAll` 为空,`:5567` 把 `m_sScr` 覆盖成空字符串,`ReCreate` 里 `CreateLoft` 因空输入直接 `return false`(`:5006`)——一次移动就永久丢掉截面数据
|
||||
- `ToJson`(`:5211`)三个分支(`kSweep`、单 region、多 region)全靠 `m_sScr` 解析出 `__sScr__`,不改则导出的 JSON 里 region 几何为空
|
||||
- 4 组 Get/Set(`:5120`~`:5209`)直接读写 `m_sScr`,外部 15 处调用方(`AecDbBDPipeBase.cpp` 6、`DTYGDlg.cpp` 1、`DTYG_MODIFY.cpp` 8)依赖它们
|
||||
|
||||
### 11.3 技术前提(核对结果,存档)
|
||||
|
||||
- `kCurrentVersionNumber` 当前是 **4**。`m_pSatBuffer` 的读写通道在 `dwgOutFields:4822` / `dwgInFields:4754`,版本 > 1 即生效,阶段三不需要动序列化
|
||||
- **不需要**新增 `CoreTools::RegionToBuffer`:`RegionToString(const AcDbRegion*, char*&)`(`CoreTools.cpp:3114`)已经输出 SAT 的 ASCII 字节和长度,内部用 `MakeTempSatPath` + `DeleteFile`
|
||||
@@ -425,15 +428,17 @@ void SetSweepData(const CString& sReg, const AcDbCurve* pCurve);
|
||||
| --- | --- | --- |
|
||||
| 一:临时文件唯一化 | 已合并 | #22、#26 |
|
||||
| 二:懒重建 | 已合并 | #25、#27 |
|
||||
| 三:region 二进制化 | 暂缓 | — |
|
||||
| 降级导出(阶段三配套) | 方案已定,未实施 | — |
|
||||
| 三:region 二进制化 | **取消**(2026-10-22) | — |
|
||||
| 降级导出(阶段三配套) | 取消,方案存档于第 12 节 | — |
|
||||
|
||||
---
|
||||
|
||||
## 12. 降级导出(新格式 → 老格式)
|
||||
## 12. 降级导出(已取消,方案存档)
|
||||
|
||||
### 12.1 结论
|
||||
|
||||
> 阶段三取消后本方案不再需要,以下保留作存档。
|
||||
|
||||
可行,而且不需要重建几何。容器里存的就是 `acisOut` 出来的 SAT ASCII 字节,老 `m_sScr` 里存的也是同一批字节;降级只是「解包容器 → 按老规则拼字符串」,纯内存操作,不调 `acisIn`、不落临时文件、不损失任何东西。
|
||||
|
||||
这让阶段三的兼容代价从「老版本永远看不到新图几何」变成「平时用新格式,交付给老版本用户前导一次」。
|
||||
@@ -551,3 +556,20 @@ void SaveLegacyDwg()
|
||||
| 主要风险 | 老格式规则核对不全,导出的图在老版本里读不出来 |
|
||||
|
||||
12.6 的结论已经定:遗留类型不参与迁移,阶段三不必为它们设计容器格式。与阶段三的先后关系:两者最好一起上——阶段三一旦合入、`m_sScr` 停写,没有降级导出的那段时间里,新图在老版本插件上就是缺几何的。
|
||||
|
||||
---
|
||||
|
||||
## 13. 下一步方向:开图速度(2026-10-22 记录)
|
||||
|
||||
阶段三取消后,性能问题回到开图本身。已核对的瓶颈:
|
||||
|
||||
- `AecDbX3dPartEntity::dwgInFields:1824` 在开图时无条件调用 `m_pPart->Create()`。全库扫描 `dwgInFields`,立即重建的只有这一处
|
||||
- `AecDbX3dPart::Create()`(`AecDbX3dPart.cpp:786`)对每个 unite 成员调 `GetDraw3dSolid()`(`EnsureCreated` + `clone` + 旋转),逐个 `booleanOper(kBoolUnite)`,再跑 subtract 列表,最后整体变换
|
||||
- 单个 part 的成本约 N×(acisIn + clone) + (N−1)×布尔。N 大、布尔对象复杂时是非线性增长,这正是「复杂几何由 boolean 得到」的场景
|
||||
|
||||
两个候选方向:
|
||||
|
||||
1. **懒执行**:把 `X3dPartEntity::dwgInFields` 里的 `Create()` 去掉,改成首次绘制或取几何时再建(同阶段二的 `m_bNeedCreate` 模式)。改动小、风险低;收益集中在关闭/冻结图层、视口外、只读打开(XREF、审核、发布)。全图都在视口内时,只是把成本从开图移到首次显示
|
||||
2. **缓存布尔结果**:把 part 最终的 solid 以 SAT 存进 DWG,开图时一次 `acisIn` 代替 N 次建体 + N 次布尔。这是唯一真正减少计算量的办法,代价是体积增大、参数变更要失效重建、`Create()` 末尾挂在 solid 上的 `BIMDATA` XData 要重新挂
|
||||
|
||||
方向未定,待决策。
|
||||
Reference in new issue
Block a user