diff --git a/docs/shots/01_iso.png b/docs/shots/01_iso.png index f0a06d3..6ffa433 100644 Binary files a/docs/shots/01_iso.png and b/docs/shots/01_iso.png differ diff --git a/docs/shots/02_front.png b/docs/shots/02_front.png index 6afff05..c1f0b8d 100644 Binary files a/docs/shots/02_front.png and b/docs/shots/02_front.png differ diff --git a/docs/shots/03_side.png b/docs/shots/03_side.png index 96d4cc8..70f2ae9 100644 Binary files a/docs/shots/03_side.png and b/docs/shots/03_side.png differ diff --git a/docs/shots/04_top.png b/docs/shots/04_top.png index 99138d7..cc85669 100644 Binary files a/docs/shots/04_top.png and b/docs/shots/04_top.png differ diff --git a/docs/shots/05_exploded.png b/docs/shots/05_exploded.png index fee936e..ecb5e75 100644 Binary files a/docs/shots/05_exploded.png and b/docs/shots/05_exploded.png differ diff --git a/docs/shots/06_wrist.png b/docs/shots/06_wrist.png index 04b14b0..5f9339d 100644 Binary files a/docs/shots/06_wrist.png and b/docs/shots/06_wrist.png differ diff --git a/docs/shots/07_joint.png b/docs/shots/07_joint.png index 0a33790..690df83 100644 Binary files a/docs/shots/07_joint.png and b/docs/shots/07_joint.png differ diff --git a/docs/shots/08_pose.png b/docs/shots/08_pose.png index 9990244..94b545a 100644 Binary files a/docs/shots/08_pose.png and b/docs/shots/08_pose.png differ diff --git a/docs/shots/09_sheet.png b/docs/shots/09_sheet.png index a0e8e09..6ffa433 100644 Binary files a/docs/shots/09_sheet.png and b/docs/shots/09_sheet.png differ diff --git a/docs/shots/10_solid.png b/docs/shots/10_solid.png index a0e8e09..6ffa433 100644 Binary files a/docs/shots/10_solid.png and b/docs/shots/10_solid.png differ diff --git a/docs/shots/11_tool_flange.png b/docs/shots/11_tool_flange.png index 0655304..7b13fcd 100644 Binary files a/docs/shots/11_tool_flange.png and b/docs/shots/11_tool_flange.png differ diff --git a/docs/shots/12_elbow_flare.png b/docs/shots/12_elbow_flare.png index 8001ea4..eac4186 100644 Binary files a/docs/shots/12_elbow_flare.png and b/docs/shots/12_elbow_flare.png differ diff --git a/docs/shots/13_forearm_side.png b/docs/shots/13_forearm_side.png index 22ca961..f0dc076 100644 Binary files a/docs/shots/13_forearm_side.png and b/docs/shots/13_forearm_side.png differ diff --git a/docs/shots/bay_p04_inside.png b/docs/shots/bay_p04_inside.png index 9334e46..81bd559 100644 Binary files a/docs/shots/bay_p04_inside.png and b/docs/shots/bay_p04_inside.png differ diff --git a/docs/shots/bay_p06_inside.png b/docs/shots/bay_p06_inside.png index 4b3db59..e277d38 100644 Binary files a/docs/shots/bay_p06_inside.png and b/docs/shots/bay_p06_inside.png differ diff --git a/docs/shots/bay_p07_inside.png b/docs/shots/bay_p07_inside.png index 794db32..8cfe1ef 100644 Binary files a/docs/shots/bay_p07_inside.png and b/docs/shots/bay_p07_inside.png differ diff --git a/docs/shots/bay_p08_inside.png b/docs/shots/bay_p08_inside.png index 419248c..a8455ae 100644 Binary files a/docs/shots/bay_p08_inside.png and b/docs/shots/bay_p08_inside.png differ diff --git a/docs/shots/boss_p04.png b/docs/shots/boss_p04.png index 6752b12..bb2dfa3 100644 Binary files a/docs/shots/boss_p04.png and b/docs/shots/boss_p04.png differ diff --git a/docs/shots/boss_p05.png b/docs/shots/boss_p05.png index 2bb49d6..48257c7 100644 Binary files a/docs/shots/boss_p05.png and b/docs/shots/boss_p05.png differ diff --git a/docs/shots/boss_p06.png b/docs/shots/boss_p06.png index ad8f976..94d1268 100644 Binary files a/docs/shots/boss_p06.png and b/docs/shots/boss_p06.png differ diff --git a/docs/shots/boss_p07.png b/docs/shots/boss_p07.png index 580a661..5dfaf44 100644 Binary files a/docs/shots/boss_p07.png and b/docs/shots/boss_p07.png differ diff --git a/docs/shots/harness_full_iso.png b/docs/shots/harness_full_iso.png index 61df2ee..6ffa433 100644 Binary files a/docs/shots/harness_full_iso.png and b/docs/shots/harness_full_iso.png differ diff --git a/docs/shots/harness_overview.png b/docs/shots/harness_overview.png index cc3c82e..8f07998 100644 Binary files a/docs/shots/harness_overview.png and b/docs/shots/harness_overview.png differ diff --git a/docs/shots/harness_p04_p05.png b/docs/shots/harness_p04_p05.png index 0550639..3efea81 100644 Binary files a/docs/shots/harness_p04_p05.png and b/docs/shots/harness_p04_p05.png differ diff --git a/docs/shots/harness_p04_p05_xray.png b/docs/shots/harness_p04_p05_xray.png index 62feef3..d85a02b 100644 Binary files a/docs/shots/harness_p04_p05_xray.png and b/docs/shots/harness_p04_p05_xray.png differ diff --git a/docs/shots/harness_p06_window.png b/docs/shots/harness_p06_window.png index 46a3242..c439284 100644 Binary files a/docs/shots/harness_p06_window.png and b/docs/shots/harness_p06_window.png differ diff --git a/docs/shots/harness_p07_window.png b/docs/shots/harness_p07_window.png index dcd2be8..e81ea5f 100644 Binary files a/docs/shots/harness_p07_window.png and b/docs/shots/harness_p07_window.png differ diff --git a/docs/shots/harness_p07_xray.png b/docs/shots/harness_p07_xray.png index ad049ca..c973099 100644 Binary files a/docs/shots/harness_p07_xray.png and b/docs/shots/harness_p07_xray.png differ diff --git a/docs/shots/harness_xray_full.png b/docs/shots/harness_xray_full.png index 61df2ee..181b789 100644 Binary files a/docs/shots/harness_xray_full.png and b/docs/shots/harness_xray_full.png differ diff --git a/docs/shots/harness_xray_internal.png b/docs/shots/harness_xray_internal.png index 6114a22..0209c78 100644 Binary files a/docs/shots/harness_xray_internal.png and b/docs/shots/harness_xray_internal.png differ diff --git a/docs/shots/hollow_p04_iso.png b/docs/shots/hollow_p04_iso.png index 38cd6f7..da5d5ca 100644 Binary files a/docs/shots/hollow_p04_iso.png and b/docs/shots/hollow_p04_iso.png differ diff --git a/docs/shots/hollow_p04_top.png b/docs/shots/hollow_p04_top.png index e925c59..36c817a 100644 Binary files a/docs/shots/hollow_p04_top.png and b/docs/shots/hollow_p04_top.png differ diff --git a/docs/shots/hollow_p06_iso.png b/docs/shots/hollow_p06_iso.png index 3f26286..1f67afc 100644 Binary files a/docs/shots/hollow_p06_iso.png and b/docs/shots/hollow_p06_iso.png differ diff --git a/docs/shots/hollow_p07_iso.png b/docs/shots/hollow_p07_iso.png index 6abfbe6..5d442d6 100644 Binary files a/docs/shots/hollow_p07_iso.png and b/docs/shots/hollow_p07_iso.png differ diff --git a/docs/shots/hollow_p07_top.png b/docs/shots/hollow_p07_top.png index ddb8b9b..a8337f3 100644 Binary files a/docs/shots/hollow_p07_top.png and b/docs/shots/hollow_p07_top.png differ diff --git a/docs/shots/j3_前端压盖_全件.png b/docs/shots/j3_前端压盖_全件.png index c8e83fc..d2756db 100644 Binary files a/docs/shots/j3_前端压盖_全件.png and b/docs/shots/j3_前端压盖_全件.png differ diff --git a/docs/shots/j3_前端压盖_装配.png b/docs/shots/j3_前端压盖_装配.png index 7c890c2..f685171 100644 Binary files a/docs/shots/j3_前端压盖_装配.png and b/docs/shots/j3_前端压盖_装配.png differ diff --git a/docs/shots/p03_light_iso.png b/docs/shots/p03_light_iso.png index a3ad605..2d1e44c 100644 Binary files a/docs/shots/p03_light_iso.png and b/docs/shots/p03_light_iso.png differ diff --git a/docs/shots/p03_light_join.png b/docs/shots/p03_light_join.png index 778a437..3224f1c 100644 Binary files a/docs/shots/p03_light_join.png and b/docs/shots/p03_light_join.png differ diff --git a/docs/shots/p03_light_rear.png b/docs/shots/p03_light_rear.png index 1286557..dd6f95d 100644 Binary files a/docs/shots/p03_light_rear.png and b/docs/shots/p03_light_rear.png differ diff --git a/docs/shots/p03_light_side.png b/docs/shots/p03_light_side.png index 80f3d80..97309ae 100644 Binary files a/docs/shots/p03_light_side.png and b/docs/shots/p03_light_side.png differ diff --git a/docs/shots/p03_light_xray.png b/docs/shots/p03_light_xray.png index a3ad605..ecda685 100644 Binary files a/docs/shots/p03_light_xray.png and b/docs/shots/p03_light_xray.png differ diff --git a/docs/shots/p03_mount_iso.png b/docs/shots/p03_mount_iso.png index 501a7ca..760867b 100644 Binary files a/docs/shots/p03_mount_iso.png and b/docs/shots/p03_mount_iso.png differ diff --git a/docs/shots/p03_mount_loose.png b/docs/shots/p03_mount_loose.png index 1c6f722..b91945c 100644 Binary files a/docs/shots/p03_mount_loose.png and b/docs/shots/p03_mount_loose.png differ diff --git a/docs/shots/p03_mount_top.png b/docs/shots/p03_mount_top.png index 972f6b1..8a32c9b 100644 Binary files a/docs/shots/p03_mount_top.png and b/docs/shots/p03_mount_top.png differ diff --git a/docs/shots/p04_both_ends.png b/docs/shots/p04_both_ends.png index f758e8f..fc2a190 100644 Binary files a/docs/shots/p04_both_ends.png and b/docs/shots/p04_both_ends.png differ diff --git a/docs/shots/p04_m2_side.png b/docs/shots/p04_m2_side.png index a1662b2..75c6894 100644 Binary files a/docs/shots/p04_m2_side.png and b/docs/shots/p04_m2_side.png differ diff --git a/docs/shots/p05_flank_view.png b/docs/shots/p05_flank_view.png index f522a78..21ea9bc 100644 Binary files a/docs/shots/p05_flank_view.png and b/docs/shots/p05_flank_view.png differ diff --git a/docs/shots/p05_m3_side.png b/docs/shots/p05_m3_side.png index d6142f6..fc6e464 100644 Binary files a/docs/shots/p05_m3_side.png and b/docs/shots/p05_m3_side.png differ diff --git a/docs/shots/p06_m4_side.png b/docs/shots/p06_m4_side.png index 938987d..d8109ef 100644 Binary files a/docs/shots/p06_m4_side.png and b/docs/shots/p06_m4_side.png differ diff --git a/docs/shots/p07_m5_side.png b/docs/shots/p07_m5_side.png index c8c8ca7..eccfa34 100644 Binary files a/docs/shots/p07_m5_side.png and b/docs/shots/p07_m5_side.png differ diff --git a/docs/shots/shot_p08_user.png b/docs/shots/shot_p08_user.png index a722068..b6d2fb5 100644 Binary files a/docs/shots/shot_p08_user.png and b/docs/shots/shot_p08_user.png differ diff --git a/docs/shots/svg_exploded.png b/docs/shots/svg_exploded.png index 89b48a8..7fbb9bb 100644 Binary files a/docs/shots/svg_exploded.png and b/docs/shots/svg_exploded.png differ diff --git a/docs/shots/svg_joint.png b/docs/shots/svg_joint.png index 449abf1..60e410d 100644 Binary files a/docs/shots/svg_joint.png and b/docs/shots/svg_joint.png differ diff --git a/docs/shots/svg_side.png b/docs/shots/svg_side.png index d92f955..315e231 100644 Binary files a/docs/shots/svg_side.png and b/docs/shots/svg_side.png differ diff --git a/docs/shots/tie_probe_negY.png b/docs/shots/tie_probe_negY.png index fb8fd09..8a471fa 100644 Binary files a/docs/shots/tie_probe_negY.png and b/docs/shots/tie_probe_negY.png differ diff --git a/docs/shots/tie_probe_posY.png b/docs/shots/tie_probe_posY.png index fd3cd69..64673f3 100644 Binary files a/docs/shots/tie_probe_posY.png and b/docs/shots/tie_probe_posY.png differ diff --git a/docs/shots/user_circle_check.png b/docs/shots/user_circle_check.png index 77aa136..1b6637c 100644 Binary files a/docs/shots/user_circle_check.png and b/docs/shots/user_circle_check.png differ diff --git a/docs/shots/user_compare_view.png b/docs/shots/user_compare_view.png index 17e621e..29f762b 100644 Binary files a/docs/shots/user_compare_view.png and b/docs/shots/user_compare_view.png differ diff --git a/docs/shots/user_contour_harness.png b/docs/shots/user_contour_harness.png index 8112974..0a6b224 100644 Binary files a/docs/shots/user_contour_harness.png and b/docs/shots/user_contour_harness.png differ diff --git a/docs/shots/user_elbow_front.png b/docs/shots/user_elbow_front.png index 71768b5..c22960e 100644 Binary files a/docs/shots/user_elbow_front.png and b/docs/shots/user_elbow_front.png differ diff --git a/docs/shots/user_elbow_rear.png b/docs/shots/user_elbow_rear.png index fd9c5a5..ae824a3 100644 Binary files a/docs/shots/user_elbow_rear.png and b/docs/shots/user_elbow_rear.png differ diff --git a/docs/shots/user_exact_view.png b/docs/shots/user_exact_view.png index e10e0b4..1defe62 100644 Binary files a/docs/shots/user_exact_view.png and b/docs/shots/user_exact_view.png differ diff --git a/docs/shots/user_fork_fixed.png b/docs/shots/user_fork_fixed.png index 777ad34..088497d 100644 Binary files a/docs/shots/user_fork_fixed.png and b/docs/shots/user_fork_fixed.png differ diff --git a/docs/shots/user_harness_view.png b/docs/shots/user_harness_view.png index aff74d1..535eec4 100644 Binary files a/docs/shots/user_harness_view.png and b/docs/shots/user_harness_view.png differ diff --git a/docs/shots/user_harness_zoom.png b/docs/shots/user_harness_zoom.png index df604d0..842313d 100644 Binary files a/docs/shots/user_harness_zoom.png and b/docs/shots/user_harness_zoom.png differ diff --git a/docs/shots/user_m1_bypass_oblique.png b/docs/shots/user_m1_bypass_oblique.png index f551bed..46cf5db 100644 Binary files a/docs/shots/user_m1_bypass_oblique.png and b/docs/shots/user_m1_bypass_oblique.png differ diff --git a/docs/shots/user_m1_exact.png b/docs/shots/user_m1_exact.png index 65e4166..e937fcd 100644 Binary files a/docs/shots/user_m1_exact.png and b/docs/shots/user_m1_exact.png differ diff --git a/docs/shots/user_m1_rear.png b/docs/shots/user_m1_rear.png index 38e252e..2eabb1d 100644 Binary files a/docs/shots/user_m1_rear.png and b/docs/shots/user_m1_rear.png differ diff --git a/docs/shots/user_p04.png b/docs/shots/user_p04.png index 0fab77b..84b3dea 100644 Binary files a/docs/shots/user_p04.png and b/docs/shots/user_p04.png differ diff --git a/docs/shots/user_p04_bottom.png b/docs/shots/user_p04_bottom.png index 6ac21e6..d9ade52 100644 Binary files a/docs/shots/user_p04_bottom.png and b/docs/shots/user_p04_bottom.png differ diff --git a/docs/shots/user_p04_bottom2.png b/docs/shots/user_p04_bottom2.png index c7dc898..df7c32b 100644 Binary files a/docs/shots/user_p04_bottom2.png and b/docs/shots/user_p04_bottom2.png differ diff --git a/docs/shots/user_p04_opp.png b/docs/shots/user_p04_opp.png index 8e8e6af..ff36237 100644 Binary files a/docs/shots/user_p04_opp.png and b/docs/shots/user_p04_opp.png differ diff --git a/docs/shots/user_p04_side.png b/docs/shots/user_p04_side.png index cb2aab6..9183250 100644 Binary files a/docs/shots/user_p04_side.png and b/docs/shots/user_p04_side.png differ diff --git a/docs/shots/user_p06_xz.png b/docs/shots/user_p06_xz.png index fc4d45d..e4fee19 100644 Binary files a/docs/shots/user_p06_xz.png and b/docs/shots/user_p06_xz.png differ diff --git a/docs/shots/user_p06_yz.png b/docs/shots/user_p06_yz.png index aaa8d51..435eca6 100644 Binary files a/docs/shots/user_p06_yz.png and b/docs/shots/user_p06_yz.png differ diff --git a/docs/shots/user_p07_check.png b/docs/shots/user_p07_check.png index 8df251c..8c1e56b 100644 Binary files a/docs/shots/user_p07_check.png and b/docs/shots/user_p07_check.png differ diff --git a/docs/shots/user_p07_creases.png b/docs/shots/user_p07_creases.png index 34f1fe8..09e4844 100644 Binary files a/docs/shots/user_p07_creases.png and b/docs/shots/user_p07_creases.png differ diff --git a/docs/shots/user_p07_wrist.png b/docs/shots/user_p07_wrist.png index 9961e96..a8cecc7 100644 Binary files a/docs/shots/user_p07_wrist.png and b/docs/shots/user_p07_wrist.png differ diff --git a/docs/shots/user_shoulder_solid.png b/docs/shots/user_shoulder_solid.png index 88b9e45..faafd32 100644 Binary files a/docs/shots/user_shoulder_solid.png and b/docs/shots/user_shoulder_solid.png differ diff --git a/docs/shots/user_shoulder_top.png b/docs/shots/user_shoulder_top.png index a1aec9a..3cdf572 100644 Binary files a/docs/shots/user_shoulder_top.png and b/docs/shots/user_shoulder_top.png differ diff --git a/docs/shots/user_shoulder_xray.png b/docs/shots/user_shoulder_xray.png index 88b9e45..faafd32 100644 Binary files a/docs/shots/user_shoulder_xray.png and b/docs/shots/user_shoulder_xray.png differ diff --git a/docs/shots/user_smooth_harness.png b/docs/shots/user_smooth_harness.png index 4c777b7..1ae8fc4 100644 Binary files a/docs/shots/user_smooth_harness.png and b/docs/shots/user_smooth_harness.png differ diff --git a/docs/shots/user_target.png b/docs/shots/user_target.png index 107bcd9..015e3bb 100644 Binary files a/docs/shots/user_target.png and b/docs/shots/user_target.png differ diff --git a/docs/shots/user_view1.png b/docs/shots/user_view1.png index baaf7e1..668e180 100644 Binary files a/docs/shots/user_view1.png and b/docs/shots/user_view1.png differ diff --git a/docs/shots/user_view2.png b/docs/shots/user_view2.png index 5c295f7..32e8a08 100644 Binary files a/docs/shots/user_view2.png and b/docs/shots/user_view2.png differ diff --git a/docs/shots/view_iso_forearm.png b/docs/shots/view_iso_forearm.png index b7970c7..8a0913b 100644 Binary files a/docs/shots/view_iso_forearm.png and b/docs/shots/view_iso_forearm.png differ diff --git a/docs/shots/view_yz_neg_x.png b/docs/shots/view_yz_neg_x.png index a089887..d1210ef 100644 Binary files a/docs/shots/view_yz_neg_x.png and b/docs/shots/view_yz_neg_x.png differ diff --git a/docs/shots/view_yz_pos_x.png b/docs/shots/view_yz_pos_x.png index cd96098..f101c46 100644 Binary files a/docs/shots/view_yz_pos_x.png and b/docs/shots/view_yz_pos_x.png differ diff --git a/docs/shots/zoom_user.png b/docs/shots/zoom_user.png index bea2e58..f57a5d0 100644 Binary files a/docs/shots/zoom_user.png and b/docs/shots/zoom_user.png differ diff --git a/tests/baselines/data_by_name.md5 b/tests/baselines/data_by_name.md5 new file mode 100644 index 0000000..4889ee9 --- /dev/null +++ b/tests/baselines/data_by_name.md5 @@ -0,0 +1,6 @@ +533c100b58b33c0317de179f65c5c681 travel.json +c66c230557548bd03f003bb4bd52ff6a travel_detail.json +4a8f14be95ed32121166a9bd37e74752 collide.json +82f8fa459be497ae0cfc92d5816497bf screws.json +83dfad6817c766ee893f54cca8fa7774 mesh_arm.json +f74cf5148cfc03c2d785829f45a608f9 sheets.jsdata diff --git a/tests/baselines/ik_exact.json b/tests/baselines/ik_exact.json new file mode 100644 index 0000000..ec02548 --- /dev/null +++ b/tests/baselines/ik_exact.json @@ -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 + } +} diff --git a/tests/baselines/shots.md5 b/tests/baselines/shots.md5 new file mode 100644 index 0000000..e382bbd --- /dev/null +++ b/tests/baselines/shots.md5 @@ -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 diff --git a/tests/ik_baseline.mjs b/tests/ik_baseline.mjs new file mode 100644 index 0000000..07b9255 --- /dev/null +++ b/tests/ik_baseline.mjs @@ -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%,需人判)` : ''));