6 votos

¿Fórmula de relleno por inundación para células Voronoi en QGIS?

Por el momento, estoy desarrollando un mapa de la ficción Occidental de la nación India con QGIS. Todo ha ido tan bien como se espera con este proyecto, a excepción de una deficiencia que metió a mí en la tarde del jueves.

La última parte de mi proyecto consiste en la agrupación de las áreas de Voronoi gráfico, basado en el atributo. Por ejemplo, si he de elegir al menos dos celdas y establecer su valor como 1, entonces cada célula de tocar sus lados debe tener 2 como su valor; aquellos tocar el "2" de las células reciben 3; y así sucesivamente hasta llegar a la tabla de límites. Este método, conocido como un "relleno", es utilizado en el procedimiento de generación; ver en acción en este Imgur álbum.

Al intentar seleccionar vaciar las células que tocan con esta expresión:

CASE
WHEN "Dist Lvl" = 1
THEN geomtouches(buffer(centroid($geometry), 100))
END

no hay resultados aparecen antes de que se puede aplicar el "2" a aquellos.

Antes de continuar, me gustaría obtener un mejor código, o Python/PyQGIS secuencia de comandos, que puede hacer el trabajo más rápido; me esforcé para redactar un texto en papel hace un tiempo. (A pesar de que de manera eficiente puede usar QGIS lo contrario, a veces tengo problemas con el PyQGIS poco, un par de ejemplos de lado.)

Al menos la lectura de muchos de estos posts aquí en los últimos años-este de aquí es mi primera ... realmente me han ayudado en mi camino como un geofiction cartógrafo. Así que ahora es tu turno para que me ayude.

4voto

Mat Puntos 196

Interesante pregunta! He hecho una similar llenar en el pasado, pero para diferentes propósitos. Yo no había pensado en usarlo para el mundo :)

He hecho esto en QGIS, Python y Postgresql/PostGIS, pero estoy seguro de que se podría hacer con pyqgis demasiado. He aquí un ejemplo con uno de la ciudad de repartir a los vecinos de los polígonos :-

enter image description here

  • En este caso, he creado un montón de puntos aleatorios, hizo un diagrama de voronoi, y se guarda como un archivo shapefile.
  • Próximo, añade un campo de entero llamado generation, y se sembraron un par de celdas con el valor 1. Otras células que se establece en NULL.
  • importado esta en postgres utilizando shp2pgsql-gui

El siguiente python va a realizar el relleno de un sitio, un anillo en un momento, hasta que no hay una celda a la izquierda para llenar.

import psycopg2

conn = psycopg2.connect("host='localhost' dbname='XXX' user='XXX' password='XXX'")

def growfrom(cell_value):
    cursor = conn.cursor()
    sql = """
        WITH
            ring as (select * from voronoi where generation=%s),
            unfilled as (select * from voronoi where generation is null)
        SELECT
            unfilled.gid as geom
        FROM
            ring, unfilled
        WHERE 
            st_intersects(ring.geom, unfilled.geom);
    """
    cursor.execute(sql, (cell_value,))
    neighbours = []
    for record in cursor.fetchall():
        neighbours.append(record[0])
    sql = """
        UPDATE 
            voronoi
        SET
            generation=%s
        WHERE 
            gid = ANY (%s);
    """
    cursor.execute(sql, (cell_value+1, neighbours))
    conn.commit()
    return len(neighbours)  # when this hits zero, stop

def main():
    start_from = 1
    while True:
        neighbours = growfrom(start_from)
        print("Added {} neighbours in generation #{}".format(neighbours, start_from))
        if neighbours == 0:
            break
        start_from += 1

if __name__=="__main__":
    main()

Yo no he probado este particular enfoque más complejas gometries (como las áreas censales); estos pueden tener casos inusuales (como enclaves, por ejemplo). Pero parece funcionar bien en polígonos de voronoi.

Dada la finalidad de este, es necesario modificar este para iniciar desde múltiples puntos de inicio, no sólo 1. Por ejemplo, usted podría hacer cada ciudad a empezar con un múltiplo de 1000, y crecer cada uno en paralelo en el bucle. De esa manera, los polígonos pueden ser fácilmente asignados a un nuevo campo (dividir por 1000), y el uso de disolver a obtener su país contornos de como esta:-

enter image description here

Para ello, podría usar algo como esto como la principal función de

def main():

    def getsequence():
        # goes 1000,2000,3000,4000,1001,2001... etc
        ix = 0
        while ix<1000:
            yield 1000+ix
            yield 2000+ix
            yield 3000+ix
            yield 4000+ix
            ix+=1

    while True:
        for start_from in getsequence():
            neighbours = growfrom(start_from)
            print("Added {} neighbours in generation #{}".format(neighbours, start_from))

Esto le da un ligero sesgo hacia los números más bajos de las ciudades, aunque, por lo que usted puede ser que desee para ajustar el generador para hacer más aleatoria :)

i-Ciencias.com

I-Ciencias es una comunidad de estudiantes y amantes de la ciencia en la que puedes resolver tus problemas y dudas.
Puedes consultar las preguntas de otros usuarios, hacer tus propias preguntas o resolver las de los demás.

Powered by:

X