写在最前:本人非计算机科班出身,写代码是绝对的外行,软件中肯定有一些bug和屎山代码。请各位多包涵,也欢迎各路大佬们疯狂吐槽
基于MATLAB appdesigner设计了两款自行车辐条计算器,一个普通版一个专业版,普通版只能计算常规车圈和常规编法。专业版可以计算任意的车圈和编法。目前需要安装MATLAB才能使用,之后可能会打包成单独的app。
注:此代码是基于MATLAB 2022b写的,这几年MATLAB appdesigner更新得挺多的,过老的版本可能不支持。
普通版:
普通版只能计算常规车圈和常规编法。但是请注意该版本只计算了点到点的距离,没有考虑辐条的直径和拉伸长度(一般来说实际辐条长度是计算结果再减去辐条直径的1/2)。
普通版界面如下,使用非常简洁明了,输入各项数据点击计算即可得出辐条长度和轮组示意图。
附上源代码:
通过网盘分享的文件:普通版
链接: https://pan.baidu.com/s/12HNwu8h4PKnFL7UVAVFH1Q 提取码: nsjy
classdef MajorTom_SpokeCalculate < matlab.apps.AppBase
% Properties that correspond to app components
properties (Access = public)
UIFigure matlab.ui.Figure
SopkeLenTextArea matlab.ui.control.TextArea
Label_5 matlab.ui.control.Label
CalculateButton matlab.ui.control.StateButton
Spoke_NumDropDown matlab.ui.control.DropDown
Label_4 matlab.ui.control.Label
WeaveDropDown matlab.ui.control.DropDown
Label_3 matlab.ui.control.Label
OffsetEditField matlab.ui.control.EditField
Label_2 matlab.ui.control.Label
HubDiamEditField matlab.ui.control.EditField
EditFieldLabel matlab.ui.control.Label
ERDEditField matlab.ui.control.EditField
Label matlab.ui.control.Label
UIAxes matlab.ui.control.UIAxes
end
properties (Access = public)
ERD
HubDiameter
HubHole_Num
RimHole_Num
Weave
Offset
SpokeLen
end
% Callbacks that handle component events
methods (Access = private)
% Value changed function: CalculateButton
function CalculateButtonValueChanged(app, event)
app.ERD = str2double(app.ERDEditField.Value);
app.HubHole_Num = str2num(app.Spoke_NumDropDown.Value);
app.RimHole_Num = str2num(app.Spoke_NumDropDown.Value);
app.Weave = app.WeaveDropDown.Value;
app.Offset = str2double(app.OffsetEditField.Value);
app.HubDiameter = str2double(app.HubDiamEditField.Value);
% ======= show the half wheel in uiAxes ========
hold(app.UIAxes,'off')
Lim = app.ERD /2 * 1.1;
app.UIAxes.XLim = [-Lim,Lim];
app.UIAxes.YLim = [-Lim,Lim];
% ----- the Rim -----
Rim_phi = linspace(0,2*pi,1024);
Rim_x = app.ERD/2 .* sin(Rim_phi);
Rim_y = app.ERD/2 .* cos(Rim_phi);
plot(app.UIAxes,Rim_x,Rim_y)
RimHole_phi = linspace(0,2*pi,app.RimHole_Num./2+1);
RimHole_x = app.ERD/2 .* sin(RimHole_phi);
RimHole_y = app.ERD/2 .* cos(RimHole_phi);
hold(app.UIAxes,'on')
plot(app.UIAxes,RimHole_x,RimHole_y,"Marker","o","LineStyle","none");
% ---- the Hub -----
Hub_phi = linspace(0,2*pi,1024);
Hub_x = app.HubDiameter/2 .* sin(Hub_phi);
Hub_y = app.HubDiameter/2 .* cos(Hub_phi);
plot(app.UIAxes,Hub_x,Hub_y)
HubHole_phi = linspace(0,2*pi,app.HubHole_Num /2+1);
HubHole_x = app.HubDiameter/2 .* sin(HubHole_phi);
HubHole_y = app.HubDiameter/2 .* cos(HubHole_phi);
plot(app.UIAxes,HubHole_x,HubHole_y,"Marker","o","LineStyle","none");
% ---- the Spoke -----
% |\
% spokeLen | \
% (2D) | \ SpokeLen(real)
% |___\
% Offset
switch app.Weave
case '0X'
% Show the Spoke
for k = 1 : app.HubHole_Num/2
plot(app.UIAxes,[HubHole_x(k),RimHole_x(k)],...
[HubHole_y(k),RimHole_y(k)],"LineStyle","-","Color",[0.39,0.83,0.07])
end
% Calculate the length of Spoken
spokeLen = sqrt( (HubHole_x(k)-RimHole_x(k)).^2 + ...
(HubHole_y(k)-RimHole_y(k)).^2 ); % the Spoken length in 2D plane
app.SpokeLen = sqrt( (app.Offset).^2 + spokeLen.^2 );
case '1X'
% Show the Spoke
for k = 1 : app.HubHole_Num/2 /2
plot(app.UIAxes,[HubHole_x(2*k),RimHole_x(2*k-1)],...
[HubHole_y(2*k),RimHole_y(2*k-1)],"LineStyle","-","Color",[0.39,0.83,0.07])
plot(app.UIAxes,[HubHole_x(2*k-1),RimHole_x(2*k)],...
[HubHole_y(2*k-1),RimHole_y(2*k)],"LineStyle","-","Color",[0.39,0.83,0.07])
end
% Calculate the length of Spoken
spokeLen = sqrt( (HubHole_x(2*k)-RimHole_x(2*k-1)).^2 + ...
(HubHole_y(2*k)-RimHole_y(2*k-1)).^2 ); % the Spoken length in 2D plane
app.SpokeLen = sqrt( (app.Offset).^2 + spokeLen.^2 );
case '2X'
HubHole_x_extend = [HubHole_x,HubHole_x(2:end)];
HubHole_y_extend = [HubHole_y,HubHole_y(2:end)];
RimHole_x_extend = [RimHole_x,RimHole_x(2:end)];
RimHole_y_extend = [RimHole_y,RimHole_y(2:end)];
for k = 2 : app.HubHole_Num/2 /2 + 1
plot(app.UIAxes,[HubHole_x_extend(2*k),RimHole_x_extend(2*k-2)],...
[HubHole_y_extend(2*k),RimHole_y_extend(2*k-2)],"LineStyle","-","Color",[0.39,0.83,0.07])
plot(app.UIAxes,[HubHole_x_extend(2*k-1),RimHole_x_extend(2*k+1)],...
[HubHole_y_extend(2*k-1),RimHole_y_extend(2*k+1)],"LineStyle","-","Color",[0.39,0.83,0.07])
end
spokeLen = sqrt( (HubHole_x_extend(2*k)-RimHole_x_extend(2*k-2)).^2 + ...
(HubHole_y_extend(2*k)-RimHole_y_extend(2*k-2)).^2 ); % the Spoken length in 2D plane
app.SpokeLen = sqrt( (app.Offset).^2 + spokeLen.^2 );
case '3X'
HubHole_x_extend = [HubHole_x,HubHole_x(2:end)];
HubHole_y_extend = [HubHole_y,HubHole_y(2:end)];
RimHole_x_extend = [RimHole_x,RimHole_x(2:end)];
RimHole_y_extend = [RimHole_y,RimHole_y(2:end)];
for k = 3 : app.HubHole_Num/2 /2 + 2
plot(app.UIAxes,[HubHole_x_extend(2*k),RimHole_x_extend(2*k-3)],...
[HubHole_y_extend(2*k),RimHole_y_extend(2*k-3)],"LineStyle","-","Color",[0.39,0.83,0.07])
plot(app.UIAxes,[HubHole_x_extend(2*k-1),RimHole_x_extend(2*k+2)],...
[HubHole_y_extend(2*k-1),RimHole_y_extend(2*k+2)],"LineStyle","-","Color",[0.39,0.83,0.07])
end
spokeLen = sqrt( (HubHole_x_extend(2*k)-RimHole_x_extend(2*k-3)).^2 + ...
(HubHole_y_extend(2*k)-RimHole_y_extend(2*k-3)).^2 ); % the Spoken length in 2D plane
app.SpokeLen = sqrt( (app.Offset).^2 + spokeLen.^2 );
case '4X'
HubHole_x_extend = [HubHole_x,HubHole_x(2:end)];
HubHole_y_extend = [HubHole_y,HubHole_y(2:end)];
RimHole_x_extend = [RimHole_x,RimHole_x(2:end)];
RimHole_y_extend = [RimHole_y,RimHole_y(2:end)];
for k = 4 : app.HubHole_Num/2 /2 + 3
plot(app.UIAxes,[HubHole_x_extend(2*k),RimHole_x_extend(2*k-4)],...
[HubHole_y_extend(2*k),RimHole_y_extend(2*k-4)],"LineStyle","-","Color",[0.39,0.83,0.07])
plot(app.UIAxes,[HubHole_x_extend(2*k-1),RimHole_x_extend(2*k+3)],...
[HubHole_y_extend(2*k-1),RimHole_y_extend(2*k+3)],"LineStyle","-","Color",[0.39,0.83,0.07])
end
spokeLen = sqrt( (HubHole_x_extend(2*k)-RimHole_x_extend(2*k-4)).^2 + ...
(HubHole_y_extend(2*k)-RimHole_y_extend(2*k-4)).^2 ); % the Spoken length in 2D plane
app.SpokeLen = sqrt( (app.Offset).^2 + spokeLen.^2 );
end
% My Experimen
% if app.ERD > 451
% app.SpokeLen = app.SpokeLen - 1.3;
% else
% app.SpokeLen = app.SpokeLen - 0.5;
% end
app.SopkeLenTextArea.Value = num2str(app.SpokeLen);
end
end
% Component initialization
methods (Access = private)
% Create UIFigure and components
function createComponents(app)
% Create UIFigure and hide until all components are created
app.UIFigure = uifigure('Visible', 'off');
app.UIFigure.Position = [100 100 829 486];
app.UIFigure.Name = 'MATLAB App';
% Create UIAxes
app.UIAxes = uiaxes(app.UIFigure);
title(app.UIAxes, '示意图')
xlabel(app.UIAxes, 'X')
ylabel(app.UIAxes, 'Y')
zlabel(app.UIAxes, 'Z')
app.UIAxes.TickDir = 'in';
app.UIAxes.Position = [9 21 445 447];
% Create Label
app.Label = uilabel(app.UIFigure);
app.Label.HorizontalAlignment = 'center';
app.Label.FontSize = 16;
app.Label.Position = [584 342 48 22];
app.Label.Text = 'ERD';
% Create ERDEditField
app.ERDEditField = uieditfield(app.UIFigure, 'text');
app.ERDEditField.FontSize = 16;
app.ERDEditField.Position = [647 339 100 25];
% Create EditFieldLabel
app.EditFieldLabel = uilabel(app.UIFigure);
app.EditFieldLabel.HorizontalAlignment = 'center';
app.EditFieldLabel.FontSize = 16;
app.EditFieldLabel.Position = [563 299 69 22];
app.EditFieldLabel.Text = '花鼓直径';
% Create HubDiamEditField
app.HubDiamEditField = uieditfield(app.UIFigure, 'text');
app.HubDiamEditField.FontSize = 16;
app.HubDiamEditField.Position = [647 298 100 25];
% Create Label_2
app.Label_2 = uilabel(app.UIFigure);
app.Label_2.HorizontalAlignment = 'center';
app.Label_2.FontSize = 16;
app.Label_2.Position = [516 258 116 22];
app.Label_2.Text = '花鼓中心偏移量';
% Create OffsetEditField
app.OffsetEditField = uieditfield(app.UIFigure, 'text');
app.OffsetEditField.FontSize = 16;
app.OffsetEditField.Position = [647 257 100 25];
% Create Label_3
app.Label_3 = uilabel(app.UIFigure);
app.Label_3.HorizontalAlignment = 'right';
app.Label_3.FontSize = 16;
app.Label_3.Position = [563 218 69 22];
app.Label_3.Text = '编织方法';
% Create WeaveDropDown
app.WeaveDropDown = uidropdown(app.UIFigure);
app.WeaveDropDown.Items = {'0X', '1X', '2X', '3X', '4X'};
app.WeaveDropDown.FontSize = 16;
app.WeaveDropDown.Position = [647 218 100 22];
app.WeaveDropDown.Value = '0X';
% Create Label_4
app.Label_4 = uilabel(app.UIFigure);
app.Label_4.HorizontalAlignment = 'right';
app.Label_4.FontSize = 16;
app.Label_4.Position = [536 381 96 22];
app.Label_4.Text = '辐条数(双边)';
% Create Spoke_NumDropDown
app.Spoke_NumDropDown = uidropdown(app.UIFigure);
app.Spoke_NumDropDown.Items = {'16', '20', '24', '28', '32', '36', '40', '48'};
app.Spoke_NumDropDown.FontSize = 16;
app.Spoke_NumDropDown.Position = [647 381 100 22];
app.Spoke_NumDropDown.Value = '16';
% Create CalculateButton
app.CalculateButton = uibutton(app.UIFigure, 'state');
app.CalculateButton.ValueChangedFcn = createCallbackFcn(app, @CalculateButtonValueChanged, true);
app.CalculateButton.Text = '计算';
app.CalculateButton.FontSize = 16;
app.CalculateButton.Position = [616 83 100 28];
% Create Label_5
app.Label_5 = uilabel(app.UIFigure);
app.Label_5.HorizontalAlignment = 'right';
app.Label_5.FontSize = 16;
app.Label_5.Position = [548 135 69 22];
app.Label_5.Text = '辐条长度';
% Create SopkeLenTextArea
app.SopkeLenTextArea = uitextarea(app.UIFigure);
app.SopkeLenTextArea.FontSize = 16;
app.SopkeLenTextArea.Position = [632 135 131 24];
% Show the figure after all components are created
app.UIFigure.Visible = 'on';
end
end
% App creation and deletion
methods (Access = public)
% Construct app
function app = MajorTom_SpokeCalculate
% Create UIFigure and components
createComponents(app)
% Register the app with App Designer
registerApp(app, app.UIFigure)
if nargout == 0
clear app
end
end
% Code that executes before app deletion
function delete(app)
% Delete UIFigure when app is deleted
delete(app.UIFigure)
end
end
end
专业版:
对于一些造型比较奇特的轮组(比如CP的G3编法,或者一些脑洞大开的编法)普通版难以胜任。目前一般的方法是用CAD画图。但是需要下载学习巨大无比的CAD软件。
但是专业版可以自定义每一个孔位的位置和每一根辐条的连接,可以轻松计算出辐条长度。(虽然现在也需要下载巨大无比的MATLAB,但之后会打包成独立的软件)
专业版界面如下:
附上源代码和使用说明:
通过网盘分享的文件:专业版
链接: https://pan.baidu.com/s/1677uNL35yYfqIn0Kljha5Q 提取码: njan
需要将三个.mlapp文件放在同一文件夹中,使用时打开SpokeCalculator_Professional_MajorTom即可。使用前请务必阅读使用说明。
欢迎各位亲切友好交流!!!