spm_XYZreg.m 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742
  1. function varargout = spm_XYZreg(varargin)
  2. % Registry for GUI XYZ locations, and point list utility functions
  3. %
  4. % ----------------
  5. %
  6. % PointList & voxel centre utilities...
  7. %
  8. % FORMAT [xyz,d] = spm_XYZreg('RoundCoords',xyz,M,D)
  9. % FORMAT [xyz,d] = spm_XYZreg('RoundCoords',xyz,V)
  10. % Round specified xyz location to nearest voxel centre
  11. % xyz - (Input) 3-vector of X, Y & Z locations, in "real" coordinates
  12. % M - 4x4 transformation matrix relating voxel to "real" coordinates
  13. % D - 3 vector of image X, Y & Z dimensions (DIM)
  14. % V - 9-vector of image and voxel sizes, and origin [DIM,VOX,ORIGIN]'
  15. % M derived as [ [diag(V(4:6)), -(V(7:9).*V(4:6))]; [zeros(1,3) ,1]]
  16. % DIM - D
  17. % VOX - Voxel dimensions in units of "real" coordinates
  18. % ORIGIN - Origin of "real" coordinates in voxel coordinates
  19. % xyz - (Output) coordinates of nearest voxel centre in "real" coordinates
  20. % d - Euclidean distance between requested xyz & nearest voxel centre
  21. %
  22. % FORMAT i = spm_XYZreg('FindXYZ',xyz,XYZ)
  23. % find position of specified voxel in XYZ pointlist
  24. % xyz - 3-vector of coordinates
  25. % XYZ - Pointlist: 3xn matrix of coordinates
  26. % i - Column(s) of XYZ equal to xyz
  27. %
  28. % FORMAT [xyz,i,d] = spm_XYZreg('NearestXYZ',xyz,XYZ)
  29. % find nearest voxel in pointlist to specified location
  30. % xyz - (Input) 3-vector of coordinates
  31. % XYZ - Pointlist: 3xn matrix of coordinates
  32. % xyz - (Output) coordinates of nearest voxel in XYZ pointlist
  33. % (ties are broken in favour of the first location in the pointlist)
  34. % i - Column of XYZ containing coordinates of nearest pointlist location
  35. % d - Euclidean distance between requested xyz & nearest pointlist location
  36. %
  37. % FORMAT d = spm_XYZreg('Edist',xyz,XYZ)
  38. % Euclidean distances between coordinates xyz & points in XYZ pointlist
  39. % xyz - 3-vector of coordinates
  40. % XYZ - Pointlist: 3xn matrix of coordinates
  41. % d - n row-vector of Euclidean distances between xyz & points of XYZ
  42. %
  43. % ----------------
  44. %
  45. % Registry functions
  46. %
  47. % FORMAT [hReg,xyz] = spm_XYZreg('InitReg',hReg,M,D,xyz)
  48. % Initialise registry in graphics object
  49. % hReg - Handle of HandleGraphics object to build registry in. Object must
  50. % be un'Tag'ged and have empty 'UserData'
  51. % M - 4x4 transformation matrix relating voxel to "real" coordinates,
  52. % used and stored for checking validity of coordinates
  53. % D - 3 vector of image X, Y & Z dimensions (DIM), used
  54. % and stored for checking validity of coordinates
  55. % xyz - (Input) Initial coordinates [Default [0;0;0]]
  56. % These are rounded to the nearest voxel centre
  57. % hReg - (Output) confirmation of registry handle
  58. % xyz - (Output) Current registry coordinates, after rounding
  59. %
  60. % FORMAT spm_XYZreg('UnInitReg',hReg)
  61. % Clear registry information from graphics object
  62. % hReg - Handle of 'hReg' 'Tag'ged registry HandleGraphics object.
  63. % Object's 'Tag' & 'UserData' are cleared
  64. %
  65. % FORMAT xyz = spm_XYZreg('GetCoords',hReg)
  66. % Get current registry coordinates
  67. % hReg - Handle of 'hReg' 'Tag'ged registry HandleGraphics object
  68. %
  69. % FORMAT [xyz,d] = spm_XYZreg('SetCoords',xyz,hReg,hC,Reg)
  70. % Set coordinates in registry & update registered HGobjects/functions
  71. % xyz - (Input) desired coordinates
  72. % hReg - Handle of 'hReg' 'Tag'ged registry HandleGraphics object
  73. % If hReg doesn't contain a registry, a warning is printed.
  74. % hC - Handle of caller object (to prevent circularities) [Default 0]
  75. % If caller object passes invalid registry handle, then spm_XYZreg
  76. % attempts to blank the 'hReg' fiend of hC's 'UserData', printing
  77. % a warning notification.
  78. % Reg - Alternative nx2 cell array Registry of handles / functions
  79. % If specified, overrides use of registry held in hReg
  80. % [Default getfield(get(hReg,'UserData'),'Reg')]
  81. % xyz - (Output) Desired coordinates are rounded to nearest voxel if hC
  82. % is not specified, or is zero. Otherwise, caller is assummed to
  83. % have checked verity of desired xyz coordinates. Output xyz
  84. % returns coordinates actually set.
  85. % d - Euclidean distance between desired and set coordinates.
  86. %
  87. % FORMAT nReg = spm_XYZreg('XReg',hReg,{h,Fcn}pairs)
  88. % Cross registration object/function pairs with the registry, push xyz coords
  89. % hReg - Handle of 'hReg' 'Tag'ged registry HandleGraphics object
  90. % h - Handle of HandleGraphics object to be registered
  91. % The 'UserData' of h must be a structure with an 'Reg' field, which
  92. % is set to hReg, the handle of the registry (back registration)
  93. % Fcn - Handling function for HandleGraphics object h
  94. % This function *must* accept XYZ updates via the call:
  95. % feval(Fcn,'SetCoords',xyz,h,hReg)
  96. % and should *not* call back the registry with the update!
  97. % {h,Fcn} are appended to the registry (forward registration)
  98. % nReg - New registry cell array: Handles are checked for validity before
  99. % entry. Invalid handles are omitted, generating a warning.
  100. %
  101. % FORMAT nReg = spm_XYZreg('Add2Reg',hReg,{h,Fcn}pairs)
  102. % Add object/function pairs for XYZ updates to registry (forward registration)
  103. % hReg - Handle of 'hReg' 'Tag'ged registry HandleGraphics object
  104. % h - Handle of HandleGraphics object to be registered
  105. % Fcn - Handling function for HandleGraphics object h
  106. % This function *must* accept XYZ updates via the call:
  107. % feval(Fcn,'SetCoords',xyz,h,hReg)
  108. % and should *not* call back the registry with the update!
  109. % {h,Fcn} are appended to the registry (forward registration)
  110. % nReg - New registry cell array: Handles are checked for validity before
  111. % entry. Invalid handles are omitted, generating a warning.
  112. %
  113. % FORMAT spm_XYZreg('SetReg',h,hReg)
  114. % Set registry field of object's UserData (back registration)
  115. % h - Handle of HandleGraphics object to be registered
  116. % The 'UserData' of h must be a structure with an 'Reg' field, which
  117. % is set to hReg, the handle of the registry (back registration)
  118. % hReg - Handle of 'hReg' 'Tag'ged registry HandleGraphics object
  119. %
  120. % FORMAT nReg = spm_XYZreg('unXReg',hReg,hD1,hD2,hD3,...)
  121. % Un-cross registration of HandleGraphics object hD
  122. % hReg - Handle of 'hReg' 'Tag'ged registry HandleGraphics object
  123. % hD? - Handles of HandleGraphics object to be unregistered
  124. % The 'UserData' of hD must be a structure with a 'Reg' field, which
  125. % is set to empty (back un-registration)
  126. % nReg - New registry cell array: Registry entries with handle entry hD are
  127. % removed from the registry (forward un-registration)
  128. % Handles not in the registry generate a warning
  129. %
  130. % FORMAT nReg = spm_XYZreg('Del2Reg',hReg,hD)
  131. % Delete HandleGraphics object hD from registry (forward un-registration)
  132. % hReg - Handle of 'hReg' 'Tag'ged registry HandleGraphics object
  133. % hD? - Handles of HandleGraphics object to be unregistered
  134. % nReg - New registry cell array: Registry entries with handle entry hD are
  135. % removed from the registry. Handles not in registry generate a warning
  136. %
  137. % FORMAT spm_XYZreg('UnSetReg',h)
  138. % Unset registry field of object's UserData (back un-registration)
  139. % h - Handle of HandleGraphics object to be unregistered
  140. % The 'UserData' of hD must be a structure with a 'Reg' field, which
  141. % is set to empty (back un-registration)
  142. %
  143. % FORMAT spm_XYZreg('CleanReg',hReg)
  144. % Clean invalid handles from registry
  145. % hReg - Handle of 'hReg' 'Tag'ged registry HandleGraphics object
  146. %
  147. % FORMAT Reg = spm_XYZreg('VReg',Reg,Warn)
  148. % Prune invalid handles from Registry cell array
  149. % Reg - (Input) nx2 cell array of {handle,function} pairs
  150. % Warn - If specified, print warning if find invalid handles
  151. % Reg - (Output) mx2 cell array of valid {handle,function} pairs
  152. %
  153. % FORMAT hReg = spm_XYZreg('FindReg',h)
  154. % Find/check registry object
  155. % h - handle of Registry, or figure containing Registry (default gcf)
  156. % If ischar(h), then uses spm_figure('FindWin',h) to locate named figures
  157. % hReg - handle of confirmed registry object
  158. % Errors if h is not a registry or a figure containing a unique registry
  159. % Registry object is identified by 'hReg' 'Tag'
  160. %__________________________________________________________________________
  161. %
  162. % spm_XYZreg provides a framework for modular inter-GUI communication of
  163. % XYZ co-orginates, and various utility functions for pointlist handling
  164. % and rounding in voxel coordinates.
  165. % Concept and examples can be found in the body of the function.
  166. %__________________________________________________________________________
  167. % Copyright (C) 1999-2018 Wellcome Trust Centre for Neuroimaging
  168. % Andrew Holmes, Chloe Hutton
  169. % $Id: spm_XYZreg.m 7388 2018-08-06 12:04:26Z guillaume $
  170. % THE REGISTRY
  171. %
  172. % The concept of the registry is of a central entity which "knows" about
  173. % other GUI objects holding XYZ coordinates, and keeps them all in sync.
  174. % Changes to the registry's XYZ coordinates are passed on to registered
  175. % functions by the registry (forward registration). Individual objects
  176. % which can change the XYZ coordinates should therefore update the
  177. % registry with the new coordinates (back registration), so that the
  178. % registry can tell all registered objects about the new location, and a
  179. % framework is provided for this.
  180. %
  181. % The registry is held as the 'UserData of a HandleGraphics object, whose
  182. % handle therefore identifies the registry. The registry object is 'Tag'ged
  183. % 'hReg' for identification (though this 'Tag' is not used for locating the
  184. % registry, so multiple registry incarnations are possible). The registry
  185. % object's 'UserData' is a structure containing the current XYZ
  186. % coordinates, the voxel-to-coordinates matrix M, the image dimensions D,
  187. % and the Registry itself. The registry is a nx2 cell array containing n
  188. % handle/function pairs.
  189. %
  190. % The model is that all GUI objects requiring linking to a common XYZ
  191. % location via the registry each be identified by a HandleGraphics handle.
  192. % This handle can be the handle of the particular instantiation of the GUI
  193. % control itself (as is the case with the MIP-GUI of spm_mip_ui where the
  194. % axis handle is used to identify the MIP to use); the handle of another
  195. % HandleGraphics object associated with the GUI control (as is the case
  196. % with the XYZ editable widgets of spm_results_ui where the handle of the
  197. % bounding frame uicontrol is used); or may be 0, the handle of the root
  198. % object, which allows non GUI functions (such as a function that just
  199. % prints information) to be added to the registry. The registry itself thus
  200. % conforms to this model. Each object has an associated "handling function"
  201. % (so this function is the registry's handling function). The registry
  202. % itself consists of object-handle/handling-function pairs.
  203. %
  204. % If an object and it's handling function are entered in the registry, then
  205. % the object is said to be "forward registered", because the registry will
  206. % now forward all location updates to that object, via it's handling
  207. % function. The assummed syntax is: feval(Fcn,'SetCoords',xyz,h,hReg),
  208. % where Fcn is the handling function for the GUI control identified by
  209. % handle h, xyz are the new coordinates, and hReg is the handle of the
  210. % registry.
  211. %
  212. % An optional extension is "back registration", whereby the GUI controls
  213. % inform the registry of the new location when they are updated. All that's
  214. % required is that the objects call the registry's 'SetCoords' function:
  215. % spm_XYZreg('SetCoords',xyz,hReg,hC), where hReg is the registry object's
  216. % handle, and hC is the handle associated with the calling GUI control. The
  217. % specification of the caller GUI control allows the registry to avoid
  218. % circularities: If the object is "forward registered" for updates, then
  219. % the registry function doesn't try to update the object which just updated
  220. % the registry! (Similarly, the handle of the registry object, hReg, is
  221. % passed to the handling function during forward XYZ updating, so that the
  222. % handling function's 'SetCoords' facility can be constructed to accept XYZ
  223. % updates from various sources, and only inform the registry if not called
  224. % by the registry, and hence avoid circularities.)
  225. %
  226. % A framework is provided for "back" registration. Really all that is
  227. % required is that the GUI controls know of the registry object (via it's
  228. % handle hReg), and call the registry's 'SetCoords' facility when
  229. % necessary. This can be done in many ways, but a simple structure is
  230. % provided, mirroring that of the registry's operation. This framework
  231. % assummes that the GUI controls identification object's 'UserData' is a
  232. % structure with a field named 'hReg', which stores the handle of the
  233. % registry (if back registered), or is empty (if not back registered, i.e.
  234. % standalone). spm_XYZreg provides utility functions for setting/unsetting
  235. % this field, and for "cross registering" - that is both forward and back
  236. % registration in one command. Cross registering involves adding the
  237. % handle/function pair to the registry, and setting the registry handle in
  238. % the GUI control object's 'UserData' 'hReg' field. It's up to the handling
  239. % function to read the registry handle from it's objects 'UserData' and act
  240. % accordingly. A simple example of such a function is provided in
  241. % spm_XYZreg_Ex2.m, illustrated below.
  242. %
  243. % SubFunctions are provided for getting and setting the current
  244. % coordinates; adding and deleting handle/function pairs from the registry
  245. % (forward registration and un-registration), setting and removing registry
  246. % handle information from the 'hReg' field of the 'UserData' of a HG object
  247. % (backward registration & un-registration); cross registration and
  248. % unregistration (including pushing of current coordinates); setting and
  249. % getting the current XYZ location. See the FORMAT statements and the
  250. % example below...
  251. %
  252. % ----------------
  253. % EXAMPLE
  254. %
  255. % %-Create a window:
  256. % F = figure;
  257. % %-Create an object to hold the registry
  258. % hReg = uicontrol(F,'Style','Text','String','hReg',...
  259. % 'Position',[100 200 100 025],...
  260. % 'FontName','Times','FontSize',14,'FontWeight','Bold',...
  261. % 'HorizontalAlignment','Center');
  262. % %-Setup M & D
  263. % V = [65;87;26;02;02;04;33;53;08];
  264. % M = [ [diag(V(4:6)), -(V(7:9).*V(4:6))]; [zeros(1,3) ,1]];
  265. % D = V(1:3);
  266. % %-Initialise a registry in this object, with initial coordinates [0;0;0]
  267. % spm_XYZreg('InitReg',hReg,M,D,[0;0;0])
  268. % % (ans returns [0;0;0] confirming current coordinates
  269. % %-Set coordinates to [10;10;10]
  270. % spm_XYZreg('SetCoords',[10,10,10],hReg)
  271. % % (warns of coordinate rounding to [10,10,12], & returns ans as [10;10;12])
  272. %
  273. % %-Forward register a command window xyz reporting function: spm_XYZreg_Ex1.m
  274. % spm_XYZreg('Add2Reg',hReg,0,'spm_XYZreg_Ex1')
  275. % % (ans returns new registry, containing just this handle/function pair
  276. % %-Set coordinates to [0;10;12]
  277. % [xyz,d] = spm_XYZreg('SetCoords',[0,10,12],hReg);
  278. % % (spm_XYZreg_Ex1 called, and prints coordinates and handles)
  279. % %-Have a peek at the registry information
  280. % RD = get(hReg,'UserData')
  281. % RD.xyz %-The current point according to the registry
  282. % RD.Reg %-The nx2 cell array of handle/function pairs
  283. %
  284. % %-Create an example GUI XYZ control, using spm_XYZreg_Ex2.m
  285. % hB = spm_XYZreg_Ex2('Create',M,D,xyz);
  286. % % (A figure window with a button appears, whose label shows the current xyz
  287. % %-Press the button, and enter new coordinates [0;0;0] in the Cmd window...
  288. % % (...the button's internal notion of the current location is changed, but
  289. % % (the registry isn't informed:
  290. % spm_XYZreg('GetCoords',hReg)
  291. % (...returns [0;10;12])
  292. % %-"Back" register the button
  293. % spm_XYZreg('SetReg',hB,hReg)
  294. % %-Check the back registration
  295. % if ( hReg == getfield(get(hB,'UserData'),'hReg') ), disp('yes!'), end
  296. % %-Now press the button, and enter [0;0;0] again...
  297. % % (...this time the registry is told, and the registry tells spm_XYZreg_Ex1,
  298. % % (which prints out the new coordinates!
  299. % %-Forward register the button to receive updates from the registry
  300. % nReg = spm_XYZreg('Add2Reg',hReg,hB,'spm_XYZreg_Ex2')
  301. % % (The new registry is returned as nReg, showing two entries
  302. % %-Set new registry coordinates to [10;10;12]
  303. % [xyz,d] = spm_XYZreg('SetCoords',[10;10;12],hReg);
  304. % % (...the button updates too!
  305. %
  306. % %-Illustration of robustness: Delete the button & use the registry
  307. % delete(hB)
  308. % [xyz,d] = spm_XYZreg('SetCoords',[10;10;12],hReg);
  309. % % (...the invalid handle hB in the registry is ignored)
  310. % %-Peek at the registry
  311. % getfield(get(hReg,'UserData'),'Reg')
  312. % %-Delete hB from the registry by "cleaning"
  313. % spm_XYZreg('CleanReg',hReg)
  314. % % (...it's gone
  315. %
  316. % %-Make a new button and cross register
  317. % hB = spm_XYZreg_Ex2('Create',M,D)
  318. % % (button created with default coordinates of [0;0;0]
  319. % nReg = spm_XYZreg('XReg',hReg,hB,'spm_XYZreg_Ex2')
  320. % % (Note that the registry pushes the current coordinates to the button
  321. % %-Use the button & spm_XYZreg('SetCoords'... at will!
  322. %==========================================================================
  323. switch lower(varargin{1}), case 'roundcoords'
  324. %==========================================================================
  325. % [xyz,d] = spm_XYZreg('RoundCoords',xyz,M,D)
  326. % [xyz,d] = spm_XYZreg('RoundCoords',xyz,V)
  327. if nargin<3, error('Insufficient arguments'), end
  328. if nargin<4
  329. V = varargin{3};
  330. M = [ [diag(V(4:6)), -(V(7:9).*V(4:6))]; [zeros(1,3) ,1]];
  331. D = V(1:3);
  332. else
  333. M = varargin{3};
  334. D = varargin{4};
  335. end
  336. %-Round xyz to coordinates of actual voxel centre
  337. %-Do rounding in voxel coordinates & ensure within image size
  338. %-Watch out for infinities!
  339. %--------------------------------------------------------------------------
  340. xyz = [varargin{2}(:); 1];
  341. xyz(isinf(xyz)) = 1e10*sign(xyz(isinf(xyz)));
  342. rcp = round(M\xyz);
  343. rcp = max([min([rcp';[D',1]]);[1,1,1,1]])';
  344. rxyz = M*rcp;
  345. %-Work out Euclidean distance between points xyz & rounded xyz
  346. d = sqrt(sum((xyz-rxyz).^2));
  347. varargout = {rxyz(1:3),d};
  348. %==========================================================================
  349. case 'findxyz'
  350. %==========================================================================
  351. % i = spm_XYZreg('FindXYZ',xyz,XYZ)
  352. if nargin<3, error('Insufficient arguments'), end
  353. XYZ = varargin{3};
  354. xyz = varargin{2};
  355. %-Find XYZ = xyz
  356. %--------------------------------------------------------------------------
  357. i = find(all([XYZ(1,:)==xyz(1);XYZ(2,:)==xyz(2);XYZ(3,:)==xyz(3)],1));
  358. varargout = {i};
  359. %==========================================================================
  360. case 'nearestxyz'
  361. %==========================================================================
  362. % [xyz,i,d] = spm_XYZreg('NearestXYZ',xyz,XYZ)
  363. if nargin<3, error('Insufficient arguments'), end
  364. %-Find in XYZ nearest point to coordinates xyz (Euclidean distance)
  365. %--------------------------------------------------------------------------
  366. [d,i] = min(spm_XYZreg('Edist',varargin{2},varargin{3}));
  367. varargout = {varargin{3}(:,i),i,d};
  368. %==========================================================================
  369. case 'edist'
  370. %==========================================================================
  371. % d = spm_XYZreg('Edist',xyz,XYZ)
  372. if nargin<3, error('Insufficient arguments'), end
  373. %-Calculate (Euclidean) distances from pointlist coords to xyz
  374. %--------------------------------------------------------------------------
  375. varargout = {sqrt(sum([ (varargin{3}(1,:) - varargin{2}(1));...
  376. (varargin{3}(2,:) - varargin{2}(2));...
  377. (varargin{3}(3,:) - varargin{2}(3)) ].^2))};
  378. %==========================================================================
  379. case 'initreg' % Initialise registry in handle h
  380. %==========================================================================
  381. % [hReg,xyz] = spm_XYZreg('InitReg',hReg,M,D,xyz)
  382. if nargin<5, xyz=[0;0;0]; else xyz=varargin{5}; end
  383. if nargin<4, error('Insufficient arguments'), end
  384. D = varargin{4};
  385. M = varargin{3};
  386. hReg = varargin{2};
  387. %-Check availability of hReg object for building a registry in
  388. %--------------------------------------------------------------------------
  389. if ~isempty(get(hReg,'UserData')), error('Object already has UserData...'), end
  390. if ~isempty(get(hReg,'Tag')), error('Object already ''Tag''ed...'), end
  391. %-Check coordinates are in range
  392. %--------------------------------------------------------------------------
  393. [xyz,d] = spm_XYZreg('RoundCoords',xyz,M,D);
  394. if d>0 && nargout<2
  395. warning('Coordinates rounded to nearest voxel center: Discrepancy %.2f',d);
  396. end
  397. %-Set up registry
  398. %--------------------------------------------------------------------------
  399. RD = struct('xyz',xyz,'M',M,'D',D,'Reg',[]);
  400. RD.Reg = {};
  401. set(hReg,'Tag','hReg','UserData',RD)
  402. %-Return current coordinates
  403. %--------------------------------------------------------------------------
  404. varargout = {hReg,xyz};
  405. %==========================================================================
  406. case 'uninitreg' % UnInitialise registry in handle hReg
  407. %==========================================================================
  408. % spm_XYZreg('UnInitReg',hReg)
  409. hReg = varargin{2};
  410. if ~strcmp(get(hReg,'Tag'),'hReg'), warning('Not an XYZ registry'), return, end
  411. set(hReg,'Tag','','UserData',[])
  412. %==========================================================================
  413. case 'getcoords' % Get current coordinates
  414. %=========================================================================
  415. % xyz = spm_XYZreg('GetCoords',hReg)
  416. if nargin<2, hReg=spm_XYZreg('FindReg'); else hReg=varargin{2}; end
  417. if ~ishandle(hReg), error('Invalid object handle'), end
  418. if ~strcmp(get(hReg,'Tag'),'hReg'), error('Not a registry'), end
  419. varargout = {getfield(get(hReg,'UserData'),'xyz')};
  420. %==========================================================================
  421. case 'setcoords' % Set coordinates & update registered functions
  422. %==========================================================================
  423. % [xyz,d] = spm_XYZreg('SetCoords',xyz,hReg,hC,Reg)
  424. % d returned empty if didn't check, warning printed if d not asked for & round
  425. % Don't check if callerhandle specified (speed)
  426. % If Registry cell array Reg is specified, then only these handles are updated
  427. hC = NaN;
  428. if nargin>=4
  429. if ~ischar(varargin{4}), hC=varargin{4}; end
  430. end
  431. hReg = varargin{3};
  432. %-Check validity of hReg registry handle
  433. %--------------------------------------------------------------------------
  434. %-Return if hReg empty, in case calling objects functions don't check isempty
  435. if isempty(hReg), return, end
  436. %-Check validity of hReg registry handle, correct calling objects if necc.
  437. if ~ishandle(hReg)
  438. str = sprintf('%s: Invalid registry handle (%.4f)',mfilename,hReg);
  439. if ishandle(hC)
  440. %-Remove hReg from caller
  441. spm_XYZreg('SetReg',hC,[])
  442. str = [str,sprintf('\n\t\t\t...removed from caller (%.4f)',hC)];
  443. end
  444. warning(str)
  445. return
  446. end
  447. xyz = varargin{2};
  448. RD = get(hReg,'UserData');
  449. %-Check validity of coords only when called without a caller handle
  450. %--------------------------------------------------------------------------
  451. if ~ishandle(hC)
  452. [xyz,d] = spm_XYZreg('RoundCoords',xyz,RD.M,RD.D);
  453. if d>0 && nargout<2
  454. warning('Coordinates rounded to nearest voxel center: Discrepancy %.2f',d);
  455. end
  456. else
  457. d = 0;
  458. end
  459. %-Sort out valid handles, eliminate caller handle, update coords with
  460. % registered handles via their functions
  461. %--------------------------------------------------------------------------
  462. if nargin<5
  463. RD.Reg = spm_XYZreg('VReg',RD.Reg);
  464. Reg = RD.Reg;
  465. else
  466. Reg = spm_XYZreg('VReg',varargin{5});
  467. end
  468. if ishandle(hC) && ~isempty(Reg), Reg([Reg{:,1}]==varargin{4},:) = []; end
  469. for i = 1:size(Reg,1)
  470. feval(Reg{i,2},'SetCoords',xyz,Reg{i,1},hReg);
  471. end
  472. %-Update registry (if using hReg) with location & cleaned Reg cellarray
  473. %--------------------------------------------------------------------------
  474. if nargin<5
  475. RD.xyz = xyz;
  476. set(hReg,'UserData',RD)
  477. end
  478. varargout = {xyz,d};
  479. %==========================================================================
  480. case 'xreg' % Cross register object handles & functions
  481. %=========================================================================
  482. % nReg = spm_XYZreg('XReg',hReg,{h,Fcn}pairs)
  483. if nargin<4, error('Insufficient arguments'), end
  484. hReg = varargin{2};
  485. %-Quick check of registry handle
  486. %--------------------------------------------------------------------------
  487. if isempty(hReg), warning('Empty registry handle'), return, end
  488. if ~ishandle(hReg), warning('Invalid registry handle'), return, end
  489. %-Condition nReg cell array & check validity of handles to be registered
  490. %--------------------------------------------------------------------------
  491. nReg = varargin(3:end);
  492. if mod(length(nReg),2), error('Registry items must be in pairs'), end
  493. if length(nReg)>2, nReg = reshape(nReg,length(nReg)/2,2)'; end
  494. nReg = spm_XYZreg('VReg',nReg,'Warn');
  495. %-Set hReg registry link for registry candidates (Back registration)
  496. %--------------------------------------------------------------------------
  497. for i = 1:size(nReg,1)
  498. spm_XYZreg('SetReg',nReg{i,1},hReg);
  499. end
  500. %-Append registry candidates to existing registry & write back to hReg
  501. %--------------------------------------------------------------------------
  502. RD = get(hReg,'UserData');
  503. Reg = RD.Reg;
  504. Reg = cat(1,Reg,nReg);
  505. RD.Reg = Reg;
  506. set(hReg,'UserData',RD)
  507. %-Synch coordinates of newly registered objects
  508. %--------------------------------------------------------------------------
  509. spm_XYZreg('SetCoords',RD.xyz,hReg,hReg,nReg);
  510. varargout = {Reg};
  511. %==========================================================================
  512. case 'add2reg' % Add handle(s) & function(s) to registry
  513. %==========================================================================
  514. % nReg = spm_XYZreg('Add2Reg',hReg,{h,Fcn}pairs)
  515. if nargin<4, error('Insufficient arguments'), end
  516. hReg = varargin{2};
  517. %-Quick check of registry handle
  518. %--------------------------------------------------------------------------
  519. if isempty(hReg), warning('Empty registry handle'), return, end
  520. if ~ishandle(hReg), warning('Invalid registry handle'), return, end
  521. %-Condition nReg cell array & check validity of handles to be registered
  522. %--------------------------------------------------------------------------
  523. nReg = varargin(3:end);
  524. if mod(length(nReg),2), error('Registry items must be in pairs'), end
  525. if length(nReg)>2, nReg = reshape(nReg,length(nReg)/2,2)'; end
  526. nReg = spm_XYZreg('VReg',nReg,'Warn');
  527. %-Append to existing registry & put back in registry object
  528. %--------------------------------------------------------------------------
  529. RD = get(hReg,'UserData');
  530. Reg = RD.Reg;
  531. Reg = cat(1,Reg,nReg);
  532. RD.Reg = Reg;
  533. set(hReg,'UserData',RD)
  534. varargout = {Reg};
  535. %==========================================================================
  536. case 'setreg' %-Set registry field of object's UserData
  537. %==========================================================================
  538. % spm_XYZreg('SetReg',h,hReg)
  539. if nargin<3, error('Insufficient arguments'), end
  540. h = varargin{2};
  541. hReg = varargin{3};
  542. if ( ~ishandle(h) || h==0 ), return, end
  543. UD = get(h,'UserData');
  544. if ~isstruct(UD) || ~any(strcmp(fieldnames(UD),'hReg'))
  545. error('No UserData structure with hReg field for this object')
  546. end
  547. UD.hReg = hReg;
  548. set(h,'UserData',UD)
  549. %==========================================================================
  550. case 'unxreg' % Un-cross register object handles & functions
  551. %==========================================================================
  552. % nReg = spm_XYZreg('unXReg',hReg,hD1,hD2,hD3,...)
  553. if nargin<3, error('Insufficient arguments'), end
  554. hD = [varargin{3:end}];
  555. hReg = varargin{2};
  556. %-Get Registry information
  557. %--------------------------------------------------------------------------
  558. RD = get(hReg,'UserData');
  559. Reg = RD.Reg;
  560. %-Find registry entires to delete
  561. %--------------------------------------------------------------------------
  562. [c,i,e] = intersect([Reg{:,1}],hD);
  563. hD(e) = [];
  564. dReg = spm_XYZreg('VReg',Reg(i,:));
  565. Reg(i,:) = [];
  566. if ~isempty(hD), warning('Not all handles were in registry'), end
  567. %-Write back new registry
  568. %--------------------------------------------------------------------------
  569. RD.Reg = Reg;
  570. set(hReg,'UserData',RD)
  571. %-UnSet hReg registry link for hD's still existing (Back un-registration)
  572. %--------------------------------------------------------------------------
  573. for i = 1:size(dReg,1)
  574. spm_XYZreg('SetReg',dReg{i,1},[]);
  575. end
  576. varargout = {Reg};
  577. %==========================================================================
  578. case 'del2reg' % Delete handle(s) & function(s) from registry
  579. %==========================================================================
  580. % nReg = spm_XYZreg('Del2Reg',hReg,hD)
  581. if nargin<3, error('Insufficient arguments'), end
  582. hD = [varargin{3:end}];
  583. hReg = varargin{2};
  584. %-Get Registry information
  585. %--------------------------------------------------------------------------
  586. RD = get(hReg,'UserData');
  587. Reg = RD.Reg;
  588. %-Find registry entires to delete
  589. %--------------------------------------------------------------------------
  590. [c,i,e] = intersect([Reg{:,1}],hD);
  591. Reg(i,:) = [];
  592. hD(e) = [];
  593. if ~isempty(hD), warning('Not all handles were in registry'), end
  594. %-Write back new registry
  595. %--------------------------------------------------------------------------
  596. RD.Reg = Reg;
  597. set(hReg,'UserData',RD)
  598. varargout = {Reg};
  599. %==========================================================================
  600. case 'unsetreg' %-Unset registry field of object's UserData
  601. %==========================================================================
  602. % spm_XYZreg('UnSetReg',h)
  603. if nargin<2, error('Insufficient arguments'), end
  604. spm_XYZreg('SetReg',varargin{2},[])
  605. %==========================================================================
  606. case 'cleanreg' % Clean invalid handles from registry
  607. %==========================================================================
  608. % spm_XYZreg('CleanReg',hReg)
  609. %if ~strcmp(get(hReg,'Tag'),'hReg'), error('Not a registry'), end
  610. hReg = varargin{2};
  611. RD = get(hReg,'UserData');
  612. RD.Reg = spm_XYZreg('VReg',RD.Reg,'Warn');
  613. set(hReg,'UserData',RD)
  614. %==========================================================================
  615. case 'vreg' % Prune invalid handles from registry cell array
  616. %==========================================================================
  617. % Reg = spm_XYZreg('VReg',Reg,Warn)
  618. if nargin<3, Warn=0; else Warn=1; end
  619. Reg = varargin{2};
  620. if isempty(Reg), varargout={Reg}; return, end
  621. i = [];
  622. for h=1:size(Reg,1)
  623. if ~ishghandle(Reg{h,1}), i = [i h]; end
  624. end
  625. %-***check existence of handling functions : exist('','file')?
  626. if Warn && ~isempty(i)
  627. warning('Disregarding invalid registry handles:\n\t%.4f',Reg{i,1});
  628. end
  629. Reg(i,:) = [];
  630. varargout = {Reg};
  631. %==========================================================================
  632. case 'findreg' % Find/check registry object
  633. %==========================================================================
  634. % hReg = spm_XYZreg('FindReg',h)
  635. if nargin<2, h=get(0,'CurrentFigure'); else h=varargin{2}; end
  636. if ischar(h), h=spm_figure('FindWin',h); end
  637. if ~ishandle(h), error('invalid handle'), end
  638. if ~strcmp(get(h,'Tag'),'hReg'), h=findobj(h,'Tag','hReg'); end
  639. if isempty(h), error('Registry object not found'), end
  640. if length(h)>1, error('Multiple registry objects found'), end
  641. varargout = {h};
  642. %==========================================================================
  643. otherwise
  644. %==========================================================================
  645. error('Unknown action string')
  646. %==========================================================================
  647. end