function [ triangle_index, edge ] = triangulation_search ( node_num, ... node_xy, triangle_order, triangle_num, triangle_node, triangle_neighbor, p ) %% TRIANGULATION_SEARCH searches a triangulation for a point. % % Purpose: % % The algorithm "walks" from one triangle to its neighboring triangle, % and so on, until a triangle is found containing point P, or P is found % to be outside the convex hull. % % The algorithm computes the barycentric coordinates of the point with % respect to the current triangle. If all three quantities are positive, % the point is contained in the triangle. If the I-th coordinate is % negative, then P lies on the far side of edge I, which is opposite % from vertex I. This gives a hint as to where to search next. % % For a Delaunay triangulation, the search is guaranteed to terminate. % For other triangulations, a cycle may occur. % % Note the surprising fact that, even for a Delaunay triangulation of % a set of points, the nearest point to P need not be one of the % vertices of the triangle containing P. % % The code can be called for triangulations of any order, but only % the first three nodes in each triangle are considered. Thus, if % higher order triangles are used, and the extra nodes are intended % to give the triangle a polygonal shape, these will have no effect, % and the results obtained here might be misleading. % % Modified: % % 27 September 2006 % % Author: % % Barry Joe, % Department of Computing Science, % University of Alberta, % Edmonton, Alberta, Canada T6G 2H1 % % Reference: % % Barry Joe, % GEOMPACK - a software package for the generation of meshes % using geometric algorithms, % Advances in Engineering Software, % Volume 13, pages 325-331, 1991. % % Parameters: % % Input, integer NODE_NUM, the number of nodes. % % Input, real NODE_XY(2,NODE_NUM), the vertices. % % Input, integer TRIANGLE_ORDER, the order of the triangles. % % Input, integer TRIANGLE_NUM, the number of triangles in the triangulation. % % Input, integer TRIANGLE_NODE(TRIANGLE_ORDER,TRIANGLE_NUM), % the nodes that make up each triangle. % % Input, integer TRIANGLE_NEIGHBOR(3,TRIANGLE_NUM), the triangle % neighbor list. % % Input, real P(2), the coordinates of a point. % % Output, integer TRIANGLE_INDEX, the index of the triangle where the % search ended. If a cycle occurred, then TRIANGLE_INDEX = -1. % % Output, integer EDGE, indicates the position of the point P in % triangle TRIANGLE_INDEX: % 0, the interior or boundary of the triangle; % -1, outside the convex hull of the triangulation, past edge 1; % -2, outside the convex hull of the triangulation, past edge 2; % -3, outside the convex hull of the triangulation, past edge 3. % dim_num = 2; count = 0; edge = 0; triangle_index = -1; seed = get_seed ( 'DUMMY' ); [ triangle, seed ] = i4_uniform ( 1, triangle_num, seed ); while ( 1 ) count = count + 1; if ( triangle_num < count ) fprintf ( 1, '\n' ); fprintf ( 1, 'TRIANGULATION_SEARCH - Fatal error!\n' ); fprintf ( 1, ' The algorithm seems to be cycling.\n' ); triangle_index = -1; edge = -1; return end % % Get the vertices of triangle TRIANGLE. % a = triangle_node(1,triangle); b = triangle_node(2,triangle); c = triangle_node(3,triangle); % % Using vertex C as a base, compute the distances to vertices A and B, % and the point P. % dxa = node_xy(1,a) - node_xy(1,c); dya = node_xy(2,a) - node_xy(2,c); dxb = node_xy(1,b) - node_xy(1,c); dyb = node_xy(2,b) - node_xy(2,c); dxp = p(1) - node_xy(1,c); dyp = p(2) - node_xy(2,c); det = dxa * dyb - dya * dxb; % % Compute the barycentric coordinates of the point P with respect % to this triangle. % alpha = ( dxp * dyb - dyp * dxb ) / det; beta = ( dxa * dyp - dya * dxp ) / det; gamma = 1.0 - alpha - beta; % % If the barycentric coordinates are all positive, then the point % is inside the triangle and we're done. % if ( 0.0 <= alpha & 0.0 <= beta & 0.0 <= gamma ) break end % % At least one barycentric coordinate is negative. % % If there is a negative barycentric coordinate for which there exists % an opposing triangle neighbor closer to the point, move to that triangle. % % (Two coordinates could be negative, in which case we could go for the % most negative one, or the most negative one normalized by the actual % distance it represents). % if ( alpha < 0.0 & 0 < triangle_neighbor(2,triangle) ) triangle = triangle_neighbor(2,triangle); continue; elseif ( beta < 0.0 & 0 < triangle_neighbor(3,triangle) ) triangle = triangle_neighbor(3,triangle); continue; elseif ( gamma < 0.0 & 0 < triangle_neighbor(1,triangle) ) triangle = triangle_neighbor(1,triangle); continue; end % % All negative barycentric coordinates correspond to vertices opposite % sides on the convex hull. % % Note the edge and exit. % if ( alpha < 0.0 ) edge = -2; break elseif ( beta < 0.0 ) edge = -3; break elseif ( gamma < 0.0 ) edge = -1; break end end triangle_index = triangle;