function [node,elem,face]=cgalv2m(vol,opt,maxvol)
%
% [node,elem,face]=cgalv2m(vol,opt,maxvol)
%
% wrapper for CGAL 3D mesher (CGAL 3.5 or up)
% convert a binary (or multi-valued) volume to tetrahedral mesh
%
% http://www.cgal.org/Manual/3.5/doc_html/cgal_manual/Mesh_3/Chapter_main.html
%
% author: Qianqian Fang (q.fang at neu.edu)
%
% input:
%	 vol: a volumetric binary image
%	 ix,iy,iz: subvolume selection indices in x,y,z directions
%	 opt: parameters for CGAL mesher, if opt is a structure, then
%	     opt.radbound: defines the maximum surface element size
%	     opt.angbound: defines the miminum angle of a surface triangle
%	     opt.distbound: defines the maximum distance between the 
%		 center of the surface bounding circle and center of the 
%		 element bounding sphere
%	     opt.reratio:  maximum radius-edge ratio
%	     if opt is a scalar, it only specifies radbound.
%	 maxvol: target maximum tetrahedral elem volume
%
% output:
%	 node: output, node coordinates of the tetrahedral mesh
%	 elem: output, element list of the tetrahedral mesh, the last 
%	      column is the region id
%	 face: output, mesh surface element list of the tetrahedral mesh
%	      the last column denotes the boundary ID
%	      note: each triangle will appear twice in the face list with each
%		    one attaches to each side of the interface. one can remove
%		    the redundant triangles by unique(face(:,1:3),'rows')
%
% -- this function is part of iso2mesh toolbox (http://iso2mesh.sf.net)
%

fprintf(1,'creating surface and tetrahedral mesh from a multi-domain volume ...\n');

if(~(islogical(vol) || isa(vol,'uint8')))
	error('cgalmesher can only handle uint8 volumes, you have to convert your image to unit8 first.');
end

if(~any(vol))
        error('no labeled regions found in the input volume.');
end

exesuff=getexeext;
exesuff=fallbackexeext(exesuff,'cgalmesh');

ang=30;
ssize=6;
approx=0.5;
reratio=3;

if(~isstruct(opt))
	ssize=opt;
end

if(isstruct(opt) && length(opt)==1)  % does not support settings for multiple labels
        ssize=jsonopt('radbound',ssize,opt);
        ang=jsonopt('angbound',ang,opt);
        approx=jsonopt('distbound',approx,opt);
        reratio=jsonopt('reratio',reratio,opt);
end

saveinr(vol,mwpath('pre_cgalmesh.inr'));
deletemeshfile(mwpath('post_cgalmesh.mesh'));

randseed=hex2dec('623F9A9E'); % "U+623F U+9A9E"

if(~isempty(getvarfrom('base','ISO2MESH_RANDSEED')))
        randseed=getvarfrom('base','ISO2MESH_RANDSEED');
end

if(ischar(maxvol))
    format_maxvol='%s';
else
    format_maxvol='%f';
end
cmd=sprintf(['"%s%s" "%s" "%s" %f %f %f %f ' format_maxvol ' %d'],mcpath('cgalmesh'),exesuff,...
    mwpath('pre_cgalmesh.inr'),mwpath('post_cgalmesh.mesh'),ang,ssize,...
    approx,reratio,maxvol,randseed);
system(cmd);
if(~exist(mwpath('post_cgalmesh.mesh'),'file'))
    error(['output file was not found, failure was encountered when running command: \n',cmd]);
end
[node,elem,face]=readmedit(mwpath('post_cgalmesh.mesh'));

% if a transformation matrix/offset vector supplied, apply them
if (isstruct(opt) && length(opt)==1)
    if(isfield(opt,'A') && isfield(opt,'B'))
        node(:,1:3)=(opt.A*node(:,1:3)'+repmat(opt.B(:),1,size(node,1)))';
    end
end

fprintf(1,'node number:\t%d\ntriangles:\t%d\ntetrahedra:\t%d\nregions:\t%d\n',...
    size(node,1),size(face,1),size(elem,1),length(unique(elem(:,end))));
fprintf(1,'surface and volume meshes complete\n');

if(size(node,1)>0)
    [node,elem,face]=sortmesh(node(1,:),node,elem,1:4,face,1:3);
end

node=node+0.5;
elem(:,1:4)=meshreorient(node(:,1:3),elem(:,1:4));

