Skip to main content
added 468 characters in body
Source Link
Ben W
  • 23.1k
  • 3
  • 19
  • 43
project = QgsProject.instance()
#Change to match your layer names below
grid = project.mapLayersByName('Hex_grid')[0]
points = project.mapLayersByName('Random_points')[0]

point_feats = [f for f in points.getFeatures()]
grid_feats = [f for f in grid.getFeatures()]

def find_nearest_empty_hexagon(feat):
    index = QgsSpatialIndex(grid.getFeatures())
    n = 0
    found = False
    while not found:
        n+=1
        nn_id = index.nearestNeighbor(feat.geometry(), n)[n-1]
        geom = grid.getFeature(nn_id).geometry()
        if not geom.intersects(QgsGeometry().collectGeometry([f.geometry() for f in points.getFeatures()])):
            found = True
    return nn_id

points_moved = []
for hex_ft in grid_feats:
    points_within = [f for f in point_feats if f.geometry().within(hex_ft.geometry())]
    if len(points_within) > 1:
        for p in points_within:
            current_centroid = hex_ft.geometry().centroid()
            min_dist = min([p.geometry().distance(current_centroid) for p in points_within])
            if p.geometry().distance(current_centroid) == min_dist:
                continue
            nearest_empty_id = find_nearest_empty_hexagon(p)
            nearest_empty_feat = [f for f in grid_feats if f.id() == nearest_empty_id][0]
            points.dataProvider().changeGeometryValues({p.id(): nearest_empty_feat.geometry().centroid()})
            points_moved.append(p.id())

points_outside_grid = []

remaining_points = [p for p in point_feats if p.id() not in points_moved]
for p in remaining_points:
    enclosing_hex = [f for f in grid_feats if f.geometry().contains(p.geometry())]
    if not enclosing_hex:
        points_outside_grid.append(p)
    elif len(enclosing_hex)>0:
        enclosing_hex_centroid = enclosing_hex[0].geometry().centroid()
    points.dataProvider().changeGeometryValues({p.id(): enclosing_hex_centroid})
    
if points_outside_grid:
    for p in points_outside_grid:
        nearest_empty_id = find_nearest_empty_hexagon(p)
        nearest_empty_feat = [f for f in grid_feats if f.id() == nearest_empty_id][0]
        points.dataProvider().changeGeometryValues({p.id(): nearest_empty_feat.geometry().centroid()})
    
points.triggerRepaint()
project = QgsProject.instance()
#Change to match your layer names below
grid = project.mapLayersByName('Hex_grid')[0]
points = project.mapLayersByName('Random_points')[0]

point_feats = [f for f in points.getFeatures()]
grid_feats = [f for f in grid.getFeatures()]

def find_nearest_empty_hexagon(feat):
    index = QgsSpatialIndex(grid.getFeatures())
    n = 0
    found = False
    while not found:
        n+=1
        nn_id = index.nearestNeighbor(feat.geometry(), n)[n-1]
        geom = grid.getFeature(nn_id).geometry()
        if not geom.intersects(QgsGeometry().collectGeometry([f.geometry() for f in points.getFeatures()])):
            found = True
    return nn_id

points_moved = []
for hex_ft in grid_feats:
    points_within = [f for f in point_feats if f.geometry().within(hex_ft.geometry())]
    if len(points_within) > 1:
        for p in points_within:
            current_centroid = hex_ft.geometry().centroid()
            min_dist = min([p.geometry().distance(current_centroid) for p in points_within])
            if p.geometry().distance(current_centroid) == min_dist:
                continue
            nearest_empty_id = find_nearest_empty_hexagon(p)
            nearest_empty_feat = [f for f in grid_feats if f.id() == nearest_empty_id][0]
            points.dataProvider().changeGeometryValues({p.id(): nearest_empty_feat.geometry().centroid()})
            points_moved.append(p.id())

remaining_points = [p for p in point_feats if p.id() not in points_moved]
for p in remaining_points:
    enclosing_hex = [f for f in grid_feats if f.geometry().contains(p.geometry())]
    if enclosing_hex:
        enclosing_hex_centroid = enclosing_hex[0].geometry().centroid()
    points.dataProvider().changeGeometryValues({p.id(): enclosing_hex_centroid})
points.triggerRepaint()
project = QgsProject.instance()
#Change to match your layer names below
grid = project.mapLayersByName('Hex_grid')[0]
points = project.mapLayersByName('Random_points')[0]

point_feats = [f for f in points.getFeatures()]
grid_feats = [f for f in grid.getFeatures()]

def find_nearest_empty_hexagon(feat):
    index = QgsSpatialIndex(grid.getFeatures())
    n = 0
    found = False
    while not found:
        n+=1
        nn_id = index.nearestNeighbor(feat.geometry(), n)[n-1]
        geom = grid.getFeature(nn_id).geometry()
        if not geom.intersects(QgsGeometry().collectGeometry([f.geometry() for f in points.getFeatures()])):
            found = True
    return nn_id

points_moved = []
for hex_ft in grid_feats:
    points_within = [f for f in point_feats if f.geometry().within(hex_ft.geometry())]
    if len(points_within) > 1:
        for p in points_within:
            current_centroid = hex_ft.geometry().centroid()
            min_dist = min([p.geometry().distance(current_centroid) for p in points_within])
            if p.geometry().distance(current_centroid) == min_dist:
                continue
            nearest_empty_id = find_nearest_empty_hexagon(p)
            nearest_empty_feat = [f for f in grid_feats if f.id() == nearest_empty_id][0]
            points.dataProvider().changeGeometryValues({p.id(): nearest_empty_feat.geometry().centroid()})
            points_moved.append(p.id())

points_outside_grid = []

remaining_points = [p for p in point_feats if p.id() not in points_moved]
for p in remaining_points:
    enclosing_hex = [f for f in grid_feats if f.geometry().contains(p.geometry())]
    if not enclosing_hex:
        points_outside_grid.append(p)
    elif len(enclosing_hex)>0:
        enclosing_hex_centroid = enclosing_hex[0].geometry().centroid()
    points.dataProvider().changeGeometryValues({p.id(): enclosing_hex_centroid})
    
if points_outside_grid:
    for p in points_outside_grid:
        nearest_empty_id = find_nearest_empty_hexagon(p)
        nearest_empty_feat = [f for f in grid_feats if f.id() == nearest_empty_id][0]
        points.dataProvider().changeGeometryValues({p.id(): nearest_empty_feat.geometry().centroid()})
    
points.triggerRepaint()
added 70 characters in body
Source Link
Ben W
  • 23.1k
  • 3
  • 19
  • 43
project = QgsProject.instance()
#Change to match your layer names below
grid = project.mapLayersByName('Hex_grid')[0]
points = project.mapLayersByName('Random_points')[0]

point_feats = [f for f in points.getFeatures()]
grid_feats = [f for f in grid.getFeatures()]

def find_nearest_empty_hexagon(feat):
    index = QgsSpatialIndex(grid.getFeatures())
    n = 0
    found = False
    while not found:
        n+=1
        nn_id = index.nearestNeighbor(feat.geometry(), n)[n-1]
        geom = grid.getFeature(nn_id).geometry()
        if not geom.intersects(QgsGeometry().collectGeometry([f.geometry() for f in points.getFeatures()])):
            found = True
    return nn_id

points_moved = []
for hex_ft in grid_feats:
    points_within = [f for f in point_feats if f.geometry().within(hex_ft.geometry())]
    if len(points_within) > 1:
        for p in points_within:
            current_centroid = hex_ft.geometry().centroid()
            min_dist = min([p.geometry().distance(current_centroid) for p in points_within])
            if p.geometry().distance(current_centroid) == min_dist:
                continue
            nearest_empty_id = find_nearest_empty_hexagon(p)
            nearest_empty_feat = [f for f in grid_feats if f.id() == nearest_empty_id][0]
            points.dataProvider().changeGeometryValues({p.id(): nearest_empty_feat.geometry().centroid()})
            points_moved.append(p.id())

remaining_points = [p for p in point_feats if p.id() not in points_moved]
for p in remaining_points:
    enclosing_hex_centroidenclosing_hex = [f for f in grid_feats if f.geometry().contains(p.geometry())][0]]
    if enclosing_hex:
        enclosing_hex_centroid = enclosing_hex[0].geometry().centroid()
    points.dataProvider().changeGeometryValues({p.id(): enclosing_hex_centroid})
points.triggerRepaint()
project = QgsProject.instance()
#Change to match your layer names below
grid = project.mapLayersByName('Hex_grid')[0]
points = project.mapLayersByName('Random_points')[0]

point_feats = [f for f in points.getFeatures()]
grid_feats = [f for f in grid.getFeatures()]

def find_nearest_empty_hexagon(feat):
    index = QgsSpatialIndex(grid.getFeatures())
    n = 0
    found = False
    while not found:
        n+=1
        nn_id = index.nearestNeighbor(feat.geometry(), n)[n-1]
        geom = grid.getFeature(nn_id).geometry()
        if not geom.intersects(QgsGeometry().collectGeometry([f.geometry() for f in points.getFeatures()])):
            found = True
    return nn_id

points_moved = []
for hex_ft in grid_feats:
    points_within = [f for f in point_feats if f.geometry().within(hex_ft.geometry())]
    if len(points_within) > 1:
        for p in points_within:
            current_centroid = hex_ft.geometry().centroid()
            min_dist = min([p.geometry().distance(current_centroid) for p in points_within])
            if p.geometry().distance(current_centroid) == min_dist:
                continue
            nearest_empty_id = find_nearest_empty_hexagon(p)
            nearest_empty_feat = [f for f in grid_feats if f.id() == nearest_empty_id][0]
            points.dataProvider().changeGeometryValues({p.id(): nearest_empty_feat.geometry().centroid()})
            points_moved.append(p.id())

remaining_points = [p for p in point_feats if p.id() not in points_moved]
for p in remaining_points:
    enclosing_hex_centroid = [f for f in grid_feats if f.geometry().contains(p.geometry())][0].geometry().centroid()
    points.dataProvider().changeGeometryValues({p.id(): enclosing_hex_centroid})
points.triggerRepaint()
project = QgsProject.instance()
#Change to match your layer names below
grid = project.mapLayersByName('Hex_grid')[0]
points = project.mapLayersByName('Random_points')[0]

point_feats = [f for f in points.getFeatures()]
grid_feats = [f for f in grid.getFeatures()]

def find_nearest_empty_hexagon(feat):
    index = QgsSpatialIndex(grid.getFeatures())
    n = 0
    found = False
    while not found:
        n+=1
        nn_id = index.nearestNeighbor(feat.geometry(), n)[n-1]
        geom = grid.getFeature(nn_id).geometry()
        if not geom.intersects(QgsGeometry().collectGeometry([f.geometry() for f in points.getFeatures()])):
            found = True
    return nn_id

points_moved = []
for hex_ft in grid_feats:
    points_within = [f for f in point_feats if f.geometry().within(hex_ft.geometry())]
    if len(points_within) > 1:
        for p in points_within:
            current_centroid = hex_ft.geometry().centroid()
            min_dist = min([p.geometry().distance(current_centroid) for p in points_within])
            if p.geometry().distance(current_centroid) == min_dist:
                continue
            nearest_empty_id = find_nearest_empty_hexagon(p)
            nearest_empty_feat = [f for f in grid_feats if f.id() == nearest_empty_id][0]
            points.dataProvider().changeGeometryValues({p.id(): nearest_empty_feat.geometry().centroid()})
            points_moved.append(p.id())

remaining_points = [p for p in point_feats if p.id() not in points_moved]
for p in remaining_points:
    enclosing_hex = [f for f in grid_feats if f.geometry().contains(p.geometry())]
    if enclosing_hex:
        enclosing_hex_centroid = enclosing_hex[0].geometry().centroid()
    points.dataProvider().changeGeometryValues({p.id(): enclosing_hex_centroid})
points.triggerRepaint()
added 167 characters in body
Source Link
Ben W
  • 23.1k
  • 3
  • 19
  • 43

As per @bugmenot123's comment you may also like to save the original geometries as x& y columns in your point layer to allow for analysing the displacement later.

Once you have made a backup and checked that both layers are using the same crs, paste the script below into a blank editor in the Python console. Change the layer names in lines 3 & 4 to match your own grid and point layer names. Click Run.

Once you have made a backup and checked that both layers are using the same crs, paste the script below into a blank editor in the Python console. Change the layer names in lines 3 & 4 to match your own grid and point layer names. Click Run.

As per @bugmenot123's comment you may also like to save the original geometries as x& y columns in your point layer to allow for analysing the displacement later.

Once you have made a backup and checked that both layers are using the same crs, paste the script below into a blank editor in the Python console. Change the layer names in lines 3 & 4 to match your own grid and point layer names. Click Run.

added 1 character in body
Source Link
Ben W
  • 23.1k
  • 3
  • 19
  • 43
Loading
added 418 characters in body
Source Link
Ben W
  • 23.1k
  • 3
  • 19
  • 43
Loading
Source Link
Ben W
  • 23.1k
  • 3
  • 19
  • 43
Loading