Distance calculation based on multiple locations (Lat,Lon) including starting/ finishing point - php

I would like to calculate the total distance of driving beetween multiple locations (loop), including the distance (starting point (garage) - first location sarting point) and (last location finishig point - finishing point (garage)).
Example:
(Garage + D1) + (D1 + D2) + (D2 + E1) + (E1 + E2) + E2 + Garage)
I'm having a problem with the correct looping. Here's my simplified code:
<?
$driver = 5;
$result2 = mysql_query("SELECT * FROM test WHERE id='$driver' LIMIT 1") or die(mysql_error());
while($row2 = mysql_fetch_array( $result2 )) {
$lon=$row2['lon'];
$lat=$row2['lat'];
echo "$lon, $lat";
}
$result = mysql_query("SELECT * FROM test1 WHERE driver='$driver'") or die(mysql_error());
while($row = mysql_fetch_array( $result )) {
$lon1=$row['lon1'];
$lat1=$row['lat1'];
$lon2=$row['lon2'];
$lat2=$row['lat2'];
////////// distance between driver address and starting address
$distancecalc = (3958*3.1415926*sqrt(($lat-$lat1)*($lat-$lat1) + cos($lat/57.29578)*cos($lat1/57.29578)*($lon-$lon1)*($lon-$lon1))/180);
////////// distance between statring address and finishing address - multiple adsresses
$distancecalc1 = $distancecalc1 + (3958*3.1415926*sqrt(($lat2-$lat1)*($lat2-$lat1) + cos($lat2/57.29578)*cos($lat1/57.29578)*($lon2-$lon1)*($lon2-$lon1))/180);
////////// distance between finishing address and driver address
$distancecalc2 = (3958*3.1415926*sqrt(($lat2-$lat)*($lat2-$lat) + cos($lat2/57.29578)*cos($lat/57.29578)*($lon2-$lon)*($lon2-$lon))/180);
$distancetotal = $distancecalc + $distancecalc1 +$distancecalc2;
echo "$distancecalc<br>
$distancecalc1<br>
$distancecalc2<br>";
}
echo "$distancetotal";
?>
I tried some things (mostly if... ) and also with more database requests, but I'm still having the problem of avoiding multiple calculations, and I also strongly believe there is way to code it to make it easier and clearer.
I would appreciate some help on this one.
Thank you very much.

Here's the function you need:
function distance ($lat1, $lon1, $lat2, $lon2) {
return (3958*3.1415926*sqrt(($lat2-$lat1)*($lat2-$lat1) + cos($lat2/57.29578)*cos($lat1/57.29578)*($lon2-$lon1)*($lon2-$lon1))/180);
}
The function body is exactly the same as the formula you used in-line, so I don't understand why you needed help with this.

The number 6367 - is the radius of the Earth in kilometers
DELIMITER $$
DROP FUNCTION IF EXISTS geodist $$
CREATE FUNCTION geodist (
src_lat DECIMAL(9,6), src_lon DECIMAL(9,6),
dst_lat DECIMAL(9,6), dst_lon DECIMAL(9,6)
) RETURNS DECIMAL(6,2) DETERMINISTIC
BEGIN
SET #dist := 6367 * 2 * ASIN(SQRT(
POWER(SIN((src_lat - ABS(dst_lat)) * PI()/180 / 2), 2) +
COS(src_lat * PI()/180) *
COS(ABS(dst_lat) * PI()/180) *
POWER(SIN((src_lon - dst_lon) * PI()/180 / 2), 2)
));
RETURN #dist;
END $$
DELIMITER ;

Ok. I worked it out with help of mac_gyver (php freaks). All calculations are done as i wish. My code below:
<?
include "connectdb.php";
$driver = 5;
$datestamp = '2013/05/07';
$result2 = mysql_query("SELECT * FROM drivers WHERE id='$driver' LIMIT 1") or die(mysql_error());
while($row2 = mysql_fetch_array( $result2 )) {
$lon=$row2['lon'];
$lat=$row2['lat'];
}
$result = mysql_query("SELECT * FROM quotedb WHERE moveday='$datestamp' AND driver='$driver' AND cleared='Not Cleared' AND status='Done' ORDER BY moveday, timeday") or die(mysql_error());
$distance = 0; // accumulate the distance
$first_pass = true; // flag to detect the first row inside the loop
while($row = mysql_fetch_assoc( $result )) {
$lon2a=$lon2;
$lat2a=$lat2;
$lon1=$row['lon1'];
$lat1=$row['lat1'];
$lon2=$row['lon2'];
$lat2=$row['lat2'];
// calculate the distance from the Garage to the first point of the first row
if($first_pass){
$distance += (3958*3.1415926*sqrt(($lat-$lat1)*($lat-$lat1) + cos($lat/57.29578)*cos($lat1/57.29578)*($lon-$lon1)*($lon-$lon1))/180);
$first_pass = false;
}
// calculate the distance for each row (segment) in the route
$distance += (3958*3.1415926*sqrt(($lat2-$lat1)*($lat2-$lat1) + cos($lat2/57.29578)*cos($lat1/57.29578)*($lon2-$lon1)*($lon2-$lon1))/180);
if ( $lon2a == "" or $lat2a =="" ) {
} else {
// calculate the distance from the second point of the first row to the first point of the next row
$distance += (3958*3.1415926*sqrt(($lat2a-$lat1)*($lat2a-$lat1) + cos($lat2a/57.29578)*cos($lat1/57.29578)*($lon2a-$lon1)*($lon2a-$lon1))/180);
}
}
// calculate the distance from the second point of the last row to the Garage
$distance += (3958*3.1415926*sqrt(($lat2-$lat)*($lat2-$lat) + cos($lat2/57.29578)*cos($lat/57.29578)*($lon2-$lon)*($lon2-$lon))/180);
echo "$distance<br>
";
?>
Still think there is a place for improvement in the code. Will aplay Haversine method for calculations. Do you guys have some suggestion to improve this piece of code ... thx

Impoved version:
<?
include "connectdb.php";
$driver = 5;
$datestamp = '2013/05/07';
$result2 = mysql_query("SELECT * FROM drivers WHERE id='$driver' LIMIT 1") or die(mysql_error());
while($row2 = mysql_fetch_array( $result2 )) {
$garage_lon=$row2['lon'];
$garage_lat=$row2['lat'];
}
$result = mysql_query("SELECT * FROM quotedb WHERE moveday='$datestamp' AND driver='$driver' AND cleared='Not Cleared' AND status='Done' ORDER BY moveday, timeday") or die(mysql_error());
function calculate_distance($lon1, $lat1, $lon2, $lat2) {
return (3958 * 3.1415926 * sqrt(($lat2 - $lat1) * ($lat2 - $lat1) + cos($lat2 / 57.29578) * cos($lat1 / 57.29578) * ($lon2 - $lon1) * ($lon2 - $lon1)) / 180);}
$previous_lon = $garage_lon;
$previous_lat = $garage_lat;
$distance = 0; // accumulate the distance
while($row = mysql_fetch_assoc( $result ))
{
$lon1 = $row['lon1'];
$lat1 = $row['lat1'];
$lon2 = $row['lon2'];
$lat2 = $row['lat2'];
if ( $previous_lon && $previous_lat )
{
// calculate the distance from the second point of the first row to the first point of the next row
$distance += calculate_distance($lon1, $lat1, $previous_lon, $previous_lat);
}
// calculate the distance for each row (segment) in the route
$distance += calculate_distance($lon1, $lat1, $lon2, $lat2);
$previous_lon = $lon2;
$previous_lat = $lat2;
}
// calculate the distance from the second point of the last row to the Garage
$distance += calculate_distance($garage_lon, $garage_lat, $lon2, $lat2);
$distance = round($distance,0);
echo "$distance<br>
";
?>

Related

sort zip codes by distance

So, I'm working on a search form for my site. I've run into a road block. Seems others have too but I've been unable to find an answer for my question, at least one that I understand.
I found a PHP function online that grabs up all the zip codes within a specified radius. I edited the sql query so that I wasn't grabbing every zip code within that radius, but ones that are associated with a user account. The function works and grabs the zip codes I'm after. This function returns an array with the zip codes. I would like to sort the zip codes by distance from nearest to farthest, and apparently I'm no where near smart enough to figure out how to do it.
What I've Tried:
I found another PHP function that will calculate the distance between 2 sets of coordinates(lat,lon2, lat2, lon2). I created my own function that loops through my zip codes array and runs each zip through the calculateDistance function. Just seems to be a big mess. I believe I have all the pieces just not sure how to put it all together. Any help would be greatly appreciated.
Here is the zipcodeRadius function I'm using:
// get all the zipcodes within the specified radius - default 20
function zipcodeRadius($lat, $lon, $radius)
{
$radius = $radius ? $radius : 20;
$dbc = mysqli_connect(DB_HOST, DB_USER, DB_PASSWORD, DB_NAME);
$sql = 'SELECT DISTINCT zipcodes.ZIP,
members.*,
location.*
FROM members
LEFT JOIN location
ON members.id = location.user_id
LEFT JOIN zipcodes
ON location.zip = zipcodes.ZIP
WHERE activated="1"
AND (3958*3.1415926*sqrt((Latitude-'.$lat.')*(Latitude-'.$lat.') + cos(Latitude/57.29578)*cos('.$lat.'/57.29578)*(Longitude-'.$lon.')*(Longitude-'.$lon.'))/180) <= '.$radius.';';
$result = mysqli_query($dbc, $sql);
// get each result
$zipcodeList = array();
while($row = mysqli_fetch_array($result))
{
array_push($zipcodeList, $row['ZIP']);
}
return $zipcodeList;
}
Here is the calculateDistance function
function calculateDistance($latitude1, $longitude1, $latitude2, $longitude2) {
$theta = $longitude1 - $longitude2;
$miles = (sin(deg2rad($latitude1)) * sin(deg2rad($latitude2))) + (cos(deg2rad($latitude1)) * cos(deg2rad($latitude2)) * cos(deg2rad($theta)));
$miles = acos($miles);
$miles = rad2deg($miles);
$miles = $miles * 60 * 1.1515;
return $miles;
}
And, Here's my seemingly useless function:
$matches = join(',',$zipCodeArray);
function sort_zip_by_distance($matches, $lat, $lon){
$dbc = mysqli_connect(DB_HOST, DB_USER, DB_PASSWORD, DB_NAME);
$queryDistance = "SELECT * FROM zipcodes WHERE ZIP IN ($matches)";
$resultDistance = mysqli_query($dbc, $queryDistance)
or die("Unable to query the database");
while($rowDistance = mysqli_fetch_array($resultDistance)){
$miles = calculateDistance($lat, $lon, $rowDistance['Latitude'], $rowDistance['Longitude']);
echo '<p>ZIP: ' . $rowDistance['ZIP'] . ' | Lat: ' . $rowDistance['Latitude'] . ' | Lon: ' . $rowDistance['Longitude'] . ' | Miles: ' . $miles . '</p><br />';
$distanceTotal = array();
array_push($distanceTotal, $rowDistance['ZIP'], $miles);
}
return $distanceTotal;
}
You can do arbitrary math in order by clauses, but you'd most likely to actually RETURN the distances found, so why not do
SELECT *, long_ugly_distance_calc_here AS distance
...
ORDER BY distance DESC

Getting a percentage of one PHP variable from another

I am trying to get a percentage of a php variable from another, for example i have two databases of information, the first database is full of unidentified information. The second database is full of the information we have identified. and so i want to work out dynamically the percentage of the total information identified.
Below is a php function to work out a percentage,
//TOTAL ENTRIES INTO Table 1 FOR total data
$result = mysql_query( "SELECT * FROM table1" );
$num_total = mysql_num_rows( $result );
//TOTAL ENTRIES IN Table 2 FOR THE PERCENTAGE
$result = mysql_query( "SELECT * FROM table2" );
$num_amount = mysql_num_rows( $result );
function percent($num_amount, $num_total) {
$count1 = $num_amount / $num_total;
$count2 = $count1 * 100;
$count3 = 100 - $count2;
$count = number_format($count3, 0);
echo $count;
}
Both queries return the correct information of the total number of rows counted in the database, however the count variable does not return any information.
Any ideas or suggestions would be appreciated.
Thanks
Stan
You echo the result, but you do not return it from the function. That is probably the problem.
However, you can do the percentage calculation all in SQL:
SELECT 100*( SELECT COUNT(*) FROM table1 ) / ( SELECT COUNT(*) FROM table2 )
AS percent;
Otherwise,
function percent($num, $total)
{
return number_format((100.0*$num)/$total, 2);
}
My guess is that something like this should probably work (mind you, I have not tested this, so it probably needs tweaking):
<?php
//TOTAL ENTRIES INTO Table 1 FOR total data
$result = mysql_query("SELECT COUNT(*) AS total FROM table1");
$table1_total = mysql_result($result, 0);
//TOTAL ENTRIES IN Table 2 FOR THE PERCENTAGE
$result2 = mysql_query("SELECT COUNT(*) AS total FROM table2");
$table2_total = mysql_result($result2, 0);
function percent($num_amount, $num_total) {
$count1 = $num_amount / $num_total;
$count2 = $count1 * 100;
$count3 = 100 - $count2;
$count = number_format($count3, 0);
echo $count;
}
percent($table1_total, $table2_total);
Try this:
<?php
function percent($num_amount, $num_total) {
$count1 = $num_amount / $num_total;
$count2 = $count1 * 100;
$count = number_format($count2, 0);
echo $count2."<br>";
}
percent(50,100);
percent(13,100);
percent(13,200);
?>

PHP / Mysql - ORDER BY When Using Temp Tables

I've been trying to get this to work using ORDER BY and LIMIT, but it will output everything that was put in. The ORDER BY and LIMIT does not seem to work:
$lat1 = 37.349418;
$lon1 = -121.896286;
$distance = 25;
$q = "SELECT * FROM cityname WHERE feature_class = 'A' OR feature_class = 'P'";
$r = mysql_query($q) or die(mysql_error());
while ($row = mysql_fetch_array($r)) {
$lat = trim($row["latitude"]);
$lon = trim($row["longitude"]);
$name = $row["name"];
$pop = $row["population"];
$miles = distance($lat, $lon, $lat1, $lon1, "m");
$milesrounded = round($miles, 2);
if ($miles < $distance) {
if ($pop > 0) {
$q2 = "CREATE TEMPORARY TABLE IF NOT EXISTS `templocation4` (
`cityname` varchar(75) NOT NULL,
`distance` double NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1";
$r2 = mysql_query($q2) or die(mysql_error());
$q1 = "INSERT INTO templocation4 (cityname, distance) VALUES ('$name', '$milesrounded')";
$r1 = mysql_query($q1) or die(mysql_error());
$q3 = "SELECT MIN(distance) FROM templocation4 GROUP BY distance DESC LIMIT 10";
$r3 = mysql_query($q3) or die(mysql_error());
while ($row1 = mysql_fetch_array($r3)) {
echo $row1["cityname"];
echo " ";
echo $row1["distance"];
echo "<br>";
}
$q5 = "DROP TABLE templocation4";
$r5 = mysql_query($q5) or die(mysql_error());
}
}
}
The table cityname has > 250K entries and I'm trying to sort it down to the closest city name based on the latitude / longitude that a user has input.
Thanks.
There's an error here:
$q3 = "SELECT MIN(distance) FROM templocation4 GROUP BY distance DESC LIMIT 10";
$r3 = mysql_query($q3) or die(mysql_error());
while ($row1 = mysql_fetch_array($r3)) {
echo $row1["cityname"]; // Where is cityname defined???
echo " ";
echo $row1["distance"]; // Where is distance defined???
echo "<br>";
}
$r3 only has one result column (which you haven't given a name). Are you sure you are using the correct variable because there's no way that your code should work as you have posted it.
Also your variable naming is really awful. Use meaningful names instead of $q1, $q2, etc...
Please check with Logic once again. "GROUP BY distance" will return single records from list of concern records. For e.g. if there are 100 users at 10 miles distance, your query will fetch 1st record found for 10 miles. this will NOT return all 100 records.
$q1 = "INSERT INTO templocation4 (cityname, distance) VALUES ('$name', '$milesrounded')";
$r1 = mysql_query($q1) or die(mysql_error());
$q3 = "SELECT MIN(distance) FROM templocation4 GROUP BY distance DESC LIMIT 10";
$r3 = mysql_query($q3) or die(mysql_error());
Need to rework with your need and logic.
//determine distance function
function distance($lat, $lon, $lat1, $lon1, $unit) {
$theta = $lon - $lon1;
$dist = sin(deg2rad($lat)) * sin(deg2rad($lat1)) + cos(deg2rad($lat)) * cos(deg2rad($lat1)) * cos(deg2rad($theta));
$dist = acos($dist);
$dist = rad2deg($dist);
$miles = $dist * 60 * 1.1515;
$unit = strtoupper($unit);
if ($unit == "K") {
return ($miles * 1.609344);
} else if ($unit == "N") {
return ($miles * 0.8684);
} else {
return $miles;
}
}
//sample latitude for testing purposes
$lat1 = 37.349418;
//sample longitude for testing purposes
$lon1 = -121.896286;
//sample distance for testing purposes
$distance = 25;
//query to select only a or p feature class
$query = "SELECT * FROM cityname WHERE feature_class = 'A' OR feature_class = 'P'";
$result = mysql_query($query) or die(mysql_error());
//create the temporary table - if it does not exist
$createtemporarytablequery = "CREATE TEMPORARY TABLE IF NOT EXISTS `templocation4` (
`cityname` varchar(75) NOT NULL,
`distance` double NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1";
$resultofcreatetemporarytablequery = mysql_query($createtemporarytablequery) or die(mysql_error());
while ($row = mysql_fetch_array($result)) {
//gets latitude of city in database
$lat = trim($row["latitude"]);
//gets longitude of city in database
$lon = trim($row["longitude"]);
//gets cityname
$name = $row["name"];
//gets population of aforementioned cityname
$pop = $row["population"];
//determines distance from sample latitude and longitude from the latitude and longitude of cities in the cityname database
$miles = distance($lat, $lon, $lat1, $lon1, "m");
//round the miles to the 2nd decimal place
$milesrounded = round($miles, 2);
//determine if the city meets the request
if ($miles < $distance) {
//make sure its a populated city
if ($pop > 0) {
//insert stuff into temporary table
$insertstuffintotemporarytable = "INSERT INTO templocation4 (cityname, distance) VALUES ('$name', '$milesrounded')";
$resultofinsertstuffintotemporarytable = mysql_query($insertstuffintotemporarytable) or die(mysql_error());
}
}
}
//retrieve the closest 10 cities from the temporary table
$retrieve10closestcities = "SELECT * FROM templocation4 GROUP BY distance ASC LIMIT 10";
$resultofretrieving10closestcities = mysql_query($retrieve10closestcities) or die(mysql_error());
//determine how many results there are
$numrows = mysql_num_rows($resultofretrieving10closestcities);
//are there more than 0 results?
if ($numrows > 0) {
//loops through array
while ($row1 = mysql_fetch_array($resultofretrieving10closestcities)) {
echo $row1["cityname"];
echo " ";
echo $row1["distance"];
echo "<br>";
}
} else {
//echos no results found
echo "No results found";
}
//drop temporary table
$droptable = "DROP TABLE templocation4";
$resultofdroptable = mysql_query($droptable) or die(mysql_error());
And the answer is:
San Jose 0.7
Buena Vista 2.24
Burbank 2.65
Santa Clara 3.25
Fruitdale 3.33
Alum Rock 3.97
East Foothills 4.85
Campbell 5.21
Seven Trees 5.41
Milpitas 5.48

using pythagorean theorem to find point within a distance

ok i have a database that has 3 fields planetkey, xcoord, ycoord...
i want to find all the planetkeys within 30 of the location entered.. this is what i have...
$sql2 = "SELECT * FROM adlplanet WHERE SQRT(POW(xcoord - 172.3900, 2) + POW(ycoord - 247.5000, 2) < 30";
$queryrow2 = mysql_query($sql2);
while ($jumpl = mysql_fetch_array($queryrow2)) {
echo $jumpl['PlanetKey '];
}
The formula is (x-a)^2 + (y-b)^2 = c^2
So the 30 should be 30^2:
$sql2 = "SELECT * FROM adlplanet WHERE SQRT(POW(xcoord - 172.3900, 2) + POW(ycoord - 247.5000, 2) < POW(30,2)";

php sql using odbc

Hi Im making a website in php with a microsoft access database through odbc and i have come across a small problem let me show you my codes first.
<form method ="POST" action="maxtimestamplog.php">
Longitude <input type="text" name="longitude" /><br/>
Latitude
<input type ="text" name = "latitude"/>
<input name="ok" type="submit" value="Submit" />
</form>
<?
$dbc = odbc_connect("X1","",""); // Trying to establish connection
// with database
echo "<br>";
$datetime =date('Y-m-d H:i:s', strtotime('+8 hours'));
echo "The Current date/time is $datetime";
echo "<br><br><br>";
if (!$dbc)
{
exit("Connection failed:".$dbc);
}
$x_origin = $_POST['longitude'];
$y_origin = $_POST['latitude'];
$query = " SELECT m.vehicle_no,
l.longitude,
l.latitude,
l.timestamp
FROM
vehicle_log AS l,
GPS_modem AS m
WHERE
m.modem_ID = l.modem_ID
AND l.timestamp = (
SELECT MAX(timestamp) FROM vehicle_log WHERE modem_ID = l.modem_ID
) order by timestamp desc
"; // SQL Statement
$rs = odbc_exec($dbc,$query);
if (!$rs)
{
exit("Error in SQL. ".$rs);
}
$i=1;
while (odbc_fetch_row($rs))
{
$lng = odbc_result($rs, "longitude");
$lat = odbc_result ($rs, "latitude");
$ts = odbc_result ($rs, "timestamp");
$vno = odbc_result ($rs, "vehicle_no");
$yyyy= substr($ts, 0, 4);
$mm= substr($ts, 5, 2);
$dd= substr($ts, 8,2);
$hr= substr($ts, 11, 2);
$min= substr($ts, 14,2);
$sec= substr($ts,17, 2);
$cyyyy= substr($datetime, 0, 4);
$cmm= substr($datetime, 5, 2);
$cdd= substr($datetime, 8,2);
$chr= substr($datetime, 11, 2);
$cmin= substr($datetime, 14,2);
$csec= substr($datetime,17, 2);
$ctss = $csec
+ ($cmin * 60)
+ ($chr * 60 * 60)
+ ($cdd * 24 * 60 * 60)
+ ($cmm * 30 * 24 * 60 * 60)
+ ($cyyyy * 365 * 24 * 60 * 60);
$tss = $sec
+ (cmin * 60) + ($hr * 60 * 60)
+ ($dd * 24 * 60 * 60)
+ ($mm * 30 * 24 * 60 * 60)
+ ($yyyy * 365 * 24 * 60 * 60);
$tssd = $ctss - $tss;
$x = $lng;
$y = $lat;
$i = $i + 1;
$xd = ($x - $x_origin);
$yd = ($y - $y_origin);
$d = ($xd*$xd) + ($yd*$yd);
$td = sqrt($d);
echo "Car Number $vno is at a distance $td away at timestamp $ts";
echo "</br></br>";
}
odbc_close($dbc);
?>
</HTML>
what I want to be done now is to only display one output not all.
Firstly I want to select only the data where variable $tssd is less than or equal to 10800 then i want to display the smallest $td out of what i selected and it shoud display
echo "Car Number $vno is at a distance $td away at timestamp $ts";
echo "</br></br>";
where $td is the least within $tssd is less than 10800
It should only display one
please try to help me im quite new to php and my sql statement is quite messy as it is i make blunder out of it.
Try to separate the SQL from the PHP.
I believe you're asking how to return only a single row rather than all the rows. To accomplish this, use the "TOP" keyword. For example,
SELECT TOP 1
m.vehicle_no,
l.longitude,
l.latitude,
l.timestamp
For the second part of your question, "where $td is the least within $tssd is less than 10800", we do not know the column names that these relate to. If we pretend they're named TD and TSSD in the vehicle_log table, then your statement might look like this:
SELECT TOP 1 m.vehicle_no,
l.longitude,
l.latitude,
l.timestamp,
l.TD,
l.TSSD
FROM
vehicle_log AS l,
GPS_modem AS m
WHERE
m.modem_ID = l.modem_ID
AND l.timestamp = (
SELECT MAX(timestamp) FROM vehicle_log WHERE modem_ID = l.modem_ID
)
AND l.TD <= 10800
order by l.TD ASC
Lastly, I changed the ORDER BY to accommodate "i want to display the smallest $td".
If this is not what you are looking for, can you provide more information?

Categories