├── .github ├── FUNDING.yml └── workflows │ ├── phpunit.yml │ └── codesee-arch-diagram.yml ├── tests ├── UnitTests │ └── phpGPX │ │ ├── Parsers │ │ ├── EmailParserTest.json │ │ ├── LinkParserTest.json │ │ ├── BoundsParserTest.json │ │ ├── EmailParserTest.xml │ │ ├── CopyrightParserTest.json │ │ ├── BoundsParserTest.xml │ │ ├── LinkParserTest.xml │ │ ├── PointParserTest.xml │ │ ├── CopyrightParserTest.xml │ │ ├── ExtensionParserTest.json │ │ ├── PersonParserTest.json │ │ ├── PersonParserTest.xml │ │ ├── PointParserTest.json │ │ ├── SegmentParserTest.xml │ │ ├── BoundsParserTest.php │ │ ├── EmailParserTest.php │ │ ├── LinkParserTest.php │ │ ├── CopyrightParserTest.php │ │ ├── ExtensionParserTest.xml │ │ ├── AbstractParserTest.php │ │ ├── PointParserTest.php │ │ ├── PersonParserTest.php │ │ ├── SegmentParserTest.php │ │ ├── ExtensionParserTest.php │ │ └── SegmentParserTest.json │ │ └── Helpers │ │ ├── GeoHelperTest.php │ │ ├── DateTimeHelperTest.php │ │ └── SerializationHelperTest.php ├── fixtures │ ├── route.gpx │ ├── gps-track.gpx │ └── timezero.gpx └── CreateWaypointTest.php ├── docs ├── _data │ └── authors.yml ├── phpGPX-Models-Summarizable.md ├── phpGPX-Models-StatsCalculator.md ├── _config.yml ├── phpGPX-Parsers-WaypointParser.md ├── phpGPX-Helpers-GeoHelper.md ├── phpGPX-Models-Extensions.md ├── phpGPX-Parsers-EmailParser.md ├── phpGPX-Parsers-PersonParser.md ├── phpGPX-Parsers-CopyrightParser.md ├── phpGPX-Models-Email.md ├── phpGPX-Parsers-BoundsParser.md ├── phpGPX-Models-Link.md ├── phpGPX-Models-Extensions-AbstractExtension.md ├── phpGPX-Helpers-DateTimeHelper.md ├── phpGPX-Parsers-ExtensionParser.md ├── phpGPX-Models-Person.md ├── phpGPX-Models-Bounds.md ├── phpGPX-Models-Copyright.md ├── phpGPX-Parsers-SegmentParser.md ├── phpGPX-Parsers-LinkParser.md ├── phpGPX-Parsers-Extensions-TrackPointExtensionParser.md ├── phpGPX-Helpers-SerializationHelper.md ├── phpGPX-Parsers-MetadataParser.md ├── phpGPX-Models-Segment.md ├── phpGPX-Parsers-TrackParser.md ├── phpGPX-Parsers-RouteParser.md ├── phpGPX-Models-GpxFile.md ├── phpGPX-phpGPX.md ├── phpGPX-Parsers-PointParser.md ├── phpGPX-Models-Metadata.md ├── phpGPX-Models-Stats.md ├── phpGPX-Models-Collection.md ├── phpGPX-Models-Track.md ├── phpGPX-Models-Route.md └── phpGPX-Models-Extensions-TrackPointExtension.md ├── .gitignore ├── .codeclimate.yml ├── src └── phpGPX │ ├── Models │ ├── Summarizable.php │ ├── StatsCalculator.php │ ├── Extensions │ │ ├── AbstractExtension.php │ │ └── TrackPointExtension.php │ ├── Email.php │ ├── Extensions.php │ ├── Link.php │ ├── Person.php │ ├── Copyright.php │ ├── Bounds.php │ ├── Collection.php │ ├── Metadata.php │ ├── Stats.php │ ├── Segment.php │ ├── Route.php │ └── GpxFile.php │ ├── Parsers │ ├── WaypointParser.php │ ├── EmailParser.php │ ├── PersonParser.php │ ├── CopyrightParser.php │ ├── BoundsParser.php │ ├── LinkParser.php │ ├── SegmentParser.php │ ├── ExtensionParser.php │ ├── Extensions │ │ └── TrackPointExtensionParser.php │ ├── TrackParser.php │ ├── RouteParser.php │ └── MetadataParser.php │ ├── Helpers │ ├── BoundsCalculator.php │ ├── DateTimeHelper.php │ ├── GeoHelper.php │ ├── SerializationHelper.php │ ├── DistanceCalculator.php │ └── ElevationGainLossCalculator.php │ └── phpGPX.php ├── .php-cs-fixer.php ├── example ├── Example.php ├── waypoints_load.php ├── waypoint_test.gpx ├── output_waypoint_test.gpx ├── waypoints_create.php └── CreateFileFromScratch.php ├── phpunit.xml ├── ISSUE_TEMPLATE.md ├── .travis.yml ├── composer.json ├── LICENSE ├── CHANGELOG.md └── CODE_OF_CONDUCT.md /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | ko_fi: sibyx 2 | custom: ['https://www.buymeacoffee.com/Sibyx'] 3 | -------------------------------------------------------------------------------- /tests/UnitTests/phpGPX/Parsers/EmailParserTest.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "jakub.dubec", 3 | "domain": "gmail.com" 4 | } -------------------------------------------------------------------------------- /docs/_data/authors.yml: -------------------------------------------------------------------------------- 1 | sibyx: 2 | picture: https://www.gravatar.com/avatar/c08cc3a6b17177a4bd7045566b0d772a?s=500 3 | twitter: jakubdubec -------------------------------------------------------------------------------- /tests/UnitTests/phpGPX/Parsers/LinkParserTest.json: -------------------------------------------------------------------------------- 1 | { 2 | "href": "https://jakubdubec.me", 3 | "text": "Portfolio", 4 | "type": "text/html" 5 | } -------------------------------------------------------------------------------- /tests/UnitTests/phpGPX/Parsers/BoundsParserTest.json: -------------------------------------------------------------------------------- 1 | { 2 | "maxlat": 49.090543, 3 | "maxlon": 18.886939, 4 | "minlat": 49.072489, 5 | "minlon": 18.814543 6 | } -------------------------------------------------------------------------------- /tests/UnitTests/phpGPX/Parsers/EmailParserTest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | composer.phar 2 | composer.lock 3 | /vendor/ 4 | /.idea/ 5 | /phpdocs/ 6 | /bin/ 7 | .DS_Store? 8 | *.DS_Store 9 | /.php_cs.cache 10 | /.phpunit.result.cache 11 | -------------------------------------------------------------------------------- /tests/UnitTests/phpGPX/Parsers/CopyrightParserTest.json: -------------------------------------------------------------------------------- 1 | { 2 | "author": "Jakub Dubec", 3 | "license": "https://github.com/Sibyx/phpGPX/blob/master/LICENSE", 4 | "year": "2017" 5 | } -------------------------------------------------------------------------------- /tests/UnitTests/phpGPX/Parsers/BoundsParserTest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /tests/UnitTests/phpGPX/Parsers/LinkParserTest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Portfolio 5 | text/html 6 | 7 | -------------------------------------------------------------------------------- /tests/UnitTests/phpGPX/Parsers/PointParserTest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 2419 5 | 6 | 7 | -------------------------------------------------------------------------------- /tests/UnitTests/phpGPX/Parsers/CopyrightParserTest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 2017 5 | https://github.com/Sibyx/phpGPX/blob/master/LICENSE 6 | 7 | -------------------------------------------------------------------------------- /tests/UnitTests/phpGPX/Parsers/ExtensionParserTest.json: -------------------------------------------------------------------------------- 1 | { 2 | "trackpoint": { 3 | "aTemp": 14, 4 | "wTemp": null, 5 | "depth": null, 6 | "hr": 152, 7 | "cad": null, 8 | "speed": null, 9 | "course": null, 10 | "bearing": null 11 | }, 12 | "unsupported": [] 13 | } 14 | -------------------------------------------------------------------------------- /tests/UnitTests/phpGPX/Parsers/PersonParserTest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Jakub Dubec", 3 | "email": { 4 | "id": "jakub.dubec", 5 | "domain": "gmail.com" 6 | }, 7 | "links": [ 8 | { 9 | "href": "https://jakubdubec.me", 10 | "text": "Portfolio", 11 | "type": "text/html" 12 | } 13 | ] 14 | } -------------------------------------------------------------------------------- /.codeclimate.yml: -------------------------------------------------------------------------------- 1 | engines: 2 | duplication: 3 | enabled: true 4 | config: 5 | languages: 6 | - php 7 | fixme: 8 | enabled: true 9 | phpmd: 10 | enabled: true 11 | ratings: 12 | paths: 13 | - "**.php" 14 | exclude_paths: 15 | - docs/* 16 | - example/* -------------------------------------------------------------------------------- /tests/UnitTests/phpGPX/Parsers/PersonParserTest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Jakub Dubec 5 | 6 | 7 | Portfolio 8 | text/html 9 | 10 | 11 | -------------------------------------------------------------------------------- /src/phpGPX/Models/Summarizable.php: -------------------------------------------------------------------------------- 1 | 5 | */ 6 | 7 | namespace phpGPX\Models; 8 | 9 | /** 10 | * Interface Summarizable 11 | * @package phpGPX\Models 12 | */ 13 | interface Summarizable 14 | { 15 | 16 | /** 17 | * Serialize object to array 18 | * @return array 19 | */ 20 | public function toArray(); 21 | } 22 | -------------------------------------------------------------------------------- /.php-cs-fixer.php: -------------------------------------------------------------------------------- 1 | 2 | in(__DIR__) 6 | ->ignoreDotFiles(true) 7 | ->ignoreVCS(true) 8 | ->exclude(['docs', 'vendor']) 9 | ->files() 10 | ->name('*.php') 11 | ; 12 | 13 | return PhpCsFixer\Config::create() 14 | ->setUsingCache(true) 15 | ->setFinder($finder) 16 | ->setRules([ 17 | '@PSR2' => true, 18 | ]) 19 | ->setIndent("\t") 20 | ; 21 | -------------------------------------------------------------------------------- /docs/phpGPX-Models-Summarizable.md: -------------------------------------------------------------------------------- 1 | phpGPX\Models\Summarizable 2 | =============== 3 | 4 | Interface Summarizable 5 | 6 | 7 | 8 | 9 | * Interface name: Summarizable 10 | * Namespace: phpGPX\Models 11 | * This is an **interface** 12 | 13 | 14 | 15 | 16 | 17 | 18 | Methods 19 | ------- 20 | 21 | 22 | ### toArray 23 | 24 | array phpGPX\Models\Summarizable::toArray() 25 | 26 | Serialize object to array 27 | 28 | 29 | 30 | * Visibility: **public** 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /docs/phpGPX-Models-StatsCalculator.md: -------------------------------------------------------------------------------- 1 | phpGPX\Models\StatsCalculator 2 | =============== 3 | 4 | 5 | 6 | 7 | 8 | 9 | * Interface name: StatsCalculator 10 | * Namespace: phpGPX\Models 11 | * This is an **interface** 12 | 13 | 14 | 15 | 16 | 17 | 18 | Methods 19 | ------- 20 | 21 | 22 | ### recalculateStats 23 | 24 | void phpGPX\Models\StatsCalculator::recalculateStats() 25 | 26 | Recalculate stats objects. 27 | 28 | 29 | 30 | * Visibility: **public** 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /example/Example.php: -------------------------------------------------------------------------------- 1 | 5 | */ 6 | 7 | use phpGPX\phpGPX; 8 | 9 | require_once '../vendor/autoload.php'; 10 | 11 | $gpx = new phpGPX(); 12 | $file = $gpx->load('endomondo.gpx'); 13 | 14 | phpGPX::$PRETTY_PRINT = true; 15 | //$file->save('output_Evening_Ride.gpx', phpGPX::XML_FORMAT); 16 | 17 | foreach ($file->tracks as $track) { 18 | var_dump($track->stats->toArray()); 19 | } 20 | -------------------------------------------------------------------------------- /src/phpGPX/Models/StatsCalculator.php: -------------------------------------------------------------------------------- 1 | 5 | */ 6 | 7 | namespace phpGPX\Models; 8 | 9 | interface StatsCalculator 10 | { 11 | 12 | /** 13 | * Recalculate stats objects. 14 | * @return void 15 | */ 16 | public function recalculateStats(); 17 | 18 | /** 19 | * Return all points in collection. 20 | * @return Point[] 21 | */ 22 | public function getPoints(); 23 | } 24 | -------------------------------------------------------------------------------- /docs/_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-cayman 2 | author: sibyx 3 | title: phpGPX library 4 | description: Simple library for reading and creating GPX files written in PHP. 5 | gems: 6 | - jekyll-seo-tag 7 | - jekyll-analytics 8 | - jekyll-sitemap 9 | social: 10 | name: Jakub Dubec 11 | links: 12 | - https://www.facebook.com/dubecj 13 | - https://github.com/Sibyx 14 | - https://keybase.io/jakubdubec 15 | 16 | jekyll_analytics: 17 | GoogleAnalytics: 18 | id: UA-99333937-1 19 | anonymizeIp: false -------------------------------------------------------------------------------- /.github/workflows/phpunit.yml: -------------------------------------------------------------------------------- 1 | name: PHPUnit 2 | 3 | on: [push] 4 | 5 | jobs: 6 | build: 7 | runs-on: ubuntu-latest 8 | strategy: 9 | max-parallel: 4 10 | matrix: 11 | php-version: ['7.3', '8.0', '8.1'] 12 | 13 | steps: 14 | - uses: actions/checkout@v3 15 | - uses: php-actions/composer@v6 16 | name: Install dependencies 17 | with: 18 | php_version: ${{ matrix.php-version }} 19 | version: 2 20 | - name: Running PHPUnit 21 | run: php vendor/bin/phpunit --configuration phpunit.xml -------------------------------------------------------------------------------- /tests/UnitTests/phpGPX/Parsers/PointParserTest.json: -------------------------------------------------------------------------------- 1 | { 2 | "ageofdgpsdata": null, 3 | "cmt": null, 4 | "desc": null, 5 | "dgpsid": null, 6 | "difference": null, 7 | "distance": null, 8 | "ele": 2419, 9 | "extensions": null, 10 | "fix": null, 11 | "geoidheight": null, 12 | "hdop": null, 13 | "lat": 46.571948, 14 | "link": [], 15 | "lon": 8.414757, 16 | "magvar": null, 17 | "name": null, 18 | "pdop": null, 19 | "sat": null, 20 | "src": null, 21 | "sym": null, 22 | "time": "2017-08-13T07:10:41+00:00", 23 | "type": null, 24 | "vdop": null 25 | } -------------------------------------------------------------------------------- /.github/workflows/codesee-arch-diagram.yml: -------------------------------------------------------------------------------- 1 | # This workflow was added by CodeSee. Learn more at https://codesee.io/ 2 | # This is v2.0 of this workflow file 3 | on: 4 | push: 5 | branches: 6 | - master 7 | pull_request_target: 8 | types: [opened, synchronize, reopened] 9 | 10 | name: CodeSee 11 | 12 | permissions: read-all 13 | 14 | jobs: 15 | codesee: 16 | runs-on: ubuntu-latest 17 | continue-on-error: true 18 | name: Analyze the repo with CodeSee 19 | steps: 20 | - uses: Codesee-io/codesee-action@v2 21 | with: 22 | codesee-token: ${{ secrets.CODESEE_ARCH_DIAG_API_TOKEN }} 23 | -------------------------------------------------------------------------------- /docs/phpGPX-Parsers-WaypointParser.md: -------------------------------------------------------------------------------- 1 | phpGPX\Parsers\WaypointParser 2 | =============== 3 | 4 | Class WaypointParser 5 | 6 | 7 | 8 | 9 | * Class name: WaypointParser 10 | * Namespace: phpGPX\Parsers 11 | * This is an **abstract** class 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | Methods 20 | ------- 21 | 22 | 23 | ### parse 24 | 25 | array phpGPX\Parsers\WaypointParser::parse(\SimpleXMLElement $nodes) 26 | 27 | 28 | 29 | 30 | 31 | * Visibility: **public** 32 | * This method is **static**. 33 | 34 | 35 | #### Arguments 36 | * $nodes **SimpleXMLElement** - <ul> 37 | <li>a non empty list of wpt elements</li> 38 | </ul> 39 | 40 | 41 | -------------------------------------------------------------------------------- /phpunit.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | tests/ 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | # Problem description 2 | 3 | 1. Library version or last commit you have 4 | 2. PHP version you use 5 | 3. Detailed problem description 6 | 7 | If you think that problem is connected with your file content, please attach it to the issue. 8 | 9 | # Code snippet you use 10 | 11 | ```php 12 | 13 | ``` 14 | 15 | # Expected behaviour 16 | 17 | # Possible solution 18 | 19 | A possible solution if you have any. 20 | 21 | # Something interesting or funny 22 | 23 | Joke or interesting fact to made readers better day :) For example: Ants get drunk and act silly, causing their friend-ants to throw them in puddles of water. 24 | 25 | # Checklist 26 | 27 | Put `x` into brackets if true. 28 | 29 | [ ] PHP version I use 30 | [ ] Package version I use -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: php 2 | 3 | php: 4 | - 7.0 5 | - 7.1 6 | - 7.2 7 | 8 | env: 9 | global: 10 | - CHECK_PHP_SYNTAX="no" 11 | 12 | matrix: 13 | include: 14 | php: 7.2 15 | env: CHECK_PHP_SYNTAX="yes" 16 | 17 | before_install: 18 | - phpenv config-rm xdebug.ini || echo "xdebug not available" 19 | 20 | install: 21 | - if [[ "$CHECK_PHP_SYNTAX" == "yes" ]]; then composer require --dev --no-update friendsofphp/php-cs-fixer:2.19; fi; 22 | - composer update --prefer-dist --no-interaction --no-suggest --no-progress --ansi 23 | 24 | script: 25 | - if [[ "$CHECK_PHP_SYNTAX" == "no" ]]; then ./vendor/bin/phpunit; fi; 26 | - if [[ "$CHECK_PHP_SYNTAX" == "yes" ]]; then ./vendor/bin/php-cs-fixer fix --dry-run --diff --no-interaction -v; fi; 27 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sibyx/phpgpx", 3 | "type": "library", 4 | "version": "1.3.0", 5 | "description": "A simple PHP library for GPX import/export", 6 | "minimum-stability": "stable", 7 | "license": "MIT", 8 | "authors": [ 9 | { 10 | "name": "Jakub Dubec", 11 | "email": "jakub.dubec@gmail.com", 12 | "homepage": "https://jakubdubec.me" 13 | } 14 | ], 15 | "require": { 16 | "php": ">=7.1", 17 | "lib-libxml": "*", 18 | "ext-simplexml": "*", 19 | "ext-dom": "*" 20 | }, 21 | "require-dev": { 22 | "evert/phpdoc-md" : "~0.2.0", 23 | "phpunit/phpunit": "^9", 24 | "friendsofphp/php-cs-fixer": "^2.18" 25 | }, 26 | "autoload": { 27 | "psr-4": { "phpGPX\\": "src/phpGPX/" } 28 | }, 29 | "autoload-dev": { 30 | "psr-4": { "phpGPX\\Tests\\": "tests/" } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /tests/UnitTests/phpGPX/Parsers/SegmentParserTest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 2419 6 | 7 | 8 | 9 | 2418.8833883882 10 | 11 | 12 | 13 | 2419.8999900064 14 | 15 | 16 | 17 | 2422 18 | 19 | 20 | 21 | 2425 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /src/phpGPX/Parsers/WaypointParser.php: -------------------------------------------------------------------------------- 1 | 5 | */ 6 | 7 | namespace phpGPX\Parsers; 8 | 9 | /** 10 | * Class WaypointParser 11 | * @package phpGPX\Parsers 12 | */ 13 | abstract class WaypointParser 14 | { 15 | 16 | /** 17 | * @param \SimpleXMLElement $nodes - a non empty list of wpt elements 18 | * @return array 19 | */ 20 | public static function parse(\SimpleXMLElement $nodes) 21 | { 22 | $points = []; 23 | 24 | // foreach ($nodes->wpt as $item) this was incorrect, the ->wpt was already done in the caller 25 | foreach ($nodes as $item) { 26 | $point = PointParser::parse($item); 27 | 28 | if ($point) { 29 | $points[] = $point; 30 | } 31 | } 32 | 33 | return $points; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /example/waypoints_load.php: -------------------------------------------------------------------------------- 1 | 5 | */ 6 | 7 | use phpGPX\phpGPX; 8 | 9 | require_once '../vendor/autoload.php'; 10 | 11 | $origFile = dirname(__FILE__).'/waypoint_test.gpx'; 12 | $outFile = dirname(__FILE__).'/output_waypoint_test.gpx'; 13 | // $outFile2 = dirname(__FILE__).'/output_waypoint_test2.gpx'; 14 | 15 | $gpx = new phpGPX(); 16 | $file = $gpx->load($origFile); 17 | 18 | phpGPX::$PRETTY_PRINT = true; 19 | $file->save($outFile, phpGPX::XML_FORMAT); 20 | 21 | $retcode = 0; 22 | system("diff $origFile $outFile", $retcode); 23 | // system("diff $origFile $outFile2", $retcode); 24 | 25 | if ($retcode != 0) { 26 | throw new \Exception("wapoint file incorrect"); 27 | } else { 28 | print "wapoint test successfull\n"; 29 | } 30 | -------------------------------------------------------------------------------- /src/phpGPX/Models/Extensions/AbstractExtension.php: -------------------------------------------------------------------------------- 1 | 5 | */ 6 | 7 | namespace phpGPX\Models\Extensions; 8 | 9 | use phpGPX\Models\Summarizable; 10 | 11 | abstract class AbstractExtension implements Summarizable 12 | { 13 | 14 | /** 15 | * XML namespace of extension 16 | * @var string 17 | */ 18 | public $namespace; 19 | 20 | /** 21 | * Node name extension. 22 | * @var string 23 | */ 24 | public $extensionName; 25 | 26 | /** 27 | * AbstractExtension constructor. 28 | * @param string $namespace 29 | * @param string $extensionName 30 | */ 31 | public function __construct($namespace, $extensionName) 32 | { 33 | $this->namespace = $namespace; 34 | $this->extensionName = $extensionName; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /docs/phpGPX-Helpers-GeoHelper.md: -------------------------------------------------------------------------------- 1 | phpGPX\Helpers\GeoHelper 2 | =============== 3 | 4 | Class GeoHelper 5 | Geolocation methods. 6 | 7 | 8 | 9 | 10 | * Class name: GeoHelper 11 | * Namespace: phpGPX\Helpers 12 | * This is an **abstract** class 13 | 14 | 15 | 16 | Constants 17 | ---------- 18 | 19 | 20 | ### EARTH_RADIUS 21 | 22 | const EARTH_RADIUS = 6371000 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | Methods 31 | ------- 32 | 33 | 34 | ### getDistance 35 | 36 | float phpGPX\Helpers\GeoHelper::getDistance(\phpGPX\Models\Point $point1, \phpGPX\Models\Point $point2) 37 | 38 | Returns distance in meters between two Points according to GPX coordinates. 39 | 40 | 41 | 42 | * Visibility: **public** 43 | * This method is **static**. 44 | 45 | 46 | #### Arguments 47 | * $point1 **[phpGPX\Models\Point](phpGPX-Models-Point.md)** 48 | * $point2 **[phpGPX\Models\Point](phpGPX-Models-Point.md)** 49 | 50 | 51 | -------------------------------------------------------------------------------- /src/phpGPX/Models/Email.php: -------------------------------------------------------------------------------- 1 | 5 | */ 6 | 7 | namespace phpGPX\Models; 8 | 9 | /** 10 | * Class Email 11 | * An email address. Broken into two parts (id and domain) to help prevent email harvesting. 12 | * @package phpGPX\Models 13 | */ 14 | class Email implements Summarizable 15 | { 16 | 17 | /** 18 | * Id half of email address (jakub.dubec) 19 | * @var string 20 | */ 21 | public $id; 22 | 23 | /** Domain half of email address (gmail.com) 24 | * @var string 25 | */ 26 | public $domain; 27 | 28 | /** 29 | * Email constructor. 30 | */ 31 | public function __construct() 32 | { 33 | $this->id = null; 34 | $this->domain = null; 35 | } 36 | 37 | 38 | /** 39 | * Serialize object to array 40 | * @return array 41 | */ 42 | public function toArray() 43 | { 44 | return [ 45 | 'id' => (string) $this->id, 46 | 'domain' => (string) $this->domain 47 | ]; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/phpGPX/Models/Extensions.php: -------------------------------------------------------------------------------- 1 | 5 | */ 6 | 7 | namespace phpGPX\Models; 8 | 9 | use phpGPX\Helpers\SerializationHelper; 10 | use phpGPX\Models\Extensions\TrackPointExtension; 11 | 12 | /** 13 | * Class Extensions 14 | * TODO: http://www.garmin.com/xmlschemas/GpxExtensions/v3 15 | * @package phpGPX\Models 16 | */ 17 | class Extensions implements Summarizable 18 | { 19 | /** 20 | * GPX Garmin TrackPointExtension v1 21 | * @see 'http://www.garmin.com/xmlschemas/TrackPointExtension/v1' 22 | * @var TrackPointExtension 23 | */ 24 | public $trackPointExtension; 25 | 26 | /** 27 | * @var [] 28 | */ 29 | public $unsupported = []; 30 | 31 | /** 32 | * Serialize object to array 33 | * @return array 34 | */ 35 | public function toArray() 36 | { 37 | return [ 38 | 'trackpoint' => SerializationHelper::serialize($this->trackPointExtension), 39 | 'unsupported' => $this->unsupported, 40 | ]; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /docs/phpGPX-Models-Extensions.md: -------------------------------------------------------------------------------- 1 | phpGPX\Models\Extensions 2 | =============== 3 | 4 | Class Extensions 5 | TODO: http://www.garmin.com/xmlschemas/GpxExtensions/v3 6 | 7 | 8 | 9 | 10 | * Class name: Extensions 11 | * Namespace: phpGPX\Models 12 | * This class implements: [phpGPX\Models\Summarizable](phpGPX-Models-Summarizable.md) 13 | 14 | 15 | 16 | 17 | Properties 18 | ---------- 19 | 20 | 21 | ### $trackPointExtension 22 | 23 | public \phpGPX\Models\Extensions\TrackPointExtension $trackPointExtension 24 | 25 | GPX Garmin TrackPointExtension v1 26 | 27 | 28 | 29 | * Visibility: **public** 30 | 31 | 32 | Methods 33 | ------- 34 | 35 | 36 | ### __construct 37 | 38 | mixed phpGPX\Models\Extensions::__construct() 39 | 40 | Extensions constructor. 41 | 42 | 43 | 44 | * Visibility: **public** 45 | 46 | 47 | 48 | 49 | ### toArray 50 | 51 | array phpGPX\Models\Summarizable::toArray() 52 | 53 | Serialize object to array 54 | 55 | 56 | 57 | * Visibility: **public** 58 | * This method is defined by [phpGPX\Models\Summarizable](phpGPX-Models-Summarizable.md) 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /example/waypoint_test.gpx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | My pretty awesome GPX file, created using phpGPX library! 5 | 6 | phpGPX Docs 7 | 8 | 9 | 10 | 11 | 0 12 | 13 | 14 | 15 | 10 16 | 17 | 18 | 19 | 42.42 20 | 21 | 22 | 23 | 12 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /example/output_waypoint_test.gpx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | My pretty awesome GPX file, created using phpGPX library! 5 | 6 | phpGPX Docs 7 | 8 | 9 | 10 | 11 | 0 12 | 13 | 14 | 15 | 10 16 | 17 | 18 | 19 | 42.42 20 | 21 | 22 | 23 | 12 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /docs/phpGPX-Parsers-EmailParser.md: -------------------------------------------------------------------------------- 1 | phpGPX\Parsers\EmailParser 2 | =============== 3 | 4 | Class EmailParser 5 | 6 | 7 | 8 | 9 | * Class name: EmailParser 10 | * Namespace: phpGPX\Parsers 11 | * This is an **abstract** class 12 | 13 | 14 | 15 | 16 | 17 | Properties 18 | ---------- 19 | 20 | 21 | ### $tagName 22 | 23 | private mixed $tagName = 'email' 24 | 25 | 26 | 27 | 28 | 29 | * Visibility: **private** 30 | * This property is **static**. 31 | 32 | 33 | Methods 34 | ------- 35 | 36 | 37 | ### parse 38 | 39 | \phpGPX\Models\Email phpGPX\Parsers\EmailParser::parse(\SimpleXMLElement $node) 40 | 41 | 42 | 43 | 44 | 45 | * Visibility: **public** 46 | * This method is **static**. 47 | 48 | 49 | #### Arguments 50 | * $node **SimpleXMLElement** 51 | 52 | 53 | 54 | ### toXML 55 | 56 | \DOMElement phpGPX\Parsers\EmailParser::toXML(\phpGPX\Models\Email $email, \DOMDocument $document) 57 | 58 | 59 | 60 | 61 | 62 | * Visibility: **public** 63 | * This method is **static**. 64 | 65 | 66 | #### Arguments 67 | * $email **[phpGPX\Models\Email](phpGPX-Models-Email.md)** 68 | * $document **DOMDocument** 69 | 70 | 71 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017-2022 Jakub Dubec 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /docs/phpGPX-Parsers-PersonParser.md: -------------------------------------------------------------------------------- 1 | phpGPX\Parsers\PersonParser 2 | =============== 3 | 4 | Class PersonParser 5 | 6 | 7 | 8 | 9 | * Class name: PersonParser 10 | * Namespace: phpGPX\Parsers 11 | * This is an **abstract** class 12 | 13 | 14 | 15 | 16 | 17 | Properties 18 | ---------- 19 | 20 | 21 | ### $tagName 22 | 23 | public mixed $tagName = 'author' 24 | 25 | 26 | 27 | 28 | 29 | * Visibility: **public** 30 | * This property is **static**. 31 | 32 | 33 | Methods 34 | ------- 35 | 36 | 37 | ### parse 38 | 39 | \phpGPX\Models\Person phpGPX\Parsers\PersonParser::parse(\SimpleXMLElement $node) 40 | 41 | 42 | 43 | 44 | 45 | * Visibility: **public** 46 | * This method is **static**. 47 | 48 | 49 | #### Arguments 50 | * $node **SimpleXMLElement** 51 | 52 | 53 | 54 | ### toXML 55 | 56 | mixed phpGPX\Parsers\PersonParser::toXML(\phpGPX\Models\Person $person, \DOMDocument $document) 57 | 58 | 59 | 60 | 61 | 62 | * Visibility: **public** 63 | * This method is **static**. 64 | 65 | 66 | #### Arguments 67 | * $person **[phpGPX\Models\Person](phpGPX-Models-Person.md)** 68 | * $document **DOMDocument** 69 | 70 | 71 | -------------------------------------------------------------------------------- /docs/phpGPX-Parsers-CopyrightParser.md: -------------------------------------------------------------------------------- 1 | phpGPX\Parsers\CopyrightParser 2 | =============== 3 | 4 | Class CopyrightParser 5 | 6 | 7 | 8 | 9 | * Class name: CopyrightParser 10 | * Namespace: phpGPX\Parsers 11 | * This is an **abstract** class 12 | 13 | 14 | 15 | 16 | 17 | Properties 18 | ---------- 19 | 20 | 21 | ### $tagName 22 | 23 | public mixed $tagName = 'copyright' 24 | 25 | 26 | 27 | 28 | 29 | * Visibility: **public** 30 | * This property is **static**. 31 | 32 | 33 | Methods 34 | ------- 35 | 36 | 37 | ### parse 38 | 39 | \phpGPX\Models\Copyright|null phpGPX\Parsers\CopyrightParser::parse(\SimpleXMLElement $node) 40 | 41 | 42 | 43 | 44 | 45 | * Visibility: **public** 46 | * This method is **static**. 47 | 48 | 49 | #### Arguments 50 | * $node **SimpleXMLElement** 51 | 52 | 53 | 54 | ### toXML 55 | 56 | \DOMElement phpGPX\Parsers\CopyrightParser::toXML(\phpGPX\Models\Copyright $copyright, \DOMDocument $document) 57 | 58 | 59 | 60 | 61 | 62 | * Visibility: **public** 63 | * This method is **static**. 64 | 65 | 66 | #### Arguments 67 | * $copyright **[phpGPX\Models\Copyright](phpGPX-Models-Copyright.md)** 68 | * $document **DOMDocument** 69 | 70 | 71 | -------------------------------------------------------------------------------- /docs/phpGPX-Models-Email.md: -------------------------------------------------------------------------------- 1 | phpGPX\Models\Email 2 | =============== 3 | 4 | Class Email 5 | An email address. Broken into two parts (id and domain) to help prevent email harvesting. 6 | 7 | 8 | 9 | 10 | * Class name: Email 11 | * Namespace: phpGPX\Models 12 | * This class implements: [phpGPX\Models\Summarizable](phpGPX-Models-Summarizable.md) 13 | 14 | 15 | 16 | 17 | Properties 18 | ---------- 19 | 20 | 21 | ### $id 22 | 23 | public string $id 24 | 25 | Id half of email address (jakub.dubec) 26 | 27 | 28 | 29 | * Visibility: **public** 30 | 31 | 32 | ### $domain 33 | 34 | public string $domain 35 | 36 | Domain half of email address (gmail.com) 37 | 38 | 39 | 40 | * Visibility: **public** 41 | 42 | 43 | Methods 44 | ------- 45 | 46 | 47 | ### __construct 48 | 49 | mixed phpGPX\Models\Email::__construct() 50 | 51 | Email constructor. 52 | 53 | 54 | 55 | * Visibility: **public** 56 | 57 | 58 | 59 | 60 | ### toArray 61 | 62 | array phpGPX\Models\Summarizable::toArray() 63 | 64 | Serialize object to array 65 | 66 | 67 | 68 | * Visibility: **public** 69 | * This method is defined by [phpGPX\Models\Summarizable](phpGPX-Models-Summarizable.md) 70 | 71 | 72 | 73 | -------------------------------------------------------------------------------- /docs/phpGPX-Parsers-BoundsParser.md: -------------------------------------------------------------------------------- 1 | phpGPX\Parsers\BoundsParser 2 | =============== 3 | 4 | Class BoundsParser 5 | 6 | 7 | 8 | 9 | * Class name: BoundsParser 10 | * Namespace: phpGPX\Parsers 11 | * This is an **abstract** class 12 | 13 | 14 | 15 | 16 | 17 | Properties 18 | ---------- 19 | 20 | 21 | ### $tagName 22 | 23 | private mixed $tagName = 'bounds' 24 | 25 | 26 | 27 | 28 | 29 | * Visibility: **private** 30 | * This property is **static**. 31 | 32 | 33 | Methods 34 | ------- 35 | 36 | 37 | ### parse 38 | 39 | \phpGPX\Models\Bounds|null phpGPX\Parsers\BoundsParser::parse(\SimpleXMLElement $node) 40 | 41 | Parse data from XML. 42 | 43 | 44 | 45 | * Visibility: **public** 46 | * This method is **static**. 47 | 48 | 49 | #### Arguments 50 | * $node **SimpleXMLElement** 51 | 52 | 53 | 54 | ### toXML 55 | 56 | \DOMElement phpGPX\Parsers\BoundsParser::toXML(\phpGPX\Models\Bounds $bounds, \DOMDocument $document) 57 | 58 | Create XML representation. 59 | 60 | 61 | 62 | * Visibility: **public** 63 | * This method is **static**. 64 | 65 | 66 | #### Arguments 67 | * $bounds **[phpGPX\Models\Bounds](phpGPX-Models-Bounds.md)** 68 | * $document **DOMDocument** 69 | 70 | 71 | -------------------------------------------------------------------------------- /src/phpGPX/Models/Link.php: -------------------------------------------------------------------------------- 1 | 5 | */ 6 | 7 | namespace phpGPX\Models; 8 | 9 | /** 10 | * Class Link according to GPX 1.1 specification. 11 | * A link to an external resource (Web page, digital photo, video clip, etc) with additional information. 12 | * @see http://www.topografix.com/GPX/1/1/#type_linkType 13 | * @package phpGPX\Models 14 | */ 15 | class Link implements Summarizable 16 | { 17 | 18 | /** 19 | * URL of hyperlink. 20 | * @var string 21 | */ 22 | public $href; 23 | 24 | /** 25 | * Text of hyperlink. 26 | * @var string|null 27 | */ 28 | public $text; 29 | 30 | /** 31 | * Mime type of content (image/jpeg) 32 | * @var string|null 33 | */ 34 | public $type; 35 | 36 | /** 37 | * Link constructor. 38 | */ 39 | public function __construct() 40 | { 41 | $this->href = null; 42 | $this->text = null; 43 | $this->type = null; 44 | } 45 | 46 | 47 | /** 48 | * Serialize object to array 49 | * @return array 50 | */ 51 | public function toArray() 52 | { 53 | return [ 54 | 'href' => (string) $this->href, 55 | 'text' => $this->text, 56 | 'type' => $this->type 57 | ]; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/phpGPX/Parsers/EmailParser.php: -------------------------------------------------------------------------------- 1 | 5 | */ 6 | 7 | namespace phpGPX\Parsers; 8 | 9 | use phpGPX\Models\Email; 10 | 11 | /** 12 | * Class EmailParser 13 | * @package phpGPX\Parsers 14 | */ 15 | abstract class EmailParser 16 | { 17 | private static $tagName = 'email'; 18 | 19 | /** 20 | * @param \SimpleXMLElement $node 21 | * @return Email 22 | */ 23 | public static function parse(\SimpleXMLElement $node) 24 | { 25 | $email = new Email(); 26 | 27 | $email->id = isset($node['id']) ? (string) $node['id'] : null; 28 | $email->domain = isset($node['domain']) ? (string) $node['domain'] : null; 29 | 30 | return $email; 31 | } 32 | 33 | 34 | /** 35 | * @param Email $email 36 | * @param \DOMDocument $document 37 | * @return \DOMElement 38 | */ 39 | public static function toXML(Email $email, \DOMDocument &$document) 40 | { 41 | $node = $document->createElement(self::$tagName); 42 | 43 | if (!empty($email->id)) { 44 | $node->setAttribute('id', $email->id); 45 | } 46 | 47 | if (!empty($email->domain)) { 48 | $node->setAttribute('domain', $email->domain); 49 | } 50 | 51 | return $node; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /docs/phpGPX-Models-Link.md: -------------------------------------------------------------------------------- 1 | phpGPX\Models\Link 2 | =============== 3 | 4 | Class Link according to GPX 1.1 specification. 5 | 6 | A link to an external resource (Web page, digital photo, video clip, etc) with additional information. 7 | 8 | 9 | * Class name: Link 10 | * Namespace: phpGPX\Models 11 | * This class implements: [phpGPX\Models\Summarizable](phpGPX-Models-Summarizable.md) 12 | 13 | 14 | 15 | 16 | Properties 17 | ---------- 18 | 19 | 20 | ### $href 21 | 22 | public string $href 23 | 24 | URL of hyperlink. 25 | 26 | 27 | 28 | * Visibility: **public** 29 | 30 | 31 | ### $text 32 | 33 | public string $text 34 | 35 | Text of hyperlink. 36 | 37 | 38 | 39 | * Visibility: **public** 40 | 41 | 42 | ### $type 43 | 44 | public string $type 45 | 46 | Mime type of content (image/jpeg) 47 | 48 | 49 | 50 | * Visibility: **public** 51 | 52 | 53 | Methods 54 | ------- 55 | 56 | 57 | ### __construct 58 | 59 | mixed phpGPX\Models\Link::__construct() 60 | 61 | Link constructor. 62 | 63 | 64 | 65 | * Visibility: **public** 66 | 67 | 68 | 69 | 70 | ### toArray 71 | 72 | array phpGPX\Models\Summarizable::toArray() 73 | 74 | Serialize object to array 75 | 76 | 77 | 78 | * Visibility: **public** 79 | * This method is defined by [phpGPX\Models\Summarizable](phpGPX-Models-Summarizable.md) 80 | 81 | 82 | 83 | -------------------------------------------------------------------------------- /docs/phpGPX-Models-Extensions-AbstractExtension.md: -------------------------------------------------------------------------------- 1 | phpGPX\Models\Extensions\AbstractExtension 2 | =============== 3 | 4 | 5 | 6 | 7 | 8 | 9 | * Class name: AbstractExtension 10 | * Namespace: phpGPX\Models\Extensions 11 | * This is an **abstract** class 12 | * This class implements: [phpGPX\Models\Summarizable](phpGPX-Models-Summarizable.md) 13 | 14 | 15 | 16 | 17 | Properties 18 | ---------- 19 | 20 | 21 | ### $namespace 22 | 23 | public string $namespace 24 | 25 | XML namespace of extension 26 | 27 | 28 | 29 | * Visibility: **public** 30 | 31 | 32 | ### $extensionName 33 | 34 | public string $extensionName 35 | 36 | Node name extension. 37 | 38 | 39 | 40 | * Visibility: **public** 41 | 42 | 43 | Methods 44 | ------- 45 | 46 | 47 | ### __construct 48 | 49 | mixed phpGPX\Models\Extensions\AbstractExtension::__construct(string $namespace, string $extensionName) 50 | 51 | AbstractExtension constructor. 52 | 53 | 54 | 55 | * Visibility: **public** 56 | 57 | 58 | #### Arguments 59 | * $namespace **string** 60 | * $extensionName **string** 61 | 62 | 63 | 64 | ### toArray 65 | 66 | array phpGPX\Models\Summarizable::toArray() 67 | 68 | Serialize object to array 69 | 70 | 71 | 72 | * Visibility: **public** 73 | * This method is defined by [phpGPX\Models\Summarizable](phpGPX-Models-Summarizable.md) 74 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /src/phpGPX/Models/Person.php: -------------------------------------------------------------------------------- 1 | 5 | */ 6 | 7 | namespace phpGPX\Models; 8 | 9 | use phpGPX\Helpers\SerializationHelper; 10 | 11 | /** 12 | * Class Person 13 | * A person or organisation 14 | * @package phpGPX\Models 15 | */ 16 | class Person implements Summarizable 17 | { 18 | 19 | /** 20 | * Name of person or organization. 21 | * An original GPX 1.1 attribute. 22 | * @var string 23 | */ 24 | public $name; 25 | 26 | /** 27 | * E-mail address. 28 | * An original GPX 1.1 attribute. 29 | * @var Email|null 30 | */ 31 | public $email; 32 | 33 | /** 34 | * Link to Web site or other external information about person. 35 | * An original GPX 1.1 attribute. 36 | * @var Link[] 37 | */ 38 | public $links; 39 | 40 | /** 41 | * Person constructor. 42 | */ 43 | public function __construct() 44 | { 45 | $this->name = null; 46 | $this->email = null; 47 | $this->links = null; 48 | } 49 | 50 | 51 | /** 52 | * Serialize object to array 53 | * @return array 54 | */ 55 | public function toArray() 56 | { 57 | return [ 58 | 'name' => (string) $this->name, 59 | 'email' => SerializationHelper::serialize($this->email), 60 | 'links' => SerializationHelper::serialize($this->links) 61 | ]; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /docs/phpGPX-Helpers-DateTimeHelper.md: -------------------------------------------------------------------------------- 1 | phpGPX\Helpers\DateTimeHelper 2 | =============== 3 | 4 | Class DateTimeHelper 5 | 6 | 7 | 8 | 9 | * Class name: DateTimeHelper 10 | * Namespace: phpGPX\Helpers 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | Methods 19 | ------- 20 | 21 | 22 | ### comparePointsByTimestamp 23 | 24 | boolean|integer phpGPX\Helpers\DateTimeHelper::comparePointsByTimestamp(\phpGPX\Models\Point $point1, \phpGPX\Models\Point $point2) 25 | 26 | 27 | 28 | 29 | 30 | * Visibility: **public** 31 | * This method is **static**. 32 | 33 | 34 | #### Arguments 35 | * $point1 **[phpGPX\Models\Point](phpGPX-Models-Point.md)** 36 | * $point2 **[phpGPX\Models\Point](phpGPX-Models-Point.md)** 37 | 38 | 39 | 40 | ### formatDateTime 41 | 42 | null|string phpGPX\Helpers\DateTimeHelper::formatDateTime($datetime, string $format, string $timezone) 43 | 44 | 45 | 46 | 47 | 48 | * Visibility: **public** 49 | * This method is **static**. 50 | 51 | 52 | #### Arguments 53 | * $datetime **mixed** 54 | * $format **string** 55 | * $timezone **string** 56 | 57 | 58 | 59 | ### parseDateTime 60 | 61 | \DateTime phpGPX\Helpers\DateTimeHelper::parseDateTime($value, string $timezone) 62 | 63 | 64 | 65 | 66 | 67 | * Visibility: **public** 68 | * This method is **static**. 69 | 70 | 71 | #### Arguments 72 | * $value **mixed** 73 | * $timezone **string** 74 | 75 | 76 | -------------------------------------------------------------------------------- /docs/phpGPX-Parsers-ExtensionParser.md: -------------------------------------------------------------------------------- 1 | phpGPX\Parsers\ExtensionParser 2 | =============== 3 | 4 | Class ExtensionParser 5 | 6 | 7 | 8 | 9 | * Class name: ExtensionParser 10 | * Namespace: phpGPX\Parsers 11 | * This is an **abstract** class 12 | 13 | 14 | 15 | 16 | 17 | Properties 18 | ---------- 19 | 20 | 21 | ### $tagName 22 | 23 | public mixed $tagName = 'extensions' 24 | 25 | 26 | 27 | 28 | 29 | * Visibility: **public** 30 | * This property is **static**. 31 | 32 | 33 | ### $usedNamespaces 34 | 35 | public mixed $usedNamespaces = array() 36 | 37 | 38 | 39 | 40 | 41 | * Visibility: **public** 42 | * This property is **static**. 43 | 44 | 45 | Methods 46 | ------- 47 | 48 | 49 | ### parse 50 | 51 | \phpGPX\Models\Extensions phpGPX\Parsers\ExtensionParser::parse(\SimpleXMLElement $nodes) 52 | 53 | 54 | 55 | 56 | 57 | * Visibility: **public** 58 | * This method is **static**. 59 | 60 | 61 | #### Arguments 62 | * $nodes **SimpleXMLElement** 63 | 64 | 65 | 66 | ### toXML 67 | 68 | \DOMElement|null phpGPX\Parsers\ExtensionParser::toXML(\phpGPX\Models\Extensions $extensions, \DOMDocument $document) 69 | 70 | 71 | 72 | 73 | 74 | * Visibility: **public** 75 | * This method is **static**. 76 | 77 | 78 | #### Arguments 79 | * $extensions **[phpGPX\Models\Extensions](phpGPX-Models-Extensions.md)** 80 | * $document **DOMDocument** 81 | 82 | 83 | -------------------------------------------------------------------------------- /tests/fixtures/route.gpx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Test file by Patrick 5 | 6 | 7 | Patrick's Route 8 | 9 | 0.0 10 | Position 1 11 | 12 | 13 | 1.0 14 | Position 2 15 | 16 | 17 | 2.0 18 | Position 3 19 | 20 | 21 | 3.0 22 | Position 4 23 | 24 | 25 | 26 | Sibyx's Route 27 | 28 | 0.0 29 | Position 4 30 | 31 | 32 | 1.0 33 | Position 3 34 | 35 | 36 | 2.0 37 | Position 2 38 | 39 | 40 | 3.0 41 | Position 1 42 | 43 | 44 | -------------------------------------------------------------------------------- /docs/phpGPX-Models-Person.md: -------------------------------------------------------------------------------- 1 | phpGPX\Models\Person 2 | =============== 3 | 4 | Class Person 5 | A person or organisation 6 | 7 | 8 | 9 | 10 | * Class name: Person 11 | * Namespace: phpGPX\Models 12 | * This class implements: [phpGPX\Models\Summarizable](phpGPX-Models-Summarizable.md) 13 | 14 | 15 | 16 | 17 | Properties 18 | ---------- 19 | 20 | 21 | ### $name 22 | 23 | public string $name 24 | 25 | Name of person or organization. 26 | 27 | An original GPX 1.1 attribute. 28 | 29 | * Visibility: **public** 30 | 31 | 32 | ### $email 33 | 34 | public \phpGPX\Models\Email $email 35 | 36 | E-mail address. 37 | 38 | An original GPX 1.1 attribute. 39 | 40 | * Visibility: **public** 41 | 42 | 43 | ### $link 44 | 45 | public \phpGPX\Models\Link $link 46 | 47 | Link to Web site or other external information about person. 48 | 49 | An original GPX 1.1 attribute. 50 | 51 | * Visibility: **public** 52 | 53 | 54 | Methods 55 | ------- 56 | 57 | 58 | ### __construct 59 | 60 | mixed phpGPX\Models\Person::__construct() 61 | 62 | Person constructor. 63 | 64 | 65 | 66 | * Visibility: **public** 67 | 68 | 69 | 70 | 71 | ### toArray 72 | 73 | array phpGPX\Models\Summarizable::toArray() 74 | 75 | Serialize object to array 76 | 77 | 78 | 79 | * Visibility: **public** 80 | * This method is defined by [phpGPX\Models\Summarizable](phpGPX-Models-Summarizable.md) 81 | 82 | 83 | 84 | -------------------------------------------------------------------------------- /docs/phpGPX-Models-Bounds.md: -------------------------------------------------------------------------------- 1 | phpGPX\Models\Bounds 2 | =============== 3 | 4 | 5 | 6 | 7 | 8 | 9 | * Class name: Bounds 10 | * Namespace: phpGPX\Models 11 | * This class implements: [phpGPX\Models\Summarizable](phpGPX-Models-Summarizable.md) 12 | 13 | 14 | 15 | 16 | Properties 17 | ---------- 18 | 19 | 20 | ### $minLatitude 21 | 22 | public float $minLatitude 23 | 24 | Minimal latitude in file. 25 | 26 | 27 | 28 | * Visibility: **public** 29 | 30 | 31 | ### $minLongitude 32 | 33 | public float $minLongitude 34 | 35 | Minimal longitude in file. 36 | 37 | 38 | 39 | * Visibility: **public** 40 | 41 | 42 | ### $maxLatitude 43 | 44 | public float $maxLatitude 45 | 46 | Maximal latitude in file. 47 | 48 | 49 | 50 | * Visibility: **public** 51 | 52 | 53 | ### $maxLongitude 54 | 55 | public float $maxLongitude 56 | 57 | Maximal longitude in file. 58 | 59 | 60 | 61 | * Visibility: **public** 62 | 63 | 64 | Methods 65 | ------- 66 | 67 | 68 | ### __construct 69 | 70 | mixed phpGPX\Models\Bounds::__construct() 71 | 72 | Bounds constructor. 73 | 74 | 75 | 76 | * Visibility: **public** 77 | 78 | 79 | 80 | 81 | ### toArray 82 | 83 | array phpGPX\Models\Summarizable::toArray() 84 | 85 | Serialize object to array 86 | 87 | 88 | 89 | * Visibility: **public** 90 | * This method is defined by [phpGPX\Models\Summarizable](phpGPX-Models-Summarizable.md) 91 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /src/phpGPX/Models/Copyright.php: -------------------------------------------------------------------------------- 1 | 5 | */ 6 | 7 | namespace phpGPX\Models; 8 | 9 | use phpGPX\Helpers\SerializationHelper; 10 | 11 | /** 12 | * Class Copyright 13 | * Information about the copyright holder and any license governing use of this file. 14 | * By linking to an appropriate license, you may place your data into the public domain or grant additional usage rights. 15 | * @package phpGPX\Models 16 | */ 17 | class Copyright implements Summarizable 18 | { 19 | 20 | /** 21 | * Copyright holder (TopoSoft, Inc.) 22 | * @var string 23 | */ 24 | public $author; 25 | 26 | /** 27 | * Year of copyright. 28 | * @var string 29 | */ 30 | public $year; 31 | 32 | /** 33 | * Link to external file containing license text. 34 | * @var string 35 | */ 36 | public $license; 37 | 38 | /** 39 | * Copyright constructor. 40 | */ 41 | public function __construct() 42 | { 43 | $this->author = null; 44 | $this->year = null; 45 | $this->license = null; 46 | } 47 | 48 | 49 | /** 50 | * Serialize object to array 51 | * @return array 52 | */ 53 | public function toArray() 54 | { 55 | return [ 56 | 'author' => $this->author, 57 | 'year' => SerializationHelper::stringOrNull($this->year), 58 | 'license' => SerializationHelper::stringOrNull($this->license) 59 | ]; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /docs/phpGPX-Models-Copyright.md: -------------------------------------------------------------------------------- 1 | phpGPX\Models\Copyright 2 | =============== 3 | 4 | Class Copyright 5 | Information about the copyright holder and any license governing use of this file. 6 | 7 | By linking to an appropriate license, you may place your data into the public domain or grant additional usage rights. 8 | 9 | 10 | * Class name: Copyright 11 | * Namespace: phpGPX\Models 12 | * This class implements: [phpGPX\Models\Summarizable](phpGPX-Models-Summarizable.md) 13 | 14 | 15 | 16 | 17 | Properties 18 | ---------- 19 | 20 | 21 | ### $author 22 | 23 | public string $author 24 | 25 | Copyright holder (TopoSoft, Inc.) 26 | 27 | 28 | 29 | * Visibility: **public** 30 | 31 | 32 | ### $year 33 | 34 | public string $year 35 | 36 | Year of copyright. 37 | 38 | 39 | 40 | * Visibility: **public** 41 | 42 | 43 | ### $license 44 | 45 | public string $license 46 | 47 | Link to external file containing license text. 48 | 49 | 50 | 51 | * Visibility: **public** 52 | 53 | 54 | Methods 55 | ------- 56 | 57 | 58 | ### __construct 59 | 60 | mixed phpGPX\Models\Copyright::__construct() 61 | 62 | Copyright constructor. 63 | 64 | 65 | 66 | * Visibility: **public** 67 | 68 | 69 | 70 | 71 | ### toArray 72 | 73 | array phpGPX\Models\Summarizable::toArray() 74 | 75 | Serialize object to array 76 | 77 | 78 | 79 | * Visibility: **public** 80 | * This method is defined by [phpGPX\Models\Summarizable](phpGPX-Models-Summarizable.md) 81 | 82 | 83 | 84 | -------------------------------------------------------------------------------- /tests/fixtures/gps-track.gpx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | GPS-Track 5 | 6 | 7 | 2419 8 | 9 | 10 | 11 | 2418.8833883882 12 | 13 | 14 | 15 | 2419.8999900064 16 | 17 | 18 | 19 | 2422 20 | 21 | 22 | 23 | 2425 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /src/phpGPX/Models/Bounds.php: -------------------------------------------------------------------------------- 1 | 5 | */ 6 | 7 | namespace phpGPX\Models; 8 | 9 | class Bounds implements Summarizable 10 | { 11 | 12 | /** 13 | * Minimal latitude in file. 14 | * @var float 15 | */ 16 | public $minLatitude; 17 | 18 | /** 19 | * Minimal longitude in file. 20 | * @var float 21 | */ 22 | public $minLongitude; 23 | 24 | /** 25 | * Maximal latitude in file. 26 | * @var float 27 | */ 28 | public $maxLatitude; 29 | 30 | /** 31 | * Maximal longitude in file. 32 | * @var float 33 | */ 34 | public $maxLongitude; 35 | 36 | /** 37 | * @param ?float $minLatitude 38 | * @param ?float $minLongitude 39 | * @param ?float $maxLatitude 40 | * @param ?float $maxLongitude 41 | */ 42 | public function __construct(?float $minLatitude, ?float $minLongitude, ?float $maxLatitude, ?float $maxLongitude) 43 | { 44 | $this->minLatitude = $minLatitude; 45 | $this->minLongitude = $minLongitude; 46 | $this->maxLatitude = $maxLatitude; 47 | $this->maxLongitude = $maxLongitude; 48 | } 49 | 50 | 51 | /** 52 | * Serialize object to array 53 | * @return array 54 | */ 55 | public function toArray(): array 56 | { 57 | return [ 58 | 'minlat' => $this->minLatitude, 59 | 'minlon' => $this->minLongitude, 60 | 'maxlat' => $this->maxLatitude, 61 | 'maxlon' => $this->maxLongitude 62 | ]; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /docs/phpGPX-Parsers-SegmentParser.md: -------------------------------------------------------------------------------- 1 | phpGPX\Parsers\SegmentParser 2 | =============== 3 | 4 | Class SegmentParser 5 | 6 | 7 | 8 | 9 | * Class name: SegmentParser 10 | * Namespace: phpGPX\Parsers 11 | * This is an **abstract** class 12 | 13 | 14 | 15 | 16 | 17 | Properties 18 | ---------- 19 | 20 | 21 | ### $tagName 22 | 23 | public mixed $tagName = 'trkseg' 24 | 25 | 26 | 27 | 28 | 29 | * Visibility: **public** 30 | * This property is **static**. 31 | 32 | 33 | Methods 34 | ------- 35 | 36 | 37 | ### parse 38 | 39 | array phpGPX\Parsers\SegmentParser::parse($nodes) 40 | 41 | 42 | 43 | 44 | 45 | * Visibility: **public** 46 | * This method is **static**. 47 | 48 | 49 | #### Arguments 50 | * $nodes **mixed** - <p>\SimpleXMLElement[]</p> 51 | 52 | 53 | 54 | ### toXML 55 | 56 | \DOMElement phpGPX\Parsers\SegmentParser::toXML(\phpGPX\Models\Segment $segment, \DOMDocument $document) 57 | 58 | 59 | 60 | 61 | 62 | * Visibility: **public** 63 | * This method is **static**. 64 | 65 | 66 | #### Arguments 67 | * $segment **[phpGPX\Models\Segment](phpGPX-Models-Segment.md)** 68 | * $document **DOMDocument** 69 | 70 | 71 | 72 | ### toXMLArray 73 | 74 | array phpGPX\Parsers\SegmentParser::toXMLArray(array $segments, \DOMDocument $document) 75 | 76 | 77 | 78 | 79 | 80 | * Visibility: **public** 81 | * This method is **static**. 82 | 83 | 84 | #### Arguments 85 | * $segments **array** 86 | * $document **DOMDocument** 87 | 88 | 89 | -------------------------------------------------------------------------------- /docs/phpGPX-Parsers-LinkParser.md: -------------------------------------------------------------------------------- 1 | phpGPX\Parsers\LinkParser 2 | =============== 3 | 4 | 5 | 6 | 7 | 8 | 9 | * Class name: LinkParser 10 | * Namespace: phpGPX\Parsers 11 | * This is an **abstract** class 12 | 13 | 14 | 15 | 16 | 17 | Properties 18 | ---------- 19 | 20 | 21 | ### $tagName 22 | 23 | private mixed $tagName = 'link' 24 | 25 | 26 | 27 | 28 | 29 | * Visibility: **private** 30 | * This property is **static**. 31 | 32 | 33 | Methods 34 | ------- 35 | 36 | 37 | ### parse 38 | 39 | array phpGPX\Parsers\LinkParser::parse(array $nodes) 40 | 41 | 42 | 43 | 44 | 45 | * Visibility: **public** 46 | * This method is **static**. 47 | 48 | 49 | #### Arguments 50 | * $nodes **array<mixed,\SimpleXMLElement>** 51 | 52 | 53 | 54 | ### toXMLArray 55 | 56 | array phpGPX\Parsers\LinkParser::toXMLArray(array $links, \DOMDocument $document) 57 | 58 | 59 | 60 | 61 | 62 | * Visibility: **public** 63 | * This method is **static**. 64 | 65 | 66 | #### Arguments 67 | * $links **array<mixed,\phpGPX\Models\Link>** 68 | * $document **DOMDocument** 69 | 70 | 71 | 72 | ### toXML 73 | 74 | \DOMElement phpGPX\Parsers\LinkParser::toXML(\phpGPX\Models\Link $link, \DOMDocument $document) 75 | 76 | 77 | 78 | 79 | 80 | * Visibility: **public** 81 | * This method is **static**. 82 | 83 | 84 | #### Arguments 85 | * $link **[phpGPX\Models\Link](phpGPX-Models-Link.md)** 86 | * $document **DOMDocument** 87 | 88 | 89 | -------------------------------------------------------------------------------- /src/phpGPX/Helpers/BoundsCalculator.php: -------------------------------------------------------------------------------- 1 | longitude; 38 | $lat = $curPoint->latitude; 39 | 40 | // Update northWest and southEast points if needed 41 | if ($lat > $north) {$north = $lat;} 42 | if ($lng > $east) {$east = $lng;} 43 | if ($lat < $south) {$south = $lat;} 44 | if ($lng < $west) {$west = $lng;} 45 | } 46 | 47 | return [ 48 | ["lat" => $north, "lng" => $west], 49 | ["lat" => $south, "lng" => $east] 50 | ]; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/phpGPX/Helpers/DateTimeHelper.php: -------------------------------------------------------------------------------- 1 | 5 | */ 6 | 7 | namespace phpGPX\Helpers; 8 | 9 | use phpGPX\Models\Point; 10 | 11 | /** 12 | * Class DateTimeHelper 13 | * @package phpGPX\Helpers 14 | */ 15 | class DateTimeHelper 16 | { 17 | 18 | /** 19 | * @param Point $point1 20 | * @param Point $point2 21 | * @return bool|int 22 | */ 23 | public static function comparePointsByTimestamp(Point $point1, Point $point2) 24 | { 25 | if ($point1->time == $point2->time) { 26 | return 0; 27 | } 28 | return $point1->time > $point2->time; 29 | } 30 | 31 | /** 32 | * @param $datetime 33 | * @param string $format 34 | * @param string $timezone 35 | * @return null|string 36 | */ 37 | public static function formatDateTime($datetime, $format = 'c', $timezone = 'UTC') 38 | { 39 | $formatted = null; 40 | 41 | if ($datetime instanceof \DateTime) { 42 | $datetime->setTimezone(new \DateTimeZone($timezone)); 43 | $formatted = $datetime->format($format); 44 | } 45 | 46 | return $formatted; 47 | } 48 | 49 | /** 50 | * @param $value 51 | * @param string $timezone 52 | * @return \DateTime 53 | */ 54 | public static function parseDateTime($value, $timezone = 'Europe/London') 55 | { 56 | $timezone = new \DateTimeZone($timezone); 57 | $datetime = new \DateTime($value, $timezone); 58 | $datetime->setTimezone(new \DateTimeZone(date_default_timezone_get())); 59 | 60 | return $datetime; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /tests/UnitTests/phpGPX/Parsers/BoundsParserTest.php: -------------------------------------------------------------------------------- 1 | 4 | */ 5 | 6 | namespace UnitTests\phpGPX\Parsers; 7 | 8 | use phpGPX\Models\Bounds; 9 | use phpGPX\Parsers\BoundsParser; 10 | 11 | class BoundsParserTest extends AbstractParserTest 12 | { 13 | protected $testModelClass = Bounds::class; 14 | protected $testParserClass = BoundsParser::class; 15 | 16 | /** 17 | * @var Bounds 18 | */ 19 | protected $testModelInstance; 20 | 21 | public static function createTestInstance() 22 | { 23 | return new Bounds(49.072489, 18.814543, 49.090543, 18.886939); 24 | } 25 | 26 | protected function setUp(): void 27 | { 28 | parent::setUp(); 29 | 30 | $this->testModelInstance = self::createTestInstance(); 31 | } 32 | 33 | public function testParse() 34 | { 35 | $bounds = BoundsParser::parse($this->testXmlFile->bounds); 36 | 37 | $this->assertNotEmpty($bounds); 38 | 39 | $this->assertEquals($this->testModelInstance->maxLatitude, $bounds->maxLatitude); 40 | $this->assertEquals($this->testModelInstance->maxLongitude, $bounds->maxLongitude); 41 | $this->assertEquals($this->testModelInstance->minLatitude, $bounds->minLatitude); 42 | $this->assertEquals($this->testModelInstance->minLongitude, $bounds->minLongitude); 43 | 44 | $this->assertEquals($this->testModelInstance->toArray(), $bounds->toArray()); 45 | } 46 | 47 | protected function convertToXML(\DOMDocument $document) 48 | { 49 | return BoundsParser::toXML($this->testModelInstance, $document); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/phpGPX/Parsers/PersonParser.php: -------------------------------------------------------------------------------- 1 | 5 | */ 6 | 7 | namespace phpGPX\Parsers; 8 | 9 | use phpGPX\Models\Person; 10 | 11 | /** 12 | * Class PersonParser 13 | * @package phpGPX\Parsers 14 | */ 15 | abstract class PersonParser 16 | { 17 | public static $tagName = 'author'; 18 | 19 | /** 20 | * @param \SimpleXMLElement $node 21 | * @return Person 22 | */ 23 | public static function parse(\SimpleXMLElement $node) 24 | { 25 | $person = new Person(); 26 | 27 | $person->name = isset($node->name) ? ((string) $node->name) : null; 28 | $person->email = isset($node->email) ? EmailParser::parse($node->email) : null; 29 | $person->links = isset($node->link) ? LinkParser::parse($node->link) : null; 30 | 31 | return $person; 32 | } 33 | 34 | public static function toXML(Person $person, \DOMDocument &$document) 35 | { 36 | $node = $document->createElement(self::$tagName); 37 | 38 | if (!empty($person->name)) { 39 | $child = $document->createElement('name', $person->name); 40 | $node->appendChild($child); 41 | } 42 | 43 | if (!empty($person->email)) { 44 | $child = EmailParser::toXML($person->email, $document); 45 | $node->appendChild($child); 46 | } 47 | 48 | # TODO: is_iterable 49 | if (!is_null($person->links)) { 50 | foreach ($person->links as $link) { 51 | $child = LinkParser::toXML($link, $document); 52 | $node->appendChild($child); 53 | } 54 | } 55 | 56 | return $node; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /tests/UnitTests/phpGPX/Parsers/EmailParserTest.php: -------------------------------------------------------------------------------- 1 | 4 | */ 5 | 6 | namespace UnitTests\phpGPX\Parsers; 7 | 8 | use phpGPX\Models\Email; 9 | use phpGPX\Parsers\EmailParser; 10 | 11 | class EmailParserTest extends AbstractParserTest 12 | { 13 | protected $testModelClass = Email::class; 14 | protected $testParserClass = EmailParser::class; 15 | 16 | /** 17 | * @var Email 18 | */ 19 | protected $testModelInstance; 20 | 21 | public static function createTestInstance() 22 | { 23 | $email = new Email(); 24 | 25 | $email->id = "jakub.dubec"; 26 | $email->domain = "gmail.com"; 27 | 28 | return $email; 29 | } 30 | 31 | protected function setUp(): void 32 | { 33 | parent::setUp(); 34 | 35 | $this->testModelInstance = self::createTestInstance(); 36 | } 37 | 38 | 39 | public function testParse() 40 | { 41 | $email = EmailParser::parse($this->testXmlFile->email); 42 | 43 | $this->assertNotEmpty($email); 44 | 45 | $this->assertEquals($this->testModelInstance->id, $email->id); 46 | $this->assertEquals($this->testModelInstance->domain, $email->domain); 47 | 48 | $this->assertEquals($this->testModelInstance->toArray(), $email->toArray()); 49 | } 50 | 51 | /** 52 | * Returns output of ::toXML method of tested parser. 53 | * @depends testParse 54 | * @param \DOMDocument $document 55 | * @return \DOMElement 56 | */ 57 | protected function convertToXML(\DOMDocument $document) 58 | { 59 | return EmailParser::toXML($this->testModelInstance, $document); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/phpGPX/Parsers/CopyrightParser.php: -------------------------------------------------------------------------------- 1 | 5 | */ 6 | 7 | namespace phpGPX\Parsers; 8 | 9 | use phpGPX\Models\Copyright; 10 | 11 | /** 12 | * Class CopyrightParser 13 | * @package phpGPX\Parsers 14 | */ 15 | abstract class CopyrightParser 16 | { 17 | public static $tagName = 'copyright'; 18 | 19 | /** 20 | * @param \SimpleXMLElement $node 21 | * @return Copyright|null 22 | */ 23 | public static function parse(\SimpleXMLElement $node) 24 | { 25 | if ($node->getName() != self::$tagName) { 26 | return null; 27 | } 28 | 29 | $copyright = new Copyright(); 30 | 31 | $copyright->author = isset($node['author']) ? (string) $node['author'] : null; 32 | $copyright->year = isset($node->year) ? (string) $node->year : null; 33 | $copyright->license = isset($node->license) ? (string) $node->license : null; 34 | 35 | return $copyright; 36 | } 37 | 38 | /** 39 | * @param Copyright $copyright 40 | * @param \DOMDocument $document 41 | * @return \DOMElement 42 | */ 43 | public static function toXML(Copyright $copyright, \DOMDocument &$document) 44 | { 45 | $node = $document->createElement(self::$tagName); 46 | 47 | $node->setAttribute('author', $copyright->author); 48 | 49 | if (!empty($copyright->year)) { 50 | $child = $document->createElement('year', $copyright->year); 51 | $node->appendChild($child); 52 | } 53 | 54 | if (!empty($copyright->license)) { 55 | $child = $document->createElement('license', $copyright->license); 56 | $node->appendChild($child); 57 | } 58 | 59 | return $node; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /tests/UnitTests/phpGPX/Parsers/LinkParserTest.php: -------------------------------------------------------------------------------- 1 | 4 | */ 5 | 6 | namespace UnitTests\phpGPX\Parsers; 7 | 8 | use phpGPX\Models\Link; 9 | use phpGPX\Parsers\LinkParser; 10 | 11 | class LinkParserTest extends AbstractParserTest 12 | { 13 | protected $testModelClass = Link::class; 14 | protected $testParserClass = LinkParser::class; 15 | 16 | /** 17 | * @var Link 18 | */ 19 | protected $testModelInstance; 20 | 21 | /** 22 | * @return Link 23 | */ 24 | public static function createTestInstance() 25 | { 26 | $link = new Link(); 27 | $link->href = "https://jakubdubec.me"; 28 | $link->text = "Portfolio"; 29 | $link->type = "text/html"; 30 | 31 | return $link; 32 | } 33 | 34 | protected function setUp(): void 35 | { 36 | parent::setUp(); 37 | 38 | $this->testModelInstance = self::createTestInstance(); 39 | } 40 | 41 | public function testParse() 42 | { 43 | $links = LinkParser::parse($this->testXmlFile->link); 44 | 45 | $this->assertNotEmpty($links); 46 | 47 | $link = $links[0]; 48 | 49 | $this->assertEquals($this->testModelInstance->href, $link->href); 50 | $this->assertEquals($this->testModelInstance->text, $link->text); 51 | $this->assertEquals($this->testModelInstance->type, $link->type); 52 | 53 | $this->assertEquals($this->testModelInstance->toArray(), $link->toArray()); 54 | } 55 | 56 | 57 | /** 58 | * Returns output of ::toXML method of tested parser. 59 | * @param \DOMDocument $document 60 | * @return \DOMElement 61 | */ 62 | protected function convertToXML(\DOMDocument $document) 63 | { 64 | return LinkParser::toXML($this->testModelInstance, $document); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /docs/phpGPX-Parsers-Extensions-TrackPointExtensionParser.md: -------------------------------------------------------------------------------- 1 | phpGPX\Parsers\Extensions\TrackPointExtensionParser 2 | =============== 3 | 4 | 5 | 6 | 7 | 8 | 9 | * Class name: TrackPointExtensionParser 10 | * Namespace: phpGPX\Parsers\Extensions 11 | 12 | 13 | 14 | 15 | 16 | Properties 17 | ---------- 18 | 19 | 20 | ### $attributeMapper 21 | 22 | private mixed $attributeMapper = array('atemp' => array('name' => 'aTemp', 'type' => 'float'), 'wtemp' => array('name' => 'wTemp', 'type' => 'float'), 'depth' => array('name' => 'depth', 'type' => 'float'), 'hr' => array('name' => 'hr', 'type' => 'float'), 'cad' => array('name' => 'cad', 'type' => 'float'), 'speed' => array('name' => 'speed', 'type' => 'float'), 'course' => array('name' => 'course', 'type' => 'int'), 'bearing' => array('name' => 'bearing', 'type' => 'int')) 23 | 24 | 25 | 26 | 27 | 28 | * Visibility: **private** 29 | * This property is **static**. 30 | 31 | 32 | Methods 33 | ------- 34 | 35 | 36 | ### parse 37 | 38 | \phpGPX\Models\Extensions\TrackPointExtension phpGPX\Parsers\Extensions\TrackPointExtensionParser::parse(\SimpleXMLElement $node) 39 | 40 | 41 | 42 | 43 | 44 | * Visibility: **public** 45 | * This method is **static**. 46 | 47 | 48 | #### Arguments 49 | * $node **SimpleXMLElement** 50 | 51 | 52 | 53 | ### toXML 54 | 55 | \DOMElement phpGPX\Parsers\Extensions\TrackPointExtensionParser::toXML(\phpGPX\Models\Extensions\TrackPointExtension $extension, \DOMDocument $document) 56 | 57 | 58 | 59 | 60 | 61 | * Visibility: **public** 62 | * This method is **static**. 63 | 64 | 65 | #### Arguments 66 | * $extension **[phpGPX\Models\Extensions\TrackPointExtension](phpGPX-Models-Extensions-TrackPointExtension.md)** 67 | * $document **DOMDocument** 68 | 69 | 70 | -------------------------------------------------------------------------------- /docs/phpGPX-Helpers-SerializationHelper.md: -------------------------------------------------------------------------------- 1 | phpGPX\Helpers\SerializationHelper 2 | =============== 3 | 4 | Class SerializationHelper 5 | Contains basic serialization helpers used in summary() methods. 6 | 7 | 8 | 9 | 10 | * Class name: SerializationHelper 11 | * Namespace: phpGPX\Helpers 12 | * This is an **abstract** class 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | Methods 21 | ------- 22 | 23 | 24 | ### integerOrNull 25 | 26 | integer|null phpGPX\Helpers\SerializationHelper::integerOrNull($value) 27 | 28 | Returns integer or null. 29 | 30 | 31 | 32 | * Visibility: **public** 33 | * This method is **static**. 34 | 35 | 36 | #### Arguments 37 | * $value **mixed** 38 | 39 | 40 | 41 | ### floatOrNull 42 | 43 | float|null phpGPX\Helpers\SerializationHelper::floatOrNull($value) 44 | 45 | Returns float or null. 46 | 47 | 48 | 49 | * Visibility: **public** 50 | * This method is **static**. 51 | 52 | 53 | #### Arguments 54 | * $value **mixed** 55 | 56 | 57 | 58 | ### stringOrNull 59 | 60 | null|string phpGPX\Helpers\SerializationHelper::stringOrNull($value) 61 | 62 | Returns string or null 63 | 64 | 65 | 66 | * Visibility: **public** 67 | * This method is **static**. 68 | 69 | 70 | #### Arguments 71 | * $value **mixed** 72 | 73 | 74 | 75 | ### serialize 76 | 77 | array|null phpGPX\Helpers\SerializationHelper::serialize(\phpGPX\Models\Summarizable|array $object) 78 | 79 | Recursively traverse Summarizable objects and returns their array representation according summary() method. 80 | 81 | 82 | 83 | * Visibility: **public** 84 | * This method is **static**. 85 | 86 | 87 | #### Arguments 88 | * $object **[phpGPX\Models\Summarizable](phpGPX-Models-Summarizable.md)|array<mixed,\phpGPX\Models\Summarizable>** 89 | 90 | 91 | -------------------------------------------------------------------------------- /src/phpGPX/Parsers/BoundsParser.php: -------------------------------------------------------------------------------- 1 | 5 | */ 6 | 7 | namespace phpGPX\Parsers; 8 | 9 | use phpGPX\Models\Bounds; 10 | 11 | /** 12 | * Class BoundsParser 13 | * @package phpGPX\Parsers 14 | */ 15 | abstract class BoundsParser 16 | { 17 | private static $tagName = 'bounds'; 18 | 19 | /** 20 | * Parse data from XML. 21 | * @param \SimpleXMLElement $node 22 | * @return Bounds|null 23 | */ 24 | public static function parse(\SimpleXMLElement $node) 25 | { 26 | if ($node->getName() != self::$tagName) { 27 | return null; 28 | } 29 | 30 | $bounds = new Bounds( 31 | isset($node['minlat']) ? (float) $node['minlat'] : null, 32 | isset($node['minlon']) ? (float) $node['minlon'] : null, 33 | isset($node['maxlat']) ? (float) $node['maxlat'] : null, 34 | isset($node['maxlon']) ? (float) $node['maxlon'] : null 35 | ); 36 | 37 | return $bounds; 38 | } 39 | 40 | /** 41 | * Create XML representation. 42 | * @param Bounds $bounds 43 | * @param \DOMDocument $document 44 | * @return \DOMElement 45 | */ 46 | public static function toXML(Bounds $bounds, \DOMDocument &$document) 47 | { 48 | $node = $document->createElement(self::$tagName); 49 | 50 | if (!is_null($bounds->minLatitude)) { 51 | $node->setAttribute('minlat', $bounds->minLatitude); 52 | } 53 | 54 | if (!is_null($bounds->minLongitude)) { 55 | $node->setAttribute('minlon', $bounds->minLongitude); 56 | } 57 | 58 | if (!is_null($bounds->maxLatitude)) { 59 | $node->setAttribute('maxlat', $bounds->maxLatitude); 60 | } 61 | 62 | if (!is_null($bounds->maxLongitude)) { 63 | $node->setAttribute('maxlon', $bounds->maxLongitude); 64 | } 65 | 66 | return $node; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/phpGPX/Helpers/GeoHelper.php: -------------------------------------------------------------------------------- 1 | 5 | */ 6 | 7 | namespace phpGPX\Helpers; 8 | 9 | use phpGPX\Models\Point; 10 | 11 | /** 12 | * Class GeoHelper 13 | * Geolocation methods. 14 | * @package phpGPX\Helpers 15 | */ 16 | abstract class GeoHelper 17 | { 18 | const EARTH_RADIUS = 6371000; 19 | 20 | /** 21 | * Returns distance in meters between two Points according to GPX coordinates. 22 | * @see Point 23 | * @param Point $point1 24 | * @param Point $point2 25 | * @return float 26 | */ 27 | public static function getRawDistance(Point $point1, Point $point2) 28 | { 29 | $latFrom = deg2rad($point1->latitude); 30 | $lonFrom = deg2rad($point1->longitude); 31 | $latTo = deg2rad($point2->latitude); 32 | $lonTo = deg2rad($point2->longitude); 33 | 34 | $lonDelta = $lonTo - $lonFrom; 35 | $a = pow(cos($latTo) * sin($lonDelta), 2) + pow(cos($latFrom) * sin($latTo) - sin($latFrom) * cos($latTo) * cos($lonDelta), 2); 36 | $b = sin($latFrom) * sin($latTo) + cos($latFrom) * cos($latTo) * cos($lonDelta); 37 | $angle = atan2(sqrt($a), $b); 38 | 39 | return $angle * self::EARTH_RADIUS; 40 | } 41 | 42 | /** 43 | * Returns distance between two points including elevation gain/loss 44 | * @param Point $point1 45 | * @param Point $point2 46 | * @return float 47 | */ 48 | public static function getRealDistance(Point $point1, Point $point2) 49 | { 50 | $distance = self::getRawDistance($point1, $point2); 51 | 52 | $elevation1 = $point1->elevation != null ? $point1->elevation : 0; 53 | $elevation2 = $point2->elevation != null ? $point2->elevation : 0; 54 | $elevDiff = abs($elevation1 - $elevation2); 55 | 56 | return sqrt(pow($distance, 2) + pow($elevDiff, 2)); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/phpGPX/Parsers/LinkParser.php: -------------------------------------------------------------------------------- 1 | 5 | */ 6 | 7 | namespace phpGPX\Parsers; 8 | 9 | use phpGPX\Models\Link; 10 | 11 | abstract class LinkParser 12 | { 13 | private static $tagName = 'link'; 14 | 15 | /** 16 | * @param \SimpleXMLElement[] $nodes 17 | * @return Link[] 18 | */ 19 | public static function parse($nodes = []) 20 | { 21 | $links = []; 22 | foreach ($nodes as $node) { 23 | $link = new Link(); 24 | $link->href = isset($node['href']) ? (string) $node['href'] : null; 25 | $link->text = isset($node->text) ? (string) $node->text : null; 26 | $link->type = isset($node->type) ? (string) $node->type : null; 27 | 28 | $links[] = $link; 29 | } 30 | return $links; 31 | } 32 | 33 | /** 34 | * @param Link[] $links 35 | * @param \DOMDocument $document 36 | * @return \DOMElement[] 37 | */ 38 | public static function toXMLArray(array $links, \DOMDocument &$document) 39 | { 40 | $result = []; 41 | 42 | foreach ($links as $link) { 43 | $result[] = self::toXML($link, $document); 44 | } 45 | 46 | return $result; 47 | } 48 | 49 | /** 50 | * @param Link $link 51 | * @param \DOMDocument $document 52 | * @return \DOMElement 53 | */ 54 | public static function toXML(Link $link, \DOMDocument &$document) 55 | { 56 | $node = $document->createElement(self::$tagName); 57 | 58 | $node->setAttribute('href', $link->href); 59 | 60 | if (!empty($link->text)) { 61 | $child = $document->createElement('text', $link->text); 62 | $node->appendChild($child); 63 | } 64 | 65 | if (!empty($link->type)) { 66 | $child = $document->createElement('type', $link->type); 67 | $node->appendChild($child); 68 | } 69 | 70 | return $node; 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /tests/UnitTests/phpGPX/Parsers/CopyrightParserTest.php: -------------------------------------------------------------------------------- 1 | 4 | */ 5 | 6 | namespace phpGPX\Tests\UnitTests\phpGPX\Parsers; 7 | 8 | use phpGPX\Models\Copyright; 9 | use phpGPX\Parsers\CopyrightParser; 10 | use UnitTests\phpGPX\Parsers\AbstractParserTest; 11 | 12 | class CopyrightParserTest extends AbstractParserTest 13 | { 14 | protected $testModelClass = Copyright::class; 15 | protected $testParserClass = CopyrightParser::class; 16 | 17 | /** 18 | * @var Copyright 19 | */ 20 | protected $testModelInstance; 21 | 22 | public static function createTestInstance() 23 | { 24 | $copyright = new Copyright(); 25 | 26 | $copyright->author = "Jakub Dubec"; 27 | $copyright->license = "https://github.com/Sibyx/phpGPX/blob/master/LICENSE"; 28 | $copyright->year = '2017'; 29 | 30 | return $copyright; 31 | } 32 | 33 | protected function setUp(): void 34 | { 35 | parent::setUp(); 36 | 37 | $this->testModelInstance = self::createTestInstance(); 38 | } 39 | 40 | public function testParse() 41 | { 42 | $copyright = CopyrightParser::parse($this->testXmlFile->copyright); 43 | 44 | $this->assertNotEmpty($copyright); 45 | 46 | $this->assertEquals($this->testModelInstance->author, $copyright->author); 47 | $this->assertEquals($this->testModelInstance->license, $copyright->license); 48 | $this->assertEquals($this->testModelInstance->year, $copyright->year); 49 | 50 | $this->assertEquals($this->testModelInstance->toArray(), $copyright->toArray()); 51 | } 52 | 53 | /** 54 | * Returns output of ::toXML method of tested parser. 55 | * @param \DOMDocument $document 56 | * @return \DOMElement 57 | */ 58 | protected function convertToXML(\DOMDocument $document) 59 | { 60 | return CopyrightParser::toXML($this->testModelInstance, $document); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /docs/phpGPX-Parsers-MetadataParser.md: -------------------------------------------------------------------------------- 1 | phpGPX\Parsers\MetadataParser 2 | =============== 3 | 4 | Class MetadataParser 5 | 6 | 7 | 8 | 9 | * Class name: MetadataParser 10 | * Namespace: phpGPX\Parsers 11 | * This is an **abstract** class 12 | 13 | 14 | 15 | 16 | 17 | Properties 18 | ---------- 19 | 20 | 21 | ### $tagName 22 | 23 | private mixed $tagName = 'metadata' 24 | 25 | 26 | 27 | 28 | 29 | * Visibility: **private** 30 | * This property is **static**. 31 | 32 | 33 | ### $attributeMapper 34 | 35 | private mixed $attributeMapper = array('name' => array('name' => 'name', 'type' => 'string'), 'desc' => array('name' => 'description', 'type' => 'string'), 'author' => array('name' => 'author', 'type' => 'object'), 'copyright' => array('name' => 'copyright', 'type' => 'object'), 'link' => array('name' => 'links', 'type' => 'array'), 'time' => array('name' => 'time', 'type' => 'object'), 'keywords' => array('name' => 'keywords', 'type' => 'string'), 'bounds' => array('name' => 'bounds', 'type' => 'object'), 'extensions' => array('name' => 'extensions', 'type' => 'object')) 36 | 37 | 38 | 39 | 40 | 41 | * Visibility: **private** 42 | * This property is **static**. 43 | 44 | 45 | Methods 46 | ------- 47 | 48 | 49 | ### parse 50 | 51 | \phpGPX\Models\Metadata phpGPX\Parsers\MetadataParser::parse(\SimpleXMLElement $node) 52 | 53 | 54 | 55 | 56 | 57 | * Visibility: **public** 58 | * This method is **static**. 59 | 60 | 61 | #### Arguments 62 | * $node **SimpleXMLElement** 63 | 64 | 65 | 66 | ### toXML 67 | 68 | mixed phpGPX\Parsers\MetadataParser::toXML(\phpGPX\Models\Metadata $metadata, \DOMDocument $document) 69 | 70 | 71 | 72 | 73 | 74 | * Visibility: **public** 75 | * This method is **static**. 76 | 77 | 78 | #### Arguments 79 | * $metadata **[phpGPX\Models\Metadata](phpGPX-Models-Metadata.md)** 80 | * $document **DOMDocument** 81 | 82 | 83 | -------------------------------------------------------------------------------- /tests/UnitTests/phpGPX/Parsers/ExtensionParserTest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 14 6 | 152 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /tests/UnitTests/phpGPX/Helpers/GeoHelperTest.php: -------------------------------------------------------------------------------- 1 | 4 | */ 5 | 6 | namespace UnitTests\phpGPX\Helpers; 7 | 8 | use phpGPX\Helpers\GeoHelper; 9 | use phpGPX\Models\Point; 10 | use PHPUnit\Framework\TestCase; 11 | 12 | class GeoHelperTest extends TestCase 13 | { 14 | 15 | /** 16 | * Tested with https://www.freemaptools.com/measure-distance.htm 17 | * 18 | * Input points: 19 | * - 48.1573923225717 17.0547121910204 20 | * - 48.1644916381763 17.0591753907502 21 | */ 22 | public function testGetDistance() 23 | { 24 | $point1 = new Point(Point::WAYPOINT); 25 | $point1->latitude = 48.1573923225717; 26 | $point1->longitude = 17.0547121910204; 27 | 28 | $point2 = new Point(Point::WAYPOINT); 29 | $point2->latitude = 48.1644916381763; 30 | $point2->longitude = 17.0591753907502; 31 | 32 | $this->assertEqualsWithDelta( 33 | 856.97, 34 | GeoHelper::getRawDistance($point1, $point2), 35 | 1, 36 | "Invalid distance between two points!" 37 | ); 38 | } 39 | 40 | /** 41 | * @link http://cosinekitty.com/compass.html 42 | */ 43 | public function testRealDistance() 44 | { 45 | $point1 = new Point(Point::WAYPOINT); 46 | $point1->latitude = 48.1573923225717; 47 | $point1->longitude = 17.0547121910204; 48 | $point1->elevation = 100; 49 | 50 | $point2 = new Point(Point::WAYPOINT); 51 | $point2->latitude = 48.1644916381763; 52 | $point2->longitude = 17.0591753907502; 53 | $point2->elevation = 200; 54 | 55 | $this->assertEqualsWithDelta( 56 | 856.97, 57 | GeoHelper::getRawDistance($point1, $point2), 58 | 1, 59 | "Invalid distance between two points!" 60 | ); 61 | 62 | $this->assertEqualsWithDelta( 63 | 862, 64 | GeoHelper::getRealDistance($point1, $point2), 65 | 1, 66 | "Invalid real distance between two points!" 67 | ); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /docs/phpGPX-Models-Segment.md: -------------------------------------------------------------------------------- 1 | phpGPX\Models\Segment 2 | =============== 3 | 4 | Class Segment 5 | A Track Segment holds a list of Track Points which are logically connected in order. 6 | 7 | To represent a single GPS track where GPS reception was lost, or the GPS receiver was turned off, 8 | start a new Track Segment for each continuous span of track data. 9 | 10 | 11 | * Class name: Segment 12 | * Namespace: phpGPX\Models 13 | * This class implements: [phpGPX\Models\Summarizable](phpGPX-Models-Summarizable.md), [phpGPX\Models\StatsCalculator](phpGPX-Models-StatsCalculator.md) 14 | 15 | 16 | 17 | 18 | Properties 19 | ---------- 20 | 21 | 22 | ### $points 23 | 24 | public array $points 25 | 26 | Array of segment points 27 | 28 | 29 | 30 | * Visibility: **public** 31 | 32 | 33 | ### $extensions 34 | 35 | public \phpGPX\Models\Extensions $extensions 36 | 37 | You can add extend GPX by adding your own elements from another schema here. 38 | 39 | 40 | 41 | * Visibility: **public** 42 | 43 | 44 | ### $stats 45 | 46 | public \phpGPX\Models\Stats $stats 47 | 48 | 49 | 50 | 51 | 52 | * Visibility: **public** 53 | 54 | 55 | Methods 56 | ------- 57 | 58 | 59 | ### __construct 60 | 61 | mixed phpGPX\Models\Segment::__construct() 62 | 63 | Segment constructor. 64 | 65 | 66 | 67 | * Visibility: **public** 68 | 69 | 70 | 71 | 72 | ### toArray 73 | 74 | array phpGPX\Models\Summarizable::toArray() 75 | 76 | Serialize object to array 77 | 78 | 79 | 80 | * Visibility: **public** 81 | * This method is defined by [phpGPX\Models\Summarizable](phpGPX-Models-Summarizable.md) 82 | 83 | 84 | 85 | 86 | ### recalculateStats 87 | 88 | void phpGPX\Models\StatsCalculator::recalculateStats() 89 | 90 | Recalculate stats objects. 91 | 92 | 93 | 94 | * Visibility: **public** 95 | * This method is defined by [phpGPX\Models\StatsCalculator](phpGPX-Models-StatsCalculator.md) 96 | 97 | 98 | 99 | -------------------------------------------------------------------------------- /tests/fixtures/timezero.gpx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Event 0000 6 | 7 | 8 | 10 9 | -16744448 10 | 11 | 12 | 13 | 14 | Event 0001 15 | 16 | 17 | 10 18 | -16744448 19 | 20 | 21 | 22 | Ownship 23 | 24 | 201 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | Ownship 40 | 41 | 102 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /src/phpGPX/Helpers/SerializationHelper.php: -------------------------------------------------------------------------------- 1 | 5 | */ 6 | 7 | namespace phpGPX\Helpers; 8 | 9 | use phpGPX\Models\Summarizable; 10 | 11 | /** 12 | * Class SerializationHelper 13 | * Contains basic serialization helpers used in summary() methods. 14 | * @package phpGPX\Helpers 15 | */ 16 | abstract class SerializationHelper 17 | { 18 | 19 | /** 20 | * Returns integer or null. 21 | * @param $value 22 | * @return int|null 23 | */ 24 | public static function integerOrNull($value) 25 | { 26 | return is_numeric($value) ? (integer) $value : null; 27 | } 28 | 29 | /** 30 | * Returns float or null. 31 | * @param $value 32 | * @return float|null 33 | */ 34 | public static function floatOrNull($value) 35 | { 36 | return is_numeric($value) ? (float) $value : null; 37 | } 38 | 39 | /** 40 | * Returns string or null 41 | * @param $value 42 | * @return null|string 43 | */ 44 | public static function stringOrNull($value) 45 | { 46 | return is_string($value) ? $value : null; 47 | } 48 | 49 | /** 50 | * Recursively traverse Summarizable objects and returns their array representation according summary() method. 51 | * @param Summarizable|Summarizable[] $object 52 | * @return array|null 53 | */ 54 | public static function serialize($object) 55 | { 56 | if (is_array($object)) { 57 | $result = []; 58 | foreach ($object as $record) { 59 | $result[] = $record->toArray(); 60 | $record = null; 61 | } 62 | $object = null; 63 | return $result; 64 | } else { 65 | return $object != null ? $object->toArray() : null; 66 | } 67 | } 68 | 69 | public static function filterNotNull(array $array) 70 | { 71 | foreach ($array as &$item) { 72 | if (!is_array($item)) { 73 | continue; 74 | } 75 | 76 | $item = self::filterNotNull($item); 77 | } 78 | 79 | $array = array_filter($array, function ($item) { 80 | return $item !== null && (!is_array($item) || count($item)); 81 | }); 82 | 83 | return $array; 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/phpGPX/Parsers/SegmentParser.php: -------------------------------------------------------------------------------- 1 | 5 | */ 6 | 7 | namespace phpGPX\Parsers; 8 | 9 | use phpGPX\Models\Segment; 10 | use phpGPX\phpGPX; 11 | 12 | /** 13 | * Class SegmentParser 14 | * @package phpGPX\Parsers 15 | */ 16 | abstract class SegmentParser 17 | { 18 | public static $tagName = 'trkseg'; 19 | 20 | /** 21 | * @param $nodes \SimpleXMLElement[] 22 | * @return Segment[] 23 | */ 24 | public static function parse($nodes) 25 | { 26 | $segments = []; 27 | 28 | foreach ($nodes as $node) { 29 | $segment = new Segment(); 30 | 31 | if (!$node->count()) { 32 | continue; 33 | } 34 | 35 | if (isset($node->trkpt)) { 36 | $segment->points = []; 37 | 38 | foreach ($node->trkpt as $point) { 39 | $segment->points[] = PointParser::parse($point); 40 | } 41 | } 42 | $segment->extensions = isset($node->extensions) ? ExtensionParser::parse($node->extensions) : null; 43 | 44 | if (phpGPX::$CALCULATE_STATS) { 45 | $segment->recalculateStats(); 46 | } 47 | 48 | $segments[] = $segment; 49 | } 50 | 51 | return $segments; 52 | } 53 | 54 | /** 55 | * @param Segment $segment 56 | * @param \DOMDocument $document 57 | * @return \DOMElement 58 | */ 59 | public static function toXML(Segment $segment, \DOMDocument &$document) 60 | { 61 | $node = $document->createElement(self::$tagName); 62 | 63 | foreach ($segment->points as $point) { 64 | $node->appendChild(PointParser::toXML($point, $document)); 65 | } 66 | 67 | if (!empty($segment->extensions)) { 68 | $node->appendChild(ExtensionParser::toXML($segment->extensions, $document)); 69 | } 70 | 71 | return $node; 72 | } 73 | 74 | /** 75 | * @param array $segments 76 | * @param \DOMDocument $document 77 | * @return \DOMElement[] 78 | */ 79 | public static function toXMLArray(array $segments, \DOMDocument $document) 80 | { 81 | $result = []; 82 | 83 | foreach ($segments as $segment) { 84 | $result[] = self::toXML($segment, $document); 85 | } 86 | 87 | return $result; 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /tests/UnitTests/phpGPX/Helpers/DateTimeHelperTest.php: -------------------------------------------------------------------------------- 1 | 4 | */ 5 | 6 | namespace UnitTests\phpGPX\Helpers; 7 | 8 | use phpGPX\Helpers\DateTimeHelper; 9 | use phpGPX\Models\Point; 10 | use PHPUnit\Framework\TestCase; 11 | 12 | class DateTimeHelperTest extends TestCase 13 | { 14 | public function testComparePointsByTimestamp() 15 | { 16 | // 2017-08-12T20:16:29+00:00 17 | $point1 = new Point(Point::WAYPOINT); 18 | $time1 = new \DateTime("2017-08-12T20:16:29+00:00", new \DateTimeZone("UTC")); 19 | $point1->time = $time1; 20 | 21 | // 2017-08-12T20:15:19+00:00 22 | $point2 = new Point(Point::WAYPOINT); 23 | $time2 = new \DateTime("2017-08-12T20:15:19+00:00", new \DateTimeZone("UTC")); 24 | $point2->time = $time2; 25 | 26 | $this->assertTrue(($time1 > $time2) && DateTimeHelper::comparePointsByTimestamp($point1, $point2)); 27 | } 28 | 29 | public function testFormatDateTime() 30 | { 31 | // 1. Basic test 32 | $datetime = new \DateTime("2017-08-12T20:16:29+00:00"); 33 | 34 | $this->assertEquals( 35 | $datetime->format("Y-m-d H:i:s"), 36 | DateTimeHelper::formatDateTime($datetime, "Y-m-d H:i:s") 37 | ); 38 | 39 | // 2. NULL value 40 | $datetime = null; 41 | 42 | $this->assertNull(DateTimeHelper::formatDateTime($datetime), "NULL input"); 43 | 44 | // 3. Empty string 45 | $datetime = ""; 46 | 47 | $this->assertNull(DateTimeHelper::formatDateTime($datetime), "Empty string input"); 48 | 49 | // 4. Timezone 50 | $datetime = new \DateTime("2017-08-12T20:16:29+00:00"); 51 | 52 | $this->assertEquals( 53 | "2017-08-12 21:16:29", 54 | DateTimeHelper::formatDateTime($datetime, "Y-m-d H:i:s", '+01:00') 55 | ); 56 | } 57 | 58 | public function testParseDateTime() 59 | { 60 | // 1. Valid string 61 | $this->assertEquals( 62 | new \DateTime("2017-08-12T20:16:29+00:00"), 63 | DateTimeHelper::parseDateTime("2017-08-12T20:16:29+00:00") 64 | ); 65 | } 66 | 67 | public function testParseDateTimeInvalidInput() 68 | { 69 | $this->expectException("Exception"); 70 | DateTimeHelper::parseDateTime("Invalid exception"); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /tests/UnitTests/phpGPX/Parsers/AbstractParserTest.php: -------------------------------------------------------------------------------- 1 | 4 | */ 5 | 6 | namespace UnitTests\phpGPX\Parsers; 7 | 8 | use phpGPX\Models\Summarizable; 9 | use PHPUnit\Framework\TestCase; 10 | 11 | abstract class AbstractParserTest extends TestCase 12 | { 13 | /** 14 | * @var \SimpleXMLElement 15 | */ 16 | protected $testXmlFile; 17 | 18 | /** 19 | * Instance of model holding data for parser. 20 | * EXAMPLE: model phpGPX\Models\Bounds belongs to parser phpGPX\Parsers\BoundsParser 21 | * @var Summarizable 22 | */ 23 | protected $testModelInstance; 24 | 25 | /** 26 | * Full name with namespace for models class. 27 | * EXAMPLE: phpGPX\Models\Bounds 28 | * @var string 29 | */ 30 | protected $testModelClass; 31 | 32 | /** 33 | * Full name with namespace for parser class. 34 | * EXAMPLE: phpGPX\Parsers\BoundsParser 35 | * @var string 36 | */ 37 | protected $testParserClass; 38 | 39 | protected function setUp(): void 40 | { 41 | $reflection = new \ReflectionClass($this->testParserClass); 42 | 43 | $this->testXmlFile = simplexml_load_file(sprintf("%s/%sTest.xml", __DIR__, $reflection->getShortName())); 44 | } 45 | 46 | abstract public function testParse(); 47 | 48 | /** 49 | * Returns output of ::toXML method of tested parser. 50 | * @depends testParse 51 | * @param \DOMDocument $document 52 | * @return \DOMElement 53 | */ 54 | abstract protected function convertToXML(\DOMDocument $document); 55 | 56 | public function testToXML() 57 | { 58 | $document = new \DOMDocument("1.0", 'UTF-8'); 59 | 60 | $root = $document->createElement("document"); 61 | $root->appendChild($this->convertToXML($document)); 62 | 63 | $document->appendChild($root); 64 | 65 | $this->assertXmlStringEqualsXmlString($this->testXmlFile->asXML(), $document->saveXML()); 66 | } 67 | 68 | public function testToJSON() 69 | { 70 | $reflection = new \ReflectionClass($this->testParserClass); 71 | 72 | $this->assertJsonStringEqualsJsonFile( 73 | sprintf("%s/%sTest.json", __DIR__, $reflection->getShortName()), 74 | json_encode($this->testModelInstance->toArray()) 75 | ); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/phpGPX/Helpers/DistanceCalculator.php: -------------------------------------------------------------------------------- 1 | points = $points; 30 | } 31 | 32 | public function getRawDistance() 33 | { 34 | return $this->calculate([GeoHelper::class, 'getRawDistance']); 35 | } 36 | 37 | public function getRealDistance() 38 | { 39 | return $this->calculate([GeoHelper::class, 'getRealDistance']); 40 | } 41 | 42 | /** 43 | * @param Point[]|array $points 44 | * @return float 45 | */ 46 | private function calculate($strategy) 47 | { 48 | $distance = 0; 49 | 50 | $pointCount = count($this->points); 51 | 52 | $lastConsideredPoint = null; 53 | 54 | for ($p = 0; $p < $pointCount; $p++) { 55 | $curPoint = $this->points[$p]; 56 | 57 | // skip the first point 58 | if ($p === 0) { 59 | $lastConsideredPoint = $curPoint; 60 | continue; 61 | } 62 | 63 | // calculate the delta from current point to last considered point 64 | $curPoint->difference = call_user_func($strategy, $lastConsideredPoint, $curPoint); 65 | 66 | // if smoothing is applied we only consider points with a delta above the threshold (e.g. 2 meters) 67 | if (phpGPX::$APPLY_DISTANCE_SMOOTHING) { 68 | $differenceFromLastConsideredPoint = call_user_func($strategy, $curPoint, $lastConsideredPoint); 69 | 70 | if ($differenceFromLastConsideredPoint > phpGPX::$DISTANCE_SMOOTHING_THRESHOLD) { 71 | $distance += $differenceFromLastConsideredPoint; 72 | $lastConsideredPoint = $curPoint; 73 | } 74 | } 75 | 76 | // if smoothing is not applied we consider every point 77 | else { 78 | $distance += $curPoint->difference; 79 | $lastConsideredPoint = $curPoint; 80 | } 81 | 82 | $curPoint->distance = $distance; 83 | } 84 | 85 | return $distance; 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/phpGPX/Parsers/ExtensionParser.php: -------------------------------------------------------------------------------- 1 | 5 | */ 6 | 7 | namespace phpGPX\Parsers; 8 | 9 | use phpGPX\Models\Extensions; 10 | use phpGPX\Models\Extensions\TrackPointExtension; 11 | use phpGPX\Parsers\Extensions\TrackPointExtensionParser; 12 | 13 | /** 14 | * Class ExtensionParser 15 | * @package phpGPX\Parsers 16 | */ 17 | abstract class ExtensionParser 18 | { 19 | public static $tagName = 'extensions'; 20 | 21 | public static $usedNamespaces = []; 22 | 23 | /** 24 | * @param \SimpleXMLElement $nodes 25 | * @return Extensions 26 | */ 27 | public static function parse($nodes) 28 | { 29 | $extensions = new Extensions(); 30 | 31 | $nodeNamespaces = $nodes->getNamespaces(true); 32 | 33 | foreach ($nodeNamespaces as $key => $namespace) { 34 | switch ($namespace) { 35 | case TrackPointExtension::EXTENSION_NAMESPACE: 36 | case TrackPointExtension::EXTENSION_V1_NAMESPACE: 37 | $node = $nodes->children($namespace)->{TrackPointExtension::EXTENSION_NAME}; 38 | if (!empty($node)) { 39 | $extensions->trackPointExtension = TrackPointExtensionParser::parse($node); 40 | } 41 | break; 42 | default: 43 | foreach ($nodes->children($namespace) as $child_key => $value) { 44 | $extensions->unsupported[$key ? "$key:$child_key" : "$child_key"] = (string) $value; 45 | } 46 | } 47 | } 48 | 49 | return $extensions; 50 | } 51 | 52 | 53 | /** 54 | * @param Extensions $extensions 55 | * @param \DOMDocument $document 56 | * @return \DOMElement|null 57 | */ 58 | public static function toXML(Extensions $extensions, \DOMDocument &$document) 59 | { 60 | $node = $document->createElement(self::$tagName); 61 | 62 | if (null !== $extensions->trackPointExtension) { 63 | $child = TrackPointExtensionParser::toXML($extensions->trackPointExtension, $document); 64 | $node->appendChild($child); 65 | } 66 | 67 | if (!empty($extensions->unsupported)) { 68 | foreach ($extensions->unsupported as $key => $value) { 69 | $child = $document->createElement($key, $value); 70 | $node->appendChild($child); 71 | } 72 | } 73 | 74 | return $node; 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /docs/phpGPX-Parsers-TrackParser.md: -------------------------------------------------------------------------------- 1 | phpGPX\Parsers\TrackParser 2 | =============== 3 | 4 | Class TrackParser 5 | 6 | 7 | 8 | 9 | * Class name: TrackParser 10 | * Namespace: phpGPX\Parsers 11 | * This is an **abstract** class 12 | 13 | 14 | 15 | 16 | 17 | Properties 18 | ---------- 19 | 20 | 21 | ### $tagName 22 | 23 | public mixed $tagName = 'trk' 24 | 25 | 26 | 27 | 28 | 29 | * Visibility: **public** 30 | * This property is **static**. 31 | 32 | 33 | ### $attributeMapper 34 | 35 | private mixed $attributeMapper = array('name' => array('name' => 'name', 'type' => 'string'), 'cmt' => array('name' => 'comment', 'type' => 'string'), 'desc' => array('name' => 'description', 'type' => 'string'), 'src' => array('name' => 'source', 'type' => 'string'), 'link' => array('name' => 'links', 'type' => 'array'), 'number' => array('name' => 'number', 'type' => 'integer'), 'type' => array('name' => 'type', 'type' => 'string'), 'extensions' => array('name' => 'extensions', 'type' => 'object'), 'trkseg' => array('name' => 'segments', 'type' => 'array')) 36 | 37 | 38 | 39 | 40 | 41 | * Visibility: **private** 42 | * This property is **static**. 43 | 44 | 45 | Methods 46 | ------- 47 | 48 | 49 | ### parse 50 | 51 | array phpGPX\Parsers\TrackParser::parse(\SimpleXMLElement $nodes) 52 | 53 | 54 | 55 | 56 | 57 | * Visibility: **public** 58 | * This method is **static**. 59 | 60 | 61 | #### Arguments 62 | * $nodes **SimpleXMLElement** 63 | 64 | 65 | 66 | ### toXML 67 | 68 | \DOMElement phpGPX\Parsers\TrackParser::toXML(\phpGPX\Models\Track $track, \DOMDocument $document) 69 | 70 | 71 | 72 | 73 | 74 | * Visibility: **public** 75 | * This method is **static**. 76 | 77 | 78 | #### Arguments 79 | * $track **[phpGPX\Models\Track](phpGPX-Models-Track.md)** 80 | * $document **DOMDocument** 81 | 82 | 83 | 84 | ### toXMLArray 85 | 86 | array phpGPX\Parsers\TrackParser::toXMLArray(array $tracks, \DOMDocument $document) 87 | 88 | 89 | 90 | 91 | 92 | * Visibility: **public** 93 | * This method is **static**. 94 | 95 | 96 | #### Arguments 97 | * $tracks **array** 98 | * $document **DOMDocument** 99 | 100 | 101 | -------------------------------------------------------------------------------- /docs/phpGPX-Parsers-RouteParser.md: -------------------------------------------------------------------------------- 1 | phpGPX\Parsers\RouteParser 2 | =============== 3 | 4 | Class RouteParser 5 | 6 | 7 | 8 | 9 | * Class name: RouteParser 10 | * Namespace: phpGPX\Parsers 11 | * This is an **abstract** class 12 | 13 | 14 | 15 | 16 | 17 | Properties 18 | ---------- 19 | 20 | 21 | ### $tagName 22 | 23 | public mixed $tagName = 'rte' 24 | 25 | 26 | 27 | 28 | 29 | * Visibility: **public** 30 | * This property is **static**. 31 | 32 | 33 | ### $attributeMapper 34 | 35 | private mixed $attributeMapper = array('name' => array('name' => 'name', 'type' => 'string'), 'cmt' => array('name' => 'comment', 'type' => 'string'), 'desc' => array('name' => 'description', 'type' => 'string'), 'src' => array('name' => 'source', 'type' => 'string'), 'link' => array('name' => 'links', 'type' => 'array'), 'number' => array('name' => 'number', 'type' => 'integer'), 'type' => array('name' => 'type', 'type' => 'string'), 'extensions' => array('name' => 'extensions', 'type' => 'object'), 'rtep' => array('name' => 'points', 'type' => 'array')) 36 | 37 | 38 | 39 | 40 | 41 | * Visibility: **private** 42 | * This property is **static**. 43 | 44 | 45 | Methods 46 | ------- 47 | 48 | 49 | ### parse 50 | 51 | array phpGPX\Parsers\RouteParser::parse(array $nodes) 52 | 53 | 54 | 55 | 56 | 57 | * Visibility: **public** 58 | * This method is **static**. 59 | 60 | 61 | #### Arguments 62 | * $nodes **array<mixed,\SimpleXMLElement>** 63 | 64 | 65 | 66 | ### toXML 67 | 68 | \DOMElement phpGPX\Parsers\RouteParser::toXML(\phpGPX\Models\Route $route, \DOMDocument $document) 69 | 70 | 71 | 72 | 73 | 74 | * Visibility: **public** 75 | * This method is **static**. 76 | 77 | 78 | #### Arguments 79 | * $route **[phpGPX\Models\Route](phpGPX-Models-Route.md)** 80 | * $document **DOMDocument** 81 | 82 | 83 | 84 | ### toXMLArray 85 | 86 | array phpGPX\Parsers\RouteParser::toXMLArray(array $routes, \DOMDocument $document) 87 | 88 | 89 | 90 | 91 | 92 | * Visibility: **public** 93 | * This method is **static**. 94 | 95 | 96 | #### Arguments 97 | * $routes **array** 98 | * $document **DOMDocument** 99 | 100 | 101 | -------------------------------------------------------------------------------- /src/phpGPX/Helpers/ElevationGainLossCalculator.php: -------------------------------------------------------------------------------- 1 | elevation; 31 | 32 | // skip points with empty elevation 33 | if ($curElevation === null) { 34 | continue; 35 | } 36 | 37 | // skip points with 0 elevation if configuration allows 38 | if (phpGPX::$IGNORE_ELEVATION_0 && $curElevation == 0) { 39 | continue; 40 | } 41 | 42 | // skip the first point 43 | if ($p === 0) { 44 | $lastConsideredElevation = $curElevation; 45 | continue; 46 | } 47 | 48 | // calculate the delta from current point to last considered point 49 | $elevationDelta = $curElevation - $lastConsideredElevation; 50 | 51 | // if smoothing is applied we only consider points with a delta above the threshold (e.g. 2 meters) 52 | if (phpGPX::$APPLY_ELEVATION_SMOOTHING && 53 | abs($elevationDelta) > phpGPX::$ELEVATION_SMOOTHING_THRESHOLD && 54 | (phpGPX::$ELEVATION_SMOOTHING_SPIKES_THRESHOLD === null || abs($elevationDelta) < phpGPX::$ELEVATION_SMOOTHING_SPIKES_THRESHOLD)) { 55 | $cumulativeElevationGain += ($elevationDelta > 0) ? $elevationDelta : 0; 56 | $cumulativeElevationLoss += ($elevationDelta < 0) ? abs($elevationDelta) : 0; 57 | 58 | $lastConsideredElevation = $curElevation; 59 | } 60 | 61 | // if smoothing is not applied we consider every point 62 | if (!phpGPX::$APPLY_ELEVATION_SMOOTHING) { 63 | $cumulativeElevationGain += ($elevationDelta > 0) ? $elevationDelta : 0; 64 | $cumulativeElevationLoss += ($elevationDelta < 0) ? abs($elevationDelta) : 0; 65 | 66 | $lastConsideredElevation = $curElevation; 67 | } 68 | } 69 | 70 | return [$cumulativeElevationGain, $cumulativeElevationLoss]; 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /tests/UnitTests/phpGPX/Parsers/PointParserTest.php: -------------------------------------------------------------------------------- 1 | latitude = 46.571948; 29 | $point->longitude = 8.414757; 30 | $point->elevation = 2419; 31 | $point->time = DateTimeHelper::parseDateTime("2017-08-13T07:10:41.000Z"); 32 | 33 | return $point; 34 | } 35 | 36 | public static function createTestInstanceWithValues( 37 | float $latitude, 38 | float $longitude, 39 | float $elevation, 40 | string $timeAsString) : Point 41 | { 42 | $point = new Point(Point::TRACKPOINT); 43 | $point->latitude = $latitude; 44 | $point->longitude = $longitude; 45 | $point->elevation = $elevation; 46 | $point->time = DateTimeHelper::parseDateTime($timeAsString); 47 | 48 | return $point; 49 | } 50 | 51 | protected function setUp(): void 52 | { 53 | parent::setUp(); 54 | 55 | $this->testModelInstance = self::createTestInstance(); 56 | } 57 | 58 | public function testParse() 59 | { 60 | $point = PointParser::parse($this->testXmlFile->trkpt); 61 | 62 | $this->assertNotEmpty($point); 63 | 64 | // Primitive attributes 65 | $this->assertEquals($this->testModelInstance->latitude, $point->latitude); 66 | $this->assertEquals($this->testModelInstance->longitude, $point->longitude); 67 | $this->assertEquals($this->testModelInstance->elevation, $point->elevation); 68 | $this->assertEquals($this->testModelInstance->time, $point->time); 69 | } 70 | 71 | /** 72 | * Returns output of ::toXML method of tested parser. 73 | * @depends testParse 74 | * @param \DOMDocument $document 75 | * @return \DOMElement 76 | */ 77 | protected function convertToXML(\DOMDocument $document) 78 | { 79 | return PointParser::toXML($this->testModelInstance, $document); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/phpGPX/Models/Collection.php: -------------------------------------------------------------------------------- 1 | 5 | */ 6 | 7 | namespace phpGPX\Models; 8 | 9 | /** 10 | * Class Collection 11 | * @package phpGPX\Models 12 | */ 13 | abstract class Collection implements Summarizable, StatsCalculator 14 | { 15 | 16 | /** 17 | * GPS name of route / track. 18 | * An original GPX 1.1 attribute. 19 | * @var string|null 20 | */ 21 | public $name; 22 | 23 | /** 24 | * GPS comment for route. 25 | * An original GPX 1.1 attribute. 26 | * @var string|null 27 | */ 28 | public $comment; 29 | 30 | /** 31 | * Text description of route/track for user. Not sent to GPS. 32 | * An original GPX 1.1 attribute. 33 | * @var string|null 34 | */ 35 | public $description; 36 | 37 | /** 38 | * Source of data. Included to give user some idea of reliability and accuracy of data. 39 | * An original GPX 1.1 attribute. 40 | * @var string|null 41 | */ 42 | public $source; 43 | 44 | /** 45 | * Links to external information about the route/track. 46 | * An original GPX 1.1 attribute. 47 | * @var Link[] 48 | */ 49 | public $links; 50 | 51 | /** 52 | * GPS route/track number. 53 | * An original GPX 1.1 attribute. 54 | * @var int|null 55 | */ 56 | public $number; 57 | 58 | /** 59 | * Type (classification) of route/track. 60 | * An original GPX 1.1 attribute. 61 | * @var string|null 62 | */ 63 | public $type; 64 | 65 | /** 66 | * You can add extend GPX by adding your own elements from another schema here. 67 | * An original GPX 1.1 attribute. 68 | * @var Extensions|null 69 | */ 70 | public $extensions; 71 | 72 | /** 73 | * Objects contains calculated statistics for collection. 74 | * @var Stats|null 75 | */ 76 | public $stats; 77 | 78 | /** 79 | * Collection constructor. 80 | */ 81 | public function __construct() 82 | { 83 | $this->name = null; 84 | $this->comment = null; 85 | $this->description = null; 86 | $this->source = null; 87 | $this->links = []; 88 | $this->number = null; 89 | $this->type = null; 90 | $this->extensions = null; 91 | } 92 | 93 | 94 | /** 95 | * Return all points in collection. 96 | * @return Point[] 97 | */ 98 | abstract public function getPoints(): array; 99 | } 100 | -------------------------------------------------------------------------------- /docs/phpGPX-Models-GpxFile.md: -------------------------------------------------------------------------------- 1 | phpGPX\Models\GpxFile 2 | =============== 3 | 4 | Class GpxFile 5 | Representation of GPX file. 6 | 7 | 8 | 9 | 10 | * Class name: GpxFile 11 | * Namespace: phpGPX\Models 12 | * This class implements: [phpGPX\Models\Summarizable](phpGPX-Models-Summarizable.md) 13 | 14 | 15 | 16 | 17 | Properties 18 | ---------- 19 | 20 | 21 | ### $waypoints 22 | 23 | public array $waypoints 24 | 25 | A list of waypoints. 26 | 27 | 28 | 29 | * Visibility: **public** 30 | 31 | 32 | ### $routes 33 | 34 | public array $routes 35 | 36 | A list of routes. 37 | 38 | 39 | 40 | * Visibility: **public** 41 | 42 | 43 | ### $tracks 44 | 45 | public array $tracks 46 | 47 | A list of tracks. 48 | 49 | 50 | 51 | * Visibility: **public** 52 | 53 | 54 | ### $metadata 55 | 56 | public \phpGPX\Models\Metadata $metadata 57 | 58 | Metadata about the file. 59 | 60 | The original GPX 1.1 attribute. 61 | 62 | * Visibility: **public** 63 | 64 | 65 | ### $extensions 66 | 67 | public \phpGPX\Models\Extensions $extensions 68 | 69 | 70 | 71 | 72 | 73 | * Visibility: **public** 74 | 75 | 76 | ### $creator 77 | 78 | public string $creator 79 | 80 | Creator of GPX file. 81 | 82 | 83 | 84 | * Visibility: **public** 85 | 86 | 87 | Methods 88 | ------- 89 | 90 | 91 | ### __construct 92 | 93 | mixed phpGPX\Models\GpxFile::__construct() 94 | 95 | GpxFile constructor. 96 | 97 | 98 | 99 | * Visibility: **public** 100 | 101 | 102 | 103 | 104 | ### toArray 105 | 106 | array phpGPX\Models\Summarizable::toArray() 107 | 108 | Serialize object to array 109 | 110 | 111 | 112 | * Visibility: **public** 113 | * This method is defined by [phpGPX\Models\Summarizable](phpGPX-Models-Summarizable.md) 114 | 115 | 116 | 117 | 118 | ### toJSON 119 | 120 | string phpGPX\Models\GpxFile::toJSON() 121 | 122 | Return JSON representation of GPX file with statistics. 123 | 124 | 125 | 126 | * Visibility: **public** 127 | 128 | 129 | 130 | 131 | ### toXML 132 | 133 | \DOMDocument phpGPX\Models\GpxFile::toXML() 134 | 135 | Create XML representation of GPX file. 136 | 137 | 138 | 139 | * Visibility: **public** 140 | 141 | 142 | 143 | 144 | ### save 145 | 146 | mixed phpGPX\Models\GpxFile::save(string $path, string $format) 147 | 148 | Save data to file according to selected format. 149 | 150 | 151 | 152 | * Visibility: **public** 153 | 154 | 155 | #### Arguments 156 | * $path **string** 157 | * $format **string** 158 | 159 | 160 | -------------------------------------------------------------------------------- /docs/phpGPX-phpGPX.md: -------------------------------------------------------------------------------- 1 | phpGPX\phpGPX 2 | =============== 3 | 4 | Class phpGPX 5 | 6 | 7 | 8 | 9 | * Class name: phpGPX 10 | * Namespace: phpGPX 11 | 12 | 13 | 14 | Constants 15 | ---------- 16 | 17 | 18 | ### JSON_FORMAT 19 | 20 | const JSON_FORMAT = 'json' 21 | 22 | 23 | 24 | 25 | 26 | ### XML_FORMAT 27 | 28 | const XML_FORMAT = 'xml' 29 | 30 | 31 | 32 | 33 | 34 | ### PACKAGE_NAME 35 | 36 | const PACKAGE_NAME = 'phpGPX' 37 | 38 | 39 | 40 | 41 | 42 | ### VERSION 43 | 44 | const VERSION = '1.0' 45 | 46 | 47 | 48 | 49 | 50 | Properties 51 | ---------- 52 | 53 | 54 | ### $CALCULATE_STATS 55 | 56 | public boolean $CALCULATE_STATS = true 57 | 58 | Create Stats object for each track, segment and route 59 | 60 | 61 | 62 | * Visibility: **public** 63 | * This property is **static**. 64 | 65 | 66 | ### $SORT_BY_TIMESTAMP 67 | 68 | public boolean $SORT_BY_TIMESTAMP = false 69 | 70 | Additional sort based on timestamp in Routes & Tracks on XML read. 71 | 72 | Disabled by default, data should be already sorted. 73 | 74 | * Visibility: **public** 75 | * This property is **static**. 76 | 77 | 78 | ### $DATETIME_FORMAT 79 | 80 | public string $DATETIME_FORMAT = 'c' 81 | 82 | Default DateTime output format in JSON serialization. 83 | 84 | 85 | 86 | * Visibility: **public** 87 | * This property is **static**. 88 | 89 | 90 | ### $DATETIME_TIMEZONE_OUTPUT 91 | 92 | public string $DATETIME_TIMEZONE_OUTPUT = 'UTC' 93 | 94 | Default timezone for display. 95 | 96 | Data are always stored in UTC timezone. 97 | 98 | * Visibility: **public** 99 | * This property is **static**. 100 | 101 | 102 | ### $PRETTY_PRINT 103 | 104 | public boolean $PRETTY_PRINT = true 105 | 106 | Pretty print. 107 | 108 | 109 | 110 | * Visibility: **public** 111 | * This property is **static**. 112 | 113 | 114 | Methods 115 | ------- 116 | 117 | 118 | ### load 119 | 120 | \phpGPX\Models\GpxFile phpGPX\phpGPX::load($path) 121 | 122 | Load GPX file. 123 | 124 | 125 | 126 | * Visibility: **public** 127 | * This method is **static**. 128 | 129 | 130 | #### Arguments 131 | * $path **mixed** 132 | 133 | 134 | 135 | ### parse 136 | 137 | \phpGPX\Models\GpxFile phpGPX\phpGPX::parse($xml) 138 | 139 | Parse GPX data string. 140 | 141 | 142 | 143 | * Visibility: **public** 144 | * This method is **static**. 145 | 146 | 147 | #### Arguments 148 | * $xml **mixed** 149 | 150 | 151 | 152 | ### getSignature 153 | 154 | string phpGPX\phpGPX::getSignature() 155 | 156 | Create library signature from name and version. 157 | 158 | 159 | 160 | * Visibility: **public** 161 | * This method is **static**. 162 | 163 | 164 | 165 | -------------------------------------------------------------------------------- /tests/UnitTests/phpGPX/Parsers/PersonParserTest.php: -------------------------------------------------------------------------------- 1 | 4 | */ 5 | 6 | namespace UnitTests\phpGPX\Parsers; 7 | 8 | use phpGPX\Models\GpxFile; 9 | use phpGPX\Models\Metadata; 10 | use phpGPX\Models\Person; 11 | use phpGPX\Parsers\PersonParser; 12 | 13 | class PersonParserTest extends AbstractParserTest 14 | { 15 | protected $testModelClass = Person::class; 16 | protected $testParserClass = PersonParser::class; 17 | 18 | /** 19 | * @var Person 20 | */ 21 | protected $testModelInstance; 22 | 23 | public static function createTestInstance() 24 | { 25 | $person = new Person(); 26 | $person->name = "Jakub Dubec"; 27 | $person->email = EmailParserTest::createTestInstance(); 28 | $person->links[] = LinkParserTest::createTestInstance(); 29 | $person->name = 'Jakub Dubec'; 30 | 31 | return $person; 32 | } 33 | 34 | protected function setUp(): void 35 | { 36 | parent::setUp(); 37 | 38 | $this->testModelInstance = self::createTestInstance(); 39 | } 40 | 41 | public function testParse() 42 | { 43 | $person = PersonParser::parse($this->testXmlFile->author); 44 | 45 | $this->assertNotEmpty($person); 46 | 47 | // Primitive attributes 48 | $this->assertEquals($this->testModelInstance->name, $person->name); 49 | 50 | // Email 51 | $this->assertEquals($this->testModelInstance->email->id, $person->email->id); 52 | $this->assertEquals($this->testModelInstance->email->domain, $person->email->domain); 53 | 54 | // Link 55 | $this->assertEquals($this->testModelInstance->links[0]->type, $person->links[0]->type); 56 | $this->assertEquals($this->testModelInstance->links[0]->text, $person->links[0]->text); 57 | $this->assertEquals($this->testModelInstance->links[0]->href, $person->links[0]->href); 58 | 59 | // toArray functions 60 | $this->assertEquals($this->testModelInstance->toArray(), $person->toArray()); 61 | $this->assertEquals($this->testModelInstance->email->toArray(), $person->email->toArray()); 62 | $this->assertEquals($this->testModelInstance->links[0]->toArray(), $person->links[0]->toArray()); 63 | } 64 | 65 | /** 66 | * Returns output of ::toXML method of tested parser. 67 | * @depends testParse 68 | * @param \DOMDocument $document 69 | * @return \DOMElement 70 | */ 71 | protected function convertToXML(\DOMDocument $document) 72 | { 73 | return PersonParser::toXML($this->testModelInstance, $document); 74 | } 75 | 76 | /** 77 | * @url https://github.com/Sibyx/phpGPX/issues/48 78 | */ 79 | public function testEmptyLinks() 80 | { 81 | $gpx_file = new GpxFile(); 82 | 83 | $gpx_file->metadata = new Metadata(); 84 | $gpx_file->metadata->author = new Person(); 85 | $gpx_file->metadata->author->name = "Arthur Dent"; 86 | 87 | $this->assertNotNull($gpx_file->toXML()->saveXML()); 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /tests/UnitTests/phpGPX/Parsers/SegmentParserTest.php: -------------------------------------------------------------------------------- 1 | points = [ 28 | PointParserTest::createTestInstanceWithValues(46.571948, 8.414757, 2419, "2017-08-13T07:10:41.000Z"), 29 | PointParserTest::createTestInstanceWithValues(46.572016, 8.414866, 2418.8833883882, "2017-08-13T07:10:54.000Z"), 30 | PointParserTest::createTestInstanceWithValues(46.572088, 8.414911, 2419.8999900064, "2017-08-13T07:11:56.000Z"), 31 | PointParserTest::createTestInstanceWithValues(46.572069, 8.414912, 2422, "2017-08-13T07:12:15.000Z"), 32 | PointParserTest::createTestInstanceWithValues(46.572054, 8.414888, 2425, "2017-08-13T07:12:18.000Z") 33 | ]; 34 | $segment->recalculateStats(); 35 | 36 | return $segment; 37 | } 38 | 39 | protected function setUp(): void 40 | { 41 | parent::setUp(); 42 | 43 | $this->testModelInstance = self::createTestInstance(); 44 | } 45 | 46 | public function testParse() 47 | { 48 | $segment = SegmentParser::parse($this->testXmlFile->trkseg); 49 | 50 | $this->assertNotEmpty($segment); 51 | 52 | // Test second point 53 | $point = $segment[0]->points[1]; 54 | $this->assertEquals($this->testModelInstance->points[1]->latitude, $point->latitude); 55 | $this->assertEquals($this->testModelInstance->points[1]->longitude, $point->longitude); 56 | $this->assertEquals($this->testModelInstance->points[1]->elevation, $point->elevation); 57 | $this->assertEquals($this->testModelInstance->points[1]->time, $point->time); 58 | 59 | // Stats 60 | $this->assertNotEmpty($this->testModelInstance->stats); 61 | 62 | // Check the boundaries 63 | $nw = $this->testModelInstance->stats->bounds[0]; 64 | $se = $this->testModelInstance->stats->bounds[1]; 65 | $this->assertEquals(46.572088, $nw["lat"]); 66 | $this->assertEquals(8.414757, $nw["lng"]); 67 | $this->assertEquals(46.571948, $se["lat"]); 68 | $this->assertEquals(8.414912, $se["lng"]); 69 | } 70 | 71 | /** 72 | * Returns output of ::toXML method of tested parser. 73 | * @depends testParse 74 | * @param \DOMDocument $document 75 | * @return \DOMElement 76 | */ 77 | protected function convertToXML(\DOMDocument $document) 78 | { 79 | return SegmentParser::toXML($this->testModelInstance, $document); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /example/waypoints_create.php: -------------------------------------------------------------------------------- 1 | 4 | */ 5 | 6 | use phpGPX\Models\GpxFile; 7 | use phpGPX\Models\Link; 8 | use phpGPX\Models\Metadata; 9 | use phpGPX\Models\Point; 10 | use phpGPX\Models\Segment; 11 | use phpGPX\Models\Track; 12 | 13 | require_once '../vendor/autoload.php'; 14 | 15 | $sample_data = [ 16 | [ 17 | 'longitude' => 9.860624216140083, 18 | 'latitude' => 54.9328621088893, 19 | 'elevation' => 0, 20 | 'time' => new \DateTime("+ 1 MINUTE") 21 | ], 22 | [ 23 | 'latitude' => 54.83293237320851, 24 | 'longitude' => 9.76092208681491, 25 | 'elevation' => 10.0, 26 | 'time' => new \DateTime("+ 2 MINUTE") 27 | ], 28 | [ 29 | 'latitude' => 54.73327743521187, 30 | 'longitude' => 9.66187816543752, 31 | 'elevation' => 42.42, 32 | 'time' => new \DateTime("+ 3 MINUTE") 33 | ], 34 | [ 35 | 'latitude' => 54.63342326167919, 36 | 'longitude' => 9.562439849679859, 37 | 'elevation' => 12, 38 | 'time' => new \DateTime("+ 4 MINUTE") 39 | ] 40 | ]; 41 | 42 | // Creating sample link object for metadata 43 | $link = new Link(); 44 | $link->href = "https://sibyx.github.io/phpgpx"; 45 | $link->text = 'phpGPX Docs'; 46 | 47 | // GpxFile contains data and handles serialization of objects 48 | $gpx_file = new GpxFile(); 49 | 50 | // Creating sample Metadata object 51 | $gpx_file->metadata = new Metadata(); 52 | 53 | // Time attribute is always \DateTime object! 54 | $gpx_file->metadata->time = new \DateTime(); 55 | 56 | // Description of GPX file 57 | $gpx_file->metadata->description = "My pretty awesome GPX file, created using phpGPX library!"; 58 | 59 | // Adding link created before to links array of metadata 60 | // Metadata of GPX file can contain more than one link 61 | $gpx_file->metadata->links[] = $link; 62 | 63 | // Creating track 64 | $track = new Track(); 65 | 66 | // Name of track 67 | $track->name = sprintf("Some random points in logical order. Input array should be already ordered!"); 68 | 69 | // Type of data stored in track 70 | $track->type = 'RUN'; 71 | 72 | // Source of GPS coordinates 73 | $track->source = sprintf("MySpecificGarminDevice"); 74 | 75 | $wp = []; 76 | foreach ($sample_data as $sample_point) { 77 | // Creating trackpoint 78 | $point = new Point(Point::WAYPOINT); 79 | $point->latitude = $sample_point['latitude']; 80 | $point->longitude = $sample_point['longitude']; 81 | $point->elevation = $sample_point['elevation']; 82 | $point->time = $sample_point['time']; 83 | 84 | $wp[] = $point; 85 | } 86 | 87 | $gpx_file->waypoints = $wp; 88 | 89 | // // Add segment to segment array of track 90 | // $track->segments[] = $segment; 91 | 92 | // // Add track to file 93 | // $gpx_file->tracks[] = $track; 94 | 95 | // GPX output 96 | $gpx_file->save('waypoint_test.gpx', \phpGPX\phpGPX::XML_FORMAT); 97 | -------------------------------------------------------------------------------- /docs/phpGPX-Parsers-PointParser.md: -------------------------------------------------------------------------------- 1 | phpGPX\Parsers\PointParser 2 | =============== 3 | 4 | 5 | 6 | 7 | 8 | 9 | * Class name: PointParser 10 | * Namespace: phpGPX\Parsers 11 | * This is an **abstract** class 12 | 13 | 14 | 15 | 16 | 17 | Properties 18 | ---------- 19 | 20 | 21 | ### $attributeMapper 22 | 23 | private mixed $attributeMapper = array('ele' => array('name' => 'elevation', 'type' => 'float'), 'time' => array('name' => 'time', 'type' => 'object'), 'magvar' => array('name' => 'magVar', 'type' => 'float'), 'geoidheight' => array('name' => 'geoidHeight', 'type' => 'float'), 'name' => array('name' => 'name', 'type' => 'string'), 'cmt' => array('name' => 'comment', 'type' => 'string'), 'desc' => array('name' => 'description', 'type' => 'string'), 'src' => array('name' => 'source', 'type' => 'string'), 'link' => array('name' => 'links', 'type' => 'object'), 'sym' => array('name' => 'symbol', 'type' => 'string'), 'type' => array('name' => 'type', 'type' => 'string'), 'fix' => array('name' => 'fix', 'type' => 'string'), 'sat' => array('name' => 'satellitesNumber', 'type' => 'integer'), 'hdop' => array('name' => 'hdop', 'type' => 'float'), 'vdop' => array('name' => 'vdop', 'type' => 'float'), 'pdop' => array('name' => 'pdop', 'type' => 'float'), 'ageofdgpsdata' => array('name' => 'ageOfGpsData', 'type' => 'float'), 'dgpsid' => array('name' => 'dgpsid', 'type' => 'integer'), 'extensions' => array('name' => 'extensions', 'type' => 'object')) 24 | 25 | 26 | 27 | 28 | 29 | * Visibility: **private** 30 | * This property is **static**. 31 | 32 | 33 | ### $typeMapper 34 | 35 | private mixed $typeMapper = array('trkpt' => \phpGPX\Models\Point::TRACKPOINT, 'wpt' => \phpGPX\Models\Point::WAYPOINT, 'rtp' => \phpGPX\Models\Point::ROUTEPOINT) 36 | 37 | 38 | 39 | 40 | 41 | * Visibility: **private** 42 | * This property is **static**. 43 | 44 | 45 | Methods 46 | ------- 47 | 48 | 49 | ### parse 50 | 51 | mixed phpGPX\Parsers\PointParser::parse(\SimpleXMLElement $node) 52 | 53 | 54 | 55 | 56 | 57 | * Visibility: **public** 58 | * This method is **static**. 59 | 60 | 61 | #### Arguments 62 | * $node **SimpleXMLElement** 63 | 64 | 65 | 66 | ### toXML 67 | 68 | \DOMElement phpGPX\Parsers\PointParser::toXML(\phpGPX\Models\Point $point, \DOMDocument $document) 69 | 70 | 71 | 72 | 73 | 74 | * Visibility: **public** 75 | * This method is **static**. 76 | 77 | 78 | #### Arguments 79 | * $point **[phpGPX\Models\Point](phpGPX-Models-Point.md)** 80 | * $document **DOMDocument** 81 | 82 | 83 | 84 | ### toXMLArray 85 | 86 | array phpGPX\Parsers\PointParser::toXMLArray(array $points, \DOMDocument $document) 87 | 88 | 89 | 90 | 91 | 92 | * Visibility: **public** 93 | * This method is **static**. 94 | 95 | 96 | #### Arguments 97 | * $points **array** 98 | * $document **DOMDocument** 99 | 100 | 101 | -------------------------------------------------------------------------------- /docs/phpGPX-Models-Metadata.md: -------------------------------------------------------------------------------- 1 | phpGPX\Models\Metadata 2 | =============== 3 | 4 | Class Metadata 5 | Information about the GPX file, author, and copyright restrictions goes in the metadata section. 6 | 7 | Providing rich, meaningful information about your GPX files allows others to search for and use your GPS data. 8 | 9 | 10 | * Class name: Metadata 11 | * Namespace: phpGPX\Models 12 | * This class implements: [phpGPX\Models\Summarizable](phpGPX-Models-Summarizable.md) 13 | 14 | 15 | 16 | 17 | Properties 18 | ---------- 19 | 20 | 21 | ### $name 22 | 23 | public string $name 24 | 25 | The name of the GPX file. 26 | 27 | Original GPX 1.1 attribute. 28 | 29 | * Visibility: **public** 30 | 31 | 32 | ### $description 33 | 34 | public string $description 35 | 36 | A description of the contents of the GPX file. 37 | 38 | Original GPX 1.1 attribute. 39 | 40 | * Visibility: **public** 41 | 42 | 43 | ### $author 44 | 45 | public \phpGPX\Models\Person $author 46 | 47 | The person or organization who created the GPX file. 48 | 49 | An original GPX 1.1 attribute. 50 | 51 | * Visibility: **public** 52 | 53 | 54 | ### $copyright 55 | 56 | public \phpGPX\Models\Copyright $copyright 57 | 58 | Copyright and license information governing use of the file. 59 | 60 | Original GPX 1.1 attribute. 61 | 62 | * Visibility: **public** 63 | 64 | 65 | ### $links 66 | 67 | public array $links 68 | 69 | Original GPX 1.1 attribute. 70 | 71 | 72 | 73 | * Visibility: **public** 74 | 75 | 76 | ### $time 77 | 78 | public \DateTime $time 79 | 80 | Date of GPX creation 81 | 82 | 83 | 84 | * Visibility: **public** 85 | 86 | 87 | ### $keywords 88 | 89 | public string $keywords 90 | 91 | Keywords associated with the file. Search engines or databases can use this information to classify the data. 92 | 93 | 94 | 95 | * Visibility: **public** 96 | 97 | 98 | ### $bounds 99 | 100 | public \phpGPX\Models\Bounds $bounds 101 | 102 | Minimum and maximum coordinates which describe the extent of the coordinates in the file. 103 | 104 | Original GPX 1.1 attribute. 105 | 106 | * Visibility: **public** 107 | 108 | 109 | ### $extensions 110 | 111 | public \phpGPX\Models\Extensions $extensions 112 | 113 | Extensions. 114 | 115 | 116 | 117 | * Visibility: **public** 118 | 119 | 120 | Methods 121 | ------- 122 | 123 | 124 | ### __construct 125 | 126 | mixed phpGPX\Models\Metadata::__construct() 127 | 128 | Metadata constructor. 129 | 130 | 131 | 132 | * Visibility: **public** 133 | 134 | 135 | 136 | 137 | ### toArray 138 | 139 | array phpGPX\Models\Summarizable::toArray() 140 | 141 | Serialize object to array 142 | 143 | 144 | 145 | * Visibility: **public** 146 | * This method is defined by [phpGPX\Models\Summarizable](phpGPX-Models-Summarizable.md) 147 | 148 | 149 | 150 | -------------------------------------------------------------------------------- /tests/UnitTests/phpGPX/Helpers/SerializationHelperTest.php: -------------------------------------------------------------------------------- 1 | 4 | */ 5 | 6 | namespace UnitTests\phpGPX\Helpers; 7 | 8 | use phpGPX\Helpers\SerializationHelper; 9 | use PHPUnit\Framework\TestCase; 10 | 11 | class SerializationHelperTest extends TestCase 12 | { 13 | public function testIntegerOrNull() 14 | { 15 | $this->assertNull(SerializationHelper::integerOrNull("")); 16 | $this->assertNull(SerializationHelper::integerOrNull(null)); 17 | $this->assertNull(SerializationHelper::integerOrNull("BLA")); 18 | $this->assertIsInt(SerializationHelper::integerOrNull(5)); 19 | $this->assertIsInt(SerializationHelper::integerOrNull("5")); 20 | } 21 | 22 | public function testFloatOrNull() 23 | { 24 | $this->assertNull(SerializationHelper::floatOrNull("")); 25 | $this->assertNull(SerializationHelper::floatOrNull(null)); 26 | $this->assertNull(SerializationHelper::floatOrNull("BLA")); 27 | $this->assertIsFloat(SerializationHelper::floatOrNull(5.6)); 28 | $this->assertIsFloat(SerializationHelper::floatOrNull(5)); 29 | $this->assertIsFloat(SerializationHelper::floatOrNull("5.6")); 30 | $this->assertIsFloat(SerializationHelper::floatOrNull("5")); 31 | } 32 | 33 | public function testStringOrNull() 34 | { 35 | $this->assertNull(SerializationHelper::stringOrNull(null)); 36 | $this->assertIsString(SerializationHelper::stringOrNull("")); 37 | $this->assertIsString(SerializationHelper::stringOrNull("Bla bla")); 38 | } 39 | 40 | /** 41 | * @dataProvider dataProviderFilterNotNull 42 | */ 43 | public function testFilterNotNull($expected, $actual) 44 | { 45 | $this->assertEquals($expected, SerializationHelper::filterNotNull($actual)); 46 | } 47 | 48 | public function dataProviderFilterNotNull() 49 | { 50 | return [ 51 | 'numeric 1' => [ 52 | [], 53 | [null], 54 | ], 55 | 'numeric 2' => [ 56 | [], 57 | [null, [null]], 58 | ], 59 | 'numeric 3' => [ 60 | [1 => 1], 61 | [null, 1], 62 | ], 63 | 'numeric 4' => [ 64 | [1 => 1, 3 => 2], 65 | [null, 1, null, 2, null], 66 | ], 67 | 'numeric 5' => [ 68 | [1 => 1, 3 => 2, 5 => [0 => 3, 2 => 4], 6 => 5], 69 | [null, 1, null, 2, null, [3, null, 4], 5, null], 70 | ], 71 | 'associative 1' => [ 72 | [], 73 | ["foo" => null], 74 | ], 75 | 'associative 2' => [ 76 | [], 77 | ["foo" => null, ["bar" => null]], 78 | ], 79 | 'associative 3' => [ 80 | ["bar" => 1], 81 | ["foo" => null, "bar" => 1], 82 | ], 83 | 'associative 4' => [ 84 | ["bar" => 1, "caw" => 2], 85 | ["foo" => null, "bar" => 1, "baz" => null, "caw" => 2, "doo" => null], 86 | ], 87 | 'associative 5' => [ 88 | ["bar" => 1, "caw" => 2, "ere" => ["foo" => 3, "baz" => 4], "moo" => 5], 89 | ["foo" => null, "bar" => 1, "baz" => null, "caw" => 2, "doo" => null, "ere" => ["foo" => 3, "bar" => null, "baz" => 4], "moo" => 5, "boo" => null], 90 | ], 91 | ]; 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /src/phpGPX/Parsers/Extensions/TrackPointExtensionParser.php: -------------------------------------------------------------------------------- 1 | 5 | */ 6 | 7 | namespace phpGPX\Parsers\Extensions; 8 | 9 | use phpGPX\Models\Extensions\TrackPointExtension; 10 | use phpGPX\Parsers\ExtensionParser; 11 | 12 | class TrackPointExtensionParser 13 | { 14 | private static $attributeMapper = [ 15 | 'atemp' => [ 16 | 'name' => 'aTemp', 17 | 'type' => 'float' 18 | ], 19 | 'wtemp' => [ 20 | 'name' => 'wTemp', 21 | 'type' => 'float' 22 | ], 23 | 'depth' => [ 24 | 'name' => 'depth', 25 | 'type' => 'float' 26 | ], 27 | 'hr' => [ 28 | 'name' => 'hr', 29 | 'type' => 'float' 30 | ], 31 | 'cad' => [ 32 | 'name' => 'cad', 33 | 'type' => 'float' 34 | ], 35 | 'speed' => [ 36 | 'name' => 'speed', 37 | 'type' => 'float' 38 | ], 39 | 'course' => [ 40 | 'name' => 'course', 41 | 'type' => 'int' 42 | ], 43 | 'bearing' => [ 44 | 'name' => 'bearing', 45 | 'type' => 'int' 46 | ] 47 | ]; 48 | 49 | /** 50 | * @param \SimpleXMLElement $node 51 | * @return TrackPointExtension 52 | */ 53 | public static function parse($node) 54 | { 55 | $extension = new TrackPointExtension(); 56 | 57 | foreach (self::$attributeMapper as $key => $attribute) { 58 | $extension->{$attribute['name']} = isset($node->$key) ? $node->$key : null; 59 | if (!is_null($extension->{$attribute['name']})) { 60 | settype($extension->{$attribute['name']}, $attribute['type']); 61 | } 62 | 63 | // Remove in v1.0 64 | if ($key == 'hr') { 65 | $extension->heartRate = $extension->hr; 66 | } 67 | 68 | // Remove in v1.0 69 | if ($key == 'cad') { 70 | $extension->cadence = $extension->cad; 71 | } 72 | 73 | // Remove in v1.0 74 | if ($key == 'atemp') { 75 | $extension->avgTemperature = $extension->aTemp; 76 | } 77 | } 78 | 79 | return $extension; 80 | } 81 | 82 | /** 83 | * @param TrackPointExtension $extension 84 | * @param \DOMDocument $document 85 | * @return \DOMElement 86 | */ 87 | public static function toXML(TrackPointExtension $extension, \DOMDocument &$document) 88 | { 89 | $node = $document->createElement("gpxtpx:TrackPointExtension"); 90 | 91 | ExtensionParser::$usedNamespaces[TrackPointExtension::EXTENSION_NAME] = [ 92 | 'namespace' => TrackPointExtension::EXTENSION_NAMESPACE, 93 | 'xsd' => TrackPointExtension::EXTENSION_NAMESPACE_XSD, 94 | 'name' => TrackPointExtension::EXTENSION_NAME, 95 | 'prefix' => TrackPointExtension::EXTENSION_NAMESPACE_PREFIX 96 | ]; 97 | 98 | foreach (self::$attributeMapper as $key => $attribute) { 99 | if (!is_null($extension->{$attribute['name']})) { 100 | $child = $document->createElement( 101 | sprintf("%s:%s", TrackPointExtension::EXTENSION_NAMESPACE_PREFIX, $key), 102 | $extension->{$attribute['name']} 103 | ); 104 | $node->appendChild($child); 105 | } 106 | } 107 | 108 | return $node; 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /src/phpGPX/Models/Metadata.php: -------------------------------------------------------------------------------- 1 | 5 | */ 6 | 7 | namespace phpGPX\Models; 8 | 9 | use phpGPX\Helpers\DateTimeHelper; 10 | use phpGPX\Helpers\SerializationHelper; 11 | 12 | /** 13 | * Class Metadata 14 | * Information about the GPX file, author, and copyright restrictions goes in the metadata section. 15 | * Providing rich, meaningful information about your GPX files allows others to search for and use your GPS data. 16 | * @package phpGPX\Models 17 | */ 18 | class Metadata implements Summarizable 19 | { 20 | 21 | /** 22 | * The name of the GPX file. 23 | * Original GPX 1.1 attribute. 24 | * @var string|null 25 | */ 26 | public $name; 27 | 28 | /** 29 | * A description of the contents of the GPX file. 30 | * Original GPX 1.1 attribute. 31 | * @var string|null 32 | */ 33 | public $description; 34 | 35 | /** 36 | * The person or organization who created the GPX file. 37 | * An original GPX 1.1 attribute. 38 | * @var Person|null 39 | */ 40 | public $author; 41 | 42 | /** 43 | * Copyright and license information governing use of the file. 44 | * Original GPX 1.1 attribute. 45 | * @var Copyright|null 46 | */ 47 | public $copyright; 48 | 49 | /** 50 | * Original GPX 1.1 attribute. 51 | * @var Link[]|null 52 | */ 53 | public $links; 54 | 55 | /** 56 | * Date of GPX creation 57 | * @var \DateTime 58 | */ 59 | public $time; 60 | 61 | /** 62 | * Keywords associated with the file. Search engines or databases can use this information to classify the data. 63 | * @var string|null 64 | */ 65 | public $keywords; 66 | 67 | /** 68 | * Minimum and maximum coordinates which describe the extent of the coordinates in the file. 69 | * Original GPX 1.1 attribute. 70 | * @var Bounds|null 71 | */ 72 | public $bounds; 73 | 74 | /** 75 | * Extensions. 76 | * @var Extensions|null 77 | */ 78 | public $extensions; 79 | 80 | /** 81 | * Metadata constructor. 82 | */ 83 | public function __construct() 84 | { 85 | $this->name = null; 86 | $this->description = null; 87 | $this->author = null; 88 | $this->copyright = null; 89 | $this->links = []; 90 | $this->time = null; 91 | $this->keywords = null; 92 | $this->bounds = null; 93 | $this->extensions = null; 94 | } 95 | 96 | 97 | /** 98 | * Serialize object to array 99 | * @return array 100 | */ 101 | public function toArray() 102 | { 103 | return [ 104 | 'name' => SerializationHelper::stringOrNull($this->name), 105 | 'desc' => SerializationHelper::stringOrNull($this->description), 106 | 'author' => SerializationHelper::serialize($this->author), 107 | 'copyright' => SerializationHelper::serialize($this->copyright), 108 | 'links' => SerializationHelper::serialize($this->links), 109 | 'time' => DateTimeHelper::formatDateTime($this->time), 110 | 'keywords' => SerializationHelper::stringOrNull($this->keywords), 111 | 'bounds' => SerializationHelper::serialize($this->bounds), 112 | 'extensions' => SerializationHelper::serialize($this->extensions) 113 | ]; 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## 1.3.0 : 2023-07-19 4 | 5 | Changed minimal PHP version to `^7.1` in `composer.json`. Library still should work with PHP5.5+, if you have troubles 6 | while installing check the `--ignore-platform-reqs` attribute of [compose](https://getcomposer.org/doc/03-cli.md). 7 | 8 | - **Added**: [Coordinates for remarqued statistic points](https://github.com/Sibyx/phpGPX/pull/64) (minAltitude, maxAltitude, startedAt, finishedAt) 9 | 10 | ## 1.2.1 : 2022-07-30 11 | 12 | - **Fixed**: Fixed `VERSION` string in `phpGPX.php` 13 | 14 | ## 1.2.0 : 2022-07-30 15 | 16 | - **Changed**: [Real distance calculation #37](https://github.com/Sibyx/phpGPX/issues/37) (DistanceCalculator refactor) 17 | 18 | ## 1.1.3 : 2021-07-29 19 | 20 | - **Fixed**: [Fix negative duration #58](https://github.com/Sibyx/phpGPX/pull/58) by [@neronmoon](https://github.com/neronmoon) 21 | 22 | ## 1.1.2 : 2021-02-28 23 | 24 | - **Fixed**: [do SORT_BY_TIMESTAMP only for tracks with timestamps #52](https://github.com/Sibyx/phpGPX/pull/52) 25 | 26 | ## 1.1.1 : 2021-02-15 27 | 28 | - **Fixed**: Fixed `VERSION` string in `phpGPX.php` 29 | 30 | ## 1.1.0 : 2021-02-05 31 | 32 | - **Added**: [Limiting maximum elevation difference to protect from spikes](https://github.com/Sibyx/phpGPX/pull/49) 33 | 34 | ## 1.0.1 35 | 36 | - **Fixed**: Fixed PersonParser::toXML() if there are no links provided 37 | [Error when $person->links is null #48](https://github.com/Sibyx/phpGPX/issues/48) 38 | 39 | ## 1.0 40 | 41 | I am not very proud of idea having a major release in such terrible state. This release is just freeze from 2017 42 | compatible API and behaviour with some bugfixies. It looks like some people use the library and I want to perform some 43 | radical refactoring. See you in `2.x`. 44 | 45 | - **Fixed**: Do not return extra `:` while parsing unsupported extensions if there is no namespace for child element 46 | - **Fixed**: Fixed Copyright test 47 | 48 | ## 1.0-RC5 49 | 50 | - **Changed:** Moved PHPUnit to development dependencies. 51 | 52 | ## 1.0-RC4 53 | 54 | - **Changed:** [Change the way to deal with extensions ](https://github.com/Sibyx/phpGPX/pull/19) 55 | - **Fixed:** [RoutePoints and TripExtensions WIP](https://github.com/Sibyx/phpGPX/issues/22) 56 | - **Fixed:** [Route point rtep versus rtept](https://github.com/Sibyx/phpGPX/issues/21) 57 | - **Fixed:** [Empty array on load route](https://github.com/Sibyx/phpGPX/issues/20) 58 | - **Fixed:** Do not load zero altitude in statistics as NULL 59 | 60 | ## 1.0-RC3 61 | 62 | - **Added:** [Cumulative Elevation in stats](https://github.com/Sibyx/phpGPX/pull/12) with pull request #12 by @Shaydu 63 | - **Fixed:** [Fix for unterminated entity references](https://github.com/Sibyx/phpGPX/pull/13) with #13 by @benlumley 64 | - **Fixed:** [split loading and parsing in separate methods so a string may be loaded as gpx data](https://github.com/Sibyx/phpGPX/pull/9) with #9 by @lommes 65 | - **Fixed:** HeartRate [typo that lead to error](https://github.com/Sibyx/phpGPX/issues/14) 66 | - **Fixed:** Skipping RC2 in packagist [Missing version in packagist](https://github.com/Sibyx/phpGPX/issues/10) 67 | 68 | ## 1.0-RC2 69 | 70 | - **Fixed:** [waypoints not loaded correctly - they are ignored](https://github.com/Sibyx/phpGPX/issues/6) 71 | - Init of unit tests 72 | 73 | ## 1.0-RC1 74 | 75 | Initial release 76 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. 6 | 7 | ## Our Standards 8 | 9 | Examples of behavior that contributes to creating a positive environment include: 10 | 11 | * Using welcoming and inclusive language 12 | * Being respectful of differing viewpoints and experiences 13 | * Gracefully accepting constructive criticism 14 | * Focusing on what is best for the community 15 | * Showing empathy towards other community members 16 | 17 | Examples of unacceptable behavior by participants include: 18 | 19 | * The use of sexualized language or imagery and unwelcome sexual attention or advances 20 | * Trolling, insulting/derogatory comments, and personal or political attacks 21 | * Public or private harassment 22 | * Publishing others' private information, such as a physical or electronic address, without explicit permission 23 | * Other conduct which could reasonably be considered inappropriate in a professional setting 24 | 25 | ## Our Responsibilities 26 | 27 | Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. 28 | 29 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. 30 | 31 | ## Scope 32 | 33 | This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. 34 | 35 | ## Enforcement 36 | 37 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at jakub.dubec@gmail.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. 38 | 39 | Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. 40 | 41 | ## Attribution 42 | 43 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] 44 | 45 | [homepage]: http://contributor-covenant.org 46 | [version]: http://contributor-covenant.org/version/1/4/ 47 | -------------------------------------------------------------------------------- /docs/phpGPX-Models-Stats.md: -------------------------------------------------------------------------------- 1 | phpGPX\Models\Stats 2 | =============== 3 | 4 | Class Stats 5 | 6 | 7 | 8 | 9 | * Class name: Stats 10 | * Namespace: phpGPX\Models 11 | * This class implements: [phpGPX\Models\Summarizable](phpGPX-Models-Summarizable.md) 12 | 13 | 14 | 15 | 16 | Properties 17 | ---------- 18 | 19 | 20 | ### $distance 21 | 22 | public float $distance 23 | 24 | Distance in meters (m) 25 | 26 | 27 | 28 | * Visibility: **public** 29 | 30 | 31 | ### $averageSpeed 32 | 33 | public float $averageSpeed = null 34 | 35 | Average speed in meters per second (m/s) 36 | 37 | 38 | 39 | * Visibility: **public** 40 | 41 | 42 | ### $averagePace 43 | 44 | public float $averagePace = null 45 | 46 | Average pace in seconds per kilometer (s/km) 47 | 48 | 49 | 50 | * Visibility: **public** 51 | 52 | 53 | ### $minAltitude 54 | 55 | public integer $minAltitude = null 56 | 57 | Minimal altitude in meters (m) 58 | 59 | 60 | 61 | * Visibility: **public** 62 | 63 | ### $minAltitudeCoords 64 | 65 | public [float,float] $minAltitudeCoords = null 66 | 67 | Minimal altitude coordinates in associative array with keys: "lat" for latitude & "lng" for longitude 68 | 69 | 70 | 71 | * Visibility: **public** 72 | 73 | 74 | ### $maxAltitude 75 | 76 | public integer $maxAltitude = null 77 | 78 | Maximal altitude in meters (m) 79 | 80 | 81 | 82 | * Visibility: **public** 83 | 84 | ### $maxAltitudeCoords 85 | 86 | public [float,float] $maxAltitudeCoords = null 87 | 88 | Maximal altitude coordinates in associative array with keys: "lat" for latitude & "lng" for longitude 89 | 90 | 91 | 92 | * Visibility: **public** 93 | 94 | 95 | ### $cumulativeElevationGain 96 | 97 | public integer $cumulativeElevationGain = null 98 | 99 | Cumulative elevation gain in meters (m) 100 | 101 | 102 | 103 | * Visibility: **public** 104 | 105 | 106 | ### $startedAt 107 | 108 | public \DateTime $startedAt = null 109 | 110 | Started time 111 | 112 | 113 | 114 | * Visibility: **public** 115 | 116 | ### $startedAtCoords 117 | 118 | public [float,float] $startedAtCoords = null 119 | 120 | Started coordinates in associative array with keys: "lat" for latitude & "lng" for longitude 121 | 122 | 123 | 124 | * Visibility: **public** 125 | 126 | 127 | ### $finishedAt 128 | 129 | public \DateTime $finishedAt = null 130 | 131 | Ending time 132 | 133 | 134 | 135 | * Visibility: **public** 136 | 137 | ### $finishedAtCoords 138 | 139 | public [float,float] $finishedAtCoords = null 140 | 141 | Ending coordinates in associative array with keys: "lat" for latitude & "lng" for longitude 142 | 143 | 144 | 145 | * Visibility: **public** 146 | 147 | 148 | ### $duration 149 | 150 | public integer $duration = null 151 | 152 | Duration is seconds 153 | 154 | 155 | 156 | * Visibility: **public** 157 | 158 | 159 | Methods 160 | ------- 161 | 162 | 163 | ### reset 164 | 165 | mixed phpGPX\Models\Stats::reset() 166 | 167 | Reset all stats 168 | 169 | 170 | 171 | * Visibility: **public** 172 | 173 | 174 | 175 | 176 | ### toArray 177 | 178 | array phpGPX\Models\Summarizable::toArray() 179 | 180 | Serialize object to array 181 | 182 | 183 | 184 | * Visibility: **public** 185 | * This method is defined by [phpGPX\Models\Summarizable](phpGPX-Models-Summarizable.md) 186 | 187 | 188 | 189 | -------------------------------------------------------------------------------- /docs/phpGPX-Models-Collection.md: -------------------------------------------------------------------------------- 1 | phpGPX\Models\Collection 2 | =============== 3 | 4 | Class Collection 5 | 6 | 7 | 8 | 9 | * Class name: Collection 10 | * Namespace: phpGPX\Models 11 | * This is an **abstract** class 12 | * This class implements: [phpGPX\Models\Summarizable](phpGPX-Models-Summarizable.md), [phpGPX\Models\StatsCalculator](phpGPX-Models-StatsCalculator.md) 13 | 14 | 15 | 16 | 17 | Properties 18 | ---------- 19 | 20 | 21 | ### $name 22 | 23 | public string $name 24 | 25 | GPS name of route / track. 26 | 27 | An original GPX 1.1 attribute. 28 | 29 | * Visibility: **public** 30 | 31 | 32 | ### $comment 33 | 34 | public string $comment 35 | 36 | GPS comment for route. 37 | 38 | An original GPX 1.1 attribute. 39 | 40 | * Visibility: **public** 41 | 42 | 43 | ### $description 44 | 45 | public string $description 46 | 47 | Text description of route/track for user. Not sent to GPS. 48 | 49 | An original GPX 1.1 attribute. 50 | 51 | * Visibility: **public** 52 | 53 | 54 | ### $source 55 | 56 | public string $source 57 | 58 | Source of data. Included to give user some idea of reliability and accuracy of data. 59 | 60 | An original GPX 1.1 attribute. 61 | 62 | * Visibility: **public** 63 | 64 | 65 | ### $links 66 | 67 | public array $links 68 | 69 | Links to external information about the route/track. 70 | 71 | An original GPX 1.1 attribute. 72 | 73 | * Visibility: **public** 74 | 75 | 76 | ### $number 77 | 78 | public integer $number 79 | 80 | GPS route/track number. 81 | 82 | An original GPX 1.1 attribute. 83 | 84 | * Visibility: **public** 85 | 86 | 87 | ### $type 88 | 89 | public string $type 90 | 91 | Type (classification) of route/track. 92 | 93 | An original GPX 1.1 attribute. 94 | 95 | * Visibility: **public** 96 | 97 | 98 | ### $extensions 99 | 100 | public \phpGPX\Models\Extensions $extensions 101 | 102 | You can add extend GPX by adding your own elements from another schema here. 103 | 104 | An original GPX 1.1 attribute. 105 | 106 | * Visibility: **public** 107 | 108 | 109 | ### $stats 110 | 111 | public \phpGPX\Models\Stats $stats 112 | 113 | Objects contains calculated statistics for collection. 114 | 115 | 116 | 117 | * Visibility: **public** 118 | 119 | 120 | Methods 121 | ------- 122 | 123 | 124 | ### __construct 125 | 126 | mixed phpGPX\Models\Collection::__construct() 127 | 128 | Collection constructor. 129 | 130 | 131 | 132 | * Visibility: **public** 133 | 134 | 135 | 136 | 137 | ### getPoints 138 | 139 | array phpGPX\Models\Collection::getPoints() 140 | 141 | Return all points in collection. 142 | 143 | 144 | 145 | * Visibility: **public** 146 | * This method is **abstract**. 147 | 148 | 149 | 150 | 151 | ### toArray 152 | 153 | array phpGPX\Models\Summarizable::toArray() 154 | 155 | Serialize object to array 156 | 157 | 158 | 159 | * Visibility: **public** 160 | * This method is defined by [phpGPX\Models\Summarizable](phpGPX-Models-Summarizable.md) 161 | 162 | 163 | 164 | 165 | ### recalculateStats 166 | 167 | void phpGPX\Models\StatsCalculator::recalculateStats() 168 | 169 | Recalculate stats objects. 170 | 171 | 172 | 173 | * Visibility: **public** 174 | * This method is defined by [phpGPX\Models\StatsCalculator](phpGPX-Models-StatsCalculator.md) 175 | 176 | 177 | 178 | -------------------------------------------------------------------------------- /docs/phpGPX-Models-Track.md: -------------------------------------------------------------------------------- 1 | phpGPX\Models\Track 2 | =============== 3 | 4 | Class Track 5 | 6 | 7 | 8 | 9 | * Class name: Track 10 | * Namespace: phpGPX\Models 11 | * Parent class: [phpGPX\Models\Collection](phpGPX-Models-Collection.md) 12 | 13 | 14 | 15 | 16 | 17 | Properties 18 | ---------- 19 | 20 | 21 | ### $segments 22 | 23 | public array $segments 24 | 25 | Array of Track segments 26 | 27 | 28 | 29 | * Visibility: **public** 30 | 31 | 32 | ### $name 33 | 34 | public string $name 35 | 36 | GPS name of route / track. 37 | 38 | An original GPX 1.1 attribute. 39 | 40 | * Visibility: **public** 41 | 42 | 43 | ### $comment 44 | 45 | public string $comment 46 | 47 | GPS comment for route. 48 | 49 | An original GPX 1.1 attribute. 50 | 51 | * Visibility: **public** 52 | 53 | 54 | ### $description 55 | 56 | public string $description 57 | 58 | Text description of route/track for user. Not sent to GPS. 59 | 60 | An original GPX 1.1 attribute. 61 | 62 | * Visibility: **public** 63 | 64 | 65 | ### $source 66 | 67 | public string $source 68 | 69 | Source of data. Included to give user some idea of reliability and accuracy of data. 70 | 71 | An original GPX 1.1 attribute. 72 | 73 | * Visibility: **public** 74 | 75 | 76 | ### $links 77 | 78 | public array $links 79 | 80 | Links to external information about the route/track. 81 | 82 | An original GPX 1.1 attribute. 83 | 84 | * Visibility: **public** 85 | 86 | 87 | ### $number 88 | 89 | public integer $number 90 | 91 | GPS route/track number. 92 | 93 | An original GPX 1.1 attribute. 94 | 95 | * Visibility: **public** 96 | 97 | 98 | ### $type 99 | 100 | public string $type 101 | 102 | Type (classification) of route/track. 103 | 104 | An original GPX 1.1 attribute. 105 | 106 | * Visibility: **public** 107 | 108 | 109 | ### $extensions 110 | 111 | public \phpGPX\Models\Extensions $extensions 112 | 113 | You can add extend GPX by adding your own elements from another schema here. 114 | 115 | An original GPX 1.1 attribute. 116 | 117 | * Visibility: **public** 118 | 119 | 120 | ### $stats 121 | 122 | public \phpGPX\Models\Stats $stats 123 | 124 | Objects contains calculated statistics for collection. 125 | 126 | 127 | 128 | * Visibility: **public** 129 | 130 | 131 | Methods 132 | ------- 133 | 134 | 135 | ### __construct 136 | 137 | mixed phpGPX\Models\Collection::__construct() 138 | 139 | Collection constructor. 140 | 141 | 142 | 143 | * Visibility: **public** 144 | * This method is defined by [phpGPX\Models\Collection](phpGPX-Models-Collection.md) 145 | 146 | 147 | 148 | 149 | ### getPoints 150 | 151 | array phpGPX\Models\Collection::getPoints() 152 | 153 | Return all points in collection. 154 | 155 | 156 | 157 | * Visibility: **public** 158 | * This method is **abstract**. 159 | * This method is defined by [phpGPX\Models\Collection](phpGPX-Models-Collection.md) 160 | 161 | 162 | 163 | 164 | ### toArray 165 | 166 | array phpGPX\Models\Summarizable::toArray() 167 | 168 | Serialize object to array 169 | 170 | 171 | 172 | * Visibility: **public** 173 | * This method is defined by [phpGPX\Models\Summarizable](phpGPX-Models-Summarizable.md) 174 | 175 | 176 | 177 | 178 | ### recalculateStats 179 | 180 | void phpGPX\Models\StatsCalculator::recalculateStats() 181 | 182 | Recalculate stats objects. 183 | 184 | 185 | 186 | * Visibility: **public** 187 | * This method is defined by [phpGPX\Models\StatsCalculator](phpGPX-Models-StatsCalculator.md) 188 | 189 | 190 | 191 | -------------------------------------------------------------------------------- /docs/phpGPX-Models-Route.md: -------------------------------------------------------------------------------- 1 | phpGPX\Models\Route 2 | =============== 3 | 4 | Class Route 5 | 6 | 7 | 8 | 9 | * Class name: Route 10 | * Namespace: phpGPX\Models 11 | * Parent class: [phpGPX\Models\Collection](phpGPX-Models-Collection.md) 12 | 13 | 14 | 15 | 16 | 17 | Properties 18 | ---------- 19 | 20 | 21 | ### $points 22 | 23 | public array $points 24 | 25 | A list of route points. 26 | 27 | An original GPX 1.1 attribute. 28 | 29 | * Visibility: **public** 30 | 31 | 32 | ### $name 33 | 34 | public string $name 35 | 36 | GPS name of route / track. 37 | 38 | An original GPX 1.1 attribute. 39 | 40 | * Visibility: **public** 41 | 42 | 43 | ### $comment 44 | 45 | public string $comment 46 | 47 | GPS comment for route. 48 | 49 | An original GPX 1.1 attribute. 50 | 51 | * Visibility: **public** 52 | 53 | 54 | ### $description 55 | 56 | public string $description 57 | 58 | Text description of route/track for user. Not sent to GPS. 59 | 60 | An original GPX 1.1 attribute. 61 | 62 | * Visibility: **public** 63 | 64 | 65 | ### $source 66 | 67 | public string $source 68 | 69 | Source of data. Included to give user some idea of reliability and accuracy of data. 70 | 71 | An original GPX 1.1 attribute. 72 | 73 | * Visibility: **public** 74 | 75 | 76 | ### $links 77 | 78 | public array $links 79 | 80 | Links to external information about the route/track. 81 | 82 | An original GPX 1.1 attribute. 83 | 84 | * Visibility: **public** 85 | 86 | 87 | ### $number 88 | 89 | public integer $number 90 | 91 | GPS route/track number. 92 | 93 | An original GPX 1.1 attribute. 94 | 95 | * Visibility: **public** 96 | 97 | 98 | ### $type 99 | 100 | public string $type 101 | 102 | Type (classification) of route/track. 103 | 104 | An original GPX 1.1 attribute. 105 | 106 | * Visibility: **public** 107 | 108 | 109 | ### $extensions 110 | 111 | public \phpGPX\Models\Extensions $extensions 112 | 113 | You can add extend GPX by adding your own elements from another schema here. 114 | 115 | An original GPX 1.1 attribute. 116 | 117 | * Visibility: **public** 118 | 119 | 120 | ### $stats 121 | 122 | public \phpGPX\Models\Stats $stats 123 | 124 | Objects contains calculated statistics for collection. 125 | 126 | 127 | 128 | * Visibility: **public** 129 | 130 | 131 | Methods 132 | ------- 133 | 134 | 135 | ### __construct 136 | 137 | mixed phpGPX\Models\Collection::__construct() 138 | 139 | Collection constructor. 140 | 141 | 142 | 143 | * Visibility: **public** 144 | * This method is defined by [phpGPX\Models\Collection](phpGPX-Models-Collection.md) 145 | 146 | 147 | 148 | 149 | ### getPoints 150 | 151 | array phpGPX\Models\Collection::getPoints() 152 | 153 | Return all points in collection. 154 | 155 | 156 | 157 | * Visibility: **public** 158 | * This method is **abstract**. 159 | * This method is defined by [phpGPX\Models\Collection](phpGPX-Models-Collection.md) 160 | 161 | 162 | 163 | 164 | ### toArray 165 | 166 | array phpGPX\Models\Summarizable::toArray() 167 | 168 | Serialize object to array 169 | 170 | 171 | 172 | * Visibility: **public** 173 | * This method is defined by [phpGPX\Models\Summarizable](phpGPX-Models-Summarizable.md) 174 | 175 | 176 | 177 | 178 | ### recalculateStats 179 | 180 | void phpGPX\Models\StatsCalculator::recalculateStats() 181 | 182 | Recalculate stats objects. 183 | 184 | 185 | 186 | * Visibility: **public** 187 | * This method is defined by [phpGPX\Models\StatsCalculator](phpGPX-Models-StatsCalculator.md) 188 | 189 | 190 | 191 | -------------------------------------------------------------------------------- /src/phpGPX/Models/Extensions/TrackPointExtension.php: -------------------------------------------------------------------------------- 1 | 5 | */ 6 | 7 | namespace phpGPX\Models\Extensions; 8 | 9 | use phpGPX\Helpers\SerializationHelper; 10 | 11 | /** 12 | * Class TrackPointExtension 13 | * Extension version: v2 14 | * Based on namespace: http://www.garmin.com/xmlschemas/TrackPointExtensionv2.xsd 15 | * @package phpGPX\Models\Extensions 16 | */ 17 | class TrackPointExtension extends AbstractExtension 18 | { 19 | const EXTENSION_V1_NAMESPACE = 'http://www.garmin.com/xmlschemas/TrackPointExtension/v1'; 20 | const EXTENSION_V1_NAMESPACE_XSD = 'http://www.garmin.com/xmlschemas/TrackPointExtensionv1.xsd'; 21 | 22 | const EXTENSION_NAMESPACE = 'http://www.garmin.com/xmlschemas/TrackPointExtension/v2'; 23 | const EXTENSION_NAMESPACE_XSD = 'http://www.garmin.com/xmlschemas/TrackPointExtensionv2.xsd'; 24 | 25 | const EXTENSION_NAME = 'TrackPointExtension'; 26 | const EXTENSION_NAMESPACE_PREFIX = 'gpxtpx'; 27 | 28 | /** 29 | * Average temperature value measured in degrees Celsius. 30 | * @var float 31 | */ 32 | public $aTemp; 33 | 34 | /** 35 | * Average temperature value measured in degrees Celsius. 36 | * @deprecated use TrackPointExtension::$aTemp instead. Will be removed in v1.0 37 | * @see TrackPointExtension::$aTemp 38 | * @var float 39 | */ 40 | public $avgTemperature; 41 | 42 | /** 43 | * @var float 44 | */ 45 | public $wTemp; 46 | 47 | /** 48 | * Depth in meters. 49 | * @var float 50 | */ 51 | public $depth; 52 | 53 | /** 54 | * Heart rate in beats per minute. 55 | * @deprecated since v1.0RC3, use attribute TrackPointExtension::$hr instead, will be removed in v1.0 56 | * @see TrackPointExtension::$hr 57 | * @var float 58 | */ 59 | public $heartRate; 60 | 61 | /** 62 | * Heart rate in beats per minute. 63 | * @since v1.0RC3 64 | * @var float 65 | */ 66 | public $hr; 67 | 68 | /** 69 | * Cadence in revolutions per minute. 70 | * @deprecated since v1.0RC3, use attribute TrackPointExtension::$cad instead, will be removed in v1.0 71 | * @see TrackPointExtension::$cad 72 | * @var float 73 | */ 74 | public $cadence; 75 | 76 | /** 77 | * Cadence in revolutions per minute. 78 | * @var float 79 | */ 80 | public $cad; 81 | 82 | /** 83 | * Speed in meters per second. 84 | * @var float 85 | */ 86 | public $speed; 87 | 88 | /** 89 | * Course. This type contains an angle measured in degrees in a clockwise direction from the true north line. 90 | * @var int 91 | */ 92 | public $course; 93 | 94 | /** 95 | * Bearing. This type contains an angle measured in degrees in a clockwise direction from the true north line. 96 | * @var int 97 | */ 98 | public $bearing; 99 | 100 | /** 101 | * TrackPointExtension constructor. 102 | */ 103 | public function __construct() 104 | { 105 | parent::__construct(self::EXTENSION_NAMESPACE, self::EXTENSION_NAME); 106 | } 107 | 108 | /** 109 | * Serialize object to array 110 | * @return array 111 | */ 112 | public function toArray() 113 | { 114 | return [ 115 | 'aTemp' => SerializationHelper::floatOrNull($this->aTemp), 116 | 'wTemp' => SerializationHelper::floatOrNull($this->wTemp), 117 | 'depth' => SerializationHelper::floatOrNull($this->depth), 118 | 'hr' => SerializationHelper::floatOrNull($this->hr), 119 | 'cad' => SerializationHelper::floatOrNull($this->cad), 120 | 'speed' => SerializationHelper::floatOrNull($this->speed), 121 | 'course' => SerializationHelper::integerOrNull($this->course), 122 | 'bearing' => SerializationHelper::integerOrNull($this->bearing) 123 | ]; 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /tests/CreateWaypointTest.php: -------------------------------------------------------------------------------- 1 | 9.860624216140083, 20 | 'latitude' => 54.9328621088893, 21 | 'elevation' => 0, 22 | 'time' => new \DateTime("+ 1 MINUTE") 23 | ], 24 | [ 25 | 'latitude' => 54.83293237320851, 26 | 'longitude' => 9.76092208681491, 27 | 'elevation' => 10.0, 28 | 'time' => new \DateTime("+ 2 MINUTE") 29 | ], 30 | [ 31 | 'latitude' => 54.73327743521187, 32 | 'longitude' => 9.66187816543752, 33 | 'elevation' => 42.42, 34 | 'time' => new \DateTime("+ 3 MINUTE") 35 | ], 36 | [ 37 | 'latitude' => 54.63342326167919, 38 | 'longitude' => 9.562439849679859, 39 | 'elevation' => 12, 40 | 'time' => new \DateTime("+ 4 MINUTE") 41 | ] 42 | ]; 43 | 44 | // Creating sample link object for metadata 45 | $link = new Link(); 46 | $link->href = "https://sibyx.github.io/phpgpx"; 47 | $link->text = 'phpGPX Docs'; 48 | 49 | // GpxFile contains data and handles serialization of objects 50 | $gpx_file = new GpxFile(); 51 | 52 | // Creating sample Metadata object 53 | $gpx_file->metadata = new Metadata(); 54 | 55 | // Time attribute is always \DateTime object! 56 | $gpx_file->metadata->time = new \DateTime(); 57 | 58 | // Description of GPX file 59 | $gpx_file->metadata->description = "My pretty awesome GPX file, created using phpGPX library!"; 60 | 61 | // Adding link created before to links array of metadata 62 | // Metadata of GPX file can contain more than one link 63 | $gpx_file->metadata->links[] = $link; 64 | 65 | // Creating track 66 | $track = new Track(); 67 | 68 | // Name of track 69 | $track->name = sprintf("Some random points in logical order. Input array should be already ordered!"); 70 | 71 | // Type of data stored in track 72 | $track->type = 'RUN'; 73 | 74 | // Source of GPS coordinates 75 | $track->source = sprintf("MySpecificGarminDevice"); 76 | 77 | $wp = []; 78 | foreach ($sample_data as $sample_point) { 79 | // Creating trackpoint 80 | $point = new Point(Point::WAYPOINT); 81 | $point->latitude = $sample_point['latitude']; 82 | $point->longitude = $sample_point['longitude']; 83 | $point->elevation = $sample_point['elevation']; 84 | $point->time = $sample_point['time']; 85 | 86 | $wp[] = $point; 87 | } 88 | 89 | $gpx_file->waypoints = $wp; 90 | 91 | $gpx_file->save($this->waypoint_created_file, \phpGPX\phpGPX::XML_FORMAT); 92 | } 93 | 94 | public function setUp(): void 95 | { 96 | $this->waypoint_created_file = dirname(__FILE__)."/waypoint_test.gpx"; 97 | $this->waypoint_saved_file = dirname(__FILE__).'/output_waypoint_test.gpx'; 98 | // remove any test file hanging around 99 | system("rm -f {$this->waypoint_created_file}"); 100 | // now create the test file 101 | $this->createWaypointFile(); 102 | } 103 | public function tearDown(): void 104 | { 105 | system("rm -f {$this->waypoint_created_file}"); 106 | system("rm -f {$this->waypoint_saved_file}"); 107 | } 108 | public function test_waypoints_load() 109 | { 110 | $origFile = $this->waypoint_created_file; 111 | $outFile = $this->waypoint_saved_file; 112 | 113 | $gpx = new phpGPX(); 114 | $file = $gpx->load($origFile); 115 | 116 | phpGPX::$PRETTY_PRINT = true; 117 | $file->save($outFile, phpGPX::XML_FORMAT); 118 | 119 | $retcode = 0; 120 | system("diff $origFile $outFile", $retcode); 121 | // system("diff $origFile $outFile2", $retcode); 122 | $this->assertEquals($retcode, 0); 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /tests/UnitTests/phpGPX/Parsers/ExtensionParserTest.php: -------------------------------------------------------------------------------- 1 | aTemp = (float) 14; 26 | $trackpoint->avgTemperature = (float) 14; 27 | $trackpoint->hr = (float) 152; 28 | $trackpoint->heartRate = (float) 152; 29 | 30 | $extensions = new Extensions(); 31 | $extensions->trackPointExtension = $trackpoint; 32 | 33 | return $extensions; 34 | } 35 | 36 | protected function setUp(): void 37 | { 38 | parent::setUp(); 39 | 40 | $this->testModelInstance = self::createTestInstance(); 41 | } 42 | 43 | public function testParse() 44 | { 45 | $extensions = ExtensionParser::parse($this->testXmlFile->extensions); 46 | 47 | $this->assertEquals($this->testModelInstance->unsupported, $extensions->unsupported); 48 | $this->assertEquals($this->testModelInstance->trackPointExtension, $extensions->trackPointExtension); 49 | 50 | $this->assertEquals($this->testModelInstance->toArray(), $extensions->toArray()); 51 | } 52 | 53 | 54 | /** 55 | * Returns output of ::toXML method of tested parser. 56 | * @param \DOMDocument $document 57 | * @return \DOMElement 58 | */ 59 | protected function convertToXML(\DOMDocument $document) 60 | { 61 | return ExtensionParser::toXML($this->testModelInstance, $document); 62 | } 63 | 64 | public function testToXML() 65 | { 66 | $document = new \DOMDocument("1.0", 'UTF-8'); 67 | 68 | $root = $document->createElement("document"); 69 | $root->appendChild($this->convertToXML($document)); 70 | 71 | $attributes = [ 72 | 'xmlns' => 'http://www.topografix.com/GPX/1/1', 73 | 'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance', 74 | 'xsi:schemaLocation' => 'http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd http://www.garmin.com/xmlschemas/GpxExtensions/v3 http://www.garmin.com/xmlschemas/GpxExtensionsv3.xsd http://www.garmin.com/xmlschemas/TrackPointExtension/v1 http://www.garmin.com/xmlschemas/TrackPointExtensionv1.xsd http://www.garmin.com/xmlschemas/GpxExtensions/v3 http://www.garmin.com/xmlschemas/GpxExtensionsv3.xsd http://www.garmin.com/xmlschemas/TrackPointExtension/v1 http://www.garmin.com/xmlschemas/TrackPointExtensionv1.xsd http://www.garmin.com/xmlschemas/GpxExtensions/v3 http://www.garmin.com/xmlschemas/GpxExtensionsv3.xsd http://www.garmin.com/xmlschemas/TrackPointExtension/v1 http://www.garmin.com/xmlschemas/TrackPointExtensionv1.xsd http://www.garmin.com/xmlschemas/GpxExtensions/v3 http://www.garmin.com/xmlschemas/GpxExtensionsv3.xsd http://www.garmin.com/xmlschemas/TrackPointExtension/v1 http://www.garmin.com/xmlschemas/TrackPointExtensionv1.xsd http://www.garmin.com/xmlschemas/GpxExtensions/v3 http://www.garmin.com/xmlschemas/GpxExtensionsv3.xsd http://www.garmin.com/xmlschemas/TrackPointExtension/v1 http://www.garmin.com/xmlschemas/TrackPointExtensionv1.xsd http://www.garmin.com/xmlschemas/GpxExtensions/v3 http://www.garmin.com/xmlschemas/GpxExtensionsv3.xsd http://www.garmin.com/xmlschemas/TrackPointExtension/v1 http://www.garmin.com/xmlschemas/TrackPointExtensionv1.xsd', 75 | 'xmlns:gpxtpx' => 'http://www.garmin.com/xmlschemas/TrackPointExtension/v1', 76 | 'xmlns:gpxx' => 'http://www.garmin.com/xmlschemas/GpxExtensions/v3', 77 | ]; 78 | 79 | foreach ($attributes as $key => $value) { 80 | $attribute = $document->createAttribute($key); 81 | $attribute->value = $value; 82 | $root->appendChild($attribute); 83 | } 84 | 85 | $document->appendChild($root); 86 | 87 | $this->assertXmlStringEqualsXmlString($this->testXmlFile->asXML(), $document->saveXML()); 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/phpGPX/phpGPX.php: -------------------------------------------------------------------------------- 1 | 5 | */ 6 | 7 | namespace phpGPX; 8 | 9 | use phpGPX\Models\GpxFile; 10 | use phpGPX\Parsers\MetadataParser; 11 | use phpGPX\Parsers\RouteParser; 12 | use phpGPX\Parsers\TrackParser; 13 | use phpGPX\Parsers\WaypointParser; 14 | 15 | /** 16 | * Class phpGPX 17 | * @package phpGPX 18 | */ 19 | class phpGPX 20 | { 21 | const JSON_FORMAT = 'json'; 22 | const XML_FORMAT = 'xml'; 23 | 24 | const PACKAGE_NAME = 'phpGPX'; 25 | const VERSION = '1.3.0'; 26 | 27 | /** 28 | * Create Stats object for each track, segment and route 29 | * @var bool 30 | */ 31 | public static $CALCULATE_STATS = true; 32 | 33 | /** 34 | * Additional sort based on timestamp in Routes & Tracks on XML read. 35 | * Disabled by default, data should be already sorted. 36 | * @var bool 37 | */ 38 | public static $SORT_BY_TIMESTAMP = false; 39 | 40 | /** 41 | * Default DateTime output format in JSON serialization. 42 | * @var string 43 | */ 44 | public static $DATETIME_FORMAT = 'c'; 45 | 46 | /** 47 | * Default timezone for display. 48 | * Data are always stored in UTC timezone. 49 | * @var string 50 | */ 51 | public static $DATETIME_TIMEZONE_OUTPUT = 'UTC'; 52 | 53 | /** 54 | * Pretty print. 55 | * @var bool 56 | */ 57 | public static $PRETTY_PRINT = true; 58 | 59 | /** 60 | * In stats elevation calculation: ignore points with an elevation of 0 61 | * This can happen with some GPS software adding a point with 0 elevation 62 | * 63 | * @var bool 64 | */ 65 | public static $IGNORE_ELEVATION_0 = true; 66 | 67 | /** 68 | * Apply elevation gain/loss smoothing? If true, the threshold in 69 | * ELEVATION_SMOOTHING_THRESHOLD and ELEVATION_SMOOTHING_SPIKES_THRESHOLD (if not null) applies 70 | * @var bool 71 | */ 72 | public static $APPLY_ELEVATION_SMOOTHING = false; 73 | 74 | /** 75 | * if APPLY_ELEVATION_SMOOTHING is true 76 | * the minimum elevation difference between considered points in meters 77 | * @var int 78 | */ 79 | public static $ELEVATION_SMOOTHING_THRESHOLD = 2; 80 | 81 | /** 82 | * if APPLY_ELEVATION_SMOOTHING is true 83 | * the maximum elevation difference between considered points in meters 84 | * @var int|null 85 | */ 86 | public static $ELEVATION_SMOOTHING_SPIKES_THRESHOLD = null; 87 | 88 | /** 89 | * Apply distance calculation smoothing? If true, the threshold in 90 | * DISTANCE_SMOOTHING_THRESHOLD applies 91 | * @var bool 92 | */ 93 | public static $APPLY_DISTANCE_SMOOTHING = false; 94 | 95 | /** 96 | * if APPLY_DISTANCE_SMOOTHING is true 97 | * the minimum distance between considered points in meters 98 | * @var int 99 | */ 100 | public static $DISTANCE_SMOOTHING_THRESHOLD = 2; 101 | 102 | /** 103 | * Load GPX file. 104 | * @param $path 105 | * @return GpxFile 106 | */ 107 | public static function load($path) 108 | { 109 | $xml = file_get_contents($path); 110 | 111 | return self::parse($xml); 112 | } 113 | 114 | /** 115 | * Parse GPX data string. 116 | * @param $xml 117 | * @return GpxFile 118 | */ 119 | public static function parse($xml) 120 | { 121 | $xml = simplexml_load_string($xml); 122 | 123 | $gpx = new GpxFile(); 124 | 125 | // Parse creator 126 | $gpx->creator = isset($xml['creator']) ? (string)$xml['creator'] : null; 127 | 128 | // Parse metadata 129 | $gpx->metadata = isset($xml->metadata) ? MetadataParser::parse($xml->metadata) : null; 130 | 131 | // Parse waypoints 132 | $gpx->waypoints = isset($xml->wpt) ? WaypointParser::parse($xml->wpt) : []; 133 | 134 | // Parse tracks 135 | $gpx->tracks = isset($xml->trk) ? TrackParser::parse($xml->trk) : []; 136 | 137 | // Parse routes 138 | $gpx->routes = isset($xml->rte) ? RouteParser::parse($xml->rte) : []; 139 | 140 | return $gpx; 141 | } 142 | 143 | /** 144 | * Create library signature from name and version. 145 | * @return string 146 | */ 147 | public static function getSignature() 148 | { 149 | return sprintf("%s/%s", self::PACKAGE_NAME, self::VERSION); 150 | } 151 | } 152 | -------------------------------------------------------------------------------- /tests/UnitTests/phpGPX/Parsers/SegmentParserTest.json: -------------------------------------------------------------------------------- 1 | { 2 | "extensions": null, 3 | "points": [ 4 | { 5 | "ageofdgpsdata": null, 6 | "cmt": null, 7 | "desc": null, 8 | "dgpsid": null, 9 | "difference": null, 10 | "distance": null, 11 | "ele": 2419, 12 | "extensions": null, 13 | "fix": null, 14 | "geoidheight": null, 15 | "hdop": null, 16 | "lat": 46.571948, 17 | "link": [], 18 | "lon": 8.414757, 19 | "magvar": null, 20 | "name": null, 21 | "pdop": null, 22 | "sat": null, 23 | "src": null, 24 | "sym": null, 25 | "time": "2017-08-13T07:10:41+00:00", 26 | "type": null, 27 | "vdop": null 28 | }, 29 | { 30 | "ageofdgpsdata": null, 31 | "cmt": null, 32 | "desc": null, 33 | "dgpsid": null, 34 | "difference": 11.252021780368882, 35 | "distance": 11.252021780368882, 36 | "ele": 2418.8833883882, 37 | "extensions": null, 38 | "fix": null, 39 | "geoidheight": null, 40 | "hdop": null, 41 | "lat": 46.572016, 42 | "link": [], 43 | "lon": 8.414866, 44 | "magvar": null, 45 | "name": null, 46 | "pdop": null, 47 | "sat": null, 48 | "src": null, 49 | "sym": null, 50 | "time": "2017-08-13T07:10:54+00:00", 51 | "type": null, 52 | "vdop": null 53 | }, 54 | { 55 | "ageofdgpsdata": null, 56 | "cmt": null, 57 | "desc": null, 58 | "dgpsid": null, 59 | "difference": 8.772816467963736, 60 | "distance": 20.024838248332617, 61 | "ele": 2419.8999900064, 62 | "extensions": null, 63 | "fix": null, 64 | "geoidheight": null, 65 | "hdop": null, 66 | "lat": 46.572088, 67 | "link": [], 68 | "lon": 8.414911, 69 | "magvar": null, 70 | "name": null, 71 | "pdop": null, 72 | "sat": null, 73 | "src": null, 74 | "sym": null, 75 | "time": "2017-08-13T07:11:56+00:00", 76 | "type": null, 77 | "vdop": null 78 | }, 79 | { 80 | "ageofdgpsdata": null, 81 | "cmt": null, 82 | "desc": null, 83 | "dgpsid": null, 84 | "difference": 2.979832475456357, 85 | "distance": 23.004670723788976, 86 | "ele": 2422, 87 | "extensions": null, 88 | "fix": null, 89 | "geoidheight": null, 90 | "hdop": null, 91 | "lat": 46.572069, 92 | "link": [], 93 | "lon": 8.414912, 94 | "magvar": null, 95 | "name": null, 96 | "pdop": null, 97 | "sat": null, 98 | "src": null, 99 | "sym": null, 100 | "time": "2017-08-13T07:12:15+00:00", 101 | "type": null, 102 | "vdop": null 103 | }, 104 | { 105 | "ageofdgpsdata": null, 106 | "cmt": null, 107 | "desc": null, 108 | "dgpsid": null, 109 | "difference": 3.8919896350020755, 110 | "distance": 26.896660358791053, 111 | "ele": 2425, 112 | "extensions": null, 113 | "fix": null, 114 | "geoidheight": null, 115 | "hdop": null, 116 | "lat": 46.572054, 117 | "link": [], 118 | "lon": 8.414888, 119 | "magvar": null, 120 | "name": null, 121 | "pdop": null, 122 | "sat": null, 123 | "src": null, 124 | "sym": null, 125 | "time": "2017-08-13T07:12:18+00:00", 126 | "type": null, 127 | "vdop": null 128 | } 129 | ], 130 | "stats": { 131 | "avgPace": 3949.728409446995, 132 | "avgSpeed": 0.2531819650202255, 133 | "bounds": [ 134 | { 135 | "lat": 46.572088, 136 | "lng": 8.414757 137 | }, 138 | { 139 | "lat": 46.571948, 140 | "lng": 8.414912 141 | } 142 | ], 143 | "cumulativeElevationGain": 6.116611611800181, 144 | "cumulativeElevationLoss": 0.11661161180018098, 145 | "distance": 24.558650606961873, 146 | "duration": 97, 147 | "finishedAt": "2017-08-13T07:12:18+00:00", 148 | "finishedAtCoords": { 149 | "lat": 46.572054, 150 | "lng": 8.414888 151 | }, 152 | "maxAltitude": 2425, 153 | "maxAltitudeCoords": { 154 | "lat": 46.572054, 155 | "lng": 8.414888 156 | }, 157 | "minAltitude": 2418.8833883882, 158 | "minAltitudeCoords": { 159 | "lat": 46.572016, 160 | "lng": 8.414866 161 | }, 162 | "realDistance": 26.896660358791053, 163 | "startedAt": "2017-08-13T07:10:41+00:00", 164 | "startedAtCoords": { 165 | "lat": 46.571948, 166 | "lng": 8.414757 167 | } 168 | } 169 | } -------------------------------------------------------------------------------- /src/phpGPX/Parsers/TrackParser.php: -------------------------------------------------------------------------------- 1 | 5 | */ 6 | 7 | namespace phpGPX\Parsers; 8 | 9 | use phpGPX\Models\Track; 10 | use phpGPX\phpGPX; 11 | 12 | /** 13 | * Class TrackParser 14 | * @package phpGPX\Parsers 15 | */ 16 | abstract class TrackParser 17 | { 18 | public static $tagName = 'trk'; 19 | 20 | private static $attributeMapper = [ 21 | 'name' => [ 22 | 'name' => 'name', 23 | 'type' => 'string' 24 | ], 25 | 'cmt' => [ 26 | 'name' => 'comment', 27 | 'type' => 'string' 28 | ], 29 | 'desc' => [ 30 | 'name' => 'description', 31 | 'type' => 'string' 32 | ], 33 | 'src' => [ 34 | 'name' => 'source', 35 | 'type' => 'string' 36 | ], 37 | 'link' => [ 38 | 'name' => 'links', 39 | 'type' => 'array' 40 | ], 41 | 'number' => [ 42 | 'name' => 'number', 43 | 'type' => 'integer' 44 | ], 45 | 'type' => [ 46 | 'name' => 'type', 47 | 'type' => 'string' 48 | ], 49 | 'extensions' => [ 50 | 'name' => 'extensions', 51 | 'type' => 'object' 52 | ], 53 | 'trkseg' => [ 54 | 'name' => 'segments', 55 | 'type' => 'array' 56 | ], 57 | ]; 58 | 59 | /** 60 | * @param \SimpleXMLElement $nodes 61 | * @return Track[] 62 | */ 63 | public static function parse(\SimpleXMLElement $nodes) 64 | { 65 | $tracks = []; 66 | 67 | foreach ($nodes as $node) { 68 | $track = new Track(); 69 | 70 | foreach (self::$attributeMapper as $key => $attribute) { 71 | switch ($key) { 72 | case 'link': 73 | $track->links = isset($node->link) ? LinkParser::parse($node->link) : []; 74 | break; 75 | case 'extensions': 76 | $track->extensions = isset($node->extensions) ? ExtensionParser::parse($node->extensions) : null; 77 | break; 78 | case 'trkseg': 79 | $track->segments = isset($node->trkseg) ? SegmentParser::parse($node->trkseg) : []; 80 | break; 81 | default: 82 | if (!in_array($attribute['type'], ['object', 'array'])) { 83 | $track->{$attribute['name']} = isset($node->$key) ? $node->$key : null; 84 | if (!is_null($track->{$attribute['name']})) { 85 | settype($track->{$attribute['name']}, $attribute['type']); 86 | } 87 | } 88 | break; 89 | } 90 | } 91 | 92 | if (phpGPX::$CALCULATE_STATS) { 93 | $track->recalculateStats(); 94 | } 95 | 96 | $tracks[] = $track; 97 | } 98 | 99 | return $tracks; 100 | } 101 | 102 | /** 103 | * @param Track $track 104 | * @param \DOMDocument $document 105 | * @return \DOMElement 106 | */ 107 | public static function toXML(Track $track, \DOMDocument &$document) 108 | { 109 | $node = $document->createElement(self::$tagName); 110 | 111 | foreach (self::$attributeMapper as $key => $attribute) { 112 | if (!is_null($track->{$attribute['name']})) { 113 | switch ($key) { 114 | case 'link': 115 | $child = LinkParser::toXMLArray($track->links, $document); 116 | break; 117 | case 'extensions': 118 | $child = ExtensionParser::toXML($track->extensions, $document); 119 | break; 120 | case 'trkseg': 121 | $child = SegmentParser::toXMLArray($track->segments, $document); 122 | break; 123 | default: 124 | $child = $document->createElement($key); 125 | $elementText = $document->createTextNode((string) $track->{$attribute['name']}); 126 | $child->appendChild($elementText); 127 | break; 128 | } 129 | 130 | if (is_array($child)) { 131 | foreach ($child as $item) { 132 | $node->appendChild($item); 133 | } 134 | } else { 135 | $node->appendChild($child); 136 | } 137 | } 138 | } 139 | 140 | return $node; 141 | } 142 | 143 | /** 144 | * @param array $tracks 145 | * @param \DOMDocument $document 146 | * @return \DOMElement[] 147 | */ 148 | public static function toXMLArray(array $tracks, \DOMDocument &$document) 149 | { 150 | $result = []; 151 | 152 | foreach ($tracks as $track) { 153 | $result[] = self::toXML($track, $document); 154 | } 155 | 156 | return $result; 157 | } 158 | } 159 | -------------------------------------------------------------------------------- /example/CreateFileFromScratch.php: -------------------------------------------------------------------------------- 1 | 4 | */ 5 | 6 | use phpGPX\Models\GpxFile; 7 | use phpGPX\Models\Link; 8 | use phpGPX\Models\Metadata; 9 | use phpGPX\Models\Point; 10 | use phpGPX\Models\Segment; 11 | use phpGPX\Models\Track; 12 | use phpGPX\Models\Extensions; 13 | use phpGPX\Models\Extensions\TrackPointExtension; 14 | 15 | require_once '../vendor/autoload.php'; 16 | 17 | $sample_data = [ 18 | [ 19 | 'longitude' => 9.860624216140083, 20 | 'latitude' => 54.9328621088893, 21 | 'elevation' => 0, 22 | 'aTemp' => 22, 23 | 'time' => new \DateTime("+ 1 MINUTE") 24 | ], 25 | [ 26 | 'latitude' => 54.83293237320851, 27 | 'longitude' => 9.76092208681491, 28 | 'elevation' => 10.0, 29 | 'aTemp' => 23, 30 | 'time' => new \DateTime("+ 2 MINUTE") 31 | ], 32 | [ 33 | 'latitude' => 54.73327743521187, 34 | 'longitude' => 9.66187816543752, 35 | 'elevation' => 42.42, 36 | 'aTemp' => 24, 37 | 'time' => new \DateTime("+ 3 MINUTE") 38 | ], 39 | [ 40 | 'latitude' => 54.63342326167919, 41 | 'longitude' => 9.562439849679859, 42 | 'elevation' => 12, 43 | 'aTemp' => 25, 44 | 'time' => new \DateTime("+ 4 MINUTE") 45 | ] 46 | ]; 47 | 48 | // Creating sample link object for metadata 49 | $link = new Link(); 50 | $link->href = "https://sibyx.github.io/phpgpx"; 51 | $link->text = 'phpGPX Docs'; 52 | 53 | // GpxFile contains data and handles serialization of objects 54 | $gpx_file = new GpxFile(); 55 | 56 | // Creating sample Metadata object 57 | $gpx_file->metadata = new Metadata(); 58 | 59 | // Time attribute is always \DateTime object! 60 | $gpx_file->metadata->time = new \DateTime(); 61 | 62 | // Description of GPX file 63 | $gpx_file->metadata->description = "My pretty awesome GPX file, created using phpGPX library!"; 64 | 65 | // Adding link created before to links array of metadata 66 | // Metadata of GPX file can contain more than one link 67 | $gpx_file->metadata->links[] = $link; 68 | 69 | // Creating track 70 | $track = new Track(); 71 | 72 | // Name of track 73 | $track->name = sprintf("Some random points in logical order. Input array should be already ordered!"); 74 | 75 | // Type of data stored in track 76 | $track->type = 'RUN'; 77 | 78 | // Source of GPS coordinates 79 | $track->source = sprintf("MySpecificGarminDevice"); 80 | 81 | // Creating Track segment 82 | $segment = new Segment(); 83 | 84 | 85 | foreach ($sample_data as $sample_point) { 86 | // Creating trackpoint 87 | $point = new Point(Point::TRACKPOINT); 88 | $point->latitude = $sample_point['latitude']; 89 | $point->longitude = $sample_point['longitude']; 90 | $point->elevation = $sample_point['elevation']; 91 | $point->time = $sample_point['time']; 92 | 93 | // Creating trackpoint extension 94 | $point->extensions = new Extensions(); 95 | $trackPointExtension = new TrackPointExtension(); 96 | $trackPointExtension->aTemp = $sample_point['aTemp']; 97 | $point->extensions->trackPointExtension = $trackPointExtension; 98 | 99 | $segment->points[] = $point; 100 | } 101 | 102 | // Add segment to segment array of track 103 | $track->segments[] = $segment; 104 | 105 | // Add track to file 106 | $gpx_file->tracks[] = $track; 107 | 108 | // Create waypoint 109 | $point = new Point(Point::WAYPOINT); 110 | $point->name = 'Example Waypoint'; 111 | $point->latitude = $sample_point['latitude']; 112 | $point->longitude = $sample_point['longitude']; 113 | $point->elevation = $sample_point['elevation']; 114 | $point->time = $sample_point['time']; 115 | 116 | // Add waypoint to file 117 | $gpx_file->waypoints[] = $point; 118 | 119 | // GPX output 120 | $gpx_file->save('CreateFileFromScratchExample.gpx', \phpGPX\phpGPX::XML_FORMAT); 121 | 122 | // Serialized data as JSON 123 | $gpx_file->save('CreateFileFromScratchExample.json', \phpGPX\phpGPX::JSON_FORMAT); 124 | 125 | // Direct GPX output to browser 126 | 127 | header("Content-Type: application/gpx+xml"); 128 | header("Content-Disposition: attachment; filename=CreatingFileFromScratchExample.gpx"); 129 | 130 | echo $gpx_file->toXML()->saveXML(); 131 | exit(); 132 | -------------------------------------------------------------------------------- /src/phpGPX/Models/Stats.php: -------------------------------------------------------------------------------- 1 | 5 | */ 6 | 7 | namespace phpGPX\Models; 8 | 9 | use phpGPX\Helpers\DateTimeHelper; 10 | use phpGPX\phpGPX; 11 | 12 | /** 13 | * Class Stats 14 | * @package phpGPX\Models 15 | */ 16 | class Stats implements Summarizable 17 | { 18 | 19 | /** 20 | * Distance in meters (m) 21 | * @var float 22 | */ 23 | public $distance = 0; 24 | 25 | /** 26 | * Distance in meters (m) including elevation loss/gain 27 | * @var float 28 | */ 29 | public $realDistance = 0; 30 | 31 | /** 32 | * Average speed in meters per second (m/s) 33 | * @var float 34 | */ 35 | public $averageSpeed = null; 36 | 37 | /** 38 | * Average pace in seconds per kilometer (s/km) 39 | * @var float 40 | */ 41 | public $averagePace = null; 42 | 43 | /** 44 | * Minimal altitude in meters (m) 45 | * @var int 46 | */ 47 | public $minAltitude = null; 48 | 49 | /** 50 | * Minimal altitude coordinate 51 | * @var [float,float] 52 | */ 53 | public $minAltitudeCoords = null; 54 | 55 | /** 56 | * Maximal altitude in meters (m) 57 | * @var int 58 | */ 59 | public $maxAltitude = null; 60 | 61 | /** 62 | * Maximal altitude coordinate 63 | * @var [float,float] 64 | */ 65 | public $maxAltitudeCoords = null; 66 | 67 | /** 68 | * Cumulative elevation gain in meters (m) 69 | * @var int 70 | */ 71 | public $cumulativeElevationGain = null; 72 | 73 | /** 74 | * Cumulative elevation loss in meters (m) 75 | * @var int 76 | */ 77 | public $cumulativeElevationLoss = null; 78 | 79 | /** 80 | * Started time 81 | * @var \DateTime 82 | */ 83 | public $startedAt = null; 84 | 85 | /** 86 | * startedAt coordinate 87 | * @var [float,float] 88 | */ 89 | public $startedAtCoords = null; 90 | 91 | /** 92 | * Ending time 93 | * @var \DateTime 94 | */ 95 | public $finishedAt = null; 96 | 97 | /** 98 | * finishedAt coordinate 99 | * @var [float,float] 100 | */ 101 | public $finishedAtCoords = null; 102 | 103 | /** 104 | * Duration is seconds 105 | * @var int 106 | */ 107 | public $duration = null; 108 | 109 | /** 110 | * An array of two points representing 111 | * the most northwestern and the most 112 | * southeastern points of a segment 113 | * @var array 114 | */ 115 | public $bounds = array(); 116 | 117 | /** 118 | * Reset all stats 119 | */ 120 | public function reset() 121 | { 122 | $this->distance = null; 123 | $this->realDistance = null; 124 | $this->averageSpeed = null; 125 | $this->averagePace = null; 126 | $this->minAltitude = null; 127 | $this->maxAltitude = null; 128 | $this->minAltitudeCoords = null; 129 | $this->maxAltitudeCoords = null; 130 | $this->cumulativeElevationGain = null; 131 | $this->cumulativeElevationLoss = null; 132 | $this->startedAt = null; 133 | $this->startedAtCoords = null; 134 | $this->finishedAt = null; 135 | $this->finishedAtCoords = null; 136 | $this->bounds = null; 137 | } 138 | 139 | /** 140 | * Serialize object to array 141 | * @return array 142 | */ 143 | public function toArray() 144 | { 145 | return [ 146 | 'distance' => (float)$this->distance, 147 | 'realDistance' => (float)$this->realDistance, 148 | 'avgSpeed' => (float)$this->averageSpeed, 149 | 'avgPace' => (float)$this->averagePace, 150 | 'minAltitude' => (float)$this->minAltitude, 151 | 'minAltitudeCoords' => $this->minAltitudeCoords, 152 | 'maxAltitude' => (float)$this->maxAltitude, 153 | 'maxAltitudeCoords' => $this->maxAltitudeCoords, 154 | 'cumulativeElevationGain' => (float)$this->cumulativeElevationGain, 155 | 'cumulativeElevationLoss' => (float)$this->cumulativeElevationLoss, 156 | 'startedAt' => DateTimeHelper::formatDateTime($this->startedAt, phpGPX::$DATETIME_FORMAT, phpGPX::$DATETIME_TIMEZONE_OUTPUT), 157 | 'startedAtCoords' => $this->startedAtCoords, 158 | 'finishedAt' => DateTimeHelper::formatDateTime($this->finishedAt, phpGPX::$DATETIME_FORMAT, phpGPX::$DATETIME_TIMEZONE_OUTPUT), 159 | 'finishedAtCoords' => $this->finishedAtCoords, 160 | 'duration' => (float)$this->duration, 161 | 'bounds' => $this->bounds 162 | ]; 163 | } 164 | } 165 | -------------------------------------------------------------------------------- /src/phpGPX/Parsers/RouteParser.php: -------------------------------------------------------------------------------- 1 | 5 | */ 6 | 7 | namespace phpGPX\Parsers; 8 | 9 | use phpGPX\Models\Route; 10 | use phpGPX\phpGPX; 11 | 12 | /** 13 | * Class RouteParser 14 | * @package phpGPX\Parsers 15 | */ 16 | abstract class RouteParser 17 | { 18 | public static $tagName = 'rte'; 19 | 20 | private static $attributeMapper = [ 21 | 'name' => [ 22 | 'name' => 'name', 23 | 'type' => 'string' 24 | ], 25 | 'cmt' => [ 26 | 'name' => 'comment', 27 | 'type' => 'string' 28 | ], 29 | 'desc' => [ 30 | 'name' => 'description', 31 | 'type' => 'string' 32 | ], 33 | 'src' => [ 34 | 'name' => 'source', 35 | 'type' => 'string' 36 | ], 37 | 'links' => [ 38 | 'name' => 'links', 39 | 'type' => 'array' 40 | ], 41 | 'number' => [ 42 | 'name' => 'number', 43 | 'type' => 'integer' 44 | ], 45 | 'type' => [ 46 | 'name' => 'type', 47 | 'type' => 'string' 48 | ], 49 | 'extensions' => [ 50 | 'name' => 'extensions', 51 | 'type' => 'object' 52 | ], 53 | 'rtept' => [ 54 | 'name' => 'points', 55 | 'type' => 'array' 56 | ], 57 | ]; 58 | 59 | /** 60 | * @param \SimpleXMLElement[] $nodes 61 | * @return Route[] 62 | */ 63 | public static function parse($nodes) 64 | { 65 | $routes = []; 66 | 67 | foreach ($nodes as $node) { 68 | $route = new Route(); 69 | 70 | foreach (self::$attributeMapper as $key => $attribute) { 71 | switch ($key) { 72 | case 'link': 73 | $route->links = isset($node->link) ? LinkParser::parse($node->link) : []; 74 | break; 75 | case 'extensions': 76 | $route->extensions = isset($node->extensions) ? ExtensionParser::parse($node->extensions) : null; 77 | break; 78 | case 'rtept': 79 | $route->points = []; 80 | 81 | if (isset($node->rtept)) { 82 | foreach ($node->rtept as $point) { 83 | $route->points[] = PointParser::parse($point); 84 | } 85 | } 86 | break; 87 | default: 88 | if (!in_array($attribute['type'], ['object', 'array'])) { 89 | $route->{$attribute['name']} = isset($node->$key) ? $node->$key : null; 90 | if (!is_null($route->{$attribute['name']})) { 91 | settype($route->{$attribute['name']}, $attribute['type']); 92 | } 93 | } 94 | break; 95 | } 96 | } 97 | 98 | if (phpGPX::$CALCULATE_STATS) { 99 | $route->recalculateStats(); 100 | } 101 | 102 | $routes[] = $route; 103 | } 104 | 105 | return $routes; 106 | } 107 | 108 | /** 109 | * @param Route $route 110 | * @param \DOMDocument $document 111 | * @return \DOMElement 112 | */ 113 | public static function toXML(Route $route, \DOMDocument &$document) 114 | { 115 | $node = $document->createElement(self::$tagName); 116 | 117 | foreach (self::$attributeMapper as $key => $attribute) { 118 | if (!is_null($route->{$attribute['name']})) { 119 | switch ($key) { 120 | case 'links': 121 | $child = LinkParser::toXMLArray($route->links, $document); 122 | break; 123 | case 'extensions': 124 | $child = ExtensionParser::toXML($route->extensions, $document); 125 | break; 126 | case 'rtept': 127 | $child = PointParser::toXMLArray($route->points, $document); 128 | break; 129 | default: 130 | $child = $document->createElement($key); 131 | $elementText = $document->createTextNode((string) $route->{$attribute['name']}); 132 | $child->appendChild($elementText); 133 | break; 134 | } 135 | 136 | if (is_array($child)) { 137 | foreach ($child as $item) { 138 | $node->appendChild($item); 139 | } 140 | } else { 141 | $node->appendChild($child); 142 | } 143 | } 144 | } 145 | 146 | return $node; 147 | } 148 | 149 | /** 150 | * @param array $routes 151 | * @param \DOMDocument $document 152 | * @return \DOMElement[] 153 | */ 154 | public static function toXMLArray(array $routes, \DOMDocument &$document) 155 | { 156 | $result = []; 157 | 158 | foreach ($routes as $route) { 159 | $result[] = self::toXML($route, $document); 160 | } 161 | 162 | return $result; 163 | } 164 | } 165 | -------------------------------------------------------------------------------- /docs/phpGPX-Models-Extensions-TrackPointExtension.md: -------------------------------------------------------------------------------- 1 | phpGPX\Models\Extensions\TrackPointExtension 2 | =============== 3 | 4 | Class TrackPointExtension 5 | Extension version: v2 6 | Based on namespace: http://www.garmin.com/xmlschemas/TrackPointExtensionv2.xsd 7 | 8 | 9 | 10 | 11 | * Class name: TrackPointExtension 12 | * Namespace: phpGPX\Models\Extensions 13 | * Parent class: [phpGPX\Models\Extensions\AbstractExtension](phpGPX-Models-Extensions-AbstractExtension.md) 14 | 15 | 16 | 17 | Constants 18 | ---------- 19 | 20 | 21 | ### EXTENSION_V1_NAMESPACE 22 | 23 | const EXTENSION_V1_NAMESPACE = 'http://www.garmin.com/xmlschemas/TrackPointExtension/v1' 24 | 25 | 26 | 27 | 28 | 29 | ### EXTENSION_V1_NAMESPACE_XSD 30 | 31 | const EXTENSION_V1_NAMESPACE_XSD = 'http://www.garmin.com/xmlschemas/TrackPointExtensionv1.xsd' 32 | 33 | 34 | 35 | 36 | 37 | ### EXTENSION_NAMESPACE 38 | 39 | const EXTENSION_NAMESPACE = 'http://www.garmin.com/xmlschemas/TrackPointExtension/v2' 40 | 41 | 42 | 43 | 44 | 45 | ### EXTENSION_NAMESPACE_XSD 46 | 47 | const EXTENSION_NAMESPACE_XSD = 'http://www.garmin.com/xmlschemas/TrackPointExtensionv2.xsd' 48 | 49 | 50 | 51 | 52 | 53 | ### EXTENSION_NAME 54 | 55 | const EXTENSION_NAME = 'TrackPointExtension' 56 | 57 | 58 | 59 | 60 | 61 | ### EXTENSION_NAMESPACE_PREFIX 62 | 63 | const EXTENSION_NAMESPACE_PREFIX = 'gpxtpx' 64 | 65 | 66 | 67 | 68 | 69 | Properties 70 | ---------- 71 | 72 | 73 | ### $aTemp 74 | 75 | public float $aTemp 76 | 77 | Average temperature value measured in degrees Celsius. 78 | 79 | 80 | 81 | * Visibility: **public** 82 | 83 | 84 | ### $wTemp 85 | 86 | public float $wTemp 87 | 88 | 89 | 90 | 91 | 92 | * Visibility: **public** 93 | 94 | 95 | ### $depth 96 | 97 | public float $depth 98 | 99 | Depth in meters. 100 | 101 | 102 | 103 | * Visibility: **public** 104 | 105 | 106 | ### $heartRate 107 | 108 | public float $heartRate 109 | 110 | Heart rate in beats per minute. 111 | 112 | 113 | 114 | * Visibility: **public** 115 | 116 | 117 | ### $hr 118 | 119 | public float $hr 120 | 121 | Heart rate in beats per minute. 122 | 123 | 124 | 125 | * Visibility: **public** 126 | 127 | 128 | ### $cadence 129 | 130 | public float $cadence 131 | 132 | Cadence in revolutions per minute. 133 | 134 | 135 | 136 | * Visibility: **public** 137 | 138 | 139 | ### $cad 140 | 141 | public float $cad 142 | 143 | Cadence in revolutions per minute. 144 | 145 | 146 | 147 | * Visibility: **public** 148 | 149 | 150 | ### $speed 151 | 152 | public float $speed 153 | 154 | Speed in meters per second. 155 | 156 | 157 | 158 | * Visibility: **public** 159 | 160 | 161 | ### $course 162 | 163 | public integer $course 164 | 165 | Course. This type contains an angle measured in degrees in a clockwise direction from the true north line. 166 | 167 | 168 | 169 | * Visibility: **public** 170 | 171 | 172 | ### $bearing 173 | 174 | public integer $bearing 175 | 176 | Bearing. This type contains an angle measured in degrees in a clockwise direction from the true north line. 177 | 178 | 179 | 180 | * Visibility: **public** 181 | 182 | 183 | ### $namespace 184 | 185 | public string $namespace 186 | 187 | XML namespace of extension 188 | 189 | 190 | 191 | * Visibility: **public** 192 | 193 | 194 | ### $extensionName 195 | 196 | public string $extensionName 197 | 198 | Node name extension. 199 | 200 | 201 | 202 | * Visibility: **public** 203 | 204 | 205 | Methods 206 | ------- 207 | 208 | 209 | ### __construct 210 | 211 | mixed phpGPX\Models\Extensions\AbstractExtension::__construct(string $namespace, string $extensionName) 212 | 213 | AbstractExtension constructor. 214 | 215 | 216 | 217 | * Visibility: **public** 218 | * This method is defined by [phpGPX\Models\Extensions\AbstractExtension](phpGPX-Models-Extensions-AbstractExtension.md) 219 | 220 | 221 | #### Arguments 222 | * $namespace **string** 223 | * $extensionName **string** 224 | 225 | 226 | 227 | ### toArray 228 | 229 | array phpGPX\Models\Summarizable::toArray() 230 | 231 | Serialize object to array 232 | 233 | 234 | 235 | * Visibility: **public** 236 | * This method is defined by [phpGPX\Models\Summarizable](phpGPX-Models-Summarizable.md) 237 | 238 | 239 | 240 | -------------------------------------------------------------------------------- /src/phpGPX/Parsers/MetadataParser.php: -------------------------------------------------------------------------------- 1 | 5 | */ 6 | 7 | namespace phpGPX\Parsers; 8 | 9 | use phpGPX\Helpers\DateTimeHelper; 10 | use phpGPX\Models\Metadata; 11 | 12 | /** 13 | * Class MetadataParser 14 | * @package phpGPX\Parsers 15 | */ 16 | abstract class MetadataParser 17 | { 18 | private static $tagName = 'metadata'; 19 | 20 | private static $attributeMapper = [ 21 | 'name' => [ 22 | 'name' => 'name', 23 | 'type' => 'string' 24 | ], 25 | 'desc' => [ 26 | 'name' => 'description', 27 | 'type' => 'string' 28 | ], 29 | 'author' => [ 30 | 'name' => 'author', 31 | 'type' => 'object' 32 | ], 33 | 'copyright' => [ 34 | 'name' => 'copyright', 35 | 'type' => 'object' 36 | ], 37 | 'link' => [ 38 | 'name' => 'links', 39 | 'type' => 'array' 40 | ], 41 | 'time' => [ 42 | 'name' => 'time', 43 | 'type' => 'object' 44 | ], 45 | 'keywords' => [ 46 | 'name' => 'keywords', 47 | 'type' => 'string' 48 | ], 49 | 'bounds' => [ 50 | 'name' => 'bounds', 51 | 'type' => 'object' 52 | ], 53 | 'extensions' => [ 54 | 'name' => 'extensions', 55 | 'type' => 'object' 56 | ] 57 | ]; 58 | 59 | /** 60 | * @param \SimpleXMLElement $node 61 | * @return Metadata 62 | */ 63 | public static function parse(\SimpleXMLElement $node) 64 | { 65 | $metadata = new Metadata(); 66 | 67 | foreach (self::$attributeMapper as $key => $attribute) { 68 | switch ($key) { 69 | case 'author': 70 | $metadata->author = isset($node->author) ? PersonParser::parse($node->author) : null; 71 | break; 72 | case 'copyright': 73 | $metadata->copyright = isset($node->copyright) ? CopyrightParser::parse($node->copyright) : null; 74 | break; 75 | case 'link': 76 | $metadata->links = isset($node->link) ? LinkParser::parse($node->link) : null; 77 | break; 78 | case 'time': 79 | $metadata->time = isset($node->time) ? DateTimeHelper::parseDateTime($node->time) : null; 80 | break; 81 | case 'bounds': 82 | $metadata->bounds = isset($node->bounds) ? BoundsParser::parse($node->bounds) : null; 83 | break; 84 | case 'extensions': 85 | $metadata->extensions = isset($node->extensions) ? ExtensionParser::parse($node->extensions) : null; 86 | break; 87 | default: 88 | if (!in_array($attribute['type'], ['object', 'array'])) { 89 | $metadata->{$attribute['name']} = isset($node->$key) ? $node->$key : null; 90 | if (!is_null($metadata->{$attribute['name']})) { 91 | settype($metadata->{$attribute['name']}, $attribute['type']); 92 | } 93 | } 94 | break; 95 | } 96 | } 97 | 98 | return $metadata; 99 | } 100 | 101 | public static function toXML(Metadata $metadata, \DOMDocument &$document) 102 | { 103 | $node = $document->createElement(self::$tagName); 104 | 105 | foreach (self::$attributeMapper as $key => $attribute) { 106 | if (!is_null($metadata->{$attribute['name']})) { 107 | switch ($key) { 108 | case 'author': 109 | $child = PersonParser::toXML($metadata->author, $document); 110 | break; 111 | case 'copyright': 112 | $child = CopyrightParser::toXML($metadata->copyright, $document); 113 | break; 114 | case 'link': 115 | $child = LinkParser::toXMLArray($metadata->links, $document); 116 | break; 117 | case 'time': 118 | $child = $document->createElement('time', DateTimeHelper::formatDateTime($metadata->time)); 119 | break; 120 | case 'bounds': 121 | $child = BoundsParser::toXML($metadata->bounds, $document); 122 | break; 123 | case 'extensions': 124 | $child = ExtensionParser::toXML($metadata->extensions, $document); 125 | break; 126 | default: 127 | $child = $document->createElement($key); 128 | $elementText = $document->createTextNode((string) $metadata->{$attribute['name']}); 129 | $child->appendChild($elementText); 130 | break; 131 | } 132 | 133 | if (is_array($child)) { 134 | foreach ($child as $item) { 135 | $node->appendChild($item); 136 | } 137 | } else { 138 | $node->appendChild($child); 139 | } 140 | } 141 | } 142 | 143 | return $node; 144 | } 145 | } 146 | -------------------------------------------------------------------------------- /src/phpGPX/Models/Segment.php: -------------------------------------------------------------------------------- 1 | 5 | */ 6 | 7 | namespace phpGPX\Models; 8 | 9 | use phpGPX\Helpers\BoundsCalculator; 10 | use phpGPX\Helpers\DistanceCalculator; 11 | use phpGPX\Helpers\ElevationGainLossCalculator; 12 | use phpGPX\Helpers\GeoHelper; 13 | use phpGPX\Helpers\SerializationHelper; 14 | use phpGPX\phpGPX; 15 | 16 | /** 17 | * Class Segment 18 | * A Track Segment holds a list of Track Points which are logically connected in order. 19 | * To represent a single GPS track where GPS reception was lost, or the GPS receiver was turned off, 20 | * start a new Track Segment for each continuous span of track data. 21 | * @package phpGPX\Models 22 | */ 23 | class Segment implements Summarizable, StatsCalculator 24 | { 25 | /** 26 | * Array of segment points 27 | * @var Point[] 28 | */ 29 | public $points; 30 | 31 | /** 32 | * You can add extend GPX by adding your own elements from another schema here. 33 | * @var Extensions|null 34 | */ 35 | public $extensions; 36 | 37 | /** 38 | * @var Stats|null 39 | */ 40 | public $stats; 41 | 42 | /** 43 | * Segment constructor. 44 | */ 45 | public function __construct() 46 | { 47 | $this->points = []; 48 | $this->extensions = null; 49 | $this->stats = null; 50 | } 51 | 52 | 53 | /** 54 | * Serialize object to array 55 | * @return array 56 | */ 57 | public function toArray() 58 | { 59 | return [ 60 | 'points' => SerializationHelper::serialize($this->points), 61 | 'extensions' => SerializationHelper::serialize($this->extensions), 62 | 'stats' => SerializationHelper::serialize($this->stats) 63 | ]; 64 | } 65 | 66 | /** 67 | * @return array|Point[] 68 | */ 69 | public function getPoints() 70 | { 71 | return $this->points; 72 | } 73 | 74 | /** 75 | * Recalculate stats objects. 76 | * @return void 77 | */ 78 | public function recalculateStats() 79 | { 80 | if (empty($this->stats)) { 81 | $this->stats = new Stats(); 82 | } 83 | 84 | $count = count($this->points); 85 | $this->stats->reset(); 86 | 87 | if (empty($this->points)) { 88 | return; 89 | } 90 | 91 | $firstPoint = &$this->points[0]; 92 | $lastPoint = end($this->points); 93 | 94 | $this->stats->startedAt = $firstPoint->time; 95 | $this->stats->startedAtCoords = ["lat" => $firstPoint->latitude, "lng" => $firstPoint->longitude]; 96 | $this->stats->finishedAt = $lastPoint->time; 97 | $this->stats->finishedAtCoords = ["lat" => $lastPoint->latitude, "lng" => $lastPoint->longitude]; 98 | $this->stats->minAltitude = $firstPoint->elevation; 99 | $this->stats->minAltitudeCoords = ["lat" => $firstPoint->latitude, "lng" => $firstPoint->longitude]; 100 | 101 | list($this->stats->cumulativeElevationGain, $this->stats->cumulativeElevationLoss) = 102 | ElevationGainLossCalculator::calculate($this->getPoints()); 103 | 104 | $calculator = new DistanceCalculator($this->getPoints()); 105 | $this->stats->distance = $calculator->getRawDistance(); 106 | $this->stats->realDistance = $calculator->getRealDistance(); 107 | 108 | for ($i = 0; $i < $count; $i++) { 109 | if ($this->stats->maxAltitude < $this->points[$i]->elevation) { 110 | $this->stats->maxAltitude = $this->points[$i]->elevation; 111 | $this->stats->maxAltitudeCoords = ["lat" => $this->points[$i]->latitude, "lng" => $this->points[$i]->longitude]; 112 | } 113 | 114 | if ((phpGPX::$IGNORE_ELEVATION_0 === false || $this->points[$i]->elevation > 0) && $this->stats->minAltitude > $this->points[$i]->elevation) { 115 | $this->stats->minAltitude = $this->points[$i]->elevation; 116 | $this->stats->minAltitudeCoords = ["lat" => $this->points[$i]->latitude, "lng" => $this->points[$i]->longitude]; 117 | } 118 | } 119 | 120 | if (isset($firstPoint->time) && isset($lastPoint->time) && $firstPoint->time instanceof \DateTime && $lastPoint->time instanceof \DateTime) { 121 | $this->stats->duration = $lastPoint->time->getTimestamp() - $firstPoint->time->getTimestamp(); 122 | 123 | if ($this->stats->duration != 0) { 124 | $this->stats->averageSpeed = $this->stats->distance / $this->stats->duration; 125 | } 126 | 127 | if ($this->stats->distance != 0) { 128 | $this->stats->averagePace = $this->stats->duration / ($this->stats->distance / 1000); 129 | } 130 | } 131 | 132 | list($northWest, $southEast) = BoundsCalculator::calculate($this->getPoints()); 133 | $this->stats->bounds = [$northWest, $southEast]; 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /src/phpGPX/Models/Route.php: -------------------------------------------------------------------------------- 1 | 5 | */ 6 | 7 | namespace phpGPX\Models; 8 | 9 | use phpGPX\Helpers\BoundsCalculator; 10 | use phpGPX\Helpers\DistanceCalculator; 11 | use phpGPX\Helpers\ElevationGainLossCalculator; 12 | use phpGPX\Helpers\GeoHelper; 13 | use phpGPX\Helpers\SerializationHelper; 14 | use phpGPX\phpGPX; 15 | 16 | /** 17 | * Class Route 18 | * @package phpGPX\Models 19 | */ 20 | class Route extends Collection 21 | { 22 | 23 | /** 24 | * A list of route points. 25 | * An original GPX 1.1 attribute. 26 | * @var Point[] 27 | */ 28 | public $points; 29 | 30 | /** 31 | * Route constructor. 32 | */ 33 | public function __construct() 34 | { 35 | parent::__construct(); 36 | $this->points = []; 37 | } 38 | 39 | 40 | /** 41 | * Return all points in collection. 42 | * @return Point[] 43 | */ 44 | public function getPoints(): array 45 | { 46 | /** @var Point[] $points */ 47 | $points = []; 48 | 49 | $points = array_merge($points, $this->points); 50 | 51 | if (phpGPX::$SORT_BY_TIMESTAMP && !empty($points) && $points[0]->time !== null) { 52 | usort($points, array('phpGPX\Helpers\DateTimeHelper', 'comparePointsByTimestamp')); 53 | } 54 | 55 | return $points; 56 | } 57 | 58 | /** 59 | * Serialize object to array 60 | * @return array 61 | */ 62 | public function toArray() 63 | { 64 | return [ 65 | 'name' => SerializationHelper::stringOrNull($this->name), 66 | 'cmt' => SerializationHelper::stringOrNull($this->comment), 67 | 'desc' => SerializationHelper::stringOrNull($this->description), 68 | 'src' => SerializationHelper::stringOrNull($this->source), 69 | 'link' => SerializationHelper::serialize($this->links), 70 | 'number' => SerializationHelper::integerOrNull($this->number), 71 | 'type' => SerializationHelper::stringOrNull($this->type), 72 | 'extensions' => SerializationHelper::serialize($this->extensions), 73 | 'rtep' => SerializationHelper::serialize($this->points), 74 | 'stats' => SerializationHelper::serialize($this->stats) 75 | ]; 76 | } 77 | 78 | /** 79 | * Recalculate stats objects. 80 | * @return void 81 | */ 82 | public function recalculateStats() 83 | { 84 | if (empty($this->stats)) { 85 | $this->stats = new Stats(); 86 | } 87 | 88 | $this->stats->reset(); 89 | 90 | if (empty($this->points)) { 91 | return; 92 | } 93 | 94 | $pointCount = count($this->points); 95 | 96 | $firstPoint = &$this->points[0]; 97 | $lastPoint = end($this->points); 98 | 99 | $this->stats->startedAt = $firstPoint->time; 100 | $this->stats->startedAtCoords = ["lat" => $firstPoint->latitude, "lng" => $firstPoint->longitude]; 101 | $this->stats->finishedAt = $lastPoint->time; 102 | $this->stats->finishedAtCoords = ["lat" => $lastPoint->latitude, "lng" => $lastPoint->longitude]; 103 | $this->stats->minAltitude = $firstPoint->elevation; 104 | $this->stats->minAltitudeCoords = ["lat" => $firstPoint->latitude, "lng" => $firstPoint->longitude]; 105 | 106 | list($this->stats->cumulativeElevationGain, $this->stats->cumulativeElevationLoss) = 107 | ElevationGainLossCalculator::calculate($this->getPoints()); 108 | 109 | $calculator = new DistanceCalculator($this->getPoints()); 110 | $this->stats->distance = $calculator->getRawDistance(); 111 | $this->stats->realDistance = $calculator->getRealDistance(); 112 | 113 | for ($p = 0; $p < $pointCount; $p++) { 114 | if ((phpGPX::$IGNORE_ELEVATION_0 === false || $this->points[$p]->elevation > 0) && $this->stats->minAltitude > $this->points[$p]->elevation) { 115 | $this->stats->minAltitude = $this->points[$p]->elevation; 116 | $this->stats->minAltitudeCoords = ["lat" => $this->points[$p]->latitude, "lng" => $this->points[$p]->longitude]; 117 | } 118 | 119 | if ($this->stats->maxAltitude < $this->points[$p]->elevation) { 120 | $this->stats->maxAltitude = $this->points[$p]->elevation; 121 | $this->stats->maxAltitudeCoords = ["lat" => $this->points[$p]->latitude, "lng" => $this->points[$p]->longitude]; 122 | } 123 | 124 | if ($this->stats->minAltitude > $this->points[$p]->elevation) { 125 | $this->stats->minAltitude = $this->points[$p]->elevation; 126 | $this->stats->minAltitudeCoords = ["lat" => $this->points[$p]->latitude, "lng" => $this->points[$p]->longitude]; 127 | } 128 | } 129 | 130 | if (($firstPoint->time instanceof \DateTime) && ($lastPoint->time instanceof \DateTime)) { 131 | $this->stats->duration = $lastPoint->time->getTimestamp() - $firstPoint->time->getTimestamp(); 132 | 133 | if ($this->stats->duration != 0) { 134 | $this->stats->averageSpeed = $this->stats->distance / $this->stats->duration; 135 | } 136 | 137 | if ($this->stats->distance != 0) { 138 | $this->stats->averagePace = $this->stats->duration / ($this->stats->distance / 1000); 139 | } 140 | } 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /src/phpGPX/Models/GpxFile.php: -------------------------------------------------------------------------------- 1 | 5 | */ 6 | 7 | namespace phpGPX\Models; 8 | 9 | use phpGPX\Helpers\SerializationHelper; 10 | use phpGPX\Parsers\ExtensionParser; 11 | use phpGPX\Parsers\MetadataParser; 12 | use phpGPX\Parsers\PointParser; 13 | use phpGPX\Parsers\RouteParser; 14 | use phpGPX\Parsers\TrackParser; 15 | use phpGPX\phpGPX; 16 | 17 | /** 18 | * Class GpxFile 19 | * Representation of GPX file. 20 | * @package phpGPX\Models 21 | */ 22 | class GpxFile implements Summarizable 23 | { 24 | /** 25 | * A list of waypoints. 26 | * @var Point[] 27 | */ 28 | public $waypoints; 29 | 30 | /** 31 | * A list of routes. 32 | * @var Route[] 33 | */ 34 | public $routes; 35 | 36 | /** 37 | * A list of tracks. 38 | * @var Track[] 39 | */ 40 | public $tracks; 41 | 42 | /** 43 | * Metadata about the file. 44 | * The original GPX 1.1 attribute. 45 | * @var Metadata|null 46 | */ 47 | public $metadata; 48 | 49 | /** 50 | * @var Extensions|null 51 | */ 52 | public $extensions; 53 | 54 | /** 55 | * Creator of GPX file. 56 | * @var string|null 57 | */ 58 | public $creator; 59 | 60 | /** 61 | * GpxFile constructor. 62 | */ 63 | public function __construct() 64 | { 65 | $this->waypoints = []; 66 | $this->routes = []; 67 | $this->tracks = []; 68 | $this->metadata = null; 69 | $this->extensions = null; 70 | $this->creator = null; 71 | } 72 | 73 | 74 | /** 75 | * Serialize object to array 76 | * @return array 77 | */ 78 | public function toArray() 79 | { 80 | return SerializationHelper::filterNotNull([ 81 | 'creator' => SerializationHelper::stringOrNull($this->creator), 82 | 'metadata' => SerializationHelper::serialize($this->metadata), 83 | 'waypoints' => SerializationHelper::serialize($this->waypoints), 84 | 'routes' => SerializationHelper::serialize($this->routes), 85 | 'tracks' => SerializationHelper::serialize($this->tracks), 86 | 'extensions' => SerializationHelper::serialize($this->extensions) 87 | ]); 88 | } 89 | 90 | /** 91 | * Return JSON representation of GPX file with statistics. 92 | * @return string 93 | */ 94 | public function toJSON() 95 | { 96 | return json_encode($this->toArray(), phpGPX::$PRETTY_PRINT ? JSON_PRETTY_PRINT : null); 97 | } 98 | 99 | /** 100 | * Create XML representation of GPX file. 101 | * @return \DOMDocument 102 | */ 103 | public function toXML() 104 | { 105 | $document = new \DOMDocument("1.0", 'UTF-8'); 106 | 107 | $gpx = $document->createElementNS("http://www.topografix.com/GPX/1/1", "gpx"); 108 | $gpx->setAttribute("version", "1.1"); 109 | $gpx->setAttribute("creator", $this->creator ? $this->creator : phpGPX::getSignature()); 110 | 111 | ExtensionParser::$usedNamespaces = []; 112 | 113 | if (!empty($this->metadata)) { 114 | $gpx->appendChild(MetadataParser::toXML($this->metadata, $document)); 115 | } 116 | 117 | foreach ($this->waypoints as $waypoint) { 118 | $gpx->appendChild(PointParser::toXML($waypoint, $document)); 119 | } 120 | 121 | foreach ($this->routes as $route) { 122 | $gpx->appendChild(RouteParser::toXML($route, $document)); 123 | } 124 | 125 | foreach ($this->tracks as $track) { 126 | $gpx->appendChild(TrackParser::toXML($track, $document)); 127 | } 128 | 129 | if (!empty($this->extensions)) { 130 | $gpx->appendChild(ExtensionParser::toXML($this->extensions, $document)); 131 | } 132 | 133 | // Namespaces 134 | $schemaLocationArray = [ 135 | 'http://www.topografix.com/GPX/1/1', 136 | 'http://www.topografix.com/GPX/1/1/gpx.xsd' 137 | ]; 138 | 139 | foreach (ExtensionParser::$usedNamespaces as $usedNamespace) { 140 | $gpx->setAttributeNS( 141 | "http://www.w3.org/2000/xmlns/", 142 | sprintf("xmlns:%s", $usedNamespace['prefix']), 143 | $usedNamespace['namespace'] 144 | ); 145 | 146 | $schemaLocationArray[] = $usedNamespace['namespace']; 147 | $schemaLocationArray[] = $usedNamespace['xsd']; 148 | } 149 | 150 | $gpx->setAttributeNS( 151 | 'http://www.w3.org/2001/XMLSchema-instance', 152 | 'xsi:schemaLocation', 153 | implode(" ", $schemaLocationArray) 154 | ); 155 | 156 | $document->appendChild($gpx); 157 | 158 | if (phpGPX::$PRETTY_PRINT) { 159 | $document->formatOutput = true; 160 | $document->preserveWhiteSpace = true; 161 | } 162 | return $document; 163 | } 164 | 165 | /** 166 | * Save data to file according to selected format. 167 | * @param string $path 168 | * @param string $format 169 | */ 170 | public function save($path, $format) 171 | { 172 | switch ($format) { 173 | case phpGPX::XML_FORMAT: 174 | $document = $this->toXML(); 175 | $document->save($path); 176 | break; 177 | case phpGPX::JSON_FORMAT: 178 | file_put_contents($path, $this->toJSON()); 179 | break; 180 | default: 181 | throw new \RuntimeException("Unsupported file format!"); 182 | }; 183 | } 184 | } 185 | --------------------------------------------------------------------------------