จะคำนวณกล่องขอบเขตสำหรับตำแหน่ง lat / lng ที่กำหนดได้อย่างไร


101

ฉันได้กำหนดตำแหน่งตามละติจูดและลองจิจูด ตอนนี้ฉันต้องการคำนวณกรอบขอบเขตภายในเช่น 10 กิโลเมตรจากจุดนั้น

ควรกำหนดกรอบขอบเขตเป็น latmin, lngmin และ latmax, lngmax

ฉันต้องการสิ่งนี้เพื่อที่จะใช้Panoramio API

มีใครรู้สูตรวิธีรับ thos บ้าง?

แก้ไข:พวกฉันกำลังมองหาสูตร / ฟังก์ชันที่ใช้ lat & lng เป็นอินพุตและส่งคืนกล่องขอบเขตเป็น latmin & lngmin และ latmax & latmin Mysql, php, c #, javascript นั้นใช้ได้ แต่ pseudocode ก็น่าจะโอเค

แก้ไข:ฉันไม่ได้มองหาวิธีแก้ปัญหาที่แสดงให้ฉันเห็นระยะทาง 2 จุด


หากคุณกำลังใช้ฐานข้อมูลภูมิศาสตร์อยู่ที่ไหนสักแห่งพวกเขาก็มีการคำนวณกล่องขอบเขตรวมอยู่ด้วย คุณสามารถตรวจสอบแหล่งที่มาของ PostGIS / GEOS ได้เช่นกัน
Vinko Vrsalovic

คำตอบ:


61

ฉันแนะนำให้ประมาณพื้นผิวโลกในพื้นที่เป็นทรงกลมที่มีรัศมีที่กำหนดโดยวงรี WGS84 ที่ละติจูดที่กำหนด ฉันสงสัยว่าการคำนวณที่แน่นอนของ latMin และ latMax จะต้องใช้ฟังก์ชันรูปไข่และจะไม่ทำให้ความแม่นยำเพิ่มขึ้นอย่างเห็นได้ชัด (WGS84 เป็นค่าประมาณ)

การใช้งานของฉันเป็นไปตามนี้ (เขียนด้วย Python ฉันยังไม่ได้ทดสอบ):

# degrees to radians
def deg2rad(degrees):
    return math.pi*degrees/180.0
# radians to degrees
def rad2deg(radians):
    return 180.0*radians/math.pi

# Semi-axes of WGS-84 geoidal reference
WGS84_a = 6378137.0  # Major semiaxis [m]
WGS84_b = 6356752.3  # Minor semiaxis [m]

# Earth radius at a given latitude, according to the WGS-84 ellipsoid [m]
def WGS84EarthRadius(lat):
    # http://en.wikipedia.org/wiki/Earth_radius
    An = WGS84_a*WGS84_a * math.cos(lat)
    Bn = WGS84_b*WGS84_b * math.sin(lat)
    Ad = WGS84_a * math.cos(lat)
    Bd = WGS84_b * math.sin(lat)
    return math.sqrt( (An*An + Bn*Bn)/(Ad*Ad + Bd*Bd) )

# Bounding box surrounding the point at given coordinates,
# assuming local approximation of Earth surface as a sphere
# of radius given by WGS84
def boundingBox(latitudeInDegrees, longitudeInDegrees, halfSideInKm):
    lat = deg2rad(latitudeInDegrees)
    lon = deg2rad(longitudeInDegrees)
    halfSide = 1000*halfSideInKm

    # Radius of Earth at given latitude
    radius = WGS84EarthRadius(lat)
    # Radius of the parallel at given latitude
    pradius = radius*math.cos(lat)

    latMin = lat - halfSide/radius
    latMax = lat + halfSide/radius
    lonMin = lon - halfSide/pradius
    lonMax = lon + halfSide/pradius

    return (rad2deg(latMin), rad2deg(lonMin), rad2deg(latMax), rad2deg(lonMax))

แก้ไข: รหัสต่อไปนี้จะแปลง (องศาไพรม์วินาที) เป็นองศา + เศษส่วนขององศาและในทางกลับกัน (ไม่ได้ทดสอบ):

def dps2deg(degrees, primes, seconds):
    return degrees + primes/60.0 + seconds/3600.0

def deg2dps(degrees):
    intdeg = math.floor(degrees)
    primes = (degrees - intdeg)*60.0
    intpri = math.floor(primes)
    seconds = (primes - intpri)*60.0
    intsec = round(seconds)
    return (int(intdeg), int(intpri), int(intsec))

4
ตามที่ระบุไว้ในเอกสารของไลบรารี CPAN ที่แนะนำสิ่งนี้เหมาะสมสำหรับ halfSide <= 10 กม. เท่านั้น
Federico A.Ramponi

1
ทำงานใกล้เสาหรือไม่ ดูเหมือนจะไม่เป็นเช่นนั้นเพราะดูเหมือนว่ามันจะลงท้ายด้วย latMin <-pi (สำหรับขั้วใต้) หรือ latMax> pi (สำหรับขั้วโลกเหนือ)? ฉันคิดว่าเมื่อคุณอยู่ภายในครึ่งหนึ่งของเสาคุณต้องส่งคืนกล่องขอบเขตที่มีลองจิจูดทั้งหมดและละติจูดที่คำนวณตามปกติสำหรับด้านที่ห่างจากเสาและที่เสาที่ด้านข้างใกล้เสา
Doug McClean

1
นี่คือการใช้งาน PHP จากข้อกำหนดที่พบใน JanMatuschek.de: github.com/anthonymartin/GeoLocation.class.php
Anthony Martin

2
ฉันได้เพิ่มการใช้งาน C # ของคำตอบนี้ด้านล่าง
ΕГИІИО

2
@ FedericoA.Ramponi haldSideinKm ที่นี่คืออะไร? ไม่เข้าใจ ... สิ่งที่ฉันต้องผ่านใน argyments นี้รัศมีระหว่างสองจุดในแผนที่หรืออะไร?

53

ฉันเขียนบทความเกี่ยวกับการค้นหาพิกัดขอบเขต:

http://JanMatuschek.de/LatitudeLongitudeBoundingCoordinates

บทความนี้อธิบายเกี่ยวกับสูตรและการใช้งาน Java (นอกจากนี้ยังแสดงให้เห็นว่าเหตุใดสูตรของ Federico สำหรับลองจิจูดต่ำสุด / สูงสุดจึงไม่ถูกต้อง)


4
ฉันได้สร้างพอร์ต PHP ของคลาส GeoLocation แล้ว สามารถพบได้ที่นี่: pastie.org/5416584
Anthony Martin

1
ฉันอัปโหลดบน github แล้ว: github.com/anthonymartin/GeoLocation.class.php
Anthony Martin

1
สิ่งนี้ตอบคำถามได้หรือไม่? หากเรามีจุดเริ่มต้นเพียง 1 จุดเราไม่สามารถคำนวณระยะทางวงกลมใหญ่ตามที่ทำในรหัสนี้ได้ซึ่งต้องใช้ตำแหน่งละติจูดยาวสองตำแหน่ง
mdoran3844

มีรหัสที่ไม่ถูกต้องในตัวแปร C # ของคุณเช่นpublic override string ToString()เป็นเรื่องแย่มากที่จะแทนที่วิธีการทั่วโลกดังกล่าวเพื่อวัตถุประสงค์เดียวเท่านั้นดีกว่าเพียงเพิ่มวิธีอื่นจากนั้นแทนที่วิธีการมาตรฐานซึ่งสามารถใช้ในส่วนอื่น ๆ ของแอปพลิเคชันได้ ไม่ใช่สำหรับ gis แน่นอน ...

นี่คือลิงค์ที่อัปเดตไปยังพอร์ต PHP ของคลาส GeoLocaiton ของ Jan: github.com/anthonymartin/GeoLocation.php
Anthony Martin

34

ที่นี่ฉันได้แปลงคำตอบของ Federico A.Ramponi เป็น C # สำหรับทุกคนที่สนใจ:

public class MapPoint
{
    public double Longitude { get; set; } // In Degrees
    public double Latitude { get; set; } // In Degrees
}

public class BoundingBox
{
    public MapPoint MinPoint { get; set; }
    public MapPoint MaxPoint { get; set; }
}        

// Semi-axes of WGS-84 geoidal reference
private const double WGS84_a = 6378137.0; // Major semiaxis [m]
private const double WGS84_b = 6356752.3; // Minor semiaxis [m]

// 'halfSideInKm' is the half length of the bounding box you want in kilometers.
public static BoundingBox GetBoundingBox(MapPoint point, double halfSideInKm)
{            
    // Bounding box surrounding the point at given coordinates,
    // assuming local approximation of Earth surface as a sphere
    // of radius given by WGS84
    var lat = Deg2rad(point.Latitude);
    var lon = Deg2rad(point.Longitude);
    var halfSide = 1000 * halfSideInKm;

    // Radius of Earth at given latitude
    var radius = WGS84EarthRadius(lat);
    // Radius of the parallel at given latitude
    var pradius = radius * Math.Cos(lat);

    var latMin = lat - halfSide / radius;
    var latMax = lat + halfSide / radius;
    var lonMin = lon - halfSide / pradius;
    var lonMax = lon + halfSide / pradius;

    return new BoundingBox { 
        MinPoint = new MapPoint { Latitude = Rad2deg(latMin), Longitude = Rad2deg(lonMin) },
        MaxPoint = new MapPoint { Latitude = Rad2deg(latMax), Longitude = Rad2deg(lonMax) }
    };            
}

// degrees to radians
private static double Deg2rad(double degrees)
{
    return Math.PI * degrees / 180.0;
}

// radians to degrees
private static double Rad2deg(double radians)
{
    return 180.0 * radians / Math.PI;
}

// Earth radius at a given latitude, according to the WGS-84 ellipsoid [m]
private static double WGS84EarthRadius(double lat)
{
    // http://en.wikipedia.org/wiki/Earth_radius
    var An = WGS84_a * WGS84_a * Math.Cos(lat);
    var Bn = WGS84_b * WGS84_b * Math.Sin(lat);
    var Ad = WGS84_a * Math.Cos(lat);
    var Bd = WGS84_b * Math.Sin(lat);
    return Math.Sqrt((An*An + Bn*Bn) / (Ad*Ad + Bd*Bd));
}

1
ขอบคุณงานนี้สำหรับฉัน ต้องทดสอบโค้ดด้วยมือไม่รู้จะเขียน unit test ได้อย่างไร แต่มันให้ผลลัพธ์ที่แม่นยำในระดับที่ต้องการ
mdoran3844

haldSideinKm ที่นี่คืออะไร ไม่เข้าใจ ... สิ่งที่ฉันต้องผ่านใน argyments นี้รัศมีระหว่างสองจุดในแผนที่หรืออะไร?

@ GeloVolro: นั่นคือความยาวครึ่งหนึ่งของกรอบที่คุณต้องการ
ΕГИІИО

1
คุณไม่จำเป็นต้องเขียนคลาส MapPoint ของคุณเอง มีคลาส GeoCoordinate ใน System.Device.Location ที่ใช้ Latitude และ Longitude เป็นพารามิเตอร์
Lawyerson

1
นี้ทำงานได้อย่างสวยงาม ฉันชื่นชมพอร์ต C # มาก
Tom Larcher

10

ฉันเขียนฟังก์ชัน JavaScript ที่ส่งกลับค่าพิกัดสี่ของกล่องขอบเขตสี่เหลี่ยมโดยกำหนดระยะทางและพิกัดคู่หนึ่ง:

'use strict';

/**
 * @param {number} distance - distance (km) from the point represented by centerPoint
 * @param {array} centerPoint - two-dimensional array containing center coords [latitude, longitude]
 * @description
 *   Computes the bounding coordinates of all points on the surface of a sphere
 *   that has a great circle distance to the point represented by the centerPoint
 *   argument that is less or equal to the distance argument.
 *   Technique from: Jan Matuschek <http://JanMatuschek.de/LatitudeLongitudeBoundingCoordinates>
 * @author Alex Salisbury
*/

getBoundingBox = function (centerPoint, distance) {
  var MIN_LAT, MAX_LAT, MIN_LON, MAX_LON, R, radDist, degLat, degLon, radLat, radLon, minLat, maxLat, minLon, maxLon, deltaLon;
  if (distance < 0) {
    return 'Illegal arguments';
  }
  // helper functions (degrees<–>radians)
  Number.prototype.degToRad = function () {
    return this * (Math.PI / 180);
  };
  Number.prototype.radToDeg = function () {
    return (180 * this) / Math.PI;
  };
  // coordinate limits
  MIN_LAT = (-90).degToRad();
  MAX_LAT = (90).degToRad();
  MIN_LON = (-180).degToRad();
  MAX_LON = (180).degToRad();
  // Earth's radius (km)
  R = 6378.1;
  // angular distance in radians on a great circle
  radDist = distance / R;
  // center point coordinates (deg)
  degLat = centerPoint[0];
  degLon = centerPoint[1];
  // center point coordinates (rad)
  radLat = degLat.degToRad();
  radLon = degLon.degToRad();
  // minimum and maximum latitudes for given distance
  minLat = radLat - radDist;
  maxLat = radLat + radDist;
  // minimum and maximum longitudes for given distance
  minLon = void 0;
  maxLon = void 0;
  // define deltaLon to help determine min and max longitudes
  deltaLon = Math.asin(Math.sin(radDist) / Math.cos(radLat));
  if (minLat > MIN_LAT && maxLat < MAX_LAT) {
    minLon = radLon - deltaLon;
    maxLon = radLon + deltaLon;
    if (minLon < MIN_LON) {
      minLon = minLon + 2 * Math.PI;
    }
    if (maxLon > MAX_LON) {
      maxLon = maxLon - 2 * Math.PI;
    }
  }
  // a pole is within the given distance
  else {
    minLat = Math.max(minLat, MIN_LAT);
    maxLat = Math.min(maxLat, MAX_LAT);
    minLon = MIN_LON;
    maxLon = MAX_LON;
  }
  return [
    minLon.radToDeg(),
    minLat.radToDeg(),
    maxLon.radToDeg(),
    maxLat.radToDeg()
  ];
};

รหัสนี้ใช้ไม่ได้เลย ฉันหมายความว่าแม้หลังจากแก้ไขข้อผิดพลาดที่ชัดเจนเช่นminLon = void 0;แล้วmaxLon = MAX_LON;ก็ยังไม่ได้ผล
aroth

1
@aroth ฉันเพิ่งทดสอบและไม่มีปัญหา โปรดจำไว้ว่าcenterPointอาร์กิวเมนต์คืออาร์เรย์ที่ประกอบด้วยสองพิกัด เช่นgetBoundingBox([42.2, 34.5], 50)- void 0คือเอาต์พุต CoffeeScript สำหรับ "ไม่ได้กำหนด" และจะไม่มีผลต่อความสามารถในการรันโค้ด
asalisbury

รหัสนี้ใช้ไม่ได้ degLat.degToRadไม่ใช่ฟังก์ชัน
user299709

โค้ดทำงานในโหนดและ Chrome ตามที่เป็นอยู่จนกว่าฉันจะใส่ไว้ในโปรเจ็กต์ที่ฉันกำลังดำเนินการและเริ่มได้รับdegToRadข้อผิดพลาด "ไม่ใช่ฟังก์ชัน" ไม่เคยพบว่าทำไม แต่Number.prototype.ไม่ใช่ความคิดที่ดีสำหรับฟังก์ชั่นยูทิลิตี้เช่นนี้ดังนั้นฉันจึงแปลงฟังก์ชันเหล่านั้นให้เป็นฟังก์ชันท้องถิ่นปกติ สิ่งสำคัญที่ควรทราบคือกล่องที่ส่งคืนคือ [LNG, LAT, LNG, LAT] แทนที่จะเป็น [LAT, LNG, LAT, LNG] ฉันแก้ไขฟังก์ชันส่งคืนเมื่อฉันใช้สิ่งนี้เพื่อหลีกเลี่ยงความสับสน
KernelDeimos

9

เนื่องจากฉันต้องการการประมาณที่หยาบมากดังนั้นเพื่อกรองเอกสารที่ไม่จำเป็นออกไปในแบบสอบถาม elasticsearch ฉันจึงใช้สูตรด้านล่าง:

Min.lat = Given.Lat - (0.009 x N)
Max.lat = Given.Lat + (0.009 x N)
Min.lon = Given.lon - (0.009 x N)
Max.lon = Given.lon + (0.009 x N)

N = kms ต้องการจากตำแหน่งที่กำหนด สำหรับกรณีของคุณ N = 10

ไม่แม่นยำ แต่มีประโยชน์


อันที่จริงไม่ถูกต้อง แต่ยังมีประโยชน์และใช้งานง่ายมาก
MV.

6

คุณกำลังมองหาสูตรทรงรี

สถานที่ที่ดีที่สุดที่ฉันพบในการเริ่มต้นการเข้ารหัสนั้นมาจากไลบรารี Geo :: Ellipsoid จาก CPAN ช่วยให้คุณมีพื้นฐานในการสร้างการทดสอบและเปรียบเทียบผลลัพธ์ของคุณกับผลลัพธ์ ฉันใช้มันเป็นพื้นฐานสำหรับไลบรารีที่คล้ายกันสำหรับ PHP ที่นายจ้างคนก่อนของฉัน

ภูมิศาสตร์ :: Ellipsoid

ลองดูlocationวิธีการ เรียกสองครั้งและคุณมี bbox ของคุณ

คุณไม่ได้โพสต์ว่าคุณใช้ภาษาอะไร อาจมีไลบรารี geocoding สำหรับคุณอยู่แล้ว

อ้อถ้าตอนนี้คุณยังคิดไม่ออกแผนที่ Google ใช้วงรี WGS84


5

ภาพประกอบของ @Jan Philip Matuschek คำอธิบายที่ยอดเยี่ยม (โปรดโหวตคำตอบของเขาไม่ใช่สิ่งนี้ฉันกำลังเพิ่มสิ่งนี้เนื่องจากฉันใช้เวลาเล็กน้อยในการทำความเข้าใจคำตอบเดิม)

เทคนิคการกำหนดกรอบขอบเขตในการหาเพื่อนบ้านที่ใกล้ที่สุดจะต้องได้รับค่าละติจูดต่ำสุดและสูงสุดคู่ลองจิจูดสำหรับจุด P ที่ระยะทาง d จุดทั้งหมดที่อยู่นอกจุดเหล่านี้มีระยะทางมากกว่า d จากจุดนั้นอย่างแน่นอน สิ่งหนึ่งที่ควรทราบคือการคำนวณละติจูดของจุดตัดตามที่ไฮไลต์ไว้ในคำอธิบายของ Jan Philip Matuschek ละติจูดของจุดตัดไม่ได้อยู่ที่ละติจูดของจุด P แต่หักล้างกันเล็กน้อย นี่เป็นส่วนที่พลาดบ่อย แต่สำคัญในการกำหนดลองจิจูดต่ำสุดและสูงสุดที่ถูกต้องสำหรับจุด P สำหรับระยะทาง d สิ่งนี้ยังมีประโยชน์ในการตรวจสอบ

ระยะฮาเวอร์ไซน์ระหว่าง (ละติจูดของจุดตัด, ลองจิจูดสูง) ถึง (ละติจูด, ลองจิจูด) ของ P เท่ากับระยะทาง d

ส่วนสำคัญ Python ที่นี่https://gist.github.com/alexcpn/f95ae83a7ee0293a5225

ใส่คำอธิบายภาพที่นี่


5

1 degree latitude ~ 111.2 kmนี่คือการดำเนินการอย่างง่ายโดยใช้จาวาสคริปต์ซึ่งจะขึ้นอยู่กับการเปลี่ยนแปลงของการศึกษาระดับปริญญารุ้งกิโลเมตรที่

ฉันกำลังคำนวณขอบเขตของแผนที่จากละติจูดและลองจิจูดที่กำหนดโดยมีความกว้าง 10 กม.

function getBoundsFromLatLng(lat, lng){
     var lat_change = 10/111.2;
     var lon_change = Math.abs(Math.cos(lat*(Math.PI/180)));
     var bounds = { 
         lat_min : lat - lat_change,
         lon_min : lng - lon_change,
         lat_max : lat + lat_change,
         lon_max : lng + lon_change
     };
     return bounds;
}

4

ฉันปรับสคริปต์ PHP ที่พบว่าทำได้เพียงแค่นี้ คุณสามารถใช้มันเพื่อหามุมของกล่องรอบ ๆ จุด (พูด 20 กม.) ตัวอย่างเฉพาะของฉันสำหรับ Google Maps API:

http://www.richardpeacock.com/blog/2011/11/draw-box-around-coordinate-google-maps-based-miles-or-kilometers


-1 สิ่งที่ OP กำลังมองหาคือ: กำหนดจุดอ้างอิง (lat, lon) และระยะทางให้ค้นหาช่องที่เล็กที่สุดเพื่อให้ทุกจุดที่ <= "ระยะทาง" ห่างจากจุดอ้างอิงไม่อยู่นอกกรอบ กล่องของคุณมีมุม "ระยะ" ห่างจากจุดอ้างอิงจึงเล็กเกินไป ตัวอย่าง: จุดที่เป็น "ระยะทาง" เนื่องจากทิศเหนืออยู่นอกกรอบของคุณ
John Machin

บังเอิญมันเป็นสิ่งที่ฉันต้องการจริงๆ ขอบคุณแม้ว่าจะไม่ค่อยตอบคำถามนี้ก็ตาม:)
Simon Steinberger

ฉันดีใจที่สามารถช่วยใครสักคนได้!
Richard

1

ฉันกำลังแก้ไขปัญหากล่องขอบเขตเป็นปัญหาด้านข้างเพื่อค้นหาจุดทั้งหมดภายในรัศมี SrcRad ของ LAT คงที่จุดยาว มีการคำนวณค่อนข้างน้อยที่ใช้

maxLon = $lon + rad2deg($rad/$R/cos(deg2rad($lat)));
minLon = $lon - rad2deg($rad/$R/cos(deg2rad($lat)));

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

(SrcRad/RadEarth)/cos(deg2rad(lat))

ฉันรู้ฉันรู้ว่าคำตอบควรจะเหมือนกัน แต่ฉันพบว่ามันไม่ใช่ ดูเหมือนว่าโดยไม่แน่ใจว่าฉันกำลังทำ (SRCrad / RadEarth) ก่อนแล้วจึงหารด้วยส่วน Cos ฉันจึงทิ้งตำแหน่งบางจุดไว้

หลังจากที่คุณได้รับจุดขอบเขตของกรอบทั้งหมดแล้วหากคุณมีฟังก์ชันที่คำนวณระยะทางของจุดต่อจุดที่กำหนดให้ lat long มันเป็นเรื่องง่ายที่จะได้รับเฉพาะจุดที่เป็นรัศมีระยะทางหนึ่งจากจุดคงที่ นี่คือสิ่งที่ฉันทำ ฉันรู้ว่าต้องใช้ขั้นตอนเพิ่มเติมเล็กน้อย แต่ก็ช่วยฉันได้

-- GLOBAL Constants
gc_pi CONSTANT REAL := 3.14159265359;  -- Pi

-- Conversion Factor Constants
gc_rad_to_degs          CONSTANT NUMBER := 180/gc_pi; -- Conversion for Radians to Degrees 180/pi
gc_deg_to_rads          CONSTANT NUMBER := gc_pi/180; --Conversion of Degrees to Radians

lv_stat_lat    -- The static latitude point that I am searching from 
lv_stat_long   -- The static longitude point that I am searching from 

-- Angular radius ratio in radians
lv_ang_radius := lv_search_radius / lv_earth_radius;
lv_bb_maxlat := lv_stat_lat + (gc_rad_to_deg * lv_ang_radius);
lv_bb_minlat := lv_stat_lat - (gc_rad_to_deg * lv_ang_radius);

--Here's the tricky part, accounting for the Longitude getting smaller as we move up the latitiude scale
-- I seperated the parts of the equation to make it easier to debug and understand
-- I may not be a smart man but I know what the right answer is... :-)

lv_int_calc := gc_deg_to_rads * lv_stat_lat;
lv_int_calc := COS(lv_int_calc);
lv_int_calc := lv_ang_radius/lv_int_calc;
lv_int_calc := gc_rad_to_degs*lv_int_calc;

lv_bb_maxlong := lv_stat_long + lv_int_calc;
lv_bb_minlong := lv_stat_long - lv_int_calc;

-- Now select the values from your location datatable 
SELECT *  FROM (
SELECT cityaliasname, city, state, zipcode, latitude, longitude, 
-- The actual distance in miles
spherecos_pnttopntdist(lv_stat_lat, lv_stat_long, latitude, longitude, 'M') as miles_dist    
FROM Location_Table 
WHERE latitude between lv_bb_minlat AND lv_bb_maxlat
AND   longitude between lv_bb_minlong and lv_bb_maxlong)
WHERE miles_dist <= lv_limit_distance_miles
order by miles_dist
;

0

มันง่ายมากเพียงไปที่เว็บไซต์ panoramio จากนั้นเปิดแผนที่โลกจากเว็บไซต์ panoramio จากนั้นไปที่ตำแหน่งที่ระบุซึ่งต้องการละติจูดและลองจิจูด

จากนั้นคุณจะพบละติจูดและลองจิจูดในแถบที่อยู่เช่นในที่อยู่นี้

http://www.panoramio.com/map#lt=32.739485&ln=70.491211&z=9&k=1&a=1&tab=1&pl=all

lt = 32.739485 => ละติจูด ln = 70.491211 => ลองจิจูด

วิดเจ็ต Panoramio JavaScript API นี้สร้างกรอบล้อมรอบคู่ละติจูด / ยาวจากนั้นส่งคืนรูปภาพทั้งหมดในขอบเขตเหล่านั้น

ประเภทของเครื่องมือ Panoramio JavaScript API อีกในที่ที่คุณยังสามารถเปลี่ยนสีพื้นหลังที่มีตัวอย่างและรหัสอยู่ที่นี่

ไม่แสดงในการแต่งอารมณ์ แต่จะแสดงหลังจากเผยแพร่

<div dir="ltr" style="text-align: center;" trbidi="on">
<script src="https://ssl.panoramio.com/wapi/wapi.js?v=1&amp;hl=en"></script>
<div id="wapiblock" style="float: right; margin: 10px 15px"></div>
<script type="text/javascript">
var myRequest = {
  'tag': 'kahna',
  'rect': {'sw': {'lat': -30, 'lng': 10.5}, 'ne': {'lat': 50.5, 'lng': 30}}
};
  var myOptions = {
  'width': 300,
  'height': 200
};
var wapiblock = document.getElementById('wapiblock');
var photo_widget = new panoramio.PhotoWidget('wapiblock', myRequest, myOptions);
photo_widget.setPosition(0);
</script>
</div>

0

ที่นี่ฉันได้แปลงคำตอบของ Federico A.Ramponi เป็น PHP แล้วหากใครสนใจ:

<?php
# deg2rad and rad2deg are already within PHP

# Semi-axes of WGS-84 geoidal reference
$WGS84_a = 6378137.0;  # Major semiaxis [m]
$WGS84_b = 6356752.3;  # Minor semiaxis [m]

# Earth radius at a given latitude, according to the WGS-84 ellipsoid [m]
function WGS84EarthRadius($lat)
{
    global $WGS84_a, $WGS84_b;

    $an = $WGS84_a * $WGS84_a * cos($lat);
    $bn = $WGS84_b * $WGS84_b * sin($lat);
    $ad = $WGS84_a * cos($lat);
    $bd = $WGS84_b * sin($lat);

    return sqrt(($an*$an + $bn*$bn)/($ad*$ad + $bd*$bd));
}

# Bounding box surrounding the point at given coordinates,
# assuming local approximation of Earth surface as a sphere
# of radius given by WGS84
function boundingBox($latitudeInDegrees, $longitudeInDegrees, $halfSideInKm)
{
    $lat = deg2rad($latitudeInDegrees);
    $lon = deg2rad($longitudeInDegrees);
    $halfSide = 1000 * $halfSideInKm;

    # Radius of Earth at given latitude
    $radius = WGS84EarthRadius($lat);
    # Radius of the parallel at given latitude
    $pradius = $radius*cos($lat);

    $latMin = $lat - $halfSide / $radius;
    $latMax = $lat + $halfSide / $radius;
    $lonMin = $lon - $halfSide / $pradius;
    $lonMax = $lon + $halfSide / $pradius;

    return array(rad2deg($latMin), rad2deg($lonMin), rad2deg($latMax), rad2deg($lonMax));
}
?>

0

ขอบคุณ @Fedrico A. สำหรับการใช้งาน Phyton ฉันได้ย้ายไปอยู่ในคลาสประเภท Objective C ที่นี่คือ:

#import "LocationService+Bounds.h"

//Semi-axes of WGS-84 geoidal reference
const double WGS84_a = 6378137.0; //Major semiaxis [m]
const double WGS84_b = 6356752.3; //Minor semiaxis [m]

@implementation LocationService (Bounds)

struct BoundsLocation {
    double maxLatitude;
    double minLatitude;
    double maxLongitude;
    double minLongitude;
};

+ (struct BoundsLocation)locationBoundsWithLatitude:(double)aLatitude longitude:(double)aLongitude maxDistanceKm:(NSInteger)aMaxKmDistance {
    return [self boundingBoxWithLatitude:aLatitude longitude:aLongitude halfDistanceKm:aMaxKmDistance/2];
}

#pragma mark - Algorithm 

+ (struct BoundsLocation)boundingBoxWithLatitude:(double)aLatitude longitude:(double)aLongitude halfDistanceKm:(double)aDistanceKm {
    double radianLatitude = [self degreesToRadians:aLatitude];
    double radianLongitude = [self degreesToRadians:aLongitude];
    double halfDistanceMeters = aDistanceKm*1000;


    double earthRadius = [self earthRadiusAtLatitude:radianLatitude];
    double parallelRadius = earthRadius*cosl(radianLatitude);

    double radianMinLatitude = radianLatitude - halfDistanceMeters/earthRadius;
    double radianMaxLatitude = radianLatitude + halfDistanceMeters/earthRadius;
    double radianMinLongitude = radianLongitude - halfDistanceMeters/parallelRadius;
    double radianMaxLongitude = radianLongitude + halfDistanceMeters/parallelRadius;

    struct BoundsLocation bounds;
    bounds.minLatitude = [self radiansToDegrees:radianMinLatitude];
    bounds.maxLatitude = [self radiansToDegrees:radianMaxLatitude];
    bounds.minLongitude = [self radiansToDegrees:radianMinLongitude];
    bounds.maxLongitude = [self radiansToDegrees:radianMaxLongitude];

    return bounds;
}

+ (double)earthRadiusAtLatitude:(double)aRadianLatitude {
    double An = WGS84_a * WGS84_a * cosl(aRadianLatitude);
    double Bn = WGS84_b * WGS84_b * sinl(aRadianLatitude);
    double Ad = WGS84_a * cosl(aRadianLatitude);
    double Bd = WGS84_b * sinl(aRadianLatitude);
    return sqrtl( ((An * An) + (Bn * Bn))/((Ad * Ad) + (Bd * Bd)) );
}

+ (double)degreesToRadians:(double)aDegrees {
    return M_PI*aDegrees/180.0;
}

+ (double)radiansToDegrees:(double)aRadians {
    return 180.0*aRadians/M_PI;
}



@end

ฉันได้ทดสอบแล้วและดูเหมือนว่าจะทำงานได้ดี Struct BoundsLocation ควรถูกแทนที่ด้วยคลาสฉันใช้มันเพื่อแบ่งปันที่นี่


0

ทั้งหมดของคำตอบข้างต้นเป็นเพียงบางส่วนที่ถูกต้อง โดยเฉพาะอย่างยิ่งในภูมิภาคเช่นออสเตรเลียพวกเขามักจะรวมเสาและคำนวณสี่เหลี่ยมผืนผ้าขนาดใหญ่มากแม้ในระยะ 10 กม.

โดยเฉพาะอัลกอริทึมของ Jan Philip Matuschek ที่http://janmatuschek.de/LatitudeLongitudeBoundingCoordinates#UsingIndexรวมรูปสี่เหลี่ยมผืนผ้าขนาดใหญ่มากจาก (-37, -90, -180, 180) สำหรับเกือบทุกจุดในออสเตรเลีย สิ่งนี้กระทบผู้ใช้จำนวนมากในฐานข้อมูลและต้องคำนวณระยะทางสำหรับผู้ใช้ทั้งหมดในเกือบครึ่งประเทศ

ฉันพบว่าDrupal API Earth Algorithm โดย Rochester Institute of Technologyทำงานได้ดีกว่าในทุก ๆ ขั้วและที่อื่น ๆ และง่ายต่อการใช้งานมาก

https://www.rit.edu/drupal/api/drupal/sites%21all%21modules%21location%21earth.inc/7.54

ใช้earth_latitude_rangeและearth_longitude_rangeจากอัลกอริทึมด้านบนสำหรับการคำนวณกรอบสี่เหลี่ยม

และใช้สูตรการคำนวณระยะทางที่จัดทำโดย google mapsเพื่อคำนวณระยะทาง

https://developers.google.com/maps/solutions/store-locator/clothing-store-locator#outputting-data-as-xml-using-php

หากต้องการค้นหาตามกิโลเมตรแทนไมล์ให้แทนที่ 3959 ด้วย 6371 สำหรับ (Lat, Lng) = (37, -122) และตาราง Markers ที่มีคอลัมน์ lat และ lngสูตรคือ:

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;

อ่านคำตอบโดยละเอียดของฉันที่https://stackoverflow.com/a/45950426/5076414


0

นี่คือคำตอบของ Federico Ramponi ใน Go หมายเหตุ: ไม่มีการตรวจสอบข้อผิดพลาด :(

import (
    "math"
)

// Semi-axes of WGS-84 geoidal reference
const (
    // Major semiaxis (meters)
    WGS84A = 6378137.0
    // Minor semiaxis (meters)
    WGS84B = 6356752.3
)

// BoundingBox represents the geo-polygon that encompasses the given point and radius
type BoundingBox struct {
    LatMin float64
    LatMax float64
    LonMin float64
    LonMax float64
}

// Convert a degree value to radians
func deg2Rad(deg float64) float64 {
    return math.Pi * deg / 180.0
}

// Convert a radian value to degrees
func rad2Deg(rad float64) float64 {
    return 180.0 * rad / math.Pi
}

// Get the Earth's radius in meters at a given latitude based on the WGS84 ellipsoid
func getWgs84EarthRadius(lat float64) float64 {
    an := WGS84A * WGS84A * math.Cos(lat)
    bn := WGS84B * WGS84B * math.Sin(lat)

    ad := WGS84A * math.Cos(lat)
    bd := WGS84B * math.Sin(lat)

    return math.Sqrt((an*an + bn*bn) / (ad*ad + bd*bd))
}

// GetBoundingBox returns a BoundingBox encompassing the given lat/long point and radius
func GetBoundingBox(latDeg float64, longDeg float64, radiusKm float64) BoundingBox {
    lat := deg2Rad(latDeg)
    lon := deg2Rad(longDeg)
    halfSide := 1000 * radiusKm

    // Radius of Earth at given latitude
    radius := getWgs84EarthRadius(lat)

    pradius := radius * math.Cos(lat)

    latMin := lat - halfSide/radius
    latMax := lat + halfSide/radius
    lonMin := lon - halfSide/pradius
    lonMax := lon + halfSide/pradius

    return BoundingBox{
        LatMin: rad2Deg(latMin),
        LatMax: rad2Deg(latMax),
        LonMin: rad2Deg(lonMin),
        LonMax: rad2Deg(lonMax),
    }
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.