Mais

Gerando polígonos de tamanhos iguais ao longo da linha com PyQGIS


Gostaria de criar polígonos ao longo de uma linha para usá-los no AtlasCreator em uma próxima etapa.

ArcMap tem uma ferramenta chamada Strip Map Index Features.

Com esta ferramenta, posso escolher a altura e a largura dos meus polígonos (digamos 8 km x 4 km) e produzi-los / girá-los ao longo da linha automaticamente.

Um dos atributos gerados de cada polígono é o ângulo de rotação que preciso para girar minhas setas norte no Atlas Generator depois.

Alguém tem alguma ideia de como resolver esta tarefa no QGIS / com PyQGIS?

Algoritmos GRASS ou SAGA ou um modelo de caixa de ferramentas prossessing que poderia ser usado dentro de um plugin personalizado também seria adequado.

Preciso não apenas das extensões de impressão, mas também dos próprios polígonos, pois desejo imprimir um mapa com todos os polígonos / extensões como uma espécie de mapa geral. Estou procurando uma solução PyQGIS que pode ser usada em um plugin QGIS sem a necessidade de instalar um software além do QGIS (sem RDBMS como PostGIS / Oracle).


Pergunta interessante! É algo que eu queria experimentar, então tentei.

Você pode fazer isso no PostGRES / POSTGIS com uma função que gera um conjunto de polígonos.

No meu caso, tenho uma tabela com um recurso (um MULTILINESTRING) que representa uma linha ferroviária. Precisa usar um CRS em metros, estou usando osgb (27700). Já fiz 'páginas' de 4km x 2km.

Aqui, você pode ver o resultado ... o verde é a rede rodoviária, presa a um buffer de 1km ao redor da ferrovia, que corresponde perfeitamente à altura dos polígonos.

Aqui está a função ...

CREATE OR REPLACE FUNCTION getAllPages (wid float, hite float, srid inteiro, overlap float) RETORNA SETOF geometry AS $ BODY $ DECLARE page geometry; - mantém cada página à medida que é gerada a geometria myline; - mantém a geometria do ponto inicial da geometria da linha; geometria do ponto final; azimute float; - ângulo de rotação curs float: = 0,0; - o quão longe ao longo da linha a borda esquerda está a flutuação de passo; stepnudge float; geometria currpoly; - usado para fazer páginas geometria currline; flutuador de currangle; numpages float; BEGIN - elimina a chamada ST_LineMerge se estiver usando LineString - substitua pela sua tabela. SELECT ST_LineMerge (geom) INTO myline de traced_osgb; numpages: = ST_Length (myline) / wid; etapa: = 1,0 / numpages; stepnudge: = (1.0-overlap) * step; FOR r em 1… cast (numpages como inteiro) LOOP - calcule o ponto inicial do segmento de linha atual: = ST_SetSRID (ST_Line_Interpolate_Point (myline, curs), srid); endpoint: = ST_SetSRID (ST_Line_Interpolate_Point (myline, curs + step), srid); currline: = ST_SetSRID (ST_MakeLine (ponto inicial, ponto final), srid); - fazer um polígono de tamanho apropriado na origem do CRS currpoly: = ST_SetSRID (ST_Extent (ST_MakeLine (ST_MakePoint (0.0,0.0), ST_MakePoint (wid, hite))), srid); - então desloque para baixo para que a linha média corresponda ao segmento de linha atual currpoly: = ST_Translate (currpoly, 0.0, -hite / 2.0); - Gire para coincidir com o ângulo - Não tenho absolutamente nenhuma ideia de como essa parte funciona. currangle: = -ST_Azimuth (ponto inicial, ponto final) - (PI () / 2.0) + PI (); currpoly: = ST_Rotate (currpoly, currangle); - em seguida, mova para o início do segmento atual currpoly: = ST_Translate (currpoly, ST_X (ponto inicial), ST_Y (ponto inicial)); página: = currpoly; RETURN PRÓXIMA página como geom; - produz o próximo resultado curs: = curs + stepnudge; END LOOP; RETORNA; END $ BODY $ LANGUAGE 'plpgsql';

Usando esta função

Aqui está um exemplo; Páginas de 4 km x 2 km, epsg: 27700 e sobreposição de 10%

selecione st_asEwkt (getallpages) em getAllPages (4000.0, 2000.0, 27700, 0.1);

Depois de executar isso, você pode exportar do PgAdminIII para um arquivo csv. Você pode importar isso para o QGIS, mas talvez seja necessário definir o CRS manualmente para a camada - o QGIS não usa o SRID no EWKT para definir o CRS da camada para você: /

Adicionando atributo de rolamento

Provavelmente é mais fácil fazer em postgis, pode ser feito em expressões QGIS, mas você precisará escrever algum código. Algo assim…

criar páginas de tabela como (selecione getallpages em getAllPages (4000.0, 2000.0, 27700, 0.1)); alterar as páginas da tabela adiciona flutuação de rolamento de coluna; atualizar o conjunto de páginas de rolamento = ST_Azimuth (ST_PointN (getallpages, 1), ST_PointN (getallpages, 2));

Ressalvas

É um pouco hackeado e só teve a chance de testar em um conjunto de dados.

Não tenho 100% de certeza de quais vértices você precisa escolher nessa atualização de atributo de rolamentoinquerir... pode precisar experimentar.

Devo confessar que não tenho ideia de por que preciso fazer uma fórmula tão complicada para girar o polígono para coincidir com o segmento de linha atual. Achei que poderia usar a saída de ST_Azimuth () em ST_Rotate (), mas aparentemente não.


Resposta de @Steven Kays em PyQGIS.

Basta selecionar as linhas em sua camada antes de executar o script. O script não suporta o linemerging, portanto não pode funcionar em camadas com cadeias multilinha

#! python # coding: utf-8 # / questions / 173127 / generator-equal-sized-polygons-along-line-with-pyqgis de qgis.core import (QgsMapLayerRegistry, QgsGeometry, QgsField, QgsFeature, QgsPoint) de PyQt4.QtCore import QVariant def getAllPages (layer, width, height, srid, overlap): para recurso em layer.selectedFeatures (): geom = feature.geometry () if geom.type () <> QGis.Line: print "O tipo de geometria deve ser a LineString "return 2 pages = QgsVectorLayer (" Polygon? crs = epsg: "+ str (srid), layer.name () + '_ id _' + str (feature.id ()) + '_ pages'," memory ") fid = QgsField ("fid", QVariant.Int, "int") ângulo = QgsField ("ângulo", QVariant.Double, "double") atributos = [fid, ângulo] pages.startEditing () pagesProvider = pages.dataProvider ( ) pagesProvider.addAttributes (atributos) curs = 0 numpages = geom.length () / (largura) step = 1.0 / numpages stepnudge = (1.0-overlap) * passo pageFeatures = [] r = 1 currangle = 0 enquanto curs <= 1 : # print 'r =' + str (r) # print 'curs =' + str (curs) startpoint = geom.interpolate (curs * geo m.length ()) endpoint = geom.interpolate ((curs + etapa) * geom.length ()) x_start = startpoint.asPoint (). x () y_start = startpoint.asPoint (). y () x_end = endpoint. asPoint (). x () y_end = endpoint.asPoint (). y () # print 'x_start:' + str (x_start) # print 'y_start:' + str (y_start) currline = QgsGeometry (). fromWkt ('LINESTRING ({} {}, {} {}) '. formato (x_início, y_início, x_end, y_end)) currpoly = QgsGeometry (). fromWkt (' POLYGON ((0 0, 0 {height}, {width} {height} , {width} 0, 0 0)) '. format (height = height, width = width)) currpoly.translate (0, -height / 2) azimuth = startpoint.asPoint (). azimuth (endpoint.asPoint ()) currangle = (startpoint.asPoint (). azimuth (endpoint.asPoint ()) + 270)% 360 # print 'azimuth:' + str (azimuth) # print 'currangle:' + str (currangle) currpoly.rotate (currangle, QgsPoint (0,0)) currpoly.translate (x_start, y_start) currpoly.asPolygon () page = currpoly curs = curs + stepnudge feat = QgsFeature () feat.setAttributes ([r, currangle]) feat.setGeometry (page) pageFeatures .append (feat) r = r + 1 pagesPro vider.addFeatures (pageFeatures) pages.commitChanges () QgsMapLayerRegistry.instance (). addMapLayer (pages) return 0 layer = iface.activeLayer () getAllPages (layer, 500, 200, 2154, 0.4)

Existem diferentes soluções. E isso pode funcionar com polilinha simples e várias entidades selecionadas

diagrama de bloco:

  1. Parâmetros

    1. selecione a orientação para a geração e leia o índice (da esquerda para a direita, do norte para o sul ...)
    2. definir o tamanho do objeto
    forma = (4000,8000) # (,)
    1. definir o coeficiente de superposição (10% por padrão?)
  2. iniciar
    1. A ordenação da polilinha (compare os pontos inicial e final) depende da sua escolha de orientação> crie uma ordem dos vértices com a classe de recursos OrderNodes
  3. loop em OrderNodes

    1. crie seu primeiro ponto como âncora

    2. para cada vértice adicione-o em dict x, y, id e calcule um vetor

    3. gerar polígono (ao longo do comprimento e orientação do vetor) com redução da superposição (10% / 2)> 5% polígono esquerdo 5% polígono direito com o mesmo ponto de ancoragem
    4. Pare quando um ponto de vértice precedente estiver fora do polígono ou se o vetor len for> para formar o comprimento
    5. Gerar polígono com a solução anterior boa e definir o ponto de ancoragem com a última posição boa
    6. Execute um novo loop e redefina dict x, y, id para gerar o próximo objeto de polígono.

Você pode alterar essa proposição se não for muito clara ou comentar.


As duas respostas (no momento da postagem) são engenhosas e bem explicadas. No entanto, há também uma solução MUITO simples, mas eficaz possível para isso (assumindo que você aceitará todos os seus mapas alinhados com o Norte no modo tradicional, ao invés de uma direção Norte aleatória baseada no rio). Se você quiser rotações, é possível, mas um pouco mais complexo (veja abaixo).

Primeiro, dê uma olhada no meu post aqui. Isso fornece instruções sobre como criar coberturas de mapa para o Atlas. O método que você deseja é uma adaptação de 'Fluxo de Trabalho 2' no manual. Divida seu recurso linear por vértices ou comprimento e armazene os recursos em qualquer valor. A quantidade de buffer determinará parcialmente a sobreposição (mas veja abaixo), mas o mais importante, ele cria um recurso com uma área. Você pode usar qualquer número de plug-ins para dividir as linhas, mas GRASS v.split.length e v.split.vert são boas opções (disponíveis na Caixa de Ferramentas de Processamento).

Tendo habilitado a Geração de Atlas no Map Composer e selecionado sua camada de buffer, volte para a guia de itens e selecione seu objeto de mapa. Marque 'Controlado pelo Atlas' e, no seu caso de uso, eu optaria pelo recurso Margem ao redor. Isso controlará sua sobreposição entre os mapas (alternativamente, você pode preferir escala fixa).

Você pode visualizar seu Atlas usando o botão Visualizar Atlas na barra de ferramentas superior do compositor e ver quantas páginas ele produzirá. Observe que você pode optar por exportar todas as páginas em um único PDF ou como arquivos separados.

Para fazer o mapa girar ao longo da linha, há um campo de rotação nas propriedades do item do Map Composer. Você precisará definir uma expressão (use o pequeno botão à direita da caixa de rotação). Selecione a variável como sua opção e, em seguida, Editar. Um construtor de expressão aparecerá e lá você pode acessar a geometria ou campos dos recursos do atlas. Você pode então construir um expresso para girar o mapa de acordo com a rotação dos recursos (você pode calcular o rumo usando os pontos inicial e final de cada segmento de linha e um pouco de trigonometria). Repita o mesmo processo para girar sua seta norte (usando a mesma expressão ou variável pré-calculada).


Eu sei que esta é uma questão antiga, mas um novo plug-in foi criado para cuidar desse problema. https://plugins.qgis.org/plugins/polystrip/

Não sou o criador e não recebo crédito pelo plugin.


Assista o vídeo: Layer in Gruppe verschieben mit python in QGIS pyQGIS (Outubro 2021).