Code covered by the BSD License  

Highlights from
Plot a 3D array using patch

image thumbnail

Plot a 3D array using patch

by

 

17 Aug 2010 (Updated )

Plotting a 3D array using a patch surface mesh

PATCH_3Darray(varargin)
function [varargout] = PATCH_3Darray(varargin)
% PATCH_3Darray  Plot a 3D array using patch to create a quadrangular surface mesh
%==========================================================================
% AUTHOR        Adam H. Aitkenhead
% CONTACT       adam.aitkenhead@christie.nhs.uk
% INSTITUTION   The Christie NHS Foundation Trust
% DATE          17th August 2010
%
% USAGE         [hpat] = PATCH_3Darray(gridINPUT)
%          or.. [hpat] = PATCH_3Darray(gridINPUT,cmap)
%          or.. [hpat] = PATCH_3Darray(gridINPUT,gridX,gridY,gridZ)
%          or.. [hpat] = PATCH_3Darray(gridINPUT,gridX,gridY,gridZ,cmap)
%          or.. [hpat] = PATCH_3Darray(gridINPUT,gridX,gridY,gridZ,'col')
%          or.. [hpat] = PATCH_3Darray(gridINPUT,gridX,gridY,gridZ,cmap,'col')
%          or.. [hpat] = PATCH_3Darray(gridINPUT,gridX,gridY,gridZ,cmap,clim,'col')
%          or.. [hpat,hcbar] = PATCH_3Darray(gridINPUT,gridX,gridY,gridZ,cmap,clim,'col')
%
% INPUTS
%   gridINPUT        - 3D array of size (P,Q,R)
%                      If not using the flag 'col', then gridINPUT should
%                      be a logical array.  If using the flag 'col' , then
%                      gridINPUT should be a numeric array where voxels
%                      which are not to be displayed contain the value NaN. 
%   gridX (optional) - A 1xP array  - List of the X axis coordinates.
%   gridY (optional) - A 1xQ array  - List of the Y axis coordinates.
%   gridZ (optional) - A 1xR array  - List of the Z axis coordinates.
%   cmap  (optional) - A Nx3 array  - The colormap definition.  When
%                      plotting using the 'col' flag, cmap must be an Nx3
%                      array, eg jet(32).  When plotting a logical array,
%                      cmap must be an RGB triplet, eg [0.5,0.5,0].
%   clim  (optional) - A 2x1 array - The colormap upper and lower limits.
%
% ADDITIONAL INPUT FLAGS
%   'col'  (optional) - When this flag is present, the colour of each
%                       facet corresponds to the value of the voxel.  In
%                       the input array gridINPUT, voxels which are not to 
%                       be displayed should have a value of NaN.
%   'barN' (optional) - Display a colorbar on North of plot.
%   'barE' (optional) - Display a colorbar on East of plot.
%   'barS' (optional) - Display a colorbar on South of plot.
%   'barW' (optional) - Display a colorbar on West of plot.
%
% OUTPUTS
%   hpat  (optional)  - Handle to the patch object.
%   hcbar (optional)  - Handle to the colorbar.
%==========================================================================

%==========================================================================
% VERSION  USER  CHANGES
% -------  ----  -------
% 100817   AHA   Original version
% 101126   AHA   Better handling of objects which are only 1 pixel wide.
% 110310   AHA   Can now produce plots where the colour of each facet
%                corresponds to the value of the voxel.
% 110311   AHA   The user can now specify the colour map for the display of
%                a 3D numeric array.
% 110316   AHA   Set the facet edges to be a darker version of the face
%                colour.
% 110324   AHA   Bugfix:  Ensure the facet values lie within [1:cres]
%                rather than [0:cres].  Otherwise the 3D object will have a
%                hole, since any 0-value facets will not be plotted.
% 110401   AHA   Minor speed up by reducing number of calls to ind2sub.
% 110407   AHA   Added control of the colorbar position.
% 111104   AHA   Housekeeping tidy-up
% 120210   AHA   The user can now define the lower and upper limits of the
%                colorbar using the input parameter 'clim'.  The input flag
%                'sym' has been removed, as the user can now define a
%                colorbar which is symmetric around zero using the input
%                parameter clim.
%==========================================================================


%======================================================
% CHECK THE INPUTS
%======================================================

checkchar = false(nargin,1);
checknl   = false(nargin,1);
for loopC = 1:nargin
  checkchar(loopC) = ischar(varargin{loopC});
  checknl(loopC)   = isnumeric(varargin{loopC}) + islogical(varargin{loopC});
end

%Check for numeric or logical inputs
if sum(checknl)==1
  gridINPUT  = varargin{checknl};
  gridSIZE   = size(gridINPUT);
  gridX      = 1:gridSIZE(1);
  gridY      = 1:gridSIZE(2);
  gridZ      = 1:gridSIZE(3);
elseif sum(checknl)==2
  checknlIND = find(checknl==1);
  gridINPUT  = varargin{checknlIND(1)};
  gridSIZE   = size(gridINPUT);
  gridX      = 1:gridSIZE(1);
  gridY      = 1:gridSIZE(2);
  gridZ      = 1:gridSIZE(3);
  if numel(varargin{checknlIND(2)})==2
    clim = varargin{checknlIND(2)};
  else
    cmap = varargin{checknlIND(2)};
  end
elseif sum(checknl)==3
  checknlIND = find(checknl==1);
  gridINPUT  = varargin{checknlIND(1)};
  gridSIZE   = size(gridINPUT);
  gridX      = 1:gridSIZE(1);
  gridY      = 1:gridSIZE(2);
  gridZ      = 1:gridSIZE(3);
  if numel(varargin{checknlIND(2)})==2
    clim = varargin{checknlIND(2)};
    cmap = varargin{checknlIND(3)};
  else
    clim = varargin{checknlIND(3)};
    cmap = varargin{checknlIND(2)};
  end
elseif sum(checknl)==4
  checknlIND = find(checknl==1);
  gridINPUT  = varargin{checknlIND(1)};
  gridSIZE   = size(gridINPUT);
  gridX      = varargin{checknlIND(2)};
  gridY      = varargin{checknlIND(3)};
  gridZ      = varargin{checknlIND(4)};
elseif sum(checknl)==5
  checknlIND = find(checknl==1);
  gridINPUT  = varargin{checknlIND(1)};
  gridSIZE   = size(gridINPUT);
  gridX      = varargin{checknlIND(2)};
  gridY      = varargin{checknlIND(3)};
  gridZ      = varargin{checknlIND(4)};
  if numel(varargin{checknlIND(5)})==2
    clim = varargin{checknlIND(5)};
  else
    cmap = varargin{checknlIND(5)};
  end
elseif sum(checknl)==6
  checknlIND = find(checknl==1);
  gridINPUT  = varargin{checknlIND(1)};
  gridSIZE   = size(gridINPUT);
  gridX      = varargin{checknlIND(2)};
  gridY      = varargin{checknlIND(3)};
  gridZ      = varargin{checknlIND(4)};
  if numel(varargin{checknlIND(5)})==2
    clim = varargin{checknlIND(5)};
    cmap = varargin{checknlIND(6)};
  else
    clim = varargin{checknlIND(6)};
    cmap = varargin{checknlIND(5)};
  end
else
  error('Incorrect number of numeric/logical inputs.')
end

%Set defaults for colormap and colorbar options
colYN = 0;
cbar  = 0;
  
%Check for character inputs
if sum(checkchar)>=1
  checkcharIND = find(checkchar==1);
  for loopCH = 1:sum(checkchar)
    if strncmpi('col',varargin{checkcharIND(loopCH)},3)==1
      colYN = 1;
    elseif strcmpi('barno',varargin{checkcharIND(loopCH)})==1
      cbar = 0;
    elseif strcmpi('barN',varargin{checkcharIND(loopCH)})==1
      cbar = 1;
    elseif strcmpi('barE',varargin{checkcharIND(loopCH)})==1
      cbar = 2;
    elseif strcmpi('barS',varargin{checkcharIND(loopCH)})==1
      cbar = 3;
    elseif strcmpi('barW',varargin{checkcharIND(loopCH)})==1
      cbar = 4;
    end
  end
end

%Check that the colormap is a 1x3 array if a logical array is to be plotted
if colYN==0 && exist('cmap','var')==1 && numel(cmap)~=3
  error('When displaying a logical array, the colour map must be a 1x3 RGB triplet.')
end

%Check the size of the grid
if size(gridX,1)>size(gridX,2)
  gridX = gridX';
end
if size(gridY,1)>size(gridY,2)
  gridY = gridY';
end
if size(gridZ,1)>size(gridZ,2)
  gridZ = gridZ';
end

if ~isequal(gridSIZE,[numel(gridX),numel(gridY),numel(gridZ)])
  error('The dimensions of gridINPUT do not match the dimensions of gridX, gridY, gridZ.')
end


%======================================================
% OBTAIN A LOGICAL ARRAY FROM gridINPUT
%======================================================

if colYN == 1;
  gridINPUTlogical = ~isnan(gridINPUT);
elseif colYN == 0;
  gridINPUTlogical = gridINPUT;
  nanvoxels = isnan(gridINPUT);
  nancount  = sum(nanvoxels(:));
  if nancount>0
    gridINPUTlogical(~nanvoxels) = 1;
    gridINPUTlogical(nanvoxels)  = 0;
  end
  gridINPUTlogical = logical(gridINPUTlogical);
end


%======================================================
% REMOVE ANY OUTER UNUSED AREAS FROM gridINPUT
%======================================================

objectIND                 = find(gridINPUTlogical);
[objectX,objectY,objectZ] = ind2sub(gridSIZE,objectIND);

if objectX(1)~=objectX(end)
  gridINPUT        = gridINPUT(min(objectX):max(objectX),:,:);
  gridINPUTlogical = gridINPUTlogical(min(objectX):max(objectX),:,:);
  gridX            = gridX(min(objectX):max(objectX));
end
if objectY(1)~=objectY(end)
  gridINPUT        = gridINPUT(:,min(objectY):max(objectY),:);
  gridINPUTlogical = gridINPUTlogical(:,min(objectY):max(objectY),:);
  gridY            = gridY(min(objectY):max(objectY));
end
if objectZ(1)~=objectZ(end)
  gridINPUT        = gridINPUT(:,:,min(objectZ):max(objectZ));
  gridINPUTlogical = gridINPUTlogical(:,:,min(objectZ):max(objectZ));
  gridZ            = gridZ(min(objectZ):max(objectZ));
end

gridSIZE = size(gridINPUT);


%======================================================
% DEFINE THE LOWER AND UPPER LIMITS OF EACH VOXEL
%======================================================

if gridSIZE(1)==1
  gridXlower = gridX;
  gridXupper = gridX;
else
  gridXsteps = gridX(2:end)-gridX(1:end-1);
  gridXlower = gridX-[gridXsteps(1),gridXsteps]/2;
  gridXupper = gridX+[gridXsteps,gridXsteps(end)]/2;
end

if gridSIZE(2)==1
  gridYlower = gridY;
  gridYupper = gridY;
else
  gridYsteps = gridY(2:end)-gridY(1:end-1);
  gridYlower = gridY-[gridYsteps(1),gridYsteps]/2;
  gridYupper = gridY+[gridYsteps,gridYsteps(end)]/2;
end

if gridSIZE(3)==1
  gridZlower = gridZ;
  gridZupper = gridZ;
else
  gridZsteps = gridZ(2:end)-gridZ(1:end-1);
  gridZlower = gridZ-[gridZsteps(1),gridZsteps]/2;
  gridZupper = gridZ+[gridZsteps,gridZsteps(end)]/2;
end

%======================================================
% FOR EACH VOXEL, IDENTIFY WHETHER ITS 6 NEIGHBOURS ARE WITHIN THE OBJECT.
% IF ANY NEIGHBOUR IS OUTSIDE THE OBJECT, DRAW FACETS BETWEEN THE VOXEL AND
% THAT NEIGHBOUR.
%======================================================

gridINPUTshifted = false(gridSIZE);
if gridSIZE(1)>2
  gridINPUTwithborder = cat(1,false(1,gridSIZE(2),gridSIZE(3)),gridINPUTlogical,false(1,gridSIZE(2),gridSIZE(3)));         %Add border
  gridINPUTshifted    = cat(1,false(1,gridSIZE(2),gridSIZE(3)),gridINPUTshifted,false(1,gridSIZE(2),gridSIZE(3)));      %Add border
  gridINPUTshifted    = gridINPUTshifted + circshift(gridINPUTwithborder,[-1,0,0]) + circshift(gridINPUTwithborder,[1,0,0]);
  gridINPUTshifted    = gridINPUTshifted(2:end-1,:,:);  %Remove border
end
if gridSIZE(2)>2
  gridINPUTwithborder = cat(2,false(gridSIZE(1),1,gridSIZE(3)),gridINPUTlogical,false(gridSIZE(1),1,gridSIZE(3)));         %Add border
  gridINPUTshifted    = cat(2,false(gridSIZE(1),1,gridSIZE(3)),gridINPUTshifted,false(gridSIZE(1),1,gridSIZE(3)));      %Add border
  gridINPUTshifted    = gridINPUTshifted + circshift(gridINPUTwithborder,[0,-1,0]) + circshift(gridINPUTwithborder,[0,1,0]);
  gridINPUTshifted    = gridINPUTshifted(:,2:end-1,:);  %Remove border
end
if gridSIZE(3)>2
  gridINPUTwithborder = cat(3,false(gridSIZE(1),gridSIZE(2),1),gridINPUTlogical,false(gridSIZE(1),gridSIZE(2),1));         %Add border
  gridINPUTshifted    = cat(3,false(gridSIZE(1),gridSIZE(2),1),gridINPUTshifted,false(gridSIZE(1),gridSIZE(2),1));      %Add border
  gridINPUTshifted    = gridINPUTshifted + circshift(gridINPUTwithborder,[0,0,-1]) + circshift(gridINPUTwithborder,[0,0,1]);
  gridINPUTshifted    = gridINPUTshifted(:,:,2:end-1);  %Remove border
end

%Identify the voxels which are at the boundary of the object:
edgevoxellogical = gridINPUTlogical & gridINPUTshifted<6;
edgevoxelindices = find(edgevoxellogical)';
edgevoxelcount   = numel(edgevoxelindices);

%Calculate the number of facets there will be in the final quadrangular mesh:
facetcount = (edgevoxelcount*6 - sum(gridINPUTshifted(edgevoxelindices)) );

%Create an array to record...
%Cols 1-6: Whether each edge voxel's 6 neighbours are inside or outside the object.
neighbourlist = false(edgevoxelcount,6);

%Initialise arrays to store the quadrangular mesh data:
facetsALL  = zeros(facetcount,3,4);
normalsALL = zeros(facetcount,3);
valuesALL  = zeros(facetcount,1);

%Create a counter to keep track of how many facets have been written as the
%following 'for' loop progresses:
facetcountsofar = 0;

[subXALL,subYALL,subZALL] = ind2sub(gridSIZE,edgevoxelindices);

for loopP = 1:edgevoxelcount
  
  subX = subXALL(loopP);
  subY = subYALL(loopP);
  subZ = subZALL(loopP);
  
  if subX==1
    neighbourlist(loopP,1) = 0;
  else
    neighbourlist(loopP,1) = gridINPUTlogical(subX-1,subY,subZ);
  end
  if subY==1
    neighbourlist(loopP,2) = 0;
  else
    neighbourlist(loopP,2) = gridINPUTlogical(subX,subY-1,subZ);
  end
  if subZ==gridSIZE(3)
    neighbourlist(loopP,3) = 0;
  else
    neighbourlist(loopP,3) = gridINPUTlogical(subX,subY,subZ+1);
  end
  if subY==gridSIZE(2)
    neighbourlist(loopP,4) = 0;
  else
    neighbourlist(loopP,4) = gridINPUTlogical(subX,subY+1,subZ);
  end
  if subZ==1
    neighbourlist(loopP,5) = 0;
  else
    neighbourlist(loopP,5) = gridINPUTlogical(subX,subY,subZ-1);
  end
  if subX==gridSIZE(1)
    neighbourlist(loopP,6) = 0;
  else
    neighbourlist(loopP,6) = gridINPUTlogical(subX+1,subY,subZ);
  end
  
  facetCOtemp         = zeros(6-sum(neighbourlist(loopP,:)),3,4);
  normalCOtemp        = zeros(6-sum(neighbourlist(loopP,:)),3);
  facetcountthisvoxel = 0;
  
  if neighbourlist(loopP,1)==0   %Neighbouring voxel in the -x direction
    facetcountthisvoxel                    = facetcountthisvoxel+1;
    facetcountsofar                        = facetcountsofar+1;
    facetCOtemp(facetcountthisvoxel,1:3,1) = [ gridXlower(subX),gridYlower(subY),gridZlower(subZ) ];
    facetCOtemp(facetcountthisvoxel,1:3,2) = [ gridXlower(subX),gridYlower(subY),gridZupper(subZ) ];
    facetCOtemp(facetcountthisvoxel,1:3,3) = [ gridXlower(subX),gridYupper(subY),gridZupper(subZ) ];
    facetCOtemp(facetcountthisvoxel,1:3,4) = [ gridXlower(subX),gridYupper(subY),gridZlower(subZ) ];
    normalCOtemp(facetcountthisvoxel,1:3)  = [-1,0,0];
  end
  if neighbourlist(loopP,2)==0   %Neighbouring voxel in the -y direction
    facetcountthisvoxel                    = facetcountthisvoxel+1;
    facetcountsofar                        = facetcountsofar+1;
    facetCOtemp(facetcountthisvoxel,1:3,1) = [ gridXlower(subX),gridYlower(subY),gridZlower(subZ) ];
    facetCOtemp(facetcountthisvoxel,1:3,2) = [ gridXupper(subX),gridYlower(subY),gridZlower(subZ) ];
    facetCOtemp(facetcountthisvoxel,1:3,3) = [ gridXupper(subX),gridYlower(subY),gridZupper(subZ) ];
    facetCOtemp(facetcountthisvoxel,1:3,4) = [ gridXlower(subX),gridYlower(subY),gridZupper(subZ) ];
    normalCOtemp(facetcountthisvoxel,1:3)  = [0,-1,0];
  end
  if neighbourlist(loopP,3)==0   %Neighbouring voxel in the +z direction
    facetcountthisvoxel                    = facetcountthisvoxel+1;
    facetcountsofar                        = facetcountsofar+1;
    facetCOtemp(facetcountthisvoxel,1:3,1) = [ gridXupper(subX),gridYlower(subY),gridZupper(subZ) ];
    facetCOtemp(facetcountthisvoxel,1:3,2) = [ gridXupper(subX),gridYupper(subY),gridZupper(subZ) ];
    facetCOtemp(facetcountthisvoxel,1:3,3) = [ gridXlower(subX),gridYupper(subY),gridZupper(subZ) ];
    facetCOtemp(facetcountthisvoxel,1:3,4) = [ gridXlower(subX),gridYlower(subY),gridZupper(subZ) ];
    normalCOtemp(facetcountthisvoxel,1:3)  = [0,0,1];
  end
  if neighbourlist(loopP,4)==0   %Neighbouring voxel in the +y direction
    facetcountthisvoxel                    = facetcountthisvoxel+1;
    facetcountsofar                        = facetcountsofar+1;
    facetCOtemp(facetcountthisvoxel,1:3,1) = [ gridXupper(subX),gridYupper(subY),gridZlower(subZ) ];
    facetCOtemp(facetcountthisvoxel,1:3,2) = [ gridXlower(subX),gridYupper(subY),gridZlower(subZ) ];
    facetCOtemp(facetcountthisvoxel,1:3,3) = [ gridXlower(subX),gridYupper(subY),gridZupper(subZ) ];
    facetCOtemp(facetcountthisvoxel,1:3,4) = [ gridXupper(subX),gridYupper(subY),gridZupper(subZ) ];
    normalCOtemp(facetcountthisvoxel,1:3)  = [0,1,0];
  end
  if neighbourlist(loopP,5)==0   %Neighbouring voxel in the -z direction
    facetcountthisvoxel                    = facetcountthisvoxel+1;
    facetcountsofar                        = facetcountsofar+1;
    facetCOtemp(facetcountthisvoxel,1:3,1) = [ gridXlower(subX),gridYlower(subY),gridZlower(subZ) ];
    facetCOtemp(facetcountthisvoxel,1:3,2) = [ gridXlower(subX),gridYupper(subY),gridZlower(subZ) ];
    facetCOtemp(facetcountthisvoxel,1:3,3) = [ gridXupper(subX),gridYupper(subY),gridZlower(subZ) ];
    facetCOtemp(facetcountthisvoxel,1:3,4) = [ gridXupper(subX),gridYlower(subY),gridZlower(subZ) ];
    normalCOtemp(facetcountthisvoxel,1:3)  = [0,-1,0];
  end
  if neighbourlist(loopP,6)==0   %Neighbouring voxel in the +x direction
    facetcountthisvoxel                    = facetcountthisvoxel+1;
    facetcountsofar                        = facetcountsofar+1;
    facetCOtemp(facetcountthisvoxel,1:3,1) = [ gridXupper(subX),gridYupper(subY),gridZlower(subZ) ];
    facetCOtemp(facetcountthisvoxel,1:3,2) = [ gridXupper(subX),gridYupper(subY),gridZupper(subZ) ];
    facetCOtemp(facetcountthisvoxel,1:3,3) = [ gridXupper(subX),gridYlower(subY),gridZupper(subZ) ];
    facetCOtemp(facetcountthisvoxel,1:3,4) = [ gridXupper(subX),gridYlower(subY),gridZlower(subZ) ];
    normalCOtemp(facetcountthisvoxel,1:3)  = [1,0,0];
  end
  
  facetsALL(facetcountsofar-facetcountthisvoxel+1:facetcountsofar,:,:) = facetCOtemp;
  normalsALL(facetcountsofar-facetcountthisvoxel+1:facetcountsofar,:)  = normalCOtemp;
  valuesALL(facetcountsofar-facetcountthisvoxel+1:facetcountsofar)     = gridINPUT(edgevoxelindices(loopP));

end

%======================================================
% PLOT THE QUADRANGULAR SURFACE MESH
%======================================================

if colYN==1
  
  %Define the colormap and resolution
  if exist('cmap','var')
    cres = size(cmap,1);
  else
    cres = 16;
    cmap = jet(cres);
  end

  %Set the colorbar range
  if exist('clim','var')==1
    crange      = [min(clim(:)),max(clim(:))];
    valuesALL(valuesALL<min(clim(:))) = min(clim(:));
    valuesALL(valuesALL>max(clim(:))) = max(clim(:));
    valuesALL  = valuesALL - min(clim(:));
    valuesALL  = 1 + round( (cres-1)*valuesALL./(max(clim(:))-min(clim(:))) );    % The '1 + ...' ensures that the values are within [1:16] rather than [0:16]
  else
    crange      = [min(valuesALL(:)),max(valuesALL(:))];
    valuesALL  = valuesALL - min(valuesALL(:));
    valuesALL  = 1 + round( (cres-1)*valuesALL./max(valuesALL(:)) );    % The '1 + ...' ensures that the values are within [1:16] rather than [0:16]
  end


  if crange(1) ~= crange(end)
    %If the facets have a range of colours
    hpat = cell(1,cres);
    for loopJ = 1:cres
      xco         = squeeze( facetsALL(valuesALL==loopJ,1,:) )';
      yco         = squeeze( facetsALL(valuesALL==loopJ,2,:) )';
      zco         = squeeze( facetsALL(valuesALL==loopJ,3,:) )';
      hpat{loopJ} = patch(xco,yco,zco,cmap(loopJ,:));
      set(hpat{loopJ},'EdgeColor',cmap(loopJ,:)/2);
    end
    set(gca, 'CLim', crange);
    if cbar==1
      hcbar = colorbar('NorthOutside','YLim',crange);
    elseif cbar==2
      hcbar = colorbar('EastOutside','YLim',crange);
    elseif cbar==3
      hcbar = colorbar('SouthOutside','YLim',crange);
    elseif cbar==4
      hcbar = colorbar('WestOutside','YLim',crange);
    end
    colormap(cmap);
  else
    %If the facets are all the same colour
    xco  = squeeze( facetsALL(:,1,:) )';
    yco  = squeeze( facetsALL(:,2,:) )';
    zco  = squeeze( facetsALL(:,3,:) )';
    hpat = patch(xco,yco,zco,cmap(round(end/2),:));
    set(hpat,'EdgeColor',cmap(round(end/2),:)/2);
    set(gca,'CLim',crange+[-1,1]);
    if cbar==1
      hcbar = colorbar('NorthOutside','YLim',crange+[-1,1]);
    elseif cbar==2
      hcbar = colorbar('EastOutside','YLim',crange+[-1,1]);
    elseif cbar==3
      hcbar = colorbar('SouthOutside','YLim',crange+[-1,1]);
    elseif cbar==4
      hcbar = colorbar('WestOutside','YLim',crange+[-1,1]);
    end
    colormap(cmap);
  end

elseif colYN==0
  
  %Define the colormap and resolution
  if exist('cmap','var')==1
    cmap = cmap(:)';  %Ensure colourmap is a 1x3 RGB triplet
  else
    cmap = [0,0,1];
  end

  %Plot a simple logical array where all facets are the same colour
  xco  = squeeze( facetsALL(:,1,:) )';
  yco  = squeeze( facetsALL(:,2,:) )';
  zco  = squeeze( facetsALL(:,3,:) )';
  hpat = patch(xco,yco,zco,cmap);
  set(hpat,'EdgeColor',cmap/2);

end
axis equal tight;


%======================================================
% SET THE OUTPUT PARAMETERS
%======================================================

if nargout>=1
  varargout(1) = {hpat};
end
if nargout==2
  if exist('hcbar','var')==1
    varargout(2) = {hcbar};
  else
    varargout(2) = {[]};
  end
end

Contact us