Sorun, görsel çözünürlüklerini artırmak için yayların ne kadar büküleceğini bulmaktır.
İşte size bir çözüm (mümkün olanların arasında). Ortak bir kaynaktan çıkan tüm yayları düşünelim. Kemerler burada en kalabalık oluyor. Onları en iyisini ayırmak için, eşit aralıklarla açılı olarak yayılacak şekilde ayarlayalım . Asıl noktadan varış noktalarına düz çizgi parçaları çizersek sorun olur, çünkü tipik olarak çeşitli yönlerde varış yerleri kümeleri olacaktır. Kalkış açılarını mümkün olduğunca eşit olarak yerleştirmek için yayları bükmek için özgürlüğümüzü kullanalım.
Basit olması için haritada dairesel yaylar kullanalım. Nokta arasında bir yay içinde "kıvrım" doğal bir ölçüsü y noktasına x onun de yatak arasındaki farktır y ve doğrudan doğruya yatağa y için x . Böyle bir yay, y ve x'in her ikisinin de yalan söylediği bir çemberin kesimidir; temel geometri, bükülme açısının yay içindeki açının yarısına eşit olduğunu gösterir .
Bir algoritmayı tanımlamak için biraz daha gösterime ihtiyacımız var. Let y kökenli noktası (harita üzerinde öngörülen şekilde) ve izin x_1 , x_2 , ..., X_n hedef noktası olsun. A_i'yi y ila x_i , i = 1, 2, ..., n olacak şekilde tanımlayın .
Ön adım olarak, rulmanların (tümü 0 ila 360 derece arasında) artan bir sırada olduğunu varsayalım: bu, yatakları hesaplamamız ve daha sonra sıralamamızı gerektirir; her ikisi de basit görevlerdir.
İdeal olarak, arkların rulmanlarının bir miktar başlangıç rulmanına göre 360 / n , 2 * 360 / n , vb . Olmasını isteriz . İstenen rulmanlar ve gerçek rulmanlar arasındaki farklar bu nedenle i * 360 / n - a_i artı başlangıç yatağı, a0'a eşittir . En büyük fark, bu n farkın maksimum ve en küçük fark ise minimumdur. A0 değerini, min ve min arasında yarıya indirelim ; bu, başlangıç rulmanı için iyi bir adaydır çünkü ortaya çıkacak maksimum bükülme miktarını en aza indirir . Sonuç olarak, tanımla
b_i = i * 360 / n - a0 - a_i:
bu kullanılacak bükülmedir .
Bu bir dairesel yay çizmek için temel geometri meselesi y için x 2 b_i o alt eğimli bir açı, detayları atlayıp bir örnek gidersiniz yüzden. Dikdörtgen bir haritaya yerleştirilen 64, 16 ve 4 rastgele nokta için çözümlerin çizimleri
Gördüğünüz gibi , varış noktalarının sayısı arttıkça çözümler daha da güzelleşiyor . N = 4 için çözüm , rulmanların nasıl eşit aralıklarla yerleştirildiğini açıkça göstermektedir, çünkü bu durumda aralık 360/4 = 90 dereceye eşittir ve açık bir şekilde aralığın tam olarak elde edilebildiği açıktır.
Bu çözüm mükemmel değil: muhtemelen grafiği geliştirmek için elle çimdiklenebilecek birkaç yay tanımlayabilirsiniz. Ancak korkunç bir iş yapmayacak ve gerçekten iyi bir başlangıç gibi görünüyor.
Algoritma aynı zamanda basit olmanın da yararına sahiptir: en karmaşık kısım hedefleri rulmanlarına göre sıralamaktan ibarettir.
Kodlama
PostGIS'i tanımıyorum, ancak belki de örnekleri çizmek için kullandığım kod, bu algoritmayı PostGIS'te (veya başka bir GIS'de) uygulamak için bir rehber görevi görebilir.
Aşağıdakileri sahte kod olarak düşünün (ancak Mathematica bunu yürütecek :-). (Bu sitenin TeX destekleniyorsa matematik, istatistik, ve TCS olanlar gibi, ben bu yapabiliriz çok daha okunabilir.) Notasyonu içerir:
- Değişken ve işlev adları büyük / küçük harf duyarlıdır.
- [Alpha] bir küçük harf Yunan karakteridir. ([Pi], olması gerektiğini düşündüğünüz değere sahip.)
- x [[i]], x dizisinin i öğesidir (1'den başlayarak dizine alınmış).
- f [a, b], f fonksiyonunu a ve b argümanlarına uygular. 'Min' ve 'Table' gibi uygun durumda fonksiyonlar sistem tarafından tanımlanmıştır; 'Açılar' ve 'ofset' gibi ilk küçük harfli fonksiyonlar kullanıcı tanımlıdır. Yorumlar, belirsiz sistem işlevlerini ('Arg' gibi) açıklar.
- Tablo [f [i], {i, 1, n}], {f [1], f [2], ..., f [n]} dizisini oluşturur.
- [O, r, {a, b}] dairesi, yarıçapın r noktasında a açısından b açısına çevrilmiş dairenin bir yayını oluşturur (her ikisi de doğuya göre saatin tersi yönünde radyan).
- [X] siparişi, x'in sıralanmış öğelerinin bir dizinini döndürür. x [[Sipariş [x]]], x'in sıralanmış sürümüdür. Y, x ile aynı uzunluğa sahip olduğunda, y [[[x]]] sıralaması x ile paralel olarak y sıralar.
Kodun çalıştırılabilir kısmı merhametle kısadır - 20 satırdan daha kısadır - çünkü bunların yarısından fazlası bildirim yükü veya yorumlardır.
Bir harita çiz
z
hedeflerin listesi ve y
kökenidir.
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}]
}]
]
Noktasından, dairesel bir yay oluşturma x
noktasına y
açı başlayarak \[Beta]
> y yatak - X nisbetle.
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}]
]
Rulmanları bir kaynaktan bir nokta listesine kadar hesaplayın.
angles[origin_, x_] := Arg[Complex@@(#-origin)] & /@ x;
Bir yatak seti artıklarının orta aralığını hesaplayın.
x
Sıralı sıraya göre rulmanlar listesidir. İdeal olarak, 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
]