refactor(layout): src/ 收成顶层包 arm/,入口统一 python -m;提升承担构建的 scratch 脚本
单文件约束取消后,Python 侧没必要再靠 16 处 sys.path.insert 维持扁平模块互认。
现在按职责分包:
arm/paths.py 路径唯一来源(含新增 CACHE、TPL)
arm/constants.py 实测接口数值(原 armcore 的 M/C/CLR/FIT/MOTOR_TOL 段)
arm/cad/{helpers,arm_build,part_tools,parts/} 几何与装配
arm/kinematics.py(原 human_layout.py,唯一运动学事实源)
arm/analysis/{sweep_v2,strength_check,torque_balance,finalize_travel,ws_sweep,gen_env_mesh}
arm/dataio/{screw_mesh,draw_sheet} arm/viewer/{build_viewer,shot}
arm/build_model.py(原 arm_model.py)
顺带修掉的既有缺陷(都是实测撞出来的,不是预防性改动):
- arm_model 第二次 sys.path 跳到 gitignore 的 scratch/ 去 import 构建必需的包络脚本:
ws_sweep/gen_env_mesh 提升进 arm/analysis/,缓存挪到 data/cache/(gitignore,可重生成)。
- finalize_travel / draw_sheet 顶层就是"算完写文件",一次 importlib 冒烟测试就把
docs/travel.json 重写了一遍;现在被 import 直接抛错。
- strength_check 用 OUT.replace("/out","/web") 靠字符串形状推路径,改成直接用 WEB。
- build_viewer 里 WORKSPACE 使用点漏改导致 NameError —— 已由构建关卡抓到并修掉。
os._exit 的处置与计划里的假设相反:实测光是 `python -c "import arm.cad.helpers"`
就会在解释器退出时段错误(exit 139,OCC 静态析构),全流程跑完也一样。所以入口
脚本尾部保留 flush + os._exit,并把原因写进注释;被 import 时不生效。
关卡(tests/):
- verify.py 一条命令跑三层:产物 md5、IK 数值 exact 段、截图。
- 截图基线重做并分级:同一构建连跑两轮实测 102 张逐字节可复现(要求 md5 相同),
3 张线束 x-ray 不可复现(mean<=0.0017、无像素差>8)改为与参考像素比容差;
这 3 张不再入库,免得每次跑关卡都脏 git。
- 新增 ?view=sheet / ?sheet=N / ?theme / ?guide=N 四个 URL 参数:工程图与装配向导
占了约一半 CSS 和 700 行 JS,原先没有任何截图覆盖,拆它们等于没有关卡。
- 关卡灵敏度已验:改坏 IK 基线一个数 -> FAIL;换旧版求解器 -> 5 处 exact 差异。
实测:python -m arm.build_model 退出码 0,全部产物 md5 与基线一致,
105 视图截图全过,IK exact 段逐字节一致。
This commit is contained in:
@@ -0,0 +1,4 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""核验脚本与基线。跑法:从仓根 `python -m tests.test_harness_collision`
|
||||
(`-m` 把仓根放进 sys.path,脚本因此能 import arm.*;直接 python tests/xxx.py 会找不到包)。
|
||||
"""
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 294 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 363 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 296 KiB |
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"note": "实测同一构建两轮:mean<=0.00174, 单像素最大差 12, 无像素差>8。阈值取约 10x 余量;超过即视为真实渲染回归。",
|
||||
"mean_max": 0.02,
|
||||
"pixel_max": 32,
|
||||
"views": {
|
||||
"harness_xray_internal": {
|
||||
"mean": 0.00087,
|
||||
"mx": 6
|
||||
},
|
||||
"harness_p07_xray": {
|
||||
"mean": 0.00097,
|
||||
"mx": 5
|
||||
},
|
||||
"harness_p04_p05_xray": {
|
||||
"mean": 0.00174,
|
||||
"mx": 12
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,228 +0,0 @@
|
||||
af5c9d74bddf7d795bd38f4371fa61ec *docs/shots/01_iso.png
|
||||
c315879cfd09f35efa4ca4ecc1564b65 *docs/shots/02_front.png
|
||||
b3157f4453cf96b930f065e134a2d18b *docs/shots/03_side.png
|
||||
068fc4bc3eec481ff7d7b1d4da2aad88 *docs/shots/04_top.png
|
||||
fbb95ea7a9229195d80c6f487021ae2b *docs/shots/05_exploded.png
|
||||
cbea750a1b52c5e8d061a9e3f4c981fe *docs/shots/06_wrist.png
|
||||
bb3dc393e4cd8f2c399c343aba0b3d35 *docs/shots/07_joint.png
|
||||
72e86ae7743ff7416e247d19556dc657 *docs/shots/08_pose.png
|
||||
af5c9d74bddf7d795bd38f4371fa61ec *docs/shots/09_sheet.png
|
||||
af5c9d74bddf7d795bd38f4371fa61ec *docs/shots/10_solid.png
|
||||
e97dcf60224e2ad968bddf02ea680e57 *docs/shots/11_grip_open.png
|
||||
8daa2255af050a225609cebbc490d3b9 *docs/shots/11_tool_flange.png
|
||||
002a1f4a2b65744515f5b54364fcc2a8 *docs/shots/12_elbow_flare.png
|
||||
b2f1454a6009a8b44ddd41be9efdaff5 *docs/shots/13_forearm_side.png
|
||||
053a9be5edad6b577bbe902c428aa135 *docs/shots/H2_前后圆角_34.png
|
||||
6d6feec7d65ea08e1175013fa3691869 *docs/shots/H2_前后圆角_侧视.png
|
||||
f17fd52c9f2eee907da3c76a80cd8073 *docs/shots/H2_前后圆角_正面.png
|
||||
9519d95093d835f72dfc008c4febc1a3 *docs/shots/H_正式_34视角.png
|
||||
cf61473cd470b5111b678f2fa01f8bcc *docs/shots/H_正式_侧视.png
|
||||
2385a6f605834163eb821a56cfa5be6a *docs/shots/H_正式_整机.png
|
||||
001e85eca69fc3f1503d41b0a7366706 *docs/shots/P04_H落地_复核.png
|
||||
351e5b573126d75bc5baf01b55199e5b *docs/shots/P04_前后圆角_复核.png
|
||||
bac1bfb89650c343b33b680c410259e9 *docs/shots/P04_前脸轮廓_改前改后对比.png
|
||||
f54e549cd743495e78e45744f3283d47 *docs/shots/P04_尖角_改后.png
|
||||
3b906449664648c1555e9aadeff83bca *docs/shots/P04_顶部_改前.png
|
||||
ff4ab3362882cb99895c94801896afe7 *docs/shots/P04_顶部_改后.png
|
||||
ae0c77ebf8a51a2541cfb903bd34f86c *docs/shots/P05_斜棱R3圆角_实施完成对比.png
|
||||
aa18505c1201d1490584ced82d16f465 *docs/shots/P05_斜棱圆角_评估对比.png
|
||||
60a8a174ce455f0539503ac1aa3d58f0 *docs/shots/P07_立柱底端圆角_对比.png
|
||||
baf85ba3b5c37d6ffb9c0deb6b8eb7d0 *docs/shots/arm_overview_notch_exact.png
|
||||
07ec81c2fcef975b2b53577f00f5176c *docs/shots/bay_inner_wall.png
|
||||
e39999d2ef28536f24d7f6178fa9a15c *docs/shots/bay_p04_inside.png
|
||||
959e4bf08e174d90a1fe03a75a042070 *docs/shots/bay_p06_inside.png
|
||||
f9d8d58365b4ca693525af5540d39d32 *docs/shots/bay_p07_inside.png
|
||||
1b07f37e5fed9d82886b9518a3839860 *docs/shots/bay_p08_inside.png
|
||||
d8955c69a48a064dc395c7c18b9db49c *docs/shots/bay_section_polar.png
|
||||
90b79bb61cacea2323ca19790d4158b2 *docs/shots/boss_p04.png
|
||||
dcc54259caf06f796e3dec84496abb12 *docs/shots/boss_p05.png
|
||||
9f2c134297f2c7a555a6eaca2e74e4de *docs/shots/boss_p06.png
|
||||
b789564315ca1ad7d6d9d18c96972cba *docs/shots/boss_p07.png
|
||||
8fdee57313c9ea826dcd881d9c4655c8 *docs/shots/compare_harn_off.png
|
||||
b8b89700a7a6a38b80aa1ef0d8966195 *docs/shots/compare_harn_on.png
|
||||
1d0cccff978809bb5e1f357d0f45a28a *docs/shots/crop_circle_detail.png
|
||||
43857f773d225ed4c6425c27f93afc2c *docs/shots/crop_p04_bottom.png
|
||||
9b2f02d28cc0f40c913ca13daad4c4f4 *docs/shots/crop_p04_bottom2.png
|
||||
baa4492159c3e4d7eab0a45f1965e640 *docs/shots/crop_p04_bottom_v2.png
|
||||
f00fbb4fad4c0127cb403d28f91ed557 *docs/shots/crop_p04_side.png
|
||||
5214b01e26e27d8033c54122c215b77b *docs/shots/crop_p04_side_v2.png
|
||||
10a610706648c4d3e2dac056eaef6f6d *docs/shots/crop_side_p05.png
|
||||
7c6c053e0875a0dda616fde588985bd3 *docs/shots/crop_side_p08.png
|
||||
8bbdcba793f44ccaf9df47a8ac316c60 *docs/shots/crop_user_circle_p05.png
|
||||
3259a8c112f1d351a1fed11973a02c95 *docs/shots/crop_user_circle_p08.png
|
||||
a618bec8aa67bb2cc743e923207df914 *docs/shots/crop_user_creases.png
|
||||
5994293cc45e59afdb907c52e4e2dd01 *docs/shots/crop_user_creases_fixed.png
|
||||
1f3b3d68bbcf563ba50f79ab74494117 *docs/shots/crop_user_feedback.png
|
||||
5768c8a960267428b10362662d78fd4e *docs/shots/crop_user_p06_yz_fixed.png
|
||||
c2b2873686ec704024bdbb178f8d19f4 *docs/shots/fence_all_sections.png
|
||||
efcb304e1e6d17f93e8fb0802ed429ac *docs/shots/fence_j2_after.png
|
||||
5a907286d59d7f0584bf0a86cee50e01 *docs/shots/fence_j4_after.png
|
||||
5a0556bda22250c7f633df0db6603154 *docs/shots/fence_j5_after.png
|
||||
dd21d8f29d1a0267866b898c75ae6d4f *docs/shots/fence_j6_after.png
|
||||
3123606bf71f402a9714aad63aa7f179 *docs/shots/full_arm_compare.png
|
||||
93893ff628702b83137e27fdcf751f60 *docs/shots/harness_3d_viewer.png
|
||||
af5c9d74bddf7d795bd38f4371fa61ec *docs/shots/harness_full_iso.png
|
||||
2c8ecd1eee5204b6cf6c4af3b3c5f62e *docs/shots/harness_full_view.png
|
||||
b8b89700a7a6a38b80aa1ef0d8966195 *docs/shots/harness_inner_front.png
|
||||
4087f9fa75d2ef805457b1e32689785d *docs/shots/harness_inner_side.png
|
||||
ae26c478855955748222592591ee6a03 *docs/shots/harness_notch_fixed.png
|
||||
8896124b0c45d9796e983f026134cff6 *docs/shots/harness_overview.png
|
||||
7a40f9f434e51299deb7ab9a59f8fc81 *docs/shots/harness_overview_xray.png
|
||||
7cbf2c699501bff3c7ebb4beb7cd34e2 *docs/shots/harness_p04_p05.png
|
||||
7b7335a79480d04dc3862f51a6377396 *docs/shots/harness_p04_p05_xray.png
|
||||
687e2184dd3e149939ce6d4214ffc698 *docs/shots/harness_p06_window.png
|
||||
9fca41ada43f36a338cce31797152c3c *docs/shots/harness_p07_window.png
|
||||
c8a688690b418e68993d06e7b60e2c05 *docs/shots/harness_p07_xray.png
|
||||
b8b89700a7a6a38b80aa1ef0d8966195 *docs/shots/harness_toggled_off.png
|
||||
84fb87bb5ce6cef73866401642ab0f9d *docs/shots/harness_xray_full.png
|
||||
7d07f7728a5cb0bbb71c787e2b44aeb1 *docs/shots/harness_xray_internal.png
|
||||
152a3bbf2ebd3531fbde77a1c201c9a0 *docs/shots/harness_xray_motor.png
|
||||
54d1ba097fdf4213811c1360204fa677 *docs/shots/harness_zoom_elbow.png
|
||||
09c5d9d5c507a182d4dea5e4cfa238dc *docs/shots/harness_zoom_shoulder.png
|
||||
7fe0cb0d52c1f7d97bf1c8fd47b22e0c *docs/shots/hollow_p04_iso.png
|
||||
c55a40d4bc4b4e73a672326fa02d573c *docs/shots/hollow_p04_top.png
|
||||
8379d580ff746c859587e29e34700d7c *docs/shots/hollow_p06_iso.png
|
||||
1464e622ec8090b6052ab82f7bcd6b22 *docs/shots/hollow_p07_iso.png
|
||||
f3b85ea576a6aa99a61953c4ff2a5ff4 *docs/shots/hollow_p07_top.png
|
||||
e169359e86a61f7ab80d4adea0231436 *docs/shots/j3_前端压盖_全件.png
|
||||
83325d3ca1b9e56fd2c70661052fd063 *docs/shots/j3_前端压盖_装配.png
|
||||
8766806e981e84aaafd880af49e6bb0f *docs/shots/j4_neg80_view.png
|
||||
7797c4490780e1d164a7784fc062ba32 *docs/shots/j4_pos80_view.png
|
||||
26f3fd913018e16e99af2edd861342b8 *docs/shots/j4_side_neg80.png
|
||||
9f411a6efadfa2fd38aa929beaaed0f0 *docs/shots/j4_side_pos80.png
|
||||
cfd861e3c300b6b91f84f40bb9753d51 *docs/shots/lingxi_6DUUEF.png
|
||||
82e86303cb609fa371600c0fb5f9b85a *docs/shots/lingxi_6DUUEG.png
|
||||
e6616300fa1a80f4316673f733b43167 *docs/shots/lingxi_6DUUEJ.png
|
||||
515d312c6cf3d2b420d19eda7a380fbe *docs/shots/m2_front_notch_exact.png
|
||||
f7ad1083e20c91ef1dcf2eeb37e0f908 *docs/shots/m2_front_view.png
|
||||
c84927682b860cfe7d9c2ec2ffc21305 *docs/shots/m2_iso_notch_exact.png
|
||||
9bb20af2e14c64203e814423e65efc75 *docs/shots/m2_notch_zoom.png
|
||||
369479ad05476793ce824fa6a58bca98 *docs/shots/m2_side_view.png
|
||||
38536cef76f4e29825705a5d3bf8bfbc *docs/shots/m3_front_assembled_after.png
|
||||
1c221106e26cdf4d85dd6d432483704f *docs/shots/m3_front_iso_after.png
|
||||
a9182da4a194b3316ba710e5e22b4299 *docs/shots/m3_front_nomotor_after.png
|
||||
88eadfa42ec551a96b52a58468bbe5ac *docs/shots/m3_front_open_after.png
|
||||
e8acef55ca4305e09dbda01de7d8af51 *docs/shots/m3_front_side_after.png
|
||||
c22cef65ca2a74b1332ecaba6b9a484a *docs/shots/p03_light_iso.png
|
||||
ebdeb9a180e95afd38f5a42d12743579 *docs/shots/p03_light_join.png
|
||||
5671bcc5a150d4899d186abd3658ef99 *docs/shots/p03_light_rear.png
|
||||
2a9e076fa310b0c78b1a0e8375e8aae8 *docs/shots/p03_light_side.png
|
||||
0aa155c87743426668114d876478582c *docs/shots/p03_light_xray.png
|
||||
d0c82d07ab6055c1b67c03c126fe267a *docs/shots/p03_mount_iso.png
|
||||
21db2e9ca69192cce0be4467b4701028 *docs/shots/p03_mount_loose.png
|
||||
78f62639acb79e30fa88cc5fda87cfea *docs/shots/p03_mount_top.png
|
||||
ae0305c092707e0c73944e1d889d076a *docs/shots/p04_both_ends.png
|
||||
f241acda8fdae460eb38f5a054e841f9 *docs/shots/p04_m2_side.png
|
||||
f9a0e5fda588e5345e32d112c3dbc116 *docs/shots/p04_top_after.png
|
||||
2b07a995cfadea3396cbf1b9bcdbe3fb *docs/shots/p04_top_iso.png
|
||||
8191b972269eab6e51b40b5771e7d3d5 *docs/shots/p05_after_groove_removed.png
|
||||
fcbf993fb18f6e7007cb66fea153cdf2 *docs/shots/p05_corner_zoom.png
|
||||
3d261042388c8b2924848d8a29f71931 *docs/shots/p05_flank_view.png
|
||||
c7bbe31a5e94574fbaaf495622f999ff *docs/shots/p05_focus.png
|
||||
9fcdb197a69d94949660b42032db1fda *docs/shots/p05_inner_corner_1.png
|
||||
665709a81624ee17b8565df8ed1947da *docs/shots/p05_inner_corner_2.png
|
||||
597ffa69b9817823c1958822482ae9d1 *docs/shots/p05_inner_corner_side.png
|
||||
2efeeb47868cb57fab926aebe980bd5b *docs/shots/p05_iso_clean.png
|
||||
9e930e7d033b8b4dfe8a486feb9b8eff *docs/shots/p05_iso_target.png
|
||||
515b204e42d75d98afe0600f8b8b419d *docs/shots/p05_m3_side.png
|
||||
bfe508bc1f44430bb3a6d43811962226 *docs/shots/p05_side.png
|
||||
0e6931d83143d767ba37fa76d12aeb41 *docs/shots/p05_side_target.png
|
||||
38794de6a818f31efade797afff934f3 *docs/shots/p05_zoom_v3.png
|
||||
3b82ff785a29a5b1a4233404f62e3106 *docs/shots/p06_iso_v3.png
|
||||
bc99a68fa6ebcc21c173188a13805834 *docs/shots/p06_iso_v4.png
|
||||
4c6014a754e233411f6e89e4112d6cde *docs/shots/p06_m4_side.png
|
||||
cf5939f305762bd064cdfae373c130d4 *docs/shots/p07_fillet_zoom.png
|
||||
aa3cb2e1e7bff6e3ca4af66bd6c70854 *docs/shots/p07_m5_side.png
|
||||
c6a061335ea757064ecf51195b89f808 *docs/shots/preview_p06_closeup.png
|
||||
c712e7385b2094bc349d06f3ff1973eb *docs/shots/preview_p06_front.png
|
||||
966427d5bba294035b3e6f15b0984e60 *docs/shots/preview_p06_iso.png
|
||||
16e9638ec903aef101594f6cd0224a40 *docs/shots/preview_p06_yz_side.png
|
||||
7635f1d057b06f014c1683261a7237b8 *docs/shots/shot_p08_user.png
|
||||
20b4517e84e161abce960994380a92c6 *docs/shots/shot_service_loop_bent.png
|
||||
468704c6678e540f54d3165768713991 *docs/shots/shot_service_loop_zero.png
|
||||
d6fba250cab75489c4ccd44b245ce02d *docs/shots/shot_service_loop_zoom.png
|
||||
977bb781966f2b94894a2fb99cc4ed69 *docs/shots/side_full_arm.png
|
||||
cd787443c8c8c4be47d24f3e4c0b0e33 *docs/shots/side_full_arm_v4.png
|
||||
5de5466396a959ce13f494da0d50298d *docs/shots/side_v3.png
|
||||
aed480014d24fcd45bc3eafd30b0376c *docs/shots/side_zoom_p05.png
|
||||
aed480014d24fcd45bc3eafd30b0376c *docs/shots/side_zoom_p05_v4.png
|
||||
4e3374649995691b3556f3c86fca5904 *docs/shots/side_zoom_p08.png
|
||||
4e3374649995691b3556f3c86fca5904 *docs/shots/side_zoom_p08_v4.png
|
||||
f1e5bd79e6921b39d0785e4208ef5cca *docs/shots/svg_exploded.png
|
||||
57ac93ac3d2be849772d51ba8300a989 *docs/shots/svg_front.png
|
||||
eadcf7d6ac9853950496a559dbd8de72 *docs/shots/svg_joint.png
|
||||
4a9a34e534496cb2c3be499ea2029d87 *docs/shots/svg_side.png
|
||||
2c8ecd1eee5204b6cf6c4af3b3c5f62e *docs/shots/test.png
|
||||
9324b57f4bfb601a6cd6606f74c0c856 *docs/shots/test_p05_fillet_after.png
|
||||
9e0c65c8e53adab6305cc1b03dd3c038 *docs/shots/test_p05_view.png
|
||||
a9b48aa3507d451d8e9159699cfeb6be *docs/shots/test_side_0.png
|
||||
96a62a6d55b26a30a5001952a8541ed8 *docs/shots/test_side_neg_y.png
|
||||
7458cdfb12232a2566142ddc6bb76424 *docs/shots/test_side_pi.png
|
||||
96635ca94ec00783d84c9a3f54fb91c0 *docs/shots/test_side_pos_y.png
|
||||
4434ed29679c4fdba76782b40d71c925 *docs/shots/test_side_x_neg.png
|
||||
02a5cd63659b58b6c4f64782ca9f61e4 *docs/shots/test_side_x_pos.png
|
||||
67a351369c1bb2e1491eb2dadc5efc00 *docs/shots/test_target_corner.png
|
||||
b7aeadaf3603105f3a47780490ad0342 *docs/shots/test_user_view.png
|
||||
d3bf901601ff221ecd1b09dc93dd2ccc *docs/shots/tie_after_close.png
|
||||
7c2be3a8488997de588e3760f966fd7d *docs/shots/tie_after_negY.png
|
||||
0b3e26c6e2fd664f91764d26b8b1ed0c *docs/shots/tie_after_oblique.png
|
||||
c39cee9deabedb4dc8fad8ec76b439e5 *docs/shots/tie_after_p0607.png
|
||||
b51a4e5424297c9012cc0562bbeec296 *docs/shots/tie_after_p0607_obl.png
|
||||
70772a99b8c5d81619127eed7bc1dab5 *docs/shots/tie_probe_negY.png
|
||||
a3bf9bd7fb796283bbb9767cc790167a *docs/shots/tie_probe_posY.png
|
||||
1e1d29129833b35e43b925b25eae4b8f *docs/shots/user_circle_check.png
|
||||
309cc9ac3238e747104e6ceee7bd68bc *docs/shots/user_compare_view.png
|
||||
d25a25539d00674d608dca7234e331e0 *docs/shots/user_contour_harness.png
|
||||
3ed51a9cbad23f7c9c7eb79ac5471eb1 *docs/shots/user_elbow_front.png
|
||||
85d13ea862263aa055924df2beca98fb *docs/shots/user_elbow_rear.png
|
||||
9c2bc97ed4ca490e624695c5e4086f8c *docs/shots/user_exact_clean.png
|
||||
6e1c039c236d28a4bec7e7b589fb2ed3 *docs/shots/user_exact_view.png
|
||||
6a86499dd36b2a0a1ac50ae28ea138e4 *docs/shots/user_fork_fixed.png
|
||||
527d30d68065fd9e59020f8234998c61 *docs/shots/user_harness_full.png
|
||||
d35c720c416b645b0560296f1062d878 *docs/shots/user_harness_notches.png
|
||||
1389d052730b4bb09eb0a17cf9c49354 *docs/shots/user_harness_view.png
|
||||
eebfbfbea1375770fbc333f83f64e959 *docs/shots/user_harness_zoom.png
|
||||
ffe701c93ce7984d125cff99a10ed319 *docs/shots/user_iso_after.png
|
||||
d3234ff06df60213391dab75589d65ab *docs/shots/user_m1_bypass_oblique.png
|
||||
99188cb1c040a2c6494322a9845ac6cb *docs/shots/user_m1_exact.png
|
||||
606e209a6d3dc64ee3a59d1fc22339f3 *docs/shots/user_m1_rear.png
|
||||
d34d5d15434bc5a980e34e5511cc49a4 *docs/shots/user_p04.png
|
||||
51d318f3584444ea78f2078d9ef3eddd *docs/shots/user_p04_bottom.png
|
||||
b31cd81ca26198896378bc38c4393b9d *docs/shots/user_p04_bottom2.png
|
||||
22ace55c6f60a6322f770b2b0a0a504c *docs/shots/user_p04_iso.png
|
||||
6ea6b98ad978b993868bd302ad1dd8c6 *docs/shots/user_p04_opp.png
|
||||
2c7f53c7bed7d25175948f09960ed634 *docs/shots/user_p04_side.png
|
||||
20e8583cae4d1705bcecdb750ac90b3b *docs/shots/user_p06_fixed.png
|
||||
2b1117068f7dc20cb24054cfea6d3453 *docs/shots/user_p06_front.png
|
||||
fe0b30e16a673beb200224a0e6607faa *docs/shots/user_p06_iso.png
|
||||
291d238a586ded723221e2f9ed49e7e3 *docs/shots/user_p06_j4_pitch_neg.png
|
||||
4798f251b423398acb0975ecdff88aa6 *docs/shots/user_p06_j4_pitch_pos.png
|
||||
5326a55ce2be7e15e78272cbdf5c6574 *docs/shots/user_p06_p07_match.png
|
||||
c8448c391e21b12831c09e82fab9da24 *docs/shots/user_p06_side.png
|
||||
729025864df7708c900e110ec175f0da *docs/shots/user_p06_xz.png
|
||||
095da56acdc9b512709786df26691481 *docs/shots/user_p06_yz.png
|
||||
152eb1db302b62238f3051b1f48fcf45 *docs/shots/user_p07_check.png
|
||||
abf7113f27b6443541e3a0859d77b3fe *docs/shots/user_p07_creases.png
|
||||
a17303b12669be77a97dc18f2463c809 *docs/shots/user_p07_wrist.png
|
||||
a60f07bb05bba7a58bdd29e5202c478f *docs/shots/user_shoulder_solid.png
|
||||
86aab5a8eb32216b4f712c730cc67068 *docs/shots/user_shoulder_top.png
|
||||
a60f07bb05bba7a58bdd29e5202c478f *docs/shots/user_shoulder_xray.png
|
||||
227a85ecdb2fd21b1d042f84bf3aa94c *docs/shots/user_side_full_v5.png
|
||||
02cfa0aa5681fec061f73b9d69fef41c *docs/shots/user_smooth_harness.png
|
||||
87a8889ba4031cdf2e378fca7e1b475c *docs/shots/user_target.png
|
||||
22f62024f51ee1827f662d8754019f57 *docs/shots/user_view1.png
|
||||
e96c715833f9321b9fd1501bc4bdf87a *docs/shots/user_view2.png
|
||||
8513509bd468d4253fff41a769fba112 *docs/shots/user_view_after.png
|
||||
f800bcb2c675c540da91ea4128626558 *docs/shots/verify_front.png
|
||||
04dcb70b0420dd9b626970e84c6c6009 *docs/shots/verify_front_no_p04.png
|
||||
f800bcb2c675c540da91ea4128626558 *docs/shots/verify_front_xray.png
|
||||
6d08599e6af8098899be6f4e04cd587f *docs/shots/verify_rear.png
|
||||
467521f6aed235e4b7e018291d7a9273 *docs/shots/view_a.png
|
||||
400e33d3f92bdc5d35030bc0560793f2 *docs/shots/view_b.png
|
||||
2e70d37bc8bfe39ec1f55956b8c90c31 *docs/shots/view_c.png
|
||||
9ac5686881ce53db4220af7599bae200 *docs/shots/view_d.png
|
||||
64a199b2c65e7f2d0ad5e2a80c5caef8 *docs/shots/view_iso_forearm.png
|
||||
22ae02822c50527ff3aa0b341337add5 *docs/shots/view_iso_zoom.png
|
||||
1d8277f0b43938423f2ca53b34df0c56 *docs/shots/view_yz_neg_x.png
|
||||
d51cde4a5e2450c529d1c8897e16cf29 *docs/shots/view_yz_pos_x.png
|
||||
d1719a9f6fb775fd63cef27c5ff17f54 *docs/shots/zoom_user.png
|
||||
@@ -0,0 +1,104 @@
|
||||
af5c9d74bddf7d795bd38f4371fa61ec docs/shots/01_iso.png
|
||||
d1719a9f6fb775fd63cef27c5ff17f54 docs/shots/zoom_user.png
|
||||
1389d052730b4bb09eb0a17cf9c49354 docs/shots/user_harness_view.png
|
||||
eebfbfbea1375770fbc333f83f64e959 docs/shots/user_harness_zoom.png
|
||||
606e209a6d3dc64ee3a59d1fc22339f3 docs/shots/user_m1_rear.png
|
||||
99188cb1c040a2c6494322a9845ac6cb docs/shots/user_m1_exact.png
|
||||
d3234ff06df60213391dab75589d65ab docs/shots/user_m1_bypass_oblique.png
|
||||
02cfa0aa5681fec061f73b9d69fef41c docs/shots/user_smooth_harness.png
|
||||
d25a25539d00674d608dca7234e331e0 docs/shots/user_contour_harness.png
|
||||
c315879cfd09f35efa4ca4ecc1564b65 docs/shots/02_front.png
|
||||
30ab6da268de109cd087b93b8b175cf9 docs/shots/m1_sheet_front.png
|
||||
45050caba87c801ab0c29ac939e51e43 docs/shots/m2_sheet_joint.png
|
||||
615621995924b8bcaf67d79a020cd8d2 docs/shots/m3_sheet_exploded.png
|
||||
2b1950dda519fac21d5e71d4a9c1f990 docs/shots/m4_sheet_side.png
|
||||
86098e0fada6f54d9ea3d285b3e0ed6e docs/shots/m5_guide_step1.png
|
||||
8366cefeca8b935f9fef31bfd2454047 docs/shots/m6_guide_step5.png
|
||||
40f4663eef6aa61f36e47e1fb1b1ab07 docs/shots/m7_sheet_blueprint.png
|
||||
2702f107e6152f05a5016b916f38cb89 docs/shots/m8_sheet_dark.png
|
||||
c84473f41febb608aea0ec2ec12ef317 docs/shots/m9_motion.png
|
||||
b3157f4453cf96b930f065e134a2d18b docs/shots/03_side.png
|
||||
068fc4bc3eec481ff7d7b1d4da2aad88 docs/shots/04_top.png
|
||||
fbb95ea7a9229195d80c6f487021ae2b docs/shots/05_exploded.png
|
||||
cbea750a1b52c5e8d061a9e3f4c981fe docs/shots/06_wrist.png
|
||||
bb3dc393e4cd8f2c399c343aba0b3d35 docs/shots/07_joint.png
|
||||
72e86ae7743ff7416e247d19556dc657 docs/shots/08_pose.png
|
||||
af5c9d74bddf7d795bd38f4371fa61ec docs/shots/09_sheet.png
|
||||
af5c9d74bddf7d795bd38f4371fa61ec docs/shots/10_solid.png
|
||||
8daa2255af050a225609cebbc490d3b9 docs/shots/11_tool_flange.png
|
||||
002a1f4a2b65744515f5b54364fcc2a8 docs/shots/12_elbow_flare.png
|
||||
b2f1454a6009a8b44ddd41be9efdaff5 docs/shots/13_forearm_side.png
|
||||
87a8889ba4031cdf2e378fca7e1b475c docs/shots/user_target.png
|
||||
d51cde4a5e2450c529d1c8897e16cf29 docs/shots/view_yz_pos_x.png
|
||||
1d8277f0b43938423f2ca53b34df0c56 docs/shots/view_yz_neg_x.png
|
||||
64a199b2c65e7f2d0ad5e2a80c5caef8 docs/shots/view_iso_forearm.png
|
||||
22f62024f51ee1827f662d8754019f57 docs/shots/user_view1.png
|
||||
e96c715833f9321b9fd1501bc4bdf87a docs/shots/user_view2.png
|
||||
d34d5d15434bc5a980e34e5511cc49a4 docs/shots/user_p04.png
|
||||
6ea6b98ad978b993868bd302ad1dd8c6 docs/shots/user_p04_opp.png
|
||||
85d13ea862263aa055924df2beca98fb docs/shots/user_elbow_rear.png
|
||||
a17303b12669be77a97dc18f2463c809 docs/shots/user_p07_wrist.png
|
||||
3ed51a9cbad23f7c9c7eb79ac5471eb1 docs/shots/user_elbow_front.png
|
||||
729025864df7708c900e110ec175f0da docs/shots/user_p06_xz.png
|
||||
095da56acdc9b512709786df26691481 docs/shots/user_p06_yz.png
|
||||
fe0b30e16a673beb200224a0e6607faa docs/shots/user_p06_iso.png
|
||||
abf7113f27b6443541e3a0859d77b3fe docs/shots/user_p07_creases.png
|
||||
959e4bf08e174d90a1fe03a75a042070 docs/shots/bay_p06_inside.png
|
||||
f9d8d58365b4ca693525af5540d39d32 docs/shots/bay_p07_inside.png
|
||||
1b07f37e5fed9d82886b9518a3839860 docs/shots/bay_p08_inside.png
|
||||
2c7f53c7bed7d25175948f09960ed634 docs/shots/user_p04_side.png
|
||||
51d318f3584444ea78f2078d9ef3eddd docs/shots/user_p04_bottom.png
|
||||
b31cd81ca26198896378bc38c4393b9d docs/shots/user_p04_bottom2.png
|
||||
a60f07bb05bba7a58bdd29e5202c478f docs/shots/user_shoulder_solid.png
|
||||
a60f07bb05bba7a58bdd29e5202c478f docs/shots/user_shoulder_xray.png
|
||||
86aab5a8eb32216b4f712c730cc67068 docs/shots/user_shoulder_top.png
|
||||
c22cef65ca2a74b1332ecaba6b9a484a docs/shots/p03_light_iso.png
|
||||
2a9e076fa310b0c78b1a0e8375e8aae8 docs/shots/p03_light_side.png
|
||||
5671bcc5a150d4899d186abd3658ef99 docs/shots/p03_light_rear.png
|
||||
ebdeb9a180e95afd38f5a42d12743579 docs/shots/p03_light_join.png
|
||||
0aa155c87743426668114d876478582c docs/shots/p03_light_xray.png
|
||||
c55a40d4bc4b4e73a672326fa02d573c docs/shots/hollow_p04_top.png
|
||||
7fe0cb0d52c1f7d97bf1c8fd47b22e0c docs/shots/hollow_p04_iso.png
|
||||
f3b85ea576a6aa99a61953c4ff2a5ff4 docs/shots/hollow_p07_top.png
|
||||
1464e622ec8090b6052ab82f7bcd6b22 docs/shots/hollow_p07_iso.png
|
||||
8379d580ff746c859587e29e34700d7c docs/shots/hollow_p06_iso.png
|
||||
78f62639acb79e30fa88cc5fda87cfea docs/shots/p03_mount_top.png
|
||||
d0c82d07ab6055c1b67c03c126fe267a docs/shots/p03_mount_iso.png
|
||||
21db2e9ca69192cce0be4467b4701028 docs/shots/p03_mount_loose.png
|
||||
83325d3ca1b9e56fd2c70661052fd063 docs/shots/j3_前端压盖_装配.png
|
||||
e169359e86a61f7ab80d4adea0231436 docs/shots/j3_前端压盖_全件.png
|
||||
90b79bb61cacea2323ca19790d4158b2 docs/shots/boss_p04.png
|
||||
6a86499dd36b2a0a1ac50ae28ea138e4 docs/shots/user_fork_fixed.png
|
||||
e39999d2ef28536f24d7f6178fa9a15c docs/shots/bay_p04_inside.png
|
||||
959e4bf08e174d90a1fe03a75a042070 docs/shots/bay_p06_inside.png
|
||||
f9d8d58365b4ca693525af5540d39d32 docs/shots/bay_p07_inside.png
|
||||
ae0305c092707e0c73944e1d889d076a docs/shots/p04_both_ends.png
|
||||
f241acda8fdae460eb38f5a054e841f9 docs/shots/p04_m2_side.png
|
||||
4c6014a754e233411f6e89e4112d6cde docs/shots/p06_m4_side.png
|
||||
aa3cb2e1e7bff6e3ca4af66bd6c70854 docs/shots/p07_m5_side.png
|
||||
515b204e42d75d98afe0600f8b8b419d docs/shots/p05_m3_side.png
|
||||
dcc54259caf06f796e3dec84496abb12 docs/shots/boss_p05.png
|
||||
309cc9ac3238e747104e6ceee7bd68bc docs/shots/user_compare_view.png
|
||||
152eb1db302b62238f3051b1f48fcf45 docs/shots/user_p07_check.png
|
||||
9f2c134297f2c7a555a6eaca2e74e4de docs/shots/boss_p06.png
|
||||
b789564315ca1ad7d6d9d18c96972cba docs/shots/boss_p07.png
|
||||
4a9a34e534496cb2c3be499ea2029d87 docs/shots/svg_side.png
|
||||
eadcf7d6ac9853950496a559dbd8de72 docs/shots/svg_joint.png
|
||||
f1e5bd79e6921b39d0785e4208ef5cca docs/shots/svg_exploded.png
|
||||
1e1d29129833b35e43b925b25eae4b8f docs/shots/user_circle_check.png
|
||||
6e1c039c236d28a4bec7e7b589fb2ed3 docs/shots/user_exact_view.png
|
||||
7635f1d057b06f014c1683261a7237b8 docs/shots/shot_p08_user.png
|
||||
3d261042388c8b2924848d8a29f71931 docs/shots/p05_flank_view.png
|
||||
af5c9d74bddf7d795bd38f4371fa61ec docs/shots/harness_full_iso.png
|
||||
8896124b0c45d9796e983f026134cff6 docs/shots/harness_overview.png
|
||||
9fca41ada43f36a338cce31797152c3c docs/shots/harness_p07_window.png
|
||||
7cbf2c699501bff3c7ebb4beb7cd34e2 docs/shots/harness_p04_p05.png
|
||||
687e2184dd3e149939ce6d4214ffc698 docs/shots/harness_p06_window.png
|
||||
84fb87bb5ce6cef73866401642ab0f9d docs/shots/harness_xray_full.png
|
||||
70772a99b8c5d81619127eed7bc1dab5 docs/shots/tie_probe_negY.png
|
||||
a3bf9bd7fb796283bbb9767cc790167a docs/shots/tie_probe_posY.png
|
||||
7c2be3a8488997de588e3760f966fd7d docs/shots/tie_after_negY.png
|
||||
0b3e26c6e2fd664f91764d26b8b1ed0c docs/shots/tie_after_oblique.png
|
||||
d3bf901601ff221ecd1b09dc93dd2ccc docs/shots/tie_after_close.png
|
||||
c39cee9deabedb4dc8fad8ec76b439e5 docs/shots/tie_after_p0607.png
|
||||
b51a4e5424297c9012cc0562bbeec296 docs/shots/tie_after_p0607_obl.png
|
||||
@@ -0,0 +1,117 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Automated 3D Wire Harness Collision Verification Suite:
|
||||
Validates that every wire segment and flexible bridge in the robot arm
|
||||
passes strictly through dedicated hollow channels and enlarged 22x22mm pass-through holes
|
||||
with ZERO solid penetrations (BRepClass3d_SolidClassifier against OCC STEP solids).
|
||||
"""
|
||||
import sys, io, os, re
|
||||
sys.stdout.reconfigure(encoding='utf-8')
|
||||
import numpy as np
|
||||
import cadquery as cq
|
||||
from OCP.BRepClass3d import BRepClass3d_SolidClassifier
|
||||
from OCP.gp import gp_Pnt
|
||||
from OCP.TopAbs import TopAbs_IN
|
||||
|
||||
def catmull_rom_sample(pts, num_samples_per_seg=25):
|
||||
pts = np.array(pts, dtype=float)
|
||||
if len(pts) == 2:
|
||||
t = np.linspace(0, 1, num_samples_per_seg)
|
||||
return [(1-s)*pts[0] + s*pts[1] for s in t]
|
||||
sampled = []
|
||||
p = np.vstack([pts[0], pts, pts[-1]])
|
||||
for i in range(1, len(p) - 2):
|
||||
p0, p1, p2, p3 = p[i-1], p[i], p[i+1], p[i+2]
|
||||
for t in np.linspace(0, 1, num_samples_per_seg, endpoint=(i == len(p)-3)):
|
||||
t2, t3 = t*t, t*t*t
|
||||
val = 0.5 * ((2*p1) + (-p0 + p2)*t + (2*p0 - 5*p1 + 4*p2 - p3)*t2 + (-p0 + 3*p1 - 3*p2 + p3)*t3)
|
||||
sampled.append(val)
|
||||
return sampled
|
||||
|
||||
def load_solids():
|
||||
clfs = {}
|
||||
for f in os.listdir('out/parts_step'):
|
||||
if f.endswith('.step'):
|
||||
tag = f.split('.')[0]
|
||||
print(f"Loading {tag}...", flush=True)
|
||||
shape = cq.importers.importStep(os.path.join('out/parts_step', f)).val()
|
||||
clfs[tag] = BRepClass3d_SolidClassifier(shape.wrapped)
|
||||
return clfs
|
||||
|
||||
def main():
|
||||
clfs = load_solids()
|
||||
print("=" * 80)
|
||||
print("【线束三维物理干涉检测】全通道、外侧走线与电机全固态零碰撞验证")
|
||||
print("=" * 80)
|
||||
|
||||
# 线束通道的锚点坐标写在查看器源码里(现在是模板,拆分后是 webapp/js/harness.js)。
|
||||
# 扫候选文件而不是写死一个路径,前端拆分时这条检查不用跟着改;一个都找不到就直接失败,
|
||||
# 绝不能"没匹配到 = 没有通道 = 零干涉"地假通过。
|
||||
from arm.paths import REPO
|
||||
cands = [REPO + "/src/viewer_tpl.html", REPO + "/webapp/js/harness.js"]
|
||||
found = [c for c in cands if os.path.exists(c)]
|
||||
if not found:
|
||||
print("找不到线束源码,检查项无法执行:", cands, flush=True)
|
||||
sys.exit(2)
|
||||
with open(found[0], 'r', encoding='utf-8') as f:
|
||||
tpl = f.read()
|
||||
|
||||
tube_matches = re.findall(r'makeHarnTube\(\[\s*([\s\S]*?)\s*\]\s*,\s*[\d\.]+\s*,\s*\w+\s*,\s*\'([^\']+)\'', tpl)
|
||||
total_hits = 0
|
||||
checked_count = 0
|
||||
|
||||
for raw_pts, name in tube_matches:
|
||||
pt_list = []
|
||||
for m in re.finditer(r'\[\s*([-\d\.]+)\s*,\s*([-\d\.]+)\s*,\s*([-\d\.]+)\s*\]', raw_pts):
|
||||
pt_list.append([float(m.group(1)), float(m.group(2)), float(m.group(3))])
|
||||
sampled = catmull_rom_sample(pt_list, num_samples_per_seg=25)
|
||||
hits = []
|
||||
for p in sampled:
|
||||
pt = gp_Pnt(float(p[0]), float(p[1]), float(p[2]))
|
||||
for part, clf in clfs.items():
|
||||
clf.Perform(pt, 1e-3)
|
||||
if clf.State() == TopAbs_IN:
|
||||
hits.append((part, p))
|
||||
checked_count += len(sampled)
|
||||
if hits:
|
||||
total_hits += len(hits)
|
||||
print(f" ❌ FAIL: {name} (发现 {len(hits)} 处实体穿透! 首击穿部件: {hits[0][0]} 坐标: {hits[0][1]})", flush=True)
|
||||
else:
|
||||
print(f" ✓ PASS: {name} ({len(sampled)} 采样点零干涉)", flush=True)
|
||||
|
||||
# Test dynamic bridges at zero pose
|
||||
bridge_specs = [
|
||||
('Bridge 1 (J1 Ω-Loop 柔性缓冲段)', [[5.5, 86.1, 610.0], [9.13, 79.4, 611.9], [12.75, 76.78, 613.5], [16.38, 79.85, 614.4], [20.0, 87.0, 615.0]]),
|
||||
('Bridge 2 (J2 U-Loop 柔性缓冲段)', [[-17.5, 102.5, 485.0], [-25.0, 102.5, 475.0], [-30.0, 102.5, 465.0], [-25.0, 102.5, 455.0], [-17.5, 102.5, 445.0]]),
|
||||
('Bridge 3 (J3 螺旋柔性过渡段)', [[-17.5, 102.5, 400.0], [-24.0, 96.0, 390.0], [-27.0, 93.0, 380.0], [-23.0, 96.0, 370.0], [-17.5, 102.5, 360.0]]),
|
||||
('Bridge 4 (J4 肘部U-Loop柔性缓冲段)', [[-17.5, 102.5, 305.0], [-24.0, 102.5, 290.0], [-30.0, 102.5, 280.0], [-24.0, 102.5, 270.0], [-17.5, 102.5, 255.0]]),
|
||||
('Bridge 5 (J5 腕部U-Loop柔性缓冲段)', [[-17.5, 102.5, 205.0], [-22.0, 102.5, 195.0], [-26.0, 102.5, 190.0], [-22.0, 102.5, 182.0], [-17.5, 102.5, 175.0]]),
|
||||
]
|
||||
|
||||
for name, pts in bridge_specs:
|
||||
sampled = catmull_rom_sample(pts, num_samples_per_seg=25)
|
||||
hits = []
|
||||
for p in sampled:
|
||||
pt = gp_Pnt(float(p[0]), float(p[1]), float(p[2]))
|
||||
for part, clf in clfs.items():
|
||||
clf.Perform(pt, 1e-3)
|
||||
if clf.State() == TopAbs_IN:
|
||||
hits.append((part, p))
|
||||
checked_count += len(sampled)
|
||||
if hits:
|
||||
total_hits += len(hits)
|
||||
print(f" ❌ FAIL: {name} (发现 {len(hits)} 处实体穿透!)", flush=True)
|
||||
else:
|
||||
print(f" ✓ PASS: {name} ({len(sampled)} 采样点零干涉)", flush=True)
|
||||
|
||||
print("=" * 80, flush=True)
|
||||
print(f"【最终结论】共评估 {checked_count} 个空间采样点,固体穿透总数: {total_hits}", flush=True)
|
||||
if total_hits == 0:
|
||||
print("🎉 恭喜!线束系统已实现 100% 结构腔体内规范走线与零碰撞干涉!", flush=True)
|
||||
print("=" * 80, flush=True)
|
||||
sys.stdout.flush()
|
||||
# 同上:OCC 析构会段错误,所以用 os._exit 带走正确退出码
|
||||
os._exit(0 if total_hits == 0 else 1)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
+172
@@ -0,0 +1,172 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""重构期的不变量关卡。
|
||||
|
||||
python -m tests.verify # 数据哈希 + IK 数值(秒级,每步都跑)
|
||||
python -m tests.verify --shots # 再加全套截图比对(约 3 分钟,前端改动后跑)
|
||||
|
||||
基线在 tests/baselines/ 下,随仓库走。产物按**文件名**匹配,不写死目录:
|
||||
mesh 从 web/ 搬到 webapp/data/ 这类移动不该让关卡失效,也不该让我以为它通过了。
|
||||
任何一项对不上就退出码 1。
|
||||
"""
|
||||
import hashlib
|
||||
import io
|
||||
import json
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
sys.stdout.reconfigure(encoding="utf-8")
|
||||
HERE = os.path.dirname(os.path.abspath(__file__))
|
||||
REPO = os.path.dirname(HERE)
|
||||
BASE = os.path.join(HERE, "baselines")
|
||||
|
||||
# 每个产物允许出现的目录,按优先级;找到第一个即取。
|
||||
CANDIDATES = {
|
||||
"mesh_arm.json": ["webapp/data", "web"],
|
||||
"sheets.jsdata": ["webapp/data", "web"],
|
||||
"travel.json": ["docs", "webapp/data"],
|
||||
"travel_detail.json": ["docs", "webapp/data"],
|
||||
"collide.json": ["docs", "webapp/data"],
|
||||
"screws.json": ["docs"],
|
||||
}
|
||||
|
||||
|
||||
def md5(path):
|
||||
h = hashlib.md5()
|
||||
with open(path, "rb") as f:
|
||||
for chunk in iter(lambda: f.read(1 << 20), b""):
|
||||
h.update(chunk)
|
||||
return h.hexdigest()
|
||||
|
||||
|
||||
def read_list(name):
|
||||
"""基线文件是 'hash filename';md5sum 的二进制模式会在文件名前加 '*',剥掉。"""
|
||||
out = {}
|
||||
for ln in io.open(os.path.join(BASE, name), encoding="utf-8"):
|
||||
ln = ln.strip()
|
||||
if ln:
|
||||
h, f = ln.split()
|
||||
out[f.lstrip("*")] = h
|
||||
return out
|
||||
|
||||
|
||||
def locate(fname, dirs):
|
||||
for d in dirs:
|
||||
p = os.path.join(REPO, d, fname)
|
||||
if os.path.exists(p):
|
||||
return p
|
||||
return None
|
||||
|
||||
|
||||
def check_data():
|
||||
base = read_list("data_by_name.md5")
|
||||
bad, rows = 0, []
|
||||
for fname, dirs in CANDIDATES.items():
|
||||
want = base.get(fname)
|
||||
if want is None:
|
||||
rows.append(("SKIP", fname, "基线里没有这项"))
|
||||
continue
|
||||
p = locate(fname, dirs)
|
||||
if p is None:
|
||||
bad += 1
|
||||
rows.append(("MISS", fname, "找不到文件(试过的目录: %s)" % ", ".join(dirs)))
|
||||
continue
|
||||
got = md5(p)
|
||||
ok = got == want
|
||||
if not ok:
|
||||
bad += 1
|
||||
rows.append(("OK " if ok else "DIFF", fname,
|
||||
os.path.relpath(p, REPO).replace("\\", "/") + " " + got[:12] +
|
||||
("" if ok else " 基线 " + want[:12])))
|
||||
for st, f, msg in rows:
|
||||
print(" [%s] %-20s %s" % (st, f, msg))
|
||||
return bad
|
||||
|
||||
|
||||
def check_ik():
|
||||
r = subprocess.run(["node", os.path.join(HERE, "ik_baseline.mjs"),
|
||||
"--compare", os.path.join(BASE, "ik_exact.json")],
|
||||
capture_output=True, text=True, cwd=REPO,
|
||||
encoding="utf-8", errors="replace")
|
||||
out = r.stdout or ""
|
||||
for ln in out.splitlines():
|
||||
print(" " + ln)
|
||||
if r.returncode != 0:
|
||||
print(" node 退出码 %d: %s" % (r.returncode, (r.stderr or "").strip()[:300]))
|
||||
# 没有 "== exact" 这一行就说明探针根本没跑出比对结果(编码炸了、node 不在、路径错…),
|
||||
# 绝不能因为"没报差异"就算通过。
|
||||
if "== exact" not in out:
|
||||
print(" [MISS] ik_baseline 没有输出比对结果,判 FAIL")
|
||||
return 1
|
||||
return 0 if r.returncode == 0 else 1
|
||||
|
||||
|
||||
def check_shots():
|
||||
"""两层判定,依据是"同一构建连跑两轮"的实测(scratch/_gate/flaky_scan.py):
|
||||
104 张逐字节可复现 -> md5 必须相同;
|
||||
3 张线束 x-ray 不可复现(mean<=0.0017、无像素差>8,纯抗锯齿噪声)
|
||||
-> 与 tests/baselines/flaky/ 里的参考像素比,超阈值才算回归。
|
||||
把不可复现的也要求 md5 相同,等于给每一步埋假 FAIL,最后只会被人肉忽略。"""
|
||||
import numpy as np
|
||||
from PIL import Image
|
||||
|
||||
base = read_list("shots_stable.md5")
|
||||
th = json.load(io.open(os.path.join(BASE, "flaky", "thresholds.json"), encoding="utf-8"))
|
||||
r = subprocess.run([sys.executable, "-m", "arm.viewer.shot"],
|
||||
capture_output=True, text=True, cwd=REPO,
|
||||
encoding="utf-8", errors="replace")
|
||||
out = r.stdout or ""
|
||||
if "all shots ok" not in out and "OK " not in out:
|
||||
print(" [MISS] shot.py 没有正常输出(退出码 %s),判 FAIL" % r.returncode)
|
||||
return 999
|
||||
bad = [l for l in out.splitlines() if "FAIL" in l]
|
||||
if bad:
|
||||
print(" [MISS] 截图失败 %d 个: %s" % (len(bad), bad[:3]))
|
||||
|
||||
fails = len(bad)
|
||||
for fname, want in sorted(base.items()):
|
||||
p = os.path.join(REPO, fname.replace("/", os.sep))
|
||||
if not os.path.exists(p):
|
||||
print(" [MISS] %s" % fname)
|
||||
fails += 1
|
||||
continue
|
||||
if md5(p) != want:
|
||||
print(" [DIFF] %-40s" % fname)
|
||||
fails += 1
|
||||
print(" 逐字节比对: %d 张稳定视图,%d 张不一致" % (len(base), fails - len(bad)))
|
||||
|
||||
tol_fails = 0
|
||||
for name, ref in sorted(th["views"].items()):
|
||||
p = os.path.join(REPO, "docs", "shots", name + ".png")
|
||||
q = os.path.join(BASE, "flaky", name + ".png")
|
||||
if not (os.path.exists(p) and os.path.exists(q)):
|
||||
print(" [MISS] 容差比对缺文件: %s" % name)
|
||||
tol_fails += 1
|
||||
continue
|
||||
d = np.abs(np.asarray(Image.open(p).convert("RGB"), dtype=np.int16)
|
||||
- np.asarray(Image.open(q).convert("RGB"), dtype=np.int16))
|
||||
mean, mx = float(d.mean()), int(d.max())
|
||||
over = mean > th["mean_max"] or mx > th["pixel_max"]
|
||||
tol_fails += 1 if over else 0
|
||||
print(" [%s] %-34s mean=%.5f (<= %.2f) 最大单像素差=%d (<= %d)"
|
||||
% ("DIFF" if over else "OK ", name, mean, th["mean_max"], mx, th["pixel_max"]))
|
||||
print(" 容差比对: %d 张噪声视图,%d 张超阈值" % (len(th["views"]), tol_fails))
|
||||
return fails + tol_fails
|
||||
|
||||
|
||||
def main():
|
||||
argv = sys.argv[1:]
|
||||
fails = 0
|
||||
print("== 数据产物哈希 ==")
|
||||
fails += check_data()
|
||||
print("== IK 数值基线 ==")
|
||||
fails += check_ik()
|
||||
if "--shots" in argv:
|
||||
print("== 截图逐字节比对 ==")
|
||||
fails += check_shots()
|
||||
print("RESULT:", "PASS" if fails == 0 else "FAIL(%d 项不一致)" % fails)
|
||||
return 1 if fails else 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
Reference in New Issue
Block a user