Mehr

Generieren gleich großer Polygone entlang einer Linie mit PyQGIS


Ich möchte Polygone entlang einer Linie erstellen, um sie in einem nächsten Schritt für AtlasCreator zu verwenden.

ArcMap verfügt über ein Werkzeug namens Strip Map Index Features.

Mit diesem Tool kann ich die Höhe und Breite meiner Polygone wählen (z. B. 8 km x 4 km) und sie automatisch entlang der Linie produzieren / drehen.

Eines der generierten Attribute jedes Polygons ist der Drehwinkel, den ich benötige, um meine Nordpfeile anschließend im Atlas Generator zu drehen.

Hat jemand eine Idee, wie man diese Aufgabe in QGIS / mit PyQGIS lösen kann?

GRASS- oder SAGA-Algorithmen oder ein Verarbeitungs-Toolbox-Modell, das in einem benutzerdefinierten Plugin verwendet werden könnte, wären auch in Ordnung.

Ich benötige nicht nur die Druckausdehnungen, sondern auch die Polygone selbst, da ich eine Karte mit allen Polygonen/Ausdehnungen als eine Art Übersichtskarte drucken möchte. Ich suche eine PyQGIS-Lösung, die in einem QGIS-Plugin verwendet werden kann ohne dass eine Software neben QGIS installiert werden muss (kein RDBMS wie PostGIS / Oracle).


Interessante Frage! Es ist etwas, was ich selbst ausprobieren wollte, also habe ich es ausprobiert.

Dies können Sie in PostGRES/POSTGIS mit einer Funktion tun, die einen Satz von Polygonen erzeugt.

In meinem Fall habe ich eine Tabelle mit einem Merkmal (einem MULTILINESTRING), das eine Eisenbahnlinie darstellt. Es muss ein CRS in Metern verwendet werden, ich verwende osgb (27700). Ich habe 4km x 2km 'Seiten' gemacht.

Hier können Sie das Ergebnis sehen… das Grüne ist das Straßennetz, das auf einen 1 km langen Puffer um die Bahnlinie herum abgeschnitten ist, was der Höhe der Polygone gut entspricht.

Hier ist die Funktion…

ERSTELLEN ODER ERSETZEN FUNKTION getAllPages(wid float, hite float, srid integer, überlappungsfloat) RÜCKGABE SETOF Geometrie ALS $BODY$ DECLARE Seitengeometrie; -- hält jede Seite, wie sie generiert wird, myline-Geometrie; -- enthält die Geometrie des Startpunkts der Liniengeometrie; Endpunktgeometrie; Azimut-Schwimmer; -- Drehwinkel curs float := 0.0 ; -- wie weit entlang der linken Kante der Linie ist der Step-Float; stufenweiser Schwimmer; Currpoly-Geometrie; -- verwendet, um Seiten-Currline-Geometrie zu erstellen; Currangle Schwimmer; Anzahl Seiten schweben; BEGIN – ST_LineMerge-Aufruf löschen, wenn LineString verwendet wird – Ersetzen Sie dies durch Ihre Tabelle. SELECT ST_LineMerge(geom) INTO myline from traced_osgb; numpages := ST_Length(myline)/wid; Schritt := 1.0/Numpages; stepnudge := (1.0-Überlappung) * step; FOR r in 1… cast (numpages als Integer) LOOP -- den Startpunkt des aktuellen Liniensegments berechnen := ST_SetSRID(ST_Line_Interpolate_Point(myline,curs),srid); Endpunkt := ST_SetSRID(ST_Line_Interpolate_Point(myline,curs+step),srid); currline := ST_SetSRID(ST_MakeLine(Startpunkt,Endpunkt),srid); -- erstelle ein Polygon geeigneter Größe am Ursprung von CRS currpoly := ST_SetSRID(ST_Extent(ST_MakeLine(ST_MakePoint(0.0,0.0),ST_MakePoint(wid,hite))),srid); -- dann nach unten schieben, damit die Mittellinie dem aktuellen Liniensegment entspricht currpoly := ST_Translate(currpoly,0.0,-hite/2.0); -- Drehen, um den Winkel anzupassen -- Ich habe absolut keine Ahnung, wie dieses Bit funktioniert. currangle := -ST_Azimuth(Startpunkt,Endpunkt) - (PI()/2.0) + PI(); currpoly := ST_Rotate(currpoly, currangle); -- dann zum Anfang des aktuellen Segments bewegen currpoly := ST_Translate(currpoly,ST_X(startpoint),ST_Y(startpoint)); Seite := currpoly; RETURN NEXT Seite als Geom; -- das nächste Ergebnis liefern curs := curs + stepnudge; SCHLEIFE ENDE; RÜCKKEHR; END $BODY$ LANGUAGE 'plpgsql' ;

Verwenden dieser Funktion

Hier ist ein Beispiel; 4 km x 2 km Seiten, epsg: 27700 und 10 % Überlappung

wähle st_asEwkt(getallpages) aus getAllPages(4000.0, 2000.0, 27700, 0.1);

Nachdem Sie dies ausgeführt haben, können Sie dann aus PgAdminIII in eine CSV-Datei exportieren. Sie können dies in QGIS importieren, müssen jedoch möglicherweise das CRS manuell für den Layer festlegen - QGIS verwendet nicht die SRID in EWKT, um das Layer-CRS für Sie festzulegen:/

Peilungsattribut hinzufügen

Dies ist wahrscheinlich einfacher in Postgis, es kann in QGIS-Ausdrücken gemacht werden, aber Sie müssen etwas Code schreiben. Etwas wie das…

Tabellenseiten erstellen als ( select getallpages from getAllPages(4000.0, 2000.0, 27700, 0.1) ); Tabellenseiten ändern Spaltenlagerschwimmer hinzufügen; Aktualisieren Sie die Seiten, setzen Sie Peilung=ST_Azimuth(ST_PointN(getallpages,1),ST_PointN(getallpages,2));

Vorbehalte

Es ist ein bisschen zusammengehackt und hatte nur die Möglichkeit, an einem Datensatz zu testen.

Nicht 100% sicher, welche zwei Scheitelpunkte Sie bei diesem Lagerattribut-Update auswählen müssenAbfrage… müssen möglicherweise experimentieren.

Ich muss gestehen, dass ich keine Ahnung habe, warum ich eine so komplizierte Formel verwenden muss, um das Polygon so zu drehen, dass es dem aktuellen Liniensegment entspricht. Ich dachte, ich könnte die Ausgabe von ST_Azimuth () in ST_Rotate () verwenden, aber anscheinend nicht.


@Steven Kays 'Antwort in PyQGIS.

Wählen Sie einfach die Linien in Ihrer Ebene aus, bevor Sie das Skript ausführen. Das Skript unterstützt die Linienzusammenführung nicht, daher kann es auf Ebenen mit Multilinestring nicht funktionieren

#!python #kodierung: utf-8 # /questions/173127/generating-equal-sized-polygons-along-line-with-pyqgis from qgis.core import (QgsMapLayerRegistry, QgsGeometry, QgsField, QgsFeature, QgsPoint) von PyQt4.QtCore import QVariant def getAllPages(layer, width, height, srid,overlap): für Feature in layer.selectedFeatures(): geom = feature.geometry() if geom.type() <> QGis.Line: print "Geometrietyp soll . sein a LineString" return 2 Seiten = QgsVectorLayer("Polygon?crs=epsg:"+str(srid), layer.name()+'_id_'+str(feature.id())+'_pages', "memory") fid = QgsField("fid", QVariant.Int, "int") angle = QgsField("angle", QVariant.Double, "double") Attribute = [fid, angle] Seiten.startEditing() SeitenProvider = Seiten.dataProvider( ) pagesProvider.addAttributes(attributes) curs = 0 numpages = geom.length()/(width) step = 1.0/numpages stepnudge = (1.0-overlap) * step pageFeatures = [] r = 1 currangle = 0 while curs <= 1 : # print 'r =' + str(r) # print 'curs = ' + str(curs) startpoint = geom.interpolate(curs*geo m.length()) endpoint = geom.interpolate((curs+step)*geom.length()) x_start = startpoint.asPoint().x() y_start = startpoint.asPoint().y() x_end = Endpunkt. asPoint().x() y_end = endpoint.asPoint().y() # print 'x_start :' + str(x_start) # print 'y_start :' + str(y_start) currline = QgsGeometry().fromWkt('LINESTRING ({} {}, {} {})'.format(x_start, y_start, 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) azimut = startpoint.asPoint().azimuth(endpoint.asPoint()) currangle = (startpoint.asPoint().azimuth(endpoint.asPoint())+270)%360 # print 'azimut :' + str(azimut) # 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 SeitenPro vider.addFeatures(pageFeatures) pages.commitChanges() QgsMapLayerRegistry.instance().addMapLayer(pages) return 0 layer = iface.activeLayer() getAllPages(layer, 500, 200, 2154, 0.4)

Es gibt verschiedene Lösungen. Und dies kann mit einfachen Polylinien und mehreren ausgewählten Elementen funktionieren

Blockschaltbild:

  1. Parameter

    1. Ausrichtung für Generierung auswählen und Index lesen (von links nach rechts, von Norden nach Süden…)
    2. Objektgröße einstellen
    Form = (4000,8000) # (,)
    1. Überlagerungskoeffizient definieren (10% standardmäßig?)
  2. drin
    1. Sortieren von Polylinien (Start- und Endpunkt vergleichen) Sortierung hängt von Ihrer Orientierungswahl ab > Erstellen einer Stützpunkt-Reihenfolge Feature-Class OrderNodes
  3. Schleife auf OrderNodes

    1. Erstellen Sie Ihren ersten Punkt als Anker

    2. für jeden Knoten füge ihn auf dict x,y,id hinzu und berechne einen Vektor

    3. Polygon erzeugen (über die Länge und Vektororientierung) mit reduzierender Überlagerung ( 10% /2) > 5% linkes Polygon 5% rechtes Polygon mit gleichem Ankerpunkt
    4. Stoppen Sie, wenn ein vorhergehender Scheitelpunkt außerhalb des Polygons liegt oder wenn der Vektor len > to shape length ist
    5. Polygon mit vorheriger guter Lösung generieren und Ankerpunkt mit letzter guter Position setzen
    6. Führen Sie eine neue Schleife aus und setzen Sie dict x,y,id zurück, um das nächste Polygonobjekt zu generieren.

Sie können diesen Vorschlag ändern, wenn er nicht wirklich klar ist oder kommentieren.


Die beiden Antworten (zum Zeitpunkt der Veröffentlichung) sind genial und gut erklärt. Es gibt jedoch auch eine SEHR einfache, aber effektive Lösung dafür (vorausgesetzt, Sie akzeptieren alle Ihre Karten, die auf traditionelle Weise mit Norden ausgerichtet sind, anstatt eine zufällige Nordrichtung basierend auf dem Fluss). Wenn Sie Rotationen wünschen, ist dies möglich, jedoch etwas komplexer (siehe unten).

Schau dir zuerst meinen Beitrag hier an. Hier erhalten Sie eine Anleitung zum Erstellen von Kartenabdeckungen für Atlas. Die gewünschte Methode ist eine Adaption von 'Workflow 2' im How-to. Teilen Sie Ihr lineares Feature nach Scheitelpunkten oder Länge und puffern Sie die Features um einen beliebigen Betrag. Der Betrag, um den Sie puffern, bestimmt teilweise die Überlappung (siehe jedoch unten), aber was noch wichtiger ist, es erstellt ein Feature mit einer Fläche. Sie können eine beliebige Anzahl von Plugins verwenden, um die Zeilen zu teilen, aber die GRASS-Optionen v.split.length und v.split.vert sind gute Optionen (verfügbar in der Processing Toolbox).

Nachdem Sie die Atlas-Generierung in Map Composer aktiviert und Ihren gepufferten Layer ausgewählt haben, wechseln Sie zurück zur Registerkarte Elemente und wählen Sie Ihr Kartenobjekt aus. Aktivieren Sie "Controlled by Atlas", und in Ihrem Anwendungsfall würde ich mich für die Funktion "Margin around" entscheiden. Dadurch wird Ihre Überlappung zwischen den Karten gesteuert (alternativ können Sie einen festen Maßstab bevorzugen).

Sie können Ihren Atlas mit dem Vorschau-Button in der oberen Symbolleiste des Composers in der Vorschau anzeigen und sehen, wie viele Seiten er produzieren wird. Beachten Sie, dass Sie alle Seiten in einer einzigen PDF-Datei oder als separate Dateien exportieren können.

Damit sich die Karte entlang der Linie dreht, gibt es in den Eigenschaften des Map Composer-Elements ein Rotationsfeld. Sie müssen einen Ausdruck festlegen (verwenden Sie die kleine Schaltfläche rechts neben dem Rotationsfeld). Wählen Sie Variable als Ihre Option und dann Bearbeiten. Es öffnet sich ein Ausdrucksgenerator, in dem Sie auf die Geometrie oder Felder der Atlas-Features zugreifen können. Sie können dann einen Express erstellen, um die Karte entsprechend der Drehung der Features zu drehen (Sie können die Peilung anhand der Start- und Endpunkte jedes Liniensegments und ein wenig trigonometrischen Wertes berechnen). Wiederholen Sie den gleichen Vorgang, um Ihren Nordpfeil zu drehen (mit demselben Ausdruck oder derselben vorberechneten Variablen).


Ich weiß, dass dies eine alte Frage ist, aber ein neues Plugin wurde erstellt, um dieses Problem zu lösen. https://plugins.qgis.org/plugins/polystrip/

Ich bin nicht der Ersteller und beanspruche das Plugin nicht.