Créer des lumières de secteur dans QGIS?

24

J'utilise QGIS 2.18. J'ai besoin de créer des feux de secteur à des fins de navigation sur une carte.

J'ai les données du secteur léger sous forme de champs donnant becon_id, degré de début, degré de fin et couleur dans un fichier de formes avec plus de 500 bouées, balises et phares qui doivent être affichés sur la carte. Pour chaque balise, il peut y avoir plusieurs lignes, chacune décrivant un secteur léger (par exemple un secteur blanc)

Le résultat final devrait ressembler à ce qui suit: Les secteurs de lumière dans les bonnes couleurs, avec la couleur marquée comme caractère dans le champ de couleur (RGW), et les lignes pointillées de 100m à 1000m de la bouée / balise / phare.

Cela devrait très probablement être créé comme un symbole basé sur des règles, mais a besoin de python, je suppose?

entrez la description de l'image ici

Voici un exemple des données du fichier de formes pour un phare (malheureusement pas celui ci-dessus) qui a un secteur vert entre 114 et 154 degrés, un secteur blanc entre 154 et 168 degrés, un secteur rouge entre 168 et 237 degrés, un vert secteur entre 237 et 314 degrés, un secteur blanc entre 314 et 320 degrés, un secteur rouge entre 320 et 337 degrés (pour une raison quelconque, 0 n'est pas le nord mais le sud):

exemple de table de fichiers de formes

Benjamin Donner
la source
2
S'il vous plaît, pourriez-vous télécharger un exemple de jeu de données et modifier votre question en élaborant quel est exactement le résultat que vous attendez? Dans l'image ci-jointe, je ne vois qu'un univers de symboles et de couleurs.
mgri
1
Des données d'exemple seraient utiles ici. Avez-vous une caractéristique par feu de secteur ou une caractéristique par bouée? Le plugin Wedge Buffer peut vous aider ici, mais la facilité de cette opération dépendra de la configuration de vos données.
Steven Kay
Salut @mgri et Steven, j'ai ajouté des exemples de données et essayé de clarifier la question :), merci!
Benjamin Donner
1
@mgri les lignes ne sont pas une variable, mais des lignes qui devraient être statiquement représentées comme des lignes de 900 m de long entre les secteurs lumineux comme dans l'image. Système de référence projeté.
Benjamin Donner

Réponses:

50

MODIFIER J'ai modifié la réponse pour gérer des situations particulières (en raison de valeurs d'angle spécifiques) et pour ne pas afficher les lignes pointillées lorsqu'un angle rond est défini.


Je propose une solution en ne revenant qu'à la symbologie et à l'étiquetage basés sur des règles.

Avant de commencer, je tiens à souligner que je concentrerai l'attention sur l'explication des choses minimales à faire pour reproduire le résultat souhaité: cela signifie que certains autres paramètres mineurs (comme les tailles, les largeurs, etc.) doivent être facilement ajustés par vous pour mieux répondre à vos besoins.

De plus, cette solution ne fonctionne que si vous supposez que le 0degré est le Nord au lieu du Sud (si 0c'est le Sud, au lieu de cela, il suffirait de sommer une 180valeur à chaque fois qui apparaît un `` 90 '' dans les formules qui traitent des angles, par exemple cos(radians(90))deviendrait cos(radians(180 + 90))). Je préférais le faire uniquement pour donner une solution plus générale.


Coiffant

Nous rendrons les points avec un Single symbolet en répétant une Simple Markeret trois Geometry generatorcouches de symboles:

entrez la description de l'image ici

Dans l'explication supplémentaire, je suivrai le même ordre des symboles dans l'image ci-dessus.

1) Marqueur simple

J'ai choisi un symbole par défaut d'une étoile noire (c'est la partie la plus facile de ce tutoriel), ayant une taille de 3 mm et une largeur de 0,4 mm.

2) Générateur de géométrie n ° 1

Ajoutez un nouveau calque de symboles et sélectionnez le Geometry generatortype:

entrez la description de l'image ici

Insérez cette expression dans le Expressionchamp:

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

Nous venons de définir la première ligne qui pointe vers le point de départ du secteur léger. Cette ligne mesure 1000 m de long et elle n'est créée que lorsque l'angle d'ouverture du feu de secteur n'est pas un angle rond (cela se produit pour éviter que la ligne ne casse un cercle entier).

3) Générateur de géométrie n ° 2

Comme ci-dessus mais, dans cette étape, vous devez utiliser cette expression:

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

Nous venons de définir la première ligne qui pointe vers le point où se termine le secteur léger. Cette ligne mesure 1000 m de long et elle n'est créée que lorsque l'angle d'ouverture du feu de secteur n'est pas un angle rond (cela se produit pour éviter que la ligne ne casse un cercle entier).

4) Générateur de géométrie n ° 3

Insérez cette expression dans le Expressionchamp:

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

Nous venons de définir l'arc entre les points de départ et d'arrivée du secteur lumineux (veuillez noter qu'il 2000s'agit d'une valeur arbitraire car j'essaie de créer un polygone à intersecter avec la limite du cercle ayant un rayon de 900 m).

De plus, nous devons définir la couleur qui est stockée dans le "VARIS"champ. Pour ce faire, nous devons le spécifier avec une expression personnalisée. Suivez la flèche dans l'image ci-dessous:

entrez la description de l'image ici

puis tapez cette expression après avoir cliqué sur le Edit...bouton:

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

Veuillez noter que, pour cette couche de symboles, j'ai créé deux lignes: la ligne supérieure définit la couleur à utiliser (en fait j'ai défini l'expression personnalisée pour celle-ci), tandis que celle du bas est utile pour définir une bordure noire (elle aura une largeur plus grande que celle de la ligne supérieure). N'oubliez pas également de définir Flatles Cap styledeux lignes pour éviter tout chevauchement de couleurs.


Étiquetage

1) Définition des étiquettes

Allez à Layer Properties> Labelset, comme d'habitude, suivez les flèches rouges:

entrez la description de l'image ici

puis tapez cette expression:

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

Nous venons de définir la règle de couleur en utilisant la valeur stockée dans le "VARIS"champ.

2) Définition du placement des étiquettes

Sélectionnez l' Placementoption dans le Labelsmenu et sélectionnez Offset from point.

Ensuite, en référence à l'image ci-dessous:

entrez la description de l'image ici

suivez la flèche rouge et tapez cette expression:

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

Ensuite, suivez la flèche verte et tapez cette expression:

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

Résultat final

Si vous avez correctement effectué les tâches précédentes, vous devriez pouvoir obtenir ce résultat:

entrez la description de l'image ici

Prime

Comme les paramètres mineurs étaient trop nombreux pour être complètement couverts dans cette réponse, j'ai attaché le style ici : vous pouvez ouvrir ce code avec n'importe quel éditeur de texte et l'enregistrer en tant que fichier de style de couche QGIS (c'est-à-dire avec une .qmlextension).

Le style ci-dessus a été créé à l'aide de QGIS 2.18.4 (il doit avoir le même nom que le fichier de formes que vous utilisez).

mgri
la source
3
Est superbe, vous montre vraiment la puissance du générateur de géométrie. Le rendu est-il lent?
HeikkiVesanto
2
@Vesanto Je l'ai testé sur un point ayant six fonctionnalités (c'est-à-dire six lumières de secteur) et il a rendu instantanément. Je pense que cela devrait également être rapide lorsqu'il s'agit de centaines de fonctionnalités, car il n'y a pas d'appel à des fournisseurs ou quelque chose de similaire, mais seulement quelques opérations mathématiques et géométries comme Well Know Text.
mgri
2
Des questions / réponses comme celles-ci montrent vraiment à quel point QGIS peut être polyvalent!
Joseph
1
@mgri vous êtes le maître, une solution incroyablement bonne et une excellente explication impliquant beaucoup de travail, MERCI !!
Benjamin Donner
1
@mgri une montagne dans cette région doit être nommée d'après vous, merci !! J'ai testé un peu et aucun problème avec vos solutions ajoutées n'a été trouvé :)!
Benjamin Donner