简体   繁体   中英

Intersection between a polygon and a line in shapely

I am trying to find the intersections between circular polygons and a line and then merge the results.

I would expect all the intersections to belong to the line and also their union, but it is not what I see.

Here an example:

from shapely.geometry import LineString, Point

line = LineString([(2, 5), (2.1, 1)])  # slightly oblique line

point1 = Point(2.5, 3)

int1 = line.intersection(point1.buffer(1))
int2 = line.intersection(point1.buffer(1.3))

union = int1.union(int2)

print union.length
print int2.length

results:

4.22183534925

2.43702622444

since int2 contains int1 I would expect their union to be exactly int2. I would expect also the union to be just a LineString, but instead it is a MultiLineString composed by 4 lines.

If I plot the union lines I see how their are really close each other but not on the same line.

I think it is something to do with the resolution of the shapely objects values.

Any suggestion how to merge "almost parallel" lines into one? Or do you suggest any other solution to this problem?

As far as I know, there is no shapely built-in function to do what you need. Besides, as you noticed, ther are some round errors that you need to address. Fortunately, there are some shapely functions that can help you to implement a short solution:

  1. The project method of a LineString that takes a point and gives you the distance from the first point of the line to the closest point of the line to the given point.
  2. The interpolate method of a LineString that given a distance, it gives you the point that is in the LineString with that distance from the first point of the line.

I will assume you know what line is inside the other, as in the example. If this is the case, what you can do is to projet the points of the shorter line into the longer line, and then sort those points considering their distance to the first point of the line.

With the following code,

from shapely.geometry import LineString, Point
from shapely.ops import linemerge

def getProyection(aline, point_coords):
    return aline.interpolate(aline.project(Point(point_coords)))

def mergeInside(aline, inside_line):
    mline_tups = [(aline.project(Point(p)), p) for p in aline.coords]
    mline_tups.extend([ (aline.project(Point(p)), getProyection(aline, p))
                                    for p in inside_line.coords])
    mline_tups.sort()
    return LineString([p for _, p in mline_tups])

line = LineString([(2, 5), (2.1, 1)])  # slightly oblique line
point1 = Point(2.5, 3)
int1 = line.intersection(point1.buffer(1))
int2 = line.intersection(point1.buffer(1.3))
merged_line = mergeInside(int2, int1)

print(int1)
print(int2)
print(merged_line)

I get:

LINESTRING (2.02796158358983 3.881536656406788, 2.072567874421353 2.097285023145893)
LINESTRING (2.019819096605441 4.207236135782384, 2.080725721869193 1.770971125232286)
LINESTRING (2.019819096605441 4.207236135782384, 2.027961583589831 3.881536656406788, 2.072567874421353 2.097285023145893, 2.080725721869193 1.770971125232286)

Since I am mainly interested in the length of the union rather then its exact vertices I have found another way to measure it.

from shapely.geometry import LineString, Point

line = LineString([(2, 5), (2.1, 1)])  # slightly oblique line

point1 = Point(2.5, 3)

int1 = line.intersection(point1.buffer(1))
int2 = line.intersection(point1.buffer(1.3))

line_not_intersected = line.difference(point1.buffer(1))
line_not_intersected = line_not_intersected.difference(point1.buffer(1.3))

print line.length - line_not_intersected.length
print int2.length

and it gives the expected result:

2.43702622444

2.43702622444

Interesting, and annoying at the same time, if I get the union as

union = line.difference(line_not_intersected)

union is a LineString, but its length is not the same as the difference of the lengths of the two lines.

print line.length - line_not_intersected.length
print union.length

2.43702622444

4.00124980475

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM