Php - getting the distance between multiple points using lon, lat and alt - php

So i want to load a gpx file and get all the cordinates and calculate the total distance traveled, but im stuck with this code:
<?php
$xml = simplexml_load_file("data/example.gpx");
echo $xml->metadata->author->name;
echo "</br>";
echo "</br>";
echo "</br>";
$lon1=0;
$lat1=0;
$lon2=0;
$lat2=0;
$alt1=0;
$alt2=0;
$dist=0;
$brr = count($xml->trk->trkseg);
$brf = 0;
for($i = 0; $i<$brr; $i++){
$br = count($xml->trk->trkseg[$i]->trkpt);
$brf= $brf + $br;
for($j = 0; $j<$br;$j++){
$lat2= (float) $xml->trk->trkseg[$i]->trkpt[$j]['lat'];
$lon2= (float) $xml->trk->trkseg[$i]->trkpt[$j]['lon'];
$alt2= (float) $xml->trk->trkseg[$i]->trkpt[$j]->ele;
$lon2 = $alt2 * cos($lat2) * sin($lon2);
$lat2 = $alt2 * sin($lat2);
$alt2 = $alt2 * cos($lat2) * cos($lon2);
if ($j==0){ //this is just for the first time because first points are not set
$lat1=$lat2;
$lon1=$lon2;
$alt1= $alt2;
}
$cdist = sqrt(pow(($lat2-$lat1),2) + pow(($lon2-$lon1),2) + pow(($alt2-$alt1),2));
$dist = $dist + $cdist;
$lat1=$lat2;
$lon1=$lon2;
$alt1=$alt2;
}
}
echo 'Distance = '.$dist;
echo '</br>';
echo 'number of coordinates = '.$brf;
?>
as result for distance i get the number 4592.6244157763 instead of 4.10km (~~4100), but coordinates are good, it goes through all coordinates. (also, the gpx file is from endomondo if it matters)

Fixed the code, in case anyone needs it, here it is:
<?php
$xml = simplexml_load_file("data/vladantd.gpx");
echo $xml->metadata->author->name;
echo "</br>";
echo "</br>";
echo "</br>";
$lon1=0;
$lat1=0;
$lon2=0;
$lat2=0;
$alt1=0;
$alt2=0;
$dist=0;
$brr = count($xml->trk->trkseg);
$brf = 0;
for($i = 0; $i<$brr; $i++){
$br = count($xml->trk->trkseg[$i]->trkpt);
$brf= $brf + $br;
for($j = 0; $j<$br;$j++){
if($j==0)
{
$j=1;
$g=1;
}
$lat2= (float) $xml->trk->trkseg[$i]->trkpt[$j]['lat'];
$lon2= (float) $xml->trk->trkseg[$i]->trkpt[$j]['lon'];
$alt2= (float) $xml->trk->trkseg[$i]->trkpt[$j]->ele;
$lon2 = $alt2 * cos($lat2) * sin($lon2);
$lat2 = $alt2 * sin($lat2);
$alt2 = $alt2 * cos($lat2) * cos($lon2);
if ($g==1){
$lat1=$lat2;
$lon1=$lon2;
$alt1= $alt2;
$j=0;
$g=0;
}
$cdist = sqrt(pow(($lat2-$lat1),2) + pow(($lon2-$lon1),2) + pow(($alt2-$alt1),2));
$dist = $dist + $cdist;
$lat1=$lat2;
$lon1=$lon2;
$alt1=$alt2;
}
}
echo 'Distance = '.$dist;
echo '</br>';
echo 'number of coordinates = '.$brf;
?>
okay, so the files that i use, every first trkpt in every trkseg doesnt have an altitude, so if j==0 then set j to 1, so it skips that first point (it sets points 1 time every few seconds so it shouldnt make a big difference (in my case) and at the same time i've set another variable g to 1, so that we can at the end of this current loop, return j back to 0 so the j++ increases it to 1 instead of skipping the point and increasing it to 2, rest should be clear, if you have any questions, just ask ^^
EDIT:
The code isnt working good. The longer the distance, the bigger the mistake it makes, for 8.1km it shows 9km, tested it out on a few gpx files and noticed. Sorry, if someone has a solution, would mean a lot!

Related

Can't understand why my php cosine similarity code isn't working

I'm working on a website for my friend's gaming clan. I'm trying to have a php code that takes the player's coordinates, loops over some known locations and print the name of the closest location.
I can't get it to work however. It always seems to want to print "Balota" which is index 1 in the array. I also noticed that the cosine function can't be working as all values are above 1.0.
But I'm completely stuck now. I think I've been beating my head over it for too long and its something right in front of me but I can't see it.
<?php
function DotProd($loc1,$loc2){
return array_sum(array_map(create_function('$a, $b', 'return $a * $b;'), $loc1, $loc2));
}
function CosineSim($loc1,$loc2){
return DotProd($loc2,$loc2)/sqrt(DotProd($loc1,$loc2)*DotProd($loc1,$loc2));
}
function Closest($loc){
$novo = array(11300,14300);
$balota = array(4500,2500);
$zelen = array(2500,5200);
$sever = array(7900,12600);
$vybor = array(4500,8200);
$nwaf = array(4500,10200);
$neaf = array(12100,12500);
$kamensk = array(7870,14600);
$bere = array(12900,10000);
$gorka = array(9600,8900);
$elektro = array(10100,2000);
$cherno = array(6600,2600);
$stary = array(6100,7700);
$novy = array(7000,7700);
$mysk = array(1100,7200);
$locations = array($novo,$balota,$zelen,$sever,$vybor,$nwaf,$neaf,
$kamensk,$bere,$gorka,$elektro,$cherno,$stary,$novy,$mysk);
$sim = 99999999999;
$locat = 0;
for($i = 14; $i >= 0; $i--){
$s = CosineSim($loc,$locations[$i]);
echo "<br>" . $i . " " . CosineSim($loc,$locations[$i]);
if($s < $sim){
$sim = $s;
$locat = $i;
}
}
$items = array("Novo","Balota","Zelenogorsk","Severograd","Vybor","NWAF","NEAF","Kamensk Military","Berezino",
"Gorka","Elektro","Cherno","Stary Sobor","Novy Sobor","Myshkino");
return $items[$locat];
}
$x = $_GET["xpos"];
$y = $_GET["ypos"];
$location = array($x,$y);
echo "<b>You are at " . $x . ":" . $y;
$index = Closest($location);
echo "<br>You're pretty close to ". $index . "<br>";
?>
I am using a distance calculation formula based on the link: https://www.mathwarehouse.com/algebra/distance_formula/index.php
I only changed CosineSim. The rest of the code remains the same. And you don't actually need DotProd. It's not elegant but it works for me.
function CosineSim($loc1,$loc2){
// sum of x coordinates
$x1 = ($loc1[0]-$loc2[0])*($loc1[0]-$loc2[0]);
// sum of y coordinates
$y2 = ($loc1[1]-$loc2[1])*($loc1[1]-$loc2[1]);
$summ = $x1 + $y2;
$sqrt_res = sqrt($summ);
return $sqrt_res;
}
If I enter something like:
You are at 4640:7205
...
You're pretty close to Vybor
Hope this helps!

JSON Array values to always total up to 100%

I have a wheel of fortune that spins, and has probability set for winning each prize that adds up to 100%. Once the quantity of a prize is met, ie, all of that prize is gone from stock, it sets the probability to 0 so you can't win it again. My problem then, is that the other values don't add up to 100. They always have to add up to 100 otherwise the wheel doesn't work.
I've got to the point of dividing all of the values by the total, rounding to two decimals and then adding them together, but i get 99 instead of 100. I've tried a few other ways of doing it and can never get to 100.
edit: My main problem seems to be that there is a 0.01% chance of winning 2 of the prizes. Dividing them by the total drops them to 0.000234234% or something similar, so when i multiply that by 100 then round that up to 2 decimals i'm getting 0.00% - but i can't think of any other way around it...
$jsonString = file_get_contents('wp-content/themes/supertheme/wheel_data.json');
$data = json_decode($jsonString, true);
echo '<pre>';
//print_r($data['segmentValuesArray'][0]['probability']);
echo '</pre>';
if ($prize1 <= 5){
$prize1before = $data['segmentValuesArray'][0]['probability'];
$data['segmentValuesArray'][0]['probability'] = 0;
}
if ($prize2 >= 5){
$data['segmentValuesArray'][1]['probability'] = 0;
}
if ($prize3 >= 300){
$data['segmentValuesArray'][2]['probability'] = 0;
}
if ($prize4 >= 500){
$data['segmentValuesArray'][3]['probability'] = 0;
}
if ($prize5 >= 10){
$data['segmentValuesArray'][4]['probability'] = 0;
}
$prize1total = $data['segmentValuesArray'][0]['probability'];
$prize2total = $data['segmentValuesArray'][1]['probability'];
$prize3total = $data['segmentValuesArray'][2]['probability'];
$prize4total = $data['segmentValuesArray'][3]['probability'];
$prize5total = $data['segmentValuesArray'][4]['probability'];
$total = $prize1total + $prize2total + $prize3total + $prize4total + $prize5total;
echo'<pre>';
print_r($total);
echo'<pre>';
$a = 0;
foreach($data['segmentValuesArray'] as $prize_array){
if($prize_array['probability'] > 0){
$a++;
}
}
$integer = $prize1before / $a;
$divided1 = $prize1total / $total;
$rounded1 = number_format((float)$divided1, 2, '.', '');
$full1 = $rounded1 * 100;
$divided2 = $prize2total / $total;
$rounded2 = number_format((float)$divided2, 2, '.', '');
$full2 = $rounded2 * 100 + $integer;
$divided3 = $prize3total / $total;
$rounded3 = number_format((float)$divided3, 2, '.', '');
$full3 = $rounded3 * 100 + $integer;
$divided4 = $prize4total / $total;
$rounded4 = number_format((float)$divided4, 2, '.', '');
$full4 = $rounded4 * 100 + $integer;
$divided5 = $prize5total / $total;
$rounded5 = number_format((float)$divided5, 2, '.', '');
$full5 = $rounded5 * 100 + $integer;
$newtotal = $full1 + $full2 + $full3 + $full4 + $full5;
echo'<pre>';
print_r($newtotal);
echo'<pre>';
$newJsonString = json_encode($data, JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES);
file_put_contents('wp-content/themes/supertheme/wheel_data.json', $newJsonString);

Convert cm to km, meters and cm

I'm trying to do an activity where I need do put a number in cm, and the program has to return it with km, m, and cm.
An example: 270004 cm = 2km, 700m, 4cm // 100cm = 0km, 1m, 0cm.
I have done this code, but, sometimes I get negative numbers, and sometimes I get strange numbers.
Maybe is why I use the PHP_ROUND_HALF_UP??
What can I do to solve it?
//I have an HTML form to introduce the number value
$num = 123456789;
$km = $num/1000;
$km = round($km, 0, PHP_ROUND_HALF_UP);
echo "km: ".$km."<br>";
$subtraction = ($km * 1000) - $num;
$m = $subtraction / 100;
$m = round($m, 0, PHP_ROUND_HALF_UP);
echo "m: ".$m."<br>";
$subtraction2 = ($m * 100) - $subtraction;
$cm = $subtraction2;
echo "cm: ".$cm."<br>";
Honestly, your code seems to be a bit over complicated :P Ever heard of modulo division? Comes in handy in here!
<?php
$x = 123456789323; // centimeters
$km = floor($x / 100000); // amount of "full" kilometers
$rkm = $x % 100000; // rest
$m = floor($rkm / 100); // amount of "full" meters"
$cm = $rkm % 100; // rest
echo $x . ' cm = ' . $km . ' kilometers ' . $m . ' meters and ' . $cm . 'centimeters' . PHP_EOL;
$cm = 234459891345;
echo sprintf('km: %02d m: %02d cm: %02d', ($cm/100000),($cm/100%100), $cm%100);

Javascript/PHP Array

I edited my code, see below:
I am trying to do an array with the time enroute. $distance works properly.
Now "ete" is giving this result for each leg: NaN Hrs. NaN Mins.
I replaced distance with 1500 and it spit out a result. That leads me to believe this [new Array();] is the problem.
I did some more digging
var distance = new Array(""); is giving me this result: 431,910,746,923
Does that mean the implode did not work?
<script type="text/javascript">
var distance = new Array(<?=implode(', ', $distance)?>);
function Aircraft() {
var mylist = document.getElementById("myList");
for(var i = 0; i < distance.length; i++) {
var hour = (Math.floor(1500 / mylist.options[mylist.selectedIndex].value));
var minute = Math.round((Math.round(1500 / mylist.options[mylist.selectedIndex].value) - hour) * 60);
document.getElementById("ete" + i).innerHTML = hour + " Hrs. " + minute + " Mins.";
}
}
</script>
We're getting closer I think...
$distance = array();
for($i = 0, $size = sizeof($Row1); $i < ($size - 1); ++$i){
$distance[$i] = ROUND((ACOS(SIN($Row2[$i][4] * PI() / 180) * SIN($Row1[$i][4] * PI() / 180) + COS($Row2[$i][4] * PI() / 180) * COS($Row1[$i][4] * PI() / 180) * COS(($Row2[$i][5] - $Row1[$i][5]) * PI() / 180)) * 180 / PI()) * 60 );
echo "<td width=100>" . $distance[$i] . " NM</td>";
echo "<td width=100><span id=\"ete" . $i . "\"></span></td>";
}
?>
<script type="text/javascript">
var distance = new Array(<?=implode(', ', $distance)?>);
function Aircraft() {
var mylist = document.getElementById("myList");
for(var i = 0; i < distance.length; i++) {
var hour = (Math.floor(distance / mylist.options[mylist.selectedIndex].value));
var minute = Math.round((Math.round(distance / mylist.options[mylist.selectedIndex].value) - hour) * 60);
document.getElementById("ete" + i).innerHTML = hour + " Hrs. " + minute + " Mins.";
}
}
Here is where Aircraft() is used:
<select id=\"myList\" style=\"width:150px;\" onchange=\"Aircraft()\">
<option>Select Aircraft</option>
<option value=\"300\">King Air 350</option>
<option value=\"450\">G-V</option>
<option value=\"470\">GLEX</option>
<option value=\"350\">Astra</option>
</select>
Not an answer to your direct question, but you don't need to write code like this in PHP:
for($i = 0, $size = sizeof($Row1); $i < $size; ++$i){
if ($i < ($size-1)){
$Row1[$i]['a']...
$Row2[$i]['b']...
}
}
You can use foreach() to iterate over an array:
foreach ($Row1 as $k => $r1){
$r2 = $Row2[$k];
$r1['a']...
$r2['a']...
}
That aside, your code does not do what you want for a couple of reasons. Assuming that the loop actually runs more than once, you're creating multiple functions all called Aircraft() - function names must be unique. Assuming you are actually running the function, then it will only run the most recently defined version of the function (i.e. the last one). You probably want something like this:
<table>
<?
# output table cells we will populate
foreach (....){
echo "<tr>";
echo "<td id=\"$id\"></td>";
echo "</tr>";
}
?>
</table>
<script>
function Aircraft(distance, id){
body of javascript here,
inserts results into element with ID of `id`
}
<?
# now output calls to the JS function that will produce the output
foreach (....){
$distance = ...;
echo "Aircraft($distance, $id);\n";
}
?>
</script>
Solved it:
<script type="text/javascript">
var distance = new Array("<?php echo implode('","',$distance)?>");
function Aircraft() {
var mylist = document.getElementById("myList");
for(var i = 0; i < distance.length; i++) {
var hour = (Math.floor(distance[i] / mylist.options[mylist.selectedIndex].value));
var minute = Math.round(((distance[i] / mylist.options[mylist.selectedIndex].value) - hour) * 60);
document.getElementById("ete" + i).innerHTML = hour + " Hrs. " + minute + " Mins.";
}
}
</script>
If I understand correctly, you want to calculate several time estimates for different distances according to the selected aircraft.
To accomplish this, a JavaScript array with the distances could be stored. Then, the Aircraft() function would only need to iterate through the different spans filling in the new ETA's.
Try replacing the first block of code with this:
<?php
$distance = array();
for ($i = 0, $size = sizeof($Row1); $i < ($size - 1); ++$i) {
$distance[$i] = ROUND((ACOS(SIN($Row2[$i][4] * PI() / 180) * SIN($Row1[$i][4] * PI() / 180) + COS($Row2[$i][4] * PI() / 180) * COS($Row1[$i][4] * PI() / 180) * COS(($Row2[$i][5] - $Row1[$i][5]) * PI() / 180)) * 180 / PI()) * 60 );
echo "<td width=100>" . $distance[$i] . " NM</td>";
echo "<td width=100><span id=\"ete" . $i . "\"></span></td>";
}
?>
<script type="text/javascript">
var distances = new Array("<?=implode('", "', $distance)?>");
function Aircraft() {
var mylist = document.getElementById("myList");
for(var i = 0; i < distances.length; i++) {
var hour = (Math.floor(distance / mylist.options[mylist.selectedIndex].value));
var minute = Math.round((Math.round(distance / mylist.options[mylist.selectedIndex].value) - hour) * 60);
document.getElementById("ete" + i).innerHTML = hour + " Hrs. " + minute + " Mins.";
}
}
</script>

SQL or PHP mistake? Distance calculation

I have a problem with my file. I'm making Travian Clone script and we went really far. Now we decided to add artefacts into game.
Goal is to show closest artefacts to the current village we are in. The code is:
function getDistance($coorx1, $coory1, $coorx2, $coory2) {
$max = 2 * WORLD_MAX + 1;
$x1 = intval($coorx1);
$y1 = intval($coory1);
$x2 = intval($coorx2);
$y2 = intval($coory2);
$distanceX = min(abs($x2 - $x1), $max - abs($x2 - $x1));
$distanceY = min(abs($y2 - $y1), $max - abs($y2 - $y1));
$dist = sqrt(pow($distanceX, 2) + pow($distanceY, 2));
return round($dist, 1);
}
unset($reqlvl);
unset($effect);
$arts = mysql_query("SELECT * FROM ".TB_PREFIX."artefacts WHERE id > 0");
$rows = array();
while($row = mysql_fetch_array($arts)) {
$query = mysql_query('SELECT * FROM `' . TB_PREFIX . 'wdata` WHERE `id` = ' . $row['vref']);
$coor2 = mysql_fetch_assoc($query);
$wref = $village->wid;
$coor = $database->getCoor($wref);
$dist = getDistance($coor['x'], $coor['y'], $coor2['x'], $coor2['y']);
$rows[$dist] = $row;
}
ksort($rows, SORT_ASC);
foreach($rows as $row) {
echo '<tr>';
echo '<td class="icon"><img class="artefact_icon_'.$row['type'].'" src="img/x.gif" alt="" title=""></td>';
echo '<td class="nam">';
echo ''.$row['name'].' <span class="bon">'.$row['effect'].'</span>';
echo '<div class="info">';
if($row['size'] == 1){
$reqlvl = 10;
$effect = "village";
}elseif($row['size'] == 2 OR $row['size'] == 3){
$reqlvl = 20;
$effect = "account";
}
echo '<div class="info">Treasury <b>'.$reqlvl.'</b>, Effect <b>'.$effect.'</b>';
echo '</div></td><td class="pla">'.$database->getUserField($row['owner'],"username",0).'</td>';
echo '<td class="dist">'.getDistance($coor['x'], $coor['y'], $coor2['x'], $coor2['y']).'</td>';
echo '</tr>';
}
?>
but the code seems to be wrong because its showing all same distances. 14.8 to me. I know i maybe have bad explanation but u will probably understand what I need.
I can't help with your current code I'm afraid but you could try using the Haversine Formula instead:
// Where:
// $l1 ==> latitude1
// $o1 ==> longitude1
// $l2 ==> latitude2
// $o2 ==> longitude2
function haversine ($l1, $o1, $l2, $o2) {
$l1 = deg2rad ($l1);
$sinl1 = sin ($l1);
$l2 = deg2rad ($l2);
$o1 = deg2rad ($o1);
$o2 = deg2rad ($o2);
$distance = (7926 - 26 * $sinl1) * asin (min (1, 0.707106781186548 * sqrt ((1 - (sin ($l2) * $sinl1) - cos ($l1) * cos ($l2) * cos ($o2 - $o1)))));
return round($distance, 2);
}
Credit goes to this post on go4expert.com, I've used this function in the past and found it works very well.

Categories