Yakınlarda rastgele konumlar oluşturuluyor mu?


30

Konumumun yakınında rasgele yerler oluşturmaya çalışıyorum. İstediğim yerimi çevreleyen 200 metrelik bir çember içerisinde rastgele enlem / boylam çiftleri oluşturmak.

Bu benim karşılaştığım formül (StackOverFlow'daki insanların yardımıyla): (-1 ile 1 arasındaki rasgele sayı) * radius + (eski boylam) = eski boylamın yarıçapı içindeki yeni boylam

(-1 ile 1 arasında rasgele sayı) * yarıçapı + (eski enlem) = eski enlem yarıçapı içindeki yeni enlem

Mesele şu ki, uygulamamla ilgili garip bir şey oluyor; çünkü tüm rastgele yerler konum merkezime çok yakın, formül tüm yarıçapı kapsamıyor gibi görünüyor.

Formülümde neyin yanlış olabileceği hakkında bir fikrin var mı?

Mevcut java uygulamasını göstermek için düzenlenmiştir:

public static Location getLocation(Location location, int radius) {
    Random random = new Random();

    // Convert radius from meters to degrees
    double radiusInDegrees = radius / METERS_IN_DEGREES;

    double x0 = location.getLongitude() * 1E6;
    double y0 = location.getLatitude() * 1E6;
    double u = random.nextInt(1001) / 1000;
    double v = random.nextInt(1001) / 1000;
    double w = radiusInDegrees * Math.sqrt(u);
    double t = 2 * Math.PI * v;
    double x = w * Math.cos(t);
    double y = w * Math.sin(t);

    // Adjust the x-coordinate for the shrinking of the east-west distances
    double new_x = x / Math.cos(y0);

    // Set the adjusted location
    Location newLocation = new Location("Loc in radius");
    newLocation.setLongitude(new_x + x0);
    newLocation.setLatitude(y + y0);

    return newLocation;
}

Neyi yanlış yaptığımdan emin değilim, çünkü yeni yerler denizin ortasında yaratılmış.

Herhangi bir fikir?


Bu formülü nasıl uyguluyorsunuz? Kodunuzun bu bölümünü sunabilir misiniz? Pseudorandom sayı üretecinde sorununuz olabilir mi?
Alex Markov

Son soruya gelince, bu gibi prosedürler böyle sorunlarla karşı karşıya kalmaktadır; Coğrafi bir koordinat sistemi yerine öngörülen bir koordinat sistemi kullanmak genellikle her iki sorunun da üstesinden gelir. Bunu yapmak, formülünüzün temel bir özelliğini ortaya çıkarır, bu arzu edilebilir veya istenmeyebilir: bir daire içinde değil, bir konum etrafındaki bir dikdörtgen içerisinde konumlar oluşturur .
whuber

Teşekkürler Alex, Java kodu stackoverflow'ta yayınlandı: stackoverflow.com/questions/10682743/…
pindleskin

Düzenlenen kod: (i) random.nextInt(1001)/1000zamanın% 1 ila% 1'inden daha büyük bir değer döndürecektir. Neden kullanmıyorsunuz random.nextDoubleya random.nextFloat? (ii) çarpma x0ve y0ile 1E6oldukça gizemlidir; doğru sonuçlar üretecek gibi görünmüyor.
whuber

Doğru, nextDouble kullanarak yöntemi düzenledi ve 1E6 kurtuldum. Şimdi, rastgele oluşturulan tüm konumlar, konumum ile aynı koordinatlara sahip. Yardımın için teşekkürler, yakında herhangi bir zamanda çözeceğim gibi görünüyor
pindleskin

Yanıtlar:


46

Bu iki nedenden dolayı zor: ilk olarak noktaları bir kare yerine bir daireyle sınırlamak; ikincisi, uzaklık hesaplarındaki çarpıklıkları hesaba katarak

Birçok CBS'de her iki komplikasyonun otomatik ve şeffaf bir şekilde ele alınabildiği yetenekler bulunmaktadır. Bununla birlikte, buradaki etiketler, bir algoritmanın GIS'den bağımsız bir tanımının istenebileceğini göstermektedir.

  1. Noktaları oluşturmak için homojen, rastgele ve bağımsız bir şekilde bir daire içinde yarıçapı r bir yerde (x0, y0) çevresinde, iki bağımsız tek tip rasgele değerlerinin üretilmesi başlamak u ve v aralığı [0, 1) 'de. (Bu hemen hemen her rasgele sayı üretecinin sağladığı şeydir.) Hesapla

    w = r * sqrt(u)
    t = 2 * Pi * v
    x = w * cos(t) 
    y = w * sin(t)

    İstenilen rastgele nokta konumdadır (x + x0, y + y0).

  2. Coğrafi (enlem, boylam) koordinatlarını kullanırken, o zaman x0 (boylam) ve y0 (enlem) derece cinsinden olacaktır, ancak r büyük olasılıkla metre (veya fit veya mil veya başka bir doğrusal ölçüm) olacaktır. İlk önce, yarıçapı r , ekvatorun yanına yerleştirilmiş gibi dereceye dönüştürün . Burada, bir derece yaklaşık 111.300 metre var.

    İkinci olarak, daha sonra üretilmesi x ve y adım (1) 'de olduğu gibi, ayarlama doğu-batı mesafelerin küçülme için x koordinatı:

    x' = x / cos(y0)

    İstenilen rasgele nokta konumdadır (x '+ x0, y + y0). Bu yaklaşık bir prosedürdür. Dünyanın her iki kutbuna yayılmayan küçük yarıçaplarda (birkaç yüz kilometreden daha az), her merkezin etrafında onbinlerce rastgele nokta oluştururken bile herhangi bir hatayı tespit edemezsiniz (x0, y0). .


2
Harika bir açıklama whuber, bilmem gereken buydu. Şimdi ben uygulayacağım. Thanks
pindleskin


1
"Bir dereceye kadar yaklaşık 111.300 metre var" sadece virgülün bin ayırıcı olarak kullanıldığını not etmek için. radiusInDegrees = yarıçap / 111300
RMalke

2
lat için, uzun koordinatlar x '= x / cos (y0 * Pi / 180)
yapmamalısınız

2
Zihin @ whuber şişmiş ve mantıklı. Ona bakmanın bir başka yolu sanırım 20'lik bir yarıçap için 55 rastgele yarıçapın üretildiğini hayal etmek. Her rastgele yarıçapın tek tip olduğunu ve tam olarak 0 ila 20, yani 0, 2, 4, ..., 20 olduğunu söyleyelim. Böylece, yarıçapı 5, 2 yarıçapı 2, vb. Olan 5 nokta olacaktır. 2 yarıçapı olan 5 (yarıçapı 2 dairesi) olan 5 nokta, yarıçaplı 5 noktadan birbirine çok daha yakın görünecektir. 20
Aziz Javed

11

Javascript için uygulandı:

var r = 100/111300 // = 100 meters
  , y0 = original_lat
  , x0 = original_lng
  , u = Math.random()
  , v = Math.random()
  , w = r * Math.sqrt(u)
  , t = 2 * Math.PI * v
  , x = w * Math.cos(t)
  , y1 = w * Math.sin(t)
  , x1 = x / Math.cos(y0)

newY = y0 + y1
newX = x0 + x1

10

Doğru uygulama:

public static void getLocation(double x0, double y0, int radius) {
    Random random = new Random();

    // Convert radius from meters to degrees
    double radiusInDegrees = radius / 111000f;

    double u = random.nextDouble();
    double v = random.nextDouble();
    double w = radiusInDegrees * Math.sqrt(u);
    double t = 2 * Math.PI * v;
    double x = w * Math.cos(t);
    double y = w * Math.sin(t);

    // Adjust the x-coordinate for the shrinking of the east-west distances
    double new_x = x / Math.cos(Math.toRadians(y0));

    double foundLongitude = new_x + x0;
    double foundLatitude = y + y0;
    System.out.println("Longitude: " + foundLongitude + "  Latitude: " + foundLatitude );
}

Daha erişilebilir hale getirmek için dış kütüphanelere olan bağımlılığı kaldırdım.


Önerilen OP düzenlemesi Bu yığın akışına göre Q&A, Java Math.cos () içinde girişleri radyan olarak bekliyor.
MikeJamam5656

3

Kabul edilen cevaplar ve türevler benim için işe yaramadı. Sonuçlar çok yanlıştı.

Javascript'te doğru uygulama:

function pointAtDistance(inputCoords, distance) {
    const result = {}
    const coords = toRadians(inputCoords)
    const sinLat =  Math.sin(coords.latitude)
    const cosLat =  Math.cos(coords.latitude)

    /* go a fixed distance in a random direction*/
    const bearing = Math.random() * TWO_PI
    const theta = distance/EARTH_RADIUS
    const sinBearing = Math.sin(bearing)
    const cosBearing =  Math.cos(bearing)
    const sinTheta = Math.sin(theta)
    const cosTheta =    Math.cos(theta)

    result.latitude = Math.asin(sinLat*cosTheta+cosLat*sinTheta*cosBearing);
    result.longitude = coords.longitude + 
        Math.atan2( sinBearing*sinTheta*cosLat, cosTheta-sinLat*Math.sin(result.latitude )
    );
    /* normalize -PI -> +PI radians (-180 - 180 deg)*/
    result.longitude = ((result.longitude+THREE_PI)%TWO_PI)-Math.PI

    return toDegrees(result)
}

function pointInCircle(coord, distance) {
    const rnd =  Math.random()
    /*use square root of random number to avoid high density at the center*/
    const randomDist = Math.sqrt(rnd) * distance
    return pointAtDistance(coord, randomDist)
}

Burada tam özü

Kabul edilen cevapta - noktaların eninin 1,5 katı yüksekliğinde (Panama'da) ve 8 katı yüksekliğinde (İsveç'in kuzeyinde) bir elips şeklinde dağıldığını tespit ettim. @ Koordinat ayarını @ whuber'un cevabından çıkardıysam, elips diğer yoldan, genişliği 8 kat daha fazla bozulur.

Cevabımdaki kod buradan gelen algoritmalara dayanıyordu.

Aşağıda, germe elipsindeki sorunu gösteren iki jsfiddles görebilirsiniz

Doğru algoritma

Bozuk algoritma


Karşılaştığınız sorunları açıklamanız, uygulamanızın yanlış olduğunu gösteriyor.
whuber

Gayet haklı olabilirsiniz. Yaptığım jsfiddles’a bir göz atmak ve bana nerede yanlış gittiğimi söylemek ister misin?
Julian Mann

Yukarıda ATOK Java cevap kıyasla ve distored algoritma sizin jsfiddle için bu değişikliği yaptık whuberPointAtDistance(): x1 = (w * Math.cos(t)) / Math.cos(y0 * (Math.PI / 180)).
Matt

1
Düzeltmeme rağmen, Julian'ın özü ile çok daha doğru sonuçlar aldım. Düzeltmelerimi whuberPointAtDistance () 'a ekledim ve hata raporuyla özünde çalıştırdım, her üç senaryoda da% 0.05 hata gösterdi (alternatiften önemli ölçüde daha yüksek).
Mat

1

Python'da

# Testing simlation of generating random points 
from __future__ import division
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1 import host_subplot
import mpl_toolkits.axisartist as AA

def create_random_point(x0,y0,distance):
    """
            Utility method for simulation of the points
    """   
    r = distance/ 111300
    u = np.random.uniform(0,1)
    v = np.random.uniform(0,1)
    w = r * np.sqrt(u)
    t = 2 * np.pi * v
    x = w * np.cos(t)
    x1 = x / np.cos(y0)
    y = w * np.sin(t)
    return (x0+x1, y0 +y)

fig = plt.figure()
ax = host_subplot(111, axes_class=AA.Axes)

#ax.set_ylim(76,78)
#ax.set_xlim(13,13.1)
ax.set_autoscale_on(True)

latitude1,longitude1 = 13.04738626,77.61946793  
ax.plot(latitude1,longitude1,'ro')

for i in range(1,20):
    x,y = create_random_point(latitude1,longitude1 ,500 )
    ax.plot(x,y,'bo')
    dist = haversine(x,y,latitude1,longitude1)
    print "Distance between points is " ,dist    # a value approxiamtely less than 500 meters   


plt.show()

Çıktı

Puanlar arasındaki mesafe 0.288044147914 Puanlar arasındaki mesafe 0,409557451806 Puanlar arasındaki mesafe 0,368260305716 Puanlar arasındaki mesafe 0,340720560546 Puanlar arasındaki mesafe 0,453773334731 Puanlar arasındaki mesafe 0,460608754561 puan Puanları arasındaki mesafe 0.503691568896 Puanları arasındaki uzaklık 0.175153349209 Puanları arasındaki uzaklık 0.195149463735 Puanları arasındaki mesafe 0.424094009858 Puanları arasındaki mesafe 0.286807741494 Puanları arasındaki mesafe 0.558049206307.

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


0

Eğer hesaplamaların sonuçlarını kontrol edebilirsiniz burada . "Hedef noktaya mesafe verilen ve başlangıç ​​noktasından gelen yatak" adlı bölüme gidin. Bunu uygulamak için altta basit bir JavaScript formülü bile var. Radyan olarak $ \ theta $ taşıyan (kuzeyden saat yönünde ölçülen) rasgele bir yatak oluşturmaya ihtiyacınız olacak, ancak bu oldukça açık bir şekilde ilerlemeli. Bu formüller,% 0.3'e kadar hatalar ürettiği için yeterince iyi olan küresel bir dünya (elipsoidal olmasına rağmen) varsaymaktadır.


0

Swift için uygulama

Geoencoder'dan lat ve lng'yi almak ve bu fonksiyona geçirmek

func generateRandomLocation(lat: CLLocationDegrees, lng: CLLocationDegrees){
    let radius : Double = 100000 // this is in meters so 100 KM
    let radiusInDegrees: Double = radius / 111000
    let u : Double = Double(arc4random_uniform(100)) / 100.0
    let v : Double = Double(arc4random_uniform(100)) / 100.0
    let w : Double = radiusInDegrees * u.squareRoot()
    let t : Double = 2 * Double.pi * v
    let x : Double = w * cos(t)
    let y : Double = w * sin(t)

    // Adjust the x-coordinate for the shrinking of the east-west distances
    //in cos converting degree to radian
    let new_x : Double = x / cos(lat * .pi / 180 )

    processedLat = new_x + lat
    processedLng = y + lng

    print("The Lat are :- ")
    print(processedLat)
    print("The Lng are :- ")
    print(processedLng)
}

Yukarıdaki örneğimde, ülkenin adını coğrafi kodlamadan enlem ve boylamları alıyorum, her seferinde olduğu gibi, ülke ismi de aynı enlem ve boylamları veriyor, bu da ülkenin ortasında, bu yüzden rastgelelik gerekiyordu.


-1

özel boşluk drawPolyline (çift lat, çift lng) {

         double Pi=Math.PI;

         double lt=lat;
         double ln=lng;

        //Earth’s radius, sphere
         double R=6378137;

         double dn = 50;
         double de = 50;

         //Coordinate offsets in radians
         double dLat = dn/R;
         double dLon = de/(R*Math.cos(Pi*lat/180));

        //OffsetPosition, decimal degrees
        double lat2 = lt + dLat * 180/Pi;
        double lon2 = ln + dLon * 180/Pi ;



            //12.987859, 80.231038
            //12.987954, 80.231252

        double lat3 = lt - dLat * 180/Pi;
        double lon3 = ln - dLon * 180/Pi ;

            LatLng origin=new LatLng(lt, lon3);

            LatLng dest=new LatLng(lt, lon2);




          Polyline line = googleMap.addPolyline(new PolylineOptions()
         .add(origin, dest)
         .width(6)
         .color(Color.RED));

5
Bunun OP'lerin sorunlarını nasıl çözdüğü üzerine biraz daha genişleyebilir ve kodunuzun kodunu açıklayabilir misiniz?
Martin,
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.