]> git.street.me.uk Git - andy/gpx.git/commitdiff
Add ability to read track types
authorAndy Street <andy@street.me.uk>
Wed, 19 Dec 2018 18:35:33 +0000 (18:35 +0000)
committerAndy Street <andy@street.me.uk>
Wed, 19 Dec 2018 18:35:33 +0000 (18:35 +0000)
docs/samples/full-1.0.gpx
docs/samples/full-1.1.gpx
src/libgpx/gpx.php
src/libgpx/gpxreader.php
src/libgpx/gpxwriter.php
src/libgpx/track.php [new file with mode: 0644]
src/libgpx/tracksegment.php [new file with mode: 0644]

index cdcf366f801dd5e06cfa52c01470aa29b8c15cc7..ab9c5f61adb2da772e2811dbb6724aef0e704631 100644 (file)
     <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>
index d913c74857198e6b46d1d7e56fd8b4eb9ac668b2..414a45ca0082b9083a4e1b86785feb213529f09f 100644 (file)
     <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
index 3d45b6f8adaf6ab258502bedeecc07b8d689cfe8..f71f7f1a4f528e8211886df648764f4159075a76 100644 (file)
@@ -113,6 +113,13 @@ class GPX implements Geographic
    */
   protected $routes;
 
+  /**
+   * A list of tracks.
+   *
+   * @var TypedDoublyLinkedList (Track)
+   */
+  protected $tracks;
+
   /**
    * Fetch the name of the program that created the GPX file.
    *
@@ -303,6 +310,19 @@ class GPX implements Geographic
     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.
    *
@@ -314,7 +334,8 @@ class GPX implements Geographic
     $result = null;
     $lists = [
       $this->waypoints,
-      $this->routes
+      $this->routes,
+      $this->tracks
     ];
     foreach ($lists as $list) {
       if ($list === null) continue;
index b98d2efcd7a41b19b84fccd60eda32d4bb60f07e..4df8d1dd9b5f7a9957be0f78dc49a3f4ace35f41 100644 (file)
@@ -183,6 +183,9 @@ class GPXReader
         },
         'rte' => function ($gpx) {
           $gpx->getRoutes()[] = $this->readRte();
+        },
+        'trk' => function ($gpx) {
+          $gpx->getTracks()[] = $this->readTrk();
         }
       ]
     ];
@@ -514,6 +517,60 @@ class GPXReader
     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.
    *
index 342f89efb4dcba1ac1e77a35b4d4e24ee41736d3..1e7878cfe0d68d758346166cb830d90627ab05aa 100644 (file)
@@ -245,6 +245,12 @@ class GPXWriter
         $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();
@@ -518,6 +524,7 @@ class GPXWriter
    *
    * @param Route $route The route to write.
    * @param XMLWriter $xml Where to write.
+   * @return void
    */
   protected function writeRoute(Route $route, XMLWriter $xml)
   {
@@ -535,4 +542,56 @@ class GPXWriter
     $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();
+  }
+
 }
diff --git a/src/libgpx/track.php b/src/libgpx/track.php
new file mode 100644 (file)
index 0000000..266d32b
--- /dev/null
@@ -0,0 +1,109 @@
+<?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;
+  }
+
+}
diff --git a/src/libgpx/tracksegment.php b/src/libgpx/tracksegment.php
new file mode 100644 (file)
index 0000000..ccb3078
--- /dev/null
@@ -0,0 +1,93 @@
+<?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;
+  }
+
+}