function theResult = tsearchsafe(x, y, tri, xi, yi) % tsearchsafe -- TSEARCH for arbitrary triangles. % tsearchsafe('demo') demonstrates itself by % invoking "tsearch(10)". % tsearchsafe(NTRI, NPTS) demonstrates itself with % NTRI triangles and NPTS test-points (defaults: % NTRI=10, NPTS=10*NTRI). % tsearchsafe(x, y, tri, xi, yi) mimics TSEARCH for % an arbitrary group of non-overlapping triangles, % not necessarily produced by DELAUNAY. The result % is an array of triangle indices for those points % that lie on or within at least one triangle. All % other points are represented by NaN. For points % lying on or within more than one triangle, only % one such boundary is identified, as in TSEARCH. % % Note: This routine exists because TSEARCH itself % is not reliable for non-Delaunay sets of triangles. % 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 04-Apr-2000 15:24:36. % Updated 08-Sep-2000 13:40:32. if nargout > 0, theResult = []; end if nargin < 1, x = 'demo'; end if isequal(x, 'demo'), help(mfilename), x = 10; end if ischar(x), x= eval(x); end if length(x) == 1 nTriangles = max(x, 5); if nargin < 2, y = 10*x; end if ischar(y), y = eval(y); end nPoints = max(y, 10); x = 0.75*rand(2*nTriangles, 1) + 1/8; y = 0.75*rand(2*nTriangles, 1) + 1/8; tri = delaunay(x, y); [r, indices] = sort(rand(size(tri, 1), 1), 1); tri = tri(indices(1:nTriangles), :); xi = rand(nPoints, 1); yi = rand(nPoints, 1); tic; result = feval(mfilename, x, y, tri, xi, yi); disp([' ## Elapsed time: ' num2str(toc) ' s']) if nargout > 0 theResult = result; else theDefaultMarkerSize = get(0, 'DefaultLineMarkerSize'); theDefaultLineWidth = get(0, 'DefaultLineLineWidth'); theMarkerSize = theDefaultMarkerSize/sqrt(nPoints/1000); theMarkerSize = min(theDefaultMarkerSize, ... max(theDefaultLineWidth, theMarkerSize)); f = find(~isnan(result)); g = find(isnan(result)); hold off h = plot(xi(f), yi(f), 'g+', ... xi(g), yi(g), 'r+', ... 'MarkerSize', theMarkerSize); hold on trimesh(tri, x, y, zeros(size(x)), ... 'EdgeColor', [0 0 1], ... 'FaceColor', 'none', ... 'LineWidth', 0.5) hold off view(2) grid off try, zoomsafe, catch, zoom on, end figure(gcf) set(gcf, 'Name', [mfilename ' ' int2str(nTriangles) ' ' int2str(nPoints)]) if nargout > 0, theResult = result; end end return end result = zeros(size(xi)) + NaN; % Compute bounding rectangles for triangles. t = tri.'; xmin = min(x(tri.')).'; xmax = max(x(tri.')).'; ymin = min(y(tri.')).'; ymax = max(y(tri.')).'; % Eliminate out-of-bounds points from % further consideration. g = find(xi >= min(xmin) & xi <= max(xmax) & ... yi >= min(ymin) & yi <= max(ymax)); if (0) eliminated = length(xi) - length(g) end % For each point, find all the triangles % for which each point lies within their % bounding rectangles, then perform TSEARCH % on each one. We depend on the assumption % that TSEARCH is reliable for a single % triangle and many points. % NOTE: By pre-sorting the triangles and the (xi, yi) % points, we could reduce the calculation time, by % (say) working from right-to-left. % Also, whereas we presently loop over the (xi, yi), % we could also do the opposite, depending on the % relative numbers of triangles and (xi, yi) points. for j = 1:length(g) k = g(j); xtemp = xi(k); ytemp = yi(k); f = find( ... % Points strictly inside the bounds. (xtemp > xmin) & ... (xtemp < xmax) & ... (ytemp > ymin) & ... (ytemp < ymax)); if any(f) for i = 1:length(f) index = tsearch(x, y, tri(f(i), :), xtemp, ytemp); if ~isnan(index) result(k) = f(i); end end end end if nargout > 0 theResult = result; else disp(result) end