function petriNetGuiDemo %PETRINETGUIDEMO Simple GUI tutorial for a Petri net. % Run: % petriNetGuiDemo places = ["Ready", "InService", "Done"]; transitions = ["Start", "Finish"]; % pre(:,j) = tokens consumed by transition j pre = [1 0; 0 1; 0 0]; % post(:,j) = tokens produced by transition j post = [0 0; 1 0; 0 1]; initialMarking = [3; 0; 0]; marking = initialMarking; stepCount = 0; maxSteps = 20; placePos = [1 0; 5 0; 9 0]; transPos = [3 0; 7 0]; placeR = 0.75; transW = 0.55; transH = 1.45; fig = figure( ... 'Name', 'Petri Net Tutorial', ... 'Color', 'w', ... 'MenuBar', 'none', ... 'ToolBar', 'none', ... 'NumberTitle', 'off', ... 'Position', [100 100 1120 640]); ax = axes('Parent', fig, 'Position', [0.04 0.18 0.92 0.78]); hold(ax, 'on'); axis(ax, [-0.5 10.5 -2.4 2.4]); axis(ax, 'equal'); axis(ax, 'off'); statusText = uicontrol( ... 'Style', 'text', ... 'Parent', fig, ... 'Units', 'normalized', ... 'Position', [0.04 0.04 0.92 0.08], ... 'BackgroundColor', 'w', ... 'HorizontalAlignment', 'left', ... 'FontSize', 11, ... 'String', ''); btnStep = uicontrol(fig, 'Style', 'pushbutton', 'Units', 'normalized', ... 'Position', [0.04 0.11 0.10 0.05], 'String', 'Step', ... 'FontSize', 10, 'Callback', @onStep); btnStart = uicontrol(fig, 'Style', 'pushbutton', 'Units', 'normalized', ... 'Position', [0.16 0.11 0.10 0.05], 'String', 'Fire Start', ... 'FontSize', 10, 'Callback', @(~,~) fireTransition(1, true)); btnFinish = uicontrol(fig, 'Style', 'pushbutton', 'Units', 'normalized', ... 'Position', [0.28 0.11 0.10 0.05], 'String', 'Fire Finish', ... 'FontSize', 10, 'Callback', @(~,~) fireTransition(2, true)); btnRun = uicontrol(fig, 'Style', 'pushbutton', 'Units', 'normalized', ... 'Position', [0.40 0.11 0.10 0.05], 'String', 'Run', ... 'FontSize', 10, 'Callback', @onRun); btnReset = uicontrol(fig, 'Style', 'pushbutton', 'Units', 'normalized', ... 'Position', [0.52 0.11 0.10 0.05], 'String', 'Reset', ... 'FontSize', 10, 'Callback', @onReset); transitionPatch = gobjects(numel(transitions), 1); countText = gobjects(numel(places), 1); drawStaticNet(); renderTokens(); updateUI(); function drawStaticNet % Arcs line(ax, [placePos(1,1) + placeR, transPos(1,1) - transW/2], [0 0], ... 'Color', [0 0 0], 'LineWidth', 1.5); line(ax, [transPos(1,1) + transW/2, placePos(2,1) - placeR], [0 0], ... 'Color', [0 0 0], 'LineWidth', 1.5); line(ax, [placePos(2,1) + placeR, transPos(2,1) - transW/2], [0 0], ... 'Color', [0 0 0], 'LineWidth', 1.5); line(ax, [transPos(2,1) + transW/2, placePos(3,1) - placeR], [0 0], ... 'Color', [0 0 0], 'LineWidth', 1.5); % Places for i = 1:numel(places) rectangle(ax, ... 'Position', [placePos(i,1) - placeR, placePos(i,2) - placeR, 2*placeR, 2*placeR], ... 'Curvature', [1 1], ... 'EdgeColor', 'k', ... 'LineWidth', 2, ... 'FaceColor', 'w'); text(ax, placePos(i,1), -1.20, places(i), ... 'HorizontalAlignment', 'center', ... 'FontSize', 11, ... 'FontWeight', 'bold'); countText(i) = text(ax, placePos(i,1), 1.20, '', ... 'HorizontalAlignment', 'center', ... 'FontSize', 10, ... 'FontWeight', 'bold'); end % Transitions for i = 1:numel(transitions) transitionPatch(i) = rectangle(ax, ... 'Position', [transPos(i,1) - transW/2, transPos(i,2) - transH/2, transW, transH], ... 'EdgeColor', 'k', ... 'LineWidth', 2, ... 'FaceColor', [0.85 0.85 0.85]); text(ax, transPos(i,1), -1.20, transitions(i), ... 'HorizontalAlignment', 'center', ... 'FontSize', 11, ... 'FontWeight', 'bold'); end text(ax, 5, 1.95, 'Simple Petri Net Tutorial', ... 'HorizontalAlignment', 'center', ... 'FontSize', 14, ... 'FontWeight', 'bold'); end function renderTokens delete(findobj(ax, 'Tag', 'token')); for p = 1:numel(places) pts = tokenLayout(placePos(p,:), marking(p)); for k = 1:size(pts, 1) plot(ax, pts(k,1), pts(k,2), 'ko', ... 'MarkerFaceColor', 'k', ... 'MarkerSize', 8, ... 'Tag', 'token'); end end end function pts = tokenLayout(center, count) if count <= 0 pts = zeros(0, 2); elseif count == 1 pts = center; else r = 0.23; ang = linspace(0, 2*pi, count + 1); ang(end) = []; pts = center + [r*cos(ang(:)), r*sin(ang(:))]; end end function updateUI enabled = all(marking >= pre, 1); enabledNames = transitions(enabled); if isempty(enabledNames) enabledText = "none"; else enabledText = strjoin(enabledNames, ", "); end for i = 1:numel(places) set(countText(i), 'String', sprintf('Tokens: %d', marking(i))); end set(btnStart, 'Enable', onOff(enabled(1))); set(btnFinish, 'Enable', onOff(enabled(2))); msg = sprintf('Step: %d/%d Marking: Ready=%d, InService=%d, Done=%d Enabled: %s', ... stepCount, maxSteps, marking(1), marking(2), marking(3), enabledText); set(statusText, 'String', msg); if any(enabled) for i = 1:numel(transitions) if enabled(i) set(transitionPatch(i), 'FaceColor', [0.75 0.93 0.75]); else set(transitionPatch(i), 'FaceColor', [0.85 0.85 0.85]); end end else for i = 1:numel(transitions) set(transitionPatch(i), 'FaceColor', [0.85 0.85 0.85]); end end end function onStep(~, ~) enabled = all(marking >= pre, 1); if ~any(enabled) updateUI(); return end if enabled(2) chosen = 2; else chosen = 1; end fireTransition(chosen, true); end function onRun(~, ~) while stepCount < maxSteps && isvalid(fig) enabled = all(marking >= pre, 1); if ~any(enabled) break end if enabled(2) chosen = 2; else chosen = 1; end fireTransition(chosen, true); pause(0.5); end end function onReset(~, ~) marking = initialMarking; stepCount = 0; renderTokens(); updateUI(); end function fireTransition(tIdx, animateFlag) enabled = all(marking >= pre, 1); if ~enabled(tIdx) updateUI(); return end inPlaces = find(pre(:, tIdx) > 0); outPlaces = find(post(:, tIdx) > 0); if animateFlag && ~isempty(inPlaces) && ~isempty(outPlaces) src = inPlaces(1); dst = outPlaces(1); token = plot(ax, placePos(src,1), placePos(src,2), 'ro', ... 'MarkerFaceColor', [0.90 0.20 0.20], ... 'MarkerSize', 10, ... 'Tag', 'token'); set(transitionPatch(tIdx), 'FaceColor', [0.98 0.85 0.55]); drawnow nFrames = 24; for s = 1:nFrames alpha = s / nFrames; x = (1 - alpha) * placePos(src,1) + alpha * placePos(dst,1); y = (1 - alpha) * placePos(src,2) + alpha * placePos(dst,2); set(token, 'XData', x, 'YData', y); drawnow pause(0.02); end delete(token); end marking = marking - pre(:, tIdx) + post(:, tIdx); stepCount = stepCount + 1; renderTokens(); updateUI(); end function s = onOff(tf) if tf s = 'on'; else s = 'off'; end end end