Skip to content
Snippets Groups Projects
Commit 700b2e63 authored by Sara Savanovic Djordjevic's avatar Sara Savanovic Djordjevic
Browse files

add: comments and docstrings to add_new_lake.py

parent be979927
No related branches found
No related tags found
1 merge request!14Clhp map
......@@ -14,7 +14,6 @@ import '../server_requests/fetch_relation.dart';
/// and the last requesting the list of all system lakes
Future<void> initialiseState(bool fetchSearchOptions) async {
bool serverConnection = true;
bool internetConnection = false;
late Future<List<Measurement>> markerListFuture;
late Future<Uint8List> relationFuture;
......
......@@ -25,9 +25,18 @@ lng = (distance_in_km × 360)/(40075km × cos(lat))
# Read a json file with relation data and send to response object
def cut_map(self, cursor, lake_name: str, dist_in_km=0.5):
def cut_map(self, cursor, lake_name: str, cell_size_in_km=0.5):
"""
Cuts a map into a grid based on a selected cell size
Parameters:
self (BaseHTTPRequestHandler): A instance of a BaseHTTPRequestHandler
cursor (cursor): An Sqlite3 cursor object that points to the database
lake_name (str): The name of the lake to be cut
cell_size_in_km (float): The selected cell size in kilometers
"""
try:
# Read relation from GeoJson file and extract all polygons
# Read relation from GeoJson file and extract all geometry of type Polygon
geo_data = gpd.read_file(LAKE_RELATIONS_PATH + lake_name + ".geojson")
polygon_data = geo_data[geo_data['geometry'].geom_type == 'Polygon']
polygons = [Polygon(polygon.exterior) for polygon in polygon_data['geometry']]
......@@ -35,26 +44,35 @@ def cut_map(self, cursor, lake_name: str, dist_in_km=0.5):
if len(polygons) <= 1:
raise Exception("Failed to convert JSON object to Shapely Polygons")
# List to store all the map tiles
divided_map = []
cell_size = dist_in_km * 10
# Convert the cell size to degrees
cell_size = cell_size_in_km * 10
cell_width = cell_size / 111.32
# A slightly more complicated formula is required to calculate the height to ensure that
# the height in km is equal to the width in km regardless of the latitude.
cell_height = (cell_size * 360) / (40075 * cos(cell_width))
# Process all polygons
for polygon in polygons:
# Generate a grid based on the calculated cell size
lines = create_grid(polygon, cell_width, cell_height)
lines.append(polygon.boundary)
# Merge the grid lines into a single grid object
lines = unary_union(lines)
lines = linemerge(lines)
lines = list(polygonize(lines))
# Divide the polygon into tiles based on the generated grid
divided_map.extend(combine_grid_with_poly(polygon, lines))
# List to store new GeoJSON feature objects
features = []
# Create subdivisions for each map tile
sub_div_id = 0
for tile in divided_map:
# Calculate tile center based on bounds, and round down to two decimals
min_x, min_y, max_x, max_y = tile.bounds
center = round(max_y - (max_y - min_y), 6), round(max_x - (max_x - min_x), 6)
......@@ -66,6 +84,7 @@ def cut_map(self, cursor, lake_name: str, dist_in_km=0.5):
rounded_coordinates.append(rounded_coords)
rounded_tile = Polygon(rounded_coordinates)
# Create new feature object
tile_feature = {
'type': 'Feature',
'properties': {
......@@ -74,9 +93,11 @@ def cut_map(self, cursor, lake_name: str, dist_in_km=0.5):
},
'geometry': rounded_tile.__geo_interface__
}
# Append new feature oject to list, and increment sub_div_id for next iteration
features.append(tile_feature)
sub_div_id += 1
# Create new GeoJSON object containing all the new feature objects
feature_collection = {
'type': 'FeatureCollection',
'features': features,
......@@ -95,10 +116,11 @@ def cut_map(self, cursor, lake_name: str, dist_in_km=0.5):
INSERT INTO BodyOfWater(Name) VALUES (?);
''', (lake_name,))
# Plot the newly created map and save it to a new file
plot_map(divided_map)
write_json_to_file(lake_name, feature_collection)
# Return the map to the response object
self.send_response(200)
self.send_header("Content-type", "application/json")
self.end_headers()
......@@ -113,21 +135,33 @@ def cut_map(self, cursor, lake_name: str, dist_in_km=0.5):
self.end_headers()
def create_grid(poly: Polygon, cell_width, cell_height):
def create_grid(poly: Polygon, cell_width: float, cell_height: float):
"""
Returns a list of vertical and horizontal LineStrings that create a grid.
Parameters:
poly (Polygon): A Shapely Polygon representing a map or part of a map
cell_width (float): The width of the grid cells in degrees
cell_height (float): The height of the grid cells in degrees
Returns:
grid_lines (list): List of LineString objects defining the grid
"""
# Retrieve bounds of the entire polygon
bounds = poly.bounds
min_x, min_y, max_x, max_y = bounds
# List to store all created lines
grid_lines = []
# Horizontal lines
# Create new horizontal lines while within bounds
y = min_y
while y <= max_y:
line = LineString([(min_x, y), (max_x, y)])
grid_lines.append(line)
y += cell_height
# Vertical lines
# Create new vertical lines while within bounds
x = min_x
while x <= max_x:
line = LineString([(x, min_y), (x, max_y)])
......@@ -138,6 +172,17 @@ def create_grid(poly: Polygon, cell_width, cell_height):
def combine_grid_with_poly(polygon, grid):
"""
Returns a list of polygons that together make up map tiles.
Parameters:
polygon (Polygon): A polygon representing a map or part of a map
grid (list): List of LineString objects defining the grid
Returns:
intersecting_tiles (list): List of Polygons
"""
# List to contain all the tiles
intersecting_tiles = []
for line in grid:
......@@ -153,24 +198,32 @@ def combine_grid_with_poly(polygon, grid):
return intersecting_tiles
def write_json_to_file(lake_name: str, json_data: dict):
def write_json_to_file(lake_name: str, map_data: dict):
"""
Writes a divided map to a JSON file and updates all_lake_names.json
Parameters:
lake_name (str): Name of the lake and file to write to
map_data (dict): List of map polygons converted to a JSON dictionary
"""
# Create and write divided map to new file
print("Writing to file...")
if not os.path.exists(LAKE_RELATIONS_PATH):
raise Exception("Directory from path does not exist")
with open(LAKE_RELATIONS_PATH + '/' + lake_name + '_div.json', 'w') as f:
json.dump(json_data, f)
json.dump(map_data, f)
# Update all_system_lakes
# Read all_system_lakes.json
with open(LAKE_RELATIONS_PATH + 'all_lake_names.json', 'r') as file:
data = json.load(file)
# Check if the lake name exists in the list
if lake_name not in data:
data.append(lake_name)
data.append(lake_name) # Only append to list if it does not already exist
# Update all_lake_names.json with new lake name
with open(LAKE_RELATIONS_PATH + 'all_lake_names.json', 'w') as file:
# json.dump(data, file, indent=2)
json.dump(data, file, ensure_ascii=False, indent=2)
......@@ -178,16 +231,26 @@ def write_json_to_file(lake_name: str, json_data: dict):
# subdivisions. Removing calls to plot_map will speed up the process, but it is recommended to plot the map
# after each division to ensure that the map was divided as intended.
def plot_map(divided_map):
tiles = [gpd.GeoDataFrame(geometry=[tile]) for tile in divided_map]
"""
Plots a divided map using matplotlib.
Parameters:
divided_map (list): List of Shapely Polygons
"""
print("Plotting... This may take some time...")
# Convert Polygon objects to GeoDataFrames
tiles = [gpd.GeoDataFrame(geometry=[tile]) for tile in divided_map]
# Configure plot settings
fig, ax = plt.subplots()
ax.set_aspect(1.5)
# Plot each tile
for tile in tiles:
# Give each tile a random color to clearly visualize the grid
random_color = "#{:06x}".format(random.randint(0, 0xFFFFFF))
gpd.GeoSeries(tile.geometry).plot(ax=ax, facecolor=random_color, edgecolor='none')
# Display plot
plt.show()
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment