1 Star 0 Fork 1

Xiaokang Lv/Graph2L

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
Graph2L.m 16.94 KB
一键复制 编辑 原始数据 按行查看 历史
Xiaokang Lv 提交于 2024-05-08 17:27 . 重命名 Graph2L_v2.m 为 Graph2L.m
%--------------------------------------------------------------------------
% 文件: Graph.m
% 作者: Xiaokang Lv
% 联系方式:lv_xiaokang@buaa.edu.cn
% 日期: 20210717
% 版本: V2
%
% 用法:
% 使用Matlab 2022a以上版本,运行Graph.m
%
% 说明:
% 1.使用Matlab运行Graph2L.m,显示GUI
% 2.在左侧坐标区的空白处单击,可放置顶点。Grid on状态下,放置的顶点会自动吸附到网格上;
% Grid off状态下,可自由放置顶点。由鼠标左中右键放置的顶点外观不同,可区分不同类型的顶点。
% 3.点击某个顶点,开始绘制边,再次点击另外一个顶点,生成一条有向边(指向后点击的顶点)。
% 有向边建立完成后,右侧列表中出现对应边,默认权值为1,可指定边更改。
% 4.使用自动生成的图论图对应的拉普拉斯矩阵,通过复制右侧网格中的拉普拉斯矩阵
% (拉普拉斯矩阵L=度矩阵D-邻接矩阵A),或者直接使用工作空间的L/D/A变量。
%--------------------------------------------------------------------------
clc
clear all
close all
global masfigure masaxe mastable L_tex;
global agent_num edge_num lamda2 lamdan;
global agent_patch;
global edge_temp;
global agent edge;
global xinit yinit;
global edge_set mascon1 mascon2;
global L D A;
global wchar_num wchar;
global handle
agent_num=0;
edge_num=0;
agent=0;
edge=0;
edge_set=0;
lamda2=0;
wchar_num = 0;
wchar = '';
L=zeros(agent_num);
D=zeros(agent_num);
A=zeros(agent_num);
fig.Visible='off';
fig.HitTest='off';
fig.Position=[500 200 1200 800];
masfigure=figure(fig);
axe.Parent=masfigure;
axe.Title='axes';
axe.FontSize=12;
axe.NextPlot='add';
axe.box='on';
axe.Units='normalized';
axe.Position=[0.03 0.22 0.5 0.75]; % 根据容器进行归一化,这里容器是图窗masfigure。容器的左下角映射到 (0,0),右上角映射到 (1,1)。
axe.XLim=[0,480];
axe.YLim=[0,480];
axe.XLimMode = 'manual' ;
axe.YLimMode = 'manual' ;
axe.XTick=[];
axe.YTick=[];
axe.XTickLabelMode = 'manual' ;
axe.YTickLabelMode = 'manual' ;
axe.XTickLabel = [];
axe.YTickLabel = [];
axe.XGrid='off';
axe.YGrid='off';
axe.ButtonDownFcn=@axe_ButtonDownFcn;
masaxe=axes(axe);
pan.Parent=masfigure;
pan.Units='pixels';
pan.Position=[700 25 450 275];
pan.Title='Panel';
pan.FontSize=12;
pan.BackgroundColor=[.94 .94 .94];
maspanel=uipanel(pan);
con1.Parent=maspanel;
con1.Style = 'listbox';
con1.String ={'No Edge'};
% con1.Tooltip = {'No Edge'};
con1.Position = [25 60 100 170];
con1.Callback = @listbox_Callback;
mascon1 = uicontrol(con1);
con1str.Parent=maspanel;
con1str.Style = 'text';
con1str.FontSize = 11;
con1str.String ={'Edge'};
con1str.Position = [30 230 80 20];
mascon1str = uicontrol(con1str);
con2.Parent=maspanel;
con2.Style = 'edit';
con2.String = 'wij';
con2.Tooltip = {'Enter'};
con2.Position = [25 10 100 20];
con2.KeyPressFcn = @wij_KeyPressFcn;
mascon2 = uicontrol(con2);
con2str.Parent=maspanel;
con2str.Style = 'text';
con2str.FontSize = 11;
con2str.String ={'Weight'};
con2str.Position = [32 35 80 20];
mascon1str = uicontrol(con2str);
con3.Parent=maspanel;
con3.Style = 'togglebutton';
con3.FontSize = 11;
con3.String ='Grid on';
con3.Value = 0;
con3.Position = [370 200 65 40];
con3.Callback = @Grid_Callback ;
mascon3 = uicontrol(con3);
mastable = uitable(masfigure,'ColumnWidth',{20});
mastable.Position=[675 320 500 455];
mastable.FontSize =7;
mastable.Data=L;
pan2.Parent=masfigure;
pan2.Units='pixels';
pan2.Position=[35 25 610 150];
pan2.Title='Character';
pan2.FontSize=12;
pan2.BackgroundColor=[.94 .94 .94];
maspanel2=uipanel(pan2);
set(masfigure,'Visible','on')
function axe_ButtonDownFcn(src,~) % 空白处单击放置智能体
global agent_num;
global L D A;
global masfigure mastable;
global handle
% 判定鼠标动作 figure 的 SelectionType 属性
switch (masfigure.SelectionType)
case 'normal' % 单击鼠标左键 放置跟踪领导者
disp('tracking leader')
flag_Curvature = [1 1];
case 'extend' % 单击鼠标中键 放置编队领导者
disp('formation leader')
flag_Curvature =[0 0];
case 'alt' % 单击鼠标右键 放置跟随者
disp('follower')
flag_Curvature = [0.5 0.5];
otherwise
disp( 'error')
end
% 判定鼠标动作 figure 的 SelectionType 属性
L = [L;zeros(1,agent_num)]; %
D = [D;zeros(1,agent_num)];
A = [A;zeros(1,agent_num)];
agent_num = agent_num+1;
L = [L,zeros(agent_num,1)]; %
D = [D,zeros(agent_num,1)];
A = [A,zeros(agent_num,1)];
mastable.Data=L; % 更新excel
% 放置图形
dpi = 30; % 分辨率
xp=dpi * round(src.CurrentPoint(1,1)/dpi); % 获取点击处坐标 axe 的 CurrentPoint 属性
yp=dpi * round(src.CurrentPoint(1,2)/dpi);
handle.agent_group(agent_num) = hggroup; % 创建节点图形对象分组
temp_rectangle_config.parent = handle.agent_group(agent_num); % 指定 对应节点下的 Patch 为父对象
temp_rectangle_config.Position = [xp-15 yp-15 30 30]; % 偏移像素值,使点击位置对应节点中心,长宽30相素
temp_rectangle_config.Curvature = flag_Curvature; % 根据点击动作,更改节点外观,曲率
temp_rectangle_config.facecolor ='w'; % 填充颜色
temp_rectangle_config.EdgeColor ='k'; % 边颜色
temp_rectangle_config.LineWidth = 1.5; % 边线宽
temp_rectangle_config.Tag = num2str(agent_num); % 对象标识符,指定为字符向量或字符串标量。您可以指定唯一的 Tag 值作为对象的标识符。如果需要访问您代码中其他位置的对象,可以使用 findobj 函数基于 Tag 值搜索对象。
temp_rectangle_config.UserData = agent_num; % 用户数据,指定为任何 MATLAB 数组。例如,您可以指定标量、向量、矩阵、元胞数组、字符数组、表或结构体。使用此属性存储对象上的任意数据。
temp_rectangle_config.Hittest ='off'; % 不响应捕获的鼠标点击
handle.agent_patch(agent_num) = rectangle(temp_rectangle_config); % 创建块对象
temp_tex_config.parent = handle.agent_group(agent_num); % 指定 对应节点下的 Patch 为父对象
temp_tex_config.string = num2str(agent_num); % 文本内容
temp_tex_config.Tag = num2str(agent_num); % 对象标识符,指定为字符向量或字符串标量。您可以指定唯一的 Tag 值作为对象的标识符。如果需要访问您代码中其他位置的对象,可以使用 findobj 函数基于 Tag 值搜索对象。
temp_tex_config.Position = [xp yp]; % 文本框位置,默认情况下,位置值是以数据单位定义的。要更改单位,请使用 Units 属性。
temp_tex_config.FontWeight = 'bold'; % 所有单位('data' 除外)都是从坐标区的左下角进行测量的。此属性会影响 Position 和 Extent 属性。
temp_tex_config.FontName = 'Times New Roman'; % 如果您在创建 Text 对象时以 Name,Value 对组的形式指定 Position 和 Units 属性,则指定顺序很重要。若要使用特定单位定义位置,请在设置 Position 属性之前先设置 Units 属性。
temp_tex_config.FontSize = 12;
temp_tex_config.Margin = 1;
temp_tex_config.HorizontalAlignment = 'center'; % 使文本框中心对准点击位置
temp_tex_config.VerticalAlignment = 'middle';
temp_tex_config.Hittest = 'off'; % 文本框 与 块不响应点击,只有两者的组才响应
handle.agent_text(agent_num) = text(temp_tex_config);
temp_group_config.SelectionHighlight='on';
temp_group_config.PickableParts='visible';
temp_group_config.HitTest='on';
temp_group_config.Tag=num2str(agent_num);
temp_group_config.ButtonDownFcn = @agent_ButtonDownFcn1; % 一旦点击已有的节点,以该节点为起始点,开始放置边
set(handle.agent_group(agent_num),temp_group_config); % 已创建的对象,重新配置
end
function agent_ButtonDownFcn1(src,~) % 放置边
global masfigure masaxe;
global agent_num edge_num;
global agent_patch;
global edge_temp;
global agent edge;
global xinit yinit;
global edge_set;
global L D A;
edge_num=edge_num+1; % 边集元素个数+1
masfigure.Pointer = 'circle'; % 鼠标变为○,表示正在等待点击第二个节点
h = findobj('parent',src,'-and','Type','rectangle'); % src回调进入点是点击节点对应的组,寻找以该组为父对象的矩形子对象
hposition=get(h,'Position'); % 获取该矩形子对象的位置,并根据偏移量还原之前放置时的点击坐标。
xinit = hposition(1)+15;
yinit = hposition(2)+15;
edge_set(edge_num,1) = get(h,'UserData'); % 边集数组行数等于节点数,将当前已知第一个节点的序号赋值给边集数组第一个元素,等待第二个元素
masaxe.ButtonDownFcn=''; % 在点击第二个节点前,不再放置新节点
h2 = findobj('Type','hggroup'); % 将现有所有节点的点击回调更改为终止边放置回调函数
for j=1:size(h2)
set(h2(j),'ButtonDownFcn',@agent_ButtonDownFcn2);
end
src.ButtonDownFcn = [];
edge_temp = line('XData',xinit,'YData',yinit,'Marker','none','color',[0.85 0.85 0.85]); % 临时边,浅灰色,表示正在等待点击第二个节点,起点为上一个节点
masfigure.WindowButtonMotionFcn = @agent_ButtonMotionFcn; % 开启figure对象的鼠标移动子函数
end
function agent_ButtonMotionFcn(~,~) % 移动鼠标子函数,只有在点击第一个节点后,等待点击第二个节点期间触发
global masfigure masaxe;
global agent_num edge_num;
global agent_patch;
global edge_temp;
global agent edge;
global xinit yinit;
cp = masaxe.CurrentPoint; % 获得当前鼠标位置
d = @(x,y) (x^2+y^2)^0.5; % 改善视觉效果,放置临时线条出现在节点内
ld=d((cp(1,1)-xinit),(cp(1,2)-yinit));
x_delta=15*(cp(1,1)-xinit)/ld;
y_delta=15*(cp(1,2)-yinit)/ld;
xdat = [xinit+x_delta,cp(1,1)-x_delta];
ydat = [yinit+y_delta,cp(1,2)-y_delta];
edge_temp.XData = xdat;
edge_temp.YData = ydat;
drawnow % 刷新线条
end
function agent_ButtonDownFcn2(src,~)
global masfigure masaxe mastable L_tex;
global edge_num agent_num lamda2 lamdan;
global agent_patch;
global edge_temp;
global agent edge;
global xinit yinit;
global edge_set mascon1 mascon2;
global L D A;
global handle
masfigure.WindowButtonMotionFcn = ''; % 关掉指示线 并 恢复鼠标图形
edge_temp.XData = 0;
edge_temp.YData = 0;
drawnow
masfigure.Pointer = 'arrow';
h = findobj('parent',src,'-and','Type','rectangle'); % src回调进入点是点击节点对应的组,寻找以该组为父对象的矩形子对象
hposition=get(h,'Position'); % 获取该矩形子对象的位置,并根据偏移量还原之前放置时的点击坐标。
xend= hposition(1)+15;
yend =hposition(2)+15;
d = @(x,y) (x^2+y^2)^0.5;
ld=d((xend-xinit),(yend-yinit));
x_delta=20*(xend-xinit)/ld;
y_delta=20*(yend-yinit)/ld;
% xdat = [xinit+x_delta,xend-x_delta];
% ydat = [yinit+y_delta,yend-y_delta];
x1y1 = [xinit+x_delta,yinit+y_delta];
x2y2 = [xend-x_delta,yend-y_delta];
edge_set(edge_num,2)=get(h,'UserData'); % 存储边
edge_set(edge_num,3)= 1;
edge_set(edge_num,4:5) = x1y1;
edge_set(edge_num,6:7) = x2y2;
edge_set(edge_num,8) = 123;
colflag = get(handle.agent_patch(edge_set(edge_num,1)),'Curvature');
edge_set=unique(edge_set,'rows'); % 去除起终点为统一节点的行
edge_num=size(edge_set,1); % 重新计算边数
% 绘制边
switch sum(colflag)
case 2
col = [1 0.2 0];
case 0
col = [1 0.6 0.00];
case 1
col = [0.12 0.56 1];
end
edge(edge_num) = plot_edge(x1y1,x2y2,'12',col,5,2.5);
% 解算LDA
D = zeros(agent_num);
for i=1:edge_num
A(edge_set(i,2),edge_set(i,1))=edge_set(i,3);
D(edge_set(i,2),edge_set(i,2))=D(edge_set(i,2),edge_set(i,2))+edge_set(i,3);
L=D-A;
mastable.Data=L; % 刷新表
end
% 更新边菜单
for i=1:edge_num
estr = num2str(edge_set(i,1:2));
mascon1.String{i} = ['E ',estr,' (wij = ',num2str(edge_set(i,3)),')'];
mascon2.String = '1';
end
% 更改回调,将坐标区恢复,能够放置新节点,将各节点回调恢复,变为开始放置边
masaxe.ButtonDownFcn=@axe_ButtonDownFcn;
h2=findobj('Type','hggroup');
for j=1:size(h2)
set(h2(j),'ButtonDownFcn',@agent_ButtonDownFcn1);
end
function [out] = plot_edge(x1y1,x2y2,direction,color,ARROW_LENGTH,ARROW_WIDTH)
unitization = @(v)v/norm(v); % 向量单位化
v0 = unitization(x2y2 - x1y1); % 向量单位化
v0_ = null(v0)'; % 求标准正交向量
x3y3 = x1y1 + ARROW_LENGTH*v0 + ARROW_WIDTH/2*v0_;
x4y4 = x1y1 + ARROW_LENGTH*v0 - ARROW_WIDTH/2*v0_;
x5y5 = x2y2 - ARROW_LENGTH*v0 + ARROW_WIDTH/2*v0_;
x6y6 = x2y2 - ARROW_LENGTH*v0 - ARROW_WIDTH/2*v0_;
fv.Vertices = [x1y1;x2y2;x3y3;x4y4;x5y5;x6y6];
switch direction
case 'un'
fv.Faces = [1,2,2;...
1,3,4;...
2,5,6];
% fv.FaceVertexCData=[.7 .7 .7;.7 .7 .7;.7 .7 .7];
case '12'
fv.Faces = [1,2,2;...
2,5,6];
% fv.FaceVertexCData=[.7 .7 .7;.7 .7 .7];
case '21'
fv.Faces = [1,2,2;...
1,3,4];
% fv.FaceVertexCData=[.7 .7 .7;.7 .7 .7];
end
% fv.FaceColor = 'flat';
fv.FaceColor = color;
fv.EdgeColor = color;
fv.LineWidth = 1;
out = patch(fv);
end
end
function Grid_Callback (src,~)
global masaxe;
if src.Value == 1
src.String ='Grid off';
src.UserData ='Grid off';
src.Value = src.Max;
masaxe.XGrid='on';
masaxe.YGrid='on';
masaxe.XTick=0:30:480;
masaxe.YTick=0:30:480;
else
src.String ='Grid on';
src.UserData ='Grid on';
src.Value = src.Min;
masaxe.XGrid='off';
masaxe.YGrid='off';
masaxe.XTick=[];
masaxe.YTick=[];
end
end
function wij_KeyPressFcn(src,keyData)
global wchar_num wchar
global mascon1
global edge_set L D A mastable agent_num edge_num
keyData.Character
switch keyData.Character
case {'-','0','.','1','2','3','4','5','6','7','8','9'}
wchar_num = wchar_num + 1;
wchar(wchar_num) = keyData.Character;
otherwise
wchar_num = 0;
src.String = wchar
edge_set(mascon1.Value,3) = str2num(wchar);
estr = num2str([edge_set(mascon1.Value,1),edge_set(mascon1.Value,2)]);
mascon1.String{mascon1.Value} = ['E ',estr,' (wij = ',wchar,')'];
x1y1 = edge_set(mascon1.Value,4:5);
x2y2 = edge_set(mascon1.Value,6:7);
v0 = null(x2y2 - x1y1)';
xtyt = (x1y1 + x2y2)/2 + 5*v0;
if edge_set(mascon1.Value,8) ~= 123;
delete(edge_set(mascon1.Value,8));
end
edge_set(mascon1.Value,8) = text('Position',xtyt,'String',wchar,'FontSize',6);
wchar = '';
D = zeros(agent_num);
for i=1:edge_num
A(edge_set(i,2),edge_set(i,1))=edge_set(i,3);
D(edge_set(i,2),edge_set(i,2))=D(edge_set(i,2),edge_set(i,2))+edge_set(i,3);
L=D-A;
mastable.Data=L; % 刷新表
end
end
end
function listbox_Callback(src,~)
global edge_set
global mascon1 mascon2
global wchar_num wchar
mascon2.String = edge_set(mascon1.Value,3);
wchar_num = 0;
wchar = '';
end
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
Matlab
1
https://gitee.com/Lxk_buaa/graph2l.git
git@gitee.com:Lxk_buaa/graph2l.git
Lxk_buaa
graph2l
Graph2L
master

搜索帮助

Cb406eda 1850385 E526c682 1850385