I have the vertices of a non-self-intersecting polygon in 2-D where the x-coordinate is centred longitude and y-coordinate is centred latitude. I want to find the edges of the polygon.
I can plot the vertices and see which vertices are neighbouring and see the edges. But my question is how can I get these edges.
For example, I am considering the sample data:
> data1
vertices lon lat
5 1.133179 1.027886
4 1.094459 1.013952
2 1.055672 1.000000
1 1.000000 1.028578
3 1.038712 1.042541
6 1.116241 1.070438
Sample Plot of the points is
I want to have an array like this
>edges
ind1 ind2
[1,] 5 6
[2,] 1 3
[3,] 3 6
[4,] 1 2
[5,] 2 4
[6,] 4 5
I am interested about this kind of shape of the polygon (with minimum area)
I got this array by using a function ashape of the R-package alphahull. But in this function Euclidean distance is used to find distance between points, which not applicable in my case (since I am considering data on (lon, lat), we can use distHaversine distance function in the package geosphere). And this function giving unsatisfactory result in case if the polygon has large number vertices and have complex shape. This polygon may or may not be convex.
Now all I want is to build an algorithm to find the edges of the non-intersecting polygon with minimum area.
Any help in this direction will be gratefully appreciated.
Algorithm for finding all possible polygons:
generate the convex hull .
Note that any non intersecting polygon must traverse its convex hull in order.
Start with any point on the convex hull
Generate a list of paths from that point to each interior point, and to the next adjacent point on the convex hull
recursively extend each path to each remaining interior point as well as to that first free point on the convex hull
for each segment added to a path reject the path if it self intersects
I'm not going to post the code, but here are all 67 possible polygons for a random set of 8 points.
As one can imagine the set of results blows up quickly with the number of points (eg. n=12 -> ~10000 polygons.. )
here are the polygons with min and max perimeters.
convert points from lon,lat to Cartesian x,y or x,y,z
use spherical or ellipsoidal surface
if the size is small enough you can project (x,y,z) to local surface plane to avoid 3D computing
you can also use lon,lat as x,y but make sure there is no zero crossing (if is then offset that axis by some value until it isn't)
now there are many possible strategies
you did not provide any rule for the shape
so I assume 'minimal' perimeter/size/area and generic concave polygon
you can not go directly to edge lines before you know where is inside and where is outside
I would do this task like this: find polygon based on find holes in 2D point set
modification 1
as you already have all the edge points (at least that is my impression)
so you can make flag for each point from the above algorithm
that will tell you where is inside or outside of polygon
for example take 8 directions (N,NE,E,...) and encode which way is filled and which empty
then on each edge start in the middle of empty direction
and find 2 closest lines to it (in angular terms) that are not intersecting any previous line
and if more available use the smallest ones
gray means inside polygon
make list of all such possible lines (2 per point)
then search for connected loops
beware this modification is not 100% error prone (I do not think that is for concave polygon even possible)
modification 2
use complete polygon from bullet 2
and try to match its edge points to your input edge points
then use the edge lines as in original polygon but with your new points
if some points are skipped then find closest edge line to it and divide it by this point
this should be more safe and accurate then bullet 3.
simple approach
if the above is too much for you then
create list of all possible lines
sort them by size ascending
remove all 'long' lines that are intersecting any 'short' line
what is short or long depends on you
for example first third of lines can be the short ones and the last third the long ones
or make average size and what is < 0.6*avg_size or > 1.2*avg_size ...
or if you have N points then first 2N lines are short the rest is long (2 lines per point)
test all and select the best option for you ...
try to find joined lines
find only lines that are connected once (no more then 2 lines per point)
remove them from list into the final solution list
after this you will have list of possible lines and list of found lines
remove all lines from possible lines that intersect any line in found lines
this should remove any non relevant lines
try to find connections again
take first possible line if found connection move it to the solution list
and go to bullet 5.
if none found continue with next line ...
stop if none line left or none connection found.
Related
Essentially I have spatial data in which I go through each point and figure out what are the surrounding points within a circle of some radius. I then want to arrange those points in a clockwise manner and I managed to have done that for "most" cases. The unique feature about this data is that there are only 6 maximum possible location that can surround any center point with how I defined my circle's radius[top-left, top-right, right, bottom-right, bottom-left, left]
So as a sample data
Center Point: 161.3861 368.8119
col row
1 164.5365 363.4114
2 155.2205 368.7669
3 167.5968 368.8569
4 158.2358 374.1674
5 164.4465 374.2124
6 158.3258 363.3663
The function would then output [4, 5 ,3, 1, 6, 2] which is the clockwise order. This sub-sample [highlighted in red with the center remained as black] of the data looks like this. [To be clear I have this case working]
But you can imagine that it is not exactly straightforward for the various corner cases. For instance the following case it has no point to the right of it so in the final out put array there should be a zero in the "right, top-right, top-left" index of the array I described earlier.
What I am struggling with is a systematic way to go through the corner cases and assign labels to the missing points. I tried using a dot product approach to quantify how closely the points are from each other (using a normal vector of straight up) but this lead to issues with discriminating top-right, right. I imagine that checking if a line goes through the point we get a sense of what axis the point exists on, but I have not managed to make it work. To summarize the two main corner cases are
Edge points
Island points
You could write a function to tell you which direction a point is in, given the point and the center-point:
Pseudo-code:
direction_vector = point - center_point
angle = atan2(direction_vector.y, direction_vector.x)
direction_index = ((angle * 12 / TWO_TIMES_PI) + 12) % 12
This will give you an index from 0 to 11 (imagine hours on bizarro clock face that goes anti-clockwise from 0, with 0 on the right where 3 o'clock is on a normal clock).
Now map this onto your directions, with 1 being top-left, 2 being top-right, 3 being right etc:
direction_index = (((16 - x) // 2) % 6) + 1
Where // is integer division and % is modulo.
Now that you have the directions, iterate from 1 to 6 and output the array index of your point that has the corresponding direction index, or 0 if there isn't one (assuming 1-based array indexing).
Your points are arranged in a hexagonal grid. When you consider the immediate neighbors, you can easily classify them in an absolute way by comparing the coordinates of the centers to three straight lines.
Then sort by index.
What about adding dummy points so that every point has six neighbors ? Then when you enumerate the neighbors in the desired order, you just skip the dummy ones.
Depending how your data structures are organized, you could truly add points to the point set, or add them "virtually" when you process a given point.
I need to ensure that a point is no more than x distance from a line derived from multiple other points.
If I plot lat/long points every 3 miles, I can infer a 'line' to travel. I want to make sure that 'potential' destinations are no more than 1 mile from that line. (the "multiple" points wont always be the same from instance to instance, BUT will be consistent per instance, and the "acceptable" distance from the line can vary per instance).
The tricky part is I have points, not a line...(the line is implied). Things work out "ok" if my "acceptable distance" is greater then my distance between the multiple points. however... If, say, my multiples are 2.5 apart, and I say a distance of 1 is acceptable for any point of interest. Then there are points between the two original points, that lie along the line but I can figure easily.
So I though since I have ONE measurement, I know the length of a line (on x axis, the distance between 2 of the multiple points..). I could treat that as one of two equal sides of a triangle and figure the hypotenuse.
d = distance between (each, multiple) points.
a = ( d/2 )
b = ( d/2 )
c = sq root of ( a^2 + b^2 )
C is going to be slightly larger then my initial "acceptable distance", so I'll use that.
Is there an better way to figure???
thx
Lets see if I can illustrate
point A point B
O----------------------------------O
distance form point A to point B is 5 miles...
Now...
point A point B
O----------------------------------O
point C
O
Question: is point C inside of 1 mile from the line that connects point A and B?????
How does one express this with math? such that the distance between points can be expressed as a variable.
This is a mapping problem, points of interest close to a 'road' or 'path' that has sample points as Lat/long the point of interest also has a lat/long.
If I use a triangle or intersecting circles, I end up with peaks or humps that are well outside of my 'acceptable distance off path', just to accommodate the space between my samples.
I hope that makes sense.
You can find the distance from a line which is defined by two points using the formula here -> http://en.wikipedia.org/wiki/Distance_from_a_point_to_a_line
A perpendicular line segment will be your friend in this problem. Find a line segment perpendicular to AB which contains point C.
The intersection of the line segments would be point D.
Get the distance of segment CD and you have your answer.
I have generated a Voronoi tessellation for N number of points in 2D space using the deldir R package.
Now I want to divide each Voronoi cell into three Voronoi cells according to given azimuth described as below:
Azimuth is given as an input. E.g.: azimuth = 0 means an area should be separated by 2 lines at angle = 0 to angle = 120. Next area by angle = 120 to angle = 240 and last area is the remainder.
Azimuth is the starting angle from north for this separation and always it spans 120 degrees. In more detail, from each point Voronoi is generated exactly three lines are drawn dividing previous Voronoi cell into three Voronoi cells.
Can this be achieved using the deldir package? if not can anyone suggest a extension for this?
I don't know any easy/implemented way of doing this. However, you could try creating those lines manually.
I would try something along the lines of:
Access the coordinates of the edges of a voronoi polygon using deldir()
Convert the coordinates into line objects using the sp package
Create line objects that reach from the "center"-point to the border of the plot (calculating the end points based on your azimuth)
Find intersections of the lines created in 3 with the lines created in 2 (check How to get the intersection point of two vector?)
Create new (shorter) lines starting from your original point and ending at the intersection point retrieved from step 4.
Plot the lines created in 5.
Loop for every polygon
This may well be a very clumsy solution, but it is the only workaround I could come up with ;)
I have series of (x, y) coordinates, if joined this represent a polyline. This polyline is a geographic track.
All that I need is to get the polyline tortuosity. It should be usefull a sort of percentage. E.g. The path has x% tortuosity.
well, it all depends on how you define tortuosity. there is a wikipedia article regarding tortuosity, which may shed some light on the subject.
an interesting sentence in the article tells us that: "roughness (or tortuosity) could be measured by relative change of curvature". that makes a good starting point.
your polyline is made of adjacent line segments. you can compute the angle between each adjacent line segment. using this information you can get a good idea of tortuosity for your polyline. for example, let seg(n) be the line segment between point n and point n+1:
tortuosity = sum(abs(angle(seg(n), seg(n+1))) for n in 1 to number of segment)
(computing the angle between 2 line segments is left as an exercise, but does not require a degree in mathematics)
the above measure is not scaled: the more points you have, the higher the value might be. you can easily scale this result according to the number of line segments you have:
unit_tortuosity = tortuosity / (n * pi)
(the maximum angle between 2 line segments is pi, adjust your angle() function so that it returns a result between 0 and pi. so your tortuosity would be at most n*pi, hence the above scaling factor which allows to have a value between 0 and 1 with 0 representing a perfectly straight polyline)
Given a list of vertices (v), and a list of edges connecting the vertices (e), and a list of surfaces that connect the edges (s), how to calculate the volume of the Polyhedron?
Take the polygons and break them into triangles.
Consider the tetrahedron formed by each triangle and an arbitrary point (the origin).
Sum the signed volumes of these tetrahedra.
Notes:
This will only work if you can keep a consistent CW or CCW order to the triangles as viewed from the outside.
The signed volume of the tetrahedron is equal to 1/6 the determinant of the following matrix:
[ x1 x2 x3 x4 ]
[ y1 y2 y3 y4 ]
[ z1 z2 z3 z4 ]
[ 1 1 1 1 ]
where the columns are the homogeneous coordinates of the verticies (x,y,z,1).
It works even if the shape does not enclose the origin by subracting off that volume as well as adding it in, but that depends on having a consistent ordering.
If you can't preserve the order you can still find some way to break it into tetrahedrons and sum 1/6 absolute value of the determinant of each one.
Edit:
I'd like to add that for triangle mesh where one vertex (say V4) of the tetrahedron is (0,0,0) the determinante of the 4x4 matrix can be simplified to the upper left 3x3 (expansion along the 0,0,0,1 column) and that can be simplified to Vol = V1xV2.V3 where "x" is cross product and "." is dot product. So compute that expression for every triangle, sum those volumes and divide by 6.
Similarly with a polygon where we can split it into triangles and sum the areas,
you could split a polyhedron into pyramids and sum their volumes. But I'm not sure how hard is to implement an algorithm for that.
(I believe there is a mathematical way/formula, like using vectors and matrices.
I suggest to post your question also on http://mathoverflow.net)
I have done this before, but the surface mesh I used always had triangular facets. If your mesh has non triangular facets, you can easily break them up into triangular facets first. Then I fed it to TetGen to obtain a tetrahedralization of the interior. Finally, I added up all the volumes of the tetrahedra. TetGen is reasonably easy to use, and is the only library other than CGAL I know of that can handle complicated meshes. CGAL is pretty easy to use if you don't mind installing a gigantic library and use templates like crazy.
First, break every face into triangles by drawing in new edges.
Now look at one triangle, and suppose it's on the "upper" surface (some of these details will turn out to be unimportant later). Look at the volume below the triangle, down to some horizontal plane below the polyhedron. If {h1, h2, h3} are the heights of the three points, and A is the area of the base, then the volume of the solid will be A(h1+h2+h3)/3. Now we have to add up the volumes of these solids for the upper faces, and subtract them for the lower faces to get the volume of the polyhedron.
Play with the algebra and you'll see that the height of the polyhedron above the horizontal plane doesn't matter. The plane can be above the polyhedron, or pass through it, and the result will still be correct.
So what we need is (1) a way to calculate the area of the base, and (2) a way to tell an "upper" face from a "lower" one. The first is easy if you have the Cartesian coordinates of the points, the second is easy if the points are ordered, and you can combine them and kill two birds with one stone. Suppose for each face you have a list of its corners, in counter-clockwise order. Then the projection of those points on the x-y plane will be counterclockwise for an upper face and clockwise for a lower one. If you use this method to calculate the area of the base, it will come up positive for an upper face and negative for a lower one, so you can add them all together and have the answer.
So how do you get the ordered lists of corners? Start with one triangle, pick an ordering, and for each edge the neighbor that shares that edge should list those two points in the opposite order. Move from neighbor to neighbor until you have a list for every triangle. If the volume of the polyhedron comes up negative, just multiply by -1 (it means you chose the wrong ordering for that first triangle, and the polyhedron was inside-out).
EDIT:
I forgot the best part! If you check the algebra for adding up these volumes, you'll see that a lot of terms cancel out, especially when combining triangles back into the original faces. I haven't worked this out in detail, but it looks as if the final result could be a surprisingly simple function.
Here's a potential implementation for that in Python.
Can anyone please check if it's correct?
I believe that I am missing permutations of the points because my second test (cube) gives 0.666 and not 1. Ideas anyone?
Cheers
EL
class Simplex(object):
'''
Simplex
'''
def __init__(self,coordinates):
'''
Constructor
'''
if not len(coordinates) == 4:
raise RuntimeError('You must provide only 4 coordinates!')
self.coordinates = coordinates
def volume(self):
'''
volume: Return volume of simplex. Formula from http://de.wikipedia.org/wiki/Tetraeder
'''
import numpy
vA = numpy.array(self.coordinates[1]) - numpy.array(self.coordinates[0])
vB = numpy.array(self.coordinates[2]) - numpy.array(self.coordinates[0])
vC = numpy.array(self.coordinates[3]) - numpy.array(self.coordinates[0])
return numpy.abs(numpy.dot(numpy.cross(vA,vB),vC)) / 6.0
class Polyeder(object):
def __init__(self,coordinates):
'''
Constructor
'''
if len(coordinates) < 4:
raise RuntimeError('You must provide at least 4 coordinates!')
self.coordinates = coordinates
def volume(self):
pivotCoordinate = self.coordinates[0]
volumeSum = 0
for i in xrange(1,len(self.coordinates)-3):
newCoordinates = [pivotCoordinate]
for j in xrange(i,i+3):
newCoordinates.append(self.coordinates[j])
simplex = Simplex(newCoordinates)
volumeSum += simplex.volume()
return volumeSum
coords = []
coords.append([0,0,0])
coords.append([1,0,0])
coords.append([0,1,0])
coords.append([0,0,1])
s = Simplex(coords)
print s.volume()
coords.append([0,1,1])
coords.append([1,0,1])
coords.append([1,1,0])
coords.append([1,1,1])
p = Polyeder(coords)
print p.volume()