voxcity 0.5.26__py3-none-any.whl → 0.5.28__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/downloader/osm.py +1038 -1040
- voxcity/exporter/__init__.py +2 -1
- voxcity/exporter/cityles.py +368 -0
- voxcity/generator.py +55 -35
- voxcity/geoprocessor/draw.py +276 -3
- voxcity/geoprocessor/grid.py +5 -3
- {voxcity-0.5.26.dist-info → voxcity-0.5.28.dist-info}/METADATA +1 -1
- {voxcity-0.5.26.dist-info → voxcity-0.5.28.dist-info}/RECORD +12 -11
- {voxcity-0.5.26.dist-info → voxcity-0.5.28.dist-info}/WHEEL +0 -0
- {voxcity-0.5.26.dist-info → voxcity-0.5.28.dist-info}/licenses/AUTHORS.rst +0 -0
- {voxcity-0.5.26.dist-info → voxcity-0.5.28.dist-info}/licenses/LICENSE +0 -0
- {voxcity-0.5.26.dist-info → voxcity-0.5.28.dist-info}/top_level.txt +0 -0
voxcity/geoprocessor/draw.py
CHANGED
|
@@ -25,10 +25,19 @@ Dependencies:
|
|
|
25
25
|
|
|
26
26
|
import math
|
|
27
27
|
from pyproj import Proj, transform
|
|
28
|
-
from ipyleaflet import
|
|
29
|
-
|
|
28
|
+
from ipyleaflet import (
|
|
29
|
+
Map,
|
|
30
|
+
DrawControl,
|
|
31
|
+
Rectangle,
|
|
32
|
+
Polygon as LeafletPolygon,
|
|
33
|
+
WidgetControl
|
|
34
|
+
)
|
|
30
35
|
from geopy import distance
|
|
31
36
|
import shapely.geometry as geom
|
|
37
|
+
import geopandas as gpd
|
|
38
|
+
from ipywidgets import VBox, HBox, Button, FloatText, Label, Output, HTML
|
|
39
|
+
import pandas as pd
|
|
40
|
+
from IPython.display import display, clear_output
|
|
32
41
|
|
|
33
42
|
from .utils import get_coordinates_from_cityname
|
|
34
43
|
|
|
@@ -484,4 +493,268 @@ def display_buildings_and_draw_polygon(building_gdf=None, rectangle_vertices=Non
|
|
|
484
493
|
draw_control.on_draw(handle_draw)
|
|
485
494
|
m.add_control(draw_control)
|
|
486
495
|
|
|
487
|
-
return m, drawn_polygon_vertices
|
|
496
|
+
return m, drawn_polygon_vertices
|
|
497
|
+
|
|
498
|
+
def draw_additional_buildings(building_gdf=None, initial_center=None, zoom=17):
|
|
499
|
+
"""
|
|
500
|
+
Creates an interactive map for drawing building footprints with height input.
|
|
501
|
+
|
|
502
|
+
This function provides an interface for users to:
|
|
503
|
+
1. Draw building footprints on an interactive map
|
|
504
|
+
2. Set building height values through a UI widget
|
|
505
|
+
3. Add new buildings to the existing building_gdf
|
|
506
|
+
|
|
507
|
+
The workflow is:
|
|
508
|
+
- User draws a polygon on the map
|
|
509
|
+
- Height input widget appears
|
|
510
|
+
- User enters height and clicks "Add Building"
|
|
511
|
+
- Building is added to GeoDataFrame and displayed on map
|
|
512
|
+
|
|
513
|
+
Args:
|
|
514
|
+
building_gdf (GeoDataFrame, optional): Existing building footprints to display.
|
|
515
|
+
If None, creates a new empty GeoDataFrame.
|
|
516
|
+
Must have 'geometry' column and optionally 'height' column.
|
|
517
|
+
initial_center (tuple, optional): Initial map center as (lon, lat).
|
|
518
|
+
If None, centers on existing buildings or defaults to (-100, 40).
|
|
519
|
+
zoom (int): Initial zoom level (default=17).
|
|
520
|
+
|
|
521
|
+
Returns:
|
|
522
|
+
tuple: (map_object, updated_building_gdf)
|
|
523
|
+
- map_object: ipyleaflet Map instance with drawing controls
|
|
524
|
+
- updated_building_gdf: GeoDataFrame that automatically updates when buildings are added
|
|
525
|
+
|
|
526
|
+
Example:
|
|
527
|
+
>>> # Start with empty buildings
|
|
528
|
+
>>> m, buildings = draw_additional_buildings()
|
|
529
|
+
>>> # Draw buildings on the map...
|
|
530
|
+
>>> print(buildings) # Will contain all drawn buildings
|
|
531
|
+
"""
|
|
532
|
+
|
|
533
|
+
# Initialize or copy the building GeoDataFrame
|
|
534
|
+
if building_gdf is None:
|
|
535
|
+
# Create empty GeoDataFrame with required columns
|
|
536
|
+
updated_gdf = gpd.GeoDataFrame(
|
|
537
|
+
columns=['geometry', 'height', 'building_id'],
|
|
538
|
+
crs='EPSG:4326'
|
|
539
|
+
)
|
|
540
|
+
else:
|
|
541
|
+
# Make a copy to avoid modifying the original
|
|
542
|
+
updated_gdf = building_gdf.copy()
|
|
543
|
+
if 'height' not in updated_gdf.columns:
|
|
544
|
+
updated_gdf['height'] = 10.0 # Default height
|
|
545
|
+
if 'building_id' not in updated_gdf.columns:
|
|
546
|
+
updated_gdf['building_id'] = range(len(updated_gdf))
|
|
547
|
+
|
|
548
|
+
# Determine map center
|
|
549
|
+
if initial_center is not None:
|
|
550
|
+
center_lon, center_lat = initial_center
|
|
551
|
+
elif updated_gdf is not None and len(updated_gdf) > 0:
|
|
552
|
+
bounds = updated_gdf.total_bounds
|
|
553
|
+
min_lon, min_lat, max_lon, max_lat = bounds
|
|
554
|
+
center_lon = (min_lon + max_lon) / 2
|
|
555
|
+
center_lat = (min_lat + max_lat) / 2
|
|
556
|
+
else:
|
|
557
|
+
center_lon, center_lat = -100.0, 40.0
|
|
558
|
+
|
|
559
|
+
# Create the map
|
|
560
|
+
m = Map(center=(center_lat, center_lon), zoom=zoom, scroll_wheel_zoom=True)
|
|
561
|
+
|
|
562
|
+
# Display existing buildings
|
|
563
|
+
building_layers = {}
|
|
564
|
+
for idx, row in updated_gdf.iterrows():
|
|
565
|
+
if isinstance(row.geometry, geom.Polygon):
|
|
566
|
+
coords = list(row.geometry.exterior.coords)
|
|
567
|
+
lat_lon_coords = [(c[1], c[0]) for c in coords[:-1]]
|
|
568
|
+
|
|
569
|
+
height = row.get('height', 10.0)
|
|
570
|
+
bldg_layer = LeafletPolygon(
|
|
571
|
+
locations=lat_lon_coords,
|
|
572
|
+
color="blue",
|
|
573
|
+
fill_color="blue",
|
|
574
|
+
fill_opacity=0.3,
|
|
575
|
+
weight=2,
|
|
576
|
+
popup=HTML(f"<b>Building ID:</b> {row.get('building_id', idx)}<br>"
|
|
577
|
+
f"<b>Height:</b> {height}m")
|
|
578
|
+
)
|
|
579
|
+
m.add_layer(bldg_layer)
|
|
580
|
+
building_layers[idx] = bldg_layer
|
|
581
|
+
|
|
582
|
+
# Create UI widgets
|
|
583
|
+
height_input = FloatText(
|
|
584
|
+
value=10.0,
|
|
585
|
+
description='Height (m):',
|
|
586
|
+
disabled=False,
|
|
587
|
+
style={'description_width': 'initial'}
|
|
588
|
+
)
|
|
589
|
+
|
|
590
|
+
add_button = Button(
|
|
591
|
+
description='Add Building',
|
|
592
|
+
button_style='success',
|
|
593
|
+
disabled=True
|
|
594
|
+
)
|
|
595
|
+
|
|
596
|
+
clear_button = Button(
|
|
597
|
+
description='Clear Drawing',
|
|
598
|
+
button_style='warning',
|
|
599
|
+
disabled=True
|
|
600
|
+
)
|
|
601
|
+
|
|
602
|
+
status_output = Output()
|
|
603
|
+
|
|
604
|
+
# Create control panel
|
|
605
|
+
control_panel = VBox([
|
|
606
|
+
HTML("<h3>Draw Building Tool</h3>"),
|
|
607
|
+
HTML("<p>1. Draw a polygon on the map<br>2. Set height<br>3. Click 'Add Building'</p>"),
|
|
608
|
+
height_input,
|
|
609
|
+
HBox([add_button, clear_button]),
|
|
610
|
+
status_output
|
|
611
|
+
])
|
|
612
|
+
|
|
613
|
+
# Add control panel to map
|
|
614
|
+
widget_control = WidgetControl(widget=control_panel, position='topright')
|
|
615
|
+
m.add_control(widget_control)
|
|
616
|
+
|
|
617
|
+
# Store the current drawn polygon
|
|
618
|
+
current_polygon = {'vertices': [], 'layer': None}
|
|
619
|
+
|
|
620
|
+
# Drawing control
|
|
621
|
+
draw_control = DrawControl(
|
|
622
|
+
polygon={
|
|
623
|
+
"shapeOptions": {
|
|
624
|
+
"color": "red",
|
|
625
|
+
"fillColor": "red",
|
|
626
|
+
"fillOpacity": 0.3,
|
|
627
|
+
"weight": 3
|
|
628
|
+
}
|
|
629
|
+
},
|
|
630
|
+
rectangle={},
|
|
631
|
+
circle={},
|
|
632
|
+
circlemarker={},
|
|
633
|
+
polyline={},
|
|
634
|
+
marker={}
|
|
635
|
+
)
|
|
636
|
+
|
|
637
|
+
def handle_draw(self, action, geo_json):
|
|
638
|
+
"""Handle polygon drawing events"""
|
|
639
|
+
with status_output:
|
|
640
|
+
clear_output()
|
|
641
|
+
|
|
642
|
+
if action == 'created' and geo_json['geometry']['type'] == 'Polygon':
|
|
643
|
+
# Store vertices
|
|
644
|
+
coordinates = geo_json['geometry']['coordinates'][0]
|
|
645
|
+
current_polygon['vertices'] = [(coord[0], coord[1]) for coord in coordinates[:-1]]
|
|
646
|
+
|
|
647
|
+
# Enable buttons
|
|
648
|
+
add_button.disabled = False
|
|
649
|
+
clear_button.disabled = False
|
|
650
|
+
|
|
651
|
+
with status_output:
|
|
652
|
+
print(f"Polygon drawn with {len(current_polygon['vertices'])} vertices")
|
|
653
|
+
print("Set height and click 'Add Building'")
|
|
654
|
+
|
|
655
|
+
def add_building_click(b):
|
|
656
|
+
"""Handle add building button click"""
|
|
657
|
+
# Use nonlocal to modify the outer scope variable
|
|
658
|
+
nonlocal updated_gdf
|
|
659
|
+
|
|
660
|
+
with status_output:
|
|
661
|
+
clear_output()
|
|
662
|
+
|
|
663
|
+
if current_polygon['vertices']:
|
|
664
|
+
# Create polygon geometry
|
|
665
|
+
polygon = geom.Polygon(current_polygon['vertices'])
|
|
666
|
+
|
|
667
|
+
# Get next building ID
|
|
668
|
+
if len(updated_gdf) > 0:
|
|
669
|
+
next_id = int(updated_gdf['building_id'].max() + 1)
|
|
670
|
+
else:
|
|
671
|
+
next_id = 1
|
|
672
|
+
|
|
673
|
+
# Create new row data
|
|
674
|
+
new_row_data = {
|
|
675
|
+
'geometry': polygon,
|
|
676
|
+
'height': float(height_input.value),
|
|
677
|
+
'building_id': next_id
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
# Add any additional columns
|
|
681
|
+
for col in updated_gdf.columns:
|
|
682
|
+
if col not in new_row_data:
|
|
683
|
+
new_row_data[col] = None
|
|
684
|
+
|
|
685
|
+
# Append the new building in-place
|
|
686
|
+
new_index = len(updated_gdf)
|
|
687
|
+
updated_gdf.loc[new_index] = new_row_data
|
|
688
|
+
|
|
689
|
+
# Add to map
|
|
690
|
+
coords = list(polygon.exterior.coords)
|
|
691
|
+
lat_lon_coords = [(c[1], c[0]) for c in coords[:-1]]
|
|
692
|
+
|
|
693
|
+
new_layer = LeafletPolygon(
|
|
694
|
+
locations=lat_lon_coords,
|
|
695
|
+
color="blue",
|
|
696
|
+
fill_color="blue",
|
|
697
|
+
fill_opacity=0.3,
|
|
698
|
+
weight=2,
|
|
699
|
+
popup=HTML(f"<b>Building ID:</b> {next_id}<br>"
|
|
700
|
+
f"<b>Height:</b> {height_input.value}m")
|
|
701
|
+
)
|
|
702
|
+
m.add_layer(new_layer)
|
|
703
|
+
|
|
704
|
+
# Clear drawing
|
|
705
|
+
draw_control.clear()
|
|
706
|
+
current_polygon['vertices'] = []
|
|
707
|
+
add_button.disabled = True
|
|
708
|
+
clear_button.disabled = True
|
|
709
|
+
|
|
710
|
+
print(f"Building {next_id} added successfully!")
|
|
711
|
+
print(f"Height: {height_input.value}m")
|
|
712
|
+
print(f"Total buildings: {len(updated_gdf)}")
|
|
713
|
+
|
|
714
|
+
def clear_drawing_click(b):
|
|
715
|
+
"""Handle clear drawing button click"""
|
|
716
|
+
with status_output:
|
|
717
|
+
clear_output()
|
|
718
|
+
draw_control.clear()
|
|
719
|
+
current_polygon['vertices'] = []
|
|
720
|
+
add_button.disabled = True
|
|
721
|
+
clear_button.disabled = True
|
|
722
|
+
print("Drawing cleared")
|
|
723
|
+
|
|
724
|
+
# Connect event handlers
|
|
725
|
+
draw_control.on_draw(handle_draw)
|
|
726
|
+
add_button.on_click(add_building_click)
|
|
727
|
+
clear_button.on_click(clear_drawing_click)
|
|
728
|
+
|
|
729
|
+
# Add draw control to map
|
|
730
|
+
m.add_control(draw_control)
|
|
731
|
+
|
|
732
|
+
# Display initial status
|
|
733
|
+
with status_output:
|
|
734
|
+
print(f"Total buildings loaded: {len(updated_gdf)}")
|
|
735
|
+
print("Draw a polygon to add a new building")
|
|
736
|
+
|
|
737
|
+
return m, updated_gdf
|
|
738
|
+
|
|
739
|
+
|
|
740
|
+
# Simple convenience function
|
|
741
|
+
def create_building_editor(building_gdf=None, initial_center=None, zoom=17):
|
|
742
|
+
"""
|
|
743
|
+
Creates and displays an interactive building editor.
|
|
744
|
+
|
|
745
|
+
Args:
|
|
746
|
+
building_gdf: Existing buildings GeoDataFrame (optional)
|
|
747
|
+
initial_center: Map center as (lon, lat) tuple (optional)
|
|
748
|
+
zoom: Initial zoom level (default=17)
|
|
749
|
+
|
|
750
|
+
Returns:
|
|
751
|
+
GeoDataFrame: The building GeoDataFrame that automatically updates
|
|
752
|
+
|
|
753
|
+
Example:
|
|
754
|
+
>>> buildings = create_building_editor()
|
|
755
|
+
>>> # Draw buildings on the displayed map
|
|
756
|
+
>>> print(buildings) # Automatically contains all drawn buildings
|
|
757
|
+
"""
|
|
758
|
+
m, gdf = draw_additional_buildings(building_gdf, initial_center, zoom)
|
|
759
|
+
display(m)
|
|
760
|
+
return gdf
|
voxcity/geoprocessor/grid.py
CHANGED
|
@@ -412,7 +412,7 @@ def create_land_cover_grid_from_geotiff_polygon(tiff_path, mesh_size, land_cover
|
|
|
412
412
|
# Flip grid vertically to match geographic orientation
|
|
413
413
|
return np.flipud(grid)
|
|
414
414
|
|
|
415
|
-
def create_land_cover_grid_from_gdf_polygon(gdf, meshsize, source, rectangle_vertices):
|
|
415
|
+
def create_land_cover_grid_from_gdf_polygon(gdf, meshsize, source, rectangle_vertices, default_class='Developed space'):
|
|
416
416
|
"""Create a grid of land cover classes from GeoDataFrame polygon data.
|
|
417
417
|
|
|
418
418
|
Args:
|
|
@@ -420,6 +420,8 @@ def create_land_cover_grid_from_gdf_polygon(gdf, meshsize, source, rectangle_ver
|
|
|
420
420
|
meshsize (float): Size of each grid cell in meters
|
|
421
421
|
source (str): Source of the land cover data to determine class priorities
|
|
422
422
|
rectangle_vertices (list): List of 4 (lon,lat) coordinate pairs defining the rectangle bounds
|
|
423
|
+
default_class (str, optional): Default land cover class for cells with no intersecting polygons.
|
|
424
|
+
Defaults to 'Developed space'.
|
|
423
425
|
|
|
424
426
|
Returns:
|
|
425
427
|
numpy.ndarray: 2D grid of land cover classes as strings
|
|
@@ -466,7 +468,7 @@ def create_land_cover_grid_from_gdf_polygon(gdf, meshsize, source, rectangle_ver
|
|
|
466
468
|
print(f"Adjusted mesh size: {adjusted_meshsize}")
|
|
467
469
|
|
|
468
470
|
# Initialize grid with default land cover class
|
|
469
|
-
grid = np.full(grid_size,
|
|
471
|
+
grid = np.full(grid_size, default_class, dtype=object)
|
|
470
472
|
|
|
471
473
|
# Calculate bounding box for spatial indexing
|
|
472
474
|
extent = [min(coord[1] for coord in rectangle_vertices), max(coord[1] for coord in rectangle_vertices),
|
|
@@ -485,7 +487,7 @@ def create_land_cover_grid_from_gdf_polygon(gdf, meshsize, source, rectangle_ver
|
|
|
485
487
|
# Iterate through each grid cell
|
|
486
488
|
for i in range(grid_size[0]):
|
|
487
489
|
for j in range(grid_size[1]):
|
|
488
|
-
land_cover_class =
|
|
490
|
+
land_cover_class = default_class
|
|
489
491
|
cell = create_cell_polygon(origin, i, j, adjusted_meshsize, u_vec, v_vec)
|
|
490
492
|
|
|
491
493
|
# Check intersections with polygons that could overlap this cell
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: voxcity
|
|
3
|
-
Version: 0.5.
|
|
3
|
+
Version: 0.5.28
|
|
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>
|
|
@@ -1,21 +1,22 @@
|
|
|
1
1
|
voxcity/__init__.py,sha256=el9v3gfybHOF_GUYPeSOqN0-vCrTW0eU1mcvi0sEfeU,252
|
|
2
|
-
voxcity/generator.py,sha256=
|
|
2
|
+
voxcity/generator.py,sha256=mEggM4FxE7LChTPCspAQmJlAoUz1PVcbaUfY11cMfzQ,54176
|
|
3
3
|
voxcity/downloader/__init__.py,sha256=o_T_EU7hZLGyXxX9wVWn1x-OAa3ThGYdnpgB1_2v3AE,151
|
|
4
4
|
voxcity/downloader/citygml.py,sha256=jVeHCLlJTf7k55OQGX0lZGQAngz_DD2V5TldSqRFlvc,36024
|
|
5
5
|
voxcity/downloader/eubucco.py,sha256=ln1YNaaOgJfxNfCtVbYaMm775-bUvpAA_LDv60_i22w,17875
|
|
6
6
|
voxcity/downloader/gee.py,sha256=O6HhQnUUumg_tTm4pP_cuyu5YjupDA1uKFxZWxD-i2E,23205
|
|
7
7
|
voxcity/downloader/mbfp.py,sha256=UXDVjsO0fnb0fSal9yqrSFEIBThnRmnutnp08kZTmCA,6595
|
|
8
8
|
voxcity/downloader/oemj.py,sha256=iDacTpiqn7RAXuqyEtHP29m0Cycwta5sMy9-GdvX3Fg,12293
|
|
9
|
-
voxcity/downloader/osm.py,sha256=
|
|
9
|
+
voxcity/downloader/osm.py,sha256=9nOVcVE50N76F5uquJbNIFr8Xajff4ac2Uj2oSGcFrc,42591
|
|
10
10
|
voxcity/downloader/overture.py,sha256=4YG2DMwUSSyZKUw_o8cGhMmAkPJon82aPqOFBvrre-Y,11987
|
|
11
11
|
voxcity/downloader/utils.py,sha256=tz6wt4B9BhEOyvoF5OYXlr8rUd5cBEDedWL3j__oT70,3099
|
|
12
|
-
voxcity/exporter/__init__.py,sha256=
|
|
12
|
+
voxcity/exporter/__init__.py,sha256=dvyWJ184Eik9tFc0VviGbzTQzZi7O0JNyrqi_n39pVI,94
|
|
13
|
+
voxcity/exporter/cityles.py,sha256=zp119kSfsmwReCv6hJEonzPL3vxKZBk6LxD0NUk_j1E,12978
|
|
13
14
|
voxcity/exporter/envimet.py,sha256=Sh7s1JdQ6SgT_L2Xd_c4gtEGWK2hTS87bccaoIqik-s,31105
|
|
14
15
|
voxcity/exporter/magicavoxel.py,sha256=SfGEgTZRlossKx3Xrv9d3iKSX-HmfQJEL9lZHgWMDX4,12782
|
|
15
16
|
voxcity/exporter/obj.py,sha256=h1_aInpemcsu96fSTwjKMqX2VZAFYbZbElWd4M1ogyI,27973
|
|
16
17
|
voxcity/geoprocessor/__init__.py,sha256=JzPVhhttxBWvaZ0IGX2w7OWL5bCo_TIvpHefWeNXruA,133
|
|
17
|
-
voxcity/geoprocessor/draw.py,sha256=
|
|
18
|
-
voxcity/geoprocessor/grid.py,sha256=
|
|
18
|
+
voxcity/geoprocessor/draw.py,sha256=qTYzXEF8GKWh3hquirspzlzwXTIzl39y9VuEJ0WjOis,32031
|
|
19
|
+
voxcity/geoprocessor/grid.py,sha256=lhELyznlk4Jt7vnd0uOpMCLPCjrYQjX7qtQq-xHkYE4,64161
|
|
19
20
|
voxcity/geoprocessor/mesh.py,sha256=ElqAE2MA8KZs7yD7B1P88XYmryC6F9nkkP6cXv7FzIk,30777
|
|
20
21
|
voxcity/geoprocessor/network.py,sha256=YynqR0nq_NUra_cQ3Z_56KxfRia1b6-hIzGCj3QT-wE,25137
|
|
21
22
|
voxcity/geoprocessor/polygon.py,sha256=-LonxtW5du3UP61oygqtDJl6GGsCYnUuN9KYwl1UFdc,53707
|
|
@@ -29,9 +30,9 @@ voxcity/utils/lc.py,sha256=h2yOWLUIrrummkyMyhRK5VbyrsPtslS0MJov_y0WGIQ,18925
|
|
|
29
30
|
voxcity/utils/material.py,sha256=H8K8Lq4wBL6dQtgj7esUW2U6wLCOTeOtelkTDJoRgMo,10007
|
|
30
31
|
voxcity/utils/visualization.py,sha256=T-jKrCA4UMm93p-1O678RWM7e99iE0_Lj4wD07efcwI,112918
|
|
31
32
|
voxcity/utils/weather.py,sha256=2Jtg-rIVJcsTtiKE-KuDnhIqS1-MSS16_zFRzj6zmu4,36435
|
|
32
|
-
voxcity-0.5.
|
|
33
|
-
voxcity-0.5.
|
|
34
|
-
voxcity-0.5.
|
|
35
|
-
voxcity-0.5.
|
|
36
|
-
voxcity-0.5.
|
|
37
|
-
voxcity-0.5.
|
|
33
|
+
voxcity-0.5.28.dist-info/licenses/AUTHORS.rst,sha256=m82vkI5QokEGdcHof2OxK39lf81w1P58kG9ZNNAKS9U,175
|
|
34
|
+
voxcity-0.5.28.dist-info/licenses/LICENSE,sha256=s_jE1Df1nTPL4A_5GCGic5Zwex0CVaPKcAmSilxJPPE,1089
|
|
35
|
+
voxcity-0.5.28.dist-info/METADATA,sha256=1-Vf32nGdVvGxmOMXMcfTIi4IM92x4uGq5T7qzlDbxY,26724
|
|
36
|
+
voxcity-0.5.28.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
37
|
+
voxcity-0.5.28.dist-info/top_level.txt,sha256=00b2U-LKfDllt6RL1R33MXie5MvxzUFye0NGD96t_8I,8
|
|
38
|
+
voxcity-0.5.28.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|