function petriNetBatchPackagingDemo % PETRINETBATCHPACKAGINGDEMO GUI demo for a weighted-arc Petri net. % P1 accumulates parts. T1 fires only when M(P1) >= 4 and % produces 1 box. fig = figure( ... 'Name', 'Factory Batch Packaging Petri Net', ... 'Color', 'w', ... 'NumberTitle', 'off', ... 'MenuBar', 'none', ... 'ToolBar', 'none', ... 'Resize', 'off', ... 'Position', [100 100 1080 620]); ax = axes( ... 'Parent', fig, ... 'Position', [0.04 0.24 0.92 0.67]); hold(ax, 'on'); axis(ax, [0 10 0 6]); axis(ax, 'equal'); axis(ax, 'off'); % ------------------------------------------------------------------------- % State % ------------------------------------------------------------------------- state.partCount = 0; state.boxCount = 0; state.message = 'Add parts to the Produced Parts Buffer. T1 needs 4 tokens to fire.'; % ------------------------------------------------------------------------- % Layout % ------------------------------------------------------------------------- bufferPos = [0.8 1.55 2.3 2.3]; t1Pos = [4.4 2.35 1.0 1.3]; boxPos = [7.0 1.55 2.3 2.3]; bufferCenter = [bufferPos(1) + bufferPos(3)/2, bufferPos(2) + bufferPos(4)/2]; t1Center = [t1Pos(1) + t1Pos(3)/2, t1Pos(2) + t1Pos(4)/2]; boxCenter = [boxPos(1) + boxPos(3)/2, boxPos(2) + boxPos(4)/2]; % Header text text(ax, 5.0, 5.78, ... 'Weighted arc example: T1 needs 4 parts before it can fire', ... 'HorizontalAlignment', 'center', 'FontSize', 12, 'FontWeight', 'bold', ... 'Interpreter', 'none'); text(ax, 5.0, 5.48, ... 'P1 = Produced Parts Buffer | T1 = Pack Box | P2 = Packed Boxes', ... 'HorizontalAlignment', 'center', 'FontSize', 10, 'Interpreter', 'none'); % Arcs h.arcIn = drawArrow([3.15 3.0], [4.4 3.0]); h.arcOut = drawArrow([5.4 3.0], [7.0 3.0]); % Places and transition h.p1 = rectangle(ax, 'Position', bufferPos, 'Curvature', [1 1], ... 'FaceColor', [1.0 0.98 0.88], 'EdgeColor', [0.25 0.25 0.25], 'LineWidth', 2); h.t1 = rectangle(ax, 'Position', t1Pos, ... 'FaceColor', [0.25 0.25 0.25], 'EdgeColor', [0.15 0.15 0.15], 'LineWidth', 1.5); h.p2 = rectangle(ax, 'Position', boxPos, 'Curvature', [1 1], ... 'FaceColor', [0.92 0.96 1.0], 'EdgeColor', [0.25 0.25 0.25], 'LineWidth', 2); % Weight label text(ax, 3.85, 3.28, '4', 'Color', [0.85 0.2 0.2], 'FontSize', 13, ... 'FontWeight', 'bold', 'HorizontalAlignment', 'center'); text(ax, 6.25, 3.28, '1', 'Color', [0.2 0.2 0.7], 'FontSize', 13, ... 'FontWeight', 'bold', 'HorizontalAlignment', 'center'); % Labels text(ax, bufferCenter(1), bufferCenter(2) + 1.45, 'P1: Produced Parts Buffer', ... 'HorizontalAlignment', 'center', 'FontSize', 11, 'Interpreter', 'none'); text(ax, t1Center(1), t1Center(2) + 1.55, 'T1: Pack Box', ... 'HorizontalAlignment', 'center', 'FontSize', 11, 'Interpreter', 'none'); text(ax, boxCenter(1), boxCenter(2) + 1.45, 'P2: Packed Boxes', ... 'HorizontalAlignment', 'center', 'FontSize', 11, 'Interpreter', 'none'); text(ax, 5.0, 2.05, 'T1 is enabled only when M(P1) >= 4', ... 'HorizontalAlignment', 'center', 'FontSize', 10, 'Color', [0.35 0.35 0.35]); % Count displays h.p1Count = text(ax, bufferCenter(1), 1.08, 'M(P1) = 0', ... 'HorizontalAlignment', 'center', 'FontSize', 11, 'FontWeight', 'bold'); h.p2Count = text(ax, boxCenter(1), 1.08, 'M(P2) = 0', ... 'HorizontalAlignment', 'center', 'FontSize', 11, 'FontWeight', 'bold'); % Token holders h.partTokens = gobjects(0); h.boxTokens = gobjects(0); % Buttons uicontrol(fig, 'Style', 'pushbutton', 'String', 'Produce Part', ... 'Position', [75 70 120 34], 'Callback', @(~, ~) producePart()); uicontrol(fig, 'Style', 'pushbutton', 'String', 'Pack Box', ... 'Position', [210 70 120 34], 'Callback', @(~, ~) packBox()); uicontrol(fig, 'Style', 'pushbutton', 'String', 'Reset', ... 'Position', [345 70 100 34], 'Callback', @(~, ~) resetDemo()); status = uicontrol(fig, 'Style', 'text', ... 'Position', [35 18 1000 30], ... 'BackgroundColor', 'w', ... 'HorizontalAlignment', 'left', ... 'FontSize', 11); updateView(); function producePart() state.partCount = state.partCount + 1; state.message = sprintf('One part entered P1. Now M(P1) = %d.', state.partCount); updateView(); end function packBox() if state.partCount < 4 state.message = sprintf('T1 is DISABLED: M(P1) = %d, but the arc weight is 4.', state.partCount); updateView(); return; end state.message = 'T1 fires: it consumes 4 parts and produces 1 box.'; updateView(); pause(0.25); state.partCount = state.partCount - 4; state.boxCount = state.boxCount + 1; state.message = sprintf('Box packed. M(P1) = %d, M(P2) = %d.', state.partCount, state.boxCount); updateView(); end function resetDemo() state.partCount = 0; state.boxCount = 0; state.message = 'Reset complete. Add parts to P1. T1 needs 4 tokens to fire.'; updateView(); end function updateView() enabled = state.partCount >= 4; if enabled set(h.t1, 'FaceColor', [1.0 0.85 0.25]); setArrowStyle(h.arcIn, [1.0 0.55 0.0], 3.0); setArrowStyle(h.arcOut, [1.0 0.55 0.0], 3.0); else set(h.t1, 'FaceColor', [0.30 0.30 0.30]); setArrowStyle(h.arcIn, [0.65 0.65 0.65], 1.3); setArrowStyle(h.arcOut, [0.65 0.65 0.65], 1.3); end set(h.p1Count, 'String', sprintf('M(P1) = %d', state.partCount)); set(h.p2Count, 'String', sprintf('M(P2) = %d', state.boxCount)); set(status, 'String', state.message); deleteValidHandles(h.partTokens); deleteValidHandles(h.boxTokens); h.partTokens = drawPartTokens(state.partCount, bufferCenter); h.boxTokens = drawBoxTokens(state.boxCount, boxCenter); drawnow; end function handles = drawPartTokens(n, center) handles = gobjects(0); if n <= 0 return; end cols = min(4, max(1, ceil(sqrt(n)))); rows = ceil(n / cols); dx = 0.33; dy = 0.33; startX = center(1) - (cols - 1) * dx / 2; startY = center(2) + (rows - 1) * dy / 2; r = 0.085; for k = 1:n c = mod(k - 1, cols); rIdx = floor((k - 1) / cols); x = startX + c * dx; y = startY - rIdx * dy; handles(end + 1) = rectangle(ax, ... %#ok 'Position', [x - r, y - r, 2 * r, 2 * r], ... 'Curvature', [1 1], ... 'FaceColor', [1.0 0.75 0.15], ... 'EdgeColor', [0.8 0.5 0.0], ... 'LineWidth', 0.8); end end function handles = drawBoxTokens(n, center) handles = gobjects(0); if n <= 0 return; end cols = min(3, max(1, ceil(sqrt(n)))); rows = ceil(n / cols); dx = 0.42; dy = 0.42; startX = center(1) - (cols - 1) * dx / 2; startY = center(2) + (rows - 1) * dy / 2; s = 0.18; for k = 1:n c = mod(k - 1, cols); rIdx = floor((k - 1) / cols); x = startX + c * dx; y = startY - rIdx * dy; handles(end + 1) = rectangle(ax, ... %#ok 'Position', [x - s, y - s, 2 * s, 2 * s], ... 'FaceColor', [0.35 0.65 1.0], ... 'EdgeColor', [0.15 0.35 0.7], ... 'LineWidth', 1.0); end end function deleteValidHandles(handles) if isempty(handles) return; end handles = handles(isgraphics(handles)); if ~isempty(handles) delete(handles); end end function setArrowStyle(hArrow, color, width) set(hArrow.line, 'Color', color, 'LineWidth', width); set(hArrow.head, 'FaceColor', color, 'EdgeColor', color); end function hArrow = drawArrow(p1, p2) hArrow.line = plot(ax, [p1(1) p2(1)], [p1(2) p2(2)], 'k-', 'LineWidth', 1.5); v = p2 - p1; u = v / norm(v); n = [-u(2) u(1)]; tip = p2; base = p2 - 0.18 * u; left = base + 0.08 * n; right = base - 0.08 * n; hArrow.head = patch(ax, [tip(1) left(1) right(1)], ... [tip(2) left(2) right(2)], 'k', 'EdgeColor', 'k'); end end