Code covered by the BSD License  

Highlights from
choose_transect_limits

image thumbnail
from choose_transect_limits by Kevin Bartlett
GUI for choosing time limits of oceanographic transects

choose_transect_limits(lat,lon,varargin)
function [] = choose_transect_limits(lat,lon,varargin)
%
% choose_transect_limits.m--GUI to choose indices to start and end times of
% oceanographic transects.
%
% Input arguments are latitude, longitude and (optionally) Matlab-format
% time.
%
% Output saved to user-chosen .mat file.
%
% Program uses "dial" GUI controls. If using pre-2008 Matlab version, or if
% dial controls use too much system overhead for your computer to handle,
% set the DIAL constant in the code to 0, and pushbutton controls will be
% used instead of dials.
%
% Syntax: choose_transect_limits(lat,lon,<time>)
%
% e.g.,   load('ctl_demodata.mat');
%         choose_transect_limits(lat,lon,time)

% Developed in Matlab 7.6.0.324 (R2008a) on GLNX86.
% Kevin Bartlett (kpb@uvic.ca), 2008-06-16 16:45
%-------------------------------------------------------------------------

% Set the DIAL constant to 1 to use dial GUI controls or zero to use more
% conventional pushbuttons (dial controls won't work on pre-R2008a versions
% of Matlab, and they may use too much overhead for some computers to
% handle). 
DIAL = 1;

wrongVersion = (DIAL == 1) && ...
    (datenum(version('-date')) < datenum('February 10, 2008'));
    
if wrongVersion
    error('Using pre-R2008a Matlab release; must set DIAL to 0');
end % if

% Handle input arguments.
if nargin ==2   
    time = [1:length(lat)];
    isMtime = false;
elseif nargin == 3
    time = varargin{1};
    isMtime = true;
else
    error([mfilename '.m--Incorrect number of input arguments.']);
end % if

if length(time)~=length(lat) || length(lon) ~= length(lat)
    error([mfilename '.m--Latitude, longitude and time vectors must all be of same length.']);
end % if

% Create GUI figure.
GuiScale = 1;

DeltaFontSize = 0;
ScreenPixelsPerInch = get(0,'ScreenPixelsPerInch');
    
if ScreenPixelsPerInch > 80
    DeltaFontSize = -1;
elseif ScreenPixelsPerInch > 100
    DeltaFontSize = -2;
elseif ScreenPixelsPerInch > 110
    DeltaFontSize = -3;
end % if

FigurePosition = NaN;
objHndls = ctl_makeguiobjects(GuiScale,DeltaFontSize,FigurePosition);
ctlFig = findobj(objHndls,'Tag','ctlFig');

% Keep track of whether dial controls are being used.
setappdata(ctlFig,'doUseDial',DIAL);

% Keep track of whether Matlab-format time is being used.
setappdata(ctlFig,'isMtime',isMtime);

% Customise figure depending on whether dials are being used or not.
headDialPlaceHolder = findobj(ctlFig,'Tag','headDialPlaceHolder');
tailDialPlaceHolder = findobj(ctlFig,'Tag','tailDialPlaceHolder');

if DIAL == 1

    delete(findobj(ctlFig,'Tag','headForwardButton'));
    delete(findobj(ctlFig,'Tag','tailForwardButton'));
    delete(findobj(ctlFig,'Tag','headBackButton'));
    delete(findobj(ctlFig,'Tag','tailBackButton'));
    delete(findobj(ctlFig,'Tag','headLabelText'));
    delete(findobj(ctlFig,'Tag','tailLabelText'));

    set(headDialPlaceHolder,'units','norm');
    headDialPos = get(headDialPlaceHolder,'Position');

    set(tailDialPlaceHolder,'units','norm');
    tailDialPos = get(tailDialPlaceHolder,'Position');

    % Number of points traversed in a single rotation of the dials. Should
    % agree with initial setting of powerPopUp pop-up menu.
    pointsPerRot = 10;
    dialRadius = 0.9;

    headDial = dial('Position',headDialPos,...
        'drawTicks',false,...
        'pointerStyle','circle',...
        'Min',1,...
        'Max',length(lon),...
        'Value',1,...
        'refVal',1,...
        'refOrientation',90*pi/180, ...
        'valRangePerRotation',pointsPerRot,...
        'titleStr','',...
        'titlePos','top',...
        'dialRadius',dialRadius,...
        'VerticalAlignment','bottom',...
        'Tag','headDial');

    tailDial = dial('Position',tailDialPos,...
        'drawTicks',false,...
        'pointerStyle','circle',...
        'Min',1,...
        'Max',length(lon),...
        'Value',1,...
        'refVal',1,...
        'refOrientation',90*pi/180, ...
        'valRangePerRotation',pointsPerRot,...
        'titleStr','',...
        'titlePos','top',...
        'dialRadius',dialRadius,...
        'VerticalAlignment','bottom',...
        'Tag','tailDial');

    set(headDial.titleHndl,'position',[0 1.1 0]);
    set(tailDial.titleHndl,'position',[0 1.1 0]);

else
    headForwardButton =  findobj(ctlFig,'Tag','headForwardButton');
    setappdata(headForwardButton,'max',length(lon));
end % if

delete(headDialPlaceHolder);
delete(tailDialPlaceHolder);

% Popup menu controls the "power" or sensitivity of the dial or pushbutton
% controls.
popUpPowers = [1 2 3 4 5 10 25 50 100 250 500 750 1000 5000 10000 50000 100000 500000 1000000];

if DIAL == 1
    popUpPowers(1:5) = [];
end % if

% ...Exclude power values that exceed the length of the data...actually
% allow one value to be greater than the data length.
findIndex = find(popUpPowers >= length(lon),1,'first');

if ~isempty(findIndex)
    popUpPowers = popUpPowers(1:findIndex);
end % if

popUpPowerStrs = {};

for iPower = 1:length(popUpPowers)
    popUpPowerStrs{iPower} = num2str(popUpPowers(iPower));
end % for

set(findobj(ctlFig,'Tag','powerPopUp'),'string',popUpPowerStrs);

% Set up map axes.
axes(findobj(ctlFig,'Tag','mapAxes'));
fullTrackLine = line(lon,lat,'color',[.6 .6 .6],'Tag','fullTrackLine',...
    'lineWidth',.5);

latlonlims;

% Set zooming on.
zoomHndl = zoom(ctlFig);
set(zoomHndl,'Enable','on');

% ...After zooming, change aspect ratio so that equal distances are shown
% in x and y directions.
set(zoomHndl,'ActionPostCallback',@latlonlims);
            
% Make line showing current selection.
SELECTCOLOUR = [1 0 0];
selectLine = line(lon(1),lat(1),'color',SELECTCOLOUR,'Tag','selectLine','lineWidth',3);

% Make single-point line with large marker to show "head" of selected line.
headLine = line(lon(1),lat(1),'color',SELECTCOLOUR,'marker','o',...
    'markerSize',9,'lineWidth',3,'Tag','headLine');

% Make single-point line with smaller marker to show "tail" of selected
% line. 
tailLine = line(lon(1),lat(1),'color',SELECTCOLOUR,'marker','x',...
    'markerSize',6,'lineWidth',3,'Tag','tailLine');

box on;

% Set up lat and lon time-series plots.
axes(findobj(ctlFig,'Tag','latAx'));
fullLatLine = line(time,lat,'color',[.6 .6 .6],'Tag','fullLatLine',...
    'lineWidth',.5);
axis('tight');
selectLatLine = line(time(1),lat(1),'color',SELECTCOLOUR,'Tag','selectLatLine','lineWidth',3);
headLatLine = line(time(1),lat(1),'color',SELECTCOLOUR,'marker','o',...
    'markerSize',9,'lineWidth',3,'Tag','headLatLine');
tailLatLine = line(time(1),lat(1),'color',SELECTCOLOUR,'marker','x',...
    'markerSize',6,'lineWidth',3,'Tag','tailLatLine');
box on;

if isMtime
    kdatetick;
end % if    
    
xlabel('');
set(gca,'xticklabel',[]);
ylabel('lat');

axes(findobj(ctlFig,'Tag','lonAx'));
fullLonLine = line(time,lon,'color',[.6 .6 .6],'Tag','fullLonLine',...
    'lineWidth',.5);
axis('tight');
selectLonLine = line(time(1),lon(1),'color',SELECTCOLOUR,'Tag','selectLonLine','lineWidth',3);
headLonLine = line(time(1),lon(1),'color',SELECTCOLOUR,'marker','o',...
    'markerSize',9,'lineWidth',3,'Tag','headLonLine');
tailLonLine = line(time(1),lon(1),'color',SELECTCOLOUR,'marker','x',...
    'markerSize',6,'lineWidth',3,'Tag','tailLonLine');
box on;

if isMtime
    kdatetick;
end % if    
    
ylabel('lon');

% Set callbacks.
if DIAL == 1
    set(headDial,'callback',@head_dial_cb);
    set(tailDial,'callback',@tail_dial_cb);
else
    set(findobj(ctlFig,'Tag','headForwardButton'),'callback',@head_forward_cb);
    set(findobj(ctlFig,'Tag','tailForwardButton'),'callback',@tail_forward_cb);
    set(findobj(ctlFig,'Tag','headBackButton'),'callback',@head_back_cb);
    set(findobj(ctlFig,'Tag','tailBackButton'),'callback',@tail_back_cb);
end % if

set(findobj(ctlFig,'Tag','powerPopUp'),'callback',@power_pop_cb);
set(findobj(ctlFig,'Tag','prevTransectButton'),'callback',@prev_transect_cb);
set(findobj(ctlFig,'Tag','nextTransectButton'),'callback',@next_transect_cb);
set(findobj(ctlFig,'Tag','insertButton'),'callback',@insert_transect_cb);
set(findobj(ctlFig,'Tag','deleteButton'),'callback',@delete_transect_cb);
set(findobj(ctlFig,'Tag','commentEdit'),'callback',@comment_edit_cb);
set(findobj(ctlFig,'Tag','quitMenu'),'callback',@quit_cb);
set(findobj(ctlFig,'Tag','saveMenu'),'callback',@save_cb);
set(findobj(ctlFig,'Tag','loadMenu'),'callback',@load_cb);

% Set up transect data.
setappdata(ctlFig,'transectPtr',1);
transects(1).numbers = 1;
transects(1).startIndex = 1;
transects(1).endIndex = 1;
transects(1).comments = '';
setappdata(ctlFig,'transects',transects);
setappdata(ctlFig,'changedSinceLastSave',false);

% Initialise display for first transect.
update_for_transect(ctlFig);

%-------------------------------------------------------------------------
function [] = set_current_selection(figNum)
%
% set_current_selection.m--Sets the start and end index pointed to by the
% selection controls. Works with either dial or pushbutton controls.
%
% Syntax: set_current_selection(figNum)

% Developed in Matlab 7.6.0.324 (R2008a) on GLNX86.
% Kevin Bartlett (kpb@uvic.ca), 2008-06-04 10:45
%-------------------------------------------------------------------------

transects = getappdata(figNum,'transects');
transectPtr = getappdata(figNum,'transectPtr');
doUseDial = getappdata(figNum,'doUseDial');
tailIndex = transects(transectPtr).startIndex;
headIndex = transects(transectPtr).endIndex;

if doUseDial == true
    
    tailDial = dial.find_dial(figNum,'tailDial');
    tailDial = tailDial{1};
    
    % Setting the dial reference value and orientation prevents the dial
    % moving when the value is set.
    thisOrientation = get(tailDial,'orientation');
    set(tailDial,'refOrientation',thisOrientation,...
        'refVal',tailIndex,...
        'Value',tailIndex);

    headDial = dial.find_dial(figNum,'headDial');
    headDial = headDial{1};
    thisOrientation = get(headDial,'orientation');
    set(headDial,'refOrientation',thisOrientation,...
        'refVal',headIndex,...
        'Value',headIndex);
    
else
    tailForwardButton = findobj(figNum,'Tag','tailForwardButton');
    setappdata(tailForwardButton,'buttonVal',tailIndex);

    headForwardButton = findobj(figNum,'Tag','headForwardButton');
    setappdata(headForwardButton,'buttonVal',headIndex);

end % if

%-------------------------------------------------------------------------
function [startIndex,endIndex] = get_current_selection(figNum)
%
% get_current_selection.m--Gets the start and end index of the
% currently-selected lat/lon data. Works with either dial or pushbutton
% controls.
%
% Syntax: [startIndex,endIndex] = get_current_selection(figNum)

% Developed in Matlab 7.6.0.324 (R2008a) on GLNX86.
% Kevin Bartlett (kpb@uvic.ca), 2008-06-04 10:45
%-------------------------------------------------------------------------

doUseDial = getappdata(figNum,'doUseDial');

if doUseDial == true
    
    tailDial = dial.find_dial(figNum,'tailDial');
    tailDial = tailDial{1};
    startIndex = round(get(tailDial,'Value'));

    headDial = dial.find_dial(figNum,'headDial');
    headDial = headDial{1};
    endIndex = round(get(headDial,'Value'));
    
else
    tailForwardButton = findobj(figNum,'Tag','tailForwardButton');
    startIndex = getappdata(tailForwardButton,'buttonVal');

    headForwardButton = findobj(figNum,'Tag','headForwardButton');
    endIndex = getappdata(headForwardButton,'buttonVal');

end % if

%-------------------------------------------------------------------------
function [] = tail_back_cb(src,eventdata)
%
% tail_back_cb.m--Callback for the "Tail back" button.
%-------------------------------------------------------------------------

buttonPower = str2num(get_popup_value(findobj(gcbf,'Tag','powerPopUp')));
tailForwardButton =  findobj(gcbf,'Tag','tailForwardButton');
tailVal = getappdata(tailForwardButton,'buttonVal');
tailVal = tailVal - buttonPower;

if tailVal < 1
    tailVal = 1;
end % if

setappdata(tailForwardButton,'buttonVal',tailVal);

% Change selection based on dial settings.
setappdata(gcbf,'changedSinceLastSave',true);
update_for_selection(gcbf);

%-------------------------------------------------------------------------
function [] = tail_forward_cb(src,eventdata)
%
% tail_forward_cb.m--Callback for the "Tail forward" button.
%-------------------------------------------------------------------------

buttonPower = str2num(get_popup_value(findobj(gcbf,'Tag','powerPopUp')));
tailForwardButton =  findobj(gcbf,'Tag','tailForwardButton');
tailVal = getappdata(tailForwardButton,'buttonVal');
tailVal = tailVal + buttonPower;

% Don't allow tail to move past head.
headForwardButton =  findobj(gcbf,'Tag','headForwardButton');
headVal = getappdata(headForwardButton,'buttonVal');

if tailVal > headVal
    tailVal = headVal;
end % if

setappdata(tailForwardButton,'buttonVal',tailVal);

% Change selection based on dial settings.
setappdata(gcbf,'changedSinceLastSave',true);
update_for_selection(gcbf);

%-------------------------------------------------------------------------
function [] = head_back_cb(src,eventdata)
%
% head_back_cb.m--Callback for the "Head back" button.
%-------------------------------------------------------------------------

buttonPower = str2num(get_popup_value(findobj(gcbf,'Tag','powerPopUp')));
headForwardButton =  findobj(gcbf,'Tag','headForwardButton');
headVal = getappdata(headForwardButton,'buttonVal') - buttonPower;

if headVal < 1
    headVal = 1;
end % if

% Don't allow head to move before tail.
tailForwardButton =  findobj(gcbf,'Tag','tailForwardButton');
tailVal = getappdata(tailForwardButton,'buttonVal');

if headVal < tailVal
    headVal = tailVal;
end % if

setappdata(headForwardButton,'buttonVal',headVal);

% Change selection based on dial settings.
setappdata(gcbf,'changedSinceLastSave',true);
update_for_selection(gcbf);

%-------------------------------------------------------------------------
function [] = head_forward_cb(src,eventdata)
%
% head_forward_cb.m--Callback for the "Head forward" button.
%-------------------------------------------------------------------------

buttonPower = str2num(get_popup_value(findobj(gcbf,'Tag','powerPopUp')));
headForwardButton =  findobj(gcbf,'Tag','headForwardButton');
headVal = getappdata(headForwardButton,'buttonVal') + buttonPower;
dataLength = getappdata(headForwardButton,'max');

if headVal > dataLength
    headVal = dataLength;
end % if

setappdata(headForwardButton,'buttonVal',headVal);

% Change selection based on dial settings.
setappdata(gcbf,'changedSinceLastSave',true);
update_for_selection(gcbf);

%-------------------------------------------------------------------------
function [] = quit_cb(src,eventdata)
%
% quit_cb.m--Callback for the "Quit" menu item.
%-------------------------------------------------------------------------

changedSinceLastSave = getappdata(gcbf,'changedSinceLastSave');

if changedSinceLastSave
    
    r = questdlg('Unsaved changes exist. Really quit?',...
        'choose_transect_limits','Yes','No','No');
    
    if ~strcmp(r,'Yes')
        return;
    end % if
    
end % if

close(gcbf);

%-------------------------------------------------------------------------
function [] = save_cb(src,eventdata)
%
% save_cb.m--Callback for the "Save" menu item.
%-------------------------------------------------------------------------

ctlFig = gcbf;
transects = getappdata(ctlFig,'transects');

% Include the current transect's selection data in the save.
transectPtr = getappdata(ctlFig,'transectPtr');
transects = getappdata(ctlFig,'transects');

% ...Get the control settings.
[thisStartIndex,thisEndIndex] = get_current_selection(ctlFig);

% ...Put control settings into "transects" data structure.
existingIndices = [transects(transectPtr).startIndex ...
    transects(transectPtr).endIndex];

if ~isequal(existingIndices,[thisStartIndex thisEndIndex])
    transects(transectPtr).startIndex = thisStartIndex;
    transects(transectPtr).endIndex = thisEndIndex;
    setappdata(ctlFig,'transects',transects);
    setappdata(ctlFig,'changedSinceLastSave',true);
end % if

% Sort the transects according to their start times (if user has inserted
% transects out of sequence, this will make order more rational).
[unsortedStartIndices{1:length(transects)}] = deal(transects.startIndex);
unsortedStartIndices = cell2mat(unsortedStartIndices);
[dummy,sortIndex] = sort(unsortedStartIndices);
transects = transects(sortIndex);

% Don't save transect numbers. These are prone to change, and it is
% misleading to assign any sort of permanent numbering system to them.
transects = rmfield(transects,'numbers');

[filename, pathname] = uiputfile('transects.mat', 'Save transects as');

if isequal(filename,0) || isequal(pathname,0)
    return;
else
    fullName = fullfile(pathname, filename);

    if exist(fullName,'file')

        r = questdlg('Specified file already exists. Overwrite?',...
            'choose_transect_limits','Yes','No','No');

        if ~strcmp(r,'Yes')
            return;
        end % if

    end % if
    
    save(fullName,'transects');
    setappdata(gcbf,'changedSinceLastSave',false);

end % if

%-------------------------------------------------------------------------
function [] = load_cb(src,eventdata)
%
% load_cb.m--Callback for the "Load" menu item.
%-------------------------------------------------------------------------

ctlFig = gcbf;
transects = getappdata(ctlFig,'transects');

isEmptyData = length(transects) == 1;
isEmptyData = isEmptyData && transects.startIndex == 1;
isEmptyData = isEmptyData && transects.endIndex == 1;
isEmptyData = isEmptyData && isempty(transects.comments);

if ~isEmptyData

    r = questdlg('Loading transect information will delete existing transects. Continue?',...
        'choose_transect_limits','Yes','No','No');

    if ~strcmp(r,'Yes')
        return;
    end % if
    
end % if

[filename, pathname, filterIndex] = uigetfile('*.mat', 'Pick a .mat file');

if filterIndex == 0
    return;
end % if

fullName = fullfile(pathname, filename);

varNames = who('-file',fullName);

if ~ismember('transects',varNames)
    errordlg('Specified .mat file does not contain ''transects'' variable.','choose_transect_limits');
    return;
end % if

loadData = load(fullName);
transects = loadData.transects;

if ~all(ismember({'startIndex' 'endIndex' 'comments'},fieldnames(transects)))    
    errordlg('''transects'' variable does not contain required fields.','choose_transect_limits');
    return;
end % if

% Sort the transects according to their start times (if user has inserted
% transects out of sequence, this will make order more rational).
[unsortedStartIndices{1:length(transects)}] = deal(transects.startIndex);
unsortedStartIndices = cell2mat(unsortedStartIndices);
[dummy,sortIndex] = sort(unsortedStartIndices);
transects = transects(sortIndex);

% Add 'numbers' field. Fields of transect structured variable must be in
% right order, so make new variable from scratch.
newTransects = [];

for iTransect = 1:length(transects)
    newTransects(iTransect).numbers = iTransect;
    newTransects(iTransect).startIndex = transects(iTransect).startIndex;
    newTransects(iTransect).endIndex = transects(iTransect).endIndex;
    newTransects(iTransect).comments = transects(iTransect).comments;    
end % for

transects = newTransects;

setappdata(ctlFig,'transects',transects);
setappdata(ctlFig,'transectPtr',1);
setappdata(ctlFig,'changedSinceLastSave',false);
update_for_transect(ctlFig);

%-------------------------------------------------------------------------
function [] = comment_edit_cb(src,eventdata)
%
% comment_edit_cb.m--Callback for the "comment" edit box.
%-------------------------------------------------------------------------

ctlFig = gcbf;
transectPtr = getappdata(ctlFig,'transectPtr');
transects = getappdata(ctlFig,'transects');
transects(transectPtr).comments = get(src,'string');
setappdata(ctlFig,'transects',transects);
setappdata(ctlFig,'changedSinceLastSave',true);

%-------------------------------------------------------------------------
function [] = prev_transect_cb(src,eventdata)
%
% prev_transect_cb.m--Callback for the "previous transect" control.
%-------------------------------------------------------------------------

ctlFig = gcbf;
transectPtr = getappdata(ctlFig,'transectPtr');

if transectPtr > 1

    % Save the current transect's selection data before moving on to the
    % previous one. 
    transects = getappdata(ctlFig,'transects');

    % ...Get the control settings.
    [thisStartIndex,thisEndIndex] = get_current_selection(ctlFig);

    % ...Put control settings into "transects" data structure.
    existingIndices = [transects(transectPtr).startIndex ...
        transects(transectPtr).endIndex];

    if ~isequal(existingIndices,[thisStartIndex thisEndIndex])
        transects(transectPtr).startIndex = thisStartIndex;
        transects(transectPtr).endIndex = thisEndIndex;

        % Save the modified version of transects.
        setappdata(ctlFig,'transects',transects);
        setappdata(ctlFig,'changedSinceLastSave',true);
    end % if
    
    % Now move to previous transect.
    transectPtr = transectPtr - 1;
    setappdata(gcbf,'transectPtr',transectPtr);
    
    % Set the selection controls to the new values.
    set_current_selection(ctlFig);
    update_for_transect(ctlFig);

end % if

%-------------------------------------------------------------------------
function [] = next_transect_cb(src,eventdata)
%
% next_transect_cb.m--Callback for the "next transect" control.

% Developed in Matlab 7.6.0.324 (R2008a) on GLNX86.
% Kevin Bartlett (kpb@uvic.ca), 2008-06-04 10:45
%-------------------------------------------------------------------------

ctlFig = gcbf;
transectPtr = getappdata(ctlFig,'transectPtr');

% Save the current transect's selection data before moving on to the next.
transects = getappdata(ctlFig,'transects');

% ...Get the control settings.
[thisStartIndex,thisEndIndex] = get_current_selection(ctlFig);

% ...Put control settings into "transects" data structure.
existingIndices = [transects(transectPtr).startIndex ...
    transects(transectPtr).endIndex];

if ~isequal(existingIndices,[thisStartIndex thisEndIndex])
    transects(transectPtr).startIndex = thisStartIndex;
    transects(transectPtr).endIndex = thisEndIndex;

    % Save the modified version of transects.
    setappdata(ctlFig,'transects',transects);
    setappdata(ctlFig,'changedSinceLastSave',true);
end % if

% Now move to next transect.
transectPtr = transectPtr + 1;    
setappdata(ctlFig,'transectPtr',transectPtr);

% If moving beyond last transect, create new one.
if transectPtr > length(transects)    
    insert_transect(ctlFig);
end % if

% Set the selection controls to the new values.
set_current_selection(ctlFig);

% Update display to show new transect.
update_for_transect(ctlFig);

%-------------------------------------------------------------------------
function [] = insert_transect(figNum)
%
% insert_transect.m--Inserts a new transect at the current transect pointer
% position. 
%
% Syntax: insert_transect(figNum)
%-------------------------------------------------------------------------

transectPtr = getappdata(figNum,'transectPtr');
transects = getappdata(figNum,'transects');

% Create new transect for insertion.
if transectPtr == 1
    newNum = 1;
    newStartIndex = 1;
    newEndIndex = 1;
else
    newNum = transectPtr;
    
    % Want selection controls both to point to start of new transect (i.e.,
    % to END of previous transect).
    newStartIndex = transects(transectPtr-1).endIndex;
    newEndIndex = transects(transectPtr-1).endIndex;
end % if

insertTransect(1).numbers = newNum;
insertTransect(1).startIndex = newStartIndex;
insertTransect(1).endIndex = newEndIndex;
insertTransect(1).comments = '';

if transectPtr > length(transects)
    % If new transect at end of data, can just append.
    transects(transectPtr) = insertTransect;
else
    % Otherwise, need to insert new transect in middle of data.
    newTransects = [transects(1:transectPtr-1) insertTransect];
    
    % Existing transects following the new one must be renumbered.
    for iTransect = (transectPtr):length(transects),        
        transects(iTransect).numbers = transects(iTransect).numbers + 1;
    end % for
    
    newTransects = [newTransects transects((transectPtr):end)];
    transects = newTransects;
    
end % if

setappdata(figNum,'transects',transects);
setappdata(figNum,'changedSinceLastSave',true);
update_for_transect(figNum);

%-------------------------------------------------------------------------
function [] = delete_transect(figNum)
%
% delete_transect.m--Deletes the current transect.
%
% Syntax: delete_transect(figNum)
%-------------------------------------------------------------------------

transectPtr = getappdata(figNum,'transectPtr');
transects = getappdata(figNum,'transects');

% Delete the current transect, but only if that will not drop us back to
% zero transects.
if length(transects) > 1
    transects(transectPtr) = [];

    numTransects = length(transects);
    
    % If deleted transect was the last transect, transect pointer will now
    % be pointing at a non-existent transect. Fix it:
    if transectPtr > numTransects
        transectPtr = numTransects;
        setappdata(figNum,'transectPtr',transectPtr);
    end % if
    
    % Renumber the remaining transects.
    for iTransect = 1:numTransects
        transects(iTransect).numbers = iTransect;
    end % for

    setappdata(figNum,'transects',transects);
    setappdata(figNum,'changedSinceLastSave',true);
end % if

update_for_transect(figNum);

%-------------------------------------------------------------------------
function [] = insert_transect_cb(src,eventdata)
%
% insert_transect_cb.m--Callback for "Insert" button.
%-------------------------------------------------------------------------

insert_transect(gcbf);

%-------------------------------------------------------------------------
function [] = delete_transect_cb(src,eventdata)
%
% delete_transect_cb.m--Callback for "Delete" button.
%-------------------------------------------------------------------------

delete_transect(gcbf);

%-------------------------------------------------------------------------
function [] = update_for_transect(figNum)
%
% update_for_transect.m--Updates display for current transect.
%
% Syntax: update_for_transect(figNum)
%-------------------------------------------------------------------------

transectPtr = getappdata(figNum,'transectPtr');
transects = getappdata(figNum,'transects');

set(findobj(figNum,'Tag','commentEdit'),'string',transects(transectPtr).comments);

fullLonLine = findobj(figNum,'Tag','fullLonLine');
time = get(fullLonLine,'xdata');
thisTransectNumber = transects(transectPtr).numbers;

transectNumText = findobj(figNum,'Tag','transectNumText');
transectNumStr = sprintf('Transect %d/%d',thisTransectNumber,length(transects));
set(transectNumText,'string',transectNumStr);

% Set the selection controls to point to the correct indices for this
% transect.
set_current_selection(figNum);

% Update display for (possibly) newly changed selection.
update_for_selection(figNum);

%-------------------------------------------------------------------------
function [] = power_pop_cb(src,eventdata)
%
% power_pop_cb.m--Callback for the "power" pop-up control.

% Developed in Matlab 7.6.0.324 (R2008a) on GLNX86.
% Kevin Bartlett (kpb@uvic.ca), 2008-06-04 10:45
%-------------------------------------------------------------------------

% Callback only needs to do anything if dial controls are being used
% instead of pushbuttons.
doUseDial = getappdata(gcbf,'doUseDial');

if doUseDial == false;
    return;
end % if
    
headDial = dial.find_dial(gcbf,'headDial');
headDial = headDial{1};
headIndex = round(get(headDial,'Value'));

tailDial = dial.find_dial(gcbf,'tailDial');
tailDial = tailDial{1};
tailIndex = round(get(tailDial,'Value'));

popUpPowerStrs = get(gcbo,'String');
popUpPower = str2num(popUpPowerStrs{get(gcbo,'Value')});

% Setting the valRangePerRotation property (the "power") of the dial will
% cause the dial to change its orientation unless the dial reference value
% and reference orientation are reset at the same time. Use the current
% dial value and orientation as the new reference value and reference
% orientation.

% ...First determine the current dial orientations.
tail_dialValue = get(tailDial,'Value');
tailOrientation = get(tailDial,'orientation');

head_dialValue = get(headDial,'Value');
headOrientation = get(headDial,'orientation');

% ...Now reset the dial to use its current orientation and value as its
% reference orientation and reference value, respectively. This will
% prevent the dial from moving when its valRangePerRotation property is
% modified at the same time.
set(tailDial,'valRangePerRotation',popUpPower,'refVal',tail_dialValue,'refOrientation',tailOrientation);
set(headDial,'valRangePerRotation',popUpPower,'refVal',head_dialValue,'refOrientation',headOrientation);

%-------------------------------------------------------------------------
function [] = tail_dial_cb(src,eventdata)
%
% tail_dial_cb.m--Callback for "tail" dial.
%
% Syntax: tail_dial_cb

% Developed in Matlab 7.6.0.324 (R2008a) on GLNX86.
% Kevin Bartlett (kpb@uvic.ca), 2008-06-04 10:45
%-------------------------------------------------------------------------

tailDial = dial.find_dial(gcbf,'tailDial');
tailDial = tailDial{1};
tailVal = round(get(tailDial,'Value'));

headDial = dial.find_dial(gcbf,'headDial');
headDial = headDial{1};
headVal = round(get(headDial,'Value'));

% Don't allow tail to overtake head.
if tailVal > headVal
    tailVal = headVal;
    set(tailDial,'Value',tailVal);
end % if

% Change selection based on dial settings.
setappdata(gcbf,'changedSinceLastSave',true);
update_for_selection(gcbf);

%-------------------------------------------------------------------------
function [] = head_dial_cb(src,eventdata)
%
% head_dial_cb.m--Callback for "head" dial.
%
% Syntax: head_dial_cb

% Developed in Matlab 7.6.0.324 (R2008a) on GLNX86.
% Kevin Bartlett (kpb@uvic.ca), 2008-06-04 10:45
%-------------------------------------------------------------------------

tailDial = dial.find_dial(gcbf,'tailDial');
tailDial = tailDial{1};
tailVal = round(get(tailDial,'Value'));

headDial = dial.find_dial(gcbf,'headDial');
headDial = headDial{1};
headVal = round(get(headDial,'Value'));

% Don't allow head to move before tail.
if headVal < tailVal
    headVal = tailVal;
    set(headDial,'Value',headVal);
end % if

% Change selection based on dial settings.
setappdata(gcbf,'changedSinceLastSave',true);
update_for_selection(gcbf);

%-------------------------------------------------------------------------
function [] = update_for_selection(figNum)
%
% update_for_selection.m--Updates display for new start index and/or end index.
%
% Syntax: update_for_selection(figNum)

% Developed in Matlab 7.6.0.324 (R2008a) on GLNX86.
% Kevin Bartlett (kpb@uvic.ca), 2008-06-04 10:45
%-------------------------------------------------------------------------

[tailIndex,headIndex] = get_current_selection(figNum);

fullTrackLine = findobj(figNum,'Tag','fullTrackLine');
lon = get(fullTrackLine,'xdata');
lat = get(fullTrackLine,'ydata');

tailPointsText = findobj(figNum,'Tag','tailPointsText');
%set(tailPointsText,'string',sprintf('Point %d/%d',tailIndex,length(lon)));
set(tailPointsText,'string',sprintf('Tail: point %d/%d',tailIndex,length(lon)));

headPointsText = findobj(figNum,'Tag','headPointsText');
%set(headPointsText,'string',sprintf('Point %d/%d',headIndex,length(lon)));
set(headPointsText,'string',sprintf('Head: point %d/%d',headIndex,length(lon)));

selectLine = findobj(figNum,'Tag','selectLine');
set(selectLine,'xdata',lon(tailIndex:headIndex),'ydata',lat(tailIndex:headIndex));

headLine = findobj(figNum,'Tag','headLine');
set(headLine,'xdata',lon(headIndex),'ydata',lat(headIndex));

tailLine = findobj(figNum,'Tag','tailLine');
set(tailLine,'xdata',lon(tailIndex),'ydata',lat(tailIndex));

fullLonLine = findobj(figNum,'Tag','fullLonLine');
time = get(fullLonLine,'xdata');

selectLonLine = findobj(figNum,'Tag','selectLonLine');
set(selectLonLine,'xdata',time(tailIndex:headIndex),'ydata',lon(tailIndex:headIndex));

headLonLine = findobj(figNum,'Tag','headLonLine');
set(headLonLine,'xdata',time(headIndex),'ydata',lon(headIndex));

tailLonLine = findobj(figNum,'Tag','tailLonLine');
set(tailLonLine,'xdata',time(tailIndex),'ydata',lon(tailIndex));

selectLatLine = findobj(figNum,'Tag','selectLatLine');
set(selectLatLine,'xdata',time(tailIndex:headIndex),'ydata',lat(tailIndex:headIndex));

headLatLine = findobj(figNum,'Tag','headLatLine');
set(headLatLine,'xdata',time(headIndex),'ydata',lat(headIndex));

tailLatLine = findobj(figNum,'Tag','tailLatLine');
set(tailLatLine,'xdata',time(tailIndex),'ydata',lat(tailIndex));

transects = getappdata(figNum,'transects');
transectPtr = getappdata(figNum,'transectPtr');
thisStartTime = time(tailIndex);
thisEndTime = time(headIndex);
thisDuration = thisEndTime - thisStartTime;
isMtime = getappdata(figNum,'isMtime');

if ~isMtime
    durationStr = sprintf('%d points',thisDuration);
elseif thisDuration < 120/(60*60*24) % (120 seconds converted to days)
    durationStr = sprintf('%d seconds',round(thisDuration*(60*60*24)));
elseif thisDuration < 120/(60*24) % (120 minutes converted to days)
    durationStr = sprintf('%d minutes',round(thisDuration*(60*24)));
else
    durationStr = sprintf('%.1f hours',thisDuration*24);
end % if

if isMtime
    startTimeStr = datestr(thisStartTime,31);
    endTimeStr = datestr(thisEndTime,31);
end % if

if thisDuration == 0
    if isMtime
        statusStr = sprintf('Zero-length transect beginning at %s',startTimeStr);
    else
        statusStr = sprintf('Zero-length transect beginning at point %d',tailIndex);
    end % if
else
    if isMtime
        statusStr = sprintf('%s - %s (duration %s)',startTimeStr,endTimeStr,durationStr);
    else
        statusStr = sprintf('%d - %d (duration %s)',tailIndex,headIndex,durationStr);
    end % if
end % if

set(findobj(figNum,'Tag','statusText'),'string',statusStr);

%-------------------------------------------------------------------------
function [] = dialPower_cb()
%
% dialPower_cb.m--Callback for dial power edit box.
%
% Syntax: dialPower_cb

% Developed in Matlab 7.6.0.324 (R2008a) on GLNX86.
% Kevin Bartlett (kpb@uvic.ca), 2008-06-04 10:45
%-------------------------------------------------------------------------

tailDial = dial.find_dial(gcbf,'tailDial');
tailDial = tailDial{1};

headDial = dial.find_dial(gcbf,'headDial');
headDial = headDial{1};

dialPowerStr = get(gcbo,'string');
dialPower = str2double(dialPowerStr);

% Setting the valRangePerRotation property (the "power") of the dial will
% cause the dial to change its orientation unless the dial reference value
% and reference orientation are reset at the same time. Use the current
% dial value and orientation as the new reference value and reference
% orientation.

% ...First determine the current dial orientations.
tail_dialValue = get(tailDial,'Value');
tailOrientation = get(tailDial,'orientation');

head_dialValue = get(headDial,'Value');
headOrientation = get(headDial,'orientation');

% ...Now reset the dial to use its current orientation and value as its
% reference orientation and reference value, respectively. This will
% prevent the dial from moving when its valRangePerRotation property is
% modified at the same time.
set(tailDial,'valRangePerRotation',dialPower,'refVal',tail_dialValue,'refOrientation',tailOrientation);
set(headDial,'valRangePerRotation',dialPower,'refVal',head_dialValue,'refOrientation',headOrientation);

Contact us at files@mathworks.com