Free Fire Call Mapping

Many fire departments are able to receive text or email messages from their dispatch center’s computer-assisted dispatch (CAD) system to alert them to a call.  These text messaging systems are usually a secondary means of notification, with voice or alphanumeric paging being the primary method, since commercial text messaging can be delayed if the system is busy.  This page describes how to use the information from a CAD system email to map out directions to the call on a Google Map page and also to show the actual building in Google Street View.  These can both be integrated into a single web page that can be displayed in a truck bay or on an apparatus laptop.  The driving directions help with route planning, and the Street View snapshot can help give us clues about building construction, occupancy type, and apparatus placement before we ever even arrive.

Getting Started

First, your dispatch center must be able to send the call information to an email address.  Next, you’ll need a list of addresses in your coverage district with associated latitude and longitude for each address.  You may be able to get this from your city our county GIS department.  If not, you can generate this data yourself using Google Earth, but it will take some work.  In addition, in order to get the Street View working properly, you’ll need a data set that has the roads in your district in some type of segmented line format.  This could be as a shapefile, KML file, etc.  Again, your GIS department may have this data, or you can generate it yourself using Google Earth.  Finally, you’ll need a web server that you can host the web page on.  The server must be running PHP.  If your department already has a website, you can probably use that web server.  Or, if you only need the mapping on one computer, you could host the web page locally using WampServer.

How It Works

  1. When a call is received the dispatch email containing the address information is sent out
  2.  Upon loading the web page, a PHP script checks the email account and parses the address information from the most-recently received email from the dispatch center.
  3.  The PHP script then loops through a pre-stored list of addresses in your district to try to find a match with the address from the dispatch email
  4.  If an exact match is found, the script grabs the latitude and longitude of that address from your pre-stored file and uses the Google Maps API to display driving directions from your fire station to that address.  Additional call information from the dispatch email can also be displayed in an infowindow.  The directions come from Google’s algorithm, so they may not always be the best for your situation.   Use them as a guide only.
  5.  If a close match to the address isn’t found, the script can send the raw address information from the dispatch email directly to the Google Maps API and get Google’s best guess as to the location and driving directions.  In this case, the background of the infowindow is colored red to indicate that the location and directions may not be accurate.
  6. If you have road segment data available, the script can also find a good camera location and heading to send to the Street View API so that a street-level picture of the building can also be shown.


The most important key to making this system work is to have accurate address data.  This means a list of addresses with associated latitude and longitude.  While Google Maps are nice, the exact addresses can be off by quite a distance, especially on rural roads.  Having your own data set allows you to map to a specific set of coordinates (which Google Maps is very good at) instead of to an address that may not be accurate in Google’s database.  This data set could come from a county or city Geographic Information Services (GIS) department, or you can manually generate it yourself using Google Earth.  In any case, the format isn’t critical, as long as you have the data.  In my situation I used an ESRI shapefile as a starting point and converted that into a KML file that I could view and edit in Google Earth.  It’s important to spend some time looking over the data set closely and making additions and corrections.  Don’t assume that the data that the county or city gives you is 100% correct (also, share your corrections with your GIS department).  After I had all of my corrections made, I converted the KML file into a CSV file for ease of use by the PHP script.  The resulting CSV file is simply a list of addresses with associated lat/long, in comma-separated text format:

18619 ZIMMERMAN RD,40.5994167,-89.2832167
18684 ZIMMERMAN RD,40.6000333,-89.2817333
18701 TANNER RD,40.6003667,-89.2939333

Once you have this, it’s all a matter of PHP and javascript code (example code).  The PHP code checks an email address for messages from your dispatch center. It then parses the address information from the email.  This parsing will be unique to the format of the emails that you receive, but it should be doable.  Once the address has been parsed, it is compared to the addresses in the CSV file using the Levenshtein distance function to try to find an exact match (Levenshtein distance = 0).  If it finds an exact match, the PHP script returns the address and the associated lat/long, which is then used by the javascript code to get and display driving directions to that lat/long using the Google Maps API.  We’ll also use the Maps API to display additional call information in an infowindow at the destination marker on the map:

 Exact Match Found

Sometimes an exact match isn’t found but a close match is found.  As an example, this can happen if an address is given as “402 FIRST AVE” in the dispatch email but is listed as “402 FIRST AV” in the CSV file.  Or you may have a new address in your district that isn’t yet in your CSV file.  If the address given is “402 FIRST AVE” but you don’t yet have that address in the CSV file, “401 FIRST AVE” would produce a close, but not exact, match.  In this case we’ll still use the lat/long from the close match to send to the Google Maps API, but we’ll give a visual indication that an exact match wasn’t found by coloring the infowindow background yellow instead of green.  This lets responders know to check the address given and the address plotted to see why they’re different.  We’ll set a threshold of the Levenshtein distance (for example, distance <=2)  to determine whether it’s a close match or not.

Close Match Found

If no exact or close match is found, we can still punt and send the raw address information directly to the Google Maps API, instead of a lat/long.  This may get us close, or it could send us to a different state, it’s hard to say.  We’ll color the background of the destination marker’s infowindow red to alert responders that they really need to be careful about trusting the directions given.  In most cases, the guess is pretty good.  For example, an address might be given as an intersection of two roads for a car accident.  Since this isn’t an actual address, it may not be in your CSV file, but Google may still be able to figure out about where it is.  Another example may be a call in a mutual aid district that you don’t have exact address data for.  Again, Google may be able to get you close.  But it could also send you to somewhere in Arizona, so be careful.


No Close Match Found – Address Out of District

No Close Match Found – Address is an Intersection

Once you know the destination lat/long, you could also show a zoomed-in aerial image of the location, in addition to the driving directions.  This could be helpful for initial sizeup and apparatus positioning.  Or, you may also be able to show the building in Street View, but that takes some additional work, as described below.

Adding Street View

Having driving directions to an address is a big help, but what if you were able to see the building you’re going to before you ever even leave the station?  Street View makes that possible.  However, it’s not as easy as just giving Google a Lat/Long of a building and having it show up in Street View.  Instead, the Street View API requires that we input the lat/long of the camera location, which is the location on the street in front of the building, as well as a camera heading, which is the direction that the camera is pointing.

So we know the lat/long of our destination address, how do we get the lat/long of the location on the street that we want the street view camera to “shoot” from?  There are two ways we can go about doing this.  The first method works if we have a data set of road segments that we can use to calculate the best camera location from.  If we don’t have that data set available, there is a way to do some web-scraping of Google’s map results to get their best camera position and heading.

Using An Existing Dataset

First, we need to know where the road is.  In GIS terms, roads are made up of segments, and each segment has a starting set of coordinates, and an ending set of coordinates (lat/long).  Even a curved road can be segmented, it’s just broken up into a lot more segments than a straight road is:


If we can get a list of road segments in our district, we can then loop through all of the segments and find the distance from the closest point on each segment to our address coordinates using this algorithm (example code).  In the drawing below, it shows the shortest distance from each segment to our address (point A).  The point at the end of the shortest of all of the distances (point B) is where we want the Street View camera to be.


Now that we know where the camera should be located, we need to figure out which direction it should be facing (its heading).  Figuring this out requires some trigonometry (hint:  think arctangent!).  Also note that since the distances we’re dealing with are probably pretty small, we can cheat and use our lat/long coordinates as if they’re Cartesian coordinates and use Euclidean geometry, rather than getting technically correct and using Riemannian geometry, which is what we’d have to do to account for the curvature of the Earth if we were dealing with long distances.


Rather than loop through every road segment every time the web page is loaded, I decided to do this processing ahead of time.  I wrote a Python script (example code) to find the camera location and heading for each address in our district and append these to the CSV file that I use for getting driving directions.  So now each entry in the CSV file contains an address (text), address latitude, address longitude, camera latitude, camera longitude, and camera heading.  This makes the PHP and javascript a bit less cumbersome and faster:

120 Oak Valley Dr,40.6146688,-89.27487764,40.6138806113,-89.2741799034,318.483443301
204 Valley Ct,40.61397648,-89.27444237,40.6138806113,-89.2741799034,290.065251912
206 Valley Ct,40.61364851,-89.27424853,40.6138806113,-89.2741799034,196.471634843

Letting Google do the Work

If we don’t have a data set of road segments, there is a way that we can make Google do the work for us.  If you do a Google Map search of a location where Street View is available, you’ll notice that on the results page there is a link that you can click on to go directly to a Street View of that location.  For example, if I search for lat/long location 43.194966, -88.728030 in Google Maps, I get this back:

The Street View hyperlink contains the camera position and heading parameters that we want, so we can do some web scraping to extract those parameters and use them for our own API call.

Here is some PHP code that sends a lat/long to Google Maps and scrapes the returned web page to see if the Street View hyperlink is available.  If it is, it extracts the camera location (from the cbll parameter) and the heading (from the cbp parameter) to use in our own API call.  See this page for more information about the Google Maps URL parameters and how to understand them.



$data = file_get_contents('' .         $bestlat . ',' . $bestlong);

    $cbp_params = $match[1];
    $cbp_params = explode(',',$cbp_params);
    $bestSVheading = $cbp_params[1];
    $cbll_params = $match[1];
    $cbll_params = explode(',',$cbll_params);
    $bestSVlat = $cbll_params[0];
    $bestSVlong = $cbll_params[1];