company-desktop
|
533632fbdd
|
feat: 开洞支持异形轮廓,新增井工具(方圆井/圆井)
两个都是 AecDbX3dPartEntity 组合体,接着上次的板/墙开洞往下做。
1) 异形洞(菜单命令 PL_YXKD):没有新增工具,add_aec_opening 加 shape=polygon
+ points:[[x,y],...](可选 bulges)。内部按 PolylineToScript
(Pool3dCmd/pool3dcmdCmd.cpp:889)拼点串 "x,y@bulge,..."、首尾自动闭合,
中心取点集包围盒中点;洞口记的中心/法向仍走 AECMCP_HOLE_CEN/_DIR。
2) 井(PL_JFZJ 方井 / PL_JYZJ 圆井 / PL_JFYJ 方圆井):新增 add_aec_well。
shape=rect 用 length/width/bottom_length/bottom_width,
shape=circle 用 diameter/bottom_diameter,再给 height/wall_thickness,
可选 slab_thickness/offset_x/offset_y/no/remark/layer。
内部照命令实现(pool3dcmdCmd.cpp:6925、6750):先 SetAsHole(1.1×板厚) 开洞,
再把中心挪半板厚、SetAsWell(...) 叠井体,写 KEY_SETASWELL/KEY_ASSOIC/KEY_NO/KEY_REM,
入库后 addPersistentReactor + 母体 AppendAssocPart。
实测(AutoCAD 2020 / R230 Debug,pcf_1.dwg,8x8m/厚300/底面-2000 的板):
- tools/list = 47;
- shape=polygon 5 边形洞 -> 3A1;get_aec_entity_detail 读回
host=3A0 / no=P-1 / position=(1500,1500,-1850)
(1500,1500 正是点集包围盒中心,z=-1850 = -2000+150 板厚中点);
- 方圆井(1500x1200,底 1000x800,深 1500,壁厚 200)-> 3A2;
- 圆井(D1200,底 D1000,深 1500,壁厚 150)-> 3A3。
未做:异形井(PL_JYXJ)与集水坑(PL_JJSK)——它们用的是"上下双轮廓点串"
的 SetAsWell 重载,需要再定义一套 top/bottom 点串参数。
|
2026-10-30 08:48:03 +08:00 |
|
company-desktop
|
51081ab849
|
feat: 开洞工具支持墙体(PL_CBKD 墙体开洞)
上一步只支持平板开洞;这次把同一个工具扩成"板/墙都能开",不再新增工具名:
add_aec_opening / update_aec_opening 的 host 传板(AecDbXSlab)或墙(AecDbXWall)。
墙的处理与命令 PL_QTKDCmdFnc(Pool3dCmd/pool3dcmdCmd.cpp:13051)一致:
- 法向 = 墙基线最近点的切线绕 Z 转 90°(新增 WallNormalAt 助手),也可用 direction 参数指定;
- 深度缺省取墙厚(WallData.dThick);
- 没给 position 时用"基线中点 + 墙底标高 + 半高"(新增 WallCenter 助手,墙没有 ClosestPointToCen);
- 中心同样挪到墙厚中点,然后 SetAsHole + KEY_ASSOIC + LAY_HOLE + AppendAssocPart + 持久反应器。
- 洞口中心/法向都记在专业数据里(AECMCP_HOLE_CEN / AECMCP_HOLE_DIR),update 时复用。
实测(AutoCAD 2020 / R230 Debug,pcf_1.dwg):
- 建 6m 长、200 厚、3m 高的墙(3A0),在其上开 DN800 圆洞 -> 洞口 3A4;
- get_aec_entity_detail 读回 host=3A0 / no=WH-1 / position=(3000, 100, 1500)
(y=100 = 墙厚一半,说明法向和"挪到厚度中点"都对);
- update 改直径成功;平板开洞(矩形 800x600)回归验证仍正常。
|
2026-10-30 08:48:03 +08:00 |
|
company-desktop
|
3013ceb4f7
|
feat: cad_mcp_aec 增加平板开洞工具(add/update_aec_opening)
对应菜单命令 PL_CDKD 平板开洞(Pool3dCmd/pool3dcmdCmd.cpp:14763)。
洞不是普通实体,是"长在母体上的 part",所以工具收 host(板的 handle):
- add_aec_opening:host + shape(circle/rect) + position(缺省取板中心)
+ diameter 或 width/height + depth(缺省取板厚)+ nozzle/no/for_use/layer。
内部照命令的序列:new AecDbX3dPartEntity -> SetAsHole(中心,尺寸,板厚,法向)
-> KEY_ASSOIC 记母体 -> LAY_HOLE 图层 -> 入库 -> 给母体 addPersistentReactor
+ AppendAssocPart(绘制时母体据此做布尔)。
- update_aec_opening:改形状/直径/宽高/深度/管嘴/编号/用途;改尺寸会重建几何。
洞口中心在创建时另存一个 AECMCP_HOLE_CEN 键(SetAsHole 自己会把 KEY_NOPOS 挪到侧边),
更新时就靠它 / 或母体中心兜底。
- query_aec_entities / get_aec_entity_detail 支持 opening(读回 host/no/for_use/position)。
实测(AutoCAD 2020 / R230 Debug,pcf_1.dwg):
- tools/list = 46;
- 先 add_aec_slab 建 6x5m/厚200 的板(3A0),再 add_aec_opening(DN600 圆洞, 中心 2000,2000)
返回洞口 3A1、host=3A0;
- get_aec_entity_detail 读回 host=3A0 / no=H-1 / position=(2000,2000,100)
(z=100 正是板厚中点,说明命令里那步"挪到厚度中点"生效);
- update_aec_opening 改直径成功;query(type=opening) 命中 1 条。
限制(写进文档):目前只支持平板 + 圆/矩形洞;墙体开洞(母体是墙)
和异形洞(点串脚本格式)还没接。
|
2026-10-30 08:48:02 +08:00 |
|
company-desktop
|
a15d04b665
|
feat: cad_mcp_aec 增加管件工具(add/update_aec_fitting)
按"先做管件"开工。管件族(弯头/变径弯头/三通/四通/大小头/法兰/堵头/箍)都是同一个
类 AecDbEwFitting,只靠专业数据 KEY_RUNTIME 区分,所以只加了两个工具:
- add_aec_fitting:position + direction/branch_direction + dn_mm/od_mm/wall_thickness_mm
+ type(elbow/reduce_elbow/reduce/tee/cross/lateral/wye/flange/cap/coupling)
+ ratio/connect/system/material/color/layer/space。
- update_aec_fitting:只改传入字段(含 type,改 type 就是换管件)。
专业数据按 TDbPipeLine::FillConfigXDataMap(PipelineCmd/AecPipeLine.cpp:3204)的
最小可用子集写:KEY_RUNTIME / KEY_MID / KEY_MAJBR / KEY_MINBR、PIPE_DN / PIPE_OD /
PIPE_TDN / PIPE_TOD / PIPE_D / PIPE_THICK / PIPE_RATIO、PIPE_CONNECT / PIPE_COLOR /
PIPE_SYS / PIPE_MATERIAL,创建时补 KEY_2DSTYLE / KEY_SINGLE / PIPE_RRADFLG /
KEY_RadRatio / PIPE_DRAWDIR。查库才能拿到的接口尺寸(PIPE_INTERFACED/L 等)先不填,
绘制时按 DN/外径/壁厚/曲率自算。
query_aec_entities / get_aec_entity_detail 也支持 fitting(读回 type/position/方向/
口径/曲率/连接方式/系统/材质/颜色)。
实测(AutoCAD 2020 / R230 Debug,pcf_1.dwg):
- tools/list = 44;
- add_aec_fitting(type=elbow, DN100/OD114/壁厚4) 建出 handle 3A1,zoom_extents 后
get_aec_entity_detail 的包围盒是 0.05/0.10/0.05 量级 —— 说明几何真的建出来了;
- update(type=tee, dn=150) 后读回 type=tee / dn_mm=150,其余字段保持;
- query_aec_entities(type=fitting) 命中 34 条(含图纸原有的 33 个管件)。
|
2026-10-30 08:48:02 +08:00 |
|
company-desktop
|
d671000269
|
fix: AecRxBase 里的 3D 缓存块去掉对 CoreLibrary 的依赖
修 rebase 后暴露的编译/链接问题(AecRxBase 不链接 CoreLibrary):
- 去掉 SectionPerf 计数器(SectionPerfCounter 的实现只在 CoreLibrary 里,
AecRxBase 用的是自己那份静态副本,打不进同一份报告,本来也没有意义);
- 去掉 CMFCDbDwgFiler 判断(CMFCDbDwgFiler 也定义在 CoreLibrary),
内存 filer 走同一条存取路径即可。
|
2026-10-30 08:47:58 +08:00 |
|
company-desktop
|
9088c47bee
|
feat: 通用 3D 缓存块存取(AecDbEntityCommon)+ 先挂在管件上
按"缓存挂在母体实体的 3dbuffer 上"的思路,把上一轮在 AecDbX3dPartEntity 里写的存取逻辑
提成通用能力:
- AecDbEntityCommon::Write3DBufferBlock() / Read3DBufferBlock():
只能在最派生类的 dwgOut/dwgInFields 末尾调用;缓存里**全是 brep 才写**,
有一个非 brep(中心线/箭头等)就整条不写(用户定的语义);
读不到 magic / 校验失败 → 保持空缓存,照旧重建;不动版本号;内存 filer 不参与。
- AecDbEwFitting 上先挂了两个 hook(管件是全库 Add3DBuffer 用得最多的类,96 处)。
- 开关 AEC_3D_DWG_CACHE,默认关(=1 才写/读),Release 与正常存盘零影响。
- AEC_HAS_MODELER_FILER 对中望也打开(沿用上一轮的 cmake 改动)。
实测结论(big1.dwg,MOVE 弄脏 + REGENALL + QSAVE):
- 存盘后的 DWG 里 magic A3DB 出现 0 次 —— 一个块都没写出去;
- 同一次存盘里 EwPipe::RegionAcisout 3011 次,说明"弄脏+重序列化"这条路本身是通的。
原因(两堵墙互相顶):改过的实体在 AssertWriteEnabled 里就被清空了 3D 缓存
(而且 REGENALL 只重建视口可见的对象);没改过的实体增量存盘按字节拷贝、根本不调
dwgOutFields。所以"缓存有效"和"实体是脏的"在存盘那一刻基本不同时成立 ——
"塞进实体自己的流"这条路机制上不成立,不是值不值的问题。
分析写进 3d-cache-dwg-verdict.md §9,并给出唯一自洽的方向:缓存与实体序列化解耦
(隐藏块/字典里的 Xrecord 旁挂 + 命令结束/空闲时写入 + 按 handle 失效)。
这一版的两个函数就是那个方向的 modeler 存取基础,留着复用。
|
2026-10-30 08:39:35 +08:00 |
|
gjm
|
49c23e4395
|
Merge pull request 'docs: cad-mcp-aec.md 增加菜单命令-实体-工具对照表' (#119) from company-desktop/company-desktop-computer/feat-aec-mcp-entities-p2 into main
Reviewed-on: https://git.ethereal-realm.top/gjm/envi-code/pulls/119
Reviewed-by: gjm <littleoldpan@163.com>
|
2026-10-30 08:35:24 +08:00 |
|
company-desktop
|
266a9f5e4c
|
feat: cad_mcp_aec 增加爬梯工具,query 支持 climb_stair
第 4 项(按 sys/*.mnu 扩工具)的第一步:从菜单命令里筛出一类参数清晰的实体先做通。
- 新增 add_aec_climb_stair / update_aec_climb_stair(AecDbClimbStair,对应菜单命令
PL_ZXPT 直爬梯、PL_YHZT 圆护爬梯)。建模序列照抄 pool3dcmdCmd.cpp:5742 的命令实现:
SetSection(踏管直径) -> SetBaseCurve(底->顶) -> SetClimbStairData(参数体),
再写专业数据 2dStyle / 朝向(KEY_MAJBR)。工具直接收两个端点,不需要复现
"放置点+朝向"那套偏移算法。
参数:start/end、width、cage_diameter、height、bottom_elevation、type(0/1)、
bar_diameter、step_height、step_spacing、wall_distance、facing、material、layer。
- query_aec_entities / get_aec_entity_detail 支持 climb_stair(读 GetClimbStairData)。
- mcp_config.json 增加这两个工具(40 -> 42),query 的 type 枚举补 climb_stair。
实测(AutoCAD 2020 / R230 Debug):
- tools/list = 42;add_aec_climb_stair 建出 handle 3A0(宽 450 / 护笼 700 / 高 3000);
- get_aec_entity_detail 读回 type=0/width=450/cage=700/height=3000/bar=20/step=300;
- update 改 width=600、step_height=250 后读回一致;query type=climb_stair 命中 1 条。
|
2026-10-29 23:56:58 +08:00 |
|
company-desktop
|
010d91af04
|
feat: X3dPart 几何块存盘/恢复(env 开关,默认关)+ 中望放开 modeler filer
按"3dbuffer 非空才存、空就不存、读不到就重建"的语义实现第一版:
- 块写在 AecDbX3dPartEntity::dwgOutFields **末尾**,读在 dwgInFields 末尾探测
magic 'A3DP'。不写在 AecDbX3dPart 里:part 是嵌在实体流中间的子流
(它后面还有 m_drawable2d),老版本会把块的字节当成后续字段读。
- 读不到 magic / 块不完整 / modeler 恢复失败 → 一律保持 m_bNeedCreate 走重建,
不刷日志、不动 kCurrentVersionNumber(老版本读新图 = 照旧重建)。
- 内存 filer(clone / copyFrom / 剪贴板)不参与,避免拷贝出来的实体夹带用不上的缓存。
- 探测块会让 filer 状态变成 eEndOfFile,所以 dwgInFields 末尾显式 return eOk,
不再 return pFiler->filerStatus()(否则整个实体会被判读取失败)。
- AecDbX3dPart 加两个存盘用访问器:GetDwgCacheSolid()(脏/没建过返回 NULL)、
SetDwgCacheSolid()(接管恢复出来的 solid,顺带丢掉 m_pSolidDraw 让绘制副本重建)。
- cmakelists.txt:AEC_HAS_MODELER_FILER 对中望也放开(ZRX/Z20xx/arxport/inc/dbacis.h
把 acdbModeler* 映射到 zcdbModeler*,ZwDatabase.lib 有这些符号)。
- 开关 AEC_3D_DWG_CACHE:默认关(确认收益前不改存盘结果),=1 打开;
AEC_3D_CACHE_TRACE=1 时把每次 read/write 写 %TEMP%\aec_x3d_cache.log。
实测(big1.dwg,R230 Debug):
- 开图期探测到 220 个 part 实体,全部 miss(老图,正常回退重建);
- 存盘(MOVE+REGEN+QSAVE)后跟踪日志 **0 条 write**,DWG 只多 128 KB:
这 220 个 part 实体在存盘时不是脏的,增量存盘按字节整块拷贝,dwgOutFields 没被调用;
- 而 X3dPart::Rebuild 是 1138 次 —— 说明 1248 个 part 里只有 220 个是入库实体,
其余 ~918 个是 AecDbBDPipeBase/AecDbSlab/AecDbWeir/AecDbWell 等绘制期 new 出来的临时 part。
结论(已写进 3d-cache-dwg-verdict.md §8):这一版覆盖面上限 220/1248 ≈ 18%,
而且是"part 自己的流里带缓存"这个方案的天生缺陷;下一步要么挂到**所有者实体**
(它们存盘时确实是脏的,写得出去),要么做**图级中央缓存**。等决策后再动。
|
2026-10-29 23:51:31 +08:00 |
|
company-desktop
|
f840d733ca
|
diag: 量 X3dPart 几何存盘的真实体积与序列化成本
问题:上一轮判定"3D 缓存存盘对管道不做"时,顺带给 X3dPart(Rebuild 占开图
18~22%)估了个"体积 +10~40 MB、存盘 +1.5~4 s"——这是估算,没有实测,结论可能
把这条路误杀了。本次补上测量。
改动:AecDbX3dPart::EnsureCreated 里加一个探针(AEC_X3D_SIZEPROBE=1 才生效,
Release 零开销):每个 part 重建后对它的 m_pSolid 做一次 AcDbBody::acisOut
到临时文件,记录 SAT 字节数与耗时,然后删文件;每 100 个 part 把汇总写
%TEMP%\aec_x3d_probe.txt。同时记录同一次 Rebuild 的耗时用于对比。
big1.dwg 实测(AutoCAD 2020 / R230 Debug,开图 95 s):
- 有几何的 part:1200(1248 个里 48 个 Hide/空,无 solid)
- SAT 总字节 3.56 MB,平均 2968 B/part,最大 36086 B
- acisOut 平均 0.799 ms/part;Rebuild 平均 15.3 ms/part(本次合计 20.4 s)
- 重建 / 序列化 = 19.1 倍
据此(都取保守侧):
- DWG 体积增量 ≤ 3.4 MB(8.2 -> ~11.6 MB,+42%)——DWG 里存的是二进制 SAB,
通常比 SAT 文本更小;
- 每次存盘多花 ≤ 0.96 s(1200 x 0.8 ms),且二进制写比转文本便宜、不落盘;
- 开图预计省 15~18 s(重建 18~20 s,恢复按 acisOut 同量级估 1~2 s)。
结论修正:X3dPart 这条"几何存盘"是值得做的,之前的体积/耗时估算高估了 3~10 倍。
配套说明写进 3d-cache-dwg-verdict.md §7。
|
2026-10-29 23:00:03 +08:00 |
|
company-desktop
|
c10f5b0083
|
feat: 补齐 cad_mcp_plugins 的批注/编辑/干涉工具(26 个工具齐了)
现象:mcp_config.json 里配了 40 个工具,但仓库的 cad_mcp_plugins 只有 16 个工厂,
add_line / add_text / add_mtext / add_polyline / add_leader_annotation /
draw_revision_cloud / delete_entities / set_entity_properties / find_collisions /
set_drawing_area 这 10 个在 tools/list 里被静默丢掉(实测只有 30 = 18 + 12)。
来源:d:\new-start\CadProject\src\cad_mcp_plugins(pull 之后新增的
dwg_annotate_*、dwg_review_ui、find_collisions、bvh.h),整体搬到本仓库。
改动:
- 新增 bvh.h、dwg_annotate_common.cpp/h、dwg_annotate_draw.cpp、
dwg_annotate_edit.cpp、dwg_review_ui.cpp、find_collisions.cpp;
- cad_mcp_plugins/cmakelists.txt 的 SOURCES 补上这 6 个 cpp;
- 移植差异两处(都在本仓库编译/运行才暴露):
1. `#include "cadsdk.h"` -> `#include "KTCad.h"`(本仓库没有 cadsdk.h);
2. 上游 cadsdk.h 带 NOMINMAX,本仓库 KTCad.h 没有,`std::min/std::max`
被 windows.h 的宏顶掉(C2589/C2059)→ 在 dwg_annotate_common.cpp、
dwg_annotate_draw.cpp、find_collisions.cpp 里 `#undef min / #undef max`。
- 上游的写库工具没有文档锁:MCP 工具跑在主线程消息里、不在命令上下文,
kForWrite 打开块表记录直接拿到 eLockViolation(0x140),报
"cannot open target space for write"。补了 `dwg_annotate::DocLock`
(acDocManager->lockDocument/unlockDocument 的 RAII),并在
dwg_annotate_draw / dwg_annotate_edit 的 8 个 Execute 开头构造。
这一条是上游在新环境下的真 bug,不修这批工具在本仓库根本用不了。
- 所有新增文件转 UTF-8 with BOM(仓库红线)。
验证:
- R230 Debug / Z2026 Debug 编译通过并部署;dumpbin 显示
cad_mcp_plugins.dll 导出 26 个 Create*Tool + 26 个 Destroy_*。
- AutoCAD 2020 实测(部署目录放仓库的 mcp_config.json,frame 优先读它):
tools/list = **40**,配置里没有一个工具缺失;
add_line / add_text / add_polyline / add_mtext / add_leader_annotation /
draw_revision_cloud 全部返回 created[handle](图层 AI_REVIEW);
set_entity_properties 改图层+颜色、delete_entities 删两个句柄都成功;
find_collisions / find_zero_length 正常返回结构。
|
2026-10-29 22:45:14 +08:00 |
|
company-desktop
|
4f1ea72e4e
|
refactor: cad_mcp_aec 工具改按仓库既有格式描述,并合入 mcp_config.json
现象:上一版自己发明的描述文件 cad-mcp-aec.json 与仓库既有工具(add_line /
query_entities / get_entity_detail)的风格不一致——工具名前缀不同、
点用 {x,y,z} 对象而不是 [x,y] 数组、颜色叫 color_index 而不是 color。
另外 cad_mcp_frame 的运行期配置文件名是 mcp_config.json(找不到才回落
cad-mcp-frame.json),单个 cad-mcp-aec.json 还得手工合并。
改动:
1. 工具改名,与既有工具同一套动词_名词风格:
list_aec_entities -> query_aec_entities
get_aec_entity -> get_aec_entity_detail
create_aec_pipe|wall|slab|column|beam -> add_aec_*
2. 参数约定对齐既有工具:
- 点改用 [x,y] / [x,y,z] 数组(对象写法仍兼容,后端不变);
- 颜色用 color(ACI,256=ByLayer),并兼容旧写法 color_index;
- add_* 支持 space(Model 或布局名),缺省模型空间;
- get_aec_entity_detail 的输出也从 color_index 改成 color,和入参对称。
3. 删掉自定义的 cad-mcp-aec.json,把 12 个工具按标准 MCP 字段 + backend
(type/dll_name/factory_function)写进 cad_mcp_aec/mcp_config.json,
与既有 28 个工具同一份文件;inputSchema 写全,带每个参数的 description。
4. 插件里的 private_name()/private_input_schema() 同步成同一套名字与 schema,
保证配置里没写 schema 时回落也一致。
验证:
- R230 Debug / Z2026 Debug 均编译通过并部署。
- AutoCAD 2020 实测(部署目录放这份 mcp_config.json,cad_mcp_frame 优先读它):
tools/list = 30(既有 18 + 本插件 12),12 个 add_aec_*/update_aec_* 工厂全部加载成功;
query 列出 20 根管道;add_aec_pipe 用 [0,0,0]->[2000,0,0] + color=1 建成功,
detail 读回 dn_mm=100/od_mm=114/wall_thickness_mm=4/color=1;
只给 end 的 update 后端点变 2500、壁厚与颜色不变;
add_aec_wall/slab/column/beam 各建一次并读回参数一致。
已知(与本次改动无关):mcp_config.json 里有 10 个工具在仓库当前的
cad_mcp_plugins.dll 里没有对应工厂函数(AddText/AddMText/AddLine/AddPolyline/
AddLeaderAnnotation/DeleteEntities/SetEntityProperties/DrawRevisionCloud/
FindCollisions/SetDrawingArea),会被静默丢掉,补齐需要先把那些工具的实现
补进 cad_mcp_plugins。
|
2026-10-29 22:26:34 +08:00 |
|
company-desktop
|
132615af42
|
feat: 新增 cad_mcp_aec 插件,让 agent 直接建/改 Envi3D 自定义实体
现象:cad_mcp_frame 的插件机制只能挂"纯 AcDb 层"的只读工具
(cad_mcp_plugins 不链接 CoreCommand,拿不到 AecDbEwPipe / AecDbXWall /
AecDbXSlab / AecDbColumn / AecDbBeam 这些类的实现),agent 没法改仓库的自定义实体。
改动:新建 SourceCode/Code2026/cad_mcp_aec,仍是普通 DLL(由 frame 运行时
LoadLibrary),但链接 CoreCommand_BAL_REMOTE(内含静态库 CoreLibrary),
因此可以 new / 修改这五类实体。cmake 照 PipelineCmd 的写法,并在顶层
cmakelists.txt 里挂在 cad_mcp_frame 同一处(C++11+ 才编,R180/R190 跳过)。
12 个工具(每个实体一个 create + 一个 update,外加 list/get):
list_aec_entities / get_aec_entity
create_aec_pipe / update_aec_pipe
create_aec_wall / update_aec_wall
create_aec_slab / update_aec_slab
create_aec_column / update_aec_column
create_aec_beam / update_aec_beam
单位约定:坐标与建筑尺寸用图纸单位;管道的 dn_mm / od_mm /
wall_thickness_mm 用毫米,内部按 AS_MUNIT 转米(与 BZGDDlg、AecPipeLineTool 一致)。
update_* 只改传入字段;管道只给一个端点时另一端沿用实体现有值。
实现上撞到三个坑,都已修:
1. MCP 工具在主线程消息里跑、不在命令上下文,写库必须先
acDocManager->lockDocument(),否则 appendAcDbEntity 返回
eLockViolation(0x140)。用 DocLock RAII 包起来。
2. 只读实体上取专业数据必须 GetSpecialtyData(AcDb::kForRead):
该函数缺省参数是 kForWrite,第一次实现没注意,直接把 acad 崩了
(%TEMP%\acminidump.dmp)。
3. SetSection() 会清掉 PIPE_THICK 等派生字段("只改 DN"会把壁厚清成 0);
AecDbXSlab::SetRegionSlab(AcGePoint2dArray&) 内部连线不补闭合点,
传点串必须自己首尾闭合。两处都按实测结果处理了。
验证方式:
- R230 Debug、Z2026 Debug 两个 preset 编译通过并自动部署
(cad_mcp_aec.dll,12 个工厂函数 + g_mcpPluginApiVersion 都在导出表里)。
- AutoCAD 2020 实测(临时把工具合进部署目录的 cad-mcp-frame.json,测完还原):
tools/list 返回 30 个工具;pcf_1.dwg 上 list 出 20 根管道;
五种实体各建一次并用 get 读回参数一致;管道改 DN+单端点后壁厚保留;
板改厚/标高生效;类型不匹配与非法 handle 返回 -32004 / -32002。
详见 cad-mcp-aec.md 第 5 节的用例表。
已知限制:只支持这五类实体;新建实体要等一次 REGEN 才有 bbox;
工具没有事务包装;运行期工具描述需要把 cad-mcp-aec.json 的 tools 追加到
部署目录的 cad-mcp-frame.json(插件侧的 private_description 已内置同样的文案)。
|
2026-10-29 21:52:05 +08:00 |
|
company-desktop
|
ece4788723
|
diag: 实测 3D 缓存存盘方案,判定对管道不做
现象:工作计划第 2 项要求把自定义实体的 3D 缓存(m_ar3DDrableBufPtrs_)
用 acdbModelerSave/RestoreEntities*Filer 存进 DWG,再用 AecDbEwPipe 做开图时间对比,
判断这套机制有没有必要。
结论:按原方案对管道不做。数据(big1.dwg,AutoCAD 2020 / R230 Debug,开图 89 s):
- EwPipeBase::Draw3d 整函数 0.20~3.34 s(106~650 次),占开图 0.2~3.7%,
而且随"开图时视图里有多少管道"变化;1088 个管道里大部分根本没画 3D。
- X3dPart::Rebuild 16.4~19.4 s(1248 次),占 18~22%,才是几何重建的大头。
- 基础体构造(GDU DrawPipe/Loft/Cylinder/Cone)合计 36.7 s,与上面有重叠,
大头不在管道身上。
机制层面撞到三个坑(都写进文档了):
1. 附加块只能挂在叶子类。第一版挂在 AecDbEwPipeBase::dwgOut/InFields,
AecDbBDPipeBase / XWall / XSlab / Beam / Weir 等派生类都继承它并在其后继续写字段,
基类读尾部块等于吃掉派生类第一个字段,XWall 曲线长度读成垃圾后无限 append,
开图从 89 s 变 10 分钟开不出来(xperf 采样定位到 AecComplexCurve::append)。
2. 增量存盘下 dwgOutFields 不会被调用。跟踪确认:开图期 AecDbEwPipe::dwgInFields
被调 1088 次,而存盘时 AecDbEwPipe::dwgOutFields 被调 0 次;同一次存盘里
XSlab 374 / XWall 333 / Weir 144 / Beam 126 等都写了(它们载入时被改脏)。
ISAVEPERCENT=0、SAVEAS 到新文件都改变不了。→ "存盘顺带写字"只对本次改过的对象成立。
3. 3D 缓存本身只在画过之后才有内容,没画到的对象缓冲区是空的。
改动范围:
- 只保留两处 Debug-only 计时(AEC_PERF_COUNTER=1 才生效,Release 零开销):
AecDbEwPipeBase::Draw3d(总耗时/重建/命中)与 AecDbX3dPart::EnsureCreated
(构件重建耗时,作为"几何存盘"收益天花板)。
- modeler filer 试点代码(写块/读块/补非 brep)全部回退,不留死代码。
- 新增 3d-cache-dwg-verdict.md 记录数据、三个坑与建议。
验证方式:R230 Debug 编译通过并部署;big1.dwg 冷启动多次实测,
计数器见 %TEMP%\aec_section_perf.txt;卡死那次的栈用 tools/perf_diagsession.py 解析。
未做 R190 / Z2026 编译(本轮没有平台相关代码,试点代码已回退)。
已知风险:无(新增代码只在 Debug+AEC_PERF_COUNTER=1 下计时)。
|
2026-10-29 21:26:53 +08:00 |
|
gjm
|
17e77b448d
|
Merge pull request 'perf: 给基础体构造加计时,定位到 DrawPipe/DrawCone/DrawLoft 共占 33%' (#109) from company-desktop/company-desktop-computer/perf-primitive-counters into main
Reviewed-on: https://git.ethereal-realm.top/gjm/envi-code/pulls/109
|
2026-10-29 16:00:21 +08:00 |
|
company-desktop
|
c25f3edb23
|
fix: 修 MCP 插件的版本校验与加载期弹窗,18 个工具全部可用
端到端实测(/b 脚本按 AecRxBase -> CoreCommand -> cad_mcp_frame 顺序加载)
暴露两个真问题:
1) 版本校验拿到垃圾值,15/16 个工具被误踢
原实现 GetProcAddress(hMod,"acrxGetApiVersion") 转函数指针调用,
和基座自己的 acrxGetApiVersion() 比数值。实测两边返回值是乱的
(1507328 / 2052390912 / 0 交替,其中 1507328=0x170000 才是正确的 23.0),
结果只有第 3 个工具加载成功,其余全被判 SDK 版本不匹配。
改为插件导出数据符号 g_mcpPluginApiVersion=(ARX<<16)|SUB_ARX
(mcp_plugin_api.h 新增 EXPORT_MCP_PLUGIN_VERSION(),每个插件 DLL 调用一次),
基座 GetProcAddress 读内存比对,不涉及调用约定;旧插件没有该符号时只告警按兼容处理。
2) 加载期 AfxMessageBox 会卡住主线程
mcp_ConfigParser 里的几处弹窗全部换成 McpLog:
同时写 %TEMP%\mcp_plugin_load.log 和命令行,并补上每个工具的
[try]/[skip] 明细(dll 是否存在、版本、create/destroy 指针)。
这也是"看起来只加载 3 个工具"的原因——弹窗把主线程挡住了。
实测结果(R230,自动化烟测):
端口 127.0.0.1:8080 6 s 内监听
tools/list 返回 18 个工具(2 lisp_inline + 16 c++_dll)
5 KB 大请求 -32601,证明整包被读完(旧实现会截断)
tools/call get_layers 真正执行插件,返回 {"count":1,"items":[{"name":"0",...}]}
加载日志 16 个 c++_dll 全部 [try] 成功,0 个 [skip]
另外把配置文件加入构建部署:copyarx.exe 能拷任意文件,照 set_debug_post_build 的写法
再加一条 POST_BUILD,把 cad-mcp-frame.json 也拷到部署目录(ZWCAD 走 zw_output_path.json)。
不部署的话 frame 起来后 LoadAndRegister 找不到配置会直接自关。
验证:R230 与 Z2026 的 frame + plugins 均编译通过并部署;R230 已做上述端到端实测。
|
2026-10-29 06:33:19 +08:00 |
|
company-desktop
|
ecb8436720
|
feat: 移植 cad_mcp_plugins,并对齐中望平台的符号与依赖
插件工程在 CadProject/src/cad_mcp_plugins(8 个 cpp/h),本次一并整合进 code2026。
移植改动:
- 源码拷到 SourceCode/Code2026/cad_mcp_plugins/;cadsdk.h -> KTCad.h
- 输出是普通 DLL(.dll),由 cad_mcp_frame 运行时 LoadLibrary,不注册 ARX 命令
- 新增 cad_mcp_plugins/cmakelists.txt:按 code2026 惯例
(target_set_name_and_suffix ".dll" / target_link_objectarx / 预编译头 / SUB_ARX)
- mcp_plugin_api.h 从 cad_mcp_frame/inc 上移到 SourceCode/Code2026/inc:
frame 与 plugins 共用,且在 ShsGlobalIncludes 的 include 路径里两边都可见;
frame 的 CMake 去掉已删除的本地 inc 目录
- 顶层在同一个 C++11+ 条件里挂载 add_custom_module_2(cad_mcp_plugins CadMcpPlugins)
- 中望适配:源码里的 #pragma comment(lib,"rxapi.lib") 在中望下没有这个库(叫 ZwRx.lib),
该 pragma 与导出名都按 #ifdef ZWCAD 分开(中望导出 zcrxGetApiVersion);
frame 里 GetProcAddress 查插件版本号的函数名同样按平台分
验证:
- R230:cad_mcp_frame.arx 826 KB + cad_mcp_plugins.dll 866 KB,已自动部署
- Z2026:cad_mcp_frame.zrx 825 KB + cad_mcp_plugins.dll 864 KB,已自动部署
- 配置里 16 个 c++_dll 工具的工厂函数(CreateXxxTool)全部出现在 dll 导出表里
- 所有 .cpp/.h 为 UTF-8 with BOM
未做:没有在 CAD 里实跑。另外配置文件本身没有随构建部署(set_debug_post_build 只拷产物),
需要把 cad-mcp-frame.json(或改名 mcp_config.json)与 LISP 目录放到部署目录,
否则 frame 起来后 LoadAndRegister 失败会直接自关。详见 cad_mcp_frame-review.md。
|
2026-10-29 00:16:37 +08:00 |
|
company-desktop
|
47d7b96cad
|
perf: 给基础体构造加计时,定位到 DrawPipe/DrawCone/DrawLoft 共占 33%
继续追"剩余效率问题"。上一轮已确认 Parasolid 的 93.4% 发生在我们的视口绘制里,
本轮机位下一层:给 GiDrawUtility 的基础体构造函数加计时。
新增 inc/PerfCounterLite.h:header-only 的轻量计数器。
AecRxBase.arx 不链接 CoreLibrary(静态库只被 CoreCommand 链接),拿不到 SectionPerf
的符号,所以单独做一份;只在 Debug + AEC_PERF_COUNTER=1 时生效,Release 零开销。
统计写 %TEMP%\aec_prim_perf.txt(独立文件,避免提前写出 aec_section_perf.txt
让自动化脚本误判"开图完成")。
接入 GiDrawUtility:DrawPipe 三个重载、DrawLoft 两个重载、DrawCone、DrawCylinder。
实测(big1.dwg,93 s 开图 / 81 s CPU):
DrawPipe(region) 7201 次 13.2 s 平均 1837us 最长 130ms
DrawLoft(reg) 883 次 5.27 s 平均 5969us
DrawLoft(curve) 883 次 5.90 s 平均 6679us
DrawCone 811 次 4.64 s 平均 5717us
DrawPipe(pts)/Cylinder 2411 次 4.07 s 平均 1688us
去重后约 27 s,占 81 s CPU 的 33%。
结论(详见 perf-primitive-cost.md):
- 7201 次管道构建 vs 约 2260 个管类实体 = 3.2 次/实体,护栏/爬梯/设备细节也在造管道
- 单次成本差一个量级:圆柱 1.7ms 最便宜(已是优化过的快路径),圆锥 5.7ms、放样 6.0~6.7ms 最贵
- 长尾明显:DrawPipe 最长 130ms(平均的 70 倍),存在个别大件
- 都在"首次构建"路径上,没有重复重建,所以只能少建 / 建得更便宜 / 跨实体复用同参数几何
验证:R230 Debug 编译通过,tools/run_acad_perf.ps1 自动开图取数;
截面缓存与回写仍为正常/0(未受本次插桩影响)。
|
2026-10-28 23:32:22 +08:00 |
|
company-desktop
|
b9c4ce56f9
|
fix: cad_mcp_frame 修 P0 收包/socket 泄漏与 P1 静默失败、无鉴权
P0 收包协议(大请求被截断 + 分包即失败)
原来只 recv 一次、缓冲固定 2048 字节。改为:
- IsJsonComplete():按 {} 与 [] 配平判断报文完整性(跳过字符串内与转义字符)
- RecvOneRequest():select + 循环 recv 追加,单次等 5s、整请求 30s、上限 4MB
- SendAll():send 循环到发完(tools/list 应答可能超一个包)
不改客户端协议:客户端仍是 sendall 后等响应断开。
P0 socket 泄漏
recv<=0 的分支原来什么都不做。现在收包失败/超时回一个 JSON-RPC 错误帧并 closesocket;
accept 失败直接 continue(原代码对 INVALID_SOCKET 也调 closesocket)。
P1 监听失败不再静默
socket/WSASocket/bind/listen/CreateWindowEx/std::thread 全部检查返回值,
监听 socket 改在主线程创建,失败时 init_mcp_server() 返回 false 并打印 WSAGetLastError,
端口被占用时能看到 "Fatal: bind 127.0.0.1:8080 failed, err=10048"。
P1 端口与配置文件名可配
- server.port 可配(默认 8080)
- 配置先找 mcp_config.json,再找 cad-mcp-frame.json(此前代码只找前者,
而仓库里带的是后者,导致加载即自关)
- 启动日志打印实际端口与 token 是否启用
P1 可选 token 鉴权
配置写了 server.token 就要求请求根级带 token,不匹配返回 -32001 且不执行工具;
没配 token 保持原行为,不破坏现有客户端。
顺带 P2:close_mcp_server() 先排空挂起的 WM_MCP_EXECUTE_TASK 并 delete TaskData
(原来会漏 socket + 内存),再销毁窗口。
验证:R230 与 Z2026 Debug 均编译通过(818->826 KB,已部署)。
未做:没有在 CAD 里实际跑 tools/list 与 tools/call 验证协议改动。
|
2026-10-28 23:28:02 +08:00 |
|
company-desktop
|
0d02d33f1d
|
feat: 把 cad_mcp_frame 整合进 Code2026 的 CMake 体系
源工程在 d:\new-start\CadProject\src\cad_mcp_frame(vcpkg 独立工程),
本次按 code2026 的 preset/CMake 体系移植到 SourceCode/Code2026/cad_mcp_frame。
移植改动:
- 源码 + .def + .rc + res/ + cad-mcp-frame.json 拷入 cad_mcp_frame/;
插件接口头 mcp_plugin_api.h 放到 cad_mcp_frame/inc/
- cadsdk.h -> KTCad.h(两者除尾部 4 个 include 与 using namespace MemOper 外完全一致)
- nlohmann/json 单头放 SourceCode/dep_inc/nlohmann/json.hpp,
ghc::filesystem 单头放 SourceCode/dep_inc/ghc/filesystem.hpp;
target_link_objectarx 已把 DEP_INC_ROOT 加进 include 路径,故无需额外配置
- 新增 cad_mcp_frame/cmakelists.txt:按 PipeHangerCmd 的写法
(add_def_file_name / target_set_name_and_suffix .arx / target_link_objectarx /
target_include_directories inc / set_debug_post_build)
- 补 SUB_ARX 宏:原工程由 CadProject 的 cmake 注入,code2026 只注入 ARX;
在模块自己的 CMake 里补,不动共享 functions.cmake(中望给 0)
- 顶层挂载 add_custom_module_2(cad_mcp_frame CadMcpFrame "SH/Other"),
并加条件:nlohmann/json 与 ghc::filesystem 都需要 C++11+,
而 R180/R190 是 C++98,故只在 (IS_ZWCAD OR CAD_SDK_VERSION >= 20) 时编译
- 中望适配两处:_zrx.def 要导出 zcrxEntryPoint/zcrxGetApiVersion;
代码里显式声明的 acrxGetApiVersion() 不会被 SDK 宏改名,
改为 #ifdef ZWCAD 取 zcrxGetApiVersion()
验证:
- R230 Debug 编译通过,cad_mcp_frame.arx 818 KB,自动部署到
c:\ShangHuaSoft\Envi3D-2026-M\R230\
- Z2026 Debug 编译通过,cad_mcp_frame.zrx 818 KB,自动部署到 ...\Z2026\
- R190/R180 按条件跳过(C++98 无法编译 nlohmann/json)
- 所有 .cpp/.h 均为 UTF-8 with BOM;cmakelists.txt 保持 ASCII 无 BOM
未做:没有在 CAD 里加载实测;配置文件仍是 cad-mcp-frame.json,
而代码里找的是 mcp_config.json,加载前需要统一(详见 cad_mcp_frame-review.md);
插件工程 cad_mcp_plugins 未移植(18 个工具里 16 个依赖它)。
|
2026-10-28 23:20:07 +08:00 |
|
company-desktop
|
facf14699b
|
fix: AecDbX3dPart 记住"已尝试建过",避免 Hide 构件被反复重建
现象:开图时 X3dPart 的 EnsureCreated 命中率只有 10.1%,1914 次重建里
721 次产出 NULL(38%),单个对象最多被重建 544 次。
根因:EnsureCreated 的命中条件是 !m_bNeedCreate && m_pSolid != NULL,
而 Rebuild() 里对 Hide 构件是"故意不建几何、直接 return true"——
m_pSolid 按设计就是 NULL,于是每次访问都重新走一遍 Rebuild,永远不可能命中。
子项全为空的构件同理。
修复:
- 新增 m_bCreated 标记"已经尝试建过"(无论是否产出实体)
- EnsureCreated 命中条件改为 !m_bNeedCreate && (m_bCreated || m_pSolid != NULL)
- Rebuild 入口置 m_bCreated = true;所有设 m_bNeedCreate = true 的 setter
同时置 m_bCreated = false,保证参数变化后仍会重建
- 重建后仍无实体时打一条日志(限前 5 条,带 m_sName),方便定位是哪些构件
实测(big1.dwg / R230 Debug):
X3dPart 命中率 10.1% -> 41.4%
重建次数 1914 -> 1248(-666)
rebuild_null 721 -> 55
单对象最多重建 544 -> <=3
开图墙钟 93 s -> 93 s(无变化)
注意:这 666 次空转没有带来可测的提速,因为 Rebuild 里 Hide 的早退分支在
布尔运算之前,每次只有几微秒。所以这是正确性/整洁度修复,不是性能修复;
但消除了"个别构件被重试几百次"这种病态行为,也暴露了"哪些构件建不出实体"。
顺带新增诊断(Debug + AEC_PERF_COUNTER=1 才生效,Release 无开销):
- SectionPerf::NoteEnsure():按 tag 统计"延迟建几何"的命中/重建,
并给出对象维度直方图与重建次数最高的对象
- AecDbX3dPart::Rebuild / AcDbX3dSolid::EnsureCreated / AecDbGuardBar::Draw3d 打点
- tools/run_acad_perf.ps1 增加 -CpuTrace:用 xperf 采 CPU 采样并 merge 成 etl,
可直接喂 tools/perf_diagsession.py(VS 的 VSDiagnostics 在这台机器上会卡住,
wpr -stop 有 COM 线程模式 bug,故用 xperf)
验证:R230 Debug 编译通过并部署,自动开图取数;截面缓存与回写仍为 0/正常。
|
2026-10-28 22:51:01 +08:00 |
|
company-desktop
|
56c89c5fa4
|
diag: 拆分"写临时文件"与"acisIn"计时,判定内存读取不值得做
修完回写后开图期仍有 1733 次临时文件写入,需要判断"改内存读取"能省多少。
在 RegionAcisInDwgInFields 与 CoreTools::StringToRegion 两个重载里,把
"写临时文件+关闭"和"AcDbBody::acisIn"拆成独立计时(RegIn.write / RegIn.acisIn /
Str2Reg.write / Str2Reg.acisIn)。
实测(big1.dwg,93 s 开图,1733 次未命中):
RegIn.write 374 次 70.5 ms 189 us
RegIn.acisIn 374 次 1422.0 ms 3.80 ms
Str2Reg.write 1359 次 267.7 ms 197 us
Str2Reg.acisIn 1359 次 5999.5 ms 4.41 ms
结论:写文件合计 338 ms,只占 9.6 s 恢复耗时的 3.5%;杀软扫描已在 write 的 190 us 里
(Defender 在关闭时扫)。即使完全省掉文件往返,上限也只有 0.3~0.5 s(开图的 0.4%)。
而 AcDbBody::acisIn 在 R19~R26 只有文件名重载,真要内存解析只能改存盘格式走
acdbModelerRestoreEntityFromDwgFiler(即暂缓的 Phase 3)。因此不做。
剩余 7.4 s 是纯解析(1733 次 × 4.3 ms),只能靠减少次数;text 通道 1560 个唯一文本
是真实不同的截面,命中率已接近上限。继续提速应转向 Parasolid 绘制那条线。
数据与结论已写入 pipe-section-region-performance-plan.md。
本次只加诊断计时(Debug + AEC_PERF_COUNTER=1 才生效),不改任何业务行为。
|
2026-10-28 22:09:48 +08:00 |
|
company-desktop
|
b981fe930a
|
perf: 护栏/爬梯等构件的管道副本改为"只存参数",消除开图期 1140 次截面回写
现象:开图期间 AecDbEwPipeBase::RegionAcisoutDwgOutFields 被调用 1140 次、耗时 2.38 s,
把截面写成临时 SAT 文件。用 AEC_WRITEBACK_TRACE 抓栈 + tools/resolve_rva.ps1 解符号,
定位到 AecDbZLineStair::DrawGuarBar3d 里的 pipe.clone():
clone 走 AcDbObject → AecDbEwPipeBase::copyFrom → CopyObject(整实体 dwgOutFields/dwgInFields
往返),于是截面被写成临时文件再读回。
这些 clone 的唯一用途是存进 m_pipes,供 ToJson() 导出 __pipes__,而截面参数在
SetSection 时已经写进 spec XData(KEY_SECSHAPE / KEY_SIZE1 / KEY_SIZE2 / PIPE_THICK /
KEY_SECCEN),完全可以按参数重建。因此把"建几何"推迟到导出时:
- AecDbEwPipeBase::BuildSectionFromXData():按 XData 参数重建截面(圆形/矩形;
自定义截面返回 NULL,那种只能存在于 SAT 里)
- AecDbEwPipeBase::CloneParamsOnly():生成只带参数(XData、放样线、实体属性、GUID、
Breaks)、不含截面几何的副本,不触发任何序列化
- AecDbEwPipeBase::ToJson():GetSection() 为空时回退到 BuildSectionFromXData(),
保证 __section__ / __section2__ 仍然导出
- 30 处 m_pipes.push_back((AecDbEwPipe*)pipe.clone()) 改为 pipe.CloneParamsOnly():
ClimbStair(10)、ZLineStair(6)、BossHolder(4)、MRPLineStair(4)、Hanger(3)、Holder(3)
过程:先只改楼梯两个文件,回写从 1140 降到 960;再抓栈解析出剩余 960 全部来自
AecDbClimbStair::DrawLadderH3d,于是把其余 20 处一并改掉,最终归零。
实测(big1.dwg / AutoCAD 2020 / R230 Debug):
开图墙钟 初始 108~113 s -> 缓存后 98 s -> 本次 93 s
开图期回写 1140 次/2.38 s -> 1140 次 -> 0
RegionAcisIn 3082 次 -> 3082 次 -> 1942 次
临时文件 6773/9.34MB -> 2694/3.34MB -> 1733/2.34MB
截面恢复总耗时 22.4 s -> 9.87 s -> 9.4 s
另外把 SectionPerf::TraceCallStack 的输出改写到独立的 aec_writeback_trace.txt,
不再写进 ENVIPERFDUMP 的报告文件(否则脚本会把"栈写出来了"误判成"开图完成")。
验证:R230 Debug 编译通过并部署;用 tools/run_acad_perf.ps1 自动开图取数。
待验证:JSON 导出。m_pipes 里现在是不含几何的参数副本,ToJson 靠
BuildSectionFromXData() 重建,需要实际触发一次导出,确认 __pipes__ 里每条仍有
__section__ / __section2__ 且与改动前一致。
|
2026-10-28 21:57:31 +08:00 |
|
company-desktop
|
7038a98441
|
diag: 用 PDB 解析栈帧,定位到 AecDbEwPipeBase::copyFrom 里的多余序列化
上一版只给了"模块+RVA"的栈,我据此先后推断成
AecDbCurveBase::subGetTransformedCopy 和 AecDbEntityCommon::base_DeepClone,两者都是错的
(用户在那里下断点不命中;新加的 PerfTraceMark 打点也没有触发)。本次用符号解析定死。
本次改动:
- 新增 inc/PerfTraceMark.h:inline 的"某函数被调用过"打点,Debug 且 AEC_WRITEBACK_TRACE=1
才生效。AecRxBase.arx 不链接 CoreLibrary(静态库只被 CoreCommand 链接),拿不到 SectionPerf,
所以做成 header-only。
- 在 5 个候选入口打点:AecDbCurveBase::subGetTransformedCopy / subDeepClone、
AecDbEntityBase::subDeepClone、AecDbEntityCommon::base_DeepClone、CKTCadUtility::CloneObject。
跑一次开图,5 个都没触发 —— 这些候选被排除。
- 新增 tools/resolve_rva.ps1:用 dbghelp 的 SymLoadModuleEx / SymFromAddr 配本地 PDB,
把"模块+RVA"解析成函数名。Windows 没有自带 symbolizer,这个脚本很轻,可反复用。
解析结果(CoreCommand.arx):
0x58f051 AecDbEwPipeBase::copyFrom+0x41
0x7e1300 AecDbZLineStair::DrawGuarBar3d+0x2c0
0x7e09d0 AecDbZLineStair::DrawSteep3d+0xbe0
0x7ddcef AecDbZLineStair::Draw3d+0x34f
真实成因:Z 型楼梯画护栏(DrawGuarBar3d)时 copyFrom 一份管道实体,
而 AecDbEwPipeBase::copyFrom 用通用的 CopyObject(inc/AecDbEntityCommon.h:331)
做"整实体 dwgOutFields/dwgInFields 往返"来拷字段,于是截面被写成临时 SAT 文件再读回来。
而且这次序列化是多余的:copyFrom 随后把所有字段又用内存级方式拷了一遍
(曲线 clone/copyFrom、截面 clone/copyFrom、XData CopyFrom、m_arUserInfs append、
标志位/图层/线型/Breaks 逐项赋值),WriteUserInterface 写的也只是 m_arUserInfs。
所以最小修改是把那句 CopyObject 去掉,并补上源为 NULL 时清空目标的分支
(目前这个"清空"是 CopyObject 顺带完成的)。
本次只做定位与记录(分析写进 pipe-section-region-performance-plan.md 并纠正了上一版的误判),
不改 copyFrom 的行为——它影响所有管系实体的复制粘贴/块内拷贝,需要单独验证。
|
2026-10-28 21:28:00 +08:00 |
|
company-desktop
|
6d6f9ddaff
|
diag: 统计回写的实体类,定位到 AecDbEwPipeBase 基类实例
上一版只抓到"绘制期深拷贝"的调用栈,还没回答"是哪个类的实体在回写"。
现在 SectionPerf 增加按类统计的写回计数(NoteWriteBackClass),
在 RegionAcisoutDwgOutFields 里记一次 isA()->name()。
实测(big1.dwg,开图一次):
---- write-backs by entity class ----
1140 AecDbEwPipeBase
全部 1140 次都是 AecDbEwPipeBase 基类实例,不是 AecDbEwPipe 也不是具名子类,
与属性 key 统计里 AecDbEwPipeBase 的 1172 次几乎一一对应——
说明图纸里约有 1172 个基类实例(由 AecDbAssembleWell.cpp 的装配井代码创建,
多为矩形截面段),绘制期每个被深拷贝一次。
完整链路(已写入计划文档):
base_ViewportDraw -> AecDbCurveBase::subGetTransformedCopy
(AecRxBase/AecDbCurveBase.cpp:307 里的 clone())
-> AecDbEntityCommon::base_DeepClone(AecDbEntityCommon.cpp:1232,dwgOut 在 1265)
-> AecDbEwPipeBase::dwgOutFields(AecDbEwPipeBase.cpp:1440)
-> AecDbEwPipeBase::RegionAcisoutDwgOutFields(AecDbEwPipeBase.cpp:1275)
顺带发现:AecDbEwPipeBase::copyFrom(:1605)复制截面用的是 m_pRegion->copyFrom(),
是内存级 ACIS 拷贝,比"写文件再读回"便宜得多。所以最局部的修法可能是给管系实体
加 subGetTransformedCopy 重载,用 isA()->create()+copyFrom() 代替 clone(),
绕开整条序列化链路;但 clone 与 copyFrom 语义不完全等价,需先核对。
本次只记录分析,不改行为。
验证:R230 Debug 编译通过并部署,脚本自动开图一次得到上述分类统计。
|
2026-10-28 21:06:22 +08:00 |
|
company-desktop
|
67d6545e6c
|
diag: 增加调用栈抓取,定位开图期 1140 次截面回写的成因
现象:开图期间 EwPipe::RegionAcisout 被调用 1140 次、耗时 2.38 s,
把几何又序列化回 SAT。之前只知现象不知来源。
新增 SectionPerf::TraceCallStack():用 RtlCaptureStackBackTrace + GetModuleHandleExW
把栈帧解析成 "模块名 + RVA" 并写进报告文件。正式代码里不开启,
只在 AEC_WRITEBACK_TRACE=1 时于 RegionAcisoutDwgOutFields 首次调用处抓一次。
结论(栈已定位):
subViewportDraw -> base_ViewportDraw -> ... -> base_DeepClone
-> AcDbObject::dwgOut -> AecDbEwPipeBase::dwgOutFields -> RegionAcisout
即:不是保存,而是绘制期的深拷贝。AecDbEntityCommon::base_DeepClone
(AecRxBase/AecDbEntityCommon.cpp:1265)用
AcDbDeepCloneFiler filer; GetMe()->dwgOut(&filer); pClone->dwgIn(&filer);
实现拷贝,于是每次克隆实体,截面都要写一个临时 SAT 文件再读回来。
读的那一半现在已被 kText 缓存吃掉,剩下 acisOut 写文件这半(2.38 s)。
顺带修正一个文档缺陷:inc/SectionPerfCounter.h 里 %TEMP%\aec_section_perf.txt
的注释之前被转义吃掉变成了 %TEMP%<BEL>ec_section_perf.txt。
修法(跳过深拷贝期的区域序列化 / 直接写缓存里的 SAT 原文)都需要动
AecDbEntityCommon 的拷贝契约或先审计 m_pRegion 的写操作,风险面不一致,
只把分析与三种方案写进 pipe-section-region-performance-plan.md,本次不改行为。
验证:R230 Debug 编译通过并部署;AEC_WRITEBACK_TRACE=1 跑图一次,栈如文档所示。
|
2026-10-28 20:49:42 +08:00 |
|
company-desktop
|
f8d10d5a3b
|
perf: 增加截面 Region 缓存,开图恢复耗时降 56%
一次开图要做 5641 次截面恢复(22.4 s),其中大量内容重复,
而每次恢复都是"写临时 SAT 文件 + 从盘 acisIn + 删文件",单次 2.7~5.5 ms,
还要过一次杀软。本提交加一级母体缓存,命中直接 clone 返回。
新增 CoreLibrary/SectionRegionCache.{h,cpp},三个通道按 key 的正确性强度分开:
- kParam:纯参数 hash,用于 AecDbEwFitting::GetSection 的两个重载
(key = dD/dt/HLR 标志 或 W/H/dt/HLR 标志,同参数必同几何)
- kAttr:类名 + spec XData(排除编号,并跳过 Id/点/向量/矩阵/二进制类型),
只给 AecDbEwPipe 用。AecDbEwPipeBase 是很多类的基类,其余派生类实例间的
区别就是截面,不满足"同数据必同截面",所以一律走内容 hash
- kText:SAT 文本内容 hash,用于 RegionAcisInDwgInFields 的其它类
与 CoreTools::StringToRegion 的两个重载
约定:母体由缓存持有、永不外泄,Acquire/Put 都返回 clone,调用方拥有返回值;
母体不入库;每条通道 4096 条上限(AEC_SECTION_CACHE_MAX 可调),超出按 FIFO 淘汰;
AEC_SECTION_CACHE=0 可整体关闭做 A/B;卸载时 ClearAll() 释放,避免 DLL 析构顺序问题。
关键发现:SAT 文本第 2 行带存盘时间戳
16 Autodesk AutoCAD 19 ASM 219.0.0.5600 NT 24 Thu Oct 22 10:19:20 2026
同一几何存盘时间不同,整份文本就不同(采样里两份 2596 字节的文本只差
10:19:20 与 10:19:16),这正是内容 hash 命中率只有 54% 的原因,与截面无关。
因此新增 HashSatText():算 hash 时跳过第 2 行,仅当该行含 "Autodesk" 时才跳过。
计数器也改用同一口径,避免两套统计互相矛盾。
实测(big1.dwg / AutoCAD 2020 / R230 Debug,AEC_SECTION_CACHE 关 vs 开):
开图墙钟 108~113 s -> 98 s
截面恢复总耗时 22.4 s -> 9.87 s(-56%)
StringToRegion 14.05 s -> 7.73 s
RegionAcisIn 8.38 s -> 2.14 s
临时文件 6773 次/9.34MB -> 2875 次/3.61MB
命中率 text 65.5% / attr 84.1% / param 88.8%
clone 开销 命中 58us、未命中 73us(合计 0.37 s,可忽略)
顺带:
- tools/run_acad_perf.ps1 增加 -CacheOff 开关,用于同一构建上的 A/B 对比
- SectionPerfCounter 增加 AppendReport(),让缓存统计也写进同一份报告文件
- 诊断口子 AEC_SAT_SAMPLE=n 可导出未命中的 SAT 原文,用于定位这类差异
验证:R230 Debug 编译通过并部署;用脚本自动开图各跑一次(缓存关/开),
数据已写入 pipe-section-region-performance-plan.md。
尚未做:R190 编译(本机缺 v100 工具集)、Release 构建的收益复测、
开图期间 1140 次 RegionAcisout 回写(与本缓存无关,需单独立项)。
|
2026-10-28 20:41:05 +08:00 |
|
company-desktop
|
764e544db4
|
perf: 增加属性 key 命中率统计(Phase 0 补充)
意图:内容 hash 只看到 54% 命中率,但业务上"同数据的管子/管件截面必然相同",
所以要用实体属性做 key 再量一次,决定 Phase 1 到底用哪种缓存键。
新增 SectionPerf::AttrKey(RAII):
- 构造时按类名(isA()->name())初始化 hash 与统计桶,析构时记一次
- Add() 增量喂字节,调用方决定哪些字段参与 key
- 统计按实体类分开(total / unique / hits / hit_rate)
接入 AecDbEwPipeBase::RegionAcisInDwgInFields:key = 类名 + 全部 spec XData,
但排除编号("No.",每根管子唯一)并跳过 Id / 点 / 向量 / 矩阵 / 二进制类型
(与截面无关或随实体变化)。只在 AEC_PERF_COUNTER=1 时构建,Release 无开销。
实测(big1.dwg,AutoCAD 2020 / R230 Debug,113 s 开图):
属性 key 合计 3082 次 / 2672 命中 = 86.7%
AecDbEwPipe 1088 次 173 唯一 84.1%
AecDbEwPipeBase 1172 次 3 唯一 99.7%
(其余类 43%~99%)
内容 hash 54.0%
结论:属性 key 显著优于内容 hash,但只覆盖 3082/5641 次恢复
(另 2559 次走 CoreTools::StringToRegion,拿不到 spec 数据,只能用内容 hash)。
混合策略预计省 14.9 s / 22.6 s 恢复开销,约占 113 s 开图的 13%。
数据已写入 pipe-section-region-performance-plan.md,并标注一个未验证点:
属性 key 命中时两份 SAT 文本是否真的相同(决定 Phase 1 是否需要 textHash 兜底校验)。
验证:R230 Debug 编译通过并部署,用 tools/run_acad_perf.ps1 自动跑图取数。
|
2026-10-28 20:06:06 +08:00 |
|
company-desktop
|
3f387485fd
|
fix: 计数器改用 NDEBUG 判断构建类型(本仓库把 _DEBUG 剥掉了)
现象:Debug 构建的 R230 里 ENVIPERFDUMP 报"未知命令",计数器也永远不生效。
根因:cmakelists.txt 第 23~24 行会把 /D_DEBUG 从 CMAKE_CXX_FLAGS_DEBUG 里正则剥掉,
所以即使 --config Debug 编译,_DEBUG 也没有定义。于是 Phase 0 里用
`#if defined(_DEBUG)` 包住的命令注册和 Enabled() 判定整块被编掉——
已用二进制验证:修复前 arx 里查不到 ENVIPERFDUMP,修复后能查到(UTF-16 字符串)。
修复:改用 NDEBUG。cmakelists.txt 只对 Release 定义 NDEBUG
(`$<$<CONFIG:Release>:NDEBUG>`),所以 `#ifndef NDEBUG` 正好等价于"Debug 构建"。
- CoreLibrary/SectionPerfCounter.cpp:计数器启用条件
- CoreCommand/EarthWorm.cpp:ENVIPERFDUMP / ENVIPERFRESET 的函数定义与命令注册
验证:R230 Debug 两个 target 重新编译通过,产物已部署;
脚本自动开图后 ENVIPERFDUMP 正常输出(数据已记录到计划文档 Phase 0 实测结果)。
已知风险:`#ifdef _DEBUG` 在本仓库本来就不生效,rxdebug.cpp 等历史代码同样如此,
本次只修自己新增的两处,没有动别处。
|
2026-10-28 19:52:18 +08:00 |
|
company-desktop
|
3afc2dd7c1
|
perf: 增加截面恢复路径的 Phase 0 计数器(Debug 探针)
按 pipe-section-region-performance-plan.md 的 Phase 0 落地。目的不是提速,而是先拿到
三个决定性数字,再判断截面缓存(Phase 1)到底值不值得做:
1) 每次截面恢复多贵(µs),一次开图共多少次;
2) 同一份 SAT 文本被重复恢复多少次(唯一 hash 数 / 模拟命中率)——直接决定缓存收益上限;
3) 临时文件写入次数与字节数(杀软扫描影响面),以及打开图纸时的回写次数。
改动:
- 新增 inc/SectionPerfCounter.h + CoreLibrary/SectionPerfCounter.cpp
- Scope(QPC 计时)+ NoteRegionText(FNV-1a 64 位 hash,统计唯一数与模拟命中)
+ NoteTempFile + NoteWriteBack + Dump/Reset
- 计数器实例放在函数内 static:CoreLibrary 是静态库且只被 CoreCommand 链接,
所以 CoreCommand.arx 里只有一份,两个入口共用
- AecDbEwPipeBase.cpp:RegionAcisInDwgInFields / RegionAcisoutDwgOutFields 接入
- CoreTools.cpp:StringToRegion 两个重载 / RegionToString 接入
- EarthWorm.cpp:注册 ENVIPERFDUMP / ENVIPERFRESET(仅 Debug)
- CoreLibrary/cmakelists.txt 加一个源文件
- 计划文档的 Phase 0 补上实际命令与采集项
开关:启动 CAD 前 set AEC_PERF_COUNTER=1;命令 ENVIPERFDUMP 打印并追加到
%TEMP%\aec_section_perf.txt,ENVIPERFRESET 清零。
Release 下 Enabled() 恒为 false,调用点只剩一次 bool 判断。
不改任何几何逻辑与存盘格式。
验证:R230 Debug 编译通过(CoreLibrary_BAL_REMOTE、CoreCommand_BAL_REMOTE,无新增 warning),
产物已自动部署到 c:\ShangHuaSoft\Envi3D-2026-M\R230\。
R190 未在本机编译(缺 v100 工具集);代码刻意只用 C++98 特性,控制台输出改走 %hs,
避开了 &wstring[0] 这类老 STL 上的写法问题。
尚未做 CAD 实测:需要开图后跑 ENVIPERFDUMP 才看得到数据。
|
2026-10-28 19:31:27 +08:00 |
|
company-desktop
|
0cb05b769f
|
perf: 缓存管线系统样式查询,管线/管件加载不再反复开库
AecDbEwPipe / AecDbEwFitting 的 dwgInFields 会给缺失的样式键回填
颜色/线型/线宽/图层(PR #87 引入),走 CoreTools 的 4 个 getter;
每个 getter 都新建 CUIISQLiteServer 开一次 Plumbing.db,内部又调
getCurrentPipeSysTblName 再开一次。单实体最多 16 次 sqlite3_open,
几百个实体的图纸即几千次串行开库;绘制路径(setInfo2Ent /
setInfo2Dc)同样走这 4 个 getter。
改为:一条 SQL 取全 COLOR/LINETYPE/LINEWIDTH/LAYNAME,结果按
「表名 + 系统名 + 中心线/外边线」做进程级缓存;表名本身按
getCurrentTrade() 缓存。首次 2 次开库,之后全部内存命中。
- 只改 CoreCommand/CoreTools.cpp,对外签名不变,192 处调用点全覆盖
(CoreLibrary / PipelineCmd / PipelineSpecCmd / HvacCmd)
- 缓存只存字符串,AcDbObjectId 仍按当前图纸每次现解析,多文档切换
不串图层/线型
- 保持原语义:库打不开时 getColorByPipeSys 返回 256、getLtByPipeSys
与 getLyByPipeSys 返回空 id、getLwByPipeSys 返回 0
- 缓存生命周期等于进程,改系统样式配置需重启生效;静态对象用故意
不释放的指针持有,避免 DLL 卸载期析构顺序问题
- getPipeColorBySystem 未动:它的 SQL 不带 PIPESYS 过滤,语义与这 4
个 getter 不同,且唯一调用点已被注释
编译验证:R190 Debug 下 AecRxBase / CoreCommand_BAL_REMOTE /
CoreLibrary_BAL_REMOTE / CoreImplement 全部通过。
|
2026-10-28 10:09:24 +08:00 |
|
gjm
|
9b80db3852
|
rafactor-pipe,fitting-speedup
rafactor-pipe,fitting-speedup
|
2026-10-27 22:29:12 +08:00 |
|
home-laptop
|
683863a5b1
|
修复 AecDbXSlab 的 L1-L9 内存泄漏
- L1 GetOffsetCurve 失败分支补 FreeBuffer,不再整批泄漏 offset 曲线
- L2 CreatePipeRegion 的 booleanOper 操作数未释放,成功/失败路径均补齐
- L3 IsPointInSide 折线分支返回前未删 GetBasinShapeCurve 新建的曲线
- L4 Draw2d 圆板分支与无 KEY_ORGPT 分支中未进缓存的 pShape 泄漏
- L5 SetRegionSlab(LPCTSTR) 的 explode 碎片未释放
- L6 SetEllipseBasin 的 offset 曲线与多余截面 region 未释放
- L7 PeelBasinWall 的 explode 碎片未释放(SetBaseCurve 内部 clone)
- L8 SetProperties eXDB 分支的 pXYPoly 未释放
- L9 DrawHatch 未被 ConvertBoundCurve 接管的克隆、非 polyline 的 pCurve 泄漏
|
2026-10-27 14:10:40 +08:00 |
|
gjm
|
2db02bbef5
|
Merge pull request 'refactor-i_aecdbxequipment-copyfrom' (#84) from refactor-i_aecdbxequipment-copyfrom into main
Reviewed-on: https://git.ethereal-realm.top/gjm/envi-code/pulls/84
|
2026-10-27 13:53:21 +08:00 |
|
company-desktop
|
8e071af21f
|
refactor-i_aecdbxequipment-copyfrom
refactor-i_aecdbxequipment-copyfrom
|
2026-10-27 11:00:54 +08:00 |
|
home-laptop
|
39634dc86a
|
修复 XEquipment 参数 getter 的 M8-M10 缺陷
- M8 DEF_KEY_FUNC 返回值改为值初始化,键缺失或类型不符时不再返回栈上垃圾值
- M9 getter 内对 m_pXDataMap 判空,避免空 map 构造的 impl 直接崩溃
- M10 GetType 读取 KEY_TYPE 失败时输出日志,不再静默返回 0
- 两份 DEF_KEY_FUNC 定义(XEquipmentImpl.h 与 ParamEquImpl.h)同步修改
|
2026-10-27 10:57:20 +08:00 |
|
home-laptop
|
75819c0b72
|
修复 XEquipment 外壳/Impl 分离机制的 M1-M7 缺陷
- M1 createParamEquImpl 成功替换前释放旧 impl,消除 inplace 编辑泄漏
- M2 copyFrom2 先克隆成功再替换,避免旧 impl 泄漏或被置空
- M3 copyFrom 补基类深拷贝并兜底重建 impl,修复 clone/复制得到空壳
- M4 在 XEquipmentImplBase 注明 impl 不拥有 xdata 的所有权契约
- M5 draw3dByImp 改用临时数组,绘制失败时保留旧 3D 缓存并提示
- M6 抽出 makeTempClone(),集中 ToJson 的克隆/补数据/拷 part 流程
- M7 getUniqueName 的 %s 统一传 LPCTSTR、修正 sizeof,XL 的 %d 改 %f
|
2026-10-26 22:36:28 +08:00 |
|
gjm
|
bc6996830f
|
fix aecdbcamera.cpp 的链接错误
fix aecdbcamera.cpp 的链接错误
|
2026-10-26 21:26:40 +08:00 |
|
company-desktop
|
39dbab85bf
|
修复相机 HLR 结果处理中的三处正确性缺陷
B1 mergeEnvelope:命中 isNull() 的 3DSOLID 时 pSolidAll 已赋值但未从 arptrs 摘除,
后续 deleteArrayVoidPtrs 会把它删掉,返回野指针。改为记下标、循环结束后统一 removeAt。
B2 process_result:outputWithoutID.append(entAr) 误写在 for 循环体内,每轮把累积数组
整体再追加一次,同一指针在 outputWithoutID 中出现多次,AddToModelSpace 第二次失败后
DELETE_PTR 会删掉已入库的实体。append 移到循环外,并先 entAr.removeAll()。
B3 process_result:erase 之后把 it 重置成 begin(),for 的 ++it 会跳过新的首元素,
多个构筑物时漏处理。改为 while + 先取 next 迭代器。
同时更新 HRL-MODEL-refactor.md:去掉未实施的内存账本方案,验证方法改为行为观察。
|
2026-10-26 21:12:27 +08:00 |
|
company-desktop
|
14f7203f3b
|
修复相机 HLR 计算链路上的几处内存泄漏
- hlrCalc 两处早退(HLR 结果为空、截面裁剪后为空)没有释放补充实体
arAdditional_all,补上释放;第一处早退发生在轴网克隆插入 result1 之前,
同时释放调用方移交所有权的 arAxisPtrs
- mergeEnvelope 找不到可用的 3DSOLID 时直接返回,漏掉 arptrs 里由
GetDraw3dables 克隆出来的全部实体
- process_result 打成块失败时,subAr 里的实体没有被块表接管,需要自行释放
|
2026-10-26 20:07:37 +08:00 |
|
company-desktop
|
e555d29529
|
fix-aecdbcamera-崩溃导致双击无法退出
fix-aecdbcamera-崩溃导致双击无法退出
|
2026-10-26 14:04:38 +08:00 |
|
gjm
|
86bb3b778a
|
优化 transfromRegion:旋转与平移合成一次 region 变换(E3)
原来对 AcDbRegion 连做两次 transformBy(先转到平面、再平移),
region 是 ACIS body,每次变换都要重建拓扑,而该函数在
DrawPipe(pCurve, pRegion, ptCenInRgn) 里每个管件都会调用。
改为先算出 ptOnRegion 变换后的落点,把平移量用 preMultBy 合成进
同一个矩阵,region 只做一次 ACIS 变换;顺带删掉 plan.get(pt0,pt1,pt2)
这三个未使用的局部变量。
|
2026-10-25 19:16:43 +08:00 |
|
gjm
|
74730f2c91
|
修复 GiDrawUtility 参数校验与规范问题 B7、B9、S1
- B7: DrawPipe(pCurve, dR) 检查 getStartPoint 返回值,避免未定义点传给 getFirstDeriv。
- B9: 补充参数校验:
DrawDish 大直径为 0 时 2*dH/dD 除零;
DrawCirTorus / DrawRectTorus 小半径不小于大半径时截面半径为负(RectTorus 另校验高度);
DrawPipe(ptFrom, ptTo, ...) 零长度路径无法扫掠;
DrawPipe(pCurve, dR) 半径非正。
- S1: spliteCurve、deleteContainerOfArx 由文件级 static 移入已有的匿名 namespace。
|
2026-10-25 19:07:16 +08:00 |
|
gjm
|
14d3ff43c9
|
修复 GiDrawUtility 逻辑缺陷 L7、B2-B5
- L7: 新增 TakeFirstRegion,createFromCurves 返回多个 region 时只取第一个并释放其余,
createRegion(AcDbEntity*)、DrawDish、DrawPipe(curve,dR) 三处统一走此路径;
DrawDish 同时在 DrawRevolve 失败时释放 region。
- B2: RotateAndMove 的零向量防护原为 "*= 1" 空操作,改为显式判零并退化为 Z 轴。
- B3: DrawTydf 的 tfdy 分支截面各自平移后未更新引导线,改为重设端点到变换后的截面中心。
- B4: DrawMesh 增加入参校验(pVertexList 非空、rows>=2、columns>=3),避免越界读与空截面。
- B5: DrawRevolve 建 region 失败时不再往模型空间塞红色曲线,改为直接释放克隆对象。
|
2026-10-25 18:46:19 +08:00 |
|
gjm
|
938edc0204
|
修复 RotateAndMove 平移项缺失旋转分量导致落点错位
平移量应为 ptDist - R*ptOrig,原实现写成 ptDist - ptOrig,
仅在 ptOrig 位于旋转轴上(含原点)时才成立。
DrawTydf 台体分支传入的 ptBottom 非原点,vtMove 倾斜时
实体整体偏移 |R*ptOrig - ptOrig|,本次一并修正。
|
2026-10-25 18:35:41 +08:00 |
|
gjm
|
4de7c883a6
|
fix: 修复 GiDrawUtility 失败路径内存泄漏(L3-L6)
- L3: DrawLoft(曲线版) createRegion 失败时清理三个 clone 及已成功的 region
- L4: DrawBox/DrawSphere 创建失败时释放 pSolid
- L5: DrawMesh loft 失败时释放 pSection 数组与 vecPLs 中各 polyline
- L6: DrawPipe(曲线,半径) ARX 扫掠分支补 DELETE_PTR(pReg),与 ZWCAD/extrude 分支对齐
|
2026-10-25 18:05:51 +08:00 |
|
gjm
|
7c9d849348
|
fix: 修复 GiDrawUtility::DrawPipe 每次画管泄漏 region
- 删除重复调用且丢弃结果的 createRegion(L1:每次调用必漏一个 AcDbRegion)
- 内圆 region 创建失败时释放 pBig(L2a)
- booleanOper 成功后释放第二个操作数 pSml(L2b,与 AecDbEwPipeBase/AecDbEwFitting 惯例一致)
|
2026-10-25 17:59:42 +08:00 |
|
company-desktop
|
e448dbacfd
|
fix: GetInterface 数组版 bSizeUnLock 被 memset 清成 false
inf.bSizeUnLock = true 原来写在循环外,循环内每次都 memset(&inf, 0, ...),
赋值被清掉,数组版返回的接口实际一直是"锁定"状态。
把赋值挪到 memset 之后;循环外那两行初始化(bSizeUnLock / dGasket)删掉,
memset 之后本来就是 0。
bSizeUnLock 目前只在 i_AecDbXEquipment.cpp 里序列化,没有读取判断的地方,
所以此前没暴露成故障。
|
2026-10-25 12:10:09 +08:00 |
|
company-desktop
|
d1f4d0b50b
|
fix: GetInterface 数组版补 dUnit,与下标版统一单位
AecDbEwEquipment::GetInterface(AcArray<AecInterface>&) 里 ptPos 已经
transformBy(xform) 缩放过(米制 0.001),但 dSize1 / dSize2 直接取
pNoze->dVal1,没有乘 dUnit;下标版 GetInterface(int, ...) 是乘了的。
结果同一个接口经两个入口读出来尺寸差 1000 倍,出现"位置按米、尺寸按毫米"。
补 * dUnit。dV / dA 是电压电流(EarThwormDef.h:518),不是长度,不参与换算。
影响面:
- 数组版的 4 处内部调用(getOsnapPoints、subErase、DrawInfArrow、vtAdjust)
只用 ptPos / vtDir,不受影响
- 外部消费 dSize1 的是 CoreCommand/pcf.cpp:1044 的 pcf_ewEquipment,
米制图纸导出的 PCF 管径此前大了 1000 倍
- 毫米图纸 dUnit 为 1,行为不变
文档同步:3.7 补结论与影响面,3.12 标记确认不改,5.1 加第 16 项,
5.4 三项按结论更新。
|
2026-10-25 11:58:00 +08:00 |
|
gjm
|
a72b38c4e5
|
Merge pull request 'fix 修正自定义设备拖拽时的效率问题' (#53) from home-lenovo-legion-r9000/修正自定义设备拖拽效率 into main
Reviewed-on: https://git.ethereal-realm.top/gjm/envi-code/pulls/53
Reviewed-by: gjm <littleoldpan@163.com>
|
2026-10-25 11:43:22 +08:00 |
|