Bir nokta ile iki lat / lng'lik sanal bir çizgi arasındaki mesafenin hesaplanması


14

Lütfen örneğe ve ilgili resme bakınız.

Aşağıdakileri başarmak istiyorum: aşağıda A ve B olarak gösterilen iki konum (lat / lng) sağlayın . Bundan sonra, sanal bir çizgi çizilecek ve daha sonra bu çizgi ile C arasındaki mesafe hesaplanacaktır (herhangi bir ölçümde).

çizim

Bunu şu anda Google Maps API v3'te başardım, ancak bunu kendi dilimde perde arkasında da gerçekleştirmek istiyorum. Herhangi bir ipucu / fikir büyük mutluluk duyacağız!


AB bir Great Circle hattı mıdır?
Kirk Kuykendall

@Kirk, Hayır, AB sadece düz bir çizgi
Mahkum

@Michael, bu ilginç bir nokta. Buna bir göz atmam gerekecek!
Mahkum

@ Mahkum @Kirk Kelimenin tam anlamıyla, dünya yüzeyinin altından bir "düz çizgi" geçecek. Genel olarak, yüzeye geri radyal izdüşümü gerçekten büyük bir dairenin bir parçası olacaktır (küresel bir dünya modeli kullanarak).
whuber

1
@Prisoner Bu son derece kullanışlı bir bilgi parçasıdır! Evet haklısın. Hala (lat, lon) kullanmanın kuzey-güney mesafelerine göre doğu-batı mesafelerini farklı şekilde bozduğu gerçeğini telafi etmeniz gerekir. @ Joseph'in önerdiği gibi, koordinatları yansıtın. Bu, boylamları ortalama enlemin kosinüsü ile önceden çarpmak ve sonra bir Öklid düzleminde gibi davranmak kadar basit olabilir.
whuber

Yanıtlar:


6
def get_perp( X1, Y1, X2, Y2, X3, Y3):
    """************************************************************************************************ 
    Purpose - X1,Y1,X2,Y2 = Two points representing the ends of the line segment
              X3,Y3 = The offset point 
    'Returns - X4,Y4 = Returns the Point on the line perpendicular to the offset or None if no such
                        point exists
    '************************************************************************************************ """
    XX = X2 - X1 
    YY = Y2 - Y1 
    ShortestLength = ((XX * (X3 - X1)) + (YY * (Y3 - Y1))) / ((XX * XX) + (YY * YY)) 
    X4 = X1 + XX * ShortestLength 
    Y4 = Y1 + YY * ShortestLength
    if X4 < X2 and X4 > X1 and Y4 < Y2 and Y4 > Y1:
        return X4,Y4
    return None

En kısa uzunluk, yanılmıyorsam gereken mesafedir.


Evet, C ile hat segmenti arasındaki en kısa mesafeyi arıyorum. Bu matematiğin hesapladığı bu mu?
Mahkum

1
Gerçekten işe yaradı, aşağıdaki üç noktayı (A, B, C) geçtim : i.imgur.com/bK9oB.jpg ve X'in lat / lng'si ile geri döndü. Harika iş!
Mahkum

1
@Hairy, Son bir şey, bunu en yakın noktaya (sadece çizgiye değil) gidecek şekilde nasıl değiştirebilirim? nokta?
Mahkum

1
@Kıllı İyi bir başlangıç, ancak Nonemeşru bir çözüm olduğunda bu kodun çok sık döndüğü anlaşılıyor . Sorun, son şartın X1 <X2 ve Y1 <Y2 olduğunu varsayar ki bu her zaman garanti edilemez. Daha iyi bir ilişki testi gereklidir.
whuber

1
@Hairy Kendinizle @prisoner arasındaki bu alışverişin verimli olduğu anlaşılıyor. Oylamada veya meydana gelebilecek herhangi bir değişiklikte herhangi bir değişiklik (veya kontrol üzerinde) olmadığımı ve yorumumun sadece cevabınızı geliştirmenize yardımcı olması gerektiğini vurgulamak isterim.
whuber

11

Belki çok karmaşık hale getiriyorum, ama istediğiniz bir noktadan çizgiye olan uzaklık. AB ile C'yi AB'ye dik bir çizgi ile bağlayan AB boyunca bir noktaya olan uzaklık. AB'ye dik olan bu vektör,

v=[x2-x1, -(y2-y1)] # Point A is [x1,y1] Point B is [x2,y2]

(Bir vektör veya iki elemanlı bir dizi tanımlamak için köşeli parantez kullandım). C [xp, yp] ve A noktası arasındaki mesafe

u=[x1-xp, y1-xp]

Çizgi ve C arasındaki mesafe sadece u'nun v'ye izdüşümüdür. Mod (v) = 1 varsayalım (sadece normalleştirin), o zaman

distance = u*v = abs( (x2-x1)*(y1-yp) - (x1-xp)*(y2-y1) )

Tek sorun, muhtemelen koordinatlarınızın WGS84 lat / log çiftleri değil, öngörülen (veya jeodezik koordinatları kullanma) olduğundan emin olmak istediğinizdir. Bunun için OGR veya Proj4 kullanabilirsiniz .


3
+ Bu arada, trigonometrik işlevleri kullanmadığı için birkaç milyon sahte nokta. Çok fazla insan buna bakmaları gerektiğinde ArcTan'ı çıkarıyor: en.wikipedia.org/wiki/Dot_product
Herb

@Jose, cevap için teşekkürler! Google Maps API'dan lat / long kullanıyorum. Matematik bölümü benim için oldukça yeni, bu yüzden bir deneyeceğim ve neler yapabileceğimi göreceğim. Matematik ile ilgili herhangi bir ipucu var mı? Örneğin [x2-x1, - (y2-y1)], bu ne anlama geliyor?
Mahkum

Bunun için kısa bir düzenleme ekledim. Temel olarak, bu bir dizi gösterimidir, ancak koordinatlarınızı x1, x2, y1, y2 ve xp, yp değişkenlerinde saklarsanız, yalnızca sağladığım son denklemin sağ tarafını yazmanız gerekir. Bu hemen hemen geçerli C, Java, JS, Python vb kod :)
Jose

1
Bu C arasındaki mesafeyi hesaplamak edilir @Jose hattı AB. Şekle dayanarak, OP'nin C'den AB çizgi segmentine kadar mesafe olmasını istediğine inanıyorum . Bu, C'nin AB çizgisine projeksiyonunun A ve B arasında olup olmadığını kontrol etmek için ekstra çalışma gerektirir. İkinci durumda, CA ve CB iki uzunluktan daha kısa kullanın.
whuber

1
@Prisoner Temel fark, bir çizginin sonsuza kadar uzanmasıdır (yalnızca bir yön vektörü ve bir nokta veya iki nokta ile tanımlanır), A ve B arasındaki bir segment, A ve A arasındaki sonsuz çizginin bitidir. B (sınırlı bir uzunluğa sahiptir)
Jose

4

Tüm bu matematiğe biraz karşı, farklı bir açıdan gelirdim. Bunu sanal bir çizgi yerine 'gerçek' bir çizgi haline getirir ve mevcut araçları kullanırdım.

A ve B bir özniteliği paylaşırsa, bunları bir çizgi çizerek bağlayabilirsiniz (Kosmo GIS, noktalardan çizgiler oluşturacak bir araca sahiptir ve bunun için bir QGIS eklentisi olduğuna inanıyorum). Çizgilere sahip olduğunuzda, 'C' nokta katmanındaki 'yakın' işlevi size çizgiye olan mesafeyi verecektir. Yazılım sizin için matematik işleyelim!


Yorum için teşekkürler ama Hairy bu bir koz geldi!
Mahkum

1
(+1) Mükemmel bir noktaya değindin. Hesaplamalı geometri algoritmaları uygulamada tamamen doğru olmak için çok zordur (şimdiye kadar sunulan tüm kodlardan görebildiğimiz gibi, yararlı ve açıklayıcıdır, ancak henüz tam olarak çalışmaz). Üst düzey bir CBS prosedürü kullanmak, beklediğiniz yanıtı aldığınızdan ve doğru olduğundan emin olmanın iyi bir yoludur (CBS'nize güvenmeniz koşuluyla ;-).
whuber

1

Android'de java kullanıyorsanız, kütüphane işlevine sahip tek satır

import static com.google.maps.android.PolyUtil.distanceToLine;

distanceToLine:

public static double distanceToLine(LatLng p, LatLng start,LatLng end)

Küre üzerindeki p noktası ile çizgi parçası başlangıcı arasındaki mesafeyi hesaplar.

Parametreler: p - ölçülecek nokta

başlangıç ​​- çizgi segmentinin başlangıcı

end - çizgi segmentinin sonu

Döndürür: metre cinsinden mesafe (küresel dünya olduğu varsayılarak)

Sadece kitaplığınıza kitaplık ekleyin.

dependencies {
    compile 'com.google.maps.android:android-maps-utils:0.5+'
}
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.