I have a point and a polygon in the same plane in 3d space and now I want to check whether or not the point is in the polygon or not.
Is there an easy way to change the algorithm from this thread Point in Polygon Algorithm to work for 3d space?
Or are there other algorithms that can solve this problem easily?
If there are not, would the following idea work:
Check if the plane is the XZ-plane or the YZ-plane, if yes, ignore the other axis (i.e. for the XZ-plane ignore the y values) and use the pip algorithm from the before mentioned thread. And if no, just ignore the z values of the point and the polygon and use the pip algorithm.
there are 2 "basic" ways of testing planar concave polygon:
convert to set of convex ones and test direction of cross product between point and all faces
the conversion to convex polygon is not as easy but its doable either by triangulation or clipping ear or what ever method... After that just check the cross products... so if your convex polygon has vertexes p0,p1,p2,...,p(n-1) and testing point p then
d0 = cross( p-p0 , p0-p(n-1) );
for (i=1;i<n;i++)
{
di = cross( p-p(i), p(i)-p(i-1) );
if ( dot ( d0 , di ) <=0.0 ) return false;
}
return true;
so just check all the polygons and return OR of the subresults
use hit test
You cast ray from your point in any direction parallel to your plane and count the number of hits you ray has done with the edges of polygon. If its even point is outside if its odd point is inside. The link in your question uses this algo. However in 3D you need to change the direction so it still is inside plane... for example by using single edge of polygon dir=p1-p0 as your direction. You also have to code some rules for cases when your ray hits Vertex directly so its counted just once instead of multiple times. Also the hit must be computed in 3D so you need axis/line intersection. It can be found here:
Cone to box collision
just look for line closest(axis a0,line l1) function. It returns line that is the closest connection between line and axis. Then just simply check if the two points are the same or not (length of the line is zero).
Now to simplify this you might port your 3D data into 2D
That can get rid of some accuracy problems related to rounding to the plane...
You are doing this by just ignoring one coordinate. That is simple but it might bring some rounding problems also the result has different shape (scaled differently in each axis) so the metrics is not the same anymore which might bring other problems latter if this is used for other purposes or any kind of thresholding is used.
There is a better method. We need any 2 basis vectors u,v that are perpendicular to each and are inside your plane and one point o inside the plane. That is easy just:
o = p0; // any point from the polygon
u = p1-p0; // any edge of polygon
u /= |u|; // normalize
v = p2-p1; // any other edge of polygon
v /= |v|; // normalize
for (;fabs(dot(u,v)>0.75;) // if too parallel
{
v=(p(1+rand(n-1))-p0); // chose random "edge"
v /= |v|; // normalize
}
v=cross(u,v); // make u,v perpendicular
v=cross(v,u); // and inside the plane
v /= |v|; // normalize just in case because of rounding the size might not be unit anymore
Now to convert point p(x,y,z) from 3D to 2D (x,y) just do:
x = dot(p-o,u);
y = dot(p-o,v);
to convert back to 3D:
p = o + x*u + y*v;
With this way of conversion the metrics is the same so the length of polygon edges and size of polygon will not change ...
Given a list of points forming a polygonal line, and both height and width of a rectangle, how can I find the number and positions of all rectangles needed to cover all the points?
The rectangles should be rotated and may overlap, but must follow the path of the polyline (A rectangle may contain multiple segments of the line, but each rectangle must contain a segment that is contiguous with the previous one.)
Do the intersections on the smallest side of the rectangle, when it is possible, would be much appreciated.
All the solutions I found so far were not clean, here is the result I get:
You should see that it gives a good render in near-flat cases, but overlaps too much in big curbs. One rectangle could clearly be removed if the previous were offset.
Actually, I put a rectangle centered at width/2 along the line and rotate it using convex hull and modified rotating calipers algorithms, and reiterate starting at the intersection point of the previous rectangle and the line.
You may observe that I took inspiration from the minimum oriented rectangle bounding box algorithm, for the orientation, but it doesn't include the cutting aspect, nor the fixed size.
Thanks for your help!
I modified k-means to solve this. It's not fast, it's not optimal, it's not guaranteed, but (IMHO) it's a good start.
There are two important modifications:
1- The distance measure
I used a Chebyshev-distance-inspired measure to see how far points are from each rectangle. To find distance from points to each rectangle, first I transformed all points to a new coordinate system, shifted to center of rectangle and rotated to its direction:
Then I used these transformed points to calculate distance:
d = max(2*abs(X)/w, 2*abs(Y)/h);
It will give equal values for all points that have same distance from each side of rectangle. The result will be less than 1.0 for points that lie inside rectangle. Now we can classify points to their closest rectangle.
2- Strategy for updating cluster centers
Each cluster center is a combination of C, center of rectangle, and a, its rotation angle. At each iteration, new set of points are assigned to a cluster. Here we have to find C and a so that rectangle covers maximum possible number of points. I don’t now if there is an analytical solution for that, but I used a statistical approach. I updated the C using weighted average of points, and used direction of first principal component of points to update a. I used results of proposed distance, powered by 500, as weight of each point in weighted average. It moves rectangle towards points that are located outside of it.
How to Find K
Initiate it with 1 and increase it till all distances from points to their corresponding rectangles become less than 1.0, meaning all points are inside a rectangle.
The results
Iterations 0, 10, 20, 30, 40, and 50 of updating cluster centers (rectangles):
Solution for test case 1:
Trying Ks: 2, 4, 6, 8, 10, and 12 for complete coverage:
Solution for test case 2:
P.M: I used parts of Chalous Road as data. It was fun downloading it from Google Maps. The I used technique described here to sample a set of equally spaced points.
It’s a little late and you’ve probably figured this out. But, I was free today and worked on the constraint reflected in your last edit (continuity of segments). As I said before in the comments, I suggest using a greedy algorithm. It’s composed of two parts:
A search algorithm that looks for furthermost point from an initial point (I used binary search algorithm), so that all points between them lie inside a rectangle of given w and h.
A repeated loop that finds best rectangle at each step and advances the initial point.
The pseudo code of them are like these respectively:
function getBestMBR( P, iFirst, w, h )
nP = length(P);
iStart = iFirst;
iEnd = nP;
while iStart <= iEnd
m = floor((iStart + iEnd) / 2);
MBR = getMBR(P[iFirst->m]);
if (MBR.w < w) & (MBR.h < h) {*}
iStart = m + 1;
iLast = m;
bestMBR = MBR;
else
iEnd = m - 1;
end
end
return bestMBR, iLast;
end
function getRectList( P, w, h )
nP = length(P);
rects = [];
iFirst = 1;
iLast = iFirst;
while iLast < nP
[bestMBR, iLast] = getBestMBR(P, iFirst, w, h);
rects.add(bestMBR.x, bestMBR.y, bestMBR.a];
iFirst = iLast;
end
return rects;
Solution for test case 1:
Solution for test case 2:
Just keep in mind that it’s not meant to find the optimal solution, but finds a sub-optimal one in a reasonable time. It’s greedy after all.
Another point is that you can improve this a little in order to decrease number of rectangles. As you can see in the line marked with (*), I kept resulting rectangle in direction of MBR (Minimum Bounding Rectangle), even though you can cover larger MBRs with rectangles of same w and h if you rotate the rectangle. (1) (2)
Now I have a function called Hexagon(x,y,n) which will draw a hexagon centered on (x,y) and with side length of n in python window.
My goal is to draw a tessellation animation which will draw the hexagon one after another from the center of the screen and spread out one by one (As the picture I attached here http://s7.postimage.org/lu6qqq2a3/Tes.jpg).
I am looking for the algorithm solving this problem. New to programing and I found it hard to do that.
Thanks!
For a ring of hexagons one can define a function like this:
def HexagonRing(x,y,n,r):
dc = n*math.sqrt(3) # distance between to neighbouring hexagon centers
xc,yc = x,y-r*dc # hexagon center of one before first hexagon (=last hexagon)
dx,dy = -dc*math.sqrt(3)/2,dc/2 # direction vector to next hexagon center
for i in range(0,6):
# draw r hexagons in line
for j in range(0,r):
xc,yc = xc+dx,yc+dy
Hexagon(xc,yc,n)
# rotate direction vector by 60°
dx,dy = (math.cos(math.pi/3)*dx+math.sin(math.pi/3)*dy,
-math.sin(math.pi/3)*dx+math.cos(math.pi/3)*dy)
Then one can draw one ring after the other:
Hexagon(0,0,10)
HexagonRing(0,0,10,1)
HexagonRing(0,0,10,2)
HexagonRing(0,0,10,3)
I have a .txt file with about 100,000 points in the 2-D plane. When I plot the points, there is a clearly defined 2-D region (think of a 2-D disc that has been morphed a bit).
What is the easiest way to compute the area of this region? Any way of doing easily in Matlab?
I made a polygonal approximation by finding a bunch (like 40) points on the boundary of the region and computing the area of the polygonal region in Matlab, but I was wondering if there is another, less tedious method than finding 40 points on the boundary.
Consider this example:
%# random points
x = randn(300,1);
y = randn(300,1);
%# convex hull
dt = DelaunayTri(x,y);
k = convexHull(dt);
%# area of convex hull
ar = polyarea(dt.X(k,1),dt.X(k,2))
%# plot
plot(dt.X(:,1), dt.X(:,2), '.'), hold on
fill(dt.X(k,1),dt.X(k,2), 'r', 'facealpha', 0.2);
hold off
title( sprintf('area = %g',ar) )
There is a short screencast By Doug Hull which solves this exact problem.
EDIT:
I am posting a second answer inspired by the solution proposed by #Jean-FrançoisCorbett.
First I create random data, and using the interactive brush tool, I remove some points to make it look like the desired "kidney" shape...
To have a baseline to compare against, we can manually trace the enclosing region using the IMFREEHAND function (I'm doing this using my laptop's touchpad, so not the most accurate drawing!). Then we find the area of this polygon using POLYAREA. Just like my previous answer, I compute the convex hull as well:
Now, and based on a previous SO question I had answered (2D histogram), the idea is to lay a grid over the data. The choice of the grid resolution is very important, mine was numBins = [20 30]; for the data used.
Next we count the number of squares containing enough points (I used at least 1 point as threshold, but you could try a higher value). Finally we multiply this count by the area of one grid square to obtain the approximated total area.
%### DATA ###
%# some random data
X = randn(100000,1)*1;
Y = randn(100000,1)*2;
%# HACK: remove some point to make data look like a kidney
idx = (X<-1 & -4<Y & Y<4 ); X(idx) = []; Y(idx) = [];
%# or use the brush tool
%#brush on
%### imfreehand ###
figure
line('XData',X, 'YData',Y, 'LineStyle','none', ...
'Color','b', 'Marker','.', 'MarkerSize',1);
daspect([1 1 1])
hROI = imfreehand('Closed',true);
pos = getPosition(hROI); %# pos = wait(hROI);
delete(hROI)
%# total area
ar1 = polyarea(pos(:,1), pos(:,2));
%# plot
hold on, plot(pos(:,1), pos(:,2), 'Color','m', 'LineWidth',2)
title('Freehand')
%### 2D histogram ###
%# center of bins
numBins = [20 30];
xbins = linspace(min(X), max(X), numBins(1));
ybins = linspace(min(Y), max(Y), numBins(2));
%# map X/Y values to bin-indices
Xi = round( interp1(xbins, 1:numBins(1), X, 'linear', 'extrap') );
Yi = round( interp1(ybins, 1:numBins(2), Y, 'linear', 'extrap') );
%# limit indices to the range [1,numBins]
Xi = max( min(Xi,numBins(1)), 1);
Yi = max( min(Yi,numBins(2)), 1);
%# count number of elements in each bin
H = accumarray([Yi(:), Xi(:)], 1, [numBins(2) numBins(1)]);
%# total area
THRESH = 0;
sqNum = sum(H(:)>THRESH);
sqArea = (xbins(2)-xbins(1)) * (ybins(2)-ybins(1));
ar2 = sqNum*sqArea;
%# plot 2D histogram/thresholded_histogram
figure, imagesc(xbins, ybins, H)
axis on, axis image, colormap hot; colorbar; %#caxis([0 500])
title( sprintf('2D Histogram, bins=[%d %d]',numBins) )
figure, imagesc(xbins, ybins, H>THRESH)
axis on, axis image, colormap gray
title( sprintf('H > %d',THRESH) )
%### convex hull ###
dt = DelaunayTri(X,Y);
k = convexHull(dt);
%# total area
ar3 = polyarea(dt.X(k,1), dt.X(k,2));
%# plot
figure, plot(X, Y, 'b.', 'MarkerSize',1), daspect([1 1 1])
hold on, fill(dt.X(k,1),dt.X(k,2), 'r', 'facealpha',0.2); hold off
title('Convex Hull')
%### plot ###
figure, hold on
%# plot histogram
imagesc(xbins, ybins, H>=1)
axis on, axis image, colormap gray
%# plot grid lines
xoff = diff(xbins(1:2))/2; yoff = diff(ybins(1:2))/2;
xv1 = repmat(xbins+xoff,[2 1]); xv1(end+1,:) = NaN;
yv1 = repmat([ybins(1)-yoff;ybins(end)+yoff;NaN],[1 size(xv1,2)]);
yv2 = repmat(ybins+yoff,[2 1]); yv2(end+1,:) = NaN;
xv2 = repmat([xbins(1)-xoff;xbins(end)+xoff;NaN],[1 size(yv2,2)]);
xgrid = [xv1(:);NaN;xv2(:)]; ygrid = [yv1(:);NaN;yv2(:)];
line(xgrid, ygrid, 'Color',[0.8 0.8 0.8], 'HandleVisibility','off')
%# plot points
h(1) = line('XData',X, 'YData',Y, 'LineStyle','none', ...
'Color','b', 'Marker','.', 'MarkerSize',1);
%# plot convex hull
h(2) = patch('XData',dt.X(k,1), 'YData',dt.X(k,2), ...
'LineWidth',2, 'LineStyle','-', ...
'EdgeColor','r', 'FaceColor','r', 'FaceAlpha',0.5);
%# plot freehand polygon
h(3) = plot(pos(:,1), pos(:,2), 'g-', 'LineWidth',2);
%# compare results
title(sprintf('area_{freehand} = %g, area_{grid} = %g, area_{convex} = %g', ...
ar1,ar2,ar3))
legend(h, {'Points' 'Convex Jull','FreeHand'})
hold off
Here is the final result of all three methods overlayed, with the area approximations displayed:
My answer is the simplest and perhaps the least elegant and precise. But first, a comment on previous answers:
Since your shape is usually kidney-shaped (not convex), calculating the area of its convex hull won't do, and an alternative is to determine its concave hull (see e.g. http://www.concavehull.com/home.php?main_menu=1) and calculate the area of that. But determining a concave hull is far more difficult than a convex hull. Plus, straggler points will cause trouble in both he convex and concave hull.
Delaunay triangulation followed by pruning, as suggested in #Ed Staub's answer, may a bit be more straightforward.
My own suggestion is this: How precise does your surface area calculation have to be? My guess is, not very. With either concave hull or pruned Delaunay triangulation, you'll have to make an arbitrary choice anyway as to where the "boundary" of your shape is (the edge isn't knife-sharp, and I see there are some straggler points sprinkled around it).
Therefore a simpler algorithm may be just as good for your application.
Divide your image in an orthogonal grid. Loop through all grid "pixels" or squares; if a given square contains at least one point (or perhaps two points?), mark the square as full, else empty. Finally, add the area of all full squares. Bingo.
The only parameter is the resolution length (size of the squares). Its value should be set to something similar to the pruning length in the case of Delaunay triangulation, i.e. "points within my shape are closer to each other than this length, and points further apart than this length should be ignored".
Perhaps an additional parameter is the number of points threshold for a square to be considered full. Maybe 2 would be good to ignore straggler points, but that may define the main shape a bit too tightly for your taste... Try both 1 and 2, and perhaps take an average of both. Or, use 1 and prune away the squares that have no neighbours (game-of-life-style). Simlarly, empty squares whose 8 neighbours are full should be considered full, to avoid holes in the middle of the shape.
There is no end to how much this algorithm can be refined, but due to the arbitrariness intrinsic to the problem definition in your particular application, any refinement is probably the algorithm equivalent of "polishing a turd".
I know next to nothing, so don't put much stock in this... consider doing a Delaunay triangulation. Then remove any hull (outer) edges longer than some maximum. Repeat until nothing to remove. Fill the remaining triangles.
This will orphan some outlier points.
I suggest using a space-filling-curve, for example a z-curve or better a moore curve. A sfc fills the full space and is good to index each points. For example for all f(x)=y you can sort the points of the curve in ascendending order and from that result you take as many points until you get a full roundtrip. These points you can then use to compute the area. Because you have many points maybe you want to use less points and use a cluster which make the result less accurate.
I think you can get the border points using convex hull algorithm with restriction to the edge length (you should sort points by vertical axis). Thus it will follow nonconvexity of your region. I propose length round 0.02. In any case you can experiment a bit with different lengths drawing the result and examining it visually.