2

I'm optimizing a model which takes some weather data and then converts the clouds into polygons, so that they can be further utilized.
The code is working, but its kinds slow. By running the profiler I was able to found out the following lines are being called 106360430 times and takes about 50 secs to process.
Is there a way I can make these lines more efficient?

function [oddNodes] = pointInPolygon (point,thePolygon)
% determine if a point is in the polygon (faster than matlab "inpolygon"command

polyPoints=size(thePolygon,1);    % number of polygon points
oddNodes = false;

j=polyPoints;
x=point(1); y=point(2);

for i=1:polyPoints
if (thePolygon(i,2)<y && thePolygon(j,2)>=y ||  thePolygon(j,2)<y && thePolygon(i,2)>=y)
if (thePolygon(i,1)+(y-thePolygon(i,2))/(thePolygon(j,2)-thePolygon(i,2))*(thePolygon(j,1)-thePolygon(i,1))<x)
oddNodes=~oddNodes;
end
end
j=i; 
end
Vikram
  • 445
  • 1
  • 4
  • 12

3 Answers3

2

inPolygon test is a heavy function, probably best done in a mex file. Here is a few FEX contributions you can look at: inpoly-mex-file, Fast Inpolygon in MEX and Fast InPolygon detection MEX. Here is a native matlab code, which is faster than the matlab inpoly.

angainor
  • 11,760
  • 2
  • 36
  • 56
1

Vectorize your code (work on a matrix instead of using a loop) like this:

function [oddNodes] = pointInPolygon (point,thePolygon)

polyPoints=size(thePolygon,1);    % number of polygon points
oddNodes = false;

j=polyPoints;
x=point(1); y=point(2);

% this part has been vectorized:

thePolygon2=circshift(thePolygon,1);
t1=(thePolygon(:,2)<y & thePolygon2(:,2)>=y | thePolygon2(:,2)<y & thePolygon(:,2)>=y);
t2=(thePolygon(:,1)+(y-thePolygon(:,2))/(thePolygon2(:,2)-thePolygon(:,2))*(thePolygon2(:,1)-thePolygon(:,1))<x);

oddNodes=mod(sum(t1&t2),2);
Bitwise
  • 7,577
  • 6
  • 33
  • 50
  • Hey! can u please explain the last line. How canyou take sum of an array with values 'true' 6 'false'..and then take a mod of it? – Vikram Oct 18 '12 at 08:50
  • 1
    @user1734167 t1&t2 is the AND operation, so the result is a binary array. Matlab allows you to sum that, counting trues as 1 and falses as 0. So the sum(t1&t2) counts the number of places which were true in both arrays. Then you just take the modulus of that number, which is the same as "flipping" the oddNodes variable in each iteration (i.e. what you have in your code). – Bitwise Oct 18 '12 at 15:24
  • Hey, the code works but takes even more time..i guess the short circuit logical operators save a lot of time in the original version compared to vectorized version. I don't think there is any other faster way. – Vikram Nov 02 '12 at 16:21
0

I did not test it for speed, but the general way to go would be: Rather than running the same line 106360430 times, try to vectorize your code. Hence, try to shape it like this:

output = pointMatrixInPolygon (pointMatrix,thePolygon)

Then try to avoid loops inside the function and you should be there. It may be the case that you can actually just feed your matrix to the regular inpolygon function.

Dennis Jaheruddin
  • 21,208
  • 8
  • 66
  • 122