Page 1 of 1

UDT for calculation of distance between two geo-coordinates

Posted: Sat Jan 17, 2009 11:15 pm
by nhaack
Hi there,

for a project I needed a quick way to calculate the distance between two gps coordinates. I though this code might be handy for others (e.g. in combination with the Geocoder API Plug-in).

Save this as a UDT with the name "calculate_distance"

Code: Select all


//
// Check for parameters, if not set or empty, set default
//

// This parameter is used to select the scaling of the result returned
if (isset($params['convert']) AND ($params['convert'] != '')) {		
	$convert = strtolower($params['convert']);	
} else {$convert = 'mi';}	

// This is the latitude of the first point
if (isset($params['gps_lat_1']) AND ($params['gps_lat_1'] != '')) {		
	$gps_lat_1 = (float)$params['gps_lat_1'];	
} else {$gps_lat_1 = -10;}	

// This is the latitude of the first point
if (isset($params['gps_lat_2']) AND ($params['gps_lat_2'] != '')) {		
	$gps_lat_2 = (float)$params['gps_lat_2'];	
} else {$gps_lat_2 = 11;}	

// This is the longitude of the second point
if (isset($params['gps_long_1']) AND ($params['gps_long_1'] != '')) {		
	$gps_long_1 = (float)$params['gps_long_1'];	
} else {$gps_long_1 = 10;}	

// This is the longitude of the second point
if (isset($params['gps_long_2']) AND ($params['gps_long_2'] != '')) {		
	$gps_long_2 = (float)$params['gps_long_2'];	
} else {$gps_long_2 = 11;}	

//
// Do the distance calculation
//

	$result = sin(deg2rad($gps_lat_1)) * sin(deg2rad($gps_lat_2)) + cos(deg2rad($gps_lat_1)) * cos(deg2rad($gps_lat_2)) * cos(deg2rad($gps_long_1 - $gps_long_2));
	$result = rad2deg(acos($result)) * 69.09;

//
// If a converting is required do this
//

	if ($convert== 'km' ) {$result = $result * 1.609344;}

//
// Return integer value for distance in selected scaling	
//

return (integer)round($result,0);

Then you can do the calculation in your templates. E.g.

{calculate_distance convert="km" gps_lat_1=10 gps_lat_2=11.63 gps_long_1=53.5123 gps_long_2=55.123}

The UDT will echo the pure value as integer (default scaling is US miles, optional: kilometer). For other scalings (e.g. nautic miles... just add your scalings below the KM conversion in the same pattern.

Best
Nils

Re: UDT for calculation of distance between two geo-coordinates

Posted: Sat Jan 17, 2009 11:48 pm
by nhaack
here is a quickly optimized version. I found a nice conversion table and integrated a few more possible scales. Output is now in smarty.  {$distance} will display the calculated distance in the requested scaling.

Just look at the source which scaling you want and use that string in the convert parameter.

Best
Nils

Code: Select all



//
// Check for parameters, if not set or empty, set default
//

// This parameter is used to select the scaling of the result returned
if (isset($params['round']) AND ($params['round'] != '')) {		
	$roundt = (integer)$params['round'];	
} else {$roundt = 0;}
	
// This parameter is used to select the scaling of the result returned
if (isset($params['convert']) AND ($params['convert'] != '')) {		
	$convert = strtolower($params['convert']);	
} else {$convert = 'mi';}	

// This is the latitude of the first point
if (isset($params['gps_lat_1']) AND ($params['gps_lat_1'] != '')) {		
	$gps_lat_1 = (float)$params['gps_lat_1'];	
} else {$gps_lat_1 = -10;}	

// This is the latitude of the first point
if (isset($params['gps_lat_2']) AND ($params['gps_lat_2'] != '')) {		
	$gps_lat_2 = (float)$params['gps_lat_2'];	
} else {$gps_lat_2 = 11;}	

// This is the longitude of the second point
if (isset($params['gps_long_1']) AND ($params['gps_long_1'] != '')) {		
	$gps_long_1 = (float)$params['gps_long_1'];	
} else {$gps_long_1 = 10;}	

// This is the longitude of the second point
if (isset($params['gps_long_2']) AND ($params['gps_long_2'] != '')) {		
	$gps_long_2 = (float)$params['gps_long_2'];	
} else {$gps_long_2 = 11;}	

//
// Do the distance calculation
//

	$result = sin(deg2rad($gps_lat_1)) * sin(deg2rad($gps_lat_2)) + cos(deg2rad($gps_lat_1)) * cos(deg2rad($gps_lat_2)) * cos(deg2rad($gps_long_1 - $gps_long_2));
	$result = rad2deg(acos($result)) * 69.09;

//
// If a converting is required do this
//
	// metric
	if ($convert== 'km' ) {$result = $result * 1.609344;}
	if ($convert== 'meter' ) {$result = $result * 1609.344;}
	if ($convert== 'cm' ) {$result = $result * 160934.4;}
	
	// imperial
	if ($convert== 'league' ) {$result = $result * 0.333333;}
	if ($convert== 'yard' ) {$result = $result * 1760;}
	if ($convert== 'foot' ) {$result = $result * 5280;}
	if ($convert== 'inch' ) {$result = $result * 63360;}
	
	// nautic
	if ($convert== 'sealeague' ) {$result = $result * 0.289659;}
	if ($convert== 'seamile' ) {$result = $result * 0.868976;}
	if ($convert== 'cable' ) {$result = $result * 7.33333;}
	if ($convert== 'shortcable' ) {$result = $result * 8.68976;}
	if ($convert== 'fathom' ) {$result = $result * 880;}
	
	// japanese
	if ($convert== 'ri' ) {$result = $result * 0.409784;}
	if ($convert== 'kairi' ) {$result = $result * 0.868976;}
	if ($convert== 'cho' ) {$result = $result * 14.7522;}
	if ($convert== 'iyo' ) {$result = $result * 531.08;}
	if ($convert== 'ken' ) {$result = $result * 885.133;}
	if ($convert== 'shyaku' ) {$result = $result * 5310.8;}
	
	// chinese imperial
	if ($convert== 'li' ) {$result = $result * 3.21869;}
	if ($convert== 'yin' ) {$result = $result * 48.2803;}
	if ($convert== 'zhang' ) {$result = $result * 482.803;}
	if ($convert== 'bu' ) {$result = $result * 965.606;}
	if ($convert== 'chi' ) {$result = $result * 4828.03;}
	if ($convert== 'cun' ) {$result = $result * 48280.3;}
	
	// German geographical
	if ($convert== 'geomile' ) {$result = $result * 0.216893;}
	
	// typographic - ATA system
	if ($convert== 'pica' ) {$result = $result * 381597;}
	if ($convert== 'point' ) {$result = $result * 4579160;}
	if ($convert== 'pixel' ) {$result = $result * 6105550;}
	
	// astronomic	
	if ($convert== 'redshift' ) {$result = $result * 1.23532e-23;}
	if ($convert== 'parsec' ) {$result = $result * 5.21553e-14;}
	if ($convert== 'astronomicalunit' ) {$result = $result * 1.70111e-13;}
	if ($convert== 'lightyear' ) {$result = $result * 1.07578e-8;}
	if ($convert== 'lightminute' ) {$result = $result * 8.94699e-8;}
	if ($convert== 'lightsecond' ) {$result = $result * 0.00000536819;}
	
	// ancient roman	
	if ($convert== 'millarium' ) {$result = $result * 1.00735;}
	if ($convert== 'akt' ) {$result = $result * 41.973;}
	if ($convert== 'decimpeda' ) {$result = $result * 503.676;}
	if ($convert== 'pace' ) {$result = $result * 1007.35;}
	if ($convert== 'cubit' ) {$result = $result * 3357.84;}
	if ($convert== 'ped' ) {$result = $result * 5036.76;} 		// ordinary ped
	if ($convert== 'ounce' ) {$result = $result * 60441.1;} 	// ounce (inch)
	if ($convert== 'digit' ) {$result = $result * 80588.1;}
	

//
// Return integer value for distance in selected scaling	
//

	$smarty->assign('distance', round($result,$roundt));
	
	return;


Re: UDT for calculation of distance between two geo-coordinates

Posted: Mon Jan 19, 2009 5:11 pm
by tyman00
Very nice! I don't have a need for it at the moment, but I could see how this would come in very handy.

Re: UDT for calculation of distance between two geo-coordinates

Posted: Mon Jan 19, 2009 5:20 pm
by calguy1000
quick tip:

Normally by convention we just 'return' the results, rather than hardcode a variable name..... we usually also try to use an 'assign' parameter
like this:

Code: Select all

if( isset($params['assign']) )
  {
      $smarty->assign(trim($params['assign']),$value);
      return;
  }
return $value;
That way you can call the UDT like this:

Code: Select all

{capture assign='mydistance'}{mydistancecalculator_udt}{/capture}
or

Code: Select all

{mydistancecalculator_udt assign='mydistance'}

Re: UDT for calculation of distance between two geo-coordinates

Posted: Mon Jan 19, 2009 5:33 pm
by nhaack
Cool, thanks for tip.

Does this apply for UDTs only, or is this something I should keep in mind for all programming I do for CMSMS?
Sorry for asking, but I never really learnt programming - I just try very hard :)

Will adjust the code and put it in the wiki afterwards ....

Best
Nils

Re: UDT for calculation of distance between two geo-coordinates

Posted: Mon Jan 19, 2009 5:55 pm
by calguy1000
Just for smarty plugins..... whether they're done as UDT's or in a module like CGSimpleSmarty does.... or as seperate files.

Re: UDT for calculation of distance between two geo-coordinates

Posted: Mon Jan 19, 2009 7:56 pm
by nhaack
Thanks, I will also soon adjust the plug-ins I have released, so they comply with the conventions. It is actually quite neat to be able to define the output variable name.

I tried searching the forum and the wiki but couldn't find any document regarding the code style - or are these generally accepted coding styles? I'd like to know more about how to make my code better for CMSMS.

Best
Nils