Eğri noktadan noktaya “rota haritaları”


39

Kısa bir süre önce belirli bir şehirden yola çıkarak rotalarını hizmet veren diğer tüm şehirlere yönlendiren havayollarının web sayfalarına bakıyorum. Noktalar arasında benzer eğimli yollar oluşturabilmek istiyorum. Bu örnekte gösterilenler gibi kavisli yaylar üretecek komut dosyaları veya fonksiyonlar üreten var mı?

Uçuş Yolları

PostGIS'te, 2 nokta bağlanırken kullanılacak eğri miktarını belirlemenizi sağlayacak bir ST_MakeLine uygulaması var mı?

Şu anda PostGIS ve QGIS'i kullanırken, aynı görünümü oluşturabilecek diğer yazılım seçeneklerini duymaktan memnuniyet duyarım.


Bunun güzel uygulamalarını bilen var mı? Örnekler ya da her neyse?
Mark Boulder,

Yanıtlar:


26

Harika çevreler oluşturmak size istenen etkiyi verebilir.

Belki de http://lists.osgeo.org/pipermail/postgis-users/2008-Febat/018620.html adresinde tartışıldığı gibi bir şey

Güncelleme:

Bu fikri “Global Connections Görselleştirme” bölümünde takip ettim . Yay oluşturmak için yeniden yapılanma kullanan tamamen PostGIS tabanlı bir çözümdür.

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

(953027 için CRS tanımını burada bulabilirsiniz: http://spatialreference.org/ref/esri/53027/ )

görüntü tanımını buraya girin


4
Büyük çevrelerde olmasına rağmen, karşılaştığınız sorun kısa mesafelerde hala genel olarak düz bir çizgiyle sonuçlanacağını düşünmek hoşuma gidiyor. Çizgiye koyduğum yay miktarını kontrol edebilmek istiyorum (yani yay = = uzaklık * 2).
RyanDalton

1
Harika çevrelerin kullanılmasıyla ilgili sorunun güzel bir örneği: gc.kls2.com/cgi-bin/…
RyanDalton

1
Bazı ek araştırmalardan sonra, bu yazıya bu yönteme yardım etmede yardımcı olabilecek bir yazı buldum. mail-archive.com/postgis-users@postgis.refractions.net/…
RyanDalton

Gelecekteki okuyucunun kullanımı için, devam edip @ underdark'in bu konuyu kapsayan son blog yazısına bağlayacağımı düşündüm. underdark.wordpress.com/2011/08/20/…
RyanDalton

Bu harika!! Projemde, kullanıcı checkinleri ve mekan konumları arasında çizgi çizmek, Forsquare
Lorenzo Barbagli

24

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

alt metin

alt metin

alt metin

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

zhedeflerin listesi ve ykö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 xnoktasına yaçı 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.

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

Bu çözümün varış noktalarını menşei çevreleyen az ya da çok varsaydığını söylemeliyim. Durum böyle olmadığında, fikrin tamamı (eşit aralıklarla yerleştirilmiş rulmanlar için) iyi bir fikir değildir. Ancak açısal boşluklara bazı sahte hedefler getirerek ve daha sonra bu hedefleri (ve yaylarını) kaldırarak kolayca düzeltilebilir. Bu işlem, rulmanlar arasındaki ortalama mesafenin hesaplanması ve büyük boşlukların, vb . Tanımlanması için kullanılmasıyla otomatikleştirilebilir .
whuber

Güzel grafikler. Havayollarının, uçuş dergilerinin arkasında gösterilen rota haritalarını hazırlarken otomatik bir araç kullanıp kullanmadıklarını merak ediyorum.
Kirk Kuykendall

1
@Kirk Muhtemelen birine elle haritacılık yapmak için para ödüyorlar :-). Basit bir yaklaşımın oldukça iyi grafikler yaratıp yaratmayacağını görmek için bu sorudan ilham aldım. Cevap umut verici görünüyor. Bu grafikler, Mathematica 8 tarafından Çember ve Nokta ilkellerini ve çember merkezlerini bulmak için küçük bir vektör aritmetiği kullanılarak üretildi .
whuber

Gösterdiğin sonucu seviyorum ve bu şekilde gitmeliyim. Yine de dürüst olacağım, kendimi teknik olarak değerlendiriyorum ama verdiğiniz formülden biraz kayboldum ve bunu PostGIS koduna nasıl çevireceğimiz neredeyse imkansız hale geldi. Dışarıdaki herkes, whuber'in konseptini uygulanabilir bir koda nasıl çevireceğine dair bir fikri var mı? Gözden geçirmeye ve denemeye çalışacağım, ancak yardım çok takdir edilecektir.
RyanDalton

@ whuber- Güncellenmiş sözde kod için teşekkürler. PostGIS’te uygulayabileceğimizi görmemiz gerekecek.
RyanDalton



3

@Nicklas Avén tarafından önerildiği gibi ST_CurveToLine işlevini kullanarak bir "iki nokta" çizgisi kümesini eğmek için bunu denemeye başladım.

Aşağıdaki 3 koordinat setini ST_OffsetCurve fonksiyonuna geçirdim:

  1. Orijinal satırın başlangıcı
  2. Orijinal çizgiye paralel bir çizginin orta noktası.
  3. Orijinal satırın sonu

Örneğimdeki orijinal çizginin uzunluğunun 1 / 10'u olan ofseti hesaplamak için ST_OffsetCurve işlevini kullandım.

İşte orijinal düz çizgilerden eğri çizgiler oluşturmak için kullandığım SQL:

    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

Gerçekten yararlı, ancak nedense sonuç, sırığımı saygılamıyor. Neden bir fikrin var mı?
DMS02

Daha fazla ayrıntı verebilir misiniz - giriş geometrisi srid, çıkış srid eksik, farklı, hatalar üretildi (hangi uygulamaları) - QGIS, PostgreSQL).
Brent Edwards,

Sonuçtaki eğri çizgileri eklemek istediğim tablonun enforce_srid_geom kısıtlaması var. Sorguyu çalıştırdığımda, bu sorgunun bu kısıtlamayı ihlal ettiğini söyleyen bir hata alıyorum. INSERT INTO testi (the_curved_geom) [SQL buradan] SEÇ hatları GELEN: kÛsÛtlamasÛna çalışır ama sonra QGIS eklemeden zaman 0. SRID Benim sorgu ile listelenir olmadan bir tablo ile
DMS02

Geometri sütunundaki (the_curved_geom) postgis.net/docs/ST_GeometryType.html ve postgis.net/docs/ST_SRID.html işlevlerini çalıştırmayı deneyin ve test tablonuzla ve zorlama testinizle çakışma olup olmadığını kontrol edin. Öyleyse, geometriyi / kızağı gerektiği gibi dönüştürebilir veya test tablonuzu / kısıtlamanızı değiştirebilirsiniz.
Brent Edwards
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.