summaryrefslogtreecommitdiff
path: root/CSXCAD/matlab/SmoothMeshLines2.m
diff options
context:
space:
mode:
Diffstat (limited to 'CSXCAD/matlab/SmoothMeshLines2.m')
-rw-r--r--CSXCAD/matlab/SmoothMeshLines2.m318
1 files changed, 318 insertions, 0 deletions
diff --git a/CSXCAD/matlab/SmoothMeshLines2.m b/CSXCAD/matlab/SmoothMeshLines2.m
new file mode 100644
index 0000000..5d347c0
--- /dev/null
+++ b/CSXCAD/matlab/SmoothMeshLines2.m
@@ -0,0 +1,318 @@
+function lines = SmoothMeshLines2(lines, max_res, ratio, varargin)
+%lines = SmoothMeshLines2( lines, max_res [, ratio, varargin] )
+%
+% Create smooth mesh lines.
+%
+% input:
+% lines: 1xn vector of (fixed) mesh lines
+% max_res: maximum distance between any two lines (e.g. lambda/10)
+% ratio: (optional) default: 1.3
+%
+% optional variable arguments ('key', value)
+% CheckMesh: Do a final mesh check (default is true)
+% allowed_max_ratio: allow only a given max. grading ratio
+% (default --> ratio*1.25)
+% output:
+% lines: 1xn vector of (smoothed) mesh lines
+%
+% example:
+% mesh.x = [0 100 2300 2400];
+% mesh.x = SmoothMeshLines2( mesh.x, 43 );
+%
+% todo:
+% - if gaps cannot be completely filled because of the ratio restriction,
+% the spacing is not optimal. SmoothRange() needs to be optimized.
+% - SmoothRange() has special handling if stop_taper is to long; can this
+% also happen for start_taper?
+%
+% CSXCAD matlab interface
+% -----------------------
+% (C) 2010 Sebastian Held <sebastian.held@uni-due.de>
+% See also SmoothMeshLines
+
+if (numel(lines)<2)
+ return
+end
+
+if (nargin<3)
+ ratio = 1.3;
+end
+
+check_mesh = true;
+max_ratio = ratio*1.25;
+
+for vn=1:2:numel(varargin)
+ if (strcmpi(varargin{vn},'CheckMesh'))
+ check_mesh = varargin{vn+1};
+ end
+ if (strcmpi(varargin{vn},'allowed_max_ratio'))
+ max_ratio = varargin{vn+1};
+ end
+end
+
+%
+% | | | |
+% | gap(1) | gap(2) | ... |
+% | | | |
+%
+% lines(1) lines(2) ... lines(end)
+
+lines = unique(sort(lines));
+
+for n=1:(numel(lines)-1)
+ old_gap(n).start_res = -1;
+ old_gap(n).stop_res = -1;
+ old_gap(n).lines = [];
+end
+
+if numel(lines) == 2
+ % special case
+ addLines = SmoothRange( lines(1), lines(2), [], [], max_res, ratio );
+ lines = sort(unique([lines addLines]));
+ [EC pos] = CheckMesh(lines,0,max_res,ratio);
+ return
+end
+
+while 1
+ gap = calc_gaps(lines,old_gap,max_res);
+
+ % determine gap to process
+ index = find( [old_gap(2:end).start_res] ~= [gap(2:end).start_res], 1, 'first' ) + 1;
+ if isempty(index)
+ index = find( [old_gap(1:end-1).stop_res] ~= [gap(1:end-1).stop_res], 1, 'first' );
+ end
+ if isempty(index)
+ break; % done
+ end
+
+ start_res = min( max_res, calc_start_res(index,lines,old_gap) );
+ stop_res = min( max_res, calc_stop_res(index,lines,old_gap) );
+
+ % create new lines
+ old_gap(index).lines = SmoothRange( lines(index), lines(index+1), start_res, stop_res, max_res, ratio );
+
+ % remember gap setting
+ old_gap(index).start_res = start_res;
+ old_gap(index).stop_res = stop_res;
+
+ % debug
+% plot_lines
+end
+
+% merge lines
+for n=1:numel(old_gap)
+ lines = [lines old_gap(n).lines];
+end
+lines = sort(unique(lines));
+
+if (check_mesh)
+ CheckMesh(lines,0,max_res,max_ratio,0);
+end
+
+end % SmoothMeshLines2()
+
+%% ------------------------------------------------------------------------
+function gap = calc_gaps(lines,old_gap,max_res)
+ temp_lines = lines;
+ for n=1:numel(old_gap)
+ temp_lines = [temp_lines old_gap(n).lines];
+ end
+ temp_lines = sort(unique(temp_lines));
+
+ if numel(temp_lines) == 2
+ gap(1).start_res = inf; % resolution not fixed
+ gap(1).stop_res = max_res;
+ return
+ end
+
+ gap(1).start_res = inf; % resolution not fixed
+ idx = interp1( temp_lines, 1:numel(temp_lines), lines(2), 'nearest' );
+ gap(1).stop_res = min( max_res, temp_lines(idx+1) - temp_lines(idx) );
+ for n=2:numel(lines)-2
+ idx = interp1( temp_lines, 1:numel(temp_lines), lines(n), 'nearest' );
+ gap(n).start_res = min( max_res, temp_lines(idx) - temp_lines(idx-1) );
+ idx = interp1( temp_lines, 1:numel(temp_lines), lines(n+1), 'nearest' );
+ gap(n).stop_res = min( max_res, temp_lines(idx+1) - temp_lines(idx) );
+ gap(n).lines = old_gap(n).lines;
+ end
+ idx = interp1( temp_lines, 1:numel(temp_lines), lines(end-1), 'nearest' );
+ gap(numel(lines)-1).start_res = min( max_res, temp_lines(idx) - temp_lines(idx-1) );
+ gap(numel(lines)-1).stop_res = inf; % resolution not fixed
+end % calc_gaps()
+
+
+%% ------------------------------------------------------------------------
+function plot_lines
+ temp_lines = lines;
+ for n=1:numel(old_gap)
+ temp_lines = [temp_lines old_gap(n).lines];
+ end
+ temp_lines = sort(unique(temp_lines));
+
+ plot( temp_lines, ones(size(temp_lines)), 'r+' );
+ hold on
+ plot( lines, ones(size(lines)), 'bo' );
+ hold off
+end % plot_lines
+
+
+%% ------------------------------------------------------------------------
+function res = calc_start_res(pos,lines,old_gap)
+ if (pos < 2) || (pos > numel(lines))
+ res = [];
+ return
+ end
+ temp_lines = lines;
+ for n=1:numel(old_gap)
+ temp_lines = [temp_lines old_gap(n).lines];
+ end
+ temp_lines = sort(unique(temp_lines));
+
+ idx = interp1( temp_lines, 1:numel(temp_lines), lines(pos), 'nearest' );
+ res = temp_lines(idx) - temp_lines(idx-1);
+end % calc_res()
+
+
+%% ------------------------------------------------------------------------
+function res = calc_stop_res(pos,lines,old_gap)
+ if (pos < 1) || (pos >= numel(lines)-1)
+ res = [];
+ return
+ end
+ temp_lines = lines;
+ for n=1:numel(old_gap)
+ temp_lines = [temp_lines old_gap(n).lines];
+ end
+ temp_lines = sort(unique(temp_lines));
+
+ idx = interp1( temp_lines, 1:numel(temp_lines), lines(pos+1), 'nearest' );
+ res = temp_lines(idx+1) - temp_lines(idx);
+end % calc_res()
+
+
+%% ------------------------------------------------------------------------
+function lines = SmoothRange(start, stop, start_res, stop_res, max_res, ratio)
+
+if (nargin<6)
+ ratio = 1.3;
+end
+
+if isempty(start_res) && isempty(stop_res)
+ % special case: fill entire range with max_res
+ n1 = ceil( (stop-start) / max_res ) + 1;
+ lines = linspace( start, stop, n1 );
+ return
+end
+
+if isempty(start_res)
+ % special case: taper from stop_res at stop to max_res at start (if
+ % possible)
+ taper = stop_res*ratio;
+ stop_taper = stop;
+ while (taper*ratio < max_res) && (stop_taper(1)-taper > start)
+ stop_taper = [stop_taper(1)-taper stop_taper];
+ taper = taper*ratio;
+ end
+ if (stop_taper(1) - start) >= max_res
+ % fill with equidistant lines
+ n1 = ceil( (stop_taper(1)-start) / max_res ) + 1;
+ stop_taper = [linspace(start,stop_taper(1),n1) stop_taper];
+ else
+ % not enough space for entire taper
+ stop_taper(1) = []; % likely too near to start
+ if numel(stop_taper) > 0
+ stop_taper = [(start+stop_taper(1))/2 stop_taper]; % create a centered line
+ end
+ end
+ lines = sort(unique(stop_taper(stop_taper>=start)));
+ return
+end
+
+if isempty(stop_res)
+ % special case: taper from stop_res at stop to max_res at start (if
+ % possible)
+ taper = start_res*ratio;
+ start_taper = start;
+ while (taper*ratio < max_res) && (start_taper(end)+taper < stop)
+ start_taper = [start_taper start_taper(end)+taper];
+ taper = taper*ratio;
+ end
+ if (stop - start_taper(end)) >= max_res
+ % fill with equidistant lines
+ n1 = ceil( (stop-start_taper(end)) / max_res ) + 1;
+ start_taper = [start_taper linspace(start_taper(end),stop,n1)];
+ else
+ % not enough space for entire taper
+ start_taper(end) = []; % likely too near to stop
+ if numel(start_taper) > 0
+ start_taper = [start_taper (stop+start_taper(end))/2]; % create a centered line
+ end
+ end
+ lines = sort(unique(start_taper(start_taper<=stop)));
+ return
+end
+
+taper = start_res*ratio;
+start_taper = start;
+while (taper*ratio<max_res) && (start_taper(end)+taper < stop)
+ start_taper = [start_taper start_taper(end)+taper];
+ taper = taper*ratio;
+end
+if (numel(start_taper) > 1) && (start_taper(end) - start_taper(end-1) > stop - start_taper(end))
+ % not enough space for entire taper
+ start_taper(end) = []; % likely too near to stop
+ start_taper = [start_taper (stop+start_taper(end))/2]; % create a centered line
+end
+
+taper = stop_res*ratio;
+stop_taper = stop;
+while (taper*ratio<max_res) && (stop_taper(1)-taper > start)
+ stop_taper = [stop_taper(1)-taper stop_taper];
+ taper = taper*ratio;
+end
+if (numel(stop_taper) > 1) && (stop_taper(2) - stop_taper(1) > start - stop_taper(1))
+ % not enough space for entire taper
+ stop_taper(1) = []; % likely too near to start
+ stop_taper = [(start+stop_taper(1))/2 stop_taper]; % create a centered line
+end
+
+while ~isempty(start_taper) && ~isempty(stop_taper) && (stop_taper(1) < start_taper(end))
+
+ diff_start = diff(start_taper);
+ if isempty(diff_start)
+ diff_start = start_res;
+ end
+ diff_stop = diff(stop_taper);
+ if isempty(diff_stop)
+ diff_stop = stop_res;
+ end
+
+ if (diff_start(end)>diff_stop(1))
+ start_taper(end) = [];
+ else
+ stop_taper(1) = [];
+ end
+end
+
+% it may happen, that the space between start_taper(end) and stop_taper(1)
+% is very small; correct it:
+if numel(start_taper)>=2 && numel(stop_taper)>=2
+ d = diff( [start_taper(end-1) start_taper(end) stop_taper(1) stop_taper(2) ]);
+ if (d(1)/d(2) > ratio) || (d(3)/d(2) > ratio)
+ addLines = linspace( start_taper(end-1), stop_taper(2), 4 );
+ lines = unique( [start_taper(1:end-1) addLines stop_taper(2:end)] );
+ return
+ end
+end
+
+if isempty(start_taper)
+ start_taper = start;
+end
+if isempty(stop_taper)
+ stop_taper = stop;
+end
+
+% fill remaining space with equidistant lines
+numL = ceil((stop_taper(1) - start_taper(end))/max_res)+1;
+lines = unique([start_taper linspace(start_taper(end),stop_taper(1),numL) stop_taper]);
+end % SmoothRange()