Solved

Application to identify city from GPS coordinates

Posted on 2011-09-12
14
410 Views
Last Modified: 2012-06-21
Hi.  I am looking for an application which can identify by name a city from long/lat.  I need to feed a file of records ...

15|1|0|09/11/2011 00:00:11|Y|51440|51440|34046999|-118457499|62|6519|22012|0|
15|1|0|09/11/2011 00:00:26|Y|51832|51832|34094666|-118347166|23|6312|18841|0|
15|1|0|09/11/2011 00:00:51|Y|51772|51772|34060999|-118435166|30|6626|21081|0|
15|1|0|09/11/2011 00:01:01|Y|51128|51128|34048166|-118459833|86|6245|19869|0|

..into it and be able to extract only those records in a specific California city.  An application or even an API to build such an application around.  Access to the internet during processing is a given.
0
Comment
Question by:michaelheffernan
  • 9
  • 5
14 Comments
 
LVL 108

Expert Comment

by:Ray Paseur
ID: 36528915
The thing you want is called a "reverse geocoder" and it is a relatively new invention.  Where did these pipe-delimited strings come from?  Can you please tell us what is in each sub-string?  Thanks.
0
 

Author Comment

by:michaelheffernan
ID: 36530167
Hello. Thank you for responding.
The fields are:
type small_int
tds_nbr int
dt_tm datetime
fl_id char
call_nbr int
info1 int
info2 int
info3 int
info4 int
vh_nbr smallint
dr_id int
user_id smallint

In this instance (an export from a vehicle dispatch system), info2 and info3 are the long/lat of an event.

"Reverse decoders" are new?  I figured Google et al have been doing this for years, and that perhaps "they" have an appropriate webservice.  However, I will need to run several thousand of these records thru this black box monthly to identify that event occurring in that city (either great circle or box-defined - it won't be perfect, I know), and suspect a web service would be too slow.  I'd rather a localized DB to run these against.


0
 
LVL 108

Expert Comment

by:Ray Paseur
ID: 36530285
I have to leave for an appointment now so I cannot write the code sample that I would normally write - at least not until tomorrow.  But have a look at this:
http://code.google.com/apis/maps/documentation/geocoding/#ReverseGeocoding
http://code.google.com/apis/maps/documentation/geocoding/#Limits

Sorry - gotta run.  But I expect that with a little creative design you can get this to work below the Google radar line of 2,500 calls.
0
 

Author Comment

by:michaelheffernan
ID: 36530622
Thanks. I will look at 'em.  I also found an API called MapPoint which might do the trick...
0
 

Author Comment

by:michaelheffernan
ID: 36530647
Well, a little research indicates something like a minute to more than two minutes per lat/lng query!  Methinks I need to stick to a localized DB...
0
 
LVL 108

Accepted Solution

by:
Ray Paseur earned 250 total points
ID: 36536095
My results suggest about a tenth of a second per geocoder query.  Here is my test script.
<?php // RAY_temp_michaelheffernan.php
error_reporting(E_ALL);
echo "<pre>";

// FROM EE: http://www.experts-exchange.com/Database/GIS_and_GPS/Q_27304002.html?cid=1572#a36530622
// FROM GOOGLE: http://maps.googleapis.com/maps/api/geocode/json?latlng=40.714224,-73.961452&sensor=true_or_false

// TEST DATA
$thing = <<<THING
15|1|0|09/11/2011 00:00:11|Y|51440|51440|34046999|-118457499|62|6519|22012|0|
15|1|0|09/11/2011 00:00:26|Y|51832|51832|34094666|-118347166|23|6312|18841|0|
15|1|0|09/11/2011 00:00:51|Y|51772|51772|34060999|-118435166|30|6626|21081|0|
15|1|0|09/11/2011 00:01:01|Y|51128|51128|34048166|-118459833|86|6245|19869|0|
THING;

// THE DESCRIPTION OF THE TEST DATA APPEARS TO HAVE OMITTED A FIELD BEFORE THE DATETIME STRING
// type small_int
// tds_nbr int
// dt_tm datetime
// fl_id char
// call_nbr int
// info1 int
// info2 int
// info3 int
// info4 int
// vh_nbr smallint
// dr_id int
// user_id smallint
// In this instance (an export from a vehicle dispatch system), info2 and info3 are the long/lat of an event.

// THE LOCATION OF THE WEB SERVICE
$url = 'http://maps.googleapis.com/maps/api/geocode/json?sensor=false&latlng=';

// START A TIMER TO SEE HOW LONG THIS PROCESS TAKES
$stw = new StopWatch;
$stw->start('GMAP');

// PROCESS THE FOUR GEOCODES THROUGH THE REVERSE GEOCODER
$dlm = '|';
$num = 0;
$arr = explode(PHP_EOL, $thing);
foreach ($arr as $str)
{
    $num++;
    $sub = explode($dlm, $str);
    $lat = (string)$sub[7] / 1000000.0;
    $lon = (string)$sub[8] / 1000000.0;
    $geo = "$lat,$lon";
    $req = $url . $geo;
    var_dump($req);
    $res = file_get_contents($req);
    $obj = json_decode($res);
    var_dump($obj);
}

// SHOW HOW LONG THIS TOOK
echo PHP_EOL;
echo "FINISHED $num GEOCODER CALLS.  HERE IS THE TIMER DATA:";
echo PHP_EOL;
echo $stw->readout('GMAP');
echo " MILLISECONDS";



// A CLASS TO TIME PART OF THIS SCRIPT
class StopWatch
{
    protected $a; // START TIME
    protected $s; // STATUS - IF RUNNING
    protected $z; // STOP TIME

    public function __construct()
    {
        $this->a = array();
        $this->s = array();
        $this->z = array();
    }

    // A METHOD TO REMOVE A TIMER
    public function reset($name='TIMER')
    {
        // RESET ALL TIMERS
        if ($name == 'TIMER')
        {
            $this->__construct();
        }
        else
        {
            unset($this->a[$name]);
            unset($this->s[$name]);
            unset($this->z[$name]);
        }
    }

    // A METHOD TO CAPTURE THE START TIME
    public function start($name='TIMER')
    {
        $this->a[$name] = microtime(TRUE);
        $this->z[$name] = $this->a[$name];
        $this->s[$name] = 'RUNNING';
    }

    // A METHOD TO CAPTURE THE END TIME
    public function stop($name='TIMER')
    {
        $ret = NULL;

        // STOP ALL THE TIMERS
        if ($name == 'TIMER')
        {
            foreach ($this->a as $name => $start_time)
            {
                // IF THIS TIMER IS STILL RUNNING, STOP IT
                if ($this->s[$name])
                {
                    $this->s[$name] = FALSE;
                    $this->z[$name] = microtime(TRUE);
                }
            }
        }

        // STOP ONLY ONE OF THE TIMERS
        else
        {
            if ($this->s[$name])
            {
                $this->s[$name] = FALSE;
                $this->z[$name] = microtime(TRUE);
            }
            else
            {
                $ret .= "ERROR: CALL TO STOP() METHOD FOR '$name' IS NOT RUNNING";
            }
        }

        // RETURN AN ERROR MESSAGE, IF ANY
        return $ret;
    }

    // A METHOD TO READ OUT THE TIMER(S)
    public function readout($name='TIMER', $dec=3, $m=1000, $eol=NULL)
    {
        $str = NULL;

        // GET READOUTS FOR ALL THE TIMERS
        if ($name == 'TIMER')
        {
            foreach ($this->a as $name => $start_time)
            {
                $str .= $name;

                // IF THIS TIMER IS STILL RUNNING UPDATE THE END TIME
                if ($this->s[$name])
                {
                    $this->z[$name] = microtime(TRUE);
                    $str .= " RUNNING ";
                }
                else
                {
                    $str .= " STOPPED ";
                }

                // RETURN A DISPLAY STRING
                $lapse_time = $this->z[$name] - $start_time;
                $lapse_msec = $lapse_time * $m;
                $lapse_echo = number_format($lapse_msec, $dec);
                $str .= " $lapse_echo";
                $str .= $eol;
            }
            return $str;
        }

        // GET A READOUT FOR ONLY ONE TIMER
        else
        {
            $str .= $name;

            // IF THIS TIME IS STILL RUNNING, UPDATE THE END TIME
            if ($this->s[$name])
            {
                $this->z[$name] = microtime(TRUE);
                $str .= " RUNNING ";
            }
            else
            {
                $str .= " STOPPED ";
            }


            // RETURN A DISPLAY STRING
            $lapse_time = $this->z[$name] - $this->a[$name];
            $lapse_msec = $lapse_time * $m;
            $lapse_echo = number_format($lapse_msec, $dec);
            $str .= " $lapse_echo";
            $str .= $eol;
            return $str;
        }
    }
}

Open in new window

0
 

Author Comment

by:michaelheffernan
ID: 36536680
Hmm...lemme give this a good look...TY
0
Find Ransomware Secrets With All-Source Analysis

Ransomware has become a major concern for organizations; its prevalence has grown due to past successes achieved by threat actors. While each ransomware variant is different, we’ve seen some common tactics and trends used among the authors of the malware.

 

Author Comment

by:michaelheffernan
ID: 36536735
// THE DESCRIPTION OF THE TEST DATA APPEARS TO HAVE OMITTED A FIELD BEFORE THE DATETIME STRING

Oops, yes, I did.  Type, status, tds_nbr,datetime.... sorry.
0
 

Author Comment

by:michaelheffernan
ID: 36537478
Well, we ran a handful of records thru Google; some of the times were indeed in the < 2 sec range.  However, there were several queries that stalled for far longer:

1. 1.23 seconds
2. 1.18 seconds
3. 1.43 seconds
4. 119.28 seconds
5. 2.43 seconds
6. 9.28 seconds
7. 1.29 seconds
8. 3.48 seconds
9. 2.11 seconds
10. 54.31 seconds

I have to suspect there are other factors (like network or server load or whatever) responsible for the wild swings.

I'm going to invest in the MapPoint solution ($500 or so is reasonable) to have local datamap access.  But I thank you for your help.
0
 

Author Closing Comment

by:michaelheffernan
ID: 36537483
query code was particularly useful.
0
 
LVL 108

Expert Comment

by:Ray Paseur
ID: 36537527
Interesting about the times you're getting from Google.  Possibly they throttle the API to prevent overloading?  I ran my script several times and never had it run longer than 0.4 seconds for the four separate calls.

I think if this were my app, I might keep a data base of lat/lon pairs and the responses (or parts of responses) that matter. That way you can check your data base first before you have to go to an outside service.  It will make the app more responsive if you do not have the external calls.  But maybe MapPoint will obviate the need for that.

Best regards, ~Ray
0
 

Author Comment

by:michaelheffernan
ID: 36537563
Ah, that is a good idea.  I can run against Google in the event MapPoint can't identify a pair.  I cannot imagine how Google would react if I ran 4500 records thru it, tho.  Not well, I'd imagine.  I suspect you're correct in speculating that Google may throttle under a variety of conditions.
Thank you again.
0
 
LVL 108

Expert Comment

by:Ray Paseur
ID: 36537743
There are 2,500 calls permitted per day.  If your script sleeps for a second between calls, you can do 2,500 now and 2,000 tomorrow.  Neither session will take longer than one hour (3,600 seconds per hour).  Just a thought.
0
 

Author Comment

by:michaelheffernan
ID: 36537858
Makes sense.  I am still concerned with the latency I did see.  Thanks.
0

Featured Post

What Should I Do With This Threat Intelligence?

Are you wondering if you actually need threat intelligence? The answer is yes. We explain the basics for creating useful threat intelligence.

Join & Write a Comment

Suggested Solutions

Title # Comments Views Activity
Create polygons with Google Earth 4 508
Google - getting coordinates 6 581
48 States 2 334
True North vs Phone North in iOS platform 18 720
I feel like more and more people want to know how to programmatically convert addresses into geospatial locations. So in this article, I will show you how you can do it with Bing Maps. I'm going to use PowerShell, which is a nice scripting language,…
Introduction This article is designed to assist GIS (Geographic Information System) and GPS (Global Positioning System) developers using ESRI ArcGIS and other spatial information management systems.   For the uninitiated the concept of projectio…
This tutorial demonstrates how to identify and create boundary or building outlines in Google Maps. In this example, I outline the boundaries of an enclosed skatepark within a community park.  Login to your Google Account, then  Google for "Google M…
This tutorial walks through the best practices in adding a local business to Google Maps including how to properly search for duplicates, marker placement, and inputing business details. Login to your Google Account, then search for "Google Mapmaker…

747 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

12 Experts available now in Live!

Get 1:1 Help Now