पास के यादृच्छिक स्थानों को उत्पन्न करना?


30

मैं अपने स्थान के पास यादृच्छिक स्थान बनाने का प्रयास कर रहा हूं। मैं जो चाहता हूं, वह मेरे स्थान के आसपास 200 मीटर सर्कल के अंदर यादृच्छिक अक्षांश / देशांतर जोड़े बनाना है।

यह वह सूत्र है जिसके साथ मैं (StackOverFlow में लोगों की मदद से) आया: (यादृच्छिक संख्या -1 और 1 के बीच) * त्रिज्या + (पुराना देशांतर) = पुराने देशांतर के त्रिज्या के भीतर नया देशांतर

(यादृच्छिक संख्या -1 और 1 के बीच) * त्रिज्या + (पुराना अक्षांश) = पुराने अक्षांश के दायरे में नया अक्षांश

बात यह है कि मेरे कार्यान्वयन के साथ कुछ अजीब हो रहा है क्योंकि सभी यादृच्छिक स्थान मेरे स्थान केंद्र के पास हैं, ऐसा लगता है कि सूत्र पूरे त्रिज्या को कवर नहीं करता है।

मेरे फॉर्मूले में गलत होने का कोई विचार हो सकता है?

वर्तमान जावा कार्यान्वयन को दिखाने के लिए संपादित:

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;
}

मुझे यकीन नहीं है कि मैं क्या गलत कर रहा हूं, क्योंकि नए स्थान समुद्र के बीच में बनाए गए हैं।

कोई उपाय?


आप इस सूत्र को कैसे लागू करेंगे? क्या आप अपने कोड के इस भाग को प्रस्तुत कर सकते हैं? आपकी समस्या Pseudorandom नंबर जनरेटर में हो सकती है ?
एलेक्स मार्कोव

जहाँ तक अंतिम प्रश्न है, इस तरह की प्रक्रियाएँ इस तरह की समस्याओं का सामना करती हैं क्योंकि (i) दूरियाँ गलत तरीके से अक्षांश या देशांतर की डिग्री में परिवर्तित हो जाती हैं और (ii) समन्वय प्रणाली की मीट्रिक विकृति का गलत हिसाब नहीं लगाया जाता है या इसका लेखा-जोखा नहीं लिया जाता है। भौगोलिक समन्वय प्रणाली के बजाय अनुमानित समन्वित प्रणाली का उपयोग करना आमतौर पर इन दोनों समस्याओं के आसपास होता है। ऐसा करने से आपके फॉर्मूले की एक मौलिक संपत्ति उजागर हो जाएगी, जो वांछनीय हो सकती है या नहीं भी हो सकती है: यह किसी आयत के भीतर स्थानों को उत्पन्न करती है , न कि किसी सर्कल के भीतर।
व्हीबर

धन्यवाद एलेक्स, जावा कोड stackoverflow पर पोस्ट किया गया है: stackoverflow.com/questions/10682743/…
pindleskin

संपादित कोड पुन:: (i) random.nextInt(1001)/1000समय के लगभग 0.1% से अधिक मूल्य लौटाएगा। आप का उपयोग क्यों नहीं कर रहे हैं random.nextDoubleया random.nextFloat? (ii) गुणा x0और y0से 1E6नहीं बल्कि रहस्यमय है, ऐसा लगता नहीं है कि यह सही परिणाम देगा।
व्हीबर

सच है, मैंने अगली विधि का उपयोग करके विधि को संपादित किया और 1E6 से छुटकारा पाया। अब, सभी रैंडम जनरेट किए गए स्थानों का समान निर्देशांक है कि मेरा स्थान। मदद के लिए धन्यवाद, ऐसा लगता है कि मैं इसे जल्द ही किसी भी समय हल करने जा रहा
हूं

जवाबों:


46

यह दो कारणों से मुश्किल है: पहला, एक वर्ग के बजाय एक सर्कल के बिंदुओं को सीमित करना; दूसरा, दूरी की गणना में विकृतियों के लिए लेखांकन।

कई जीआईएस में ऐसी क्षमताएं शामिल हैं जो स्वचालित रूप से और पारदर्शी रूप से दोनों जटिलताओं को संभालती हैं। हालांकि, यहां दिए गए टैग बताते हैं कि एक एल्गोरिथ्म का जीआईएस-स्वतंत्र विवरण वांछनीय हो सकता है।

  1. अंक उत्पन्न करने के लिए समान रूप से, बेतरतीब ढंग से, और एक सर्कल के भीतर स्वतंत्र रूप से त्रिज्या के आर एक स्थान (x0, Y0) के आसपास, दो स्वतंत्र वर्दी यादृच्छिक मान उत्पन्न करके शुरू यू और वी अंतराल [0, 1) में। (यह वही है जो लगभग हर यादृच्छिक संख्या जनरेटर आपको प्रदान करता है।) गणना

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

    वांछित यादृच्छिक बिंदु स्थान पर है (x + x0, y + y0)।

  2. जब भौगोलिक (लाट, लोन) निर्देशांक का उपयोग करते हैं, तो x0 (देशांतर) और y0 (अक्षांश) डिग्री में होंगे लेकिन r सबसे अधिक मीटर (या पैर या मील या कुछ अन्य रैखिक माप) में होगा। सबसे पहले, त्रिज्या r को डिग्री में बदलें जैसे कि आप भूमध्य रेखा के पास स्थित थे। यहां, एक डिग्री में लगभग 111,300 मीटर हैं।

    दूसरा, बाद में चरण (1) के रूप में x और y उत्पन्न करने के पूर्व-पश्चिम की दूरी के सिकुड़ने के लिए x- समन्वय को समायोजित करें:

    x' = x / cos(y0)

    वांछित यादृच्छिक बिंदु स्थान पर है (x '+ x0, y + y0)। यह एक अनुमानित प्रक्रिया है। छोटे रेडी (कुछ सौ किलोमीटर से कम) के लिए जो पृथ्वी के किसी भी ध्रुव पर नहीं फैलते हैं, यह आमतौर पर इतना सटीक होगा कि आप किसी भी त्रुटि का पता नहीं लगा सकते हैं जब प्रत्येक केंद्र के चारों ओर हजारों यादृच्छिक बिंदुओं का निर्माण होता है (x0, y0) ।


2
महान व्याख्या, जो मुझे पता है की जरूरत है अब मैं इसे लागू करने जा रहा हूं। धन्यवाद
pindleskin

1
मैंने सूत्र के कुछ जावा कार्यान्वयन को दिखाने के लिए प्रश्न को संपादित किया
पिंडल्सकिन

1
"एक डिग्री में लगभग 111,300 मीटर हैं" बस ध्यान दें कि कॉमा को हजार विभाजक के रूप में उपयोग किया जाता है। radiusInDegrees = त्रिज्या / 111300
RMalke

2
अक्षांश के लिए, लंबे निर्देशांक आपको x '= x / cos (y0 * Pi / 180) नहीं करना चाहिए
हारून स्टेनबैक

2
मन उड़ गया @whuber, और यह समझ में आता है। इसे देखने का एक और तरीका मुझे लगता है कि 20 की त्रिज्या के लिए 55 यादृच्छिक त्रिज्या की कल्पना की जा रही है। मान लीजिए कि प्रत्येक यादृच्छिक त्रिज्या एक समान है और 0 से 20 के बराबर है, इसलिए 0, 2, 4, ..., 20 .तो वहाँ 5 के एक त्रिज्या के साथ 5 अंक होंगे, 2 के 5 के त्रिज्या, 2 के एक त्रिज्या के साथ 5 अंक (त्रिज्या के 2 के एक चक्र के आसपास) एक साथ एक दूसरे के करीब 5 बिंदुओं के साथ MUCH दिखेगा 20 का।
अजीज जावेद

11

जावास्क्रिप्ट के लिए लागू:

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

सही कार्यान्वयन है:

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 );
}

मैंने इसे अधिक सुलभ बनाने के लिए बाहरी पुस्तकालयों पर निर्भरता को हटा दिया।


ओपी का प्रस्तावित संपादन इस स्टैकओवरफ्लो Q & A के अनुसार, जावा मैथकोस () में रेडियन में इनपुट की अपेक्षा करता है।
मिकराजमासी ५६

3

स्वीकृत उत्तर और डेरिवेटिव मेरे लिए कारगर नहीं थे। परिणाम बहुत गलत थे।

जावास्क्रिप्ट में सही कार्यान्वयन:

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)
}

यहां पूरी तरह से जिस्ट

स्वीकृत उत्तर में - मैंने पाया कि एक दीर्घवृत्त में इसकी चौड़ाई 1.5 गुना (पनामा में) और 8 बार इसकी ऊंचाई (स्वीडन के उत्तर में) के साथ वितरित की जाती है। अगर मैंने @ व्हिबर के उत्तर से x समन्वय समायोजन को हटा दिया तो दीर्घवृत्त दूसरे तरीके से विकृत हो जाता है, इसकी चौड़ाई से 8 गुना अधिक है।

मेरे उत्तर में कोड यहाँ से एल्गोरिदम पर आधारित था

नीचे आप दो jsfiddles देख सकते हैं जो स्ट्रेचिंग दीर्घवृत्त के साथ समस्या दिखाते हैं

सही एल्गोरिदम

विकृत एल्गोरिथ्म


जिन समस्याओं के बारे में आपने सुझाव दिया है उनका आपका वर्णन गलत है कि आपका कार्यान्वयन गलत था।
whuber

आप अच्छी तरह से सही हो सकते हैं। क्या आप मेरे द्वारा किए गए jsfiddles पर एक नज़र रखने की परवाह करेंगे और मुझे बताएंगे कि मैं कहाँ गलत हो गया।
जूलियन मान

मैं ऊपर ATOK के जावा जवाब के साथ तुलना में, और में distored एल्गोरिथ्म के अपने jsfiddle लिए यह परिवर्तन किया whuberPointAtDistance(): x1 = (w * Math.cos(t)) / Math.cos(y0 * (Math.PI / 180))
मैट

1
मेरे सुधार के बावजूद मेरे पास जूलियन जीस्ट के साथ और अधिक सटीक परिणाम थे। व्हाट्सएप ग्रुपअटस्टैंस () में मेरे सुधार को जोड़ते हुए और उन्हें त्रुटि रिपोर्ट के साथ जीआईएसटी में चलाने पर, यह तीनों परिदृश्यों में 0.05% त्रुटि दिखाती है (वैकल्पिक से काफी अधिक)।
मैट

1

पायथन में

# 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()

उत्पादन

अंकों के बीच की दूरी 0.288044147914 है। अंकों के बीच की दूरी 0.409557451806 है। अंकों के बीच की दूरी 0.368260305716 है। अंकों के बीच की दूरी 0.340720560546 है और अंकों के बीच की दूरी 0.453773334731 है और अंकों के बीच की दूरी 0.460608754561 है। अंकों के बीच की दूरी 0.4971888255 अंकों के बीच है। 0.607887857 अंकों के बीच की दूरी 0.607.8257 है। अंकों के बीच की दूरी 0.503691568896 है। अंकों के बीच की दूरी 0.175153349209 है। अंकों के बीच की दूरी 0.195149463735 है। अंकों के बीच की दूरी 0.424094009858 है और अंकों के बीच की दूरी 0.286807741494 है। अंकों के बीच की दूरी 0.558049206307 है। अंकों के बीच की दूरी 0.498612174179 है, जो अंकों के बीच की दूरी है।

यहां छवि विवरण दर्ज करें


0

आप यहां अपनी गणना के परिणामों की जांच कर सकते हैं । "आरंभ बिंदु से दी गई दूरी और असर" नामक अनुभाग पर नीचे स्क्रॉल करें। इसे लागू करने के लिए नीचे एक सरल जावास्क्रिप्ट फॉर्मूला भी है। आपको अभी भी रेडियन (उत्तर से दक्षिणावर्त मापा) में एक यादृच्छिक असर $ $ थीटा उत्पन्न करने की आवश्यकता होगी, हालांकि यह बहुत सीधा होना चाहिए। ये सूत्र एक गोलाकार पृथ्वी मानते हैं (हालांकि यह दीर्घवृत्त है), जो काफी अच्छा है क्योंकि यह 0.3% तक की त्रुटियां पैदा करता है।


0

स्विफ्ट के लिए कार्यान्वयन

जियोकोनोडर से लेट और लैंग प्राप्त करना और इसे इस फ़ंक्शन में पास करना

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)
}

ऊपर मेरे उदाहरण में, मुझे देश के नाम को जियोएन्कोडिंग से अक्षांश और देशांतर मिलते हैं, जैसा कि हर बार, देश का नाम एक ही अक्षांश और देशांतर देता है, वह भी देश के मध्य में, इसलिए मुझे यादृच्छिकता की आवश्यकता थी।


-1

निजी शून्य ड्रापॉलीलाइन (डबल लेट, डबल लैंग) {

         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
क्या आप इस बारे में थोड़ा विस्तार कर सकते हैं कि यह ओपी समस्याओं को कैसे हल करता है और आपके कोड को संक्षिप्त रूप से समझाता है?
मार्टिन
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.