30 votos

¿Crear luces de sector en QGIS?

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

Tengo los datos del sector de la luz como campos que dan becon_id, grado de inicio, grado final y color en un shapefile con más de 500 boyas, balizas y faros que necesitan ser mostrados en el mapa. Para cada baliza puede haber muchas filas, cada una de las cuales describe un sector luminoso (por ejemplo, un sector blanco)

El resultado final debería ser como el siguiente: Los sectores de luz en los colores correctos, con el color marcado como el carácter en el campo de color (R G W), y líneas punteadas de 100m a 1000m de la boya/baliza/faro.

Lo más probable es que esto se cree como un símbolo basado en reglas, pero necesita algo de python, supongo.

enter image description here

A continuación se muestra un ejemplo de los datos del shapefile de un faro (desgraciadamente 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 sector verde 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, el 0 no es el norte sino el sur):

shapefile table example

57voto

Geoffrey Puntos 228

EDITAR He editado la respuesta para gestionar situaciones particulares (debido a valores de ángulo específicos) y para no mostrar las líneas de puntos cuando se define un ángulo redondo.


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

Antes de empezar, quiero subrayar que centraré la atención en la explicación de las cosas mínimas que hay que hacer para reproducir el resultado deseado: esto significa que algunos otros parámetros menores (como los tamaños, los anchos y demás) deberían ser ajustados fácilmente por usted para adaptarse mejor a sus necesidades.

Además, esta solución sólo funciona si usted asume que 0 grado es el Norte en lugar del Sur (si 0 es el Sur, en cambio, bastaría con sumar un 180 cada vez que aparece un "90" en las fórmulas que tratan de ángulos, por ejemplo cos(radians(90)) se convertiría en cos(radians(180 + 90)) ). He preferido hacer esto sólo para dar una solución más general.


Estilismo

Haremos los puntos con un Single symbol y recurriendo a una Simple Marker y tres Geometry generator capas de símbolos:

enter image description here

En la explicación posterior, seguiré el mismo orden de los símbolos de la imagen anterior.

1) Marcador simple

Elegí un símbolo por defecto de una estrella negra (esta es la parte más fácil de este tutorial), con un tamaño de 3 mm y un ancho de 0,4 mm.

2) Generador de geometría nº 1

Añade una nueva capa de símbolos y selecciona el Geometry generator tipo:

enter image description here

Inserte esta expresión en el Expression campo:

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 del que parte el sector luminoso. Esta línea tiene una longitud de 1000 m y se crea sólo cuando el ángulo de apertura del sector luminoso no es un ángulo redondo (esto ocurre para evitar que la línea rompa un círculo completo).

3) Generador de geometría nº 2

Igual que en el caso anterior, pero en este paso hay que utilizar 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 luminoso. Esta línea tiene una longitud de 1000 m y se crea sólo cuando el ángulo de apertura del sector luminoso no es un ángulo redondo (esto ocurre para evitar que la línea rompa un círculo completo).

4) Generador de geometría nº 3

Inserte esta expresión en el Expression campo:

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 luminoso (tenga en cuenta que 2000 es un valor arbitrario porque estoy tratando de crear un polígono para que se cruce con el límite del círculo que tiene un radio de 900 m).

Además, tenemos que establecer el color que se almacena en el "VARIS" campo. Para ello, debemos especificarlo con una expresión personalizada. Siga la flecha en la imagen de abajo:

enter image description here

y luego escriba esta expresión después de haber pulsado el botón 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ímbolos, he creado dos líneas: la línea superior define el color a utilizar (de hecho, establecí la expresión personalizada para este), mientras que la inferior es útil para definir un borde negro (tendrá un ancho mayor que el de la línea superior). Recuerde también establecer Flat como Cap style para ambas líneas para evitar cualquier superposición de colores.


Etiquetado

1) Configuración de las etiquetas

Ir a Layer Properties > Labels y, como siempre, sigue las flechas rojas:

enter image description here

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) Fijar la ubicación de las etiquetas

Seleccione el Placement en la opción Labels Menú y seleccione Offset from point .

A continuación, con referencia a la imagen de abajo:

enter image description here

sigue la flecha roja y escribe 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

A continuación, siga la flecha verde y escriba esta expresión:

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

Resultado final

Si ha realizado correctamente las tareas anteriores, debería obtener este resultado:

enter image description here

Bono

Como los parámetros menores eran demasiados para ser cubiertos completamente dentro de 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 de QGIS (es decir, con un .qml extensión).

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

2voto

Specur Puntos 516

Muy buen trabajo.

Sólo una breve nota que desde la versión 3.16 más o menos hay una expresión 'wedge_buffer' que se puede utilizar en un generador de geometría (para crear una cuña (polígono negro) a partir de una capa de puntos (punto rojo)) como en:

wedge buffer

Este es el resultado de generar un polígono utilizando la siguiente expresión:

wedge_buffer(center:=$geometry,azimuth:=90,width:=60,outer_radius:=1000,inner_radius:=200)

donde $geometría es el punto geométrico, tenga en cuenta que el acimut, la anchura y el radio exterior e interior están codificados aquí, pero pueden provenir de los campos de la capa

i-Ciencias.com

I-Ciencias es una comunidad de estudiantes y amantes de la ciencia en la que puedes resolver tus problemas y dudas.
Puedes consultar las preguntas de otros usuarios, hacer tus propias preguntas o resolver las de los demás.

Powered by:

X