किसी दिए गए Lat Lng स्थान से निश्चित दूरी के भीतर सभी अक्षांश देशांतर स्थानों को खोजने के लिए एल्गोरिथम


86

अक्षांश + देशांतर वाले स्थानों के डेटाबेस को देखते हुए, जैसे कि 40.8120390, -73.4889650, मैं किसी विशिष्ट स्थान की दी गई दूरी के भीतर सभी स्थानों को कैसे ढूँढूंगा?

यह DB से सभी स्थानों का चयन करने के लिए बहुत कुशल नहीं लगता है और फिर एक-एक करके उनके माध्यम से जाना, आरंभिक स्थान से दूरी देखने के लिए कि क्या वे निर्दिष्ट दूरी के भीतर हैं। क्या डीबी से शुरू में चयनित स्थानों को संकीर्ण करने का एक अच्छा तरीका है? एक बार जब मेरे पास स्थानों का एक संकुचित सेट होता है (या नहीं?), क्या मैं अभी भी एक-एक करके उनके माध्यम से दूरी की जांच करता हूं, या बेहतर तरीका है?

जिस भाषा में मैं यह करता हूं वह वास्तव में मायने नहीं रखती है। धन्यवाद!


4
यह वही हो सकता है जो आपको चाहिए: en.wikipedia.org/wiki/K-d_tree
biziclop

1
एक SQL क्वेरी इसे हल नहीं कर सका? स्थानों से चयन करें (लैट -: लाट) ^ 2 + (दीर्घ -: दीर्घ) ^ 2 <=: दूरी ^ 2 (inc, कुछ अन्य गणित पृथ्वी के गोलाकार होने और सभी के साथ शामिल है, यह सिर्फ एक उदाहरण है)
डायलेक्टिकस

1
@ अशु, nOiAd, दुर्भाग्य से मुझे उस परियोजना को छोड़ना पड़ा, इसलिए मैंने कोई समाधान नहीं निकाला। यदि आप लोग अपनी परियोजनाओं में से किसी एक समाधान का उपयोग करते हैं, तो मैं और अन्य वास्तव में इसके बारे में आपकी टिप्पणियों की सराहना करेंगे।
वलेरा

जवाबों:


41

अक्षांशों के बीच की दूरी की तुलना करके शुरू करें। अक्षांश का प्रत्येक अंश लगभग 69 मील (111 किलोमीटर) अलग है। ध्रुवों पर भूमध्य रेखा पर 69.407 (111.699 किमी) के लिए 68.703 मील (110.567 किमी) की सीमा (पृथ्वी की थोड़ी दीर्घवृत्ताकार आकृति के कारण) में भिन्नता है। दो स्थानों के बीच की दूरी उनके अक्षांशों के बीच की दूरी के बराबर या बड़ी होगी।

ध्यान दें कि यह अनुदैर्ध्य के लिए सही नहीं है - देशांतर के प्रत्येक डिग्री की लंबाई अक्षांश पर निर्भर है। हालांकि, यदि आपका डेटा किसी क्षेत्र (उदाहरण के लिए एक एकल देश) से जुड़ा हुआ है - तो आप लॉन्गिट्यूड के लिए भी न्यूनतम और अधिकतम सीमा की गणना कर सकते हैं।


जारी रहेगा एक कम सटीकता, तेजी से दूरी की गणना जो गोलाकार पृथ्वी मानती है:

निर्देशांक {lat1, lon1} और {lat2, lon2} के साथ दो बिंदुओं के बीच की बड़ी सर्कल दूरी d के लिए दी गई है:

d = acos(sin(lat1)*sin(lat2)+cos(lat1)*cos(lat2)*cos(lon1-lon2))

गणितीय रूप से समतुल्य सूत्र, जो कम दूरी के लिए गोल त्रुटि के अधीन है:

d = 2*asin(sqrt((sin((lat1-lat2)/2))^2 +
    cos(lat1)*cos(lat2)*(sin((lon1-lon2)/2))^2))

d रेडियन में दूरी है

distance_km ≈ radius_km * distance_radians ≈ 6371 * d

(6371 किमी पृथ्वी की औसत त्रिज्या है )

यह विधि कम्प्यूटेशनल आवश्यकताओं की नकल है। हालांकि परिणाम छोटी दूरी के लिए बहुत सटीक है।


फिर, यदि यह दी गई दूरी में है, तो कम या ज्यादा, अधिक सटीक विधि का उपयोग करें।

भौगोलिक रूप से सबसे सटीक कार्यान्वयन मुझे पता है, हालांकि विन्सेन्टी व्युत्क्रम सूत्र का भी उपयोग किया जा सकता है।


यदि आप RDBMS का उपयोग कर रहे हैं, तो अक्षांश को प्राथमिक कुंजी के रूप में और देशांतर को द्वितीयक कुंजी के रूप में सेट करें। एक अक्षांश सीमा के लिए क्वेरी, या एक अक्षांश / देशांतर सीमा के लिए, जैसा कि ऊपर वर्णित है, फिर परिणाम सेट के लिए सटीक दूरी की गणना करें।

ध्यान दें कि सभी प्रमुख RDBMS के आधुनिक संस्करण भौगोलिक डेटा-प्रकार और प्रश्नों का मूल रूप से समर्थन करते हैं।


बस एक सिर ऊपर है, पहला लिंक टूट गया है।
कुँहार

@kunruh: धन्यवाद। यह लिंक एड विलियम्स के एविएशन फॉर्म्युलेरी की ओर इशारा कर रहा था, जो अब ऑफलाइन लगता है। मैंने लिंक को एक सूत्र के साथ बदल दिया है।
लायर कोगन

इस लिंक ने इस विषय से जुड़े लगभग सभी विषयों को समझाया-able.type.co.uk/scripts/…
madeinQuant

14

वर्तमान उपयोगकर्ता के अक्षांश, देशांतर और उस दूरी के आधार पर जिसे आप खोजना चाहते हैं, नीचे sql क्वेरी दी गई है।

SELECT * FROM(
    SELECT *,(((acos(sin((@latitude*pi()/180)) * sin((Latitude*pi()/180))+cos((@latitude*pi()/180)) * cos((Latitude*pi()/180)) * cos(((@longitude - Longitude)*pi()/180))))*180/pi())*60*1.1515*1.609344) as distance FROM Distances) t
WHERE distance <= @distance

@ अक्षांश और देशांतर बिंदु के अक्षांश और देशांतर हैं। अक्षांश और देशांतर दूरी तालिका के स्तंभ हैं। पाई का मूल्य 22/7 है


2
KMs या मील में @distance पैरामीटर है?
गारफ्रेडाज़

मुझे लगता है कि दूरी KMs में है या मेरी स्क्रिप्ट गलत होगी, कुछ कृपया उपरोक्त प्रश्न का उत्तर दें।
उमर अब्बास 12


5

टंकी का योगिहोस्टिंग

मैं अपने डेटाबेस में ओपन स्ट्रीप मैप्स से टेबल की एक गपशप करता हूं और मैंने सफल परीक्षण किया है।

दूरी मीटर में ठीक काम।

SET @orig_lat=-8.116137;
SET @orig_lon=-34.897488;
SET @dist=1000;

SELECT *,(((acos(sin((@orig_lat*pi()/180)) * sin((dest.latitude*pi()/180))+cos((@orig_lat*pi()/180))*cos((dest.latitude*pi()/180))*cos(((@orig_lon-dest.longitude)*pi()/180))))*180/pi())*60*1.1515*1609.344) as distance FROM nodes AS dest HAVING distance < @dist ORDER BY distance ASC LIMIT 100;

दुनिया एक क्षेत्र नहीं है!
टॉबी स्पाइट

आपका क्या सुझाव है?
हेल्मुट केम्पर

2

जब भी यह सैद्धांतिक रूप से प्रश्न का उत्तर दे सकता है, तो उत्तर के आवश्यक भागों को शामिल करना और संदर्भ के लिए लिंक प्रदान करना बेहतर होगा
टॉबी स्पाइट

2

जैसा कि बिजिकलोप ने उल्लेख किया है, किसी प्रकार का मीट्रिक स्पेस ट्री संभवतः आपका सबसे अच्छा विकल्प होगा। मेरे पास केडी-ट्री और क्वाड ट्री का उपयोग करने के लिए इस प्रकार की रेंज क्वेरीज़ का अनुभव है और वे आश्चर्यजनक रूप से तेज़ हैं; वे भी लिखना मुश्किल नहीं है। मैं इन संरचनाओं में से एक को देखने का सुझाव देता हूं, क्योंकि वे आपको अन्य दिलचस्प सवालों के जवाब देने देती हैं जैसे "इस बिंदु पर मेरे डेटा में निकटतम बिंदु क्या है?"


हालांकि यह समस्या को हल करने के लिए एक मूल्यवान संकेत हो सकता है, एक जवाब वास्तव में समाधान प्रदर्शित करने की आवश्यकता है। कृपया संपादित तुम क्या मतलब है दिखाने के लिए उदाहरण कोड प्रदान करने के लिए। वैकल्पिक रूप से, इसे टिप्पणी के बजाय लिखने पर विचार करें।
स्पाइट

1
मुझे वास्तव में लगता है कि यहाँ कोड विचलित करने वाला होगा - यह पेड़ की संरचना वाली लाइब्रेरी के लिए बहुत विशिष्ट होगा और चुनी गई विशेष भाषा (ध्यान दें कि यह प्रश्न किसी भाषा के साथ टैग नहीं किया गया है।)
templatetypedef

1

आपको जो भी चाहिए वह स्थानिक खोज है। आप Solr स्थानिक खोज का उपयोग कर सकते हैं । इसमें लैट / लॉन्ग डेटेटाइप भी बनाया गया है, यहाँ देखें


जब भी यह सैद्धांतिक रूप से प्रश्न का उत्तर दे सकता है, तो उत्तर के आवश्यक भागों को शामिल करना और संदर्भ के लिए लिंक प्रदान करना बेहतर होगा
स्पाइट

0

आप अक्षांश-देशांतर को यूटीएम प्रारूप में परिवर्तित कर सकते हैं जो मीट्रिक प्रारूप है जो आपको दूरी की गणना करने में मदद कर सकता है। फिर आप आसानी से तय कर सकते हैं कि बिंदु विशिष्ट स्थान पर आता है या नहीं।


1
हालांकि यह समस्या को हल करने के लिए एक मूल्यवान संकेत हो सकता है, एक जवाब वास्तव में समाधान का प्रदर्शन करने की आवश्यकता है। कृपया संपादित तुम क्या मतलब है दिखाने के लिए उदाहरण कोड प्रदान करने के लिए। वैकल्पिक रूप से, इसे टिप्पणी के बजाय लिखने पर विचार करें।
टॉबी स्पाइट

0

चूंकि आप कहते हैं कि कोई भी भाषा स्वीकार्य है, इसलिए प्राकृतिक विकल्प पोस्टगिस है:

SELECT * FROM places
WHERE ST_DistanceSpheroid(geom, $location, $spheroid) < $max_metres;

आप डब्ल्यूजीएस गृहीत का उपयोग करना चाहते हैं, तो आप स्थापित करना चाहिए $spheroidकरने के लिए'SPHEROID["WGS 84",6378137,298.257223563]'

यह मानते हुए कि आपने कॉलम placesद्वारा अनुक्रमित किया है geom, यह यथोचित कुशल होना चाहिए।


0

@Yogihosting द्वारा प्रदान किए गए समाधान के लिए धन्यवाद, मैं नीचे दिए गए लिंक के साथ mysql के योजनाबद्ध कॉलम से समान परिणाम प्राप्त करने में सक्षम था:

// @params - will be bound to named query parameters
$criteria = [];
$criteria['latitude'] = '9.0285183';
$criteria['longitude'] = '7.4869546';
$criteria['distance'] = 500;
$criteria['skill'] = 'software developer';

// Get doctrine connection 
$conn = $this->getEntityManager()->getConnection();

        $sql = '
               SELECT DISTINCT m.uuid AS phone, (((acos(sin((:latitude*pi()/180)) * sin((JSON_EXTRACT(m.location, "$.latitude")*pi()/180))+cos((:latitude*pi()/180)) * 
              cos((JSON_EXTRACT(m.location, "$.latitude")*pi()/180)) * 
              cos(((:longitude - JSON_EXTRACT(m.location, "$.longitude"))*pi()/180))))*180/pi())*60*1.1515*1.609344) AS distance FROM member_profile AS m 
               INNER JOIN member_card_subscription mcs ON mcs.primary_identity = m.uuid
               WHERE mcs.end > now() AND JSON_SEARCH(m.skill_logic, "one", :skill) IS NOT NULL  AND (((acos(sin((:latitude*pi()/180)) * sin((JSON_EXTRACT(m.location, "$.latitude")*pi()/180))+cos((:latitude*pi()/180)) * 
              cos((JSON_EXTRACT(m.location, "$.latitude")*pi()/180)) * 
              cos(((:longitude - JSON_EXTRACT(m.location, "$.longitude"))*pi()/180))))*180/pi())*60*1.1515*1.609344) <= :distance ORDER BY distance
               ';
        $stmt = $conn->prepare($sql);
        $stmt->execute(['latitude'=>$criteria['latitude'], 'longitude'=>$criteria['longitude'], 'skill'=>$criteria['skill'], 'distance'=>$criteria['distance']]);
        var_dump($stmt->fetchAll());

कृपया ध्यान दें उपरोक्त कोड स्निपेट सिद्धांत डीबी कनेक्शन और पीएचपी का उपयोग कर रहा है


-2

आप इस समीकरण को देख सकते हैं, मुझे लगता है कि इससे मदद मिलेगी

SELECT id, ( 3959 * acos( cos( radians(37) ) * cos( radians( lat ) ) * cos( radians( lng ) - radians(-122) ) + sin( radians(37) ) * sin( radians( lat ) ) ) ) AS distance FROM markers HAVING distance < 25 ORDER BY distance LIMIT 0 , 20;

यद्यपि यह कोड समस्या को हल करने में मदद कर सकता है, लेकिन यह इस बात की व्याख्या नहीं करता है कि क्यों और / या यह कैसे उत्तर देता है। इस अतिरिक्त संदर्भ को प्रदान करने से इसके दीर्घकालिक शैक्षिक मूल्य में काफी सुधार होगा। कृपया स्पष्टीकरण जोड़ने के लिए अपने जवाब को संपादित करें, जिसमें सीमाएं और मान्यताएं शामिल हैं। विशेष रूप से, जादू के मूल्य 3959 और 37 कहां से आते हैं?
टोबी स्पाइट
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.