SQLite ile Büyük-Çember Mesafe Hesaplama

3 Cevap php

İşte benim sorunum ben yerleri ve enlemleri / boylamları ile SQLite tablo var, bir. Temelde gerekiyor:

SELECT location, HAVERSINE(lat, lon) AS distance FROM location ORDER BY distance ASC;

HAVERSINE() PHP işlevi locations tabloda that should return the Great-Circle Distance (in miles or km) given a pair of latitude and longitude values. One of these pairs should be provided by PHP and the other pair should be provided by each latitude / longitude row kullanılabilir.

SQLite herhangi Geo Mekansal uzantısına sahip olmadığından (AFAIK SpatiaLite ancak hala var ... ) Ben iyi yaklaşım tahmin ediyorum özel bir işlevi kullanmak olacaktır ile ya PDO yöntemlerden biri:

Ancak bu fonksiyon ile benim sınırlı deneyim PHP Kılavuzunda sağlanan benzer kullanım durumda azaltılmış olabilir, bu durum için PDO::sqliteCreateFunction() yeterli olacağını düşünüyorum:

$db = new PDO('sqlite:geo.db');

function md5_and_reverse($string) { return strrev(md5($string)); }

$db->sqliteCreateFunction('md5rev', 'md5_and_reverse', 1);
$rows = $db->query('SELECT md5rev(filename) FROM files')->fetchAll();

Ben nasıl process data from PHP and table data at the same time bir SQLite kullanıcı tanımlı işlevi alabilirsiniz sergiyi bazı sorun yaşıyorum ve aynı zamanda (SQLite IMO büyük bir galibiyet) SQLite UDF'leri anlayış iken birisi bana bu sorunu çözmeye yardımcı olabilir sevinirim biraz daha iyi.

Şimdiden teşekkürler!

3 Cevap

Sizin "ilginç bağlantıyı" dan.

function sqlite3_distance_func($lat1,$lon1,$lat2,$lon2) {
    // convert lat1 and lat2 into radians now, to avoid doing it twice below
    $lat1rad = deg2rad($lat1);
    $lat2rad = deg2rad($lat2);
    // apply the spherical law of cosines to our latitudes and longitudes, and set the result appropriately
    // 6378.1 is the approximate radius of the earth in kilometres
    return acos( sin($lat1rad) * sin($lat2rad) + cos($lat1rad) * cos($lat2rad) * cos( deg2rad($lon2) - deg2rad($lon1) ) ) * 6378.1;
}

$db->sqliteCreateFunction('DISTANCE', 'sqlite3_distance_func', 4);

Sonra bir sorgu yapın:

"SELECT * FROM location ORDER BY distance(latitude,longitude,{$lat},{$lon}) LIMIT 1"

EDIT (by QOP): Sonunda yine bu gerekli ve bu çözüm amele büyük, ben sadece biraz biraz daha ayrıntılı ve incelikle sayısal olmayan değerleri işleme kodunu değiştirerek sona erdi, işte burada:

$db->sqliteCreateFunction('distance', function () {
    if (count($geo = array_map('deg2rad', array_filter(func_get_args(), 'is_numeric'))) == 4) {
        return round(acos(sin($geo[0]) * sin($geo[2]) + cos($geo[0]) * cos($geo[2]) * cos($geo[1] - $geo[3])) * 6378.14, 3);
    }

    return null;
}, 4);

Şimdiye kadar sadece bu çözüm düşünebiliriz:

$db = new PDO('sqlite:geo.db');

$db->sqliteCreateFunction('ACOS', 'acos', 1);
$db->sqliteCreateFunction('COS', 'cos', 1);
$db->sqliteCreateFunction('RADIANS', 'deg2rad', 1);
$db->sqliteCreateFunction('SIN', 'sin', 1);

Ve sonra aşağıdaki uzun sorguyu yürütün:

SELECT "location",
       (6371 * ACOS(COS(RADIANS($latitude)) * COS(RADIANS("latitude")) * COS(RADIANS("longitude") - RADIANS($longitude)) + SIN(RADIANS($latitude)) * SIN(RADIANS("latitude")))) AS "distance"
FROM "locations"
HAVING "distance" < $distance
ORDER BY "distance" ASC
LIMIT 10;

Herkes daha iyi bir çözüm düşünüyorum eğer bana bildirin lütfen.


I just found this interesting link, yarın bunu deneyeceğim.

Alix'ın cevabı kapalı bina ...

$db->sqliteCreateFunction('HAVERSINE', 'haversine', 2);

Ben bu sorunuzun belirtilen sorgu çalışmak için izin olacağını hayal ediyorum.