Determine if the direction of the line is clockwise or counterclockwise
One of the possible approaches. It should work well enough if the sampling of the line represented by your list of points is uniform and smooth enough, and if the line is simple enough.
- Subtract the average for the "center" of the line.
- Convert to polar coordinates to get an angle.
- Expand the corner to make sure it matters.
- Check if the overall increment is probable or negative.
I am assuming you have data in vectors x
and y
.
theta = cart2pol(x-mean(x), y-mean(y)); %// steps 1 and 2
theta = unwrap(theta); %// step 3
clockwise = theta(end)<theta(1); %// step 4. Gives 1 if CW, 0 if ACW
This only takes into account the integrated effect of all points. It doesn't tell you if there are "kinks" or sections with different turning directions.
A possible improvement would be to replace the mean value x
and y
at some integral. The reason is that if the sample is denser in the area, then the mean will be biased towards that, while the integral will not.
source to share
Alternatively, you can use some linear algebra. If there are three points a, b and c in this order, do the following:
1) create the vectors u = (b-a) = (b.x-a.x,b.y-a.y) and v = (c-b) ...
2) calculate the cross product uxv = u.x*v.y-u.y*v.x
3) if uxv is -ve then a-b-c is curving in clockwise direction (and vice-versa).
by following a longer curve in the same way, you may even find that the 's' -shaped curve changes from clockwise to counterclockwise, if useful.
source to share
This is now my approach, as mentioned in the comment to the question -
Another approach: draw a line from the start point to the end point. This line is indeed a vector. The CW has most of its RHS portion of this line. For CCW on the left.
I wrote a sample code to develop this idea. Most of the explanation can be found in the comments in the code.
clear;clc;close all
%% draw a spiral curve
N = 30;
theta = linspace(0,pi/2,N); % a CCW curve
rho = linspace(1,.5,N);
[x,y] = pol2cart(theta,rho);
clearvars theta rho N
plot(x,y);
hold on
%% find "the vector"
vec(:,:,1) = [x(1), y(1); x(end), y(end)]; % "the vector"
scatter(x(1),y(1), 200,'s','r','fill') % square is the starting point
scatter(x(end),y(end), 200,'^','r','fill') % triangle is the ending point
line(vec(:,1,1), vec(:,2,1), 'LineStyle', '-', 'Color', 'r')
%% find center of mass
com = [mean(x), mean(y)]; % center of mass
vec(:,:,2) = [x(1), y(1); com]; % secondary vector (start -> com)
scatter(com(1), com(2), 200,'d','k','fill') % diamond is the com
line(vec(:,1,2), vec(:,2,2), 'LineStyle', '-', 'Color', 'k')
%% find rotation angle
dif = diff(vec,1,1);
[ang, ~] = cart2pol(reshape(dif(1,1,:),1,[]), reshape(dif(1,2,:),1,[]));
clearvars dif
% now you can tell the answer by the rotation angle
if ( diff(ang)>0 )
disp('CW!')
else
disp('CCW!')
end
On which side of a directed line (vector) you can always point a point by comparing two vectors, namely rotating the vector [start point -> center of mass] with the vector [start point -> end point] and then comparing the rotation angle by 0. Several seconds of animation thinking can help you understand.
source to share