Home > matGeom > polygons2d > polylineSelfIntersections.m

polylineSelfIntersections

PURPOSE ^

POLYLINESELFINTERSECTIONS Find self-intersection points of a polyline.

SYNOPSIS ^

function varargout = polylineSelfIntersections(poly, varargin)

DESCRIPTION ^

POLYLINESELFINTERSECTIONS Find self-intersection points of a polyline.

   Computes self-intersections of a polyline, eventually specifying if
   polyline is closed or open, and eventually returning position of
   intersection points on polyline.
   For common use cases, the intersectPolylines function may return the
   desired result in a faster way.


   PTS = polylineSelfIntersections(POLY);
   Returns the position of self intersections of the given polyline.

   PTS = polylineSelfIntersections(POLY, CLOSED);
   Adds an options to specify if the polyline is closed (i.e., is a
   polygon), or open (the default). CLOSED can be a boolean, or one of
   'closed' or 'open'.

   [PTS, POS1, POS2] = polylineSelfIntersections(POLY);
   Also return the 2 positions of each intersection point (the position
   when meeting point for first time, then position when meeting point
   for the second time).

   [...] = polylineSelfIntersections(POLY, 'tolerance', TOL)
   Specifies an additional parameter to decide whether two intersection
   points should be considered the same, based on their Euclidean
   distance.  


   Example
       % use a gamma-shaped polyline
       poly = [0 0;0 10;20 10;20 20;10 20;10 0];
       polylineSelfIntersections(poly)
       ans = 
           10 10

       % use a 'S'-shaped polyline
       poly = [10 0;0 0;0 10;20 10;20 20;10 20];
       polylineSelfIntersections(poly)
       ans =
           Empty matrix: 0-by-2
       polylineSelfIntersections(poly, 'closed')
       ans = 
           10 10

   See also
   polygons2d, intersectPolylines, polygonSelfIntersections

CROSS-REFERENCE INFORMATION ^

This function calls: This function is called by:

SOURCE CODE ^

0001 function varargout = polylineSelfIntersections(poly, varargin)
0002 %POLYLINESELFINTERSECTIONS Find self-intersection points of a polyline.
0003 %
0004 %   Computes self-intersections of a polyline, eventually specifying if
0005 %   polyline is closed or open, and eventually returning position of
0006 %   intersection points on polyline.
0007 %   For common use cases, the intersectPolylines function may return the
0008 %   desired result in a faster way.
0009 %
0010 %
0011 %   PTS = polylineSelfIntersections(POLY);
0012 %   Returns the position of self intersections of the given polyline.
0013 %
0014 %   PTS = polylineSelfIntersections(POLY, CLOSED);
0015 %   Adds an options to specify if the polyline is closed (i.e., is a
0016 %   polygon), or open (the default). CLOSED can be a boolean, or one of
0017 %   'closed' or 'open'.
0018 %
0019 %   [PTS, POS1, POS2] = polylineSelfIntersections(POLY);
0020 %   Also return the 2 positions of each intersection point (the position
0021 %   when meeting point for first time, then position when meeting point
0022 %   for the second time).
0023 %
0024 %   [...] = polylineSelfIntersections(POLY, 'tolerance', TOL)
0025 %   Specifies an additional parameter to decide whether two intersection
0026 %   points should be considered the same, based on their Euclidean
0027 %   distance.
0028 %
0029 %
0030 %   Example
0031 %       % use a gamma-shaped polyline
0032 %       poly = [0 0;0 10;20 10;20 20;10 20;10 0];
0033 %       polylineSelfIntersections(poly)
0034 %       ans =
0035 %           10 10
0036 %
0037 %       % use a 'S'-shaped polyline
0038 %       poly = [10 0;0 0;0 10;20 10;20 20;10 20];
0039 %       polylineSelfIntersections(poly)
0040 %       ans =
0041 %           Empty matrix: 0-by-2
0042 %       polylineSelfIntersections(poly, 'closed')
0043 %       ans =
0044 %           10 10
0045 %
0046 %   See also
0047 %   polygons2d, intersectPolylines, polygonSelfIntersections
0048 %
0049 
0050 % ------
0051 % Author: David Legland
0052 % e-mail: david.legland@inra.fr
0053 % Created: 2009-06-15,    using Matlab 7.7.0.471 (R2008b)
0054 % Copyright 2009 INRA - Cepia Software Platform.
0055 
0056 %   HISTORY
0057 %   2009/06/18 check bounding boxes before computing intersections
0058 
0059 
0060 %% Initialisations
0061 
0062 % flag indicating whether the polyline is closed (polygon) or not
0063 closed = false;
0064 
0065 % the tolerance for comparing positions based on distances
0066 tol = 1e-14;
0067 
0068 % determine whether the polyline is open or closed
0069 if ~isempty(varargin)
0070     closed = varargin{1};
0071     if ischar(closed)
0072         if strcmp(closed, 'closed')
0073             closed = true;
0074             varargin(1) = [];
0075         elseif strcmp(closed, 'open')
0076             closed = false;
0077             varargin(1) = [];
0078         end
0079     end
0080 end
0081 
0082 % parse optional arguments
0083 while length(varargin) > 1
0084     pname = varargin{1};
0085     if ~ischar(pname)
0086         error('Expect optional arguments as name-value pairs');
0087     end
0088     
0089     if strcmpi(pname, 'tolerance')
0090         tol = varargin{2};
0091     else
0092         error(['Unknown parameter name: ' pname]);
0093     end
0094     varargin(1:2) = [];
0095 end
0096 
0097 % if polyline is closed, ensure the last point equals the first one
0098 if closed
0099     if sum(abs(poly(end, :) - poly(1,:)) < tol) ~= 2
0100         poly = [poly; poly(1,:)];
0101     end
0102 end
0103 
0104 % arrays for storing results
0105 points  = zeros(0, 2);
0106 pos1    = zeros(0, 1);
0107 pos2    = zeros(0, 1);
0108 
0109 % number of edges
0110 nEdges = size(poly, 1) - 1;
0111 
0112 
0113 %% Main processing
0114 
0115 % index of current intersection
0116 ip = 0;
0117 
0118 % iterate over each couple of edge ( (N-1)*(N-2)/2 iterations)
0119 for iEdge1 = 1:nEdges-1
0120     % create first edge
0121     edge1 = [poly(iEdge1, :) poly(iEdge1+1, :)];
0122     for iEdge2 = iEdge1+2:nEdges
0123         % create second edge
0124         edge2 = [poly(iEdge2, :) poly(iEdge2+1, :)];
0125 
0126         % check conditions on bounding boxes, to avoid computing the
0127         % intersections
0128         if min(edge1([1 3])) > max(edge2([1 3]))
0129             continue;
0130         end
0131         if max(edge1([1 3])) < min(edge2([1 3]))
0132             continue;
0133         end
0134         if min(edge1([2 4])) > max(edge2([2 4]))
0135             continue;
0136         end
0137         if max(edge1([2 4])) < min(edge2([2 4]))
0138             continue;
0139         end
0140         
0141         % compute intersection point
0142         inter = intersectEdges(edge1, edge2, tol);
0143         
0144         if sum(isfinite(inter)) == 2
0145             % add point to the list
0146             ip = ip + 1;
0147             points(ip, :) = inter;
0148             
0149             % also compute positions on the polyline
0150             pos1(ip, 1) = iEdge1 - 1 + edgePosition(inter, edge1);
0151             pos2(ip, 1) = iEdge2 - 1 + edgePosition(inter, edge2);
0152         end
0153     end
0154 end
0155 
0156 
0157 %% Post-processing
0158 
0159 % if polyline is closed, the first vertex was found as an intersection, so
0160 % we need to remove it
0161 if closed
0162     % identify the intersection between first and last edges using position
0163     % indices (pos1 < pos2 by construction)
0164     ind = pos1 == 0 & pos2 == size(poly,1)-1;
0165     points(ind,:) = [];
0166     pos1(ind)   = [];
0167     pos2(ind)   = [];
0168 end
0169 
0170 % remove multiple intersections
0171 [points, I, J] = unique(points, 'rows', 'first'); %#ok<ASGLU>
0172 pos1 = pos1(I);
0173 pos2 = pos2(I);
0174 
0175 % remove multiple intersections, using tolerance on distance
0176 iInter = 0;
0177 while iInter < size(points, 1) - 1
0178     iInter = iInter + 1;
0179 % for iInter = 1:size(points, 1)-1
0180     % determine distance between current point and remaining points
0181     inds = iInter+1:size(points, 1);
0182     dists = distancePoints(points(iInter,:), points(inds, :));
0183     
0184     % identify index of other points located in a close neighborhood
0185     inds = inds(dists < tol);
0186     
0187     % remove redundant intersection points
0188     if ~isempty(inds)
0189         points(inds, :) = [];
0190         pos1(inds) = [];
0191         pos2(inds) = [];
0192     end
0193 end
0194 
0195 
0196 %% process output arguments
0197 
0198 if nargout <= 1
0199     varargout{1} = points;
0200     
0201 elseif nargout == 3
0202     varargout{1} = points;
0203     varargout{2} = pos1;
0204     varargout{3} = pos2;
0205 end

Generated on Wed 16-Feb-2022 15:10:47 by m2html © 2003-2019