PDE Plots in GUI应用中使用PDE工具箱的绘图函数
前言
在网上有一个问题没有得到很好的解决,就是在GUI中显示PDE工具箱的计算结果。目前英文网站上有一个解决方案,非常好玩,先建立一个图窗,把结果绘制在该图窗上,然后用copyobj
函数把结果复制到GUI的图窗上。还有一个牛人把网格和结果自己插值搞在坐标上。
这两个例子就不要扩散了……但是AI已经被搞坏了,很喜欢这两个方式。
1figure;
2pdeplot(model,'ColorMap','default');
3h = get(gcf,'Children');
4set(h,'HandleVisibility','off');
5
6% ... uiaxes中绘制
7
8ax = uiaxes(parent);
9copyobj(h,ax);
还有一个好玩的解放方式,就是把UIfigure
/uiaxes
的句柄可见性设置为’on’, 然后就能让绘图函数感知到相应的图形对象。
就大概是这样的把戏,但是那个绘图图窗的隐藏老是有这样那样的问题。
我以前也搞了一个更加无聊的产生PDE几何模型的GUI,我的做法是把几何模型导出成stl文件,然后界面上显示STL文件。 用的函数式pdegplot,这个函数本身是支持第一个参数为uiaxes的。
而2D结果显示的函数是pdeplot,这个函数也支持在uiaxes中绘制。
1ax = uiaxes(parent);
2pdeplot(ax, model,'ColorMap','default');
但是pdeplot3D
不支持第一个参数axes
的语法,但是通过Parent
参数,可以直接在GUI的图窗中绘制。
1ax = uiaxes(parent);
2pdeplot3D(model,'ColorMap','default','Parent',ax);
总结一下,PDE工具箱的绘图函数:
函数 | 支持的参数 | 备注 |
---|---|---|
pdegplot | 支持uiaxes作为第一个参数 | 2D |
pdeplot | 支持uiaxes作为第一个参数 | 2D |
pdeplot3D | 支持uiaxes作为Parent 参数 | 3D |
一个简单的GUI
我们来实现一个简单的悬臂梁分析GUI,这个GUI的界面如下:
用户可以设置几何参数(长度、宽度、高度),材料参数(杨氏模量、泊松比),载荷参数(力),网格参数(网格尺寸),变形显示参数(变形比例)等参数;并通过按钮开产生几何体、生成网格和求解。结果则在右侧的图窗中显示,包括几何、网格和结果。
按照默认参数,点击产生几何体按钮,几何体显示在右侧的图窗中。
再点击生成网格按钮,网格显示在右侧的图窗中。
然后点击求解按钮,结果显示在右侧的图窗中。
调节变形比例到2085后,悬臂梁的变形以更加夸张的方式显示在右侧的图窗中。
这里所有的图片都是通过exportapp
函数导出的。
1exportapp(app.UIFigure, "app.png");
GUI代码
1classdef simplePDE < matlab.apps.AppBase
2 % 一个简单的PDE工具箱例子的GUI App
3
4 properties (Access = public)
5 % 用户界面组件
6 UIFigure matlab.ui.Figure
7 end
8
9 properties (Access = private)
10
11 % 主布局
12 MainLayout matlab.ui.container.GridLayout
13
14 % 控制面板
15 ControlPanel matlab.ui.container.Panel
16
17 % 几何参数控制
18 LengthSpinner matlab.ui.control.Spinner % 长度
19 WidthSpinner matlab.ui.control.Spinner % 宽度
20 HeightSpinner matlab.ui.control.Spinner % 高度
21
22 % 材料参数控制
23 YoungModulusSpinner matlab.ui.control.Spinner % 杨氏模量
24 PoissonRatioSpinner matlab.ui.control.Spinner % 泊松比
25
26 % 载荷参数控制
27 LoadSpinner matlab.ui.control.Spinner % 载荷大小
28
29 % 网格参数
30 MeshSizeSpinner matlab.ui.control.Spinner % 网格尺寸
31
32 % 变形显示控制
33 DeformationSlider matlab.ui.control.Slider % 变形比例因子
34 DeformationValueLabel matlab.ui.control.Label % 变形比例值显示
35
36 % 按钮控件
37 GeometryButton matlab.ui.control.Button % 生成几何体按钮
38 MeshButton matlab.ui.control.Button % 生成网格按钮
39 SolveButton matlab.ui.control.Button % 求解按钮
40
41 % 结果显示区域
42 ResultsPanel matlab.ui.container.Panel
43 TabGroup matlab.ui.container.TabGroup
44 GeometryTab matlab.ui.container.Tab
45 MeshTab matlab.ui.container.Tab
46 ResultsTab matlab.ui.container.Tab
47 GeometryAxes matlab.ui.control.UIAxes
48 MeshAxes matlab.ui.control.UIAxes
49 ResultsAxes matlab.ui.control.UIAxes
50
51 % 结果类型选择
52 ResultTypeDropDown matlab.ui.control.DropDown
53
54 % PDE模型
55 Model
56 Results
57 end
这里,大部分控件都是不可在外部访问的,access
属性为private
。我们把UIFigure
作为public
属性,这样就可以在对象中访问,便于调用exportapp
函数把界面输出图片。
1 methods (Access = private)
2 function createComponents(app)
3 % 创建主窗口
4 app.UIFigure = uifigure('Name', '悬臂梁有限元分析');
5 app.UIFigure.Position = [100 100 1200 800];
6 movegui(app.UIFigure,'center');
7
8 % 创建主网格布局
9 app.MainLayout = uigridlayout(app.UIFigure, [1 2]);
10 app.MainLayout.ColumnWidth = {300, '1x'};
11 app.MainLayout.Padding = [0 0 0 0]; % 移除边距
12 app.MainLayout.RowSpacing = 0; % 移除行间距
13 app.MainLayout.ColumnSpacing = 0; % 移除列间距
14
15 % 创建控制面板
16 app.ControlPanel = uipanel(app.MainLayout);
17 app.ControlPanel.Title = '参数控制';
18 app.ControlPanel.Layout.Column = 1;
19
20 % 修改控制面板的网格布局以容纳更多控件
21 controlGrid = uigridlayout(app.ControlPanel, [18 2]);
22 controlGrid.RowHeight = {25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 35, 25, 25, 25, 25, 25, 25}; % 固定每行高度
23 controlGrid.ColumnWidth = {'1x', '1x'}; % 两列等宽
24 controlGrid.Padding = [10 10 10 10];
25 controlGrid.RowSpacing = 5; % 减小行间距
26 controlGrid.ColumnSpacing = 10; % 设置列间距
27
28 % 几何参数控件
29 uilabel(controlGrid, 'Text', '几何参数', 'FontWeight', 'bold');
30 uilabel(controlGrid, 'Text', '');
31
32 uilabel(controlGrid, 'Text', '长度 (m)');
33 app.LengthSpinner = uispinner(controlGrid);
34 app.LengthSpinner.Limits = [0.1 10];
35 app.LengthSpinner.Value = 1;
36
37 uilabel(controlGrid, 'Text', '宽度 (m)');
38 app.WidthSpinner = uispinner(controlGrid);
39 app.WidthSpinner.Limits = [0.01 1];
40 app.WidthSpinner.Value = 0.1;
41
42 uilabel(controlGrid, 'Text', '高度 (m)');
43 app.HeightSpinner = uispinner(controlGrid);
44 app.HeightSpinner.Limits = [0.01 1];
45 app.HeightSpinner.Value = 0.1;
46
47 % 材料参数控件
48 uilabel(controlGrid, 'Text', '材料参数', 'FontWeight', 'bold');
49 emptyLabel = uilabel(controlGrid, 'Text', '');
50
51 uilabel(controlGrid, 'Text', '杨氏模量 (Pa)');
52 app.YoungModulusSpinner = uispinner(controlGrid);
53 app.YoungModulusSpinner.Limits = [1e6 1e12];
54 app.YoungModulusSpinner.Value = 2e11; % 钢的杨氏模量
55 app.YoungModulusSpinner.Step = 1e9;
56
57 uilabel(controlGrid, 'Text', '泊松比');
58 app.PoissonRatioSpinner = uispinner(controlGrid);
59 app.PoissonRatioSpinner.Limits = [0 0.5];
60 app.PoissonRatioSpinner.Value = 0.3;
61 app.PoissonRatioSpinner.Step = 0.01;
62
63 % 载荷参数控件
64 uilabel(controlGrid, 'Text', '载荷参数', 'FontWeight', 'bold');
65 uilabel(controlGrid, 'Text', '');
66
67 uilabel(controlGrid, 'Text', '载荷 (N)');
68 app.LoadSpinner = uispinner(controlGrid);
69 app.LoadSpinner.Limits = [-1e6 1e6];
70 app.LoadSpinner.Value = -100000;
71 app.LoadSpinner.Step = 100;
72
73 % 网格参数控件
74 uilabel(controlGrid, 'Text', '网格参数', 'FontWeight', 'bold');
75 uilabel(controlGrid, 'Text', '');
76
77 uilabel(controlGrid, 'Text', '网格尺寸');
78 app.MeshSizeSpinner = uispinner(controlGrid);
79 app.MeshSizeSpinner.Limits = [0.01 0.5];
80 app.MeshSizeSpinner.Value = 0.05;
81 app.MeshSizeSpinner.Step = 0.01;
82
83 % 变形显示控制
84 uilabel(controlGrid, 'Text', '变形显示', 'FontWeight', 'bold');
85 uilabel(controlGrid, 'Text', '');
86
87 uilabel(controlGrid, 'Text', '变形比例');
88 app.DeformationValueLabel = uilabel(controlGrid, 'Text', '500'); % 初始值显示
89
90 sliderGrid = uigridlayout(controlGrid, [1 1]); % 创建滑块的网格布局
91 sliderGrid.Layout.Column = [1 2]; % 跨两列
92 sliderGrid.Padding = [0 5 0 5]; % 添加适当的上下内边距
93 app.DeformationSlider = uislider(sliderGrid);
94 app.DeformationSlider.Limits = [10 10000];
95 app.DeformationSlider.Value = 500;
96 app.DeformationSlider.ValueChangedFcn = @(src,~) deformationValueChanged(app, src);
97 app.DeformationSlider.Enable = 'off'; % 初始禁用
98 app.DeformationValueLabel.Enable = 'off'; % 初始禁用
99
100 % 添加结果类型选择下拉列表
101 uilabel(controlGrid, 'Text', '结果类型');
102 app.ResultTypeDropDown = uidropdown(controlGrid);
103 app.ResultTypeDropDown.Items = {'位移大小', '应力von Mises', 'x方向位移', 'y方向位移', 'z方向位移'};
104 app.ResultTypeDropDown.Value = '位移大小';
105 app.ResultTypeDropDown.ValueChangedFcn = @(~,~) updateResultsDisplay(app);
106 app.ResultTypeDropDown.Enable = 'off'; % 初始禁用
107
108 % 添加按钮控件(在控制面板网格布局中)
109 % 生成几何体按钮
110 app.GeometryButton = uibutton(controlGrid, 'Text', '生成几何体');
111 app.GeometryButton.Layout.Column = [1 2];
112 app.GeometryButton.ButtonPushedFcn = @(~,~) generateGeometry(app);
113
114 % 生成网格按钮
115 app.MeshButton = uibutton(controlGrid, 'Text', '生成网格');
116 app.MeshButton.Layout.Column = [1 2];
117 app.MeshButton.Enable = 'off'; % 初始禁用
118 app.MeshButton.ButtonPushedFcn = @(~,~) generateMesh(app);
119
120 % 求解按钮
121 app.SolveButton = uibutton(controlGrid, 'Text', '求解');
122 app.SolveButton.Layout.Column = [1 2];
123 app.SolveButton.Enable = 'off'; % 初始禁用
124 app.SolveButton.ButtonPushedFcn = @(~,~) solvePDE(app);
125
126 % 创建结果显示面板
127 app.ResultsPanel = uipanel(app.MainLayout);
128 app.ResultsPanel.Title = '计算结果';
129 app.ResultsPanel.Layout.Column = 2;
130
131 % 创建结果区域的网格布局
132 resultsGrid = uigridlayout(app.ResultsPanel, [1 1]);
133 resultsGrid.Padding = [0 0 0 0]; % 移除内边距
134
135 % 创建TabGroup并使其填满整个网格
136 app.TabGroup = uitabgroup(resultsGrid);
137 app.TabGroup.Layout.Row = 1;
138 app.TabGroup.Layout.Column = 1;
139
140 % 创建各个标签页
141 app.GeometryTab = uitab(app.TabGroup, 'Title', '几何体');
142 app.MeshTab = uitab(app.TabGroup, 'Title', '网格');
143 app.ResultsTab = uitab(app.TabGroup, 'Title', '结果');
144
145 % 为每个标签页创建网格布局
146 geomGrid = uigridlayout(app.GeometryTab, [1 1]);
147 meshGrid = uigridlayout(app.MeshTab, [1 1]);
148 resultGrid = uigridlayout(app.ResultsTab, [1 1]);
149
150 % 设置网格布局的属性
151 grids = {geomGrid, meshGrid, resultGrid};
152 for g = grids
153 g{1}.Padding = [0 0 0 0];
154 end
155
156 % 创建坐标轴
157 app.GeometryAxes = uiaxes(geomGrid);
158 app.MeshAxes = uiaxes(meshGrid);
159 app.ResultsAxes = uiaxes(resultGrid);
160
161 % 设置所有坐标轴的基本属性
162 axesList = [app.GeometryAxes, app.MeshAxes, app.ResultsAxes];
163 for ax = axesList
164 ax.XGrid = 'on';
165 ax.YGrid = 'on';
166 ax.ZGrid = 'on';
167 ax.Box = 'on';
168 view(ax, 30, 30);
169 end
170
171 % 添加标签切换回调
172 app.TabGroup.SelectionChangedFcn = @(~,~) tabChanged(app);
173 end
实际构造GUI的部分在createComponents
函数中,这个函数在simplePDE
函数(构造函数)中调用。
1 methods
2 function app = simplePDE
3 % 构造函数
4 createComponents(app);
5
6 registerApp(app, app.UIFigure);
7 % 显示界面
8 app.UIFigure.Visible = 'on';
9 end
10
11 function delete(app)
12 % 析构函数
13 if isvalid(app.UIFigure)
14 delete(app.UIFigure);
15 end
16 end
17 end
回调函数
具体的功能在几个回调函数中实现。
1 function tabChanged(app)
2 % 根据当前选择的标签更新显示
3 if isempty(app.Model)
4 return;
5 end
6
7 switch app.TabGroup.SelectedTab.Title
8 case '几何体'
9 cla(app.GeometryAxes);
10 pdegplot(app.Model.Geometry,'FaceLabels','on','FaceAlpha',0.5,...
11 'Parent',app.GeometryAxes);
12 app.ResultTypeDropDown.Enable = 'off';
13 app.DeformationSlider.Enable = 'off';
14 app.DeformationValueLabel.Enable = 'off';
15
16 case '网格'
17 cla(app.MeshAxes);
18 pdeplot3D(app.Model.Mesh,'Parent',app.MeshAxes);
19 app.ResultTypeDropDown.Enable = 'off';
20 app.DeformationSlider.Enable = 'off';
21 app.DeformationValueLabel.Enable = 'off';
22
23 case '结果'
24 if ~isempty(app.Results)
25 app.ResultTypeDropDown.Enable = 'on';
26 app.DeformationSlider.Enable = 'on';
27 app.DeformationValueLabel.Enable = 'on';
28 updateResultsDisplay(app);
29 end
30 end
31
32 end
这个回调函数处理几何体、网格和结果的显示。
1 function updateResultsDisplay(app)
2 if ~isempty(app.Results)
3 cla(app.ResultsAxes);
4
5 % 预处理:根据选择确定要显示的数据
6 switch app.ResultTypeDropDown.Value
7 case '位移大小'
8 colorData = app.Results.Displacement.Magnitude;
9 titleStr = '位移大小';
10 isDisplacement = true;
11 case '应力von Mises'
12 colorData = app.Results.VonMisesStress;
13 titleStr = 'von Mises应力';
14 isDisplacement = false;
15 case 'x方向位移'
16 colorData = app.Results.Displacement.x;
17 titleStr = 'X方向位移';
18 isDisplacement = true;
19 case 'y方向位移'
20 colorData = app.Results.Displacement.y;
21 titleStr = 'Y方向位移';
22 isDisplacement = true;
23 case 'z方向位移'
24 colorData = app.Results.Displacement.z;
25 titleStr = 'Z方向位移';
26 isDisplacement = true;
27 end
28
29 % 自动单位转换
30 if isDisplacement
31 maxAbs = max(abs(colorData(:)));
32 if maxAbs >= 1
33 unitStr = 'm';
34 factor = 1;
35 elseif maxAbs >= 1e-3
36 unitStr = 'mm';
37 factor = 1e3;
38 elseif maxAbs >= 1e-6
39 unitStr = 'μm';
40 factor = 1e6;
41 else
42 unitStr = 'nm';
43 factor = 1e9;
44 end
45 colorData = colorData * factor;
46 else
47 maxAbs = max(abs(colorData(:)));
48 if maxAbs >= 1e9
49 unitStr = 'GPa';
50 factor = 1e-9;
51 elseif maxAbs >= 1e6
52 unitStr = 'MPa';
53 factor = 1e-6;
54 elseif maxAbs >= 1e3
55 unitStr = 'kPa';
56 factor = 1e-3;
57 else
58 unitStr = 'Pa';
59 factor = 1;
60 end
61 colorData = colorData * factor;
62 end
63
64 % 统一的绘图调用
65 pdeplot3D(app.Results.Mesh,...
66 'ColorMapData', colorData,...
67 'Deformation', app.Results.Displacement,...
68 'DeformationScaleFactor', app.DeformationSlider.Value,...
69 'Parent', app.ResultsAxes);
70
71
72 % 添加颜色条和标题
73 cb = colorbar(app.ResultsAxes);
74 title(app.ResultsAxes, titleStr);
75
76 % 设置颜色条标签
77 if isDisplacement
78 cb.Label.String = sprintf('位移 (%s)', unitStr);
79 else
80 cb.Label.String = sprintf('应力 (%s)', unitStr);
81 end
82 end
83 end
这个回调函数处理结果的显示,根据一个下拉列表选择的结果类型,显示不同的结果。注意这里pdeplot3D
的Parent
参数设置为app.ResultsAxes
,这样就可以在GUI的图窗中显示结果。
1 function generateGeometry(app)
2 % 创建有限元模型
3 app.Model = femodel(AnalysisType="structuralStatic");
4
5 % 创建几何
6 L = app.LengthSpinner.Value;
7 W = app.WidthSpinner.Value;
8 H = app.HeightSpinner.Value;
9
10 % 定义长方体几何
11 gm = multicuboid(L,W,H);
12
13 % 将几何导入到模型中
14 app.Model.Geometry = gm;
15
16 % 切换到几何体标签页并显示
17 app.TabGroup.SelectedTab = app.GeometryTab;
18 tabChanged(app);
19
20 % 启用网格生成按钮
21 app.MeshButton.Enable = 'on';
22
23 end
这个回调函数产生几何体,就简单调用multicuboid
函数产生一个长方体,这个函数会把右边的显示切换成几何显示。
1 function generateMesh(app)
2 % 生成网格
3 app.Model = generateMesh(app.Model,'Hmax',app.MeshSizeSpinner.Value);
4
5 % 切换到网格标签页并显示
6 app.TabGroup.SelectedTab = app.MeshTab;
7 tabChanged(app);
8
9 % 启用求解按钮
10 app.SolveButton.Enable = 'on';
11
12
13 end
这个回调函数生成网格,调用generateMesh
函数生成网格,并把右边的显示切换成网格显示。控制网格尺寸的参数从UI中获取。
1 function solvePDE(app)
2 app.SolveButton.Enable = 'off';
3 generateGeometry(app);
4 generateMesh(app);
5 % 设置材料属性
6 app.Model.MaterialProperties = materialProperties(...
7 YoungsModulus=app.YoungModulusSpinner.Value,...
8 PoissonsRatio=app.PoissonRatioSpinner.Value);
9
10 % 设置边界条件
11 % 固定端(F3面,x=0)
12 app.Model.FaceBC(3) = faceBC(Constraint="fixed");
13
14 % 自由端载荷(F5面,x=L)
15 load = app.LoadSpinner.Value;
16 app.Model.FaceLoad(5) = faceLoad(SurfaceTraction=[0;0;load]);
17
18 % 求解
19 app.Results = solve(app.Model);
20
21 % 求解完成后自动切换到结果标签
22 app.TabGroup.SelectedTab = app.ResultsTab;
23 tabChanged(app);
24 app.SolveButton.Enable = 'on';
25 end
这个回调函数求解PDE,调用solve
函数求解PDE,并把右边的显示切换成结果显示。这里边界条件中固定端是faceBC
,载荷是faceLoad
。
完成计算后,还可以切换变形量的显示比例。
1 function deformationValueChanged(app, src)
2 % 更新标签显示
3 app.DeformationValueLabel.Text = sprintf('%.0f', src.Value);
4 % 更新显示
5 updateResultsDisplay(app);
6 end
大概上面的代码就能够构造一个基本的PDE求解的GUI了。当然,我们还可以增加一些优化过程的GUI控制,构成比较完整的、可以提交给用户的App。
完整代码
1classdef simplePDE < matlab.apps.AppBase
2 % 一个简单的PDE工具箱例子的GUI App
3
4 properties (Access = public)
5 % 用户界面组件
6 UIFigure matlab.ui.Figure
7 end
8
9 properties (Access = private)
10
11 % 主布局
12 MainLayout matlab.ui.container.GridLayout
13
14 % 控制面板
15 ControlPanel matlab.ui.container.Panel
16
17 % 几何参数控制
18 LengthSpinner matlab.ui.control.Spinner % 长度
19 WidthSpinner matlab.ui.control.Spinner % 宽度
20 HeightSpinner matlab.ui.control.Spinner % 高度
21
22 % 材料参数控制
23 YoungModulusSpinner matlab.ui.control.Spinner % 杨氏模量
24 PoissonRatioSpinner matlab.ui.control.Spinner % 泊松比
25
26 % 载荷参数控制
27 LoadSpinner matlab.ui.control.Spinner % 载荷大小
28
29 % 网格参数
30 MeshSizeSpinner matlab.ui.control.Spinner % 网格尺寸
31
32 % 变形显示控制
33 DeformationSlider matlab.ui.control.Slider % 变形比例因子
34 DeformationValueLabel matlab.ui.control.Label % 变形比例值显示
35
36 % 按钮控件
37 GeometryButton matlab.ui.control.Button % 生成几何体按钮
38 MeshButton matlab.ui.control.Button % 生成网格按钮
39 SolveButton matlab.ui.control.Button % 求解按钮
40
41 % 结果显示区域
42 ResultsPanel matlab.ui.container.Panel
43 TabGroup matlab.ui.container.TabGroup
44 GeometryTab matlab.ui.container.Tab
45 MeshTab matlab.ui.container.Tab
46 ResultsTab matlab.ui.container.Tab
47 GeometryAxes matlab.ui.control.UIAxes
48 MeshAxes matlab.ui.control.UIAxes
49 ResultsAxes matlab.ui.control.UIAxes
50
51 % 结果类型选择
52 ResultTypeDropDown matlab.ui.control.DropDown
53
54 % PDE模型
55 Model
56 Results
57 end
58
59 methods (Access = private)
60 function createComponents(app)
61 % 创建主窗口
62 app.UIFigure = uifigure('Name', '悬臂梁有限元分析');
63 app.UIFigure.Position = [100 100 1200 800];
64 movegui(app.UIFigure,'center');
65
66 % 创建主网格布局
67 app.MainLayout = uigridlayout(app.UIFigure, [1 2]);
68 app.MainLayout.ColumnWidth = {300, '1x'};
69 app.MainLayout.Padding = [0 0 0 0]; % 移除边距
70 app.MainLayout.RowSpacing = 0; % 移除行间距
71 app.MainLayout.ColumnSpacing = 0; % 移除列间距
72
73 % 创建控制面板
74 app.ControlPanel = uipanel(app.MainLayout);
75 app.ControlPanel.Title = '参数控制';
76 app.ControlPanel.Layout.Column = 1;
77
78 % 修改控制面板的网格布局以容纳更多控件
79 controlGrid = uigridlayout(app.ControlPanel, [18 2]);
80 controlGrid.RowHeight = {25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 35, 25, 25, 25, 25, 25, 25}; % 固定每行高度
81 controlGrid.ColumnWidth = {'1x', '1x'}; % 两列等宽
82 controlGrid.Padding = [10 10 10 10];
83 controlGrid.RowSpacing = 5; % 减小行间距
84 controlGrid.ColumnSpacing = 10; % 设置列间距
85
86 % 几何参数控件
87 uilabel(controlGrid, 'Text', '几何参数', 'FontWeight', 'bold');
88 uilabel(controlGrid, 'Text', '');
89
90 uilabel(controlGrid, 'Text', '长度 (m)');
91 app.LengthSpinner = uispinner(controlGrid);
92 app.LengthSpinner.Limits = [0.1 10];
93 app.LengthSpinner.Value = 1;
94
95 uilabel(controlGrid, 'Text', '宽度 (m)');
96 app.WidthSpinner = uispinner(controlGrid);
97 app.WidthSpinner.Limits = [0.01 1];
98 app.WidthSpinner.Value = 0.1;
99
100 uilabel(controlGrid, 'Text', '高度 (m)');
101 app.HeightSpinner = uispinner(controlGrid);
102 app.HeightSpinner.Limits = [0.01 1];
103 app.HeightSpinner.Value = 0.1;
104
105 % 材料参数控件
106 uilabel(controlGrid, 'Text', '材料参数', 'FontWeight', 'bold');
107 emptyLabel = uilabel(controlGrid, 'Text', '');
108
109 uilabel(controlGrid, 'Text', '杨氏模量 (Pa)');
110 app.YoungModulusSpinner = uispinner(controlGrid);
111 app.YoungModulusSpinner.Limits = [1e6 1e12];
112 app.YoungModulusSpinner.Value = 2e11; % 钢的杨氏模量
113 app.YoungModulusSpinner.Step = 1e9;
114
115 uilabel(controlGrid, 'Text', '泊松比');
116 app.PoissonRatioSpinner = uispinner(controlGrid);
117 app.PoissonRatioSpinner.Limits = [0 0.5];
118 app.PoissonRatioSpinner.Value = 0.3;
119 app.PoissonRatioSpinner.Step = 0.01;
120
121 % 载荷参数控件
122 uilabel(controlGrid, 'Text', '载荷参数', 'FontWeight', 'bold');
123 uilabel(controlGrid, 'Text', '');
124
125 uilabel(controlGrid, 'Text', '载荷 (N)');
126 app.LoadSpinner = uispinner(controlGrid);
127 app.LoadSpinner.Limits = [-1e6 1e6];
128 app.LoadSpinner.Value = -100000;
129 app.LoadSpinner.Step = 100;
130
131 % 网格参数控件
132 uilabel(controlGrid, 'Text', '网格参数', 'FontWeight', 'bold');
133 uilabel(controlGrid, 'Text', '');
134
135 uilabel(controlGrid, 'Text', '网格尺寸');
136 app.MeshSizeSpinner = uispinner(controlGrid);
137 app.MeshSizeSpinner.Limits = [0.01 0.5];
138 app.MeshSizeSpinner.Value = 0.05;
139 app.MeshSizeSpinner.Step = 0.01;
140
141 % 变形显示控制
142 uilabel(controlGrid, 'Text', '变形显示', 'FontWeight', 'bold');
143 uilabel(controlGrid, 'Text', '');
144
145 uilabel(controlGrid, 'Text', '变形比例');
146 app.DeformationValueLabel = uilabel(controlGrid, 'Text', '500'); % 初始值显示
147
148 sliderGrid = uigridlayout(controlGrid, [1 1]); % 创建滑块的网格布局
149 sliderGrid.Layout.Column = [1 2]; % 跨两列
150 sliderGrid.Padding = [0 5 0 5]; % 添加适当的上下内边距
151 app.DeformationSlider = uislider(sliderGrid);
152 app.DeformationSlider.Limits = [10 10000];
153 app.DeformationSlider.Value = 500;
154 app.DeformationSlider.ValueChangedFcn = @(src,~) deformationValueChanged(app, src);
155 app.DeformationSlider.Enable = 'off'; % 初始禁用
156 app.DeformationValueLabel.Enable = 'off'; % 初始禁用
157
158 % 添加结果类型选择下拉列表
159 uilabel(controlGrid, 'Text', '结果类型');
160 app.ResultTypeDropDown = uidropdown(controlGrid);
161 app.ResultTypeDropDown.Items = {'位移大小', '应力von Mises', 'x方向位移', 'y方向位移', 'z方向位移'};
162 app.ResultTypeDropDown.Value = '位移大小';
163 app.ResultTypeDropDown.ValueChangedFcn = @(~,~) updateResultsDisplay(app);
164 app.ResultTypeDropDown.Enable = 'off'; % 初始禁用
165
166 % 添加按钮控件(在控制面板网格布局中)
167 % 生成几何体按钮
168 app.GeometryButton = uibutton(controlGrid, 'Text', '生成几何体');
169 app.GeometryButton.Layout.Column = [1 2];
170 app.GeometryButton.ButtonPushedFcn = @(~,~) generateGeometry(app);
171
172 % 生成网格按钮
173 app.MeshButton = uibutton(controlGrid, 'Text', '生成网格');
174 app.MeshButton.Layout.Column = [1 2];
175 app.MeshButton.Enable = 'off'; % 初始禁用
176 app.MeshButton.ButtonPushedFcn = @(~,~) generateMesh(app);
177
178 % 求解按钮
179 app.SolveButton = uibutton(controlGrid, 'Text', '求解');
180 app.SolveButton.Layout.Column = [1 2];
181 app.SolveButton.Enable = 'off'; % 初始禁用
182 app.SolveButton.ButtonPushedFcn = @(~,~) solvePDE(app);
183
184 % 创建结果显示面板
185 app.ResultsPanel = uipanel(app.MainLayout);
186 app.ResultsPanel.Title = '计算结果';
187 app.ResultsPanel.Layout.Column = 2;
188
189 % 创建结果区域的网格布局
190 resultsGrid = uigridlayout(app.ResultsPanel, [1 1]);
191 resultsGrid.Padding = [0 0 0 0]; % 移除内边距
192
193 % 创建TabGroup并使其填满整个网格
194 app.TabGroup = uitabgroup(resultsGrid);
195 app.TabGroup.Layout.Row = 1;
196 app.TabGroup.Layout.Column = 1;
197
198 % 创建各个标签页
199 app.GeometryTab = uitab(app.TabGroup, 'Title', '几何体');
200 app.MeshTab = uitab(app.TabGroup, 'Title', '网格');
201 app.ResultsTab = uitab(app.TabGroup, 'Title', '结果');
202
203 % 为每个标签页创建网格布局
204 geomGrid = uigridlayout(app.GeometryTab, [1 1]);
205 meshGrid = uigridlayout(app.MeshTab, [1 1]);
206 resultGrid = uigridlayout(app.ResultsTab, [1 1]);
207
208 % 设置网格布局的属性
209 grids = {geomGrid, meshGrid, resultGrid};
210 for g = grids
211 g{1}.Padding = [0 0 0 0];
212 end
213
214 % 创建坐标轴
215 app.GeometryAxes = uiaxes(geomGrid);
216 app.MeshAxes = uiaxes(meshGrid);
217 app.ResultsAxes = uiaxes(resultGrid);
218
219 % 设置所有坐标轴的基本属性
220 axesList = [app.GeometryAxes, app.MeshAxes, app.ResultsAxes];
221 for ax = axesList
222 ax.XGrid = 'on';
223 ax.YGrid = 'on';
224 ax.ZGrid = 'on';
225 ax.Box = 'on';
226 view(ax, 30, 30);
227 end
228
229 % 添加标签切换回调
230 app.TabGroup.SelectionChangedFcn = @(~,~) tabChanged(app);
231 end
232
233 function tabChanged(app)
234 % 根据当前选择的标签更新显示
235 if isempty(app.Model)
236 return;
237 end
238
239 switch app.TabGroup.SelectedTab.Title
240 case '几何体'
241 cla(app.GeometryAxes);
242 pdegplot(app.Model.Geometry,'FaceLabels','on','FaceAlpha',0.5,...
243 'Parent',app.GeometryAxes);
244 app.ResultTypeDropDown.Enable = 'off';
245 app.DeformationSlider.Enable = 'off';
246 app.DeformationValueLabel.Enable = 'off';
247
248 case '网格'
249 cla(app.MeshAxes);
250 pdeplot3D(app.Model.Mesh,'Parent',app.MeshAxes);
251 app.ResultTypeDropDown.Enable = 'off';
252 app.DeformationSlider.Enable = 'off';
253 app.DeformationValueLabel.Enable = 'off';
254
255 case '结果'
256 if ~isempty(app.Results)
257 app.ResultTypeDropDown.Enable = 'on';
258 app.DeformationSlider.Enable = 'on';
259 app.DeformationValueLabel.Enable = 'on';
260 updateResultsDisplay(app);
261 end
262 end
263
264 end
265
266 function updateResultsDisplay(app)
267 if ~isempty(app.Results)
268 cla(app.ResultsAxes);
269
270 % 预处理:根据选择确定要显示的数据
271 switch app.ResultTypeDropDown.Value
272 case '位移大小'
273 colorData = app.Results.Displacement.Magnitude;
274 titleStr = '位移大小';
275 isDisplacement = true;
276 case '应力von Mises'
277 colorData = app.Results.VonMisesStress;
278 titleStr = 'von Mises应力';
279 isDisplacement = false;
280 case 'x方向位移'
281 colorData = app.Results.Displacement.x;
282 titleStr = 'X方向位移';
283 isDisplacement = true;
284 case 'y方向位移'
285 colorData = app.Results.Displacement.y;
286 titleStr = 'Y方向位移';
287 isDisplacement = true;
288 case 'z方向位移'
289 colorData = app.Results.Displacement.z;
290 titleStr = 'Z方向位移';
291 isDisplacement = true;
292 end
293
294 % 自动单位转换
295 if isDisplacement
296 maxAbs = max(abs(colorData(:)));
297 if maxAbs >= 1
298 unitStr = 'm';
299 factor = 1;
300 elseif maxAbs >= 1e-3
301 unitStr = 'mm';
302 factor = 1e3;
303 elseif maxAbs >= 1e-6
304 unitStr = 'μm';
305 factor = 1e6;
306 else
307 unitStr = 'nm';
308 factor = 1e9;
309 end
310 colorData = colorData * factor;
311 else
312 maxAbs = max(abs(colorData(:)));
313 if maxAbs >= 1e9
314 unitStr = 'GPa';
315 factor = 1e-9;
316 elseif maxAbs >= 1e6
317 unitStr = 'MPa';
318 factor = 1e-6;
319 elseif maxAbs >= 1e3
320 unitStr = 'kPa';
321 factor = 1e-3;
322 else
323 unitStr = 'Pa';
324 factor = 1;
325 end
326 colorData = colorData * factor;
327 end
328
329 % 统一的绘图调用
330 pdeplot3D(app.Results.Mesh,...
331 'ColorMapData', colorData,...
332 'Deformation', app.Results.Displacement,...
333 'DeformationScaleFactor', app.DeformationSlider.Value,...
334 'Parent', app.ResultsAxes);
335
336
337 % 添加颜色条和标题
338 cb = colorbar(app.ResultsAxes);
339 title(app.ResultsAxes, titleStr);
340
341 % 设置颜色条标签
342 if isDisplacement
343 cb.Label.String = sprintf('位移 (%s)', unitStr);
344 else
345 cb.Label.String = sprintf('应力 (%s)', unitStr);
346 end
347 end
348 end
349
350 function generateGeometry(app)
351 % 创建有限元模型
352 app.Model = femodel(AnalysisType="structuralStatic");
353
354 % 创建几何
355 L = app.LengthSpinner.Value;
356 W = app.WidthSpinner.Value;
357 H = app.HeightSpinner.Value;
358
359 % 定义长方体几何
360 gm = multicuboid(L,W,H);
361
362 % 将几何导入到模型中
363 app.Model.Geometry = gm;
364
365 % 切换到几何体标签页并显示
366 app.TabGroup.SelectedTab = app.GeometryTab;
367 tabChanged(app);
368
369 % 启用网格生成按钮
370 app.MeshButton.Enable = 'on';
371
372 end
373
374 function generateMesh(app)
375 % 生成网格
376 app.Model = generateMesh(app.Model,'Hmax',app.MeshSizeSpinner.Value);
377
378 % 切换到网格标签页并显示
379 app.TabGroup.SelectedTab = app.MeshTab;
380 tabChanged(app);
381
382 % 启用求解按钮
383 app.SolveButton.Enable = 'on';
384
385
386 end
387
388 function solvePDE(app)
389 app.SolveButton.Enable = 'off';
390 generateGeometry(app);
391 generateMesh(app);
392 % 设置材料属性
393 app.Model.MaterialProperties = materialProperties(...
394 YoungsModulus=app.YoungModulusSpinner.Value,...
395 PoissonsRatio=app.PoissonRatioSpinner.Value);
396
397 % 设置边界条件
398 % 固定端(F3面,x=0)
399 app.Model.FaceBC(3) = faceBC(Constraint="fixed");
400
401 % 自由端载荷(F5面,x=L)
402 load = app.LoadSpinner.Value;
403 app.Model.FaceLoad(5) = faceLoad(SurfaceTraction=[0;0;load]);
404
405 % 求解
406 app.Results = solve(app.Model);
407
408 % 求解完成后自动切换到结果标签
409 app.TabGroup.SelectedTab = app.ResultsTab;
410 tabChanged(app);
411 app.SolveButton.Enable = 'on';
412 end
413
414 function deformationValueChanged(app, src)
415 % 更新标签显示
416 app.DeformationValueLabel.Text = sprintf('%.0f', src.Value);
417 % 更新显示
418 updateResultsDisplay(app);
419 end
420 end
421
422 methods
423 function app = simplePDE
424 % 构造函数
425 createComponents(app);
426
427 registerApp(app, app.UIFigure);
428 % 显示界面
429 app.UIFigure.Visible = 'on';
430 end
431
432 function delete(app)
433 % 析构函数
434 if isvalid(app.UIFigure)
435 delete(app.UIFigure);
436 end
437 end
438 end
439end
文章标签
|-->matlab |-->pdegplot |-->pdeplot |-->pdeplot3D |-->GUI |-->appdesigner
- 本站总访问量:次
- 本站总访客数:人
- 可通过邮件联系作者:Email大福
- 也可以访问技术博客:大福是小强
- 也可以在知乎搞抽象:知乎-大福
- Comments, requests, and/or opinions go to: Github Repository