<rtept lat="0.0" lon="0.0"/>
<rtept lat="1.0" lon="1.0"/>
</rte>
+ <trk>
+ <name>Sample Track</name>
+ <cmt>track</cmt>
+ <desc>A sample track</desc>
+ <src>Imagination</src>
+ <url>https://www.example.com/track</url>
+ <urlname>Sample Route</urlname>
+ <number>1</number>
+ <custom:checkedBy>Jane Doe</custom:checkedBy>
+ <trkseg>
+ <trkpt lat="0.0" lon="0.0"/>
+ <trkpt lat="1.0" lon="1.0"/>
+ </trkseg>
+ <trkseg>
+ <trkpt lat="2.0" lon="2.0"/>
+ <trkpt lat="3.0" lon="3.0"/>
+ </trkseg>
+ </trk>
</gpx>
<rtept lat="0.0" lon="0.0"/>\r
<rtept lat="1.0" lon="1.0"/>\r
</rte>\r
+ <trk>\r
+ <name>Sample Track</name>\r
+ <cmt>track</cmt>\r
+ <desc>A sample track</desc>\r
+ <src>Imagination</src>\r
+ <link href="https://www.example.com/track">\r
+ <text>Sample Route</text>\r
+ <type>text/html</type>\r
+ </link>\r
+ <number>1</number>\r
+ <type>A type</type>\r
+ <extensions>\r
+ <custom:checkedBy>Jane Doe</custom:checkedBy>\r
+ </extensions>\r
+ <trkseg>\r
+ <extensions>\r
+ <custom:checkedBy>Jane Doe</custom:checkedBy>\r
+ </extensions>\r
+ <trkpt lat="0.0" lon="0.0"/>\r
+ <trkpt lat="1.0" lon="1.0"/>\r
+ </trkseg>\r
+ <trkseg>\r
+ <trkpt lat="2.0" lon="2.0"/>\r
+ <trkpt lat="3.0" lon="3.0"/>\r
+ </trkseg>\r
+ </trk>\r
</gpx>\r
*/
protected $routes;
+ /**
+ * A list of tracks.
+ *
+ * @var TypedDoublyLinkedList (Track)
+ */
+ protected $tracks;
+
/**
* Fetch the name of the program that created the GPX file.
*
return $this->routes;
}
+ /**
+ * Fetch a list of tracks.
+ *
+ * @param boolean $create Create the list if it does not already exist.
+ * @return TypedDoublyLinkedList A list of tracks.
+ */
+ public function getTracks(bool $create = true)
+ {
+ if ($create && $this->tracks === null)
+ $this->tracks = new TypedDoublyLinkedList('libgpx\Track');
+ return $this->tracks;
+ }
+
/**
* Fetch a bounding box that covers the feature.
*
$result = null;
$lists = [
$this->waypoints,
- $this->routes
+ $this->routes,
+ $this->tracks
];
foreach ($lists as $list) {
if ($list === null) continue;
},
'rte' => function ($gpx) {
$gpx->getRoutes()[] = $this->readRte();
+ },
+ 'trk' => function ($gpx) {
+ $gpx->getTracks()[] = $this->readTrk();
}
]
];
return $result;
}
+ /**
+ * Read a trk type.
+ *
+ * @see https://www.topografix.com/GPX/1/1/#type_trkType
+ *
+ * @return Track
+ * @throws MalformedGPXException If the GPX file was invalid or not supported.
+ */
+ protected function readTrk()
+ {
+ try {
+ $result = new Track();
+ $struct = $this->getDataTypeStruct();
+ $struct['elements']['number'] = function ($track) {
+ $track->setNumber($this->string2int($this->readXSDString()));
+ };
+ $struct['elements']['trkseg'] = function ($track) {
+ $track->getSegments()[] = $this->readTrkseg();
+ };
+ $this->readStruct($struct, $result);
+ } catch (DomainException $e) {
+ throw new MalformedGPXException(
+ $e->getMessage(), $e->getCode(), $e
+ );
+ }
+ return $result;
+ }
+
+ /**
+ * Read a trkseg type.
+ *
+ * @see https://www.topografix.com/GPX/1/1/#type_trksegType
+ *
+ * @return TrackSegment
+ * @throws MalformedGPXException If the GPX file was invalid or not supported.
+ */
+ protected function readTrkseg()
+ {
+ $result = new TrackSegment();
+ $struct = [
+ 'elements' => [
+ 'trkpt' => function ($segment) {
+ $segment->getPoints()[] = $this->readWpt();
+ }
+ ]
+ ];
+ if ($this->version == '1.1')
+ $struct['elements']['extensions'] = function ($segment) {
+ $this->readExtension($segment->getExtensions());
+ };
+ $this->readStruct($struct, $result);
+ return $result;
+ }
+
/**
* Read a data structure from XML.
*
$this->writeRoute($route, $xml);
}
}
+ $tracks = $gpx->getTracks(false);
+ if ($tracks !== null) {
+ foreach ($tracks as $track) {
+ $this->writeTrack($track, $xml);
+ }
+ }
$xml->endElement();
$xml->endDocument();
$xml->flush();
*
* @param Route $route The route to write.
* @param XMLWriter $xml Where to write.
+ * @return void
*/
protected function writeRoute(Route $route, XMLWriter $xml)
{
$xml->endElement();
}
+ /**
+ * Write XML for a track element.
+ *
+ * @param Track $track The track to write.
+ * @param XMLWriter $xml Where to write.
+ * @return void
+ */
+ protected function writeTrack(Track $track, XMLWriter $xml)
+ {
+ $xml->startElement('trk');
+ $var = $track->getNumber();
+ if ($var !== null)
+ $xml->writeElement('number', $var);
+ $this->writeDataType($track, $xml);
+ $var = $track->getSegments(false);
+ if ($var !== null) {
+ foreach ($var as $segment) {
+ $this->writeTrackSegment($segment, $xml);
+ }
+ }
+ $xml->endElement();
+ }
+
+ /**
+ * Write XML for a track segment element.
+ *
+ * @param TrackSegment $segment The segment to write.
+ * @param XMLWriter $xml Where to write.
+ * @return void
+ */
+ protected function writeTrackSegment(TrackSegment $segment, XMLWriter $xml)
+ {
+ $xml->startElement('trkseg');
+ $var = $segment->getPoints(false);
+ if ($var !== null) {
+ foreach ($var as $point) {
+ $this->writePoint($point, 'trkpt', $xml);
+ }
+ }
+ if ($this->format == '1.1') {
+ $var = $segment->getExtensions(false);
+ if ($var !== null) {
+ $xml->startElement('extensions');
+ foreach ($var as $extension) {
+ $xml->writeRaw($extension);
+ }
+ $xml->endElement();
+ }
+ }
+ $xml->endElement();
+ }
+
}
--- /dev/null
+<?php
+/**
+ * tracksegment.php
+ *
+ * Copyright 2018 Andy Street <andy@street.me.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ *
+ */
+
+namespace libgpx;
+
+use \DomainException;
+
+/**
+ * A GPX trk type.
+ *
+ * @author Andy Street <andy@street.me.uk>
+ */
+class Track extends DataType implements Geographic
+{
+
+ /**
+ * GPS track number.
+ *
+ * @var int
+ */
+ protected $number;
+
+ /**
+ * A list of track segments.
+ *
+ * @var DoublyLinkedList (TrackSegment)
+ *
+ */
+ protected $segments;
+
+ /**
+ * Fetch the track number.
+ *
+ * @return int|null The route number or null if not set.
+ */
+ public function getNumber()
+ {
+ return $this->number;
+ }
+
+ /**
+ * Set the number of the track.
+ *
+ * @param int $number The route number or null to delete.
+ * @return void
+ * @throws DomainException If the number is < 0
+ */
+ public function setNumber(int $number = null)
+ {
+ if ($number !== null && $number < 0)
+ throw new DomainException(
+ sprintf('Number must be >= 0 but got "%s"', $number)
+ );
+ $this->number = $number;
+ }
+
+ /**
+ * Fetch an ordered list of track segments.
+ *
+ * @param boolean $create Create the list if it does not already exist.
+ * @return TypedDoublyLinkedList|null A list of track segments.
+ */
+ public function getSegments(bool $create = true)
+ {
+ if ($create && $this->segments === null)
+ $this->segments = new TypedDoublyLinkedList('libgpx\TrackSegment');
+ return $this->segments;
+ }
+
+ /**
+ * Fetch a bounding box that covers the feature.
+ *
+ * @return Bounds|null A bounding box covering the extent of the feature or
+ * null if not applicable.
+ */
+ public function getBounds()
+ {
+ $result = null;
+ if ($this->segments !== null) {
+ foreach ($this->segments as $segment) {
+ $bounds = $segment->getBounds();
+ $result = ($result === null ? $bounds : $result->extend($bounds));
+ }
+ }
+ return $result;
+ }
+
+}
--- /dev/null
+<?php
+/**
+ * tracksegment.php
+ *
+ * Copyright 2018 Andy Street <andy@street.me.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ *
+ */
+
+namespace libgpx;
+
+/**
+ * A GPX trkseg type.
+ *
+ * @author Andy Street <andy@street.me.uk>
+ */
+class TrackSegment implements Geographic
+{
+
+ /**
+ * A list of track points.
+ *
+ * @var TypedDoublyLinkedList (Point)
+ */
+ protected $points;
+
+ /**
+ * A list of XML snippets describing unsupported data.
+ *
+ * @var TypedDoublyLinkedList (string)
+ */
+ protected $extensions;
+
+ /**
+ * Fetch an ordered list of points that defines this track segment.
+ *
+ * @param boolean $create Create the list if it does not already exist.
+ * @return TypedDoublyLinkedList|null A list points.
+ */
+ public function getPoints(bool $create = true)
+ {
+ if ($create && $this->points === null)
+ $this->points = new TypedDoublyLinkedList('libgpx\Point');
+ return $this->points;
+ }
+
+ /**
+ * Fetch a list of XML strings that describe unsupported elements.
+ *
+ * @param boolean $create Create the list if it does not already exist.
+ * @return TypedDoublyLinkedList|null A list of XML strings.
+ */
+ public function getExtensions(bool $create = true)
+ {
+ if ($create && $this->extensions === null)
+ $this->extensions = new TypedDoublyLinkedList('string');
+ return $this->extensions;
+ }
+
+ /**
+ * Fetch a bounding box that covers the feature.
+ *
+ * @return Bounds|null A bounding box covering the extent of the feature or
+ * null if not applicable.
+ */
+ public function getBounds()
+ {
+ $result = null;
+ if ($this->points !== null) {
+ foreach ($this->points as $point) {
+ $bounds = $point->getBounds();
+ $result = ($result === null ? $bounds : $result->extend($bounds));
+ }
+ }
+ return $result;
+ }
+
+}