tags:

views:

417

answers:

4

Hi everyone,

thats my first post, so please be kind.

I have a matrix with 3~10 coordinates and I want to connect these points to become a polygone with maximum size.

I tried fill() [1] to generate a plot but how do I calculate the area of this plot? Is there a way of converting the plot back to an matrix?

What would you reccomend me?

Thank you in advance!

[1]

x1 = [ 0.0, 0.5, 0.5 ];
y1 = [ 0.5, 0.5, 1.0 ];
fill ( x1, y1, 'r' );

[update]

Thank you for your answer MatlabDoug, but I think I did not formulate my question clear enough. I want to connect all of these points to become a polygone with maximum size.

Any new ideas?

+3  A: 
 x1 = rand(1,10)
 y1 = rand(1,10)

 vi = convhull(x1,y1)
 polyarea(x1(vi),y1(vi))

 fill ( x1(vi), y1(vi), 'r' ); 
 hold on
 plot(x1,y1,'.')
 hold off

What is happening here is that CONVHULL is telling us which verticies (vi) are on the convex hull (the smallest polygon that encloses all the points). Knowing which ones are on the convex hull, we ask MATLAB for the area with POLYAREA.

Finally, we use your FILL command to draw the polygon, then PLOT to place the points on there for confirmation.

MatlabDoug
skip convhull() if the coordinates are known to be the boundary (e.g. for concave polygons)
Jason S
but the points still have be ordered for polyarea() to work, isnt it?
Amro
A: 

Finding the right order for the points is the hard part, as Amro commented. Does this function suffice?

function [idx] = Polyfy(x, y)
% [idx] = Polyfy(x, y)
% Given vectors x and y that contain pairs of points, find the order that
% joins them into a polygon. fill(x(idx),y(idx),'r') should show no holes.

%ensure column vectors
if (size(x,1) == 1)
  x = x';
end
if (size(y,1) == 1)
  y = y';
end

% vectors from centroid of points to each point
vx = x - mean(x);
vy = y - mean(y);
% unit vectors from centroid towards each point
v = (vx + 1i*vy)./abs(vx + 1i*vy);
vx = real(v);
vy = imag(v);

% rotate all unit vectors by first
rot = [vx(1) vy(1) ; -vy(1) vx(1)];
v = (rot*[vx vy]')';

% find angles from first vector to each vector
angles = atan2(v(:,2), v(:,1));
[angles, idx] = sort(angles);
end

The idea is to find the centroid of the points, then find vectors from the centroid to each point. You can think of these vectors as sides of triangles. The polygon is made up the set of triangles where each vector is used as the "left" and "right" only once, and no vectors are skipped. This boils down to ordering the vectors by angle around the centroid.

I chose to do this by normalizing the vectors to unit length, choosing one of them as a rotation vector, and rotating the rest. This allowed me to simply use atan2 to find the angles. There's probably a faster and/or more elegant way to do this, but I was confusing myself with trig identities. Finally, sorting those angles provides the correct order for the points to form the desired polygon.

This is the test function:

function [x, y] = TestPolyArea(N)
x = rand(N,1);
y = rand(N,1);
[indexes] = Polyfy(x, y);
x2 = x(indexes);
y2 = y(indexes);
a = polyarea(x2, y2);
disp(num2str(a));
fill(x2, y2, 'r');
hold on
plot(x2, y2, '.');
hold off
end

You can get some pretty wild pictures by passing N = 100 or so!

mtrw
I can think of a simple case in which your proposed algorithm will not find a maximum area polygon. Consider four small points centered about the origin forming a square. Include four points on the cartesian axes that are far away from the origin. Your algorithm will produce a star-like polygon, but the right thing to do is to form a large bow-tie like polygon, with the far-away-from-origin points forming the outer corners of the bow-tie.
Victor Liu
@Victor Liu - Thanks. I should have seen that myself. I'll leave this up here in case it gives anyone else any ideas.
mtrw
+1  A: 

You said you only have 3...10 points to connect. In this case, I suggest you just take all possible combinations, compute the areas with polyarea and take the biggest one.

Only if your number of points increases or if you have to compute it frequently so that compuation time matters, it's worth investing some time in a better algorithm. However I think it's difficult to come up with an algorithm and prove its completeness.

groovingandi
+1  A: 

I second groovingandi's suggestion of trying all polygons; you just have to be sure to check the validity of the polygon (no self-intersections, etc).

Now, if you want to work with lots of points... As MatlabDoug pointed out, the convex hull is a good place to start. Notice that the convex hull gives a polygon whose area is the maximum possible. The problem, of course, is that there could be points in the interior of the hull that are not part of the polygon. I propose the following greedy algorithm, but I am not sure if it guarantees THE maximum area polygon.

The basic idea is to start with the convex hull as a candidate final polygon, and carve out triangles corresponding to the unused points until all the points belong to the final polygon. At each stage, the smallest possible triangle is removed.

Given: Points P = {p1, ... pN}, convex hull H = {h1, ..., hM}
       where each h is a point that lies on the convex hull.
       H is a subset of P, and it is also ordered such that adjacent
       points in the list of H are edges of the convex hull, and the
       first and last points form an edge.
Let Q = H
while(Q.size < P.size)
    % For each point, compute minimum area triangle
    T = empty heap of triangles with value of their area
    For each P not in Q
        For each edge E of Q
            If triangle formed by P and E does not contain any other point
                Add triangle(P,E) with value area(triangle(P,E))
    % Modify the current polygon Q to carve out the triangle
    Let t=(P,E) be the element of T with minimum area
    Find the ordered pair of points that form the edge E within Q
    (denote them Pa and Pb)
    Replace the pair (Pa,Pb) with (Pa,E,Pb)

Now, in practice you don't need a heap for T, just append the data to four lists: one for P, one for Pa, one for Pb, and one for the area. To test if a point lies within a triangle, you only need to test each point against the lines forming the sides of the triangle, and you only need to test points not already in Q. Finally, to compute the area of the final polygon, you can triangulate it (like with the delaunay function, and sum up the areas of each triangle in the triangulation), or you can find the area of the convex hull, and subtract out the areas of the triangles as you carve them out.

Again, I don't know if this greedy algorithm is guaranteed to find the maximum area polygon, but I think it should work most of the time, and is interesting nonetheless.

Victor Liu
I don't think the algorithm gauarantees you the maximum area polygon as the result depends on the order of the remaining points. But this reduces at least the number of permutations you have to test...
groovingandi
@groovingandi How does the result depend on the order of the remaining points? At each stage you consider all remaining points and select the best one to include.
Victor Liu
@Victor Lui: Ah now I see... The first time I read your algorithm I somehow overlooked that you consider all remaining points at the same time before deciding which one should be included next. Then, of course, it doesn't depend on the order of the remaining points. I tried to find a counterexample where your algorith doesn't work, but failed so far...
groovingandi

related questions