Untitled
from qgis.core import ( QgsProject, QgsVectorLayer, QgsFeature, QgsPointXY, QgsGeometry, QgsVectorFileWriter, QgsField, QgsFields ) from qgis.PyQt.QtCore import QVariant # Load the "wards" layer wards_layer = QgsProject.instance().mapLayersByName('wards')[0] # Create a new point layer to store the points fields = QgsFields() fields.append(QgsField('candidate', QVariant.String)) point_layer = QgsVectorLayer('Point?crs=EPSG:4326', 'voting_points', 'memory') provider = point_layer.dataProvider() provider.addAttributes(fields) point_layer.updateFields() # Define a fixed grid spacing value (e.g., 0.001 degrees or any unit of your CRS) fixed_spacing = 0.005 # Adjust this value as needed for your specific case # Function to find the closest point within the polygon def closest_point_within_polygon(polygon, point, spacing, placed_points): closest_point = point min_dist = float('inf') for i in range(-1, 2): for j in range(-1, 2): candidate_point = QgsPointXY(point.x() + i * spacing, point.y() + j * spacing) if polygon.contains(QgsGeometry.fromPointXY(candidate_point)) and candidate_point not in placed_points: dist = QgsGeometry.fromPointXY(point).distance(QgsGeometry.fromPointXY(candidate_point)) if dist < min_dist: min_dist = dist closest_point = candidate_point return closest_point # Function to create a grid of points centered on the centroid of a polygon def create_grid_at_centroid(centroid, polygon, num_points, spacing): points = [] placed_points = set() # To track points that have been placed already grid_size = int(num_points ** 0.5) + 1 # Determine grid size to fit num_points with a buffer start_x = centroid.x() - (grid_size // 2) * spacing start_y = centroid.y() - (grid_size // 2) * spacing for i in range(grid_size): for j in range(grid_size): if len(points) < num_points: point = QgsPointXY(start_x + i * spacing, start_y + j * spacing) if polygon.contains(QgsGeometry.fromPointXY(point)) and point not in placed_points: points.append(point) placed_points.add(point) else: adjusted_point = closest_point_within_polygon(polygon, point, spacing, placed_points) points.append(adjusted_point) placed_points.add(adjusted_point) return points # Iterate over each polygon in the wards layer for ward in wards_layer.getFeatures(): geom = ward.geometry() # Get the centroid of the polygon centroid = geom.centroid().asPoint() jones_votes = ward['Jones'] nguyen_votes = ward['Nguyen'] smith_votes = ward['Smith'] # Calculate total number of points needed total_votes = jones_votes + nguyen_votes + smith_votes # Create grid points centered at the centroid and ensure they are within the polygon grid_points = create_grid_at_centroid(centroid, geom, total_votes, fixed_spacing) # Use fixed spacing # Assign points to each candidate start_index = 0 for candidate, votes in zip(['Jones', 'Nguyen', 'Smith'], [jones_votes, nguyen_votes, smith_votes]): candidate_points = grid_points[start_index:start_index + votes] start_index += votes for point in candidate_points: feat = QgsFeature(point_layer.fields()) feat.setGeometry(QgsGeometry.fromPointXY(point)) feat.setAttribute('candidate', candidate) provider.addFeature(feat) point_layer.updateExtents() # Add the points layer to the project QgsProject.instance().addMapLayer(point_layer)
Leave a Comment