test: 加 IK/数据/截图三重基线关卡,并刷新过期的截图基线
重构 2955 行的单文件查看器必须有"行为没变"的可判据,否则改到什么程度全靠感觉。
tests/ik_baseline.mjs 在 Node 里直接跑求解器(它本就是 UMD,带 module.exports 分支,
不需要浏览器),输出分两段:
exact —— 件数/顶点/三角、TCP 推断、限位、固定 FK/fkChain/orient、固定目标的
solveDyn 解向量、selfTest/poseSelfTest 的误差与命中数。selfTest 内部走
Math.random,这里锁成定 LCG,所以 exact 跨进程逐字节可复现。
timing —— solveDyn 中位耗时(9 次去头 3 次预热)。本机进程间抖动实测约 ±28%,
因此只按 ±10% 报 WARN,不当硬门。
关卡灵敏度已验:指向 scratch/arm-ik-solver_before.js 时报 5 处 exact 差异并 FAIL。
docs/shots/ 里 92 张是 10-09 生成的,早于 10-14 的重建,属过期基线;重跑 96 视图
全部 OK、0 FAIL。另发现既有非幂等问题:committed 的 mesh 是"端到端构建后再单跑一次
screw_mesh.py"的产物(螺钉 idx 118..214、ENV 件排在第 19 位),端到端构建则为
20..116、ENV 排在末尾,两者零件集合相同但顺序不同,导致 2 张线束透视图的透明排序
像素级不同。本提交以端到端构建为准。
|
Before Width: | Height: | Size: 135 KiB After Width: | Height: | Size: 135 KiB |
|
Before Width: | Height: | Size: 98 KiB After Width: | Height: | Size: 101 KiB |
|
Before Width: | Height: | Size: 103 KiB After Width: | Height: | Size: 105 KiB |
|
Before Width: | Height: | Size: 109 KiB After Width: | Height: | Size: 119 KiB |
|
Before Width: | Height: | Size: 156 KiB After Width: | Height: | Size: 156 KiB |
|
Before Width: | Height: | Size: 191 KiB After Width: | Height: | Size: 195 KiB |
|
Before Width: | Height: | Size: 140 KiB After Width: | Height: | Size: 147 KiB |
|
Before Width: | Height: | Size: 134 KiB After Width: | Height: | Size: 138 KiB |
|
Before Width: | Height: | Size: 134 KiB After Width: | Height: | Size: 135 KiB |
|
Before Width: | Height: | Size: 134 KiB After Width: | Height: | Size: 135 KiB |
|
Before Width: | Height: | Size: 190 KiB After Width: | Height: | Size: 195 KiB |
|
Before Width: | Height: | Size: 172 KiB After Width: | Height: | Size: 174 KiB |
|
Before Width: | Height: | Size: 121 KiB After Width: | Height: | Size: 138 KiB |
|
Before Width: | Height: | Size: 147 KiB After Width: | Height: | Size: 193 KiB |
|
Before Width: | Height: | Size: 147 KiB After Width: | Height: | Size: 173 KiB |
|
Before Width: | Height: | Size: 154 KiB After Width: | Height: | Size: 178 KiB |
|
Before Width: | Height: | Size: 112 KiB After Width: | Height: | Size: 130 KiB |
|
Before Width: | Height: | Size: 114 KiB After Width: | Height: | Size: 116 KiB |
|
Before Width: | Height: | Size: 120 KiB After Width: | Height: | Size: 147 KiB |
|
Before Width: | Height: | Size: 111 KiB After Width: | Height: | Size: 136 KiB |
|
Before Width: | Height: | Size: 99 KiB After Width: | Height: | Size: 114 KiB |
|
Before Width: | Height: | Size: 135 KiB After Width: | Height: | Size: 135 KiB |
|
Before Width: | Height: | Size: 169 KiB After Width: | Height: | Size: 169 KiB |
|
Before Width: | Height: | Size: 155 KiB After Width: | Height: | Size: 180 KiB |
|
Before Width: | Height: | Size: 276 KiB After Width: | Height: | Size: 294 KiB |
|
Before Width: | Height: | Size: 193 KiB After Width: | Height: | Size: 186 KiB |
|
Before Width: | Height: | Size: 182 KiB After Width: | Height: | Size: 175 KiB |
|
Before Width: | Height: | Size: 375 KiB After Width: | Height: | Size: 363 KiB |
|
Before Width: | Height: | Size: 135 KiB After Width: | Height: | Size: 136 KiB |
|
Before Width: | Height: | Size: 299 KiB After Width: | Height: | Size: 296 KiB |
|
Before Width: | Height: | Size: 107 KiB After Width: | Height: | Size: 144 KiB |
|
Before Width: | Height: | Size: 98 KiB After Width: | Height: | Size: 115 KiB |
|
Before Width: | Height: | Size: 117 KiB After Width: | Height: | Size: 150 KiB |
|
Before Width: | Height: | Size: 127 KiB After Width: | Height: | Size: 155 KiB |
|
Before Width: | Height: | Size: 105 KiB After Width: | Height: | Size: 118 KiB |
|
Before Width: | Height: | Size: 201 KiB After Width: | Height: | Size: 236 KiB |
|
Before Width: | Height: | Size: 122 KiB After Width: | Height: | Size: 182 KiB |
|
Before Width: | Height: | Size: 127 KiB After Width: | Height: | Size: 163 KiB |
|
Before Width: | Height: | Size: 148 KiB After Width: | Height: | Size: 171 KiB |
|
Before Width: | Height: | Size: 101 KiB After Width: | Height: | Size: 131 KiB |
|
Before Width: | Height: | Size: 94 KiB After Width: | Height: | Size: 135 KiB |
|
Before Width: | Height: | Size: 127 KiB After Width: | Height: | Size: 163 KiB |
|
Before Width: | Height: | Size: 112 KiB After Width: | Height: | Size: 160 KiB |
|
Before Width: | Height: | Size: 148 KiB After Width: | Height: | Size: 153 KiB |
|
Before Width: | Height: | Size: 99 KiB After Width: | Height: | Size: 126 KiB |
|
Before Width: | Height: | Size: 92 KiB After Width: | Height: | Size: 136 KiB |
|
Before Width: | Height: | Size: 109 KiB After Width: | Height: | Size: 176 KiB |
|
Before Width: | Height: | Size: 161 KiB After Width: | Height: | Size: 148 KiB |
|
Before Width: | Height: | Size: 126 KiB After Width: | Height: | Size: 186 KiB |
|
Before Width: | Height: | Size: 114 KiB After Width: | Height: | Size: 161 KiB |
|
Before Width: | Height: | Size: 110 KiB After Width: | Height: | Size: 154 KiB |
|
Before Width: | Height: | Size: 110 KiB After Width: | Height: | Size: 134 KiB |
|
Before Width: | Height: | Size: 86 KiB After Width: | Height: | Size: 90 KiB |
|
Before Width: | Height: | Size: 59 KiB After Width: | Height: | Size: 53 KiB |
|
Before Width: | Height: | Size: 80 KiB After Width: | Height: | Size: 85 KiB |
|
Before Width: | Height: | Size: 128 KiB After Width: | Height: | Size: 128 KiB |
|
Before Width: | Height: | Size: 123 KiB After Width: | Height: | Size: 123 KiB |
|
Before Width: | Height: | Size: 160 KiB After Width: | Height: | Size: 196 KiB |
|
Before Width: | Height: | Size: 115 KiB After Width: | Height: | Size: 121 KiB |
|
Before Width: | Height: | Size: 139 KiB After Width: | Height: | Size: 143 KiB |
|
Before Width: | Height: | Size: 144 KiB After Width: | Height: | Size: 127 KiB |
|
Before Width: | Height: | Size: 116 KiB After Width: | Height: | Size: 136 KiB |
|
Before Width: | Height: | Size: 120 KiB After Width: | Height: | Size: 167 KiB |
|
Before Width: | Height: | Size: 122 KiB After Width: | Height: | Size: 124 KiB |
|
Before Width: | Height: | Size: 176 KiB After Width: | Height: | Size: 169 KiB |
|
Before Width: | Height: | Size: 184 KiB After Width: | Height: | Size: 174 KiB |
|
Before Width: | Height: | Size: 173 KiB After Width: | Height: | Size: 169 KiB |
|
Before Width: | Height: | Size: 142 KiB After Width: | Height: | Size: 136 KiB |
|
Before Width: | Height: | Size: 150 KiB After Width: | Height: | Size: 144 KiB |
|
Before Width: | Height: | Size: 122 KiB After Width: | Height: | Size: 139 KiB |
|
Before Width: | Height: | Size: 158 KiB After Width: | Height: | Size: 196 KiB |
|
Before Width: | Height: | Size: 153 KiB After Width: | Height: | Size: 208 KiB |
|
Before Width: | Height: | Size: 114 KiB After Width: | Height: | Size: 148 KiB |
|
Before Width: | Height: | Size: 113 KiB After Width: | Height: | Size: 160 KiB |
|
Before Width: | Height: | Size: 128 KiB After Width: | Height: | Size: 149 KiB |
|
Before Width: | Height: | Size: 134 KiB After Width: | Height: | Size: 138 KiB |
|
Before Width: | Height: | Size: 95 KiB After Width: | Height: | Size: 120 KiB |
|
Before Width: | Height: | Size: 176 KiB After Width: | Height: | Size: 177 KiB |
|
Before Width: | Height: | Size: 118 KiB After Width: | Height: | Size: 122 KiB |
|
Before Width: | Height: | Size: 134 KiB After Width: | Height: | Size: 174 KiB |
|
Before Width: | Height: | Size: 233 KiB After Width: | Height: | Size: 238 KiB |
|
Before Width: | Height: | Size: 134 KiB After Width: | Height: | Size: 174 KiB |
|
Before Width: | Height: | Size: 148 KiB After Width: | Height: | Size: 146 KiB |
|
Before Width: | Height: | Size: 120 KiB After Width: | Height: | Size: 121 KiB |
|
Before Width: | Height: | Size: 156 KiB After Width: | Height: | Size: 165 KiB |
|
Before Width: | Height: | Size: 148 KiB After Width: | Height: | Size: 154 KiB |
|
Before Width: | Height: | Size: 203 KiB After Width: | Height: | Size: 206 KiB |
|
Before Width: | Height: | Size: 87 KiB After Width: | Height: | Size: 88 KiB |
|
Before Width: | Height: | Size: 123 KiB After Width: | Height: | Size: 127 KiB |
|
Before Width: | Height: | Size: 197 KiB After Width: | Height: | Size: 195 KiB |
@@ -0,0 +1,6 @@
|
||||
533c100b58b33c0317de179f65c5c681 travel.json
|
||||
c66c230557548bd03f003bb4bd52ff6a travel_detail.json
|
||||
4a8f14be95ed32121166a9bd37e74752 collide.json
|
||||
82f8fa459be497ae0cfc92d5816497bf screws.json
|
||||
83dfad6817c766ee893f54cca8fa7774 mesh_arm.json
|
||||
f74cf5148cfc03c2d785829f45a608f9 sheets.jsdata
|
||||
@@ -0,0 +1,228 @@
|
||||
{
|
||||
"meta": {
|
||||
"solver": "web/arm-ik-solver.js",
|
||||
"mesh": "web/mesh_arm.json"
|
||||
},
|
||||
"exact": {
|
||||
"counts": {
|
||||
"parts": 117,
|
||||
"verts": 367118,
|
||||
"tris": 351491,
|
||||
"printed": 13,
|
||||
"env": 1,
|
||||
"joints": 6
|
||||
},
|
||||
"tcpZ": 93,
|
||||
"TCP0": [
|
||||
19.5,
|
||||
128,
|
||||
93
|
||||
],
|
||||
"motorTravel": 360,
|
||||
"noAdjAxes": [],
|
||||
"caps": 1936,
|
||||
"lim": {
|
||||
"J1": [
|
||||
-180,
|
||||
180,
|
||||
true
|
||||
],
|
||||
"J2": [
|
||||
-93,
|
||||
126,
|
||||
false
|
||||
],
|
||||
"J3": [
|
||||
-180,
|
||||
180,
|
||||
true
|
||||
],
|
||||
"J4": [
|
||||
-113,
|
||||
113,
|
||||
false
|
||||
],
|
||||
"J5": [
|
||||
-94,
|
||||
89,
|
||||
false
|
||||
],
|
||||
"J6": [
|
||||
-180,
|
||||
180,
|
||||
true
|
||||
]
|
||||
},
|
||||
"fkQ0": [
|
||||
106.498451,
|
||||
235.370133,
|
||||
140.165364
|
||||
],
|
||||
"fkChainQ0": [
|
||||
106.498451,
|
||||
235.370133,
|
||||
140.165364
|
||||
],
|
||||
"orientQ0": [
|
||||
0.595153,
|
||||
0.645892,
|
||||
-0.478139,
|
||||
-0.757749,
|
||||
0.649173,
|
||||
-0.06626,
|
||||
0.267598,
|
||||
0.401744,
|
||||
0.875781
|
||||
],
|
||||
"solveDyn": [
|
||||
{
|
||||
"T": [
|
||||
150,
|
||||
128,
|
||||
260
|
||||
],
|
||||
"ok": true,
|
||||
"err": 0,
|
||||
"q": [
|
||||
0.041,
|
||||
5.809,
|
||||
0.094,
|
||||
-17.507,
|
||||
-94,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"T": [
|
||||
180,
|
||||
128,
|
||||
300
|
||||
],
|
||||
"ok": true,
|
||||
"err": 0,
|
||||
"q": [
|
||||
0.049,
|
||||
-0.026,
|
||||
0.094,
|
||||
-26.821,
|
||||
-94,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"T": [
|
||||
120,
|
||||
-150,
|
||||
320
|
||||
],
|
||||
"ok": true,
|
||||
"err": 0,
|
||||
"q": [
|
||||
-43.713,
|
||||
6.027,
|
||||
0.239,
|
||||
-0.279,
|
||||
-89.002,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"T": [
|
||||
60,
|
||||
128,
|
||||
420
|
||||
],
|
||||
"ok": true,
|
||||
"err": 0,
|
||||
"q": [
|
||||
38.165,
|
||||
0.129,
|
||||
70.062,
|
||||
-89.578,
|
||||
-80.719,
|
||||
0
|
||||
]
|
||||
}
|
||||
],
|
||||
"selfTest": {
|
||||
"maxFkErr": 4.689582056016661e-13,
|
||||
"maxIkErr": 7.082653493385528e-13,
|
||||
"ikHit": 200,
|
||||
"ikTried": 200,
|
||||
"structWarn": [],
|
||||
"poseHit": 8,
|
||||
"poseTried": 8,
|
||||
"poseErr": 0.0000017075472925031877,
|
||||
"K": {
|
||||
"X0": 19.5,
|
||||
"Y0": 128,
|
||||
"Z1": 610,
|
||||
"Z2": 490,
|
||||
"Z3": 445,
|
||||
"Z4": 332,
|
||||
"Z5": 222,
|
||||
"TCP0": [
|
||||
19.5,
|
||||
128,
|
||||
93
|
||||
],
|
||||
"ax": [
|
||||
0,
|
||||
0,
|
||||
-1
|
||||
],
|
||||
"C0": -120,
|
||||
"A43": -113,
|
||||
"A32": -45,
|
||||
"A54": -110,
|
||||
"L5": 129
|
||||
},
|
||||
"LIM": {
|
||||
"J1": {
|
||||
"lo": -180,
|
||||
"hi": 180,
|
||||
"cont": true
|
||||
},
|
||||
"J2": {
|
||||
"lo": -93,
|
||||
"hi": 126,
|
||||
"cont": false
|
||||
},
|
||||
"J3": {
|
||||
"lo": -180,
|
||||
"hi": 180,
|
||||
"cont": true
|
||||
},
|
||||
"J4": {
|
||||
"lo": -113,
|
||||
"hi": 113,
|
||||
"cont": false
|
||||
},
|
||||
"J5": {
|
||||
"lo": -94,
|
||||
"hi": 89,
|
||||
"cont": false
|
||||
},
|
||||
"J6": {
|
||||
"lo": -180,
|
||||
"hi": 180,
|
||||
"cont": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"poseSelfTest": {
|
||||
"poseHit": 8,
|
||||
"poseTried": 8,
|
||||
"poseErr": 0.0000012074182697257333
|
||||
}
|
||||
},
|
||||
"timing": {
|
||||
"solveDynMedianMs": [
|
||||
252.53,
|
||||
239.83,
|
||||
192.01,
|
||||
192.92
|
||||
],
|
||||
"poseSelfTestAvgMs": 93.48
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,228 @@
|
||||
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,170 @@
|
||||
/**
|
||||
* IK 数值基线探针(Node,不需要浏览器)。
|
||||
*
|
||||
* node tests/ik_baseline.mjs 生成基线到 stdout
|
||||
* node tests/ik_baseline.mjs --out scratch/_gate/ik.json
|
||||
* node tests/ik_baseline.mjs --compare scratch/_gate/ik.json 重构后跑这条,FAIL 就退出码 1
|
||||
* node tests/ik_baseline.mjs --solver web/arm-ik-solver.js 指定求解器文件
|
||||
*
|
||||
* 输出分两段,因为它们的判定方式不同:
|
||||
* exact —— 件数/顶点数、TCP 推断、限位、固定 FK、固定目标的解向量、selfTest 误差与命中数。
|
||||
* 这些必须逐字节相同;用定种子 RNG 保证可复现(selfTest 内部原本走 Math.random)。
|
||||
* timing —— solveDyn 中位耗时。机器负载会变,只按 ±10% 报 WARN,不作 FAIL。
|
||||
*
|
||||
* 求解器配置构造与查看器里的 ik-glue 逐行对齐(JMap/COL/TR/TCP0),
|
||||
* 否则两边算的不是同一个问题,对比无意义。
|
||||
*/
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import { pathToFileURL } from 'url';
|
||||
|
||||
const ROOT = path.resolve(import.meta.dirname, '..');
|
||||
const first = (...cands) => cands.find(p => fs.existsSync(p));
|
||||
|
||||
const argv = process.argv.slice(2);
|
||||
const argVal = (name, dflt) => {
|
||||
const i = argv.indexOf('--' + name);
|
||||
return i >= 0 && argv[i + 1] && !argv[i + 1].startsWith('--') ? argv[i + 1] : dflt;
|
||||
};
|
||||
|
||||
const SOLVER = argVal('solver', first(
|
||||
path.join(ROOT, 'webapp/js/ik/solver.js'),
|
||||
path.join(ROOT, 'web/arm-ik-solver.js')));
|
||||
const MESH = first(path.join(ROOT, 'webapp/data/mesh_arm.json'),
|
||||
path.join(ROOT, 'web/mesh_arm.json'));
|
||||
const TRAVEL = path.join(ROOT, 'docs/travel.json');
|
||||
const COLLIDE = path.join(ROOT, 'docs/collide.json');
|
||||
|
||||
const mod = await import(pathToFileURL(SOLVER).href);
|
||||
const ArmIK = mod.ArmIK || mod.default;
|
||||
if (!ArmIK) throw new Error('求解器没有导出 ArmIK: ' + SOLVER);
|
||||
|
||||
const mesh = JSON.parse(fs.readFileSync(MESH, 'utf8'));
|
||||
const travel = JSON.parse(fs.readFileSync(TRAVEL, 'utf8'));
|
||||
const collide = fs.existsSync(COLLIDE) ? JSON.parse(fs.readFileSync(COLLIDE, 'utf8')) : null;
|
||||
|
||||
/* ---- 与 ik-glue.js:16-52 同构的配置 ---- */
|
||||
const JO = mesh.joints;
|
||||
const JJ = {}; for (const j of JO) JJ[j.id] = j;
|
||||
const JMap = {}; for (const j of JO) JMap[j.id] = { rear: j.rear, d: j.d };
|
||||
const COL = (collide && collide.caps && collide.caps.length) ? collide : null;
|
||||
const ADJ = (COL && COL.adj) || {};
|
||||
const MOTOR = +((COL && COL.motor_limit_deg) || 360);
|
||||
const TR = {}; const noAdj = [];
|
||||
for (const t of travel) {
|
||||
const a = ADJ[t.axis];
|
||||
if (!a && !t.continuous) noAdj.push(t.axis);
|
||||
TR[t.axis] = { lo: a ? a[0] : t.lo, hi: a ? a[1] : t.hi, continuous: !!t.continuous };
|
||||
}
|
||||
/* TCP 高度:J6 组内实打印件(排除 ENV_)顶点的最小查看器 y,查看器 y = CAD z。
|
||||
与 ik-glue.js:17-27 同语义:只有真找到才覆盖默认值 93,不是拿 93 当下界。 */
|
||||
let tcpZ = 93, loFound = Infinity;
|
||||
for (const p of mesh.parts) {
|
||||
if (p.grp !== 'J6' || !p.printed || String(p.name).slice(0, 4) === 'ENV_') continue;
|
||||
if (!p.v || !p.v.length) continue;
|
||||
for (const q of p.v) loFound = Math.min(loFound, q[2]);
|
||||
}
|
||||
if (isFinite(loFound)) tcpZ = loFound;
|
||||
const TCP0 = [JJ.J6.rear[0], JJ.J6.rear[1], tcpZ];
|
||||
|
||||
const S = ArmIK.make({ joints: JMap, travel: TR, tcp: TCP0, collide: COL });
|
||||
const ORDER = ArmIK.ORDER;
|
||||
|
||||
/* selfTest/poseSelfTest 内部用 Math.random(),不锁种子的话两次跑的误差数字就不同,
|
||||
关卡会退化成"看大概"。这里换成定LCG,让 exact 段逐字节可复现。 */
|
||||
const _rand = Math.random;
|
||||
function seeded(seed, fn) {
|
||||
let s = seed >>> 0;
|
||||
Math.random = () => { s = (s * 1664525 + 1013904223) >>> 0; return s / 4294967296; };
|
||||
try { return fn(); } finally { Math.random = _rand; }
|
||||
}
|
||||
|
||||
const parts = mesh.parts;
|
||||
const r6 = v => +v.toFixed(6);
|
||||
|
||||
/* ---- 固定输入(不含随机)的可复现输出 ---- */
|
||||
const Q0 = [10, -20, 30, 40, -50, 15];
|
||||
const zeros = ORDER.map(() => 0);
|
||||
const targets = [[150, 128, 260], [180, 128, 300], [120, -150, 320], [60, 128, 420]];
|
||||
|
||||
const solveRuns = targets.map(T => {
|
||||
const xs = [];
|
||||
for (let k = 0; k < 9; k++) {
|
||||
const t0 = performance.now();
|
||||
const r = S.solveDyn(T.slice(), { tool: 0, step: 0.25, ref: zeros, from: zeros.slice() });
|
||||
xs.push({ ms: performance.now() - t0, q: r && r.q ? r.q.map(v => +v.toFixed(3)) : null,
|
||||
ok: !!(r && r.q), err: r && r.err != null ? +r.err.toFixed(9) : null });
|
||||
}
|
||||
/* 头 3 次是 JIT 预热,留中位数也去不掉进程间的预热差;实测取 9 次里后 6 次的中位,
|
||||
自比抖动从 >50% 降到可直接判定的量级。 */
|
||||
const warm = xs.slice(3).sort((a, b) => a.ms - b.ms);
|
||||
const m = warm[Math.floor(warm.length / 2)];
|
||||
return { T, medianMs: +m.ms.toFixed(2), q: m.q, ok: m.ok, err: m.err };
|
||||
});
|
||||
|
||||
const st = seeded(20261015, () => S.selfTest(400, 8));
|
||||
const pst = seeded(777, () => S.poseSelfTest(8));
|
||||
|
||||
const exact = {
|
||||
counts: {
|
||||
parts: parts.length,
|
||||
verts: parts.reduce((n, p) => n + ((p.v && p.v.length) || 0), 0),
|
||||
tris: parts.reduce((n, p) => n + ((p.t && p.t.length) || 0), 0),
|
||||
printed: parts.filter(p => p.printed).length,
|
||||
env: parts.filter(p => String(p.name).startsWith('ENV_')).length,
|
||||
joints: JO.length,
|
||||
},
|
||||
tcpZ: +tcpZ.toFixed(3),
|
||||
TCP0: TCP0.map(v => +v.toFixed(3)),
|
||||
motorTravel: MOTOR,
|
||||
noAdjAxes: noAdj,
|
||||
caps: COL ? COL.caps.length : 0,
|
||||
lim: Object.fromEntries(ORDER.map(id => [id, [r6(S.LIM[id].lo), r6(S.LIM[id].hi), !!S.LIM[id].cont]])),
|
||||
fkQ0: S.fk(Q0, 0).map(r6),
|
||||
fkChainQ0: S.fkChain(Q0, 0).map(r6),
|
||||
orientQ0: S.orient(Q0).map(r6),
|
||||
solveDyn: solveRuns.map(r => ({ T: r.T, ok: r.ok, err: r.err, q: r.q })),
|
||||
selfTest: { maxFkErr: st.maxFkErr, maxIkErr: st.maxIkErr, ikHit: st.ikHit, ikTried: st.ikTried,
|
||||
structWarn: st.structWarn, poseHit: st.poseHit, poseTried: st.poseTried,
|
||||
poseErr: st.poseErr, K: st.K, LIM: st.LIM },
|
||||
poseSelfTest: { poseHit: pst.poseHit, poseTried: pst.poseTried, poseErr: pst.poseErr },
|
||||
};
|
||||
const timing = {
|
||||
solveDynMedianMs: solveRuns.map(r => r.medianMs),
|
||||
poseSelfTestAvgMs: +pst.poseMs.toFixed(2),
|
||||
};
|
||||
|
||||
const doc = { meta: { solver: path.relative(ROOT, SOLVER).replace(/\\/g, '/'),
|
||||
mesh: path.relative(ROOT, MESH).replace(/\\/g, '/') },
|
||||
exact, timing };
|
||||
const text = JSON.stringify(doc, null, 1);
|
||||
|
||||
const out = argVal('out', null);
|
||||
if (out) fs.writeFileSync(out, text + '\n');
|
||||
|
||||
const base = argVal('compare', null);
|
||||
if (!base) { if (!out) console.log(text); process.exit(0); }
|
||||
|
||||
const b = JSON.parse(fs.readFileSync(base, 'utf8'));
|
||||
const diffs = [];
|
||||
(function walk(x, y, p) {
|
||||
if (x === null || y === null || typeof x !== 'object' || typeof y !== 'object') {
|
||||
if (JSON.stringify(x) !== JSON.stringify(y)) diffs.push(p + ': ' + JSON.stringify(y) + ' -> ' + JSON.stringify(x));
|
||||
return;
|
||||
}
|
||||
for (const k of new Set([...Object.keys(x), ...Object.keys(y)])) walk(x[k], y[k], p ? p + '.' + k : k);
|
||||
})(doc.exact, b.exact, '');
|
||||
|
||||
console.log('== exact(必须逐字节相同)==');
|
||||
console.log(diffs.length ? diffs.map(d => ' DIFF ' + d).join('\n') : ' 全部一致 ✓');
|
||||
console.log('== timing(±10% 只报 WARN)==');
|
||||
const tb = b.timing;
|
||||
let warn = 0;
|
||||
doc.timing.solveDynMedianMs.forEach((v, i) => {
|
||||
const o = tb.solveDynMedianMs[i];
|
||||
const d = (v - o) / o * 100;
|
||||
if (Math.abs(d) > 10) { warn++; console.log(` WARN solveDyn#${i}: ${o} -> ${v} ms (${d.toFixed(1)}%)`); }
|
||||
else console.log(` ok solveDyn#${i}: ${o} -> ${v} ms (${d.toFixed(1)}%)`);
|
||||
});
|
||||
if (diffs.length) { console.log('RESULT: FAIL(exact 有 %d 处差异)', diffs.length); process.exit(1); }
|
||||
console.log('RESULT: PASS' + (warn ? `(timing ${warn} 项超 ±10%,需人判)` : ''));
|
||||