I have a MultiLineString lines which runs along the edges of several polygons 'poly`. All are GeoPandas GeoDataFrames.
The polygons are triangles formed through scipy.spatial.delaunay
I'm trying to get 3 separate bool masks to identify those polygons which share 1, 2, or 3 edges with the MultiLineString.
I've been trying every combination of:
contains/crosses/intersects/overlaps/touches/within/covers/
mask = poly.<method>(lines)
Any ideas?
Give the geopandas docs on merging data a close read. All of those methods are binary predicates which merge the dataframes on their indexes. So unless the dataframes are already aligned, you’ll get incorrect results or nans.
You want a spatial join using GeoDataFrame.sjoin:
poly.sjoin(lines, how="left")
This will give you any lines which intersect the polygons.
Related
I am using boost geometry and I am trying to calculate a "bounded" polygon (see image below) from intersecting polylines (linestrings 2d in Boost geometry). Currently, my approach is i) to get all the intersection points between these lines and then ii) "split" each line at the intersection points. However, this algorithm is a little bit exhaustive. Does anyone know if boost geometry has something more efficient for this?
Moreover, how could I get the segment (or vector of points) for each linestring that lie withing two intersection points? For example, for the green linestring, if I have the two red intersection points, how can I get the linestring between these two points (vector of points containing the two red intersection points and the two interior blue points)? Is there any "split"-like functionality in boost geometry?
Any suggestion is much appreciated. Thanks a lot in advance.
From the given description, it seems that the (poly)lines intersect in pairs to form a single loop, so that the inner polygon is well defined. If this is not true, the solution is not unique.
As the number of lines is small, exhaustive search for the pairwise intersections will not be a big sin. For 5 (poly)lines, there are 10 pairs to be tried, while you expect 5 intersections. Forming the loop from the intersections is not a big deal.
What matters most is if Boost Geometry uses an efficient algorithm to intersect polylines. Unsure if this is documented. For moderate numbers of vertices (say below 100), this is not so important.
If the number of points is truly large, you can resort to an efficient line segment intersection algorithm, which lowers the complexity from O(n²+k) down to O((n+k) log n). See https://en.wikipedia.org/wiki/Bentley%E2%80%93Ottmann_algorithm. You can process all polylines in a single go.
If your polylines have specific properties, they can be exploited to ease the task.
While investigating packings of spheres I ran into this problem where I have a list of vectors and I want to know how many planes they generate. I'm generating these lists of vectors that point from the center of a sphere to a contact point on the outside surface of the sphere and I want to know how many of these vectors are coplanar. For example I want an algorithm that will do the following..
Given the vectors {1,2,3}, {2,4,6}, and {0,6,9} it should report that there is only one unique plane generated by either one of the first two and the third.
All of my attempts haven't gotten anywhere because every time I count how many planes are generated I drastically over count. I feel like this should be an easy thing to do and I'm also curios if there is any linear algebra that can somehow come to the rescue. If I can determine how many planes are generated and what those planes are I think it will be easy to determine how many vectors lie in each plane which is the last part of this problem. If anyone can think of a more general approach to any dimension two or greater that would actually be ideal but for now this is all I'm concerned with.
You can use Gaussian elimination to determine the dimension of the span of several vectors. (the space that is created by all linear combinations of these - also called rank of the matrix)
Create a matrix from your vectors by writing the vectors in the rows of your matrix. Then use Gaussian elimination and count the number of Rows that still have non-zero entries. This is the dimension of the spanned vectorspace.
Since you use vectors from R^3 this will never be greater than 3. However a plane is a 2-dimensional vectorspace, so you need to find all combinations of vectors that result in a 2-dimensional span, which can be easily found by iterating over your vectors once you have implemented gaussian elimination.
Edit:
An example since it seems that this can still lead to confusion:
you have a set of 3 vectors: (1,0,0); (0,1,0); (0,0,1)
You can create 3 different planes from these (by combining any two of these vectors you get a different plane.) To formally check if that statement is true you need to do the following for every pair v1,v2 of vectors:
check whether v1,v2 are linear independant - if they aren't, they don't create a plane, so you go ahead and pick the next two vectors. (in this example they always are linear independant)
Check for each other vector in your list, if it (v3) does not lie within the created plane (it is not coplanar to v1,v2). To do this use gaussian elimination on the matrix (v1,v2,v3) and confirm that the rank of the matrix is 3.
If the matrix in step 2 has a rank of 2, this means that the vectors v1,v2,v3 are coplanar. Thus you can pick any two of these vectors to generate the exact same plane.
As an example: you start with vectors (1,0,0) and (0,1,0). Then you check several other vectors and find that two of them are coplanar to your initial vectors (for example (1,1,0) and (-1,-1,0)). This means that for your list of unique planes, you may add the plane generated by any two out of these four vectors, but not add any other combination of these.
Note: this works for finding 2 dimensional planes in higher dimensions as well of course. You can even check for higher dimensional planes, but this needs some adapting in the number of vectors you compare and the rank for which you check.
I am working with a serialization pipeline. I am taking a model and exporting it. I do not wish to export any model with a hole in a face. How would I detect a hole and report a error?
I have access to all vertexes, edges, faces etc.
Here is a picture of what I mean.
As you can see there is a hole in the face. I am fairly new to geometry so please try to explain in layman terms.
If a 3D object is "simple", meaning that it doesn't have holes, it satisfies Euler's Formula for Polyhedra, V - E + F = 2 where V is the number of vertices in the figure, E is the number of edges, and F is the number of faces. If you can easily obtain those three numbers, you can calculate the formula V - E + F. If the result is not 2, the object has a hole (or some other pathology like a pinch). In fact, you can tell how many holes the object has by V - E + F: if the number is 0, it has one hole; if the number is -2, it has two holes; etc.
Calculating V, E, and F can be a little tricky because vertices are generally shared by two or more edges, and edges are generally shared by two faces. You don't want to overcount; if three edges meet in a single vertex, you only want to count the vertex once, not three times.
Not only that, but it's easy to make a mistake counting when the shapes have holes (which is exactly the case you're interested in). The easiest way to avoid making a mistake is to break the figure up into convex parts with e.g., triangulation.
The formula doesn't tell you which face has the hole, but if you know that the figure has a hole you can apply Euler's formula to each face individually, again with triangulation. In that case, faces without holes will have V - E + F = 1 where V,E,F are now restricted to the face in question. (the discrepancy with the previous formula is resolved if you count the region outside the face as another (infinite) face). Faces with holes will have V - E + F < 1.
For example, a triangle on the plane has V=3, E=3, and F=1 (the "face" of the triangle represented by its interior) giving V-E+F=1. On the other hand, a triangle with a similarly shaped triangular hole inside, in which corresponding vertices of inner and outer triangles are connected, will have V=6, E=9, and F=3 for V-E+F=0. I have broken the figure into three convex quadrilaterals in this case.
Most books on computer graphics have a discussion of this topic.
If I understand correctly, you want to detect polygons with holes. Now how polygons with holes are represented can vary with each software (some store separate internal contour lists). However, a common representation in 3D packages (including formats like OBJ) use a flat face vertices representation which tends to look like this:
... where 2,6 and 1,7 would be the same vertex index stored twice in the same polygon (the numbers in the picture indicate face point indices). Note that this edge from 1,7 to 2,6 could be hidden in some software, but it's there even if it's not visible if the software stores polygon vertices in a flat list of indices/pointers.
So a quick way to tell if a polygon has a hole with such representations given only face data (ex: from an OBJ file) is to see if it has duplicate entries for the vertex indices. If the same vertex index is repeated more than one time in a polygon, then it has a hole.
Now there is a case where you can find duplicated vertices for an empty inner contour, like so:
... where 2,4 are welded (same vertex). If you want to distinguish these cases, you can detect them when the edge connecting exterior contour to interior contour only has one vertex duplicated instead of two. In that case, the interior contour is empty and this polygon is just a funky one (perhaps created through a CSG/plane slicing operation).
If you want a really robust solution, it's worth writing a routine that "unflattens" these flat contour lists into multiple interior/exterior groups by splitting the list apart where the duplicate edges connecting one contour to another are found. If the interior groups have fewer than 3 vertices, then they're probably just funky polygons without a visually noticeable hole. If they have 3 or more, then they meet the criteria required to show a hole which you can see visually. In cases where the interior contours don't form a full-fledged hole, you can just toss the interior contour and keep the exterior contour (in which case it's like just keeping the 3-point triangle exterior in the above pic while tossing out those redundant vertices, kind of cleaning up the geometry in the process and giving you the triangle formed from {1, 2/4, 5}).
A simple solution you can apply if you don't mind exporting unwelded geometry as long as it isn't funky (no holes or interior contours) is to simply clone (make unique) vertices that are duplicates in a polygon, basically unwelding it, like so:
That's a little easier than a full-blown tessellation kind of solution, and it still ends up giving you polygons without any holes or separate interiors. I visually moved 2 and 4 apart for the sake of demonstration to emphasize that they're now separate vertices, but you don't have to do that (they can be coincident).
This kind of unwelding technique is also useful if you have a tessellator that doesn't support holes. You can apply this technique to unweld the polygon, tessellate it, then weld/merge back coincident vertices to give you the final result.
Given a bunch of convex polygons layed out like a house truss, is there a way to compute the empty area, or get a polygon for each of those "holes" between the polygons?
I tried starting from any given polygon and then finding the intersections between some of the lines of the polygons and somehow I'm stuck at how to properly select which lines to use for the intersections.
I then tried to verify for a clockwise detection of the area but it seem that my algo for determining the CW/CCW of two lines does not work as, I think, it act as if the lines have the same origin instead of being "in sequence" from each other.
According to comments the solution is quite easy
1.prepare data
represent your mesh as table of points and remove redundant points (point = x,y,z... + int cnt=0; )
and table of lines (line = 2 * index of point from point table + bool deleted=false)
while creating table of lines for each used point increment its cnt counter
2.remove redundant lines (join border between thick lines)
find all lines that are overlapping and lie on the same line
they have the same or opposite direction
remove the shorter one and dissect the bigger one and update all tables accordingly (also point cnt !!!)
after this find all lines between points used booth more than twice
delete them ...
3.find all closed loops
something like this:
1.create list of polygons
polygon is list of point indexes
2.take any undeleted line
if found add new polygon to list and
copy its points to polygon
flag line as deleted
if not found stop
3.find line with point matching last polygon point
add the other point to polygon
flag line as deleted
repeat bullet 2 until there is no such line found
4.goto 1
4.now found polygon with the biggest bounding box
this polygon is the outer perimeter
so delete it
also you can draw it by different color for debugging purposes
5.now sum the rest
all remaining polygons are the holes
so triangulate them
and sum all triangle areas by basic math formula ...
also you can draw them by other different color for debugging purposes
This is not a straightforward problem, as the complete geometry needs to be computed incrementally, using some intersection points and/or chamfering/trimming rules.
I imagine two approaches:
1) build yourself a toolbox of the required geometric operations (using analytic geometry), among which segment/segment intersection and probably a few others (which will map to the truss design rules); using this toolbox, construct all required polygon vertices "by hand", based on the picture; lastly, compute the area of the polygonal holes with the general formula: http://en.wikipedia.org/wiki/Polygon#Area_and_centroid.
2) use a ready-made polygon manipulation library like Clipper (http://www.angusj.com/delphi/clipper.php), which will allow you to draw the logs without much care about the trimmings at endpoints (you will perform a union of rectangles and get a polygon with holes).
After my understanding of your question, the first approach is better.
UPDATE:
If what you have is a set of polygons corresponding to every log, the answer is different:
If you only care about the total area of the voids, compute the area of the outer outline and deduce the areas of every log.
And if you need the areas of individual holes, then use the second approach: perform the union of the polygons and query for the holes.
I am having 2D line segments. My goal is to make different closed polygons. But, in here, I want to select most outer line segments when there are few parallel line segments stay closed to each other. with different line combinations, I can make different closed polygons.I was thinking and struggling to know how to get most outer lines as I need the polygon which make by outer most lines. (Polyogns are at the end constructed by intersecting adjoying line segments.)
I was thinking to get a large bounding box containing all segments and get the centroid and then find the perpendicular distances to each line. In this process, I found nearby line segments which oriented close to each other (i.e. near parallel lines). So, from those nearby parallel lines I want outer most one. (that is red one).
But If I used the centroid and compare the distnaces, then longest distance (among nearby parallel lines) does not give correct outer most line when more concave and convex turns exist as some cases outer most (red) one does not give by the longest distance. What I have is; end point coordinates of each line segments. (that is vector data)
So, I am looking for some good way to get most outer line segments from nearby parallel lines.
For you to understand I have attached a sample data which i have. The most outer line segments are shown in red color. finally this red lines give me the boundary of my polygon. So, I want to get red lines out of corresponding nearby parallel black lines.
NOTE: My line segments are oriented into different direction. And not only to X & Y axes. Also, nearby lines donot make always 90 or 180 angles with adjacent lines.
please suggest me a method. thanks in advance
for example, if A,B and C,D are nearby parallel line segments. then outer most line should be B and C. But, If i compare distances from centroid (O), then I can get C as outer most, but B can not get as distance from O to B is smaller than O to A. My method fails in this type of spots. So, look alternatives..
A general way to find lines is using the Hough Transform.
http://en.wikipedia.org/wiki/Hough_transform
However, the sample data you give has lines parallel to the axes. I don't know if that is the nature of all of your data, but if it is then the Hough Transform basically breaks down to simply summing up the intensities by rows for lines parallel to the x-axis and summing by columns for lines parallel to the y-axis.
You will end up with two 1D arrays, one with row sums and one with column sums. Since the lines are black and the foreground is white, local minimums in these arrays will represent line locations along each axis. Since you only need the outer lines, you do not have to sum every column/row - just start at the edges of the image and compute the sums until you hit a local min. Once you have the line's placement on the axis, you can traverse that cut of the axis in the image to find the endpoints of the line.