หาระยะห่างระหว่างจุดทางภูมิศาสตร์สองจุด


108

ฉันต้องการสร้างแอปที่ตรวจสอบสถานที่ที่ใกล้ที่สุดที่ผู้ใช้อยู่ ฉันสามารถหาตำแหน่งของผู้ใช้ได้อย่างง่ายดายและฉันมีรายชื่อสถานที่พร้อมละติจูดและลองจิจูดแล้ว

อะไรคือวิธีที่ดีที่สุดในการทราบตำแหน่งที่ใกล้ที่สุดของรายการเทียบกับตำแหน่งของผู้ใช้ปัจจุบัน

ฉันไม่พบสิ่งใดใน Google API

คำตอบ:


164
Location loc1 = new Location("");
loc1.setLatitude(lat1);
loc1.setLongitude(lon1);

Location loc2 = new Location("");
loc2.setLatitude(lat2);
loc2.setLongitude(lon2);

float distanceInMeters = loc1.distanceTo(loc2);

อ้างอิง: http://developer.android.com/reference/android/location/Location.html#distanceTo(android.location.Location)


2
อาจช้ากว่าการใช้ Location.DistanceBetween () เนื่องจากใช้วัตถุ Location แต่ทำงานได้ดีสำหรับวัตถุประสงค์ของฉัน
ZoltanF

ฉันต้องนำเข้าคลาสใดสำหรับสถานที่ตั้งimport android.location.Location;หรือคลาสใด
Pranav MS

@PranavMS ใช่ android.location.Location;
AndrewS

ฉันคิดว่าระยะทางในการคืนค่าระยะห่างระหว่างจุดแรกและจุดสุดท้าย แต่เป็นเส้นตรงดังนั้นหากคุณใช้ทิศทางอื่นจากจุด A ไปยังจุด B มันจะไม่มีทางได้รับเนื่องจากเส้นทางนั้นแตกต่างกันนั่นคือเมื่อระยะทางระหว่างการรวมเข้าคุณสามารถ บันทึกระยะห่างระหว่างจุด beign ที่สร้างขึ้นจากนั้นด้วยผลลัพธ์พารามิเตอร์สุดท้าย [] ให้ได้ระยะทางที่ถูกต้อง
GastónSaillén

122

http://developer.android.com/reference/android/location/Location.html

มองเข้าไปในระยะทางถึงหรือระยะทางระหว่าง คุณสามารถสร้างวัตถุตำแหน่งจากละติจูดและลองจิจูด:

Location location = new Location("");
location.setLatitude(lat);
location.setLongitude(lon);

37
distanceBetween เป็นวิธีการแบบคงที่ที่ใช้จุด lat long 2 ชุดดังนั้นคุณไม่จำเป็นต้องสร้างอินสแตนซ์วัตถุตำแหน่ง =)
Stan Kurdziel

4
ฉันแน่ใจว่าเขาหมายถึงdistanceToวิธีการนั้น
laph

สิ่งนี้ยอดเยี่ยมและมีประโยชน์มาก แต่ผู้ให้บริการ String ใน constrructor คืออะไร?
miss.serena

33

วิธีแก้ปัญหาโดยประมาณ (ขึ้นอยู่กับการฉายภาพเชิงเส้นตรง) เร็วกว่ามาก (ต้องใช้เพียง 1 ตรีโกณและ 1 รากที่สอง)

การประมาณนี้มีความเกี่ยวข้องหากคะแนนของคุณไม่ห่างกันเกินไป มันจะเกินประมาณการเสมอเมื่อเทียบกับระยะทางไกลจริง ยกตัวอย่างเช่นมันจะเพิ่มไม่เกิน 0.05382%กับระยะทางจริงถ้าเส้นรุ้งเส้นแวงเดลต้าหรือระหว่างจุดสองจุดของคุณไม่เกิน 4 องศาทศนิยม

สูตรมาตรฐาน (Haversine) เป็นสูตรที่แน่นอน (นั่นคือใช้ได้กับลองจิจูด / ละติจูดบนโลก) แต่จะช้ากว่ามากเนื่องจากต้องมีตรีโกณมิติ 7 ตัวและรากที่สอง 2 หากจุดสองจุดของคุณอยู่ห่างกันไม่มากเกินไปและความแม่นยำสัมบูรณ์ไม่ใช่สิ่งสำคัญยิ่งคุณสามารถใช้เวอร์ชันโดยประมาณนี้ (Equirectangular) ซึ่งเร็วกว่ามากเนื่องจากใช้ตรีโกณมิติเดียวและรากที่สองหนึ่งรูท

// Approximate Equirectangular -- works if (lat1,lon1) ~ (lat2,lon2)
int R = 6371; // km
double x = (lon2 - lon1) * Math.cos((lat1 + lat2) / 2);
double y = (lat2 - lat1);
double distance = Math.sqrt(x * x + y * y) * R;

คุณสามารถเพิ่มประสิทธิภาพเพิ่มเติมได้โดย:

  1. การลบรากที่สองถ้าคุณเปรียบเทียบระยะทางกับอีกระยะหนึ่ง (ในกรณีนั้นให้เปรียบเทียบทั้งระยะทางกำลังสอง)
  2. การแยกตัวประกอบของโคไซน์ถ้าคุณคำนวณระยะทางจากจุดต้นแบบหนึ่งไปยังจุดอื่น ๆ อีกหลายจุด (ในกรณีนี้คุณจะทำการฉายภาพที่มีศูนย์กลางอยู่ที่จุดต้นแบบดังนั้นคุณจึงสามารถคำนวณโคไซน์หนึ่งครั้งสำหรับการเปรียบเทียบทั้งหมด)

ดูข้อมูลเพิ่มเติมได้ที่: http://www.movable-type.co.uk/scripts/latlong.html

มีการใช้อ้างอิงที่ดีของสูตร Haversine ในหลายภาษาที่: http://www.codecodex.com/wiki/Calculate_Distance_Between_Two_Points_on_a_Globe


ขอบคุณผู้ยิ่งใหญ่ แต่ถ้าฉันต้องการชุดของสถานที่รอบ ๆ สถานที่หนึ่งในขอบเขตฉันควรใช้ while loop เพื่อตรวจสอบสถานที่แต่ละแห่งเทียบกับสถานที่ที่ค้นหาและเก็บเฉพาะสถานที่ที่อยู่ในขอบเขตหรือไม่
themhz

คุณทำได้ แต่นั่นเป็นวิธีการที่ดุร้ายในO(n). สำหรับO(1)วิธีแก้ปัญหาให้ใช้ดัชนีเชิงพื้นที่ 2 มิติเพื่อตัดทอนการจับคู่ที่อาจเกิดขึ้นก่อนที่จะคำนวณโซลูชันที่แน่นอน เรากำลังออกจากขอบเขตของคำถามนี้ :)
Laurent Grégoire

นี่เป็นการสรุปที่ดีมากของการเพิ่มประสิทธิภาพที่ดีที่เป็นไปได้ ... ขอบคุณ! ตรงกับสิ่งที่ฉันกำลังมองหา
Sam Vloeberghs

ฉันแค่อยากรู้ว่าสูตรนี้ใช้ได้กับระยะทางไกลหรือไม่
Sandipan Majhi

ดูคำตอบ แต่โดยย่อ: ไม่ใช้ไม่ได้ในระยะทางไกล ยิ่งระยะห่างระหว่างจุดทั้งสองกว้างขึ้นเท่าใดข้อผิดพลาดก็จะยิ่งมากขึ้นเมื่อเทียบกับHaversine formulæ ที่แน่นอน
Laurent Grégoire

11

มีสองวิธีที่คุณสามารถใช้ได้ แต่ในการพิจารณาว่าวิธีใดดีที่สุดเราจำเป็นต้องทราบก่อนว่าคุณตระหนักถึงระดับความสูงของผู้ใช้และระดับความสูงของจุดอื่น ๆ หรือไม่?

ขึ้นอยู่กับระดับความแม่นยำที่คุณต้องการคุณสามารถดูสูตร Haversine หรือ Vincenty ได้ ...

หน้าเหล่านี้ให้รายละเอียดเกี่ยวกับสูตรและสำหรับผู้ที่มีความโน้มเอียงทางคณิตศาสตร์น้อยกว่ายังให้คำอธิบายเกี่ยวกับวิธีการนำไปใช้ในสคริปต์ด้วย!

สูตร Haversine: http://www.movable-type.co.uk/scripts/latlong.html

Vincenty Formula: http://www.movable-type.co.uk/scripts/latlong-vincenty.html

หากคุณมีปัญหาเกี่ยวกับความหมายใด ๆ ในสูตรเพียงแสดงความคิดเห็นและฉันจะพยายามอย่างเต็มที่เพื่อตอบ :)


4

มีสองวิธีในการหาระยะห่างระหว่าง LatLng

public static void distanceBetween (double startLatitude, double startLongitude, double endLatitude, double endLongitude, float[] results)

ดูนี่

และที่สอง

public float distanceTo (Location dest) ตามคำตอบของ praveen


3
private float getDistance(double lat1, double lon1, double lat2, double lon2) {
        float[] distance = new float[2];
        Location.distanceBetween(lat1, lon1, lat2, lon2, distance);
        return distance[0];
    }

1

เพียงใช้วิธีต่อไปนี้ส่ง lat และ long และรับระยะทางเป็นเมตร:

private static double distance_in_meter(final double lat1, final double lon1, final double lat2, final double lon2) {
    double R = 6371000f; // Radius of the earth in m
    double dLat = (lat1 - lat2) * Math.PI / 180f;
    double dLon = (lon1 - lon2) * Math.PI / 180f;
    double a = Math.sin(dLat/2) * Math.sin(dLat/2) +
            Math.cos(latlong1.latitude * Math.PI / 180f) * Math.cos(latlong2.latitude * Math.PI / 180f) *
                    Math.sin(dLon/2) * Math.sin(dLon/2);
    double c = 2f * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
    double d = R * c;
    return d;
}

2
latlong1 และ latlong2 ไม่ได้กำหนดไว้
Boy

1
latlong1 & latlong2 คืออะไร?
Nisal Malinda Livera

0

คุณสามารถรับระยะทางและเวลาโดยใช้ google Map API Google Map API

เพียงแค่ส่ง JSON ที่ดาวน์โหลดมาไปยังวิธีนี้คุณจะได้รับระยะทางและเวลาแบบเรียลไทม์ระหว่างสอง latlong

void parseJSONForDurationAndKMS(String json) throws JSONException {

    Log.d(TAG, "called parseJSONForDurationAndKMS");
    JSONObject jsonObject = new JSONObject(json);
    String distance;
    String duration;
    distance = jsonObject.getJSONArray("routes").getJSONObject(0).getJSONArray("legs").getJSONObject(0).getJSONObject("distance").getString("text");
    duration = jsonObject.getJSONArray("routes").getJSONObject(0).getJSONArray("legs").getJSONObject(0).getJSONObject("duration").getString("text");

    Log.d(TAG, "distance : " + distance);
    Log.d(TAG, "duration : " + duration);

    distanceBWLats.setText("Distance : " + distance + "\n" + "Duration : " + duration);


}

0

a = sin² (Δφ / 2) + cos φ1⋅ cos φ2⋅sin² (Δλ / 2)

c = 2 ⋅ atan2 (√a, √ (1 − ก))

ระยะทาง = R ⋅ c

โดยที่φคือละติจูดλคือลองจิจูด R คือรัศมีของโลก (รัศมีเฉลี่ย = 6,371 กม.)

โปรดทราบว่ามุมจะต้องเป็นเรเดียนเพื่อส่งผ่านไปยังฟังก์ชันทริก!

fun distanceInMeter(firstLocation: Location, secondLocation: Location): Double {
    val earthRadius = 6371000.0
    val deltaLatitudeDegree = (firstLocation.latitude - secondLocation.latitude) * Math.PI / 180f
    val deltaLongitudeDegree = (firstLocation.longitude - secondLocation.longitude) * Math.PI / 180f
    val a = sin(deltaLatitudeDegree / 2).pow(2) +
            cos(firstLocation.latitude * Math.PI / 180f) * cos(secondLocation.latitude * Math.PI / 180f) *
            sin(deltaLongitudeDegree / 2).pow(2)
    val c = 2f * atan2(sqrt(a), sqrt(1 - a))
    return earthRadius * c
}


data class Location(val latitude: Double, val longitude: Double)
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.