Master Thesis Code
by Simon Moser
Loading...
Searching...
No Matches
trajectoryVisualizationApp.m
Go to the documentation of this file.
1% =========================================================================== %
2%> @brief app that can be used to visualize a Trajectory object
3%>
4%> This app is designed to visualize a Trajectory object either from the
5%> workspace or from the trajectoryGenerationApp. It provides a 3D plot of the
6%> trajectory, a zoomed in plot of the current position and orientation, and
7%> controls to play, pause, and skip through the trajectory.
8%>
9%> The app is designed to be used with the Trajectory object which must have
10%> a minimum of one Waypoint entry. The Trajectory object can be generated
11%> from the trajectoryGenerationApp or manually, like in the @ref trajectoryExample.m
12%> @code
13%> app = trajectoryVisualizationApp(traj);
14%> @endcode
15%>
16%> @copyright see the file @ref LICENSE in the root directory of the repository
17%>
18%> \par Example Usage
19%>
20%> \image html trajectoryVisualizationApp.gif
21% =========================================================================== %
22
23classdef trajectoryVisualizationApp < matlab.apps.AppBase
24
25 % Properties that correspond to app components
26 properties (Access = public)
27 TrajectoryVisualizationUIFigure matlab.ui.Figure
28 gridMain matlab.ui.container.GridLayout
29 gridSettingsZoom matlab.ui.container.GridLayout
30 gridSettings matlab.ui.container.GridLayout
31 gridSettingsCtrl matlab.ui.container.GridLayout
32 ZoomSlider matlab.ui.control.Slider
33 ZoomSliderLabel matlab.ui.control.Label
34 PlaySpeedSlider matlab.ui.control.Slider
35 PlaySpeedSliderLabel matlab.ui.control.Label
36 SettingsLabel matlab.ui.control.Label
37 axTrajZoom matlab.ui.control.UIAxes
38 gridControl matlab.ui.container.GridLayout
39 gridControlBtns matlab.ui.container.GridLayout
40 fldCurrTime matlab.ui.control.EditField
41 btnGoToOut matlab.ui.control.Button
42 gridPlay matlab.ui.container.GridLayout
43 btnPlayPause matlab.ui.control.StateButton
44 btnNextFrame matlab.ui.control.Button
45 btnPrevFrame matlab.ui.control.Button
46 btnGoToIn matlab.ui.control.Button
47 gridTimeSliders matlab.ui.container.GridLayout
48 sliderTime matlab.ui.control.Slider
49 sliderRange matlab.ui.control.RangeSlider
50 gridFooter matlab.ui.container.GridLayout
51 lblMoss matlab.ui.control.Label
52 imgLogo matlab.ui.control.Image
53 axTrajMain matlab.ui.control.UIAxes
54 end
55
57 properties (Access = private)
58 traj % trajectory table of the imported traj object
59 fs % frequency of the trajectory
60 mainPosePatch % posePatch Object of the main Plot
61 zoomPosePatch % posePatch Object of the zoom Plot
62 playing = false % boolean to check if the animation is playing
63 playTimer % timer for the animation
64 pointIn % in point of the trajectory
65 pointOut % out point of the trajectory
66 colors % global colormap
67 colorIdx % mapping from traj idx to color idx
68 end
69
71 % Callbacks that handle component events
72 methods (Access = private)
73
74 % Code that executes after component creation
75 function startupFcn(app, traj)
76 arguments
77 app
78 traj {mustBeA(traj,"Trajectory")} = Trajectory
79 end
81 try
83 % check traj TODO: add possibility to import on startup, if
84 % tray is empty
85 assert(height(traj.getTab) > 0,"There must exist Waypoint Entries in the Trajectory Object.")
86 if ~traj.getIsGenerated
87 traj.generateTrajectory;
88 end
89
90 app.traj = traj.getTrajectory;
91 app.fs = traj.getSamplingFrequency;
93 %% setup the play timer
94 fps = min([app.fs, 30]);
95 app.playTimer = timer("ExecutionMode","fixedRate","Period",round(1/fps,3), "TimerFcn", {@app.playTimerCallback});
96 app.playTimer.UserData = 1;
97
98 %% generate the colormap
99 [~, idx, app.colorIdx] = unique([app.traj.pos,app.traj.ori.normalize.compact], "rows", "stable");
100 pos = app.traj.pos(idx,:);
101 app.colors = turbo(height(pos));
103 %% generate initial Main Plot
104 % pose patch
105 app.mainPosePatch = poseplot(app.axTrajMain,app.traj.ori(1),app.traj.pos(1,:),"NED","MeshFileName","jumpSimplified.stl");
106 app.mainPosePatch.PatchFaceColor = app.colors(1,:);
107 app.mainPosePatch.PatchFaceAlpha = 1;
108 app.mainPosePatch.ScaleFactor = 5;
109
110 % 3d axis
111 app.axTrajMain.XLim = [min(app.traj.pos(:,1)) - 0.5, max(app.traj.pos(:,1)) + 0.5];
112 app.axTrajMain.YLim = [min(app.traj.pos(:,2)) - 0.5, max(app.traj.pos(:,2)) + 0.5];
113 app.axTrajMain.ZLim = [min(app.traj.pos(:,3)) - 0.5, max(app.traj.pos(:,3)) + 0.5];
114 app.axTrajMain.Projection = "perspective";
115 app.axTrajMain.XGrid = "on";
116 app.axTrajMain.YGrid = "on";
117 app.axTrajMain.ZGrid = "on";
118 app.axTrajMain.Title.String = "";
119 app.axTrajMain.Title.Visible = "off";
120 app.axTrajMain.XLabel.String = "x [m]";
121 app.axTrajMain.YLabel.String = "y [m]";
122 app.axTrajMain.ZLabel.String = "z [m]";
123 app.axTrajMain.PlotBoxAspectRatioMode = "manual";
124 app.axTrajMain.PlotBoxAspectRatio = [1,1,1];
125 app.axTrajMain.DataAspectRatioMode = "manual";
126 app.axTrajMain.DataAspectRatio = [1,1,1];
127
128 % full trajectory
129 plotStep = ceil(height(pos)/1000);
130 for i=1:plotStep:height(pos)-plotStep-1
131 hold(app.axTrajMain,"on");
132 plot3(app.axTrajMain,pos([i,i+plotStep],1),pos([i,i+plotStep],2),pos([i,i+plotStep],3),'-','Color',app.colors(i,:),'LineWidth',0.5)
133 end
134
135 % in and out points
136 app.pointIn = plot3(app.axTrajMain,app.traj.pos(1,1),app.traj.pos(1,2),app.traj.pos(1,3),'o','MarkerSize',5,'MarkerFaceColor',app.colors(1,:),'MarkerEdgeColor',[0,0.57,0.82]);
137 app.pointOut = plot3(app.axTrajMain,app.traj.pos(end,1),app.traj.pos(end,2),app.traj.pos(end,3),'o','MarkerSize',5,'MarkerFaceColor',app.colors(end,:),'MarkerEdgeColor',[0.82,0.57,0]);
138 hold(app.axTrajMain,"off");
139
140 %% generate initial Zoom Plot
141 % pose patch
142 app.zoomPosePatch = poseplot(app.axTrajZoom,app.traj.ori(1),app.traj.pos(1,:),"NED","MeshFileName","jumpSimplified.stl");
143 app.zoomPosePatch.PatchFaceColor = app.colors(1,:);
144 app.zoomPosePatch.PatchFaceAlpha = 1;
145 app.zoomPosePatch.ScaleFactor = 2;
146
147 % 3d axis
148 app.axTrajZoom.XLim = [app.traj.pos(1,1) - 0.5, app.traj.pos(1,1) + 0.5];
149 app.axTrajZoom.YLim = [app.traj.pos(1,2) - 0.5, app.traj.pos(1,2) + 0.5];
150 app.axTrajZoom.ZLim = [app.traj.pos(1,3) - 0.5, app.traj.pos(1,3) + 0.5];
151 app.axTrajZoom.Projection = "perspective";
152 app.axTrajZoom.XGrid = "on";
153 app.axTrajZoom.YGrid = "on";
154 app.axTrajZoom.ZGrid = "on";
155 app.axTrajZoom.Title.String = "";
156 app.axTrajZoom.Title.Visible = "off";
157 app.axTrajZoom.XLabel.String = "x [m]";
158 app.axTrajZoom.YLabel.String = "y [m]";
159 app.axTrajZoom.ZLabel.String = "z [m]";
160 app.axTrajZoom.PlotBoxAspectRatioMode = "manual";
161 app.axTrajZoom.PlotBoxAspectRatio = [1,1,1];
162 app.axTrajZoom.DataAspectRatioMode = "manual";
163 app.axTrajZoom.DataAspectRatio = [1,1,1];
164
165 % full trajectory
166 plotStep = ceil(height(pos)/1000);
167 for i=1:plotStep:height(pos)-plotStep-1
168 hold(app.axTrajZoom,"on");
169 plot3(app.axTrajZoom,pos([i,i+plotStep],1),pos([i,i+plotStep],2),pos([i,i+plotStep],3),'-','Color',app.colors(i,:),'LineWidth',2)
170 end
171
172 %% setup controls
173 % set up time indicator
174 app.fldCurrTime.Value = string(app.traj.t(1),"mm:ss.SSS");
175
176 % set up time slider
177 app.sliderTime.Limits = seconds([app.traj.t(1),app.traj.t(end)]);
178 app.sliderTime.Value = seconds(app.traj.t(1));
179 app.sliderTime.ValueChangingFcn = createCallbackFcn(app, @sliderTimeChange, true);
180
181 % set up range slider
182 app.sliderRange.Limits = seconds([app.traj.t(1),app.traj.t(end)]);
183 app.sliderRange.Value = seconds([app.traj.t(1),app.traj.t(end)]);
184 app.sliderRange.ValueChangingFcn = createCallbackFcn(app, @sliderRangeChanging, true);
185
186 % set up play speed
187 app.PlaySpeedSlider.Value = 1;
188
189 % set up zoom
190 app.ZoomSlider.Value = 10;
191 app.ZoomSlider.ValueChangedFcn = createCallbackFcn(app, @zoomSliderChange, false);
192
193 % set up play/pause button
194 app.btnPlayPause.ValueChangedFcn = createCallbackFcn(app, @playPause, true);
195
196 % set up next/prev frame buttons
197 app.btnNextFrame.ButtonPushedFcn = createCallbackFcn(app, @nextFrame, false);
198 app.btnPrevFrame.ButtonPushedFcn = createCallbackFcn(app, @prevFrame, false);
199
200 % set up go to in/out buttons
201 app.btnGoToIn.ButtonPushedFcn = createCallbackFcn(app, @goToIn, false);
202 app.btnGoToOut.ButtonPushedFcn = createCallbackFcn(app, @goToOut, false);
203
204 % set up the current time field
205 app.fldCurrTime.Value = string(app.traj.t(1),"mm:ss.SSS");
206 app.fldCurrTime.ValueChangedFcn = createCallbackFcn(app, @fldCurrTimeChanged, false);
207
208 catch e
209 msg = "There occured an error during start. Please check the following error message:" + newline + newline + e.message;
210
211 e = errordlg(msg,"Startup Failed","modal");
212 uiwait(e);
213
214 app.delete;
215 end
216
217 end
218
219 % Value changed function: sliderTime
220 function sliderTimeChange(app, event)
221 % update the plots
222 % find the closest index to the time
223 [~,idx] = min(abs(app.traj.t - seconds(event.Value)));
224
225 % stop playing
226 app.playPause(play=false);
227
228 % wait for the animation to stop
229 while app.playing
230 pause(0.1);
231 end
232
233 app.updatePlots(idx, updateTimeSlider=true);
234 app.playTimer.UserData = idx;
235 end
236
237 % Value changed function: btnPlayPause
238 function playPause(app,event,options)
239
240 arguments
241 app
242 event (1,1) = NaN
243 options.play (1,1) logical = true
244 end
245
246 if isa(event, 'matlab.ui.eventdata.ValueChangedData')
247 app.playing = event.Value;
248 else
249 app.playing = options.play;
250 end
251
252 if ~app.playing
253 app.playing = false;
254 app.btnPlayPause.Icon = "Play.svg";
255 stop(app.playTimer);
256 else
257 app.playing = true;
258 app.btnPlayPause.Icon = "Pause.svg";
259 app.playTimer.UserData = find(app.traj.t >= seconds(app.sliderTime.Value),1);
260 start(app.playTimer);
261 end
262 end
263
264 % value changed function: zoomSlider
265 function zoomSliderChange(app)
266 idx = app.playTimer.UserData;
267 app.axTrajZoom.XLim = [app.traj.pos(idx,1) - 1/app.ZoomSlider.Value, app.traj.pos(idx,1) + 1/app.ZoomSlider.Value];
268 app.axTrajZoom.YLim = [app.traj.pos(idx,2) - 1/app.ZoomSlider.Value, app.traj.pos(idx,2) + 1/app.ZoomSlider.Value];
269 app.axTrajZoom.ZLim = [app.traj.pos(idx,3) - 1/app.ZoomSlider.Value, app.traj.pos(idx,3) + 1/app.ZoomSlider.Value];
270 end
271
272 % Button pushed function: btnNextFrame
273 function nextFrame(app)
274 % stop playing
275 app.playPause(play=false);
276
277 % wait for the animation to stop
278 while app.playing
279 pause(0.1);
280 end
281
282 % update the plots
283 idx = app.playTimer.UserData + 1;
284 if idx > height(app.traj)
285 idx = height(app.traj);
286 end
287 app.updatePlots(idx);
288 app.playTimer.UserData = idx;
289 end
290
291 % Button pushed function: btnPrevFrame
292 function prevFrame(app)
293 % stop playing
294 app.playPause(play=false);
295
296 % wait for the animation to stop
297 while app.playing
298 pause(0.1);
299 end
300
301 % update the plots
302 idx = app.playTimer.UserData - 1;
303 if idx < 1
304 idx = 1;
305 end
306 app.updatePlots(idx);
307 app.playTimer.UserData = idx;
308 end
309
310 % Button pushed function: btnGoToIn
311 function goToIn(app)
312 % stop playing
313 app.playPause(play=false);
314
315 % wait for the animation to stop
316 while app.playing
317 pause(0.1);
318 end
319
320 % find the closest index to the first value of the range slider
321 [~,idx] = min(abs(app.traj.t - seconds(app.sliderRange.Value(1))));
322 app.updatePlots(idx);
323 app.playTimer.UserData = idx;
324 end
325
326 % Button pushed function: btnGoToOut
327 function goToOut(app)
328 % stop playing
329 app.playPause(play=false);
330
331 % wait for the animation to stop
332 while app.playing
333 pause(0.1);
334 end
335
336 % find the closest index to the second value of the range slider
337 [~,idx] = min(abs(app.traj.t - seconds(app.sliderRange.Value(2))));
338 app.updatePlots(idx);
339 app.playTimer.UserData = idx;
340 end
341
342 % Value changed function: fldCurrTime
343 function fldCurrTimeChanged(app, varargin)
344 % stop playing
345 app.playPause(play=false);
346
347 % wait for the animation to stop
348 while app.playing
349 pause(0.1);
350 end
351
352 % parse the time
353 if contains(app.fldCurrTime.Value,":")
354 time = datetime(app.fldCurrTime.Value,"InputFormat","mm:ss.SSS");
355 else
356 time = seconds(str2double(app.fldCurrTime.Value));
357 end
358
359 % find the closest index to the time
360 [~,idx] = min(abs(app.traj.t - time));
361
362 app.updatePlots(idx, updateTimeSlider=true);
363 app.playTimer.UserData = idx;
364 end
365
366 % Value changing function: sliderRange
367 function sliderRangeChanging(app, event)
368
369 % find idx
370 [~,idx1] = min(abs(app.traj.t - seconds(event.Value(1))));
371 [~,idx2] = min(abs(app.traj.t - seconds(event.Value(2))));
372
373 % update the in point
374 app.pointIn.XData = app.traj.pos(idx1,1);
375 app.pointIn.YData = app.traj.pos(idx1,2);
376 app.pointIn.ZData = app.traj.pos(idx1,3);
377 app.pointIn.MarkerFaceColor = app.colors(app.colorIdx(idx1),:);
378 app.pointIn.MarkerEdgeColor = app.colors(app.colorIdx(idx1),:);
379
380 % update the out point
381 app.pointOut.XData = app.traj.pos(idx2,1);
382 app.pointOut.YData = app.traj.pos(idx2,2);
383 app.pointOut.ZData = app.traj.pos(idx2,3);
384 app.pointOut.MarkerFaceColor = app.colors(app.colorIdx(idx2),:);
385 app.pointOut.MarkerEdgeColor = app.colors(app.colorIdx(idx2),:);
386 end
387
388 end
389
390 % helper functions
391 methods (Access = private)
392 function updatePlots(app, idx, options)
393 arguments
394 app
395 idx (1,1) {mustBeInteger, mustBePositive}
396 options.updateMain (1,1) logical = true
397 options.updateZoom (1,1) logical = true
398 options.updateCurrTime (1,1) logical = true
399 options.updateTimeSlider (1,1) logical = true
400 end
401
402 % update the controls
403 if options.updateCurrTime
404 app.fldCurrTime.Value = string(app.traj.t(idx),"mm:ss.SSS");
405 end
406 if options.updateTimeSlider
407 app.sliderTime.Value = seconds(app.traj.t(idx));
408 end
409
410 % check if position or orientation has changed
411 if options.updateMain || options.updateZoom
412 if any(app.mainPosePatch.Position ~= app.traj.pos(idx,:)) || any(app.zoomPosePatch.Position ~= app.traj.pos(idx,:))
413 newPos = true;
414 else
415 newPos = false;
416 end
417 if any(app.mainPosePatch.Orientation ~= app.traj.ori(idx,:)) || any(app.zoomPosePatch.Orientation ~= app.traj.ori(idx,:))
418 newOri = true;
419 else
420 newOri = false;
421 end
422 end
423
424 % update the main plot if different
425 if options.updateMain
426 if newPos
427 app.mainPosePatch.Position = app.traj.pos(idx,:);
428 app.mainPosePatch.PatchFaceColor = app.colors(app.colorIdx(idx),:);
429 end
430 if newOri
431 app.mainPosePatch.Orientation = app.traj.ori(idx,:);
432 end
433 end
434
435 % update the zoom plot if different
436 if options.updateZoom
437 if newPos
438 app.zoomPosePatch.Position = app.traj.pos(idx,:);
439 app.zoomPosePatch.PatchFaceColor = app.colors(app.colorIdx(idx),:);
440
441 app.axTrajZoom.XLim = [app.traj.pos(idx,1) - 1/app.ZoomSlider.Value, app.traj.pos(idx,1) + 1/app.ZoomSlider.Value];
442 app.axTrajZoom.YLim = [app.traj.pos(idx,2) - 1/app.ZoomSlider.Value, app.traj.pos(idx,2) + 1/app.ZoomSlider.Value];
443 app.axTrajZoom.ZLim = [app.traj.pos(idx,3) - 1/app.ZoomSlider.Value, app.traj.pos(idx,3) + 1/app.ZoomSlider.Value];
444 end
445 if newOri
446 app.zoomPosePatch.Orientation = app.traj.ori(idx,:);
447 end
448 end
449 end
450
451 function playTimerCallback(app, ~, ~)
452 % check if animation et end or before of range slider
453 idx_range_start = find(app.traj.t >= seconds(app.sliderRange.Value(1)),1);
454 idx_range_end = find(app.traj.t >= seconds(app.sliderRange.Value(2)),1);
455 if app.playTimer.UserData > idx_range_end || app.playTimer.UserData < idx_range_start
456 % jump to start of range slider
457 app.playTimer.UserData = idx_range_start;
458 else
459
460 % update the plots
461 app.updatePlots(app.playTimer.UserData);
462
463 % calculate this fps
464 curr_fps = 1/(app.playTimer.InstantPeriod);
465 if isnan(curr_fps)
466 curr_fps = 30;
467 end
468
469 % calculate steps to skip to keep up with the desired frequency
470 skip = ceil(app.PlaySpeedSlider.Value * app.fs/curr_fps);
471
472
473 % update counter
474 app.playTimer.UserData = app.playTimer.UserData + skip;
475 end
476 end
477 end
478
479 % Component initialization
480 methods (Access = private)
481
482 % Create UIFigure and components
483 function createComponents(app)
484
485 % Create TrajectoryVisualizationUIFigure and hide until all components are created
486 app.TrajectoryVisualizationUIFigure = uifigure('Visible', 'off');
487 app.TrajectoryVisualizationUIFigure.Position = [100 100 1024 768];
488 app.TrajectoryVisualizationUIFigure.Name = 'Trajectory Visualization';
489 app.TrajectoryVisualizationUIFigure.Icon = 'logo_zhaw.png';
490 app.TrajectoryVisualizationUIFigure.CloseRequestFcn = createCallbackFcn(app, @delete, false);
491
492 % Create gridMain
493 app.gridMain = uigridlayout(app.TrajectoryVisualizationUIFigure);
494 app.gridMain.ColumnWidth = {'1x'};
495 app.gridMain.RowHeight = {'3x', '2x', 70, 50};
496 app.gridMain.Padding = [25 25 25 25];
497
498 % Create axTrajMain
499 app.axTrajMain = uiaxes(app.gridMain);
500 title(app.axTrajMain, 'Title')
501 xlabel(app.axTrajMain, 'X')
502 ylabel(app.axTrajMain, 'Y')
503 zlabel(app.axTrajMain, 'Z')
504 app.axTrajMain.Layout.Row = 1;
505 app.axTrajMain.Layout.Column = 1;
506
507 % Create gridFooter
508 app.gridFooter = uigridlayout(app.gridMain);
509 app.gridFooter.RowHeight = {'1x'};
510 app.gridFooter.ColumnSpacing = 0;
511 app.gridFooter.RowSpacing = 0;
512 app.gridFooter.Padding = [0 0 0 0];
513 app.gridFooter.Layout.Row = 4;
514 app.gridFooter.Layout.Column = 1;
515
516 % Create imgLogo
517 app.imgLogo = uiimage(app.gridFooter);
518 app.imgLogo.Layout.Row = 1;
519 app.imgLogo.Layout.Column = 1;
520 app.imgLogo.HorizontalAlignment = 'left';
521 app.imgLogo.VerticalAlignment = 'bottom';
522 app.imgLogo.ImageSource = 'logo_isc.png';
523
524 % Create lblMoss
525 app.lblMoss = uilabel(app.gridFooter);
526 app.lblMoss.HorizontalAlignment = 'right';
527 app.lblMoss.VerticalAlignment = 'bottom';
528 app.lblMoss.FontColor = [0.502 0.502 0.502];
529 app.lblMoss.Layout.Row = 1;
530 app.lblMoss.Layout.Column = 2;
531 app.lblMoss.Text = 'moss, February 2024';
532
533 % Create gridControl
534 app.gridControl = uigridlayout(app.gridMain);
535 app.gridControl.ColumnWidth = {300, '2x'};
536 app.gridControl.RowHeight = {'1x'};
537 app.gridControl.Layout.Row = 3;
538 app.gridControl.Layout.Column = 1;
539
540 % Create gridTimeSliders
541 app.gridTimeSliders = uigridlayout(app.gridControl);
542 app.gridTimeSliders.ColumnWidth = {'fit', '1x'};
543 app.gridTimeSliders.ColumnSpacing = 0;
544 app.gridTimeSliders.RowSpacing = 0;
545 app.gridTimeSliders.Padding = [0 0 0 0];
546 app.gridTimeSliders.Layout.Row = 1;
547 app.gridTimeSliders.Layout.Column = 2;
548
549 % Create sliderRange
550 app.sliderRange = uislider(app.gridTimeSliders, 'range');
551 app.sliderRange.MajorTicks = [];
552 app.sliderRange.MajorTickLabels = {''};
553 app.sliderRange.MinorTicks = [];
554 app.sliderRange.Layout.Row = 1;
555 app.sliderRange.Layout.Column = 2;
556
557 % Create sliderTime
558 app.sliderTime = uislider(app.gridTimeSliders);
559 app.sliderTime.MajorTicks = [];
560 app.sliderTime.MajorTickLabels = {''};
561 app.sliderTime.MinorTicks = [];
562 app.sliderTime.Layout.Row = 2;
563 app.sliderTime.Layout.Column = 2;
564
565 % Create gridControlBtns
566 app.gridControlBtns = uigridlayout(app.gridControl);
567 app.gridControlBtns.ColumnWidth = {'1x', '3x', '1x', 'fit', '2x'};
568 app.gridControlBtns.RowHeight = {'1x'};
569 app.gridControlBtns.Padding = [0 10 0 10];
570 app.gridControlBtns.Layout.Row = 1;
571 app.gridControlBtns.Layout.Column = 1;
572
573 % Create btnGoToIn
574 app.btnGoToIn = uibutton(app.gridControlBtns, 'push');
575 app.btnGoToIn.Icon = 'goToIn.svg';
576 app.btnGoToIn.Layout.Row = 1;
577 app.btnGoToIn.Layout.Column = 1;
578 app.btnGoToIn.Text = '';
579
580 % Create gridPlay
581 app.gridPlay = uigridlayout(app.gridControlBtns);
582 app.gridPlay.ColumnWidth = {'1x', '1x', '1x'};
583 app.gridPlay.RowHeight = {'1x'};
584 app.gridPlay.ColumnSpacing = 0;
585 app.gridPlay.RowSpacing = 0;
586 app.gridPlay.Padding = [0 0 0 0];
587 app.gridPlay.Layout.Row = 1;
588 app.gridPlay.Layout.Column = 2;
589
590 % Create btnPrevFrame
591 app.btnPrevFrame = uibutton(app.gridPlay, 'push');
592 app.btnPrevFrame.Icon = 'prevFrame.svg';
593 app.btnPrevFrame.Layout.Row = 1;
594 app.btnPrevFrame.Layout.Column = 1;
595 app.btnPrevFrame.Text = '';
596
597 % Create btnNextFrame
598 app.btnNextFrame = uibutton(app.gridPlay, 'push');
599 app.btnNextFrame.Icon = 'nextFrame.svg';
600 app.btnNextFrame.Layout.Row = 1;
601 app.btnNextFrame.Layout.Column = 3;
602 app.btnNextFrame.Text = '';
603
604 % Create btnPlayPause
605 app.btnPlayPause = uibutton(app.gridPlay, 'state');
606 app.btnPlayPause.Icon = 'Play.svg';
607 app.btnPlayPause.Text = '';
608 app.btnPlayPause.Layout.Row = 1;
609 app.btnPlayPause.Layout.Column = 2;
610
611 % Create btnGoToOut
612 app.btnGoToOut = uibutton(app.gridControlBtns, 'push');
613 app.btnGoToOut.Icon = 'goToOut.svg';
614 app.btnGoToOut.Layout.Row = 1;
615 app.btnGoToOut.Layout.Column = 3;
616 app.btnGoToOut.Text = '';
617
618 % Create fldCurrTime
619 app.fldCurrTime = uieditfield(app.gridControlBtns, 'text');
620 app.fldCurrTime.Layout.Row = 1;
621 app.fldCurrTime.Layout.Column = 5;
622 app.fldCurrTime.Value = '00:00.000';
623 app.fldCurrTime.HorizontalAlignment = 'center';
624
625 % Create gridSettingsZoom
626 app.gridSettingsZoom = uigridlayout(app.gridMain);
627 app.gridSettingsZoom.ColumnWidth = {300, '1x'};
628 app.gridSettingsZoom.RowHeight = {'1x'};
629 app.gridSettingsZoom.Padding = [0 0 0 0];
630 app.gridSettingsZoom.Layout.Row = 2;
631 app.gridSettingsZoom.Layout.Column = 1;
632
633 % Create axTrajZoom
634 app.axTrajZoom = uiaxes(app.gridSettingsZoom);
635 title(app.axTrajZoom, 'Title')
636 xlabel(app.axTrajZoom, 'X')
637 ylabel(app.axTrajZoom, 'Y')
638 zlabel(app.axTrajZoom, 'Z')
639 app.axTrajZoom.Layout.Row = 1;
640 app.axTrajZoom.Layout.Column = 2;
641
642 % Create gridSettings
643 app.gridSettings = uigridlayout(app.gridSettingsZoom);
644 app.gridSettings.ColumnWidth = {'1x'};
645 app.gridSettings.RowHeight = {'fit', '1x'};
646 app.gridSettings.Padding = [0 0 0 0];
647 app.gridSettings.Layout.Row = 1;
648 app.gridSettings.Layout.Column = 1;
649
650 % Create SettingsLabel
651 app.SettingsLabel = uilabel(app.gridSettings);
652 app.SettingsLabel.FontSize = 14;
653 app.SettingsLabel.FontWeight = 'bold';
654 app.SettingsLabel.Layout.Row = 1;
655 app.SettingsLabel.Layout.Column = 1;
656 app.SettingsLabel.Text = 'Settings';
657
658 % Create gridSettingsCtrl
659 app.gridSettingsCtrl = uigridlayout(app.gridSettings);
660 app.gridSettingsCtrl.ColumnWidth = {'fit', '1x'};
661 app.gridSettingsCtrl.RowHeight = {'fit', 'fit', 'fit'};
662 app.gridSettingsCtrl.Padding = [0 0 0 0];
663 app.gridSettingsCtrl.Layout.Row = 2;
664 app.gridSettingsCtrl.Layout.Column = 1;
665
666 % Create PlaySpeedSliderLabel
667 app.PlaySpeedSliderLabel = uilabel(app.gridSettingsCtrl);
668 app.PlaySpeedSliderLabel.HorizontalAlignment = 'right';
669 app.PlaySpeedSliderLabel.Layout.Row = 1;
670 app.PlaySpeedSliderLabel.Layout.Column = 1;
671 app.PlaySpeedSliderLabel.Text = 'Play Speed';
672
673 % Create PlaySpeedSlider
674 app.PlaySpeedSlider = uislider(app.gridSettingsCtrl);
675 app.PlaySpeedSlider.Limits = [0 5];
676 app.PlaySpeedSlider.Layout.Row = 1;
677 app.PlaySpeedSlider.Layout.Column = 2;
678
679 % Create ZoomSliderLabel
680 app.ZoomSliderLabel = uilabel(app.gridSettingsCtrl);
681 app.ZoomSliderLabel.HorizontalAlignment = 'right';
682 app.ZoomSliderLabel.Layout.Row = 2;
683 app.ZoomSliderLabel.Layout.Column = 1;
684 app.ZoomSliderLabel.Text = 'Zoom';
685
686 % Create ZoomSlider
687 app.ZoomSlider = uislider(app.gridSettingsCtrl);
688 app.ZoomSlider.Limits = [2 22];
689 app.ZoomSlider.Layout.Row = 2;
690 app.ZoomSlider.Layout.Column = 2;
691
692 % Show the figure after all components are created
693 app.TrajectoryVisualizationUIFigure.Visible = 'on';
694 end
695 end
696
697 % App creation and deletion
698 methods (Access = public)
699
700 % Construct app
701 function app = trajectoryVisualizationApp(varargin)
702
703 % Create UIFigure and components
704 createComponents(app)
705
706 % Register the app with App Designer
707 registerApp(app, app.TrajectoryVisualizationUIFigure)
708
709 % Execute the startup function
710 runStartupFcn(app, @(app)startupFcn(app, varargin{:}))
711
712 if nargout == 0
713 clear app
714 end
715 end
716
717 % Code that executes before app deletion
718 function delete(app)
719
720 % make sure the timer is stopped
721 try
722 stop(app.playTimer);
723 delete(app.playTimer);
724 catch
725 end
726
727 % Delete UIFigure when app is deleted
728 delete(app.TrajectoryVisualizationUIFigure)
729 end
730 end
731end
Trajectory Class for generating and manipulating trajectories from waypoints.
Definition Trajectory.m:37
function getIsGenerated(in obj)
handle class from MATLAB.
app that helps to generate a trajectory.
app that can be used to visualize a Trajectory object
function trajectoryVisualizationApp(in varargin)
function playTimerCallback(in app, in ignoredArg, in ignoredArg)
function prevFrame(in app)
function nextFrame(in app)
function zoomSliderChange(in app)
function sliderTimeChange(in app, in event)
function goToOut(in app)
function playPause(in app, in event, in options)
function goToIn(in app)
function startupFcn(in app, in traj)
function sliderRangeChanging(in app, in event)
function fldCurrTimeChanged(in app, in varargin)
function updatePlots(in app, in idx, in options)
function createComponents(in app)