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
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
]