/
sfun3d.m
191 lines (155 loc) · 8.41 KB
/
sfun3d.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
function [sys, x0, str, ts] = sfun3d(~,~,u,flag,ax,varargin)
%SFUN3D S-function that acts as an X-Y-Z scope using MATLAB plotting functions.
% This M-file is designed to be used in a Simulink S-function block.
% It draws a line from the previous input point and the current point.
%
% NOTE: this is a new version of sfunxyz. It has more natural inputs
% that is (x1,y1,z1, x2,y2,z2 ... instead of x1,x2, y1,y2, z1,z2 ...)
% and has the LineStyle and Marker properties as additional parameters,
% so for versions 2014b and later users should try to use this one
% instead of the older sfunxyz.
%
% See also sfunxy, sfunxys.
% Copyright 2017 The MathWorks, Inc.
% Based on original work by Andy Grace (May-91), Wes Wang (Apr-93, Aug-93,
% Dec-93), Craig Santos (Oct-96), and Giampiero Campa (Apr-04, Nov-15,
% Jan-17, Nov-17).
switch flag
case 0 % [sys,x0,str,ts]=mdlInitializeSizes (ax,varargin) -------------
% Returns the sizes, initial conditions, and sample times
% Here is used also to set callbacks, and initialize the figure objects
% version check
vrs=version;
if str2double(vrs(1:3))<8.4
error('This S-Function (sfun3d.m) works only within MATLAB versions 2014b and later. For older versions, please delete any existing version of 3Dscope, (re)install it with this MATLAB version, and use the legacy S-Function ''sfunxyz.m''.');
end
% build callback strings (to be called when the user performs some actions on the block)
callbacks={
'CopyFcn', 'if exist(''sfun3d'',''file''), sfun3d([],[],[],''CopyBlock''); end';
'DeleteFcn', 'if exist(''sfun3d'',''file''), sfun3d([],[],[],''DeleteBlock''); end';
'LoadFcn', 'if exist(''sfun3d'',''file''), sfun3d([],[],[],''LoadBlock''); end';
'NameChangeFcn', 'if exist(''sfun3d'',''file''), sfun3d([],[],[],''NameChange''); end';
'StartFcn', '';
'StopFcn', '';
};
% set callbacks as block properties (for these, flag is a string)
for i=1:length(callbacks)
if ~strcmp(get_param(gcbh,callbacks{i,1}),callbacks{i,2})
set_param(gcbh,callbacks{i,1},callbacks{i,2})
end
end
% ax was there in sfunxy, for everything else there's varargin
if length(ax)~=6, error('Axes limits must be defined.'); end
% get number of moving points (i.e. number of lines) to be plotted
if nargin>6, nmax=fix(varargin{2}); else nmax=1; end
sizes=simsizes; % this initializes size vector to zero
sizes.NumInputs = 3*nmax; % input vector size at runtime
sizes.NumSampleTimes = 1; % fill number of sample times
% get sample time
if nargin>5, ts=[varargin{1} 0]; else ts=[0.01 0]; end
% return initialization values to simulink as function outputs
sys=simsizes(sizes);x0=[];str=[];
% get the active figure parameter (toolbar and menubar)
if nargin>13 && varargin{9}, tb='figure'; else tb='none'; end
% do the figure initialization
FigHandle=get_param(gcbh,'UserData');
if isempty(FigHandle) || ~ishandle(FigHandle)
% the figure doesn't exist, create one
FigHandle = figure(...
'Units', 'pixel',...
'Position', [100 100 400 300],...
'Name', get_param(gcbh,'Name'),...
'Tag', 'SIMULINK_3DGRAPH_FIGURE',...
'NumberTitle', 'off',...
'IntegerHandle', 'off',...
'Toolbar', tb,...
'Menubar', tb);
else
% otherwise clear it
clf(FigHandle);
end
% get number of moving points, camera position, and grid switch
if nargin>7, CPos=varargin{3}; else CPos=[3 2 1]*100; end
if nargin>8 && varargin{4}, GdSw='On'; else GdSw='Off'; end
% Note: the structure pd contains all the plot data and will be
% later stored in the figure's userdata!
% create axes
pd.XYZAxes = axes('Parent',FigHandle);
cord=get(pd.XYZAxes,'ColorOrder');
set(pd.XYZAxes,'Visible','on','Xlim', ax(1:2),'Ylim', ax(3:4),'Zlim', ax(5:6),'CameraPosition',CPos,'XGrid',GdSw,'YGrid',GdSw,'ZGrid',GdSw);
% get LineStyle string, Marker string, and max num of line points
if nargin>9, ls=varargin{5}; else ls='-'; end
if nargin>10, mk=varargin{6}; else mk='none'; end
if nargin>11, mx=varargin{7}; else mx=1e5; end
% create a vector of animatedline objects
pd.XYZLine = [];
for n=1:nmax
pd.XYZLine = [pd.XYZLine animatedline('Parent',pd.XYZAxes,'LineStyle',ls,'Marker',mk,'MaximumNumPoints',mx,'Color',cord(1+mod(n-1,size(cord,1)),:))];
end
% create a vector of line object that will represent the current point position
if nargin>12 && varargin{8}
pd.XYZHead = [];
mrks={'o';'square';'diamond';'v';'+';'*';'x';'^';'>';'<';'pentagram';'hexagram'};
for n=1:nmax
pd.XYZHead = [pd.XYZHead line('Parent',pd.XYZAxes,'Marker',mrks{1+mod(n-1,size(mrks,1))},'Color',cord(1+mod(n-1,size(cord,1)),:))];
end
end
% create axis labels
xlabel('X Axis');ylabel('Y Axis');zlabel('Z Axis');
% create plot title
pd.XYZTitle = get(pd.XYZAxes,'Title');
set(pd.XYZTitle,'String','X Y Z Plot');
% Store pd so it can be later retrieved at runtime
set(FigHandle,'UserData',pd); % store pd in figure's userdata
set_param(gcbh,'UserData',FigHandle); % store figure handle in block's UserData
case 2 % sys=mdlUpdate(~,~,u,~) ---------------------------------------
% Handle discrete state updates, sample time hits, and major time step stuff
% Here is used only to add another point to the lines
% always return empty, as there are no states
sys = [];
% Locate the figure window associated with this block. If it's not a valid
% handle (it may have been closed by the user), then return.
FigHandle=get_param(gcbh,'UserData');
if isempty(FigHandle) || ~ishandle(FigHandle), return, end
% get plot data structure
pd = get(FigHandle,'UserData');
% add points to each line
nmax=length(pd.XYZLine);
for i=1:nmax
addpoints(pd.XYZLine(i),u(3*(i-1)+1),u(3*(i-1)+2),u(3*(i-1)+3));
end
% update head position
if nargin>12 && varargin{8}
for i=1:nmax
set(pd.XYZHead(i),'xdata',u(3*(i-1)+1),'ydata',u(3*(i-1)+2),'zdata',u(3*(i-1)+3));
end
end
% Note: the following four callbacks were set by "case 0" above
case 'NameChange' % ---------------------------------------------------
% get the figure associated with this block, if it's valid, change
% the name of the figure
FigHandle=get_param(gcbh,'UserData');
if ishandle(FigHandle)
set(FigHandle,'Name',get_param(gcbh,'Name'));
end
case {'CopyBlock', 'LoadBlock'} % -------------------------------------
% Initialize the block's UserData such that a figure is not associated with the block
set_param(gcbh,'UserData',-1);
case 'DeleteBlock' % --------------------------------------------------
% Get the figure handle associated with the block, if it exists, delete it
FigHandle=get_param(gcbh,'UserData');
if ishandle(FigHandle)
delete(FigHandle);
set_param(gcbh,'UserData',-1);
end
case {3,9} % ----------------------------------------------------------
sys=[];
otherwise % -----------------------------------------------------------
if ischar(flag)
errmsg=sprintf('Unhandled flag: ''%s''', flag);
else
errmsg=sprintf('Unhandled flag: %d', flag);
end
error(errmsg);
end
% end sfun3d