用Matlab脚本实现Simulink模块的自动整理

        作为模型工程师,在Simulink中建模时,总是希望把模块排列整齐从而更加美观。但是模型的反复修改使得我们没有太多的精力去做这些整理工作。因此笔者开发了如下脚本来自动实现Simulink模块的整理工作,效果如下图所示:

        大家可以自取使用,希望可以给大家的开发工作带来一点便利。使用方法是,在模型中点击想要被整理的模块(比如一个subsystem,使得gcbh为当前选中模块的句柄),再运行函数 arrangeit() 即可。

 代码如下:

% 整理与所选模块的输入和输出连接的模块的位置,使之排布整齐
% 操作方法:先在simulink中点击选中目标模块,再运行该函数

function arrangeit()
lineh = get(gcbh, 'LineHandles');
porth = get(gcbh, 'PortHandles');
blkDistance = 150;

%% 设置输入接口模块
for i = 1:1:length(porth.Inport)
    % 如果当前port口上悬空,没有连线,则跳过
    if isequal(lineh.Inport(i), -1)
        continue;
    end
    
    % 获取当前port口的位置
    [portx, porty, ~, ~] = lgetpos(porth.Inport(i));
    % 获取当前port口连线的源模块的句柄
    curtLineSrcBlkH = get_param(lineh.Inport(i), 'SrcBlockHandle');
    
    % 如果源模块是subsystem,则不对该subsystem的位置进行设置
    if isequal('SubSystem', get_param(curtLineSrcBlkH, 'BlockType'))
        continue;
    end
    % 获取源模块的宽度和高度值
    [~, ~, width, height] = lgetpos(curtLineSrcBlkH);
    % 重新设置源模块的位置,保持其宽度和高度值不变
    newx = portx - blkDistance;
    newy = porty - height / 2;
    lsetpos(curtLineSrcBlkH, newx, newy, width, height);
end

%% 设置输出接口模块
for i = 1:1:length(porth.Outport)
    % 如果当前port口上悬空,没有连线,则跳过
    if isequal(lineh.Outport(i), -1)
        continue;
    end

    % curtPortPos = get_param(porth.Outport(i), 'Position');
    % 获取当前port口的位置
    [portx, porty, ~, ~] = lgetpos(porth.Outport(i));
    % 获取当前port口连线的目标模块的句柄
    curtLineDstBlkH = get_param(lineh.Outport(i), 'DstBlockHandle');
    
    % 如果目标模块是subsystem,则不对该subsystem的位置进行设置
    if isequal('SubSystem', get_param(curtLineDstBlkH, 'BlockType'))
        continue;
    end
    % 如果目标模块是 swithc, 则不对该subsystem的位置进行设置
    if isequal('Switch', get_param(curtLineDstBlkH, 'BlockType'))
        continue;
    end
    
    % 当前port连线的目标模块可能有多个模块,因此挨个处理
    for j = 1:1:length(curtLineDstBlkH)
        % 获取源模块的宽度和高度值
        [~, ~, width, height] = lgetpos(curtLineDstBlkH(j));
        % newx = curtPortPos(1) + blkDistance;
        % newy = curtPortPos(2) - height / 2 + height * (j - 1);
        newx = portx + blkDistance;
        newy = porty - height / 2 + height * (j - 1);
        lsetpos(curtLineDstBlkH(j), newx, newy, width, height);
    end
end

%% 设置 enable 或 trigger 接口,两种类型的port合并后处理
EnableTriggerPortH = -1;
EnableTriggerLineH = -1;
if (~isequal(lineh.Enable, -1)) && (~isempty(lineh.Enable))
    EnableTriggerPortH = porth.Enable;
    EnableTriggerLineH = lineh.Enable;
end
if (~isequal(lineh.Trigger, -1)) && (~isempty(lineh.Trigger))
    EnableTriggerPortH = porth.Trigger;
    EnableTriggerLineH = lineh.Trigger;
end

if ~isequal(EnableTriggerPortH, -1)
    % 获取当前port口的位置
    [portx, porty, ~, ~] = lgetpos(EnableTriggerPortH);
    % 获取当前port口连线的源模块的句柄
    curtLineSrcBlkH = get_param(EnableTriggerLineH, 'SrcBlockHandle');
    
    % 只有当enable port的源模块是 inport 类型的模块时,才对其位置进行优化
    if isequal('Inport', get_param(curtLineSrcBlkH, 'BlockType'))
        % 获取源模块的宽度和高度值
        [~, ~, width, height] = lgetpos(curtLineSrcBlkH);
        % 重新设置源模块的位置,保持其宽度和高度值不变
        newx = portx - width * 3;
        newy = porty - height * 2;
        lsetpos(curtLineSrcBlkH, newx, newy, width, height);
    end
end

end

函数 arrangeit() 使用到了位置设置和位置读取的两个函数的代码如下:

function lsetpos(blockH, x, y, width, height)
% lsetpos(blockH, x, y, width, height)
% blockH 可以是 目标模块句柄,或者是 目标模块路径
% blockH 不能是 port 或者 line 的句柄
% width 和 height 必须 ≥ 0

% 入参合法性检查
% 如果 blockH 是句柄,则维度必须是1
% 如果 blockH 是目标模块路径,则是字符串
if ((length(blockH) > 1) && (~ischar(blockH)))
    errordlg('函数 lsetpos 的入参 blockH 的长度大于1','错误','creatmode');
end
if (width < 0)
    errordlg('错误信息:函数 lsetpos 的入参 width 小于0 ! 应 ≥ 0 ','错误','creatmode');
end
if (height < 0)
    errordlg('错误信息:函数 lsetpos 的入参 height 小于0 ! 应 ≥ 0 ','错误','creatmode');
end

set_param(blockH, 'Position', [x, y, x + width, y + height]);

end


function [x, y, width, height] = lgetpos(blockH)
% [x, y, width, height] = lgetpos(目标模块句柄)
% 如果 目标模块句柄 是一个 port 的句柄,则 width 和 height 返回-1

% 入参合法性检查
if (length(blockH) > 1)
    errordlg('函数 lgetpos 的入参 blockH 的长度大于1','错误','creatmode');
end

pos = get_param(blockH, 'Position');

x = pos(1);
y = pos(2);

% 如果目标句柄是port的句柄,则pos只有两维,此时宽度和高度返回-1
if length(pos) == 4
    width = pos(3) - pos(1);
    height = pos(4) - pos(2);
else
    width = -1;
    height = -1;
end

end

如果大家觉得有点用处,还请点个赞,欢迎留言讨论~

  • 26
    点赞
  • 63
    收藏
    觉得还不错? 一键收藏
  • 12
    评论
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值