¿Crear luces de sector en QGIS?

24

Estoy usando QGIS 2.18. Necesito crear luces de sector para fines de navegación en un mapa.

Tengo los datos del sector de la luz como campos que dan becon_id, grado inicial, grado final y color en un archivo de forma con más de 500 boyas, balizas y faros que deben mostrarse en el mapa. Para cada baliza, puede haber muchas filas, cada una de las cuales describe un sector ligero (por ejemplo, un sector blanco)

El resultado final debe ser similar al siguiente: los sectores de luz en los colores correctos, con el color marcado como el carácter en el campo de color (RGW) y líneas punteadas de 100 ma 1000 m desde la boya / baliza / faro.

Lo más probable es que esto se cree como un símbolo basado en reglas, pero ¿necesita algo de pitón, supongo?

ingrese la descripción de la imagen aquí

A continuación se muestra un ejemplo de los datos del archivo de forma para un faro (desafortunadamente no el anterior) que tiene un sector verde entre 114 y 154 grados, un sector blanco entre 154 y 168 grados, un sector rojo entre 168 y 237 grados, un verde sector entre 237 y 314 grados, un sector blanco entre 314 y 320 grados, un sector rojo entre 320 y 337 grados (por alguna razón, 0 no es norte sino sur):

ejemplo de tabla de shapefile

Benjamin Donner
fuente
2
Por favor, ¿podría cargar un conjunto de datos de muestra y editar su pregunta elaborando cuál es exactamente el resultado que espera? En la imagen adjunta solo veo un universo de símbolos y colores.
mgri
1
Los datos de ejemplo ayudarían aquí. ¿Tiene una característica por sector de luz o una característica por boya? El complemento Wedge Buffer podría ayudar aquí, pero lo fácil que sea esto dependerá de cómo se configuren sus datos.
Steven Kay
Hola @mgri y Steven, agregué datos de ejemplo e intenté aclarar la pregunta :), ¡gracias!
Benjamin Donner
1
@mgri las líneas no son una variable, sino líneas que deberían mostrarse estáticamente como líneas de 900 m de largo entre los sectores claros, como en la imagen. Sistema de referencia proyectado.
Benjamin Donner

Respuestas:

50

EDITAR Edité la respuesta para manejar situaciones particulares (debido a valores de ángulo específicos) y para no mostrar las líneas punteadas cuando se define un ángulo redondo.


Propongo una solución recurriendo solo a la simbología y el etiquetado basados ​​en reglas.

Antes de comenzar, quiero subrayar que enfocaré la atención en la explicación de las cosas mínimas para reproducir el resultado deseado: esto significa que usted debe ajustar fácilmente otros parámetros menores (como tamaños, anchos, etc.) para adaptarse mejor a sus necesidades.

Además, esta solución solo funciona si supone que el 0grado es Norte en lugar de Sur (si 0es Sur, en cambio, sería suficiente sumar un 180valor cada vez que aparezca un '90' en las fórmulas que tratan con ángulos, por ejemplo, cos(radians(90))se convertiría en cos(radians(180 + 90))). Preferí hacer esto solo por dar una solución más general.


Estilo

Representaremos los puntos con Single symbolay recurriendo a una Simple Markery tres Geometry generatorcapas de símbolos:

ingrese la descripción de la imagen aquí

En la explicación adicional, seguiré el mismo orden de los símbolos en la imagen de arriba.

1) Marcador simple

Elegí un símbolo predeterminado de una estrella negra (esta es la parte más fácil de este tutorial), que tiene un tamaño de 3 mm y un ancho de 0.4 mm.

2) Geometry Generator No. 1

Agregue una nueva capa de símbolo y seleccione el Geometry generatortipo:

ingrese la descripción de la imagen aquí

Inserte esta expresión en el Expressioncampo:

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

Acabamos de definir la primera línea que apunta hacia el punto desde donde comienza el sector de la luz. Esta línea tiene 1000 m de largo y se crea solo cuando el ángulo de apertura de la luz del sector no es un ángulo redondo (esto sucede para evitar que la línea rompa un círculo completo).

3) Geometry Generator No. 2

Igual que el anterior pero, en este paso, debe usar esta expresión:

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

Acabamos de definir la primera línea que apunta hacia el punto donde termina el sector de la luz. Esta línea tiene 1000 m de largo y se crea solo cuando el ángulo de apertura de la luz del sector no es un ángulo redondo (esto sucede para evitar que la línea rompa un círculo completo).

4) Geometry Generator No. 3

Inserte esta expresión en el Expressioncampo:

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

Acabamos de definir el arco entre los puntos inicial y final del sector de la luz (tenga en cuenta que 2000es un valor arbitrario porque estoy tratando de crear un polígono para intersecar con el límite del círculo que tiene un radio de 900 m).

Además, necesitamos establecer el color que se almacena en el "VARIS"campo. Para hacer esto, necesitamos especificarlo con una expresión personalizada. Sigue la flecha en la imagen a continuación:

ingrese la descripción de la imagen aquí

y luego escriba esta expresión después de hacer clic en el Edit...botón:

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

Tenga en cuenta que, para esta capa de símbolo, creé dos líneas: la línea superior define el color que se usará (de hecho, configuro la expresión personalizada para esta), mientras que la inferior es útil para definir un borde negro (tendrá un ancho que es más grande que el de la línea superior). Recuerde también para establecer Flatcomo Cap stylepara ambas líneas para evitar cualquier color superpuestas.


Etiquetado

1) Establecer las etiquetas

Vaya a Layer Properties> Labelsy, como siempre, siga las flechas rojas:

ingrese la descripción de la imagen aquí

y luego escribe esta expresión:

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

Acabamos de definir la regla de color utilizando el valor almacenado en el "VARIS"campo.

2) Establecer la ubicación de las etiquetas

Seleccione la Placementopción en el LabelsMenú y seleccione Offset from point.

Luego, con referencia a la imagen a continuación:

ingrese la descripción de la imagen aquí

siga la flecha roja y escriba esta expresión:

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

Luego, sigue la flecha verde y escribe esta expresión:

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

Resultado final

Si realizó correctamente las tareas anteriores, debería poder obtener este resultado:

ingrese la descripción de la imagen aquí

Prima

Dado que los parámetros menores eran demasiados para estar completamente cubiertos en esta respuesta, he adjuntado el estilo aquí : puede abrir este código con cualquier editor de texto y guardarlo como un archivo de estilo de capa QGIS (es decir, con una .qmlextensión).

El estilo anterior se creó con QGIS 2.18.4 (debe tener el mismo nombre del archivo de forma que está utilizando).

mgri
fuente
3
Se ve muy bien, realmente te muestra el poder del generador de geometría. ¿Es lento para renderizar?
HeikkiVesanto
2
@Vesanto Lo probé en un punto que tenía seis características (es decir, seis luces de sector) y se renderizó al instante. Creo que también debería ser rápido cuando se trata con cientos de características porque no hay llamadas a proveedores o algo similar, sino solo un par de operaciones matemáticas y geometrías como Well Know Text.
mgri
2
¡Preguntas / respuestas como estas realmente muestran cuán versátil puede ser QGIS!
Joseph
1
@mgri eres el maestro, una solución fantásticamente buena y una gran explicación que implica mucho trabajo, ¡GRACIAS!
Benjamin Donner
1
@mgri una montaña en esta región debe llevarse su nombre, ¡gracias! ¡He probado un poco y no se han encontrado problemas con sus soluciones agregadas :)!
Benjamin Donner