docs: 补阶段三的降级导出方案(新格式 → 老格式)
新增第 12 节。核心结论:降级不需要重建几何,容器里就是 acisOut 的 SAT ASCII 字节,老 m_sScr 里也是同一批字节,解包后按老规则拼回即可,纯内存、 不调 acisIn、不落临时文件。 - 在 dwgOutFields 里做:AcDbX3dSolid 的持有关系分散在 X3dPart、X3dPartEntity 以及 Hanger/Roof/Stair 的 m_solids 缓存里,命令层遍历不全,但存盘时每个 实例必然走 dwgOutFields - 进程级开关 + RAII 复位,只改写出内容,不改对象状态,导出后当前图仍是新格式 - MakeLegacyScr 按 3.2 的表分四类拼回,容器写出长度 0 - 12.6 指出 4.3.6「region 类型停写 m_sScr」与 kIntersect/kSliceSolid 的折线 后缀冲突,建议这两种类型继续只写折线后缀 - 12.8 记录限制:导出写的对象版本号是 4,只能被 kCurrentVersionNumber >= 4 的插件读取;版本号 3 的存量插件靠降级救不回来,需要另写 v3 布局 11.1、11.2、11.4 同步加交叉引用与状态行。
This commit is contained in:
1 parent
186431a11e
commit
cad5289fae
1 file changed
+130
@@ -385,6 +385,8 @@ void SetSweepData(const CString& sReg, const AcDbCurve* pCurve);
|
||||
|
||||
不可见不等于丢数据:`m_pSatBuffer` 老版本也会原样读写(版本 > 1 的通道一直都在),所以旧版打开后另存、再回新版打开,几何仍能恢复。非 region 类型(`m_sszPoint2ds` 点串、SubDMesh、管廊脚本)不受影响。
|
||||
|
||||
需要把图交给老版本用户时,用第 12 节的降级导出:存盘瞬间把容器翻成老格式的 `m_sScr`,老插件就能正常显示几何,当前文档本身不受影响。
|
||||
|
||||
| 选项 | 后果 | 结论 |
|
||||
| --- | --- | --- |
|
||||
| 不升版本号,接受老插件缺几何 | 老插件能开图、参数都在,region 类型几何不显示;换新版可恢复 | **已定,选这个** |
|
||||
@@ -395,6 +397,7 @@ void SetSweepData(const CString& sReg, const AcDbCurve* pCurve);
|
||||
|
||||
1. `TransformBy`、`ToJson` 是否一起改——这两处在运行时会反复导出/解析 SAT,是阶段三改动量的大头
|
||||
2. 老图纸里 region 类型的实际占比——占比低的话体积收益有限,可以永久搁置
|
||||
3. `kIntersect` / `kSliceSolid` 的折线后缀怎么存(12.6)——阶段三动 `m_sScr` 之前必须先定,否则折线文本会丢
|
||||
|
||||
### 11.3 实施时的技术前提(已核对)
|
||||
|
||||
@@ -411,3 +414,130 @@ void SetSweepData(const CString& sReg, const AcDbCurve* pCurve);
|
||||
| 一:临时文件唯一化 | 已合并 | #22、#26 |
|
||||
| 二:懒重建 | 已合并 | #25、#27 |
|
||||
| 三:region 二进制化 | 暂缓 | — |
|
||||
| 降级导出(阶段三配套) | 方案已定,未实施 | — |
|
||||
|
||||
---
|
||||
|
||||
## 12. 降级导出(新格式 → 老格式)
|
||||
|
||||
### 12.1 结论
|
||||
|
||||
可行,而且不需要重建几何。容器里存的就是 `acisOut` 出来的 SAT ASCII 字节,老 `m_sScr` 里存的也是同一批字节;降级只是「解包容器 → 按老规则拼字符串」,纯内存操作,不调 `acisIn`、不落临时文件、不损失任何东西。
|
||||
|
||||
这让阶段三的兼容代价从「老版本永远看不到新图几何」变成「平时用新格式,交付给老版本用户前导一次」。
|
||||
|
||||
### 12.2 为什么在 `dwgOutFields` 里做
|
||||
|
||||
`AcDbX3dSolid` 的持有关系是分散的:`AecDbX3dPart`、`AecDbX3dPartEntity`,以及 `AecDbHanger` / `AecDbRoof` / `AecDbStair` 各自的 `m_solids` 缓存。从命令层遍历找不全所有实例,但存盘时每个实例一定会走 `dwgOutFields`。
|
||||
|
||||
所以在序列化层加一个进程级开关:开关打开时,`dwgOutFields` 把 region 容器翻译成老格式的 `m_sScr`,并抑制容器写出。
|
||||
|
||||
### 12.3 接口
|
||||
|
||||
```cpp
|
||||
// AcDbX3dSolid.h
|
||||
static void SetLegacyOutput(bool b);
|
||||
static bool IsLegacyOutput();
|
||||
|
||||
private:
|
||||
bool MakeLegacyScr(CString& sScr) const; // 解包容器,按 m_eType 拼回老格式
|
||||
bool HasNewRegionData() const; // 见 4.3.4
|
||||
```
|
||||
|
||||
`MakeLegacyScr` 成功返回 true;容器损坏、解包不出 region 时返回 false,调用方退回写新格式(宁可不降级,也不写出空几何)。
|
||||
|
||||
### 12.4 `dwgOutFields` 的改动
|
||||
|
||||
只有两处:`:4797` 写 `m_sScr`、`:4822-4829` 写容器。
|
||||
|
||||
```cpp
|
||||
CString sScrOut = m_sScr;
|
||||
const void* pSatOut = m_pSatBuffer;
|
||||
Adesk::UInt32 nSatOut = m_nSatLen;
|
||||
|
||||
if (IsLegacyOutput() && HasNewRegionData() && MakeLegacyScr(sScrOut))
|
||||
{
|
||||
pSatOut = NULL; // 容器不写出,老插件读到长度 0
|
||||
nSatOut = 0;
|
||||
}
|
||||
|
||||
pFiler->writeString((LPCTSTR)sScrOut);
|
||||
...
|
||||
pFiler->writeUInt32(nSatOut);
|
||||
if (pSatOut != NULL)
|
||||
pFiler->writeBytes(pSatOut, nSatOut);
|
||||
```
|
||||
|
||||
关键点:
|
||||
|
||||
- **不改对象状态**。`m_sScr` / `m_pSatBuffer` 都不动,只换写出的内容,导出后当前图纸仍是新格式,可以继续编辑、继续存盘
|
||||
- 容器写 0 长度,老插件 `readUInt32` 读到 0 直接跳过,不会报错
|
||||
- 对象版本号仍写 4,不升
|
||||
|
||||
### 12.5 `MakeLegacyScr` 的拼法(按 3.2 的表)
|
||||
|
||||
| 类型 | 容器里 | 拼回 `m_sScr` |
|
||||
| --- | --- | --- |
|
||||
| `kExtrude2` / `kSlicePipe` / `kRevolve` / `kRevolve2` / `kSweep` | 1 个 region | region 的 SAT 文本 |
|
||||
| `kConePipe` | 2 个 region(外、内) | `外环SAT` + `\|` + `内环SAT` |
|
||||
| `kIntersect` / `kSliceSolid` | 1 个 region | `regionSAT` + `m_sScr`(折线后缀,见 12.6) |
|
||||
| `kLoft` | N 个 region | N 段 SAT 用 `@region@` 连接 |
|
||||
|
||||
读端能容忍 `|` 留在第二段:`kConePipe` 用 `StringToRegion(sScr2)`(`:4489`)、`kIntersect` / `kSliceSolid` 用 `StringToPolyline(sScr2)`(`:4403`、`:4441`),两者内部都靠找 ACIS 头 / 数值容错。
|
||||
|
||||
### 12.6 阶段三必须先把折线后缀的位置定下来
|
||||
|
||||
`kIntersect` / `kSliceSolid` 的老格式是 `regionSAT|折线文本`,折线文本不是 region,不进容器。而 4.3.6 要求 region 类型停写 `m_sScr`——这两条冲突。
|
||||
|
||||
**建议**:这两种类型继续写 `m_sScr`,但只写老格式的第二段(含开头的 `|`,即原来的 `sScr2`)。理由:
|
||||
|
||||
- 体积上只多了折线文本,region 那部分照常减半
|
||||
- 读端 `sScr2 = m_sScr.Mid(nPos)` 的既有切分逻辑不用改
|
||||
- 降级导出直接 `regionSAT + m_sScr`,不需要额外字段
|
||||
|
||||
不这么做的话,折线只能塞进容器做第二个 section,容器格式要加类型标签,复杂度和风险都上一个台阶。
|
||||
|
||||
### 12.7 命令
|
||||
|
||||
```cpp
|
||||
void SaveLegacyDwg()
|
||||
{
|
||||
AcDbDatabase* pDb = acdbHostApplicationServices()->workingDatabase();
|
||||
// 目标文件:当前图名 + _legacy.dwg,或让用户选
|
||||
ScopedLegacyOutput guard; // 构造时置位,析构复位
|
||||
Acad::ErrorStatus es = pDb->saveAs(szTarget, false, AcDb::kDHL_CURRENT);
|
||||
if (es != Acad::eOk)
|
||||
acutPrintf(_T("\n导出失败,err=%d"), es);
|
||||
}
|
||||
```
|
||||
|
||||
- `saveAs(file, false, ...)` 的第二个参数是 `bBakAndRename`,传 `false` 只写副本、不切换当前文档(`dbmain.h:473`)
|
||||
- 开关用 RAII 复位,命令异常、用户取消都不会留下「后续存盘全变老格式」的状态
|
||||
- 只处理当前数据库,外部参照里的 `AcDbX3dSolid` 不在范围内
|
||||
|
||||
### 12.8 一个必须说清的限制:只能兼容 `kCurrentVersionNumber >= 4` 的插件
|
||||
|
||||
`dwgOutFields` 写出的对象版本号固定是 4(`:4776`)。老插件的 `dwgInFields` 一旦发现 `version > kCurrentVersionNumber` 就返回 `eMakeMeProxy`(`:4682`),整个对象变代理,降级内容一点都读不到。
|
||||
|
||||
`dwgInFields` 里还留着 `version > 2 && version < 4` 的分支(`:4759`),说明线上确实存在版本号 3 的插件。**这些插件靠降级导出救不回来**——要兼容它们得额外写 v3 布局(`kSweep` 的路径要以 polyline 内联在对象字段之后),工作量另算,本次不做。
|
||||
|
||||
降级导出的目标客户是「版本号已经是 4、只是不认识容器」的插件。
|
||||
|
||||
### 12.9 验证清单
|
||||
|
||||
- 9 种类型各建一个样本,导出后装到老版本插件里打开,几何、面积、位置都正确
|
||||
- 老版本打开导出的图 → 另存 → 回新版打开,几何仍正确(回环)
|
||||
- 导出前后,当前文档自身存盘仍是新格式(开关已复位)
|
||||
- 容器被人为改坏(magic 对、region 段截断)时,`MakeLegacyScr` 返回 false,导出退回新格式并打日志,不产出空几何
|
||||
- `kIntersect` / `kSliceSolid` 的折线后缀原样保留,读回后截面边界正确
|
||||
|
||||
### 12.10 成本与时机
|
||||
|
||||
| 项 | 量 |
|
||||
| --- | --- |
|
||||
| 开关 + `dwgOutFields` 分支 | ~30 行 |
|
||||
| `MakeLegacyScr` 按类型拼回 | ~100 行 |
|
||||
| 导出命令 + 文件选择 | ~40 行 |
|
||||
| 主要风险 | 老格式规则核对不全,导出的图在老版本里读不出来 |
|
||||
|
||||
依赖 12.6 的折线后缀方案先定。与阶段三的先后关系:两者最好一起上——阶段三一旦合入、`m_sScr` 停写,没有降级导出的那段时间里,新图在老版本插件上就是缺几何的。
|
||||
Reference in new issue
Block a user