Untitled
unknown
plain_text
a year ago
3.8 kB
43
Indexable
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)
Editor is loading...
Leave a Comment