ø Don’t waste your time reading this blog ø

Codeigniter Zipcode/Distance Calculator

Filed under: random, web 2.0 — Tags: , — taewoo @ 3:27 pm April 8, 2010

Port of Micah Carrick’s PHP Zip Code Range and Distance Calculation for Codeigniter:

application/plugins/zipcode_pi.php

 

 *      v1.0.0 [Apr 12, 2005] - Initial Version
 *
 *******************************************************************************
 *  DESCRIPTION:

 *    A PHP Class and MySQL table to find the distance between zip codes and
 *    find all zip codes within a given mileage or kilometer range.
 *
 *******************************************************************************
*/

// constants for setting the $units data member
define('_UNIT_MILES', 'm');
define('_UNIT_KILOMETERS', 'k');

// constants for passing $sort to get_zips_in_range()
define('_ZIPS_SORT_BY_DISTANCE_ASC', 1);
define('_ZIPS_SORT_BY_DISTANCE_DESC', 2);
define('_ZIPS_SORT_BY_ZIP_ASC', 3);
define('_ZIPS_SORT_BY_ZIP_DESC', 4);

// constant for miles to kilometers conversion
define('_M2KM_FACTOR', 1.609344);

class Zipcode {

   var $last_error = "";            // last error message set by this class
   var $last_time = 0;              // last function execution time (debug info)
   var $units = _UNIT_MILES;        // miles or kilometers
   var $decimals = 2;               // decimal places for returned distance
   var $CI;

   function Zipcode()
   {
      $this->CI =& get_instance();
      $this->CI->load->model('zipcode_model');
   }

   function get_distance($zip1, $zip2) {

      // returns the distance between to zip codes.  If there is an error, the
      // function will return false and set the $last_error variable.

      $this->chronometer();         // start the clock

      if ($zip1 == $zip2) return 0; // same zip code means 0 miles between. :) 

      // get details from database about each zip and exit if there is an error

      $details1 = $this->get_zip_point($zip1);
      $details2 = $this->get_zip_point($zip2);
      if ($details1 == false) {
         $this->last_error = "No details found for zip code: $zip1";
         return false;
      }
      if ($details2 == false) {
         $this->last_error = "No details found for zip code: $zip2";
         return false;
      }     

      // calculate the distance between the two points based on the lattitude
      // and longitude pulled out of the database.

      $miles = $this->calculate_mileage($details1[0], $details2[0], $details1[1], $details2[1]);

      $this->last_time = $this->chronometer();

      if ($this->units == _UNIT_KILOMETERS) return round($miles * _M2KM_FACTOR, $this->decimals);
      else return round($miles, $this->decimals);       // must be miles

   }   

	function get_zip_code($city, $state)
	{
		$rows = $this->CI->zipcode_model->get_zip_code($city, $state);
		if(count($rows) == 0)
			return FALSE;
		return $rows[0]->zip_code;
	}

   function get_zip_details($zip) {

      // This function pulls the details from the database for a
      // given zip code.
      $row = $this->CI->zipcode_model->get_zip_details($zip);

      if(count($row) == 0 )
      {
         return FALSE;
      }

      return array("latitude" => $row[0]->latitude,
                   "longitude" => $row[0]->longitude,
                   "city" => $row[0]->city,
                   "county" => $row[0]->county,
                   "state_prefix" =>$row[0]->state_prefix,
                   "state_name" =>$row[0]->state_name,
                   "area_code" =>$row[0]->area_code,
                   "time_zone" => $row[0]->time_zone);

   }

   function get_zip_point($zip) {

      $row = $this->CI->zipcode_model->get_zip_point($zip);

      if(count($row) == 0 )
      {
         return FALSE;
      }

      return array($row[0]->lat,$row[0]->lon);

   }

   function calculate_mileage($lat1, $lat2, $lon1, $lon2) {

      // used internally, this function actually performs that calculation to
      // determine the mileage between 2 points defined by lattitude and
      // longitude coordinates.  This calculation is based on the code found
      // at http://www.cryptnet.net/fsp/zipdy/

      // Convert lattitude/longitude (degrees) to radians for calculations
      $lat1 = deg2rad($lat1);
      $lon1 = deg2rad($lon1);
      $lat2 = deg2rad($lat2);
      $lon2 = deg2rad($lon2);

      // Find the deltas
      $delta_lat = $lat2 - $lat1;
      $delta_lon = $lon2 - $lon1;

      // Find the Great Circle distance
      $temp = pow(sin($delta_lat/2.0),2) + cos($lat1) * cos($lat2) * pow(sin($delta_lon/2.0),2);
      $distance = 3956 * 2 * atan2(sqrt($temp),sqrt(1-$temp));

      return $distance;
   }

	function get_city_states($zips)
	{
		$rows = $this->CI->zipcode_model->get_city_states($zips);
		if(count($rows) == 0)
			return FALSE;

		$city_states = array();
		foreach($rows as $row)
		{
			$city_states["city"] = $row->city;
			$city_states["state_prefix"] = $row->state_prefix;
		}
		return $city_states;
	}

   function get_zips_in_range($zip, $range, $sort=1, $include_base) {

      // returns an array of the zip codes within $range of $zip. Returns
      // an array with keys as zip codes and values as the distance from
      // the zipcode defined in $zip.

      $this->chronometer();                     // start the clock

      $details = $this->get_zip_point($zip);  // base zip details
      if ($details == false) return false;

      // This portion of the routine  calculates the minimum and maximum lat and
      // long within a given range.  This portion of the code was written
      // by Jeff Bearer (http://www.jeffbearer.com). This significanly decreases
      // the time it takes to execute a query.  My demo took 3.2 seconds in
      // v1.0.0 and now executes in 0.4 seconds!  Greate job Jeff!

      // Find Max - Min Lat / Long for Radius and zero point and query
      // only zips in that range.
      $lat_range = $range/69.172;
      $lon_range = abs($range/(cos($details[0]) * 69.172));
      $min_lat = number_format($details[0] - $lat_range, "4", ".", "");
      $max_lat = number_format($details[0] + $lat_range, "4", ".", "");
      $min_lon = number_format($details[1] - $lon_range, "4", ".", "");
      $max_lon = number_format($details[1] + $lon_range, "4", ".", "");

      $rows = $this->CI->zipcode_model->get_zips_in_range($zip,$min_lat, $max_lat,$min_lon,$max_lon,$include_base);

      if(count($rows) == 0 )
      {
         return FALSE;
      }

      $return = array();    // declared here for scope

      foreach($rows as $row)
      {
         // loop through all 40 some thousand zip codes and determine whether
         // or not it's within the specified range.

         // calculate_mileage($lat1, $lat2, $lon1, $lon2)
         // $dist = $this->calculate_mileage($details[0],$row[1],$details[1],$row[2]);
         $dist = $this->calculate_mileage($details[0], $row->lat, $details[1], $row->lon);
         if ($this->units == _UNIT_KILOMETERS) $dist = $dist * _M2KM_FACTOR;
         if ($dist <= $range) {
            $return[] = array(
				"city"		=> $row->city,
				"state"		=> $row->state_prefix,
				"zip_code"	=> $row->zip_code,
				"distance" 	=> round($dist, $this->decimals));
         }
      }

      // sort array
      switch($sort)
      {
         case _ZIPS_SORT_BY_DISTANCE_ASC:
            usort($return, array($this, "distance_sort_asc"));
            break;

         case _ZIPS_SORT_BY_DISTANCE_DESC:
            usort($return, array($this, "distance_sort_desc"));
            break;

         case _ZIPS_SORT_BY_ZIP_ASC:
            usort($return, array($this, "zip_code_sort_asc"));
            break;

         case _ZIPS_SORT_BY_ZIP_DESC:
            usort($return, array($this, "zip_code_sort_desc"));
            break;
      }

      $this->last_time = $this->chronometer();

      if (empty($return)) return false;
      return $return;
   }

	function chronometer()
	{
	   // chronometer function taken from the php manual.  This is used primarily
	   // for debugging and anlyzing the functions while developing this class.  

	   $now = microtime(TRUE);  // float, in _seconds_
	   $now = $now + time();
	   $malt = 1;
	   $round = 7;

	   if ($this->last_time > 0) {
	       /* Stop the chronometer : return the amount of time since it was started,
	       in ms with a precision of 3 decimal places, and reset the start time.
	       We could factor the multiplication by 1000 (which converts seconds
	       into milliseconds) to save memory, but considering that floats can
	       reach e+308 but only carry 14 decimals, this is certainly more precise */

	       $retElapsed = round($now * $malt - $this->last_time * $malt, $round);

	       $this->last_time = $now;

	       return $retElapsed;
	   } else {
	       // Start the chronometer : save the starting time

	       $this->last_time = $now;

	       return 0;
	   }
   }

   function zip_code_sort_asc($a, $b)
	{
		return $this->sortAscend($a, $b, "zip_code");
	}

	function zip_code_sort_desc($a, $b)
	{
		return $this->sortDescend($a, $b, "zip_code");
	}

	function distance_sort_asc($a, $b)
	{
		return $this->sortAscend($a, $b, "distance");
	}

	function distance_sort_desc($a, $b)
	{
		return $this->sortDescend($a, $b, "distance");
	}

	function sortAscend($a, $b, $key)
	{
	   if ($a[$key] == $b[$key]) {
	        return 0;
	    }
	    return ($a[$key] < $b[$key] ) ? -1 : 1;
	}

	function sortDescend($a, $b, $key)
	{
	   if ($a[$key] == $b[$key]) {
	        return 0;
	    }
	    return ($a[$key] < $b[$key] ) ? 1 : -1;
	}
}
?>

And the model

application/model/zipcode_model.php

db->query($select.$from.$where.$order);
		return $query->result();
	}

	function get_zip_details($zip)
	{
		$sql = "SELECT lat AS latitude, lon AS longitude, city, county, state_prefix,
              state_name, area_code, time_zone
              FROM zip_code
              WHERE zip_code='$zip'";

		$query = $this->db->query($sql);
		return $query->result();
	}

	function  get_zip_point($zip)
	{
      $sql = "SELECT lat, lon from zip_code WHERE zip_code='$zip'";
		$query = $this->db->query($sql);
		return $query->result();
	}

	function get_city_states($zip_codes)
	{
		$sql = "select distinct city, state_prefix from zip_code where zip_code in (". implode(", ", $zip_codes).")";
		$query = $this->db->query($sql);
		return $query->result();

	}

	function get_zips_in_range($zip,$min_lat, $max_lat,$min_lon,$max_lon, $include_base)
	{
		$sql = "SELECT * FROM zip_code ";
	    if (!$include_base) $sql .= "WHERE zip_code <> '$zip' AND ";
	    else $sql .= "WHERE ";
	    $sql .= "lat BETWEEN '$min_lat' AND '$max_lat' AND lon BETWEEN '$min_lon' AND '$max_lon'";

		$query = $this->db->query($sql);
		return $query->result();
	}

	function get_zip_code($city, $state)
	{
		$sql = "select zip_code from zip_code where city = '".($city)."' and state_prefix='".$state."' limit 1";
		$query = $this->db->query($sql);
		return $query->result();
	}

}
?>

Related Blogs

Couple let baby starve to death while caring for virtual child

Filed under: funny, random — Tags: — taewoo @ 9:13 pm March 12, 2010

Once again, the some people are too dumb to be allowed to have kids:

An internet-obsessed Korean couple allegedly allowed their infant daughter to starve to death while they cared for their virtual child, police said on Friday.

Kim Yoo-chul, 41, and his partner Choi Mi-sun, 25, fed their three-month-old baby only on visits home between 12-hour sessions at a neighbourhood internet cafe, where they were raising an avatar daughter in a Second-Life-style game called Prius online, police said.

Leaving their real daughter at their home in a suburb of Seoul to fend for herself, the pair, who were unemployed, spent hours role-playing in the virtual reality game, which allows users to choose a career and friends, granting them offspring as a reward for passing a certain level.

The pair became obsessed with nurturing their virtual daughter, called Anima, but neglected their real daughter, who was not named.

This is FREAKIN’ CRAZY. What 26 in her right mind who marry a 41 year old unemployed geek? That’s just insane.

Then I took a dump like Chuck Norris.

chuck norris

Related Blogs

Chase cut my mine of credit from $70k to $35k in one a month

Filed under: business, random — taewoo @ 3:50 pm November 3, 2009

So pissed off. Writing to all the C-level execs (James Dimon, Michael J. Cavanagh, Charles W. Scharf, Gordon A. Smith, and Frank Bisignano):

Dear Mr. James Dimon

My name is TaeWoo Kim. I have been a faithful customer of Chase/Washington Mutual for over 8 years now. The reason for this letter is simple: I need your help.

First off, let me start off by saying how much I’ve appreciated Chase, especially with customer service and communication. Your online service alone has saved me countless hours and money. Thank you for your years of service.

I understand that I am one of millions of customers Chase deals with. I also understand that not everyone’s needs can be met. I don’t believe in entitlement nor do I expect things in return for my loyalty. But I feel lost in this big banking system of yours. I have spoken to many of your employees but I get the same answer without getting any solution.

I have three three credit cards with Chase. One had a limit of $40k, another with $15k, and the last with $1k. My credit score has always been outstanding (see latest report from MyFico.com) and I’ve rarely had late payments. Even if they were, it was due to ACH delay issues that I’ve managed to clear with Chase. I’m certain your call service center logs can verify this. I’ve always been a cautious borrower so I made sure I did not borrow beyond my means that can jeopardize my financial situation or my business standing with Chase. That’s why my history shows lack of information regarding revolving balances.

But lately, despite the economy’s downturn, my business has had tremendous success in the past few months. To expand my business advertising and marketing efforts, we rely heavily on our line of credit to buffer us. I haven’t had to use my Chase credit cards in a while because we’ve had partners who have fronted us their line of credit, but now they’re also in a crunch. So lately, I’ve started to use my Chase credit cards.

I get 3 letters within days of each other with the following changes to my accounts:

  1. One line of credit went from $40k to $20k
  2. Second one from $15k to $1k. Let me repeat: $15,000 to $1,000.
  3. Third one was flat out closed due to lack of activity.

Now, you can see how anyone would get extremely disturbed by this. While I’m no credit guru, I do understand my borrower-worthiness depends on my credit score, and a big chunk of it depends on my total line of credit. Effectively, $35k worth of line of credit has been wiped out. (The one with $1k line of credit wasn’t used because well, it only had $1k.)

I do admit there was a problem with one payment of $9k to Chase being returned as a result of my mistake. I have two bank accounts that submit payments from and one night, I carelessly chose the wrong account that did not have the balance. That resulted in payment to be returned from Chase. But I did remedy the situation right away by submitting the payment within days to correct the situation. Other than this one blooper, my account has been in good standing 99% of the time.

I hope I can appeal to your sensibility.

  1. In the current economy, we need more jobs. While my company’s not huge (yet), we are in state of growth. The more line of credit we have access to, the greater the growth. The more we grow, the more we can borrow. The more we can borrow, more we can do business with chase.
  2. I do understand mistakes are red flags but don’t we all make mistakes as humans? As the good Bible says, “let those without sin throw the first rock.” I hope a single mistake isn’t going to spiral me down from a good borrower of many years to a bad borrower due to one day’s event.
  3. All I get from your Chase reps are: “I can’t help you”, “we can’t do that”, “call us back”, etc. Is Chase a can-do company or not?

For years, I’ve been raving to my friends about how great Chase is. Why? My experience with Chase products and customer service has been phenomenal. But over a short period of time, my faith in Chase has slowly deteriorated to a point where I’m considering alternatives as far as banking goes. Of course, I would rather stay at chase because my financial details are well entrenched with Chase.

I am asking your helping restoring my line of credit on all three. If possible, I would like them even increased to double. I’ve spoken to a bank representative about why banks close idle accounts (i.e. holding cash just in case I borrow loses money). So if you’d like, I can concede to a condition that if I don’t use them in a year’s period of time, I will forfeit them.

The lives of four (to six, depending on season) rest heavily on my ability to borrow (responsibly). This line of credit is the buffer we need to get our “lifeblood” going in our company. Even if I haven’t made a convincing argument, I hope I can appeal to your sense of human camaraderie and mutual business respect.

Very sincerely,

TaeWoo Kim

« Newer PostsOlder Posts »