Tworzenie świateł sektorowych w QGIS?

24

Używam QGIS 2.18. Muszę stworzyć światła sektorowe do celów nawigacyjnych na mapie.

Mam dane sektora lekkiego jako pola podające becon_id, stopień początkowy, stopień końcowy i kolor w pliku kształtu z ponad 500 boi, latarni i latarni morskich, które muszą być pokazane na mapie. Dla każdego sygnału nawigacyjnego może być wiele wierszy, każdy opisujący jeden sektor lekki (na przykład sektor biały)

Wynik końcowy powinien wyglądać mniej więcej tak: Sektory światła we właściwych kolorach, z kolorem oznaczonym jako znak w polu koloru (RGW) i przerywanymi liniami od 100 m do 1000 m od boi / latarni / latarni morskiej.

Najprawdopodobniej powinien zostać utworzony jako symbol oparty na regułach, ale chyba potrzebuję trochę pytona?

wprowadź opis zdjęcia tutaj

Poniżej znajduje się przykład danych kształtu pliku dla latarni morskiej (niestety nie powyższej), która ma zielony sektor między 114 a 154 stopni, biały sektor między 154 a 168 stopni, czerwony sektor między 168 a 237 stopni, zielony sektor między 237 a 314 stopni, biały sektor między 314 a 320 stopni, czerwony sektor między 320 a 337 stopni (z jakiegoś powodu 0 to nie północ, ale południe):

przykład tabeli plików kształtu

Benjamin Donner
źródło
2
Czy możesz przesłać przykładowy zestaw danych i edytować swoje pytanie, opracowując dokładnie taki wynik, jakiego oczekujesz? Na załączonym obrazku widzę tylko wszechświat symboli i kolorów.
mgri
1
Przydałyby się tutaj przykładowe dane. Czy masz jedną cechę na lampę sektorową, czy jedną na boję? Wtyczka Wedge Buffer może tutaj pomóc, ale to, jak łatwe będzie to zależy od konfiguracji danych.
Steven Kay,
Cześć @mgri i Steven, dodałem przykładowe dane i starałem się wyjaśnić pytanie :), dziękuję!
Benjamin Donner
1
@ mgri linie nie są zmienne, ale linie, które powinny być statycznie pokazane jako linie o długości 900 m między sektorami światła, jak na zdjęciu. Rzutowany system odniesienia.
Benjamin Donner

Odpowiedzi:

50

EDYCJA Edytowałem odpowiedź na zarządzanie konkretnymi sytuacjami (ze względu na określone wartości kątów) i za brak wyświetlania kropkowanych linii, gdy zdefiniowano kąt okrągły.


Proponuję rozwiązanie, powracając tylko do opartej na regułach symboliki i znakowania.

Przed rozpoczęciem chcę podkreślić, że skupię uwagę na wyjaśnieniu minimalnych czynności, które należy wykonać, aby odtworzyć pożądany rezultat: oznacza to, że niektóre inne drobne parametry (takie jak rozmiary, szerokości itp.) Powinny być łatwo dostosowane przez ciebie dla lepszego dopasowania do twoich potrzeb.

Co więcej, to rozwiązanie działa tylko wtedy , gdy założymy, że 0stopień to Północ zamiast Południa (jeśli 0jest to Południe, wystarczyłoby sumowanie 180wartości za każdym razem, gdy pojawia się „90” w formułach, które dotyczą kątów, np. cos(radians(90))Stałyby się cos(radians(180 + 90))). Wolałem to robić tylko po to, aby dać bardziej ogólne rozwiązanie.


Stylizacja

Wyrenderujemy punkty za pomocą Single symboli, powtarzając się do jednej Simple Markeri trzech Geometry generatorwarstw symboli:

wprowadź opis zdjęcia tutaj

W dalszym objaśnieniu zastosuję tę samą kolejność symboli na powyższym obrazku.

1) Prosty znacznik

Wybrałem domyślny symbol czarnej gwiazdy (jest to łatwiejsza część tego samouczka), mający rozmiar 3 mm i szerokość 0,4 mm.

2) Generator geometrii nr 1

Dodaj nową warstwę symboli i wybierz Geometry generatortyp:

wprowadź opis zdjęcia tutaj

Wstaw to wyrażenie w Expressionpole:

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

Właśnie zdefiniowaliśmy pierwszą linię, która wskazuje punkt, od którego zaczyna się sektor światła. Ta linia ma 1000 m długości i jest tworzona tylko wtedy, gdy kąt otwarcia światła sektorowego nie jest kątem okrągłym (dzieje się tak, aby uniknąć pęknięcia całego okręgu).

3) Generator geometrii nr 2

To samo co powyżej, ale na tym etapie musisz użyć tego wyrażenia:

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

Właśnie zdefiniowaliśmy pierwszą linię, która wskazuje punkt, w którym kończy się sektor światła. Ta linia ma 1000 m długości i jest tworzona tylko wtedy, gdy kąt otwarcia światła sektorowego nie jest kątem okrągłym (dzieje się tak, aby uniknąć pęknięcia całego okręgu).

4) Generator geometrii nr 3

Wstaw to wyrażenie w Expressionpole:

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

Właśnie zdefiniowaliśmy łuk między punktami początkowym i końcowym sektora lekkiego (pamiętaj, że 2000jest to dowolna wartość, ponieważ próbuję utworzyć wielokąt przecinający się z granicą okręgu o promieniu 900 m).

Ponadto musimy ustawić kolor, który jest przechowywany w "VARIS"polu. W tym celu musimy podać niestandardowe wyrażenie. Postępuj zgodnie ze strzałką na obrazku poniżej:

wprowadź opis zdjęcia tutaj

a następnie wpisz to wyrażenie po kliknięciu Edit...przycisku:

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

Pamiętaj, że dla tej warstwy symboli utworzyłem dwie linie: górna linia określa kolor, który ma być używany (w rzeczywistości ustawiam dla niej niestandardowe wyrażenie), podczas gdy dolna jest przydatna do definiowania czarnej ramki (będzie miała szerokość, która jest większa niż górna linia). Pamiętaj również, aby ustawić Flatjak Cap styledla obu linii, aby uniknąć nakładania się kolorów.


Etykietowanie

1) Ustawianie etykiet

Przejdź do Layer Properties> Labelsi, jak zwykle, postępuj zgodnie z czerwonymi strzałkami:

wprowadź opis zdjęcia tutaj

a następnie wpisz to wyrażenie:

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

Właśnie zdefiniowaliśmy regułę koloru za pomocą wartości zapisanej w "VARIS"polu.

2) Ustawienie położenia etykiet

Wybierz Placementopcję w Labelsmenu i wybierz Offset from point.

Następnie w odniesieniu do poniższego obrazu:

wprowadź opis zdjęcia tutaj

postępuj zgodnie z czerwoną strzałką i wpisz to wyrażenie:

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

Następnie postępuj zgodnie z zieloną strzałką i wpisz to wyrażenie:

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

Ostateczny wynik

Jeśli poprawnie wykonałeś poprzednie zadania, powinieneś być w stanie uzyskać ten wynik:

wprowadź opis zdjęcia tutaj

Premia

Ponieważ drugorzędnych parametrów było zbyt wiele, aby można je było w całości ująć w tej odpowiedzi, załączyłem tutaj styl : możesz otworzyć ten kod w dowolnym edytorze tekstu i zapisać go jako plik stylu warstwy QGIS (tj. Z .qmlrozszerzeniem).

Powyższy styl został stworzony przy użyciu QGIS 2.18.4 (musi mieć tę samą nazwę, z której korzystasz).

mgri
źródło
3
Wygląda świetnie, naprawdę pokazuje moc generatora geometrii. Czy renderowanie jest wolne?
HeikkiVesanto
2
@ Vesanto Przetestowałem go w jednym punkcie posiadającym sześć funkcji (tj. Sześć lamp sektorowych) i renderowałem natychmiast. Myślę, że powinno to być szybkie także w przypadku setek funkcji, ponieważ nie ma połączenia z dostawcami lub czymś podobnym, ale tylko kilka operacji matematycznych i geometrii, a także tekst.
mgri
2
Takie pytania / odpowiedzi naprawdę pokazują, jak wszechstronny może być QGIS!
Joseph
1
@mgri jesteś Mistrzem, fantastycznie dobre rozwiązanie i świetne wytłumaczenie wymagające dużo pracy, DZIĘKUJĘ !!
Benjamin Donner,
1
@ mgri góra w tym regionie powinna nosić imię po tobie, dziękuję !! Trochę przetestowałem i nie znaleziono problemów z dodanymi przez Ciebie rozwiązaniami :)!
Benjamin Donner