123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863 |
- function varargout = spm_mesh_render(action,varargin)
- % Display a surface mesh & various utilities
- % FORMAT H = spm_mesh_render('Disp',M,'PropertyName',propertyvalue)
- % M - a GIfTI filename/object or patch structure
- % H - structure containing handles of various objects
- % Opens a new figure unless a 'parent' Property is provided with an axis
- % handle.
- %
- % FORMAT H = spm_mesh_render(M)
- % Shortcut to previous call format.
- %
- % FORMAT H = spm_mesh_render('ContextMenu',AX)
- % AX - axis handle or structure returned by spm_mesh_render('Disp',...)
- %
- % FORMAT H = spm_mesh_render('Overlay',AX,P)
- % AX - axis handle or structure given by spm_mesh_render('Disp',...)
- % P - data to be overlayed on mesh (see spm_mesh_project)
- %
- % FORMAT H = spm_mesh_render('ColourBar',AX,MODE)
- % AX - axis handle or structure returned by spm_mesh_render('Disp',...)
- % MODE - {['on'],'off'}
- %
- % FORMAT H = spm_mesh_render('ColourMap',AX,MAP)
- % AX - axis handle or structure returned by spm_mesh_render('Disp',...)
- % MAP - a colour map matrix
- %
- % FORMAT MAP = spm_mesh_render('ColourMap',AX)
- % Retrieves the current colourmap.
- %
- % FORMAT H = spm_mesh_render('View',AX, V)
- % AX - axis handle or structure returned by spm_mesh_render('Disp',...)
- % V - viewpoint specification (see view())
- %
- % FORMAT spm_mesh_render('Register',AX,hReg)
- % AX - axis handle or structure returned by spm_mesh_render('Disp',...)
- % hReg - Handle of HandleGraphics object to build registry in.
- % See spm_XYZreg for more information.
- %__________________________________________________________________________
- % Copyright (C) 2010-2018 Wellcome Trust Centre for Neuroimaging
- % Guillaume Flandin
- % $Id: spm_mesh_render.m 7381 2018-07-25 10:27:54Z guillaume $
- %-Input parameters
- %--------------------------------------------------------------------------
- if ~nargin, action = 'Disp'; end
- if ~ischar(action)
- varargin = {action varargin{:}};
- action = 'Disp';
- end
- varargout = {[]};
- %-Action
- %--------------------------------------------------------------------------
- switch lower(action)
-
- %-Display
- %======================================================================
- case 'disp'
- if isempty(varargin)
- [M, sts] = spm_select([1,Inf],'mesh','Select surface mesh file');
- if ~sts, return; end
- else
- M = varargin{1};
- end
- M = gifti(M);
- if numel(M) > 1, M = gifti(spm_mesh_join(M)); end
- if ~isfield(M,'vertices')
- try
- MM = M;
- M = gifti(MM.private.metadata(1).value);
- try, M.cdata = MM.cdata(); end
- catch
- error('Cannot find a surface mesh to be displayed.');
- end
- end
- M = export(M,'patch');
- O = getOptions(varargin{2:end});
-
- %-Figure & Axis
- %------------------------------------------------------------------
- if isfield(O,'parent')
- H.axis = O.parent;
- H.figure = ancestor(H.axis,'figure');
- figure(H.figure); axes(H.axis);
- else
- H.figure = figure('Color',[1 1 1]);
- H.axis = axes('Parent',H.figure);
- set(H.axis,'Visible','off');
- end
- renderer = get(H.figure,'Renderer');
- set(H.figure,'Renderer','OpenGL');
-
- %-Patch
- %------------------------------------------------------------------
- P = struct('vertices',M.vertices, 'faces',M.faces);
- H.patch = patch(P,...
- 'FaceColor', [0.6 0.6 0.6],...
- 'EdgeColor', 'none',...
- 'FaceLighting', 'gouraud',...
- 'SpecularStrength', 0.7,...
- 'AmbientStrength', 0.1,...
- 'DiffuseStrength', 0.7,...
- 'SpecularExponent', 10,...
- 'Clipping', 'off',...
- 'DeleteFcn', {@myDeleteFcn, renderer},...
- 'Visible', 'off',...
- 'Tag', 'SPMMeshRender',...
- 'Parent', H.axis);
- setappdata(H.patch,'patch',P);
-
- %-Label connected components of the mesh
- %------------------------------------------------------------------
- C = spm_mesh_label(P);
- setappdata(H.patch,'cclabel',C);
-
- %-Compute mesh curvature
- %------------------------------------------------------------------
- curv = spm_mesh_curvature(P) > 0;
- setappdata(H.patch,'curvature',curv);
-
- %-Apply texture to mesh
- %------------------------------------------------------------------
- if isfield(M,'facevertexcdata')
- T = M.facevertexcdata;
- else
- T = [];
- end
- updateTexture(H,T);
-
- %-Set viewpoint, light and manipulation options
- %------------------------------------------------------------------
- if isfield(O,'azimuth'), az = O.azimuth; else az = -90; end
- if isfield(O,'elevation'), el = O.elevation; else el = 0; end
- axis(H.axis,'image');
- axis(H.axis,'off');
- view(H.axis,[az el]);
- material(H.figure,'dull');
- H.light = camlight; set(H.light,'Parent',H.axis);
-
- try, H.rotate3d = rotate3d(H.axis); catch, H.rotate3d = []; end % bug #49747
- set(H.rotate3d,'Enable','on');
- set(H.rotate3d,'ActionPostCallback',{@myPostCallback, H});
- %try
- % setAllowAxesRotate(H.rotate3d, ...
- % setxor(findobj(H.figure,'Type','axes'),H.axis), false);
- %end
-
- %-Store handles
- %------------------------------------------------------------------
- setappdata(H.axis,'handles',H);
- set(H.patch,'Visible','on');
- camlight(H.light);
-
- %-Add context menu
- %------------------------------------------------------------------
- spm_mesh_render('ContextMenu',H);
-
- %-Context Menu
- %======================================================================
- case 'contextmenu'
- if isempty(varargin), varargin{1} = gca; end
- H = getHandles(varargin{1});
- if ~isempty(get(H.patch,'UIContextMenu')), return; end
-
- cmenu = uicontextmenu('Callback',{@myMenuCallback, H});
-
- uimenu(cmenu, 'Label','Inflate', 'Interruptible','off', ...
- 'Callback',{@myInflate, H});
-
- uimenu(cmenu, 'Label','Overlay...', 'Interruptible','off', ...
- 'Callback',{@myOverlay, H});
-
- uimenu(cmenu, 'Label','Image Sections...', 'Interruptible','off', ...
- 'Callback',{@myImageSections, H});
-
- uimenu(cmenu, 'Label','Change geometry...', 'Interruptible','off', ...
- 'Callback',{@myChangeGeometry, H});
-
- c = uimenu(cmenu, 'Label', 'Connected Components', 'Interruptible','off');
- C = getappdata(H.patch,'cclabel');
- for i=1:length(unique(C))
- uimenu(c, 'Label',sprintf('Component %d',i), 'Checked','on', ...
- 'Callback',{@myCCLabel, H});
- end
-
- uimenu(cmenu, 'Label','Rotate', 'Checked','on', 'Separator','on', ...
- 'Callback',{@mySwitchRotate, H});
-
- uimenu(cmenu, 'Label','Synchronise Views', 'Visible','off', ...
- 'Checked','off', 'Tag','SynchroMenu', 'Callback',{@mySynchroniseViews, H});
-
- c = uimenu(cmenu, 'Label','View');
- uimenu(c, 'Label','Go to Y-Z view (right)', 'Callback', {@myView, H, [90 0]});
- uimenu(c, 'Label','Go to Y-Z view (left)', 'Callback', {@myView, H, [-90 0]});
- uimenu(c, 'Label','Go to X-Y view (top)', 'Callback', {@myView, H, [0 90]});
- uimenu(c, 'Label','Go to X-Y view (bottom)', 'Callback', {@myView, H, [-180 -90]});
- uimenu(c, 'Label','Go to X-Z view (front)', 'Callback', {@myView, H, [-180 0]});
- uimenu(c, 'Label','Go to X-Z view (back)', 'Callback', {@myView, H, [0 0]});
-
- uimenu(cmenu, 'Label','Colorbar', 'Callback', {@myColourbar, H});
-
- c = uimenu(cmenu, 'Label','Colormap');
- clrmp = {'hot' 'jet' 'gray' 'hsv' 'bone' 'copper' 'pink' 'white' ...
- 'flag' 'lines' 'colorcube' 'prism' 'cool' 'autumn' ...
- 'spring' 'winter' 'summer'};
- for i=1:numel(clrmp)
- uimenu(c, 'Label', clrmp{i}, 'Callback', {@myColourmap, H});
- end
-
- c = uimenu(cmenu, 'Label','Transparency');
- uimenu(c, 'Label','0%', 'Checked','on', 'Callback', {@myTransparency, H});
- uimenu(c, 'Label','20%', 'Checked','off', 'Callback', {@myTransparency, H});
- uimenu(c, 'Label','40%', 'Checked','off', 'Callback', {@myTransparency, H});
- uimenu(c, 'Label','60%', 'Checked','off', 'Callback', {@myTransparency, H});
- uimenu(c, 'Label','80%', 'Checked','off', 'Callback', {@myTransparency, H});
-
- uimenu(cmenu, 'Label','Data Cursor', 'Callback', {@myDataCursor, H});
-
- c = uimenu(cmenu, 'Label','Background Color');
- uimenu(c, 'Label','White', 'Callback', {@myBackgroundColor, H, [1 1 1]});
- uimenu(c, 'Label','Black', 'Callback', {@myBackgroundColor, H, [0 0 0]});
- uimenu(c, 'Label','Custom...', 'Callback', {@myBackgroundColor, H, []});
-
- uimenu(cmenu, 'Label','Save As...', 'Separator', 'on', ...
- 'Callback', {@mySave, H});
-
- set(H.rotate3d,'Enable','off');
- try, set(H.rotate3d,'UIContextMenu',cmenu); end
- try, set(H.patch, 'UIContextMenu',cmenu); end
- set(H.rotate3d,'Enable','on');
-
- try
- dcm_obj = datacursormode(H.figure);
- set(dcm_obj, 'Enable','off', 'SnapToDataVertex','on', ...
- 'DisplayStyle','Window', 'Updatefcn',{@myDataCursorUpdate, H});
- end
-
- %-Overlay
- %======================================================================
- case 'overlay'
- if isempty(varargin), varargin{1} = gca; end
- H = getHandles(varargin{1});
- if nargin < 3, varargin{2} = []; end
- updateTexture(H,varargin{2:end});
-
- %-Slices
- %======================================================================
- case 'slices'
- if isempty(varargin), varargin{1} = gca; end
- H = getHandles(varargin{1});
- if nargin < 3, varargin{2} = []; end
- renderSlices(H,varargin{2:end});
-
- %-ColourBar
- %======================================================================
- case {'colourbar', 'colorbar'}
- if isempty(varargin), varargin{1} = gca; end
- if length(varargin) == 1, varargin{2} = 'on'; end
- H = getHandles(varargin{1});
- d = getappdata(H.patch,'data');
- col = getappdata(H.patch,'colourmap');
- if strcmpi(varargin{2},'off')
- if isfield(H,'colourbar') && ishandle(H.colourbar)
- delete(H.colourbar);
- H = rmfield(H,'colourbar');
- setappdata(H.axis,'handles',H);
- end
- return;
- end
- if isempty(d) || ~any(d(:)), varargout = {H}; return; end
- if isempty(col), col = hot(256); end
- if ~isfield(H,'colourbar') || ~ishandle(H.colourbar)
- H.colourbar = colorbar('peer',H.axis);
- set(H.colourbar,'Tag','');
- set(get(H.colourbar,'Children'),'Tag','');
- end
- c(1:size(col,1),1,1:size(col,2)) = col;
- ic = findobj(H.colourbar,'Type','image');
- if size(d,1) > 1
- set(ic,'CData',c(1:size(d,1),:,:));
- set(ic,'YData',[1 size(d,1)]);
- set(H.colourbar,'YLim',[1 size(d,1)]);
- set(H.colourbar,'YTickLabel',[]);
- else
- set(ic,'CData',c);
- clim = getappdata(H.patch,'clim');
- if isempty(clim), clim = [false min(d) max(d)]; end
- set(ic,'YData',clim(2:3));
- set(H.colourbar,'YLim',clim(2:3));
- end
- setappdata(H.axis,'handles',H);
-
- %-ColourMap
- %======================================================================
- case {'colourmap', 'colormap'}
- if isempty(varargin), varargin{1} = gca; end
- H = getHandles(varargin{1});
- if length(varargin) == 1
- varargout = { getappdata(H.patch,'colourmap') };
- return;
- else
- setappdata(H.patch,'colourmap',varargin{2});
- d = getappdata(H.patch,'data');
- updateTexture(H,d);
- end
-
- %-CLim
- %======================================================================
- case 'clim'
- if isempty(varargin), varargin{1} = gca; end
- H = getHandles(varargin{1});
- if length(varargin) == 1
- c = getappdata(H.patch,'clim');
- if ~isempty(c), c = c(2:3); end
- varargout = { c };
- return;
- else
- if isempty(varargin{2}) || any(~isfinite(varargin{2}))
- setappdata(H.patch,'clim',[false NaN NaN]);
- else
- setappdata(H.patch,'clim',[true varargin{2}]);
- end
- d = getappdata(H.patch,'data');
- updateTexture(H,d);
- end
-
- %-View
- %======================================================================
- case 'view'
- if isempty(varargin), varargin{1} = gca; end
- H = getHandles(varargin{1});
- if numel(varargin) < 2, v = 'left'; else v = varargin{2}; end
- if ischar(v)
- switch lower(v)
- case 'right'
- v = [90 0];
- case 'left'
- v = [-90 0];
- case 'top'
- v = [0 90];
- case 'bottom'
- v = [-180 -90];
- case 'front'
- v = [-180 0];
- case 'back'
- v = [0 0];
- otherwise
- error('Unknown view position.');
- end
- end
- myView([],[],H,v);
-
- %-Register
- %======================================================================
- case 'register'
- if isempty(varargin), varargin{1} = gca; end
- H = getHandles(varargin{1});
- hReg = varargin{2};
- xyz = spm_XYZreg('GetCoords',hReg);
- hs = myCrossBar('Create',H,xyz);
- set(hs,'UserData',hReg);
- spm_XYZreg('Add2Reg',hReg,hs,@myCrossBar);
-
- %-Debug
- %======================================================================
- case 'debug'
- if isempty(varargin), varargin{1} = gca; end
- H = getHandles(varargin{1});
- set(H.patch,'EdgeColor','r');
- M = getappdata(H.patch,'patch');
- for i=1:size(M.vertices,1)
- text(M.vertices(i,1),M.vertices(i,2),M.vertices(i,3),...
- sprintf('%d',i));
- end
-
- %-Otherwise...
- %======================================================================
- otherwise
- try
- H = spm_mesh_render('Disp',action,varargin{:});
- catch
- error('Unknown action.');
- end
- end
- varargout = {H};
- %==========================================================================
- function O = getOptions(varargin)
- O = [];
- if ~nargin
- return;
- elseif nargin == 1 && isstruct(varargin{1})
- for i=fieldnames(varargin{1})
- O.(lower(i{1})) = varargin{1}.(i{1});
- end
- elseif mod(nargin,2) == 0
- for i=1:2:numel(varargin)
- O.(lower(varargin{i})) = varargin{i+1};
- end
- else
- error('Invalid list of property/value pairs.');
- end
- %==========================================================================
- function H = getHandles(H)
- if ~nargin || isempty(H), H = gca; end
- if ishandle(H) && ~isappdata(H,'handles')
- a = H; clear H;
- H.axis = a;
- H.figure = ancestor(H.axis,'figure');
- H.patch = findobj(H.axis,'type','patch');
- H.light = findobj(H.axis,'type','light');
- H.rotate3d = rotate3d(H.figure);
- setappdata(H.axis,'handles',H);
- elseif ishandle(H)
- H = getappdata(H,'handles');
- else
- H = getappdata(H.axis,'handles');
- end
- %==========================================================================
- function myMenuCallback(obj,evt,H)
- H = getHandles(H);
- h = findobj(obj,'Label','Rotate');
- if strcmpi(get(H.rotate3d,'Enable'),'on')
- set(h,'Checked','on');
- else
- set(h,'Checked','off');
- end
- if numel(findobj('Tag','SPMMeshRender','Type','Patch')) > 1
- h = findobj(obj,'Tag','SynchroMenu');
- set(h,'Visible','on');
- end
- h = findobj(obj,'Label','Colorbar');
- d = getappdata(H.patch,'data');
- if isempty(d) || ~any(d(:)), set(h,'Enable','off'); else set(h,'Enable','on'); end
- if isfield(H,'colourbar')
- if ishandle(H.colourbar)
- set(h,'Checked','on');
- else
- H = rmfield(H,'colourbar');
- set(h,'Checked','off');
- end
- else
- set(h,'Checked','off');
- end
- setappdata(H.axis,'handles',H);
- %==========================================================================
- function myPostCallback(obj,evt,H)
- P = findobj('Tag','SPMMeshRender','Type','Patch');
- if numel(P) == 1
- camlight(H.light);
- else
- for i=1:numel(P)
- H = getappdata(ancestor(P(i),'axes'),'handles');
- camlight(H.light);
- end
- end
- %==========================================================================
- function varargout = myCrossBar(varargin)
- switch lower(varargin{1})
- case 'create'
- %----------------------------------------------------------------------
- % hMe = myCrossBar('Create',H,xyz)
- H = varargin{2};
- xyz = varargin{3};
- hold(H.axis,'on');
- hs = plot3(xyz(1),xyz(2),xyz(3),'Marker','+','MarkerSize',60,...
- 'parent',H.axis,'Color',[1 1 1],'Tag','CrossBar','ButtonDownFcn',{});
- varargout = {hs};
-
- case 'setcoords'
- %----------------------------------------------------------------------
- % [xyz,d] = myCrossBar('SetCoords',xyz,hMe)
- hMe = varargin{3};
- xyz = varargin{2};
- set(hMe,'XData',xyz(1));
- set(hMe,'YData',xyz(2));
- set(hMe,'ZData',xyz(3));
- varargout = {xyz,[]};
-
- otherwise
- %----------------------------------------------------------------------
- error('Unknown action string')
- end
- %==========================================================================
- function myInflate(obj,evt,H)
- spm_mesh_inflate(H.patch,Inf,1);
- axis(H.axis,'image');
- %==========================================================================
- function myCCLabel(obj,evt,H)
- C = getappdata(H.patch,'cclabel');
- F = get(H.patch,'Faces');
- ind = sscanf(get(obj,'Label'),'Component %d');
- V = get(H.patch,'FaceVertexAlphaData');
- Fa = get(H.patch,'FaceAlpha');
- if ~isnumeric(Fa)
- if ~isempty(V), Fa = max(V); else Fa = 1; end
- if Fa == 0, Fa = 1; end
- end
- if isempty(V) || numel(V) == 1
- Ve = get(H.patch,'Vertices');
- if isempty(V) || V == 1
- V = Fa * ones(size(Ve,1),1);
- else
- V = zeros(size(Ve,1),1);
- end
- end
- if strcmpi(get(obj,'Checked'),'on')
- V(reshape(F(C==ind,:),[],1)) = 0;
- set(obj,'Checked','off');
- else
- V(reshape(F(C==ind,:),[],1)) = Fa;
- set(obj,'Checked','on');
- end
- set(H.patch, 'FaceVertexAlphaData', V);
- if all(V)
- set(H.patch, 'FaceAlpha', Fa);
- else
- set(H.patch, 'FaceAlpha', 'interp');
- end
- %==========================================================================
- function myTransparency(obj,evt,H)
- t = 1 - sscanf(get(obj,'Label'),'%d%%') / 100;
- set(H.patch,'FaceAlpha',t);
- set(get(get(obj,'parent'),'children'),'Checked','off');
- set(obj,'Checked','on');
- %==========================================================================
- function mySwitchRotate(obj,evt,H)
- if strcmpi(get(H.rotate3d,'Enable'),'on')
- set(H.rotate3d,'Enable','off');
- set(obj,'Checked','off');
- else
- set(H.rotate3d,'Enable','on');
- set(obj,'Checked','on');
- end
- %==========================================================================
- function myView(obj,evt,H,varargin)
- view(H.axis,varargin{1});
- axis(H.axis,'image');
- camlight(H.light);
- %==========================================================================
- function myColourbar(obj,evt,H)
- y = {'on','off'}; toggle = @(x) y{1+strcmpi(x,'on')};
- spm_mesh_render('Colourbar',H,toggle(get(obj,'Checked')));
- %==========================================================================
- function myColourmap(obj,evt,H)
- spm_mesh_render('Colourmap',H,feval(get(obj,'Label'),256));
- %==========================================================================
- function mySynchroniseViews(obj,evt,H)
- P = findobj('Tag','SPMMeshRender','Type','Patch');
- v = get(H.axis,'cameraposition');
- for i=1:numel(P)
- H = getappdata(ancestor(P(i),'axes'),'handles');
- set(H.axis,'cameraposition',v);
- axis(H.axis,'image');
- camlight(H.light);
- end
- %==========================================================================
- function myDataCursor(obj,evt,H)
- dcm_obj = datacursormode(H.figure);
- set(dcm_obj, 'Enable','on', 'SnapToDataVertex','on', ...
- 'DisplayStyle','Window', 'Updatefcn',{@myDataCursorUpdate, H});
- %==========================================================================
- function txt = myDataCursorUpdate(obj,evt,H)
- pos = get(evt,'Position');
- txt = {['X: ',num2str(pos(1))],...
- ['Y: ',num2str(pos(2))],...
- ['Z: ',num2str(pos(3))]};
- i = ismember(get(H.patch,'vertices'),pos,'rows');
- txt = {['Node: ' num2str(find(i))] txt{:}};
- d = getappdata(H.patch,'data');
- if ~isempty(d) && any(d(:))
- if any(i), txt = {txt{:} ['T: ',num2str(d(i))]}; end
- end
- hMe = findobj(H.axis,'Tag','CrossBar');
- if ~isempty(hMe)
- ws = warning('off');
- spm_XYZreg('SetCoords',pos,get(hMe,'UserData'));
- warning(ws);
- end
- %==========================================================================
- function myBackgroundColor(obj,evt,H,varargin)
- if isempty(varargin{1})
- c = uisetcolor(H.figure, ...
- 'Pick a background color...');
- if numel(c) == 1, return; end
- else
- c = varargin{1};
- end
- h = findobj(H.figure,'Tag','SPMMeshRenderBackground');
- if isempty(h)
- set(H.figure,'Color',c);
- else
- set(h,'Color',c);
- end
- %==========================================================================
- function mySave(obj,evt,H)
- [filename, pathname, filterindex] = uiputfile({...
- '*.gii' 'GIfTI files (*.gii)'; ...
- '*.png' 'PNG files (*.png)';...
- '*.dae' 'Collada files (*.dae)';...
- '*.idtf' 'IDTF files (*.idtf)';...
- '*.vtk' 'VTK files (*.vtk)';...
- '*.obj' 'OBJ files (*.obj)';...
- '*.js' 'JS files (*.js)';...
- '*.json' 'JSON files (*.json)'}, 'Save as');
- if ~isequal(filename,0) && ~isequal(pathname,0)
- [pth,nam,ext] = fileparts(filename);
- switch ext
- case '.gii'
- filterindex = 1;
- case '.png'
- filterindex = 2;
- case '.dae'
- filterindex = 3;
- case '.idtf'
- filterindex = 4;
- case {'.vtk','.vtp'}
- filterindex = 5;
- case '.obj'
- filterindex = 6;
- case '.js'
- filterindex = 7;
- case '.json'
- filterindex = 8;
- otherwise
- switch filterindex
- case 1
- filename = [filename '.gii'];
- case 2
- filename = [filename '.png'];
- case 3
- filename = [filename '.dae'];
- case 4
- filename = [filename '.idtf'];
- case 5
- filename = [filename '.vtk'];
- case 6
- filename = [filename '.obj'];
- case 7
- filename = [filename '.js'];
- case 8
- filename = [filename '.json'];
- end
- end
- switch filterindex
- case 1
- G = gifti(H.patch);
- [p,n,e] = fileparts(filename);
- [p,n,e] = fileparts(n);
- switch lower(e)
- case '.func'
- save(gifti(getappdata(H.patch,'data')),...
- fullfile(pathname, filename));
- case '.surf'
- save(gifti(struct('vertices',G.vertices,'faces',G.faces)),...
- fullfile(pathname, filename));
- case '.rgba'
- save(gifti(G.cdata),fullfile(pathname, filename));
- otherwise
- save(G,fullfile(pathname, filename));
- end
- case 2
- u = get(H.axis,'units');
- set(H.axis,'units','pixels');
- p = get(H.axis,'Position');
- r = get(H.figure,'Renderer');
- hc = findobj(H.figure,'Tag','SPMMeshRenderBackground');
- if isempty(hc)
- c = get(H.figure,'Color');
- else
- c = get(hc,'Color');
- end
- h = figure('Position',p+[0 0 10 10], ...
- 'InvertHardcopy','off', ...
- 'Color',c, ...
- 'Renderer',r);
- copyobj(H.axis,h);
- set(H.axis,'units',u);
- set(get(h,'children'),'visible','off');
- %a = get(h,'children');
- %set(a,'Position',get(a,'Position').*[0 0 1 1]+[10 10 0 0]);
- print(h, '-dpng', '-opengl', fullfile(pathname, filename));
- close(h);
- set(getappdata(obj,'fig'),'renderer',r);
- case 3
- saveas(gifti(H.patch),fullfile(pathname, filename),'collada');
- case 4
- saveas(gifti(H.patch),fullfile(pathname, filename),'idtf');
- case 5
- saveas(gifti(H.patch),fullfile(pathname, filename),'vtk');
- case 6
- saveas(gifti(H.patch),fullfile(pathname, filename),'obj');
- case 7
- saveas(gifti(H.patch),fullfile(pathname, filename),'js');
- case 8
- saveas(gifti(H.patch),fullfile(pathname, filename),'json');
- end
- end
- %==========================================================================
- function myDeleteFcn(obj,evt,renderer)
- try, rotate3d(get(obj,'parent'),'off'); end
- set(ancestor(obj,'figure'),'Renderer',renderer);
- %==========================================================================
- function myOverlay(obj,evt,H)
- [P, sts] = spm_select(1,'\.img|\.nii|\.gii|\.mat','Select file to overlay');
- if ~sts, return; end
- spm_mesh_render('Overlay',H,P);
- %==========================================================================
- function myImageSections(obj,evt,H)
- [P, sts] = spm_select(1,'image','Select image to render');
- if ~sts, return; end
- renderSlices(H,P);
- %==========================================================================
- function myChangeGeometry(obj,evt,H)
- [P, sts] = spm_select([1, Inf],'mesh','Select new geometry mesh');
- if ~sts, return; end
- G = gifti(P);
- if numel(G) > 1, G = gifti(spm_mesh_join(G)); end
- if size(H.patch.Vertices,1) ~= size(G.vertices,1)
- error('Number of vertices must match.');
- end
- H.patch.Vertices = G.vertices;
- H.patch.Faces = G.faces;
- %==========================================================================
- function renderSlices(H,P,pls)
- if nargin <3
- pls = 0.05:0.2:0.9;
- end
- N = nifti(P);
- d = size(N.dat);
- pls = round(pls.*d(3));
- hold(H.axis,'on');
- for i=1:numel(pls)
- [x,y,z] = ndgrid(1:d(1),1:d(2),pls(i));
- f = N.dat(:,:,pls(i));
- x1 = N.mat(1,1)*x + N.mat(1,2)*y + N.mat(1,3)*z + N.mat(1,4);
- y1 = N.mat(2,1)*x + N.mat(2,2)*y + N.mat(2,3)*z + N.mat(2,4);
- z1 = N.mat(3,1)*x + N.mat(3,2)*y + N.mat(3,3)*z + N.mat(3,4);
- surf(x1,y1,z1, repmat(f,[1 1 3]), 'EdgeColor','none', ...
- 'Clipping','off', 'Parent',H.axis);
- end
- hold(H.axis,'off');
- axis(H.axis,'image');
- %==========================================================================
- function C = updateTexture(H,v,col)
- %-Get colourmap
- %--------------------------------------------------------------------------
- if nargin<3, col = getappdata(H.patch,'colourmap'); end
- if isempty(col), col = hot(256); end
- setappdata(H.patch,'colourmap',col);
- %-Get curvature
- %--------------------------------------------------------------------------
- curv = getappdata(H.patch,'curvature');
- if size(curv,2) == 1
- curv = 0.5 * repmat(curv,1,3) + 0.3 * repmat(~curv,1,3);
- end
-
- %-Project data onto surface mesh
- %--------------------------------------------------------------------------
- if nargin < 2, v = []; end
- if ischar(v)
- [p,n,e] = fileparts(v);
- if strcmp([n e],'SPM.mat')
- swd = pwd;
- spm_figure('GetWin','Interactive');
- [SPM,v] = spm_getSPM(struct('swd',p));
- cd(swd);
- else
- try, spm_vol(v); catch, v = gifti(v); end
- end
- end
- if isa(v,'gifti'), v = v.cdata; end
- if isa(v,'file_array'), v = v(); end
- if isempty(v)
- v = zeros(size(curv))';
- elseif ischar(v) || iscellstr(v) || isstruct(v)
- v = spm_mesh_project(H.patch,v);
- elseif isnumeric(v) || islogical(v)
- if size(v,2) == 1
- v = v';
- end
- else
- error('Unknown data type.');
- end
- v(isinf(v)) = NaN;
- setappdata(H.patch,'data',v);
- %-Create RGB representation of data according to colourmap
- %--------------------------------------------------------------------------
- C = zeros(size(v,2),3);
- clim = getappdata(H.patch, 'clim');
- if isempty(clim), clim = [false NaN NaN]; end
- mi = clim(2); ma = clim(3);
- if any(v(:))
- if size(col,1)>3 && size(col,1) ~= size(v,1)
- if size(v,1) == 1
- if ~clim(1), mi = min(v(:)); ma = max(v(:)); end
- C = squeeze(ind2rgb(floor(((v(:)-mi)/(ma-mi))*size(col,1)),col));
- elseif isequal(size(v),[size(curv,1) 3])
- C = v; v = v';
- else
- if ~clim(1), mi = min(v(:)); ma = max(v(:)); end
- for i=1:size(v,1)
- C = C + squeeze(ind2rgb(floor(((v(i,:)-mi)/(ma-mi))*size(col,1)),col));
- end
- end
- else
- if ~clim(1), ma = max(v(:)); end
- for i=1:size(v,1)
- C = C + v(i,:)'/ma * col(i,:);
- end
- end
- end
- setappdata(H.patch, 'clim', [false mi ma]);
- %-Build texture by merging curvature and data
- %--------------------------------------------------------------------------
- C = repmat(~any(v,1),3,1)' .* curv + repmat(any(v,1),3,1)' .* C;
- set(H.patch, 'FaceVertexCData',C, 'FaceColor','interp');
- %-Update the colourbar
- %--------------------------------------------------------------------------
- if isfield(H,'colourbar')
- spm_mesh_render('Colourbar',H);
- end
|