39 votos

Curva de punto-a-punto "mapas de ruta"

Recientemente he estado buscando en las líneas aéreas de páginas web que muestran sus vías de salida una ciudad para todas las otras ciudades que prestan servicio. Me gustaría ser capaz de crear semejantes curvas rutas entre puntos. Alguien ha creado las secuencias de comandos o funciones que va a generar la curva de arcos, como los que se muestran en este ejemplo?

Flight Paths

En PostGIS, hay una aplicación de la ST_MakeLine que permiten especificar la cantidad de curva que se utiliza al conectar 2 puntos?

Mientras que actualmente estoy usando en PostGIS y QGIS, me daría la bienvenida a la audiencia acerca de otras opciones de software que podría ser capaz de crear el mismo aspecto.

26voto

tobes Puntos 19

La creación de grandes círculos de poder darle el efecto deseado.

Tal vez algo como discutido en http://lists.osgeo.org/pipermail/postgis-users/2008-February/018620.html

Actualización:

He seguido en esta idea en "Visualización de las Conexiones Globales". Es puramente PostGIS solución basada en el uso de reproyección para crear arcos.

SELECT ST_Transform(
  ST_Segmentize(
    ST_MakeLine(
      ST_Transform(a.the_geom, 953027),
      ST_Transform(b.the_geom, 953027)
    ), 
  100000), 
4326)

(El CRS definición de 953027 se puede encontrar aquí: http://spatialreference.org/ref/esri/53027/)

enter image description here

24voto

cjstehno Puntos 131

El problema es averiguar cuánto doblar los arcos para aumentar su resolución visual.

Aquí es una solución de (entre muchos posibles). Vamos a considerar todos los arcos que emana de un origen común. Los arcos obtener más lleno de gente aquí. Para separar el mejor, vamos a organizar, de manera que se extienden en equiespaciados ángulos. Es un problema si queremos dibujar segmentos de línea recta desde el origen a los destinos, porque normalmente habrá grupos de destinos en diferentes direcciones. Vamos a usar nuestra libertad para doblar arcos para el espacio de la partida de los ángulos de tan uniformemente como sea posible.

Por simplicidad, vamos a utilizar los arcos circulares en el mapa. Una medida natural de la "curva" en un arco desde el punto y el punto x es la diferencia entre el cojinete en y y el rodamiento directamente de y a x. Un arco es un sector de un círculo en el que y y x tanto mentir; geometría elemental muestra que el ángulo de flexión es igual a la mitad el ángulo en el arco.

Para describir un algoritmo necesitamos un poco más de la notación. Vamos y ser el punto de origen (que se proyecta sobre el mapa) y dejar x_1, x_2, ..., x_n ser los puntos de destino. Definir a_i a ser el rodamiento y a x_i, i = 1, 2, ..., n.

Como un paso preliminar, asumir los rodamientos (entre 0 y 360 grados) son, en orden ascendente: esto nos obliga a calcular los rodamientos y, a continuación, ordenar; ambos son sencillas tareas.

Idealmente, nos gustaría que los rodamientos de los arcos a la igualdad de 360/n, 2*360/n, etc., en relación con algunos de partida de rodamiento. Las diferencias entre la deseada cojinetes y el real rodamientos, por tanto, igual que yo * 360 / n - a_i además de la partida de rodamiento, a0. La diferencia más grande es la máxima de estos n de las diferencias y la más pequeña diferencia está en su mínimo. Vamos a establecer a0 a estar a mitad de camino entre el max y el min; este es un buen candidato para el inicio del rodamiento debido a que se minimiza la cantidad máxima de flexión que se producen. En consecuencia, definir

b_i = i * 360 / n - a0 - a_i:

esta es la flexión de usar.

Es una cuestión de elemental de la geometría para dibujar un arco circular de y a x que subtienda un ángulo de 2 b_i, así que voy a omitir los detalles e ir directamente a un ejemplo. Aquí están las ilustraciones de las soluciones para el de 64, de 16 años, y de 4 puntos al azar coloca dentro de un mapa rectangular

alt text

alt text

alt text

Como se puede ver, las soluciones parecen tener más agradable a medida que el número de puntos de destino aumenta. La solución para n = 4 se muestra claramente cómo los rodamientos están igualmente espaciados, en este caso el espacio es igual a 360/4 = 90 grados y, obviamente, que el espaciamiento es exactamente logrado.

Esta solución no es perfecta: usted probablemente puede identificar varios arcos que podrían ser ajustado manualmente para mejorar los gráficos. Pero no va a hacer un trabajo terrible y parece ser un muy buen comienzo.

El algoritmo también tiene el mérito de ser simple: la parte más complicada consiste en la ordenación de los destinos de acuerdo a sus rodamientos.


Codificación

No sé PostGIS, pero tal vez el código que he usado para dibujar los ejemplos que pueden servir de guía para la aplicación de este algoritmo en PostGIS (o cualquier otro SIG).

Considere el siguiente pseudocódigo (pero Mathematica se va a ejecutar :-). (Si este sitio compatible TeX, como las matemáticas, estadísticas, y TCS hacen, yo podría hacer de esto una mucho más legible.) La notación incluye:

  • Nombres de variables y funciones son sensibles a las mayúsculas.
  • [Alfa] es una minúscula carácter griego. ([Pi] tiene el valor que usted piensa que debería tener).
  • x[[i]] es el elemento i de una matriz x (indexada a partir de la 1).
  • f[a,b], se aplica la función f de los argumentos a y b. Funciones en buen caso, como el de 'Min' y 'Tabla', son definidas por el sistema; las funciones con inicial minúscula, como 'angles' y 'offset', son definidos por el usuario. Comentarios explicar cualquier oscuro funciones de sistema (como 'Arg').
  • Tabla[f[i], {i, 1, n}] crea la matriz {f[1], f[2], ..., f[n]}.
  • Círculo[o, r, {a, b}] crea un arco de círculo con centro en o de radio r desde el ángulo de un ángulo b (ambos en radianes en sentido antihorario desde el este).
  • Pedidos[x] devuelve una matriz de índices de los elementos ordenados de x. x[[ Ordenar[x] ]] es la versión ordenada de x. Cuando y tiene la misma longitud que x, y[[ Ordenar[x] ]] tipo y en paralelo con la x.

El ejecutable parte del código es misericordiosamente breve-menos de 20 líneas-porque más de la mitad de ella es declarativa sobrecarga o comentarios.

Dibujar un mapa

z es una lista de destinos y y es el origen.

circleMap[z_List, y_] := 
Module[{\[Alpha] = angles[y,z], \[Beta], \[Delta], n},
    (* Sort the destinations by bearing *)
    \[Beta] = Ordering[\[Alpha]];
    x = z[[\[Beta] ]]; (* Destinations, sorted by bearing from y *)
    \[Alpha] = \[Alpha][[\[Beta]]]; (* Bearings, in sorted order *)
    \[Delta] = offset[\[Alpha]];
    n = Length[\[Alpha]];
    Graphics[{(* Draw the lines *)
        Gray, Table[circle[y, x[[i]],2 \[Pi] i / n + \[Delta] - \[Alpha][[i]]], 
             {i, 1, Length[\[Alpha]]}],
        (* Draw the destination points *)
        Red, PointSize[0.02], Table[Point[u], {u, x}]
    }]
]

Crear un arco circular de un punto a a x punto y de partida en el ángulo \[Beta] en relación a la x-->y el cojinete.

circle[x_, y_, \[Beta]_] /; -\[Pi] < \[Beta] < \[Pi] := 
Module[{v,  \[Rho], r, o, \[Theta], sign},
    If[\[Beta]==0, Return[Line[{x,y}]]];

    (* Obtain the vector from x to y in polar coordinates. *)
    v = y - x; (* Vector from x to y *)
    \[Rho] = Norm[v]; (* Length of v *)
    \[Theta] = Arg[Complex @@ v]; (* Bearing from x to y *)

    (* Compute the radius and center of the circle.*)
    r = \[Rho] / (2 Sin[\[Beta]]); (* Circle radius, up to sign *)
    If[r < 0, sign = \[Pi], sign = 0];
    o = (x+y)/2 + (r/\[Rho]) Cos[\[Beta]]{v[[2]], -v[[1]]}; (* Circle center *)

    (* Create a sector of the circle. *)
    Circle[o, Abs[r], {\[Pi]/2 - \[Beta] + \[Theta] + sign, \[Pi] /2 + \[Beta] + \[Theta] + sign}]
]

Calcular los rodamientos de un origen a una lista de puntos.

angles[origin_, x_] := Arg[Complex@@(#-origin)] & /@ x;

Calcular el rango medio de los residuales de un conjunto de rodamientos.

x es una lista de los rodamientos en orden. Idealmente, x[[i]] ~ 2[Pi]i/n.

offset[x_List] :=
Module[
    {n = Length[x], y},
    (* Compute the residuals. *)
    y = Table[x[[i]] - 2 \[Pi] i / n, {i, 1, n}];
    (* Return their midrange. *)
    (Max[y] + Min[y])/2
]

3voto

JohnMcG Puntos 5062

Yo creo que solo le quieren darse su propio polilínea con algunos vector de matemáticas , http://en.wikipedia.org/wiki/B%C3%A9zier_curveo si el sig tiene una ICurve de la interfaz.

3voto

Chris Upchurch Puntos 10484

Acabé tratando de esto a la curva de un conjunto de "dos puntos" linestrings el uso de la ST_CurveToLine función como sugerido por @Nicklas Avén.

Pasé los siguientes 3 conjuntos de coordenadas para el ST_OffsetCurve función :

  1. Inicio de la línea original
  2. Punto medio de una línea de desplazamiento paralelo a la línea original
  3. Final de la línea original

He utilizado el ST_OffsetCurve función para calcular el desplazamiento - 1/10 de la longitud de la línea original en mi ejemplo.

Aquí está el SQL me utilizados para generar las líneas curvas de la original líneas rectas :

    ST_CurveToLine('CIRCULARSTRING(' || st_x(st_startpoint(the_geom)) || ' ' || st_y(st_startpoint(the_geom)) || ', ' || st_x(st_centroid(ST_OffsetCurve(the_geom, st_length(the_geom)/10, 'quad_segs=4 join=bevel'))) || ' ' || st_y(st_centroid(ST_OffsetCurve(the_geom, st_length(the_geom)/10, 'quad_segs=4 join=bevel'))) || ', ' || st_x(st_endpoint(the_geom)) || ' ' ||  st_y(st_endpoint(the_geom)) || ')') AS the_curved_geom

0voto

Lars Mæhlum Puntos 4569

Trate De ST_CurveToLine

Algo como por ejemplo:

SELECT ST_CurveToLine('CIRCULARSTRING(1 1,5 3,10 1)'::geometry) as the_geom;

Puede visualizar esta por afrontamiento de la consulta en el cuadro de texto y pulsando Map1 en http://www.postgisonline.org/map.php

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