% Installer: "tri_install.m" % Created: 30-Apr-2003 10:49:43. function bund_driver % bund_driver -- Driver for "bund" bundles. % bund_driver (no arguments) contains Matlab commands % to inflate the instructions and files that are % encoded into the "bund_data" function of this package. % Copyright (C) 2001 Dr. Charles R. Denham, ZYDECO. % All Rights Reserved. % Disclosure without explicit written consent from the % copyright owner does not constitute publication. % Version of 14-Jun-2001 10:54:16. % Updated 06-Feb-2003 14:36:58. help(mfilename) v = version; isVersion6 = (v(1) == '6'); BINARY_TAG = '?'; CR = char(13); LF = char(10); comp = upper(computer); if any(findstr(comp, 'PCWIN')) % Windows. NL = [CR LF]; elseif any(findstr(comp, 'MAC')) % Macintosh. NL = CR; else % Unix. NL = LF; end c = zeros(1, 256); c(abs('0'):abs('9')) = 0:9; c(abs('a'):abs('f')) = 10:15; disp([' ']) disp([' ## This installer is ready to expand its contents,']) disp([' ## starting in the present directory: "' pwd '"']) disp([' ## To abort, execute an interruption now.']) disp([' ## Otherwise, to continue, press any key.']) disp([' ']) try pause catch disp([' ## Installation interrupted.']) disp([' ']) return end % eval('pause', 'disp(''Installation interrupted.''), return') tic w = which(mfilename); fin = fopen(w, 'r'); if fin < 0, return, end found = ~~0; while ~found s = fgetl(fin); if isequal(s, -1) fclose(fin); return end s = strrep(s, LF, ''); % Not necessary? s = strrep(s, CR, ''); % Not necessary? if isequal(s, 'function bund_data') found = ~~1; end end fout = -1; done = ~~0; while ~done s = fgetl(fin); if isequal(s, -1) fclose(fin); return end s = strrep(s, LF, ''); % Not necessary? s = strrep(s, CR, ''); % Not necessary? if length(s) > 0 if s(1) ~= '%' f = findstr(s, 'bund_setdir'); if any(f) theDir = eval(strrep(s, 'bund_setdir', '')); [status, msg] = mkdir(theDir); switch status case 1 if isVersion6 & any(msg) disp([' ## Directory exists: "' theDir '"']) else disp([' ## Directory created: "' theDir '"']) end case 2 disp([' ## Directory exists: "' theDir '"']) otherwise error([' ## Error while making new directory.']) end try cd(theDir) catch error([' ## Unable to go to directory: "' theDir '"']) end % eval('cd(theDir)', ... % 'disp(theDir), error('' ## Unable to go to directory.'')') else % try % eval(s); % catch % error([' ## Unable to evaluate: "' s '"']) % end eval(s, ... 'disp(s), error(''Unable to evaluate statement.'')') end elseif length(s) > 1 & s(2) == BINARY_TAG hx = double(s(3:end)); % Assume hex data. bin = 16*c(hx(1:2:end)) + c(hx(2:2:end)); fwrite(fout, bin, 'uchar'); else fprintf(fout, '%s', s(2:end)); fprintf(fout, NL); end end end fclose(fin); disp([' ## Elapsed time: ' num2str(fix(10*toc)/10) ' s.']) function bund_data bund_setdir('tri') disp(' ## Installing: "areaxy.m" (text)') fout = fopen('areaxy.m', 'w'); %function theResult = areaxy(x, y) % %% areaxy -- Signed-area of polygon (x, y). %% areaxy(x, y) returns the signed-area of the %% polygon given by the (x, y) vertices. The %% sign is positive for the counter-clockwise %% sense; negative for clockwise. (The Matlab %% "polyarea" result is unsigned.) % %% Copyright (C) 1999 Dr. Charles R. Denham, ZYDECO. %% All Rights Reserved. %% Disclosure without explicit written consent from the %% copyright owner does not constitute publication. % %% Version of 08-Jul-1999 22:00:38. %% Updated 08-Jul-1999 22:00:38. % %if nargin < 1, help(mfilename), return, end % %result = 0; % %if ~isempty(x) & length(x) == length(y) % x = [x(:); x(1)]; % y = [y(:); y(1)]; % i = 1:length(x)-1; % result = 0.5 * sum((x(i) .* y(i+1) - y(i) .* x(i+1))); %end % %if nargout > 0 % theResult = result; %else % disp(result) % assignin('caller', 'ans', result) %end fclose(fout); disp(' ## Installing: "at.m" (text)') fout = fopen('at.m', 'w'); %function theResult = at(theFile, theOffset) % %% at -- Switch to the folder of a given file. %% at('theFunction') switches to the folder of %% 'theFunction', as determined by the "which" %% function. %% at('theFunction', theOffset) performs as above, %% then marches into higher directories by the %% amount of theOffset, which must be a negative %% integer. % %% Copyright (C) 2000 Dr. Charles R. Denham, ZYDECO. %% All Rights Reserved. %% Disclosure without explicit written consent from the %% copyright owner does not constitute publication. % %% Version of 01-Feb-2000 22:21:09. %% Updated 22-Apr-2003 09:19:37. % %if nargout > 0, theResult = []; end % %if nargin < 1, help(mfilename), return, end %if nargin < 2, theOffset = 0; end %if ischar(theOffset), theOffset = eval(theOffset); end % %w = which(theFile); % %if isempty(w) % w = which([theFile '/' theFile]); % if isempty(w) % disp([' ## No such file: ' theFile]) % return % end %elseif isequal(w, 'built-in') % disp([' ## ' theFile ' is built-in. Try "at ' theFile '.m".']) % return %end % %[thePath, theName, theExtension, theVersion] = fileparts(w); % %if any(thePath) % cd(thePath) % if theOffset < 0 % for i = 1:fix(abs(theOffset)) % cd .. % end % end %end % %if nargout > 0 % theResult = pwd; %else % disp([' ## ' pwd]) %end fclose(fout); disp(' ## Installing: "grid2tri.m" (text)') fout = fopen('grid2tri.m', 'w'); %function tri = grid2tri(m, n) % %% grid2tri -- Convert plaid-grid to triangles. %% grid2tri(theSize) returns triangle indices for %% a plaid-grid of theSize, as if each cell were %% split into two triangles by a simple diagonal. %% Indices run columnwise in conventional Matlab %% fashion, and the triangles run counterclockwise. %% grid2tri(m, n) is the same as grid2tri([m n]). % %% Copyright (C) 2001 Dr. Charles R. Denham, ZYDECO. %% All Rights Reserved. %% Disclosure without explicit written consent from the %% copyright owner does not constitute publication. % %% Version of 16-Mar-2001 15:30:46. %% Updated 16-Mar-2001 16:06:27. % %if nargin < 1 % help(mfilename) % m = 'demo'; %end % %if isequal(m, 'demo') % m = 2; n = 2; %end % %if isstr(m), m = eval(m); end %if nargin > 1 & isstr(n), n = eval(n); end % %if nargin < 2 % if length(m) < 2 % n = m; % else % n = m(2); % m = m(1); % end %end % %% Fill a grid with one-dimensional indices. % %g = zeros(m, n); %g(:) = 1:m*n; % %% Allocate the output array. % %t = zeros(2*(m-1)*(n-1), 3); % %% Two approaches: a slow one with nested for-loops, %% and a very fast one that is fully vectorized. % %SLOW = 0; % %if SLOW % k = 0; % for j = 1:n-1 % for i = 1:m-1 % k = k+1; % t(k, :) = [g(i, j) g(i+1, j) g(i+1, j+1)]; % k = k+1; % t(k, :) = [g(i, j) g(i+1, j+1) g(i, j+1)]; % end % end %else % temp = g(1:end-1, 1:end-1); % Upper left. % temp = temp(:); % t(1:2:end, 1) = temp; % t(2:2:end, 1) = temp; % temp = g(2:end, 1:end-1); % Lower left. % t(1:2:end, 2) = temp(:); % temp = g(2:end, 2:end); % Lower right. % temp = temp(:); % t(1:2:end, 3) = temp; % t(2:2:end, 2) = temp; % temp = g(1:end-1, 2:end); % Upper right. % t(2:2:end, 3) = temp(:); %end % %if nargout > 0 % tri = t; %else % disp(t) %end fclose(fout); disp(' ## Installing: "inpoly.m" (text)') fout = fopen('inpoly.m', 'w'); %function theResult = inpoly(x, y, xi, yi) % %% inpoly -- In-polygon function, based on triangles. %% inpoly(x, y, xi, yi) returns a logical vector that %% describes whether the (xi, yi) points are inside %% (TRUE) or outside (FALSE) the polygon given by %% the (x, y) perimeter. % %% Copyright (C) 1999 Dr. Charles R. Denham, ZYDECO. %% All Rights Reserved. %% Disclosure without explicit written consent from the %% copyright owner does not constitute publication. % %% Version of 12-Jul-1999 19:51:14. %% Updated 12-Jul-1999 19:51:14. % %if nargout > 0, theResult = []; end % %if nargin < 4, help(mfilename), return, end % %if x(1) == x(end) & y(1) == y(end) % x(end) = []; % y(end) = []; %end % %[xp, yp, tp] = tripoly(x, y); % %t = tsearch(xp, yp, tp, xi, yi); %t(isnan(t)) = 0; % %s = (trisense(tp, xp, yp) > 0); % %result = zeros(size(t)); %result(t ~= 0) = s(t(t ~= 0)); % %if nargout > 0 % theResult = result; %else % disp(result) % assignin('caller', 'ans', result) %end fclose(fout); disp(' ## Installing: "isconvex.m" (text)') fout = fopen('isconvex.m', 'w'); %function theResult = isconvex(x, y) % %% isconvex -- Is polygon (x, y) convex? %% isconvex(x, y) returns TRUE if the (x, y) polygon %% is convex (TRUE); otherwise, FALSE. % %% Copyright (C) 1999 Dr. Charles R. Denham, ZYDECO. %% All Rights Reserved. %% Disclosure without explicit written consent from the %% copyright owner does not constitute publication. % %% Version of 12-Jul-1999 20:35:58. %% Updated 12-Jul-1999 20:35:58. % %if nargin < 1, help(mfilename), return, end % %if x(1) == x(end) & y(1) == y(end) % x(end) = []; % y(end) = []; %end % %tri = delaunay(x, y); % %h = trihull(tri); % %result = (length(h) == length(x)); % %if nargout > 0 % theResult = result; %else % disp(result) % assignin('caller', 'ans', result) %end fclose(fout); disp(' ## Installing: "polyangles.m" (text)') fout = fopen('polyangles.m', 'w'); %function [theResult, err] = polyangles(x, y) % %% polyangles -- Angles around a polygon. %% polyangles('demo') calls polyangles(10). %% polyangles(N) demonstrates itself by computing %% the angles for a random N-sided polygon. %% polyangles(x, y) returns the angles of the %% polygon (x, y) vertices, in radians. Angles %% for a counter-clockwise polygon will sum %% to +2*pi radians; clockwise begets -2*pi. %% polyangles(z) does the same for complex %% polygon vertices z. %% [result, err] = ... also returns the error %% from a +/- 2*pi closure. %% %% Also see: polyrand. % %% Copyright (C) 2003 Dr. Charles R. Denham, ZYDECO. %% All Rights Reserved. %% Disclosure without explicit written consent from the %% copyright owner does not constitute publication. % %% Version of 15-Apr-2003 17:03:24. %% Updated 15-Apr-2003 17:03:24. % %if nargin < 1 % help(mfilename) % x = 'demo'; %end % %if isequal(x, 'demo'), x = 10; end %if ischar(x), x = eval(x); end % %if length(x) == 1 % N = x; % [x, y] = polyrand('demo', N); % hold on, plot(x(1), y(1), 'r*'), hold off % x = x + sqrt(-1)*y; %end % %if nargin > 1 % z = x + sqrt(-1)*y; %else % z = x; %end % %z(end+1) = z(1); %dz = diff(z); %dz(end+1) = dz(1); %dz = dz(2:end)./dz(1:end-1); % %angles = angle(dz); % %while any(angles < -pi) % f = find(angles < -pi); % angles(f) = angles(f) + pi; %end %while any(angles > pi) % f = find(angles > pi); % angles(f) = angles(f) - pi; %end % %% Rearrange so angles correspond to vertex indices. % %result = zeros(size(angles)); %result(1) = angles(end); %result(2:end) = angles(1:end-1); % %% Error estimate. % %err = abs(abs(sum(result)) - 2*pi); % %if nargout > 0 % theResult = result; %else % disp(result) % assignin('caller', 'ans', result) %end fclose(fout); disp(' ## Installing: "polyrand.m" (text)') fout = fopen('polyrand.m', 'w'); %function [x, y] = polyrand(xx, yy) % %% polyrand -- Random non-intersecting polygon. %% polyrand('demo', nVertices) demonstrates itself %% with nVertices (default = 8). %% [x, y] = polyrand(nVertices) returns the (x, y) %% coordinates of a random polygon having nVertices. %% In the event of (very rare) failure, the result %% is empty. %% [x, y] = polyrand(xx, yy) returns the (x, y) %% coordinates for a polygon whose vertices are %% (xx, yy). The sequence of vertices is not %% necessarily unique. %% z = ... returns the polygon as complex points %% x + sqrt(-1)*y. %% %% Also see: TRIPLOT1, TRIHULL, TRI_REFLECT, DELAUNAY. % %% Copyright (C) 2002 Dr. Charles R. Denham, ZYDECO. %% All Rights Reserved. %% Disclosure without explicit written consent from the %% copyright owner does not constitute publication. % %% Version of 06-Aug-2002 11:11:27. %% Updated 17-Apr-2003 10:16:42. % %if nargin < 1, help(mfilename), xx = 'demo'; end % %if isequal(xx, 'demo') % if nargin > 1 % nVertices = yy; % else % nVertices = 8; % end % if ischar(nVertices), nVertices = eval(nVertices); end % xx = rand(1, nVertices); % yy = rand(size(xx)); % hold off % tri = delaunay(xx, yy); % h = triplot1(tri, xx, yy); % set(h, 'LineStyle', ':') % iter = 0; % while iter < 10 % iter = iter + 1; % [xo, yo] = feval(mfilename, xx, yy); % if ~isempty(xo), break, end % end % if ~isempty(xo) % hold on % plot([xo xo(1)], [yo yo(1)], '-g', 'LineWidth', 2) % hold off % else % disp([' ## Exceeded 10 iterations. Try again.']) % end % set(gca, 'XLim', [-0.05 1.05], 'YLim', [-0.05 1.05]) % title([mfilename ' demo ' int2str(nVertices)]) % xlabel x % ylabel y % try, zoomsafe, catch, end % set(gcf, 'Name', 'PolyRand Demo') % figure(gcf) % if nargout > 1 % x = xo; % y = yo; % elseif nargout > 0 % x = xo + sqrt(-1)*yo; % end % return %end % %if nargin < 2 % nVertices = xx; % if ischar(nVertices), nVertices = eval(nVertices); end % xx = rand(1, nVertices); % yy = rand(size(xx)); %else % nVertices = length(xx); %end % %% Compute the convex hull. % %tri = delaunay(xx, yy); %tri_original = tri; % %try % hull = feval('convhull', xx, yy); % hull(end) = []; %catch % hull = trihull(tri); %end % %% Rotate to make minimum hull index first. % %f = find(hull == min(hull)); %if length(f) == 1 % hull = hull(:); % hull = [hull(f:end); hull(1:f-1)]; %else % error(' ## Bad starting hull.') %end % %% Eliminate one hull edge from the set, by deleting %% its corresponding triangle. However, never %% completely eliminate any point from the set. %% Repeat until all the points are part of %% the pseudo-hull. For variety, we randomly %% rotate the current hull at each iteration. % %okay = ~~1; %iter = 0; % %while okay & length(hull) < nVertices & iter < 3*nVertices % % iter = iter + 1; % % if (1) % Randomly rotate the hull for variety. % [ignore, index] = sort(rand(size(hull))); % if index(1) > 1 % hull = [hull(index(1):end); hull(1:index(1)-1)]; % end % end % % okay = ~~0; % % hull(end+1) = hull(1); % for i = 1:length(hull)-1 % if sum(tri(:) == hull(i)) > 1 & ... % sum(tri(:) == hull(i+1)) > 1 % f = find(any(tri == hull(i), 2) & any(tri == hull(i+1), 2)); % if any(f) % t = tri(f, :); % t(t == hull(i)) = []; % t(t == hull(i+1)) = []; % if ~any(t == hull) % tri(f, :) = []; % okay = ~~1; % break % end % end % end % end % % if okay % % hull = [hull(1:i); t; hull(i+1:end)]; % hull(end) = []; % % else % Unable to reach an interior point. % %% Find a point that is not yet in the pseudo-hull, but %% connects directly to it. Find an opposing edge that %% connects on both ends to the hull, and that can be %% reflected. Reflect it, then continue processing. % % hull(end) = []; % eligible = 1:nVertices; % eligible(hull) = []; % Eligible vertices remaining. % for j = 1:length(eligible) % f = find(any(tri == eligible(j), 2)); % for k = 1:length(f) % t = tri(f(k), :); % t(t == eligible(j)) = []; % if any(t(1) == hull) & any(t(2) == hull) % tri_new = tri_reflect(tri, xx, yy, t(1), t(2)); % okay = ~isequal(tri_new, tri); % if okay %% disp([' ## Reflected ' mat2str(t)]) % tri = tri_new; % break % else %% disp([' ## Unable to reflect ' mat2str(t)]) % end % end % end % if okay, break, end % end % if ~okay % disp([' ## No edge eligible for reflection.']) % end % end %end % %% Verify that all vertices are included. % %okay = isequal(sort(hull(:).'), 1:nVertices); % %% If not, display the result. % %if ~okay % disp(' ## Invalid result.') % missing = 1:nVertices; % missing(hull) = []; % if ~isempty(missing) % disp([' ## ' mfilename ': Missing vertex # ' mat2str(missing)]) % end % if (1) % figure('Name', 'POLYRAND Error') % subplot(1, 2, 1) % h = triplot(tri_original, xx, yy); % set(h, 'LineStyle', ':') % limits = [-0.05 1.05]; % set(gca, 'XLim', limits, 'YLim', limits) % title('Original') % subplot(1, 2, 2) % h = triplot(tri, xx, yy); % set(h, 'LineStyle', ':') % xxx = xx(hull); xxx(end+1) = xxx(1); % yyy = yy(hull); yyy(end+1) = yyy(1); % hold on % plot(xxx, yyy, 'g-', 'LineWidth', 2) % set(gca, 'XLim', limits, 'YLim', limits) % title('Erroneous') % try, zoomsafe all, catch, end % end %end % %if okay % xx = xx(hull); % yy = yy(hull); %else % xx = []; % yy = []; %end % %if nargout > 1 % x = xx; % y = yy; %elseif nargout > 0 % x = xx + sqrt(-1)*yy; %end fclose(fout); disp(' ## Installing: "polytie.m" (text)') fout = fopen('polytie.m', 'w'); %function theSequence = polytie(i, j) % %% polytie -- Tie polygon edges together. %% polytie(N) demonstrates itself for N points. %% polytie(i, j) ties polygon edges (i, j) together into %% a closed sequence, where each vertex i connects %% to the corresponding j. Every vertex must appear %% exactly twice in the [i j] data. %% polytie([i j]) is an alternative syntax. %% polytie(tri) returns the indices of the perimeter of %% triangulation tri. % %% Copyright (C) 2002 Dr. Charles R. Denham, ZYDECO. %% All Rights Reserved. %% Disclosure without explicit written consent from the %% copyright owner does not constitute publication. % %% Version of 11-Sep-2002 15:47:08. %% Updated 30-Apr-2003 09:50:08. % %if nargin < 1, help(mfilename), i = 'demo'; return, end % %if isequal(i, 'demo'), i = 5; end %if ischar(i), i = eval(i); end % %if length(i) == 1 % n = i; % x = rand(1, n); % y = rand(size(x)); % tri = delaunay(x, y); % theSequence = feval(mfilename, tri); % triplot1(tri, x, y) % set(gcf, 'Name', [mfilename ' ' int2str(n)]) % figure(gcf) % return %end % %[m, n] = size(i); % %if n == 3 % It is a triangulation. % tri = i; % t = [tri(:, [1 2]); tri(:, [2 3]); tri(:, [3 1])]; % t = sort(t, 2); % n = max(max(t)); % s = sparse(t(:, 1), t(:, 2), 1, n, n); % s(s > 1) = 0; % [i, j] = find(s); %elseif n == 2 % It is two columns [i j]. % j = i(:, 2); % i = i(:, 1); %end % %t = [i(:) j(:)]; % %% To the (i, j) indices, append (j, i), %% then sort. % %t = [t; t(:, [2 1])]; % %for k = [2 1] % [ignore, indices] = sort(t(:, k)); % t = t(indices, :); %end % %i = t(:, 1); %j = t(:, 2); %m = max(max(t)); %n = m; % %% Place the two entries for each index i %% at rows 2*i-1 and 2*i. Zeros mark %% unfilled indices. % %tt = zeros(2*max(max(t)), 2); % %[m, n] = size(t); % %for k = m-1:-2:1 % kk = 2*t(k, 1)-1; % tt([kk kk+1], :) = t([k k+1], :); %end % %i = tt(:, 1); %j = tt(:, 2); % %% Using a sparse maatrix, fill the (i, j) %% entry with the vertex that edge (i, j) %% points to. This can be vectorized. % %m = max(max(tt)); %n = m; % %s = sparse(i(i ~= 0), j(j ~= 0), 1, m, n); % %[m, n] = size(tt); % %for k = 1:length(i) % if i(k) > 0 % kk = 2*j(k)-1; % if j(kk) ~= i(k) % s(i(k), j(k)) = j(kk); % else % s(i(k), j(k)) = j(kk+1); % end % end %end % %i = i(i ~= 0); %j = j(j ~= 0); % %i = i(1); %j = j(1); % %[m, n] = size(t); % %sequence = zeros(m/2, 1); %sequence(1) = i; %sequence(2) = j; % %% Follow the sequence. % %for k = 3:m/2 % next = s(i, j); % sequence(k) = next; % i = j; % j = next; %end % %if nargout > 0 % theSequence = sequence; %else % assignin('caller', 'ans', sequence); % disp(sequence) %end fclose(fout); disp(' ## Installing: "tri.m" (text)') fout = fopen('tri.m', 'w'); %function tri % %at(mfilename) fclose(fout); disp(' ## Installing: "tri_bundle.m" (text)') fout = fopen('tri_bundle.m', 'w'); %function tri_bundle % %% tri_bundle -- Bundle the TRI directory. %% tri_bundle (no argument) bundles the M-files %% in the "tri" folder. % %% Copyright (C) 2003 Dr. Charles R. Denham, ZYDECO. %% All Rights Reserved. %% Disclosure without explicit written consent from the %% copyright owner does not constitute publication. % %% Version of 29-Apr-2003 15:34:28. %% Updated 29-Apr-2003 15:34:28. % %fclose('all'); % %at(mfilename) % %d = dir; %i = 0; %for k = 1:length(d) % [pat, nam, ext, ver] = fileparts(d(k).name); % if isequal(ext, '.m') % i = i+1; % theMFiles{i} = nam; % end %end % %for i = length(theMFiles):-1:1 % if isequal(theMFiles{i}, 'tri_install') % theMFiles(i) = []; % end %end % %theMFiles{end+1} = 'zoomsafe'; %theMFiles{end+1} = 'at'; % %theMFiles = sort(theMFiles); % %theMessage = { % ' ' % ' ## Add the "tri" folder to your Matlab path.' % ' ## Execute "polyrand" at the Matlab prompt.' % ' ' %}; % %bund new tri %bund setdir tri %bund('mfile', theMFiles) %bund cd .. %bund('disp', theMessage) %bund close % %if (0) % disp(' ## Manually delete "tri_install.m" if error occurs.') % % fclose('all'); % % at(mfilename) % % delete tri_install.m % delete tri_install.p % % d = dir; % for i = 1:length(d) % theMFiles{i} = strrep(d(i).name, '.m', ''); % end % % for i = length(theMFiles):-1:1 % if isequal(theMFiles{i}, mfilename) % theMFiles(i) = []; % break % end % end % % theMFiles = [sort(theMFiles(:)); {'zoomsafe'}]; % % theMessage = { % 'Restart Matlab, then execute "trisearch"' % 'to see if the installation worked.' % }; % % dst = 'tri_install'; % % self = bundle(dst, 'new'); % % self = add_setdir(self, 'tri'); % self = add_mfile(self, theMFiles); % self = add_message(self, theMessage); % self = add_setdir(self, '..'); % % self = make_pcode(self); %end % fclose(fout); disp(' ## Installing: "tri_reflect.m" (text)') fout = fopen('tri_reflect.m', 'w'); %function tri_out = tri_reflect(tri, x, y, i, j) % %% tri_reflect -- Reflect a triangulation edge. %% tri_reflect(tri, x, y, i, j) reflects edge(i, j) in %% in triangulation tri, whose vertices are (x, y). %% That is, the two triangles that share vertices %% (i, j) are reformed by replacing edge (i, j) %% with an edge spanning the two non-shared %% vertices. This is allowed only if such an %% edge does not already exist, and if it would %% not cross other edges if it did exist. On %% input, all the triangles are expected to %% have the same sense of rotation. % %% Copyright (C) 2002 Dr. Charles R. Denham, ZYDECO. %% All Rights Reserved. %% Disclosure without explicit written consent from the %% copyright owner does not constitute publication. % %% Version of 07-Aug-2002 09:23:54. %% Updated 07-Aug-2002 10:29:40. % %if nargin < 1, help(mfilename), tri = 'demo'; end % %if isequal(tri, 'demo') % n = 4; % x = rand(1, 4); % y = rand(size(x)); % tri = delaunay(x, y); % a = [tri(:, 1:2); tri(:, 2:3); tri(:, [3 1])]; % a = sort(a, 2); % [ignore, ind] = sort(a); % a = a(ind, :); % d = diff(a); % f = find(all(d == 0, 2)); % if any(f) % i = a(f(1), 1); % j = a(f(1), 2); % t = feval(mfilename, tri, x, y, i, j); % subplot % subplot(1, 2, 1) % triplot(tri, x, y) % title('Original') % xlabel x % ylabel y % subplot(1, 2, 2) % triplot(t, x, y) % title('Reflected') % xlabel x % ylabel y % if isequal(tri, t) % title('Not Reflected') % disp([' ## Edge (' int2str([i j]) ') cannot be flipped.']) % end % set(gcf, 'Name', 'Tri_Reflect Demo') % figure(gcf) % end % return %end % %for k = 1:length(i) % % f = find(any(tri == i(k), 2) & any(tri == j(k), 2)); % % if length(f) == 2 % A shared edge. % a = find(tri(f(1), :) == i(k)); % b = find(tri(f(1), :) == j(k)); % if a == b-2 | a == b+1 % f = flipud(f(:)); % Preserve sense. % end % a = tri(f(1), :); % b = tri(f(2), :); % a(a == i(k) | a == j(k)) = []; % b(b == i(k) | b == j(k)) = []; % g = find(any(tri == a, 2) & any(tri == b, 2)); % if ~any(g) % No such edge; try to reflect it. % tri_new = tri; % tri_new(f(1), :) = [a i(k) b]; % tri_new(f(2), :) = [b j(k) a]; % s = trisense(tri, x, y); % s_new = trisense(tri_new, x, y); % if all(s == s_new) % tri = tri_new; % % end % end % end %end % %if nargout > 0 % tri_out = tri; %else % assignin('caller', 'ans', tri) %end fclose(fout); disp(' ## Installing: "triage.m" (text)') fout = fopen('triage.m', 'w'); %function [triout, xout, yout, zout] = triage(tri, x, y, z) % %% triage -- Triangle repair. %% [triout, xout, yout, zout] = triage(tri, x, y, z) performs %% triage on the triangles "tri", whose vertices lie at (x, y, z), %% so that the Matlab "tsearch" function can be applied, despite %% concavities. The algorithm is: %% 1. Cast existing "tri" to counter-clockwise sense. %% 2. Fill all concavities and holes with clockwise %% triangles that have at least one NaN vertex. %% If a "z" vector is given, it will be made compatible %% with the (xout, yout) values. Added boundary points %% will be interpolated from the original z, and all %% supplemental interior points will be set to NaN. %% The output consists of the original triangles and %% data at the top, followed by the supplemental items %% at the bottom. %% triage(N) demonstrates itself with N vertices (default = 32). % %% Copyright (C) 1999 Dr. Charles R. Denham, ZYDECO. %% All Rights Reserved. %% Disclosure without explicit written consent from the %% copyright owner does not constitute publication. % %% Version of 09-Jul-1999 04:43:15. %% Updated 30-Apr-2003 09:52:05. % %if nargin < 1, help(mfilename), tri = 'demo'; end %if isequal(tri, 'demo'), tri = 32; end %if ischar(tri), tri = eval(tri); end % %if length(tri) == 1 % nvertices = tri; % scale = nvertices^(1/4); % rad = 1 + rand(nvertices, 1) / scale; % ang = sort(rand(size(rad)) * 2 * pi); % xy = rad .* exp(ang*sqrt(-1)); % x = real(xy); y = imag(xy); % % [tt, xx, yy, ii] = tripoly(x, y); % % new = ones(size(x)); % new(ii) = 0; % new = find(new); % xnew = xx(new); ynew = yy(new); % % s = trisense(tt, xx, yy); % ccw = find(s > 0); % cw = find(s < 0); % if any(cw), tt(cw, :) = []; end % [to, xo, yo] = feval(mfilename, tt, xx, yy); % delete(get(gca, 'Children')) % hold off % h = tripatch(to, xo, yo); % theBDF = [mfilename ' ' int2str(nvertices)]; % set(h, 'ButtonDownFcn', theBDF) % hold on, plot(x, y, 'o', xnew, ynew, '+'), hold off % set(gca, 'XLim', [-2 2], 'YLim', [-2 2]) % set(gcf, 'Name', theBDF) % figure(gcf) % zoomsafe % return %end % %if nargin < 3, help(mfilename), return, end %if nargin < 4, z = zeros(size(x)); end % %x = x(:); y = y(:); z = z(:); % %trinew = []; % %s = trisense(tri, x, y); %cw = (s < 0); ccw = (s > 0); %tri(cw, :) = fliplr(tri(cw, :)); % %% disp(' ## trihull...') %[h, overlapping] = trihull(tri); % %if ~overlapping %% disp(' ## tripoly...') % h = [NaN; h(:); NaN]; % f = find(isnan(h)); % % kstart = 2; % kstop = length(f); % % for k = kstart:kstop % % remaining = length(f)-k+1; % if 0 & k == 2 | rem(remaining, 10) == 0 % disp([' ## Remaining: ' int2str(remaining) ' segments.']) % end % % hi = h(f(k-1)+1:f(k)-1); % xhi = x(hi); yhi = y(hi); % [ti, xi, yi, ind] = tripoly(xhi(:), yhi(:)); % %% Renumber and rearrange with old on top and new below. % % inserted = length(xi) - length(xhi); % if any(inserted) % disp([' ## "tripoly" has inserted ' int2str(inserted) ' points.']) % % old = ind; % % new = ones(size(xi)); % new(old) = 0; % new = find(new); % % htemp = [old(:); new(:)]; % xi = xi(htemp); % yi = yi(htemp); % % [ignore, hinv] = sort(htemp); % ti = hinv(ti); % % old = 1:length(old); % new = length(old) + (1:length(new)); % old = old(:); % new = new(:); % % hi_old = hi; % hi_new = length(x) + [1:length(new)]; % hi = [hi_old(:); hi_new(:)]; % % xi_new = xi(new); % yi_new = yi(new); % x = [x; xi_new(:)]; % y = [y; yi_new(:)]; % end % % ti = hi(ti); % Map to original indices. % % [m, n] = size(ti); % if n == 1, ti = ti.'; end % s = trisense(ti, x, y); % cw = (s < 0); ccw = (s > 0); % a(k-1) = areaxy(xi, yi); % if a < 0 % cw % ti = ti(ccw, :); % else % ccw. % ti = ti(cw, :); % end % trinew = [trinew; ti]; % end %end % %% Interpolate z for any new (x, y) points. % %if nargin > 3 & length(z) < length(x) % inserted = (length(z)+1):length(x); % z(length(x)) = 0; % z(inserted) = triterp(trinew, x, y, z, x(inserted), y(inserted)); %end % %xnew = []; ynew = []; znew = []; % %if ~isempty(trinew) % [m, n] = size(trinew); % if n == 1, trinew = trinew.'; end % xnew = x(trinew); % ynew = y(trinew); % [m, n] = size(xnew); % if n == 1, xnew = xnew.'; ynew = ynew.'; end % xnew = xnew * [1;1;1] / 3; % ynew = ynew * [1;1;1] / 3; % znew = zeros(size(xnew)) + NaN; %end % %xout = [x; xnew]; %yout = [y; ynew]; %if nargout > 3, zout = [z; znew]; end % %if ~isempty(trinew) % k = (length(x) + (1:length(xnew))).'; % trinew = [[trinew(:, [1 2]); trinew(:, [2 3]); trinew(:, [3 1])] [k; k; k]]; % s = trisense(trinew, xout, yout); % ccw = (s > 0); % if any(ccw) % trinew(ccw, :) = fliplr(trinew(ccw, :)); % end %end % %if nargout > 0 % triout = [tri; trinew]; %end % fclose(fout); disp(' ## Installing: "triarea.m" (text)') fout = fopen('triarea.m', 'w'); %function theResult = triarea(tri, x, y) % %% triarea -- Signed areas of triangles. %% triarea(tri, x, y) returns the areas of the %% triangles tri, whose vertices are (x, y), %% such as returned by "delaunay". % %% Copyright (C) 1999 Dr. Charles R. Denham, ZYDECO. %% All Rights Reserved. %% Disclosure without explicit written consent from the %% copyright owner does not constitute publication. % %% Version of 29-Apr-1999 08:20:50. %% Updated 30-Apr-2003 09:55:04. % %if nargin < 1, help(mfilename), return, end % %t = tri(:, [1 2 3 1]); % %x = x(t); %y = y(t); % %result = 0.5 .* ... % (x(:, 1:3).*y(:, 2:4) - x(:, 2:4).*y(:, 1:3)) * ... % ones(3, 1); % %if nargout > 0 % theResult = result; %else % disp(result) %end fclose(fout); disp(' ## Installing: "triclean.m" (text)') fout = fopen('triclean.m', 'w'); %function [tout, xo, yo, io] = triclean(tri, x, y, ind, verbose) % %% triclean -- Triangle clean-up. %% triclean(tri, x, y, ind) cleans-up the output of "tripoly" %% by combining triangles and flipping quadralaterals that %% involve "fake" points, until the interior triangles no %% longer have any such points. The triangle vertices that %% are indexed in "tri" correspond to the polygon perimeter %% (x, y); the original polygon points (as output by "tripoly") %% are indexed in "ind". The same information is returned, %% now cleaned-up. Only the counter-clockwise triangles remain. % %% Copyright (C) 1999 Dr. Charles R. Denham, ZYDECO. %% All Rights Reserved. %% Disclosure without explicit written consent from the %% copyright owner does not constitute publication. % %% Version of 26-Jul-1999 15:24:23. %% Updated 29-Jul-1999 14:07:29. % %if nargin < 1, help(mfilename), return, end %if nargin < 5, isVerbose = 0; end % %result = []; % %s = trisense(tri, x, y); %ccw = find(s > 0); %cw = find(s < 0); % %if any(cw), tri(cw, :) = []; end % %to = tri; xo = x; yo = y; io = ind; % %tic % %done = 0; %while ~done % done = 1; % %% In the first pass, we squeeze adjacent triangles %% together, if they have a simple geometry. The %% slowest lines are "f = find(to...)" and the next. %% Also the calls to "trisort" and "uniq". % %to = [to(:, [1 2 3]); to(:, [1 3 2]); to(:, [2 1 3]); ... % to(:, [2 3 1]); to(:, [3 1 2]); to(:, [3 2 1])]; % % squeezed = 1; % while any(squeezed) % squeezed = 0; % fake = ones(size(xo)); % fake(io) = 0; % fake = find(fake); % if isempty(fake), break, end % if rem(length(fake), 10) == 0 % disp([' ## Remaining: ' int2str(length(fake))]) % end % for k = 1:length(fake) % node = fake(k); % before = rem(node - 2 + length(xo), length(xo)) + 1; % after = rem(node, length(xo)) + 1; % f = find(to(:, 1) == before & to(:, 2) == node); % Slow 23-31%. % g = find(to(:, 1) == node & to(:, 2) == after); % Slow 22-30%. % for j = 1:length(g) % for i = 1:length(f) % if to(f(i), 3) == to(g(j), 3) % opposite = to(f(i), 3); % temp = sort([before opposite after]); % indices = [1 2 3; 1 3 2; 2 1 3; ... % 2 3 1; 3 1 2; 3 2 1]; % tnew = temp(indices); % if isVerbose % disp([' ## Squeezed: ' int2str(node) ... % ' ' mat2str(to(f(i), :)) ... % ' ' mat2str(to(g(j), :)) ... % ' ' mat2str(tnew(1, :))]) % end % h = find(any(to.' == node)); % to(h(1:6), :) = tnew; % to(h(7:end), :) = []; % xo(node) = []; % yo(node) = []; % io(io == node) = []; % io(io > node) = io(io > node) - 1; % to(to > node) = to(to > node) - 1; % squeezed = 1; % done = 0; % break % end % end % if squeezed, break, end % end % if squeezed, break, end % end % end % % to = trisort(to); % Slow 7-13%. % to = uniq(to); % Slow 7-12%. % % s = trisense(to, xo, yo); % cw = (s < 0); % if any(cw), to(cw, :) = fliplr(to(cw, :)); end % %% In the second pass, we flip one convex quadralateral %% that involves a fake point. Then, we go back to %% pass #1. % % [m, n] = size(to); % to = [to(:, [1 2 3]); to(:, [1 3 2]); to(:, [2 1 3]); ... % to(:, [2 3 1]); to(:, [3 1 2]); to(:, [3 2 1])]; % % indices = (1:m).'; % indices = indices * ones(1, 6); % to = [to indices(:)]; % % flipped = 1; % % while any(flipped) % flipped = 0; % flag = 0; % fake = ones(size(xo)); % fake(io) = 0; % fake = find(fake); % if isempty(fake), break, end % for k = 1:length(fake) % node = fake(k); % f = find(to(:, 1) == node); % for j = 1:length(f)-1 % for i = j+1:length(f) % if to(f(i), 2) == to(f(j), 2) % a = node; % b = to(f(i), 3); % c = to(f(i), 2); % d = to(f(j), 3); % abcd = [a b c d]; % xtemp = xo(abcd); % ytemp = yo(abcd); % if isconvex(xtemp, ytemp) % if isVerbose % disp([' ## Flipped: ' mat2str([a b c d])]) % end % triangle = to(f(i), 4); % h = find(to(:, 4) == triangle); % to(h(1), :) = [a b d triangle]; % triangle = to(f(j), 4); % h = find(to(:, 4) == triangle); % to(h(1), :) = [b c d triangle]; % flipped = 1; % done = 0; % break % end % end % end % if flipped, break, end % end % if flipped, break, end % end % flipped = 0; % Do just one. % end % % to = to(1:m, 1:3); % to = trisort(to); % to = uniq(to); % % s = trisense(to, xo, yo); % cw = (s < 0); % if any(cw), to(cw, :) = fliplr(to(cw, :)); end %end % %toc % %if nargout > 0 % tout = to; %else % assignin('caller', 'ans', to) %end % %fake = ones(length(x), 1); %fake(ind) = 0; %fake = find(fake); % %subplot(1, 2, 1) %delete(get(gca, 'Children')) %hold off %axis normal %tripatch(tri, x, y) %hold on %% plot(x(ind), y(ind), 'o-') %plot(x(fake), y(fake), '+') %hold off %zoomsafe out % %fake = ones(length(xo), 1); %fake(io) = 0; %fake = find(fake); % %subplot(1, 2, 2) %delete(get(gca, 'Children')) %hold off %axis normal %tripatch(to, xo, yo) %hold on %% plot(xo(io), yo(io), 'o-') %plot(xo(fake), yo(fake), '+') %hold off %zoomsafe out % %zoomsafe all fclose(fout); disp(' ## Installing: "tridemo.m" (text)') fout = fopen('tridemo.m', 'w'); %function tridemo(nPoints) % %% tridemo -- Demonstration of "triage". %% tridemo(nPoints) shows the result of applying %% "triage" to a non-convex set of triangles, %% based on nPoints random points (default = 10). %% The original triangles are displayed in "green"; %% the added ones are in "red"; and circles show %% the locations of added "nanified" points. %% Clicking on any triangle will cause the demo %% to repeat itself with different points. % %% Copyright (C) 1999 Dr. Charles R. Denham, ZYDECO. %% All Rights Reserved. %% Disclosure without explicit written consent from the %% copyright owner does not constitute publication. % %% Version of 12-Jul-1999 08:13:31. %% Updated 12-Jul-1999 16:52:44. % %if nargin < 1, help(mfilename), nPoints = 'demo'; end %if isequal(nPoints, 'demo'), nPoints = 10; end %if ischar(nPoints), nPoints = eval(nPoints); end % %overlapping = 1; % %while overlapping % x = rand(nPoints, 1); % y = rand(nPoints, 1); % tri = delaunay(x, y); % % index = 0; % while any(index < 1 | index > nPoints) % remove = ceil(sqrt(nPoints)); % index = fix(nPoints * rand(1, remove)) + 1; % end % % tri(index, :) = []; % % s = trisense(tri, x, y); % tri(s < 0, :) = fliplr(tri(s < 0, :)); % % [th, overlapping] = trihull(tri); % segments = sum(isnan(th)) + 1; %end % %[to, xo, yo, zo] = triage(tri, x, y); % %s = trisense(to, xo, yo); %cw = (s < 0); %ccw = (s > 0); % %delete(get(gca, 'Children')) % %hold off %if any(cw) % h = trimesh(to(cw, :), xo, yo, 0*xo); % set(h, 'FaceColor', [1 0 0]) % set(h, 'ButtonDownFcn', ['tridemo ' int2str(nPoints)]) % f = find(isnan(zo)); % if any(f) % hold on % plot(xo(f), yo(f), 'ko') % hold off % end %end %hold on %if any(ccw) % h = trimesh(to(ccw, :), xo, yo, 0*xo); % set(h, 'FaceColor', [0 1 0]) % set(h, 'ButtonDownFcn', ['tridemo ' int2str(nPoints)]) %end %hold off %view(2) %zoomsafe %set(gcf, 'Name', ['tridemo ' int2str(nPoints)]) %figure(gcf) fclose(fout); disp(' ## Installing: "trigui.m" (text)') fout = fopen('trigui.m', 'w'); %function [trio, xo, yo] = trigui(tri, x, y) % %% trigui -- Manipulate a triangulation. %% trigui('demo') calls "trigui(10)". %% trigui(N) demonstrates itself with N points %% (default = 10). %% trigui(tri, x, y) plots the triangulation (tri, x, y), %% then allows the user to add/delete/move points by %% manipulating vertices, edges, and triangles. Each %% change forces the data to be re-triangulated. %% trigui('method', x, y) uses the given 'method' %% to triangulate the (x, y) data. The method %% must return an array of indices, analogous %% to the output of the 'delaunay' routine. %% Although 'trigui' was written with triangles %% in mind, any number of polygon vertices is %% allowed, so long as there is an appropriate %% 'method' to process them. %% trigui(x, y) uses 'delaunay' to triangulate %% the (x, y) data. %% [trio, xo, yo] = trigui('get') returns the current %% data. If only one argument is provided, a struct %% of the current data is returned. %% %% Button #1 (Mac normal) on any item to drag it. %% #2 (Mac shift-click) on a triangle to add a point. %% #3 (Mac option-click) on any item delete it. %% %% To add an exterior point, add it within an existing %% triangle, then drag it outside. %% %% While the mouse-button is down, its (x, y) position %% is shown in the figure's title bar. % %% Copyright (C) 2002 Dr. Charles R. Denham, ZYDECO. %% All Rights Reserved. %% Disclosure without explicit written consent from the %% copyright owner does not constitute publication. % %% Version of 13-Sep-2002 09:32:05. %% Updated 29-Apr-2003 16:22:07. % %% Question: What is the region within which %% a vertex can be moved without changing a %% Delaunay tessellation? % %persistent theItem %persistent theDownXY %persistent theClone % %if nargin < 1, help(mfilename), tri = 'demo'; end %if isequal(tri, 'demo'), tri = 10; end % %if ischar(tri) & any(tri(1) == '0123456789') % tri = eval(tri); %end % %if length(tri) == 1 % n = tri; % x = rand(1, n); % y = rand(size(x)); % tri = delaunay(x, y); % feval(mfilename, tri, x, y); % return %end % %theBDF = [mfilename ' ButtonDownFcn']; %theWBDF = [mfilename ' WindowButtonDownFcn']; %theWBMF = [mfilename ' WindowButtonMotionFcn']; %theWBUF = [mfilename ' WindowButtonUpFcn']; % %% Update the drawing. % %if nargin > 1 % if nargin == 2 % y = x; % x = tri; % tri = 'delaunay'; % end % if ischar(tri) % theMethod = tri; % tri = feval(theMethod, x, y); % else % theMethod = 'delaunay'; % end % theItem = []; % theDownXY = []; % theData = []; % theData.tri = tri; % theData.x = x; % theData.y = y; % theData.method = theMethod; % set(gcf, 'UserData', theData) % % [m, n] = size(tri); % % % Plot polygons. % % if n > 2 % t = tri; % theTriangles = zeros(m, 1); % delete(get(gca, 'Children')) % hold off % for i = 1:m % xx = x(t(i, :)); % yy = y(t(i, :)); % theTriangles(i) = patch(xx, yy, 0*xx, ... % 'FaceColor', 'y', ... % 'EdgeColor', 'none', ... % 'ButtonDownFcn', theBDF, ... % 'UserData', t(i, :), ... % 'Tag', 'polygon'); % hold on % end % end % % % Plot edges. % % if n > 1 % t = zeros(m*(n-1), 2); % k = 0; % for i = 1:n % if i < n % t(k+1:k+m, :) = tri(:, [i i+1]); % else % t(k+1:k+m, :) = tri(:, [i 1]); % end % k = k + m; % end % for i = [2 1] % [ignore, indices] = sort(t(:, i)); % t = t(indices, :); % end % d = diff(t); % f = find(all(d == 0, 2)); % t(f, :) = []; % [m, n] = size(t); % theEdges = zeros(m, 1); % for i = 1:m % xx = x(t(i, :)); % yy = y(t(i, :)); % theEdges(i) = plot(xx, yy, 'k-', ... % 'LineWidth', 2.5, ... % 'ButtonDownFcn', theBDF, ... % 'UserData', t(i, :), ... % 'Tag', 'edge'); % end % end % % % Plot vertices. % % theVertices = zeros(size(x)); % for i = 1:length(x) % theVertices(i) = plot(x(i), y(i), 'ko', ... % 'MarkerFaceColor', 'k', ... % 'ButtonDownFcn', theBDF, ... % 'UserData', i, ... % 'Tag', 'vertex'); % end % hold off % set(gcf, 'ButtonDownFcn', theBDF) % set(gcf, 'Pointer', 'arrow') % set(gcf, 'Name', 'TriGUI') % title('') % figure(gcf) % return %end % %if ~ischar(tri), return, end % %p = get(gca, 'CurrentPoint'); %px = p(1, 1); %py = p(1, 2); % %theData = get(gcf, 'UserData'); %theTri = theData.tri; %theX = theData.x; %theY = theData.y; %theMethod = theData.method; % %theCommand = tri; %theTag = get(gcbo, 'Tag'); %theSelectionType = get(gcbf, 'SelectionType'); % %% Double-clicking: not invoked. % %CAN_DOUBLE_CLICK = ~~0; %if CAN_DOUBLE_CLICK % switch lower(theCommand) % case 'buttondownfcn' % if doubleclick % theCommand = 'DoubleClickFcn' % return % end % otherwise % end %end % %switch lower(theCommand) % case 'get' % if nargout < 2 % trio = theData; % else % trio = theTri; % xo = x; % yo = y; % end % case 'buttondownfcn' % set(gcf, 'Name', num2str([px py], 4)) % switch lower(theTag) % case {'vertex', 'edge', 'polygon'} % theItem = gcbo; % theDownXY = [px py]; % set(gcf, 'Pointer', 'circle') % theIndices = get(theItem, 'UserData'); % theColor = 'g'; % if length(theIndices) < 3 % theClone = line( ... % theX(theIndices), theY(theIndices), ... % 'Color', theColor, ... % 'Marker', 'o', 'LineStyle', '-', ... % 'EraseMode', 'xor'); % else % theClone = patch( ... % theX(theIndices), theY(theIndices), ... % theColor, ... % 'Marker', 'o', 'LineStyle', '-', ... % 'EraseMode', 'xor'); % end % otherwise % end % switch lower(theTag) % case 'vertex' % set(theItem, 'MarkerEdgeColor', 'r', ... % 'MarkerFaceColor', 'r') % case 'edge' % % theItem = gcbo; % set(theItem, 'Color', 'r') % case 'polygon' % % theItem = gcbo; % set(theItem, 'FaceColor', 'r') % otherwise % end % switch lower(theTag) % case {'vertex', 'edge', 'polygon'} % theIndices = get(theItem, 'UserData'); % switch lower(theSelectionType) % case 'extend' % switch lower(theTag) % case 'polygon' % theX(end+1) = px; % theY(end+1) = py; % feval(mfilename, theMethod, theX, theY) % otherwise % end % case 'alt' % [m, n] = size(theTri); % if length(theX) - length(theIndices) >= n % theX(theIndices) = []; % theY(theIndices) = []; % end % feval(mfilename, theMethod, theX, theY) % otherwise % set(gcf, 'WindowButtonMotionFcn', theWBMF) % set(gcf, 'WindowButtonUpFcn', theWBUF) % end % otherwise % end % case 'windowbuttondownfcn' % case 'windowbuttonmotionfcn' % set(gcf, 'Name', num2str([px py], 4)) % dx = px - theDownXY(1); % dy = py - theDownXY(2); % theIndices = get(theItem, 'UserData'); % x = theX(theIndices) + dx; % y = theY(theIndices) + dy; % set(theClone, 'XData', x, 'YData', y); % case 'windowbuttonupfcn' % set(gcf, 'Name', num2str([px py], 4)) % theTag = get(theItem, 'Tag'); % set(gcf, 'WindowButtonMotionFcn', '') % set(gcf, 'WindowButtonUpFcn', '') % set(gcf, 'Pointer', 'arrow') % dx = px - theDownXY(1); % dy = py - theDownXY(2); % switch lower(theTag) % case {'edge', 'vertex', 'polygon'} % delete(theClone) % theClone = []; % theIndices = get(theItem, 'UserData'); % theX(theIndices) = theX(theIndices) + dx; % theY(theIndices) = theY(theIndices) + dy; % feval(mfilename, theMethod, theX, theY) % otherwise % end % theItem = []; % theDownXY = []; % otherwise % disp([' ## ' theCommand ' ' theType]) %end fclose(fout); disp(' ## Installing: "trihull.m" (text)') fout = fopen('trihull.m', 'w'); %function [theHull, nonUnique] = trihull(theTri) % %% trihull -- Indices of boundary of triangulation. %% trihull(theTri) returns the indices of the bounding %% polygon associated with theTri triangulation. This %% corresponds to the convex-hull if the triangles form %% a filled convex set. For triangulations that contain %% holes, the individual segments are separated by NaNs. %% [theHull, nonUnique] = trihull(theTri) also returns %% nonUnique = TRUE (non-zero) if any point appears in %% more than one segment. % %% Copyright (C) 1999 Dr. Charles R. Denham, ZYDECO. %% All Rights Reserved. %% Disclosure without explicit written consent from the %% copyright owner does not constitute publication. % %% Version of 02-Jul-1999 17:02:50. %% Updated 30-Apr-2003 10:19:13. % %if nargin < 1 % help(mfilename) % theTri = 'demo'; %end % %if isequal(theTri, 'demo'), theTri = 10; end %if ischar(theTri), theTri = eval(theTri); end % %if length(theTri) == 1 % try % nPoints = theTri; % x = rand(nPoints, 1); y = rand(size(x)); % tri = delaunay(x, y); % h = feval(mfilename, tri); % trimesh(tri, x, y, x*0) % view(2) % px = x(h); py = y(h); % px(end+1) = px(1); py(end+1) = py(1); % hold on % plot(px, py, '-bo') % hold off % f = findobj(gcf, 'Type', 'patch'); % theBDF = [mfilename ' ' int2str(nPoints)]; % title(theBDF) % set(f, 'buttondownfcn', theBDF) % set(gcf, 'Name', [mfilename ' Demo']) % zoomsafe % figure(gcf) % if nargout > 0, theHull = h; end % return % catch % disp([' ## ' mfilename ' error.']) % disp([' ## ' lasterr]) % disp([' ## ' mfilename ' needs work.']) % return % end %end % %t = [theTri(:, [1 2]); theTri(:, [2 3]); theTri(:, [3 1])]; % %m = max(max(t)); n = m; % %s = sparse(t(:, 1), t(:, 2), ones(size(t(:, 1))), m, n); % %t = sort(t.').'; %s1 = sparse(t(:, 1), t(:, 2), ones(size(t(:, 1))), m, n); % %s1 = s1 + s1.'; % %[i, j] = find(s == 1 & s1 == 1); % Too slow. % %[i, indices] = sort(i); %j = j(indices); % %connect(i) = j; % %h = zeros(size(i)); %f = find(connect); %f = f(1); %h(1) = connect(f); %connect(f) = 0; %starts(1) = 1; % %for k = 2:length(h) %% remaining = length(h)-k+1; %% if rem(remaining, 1000) == 0 & k > 2 %% disp([' ## Remaining: ' int2str(remaining) ' edges.']) %% end % if connect(h(k-1)) % h(k) = connect(h(k-1)); % connect(h(k-1)) = 0; % else % f = find(connect); % if any(f) % f = f(1); % h(k) = connect(f); % connect(f) = 0; % starts(end+1) = k; % else % break % end % end %end % %if 0 & length(starts) > 1 % disp([' ## Segments: ' int2str(length(starts))]) %end % %% Check perimeters for points represented more than once. % %htemp = h(h ~= 0); %s = sparse(htemp, htemp, ones(size(htemp))); %[i, j] = find(s > 1); %nonUnique = any(i); %if nonUnique & nargout < 2 % disp([' ## ' mfilename ': Some perimeters overlap.']) %end % %if length(starts) > 1 % htemp = []; % starts(end+1) = length(h) + 1; % for k = 1:length(starts)-1 % i = starts(k):starts(k+1)-1; % if k > 1, htemp = [htemp; NaN]; end % htemp = [htemp; h(i)]; % end % h = htemp; %end % %if nargout > 0 % theHull = h; %else % assignin('caller', 'ans', h) %end fclose(fout); disp(' ## Installing: "trihull1.m" (text)') fout = fopen('trihull1.m', 'w'); %function h = trihull1(tri) % %% trihull1 -- Alternative to TRIHULL. %% trihull1('demo') demonstrates itself. %% trihull1(N) demonstrates itself with N points. %% trihull1(tri) returns the convex-hull %% for triangulation tri. Does not employ %% sparse matrices. %% %% This is an attempt to accelerate the process, %% but alas, TRIHULL is 3x faster. Evidently, %% the sparse matrix operations are very quick. %% %% Also see: TRIHULL, TRIPLOT, DELAUNAY. % %% Copyright (C) 2002 Dr. Charles R. Denham, ZYDECO. %% All Rights Reserved. %% Disclosure without explicit written consent from the %% copyright owner does not constitute publication. % %% Version of 07-Aug-2002 18:47:49. %% Updated 30-Apr-2003 10:49:27. % %if nargin < 1, tri = 'demo'; end %if isequal(tri, 'demo'), tri = 10; end %if ischar(tri), tri = eval(tri); end % %if length(tri) == 1 % try % n = tri; % x = rand(1, n); % y = rand(size(x)); % tri = delaunay(x, y); % hh = feval(mfilename, tri); % hhh = trihull(tri); % f = find(hhh == min(hhh)); % if f > 1 % hhh = [hhh(f:end); hhh(1:f-1)]; % end % if ~isequal(hh, hhh) % disp([' ## TRIHULL1 result not same as TRIHULL result.']) % end % hold off % hhh = [hh; hh(1)]; % plot(x(hhh), y(hhh), 'g-', 'LineWidth', 3) % hold on % triplot(tri, x, y) % title([mfilename ' ' int2str(n)]) % xlabel x % ylabel y % limits = [-0.05 1.05]; % set(gca, 'XLim', limits, 'YLim', limits) % set(gcf, 'Name', 'TriHull1 Demo') % try, zoomsafe, catch, end % figure(gcf) % return % catch % disp([' ## ' mfilename ' error.']) % disp([' ## ' lasterr]) % disp([' ## ' mfilename ' needs work.']) % return % end %end % %t = [tri(:, [1 2]); tri(:, [2 3]); tri(:, [3 1])]; % %t1 = sort(t, 2); %t2 = t; % %[ignore, i] = sort(t1(:, 2)); %t1 = t1(i, :); %t2 = t2(i, :); %[ignore, i] = sort(t1(:, 1)); %t1 = t1(i, :); %t2 = t2(i, :); % %% Keep only unique edges. % %d = diff(t1); %f = find(all(d == 0, 2)); %g = sort([f; f+1]); %g(diff(g) == 0) = []; %t2(g, :) = []; % %% Make a transition list. % %j = zeros(max(t2(:, 1)), 1); % %j(t2(:, 1)) = t2(:, 2); %f = find(j > 0); %f = f(1); % %% Traverse the list. % %[m, n] = size(t2); %h = zeros(m, 1); %for i = 1:length(h) % h(i) = f; % f = j(f); % Trouble here. %end fclose(fout); disp(' ## Installing: "trilabel.m" (text)') fout = fopen('trilabel.m', 'w'); %function theTextHandles = trilabel(tri, x, y, varargin) % %% trilabel -- Label plot of triangulation. %% trilabel (no argument) demonstrates itself. %% trilabel(tri, x, y, ...) labels the vertices and %% triangles of triangulation tri, as either 1..N %% or 0:N-1, depending on the base of the "tri" %% indices. The handles of the text-objects are %% returned. % %% Copyright (C) 2001 Dr. Charles R. Denham, ZYDECO. %% All Rights Reserved. %% Disclosure without explicit written consent from the %% copyright owner does not constitute publication. % %% Version of 30-Jul-2001 14:32:13. %% Updated 11-Sep-2002 21:04:15. % %% Demonstration. % %if nargin < 1 % % help(mfilename) % % tri = [ % 0 1 7 % 1 2 3 % 3 4 5 % 5 6 7 % 7 3 5 % 7 1 3 % ]; % % lonlat = [ % -124.018048 46.694592 1 % -124.044816 46.668488 1 % -124.017968 46.650984 1 % -123.992400 46.664772 1 % -123.964264 46.646212 1 % -123.929744 46.673788 1 % -123.956592 46.696068 1 % -123.991760 46.683868 1 % ]; % % x = lonlat(:, 1); % y = lonlat(:, 2); % % triplot(tri+1, x, y) % %end % %isZero = (min(tri(:)) == 0); % %t = [tri(:, 1:2); tri(:, 2:3); tri(:, 3:-2:1)]; % %tt = t.'; %if isZero % tt = tt + 1; %end % %x = x(:).'; %y = y(:).'; % %xx = x(tt); %yy = y(tt); % %if (0) % Legacy of TRIPLOT1. % if nargin < 4 % h = plot(xx, yy, 'b-'); % else % h = plot3(xx, yy, 'b-', varargin{:}); % end %end % %k = 1:length(x); %if isZero % k = k - 1; %end % %label = cell(size(x)); %for i = 1:length(x) % index = k(i); % label{i} = int2str(index); %end % %h1 = text(x, y, label, 'Color', 'k', ... % 'HorizontalAlignment', 'center', ... % 'VerticalAlignment', 'middle', ... % 'FontWeight', 'bold', 'FontSize', 12, ... % 'Tag', [mfilename 'vertex']); % %t = tri.'; %if isZero, t = t + 1; end % %xx = mean(x(t)); %yy = mean(y(t)); % %[m, n] = size(tri); %k = 1:m; %if isZero, k = k - 1; end % %label = cell(size(xx)); %for i = 1:length(k) % index = k(i); % label{i} = int2str(index); %end % %h2 = text(xx, yy, label, 'Color', 'r', ... % 'HorizontalAlignment', 'center', ... % 'VerticalAlignment', 'middle', ... % 'FontWeight', 'bold', 'FontSize', 12, ... % 'Tag', [mfilename 'triangle']); % %if nargout > 0, theTextHandles = [h1; h2]; end fclose(fout); disp(' ## Installing: "tripatch.m" (text)') fout = fopen('tripatch.m', 'w'); %function theHandles = tripatch(tri, x, y, z) % %% tripatch -- Plot triangles w/r to sense. %% tripatch(tri, x, y, z) plots the triangles tri, %% using green for counter-clockwise sense and %% red for clockwise. The patch-handles are %% returned. % %% Copyright (C) 1999 Dr. Charles R. Denham, ZYDECO. %% All Rights Reserved. %% Disclosure without explicit written consent from the %% copyright owner does not constitute publication. % %% Version of 22-Jul-1999 13:31:09. %% Updated 30-Apr-2003 10:23:13. % %if nargin < 3, help(mfilename), return, end %if nargin < 4, z = 0*x; end % %red = [1 0 0]; %green = [0 1 0]; %blue = [0 0 1]; %white = red + blue + green; %black = 0*white; % %[m, n] = size(tri); % %theSense = trisense(tri, x, y); %ccw = find(theSense > 0); %cw = find(theSense < 0); % %h = [NaN; NaN]; % %wasHold = ishold; % %if any(cw) % t = tri(cw, :).'; % if nargin < 4 % h(2) = patch(x(t), y(t), red, 'EdgeColor', black); % else % h(2) = patch(x(t), y(t), z(t), red, 'EdgeColor', black); % end % hold on %end % %if any(ccw) % t = tri(ccw, :).'; % if nargin < 4 % h(1) = patch(x(t), y(t), green, 'EdgeColor', white); % else % h(1) = patch(x(t), y(t), z(t), green, 'EdgeColor', white); % end %end % %if ~isnan(h(2)) % set(h(2), 'EdgeColor', black) %end % %if ~isnan(h(1)) % set(h(1), 'EdgeColor', white) %end % %if ~wasHold, hold off, end % %if nargout > 0, theHandles = h; end fclose(fout); disp(' ## Installing: "triperim.m" (text)') fout = fopen('triperim.m', 'w'); %function thePerimeter = triperim(theTri) % %% triperim -- Indices of triangulation perimeter. %% triperim(theTri) returns the indices of points %% comprising the perimeter of theTri triangulation. %% %% Also see: POLYTIE. % %% Copyright (C) 2002 Dr. Charles R. Denham, ZYDECO. %% All Rights Reserved. %% Disclosure without explicit written consent from the %% copyright owner does not constitute publication. % %% Version of 11-Sep-2002 11:54:10. %% Updated 30-Apr-2003 10:24:18. % %if nargin < 1, help(mfilename), return, end % %p = polytie(theTri); % %if nargout > 0 % thePerimeter = p; %else % assignin('caller', 'ans', p) %end fclose(fout); disp(' ## Installing: "triplot1.m" (text)') fout = fopen('triplot1.m', 'w'); %function theHandle = triplot1(tri, x, y, varargin) % %% triplot1 -- Simple plot of triangulation. %% triplot1('demo') demonstrates itself with %% some hard-wired data. %% triplot1(N) demonstrates itself with a %% triangulation of N points (default = 8). %% triplot1(tri, x, y, ...) plots the given triangulation, %% whose indices are "tri", and whose positions are %% (x, y). Additional name/value pairs are passed %% directly to the "plot" command. The vertices and %% triangles are labeled, either 1..N or 0..N-1, %% depending on the base of the "tri" indices. % %% Copyright (C) 2001 Dr. Charles R. Denham, ZYDECO. %% All Rights Reserved. %% Disclosure without explicit written consent from the %% copyright owner does not constitute publication. % %% Version of 30-Jul-2001 14:32:13. %% Updated 30-Jul-2001 14:32:13. % %% Demonstration. % %if nargin == 1 & isequal(tri, 'demo') % % help(mfilename) % % tri = [ % 0 1 7 % 1 2 3 % 3 4 5 % 5 6 7 % 7 3 5 % 7 1 3 % ]; % % lonlat = [ % -124.018048 46.694592 1 % -124.044816 46.668488 1 % -124.017968 46.650984 1 % -123.992400 46.664772 1 % -123.964264 46.646212 1 % -123.929744 46.673788 1 % -123.956592 46.696068 1 % -123.991760 46.683868 1 % ]; % % x = lonlat(:, 1); % y = lonlat(:, 2); %end % %if nargin < 1, tri = 8; end %if ischar(tri), tri = eval(tri); end % %if length(tri) == 1 % n = tri; % x = rand(1, n); % y = rand(size(x)); % tri = delaunay(x, y); %end % %if nargin < 3 % % feval(mfilename, tri, x, y); % % set(gcf, 'Name', [upper(mfilename) ' Demo']) % figure(gcf) % % return % %end % %isZero = (min(tri(:)) == 0); % %t = [tri(:, 1:2); tri(:, 2:3); tri(:, 3:-2:1)]; % %tt = t.'; %if isZero % tt = tt + 1; %end % %x = x(:).'; %y = y(:).'; % %xx = x(tt); %yy = y(tt); % %if nargin < 4 % h = plot(xx, yy, 'b-'); %else % h = plot3(xx, yy, 'b-', varargin{:}); %end % %k = 1:length(x); %if isZero % k = k - 1; %end % %label = cell(size(x)); %for i = 1:length(x) % index = k(i); % label{i} = int2str(index); %end % %text(x, y, label, 'Color', 'k', ... % 'HorizontalAlignment', 'center', ... % 'VerticalAlignment', 'middle', ... % 'FontWeight', 'bold', 'FontSize', 12); % %t = tri.'; %if isZero, t = t + 1; end % %xx = mean(x(t)); %yy = mean(y(t)); % %[m, n] = size(tri); %k = 1:m; %if isZero, k = k - 1; end % %label = cell(size(xx)); %for i = 1:length(k) % index = k(i); % label{i} = int2str(index); %end % %text(xx, yy, label, 'Color', 'r', ... % 'HorizontalAlignment', 'center', ... % 'VerticalAlignment', 'middle', ... % 'FontWeight', 'bold', 'FontSize', 12); % %if nargout > 0, theHandle = h; end fclose(fout); disp(' ## Installing: "tripoly.m" (text)') fout = fopen('tripoly.m', 'w'); %function [tout, xout, yout, ind] = tripoly(x, y, doPlot) % %% tripoly -- Triangulation of a polygon. %% [tout, xout, yout, ind] = tripoly(x, y, doPlot) modifies polygon %% points (x, y), such that its triangulation tout consists solely %% of strictly interior and exterior triangles, identifiable by their %% counter-clockwise or clockwise sense, respectively. Use the %% "trisense" function to distinguish between them. The returned %% ind vector contains indices for reconstructing the original %% polygon, using x = xout(ind) and y = yout(ind). Points not %% listed in ind are "fake", i.e. added to achieve the goal of %% this routine. %% tripoly(nVertices, doPlot) demonstrates itself with nVertices %% (random). Clicking on any triangle invokes the demonstration %% again with different data. The "fake" points are marked by %% a solid symbol. The plot is zoomable via "zoomsafe". % %% Copyright (C) 1999 Dr. Charles R. Denham, ZYDECO. %% All Rights Reserved. %% Disclosure without explicit written consent from the %% copyright owner does not constitute publication. % %% Version of 07-Jul-1999 09:15:01. %% Updated 30-Apr-2003 09:43:28. % %% The following URL describes the interesting Seidel's %% Algorithm, not used here, in which the polygon is %% decomposed first into trapezoids, and then into %% "monotone" polygons, which are triangulated: %% % %if nargin < 1, help(mfilename), x = 'demo'; end %if isequal(x, 'demo'), x = 32; end %if ischar(x), x = eval(x); end % %if nargin < 3, doPlot = 0; end % %if length(x) == 1 % if nargin > 1 % doPlot = y; % elseif nargout < 1 % doPlot = 1; % else % doPlot = 0; % end % nVertices = x; % scale = nVertices^(1/3); % rad = 1 + rand(nVertices, 1) / scale; % ang = sort(rand(size(rad)) * 2 * pi); % xy = rad .* exp(ang*sqrt(-1)); % x = real(xy); y = imag(xy); %end % %xi = x(:); yi = y(:); %[zi, indices] = uniq([xi yi]); %xi = zi(:, 1); yi = zi(:, 2); % %if length(xi) ~= length(x) % warning(' ## Some data were culled because of non-uniqueness.') %end % %% Make the polygon counter-clockwise. %% Perhaps this step should not be done. % %if (0) % if areaxy(xi, yi) < 0 % xi = flipud(xi); % yi = flipud(yi); % end %end % %% Algorithm: after triangulating the (x, y) points, %% search for polygon edges that do not appear in %% the triangulation itself. Bisect those orphaned %% edges, re-triangulate, then test again, iterating %% until no such edges remain. This scheme will %% converge so long as the poly-line does not intersect %% itself. % %% Eventually, we will stamp out the supplemental points, %% ideally producing a triangularization from the original %% points alone. This will be done by combining adjacent %% triangles into a larger one where possible. Where not, %% we will flip diagonals in existing quadralaterals, thereby %% eliminating all edges that refer to one or more supplemental %% points. Those points can then be deleted. % %% disp(' ') % %% tic % %added = zeros(length(xi), 1); % %orphans = 1; % %iteration = 0; %while any(orphans) % iteration = iteration + 1; % tri = delaunay(xi, yi); % tri = sort(tri.').'; % edges = [tri(:, [1 2]); tri(:, [1 3]); tri(:, [2 3]); [length(xi) length(xi)]]; % s = sparse(edges(:, 1), edges(:, 2), ones(size(edges(:,1)))); % orphans = zeros(1, length(xi)); % k = [1:length(xi) 1]; % len = length(k); % for i = len:-1:2 % if i == len % found = s(k(i), k(i-1)); % else % found = s(k(i-1), k(i)); % end % orphans(k(i-1)) = ~found; % end % % f = find(orphans); % if any(f) % added(end+1) = 0; % added = [added ones(size(added))].'; % k = 1:length(xi)+1; % ki = zeros(2, length(xi)+1); % ki(1, :) = 1:length(xi)+1; % ki(2, f) = f+0.5; %% added = added(logical(ki)); % added = added(~~ki); % added = added(:); % added(end) = []; %% ki = ki(logical(ki)); % ki = ki(~~ki); % xtemp = xi(:); xtemp(end+1) = xi(1); % ytemp = yi(:); ytemp(end+1) = yi(1); % xi = interp1(k, xtemp, ki, '*linear'); % yi = interp1(k, ytemp, ki, '*linear'); % xi(end) = []; % yi(end) = []; % xi = xi(:); % yi = yi(:); % end % % if any(orphans) & rem(iteration, 10) == 0 % disp([' ## ' mfilename ': orphans: ' int2str(sum(orphans))... % '; length: ' int2str(length(xi))]); % end %end % %tri = trisort(tri); % %% To polish the solution, traverse around the original polygon, %% seeking each "added" point in turn. If its geometry is %% "simple", then the two adjacent interior triangles can be %% squeezed together. Iterate until no such situations remain. %% If we are lucky, the interior will thereby become devoid %% of added triangles. % %% disp([' ## Elapsed time: ' num2str(toc) ' seconds.']) % %if nargout > 0 % tout = tri; xout = xi; yout = yi; ind = find(~added); %end % %if ~doPlot, return, end % %disp([' ## Added ' int2str(sum(~~added)) ' points.']) % %red = [1 0 0]; %green = [0 1 0]; %blue = [0 0 1]; %white = red + green + blue; %black = 0*white; % %delete(get(gca, 'Children')) %hold off %h = tripatch(tri, xi, yi); %theBDF = [mfilename ' ' int2str(length(x))]; %set(h(~isnan(h)), 'ButtonDownFcn', theBDF, 'EdgeColor', white) %hold on %f = find(added); %plot(xi(f), yi(f), 'k+', 'MarkerFaceColor', 'k'); %hold off %view(2) %title(theBDF) %set(gca, 'XLim', [-2 2], 'YLim', [-2 2]) %figure(gcf) %zoomsafe % %if (0) % %theSense = trisense(tri, xi, yi); %[m, n] = size(tri); % %delete(get(gca, 'Children')) %hold off % %red = [1 0 0]; %green = [0 1 0]; %blue = [0 0 1]; %white = red + green + blue; %black = 0*white; % %for i = 1:m % switch theSense(i) % case -1 % theColor = red; % otherwise % theColor = green; % end % h(i) = patch(xi(tri(i, :)), yi(tri(i, :)), theColor); % hold on %end % %theBDF = [mfilename ' ' int2str(length(x))]; %set(h(~isnan(h)), 'ButtonDownFcn', theBDF, 'EdgeColor', white) %f = find(added); %h = plot(xi(f), yi(f), 'ko', 'MarkerFaceColor', 'k'); %set(h, 'LineWidth', 1.5) %f = find(~added); %f(end+1) = 1; %h = plot(xi(f), yi(f), '-ko'); %set(h, 'LineWidth', 1.5) %hold off %view(2) %title(theBDF) %set(gca, 'XLim', [-2 2], 'YLim', [-2 2]) %figure(gcf) %zoomsafe % %end fclose(fout); disp(' ## Installing: "trisense.m" (text)') fout = fopen('trisense.m', 'w'); %function theResult = trisense(tri, x, y) % %% trisense -- Sense of index rotation for triangles. %% trisense(tri, x, y) returns +1 for the counter- %% clockwise triangles of tri, and -1 for the %% clockwise ones. The data are (x, y). %% trisense('demo') demonstrates itself. % %% Copyright (C) 1999 Dr. Charles R. Denham, ZYDECO. %% All Rights Reserved. %% Disclosure without explicit written consent from the %% copyright owner does not constitute publication. % %% Version of 29-Apr-1999 08:05:16. %% Updated 12-Jul-1999 08:33:28. % %warning off MATLAB:convhull:ObsoleteThirdArgument % %if nargin < 1, help(mfilename), tri = 'demo'; end %if isequal(tri, 'demo'), tri = 10; end %if isstr(tri), tri = eval(tri); end % %if length(tri) == 1 % npoints = tri; % rad = 1 + rand(npoints, 1); % ang = sort(rand(size(rad)) * 2 * pi); % xy = rad .* exp(ang*sqrt(-1)); % x = real(xy); y = imag(xy); % tri = delaunay(x, y); % hull = convhull(x, y, tri); % tri = trisort(tri); % s = trisense(tri, x, y); % hold off % i = s < 0; % theColor = [1 0 0]; % z = zeros(size(x)); % for k = 1:2 % if any(i) % h = trimesh(tri(i, :), x, y, z, 'Tag', mfilename); % set(h, 'FaceColor', theColor) % hold on % end % i = s > 0; % theColor = [0 1 0]; % end % theButtonDownFcn = ['trisense ' int2str(npoints)]; % h = findobj(gcf, 'Tag', mfilename); % set(h, 'ButtonDownFcn', theButtonDownFcn) % x(end+1) = x(1); % y(end+1) = y(1); % plot(x, y, '-', 'LineWidth', 2.5) % plot(x(hull), y(hull), 'o', 'MarkerSize', 10) % hold off % view(2) % title(theButtonDownFcn) % set(gcf, 'Name', 'TriSense Demo') % zoomsafe % figure(gcf) % return %end % %[m, n] = size(tri); %if n == 1, tri = tri.'; end % %t = tri(:, [1 2 3 1]); % %x = x(t); %y = y(t); % %[m, n] = size(x); %if n == 1, x = x.'; y = y.'; end % %areas = 0.5 .* (x(:, 1:3).*y(:, 2:4) - x(:, 2:4).*y(:, 1:3)) * ones(3, 1); % %result = sign(areas); % %if nargout > 0 % theResult = result; %else % disp(result) %end fclose(fout); disp(' ## Installing: "trisort.m" (text)') fout = fopen('trisort.m', 'w'); %function theResult = trisort(tri) % %% trisort -- Sort a triangular tessellation. %% trisort(tri) sorts the indices of tri, %% a triangular tessellation such as from %% the "delaunay" function. The rows are %% sorted and then arranged in order of %% ascending first index. % %% Copyright (C) 1999 Dr. Charles R. Denham, ZYDECO. %% All Rights Reserved. %% Disclosure without explicit written consent from the %% copyright owner does not constitute publication. % %% Version of 29-Apr-1999 08:00:44. % %if nargin < 1, help(mfilename), return, end % %result = sort(tri.').'; %for j = 3:-1:1 % [ignore, indices] = sort(result(:, j)); % result = result(indices, :); %end % %if nargout > 0 % theResult = result; %else % disp(result) %end fclose(fout); disp(' ## Installing: "triterp.m" (text)') fout = fopen('triterp.m', 'w'); %function theResult = triterp(tri, x, y, z, xi, yi) % %% triterp -- Linear interpolation on triangles. %% triterp(tri, x, y, z, xi, yi) interpolates z(x, y) %% at points (xi, yi), using the triangulation %% tri. If tri is empty, the Matlab "delaunay" %% routine is called to compute it. %% triterp(x, y, z, xi, yi) calls triterp([], x, y, z, xi, yi). % %% This routine is cloned directly from the "linear" %% sub-function found in "griddata.m". % %% Modified blocks below are marked by "ZYDECO": %% Copyright (C) 1999 Dr. Charles R. Denham, ZYDECO. %% All Rights Reserved. %% Disclosure without explicit written consent from the %% copyright owner does not constitute publication. % %% Version of 25-Jun-1999 09:29:57. %% Updated 30-Apr-2003 10:30:16. % %%function zi = linear(x,y,z,xi,yi) %%LINEAR Triangle-based linear interpolation % %% Reference: David F. Watson, "Contouring: A guide %% to the analysis and display of spacial data", Pergamon, 1994. % %warning off MATLAB:delaunay:ObsoleteThirdArgument % %if nargin < 5 | nargin > 6 % ZYDECO. % help(mfilename) % if nargout > 0, theResult = []; end % return %end % %if nargin < 5 | nargin > 6 % ZYDECO. % error(' ## Requires exactly five or six input arguments.') %end % %% Prepare for unavailable tri. % %if nargin == 5 % ZYDECO. % yi = xi; % xi = z; % z = y; % y = x; % x = tri; % tri = []; % zi = triterp(tri, x, y, z, xi, yi); % return %end % %% Pad z with NaNs if shorter than the (x, y) data. % %if length(z) < length(x) % ZYDECO. % z(length(x)) = 0; % z(length(x)+1:end) = NaN; %end % %siz = size(xi); %xi = xi(:); yi = yi(:); % Treat these as columns %x = x(:); y = y(:); % Treat these as columns % %% Triangularize the data % %if isempty(tri) % ZYDECO. % tri = delaunay(x, y, 'sorted'); %end % %if isempty(tri), % warning('Data cannot be triangulated.'); % zi = repmat(NaN, size(xi)); % return %end % %% Find the nearest triangle (t). % %v = version; %if eval(v(1)) >= 6 % t = tsearch(x, y, tri, xi, yi); %else % t = tsearchsafe(x, y, tri, xi, yi); % ZYCEDO. %end % %% Only keep the relevant triangles. % %out = find(isnan(t)); %if ~isempty(out), t(out) = ones(size(out)); end %tri = tri(t,:); % %% Compute Barycentric coordinates (w). P. 78 in Watson. % %del = (x(tri(:,2))-x(tri(:,1))) .* (y(tri(:,3))-y(tri(:,1))) - ... % (x(tri(:,3))-x(tri(:,1))) .* (y(tri(:,2))-y(tri(:,1))); %w(:,3) = ((x(tri(:,1))-xi).*(y(tri(:,2))-yi) - ... % (x(tri(:,2))-xi).*(y(tri(:,1))-yi)) ./ del; %w(:,2) = ((x(tri(:,3))-xi).*(y(tri(:,1))-yi) - ... % (x(tri(:,1))-xi).*(y(tri(:,3))-yi)) ./ del; %w(:,1) = ((x(tri(:,2))-xi).*(y(tri(:,3))-yi) - ... % (x(tri(:,3))-xi).*(y(tri(:,2))-yi)) ./ del; %w(out,:) = zeros(length(out),3); % %z = z(:).'; % Treat z as a row so that code below involving % % z(tri) works even when tri is 1-by-3. % %zi = sum(z(tri) .* w, 2); % %zi = reshape(zi, siz); % %if ~isempty(out), zi(out) = NaN; end % %if nargout > 0 % theResult = zi; %end fclose(fout); disp(' ## Installing: "uniq.m" (text)') fout = fopen('uniq.m', 'w'); %function [theResult, indices] = uniq(x) % %% uniq -- Delete duplicated rows in matrix. %% uniq(x) deletes duplicated rows from matrix x. %% Unlike the Matlab "unique" routine, the present %% function does not rearrange the order of rows. %% [y, indices] = unique(x) also returns indices %% such that y = x(indices, :). % %% Copyright (C) 1999 Dr. Charles R. Denham, ZYDECO. %% All Rights Reserved. %% Disclosure without explicit written consent from the %% copyright owner does not constitute publication. % %% Version of 05-May-1999 09:59:50. %% Updated 20-Jul-1999 11:04:23. % %[m, n] = size(x); %oldm = m; %if oldm == 1, x = x.'; end %[m, n] = size(x); % %xout = x; % %indices = (1:m).'; %for j = n:-1:1 % [ignore, ind] = sort(x(:, j)); % x = x(ind, :); % indices = indices(ind); %end % %d = diff(x); % %if n == 1 % f = find(d == 0); %else % f = find(all(d.' == 0).'); %end % %if any(f) % indices(f+1) = []; % indices = sort(indices); % xout = xout(indices, :); %end % %if oldm == 1, xout = xout.'; end % %if nargout > 0 % theResult = xout; %else % disp(xout) %end fclose(fout); disp(' ## Installing: "zoomsafe.m" (text)') fout = fopen('zoomsafe.m', 'w'); %function theResult = zoomsafe(varargin) % %% zoomsafe -- Safe zooming with the mouse. %% zoomsafe('demo') demonstrates itself with an interactive %% line. Zooming occurs with clicks that are NOT on the line. %% zoomsafe('on') initiates safe-zooming in the current window. %% Zooming occurs with each click in the current-figure, except %% on a graphical object whose "ButtonDownFcn" is active. %% zoomsafe('on', 'all') applies any new axis limits to all the %% axes in the figure. For companion axes having exactly the %% same 'XLim' range as the one that was clicked, the 'YLim' %% range remains intact. The same synchronization is invoked %% for corresponding 'YLim' situations as well. %% zoomsafe('all') same as zoomsafe('on', 'all'). %% zoomsafe (no argument) same as zoomsafe('on'). %% zoomsafe('off') turns it off. %% zoomsafe('out') zooms fully out. %% zoomsafe(theAmount, theDirection) applies theAmount of zooming %% to theDirection: 'x', 'y', or 'xy' (default). %% Note: when zooming actually occurs, this routine returns %% logical(1); otherwise, logical(0). %% %% "Click-Mode" (Macintosh Action) Result %% "normal" (click) Zoom out x2, centered on click. %% "extend" (shift-click) Zoom in x2, centered on click. %% "alt" (option-click) Center on click without zooming. %% "open" (double-click) Revert to unzoomed state. %% (Use click-down-and-drag to invoke a rubber-rectangle.) %% %% Use click-drag to map the zooming to a rubber-rectangle. % %% Copyright (C) 1997 Dr. Charles R. Denham, ZYDECO. %% All Rights Reserved. %% Disclosure without explicit written consent from the %% copyright owner does not constitute publication. % %% Version of 19-Jun-1997 08:42:57. %% Updated 02-Aug-1999 14:40:31. % %result = logical(0); % %if nargin < 1, varargin = {'on'}; end % %if isstr(varargin{1}) & ~isempty(varargin{1}) & ... % any(varargin{1}(1) == '0123456789.') % varargin{1} = eval(varargin{1}); %end % %if ~isstr(varargin{1}) % theAmount = varargin{1}; % varargin{1} = 'manual'; %end % %theFlag = logical(0); %isAll = logical(0); % %theOldXLim = get(gca, 'XLim'); %theOldYLim = get(gca, 'YLim'); % %switch varargin{1} %case 'manual' % isAll = (nargin > 2); % theDirection = 'xy'; % if nargin > 1, theDirection = varargin{2}; end % theXLim = get(gca, 'XLim'); % theYLim = get(gca, 'YLim'); % if theAmount == 0 % axis tight % switch theDirection % case 'x' % set(gca, 'YLim', theYLim) % case 'y' % set(gca, 'XLim', theXLim) % case 'xy' % otherwise % end % theAmount = 1; % theXLim = get(gca, 'XLim'); % theYLim = get(gca, 'YLim'); % end % cx = mean(theXLim); % cy = mean(theYLim); % dx = diff(theXLim) ./ 2; % dy = diff(theYLim) ./ 2; % switch theDirection % case 'x' % theXLim = cx + [-dx dx] ./ theAmount; % case 'y' % theYLim = cy + [-dy dy] ./ theAmount; % case 'xy' % theXLim = cx + [-dx dx] ./ theAmount; % theYLim = cy + [-dy dy] ./ theAmount; % otherwise % end % set(gca, 'XLim', theXLim, 'YLim', theYLim); % theFlag = 1; %case 'demo' % x = (0:30) ./ 30; % y = rand(size(x)) - 0.5; % for i = 2:-1:1 % subplot(1, 2, i) % theLine = plot(x, y, '-o'); % set(theLine, 'ButtonDownFcn', 'disp(''## hello'')') % set(gcf, 'Name', 'zoomsafe Demo') % end % result = zoomsafe('on', 'all'); %case 'all' % result = zoomsafe('on', 'all'); %case 'on' % isAll = (nargin > 1); % if ~isAll % set(gcf, 'WindowButtonDownFcn', 'if zoomsafe(''down''), end') % else % set(gcf, 'WindowButtonDownFcn', 'if zoomsafe(''down'', ''all''), end') % end %case 'down' % isAll = (nargin > 1); % dozoom = 0; % switch get(gcbo, 'Type') % case {'figure'} % "axes" not needed. % switch switchsafe(get(gco, 'Type')) % case {'figure'} % dozoom = 1; % otherwise % if isempty(get(gco, 'ButtonDownFcn')) % dozoom = 1; % end % end % otherwise % end % switch dozoom % case 1 % thePointer = get(gcf, 'Pointer'); % set(gcf, 'Pointer', 'watch') % theRBRect = rbrect; % x = sort(theRBRect([1 3])); % y = sort(theRBRect([2 4])); % theXLim = get(gca, 'XLim'); % theYLim = get(gca, 'YLim'); % theLimRect = [theXLim(1) theYLim(1) theXLim(2) theYLim(2)]; % d = doubleclick; % Trap any double-click. % if any(d) % Valid double-click. % if ~isAll % result = zoomsafe('out'); % else % result = zoomsafe('out', 'all'); % end % set(gcf, 'Pointer', 'arrow') % if nargout > 0, theResult = result; end % return % elseif isempty(d) % Ignore initial-click of double. % if nargout > 0, theResult = result; end % return % else % Not a double-click. % end % switch get(gcf, 'SelectionType') % case 'normal' % theFlag = 1; % theAmount = [2 2]; % Zoom-in by factor of 2. % case 'extend' % theFlag = 1; % theAmount = [0.5 0.5]; % case 'open' % Pre-empted by "doubleclick" above. % if ~isAll % result = zoomsafe('out'); % else % result = zoomsafe('out', 'all'); % end % set(gcf, 'Pointer', 'arrow') % if nargout > 0, theResult = result; end % return % otherwise % theAmount = [1 1]; % x = [mean(x) mean(x)]; % y = [mean(y) mean(y)]; % end % if diff(x) == 0 | diff(y) == 0 % cx = mean(x); % cy = mean(y); % dx = diff(theXLim) ./ 2; % dy = diff(theYLim) ./ 2; % x = cx + [-dx dx] ./ theAmount(1); % y = cy + [-dy dy] ./ theAmount(2); % else % r1 = theLimRect; % r2 = theRBRect; % switch get(gcf, 'SelectionType') % case 'normal' % r4 = maprect(r1, r2, r1); % case 'extend' % r4 = maprect(r2, r1, r1); % otherwise % r4 = r1; % end % x = r4([1 3]); % y = r4([2 4]); % end % set(gca, 'XLim', sort(x), 'YLim', sort(y)) % theFlag = 1; % result = logical(1); % switch thePointer % case {'watch', 'circle'} % thePointer = 'arrow'; % otherwise % end % set(gcf, 'Pointer', thePointer) % set(gcf, 'Pointer', 'arrow') % otherwise % end %case 'motion' %case 'up' %case 'off' % set(gcf, 'WindowButtonDownFcn', ''); %case 'out' % isAll = (nargin > 1); % theFlag = 1; % axis tight % result = logical(1); %otherwise % temp = eval(varargin{1}); % switch class(temp) % case 'double' % if ~isAll % result = zoomsafe(temp); % else % result = zoomsafe(temp, 'all'); % end % otherwise % warning('## Unknown option') % end %end % %% Synchronize the other axes. % %if isAll & theFlag & 1 % theGCA = gca; % theXLim = get(theGCA, 'XLim'); % theYLim = get(theGCA, 'YLim'); % theAxes = findobj(gcf, 'Type', 'axes'); % for i = 1:length(theAxes) % if theAxes(i) ~= theGCA % axes(theAxes(i)) % x = get(gca, 'XLim'); % y = get(gca, 'YLim'); % if all(x == theOldXLim) % set(theAxes(i), 'XLim', theXLim) % end % if all(y == theOldYLim) % set(theAxes(i), 'YLim', theYLim) % end % end % end % axes(theGCA) %end % %if nargout > 0, theResult = result; end % %% legend % Causes excessive flashing. % %function theResult = rbrect(onMouseUp, onMouseMove, onMouseDown) % %% rbrect -- Rubber rectangle tracking (Matlab-4 and Matlab-5). %% rbrect('demo') demonstrates itself. %% rbrect('onMouseUp', 'onMouseMove', 'onMouseDown') conducts interactive %% rubber-rectangle tracking, presumably because of a mouse button press %% on the current-callback-object (gcbo). The 'on...' callbacks are %% automatically invoked with: "feval(theCallback, theInitiator, theRect)" %% after each window-button event, using the object that started this %% process, plus theRect as [xStart yStart xEnd yEnd] for the current %% rubber-rect. The callbacks default to ''. The coordinates of the %% rectangle are returned as [xStart yStart xEnd yEnd]. % %% Private interface: %% rbrect(1) is automatically called on window-button-motions. %% rbrect(2) is automatically called on window-button-up. % %% Copyright (C) 1997 Dr. Charles R. Denham, ZYDECO. %% All Rights Reserved. %% Disclosure without explicit written consent from the %% copyright owner does not constitute publication. % %% Version of 03-Jun-1997 15:54:39. %% Version of 11-Jun-1997 15:17:22. %% Version of 17-Jun-1997 16:52:46. % %global RBRECT_HANDLE %global RBRECT_INITIATOR %global RBRECT_ON_MOUSE_MOVE % %if nargin < 1, onMouseUp = 0; end % %if strcmp(onMouseUp, 'demo') % help rbrect % x = cumsum(rand(200, 1) - 0.45); % y = cumsum(rand(200, 1) - 0.25); % h = plot(x, y, '-r'); % set(h, 'ButtonDownFcn', 'disp(rbrect)') % figure(gcf), set(gcf, 'Name', 'RBRECT Demo') % return % elseif isstr(onMouseUp) % theMode = 0; % else % theMode = onMouseUp; % onMouseUp = ''; %end % % %if theMode == 0 % Mouse down. % if nargin < 3, onMouseDown = ''; end % if nargin < 2, onMouseMove = ''; end % if nargin < 1, onMouseUp = ''; end % theVersion = version; % isVersion5 = (theVersion(1) == '5'); % if isVersion5 % theCurrentObject = 'gcbo'; % else % theCurrentObject = 'gco'; % end % RBRECT_INITIATOR = eval(theCurrentObject); % switch get(RBRECT_INITIATOR, 'Type') % case 'line' % theColor = get(RBRECT_INITIATOR, 'Color'); % otherwise % theColor = 'black'; % end % RBRECT_ON_MOUSE_MOVE = onMouseMove; % pt = mean(get(gca, 'CurrentPoint')); % x = [pt(1) pt(1)]; y = [pt(2) pt(2)]; % RBRECT_HANDLE = line(x, y, ... % 'EraseMode', 'xor', ... % 'LineStyle', '--', ... % 'LineWidth', 2.5, ... % 'Color', theColor, ... % 'Marker', '+', 'MarkerSize', 13, ... % 'UserData', 1); % set(gcf, 'WindowButtonMotionFcn', 'rbrect(1);') % set(gcf, 'WindowButtonUpFcn', 'rbrect(2);') % theRBRect = [x(1) y(1) x(2) y(2)]; % if ~isempty(onMouseDown) % feval(onMouseDown, RBRECT_INITIATOR, theRBRect) % end % thePointer = get(gcf, 'Pointer'); % set(gcf, 'Pointer', 'circle'); % if isVersion5 & 0 % Disable for rbrect().. % eval('waitfor(RBRECT_HANDLE, ''UserData'', [])') % else % set(RBRECT_HANDLE, 'Visible', 'off') % Invisible. % eval('rbbox') % No "waitfor" in Matlab-4. % end % set(gcf, 'Pointer', thePointer); % set(gcf, 'WindowButtonMotionFcn', '') % set(gcf, 'WindowButtonUpFcn', '') % x = get(RBRECT_HANDLE, 'XData'); % y = get(RBRECT_HANDLE, 'YData'); % delete(RBRECT_HANDLE) % theRBRect = [x(1) y(1) x(2) y(2)]; % Scientific. % if ~isempty(onMouseUp) % feval(onMouseUp, RBRECT_INITIATOR, theRBRect) % end %elseif theMode == 1 % Mouse move. % pt2 = mean(get(gca, 'CurrentPoint')); % x = get(RBRECT_HANDLE, 'XData'); % y = get(RBRECT_HANDLE, 'YData'); % x(2) = pt2(1); y(2) = pt2(2); % set(RBRECT_HANDLE, 'XData', x, 'YData', y) % theRBRect = [x(1) y(1) x(2) y(2)]; % if ~isempty(RBRECT_ON_MOUSE_MOVE) % feval(RBRECT_ON_MOUSE_MOVE, RBRECT_INITIATOR, theRBRect) % end %elseif theMode == 2 % Mouse up. % pt2 = mean(get(gca, 'CurrentPoint')); % x = get(RBRECT_HANDLE, 'XData'); % y = get(RBRECT_HANDLE, 'YData'); % x(2) = pt2(1); y(2) = pt2(2); % set(RBRECT_HANDLE, 'XData', x, 'YData', y, 'UserData', []) %else %end % %if nargout > 0, theResult = theRBRect; end % %function rect4 = maprect(rect1, rect2, rect3) % %% maprect -- Map rectangles. %% maprect(rect1, rect2, rect3) returns the rectangle %% that is to rect3 what rect1 is to rect2. Each %% rectangle is given as [x1 y1 x2 y2]. %% maprect('demo') demonstrates itself by showing %% that maprect(r1, r2, r1) ==> r2. % %% Copyright (C) 1997 Dr. Charles R. Denham, ZYDECO. %% All Rights Reserved. %% Disclosure without explicit written consent from the %% copyright owner does not constitute publication. % %% Version of 19-Jun-1997 08:33:39. % %if nargin < 1, help(mfilename), rect1 = 'demo'; end % %if strcmp(rect1, 'demo') % rect1 = [0 0 3 3]; % rect2 = [1 1 2 2]; % rect3 = rect1; % r4 = maprect(rect1, rect2, rect3); % begets(mfilename, 3, rect1, rect2, rect3, r4) % return %end % %if nargin < 3, help(mfilename), return, end % %r4 = zeros(1, 4); %i = [1 3]; %for k = 1:2 % r4(i) = polyval(polyfit(rect1(i), rect2(i), 1), rect3(i)); % i = i + 1; %end % %if nargout > 0 % rect4 = r4; % else % disp(r4) %end % %function theResult = doubleclick % %% doubleclick -- Trap for double-clicks. %% doubleclick (no argument) returns TRUE if a click %% is detected during its execution; otherwise, FALSE. %% Call "doubleclick" during a "WindowButtonDown" or %% "ButtonDown" callback, preferably at the top of %% procedure. The 'Interruptible' property of the %% callback-object must be 'on'. The double-click %% time is 0.5 sec. A valid double-click causes %% two values to be returned: first, a logical(1), %% then an empty-matrix []. The latter signifies %% the single-click that initiated the process. %% For a valid single-click, only logical(0) is %% returned. % %% Copyright (C) 1997 Dr. Charles R. Denham, ZYDECO. %% All Rights Reserved. %% Disclosure without explicit written consent from the %% copyright owner does not constitute publication. % %% Version of 25-Jul-1998 09:47:16. % %global CLICK_COUNT % %DOUBLE_CLICK_TIME = 1/2; % Seconds. % %if isempty(CLICK_COUNT), CLICK_COUNT = 0; end % %CLICK_COUNT = CLICK_COUNT + 1; % %if CLICK_COUNT == 1 % tic % while isequal(CLICK_COUNT, 1) & toc < DOUBLE_CLICK_TIME, end %end % %drawnow % Process the event-cue. % %% Note: %% Despite the "drawnow" seen above, Matlab does not %% update the "SelectionType" in timely fashion, so %% it cannot be used to trap a double-click properly. % %result = (CLICK_COUNT > 1); % %CLICK_COUNT = []; % %if nargout > 0 % theResult = result; %else % disp(result) %end fclose(fout); cd ('..') disp(' ') disp(' ## Add the "tri" folder to your Matlab path.') disp(' ## Execute "polyrand" at the Matlab prompt.') disp(' ')