function fig_replay(name) %FIG_REPLAY 回放画布(点运动图):世界视图 + 事件流水 + 虚拟时间轴。 % name: 'replay_q3' 或 'replay_q4',对应 docs/figures/.data/.mat。 % 本图是唯一保留自定义画布版式的图:三个区互不重叠,图例置于世界视图下方。 if nargin < 1 name = 'replay_q3'; end S = fig_style(); D = load_data(S, name); H = geom_helpers(); fig = figure('Color', 'w', 'Visible', 'off', 'Position', [100 100 1040 660]); c_path = [0.35 0.35 0.35]; c_ray = pick_color(S, 'primary'); c_solved = pick_color(S, 'success'); c_unsolv = pick_color(S, 'accent'); c_head = pick_color(S, 'violet'); % ---------------- 世界视图 ---------------- ax = axes(fig, 'Position', [0.075 0.40 0.49 0.56]); hold(ax, 'on'); H.circle(ax, [0 0], D.omega_r, pick_color(S, 'primary'), 1.2, '-'); h_path = plot(ax, D.path(:, 1), D.path(:, 2), 'Color', c_path, 'LineWidth', 0.9); h_ray = plot(ax, nan, nan, 'Color', c_ray, 'LineWidth', 0.8); for i = 1:size(D.rays, 1) p0 = D.rays(i, 1:2); p1 = p0 + D.rays(i, 3:4); plot(ax, [p0(1) p1(1)], [p0(2) p1(2)], 'Color', c_ray, 'LineWidth', 0.8); end h_disk = gobjects(0); for i = 1:size(D.half_disks, 1) disk = squeeze(D.half_disks(i, :, :)); h_disk(end + 1) = patch(ax, 'XData', disk(:, 1), 'YData', disk(:, 2), ... 'FaceColor', c_head, 'FaceAlpha', 0.10, ... 'EdgeColor', c_head, 'LineWidth', 0.8); %#ok end for i = 1:size(D.headings, 1) p0 = D.headings(i, 1:2); p1 = p0 + D.headings(i, 3:4); H.arrow(ax, p0, p1, c_head); end solved = D.truth_solved > 0.5; h_solved = plot(ax, D.truth(solved, 1), D.truth(solved, 2), 'o', ... 'MarkerSize', 6, 'MarkerFaceColor', c_solved, 'MarkerEdgeColor', 'none'); h_unsolv = plot(ax, D.truth(~solved, 1), D.truth(~solved, 2), 'o', ... 'MarkerSize', 6, 'MarkerFaceColor', c_unsolv, 'MarkerEdgeColor', 'none'); label_color = repmat(c_unsolv, size(D.truth, 1), 1); label_color(solved, :) = repmat(c_solved, nnz(solved), 1); H.label_points(ax, D.truth, D.truth_labels, label_color); plot(ax, D.clears(D.clears(:, 3) > 0.5, 1), D.clears(D.clears(:, 3) > 0.5, 2), ... 'x', 'MarkerSize', 7, 'LineWidth', 1.4, 'Color', c_solved); plot(ax, D.clears(D.clears(:, 3) <= 0.5, 1), D.clears(D.clears(:, 3) <= 0.5, 2), ... 'o', 'MarkerSize', 6, 'MarkerEdgeColor', 'k', 'MarkerFaceColor', 'none'); hold(ax, 'off'); axis(ax, 'equal'); xlim(ax, [-D.half, D.half]); ylim(ax, [-D.half, D.half]); xlabel(ax, 'x / m'); ylabel(ax, 'y / m'); hleg = [h_path, h_ray]; if ~isempty(h_disk) hleg(end + 1) = h_disk(1); end hleg = [hleg, h_solved, h_unsolv]; legend(ax, hleg, D.legend, 'Location', 'southoutside', 'Orientation', 'horizontal'); % ---------------- 事件流水 ---------------- ex = axes(fig, 'Position', [0.625 0.40 0.345 0.56], ... 'XLim', [0 1], 'YLim', [0 1], 'Visible', 'off'); hold(ex, 'on'); cols = [0.00 0.34 1.00]; align = {'left', 'left', 'right'}; head = {'动作', '参数', 't / s'}; for j = 1:3 text(ex, cols(j), 0.97, head{j}, 'FontWeight', 'bold', ... 'HorizontalAlignment', align{j}); end for i = 1:size(D.events, 1) y = 0.90 - (i - 1) * 0.088; for j = 1:3 text(ex, cols(j), y, D.events{i, j}, 'HorizontalAlignment', align{j}, ... 'Interpreter', 'none'); end end hold(ex, 'off'); % ---------------- 虚拟时间轴 ---------------- tx = axes(fig, 'Position', [0.075 0.155 0.90 0.125]); hold(tx, 'on'); rectangle(tx, 'Position', [0 0.34 D.total_s 0.32], ... 'FaceColor', pick_color(S, 'primary'), 'FaceAlpha', 0.12, ... 'EdgeColor', 'none'); for i = 1:size(D.marks, 1) t = D.marks(i, 1); if D.marks(i, 3) > 0.5 plot(tx, [t t], [0.05 0.95], 'Color', c_solved, 'LineWidth', 1.0); elseif D.marks(i, 2) > 0.5 plot(tx, [t t], [0.22 0.78], 'Color', c_unsolv, 'LineWidth', 0.8); end end hold(tx, 'off'); xlim(tx, [0 D.total_s]); ylim(tx, [0 1]); set(tx, 'YTick', []); xlabel(tx, '虚拟时间 t / s'); fig_save(fig, S, D.out_png{1}); end