You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

149 lines
4.5 KiB

3 years ago
function b = isPointOnEdge(point, edge, varargin)
%ISPOINTONEDGE Test if a point belongs to an edge.
%
% Usage
% B = isPointOnEdge(POINT, EDGE)
% B = isPointOnEdge(POINT, EDGE, TOL)
%
% Description
% B = isPointOnEdge(POINT, EDGE)
% with POINT being [xp yp], and EDGE being [x1 y1 x2 y2], returns TRUE if
% the point is located on the edge, and FALSE otherwise.
%
% B = isPointOnEdge(POINT, EDGE, TOL)
% Specify an optilonal tolerance value TOL. The tolerance is given as a
% fraction of the norm of the edge direction vector. Default is 1e-14.
%
% B = isPointOnEdge(POINTARRAY, EDGE)
% B = isPointOnEdge(POINT, EDGEARRAY)
% When one of the inputs has several rows, return the result of the test
% for each element of the array tested against the single parameter.
%
% B = isPointOnEdge(POINTARRAY, EDGEARRAY)
% When both POINTARRAY and EDGEARRAY have the same number of rows,
% returns a column vector with the same number of rows.
% When the number of rows are different and both greater than 1, returns
% a Np-by-Ne matrix of booleans, containing the result for each couple of
% point and edge.
%
% Examples
% % create a point array
% points = [10 10;15 10; 30 10];
% % create an edge array
% vertices = [10 10;20 10;20 20;10 20];
% edges = [vertices vertices([2:end 1], :)];
%
% % Test one point and one edge
% isPointOnEdge(points(1,:), edges(1,:))
% ans =
% 1
% isPointOnEdge(points(3,:), edges(1,:))
% ans =
% 0
%
% % Test one point and several edges
% isPointOnEdge(points(1,:), edges)'
% ans =
% 1 0 0 1
%
% % Test several points and one edge
% isPointOnEdge(points, edges(1,:))'
% ans =
% 1 1 0
%
% % Test N points and N edges
% isPointOnEdge(points, edges(1:3,:))'
% ans =
% 1 0 0
%
% % Test NP points and NE edges
% isPointOnEdge(points, edges)
% ans =
% 1 0 0 1
% 1 0 0 0
% 0 0 0 0
%
%
% See also
% edges2d, points2d, isPointOnLine
%
% ---------
% author : David Legland
% INRA - TPV URPOI - BIA IMASTE
% created the 31/10/2003.
%
% HISTORY
% 11/03/2004 change input format: edge is [x1 y1 x2 y2].
% 17/01/2005 if test N edges with N points, return N boolean.
% 21/01/2005 normalize test for colinearity, so enhance precision
% 22/05/2009 rename to isPointOnEdge, add psb to specify tolerance
% 26/01/2010 fix bug in precision computation
% 04/10/2010 fix a bug, and clean up code
% 28/10/2010 fix bug to have N results when input is N points and N
% edges, add support for arrays with different numbers of rows, and
% update doc.
% 2011-06-15 rewrites by using less memory, and avoiding repmat when psb
% extract computation tolerance
tol = 1e-14;
if ~isempty(varargin)
tol = varargin{1};
end
% number of edges and of points
nPoints = size(point, 1);
nEdges = size(edge, 1);
% adapt size of inputs if needed, and extract elements for computation
if nPoints == nEdges
% When the number of points and edges is the same, the one-to-one test
% will be computed, so there is no need to repeat matrices
dx = edge(:,3) - edge(:,1);
dy = edge(:,4) - edge(:,2);
lx = point(:,1) - edge(:,1);
ly = point(:,2) - edge(:,2);
elseif nPoints == 1
% one point, several edges
dx = edge(:, 3) - edge(:, 1);
dy = edge(:, 4) - edge(:, 2);
lx = point(ones(nEdges, 1), 1) - edge(:, 1);
ly = point(ones(nEdges, 1), 2) - edge(:, 2);
elseif nEdges == 1
% several points, one edge
dx = (edge(3) - edge(1)) * ones(nPoints, 1);
dy = (edge(4) - edge(2)) * ones(nPoints, 1);
lx = point(:, 1) - edge(1);
ly = point(:, 2) - edge(2);
else
% Np points and Ne edges:
% Create an array for each parameter, so that the result will be a
% Np-by-Ne matrix of booleans (requires more memory, and uses repmat)
x0 = repmat(edge(:, 1)', nPoints, 1);
y0 = repmat(edge(:, 2)', nPoints, 1);
dx = repmat(edge(:, 3)', nPoints, 1) - x0;
dy = repmat(edge(:, 4)', nPoints, 1) - y0;
lx = repmat(point(:, 1), 1, nEdges) - x0;
ly = repmat(point(:, 2), 1, nEdges) - y0;
end
% test if point is located on supporting line
b1 = abs(lx.*dy - ly.*dx) ./ (dx.*dx + dy.*dy) < tol;
% compute position of point with respect to edge bounds
% use different tests depending on line angle
ind = abs(dx) > abs(dy);
t = zeros(size(dx));
t(ind) = lx( ind) ./ dx( ind);
t(~ind) = ly(~ind) ./ dy(~ind);
% check if point is located between edge bounds
b = t >- tol & t-1 < tol & b1;