Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Real distance calculator #61

Merged
merged 4 commits into from
Jul 30, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Changelog

## 1.2.0 : 2022-07-30

- **Feature**: [Real distance calculation #37](https://github.com/Sibyx/phpGPX/issues/37) (DistanceCalculator refactor)

## 1.1.3 : 2021-07-29

- **Fix**: [Fix negative duration #58](https://github.com/Sibyx/phpGPX/pull/58) by [@neronmoon](https://github.com/neronmoon)
Expand Down
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
MIT License

Copyright (c) 2017 Jakub Dubec
Copyright (c) 2017-2022 Jakub Dubec

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ You can easily install phpGPX library with [composer](https://getcomposer.org/).
please use release candidates.

```
composer require sibyx/phpgpx:1.1.3
composer require sibyx/phpgpx:1.2.0
```

## Examples
Expand Down
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "sibyx/phpgpx",
"type": "library",
"version": "1.1.3",
"version": "1.2.0",
"description": "A simple PHP library for GPX import/export",
"minimum-stability": "stable",
"license": "MIT",
Expand Down
37 changes: 31 additions & 6 deletions src/phpGPX/Helpers/DistanceCalculator.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,31 +3,56 @@
* DistanceCalculator.php
*
* @author Jens Hassler
* @author Jakub Dubec
* @since 07/2018
* @version 2.0
*/

namespace phpGPX\Helpers;

use phpGPX\Helpers\GeoHelper;
use phpGPX\Models\Point;
use phpGPX\phpGPX;

class DistanceCalculator
{
/**
* @var Point[]
*/
private $points;

/**
* DistanceCalculator constructor.
* @param Point[] $points
*/
public function __construct(array $points)
{
$this->points = $points;
}

public function getRawDistance()
{
return $this->calculate([GeoHelper::class, 'getRawDistance']);
}

public function getRealDistance()
{
return $this->calculate([GeoHelper::class, 'getRealDistance']);
}

/**
* @param Point[]|array $points
* @return float
*/
public static function calculate(array $points)
private function calculate($strategy)
{
$distance = 0;

$pointCount = count($points);
$pointCount = count($this->points);

$lastConsideredPoint = null;

for ($p = 0; $p < $pointCount; $p++) {
$curPoint = $points[$p];
$curPoint = $this->points[$p];

// skip the first point
if ($p === 0) {
Expand All @@ -36,11 +61,11 @@ public static function calculate(array $points)
}

// calculate the delta from current point to last considered point
$curPoint->difference = GeoHelper::getDistance($lastConsideredPoint, $curPoint);
$curPoint->difference = call_user_func($strategy, $lastConsideredPoint, $curPoint);

// if smoothing is applied we only consider points with a delta above the threshold (e.g. 2 meters)
if (phpGPX::$APPLY_DISTANCE_SMOOTHING) {
$differenceFromLastConsideredPoint = GeoHelper::getDistance($curPoint, $lastConsideredPoint);
$differenceFromLastConsideredPoint = call_user_func($strategy, $curPoint, $lastConsideredPoint);

if ($differenceFromLastConsideredPoint > phpGPX::$DISTANCE_SMOOTHING_THRESHOLD) {
$distance += $differenceFromLastConsideredPoint;
Expand Down
19 changes: 18 additions & 1 deletion src/phpGPX/Helpers/GeoHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ abstract class GeoHelper
* @param Point $point2
* @return float
*/
public static function getDistance(Point $point1, Point $point2)
public static function getRawDistance(Point $point1, Point $point2)
{
$latFrom = deg2rad($point1->latitude);
$lonFrom = deg2rad($point1->longitude);
Expand All @@ -38,4 +38,21 @@ public static function getDistance(Point $point1, Point $point2)

return $angle * self::EARTH_RADIUS;
}

/**
* Returns distance between two points including elevation gain/loss
* @param Point $point1
* @param Point $point2
* @return float
*/
public static function getRealDistance(Point $point1, Point $point2)
{
$distance = self::getRawDistance($point1, $point2);

$elevation1 = $point1->elevation != null ? $point1->elevation : 0;
$elevation2 = $point2->elevation != null ? $point2->elevation : 0;
$elevDiff = abs($elevation1 - $elevation2);

return sqrt(pow($distance, 2) + pow($elevDiff, 2));
}
}
4 changes: 3 additions & 1 deletion src/phpGPX/Models/Route.php
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,9 @@ public function recalculateStats()
list($this->stats->cumulativeElevationGain, $this->stats->cumulativeElevationLoss) =
ElevationGainLossCalculator::calculate($this->getPoints());

$this->stats->distance = DistanceCalculator::calculate($this->getPoints());
$calculator = new DistanceCalculator($this->getPoints());
$this->stats->distance = $calculator->getRawDistance();
$this->stats->realDistance = $calculator->getRealDistance();

for ($p = 0; $p < $pointCount; $p++) {
if ((phpGPX::$IGNORE_ELEVATION_0 === false || $this->points[$p]->elevation > 0) && $this->stats->minAltitude > $this->points[$p]->elevation) {
Expand Down
4 changes: 3 additions & 1 deletion src/phpGPX/Models/Segment.php
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,9 @@ public function recalculateStats()
list($this->stats->cumulativeElevationGain, $this->stats->cumulativeElevationLoss) =
ElevationGainLossCalculator::calculate($this->getPoints());

$this->stats->distance = DistanceCalculator::calculate($this->getPoints());
$calculator = new DistanceCalculator($this->getPoints());
$this->stats->distance = $calculator->getRawDistance();
$this->stats->realDistance = $calculator->getRealDistance();

for ($i = 0; $i < $count; $i++) {
if ($this->stats->maxAltitude < $this->points[$i]->elevation) {
Expand Down
8 changes: 8 additions & 0 deletions src/phpGPX/Models/Stats.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,12 @@ class Stats implements Summarizable
*/
public $distance = 0;

/**
* Distance in meters (m) including elevation loss/gain
* @var float
*/
public $realDistance = 0;

/**
* Average speed in meters per second (m/s)
* @var float
Expand Down Expand Up @@ -82,6 +88,7 @@ class Stats implements Summarizable
public function reset()
{
$this->distance = null;
$this->realDistance = null;
$this->averageSpeed = null;
$this->averagePace = null;
$this->minAltitude = null;
Expand All @@ -100,6 +107,7 @@ public function toArray()
{
return [
'distance' => (float)$this->distance,
'realDistance' => (float)$this->realDistance,
'avgSpeed' => (float)$this->averageSpeed,
'avgPace' => (float)$this->averagePace,
'minAltitude' => (float)$this->minAltitude,
Expand Down
1 change: 1 addition & 0 deletions src/phpGPX/Models/Track.php
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ public function recalculateStats()
$this->stats->cumulativeElevationLoss += $this->segments[$s]->stats->cumulativeElevationLoss;

$this->stats->distance += $this->segments[$s]->stats->distance;
$this->stats->realDistance += $this->segments[$s]->stats->realDistance;

if ($this->stats->minAltitude === null) {
$this->stats->minAltitude = $this->segments[$s]->stats->minAltitude;
Expand Down
4 changes: 4 additions & 0 deletions tests/LoadFileTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ private function createExpectedArray()
],
'stats' => [
'distance' => 2.314424561683643,
'realDistance' => 2.314424561683643,
'avgSpeed' => 0.2571582846315159,
'avgPace' => 3888.6555859279733,
'minAltitude' => 0.0,
Expand All @@ -98,6 +99,7 @@ private function createExpectedArray()
],
'stats' => [
'distance' => 2.314424561683643,
'realDistance' => 2.314424561683643,
'avgSpeed' => 0.2571582846315159,
'avgPace' => 3888.6555859279733,
'minAltitude' => 0.0,
Expand Down Expand Up @@ -141,6 +143,7 @@ private function createExpectedArray()
],
'stats' => [
'distance' => 7.062730302497254,
'realDistance' => 7.062730302497254,
'avgSpeed' => 2.354243434165751,
'avgPace' => 424.7649098167112,
'minAltitude' => 0.0,
Expand All @@ -155,6 +158,7 @@ private function createExpectedArray()
],
'stats' => [
'distance' => 7.062730302497254,
'realDistance' => 7.062730302497254,
'avgSpeed' => 2.354243434165751,
'avgPace' => 424.7649098167112,
'minAltitude' => 0.0,
Expand Down
2 changes: 2 additions & 0 deletions tests/LoadRouteFileTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ private function createExpectedArray()
],
'stats' => [
'distance' => 132.0785853,
'realDistance' => 132.0785853,
'avgSpeed' => 0.0,
'avgPace' => 0.0,
'minAltitude' => 0.0,
Expand Down Expand Up @@ -133,6 +134,7 @@ private function createExpectedArray()
],
'stats' => [
'distance' => 132.0785853,
'realDistance' => 132.0785853,
'avgSpeed' => 0.0,
'avgPace' => 0.0,
'minAltitude' => 0.0,
Expand Down
32 changes: 31 additions & 1 deletion tests/UnitTests/phpGPX/Helpers/GeoHelperTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,39 @@ public function testGetDistance()

$this->assertEquals(
856.97,
GeoHelper::getDistance($point1, $point2),
GeoHelper::getRawDistance($point1, $point2),
"Invalid distance between two points!",
1
);
}

/**
* @link http://cosinekitty.com/compass.html
*/
public function testRealDistance()
{
$point1 = new Point(Point::WAYPOINT);
$point1->latitude = 48.1573923225717;
$point1->longitude = 17.0547121910204;
$point1->elevation = 100;

$point2 = new Point(Point::WAYPOINT);
$point2->latitude = 48.1644916381763;
$point2->longitude = 17.0591753907502;
$point2->elevation = 200;

$this->assertEquals(
856.97,
GeoHelper::getRawDistance($point1, $point2),
"Invalid distance between two points!",
1
);

$this->assertEquals(
862,
GeoHelper::getRealDistance($point1, $point2),
"Invalid real distance between two points!",
1
);
}
}