Sektorlichter in QGIS erstellen?

24

Ich benutze QGIS 2.18. Ich muss Sektorlichter für Navigationszwecke auf einer Karte erstellen.

Ich habe die Lichtsektordaten als Felder, die becon_id, Startgrad, Endgrad und Farbe in einem Shapefile mit über 500 Bojen, Baken und Leuchttürmen angeben, die auf der Karte angezeigt werden müssen. Für jedes Leuchtfeuer können mehrere Zeilen vorhanden sein, die jeweils einen Lichtsektor (z. B. einen weißen Sektor) beschreiben.

Das Endergebnis sollte ungefähr so ​​aussehen: Die Lichtsektoren in den richtigen Farben, wobei die Farbe als Zeichen im Farbfeld (RGW) markiert ist, und gepunktete Linien in einem Abstand von 100 m bis 1000 m von der Boje / dem Leuchtfeuer / dem Leuchtturm.

Dies sollte höchstwahrscheinlich als regelbasiertes Symbol erstellt werden, aber ich vermute, Sie benötigen Python?

Bildbeschreibung hier eingeben

Im Folgenden finden Sie ein Beispiel für die Shapefile-Daten eines Leuchtturms (leider nicht der obigen), der einen grünen Sektor zwischen 114 und 154 Grad, einen weißen Sektor zwischen 154 und 168 Grad, einen roten Sektor zwischen 168 und 237 Grad und ein grünes aufweist Sektor zwischen 237 und 314 Grad, ein weißer Sektor zwischen 314 und 320 Grad, ein roter Sektor zwischen 320 und 337 Grad (aus irgendeinem Grund ist 0 nicht Nord, sondern Süd):

Beispiel für eine Shapefile-Tabelle

Benjamin Donner
quelle
2
Könnten Sie bitte einen Beispieldatensatz hochladen und Ihre Frage bearbeiten, indem Sie herausfinden, welches Ergebnis Sie genau erwarten? Im angehängten Bild sehe ich nur ein Universum von Symbolen und Farben.
Mi
1
Beispieldaten würden hier helfen. Haben Sie ein Feature pro Sektorlicht oder ein Feature pro Boje? Das Wedge Buffer-Plugin kann hier hilfreich sein, aber wie einfach dies ist, hängt davon ab, wie Ihre Daten eingerichtet sind.
Steven Kay
Hallo @mgri und Steven, ich habe Beispieldaten hinzugefügt und versucht, die Frage klarer zu machen :), danke!
Benjamin Donner
1
@mgri die linien sind keine variablen, sondern linien, die statisch als 900m lange linien zwischen den lichtsektoren wie im bild dargestellt werden sollen. Projiziertes Referenzsystem.
Benjamin Donner

Antworten:

50

BEARBEITEN Ich habe die Antwort bearbeitet, um bestimmte Situationen (aufgrund bestimmter Winkelwerte) zu verwalten und um die gepunkteten Linien nicht anzuzeigen, wenn ein runder Winkel definiert ist.


Ich schlage eine Lösung vor, indem ich nur regelbasierte Symbologie und Beschriftung wiederhole.

Bevor ich anfange, möchte ich unterstreichen, dass ich mich auf die Erklärung der minimalen Dinge konzentrieren werde, die für die Reproduktion des gewünschten Ergebnisses zu tun sind: Dies bedeutet, dass einige andere kleinere Parameter (wie Größen, Breiten usw.) von Ihnen einfach angepasst werden sollten für eine bessere Anpassung an Ihre Bedürfnisse.

Darüber hinaus funktioniert diese Lösung nur, wenn Sie davon ausgehen, dass der 0Grad Nord statt Süd ist (wenn dies 0Süd ist, würde es ausreichen 180, jedes Mal einen Wert zu summieren , der in Formeln, die sich mit Winkeln befassen, mit einer '90' angegeben wird, z . B. cos(radians(90))wird cos(radians(180 + 90))). Ich habe es vorgezogen, dies nur zu tun, um eine allgemeinere Lösung zu finden.


Styling

Wir werden die Punkte mit einem Single symbolund rendern, indem wir uns auf eine Simple Markerund drei Geometry generatorSymbolebenen wiederholen :

Bildbeschreibung hier eingeben

In der weiteren Erläuterung folge ich der gleichen Reihenfolge der Symbole im obigen Bild.

1) Einfacher Marker

Ich habe ein Standardsymbol für einen schwarzen Stern (dies ist der einfachere Teil dieses Tutorials) mit einer Größe von 3 mm und einer Breite von 0,4 mm ausgewählt.

2) Geometriegenerator Nr. 1

Fügen Sie eine neue Symbolebene hinzu und wählen Sie den Geometry generatorTyp:

Bildbeschreibung hier eingeben

Fügen Sie diesen Ausdruck in das ExpressionFeld ein:

CASE
WHEN abs( "ALKUKULMA" - "LOPPUKULMA") < 360
THEN
make_line(
 $geometry,
 make_point(
  $x + 1000*cos(radians(90 - "ALKUKULMA")),
  $y + 1000*sin(radians(90 - "ALKUKULMA"))
  )
)
END

Wir haben gerade die erste Linie definiert, die auf den Punkt zeigt, an dem der Lichtsektor beginnt. Diese Linie ist 1000 m lang und wird nur erstellt, wenn der Öffnungswinkel des Sektorlichts kein runder Winkel ist (dies geschieht, um zu vermeiden, dass die Linie einen ganzen Kreis durchbricht).

3) Geometriegenerator Nr. 2

Wie oben, aber in diesem Schritt müssen Sie diesen Ausdruck verwenden:

CASE
WHEN abs( "ALKUKULMA" - "LOPPUKULMA") < 360
THEN
make_line(
 $geometry,
 make_point(
  $x + 1000*cos(radians(90 - "LOPPUKULMA")),
  $y + 1000*sin(radians(90 - "LOPPUKULMA"))
  )
)
END

Wir haben gerade die erste Linie definiert, die auf den Punkt zeigt, an dem der Lichtsektor endet. Diese Linie ist 1000 m lang und wird nur erstellt, wenn der Öffnungswinkel des Sektorlichts kein runder Winkel ist (dies geschieht, um zu vermeiden, dass die Linie einen ganzen Kreis durchbricht).

4) Geometriegenerator Nr. 3

Fügen Sie diesen Ausdruck in das ExpressionFeld ein:

CASE

WHEN abs("ALKUKULMA" - "LOPPUKULMA") <= 180 AND "ALKUKULMA" >= "LOPPUKULMA"
THEN
difference(
 boundary(
  buffer(
   $geometry, 900)
   ),
  make_polygon(
   geom_from_wkt(
    geom_to_wkt(
     make_line(
      $geometry,
      make_point($x + 2000*cos(radians(90 - "ALKUKULMA" )), $y + 2000*sin(radians((90 - "ALKUKULMA" )))),
      make_point($x + 2000*cos(radians(90 - ("LOPPUKULMA" + "ALKUKULMA")/2 )), $y + 2000*sin(radians((90 - ("LOPPUKULMA" + "ALKUKULMA")/2 )))),
      make_point($x + 2000*cos(radians(90 - "LOPPUKULMA")), $y + 2000*sin(radians((90 - "LOPPUKULMA")))),
      $geometry)
   )  
  )
 )
)

WHEN abs("ALKUKULMA" - "LOPPUKULMA") <= 180 AND "ALKUKULMA" <= "LOPPUKULMA"
THEN
intersection(
 boundary(
  buffer(
   $geometry, 900)
   ),
  make_polygon(
   geom_from_wkt(
    geom_to_wkt(
     make_line(
      $geometry,
      make_point($x + 2000*cos(radians(90 - "ALKUKULMA" )), $y + 2000*sin(radians((90 - "ALKUKULMA" )))),
      make_point($x + 2000*cos(radians(90 - ("LOPPUKULMA" + "ALKUKULMA")/2 )), $y + 2000*sin(radians((90 - ("LOPPUKULMA" + "ALKUKULMA")/2 )))),
      make_point($x + 2000*cos(radians(90 - "LOPPUKULMA")), $y + 2000*sin(radians((90 - "LOPPUKULMA")))),
      $geometry)
   )  
  )
 )
)

WHEN abs("ALKUKULMA" - "LOPPUKULMA") > 180 AND "ALKUKULMA" >= "LOPPUKULMA"
THEN
intersection(
 boundary(
  buffer(
   $geometry, 900)
   ),
  make_polygon(
   geom_from_wkt(
    geom_to_wkt(
     make_line(
      $geometry,
      make_point($x + 2000*cos(radians(90 - "ALKUKULMA" )), $y + 2000*sin(radians((90 - "ALKUKULMA" )))),
      make_point($x - 2000*cos(radians(90 - ("LOPPUKULMA" + "ALKUKULMA")/2 )), $y - 2000*sin(radians((90 - ("LOPPUKULMA" + "ALKUKULMA")/2 )))),
      make_point($x + 2000*cos(radians(90 - "LOPPUKULMA")), $y + 2000*sin(radians((90 - "LOPPUKULMA")))),
      $geometry)
   )  
  )
 )
)

WHEN abs("ALKUKULMA" - "LOPPUKULMA") > 180 AND "ALKUKULMA" <= "LOPPUKULMA"
THEN
difference(
 boundary(
  buffer(
   $geometry, 900)
   ),
  make_polygon(
   geom_from_wkt(
    geom_to_wkt(
     make_line(
      $geometry,
      make_point($x + 2000*cos(radians(90 - "ALKUKULMA" )), $y + 2000*sin(radians((90 - "ALKUKULMA" )))),
      make_point($x - 2000*cos(radians(90 - ("LOPPUKULMA" + "ALKUKULMA")/2 )), $y - 2000*sin(radians((90 - ("LOPPUKULMA" + "ALKUKULMA")/2 )))),
      make_point($x + 2000*cos(radians(90 - "LOPPUKULMA")), $y + 2000*sin(radians((90 - "LOPPUKULMA")))),
      $geometry)
   )  
  )
 )
)


END

Wir haben gerade den Bogen zwischen dem Start- und dem Endpunkt des Lichtsektors definiert (bitte beachten Sie, dass dies 2000ein willkürlicher Wert ist, da ich versuche, ein Polygon zu erstellen , das die Grenze des Kreises mit einem Radius von 900 m schneidet).

Außerdem müssen wir die Farbe einstellen, die im "VARIS"Feld gespeichert ist. Dazu müssen wir es mit einem benutzerdefinierten Ausdruck angeben. Folgen Sie dem Pfeil im Bild unten:

Bildbeschreibung hier eingeben

und geben Sie diesen Ausdruck ein, nachdem Sie auf die Edit...Schaltfläche geklickt haben :

CASE
WHEN  "VARIS" = 'vi' THEN color_rgb(51,160,44)
WHEN "VARIS" = 'v' THEN color_rgb(255,255,255)
WHEN "VARIS" = 'p' THEN color_rgb(227,26,28)
END

Bitte beachten Sie, dass ich für diese Symbolebene zwei Linien erstellt habe: Die obere Linie definiert die zu verwendende Farbe (in der Tat habe ich den benutzerdefinierten Ausdruck für diese festgelegt), während die untere nützlich ist, um einen schwarzen Rand zu definieren (dies wird der Fall sein) eine Breite, die größer ist als die der oberen Zeile). Denken Sie auch daran, Flatwie Cap stylefür beide Linien festzulegen, um Farbüberlappungen zu vermeiden.


Beschriftung

1) Etiketten setzen

Gehe zu Layer Properties> Labelsund folge wie gewohnt den roten Pfeilen:

Bildbeschreibung hier eingeben

und geben Sie dann diesen Ausdruck ein:

CASE
WHEN "VARIS" = 'vi' THEN 'G'
WHEN "VARIS" = 'v' THEN 'W'
WHEN "VARIS" = 'p' THEN 'R'
END

Wir haben die Farbregel mit dem im "VARIS"Feld gespeicherten Wert definiert.

2) Einstellen der Platzierung für Etiketten

Wählen Sie die PlacementOption im LabelsMenü und wählen Sie Offset from point.

Dann mit Bezug auf das Bild unten:

Bildbeschreibung hier eingeben

folge dem roten Pfeil und tippe diesen Ausdruck:

CASE
WHEN "ALKUKULMA" > "LOPPUKULMA"
THEN
concat(
 -1000*cos(radians(90 - ("ALKUKULMA" + "LOPPUKULMA")/2)),
  ',',
  1000*sin(radians(90 - ("ALKUKULMA" + "LOPPUKULMA")/2))
)
WHEN "ALKUKULMA" <= "LOPPUKULMA"
THEN
concat(
 1000*cos(radians(90 - ("ALKUKULMA" + "LOPPUKULMA")/2)),
  ',',
  -1000*sin(radians(90 - ("ALKUKULMA" + "LOPPUKULMA")/2))
)
END

Folgen Sie dann dem grünen Pfeil und geben Sie diesen Ausdruck ein:

CASE
WHEN "ALKUKULMA" >= "LOPPUKULMA"
THEN
180-(("ALKUKULMA" + "LOPPUKULMA")/2)
WHEN "ALKUKULMA" < "LOPPUKULMA"
THEN
- (("ALKUKULMA" + "LOPPUKULMA")/2)
END

Endergebnis

Wenn Sie die vorherigen Aufgaben korrekt ausgeführt haben, sollten Sie in der Lage sein, das folgende Ergebnis zu erhalten:

Bildbeschreibung hier eingeben

Bonus

Da die untergeordneten Parameter zu viele waren, um in dieser Antwort vollständig behandelt zu werden, habe ich den Stil hier angehängt : Sie können diesen Code mit einem beliebigen Texteditor öffnen und als QGIS Layer Style-Datei (dh mit einer .qmlErweiterung) speichern .

Der obige Stil wurde mit QGIS 2.18.4 erstellt (er muss denselben Namen wie das von Ihnen verwendete Shapefile haben).

mgri
quelle
3
Sieht gut aus, zeigt Ihnen wirklich die Leistung des Geometriegenerators. Ist das Rendern langsam?
HeikkiVesanto
2
@ Vesanto Ich habe es an einem Punkt mit sechs Funktionen (dh sechs Sektorlichtern) getestet und es wird sofort gerendert. Ich denke, es sollte schnell gehen, auch wenn es um Hunderte von Features geht, da Anbieter oder ähnliches nicht angerufen werden, sondern nur ein paar mathematische Operationen und Geometrien wie Well Know Text.
Mi
2
Fragen / Antworten wie diese zeigen wirklich, wie vielseitig QGIS sein kann!
Joseph
1
@mgri du bist der Meister, eine fantastisch gute Lösung und eine großartige Erklärung mit viel Arbeit, DANKE !!
Benjamin Donner
1
@mgri ein Berg in dieser Region sollte nach dir benannt werden, danke !! Ich habe ein wenig getestet und es wurden keine Probleme mit Ihren hinzugefügten Lösungen gefunden :)!
Benjamin Donner