-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathst_buffer_squashed.py
More file actions
73 lines (57 loc) · 3.2 KB
/
st_buffer_squashed.py
File metadata and controls
73 lines (57 loc) · 3.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
def st_buffer_squashed(linestring, buffer_radius, end_cap_radius):
import numpy as np
import shapely
from shapely.geometry import LineString
from shapely.geometry import Point
from shapely.geometry import Polygon
import warnings
if end_cap_radius > buffer_radius:
warnings.warn("end_cap_radius > buffer_radius. Truncating end_cap_radius", UserWarning)
end_cap_radius = buffer_radius
if end_cap_radius < 0:
warnings.warn("end_cap_radius < 0. Returning flat cap buffer", UserWarning)
return linestring.buffer(buffer_radius, cap_style='flat')
first_two_points = list(linestring.coords[:2])
line_first_two_points = LineString(first_two_points)
first_two_x, first_two_y = line_first_two_points.xy
last_two_points = list(linestring.coords[-2:])
line_last_two_points = LineString(last_two_points)
last_two_x, last_two_y = line_last_two_points.xy
### handle inf slope
if first_two_x[1] == first_two_x[0]:
first_two_x[1] += 0.000001
if last_two_x[1] == last_two_x[0]:
last_two_x[1] += 0.000001
first_two_slope = (first_two_y[1] - first_two_y[0])/(first_two_x[1] - first_two_x[0])
last_two_slope = (last_two_y[1] - last_two_y[0])/(last_two_x[1] - last_two_x[0])
### distance to move off from first point or last point to get center of circle
circle_center_distance = (buffer_radius**2-end_cap_radius**2)/(2*end_cap_radius)
### radius of circle that will define squashed end
circle_radius = np.sqrt(circle_center_distance**2 + buffer_radius**2)
start_posn_delta_x = np.sqrt(circle_center_distance**2 / (1 + first_two_slope**2))
if first_two_x[1] < first_two_x[0]:
start_posn_delta_x *= -1
start_posn_delta_y = first_two_slope * start_posn_delta_x
end_posn_delta_x = np.sqrt(circle_center_distance**2 / (1 + last_two_slope**2))
if last_two_x[1] < last_two_x[0]:
end_posn_delta_x *= -1
end_posn_delta_y = last_two_slope * end_posn_delta_x
start_circle_x_center = first_two_x[0] + start_posn_delta_x
start_circle_y_center = first_two_y[0] + start_posn_delta_y
end_circle_x_center = last_two_x[1] - end_posn_delta_x
end_circle_y_center = last_two_y[1] - end_posn_delta_y
start_circle_center = Point(start_circle_x_center, start_circle_y_center)
end_circle_center = Point(end_circle_x_center, end_circle_y_center)
# Create a circular polygon using the buffer method
start_circle = start_circle_center.buffer(circle_radius)
end_circle = end_circle_center.buffer(circle_radius)
### st functions
buffer_flat = linestring.buffer(buffer_radius, cap_style='flat')
start_round = Point(first_two_x[0],first_two_y[0]).buffer(buffer_radius)
end_round = Point(last_two_x[1],last_two_y[1]).buffer(buffer_radius)
buffer_difference_start = start_round.difference(buffer_flat)
buffer_difference_end = end_round.difference(buffer_flat)
start_cap_squashed = buffer_difference_start.intersection(start_circle)
end_cap_squashed = buffer_difference_end.intersection(end_circle)
final_squashed_buffer = buffer_flat.union(start_cap_squashed).union(end_cap_squashed)
return final_squashed_buffer