From b8562df95ad29fe5a383aeb8ce25d87ce2dc63f1 Mon Sep 17 00:00:00 2001 From: Amit Subhash <64542797+AmitSubhash@users.noreply.github.com> Date: Tue, 3 Jun 2025 17:36:39 -0400 Subject: [PATCH 1/3] rename selection helper and update GUI reference --- gui/gui_place_sources_detectors.m | 1 + toolbox/select3d.m | 536 +++++++++--------------------- 2 files changed, 156 insertions(+), 381 deletions(-) diff --git a/gui/gui_place_sources_detectors.m b/gui/gui_place_sources_detectors.m index b7bd83d..ebcb3f3 100644 --- a/gui/gui_place_sources_detectors.m +++ b/gui/gui_place_sources_detectors.m @@ -383,6 +383,7 @@ function figure1_WindowButtonDownFcn(hObject, eventdata, handles) % eventdata reserved - to be defined in a future version of MATLAB % handles structure with handles and user data (see GUIDATA) if handles.dimension == 3 + % Use bundled SELECT3D implementation for modern MATLAB versions p = select3d; if ~isempty(p) if handles.sourceflag == 1 diff --git a/toolbox/select3d.m b/toolbox/select3d.m index dfcfe83..1981638 100644 --- a/toolbox/select3d.m +++ b/toolbox/select3d.m @@ -1,381 +1,155 @@ -function [pout, vout, viout, facevout, faceiout] = select3d(obj) - -% [pout, vout, viout, facevout, faceiout] = select3d(obj) -% -% Copyright (c) 2009, The MathWorks, Inc. -% All rights reserved. -% -% Redistribution and use in source and binary forms, with or without -% modification, are permitted provided that the following conditions are -% met: -% -% * Redistributions of source code must retain the above copyright -% notice, this list of conditions and the following disclaimer. -% * Redistributions in binary form must reproduce the above copyright -% notice, this list of conditions and the following disclaimer in -% the documentation and/or other materials provided with the distribution -% * Neither the name of the The MathWorks, Inc. nor the names -% of its contributors may be used to endorse or promote products derived -% from this software without specific prior written permission. -% -% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -% POSSIBILITY OF SUCH DAMAGE. - - -%SELECT3D(H) Determines the selected point in 3-D data space. -% P = SELECT3D determines the point, P, in data space corresponding -% to the current selection position. P is a point on the first -% patch or surface face intersected along the selection ray. If no -% face is encountered along the selection ray, P returns empty. -% -% P = SELECT3D(H) constrains selection to graphics handle H and, -% if applicable, any of its children. H can be a figure, axes, -% patch, or surface object. -% -% [P V] = SELECT3D(...), V is the closest face or line vertex -% selected based on the figure's current object. -% -% [P V VI] = SELECT3D(...), VI is the index into the object's -% x,y,zdata properties corresponding to V, the closest face vertex -% selected. -% -% [P V VI FACEV] = SELECT3D(...), FACE is an array of vertices -% corresponding to the face polygon containing P and V. -% -% [P V VI FACEV FACEI] = SELECT3D(...), FACEI is the row index into -% the object's face array corresponding to FACE. For patch -% objects, the face array can be obtained by doing -% get(mypatch,'faces'). For surface objects, the face array -% can be obtained from the output of SURF2PATCH (see -% SURF2PATCH for more information). -% -% RESTRICTIONS: -% SELECT3D supports surface, patch, or line object primitives. For surface -% and patches, the algorithm assumes non-self-intersecting planar faces. -% For line objects, the algorithm always returns P as empty, and V will -% be the closest vertex relative to the selection point. -% -% Example: -% -% h = surf(peaks); -% zoom(10); -% disp('Click anywhere on the surface, then hit return') -% pause -% [p v vi face facei] = select3d; -% marker1 = line('xdata',p(1),'ydata',p(2),'zdata',p(3),'marker','o',... -% 'erasemode','xor','markerfacecolor','k'); -% marker2 = line('xdata',v(1),'ydata',v(2),'zdata',v(3),'marker','o',... -% 'erasemode','xor','markerfacecolor','k'); -% marker2 = line('erasemode','xor','xdata',face(1,:),'ydata',face(2,:),... -% 'zdata',face(3,:),'linewidth',10); -% disp(sprintf('\nYou clicked at\nX: %.2f\nY: %.2f\nZ: %.2f',p(1),p(2),p(3)')) -% disp(sprintf('\nThe nearest vertex is\nX: %.2f\nY: %.2f\nZ: %.2f',v(1),v(2),v(3)')) -% -% Version 1.3 11-11-04 -% Copyright Joe Conti 2004 -% Send comments to jconti@mathworks.com -% -% See also GINPUT, GCO. - -% Output variables -pout = []; -vout = []; -viout = []; -facevout = []; -faceiout = []; - -% other variables -ERRMSG = 'Input argument must be a valid graphics handle'; -isline = logical(0); -isperspective = logical(0); - -% Parse input arguments -if nargin<1 - obj = gco; -end - -if isempty(obj) | ~ishandle(obj) | length(obj)~=1 - error(ERRMSG); -end - -% if obj is a figure -if strcmp(get(obj,'type'),'figure') - fig = obj; - ax = get(fig,'currentobject'); - currobj = get(fig,'currentobject'); - - % bail out if not a child of the axes - if ~strcmp(get(get(currobj,'parent'),'type'),'axes') - return; - end - -% if obj is an axes -elseif strcmp(get(obj,'type'),'axes') - ax = obj; - fig = get(ax,'parent'); - currobj = get(fig,'currentobject'); - currax = get(currobj,'parent'); - - % Bail out if current object is under an unspecified axes - if ~isequal(ax,currax) - return; - end - -% if obj is child of axes -elseif strcmp(get(get(obj,'parent'),'type'),'axes') - currobj = obj; - ax = get(obj,'parent'); - fig = get(ax,'parent'); - -% Bail out -else - return -end - -axchild = currobj; -obj_type = get(axchild,'type'); - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% Get vertex, face, and current point data %% -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -cp = get(ax,'currentpoint')'; - -% If surface object -if strcmp(obj_type,'surface') - % Get surface face and vertices - fv = surf2patch(axchild); - vert = fv.vertices; - faces = fv.faces; - -% If patch object -elseif strcmp(obj_type,'patch') - vert = get(axchild,'vertices'); - faces = get(axchild,'faces'); - -% If line object -elseif strcmp(obj_type,'line') - xdata = get(axchild,'xdata'); - ydata = get(axchild,'ydata'); - zdata = get(axchild,'zdata'); - vert = [xdata', ydata',zdata']; - faces = []; - isline = logical(1); - -% Ignore all other objects -else - return; -end - -% Add z if empty -if size(vert,2)==2 - vert(:,3) = zeros(size(vert(:,2))); - if isline - zdata = vert(:,3); - end -end - -% NaN and Inf check -nan_inf_test1 = isnan(faces) | isinf(faces); -nan_inf_test2 = isnan(vert) | isinf(vert); -if any(nan_inf_test1(:)) | any(nan_inf_test2(:)) - warning(sprintf('%s does not support NaNs or Infs in face/vertex data.',mfilename)); -end - -% For debugging -% if 0 -% ax1 = getappdata(ax,'testselect3d'); -% if isempty(ax1) | ~ishandle(ax1) -% fig = figure; -% ax1 = axes; -% axis(ax1,'equal'); -% setappdata(ax,'testselect3d',ax1); -% end -% cla(ax1); -% patch('parent',ax1,'faces',faces,'vertices',xvert','facecolor','none','edgecolor','k'); -% line('parent',ax1,'xdata',xcp(1,2),'ydata',xcp(2,2),'zdata',0,'marker','o','markerfacecolor','r','erasemode','xor'); -% end - -% Transform vertices from data space to pixel space -xvert = local_Data2PixelTransform(ax,vert)'; -xcp = local_Data2PixelTransform(ax,cp')'; - -% Translate vertices so that the selection point is at the origin. -xvert(1,:) = xvert(1,:) - xcp(1,2); -xvert(2,:) = xvert(2,:) - xcp(2,2); - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% simple algorithm (almost naive algorithm!) for line objects %% -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -if isline - - % Ignoring line width and marker attributes, find closest - % vertex in 2-D view space. - d = xvert(1,:).*xvert(1,:) + xvert(2,:).*xvert(2,:); - [val i] = min(d); - i = i(1); % enforce only one output - - % Assign output - vout = [ xdata(i) ydata(i) zdata(i)]; - viout = i; - - return % Bail out early -end - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% Perform 2-D crossing test (Jordan Curve Theorem) %% -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -% Find all vertices that have y components less than zero -vert_with_negative_y = zeros(size(faces)); -face_y_vert = xvert(2,faces); -ind_vert_with_negative_y = find(face_y_vert<0); -vert_with_negative_y(ind_vert_with_negative_y) = logical(1); - -% Find all the line segments that span the x axis -is_line_segment_spanning_x = abs(diff([vert_with_negative_y, vert_with_negative_y(:,1)],1,2)); - -% Find all the faces that have line segments that span the x axis -ind_is_face_spanning_x = find(any(is_line_segment_spanning_x,2)); - -% Ignore data that doesn't span the x axis -candidate_faces = faces(ind_is_face_spanning_x,:); -vert_with_negative_y = vert_with_negative_y(ind_is_face_spanning_x,:); -is_line_segment_spanning_x = is_line_segment_spanning_x(ind_is_face_spanning_x,:); - -% Create line segment arrays -pt1 = candidate_faces; -pt2 = [candidate_faces(:,2:end), candidate_faces(:,1)]; - -% Point 1 -x1 = reshape(xvert(1,pt1),size(pt1)); -y1 = reshape(xvert(2,pt1),size(pt1)); - -% Point 2 -x2 = reshape(xvert(1,pt2),size(pt2)); -y2 = reshape(xvert(2,pt2),size(pt2)); - -% Cross product of vector to origin with line segment -cross_product_test = -x1.*(y2-y1) > -y1.*(x2-x1); - -% Find all line segments that cross the positive x axis -crossing_test = (cross_product_test==vert_with_negative_y) & is_line_segment_spanning_x; - -% If the number of line segments is odd, then we intersected the polygon -s = sum(crossing_test,2); -s = mod(s,2); -ind_intersection_test = find(s~=0); - -% Bail out early if no faces were hit -if isempty(ind_intersection_test) - return; -end - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% Plane/ray intersection test %% -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% Perform plane/ray intersection with the faces that passed -% the polygon intersection tests. Grab the only the first -% three vertices since that is all we need to define a plane). -% assuming planar polygons. -candidate_faces = candidate_faces(ind_intersection_test,1:3); -candidate_faces = reshape(candidate_faces',1,prod(size(candidate_faces))); -vert = vert'; -candidate_facev = vert(:,candidate_faces); -candidate_facev = reshape(candidate_facev,3,3,length(ind_intersection_test)); - -% Get three contiguous vertices along polygon -v1 = squeeze(candidate_facev(:,1,:)); -v2 = squeeze(candidate_facev(:,2,:)); -v3 = squeeze(candidate_facev(:,3,:)); - -% Get normal to face plane -vec1 = [v2-v1]; -vec2 = [v3-v2]; -crs = cross(vec1,vec2); -mag = sqrt(sum(crs.*crs)); -nplane(1,:) = crs(1,:)./mag; -nplane(2,:) = crs(2,:)./mag; -nplane(3,:) = crs(3,:)./mag; - -% Compute intersection between plane and ray -cp1 = cp(:,1); -cp2 = cp(:,2); -d = cp2-cp1; -dp = dot(-nplane,v1); - -%A = dot(nplane,d); -A(1,:) = nplane(1,:).*d(1); -A(2,:) = nplane(2,:).*d(2); -A(3,:) = nplane(3,:).*d(3); -A = sum(A,1); - -%B = dot(nplane,pt1) -B(1,:) = nplane(1,:).*cp1(1); -B(2,:) = nplane(2,:).*cp1(2); -B(3,:) = nplane(3,:).*cp1(3); -B = sum(B,1); - -% Distance to intersection point -t = (-dp-B)./A; - -% Find "best" distance (smallest) -[tbest ind_best] = min(t); - -% Determine intersection point -pout = cp1 + tbest .* d; - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% Assign additional output variables %% -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -if nargout>1 - - % Get face index and vertices - faceiout = ind_is_face_spanning_x(ind_intersection_test(ind_best)); - facevout = vert(:,faces(faceiout,:)); - - % Determine index of closest face vertex intersected - facexv = xvert(:,faces(faceiout,:)); - dist = sqrt(facexv(1,:).*facexv(1,:) + facexv(2,:).*facexv(2,:)); - min_dist = min(dist); - min_index = find(dist==min_dist); - - % Get closest vertex index and vertex - viout = faces(faceiout,min_index); - vout = vert(:,viout); -end - -%--------------------------------------------------------% -function [p] = local_Data2PixelTransform(ax,vert) -% Transform vertices from data space to pixel space. - -% Get needed transforms -xform = get(ax,'x_RenderTransform'); -offset = get(ax,'x_RenderOffset'); -scale = get(ax,'x_RenderScale'); - -% Equivalent: nvert = vert/scale - offset; -nvert(:,1) = vert(:,1)./scale(1) - offset(1); -nvert(:,2) = vert(:,2)./scale(2) - offset(2); -nvert(:,3) = vert(:,3)./scale(3) - offset(3); - -% Equivalent xvert = xform*xvert; -w = xform(4,1) * nvert(:,1) + xform(4,2) * nvert(:,2) + xform(4,3) * nvert(:,3) + xform(4,4); -xvert(:,1) = xform(1,1) * nvert(:,1) + xform(1,2) * nvert(:,2) + xform(1,3) * nvert(:,3) + xform(1,4); -xvert(:,2) = xform(2,1) * nvert(:,1) + xform(2,2) * nvert(:,2) + xform(2,3) * nvert(:,3) + xform(2,4); - -% w may be 0 for perspective plots -ind = find(w==0); -w(ind) = 1; % avoid divide by zero warning -xvert(ind,:) = 0; % set pixel to 0 - -p(:,1) = xvert(:,1) ./ w; -p(:,2) = xvert(:,2) ./ w; +function [pout, vout, viout, facevout, faceiout] = select3d(obj) +%SELECT3D 3-D point selection compatible with modern MATLAB +% P = SELECT3D() returns the 3-D point on the current axes +% intersected by the mouse click. The implementation mirrors the +% behaviour of the legacy SELECT3D utility shipped with older MATLAB +% releases but avoids using internal graphics properties that are no +% longer available in recent versions. +% +% [P, V, VI, FACEV, FACEI] additionally return the closest vertex and +% face information for patch and surface objects. Line objects return +% the nearest vertex. +% +% This function is self contained so that NIRFAST does not rely on +% MATLAB''s own SELECT3D which has changed across releases. + +if nargin < 1 + obj = gco; +end + +if isempty(obj) || ~ishandle(obj) || numel(obj) ~= 1 + error('Input argument must be a valid graphics handle'); +end + +switch get(obj,'Type') + case 'figure' + fig = obj; + ax = get(fig,'CurrentAxes'); + currobj = get(fig,'CurrentObject'); + if isempty(ax) || ~strcmp(get(currobj,'Parent'),'axes') + pout=[]; vout=[]; viout=[]; facevout=[]; faceiout=[]; return; + end + case 'axes' + ax = obj; + fig = ancestor(ax,'figure'); + currobj = get(fig,'CurrentObject'); + if ~isequal(ax,ancestor(currobj,'axes')) + pout=[]; vout=[]; viout=[]; facevout=[]; faceiout=[]; return; + end + otherwise + ax = ancestor(obj,'axes'); + fig = ancestor(ax,'figure'); + currobj = obj; + if isempty(ax) + pout=[]; vout=[]; viout=[]; facevout=[]; faceiout=[]; return; + end +end + +obj_type = get(currobj,'Type'); + +switch obj_type + case 'surface' + fv = surf2patch(currobj); + vertices = fv.vertices; + faces = fv.faces; + case 'patch' + vertices = get(currobj,'Vertices'); + faces = get(currobj,'Faces'); + case 'line' + xdata = get(currobj,'XData'); + ydata = get(currobj,'YData'); + zdata = get(currobj,'ZData'); + vertices = [xdata(:), ydata(:), zdata(:)]; + faces = []; + otherwise + pout=[]; vout=[]; viout=[]; facevout=[]; faceiout=[]; return; +end + +% add zero z for 2-D data +if size(vertices,2)==2 + vertices(:,3) = 0; + if strcmp(obj_type,'line') + zdata = zeros(size(xdata)); + end +end + +cp = get(ax,'CurrentPoint'); +ray_origin = cp(1,:); +ray_dir = cp(2,:) - cp(1,:); + +if strcmp(obj_type,'line') + % closest vertex in 2-D projection + verts2d = vertices(:,1:2); + pt2d = ray_origin(1:2); + d2 = sum((verts2d - pt2d).^2,2); + [~, idx] = min(d2); + pout = []; + vout = vertices(idx,:).'; + viout = idx; + facevout = []; + faceiout = []; + return; +end + +hit = false; +best_t = Inf; +best_face = 0; +best_uv = [0 0]; + +for i=1:size(faces,1) + tri = vertices(faces(i,:),:); + [intersects, tval, uval, vval] = local_rayTri(ray_origin, ray_dir, tri); + if intersects && tval < best_t + hit = true; + best_t = tval; + best_face = i; + best_uv = [uval vval]; + end +end + +if ~hit + pout=[]; vout=[]; viout=[]; facevout=[]; faceiout=[]; return; +end + +pout = (ray_origin + best_t * ray_dir).'; + +if nargout > 1 + facevout = vertices(faces(best_face,:),:).'; + faceiout = best_face; + verts = vertices(faces(best_face,:),:); + % choose vertex closest to intersection + [~,v_idx] = min(sum(bsxfun(@minus,verts,pout.').^2,2)); + vout = verts(v_idx,:).'; + viout = faces(best_face,v_idx); +end + +end + +function [hit, t, u, v] = local_rayTri(orig, dir, tri) +%MOLLERTRUMBORE Ray/triangle intersection +epsilon = 1e-12; +edge1 = tri(2,:) - tri(1,:); +edge2 = tri(3,:) - tri(1,:); +h = cross(dir, edge2); +a = dot(edge1, h); +if abs(a) < epsilon + hit = false; t = Inf; u=0; v=0; return; +end +f = 1.0 / a; +s = orig - tri(1,:); +u = f * dot(s, h); +if u < 0.0 || u > 1.0 + hit = false; t = Inf; return; +end +q = cross(s, edge1); +v = f * dot(dir, q); +if v < 0.0 || (u + v) > 1.0 + hit = false; t = Inf; return; +end +t = f * dot(edge2, q); +if t > epsilon + hit = true; +else + hit = false; t = Inf; +end +end From 95068f00211eadf89153124ebfcc062b986b1888 Mon Sep 17 00:00:00 2001 From: Amit Subhash <64542797+AmitSubhash@users.noreply.github.com> Date: Tue, 3 Jun 2025 17:48:38 -0400 Subject: [PATCH 2/3] Fix select3d intersection logic --- toolbox/select3d.m | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/toolbox/select3d.m b/toolbox/select3d.m index 1981638..cf8e3ac 100644 --- a/toolbox/select3d.m +++ b/toolbox/select3d.m @@ -49,12 +49,16 @@ switch obj_type case 'surface' - fv = surf2patch(currobj); + % Use triangulation to simplify intersection tests + fv = surf2patch(currobj,'triangles'); vertices = fv.vertices; faces = fv.faces; case 'patch' vertices = get(currobj,'Vertices'); faces = get(currobj,'Faces'); + if size(faces,2) > 3 || any(isnan(faces(:))) + faces = local_triangulate(faces); + end case 'line' xdata = get(currobj,'XData'); ydata = get(currobj,'YData'); @@ -139,7 +143,7 @@ s = orig - tri(1,:); u = f * dot(s, h); if u < 0.0 || u > 1.0 - hit = false; t = Inf; return; + hit = false; t = Inf; v = 0; return; end q = cross(s, edge1); v = f * dot(dir, q); @@ -153,3 +157,18 @@ hit = false; t = Inf; end end + +function faces_tri = local_triangulate(faces) +%LOCAL_TRIANGULATE Convert polygon faces to triangles +faces_tri = []; +for i = 1:size(faces,1) + idx = faces(i,:); + idx = idx(~isnan(idx)); + if numel(idx) < 3 + continue; + end + for k = 2:(numel(idx)-1) + faces_tri(end+1,:) = [idx(1) idx(k) idx(k+1)]; %#ok + end +end +end From 9f4e1650f108a9e2aa97a91dc55cfa3a8183e6dd Mon Sep 17 00:00:00 2001 From: AmitSubhash Date: Sat, 4 Apr 2026 14:07:49 -0400 Subject: [PATCH 3/3] fix: use %d format for integer data in mysave to prevent precision loss The %g format specifier defaults to 6 significant digits, which silently truncates node indices above ~1e6 when writing .elem files. For example, node index 1932581 is written as 1.93258e+06 and read back as 1932580. This causes "invalid triangulation" errors in PlotMeshSurface when the mesh has more than ~1 million nodes, because element indices reference node positions that no longer exist after the round-trip through save_mesh/load_mesh. The fix detects integer-valued data and uses %d instead of %g, while preserving %g for floating-point data like node coordinates. --- toolbox/mysave.m | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/toolbox/mysave.m b/toolbox/mysave.m index 5d69a65..59159b2 100644 --- a/toolbox/mysave.m +++ b/toolbox/mysave.m @@ -3,29 +3,30 @@ function mysave(fn,data) % mysave(fn,data) % % save function that will work with matlab compiler -% +% % fn is the filename to be saved % data is the variable to be saved - -dlim = '\t'; data = data'; [nrow,ncol]=size(data); fid = OpenFile(fn,'w'); -str = ['fprintf(fid, ', '''', '%g']; -if nrow>1 - str1 = []; - for i = 2: nrow - str1 = [str1, dlim, '%g']; - end -end -if exist('str1', 'var') - str = [str, str1, '\n', '''', ',data);']; +% Use %d for integer-valued data (e.g. element indices, region labels) +% to avoid precision loss from %g scientific notation on large integers. +% %g defaults to 6 significant digits, which silently corrupts node +% indices above ~1e6 when saving .elem files, causing invalid +% triangulation errors on mesh reload. +if isequal(data, round(data)) + fmt = '%d'; else - str = [str, '\n', '''', ',data);']; + fmt = '%g'; end -eval(str) +fmtstr = fmt; +for i = 2:nrow + fmtstr = [fmtstr, '\t', fmt]; +end +fmtstr = [fmtstr, '\n']; +fprintf(fid, fmtstr, data); fclose(fid);