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@inrae.fr
0053 % Created: 2009-06-15, using Matlab 7.7.0.471 (R2008b)
0054 % Copyright 2009-2024 INRA - Cepia Software Platform
0055 
0056 %% Initialisations
0057 
0058 % flag indicating whether the polyline is closed (polygon) or not
0059 closed = false;
0060 
0061 % the tolerance for comparing positions based on distances
0062 tol = 1e-14;
0063 
0064 % determine whether the polyline is open or closed
0065 if ~isempty(varargin)
0066     closed = varargin{1};
0067     if ischar(closed)
0068         if strcmp(closed, 'closed')
0069             closed = true;
0070             varargin(1) = [];
0071         elseif strcmp(closed, 'open')
0072             closed = false;
0073             varargin(1) = [];
0074         end
0075     end
0076 end
0077 
0078 % parse optional arguments
0079 while length(varargin) > 1
0080     pname = varargin{1};
0081     if ~ischar(pname)
0082         error('Expect optional arguments as name-value pairs');
0083     end
0084     
0085     if strcmpi(pname, 'tolerance')
0086         tol = varargin{2};
0087     else
0088         error(['Unknown parameter name: ' pname]);
0089     end
0090     varargin(1:2) = [];
0091 end
0092 
0093 % if polyline is closed, ensure the last point equals the first one
0094 if closed
0095     if sum(abs(poly(end, :) - poly(1,:)) < tol) ~= 2
0096         poly = [poly; poly(1,:)];
0097     end
0098 end
0099 
0100 % arrays for storing results
0101 points  = zeros(0, 2);
0102 pos1    = zeros(0, 1);
0103 pos2    = zeros(0, 1);
0104 
0105 % number of edges
0106 nEdges = size(poly, 1) - 1;
0107 
0108 
0109 %% Main processing
0110 
0111 % index of current intersection
0112 ip = 0;
0113 
0114 % iterate over each couple of edge ( (N-1)*(N-2)/2 iterations)
0115 for iEdge1 = 1:nEdges-1
0116     % create first edge
0117     edge1 = [poly(iEdge1, :) poly(iEdge1+1, :)];
0118     for iEdge2 = iEdge1+2:nEdges
0119         % create second edge
0120         edge2 = [poly(iEdge2, :) poly(iEdge2+1, :)];
0121 
0122         % check conditions on bounding boxes, to avoid computing the
0123         % intersections
0124         if min(edge1([1 3])) > max(edge2([1 3]))
0125             continue;
0126         end
0127         if max(edge1([1 3])) < min(edge2([1 3]))
0128             continue;
0129         end
0130         if min(edge1([2 4])) > max(edge2([2 4]))
0131             continue;
0132         end
0133         if max(edge1([2 4])) < min(edge2([2 4]))
0134             continue;
0135         end
0136         
0137         % compute intersection point
0138         inter = intersectEdges(edge1, edge2, tol);
0139         
0140         if sum(isfinite(inter)) == 2
0141             % add point to the list
0142             ip = ip + 1;
0143             points(ip, :) = inter;
0144             
0145             % also compute positions on the polyline
0146             pos1(ip, 1) = iEdge1 - 1 + edgePosition(inter, edge1);
0147             pos2(ip, 1) = iEdge2 - 1 + edgePosition(inter, edge2);
0148         end
0149     end
0150 end
0151 
0152 
0153 %% Post-processing
0154 
0155 % if polyline is closed, the first vertex was found as an intersection, so
0156 % we need to remove it
0157 if closed
0158     % identify the intersection between first and last edges using position
0159     % indices (pos1 < pos2 by construction)
0160     ind = pos1 == 0 & pos2 == size(poly,1)-1;
0161     points(ind,:) = [];
0162     pos1(ind)   = [];
0163     pos2(ind)   = [];
0164 end
0165 
0166 % remove multiple intersections
0167 [points, I, J] = unique(points, 'rows', 'first'); %#ok<ASGLU>
0168 pos1 = pos1(I);
0169 pos2 = pos2(I);
0170 
0171 % remove multiple intersections, using tolerance on distance
0172 iInter = 0;
0173 while iInter < size(points, 1) - 1
0174     iInter = iInter + 1;
0175 % for iInter = 1:size(points, 1)-1
0176     % determine distance between current point and remaining points
0177     inds = iInter+1:size(points, 1);
0178     dists = distancePoints(points(iInter,:), points(inds, :));
0179     
0180     % identify index of other points located in a close neighborhood
0181     inds = inds(dists < tol);
0182     
0183     % remove redundant intersection points
0184     if ~isempty(inds)
0185         points(inds, :) = [];
0186         pos1(inds) = [];
0187         pos2(inds) = [];
0188     end
0189 end
0190 
0191 
0192 %% process output arguments
0193 
0194 if nargout <= 1
0195     varargout{1} = points;
0196     
0197 elseif nargout == 3
0198     varargout{1} = points;
0199     varargout{2} = pos1;
0200     varargout{3} = pos2;
0201 end

Generated on Thu 21-Nov-2024 11:30:22 by m2html © 2003-2022