123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742 |
- function varargout = spm_XYZreg(varargin)
- % Registry for GUI XYZ locations, and point list utility functions
- %
- % ----------------
- %
- % PointList & voxel centre utilities...
- %
- % FORMAT [xyz,d] = spm_XYZreg('RoundCoords',xyz,M,D)
- % FORMAT [xyz,d] = spm_XYZreg('RoundCoords',xyz,V)
- % Round specified xyz location to nearest voxel centre
- % xyz - (Input) 3-vector of X, Y & Z locations, in "real" coordinates
- % M - 4x4 transformation matrix relating voxel to "real" coordinates
- % D - 3 vector of image X, Y & Z dimensions (DIM)
- % V - 9-vector of image and voxel sizes, and origin [DIM,VOX,ORIGIN]'
- % M derived as [ [diag(V(4:6)), -(V(7:9).*V(4:6))]; [zeros(1,3) ,1]]
- % DIM - D
- % VOX - Voxel dimensions in units of "real" coordinates
- % ORIGIN - Origin of "real" coordinates in voxel coordinates
- % xyz - (Output) coordinates of nearest voxel centre in "real" coordinates
- % d - Euclidean distance between requested xyz & nearest voxel centre
- %
- % FORMAT i = spm_XYZreg('FindXYZ',xyz,XYZ)
- % find position of specified voxel in XYZ pointlist
- % xyz - 3-vector of coordinates
- % XYZ - Pointlist: 3xn matrix of coordinates
- % i - Column(s) of XYZ equal to xyz
- %
- % FORMAT [xyz,i,d] = spm_XYZreg('NearestXYZ',xyz,XYZ)
- % find nearest voxel in pointlist to specified location
- % xyz - (Input) 3-vector of coordinates
- % XYZ - Pointlist: 3xn matrix of coordinates
- % xyz - (Output) coordinates of nearest voxel in XYZ pointlist
- % (ties are broken in favour of the first location in the pointlist)
- % i - Column of XYZ containing coordinates of nearest pointlist location
- % d - Euclidean distance between requested xyz & nearest pointlist location
- %
- % FORMAT d = spm_XYZreg('Edist',xyz,XYZ)
- % Euclidean distances between coordinates xyz & points in XYZ pointlist
- % xyz - 3-vector of coordinates
- % XYZ - Pointlist: 3xn matrix of coordinates
- % d - n row-vector of Euclidean distances between xyz & points of XYZ
- %
- % ----------------
- %
- % Registry functions
- %
- % FORMAT [hReg,xyz] = spm_XYZreg('InitReg',hReg,M,D,xyz)
- % Initialise registry in graphics object
- % hReg - Handle of HandleGraphics object to build registry in. Object must
- % be un'Tag'ged and have empty 'UserData'
- % M - 4x4 transformation matrix relating voxel to "real" coordinates,
- % used and stored for checking validity of coordinates
- % D - 3 vector of image X, Y & Z dimensions (DIM), used
- % and stored for checking validity of coordinates
- % xyz - (Input) Initial coordinates [Default [0;0;0]]
- % These are rounded to the nearest voxel centre
- % hReg - (Output) confirmation of registry handle
- % xyz - (Output) Current registry coordinates, after rounding
- %
- % FORMAT spm_XYZreg('UnInitReg',hReg)
- % Clear registry information from graphics object
- % hReg - Handle of 'hReg' 'Tag'ged registry HandleGraphics object.
- % Object's 'Tag' & 'UserData' are cleared
- %
- % FORMAT xyz = spm_XYZreg('GetCoords',hReg)
- % Get current registry coordinates
- % hReg - Handle of 'hReg' 'Tag'ged registry HandleGraphics object
- %
- % FORMAT [xyz,d] = spm_XYZreg('SetCoords',xyz,hReg,hC,Reg)
- % Set coordinates in registry & update registered HGobjects/functions
- % xyz - (Input) desired coordinates
- % hReg - Handle of 'hReg' 'Tag'ged registry HandleGraphics object
- % If hReg doesn't contain a registry, a warning is printed.
- % hC - Handle of caller object (to prevent circularities) [Default 0]
- % If caller object passes invalid registry handle, then spm_XYZreg
- % attempts to blank the 'hReg' fiend of hC's 'UserData', printing
- % a warning notification.
- % Reg - Alternative nx2 cell array Registry of handles / functions
- % If specified, overrides use of registry held in hReg
- % [Default getfield(get(hReg,'UserData'),'Reg')]
- % xyz - (Output) Desired coordinates are rounded to nearest voxel if hC
- % is not specified, or is zero. Otherwise, caller is assummed to
- % have checked verity of desired xyz coordinates. Output xyz
- % returns coordinates actually set.
- % d - Euclidean distance between desired and set coordinates.
- %
- % FORMAT nReg = spm_XYZreg('XReg',hReg,{h,Fcn}pairs)
- % Cross registration object/function pairs with the registry, push xyz coords
- % hReg - Handle of 'hReg' 'Tag'ged registry HandleGraphics object
- % h - Handle of HandleGraphics object to be registered
- % The 'UserData' of h must be a structure with an 'Reg' field, which
- % is set to hReg, the handle of the registry (back registration)
- % Fcn - Handling function for HandleGraphics object h
- % This function *must* accept XYZ updates via the call:
- % feval(Fcn,'SetCoords',xyz,h,hReg)
- % and should *not* call back the registry with the update!
- % {h,Fcn} are appended to the registry (forward registration)
- % nReg - New registry cell array: Handles are checked for validity before
- % entry. Invalid handles are omitted, generating a warning.
- %
- % FORMAT nReg = spm_XYZreg('Add2Reg',hReg,{h,Fcn}pairs)
- % Add object/function pairs for XYZ updates to registry (forward registration)
- % hReg - Handle of 'hReg' 'Tag'ged registry HandleGraphics object
- % h - Handle of HandleGraphics object to be registered
- % Fcn - Handling function for HandleGraphics object h
- % This function *must* accept XYZ updates via the call:
- % feval(Fcn,'SetCoords',xyz,h,hReg)
- % and should *not* call back the registry with the update!
- % {h,Fcn} are appended to the registry (forward registration)
- % nReg - New registry cell array: Handles are checked for validity before
- % entry. Invalid handles are omitted, generating a warning.
- %
- % FORMAT spm_XYZreg('SetReg',h,hReg)
- % Set registry field of object's UserData (back registration)
- % h - Handle of HandleGraphics object to be registered
- % The 'UserData' of h must be a structure with an 'Reg' field, which
- % is set to hReg, the handle of the registry (back registration)
- % hReg - Handle of 'hReg' 'Tag'ged registry HandleGraphics object
- %
- % FORMAT nReg = spm_XYZreg('unXReg',hReg,hD1,hD2,hD3,...)
- % Un-cross registration of HandleGraphics object hD
- % hReg - Handle of 'hReg' 'Tag'ged registry HandleGraphics object
- % hD? - Handles of HandleGraphics object to be unregistered
- % The 'UserData' of hD must be a structure with a 'Reg' field, which
- % is set to empty (back un-registration)
- % nReg - New registry cell array: Registry entries with handle entry hD are
- % removed from the registry (forward un-registration)
- % Handles not in the registry generate a warning
- %
- % FORMAT nReg = spm_XYZreg('Del2Reg',hReg,hD)
- % Delete HandleGraphics object hD from registry (forward un-registration)
- % hReg - Handle of 'hReg' 'Tag'ged registry HandleGraphics object
- % hD? - Handles of HandleGraphics object to be unregistered
- % nReg - New registry cell array: Registry entries with handle entry hD are
- % removed from the registry. Handles not in registry generate a warning
- %
- % FORMAT spm_XYZreg('UnSetReg',h)
- % Unset registry field of object's UserData (back un-registration)
- % h - Handle of HandleGraphics object to be unregistered
- % The 'UserData' of hD must be a structure with a 'Reg' field, which
- % is set to empty (back un-registration)
- %
- % FORMAT spm_XYZreg('CleanReg',hReg)
- % Clean invalid handles from registry
- % hReg - Handle of 'hReg' 'Tag'ged registry HandleGraphics object
- %
- % FORMAT Reg = spm_XYZreg('VReg',Reg,Warn)
- % Prune invalid handles from Registry cell array
- % Reg - (Input) nx2 cell array of {handle,function} pairs
- % Warn - If specified, print warning if find invalid handles
- % Reg - (Output) mx2 cell array of valid {handle,function} pairs
- %
- % FORMAT hReg = spm_XYZreg('FindReg',h)
- % Find/check registry object
- % h - handle of Registry, or figure containing Registry (default gcf)
- % If ischar(h), then uses spm_figure('FindWin',h) to locate named figures
- % hReg - handle of confirmed registry object
- % Errors if h is not a registry or a figure containing a unique registry
- % Registry object is identified by 'hReg' 'Tag'
- %__________________________________________________________________________
- %
- % spm_XYZreg provides a framework for modular inter-GUI communication of
- % XYZ co-orginates, and various utility functions for pointlist handling
- % and rounding in voxel coordinates.
- % Concept and examples can be found in the body of the function.
- %__________________________________________________________________________
- % Copyright (C) 1999-2018 Wellcome Trust Centre for Neuroimaging
- % Andrew Holmes, Chloe Hutton
- % $Id: spm_XYZreg.m 7388 2018-08-06 12:04:26Z guillaume $
- % THE REGISTRY
- %
- % The concept of the registry is of a central entity which "knows" about
- % other GUI objects holding XYZ coordinates, and keeps them all in sync.
- % Changes to the registry's XYZ coordinates are passed on to registered
- % functions by the registry (forward registration). Individual objects
- % which can change the XYZ coordinates should therefore update the
- % registry with the new coordinates (back registration), so that the
- % registry can tell all registered objects about the new location, and a
- % framework is provided for this.
- %
- % The registry is held as the 'UserData of a HandleGraphics object, whose
- % handle therefore identifies the registry. The registry object is 'Tag'ged
- % 'hReg' for identification (though this 'Tag' is not used for locating the
- % registry, so multiple registry incarnations are possible). The registry
- % object's 'UserData' is a structure containing the current XYZ
- % coordinates, the voxel-to-coordinates matrix M, the image dimensions D,
- % and the Registry itself. The registry is a nx2 cell array containing n
- % handle/function pairs.
- %
- % The model is that all GUI objects requiring linking to a common XYZ
- % location via the registry each be identified by a HandleGraphics handle.
- % This handle can be the handle of the particular instantiation of the GUI
- % control itself (as is the case with the MIP-GUI of spm_mip_ui where the
- % axis handle is used to identify the MIP to use); the handle of another
- % HandleGraphics object associated with the GUI control (as is the case
- % with the XYZ editable widgets of spm_results_ui where the handle of the
- % bounding frame uicontrol is used); or may be 0, the handle of the root
- % object, which allows non GUI functions (such as a function that just
- % prints information) to be added to the registry. The registry itself thus
- % conforms to this model. Each object has an associated "handling function"
- % (so this function is the registry's handling function). The registry
- % itself consists of object-handle/handling-function pairs.
- %
- % If an object and it's handling function are entered in the registry, then
- % the object is said to be "forward registered", because the registry will
- % now forward all location updates to that object, via it's handling
- % function. The assummed syntax is: feval(Fcn,'SetCoords',xyz,h,hReg),
- % where Fcn is the handling function for the GUI control identified by
- % handle h, xyz are the new coordinates, and hReg is the handle of the
- % registry.
- %
- % An optional extension is "back registration", whereby the GUI controls
- % inform the registry of the new location when they are updated. All that's
- % required is that the objects call the registry's 'SetCoords' function:
- % spm_XYZreg('SetCoords',xyz,hReg,hC), where hReg is the registry object's
- % handle, and hC is the handle associated with the calling GUI control. The
- % specification of the caller GUI control allows the registry to avoid
- % circularities: If the object is "forward registered" for updates, then
- % the registry function doesn't try to update the object which just updated
- % the registry! (Similarly, the handle of the registry object, hReg, is
- % passed to the handling function during forward XYZ updating, so that the
- % handling function's 'SetCoords' facility can be constructed to accept XYZ
- % updates from various sources, and only inform the registry if not called
- % by the registry, and hence avoid circularities.)
- %
- % A framework is provided for "back" registration. Really all that is
- % required is that the GUI controls know of the registry object (via it's
- % handle hReg), and call the registry's 'SetCoords' facility when
- % necessary. This can be done in many ways, but a simple structure is
- % provided, mirroring that of the registry's operation. This framework
- % assummes that the GUI controls identification object's 'UserData' is a
- % structure with a field named 'hReg', which stores the handle of the
- % registry (if back registered), or is empty (if not back registered, i.e.
- % standalone). spm_XYZreg provides utility functions for setting/unsetting
- % this field, and for "cross registering" - that is both forward and back
- % registration in one command. Cross registering involves adding the
- % handle/function pair to the registry, and setting the registry handle in
- % the GUI control object's 'UserData' 'hReg' field. It's up to the handling
- % function to read the registry handle from it's objects 'UserData' and act
- % accordingly. A simple example of such a function is provided in
- % spm_XYZreg_Ex2.m, illustrated below.
- %
- % SubFunctions are provided for getting and setting the current
- % coordinates; adding and deleting handle/function pairs from the registry
- % (forward registration and un-registration), setting and removing registry
- % handle information from the 'hReg' field of the 'UserData' of a HG object
- % (backward registration & un-registration); cross registration and
- % unregistration (including pushing of current coordinates); setting and
- % getting the current XYZ location. See the FORMAT statements and the
- % example below...
- %
- % ----------------
- % EXAMPLE
- %
- % %-Create a window:
- % F = figure;
- % %-Create an object to hold the registry
- % hReg = uicontrol(F,'Style','Text','String','hReg',...
- % 'Position',[100 200 100 025],...
- % 'FontName','Times','FontSize',14,'FontWeight','Bold',...
- % 'HorizontalAlignment','Center');
- % %-Setup M & D
- % V = [65;87;26;02;02;04;33;53;08];
- % M = [ [diag(V(4:6)), -(V(7:9).*V(4:6))]; [zeros(1,3) ,1]];
- % D = V(1:3);
- % %-Initialise a registry in this object, with initial coordinates [0;0;0]
- % spm_XYZreg('InitReg',hReg,M,D,[0;0;0])
- % % (ans returns [0;0;0] confirming current coordinates
- % %-Set coordinates to [10;10;10]
- % spm_XYZreg('SetCoords',[10,10,10],hReg)
- % % (warns of coordinate rounding to [10,10,12], & returns ans as [10;10;12])
- %
- % %-Forward register a command window xyz reporting function: spm_XYZreg_Ex1.m
- % spm_XYZreg('Add2Reg',hReg,0,'spm_XYZreg_Ex1')
- % % (ans returns new registry, containing just this handle/function pair
- % %-Set coordinates to [0;10;12]
- % [xyz,d] = spm_XYZreg('SetCoords',[0,10,12],hReg);
- % % (spm_XYZreg_Ex1 called, and prints coordinates and handles)
- % %-Have a peek at the registry information
- % RD = get(hReg,'UserData')
- % RD.xyz %-The current point according to the registry
- % RD.Reg %-The nx2 cell array of handle/function pairs
- %
- % %-Create an example GUI XYZ control, using spm_XYZreg_Ex2.m
- % hB = spm_XYZreg_Ex2('Create',M,D,xyz);
- % % (A figure window with a button appears, whose label shows the current xyz
- % %-Press the button, and enter new coordinates [0;0;0] in the Cmd window...
- % % (...the button's internal notion of the current location is changed, but
- % % (the registry isn't informed:
- % spm_XYZreg('GetCoords',hReg)
- % (...returns [0;10;12])
- % %-"Back" register the button
- % spm_XYZreg('SetReg',hB,hReg)
- % %-Check the back registration
- % if ( hReg == getfield(get(hB,'UserData'),'hReg') ), disp('yes!'), end
- % %-Now press the button, and enter [0;0;0] again...
- % % (...this time the registry is told, and the registry tells spm_XYZreg_Ex1,
- % % (which prints out the new coordinates!
- % %-Forward register the button to receive updates from the registry
- % nReg = spm_XYZreg('Add2Reg',hReg,hB,'spm_XYZreg_Ex2')
- % % (The new registry is returned as nReg, showing two entries
- % %-Set new registry coordinates to [10;10;12]
- % [xyz,d] = spm_XYZreg('SetCoords',[10;10;12],hReg);
- % % (...the button updates too!
- %
- % %-Illustration of robustness: Delete the button & use the registry
- % delete(hB)
- % [xyz,d] = spm_XYZreg('SetCoords',[10;10;12],hReg);
- % % (...the invalid handle hB in the registry is ignored)
- % %-Peek at the registry
- % getfield(get(hReg,'UserData'),'Reg')
- % %-Delete hB from the registry by "cleaning"
- % spm_XYZreg('CleanReg',hReg)
- % % (...it's gone
- %
- % %-Make a new button and cross register
- % hB = spm_XYZreg_Ex2('Create',M,D)
- % % (button created with default coordinates of [0;0;0]
- % nReg = spm_XYZreg('XReg',hReg,hB,'spm_XYZreg_Ex2')
- % % (Note that the registry pushes the current coordinates to the button
- % %-Use the button & spm_XYZreg('SetCoords'... at will!
- %==========================================================================
- switch lower(varargin{1}), case 'roundcoords'
- %==========================================================================
- % [xyz,d] = spm_XYZreg('RoundCoords',xyz,M,D)
- % [xyz,d] = spm_XYZreg('RoundCoords',xyz,V)
- if nargin<3, error('Insufficient arguments'), end
- if nargin<4
- V = varargin{3};
- M = [ [diag(V(4:6)), -(V(7:9).*V(4:6))]; [zeros(1,3) ,1]];
- D = V(1:3);
- else
- M = varargin{3};
- D = varargin{4};
- end
- %-Round xyz to coordinates of actual voxel centre
- %-Do rounding in voxel coordinates & ensure within image size
- %-Watch out for infinities!
- %--------------------------------------------------------------------------
- xyz = [varargin{2}(:); 1];
- xyz(isinf(xyz)) = 1e10*sign(xyz(isinf(xyz)));
- rcp = round(M\xyz);
- rcp = max([min([rcp';[D',1]]);[1,1,1,1]])';
- rxyz = M*rcp;
- %-Work out Euclidean distance between points xyz & rounded xyz
- d = sqrt(sum((xyz-rxyz).^2));
- varargout = {rxyz(1:3),d};
- %==========================================================================
- case 'findxyz'
- %==========================================================================
- % i = spm_XYZreg('FindXYZ',xyz,XYZ)
- if nargin<3, error('Insufficient arguments'), end
- XYZ = varargin{3};
- xyz = varargin{2};
- %-Find XYZ = xyz
- %--------------------------------------------------------------------------
- i = find(all([XYZ(1,:)==xyz(1);XYZ(2,:)==xyz(2);XYZ(3,:)==xyz(3)],1));
- varargout = {i};
- %==========================================================================
- case 'nearestxyz'
- %==========================================================================
- % [xyz,i,d] = spm_XYZreg('NearestXYZ',xyz,XYZ)
- if nargin<3, error('Insufficient arguments'), end
- %-Find in XYZ nearest point to coordinates xyz (Euclidean distance)
- %--------------------------------------------------------------------------
- [d,i] = min(spm_XYZreg('Edist',varargin{2},varargin{3}));
- varargout = {varargin{3}(:,i),i,d};
- %==========================================================================
- case 'edist'
- %==========================================================================
- % d = spm_XYZreg('Edist',xyz,XYZ)
- if nargin<3, error('Insufficient arguments'), end
- %-Calculate (Euclidean) distances from pointlist coords to xyz
- %--------------------------------------------------------------------------
- varargout = {sqrt(sum([ (varargin{3}(1,:) - varargin{2}(1));...
- (varargin{3}(2,:) - varargin{2}(2));...
- (varargin{3}(3,:) - varargin{2}(3)) ].^2))};
- %==========================================================================
- case 'initreg' % Initialise registry in handle h
- %==========================================================================
- % [hReg,xyz] = spm_XYZreg('InitReg',hReg,M,D,xyz)
- if nargin<5, xyz=[0;0;0]; else xyz=varargin{5}; end
- if nargin<4, error('Insufficient arguments'), end
- D = varargin{4};
- M = varargin{3};
- hReg = varargin{2};
- %-Check availability of hReg object for building a registry in
- %--------------------------------------------------------------------------
- if ~isempty(get(hReg,'UserData')), error('Object already has UserData...'), end
- if ~isempty(get(hReg,'Tag')), error('Object already ''Tag''ed...'), end
- %-Check coordinates are in range
- %--------------------------------------------------------------------------
- [xyz,d] = spm_XYZreg('RoundCoords',xyz,M,D);
- if d>0 && nargout<2
- warning('Coordinates rounded to nearest voxel center: Discrepancy %.2f',d);
- end
- %-Set up registry
- %--------------------------------------------------------------------------
- RD = struct('xyz',xyz,'M',M,'D',D,'Reg',[]);
- RD.Reg = {};
- set(hReg,'Tag','hReg','UserData',RD)
- %-Return current coordinates
- %--------------------------------------------------------------------------
- varargout = {hReg,xyz};
- %==========================================================================
- case 'uninitreg' % UnInitialise registry in handle hReg
- %==========================================================================
- % spm_XYZreg('UnInitReg',hReg)
- hReg = varargin{2};
- if ~strcmp(get(hReg,'Tag'),'hReg'), warning('Not an XYZ registry'), return, end
- set(hReg,'Tag','','UserData',[])
- %==========================================================================
- case 'getcoords' % Get current coordinates
- %=========================================================================
- % xyz = spm_XYZreg('GetCoords',hReg)
- if nargin<2, hReg=spm_XYZreg('FindReg'); else hReg=varargin{2}; end
- if ~ishandle(hReg), error('Invalid object handle'), end
- if ~strcmp(get(hReg,'Tag'),'hReg'), error('Not a registry'), end
- varargout = {getfield(get(hReg,'UserData'),'xyz')};
- %==========================================================================
- case 'setcoords' % Set coordinates & update registered functions
- %==========================================================================
- % [xyz,d] = spm_XYZreg('SetCoords',xyz,hReg,hC,Reg)
- % d returned empty if didn't check, warning printed if d not asked for & round
- % Don't check if callerhandle specified (speed)
- % If Registry cell array Reg is specified, then only these handles are updated
- hC = NaN;
- if nargin>=4
- if ~ischar(varargin{4}), hC=varargin{4}; end
- end
- hReg = varargin{3};
- %-Check validity of hReg registry handle
- %--------------------------------------------------------------------------
- %-Return if hReg empty, in case calling objects functions don't check isempty
- if isempty(hReg), return, end
- %-Check validity of hReg registry handle, correct calling objects if necc.
- if ~ishandle(hReg)
- str = sprintf('%s: Invalid registry handle (%.4f)',mfilename,hReg);
- if ishandle(hC)
- %-Remove hReg from caller
- spm_XYZreg('SetReg',hC,[])
- str = [str,sprintf('\n\t\t\t...removed from caller (%.4f)',hC)];
- end
- warning(str)
- return
- end
- xyz = varargin{2};
- RD = get(hReg,'UserData');
- %-Check validity of coords only when called without a caller handle
- %--------------------------------------------------------------------------
- if ~ishandle(hC)
- [xyz,d] = spm_XYZreg('RoundCoords',xyz,RD.M,RD.D);
- if d>0 && nargout<2
- warning('Coordinates rounded to nearest voxel center: Discrepancy %.2f',d);
- end
- else
- d = 0;
- end
- %-Sort out valid handles, eliminate caller handle, update coords with
- % registered handles via their functions
- %--------------------------------------------------------------------------
- if nargin<5
- RD.Reg = spm_XYZreg('VReg',RD.Reg);
- Reg = RD.Reg;
- else
- Reg = spm_XYZreg('VReg',varargin{5});
- end
- if ishandle(hC) && ~isempty(Reg), Reg([Reg{:,1}]==varargin{4},:) = []; end
- for i = 1:size(Reg,1)
- feval(Reg{i,2},'SetCoords',xyz,Reg{i,1},hReg);
- end
- %-Update registry (if using hReg) with location & cleaned Reg cellarray
- %--------------------------------------------------------------------------
- if nargin<5
- RD.xyz = xyz;
- set(hReg,'UserData',RD)
- end
- varargout = {xyz,d};
- %==========================================================================
- case 'xreg' % Cross register object handles & functions
- %=========================================================================
- % nReg = spm_XYZreg('XReg',hReg,{h,Fcn}pairs)
- if nargin<4, error('Insufficient arguments'), end
- hReg = varargin{2};
- %-Quick check of registry handle
- %--------------------------------------------------------------------------
- if isempty(hReg), warning('Empty registry handle'), return, end
- if ~ishandle(hReg), warning('Invalid registry handle'), return, end
- %-Condition nReg cell array & check validity of handles to be registered
- %--------------------------------------------------------------------------
- nReg = varargin(3:end);
- if mod(length(nReg),2), error('Registry items must be in pairs'), end
- if length(nReg)>2, nReg = reshape(nReg,length(nReg)/2,2)'; end
- nReg = spm_XYZreg('VReg',nReg,'Warn');
- %-Set hReg registry link for registry candidates (Back registration)
- %--------------------------------------------------------------------------
- for i = 1:size(nReg,1)
- spm_XYZreg('SetReg',nReg{i,1},hReg);
- end
- %-Append registry candidates to existing registry & write back to hReg
- %--------------------------------------------------------------------------
- RD = get(hReg,'UserData');
- Reg = RD.Reg;
- Reg = cat(1,Reg,nReg);
- RD.Reg = Reg;
- set(hReg,'UserData',RD)
- %-Synch coordinates of newly registered objects
- %--------------------------------------------------------------------------
- spm_XYZreg('SetCoords',RD.xyz,hReg,hReg,nReg);
- varargout = {Reg};
- %==========================================================================
- case 'add2reg' % Add handle(s) & function(s) to registry
- %==========================================================================
- % nReg = spm_XYZreg('Add2Reg',hReg,{h,Fcn}pairs)
- if nargin<4, error('Insufficient arguments'), end
- hReg = varargin{2};
- %-Quick check of registry handle
- %--------------------------------------------------------------------------
- if isempty(hReg), warning('Empty registry handle'), return, end
- if ~ishandle(hReg), warning('Invalid registry handle'), return, end
- %-Condition nReg cell array & check validity of handles to be registered
- %--------------------------------------------------------------------------
- nReg = varargin(3:end);
- if mod(length(nReg),2), error('Registry items must be in pairs'), end
- if length(nReg)>2, nReg = reshape(nReg,length(nReg)/2,2)'; end
- nReg = spm_XYZreg('VReg',nReg,'Warn');
- %-Append to existing registry & put back in registry object
- %--------------------------------------------------------------------------
- RD = get(hReg,'UserData');
- Reg = RD.Reg;
- Reg = cat(1,Reg,nReg);
- RD.Reg = Reg;
- set(hReg,'UserData',RD)
- varargout = {Reg};
- %==========================================================================
- case 'setreg' %-Set registry field of object's UserData
- %==========================================================================
- % spm_XYZreg('SetReg',h,hReg)
- if nargin<3, error('Insufficient arguments'), end
- h = varargin{2};
- hReg = varargin{3};
- if ( ~ishandle(h) || h==0 ), return, end
- UD = get(h,'UserData');
- if ~isstruct(UD) || ~any(strcmp(fieldnames(UD),'hReg'))
- error('No UserData structure with hReg field for this object')
- end
- UD.hReg = hReg;
- set(h,'UserData',UD)
- %==========================================================================
- case 'unxreg' % Un-cross register object handles & functions
- %==========================================================================
- % nReg = spm_XYZreg('unXReg',hReg,hD1,hD2,hD3,...)
- if nargin<3, error('Insufficient arguments'), end
- hD = [varargin{3:end}];
- hReg = varargin{2};
- %-Get Registry information
- %--------------------------------------------------------------------------
- RD = get(hReg,'UserData');
- Reg = RD.Reg;
- %-Find registry entires to delete
- %--------------------------------------------------------------------------
- [c,i,e] = intersect([Reg{:,1}],hD);
- hD(e) = [];
- dReg = spm_XYZreg('VReg',Reg(i,:));
- Reg(i,:) = [];
- if ~isempty(hD), warning('Not all handles were in registry'), end
- %-Write back new registry
- %--------------------------------------------------------------------------
- RD.Reg = Reg;
- set(hReg,'UserData',RD)
- %-UnSet hReg registry link for hD's still existing (Back un-registration)
- %--------------------------------------------------------------------------
- for i = 1:size(dReg,1)
- spm_XYZreg('SetReg',dReg{i,1},[]);
- end
- varargout = {Reg};
- %==========================================================================
- case 'del2reg' % Delete handle(s) & function(s) from registry
- %==========================================================================
- % nReg = spm_XYZreg('Del2Reg',hReg,hD)
- if nargin<3, error('Insufficient arguments'), end
- hD = [varargin{3:end}];
- hReg = varargin{2};
- %-Get Registry information
- %--------------------------------------------------------------------------
- RD = get(hReg,'UserData');
- Reg = RD.Reg;
- %-Find registry entires to delete
- %--------------------------------------------------------------------------
- [c,i,e] = intersect([Reg{:,1}],hD);
- Reg(i,:) = [];
- hD(e) = [];
- if ~isempty(hD), warning('Not all handles were in registry'), end
- %-Write back new registry
- %--------------------------------------------------------------------------
- RD.Reg = Reg;
- set(hReg,'UserData',RD)
- varargout = {Reg};
- %==========================================================================
- case 'unsetreg' %-Unset registry field of object's UserData
- %==========================================================================
- % spm_XYZreg('UnSetReg',h)
- if nargin<2, error('Insufficient arguments'), end
- spm_XYZreg('SetReg',varargin{2},[])
- %==========================================================================
- case 'cleanreg' % Clean invalid handles from registry
- %==========================================================================
- % spm_XYZreg('CleanReg',hReg)
- %if ~strcmp(get(hReg,'Tag'),'hReg'), error('Not a registry'), end
- hReg = varargin{2};
- RD = get(hReg,'UserData');
- RD.Reg = spm_XYZreg('VReg',RD.Reg,'Warn');
- set(hReg,'UserData',RD)
- %==========================================================================
- case 'vreg' % Prune invalid handles from registry cell array
- %==========================================================================
- % Reg = spm_XYZreg('VReg',Reg,Warn)
- if nargin<3, Warn=0; else Warn=1; end
- Reg = varargin{2};
- if isempty(Reg), varargout={Reg}; return, end
- i = [];
- for h=1:size(Reg,1)
- if ~ishghandle(Reg{h,1}), i = [i h]; end
- end
- %-***check existence of handling functions : exist('','file')?
- if Warn && ~isempty(i)
- warning('Disregarding invalid registry handles:\n\t%.4f',Reg{i,1});
- end
- Reg(i,:) = [];
- varargout = {Reg};
- %==========================================================================
- case 'findreg' % Find/check registry object
- %==========================================================================
- % hReg = spm_XYZreg('FindReg',h)
- if nargin<2, h=get(0,'CurrentFigure'); else h=varargin{2}; end
- if ischar(h), h=spm_figure('FindWin',h); end
- if ~ishandle(h), error('invalid handle'), end
- if ~strcmp(get(h,'Tag'),'hReg'), h=findobj(h,'Tag','hReg'); end
- if isempty(h), error('Registry object not found'), end
- if length(h)>1, error('Multiple registry objects found'), end
- varargout = {h};
- %==========================================================================
- otherwise
- %==========================================================================
- error('Unknown action string')
- %==========================================================================
- end
|