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

+65 -30
View File
@@ -302,7 +302,7 @@ void dwgOutFieldsForXPrim(AecEqui::XPrimData *pSolid, ...) // :239
顺带处理:跳过 `NULL` 指针并单独计数,避免"写了数量但循环少写一条"导致读写错位;删掉原来定义后未使用的 `int num`。
### 3.2 P1:`subErase` 里 `Find` 当布尔用
### 3.2 P1:`subErase` 里 `Find` 当布尔用(已修复)
```cpp
if (eSubType == eValve || sName.Find(_T("阀")) != -1 || sName.Find(_T("接头"))) // :2119
@@ -310,7 +310,9 @@ if (eSubType == eValve || sName.Find(_T("阀")) != -1 || sName.Find(_T("接头")
`CString::Find` 找不到返回 `-1`,非 0 即真,所以**第三个条件恒真**。整句等价于"永远是阀门",删除任何设备都会走合并管线那段逻辑(`GetInterface` + `PushGripMessage`)。应写成 `!= -1`。
### 3.3 P1:`DrawHandFlg` 用 `==` 赋值
**已修复**:补 `!= -1`。删除普通设备不再误走阀门/接头的合并管线分支。
### 3.3 P1:`DrawHandFlg` 用 `==` 赋值(已修复)
```cpp
if (nVt == 1) sFlag = _T("M");
@@ -320,7 +322,9 @@ else sFlag == _T("Y"); // :2656 应为 =
液动(3)时文字为空,画出来是空标注。另外这里直接取 `GetInterface(0)` / `GetInterface(1)`,接口不足 2 个时 `inf2` 是默认值,`distanceTo` 为 0、`normalize()` 得到零向量,后续 `angleTo` 结果不可信。
### 3.4 P1:`ProcessHlrResult` 在遍历中删 map 元素
**已修复**:`==` 改为 `=`,液动阀(3)现在会画出 `Y`。接口不足 2 个时 `inf2` 取默认值、方向不可信的问题未动,属于显示容错,另行评估。
### 3.4 P1:`ProcessHlrResult` 在遍历中删 map 元素(已修复)
```cpp
for (; it != _preAr.end(); ++it)
@@ -332,7 +336,9 @@ for (; it != _preAr.end(); ++it)
应改为 `it = _preAr.erase(it);`。这是典型的偶发崩溃点(容器元素少时不容易复现)。
### 3.5 P1:`GetSectionDraw` 返回值取反
**已修复**:改成 `while` + `erase(it++)`。没有用 `it = erase(it)`,因为 R190 走的是 C++98 标准(`cmakelists.txt` 按 SDK 版本切换),C++03 的 `map::erase(iterator)` 返回 `void`。
### 3.5 P1:`GetSectionDraw` 返回值取反(已修复)
```cpp
int nCount = arRegionPtrs.length();
@@ -343,6 +349,10 @@ return (nCount - nCoundPre); // :12762 顺序反了
返回的是"调用前 − 调用后",恒为 0 或负数。若调用方用它判断"是否剖到东西",判断必然失败。
**已修复**:改为 `nCoundPre - nCount`。全库调用点都忽略这个返回值,所以此前没有实际故障。
注意:`AecDbEwFitting.cpp:16523`、`AecDbECFitting.cpp:8751` 的同名函数是一模一样的写法(同样的错误),本次未改,见 5.4。
### 3.6 P1:`HLR_CALC` 标志会被存进图纸
`Draw3d:3009` 一旦读到 `HLR_CALC` 为真就直接返回,什么都不画。这个标志由 `PreprocessForHlr:13204` / `:13360` 置真、`ProcessHlrResult:13107` 复位。
@@ -360,11 +370,13 @@ return (nCount - nCoundPre); // :12762 顺序反了
米制图纸里,同一份数据经两个入口读出来的接口尺寸差 1000 倍。`Draw*Vlv2d` 用下标版,`subErase` / `PreprocessForHlr` 用数组版,两边算出来的东西对不上。
### 3.8 P1:`copyFrom` 漏拷字段
### 3.8 P1:`copyFrom` 漏拷字段(已修复)
`:2174` 只拷了 `m_mapSpecXData` / `m_nInfActive` / `m_ptInsert` / `m_vtDir` / 几何单元,**没有拷 `m_bVert`、`m_idDash`、`m_idCenter`**。复制粘贴一个竖放阀门,粘贴出来是横放的;两个图层软指针也丢了(虚线和中心线会跑到默认图层)。
### 3.9 P2:`MakeBlockRefSet` 的范围累加逻辑错
**已修复**:补拷 `m_bVert` / `m_idDash` / `m_idCenter`。
### 3.9 P2:`MakeBlockRefSet` 的范围累加逻辑错(已修复)
```cpp
for (...) {
@@ -382,7 +394,9 @@ for (...) {
应改成 `if (isValidExtents(extAdd)) ext.addExt(extAdd);`,块参照分支直接 `continue`。
### 3.10 P2:`byJson` 的 `m_pData` 尺寸对不上
**已修复**:块参照直接 `continue`;`extAdd` 每轮重新构造并检查 `getGeomExtents` 返回值;判断对象改为 `extAdd`。
### 3.10 P2:`byJson` 的 `m_pData` 尺寸对不上(已修复)
```cpp
p->m_nSize = it->value.GetInt(); // 字节数(来自 __nSize__)
@@ -393,16 +407,20 @@ p->m_pData = new PVOID[br._len]; // 按 PVOID 个数分配
分配长度取决于 `br._len`,使用长度取决于 `m_nSize`,两者来自不同字段。JSON 被改过或版本不一致时就会越界读写。应按 `m_nSize` 分配并校验 `sizeof(PVOID)*br._len >= m_nSize`。
### 3.11 P2:开图读入没有边界校验
**已修复**:`br._len` 本来就是字节数,改为 `new byte[br._len]` + `memcpy(..., br._len)`,并用 `br._len` 覆盖 `m_nSize`(两者不一致时以实际数据长度为准)。
### 3.11 P2:开图读入没有边界校验(已修复)
`dwgInFieldsForXPrim:172`:
- `readInt32(&nSize)` 后直接 `new byte[pSolid->m_nSize]`(`:193`),负值或超大值都没有检查(负值转 `size_t` 会申请巨大内存)
- `readInt32(&nSize)` 后直接 `new byte[pSolid->m_nSize]`(`:193`),超大值没有检查(负值被 `> 0` 挡住,不会分配)
- `readBytes` 的返回值没有检查
- `m_Combins` 是**递归**读(`:227`),没有深度上限,损坏的图纸可以打爆栈
同类的 `AcDbX3dSolid` 阶段一、二已经补过类似的防护,这里可以照搬。
**已修复**:加 16MB 上限(`kMaxXPrimDataSize`),超限 `setFilerStatus(Acad::eInvalidInput)` 让整个 `dwgInFields` 退出;`readBytes` 检查返回值,失败时释放并清零。`m_Combins` 的递归深度上限未加,损坏图纸仍可能打爆栈,优先级低。
### 3.12 P2:`PreprocessForHlr` 的"对面"被变换了两次
```cpp
@@ -417,14 +435,18 @@ for (...) {
原实体在 `-H/2` 位置,克隆体被移到 `+H` 位置(两次 `+H/2`),两侧不对称。除非这是刻意做的"厚度补偿",否则应只乘一次。建议拿一个剖切样例对照确认。
### 3.13 P2:`GetBodyBox` 恒返回 `TRUE`
### 3.13 P2:`GetBodyBox` 恒返回 `TRUE`(已修复)
`:4205` 无论有没有取到实体都 `return TRUE`;且 `ar3D` 引用在 `Draw3d` 之前就绑定了(`:4207`)。当前 `Get3DBuffer()` 返回成员引用,重新填充不会换对象,所以能工作;但如果哪天改成返回副本就会静默失效。返回值也应反映实际结果。
### 3.14 P2:`clearGeoBuffer()` 是空实现
**已修复**:返回实际是否取到范围;`_ext` 改为每轮新建,避免把上一轮的累积结果重复并入。11 处调用点都忽略返回值,行为不变。
### 3.14 P2:`clearGeoBuffer()` 是空实现(已修复)
`:12861` 函数体只有 `AssertWriteEnabled();`。`PipelineCmd/EquipmentMakeDlg.cpp` 有 8 处调用,本意应该是清掉 2D/3D 缓存(`Clean2DBuffer` / `Clean3DBuffer`)。现在是"调了没反应",改了参数后旧几何还在。
**已修复**:改为 `Clean2DBuffer(); Clean3DBuffer();`。调用方(`EquipmentMakeDlg`、`EQU_MODIFY`、`ParamEquJson`)都是改完参数后调它,语义一致。
### 3.15 P2:`booleanOper` 的所有权写法在本文件里自相矛盾
同一文件里两种写法并存:
@@ -539,21 +561,25 @@ Draw3dSolid(&dc, nColor); // :3062 拖拽时每帧都走到这里
### 5.1 第一批:内存与正确性(不改接口、不改格式)
拆成两批提交:**内存问题已做(见 2.13)**,逻辑缺陷待做。
分两批提交:**内存问题已完成(见 2.13)**,**逻辑缺陷已完成(见 3.2~3.14)**。
| # | 改动 | 位置 | 风险 | 状态 |
| --- | --- | --- | --- | --- |
| 1 | 删掉 `dwgInFields` 里的重复分配,`readString` 补 `acutDelString` | `:1707` `:1720` | 低 | 已完成 |
| 2 | 析构补 `FreeSubPrimData()` | `:1686` | 低(依赖 #3) | 已完成 |
| 3 | `releaseData()` 统一 `delete[]`,`FreeSubPrimData()` 释放 `m_pData` 后删结构体 | `:1520` | 低 | 已完成(见 2.3、2.13) |
| 4 | `subDMesh2NewSolid` 按下标倒序删除并释放 | `:3159` | 中(涉及几何正确性,需样例图) | 已完成 |
| 5 | `RemoveSubPrimObj*` 补释放 `m_pData` | `:4276` `:4291` | 低 | 已完成 |
| 6 | `subErase` 的 `Find` 补 `!= -1` | `:2119` | 低(行为会变,需回归删除阀门) | 待做 |
| 7 | `DrawHandFlg` 的 `==` 改 `=` | `:2656` | 低 | 待做 |
| 8 | `ProcessHlrResult` 改用 `it = erase(it)` | `:13128` | 低 | 待做 |
| 9 | `copyFrom` 补 `m_bVert` / `m_idDash` / `m_idCenter` | `:2174` | 低 | 待做 |
| 10 | `GetSectionDraw` 返回值改 `nCoundPre - nCount` | `:12762` | 低(需确认调用方语义) | 待做 |
| 11 | `clearGeoBuffer` 实现为清 2D/3D 缓存 | `:12861` | 低 | 待做 |
| # | 改动 | 风险 | 状态 |
| --- | --- | --- | --- |
| 1 | 删掉 `dwgInFields` 里的重复分配,`readString` 补 `acutDelString` | 低 | 已完成 |
| 2 | 析构补 `FreeSubPrimData()` | 低 | 已完成 |
| 3 | `releaseData()` 统一 `delete[]`,`FreeSubPrimData()` 释放 `m_pData` 后删结构体 | 低 | 已完成(见 2.3、2.13) |
| 4 | `subDMesh2NewSolid` 按下标倒序删除并释放 | 中 | 已完成 |
| 5 | `RemoveSubPrimObj*` 补释放 `m_pData` | 低 | 已完成 |
| 6 | `subErase` 的 `Find` 补 `!= -1` | 低(行为会变) | 已完成 |
| 7 | `DrawHandFlg` 的 `==` 改 `=` | 低 | 已完成 |
| 8 | `ProcessHlrResult` 改用 `while` + `erase(it++)` | 低 | 已完成 |
| 9 | `copyFrom` 补 `m_bVert` / `m_idDash` / `m_idCenter` | 低 | 已完成 |
| 10 | `GetSectionDraw` 返回值改 `nCoundPre - nCount` | 低 | 已完成 |
| 11 | `clearGeoBuffer` 实现为清 2D/3D 缓存 | 中(影响所有改参数路径) | 已完成 |
| 12 | `MakeBlockRefSet` 范围累加改判 `extAdd` | 低 | 已完成 |
| 13 | `byJson` 按字节长度分配 `m_pData` | 低 | 已完成 |
| 14 | `dwgInFieldsForXPrim` 加尺寸上限与读失败处理 | 低 | 已完成 |
| 15 | `GetBodyBox` 返回实际结果 | 低 | 已完成 |
另外补做的 4 处内存修复(2.6、2.7、2.9、2.10、2.11、`GetDraw3dables` 合并泄漏、`dwgInFields` 的 `RemoveAll`)见 2.13。
@@ -581,9 +607,12 @@ Draw3dSolid(&dc, nColor); // :3062 拖拽时每帧都走到这里
### 5.4 需要先确认的事
1. ~~`booleanOper` 是否删除入参(3.15)~~ —— 2026-10-23 按「不删除入参」处理,理由见 3.15
2. `GetSectionDraw` 的返回值调用方到底期望什么(3.5)
3. `PreprocessForHlr` 的 `mat4` 双次变换是否刻意(3.12)
4. ~~`kCombination` 单元的实际存量(5.2)~~ —— 2026-10-25 确认仍在用,见 3.1
2. ~~`GetSectionDraw` 的返回值调用方到底期望什么(3.5)~~ —— 2026-10-25 核实全库调用点都忽略返回值,已按「返回新增个数」修正
3. ~~`kCombination` 单元的实际存量(5.2)~~ —— 2026-10-25 确认仍在用,见 3.1
4. `PreprocessForHlr` 的 `mat4` 双次变换是否刻意(3.12)
5. `HLR_CALC` 是否从 `m_mapSpecXData` 的序列化里排除(3.6):要动 `AecDbObjXDataMap` 公共类,且 `AecDbEwPipe` / `AecDbEwFitting` / `AecDbOpening` / `AecDbPipeHanger` 都在用它,需逐个确认有没有依赖它跨会话保持的地方
6. `GetInterface` 数组版是否补 `dUnit`(3.7):补了之后米制图纸里所有走数组版的尺寸会放大 1000 倍,需确认 `subErase`、`PreprocessForHlr`、`Draw*Vlv2d` 的下游计算不受影响
7. `AecDbEwFitting.cpp:16523` / `AecDbECFitting.cpp:8751` 的 `GetSectionDraw` 同样写反,是否一起改
---
@@ -599,6 +628,12 @@ Draw3dSolid(&dc, nColor); // :3062 拖拽时每帧都走到这里
| `subErase` | 删除阀门/接头/普通设备各一次,确认只有阀门走合并管线 |
| `HLR_CALC` | 剖切过程中保存再重开,设备 3D 仍可见 |
| `copyFrom` | 复制粘贴竖放阀门,方向与图层保持 |
| `DrawHandFlg` | 液动阀(驱动类型 3)2D 符号旁显示 `Y` |
| `ProcessHlrResult` | 反复开关阀门剖切 2D 显示,不崩溃 |
| `clearGeoBuffer` | 改单元参数(box/cylinder/cone)后关闭对话框,几何立即更新 |
| `MakeBlockRefSet` | 剖切/2D 导出生成的块,插入点位于设备中心而不是原点 |
| `byJson` | JSON 导入设备,几何与参数正确 |
| `subErase` 的 `Find` | 删除普通设备后,相邻管线不被合并 |
| 拖拽优化 | 拖夹点 10 秒,内存不涨、帧率稳定;松手后几何位置正确 |
| 2D bbox | 各阀门 2D 符号方向、手柄位置与改前一致 |
@@ -618,6 +653,6 @@ Draw3dSolid(&dc, nColor); // :3062 拖拽时每帧都走到这里
1. ~~第一批 1~5(内存),单独一个 PR,可独立验证~~ —— 已完成,范围扩到 2.1~2.11 全部内存项,见 2.13
2. ~~第二批(`m_Combins` 存盘清空)~~ —— 已完成(PR #48),见 3.1、5.2
3. 第一批 6~11(逻辑),单独一个 PR
4. 确认 5.4 剩下的两个问题
3. ~~第一批 6~11(逻辑)~~ —— 已完成,范围扩到 3.2~3.14 共 10 项,见 5.1
4. 确认 5.4 剩下的问题(3.6 `HLR_CALC` 序列化、3.7 `GetInterface` 单位、3.12 `mat4` 双次变换)
5. 第三批按 4.7 度量结果排序,一项一个 PR