ObjectNat 1.3.1__tar.gz → 1.3.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {objectnat-1.3.1 → objectnat-1.3.3}/PKG-INFO +1 -1
- {objectnat-1.3.1 → objectnat-1.3.3}/pyproject.toml +1 -1
- objectnat-1.3.3/src/objectnat/_version.py +1 -0
- {objectnat-1.3.1 → objectnat-1.3.3}/src/objectnat/methods/noise/noise_simulation_simplified.py +18 -6
- {objectnat-1.3.1 → objectnat-1.3.3}/src/objectnat/methods/visibility/visibility_analysis.py +80 -57
- objectnat-1.3.1/src/objectnat/_version.py +0 -1
- {objectnat-1.3.1 → objectnat-1.3.3}/LICENSE.txt +0 -0
- {objectnat-1.3.1 → objectnat-1.3.3}/README.rst +0 -0
- {objectnat-1.3.1 → objectnat-1.3.3}/src/objectnat/__init__.py +0 -0
- {objectnat-1.3.1 → objectnat-1.3.3}/src/objectnat/_api.py +0 -0
- {objectnat-1.3.1 → objectnat-1.3.3}/src/objectnat/_config.py +0 -0
- {objectnat-1.3.1 → objectnat-1.3.3}/src/objectnat/methods/__init__.py +0 -0
- {objectnat-1.3.1 → objectnat-1.3.3}/src/objectnat/methods/coverage_zones/__init__.py +0 -0
- {objectnat-1.3.1 → objectnat-1.3.3}/src/objectnat/methods/coverage_zones/graph_coverage.py +0 -0
- {objectnat-1.3.1 → objectnat-1.3.3}/src/objectnat/methods/coverage_zones/radius_voronoi_coverage.py +0 -0
- {objectnat-1.3.1 → objectnat-1.3.3}/src/objectnat/methods/coverage_zones/stepped_coverage.py +0 -0
- {objectnat-1.3.1 → objectnat-1.3.3}/src/objectnat/methods/isochrones/__init__.py +0 -0
- {objectnat-1.3.1 → objectnat-1.3.3}/src/objectnat/methods/isochrones/isochrone_utils.py +0 -0
- {objectnat-1.3.1 → objectnat-1.3.3}/src/objectnat/methods/isochrones/isochrones.py +0 -0
- {objectnat-1.3.1 → objectnat-1.3.3}/src/objectnat/methods/noise/__init__.py +0 -0
- {objectnat-1.3.1 → objectnat-1.3.3}/src/objectnat/methods/noise/noise_init_data.py +0 -0
- {objectnat-1.3.1 → objectnat-1.3.3}/src/objectnat/methods/noise/noise_reduce.py +0 -0
- {objectnat-1.3.1 → objectnat-1.3.3}/src/objectnat/methods/noise/noise_simulation.py +0 -0
- {objectnat-1.3.1 → objectnat-1.3.3}/src/objectnat/methods/point_clustering/__init__.py +0 -0
- {objectnat-1.3.1 → objectnat-1.3.3}/src/objectnat/methods/point_clustering/cluster_points_in_polygons.py +0 -0
- {objectnat-1.3.1 → objectnat-1.3.3}/src/objectnat/methods/provision/__init__.py +0 -0
- {objectnat-1.3.1 → objectnat-1.3.3}/src/objectnat/methods/provision/provision.py +0 -0
- {objectnat-1.3.1 → objectnat-1.3.3}/src/objectnat/methods/provision/provision_exceptions.py +0 -0
- {objectnat-1.3.1 → objectnat-1.3.3}/src/objectnat/methods/provision/provision_model.py +0 -0
- {objectnat-1.3.1 → objectnat-1.3.3}/src/objectnat/methods/utils/__init__.py +0 -0
- {objectnat-1.3.1 → objectnat-1.3.3}/src/objectnat/methods/utils/geom_utils.py +0 -0
- {objectnat-1.3.1 → objectnat-1.3.3}/src/objectnat/methods/utils/graph_utils.py +0 -0
- {objectnat-1.3.1 → objectnat-1.3.3}/src/objectnat/methods/utils/math_utils.py +0 -0
- {objectnat-1.3.1 → objectnat-1.3.3}/src/objectnat/methods/visibility/__init__.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "ObjectNat"
|
|
3
|
-
version = "1.3.
|
|
3
|
+
version = "1.3.3"
|
|
4
4
|
description = "ObjectNat is an open-source library created for geospatial analysis created by IDU team"
|
|
5
5
|
license = "BSD-3-Clause"
|
|
6
6
|
authors = ["DDonnyy <63115678+DDonnyy@users.noreply.github.com>"]
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
VERSION = "1.3.3"
|
{objectnat-1.3.1 → objectnat-1.3.3}/src/objectnat/methods/noise/noise_simulation_simplified.py
RENAMED
|
@@ -131,9 +131,16 @@ def calculate_simplified_noise_frame(
|
|
|
131
131
|
point_from = row.geometry
|
|
132
132
|
point_buffer = point_from.buffer(max_dist, resolution=16)
|
|
133
133
|
local_obstacles = obstacles[obstacles.intersects(point_buffer)]
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
134
|
+
vis_poly_gdf = get_visibility_accurate(
|
|
135
|
+
gpd.GeoDataFrame(geometry=[point_from], crs=local_crs),
|
|
136
|
+
obstacles=local_obstacles,
|
|
137
|
+
view_distance=max_dist,
|
|
138
|
+
)
|
|
139
|
+
if len(vis_poly_gdf) > 0:
|
|
140
|
+
noise_from_feature = _eval_donuts_gdf(
|
|
141
|
+
point_from, dist_db, local_crs, vis_poly_gdf.iloc[0].geometry
|
|
142
|
+
)
|
|
143
|
+
frame_result.append(noise_from_feature)
|
|
137
144
|
pbar.update(1)
|
|
138
145
|
|
|
139
146
|
elif geom_type == "LineString":
|
|
@@ -148,7 +155,7 @@ def calculate_simplified_noise_frame(
|
|
|
148
155
|
)
|
|
149
156
|
frame_result.append(noise_from_feature)
|
|
150
157
|
elif geom_type == "Polygon":
|
|
151
|
-
group_gdf.geometry = group_gdf.buffer(0.1, resolution=
|
|
158
|
+
group_gdf.geometry = group_gdf.buffer(0.1, resolution=2)
|
|
152
159
|
layer_points = distribute_points_on_polygons(
|
|
153
160
|
group_gdf, only_exterior=False, radius=polygon_point_radius, lloyd_relax_n=1
|
|
154
161
|
)
|
|
@@ -186,8 +193,13 @@ def _process_lines_or_polygons(
|
|
|
186
193
|
local_obstacles = obstacles[obstacles.intersects(layer_buffer)]
|
|
187
194
|
for _, row in layer_points.iterrows():
|
|
188
195
|
point_from = row.geometry
|
|
189
|
-
|
|
190
|
-
|
|
196
|
+
vis_poly_gdf = get_visibility_accurate(
|
|
197
|
+
gpd.GeoDataFrame(geometry=[point_from], crs=local_crs),
|
|
198
|
+
obstacles=local_obstacles,
|
|
199
|
+
view_distance=max_dist,
|
|
200
|
+
)
|
|
201
|
+
if len(vis_poly_gdf) > 0:
|
|
202
|
+
features_vision_polys.append(vis_poly_gdf.iloc[0].geometry)
|
|
191
203
|
pbar.update(1)
|
|
192
204
|
features_vision_polys = unary_union(features_vision_polys)
|
|
193
205
|
return _eval_donuts_gdf(group_gdf.union_all(), dist_db, local_crs, features_vision_polys)
|
|
@@ -21,6 +21,44 @@ from objectnat.methods.utils.math_utils import min_max_normalization
|
|
|
21
21
|
logger = config.logger
|
|
22
22
|
|
|
23
23
|
|
|
24
|
+
def _ensure_crs(point_from, obstacles):
|
|
25
|
+
if isinstance(point_from, gpd.GeoDataFrame):
|
|
26
|
+
if point_from.empty:
|
|
27
|
+
raise ValueError("GeoDataFrame 'point_from' is empty.")
|
|
28
|
+
return_gdf = True
|
|
29
|
+
original_crs = point_from.crs
|
|
30
|
+
local_crs = point_from.estimate_utm_crs()
|
|
31
|
+
point_from = point_from.to_crs(local_crs)
|
|
32
|
+
if len(point_from) > 1:
|
|
33
|
+
logger.warning(
|
|
34
|
+
"This method processes only a single point. "
|
|
35
|
+
f"The GeoDataFrame contains {len(point_from)} points – "
|
|
36
|
+
"only the first geometry will be used for visibility calculation."
|
|
37
|
+
)
|
|
38
|
+
point_geom = point_from.iloc[0].geometry
|
|
39
|
+
if len(obstacles) > 0:
|
|
40
|
+
obstacles = obstacles.to_crs(local_crs)
|
|
41
|
+
|
|
42
|
+
else:
|
|
43
|
+
return_gdf = False
|
|
44
|
+
|
|
45
|
+
if len(obstacles) > 0:
|
|
46
|
+
original_crs = obstacles.crs
|
|
47
|
+
local_crs = obstacles.estimate_utm_crs()
|
|
48
|
+
obstacles = obstacles.to_crs(local_crs)
|
|
49
|
+
point_geom = gpd.GeoDataFrame(geometry=[point_from], crs=original_crs).to_crs(local_crs).iloc[0].geometry
|
|
50
|
+
else:
|
|
51
|
+
original_crs = 4326
|
|
52
|
+
logger.warning("No information about CRS was found, accepting everything in 4326")
|
|
53
|
+
point_gdf = gpd.GeoDataFrame(geometry=[point_from], crs=original_crs)
|
|
54
|
+
local_crs = point_gdf.estimate_utm_crs()
|
|
55
|
+
|
|
56
|
+
point_gdf = point_gdf.to_crs(local_crs)
|
|
57
|
+
point_geom = point_gdf.geometry.iloc[0]
|
|
58
|
+
|
|
59
|
+
return point_geom, obstacles, original_crs, local_crs, return_gdf
|
|
60
|
+
|
|
61
|
+
|
|
24
62
|
def get_visibility_accurate(
|
|
25
63
|
point_from: Point | gpd.GeoDataFrame, obstacles: gpd.GeoDataFrame, view_distance, return_max_view_dist=False
|
|
26
64
|
) -> Polygon | gpd.GeoDataFrame | tuple[Polygon | gpd.GeoDataFrame, float]:
|
|
@@ -56,31 +94,21 @@ def get_visibility_accurate(
|
|
|
56
94
|
raise e
|
|
57
95
|
return res
|
|
58
96
|
|
|
59
|
-
local_crs =
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
point_from = point_from.to_crs(local_crs)
|
|
71
|
-
if len(point_from) > 1:
|
|
72
|
-
logger.warning(
|
|
73
|
-
f"This method processes only single point. The GeoDataFrame contains {len(point_from)} points - "
|
|
74
|
-
"only the first geometry will be used for isochrone calculation. "
|
|
75
|
-
)
|
|
76
|
-
point_from = point_from.iloc[0].geometry
|
|
77
|
-
else:
|
|
78
|
-
obstacles = obstacles.copy()
|
|
79
|
-
if obstacles.contains(point_from).any():
|
|
80
|
-
return Polygon()
|
|
97
|
+
point_geom, obstacles, original_crs, local_crs, return_gdf = _ensure_crs(point_from, obstacles)
|
|
98
|
+
|
|
99
|
+
if len(obstacles) > 0 and obstacles.contains(point_geom).any():
|
|
100
|
+
return gpd.GeoDataFrame() if return_gdf else Point()
|
|
101
|
+
|
|
102
|
+
point_buffer = point_geom.buffer(view_distance, resolution=32)
|
|
103
|
+
|
|
104
|
+
if len(obstacles) == 0:
|
|
105
|
+
full_vision_gdf = gpd.GeoDataFrame(geometry=[point_buffer], crs=local_crs).to_crs(original_crs)
|
|
106
|
+
return full_vision_gdf if return_gdf else full_vision_gdf.iloc[0].geometry
|
|
107
|
+
|
|
81
108
|
obstacles.reset_index(inplace=True, drop=True)
|
|
82
|
-
|
|
109
|
+
|
|
83
110
|
allowed_geom_types = ["MultiPolygon", "Polygon", "LineString", "MultiLineString"]
|
|
111
|
+
|
|
84
112
|
obstacles = obstacles[obstacles.geom_type.isin(allowed_geom_types)]
|
|
85
113
|
s = obstacles.intersects(point_buffer)
|
|
86
114
|
obstacles_in_buffer = obstacles.loc[s[s].index].geometry
|
|
@@ -98,26 +126,26 @@ def get_visibility_accurate(
|
|
|
98
126
|
+ [Point(line.coords[-1]) for line in buildings_lines_in_buffer.geometry]
|
|
99
127
|
)
|
|
100
128
|
|
|
101
|
-
max_dist = max(view_distance, buildings_in_buffer_points.distance(
|
|
129
|
+
max_dist = max(view_distance, buildings_in_buffer_points.distance(point_geom).max())
|
|
102
130
|
polygons = []
|
|
103
131
|
buildings_lines_in_buffer = gpd.GeoDataFrame(geometry=buildings_lines_in_buffer, crs=obstacles.crs).reset_index()
|
|
104
132
|
logger.debug("Calculation vis polygon")
|
|
105
133
|
while not buildings_lines_in_buffer.empty:
|
|
106
134
|
gdf_sindex = buildings_lines_in_buffer.sindex
|
|
107
135
|
# TODO check if 2 walls are nearest and use the widest angle between points
|
|
108
|
-
nearest_wall_sind = gdf_sindex.nearest(
|
|
136
|
+
nearest_wall_sind = gdf_sindex.nearest(point_geom, return_all=False, max_distance=max_dist)
|
|
109
137
|
nearest_wall = buildings_lines_in_buffer.loc[nearest_wall_sind[1]].iloc[0]
|
|
110
138
|
wall_points = [Point(coords) for coords in nearest_wall.geometry.coords]
|
|
111
139
|
|
|
112
140
|
# Calculate angles and sort by angle
|
|
113
141
|
points_with_angle = sorted(
|
|
114
|
-
[(pt, math.atan2(pt.y -
|
|
142
|
+
[(pt, math.atan2(pt.y - point_geom.y, pt.x - point_geom.x)) for pt in wall_points], key=lambda x: x[1]
|
|
115
143
|
)
|
|
116
144
|
delta_angle = 2 * math.pi + points_with_angle[0][1] - points_with_angle[-1][1]
|
|
117
145
|
if round(delta_angle, 10) == round(math.pi, 10):
|
|
118
146
|
wall_b_centroid = obstacles_in_buffer.loc[nearest_wall["index"]].centroid
|
|
119
|
-
p1 = get_point_from_a_thorough_b(
|
|
120
|
-
p2 = get_point_from_a_thorough_b(
|
|
147
|
+
p1 = get_point_from_a_thorough_b(point_geom, points_with_angle[0][0], max_dist)
|
|
148
|
+
p2 = get_point_from_a_thorough_b(point_geom, points_with_angle[1][0], max_dist)
|
|
121
149
|
polygon = LineString([p1, p2])
|
|
122
150
|
polygon = polygon.buffer(
|
|
123
151
|
distance=max_dist * point_side_of_line(polygon, wall_b_centroid), single_sided=True
|
|
@@ -126,8 +154,8 @@ def get_visibility_accurate(
|
|
|
126
154
|
if delta_angle > math.pi:
|
|
127
155
|
delta_angle = 2 * math.pi - delta_angle
|
|
128
156
|
a = math.sqrt((max_dist**2) * (1 + (math.tan(delta_angle / 2) ** 2)))
|
|
129
|
-
p1 = get_point_from_a_thorough_b(
|
|
130
|
-
p2 = get_point_from_a_thorough_b(
|
|
157
|
+
p1 = get_point_from_a_thorough_b(point_geom, points_with_angle[0][0], a)
|
|
158
|
+
p2 = get_point_from_a_thorough_b(point_geom, points_with_angle[-1][0], a)
|
|
131
159
|
polygon = Polygon([points_with_angle[0][0], p1, p2, points_with_angle[1][0]])
|
|
132
160
|
|
|
133
161
|
polygons.append(polygon)
|
|
@@ -146,15 +174,16 @@ def get_visibility_accurate(
|
|
|
146
174
|
if isinstance(res, MultiPolygon):
|
|
147
175
|
res = list(res.geoms)
|
|
148
176
|
for polygon in res:
|
|
149
|
-
if polygon.intersects(
|
|
177
|
+
if polygon.intersects(point_geom):
|
|
150
178
|
res = polygon
|
|
151
179
|
break
|
|
152
180
|
|
|
181
|
+
result_gdf = gpd.GeoDataFrame(geometry=[res], crs=local_crs).to_crs(original_crs)
|
|
153
182
|
if return_gdf:
|
|
154
|
-
|
|
155
|
-
|
|
183
|
+
return result_gdf
|
|
184
|
+
res = result_gdf.to_crs(original_crs).iloc[0].geometry
|
|
156
185
|
if return_max_view_dist:
|
|
157
|
-
return res, find_furthest_point(
|
|
186
|
+
return res, find_furthest_point(point_geom, res)
|
|
158
187
|
return res
|
|
159
188
|
|
|
160
189
|
|
|
@@ -184,29 +213,24 @@ def get_visibility(
|
|
|
184
213
|
This function provides a quicker but less accurate result compared to `get_visibility_accurate()`.
|
|
185
214
|
If accuracy is important, consider using `get_visibility_accurate()` instead.
|
|
186
215
|
"""
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
)
|
|
202
|
-
point_from = point_from.iloc[0].geometry
|
|
203
|
-
else:
|
|
204
|
-
obstacles = obstacles.copy()
|
|
205
|
-
point_buffer = point_from.buffer(view_distance, resolution=resolution)
|
|
216
|
+
|
|
217
|
+
obstacles = obstacles.copy()
|
|
218
|
+
|
|
219
|
+
point_geom, obstacles, original_crs, local_crs, return_gdf = _ensure_crs(point_from, obstacles)
|
|
220
|
+
print(return_gdf)
|
|
221
|
+
if len(obstacles) > 0 and obstacles.contains(point_geom).any():
|
|
222
|
+
return Polygon()
|
|
223
|
+
|
|
224
|
+
point_buffer = point_geom.buffer(view_distance, resolution=resolution)
|
|
225
|
+
|
|
226
|
+
if len(obstacles) == 0:
|
|
227
|
+
full_vision_gdf = gpd.GeoDataFrame(geometry=[point_buffer], crs=local_crs).to_crs(original_crs)
|
|
228
|
+
return full_vision_gdf if return_gdf else full_vision_gdf.iloc[0].geometry
|
|
229
|
+
|
|
206
230
|
s = obstacles.intersects(point_buffer)
|
|
207
231
|
buildings_in_buffer = obstacles.loc[s[s].index].reset_index(drop=True)
|
|
208
232
|
buffer_exterior_ = list(point_buffer.exterior.coords)
|
|
209
|
-
line_geometry = [LineString([
|
|
233
|
+
line_geometry = [LineString([point_geom, ext]) for ext in buffer_exterior_]
|
|
210
234
|
buffer_lines_gdf = gpd.GeoDataFrame(geometry=line_geometry)
|
|
211
235
|
united_buildings = buildings_in_buffer.union_all()
|
|
212
236
|
if united_buildings:
|
|
@@ -223,9 +247,8 @@ def get_visibility(
|
|
|
223
247
|
if united_buildings:
|
|
224
248
|
circuit = circuit.difference(united_buildings)
|
|
225
249
|
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
return circuit
|
|
250
|
+
result_gdf = gpd.GeoDataFrame(geometry=[circuit], crs=local_crs).to_crs(original_crs)
|
|
251
|
+
return result_gdf if return_gdf else result_gdf.iloc[0].geometry
|
|
229
252
|
|
|
230
253
|
|
|
231
254
|
def get_visibilities_from_points(
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
VERSION = "1.3.1"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{objectnat-1.3.1 → objectnat-1.3.3}/src/objectnat/methods/coverage_zones/radius_voronoi_coverage.py
RENAMED
|
File without changes
|
{objectnat-1.3.1 → objectnat-1.3.3}/src/objectnat/methods/coverage_zones/stepped_coverage.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|