Cómo crear cadenas lineales con un ángulo y longitud definidos, que se fijan a un punto

8

Quiero crear cadenas lineales con un ángulo definido (por ejemplo, 160 °) y una longitud (por ejemplo, 2 m) que se fijan en varios puntos de otra cadena lineal. Por lo tanto, quiero usar la función ST_DumpPoints para encontrar los puntos y unirles las cadenas de líneas creadas. ¿Hay alguna manera de declarar un ángulo (α) durante la creación de la cadena lineal? Aquí hay una imagen de ejemplo:

ingrese la descripción de la imagen aquí

Quiero crear las cadenas lineales azules.

EDITAR

El ángulo (α2) en la imagen no es realmente ejemplar. Pero más bien un acimut de 160 ° (como α1).

ACTUALIZAR

La respuesta de Evil Genius me ayudó a calcular el ancho máximo de un polígono con un aspecto dado.

Stefan
fuente

Respuestas:

11

Podría lograr esto de diferentes maneras dependiendo del tipo de salida que desee, pero el concepto es el mismo. En general, es más fácil hacer una rotación simple seguida de una traducción en lugar de tratar de calcular las coordenadas en un solo paso.

En este caso, los pasos básicos son:

  • Cree una línea de la longitud deseada en el origen (0,0). Esta línea debe correr a lo largo del eje desde el que desea medir su ángulo y tener su centro en el origen.
  • Gire la línea alrededor del origen.
  • Traslade la línea por las coordenadas del punto en el que desea que se centre.

La siguiente vista de PostGIS crea las líneas de su escenario de ejemplo. Se suponen algunas cosas:

  • La columna de geometría se llama shape
  • El ángulo se mide desde el eje x. Su dibujo de ejemplo fue un poco confuso ya que mencionó por primera vez 40 grados, dibujó una línea vertical punteada, pero luego dijo que debería estar alrededor de 160 grados. He interpretado que significa que realmente quieres medir desde el eje x.
  • Los datos se proyectan en las mismas unidades con las que desea medir (es decir, metros).

    CREATE OR REPLACE VIEW <viewname> AS
    WITH vertices AS
    (SELECT 
          objectid, 
          (ST_DumpPoints(shape)).path[1] AS v_id, 
          (ST_DumpPoints(shape)).geom AS vertex
    FROM <source_data>
    )
    SELECT
        objectid,
        v_id,
        ST_SetSRID(ST_Translate(ST_Rotate(ST_MakeLine(ST_MakePoint( 1.0,0.0), 
                                                      ST_MakePoint(-1.0,0.0)),
                                          radians(40)), ST_X(vertex), ST_Y(Vertex)),
                                          ST_SRID(vertex)) AS newline
    FROM vertices

Para desglosar lo que realmente está sucediendo con esa última línea, comenzando desde el interior: ST_SetSRID(ST_Translate(ST_Rotate(ST_MakeLine(ST_MakePoint( 0,1.0), ST_MakePoint(0,-1.0)), radians(40)), ST_X(vertex), ST_Y(Vertex)), ST_SRID(vertex)) AS newline

  • ST_MakePoint(1.0,0.0)y ST_MakePoint(-1.0,0.0): Cree los puntos finales para una línea horizontal que sea nuestra longitud deseada y centrada en el origen.
  • ST_MakeLine(...): Use nuestros puntos finales recién creados para crear una línea.
  • ST_Rotate(..., radians(40)): Gire esa nueva línea alrededor del origen.
  • ST_Translate(..., ST_X(vertex), ST_Y(vertex)): Centre la línea girada en nuestro punto de referencia (entrada).
  • ST_SetSRID(..., ST_SRID(vertex)): Asigne a la nueva línea el mismo SRID que la geometría de entrada.

Si está utilizando PostGIS 2.0, puede simplificar esto ya que puede especificar un origen diferente para ST_Rotate. Si desea rotar a un ángulo basado en la pendiente de la línea, primero deberá calcularlo y agregarlo al ángulo de rotación.

Si los datos no se proyectan en las mismas unidades que desea medir, aún puede hacer algo similar, pero necesitará un paso adicional:

  • Cree una línea (proyectada en algo que use lo que desea medir)
  • Girar
  • Reproyectar a su proyección objetivo
  • Traducir al punto objetivo

Editar

Ahora entiendo lo que quieres decir con el ángulo. Esencialmente, desea una rotación en el sentido de las agujas del reloj desde el eje Y (0 es hacia arriba, 90 es hacia la derecha, 180 es hacia abajo, etc.).

Todavía necesita usar la radiansfunción ya que ST_Rotateespera el ángulo en radianes. Debería poder obtener el ángulo correcto con dos pequeños cambios:

  • Comience con una línea vertical (use ST_MakePoint(0.0,1.0)y ST_MakePoint(0.0,-1.0))
  • Multiplica tu ángulo por -1. Esto lo hará negativo, causando ST_rotateque gire en sentido horario.radians(<angle> * -1)
Genio malvado
fuente
Eres un genio malvado! Gracias. Funciona perfecto, pero configurando el ángulo correcto. Trabajo con ángulos (almacenados en una columna), que son como una exposición o aspecto (0 a 360 grados). Un aspecto de 200 °, por ejemplo (como dirección geográfica SSW): cuando trazo las cadenas lineales no tienen el ángulo correcto. Usando grados () la dirección geográfica es como SSE y usando radianes () como SW.
Stefan
@StefanB. ¡Me alegra que haya sido útil! He editado mi respuesta (muy abajo) para mostrar cómo deberías poder lograr el ángulo que deseas.
Evil Genius
Funciona. ¡Brillante idea!
Stefan