diff --git a/.github/workflows/run_test.yml b/.github/workflows/run_test.yml
index 76c2b97..4c3d874 100644
--- a/.github/workflows/run_test.yml
+++ b/.github/workflows/run_test.yml
@@ -27,9 +27,9 @@ jobs:
brew install gnuplot
brew install octave
else
- curl --retry 3 -kL http://cdimage.debian.org/mirror/gnu.org/gnu/octave/windows/octave-5.2.0-w64-64.7z --output octave_5.2.0.7z
- 7z x octave_5.2.0.7z -ooctave -y
- echo "$PWD/octave/octave-5.2.0-w64-64/mingw64/bin" >> $GITHUB_PATH
+ curl --retry 3 -kL http://cdimage.debian.org/mirror/gnu.org/gnu/octave/windows/octave-6.2.0-w64-64.7z --output octave_6.2.0.7z
+ 7z x octave_6.2.0.7z -ooctave -y
+ echo "$PWD/octave/octave-6.2.0-w64-64/mingw64/bin" >> $GITHUB_PATH
fi
- name: Install octave-image (Windows)
if: ${{ runner.os == 'Windows' }}
diff --git a/i2m.prj b/i2m.prj
index bea4ce7..b0eac45 100644
--- a/i2m.prj
+++ b/i2m.prj
@@ -3,11 +3,11 @@
i2m
- 0.8
+ 0.9
Qianqian Fang
q.fang at neu.edu
Northeastern University
- I2M is an integrated GUI for the 3D meshing toolbox Iso2Mesh developed by Qianqian Fang
+ I2M is an integrated graphical user interface (GUI) for the 3D meshing toolbox Iso2Mesh developed by Qianqian Fang
Iso2Mesh is a free matlab/octave-based mesh generation and processing toolbox. It can create 3D tetrahedral finite element (FE) mesh from surfaces, 3D binary and gray-scale volumetric images such as segmented MRI/CT scans.
@@ -103,7 +103,6 @@
${PROJECT_ROOT}/fallbackexeext.m
${PROJECT_ROOT}/finddisconnsurf.m
${PROJECT_ROOT}/getexeext.m
- ${PROJECT_ROOT}/getoptkey.m
${PROJECT_ROOT}/getplanefrom3pt.m
${PROJECT_ROOT}/getvarfrom.m
${PROJECT_ROOT}/img2mesh.fig
@@ -140,7 +139,6 @@
${PROJECT_ROOT}/readinr.m
${PROJECT_ROOT}/readmedit.m
${PROJECT_ROOT}/readmptiff.m
- ${PROJECT_ROOT}/readnifti.m
${PROJECT_ROOT}/readoff.m
${PROJECT_ROOT}/readsmf.m
${PROJECT_ROOT}/readtetgen.m
@@ -152,7 +150,6 @@
${PROJECT_ROOT}/rotmat2vec.m
${PROJECT_ROOT}/s2m.m
${PROJECT_ROOT}/s2v.m
- ${PROJECT_ROOT}/savegts.m
${PROJECT_ROOT}/saveinr.m
${PROJECT_ROOT}/savejmesh.m
${PROJECT_ROOT}/savejson.m
@@ -178,6 +175,31 @@
${PROJECT_ROOT}/vol2restrictedtri.m
${PROJECT_ROOT}/vol2surf.m
${PROJECT_ROOT}/volface.m
+ ${PROJECT_ROOT}/base64decode.m
+ ${PROJECT_ROOT}/base64encode.m
+ ${PROJECT_ROOT}/blosc2decode.m
+ ${PROJECT_ROOT}/blosc2encode.m
+ ${PROJECT_ROOT}/decodevarname.m
+ ${PROJECT_ROOT}/encodevarname.m
+ ${PROJECT_ROOT}/fast_match_bracket.m
+ ${PROJECT_ROOT}/fillholes3d.m
+ ${PROJECT_ROOT}/fillsurf.m
+ ${PROJECT_ROOT}/filterjsonmmap.m
+ ${PROJECT_ROOT}/getfromjsonpath.m
+ ${PROJECT_ROOT}/jdatadecode.m
+ ${PROJECT_ROOT}/jdataencode.m
+ ${PROJECT_ROOT}/loadbj.m
+ ${PROJECT_ROOT}/loadh5.m
+ ${PROJECT_ROOT}/loadmsgpack.m
+ ${PROJECT_ROOT}/match_bracket.m
+ ${PROJECT_ROOT}/meshquality.m
+ ${PROJECT_ROOT}/meshreorient.m
+ ${PROJECT_ROOT}/nestbracket2dim.m
+ ${PROJECT_ROOT}/regrouph5.m
+ ${PROJECT_ROOT}/remeshsurf.m
+ ${PROJECT_ROOT}/savebj.m
+ ${PROJECT_ROOT}/surfreorient.m
+ ${PROJECT_ROOT}/transposemat.m
${PROJECT_ROOT}/i2m/for_testing/readme.txt
@@ -187,33 +209,6 @@
- /drives/hoyi1/users/shared/MATLAB/R2016a
-
-
-
-
-
-
-
-
- true
-
-
-
-
- true
-
-
-
-
- true
-
-
-
-
- true
-
-
true
diff --git a/img2mesh.m b/img2mesh.m
index 54a5da7..67b4809 100644
--- a/img2mesh.m
+++ b/img2mesh.m
@@ -35,6 +35,10 @@
gui_State.gui_Callback = str2func(varargin{1});
end
+if (isdeployed)
+ assignin('base', 'ISO2MESH_BIN', [pwd filesep 'bin']);
+end
+
if nargout
[varargout{1:nargout}] = gui_mainfcn(gui_State, varargin{:});
else
@@ -89,14 +93,28 @@ function i2m_OpeningFcn(hObject, eventdata, handles, varargin)
mimeshing.Separator = 'on';
mirefresh.Separator = 'on';
+hbackground = axes('units', 'normalized', 'position', [0 0 1 1]);
+uistack(hbackground, 'down');
+text(0.97, 0, 'Iso2Mesh', 'FontSize', 40, 'Color', [1 1 1], 'Parent', hbackground, ...
+ 'HorizontalAlignment', 'right', 'VerticalAlignment', 'bottom', ...
+ 'FontWeight', 'bold', 'FontName', 'sans', 'FontAngle', 'italic');
+hold(hbackground, 'on');
+text(0.972, 0.002, 'Iso2Mesh', 'FontSize', 40, 'Color', [1 1 1] * 0.8, 'Parent', hbackground, ...
+ 'HorizontalAlignment', 'right', 'VerticalAlignment', 'bottom', ...
+ 'FontWeight', 'bold', 'FontName', 'sans', 'FontAngle', 'italic');
+set(hbackground, 'handlevisibility', 'off', 'visible', 'off');
+
root = get(handles.fgI2M, 'userdata');
if (isempty(root))
root = struct('graph', digraph, 'menu', cm);
end
set(handles.fgI2M, 'userdata', root);
-set(handles.axFlow, 'position', [0 0 1 1]);
-set(handles.axPreview, 'position', [0 0 1 1]);
+set(handles.fgI2M, 'color', [0.78, 0.91, 1.0]);
+set(handles.axFlow, 'position', [0.01 0.01 1 - 0.02 1 - 0.02]);
+
+set(handles.axPreview, 'position', [0.01 0.01 1 - 0.02 1 - 0.02]);
+set(handles.axPreview, 'color', get(handles.fgI2M, 'color'));
set(handles.fgI2M, 'UIContextMenu', handles.meCreate);
@@ -135,21 +153,21 @@ function processdata(source, callbackdata, handles)
[newdata, newtype] = v2sgui(nodedata);
prefix = 'Vol2Surf';
else
- error('no volume data found');
+ errordlg('no volume data found');
end
case 'Volume to mesh'
if (nodetype.hasvol)
[newdata, newtype] = v2mgui(nodedata);
prefix = 'Vol2Mesh';
else
- error('no volume data found');
+ errordlg('no volume data found');
end
case 'Surface to mesh'
if (nodetype.hasnode && nodetype.hasface)
[newdata, newtype] = s2mgui(nodedata);
prefix = 'Surf2Mesh';
else
- error('no surface data found');
+ errordlg('no surface data found');
end
case 'Surface to volume'
if (nodetype.hasnode && nodetype.hasface)
@@ -158,20 +176,20 @@ function processdata(source, callbackdata, handles)
if (isempty(ndiv))
return
end
- newdata.vol = s2v(nodedata.node, nodedata.face, str2num(ndiv{1}));
+ newdata.vol = s2v(nodedata.node, nodedata.face, str2double(ndiv{1}));
newtype.hasvol = 1;
prefix = 'Surf2Vol';
else
- error('no surface data found');
+ errordlg('no surface data found');
end
case 'Close and fill volume'
if (nodetype.hasvol)
rad = inputdlg('maximum gap length in voxel (scalar)', 'Close and fill a volume', 1, {'1'});
- newdata.vol = fillholes3d(nodedata.vol, str2num(rad{1}));
+ newdata.vol = fillholes3d(nodedata.vol, str2double(rad{1}));
newtype = nodetype;
prefix = 'FillVol';
else
- error('no volume data found');
+ errordlg('no volume data found');
end
case 'Extract surface'
if (isstruct(nodetype) && isfield(nodetype, 'hasvol') && nodetype.hasvol)
@@ -194,7 +212,7 @@ function processdata(source, callbackdata, handles)
newtype = nodetype;
prefix = 'CleanSurf';
else
- error('no surface data found');
+ errordlg('no surface data found');
end
case 'Repair surface'
if (nodetype.hasnode && nodetype.hasface)
@@ -202,7 +220,7 @@ function processdata(source, callbackdata, handles)
newtype = nodetype;
prefix = 'RepairSurf';
else
- error('no surface data found');
+ errordlg('no surface data found');
end
case 'Smooth surface'
if (nodetype.hasnode && nodetype.hasface)
@@ -213,23 +231,23 @@ function processdata(source, callbackdata, handles)
end
newdata = nodedata;
newtype = nodetype;
- newdata.node = sms(nodedata.node, nodedata.face, str2num(res{2}), str2num(res{3}), res{1});
+ newdata.node = sms(nodedata.node, nodedata.face, str2double(res{2}), str2double(res{3}), res{1});
prefix = 'SmoothSurf';
else
- error('no surface data found');
+ errordlg('no surface data found');
end
case 'Simplify surface'
if (nodetype.hasnode && nodetype.hasface)
res = inputdlg('Percentage of edges to keep (0-1):', ...
- 'Simplify mesh', [1], {'1'});
+ 'Simplify mesh', 1, {'1'});
if (isempty(res))
return
end
- [newdata.node, newdata.face] = meshresample(nodedata.node, nodedata.face, str2num(res{1}));
+ [newdata.node, newdata.face] = meshresample(nodedata.node, nodedata.face, str2double(res{1}));
newtype = nodetype;
prefix = 'SimplifySurf';
else
- error('no surface data found');
+ errordlg('no surface data found');
end
case 'Remesh surface'
if (nodetype.hasnode && nodetype.hasface)
@@ -238,15 +256,15 @@ function processdata(source, callbackdata, handles)
if (isempty(res))
return
end
- opt.gridsize = str2num(res{1});
- opt.closesize = str2num(res{2});
- opt.elemsize = str2num(res{3});
+ opt.gridsize = str2double(res{1});
+ opt.closesize = str2double(res{2});
+ opt.elemsize = str2double(res{3});
[newdata.node, newdata.face] = remeshsurf(nodedata.node, nodedata.face, opt);
newtype.hasnode = 1;
newtype.hasface = 1;
prefix = 'RemeshSurf';
else
- error('no surface data found');
+ errordlg('no surface data found');
end
case 'Tessellate surface'
if (nodetype.hasnode && nodetype.hasface)
@@ -256,7 +274,7 @@ function processdata(source, callbackdata, handles)
newtype.haselem = 1;
prefix = 'TessMesh';
else
- error('no surface data found');
+ errordlg('no surface data found');
end
case 'Reorient mesh elements'
if (nodetype.hasnode && nodetype.haselem)
@@ -268,7 +286,7 @@ function processdata(source, callbackdata, handles)
newtype = nodetype;
prefix = 'ReorientSurf';
else
- error('no surface or tetrahedral mesh data found');
+ errordlg('no surface or tetrahedral mesh data found');
end
case 'Mesh quality histogram'
if (nodetype.hasnode && nodetype.haselem)
@@ -342,7 +360,7 @@ function processdata(source, callbackdata, handles)
if (nodetype2.hasnode && nodetype2.haselem)
nodedata2.face = volface(nodedata2.elem);
else
- error('Second operand does not contain a surface');
+ errordlg('Second operand does not contain a surface');
end
end
op = source.Label;
@@ -369,21 +387,20 @@ function processdata(source, callbackdata, handles)
updategraph(root, handles);
case 'Rename'
newname = inputdlg('Define a new name:', ...
- 'Rename', 1, {root.graph.Nodes.Name{nodeid}});
+ 'Rename', 1, root.graph.Nodes.Name(nodeid));
if (isempty(newname))
return
end
if (isempty(newname{1}) || ~isempty(cell2mat(regexp(root.graph.Nodes.Name, ['^' newname{1} '$']))))
- error('empty or duplicated node name');
+ errordlg('empty or duplicated node name');
end
root.graph.Nodes.Name{nodeid} = newname{1};
updategraph(root, handles);
case 'Save as'
if (~nodetype.haselem && ~nodetype.hasnode)
- error('selected data does not have a mesh');
- return
+ errordlg('selected data does not have a mesh');
end
- filter = {'*.jmesh'; '*.*'};
+ filter = {'*.jmsh'; '*.*'};
[file, path] = uiputfile(filter, 'Export mesh');
if ~isequal(file, 0) && ~isequal(path, 0)
if (nodetype.haselem)
@@ -397,11 +414,11 @@ function processdata(source, callbackdata, handles)
if (exist('newdata', 'var') && exist('newtype', 'var'))
cla(handles.axPreview);
cla(handles.axFlow);
- newdata.preview = getpreview(newdata, newtype, [400, 400]);
+ newdata.preview = getpreview(newdata, newtype, [800, 800]);
[newkey, root.graph] = addnodewithdata(handles, newdata, newtype, prefix);
- root.graph = addedge(root.graph, {root.graph.Nodes.Name{nodeid}}, {newkey});
+ root.graph = addedge(root.graph, root.graph.Nodes.Name(nodeid), {newkey});
if (strcmp(source.Parent.Type, 'uimenu') && strcmp(source.Parent.Label, 'Surface boolean'))
- root.graph = addedge(root.graph, {root.graph.Nodes.Name{nodeid2}}, {newkey});
+ root.graph = addedge(root.graph, root.graph.Nodes.Name(nodeid2), {newkey});
end
updategraph(root, handles);
end
@@ -483,7 +500,7 @@ function plotfigevent(hobject, event)
return
end
-opt = struct('radbound', str2num(res{2}), 'distbound', str2num(res{3}));
+opt = struct('radbound', str2double(res{2}), 'distbound', str2double(res{3}));
[newdata.node, newdata.face] = v2s(data.vol, eval(res{1}), opt, res{4});
newtype.hasnode = 1;
newtype.hasface = 1;
@@ -505,7 +522,7 @@ function plotfigevent(hobject, event)
return
end
-opt = struct('radbound', str2num(res{2}), 'distbound', str2num(res{3}));
+opt = struct('radbound', str2double(res{2}), 'distbound', str2double(res{3}));
[newdata.node, newdata.elem, newdata.face] = v2m(data.vol, eval(res{1}), ...
opt, res{4});
newtype.hasnode = 1;
@@ -514,7 +531,7 @@ function plotfigevent(hobject, event)
% ----------------------------------------------------------------
function img = getpreview(nodedata, nodetype, imsize)
-hfpreview = figure('visible', 'off');
+hfpreview = figure('visible', 'off', 'position', [0, 0, imsize(1), imsize(2)]);
ax = axes('parent', hfpreview, 'Units', 'pixels', 'position', [1, 1, imsize(1), imsize(2)]);
if (isfield(nodetype, 'haselem') && nodetype.haselem)
plotmesh(nodedata.node, [], nodedata.elem, 'linestyle', ':', 'edgealpha', 0.3, 'parent', ax);
@@ -552,8 +569,8 @@ function plotfigevent(hobject, event)
end
[newdata.node, newdata.elem, newdata.face] = ...
- s2m(data.node, data.face, str2num(res{1}), ...
- str2num(res{2}), res{3}, eval(res{4}), eval(res{5}));
+ s2m(data.node, data.face, str2double(res{1}), ...
+ str2double(res{2}), res{3}, eval(res{4}), eval(res{5}));
newtype.hasnode = 1;
newtype.hasface = 1;
newtype.haselem = 1;
@@ -582,14 +599,14 @@ function miAbout_Callback(hObject, eventdata, handles)
helpmsg = {
'\bf\fontsize{12}I2M: An Integrated GUI for Iso2Mesh Meshing Toolbox\rm\fontsize{10}'
''
- 'Copyright (c) 2018 Qianqian Fang '
+ 'Copyright (c) 2018-2024 Qianqian Fang '
''
'Computational Optics&Translational Imaging Lab (http://fanglab.org)'
'Department of Bioengineering'
'Northeastern University'
'360 Huntington Ave, Boston, MA 02115, USA'
''
- 'URL: http://iso2mesh.sourceforge.net'
+ 'URL: http://iso2mesh.sf.net'
''};
opt.Interpreter = 'tex';
@@ -610,20 +627,20 @@ function miSphere_Callback(hObject, eventdata, handles)
return
end
newtype = dummytype;
-opt = str2num(res{3});
-if (str2num(res{4}) == 0)
+opt = str2double(res{3});
+if (str2double(res{4}) == 0)
[newdata.node, newdata.face] = meshasphere(eval(res{1}), ...
- str2num(res{2}), opt);
+ str2double(res{2}), opt);
else
[newdata.node, newdata.face, newdata.elem] = meshasphere(eval(res{1}), ...
- str2num(res{2}), opt, str2num(res{4}));
+ str2double(res{2}), opt, str2double(res{4}));
newtype.haselem = 1;
end
newtype.hasnode = 1;
newtype.hasface = 1;
if (exist('newdata', 'var') && exist('newtype', 'var'))
- newkey = addnodewithdata(handles, newdata, newtype, 'Sphere');
+ addnodewithdata(handles, newdata, newtype, 'Sphere');
end
% --------------------------------------------------------------------
@@ -639,19 +656,19 @@ function miBox_Callback(hObject, eventdata, handles)
return
end
newtype = dummytype;
-opt = str2num(res{3});
-if (str2num(res{4}) == 0)
+opt = str2double(res{3});
+if (str2double(res{4}) == 0)
[newdata.node, newdata.face] = meshabox(eval(res{1}), eval(res{2}), opt);
else
[newdata.node, newdata.face, newdata.elem] = meshabox(eval(res{1}), ...
- eval(res{2}), opt, str2num(res{4}));
+ eval(res{2}), opt, str2double(res{4}));
newtype.haselem = 1;
end
newtype.hasnode = 1;
newtype.hasface = 1;
if (exist('newdata', 'var') && exist('newtype', 'var'))
- newkey = addnodewithdata(handles, newdata, newtype, 'Box');
+ addnodewithdata(handles, newdata, newtype, 'Box');
end
% --------------------------------------------------------------------
@@ -668,22 +685,22 @@ function miCylinder_Callback(hObject, eventdata, handles)
return
end
newtype = dummytype;
-opt = str2num(res{4});
-maxvol = str2num(res{5});
+opt = str2double(res{4});
+maxvol = str2double(res{5});
if (maxvol == 0)
[newdata.node, newdata.face] = meshacylinder(eval(res{1}), eval(res{2}), ...
- str2num(res{3}), opt);
+ str2double(res{3}), opt);
else
[newdata.node, newdata.face, newdata.elem] = meshacylinder(eval(res{1}), eval(res{2}), ...
- str2num(res{3}), opt, maxvol);
+ str2double(res{3}), opt, maxvol);
newtype.haselem = 1;
end
newtype.hasnode = 1;
newtype.hasface = 1;
if (exist('newdata', 'var') && exist('newtype', 'var'))
- newkey = addnodewithdata(handles, newdata, newtype, 'Cyl');
+ addnodewithdata(handles, newdata, newtype, 'Cyl');
end
% --------------------------------------------------------------------
@@ -691,33 +708,38 @@ function miLoadVol_Callback(hObject, eventdata, handles)
nodedata = struct;
nodetype = dummytype;
-filters = {'*.nii;*.hdr;*.img;*.tif;*.tiff;*.inr;*.bin;*.ubj', '3D volume file (*.nii;*.hdr;*.img;*.tif;*.tiff;*.inr;*.bin;*.ubj)'; ...
- '*.nii', 'Nifti file (*.nii)'; ...
+filters = {'*.jnii;*.nii;*.hdr;*.img;*.tif;*.tiff;*.inr;*.bin;*.ubj', '3D volume file (*.jnii;*.nii;*.hdr;*.img;*.tif;*.tiff;*.inr;*.bin;*.ubj)'; ...
+ '*.jnii', 'JNIFTI file (*.jnii)'; ...
+ '*.nii', 'NIFTI file (*.nii)'; ...
'*.hdr;*.img', 'Analyze 7.5 file (*.hdr;*.img)'; ...
'*.tif;*.tiff', 'Multipage TIFF file (*.tif)'; ...
'*.inr', 'INR image (*.inr)'; ...
'*.bin', 'Binary file (*.bin)'; ...
- '*.ubj', 'Universal JSON (*.ubj)'; ...
+ '*.jdb', 'Binary JSON (*.jdb)'; ...
'*.*', 'All (*.*)'};
-[file, path, idx] = uigetfile(filters);
+[file, path] = uigetfile(filters);
if isequal(file, 0)
return
else
- if (regexp(file, '\.[Nn][Ii][Ii]$'))
- im = readnifti(fullfile(path, file));
- nodedata.vol = im.img;
+ if (~isempty(regexpi(file, '\.j*nii(\.gz)*$', 'once')))
+ im = loadnifti(fullfile(path, file));
+ if (isfield(im, 'NIFTIData'))
+ nodedata.vol = im.NIFTIData;
+ else
+ nodedata.vol = im.img;
+ end
nodetype.hasvol = 1;
- elseif (regexp(file, '(\.[Hh][Dd][Rr]$|\.[Ii][Mm][Gg]$)'))
- im = readnifti(fullfile(path, file));
+ elseif (~isempty(regexpi(file, '(\.hdr$|\.[img$)', 'once')))
+ im = loadnifti(fullfile(path, file));
nodedata.vol = im.img;
nodetype.hasvol = 1;
- elseif (regexp(file, '\.[Tt][Ii][Ff][Ff]*$'))
+ elseif (~isempty(regexpi(file, '\.tiff*$', 'once')))
nodedata.vol = readmptiff(fullfile(path, file));
nodetype.hasvol = 1;
- elseif (regexp(file, '\.[Ii][Nn][Rr]$'))
+ elseif (~isempty(regexpi(file, '\.inr$', 'once')))
nodedata.vol = readinr(fullfile(path, file));
nodetype.hasvol = 1;
- elseif (regexp(file, '\.[Bb][Ii][Nn]$'))
+ elseif (~isempty(regexpi(file, '\.bin$', 'once')))
prompt = {'Dimension (1x3 vector):', ...
'Datatype (short,float,double,integer,...):'};
title = 'Load generic binary file';
@@ -727,10 +749,15 @@ function miLoadVol_Callback(hObject, eventdata, handles)
if (isok == 0)
return
end
- nodedata.vol = loadmc2(fullfile(path, file), eval(res{1}), res{2});
+ fid = fopen(fullfile(path, file), 'rb');
+ if (fid == 0)
+ errordlg('can not open the specified file');
+ end
+ nodedata.vol = fread(fid, eval(res{1}), res{2});
+ fclose(fid);
nodetype.hasvol = 1;
- elseif (regexp(file, '\.[Uu][Bb][Jj]$'))
- nodedata = loadbj(fullfile(path, file));
+ elseif (~isempty(regexpi(file, '\.jdb$', 'once')))
+ nodedata = loadjd(fullfile(path, file));
if (isstruct(nodedata) && isfield(nodedata, 'vol'))
nodetype.hasvol = 1;
end
@@ -751,27 +778,28 @@ function miLoadMesh_Callback(hObject, eventdata, handles)
nodedata = struct;
nodetype = dummytype;
-filters = {'*.jmesh;*.off;*.medit;*.smf;*.json', '3D Mesh files (*.jmesh;*.off;*.medit;*.smf;*.json)'; ...
- '*.jmesh', 'JSON mesh (*.jmesh)'; ...
+filters = {'*.jmsh;*.bmsh,*.off;*.medit;*.smf;*.json', '3D Mesh files (*.jmsh;*.bmsh;*.off;*.medit;*.smf;*.json)'; ...
+ '*.jmsh', 'JSON mesh (*.jmsh)'; ...
+ '*.bmsh', 'Binary JSON mesh (*.bmsh)'; ...
'*.off', 'OFF file (*.off)'; ...
'*.medit', 'Medit file (*.medit)'; ...
'*.ele', 'Tetgen element mesh file (*.ele)'; ...
'*.json', 'JSON file (*.json)'; '*.*', 'All (*.*)'};
-[file, path, idx] = uigetfile(filters);
+[file, path] = uigetfile(filters);
if isequal(file, 0)
return
else
- if (regexp(file, '\.[Oo][Ff][Ff]$'))
+ if (~isempty(regexpi(file, '\.off$', 'once')))
[nodedata.node, nodedata.face] = readoff(fullfile(path, file));
- elseif (regexp(file, '\.[Mm][Ee][Dd][Ii][Tt]$'))
+ elseif (~isempty(regexpi(file, '\.medit$', 'once')))
[nodedata.node, nodedata.elem] = readmedit(fullfile(path, file));
- elseif (regexp(file, '\.[Ee][Ll][Ee]$'))
- [pathstr, name, ext] = fileparts(fullfile(path, file));
+ elseif (~isempty(regexpi(file, '\.ele$', 'once')))
+ [pathstr, name] = fileparts(fullfile(path, file));
[nodedata.node, nodedata.elem] = readtetgen(fullfile(pathstr, name));
- elseif (regexp(file, '\.[Jj][Mm][Ee][Ss][Hh]$'))
+ elseif (~isempty(regexpi(file, '\.[bj]me*sh$', 'once')))
nodedata = importjmesh(fullfile(path, file));
- elseif (regexp(file, '\.[Jj][Ss][Oo][Nn]$'))
- nodedata = loadjson(fullfile(path, file));
+ elseif (~isempty(regexpi(file, '\.json$', 'once')))
+ nodedata = loadjd(fullfile(path, file));
end
end
if (exist('nodedata', 'var'))
@@ -784,29 +812,30 @@ function miLoadMesh_Callback(hObject, eventdata, handles)
function miLoadSurf_Callback(hObject, eventdata, handles)
nodedata = struct;
nodetype = dummytype;
-filters = {'*.jmesh;*.off;*.asc;*.smf;*.smf;*.json', '3D Mesh files (*.jmesh;*.off;*.asc;*.smf;*.smf;*.json)'; ...
- '*.jmesh', 'JSON mesh (*.jmesh)'; ...
+filters = {'*.jmsh;*.bmsh;*.off;*.asc;*.smf;*.smf;*.json', '3D Mesh files (*.jmsh;*.bmsh;*.off;*.asc;*.smf;*.smf;*.json)'; ...
+ '*.jmsh', 'JSON mesh (*.jmsh)'; ...
+ '*.bmsh', 'Binary JSON mesh (*.bmsh)'; ...
'*.off', 'OFF file (*.off)'; ...
'*.asc', 'ASC file (*.asc)'; ...
'*.gts', 'GNU Trangulated Surface file (*.gts)'; ...
'*.smf', 'Simple Model Format (*.smf)'; ...
'*.json', 'JSON file (*.json)'; '*.*', 'All (*.*)'};
-[file, path, idx] = uigetfile(filters);
+[file, path] = uigetfile(filters);
if isequal(file, 0)
return
else
- if (regexp(file, '\.[Oo][Ff][Ff]$'))
+ if (~isempty(regexpi(file, '\.off$', 'once')))
[nodedata.node, nodedata.face] = readoff(fullfile(path, file));
- elseif (regexp(file, '\.[Aa][Ss][Cc]$'))
+ elseif (~isempty(regexpi(file, '\.asc$', 'once')))
[nodedata.node, nodedata.face] = readasc(fullfile(path, file));
- elseif (regexp(file, '\.[Gg][Tt][Ss]$'))
+ elseif (~isempty(regexpi(file, '\.gts$', 'once')))
[nodedata.node, nodedata.face] = readgts(fullfile(path, file));
- elseif (regexp(file, '\.[Ss][Mm][Ff]$'))
+ elseif (~isempty(regexpi(file, '\.smf$', 'once')))
[nodedata.node, nodedata.face] = readsmf(fullfile(path, file));
- elseif (regexp(file, '\.[Jj][Mm][Ee][Ss][Hh]$'))
+ elseif (~isempty(regexpi(file, '\.[bj]me*sh$', 'once')))
nodedata = importjmesh(fullfile(path, file));
- elseif (regexp(file, '\.[Jj][Ss][Oo][Nn]$'))
- nodedata = loadjson(fullfile(path, file));
+ elseif (~isempty(regexpi(file, '\.json$', 'once')))
+ nodedata = loadjd(fullfile(path, file));
end
end
if (exist('nodedata', 'var'))
@@ -817,7 +846,7 @@ function miLoadSurf_Callback(hObject, eventdata, handles)
% --------------------------------------------------------------------
function nodedata = importjmesh(filename)
-data = loadjson(filename);
+data = loadjd(filename);
nodedata = struct;
if (isfield(data, 'MeshNode'))
nodedata.node = data.MeshNode;
@@ -908,7 +937,7 @@ function fgI2M_CreateFcn(hObject, eventdata, handles)
cla(handles.axPreview);
cla(handles.axFlow);
-nodedata.preview = getpreview(nodedata, nodetype, [400, 400]);
+nodedata.preview = getpreview(nodedata, nodetype, [800, 800]);
nodeprop = table({key}, {nodedata}, {nodetype}, 'VariableNames', {'Name', 'Data', 'Type'});
root.graph = addnode(root.graph, nodeprop);
@@ -938,8 +967,9 @@ function fgI2M_CreateFcn(hObject, eventdata, handles)
for i = 1:nn
if (isfield(root.graph.Nodes.Data{i}, 'preview'))
- hobj(i) = imagesc(nx(i) + [-2 * wd 0], ny(i) + [-wd wd] * (wfig / hfig), imresize(root.graph.Nodes.Data{i}.preview, 0.25), ...
- 'parent', handles.axPreview);
+ previewdata = imresize(root.graph.Nodes.Data{i}.preview, 0.5);
+ hobj(i) = imagesc(nx(i) + [-1.8 0] * wd, ny(i) + 0.9 * [-wd wd] * (wfig / hfig), previewdata, ...
+ 'parent', handles.axPreview, 'AlphaData', sum(previewdata, 3) < (240 * 3));
end
end
set(hobj, 'userdata', obj);
@@ -981,8 +1011,8 @@ function miEllipsoid_Callback(hObject, eventdata, handles)
return
end
newtype = dummytype;
-opt = str2num(res{3});
-maxvol = str2num(res{4});
+opt = str2double(res{3});
+maxvol = str2double(res{4});
if (maxvol == 0)
[newdata.node, newdata.face] = meshanellip(eval(res{1}), eval(res{2}), opt);
@@ -995,7 +1025,7 @@ function miEllipsoid_Callback(hObject, eventdata, handles)
newtype.hasface = 1;
if (exist('newdata', 'var') && exist('newtype', 'var'))
- newkey = addnodewithdata(handles, newdata, newtype, 'Cyl');
+ addnodewithdata(handles, newdata, newtype, 'Cyl');
end
% --------------------------------------------------------------------
@@ -1012,7 +1042,7 @@ function miLattice_Callback(hObject, eventdata, handles)
return
end
newtype = dummytype;
-maxvol = str2num(res{4});
+maxvol = str2double(res{4});
if (maxvol == 0)
[newdata.node, newdata.face] = latticegrid(eval(res{1}), eval(res{2}), eval(res{3}));
else
@@ -1024,7 +1054,7 @@ function miLattice_Callback(hObject, eventdata, handles)
newtype.hasface = 1;
if (exist('newdata', 'var') && exist('newtype', 'var'))
- newkey = addnodewithdata(handles, newdata, newtype, 'Lattice');
+ addnodewithdata(handles, newdata, newtype, 'Lattice');
end
% --------------------------------------------------------------------
@@ -1048,7 +1078,7 @@ function miMeshgrid5_Callback(hObject, eventdata, handles)
newtype.haselem = 1;
if (exist('newdata', 'var') && exist('newtype', 'var'))
- newkey = addnodewithdata(handles, newdata, newtype, 'Meshgrid5_');
+ addnodewithdata(handles, newdata, newtype, 'Meshgrid5_');
end
% --------------------------------------------------------------------
@@ -1072,7 +1102,7 @@ function miMeshgrid6_Callback(hObject, eventdata, handles)
newtype.haselem = 1;
if (exist('newdata', 'var') && exist('newtype', 'var'))
- newkey = addnodewithdata(handles, newdata, newtype, 'Meshgrid6_');
+ addnodewithdata(handles, newdata, newtype, 'Meshgrid6_');
end
% --------------------------------------------------------------------
diff --git a/iso2meshver.m b/iso2meshver.m
index d3a4062..1068d9c 100644
--- a/iso2meshver.m
+++ b/iso2meshver.m
@@ -22,7 +22,7 @@
major = 1;
minor = 9;
-patchnum = 5;
+patchnum = 8;
extra = '$Rev:: $';
extra = regexprep(extra, '[\s$:]', '');
diff --git a/transposemat.m b/transposemat.m
new file mode 100644
index 0000000..04593a0
--- /dev/null
+++ b/transposemat.m
@@ -0,0 +1,40 @@
+function data = transposemat(input)
+%
+% data=transposemat(input)
+%
+% Iterate over struct/cell and transpose 2D or higher-dimensional numerical
+% array to match Octave loaded HDF5 array elements with loadh5 default setting
+%
+% author: Qianqian Fang (q.fang neu.edu)
+%
+% input:
+% name: a matlab variable, can be a cell, struct, containers.Map, numeric array or strings
+%
+% output:
+% newname: the restored original string
+%
+% example:
+% a=struct('a', ones(2,3), 'b', 'a string', 'c', uint8(zeros(2,3,4)));
+% b=transposemat(a)
+%
+% this file is part of EasyH5 Toolbox: https://github.com/NeuroJSON/easyh5
+%
+% License: GPLv3 or 3-clause BSD license, see https://github.com/NeuroJSON/easyh5 for details
+%
+
+if (isstruct(input))
+ data = structfun(@transposemat, input, 'UniformOutput', false);
+elseif (iscell(input))
+ data = cellfun(@transposemat, input, 'UniformOutput', 'false');
+elseif (isa(input, 'containers.Map'))
+ allkeys = keys(input);
+ for i = 1:length(allkeys)
+ input(allkeys(i)) = transposemat(allkeys(i));
+ end
+elseif (isnumeric(input) && (ndims(input) > 2 || all(size(input) > 1)))
+ data = permute(input, ndims(input):-1:1);
+elseif (ischar(input) && ndims(input) == 2 && size(input, 1) == 1 && size(input, 2) > 1 && input(end) == ' ')
+ data = input(1:end - 1);
+else
+ data = input;
+end