Untitled

mail@pastecode.io avatar
unknown
plain_text
5 months ago
3.8 kB
11
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)
Leave a Comment