GPS konumlarıyla yakın noktaları nasıl gruplayabilirim?


10

Ben bir BT insanıyım, bu yüzden projeksiyonlar hakkında çok fazla şey bilmiyorum ve umarım bana yardımcı olabilirsiniz.

Android için bir GPS konumu toplayan bir uygulama yaptım, bu yüzden belirli bir zamanda enlem ve boylam var. Birbirine yakın olan öğeleri , aynı fiziksel büyüklükteki arazi alanı gruplarında birlikte kaydetmek istiyorum ; Sorun şu ki , noktaları önceden bilmiyorum ve dünyanın herhangi bir yerinden gelebilirler .

İlk fikrim (sorunu biraz daha açıklamak için) enlemin ondalık sayılarını ve gruplama için boylamı kullanmaktı; örneğin, bir grup 35.123 ile 35.124 arasında enlem ve 60.101 ile 60.102 arasında enlem olan konumlar olacaktır. Yani lat = 35.1235647 ve lon = 60.1012254598 gibi bir konum alırsam, bu nokta o gruba gider.

Bu çözüm, 0.001 birim genişliğinde ve yüksekliğinde alanlara sahip olacağım için, kartezyen bir 2D temsil için uygun olacaktır; ancak, 1 derece boylam boyutu farklı enlemlerde farklı olduğu için bu yaklaşımı kullanamam.

Herhangi bir fikir?


Neden pozisyonu olduğu gibi saklayamıyor ve daha sonra işlemeyi daha sonra yapamıyorsunuz? Ekvatorda, 1 boylam derecesi yaklaşık 111 km'dir, bu nedenle 0.001 derece 1 Km'den biraz daha fazla olacaktır. Kutularınızı gerçekten bu kadar büyük mü istiyorsun?
Devdatta Tengshe

0.001 derecesi benim fikrimin sadece bir örneğiydi. Tabii ki gereksinimlere uyarlamak zorunda kalacağım. Gerçek zamanlı bir uygulama olması planlandığı için bir post-işlem yapamam ve kullanıcılarıma "yarına kadar beklemem diyemem , çünkü noktaları gruplandırmak zorundayım" Yine de fikirler için teşekkürler;)
Kuu

Yanıtlar:


6

Hızlı ve kirli bir yol, tekrarlayan küresel bir alt bölüm kullanır . Dünya yüzeyinin bir üçgenlemesinden başlayarak, her üçgeni bir tepe noktasından en uzun kenarının ortasına kadar tekrar tekrar bölün. (İdeal olarak üçgeni iki eşit çaplı parçaya veya eşit alan parçasına bölebilirsiniz, ancak bunlar biraz hesaplama içerdiğinden, kenarları tam olarak ikiye böldüm: bu, çeşitli üçgenlerin sonunda biraz değişmesine neden olur, ancak bu uygulama için kritik görünmüyor.)

Tabii ki bu alt bölümü, herhangi bir keyfi noktanın bulunduğu üçgeni hızlı bir şekilde tanımlamaya izin veren bir veri yapısında koruyacaksınız. Bir ikili ağaç (özyinelemeli çağrılara dayalı olarak) güzel çalışır: bir üçgen her bölünüşünde, ağaç bu üçgenin düğümüne bölünür. Yarma düzlemi ile ilgili veriler korunur, böylece herhangi bir keyfi noktanın düzlemin hangi tarafında bulunduğunu hızlı bir şekilde belirleyebilirsiniz: bu, ağacın sola mı yoksa sağa mı gidileceğini belirler.

Evet - eğer dünyanın yüzeyini bir küre olarak modelleyip jeosantrik (x, y, z) koordinatlarını kullanırsanız, hesaplamalarımızın çoğu üçgenin kenarlarının parça olduğu üç boyutta gerçekleşir. kürenin kökeni boyunca düzlemlerle kesişimleri . Bu hesaplamaları hızlı ve kolay hale getirir.)


Prosedürü bir kürenin bir oktanında göstererek açıklayacağım; diğer yedi oktant da aynı şekilde işlenir. Böyle bir oktan 90-90-90 üçgendir. Grafiklerimde, aynı köşeleri kapsayan Öklid üçgenleri çizeceğim: küçülene kadar çok iyi görünmüyorlar, ancak kolayca ve hızlı bir şekilde çizilebilirler. İşte oktata karşılık gelen Öklid üçgeni: prosedürün başlangıcıdır.

Şekil 1

Tüm taraflar eşit uzunlukta olduğundan, biri "en uzun" olarak rastgele seçilir ve alt bölümlere ayrılır:

şekil 2

Yeni üçgenlerin her biri için bunu tekrarlayın:

Figür 3

N adımdan sonra 2 ^ n üçgenimiz olacak. İşte 10 adımdan sonra, oktanda 1024 üçgen (ve genel olarak kürede 8192) gösteren durum:

Şekil 4

Başka bir örnek olarak, bu oktan içinde rastgele bir nokta oluşturdum ve üçgenin en uzun tarafı 0.05 radyandan daha azına ulaşana kadar alt bölüm ağacını dolaştım. (Kartezyen) üçgenler prob noktası kırmızı ile gösterilir.

Resim 5

Bu arada, bir noktanın konumunu bir enlem derecesine (yaklaşık) daraltmak için, bunun yaklaşık 1/60 radyan olduğunu ve böylece (1/60) ^ 2 / (Pi / 2) = 1/6000 toplam yüzey. Her alt bölüm yaklaşık olarak üçgen boyutunu yarıya indirdiğinden, oktanın yaklaşık 13 ila 14 alt bölümü hile yapacaktır. Bu çok fazla hesaplama değil - aşağıda göreceğimiz gibi - ağacı hiç saklamamayı değil, altbölümü anında gerçekleştirmeyi verimli hale getiriyor. Başlangıçta, noktanın hangi oktantta yattığını not edersiniz - bu, üç basamaklı bir ikili sayı olarak kaydedilebilen üç koordinatının işaretleri ile belirlenir - ve her adımda noktanın yalan söyleyip söylemediğini hatırlamak istersiniz üçgenin solunda (0) veya sağında (1). Bu başka bir 14 haneli ikili sayı verir. Bu kodları rasgele noktaları gruplamak için kullanabilirsiniz.

(Genellikle, iki kod gerçek ikili sayılara yakın olduğunda, karşılık gelen noktalar yakındır; ancak, noktalar hala yakın olabilir ve oldukça farklı kodlara sahip olabilir. Örneğin, Ekvator'u bir metre aralıklarla ayıran iki noktayı düşünün: kodları bile farklı olmalıdır çünkü farklı oktanlar içindedir. Bu tür bir şey uzayın sabit bir şekilde bölünmesi ile kaçınılmazdır.)


Bunu uygulamak için Mathematica 8'i kullandım : en sevdiğiniz programlama ortamındaki bir uygulama için olduğu gibi veya sözde kod olarak alabilirsiniz.

Düzlem 0-ab noktası p'nin hangi tarafında bulunduğunu belirleyin :

side[p_, {a_, b_}] := If[Det[{p, a, b}] >=  0, left, right];

Üçgen abc noktasını p noktasına göre daraltın.

refine[p_, {a_, b_, c_}] := Block[{sides, x, y, z, m},
  sides = Norm /@ {b - c, c - a, a - b} // N;
  {x, y, z} = RotateLeft[{a, b, c}, First[Position[sides, Max[sides]]] - 1];
  m = Normalize[Mean[{y, z}]];
  If[side[p, {x, m}] === right, {y, m, x}, {x, m, z}] 
  ]

Son şekil, oktanı görüntüleyerek ve bunun üzerine, aşağıdaki listeyi bir çokgen kümesi olarak oluşturarak çizildi:

p = Normalize@RandomReal[NormalDistribution[0, 1], 3]        (* Random point *)
{a, b, c} = IdentityMatrix[3] . DiagonalMatrix[Sign[p]] // N (* First octant *)
NestWhileList[refine[p, #] &, {a, b, c}, Norm[#[[1]] - #[[2]]] >= 0.05 &, 1, 16]

NestWhileListrefinebir durum söz konusu olduğunda (üçgen büyüktür) veya maksimum çalışma sayısına ulaşılana kadar bir işlemi ( ) tekrar tekrar uygular (16).

Oktanın tam üçgenlemesini göstermek için ilk oktanla başladım ve arıtmayı on kez tekrarladım. Bu, aşağıdakilerin hafif bir modifikasyonu ile başlar refine:

split[{a_, b_, c_}] := Module[{sides, x, y, z, m},
  sides = Norm /@ {b - c, c - a, a - b} // N;
  {x, y, z} = RotateLeft[{a, b, c}, First[Position[sides, Max[sides]]] - 1];
  m = Normalize[Mean[{y, z}]];
  {{y, m, x}, {x, m, z}}
  ]

Fark, belirli bir noktanın bulunduğu üçgen yerine giriş üçgeninin her iki yarısını da splitdöndürmesidir . Tam nirengi, bunun tekrarlanmasıyla elde edilir:

triangles = NestList[Flatten[split /@ #, 1] &, {IdentityMatrix[3] // N}, 10];

Kontrol etmek için, her üçgenin büyüklüğünün bir ölçüsünü hesapladım ve aralığa baktım. (Bu "boyut", her bir üçgen ve kürenin merkezi tarafından incelenen piramit şeklindeki şekil ile orantılıdır; bunlar gibi küçük üçgenler için, bu boyut esas olarak küresel alanı ile orantılıdır.)

Through[{Min, Max}[Map[Round[Det[#], 0.00001] &, triangles[[10]] // N, {1}]]]

{0.00523, 0.00739}

Böylece, boyutlar ortalamalarından yaklaşık% 25 oranında artar veya azalır: bu, grup noktalarına yaklaşık olarak eşit bir yol elde etmek için makul görünüyor.

Bu kodu tararken, hiçbir trigonometri görmezsiniz : ihtiyaç duyduğu tek yer, eğer varsa, küresel ve kartezyen koordinatlar arasında ileri geri dönüştürme olacaktır. Kod ayrıca dünyanın yüzeyini herhangi bir haritaya yansıtmaz, böylece eşlik eden bozulmaları önler. Aksi takdirde, tüm işi yapmak için sadece ortalama ( Mean), Pisagor Teoremi ( Norm) ve 3'e 3 belirleyici ( Det) kullanır. ( Her üçgenin en uzun tarafının aranmasıyla birlikte RotateLeftve gibi bazı basit liste işleme komutları vardır Flatten.)


1

Bu zor bir şey, çünkü projeksiyonlar 3D WGS84 coğrafi koordinat sisteminden düz bir 2D projeksiyona geçerken bozulma sağlıyor. Küresel ölçekte, sistemin herhangi bir yerinde bozulmalara maruz kalırsınız.

Bence en iyi seçim Evrensel Enine Mercator projeksiyonuna yansıtmak . Bildiğim kadarıyla bu en yakın çarpıklık ile küresel bir projeksiyon elde edebilirsiniz.

Grupların tam olarak aynı boyuttaki alanlarda tanımlanması gereken gereksinimleri ve gerçek zamanlı işleme gereksinimini gevşetebiliyorsanız , DBSCAN ve bir türev ailesi gibi gruplama üretmeye yardımcı olabilecek kümeleme algoritmaları vardır .


1
UTM bir "küresel projeksiyon" değildir: gösteri, (500000, 5000000) gibi hemen hemen her geçerli koordinat çiftinin, UTM sistemindeki en az 120 ayrı genişçe ayrılmış noktaya karşılık geldiğidir. Ve ne yazık ki, kümeleme algoritmaları OP'nin puanları gerçek zamanlı olarak yalnızca konumlarına (ve diğer noktalara olan yakınlıklarına göre) göre gruplama gereksinimlerini karşılamıyor .
whuber

@whuber re: "küresel projeksiyon" - doğru. Bu yüzden "küresel bir projeksiyona en yakın olabileceğinizi" söyledim. Daha uygun olan daha iyi bir projeksiyon sistemi biliyorsanız, lütfen yorumlarda bırakın ve cevabımı düzenleyeceğim. Ayrıca, OP'nin ilk gönderide gerçek zamanlı bir gereksinimi yoktu. Bunu dikkate almak için cevabımı düzenleyeceğim.
Sean Barbeau

Sean, (1) Küresel projeksiyon problemine benim çözümüm bir tane kullanmak değil. Orada var olan hiçbir tekilliklerden olmadan küresel projeksiyon. (2) Doğru, gerçek zamanlı açıklama bir yorumda ortaya çıktı. “İlk fikrim” i takip eden metin iyi bir iş çıkarıyor, ancak bu sorunun bir dizi yeri kümelemekten ziyade dünyanın yüzeyini bölmek olduğunu vurguluyor . Bu, (daha etkili bir şekilde değil) size önceki yorumumda karşılaşmaya çalıştığım nokta.
whuber
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.