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 29-Jul-1999 08:51:57. if nargin < 1, 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(:); added(end) = []; ki = ki(logical(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