I'm trying to write a code that would allow to identify which side of a random polyline (not closed one) a random point is. Polyline is considered infinite with the first and last segments extended to infinity. If they are crossed polyline should be considered as a polygon (I haven't elaborate the code for this case yet). The logic is following:
1. Define the vertex of a polyline, the distance to which from the point under consideration is minimum. Variable minimum2p
is the distance to that vertex, I2p
is the index of the vertex.
2. Define the segment of a polyline, the distance to which from the point under consideration is minimum. Only those segments count (variable count_s
) which are intersected by a perpendicular from the point under consideration. Variable minimum2s
is the minimum distance to the segment; I2p
is the index of the first vertex of that segment; flag
is the boolean variable, which stores the information on which segment is intersected by the mentioned perpendicular.
3. Next it's just a matter to choose proper segment to compare with using, for example, ideas from the links link-1, link-2 or link-3. I tried the approach from here, but it doesn't work for many special cases. I use the best answer there for internal points of a polyline though. So, my approach is the following:
4. First, check if it's the first or the last vertex of a polyline. If this is the case, then the chosen segment is either first or last one correspondingly, but only if there is no other segment closer than the first or the last ones. If there is another segment then I chose that segment.
5. Next, if step 4 is not the case, then I check internal vertex of a polyline. If there is also a segment close nearby then I compare indexes I2p
and I2s
, if the last exists. If they coincide then there are no ambiguities in choosing the proper segment to compare with. If they are different then preference goes to the closest segment rather than to the closest vertex.
6. Finally, if there is no segment nearby (in the sense of perpendicular from the point crossing the segment), then for the internal vertex I apply the idea from the best answer here.
Here are some results for different polylines, which are defined by the X and Y coordinates of their vertexes, stored in 'polylineX' and 'polylineY' correspondingly (red color is for the 'left' position, grey color is for the 'right' position, black color is the position on the polyline, blue line represents a polyline).
As you can notice, for relatively smooth polylines the code works. However, for sharper ones, or in some ways complicated ones, the code doesn't work properly. What do I miss in my code? What condition should be added to take some cases into account?
The code is the following:
clear all
close all
clc
clf
polylineX = [0 1 2 3 4 5 6 7 8];
polylineY = [-10 20 -13 18 -17 16 -21 23 -25];
hold on
title(['polylineX=[',num2str(polylineX),'], polylineY=[',num2str(polylineY),']'])
chosen = 0;
span = 60;
for ii = 10:70
for jj = 30:60
ii
jj
position = -2;
point = [(jj-round(span/2))/1 (ii-round(span/2))/1];
axis equal
plot(polylineX,polylineY,'.-','MarkerSize',1,'LineWidth',1);
distance2p = zeros(1,length(polylineX)); % distances from the point to the points (2p) of the polyline
distance2s = zeros(1,length(polylineX)-1); % distances from the point to the segments (2s) of the polyline
flag = zeros(1,length(polylineX)-1);
count_s = 0; % counter of segments, which are intersected by the normal pointing from the 'point'
k = 0;
for i = 1:length(polylineX)-1
pos = sign((polylineX(i+1) - polylineX(i)) * (point(2) - polylineY(i)) -...
(polylineY(i+1) - polylineY(i)) * (point(1) - polylineX(i)));
% computing the distances from the 'point' to all segments and mark if
% the distance vectors intersect the segments
[flag(i),distance2s(i)] = distanceToLine([polylineX(i) polylineX(i+1)],[polylineY(i) polylineY(i+1)],[point(1) point(2)]);
if flag(i)
if k == 0
minimum2s = distance2s(i);
I2s = i;
end;
k = 1;
count_s = count_s + 1; % count segments, which are intersected by the normal pointing from the 'point'
if distance2s(i) < minimum2s
I2s = i;
minimum2s = distance2s(i);
end;
end;
end;
% first compute the distances between the 'point' under consideration and the
% points of the given polyline
for i = 1:length(polylineX)
distance2p(i) = sqrt((point(1)-polylineX(i))^2+(point(2)-polylineY(i))^2);
end;
[minimum2p,I2p] = min(distance2p);
clear k pos i
% now we need to choose which segment of the polyline to compare our 'point' with. These
% segments are either adjacent to that point of the polyline, which is the closest
% to the 'point' of interest, or the closest to the 'point' segment, which
% has an intersection with the normale pointing from the 'point'.
if I2p == 1 % if the 'point' is near the start of polyline
if exist('minimum2s','var')
if I2p == I2s
chosen = I2p;
else
chosen = I2s;
end;
else
chosen = I2p;
end;
elseif I2p == length(polylineX) % if the 'point' is near the end of polyline
if exist('minimum2s','var')
if I2s == I2p-1
chosen = I2p - 1;
else
chosen = I2s;
end;
else
chosen = I2p - 1;
end;
else
if exist('minimum2s','var')
if I2p == I2s
chosen = I2p;
else
chosen = I2s;
end;
else
pos1 = sign((polylineX(I2p) - polylineX(I2p-1)) * (point(2) - polylineY(I2p-1)) -...
(polylineY(I2p) - polylineY(I2p-1)) * (point(1) - polylineX(I2p-1)));
% position of the second segment relative to the first segment
pos2 = sign((polylineX(I2p) - polylineX(I2p-1)) * (polylineY(I2p+1) - polylineY(I2p-1)) -...
(polylineY(I2p) - polylineY(I2p-1)) * (polylineX(I2p+1) - polylineX(I2p-1)));
if (pos1 == 1 && pos2 == 1) || (pos1 == -1 && pos2 == -1)
chosen = I2p;
elseif pos1 == 0 || pos2 == 0
chosen = I2p;
else
chosen = I2p - 1;
end;
end;
end;
position = sign((polylineX(chosen+1) - polylineX(chosen)) * (point(2) - polylineY(chosen)) -...
(polylineY(chosen+1) - polylineY(chosen)) * (point(1) - polylineX(chosen)));
if position == 1
plot(point(1),point(2),'r.','MarkerSize',5)
elseif position == -1;
plot(point(1),point(2),'.','Color',[0.9 0.9 0.9],'MarkerSize',5) % gray color
elseif position == 0
plot(point(1),point(2),'k.','MarkerSize',5)
elseif position == -2
plot(point(1),point(2),'g.','MarkerSize',5)
end;
pause(0.00000001)
clear chosen count_s distance2p distance 2s flag I2p I2s minimum2p minimum2s point pos1 pos2 position
end;
end;