Requirement: Enlarge the map proportionally
Analysis: Considering that the relative positional relationships of objects such as rivers and roads need to be preserved during map enlargement, here we choose to merge the coordinate matrices of objects such as rivers and roads into terrain_matrix
and perform scaling on this merged matrix. . The magnified matrix updates the magnification matrix of the respective object according to the position of the object marked in the matrix.
Idea: To enlarge the map proportionally, borrow the idea of image enlargement and use nearest neighbor interpolation to fill the gaps created after enlargement.
accomplish:
Supplementary resizing parametersself.zoomScale
Before initializing self.grid
in _init_
, add the resizing parameter: self.zoomScale
. The code for the modification part of the _init_
function is as follows:
def __init__(self, N=10, K=0, width=50, height=102, civil_info_exchange=True, model_layer=-1, is_fired=False, is_flood=True, count=0): self.warning_UI = "" # Warning information self.resizeScale=3 # parameter using to control the scale of the map
Add map enlargement and update code in the _init_
function
# Load the safe passage coordinates into the map self.draw_environment(self.pos_exits) #Create coordinate space self.graph = path_finding.create_graph(self) self.combine_matrices() # To rescale the terrain map size after combination. self.resize_matrices(self.resizeScale) self.separate_matrix() # update different object matrix from the resized matrix.
Definition of map magnification function resize_matrices
def resize_matrices(self, degree): """ Resize the terrain and constituent matrices while maintaining aspect ratio. :param degree: New rescaling degree. """ scaling_factor = (degree, degree) # Resize the main terrain matrix self.terrain_matrix = zoom(self.terrain_matrix, scaling_factor, order=0) # order=1 for bilinear interpolation and 0 for nearest-neighbor interpolation. # This change will ensure that your matrices' integer values are preserved during the resizing process.
Update the coordinate matrix function of other objects after zooming inseparate_matrix
def separate_matrix(self): """ Separate the combined terrain matrix into individual feature matrices. Each matrix should represent one feature (e.g., river, road) with 1s where the feature exists and 0s where it doesn't. """ # Identify all unique features in the terrain matrix, excluding 0 (empty) unique_features = np.unique(self.terrain_matrix) # Define a mapping from feature codes to the corresponding class attributes feature_mapping = {<!-- --> 1: 'river_matrix', 2: 'road_matrix', 3: 'wall_matrix', 4: 'indoor_matrix', 5: 'exits_matrix', 6: 'pillar_matrix', 7: 'ditch_matrix' } # Initialize each matrix as an array of zeros for matrix_name in feature_mapping.values(): setattr(self, matrix_name, np.zeros_like(self.terrain_matrix)) # For each feature, populate the corresponding matrix for feature in unique_features: if feature == 0: continue # Skip the 'empty' feature matrix_name = feature_mapping.get(feature) if not matrix_name: continue # Skip if the feature is not recognized #Update the corresponding matrix directly feature_matrix = np.where(self.terrain_matrix == feature, 1, 0) setattr(self, matrix_name, feature_matrix) # At this point, each feature matrix (e.g., self.river_matrix) has been updated directly # No need to return anything since we're modifying the class attributes directly
Supplement: Visual script of the enlarged map
Please run it with a separate .py file.
# It's assumed you have executed the following installation command in your local environment: # !pip install datashader import datashader as ds import datashader.transfer_functions as tf import pandas as pd # Load and prepare the data from matplotlib import pyplot as plt file_path = 'G:\terrain_matrix3.csv' data = pd.read_csv(file_path) # Calculate the aspect ratio of the original data num_rows, num_cols = data.shape # Assuming 'data' is your DataFrame aspect_ratio = num_cols / num_rows # Ensure column headers are consistent and represent coordinates or indexing # If headers are numeric: good; if not, you might want to set headers as a range of numbers representing columns data.columns = range(len(data.columns)) # Resetting the index to turn it into a column for melting data = data.reset_index() # Melting the data (now 'X' should be consistently numeric) melted_data = data.melt(id_vars=['index'], var_name='X', value_name='Value') melted_data['Y'] = melted_data['index'] melted_data.drop(columns=['index'], inplace=True) # Convert 'X' and 'Y' to numeric values, coercing errors (i.e., non-numeric values are set as NaN) melted_data['X'] = pd.to_numeric(melted_data['X'], errors='coerce') melted_data['Y'] = pd.to_numeric(melted_data['Y'], errors='coerce') # Handle or remove any rows with NaN if necessary (created by 'coerce') melted_data.dropna(subset=['X', 'Y'], inplace=True) # Define the dimensions for the canvas plot_width = 800 plot_height = int(plot_width / aspect_ratio) # Maintain the aspect ratio of the original data # Set up the canvas with the correct aspect ratio canvas = ds.Canvas(plot_width=plot_width, plot_height=plot_height) # Aggregating data into a grid agg = canvas.points(melted_data, 'X', 'Y', ds.mean('Value')) # Creating an image by coloring the aggregated data img = tf.shade(agg, cmap=['lightblue', 'darkblue'], how='linear') # Convert the Datashader image to a format that can be displayed by matplotlib img_to_plot = tf.shade(agg, cmap=['lightblue', 'darkblue'], how='linear') img_plt = tf.set_background(img_to_plot, 'white') # Display the image using matplotlib plt.imshow(img_plt.to_pil()) plt.axis('off') # Optional: this removes the axes for a cleaner look plt.title('Presentation of the rescaling map data(3X).') plt.show()
The following is an example of the output of the visual script. Among them, 2X and 3X respectively represent the set map magnification.