voxcity 0.3.7__py3-none-any.whl → 0.3.9__py3-none-any.whl
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.
Potentially problematic release.
This version of voxcity might be problematic. Click here for more details.
- voxcity/geo/network.py +347 -0
- voxcity/sim/solar.py +1 -1
- {voxcity-0.3.7.dist-info → voxcity-0.3.9.dist-info}/METADATA +2 -1
- {voxcity-0.3.7.dist-info → voxcity-0.3.9.dist-info}/RECORD +8 -8
- {voxcity-0.3.7.dist-info → voxcity-0.3.9.dist-info}/AUTHORS.rst +0 -0
- {voxcity-0.3.7.dist-info → voxcity-0.3.9.dist-info}/LICENSE +0 -0
- {voxcity-0.3.7.dist-info → voxcity-0.3.9.dist-info}/WHEEL +0 -0
- {voxcity-0.3.7.dist-info → voxcity-0.3.9.dist-info}/top_level.txt +0 -0
voxcity/geo/network.py
CHANGED
|
@@ -6,6 +6,12 @@ import geopandas as gpd
|
|
|
6
6
|
from shapely.geometry import LineString
|
|
7
7
|
import networkx as nx
|
|
8
8
|
import osmnx as ox
|
|
9
|
+
import os
|
|
10
|
+
import shapely
|
|
11
|
+
from shapely.geometry import Point
|
|
12
|
+
from shapely.ops import transform
|
|
13
|
+
from pyproj import Transformer
|
|
14
|
+
from joblib import Parallel, delayed
|
|
9
15
|
|
|
10
16
|
from .grid import grid_to_geodataframe
|
|
11
17
|
|
|
@@ -191,4 +197,345 @@ def get_network_values(grid, rectangle_vertices, meshsize, value_name='value', *
|
|
|
191
197
|
# plt.title(f'Network {value_name} Analysis', pad=20)
|
|
192
198
|
plt.show()
|
|
193
199
|
|
|
200
|
+
return G, edge_gdf
|
|
201
|
+
|
|
202
|
+
# -------------------------------------------------------------------
|
|
203
|
+
# Optionally import your DEM helper
|
|
204
|
+
# -------------------------------------------------------------------
|
|
205
|
+
from voxcity.geo.grid import grid_to_geodataframe
|
|
206
|
+
|
|
207
|
+
# -------------------------------------------------------------------
|
|
208
|
+
# 1) Functions for interpolation, parallelization, and slope
|
|
209
|
+
# -------------------------------------------------------------------
|
|
210
|
+
|
|
211
|
+
def interpolate_points_along_line(line, interval):
|
|
212
|
+
"""
|
|
213
|
+
Interpolate points along a single LineString at a given interval (in meters).
|
|
214
|
+
If the line is shorter than `interval`, only start/end points are returned.
|
|
215
|
+
|
|
216
|
+
Parameters
|
|
217
|
+
----------
|
|
218
|
+
line : shapely.geometry.LineString
|
|
219
|
+
Edge geometry in EPSG:4326 (lon/lat).
|
|
220
|
+
interval : float
|
|
221
|
+
Distance in meters between interpolated points.
|
|
222
|
+
|
|
223
|
+
Returns
|
|
224
|
+
-------
|
|
225
|
+
list of shapely.geometry.Point
|
|
226
|
+
Points in EPSG:4326 along the line.
|
|
227
|
+
"""
|
|
228
|
+
if line.is_empty:
|
|
229
|
+
return []
|
|
230
|
+
|
|
231
|
+
# Transformers for metric distance calculations
|
|
232
|
+
project = Transformer.from_crs("EPSG:4326", "EPSG:3857", always_xy=True).transform
|
|
233
|
+
project_rev = Transformer.from_crs("EPSG:3857", "EPSG:4326", always_xy=True).transform
|
|
234
|
+
|
|
235
|
+
# Project line to Web Mercator
|
|
236
|
+
line_merc = shapely.ops.transform(project, line)
|
|
237
|
+
length_m = line_merc.length
|
|
238
|
+
if length_m == 0:
|
|
239
|
+
return [Point(line.coords[0])]
|
|
240
|
+
|
|
241
|
+
# If line is shorter than interval, just start & end
|
|
242
|
+
if length_m < interval:
|
|
243
|
+
return [Point(line.coords[0]), Point(line.coords[-1])]
|
|
244
|
+
|
|
245
|
+
# Otherwise, create distances
|
|
246
|
+
num_points = int(length_m // interval)
|
|
247
|
+
dists = [i * interval for i in range(num_points + 1)]
|
|
248
|
+
# Ensure end
|
|
249
|
+
if dists[-1] < length_m:
|
|
250
|
+
dists.append(length_m)
|
|
251
|
+
|
|
252
|
+
# Interpolate
|
|
253
|
+
points_merc = [line_merc.interpolate(d) for d in dists]
|
|
254
|
+
# Reproject back
|
|
255
|
+
return [shapely.ops.transform(project_rev, pt) for pt in points_merc]
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
def gather_interpolation_points(G, interval=10.0, n_jobs=1):
|
|
259
|
+
"""
|
|
260
|
+
Gather all interpolation points for each edge in the graph into a single GeoDataFrame.
|
|
261
|
+
Can be parallelized with `n_jobs`.
|
|
262
|
+
|
|
263
|
+
Parameters
|
|
264
|
+
----------
|
|
265
|
+
G : networkx.MultiDiGraph
|
|
266
|
+
OSMnx graph with 'geometry' attributes or x,y coordinates in the nodes.
|
|
267
|
+
interval : float, default=10.0
|
|
268
|
+
Interpolation distance interval in meters.
|
|
269
|
+
n_jobs : int, default=1
|
|
270
|
+
Number of parallel jobs (1 => no parallelization).
|
|
271
|
+
|
|
272
|
+
Returns
|
|
273
|
+
-------
|
|
274
|
+
gpd.GeoDataFrame
|
|
275
|
+
Columns: edge_id, index_in_edge, geometry (EPSG:4326).
|
|
276
|
+
"""
|
|
277
|
+
edges = list(G.edges(keys=True, data=True))
|
|
278
|
+
|
|
279
|
+
def process_edge(u, v, k, data, idx):
|
|
280
|
+
if 'geometry' in data:
|
|
281
|
+
line = data['geometry']
|
|
282
|
+
else:
|
|
283
|
+
# If no geometry, build from node coords
|
|
284
|
+
start_node = G.nodes[u]
|
|
285
|
+
end_node = G.nodes[v]
|
|
286
|
+
line = LineString([(start_node['x'], start_node['y']),
|
|
287
|
+
(end_node['x'], end_node['y'])])
|
|
288
|
+
|
|
289
|
+
pts = interpolate_points_along_line(line, interval)
|
|
290
|
+
df = pd.DataFrame({
|
|
291
|
+
'edge_id': [idx]*len(pts),
|
|
292
|
+
'index_in_edge': np.arange(len(pts)),
|
|
293
|
+
'geometry': pts
|
|
294
|
+
})
|
|
295
|
+
return df
|
|
296
|
+
|
|
297
|
+
# Parallel interpolation
|
|
298
|
+
results = Parallel(n_jobs=n_jobs, backend='threading')(
|
|
299
|
+
delayed(process_edge)(u, v, k, data, i)
|
|
300
|
+
for i, (u, v, k, data) in enumerate(edges)
|
|
301
|
+
)
|
|
302
|
+
|
|
303
|
+
all_points_df = pd.concat(results, ignore_index=True)
|
|
304
|
+
points_gdf = gpd.GeoDataFrame(all_points_df, geometry='geometry', crs="EPSG:4326")
|
|
305
|
+
return points_gdf
|
|
306
|
+
|
|
307
|
+
|
|
308
|
+
def fetch_elevations_for_points(points_gdf_3857, dem_gdf_3857, elevation_col='value'):
|
|
309
|
+
"""
|
|
310
|
+
Do a spatial join (nearest) in a projected CRS (EPSG:3857) to fetch DEM elevations.
|
|
311
|
+
|
|
312
|
+
Parameters
|
|
313
|
+
----------
|
|
314
|
+
points_gdf_3857 : gpd.GeoDataFrame
|
|
315
|
+
Interpolation points in EPSG:3857.
|
|
316
|
+
dem_gdf_3857 : gpd.GeoDataFrame
|
|
317
|
+
DEM polygons in EPSG:3857, must have `elevation_col`.
|
|
318
|
+
elevation_col : str, default='value'
|
|
319
|
+
Column with elevation values in dem_gdf_3857.
|
|
320
|
+
|
|
321
|
+
Returns
|
|
322
|
+
-------
|
|
323
|
+
gpd.GeoDataFrame
|
|
324
|
+
A copy of points_gdf_3857 with new column 'elevation'.
|
|
325
|
+
"""
|
|
326
|
+
joined = gpd.sjoin_nearest(
|
|
327
|
+
points_gdf_3857,
|
|
328
|
+
dem_gdf_3857[[elevation_col, 'geometry']].copy(),
|
|
329
|
+
how='left',
|
|
330
|
+
distance_col='dist_to_poly'
|
|
331
|
+
)
|
|
332
|
+
joined.rename(columns={elevation_col: 'elevation'}, inplace=True)
|
|
333
|
+
return joined
|
|
334
|
+
|
|
335
|
+
|
|
336
|
+
def compute_slope_for_group(df):
|
|
337
|
+
"""
|
|
338
|
+
Given a subset of points for a single edge, compute average slope between
|
|
339
|
+
consecutive points, using columns: geometry, elevation, index_in_edge.
|
|
340
|
+
|
|
341
|
+
Note: We assume df is already in EPSG:3857 for direct distance calculations.
|
|
342
|
+
"""
|
|
343
|
+
# Sort by position along the edge
|
|
344
|
+
df = df.sort_values("index_in_edge")
|
|
345
|
+
|
|
346
|
+
# Coordinates
|
|
347
|
+
xs = df.geometry.x.to_numpy()
|
|
348
|
+
ys = df.geometry.y.to_numpy()
|
|
349
|
+
elevs = df["elevation"].to_numpy()
|
|
350
|
+
|
|
351
|
+
# Differences
|
|
352
|
+
dx = np.diff(xs)
|
|
353
|
+
dy = np.diff(ys)
|
|
354
|
+
horizontal_dist = np.sqrt(dx**2 + dy**2)
|
|
355
|
+
elev_diff = np.diff(elevs)
|
|
356
|
+
|
|
357
|
+
# Slope in %
|
|
358
|
+
valid_mask = horizontal_dist > 0
|
|
359
|
+
slopes = (np.abs(elev_diff[valid_mask]) / horizontal_dist[valid_mask]) * 100
|
|
360
|
+
|
|
361
|
+
if len(slopes) == 0:
|
|
362
|
+
return np.nan
|
|
363
|
+
return slopes.mean()
|
|
364
|
+
|
|
365
|
+
|
|
366
|
+
def calculate_edge_slopes_from_join(joined_points_gdf, n_edges):
|
|
367
|
+
"""
|
|
368
|
+
Calculate average slopes for each edge by grouping joined points.
|
|
369
|
+
|
|
370
|
+
Parameters
|
|
371
|
+
----------
|
|
372
|
+
joined_points_gdf : gpd.GeoDataFrame
|
|
373
|
+
Must have columns: edge_id, index_in_edge, elevation, geometry (EPSG:3857).
|
|
374
|
+
n_edges : int
|
|
375
|
+
Number of edges from the graph.
|
|
376
|
+
|
|
377
|
+
Returns
|
|
378
|
+
-------
|
|
379
|
+
dict
|
|
380
|
+
edge_id -> average slope (in %).
|
|
381
|
+
"""
|
|
382
|
+
# We'll group by edge_id, ignoring the group columns in apply (pandas >= 2.1).
|
|
383
|
+
# If your pandas version < 2.1, just do a column subset after groupby.
|
|
384
|
+
# E.g. .groupby("edge_id", group_keys=False)[["geometry","elevation","index_in_edge"]]...
|
|
385
|
+
grouped = joined_points_gdf.groupby("edge_id", group_keys=False)
|
|
386
|
+
results = grouped[["geometry", "elevation", "index_in_edge"]].apply(compute_slope_for_group)
|
|
387
|
+
|
|
388
|
+
# Convert series -> dict
|
|
389
|
+
slope_dict = results.to_dict()
|
|
390
|
+
|
|
391
|
+
# Fill any missing edge IDs with NaN
|
|
392
|
+
for i in range(n_edges):
|
|
393
|
+
if i not in slope_dict:
|
|
394
|
+
slope_dict[i] = np.nan
|
|
395
|
+
|
|
396
|
+
return slope_dict
|
|
397
|
+
|
|
398
|
+
# -------------------------------------------------------------------
|
|
399
|
+
# 2) Main function to analyze network slopes
|
|
400
|
+
# -------------------------------------------------------------------
|
|
401
|
+
|
|
402
|
+
def analyze_network_slopes(
|
|
403
|
+
dem_grid,
|
|
404
|
+
meshsize,
|
|
405
|
+
value_name='slope',
|
|
406
|
+
interval=10.0,
|
|
407
|
+
n_jobs=1,
|
|
408
|
+
**kwargs
|
|
409
|
+
):
|
|
410
|
+
"""
|
|
411
|
+
Analyze and visualize network slopes based on DEM data, using vectorized + parallel methods.
|
|
412
|
+
|
|
413
|
+
Parameters
|
|
414
|
+
----------
|
|
415
|
+
dem_grid : array-like
|
|
416
|
+
DEM grid data.
|
|
417
|
+
meshsize : float
|
|
418
|
+
Mesh grid size.
|
|
419
|
+
value_name : str, default='slope'
|
|
420
|
+
Column name for slopes assigned to each edge.
|
|
421
|
+
interval : float, default=10.0
|
|
422
|
+
Interpolation distance in meters.
|
|
423
|
+
n_jobs : int, default=1
|
|
424
|
+
Parallelization for edge interpolation (1 => sequential).
|
|
425
|
+
**kwargs : dict
|
|
426
|
+
Additional parameters:
|
|
427
|
+
- rectangle_vertices : list of (x, y) in EPSG:4326
|
|
428
|
+
- network_type : str, default='walk'
|
|
429
|
+
- vis_graph : bool, default=True
|
|
430
|
+
- colormap, vmin, vmax, edge_width, fig_size, zoom, basemap_style, alpha
|
|
431
|
+
- output_directory, output_file_name
|
|
432
|
+
"""
|
|
433
|
+
defaults = {
|
|
434
|
+
'rectangle_vertices': None,
|
|
435
|
+
'network_type': 'walk',
|
|
436
|
+
'vis_graph': True,
|
|
437
|
+
'colormap': 'viridis',
|
|
438
|
+
'vmin': None,
|
|
439
|
+
'vmax': None,
|
|
440
|
+
'edge_width': 1,
|
|
441
|
+
'fig_size': (15, 15),
|
|
442
|
+
'zoom': 16,
|
|
443
|
+
'basemap_style': ctx.providers.CartoDB.Positron,
|
|
444
|
+
'output_directory': None,
|
|
445
|
+
'output_file_name': 'network_slopes',
|
|
446
|
+
'alpha': 1.0
|
|
447
|
+
}
|
|
448
|
+
settings = {**defaults, **kwargs}
|
|
449
|
+
|
|
450
|
+
# Validate bounding box
|
|
451
|
+
if settings['rectangle_vertices'] is None:
|
|
452
|
+
raise ValueError("Must supply 'rectangle_vertices' in kwargs.")
|
|
453
|
+
|
|
454
|
+
# 1) Build DEM GeoDataFrame in EPSG:4326
|
|
455
|
+
dem_gdf = grid_to_geodataframe(dem_grid, settings['rectangle_vertices'], meshsize)
|
|
456
|
+
if dem_gdf.crs is None:
|
|
457
|
+
dem_gdf.set_crs(epsg=4326, inplace=True)
|
|
458
|
+
|
|
459
|
+
# 2) Download bounding box from rectangle_vertices
|
|
460
|
+
north, south = settings['rectangle_vertices'][1][1], settings['rectangle_vertices'][0][1]
|
|
461
|
+
east, west = settings['rectangle_vertices'][2][0], settings['rectangle_vertices'][0][0]
|
|
462
|
+
bbox = (west, south, east, north)
|
|
463
|
+
|
|
464
|
+
G = ox.graph.graph_from_bbox(
|
|
465
|
+
bbox=bbox,
|
|
466
|
+
network_type=settings['network_type'],
|
|
467
|
+
simplify=True
|
|
468
|
+
)
|
|
469
|
+
|
|
470
|
+
# 3) Interpolate points along edges (EPSG:4326)
|
|
471
|
+
points_gdf_4326 = gather_interpolation_points(G, interval=interval, n_jobs=n_jobs)
|
|
472
|
+
|
|
473
|
+
# 4) Reproject DEM + Points to EPSG:3857 for correct distance operations
|
|
474
|
+
dem_gdf_3857 = dem_gdf.to_crs(epsg=3857)
|
|
475
|
+
points_gdf_3857 = points_gdf_4326.to_crs(epsg=3857)
|
|
476
|
+
|
|
477
|
+
# 5) Perform spatial join to get elevations
|
|
478
|
+
joined_points_3857 = fetch_elevations_for_points(points_gdf_3857, dem_gdf_3857, elevation_col='value')
|
|
479
|
+
|
|
480
|
+
# 6) Compute slopes for each edge
|
|
481
|
+
n_edges = len(list(G.edges(keys=True)))
|
|
482
|
+
slope_dict = calculate_edge_slopes_from_join(joined_points_3857, n_edges)
|
|
483
|
+
|
|
484
|
+
# 7) Assign slopes back to G
|
|
485
|
+
edges = list(G.edges(keys=True, data=True))
|
|
486
|
+
edge_slopes = {}
|
|
487
|
+
for i, (u, v, k, data) in enumerate(edges):
|
|
488
|
+
edge_slopes[(u, v, k)] = slope_dict.get(i, np.nan)
|
|
489
|
+
nx.set_edge_attributes(G, edge_slopes, name=value_name)
|
|
490
|
+
|
|
491
|
+
# 8) Build an edge GeoDataFrame in EPSG:4326
|
|
492
|
+
edges_with_values = []
|
|
493
|
+
for (u, v, k, data), edge_id in zip(edges, range(len(edges))):
|
|
494
|
+
if 'geometry' in data:
|
|
495
|
+
geom = data['geometry']
|
|
496
|
+
else:
|
|
497
|
+
start_node = G.nodes[u]
|
|
498
|
+
end_node = G.nodes[v]
|
|
499
|
+
geom = LineString([(start_node['x'], start_node['y']),
|
|
500
|
+
(end_node['x'], end_node['y'])])
|
|
501
|
+
|
|
502
|
+
edges_with_values.append({
|
|
503
|
+
'u': u,
|
|
504
|
+
'v': v,
|
|
505
|
+
'key': k,
|
|
506
|
+
'geometry': geom,
|
|
507
|
+
value_name: slope_dict.get(edge_id, np.nan)
|
|
508
|
+
})
|
|
509
|
+
|
|
510
|
+
edge_gdf = gpd.GeoDataFrame(edges_with_values, crs="EPSG:4326")
|
|
511
|
+
|
|
512
|
+
# 9) Save output if requested
|
|
513
|
+
if settings['output_directory']:
|
|
514
|
+
os.makedirs(settings['output_directory'], exist_ok=True)
|
|
515
|
+
out_path = os.path.join(
|
|
516
|
+
settings['output_directory'],
|
|
517
|
+
f"{settings['output_file_name']}.gpkg"
|
|
518
|
+
)
|
|
519
|
+
edge_gdf.to_file(out_path, driver="GPKG")
|
|
520
|
+
|
|
521
|
+
# 10) Visualization
|
|
522
|
+
if settings['vis_graph']:
|
|
523
|
+
edge_gdf_web = edge_gdf.to_crs(epsg=3857)
|
|
524
|
+
fig, ax = plt.subplots(figsize=settings['fig_size'])
|
|
525
|
+
edge_gdf_web.plot(
|
|
526
|
+
column=value_name,
|
|
527
|
+
ax=ax,
|
|
528
|
+
cmap=settings['colormap'],
|
|
529
|
+
legend=True,
|
|
530
|
+
vmin=settings['vmin'],
|
|
531
|
+
vmax=settings['vmax'],
|
|
532
|
+
linewidth=settings['edge_width'],
|
|
533
|
+
alpha=settings['alpha'],
|
|
534
|
+
legend_kwds={'label': f"{value_name} (%)"}
|
|
535
|
+
)
|
|
536
|
+
ctx.add_basemap(ax, source=settings['basemap_style'], zoom=settings['zoom'])
|
|
537
|
+
ax.set_axis_off()
|
|
538
|
+
plt.title(f'Network {value_name} Analysis', pad=20)
|
|
539
|
+
plt.show()
|
|
540
|
+
|
|
194
541
|
return G, edge_gdf
|
voxcity/sim/solar.py
CHANGED
|
@@ -750,7 +750,7 @@ def get_global_solar_irradiance_using_epw(
|
|
|
750
750
|
end_hour = kwargs.get("end_hour", 23) # Default to 11 PM
|
|
751
751
|
|
|
752
752
|
# Filter dataframe for specified hours
|
|
753
|
-
df_filtered = df[df.index.hour
|
|
753
|
+
df_filtered = df[(df.index.hour >= start_hour) & (df.index.hour <= end_hour)]
|
|
754
754
|
|
|
755
755
|
solar_map = get_cumulative_global_solar_irradiance(
|
|
756
756
|
voxel_data,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: voxcity
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.9
|
|
4
4
|
Summary: voxcity is an easy and one-stop tool to output 3d city models for microclimate simulation by integrating multiple geospatial open-data
|
|
5
5
|
Author-email: Kunihiko Fujiwara <kunihiko@nus.edu.sg>
|
|
6
6
|
Maintainer-email: Kunihiko Fujiwara <kunihiko@nus.edu.sg>
|
|
@@ -49,6 +49,7 @@ Requires-Dist: protobuf==3.20.3
|
|
|
49
49
|
Requires-Dist: timezonefinder
|
|
50
50
|
Requires-Dist: astral
|
|
51
51
|
Requires-Dist: osmnx
|
|
52
|
+
Requires-Dist: joblib
|
|
52
53
|
Provides-Extra: dev
|
|
53
54
|
Requires-Dist: coverage; extra == "dev"
|
|
54
55
|
Requires-Dist: mypy; extra == "dev"
|
|
@@ -17,10 +17,10 @@ voxcity/file/obj.py,sha256=oW-kPoZj53nfmO9tXP3Wvizq6Kkjh-QQR8UBexRuMiI,21609
|
|
|
17
17
|
voxcity/geo/__init_.py,sha256=AZYQxK1zY1M_mDT1HmgcdVI86OAtwK7CNo3AOScLHco,88
|
|
18
18
|
voxcity/geo/draw.py,sha256=roljWXyqYdsWYkmb-5_WNxrJrfV5lnAt8uZblCCo_3Q,13555
|
|
19
19
|
voxcity/geo/grid.py,sha256=_MzO-Cu2GhlP9nuCql6f1pfbU2_OAL27aQ_zCj1u_zk,36288
|
|
20
|
-
voxcity/geo/network.py,sha256=
|
|
20
|
+
voxcity/geo/network.py,sha256=lcDLgsmPb9MyFeQlJwscXl7_9JCG7TIlbAu19MPf2m8,18846
|
|
21
21
|
voxcity/geo/utils.py,sha256=1BRHp-DDeOA8HG8jplY7Eo75G3oXkVGL6DGONL4BA8A,19815
|
|
22
22
|
voxcity/sim/__init_.py,sha256=APdkcdaovj0v_RPOaA4SBvFUKT2RM7Hxuuz3Sux4gCo,65
|
|
23
|
-
voxcity/sim/solar.py,sha256=
|
|
23
|
+
voxcity/sim/solar.py,sha256=f9GLANRnEVj7NseSETVRDvTD_t_Bn9hC6dJUV5Ak_cU,31799
|
|
24
24
|
voxcity/sim/utils.py,sha256=sEYBB2-hLJxTiXQps1_-Fi7t1HN3-1OPOvBCWtgIisA,130
|
|
25
25
|
voxcity/sim/view.py,sha256=oq6G-f0Tn-KT0vjYNJfucmOIrv1GNjljhA-zvU4nNoA,36668
|
|
26
26
|
voxcity/utils/__init_.py,sha256=nLYrj2huBbDBNMqfchCwexGP8Tlt9O_XluVDG7MoFkw,98
|
|
@@ -28,9 +28,9 @@ voxcity/utils/lc.py,sha256=RwPd-VY3POV3gTrBhM7TubgGb9MCd3nVah_G8iUEF7k,11562
|
|
|
28
28
|
voxcity/utils/material.py,sha256=Vt3IID5Ft54HNJcEC4zi31BCPqi_687X3CSp7rXaRVY,5907
|
|
29
29
|
voxcity/utils/visualization.py,sha256=FNBMN0V5IPuAdqvLHnqSGYqNS7jWesg0ZADEtsUtl0A,31925
|
|
30
30
|
voxcity/utils/weather.py,sha256=P6s1y_EstBL1OGP_MR_6u3vr-t6Uawg8uDckJnoI7FI,21482
|
|
31
|
-
voxcity-0.3.
|
|
32
|
-
voxcity-0.3.
|
|
33
|
-
voxcity-0.3.
|
|
34
|
-
voxcity-0.3.
|
|
35
|
-
voxcity-0.3.
|
|
36
|
-
voxcity-0.3.
|
|
31
|
+
voxcity-0.3.9.dist-info/AUTHORS.rst,sha256=m82vkI5QokEGdcHof2OxK39lf81w1P58kG9ZNNAKS9U,175
|
|
32
|
+
voxcity-0.3.9.dist-info/LICENSE,sha256=-hGliOFiwUrUSoZiB5WF90xXGqinKyqiDI2t6hrnam8,1087
|
|
33
|
+
voxcity-0.3.9.dist-info/METADATA,sha256=wbktfEaoqiafDk3sX8gZxM2m6-pYxXDkGI5daZbU-S4,25110
|
|
34
|
+
voxcity-0.3.9.dist-info/WHEEL,sha256=A3WOREP4zgxI0fKrHUG8DC8013e3dK3n7a6HDbcEIwE,91
|
|
35
|
+
voxcity-0.3.9.dist-info/top_level.txt,sha256=00b2U-LKfDllt6RL1R33MXie5MvxzUFye0NGD96t_8I,8
|
|
36
|
+
voxcity-0.3.9.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|