Reputation: 1001
I have different shapely.LineStrings
like so:
which I then buffer
to create a polygon like so:
I've played around a bit and found that buffering each line segment is slightly faster than unary_union
-ing all the linestrings and then buffering the whole thing together. However I do need the total area of the buffered lines as a shapely polygon as I am using it for intersection detection later. So I end up having to unary_union
the buffered polygons to get the overall polygon and this is taking some time (not for this particular example but for other examples with more green lines).
So is there a faster way to get the buffered polygon that I am unaware of?
Here is a reproducible example:
import numpy as np
from shapely.geometry import MultiLineString, LineString, Polygon
from shapely import ops, affinity
import matplotlib.pyplot as plt
from math import atan2, degrees
from descartes.patch import PolygonPatch
if __name__ == '__main__':
Coords = np.array([
[0, 0, 0, 0, 'N', 0, 0],
[0, 1, 0, 'BRANCH', 'N', 0, 0],
[0, 0, 0, 'BRANCH', 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0],
[-0.85, -0.51, 0, 'BRANCH', 'Y', 45, 0],
[-0.85, -0.51, 0, 'NODE', 'Y', 45, 0],
[-1.71, -1.03, 0, 0, 'Y', 45, 0],
[-1.66, -2.02, 0, 'BRANCH', 'Y', 45, 0],
[-1.66, -2.02, 0, 'NODE', 'Y', 45, 0],
[-1.60, -3.02, 0, 'BRANCH', 'Y', 45, 0],
[0, 0, 0, 0, 0, 0, 0],
[0.90, -0.42, 0, 'BRANCH', 'Y', 45, 0],
[0.90, -0.42, 0, 'NODE', 'Y', 45, 0],
[1.81, -0.84, 0, 'BRANCH', 'Y', 45, 0],
[0, 0, 0, 'BRANCH', 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0],
[0.10, -0.99, 0, 0, 'Y', 45, 0],
[-0.69, -1.59, 0, 0, 'Y', 45, 0],
[-0.53, -2.58, 0, 'BRANCH', 'Y', 45, 0],
[-0.53, -2.58, 0, 'NODE', 'Y', 45, 0],
], dtype=object)
for ind, coord in enumerate(Coords):
if coord[3] == 'BRANCH':
if (coord[0:3] == Coords[ind + 1, 0:3]).all():
np.delete(Coords, ind, 0)
lines = []
j = 0
for i in range(len(Coords)):
if (Coords[i, 3] == 'BRANCH') or (i == (len(Coords) - 1)):
lines.append(Coords[j:i+1].tolist())
j = i+1
if not lines:
Lines = [Coords[:]]
else:
Lines = [line for line in lines if len(line) > 1]
fig, ax = plt.subplots()
patches = []
lines = []
Vs = []
all_r_lines = []
texts = []
for num, line in enumerate(Lines):
line = np.asarray(line, dtype=object)
num_coords = line[:, 0:2]
cumm = 0
indi_coords = []
for i, joint in enumerate(line):
if joint[4] == 'Y' and joint[3] != 'BRANCH':
""" --------------- BODY -------------------------------- """
indi_coords.append((joint[0], joint[1]))
new_coords = ((line[i+1][0]), (line[i+1][1]))
angle = degrees(atan2(
(new_coords[1] - joint[1]),
(new_coords[0] - joint[0])
))
if cumm > 0:
Lines[num][i][6] = cumm
cumm += 1
else:
indi_coords.append((joint[0], joint[1]))
cumm = 0
lines.append(np.asarray(indi_coords))
linestring = MultiLineString(lines)
for num, line_coords in reversed(list(enumerate(Lines))):
for i, joint in reversed(list(enumerate(line_coords))):
if joint[4] == 'Y' and i < (len(Coords)-1) and joint[3] != 'BRANCH':
if joint[6] > 0:
""" --------------- PATCH -------------------------------- """
lineA = LineString([(joint[0], joint[1]),
((line_coords[i+1][0]), (line_coords[i+1][1]))])
left_line = affinity.rotate(
lineA, joint[5]/2, (joint[0], joint[1]))
rigt_line = affinity.rotate(
lineA, -joint[5]/2, (joint[0], joint[1]))
try:
Vs[-1] = ops.unary_union([MultiLineString(
[lineA, left_line, rigt_line])] + all_r_lines[-1])
except:
Vs.append(MultiLineString([lineA, left_line, rigt_line]))
""" --------------- ANGLE LINES -------------------------------- """
rotate_angle = line_coords[i-1][5]/2
r_lines = [affinity.rotate(
Vs[-1],
j,
(line_coords[i-1][0], line_coords[i-1][1])
) for j in np.linspace(-rotate_angle, rotate_angle, num=3)
]
all_r_lines += [r_lines]
Vs[-1] = ops.unary_union([Vs[-1]] + r_lines)
else:
""" --------------- PATCH -------------------------------- """
lineA = LineString([(joint[0], joint[1]),
((line_coords[i+1][0]), (line_coords[i+1][1]))])
left_line = affinity.rotate(
lineA, joint[5]/2, (joint[0], joint[1]))
rigt_line = affinity.rotate(
lineA, -joint[5]/2, (joint[0], joint[1]))
Vs.append(MultiLineString([lineA, left_line, rigt_line]))
all_r_lines = []
all_lines = Vs
a = ops.unary_union(all_lines)
creature = (Vs + [a] + [linestring])
polies = []
for l in creature:
polies.append(Polygon(l.buffer(0.5)))
creature_poly = ops.unary_union(polies)
creature_patch = PolygonPatch(creature_poly, fc='BLUE', alpha=0.1)
absorbA = creature_poly
moves = Vs
for c_l in linestring:
x, y = c_l.xy
ax.plot(x, y)
for m in all_lines:
for line in m:
x, y = line.xy
ax.plot(x, y, 'g--', alpha=0.25)
ax.axis('equal')
ax.add_patch(creature_patch)
ax.axis('equal')
plt.show()
Upvotes: 2
Views: 6238
Reputation: 85
Have you tried shapelys cascaded_union?
polygons = [Point(i, 0).buffer(0.7) for i in range(5)]
cascaded_union(polygons)
or in your case Line instead of Point?
https://shapely.readthedocs.io/en/stable/manual.html#shapely.ops.cascaded_union
Upvotes: 1