दो लाट / लंबे बिंदुओं के बीच की दूरी का पता लगाने का सबसे तेज़ तरीका


227

वर्तमान में मेरे पास mysql डेटाबेस में केवल एक लाख स्थानों के अंतर्गत देशांतर और अक्षांश जानकारी है।

मैं एक प्रश्न के माध्यम से एक बिंदु और कई अन्य बिंदुओं के बीच की दूरी खोजने की कोशिश कर रहा हूं। यह उतना तेज नहीं है जितना मैं चाहता हूं कि यह 100+ हिट के साथ विशेष रूप से हो।

क्या इसके लिए mysql के अलावा कोई तेज़ क्वेरी या संभवतः तेज़ सिस्टम है? मैं इस क्वेरी का उपयोग कर रहा हूं:

SELECT 
  name, 
   ( 3959 * acos( cos( radians(42.290763) ) * cos( radians( locations.lat ) ) 
   * cos( radians(locations.lng) - radians(-71.35368)) + sin(radians(42.290763)) 
   * sin( radians(locations.lat)))) AS distance 
FROM locations 
WHERE active = 1 
HAVING distance < 10 
ORDER BY distance;

नोट: प्रदान की गई दूरी मीलों में है । यदि आपको किलोमीटर की आवश्यकता है , तो 6371इसके बजाय का उपयोग करें 3959


31
आपके द्वारा दिए गए सूत्र में बहुत सारे तत्व हैं जो निरंतर हैं। क्या डेटा को पूर्व-गणना करना और उन मूल्यों को अपने डीबी में संग्रहीत करना संभव है? उदाहरण के लिए 3959 * एकोस (कॉस (रेडियंस (42.290763)) एक स्थिर है, लेकिन इसमें 4 प्रमुख संकलन हैं। इसके बजाय आप सिर्फ 6696.7837 स्टोर कर सकते हैं?
पीटर एम

1
या क्वेरी के बाहर कम से कम पूर्व-स्थिर स्थिरांक? जो काम करना है, उसमें कटौती करेगा।
पीटर एम

2
@Peter M यह संभावना है कि किसी भी सभ्य SQL डेटाबेस का अनुकूलन होगा ताकि केवल एक बार गणना की गई थी।
mhenry1384

25
सोच रहे लोगों के लिए, 42.290763 अक्षांश और -71.35368 उस बिंदु का देशांतर है जहां से दूरियों की गणना की जाती है।
user276648

14
बस जानकारी के लिए, इस फॉर्मूले से दूरी की दूरी मीलों में है, किलोमीटर में नहीं। कृपया 3959 से 6371 की जगह किलोमीटर में परिणाम प्राप्त करें
साहिल

जवाबों:


115

, या, MySQL 5.1और इसके बाद के संस्करण:

    SELECT  *
    FROM    table
    WHERE   MBRContains
                    (
                    LineString
                            (
                            Point (
                                    @lon + 10 / ( 111.1 / COS(RADIANS(@lat))),
                                    @lat + 10 / 111.1
                                  ),
                            Point (
                                    @lon - 10 / ( 111.1 / COS(RADIANS(@lat))),
                                    @lat - 10 / 111.1
                                  ) 
                            ),
                    mypoint
                    )

यह बॉक्स के भीतर लगभग सभी बिंदुओं का चयन करेगा (@lat +/- 10 km, @lon +/- 10km)

यह वास्तव में एक बॉक्स नहीं है, लेकिन एक गोलाकार आयत है: क्षेत्र का अक्षांश और देशांतर बाध्य खंड। यह फ्रांज जोसेफ भूमि पर एक सादे आयत से भिन्न हो सकता है , लेकिन अधिकांश बसे हुए स्थानों पर यह काफी करीब है।

  • सर्कल के अंदर सब कुछ चुनने के लिए अतिरिक्त फ़िल्टरिंग लागू करें (वर्ग नहीं)

  • संभवतः बड़े सर्कल दूरी (बड़ी दूरी के लिए) के लिए खाते में अतिरिक्त ठीक फ़िल्टरिंग लागू करें


15
@Quassnoi: एक जोड़े में सुधार: आप शायद निर्देशांक के क्रम को लैट, लॉन्ग में बदलना चाहते हैं। इसके अलावा, अनुदैर्ध्य दूरियां अक्षांश के कोसाइन के समानुपाती होती हैं, देशांतर नहीं। और आप इसे गुणन से विभाजन तक बदलना चाहते हैं, इसलिए आपका पहला समन्वय सही होगा @lon - 10 / ( 111.1 / cos(@lat))(और जोड़ी में दूसरा होगा क्योंकि सब कुछ सही था।
एम। डेव औयन

8
चेतावनी : @M द्वारा की गई बहुत ही मान्य टिप्पणी के साथ जवाब देने के लिए निकाय को संपादित नहीं किया गया है। दवे औयण। आगे के नोट: यदि ब्याज का चक्र (a) एक ध्रुव या (b) शामिल है, तो देश के +/- 180 डिग्री मध्याह्न के देशांतर से यह विधि नाश हो जाती है। साथ ही इसका उपयोग cos(lon)करना केवल छोटी-छोटी दूरियों के लिए सटीक है। देखें janmatuschek.de/LatitudeLongitudeBoundingCoordinates
जॉन Machin

3
क्या कोई ऐसा तरीका है जिससे हम कुछ अंतर्दृष्टि प्राप्त कर सकते हैं कि क्या स्थिरांक (10, 111.11, @ लाट, @लॉन, मायपॉइंट) का प्रतिनिधित्व करते हैं? मुझे लगता है कि 10 किलोमीटर की दूरी के लिए है, @ लाट और @ एलोन प्रदान किए गए अक्षांश और देशांतर का प्रतिनिधित्व करते हैं, लेकिन 111.11 और mypoint उदाहरण में क्या दर्शाते हैं?
बजे

4
@ साएश: 111.(1)अक्षांश की एक डिग्री में लगभग किमी हैं । mypointतालिकाओं को संग्रहीत करने वाली तालिका में फ़ील्ड है।
क्वासोनी

1
एक और त्रुटि सुधार - आपको दूसरी पंक्ति में दूसरी पंक्ति पर एक बंद याद आ रही है
आईएनए

100

MySql के विशिष्ट उत्तर नहीं, लेकिन यह आपके sql स्टेटमेंट के प्रदर्शन में सुधार करेगा।

आप जो प्रभावी ढंग से कर रहे हैं वह तालिका के प्रत्येक बिंदु से दूरी की गणना कर रहा है, यह देखने के लिए कि क्या यह किसी दिए गए बिंदु की 10 इकाइयों के भीतर है।

इस वर्ग को चलाने से पहले आप क्या कर सकते हैं, चार बिंदुओं का निर्माण करते हैं जो केंद्र में एक बिंदु पर एक बॉक्स 20 इकाइयों को खींचते हैं, अर्थात। (एक्स 1, वाई 1)। । । (x4, y4), जहां (X1, y1) (दी गई + 10 इकाइयों, दिए गए + 10 यूनिट्स) है। । । (दिए गए लोंग - 10 यूनिट, दिए गए -10 इकाइयाँ)। वास्तव में, आपको केवल दो बिंदु चाहिए, ऊपर बाएं और नीचे दाएं कॉल उन्हें (X1, Y1) और (X2, Y2)

अब आपका एसक्यूएल स्टेटमेंट इन बिंदुओं का उपयोग उन पंक्तियों को बाहर करने के लिए करता है जो निश्चित रूप से आपके दिए गए बिंदु से 10u से अधिक हैं, यह अक्षांश और देशांतर पर अनुक्रमित का उपयोग कर सकता है, इसलिए आपके पास वर्तमान में जो कुछ भी है, उससे अधिक तेजी के आदेश होंगे।

जैसे

select . . . 
where locations.lat between X1 and X2 
and   locations.Long between y1 and y2;

बॉक्स दृष्टिकोण गलत सकारात्मक लौट सकता है (आप दिए गए बिंदु से> 10u बॉक्स के कोनों में अंक उठा सकते हैं), इसलिए आपको अभी भी प्रत्येक बिंदु की दूरी की गणना करने की आवश्यकता है। हालाँकि यह फिर से बहुत तेज़ होगा क्योंकि आपने बॉक्स के भीतर बिंदुओं की जाँच करने के लिए अंकों की संख्या को बहुत सीमित कर दिया है।

मैं इस तकनीक को "बॉक्स के अंदर सोच" कहता हूं :)

संपादित करें: यह एक एसक्यूएल बयान में डाला जा सकता है?

मुझे नहीं पता कि mySql या Php क्या करने में सक्षम है, क्षमा करें। मुझे नहीं पता कि चार बिंदुओं का निर्माण करने के लिए सबसे अच्छी जगह कहाँ है, या वे कैसे php में एक mySql क्वेरी को पारित कर सकते हैं। हालाँकि, एक बार जब आपके पास चार बिंदु होते हैं, तो कुछ भी नहीं होता है जो आपको अपने स्वयं के एसक्यूएल स्टेटमेंट के साथ जोड़ रहा है।

select name, 
       ( 3959 * acos( cos( radians(42.290763) ) 
              * cos( radians( locations.lat ) ) 
              * cos( radians( locations.lng ) - radians(-71.35368) ) 
              + sin( radians(42.290763) ) 
              * sin( radians( locations.lat ) ) ) ) AS distance 
from locations 
where active = 1 
and locations.lat between X1 and X2 
and locations.Long between y1 and y2
having distance < 10 ORDER BY distance;

मैं एमएस एसक्यूएल के साथ जानता हूं कि मैं एक एसक्यूएल स्टेटमेंट बना सकता हूं जो चार फ्लोट्स (एक्स 1, वाई 1, एक्स 2, वाई 2) की घोषणा करता है और "मुख्य" चुनिंदा स्टेटमेंट से पहले उनकी गणना करता है, जैसे मैंने कहा, मुझे कोई अंदाजा नहीं है कि क्या यह किया जा सकता है माई एसक्यूएल। हालाँकि मैं अभी भी C # में चार बिंदुओं का निर्माण करने और उन्हें SQL क्वेरी के मापदंडों के रूप में पारित करने के लिए इच्छुक हूं।

क्षमा करें, मैं और अधिक मदद नहीं कर सकता, अगर कोई भी इस के MySQL और Php विशिष्ट भागों का उत्तर दे सकता है, ऐसा करने के लिए इस उत्तर को संपादित करने के लिए स्वतंत्र महसूस करें।


4
आप इस प्रस्तुति में इस दृष्टिकोण के लिए एक mysql प्रक्रिया पा सकते हैं: scribd.com/doc/2569355/Geo-Distance-Search-with-MySQL
लूसिया

37
मील के बजाय किलोमीटर से खोजने के लिए, 3959 को 6371 से बदलें।
ErichBSchulz

4
+1, बढ़िया विकल्प; बॉक्स को जोड़ने से मेरी क्वेरी 4 जी से 0.03s एवीजी तक कम हो गई।
jvenema

1
यह बहुत तर्क लगता है, आप इस समाधान के लिए एक पुरस्कार आरक्षित करते हैं! 2 मीलियन रिकॉर्ड डेटाबेस पर क्वेरी 16 सेकंड से 0.06 सेकंड तक चली गई। नोट: यदि आप क्वेरी से बाहर की दूरी की गणना में कटौती करते हैं और अपने प्रोग्राम कोड में दूरी के लिए गणना करते हैं तो यह और भी तेज़ है।
NLAnaconda

2
@ बेसिनरी बैरियर: तो यहां दिए गए उदाहरण के अनुसार X1, X2 और Y1, Y2 देशांतर मिन और मैक्स और अक्षांश मिन और मैक्स होंगे: blog.fedecarg.com/2009/02/08/… कृपया सलाह दें।
प्रभात

14

निम्नलिखित MySQL फ़ंक्शन इस ब्लॉग पोस्ट पर पोस्ट किया गया था । मैंने इसका बहुत परीक्षण नहीं किया है, लेकिन जो मैंने पोस्ट से इकट्ठा किया था, अगर आपके अक्षांश और देशांतर क्षेत्रों को अनुक्रमित किया जाता है , तो यह आपके लिए अच्छा काम कर सकता है:

DELIMITER $$

DROP FUNCTION IF EXISTS `get_distance_in_miles_between_geo_locations` $$
CREATE FUNCTION get_distance_in_miles_between_geo_locations(
  geo1_latitude decimal(10,6), geo1_longitude decimal(10,6), 
  geo2_latitude decimal(10,6), geo2_longitude decimal(10,6)) 
returns decimal(10,3) DETERMINISTIC
BEGIN
  return ((ACOS(SIN(geo1_latitude * PI() / 180) * SIN(geo2_latitude * PI() / 180) 
    + COS(geo1_latitude * PI() / 180) * COS(geo2_latitude * PI() / 180) 
    * COS((geo1_longitude - geo2_longitude) * PI() / 180)) * 180 / PI()) 
    * 60 * 1.1515);
END $$

DELIMITER ;

नमूना उपयोग:

एक तालिका मानकर placesफ़ील्ड latitudeऔर longitude:

SELECT get_distance_in_miles_between_geo_locations(-34.017330, 22.809500,
latitude, longitude) AS distance_from_input FROM places;

मैंने यह कोशिश की है और यह पूरी तरह से काम करता है, लेकिन किसी तरह यह मुझे दूरी_फ्रेम_पुट पर आधारित WHERE के बयान में डालने की अनुमति नहीं देता है। कोई विचार क्यों नहीं?
क्रिस विज़सर

आप इसे एक उप-चयन के रूप में कर सकते हैं: जहां से (...) टी का चयन करें, जहां दूरी_फ्रॉम_इनपुट> 5;
ब्रैड पार्क्स

2
या इसके साथ सीधे जाएं: उन स्थानों से * चुनें जहां से get_distance_in_miles_between_geo_locations (-34.017330, 22.809500, अक्षांश, देशांतर)> 5000;
ब्रैड पार्क

2
वापसी मीटर:SELECT ROUND(((ACOS(SIN(lat1 * PI() / 180) * SIN(lat2 * PI() / 180) + COS(lat1 * PI() / 180) * COS(lat2 * PI() / 180) * COS((lnt1 - lnt2) * PI() / 180)) * 180 / PI()) * 60 * 1.1515) * 1.609344 * 1000) AS distance
मोहम्मद

13

मुझे इसी तरह की समस्या को हल करने की जरूरत थी (एकल बिंदु से दूरी द्वारा पंक्तियों को फ़िल्टर करना) और मूल प्रश्न को उत्तर और टिप्पणियों के साथ जोड़कर, मैं समाधान के साथ आया जो मेरे लिए MySQL 5.6 और 5.7 दोनों पर पूरी तरह से काम करता है।

SELECT 
    *,
    (6371 * ACOS(COS(RADIANS(56.946285)) * COS(RADIANS(Y(coordinates))) 
    * COS(RADIANS(X(coordinates)) - RADIANS(24.105078)) + SIN(RADIANS(56.946285))
    * SIN(RADIANS(Y(coordinates))))) AS distance
FROM places
WHERE MBRContains
    (
    LineString
        (
        Point (
            24.105078 + 15 / (111.320 * COS(RADIANS(56.946285))),
            56.946285 + 15 / 111.133
        ),
        Point (
            24.105078 - 15 / (111.320 * COS(RADIANS(56.946285))),
            56.946285 - 15 / 111.133
        )
    ),
    coordinates
    )
HAVING distance < 15
ORDER By distance

coordinatesप्रकार के साथ क्षेत्र है POINTऔर किलोमीटर में दूरी की गणना के लिए SPATIALसूचकांक
6371है
56.946285, केंद्रीय बिंदु के लिए अक्षांश है केंद्रीय बिंदु के
24.105078लिए देशांतर
15है किलोमीटर में अधिकतम दूरी

मेरे परीक्षणों में, MySQL coordinatesक्षेत्र पर SPATIAL इंडेक्स का उपयोग करता है जो सभी पंक्तियों को जल्दी से चुनता है जो आयत के भीतर हैं और फिर आयतों कोनों से स्थानों को बाहर करने के लिए सभी फ़िल्टर किए गए स्थानों के लिए वास्तविक दूरी की गणना करता है और केवल सर्कल के अंदर स्थानों को छोड़ देता है।

यह मेरे परिणाम का दृश्य है:

नक्शा

ग्रे सितारे नक्शे पर सभी बिंदुओं की कल्पना करते हैं, पीले सितारे हैं जो MySQL क्वेरी द्वारा लौटाए गए हैं। आयत के कोनों (लेकिन बाहर सर्कल) के अंदर ग्रे सितारों का चयन किया गया था MBRContains()और फिर HAVINGखंड द्वारा अचयनित किया गया था ।


यह पर्याप्त नहीं हो सकता। लगभग 5 मिलियन रिकॉर्ड्स के साथ एक तालिका के माध्यम से खोज और इस विधि के साथ एक स्थानिक सूचकांक खोज समय एक पुराने ए 8 प्रोसेसर पर 0.005 सेकंड है। मुझे पता है कि मील में परिणाम प्राप्त करने के लिए 6371 को 3959 के साथ प्रतिस्थापित किया जा सकता है लेकिन क्या 111.133 और 111.320 के मूल्यों को समायोजित करने की आवश्यकता है या वे सार्वभौमिक रूप से स्थिर हैं?
1919 को

महान समाधान।
SeaBiscuit

पॉइंट कैसे बनाये यह POINT (lat, lng) या POINT (
lng

2
@ user606669 यह POINT (lng, lat) है
Mris Kisesovs

X () और Y () फ़ंक्शन आजकल ST_Y और ST_X होना चाहिए।
एंड्रियास

11

यदि आप MySQL 5.7 का उपयोग कर रहे हैं। *, तो आप st_distance_sphere (POINT, POINT) का उपयोग कर सकते हैं ।

Select st_distance_sphere(POINT(-2.997065, 53.404146 ), POINT(58.615349, 23.56676 ))/1000  as distcance

1
यह एक बहुत अच्छा और पढ़ने में आसान विकल्प है। ध्यान रखें, POINT () का पैरामीटर ऑर्डर (lng, lat) है अन्यथा आप "क्लोज़" के साथ समाप्त हो जाएंगे, लेकिन फिर भी यहां अन्य विधियों के बहुत अलग परिणाम हैं। देखें: stackoverflow.com/questions/35939853/…
एंडी पी

9
SELECT * FROM (SELECT *,(((acos(sin((43.6980168*pi()/180)) * 
sin((latitude*pi()/180))+cos((43.6980168*pi()/180)) * 
cos((latitude*pi()/180)) * cos(((7.266903899999988- longitude)* 
pi()/180))))*180/pi())*60*1.1515 ) as distance 
FROM wp_users WHERE 1 GROUP BY ID limit 0,10) as X 
ORDER BY ID DESC

यह MySQL में अंकों के बीच की दूरी की गणना क्वेरी है, मैंने इसे एक लंबे डेटाबेस में उपयोग किया है, यह इसे सही काम कर रहा है! नोट: अपनी आवश्यकताओं के अनुसार परिवर्तन (डेटाबेस का नाम, तालिका का नाम, स्तंभ आदि) करें।


1.1515 मान क्या दर्शाता है? मैंने पहले भी ऐसा ही फॉर्मूला देखा है, लेकिन इसमें 1.15 के बजाय 1.75 का इस्तेमाल किया गया।
TryHarder

1
मेरे अपने प्रश्न के उत्तर में, मुझे लगता है कि इसका उत्तर यहाँ मौजूद हो सकता है stackoverflow.com/a/389251/691053
TryHarder

8
set @latitude=53.754842;
set @longitude=-2.708077;
set @radius=20;

set @lng_min = @longitude - @radius/abs(cos(radians(@latitude))*69);
set @lng_max = @longitude + @radius/abs(cos(radians(@latitude))*69);
set @lat_min = @latitude - (@radius/69);
set @lat_max = @latitude + (@radius/69);

SELECT * FROM postcode
WHERE (longitude BETWEEN @lng_min AND @lng_max)
AND (latitude BETWEEN @lat_min and @lat_max);

स्रोत


11
कृपया अपने स्रोतों का हवाला दें। यह इस से है: blog.fedecarg.com/2009/02/08/…
redburn

इस मामले में 69 क्या है? अगर हमारे पास पृथ्वी की त्रिज्या है तो कैसे करें?
कोडरनर

2
1 लैटिटूड में किलोमीटर 111 KM है। 1 लैटिट्यूड में मील 69 मील है। और 69 मील = 111 किमी। इसलिए हमने रूपांतरणों में मापदंडों का उपयोग किया है।
कोडरनर

मैं हमेशा के लिए यह देख रहा था। नहीं पता था कि यह इतना आसान हो सकता है। बहुत बहुत धन्यवाद।
विकास

यह गलत नहीं होगा क्योंकि lng_min / lng_max को त्रिज्या गणित में lat_min और lat_max का उपयोग करने की आवश्यकता होगी?
बेन

6
   select
   (((acos(sin(('$latitude'*pi()/180)) * sin((`lat`*pi()/180))+cos(('$latitude'*pi()/180)) 
    * cos((`lat`*pi()/180)) * cos((('$longitude'- `lng`)*pi()/180))))*180/pi())*60*1.1515) 
    AS distance
    from table having distance<22;

5

एक MySQL फ़ंक्शन जो दो निर्देशांक के बीच मीटर की संख्या लौटाता है:

CREATE FUNCTION DISTANCE_BETWEEN (lat1 DOUBLE, lon1 DOUBLE, lat2 DOUBLE, lon2 DOUBLE)
RETURNS DOUBLE DETERMINISTIC
RETURN ACOS( SIN(lat1*PI()/180)*SIN(lat2*PI()/180) + COS(lat1*PI()/180)*COS(lat2*PI()/180)*COS(lon2*PI()/180-lon1*PI()/180) ) * 6371000

एक अलग प्रारूप में मूल्य वापस करने के लिए, 6371000फ़ंक्शन को अपनी पसंद की इकाई में पृथ्वी की त्रिज्या के साथ बदलें । उदाहरण के लिए, किलोमीटर होगा 6371और मील होगा 3959

फ़ंक्शन का उपयोग करने के लिए, बस इसे कॉल करें जैसे कि आप MySQL में कोई अन्य फ़ंक्शन करेंगे। उदाहरण के लिए, यदि आपके पास एक मेज है city, तो आप हर शहर से हर दूसरे शहर के बीच की दूरी पा सकते हैं:

SELECT
    `city1`.`name`,
    `city2`.`name`,
    ROUND(DISTANCE_BETWEEN(`city1`.`latitude`, `city1`.`longitude`, `city2`.`latitude`, `city2`.`longitude`)) AS `distance`
FROM
    `city` AS `city1`
JOIN
    `city` AS `city2`

4

MySQL प्लगइन के रूप में स्थापित करने के तरीके के बारे में विवरण के साथ पूर्ण कोड यहाँ हैं: https://github.com/lucasepe/lib_mysqludf_haversine

मैंने पिछले साल इसे टिप्पणी के रूप में पोस्ट किया था। चूंकि कृपया @TylerCollier ने मुझे उत्तर के रूप में पोस्ट करने का सुझाव दिया है, यहां यह है।

एक अन्य तरीका एक कस्टम यूडीएफ फ़ंक्शन लिखना है जो दो बिंदुओं से हैवरसिन दूरी को वापस करता है। यह फ़ंक्शन इनपुट में ले सकता है:

lat1 (real), lng1 (real), lat2 (real), lng2 (real), type (string - optinal - 'km', 'ft', 'mi')

तो हम कुछ इस तरह लिख सकते हैं:

SELECT id, name FROM MY_PLACES WHERE haversine_distance(lat1, lng1, lat2, lng2) < 40;

40 किलोमीटर तक कम दूरी के साथ सभी रिकॉर्ड हासिल करना। या:

SELECT id, name FROM MY_PLACES WHERE haversine_distance(lat1, lng1, lat2, lng2, 'ft') < 25;

25 फीट से कम दूरी के साथ सभी रिकॉर्ड लाने के लिए।

मुख्य कार्य है:

double
haversine_distance( UDF_INIT* initid, UDF_ARGS* args, char* is_null, char *error ) {
    double result = *(double*) initid->ptr;
    /*Earth Radius in Kilometers.*/ 
    double R = 6372.797560856;
    double DEG_TO_RAD = M_PI/180.0;
    double RAD_TO_DEG = 180.0/M_PI;
    double lat1 = *(double*) args->args[0];
    double lon1 = *(double*) args->args[1];
    double lat2 = *(double*) args->args[2];
    double lon2 = *(double*) args->args[3];
    double dlon = (lon2 - lon1) * DEG_TO_RAD;
    double dlat = (lat2 - lat1) * DEG_TO_RAD;
    double a = pow(sin(dlat * 0.5),2) + 
        cos(lat1*DEG_TO_RAD) * cos(lat2*DEG_TO_RAD) * pow(sin(dlon * 0.5),2);
    double c = 2.0 * atan2(sqrt(a), sqrt(1-a));
    result = ( R * c );
    /*
     * If we have a 5th distance type argument...
     */
    if (args->arg_count == 5) {
        str_to_lowercase(args->args[4]);
        if (strcmp(args->args[4], "ft") == 0) result *= 3280.8399;
        if (strcmp(args->args[4], "mi") == 0) result *= 0.621371192;
    }

    return result;
}

3

एक तेज, सरल और सटीक (छोटी दूरी के लिए) सन्निकटन एक गोलाकार प्रक्षेपण के साथ किया जा सकता है । कम से कम मेरे रूटिंग एल्गोरिथ्म में मुझे सही गणना की तुलना में 20% बढ़ावा मिलता है। जावा कोड में ऐसा दिखता है:

public double approxDistKm(double fromLat, double fromLon, double toLat, double toLon) {
    double dLat = Math.toRadians(toLat - fromLat);
    double dLon = Math.toRadians(toLon - fromLon);
    double tmp = Math.cos(Math.toRadians((fromLat + toLat) / 2)) * dLon;
    double d = dLat * dLat + tmp * tmp;
    return R * Math.sqrt(d);
}

MySQL (क्षमा करें!) के बारे में निश्चित नहीं है।

सुनिश्चित करें कि आप सीमा के बारे में जानते हैं (मुखरता का तीसरा पैराग्राफ किलोमीटर में सटीकता का मतलब है):

    float lat = 24.235f;
    float lon = 47.234f;
    CalcDistance dist = new CalcDistance();
    double res = 15.051;
    assertEquals(res, dist.calcDistKm(lat, lon, lat - 0.1, lon + 0.1), 1e-3);
    assertEquals(res, dist.approxDistKm(lat, lon, lat - 0.1, lon + 0.1), 1e-3);

    res = 150.748;
    assertEquals(res, dist.calcDistKm(lat, lon, lat - 1, lon + 1), 1e-3);
    assertEquals(res, dist.approxDistKm(lat, lon, lat - 1, lon + 1), 1e-2);

    res = 1527.919;
    assertEquals(res, dist.calcDistKm(lat, lon, lat - 10, lon + 10), 1e-3);
    assertEquals(res, dist.approxDistKm(lat, lon, lat - 10, lon + 10), 10);

3

यहाँ MySQL के साथ जियो डिस्टेंस सर्च का बहुत विस्तृत विवरण है जो हैव्सरीन फॉर्मूला के कार्यान्वयन से लेकर माईस्क्ल तक आधारित है। सिद्धांत, कार्यान्वयन और आगे के प्रदर्शन अनुकूलन के साथ पूर्ण समाधान विवरण। यद्यपि स्थानिक अनुकूलन वाला हिस्सा मेरे मामले में सही काम नहीं करता था। http://www.scribd.com/doc/2569355/Geo-Distance-Search-with-MySQL


3

की एक पढ़ा है MySQL के साथ जियो दूरी खोजें , एक समाधान MySQL करने के लिए Haversine फॉर्मूला के कार्यान्वयन पर आधारित है। यह सिद्धांत, कार्यान्वयन और आगे के प्रदर्शन अनुकूलन के साथ एक पूर्ण समाधान विवरण है। यद्यपि स्थानिक अनुकूलन वाला हिस्सा मेरे मामले में सही ढंग से काम नहीं करता था।

मैंने इसमें दो गलतियाँ देखीं:

  1. absp8 पर चुनिंदा स्टेटमेंट का उपयोग । मैं बस छोड़ दिया absऔर यह काम किया।

  2. p27 पर स्थानिक खोज दूरी फ़ंक्शन रेडियन में परिवर्तित नहीं होता है या cos(latitude)तब तक देशांतर से गुणा नहीं करता है , जब तक कि उसका स्थानिक डेटा इस पर ध्यान नहीं दिया जाता है (लेख के संदर्भ से नहीं बता सकता है), लेकिन p26 पर उसका उदाहरण इंगित करता है कि उसका स्थानिक डेटा POINTलोड नहीं है रेडियन या डिग्री।


0
$objectQuery = "SELECT table_master.*, ((acos(sin((" . $latitude . "*pi()/180)) * sin((`latitude`*pi()/180))+cos((" . $latitude . "*pi()/180)) * cos((`latitude`*pi()/180)) * cos(((" . $longitude . "- `longtude`)* pi()/180))))*180/pi())*60*1.1515  as distance FROM `table_post_broadcasts` JOIN table_master ON table_post_broadcasts.master_id = table_master.id WHERE table_master.type_of_post ='type' HAVING distance <='" . $Radius . "' ORDER BY distance asc";

0

Mysql का उपयोग करना

SET @orig_lon = 1.027125;
SET @dest_lon = 1.027125;

SET @orig_lat = 2.398441;
SET @dest_lat = 2.398441;

SET @kmormiles = 6371;-- for distance in miles set to : 3956

SELECT @kmormiles * ACOS(LEAST(COS(RADIANS(@orig_lat)) * 
 COS(RADIANS(@dest_lat)) * COS(RADIANS(@orig_lon - @dest_lon)) + 
 SIN(RADIANS(@orig_lat)) * SIN(RADIANS(@dest_lat)),1.0)) as distance;

देखें: https://andrew.hedges.name/experiments/haversine/

देखें: https://stackoverflow.com/a/24372831/5155484

देखें: http://www.plumislandmedia.net/mysql/haversine-mysql-nearest-loc/

नोट: https://stackoverflow.com/a/24372831/5155344LEAST पर सुझाई गई टिप्पणी के रूप में अशक्त मूल्यों से बचने के लिए उपयोग किया जाता है

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.