function varargout = fsdv221(varargin)
% FSDV221 M-file for fsdv221.fig
% FSDV221, by itself, creates a fsdv221 FSDV221 or raises the existing
% singleton*.
%
% H = FSDV221 returns the handle to a fsdv221 FSDV221 or the handle to
% the existing singleton*.
%
% FSDV221('CALLBACK',hObject,eventData,handles,...) calls the local
% function named CALLBACK in FSDV221.M with the given input arguments.
%
% FSDV221('Property','Value',...) creates a fsdv221 FSDV221 or raises the
% existing singleton*. Starting from the left, property value pairs are
% applied to the GUI before fsdv221_OpeningFunction gets called. An
% unrecognized property name or invalid value makes property application
% stop. All inputs are passed to fsdv221_OpeningFcn via varargin.
%
% *See GUI Options on GUIDE's Tools menu. Choose "GUI allows only one
% instance to run (singleton)".
%
% See also: GUIDE, GUIDATA, GUIHANDLES
% Edit the above text to modify the response to help fsdv221
% Last Modified by GUIDE v2.5 28-Nov-2005 15:16:13
% Begin initialization code - DO NOT EDIT
gui_Singleton = 1;
gui_State = struct('gui_Name', mfilename, ...
'gui_Singleton', gui_Singleton, ...
'gui_OpeningFcn', @fsdv221_OpeningFcn, ...
'gui_OutputFcn', @fsdv221_OutputFcn, ...
'gui_LayoutFcn', [] , ...
'gui_Callback', []);
if nargin && ischar(varargin{1})
gui_State.gui_Callback = str2func(varargin{1});
end
if nargout
[varargout{1:nargout}] = gui_mainfcn(gui_State, varargin{:});
else
gui_mainfcn(gui_State, varargin{:});
end
% End initialization code - DO NOT EDIT
% --- Executes just before fsdv221 is made visible.
function fsdv221_OpeningFcn(hObject, eventdata, handles, varargin)
% This function has no output args, see OutputFcn.
% hObject handle to figure
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
% varargin command line arguments to fsdv221 (see VARARGIN)
% Choose default command line output for fsdv221
handles.output = hObject;
% initialise globals needed by many functions
handles.bHasBeenMirrored = 0;
handles.bReconstructState = 0;
handles.sInputFileName = [];
handles.sInputFilePath = [];
handles.bValidInputDataLoaded = 0;
handles.bAnalysisDone = 0;
handles.bValidInputDataLoaded = 0;
handles.bReconDone = 0;
handles.iSymmetryType = 3; % defaults to "Mirror", 1 indicates symmetry
% about the x axis, 2 symmetry about y
handles.rFSDs = [];
handles.rDiffs = [];
handles.rInputData = [];
handles.ReconnedOutline = [];
handles.rMirroredInputData = [];
handles.iInputDataLengths = [];
handles.iOutlineNo = 0;
handles.rColourArray = [0 0 0; 0 0 0; 0 0 1; 0 1 0; 0 1 1; 1 0 0; 1 0 1; 1 1 0; 1 1 1];
% Update handles structure
guidata(hObject, handles);
% --- Outputs from this function are returned to the command line.
function varargout = fsdv221_OutputFcn(hObject, eventdata, handles)
varargout{1} = handles.output;
% --------------------------------------------------------------------
% Checkbox callbacks and create functions
% --------------------------------------------------------------------
% --- Executes on button press in checkbox5.
function checkbox5_Callback(hObject, eventdata, handles)
% the Symmetry checkbox
% --- Executes on button press in checkbox6.
function checkbox6_Callback(hObject, eventdata, handles)
% the Normalse for size checkbox
% --- Executes on button press in checkbox7.
function checkbox7_Callback(hObject, eventdata, handles)
% the Normalise for orientation checkbox
% --- Executes on button press in checkbox8.
function checkbox8_Callback(hObject, eventdata, handles)
% the Symmetry: checkbox
function uipanel2_SelectionChangeFcn(hObject, eventdata, handles)
% radio buttons to select x, y axis for symmetry or overlay
% radiobutton1 = x, 2=y, 3=overlay
% hObject handle to uipanel1 (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
switch get(hObject,'Tag') % Get Tag of selected object
case 'radiobutton1'
handles.iSymmetryType = 1;
case 'radiobutton2'
handles.iSymmetryType = 2;
case 'radiobutton3'
% this is the same as the earlier "Mirror" operation
handles.iSymmetryType = 3;
end
guidata(hObject, handles); % update handles objecgt
% --- Executes on button press in checkbox9.
function checkbox9_Callback(hObject, eventdata, handles)
% the Plot coefficient values checkbox
% --------------------------------------------------------------------
% Edit box callbacks and create functions
% --------------------------------------------------------------------
function edit2_Callback(hObject, eventdata, handles)
% # of harmonics to use for analysis
NoOfHarmonicsAnalyse = str2double(get(hObject,'String'));
set(hObject,'Value', NoOfHarmonicsAnalyse);
NoOfHarmonicsRecon = get(handles.edit2, 'Value');
% force the number of harmonics for reconstruction to be no more than the
% number for analysis
if NoOfHarmonicsRecon > NoOfHarmonicsAnalyse
set(handles.edit2, ...
'String', num2str(NoOfHarmonicsAnalyse), ...
'Value', NoOfHarmonicsAnalyse);
end
% --- Executes during object creation, after setting all properties.
function edit2_CreateFcn(hObject, eventdata, handles)
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
set(hObject,'BackgroundColor','white');
end
function edit3_Callback(hObject, eventdata, handles)
NoOfHarmonicsRecon = str2double(get(hObject,'String'));
set(hObject,'Value', NoOfHarmonicsRecon);
NoOfHarmonicsAnalyse = get(handles.edit2, 'Value');
% force the number of harmonics for reconstruction to be no more than the
% number for analysis
if NoOfHarmonicsRecon > NoOfHarmonicsAnalyse
warndlg('You cannot reconstruct using more harmonics than have been created', 'Be careful!');
set(handles.edit3, ...
'String', num2str(NoOfHarmonicsAnalyse), ...
'Value', NoOfHarmonicsAnalyse);
end
% --- Executes during object creation, after setting all properties.
function edit3_CreateFcn(hObject, eventdata, handles)
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
set(hObject,'BackgroundColor','white');
end
function edit4_Callback(hObject, eventdata, handles)
% Mean eror per point display only
% --- Executes during object creation, after setting all properties.
function edit4_CreateFcn(hObject, eventdata, handles)
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
set(hObject,'BackgroundColor','white');
end
function edit5_Callback(hObject, eventdata, handles)
% Error SD display only
% --- Executes during object creation, after setting all properties.
function edit5_CreateFcn(hObject, eventdata, handles)
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
set(hObject,'BackgroundColor','white');
end
% --- Executes on button press in pushbutton1.
function pushbutton1_Callback(hObject, eventdata, handles)
% the Plot input data button
rInputData = handles.rInputData; % a cell array
rMirroredInputData = handles.rMirroredInputData; % a cell array
sInputFileName = handles.sInputFileName;
bValidInputDataLoaded = handles.bValidInputDataLoaded;
bMirrorState = get(handles.checkbox8, 'value');
iOutlineNo = handles.iOutlineNo;
rColourArray = handles.rColourArray;
if bValidInputDataLoaded
h0 = figure('Units','points', ...
'Color',[0 0.8 0.8], ...
'MenuBar','figure', ...
'Name','Input Data Plot', ...
'NumberTitle','off', ...
'PaperPosition',[18 180 576 432], ...
'PaperType','A4', ...
'PaperUnits','points', ...
'Pointer','crosshair', ...
'Position', [12 114 318 296], ...
'Tag','InputDataFigure');
h1 = axes('Parent',h0, ...
'Box','off', ...
'CameraUpVector',[0 1 0], ...
'Color',[1 1 1], ...
'DataAspectRatioMode','manual', ...
'DataAspectRatio',[80 80 1], ...
'Position', [0.2 0.1 0.5 0.8], ...
'Tag','Axes1', ...
'WarpToFill','off', ...
'XColor',[0 0 0], ...
'YColor',[0 0 0], ...
'ZColor',[0 0 0]);
for iCount = 1 : iOutlineNo % plot all input outlines on the same axes
if bMirrorState == 1
rLocalDataCell = rMirroredInputData{iCount};
else
rLocalDataCell = rInputData{iCount};
end
for i=1:size(rLocalDataCell{1},1) % convert from cell to numeric array
for j=1:2
rLocalData(i,j) = rLocalDataCell{1}(i,j);
end
end
rLocalDataCell = {};
rColour = rColourArray(rem(iCount,8)+1,:);
h2 = line('Parent',h1, ...
'Color', rColour, ...
'Tag','Axes1Line1', ...
'XData',rLocalData(:,1), ...
'YData',rLocalData(:,2));
rLocalData = [];
end % for iCount = 1 : iOutlineNo
else
errordlg('There is no data to plot!', 'Input data error' );
end; % "if bValidInputDataLoaded"
% --- Executes on button press in pushbutton2.
function pushbutton2_Callback(hObject, eventdata, handles)
% the Analyse button
% Calculates a set of elliptical Fourier shape descriptors -
% see Giardina and Kuhl.
% Input is from a file into rLocalData.
% Output is via rFSDs.
% Input data list is mirrored if bMirrorState is TRUE - see Kuhl and Giardina.
% Mirroring helps deal with outline figures that are open-ended
% The output FSDs will be normalised for location, size and orientation
% if bNormaliseState is TRUE
rInputData = handles.rInputData; % a cell array
rMirroredInputData = handles.rMirroredInputData; % a cell array
sInputFileName = handles.sInputFileName;
bValidInputDataLoaded = handles.bValidInputDataLoaded;
iOutlineNo = handles.iOutlineNo;
rColourArray = handles.rColourArray;
bMirrorState = get(handles.checkbox8, 'value'); % read the state of the 'Symmetry" checkbox
bNormaliseSizeState = get(handles.checkbox6, 'Value');
bNormaliseOrientationState = get(handles.checkbox7, 'Value');
bPlotCoeffs = get(handles.checkbox9, 'Value');
iNoOfHarmonicsAnalyse = get(handles.edit2, 'Value');
rFSDs = 0; % clear all shape descriptors
if bValidInputDataLoaded % only do the analysis if there is something to analyse!
% analyse all figures that have been loaded
% choose between the mirrored and ordinary data sets
for iInputFigCount = 1 : iOutlineNo
rLocalData = []; % clear this each time
if bMirrorState == 1
rLocalDataCell = rMirroredInputData{iInputFigCount};
else
rLocalDataCell = rInputData{iInputFigCount};
end
for i=1:size(rLocalDataCell{1},1) % convert from cell to numeric array
for j=1:2
rLocalData(i,j) = rLocalDataCell{1}(i,j);
end
end
rLocalDataCell = {}; % finished with this, clear it
iNoOfPoints = size(rLocalData,1); % gives the number of rows in the matrix
% Pre-calculate some constant arrays
% n * 2 * pi
% n^2 * 2* pi^2
% where n is the number of harmonics to be used in the analysis
rTwoNPi = (1:1:iNoOfHarmonicsAnalyse)* 2 * pi;
rTwoNSqPiSq = (1:1:iNoOfHarmonicsAnalyse) .* (1:1:iNoOfHarmonicsAnalyse)* 2 * pi * pi;
% the following loops are copied from the Excel implementation
% there undoubtably is a more efficient vector form for all this
% but "one thing at a time"...
iNoOfPoints = size(rLocalData,1) - 1; % hence there is 1 more data point in rLocalData than iNoOfPoints
for iCount = 2 : iNoOfPoints + 1
rDeltaX(iCount-1) = rLocalData(iCount,1) - rLocalData(iCount-1,1);
rDeltaY(iCount-1) = rLocalData(iCount,2) - rLocalData(iCount-1,2);
end
% Calculate 'time' differences from point to point - actually distances, but we are
% carrying on the fiction of a point running around the closed figure at constant speed.
% We are analysing the projections on to the x and y axes of this point's path around the figure
for iCount = 1 : iNoOfPoints
rDeltaT(iCount) = sqrt((rDeltaX(iCount)^2) + (rDeltaY(iCount)^2));
end
% now sum the incremental times to get the time at any point
rTime(1) = 0;
for iCount = 2 : iNoOfPoints + 1
rTime(iCount) = rTime(iCount - 1) + rDeltaT(iCount-1);
end
rPeriod = rTime(iNoOfPoints+1); % rPeriod defined for readability
% calculate the A-sub-0 coefficient
rSum1 = 0;
rIncr1 = 0;
for iP = 2 : iNoOfPoints + 1
rSum2 = 0;
rSum3 = 0;
rInnerDiff = 0;
% calculate the partial sums - these are 0 for iCount = 1
if iP > 1
for iJ = 2 : iP-1
rSum2 = rSum2 + rDeltaX(iJ-1);
rSum3 = rSum3 + rDeltaT(iJ-1);
end
rInnerDiff = rSum2 - ((rDeltaX(iP-1) / rDeltaT(iP-1)) * rSum3);
end
rIncr1 = ((rDeltaX(iP-1) / (2*rDeltaT(iP-1)))*(rTime(iP)^2-rTime(iP-1)^2) + rInnerDiff*(rTime(iP)-rTime(iP-1)));
rSum1 = rSum1 + rIncr1;
end
rFSDs(iInputFigCount,1,1) = ((1 / rPeriod) * rSum1) + rLocalData(1,1); % store A-sub-0 in output FSDs array - this array will be 4 x iNoOfHarmonicsAnalyse
% calculate the a-sub-n coefficients
for iHNo = 2 : iNoOfHarmonicsAnalyse
rSum1 = 0;
rIncr1 = 0;
for iP = 1 : iNoOfPoints
rIncr1 = (rDeltaX(iP) / rDeltaT(iP))*((cos(rTwoNPi(iHNo-1)*rTime(iP+1)/rPeriod) - cos(rTwoNPi(iHNo-1)*rTime(iP)/rPeriod)));
rSum1 = rSum1 + rIncr1;
end
rFSDs(iInputFigCount,1,iHNo) = (rPeriod / rTwoNSqPiSq(iHNo-1)) * rSum1;
end % "foriHNo = 1 :..."
rFSDs(iInputFigCount,2,1) = 0; % there is no 0th order sine coefficient
% calculate the b-sub-n coefficients
for iHNo = 2 : iNoOfHarmonicsAnalyse
rSum1 = 0;
rIncr1 = 0;
for iP = 1 : iNoOfPoints
rIncr1 = (rDeltaX(iP) / rDeltaT(iP))*((sin(rTwoNPi(iHNo-1)*rTime(iP+1)/rPeriod) - sin(rTwoNPi(iHNo-1)*rTime(iP)/rPeriod)));
rSum1 = rSum1 + rIncr1;
end
rFSDs(iInputFigCount,2,iHNo) = (rPeriod / rTwoNSqPiSq(iHNo-1)) * rSum1;
end % "foriHNo = 1 :..."
% calculate the C-sub-0 coefficient
rSum1 = 0;
rIncr1 = 0;
for iP = 2 : iNoOfPoints + 1
rSum2 = 0;
rSum3 = 0;
rInnerDiff = 0;
% calculate the partial sums - these are 0 for iCount = 1
if iP > 1
for iJ = 2 : iP-1
rSum2 = rSum2 + rDeltaY(iJ-1);
rSum3 = rSum3 + rDeltaT(iJ-1);
end
rInnerDiff = rSum2 - ((rDeltaY(iP-1) / rDeltaT(iP-1)) * rSum3);
end
rIncr1 = ((rDeltaY(iP-1) / (2*rDeltaT(iP-1)))*(rTime(iP)^2-rTime(iP-1)^2) + rInnerDiff*(rTime(iP)-rTime(iP-1)));
rSum1 = rSum1 + rIncr1;
end
rFSDs(iInputFigCount,3,1) = ((1 / rPeriod) * rSum1) + rLocalData(1,2); % store C-sub-0 in output FSDs array - this array will be 4 x iNoOfHarmonicsAnalyse
% calculate the C-sub-n coefficients
for iHNo = 2 : iNoOfHarmonicsAnalyse
rSum1 = 0;
rIncr1 = 0;
for iP = 1 : iNoOfPoints
rIncr1 = (rDeltaY(iP) / rDeltaT(iP))*((cos(rTwoNPi(iHNo-1)*rTime(iP+1)/rPeriod) - cos(rTwoNPi(iHNo-1)*rTime(iP)/rPeriod)));
rSum1 = rSum1 + rIncr1;
end
rFSDs(iInputFigCount,3,iHNo) = (rPeriod / rTwoNSqPiSq(iHNo-1)) * rSum1;
end % "foriHNo = 1 :..."
rFSDs(iInputFigCount,4,1) = 0; % there is no 0th order sine coefficient
% calculate the D-sub-n coefficients
for iHNo = 2 : iNoOfHarmonicsAnalyse
rSum1 = 0;
rIncr1 = 0;
for iP = 1 : iNoOfPoints
rIncr1 = (rDeltaY(iP) / rDeltaT(iP))*((sin(rTwoNPi(iHNo-1)*rTime(iP+1)/rPeriod) - sin(rTwoNPi(iHNo-1)*rTime(iP)/rPeriod)));
rSum1 = rSum1 + rIncr1;
end
rFSDs(iInputFigCount,4,iHNo) = (rPeriod / rTwoNSqPiSq(iHNo-1)) * rSum1;
end % "foriHNo = 1 :...
% the non-normalised coefficients are now in rFSDs
% if we want the normalised ones, this is where it happens
if (bNormaliseSizeState == 1) || (bNormaliseOrientationState == 1)
% rTheta1 is the angle through which the starting position of the first
% harmonic phasor must be rotated to be aligned with the major axis of
% the first harmonic ellipse
rFSDsTemp = rFSDs;
rTheta1 = 0.5 * atan(2 * (rFSDsTemp(iInputFigCount,1,2) * rFSDsTemp(iInputFigCount,2,2) + rFSDsTemp(iInputFigCount,3,2) * rFSDsTemp(iInputFigCount,4,2)) / ...
(rFSDsTemp(iInputFigCount,1,2)^2 + rFSDsTemp(iInputFigCount,3,2)^2 - rFSDsTemp(iInputFigCount,2,2)^2 - rFSDsTemp(iInputFigCount,4,2)^2));
% calculate the partially normalised coefficients - normalised for
% starting point
for iHNo = 1 : iNoOfHarmonicsAnalyse
rStarFSDs(iInputFigCount,1,iHNo) = cos((iHNo-1) * rTheta1) * rFSDsTemp(iInputFigCount,1,iHNo) + sin((iHNo-1) * rTheta1) * rFSDsTemp(iInputFigCount,2,iHNo);
rStarFSDs(iInputFigCount,2,iHNo) = -sin((iHNo-1) * rTheta1) * rFSDsTemp(iInputFigCount,1,iHNo) + cos((iHNo-1) * rTheta1) * rFSDsTemp(iInputFigCount,2,iHNo);
rStarFSDs(iInputFigCount,3,iHNo) = cos((iHNo-1) * rTheta1) * rFSDsTemp(iInputFigCount,3,iHNo) + sin((iHNo-1) * rTheta1) * rFSDsTemp(iInputFigCount,4,iHNo);
rStarFSDs(iInputFigCount,4,iHNo) = -sin((iHNo-1) * rTheta1) * rFSDsTemp(iInputFigCount,3,iHNo) + cos((iHNo-1) * rTheta1) * rFSDsTemp(iInputFigCount,4,iHNo);
end % for iHNo = 1 : iNoOfHarmonicsAnalyse
rPsi1 = atan(rStarFSDs(iInputFigCount,3,2) / rStarFSDs(iInputFigCount,1,2));
rSemiMajor = sqrt(rStarFSDs(iInputFigCount,1,2)^2 + rStarFSDs(iInputFigCount,3,2)^2); % find the semi-major axis of the first ellipse
rFSDs(iInputFigCount,:,:) = rStarFSDs(iInputFigCount,:,:) ./ rSemiMajor; % if we haven't asked for normalisation of orientation,
% return the coefficients normalised for starting point and size
if bNormaliseOrientationState == 1
% now find the orientation normalised values - return them in rFSDs
for iHNo = 1 : iNoOfHarmonicsAnalyse
rFSDsTemp(iInputFigCount,1,iHNo) = (cos(rPsi1) * rStarFSDs(iInputFigCount,1,iHNo) + sin(rPsi1) * rStarFSDs(iInputFigCount,3,iHNo)) / rSemiMajor;
rFSDsTemp(iInputFigCount,2,iHNo) = (cos(rPsi1) * rStarFSDs(iInputFigCount,2,iHNo) + sin(rPsi1) * rStarFSDs(iInputFigCount,4,iHNo)) / rSemiMajor;
rFSDsTemp(iInputFigCount,3,iHNo) = (-sin(rPsi1) * rStarFSDs(iInputFigCount,1,iHNo) + cos(rPsi1) * rStarFSDs(iInputFigCount,3,iHNo)) / rSemiMajor;
rFSDsTemp(iInputFigCount,4,iHNo) = (-sin(rPsi1) * rStarFSDs(iInputFigCount,2,iHNo) + cos(rPsi1) * rStarFSDs(iInputFigCount,4,iHNo)) / rSemiMajor;
end % for iHNo = 1 : iNoOfHarmonicsAnalyse
rFSDs = rFSDsTemp; % return fully normlised coefficients
end
end % if (bNormaliseSizeState == 1) || (bNormaliseOrientationState == 1)
end %for iInputFigCount = 1 : iOutlineNo
rLocalData = {}; % finished with this, clear it
bAnalysisDone = 1;
rPowerSpectrum = []; % clear all intermediate variables - their size may need to change from run to run
rPhaseSpectrum = [];
% now calculate all derived values:
for iInputFigCount = 1 : iOutlineNo
rPowerSpectrum(iInputFigCount,1,:) = real(sqrt(rFSDs(iInputFigCount,1,:).^2.0 + rFSDs(iInputFigCount,2,:)));
rPowerSpectrum(iInputFigCount,2,:) = real(sqrt(rFSDs(iInputFigCount,3,:).^2.0 + rFSDs(iInputFigCount,4,:)));
rFSDs(iInputFigCount,2,:) = rFSDs(iInputFigCount,2,:) + (eps*5); % small, but not zero
rFSDs(iInputFigCount,4,:) = rFSDs(iInputFigCount,4,:) + (eps*5); % to prevent "divide by 0" errors
rPhaseSpectrum(iInputFigCount,1,:) = atan(rFSDs(iInputFigCount,1,:)./rFSDs(iInputFigCount,2,:));
rPhaseSpectrum(iInputFigCount,2,:) = atan(rFSDs(iInputFigCount,3,:)./rFSDs(iInputFigCount,4,:));
rFSDs(iInputFigCount,2,:) = rFSDs(iInputFigCount,2,:) - (eps*5); % put it back the way it was
rFSDs(iInputFigCount,4,:) = rFSDs(iInputFigCount,4,:) - (eps*5);
end
rXCosProduct = []; % clear all intermediate variables - their size may need to change from run to run
rYCosProduct = [];
rXSinProduct = [];
rYSinProduct = [];
rXCosDiff = [];
rYCosDiff = [];
rXSinDiff = [];
rYSinDiff = [];
rXHarmonicDistance = [];
rYHarmonicDistance = [];
if bNormaliseSizeState
iStartHarmonic = 3;
else
iStartHarmonic = 2;
end
% calculate harmonic distances (only if there is more than one outline)
% use the normalised RMS distance method
if iOutlineNo > 1 %ie there are distances to calculate
rXCosDiff = [];
rYCosDiff = [];
rXSinDiff = [];
rYSinDiff = [];
rXRMSDistance = [];
rYRMSDistance = [];
for iLeft = 1 : iOutlineNo
for iRight = (iLeft+1) : iOutlineNo
rXCosDiff = (rFSDs(iLeft,1,iStartHarmonic:iNoOfHarmonicsAnalyse) - rFSDs(iRight,1,iStartHarmonic:iNoOfHarmonicsAnalyse)).^2;
rYCosDiff = (rFSDs(iLeft,3,iStartHarmonic:iNoOfHarmonicsAnalyse) - rFSDs(iRight,3,iStartHarmonic:iNoOfHarmonicsAnalyse)).^2;
rXSinDiff = (rFSDs(iLeft,2,iStartHarmonic:iNoOfHarmonicsAnalyse) - rFSDs(iRight,2,iStartHarmonic:iNoOfHarmonicsAnalyse)).^2;
rYSinDiff = (rFSDs(iLeft,4,iStartHarmonic:iNoOfHarmonicsAnalyse) - rFSDs(iRight,4,iStartHarmonic:iNoOfHarmonicsAnalyse)).^2;
% iStartHarmonic = 2 is used to avoid adding in
% differences in the location of the centroids of the outlines
% iStartHarmonic = 3 removes the 1 | -1 for the normalised size as
% well
rXRMSDistance(iLeft,iRight) = sqrt(sum(rXCosDiff + rXSinDiff) ./ iNoOfHarmonicsAnalyse);
rYRMSDistance(iLeft,iRight) = sqrt(sum(rYCosDiff + rYSinDiff) ./ iNoOfHarmonicsAnalyse);
end
end
rDiffs = rXRMSDistance;
rDiffs = [rDiffs; rYRMSDistance];
rXData = [];
rYData = [];
iPlotSize = size(rXRMSDistance,1) * size(rXRMSDistance,2);
rXData = reshape(rXRMSDistance, 1, iPlotSize);% convert matrix to row vector
rYData = reshape(rYRMSDistance, 1, iPlotSize);
% plot all distances (there will be one fewer distances than there are outlines)
h0 = figure('Units','points', ...
'Color',[0 0.8 0.8], ...
'MenuBar','figure', ...
'Name',['Harmonic distances plot - RMS distances method'], ...
'NumberTitle','off', ...
'Pointer','crosshair', ...
'Position', [12 114 318 296], ...
'Tag','DistancePlotFigure');
h1 = axes('Parent',h0, ...
'Box','off', ...
'CameraUpVector',[0 1 0], ...
'Color',[1 1 1], ...
'Tag','Axes1', ...
'WarpToFill','off', ...
'XColor',[0 0 0], ...
'YColor',[0 0 0], ...
'ZColor',[0 0 0]);
set(h1,'Xlabel',text('String','X projection distance'));
set(h1,'Ylabel',text('String','Y projection distance'));
h2 = line('Parent',h1, ...
'Color', 'r', ...
'LineStyle', 'none', ...
'Marker', 'x', ...
'Tag','Axes1Line1', ...
'XData',rXData, ...
'YData',rYData);
for iLeft = 1 : iOutlineNo
cLLabel = num2str(iLeft);
rColourLLabel = rColourArray(iLeft,:);
for iRight = (iLeft+1) : iOutlineNo
cRLabel = num2str(iRight);
rColourRLabel = rColourArray(iRight,:);
h3 = text('Parent', h1, ...
'Units', 'data', ...
'Color', rColourLLabel, ...
'Position', [rXRMSDistance(iLeft,iRight) rYRMSDistance(iLeft,iRight)], ...
'VerticalAlignment', 'bottom', ...
'String', [cLLabel '-' cRLabel] );
end
end
handles.rDiffs = rDiffs;
end %if iOutlineNo > 1
if bPlotCoeffs == 1 % Plot the four sets of raw harmonic coefficients
h0 = figure('Units','normalized', ...
'Color',[0 0.8 0.8], ...
'MenuBar','figure', ...
'Name','Harmonic coefficient values', ...
'NumberTitle','off', ...
'Pointer','crosshair', ...
'Position',[.35 .1 .6 .85], ...
'ToolBar','figure');
h1 = axes('Parent',h0, ...
'Box','off', ...
'Color',[1 1 1], ...
'GridLineStyle', '-', ...
'Position',[0.1 0.8 0.8 0.18], ...
'XLim',[1,iNoOfHarmonicsAnalyse]);
set(h1,'Ylabel',text('String','X cosine'));
for iInputFigCount = 1 : iOutlineNo
h2 = line('Parent',h1, ...
'Color',rColourArray(rem(iInputFigCount,8),:), ...
'Tag','Axes1Line1', ...
'Linewidth', 0.3, ...
'Marker','.', ...
'MarkerSize', 8, ...
'XData', [1:1:iNoOfHarmonicsAnalyse], ...
'YData',rFSDs(iInputFigCount,1,:));
end % for iInputFigCount = 1 : iOutlineNo
grid on;
h1 = axes('Parent',h0, ...
'Box','off', ...
'Color',[1 1 1], ...
'GridLineStyle', '-', ...
'Position',[0.1 0.55 0.8 0.18], ...
'XLim',[1,iNoOfHarmonicsAnalyse]);
set(h1,'Ylabel',text('String','X sine'));
for iInputFigCount = 1 : iOutlineNo
h2 = line('Parent',h1, ...
'Color',rColourArray(rem(iInputFigCount,8),:), ...
'Tag','Axes1Line1', ...
'Linewidth', 0.3, ...
'Marker','.', ...
'MarkerSize', 8, ...
'XData', [1:1:iNoOfHarmonicsAnalyse], ...
'YData',rFSDs(iInputFigCount,2,:));
end % for iInputFigCount = 1 : iOutlineNo
grid on;
h1 = axes('Parent',h0, ...
'Box','off', ...
'Color',[1 1 1], ...
'GridLineStyle', '-', ...
'Position',[0.1 0.3 0.8 0.18], ...
'XLim',[1,iNoOfHarmonicsAnalyse]);
set(h1,'Ylabel',text('String','Y cosine'));
for iInputFigCount = 1 : iOutlineNo
h2 = line('Parent',h1, ...
'Color',rColourArray(rem(iInputFigCount,8),:), ...
'Tag','Axes1Line1', ...
'Linewidth', 0.3, ...
'Marker','.', ...
'MarkerSize', 8, ...
'XData', [1:1:iNoOfHarmonicsAnalyse], ...
'YData',rFSDs(iInputFigCount,3,:));
end % for iInputFigCount = 1 : iOutlineNo
grid on;
h1 = axes('Parent',h0, ...
'Box','off', ...
'Color',[1 1 1], ...
'GridLineStyle', '-', ...
'Position',[0.1 0.05 0.8 0.18], ...
'XLim',[1,iNoOfHarmonicsAnalyse]);
set(h1,'Ylabel',text('String','Y sine'));
for iInputFigCount = 1 : iOutlineNo
h2 = line('Parent',h1, ...
'Color',rColourArray(rem(iInputFigCount,8),:), ...
'Tag','Axes1Line1', ...
'Linewidth', 0.3, ...
'Marker','.', ...
'MarkerSize', 8, ...
'XData', [1:1:iNoOfHarmonicsAnalyse], ...
'YData',rFSDs(iInputFigCount,4,:));
end % for iInputFigCount = 1 : iOutlineNo
grid on;
h0 = figure('Units','normalized', ... %plot the x and y power spectra
'Color',[0 0.8 0.8], ...
'MenuBar','figure', ...
'Name','Power spectra', ...
'NumberTitle','off', ...
'Pointer','crosshair', ...
'Position',[.3 .1 .6 .45], ...
'ToolBar','figure');
h1 = axes('Parent',h0, ...
'Box','off', ...
'Color',[1 1 1], ...
'GridLineStyle', '-', ...
'Position',[0.1 0.55 0.8 0.35], ...
'XLim',[1,iNoOfHarmonicsAnalyse]);
set(h1,'Ylabel',text('String','X projection'));
for iInputFigCount = 1 : iOutlineNo
h2 = line('Parent',h1, ...
'Color',rColourArray(rem(iInputFigCount,8),:), ...
'Tag','Axes1Line1', ...
'Linewidth', 0.3, ...
'Marker','.', ...
'MarkerSize', 8, ...
'XData', [1:1:iNoOfHarmonicsAnalyse], ...
'YData',rPowerSpectrum(iInputFigCount,1,:));
end % for iInputFigCount = 1 : iOutlineNo
grid on;
h1 = axes('Parent',h0, ...
'Box','off', ...
'Color',[1 1 1], ...
'GridLineStyle', '-', ...
'Position',[0.1 0.1 0.8 0.35], ...
'XLim',[1,iNoOfHarmonicsAnalyse]);
set(h1,'Ylabel',text('String','Y projection'));
for iInputFigCount = 1 : iOutlineNo
h2 = line('Parent',h1, ...
'Color',rColourArray(rem(iInputFigCount,8),:), ...
'Tag','Axes1Line1', ...
'Linewidth', 0.3, ...
'Marker','.', ...
'MarkerSize', 8, ...
'XData', [1:1:iNoOfHarmonicsAnalyse], ...
'YData',rPowerSpectrum(iInputFigCount,2,:));
end % for iInputFigCount = 1 : iOutlineNo
grid on;
end % if bPlotCoeffs == 1
handles.rDeltaT = rDeltaT;
handles.rFSDs = rFSDs;
handles.rPowerSpectrum = rPowerSpectrum;
handles.rPhaseSpectrum = rPhaseSpectrum;
handles.bAnalysisDone = 1;
guidata(hObject, handles);
else
errordlg('There is no data loaded to analyse!', 'Data input error' );
end;% "if bValidInputDataLoaded"
% --- Executes on button press in pushbutton3.
function pushbutton3_Callback(hObject, eventdata, handles)
% the Reconstruct button
% Reconstructs the outline figure using the specified
% number of harmonics. Plots an x-y graph of the result
bAnalysisDone = handles.bAnalysisDone;
rFSDs = handles.rFSDs;
rDeltaT = handles.rDeltaT; % time increments used in the analysis will be used
% for the reconstruction. Could use any arbitrary points (eg equally
% spaced) but there is no need for spacing to be equal or for there to be
% any particular number of points.
% We should store seperate rDeltaT vectors for each outline when there are
% multiple outlines
iNoOfHarmonicsReconstruct = get(handles.edit3, 'Value');
iOutlineNo = handles.iOutlineNo;
rColourArray = handles.rColourArray;
sInputFileName = handles.sInputFileName;
iStartHarmonic = 2; % start at 2 - No.1 is just a location,could be added in
m = size(rDeltaT, 2) + 1;
rTimeSteps(1) = 0;
rTimeSteps = [rTimeSteps rDeltaT];
for i=2:m
rTimeSteps(i) = rTimeSteps(i) + rTimeSteps(i-1);
end
rTimeSteps = (rTimeSteps/sum(rDeltaT)) * pi; % fractions of pi up to 100%
ReconnedOutline = 0;
if bAnalysisDone == 1 % don't try to reconstruct if the analysis hasn't been done on the currently loaded data
for iInputFigCount = 1 : iOutlineNo
% reconstruct the x-projection
for iTime = 1:size(rTimeSteps, 2)
rSum = 0.0;
for iHNo = iStartHarmonic:iNoOfHarmonicsReconstruct
rSum = rSum + (rFSDs(iInputFigCount,1,iHNo) * cos(2*(iHNo-1)* rTimeSteps(iTime)) + ...
rFSDs(iInputFigCount,2,iHNo) * sin(2*(iHNo-1)* rTimeSteps(iTime)));
end % for iHNo = 1 : iNoOfHarmonicsReconstruct
ReconnedOutline(iInputFigCount,iTime,1) = rFSDs(iInputFigCount,1,1) + rSum;
end % for iTime = 1 : size(rTimeSteps, 2)
% reconstruct the y-projection
for iTime = 1:size(rTimeSteps, 2)
rSum = 0.0;
for iHNo = iStartHarmonic:iNoOfHarmonicsReconstruct
rSum = rSum + (rFSDs(iInputFigCount,3,iHNo) * cos(2*(iHNo-1)* rTimeSteps(iTime)) + ...
rFSDs(iInputFigCount,4,iHNo) * sin(2*(iHNo-1)* rTimeSteps(iTime)));
end % for iHNo = 1 : iNoOfHarmonicsReconstruct
ReconnedOutline(iInputFigCount,iTime,2) = rFSDs(iInputFigCount,3,1) + rSum;
end % for iTime = 1 : size(rTimeSteps, 2)
end %for iInputFigCount = 1 : iOutlineNo
h0 = figure('Units','points', ...
'Color',[0 0.8 0.8], ...
'MenuBar','figure', ...
'Name',['Reconstructed figure plot: ' sInputFileName], ...
'NumberTitle','off', ...
'PaperPosition',[18 180 576 432], ...
'PaperType','A4', ...
'PaperUnits','points', ...
'Pointer','crosshair', ...
'Position', [12 114 318 296], ...
'Tag','ReconnedDataFigure', ...
'ToolBar','figure');
h1 = axes('Parent',h0, ...
'Box','off', ...
'CameraUpVector',[0 1 0], ...
'Color',[1 1 1], ...
'DataAspectRatioMode','manual', ...
'DataAspectRatio',[80 80 1], ...
'Position', [0.2 0.1 0.5 0.8], ...
'Tag','Axes1', ...
'WarpToFill','off', ...
'XColor',[0 0 0], ...
'YColor',[0 0 0], ...
'ZColor',[0 0 0]);
for iInputFigCount = 1 : iOutlineNo % plot all reconstructed outlines
h2 = line('Parent',h1, ...
'Color',rColourArray(rem(iInputFigCount,8)+1,:), ...
'Tag','Axes1Line1', ...
'XData',ReconnedOutline(iInputFigCount,:,1), ...
'YData',ReconnedOutline(iInputFigCount,:,2));
end % for iInputFigCount = 1 : iOutlineNo
else
errordlg('Cannot reconstruct - there are no valid FSDs!', 'Reconstruction error' );
end %
% recover the original data to calculate the error estimate
rInputData = handles.rInputData; % a cell array
rLocalData = []; % clear this each time
rLocalDataCell = rInputData{iInputFigCount};
for i=1:size(rLocalDataCell{1},1) % convert from cell to numeric array
for j=1:2
rLocalData(i,j) = rLocalDataCell{1}(i,j);
end
end
%remove the last point from the input data - was added to "close" the figure
iNoOfPoints = size(rLocalData,1)-1;
rLocalData = rLocalData(1:iNoOfPoints, :);
ro = ReconnedOutline(:,:,1)';
ro = [ro ReconnedOutline(:,:,2)'];
bMirrorState = get(handles.checkbox8, 'value');
if bMirrorState
ro = ro(1:iNoOfPoints, :);
end
errors = [];
for m=1:iNoOfPoints
errors(m) = EuclidDist(rLocalData(m,:), ro(m,:));
end
totalError = sum(errors);
meanErrorPerPoint = totalError / iNoOfPoints;
errorDeviations = (errors - meanErrorPerPoint).^2;
errorVariance = sum(errorDeviations)/(iNoOfPoints-1);
errorSD = sqrt(errorVariance);
set(handles.edit5, ...
'String', num2str(errorSD), ...
'Value', errorSD);
set(handles.edit4, ...
'String', num2str(meanErrorPerPoint), ...
'Value', meanErrorPerPoint);
handles.ReconnedOutline = ReconnedOutline;
handles.bReconDone = 1;
% Update handles structure
guidata(hObject, handles);
% --- Executes on button press in pushbutton4.
function pushbutton4_Callback(hObject, eventdata, handles)
% the Clear outlines button
% Clears all outlines and FSDs from memory
% Specific to the multiple outlines version
% in the single outlines version, loading a
% fresh outline or set of FSDs automatically
% over-writes the previous data.
handles.rInputData = {};
handles.rMirroredInputData = {};
handles.rFSDs = [];
handles.ReconnedOutline = [];
handles.iOutlineNo = 0;
handles.ReconnedOutline = 0;
handles.bValidInputDataLoaded = 0;
handles.bAnalysisDone = 0;
guidata(hObject, handles);
% --- Executes on button press in pushbutton5.
function pushbutton5_Callback(hObject, eventdata, handles)
% the Close button
delete(handles.figure1);
% --------------------------------------------------------------------
% Menu callbacks
% --------------------------------------------------------------------
function FileMenu_Callback(hObject, eventdata, handles)
% --------------------------------------------------------------------
function OpenXyMenu_Callback(hObject, eventdata, handles)
% Prompts for filename using a dialog box
% Opens the selected file (assumes it is TAB delimited text)
% and reads it into a matrix
% A "mirrored" version is also created
% Intended to be the callback for the file-open menu entry in 'Figure1.m'
iOutlineNo = handles.iOutlineNo;
sInputFilePath = handles.sInputFilePath;
sInputFileName = handles.sInputFileName;
if iOutlineNo == 0 %ie we are here for the first time
[fname,sInputFilePath] = uigetfile('*.txt;*.csv;*.xls', 'Find the input data file to open');
if fname == 0
return; % bail out if user Cancels
else
iOutlineNo = iOutlineNo + 1;
end
sInputFileName = fullfile(sInputFilePath, fname);
[pathstr,name,inputFileExtention,versn] = fileparts(sInputFileName);
[hFileHandle, message] = fopen(sInputFileName, 'r');
sOpenFileList{iOutlineNo} = fname;
else % we have opened one already - go back to the same directory path
[fname,sInputFilePath] = uigetfile([sInputFilePath '*.txt;*.csv;*.xls'], 'Find the input data file to open');
if fname == 0
return; % bail out if user Cancels
else
iOutlineNo = iOutlineNo + 1;
end
sInputFileName = fullfile(sInputFilePath, fname);
[pathstr,name,inputFileExtention,versn] = fileparts(sInputFileName);
[hFileHandle, message] = fopen(sInputFileName, 'r');
sOpenFileList{iOutlineNo} = fname;
end
rThisInputData = [];
rThisMirroredInputData = [];
%read x,y data - dlmread uses textread that is only available as a MEX file and cannot yet (R11) be compiled
switch lower(inputFileExtention)
case '.txt'
while feof(hFileHandle) == 0
line = fgetl(hFileHandle);
xy = sscanf(line, '%g%g');
xyt = xy';
rThisInputData = [rThisInputData;xyt];
end
fclose(hFileHandle);
case '.csv'
while feof(hFileHandle) == 0
line = fgetl(hFileHandle);
xy = sscanf(line, '%g,%g');
xyt = xy';
rThisInputData = [rThisInputData;xyt];
end
fclose(hFileHandle);
case '.xls'
rThisInputData = xlsread(sInputFileName);
end
iNoOfPoints = size(rThisInputData,1); % gives the number of columns in the matrix
rFirstPt = rThisInputData(1, :);
rLastPt = rThisInputData(iNoOfPoints, :); % these Pts are x-y pairs
if EuclidDist(rFirstPt, rLastPt) < .1 % millimetres are the usual units
rThisInputData = rThisInputData(1:iNoOfPoints-1, :);
% removes last point from rInputData
% if it is too close to the first (ie figure is "closed")
end
iSymmetryType = handles.iSymmetryType;
switch iSymmetryType
case 1
rSecondHalfOfMirroredData(:,1) = rThisInputData(iNoOfPoints-1:-1:2, 1)*-1;
rSecondHalfOfMirroredData(:,2) = rThisInputData(iNoOfPoints-1:-1:2, 2);
% flips the sign of the x coordinates and reverses the data
case 2
rSecondHalfOfMirroredData(:,1) = rThisInputData(iNoOfPoints-1:-1:2, 1);
rSecondHalfOfMirroredData(:,2) = rThisInputData(iNoOfPoints-1:-1:2, 2)*-1;
% flips the sign of the y coordinates and reverses the data
case 3
rSecondHalfOfMirroredData(:,1) = rThisInputData(iNoOfPoints-1:-1:2, 1);
rSecondHalfOfMirroredData(:,2) = rThisInputData(iNoOfPoints-1:-1:2, 2);
% this is the same as the earlier "Mirror" operation - overlays the
% data with a reverse order copy of itself
end
%if iSymmetryType == 1
% rSecondHalfOfMirroredData(:,1) = rThisInputData(iNoOfPoints-1:-1:2, 1) *-1;
%else
% rSecondHalfOfMirroredData(:,1) = rThisInputData(iNoOfPoints-1:-1:2, 1);
%end
%rSecondHalfOfMirroredData(:,2) = rThisInputData(iNoOfPoints-1:-1:2, 2);
rThisMirroredInputData = [rThisInputData; rSecondHalfOfMirroredData];
% puts the two halves of the data together to form the symmetrical data
% Duplicate the first point to close the figure.
% I know this may just be a reversal of the removal of the
% duplicate point done above, BUT this way it doesn't matter whether someone
% has already closed the input figure or not.
% Really just input data validation
rThisInputData = [rThisInputData; rThisInputData(1,:)];
rThisMirroredInputData = [rThisMirroredInputData; rThisMirroredInputData(1,:)];
% when we get here there are two alternative sets of input data
% one is mirrored, the other not. Both are "closed" correctly.
handles.iOutlineNo = iOutlineNo;
handles.rInputData{iOutlineNo} = {rThisInputData}; % a cell array
handles.rMirroredInputData{iOutlineNo} = {rThisMirroredInputData}; % a cell array
handles.sInputFileName = sInputFileName;
handles.bValidInputDataLoaded = 1;
handles.bAnalysisDone = 0; % new data is loaded but not analysed
handles.sInputFilePath = sInputFilePath;
% Update handles structure
guidata(hObject, handles);
% --------------------------------------------------------------------
function OpenFSDsMenu_Callback(hObject, eventdata, handles)
% callback for "Load FSDs from text file" menu entry
% Loads the FSDs from a TAB delimited text file
iOutlineNo = handles.iOutlineNo;
[fname,pname] = uigetfile('*.txt', 'Specify the file from which to load the FSDs');
if fname == 0
return; % bail out if user Cancels
end
sInputFileName = fullfile(pname, fname);
hFileHandle = fopen(sInputFileName, 'rt');
if hFileHandle == -1
return; % bail out if fopen fails for any reason
end
rFSDs = [];
rFSDsTemp = [];
iOutlineNo = 0;
while feof(hFileHandle) == 0
iOutlineNo = iOutlineNo + 1;
sLine1 = fgetl(hFileHandle);
sLine2 = fgetl(hFileHandle);
sLine3 = fgetl(hFileHandle);
sLine4 = fgetl(hFileHandle);
rFSDsTemp = sscanf(sLine1, '%g', [1 inf]);
iNoOfHarmonicsAnalyse = size(rFSDsTemp,2);
rFSDsTemp = [rFSDsTemp ; sscanf(sLine2, '%g', [1 iNoOfHarmonicsAnalyse])]; % concatenate the next row
rFSDsTemp = [rFSDsTemp ; sscanf(sLine3, '%g', [1 iNoOfHarmonicsAnalyse])]; % and again
rFSDsTemp = [rFSDsTemp ; sscanf(sLine4, '%g', [1 iNoOfHarmonicsAnalyse])]; % and again
rFSDs(iOutlineNo,:,:) = rFSDsTemp;
end %while feof(hFileHandle)
fclose(hFileHandle);
set(handles.edit2, ...
'String', num2str(iNoOfHarmonicsAnalyse), ...
'Value', iNoOfHarmonicsAnalyse); % force edit box contents
set(handles.edit3, ...
'String', num2str(iNoOfHarmonicsAnalyse), ...
'Value', iNoOfHarmonicsAnalyse);
handles.rFSDs = rFSDs;
handles.iOutlineNo = iOutlineNo;
handles.bValidInputDataLoaded = 0; % we have loaded FSDs - cannot assume there is anything to analyse
handles.bAnalysisDone = 1; % but there are valid FSDs to reconstruct
guidata(hObject, handles);
% --------------------------------------------------------------------
function SaveFSDsMenu_Callback(hObject, eventdata, handles)
% callback for "Save FSDs to text file" menu entry
% saves the FSDs in a TAB delimited text file
rFSDs = handles.rFSDs;
bAnalysisDone = handles.bAnalysisDone;
iOutlineNo = handles.iOutlineNo;
if bAnalysisDone == 1 % ie there should be valid data in rFSDs
[fname,pname] = uiputfile('*.txt', 'Specify the file in which to save the FSDs');
if fname == 0
return; % bail out if user Cancels
end
sOutputFileName = fullfile(pname, fname);
hFileHandle = fopen(sOutputFileName, 'w');
for iInputFigCount = 1 : iOutlineNo
rLine1 = rFSDs(iInputFigCount,1,:);
rLine2 = rFSDs(iInputFigCount,2,:);
rLine3 = rFSDs(iInputFigCount,3,:);
rLine4 = rFSDs(iInputFigCount,4,:);
fprintf(hFileHandle, '%7.5f\t', rLine1);
fprintf(hFileHandle, '\r\n');
fprintf(hFileHandle, '%7.5f\t', rLine2);
fprintf(hFileHandle, '\r\n');
fprintf(hFileHandle, '%7.5f\t', rLine3);
fprintf(hFileHandle, '\r\n');
fprintf(hFileHandle, '%7.5f\t', rLine4);
fprintf(hFileHandle, '\r\n');
end %for iInputFigCount = 1 : iOutlineNo
% dlmwrite(sOutputFileName, rFSDs, '\t'); % dlmwrite leaves blanks for 0s - not what we want!
fclose(hFileHandle);
else
errordlg('There are no FSDs to write out!', 'File output error' );
end % if bAnalysisDone == 1
% --------------------------------------------------------------------
function SaveRecon_Callback(hObject, eventdata, handles)
% callback for "Save reconstructed outline" menu entry
% saves the outline in a TAB delimited text file
ReconnedOutline = handles.ReconnedOutline;
bReconDone = handles.bReconDone;
iOutlineNo = handles.iOutlineNo;
if bReconDone == 1 % ie there should be valid data in rDiffs
[fname,pname] = uiputfile('*.txt', 'Specify the file in which to save the reconstruction');
if fname == 0
return; % bail out if user Cancels
end
sOutputFileName = fullfile(pname, fname);
hFileHandle = fopen(sOutputFileName, 'w');
for iThisOutline = 1:iOutlineNo
for iCol = 1 : size(ReconnedOutline,2)
rLine1 = ReconnedOutline(iOutlineNo,iCol, :);
fprintf(hFileHandle, '%7.5f\t', rLine1);
fprintf(hFileHandle, '\r\n');
end %for iRow = 1 : iOutlineNo
end
fclose(hFileHandle);
else
errordlg('No reconstruction has been done, hence there is no data to write!', 'File output error' );
end % if bAnalysisDone == 1
% --------------------------------------------------------------------
function SaveDiffsToFile_Callback(hObject, eventdata, handles)
% callback for "Save differences to file" menu entry
% saves the RMS differences in a TAB delimited text file
rDiffs = handles.rDiffs;
bAnalysisDone = handles.bAnalysisDone;
iOutlineNo = handles.iOutlineNo;
if bAnalysisDone == 1 % ie there should be valid data in rDiffs
[fname,pname] = uiputfile('*.txt', 'Specify the file in which to save the differences');
if fname == 0
return; % bail out if user Cancels
end
sOutputFileName = fullfile(pname, fname);
hFileHandle = fopen(sOutputFileName, 'w');
for iRow = 1 : 2 .* (iOutlineNo - 1)
rLine1 = rDiffs(iRow, :);
fprintf(hFileHandle, '%7.5f\t', rLine1);
fprintf(hFileHandle, '\r\n');
end %for iRow = 1 : iOutlineNo
fclose(hFileHandle);
else
errordlg('There are no differences calculated! Cannot write the file', 'File output error' );
end % if bAnalysisDone == 1
% --------------------------------------------------------------------
function ExitMenu_Callback(hObject, eventdata, handles)
delete(handles.figure1);
% --------------------------------------------------------------------
function AboutMenu_Callback(hObject, eventdata, handles)
msgbox(['Fourier shape descriptor program - Version V2.21. C David L Thomas, Oral ' ...
'Anatomy, Medicine & Surgery Unit, School of Dental Science, ' ...
'University of Melbourne. November 2005'], 'About FSD');
% --------------------------------------------------------------------
% Helper functions
% --------------------------------------------------------------------
function rDistance = EuclidDist(rPt1, rPt2)
% returns the Euclidian distance between rPt1 and rPt2
% which are assumed to be x-y pairs of floating-point numbers
rXDist = abs(rPt1(1) - rPt2(1));
rYDist = abs(rPt1(2) - rPt2(2));
rDistance = sqrt(rXDist*rXDist + rYDist*rYDist);